Commit 39a0ad87 authored by Zhao Yakui's avatar Zhao Yakui Committed by Len Brown

ACPI : Load device driver according to the status of acpi device

According to ACPI spec when the status of some device is not present
but functional, the device is valid and the children of this device
should be enumerated. It means that the device should be added to
linux acpi device tree. But the device driver for this device should not
be loaded.
    The detailed info can be found in the section 6.3.7 of ACPI 3.0b spec.
    _STA may return bit 0 clear (not present) with bit 3 set (device is
functional). This case is used to indicate a valid device for which no
device driver should be loaded (for example, a bridge device.).
Children of this device may be present and valid. OS should continue
enumeration below a device whose _STA returns this bit combination

http://bugzilla.kernel.org/show_bug.cgi?id=3358Signed-off-by: default avatarZhao Yakui <yakui.zhao@intel.com>
Signed-off-by: default avatarLi Shaohua <shaohua.li@intel.com>
Signed-off-by: default avatarZhang Rui <rui.zhang@intel.com>
Signed-off-by: default avatarAndi Kleen <ak@linux.intel.com>
Signed-off-by: default avatarLen Brown <len.brown@intel.com>
parent 6415e12b
...@@ -112,21 +112,21 @@ int acpi_bus_get_status(struct acpi_device *device) ...@@ -112,21 +112,21 @@ int acpi_bus_get_status(struct acpi_device *device)
} }
/* /*
* Otherwise we assume the status of our parent (unless we don't * According to ACPI spec some device can be present and functional
* have one, in which case status is implied). * even if the parent is not present but functional.
* In such conditions the child device should not inherit the status
* from the parent.
*/ */
else if (device->parent)
device->status = device->parent->status;
else else
STRUCT_TO_INT(device->status) = STRUCT_TO_INT(device->status) =
ACPI_STA_DEVICE_PRESENT | ACPI_STA_DEVICE_ENABLED | ACPI_STA_DEVICE_PRESENT | ACPI_STA_DEVICE_ENABLED |
ACPI_STA_DEVICE_UI | ACPI_STA_DEVICE_FUNCTIONING; ACPI_STA_DEVICE_UI | ACPI_STA_DEVICE_FUNCTIONING;
if (device->status.functional && !device->status.present) { if (device->status.functional && !device->status.present) {
printk(KERN_WARNING PREFIX "Device [%s] status [%08x]: " ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] status [%08x]: "
"functional but not present; setting present\n", "functional but not present;\n",
device->pnp.bus_id, (u32) STRUCT_TO_INT(device->status)); device->pnp.bus_id,
device->status.present = 1; (u32) STRUCT_TO_INT(device->status)));
} }
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] status [%08x]\n", ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] status [%08x]\n",
......
...@@ -276,6 +276,13 @@ int acpi_match_device_ids(struct acpi_device *device, ...@@ -276,6 +276,13 @@ int acpi_match_device_ids(struct acpi_device *device,
{ {
const struct acpi_device_id *id; const struct acpi_device_id *id;
/*
* If the device is not present, it is unnecessary to load device
* driver for it.
*/
if (!device->status.present)
return -ENODEV;
if (device->flags.hardware_id) { if (device->flags.hardware_id) {
for (id = ids; id->id[0]; id++) { for (id = ids; id->id[0]; id++) {
if (!strcmp((char*)id->id, device->pnp.hardware_id)) if (!strcmp((char*)id->id, device->pnp.hardware_id))
...@@ -1222,15 +1229,18 @@ acpi_add_single_object(struct acpi_device **child, ...@@ -1222,15 +1229,18 @@ acpi_add_single_object(struct acpi_device **child,
result = -ENODEV; result = -ENODEV;
goto end; goto end;
} }
if (!device->status.present) { /*
/* Bay and dock should be handled even if absent */ * When the device is neither present nor functional, the
if (!ACPI_SUCCESS( * device should not be added to Linux ACPI device tree.
acpi_is_child_device(device, acpi_bay_match)) && * When the status of the device is not present but functinal,
!ACPI_SUCCESS( * it should be added to Linux ACPI tree. For example : bay
acpi_is_child_device(device, acpi_dock_match))) { * device , dock device.
result = -ENODEV; * In such conditions it is unncessary to check whether it is
goto end; * bay device or dock device.
} */
if (!device->status.present && !device->status.functional) {
result = -ENODEV;
goto end;
} }
break; break;
default: default:
...@@ -1411,7 +1421,12 @@ static int acpi_bus_scan(struct acpi_device *start, struct acpi_bus_ops *ops) ...@@ -1411,7 +1421,12 @@ static int acpi_bus_scan(struct acpi_device *start, struct acpi_bus_ops *ops)
* TBD: Need notifications and other detection mechanisms * TBD: Need notifications and other detection mechanisms
* in place before we can fully implement this. * in place before we can fully implement this.
*/ */
if (child->status.present) { /*
* When the device is not present but functional, it is also
* necessary to scan the children of this device.
*/
if (child->status.present || (!child->status.present &&
child->status.functional)) {
status = acpi_get_next_object(ACPI_TYPE_ANY, chandle, status = acpi_get_next_object(ACPI_TYPE_ANY, chandle,
NULL, NULL); NULL, NULL);
if (ACPI_SUCCESS(status)) { if (ACPI_SUCCESS(status)) {
......
...@@ -148,9 +148,13 @@ static int __init pnpacpi_add_device(struct acpi_device *device) ...@@ -148,9 +148,13 @@ static int __init pnpacpi_add_device(struct acpi_device *device)
acpi_status status; acpi_status status;
struct pnp_dev *dev; struct pnp_dev *dev;
/*
* If a PnPacpi device is not present , the device
* driver should not be loaded.
*/
status = acpi_get_handle(device->handle, "_CRS", &temp); status = acpi_get_handle(device->handle, "_CRS", &temp);
if (ACPI_FAILURE(status) || !ispnpidacpi(acpi_device_hid(device)) || if (ACPI_FAILURE(status) || !ispnpidacpi(acpi_device_hid(device)) ||
is_exclusive_device(device)) is_exclusive_device(device) || (!device->status.present))
return 0; return 0;
dev = pnp_alloc_dev(&pnpacpi_protocol, num, acpi_device_hid(device)); dev = pnp_alloc_dev(&pnpacpi_protocol, num, acpi_device_hid(device));
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment