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