| From 75bd3bf2ade9d548be0d2bde60b5ee0fdce0b127 Mon Sep 17 00:00:00 2001 |
| From: Henrique de Moraes Holschuh <hmh@hmh.eng.br> |
| Date: Tue, 14 Apr 2009 02:44:11 +0000 |
| Subject: thinkpad-acpi: fix LED blinking through timer trigger |
| |
| From: Henrique de Moraes Holschuh <hmh@hmh.eng.br> |
| |
| commit 75bd3bf2ade9d548be0d2bde60b5ee0fdce0b127 upstream. |
| |
| The set_blink hook code in the LED subdriver would never manage to get |
| a LED to blink, and instead it would just turn it on. The consequence |
| of this is that the "timer" trigger would not cause the LED to blink |
| if given default parameters. |
| |
| This problem exists since 2.6.26-rc1. |
| |
| To fix it, switch the deferred LED work handling to use the |
| thinkpad-acpi-specific LED status (off/on/blink) directly. |
| |
| This also makes the code easier to read, and to extend later. |
| |
| Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br> |
| Cc: stable@kernel.org |
| Signed-off-by: Len Brown <len.brown@intel.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> |
| |
| --- |
| drivers/misc/thinkpad_acpi.c | 41 +++++++++++++++++++---------------------- |
| 1 file changed, 19 insertions(+), 22 deletions(-) |
| |
| --- a/drivers/misc/thinkpad_acpi.c |
| +++ b/drivers/misc/thinkpad_acpi.c |
| @@ -281,11 +281,17 @@ static u32 dbg_level; |
| |
| static struct workqueue_struct *tpacpi_wq; |
| |
| +enum led_status_t { |
| + TPACPI_LED_OFF = 0, |
| + TPACPI_LED_ON, |
| + TPACPI_LED_BLINK, |
| +}; |
| + |
| /* Special LED class that can defer work */ |
| struct tpacpi_led_classdev { |
| struct led_classdev led_classdev; |
| struct work_struct work; |
| - enum led_brightness new_brightness; |
| + enum led_status_t new_state; |
| unsigned int led; |
| }; |
| |
| @@ -3489,7 +3495,7 @@ static void light_set_status_worker(stru |
| container_of(work, struct tpacpi_led_classdev, work); |
| |
| if (likely(tpacpi_lifecycle == TPACPI_LIFE_RUNNING)) |
| - light_set_status((data->new_brightness != LED_OFF)); |
| + light_set_status((data->new_state != TPACPI_LED_OFF)); |
| } |
| |
| static void light_sysfs_set(struct led_classdev *led_cdev, |
| @@ -3499,7 +3505,8 @@ static void light_sysfs_set(struct led_c |
| container_of(led_cdev, |
| struct tpacpi_led_classdev, |
| led_classdev); |
| - data->new_brightness = brightness; |
| + data->new_state = (brightness != LED_OFF) ? |
| + TPACPI_LED_ON : TPACPI_LED_OFF; |
| queue_work(tpacpi_wq, &data->work); |
| } |
| |
| @@ -4006,12 +4013,6 @@ enum { /* For TPACPI_LED_OLD */ |
| TPACPI_LED_EC_HLMS = 0x0e, /* EC reg to select led to command */ |
| }; |
| |
| -enum led_status_t { |
| - TPACPI_LED_OFF = 0, |
| - TPACPI_LED_ON, |
| - TPACPI_LED_BLINK, |
| -}; |
| - |
| static enum led_access_mode led_supported; |
| |
| TPACPI_HANDLE(led, ec, "SLED", /* 570 */ |
| @@ -4105,23 +4106,13 @@ static int led_set_status(const unsigned |
| return rc; |
| } |
| |
| -static void led_sysfs_set_status(unsigned int led, |
| - enum led_brightness brightness) |
| -{ |
| - led_set_status(led, |
| - (brightness == LED_OFF) ? |
| - TPACPI_LED_OFF : |
| - (tpacpi_led_state_cache[led] == TPACPI_LED_BLINK) ? |
| - TPACPI_LED_BLINK : TPACPI_LED_ON); |
| -} |
| - |
| static void led_set_status_worker(struct work_struct *work) |
| { |
| struct tpacpi_led_classdev *data = |
| container_of(work, struct tpacpi_led_classdev, work); |
| |
| if (likely(tpacpi_lifecycle == TPACPI_LIFE_RUNNING)) |
| - led_sysfs_set_status(data->led, data->new_brightness); |
| + led_set_status(data->led, data->new_state); |
| } |
| |
| static void led_sysfs_set(struct led_classdev *led_cdev, |
| @@ -4130,7 +4121,13 @@ static void led_sysfs_set(struct led_cla |
| struct tpacpi_led_classdev *data = container_of(led_cdev, |
| struct tpacpi_led_classdev, led_classdev); |
| |
| - data->new_brightness = brightness; |
| + if (brightness == LED_OFF) |
| + data->new_state = TPACPI_LED_OFF; |
| + else if (tpacpi_led_state_cache[data->led] != TPACPI_LED_BLINK) |
| + data->new_state = TPACPI_LED_ON; |
| + else |
| + data->new_state = TPACPI_LED_BLINK; |
| + |
| queue_work(tpacpi_wq, &data->work); |
| } |
| |
| @@ -4148,7 +4145,7 @@ static int led_sysfs_blink_set(struct le |
| } else if ((*delay_on != 500) || (*delay_off != 500)) |
| return -EINVAL; |
| |
| - data->new_brightness = TPACPI_LED_BLINK; |
| + data->new_state = TPACPI_LED_BLINK; |
| queue_work(tpacpi_wq, &data->work); |
| |
| return 0; |