2005-04-16 15:20:36 -07:00
/*
* PCI HotPlug Controller Core
*
* Copyright ( C ) 2001 - 2002 Greg Kroah - Hartman ( greg @ kroah . com )
* Copyright ( C ) 2001 - 2002 IBM Corp .
*
* All rights reserved .
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or ( at
* your option ) any later version .
*
* This program is distributed in the hope that it will be useful , but
* WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE , GOOD TITLE or
* NON INFRINGEMENT . See the GNU General Public License for more
* details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*
2006-09-29 10:30:27 -07:00
* Send feedback to < kristen . c . accardi @ intel . com >
2005-04-16 15:20:36 -07:00
*
*/
# include <linux/module.h>
# include <linux/moduleparam.h>
# include <linux/kernel.h>
# include <linux/types.h>
# include <linux/list.h>
2006-10-13 20:05:19 -07:00
# include <linux/kobject.h>
# include <linux/sysfs.h>
2005-04-16 15:20:36 -07:00
# include <linux/pagemap.h>
# include <linux/init.h>
# include <linux/mount.h>
# include <linux/namei.h>
2008-10-20 17:40:57 -06:00
# include <linux/mutex.h>
2005-04-16 15:20:36 -07:00
# include <linux/pci.h>
2006-10-13 20:05:19 -07:00
# include <linux/pci_hotplug.h>
2005-04-16 15:20:36 -07:00
# include <asm/uaccess.h>
2008-06-10 15:28:50 -06:00
# include "../pci.h"
2013-04-15 10:44:18 -06:00
# include "cpci_hotplug.h"
2005-04-16 15:20:36 -07:00
# define MY_NAME "pci_hotplug"
2008-03-03 19:09:46 -08:00
# define dbg(fmt, arg...) do { if (debug) printk(KERN_DEBUG "%s: %s: " fmt , MY_NAME , __func__ , ## arg); } while (0)
2005-04-16 15:20:36 -07:00
# define err(format, arg...) printk(KERN_ERR "%s: " format , MY_NAME , ## arg)
# define info(format, arg...) printk(KERN_INFO "%s: " format , MY_NAME , ## arg)
# define warn(format, arg...) printk(KERN_WARNING "%s: " format , MY_NAME , ## arg)
/* local variables */
2012-01-13 09:32:20 +10:30
static bool debug ;
2005-04-16 15:20:36 -07:00
# define DRIVER_VERSION "0.5"
# define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com>, Scott Murray <scottm@somanetworks.com>"
# define DRIVER_DESC "PCI Hot Plug PCI Core"
//////////////////////////////////////////////////////////////////
static LIST_HEAD ( pci_hotplug_slot_list ) ;
2008-10-20 17:40:57 -06:00
static DEFINE_MUTEX ( pci_hp_mutex ) ;
2005-04-16 15:20:36 -07:00
/* Weee, fun with macros... */
# define GET_STATUS(name,type) \
static int get_ # # name ( struct hotplug_slot * slot , type * value ) \
{ \
struct hotplug_slot_ops * ops = slot - > ops ; \
int retval = 0 ; \
2008-09-29 17:37:05 +09:00
if ( ! try_module_get ( ops - > owner ) ) \
2008-09-22 14:26:05 +08:00
return - ENODEV ; \
if ( ops - > get_ # # name ) \
retval = ops - > get_ # # name ( slot , value ) ; \
else \
* value = slot - > info - > name ; \
module_put ( ops - > owner ) ; \
2005-04-16 15:20:36 -07:00
return retval ; \
}
GET_STATUS ( power_status , u8 )
GET_STATUS ( attention_status , u8 )
GET_STATUS ( latch_status , u8 )
GET_STATUS ( adapter_status , u8 )
2008-06-10 15:28:50 -06:00
static ssize_t power_read_file ( struct pci_slot * slot , char * buf )
2005-04-16 15:20:36 -07:00
{
int retval ;
u8 value ;
2008-06-10 15:28:50 -06:00
retval = get_power_status ( slot - > hotplug , & value ) ;
2005-04-16 15:20:36 -07:00
if ( retval )
goto exit ;
retval = sprintf ( buf , " %d \n " , value ) ;
exit :
return retval ;
}
2008-06-10 15:28:50 -06:00
static ssize_t power_write_file ( struct pci_slot * pci_slot , const char * buf ,
2005-04-16 15:20:36 -07:00
size_t count )
{
2008-06-10 15:28:50 -06:00
struct hotplug_slot * slot = pci_slot - > hotplug ;
2005-04-16 15:20:36 -07:00
unsigned long lpower ;
u8 power ;
int retval = 0 ;
lpower = simple_strtoul ( buf , NULL , 10 ) ;
power = ( u8 ) ( lpower & 0xff ) ;
dbg ( " power = %d \n " , power ) ;
if ( ! try_module_get ( slot - > ops - > owner ) ) {
retval = - ENODEV ;
goto exit ;
}
switch ( power ) {
case 0 :
if ( slot - > ops - > disable_slot )
retval = slot - > ops - > disable_slot ( slot ) ;
break ;
case 1 :
if ( slot - > ops - > enable_slot )
retval = slot - > ops - > enable_slot ( slot ) ;
break ;
default :
err ( " Illegal value specified for power \n " ) ;
retval = - EINVAL ;
}
module_put ( slot - > ops - > owner ) ;
exit :
if ( retval )
return retval ;
return count ;
}
2008-06-10 15:28:50 -06:00
static struct pci_slot_attribute hotplug_slot_attr_power = {
2005-04-16 15:20:36 -07:00
. attr = { . name = " power " , . mode = S_IFREG | S_IRUGO | S_IWUSR } ,
. show = power_read_file ,
. store = power_write_file
} ;
2008-06-10 15:28:50 -06:00
static ssize_t attention_read_file ( struct pci_slot * slot , char * buf )
2005-04-16 15:20:36 -07:00
{
int retval ;
u8 value ;
2008-06-10 15:28:50 -06:00
retval = get_attention_status ( slot - > hotplug , & value ) ;
2005-04-16 15:20:36 -07:00
if ( retval )
goto exit ;
2008-06-10 15:28:50 -06:00
retval = sprintf ( buf , " %d \n " , value ) ;
2005-04-16 15:20:36 -07:00
exit :
return retval ;
}
2008-06-10 15:28:50 -06:00
static ssize_t attention_write_file ( struct pci_slot * slot , const char * buf ,
2005-04-16 15:20:36 -07:00
size_t count )
{
2008-06-10 15:28:50 -06:00
struct hotplug_slot_ops * ops = slot - > hotplug - > ops ;
2005-04-16 15:20:36 -07:00
unsigned long lattention ;
u8 attention ;
int retval = 0 ;
lattention = simple_strtoul ( buf , NULL , 10 ) ;
attention = ( u8 ) ( lattention & 0xff ) ;
dbg ( " - attention = %d \n " , attention ) ;
2008-06-10 15:28:50 -06:00
if ( ! try_module_get ( ops - > owner ) ) {
2005-04-16 15:20:36 -07:00
retval = - ENODEV ;
goto exit ;
}
2008-06-10 15:28:50 -06:00
if ( ops - > set_attention_status )
retval = ops - > set_attention_status ( slot - > hotplug , attention ) ;
module_put ( ops - > owner ) ;
2005-04-16 15:20:36 -07:00
exit :
if ( retval )
return retval ;
return count ;
}
2008-06-10 15:28:50 -06:00
static struct pci_slot_attribute hotplug_slot_attr_attention = {
2005-04-16 15:20:36 -07:00
. attr = { . name = " attention " , . mode = S_IFREG | S_IRUGO | S_IWUSR } ,
. show = attention_read_file ,
. store = attention_write_file
} ;
2008-06-10 15:28:50 -06:00
static ssize_t latch_read_file ( struct pci_slot * slot , char * buf )
2005-04-16 15:20:36 -07:00
{
int retval ;
u8 value ;
2008-06-10 15:28:50 -06:00
retval = get_latch_status ( slot - > hotplug , & value ) ;
2005-04-16 15:20:36 -07:00
if ( retval )
goto exit ;
retval = sprintf ( buf , " %d \n " , value ) ;
exit :
return retval ;
}
2008-06-10 15:28:50 -06:00
static struct pci_slot_attribute hotplug_slot_attr_latch = {
2005-04-16 15:20:36 -07:00
. attr = { . name = " latch " , . mode = S_IFREG | S_IRUGO } ,
. show = latch_read_file ,
} ;
2008-06-10 15:28:50 -06:00
static ssize_t presence_read_file ( struct pci_slot * slot , char * buf )
2005-04-16 15:20:36 -07:00
{
int retval ;
u8 value ;
2008-06-10 15:28:50 -06:00
retval = get_adapter_status ( slot - > hotplug , & value ) ;
2005-04-16 15:20:36 -07:00
if ( retval )
goto exit ;
retval = sprintf ( buf , " %d \n " , value ) ;
exit :
return retval ;
}
2008-06-10 15:28:50 -06:00
static struct pci_slot_attribute hotplug_slot_attr_presence = {
2005-04-16 15:20:36 -07:00
. attr = { . name = " adapter " , . mode = S_IFREG | S_IRUGO } ,
. show = presence_read_file ,
} ;
2008-06-10 15:28:50 -06:00
static ssize_t test_write_file ( struct pci_slot * pci_slot , const char * buf ,
2005-04-16 15:20:36 -07:00
size_t count )
{
2008-06-10 15:28:50 -06:00
struct hotplug_slot * slot = pci_slot - > hotplug ;
2005-04-16 15:20:36 -07:00
unsigned long ltest ;
u32 test ;
int retval = 0 ;
ltest = simple_strtoul ( buf , NULL , 10 ) ;
test = ( u32 ) ( ltest & 0xffffffff ) ;
dbg ( " test = %d \n " , test ) ;
if ( ! try_module_get ( slot - > ops - > owner ) ) {
retval = - ENODEV ;
goto exit ;
}
if ( slot - > ops - > hardware_test )
retval = slot - > ops - > hardware_test ( slot , test ) ;
module_put ( slot - > ops - > owner ) ;
exit :
if ( retval )
return retval ;
return count ;
}
2008-06-10 15:28:50 -06:00
static struct pci_slot_attribute hotplug_slot_attr_test = {
2005-04-16 15:20:36 -07:00
. attr = { . name = " test " , . mode = S_IFREG | S_IRUGO | S_IWUSR } ,
. store = test_write_file
} ;
2009-06-16 11:00:47 +09:00
static bool has_power_file ( struct pci_slot * pci_slot )
2005-04-16 15:20:36 -07:00
{
2008-06-10 15:28:50 -06:00
struct hotplug_slot * slot = pci_slot - > hotplug ;
2005-04-16 15:20:36 -07:00
if ( ( ! slot ) | | ( ! slot - > ops ) )
2009-06-16 11:00:47 +09:00
return false ;
2005-04-16 15:20:36 -07:00
if ( ( slot - > ops - > enable_slot ) | |
( slot - > ops - > disable_slot ) | |
( slot - > ops - > get_power_status ) )
2009-06-16 11:00:47 +09:00
return true ;
return false ;
2005-04-16 15:20:36 -07:00
}
2009-06-16 11:00:47 +09:00
static bool has_attention_file ( struct pci_slot * pci_slot )
2005-04-16 15:20:36 -07:00
{
2008-06-10 15:28:50 -06:00
struct hotplug_slot * slot = pci_slot - > hotplug ;
2005-04-16 15:20:36 -07:00
if ( ( ! slot ) | | ( ! slot - > ops ) )
2009-06-16 11:00:47 +09:00
return false ;
2005-04-16 15:20:36 -07:00
if ( ( slot - > ops - > set_attention_status ) | |
( slot - > ops - > get_attention_status ) )
2009-06-16 11:00:47 +09:00
return true ;
return false ;
2005-04-16 15:20:36 -07:00
}
2009-06-16 11:00:47 +09:00
static bool has_latch_file ( struct pci_slot * pci_slot )
2005-04-16 15:20:36 -07:00
{
2008-06-10 15:28:50 -06:00
struct hotplug_slot * slot = pci_slot - > hotplug ;
2005-04-16 15:20:36 -07:00
if ( ( ! slot ) | | ( ! slot - > ops ) )
2009-06-16 11:00:47 +09:00
return false ;
2005-04-16 15:20:36 -07:00
if ( slot - > ops - > get_latch_status )
2009-06-16 11:00:47 +09:00
return true ;
return false ;
2005-04-16 15:20:36 -07:00
}
2009-06-16 11:00:47 +09:00
static bool has_adapter_file ( struct pci_slot * pci_slot )
2005-04-16 15:20:36 -07:00
{
2008-06-10 15:28:50 -06:00
struct hotplug_slot * slot = pci_slot - > hotplug ;
2005-04-16 15:20:36 -07:00
if ( ( ! slot ) | | ( ! slot - > ops ) )
2009-06-16 11:00:47 +09:00
return false ;
2005-04-16 15:20:36 -07:00
if ( slot - > ops - > get_adapter_status )
2009-06-16 11:00:47 +09:00
return true ;
return false ;
2005-04-16 15:20:36 -07:00
}
2009-06-16 11:00:47 +09:00
static bool has_test_file ( struct pci_slot * pci_slot )
2005-04-16 15:20:36 -07:00
{
2008-06-10 15:28:50 -06:00
struct hotplug_slot * slot = pci_slot - > hotplug ;
2005-04-16 15:20:36 -07:00
if ( ( ! slot ) | | ( ! slot - > ops ) )
2009-06-16 11:00:47 +09:00
return false ;
2005-04-16 15:20:36 -07:00
if ( slot - > ops - > hardware_test )
2009-06-16 11:00:47 +09:00
return true ;
return false ;
2005-04-16 15:20:36 -07:00
}
2008-06-10 15:28:50 -06:00
static int fs_add_slot ( struct pci_slot * slot )
2005-04-16 15:20:36 -07:00
{
2006-08-28 11:43:25 -07:00
int retval = 0 ;
2005-04-16 15:20:36 -07:00
2009-06-16 11:01:25 +09:00
/* Create symbolic link to the hotplug driver module */
pci_hp_create_module_link ( slot ) ;
2009-06-16 11:00:47 +09:00
if ( has_power_file ( slot ) ) {
retval = sysfs_create_file ( & slot - > kobj ,
& hotplug_slot_attr_power . attr ) ;
2006-08-28 11:43:25 -07:00
if ( retval )
goto exit_power ;
}
2005-04-16 15:20:36 -07:00
2009-06-16 11:00:47 +09:00
if ( has_attention_file ( slot ) ) {
2006-08-28 11:43:25 -07:00
retval = sysfs_create_file ( & slot - > kobj ,
& hotplug_slot_attr_attention . attr ) ;
if ( retval )
goto exit_attention ;
}
2005-04-16 15:20:36 -07:00
2009-06-16 11:00:47 +09:00
if ( has_latch_file ( slot ) ) {
2006-08-28 11:43:25 -07:00
retval = sysfs_create_file ( & slot - > kobj ,
& hotplug_slot_attr_latch . attr ) ;
if ( retval )
goto exit_latch ;
}
2005-04-16 15:20:36 -07:00
2009-06-16 11:00:47 +09:00
if ( has_adapter_file ( slot ) ) {
2006-08-28 11:43:25 -07:00
retval = sysfs_create_file ( & slot - > kobj ,
& hotplug_slot_attr_presence . attr ) ;
if ( retval )
goto exit_adapter ;
}
2005-04-16 15:20:36 -07:00
2009-06-16 11:00:47 +09:00
if ( has_test_file ( slot ) ) {
2006-08-28 11:43:25 -07:00
retval = sysfs_create_file ( & slot - > kobj ,
& hotplug_slot_attr_test . attr ) ;
if ( retval )
goto exit_test ;
}
goto exit ;
exit_test :
2009-06-16 11:00:47 +09:00
if ( has_adapter_file ( slot ) )
sysfs_remove_file ( & slot - > kobj ,
& hotplug_slot_attr_presence . attr ) ;
2006-08-28 11:43:25 -07:00
exit_adapter :
2009-06-16 11:00:47 +09:00
if ( has_latch_file ( slot ) )
2006-08-28 11:43:25 -07:00
sysfs_remove_file ( & slot - > kobj , & hotplug_slot_attr_latch . attr ) ;
exit_latch :
2009-06-16 11:00:47 +09:00
if ( has_attention_file ( slot ) )
sysfs_remove_file ( & slot - > kobj ,
& hotplug_slot_attr_attention . attr ) ;
2006-08-28 11:43:25 -07:00
exit_attention :
2009-06-16 11:00:47 +09:00
if ( has_power_file ( slot ) )
2006-08-28 11:43:25 -07:00
sysfs_remove_file ( & slot - > kobj , & hotplug_slot_attr_power . attr ) ;
exit_power :
2009-06-16 11:01:25 +09:00
pci_hp_remove_module_link ( slot ) ;
2006-08-28 11:43:25 -07:00
exit :
return retval ;
2005-04-16 15:20:36 -07:00
}
2008-06-10 15:28:50 -06:00
static void fs_remove_slot ( struct pci_slot * slot )
2005-04-16 15:20:36 -07:00
{
2009-06-16 11:00:47 +09:00
if ( has_power_file ( slot ) )
2005-04-16 15:20:36 -07:00
sysfs_remove_file ( & slot - > kobj , & hotplug_slot_attr_power . attr ) ;
2009-06-16 11:00:47 +09:00
if ( has_attention_file ( slot ) )
sysfs_remove_file ( & slot - > kobj ,
& hotplug_slot_attr_attention . attr ) ;
2005-04-16 15:20:36 -07:00
2009-06-16 11:00:47 +09:00
if ( has_latch_file ( slot ) )
2005-04-16 15:20:36 -07:00
sysfs_remove_file ( & slot - > kobj , & hotplug_slot_attr_latch . attr ) ;
2009-06-16 11:00:47 +09:00
if ( has_adapter_file ( slot ) )
sysfs_remove_file ( & slot - > kobj ,
& hotplug_slot_attr_presence . attr ) ;
2005-04-16 15:20:36 -07:00
2009-06-16 11:00:47 +09:00
if ( has_test_file ( slot ) )
2005-04-16 15:20:36 -07:00
sysfs_remove_file ( & slot - > kobj , & hotplug_slot_attr_test . attr ) ;
2009-06-16 11:01:25 +09:00
pci_hp_remove_module_link ( slot ) ;
2005-04-16 15:20:36 -07:00
}
static struct hotplug_slot * get_slot_from_name ( const char * name )
{
struct hotplug_slot * slot ;
struct list_head * tmp ;
list_for_each ( tmp , & pci_hotplug_slot_list ) {
slot = list_entry ( tmp , struct hotplug_slot , slot_list ) ;
2008-10-20 17:41:58 -06:00
if ( strcmp ( hotplug_slot_name ( slot ) , name ) = = 0 )
2008-10-20 17:40:57 -06:00
return slot ;
2005-04-16 15:20:36 -07:00
}
2008-10-20 17:40:57 -06:00
return NULL ;
2005-04-16 15:20:36 -07:00
}
/**
2009-06-16 11:01:25 +09:00
* __pci_hp_register - register a hotplug_slot with the PCI hotplug subsystem
2008-06-25 15:27:34 -07:00
* @ bus : bus this slot is on
2005-04-16 15:20:36 -07:00
* @ slot : pointer to the & struct hotplug_slot to register
2009-06-16 11:01:25 +09:00
* @ devnr : device number
2008-10-20 17:40:42 -06:00
* @ name : name registered with kobject core
2009-06-24 09:18:14 -07:00
* @ owner : caller module owner
* @ mod_name : caller module name
2005-04-16 15:20:36 -07:00
*
* Registers a hotplug slot with the pci hotplug subsystem , which will allow
* userspace interaction to the slot .
*
* Returns 0 if successful , anything else for an error .
*/
2009-06-16 11:01:25 +09:00
int __pci_hp_register ( struct hotplug_slot * slot , struct pci_bus * bus ,
int devnr , const char * name ,
struct module * owner , const char * mod_name )
2005-04-16 15:20:36 -07:00
{
int result ;
2008-06-10 15:28:50 -06:00
struct pci_slot * pci_slot ;
2005-04-16 15:20:36 -07:00
if ( slot = = NULL )
return - ENODEV ;
if ( ( slot - > info = = NULL ) | | ( slot - > ops = = NULL ) )
return - EINVAL ;
if ( slot - > release = = NULL ) {
2007-11-19 17:48:29 -08:00
dbg ( " Why are you trying to register a hotplug slot "
2005-04-16 15:20:36 -07:00
" without a proper release function? \n " ) ;
return - EINVAL ;
}
2009-06-16 11:01:25 +09:00
slot - > ops - > owner = owner ;
slot - > ops - > mod_name = mod_name ;
2008-10-20 17:40:57 -06:00
2009-06-16 11:01:25 +09:00
mutex_lock ( & pci_hp_mutex ) ;
2008-06-10 15:30:42 -06:00
/*
* No problems if we call this interface from both ACPI_PCI_SLOT
* driver and call it here again . If we ' ve already created the
* pci_slot , the interface will simply bump the refcount .
*/
2009-06-16 11:01:25 +09:00
pci_slot = pci_create_slot ( bus , devnr , name , slot ) ;
2008-10-20 17:40:57 -06:00
if ( IS_ERR ( pci_slot ) ) {
result = PTR_ERR ( pci_slot ) ;
2008-10-20 17:41:02 -06:00
goto out ;
2005-04-16 15:20:36 -07:00
}
2007-12-17 15:54:39 -04:00
2008-06-10 15:28:50 -06:00
slot - > pci_slot = pci_slot ;
pci_slot - > hotplug = slot ;
list_add ( & slot - > slot_list , & pci_hotplug_slot_list ) ;
result = fs_add_slot ( pci_slot ) ;
kobject_uevent ( & pci_slot - > kobj , KOBJ_ADD ) ;
2008-10-20 17:40:42 -06:00
dbg ( " Added slot %s to the list \n " , name ) ;
2008-10-20 17:40:57 -06:00
out :
mutex_unlock ( & pci_hp_mutex ) ;
2005-04-16 15:20:36 -07:00
return result ;
}
/**
* pci_hp_deregister - deregister a hotplug_slot with the PCI hotplug subsystem
2008-06-25 15:27:34 -07:00
* @ hotplug : pointer to the & struct hotplug_slot to deregister
2005-04-16 15:20:36 -07:00
*
* The @ slot must have been registered with the pci hotplug subsystem
* previously with a call to pci_hp_register ( ) .
*
* Returns 0 if successful , anything else for an error .
*/
2008-06-10 15:28:50 -06:00
int pci_hp_deregister ( struct hotplug_slot * hotplug )
2005-04-16 15:20:36 -07:00
{
struct hotplug_slot * temp ;
2008-06-10 15:28:50 -06:00
struct pci_slot * slot ;
2005-04-16 15:20:36 -07:00
2008-06-10 15:28:50 -06:00
if ( ! hotplug )
2005-04-16 15:20:36 -07:00
return - ENODEV ;
2008-10-20 17:40:57 -06:00
mutex_lock ( & pci_hp_mutex ) ;
2008-10-20 17:41:58 -06:00
temp = get_slot_from_name ( hotplug_slot_name ( hotplug ) ) ;
2008-10-20 17:40:57 -06:00
if ( temp ! = hotplug ) {
mutex_unlock ( & pci_hp_mutex ) ;
2005-04-16 15:20:36 -07:00
return - ENODEV ;
2008-10-20 17:40:57 -06:00
}
2005-04-16 15:20:36 -07:00
2008-06-10 15:28:50 -06:00
list_del ( & hotplug - > slot_list ) ;
slot = hotplug - > pci_slot ;
fs_remove_slot ( slot ) ;
2008-10-20 17:41:58 -06:00
dbg ( " Removed slot %s from the list \n " , hotplug_slot_name ( hotplug ) ) ;
2008-06-10 15:28:50 -06:00
hotplug - > release ( hotplug ) ;
slot - > hotplug = NULL ;
pci_destroy_slot ( slot ) ;
2008-10-20 17:40:57 -06:00
mutex_unlock ( & pci_hp_mutex ) ;
2008-06-10 15:28:50 -06:00
2005-04-16 15:20:36 -07:00
return 0 ;
}
/**
* pci_hp_change_slot_info - changes the slot ' s information structure in the core
2008-06-25 15:27:34 -07:00
* @ hotplug : pointer to the slot whose info has changed
2005-04-16 15:20:36 -07:00
* @ info : pointer to the info copy into the slot ' s info structure
*
* @ slot must have been registered with the pci
* hotplug subsystem previously with a call to pci_hp_register ( ) .
*
* Returns 0 if successful , anything else for an error .
*/
2008-06-10 15:28:50 -06:00
int __must_check pci_hp_change_slot_info ( struct hotplug_slot * hotplug ,
2006-08-28 11:43:25 -07:00
struct hotplug_slot_info * info )
2005-04-16 15:20:36 -07:00
{
2008-06-10 15:28:50 -06:00
if ( ! hotplug | | ! info )
2005-04-16 15:20:36 -07:00
return - ENODEV ;
2008-06-10 15:28:50 -06:00
memcpy ( hotplug - > info , info , sizeof ( struct hotplug_slot_info ) ) ;
2005-04-16 15:20:36 -07:00
return 0 ;
}
static int __init pci_hotplug_init ( void )
{
int result ;
2007-11-01 19:41:16 -07:00
2005-04-16 15:20:36 -07:00
result = cpci_hotplug_init ( debug ) ;
if ( result ) {
err ( " cpci_hotplug_init with error %d \n " , result ) ;
2008-06-10 15:28:50 -06:00
goto err_cpci ;
2005-04-16 15:20:36 -07:00
}
info ( DRIVER_DESC " version: " DRIVER_VERSION " \n " ) ;
2007-10-29 23:22:26 -05:00
2008-06-10 15:28:50 -06:00
err_cpci :
2005-04-16 15:20:36 -07:00
return result ;
}
static void __exit pci_hotplug_exit ( void )
{
cpci_hotplug_exit ( ) ;
}
module_init ( pci_hotplug_init ) ;
module_exit ( pci_hotplug_exit ) ;
MODULE_AUTHOR ( DRIVER_AUTHOR ) ;
MODULE_DESCRIPTION ( DRIVER_DESC ) ;
MODULE_LICENSE ( " GPL " ) ;
module_param ( debug , bool , 0644 ) ;
MODULE_PARM_DESC ( debug , " Debugging mode enabled or not " ) ;
2009-06-16 11:01:25 +09:00
EXPORT_SYMBOL_GPL ( __pci_hp_register ) ;
2005-04-16 15:20:36 -07:00
EXPORT_SYMBOL_GPL ( pci_hp_deregister ) ;
EXPORT_SYMBOL_GPL ( pci_hp_change_slot_info ) ;