From 75700e53cd14ccc7a5a42547497dff11fe209186 Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Sat, 18 Oct 2008 14:23:52 -0300 Subject: [PATCH 1/4] ACPI: thinkpad-acpi: attempt to preserve fan state on resume Attempt to preserve fan state across sleep and hibernation if the fan control mode is enabled. For safety reasons, only the PWM OFF (fan at 100%) or maximum closed-loop level (level 7) are preserved. If the fan state was set to anything else, it will not be restored. Also, should the fan be at PWM OFF mode at resume, it will be left at that state (but this is extremely unlikely, no ThinkPad firmware was ever reported to do this). For reference, the known states used for fan control upon resume by the firmware are either "auto" or "level 7" depending on whether the laptop wakes due to normal conditions or a thermal emergency. Fixes: http://bugzilla.kernel.org/show_bug.cgi?id=11331 Signed-off-by: Henrique de Moraes Holschuh Cc: Richard Hartmann Signed-off-by: Len Brown --- drivers/misc/thinkpad_acpi.c | 48 ++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c index 6b9300779a43..1dcf0660d8b5 100644 --- a/drivers/misc/thinkpad_acpi.c +++ b/drivers/misc/thinkpad_acpi.c @@ -5983,6 +5983,52 @@ static void fan_exit(void) flush_workqueue(tpacpi_wq); } +static void fan_suspend(pm_message_t state) +{ + if (!fan_control_allowed) + return; + + /* Store fan status in cache */ + fan_get_status_safe(NULL); + if (tp_features.fan_ctrl_status_undef) + fan_control_desired_level = TP_EC_FAN_AUTO; +} + +static void fan_resume(void) +{ + u8 saved_fan_level; + u8 current_level = 7; + bool do_set = false; + + /* DSDT *always* updates status on resume */ + tp_features.fan_ctrl_status_undef = 0; + + saved_fan_level = fan_control_desired_level; + if (!fan_control_allowed || + (fan_get_status_safe(¤t_level) < 0)) + return; + + switch (fan_control_access_mode) { + case TPACPI_FAN_WR_ACPI_SFAN: + do_set = (saved_fan_level > current_level); + break; + case TPACPI_FAN_WR_ACPI_FANS: + case TPACPI_FAN_WR_TPEC: + do_set = ((saved_fan_level & TP_EC_FAN_FULLSPEED) || + (saved_fan_level == 7 && + !(current_level & TP_EC_FAN_FULLSPEED))); + break; + default: + return; + } + if (do_set) { + printk(TPACPI_NOTICE + "restoring fan level to 0x%02x\n", + saved_fan_level); + fan_set_level_safe(saved_fan_level); + } +} + static int fan_read(char *p) { int len = 0; @@ -6174,6 +6220,8 @@ static struct ibm_struct fan_driver_data = { .read = fan_read, .write = fan_write, .exit = fan_exit, + .suspend = fan_suspend, + .resume = fan_resume, }; /**************************************************************************** From 4f778b92c9d8d87c670fc063c66edf1aa46f6f1c Mon Sep 17 00:00:00 2001 From: Mariusz Kozlowski Date: Sat, 18 Oct 2008 14:23:53 -0300 Subject: [PATCH 2/4] ACPI: thinkpad-acpi: trivial fix of error message Trivial fix makes the error message match the code before it (ibm->driver vs ibm->acpi-driver) better. Signed-off-by: Mariusz Kozlowski Acked-by: Henrique de Moraes Holschuh Signed-off-by: Len Brown --- drivers/misc/thinkpad_acpi.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c index 1dcf0660d8b5..6c9b6c892288 100644 --- a/drivers/misc/thinkpad_acpi.c +++ b/drivers/misc/thinkpad_acpi.c @@ -582,7 +582,8 @@ static int __init register_tpacpi_subdriver(struct ibm_struct *ibm) ibm->acpi->driver = kzalloc(sizeof(struct acpi_driver), GFP_KERNEL); if (!ibm->acpi->driver) { - printk(TPACPI_ERR "kzalloc(ibm->driver) failed\n"); + printk(TPACPI_ERR + "failed to allocate memory for ibm->acpi->driver\n"); return -ENOMEM; } From 396293237cbc964fcedd4208cbc0d0f4880a98bb Mon Sep 17 00:00:00 2001 From: Pascal Terjan Date: Sat, 18 Oct 2008 14:23:54 -0300 Subject: [PATCH 3/4] ACPI: thinkpad-acpi: Remove duplicate line Signed-off-by: Pascal Terjan Acked-by: Henrique de Moraes Holschuh Signed-off-by: Len Brown --- drivers/misc/thinkpad_acpi.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c index 6c9b6c892288..4c47f9b80478 100644 --- a/drivers/misc/thinkpad_acpi.c +++ b/drivers/misc/thinkpad_acpi.c @@ -158,7 +158,6 @@ enum { #define TPACPI_INFO KERN_INFO TPACPI_LOG #define TPACPI_DEBUG KERN_DEBUG TPACPI_LOG -#define TPACPI_DBG_ALL 0xffff #define TPACPI_DBG_ALL 0xffff #define TPACPI_DBG_INIT 0x0001 #define TPACPI_DBG_EXIT 0x0002 From d64c81c4cea0a14e88fc76e2c845e4885e491754 Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Sat, 18 Oct 2008 14:23:55 -0300 Subject: [PATCH 4/4] ACPI: thinkpad-acpi: Remove firmware backlight delays for Intel ACPI IGD OpRegion Based on analysis and a patch from Matthew Garrett . Instruct the ThinkPad ACPI firmware to remove delays on the processing of backlight brightness changes. This method is present on ThinkPad Vista-compatible BIOSes with standard ACPI backlight level control. Signed-off-by: Henrique de Moraes Holschuh Cc: Matthew Garrett Cc: Yves-Alexis Perez Signed-off-by: Len Brown --- drivers/misc/thinkpad_acpi.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c index 4c47f9b80478..17b8281deee5 100644 --- a/drivers/misc/thinkpad_acpi.c +++ b/drivers/misc/thinkpad_acpi.c @@ -838,6 +838,13 @@ static int parse_strtoul(const char *buf, return 0; } +static void tpacpi_disable_brightness_delay(void) +{ + if (acpi_evalf(hkey_handle, NULL, "PWMS", "qvd", 0)) + printk(TPACPI_NOTICE + "ACPI backlight control delay disabled\n"); +} + static int __init tpacpi_query_bcl_levels(acpi_handle handle) { struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; @@ -2139,6 +2146,8 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) if (!tp_features.hotkey) return 1; + tpacpi_disable_brightness_delay(); + hotkey_dev_attributes = create_attr_set(13, NULL); if (!hotkey_dev_attributes) return -ENOMEM; @@ -2512,6 +2521,8 @@ static void hotkey_suspend(pm_message_t state) static void hotkey_resume(void) { + tpacpi_disable_brightness_delay(); + if (hotkey_mask_get()) printk(TPACPI_ERR "error while trying to read hot key mask "