From e9ae71078b2c8657c0e8de808b76b76049806906 Mon Sep 17 00:00:00 2001 From: Zhang Rui Date: Tue, 22 Apr 2008 08:50:09 +0800 Subject: thermal: update the documentation Update the documentation for the thermal driver hwmon sys I/F. Change the ACPI thermal zone type to be consistent with hwmon. Signed-off-by: Zhang Rui Acked-by: Jean Delvare Signed-off-by: Len Brown --- Documentation/thermal/sysfs-api.txt | 33 +++++++++++++++++++++++++++------ 1 file changed, 27 insertions(+), 6 deletions(-) (limited to 'Documentation') diff --git a/Documentation/thermal/sysfs-api.txt b/Documentation/thermal/sysfs-api.txt index d9f28be75403..70d68ce8640a 100644 --- a/Documentation/thermal/sysfs-api.txt +++ b/Documentation/thermal/sysfs-api.txt @@ -108,10 +108,12 @@ and throttle appropriate devices. RO read only value RW read/write value -All thermal sysfs attributes will be represented under /sys/class/thermal +Thermal sysfs attributes will be represented under /sys/class/thermal. +Hwmon sysfs I/F extension is also available under /sys/class/hwmon +if hwmon is compiled in or built as a module. Thermal zone device sys I/F, created once it's registered: -|thermal_zone[0-*]: +/sys/class/thermal/thermal_zone[0-*]: |-----type: Type of the thermal zone |-----temp: Current temperature |-----mode: Working mode of the thermal zone @@ -119,7 +121,7 @@ Thermal zone device sys I/F, created once it's registered: |-----trip_point_[0-*]_type: Trip point type Thermal cooling device sys I/F, created once it's registered: -|cooling_device[0-*]: +/sys/class/thermal/cooling_device[0-*]: |-----type : Type of the cooling device(processor/fan/...) |-----max_state: Maximum cooling state of the cooling device |-----cur_state: Current cooling state of the cooling device @@ -130,10 +132,19 @@ They represent the relationship between a thermal zone and its associated coolin They are created/removed for each thermal_zone_bind_cooling_device/thermal_zone_unbind_cooling_device successful execution. -|thermal_zone[0-*] +/sys/class/thermal/thermal_zone[0-*] |-----cdev[0-*]: The [0-*]th cooling device in the current thermal zone |-----cdev[0-*]_trip_point: Trip point that cdev[0-*] is associated with +Besides the thermal zone device sysfs I/F and cooling device sysfs I/F, +the generic thermal driver also creates a hwmon sysfs I/F for each _type_ of +thermal zone device. E.g. the generic thermal driver registers one hwmon class device +and build the associated hwmon sysfs I/F for all the registered ACPI thermal zones. +/sys/class/hwmon/hwmon[0-*]: + |-----name: The type of the thermal zone devices. + |-----temp[1-*]_input: The current temperature of thermal zone [1-*]. + |-----temp[1-*]_critical: The critical trip point of thermal zone [1-*]. +Please read Documentation/hwmon/sysfs-interface for additional information. *************************** * Thermal zone attributes * @@ -141,7 +152,10 @@ thermal_zone_bind_cooling_device/thermal_zone_unbind_cooling_device successful e type Strings which represent the thermal zone type. This is given by thermal zone driver as part of registration. - Eg: "ACPI thermal zone" indicates it's a ACPI thermal device + Eg: "acpitz" indicates it's an ACPI thermal device. + In order to keep it consistent with hwmon sys attribute, + this should be a short, lowercase string, + not containing spaces nor dashes. RO Required @@ -218,7 +232,7 @@ the sys I/F structure will be built like this: /sys/class/thermal: |thermal_zone1: - |-----type: ACPI thermal zone + |-----type: acpitz |-----temp: 37000 |-----mode: kernel |-----trip_point_0_temp: 100000 @@ -243,3 +257,10 @@ the sys I/F structure will be built like this: |-----type: Fan |-----max_state: 2 |-----cur_state: 0 + +/sys/class/hwmon: + +|hwmon0: + |-----name: acpitz + |-----temp1_input: 37000 + |-----temp1_crit: 100000 -- cgit v1.2.3 From b59727965d7f286489206c292e2788d4835a8a23 Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Sat, 26 Apr 2008 01:02:17 -0300 Subject: ACPI: thinkpad-acpi: BIOS backlight mode helper (v2.1) Lenovo ThinkPads with generic ACPI backlight level control can be easily set to react to keyboard brightness key presses in a more predictable way than what they do when in "DOS / bootloader" mode after Linux brings up the ACPI interface. The switch to the ACPI backlight mode in the firmware is designed to be safe to use only as an one way trapdoor. One is not to force the firmware to switch back to "DOS/bootloader" mode except by rebooting. The mode switch itself is performed by calling any of the ACPI _BCL methods at least once. When in ACPI mode, the backlight firmware just issues (standard) events for the brightness up/down hot key presses along with the non-standard HKEY events which thinkpad-acpi traps, and doesn't touch the hardware. thinkpad-acpi will: 1. Place the ThinkPad firmware in ACPI backlight control mode if one is available 2. Suppress HKEY backlight change notifications by default to avoid double-reporting when ACPI video is loaded when the ThinkPad is in ACPI backlight control mode 3. Urge the user to load the ACPI video driver The user is free to use either the ACPI video driver to get the brightness key events, or to override the thinkpad-acpi default hotkey mask to get them from thinkpad-acpi as well (this will result in duplicate events if ACPI video is loaded, so let's hope distros won't screw this up). Provided userspace is sane, all should work (and *keep* working), which is more that can be said about the non-ACPI mode of the new Lenovo ThinkPad BIOSes when coupled to current userspace and X.org drivers. Full guidelines for backlight hot key reporting and use of the thinkpad-acpi backlight interface have been added to the documentation. Signed-off-by: Henrique de Moraes Holschuh Cc: Matthew Garrett Cc: Thomas Renninger Signed-off-by: Len Brown --- Documentation/laptops/thinkpad-acpi.txt | 50 +++++++ drivers/misc/thinkpad_acpi.c | 238 ++++++++++++++++++-------------- 2 files changed, 183 insertions(+), 105 deletions(-) (limited to 'Documentation') diff --git a/Documentation/laptops/thinkpad-acpi.txt b/Documentation/laptops/thinkpad-acpi.txt index 76cb428435da..a77da28a6f8e 100644 --- a/Documentation/laptops/thinkpad-acpi.txt +++ b/Documentation/laptops/thinkpad-acpi.txt @@ -571,6 +571,47 @@ netlink interface and the input layer interface, and don't bother at all with hotkey_report_mode. +Brightness hotkey notes: + +These are the current sane choices for brightness key mapping in +thinkpad-acpi: + +For IBM and Lenovo models *without* ACPI backlight control (the ones on +which thinkpad-acpi will autoload its backlight interface by default, +and on which ACPI video does not export a backlight interface): + +1. Don't enable or map the brightness hotkeys in thinkpad-acpi, as + these older firmware versions unfortunately won't respect the hotkey + mask for brightness keys anyway, and always reacts to them. This + usually work fine, unless X.org drivers are doing something to block + the BIOS. In that case, use (3) below. This is the default mode of + operation. + +2. Enable the hotkeys, but map them to something else that is NOT + KEY_BRIGHTNESS_UP/DOWN or any other keycode that would cause + userspace to try to change the backlight level, and use that as an + on-screen-display hint. + +3. IF AND ONLY IF X.org drivers find a way to block the firmware from + automatically changing the brightness, enable the hotkeys and map + them to KEY_BRIGHTNESS_UP and KEY_BRIGHTNESS_DOWN, and feed that to + something that calls xbacklight. thinkpad-acpi will not be able to + change brightness in that case either, so you should disable its + backlight interface. + +For Lenovo models *with* ACPI backlight control: + +1. Load up ACPI video and use that. ACPI video will report ACPI + events for brightness change keys. Do not mess with thinkpad-acpi + defaults in this case. thinkpad-acpi should not have anything to do + with backlight events in a scenario where ACPI video is loaded: + brightness hotkeys must be disabled, and the backlight interface is + to be kept disabled as well. This is the default mode of operation. + +2. Do *NOT* load up ACPI video, enable the hotkeys in thinkpad-acpi, + and map them to KEY_BRIGHTNESS_UP and KEY_BRIGHTNESS_DOWN. Process + these keys on userspace somehow (e.g. by calling xbacklight). + Bluetooth --------- @@ -1090,6 +1131,15 @@ it there will be the following attributes: dim the display. +WARNING: + + Whatever you do, do NOT ever call thinkpad-acpi backlight-level change + interface and the ACPI-based backlight level change interface + (available on newer BIOSes, and driven by the Linux ACPI video driver) + at the same time. The two will interact in bad ways, do funny things, + and maybe reduce the life of the backlight lamps by needlessly kicking + its level up and down at every change. + Volume control -- /proc/acpi/ibm/volume --------------------------------------- diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c index 6cb781262f94..2c85a2e10a25 100644 --- a/drivers/misc/thinkpad_acpi.c +++ b/drivers/misc/thinkpad_acpi.c @@ -225,6 +225,7 @@ static struct { u32 light:1; u32 light_status:1; u32 bright_16levels:1; + u32 bright_acpimode:1; u32 wan:1; u32 fan_ctrl_status_undef:1; u32 input_device_registered:1; @@ -807,6 +808,80 @@ static int parse_strtoul(const char *buf, return 0; } +static int __init tpacpi_query_bcl_levels(acpi_handle handle) +{ + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; + union acpi_object *obj; + int rc; + + if (ACPI_SUCCESS(acpi_evaluate_object(handle, NULL, NULL, &buffer))) { + obj = (union acpi_object *)buffer.pointer; + if (!obj || (obj->type != ACPI_TYPE_PACKAGE)) { + printk(TPACPI_ERR "Unknown _BCL data, " + "please report this to %s\n", TPACPI_MAIL); + rc = 0; + } else { + rc = obj->package.count; + } + } else { + return 0; + } + + kfree(buffer.pointer); + return rc; +} + +static acpi_status __init tpacpi_acpi_walk_find_bcl(acpi_handle handle, + u32 lvl, void *context, void **rv) +{ + char name[ACPI_PATH_SEGMENT_LENGTH]; + struct acpi_buffer buffer = { sizeof(name), &name }; + + if (ACPI_SUCCESS(acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer)) && + !strncmp("_BCL", name, sizeof(name) - 1)) { + BUG_ON(!rv || !*rv); + **(int **)rv = tpacpi_query_bcl_levels(handle); + return AE_CTRL_TERMINATE; + } else { + return AE_OK; + } +} + +/* + * Returns 0 (no ACPI _BCL or _BCL invalid), or size of brightness map + */ +static int __init tpacpi_check_std_acpi_brightness_support(void) +{ + int status; + int bcl_levels = 0; + void *bcl_ptr = &bcl_levels; + + if (!vid_handle) { + TPACPI_ACPIHANDLE_INIT(vid); + } + if (!vid_handle) + return 0; + + /* + * Search for a _BCL method, and execute it. This is safe on all + * ThinkPads, and as a side-effect, _BCL will place a Lenovo Vista + * BIOS in ACPI backlight control mode. We do NOT have to care + * about calling the _BCL method in an enabled video device, any + * will do for our purposes. + */ + + status = acpi_walk_namespace(ACPI_TYPE_METHOD, vid_handle, 3, + tpacpi_acpi_walk_find_bcl, NULL, + &bcl_ptr); + + if (ACPI_SUCCESS(status) && bcl_levels > 2) { + tp_features.bright_acpimode = 1; + return (bcl_levels - 2); + } + + return 0; +} + /************************************************************************* * thinkpad-acpi driver attributes */ @@ -1887,6 +1962,9 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) KEY_UNKNOWN, /* 0x0D: FN+INSERT */ KEY_UNKNOWN, /* 0x0E: FN+DELETE */ + /* These either have to go through ACPI video, or + * act like in the IBM ThinkPads, so don't ever + * enable them by default */ KEY_RESERVED, /* 0x0F: FN+HOME (brightness up) */ KEY_RESERVED, /* 0x10: FN+END (brightness down) */ @@ -2091,6 +2169,32 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) set_bit(SW_TABLET_MODE, tpacpi_inputdev->swbit); } + /* Do not issue duplicate brightness change events to + * userspace */ + if (!tp_features.bright_acpimode) + /* update bright_acpimode... */ + tpacpi_check_std_acpi_brightness_support(); + + if (tp_features.bright_acpimode) { + printk(TPACPI_INFO + "This ThinkPad has standard ACPI backlight " + "brightness control, supported by the ACPI " + "video driver\n"); + printk(TPACPI_NOTICE + "Disabling thinkpad-acpi brightness events " + "by default...\n"); + + /* The hotkey_reserved_mask change below is not + * necessary while the keys are at KEY_RESERVED in the + * default map, but better safe than sorry, leave it + * here as a marker of what we have to do, especially + * when we finally become able to set this at runtime + * on response to X.org requests */ + hotkey_reserved_mask |= + (1 << TP_ACPI_HOTKEYSCAN_FNHOME) + | (1 << TP_ACPI_HOTKEYSCAN_FNEND); + } + dbg_printk(TPACPI_DBG_INIT, "enabling hot key handling\n"); res = hotkey_status_set(1); @@ -4273,100 +4377,6 @@ static struct backlight_ops ibm_backlight_data = { /* --------------------------------------------------------------------- */ -static int __init tpacpi_query_bcll_levels(acpi_handle handle) -{ - struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; - union acpi_object *obj; - int rc; - - if (ACPI_SUCCESS(acpi_evaluate_object(handle, NULL, NULL, &buffer))) { - obj = (union acpi_object *)buffer.pointer; - if (!obj || (obj->type != ACPI_TYPE_PACKAGE)) { - printk(TPACPI_ERR "Unknown BCLL data, " - "please report this to %s\n", TPACPI_MAIL); - rc = 0; - } else { - rc = obj->package.count; - } - } else { - return 0; - } - - kfree(buffer.pointer); - return rc; -} - -static acpi_status __init brightness_find_bcll(acpi_handle handle, u32 lvl, - void *context, void **rv) -{ - char name[ACPI_PATH_SEGMENT_LENGTH]; - struct acpi_buffer buffer = { sizeof(name), &name }; - - if (ACPI_SUCCESS(acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer)) && - !strncmp("BCLL", name, sizeof(name) - 1)) { - if (tpacpi_query_bcll_levels(handle) == 16) { - *rv = handle; - return AE_CTRL_TERMINATE; - } else { - return AE_OK; - } - } else { - return AE_OK; - } -} - -static int __init brightness_check_levels(void) -{ - int status; - void *found_node = NULL; - - if (!vid_handle) { - TPACPI_ACPIHANDLE_INIT(vid); - } - if (!vid_handle) - return 0; - - /* Search for a BCLL package with 16 levels */ - status = acpi_walk_namespace(ACPI_TYPE_PACKAGE, vid_handle, 3, - brightness_find_bcll, NULL, - &found_node); - - return (ACPI_SUCCESS(status) && found_node != NULL); -} - -static acpi_status __init brightness_find_bcl(acpi_handle handle, u32 lvl, - void *context, void **rv) -{ - char name[ACPI_PATH_SEGMENT_LENGTH]; - struct acpi_buffer buffer = { sizeof(name), &name }; - - if (ACPI_SUCCESS(acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer)) && - !strncmp("_BCL", name, sizeof(name) - 1)) { - *rv = handle; - return AE_CTRL_TERMINATE; - } else { - return AE_OK; - } -} - -static int __init brightness_check_std_acpi_support(void) -{ - int status; - void *found_node = NULL; - - if (!vid_handle) { - TPACPI_ACPIHANDLE_INIT(vid); - } - if (!vid_handle) - return 0; - - /* Search for a _BCL method, but don't execute it */ - status = acpi_walk_namespace(ACPI_TYPE_METHOD, vid_handle, 3, - brightness_find_bcl, NULL, &found_node); - - return (ACPI_SUCCESS(status) && found_node != NULL); -} - static int __init brightness_init(struct ibm_init_struct *iibm) { int b; @@ -4375,13 +4385,19 @@ static int __init brightness_init(struct ibm_init_struct *iibm) mutex_init(&brightness_mutex); - if (!brightness_enable) { - dbg_printk(TPACPI_DBG_INIT, - "brightness support disabled by " - "module parameter\n"); - return 1; - } else if (brightness_enable > 1) { - if (brightness_check_std_acpi_support()) { + /* + * We always attempt to detect acpi support, so as to switch + * Lenovo Vista BIOS to ACPI brightness mode even if we are not + * going to publish a backlight interface + */ + b = tpacpi_check_std_acpi_brightness_support(); + if (b > 0) { + if (thinkpad_id.vendor == PCI_VENDOR_ID_LENOVO) { + printk(TPACPI_NOTICE + "Lenovo BIOS switched to ACPI backlight " + "control mode\n"); + } + if (brightness_enable > 1) { printk(TPACPI_NOTICE "standard ACPI backlight interface " "available, not loading native one...\n"); @@ -4389,6 +4405,22 @@ static int __init brightness_init(struct ibm_init_struct *iibm) } } + if (!brightness_enable) { + dbg_printk(TPACPI_DBG_INIT, + "brightness support disabled by " + "module parameter\n"); + return 1; + } + + if (b > 16) { + printk(TPACPI_ERR + "Unsupported brightness interface, " + "please contact %s\n", TPACPI_MAIL); + return 1; + } + if (b == 16) + tp_features.bright_16levels = 1; + if (!brightness_mode) { if (thinkpad_id.vendor == PCI_VENDOR_ID_LENOVO) brightness_mode = 2; @@ -4402,10 +4434,6 @@ static int __init brightness_init(struct ibm_init_struct *iibm) if (brightness_mode > 3) return -EINVAL; - tp_features.bright_16levels = - thinkpad_id.vendor == PCI_VENDOR_ID_LENOVO && - brightness_check_levels(); - b = brightness_get(NULL); if (b < 0) return 1; -- cgit v1.2.3 From 95e57ab2cbd8b016327b23d76da8a96cbd26ac0c Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Sat, 26 Apr 2008 01:02:22 -0300 Subject: ACPI: thinkpad-acpi: claim tpacpi as an official short handle (v1.1) Unfortunately, a lot of stuff in the kernel has size limitations, so "thinkpad-acpi" ends up eating up too much real estate. We were using "tpacpi" in symbols already, but this shorthand was not visible to userland. Document that the driver will use tpacpi as a short hand where necessary, and use it to name the kernel thread for NVRAM polling (now named "ktpacpi_nvramd"). Also, register a module alias with the shorthand. One can refer to the module using the shorthand name. Signed-off-by: Henrique de Moraes Holschuh Signed-off-by: Len Brown --- Documentation/laptops/thinkpad-acpi.txt | 5 +++++ drivers/misc/thinkpad_acpi.c | 8 ++++++-- 2 files changed, 11 insertions(+), 2 deletions(-) (limited to 'Documentation') diff --git a/Documentation/laptops/thinkpad-acpi.txt b/Documentation/laptops/thinkpad-acpi.txt index a77da28a6f8e..a41bc893f8d6 100644 --- a/Documentation/laptops/thinkpad-acpi.txt +++ b/Documentation/laptops/thinkpad-acpi.txt @@ -18,6 +18,11 @@ This driver used to be named ibm-acpi until kernel 2.6.21 and release moved to the drivers/misc tree and renamed to thinkpad-acpi for kernel 2.6.22, and release 0.14. +The driver is named "thinkpad-acpi". In some places, like module +names, "thinkpad_acpi" is used because of userspace issues. + +"tpacpi" is used as a shorthand where "thinkpad-acpi" would be too +long due to length limitations on some Linux kernel versions. Status ------ diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c index 5e25abc54008..2b73dfafac9d 100644 --- a/drivers/misc/thinkpad_acpi.c +++ b/drivers/misc/thinkpad_acpi.c @@ -133,8 +133,11 @@ enum { #define TPACPI_PROC_DIR "ibm" #define TPACPI_ACPI_EVENT_PREFIX "ibm" #define TPACPI_DRVR_NAME TPACPI_FILE +#define TPACPI_DRVR_SHORTNAME "tpacpi" #define TPACPI_HWMON_DRVR_NAME TPACPI_NAME "_hwmon" +#define TPACPI_NVRAM_KTHREAD_NAME "ktpacpi_nvramd" + #define TPACPI_MAX_ACPI_ARGS 3 /* Debugging */ @@ -1523,8 +1526,7 @@ static void hotkey_poll_setup(int may_warn) (tpacpi_inputdev->users > 0 || hotkey_report_mode < 2)) { if (!tpacpi_hotkey_task) { tpacpi_hotkey_task = kthread_run(hotkey_kthread, - NULL, - TPACPI_FILE "d"); + NULL, TPACPI_NVRAM_KTHREAD_NAME); if (IS_ERR(tpacpi_hotkey_task)) { tpacpi_hotkey_task = NULL; printk(TPACPI_ERR @@ -6316,6 +6318,8 @@ static int __init thinkpad_acpi_module_init(void) /* Please remove this in year 2009 */ MODULE_ALIAS("ibm_acpi"); +MODULE_ALIAS(TPACPI_DRVR_SHORTNAME); + /* * DMI matching for module autoloading * -- cgit v1.2.3 From e306501d1c4ff610feaba74ac35dd13e470480e6 Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Sat, 26 Apr 2008 01:02:24 -0300 Subject: ACPI: thinkpad-acpi: add sysfs led class support for thinklight (v3.1) Add a sysfs led class interface to the thinklight (light subdriver). Signed-off-by: Henrique de Moraes Holschuh Cc: Richard Purdie Signed-off-by: Len Brown --- Documentation/laptops/thinkpad-acpi.txt | 25 ++++++++++++--- drivers/misc/thinkpad_acpi.c | 57 ++++++++++++++++++++++++++++++++- 2 files changed, 76 insertions(+), 6 deletions(-) (limited to 'Documentation') 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: https://bugs.freedesktop.org/show_bug.cgi?id=2000 -ThinkLight control -- /proc/acpi/ibm/light ------------------------------------------- +ThinkLight control +------------------ + +procfs: /proc/acpi/ibm/light +sysfs attributes: as per led class, for the "tpacpi::thinklight" led + +procfs notes: -The current status of the ThinkLight can be found in this file. A few -models which do not make the status available will show it as -"unknown". The available commands are: +The ThinkLight status can be read and set through the procfs interface. A +few models which do not make the status available will show the ThinkLight +status as "unknown". The available commands are: echo on > /proc/acpi/ibm/light echo off > /proc/acpi/ibm/light +sysfs notes: + +The ThinkLight sysfs interface is documented by the led class +documentation, in Documentation/leds-class.txt. The ThinkLight led name +is "tpacpi::thinklight". + +Due to limitations in the sysfs led class, if the status of the thinklight +cannot be read or if it is unknown, thinkpad-acpi will report it as "off". +It is impossible to know if the status returned through sysfs is valid. + Docking / undocking -- /proc/acpi/ibm/dock ------------------------------------------ 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) return -ENXIO; } +static void light_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)) + light_set_status((data->new_brightness != LED_OFF)); +} + +static void light_sysfs_set(struct led_classdev *led_cdev, + enum led_brightness brightness) +{ + struct tpacpi_led_classdev *data = + container_of(led_cdev, + struct tpacpi_led_classdev, + led_classdev); + data->new_brightness = brightness; + schedule_work(&data->work); +} + +static enum led_brightness light_sysfs_get(struct led_classdev *led_cdev) +{ + return (light_get_status() == 1)? LED_FULL : LED_OFF; +} + +static struct tpacpi_led_classdev tpacpi_led_thinklight = { + .led_classdev = { + .name = "tpacpi::thinklight", + .brightness_set = &light_sysfs_set, + .brightness_get = &light_sysfs_get, + } +}; + static int __init light_init(struct ibm_init_struct *iibm) { + int rc = 0; + vdbg_printk(TPACPI_DBG_INIT, "initializing light subdriver\n"); TPACPI_ACPIHANDLE_INIT(ledb); TPACPI_ACPIHANDLE_INIT(lght); TPACPI_ACPIHANDLE_INIT(cmos); + INIT_WORK(&tpacpi_led_thinklight.work, light_set_status_worker); /* light not supported on 570, 600e/x, 770e, 770x, G4x, R30, R31 */ tp_features.light = (cmos_handle || lght_handle) && !ledb_handle; @@ -3300,7 +3336,25 @@ static int __init light_init(struct ibm_init_struct *iibm) vdbg_printk(TPACPI_DBG_INIT, "light is %s\n", str_supported(tp_features.light)); - return (tp_features.light)? 0 : 1; + if (tp_features.light) { + rc = led_classdev_register(&tpacpi_pdev->dev, + &tpacpi_led_thinklight.led_classdev); + } + + if (rc < 0) { + tp_features.light = 0; + tp_features.light_status = 0; + } else { + rc = (tp_features.light)? 0 : 1; + } + return rc; +} + +static void light_exit(void) +{ + led_classdev_unregister(&tpacpi_led_thinklight.led_classdev); + if (work_pending(&tpacpi_led_thinklight.work)) + flush_scheduled_work(); } static int light_read(char *p) @@ -3348,6 +3402,7 @@ static struct ibm_struct light_driver_data = { .name = "light", .read = light_read, .write = light_write, + .exit = light_exit, }; /************************************************************************* -- cgit v1.2.3 From af116101924914a9655dfad108548d0db58c40f9 Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Sat, 26 Apr 2008 01:02:25 -0300 Subject: ACPI: thinkpad-acpi: add sysfs led class support to thinkpad leds (v3.2) Add a sysfs led class interface to the led subdriver. Signed-off-by: Henrique de Moraes Holschuh Cc: Richard Purdie Signed-off-by: Len Brown --- Documentation/laptops/thinkpad-acpi.txt | 47 +++++++++-- drivers/misc/thinkpad_acpi.c | 136 +++++++++++++++++++++++++++++++- 2 files changed, 176 insertions(+), 7 deletions(-) (limited to 'Documentation') diff --git a/Documentation/laptops/thinkpad-acpi.txt b/Documentation/laptops/thinkpad-acpi.txt index af1f2bcb6f66..73b80a7e9b03 100644 --- a/Documentation/laptops/thinkpad-acpi.txt +++ b/Documentation/laptops/thinkpad-acpi.txt @@ -876,28 +876,63 @@ The cmos command interface is prone to firmware split-brain problems, as in newer ThinkPads it is just a compatibility layer. Do not use it, it is exported just as a debug tool. -LED control -- /proc/acpi/ibm/led ---------------------------------- +LED control +----------- -Some of the LED indicators can be controlled through this feature. The -available commands are: +procfs: /proc/acpi/ibm/led +sysfs attributes: as per led class, see below for names + +Some of the LED indicators can be controlled through this feature. On +some older ThinkPad models, it is possible to query the status of the +LED indicators as well. Newer ThinkPads cannot query the real status +of the LED indicators. + +procfs notes: + +The available commands are: echo ' on' >/proc/acpi/ibm/led echo ' off' >/proc/acpi/ibm/led echo ' blink' >/proc/acpi/ibm/led The range is 0 to 7. The set of LEDs that can be -controlled varies from model to model. Here is the mapping on the X40: +controlled varies from model to model. Here is the common ThinkPad +mapping: 0 - power 1 - battery (orange) 2 - battery (green) - 3 - UltraBase + 3 - UltraBase/dock 4 - UltraBay + 5 - UltraBase battery slot + 6 - (unknown) 7 - standby All of the above can be turned on and off and can be made to blink. +sysfs notes: + +The ThinkPad LED sysfs interface is described in detail by the led class +documentation, in Documentation/leds-class.txt. + +The leds are named (in LED ID order, from 0 to 7): +"tpacpi::power", "tpacpi:orange:batt", "tpacpi:green:batt", +"tpacpi::dock_active", "tpacpi::bay_active", "tpacpi::dock_batt", +"tpacpi::unknown_led", "tpacpi::standby". + +Due to limitations in the sysfs led class, if the status of the LED +indicators cannot be read due to an error, thinkpad-acpi will report it as +a brightness of zero (same as LED off). + +If the thinkpad firmware doesn't support reading the current status, +trying to read the current LED brightness will just return whatever +brightness was last written to that attribute. + +These LEDs can blink using hardware acceleration. To request that a +ThinkPad indicator LED should blink in hardware accelerated mode, use the +"timer" trigger, and leave the delay_on and delay_off parameters set to +zero (to request hardware acceleration autodetection). + ACPI sounds -- /proc/acpi/ibm/beep ---------------------------------- diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c index 38a119bd931e..2ab3633f4e56 100644 --- a/drivers/misc/thinkpad_acpi.c +++ b/drivers/misc/thinkpad_acpi.c @@ -277,6 +277,7 @@ struct tpacpi_led_classdev { struct led_classdev led_classdev; struct work_struct work; enum led_brightness new_brightness; + unsigned int led; }; /**************************************************************************** @@ -3814,20 +3815,38 @@ TPACPI_HANDLE(led, ec, "SLED", /* 570 */ "LED", /* all others */ ); /* R30, R31 */ +#define TPACPI_LED_NUMLEDS 8 +static struct tpacpi_led_classdev *tpacpi_leds; +static enum led_status_t tpacpi_led_state_cache[TPACPI_LED_NUMLEDS]; +static const char const *tpacpi_led_names[TPACPI_LED_NUMLEDS] = { + /* there's a limit of 19 chars + NULL before 2.6.26 */ + "tpacpi::power", + "tpacpi:orange:batt", + "tpacpi:green:batt", + "tpacpi::dock_active", + "tpacpi::bay_active", + "tpacpi::dock_batt", + "tpacpi::unknown_led", + "tpacpi::standby", +}; + static int led_get_status(unsigned int led) { int status; + enum led_status_t led_s; switch (led_supported) { case TPACPI_LED_570: if (!acpi_evalf(ec_handle, &status, "GLED", "dd", 1 << led)) return -EIO; - return (status == 0)? + led_s = (status == 0)? TPACPI_LED_OFF : ((status == 1)? TPACPI_LED_ON : TPACPI_LED_BLINK); + tpacpi_led_state_cache[led] = led_s; + return led_s; default: return -ENXIO; } @@ -3874,11 +3893,96 @@ static int led_set_status(unsigned int led, enum led_status_t ledstatus) rc = -ENXIO; } + if (!rc) + tpacpi_led_state_cache[led] = ledstatus; + 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); +} + +static void led_sysfs_set(struct led_classdev *led_cdev, + enum led_brightness brightness) +{ + struct tpacpi_led_classdev *data = container_of(led_cdev, + struct tpacpi_led_classdev, led_classdev); + + data->new_brightness = brightness; + schedule_work(&data->work); +} + +static int led_sysfs_blink_set(struct led_classdev *led_cdev, + unsigned long *delay_on, unsigned long *delay_off) +{ + struct tpacpi_led_classdev *data = container_of(led_cdev, + struct tpacpi_led_classdev, led_classdev); + + /* Can we choose the flash rate? */ + if (*delay_on == 0 && *delay_off == 0) { + /* yes. set them to the hardware blink rate (1 Hz) */ + *delay_on = 500; /* ms */ + *delay_off = 500; /* ms */ + } else if ((*delay_on != 500) || (*delay_off != 500)) + return -EINVAL; + + data->new_brightness = TPACPI_LED_BLINK; + schedule_work(&data->work); + + return 0; +} + +static enum led_brightness led_sysfs_get(struct led_classdev *led_cdev) +{ + int rc; + + struct tpacpi_led_classdev *data = container_of(led_cdev, + struct tpacpi_led_classdev, led_classdev); + + rc = led_get_status(data->led); + + if (rc == TPACPI_LED_OFF || rc < 0) + rc = LED_OFF; /* no error handling in led class :( */ + else + rc = LED_FULL; + + return rc; +} + +static void led_exit(void) +{ + unsigned int i; + + for (i = 0; i < TPACPI_LED_NUMLEDS; i++) { + if (tpacpi_leds[i].led_classdev.name) + led_classdev_unregister(&tpacpi_leds[i].led_classdev); + } + + kfree(tpacpi_leds); + tpacpi_leds = NULL; +} + static int __init led_init(struct ibm_init_struct *iibm) { + unsigned int i; + int rc; + vdbg_printk(TPACPI_DBG_INIT, "initializing LED subdriver\n"); TPACPI_ACPIHANDLE_INIT(led); @@ -3899,6 +4003,35 @@ static int __init led_init(struct ibm_init_struct *iibm) vdbg_printk(TPACPI_DBG_INIT, "LED commands are %s, mode %d\n", str_supported(led_supported), led_supported); + tpacpi_leds = kzalloc(sizeof(*tpacpi_leds) * TPACPI_LED_NUMLEDS, + GFP_KERNEL); + if (!tpacpi_leds) { + printk(TPACPI_ERR "Out of memory for LED data\n"); + return -ENOMEM; + } + + for (i = 0; i < TPACPI_LED_NUMLEDS; i++) { + tpacpi_leds[i].led = i; + + tpacpi_leds[i].led_classdev.brightness_set = &led_sysfs_set; + tpacpi_leds[i].led_classdev.blink_set = &led_sysfs_blink_set; + if (led_supported == TPACPI_LED_570) + tpacpi_leds[i].led_classdev.brightness_get = + &led_sysfs_get; + + tpacpi_leds[i].led_classdev.name = tpacpi_led_names[i]; + + INIT_WORK(&tpacpi_leds[i].work, led_set_status_worker); + + rc = led_classdev_register(&tpacpi_pdev->dev, + &tpacpi_leds[i].led_classdev); + if (rc < 0) { + tpacpi_leds[i].led_classdev.name = NULL; + led_exit(); + return rc; + } + } + return (led_supported != TPACPI_LED_NONE)? 0 : 1; } @@ -3969,6 +4102,7 @@ static struct ibm_struct led_driver_data = { .name = "led", .read = led_read, .write = led_write, + .exit = led_exit, }; /************************************************************************* -- cgit v1.2.3 From 65807cc284dd291b024dd6e55de88feb16b4230a Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Sat, 26 Apr 2008 01:02:26 -0300 Subject: ACPI: thinkpad-acpi: use uppercase for "LED" on user documentation Change all occourences of the "led" word to full uppercase in user documentation. Signed-off-by: Henrique de Moraes Holschuh Acked-by: Randy Dunlap Signed-off-by: Len Brown --- Documentation/laptops/thinkpad-acpi.txt | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'Documentation') diff --git a/Documentation/laptops/thinkpad-acpi.txt b/Documentation/laptops/thinkpad-acpi.txt index 73b80a7e9b03..947b72654e36 100644 --- a/Documentation/laptops/thinkpad-acpi.txt +++ b/Documentation/laptops/thinkpad-acpi.txt @@ -697,7 +697,7 @@ ThinkLight control ------------------ procfs: /proc/acpi/ibm/light -sysfs attributes: as per led class, for the "tpacpi::thinklight" led +sysfs attributes: as per LED class, for the "tpacpi::thinklight" LED procfs notes: @@ -710,11 +710,11 @@ status as "unknown". The available commands are: sysfs notes: -The ThinkLight sysfs interface is documented by the led class -documentation, in Documentation/leds-class.txt. The ThinkLight led name +The ThinkLight sysfs interface is documented by the LED class +documentation, in Documentation/leds-class.txt. The ThinkLight LED name is "tpacpi::thinklight". -Due to limitations in the sysfs led class, if the status of the thinklight +Due to limitations in the sysfs LED class, if the status of the thinklight cannot be read or if it is unknown, thinkpad-acpi will report it as "off". It is impossible to know if the status returned through sysfs is valid. @@ -880,7 +880,7 @@ LED control ----------- procfs: /proc/acpi/ibm/led -sysfs attributes: as per led class, see below for names +sysfs attributes: as per LED class, see below for names Some of the LED indicators can be controlled through this feature. On some older ThinkPad models, it is possible to query the status of the @@ -891,11 +891,11 @@ procfs notes: The available commands are: - echo ' on' >/proc/acpi/ibm/led - echo ' off' >/proc/acpi/ibm/led - echo ' blink' >/proc/acpi/ibm/led + echo ' on' >/proc/acpi/ibm/led + echo ' off' >/proc/acpi/ibm/led + echo ' blink' >/proc/acpi/ibm/led -The range is 0 to 7. The set of LEDs that can be +The range is 0 to 7. The set of LEDs that can be controlled varies from model to model. Here is the common ThinkPad mapping: @@ -912,7 +912,7 @@ All of the above can be turned on and off and can be made to blink. sysfs notes: -The ThinkPad LED sysfs interface is described in detail by the led class +The ThinkPad LED sysfs interface is described in detail by the LED class documentation, in Documentation/leds-class.txt. The leds are named (in LED ID order, from 0 to 7): @@ -920,7 +920,7 @@ The leds are named (in LED ID order, from 0 to 7): "tpacpi::dock_active", "tpacpi::bay_active", "tpacpi::dock_batt", "tpacpi::unknown_led", "tpacpi::standby". -Due to limitations in the sysfs led class, if the status of the LED +Due to limitations in the sysfs LED class, if the status of the LED indicators cannot be read due to an error, thinkpad-acpi will report it as a brightness of zero (same as LED off). -- cgit v1.2.3 From 68f12ae5d778279e13e406d3913c74c592307770 Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Sat, 26 Apr 2008 01:02:30 -0300 Subject: ACPI: thinkpad-acpi: bump up version to 0.20 Full LED sysfs support, and the rest of the assorted minor fixes and enhancements are a good reason to checkpoint a new version... Signed-off-by: Henrique de Moraes Holschuh Signed-off-by: Len Brown --- Documentation/laptops/thinkpad-acpi.txt | 4 ++-- drivers/misc/thinkpad_acpi.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'Documentation') diff --git a/Documentation/laptops/thinkpad-acpi.txt b/Documentation/laptops/thinkpad-acpi.txt index 947b72654e36..01c6c3d8a7e3 100644 --- a/Documentation/laptops/thinkpad-acpi.txt +++ b/Documentation/laptops/thinkpad-acpi.txt @@ -1,7 +1,7 @@ ThinkPad ACPI Extras Driver - Version 0.19 - January 06th, 2008 + Version 0.20 + April 09th, 2008 Borislav Deianov Henrique de Moraes Holschuh diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c index d5c08c01fd11..d29ad2e4afc2 100644 --- a/drivers/misc/thinkpad_acpi.c +++ b/drivers/misc/thinkpad_acpi.c @@ -21,7 +21,7 @@ * 02110-1301, USA. */ -#define TPACPI_VERSION "0.19" +#define TPACPI_VERSION "0.20" #define TPACPI_SYSFS_VERSION 0x020200 /* -- cgit v1.2.3