ACPI / video: Quirk initial backlight level 0
[linux-3.10.git] / drivers / acpi / sleep.c
index 77c517f..9c1a435 100644 (file)
@@ -80,6 +80,12 @@ static int acpi_sleep_prepare(u32 acpi_state)
 
 #ifdef CONFIG_ACPI_SLEEP
 static u32 acpi_target_sleep_state = ACPI_STATE_S0;
+
+u32 acpi_target_system_state(void)
+{
+       return acpi_target_sleep_state;
+}
+
 static bool pwr_btn_event_pending;
 
 /*
@@ -97,6 +103,21 @@ void __init acpi_nvs_nosave(void)
 }
 
 /*
+ * The ACPI specification wants us to save NVS memory regions during hibernation
+ * but says nothing about saving NVS during S3.  Not all versions of Windows
+ * save NVS on S3 suspend either, and it is clear that not all systems need
+ * NVS to be saved at S3 time.  To improve suspend/resume time, allow the
+ * user to disable saving NVS on S3 if their system does not require it, but
+ * continue to save/restore NVS for S4 as specified.
+ */
+static bool nvs_nosave_s3;
+
+void __init acpi_nvs_nosave_s3(void)
+{
+       nvs_nosave_s3 = true;
+}
+
+/*
  * 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'
  * kernel command line option that causes the following variable to be set.
@@ -108,6 +129,196 @@ void __init acpi_old_suspend_ordering(void)
        old_suspend_ordering = true;
 }
 
+static int __init init_old_suspend_ordering(const struct dmi_system_id *d)
+{
+       acpi_old_suspend_ordering();
+       return 0;
+}
+
+static int __init init_nvs_nosave(const struct dmi_system_id *d)
+{
+       acpi_nvs_nosave();
+       return 0;
+}
+
+static struct dmi_system_id __initdata acpisleep_dmi_table[] = {
+       {
+       .callback = init_old_suspend_ordering,
+       .ident = "Abit KN9 (nForce4 variant)",
+       .matches = {
+               DMI_MATCH(DMI_BOARD_VENDOR, "http://www.abit.com.tw/"),
+               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"),
+               },
+       },
+       {
+       .callback = init_old_suspend_ordering,
+       .ident = "Asus Pundit P1-AH2 (M2N8L motherboard)",
+       .matches = {
+               DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTek Computer INC."),
+               DMI_MATCH(DMI_BOARD_NAME, "M2N8L"),
+               },
+       },
+       {
+       .callback = init_old_suspend_ordering,
+       .ident = "Panasonic CF51-2L",
+       .matches = {
+               DMI_MATCH(DMI_BOARD_VENDOR,
+                               "Matsushita Electric Industrial Co.,Ltd."),
+               DMI_MATCH(DMI_BOARD_NAME, "CF51-2L"),
+               },
+       },
+       {
+       .callback = init_nvs_nosave,
+       .ident = "Sony Vaio VGN-FW41E_H",
+       .matches = {
+               DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
+               DMI_MATCH(DMI_PRODUCT_NAME, "VGN-FW41E_H"),
+               },
+       },
+       {
+       .callback = init_nvs_nosave,
+       .ident = "Sony Vaio VGN-FW21E",
+       .matches = {
+               DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
+               DMI_MATCH(DMI_PRODUCT_NAME, "VGN-FW21E"),
+               },
+       },
+       {
+       .callback = init_nvs_nosave,
+       .ident = "Sony Vaio VGN-FW21M",
+       .matches = {
+               DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
+               DMI_MATCH(DMI_PRODUCT_NAME, "VGN-FW21M"),
+               },
+       },
+       {
+       .callback = init_nvs_nosave,
+       .ident = "Sony Vaio VPCEB17FX",
+       .matches = {
+               DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
+               DMI_MATCH(DMI_PRODUCT_NAME, "VPCEB17FX"),
+               },
+       },
+       {
+       .callback = init_nvs_nosave,
+       .ident = "Sony Vaio VGN-SR11M",
+       .matches = {
+               DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
+               DMI_MATCH(DMI_PRODUCT_NAME, "VGN-SR11M"),
+               },
+       },
+       {
+       .callback = init_nvs_nosave,
+       .ident = "Everex StepNote Series",
+       .matches = {
+               DMI_MATCH(DMI_SYS_VENDOR, "Everex Systems, Inc."),
+               DMI_MATCH(DMI_PRODUCT_NAME, "Everex StepNote Series"),
+               },
+       },
+       {
+       .callback = init_nvs_nosave,
+       .ident = "Sony Vaio VPCEB1Z1E",
+       .matches = {
+               DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
+               DMI_MATCH(DMI_PRODUCT_NAME, "VPCEB1Z1E"),
+               },
+       },
+       {
+       .callback = init_nvs_nosave,
+       .ident = "Sony Vaio VGN-NW130D",
+       .matches = {
+               DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
+               DMI_MATCH(DMI_PRODUCT_NAME, "VGN-NW130D"),
+               },
+       },
+       {
+       .callback = init_nvs_nosave,
+       .ident = "Sony Vaio VPCCW29FX",
+       .matches = {
+               DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
+               DMI_MATCH(DMI_PRODUCT_NAME, "VPCCW29FX"),
+               },
+       },
+       {
+       .callback = init_nvs_nosave,
+       .ident = "Averatec AV1020-ED2",
+       .matches = {
+               DMI_MATCH(DMI_SYS_VENDOR, "AVERATEC"),
+               DMI_MATCH(DMI_PRODUCT_NAME, "1000 Series"),
+               },
+       },
+       {
+       .callback = init_old_suspend_ordering,
+       .ident = "Asus A8N-SLI DELUXE",
+       .matches = {
+               DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
+               DMI_MATCH(DMI_BOARD_NAME, "A8N-SLI DELUXE"),
+               },
+       },
+       {
+       .callback = init_old_suspend_ordering,
+       .ident = "Asus A8N-SLI Premium",
+       .matches = {
+               DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
+               DMI_MATCH(DMI_BOARD_NAME, "A8N-SLI Premium"),
+               },
+       },
+       {
+       .callback = init_nvs_nosave,
+       .ident = "Sony Vaio VGN-SR26GN_P",
+       .matches = {
+               DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
+               DMI_MATCH(DMI_PRODUCT_NAME, "VGN-SR26GN_P"),
+               },
+       },
+       {
+       .callback = init_nvs_nosave,
+       .ident = "Sony Vaio VPCEB1S1E",
+       .matches = {
+               DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
+               DMI_MATCH(DMI_PRODUCT_NAME, "VPCEB1S1E"),
+               },
+       },
+       {
+       .callback = init_nvs_nosave,
+       .ident = "Sony Vaio VGN-FW520F",
+       .matches = {
+               DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
+               DMI_MATCH(DMI_PRODUCT_NAME, "VGN-FW520F"),
+               },
+       },
+       {
+       .callback = init_nvs_nosave,
+       .ident = "Asus K54C",
+       .matches = {
+               DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
+               DMI_MATCH(DMI_PRODUCT_NAME, "K54C"),
+               },
+       },
+       {
+       .callback = init_nvs_nosave,
+       .ident = "Asus K54HR",
+       .matches = {
+               DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
+               DMI_MATCH(DMI_PRODUCT_NAME, "K54HR"),
+               },
+       },
+       {},
+};
+
+static void acpi_sleep_dmi_check(void)
+{
+       dmi_check_system(acpisleep_dmi_table);
+}
+
 /**
  * acpi_pm_freeze - Disable the GPEs and suspend EC transactions.
  */
@@ -191,6 +402,8 @@ static void acpi_pm_finish(void)
 
        acpi_target_sleep_state = ACPI_STATE_S0;
 
+       acpi_resume_power_resources();
+
        /* If we were woken with the fixed power button, provide a small
         * hint to userspace in the form of a wakeup event on the fixed power
         * button device (if it can be found).
@@ -223,6 +436,7 @@ static void acpi_pm_end(void)
 }
 #else /* !CONFIG_ACPI_SLEEP */
 #define acpi_target_sleep_state        ACPI_STATE_S0
+static inline void acpi_sleep_dmi_check(void) {}
 #endif /* CONFIG_ACPI_SLEEP */
 
 #ifdef CONFIG_SUSPEND
@@ -242,7 +456,7 @@ static int acpi_suspend_begin(suspend_state_t pm_state)
        u32 acpi_state = acpi_suspend_states[pm_state];
        int error = 0;
 
-       error = nvs_nosave ? 0 : suspend_nvs_alloc();
+       error = (nvs_nosave || nvs_nosave_s3) ? 0 : suspend_nvs_alloc();
        if (error)
                return error;
 
@@ -382,167 +596,26 @@ static const struct platform_suspend_ops acpi_suspend_ops_old = {
        .recover = acpi_pm_finish,
 };
 
-static int __init init_old_suspend_ordering(const struct dmi_system_id *d)
+static void acpi_sleep_suspend_setup(void)
 {
-       old_suspend_ordering = true;
-       return 0;
-}
+       int i;
 
-static int __init init_nvs_nosave(const struct dmi_system_id *d)
-{
-       acpi_nvs_nosave();
-       return 0;
-}
+       for (i = ACPI_STATE_S1; i < ACPI_STATE_S4; i++) {
+               acpi_status status;
+               u8 type_a, type_b;
 
-static struct dmi_system_id __initdata acpisleep_dmi_table[] = {
-       {
-       .callback = init_old_suspend_ordering,
-       .ident = "Abit KN9 (nForce4 variant)",
-       .matches = {
-               DMI_MATCH(DMI_BOARD_VENDOR, "http://www.abit.com.tw/"),
-               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"),
-               },
-       },
-       {
-       .callback = init_old_suspend_ordering,
-       .ident = "Asus Pundit P1-AH2 (M2N8L motherboard)",
-       .matches = {
-               DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTek Computer INC."),
-               DMI_MATCH(DMI_BOARD_NAME, "M2N8L"),
-               },
-       },
-       {
-       .callback = init_old_suspend_ordering,
-       .ident = "Panasonic CF51-2L",
-       .matches = {
-               DMI_MATCH(DMI_BOARD_VENDOR,
-                               "Matsushita Electric Industrial Co.,Ltd."),
-               DMI_MATCH(DMI_BOARD_NAME, "CF51-2L"),
-               },
-       },
-       {
-       .callback = init_nvs_nosave,
-       .ident = "Sony Vaio VGN-FW21E",
-       .matches = {
-               DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
-               DMI_MATCH(DMI_PRODUCT_NAME, "VGN-FW21E"),
-               },
-       },
-       {
-       .callback = init_nvs_nosave,
-       .ident = "Sony Vaio VPCEB17FX",
-       .matches = {
-               DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
-               DMI_MATCH(DMI_PRODUCT_NAME, "VPCEB17FX"),
-               },
-       },
-       {
-       .callback = init_nvs_nosave,
-       .ident = "Sony Vaio VGN-SR11M",
-       .matches = {
-               DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
-               DMI_MATCH(DMI_PRODUCT_NAME, "VGN-SR11M"),
-               },
-       },
-       {
-       .callback = init_nvs_nosave,
-       .ident = "Everex StepNote Series",
-       .matches = {
-               DMI_MATCH(DMI_SYS_VENDOR, "Everex Systems, Inc."),
-               DMI_MATCH(DMI_PRODUCT_NAME, "Everex StepNote Series"),
-               },
-       },
-       {
-       .callback = init_nvs_nosave,
-       .ident = "Sony Vaio VPCEB1Z1E",
-       .matches = {
-               DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
-               DMI_MATCH(DMI_PRODUCT_NAME, "VPCEB1Z1E"),
-               },
-       },
-       {
-       .callback = init_nvs_nosave,
-       .ident = "Sony Vaio VGN-NW130D",
-       .matches = {
-               DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
-               DMI_MATCH(DMI_PRODUCT_NAME, "VGN-NW130D"),
-               },
-       },
-       {
-       .callback = init_nvs_nosave,
-       .ident = "Sony Vaio VPCCW29FX",
-       .matches = {
-               DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
-               DMI_MATCH(DMI_PRODUCT_NAME, "VPCCW29FX"),
-               },
-       },
-       {
-       .callback = init_nvs_nosave,
-       .ident = "Averatec AV1020-ED2",
-       .matches = {
-               DMI_MATCH(DMI_SYS_VENDOR, "AVERATEC"),
-               DMI_MATCH(DMI_PRODUCT_NAME, "1000 Series"),
-               },
-       },
-       {
-       .callback = init_old_suspend_ordering,
-       .ident = "Asus A8N-SLI DELUXE",
-       .matches = {
-               DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
-               DMI_MATCH(DMI_BOARD_NAME, "A8N-SLI DELUXE"),
-               },
-       },
-       {
-       .callback = init_old_suspend_ordering,
-       .ident = "Asus A8N-SLI Premium",
-       .matches = {
-               DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
-               DMI_MATCH(DMI_BOARD_NAME, "A8N-SLI Premium"),
-               },
-       },
-       {
-       .callback = init_nvs_nosave,
-       .ident = "Sony Vaio VGN-SR26GN_P",
-       .matches = {
-               DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
-               DMI_MATCH(DMI_PRODUCT_NAME, "VGN-SR26GN_P"),
-               },
-       },
-       {
-       .callback = init_nvs_nosave,
-       .ident = "Sony Vaio VGN-FW520F",
-       .matches = {
-               DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
-               DMI_MATCH(DMI_PRODUCT_NAME, "VGN-FW520F"),
-               },
-       },
-       {
-       .callback = init_nvs_nosave,
-       .ident = "Asus K54C",
-       .matches = {
-               DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
-               DMI_MATCH(DMI_PRODUCT_NAME, "K54C"),
-               },
-       },
-       {
-       .callback = init_nvs_nosave,
-       .ident = "Asus K54HR",
-       .matches = {
-               DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
-               DMI_MATCH(DMI_PRODUCT_NAME, "K54HR"),
-               },
-       },
-       {},
-};
-#endif /* CONFIG_SUSPEND */
+               status = acpi_get_sleep_type_data(i, &type_a, &type_b);
+               if (ACPI_SUCCESS(status)) {
+                       sleep_states[i] = 1;
+               }
+       }
+
+       suspend_set_ops(old_suspend_ordering ?
+               &acpi_suspend_ops_old : &acpi_suspend_ops);
+}
+#else /* !CONFIG_SUSPEND */
+static inline void acpi_sleep_suspend_setup(void) {}
+#endif /* !CONFIG_SUSPEND */
 
 #ifdef CONFIG_HIBERNATION
 static unsigned long s4_hardware_signature;
@@ -663,7 +736,29 @@ static const struct platform_hibernation_ops acpi_hibernation_ops_old = {
        .restore_cleanup = acpi_pm_thaw,
        .recover = acpi_pm_finish,
 };
-#endif /* CONFIG_HIBERNATION */
+
+static void acpi_sleep_hibernate_setup(void)
+{
+       acpi_status status;
+       u8 type_a, type_b;
+
+       status = acpi_get_sleep_type_data(ACPI_STATE_S4, &type_a, &type_b);
+       if (ACPI_FAILURE(status))
+               return;
+
+       hibernation_set_ops(old_suspend_ordering ?
+                       &acpi_hibernation_ops_old : &acpi_hibernation_ops);
+       sleep_states[ACPI_STATE_S4] = 1;
+       if (nosigcheck)
+               return;
+
+       acpi_get_table(ACPI_SIG_FACS, 1, (struct acpi_table_header **)&facs);
+       if (facs)
+               s4_hardware_signature = facs->hardware_signature;
+}
+#else /* !CONFIG_HIBERNATION */
+static inline void acpi_sleep_hibernate_setup(void) {}
+#endif /* !CONFIG_HIBERNATION */
 
 int acpi_suspend(u32 acpi_state)
 {
@@ -680,63 +775,6 @@ int acpi_suspend(u32 acpi_state)
        return -EINVAL;
 }
 
-#ifdef CONFIG_PM
-/**
- * acpi_pm_device_sleep_state - Get preferred power state of ACPI device.
- * @dev: Device whose preferred target power state to return.
- * @d_min_p: Location to store the upper limit of the allowed states range.
- * @d_max_in: Deepest low-power state to take into consideration.
- * Return value: Preferred power state of the device on success, -ENODEV
- * (if there's no 'struct acpi_device' for @dev) or -EINVAL on failure
- *
- * The caller must ensure that @dev is valid before using this function.
- */
-int acpi_pm_device_sleep_state(struct device *dev, int *d_min_p, int d_max_in)
-{
-       acpi_handle handle = DEVICE_ACPI_HANDLE(dev);
-       struct acpi_device *adev;
-
-       if (!handle || ACPI_FAILURE(acpi_bus_get_device(handle, &adev))) {
-               dev_dbg(dev, "ACPI handle without context in %s!\n", __func__);
-               return -ENODEV;
-       }
-
-       return acpi_device_power_state(dev, adev, acpi_target_sleep_state,
-                                      d_max_in, d_min_p);
-}
-EXPORT_SYMBOL(acpi_pm_device_sleep_state);
-#endif /* CONFIG_PM */
-
-#ifdef CONFIG_PM_SLEEP
-/**
- * acpi_pm_device_sleep_wake - Enable or disable device to wake up the system.
- * @dev: Device to enable/desible to wake up the system from sleep states.
- * @enable: Whether to enable or disable @dev to wake up the system.
- */
-int acpi_pm_device_sleep_wake(struct device *dev, bool enable)
-{
-       acpi_handle handle;
-       struct acpi_device *adev;
-       int error;
-
-       if (!device_can_wakeup(dev))
-               return -EINVAL;
-
-       handle = DEVICE_ACPI_HANDLE(dev);
-       if (!handle || ACPI_FAILURE(acpi_bus_get_device(handle, &adev))) {
-               dev_dbg(dev, "ACPI handle without context in %s!\n", __func__);
-               return -ENODEV;
-       }
-
-       error = __acpi_device_sleep_wake(adev, acpi_target_sleep_state, enable);
-       if (!error)
-               dev_info(dev, "System wakeup %s by ACPI\n",
-                               enable ? "enabled" : "disabled");
-
-       return error;
-}
-#endif  /* CONFIG_PM_SLEEP */
-
 static void acpi_power_off_prepare(void)
 {
        /* Prepare to power off the system */
@@ -756,55 +794,34 @@ 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
+       char supported[ACPI_S_STATE_COUNT * 3 + 1];
+       char *pos = supported;
+       int i;
 
        if (acpi_disabled)
                return 0;
 
-       sleep_states[ACPI_STATE_S0] = 1;
-       printk(KERN_INFO PREFIX "(supports S0");
+       acpi_sleep_dmi_check();
 
-#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(KERN_CONT " S%d", i);
-               }
-       }
+       sleep_states[ACPI_STATE_S0] = 1;
 
-       suspend_set_ops(old_suspend_ordering ?
-               &acpi_suspend_ops_old : &acpi_suspend_ops);
-#endif
+       acpi_sleep_suspend_setup();
+       acpi_sleep_hibernate_setup();
 
-#ifdef CONFIG_HIBERNATION
-       status = acpi_get_sleep_type_data(ACPI_STATE_S4, &type_a, &type_b);
-       if (ACPI_SUCCESS(status)) {
-               hibernation_set_ops(old_suspend_ordering ?
-                       &acpi_hibernation_ops_old : &acpi_hibernation_ops);
-               sleep_states[ACPI_STATE_S4] = 1;
-               printk(KERN_CONT " S4");
-               if (!nosigcheck) {
-                       acpi_get_table(ACPI_SIG_FACS, 1,
-                               (struct acpi_table_header **)&facs);
-                       if (facs)
-                               s4_hardware_signature =
-                                       facs->hardware_signature;
-               }
-       }
-#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(KERN_CONT " S5");
                pm_power_off_prepare = acpi_power_off_prepare;
                pm_power_off = acpi_power_off;
        }
-       printk(KERN_CONT ")\n");
+
+       supported[0] = 0;
+       for (i = 0; i < ACPI_S_STATE_COUNT; i++) {
+               if (sleep_states[i])
+                       pos += sprintf(pos, " S%d", i);
+       }
+       pr_info(PREFIX "(supports%s)\n", supported);
+
        /*
         * Register the tts_notifier to reboot notifier list so that the _TTS
         * object can also be evaluated when the system enters S5.