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 / 0008-ACPI-thinkpad-acpi-prepare-light-and-LED-for-sysfs.patch
blobb853d9a612ddd81ceb64f46af7c8aa9f83bde365
1 From 4fa6811b8ade1b7839342824939817a8fc751539 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:23 -0300
4 Subject: ACPI: thinkpad-acpi: prepare light and LED for sysfs support
6 Do some preparatory work to add sysfs support to the thinklight and
7 thinkpad leds driver.
9 Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
10 Signed-off-by: Len Brown <len.brown@intel.com>
11 ---
12 drivers/misc/Kconfig | 2 +
13 drivers/misc/thinkpad_acpi.c | 191 ++++++++++++++++++++++++++++++------------
14 2 files changed, 138 insertions(+), 55 deletions(-)
16 diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
17 index 297a48f..3a5d769 100644
18 --- a/drivers/misc/Kconfig
19 +++ b/drivers/misc/Kconfig
20 @@ -245,6 +245,8 @@ config THINKPAD_ACPI
21 select HWMON
22 select NVRAM
23 depends on INPUT
24 + select NEW_LEDS
25 + select LEDS_CLASS
26 ---help---
27 This is a driver for the IBM and Lenovo ThinkPad laptops. It adds
28 support for Fn-Fx key combinations, Bluetooth control, video
29 diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c
30 index 2b73dfa..5a3fb09 100644
31 --- a/drivers/misc/thinkpad_acpi.c
32 +++ b/drivers/misc/thinkpad_acpi.c
33 @@ -67,6 +67,7 @@
34 #include <linux/hwmon.h>
35 #include <linux/hwmon-sysfs.h>
36 #include <linux/input.h>
37 +#include <linux/leds.h>
38 #include <asm/uaccess.h>
40 #include <linux/dmi.h>
41 @@ -85,6 +86,8 @@
42 #define TP_CMOS_VOLUME_MUTE 2
43 #define TP_CMOS_BRIGHTNESS_UP 4
44 #define TP_CMOS_BRIGHTNESS_DOWN 5
45 +#define TP_CMOS_THINKLIGHT_ON 12
46 +#define TP_CMOS_THINKLIGHT_OFF 13
48 /* NVRAM Addresses */
49 enum tp_nvram_addr {
50 @@ -269,6 +272,13 @@ static enum {
51 static int experimental;
52 static u32 dbg_level;
54 +/* Special LED class that can defer work */
55 +struct tpacpi_led_classdev {
56 + struct led_classdev led_classdev;
57 + struct work_struct work;
58 + enum led_brightness new_brightness;
59 +};
61 /****************************************************************************
62 ****************************************************************************
64 @@ -3237,6 +3247,39 @@ static struct ibm_struct video_driver_data = {
65 TPACPI_HANDLE(lght, root, "\\LGHT"); /* A21e, A2xm/p, T20-22, X20-21 */
66 TPACPI_HANDLE(ledb, ec, "LEDB"); /* G4x */
68 +static int light_get_status(void)
70 + int status = 0;
72 + if (tp_features.light_status) {
73 + if (!acpi_evalf(ec_handle, &status, "KBLT", "d"))
74 + return -EIO;
75 + return (!!status);
76 + }
78 + return -ENXIO;
81 +static int light_set_status(int status)
83 + int rc;
85 + if (tp_features.light) {
86 + if (cmos_handle) {
87 + rc = acpi_evalf(cmos_handle, NULL, NULL, "vd",
88 + (status)?
89 + TP_CMOS_THINKLIGHT_ON :
90 + TP_CMOS_THINKLIGHT_OFF);
91 + } else {
92 + rc = acpi_evalf(lght_handle, NULL, NULL, "vd",
93 + (status)? 1 : 0);
94 + }
95 + return (rc)? 0 : -EIO;
96 + }
98 + return -ENXIO;
101 static int __init light_init(struct ibm_init_struct *iibm)
103 vdbg_printk(TPACPI_DBG_INIT, "initializing light subdriver\n");
104 @@ -3263,7 +3306,7 @@ static int __init light_init(struct ibm_init_struct *iibm)
105 static int light_read(char *p)
107 int len = 0;
108 - int status = 0;
109 + int status;
111 if (!tp_features.light) {
112 len += sprintf(p + len, "status:\t\tnot supported\n");
113 @@ -3271,8 +3314,9 @@ static int light_read(char *p)
114 len += sprintf(p + len, "status:\t\tunknown\n");
115 len += sprintf(p + len, "commands:\ton, off\n");
116 } else {
117 - if (!acpi_evalf(ec_handle, &status, "KBLT", "d"))
118 - return -EIO;
119 + status = light_get_status();
120 + if (status < 0)
121 + return status;
122 len += sprintf(p + len, "status:\t\t%s\n", onoff(status, 0));
123 len += sprintf(p + len, "commands:\ton, off\n");
125 @@ -3282,31 +3326,22 @@ static int light_read(char *p)
127 static int light_write(char *buf)
129 - int cmos_cmd, lght_cmd;
130 char *cmd;
131 - int success;
132 + int newstatus = 0;
134 if (!tp_features.light)
135 return -ENODEV;
137 while ((cmd = next_cmd(&buf))) {
138 if (strlencmp(cmd, "on") == 0) {
139 - cmos_cmd = 0x0c;
140 - lght_cmd = 1;
141 + newstatus = 1;
142 } else if (strlencmp(cmd, "off") == 0) {
143 - cmos_cmd = 0x0d;
144 - lght_cmd = 0;
145 + newstatus = 0;
146 } else
147 return -EINVAL;
149 - success = cmos_handle ?
150 - acpi_evalf(cmos_handle, NULL, NULL, "vd", cmos_cmd) :
151 - acpi_evalf(lght_handle, NULL, NULL, "vd", lght_cmd);
152 - if (!success)
153 - return -EIO;
156 - return 0;
157 + return light_set_status(newstatus);
160 static struct ibm_struct light_driver_data = {
161 @@ -3710,6 +3745,12 @@ enum { /* For TPACPI_LED_OLD */
162 TPACPI_LED_EC_HLMS = 0x0e, /* EC reg to select led to command */
165 +enum led_status_t {
166 + TPACPI_LED_OFF = 0,
167 + TPACPI_LED_ON,
168 + TPACPI_LED_BLINK,
171 static enum led_access_mode led_supported;
173 TPACPI_HANDLE(led, ec, "SLED", /* 570 */
174 @@ -3718,6 +3759,69 @@ TPACPI_HANDLE(led, ec, "SLED", /* 570 */
175 "LED", /* all others */
176 ); /* R30, R31 */
178 +static int led_get_status(unsigned int led)
180 + int status;
182 + switch (led_supported) {
183 + case TPACPI_LED_570:
184 + if (!acpi_evalf(ec_handle,
185 + &status, "GLED", "dd", 1 << led))
186 + return -EIO;
187 + return (status == 0)?
188 + TPACPI_LED_OFF :
189 + ((status == 1)?
190 + TPACPI_LED_ON :
191 + TPACPI_LED_BLINK);
192 + default:
193 + return -ENXIO;
196 + /* not reached */
199 +static int led_set_status(unsigned int led, enum led_status_t ledstatus)
201 + /* off, on, blink. Index is led_status_t */
202 + static const int const led_sled_arg1[] = { 0, 1, 3 };
203 + static const int const led_exp_hlbl[] = { 0, 0, 1 }; /* led# * */
204 + static const int const led_exp_hlcl[] = { 0, 1, 1 }; /* led# * */
205 + static const int const led_led_arg1[] = { 0, 0x80, 0xc0 };
207 + int rc = 0;
209 + switch (led_supported) {
210 + case TPACPI_LED_570:
211 + /* 570 */
212 + led = 1 << led;
213 + if (!acpi_evalf(led_handle, NULL, NULL, "vdd",
214 + led, led_sled_arg1[ledstatus]))
215 + rc = -EIO;
216 + break;
217 + case TPACPI_LED_OLD:
218 + /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20 */
219 + led = 1 << led;
220 + rc = ec_write(TPACPI_LED_EC_HLMS, led);
221 + if (rc >= 0)
222 + rc = ec_write(TPACPI_LED_EC_HLBL,
223 + led * led_exp_hlbl[ledstatus]);
224 + if (rc >= 0)
225 + rc = ec_write(TPACPI_LED_EC_HLCL,
226 + led * led_exp_hlcl[ledstatus]);
227 + break;
228 + case TPACPI_LED_NEW:
229 + /* all others */
230 + if (!acpi_evalf(led_handle, NULL, NULL, "vdd",
231 + led, led_led_arg1[ledstatus]))
232 + rc = -EIO;
233 + break;
234 + default:
235 + rc = -ENXIO;
238 + return rc;
241 static int __init led_init(struct ibm_init_struct *iibm)
243 vdbg_printk(TPACPI_DBG_INIT, "initializing LED subdriver\n");
244 @@ -3743,7 +3847,9 @@ static int __init led_init(struct ibm_init_struct *iibm)
245 return (led_supported != TPACPI_LED_NONE)? 0 : 1;
248 -#define led_status(s) ((s) == 0 ? "off" : ((s) == 1 ? "on" : "blinking"))
249 +#define str_led_status(s) \
250 + ((s) == TPACPI_LED_OFF ? "off" : \
251 + ((s) == TPACPI_LED_ON ? "on" : "blinking"))
253 static int led_read(char *p)
255 @@ -3759,11 +3865,11 @@ static int led_read(char *p)
256 /* 570 */
257 int i, status;
258 for (i = 0; i < 8; i++) {
259 - if (!acpi_evalf(ec_handle,
260 - &status, "GLED", "dd", 1 << i))
261 + status = led_get_status(i);
262 + if (status < 0)
263 return -EIO;
264 len += sprintf(p + len, "%d:\t\t%s\n",
265 - i, led_status(status));
266 + i, str_led_status(status));
270 @@ -3773,16 +3879,11 @@ static int led_read(char *p)
271 return len;
274 -/* off, on, blink */
275 -static const int led_sled_arg1[] = { 0, 1, 3 };
276 -static const int led_exp_hlbl[] = { 0, 0, 1 }; /* led# * */
277 -static const int led_exp_hlcl[] = { 0, 1, 1 }; /* led# * */
278 -static const int led_led_arg1[] = { 0, 0x80, 0xc0 };
280 static int led_write(char *buf)
282 char *cmd;
283 - int led, ind, ret;
284 + int led, rc;
285 + enum led_status_t s;
287 if (!led_supported)
288 return -ENODEV;
289 @@ -3792,38 +3893,18 @@ static int led_write(char *buf)
290 return -EINVAL;
292 if (strstr(cmd, "off")) {
293 - ind = 0;
294 + s = TPACPI_LED_OFF;
295 } else if (strstr(cmd, "on")) {
296 - ind = 1;
297 + s = TPACPI_LED_ON;
298 } else if (strstr(cmd, "blink")) {
299 - ind = 2;
300 - } else
301 - return -EINVAL;
303 - if (led_supported == TPACPI_LED_570) {
304 - /* 570 */
305 - led = 1 << led;
306 - if (!acpi_evalf(led_handle, NULL, NULL, "vdd",
307 - led, led_sled_arg1[ind]))
308 - return -EIO;
309 - } else if (led_supported == TPACPI_LED_OLD) {
310 - /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20 */
311 - led = 1 << led;
312 - ret = ec_write(TPACPI_LED_EC_HLMS, led);
313 - if (ret >= 0)
314 - ret = ec_write(TPACPI_LED_EC_HLBL,
315 - led * led_exp_hlbl[ind]);
316 - if (ret >= 0)
317 - ret = ec_write(TPACPI_LED_EC_HLCL,
318 - led * led_exp_hlcl[ind]);
319 - if (ret < 0)
320 - return ret;
321 + s = TPACPI_LED_BLINK;
322 } else {
323 - /* all others */
324 - if (!acpi_evalf(led_handle, NULL, NULL, "vdd",
325 - led, led_led_arg1[ind]))
326 - return -EIO;
327 + return -EINVAL;
330 + rc = led_set_status(led, s);
331 + if (rc < 0)
332 + return rc;
335 return 0;
337 1.5.4.4