aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/laptops/thinkpad-acpi.txt25
-rw-r--r--drivers/misc/thinkpad_acpi.c57
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
694https://bugs.freedesktop.org/show_bug.cgi?id=2000 694https://bugs.freedesktop.org/show_bug.cgi?id=2000
695 695
696ThinkLight control -- /proc/acpi/ibm/light 696ThinkLight control
697------------------------------------------ 697------------------
698
699procfs: /proc/acpi/ibm/light
700sysfs attributes: as per led class, for the "tpacpi::thinklight" led
701
702procfs notes:
698 703
699The current status of the ThinkLight can be found in this file. A few 704The ThinkLight status can be read and set through the procfs interface. A
700models which do not make the status available will show it as 705few models which do not make the status available will show the ThinkLight
701"unknown". The available commands are: 706status 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
711sysfs notes:
712
713The ThinkLight sysfs interface is documented by the led class
714documentation, in Documentation/leds-class.txt. The ThinkLight led name
715is "tpacpi::thinklight".
716
717Due to limitations in the sysfs led class, if the status of the thinklight
718cannot be read or if it is unknown, thinkpad-acpi will report it as "off".
719It is impossible to know if the status returned through sysfs is valid.
720
706Docking / undocking -- /proc/acpi/ibm/dock 721Docking / 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
3283static 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
3292static 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
3303static enum led_brightness light_sysfs_get(struct led_classdev *led_cdev)
3304{
3305 return (light_get_status() == 1)? LED_FULL : LED_OFF;
3306}
3307
3308static 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
3283static int __init light_init(struct ibm_init_struct *iibm) 3316static 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
3353static 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
3306static int light_read(char *p) 3360static 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/*************************************************************************