Merge master.kernel.org:/pub/scm/linux/kernel/git/jejb/scsi-rc-fixes-2.6
[pandora-kernel.git] / drivers / acpi / sleep / main.c
index ab21357..2cbb9aa 100644 (file)
 #include <linux/dmi.h>
 #include <linux/device.h>
 #include <linux/suspend.h>
+
+#include <asm/io.h>
+
 #include <acpi/acpi_bus.h>
 #include <acpi/acpi_drivers.h>
 #include "sleep.h"
 
 u8 sleep_states[ACPI_S_STATE_COUNT];
 
+#ifdef CONFIG_PM_SLEEP
+static u32 acpi_target_sleep_state = ACPI_STATE_S0;
+#endif
+
+int acpi_sleep_prepare(u32 acpi_state)
+{
+#ifdef CONFIG_ACPI_SLEEP
+       /* do we have a wakeup address for S2 and S3? */
+       if (acpi_state == ACPI_STATE_S3) {
+               if (!acpi_wakeup_address) {
+                       return -EFAULT;
+               }
+               acpi_set_firmware_waking_vector((acpi_physical_address)
+                                               virt_to_phys((void *)
+                                                            acpi_wakeup_address));
+
+       }
+       ACPI_FLUSH_CPU_CACHE();
+       acpi_enable_wakeup_device_prep(acpi_state);
+#endif
+       acpi_gpe_sleep_prepare(acpi_state);
+       acpi_enter_sleep_state_prep(acpi_state);
+       return 0;
+}
+
+#ifdef CONFIG_SUSPEND
 static struct pm_ops acpi_pm_ops;
 
 extern void do_suspend_lowlevel(void);
@@ -34,11 +63,6 @@ static u32 acpi_suspend_states[] = {
 
 static int init_8259A_after_S1;
 
-extern int acpi_sleep_prepare(u32 acpi_state);
-extern void acpi_power_off(void);
-
-static u32 acpi_target_sleep_state = ACPI_STATE_S0;
-
 /**
  *     acpi_pm_set_target - Set the target system sleep state to the state
  *             associated with given @pm_state, if supported.
@@ -163,21 +187,6 @@ static int acpi_pm_finish(suspend_state_t pm_state)
        return 0;
 }
 
-int acpi_suspend(u32 acpi_state)
-{
-       suspend_state_t states[] = {
-               [1] = PM_SUSPEND_STANDBY,
-               [3] = PM_SUSPEND_MEM,
-               [5] = PM_SUSPEND_MAX
-       };
-
-       if (acpi_state < 6 && states[acpi_state])
-               return pm_suspend(states[acpi_state]);
-       if (acpi_state == 4)
-               return hibernate();
-       return -EINVAL;
-}
-
 static int acpi_pm_state_valid(suspend_state_t pm_state)
 {
        u32 acpi_state;
@@ -202,7 +211,28 @@ static struct pm_ops acpi_pm_ops = {
        .finish = acpi_pm_finish,
 };
 
-#ifdef CONFIG_SOFTWARE_SUSPEND
+/*
+ * Toshiba fails to preserve interrupts over S1, reinitialization
+ * of 8259 is needed after S1 resume.
+ */
+static int __init init_ints_after_s1(struct dmi_system_id *d)
+{
+       printk(KERN_WARNING "%s with broken S1 detected.\n", d->ident);
+       init_8259A_after_S1 = 1;
+       return 0;
+}
+
+static struct dmi_system_id __initdata acpisleep_dmi_table[] = {
+       {
+        .callback = init_ints_after_s1,
+        .ident = "Toshiba Satellite 4030cdt",
+        .matches = {DMI_MATCH(DMI_PRODUCT_NAME, "S4030CDT/4.3"),},
+        },
+       {},
+};
+#endif /* CONFIG_SUSPEND */
+
+#ifdef CONFIG_HIBERNATION
 static int acpi_hibernation_prepare(void)
 {
        return acpi_sleep_prepare(ACPI_STATE_S4);
@@ -254,8 +284,24 @@ static struct hibernation_ops acpi_hibernation_ops = {
        .pre_restore = acpi_hibernation_pre_restore,
        .restore_cleanup = acpi_hibernation_restore_cleanup,
 };
-#endif                         /* CONFIG_SOFTWARE_SUSPEND */
+#endif                         /* CONFIG_HIBERNATION */
+
+int acpi_suspend(u32 acpi_state)
+{
+       suspend_state_t states[] = {
+               [1] = PM_SUSPEND_STANDBY,
+               [3] = PM_SUSPEND_MEM,
+               [5] = PM_SUSPEND_MAX
+       };
+
+       if (acpi_state < 6 && states[acpi_state])
+               return pm_suspend(states[acpi_state]);
+       if (acpi_state == 4)
+               return hibernate();
+       return -EINVAL;
+}
 
+#ifdef CONFIG_PM_SLEEP
 /**
  *     acpi_pm_device_sleep_state - return preferred power state of ACPI device
  *             in the system sleep state given by %acpi_target_sleep_state
@@ -286,7 +332,7 @@ int acpi_pm_device_sleep_state(struct device *dev, int wake, int *d_min_p)
        unsigned long d_min, d_max;
 
        if (!handle || ACPI_FAILURE(acpi_bus_get_device(handle, &adev))) {
-               printk(KERN_ERR "ACPI handle has no context!\n");
+               printk(KERN_DEBUG "ACPI handle has no context!\n");
                return -ENODEV;
        }
 
@@ -330,56 +376,65 @@ int acpi_pm_device_sleep_state(struct device *dev, int wake, int *d_min_p)
                *d_min_p = d_min;
        return d_max;
 }
+#endif
 
-/*
- * Toshiba fails to preserve interrupts over S1, reinitialization
- * of 8259 is needed after S1 resume.
- */
-static int __init init_ints_after_s1(struct dmi_system_id *d)
+static void acpi_power_off_prepare(void)
 {
-       printk(KERN_WARNING "%s with broken S1 detected.\n", d->ident);
-       init_8259A_after_S1 = 1;
-       return 0;
+       /* Prepare to power off the system */
+       acpi_sleep_prepare(ACPI_STATE_S5);
 }
 
-static struct dmi_system_id __initdata acpisleep_dmi_table[] = {
-       {
-        .callback = init_ints_after_s1,
-        .ident = "Toshiba Satellite 4030cdt",
-        .matches = {DMI_MATCH(DMI_PRODUCT_NAME, "S4030CDT/4.3"),},
-        },
-       {},
-};
+static void acpi_power_off(void)
+{
+       /* acpi_sleep_prepare(ACPI_STATE_S5) should have already been called */
+       printk("%s called\n", __FUNCTION__);
+       local_irq_disable();
+       acpi_enter_sleep_state(ACPI_STATE_S5);
+}
 
 int __init acpi_sleep_init(void)
 {
+       acpi_status status;
+       u8 type_a, type_b;
+#ifdef CONFIG_SUSPEND
        int i = 0;
 
        dmi_check_system(acpisleep_dmi_table);
+#endif
 
        if (acpi_disabled)
                return 0;
 
-       printk(KERN_INFO PREFIX "(supports");
-       for (i = 0; i < ACPI_S_STATE_COUNT; i++) {
-               acpi_status status;
-               u8 type_a, type_b;
+       sleep_states[ACPI_STATE_S0] = 1;
+       printk(KERN_INFO PREFIX "(supports S0");
+
+#ifdef CONFIG_SUSPEND
+       for (i = ACPI_STATE_S1; i < ACPI_STATE_S4; i++) {
                status = acpi_get_sleep_type_data(i, &type_a, &type_b);
                if (ACPI_SUCCESS(status)) {
                        sleep_states[i] = 1;
                        printk(" S%d", i);
                }
        }
-       printk(")\n");
 
        pm_set_ops(&acpi_pm_ops);
+#endif
 
-#ifdef CONFIG_SOFTWARE_SUSPEND
-       if (sleep_states[ACPI_STATE_S4])
+#ifdef CONFIG_HIBERNATION
+       status = acpi_get_sleep_type_data(ACPI_STATE_S4, &type_a, &type_b);
+       if (ACPI_SUCCESS(status)) {
                hibernation_set_ops(&acpi_hibernation_ops);
-#else
-       sleep_states[ACPI_STATE_S4] = 0;
+               sleep_states[ACPI_STATE_S4] = 1;
+               printk(" S4");
+       }
 #endif
-
+       status = acpi_get_sleep_type_data(ACPI_STATE_S5, &type_a, &type_b);
+       if (ACPI_SUCCESS(status)) {
+               sleep_states[ACPI_STATE_S5] = 1;
+               printk(" S5");
+               pm_power_off_prepare = acpi_power_off_prepare;
+               pm_power_off = acpi_power_off;
+       }
+       printk(")\n");
        return 0;
 }