diff options
Diffstat (limited to 'drivers/acpi/bus.c')
-rw-r--r-- | drivers/acpi/bus.c | 74 |
1 files changed, 64 insertions, 10 deletions
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index 0885fc796fa0..c797c6473f31 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c | |||
@@ -48,6 +48,23 @@ EXPORT_SYMBOL(acpi_root_dir); | |||
48 | 48 | ||
49 | #define STRUCT_TO_INT(s) (*((int*)&s)) | 49 | #define STRUCT_TO_INT(s) (*((int*)&s)) |
50 | 50 | ||
51 | static int set_power_nocheck(const struct dmi_system_id *id) | ||
52 | { | ||
53 | printk(KERN_NOTICE PREFIX "%s detected - " | ||
54 | "disable power check in power transistion\n", id->ident); | ||
55 | acpi_power_nocheck = 1; | ||
56 | return 0; | ||
57 | } | ||
58 | static struct dmi_system_id __cpuinitdata power_nocheck_dmi_table[] = { | ||
59 | { | ||
60 | set_power_nocheck, "HP Pavilion 05", { | ||
61 | DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"), | ||
62 | DMI_MATCH(DMI_SYS_VENDOR, "HP Pavilion 05"), | ||
63 | DMI_MATCH(DMI_PRODUCT_VERSION, "2001211RE101GLEND") }, NULL}, | ||
64 | {}, | ||
65 | }; | ||
66 | |||
67 | |||
51 | /* -------------------------------------------------------------------------- | 68 | /* -------------------------------------------------------------------------- |
52 | Device Management | 69 | Device Management |
53 | -------------------------------------------------------------------------- */ | 70 | -------------------------------------------------------------------------- */ |
@@ -95,21 +112,21 @@ int acpi_bus_get_status(struct acpi_device *device) | |||
95 | } | 112 | } |
96 | 113 | ||
97 | /* | 114 | /* |
98 | * Otherwise we assume the status of our parent (unless we don't | 115 | * According to ACPI spec some device can be present and functional |
99 | * have one, in which case status is implied). | 116 | * even if the parent is not present but functional. |
117 | * In such conditions the child device should not inherit the status | ||
118 | * from the parent. | ||
100 | */ | 119 | */ |
101 | else if (device->parent) | ||
102 | device->status = device->parent->status; | ||
103 | else | 120 | else |
104 | STRUCT_TO_INT(device->status) = | 121 | STRUCT_TO_INT(device->status) = |
105 | ACPI_STA_DEVICE_PRESENT | ACPI_STA_DEVICE_ENABLED | | 122 | ACPI_STA_DEVICE_PRESENT | ACPI_STA_DEVICE_ENABLED | |
106 | ACPI_STA_DEVICE_UI | ACPI_STA_DEVICE_FUNCTIONING; | 123 | ACPI_STA_DEVICE_UI | ACPI_STA_DEVICE_FUNCTIONING; |
107 | 124 | ||
108 | if (device->status.functional && !device->status.present) { | 125 | if (device->status.functional && !device->status.present) { |
109 | printk(KERN_WARNING PREFIX "Device [%s] status [%08x]: " | 126 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] status [%08x]: " |
110 | "functional but not present; setting present\n", | 127 | "functional but not present;\n", |
111 | device->pnp.bus_id, (u32) STRUCT_TO_INT(device->status)); | 128 | device->pnp.bus_id, |
112 | device->status.present = 1; | 129 | (u32) STRUCT_TO_INT(device->status))); |
113 | } | 130 | } |
114 | 131 | ||
115 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] status [%08x]\n", | 132 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] status [%08x]\n", |
@@ -223,7 +240,19 @@ int acpi_bus_set_power(acpi_handle handle, int state) | |||
223 | /* | 240 | /* |
224 | * Get device's current power state | 241 | * Get device's current power state |
225 | */ | 242 | */ |
226 | acpi_bus_get_power(device->handle, &device->power.state); | 243 | if (!acpi_power_nocheck) { |
244 | /* | ||
245 | * Maybe the incorrect power state is returned on the bogus | ||
246 | * bios, which is different with the real power state. | ||
247 | * For example: the bios returns D0 state and the real power | ||
248 | * state is D3. OS expects to set the device to D0 state. In | ||
249 | * such case if OS uses the power state returned by the BIOS, | ||
250 | * the device can't be transisted to the correct power state. | ||
251 | * So if the acpi_power_nocheck is set, it is unnecessary to | ||
252 | * get the power state by calling acpi_bus_get_power. | ||
253 | */ | ||
254 | acpi_bus_get_power(device->handle, &device->power.state); | ||
255 | } | ||
227 | if ((state == device->power.state) && !device->flags.force_power_state) { | 256 | if ((state == device->power.state) && !device->flags.force_power_state) { |
228 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device is already at D%d\n", | 257 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device is already at D%d\n", |
229 | state)); | 258 | state)); |
@@ -496,6 +525,19 @@ static int acpi_bus_check_scope(struct acpi_device *device) | |||
496 | return 0; | 525 | return 0; |
497 | } | 526 | } |
498 | 527 | ||
528 | static BLOCKING_NOTIFIER_HEAD(acpi_bus_notify_list); | ||
529 | int register_acpi_bus_notifier(struct notifier_block *nb) | ||
530 | { | ||
531 | return blocking_notifier_chain_register(&acpi_bus_notify_list, nb); | ||
532 | } | ||
533 | EXPORT_SYMBOL_GPL(register_acpi_bus_notifier); | ||
534 | |||
535 | void unregister_acpi_bus_notifier(struct notifier_block *nb) | ||
536 | { | ||
537 | blocking_notifier_chain_unregister(&acpi_bus_notify_list, nb); | ||
538 | } | ||
539 | EXPORT_SYMBOL_GPL(unregister_acpi_bus_notifier); | ||
540 | |||
499 | /** | 541 | /** |
500 | * acpi_bus_notify | 542 | * acpi_bus_notify |
501 | * --------------- | 543 | * --------------- |
@@ -506,6 +548,8 @@ static void acpi_bus_notify(acpi_handle handle, u32 type, void *data) | |||
506 | int result = 0; | 548 | int result = 0; |
507 | struct acpi_device *device = NULL; | 549 | struct acpi_device *device = NULL; |
508 | 550 | ||
551 | blocking_notifier_call_chain(&acpi_bus_notify_list, | ||
552 | type, (void *)handle); | ||
509 | 553 | ||
510 | if (acpi_bus_get_device(handle, &device)) | 554 | if (acpi_bus_get_device(handle, &device)) |
511 | return; | 555 | return; |
@@ -749,6 +793,12 @@ static int __init acpi_bus_init(void) | |||
749 | goto error1; | 793 | goto error1; |
750 | } | 794 | } |
751 | 795 | ||
796 | /* | ||
797 | * Maybe EC region is required at bus_scan/acpi_get_devices. So it | ||
798 | * is necessary to enable it as early as possible. | ||
799 | */ | ||
800 | acpi_boot_ec_enable(); | ||
801 | |||
752 | printk(KERN_INFO PREFIX "Interpreter enabled\n"); | 802 | printk(KERN_INFO PREFIX "Interpreter enabled\n"); |
753 | 803 | ||
754 | /* Initialize sleep structures */ | 804 | /* Initialize sleep structures */ |
@@ -818,7 +868,11 @@ static int __init acpi_init(void) | |||
818 | } | 868 | } |
819 | } else | 869 | } else |
820 | disable_acpi(); | 870 | disable_acpi(); |
821 | 871 | /* | |
872 | * If the laptop falls into the DMI check table, the power state check | ||
873 | * will be disabled in the course of device power transistion. | ||
874 | */ | ||
875 | dmi_check_system(power_nocheck_dmi_table); | ||
822 | return result; | 876 | return result; |
823 | } | 877 | } |
824 | 878 | ||