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"
# define ACPI_BUS_HID "ACPI_BUS"
# 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
} ;
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
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
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
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
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
2006-12-07 15:56:27 +03:00
return ! acpi_match_ids ( acpi_dev , acpi_drv - > ids ) ;
}
2005-04-17 02:20:36 +04:00
2006-12-07 15:56:27 +03:00
static int acpi_device_uevent ( struct device * dev , char * * envp , int num_envp ,
char * buffer , int buffer_size )
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 ) ;
int i = 0 , length = 0 , ret = 0 ;
if ( acpi_dev - > flags . hardware_id )
ret = add_uevent_var ( envp , num_envp , & i ,
buffer , buffer_size , & length ,
" HWID=%s " , acpi_dev - > pnp . hardware_id ) ;
if ( ret )
return - ENOMEM ;
if ( acpi_dev - > flags . compatible_ids ) {
int j ;
struct acpi_compatible_id_list * cid_list ;
cid_list = acpi_dev - > pnp . cid_list ;
for ( j = 0 ; j < cid_list - > count ; j + + ) {
ret = add_uevent_var ( envp , num_envp , & i , buffer ,
buffer_size , & length , " COMPTID=%s " ,
cid_list - > id [ j ] . value ) ;
if ( ret )
return - ENOMEM ;
2006-12-07 15:56:16 +03:00
}
}
2006-12-07 15:56:27 +03:00
envp [ i ] = NULL ;
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 ) {
printk ( " Error adding device %s " , device - > dev . bus_id ) ;
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 ;
status = acpi_get_handle ( NULL , obj - > string . pointer , ejd ) ;
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 ;
}
int acpi_match_ids ( struct acpi_device * device , char * ids )
{
if ( device - > flags . hardware_id )
if ( strstr ( ids , device - > pnp . hardware_id ) )
return 0 ;
if ( device - > flags . compatible_ids ) {
struct acpi_compatible_id_list * cid_list = device - > pnp . cid_list ;
int i ;
/* compare multiple _CID entries against driver ids */
for ( i = 0 ; i < cid_list - > count ; i + + ) {
if ( strstr ( ids , cid_list - > id [ i ] . value ) )
return 0 ;
}
}
return - ENOENT ;
}
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 ;
2005-04-17 02:20:36 +04:00
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 ;
/* Power button, Lid switch always enable wakeup */
if ( ! acpi_match_ids ( device , " PNP0C0D,PNP0C0C,PNP0C0E " ) )
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 ;
/* TBD: Peformance management */
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 ;
}
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 ;
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 ) ) {
2005-08-05 08:44:28 +04:00
printk ( " %s: Error reading device info \n " , __FUNCTION__ ) ;
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
if ( ! ( info - > valid & ( ACPI_VALID_HID | ACPI_VALID_CID ) ) ) {
status = acpi_video_bus_match ( device ) ;
if ( ACPI_SUCCESS ( status ) )
hid = ACPI_VIDEO_HID ;
2007-01-11 10:09:09 +03:00
status = acpi_bay_match ( device ) ;
if ( ACPI_SUCCESS ( status ) )
hid = ACPI_BAY_HID ;
2006-12-07 15:57:10 +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 ;
}
if ( cid_list ) {
device - > pnp . cid_list = kmalloc ( cid_list - > size , GFP_KERNEL ) ;
if ( device - > pnp . cid_list )
memcpy ( device - > pnp . cid_list , cid_list , cid_list - > size ) ;
else
printk ( KERN_ERR " Memory allocation error \n " ) ;
}
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 ) ) {
printk ( " Error attaching device data \n " ) ;
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
}
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 ) ;
if ( ACPI_FAILURE ( result ) | | ! device - > status . present ) {
result = - ENOENT ;
goto end ;
}
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
}
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 ) ;
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 ) ;