diff options
-rw-r--r-- | Documentation/laptops/thinkpad-acpi.txt | 25 | ||||
-rw-r--r-- | drivers/misc/thinkpad_acpi.c | 57 |
2 files changed, 76 insertions, 6 deletions
diff --git a/Documentation/laptops/thinkpad-acpi.txt b/Documentation/laptops/thinkpad-acpi.txt index a41bc893f8d6..af1f2bcb6f66 100644 --- a/Documentation/laptops/thinkpad-acpi.txt +++ b/Documentation/laptops/thinkpad-acpi.txt | |||
@@ -693,16 +693,31 @@ while others are still having problems. For more information: | |||
693 | 693 | ||
694 | https://bugs.freedesktop.org/show_bug.cgi?id=2000 | 694 | https://bugs.freedesktop.org/show_bug.cgi?id=2000 |
695 | 695 | ||
696 | ThinkLight control -- /proc/acpi/ibm/light | 696 | ThinkLight control |
697 | ------------------------------------------ | 697 | ------------------ |
698 | |||
699 | procfs: /proc/acpi/ibm/light | ||
700 | sysfs attributes: as per led class, for the "tpacpi::thinklight" led | ||
701 | |||
702 | procfs notes: | ||
698 | 703 | ||
699 | The current status of the ThinkLight can be found in this file. A few | 704 | The ThinkLight status can be read and set through the procfs interface. A |
700 | models which do not make the status available will show it as | 705 | few models which do not make the status available will show the ThinkLight |
701 | "unknown". The available commands are: | 706 | status as "unknown". The available commands are: |
702 | 707 | ||
703 | echo on > /proc/acpi/ibm/light | 708 | echo on > /proc/acpi/ibm/light |
704 | echo off > /proc/acpi/ibm/light | 709 | echo off > /proc/acpi/ibm/light |
705 | 710 | ||
711 | sysfs notes: | ||
712 | |||
713 | The ThinkLight sysfs interface is documented by the led class | ||
714 | documentation, in Documentation/leds-class.txt. The ThinkLight led name | ||
715 | is "tpacpi::thinklight". | ||
716 | |||
717 | Due to limitations in the sysfs led class, if the status of the thinklight | ||
718 | cannot be read or if it is unknown, thinkpad-acpi will report it as "off". | ||
719 | It is impossible to know if the status returned through sysfs is valid. | ||
720 | |||
706 | Docking / undocking -- /proc/acpi/ibm/dock | 721 | Docking / undocking -- /proc/acpi/ibm/dock |
707 | ------------------------------------------ | 722 | ------------------------------------------ |
708 | 723 | ||
diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c index 5a3fb09f10d3..38a119bd931e 100644 --- a/drivers/misc/thinkpad_acpi.c +++ b/drivers/misc/thinkpad_acpi.c | |||
@@ -3280,13 +3280,49 @@ static int light_set_status(int status) | |||
3280 | return -ENXIO; | 3280 | return -ENXIO; |
3281 | } | 3281 | } |
3282 | 3282 | ||
3283 | static void light_set_status_worker(struct work_struct *work) | ||
3284 | { | ||
3285 | struct tpacpi_led_classdev *data = | ||
3286 | container_of(work, struct tpacpi_led_classdev, work); | ||
3287 | |||
3288 | if (likely(tpacpi_lifecycle == TPACPI_LIFE_RUNNING)) | ||
3289 | light_set_status((data->new_brightness != LED_OFF)); | ||
3290 | } | ||
3291 | |||
3292 | static void light_sysfs_set(struct led_classdev *led_cdev, | ||
3293 | enum led_brightness brightness) | ||
3294 | { | ||
3295 | struct tpacpi_led_classdev *data = | ||
3296 | container_of(led_cdev, | ||
3297 | struct tpacpi_led_classdev, | ||
3298 | led_classdev); | ||
3299 | data->new_brightness = brightness; | ||
3300 | schedule_work(&data->work); | ||
3301 | } | ||
3302 | |||
3303 | static enum led_brightness light_sysfs_get(struct led_classdev *led_cdev) | ||
3304 | { | ||
3305 | return (light_get_status() == 1)? LED_FULL : LED_OFF; | ||
3306 | } | ||
3307 | |||
3308 | static struct tpacpi_led_classdev tpacpi_led_thinklight = { | ||
3309 | .led_classdev = { | ||
3310 | .name = "tpacpi::thinklight", | ||
3311 | .brightness_set = &light_sysfs_set, | ||
3312 | .brightness_get = &light_sysfs_get, | ||
3313 | } | ||
3314 | }; | ||
3315 | |||
3283 | static int __init light_init(struct ibm_init_struct *iibm) | 3316 | static int __init light_init(struct ibm_init_struct *iibm) |
3284 | { | 3317 | { |
3318 | int rc = 0; | ||
3319 | |||
3285 | vdbg_printk(TPACPI_DBG_INIT, "initializing light subdriver\n"); | 3320 | vdbg_printk(TPACPI_DBG_INIT, "initializing light subdriver\n"); |
3286 | 3321 | ||
3287 | TPACPI_ACPIHANDLE_INIT(ledb); | 3322 | TPACPI_ACPIHANDLE_INIT(ledb); |
3288 | TPACPI_ACPIHANDLE_INIT(lght); | 3323 | TPACPI_ACPIHANDLE_INIT(lght); |
3289 | TPACPI_ACPIHANDLE_INIT(cmos); | 3324 | TPACPI_ACPIHANDLE_INIT(cmos); |
3325 | INIT_WORK(&tpacpi_led_thinklight.work, light_set_status_worker); | ||
3290 | 3326 | ||
3291 | /* light not supported on 570, 600e/x, 770e, 770x, G4x, R30, R31 */ | 3327 | /* light not supported on 570, 600e/x, 770e, 770x, G4x, R30, R31 */ |
3292 | tp_features.light = (cmos_handle || lght_handle) && !ledb_handle; | 3328 | tp_features.light = (cmos_handle || lght_handle) && !ledb_handle; |
@@ -3300,7 +3336,25 @@ static int __init light_init(struct ibm_init_struct *iibm) | |||
3300 | vdbg_printk(TPACPI_DBG_INIT, "light is %s\n", | 3336 | vdbg_printk(TPACPI_DBG_INIT, "light is %s\n", |
3301 | str_supported(tp_features.light)); | 3337 | str_supported(tp_features.light)); |
3302 | 3338 | ||
3303 | return (tp_features.light)? 0 : 1; | 3339 | if (tp_features.light) { |
3340 | rc = led_classdev_register(&tpacpi_pdev->dev, | ||
3341 | &tpacpi_led_thinklight.led_classdev); | ||
3342 | } | ||
3343 | |||
3344 | if (rc < 0) { | ||
3345 | tp_features.light = 0; | ||
3346 | tp_features.light_status = 0; | ||
3347 | } else { | ||
3348 | rc = (tp_features.light)? 0 : 1; | ||
3349 | } | ||
3350 | return rc; | ||
3351 | } | ||
3352 | |||
3353 | static void light_exit(void) | ||
3354 | { | ||
3355 | led_classdev_unregister(&tpacpi_led_thinklight.led_classdev); | ||
3356 | if (work_pending(&tpacpi_led_thinklight.work)) | ||
3357 | flush_scheduled_work(); | ||
3304 | } | 3358 | } |
3305 | 3359 | ||
3306 | static int light_read(char *p) | 3360 | static int light_read(char *p) |
@@ -3348,6 +3402,7 @@ static struct ibm_struct light_driver_data = { | |||
3348 | .name = "light", | 3402 | .name = "light", |
3349 | .read = light_read, | 3403 | .read = light_read, |
3350 | .write = light_write, | 3404 | .write = light_write, |
3405 | .exit = light_exit, | ||
3351 | }; | 3406 | }; |
3352 | 3407 | ||
3353 | /************************************************************************* | 3408 | /************************************************************************* |