]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/acpi/sleep/main.c
Merge git://git.infradead.org/mtd-2.6
[linux-2.6-omap-h63xx.git] / drivers / acpi / sleep / main.c
index d13194a031bfbe0d1f9de3c83cd25471c10eda7a..80c0868d0480e76a0eced99a00a163f98114353c 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/dmi.h>
 #include <linux/device.h>
 #include <linux/suspend.h>
+#include <linux/reboot.h>
 
 #include <asm/io.h>
 
 
 u8 sleep_states[ACPI_S_STATE_COUNT];
 
+static void acpi_sleep_tts_switch(u32 acpi_state)
+{
+       union acpi_object in_arg = { ACPI_TYPE_INTEGER };
+       struct acpi_object_list arg_list = { 1, &in_arg };
+       acpi_status status = AE_OK;
+
+       in_arg.integer.value = acpi_state;
+       status = acpi_evaluate_object(NULL, "\\_TTS", &arg_list, NULL);
+       if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
+               /*
+                * OS can't evaluate the _TTS object correctly. Some warning
+                * message will be printed. But it won't break anything.
+                */
+               printk(KERN_NOTICE "Failure in evaluating _TTS object\n");
+       }
+}
+
+static int tts_notify_reboot(struct notifier_block *this,
+                       unsigned long code, void *x)
+{
+       acpi_sleep_tts_switch(ACPI_STATE_S5);
+       return NOTIFY_DONE;
+}
+
+static struct notifier_block tts_notifier = {
+       .notifier_call  = tts_notify_reboot,
+       .next           = NULL,
+       .priority       = 0,
+};
+
 static int acpi_sleep_prepare(u32 acpi_state)
 {
 #ifdef CONFIG_ACPI_SLEEP
@@ -45,9 +76,8 @@ static int acpi_sleep_prepare(u32 acpi_state)
        return 0;
 }
 
-#ifdef CONFIG_PM_SLEEP
+#ifdef CONFIG_ACPI_SLEEP
 static u32 acpi_target_sleep_state = ACPI_STATE_S0;
-
 /*
  * ACPI 1.0 wants us to execute _PTS before suspending devices, so we allow the
  * user to request that behavior by using the 'acpi_old_suspend_ordering'
@@ -131,8 +161,11 @@ static void acpi_pm_end(void)
         * failing transition to a sleep state.
         */
        acpi_target_sleep_state = ACPI_STATE_S0;
+       acpi_sleep_tts_switch(acpi_target_sleep_state);
 }
-#endif /* CONFIG_PM_SLEEP */
+#else /* !CONFIG_ACPI_SLEEP */
+#define acpi_target_sleep_state        ACPI_STATE_S0
+#endif /* CONFIG_ACPI_SLEEP */
 
 #ifdef CONFIG_SUSPEND
 extern void do_suspend_lowlevel(void);
@@ -155,6 +188,7 @@ static int acpi_suspend_begin(suspend_state_t pm_state)
 
        if (sleep_states[acpi_state]) {
                acpi_target_sleep_state = acpi_state;
+               acpi_sleep_tts_switch(acpi_target_sleep_state);
        } else {
                printk(KERN_ERR "ACPI does not support this state: %d\n",
                        pm_state);
@@ -200,6 +234,8 @@ static int acpi_suspend_enter(suspend_state_t pm_state)
                break;
        }
 
+       /* If ACPI is not enabled by the BIOS, we need to enable it here. */
+       acpi_enable();
        /* Reprogram control registers and execute _BFS */
        acpi_leave_sleep_state_prep(acpi_state);
 
@@ -296,6 +332,14 @@ static struct dmi_system_id __initdata acpisleep_dmi_table[] = {
                DMI_MATCH(DMI_BOARD_NAME, "KN9 Series(NF-CK804)"),
                },
        },
+       {
+       .callback = init_old_suspend_ordering,
+       .ident = "HP xw4600 Workstation",
+       .matches = {
+               DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
+               DMI_MATCH(DMI_PRODUCT_NAME, "HP xw4600 Workstation"),
+               },
+       },
        {},
 };
 #endif /* CONFIG_SUSPEND */
@@ -313,6 +357,7 @@ void __init acpi_no_s4_hw_signature(void)
 static int acpi_hibernation_begin(void)
 {
        acpi_target_sleep_state = ACPI_STATE_S4;
+       acpi_sleep_tts_switch(acpi_target_sleep_state);
        return 0;
 }
 
@@ -376,7 +421,15 @@ static struct platform_hibernation_ops acpi_hibernation_ops = {
  */
 static int acpi_hibernation_begin_old(void)
 {
-       int error = acpi_sleep_prepare(ACPI_STATE_S4);
+       int error;
+       /*
+        * The _TTS object should always be evaluated before the _PTS object.
+        * When the old_suspended_ordering is true, the _PTS object is
+        * evaluated in the acpi_sleep_prepare.
+        */
+       acpi_sleep_tts_switch(ACPI_STATE_S4);
+
+       error = acpi_sleep_prepare(ACPI_STATE_S4);
 
        if (!error)
                acpi_target_sleep_state = ACPI_STATE_S4;
@@ -444,7 +497,7 @@ int acpi_pm_device_sleep_state(struct device *dev, int *d_min_p)
        acpi_handle handle = DEVICE_ACPI_HANDLE(dev);
        struct acpi_device *adev;
        char acpi_method[] = "_SxD";
-       unsigned long d_min, d_max;
+       unsigned long long d_min, d_max;
 
        if (!handle || ACPI_FAILURE(acpi_bus_get_device(handle, &adev))) {
                printk(KERN_DEBUG "ACPI handle has no context!\n");
@@ -596,5 +649,10 @@ int __init acpi_sleep_init(void)
                pm_power_off = acpi_power_off;
        }
        printk(")\n");
+       /*
+        * Register the tts_notifier to reboot notifier list so that the _TTS
+        * object can also be evaluated when the system enters S5.
+        */
+       register_reboot_notifier(&tts_notifier);
        return 0;
 }