2005-04-17 02:20:36 +04:00
/*
* scan . c - support for transforming the ACPI namespace into individual objects
*/
# include <linux/module.h>
# include <linux/init.h>
2006-07-12 10:08:00 +04:00
# include <linux/kernel.h>
2005-04-17 02:20:36 +04:00
# include <linux/acpi.h>
# include <acpi/acpi_drivers.h>
# include <acpi/acinterp.h> /* for acpi_ex_eisa_id_to_string() */
# define _COMPONENT ACPI_BUS_COMPONENT
2007-02-13 06:42:12 +03:00
ACPI_MODULE_NAME ( " scan " ) ;
2005-04-17 02:20:36 +04:00
# define STRUCT_TO_INT(s) (*((int*)&s))
2005-08-05 08:44:28 +04:00
extern struct acpi_device * acpi_root ;
2005-04-17 02:20:36 +04:00
# define ACPI_BUS_CLASS "system_bus"
2007-07-23 16:43:51 +04:00
# define ACPI_BUS_HID "LNXSYBUS"
2005-04-17 02:20:36 +04:00
# define ACPI_BUS_DEVICE_NAME "System Bus"
static LIST_HEAD ( acpi_device_list ) ;
ACPI: use PNPID:instance_no as bus_id of ACPI device
Previously we used the device name in the DSDT, but would
crash upon encountering a duplicate. Also, exposing the
DSDT device name to the user in a patch isn't a good idea,
because it is arbitrary.
After some discussion, we finally decided to use
"PNPID:instance_no" as the bus_id of ACPI devices.
Two attributes for each device are added at the same time,
the full pathname in ACPI namespace and hardware_id if it has.
NOTE: acpi_bus_id_list is used to keep the information of PNPID
and instance number of the given PNPID. Loop the
acpi_bus_id_list to find the instance_no of the same PNPID
when register a device. If failed, i.e. we don't have a
node with this PNPID, allocate one and link it to this list.
NOTE: Now I don't take the memory free work in charge.
If necessary, I can add a reference count in
struct acpi_device_bus_id, and check the reference and
when unregister a device, i.e. memory is freed when
the reference count of a given PNPID is 0.
Signed-off-by: Li Shaohua <shaohua.li@intel.com>
Signed-off-by: Len Brown <len.brown@intel.com>
2006-12-08 12:23:43 +03:00
static LIST_HEAD ( acpi_bus_id_list ) ;
2005-04-17 02:20:36 +04:00
DEFINE_SPINLOCK ( acpi_device_lock ) ;
LIST_HEAD ( acpi_wakeup_device_list ) ;
ACPI: use PNPID:instance_no as bus_id of ACPI device
Previously we used the device name in the DSDT, but would
crash upon encountering a duplicate. Also, exposing the
DSDT device name to the user in a patch isn't a good idea,
because it is arbitrary.
After some discussion, we finally decided to use
"PNPID:instance_no" as the bus_id of ACPI devices.
Two attributes for each device are added at the same time,
the full pathname in ACPI namespace and hardware_id if it has.
NOTE: acpi_bus_id_list is used to keep the information of PNPID
and instance number of the given PNPID. Loop the
acpi_bus_id_list to find the instance_no of the same PNPID
when register a device. If failed, i.e. we don't have a
node with this PNPID, allocate one and link it to this list.
NOTE: Now I don't take the memory free work in charge.
If necessary, I can add a reference count in
struct acpi_device_bus_id, and check the reference and
when unregister a device, i.e. memory is freed when
the reference count of a given PNPID is 0.
Signed-off-by: Li Shaohua <shaohua.li@intel.com>
Signed-off-by: Len Brown <len.brown@intel.com>
2006-12-08 12:23:43 +03:00
struct acpi_device_bus_id {
2007-01-04 10:03:18 +03:00
char bus_id [ 15 ] ;
ACPI: use PNPID:instance_no as bus_id of ACPI device
Previously we used the device name in the DSDT, but would
crash upon encountering a duplicate. Also, exposing the
DSDT device name to the user in a patch isn't a good idea,
because it is arbitrary.
After some discussion, we finally decided to use
"PNPID:instance_no" as the bus_id of ACPI devices.
Two attributes for each device are added at the same time,
the full pathname in ACPI namespace and hardware_id if it has.
NOTE: acpi_bus_id_list is used to keep the information of PNPID
and instance number of the given PNPID. Loop the
acpi_bus_id_list to find the instance_no of the same PNPID
when register a device. If failed, i.e. we don't have a
node with this PNPID, allocate one and link it to this list.
NOTE: Now I don't take the memory free work in charge.
If necessary, I can add a reference count in
struct acpi_device_bus_id, and check the reference and
when unregister a device, i.e. memory is freed when
the reference count of a given PNPID is 0.
Signed-off-by: Li Shaohua <shaohua.li@intel.com>
Signed-off-by: Len Brown <len.brown@intel.com>
2006-12-08 12:23:43 +03:00
unsigned int instance_no ;
struct list_head node ;
2005-04-17 02:20:36 +04:00
} ;
2007-07-23 16:43:51 +04:00
/*
* Creates hid / cid ( s ) string needed for modalias and uevent
* e . g . on a device with hid : IBM0001 and cid : ACPI0001 you get :
* char * modalias : " acpi:IBM0001:ACPI0001 "
*/
2007-08-15 01:22:35 +04:00
static int create_modalias ( struct acpi_device * acpi_dev , char * modalias ,
int size )
{
2007-07-23 16:43:51 +04:00
int len ;
2008-03-20 11:40:32 +03:00
int count ;
2007-07-23 16:43:51 +04:00
2008-03-20 11:40:32 +03:00
if ( ! acpi_dev - > flags . hardware_id & & ! acpi_dev - > flags . compatible_ids )
2007-07-23 16:43:51 +04:00
return - ENODEV ;
2008-03-20 11:40:32 +03:00
len = snprintf ( modalias , size , " acpi: " ) ;
2007-07-23 16:43:51 +04:00
size - = len ;
2008-03-20 11:40:32 +03:00
if ( acpi_dev - > flags . hardware_id ) {
count = snprintf ( & modalias [ len ] , size , " %s: " ,
acpi_dev - > pnp . hardware_id ) ;
if ( count < 0 | | count > = size )
return - EINVAL ;
len + = count ;
size - = count ;
}
2007-07-23 16:43:51 +04:00
if ( acpi_dev - > flags . compatible_ids ) {
struct acpi_compatible_id_list * cid_list ;
int i ;
cid_list = acpi_dev - > pnp . cid_list ;
for ( i = 0 ; i < cid_list - > count ; i + + ) {
count = snprintf ( & modalias [ len ] , size , " %s: " ,
cid_list - > id [ i ] . value ) ;
if ( count < 0 | | count > = size ) {
2008-01-01 22:00:00 +03:00
printk ( KERN_ERR PREFIX " %s cid[%i] exceeds event buffer size " ,
2007-07-23 16:43:51 +04:00
acpi_dev - > pnp . device_name , i ) ;
break ;
}
len + = count ;
size - = count ;
}
}
modalias [ len ] = ' \0 ' ;
return len ;
}
static ssize_t
acpi_device_modalias_show ( struct device * dev , struct device_attribute * attr , char * buf ) {
struct acpi_device * acpi_dev = to_acpi_device ( dev ) ;
int len ;
/* Device has no HID and no CID or string is >1024 */
len = create_modalias ( acpi_dev , buf , 1024 ) ;
if ( len < = 0 )
return 0 ;
buf [ len + + ] = ' \n ' ;
return len ;
}
static DEVICE_ATTR ( modalias , 0444 , acpi_device_modalias_show , NULL ) ;
2005-08-05 08:44:28 +04:00
static int acpi_eject_operation ( acpi_handle handle , int lockable )
2005-04-17 02:20:36 +04:00
{
struct acpi_object_list arg_list ;
union acpi_object arg ;
acpi_status status = AE_OK ;
/*
* TBD : evaluate _PS3 ?
*/
if ( lockable ) {
arg_list . count = 1 ;
arg_list . pointer = & arg ;
arg . type = ACPI_TYPE_INTEGER ;
arg . integer . value = 0 ;
acpi_evaluate_object ( handle , " _LCK " , & arg_list , NULL ) ;
}
arg_list . count = 1 ;
arg_list . pointer = & arg ;
arg . type = ACPI_TYPE_INTEGER ;
arg . integer . value = 1 ;
/*
* TBD : _EJD support .
*/
status = acpi_evaluate_object ( handle , " _EJ0 " , & arg_list , NULL ) ;
if ( ACPI_FAILURE ( status ) ) {
2005-08-05 08:44:28 +04:00
return ( - ENODEV ) ;
2005-04-17 02:20:36 +04:00
}
2005-08-05 08:44:28 +04:00
return ( 0 ) ;
2005-04-17 02:20:36 +04:00
}
static ssize_t
2006-12-07 15:56:38 +03:00
acpi_eject_store ( struct device * d , struct device_attribute * attr ,
const char * buf , size_t count )
2005-04-17 02:20:36 +04:00
{
2005-08-05 08:44:28 +04:00
int result ;
int ret = count ;
int islockable ;
acpi_status status ;
acpi_handle handle ;
acpi_object_type type = 0 ;
2006-12-07 15:56:38 +03:00
struct acpi_device * acpi_device = to_acpi_device ( d ) ;
2005-04-17 02:20:36 +04:00
if ( ( ! count ) | | ( buf [ 0 ] ! = ' 1 ' ) ) {
return - EINVAL ;
}
# ifndef FORCE_EJECT
2006-12-07 15:56:38 +03:00
if ( acpi_device - > driver = = NULL ) {
2005-04-17 02:20:36 +04:00
ret = - ENODEV ;
goto err ;
}
# endif
2006-12-07 15:56:38 +03:00
status = acpi_get_type ( acpi_device - > handle , & type ) ;
if ( ACPI_FAILURE ( status ) | | ( ! acpi_device - > flags . ejectable ) ) {
2005-04-17 02:20:36 +04:00
ret = - ENODEV ;
goto err ;
}
2006-12-07 15:56:38 +03:00
islockable = acpi_device - > flags . lockable ;
handle = acpi_device - > handle ;
2006-07-12 10:08:00 +04:00
2006-12-07 15:56:38 +03:00
result = acpi_bus_trim ( acpi_device , 1 ) ;
2005-04-17 02:20:36 +04:00
if ( ! result )
result = acpi_eject_operation ( handle , islockable ) ;
if ( result ) {
ret = - EBUSY ;
}
2005-08-05 08:44:28 +04:00
err :
2005-04-17 02:20:36 +04:00
return ret ;
}
2006-12-07 15:56:38 +03:00
static DEVICE_ATTR ( eject , 0200 , NULL , acpi_eject_store ) ;
2005-04-17 02:20:36 +04:00
ACPI: use PNPID:instance_no as bus_id of ACPI device
Previously we used the device name in the DSDT, but would
crash upon encountering a duplicate. Also, exposing the
DSDT device name to the user in a patch isn't a good idea,
because it is arbitrary.
After some discussion, we finally decided to use
"PNPID:instance_no" as the bus_id of ACPI devices.
Two attributes for each device are added at the same time,
the full pathname in ACPI namespace and hardware_id if it has.
NOTE: acpi_bus_id_list is used to keep the information of PNPID
and instance number of the given PNPID. Loop the
acpi_bus_id_list to find the instance_no of the same PNPID
when register a device. If failed, i.e. we don't have a
node with this PNPID, allocate one and link it to this list.
NOTE: Now I don't take the memory free work in charge.
If necessary, I can add a reference count in
struct acpi_device_bus_id, and check the reference and
when unregister a device, i.e. memory is freed when
the reference count of a given PNPID is 0.
Signed-off-by: Li Shaohua <shaohua.li@intel.com>
Signed-off-by: Len Brown <len.brown@intel.com>
2006-12-08 12:23:43 +03:00
static ssize_t
acpi_device_hid_show ( struct device * dev , struct device_attribute * attr , char * buf ) {
struct acpi_device * acpi_dev = to_acpi_device ( dev ) ;
2005-04-17 02:20:36 +04:00
ACPI: use PNPID:instance_no as bus_id of ACPI device
Previously we used the device name in the DSDT, but would
crash upon encountering a duplicate. Also, exposing the
DSDT device name to the user in a patch isn't a good idea,
because it is arbitrary.
After some discussion, we finally decided to use
"PNPID:instance_no" as the bus_id of ACPI devices.
Two attributes for each device are added at the same time,
the full pathname in ACPI namespace and hardware_id if it has.
NOTE: acpi_bus_id_list is used to keep the information of PNPID
and instance number of the given PNPID. Loop the
acpi_bus_id_list to find the instance_no of the same PNPID
when register a device. If failed, i.e. we don't have a
node with this PNPID, allocate one and link it to this list.
NOTE: Now I don't take the memory free work in charge.
If necessary, I can add a reference count in
struct acpi_device_bus_id, and check the reference and
when unregister a device, i.e. memory is freed when
the reference count of a given PNPID is 0.
Signed-off-by: Li Shaohua <shaohua.li@intel.com>
Signed-off-by: Len Brown <len.brown@intel.com>
2006-12-08 12:23:43 +03:00
return sprintf ( buf , " %s \n " , acpi_dev - > pnp . hardware_id ) ;
2005-04-17 02:20:36 +04:00
}
ACPI: use PNPID:instance_no as bus_id of ACPI device
Previously we used the device name in the DSDT, but would
crash upon encountering a duplicate. Also, exposing the
DSDT device name to the user in a patch isn't a good idea,
because it is arbitrary.
After some discussion, we finally decided to use
"PNPID:instance_no" as the bus_id of ACPI devices.
Two attributes for each device are added at the same time,
the full pathname in ACPI namespace and hardware_id if it has.
NOTE: acpi_bus_id_list is used to keep the information of PNPID
and instance number of the given PNPID. Loop the
acpi_bus_id_list to find the instance_no of the same PNPID
when register a device. If failed, i.e. we don't have a
node with this PNPID, allocate one and link it to this list.
NOTE: Now I don't take the memory free work in charge.
If necessary, I can add a reference count in
struct acpi_device_bus_id, and check the reference and
when unregister a device, i.e. memory is freed when
the reference count of a given PNPID is 0.
Signed-off-by: Li Shaohua <shaohua.li@intel.com>
Signed-off-by: Len Brown <len.brown@intel.com>
2006-12-08 12:23:43 +03:00
static DEVICE_ATTR ( hid , 0444 , acpi_device_hid_show , NULL ) ;
2005-04-17 02:20:36 +04:00
ACPI: use PNPID:instance_no as bus_id of ACPI device
Previously we used the device name in the DSDT, but would
crash upon encountering a duplicate. Also, exposing the
DSDT device name to the user in a patch isn't a good idea,
because it is arbitrary.
After some discussion, we finally decided to use
"PNPID:instance_no" as the bus_id of ACPI devices.
Two attributes for each device are added at the same time,
the full pathname in ACPI namespace and hardware_id if it has.
NOTE: acpi_bus_id_list is used to keep the information of PNPID
and instance number of the given PNPID. Loop the
acpi_bus_id_list to find the instance_no of the same PNPID
when register a device. If failed, i.e. we don't have a
node with this PNPID, allocate one and link it to this list.
NOTE: Now I don't take the memory free work in charge.
If necessary, I can add a reference count in
struct acpi_device_bus_id, and check the reference and
when unregister a device, i.e. memory is freed when
the reference count of a given PNPID is 0.
Signed-off-by: Li Shaohua <shaohua.li@intel.com>
Signed-off-by: Len Brown <len.brown@intel.com>
2006-12-08 12:23:43 +03:00
static ssize_t
acpi_device_path_show ( struct device * dev , struct device_attribute * attr , char * buf ) {
struct acpi_device * acpi_dev = to_acpi_device ( dev ) ;
struct acpi_buffer path = { ACPI_ALLOCATE_BUFFER , NULL } ;
int result ;
2005-04-17 02:20:36 +04:00
ACPI: use PNPID:instance_no as bus_id of ACPI device
Previously we used the device name in the DSDT, but would
crash upon encountering a duplicate. Also, exposing the
DSDT device name to the user in a patch isn't a good idea,
because it is arbitrary.
After some discussion, we finally decided to use
"PNPID:instance_no" as the bus_id of ACPI devices.
Two attributes for each device are added at the same time,
the full pathname in ACPI namespace and hardware_id if it has.
NOTE: acpi_bus_id_list is used to keep the information of PNPID
and instance number of the given PNPID. Loop the
acpi_bus_id_list to find the instance_no of the same PNPID
when register a device. If failed, i.e. we don't have a
node with this PNPID, allocate one and link it to this list.
NOTE: Now I don't take the memory free work in charge.
If necessary, I can add a reference count in
struct acpi_device_bus_id, and check the reference and
when unregister a device, i.e. memory is freed when
the reference count of a given PNPID is 0.
Signed-off-by: Li Shaohua <shaohua.li@intel.com>
Signed-off-by: Len Brown <len.brown@intel.com>
2006-12-08 12:23:43 +03:00
result = acpi_get_name ( acpi_dev - > handle , ACPI_FULL_PATHNAME , & path ) ;
if ( result )
goto end ;
2005-04-17 02:20:36 +04:00
ACPI: use PNPID:instance_no as bus_id of ACPI device
Previously we used the device name in the DSDT, but would
crash upon encountering a duplicate. Also, exposing the
DSDT device name to the user in a patch isn't a good idea,
because it is arbitrary.
After some discussion, we finally decided to use
"PNPID:instance_no" as the bus_id of ACPI devices.
Two attributes for each device are added at the same time,
the full pathname in ACPI namespace and hardware_id if it has.
NOTE: acpi_bus_id_list is used to keep the information of PNPID
and instance number of the given PNPID. Loop the
acpi_bus_id_list to find the instance_no of the same PNPID
when register a device. If failed, i.e. we don't have a
node with this PNPID, allocate one and link it to this list.
NOTE: Now I don't take the memory free work in charge.
If necessary, I can add a reference count in
struct acpi_device_bus_id, and check the reference and
when unregister a device, i.e. memory is freed when
the reference count of a given PNPID is 0.
Signed-off-by: Li Shaohua <shaohua.li@intel.com>
Signed-off-by: Len Brown <len.brown@intel.com>
2006-12-08 12:23:43 +03:00
result = sprintf ( buf , " %s \n " , ( char * ) path . pointer ) ;
kfree ( path . pointer ) ;
end :
return result ;
2005-04-17 02:20:36 +04:00
}
ACPI: use PNPID:instance_no as bus_id of ACPI device
Previously we used the device name in the DSDT, but would
crash upon encountering a duplicate. Also, exposing the
DSDT device name to the user in a patch isn't a good idea,
because it is arbitrary.
After some discussion, we finally decided to use
"PNPID:instance_no" as the bus_id of ACPI devices.
Two attributes for each device are added at the same time,
the full pathname in ACPI namespace and hardware_id if it has.
NOTE: acpi_bus_id_list is used to keep the information of PNPID
and instance number of the given PNPID. Loop the
acpi_bus_id_list to find the instance_no of the same PNPID
when register a device. If failed, i.e. we don't have a
node with this PNPID, allocate one and link it to this list.
NOTE: Now I don't take the memory free work in charge.
If necessary, I can add a reference count in
struct acpi_device_bus_id, and check the reference and
when unregister a device, i.e. memory is freed when
the reference count of a given PNPID is 0.
Signed-off-by: Li Shaohua <shaohua.li@intel.com>
Signed-off-by: Len Brown <len.brown@intel.com>
2006-12-08 12:23:43 +03:00
static DEVICE_ATTR ( path , 0444 , acpi_device_path_show , NULL ) ;
2005-04-17 02:20:36 +04:00
ACPI: use PNPID:instance_no as bus_id of ACPI device
Previously we used the device name in the DSDT, but would
crash upon encountering a duplicate. Also, exposing the
DSDT device name to the user in a patch isn't a good idea,
because it is arbitrary.
After some discussion, we finally decided to use
"PNPID:instance_no" as the bus_id of ACPI devices.
Two attributes for each device are added at the same time,
the full pathname in ACPI namespace and hardware_id if it has.
NOTE: acpi_bus_id_list is used to keep the information of PNPID
and instance number of the given PNPID. Loop the
acpi_bus_id_list to find the instance_no of the same PNPID
when register a device. If failed, i.e. we don't have a
node with this PNPID, allocate one and link it to this list.
NOTE: Now I don't take the memory free work in charge.
If necessary, I can add a reference count in
struct acpi_device_bus_id, and check the reference and
when unregister a device, i.e. memory is freed when
the reference count of a given PNPID is 0.
Signed-off-by: Li Shaohua <shaohua.li@intel.com>
Signed-off-by: Len Brown <len.brown@intel.com>
2006-12-08 12:23:43 +03:00
static int acpi_device_setup_files ( struct acpi_device * dev )
2005-04-17 02:20:36 +04:00
{
2006-12-07 15:56:38 +03:00
acpi_status status ;
acpi_handle temp ;
ACPI: use PNPID:instance_no as bus_id of ACPI device
Previously we used the device name in the DSDT, but would
crash upon encountering a duplicate. Also, exposing the
DSDT device name to the user in a patch isn't a good idea,
because it is arbitrary.
After some discussion, we finally decided to use
"PNPID:instance_no" as the bus_id of ACPI devices.
Two attributes for each device are added at the same time,
the full pathname in ACPI namespace and hardware_id if it has.
NOTE: acpi_bus_id_list is used to keep the information of PNPID
and instance number of the given PNPID. Loop the
acpi_bus_id_list to find the instance_no of the same PNPID
when register a device. If failed, i.e. we don't have a
node with this PNPID, allocate one and link it to this list.
NOTE: Now I don't take the memory free work in charge.
If necessary, I can add a reference count in
struct acpi_device_bus_id, and check the reference and
when unregister a device, i.e. memory is freed when
the reference count of a given PNPID is 0.
Signed-off-by: Li Shaohua <shaohua.li@intel.com>
Signed-off-by: Len Brown <len.brown@intel.com>
2006-12-08 12:23:43 +03:00
int result = 0 ;
2005-04-17 02:20:36 +04:00
/*
ACPI: use PNPID:instance_no as bus_id of ACPI device
Previously we used the device name in the DSDT, but would
crash upon encountering a duplicate. Also, exposing the
DSDT device name to the user in a patch isn't a good idea,
because it is arbitrary.
After some discussion, we finally decided to use
"PNPID:instance_no" as the bus_id of ACPI devices.
Two attributes for each device are added at the same time,
the full pathname in ACPI namespace and hardware_id if it has.
NOTE: acpi_bus_id_list is used to keep the information of PNPID
and instance number of the given PNPID. Loop the
acpi_bus_id_list to find the instance_no of the same PNPID
when register a device. If failed, i.e. we don't have a
node with this PNPID, allocate one and link it to this list.
NOTE: Now I don't take the memory free work in charge.
If necessary, I can add a reference count in
struct acpi_device_bus_id, and check the reference and
when unregister a device, i.e. memory is freed when
the reference count of a given PNPID is 0.
Signed-off-by: Li Shaohua <shaohua.li@intel.com>
Signed-off-by: Len Brown <len.brown@intel.com>
2006-12-08 12:23:43 +03:00
* Devices gotten from FADT don ' t have a " path " attribute
2005-04-17 02:20:36 +04:00
*/
ACPI: use PNPID:instance_no as bus_id of ACPI device
Previously we used the device name in the DSDT, but would
crash upon encountering a duplicate. Also, exposing the
DSDT device name to the user in a patch isn't a good idea,
because it is arbitrary.
After some discussion, we finally decided to use
"PNPID:instance_no" as the bus_id of ACPI devices.
Two attributes for each device are added at the same time,
the full pathname in ACPI namespace and hardware_id if it has.
NOTE: acpi_bus_id_list is used to keep the information of PNPID
and instance number of the given PNPID. Loop the
acpi_bus_id_list to find the instance_no of the same PNPID
when register a device. If failed, i.e. we don't have a
node with this PNPID, allocate one and link it to this list.
NOTE: Now I don't take the memory free work in charge.
If necessary, I can add a reference count in
struct acpi_device_bus_id, and check the reference and
when unregister a device, i.e. memory is freed when
the reference count of a given PNPID is 0.
Signed-off-by: Li Shaohua <shaohua.li@intel.com>
Signed-off-by: Len Brown <len.brown@intel.com>
2006-12-08 12:23:43 +03:00
if ( dev - > handle ) {
result = device_create_file ( & dev - > dev , & dev_attr_path ) ;
if ( result )
goto end ;
2005-04-17 02:20:36 +04:00
}
ACPI: use PNPID:instance_no as bus_id of ACPI device
Previously we used the device name in the DSDT, but would
crash upon encountering a duplicate. Also, exposing the
DSDT device name to the user in a patch isn't a good idea,
because it is arbitrary.
After some discussion, we finally decided to use
"PNPID:instance_no" as the bus_id of ACPI devices.
Two attributes for each device are added at the same time,
the full pathname in ACPI namespace and hardware_id if it has.
NOTE: acpi_bus_id_list is used to keep the information of PNPID
and instance number of the given PNPID. Loop the
acpi_bus_id_list to find the instance_no of the same PNPID
when register a device. If failed, i.e. we don't have a
node with this PNPID, allocate one and link it to this list.
NOTE: Now I don't take the memory free work in charge.
If necessary, I can add a reference count in
struct acpi_device_bus_id, and check the reference and
when unregister a device, i.e. memory is freed when
the reference count of a given PNPID is 0.
Signed-off-by: Li Shaohua <shaohua.li@intel.com>
Signed-off-by: Len Brown <len.brown@intel.com>
2006-12-08 12:23:43 +03:00
if ( dev - > flags . hardware_id ) {
result = device_create_file ( & dev - > dev , & dev_attr_hid ) ;
if ( result )
goto end ;
}
2005-04-17 02:20:36 +04:00
2007-07-23 16:43:51 +04:00
if ( dev - > flags . hardware_id | | dev - > flags . compatible_ids ) {
result = device_create_file ( & dev - > dev , & dev_attr_modalias ) ;
if ( result )
goto end ;
}
ACPI: use PNPID:instance_no as bus_id of ACPI device
Previously we used the device name in the DSDT, but would
crash upon encountering a duplicate. Also, exposing the
DSDT device name to the user in a patch isn't a good idea,
because it is arbitrary.
After some discussion, we finally decided to use
"PNPID:instance_no" as the bus_id of ACPI devices.
Two attributes for each device are added at the same time,
the full pathname in ACPI namespace and hardware_id if it has.
NOTE: acpi_bus_id_list is used to keep the information of PNPID
and instance number of the given PNPID. Loop the
acpi_bus_id_list to find the instance_no of the same PNPID
when register a device. If failed, i.e. we don't have a
node with this PNPID, allocate one and link it to this list.
NOTE: Now I don't take the memory free work in charge.
If necessary, I can add a reference count in
struct acpi_device_bus_id, and check the reference and
when unregister a device, i.e. memory is freed when
the reference count of a given PNPID is 0.
Signed-off-by: Li Shaohua <shaohua.li@intel.com>
Signed-off-by: Len Brown <len.brown@intel.com>
2006-12-08 12:23:43 +03:00
/*
* If device has _EJ0 , ' eject ' file is created that is used to trigger
* hot - removal function from userland .
*/
2006-12-07 15:56:38 +03:00
status = acpi_get_handle ( dev - > handle , " _EJ0 " , & temp ) ;
if ( ACPI_SUCCESS ( status ) )
ACPI: use PNPID:instance_no as bus_id of ACPI device
Previously we used the device name in the DSDT, but would
crash upon encountering a duplicate. Also, exposing the
DSDT device name to the user in a patch isn't a good idea,
because it is arbitrary.
After some discussion, we finally decided to use
"PNPID:instance_no" as the bus_id of ACPI devices.
Two attributes for each device are added at the same time,
the full pathname in ACPI namespace and hardware_id if it has.
NOTE: acpi_bus_id_list is used to keep the information of PNPID
and instance number of the given PNPID. Loop the
acpi_bus_id_list to find the instance_no of the same PNPID
when register a device. If failed, i.e. we don't have a
node with this PNPID, allocate one and link it to this list.
NOTE: Now I don't take the memory free work in charge.
If necessary, I can add a reference count in
struct acpi_device_bus_id, and check the reference and
when unregister a device, i.e. memory is freed when
the reference count of a given PNPID is 0.
Signed-off-by: Li Shaohua <shaohua.li@intel.com>
Signed-off-by: Len Brown <len.brown@intel.com>
2006-12-08 12:23:43 +03:00
result = device_create_file ( & dev - > dev , & dev_attr_eject ) ;
end :
return result ;
2005-04-17 02:20:36 +04:00
}
2006-12-07 15:56:38 +03:00
static void acpi_device_remove_files ( struct acpi_device * dev )
2005-04-17 02:20:36 +04:00
{
2006-12-07 15:56:38 +03:00
acpi_status status ;
acpi_handle temp ;
2005-04-17 02:20:36 +04:00
2006-12-07 15:56:38 +03:00
/*
* If device has _EJ0 , ' eject ' file is created that is used to trigger
* hot - removal function from userland .
*/
status = acpi_get_handle ( dev - > handle , " _EJ0 " , & temp ) ;
if ( ACPI_SUCCESS ( status ) )
device_remove_file ( & dev - > dev , & dev_attr_eject ) ;
2005-04-17 02:20:36 +04:00
2007-07-23 16:43:51 +04:00
if ( dev - > flags . hardware_id | | dev - > flags . compatible_ids )
device_remove_file ( & dev - > dev , & dev_attr_modalias ) ;
ACPI: use PNPID:instance_no as bus_id of ACPI device
Previously we used the device name in the DSDT, but would
crash upon encountering a duplicate. Also, exposing the
DSDT device name to the user in a patch isn't a good idea,
because it is arbitrary.
After some discussion, we finally decided to use
"PNPID:instance_no" as the bus_id of ACPI devices.
Two attributes for each device are added at the same time,
the full pathname in ACPI namespace and hardware_id if it has.
NOTE: acpi_bus_id_list is used to keep the information of PNPID
and instance number of the given PNPID. Loop the
acpi_bus_id_list to find the instance_no of the same PNPID
when register a device. If failed, i.e. we don't have a
node with this PNPID, allocate one and link it to this list.
NOTE: Now I don't take the memory free work in charge.
If necessary, I can add a reference count in
struct acpi_device_bus_id, and check the reference and
when unregister a device, i.e. memory is freed when
the reference count of a given PNPID is 0.
Signed-off-by: Li Shaohua <shaohua.li@intel.com>
Signed-off-by: Len Brown <len.brown@intel.com>
2006-12-08 12:23:43 +03:00
if ( dev - > flags . hardware_id )
device_remove_file ( & dev - > dev , & dev_attr_hid ) ;
if ( dev - > handle )
device_remove_file ( & dev - > dev , & dev_attr_path ) ;
2005-04-17 02:20:36 +04:00
}
/* --------------------------------------------------------------------------
2006-12-07 15:56:16 +03:00
ACPI Bus operations
2005-04-17 02:20:36 +04:00
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2007-07-23 16:43:51 +04:00
int acpi_match_device_ids ( struct acpi_device * device ,
const struct acpi_device_id * ids )
{
const struct acpi_device_id * id ;
if ( device - > flags . hardware_id ) {
for ( id = ids ; id - > id [ 0 ] ; id + + ) {
if ( ! strcmp ( ( char * ) id - > id , device - > pnp . hardware_id ) )
return 0 ;
}
}
if ( device - > flags . compatible_ids ) {
struct acpi_compatible_id_list * cid_list = device - > pnp . cid_list ;
int i ;
for ( id = ids ; id - > id [ 0 ] ; id + + ) {
/* compare multiple _CID entries against driver ids */
for ( i = 0 ; i < cid_list - > count ; i + + ) {
if ( ! strcmp ( ( char * ) id - > id ,
cid_list - > id [ i ] . value ) )
return 0 ;
}
}
}
return - ENOENT ;
}
EXPORT_SYMBOL ( acpi_match_device_ids ) ;
2006-12-07 15:56:31 +03:00
static void acpi_device_release ( struct device * dev )
2005-04-17 02:20:36 +04:00
{
2006-12-07 15:56:31 +03:00
struct acpi_device * acpi_dev = to_acpi_device ( dev ) ;
2005-04-17 02:20:36 +04:00
2006-12-07 15:56:31 +03:00
kfree ( acpi_dev - > pnp . cid_list ) ;
kfree ( acpi_dev ) ;
2005-04-17 02:20:36 +04:00
}
2006-12-07 15:56:27 +03:00
static int acpi_device_suspend ( struct device * dev , pm_message_t state )
2005-04-17 02:20:36 +04:00
{
2006-12-07 15:56:27 +03:00
struct acpi_device * acpi_dev = to_acpi_device ( dev ) ;
struct acpi_driver * acpi_drv = acpi_dev - > driver ;
2005-04-17 02:20:36 +04:00
2006-12-07 15:56:27 +03:00
if ( acpi_drv & & acpi_drv - > ops . suspend )
return acpi_drv - > ops . suspend ( acpi_dev , state ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2006-12-07 15:56:27 +03:00
static int acpi_device_resume ( struct device * dev )
2006-12-07 15:56:16 +03:00
{
2006-12-07 15:56:27 +03:00
struct acpi_device * acpi_dev = to_acpi_device ( dev ) ;
struct acpi_driver * acpi_drv = acpi_dev - > driver ;
2005-04-17 02:20:36 +04:00
2006-12-07 15:56:27 +03:00
if ( acpi_drv & & acpi_drv - > ops . resume )
return acpi_drv - > ops . resume ( acpi_dev ) ;
2006-06-27 08:41:40 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
2006-12-07 15:56:27 +03:00
static int acpi_bus_match ( struct device * dev , struct device_driver * drv )
2006-12-07 15:56:16 +03:00
{
2006-12-07 15:56:27 +03:00
struct acpi_device * acpi_dev = to_acpi_device ( dev ) ;
struct acpi_driver * acpi_drv = to_acpi_driver ( drv ) ;
2005-04-17 02:20:36 +04:00
2007-07-23 16:43:51 +04:00
return ! acpi_match_device_ids ( acpi_dev , acpi_drv - > ids ) ;
2006-12-07 15:56:27 +03:00
}
2005-04-17 02:20:36 +04:00
2007-08-14 17:15:12 +04:00
static int acpi_device_uevent ( struct device * dev , struct kobj_uevent_env * env )
2005-04-17 02:20:36 +04:00
{
2006-12-07 15:56:27 +03:00
struct acpi_device * acpi_dev = to_acpi_device ( dev ) ;
2007-08-14 17:15:12 +04:00
int len ;
2006-12-07 15:56:27 +03:00
2007-08-14 17:15:12 +04:00
if ( add_uevent_var ( env , " MODALIAS= " ) )
return - ENOMEM ;
len = create_modalias ( acpi_dev , & env - > buf [ env - > buflen - 1 ] ,
sizeof ( env - > buf ) - env - > buflen ) ;
if ( len > = ( sizeof ( env - > buf ) - env - > buflen ) )
return - ENOMEM ;
env - > buflen + = len ;
2006-12-07 15:56:16 +03:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
2006-12-07 15:56:27 +03:00
static int acpi_bus_driver_init ( struct acpi_device * , struct acpi_driver * ) ;
static int acpi_start_single_object ( struct acpi_device * ) ;
static int acpi_device_probe ( struct device * dev )
2005-04-17 02:20:36 +04:00
{
2006-12-07 15:56:27 +03:00
struct acpi_device * acpi_dev = to_acpi_device ( dev ) ;
struct acpi_driver * acpi_drv = to_acpi_driver ( dev - > driver ) ;
int ret ;
ret = acpi_bus_driver_init ( acpi_dev , acpi_drv ) ;
if ( ! ret ) {
2006-12-07 15:56:41 +03:00
if ( acpi_dev - > bus_ops . acpi_op_start )
acpi_start_single_object ( acpi_dev ) ;
2006-12-07 15:56:27 +03:00
ACPI_DEBUG_PRINT ( ( ACPI_DB_INFO ,
" Found driver [%s] for device [%s] \n " ,
acpi_drv - > name , acpi_dev - > pnp . bus_id ) ) ;
get_device ( dev ) ;
}
return ret ;
}
2005-04-17 02:20:36 +04:00
2006-12-07 15:56:27 +03:00
static int acpi_device_remove ( struct device * dev )
{
struct acpi_device * acpi_dev = to_acpi_device ( dev ) ;
struct acpi_driver * acpi_drv = acpi_dev - > driver ;
if ( acpi_drv ) {
if ( acpi_drv - > ops . stop )
2006-12-07 15:56:46 +03:00
acpi_drv - > ops . stop ( acpi_dev , acpi_dev - > removal_type ) ;
2006-12-07 15:56:27 +03:00
if ( acpi_drv - > ops . remove )
2006-12-07 15:56:46 +03:00
acpi_drv - > ops . remove ( acpi_dev , acpi_dev - > removal_type ) ;
2005-04-17 02:20:36 +04:00
}
2006-12-07 15:56:27 +03:00
acpi_dev - > driver = NULL ;
acpi_driver_data ( dev ) = NULL ;
2005-04-17 02:20:36 +04:00
2006-12-07 15:56:27 +03:00
put_device ( dev ) ;
2006-12-07 15:56:16 +03:00
return 0 ;
}
2005-04-17 02:20:36 +04:00
2006-12-07 15:56:27 +03:00
static void acpi_device_shutdown ( struct device * dev )
2005-04-17 02:20:36 +04:00
{
2006-12-07 15:56:27 +03:00
struct acpi_device * acpi_dev = to_acpi_device ( dev ) ;
struct acpi_driver * acpi_drv = acpi_dev - > driver ;
2005-04-17 02:20:36 +04:00
2006-12-07 15:56:27 +03:00
if ( acpi_drv & & acpi_drv - > ops . shutdown )
acpi_drv - > ops . shutdown ( acpi_dev ) ;
2005-04-17 02:20:36 +04:00
2006-12-07 15:56:27 +03:00
return ;
2005-04-17 02:20:36 +04:00
}
2007-05-08 11:28:35 +04:00
struct bus_type acpi_bus_type = {
2006-12-07 15:56:16 +03:00
. name = " acpi " ,
. suspend = acpi_device_suspend ,
. resume = acpi_device_resume ,
2006-12-07 15:56:27 +03:00
. shutdown = acpi_device_shutdown ,
. match = acpi_bus_match ,
. probe = acpi_device_probe ,
. remove = acpi_device_remove ,
. uevent = acpi_device_uevent ,
2006-12-07 15:56:16 +03:00
} ;
ACPI: use PNPID:instance_no as bus_id of ACPI device
Previously we used the device name in the DSDT, but would
crash upon encountering a duplicate. Also, exposing the
DSDT device name to the user in a patch isn't a good idea,
because it is arbitrary.
After some discussion, we finally decided to use
"PNPID:instance_no" as the bus_id of ACPI devices.
Two attributes for each device are added at the same time,
the full pathname in ACPI namespace and hardware_id if it has.
NOTE: acpi_bus_id_list is used to keep the information of PNPID
and instance number of the given PNPID. Loop the
acpi_bus_id_list to find the instance_no of the same PNPID
when register a device. If failed, i.e. we don't have a
node with this PNPID, allocate one and link it to this list.
NOTE: Now I don't take the memory free work in charge.
If necessary, I can add a reference count in
struct acpi_device_bus_id, and check the reference and
when unregister a device, i.e. memory is freed when
the reference count of a given PNPID is 0.
Signed-off-by: Li Shaohua <shaohua.li@intel.com>
Signed-off-by: Len Brown <len.brown@intel.com>
2006-12-08 12:23:43 +03:00
static int acpi_device_register ( struct acpi_device * device ,
2006-12-07 15:56:16 +03:00
struct acpi_device * parent )
2005-04-17 02:20:36 +04:00
{
2005-08-05 08:44:28 +04:00
int result ;
ACPI: use PNPID:instance_no as bus_id of ACPI device
Previously we used the device name in the DSDT, but would
crash upon encountering a duplicate. Also, exposing the
DSDT device name to the user in a patch isn't a good idea,
because it is arbitrary.
After some discussion, we finally decided to use
"PNPID:instance_no" as the bus_id of ACPI devices.
Two attributes for each device are added at the same time,
the full pathname in ACPI namespace and hardware_id if it has.
NOTE: acpi_bus_id_list is used to keep the information of PNPID
and instance number of the given PNPID. Loop the
acpi_bus_id_list to find the instance_no of the same PNPID
when register a device. If failed, i.e. we don't have a
node with this PNPID, allocate one and link it to this list.
NOTE: Now I don't take the memory free work in charge.
If necessary, I can add a reference count in
struct acpi_device_bus_id, and check the reference and
when unregister a device, i.e. memory is freed when
the reference count of a given PNPID is 0.
Signed-off-by: Li Shaohua <shaohua.li@intel.com>
Signed-off-by: Len Brown <len.brown@intel.com>
2006-12-08 12:23:43 +03:00
struct acpi_device_bus_id * acpi_device_bus_id , * new_bus_id ;
int found = 0 ;
2006-12-07 15:56:16 +03:00
/*
* Linkage
* - - - - - - -
* Link this device to its parent and siblings .
*/
INIT_LIST_HEAD ( & device - > children ) ;
INIT_LIST_HEAD ( & device - > node ) ;
INIT_LIST_HEAD ( & device - > g_list ) ;
INIT_LIST_HEAD ( & device - > wakeup_list ) ;
2005-04-17 02:20:36 +04:00
ACPI: use PNPID:instance_no as bus_id of ACPI device
Previously we used the device name in the DSDT, but would
crash upon encountering a duplicate. Also, exposing the
DSDT device name to the user in a patch isn't a good idea,
because it is arbitrary.
After some discussion, we finally decided to use
"PNPID:instance_no" as the bus_id of ACPI devices.
Two attributes for each device are added at the same time,
the full pathname in ACPI namespace and hardware_id if it has.
NOTE: acpi_bus_id_list is used to keep the information of PNPID
and instance number of the given PNPID. Loop the
acpi_bus_id_list to find the instance_no of the same PNPID
when register a device. If failed, i.e. we don't have a
node with this PNPID, allocate one and link it to this list.
NOTE: Now I don't take the memory free work in charge.
If necessary, I can add a reference count in
struct acpi_device_bus_id, and check the reference and
when unregister a device, i.e. memory is freed when
the reference count of a given PNPID is 0.
Signed-off-by: Li Shaohua <shaohua.li@intel.com>
Signed-off-by: Len Brown <len.brown@intel.com>
2006-12-08 12:23:43 +03:00
new_bus_id = kzalloc ( sizeof ( struct acpi_device_bus_id ) , GFP_KERNEL ) ;
if ( ! new_bus_id ) {
printk ( KERN_ERR PREFIX " Memory allocation error \n " ) ;
return - ENOMEM ;
2005-04-17 02:20:36 +04:00
}
ACPI: use PNPID:instance_no as bus_id of ACPI device
Previously we used the device name in the DSDT, but would
crash upon encountering a duplicate. Also, exposing the
DSDT device name to the user in a patch isn't a good idea,
because it is arbitrary.
After some discussion, we finally decided to use
"PNPID:instance_no" as the bus_id of ACPI devices.
Two attributes for each device are added at the same time,
the full pathname in ACPI namespace and hardware_id if it has.
NOTE: acpi_bus_id_list is used to keep the information of PNPID
and instance number of the given PNPID. Loop the
acpi_bus_id_list to find the instance_no of the same PNPID
when register a device. If failed, i.e. we don't have a
node with this PNPID, allocate one and link it to this list.
NOTE: Now I don't take the memory free work in charge.
If necessary, I can add a reference count in
struct acpi_device_bus_id, and check the reference and
when unregister a device, i.e. memory is freed when
the reference count of a given PNPID is 0.
Signed-off-by: Li Shaohua <shaohua.li@intel.com>
Signed-off-by: Len Brown <len.brown@intel.com>
2006-12-08 12:23:43 +03:00
2006-12-07 15:56:16 +03:00
spin_lock ( & acpi_device_lock ) ;
ACPI: use PNPID:instance_no as bus_id of ACPI device
Previously we used the device name in the DSDT, but would
crash upon encountering a duplicate. Also, exposing the
DSDT device name to the user in a patch isn't a good idea,
because it is arbitrary.
After some discussion, we finally decided to use
"PNPID:instance_no" as the bus_id of ACPI devices.
Two attributes for each device are added at the same time,
the full pathname in ACPI namespace and hardware_id if it has.
NOTE: acpi_bus_id_list is used to keep the information of PNPID
and instance number of the given PNPID. Loop the
acpi_bus_id_list to find the instance_no of the same PNPID
when register a device. If failed, i.e. we don't have a
node with this PNPID, allocate one and link it to this list.
NOTE: Now I don't take the memory free work in charge.
If necessary, I can add a reference count in
struct acpi_device_bus_id, and check the reference and
when unregister a device, i.e. memory is freed when
the reference count of a given PNPID is 0.
Signed-off-by: Li Shaohua <shaohua.li@intel.com>
Signed-off-by: Len Brown <len.brown@intel.com>
2006-12-08 12:23:43 +03:00
/*
* Find suitable bus_id and instance number in acpi_bus_id_list
* If failed , create one and link it into acpi_bus_id_list
*/
list_for_each_entry ( acpi_device_bus_id , & acpi_bus_id_list , node ) {
2007-01-04 10:03:18 +03:00
if ( ! strcmp ( acpi_device_bus_id - > bus_id , device - > flags . hardware_id ? device - > pnp . hardware_id : " device " ) ) {
ACPI: use PNPID:instance_no as bus_id of ACPI device
Previously we used the device name in the DSDT, but would
crash upon encountering a duplicate. Also, exposing the
DSDT device name to the user in a patch isn't a good idea,
because it is arbitrary.
After some discussion, we finally decided to use
"PNPID:instance_no" as the bus_id of ACPI devices.
Two attributes for each device are added at the same time,
the full pathname in ACPI namespace and hardware_id if it has.
NOTE: acpi_bus_id_list is used to keep the information of PNPID
and instance number of the given PNPID. Loop the
acpi_bus_id_list to find the instance_no of the same PNPID
when register a device. If failed, i.e. we don't have a
node with this PNPID, allocate one and link it to this list.
NOTE: Now I don't take the memory free work in charge.
If necessary, I can add a reference count in
struct acpi_device_bus_id, and check the reference and
when unregister a device, i.e. memory is freed when
the reference count of a given PNPID is 0.
Signed-off-by: Li Shaohua <shaohua.li@intel.com>
Signed-off-by: Len Brown <len.brown@intel.com>
2006-12-08 12:23:43 +03:00
acpi_device_bus_id - > instance_no + + ;
found = 1 ;
kfree ( new_bus_id ) ;
break ;
}
2005-04-17 02:20:36 +04:00
}
ACPI: use PNPID:instance_no as bus_id of ACPI device
Previously we used the device name in the DSDT, but would
crash upon encountering a duplicate. Also, exposing the
DSDT device name to the user in a patch isn't a good idea,
because it is arbitrary.
After some discussion, we finally decided to use
"PNPID:instance_no" as the bus_id of ACPI devices.
Two attributes for each device are added at the same time,
the full pathname in ACPI namespace and hardware_id if it has.
NOTE: acpi_bus_id_list is used to keep the information of PNPID
and instance number of the given PNPID. Loop the
acpi_bus_id_list to find the instance_no of the same PNPID
when register a device. If failed, i.e. we don't have a
node with this PNPID, allocate one and link it to this list.
NOTE: Now I don't take the memory free work in charge.
If necessary, I can add a reference count in
struct acpi_device_bus_id, and check the reference and
when unregister a device, i.e. memory is freed when
the reference count of a given PNPID is 0.
Signed-off-by: Li Shaohua <shaohua.li@intel.com>
Signed-off-by: Len Brown <len.brown@intel.com>
2006-12-08 12:23:43 +03:00
if ( ! found ) {
acpi_device_bus_id = new_bus_id ;
2007-01-04 10:03:18 +03:00
strcpy ( acpi_device_bus_id - > bus_id , device - > flags . hardware_id ? device - > pnp . hardware_id : " device " ) ;
ACPI: use PNPID:instance_no as bus_id of ACPI device
Previously we used the device name in the DSDT, but would
crash upon encountering a duplicate. Also, exposing the
DSDT device name to the user in a patch isn't a good idea,
because it is arbitrary.
After some discussion, we finally decided to use
"PNPID:instance_no" as the bus_id of ACPI devices.
Two attributes for each device are added at the same time,
the full pathname in ACPI namespace and hardware_id if it has.
NOTE: acpi_bus_id_list is used to keep the information of PNPID
and instance number of the given PNPID. Loop the
acpi_bus_id_list to find the instance_no of the same PNPID
when register a device. If failed, i.e. we don't have a
node with this PNPID, allocate one and link it to this list.
NOTE: Now I don't take the memory free work in charge.
If necessary, I can add a reference count in
struct acpi_device_bus_id, and check the reference and
when unregister a device, i.e. memory is freed when
the reference count of a given PNPID is 0.
Signed-off-by: Li Shaohua <shaohua.li@intel.com>
Signed-off-by: Len Brown <len.brown@intel.com>
2006-12-08 12:23:43 +03:00
acpi_device_bus_id - > instance_no = 0 ;
list_add_tail ( & acpi_device_bus_id - > node , & acpi_bus_id_list ) ;
2005-04-17 02:20:36 +04:00
}
ACPI: use PNPID:instance_no as bus_id of ACPI device
Previously we used the device name in the DSDT, but would
crash upon encountering a duplicate. Also, exposing the
DSDT device name to the user in a patch isn't a good idea,
because it is arbitrary.
After some discussion, we finally decided to use
"PNPID:instance_no" as the bus_id of ACPI devices.
Two attributes for each device are added at the same time,
the full pathname in ACPI namespace and hardware_id if it has.
NOTE: acpi_bus_id_list is used to keep the information of PNPID
and instance number of the given PNPID. Loop the
acpi_bus_id_list to find the instance_no of the same PNPID
when register a device. If failed, i.e. we don't have a
node with this PNPID, allocate one and link it to this list.
NOTE: Now I don't take the memory free work in charge.
If necessary, I can add a reference count in
struct acpi_device_bus_id, and check the reference and
when unregister a device, i.e. memory is freed when
the reference count of a given PNPID is 0.
Signed-off-by: Li Shaohua <shaohua.li@intel.com>
Signed-off-by: Len Brown <len.brown@intel.com>
2006-12-08 12:23:43 +03:00
sprintf ( device - > dev . bus_id , " %s:%02x " , acpi_device_bus_id - > bus_id , acpi_device_bus_id - > instance_no ) ;
2005-04-17 02:20:36 +04:00
2006-12-07 15:56:16 +03:00
if ( device - > parent ) {
list_add_tail ( & device - > node , & device - > parent - > children ) ;
list_add_tail ( & device - > g_list , & device - > parent - > g_list ) ;
} else
list_add_tail ( & device - > g_list , & acpi_device_list ) ;
if ( device - > wakeup . flags . valid )
list_add_tail ( & device - > wakeup_list , & acpi_wakeup_device_list ) ;
spin_unlock ( & acpi_device_lock ) ;
2005-04-17 02:20:36 +04:00
2006-12-07 15:56:31 +03:00
if ( device - > parent )
device - > dev . parent = & parent - > dev ;
device - > dev . bus = & acpi_bus_type ;
device_initialize ( & device - > dev ) ;
device - > dev . release = & acpi_device_release ;
ACPI: use PNPID:instance_no as bus_id of ACPI device
Previously we used the device name in the DSDT, but would
crash upon encountering a duplicate. Also, exposing the
DSDT device name to the user in a patch isn't a good idea,
because it is arbitrary.
After some discussion, we finally decided to use
"PNPID:instance_no" as the bus_id of ACPI devices.
Two attributes for each device are added at the same time,
the full pathname in ACPI namespace and hardware_id if it has.
NOTE: acpi_bus_id_list is used to keep the information of PNPID
and instance number of the given PNPID. Loop the
acpi_bus_id_list to find the instance_no of the same PNPID
when register a device. If failed, i.e. we don't have a
node with this PNPID, allocate one and link it to this list.
NOTE: Now I don't take the memory free work in charge.
If necessary, I can add a reference count in
struct acpi_device_bus_id, and check the reference and
when unregister a device, i.e. memory is freed when
the reference count of a given PNPID is 0.
Signed-off-by: Li Shaohua <shaohua.li@intel.com>
Signed-off-by: Len Brown <len.brown@intel.com>
2006-12-08 12:23:43 +03:00
result = device_add ( & device - > dev ) ;
if ( result ) {
2008-01-01 22:00:00 +03:00
printk ( KERN_ERR PREFIX " Error adding device %s " , device - > dev . bus_id ) ;
ACPI: use PNPID:instance_no as bus_id of ACPI device
Previously we used the device name in the DSDT, but would
crash upon encountering a duplicate. Also, exposing the
DSDT device name to the user in a patch isn't a good idea,
because it is arbitrary.
After some discussion, we finally decided to use
"PNPID:instance_no" as the bus_id of ACPI devices.
Two attributes for each device are added at the same time,
the full pathname in ACPI namespace and hardware_id if it has.
NOTE: acpi_bus_id_list is used to keep the information of PNPID
and instance number of the given PNPID. Loop the
acpi_bus_id_list to find the instance_no of the same PNPID
when register a device. If failed, i.e. we don't have a
node with this PNPID, allocate one and link it to this list.
NOTE: Now I don't take the memory free work in charge.
If necessary, I can add a reference count in
struct acpi_device_bus_id, and check the reference and
when unregister a device, i.e. memory is freed when
the reference count of a given PNPID is 0.
Signed-off-by: Li Shaohua <shaohua.li@intel.com>
Signed-off-by: Len Brown <len.brown@intel.com>
2006-12-08 12:23:43 +03:00
goto end ;
2005-04-17 02:20:36 +04:00
}
ACPI: use PNPID:instance_no as bus_id of ACPI device
Previously we used the device name in the DSDT, but would
crash upon encountering a duplicate. Also, exposing the
DSDT device name to the user in a patch isn't a good idea,
because it is arbitrary.
After some discussion, we finally decided to use
"PNPID:instance_no" as the bus_id of ACPI devices.
Two attributes for each device are added at the same time,
the full pathname in ACPI namespace and hardware_id if it has.
NOTE: acpi_bus_id_list is used to keep the information of PNPID
and instance number of the given PNPID. Loop the
acpi_bus_id_list to find the instance_no of the same PNPID
when register a device. If failed, i.e. we don't have a
node with this PNPID, allocate one and link it to this list.
NOTE: Now I don't take the memory free work in charge.
If necessary, I can add a reference count in
struct acpi_device_bus_id, and check the reference and
when unregister a device, i.e. memory is freed when
the reference count of a given PNPID is 0.
Signed-off-by: Li Shaohua <shaohua.li@intel.com>
Signed-off-by: Len Brown <len.brown@intel.com>
2006-12-08 12:23:43 +03:00
result = acpi_device_setup_files ( device ) ;
if ( result )
ACPI_DEBUG_PRINT ( ( ACPI_DB_ERROR , " Error creating sysfs interface for device %s \n " , device - > dev . bus_id ) ) ;
2005-04-17 02:20:36 +04:00
2006-12-07 15:56:46 +03:00
device - > removal_type = ACPI_BUS_REMOVAL_NORMAL ;
2005-04-17 02:20:36 +04:00
return 0 ;
ACPI: use PNPID:instance_no as bus_id of ACPI device
Previously we used the device name in the DSDT, but would
crash upon encountering a duplicate. Also, exposing the
DSDT device name to the user in a patch isn't a good idea,
because it is arbitrary.
After some discussion, we finally decided to use
"PNPID:instance_no" as the bus_id of ACPI devices.
Two attributes for each device are added at the same time,
the full pathname in ACPI namespace and hardware_id if it has.
NOTE: acpi_bus_id_list is used to keep the information of PNPID
and instance number of the given PNPID. Loop the
acpi_bus_id_list to find the instance_no of the same PNPID
when register a device. If failed, i.e. we don't have a
node with this PNPID, allocate one and link it to this list.
NOTE: Now I don't take the memory free work in charge.
If necessary, I can add a reference count in
struct acpi_device_bus_id, and check the reference and
when unregister a device, i.e. memory is freed when
the reference count of a given PNPID is 0.
Signed-off-by: Li Shaohua <shaohua.li@intel.com>
Signed-off-by: Len Brown <len.brown@intel.com>
2006-12-08 12:23:43 +03:00
end :
spin_lock ( & acpi_device_lock ) ;
if ( device - > parent ) {
list_del ( & device - > node ) ;
list_del ( & device - > g_list ) ;
} else
list_del ( & device - > g_list ) ;
list_del ( & device - > wakeup_list ) ;
spin_unlock ( & acpi_device_lock ) ;
return result ;
2005-04-17 02:20:36 +04:00
}
2006-12-07 15:56:16 +03:00
static void acpi_device_unregister ( struct acpi_device * device , int type )
{
spin_lock ( & acpi_device_lock ) ;
if ( device - > parent ) {
list_del ( & device - > node ) ;
list_del ( & device - > g_list ) ;
} else
list_del ( & device - > g_list ) ;
2005-04-17 02:20:36 +04:00
2006-12-07 15:56:16 +03:00
list_del ( & device - > wakeup_list ) ;
spin_unlock ( & acpi_device_lock ) ;
2005-04-17 02:20:36 +04:00
2006-12-07 15:56:16 +03:00
acpi_detach_data ( device - > handle , acpi_bus_data_handler ) ;
2006-12-07 15:56:31 +03:00
2006-12-07 15:56:38 +03:00
acpi_device_remove_files ( device ) ;
2006-12-07 15:56:31 +03:00
device_unregister ( & device - > dev ) ;
2005-04-17 02:20:36 +04:00
}
2006-12-07 15:56:16 +03:00
/* --------------------------------------------------------------------------
Driver Management
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2005-04-17 02:20:36 +04:00
/**
2006-01-06 09:31:00 +03:00
* acpi_bus_driver_init - add a device to a driver
* @ device : the device to add and initialize
* @ driver : driver for the device
*
2005-04-17 02:20:36 +04:00
* Used to initialize a device via its device driver . Called whenever a
2006-12-07 15:56:31 +03:00
* driver is bound to a device . Invokes the driver ' s add ( ) ops .
2005-04-17 02:20:36 +04:00
*/
static int
2005-08-05 08:44:28 +04:00
acpi_bus_driver_init ( struct acpi_device * device , struct acpi_driver * driver )
2005-04-17 02:20:36 +04:00
{
2005-08-05 08:44:28 +04:00
int result = 0 ;
2005-04-17 02:20:36 +04:00
if ( ! device | | ! driver )
2006-06-27 08:41:40 +04:00
return - EINVAL ;
2005-04-17 02:20:36 +04:00
if ( ! driver - > ops . add )
2006-06-27 08:41:40 +04:00
return - ENOSYS ;
2005-04-17 02:20:36 +04:00
result = driver - > ops . add ( device ) ;
if ( result ) {
device - > driver = NULL ;
acpi_driver_data ( device ) = NULL ;
2006-06-27 08:41:40 +04:00
return result ;
2005-04-17 02:20:36 +04:00
}
device - > driver = driver ;
/*
* TBD - Configuration Management : Assign resources to device based
* upon possible configuration and currently allocated resources .
*/
2005-08-05 08:44:28 +04:00
ACPI_DEBUG_PRINT ( ( ACPI_DB_INFO ,
" Driver successfully bound to device \n " ) ) ;
2006-06-27 08:41:40 +04:00
return 0 ;
2005-04-28 11:25:52 +04:00
}
2005-09-03 01:16:48 +04:00
static int acpi_start_single_object ( struct acpi_device * device )
2005-04-28 11:25:52 +04:00
{
int result = 0 ;
struct acpi_driver * driver ;
if ( ! ( driver = device - > driver ) )
2006-06-27 08:41:40 +04:00
return 0 ;
2005-04-28 11:25:52 +04:00
2005-04-17 02:20:36 +04:00
if ( driver - > ops . start ) {
result = driver - > ops . start ( device ) ;
if ( result & & driver - > ops . remove )
driver - > ops . remove ( device , ACPI_BUS_REMOVAL_NORMAL ) ;
}
2006-06-27 08:41:40 +04:00
return result ;
2005-04-17 02:20:36 +04:00
}
2006-12-07 15:56:16 +03:00
/**
* acpi_bus_register_driver - register a driver with the ACPI bus
* @ driver : driver being registered
*
* Registers a driver with the ACPI bus . Searches the namespace for all
* devices that match the driver ' s criteria and binds . Returns zero for
* success or a negative error status for failure .
*/
int acpi_bus_register_driver ( struct acpi_driver * driver )
2005-04-17 02:20:36 +04:00
{
2006-12-07 15:56:31 +03:00
int ret ;
2005-04-17 02:20:36 +04:00
2006-12-07 15:56:16 +03:00
if ( acpi_disabled )
return - ENODEV ;
2006-12-07 15:56:31 +03:00
driver - > drv . name = driver - > name ;
driver - > drv . bus = & acpi_bus_type ;
driver - > drv . owner = driver - > owner ;
2005-04-17 02:20:36 +04:00
2006-12-07 15:56:31 +03:00
ret = driver_register ( & driver - > drv ) ;
return ret ;
2006-12-07 15:56:16 +03:00
}
2005-04-17 02:20:36 +04:00
2006-12-07 15:56:16 +03:00
EXPORT_SYMBOL ( acpi_bus_register_driver ) ;
/**
* acpi_bus_unregister_driver - unregisters a driver with the APIC bus
* @ driver : driver to unregister
*
* Unregisters a driver with the ACPI bus . Searches the namespace for all
* devices that match the driver ' s criteria and unbinds .
*/
void acpi_bus_unregister_driver ( struct acpi_driver * driver )
{
2006-12-07 15:56:31 +03:00
driver_unregister ( & driver - > drv ) ;
2006-12-07 15:56:16 +03:00
}
EXPORT_SYMBOL ( acpi_bus_unregister_driver ) ;
/* --------------------------------------------------------------------------
Device Enumeration
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
acpi_status
acpi_bus_get_ejd ( acpi_handle handle , acpi_handle * ejd )
{
acpi_status status ;
acpi_handle tmp ;
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER , NULL } ;
union acpi_object * obj ;
status = acpi_get_handle ( handle , " _EJD " , & tmp ) ;
if ( ACPI_FAILURE ( status ) )
return status ;
status = acpi_evaluate_object ( handle , " _EJD " , NULL , & buffer ) ;
if ( ACPI_SUCCESS ( status ) ) {
obj = buffer . pointer ;
2008-02-14 15:40:34 +03:00
status = acpi_get_handle ( ACPI_ROOT_OBJECT , obj - > string . pointer ,
ejd ) ;
2006-12-07 15:56:16 +03:00
kfree ( buffer . pointer ) ;
}
return status ;
}
EXPORT_SYMBOL_GPL ( acpi_bus_get_ejd ) ;
void acpi_bus_data_handler ( acpi_handle handle , u32 function , void * context )
{
/* TBD */
return ;
}
static int acpi_bus_get_perf_flags ( struct acpi_device * device )
{
device - > performance . state = ACPI_STATE_UNKNOWN ;
return 0 ;
}
static acpi_status
acpi_bus_extract_wakeup_device_power_package ( struct acpi_device * device ,
union acpi_object * package )
{
int i = 0 ;
union acpi_object * element = NULL ;
if ( ! device | | ! package | | ( package - > package . count < 2 ) )
return AE_BAD_PARAMETER ;
element = & ( package - > package . elements [ 0 ] ) ;
if ( ! element )
return AE_BAD_PARAMETER ;
if ( element - > type = = ACPI_TYPE_PACKAGE ) {
if ( ( element - > package . count < 2 ) | |
( element - > package . elements [ 0 ] . type ! =
ACPI_TYPE_LOCAL_REFERENCE )
| | ( element - > package . elements [ 1 ] . type ! = ACPI_TYPE_INTEGER ) )
return AE_BAD_DATA ;
device - > wakeup . gpe_device =
element - > package . elements [ 0 ] . reference . handle ;
device - > wakeup . gpe_number =
( u32 ) element - > package . elements [ 1 ] . integer . value ;
} else if ( element - > type = = ACPI_TYPE_INTEGER ) {
device - > wakeup . gpe_number = element - > integer . value ;
} else
return AE_BAD_DATA ;
element = & ( package - > package . elements [ 1 ] ) ;
if ( element - > type ! = ACPI_TYPE_INTEGER ) {
return AE_BAD_DATA ;
}
device - > wakeup . sleep_state = element - > integer . value ;
if ( ( package - > package . count - 2 ) > ACPI_MAX_HANDLES ) {
return AE_NO_MEMORY ;
}
device - > wakeup . resources . count = package - > package . count - 2 ;
for ( i = 0 ; i < device - > wakeup . resources . count ; i + + ) {
element = & ( package - > package . elements [ i + 2 ] ) ;
if ( element - > type ! = ACPI_TYPE_ANY ) {
return AE_BAD_DATA ;
2005-04-17 02:20:36 +04:00
}
2006-12-07 15:56:16 +03:00
device - > wakeup . resources . handles [ i ] = element - > reference . handle ;
2005-04-17 02:20:36 +04:00
}
2006-12-07 15:56:16 +03:00
return AE_OK ;
2005-04-17 02:20:36 +04:00
}
2006-12-07 15:56:16 +03:00
static int acpi_bus_get_wakeup_device_flags ( struct acpi_device * device )
2005-04-17 02:20:36 +04:00
{
2006-12-07 15:56:16 +03:00
acpi_status status = 0 ;
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER , NULL } ;
union acpi_object * package = NULL ;
2008-03-19 08:26:54 +03:00
union acpi_object in_arg [ 3 ] ;
struct acpi_object_list arg_list = { 3 , in_arg } ;
acpi_status psw_status = AE_OK ;
2005-04-17 02:20:36 +04:00
2007-07-23 16:43:51 +04:00
struct acpi_device_id button_device_ids [ ] = {
{ " PNP0C0D " , 0 } ,
{ " PNP0C0C " , 0 } ,
{ " PNP0C0E " , 0 } ,
{ " " , 0 } ,
} ;
2006-12-07 15:56:16 +03:00
/* _PRW */
status = acpi_evaluate_object ( device - > handle , " _PRW " , NULL , & buffer ) ;
if ( ACPI_FAILURE ( status ) ) {
ACPI_EXCEPTION ( ( AE_INFO , status , " Evaluating _PRW " ) ) ;
goto end ;
2005-04-17 02:20:36 +04:00
}
2006-12-07 15:56:16 +03:00
package = ( union acpi_object * ) buffer . pointer ;
status = acpi_bus_extract_wakeup_device_power_package ( device , package ) ;
if ( ACPI_FAILURE ( status ) ) {
ACPI_EXCEPTION ( ( AE_INFO , status , " Extracting _PRW package " ) ) ;
goto end ;
}
2005-04-17 02:20:36 +04:00
2006-12-07 15:56:16 +03:00
kfree ( buffer . pointer ) ;
2005-04-17 02:20:36 +04:00
2006-12-07 15:56:16 +03:00
device - > wakeup . flags . valid = 1 ;
2008-03-19 08:26:54 +03:00
/* Call _PSW/_DSW object to disable its ability to wake the sleeping
* system for the ACPI device with the _PRW object .
* The _PSW object is depreciated in ACPI 3.0 and is replaced by _DSW .
* So it is necessary to call _DSW object first . Only when it is not
* present will the _PSW object used .
*/
/*
* Three agruments are needed for the _DSW object .
* Argument 0 : enable / disable the wake capabilities
* When _DSW object is called to disable the wake capabilities , maybe
* the first argument is filled . The value of the other two agruments
* is meaningless .
*/
in_arg [ 0 ] . type = ACPI_TYPE_INTEGER ;
in_arg [ 0 ] . integer . value = 0 ;
in_arg [ 1 ] . type = ACPI_TYPE_INTEGER ;
in_arg [ 1 ] . integer . value = 0 ;
in_arg [ 2 ] . type = ACPI_TYPE_INTEGER ;
in_arg [ 2 ] . integer . value = 0 ;
psw_status = acpi_evaluate_object ( device - > handle , " _DSW " ,
& arg_list , NULL ) ;
if ( ACPI_FAILURE ( psw_status ) & & ( psw_status ! = AE_NOT_FOUND ) )
ACPI_DEBUG_PRINT ( ( ACPI_DB_INFO , " error in evaluate _DSW \n " ) ) ;
/*
* When the _DSW object is not present , OSPM will call _PSW object .
*/
if ( psw_status = = AE_NOT_FOUND ) {
/*
* Only one agruments is required for the _PSW object .
* agrument 0 : enable / disable the wake capabilities
*/
arg_list . count = 1 ;
in_arg [ 0 ] . integer . value = 0 ;
psw_status = acpi_evaluate_object ( device - > handle , " _PSW " ,
& arg_list , NULL ) ;
if ( ACPI_FAILURE ( psw_status ) & & ( psw_status ! = AE_NOT_FOUND ) )
ACPI_DEBUG_PRINT ( ( ACPI_DB_INFO , " error in "
" evaluate _PSW \n " ) ) ;
}
2006-12-07 15:56:16 +03:00
/* Power button, Lid switch always enable wakeup */
2007-07-23 16:43:51 +04:00
if ( ! acpi_match_device_ids ( device , button_device_ids ) )
2006-12-07 15:56:16 +03:00
device - > wakeup . flags . run_wake = 1 ;
2005-04-17 02:20:36 +04:00
2006-12-07 15:56:16 +03:00
end :
if ( ACPI_FAILURE ( status ) )
device - > flags . wake_capable = 0 ;
2006-06-27 08:41:40 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
2006-12-07 15:56:16 +03:00
static int acpi_bus_get_power_flags ( struct acpi_device * device )
2005-04-17 02:20:36 +04:00
{
2006-12-07 15:56:16 +03:00
acpi_status status = 0 ;
acpi_handle handle = NULL ;
u32 i = 0 ;
2006-03-29 02:04:00 +04:00
2005-08-05 08:44:28 +04:00
2006-12-07 15:56:16 +03:00
/*
* Power Management Flags
*/
status = acpi_get_handle ( device - > handle , " _PSC " , & handle ) ;
if ( ACPI_SUCCESS ( status ) )
device - > power . flags . explicit_get = 1 ;
status = acpi_get_handle ( device - > handle , " _IRC " , & handle ) ;
if ( ACPI_SUCCESS ( status ) )
device - > power . flags . inrush_current = 1 ;
2005-04-17 02:20:36 +04:00
2006-12-07 15:56:16 +03:00
/*
* Enumerate supported power management states
*/
for ( i = ACPI_STATE_D0 ; i < = ACPI_STATE_D3 ; i + + ) {
struct acpi_device_power_state * ps = & device - > power . states [ i ] ;
char object_name [ 5 ] = { ' _ ' , ' P ' , ' R ' , ' 0 ' + i , ' \0 ' } ;
2005-04-17 02:20:36 +04:00
2006-12-07 15:56:16 +03:00
/* Evaluate "_PRx" to se if power resources are referenced */
acpi_evaluate_reference ( device - > handle , object_name , NULL ,
& ps - > resources ) ;
if ( ps - > resources . count ) {
device - > power . flags . power_resources = 1 ;
ps - > flags . valid = 1 ;
2005-04-17 02:20:36 +04:00
}
2006-12-07 15:56:16 +03:00
/* Evaluate "_PSx" to see if we can do explicit sets */
object_name [ 2 ] = ' S ' ;
status = acpi_get_handle ( device - > handle , object_name , & handle ) ;
if ( ACPI_SUCCESS ( status ) ) {
ps - > flags . explicit_set = 1 ;
ps - > flags . valid = 1 ;
2005-04-17 02:20:36 +04:00
}
2006-12-07 15:56:16 +03:00
/* State is valid if we have some power control */
if ( ps - > resources . count | | ps - > flags . explicit_set )
ps - > flags . valid = 1 ;
2005-04-17 02:20:36 +04:00
2006-12-07 15:56:16 +03:00
ps - > power = - 1 ; /* Unknown - driver assigned */
ps - > latency = - 1 ; /* Unknown - driver assigned */
}
2005-04-17 02:20:36 +04:00
2006-12-07 15:56:16 +03:00
/* Set defaults for D0 and D3 states (always valid) */
device - > power . states [ ACPI_STATE_D0 ] . flags . valid = 1 ;
device - > power . states [ ACPI_STATE_D0 ] . power = 100 ;
device - > power . states [ ACPI_STATE_D3 ] . flags . valid = 1 ;
device - > power . states [ ACPI_STATE_D3 ] . power = 0 ;
2006-07-10 01:22:28 +04:00
2006-12-07 15:56:16 +03:00
/* TBD: System wake support and resource requirements. */
2006-07-10 01:22:28 +04:00
2006-12-07 15:56:16 +03:00
device - > power . state = ACPI_STATE_UNKNOWN ;
2006-07-10 01:22:28 +04:00
2006-12-07 15:56:16 +03:00
return 0 ;
}
2006-07-10 01:22:28 +04:00
2005-08-05 08:44:28 +04:00
static int acpi_bus_get_flags ( struct acpi_device * device )
2005-04-17 02:20:36 +04:00
{
2005-08-05 08:44:28 +04:00
acpi_status status = AE_OK ;
acpi_handle temp = NULL ;
2005-04-17 02:20:36 +04:00
/* Presence of _STA indicates 'dynamic_status' */
status = acpi_get_handle ( device - > handle , " _STA " , & temp ) ;
if ( ACPI_SUCCESS ( status ) )
device - > flags . dynamic_status = 1 ;
/* Presence of _CID indicates 'compatible_ids' */
status = acpi_get_handle ( device - > handle , " _CID " , & temp ) ;
if ( ACPI_SUCCESS ( status ) )
device - > flags . compatible_ids = 1 ;
/* Presence of _RMV indicates 'removable' */
status = acpi_get_handle ( device - > handle , " _RMV " , & temp ) ;
if ( ACPI_SUCCESS ( status ) )
device - > flags . removable = 1 ;
/* Presence of _EJD|_EJ0 indicates 'ejectable' */
status = acpi_get_handle ( device - > handle , " _EJD " , & temp ) ;
if ( ACPI_SUCCESS ( status ) )
device - > flags . ejectable = 1 ;
else {
status = acpi_get_handle ( device - > handle , " _EJ0 " , & temp ) ;
if ( ACPI_SUCCESS ( status ) )
device - > flags . ejectable = 1 ;
}
/* Presence of _LCK indicates 'lockable' */
status = acpi_get_handle ( device - > handle , " _LCK " , & temp ) ;
if ( ACPI_SUCCESS ( status ) )
device - > flags . lockable = 1 ;
/* Presence of _PS0|_PR0 indicates 'power manageable' */
status = acpi_get_handle ( device - > handle , " _PS0 " , & temp ) ;
if ( ACPI_FAILURE ( status ) )
status = acpi_get_handle ( device - > handle , " _PR0 " , & temp ) ;
if ( ACPI_SUCCESS ( status ) )
device - > flags . power_manageable = 1 ;
/* Presence of _PRW indicates wake capable */
status = acpi_get_handle ( device - > handle , " _PRW " , & temp ) ;
if ( ACPI_SUCCESS ( status ) )
device - > flags . wake_capable = 1 ;
2008-02-03 18:06:17 +03:00
/* TBD: Performance management */
2005-04-17 02:20:36 +04:00
2006-06-27 08:41:40 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
2005-08-05 08:44:28 +04:00
static void acpi_device_get_busid ( struct acpi_device * device ,
acpi_handle handle , int type )
2005-04-17 02:20:36 +04:00
{
2005-08-05 08:44:28 +04:00
char bus_id [ 5 ] = { ' ? ' , 0 } ;
struct acpi_buffer buffer = { sizeof ( bus_id ) , bus_id } ;
int i = 0 ;
2005-04-17 02:20:36 +04:00
/*
* Bus ID
* - - - - - -
* The device ' s Bus ID is simply the object name .
* TBD : Shouldn ' t this value be unique ( within the ACPI namespace ) ?
*/
switch ( type ) {
case ACPI_BUS_TYPE_SYSTEM :
strcpy ( device - > pnp . bus_id , " ACPI " ) ;
break ;
case ACPI_BUS_TYPE_POWER_BUTTON :
strcpy ( device - > pnp . bus_id , " PWRF " ) ;
break ;
case ACPI_BUS_TYPE_SLEEP_BUTTON :
strcpy ( device - > pnp . bus_id , " SLPF " ) ;
break ;
default :
acpi_get_name ( handle , ACPI_SINGLE_NAME , & buffer ) ;
/* Clean up trailing underscores (if any) */
for ( i = 3 ; i > 1 ; i - - ) {
if ( bus_id [ i ] = = ' _ ' )
bus_id [ i ] = ' \0 ' ;
else
break ;
}
strcpy ( device - > pnp . bus_id , bus_id ) ;
break ;
}
}
2006-12-07 15:57:10 +03:00
static int
acpi_video_bus_match ( struct acpi_device * device )
{
acpi_handle h_dummy1 ;
acpi_handle h_dummy2 ;
acpi_handle h_dummy3 ;
if ( ! device )
return - EINVAL ;
/* Since there is no HID, CID for ACPI Video drivers, we have
* to check well known required nodes for each feature we support .
*/
/* Does this device able to support video switching ? */
if ( ACPI_SUCCESS ( acpi_get_handle ( device - > handle , " _DOD " , & h_dummy1 ) ) & &
ACPI_SUCCESS ( acpi_get_handle ( device - > handle , " _DOS " , & h_dummy2 ) ) )
return 0 ;
/* Does this device able to retrieve a video ROM ? */
if ( ACPI_SUCCESS ( acpi_get_handle ( device - > handle , " _ROM " , & h_dummy1 ) ) )
return 0 ;
/* Does this device able to configure which video head to be POSTed ? */
if ( ACPI_SUCCESS ( acpi_get_handle ( device - > handle , " _VPO " , & h_dummy1 ) ) & &
ACPI_SUCCESS ( acpi_get_handle ( device - > handle , " _GPD " , & h_dummy2 ) ) & &
ACPI_SUCCESS ( acpi_get_handle ( device - > handle , " _SPD " , & h_dummy3 ) ) )
return 0 ;
return - ENODEV ;
}
2007-01-11 10:09:09 +03:00
/*
* acpi_bay_match - see if a device is an ejectable driver bay
*
* If an acpi object is ejectable and has one of the ACPI ATA methods defined ,
* then we can safely call it an ejectable drive bay
*/
static int acpi_bay_match ( struct acpi_device * device ) {
acpi_status status ;
acpi_handle handle ;
acpi_handle tmp ;
acpi_handle phandle ;
handle = device - > handle ;
status = acpi_get_handle ( handle , " _EJ0 " , & tmp ) ;
if ( ACPI_FAILURE ( status ) )
return - ENODEV ;
if ( ( ACPI_SUCCESS ( acpi_get_handle ( handle , " _GTF " , & tmp ) ) ) | |
( ACPI_SUCCESS ( acpi_get_handle ( handle , " _GTM " , & tmp ) ) ) | |
( ACPI_SUCCESS ( acpi_get_handle ( handle , " _STM " , & tmp ) ) ) | |
( ACPI_SUCCESS ( acpi_get_handle ( handle , " _SDD " , & tmp ) ) ) )
return 0 ;
if ( acpi_get_parent ( handle , & phandle ) )
return - ENODEV ;
if ( ( ACPI_SUCCESS ( acpi_get_handle ( phandle , " _GTF " , & tmp ) ) ) | |
( ACPI_SUCCESS ( acpi_get_handle ( phandle , " _GTM " , & tmp ) ) ) | |
( ACPI_SUCCESS ( acpi_get_handle ( phandle , " _STM " , & tmp ) ) ) | |
( ACPI_SUCCESS ( acpi_get_handle ( phandle , " _SDD " , & tmp ) ) ) )
return 0 ;
return - ENODEV ;
}
2007-12-07 15:20:34 +03:00
/*
* acpi_dock_match - see if a device has a _DCK method
*/
static int acpi_dock_match ( struct acpi_device * device )
{
acpi_handle tmp ;
return acpi_get_handle ( device - > handle , " _DCK " , & tmp ) ;
}
2005-08-05 08:44:28 +04:00
static void acpi_device_set_id ( struct acpi_device * device ,
struct acpi_device * parent , acpi_handle handle ,
int type )
2005-04-17 02:20:36 +04:00
{
2005-08-05 08:44:28 +04:00
struct acpi_device_info * info ;
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER , NULL } ;
char * hid = NULL ;
char * uid = NULL ;
2005-04-17 02:20:36 +04:00
struct acpi_compatible_id_list * cid_list = NULL ;
2007-12-07 15:20:34 +03:00
const char * cid_add = NULL ;
2005-08-05 08:44:28 +04:00
acpi_status status ;
2005-04-17 02:20:36 +04:00
switch ( type ) {
case ACPI_BUS_TYPE_DEVICE :
status = acpi_get_object_info ( handle , & buffer ) ;
if ( ACPI_FAILURE ( status ) ) {
2008-03-06 05:24:51 +03:00
printk ( KERN_ERR PREFIX " %s: Error reading device info \n " , __func__ ) ;
2005-04-17 02:20:36 +04:00
return ;
}
info = buffer . pointer ;
if ( info - > valid & ACPI_VALID_HID )
hid = info - > hardware_id . value ;
if ( info - > valid & ACPI_VALID_UID )
uid = info - > unique_id . value ;
if ( info - > valid & ACPI_VALID_CID )
cid_list = & info - > compatibility_id ;
if ( info - > valid & ACPI_VALID_ADR ) {
device - > pnp . bus_address = info - > address ;
device - > flags . bus_address = 1 ;
}
2006-12-07 15:57:10 +03:00
2007-12-07 15:20:34 +03:00
/* If we have a video/bay/dock device, add our selfdefined
HID to the CID list . Like that the video / bay / dock drivers
will get autoloaded and the device might still match
against another driver .
*/
if ( ACPI_SUCCESS ( acpi_video_bus_match ( device ) ) )
cid_add = ACPI_VIDEO_HID ;
else if ( ACPI_SUCCESS ( acpi_bay_match ( device ) ) )
cid_add = ACPI_BAY_HID ;
else if ( ACPI_SUCCESS ( acpi_dock_match ( device ) ) )
cid_add = ACPI_DOCK_HID ;
2007-01-11 10:09:09 +03:00
2005-04-17 02:20:36 +04:00
break ;
case ACPI_BUS_TYPE_POWER :
hid = ACPI_POWER_HID ;
break ;
case ACPI_BUS_TYPE_PROCESSOR :
hid = ACPI_PROCESSOR_HID ;
break ;
case ACPI_BUS_TYPE_SYSTEM :
hid = ACPI_SYSTEM_HID ;
break ;
case ACPI_BUS_TYPE_THERMAL :
hid = ACPI_THERMAL_HID ;
break ;
case ACPI_BUS_TYPE_POWER_BUTTON :
hid = ACPI_BUTTON_HID_POWERF ;
break ;
case ACPI_BUS_TYPE_SLEEP_BUTTON :
hid = ACPI_BUTTON_HID_SLEEPF ;
break ;
}
/*
* \ _SB
* - - - -
* Fix for the system root bus device - - the only root - level device .
*/
2005-11-17 21:07:00 +03:00
if ( ( ( acpi_handle ) parent = = ACPI_ROOT_OBJECT ) & & ( type = = ACPI_BUS_TYPE_DEVICE ) ) {
2005-04-17 02:20:36 +04:00
hid = ACPI_BUS_HID ;
strcpy ( device - > pnp . device_name , ACPI_BUS_DEVICE_NAME ) ;
strcpy ( device - > pnp . device_class , ACPI_BUS_CLASS ) ;
}
if ( hid ) {
strcpy ( device - > pnp . hardware_id , hid ) ;
device - > flags . hardware_id = 1 ;
}
if ( uid ) {
strcpy ( device - > pnp . unique_id , uid ) ;
device - > flags . unique_id = 1 ;
}
2007-12-07 15:20:34 +03:00
if ( cid_list | | cid_add ) {
struct acpi_compatible_id_list * list ;
int size = 0 ;
int count = 0 ;
if ( cid_list ) {
size = cid_list - > size ;
} else if ( cid_add ) {
size = sizeof ( struct acpi_compatible_id_list ) ;
cid_list = ACPI_ALLOCATE_ZEROED ( ( acpi_size ) size ) ;
if ( ! cid_list ) {
printk ( KERN_ERR " Memory allocation error \n " ) ;
kfree ( buffer . pointer ) ;
return ;
} else {
cid_list - > count = 0 ;
cid_list - > size = size ;
}
}
if ( cid_add )
size + = sizeof ( struct acpi_compatible_id ) ;
list = kmalloc ( size , GFP_KERNEL ) ;
if ( list ) {
if ( cid_list ) {
memcpy ( list , cid_list , cid_list - > size ) ;
count = cid_list - > count ;
}
if ( cid_add ) {
strncpy ( list - > id [ count ] . value , cid_add ,
ACPI_MAX_CID_LENGTH ) ;
count + + ;
device - > flags . compatible_ids = 1 ;
}
list - > size = size ;
list - > count = count ;
device - > pnp . cid_list = list ;
} else
2008-01-01 22:00:00 +03:00
printk ( KERN_ERR PREFIX " Memory allocation error \n " ) ;
2005-04-17 02:20:36 +04:00
}
2006-06-30 11:19:10 +04:00
kfree ( buffer . pointer ) ;
2005-04-17 02:20:36 +04:00
}
2005-08-05 08:44:28 +04:00
static int acpi_device_set_context ( struct acpi_device * device , int type )
2005-04-17 02:20:36 +04:00
{
acpi_status status = AE_OK ;
int result = 0 ;
/*
* Context
* - - - - - - -
* Attach this ' struct acpi_device ' to the ACPI object . This makes
* resolutions from handle - > device very efficient . Note that we need
* to be careful with fixed - feature devices as they all attach to the
* root object .
*/
2005-08-05 08:44:28 +04:00
if ( type ! = ACPI_BUS_TYPE_POWER_BUTTON & &
2005-04-17 02:20:36 +04:00
type ! = ACPI_BUS_TYPE_SLEEP_BUTTON ) {
status = acpi_attach_data ( device - > handle ,
2005-08-05 08:44:28 +04:00
acpi_bus_data_handler , device ) ;
2005-04-17 02:20:36 +04:00
if ( ACPI_FAILURE ( status ) ) {
2008-01-01 22:00:00 +03:00
printk ( KERN_ERR PREFIX " Error attaching device data \n " ) ;
2005-04-17 02:20:36 +04:00
result = - ENODEV ;
}
}
return result ;
}
2005-08-05 08:44:28 +04:00
static int acpi_bus_remove ( struct acpi_device * dev , int rmdevice )
2005-04-17 02:20:36 +04:00
{
if ( ! dev )
2006-06-27 08:41:40 +04:00
return - EINVAL ;
2005-04-17 02:20:36 +04:00
2006-12-07 15:56:46 +03:00
dev - > removal_type = ACPI_BUS_REMOVAL_EJECT ;
2006-12-07 15:56:31 +03:00
device_release_driver ( & dev - > dev ) ;
2005-04-17 02:20:36 +04:00
if ( ! rmdevice )
2006-06-27 08:41:40 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
2006-12-21 10:21:13 +03:00
/*
* unbind _ADR - Based Devices when hot removal
*/
2005-04-17 02:20:36 +04:00
if ( dev - > flags . bus_address ) {
if ( ( dev - > parent ) & & ( dev - > parent - > ops . unbind ) )
dev - > parent - > ops . unbind ( dev ) ;
}
acpi_device_unregister ( dev , ACPI_BUS_REMOVAL_EJECT ) ;
2006-06-27 08:41:40 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
2007-12-07 15:20:34 +03:00
static int
acpi_is_child_device ( struct acpi_device * device ,
int ( * matcher ) ( struct acpi_device * ) )
{
int result = - ENODEV ;
do {
if ( ACPI_SUCCESS ( matcher ( device ) ) )
return AE_OK ;
} while ( ( device = device - > parent ) ) ;
return result ;
}
2005-04-28 11:25:52 +04:00
static int
2005-08-05 08:44:28 +04:00
acpi_add_single_object ( struct acpi_device * * child ,
2006-12-07 15:56:41 +03:00
struct acpi_device * parent , acpi_handle handle , int type ,
struct acpi_bus_ops * ops )
2005-04-17 02:20:36 +04:00
{
2005-08-05 08:44:28 +04:00
int result = 0 ;
struct acpi_device * device = NULL ;
2005-04-17 02:20:36 +04:00
if ( ! child )
2006-06-27 08:41:40 +04:00
return - EINVAL ;
2005-04-17 02:20:36 +04:00
2006-12-19 23:56:11 +03:00
device = kzalloc ( sizeof ( struct acpi_device ) , GFP_KERNEL ) ;
2005-04-17 02:20:36 +04:00
if ( ! device ) {
2006-06-27 07:41:38 +04:00
printk ( KERN_ERR PREFIX " Memory allocation error \n " ) ;
2006-06-27 08:41:40 +04:00
return - ENOMEM ;
2005-04-17 02:20:36 +04:00
}
device - > handle = handle ;
device - > parent = parent ;
2006-12-07 15:56:41 +03:00
device - > bus_ops = * ops ; /* workround for not call .start */
2005-04-17 02:20:36 +04:00
2005-08-05 08:44:28 +04:00
acpi_device_get_busid ( device , handle , type ) ;
2005-04-17 02:20:36 +04:00
/*
* Flags
* - - - - -
* Get prior to calling acpi_bus_get_status ( ) so we know whether
* or not _STA is present . Note that we only look for object
* handles - - cannot evaluate objects until we know the device is
* present and properly initialized .
*/
result = acpi_bus_get_flags ( device ) ;
if ( result )
goto end ;
/*
* Status
* - - - - - -
2005-03-31 08:15:47 +04:00
* See if the device is present . We always assume that non - Device
* and non - Processor objects ( e . g . thermal zones , power resources ,
* etc . ) are present , functioning , etc . ( at least when parent object
* is present ) . Note that _STA has a different meaning for some
* objects ( e . g . power resources ) so we need to be careful how we use
* it .
2005-04-17 02:20:36 +04:00
*/
switch ( type ) {
2005-03-31 08:15:47 +04:00
case ACPI_BUS_TYPE_PROCESSOR :
2005-04-17 02:20:36 +04:00
case ACPI_BUS_TYPE_DEVICE :
result = acpi_bus_get_status ( device ) ;
2007-12-07 15:20:34 +03:00
if ( ACPI_FAILURE ( result ) ) {
result = - ENODEV ;
2005-04-17 02:20:36 +04:00
goto end ;
}
2007-12-07 15:20:34 +03:00
if ( ! device - > status . present ) {
/* Bay and dock should be handled even if absent */
if ( ! ACPI_SUCCESS (
acpi_is_child_device ( device , acpi_bay_match ) ) & &
! ACPI_SUCCESS (
acpi_is_child_device ( device , acpi_dock_match ) ) ) {
result = - ENODEV ;
goto end ;
}
}
2005-04-17 02:20:36 +04:00
break ;
default :
2007-04-25 22:20:58 +04:00
STRUCT_TO_INT ( device - > status ) =
ACPI_STA_DEVICE_PRESENT | ACPI_STA_DEVICE_ENABLED |
ACPI_STA_DEVICE_UI | ACPI_STA_DEVICE_FUNCTIONING ;
2005-04-17 02:20:36 +04:00
break ;
}
/*
* Initialize Device
* - - - - - - - - - - - - - - - - -
* TBD : Synch with Core ' s enumeration / initialization process .
*/
/*
* Hardware ID , Unique ID , & Bus Address
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
2005-08-05 08:44:28 +04:00
acpi_device_set_id ( device , parent , handle , type ) ;
2005-04-17 02:20:36 +04:00
/*
* Power Management
* - - - - - - - - - - - - - - - -
*/
if ( device - > flags . power_manageable ) {
result = acpi_bus_get_power_flags ( device ) ;
if ( result )
goto end ;
}
2005-08-05 08:44:28 +04:00
/*
2005-04-17 02:20:36 +04:00
* Wakeup device management
* - - - - - - - - - - - - - - - - - - - - - - -
*/
if ( device - > flags . wake_capable ) {
result = acpi_bus_get_wakeup_device_flags ( device ) ;
if ( result )
goto end ;
}
/*
* Performance Management
* - - - - - - - - - - - - - - - - - - - - - -
*/
if ( device - > flags . performance_manageable ) {
result = acpi_bus_get_perf_flags ( device ) ;
if ( result )
goto end ;
}
2005-08-05 08:44:28 +04:00
if ( ( result = acpi_device_set_context ( device , type ) ) )
2005-04-17 02:20:36 +04:00
goto end ;
ACPI: use PNPID:instance_no as bus_id of ACPI device
Previously we used the device name in the DSDT, but would
crash upon encountering a duplicate. Also, exposing the
DSDT device name to the user in a patch isn't a good idea,
because it is arbitrary.
After some discussion, we finally decided to use
"PNPID:instance_no" as the bus_id of ACPI devices.
Two attributes for each device are added at the same time,
the full pathname in ACPI namespace and hardware_id if it has.
NOTE: acpi_bus_id_list is used to keep the information of PNPID
and instance number of the given PNPID. Loop the
acpi_bus_id_list to find the instance_no of the same PNPID
when register a device. If failed, i.e. we don't have a
node with this PNPID, allocate one and link it to this list.
NOTE: Now I don't take the memory free work in charge.
If necessary, I can add a reference count in
struct acpi_device_bus_id, and check the reference and
when unregister a device, i.e. memory is freed when
the reference count of a given PNPID is 0.
Signed-off-by: Li Shaohua <shaohua.li@intel.com>
Signed-off-by: Len Brown <len.brown@intel.com>
2006-12-08 12:23:43 +03:00
result = acpi_device_register ( device , parent ) ;
2005-04-17 02:20:36 +04:00
/*
2006-12-21 10:21:13 +03:00
* Bind _ADR - Based Devices when hot add
2005-04-17 02:20:36 +04:00
*/
if ( device - > flags . bus_address ) {
if ( device - > parent & & device - > parent - > ops . bind )
device - > parent - > ops . bind ( device ) ;
}
2005-08-05 08:44:28 +04:00
end :
2005-04-17 02:20:36 +04:00
if ( ! result )
* child = device ;
else {
2005-11-07 12:01:32 +03:00
kfree ( device - > pnp . cid_list ) ;
2005-04-17 02:20:36 +04:00
kfree ( device ) ;
}
2006-06-27 08:41:40 +04:00
return result ;
2005-04-17 02:20:36 +04:00
}
2005-08-05 08:44:28 +04:00
static int acpi_bus_scan ( struct acpi_device * start , struct acpi_bus_ops * ops )
2005-04-17 02:20:36 +04:00
{
2005-08-05 08:44:28 +04:00
acpi_status status = AE_OK ;
struct acpi_device * parent = NULL ;
struct acpi_device * child = NULL ;
acpi_handle phandle = NULL ;
acpi_handle chandle = NULL ;
acpi_object_type type = 0 ;
u32 level = 1 ;
2005-04-17 02:20:36 +04:00
if ( ! start )
2006-06-27 08:41:40 +04:00
return - EINVAL ;
2005-04-17 02:20:36 +04:00
parent = start ;
phandle = start - > handle ;
2005-08-05 08:44:28 +04:00
2005-04-17 02:20:36 +04:00
/*
* Parse through the ACPI namespace , identify all ' devices ' , and
* create a new ' struct acpi_device ' for each .
*/
while ( ( level > 0 ) & & parent ) {
status = acpi_get_next_object ( ACPI_TYPE_ANY , phandle ,
2005-08-05 08:44:28 +04:00
chandle , & chandle ) ;
2005-04-17 02:20:36 +04:00
/*
* If this scope is exhausted then move our way back up .
*/
if ( ACPI_FAILURE ( status ) ) {
level - - ;
chandle = phandle ;
acpi_get_parent ( phandle , & phandle ) ;
if ( parent - > parent )
parent = parent - > parent ;
continue ;
}
status = acpi_get_type ( chandle , & type ) ;
if ( ACPI_FAILURE ( status ) )
continue ;
/*
* If this is a scope object then parse it ( depth - first ) .
*/
if ( type = = ACPI_TYPE_LOCAL_SCOPE ) {
level + + ;
phandle = chandle ;
chandle = NULL ;
continue ;
}
/*
* We ' re only interested in objects that we consider ' devices ' .
*/
switch ( type ) {
case ACPI_TYPE_DEVICE :
type = ACPI_BUS_TYPE_DEVICE ;
break ;
case ACPI_TYPE_PROCESSOR :
type = ACPI_BUS_TYPE_PROCESSOR ;
break ;
case ACPI_TYPE_THERMAL :
type = ACPI_BUS_TYPE_THERMAL ;
break ;
case ACPI_TYPE_POWER :
type = ACPI_BUS_TYPE_POWER ;
break ;
default :
continue ;
}
2005-04-28 11:25:52 +04:00
if ( ops - > acpi_op_add )
status = acpi_add_single_object ( & child , parent ,
2006-12-07 15:56:41 +03:00
chandle , type , ops ) ;
2005-08-05 08:44:28 +04:00
else
2005-04-28 11:25:52 +04:00
status = acpi_bus_get_device ( chandle , & child ) ;
2005-08-05 08:44:28 +04:00
if ( ACPI_FAILURE ( status ) )
continue ;
2005-04-28 11:25:52 +04:00
2006-12-07 15:56:41 +03:00
if ( ops - > acpi_op_start & & ! ( ops - > acpi_op_add ) ) {
2005-04-28 11:25:52 +04:00
status = acpi_start_single_object ( child ) ;
if ( ACPI_FAILURE ( status ) )
continue ;
}
2005-04-17 02:20:36 +04:00
/*
* If the device is present , enabled , and functioning then
* parse its scope ( depth - first ) . Note that we need to
* represent absent devices to facilitate PnP notifications
* - - but only the subtree head ( not all of its children ,
* which will be enumerated when the parent is inserted ) .
*
* TBD : Need notifications and other detection mechanisms
2005-08-05 08:44:28 +04:00
* in place before we can fully implement this .
2005-04-17 02:20:36 +04:00
*/
if ( child - > status . present ) {
status = acpi_get_next_object ( ACPI_TYPE_ANY , chandle ,
NULL , NULL ) ;
if ( ACPI_SUCCESS ( status ) ) {
level + + ;
phandle = chandle ;
chandle = NULL ;
parent = child ;
}
}
}
2006-06-27 08:41:40 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
2005-04-28 11:25:52 +04:00
int
2005-08-05 08:44:28 +04:00
acpi_bus_add ( struct acpi_device * * child ,
struct acpi_device * parent , acpi_handle handle , int type )
2005-04-28 11:25:52 +04:00
{
int result ;
struct acpi_bus_ops ops ;
2006-12-07 15:56:41 +03:00
memset ( & ops , 0 , sizeof ( ops ) ) ;
ops . acpi_op_add = 1 ;
2005-04-28 11:25:52 +04:00
2006-12-07 15:56:41 +03:00
result = acpi_add_single_object ( child , parent , handle , type , & ops ) ;
if ( ! result )
2005-04-28 11:25:52 +04:00
result = acpi_bus_scan ( * child , & ops ) ;
2006-12-07 15:56:41 +03:00
2006-06-27 08:41:40 +04:00
return result ;
2005-04-28 11:25:52 +04:00
}
2005-08-05 08:44:28 +04:00
2005-04-28 11:25:52 +04:00
EXPORT_SYMBOL ( acpi_bus_add ) ;
2005-08-05 08:44:28 +04:00
int acpi_bus_start ( struct acpi_device * device )
2005-04-28 11:25:52 +04:00
{
int result ;
struct acpi_bus_ops ops ;
if ( ! device )
2006-06-27 08:41:40 +04:00
return - EINVAL ;
2005-04-28 11:25:52 +04:00
result = acpi_start_single_object ( device ) ;
if ( ! result ) {
memset ( & ops , 0 , sizeof ( ops ) ) ;
ops . acpi_op_start = 1 ;
result = acpi_bus_scan ( device , & ops ) ;
}
2006-06-27 08:41:40 +04:00
return result ;
2005-04-28 11:25:52 +04:00
}
2005-08-05 08:44:28 +04:00
2005-04-28 11:25:52 +04:00
EXPORT_SYMBOL ( acpi_bus_start ) ;
2005-04-17 02:20:36 +04:00
2006-02-24 04:56:01 +03:00
int acpi_bus_trim ( struct acpi_device * start , int rmdevice )
2005-04-17 02:20:36 +04:00
{
2005-08-05 08:44:28 +04:00
acpi_status status ;
struct acpi_device * parent , * child ;
acpi_handle phandle , chandle ;
acpi_object_type type ;
u32 level = 1 ;
int err = 0 ;
parent = start ;
2005-04-17 02:20:36 +04:00
phandle = start - > handle ;
child = chandle = NULL ;
while ( ( level > 0 ) & & parent & & ( ! err ) ) {
status = acpi_get_next_object ( ACPI_TYPE_ANY , phandle ,
2005-08-05 08:44:28 +04:00
chandle , & chandle ) ;
2005-04-17 02:20:36 +04:00
/*
* If this scope is exhausted then move our way back up .
*/
if ( ACPI_FAILURE ( status ) ) {
level - - ;
chandle = phandle ;
acpi_get_parent ( phandle , & phandle ) ;
child = parent ;
parent = parent - > parent ;
if ( level = = 0 )
err = acpi_bus_remove ( child , rmdevice ) ;
else
err = acpi_bus_remove ( child , 1 ) ;
continue ;
}
status = acpi_get_type ( chandle , & type ) ;
if ( ACPI_FAILURE ( status ) ) {
continue ;
}
/*
* If there is a device corresponding to chandle then
* parse it ( depth - first ) .
*/
if ( acpi_bus_get_device ( chandle , & child ) = = 0 ) {
level + + ;
phandle = chandle ;
chandle = NULL ;
parent = child ;
}
continue ;
}
return err ;
}
2006-02-24 04:56:01 +03:00
EXPORT_SYMBOL_GPL ( acpi_bus_trim ) ;
2005-04-17 02:20:36 +04:00
2005-08-05 08:44:28 +04:00
static int acpi_bus_scan_fixed ( struct acpi_device * root )
2005-04-17 02:20:36 +04:00
{
2005-08-05 08:44:28 +04:00
int result = 0 ;
struct acpi_device * device = NULL ;
2006-12-07 15:56:41 +03:00
struct acpi_bus_ops ops ;
2005-04-17 02:20:36 +04:00
if ( ! root )
2006-06-27 08:41:40 +04:00
return - ENODEV ;
2005-04-17 02:20:36 +04:00
2006-12-07 15:56:41 +03:00
memset ( & ops , 0 , sizeof ( ops ) ) ;
ops . acpi_op_add = 1 ;
ops . acpi_op_start = 1 ;
2005-04-17 02:20:36 +04:00
/*
* Enumerate all fixed - feature devices .
*/
2007-02-02 19:48:22 +03:00
if ( ( acpi_gbl_FADT . flags & ACPI_FADT_POWER_BUTTON ) = = 0 ) {
2005-04-28 11:25:52 +04:00
result = acpi_add_single_object ( & device , acpi_root ,
2005-08-05 08:44:28 +04:00
NULL ,
2006-12-07 15:56:41 +03:00
ACPI_BUS_TYPE_POWER_BUTTON ,
& ops ) ;
2005-04-28 11:25:52 +04:00
}
2005-04-17 02:20:36 +04:00
2007-02-02 19:48:22 +03:00
if ( ( acpi_gbl_FADT . flags & ACPI_FADT_SLEEP_BUTTON ) = = 0 ) {
2005-04-28 11:25:52 +04:00
result = acpi_add_single_object ( & device , acpi_root ,
2005-08-05 08:44:28 +04:00
NULL ,
2006-12-07 15:56:41 +03:00
ACPI_BUS_TYPE_SLEEP_BUTTON ,
& ops ) ;
2005-04-28 11:25:52 +04:00
}
2005-04-17 02:20:36 +04:00
2006-06-27 08:41:40 +04:00
return result ;
2005-04-17 02:20:36 +04:00
}
2008-01-01 22:12:55 +03:00
int __init acpi_boot_ec_enable ( void ) ;
2005-04-17 02:20:36 +04:00
static int __init acpi_scan_init ( void )
{
int result ;
2005-04-28 11:25:52 +04:00
struct acpi_bus_ops ops ;
2005-04-17 02:20:36 +04:00
if ( acpi_disabled )
2006-06-27 08:41:40 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
2006-12-07 15:56:41 +03:00
memset ( & ops , 0 , sizeof ( ops ) ) ;
ops . acpi_op_add = 1 ;
ops . acpi_op_start = 1 ;
2005-04-17 02:20:36 +04:00
2006-05-10 18:33:00 +04:00
result = bus_register ( & acpi_bus_type ) ;
if ( result ) {
/* We don't want to quit even if we failed to add suspend/resume */
printk ( KERN_ERR PREFIX " Could not register bus type \n " ) ;
}
2005-04-17 02:20:36 +04:00
/*
* Create the root device in the bus ' s device tree
*/
2005-04-28 11:25:52 +04:00
result = acpi_add_single_object ( & acpi_root , NULL , ACPI_ROOT_OBJECT ,
2006-12-07 15:56:41 +03:00
ACPI_BUS_TYPE_SYSTEM , & ops ) ;
2005-04-17 02:20:36 +04:00
if ( result )
goto Done ;
/*
* Enumerate devices in the ACPI namespace .
*/
result = acpi_bus_scan_fixed ( acpi_root ) ;
2008-01-01 22:12:55 +03:00
/* EC region might be needed at bus_scan, so enable it now */
acpi_boot_ec_enable ( ) ;
2006-12-07 15:56:41 +03:00
if ( ! result )
2005-04-28 11:25:52 +04:00
result = acpi_bus_scan ( acpi_root , & ops ) ;
2005-04-17 02:20:36 +04:00
if ( result )
acpi_device_unregister ( acpi_root , ACPI_BUS_REMOVAL_NORMAL ) ;
2005-08-05 08:44:28 +04:00
Done :
2006-06-27 08:41:40 +04:00
return result ;
2005-04-17 02:20:36 +04:00
}
subsys_initcall ( acpi_scan_init ) ;