aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHenrique de Moraes Holschuh <hmh@hmh.eng.br>2009-04-13 22:44:11 -0400
committerLen Brown <len.brown@intel.com>2009-04-18 01:19:53 -0400
commit75bd3bf2ade9d548be0d2bde60b5ee0fdce0b127 (patch)
tree0133d0631c052d4f3a9b9f3feee4dd905442b431
parent406e988bef742aa74cdc1f5fafc812ecebf7c02b (diff)
thinkpad-acpi: fix LED blinking through timer trigger
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>
-rw-r--r--drivers/platform/x86/thinkpad_acpi.c41
1 files changed, 19 insertions, 22 deletions
diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c
index a186c5bbdcd9..a1d2abce3090 100644
--- a/drivers/platform/x86/thinkpad_acpi.c
+++ b/drivers/platform/x86/thinkpad_acpi.c
@@ -303,11 +303,17 @@ static u32 dbg_level;
303 303
304static struct workqueue_struct *tpacpi_wq; 304static struct workqueue_struct *tpacpi_wq;
305 305
306enum led_status_t {
307 TPACPI_LED_OFF = 0,
308 TPACPI_LED_ON,
309 TPACPI_LED_BLINK,
310};
311
306/* Special LED class that can defer work */ 312/* Special LED class that can defer work */
307struct tpacpi_led_classdev { 313struct tpacpi_led_classdev {
308 struct led_classdev led_classdev; 314 struct led_classdev led_classdev;
309 struct work_struct work; 315 struct work_struct work;
310 enum led_brightness new_brightness; 316 enum led_status_t new_state;
311 unsigned int led; 317 unsigned int led;
312}; 318};
313 319
@@ -4213,7 +4219,7 @@ static void light_set_status_worker(struct work_struct *work)
4213 container_of(work, struct tpacpi_led_classdev, work); 4219 container_of(work, struct tpacpi_led_classdev, work);
4214 4220
4215 if (likely(tpacpi_lifecycle == TPACPI_LIFE_RUNNING)) 4221 if (likely(tpacpi_lifecycle == TPACPI_LIFE_RUNNING))
4216 light_set_status((data->new_brightness != LED_OFF)); 4222 light_set_status((data->new_state != TPACPI_LED_OFF));
4217} 4223}
4218 4224
4219static void light_sysfs_set(struct led_classdev *led_cdev, 4225static void light_sysfs_set(struct led_classdev *led_cdev,
@@ -4223,7 +4229,8 @@ static void light_sysfs_set(struct led_classdev *led_cdev,
4223 container_of(led_cdev, 4229 container_of(led_cdev,
4224 struct tpacpi_led_classdev, 4230 struct tpacpi_led_classdev,
4225 led_classdev); 4231 led_classdev);
4226 data->new_brightness = brightness; 4232 data->new_state = (brightness != LED_OFF) ?
4233 TPACPI_LED_ON : TPACPI_LED_OFF;
4227 queue_work(tpacpi_wq, &data->work); 4234 queue_work(tpacpi_wq, &data->work);
4228} 4235}
4229 4236
@@ -4730,12 +4737,6 @@ enum { /* For TPACPI_LED_OLD */
4730 TPACPI_LED_EC_HLMS = 0x0e, /* EC reg to select led to command */ 4737 TPACPI_LED_EC_HLMS = 0x0e, /* EC reg to select led to command */
4731}; 4738};
4732 4739
4733enum led_status_t {
4734 TPACPI_LED_OFF = 0,
4735 TPACPI_LED_ON,
4736 TPACPI_LED_BLINK,
4737};
4738
4739static enum led_access_mode led_supported; 4740static enum led_access_mode led_supported;
4740 4741
4741TPACPI_HANDLE(led, ec, "SLED", /* 570 */ 4742TPACPI_HANDLE(led, ec, "SLED", /* 570 */
@@ -4847,23 +4848,13 @@ static int led_set_status(const unsigned int led,
4847 return rc; 4848 return rc;
4848} 4849}
4849 4850
4850static void led_sysfs_set_status(unsigned int led,
4851 enum led_brightness brightness)
4852{
4853 led_set_status(led,
4854 (brightness == LED_OFF) ?
4855 TPACPI_LED_OFF :
4856 (tpacpi_led_state_cache[led] == TPACPI_LED_BLINK) ?
4857 TPACPI_LED_BLINK : TPACPI_LED_ON);
4858}
4859
4860static void led_set_status_worker(struct work_struct *work) 4851static void led_set_status_worker(struct work_struct *work)
4861{ 4852{
4862 struct tpacpi_led_classdev *data = 4853 struct tpacpi_led_classdev *data =
4863 container_of(work, struct tpacpi_led_classdev, work); 4854 container_of(work, struct tpacpi_led_classdev, work);
4864 4855
4865 if (likely(tpacpi_lifecycle == TPACPI_LIFE_RUNNING)) 4856 if (likely(tpacpi_lifecycle == TPACPI_LIFE_RUNNING))
4866 led_sysfs_set_status(data->led, data->new_brightness); 4857 led_set_status(data->led, data->new_state);
4867} 4858}
4868 4859
4869static void led_sysfs_set(struct led_classdev *led_cdev, 4860static void led_sysfs_set(struct led_classdev *led_cdev,
@@ -4872,7 +4863,13 @@ static void led_sysfs_set(struct led_classdev *led_cdev,
4872 struct tpacpi_led_classdev *data = container_of(led_cdev, 4863 struct tpacpi_led_classdev *data = container_of(led_cdev,
4873 struct tpacpi_led_classdev, led_classdev); 4864 struct tpacpi_led_classdev, led_classdev);
4874 4865
4875 data->new_brightness = brightness; 4866 if (brightness == LED_OFF)
4867 data->new_state = TPACPI_LED_OFF;
4868 else if (tpacpi_led_state_cache[data->led] != TPACPI_LED_BLINK)
4869 data->new_state = TPACPI_LED_ON;
4870 else
4871 data->new_state = TPACPI_LED_BLINK;
4872
4876 queue_work(tpacpi_wq, &data->work); 4873 queue_work(tpacpi_wq, &data->work);
4877} 4874}
4878 4875
@@ -4890,7 +4887,7 @@ static int led_sysfs_blink_set(struct led_classdev *led_cdev,
4890 } else if ((*delay_on != 500) || (*delay_off != 500)) 4887 } else if ((*delay_on != 500) || (*delay_off != 500))
4891 return -EINVAL; 4888 return -EINVAL;
4892 4889
4893 data->new_brightness = TPACPI_LED_BLINK; 4890 data->new_state = TPACPI_LED_BLINK;
4894 queue_work(tpacpi_wq, &data->work); 4891 queue_work(tpacpi_wq, &data->work);
4895 4892
4896 return 0; 4893 return 0;