ACPI: ibm-acpi: clean up fan_read
[pandora-kernel.git] / drivers / acpi / ibm_acpi.c
1 /*
2  *  ibm_acpi.c - IBM ThinkPad ACPI Extras
3  *
4  *
5  *  Copyright (C) 2004-2005 Borislav Deianov <borislav@users.sf.net>
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License as published by
9  *  the Free Software Foundation; either version 2 of the License, or
10  *  (at your option) any later version.
11  *
12  *  This program is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *  GNU General Public License for more details.
16  *
17  *  You should have received a copy of the GNU General Public License
18  *  along with this program; if not, write to the Free Software
19  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
21
22 #define IBM_VERSION "0.12a"
23
24 /*
25  *  Changelog:
26  *  
27  *  2005-08-17  0.12    fix compilation on 2.6.13-rc kernels
28  *  2005-03-17  0.11    support for 600e, 770x
29  *                          thanks to Jamie Lentin <lentinj@dial.pipex.com>
30  *                      support for 770e, G41
31  *                      G40 and G41 don't have a thinklight
32  *                      temperatures no longer experimental
33  *                      experimental brightness control
34  *                      experimental volume control
35  *                      experimental fan enable/disable
36  *  2005-01-16  0.10    fix module loading on R30, R31 
37  *  2005-01-16  0.9     support for 570, R30, R31
38  *                      ultrabay support on A22p, A3x
39  *                      limit arg for cmos, led, beep, drop experimental status
40  *                      more capable led control on A21e, A22p, T20-22, X20
41  *                      experimental temperatures and fan speed
42  *                      experimental embedded controller register dump
43  *                      mark more functions as __init, drop incorrect __exit
44  *                      use MODULE_VERSION
45  *                          thanks to Henrik Brix Andersen <brix@gentoo.org>
46  *                      fix parameter passing on module loading
47  *                          thanks to Rusty Russell <rusty@rustcorp.com.au>
48  *                          thanks to Jim Radford <radford@blackbean.org>
49  *  2004-11-08  0.8     fix init error case, don't return from a macro
50  *                          thanks to Chris Wright <chrisw@osdl.org>
51  *  2004-10-23  0.7     fix module loading on A21e, A22p, T20, T21, X20
52  *                      fix led control on A21e
53  *  2004-10-19  0.6     use acpi_bus_register_driver() to claim HKEY device
54  *  2004-10-18  0.5     thinklight support on A21e, G40, R32, T20, T21, X20
55  *                      proc file format changed
56  *                      video_switch command
57  *                      experimental cmos control
58  *                      experimental led control
59  *                      experimental acpi sounds
60  *  2004-09-16  0.4     support for module parameters
61  *                      hotkey mask can be prefixed by 0x
62  *                      video output switching
63  *                      video expansion control
64  *                      ultrabay eject support
65  *                      removed lcd brightness/on/off control, didn't work
66  *  2004-08-17  0.3     support for R40
67  *                      lcd off, brightness control
68  *                      thinklight on/off
69  *  2004-08-14  0.2     support for T series, X20
70  *                      bluetooth enable/disable
71  *                      hotkey events disabled by default
72  *                      removed fan control, currently useless
73  *  2004-08-09  0.1     initial release, support for X series
74  */
75
76 #include <linux/kernel.h>
77 #include <linux/module.h>
78 #include <linux/init.h>
79 #include <linux/types.h>
80 #include <linux/proc_fs.h>
81 #include <linux/backlight.h>
82 #include <asm/uaccess.h>
83 #include <linux/dmi.h>
84
85 #include <acpi/acpi_drivers.h>
86 #include <acpi/acnamesp.h>
87
88 #define IBM_NAME "ibm"
89 #define IBM_DESC "IBM ThinkPad ACPI Extras"
90 #define IBM_FILE "ibm_acpi"
91 #define IBM_URL "http://ibm-acpi.sf.net/"
92
93 MODULE_AUTHOR("Borislav Deianov");
94 MODULE_DESCRIPTION(IBM_DESC);
95 MODULE_VERSION(IBM_VERSION);
96 MODULE_LICENSE("GPL");
97
98 #define IBM_DIR IBM_NAME
99
100 #define IBM_LOG IBM_FILE ": "
101 #define IBM_ERR    KERN_ERR    IBM_LOG
102 #define IBM_NOTICE KERN_NOTICE IBM_LOG
103 #define IBM_INFO   KERN_INFO   IBM_LOG
104 #define IBM_DEBUG  KERN_DEBUG  IBM_LOG
105
106 #define IBM_MAX_ACPI_ARGS 3
107
108 #define __unused __attribute__ ((unused))
109
110 static int experimental;
111 module_param(experimental, int, 0);
112
113 static acpi_handle root_handle = NULL;
114
115 #define IBM_HANDLE(object, parent, paths...)                    \
116         static acpi_handle  object##_handle;                    \
117         static acpi_handle *object##_parent = &parent##_handle; \
118         static char        *object##_path;                      \
119         static char        *object##_paths[] = { paths }
120
121 /*
122  * The following models are supported to various degrees:
123  *
124  * 570, 600e, 600x, 770e, 770x
125  * A20m, A21e, A21m, A21p, A22p, A30, A30p, A31, A31p
126  * G40, G41
127  * R30, R31, R32, R40, R40e, R50, R50e, R50p, R51
128  * T20, T21, T22, T23, T30, T40, T40p, T41, T41p, T42, T42p, T43
129  * X20, X21, X22, X23, X24, X30, X31, X40
130  *
131  * The following models have no supported features:
132  *
133  * 240, 240x, i1400
134  *
135  * Still missing DSDTs for the following models:
136  *
137  * A20p, A22e, A22m
138  * R52
139  * S31
140  * T43p
141  */
142
143 IBM_HANDLE(ec, root, "\\_SB.PCI0.ISA.EC0",      /* 240, 240x */
144            "\\_SB.PCI.ISA.EC",  /* 570 */
145            "\\_SB.PCI0.ISA0.EC0",       /* 600e/x, 770e, 770x */
146            "\\_SB.PCI0.ISA.EC", /* A21e, A2xm/p, T20-22, X20-21 */
147            "\\_SB.PCI0.AD4S.EC0",       /* i1400, R30 */
148            "\\_SB.PCI0.ICH3.EC0",       /* R31 */
149            "\\_SB.PCI0.LPC.EC", /* all others */
150     );
151
152 IBM_HANDLE(vid, root, "\\_SB.PCI.AGP.VGA",      /* 570 */
153            "\\_SB.PCI0.AGP0.VID0",      /* 600e/x, 770x */
154            "\\_SB.PCI0.VID0",   /* 770e */
155            "\\_SB.PCI0.VID",    /* A21e, G4x, R50e, X30, X40 */
156            "\\_SB.PCI0.AGP.VID",        /* all others */
157     );                          /* R30, R31 */
158
159 IBM_HANDLE(vid2, root, "\\_SB.PCI0.AGPB.VID");  /* G41 */
160
161 IBM_HANDLE(cmos, root, "\\UCMS",        /* R50, R50e, R50p, R51, T4x, X31, X40 */
162            "\\CMOS",            /* A3x, G4x, R32, T23, T30, X22-24, X30 */
163            "\\CMS",             /* R40, R40e */
164     );                          /* all others */
165 #ifdef CONFIG_ACPI_IBM_DOCK
166 IBM_HANDLE(dock, root, "\\_SB.GDCK",    /* X30, X31, X40 */
167            "\\_SB.PCI0.DOCK",   /* 600e/x,770e,770x,A2xm/p,T20-22,X20-21 */
168            "\\_SB.PCI0.PCI1.DOCK",      /* all others */
169            "\\_SB.PCI.ISA.SLCE",        /* 570 */
170     );                          /* A21e,G4x,R30,R31,R32,R40,R40e,R50e */
171 #endif
172 IBM_HANDLE(bay, root, "\\_SB.PCI.IDE.SECN.MAST",        /* 570 */
173            "\\_SB.PCI0.IDE0.IDES.IDSM", /* 600e/x, 770e, 770x */
174            "\\_SB.PCI0.IDE0.SCND.MSTR", /* all others */
175     );                          /* A21e, R30, R31 */
176
177 IBM_HANDLE(bay_ej, bay, "_EJ3", /* 600e/x, A2xm/p, A3x */
178            "_EJ0",              /* all others */
179     );                          /* 570,A21e,G4x,R30,R31,R32,R40e,R50e */
180
181 IBM_HANDLE(bay2, root, "\\_SB.PCI0.IDE0.PRIM.SLAV",     /* A3x, R32 */
182            "\\_SB.PCI0.IDE0.IDEP.IDPS", /* 600e/x, 770e, 770x */
183     );                          /* all others */
184
185 IBM_HANDLE(bay2_ej, bay2, "_EJ3",       /* 600e/x, 770e, A3x */
186            "_EJ0",              /* 770x */
187     );                          /* all others */
188
189 /* don't list other alternatives as we install a notify handler on the 570 */
190 IBM_HANDLE(pci, root, "\\_SB.PCI");     /* 570 */
191
192 IBM_HANDLE(hkey, ec, "\\_SB.HKEY",      /* 600e/x, 770e, 770x */
193            "^HKEY",             /* R30, R31 */
194            "HKEY",              /* all others */
195     );                          /* 570 */
196
197 IBM_HANDLE(lght, root, "\\LGHT");       /* A21e, A2xm/p, T20-22, X20-21 */
198 IBM_HANDLE(ledb, ec, "LEDB");   /* G4x */
199
200 IBM_HANDLE(led, ec, "SLED",     /* 570 */
201            "SYSL",              /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20-21 */
202            "LED",               /* all others */
203     );                          /* R30, R31 */
204
205 IBM_HANDLE(beep, ec, "BEEP");   /* all except R30, R31 */
206 IBM_HANDLE(ecrd, ec, "ECRD");   /* 570 */
207 IBM_HANDLE(ecwr, ec, "ECWR");   /* 570 */
208 IBM_HANDLE(fans, ec, "FANS");   /* X31, X40 */
209
210 IBM_HANDLE(gfan, ec, "GFAN",    /* 570 */
211            "\\FSPD",            /* 600e/x, 770e, 770x */
212     );                          /* all others */
213
214 IBM_HANDLE(sfan, ec, "SFAN",    /* 570 */
215            "JFNS",              /* 770x-JL */
216     );                          /* all others */
217
218 #define IBM_HKEY_HID    "IBM0068"
219 #define IBM_PCI_HID     "PNP0A03"
220
221 enum thermal_access_mode {
222         IBMACPI_THERMAL_NONE = 0,       /* No thermal support */
223         IBMACPI_THERMAL_ACPI_TMP07,     /* Use ACPI TMP0-7 */
224         IBMACPI_THERMAL_ACPI_UPDT,      /* Use ACPI TMP0-7 with UPDT */
225         IBMACPI_THERMAL_TPEC_8,         /* Use ACPI EC regs, 8 sensors */
226         IBMACPI_THERMAL_TPEC_16,        /* Use ACPI EC regs, 16 sensors */
227 };
228
229 #define IBMACPI_MAX_THERMAL_SENSORS 16  /* Max thermal sensors supported */
230 struct ibm_thermal_sensors_struct {
231         s32 temp[IBMACPI_MAX_THERMAL_SENSORS];
232 };
233
234 enum fan_status_access_mode {
235         IBMACPI_FAN_NONE = 0,           /* No fan status or control */
236         IBMACPI_FAN_RD_ACPI_GFAN,       /* Use ACPI GFAN */
237         IBMACPI_FAN_RD_TPEC,            /* Use ACPI EC regs 0x2f, 0x84-0x85 */
238 };
239
240 enum fan_control_access_mode {
241         IBMACPI_FAN_WR_NONE = 0,        /* No fan control */
242         IBMACPI_FAN_WR_ACPI_SFAN,       /* Use ACPI SFAN */
243         IBMACPI_FAN_WR_TPEC,            /* Use ACPI EC reg 0x2f */
244         IBMACPI_FAN_WR_ACPI_FANS,       /* Use ACPI FANS and EC reg 0x2f */
245 };
246
247 enum fan_control_commands {
248         IBMACPI_FAN_CMD_SPEED   = 0x0001,       /* speed command */
249         IBMACPI_FAN_CMD_LEVEL   = 0x0002,       /* level command  */
250         IBMACPI_FAN_CMD_ENABLE  = 0x0004,       /* enable/disable cmd */
251 };
252
253 enum {                                  /* Fan control constants */
254         fan_status_offset = 0x2f,       /* EC register 0x2f */
255         fan_rpm_offset = 0x84,          /* EC register 0x84: LSB, 0x85 MSB (RPM)
256                                          * 0x84 must be read before 0x85 */
257 };
258
259 static int ibm_thinkpad_ec_found;
260
261 struct ibm_struct {
262         char *name;
263         char param[32];
264
265         char *hid;
266         struct acpi_driver *driver;
267
268         int (*init) (void);
269         int (*read) (char *);
270         int (*write) (char *);
271         void (*exit) (void);
272
273         void (*notify) (struct ibm_struct *, u32);
274         acpi_handle *handle;
275         int type;
276         struct acpi_device *device;
277
278         int driver_registered;
279         int proc_created;
280         int init_called;
281         int notify_installed;
282
283         int experimental;
284 };
285
286 static struct proc_dir_entry *proc_dir = NULL;
287
288 static struct backlight_device *ibm_backlight_device;
289
290 #define onoff(status,bit) ((status) & (1 << (bit)) ? "on" : "off")
291 #define enabled(status,bit) ((status) & (1 << (bit)) ? "enabled" : "disabled")
292 #define strlencmp(a,b) (strncmp((a), (b), strlen(b)))
293
294 static int acpi_evalf(acpi_handle handle,
295                       void *res, char *method, char *fmt, ...)
296 {
297         char *fmt0 = fmt;
298         struct acpi_object_list params;
299         union acpi_object in_objs[IBM_MAX_ACPI_ARGS];
300         struct acpi_buffer result, *resultp;
301         union acpi_object out_obj;
302         acpi_status status;
303         va_list ap;
304         char res_type;
305         int success;
306         int quiet;
307
308         if (!*fmt) {
309                 printk(IBM_ERR "acpi_evalf() called with empty format\n");
310                 return 0;
311         }
312
313         if (*fmt == 'q') {
314                 quiet = 1;
315                 fmt++;
316         } else
317                 quiet = 0;
318
319         res_type = *(fmt++);
320
321         params.count = 0;
322         params.pointer = &in_objs[0];
323
324         va_start(ap, fmt);
325         while (*fmt) {
326                 char c = *(fmt++);
327                 switch (c) {
328                 case 'd':       /* int */
329                         in_objs[params.count].integer.value = va_arg(ap, int);
330                         in_objs[params.count++].type = ACPI_TYPE_INTEGER;
331                         break;
332                         /* add more types as needed */
333                 default:
334                         printk(IBM_ERR "acpi_evalf() called "
335                                "with invalid format character '%c'\n", c);
336                         return 0;
337                 }
338         }
339         va_end(ap);
340
341         if (res_type != 'v') {
342                 result.length = sizeof(out_obj);
343                 result.pointer = &out_obj;
344                 resultp = &result;
345         } else
346                 resultp = NULL;
347
348         status = acpi_evaluate_object(handle, method, &params, resultp);
349
350         switch (res_type) {
351         case 'd':               /* int */
352                 if (res)
353                         *(int *)res = out_obj.integer.value;
354                 success = status == AE_OK && out_obj.type == ACPI_TYPE_INTEGER;
355                 break;
356         case 'v':               /* void */
357                 success = status == AE_OK;
358                 break;
359                 /* add more types as needed */
360         default:
361                 printk(IBM_ERR "acpi_evalf() called "
362                        "with invalid format character '%c'\n", res_type);
363                 return 0;
364         }
365
366         if (!success && !quiet)
367                 printk(IBM_ERR "acpi_evalf(%s, %s, ...) failed: %d\n",
368                        method, fmt0, status);
369
370         return success;
371 }
372
373 static void __unused acpi_print_int(acpi_handle handle, char *method)
374 {
375         int i;
376
377         if (acpi_evalf(handle, &i, method, "d"))
378                 printk(IBM_INFO "%s = 0x%x\n", method, i);
379         else
380                 printk(IBM_ERR "error calling %s\n", method);
381 }
382
383 static char *next_cmd(char **cmds)
384 {
385         char *start = *cmds;
386         char *end;
387
388         while ((end = strchr(start, ',')) && end == start)
389                 start = end + 1;
390
391         if (!end)
392                 return NULL;
393
394         *end = 0;
395         *cmds = end + 1;
396         return start;
397 }
398
399 static int driver_init(void)
400 {
401         printk(IBM_INFO "%s v%s\n", IBM_DESC, IBM_VERSION);
402         printk(IBM_INFO "%s\n", IBM_URL);
403
404         return 0;
405 }
406
407 static int driver_read(char *p)
408 {
409         int len = 0;
410
411         len += sprintf(p + len, "driver:\t\t%s\n", IBM_DESC);
412         len += sprintf(p + len, "version:\t%s\n", IBM_VERSION);
413
414         return len;
415 }
416
417 static int hotkey_supported;
418 static int hotkey_mask_supported;
419 static int hotkey_orig_status;
420 static int hotkey_orig_mask;
421
422 static int hotkey_get(int *status, int *mask)
423 {
424         if (!acpi_evalf(hkey_handle, status, "DHKC", "d"))
425                 return 0;
426
427         if (hotkey_mask_supported)
428                 if (!acpi_evalf(hkey_handle, mask, "DHKN", "d"))
429                         return 0;
430
431         return 1;
432 }
433
434 static int hotkey_set(int status, int mask)
435 {
436         int i;
437
438         if (!acpi_evalf(hkey_handle, NULL, "MHKC", "vd", status))
439                 return 0;
440
441         if (hotkey_mask_supported)
442                 for (i = 0; i < 32; i++) {
443                         int bit = ((1 << i) & mask) != 0;
444                         if (!acpi_evalf(hkey_handle,
445                                         NULL, "MHKM", "vdd", i + 1, bit))
446                                 return 0;
447                 }
448
449         return 1;
450 }
451
452 static int hotkey_init(void)
453 {
454         /* hotkey not supported on 570 */
455         hotkey_supported = hkey_handle != NULL;
456
457         if (hotkey_supported) {
458                 /* mask not supported on 570, 600e/x, 770e, 770x, A21e, A2xm/p,
459                    A30, R30, R31, T20-22, X20-21, X22-24 */
460                 hotkey_mask_supported =
461                     acpi_evalf(hkey_handle, NULL, "DHKN", "qv");
462
463                 if (!hotkey_get(&hotkey_orig_status, &hotkey_orig_mask))
464                         return -ENODEV;
465         }
466
467         return 0;
468 }
469
470 static int hotkey_read(char *p)
471 {
472         int status, mask;
473         int len = 0;
474
475         if (!hotkey_supported) {
476                 len += sprintf(p + len, "status:\t\tnot supported\n");
477                 return len;
478         }
479
480         if (!hotkey_get(&status, &mask))
481                 return -EIO;
482
483         len += sprintf(p + len, "status:\t\t%s\n", enabled(status, 0));
484         if (hotkey_mask_supported) {
485                 len += sprintf(p + len, "mask:\t\t0x%04x\n", mask);
486                 len += sprintf(p + len,
487                                "commands:\tenable, disable, reset, <mask>\n");
488         } else {
489                 len += sprintf(p + len, "mask:\t\tnot supported\n");
490                 len += sprintf(p + len, "commands:\tenable, disable, reset\n");
491         }
492
493         return len;
494 }
495
496 static int hotkey_write(char *buf)
497 {
498         int status, mask;
499         char *cmd;
500         int do_cmd = 0;
501
502         if (!hotkey_supported)
503                 return -ENODEV;
504
505         if (!hotkey_get(&status, &mask))
506                 return -EIO;
507
508         while ((cmd = next_cmd(&buf))) {
509                 if (strlencmp(cmd, "enable") == 0) {
510                         status = 1;
511                 } else if (strlencmp(cmd, "disable") == 0) {
512                         status = 0;
513                 } else if (strlencmp(cmd, "reset") == 0) {
514                         status = hotkey_orig_status;
515                         mask = hotkey_orig_mask;
516                 } else if (sscanf(cmd, "0x%x", &mask) == 1) {
517                         /* mask set */
518                 } else if (sscanf(cmd, "%x", &mask) == 1) {
519                         /* mask set */
520                 } else
521                         return -EINVAL;
522                 do_cmd = 1;
523         }
524
525         if (do_cmd && !hotkey_set(status, mask))
526                 return -EIO;
527
528         return 0;
529 }
530
531 static void hotkey_exit(void)
532 {
533         if (hotkey_supported)
534                 hotkey_set(hotkey_orig_status, hotkey_orig_mask);
535 }
536
537 static void hotkey_notify(struct ibm_struct *ibm, u32 event)
538 {
539         int hkey;
540
541         if (acpi_evalf(hkey_handle, &hkey, "MHKP", "d"))
542                 acpi_bus_generate_event(ibm->device, event, hkey);
543         else {
544                 printk(IBM_ERR "unknown hotkey event %d\n", event);
545                 acpi_bus_generate_event(ibm->device, event, 0);
546         }
547 }
548
549 static int bluetooth_supported;
550
551 static int bluetooth_init(void)
552 {
553         /* bluetooth not supported on 570, 600e/x, 770e, 770x, A21e, A2xm/p,
554            G4x, R30, R31, R40e, R50e, T20-22, X20-21 */
555         bluetooth_supported = hkey_handle &&
556             acpi_evalf(hkey_handle, NULL, "GBDC", "qv");
557
558         return 0;
559 }
560
561 static int bluetooth_status(void)
562 {
563         int status;
564
565         if (!bluetooth_supported ||
566             !acpi_evalf(hkey_handle, &status, "GBDC", "d"))
567                 status = 0;
568
569         return status;
570 }
571
572 static int bluetooth_read(char *p)
573 {
574         int len = 0;
575         int status = bluetooth_status();
576
577         if (!bluetooth_supported)
578                 len += sprintf(p + len, "status:\t\tnot supported\n");
579         else if (!(status & 1))
580                 len += sprintf(p + len, "status:\t\tnot installed\n");
581         else {
582                 len += sprintf(p + len, "status:\t\t%s\n", enabled(status, 1));
583                 len += sprintf(p + len, "commands:\tenable, disable\n");
584         }
585
586         return len;
587 }
588
589 static int bluetooth_write(char *buf)
590 {
591         int status = bluetooth_status();
592         char *cmd;
593         int do_cmd = 0;
594
595         if (!bluetooth_supported)
596                 return -ENODEV;
597
598         while ((cmd = next_cmd(&buf))) {
599                 if (strlencmp(cmd, "enable") == 0) {
600                         status |= 2;
601                 } else if (strlencmp(cmd, "disable") == 0) {
602                         status &= ~2;
603                 } else
604                         return -EINVAL;
605                 do_cmd = 1;
606         }
607
608         if (do_cmd && !acpi_evalf(hkey_handle, NULL, "SBDC", "vd", status))
609                 return -EIO;
610
611         return 0;
612 }
613
614 static int wan_supported;
615
616 static int wan_init(void)
617 {
618         wan_supported = hkey_handle &&
619             acpi_evalf(hkey_handle, NULL, "GWAN", "qv");
620
621         return 0;
622 }
623
624 static int wan_status(void)
625 {
626         int status;
627
628         if (!wan_supported || !acpi_evalf(hkey_handle, &status, "GWAN", "d"))
629                 status = 0;
630
631         return status;
632 }
633
634 static int wan_read(char *p)
635 {
636         int len = 0;
637         int status = wan_status();
638
639         if (!wan_supported)
640                 len += sprintf(p + len, "status:\t\tnot supported\n");
641         else if (!(status & 1))
642                 len += sprintf(p + len, "status:\t\tnot installed\n");
643         else {
644                 len += sprintf(p + len, "status:\t\t%s\n", enabled(status, 1));
645                 len += sprintf(p + len, "commands:\tenable, disable\n");
646         }
647
648         return len;
649 }
650
651 static int wan_write(char *buf)
652 {
653         int status = wan_status();
654         char *cmd;
655         int do_cmd = 0;
656
657         if (!wan_supported)
658                 return -ENODEV;
659
660         while ((cmd = next_cmd(&buf))) {
661                 if (strlencmp(cmd, "enable") == 0) {
662                         status |= 2;
663                 } else if (strlencmp(cmd, "disable") == 0) {
664                         status &= ~2;
665                 } else
666                         return -EINVAL;
667                 do_cmd = 1;
668         }
669
670         if (do_cmd && !acpi_evalf(hkey_handle, NULL, "SWAN", "vd", status))
671                 return -EIO;
672
673         return 0;
674 }
675
676 static int video_supported;
677 static int video_orig_autosw;
678
679 #define VIDEO_570 1
680 #define VIDEO_770 2
681 #define VIDEO_NEW 3
682
683 static int video_init(void)
684 {
685         int ivga;
686
687         if (vid2_handle && acpi_evalf(NULL, &ivga, "\\IVGA", "d") && ivga)
688                 /* G41, assume IVGA doesn't change */
689                 vid_handle = vid2_handle;
690
691         if (!vid_handle)
692                 /* video switching not supported on R30, R31 */
693                 video_supported = 0;
694         else if (acpi_evalf(vid_handle, &video_orig_autosw, "SWIT", "qd"))
695                 /* 570 */
696                 video_supported = VIDEO_570;
697         else if (acpi_evalf(vid_handle, &video_orig_autosw, "^VADL", "qd"))
698                 /* 600e/x, 770e, 770x */
699                 video_supported = VIDEO_770;
700         else
701                 /* all others */
702                 video_supported = VIDEO_NEW;
703
704         return 0;
705 }
706
707 static int video_status(void)
708 {
709         int status = 0;
710         int i;
711
712         if (video_supported == VIDEO_570) {
713                 if (acpi_evalf(NULL, &i, "\\_SB.PHS", "dd", 0x87))
714                         status = i & 3;
715         } else if (video_supported == VIDEO_770) {
716                 if (acpi_evalf(NULL, &i, "\\VCDL", "d"))
717                         status |= 0x01 * i;
718                 if (acpi_evalf(NULL, &i, "\\VCDC", "d"))
719                         status |= 0x02 * i;
720         } else if (video_supported == VIDEO_NEW) {
721                 acpi_evalf(NULL, NULL, "\\VUPS", "vd", 1);
722                 if (acpi_evalf(NULL, &i, "\\VCDC", "d"))
723                         status |= 0x02 * i;
724
725                 acpi_evalf(NULL, NULL, "\\VUPS", "vd", 0);
726                 if (acpi_evalf(NULL, &i, "\\VCDL", "d"))
727                         status |= 0x01 * i;
728                 if (acpi_evalf(NULL, &i, "\\VCDD", "d"))
729                         status |= 0x08 * i;
730         }
731
732         return status;
733 }
734
735 static int video_autosw(void)
736 {
737         int autosw = 0;
738
739         if (video_supported == VIDEO_570)
740                 acpi_evalf(vid_handle, &autosw, "SWIT", "d");
741         else if (video_supported == VIDEO_770 || video_supported == VIDEO_NEW)
742                 acpi_evalf(vid_handle, &autosw, "^VDEE", "d");
743
744         return autosw & 1;
745 }
746
747 static int video_read(char *p)
748 {
749         int status = video_status();
750         int autosw = video_autosw();
751         int len = 0;
752
753         if (!video_supported) {
754                 len += sprintf(p + len, "status:\t\tnot supported\n");
755                 return len;
756         }
757
758         len += sprintf(p + len, "status:\t\tsupported\n");
759         len += sprintf(p + len, "lcd:\t\t%s\n", enabled(status, 0));
760         len += sprintf(p + len, "crt:\t\t%s\n", enabled(status, 1));
761         if (video_supported == VIDEO_NEW)
762                 len += sprintf(p + len, "dvi:\t\t%s\n", enabled(status, 3));
763         len += sprintf(p + len, "auto:\t\t%s\n", enabled(autosw, 0));
764         len += sprintf(p + len, "commands:\tlcd_enable, lcd_disable\n");
765         len += sprintf(p + len, "commands:\tcrt_enable, crt_disable\n");
766         if (video_supported == VIDEO_NEW)
767                 len += sprintf(p + len, "commands:\tdvi_enable, dvi_disable\n");
768         len += sprintf(p + len, "commands:\tauto_enable, auto_disable\n");
769         len += sprintf(p + len, "commands:\tvideo_switch, expand_toggle\n");
770
771         return len;
772 }
773
774 static int video_switch(void)
775 {
776         int autosw = video_autosw();
777         int ret;
778
779         if (!acpi_evalf(vid_handle, NULL, "_DOS", "vd", 1))
780                 return -EIO;
781         ret = video_supported == VIDEO_570 ?
782             acpi_evalf(ec_handle, NULL, "_Q16", "v") :
783             acpi_evalf(vid_handle, NULL, "VSWT", "v");
784         acpi_evalf(vid_handle, NULL, "_DOS", "vd", autosw);
785
786         return ret;
787 }
788
789 static int video_expand(void)
790 {
791         if (video_supported == VIDEO_570)
792                 return acpi_evalf(ec_handle, NULL, "_Q17", "v");
793         else if (video_supported == VIDEO_770)
794                 return acpi_evalf(vid_handle, NULL, "VEXP", "v");
795         else
796                 return acpi_evalf(NULL, NULL, "\\VEXP", "v");
797 }
798
799 static int video_switch2(int status)
800 {
801         int ret;
802
803         if (video_supported == VIDEO_570) {
804                 ret = acpi_evalf(NULL, NULL,
805                                  "\\_SB.PHS2", "vdd", 0x8b, status | 0x80);
806         } else if (video_supported == VIDEO_770) {
807                 int autosw = video_autosw();
808                 if (!acpi_evalf(vid_handle, NULL, "_DOS", "vd", 1))
809                         return -EIO;
810
811                 ret = acpi_evalf(vid_handle, NULL,
812                                  "ASWT", "vdd", status * 0x100, 0);
813
814                 acpi_evalf(vid_handle, NULL, "_DOS", "vd", autosw);
815         } else {
816                 ret = acpi_evalf(NULL, NULL, "\\VUPS", "vd", 0x80) &&
817                     acpi_evalf(NULL, NULL, "\\VSDS", "vdd", status, 1);
818         }
819
820         return ret;
821 }
822
823 static int video_write(char *buf)
824 {
825         char *cmd;
826         int enable, disable, status;
827
828         if (!video_supported)
829                 return -ENODEV;
830
831         enable = disable = 0;
832
833         while ((cmd = next_cmd(&buf))) {
834                 if (strlencmp(cmd, "lcd_enable") == 0) {
835                         enable |= 0x01;
836                 } else if (strlencmp(cmd, "lcd_disable") == 0) {
837                         disable |= 0x01;
838                 } else if (strlencmp(cmd, "crt_enable") == 0) {
839                         enable |= 0x02;
840                 } else if (strlencmp(cmd, "crt_disable") == 0) {
841                         disable |= 0x02;
842                 } else if (video_supported == VIDEO_NEW &&
843                            strlencmp(cmd, "dvi_enable") == 0) {
844                         enable |= 0x08;
845                 } else if (video_supported == VIDEO_NEW &&
846                            strlencmp(cmd, "dvi_disable") == 0) {
847                         disable |= 0x08;
848                 } else if (strlencmp(cmd, "auto_enable") == 0) {
849                         if (!acpi_evalf(vid_handle, NULL, "_DOS", "vd", 1))
850                                 return -EIO;
851                 } else if (strlencmp(cmd, "auto_disable") == 0) {
852                         if (!acpi_evalf(vid_handle, NULL, "_DOS", "vd", 0))
853                                 return -EIO;
854                 } else if (strlencmp(cmd, "video_switch") == 0) {
855                         if (!video_switch())
856                                 return -EIO;
857                 } else if (strlencmp(cmd, "expand_toggle") == 0) {
858                         if (!video_expand())
859                                 return -EIO;
860                 } else
861                         return -EINVAL;
862         }
863
864         if (enable || disable) {
865                 status = (video_status() & 0x0f & ~disable) | enable;
866                 if (!video_switch2(status))
867                         return -EIO;
868         }
869
870         return 0;
871 }
872
873 static void video_exit(void)
874 {
875         acpi_evalf(vid_handle, NULL, "_DOS", "vd", video_orig_autosw);
876 }
877
878 static int light_supported;
879 static int light_status_supported;
880
881 static int light_init(void)
882 {
883         /* light not supported on 570, 600e/x, 770e, 770x, G4x, R30, R31 */
884         light_supported = (cmos_handle || lght_handle) && !ledb_handle;
885
886         if (light_supported)
887                 /* light status not supported on
888                    570, 600e/x, 770e, 770x, G4x, R30, R31, R32, X20 */
889                 light_status_supported = acpi_evalf(ec_handle, NULL,
890                                                     "KBLT", "qv");
891
892         return 0;
893 }
894
895 static int light_read(char *p)
896 {
897         int len = 0;
898         int status = 0;
899
900         if (!light_supported) {
901                 len += sprintf(p + len, "status:\t\tnot supported\n");
902         } else if (!light_status_supported) {
903                 len += sprintf(p + len, "status:\t\tunknown\n");
904                 len += sprintf(p + len, "commands:\ton, off\n");
905         } else {
906                 if (!acpi_evalf(ec_handle, &status, "KBLT", "d"))
907                         return -EIO;
908                 len += sprintf(p + len, "status:\t\t%s\n", onoff(status, 0));
909                 len += sprintf(p + len, "commands:\ton, off\n");
910         }
911
912         return len;
913 }
914
915 static int light_write(char *buf)
916 {
917         int cmos_cmd, lght_cmd;
918         char *cmd;
919         int success;
920
921         if (!light_supported)
922                 return -ENODEV;
923
924         while ((cmd = next_cmd(&buf))) {
925                 if (strlencmp(cmd, "on") == 0) {
926                         cmos_cmd = 0x0c;
927                         lght_cmd = 1;
928                 } else if (strlencmp(cmd, "off") == 0) {
929                         cmos_cmd = 0x0d;
930                         lght_cmd = 0;
931                 } else
932                         return -EINVAL;
933
934                 success = cmos_handle ?
935                     acpi_evalf(cmos_handle, NULL, NULL, "vd", cmos_cmd) :
936                     acpi_evalf(lght_handle, NULL, NULL, "vd", lght_cmd);
937                 if (!success)
938                         return -EIO;
939         }
940
941         return 0;
942 }
943
944 static int _sta(acpi_handle handle)
945 {
946         int status;
947
948         if (!handle || !acpi_evalf(handle, &status, "_STA", "d"))
949                 status = 0;
950
951         return status;
952 }
953
954 #ifdef CONFIG_ACPI_IBM_DOCK
955 #define dock_docked() (_sta(dock_handle) & 1)
956
957 static int dock_read(char *p)
958 {
959         int len = 0;
960         int docked = dock_docked();
961
962         if (!dock_handle)
963                 len += sprintf(p + len, "status:\t\tnot supported\n");
964         else if (!docked)
965                 len += sprintf(p + len, "status:\t\tundocked\n");
966         else {
967                 len += sprintf(p + len, "status:\t\tdocked\n");
968                 len += sprintf(p + len, "commands:\tdock, undock\n");
969         }
970
971         return len;
972 }
973
974 static int dock_write(char *buf)
975 {
976         char *cmd;
977
978         if (!dock_docked())
979                 return -ENODEV;
980
981         while ((cmd = next_cmd(&buf))) {
982                 if (strlencmp(cmd, "undock") == 0) {
983                         if (!acpi_evalf(dock_handle, NULL, "_DCK", "vd", 0) ||
984                             !acpi_evalf(dock_handle, NULL, "_EJ0", "vd", 1))
985                                 return -EIO;
986                 } else if (strlencmp(cmd, "dock") == 0) {
987                         if (!acpi_evalf(dock_handle, NULL, "_DCK", "vd", 1))
988                                 return -EIO;
989                 } else
990                         return -EINVAL;
991         }
992
993         return 0;
994 }
995
996 static void dock_notify(struct ibm_struct *ibm, u32 event)
997 {
998         int docked = dock_docked();
999         int pci = ibm->hid && strstr(ibm->hid, IBM_PCI_HID);
1000
1001         if (event == 1 && !pci) /* 570 */
1002                 acpi_bus_generate_event(ibm->device, event, 1); /* button */
1003         else if (event == 1 && pci)     /* 570 */
1004                 acpi_bus_generate_event(ibm->device, event, 3); /* dock */
1005         else if (event == 3 && docked)
1006                 acpi_bus_generate_event(ibm->device, event, 1); /* button */
1007         else if (event == 3 && !docked)
1008                 acpi_bus_generate_event(ibm->device, event, 2); /* undock */
1009         else if (event == 0 && docked)
1010                 acpi_bus_generate_event(ibm->device, event, 3); /* dock */
1011         else {
1012                 printk(IBM_ERR "unknown dock event %d, status %d\n",
1013                        event, _sta(dock_handle));
1014                 acpi_bus_generate_event(ibm->device, event, 0); /* unknown */
1015         }
1016 }
1017 #endif
1018
1019 static int bay_status_supported;
1020 static int bay_status2_supported;
1021 static int bay_eject_supported;
1022 static int bay_eject2_supported;
1023
1024 static int bay_init(void)
1025 {
1026         bay_status_supported = bay_handle &&
1027             acpi_evalf(bay_handle, NULL, "_STA", "qv");
1028         bay_status2_supported = bay2_handle &&
1029             acpi_evalf(bay2_handle, NULL, "_STA", "qv");
1030
1031         bay_eject_supported = bay_handle && bay_ej_handle &&
1032             (strlencmp(bay_ej_path, "_EJ0") == 0 || experimental);
1033         bay_eject2_supported = bay2_handle && bay2_ej_handle &&
1034             (strlencmp(bay2_ej_path, "_EJ0") == 0 || experimental);
1035
1036         return 0;
1037 }
1038
1039 #define bay_occupied(b) (_sta(b##_handle) & 1)
1040
1041 static int bay_read(char *p)
1042 {
1043         int len = 0;
1044         int occupied = bay_occupied(bay);
1045         int occupied2 = bay_occupied(bay2);
1046         int eject, eject2;
1047
1048         len += sprintf(p + len, "status:\t\t%s\n", bay_status_supported ?
1049                        (occupied ? "occupied" : "unoccupied") :
1050                        "not supported");
1051         if (bay_status2_supported)
1052                 len += sprintf(p + len, "status2:\t%s\n", occupied2 ?
1053                                "occupied" : "unoccupied");
1054
1055         eject = bay_eject_supported && occupied;
1056         eject2 = bay_eject2_supported && occupied2;
1057
1058         if (eject && eject2)
1059                 len += sprintf(p + len, "commands:\teject, eject2\n");
1060         else if (eject)
1061                 len += sprintf(p + len, "commands:\teject\n");
1062         else if (eject2)
1063                 len += sprintf(p + len, "commands:\teject2\n");
1064
1065         return len;
1066 }
1067
1068 static int bay_write(char *buf)
1069 {
1070         char *cmd;
1071
1072         if (!bay_eject_supported && !bay_eject2_supported)
1073                 return -ENODEV;
1074
1075         while ((cmd = next_cmd(&buf))) {
1076                 if (bay_eject_supported && strlencmp(cmd, "eject") == 0) {
1077                         if (!acpi_evalf(bay_ej_handle, NULL, NULL, "vd", 1))
1078                                 return -EIO;
1079                 } else if (bay_eject2_supported &&
1080                            strlencmp(cmd, "eject2") == 0) {
1081                         if (!acpi_evalf(bay2_ej_handle, NULL, NULL, "vd", 1))
1082                                 return -EIO;
1083                 } else
1084                         return -EINVAL;
1085         }
1086
1087         return 0;
1088 }
1089
1090 static void bay_notify(struct ibm_struct *ibm, u32 event)
1091 {
1092         acpi_bus_generate_event(ibm->device, event, 0);
1093 }
1094
1095 static int cmos_read(char *p)
1096 {
1097         int len = 0;
1098
1099         /* cmos not supported on 570, 600e/x, 770e, 770x, A21e, A2xm/p,
1100            R30, R31, T20-22, X20-21 */
1101         if (!cmos_handle)
1102                 len += sprintf(p + len, "status:\t\tnot supported\n");
1103         else {
1104                 len += sprintf(p + len, "status:\t\tsupported\n");
1105                 len += sprintf(p + len, "commands:\t<cmd> (<cmd> is 0-21)\n");
1106         }
1107
1108         return len;
1109 }
1110
1111 static int cmos_eval(int cmos_cmd)
1112 {
1113         if (cmos_handle)
1114                 return acpi_evalf(cmos_handle, NULL, NULL, "vd", cmos_cmd);
1115         else
1116                 return 1;
1117 }
1118
1119 static int cmos_write(char *buf)
1120 {
1121         char *cmd;
1122         int cmos_cmd;
1123
1124         if (!cmos_handle)
1125                 return -EINVAL;
1126
1127         while ((cmd = next_cmd(&buf))) {
1128                 if (sscanf(cmd, "%u", &cmos_cmd) == 1 &&
1129                     cmos_cmd >= 0 && cmos_cmd <= 21) {
1130                         /* cmos_cmd set */
1131                 } else
1132                         return -EINVAL;
1133
1134                 if (!cmos_eval(cmos_cmd))
1135                         return -EIO;
1136         }
1137
1138         return 0;
1139 }
1140
1141 static int led_supported;
1142
1143 #define LED_570 1
1144 #define LED_OLD 2
1145 #define LED_NEW 3
1146
1147 static int led_init(void)
1148 {
1149         if (!led_handle)
1150                 /* led not supported on R30, R31 */
1151                 led_supported = 0;
1152         else if (strlencmp(led_path, "SLED") == 0)
1153                 /* 570 */
1154                 led_supported = LED_570;
1155         else if (strlencmp(led_path, "SYSL") == 0)
1156                 /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20-21 */
1157                 led_supported = LED_OLD;
1158         else
1159                 /* all others */
1160                 led_supported = LED_NEW;
1161
1162         return 0;
1163 }
1164
1165 #define led_status(s) ((s) == 0 ? "off" : ((s) == 1 ? "on" : "blinking"))
1166
1167 static int led_read(char *p)
1168 {
1169         int len = 0;
1170
1171         if (!led_supported) {
1172                 len += sprintf(p + len, "status:\t\tnot supported\n");
1173                 return len;
1174         }
1175         len += sprintf(p + len, "status:\t\tsupported\n");
1176
1177         if (led_supported == LED_570) {
1178                 /* 570 */
1179                 int i, status;
1180                 for (i = 0; i < 8; i++) {
1181                         if (!acpi_evalf(ec_handle,
1182                                         &status, "GLED", "dd", 1 << i))
1183                                 return -EIO;
1184                         len += sprintf(p + len, "%d:\t\t%s\n",
1185                                        i, led_status(status));
1186                 }
1187         }
1188
1189         len += sprintf(p + len, "commands:\t"
1190                        "<led> on, <led> off, <led> blink (<led> is 0-7)\n");
1191
1192         return len;
1193 }
1194
1195 /* off, on, blink */
1196 static const int led_sled_arg1[] = { 0, 1, 3 };
1197 static const int led_exp_hlbl[] = { 0, 0, 1 };  /* led# * */
1198 static const int led_exp_hlcl[] = { 0, 1, 1 };  /* led# * */
1199 static const int led_led_arg1[] = { 0, 0x80, 0xc0 };
1200
1201 #define EC_HLCL 0x0c
1202 #define EC_HLBL 0x0d
1203 #define EC_HLMS 0x0e
1204
1205 static int led_write(char *buf)
1206 {
1207         char *cmd;
1208         int led, ind, ret;
1209
1210         if (!led_supported)
1211                 return -ENODEV;
1212
1213         while ((cmd = next_cmd(&buf))) {
1214                 if (sscanf(cmd, "%d", &led) != 1 || led < 0 || led > 7)
1215                         return -EINVAL;
1216
1217                 if (strstr(cmd, "off")) {
1218                         ind = 0;
1219                 } else if (strstr(cmd, "on")) {
1220                         ind = 1;
1221                 } else if (strstr(cmd, "blink")) {
1222                         ind = 2;
1223                 } else
1224                         return -EINVAL;
1225
1226                 if (led_supported == LED_570) {
1227                         /* 570 */
1228                         led = 1 << led;
1229                         if (!acpi_evalf(led_handle, NULL, NULL, "vdd",
1230                                         led, led_sled_arg1[ind]))
1231                                 return -EIO;
1232                 } else if (led_supported == LED_OLD) {
1233                         /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20 */
1234                         led = 1 << led;
1235                         ret = ec_write(EC_HLMS, led);
1236                         if (ret >= 0)
1237                                 ret =
1238                                     ec_write(EC_HLBL, led * led_exp_hlbl[ind]);
1239                         if (ret >= 0)
1240                                 ret =
1241                                     ec_write(EC_HLCL, led * led_exp_hlcl[ind]);
1242                         if (ret < 0)
1243                                 return ret;
1244                 } else {
1245                         /* all others */
1246                         if (!acpi_evalf(led_handle, NULL, NULL, "vdd",
1247                                         led, led_led_arg1[ind]))
1248                                 return -EIO;
1249                 }
1250         }
1251
1252         return 0;
1253 }
1254
1255 static int beep_read(char *p)
1256 {
1257         int len = 0;
1258
1259         if (!beep_handle)
1260                 len += sprintf(p + len, "status:\t\tnot supported\n");
1261         else {
1262                 len += sprintf(p + len, "status:\t\tsupported\n");
1263                 len += sprintf(p + len, "commands:\t<cmd> (<cmd> is 0-17)\n");
1264         }
1265
1266         return len;
1267 }
1268
1269 static int beep_write(char *buf)
1270 {
1271         char *cmd;
1272         int beep_cmd;
1273
1274         if (!beep_handle)
1275                 return -ENODEV;
1276
1277         while ((cmd = next_cmd(&buf))) {
1278                 if (sscanf(cmd, "%u", &beep_cmd) == 1 &&
1279                     beep_cmd >= 0 && beep_cmd <= 17) {
1280                         /* beep_cmd set */
1281                 } else
1282                         return -EINVAL;
1283                 if (!acpi_evalf(beep_handle, NULL, NULL, "vdd", beep_cmd, 0))
1284                         return -EIO;
1285         }
1286
1287         return 0;
1288 }
1289
1290 static int acpi_ec_read(int i, u8 * p)
1291 {
1292         int v;
1293
1294         if (ecrd_handle) {
1295                 if (!acpi_evalf(ecrd_handle, &v, NULL, "dd", i))
1296                         return 0;
1297                 *p = v;
1298         } else {
1299                 if (ec_read(i, p) < 0)
1300                         return 0;
1301         }
1302
1303         return 1;
1304 }
1305
1306 static int acpi_ec_write(int i, u8 v)
1307 {
1308         if (ecwr_handle) {
1309                 if (!acpi_evalf(ecwr_handle, NULL, NULL, "vdd", i, v))
1310                         return 0;
1311         } else {
1312                 if (ec_write(i, v) < 0)
1313                         return 0;
1314         }
1315
1316         return 1;
1317 }
1318
1319 static enum thermal_access_mode thermal_read_mode;
1320
1321 static int thermal_init(void)
1322 {
1323         u8 t, ta1, ta2;
1324         int i;
1325         int acpi_tmp7 = acpi_evalf(ec_handle, NULL, "TMP7", "qv");
1326
1327         if (ibm_thinkpad_ec_found && experimental) {
1328                 /*
1329                  * Direct EC access mode: sensors at registers
1330                  * 0x78-0x7F, 0xC0-0xC7.  Registers return 0x00 for
1331                  * non-implemented, thermal sensors return 0x80 when
1332                  * not available
1333                  */
1334
1335                 ta1 = ta2 = 0;
1336                 for (i = 0; i < 8; i++) {
1337                         if (likely(acpi_ec_read(0x78 + i, &t))) {
1338                                 ta1 |= t;
1339                         } else {
1340                                 ta1 = 0;
1341                                 break;
1342                         }
1343                         if (likely(acpi_ec_read(0xC0 + i, &t))) {
1344                                 ta2 |= t;
1345                         } else {
1346                                 ta1 = 0;
1347                                 break;
1348                         }
1349                 }
1350                 if (ta1 == 0) {
1351                         /* This is sheer paranoia, but we handle it anyway */
1352                         if (acpi_tmp7) {
1353                                 printk(IBM_ERR
1354                                        "ThinkPad ACPI EC access misbehaving, "
1355                                        "falling back to ACPI TMPx access mode\n");
1356                                 thermal_read_mode = IBMACPI_THERMAL_ACPI_TMP07;
1357                         } else {
1358                                 printk(IBM_ERR
1359                                        "ThinkPad ACPI EC access misbehaving, "
1360                                        "disabling thermal sensors access\n");
1361                                 thermal_read_mode = IBMACPI_THERMAL_NONE;
1362                         }
1363                 } else {
1364                         thermal_read_mode =
1365                             (ta2 != 0) ?
1366                             IBMACPI_THERMAL_TPEC_16 : IBMACPI_THERMAL_TPEC_8;
1367                 }
1368         } else if (acpi_tmp7) {
1369                 if (acpi_evalf(ec_handle, NULL, "UPDT", "qv")) {
1370                         /* 600e/x, 770e, 770x */
1371                         thermal_read_mode = IBMACPI_THERMAL_ACPI_UPDT;
1372                 } else {
1373                         /* Standard ACPI TMPx access, max 8 sensors */
1374                         thermal_read_mode = IBMACPI_THERMAL_ACPI_TMP07;
1375                 }
1376         } else {
1377                 /* temperatures not supported on 570, G4x, R30, R31, R32 */
1378                 thermal_read_mode = IBMACPI_THERMAL_NONE;
1379         }
1380
1381         return 0;
1382 }
1383
1384 static int thermal_get_sensors(struct ibm_thermal_sensors_struct *s)
1385 {
1386         int i, t;
1387         s8 tmp;
1388         char tmpi[] = "TMPi";
1389
1390         if (!s)
1391                 return -EINVAL;
1392
1393         switch (thermal_read_mode) {
1394 #if IBMACPI_MAX_THERMAL_SENSORS >= 16
1395         case IBMACPI_THERMAL_TPEC_16:
1396                 for (i = 0; i < 8; i++) {
1397                         if (!acpi_ec_read(0xC0 + i, &tmp))
1398                                 return -EIO;
1399                         s->temp[i + 8] = tmp * 1000;
1400                 }
1401                 /* fallthrough */
1402 #endif
1403         case IBMACPI_THERMAL_TPEC_8:
1404                 for (i = 0; i < 8; i++) {
1405                         if (!acpi_ec_read(0x78 + i, &tmp))
1406                                 return -EIO;
1407                         s->temp[i] = tmp * 1000;
1408                 }
1409                 return (thermal_read_mode == IBMACPI_THERMAL_TPEC_16) ? 16 : 8;
1410
1411         case IBMACPI_THERMAL_ACPI_UPDT:
1412                 if (!acpi_evalf(ec_handle, NULL, "UPDT", "v"))
1413                         return -EIO;
1414                 for (i = 0; i < 8; i++) {
1415                         tmpi[3] = '0' + i;
1416                         if (!acpi_evalf(ec_handle, &t, tmpi, "d"))
1417                                 return -EIO;
1418                         s->temp[i] = (t - 2732) * 100;
1419                 }
1420                 return 8;
1421
1422         case IBMACPI_THERMAL_ACPI_TMP07:
1423                 for (i = 0; i < 8; i++) {
1424                         tmpi[3] = '0' + i;
1425                         if (!acpi_evalf(ec_handle, &t, tmpi, "d"))
1426                                 return -EIO;
1427                         s->temp[i] = t * 1000;
1428                 }
1429                 return 8;
1430
1431         case IBMACPI_THERMAL_NONE:
1432         default:
1433                 return 0;
1434         }
1435 }
1436
1437 static int thermal_read(char *p)
1438 {
1439         int len = 0;
1440         int n, i;
1441         struct ibm_thermal_sensors_struct t;
1442
1443         n = thermal_get_sensors(&t);
1444         if (unlikely(n < 0))
1445                 return n;
1446
1447         len += sprintf(p + len, "temperatures:\t");
1448
1449         if (n > 0) {
1450                 for (i = 0; i < (n - 1); i++)
1451                         len += sprintf(p + len, "%d ", t.temp[i] / 1000);
1452                 len += sprintf(p + len, "%d\n", t.temp[i] / 1000);
1453         } else
1454                 len += sprintf(p + len, "not supported\n");
1455
1456         return len;
1457 }
1458
1459 static u8 ecdump_regs[256];
1460
1461 static int ecdump_read(char *p)
1462 {
1463         int len = 0;
1464         int i, j;
1465         u8 v;
1466
1467         len += sprintf(p + len, "EC      "
1468                        " +00 +01 +02 +03 +04 +05 +06 +07"
1469                        " +08 +09 +0a +0b +0c +0d +0e +0f\n");
1470         for (i = 0; i < 256; i += 16) {
1471                 len += sprintf(p + len, "EC 0x%02x:", i);
1472                 for (j = 0; j < 16; j++) {
1473                         if (!acpi_ec_read(i + j, &v))
1474                                 break;
1475                         if (v != ecdump_regs[i + j])
1476                                 len += sprintf(p + len, " *%02x", v);
1477                         else
1478                                 len += sprintf(p + len, "  %02x", v);
1479                         ecdump_regs[i + j] = v;
1480                 }
1481                 len += sprintf(p + len, "\n");
1482                 if (j != 16)
1483                         break;
1484         }
1485
1486         /* These are way too dangerous to advertise openly... */
1487 #if 0
1488         len += sprintf(p + len, "commands:\t0x<offset> 0x<value>"
1489                        " (<offset> is 00-ff, <value> is 00-ff)\n");
1490         len += sprintf(p + len, "commands:\t0x<offset> <value>  "
1491                        " (<offset> is 00-ff, <value> is 0-255)\n");
1492 #endif
1493         return len;
1494 }
1495
1496 static int ecdump_write(char *buf)
1497 {
1498         char *cmd;
1499         int i, v;
1500
1501         while ((cmd = next_cmd(&buf))) {
1502                 if (sscanf(cmd, "0x%x 0x%x", &i, &v) == 2) {
1503                         /* i and v set */
1504                 } else if (sscanf(cmd, "0x%x %u", &i, &v) == 2) {
1505                         /* i and v set */
1506                 } else
1507                         return -EINVAL;
1508                 if (i >= 0 && i < 256 && v >= 0 && v < 256) {
1509                         if (!acpi_ec_write(i, v))
1510                                 return -EIO;
1511                 } else
1512                         return -EINVAL;
1513         }
1514
1515         return 0;
1516 }
1517
1518 static int brightness_offset = 0x31;
1519
1520 static int brightness_get(struct backlight_device *bd)
1521 {
1522         u8 level;
1523         if (!acpi_ec_read(brightness_offset, &level))
1524                 return -EIO;
1525
1526         level &= 0x7;
1527         return level;
1528 }
1529
1530 static int brightness_read(char *p)
1531 {
1532         int len = 0;
1533         int level;
1534
1535         if ((level = brightness_get(NULL)) < 0) {
1536                 len += sprintf(p + len, "level:\t\tunreadable\n");
1537         } else {
1538                 len += sprintf(p + len, "level:\t\t%d\n", level & 0x7);
1539                 len += sprintf(p + len, "commands:\tup, down\n");
1540                 len += sprintf(p + len, "commands:\tlevel <level>"
1541                                " (<level> is 0-7)\n");
1542         }
1543
1544         return len;
1545 }
1546
1547 #define BRIGHTNESS_UP   4
1548 #define BRIGHTNESS_DOWN 5
1549
1550 static int brightness_set(int value)
1551 {
1552         int cmos_cmd, inc, i;
1553         int current_value = brightness_get(NULL);
1554
1555         value &= 7;
1556
1557         cmos_cmd = value > current_value ? BRIGHTNESS_UP : BRIGHTNESS_DOWN;
1558         inc = value > current_value ? 1 : -1;
1559         for (i = current_value; i != value; i += inc) {
1560                 if (!cmos_eval(cmos_cmd))
1561                         return -EIO;
1562                 if (!acpi_ec_write(brightness_offset, i + inc))
1563                         return -EIO;
1564         }
1565
1566         return 0;
1567 }
1568
1569 static int brightness_write(char *buf)
1570 {
1571         int level;
1572         int new_level;
1573         char *cmd;
1574
1575         while ((cmd = next_cmd(&buf))) {
1576                 if ((level = brightness_get(NULL)) < 0)
1577                         return level;
1578                 level &= 7;
1579
1580                 if (strlencmp(cmd, "up") == 0) {
1581                         new_level = level == 7 ? 7 : level + 1;
1582                 } else if (strlencmp(cmd, "down") == 0) {
1583                         new_level = level == 0 ? 0 : level - 1;
1584                 } else if (sscanf(cmd, "level %d", &new_level) == 1 &&
1585                            new_level >= 0 && new_level <= 7) {
1586                         /* new_level set */
1587                 } else
1588                         return -EINVAL;
1589
1590                 brightness_set(new_level);
1591         }
1592
1593         return 0;
1594 }
1595
1596 static int brightness_update_status(struct backlight_device *bd)
1597 {
1598         return brightness_set(bd->props->brightness);
1599 }
1600
1601 static int volume_offset = 0x30;
1602
1603 static int volume_read(char *p)
1604 {
1605         int len = 0;
1606         u8 level;
1607
1608         if (!acpi_ec_read(volume_offset, &level)) {
1609                 len += sprintf(p + len, "level:\t\tunreadable\n");
1610         } else {
1611                 len += sprintf(p + len, "level:\t\t%d\n", level & 0xf);
1612                 len += sprintf(p + len, "mute:\t\t%s\n", onoff(level, 6));
1613                 len += sprintf(p + len, "commands:\tup, down, mute\n");
1614                 len += sprintf(p + len, "commands:\tlevel <level>"
1615                                " (<level> is 0-15)\n");
1616         }
1617
1618         return len;
1619 }
1620
1621 #define VOLUME_DOWN     0
1622 #define VOLUME_UP       1
1623 #define VOLUME_MUTE     2
1624
1625 static int volume_write(char *buf)
1626 {
1627         int cmos_cmd, inc, i;
1628         u8 level, mute;
1629         int new_level, new_mute;
1630         char *cmd;
1631
1632         while ((cmd = next_cmd(&buf))) {
1633                 if (!acpi_ec_read(volume_offset, &level))
1634                         return -EIO;
1635                 new_mute = mute = level & 0x40;
1636                 new_level = level = level & 0xf;
1637
1638                 if (strlencmp(cmd, "up") == 0) {
1639                         if (mute)
1640                                 new_mute = 0;
1641                         else
1642                                 new_level = level == 15 ? 15 : level + 1;
1643                 } else if (strlencmp(cmd, "down") == 0) {
1644                         if (mute)
1645                                 new_mute = 0;
1646                         else
1647                                 new_level = level == 0 ? 0 : level - 1;
1648                 } else if (sscanf(cmd, "level %d", &new_level) == 1 &&
1649                            new_level >= 0 && new_level <= 15) {
1650                         /* new_level set */
1651                 } else if (strlencmp(cmd, "mute") == 0) {
1652                         new_mute = 0x40;
1653                 } else
1654                         return -EINVAL;
1655
1656                 if (new_level != level) {       /* mute doesn't change */
1657                         cmos_cmd = new_level > level ? VOLUME_UP : VOLUME_DOWN;
1658                         inc = new_level > level ? 1 : -1;
1659
1660                         if (mute && (!cmos_eval(cmos_cmd) ||
1661                                      !acpi_ec_write(volume_offset, level)))
1662                                 return -EIO;
1663
1664                         for (i = level; i != new_level; i += inc)
1665                                 if (!cmos_eval(cmos_cmd) ||
1666                                     !acpi_ec_write(volume_offset, i + inc))
1667                                         return -EIO;
1668
1669                         if (mute && (!cmos_eval(VOLUME_MUTE) ||
1670                                      !acpi_ec_write(volume_offset,
1671                                                     new_level + mute)))
1672                                 return -EIO;
1673                 }
1674
1675                 if (new_mute != mute) { /* level doesn't change */
1676                         cmos_cmd = new_mute ? VOLUME_MUTE : VOLUME_UP;
1677
1678                         if (!cmos_eval(cmos_cmd) ||
1679                             !acpi_ec_write(volume_offset, level + new_mute))
1680                                 return -EIO;
1681                 }
1682         }
1683
1684         return 0;
1685 }
1686
1687 static enum fan_status_access_mode fan_status_access_mode;
1688 static enum fan_control_access_mode fan_control_access_mode;
1689 static enum fan_control_commands fan_control_commands;
1690
1691 static int fan_init(void)
1692 {
1693         u8 status;
1694
1695         fan_status_access_mode = IBMACPI_FAN_NONE;
1696         fan_control_access_mode = IBMACPI_FAN_WR_NONE;
1697         fan_control_commands = 0;
1698
1699         if (gfan_handle) {
1700                 /* 570, 600e/x, 770e, 770x */
1701                 fan_status_access_mode = IBMACPI_FAN_RD_ACPI_GFAN;
1702         } else {
1703                 /* all other ThinkPads: note that even old-style
1704                  * ThinkPad ECs supports the fan control register */
1705                 if (likely(acpi_ec_read(fan_status_offset, &status))) {
1706                         fan_status_access_mode = IBMACPI_FAN_RD_TPEC;
1707                 } else {
1708                         printk(IBM_ERR
1709                                "ThinkPad ACPI EC access misbehaving, "
1710                                "fan status and control unavailable\n");
1711                         return 0;
1712                 }
1713         }
1714
1715         if (sfan_handle) {
1716                 /* 570, 770x-JL */
1717                 fan_control_access_mode = IBMACPI_FAN_WR_ACPI_SFAN;
1718                 fan_control_commands |= IBMACPI_FAN_CMD_LEVEL;
1719         } else {
1720                 if (!gfan_handle) {
1721                         /* gfan without sfan means no fan control */
1722                         /* all other models implement TP EC 0x2f control */
1723
1724                         if (fans_handle) {
1725                                 /* X31, X40 */
1726                                 fan_control_access_mode =
1727                                     IBMACPI_FAN_WR_ACPI_FANS;
1728                                 fan_control_commands |=
1729                                     IBMACPI_FAN_CMD_SPEED |
1730                                     IBMACPI_FAN_CMD_ENABLE;
1731                         } else {
1732                                 fan_control_access_mode = IBMACPI_FAN_WR_TPEC;
1733                                 fan_control_commands |= IBMACPI_FAN_CMD_ENABLE;
1734                         }
1735                 }
1736         }
1737
1738         return 0;
1739 }
1740
1741 static int fan_read(char *p)
1742 {
1743         int len = 0;
1744         u8 lo, hi, status;
1745
1746         switch (fan_status_access_mode) {
1747         case IBMACPI_FAN_RD_ACPI_GFAN:
1748                 /* 570, 600e/x, 770e, 770x */
1749                 if (unlikely(!acpi_evalf(gfan_handle, &status, NULL, "d")))
1750                         return -EIO;
1751
1752                 len += sprintf(p + len, "level:\t\t%d\n", status);
1753
1754                 break;
1755
1756         case IBMACPI_FAN_RD_TPEC:
1757                 /* all except 570, 600e/x, 770e, 770x */
1758                 if (unlikely(!acpi_ec_read(fan_status_offset, &status)))
1759                         return -EIO;
1760                 else
1761                         len += sprintf(p + len, "status:\t\t%s\n",
1762                                        enabled(status, 7));
1763
1764                 if (unlikely(!acpi_ec_read(fan_rpm_offset, &lo) ||
1765                              !acpi_ec_read(fan_rpm_offset + 1, &hi)))
1766                         return -EIO;
1767                 else
1768                         len += sprintf(p + len, "speed:\t\t%d\n",
1769                                        (hi << 8) + lo);
1770
1771                 break;
1772
1773         case IBMACPI_FAN_NONE:
1774         default:
1775                 len += sprintf(p + len, "status:\t\tnot supported\n");
1776         }
1777
1778         if (fan_control_commands & IBMACPI_FAN_CMD_LEVEL)
1779                 len += sprintf(p + len, "commands:\tlevel <level>"
1780                                " (<level> is 0-7)\n");
1781
1782         if (fan_control_commands & IBMACPI_FAN_CMD_ENABLE)
1783                 len += sprintf(p + len, "commands:\tenable, disable\n");
1784
1785         if (fan_control_commands & IBMACPI_FAN_CMD_SPEED)
1786                 len += sprintf(p + len, "commands:\tspeed <speed>"
1787                                " (<speed> is 0-65535)\n");
1788
1789         return len;
1790 }
1791
1792 static int fan_write(char *buf)
1793 {
1794         char *cmd;
1795         int level, speed;
1796
1797         while ((cmd = next_cmd(&buf))) {
1798                 if (sfan_handle &&
1799                     sscanf(cmd, "level %d", &level) == 1 &&
1800                     level >= 0 && level <= 7) {
1801                         /* 570, 770x-JL */
1802                         if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", level))
1803                                 return -EIO;
1804                 } else if (!gfan_handle && strlencmp(cmd, "enable") == 0) {
1805                         /* all except 570, 600e/x, 770e, 770x */
1806                         if (!acpi_ec_write(fan_status_offset, 0x80))
1807                                 return -EIO;
1808                 } else if (!gfan_handle && strlencmp(cmd, "disable") == 0) {
1809                         /* all except 570, 600e/x, 770e, 770x */
1810                         if (!acpi_ec_write(fan_status_offset, 0x00))
1811                                 return -EIO;
1812                 } else if (fans_handle &&
1813                            sscanf(cmd, "speed %d", &speed) == 1 &&
1814                            speed >= 0 && speed <= 65535) {
1815                         /* X31, X40 */
1816                         if (!acpi_evalf(fans_handle, NULL, NULL, "vddd",
1817                                         speed, speed, speed))
1818                                 return -EIO;
1819                 } else
1820                         return -EINVAL;
1821         }
1822
1823         return 0;
1824 }
1825
1826 static struct ibm_struct ibms[] = {
1827         {
1828          .name = "driver",
1829          .init = driver_init,
1830          .read = driver_read,
1831          },
1832         {
1833          .name = "hotkey",
1834          .hid = IBM_HKEY_HID,
1835          .init = hotkey_init,
1836          .read = hotkey_read,
1837          .write = hotkey_write,
1838          .exit = hotkey_exit,
1839          .notify = hotkey_notify,
1840          .handle = &hkey_handle,
1841          .type = ACPI_DEVICE_NOTIFY,
1842          },
1843         {
1844          .name = "bluetooth",
1845          .init = bluetooth_init,
1846          .read = bluetooth_read,
1847          .write = bluetooth_write,
1848          },
1849         {
1850          .name = "wan",
1851          .init = wan_init,
1852          .read = wan_read,
1853          .write = wan_write,
1854          .experimental = 1,
1855          },
1856         {
1857          .name = "video",
1858          .init = video_init,
1859          .read = video_read,
1860          .write = video_write,
1861          .exit = video_exit,
1862          },
1863         {
1864          .name = "light",
1865          .init = light_init,
1866          .read = light_read,
1867          .write = light_write,
1868          },
1869 #ifdef CONFIG_ACPI_IBM_DOCK
1870         {
1871          .name = "dock",
1872          .read = dock_read,
1873          .write = dock_write,
1874          .notify = dock_notify,
1875          .handle = &dock_handle,
1876          .type = ACPI_SYSTEM_NOTIFY,
1877          },
1878         {
1879          .name = "dock",
1880          .hid = IBM_PCI_HID,
1881          .notify = dock_notify,
1882          .handle = &pci_handle,
1883          .type = ACPI_SYSTEM_NOTIFY,
1884          },
1885 #endif
1886         {
1887          .name = "bay",
1888          .init = bay_init,
1889          .read = bay_read,
1890          .write = bay_write,
1891          .notify = bay_notify,
1892          .handle = &bay_handle,
1893          .type = ACPI_SYSTEM_NOTIFY,
1894          },
1895         {
1896          .name = "cmos",
1897          .read = cmos_read,
1898          .write = cmos_write,
1899          },
1900         {
1901          .name = "led",
1902          .init = led_init,
1903          .read = led_read,
1904          .write = led_write,
1905          },
1906         {
1907          .name = "beep",
1908          .read = beep_read,
1909          .write = beep_write,
1910          },
1911         {
1912          .name = "thermal",
1913          .init = thermal_init,
1914          .read = thermal_read,
1915          },
1916         {
1917          .name = "ecdump",
1918          .read = ecdump_read,
1919          .write = ecdump_write,
1920          .experimental = 1,
1921          },
1922         {
1923          .name = "brightness",
1924          .read = brightness_read,
1925          .write = brightness_write,
1926          },
1927         {
1928          .name = "volume",
1929          .read = volume_read,
1930          .write = volume_write,
1931          },
1932         {
1933          .name = "fan",
1934          .read = fan_read,
1935          .write = fan_write,
1936          .init = fan_init,
1937          .experimental = 1,
1938          },
1939 };
1940
1941 static int dispatch_read(char *page, char **start, off_t off, int count,
1942                          int *eof, void *data)
1943 {
1944         struct ibm_struct *ibm = (struct ibm_struct *)data;
1945         int len;
1946
1947         if (!ibm || !ibm->read)
1948                 return -EINVAL;
1949
1950         len = ibm->read(page);
1951         if (len < 0)
1952                 return len;
1953
1954         if (len <= off + count)
1955                 *eof = 1;
1956         *start = page + off;
1957         len -= off;
1958         if (len > count)
1959                 len = count;
1960         if (len < 0)
1961                 len = 0;
1962
1963         return len;
1964 }
1965
1966 static int dispatch_write(struct file *file, const char __user * userbuf,
1967                           unsigned long count, void *data)
1968 {
1969         struct ibm_struct *ibm = (struct ibm_struct *)data;
1970         char *kernbuf;
1971         int ret;
1972
1973         if (!ibm || !ibm->write)
1974                 return -EINVAL;
1975
1976         kernbuf = kmalloc(count + 2, GFP_KERNEL);
1977         if (!kernbuf)
1978                 return -ENOMEM;
1979
1980         if (copy_from_user(kernbuf, userbuf, count)) {
1981                 kfree(kernbuf);
1982                 return -EFAULT;
1983         }
1984
1985         kernbuf[count] = 0;
1986         strcat(kernbuf, ",");
1987         ret = ibm->write(kernbuf);
1988         if (ret == 0)
1989                 ret = count;
1990
1991         kfree(kernbuf);
1992
1993         return ret;
1994 }
1995
1996 static void dispatch_notify(acpi_handle handle, u32 event, void *data)
1997 {
1998         struct ibm_struct *ibm = (struct ibm_struct *)data;
1999
2000         if (!ibm || !ibm->notify)
2001                 return;
2002
2003         ibm->notify(ibm, event);
2004 }
2005
2006 static int __init setup_notify(struct ibm_struct *ibm)
2007 {
2008         acpi_status status;
2009         int ret;
2010
2011         if (!*ibm->handle)
2012                 return 0;
2013
2014         ret = acpi_bus_get_device(*ibm->handle, &ibm->device);
2015         if (ret < 0) {
2016                 printk(IBM_ERR "%s device not present\n", ibm->name);
2017                 return 0;
2018         }
2019
2020         acpi_driver_data(ibm->device) = ibm;
2021         sprintf(acpi_device_class(ibm->device), "%s/%s", IBM_NAME, ibm->name);
2022
2023         status = acpi_install_notify_handler(*ibm->handle, ibm->type,
2024                                              dispatch_notify, ibm);
2025         if (ACPI_FAILURE(status)) {
2026                 printk(IBM_ERR "acpi_install_notify_handler(%s) failed: %d\n",
2027                        ibm->name, status);
2028                 return -ENODEV;
2029         }
2030
2031         return 0;
2032 }
2033
2034 static int __init ibm_device_add(struct acpi_device *device)
2035 {
2036         return 0;
2037 }
2038
2039 static int __init register_driver(struct ibm_struct *ibm)
2040 {
2041         int ret;
2042
2043         ibm->driver = kmalloc(sizeof(struct acpi_driver), GFP_KERNEL);
2044         if (!ibm->driver) {
2045                 printk(IBM_ERR "kmalloc(ibm->driver) failed\n");
2046                 return -1;
2047         }
2048
2049         memset(ibm->driver, 0, sizeof(struct acpi_driver));
2050         sprintf(ibm->driver->name, "%s_%s", IBM_NAME, ibm->name);
2051         ibm->driver->ids = ibm->hid;
2052         ibm->driver->ops.add = &ibm_device_add;
2053
2054         ret = acpi_bus_register_driver(ibm->driver);
2055         if (ret < 0) {
2056                 printk(IBM_ERR "acpi_bus_register_driver(%s) failed: %d\n",
2057                        ibm->hid, ret);
2058                 kfree(ibm->driver);
2059         }
2060
2061         return ret;
2062 }
2063
2064 static int __init ibm_init(struct ibm_struct *ibm)
2065 {
2066         int ret;
2067         struct proc_dir_entry *entry;
2068
2069         if (ibm->experimental && !experimental)
2070                 return 0;
2071
2072         if (ibm->hid) {
2073                 ret = register_driver(ibm);
2074                 if (ret < 0)
2075                         return ret;
2076                 ibm->driver_registered = 1;
2077         }
2078
2079         if (ibm->init) {
2080                 ret = ibm->init();
2081                 if (ret != 0)
2082                         return ret;
2083                 ibm->init_called = 1;
2084         }
2085
2086         if (ibm->read) {
2087                 entry = create_proc_entry(ibm->name,
2088                                           S_IFREG | S_IRUGO | S_IWUSR,
2089                                           proc_dir);
2090                 if (!entry) {
2091                         printk(IBM_ERR "unable to create proc entry %s\n",
2092                                ibm->name);
2093                         return -ENODEV;
2094                 }
2095                 entry->owner = THIS_MODULE;
2096                 entry->data = ibm;
2097                 entry->read_proc = &dispatch_read;
2098                 if (ibm->write)
2099                         entry->write_proc = &dispatch_write;
2100                 ibm->proc_created = 1;
2101         }
2102
2103         if (ibm->notify) {
2104                 ret = setup_notify(ibm);
2105                 if (ret < 0)
2106                         return ret;
2107                 ibm->notify_installed = 1;
2108         }
2109
2110         return 0;
2111 }
2112
2113 static void ibm_exit(struct ibm_struct *ibm)
2114 {
2115         if (ibm->notify_installed)
2116                 acpi_remove_notify_handler(*ibm->handle, ibm->type,
2117                                            dispatch_notify);
2118
2119         if (ibm->proc_created)
2120                 remove_proc_entry(ibm->name, proc_dir);
2121
2122         if (ibm->init_called && ibm->exit)
2123                 ibm->exit();
2124
2125         if (ibm->driver_registered) {
2126                 acpi_bus_unregister_driver(ibm->driver);
2127                 kfree(ibm->driver);
2128         }
2129 }
2130
2131 static void __init ibm_handle_init(char *name,
2132                                    acpi_handle * handle, acpi_handle parent,
2133                                    char **paths, int num_paths, char **path)
2134 {
2135         int i;
2136         acpi_status status;
2137
2138         for (i = 0; i < num_paths; i++) {
2139                 status = acpi_get_handle(parent, paths[i], handle);
2140                 if (ACPI_SUCCESS(status)) {
2141                         *path = paths[i];
2142                         return;
2143                 }
2144         }
2145
2146         *handle = NULL;
2147 }
2148
2149 #define IBM_HANDLE_INIT(object)                                         \
2150         ibm_handle_init(#object, &object##_handle, *object##_parent,    \
2151                 object##_paths, ARRAY_SIZE(object##_paths), &object##_path)
2152
2153 static int set_ibm_param(const char *val, struct kernel_param *kp)
2154 {
2155         unsigned int i;
2156
2157         for (i = 0; i < ARRAY_SIZE(ibms); i++)
2158                 if (strcmp(ibms[i].name, kp->name) == 0 && ibms[i].write) {
2159                         if (strlen(val) > sizeof(ibms[i].param) - 2)
2160                                 return -ENOSPC;
2161                         strcpy(ibms[i].param, val);
2162                         strcat(ibms[i].param, ",");
2163                         return 0;
2164                 }
2165
2166         return -EINVAL;
2167 }
2168
2169 #define IBM_PARAM(feature) \
2170         module_param_call(feature, set_ibm_param, NULL, NULL, 0)
2171
2172 IBM_PARAM(hotkey);
2173 IBM_PARAM(bluetooth);
2174 IBM_PARAM(video);
2175 IBM_PARAM(light);
2176 #ifdef CONFIG_ACPI_IBM_DOCK
2177 IBM_PARAM(dock);
2178 #endif
2179 IBM_PARAM(bay);
2180 IBM_PARAM(cmos);
2181 IBM_PARAM(led);
2182 IBM_PARAM(beep);
2183 IBM_PARAM(ecdump);
2184 IBM_PARAM(brightness);
2185 IBM_PARAM(volume);
2186 IBM_PARAM(fan);
2187
2188 static struct backlight_properties ibm_backlight_data = {
2189         .owner = THIS_MODULE,
2190         .get_brightness = brightness_get,
2191         .update_status = brightness_update_status,
2192         .max_brightness = 7,
2193 };
2194
2195 static void acpi_ibm_exit(void)
2196 {
2197         int i;
2198
2199         if (ibm_backlight_device)
2200                 backlight_device_unregister(ibm_backlight_device);
2201
2202         for (i = ARRAY_SIZE(ibms) - 1; i >= 0; i--)
2203                 ibm_exit(&ibms[i]);
2204
2205         remove_proc_entry(IBM_DIR, acpi_root_dir);
2206 }
2207
2208 static int __init check_dmi_for_ec(void)
2209 {
2210         struct dmi_device *dev = NULL;
2211
2212         /*
2213          * ThinkPad T23 or newer, A31 or newer, R50e or newer,
2214          * X32 or newer, all Z series;  Some models must have an
2215          * up-to-date BIOS or they will not be detected.
2216          *
2217          * See http://thinkwiki.org/wiki/List_of_DMI_IDs
2218          */
2219         while ((dev = dmi_find_device(DMI_DEV_TYPE_OEM_STRING, NULL, dev))) {
2220                 if (strstr(dev->name, "IBM ThinkPad Embedded Controller"))
2221                         return 1;
2222         }
2223         return 0;
2224 }
2225
2226 static int __init acpi_ibm_init(void)
2227 {
2228         int ret, i;
2229
2230         if (acpi_disabled)
2231                 return -ENODEV;
2232
2233         if (!acpi_specific_hotkey_enabled) {
2234                 printk(IBM_ERR "using generic hotkey driver\n");
2235                 return -ENODEV;
2236         }
2237
2238         /* ec is required because many other handles are relative to it */
2239         IBM_HANDLE_INIT(ec);
2240         if (!ec_handle) {
2241                 printk(IBM_ERR "ec object not found\n");
2242                 return -ENODEV;
2243         }
2244
2245         /* Models with newer firmware report the EC in DMI */
2246         ibm_thinkpad_ec_found = check_dmi_for_ec();
2247
2248         /* these handles are not required */
2249         IBM_HANDLE_INIT(vid);
2250         IBM_HANDLE_INIT(vid2);
2251         IBM_HANDLE_INIT(ledb);
2252         IBM_HANDLE_INIT(led);
2253         IBM_HANDLE_INIT(hkey);
2254         IBM_HANDLE_INIT(lght);
2255         IBM_HANDLE_INIT(cmos);
2256 #ifdef CONFIG_ACPI_IBM_DOCK
2257         IBM_HANDLE_INIT(dock);
2258 #endif
2259         IBM_HANDLE_INIT(pci);
2260         IBM_HANDLE_INIT(bay);
2261         if (bay_handle)
2262                 IBM_HANDLE_INIT(bay_ej);
2263         IBM_HANDLE_INIT(bay2);
2264         if (bay2_handle)
2265                 IBM_HANDLE_INIT(bay2_ej);
2266         IBM_HANDLE_INIT(beep);
2267         IBM_HANDLE_INIT(ecrd);
2268         IBM_HANDLE_INIT(ecwr);
2269         IBM_HANDLE_INIT(fans);
2270         IBM_HANDLE_INIT(gfan);
2271         IBM_HANDLE_INIT(sfan);
2272
2273         proc_dir = proc_mkdir(IBM_DIR, acpi_root_dir);
2274         if (!proc_dir) {
2275                 printk(IBM_ERR "unable to create proc dir %s", IBM_DIR);
2276                 return -ENODEV;
2277         }
2278         proc_dir->owner = THIS_MODULE;
2279
2280         for (i = 0; i < ARRAY_SIZE(ibms); i++) {
2281                 ret = ibm_init(&ibms[i]);
2282                 if (ret >= 0 && *ibms[i].param)
2283                         ret = ibms[i].write(ibms[i].param);
2284                 if (ret < 0) {
2285                         acpi_ibm_exit();
2286                         return ret;
2287                 }
2288         }
2289
2290         ibm_backlight_device = backlight_device_register("ibm", NULL,
2291                                                          &ibm_backlight_data);
2292         if (IS_ERR(ibm_backlight_device)) {
2293                 printk(IBM_ERR "Could not register ibm backlight device\n");
2294                 ibm_backlight_device = NULL;
2295                 acpi_ibm_exit();
2296         }
2297
2298         return 0;
2299 }
2300
2301 module_init(acpi_ibm_init);
2302 module_exit(acpi_ibm_exit);