Add patches accepted for 2.6.26-rc1
[linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git] / releases / upstream / 2.6.26-rc1 / 0010-ACPI-thinkpad-acpi-add-sysfs-led-class-support-to.patch
blobf2df76b7b999ee00c89fe0822a5a3f2c4255a1e6
1 From af116101924914a9655dfad108548d0db58c40f9 Mon Sep 17 00:00:00 2001
2 From: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
3 Date: Sat, 26 Apr 2008 01:02:25 -0300
4 Subject: ACPI: thinkpad-acpi: add sysfs led class support to thinkpad leds (v3.2)
6 Add a sysfs led class interface to the led subdriver.
8 Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
9 Cc: Richard Purdie <rpurdie@rpsys.net>
10 Signed-off-by: Len Brown <len.brown@intel.com>
11 ---
12 Documentation/laptops/thinkpad-acpi.txt | 47 +++++++++--
13 drivers/misc/thinkpad_acpi.c | 136 ++++++++++++++++++++++++++++++-
14 2 files changed, 176 insertions(+), 7 deletions(-)
16 diff --git a/Documentation/laptops/thinkpad-acpi.txt b/Documentation/laptops/thinkpad-acpi.txt
17 index af1f2bc..73b80a7 100644
18 --- a/Documentation/laptops/thinkpad-acpi.txt
19 +++ b/Documentation/laptops/thinkpad-acpi.txt
20 @@ -876,28 +876,63 @@ The cmos command interface is prone to firmware split-brain problems, as
21 in newer ThinkPads it is just a compatibility layer. Do not use it, it is
22 exported just as a debug tool.
24 -LED control -- /proc/acpi/ibm/led
25 ----------------------------------
26 +LED control
27 +-----------
29 -Some of the LED indicators can be controlled through this feature. The
30 -available commands are:
31 +procfs: /proc/acpi/ibm/led
32 +sysfs attributes: as per led class, see below for names
34 +Some of the LED indicators can be controlled through this feature. On
35 +some older ThinkPad models, it is possible to query the status of the
36 +LED indicators as well. Newer ThinkPads cannot query the real status
37 +of the LED indicators.
39 +procfs notes:
41 +The available commands are:
43 echo '<led number> on' >/proc/acpi/ibm/led
44 echo '<led number> off' >/proc/acpi/ibm/led
45 echo '<led number> blink' >/proc/acpi/ibm/led
47 The <led number> range is 0 to 7. The set of LEDs that can be
48 -controlled varies from model to model. Here is the mapping on the X40:
49 +controlled varies from model to model. Here is the common ThinkPad
50 +mapping:
52 0 - power
53 1 - battery (orange)
54 2 - battery (green)
55 - 3 - UltraBase
56 + 3 - UltraBase/dock
57 4 - UltraBay
58 + 5 - UltraBase battery slot
59 + 6 - (unknown)
60 7 - standby
62 All of the above can be turned on and off and can be made to blink.
64 +sysfs notes:
66 +The ThinkPad LED sysfs interface is described in detail by the led class
67 +documentation, in Documentation/leds-class.txt.
69 +The leds are named (in LED ID order, from 0 to 7):
70 +"tpacpi::power", "tpacpi:orange:batt", "tpacpi:green:batt",
71 +"tpacpi::dock_active", "tpacpi::bay_active", "tpacpi::dock_batt",
72 +"tpacpi::unknown_led", "tpacpi::standby".
74 +Due to limitations in the sysfs led class, if the status of the LED
75 +indicators cannot be read due to an error, thinkpad-acpi will report it as
76 +a brightness of zero (same as LED off).
78 +If the thinkpad firmware doesn't support reading the current status,
79 +trying to read the current LED brightness will just return whatever
80 +brightness was last written to that attribute.
82 +These LEDs can blink using hardware acceleration. To request that a
83 +ThinkPad indicator LED should blink in hardware accelerated mode, use the
84 +"timer" trigger, and leave the delay_on and delay_off parameters set to
85 +zero (to request hardware acceleration autodetection).
87 ACPI sounds -- /proc/acpi/ibm/beep
88 ----------------------------------
90 diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c
91 index 38a119b..2ab3633 100644
92 --- a/drivers/misc/thinkpad_acpi.c
93 +++ b/drivers/misc/thinkpad_acpi.c
94 @@ -277,6 +277,7 @@ struct tpacpi_led_classdev {
95 struct led_classdev led_classdev;
96 struct work_struct work;
97 enum led_brightness new_brightness;
98 + unsigned int led;
101 /****************************************************************************
102 @@ -3814,20 +3815,38 @@ TPACPI_HANDLE(led, ec, "SLED", /* 570 */
103 "LED", /* all others */
104 ); /* R30, R31 */
106 +#define TPACPI_LED_NUMLEDS 8
107 +static struct tpacpi_led_classdev *tpacpi_leds;
108 +static enum led_status_t tpacpi_led_state_cache[TPACPI_LED_NUMLEDS];
109 +static const char const *tpacpi_led_names[TPACPI_LED_NUMLEDS] = {
110 + /* there's a limit of 19 chars + NULL before 2.6.26 */
111 + "tpacpi::power",
112 + "tpacpi:orange:batt",
113 + "tpacpi:green:batt",
114 + "tpacpi::dock_active",
115 + "tpacpi::bay_active",
116 + "tpacpi::dock_batt",
117 + "tpacpi::unknown_led",
118 + "tpacpi::standby",
121 static int led_get_status(unsigned int led)
123 int status;
124 + enum led_status_t led_s;
126 switch (led_supported) {
127 case TPACPI_LED_570:
128 if (!acpi_evalf(ec_handle,
129 &status, "GLED", "dd", 1 << led))
130 return -EIO;
131 - return (status == 0)?
132 + led_s = (status == 0)?
133 TPACPI_LED_OFF :
134 ((status == 1)?
135 TPACPI_LED_ON :
136 TPACPI_LED_BLINK);
137 + tpacpi_led_state_cache[led] = led_s;
138 + return led_s;
139 default:
140 return -ENXIO;
142 @@ -3874,11 +3893,96 @@ static int led_set_status(unsigned int led, enum led_status_t ledstatus)
143 rc = -ENXIO;
146 + if (!rc)
147 + tpacpi_led_state_cache[led] = ledstatus;
149 return rc;
152 +static void led_sysfs_set_status(unsigned int led,
153 + enum led_brightness brightness)
155 + led_set_status(led,
156 + (brightness == LED_OFF) ?
157 + TPACPI_LED_OFF :
158 + (tpacpi_led_state_cache[led] == TPACPI_LED_BLINK) ?
159 + TPACPI_LED_BLINK : TPACPI_LED_ON);
162 +static void led_set_status_worker(struct work_struct *work)
164 + struct tpacpi_led_classdev *data =
165 + container_of(work, struct tpacpi_led_classdev, work);
167 + if (likely(tpacpi_lifecycle == TPACPI_LIFE_RUNNING))
168 + led_sysfs_set_status(data->led, data->new_brightness);
171 +static void led_sysfs_set(struct led_classdev *led_cdev,
172 + enum led_brightness brightness)
174 + struct tpacpi_led_classdev *data = container_of(led_cdev,
175 + struct tpacpi_led_classdev, led_classdev);
177 + data->new_brightness = brightness;
178 + schedule_work(&data->work);
181 +static int led_sysfs_blink_set(struct led_classdev *led_cdev,
182 + unsigned long *delay_on, unsigned long *delay_off)
184 + struct tpacpi_led_classdev *data = container_of(led_cdev,
185 + struct tpacpi_led_classdev, led_classdev);
187 + /* Can we choose the flash rate? */
188 + if (*delay_on == 0 && *delay_off == 0) {
189 + /* yes. set them to the hardware blink rate (1 Hz) */
190 + *delay_on = 500; /* ms */
191 + *delay_off = 500; /* ms */
192 + } else if ((*delay_on != 500) || (*delay_off != 500))
193 + return -EINVAL;
195 + data->new_brightness = TPACPI_LED_BLINK;
196 + schedule_work(&data->work);
198 + return 0;
201 +static enum led_brightness led_sysfs_get(struct led_classdev *led_cdev)
203 + int rc;
205 + struct tpacpi_led_classdev *data = container_of(led_cdev,
206 + struct tpacpi_led_classdev, led_classdev);
208 + rc = led_get_status(data->led);
210 + if (rc == TPACPI_LED_OFF || rc < 0)
211 + rc = LED_OFF; /* no error handling in led class :( */
212 + else
213 + rc = LED_FULL;
215 + return rc;
218 +static void led_exit(void)
220 + unsigned int i;
222 + for (i = 0; i < TPACPI_LED_NUMLEDS; i++) {
223 + if (tpacpi_leds[i].led_classdev.name)
224 + led_classdev_unregister(&tpacpi_leds[i].led_classdev);
227 + kfree(tpacpi_leds);
228 + tpacpi_leds = NULL;
231 static int __init led_init(struct ibm_init_struct *iibm)
233 + unsigned int i;
234 + int rc;
236 vdbg_printk(TPACPI_DBG_INIT, "initializing LED subdriver\n");
238 TPACPI_ACPIHANDLE_INIT(led);
239 @@ -3899,6 +4003,35 @@ static int __init led_init(struct ibm_init_struct *iibm)
240 vdbg_printk(TPACPI_DBG_INIT, "LED commands are %s, mode %d\n",
241 str_supported(led_supported), led_supported);
243 + tpacpi_leds = kzalloc(sizeof(*tpacpi_leds) * TPACPI_LED_NUMLEDS,
244 + GFP_KERNEL);
245 + if (!tpacpi_leds) {
246 + printk(TPACPI_ERR "Out of memory for LED data\n");
247 + return -ENOMEM;
250 + for (i = 0; i < TPACPI_LED_NUMLEDS; i++) {
251 + tpacpi_leds[i].led = i;
253 + tpacpi_leds[i].led_classdev.brightness_set = &led_sysfs_set;
254 + tpacpi_leds[i].led_classdev.blink_set = &led_sysfs_blink_set;
255 + if (led_supported == TPACPI_LED_570)
256 + tpacpi_leds[i].led_classdev.brightness_get =
257 + &led_sysfs_get;
259 + tpacpi_leds[i].led_classdev.name = tpacpi_led_names[i];
261 + INIT_WORK(&tpacpi_leds[i].work, led_set_status_worker);
263 + rc = led_classdev_register(&tpacpi_pdev->dev,
264 + &tpacpi_leds[i].led_classdev);
265 + if (rc < 0) {
266 + tpacpi_leds[i].led_classdev.name = NULL;
267 + led_exit();
268 + return rc;
272 return (led_supported != TPACPI_LED_NONE)? 0 : 1;
275 @@ -3969,6 +4102,7 @@ static struct ibm_struct led_driver_data = {
276 .name = "led",
277 .read = led_read,
278 .write = led_write,
279 + .exit = led_exit,
282 /*************************************************************************
284 1.5.4.4