]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/acpi/bus.c
Merge branch 'ec' into test
[linux-2.6-omap-h63xx.git] / drivers / acpi / bus.c
index 0e0bbc6209e5a3e08c2b133fafe33c91cd5a1fb0..b11400e2f856e28f787ba23160b18a894a93c285 100644 (file)
@@ -48,6 +48,23 @@ EXPORT_SYMBOL(acpi_root_dir);
 
 #define STRUCT_TO_INT(s)       (*((int*)&s))
 
+static int set_power_nocheck(const struct dmi_system_id *id)
+{
+       printk(KERN_NOTICE PREFIX "%s detected - "
+               "disable power check in power transistion\n", id->ident);
+       acpi_power_nocheck = 1;
+       return 0;
+}
+static struct dmi_system_id __cpuinitdata power_nocheck_dmi_table[] = {
+       {
+       set_power_nocheck, "HP Pavilion 05", {
+       DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
+       DMI_MATCH(DMI_SYS_VENDOR, "HP Pavilion 05"),
+       DMI_MATCH(DMI_PRODUCT_VERSION, "2001211RE101GLEND") }, NULL},
+       {},
+};
+
+
 /* --------------------------------------------------------------------------
                                 Device Management
    -------------------------------------------------------------------------- */
@@ -95,21 +112,21 @@ int acpi_bus_get_status(struct acpi_device *device)
        }
 
        /*
-        * Otherwise we assume the status of our parent (unless we don't
-        * have one, in which case status is implied).
+        * According to ACPI spec some device can be present and functional
+        * 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
                STRUCT_TO_INT(device->status) =
                    ACPI_STA_DEVICE_PRESENT | ACPI_STA_DEVICE_ENABLED |
                    ACPI_STA_DEVICE_UI      | ACPI_STA_DEVICE_FUNCTIONING;
 
        if (device->status.functional && !device->status.present) {
-               printk(KERN_WARNING PREFIX "Device [%s] status [%08x]: "
-                      "functional but not present; setting present\n",
-                      device->pnp.bus_id, (u32) STRUCT_TO_INT(device->status));
-               device->status.present = 1;
+               ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] status [%08x]: "
+                      "functional but not present;\n",
+                       device->pnp.bus_id,
+                       (u32) STRUCT_TO_INT(device->status)));
        }
 
        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)
        /*
         * Get device's current power state
         */
-       acpi_bus_get_power(device->handle, &device->power.state);
+       if (!acpi_power_nocheck) {
+               /*
+                * Maybe the incorrect power state is returned on the bogus
+                * bios, which is different with the real power state.
+                * For example: the bios returns D0 state and the real power
+                * state is D3. OS expects to set the device to D0 state. In
+                * such case if OS uses the power state returned by the BIOS,
+                * the device can't be transisted to the correct power state.
+                * So if the acpi_power_nocheck is set, it is unnecessary to
+                * get the power state by calling acpi_bus_get_power.
+                */
+               acpi_bus_get_power(device->handle, &device->power.state);
+       }
        if ((state == device->power.state) && !device->flags.force_power_state) {
                ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device is already at D%d\n",
                                  state));
@@ -496,6 +525,19 @@ static int acpi_bus_check_scope(struct acpi_device *device)
        return 0;
 }
 
+static BLOCKING_NOTIFIER_HEAD(acpi_bus_notify_list);
+int register_acpi_bus_notifier(struct notifier_block *nb)
+{
+       return blocking_notifier_chain_register(&acpi_bus_notify_list, nb);
+}
+EXPORT_SYMBOL_GPL(register_acpi_bus_notifier);
+
+void unregister_acpi_bus_notifier(struct notifier_block *nb)
+{
+       blocking_notifier_chain_unregister(&acpi_bus_notify_list, nb);
+}
+EXPORT_SYMBOL_GPL(unregister_acpi_bus_notifier);
+
 /**
  * acpi_bus_notify
  * ---------------
@@ -506,6 +548,8 @@ static void acpi_bus_notify(acpi_handle handle, u32 type, void *data)
        int result = 0;
        struct acpi_device *device = NULL;
 
+       blocking_notifier_call_chain(&acpi_bus_notify_list,
+               type, (void *)handle);
 
        if (acpi_bus_get_device(handle, &device))
                return;
@@ -824,7 +868,11 @@ static int __init acpi_init(void)
                }
        } else
                disable_acpi();
-
+       /*
+        * If the laptop falls into the DMI check table, the power state check
+        * will be disabled in the course of device power transistion.
+        */
+       dmi_check_system(power_nocheck_dmi_table);
        return result;
 }