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