ACPI: thinkpad-acpi: clean up hotkey subdriver
[linux-2.6-block.git] / drivers / misc / thinkpad_acpi.c
1 /*
2  *  thinkpad_acpi.c - ThinkPad ACPI Extras
3  *
4  *
5  *  Copyright (C) 2004-2005 Borislav Deianov <borislav@users.sf.net>
6  *  Copyright (C) 2006-2007 Henrique de Moraes Holschuh <hmh@hmh.eng.br>
7  *
8  *  This program is free software; you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License as published by
10  *  the Free Software Foundation; either version 2 of the License, or
11  *  (at your option) any later version.
12  *
13  *  This program is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *  GNU General Public License for more details.
17  *
18  *  You should have received a copy of the GNU General Public License
19  *  along with this program; if not, write to the Free Software
20  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21  *  02110-1301, USA.
22  */
23
24 #define IBM_VERSION "0.14"
25
26 /*
27  *  Changelog:
28  *  2007-03-27  0.14    renamed to thinkpad_acpi and moved to
29  *                      drivers/misc.
30  *
31  *  2006-11-22  0.13    new maintainer
32  *                      changelog now lives in git commit history, and will
33  *                      not be updated further in-file.
34  *
35  *  2005-08-17  0.12    fix compilation on 2.6.13-rc kernels
36  *  2005-03-17  0.11    support for 600e, 770x
37  *                          thanks to Jamie Lentin <lentinj@dial.pipex.com>
38  *                      support for 770e, G41
39  *                      G40 and G41 don't have a thinklight
40  *                      temperatures no longer experimental
41  *                      experimental brightness control
42  *                      experimental volume control
43  *                      experimental fan enable/disable
44  *  2005-01-16  0.10    fix module loading on R30, R31
45  *  2005-01-16  0.9     support for 570, R30, R31
46  *                      ultrabay support on A22p, A3x
47  *                      limit arg for cmos, led, beep, drop experimental status
48  *                      more capable led control on A21e, A22p, T20-22, X20
49  *                      experimental temperatures and fan speed
50  *                      experimental embedded controller register dump
51  *                      mark more functions as __init, drop incorrect __exit
52  *                      use MODULE_VERSION
53  *                          thanks to Henrik Brix Andersen <brix@gentoo.org>
54  *                      fix parameter passing on module loading
55  *                          thanks to Rusty Russell <rusty@rustcorp.com.au>
56  *                          thanks to Jim Radford <radford@blackbean.org>
57  *  2004-11-08  0.8     fix init error case, don't return from a macro
58  *                          thanks to Chris Wright <chrisw@osdl.org>
59  *  2004-10-23  0.7     fix module loading on A21e, A22p, T20, T21, X20
60  *                      fix led control on A21e
61  *  2004-10-19  0.6     use acpi_bus_register_driver() to claim HKEY device
62  *  2004-10-18  0.5     thinklight support on A21e, G40, R32, T20, T21, X20
63  *                      proc file format changed
64  *                      video_switch command
65  *                      experimental cmos control
66  *                      experimental led control
67  *                      experimental acpi sounds
68  *  2004-09-16  0.4     support for module parameters
69  *                      hotkey mask can be prefixed by 0x
70  *                      video output switching
71  *                      video expansion control
72  *                      ultrabay eject support
73  *                      removed lcd brightness/on/off control, didn't work
74  *  2004-08-17  0.3     support for R40
75  *                      lcd off, brightness control
76  *                      thinklight on/off
77  *  2004-08-14  0.2     support for T series, X20
78  *                      bluetooth enable/disable
79  *                      hotkey events disabled by default
80  *                      removed fan control, currently useless
81  *  2004-08-09  0.1     initial release, support for X series
82  */
83
84 #include "thinkpad_acpi.h"
85
86 MODULE_AUTHOR("Borislav Deianov, Henrique de Moraes Holschuh");
87 MODULE_DESCRIPTION(IBM_DESC);
88 MODULE_VERSION(IBM_VERSION);
89 MODULE_LICENSE("GPL");
90
91 /* Please remove this in year 2009 */
92 MODULE_ALIAS("ibm_acpi");
93
94 #define __unused __attribute__ ((unused))
95
96 /****************************************************************************
97  ****************************************************************************
98  *
99  * ACPI Helpers and device model
100  *
101  ****************************************************************************
102  ****************************************************************************/
103
104 /*************************************************************************
105  * ACPI basic handles
106  */
107
108 static acpi_handle root_handle = NULL;
109
110 #define IBM_HANDLE(object, parent, paths...)                    \
111         static acpi_handle  object##_handle;                    \
112         static acpi_handle *object##_parent = &parent##_handle; \
113         static char        *object##_path;                      \
114         static char        *object##_paths[] = { paths }
115
116 IBM_HANDLE(ec, root, "\\_SB.PCI0.ISA.EC0",      /* 240, 240x */
117            "\\_SB.PCI.ISA.EC",  /* 570 */
118            "\\_SB.PCI0.ISA0.EC0",       /* 600e/x, 770e, 770x */
119            "\\_SB.PCI0.ISA.EC", /* A21e, A2xm/p, T20-22, X20-21 */
120            "\\_SB.PCI0.AD4S.EC0",       /* i1400, R30 */
121            "\\_SB.PCI0.ICH3.EC0",       /* R31 */
122            "\\_SB.PCI0.LPC.EC", /* all others */
123            );
124
125 IBM_HANDLE(ecrd, ec, "ECRD");   /* 570 */
126 IBM_HANDLE(ecwr, ec, "ECWR");   /* 570 */
127
128
129 /*************************************************************************
130  * Misc ACPI handles
131  */
132
133 IBM_HANDLE(cmos, root, "\\UCMS",        /* R50, R50e, R50p, R51, T4x, X31, X40 */
134            "\\CMOS",            /* A3x, G4x, R32, T23, T30, X22-24, X30 */
135            "\\CMS",             /* R40, R40e */
136            );                   /* all others */
137
138 IBM_HANDLE(hkey, ec, "\\_SB.HKEY",      /* 600e/x, 770e, 770x */
139            "^HKEY",             /* R30, R31 */
140            "HKEY",              /* all others */
141            );                   /* 570 */
142
143
144 /*************************************************************************
145  * ACPI helpers
146  */
147
148 static int acpi_evalf(acpi_handle handle,
149                       void *res, char *method, char *fmt, ...)
150 {
151         char *fmt0 = fmt;
152         struct acpi_object_list params;
153         union acpi_object in_objs[IBM_MAX_ACPI_ARGS];
154         struct acpi_buffer result, *resultp;
155         union acpi_object out_obj;
156         acpi_status status;
157         va_list ap;
158         char res_type;
159         int success;
160         int quiet;
161
162         if (!*fmt) {
163                 printk(IBM_ERR "acpi_evalf() called with empty format\n");
164                 return 0;
165         }
166
167         if (*fmt == 'q') {
168                 quiet = 1;
169                 fmt++;
170         } else
171                 quiet = 0;
172
173         res_type = *(fmt++);
174
175         params.count = 0;
176         params.pointer = &in_objs[0];
177
178         va_start(ap, fmt);
179         while (*fmt) {
180                 char c = *(fmt++);
181                 switch (c) {
182                 case 'd':       /* int */
183                         in_objs[params.count].integer.value = va_arg(ap, int);
184                         in_objs[params.count++].type = ACPI_TYPE_INTEGER;
185                         break;
186                         /* add more types as needed */
187                 default:
188                         printk(IBM_ERR "acpi_evalf() called "
189                                "with invalid format character '%c'\n", c);
190                         return 0;
191                 }
192         }
193         va_end(ap);
194
195         if (res_type != 'v') {
196                 result.length = sizeof(out_obj);
197                 result.pointer = &out_obj;
198                 resultp = &result;
199         } else
200                 resultp = NULL;
201
202         status = acpi_evaluate_object(handle, method, &params, resultp);
203
204         switch (res_type) {
205         case 'd':               /* int */
206                 if (res)
207                         *(int *)res = out_obj.integer.value;
208                 success = status == AE_OK && out_obj.type == ACPI_TYPE_INTEGER;
209                 break;
210         case 'v':               /* void */
211                 success = status == AE_OK;
212                 break;
213                 /* add more types as needed */
214         default:
215                 printk(IBM_ERR "acpi_evalf() called "
216                        "with invalid format character '%c'\n", res_type);
217                 return 0;
218         }
219
220         if (!success && !quiet)
221                 printk(IBM_ERR "acpi_evalf(%s, %s, ...) failed: %d\n",
222                        method, fmt0, status);
223
224         return success;
225 }
226
227 static void __unused acpi_print_int(acpi_handle handle, char *method)
228 {
229         int i;
230
231         if (acpi_evalf(handle, &i, method, "d"))
232                 printk(IBM_INFO "%s = 0x%x\n", method, i);
233         else
234                 printk(IBM_ERR "error calling %s\n", method);
235 }
236
237 static int acpi_ec_read(int i, u8 * p)
238 {
239         int v;
240
241         if (ecrd_handle) {
242                 if (!acpi_evalf(ecrd_handle, &v, NULL, "dd", i))
243                         return 0;
244                 *p = v;
245         } else {
246                 if (ec_read(i, p) < 0)
247                         return 0;
248         }
249
250         return 1;
251 }
252
253 static int acpi_ec_write(int i, u8 v)
254 {
255         if (ecwr_handle) {
256                 if (!acpi_evalf(ecwr_handle, NULL, NULL, "vdd", i, v))
257                         return 0;
258         } else {
259                 if (ec_write(i, v) < 0)
260                         return 0;
261         }
262
263         return 1;
264 }
265
266 static int _sta(acpi_handle handle)
267 {
268         int status;
269
270         if (!handle || !acpi_evalf(handle, &status, "_STA", "d"))
271                 status = 0;
272
273         return status;
274 }
275
276 /*************************************************************************
277  * ACPI device model
278  */
279
280 static void drv_acpi_handle_init(char *name,
281                            acpi_handle *handle, acpi_handle parent,
282                            char **paths, int num_paths, char **path)
283 {
284         int i;
285         acpi_status status;
286
287         for (i = 0; i < num_paths; i++) {
288                 status = acpi_get_handle(parent, paths[i], handle);
289                 if (ACPI_SUCCESS(status)) {
290                         *path = paths[i];
291                         return;
292                 }
293         }
294
295         *handle = NULL;
296 }
297
298 static void dispatch_acpi_notify(acpi_handle handle, u32 event, void *data)
299 {
300         struct ibm_struct *ibm = data;
301
302         if (!ibm || !ibm->acpi || !ibm->acpi->notify)
303                 return;
304
305         ibm->acpi->notify(ibm, event);
306 }
307
308 static int __init setup_acpi_notify(struct ibm_struct *ibm)
309 {
310         acpi_status status;
311         int ret;
312
313         BUG_ON(!ibm->acpi);
314
315         if (!*ibm->acpi->handle)
316                 return 0;
317
318         dbg_printk(TPACPI_DBG_INIT,
319                 "setting up ACPI notify for %s\n", ibm->name);
320
321         ret = acpi_bus_get_device(*ibm->acpi->handle, &ibm->acpi->device);
322         if (ret < 0) {
323                 printk(IBM_ERR "%s device not present\n", ibm->name);
324                 return -ENODEV;
325         }
326
327         acpi_driver_data(ibm->acpi->device) = ibm;
328         sprintf(acpi_device_class(ibm->acpi->device), "%s/%s",
329                 IBM_ACPI_EVENT_PREFIX,
330                 ibm->name);
331
332         status = acpi_install_notify_handler(*ibm->acpi->handle,
333                         ibm->acpi->type, dispatch_acpi_notify, ibm);
334         if (ACPI_FAILURE(status)) {
335                 if (status == AE_ALREADY_EXISTS) {
336                         printk(IBM_NOTICE "another device driver is already handling %s events\n",
337                                 ibm->name);
338                 } else {
339                         printk(IBM_ERR "acpi_install_notify_handler(%s) failed: %d\n",
340                                 ibm->name, status);
341                 }
342                 return -ENODEV;
343         }
344         ibm->flags.acpi_notify_installed = 1;
345         return 0;
346 }
347
348 static int __init tpacpi_device_add(struct acpi_device *device)
349 {
350         return 0;
351 }
352
353 static int __init register_tpacpi_subdriver(struct ibm_struct *ibm)
354 {
355         int ret;
356
357         dbg_printk(TPACPI_DBG_INIT,
358                 "registering %s as an ACPI driver\n", ibm->name);
359
360         BUG_ON(!ibm->acpi);
361
362         ibm->acpi->driver = kzalloc(sizeof(struct acpi_driver), GFP_KERNEL);
363         if (!ibm->acpi->driver) {
364                 printk(IBM_ERR "kzalloc(ibm->driver) failed\n");
365                 return -ENOMEM;
366         }
367
368         sprintf(ibm->acpi->driver->name, "%s_%s", IBM_NAME, ibm->name);
369         ibm->acpi->driver->ids = ibm->acpi->hid;
370         ibm->acpi->driver->ops.add = &tpacpi_device_add;
371
372         ret = acpi_bus_register_driver(ibm->acpi->driver);
373         if (ret < 0) {
374                 printk(IBM_ERR "acpi_bus_register_driver(%s) failed: %d\n",
375                        ibm->acpi->hid, ret);
376                 kfree(ibm->acpi->driver);
377                 ibm->acpi->driver = NULL;
378         } else if (!ret)
379                 ibm->flags.acpi_driver_registered = 1;
380
381         return ret;
382 }
383
384
385 /****************************************************************************
386  ****************************************************************************
387  *
388  * Procfs Helpers
389  *
390  ****************************************************************************
391  ****************************************************************************/
392
393 static int dispatch_procfs_read(char *page, char **start, off_t off,
394                         int count, int *eof, void *data)
395 {
396         struct ibm_struct *ibm = data;
397         int len;
398
399         if (!ibm || !ibm->read)
400                 return -EINVAL;
401
402         len = ibm->read(page);
403         if (len < 0)
404                 return len;
405
406         if (len <= off + count)
407                 *eof = 1;
408         *start = page + off;
409         len -= off;
410         if (len > count)
411                 len = count;
412         if (len < 0)
413                 len = 0;
414
415         return len;
416 }
417
418 static int dispatch_procfs_write(struct file *file,
419                         const char __user * userbuf,
420                         unsigned long count, void *data)
421 {
422         struct ibm_struct *ibm = data;
423         char *kernbuf;
424         int ret;
425
426         if (!ibm || !ibm->write)
427                 return -EINVAL;
428
429         kernbuf = kmalloc(count + 2, GFP_KERNEL);
430         if (!kernbuf)
431                 return -ENOMEM;
432
433         if (copy_from_user(kernbuf, userbuf, count)) {
434                 kfree(kernbuf);
435                 return -EFAULT;
436         }
437
438         kernbuf[count] = 0;
439         strcat(kernbuf, ",");
440         ret = ibm->write(kernbuf);
441         if (ret == 0)
442                 ret = count;
443
444         kfree(kernbuf);
445
446         return ret;
447 }
448
449 static char *next_cmd(char **cmds)
450 {
451         char *start = *cmds;
452         char *end;
453
454         while ((end = strchr(start, ',')) && end == start)
455                 start = end + 1;
456
457         if (!end)
458                 return NULL;
459
460         *end = 0;
461         *cmds = end + 1;
462         return start;
463 }
464
465
466 /****************************************************************************
467  ****************************************************************************
468  *
469  * Subdrivers
470  *
471  ****************************************************************************
472  ****************************************************************************/
473
474 /*************************************************************************
475  * thinkpad-acpi init subdriver
476  */
477
478 static int __init thinkpad_acpi_driver_init(struct ibm_init_struct *iibm)
479 {
480         printk(IBM_INFO "%s v%s\n", IBM_DESC, IBM_VERSION);
481         printk(IBM_INFO "%s\n", IBM_URL);
482
483         if (ibm_thinkpad_ec_found)
484                 printk(IBM_INFO "ThinkPad EC firmware %s\n",
485                        ibm_thinkpad_ec_found);
486
487         return 0;
488 }
489
490 static int thinkpad_acpi_driver_read(char *p)
491 {
492         int len = 0;
493
494         len += sprintf(p + len, "driver:\t\t%s\n", IBM_DESC);
495         len += sprintf(p + len, "version:\t%s\n", IBM_VERSION);
496
497         return len;
498 }
499
500 static struct ibm_struct thinkpad_acpi_driver_data = {
501         .name = "driver",
502         .read = thinkpad_acpi_driver_read,
503 };
504
505 /*************************************************************************
506  * Hotkey subdriver
507  */
508
509 static int hotkey_orig_status;
510 static int hotkey_orig_mask;
511
512 static int __init hotkey_init(struct ibm_init_struct *iibm)
513 {
514         int res;
515
516         vdbg_printk(TPACPI_DBG_INIT, "initializing hotkey subdriver\n");
517
518         IBM_ACPIHANDLE_INIT(hkey);
519
520         /* hotkey not supported on 570 */
521         tp_features.hotkey = hkey_handle != NULL;
522
523         vdbg_printk(TPACPI_DBG_INIT, "hotkeys are %s\n",
524                 str_supported(tp_features.hotkey));
525
526         if (tp_features.hotkey) {
527                 /* mask not supported on 570, 600e/x, 770e, 770x, A21e, A2xm/p,
528                    A30, R30, R31, T20-22, X20-21, X22-24 */
529                 tp_features.hotkey_mask =
530                         acpi_evalf(hkey_handle, NULL, "DHKN", "qv");
531
532                 vdbg_printk(TPACPI_DBG_INIT, "hotkey masks are %s\n",
533                         str_supported(tp_features.hotkey_mask));
534
535                 res = hotkey_get(&hotkey_orig_status, &hotkey_orig_mask);
536                 if (res)
537                         return res;
538         }
539
540         return (tp_features.hotkey)? 0 : 1;
541 }
542
543 static void hotkey_exit(void)
544 {
545         int res;
546
547         if (tp_features.hotkey) {
548                 dbg_printk(TPACPI_DBG_EXIT, "restoring original hotkey mask\n");
549                 res = hotkey_set(hotkey_orig_status, hotkey_orig_mask);
550                 if (res)
551                         printk(IBM_ERR "failed to restore hotkey to BIOS defaults\n");
552         }
553 }
554
555 static void hotkey_notify(struct ibm_struct *ibm, u32 event)
556 {
557         int hkey;
558
559         if (acpi_evalf(hkey_handle, &hkey, "MHKP", "d"))
560                 acpi_bus_generate_event(ibm->acpi->device, event, hkey);
561         else {
562                 printk(IBM_ERR "unknown hotkey event %d\n", event);
563                 acpi_bus_generate_event(ibm->acpi->device, event, 0);
564         }
565 }
566
567 static int hotkey_get(int *status, int *mask)
568 {
569         if (!acpi_evalf(hkey_handle, status, "DHKC", "d"))
570                 return -EIO;
571
572         if (tp_features.hotkey_mask)
573                 if (!acpi_evalf(hkey_handle, mask, "DHKN", "d"))
574                         return -EIO;
575
576         return 0;
577 }
578
579 static int hotkey_set(int status, int mask)
580 {
581         int i;
582
583         if (!acpi_evalf(hkey_handle, NULL, "MHKC", "vd", status))
584                 return -EIO;
585
586         if (tp_features.hotkey_mask)
587                 for (i = 0; i < 32; i++) {
588                         int bit = ((1 << i) & mask) != 0;
589                         if (!acpi_evalf(hkey_handle,
590                                         NULL, "MHKM", "vdd", i + 1, bit))
591                                 return -EIO;
592                 }
593
594         return 0;
595 }
596
597 static int hotkey_read(char *p)
598 {
599         int res, status, mask;
600         int len = 0;
601
602         if (!tp_features.hotkey) {
603                 len += sprintf(p + len, "status:\t\tnot supported\n");
604                 return len;
605         }
606
607         res = hotkey_get(&status, &mask);
608         if (res)
609                 return res;
610
611         len += sprintf(p + len, "status:\t\t%s\n", enabled(status, 0));
612         if (tp_features.hotkey_mask) {
613                 len += sprintf(p + len, "mask:\t\t0x%04x\n", mask);
614                 len += sprintf(p + len,
615                                "commands:\tenable, disable, reset, <mask>\n");
616         } else {
617                 len += sprintf(p + len, "mask:\t\tnot supported\n");
618                 len += sprintf(p + len, "commands:\tenable, disable, reset\n");
619         }
620
621         return len;
622 }
623
624 static int hotkey_write(char *buf)
625 {
626         int res, status, mask;
627         char *cmd;
628         int do_cmd = 0;
629
630         if (!tp_features.hotkey)
631                 return -ENODEV;
632
633         res = hotkey_get(&status, &mask);
634         if (res)
635                 return res;
636
637         while ((cmd = next_cmd(&buf))) {
638                 if (strlencmp(cmd, "enable") == 0) {
639                         status = 1;
640                 } else if (strlencmp(cmd, "disable") == 0) {
641                         status = 0;
642                 } else if (strlencmp(cmd, "reset") == 0) {
643                         status = hotkey_orig_status;
644                         mask = hotkey_orig_mask;
645                 } else if (sscanf(cmd, "0x%x", &mask) == 1) {
646                         /* mask set */
647                 } else if (sscanf(cmd, "%x", &mask) == 1) {
648                         /* mask set */
649                 } else
650                         return -EINVAL;
651                 do_cmd = 1;
652         }
653
654         if (do_cmd) {
655                 res = hotkey_set(status, mask);
656                 if (res)
657                         return res;
658         }
659
660         return 0;
661 }
662
663 static struct tp_acpi_drv_struct ibm_hotkey_acpidriver = {
664         .hid = IBM_HKEY_HID,
665         .notify = hotkey_notify,
666         .handle = &hkey_handle,
667         .type = ACPI_DEVICE_NOTIFY,
668 };
669
670 static struct ibm_struct hotkey_driver_data = {
671         .name = "hotkey",
672         .read = hotkey_read,
673         .write = hotkey_write,
674         .exit = hotkey_exit,
675         .acpi = &ibm_hotkey_acpidriver,
676 };
677
678 /*************************************************************************
679  * Bluetooth subdriver
680  */
681
682 static int __init bluetooth_init(struct ibm_init_struct *iibm)
683 {
684         vdbg_printk(TPACPI_DBG_INIT, "initializing bluetooth subdriver\n");
685
686         IBM_ACPIHANDLE_INIT(hkey);
687
688         /* bluetooth not supported on 570, 600e/x, 770e, 770x, A21e, A2xm/p,
689            G4x, R30, R31, R40e, R50e, T20-22, X20-21 */
690         tp_features.bluetooth = hkey_handle &&
691             acpi_evalf(hkey_handle, NULL, "GBDC", "qv");
692
693         vdbg_printk(TPACPI_DBG_INIT, "bluetooth is %s\n",
694                 str_supported(tp_features.bluetooth));
695
696         return (tp_features.bluetooth)? 0 : 1;
697 }
698
699 static int bluetooth_status(void)
700 {
701         int status;
702
703         if (!tp_features.bluetooth ||
704             !acpi_evalf(hkey_handle, &status, "GBDC", "d"))
705                 status = 0;
706
707         return status;
708 }
709
710 static int bluetooth_read(char *p)
711 {
712         int len = 0;
713         int status = bluetooth_status();
714
715         if (!tp_features.bluetooth)
716                 len += sprintf(p + len, "status:\t\tnot supported\n");
717         else if (!(status & 1))
718                 len += sprintf(p + len, "status:\t\tnot installed\n");
719         else {
720                 len += sprintf(p + len, "status:\t\t%s\n", enabled(status, 1));
721                 len += sprintf(p + len, "commands:\tenable, disable\n");
722         }
723
724         return len;
725 }
726
727 static int bluetooth_write(char *buf)
728 {
729         int status = bluetooth_status();
730         char *cmd;
731         int do_cmd = 0;
732
733         if (!tp_features.bluetooth)
734                 return -ENODEV;
735
736         while ((cmd = next_cmd(&buf))) {
737                 if (strlencmp(cmd, "enable") == 0) {
738                         status |= 2;
739                 } else if (strlencmp(cmd, "disable") == 0) {
740                         status &= ~2;
741                 } else
742                         return -EINVAL;
743                 do_cmd = 1;
744         }
745
746         if (do_cmd && !acpi_evalf(hkey_handle, NULL, "SBDC", "vd", status))
747                 return -EIO;
748
749         return 0;
750 }
751
752 static struct ibm_struct bluetooth_driver_data = {
753         .name = "bluetooth",
754         .read = bluetooth_read,
755         .write = bluetooth_write,
756 };
757
758 /*************************************************************************
759  * Wan subdriver
760  */
761
762 static int __init wan_init(struct ibm_init_struct *iibm)
763 {
764         vdbg_printk(TPACPI_DBG_INIT, "initializing wan subdriver\n");
765
766         IBM_ACPIHANDLE_INIT(hkey);
767
768         tp_features.wan = hkey_handle &&
769                           acpi_evalf(hkey_handle, NULL, "GWAN", "qv");
770
771         vdbg_printk(TPACPI_DBG_INIT, "wan is %s\n",
772                 str_supported(tp_features.wan));
773
774         return (tp_features.wan)? 0 : 1;
775 }
776
777 static int wan_status(void)
778 {
779         int status;
780
781         if (!tp_features.wan ||
782             !acpi_evalf(hkey_handle, &status, "GWAN", "d"))
783                 status = 0;
784
785         return status;
786 }
787
788 static int wan_read(char *p)
789 {
790         int len = 0;
791         int status = wan_status();
792
793         if (!tp_features.wan)
794                 len += sprintf(p + len, "status:\t\tnot supported\n");
795         else if (!(status & 1))
796                 len += sprintf(p + len, "status:\t\tnot installed\n");
797         else {
798                 len += sprintf(p + len, "status:\t\t%s\n", enabled(status, 1));
799                 len += sprintf(p + len, "commands:\tenable, disable\n");
800         }
801
802         return len;
803 }
804
805 static int wan_write(char *buf)
806 {
807         int status = wan_status();
808         char *cmd;
809         int do_cmd = 0;
810
811         if (!tp_features.wan)
812                 return -ENODEV;
813
814         while ((cmd = next_cmd(&buf))) {
815                 if (strlencmp(cmd, "enable") == 0) {
816                         status |= 2;
817                 } else if (strlencmp(cmd, "disable") == 0) {
818                         status &= ~2;
819                 } else
820                         return -EINVAL;
821                 do_cmd = 1;
822         }
823
824         if (do_cmd && !acpi_evalf(hkey_handle, NULL, "SWAN", "vd", status))
825                 return -EIO;
826
827         return 0;
828 }
829
830 static struct ibm_struct wan_driver_data = {
831         .name = "wan",
832         .read = wan_read,
833         .write = wan_write,
834         .flags.experimental = 1,
835 };
836
837 /*************************************************************************
838  * Video subdriver
839  */
840
841 static enum video_access_mode video_supported;
842 static int video_orig_autosw;
843
844 IBM_HANDLE(vid, root, "\\_SB.PCI.AGP.VGA",      /* 570 */
845            "\\_SB.PCI0.AGP0.VID0",      /* 600e/x, 770x */
846            "\\_SB.PCI0.VID0",   /* 770e */
847            "\\_SB.PCI0.VID",    /* A21e, G4x, R50e, X30, X40 */
848            "\\_SB.PCI0.AGP.VID",        /* all others */
849            );                           /* R30, R31 */
850
851 IBM_HANDLE(vid2, root, "\\_SB.PCI0.AGPB.VID");  /* G41 */
852
853 static int __init video_init(struct ibm_init_struct *iibm)
854 {
855         int ivga;
856
857         vdbg_printk(TPACPI_DBG_INIT, "initializing video subdriver\n");
858
859         IBM_ACPIHANDLE_INIT(vid);
860         IBM_ACPIHANDLE_INIT(vid2);
861
862         if (vid2_handle && acpi_evalf(NULL, &ivga, "\\IVGA", "d") && ivga)
863                 /* G41, assume IVGA doesn't change */
864                 vid_handle = vid2_handle;
865
866         if (!vid_handle)
867                 /* video switching not supported on R30, R31 */
868                 video_supported = TPACPI_VIDEO_NONE;
869         else if (acpi_evalf(vid_handle, &video_orig_autosw, "SWIT", "qd"))
870                 /* 570 */
871                 video_supported = TPACPI_VIDEO_570;
872         else if (acpi_evalf(vid_handle, &video_orig_autosw, "^VADL", "qd"))
873                 /* 600e/x, 770e, 770x */
874                 video_supported = TPACPI_VIDEO_770;
875         else
876                 /* all others */
877                 video_supported = TPACPI_VIDEO_NEW;
878
879         vdbg_printk(TPACPI_DBG_INIT, "video is %s, mode %d\n",
880                 str_supported(video_supported != TPACPI_VIDEO_NONE),
881                 video_supported);
882
883         return (video_supported != TPACPI_VIDEO_NONE)? 0 : 1;
884 }
885
886 static void video_exit(void)
887 {
888         dbg_printk(TPACPI_DBG_EXIT, "restoring original video autoswitch mode\n");
889         acpi_evalf(vid_handle, NULL, "_DOS", "vd", video_orig_autosw);
890 }
891
892 static int video_status(void)
893 {
894         int status = 0;
895         int i;
896
897         if (video_supported == TPACPI_VIDEO_570) {
898                 if (acpi_evalf(NULL, &i, "\\_SB.PHS", "dd", 0x87))
899                         status = i & 3;
900         } else if (video_supported == TPACPI_VIDEO_770) {
901                 if (acpi_evalf(NULL, &i, "\\VCDL", "d"))
902                         status |= 0x01 * i;
903                 if (acpi_evalf(NULL, &i, "\\VCDC", "d"))
904                         status |= 0x02 * i;
905         } else if (video_supported == TPACPI_VIDEO_NEW) {
906                 acpi_evalf(NULL, NULL, "\\VUPS", "vd", 1);
907                 if (acpi_evalf(NULL, &i, "\\VCDC", "d"))
908                         status |= 0x02 * i;
909
910                 acpi_evalf(NULL, NULL, "\\VUPS", "vd", 0);
911                 if (acpi_evalf(NULL, &i, "\\VCDL", "d"))
912                         status |= 0x01 * i;
913                 if (acpi_evalf(NULL, &i, "\\VCDD", "d"))
914                         status |= 0x08 * i;
915         }
916
917         return status;
918 }
919
920 static int video_autosw(void)
921 {
922         int autosw = 0;
923
924         if (video_supported == TPACPI_VIDEO_570)
925                 acpi_evalf(vid_handle, &autosw, "SWIT", "d");
926         else if (video_supported == TPACPI_VIDEO_770 ||
927                  video_supported == TPACPI_VIDEO_NEW)
928                 acpi_evalf(vid_handle, &autosw, "^VDEE", "d");
929
930         return autosw & 1;
931 }
932
933 static int video_switch(void)
934 {
935         int autosw = video_autosw();
936         int ret;
937
938         if (!acpi_evalf(vid_handle, NULL, "_DOS", "vd", 1))
939                 return -EIO;
940         ret = video_supported == TPACPI_VIDEO_570 ?
941             acpi_evalf(ec_handle, NULL, "_Q16", "v") :
942             acpi_evalf(vid_handle, NULL, "VSWT", "v");
943         acpi_evalf(vid_handle, NULL, "_DOS", "vd", autosw);
944
945         return ret;
946 }
947
948 static int video_expand(void)
949 {
950         if (video_supported == TPACPI_VIDEO_570)
951                 return acpi_evalf(ec_handle, NULL, "_Q17", "v");
952         else if (video_supported == TPACPI_VIDEO_770)
953                 return acpi_evalf(vid_handle, NULL, "VEXP", "v");
954         else
955                 return acpi_evalf(NULL, NULL, "\\VEXP", "v");
956 }
957
958 static int video_switch2(int status)
959 {
960         int ret;
961
962         if (video_supported == TPACPI_VIDEO_570) {
963                 ret = acpi_evalf(NULL, NULL,
964                                  "\\_SB.PHS2", "vdd", 0x8b, status | 0x80);
965         } else if (video_supported == TPACPI_VIDEO_770) {
966                 int autosw = video_autosw();
967                 if (!acpi_evalf(vid_handle, NULL, "_DOS", "vd", 1))
968                         return -EIO;
969
970                 ret = acpi_evalf(vid_handle, NULL,
971                                  "ASWT", "vdd", status * 0x100, 0);
972
973                 acpi_evalf(vid_handle, NULL, "_DOS", "vd", autosw);
974         } else {
975                 ret = acpi_evalf(NULL, NULL, "\\VUPS", "vd", 0x80) &&
976                     acpi_evalf(NULL, NULL, "\\VSDS", "vdd", status, 1);
977         }
978
979         return ret;
980 }
981
982 static int video_read(char *p)
983 {
984         int status = video_status();
985         int autosw = video_autosw();
986         int len = 0;
987
988         if (!video_supported) {
989                 len += sprintf(p + len, "status:\t\tnot supported\n");
990                 return len;
991         }
992
993         len += sprintf(p + len, "status:\t\tsupported\n");
994         len += sprintf(p + len, "lcd:\t\t%s\n", enabled(status, 0));
995         len += sprintf(p + len, "crt:\t\t%s\n", enabled(status, 1));
996         if (video_supported == TPACPI_VIDEO_NEW)
997                 len += sprintf(p + len, "dvi:\t\t%s\n", enabled(status, 3));
998         len += sprintf(p + len, "auto:\t\t%s\n", enabled(autosw, 0));
999         len += sprintf(p + len, "commands:\tlcd_enable, lcd_disable\n");
1000         len += sprintf(p + len, "commands:\tcrt_enable, crt_disable\n");
1001         if (video_supported == TPACPI_VIDEO_NEW)
1002                 len += sprintf(p + len, "commands:\tdvi_enable, dvi_disable\n");
1003         len += sprintf(p + len, "commands:\tauto_enable, auto_disable\n");
1004         len += sprintf(p + len, "commands:\tvideo_switch, expand_toggle\n");
1005
1006         return len;
1007 }
1008
1009 static int video_write(char *buf)
1010 {
1011         char *cmd;
1012         int enable, disable, status;
1013
1014         if (!video_supported)
1015                 return -ENODEV;
1016
1017         enable = disable = 0;
1018
1019         while ((cmd = next_cmd(&buf))) {
1020                 if (strlencmp(cmd, "lcd_enable") == 0) {
1021                         enable |= 0x01;
1022                 } else if (strlencmp(cmd, "lcd_disable") == 0) {
1023                         disable |= 0x01;
1024                 } else if (strlencmp(cmd, "crt_enable") == 0) {
1025                         enable |= 0x02;
1026                 } else if (strlencmp(cmd, "crt_disable") == 0) {
1027                         disable |= 0x02;
1028                 } else if (video_supported == TPACPI_VIDEO_NEW &&
1029                            strlencmp(cmd, "dvi_enable") == 0) {
1030                         enable |= 0x08;
1031                 } else if (video_supported == TPACPI_VIDEO_NEW &&
1032                            strlencmp(cmd, "dvi_disable") == 0) {
1033                         disable |= 0x08;
1034                 } else if (strlencmp(cmd, "auto_enable") == 0) {
1035                         if (!acpi_evalf(vid_handle, NULL, "_DOS", "vd", 1))
1036                                 return -EIO;
1037                 } else if (strlencmp(cmd, "auto_disable") == 0) {
1038                         if (!acpi_evalf(vid_handle, NULL, "_DOS", "vd", 0))
1039                                 return -EIO;
1040                 } else if (strlencmp(cmd, "video_switch") == 0) {
1041                         if (!video_switch())
1042                                 return -EIO;
1043                 } else if (strlencmp(cmd, "expand_toggle") == 0) {
1044                         if (!video_expand())
1045                                 return -EIO;
1046                 } else
1047                         return -EINVAL;
1048         }
1049
1050         if (enable || disable) {
1051                 status = (video_status() & 0x0f & ~disable) | enable;
1052                 if (!video_switch2(status))
1053                         return -EIO;
1054         }
1055
1056         return 0;
1057 }
1058
1059 static struct ibm_struct video_driver_data = {
1060         .name = "video",
1061         .read = video_read,
1062         .write = video_write,
1063         .exit = video_exit,
1064 };
1065
1066 /*************************************************************************
1067  * Light (thinklight) subdriver
1068  */
1069
1070 IBM_HANDLE(lght, root, "\\LGHT");       /* A21e, A2xm/p, T20-22, X20-21 */
1071 IBM_HANDLE(ledb, ec, "LEDB");           /* G4x */
1072
1073 static int __init light_init(struct ibm_init_struct *iibm)
1074 {
1075         vdbg_printk(TPACPI_DBG_INIT, "initializing light subdriver\n");
1076
1077         IBM_ACPIHANDLE_INIT(ledb);
1078         IBM_ACPIHANDLE_INIT(lght);
1079         IBM_ACPIHANDLE_INIT(cmos);
1080
1081         /* light not supported on 570, 600e/x, 770e, 770x, G4x, R30, R31 */
1082         tp_features.light = (cmos_handle || lght_handle) && !ledb_handle;
1083
1084         if (tp_features.light)
1085                 /* light status not supported on
1086                    570, 600e/x, 770e, 770x, G4x, R30, R31, R32, X20 */
1087                 tp_features.light_status =
1088                         acpi_evalf(ec_handle, NULL, "KBLT", "qv");
1089
1090         vdbg_printk(TPACPI_DBG_INIT, "light is %s\n",
1091                 str_supported(tp_features.light));
1092
1093         return (tp_features.light)? 0 : 1;
1094 }
1095
1096 static int light_read(char *p)
1097 {
1098         int len = 0;
1099         int status = 0;
1100
1101         if (!tp_features.light) {
1102                 len += sprintf(p + len, "status:\t\tnot supported\n");
1103         } else if (!tp_features.light_status) {
1104                 len += sprintf(p + len, "status:\t\tunknown\n");
1105                 len += sprintf(p + len, "commands:\ton, off\n");
1106         } else {
1107                 if (!acpi_evalf(ec_handle, &status, "KBLT", "d"))
1108                         return -EIO;
1109                 len += sprintf(p + len, "status:\t\t%s\n", onoff(status, 0));
1110                 len += sprintf(p + len, "commands:\ton, off\n");
1111         }
1112
1113         return len;
1114 }
1115
1116 static int light_write(char *buf)
1117 {
1118         int cmos_cmd, lght_cmd;
1119         char *cmd;
1120         int success;
1121
1122         if (!tp_features.light)
1123                 return -ENODEV;
1124
1125         while ((cmd = next_cmd(&buf))) {
1126                 if (strlencmp(cmd, "on") == 0) {
1127                         cmos_cmd = 0x0c;
1128                         lght_cmd = 1;
1129                 } else if (strlencmp(cmd, "off") == 0) {
1130                         cmos_cmd = 0x0d;
1131                         lght_cmd = 0;
1132                 } else
1133                         return -EINVAL;
1134
1135                 success = cmos_handle ?
1136                     acpi_evalf(cmos_handle, NULL, NULL, "vd", cmos_cmd) :
1137                     acpi_evalf(lght_handle, NULL, NULL, "vd", lght_cmd);
1138                 if (!success)
1139                         return -EIO;
1140         }
1141
1142         return 0;
1143 }
1144
1145 static struct ibm_struct light_driver_data = {
1146         .name = "light",
1147         .read = light_read,
1148         .write = light_write,
1149 };
1150
1151 /*************************************************************************
1152  * Dock subdriver
1153  */
1154
1155 #ifdef CONFIG_THINKPAD_ACPI_DOCK
1156
1157 IBM_HANDLE(dock, root, "\\_SB.GDCK",    /* X30, X31, X40 */
1158            "\\_SB.PCI0.DOCK",   /* 600e/x,770e,770x,A2xm/p,T20-22,X20-21 */
1159            "\\_SB.PCI0.PCI1.DOCK",      /* all others */
1160            "\\_SB.PCI.ISA.SLCE",        /* 570 */
1161     );                          /* A21e,G4x,R30,R31,R32,R40,R40e,R50e */
1162
1163 /* don't list other alternatives as we install a notify handler on the 570 */
1164 IBM_HANDLE(pci, root, "\\_SB.PCI");     /* 570 */
1165
1166 #define dock_docked() (_sta(dock_handle) & 1)
1167
1168 static int __init dock_init(struct ibm_init_struct *iibm)
1169 {
1170         vdbg_printk(TPACPI_DBG_INIT, "initializing dock subdriver\n");
1171
1172         IBM_ACPIHANDLE_INIT(dock);
1173         IBM_ACPIHANDLE_INIT(pci);
1174
1175         vdbg_printk(TPACPI_DBG_INIT, "dock is %s\n",
1176                 str_supported(dock_handle != NULL));
1177
1178         return (dock_handle)? 0 : 1;
1179 }
1180
1181 static void dock_notify(struct ibm_struct *ibm, u32 event)
1182 {
1183         int docked = dock_docked();
1184         int pci = ibm->acpi->hid && strstr(ibm->acpi->hid, IBM_PCI_HID);
1185
1186         if (event == 1 && !pci) /* 570 */
1187                 acpi_bus_generate_event(ibm->acpi->device, event, 1);   /* button */
1188         else if (event == 1 && pci)     /* 570 */
1189                 acpi_bus_generate_event(ibm->acpi->device, event, 3);   /* dock */
1190         else if (event == 3 && docked)
1191                 acpi_bus_generate_event(ibm->acpi->device, event, 1);   /* button */
1192         else if (event == 3 && !docked)
1193                 acpi_bus_generate_event(ibm->acpi->device, event, 2);   /* undock */
1194         else if (event == 0 && docked)
1195                 acpi_bus_generate_event(ibm->acpi->device, event, 3);   /* dock */
1196         else {
1197                 printk(IBM_ERR "unknown dock event %d, status %d\n",
1198                        event, _sta(dock_handle));
1199                 acpi_bus_generate_event(ibm->acpi->device, event, 0);   /* unknown */
1200         }
1201 }
1202
1203 static int dock_read(char *p)
1204 {
1205         int len = 0;
1206         int docked = dock_docked();
1207
1208         if (!dock_handle)
1209                 len += sprintf(p + len, "status:\t\tnot supported\n");
1210         else if (!docked)
1211                 len += sprintf(p + len, "status:\t\tundocked\n");
1212         else {
1213                 len += sprintf(p + len, "status:\t\tdocked\n");
1214                 len += sprintf(p + len, "commands:\tdock, undock\n");
1215         }
1216
1217         return len;
1218 }
1219
1220 static int dock_write(char *buf)
1221 {
1222         char *cmd;
1223
1224         if (!dock_docked())
1225                 return -ENODEV;
1226
1227         while ((cmd = next_cmd(&buf))) {
1228                 if (strlencmp(cmd, "undock") == 0) {
1229                         if (!acpi_evalf(dock_handle, NULL, "_DCK", "vd", 0) ||
1230                             !acpi_evalf(dock_handle, NULL, "_EJ0", "vd", 1))
1231                                 return -EIO;
1232                 } else if (strlencmp(cmd, "dock") == 0) {
1233                         if (!acpi_evalf(dock_handle, NULL, "_DCK", "vd", 1))
1234                                 return -EIO;
1235                 } else
1236                         return -EINVAL;
1237         }
1238
1239         return 0;
1240 }
1241
1242 static struct tp_acpi_drv_struct ibm_dock_acpidriver[2] = {
1243         {
1244          .notify = dock_notify,
1245          .handle = &dock_handle,
1246          .type = ACPI_SYSTEM_NOTIFY,
1247         },
1248         {
1249          .hid = IBM_PCI_HID,
1250          .notify = dock_notify,
1251          .handle = &pci_handle,
1252          .type = ACPI_SYSTEM_NOTIFY,
1253         },
1254 };
1255
1256 static struct ibm_struct dock_driver_data[2] = {
1257         {
1258          .name = "dock",
1259          .read = dock_read,
1260          .write = dock_write,
1261          .acpi = &ibm_dock_acpidriver[0],
1262         },
1263         {
1264          .name = "dock",
1265          .acpi = &ibm_dock_acpidriver[1],
1266         },
1267 };
1268
1269 #endif /* CONFIG_THINKPAD_ACPI_DOCK */
1270
1271 /*************************************************************************
1272  * Bay subdriver
1273  */
1274
1275 #ifdef CONFIG_THINKPAD_ACPI_BAY
1276 IBM_HANDLE(bay, root, "\\_SB.PCI.IDE.SECN.MAST",        /* 570 */
1277            "\\_SB.PCI0.IDE0.IDES.IDSM", /* 600e/x, 770e, 770x */
1278            "\\_SB.PCI0.SATA.SCND.MSTR", /* T60, X60, Z60 */
1279            "\\_SB.PCI0.IDE0.SCND.MSTR", /* all others */
1280            );                           /* A21e, R30, R31 */
1281 IBM_HANDLE(bay_ej, bay, "_EJ3", /* 600e/x, A2xm/p, A3x */
1282            "_EJ0",              /* all others */
1283            );                   /* 570,A21e,G4x,R30,R31,R32,R40e,R50e */
1284 IBM_HANDLE(bay2, root, "\\_SB.PCI0.IDE0.PRIM.SLAV",     /* A3x, R32 */
1285            "\\_SB.PCI0.IDE0.IDEP.IDPS", /* 600e/x, 770e, 770x */
1286            );                           /* all others */
1287 IBM_HANDLE(bay2_ej, bay2, "_EJ3",       /* 600e/x, 770e, A3x */
1288            "_EJ0",                      /* 770x */
1289            );                           /* all others */
1290
1291 static int __init bay_init(struct ibm_init_struct *iibm)
1292 {
1293         vdbg_printk(TPACPI_DBG_INIT, "initializing bay subdriver\n");
1294
1295         IBM_ACPIHANDLE_INIT(bay);
1296         if (bay_handle)
1297                 IBM_ACPIHANDLE_INIT(bay_ej);
1298         IBM_ACPIHANDLE_INIT(bay2);
1299         if (bay2_handle)
1300                 IBM_ACPIHANDLE_INIT(bay2_ej);
1301
1302         tp_features.bay_status = bay_handle &&
1303                 acpi_evalf(bay_handle, NULL, "_STA", "qv");
1304         tp_features.bay_status2 = bay2_handle &&
1305                 acpi_evalf(bay2_handle, NULL, "_STA", "qv");
1306
1307         tp_features.bay_eject = bay_handle && bay_ej_handle &&
1308                 (strlencmp(bay_ej_path, "_EJ0") == 0 || experimental);
1309         tp_features.bay_eject2 = bay2_handle && bay2_ej_handle &&
1310                 (strlencmp(bay2_ej_path, "_EJ0") == 0 || experimental);
1311
1312         vdbg_printk(TPACPI_DBG_INIT,
1313                 "bay 1: status %s, eject %s; bay 2: status %s, eject %s\n",
1314                 str_supported(tp_features.bay_status),
1315                 str_supported(tp_features.bay_eject),
1316                 str_supported(tp_features.bay_status2),
1317                 str_supported(tp_features.bay_eject2));
1318
1319         return (tp_features.bay_status || tp_features.bay_eject ||
1320                 tp_features.bay_status2 || tp_features.bay_eject2)? 0 : 1;
1321 }
1322
1323 static void bay_notify(struct ibm_struct *ibm, u32 event)
1324 {
1325         acpi_bus_generate_event(ibm->acpi->device, event, 0);
1326 }
1327
1328 #define bay_occupied(b) (_sta(b##_handle) & 1)
1329
1330 static int bay_read(char *p)
1331 {
1332         int len = 0;
1333         int occupied = bay_occupied(bay);
1334         int occupied2 = bay_occupied(bay2);
1335         int eject, eject2;
1336
1337         len += sprintf(p + len, "status:\t\t%s\n",
1338                 tp_features.bay_status ?
1339                         (occupied ? "occupied" : "unoccupied") :
1340                                 "not supported");
1341         if (tp_features.bay_status2)
1342                 len += sprintf(p + len, "status2:\t%s\n", occupied2 ?
1343                                "occupied" : "unoccupied");
1344
1345         eject = tp_features.bay_eject && occupied;
1346         eject2 = tp_features.bay_eject2 && occupied2;
1347
1348         if (eject && eject2)
1349                 len += sprintf(p + len, "commands:\teject, eject2\n");
1350         else if (eject)
1351                 len += sprintf(p + len, "commands:\teject\n");
1352         else if (eject2)
1353                 len += sprintf(p + len, "commands:\teject2\n");
1354
1355         return len;
1356 }
1357
1358 static int bay_write(char *buf)
1359 {
1360         char *cmd;
1361
1362         if (!tp_features.bay_eject && !tp_features.bay_eject2)
1363                 return -ENODEV;
1364
1365         while ((cmd = next_cmd(&buf))) {
1366                 if (tp_features.bay_eject && strlencmp(cmd, "eject") == 0) {
1367                         if (!acpi_evalf(bay_ej_handle, NULL, NULL, "vd", 1))
1368                                 return -EIO;
1369                 } else if (tp_features.bay_eject2 &&
1370                            strlencmp(cmd, "eject2") == 0) {
1371                         if (!acpi_evalf(bay2_ej_handle, NULL, NULL, "vd", 1))
1372                                 return -EIO;
1373                 } else
1374                         return -EINVAL;
1375         }
1376
1377         return 0;
1378 }
1379
1380 static struct tp_acpi_drv_struct ibm_bay_acpidriver = {
1381         .notify = bay_notify,
1382         .handle = &bay_handle,
1383         .type = ACPI_SYSTEM_NOTIFY,
1384 };
1385
1386 static struct ibm_struct bay_driver_data = {
1387         .name = "bay",
1388         .read = bay_read,
1389         .write = bay_write,
1390         .acpi = &ibm_bay_acpidriver,
1391 };
1392
1393 #endif /* CONFIG_THINKPAD_ACPI_BAY */
1394
1395 /*************************************************************************
1396  * CMOS subdriver
1397  */
1398
1399 static int __init cmos_init(struct ibm_init_struct *iibm)
1400 {
1401         vdbg_printk(TPACPI_DBG_INIT,
1402                 "initializing cmos commands subdriver\n");
1403
1404         IBM_ACPIHANDLE_INIT(cmos);
1405
1406         vdbg_printk(TPACPI_DBG_INIT, "cmos commands are %s\n",
1407                 str_supported(cmos_handle != NULL));
1408         return (cmos_handle)? 0 : 1;
1409 }
1410
1411 static int cmos_eval(int cmos_cmd)
1412 {
1413         if (cmos_handle)
1414                 return acpi_evalf(cmos_handle, NULL, NULL, "vd", cmos_cmd);
1415         else
1416                 return 1;
1417 }
1418
1419 static int cmos_read(char *p)
1420 {
1421         int len = 0;
1422
1423         /* cmos not supported on 570, 600e/x, 770e, 770x, A21e, A2xm/p,
1424            R30, R31, T20-22, X20-21 */
1425         if (!cmos_handle)
1426                 len += sprintf(p + len, "status:\t\tnot supported\n");
1427         else {
1428                 len += sprintf(p + len, "status:\t\tsupported\n");
1429                 len += sprintf(p + len, "commands:\t<cmd> (<cmd> is 0-21)\n");
1430         }
1431
1432         return len;
1433 }
1434
1435 static int cmos_write(char *buf)
1436 {
1437         char *cmd;
1438         int cmos_cmd;
1439
1440         if (!cmos_handle)
1441                 return -EINVAL;
1442
1443         while ((cmd = next_cmd(&buf))) {
1444                 if (sscanf(cmd, "%u", &cmos_cmd) == 1 &&
1445                     cmos_cmd >= 0 && cmos_cmd <= 21) {
1446                         /* cmos_cmd set */
1447                 } else
1448                         return -EINVAL;
1449
1450                 if (!cmos_eval(cmos_cmd))
1451                         return -EIO;
1452         }
1453
1454         return 0;
1455 }
1456
1457 static struct ibm_struct cmos_driver_data = {
1458         .name = "cmos",
1459         .read = cmos_read,
1460         .write = cmos_write,
1461 };
1462
1463 /*************************************************************************
1464  * LED subdriver
1465  */
1466
1467 static enum led_access_mode led_supported;
1468
1469 IBM_HANDLE(led, ec, "SLED",     /* 570 */
1470            "SYSL",              /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20-21 */
1471            "LED",               /* all others */
1472            );                   /* R30, R31 */
1473
1474 static int __init led_init(struct ibm_init_struct *iibm)
1475 {
1476         vdbg_printk(TPACPI_DBG_INIT, "initializing LED subdriver\n");
1477
1478         IBM_ACPIHANDLE_INIT(led);
1479
1480         if (!led_handle)
1481                 /* led not supported on R30, R31 */
1482                 led_supported = TPACPI_LED_NONE;
1483         else if (strlencmp(led_path, "SLED") == 0)
1484                 /* 570 */
1485                 led_supported = TPACPI_LED_570;
1486         else if (strlencmp(led_path, "SYSL") == 0)
1487                 /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20-21 */
1488                 led_supported = TPACPI_LED_OLD;
1489         else
1490                 /* all others */
1491                 led_supported = TPACPI_LED_NEW;
1492
1493         vdbg_printk(TPACPI_DBG_INIT, "LED commands are %s, mode %d\n",
1494                 str_supported(led_supported), led_supported);
1495
1496         return (led_supported != TPACPI_LED_NONE)? 0 : 1;
1497 }
1498
1499 #define led_status(s) ((s) == 0 ? "off" : ((s) == 1 ? "on" : "blinking"))
1500
1501 static int led_read(char *p)
1502 {
1503         int len = 0;
1504
1505         if (!led_supported) {
1506                 len += sprintf(p + len, "status:\t\tnot supported\n");
1507                 return len;
1508         }
1509         len += sprintf(p + len, "status:\t\tsupported\n");
1510
1511         if (led_supported == TPACPI_LED_570) {
1512                 /* 570 */
1513                 int i, status;
1514                 for (i = 0; i < 8; i++) {
1515                         if (!acpi_evalf(ec_handle,
1516                                         &status, "GLED", "dd", 1 << i))
1517                                 return -EIO;
1518                         len += sprintf(p + len, "%d:\t\t%s\n",
1519                                        i, led_status(status));
1520                 }
1521         }
1522
1523         len += sprintf(p + len, "commands:\t"
1524                        "<led> on, <led> off, <led> blink (<led> is 0-7)\n");
1525
1526         return len;
1527 }
1528
1529 /* off, on, blink */
1530 static const int led_sled_arg1[] = { 0, 1, 3 };
1531 static const int led_exp_hlbl[] = { 0, 0, 1 };  /* led# * */
1532 static const int led_exp_hlcl[] = { 0, 1, 1 };  /* led# * */
1533 static const int led_led_arg1[] = { 0, 0x80, 0xc0 };
1534
1535 static int led_write(char *buf)
1536 {
1537         char *cmd;
1538         int led, ind, ret;
1539
1540         if (!led_supported)
1541                 return -ENODEV;
1542
1543         while ((cmd = next_cmd(&buf))) {
1544                 if (sscanf(cmd, "%d", &led) != 1 || led < 0 || led > 7)
1545                         return -EINVAL;
1546
1547                 if (strstr(cmd, "off")) {
1548                         ind = 0;
1549                 } else if (strstr(cmd, "on")) {
1550                         ind = 1;
1551                 } else if (strstr(cmd, "blink")) {
1552                         ind = 2;
1553                 } else
1554                         return -EINVAL;
1555
1556                 if (led_supported == TPACPI_LED_570) {
1557                         /* 570 */
1558                         led = 1 << led;
1559                         if (!acpi_evalf(led_handle, NULL, NULL, "vdd",
1560                                         led, led_sled_arg1[ind]))
1561                                 return -EIO;
1562                 } else if (led_supported == TPACPI_LED_OLD) {
1563                         /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20 */
1564                         led = 1 << led;
1565                         ret = ec_write(TPACPI_LED_EC_HLMS, led);
1566                         if (ret >= 0)
1567                                 ret =
1568                                     ec_write(TPACPI_LED_EC_HLBL,
1569                                              led * led_exp_hlbl[ind]);
1570                         if (ret >= 0)
1571                                 ret =
1572                                     ec_write(TPACPI_LED_EC_HLCL,
1573                                              led * led_exp_hlcl[ind]);
1574                         if (ret < 0)
1575                                 return ret;
1576                 } else {
1577                         /* all others */
1578                         if (!acpi_evalf(led_handle, NULL, NULL, "vdd",
1579                                         led, led_led_arg1[ind]))
1580                                 return -EIO;
1581                 }
1582         }
1583
1584         return 0;
1585 }
1586
1587 static struct ibm_struct led_driver_data = {
1588         .name = "led",
1589         .read = led_read,
1590         .write = led_write,
1591 };
1592
1593 /*************************************************************************
1594  * Beep subdriver
1595  */
1596
1597 IBM_HANDLE(beep, ec, "BEEP");   /* all except R30, R31 */
1598
1599 static int __init beep_init(struct ibm_init_struct *iibm)
1600 {
1601         vdbg_printk(TPACPI_DBG_INIT, "initializing beep subdriver\n");
1602
1603         IBM_ACPIHANDLE_INIT(beep);
1604
1605         vdbg_printk(TPACPI_DBG_INIT, "beep is %s\n",
1606                 str_supported(beep_handle != NULL));
1607
1608         return (beep_handle)? 0 : 1;
1609 }
1610
1611 static int beep_read(char *p)
1612 {
1613         int len = 0;
1614
1615         if (!beep_handle)
1616                 len += sprintf(p + len, "status:\t\tnot supported\n");
1617         else {
1618                 len += sprintf(p + len, "status:\t\tsupported\n");
1619                 len += sprintf(p + len, "commands:\t<cmd> (<cmd> is 0-17)\n");
1620         }
1621
1622         return len;
1623 }
1624
1625 static int beep_write(char *buf)
1626 {
1627         char *cmd;
1628         int beep_cmd;
1629
1630         if (!beep_handle)
1631                 return -ENODEV;
1632
1633         while ((cmd = next_cmd(&buf))) {
1634                 if (sscanf(cmd, "%u", &beep_cmd) == 1 &&
1635                     beep_cmd >= 0 && beep_cmd <= 17) {
1636                         /* beep_cmd set */
1637                 } else
1638                         return -EINVAL;
1639                 if (!acpi_evalf(beep_handle, NULL, NULL, "vdd", beep_cmd, 0))
1640                         return -EIO;
1641         }
1642
1643         return 0;
1644 }
1645
1646 static struct ibm_struct beep_driver_data = {
1647         .name = "beep",
1648         .read = beep_read,
1649         .write = beep_write,
1650 };
1651
1652 /*************************************************************************
1653  * Thermal subdriver
1654  */
1655
1656 static enum thermal_access_mode thermal_read_mode;
1657
1658 static int __init thermal_init(struct ibm_init_struct *iibm)
1659 {
1660         u8 t, ta1, ta2;
1661         int i;
1662         int acpi_tmp7;
1663
1664         vdbg_printk(TPACPI_DBG_INIT, "initializing thermal subdriver\n");
1665
1666         acpi_tmp7 = acpi_evalf(ec_handle, NULL, "TMP7", "qv");
1667
1668         if (ibm_thinkpad_ec_found && experimental) {
1669                 /*
1670                  * Direct EC access mode: sensors at registers
1671                  * 0x78-0x7F, 0xC0-0xC7.  Registers return 0x00 for
1672                  * non-implemented, thermal sensors return 0x80 when
1673                  * not available
1674                  */
1675
1676                 ta1 = ta2 = 0;
1677                 for (i = 0; i < 8; i++) {
1678                         if (likely(acpi_ec_read(0x78 + i, &t))) {
1679                                 ta1 |= t;
1680                         } else {
1681                                 ta1 = 0;
1682                                 break;
1683                         }
1684                         if (likely(acpi_ec_read(0xC0 + i, &t))) {
1685                                 ta2 |= t;
1686                         } else {
1687                                 ta1 = 0;
1688                                 break;
1689                         }
1690                 }
1691                 if (ta1 == 0) {
1692                         /* This is sheer paranoia, but we handle it anyway */
1693                         if (acpi_tmp7) {
1694                                 printk(IBM_ERR
1695                                        "ThinkPad ACPI EC access misbehaving, "
1696                                        "falling back to ACPI TMPx access mode\n");
1697                                 thermal_read_mode = TPACPI_THERMAL_ACPI_TMP07;
1698                         } else {
1699                                 printk(IBM_ERR
1700                                        "ThinkPad ACPI EC access misbehaving, "
1701                                        "disabling thermal sensors access\n");
1702                                 thermal_read_mode = TPACPI_THERMAL_NONE;
1703                         }
1704                 } else {
1705                         thermal_read_mode =
1706                             (ta2 != 0) ?
1707                             TPACPI_THERMAL_TPEC_16 : TPACPI_THERMAL_TPEC_8;
1708                 }
1709         } else if (acpi_tmp7) {
1710                 if (acpi_evalf(ec_handle, NULL, "UPDT", "qv")) {
1711                         /* 600e/x, 770e, 770x */
1712                         thermal_read_mode = TPACPI_THERMAL_ACPI_UPDT;
1713                 } else {
1714                         /* Standard ACPI TMPx access, max 8 sensors */
1715                         thermal_read_mode = TPACPI_THERMAL_ACPI_TMP07;
1716                 }
1717         } else {
1718                 /* temperatures not supported on 570, G4x, R30, R31, R32 */
1719                 thermal_read_mode = TPACPI_THERMAL_NONE;
1720         }
1721
1722         vdbg_printk(TPACPI_DBG_INIT, "thermal is %s, mode %d\n",
1723                 str_supported(thermal_read_mode != TPACPI_THERMAL_NONE),
1724                 thermal_read_mode);
1725
1726         return (thermal_read_mode != TPACPI_THERMAL_NONE)? 0 : 1;
1727 }
1728
1729 static int thermal_get_sensors(struct ibm_thermal_sensors_struct *s)
1730 {
1731         int i, t;
1732         s8 tmp;
1733         char tmpi[] = "TMPi";
1734
1735         if (!s)
1736                 return -EINVAL;
1737
1738         switch (thermal_read_mode) {
1739 #if TPACPI_MAX_THERMAL_SENSORS >= 16
1740         case TPACPI_THERMAL_TPEC_16:
1741                 for (i = 0; i < 8; i++) {
1742                         if (!acpi_ec_read(0xC0 + i, &tmp))
1743                                 return -EIO;
1744                         s->temp[i + 8] = tmp * 1000;
1745                 }
1746                 /* fallthrough */
1747 #endif
1748         case TPACPI_THERMAL_TPEC_8:
1749                 for (i = 0; i < 8; i++) {
1750                         if (!acpi_ec_read(0x78 + i, &tmp))
1751                                 return -EIO;
1752                         s->temp[i] = tmp * 1000;
1753                 }
1754                 return (thermal_read_mode == TPACPI_THERMAL_TPEC_16) ? 16 : 8;
1755
1756         case TPACPI_THERMAL_ACPI_UPDT:
1757                 if (!acpi_evalf(ec_handle, NULL, "UPDT", "v"))
1758                         return -EIO;
1759                 for (i = 0; i < 8; i++) {
1760                         tmpi[3] = '0' + i;
1761                         if (!acpi_evalf(ec_handle, &t, tmpi, "d"))
1762                                 return -EIO;
1763                         s->temp[i] = (t - 2732) * 100;
1764                 }
1765                 return 8;
1766
1767         case TPACPI_THERMAL_ACPI_TMP07:
1768                 for (i = 0; i < 8; i++) {
1769                         tmpi[3] = '0' + i;
1770                         if (!acpi_evalf(ec_handle, &t, tmpi, "d"))
1771                                 return -EIO;
1772                         s->temp[i] = t * 1000;
1773                 }
1774                 return 8;
1775
1776         case TPACPI_THERMAL_NONE:
1777         default:
1778                 return 0;
1779         }
1780 }
1781
1782 static int thermal_read(char *p)
1783 {
1784         int len = 0;
1785         int n, i;
1786         struct ibm_thermal_sensors_struct t;
1787
1788         n = thermal_get_sensors(&t);
1789         if (unlikely(n < 0))
1790                 return n;
1791
1792         len += sprintf(p + len, "temperatures:\t");
1793
1794         if (n > 0) {
1795                 for (i = 0; i < (n - 1); i++)
1796                         len += sprintf(p + len, "%d ", t.temp[i] / 1000);
1797                 len += sprintf(p + len, "%d\n", t.temp[i] / 1000);
1798         } else
1799                 len += sprintf(p + len, "not supported\n");
1800
1801         return len;
1802 }
1803
1804 static struct ibm_struct thermal_driver_data = {
1805         .name = "thermal",
1806         .read = thermal_read,
1807 };
1808
1809 /*************************************************************************
1810  * EC Dump subdriver
1811  */
1812
1813 static u8 ecdump_regs[256];
1814
1815 static int ecdump_read(char *p)
1816 {
1817         int len = 0;
1818         int i, j;
1819         u8 v;
1820
1821         len += sprintf(p + len, "EC      "
1822                        " +00 +01 +02 +03 +04 +05 +06 +07"
1823                        " +08 +09 +0a +0b +0c +0d +0e +0f\n");
1824         for (i = 0; i < 256; i += 16) {
1825                 len += sprintf(p + len, "EC 0x%02x:", i);
1826                 for (j = 0; j < 16; j++) {
1827                         if (!acpi_ec_read(i + j, &v))
1828                                 break;
1829                         if (v != ecdump_regs[i + j])
1830                                 len += sprintf(p + len, " *%02x", v);
1831                         else
1832                                 len += sprintf(p + len, "  %02x", v);
1833                         ecdump_regs[i + j] = v;
1834                 }
1835                 len += sprintf(p + len, "\n");
1836                 if (j != 16)
1837                         break;
1838         }
1839
1840         /* These are way too dangerous to advertise openly... */
1841 #if 0
1842         len += sprintf(p + len, "commands:\t0x<offset> 0x<value>"
1843                        " (<offset> is 00-ff, <value> is 00-ff)\n");
1844         len += sprintf(p + len, "commands:\t0x<offset> <value>  "
1845                        " (<offset> is 00-ff, <value> is 0-255)\n");
1846 #endif
1847         return len;
1848 }
1849
1850 static int ecdump_write(char *buf)
1851 {
1852         char *cmd;
1853         int i, v;
1854
1855         while ((cmd = next_cmd(&buf))) {
1856                 if (sscanf(cmd, "0x%x 0x%x", &i, &v) == 2) {
1857                         /* i and v set */
1858                 } else if (sscanf(cmd, "0x%x %u", &i, &v) == 2) {
1859                         /* i and v set */
1860                 } else
1861                         return -EINVAL;
1862                 if (i >= 0 && i < 256 && v >= 0 && v < 256) {
1863                         if (!acpi_ec_write(i, v))
1864                                 return -EIO;
1865                 } else
1866                         return -EINVAL;
1867         }
1868
1869         return 0;
1870 }
1871
1872 static struct ibm_struct ecdump_driver_data = {
1873         .name = "ecdump",
1874         .read = ecdump_read,
1875         .write = ecdump_write,
1876         .flags.experimental = 1,
1877 };
1878
1879 /*************************************************************************
1880  * Backlight/brightness subdriver
1881  */
1882
1883 static struct backlight_device *ibm_backlight_device = NULL;
1884
1885 static struct backlight_ops ibm_backlight_data = {
1886         .get_brightness = brightness_get,
1887         .update_status  = brightness_update_status,
1888 };
1889
1890 static int __init brightness_init(struct ibm_init_struct *iibm)
1891 {
1892         int b;
1893
1894         vdbg_printk(TPACPI_DBG_INIT, "initializing brightness subdriver\n");
1895
1896         b = brightness_get(NULL);
1897         if (b < 0)
1898                 return b;
1899
1900         ibm_backlight_device = backlight_device_register("ibm", NULL, NULL,
1901                                                          &ibm_backlight_data);
1902         if (IS_ERR(ibm_backlight_device)) {
1903                 printk(IBM_ERR "Could not register backlight device\n");
1904                 return PTR_ERR(ibm_backlight_device);
1905         }
1906         vdbg_printk(TPACPI_DBG_INIT, "brightness is supported\n");
1907
1908         ibm_backlight_device->props.max_brightness = 7;
1909         ibm_backlight_device->props.brightness = b;
1910         backlight_update_status(ibm_backlight_device);
1911
1912         return 0;
1913 }
1914
1915 static void brightness_exit(void)
1916 {
1917         if (ibm_backlight_device) {
1918                 vdbg_printk(TPACPI_DBG_EXIT,
1919                             "calling backlight_device_unregister()\n");
1920                 backlight_device_unregister(ibm_backlight_device);
1921                 ibm_backlight_device = NULL;
1922         }
1923 }
1924
1925 static int brightness_update_status(struct backlight_device *bd)
1926 {
1927         return brightness_set(
1928                 (bd->props.fb_blank == FB_BLANK_UNBLANK &&
1929                  bd->props.power == FB_BLANK_UNBLANK) ?
1930                                 bd->props.brightness : 0);
1931 }
1932
1933 static int brightness_get(struct backlight_device *bd)
1934 {
1935         u8 level;
1936         if (!acpi_ec_read(brightness_offset, &level))
1937                 return -EIO;
1938
1939         level &= 0x7;
1940
1941         return level;
1942 }
1943
1944 static int brightness_set(int value)
1945 {
1946         int cmos_cmd, inc, i;
1947         int current_value = brightness_get(NULL);
1948
1949         value &= 7;
1950
1951         cmos_cmd = value > current_value ? TP_CMOS_BRIGHTNESS_UP : TP_CMOS_BRIGHTNESS_DOWN;
1952         inc = value > current_value ? 1 : -1;
1953         for (i = current_value; i != value; i += inc) {
1954                 if (!cmos_eval(cmos_cmd))
1955                         return -EIO;
1956                 if (!acpi_ec_write(brightness_offset, i + inc))
1957                         return -EIO;
1958         }
1959
1960         return 0;
1961 }
1962
1963 static int brightness_read(char *p)
1964 {
1965         int len = 0;
1966         int level;
1967
1968         if ((level = brightness_get(NULL)) < 0) {
1969                 len += sprintf(p + len, "level:\t\tunreadable\n");
1970         } else {
1971                 len += sprintf(p + len, "level:\t\t%d\n", level & 0x7);
1972                 len += sprintf(p + len, "commands:\tup, down\n");
1973                 len += sprintf(p + len, "commands:\tlevel <level>"
1974                                " (<level> is 0-7)\n");
1975         }
1976
1977         return len;
1978 }
1979
1980 static int brightness_write(char *buf)
1981 {
1982         int level;
1983         int new_level;
1984         char *cmd;
1985
1986         while ((cmd = next_cmd(&buf))) {
1987                 if ((level = brightness_get(NULL)) < 0)
1988                         return level;
1989                 level &= 7;
1990
1991                 if (strlencmp(cmd, "up") == 0) {
1992                         new_level = level == 7 ? 7 : level + 1;
1993                 } else if (strlencmp(cmd, "down") == 0) {
1994                         new_level = level == 0 ? 0 : level - 1;
1995                 } else if (sscanf(cmd, "level %d", &new_level) == 1 &&
1996                            new_level >= 0 && new_level <= 7) {
1997                         /* new_level set */
1998                 } else
1999                         return -EINVAL;
2000
2001                 brightness_set(new_level);
2002         }
2003
2004         return 0;
2005 }
2006
2007 static struct ibm_struct brightness_driver_data = {
2008         .name = "brightness",
2009         .read = brightness_read,
2010         .write = brightness_write,
2011         .exit = brightness_exit,
2012 };
2013
2014 /*************************************************************************
2015  * Volume subdriver
2016  */
2017
2018 static int volume_read(char *p)
2019 {
2020         int len = 0;
2021         u8 level;
2022
2023         if (!acpi_ec_read(volume_offset, &level)) {
2024                 len += sprintf(p + len, "level:\t\tunreadable\n");
2025         } else {
2026                 len += sprintf(p + len, "level:\t\t%d\n", level & 0xf);
2027                 len += sprintf(p + len, "mute:\t\t%s\n", onoff(level, 6));
2028                 len += sprintf(p + len, "commands:\tup, down, mute\n");
2029                 len += sprintf(p + len, "commands:\tlevel <level>"
2030                                " (<level> is 0-15)\n");
2031         }
2032
2033         return len;
2034 }
2035
2036 static int volume_write(char *buf)
2037 {
2038         int cmos_cmd, inc, i;
2039         u8 level, mute;
2040         int new_level, new_mute;
2041         char *cmd;
2042
2043         while ((cmd = next_cmd(&buf))) {
2044                 if (!acpi_ec_read(volume_offset, &level))
2045                         return -EIO;
2046                 new_mute = mute = level & 0x40;
2047                 new_level = level = level & 0xf;
2048
2049                 if (strlencmp(cmd, "up") == 0) {
2050                         if (mute)
2051                                 new_mute = 0;
2052                         else
2053                                 new_level = level == 15 ? 15 : level + 1;
2054                 } else if (strlencmp(cmd, "down") == 0) {
2055                         if (mute)
2056                                 new_mute = 0;
2057                         else
2058                                 new_level = level == 0 ? 0 : level - 1;
2059                 } else if (sscanf(cmd, "level %d", &new_level) == 1 &&
2060                            new_level >= 0 && new_level <= 15) {
2061                         /* new_level set */
2062                 } else if (strlencmp(cmd, "mute") == 0) {
2063                         new_mute = 0x40;
2064                 } else
2065                         return -EINVAL;
2066
2067                 if (new_level != level) {       /* mute doesn't change */
2068                         cmos_cmd = new_level > level ? TP_CMOS_VOLUME_UP : TP_CMOS_VOLUME_DOWN;
2069                         inc = new_level > level ? 1 : -1;
2070
2071                         if (mute && (!cmos_eval(cmos_cmd) ||
2072                                      !acpi_ec_write(volume_offset, level)))
2073                                 return -EIO;
2074
2075                         for (i = level; i != new_level; i += inc)
2076                                 if (!cmos_eval(cmos_cmd) ||
2077                                     !acpi_ec_write(volume_offset, i + inc))
2078                                         return -EIO;
2079
2080                         if (mute && (!cmos_eval(TP_CMOS_VOLUME_MUTE) ||
2081                                      !acpi_ec_write(volume_offset,
2082                                                     new_level + mute)))
2083                                 return -EIO;
2084                 }
2085
2086                 if (new_mute != mute) { /* level doesn't change */
2087                         cmos_cmd = new_mute ? TP_CMOS_VOLUME_MUTE : TP_CMOS_VOLUME_UP;
2088
2089                         if (!cmos_eval(cmos_cmd) ||
2090                             !acpi_ec_write(volume_offset, level + new_mute))
2091                                 return -EIO;
2092                 }
2093         }
2094
2095         return 0;
2096 }
2097
2098 static struct ibm_struct volume_driver_data = {
2099         .name = "volume",
2100         .read = volume_read,
2101         .write = volume_write,
2102 };
2103
2104 /*************************************************************************
2105  * Fan subdriver
2106  */
2107
2108 /*
2109  * FAN ACCESS MODES
2110  *
2111  * TPACPI_FAN_RD_ACPI_GFAN:
2112  *      ACPI GFAN method: returns fan level
2113  *
2114  *      see TPACPI_FAN_WR_ACPI_SFAN
2115  *      EC 0x2f (HFSP) not available if GFAN exists
2116  *
2117  * TPACPI_FAN_WR_ACPI_SFAN:
2118  *      ACPI SFAN method: sets fan level, 0 (stop) to 7 (max)
2119  *
2120  *      EC 0x2f (HFSP) might be available *for reading*, but do not use
2121  *      it for writing.
2122  *
2123  * TPACPI_FAN_WR_TPEC:
2124  *      ThinkPad EC register 0x2f (HFSP): fan control loop mode
2125  *      Supported on almost all ThinkPads
2126  *
2127  *      Fan speed changes of any sort (including those caused by the
2128  *      disengaged mode) are usually done slowly by the firmware as the
2129  *      maximum ammount of fan duty cycle change per second seems to be
2130  *      limited.
2131  *
2132  *      Reading is not available if GFAN exists.
2133  *      Writing is not available if SFAN exists.
2134  *
2135  *      Bits
2136  *       7      automatic mode engaged;
2137  *              (default operation mode of the ThinkPad)
2138  *              fan level is ignored in this mode.
2139  *       6      full speed mode (takes precedence over bit 7);
2140  *              not available on all thinkpads.  May disable
2141  *              the tachometer while the fan controller ramps up
2142  *              the speed (which can take up to a few *minutes*).
2143  *              Speeds up fan to 100% duty-cycle, which is far above
2144  *              the standard RPM levels.  It is not impossible that
2145  *              it could cause hardware damage.
2146  *      5-3     unused in some models.  Extra bits for fan level
2147  *              in others, but still useless as all values above
2148  *              7 map to the same speed as level 7 in these models.
2149  *      2-0     fan level (0..7 usually)
2150  *                      0x00 = stop
2151  *                      0x07 = max (set when temperatures critical)
2152  *              Some ThinkPads may have other levels, see
2153  *              TPACPI_FAN_WR_ACPI_FANS (X31/X40/X41)
2154  *
2155  *      FIRMWARE BUG: on some models, EC 0x2f might not be initialized at
2156  *      boot. Apparently the EC does not intialize it, so unless ACPI DSDT
2157  *      does so, its initial value is meaningless (0x07).
2158  *
2159  *      For firmware bugs, refer to:
2160  *      http://thinkwiki.org/wiki/Embedded_Controller_Firmware#Firmware_Issues
2161  *
2162  *      ----
2163  *
2164  *      ThinkPad EC register 0x84 (LSB), 0x85 (MSB):
2165  *      Main fan tachometer reading (in RPM)
2166  *
2167  *      This register is present on all ThinkPads with a new-style EC, and
2168  *      it is known not to be present on the A21m/e, and T22, as there is
2169  *      something else in offset 0x84 according to the ACPI DSDT.  Other
2170  *      ThinkPads from this same time period (and earlier) probably lack the
2171  *      tachometer as well.
2172  *
2173  *      Unfortunately a lot of ThinkPads with new-style ECs but whose firwmare
2174  *      was never fixed by IBM to report the EC firmware version string
2175  *      probably support the tachometer (like the early X models), so
2176  *      detecting it is quite hard.  We need more data to know for sure.
2177  *
2178  *      FIRMWARE BUG: always read 0x84 first, otherwise incorrect readings
2179  *      might result.
2180  *
2181  *      FIRMWARE BUG: may go stale while the EC is switching to full speed
2182  *      mode.
2183  *
2184  *      For firmware bugs, refer to:
2185  *      http://thinkwiki.org/wiki/Embedded_Controller_Firmware#Firmware_Issues
2186  *
2187  * TPACPI_FAN_WR_ACPI_FANS:
2188  *      ThinkPad X31, X40, X41.  Not available in the X60.
2189  *
2190  *      FANS ACPI handle: takes three arguments: low speed, medium speed,
2191  *      high speed.  ACPI DSDT seems to map these three speeds to levels
2192  *      as follows: STOP LOW LOW MED MED HIGH HIGH HIGH HIGH
2193  *      (this map is stored on FAN0..FAN8 as "0,1,1,2,2,3,3,3,3")
2194  *
2195  *      The speeds are stored on handles
2196  *      (FANA:FAN9), (FANC:FANB), (FANE:FAND).
2197  *
2198  *      There are three default speed sets, acessible as handles:
2199  *      FS1L,FS1M,FS1H; FS2L,FS2M,FS2H; FS3L,FS3M,FS3H
2200  *
2201  *      ACPI DSDT switches which set is in use depending on various
2202  *      factors.
2203  *
2204  *      TPACPI_FAN_WR_TPEC is also available and should be used to
2205  *      command the fan.  The X31/X40/X41 seems to have 8 fan levels,
2206  *      but the ACPI tables just mention level 7.
2207  */
2208
2209 static enum fan_status_access_mode fan_status_access_mode;
2210 static enum fan_control_access_mode fan_control_access_mode;
2211 static enum fan_control_commands fan_control_commands;
2212
2213 static u8 fan_control_initial_status;
2214
2215 static void fan_watchdog_fire(struct work_struct *ignored);
2216 static int fan_watchdog_maxinterval;
2217 static DECLARE_DELAYED_WORK(fan_watchdog_task, fan_watchdog_fire);
2218
2219 IBM_HANDLE(fans, ec, "FANS");   /* X31, X40, X41 */
2220 IBM_HANDLE(gfan, ec, "GFAN",    /* 570 */
2221            "\\FSPD",            /* 600e/x, 770e, 770x */
2222            );                   /* all others */
2223 IBM_HANDLE(sfan, ec, "SFAN",    /* 570 */
2224            "JFNS",              /* 770x-JL */
2225            );                   /* all others */
2226
2227 static int __init fan_init(struct ibm_init_struct *iibm)
2228 {
2229         vdbg_printk(TPACPI_DBG_INIT, "initializing fan subdriver\n");
2230
2231         fan_status_access_mode = TPACPI_FAN_NONE;
2232         fan_control_access_mode = TPACPI_FAN_WR_NONE;
2233         fan_control_commands = 0;
2234         fan_watchdog_maxinterval = 0;
2235         tp_features.fan_ctrl_status_undef = 0;
2236
2237         IBM_ACPIHANDLE_INIT(fans);
2238         IBM_ACPIHANDLE_INIT(gfan);
2239         IBM_ACPIHANDLE_INIT(sfan);
2240
2241         if (gfan_handle) {
2242                 /* 570, 600e/x, 770e, 770x */
2243                 fan_status_access_mode = TPACPI_FAN_RD_ACPI_GFAN;
2244         } else {
2245                 /* all other ThinkPads: note that even old-style
2246                  * ThinkPad ECs supports the fan control register */
2247                 if (likely(acpi_ec_read(fan_status_offset,
2248                                         &fan_control_initial_status))) {
2249                         fan_status_access_mode = TPACPI_FAN_RD_TPEC;
2250
2251                         /* In some ThinkPads, neither the EC nor the ACPI
2252                          * DSDT initialize the fan status, and it ends up
2253                          * being set to 0x07 when it *could* be either
2254                          * 0x07 or 0x80.
2255                          *
2256                          * Enable for TP-1Y (T43), TP-78 (R51e),
2257                          * TP-76 (R52), TP-70 (T43, R52), which are known
2258                          * to be buggy. */
2259                         if (fan_control_initial_status == 0x07 &&
2260                             ibm_thinkpad_ec_found &&
2261                             ((ibm_thinkpad_ec_found[0] == '1' &&
2262                               ibm_thinkpad_ec_found[1] == 'Y') ||
2263                              (ibm_thinkpad_ec_found[0] == '7' &&
2264                               (ibm_thinkpad_ec_found[1] == '6' ||
2265                                ibm_thinkpad_ec_found[1] == '8' ||
2266                                ibm_thinkpad_ec_found[1] == '0'))
2267                             )) {
2268                                 printk(IBM_NOTICE
2269                                        "fan_init: initial fan status is "
2270                                        "unknown, assuming it is in auto "
2271                                        "mode\n");
2272                                 tp_features.fan_ctrl_status_undef = 1;
2273                         }
2274                 } else {
2275                         printk(IBM_ERR
2276                                "ThinkPad ACPI EC access misbehaving, "
2277                                "fan status and control unavailable\n");
2278                         return 1;
2279                 }
2280         }
2281
2282         if (sfan_handle) {
2283                 /* 570, 770x-JL */
2284                 fan_control_access_mode = TPACPI_FAN_WR_ACPI_SFAN;
2285                 fan_control_commands |=
2286                     TPACPI_FAN_CMD_LEVEL | TPACPI_FAN_CMD_ENABLE;
2287         } else {
2288                 if (!gfan_handle) {
2289                         /* gfan without sfan means no fan control */
2290                         /* all other models implement TP EC 0x2f control */
2291
2292                         if (fans_handle) {
2293                                 /* X31, X40, X41 */
2294                                 fan_control_access_mode =
2295                                     TPACPI_FAN_WR_ACPI_FANS;
2296                                 fan_control_commands |=
2297                                     TPACPI_FAN_CMD_SPEED |
2298                                     TPACPI_FAN_CMD_LEVEL |
2299                                     TPACPI_FAN_CMD_ENABLE;
2300                         } else {
2301                                 fan_control_access_mode = TPACPI_FAN_WR_TPEC;
2302                                 fan_control_commands |=
2303                                     TPACPI_FAN_CMD_LEVEL |
2304                                     TPACPI_FAN_CMD_ENABLE;
2305                         }
2306                 }
2307         }
2308
2309         vdbg_printk(TPACPI_DBG_INIT, "fan is %s, modes %d, %d\n",
2310                 str_supported(fan_status_access_mode != TPACPI_FAN_NONE ||
2311                   fan_control_access_mode != TPACPI_FAN_WR_NONE),
2312                 fan_status_access_mode, fan_control_access_mode);
2313
2314         return (fan_status_access_mode != TPACPI_FAN_NONE ||
2315                 fan_control_access_mode != TPACPI_FAN_WR_NONE)?
2316                         0 : 1;
2317 }
2318
2319 static int fan_get_status(u8 *status)
2320 {
2321         u8 s;
2322
2323         /* TODO:
2324          * Add TPACPI_FAN_RD_ACPI_FANS ? */
2325
2326         switch (fan_status_access_mode) {
2327         case TPACPI_FAN_RD_ACPI_GFAN:
2328                 /* 570, 600e/x, 770e, 770x */
2329
2330                 if (unlikely(!acpi_evalf(gfan_handle, &s, NULL, "d")))
2331                         return -EIO;
2332
2333                 if (likely(status))
2334                         *status = s & 0x07;
2335
2336                 break;
2337
2338         case TPACPI_FAN_RD_TPEC:
2339                 /* all except 570, 600e/x, 770e, 770x */
2340                 if (unlikely(!acpi_ec_read(fan_status_offset, &s)))
2341                         return -EIO;
2342
2343                 if (likely(status))
2344                         *status = s;
2345
2346                 break;
2347
2348         default:
2349                 return -ENXIO;
2350         }
2351
2352         return 0;
2353 }
2354
2355 static void fan_exit(void)
2356 {
2357         vdbg_printk(TPACPI_DBG_EXIT, "cancelling any pending watchdogs\n");
2358         cancel_delayed_work(&fan_watchdog_task);
2359         flush_scheduled_work();
2360 }
2361
2362 static int fan_get_speed(unsigned int *speed)
2363 {
2364         u8 hi, lo;
2365
2366         switch (fan_status_access_mode) {
2367         case TPACPI_FAN_RD_TPEC:
2368                 /* all except 570, 600e/x, 770e, 770x */
2369                 if (unlikely(!acpi_ec_read(fan_rpm_offset, &lo) ||
2370                              !acpi_ec_read(fan_rpm_offset + 1, &hi)))
2371                         return -EIO;
2372
2373                 if (likely(speed))
2374                         *speed = (hi << 8) | lo;
2375
2376                 break;
2377
2378         default:
2379                 return -ENXIO;
2380         }
2381
2382         return 0;
2383 }
2384
2385 static void fan_watchdog_fire(struct work_struct *ignored)
2386 {
2387         printk(IBM_NOTICE "fan watchdog: enabling fan\n");
2388         if (fan_set_enable()) {
2389                 printk(IBM_ERR "fan watchdog: error while enabling fan\n");
2390                 /* reschedule for later */
2391                 fan_watchdog_reset();
2392         }
2393 }
2394
2395 static void fan_watchdog_reset(void)
2396 {
2397         static int fan_watchdog_active = 0;
2398
2399         if (fan_watchdog_active)
2400                 cancel_delayed_work(&fan_watchdog_task);
2401
2402         if (fan_watchdog_maxinterval > 0) {
2403                 fan_watchdog_active = 1;
2404                 if (!schedule_delayed_work(&fan_watchdog_task,
2405                                 msecs_to_jiffies(fan_watchdog_maxinterval
2406                                                  * 1000))) {
2407                         printk(IBM_ERR "failed to schedule the fan watchdog, "
2408                                "watchdog will not trigger\n");
2409                 }
2410         } else
2411                 fan_watchdog_active = 0;
2412 }
2413
2414 static int fan_set_level(int level)
2415 {
2416         switch (fan_control_access_mode) {
2417         case TPACPI_FAN_WR_ACPI_SFAN:
2418                 if (level >= 0 && level <= 7) {
2419                         if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", level))
2420                                 return -EIO;
2421                 } else
2422                         return -EINVAL;
2423                 break;
2424
2425         case TPACPI_FAN_WR_ACPI_FANS:
2426         case TPACPI_FAN_WR_TPEC:
2427                 if ((level != TP_EC_FAN_AUTO) &&
2428                     (level != TP_EC_FAN_FULLSPEED) &&
2429                     ((level < 0) || (level > 7)))
2430                         return -EINVAL;
2431
2432                 if (!acpi_ec_write(fan_status_offset, level))
2433                         return -EIO;
2434                 else
2435                         tp_features.fan_ctrl_status_undef = 0;
2436                 break;
2437
2438         default:
2439                 return -ENXIO;
2440         }
2441         return 0;
2442 }
2443
2444 static int fan_set_enable(void)
2445 {
2446         u8 s;
2447         int rc;
2448
2449         switch (fan_control_access_mode) {
2450         case TPACPI_FAN_WR_ACPI_FANS:
2451         case TPACPI_FAN_WR_TPEC:
2452                 if ((rc = fan_get_status(&s)) < 0)
2453                         return rc;
2454
2455                 /* Don't go out of emergency fan mode */
2456                 if (s != 7)
2457                         s = TP_EC_FAN_AUTO;
2458
2459                 if (!acpi_ec_write(fan_status_offset, s))
2460                         return -EIO;
2461                 else
2462                         tp_features.fan_ctrl_status_undef = 0;
2463                 break;
2464
2465         case TPACPI_FAN_WR_ACPI_SFAN:
2466                 if ((rc = fan_get_status(&s)) < 0)
2467                         return rc;
2468
2469                 s &= 0x07;
2470
2471                 /* Set fan to at least level 4 */
2472                 if (s < 4)
2473                         s = 4;
2474
2475                 if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", s))
2476                         return -EIO;
2477                 break;
2478
2479         default:
2480                 return -ENXIO;
2481         }
2482         return 0;
2483 }
2484
2485 static int fan_set_disable(void)
2486 {
2487         switch (fan_control_access_mode) {
2488         case TPACPI_FAN_WR_ACPI_FANS:
2489         case TPACPI_FAN_WR_TPEC:
2490                 if (!acpi_ec_write(fan_status_offset, 0x00))
2491                         return -EIO;
2492                 else
2493                         tp_features.fan_ctrl_status_undef = 0;
2494                 break;
2495
2496         case TPACPI_FAN_WR_ACPI_SFAN:
2497                 if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", 0x00))
2498                         return -EIO;
2499                 break;
2500
2501         default:
2502                 return -ENXIO;
2503         }
2504         return 0;
2505 }
2506
2507 static int fan_set_speed(int speed)
2508 {
2509         switch (fan_control_access_mode) {
2510         case TPACPI_FAN_WR_ACPI_FANS:
2511                 if (speed >= 0 && speed <= 65535) {
2512                         if (!acpi_evalf(fans_handle, NULL, NULL, "vddd",
2513                                         speed, speed, speed))
2514                                 return -EIO;
2515                 } else
2516                         return -EINVAL;
2517                 break;
2518
2519         default:
2520                 return -ENXIO;
2521         }
2522         return 0;
2523 }
2524
2525 static int fan_read(char *p)
2526 {
2527         int len = 0;
2528         int rc;
2529         u8 status;
2530         unsigned int speed = 0;
2531
2532         switch (fan_status_access_mode) {
2533         case TPACPI_FAN_RD_ACPI_GFAN:
2534                 /* 570, 600e/x, 770e, 770x */
2535                 if ((rc = fan_get_status(&status)) < 0)
2536                         return rc;
2537
2538                 len += sprintf(p + len, "status:\t\t%s\n"
2539                                "level:\t\t%d\n",
2540                                (status != 0) ? "enabled" : "disabled", status);
2541                 break;
2542
2543         case TPACPI_FAN_RD_TPEC:
2544                 /* all except 570, 600e/x, 770e, 770x */
2545                 if ((rc = fan_get_status(&status)) < 0)
2546                         return rc;
2547
2548                 if (unlikely(tp_features.fan_ctrl_status_undef)) {
2549                         if (status != fan_control_initial_status)
2550                                 tp_features.fan_ctrl_status_undef = 0;
2551                         else
2552                                 /* Return most likely status. In fact, it
2553                                  * might be the only possible status */
2554                                 status = TP_EC_FAN_AUTO;
2555                 }
2556
2557                 len += sprintf(p + len, "status:\t\t%s\n",
2558                                (status != 0) ? "enabled" : "disabled");
2559
2560                 if ((rc = fan_get_speed(&speed)) < 0)
2561                         return rc;
2562
2563                 len += sprintf(p + len, "speed:\t\t%d\n", speed);
2564
2565                 if (status & TP_EC_FAN_FULLSPEED)
2566                         /* Disengaged mode takes precedence */
2567                         len += sprintf(p + len, "level:\t\tdisengaged\n");
2568                 else if (status & TP_EC_FAN_AUTO)
2569                         len += sprintf(p + len, "level:\t\tauto\n");
2570                 else
2571                         len += sprintf(p + len, "level:\t\t%d\n", status);
2572                 break;
2573
2574         case TPACPI_FAN_NONE:
2575         default:
2576                 len += sprintf(p + len, "status:\t\tnot supported\n");
2577         }
2578
2579         if (fan_control_commands & TPACPI_FAN_CMD_LEVEL) {
2580                 len += sprintf(p + len, "commands:\tlevel <level>");
2581
2582                 switch (fan_control_access_mode) {
2583                 case TPACPI_FAN_WR_ACPI_SFAN:
2584                         len += sprintf(p + len, " (<level> is 0-7)\n");
2585                         break;
2586
2587                 default:
2588                         len += sprintf(p + len, " (<level> is 0-7, "
2589                                        "auto, disengaged)\n");
2590                         break;
2591                 }
2592         }
2593
2594         if (fan_control_commands & TPACPI_FAN_CMD_ENABLE)
2595                 len += sprintf(p + len, "commands:\tenable, disable\n"
2596                                "commands:\twatchdog <timeout> (<timeout> is 0 (off), "
2597                                "1-120 (seconds))\n");
2598
2599         if (fan_control_commands & TPACPI_FAN_CMD_SPEED)
2600                 len += sprintf(p + len, "commands:\tspeed <speed>"
2601                                " (<speed> is 0-65535)\n");
2602
2603         return len;
2604 }
2605
2606 static int fan_write_cmd_level(const char *cmd, int *rc)
2607 {
2608         int level;
2609
2610         if (strlencmp(cmd, "level auto") == 0)
2611                 level = TP_EC_FAN_AUTO;
2612         else if (strlencmp(cmd, "level disengaged") == 0)
2613                 level = TP_EC_FAN_FULLSPEED;
2614         else if (sscanf(cmd, "level %d", &level) != 1)
2615                 return 0;
2616
2617         if ((*rc = fan_set_level(level)) == -ENXIO)
2618                 printk(IBM_ERR "level command accepted for unsupported "
2619                        "access mode %d", fan_control_access_mode);
2620
2621         return 1;
2622 }
2623
2624 static int fan_write_cmd_enable(const char *cmd, int *rc)
2625 {
2626         if (strlencmp(cmd, "enable") != 0)
2627                 return 0;
2628
2629         if ((*rc = fan_set_enable()) == -ENXIO)
2630                 printk(IBM_ERR "enable command accepted for unsupported "
2631                        "access mode %d", fan_control_access_mode);
2632
2633         return 1;
2634 }
2635
2636 static int fan_write_cmd_disable(const char *cmd, int *rc)
2637 {
2638         if (strlencmp(cmd, "disable") != 0)
2639                 return 0;
2640
2641         if ((*rc = fan_set_disable()) == -ENXIO)
2642                 printk(IBM_ERR "disable command accepted for unsupported "
2643                        "access mode %d", fan_control_access_mode);
2644
2645         return 1;
2646 }
2647
2648 static int fan_write_cmd_speed(const char *cmd, int *rc)
2649 {
2650         int speed;
2651
2652         /* TODO:
2653          * Support speed <low> <medium> <high> ? */
2654
2655         if (sscanf(cmd, "speed %d", &speed) != 1)
2656                 return 0;
2657
2658         if ((*rc = fan_set_speed(speed)) == -ENXIO)
2659                 printk(IBM_ERR "speed command accepted for unsupported "
2660                        "access mode %d", fan_control_access_mode);
2661
2662         return 1;
2663 }
2664
2665 static int fan_write_cmd_watchdog(const char *cmd, int *rc)
2666 {
2667         int interval;
2668
2669         if (sscanf(cmd, "watchdog %d", &interval) != 1)
2670                 return 0;
2671
2672         if (interval < 0 || interval > 120)
2673                 *rc = -EINVAL;
2674         else
2675                 fan_watchdog_maxinterval = interval;
2676
2677         return 1;
2678 }
2679
2680 static int fan_write(char *buf)
2681 {
2682         char *cmd;
2683         int rc = 0;
2684
2685         while (!rc && (cmd = next_cmd(&buf))) {
2686                 if (!((fan_control_commands & TPACPI_FAN_CMD_LEVEL) &&
2687                       fan_write_cmd_level(cmd, &rc)) &&
2688                     !((fan_control_commands & TPACPI_FAN_CMD_ENABLE) &&
2689                       (fan_write_cmd_enable(cmd, &rc) ||
2690                        fan_write_cmd_disable(cmd, &rc) ||
2691                        fan_write_cmd_watchdog(cmd, &rc))) &&
2692                     !((fan_control_commands & TPACPI_FAN_CMD_SPEED) &&
2693                       fan_write_cmd_speed(cmd, &rc))
2694                     )
2695                         rc = -EINVAL;
2696                 else if (!rc)
2697                         fan_watchdog_reset();
2698         }
2699
2700         return rc;
2701 }
2702
2703 static struct ibm_struct fan_driver_data = {
2704         .name = "fan",
2705         .read = fan_read,
2706         .write = fan_write,
2707         .exit = fan_exit,
2708         .flags.experimental = 1,
2709 };
2710
2711 /****************************************************************************
2712  ****************************************************************************
2713  *
2714  * Infrastructure
2715  *
2716  ****************************************************************************
2717  ****************************************************************************/
2718
2719 /* /proc support */
2720 static struct proc_dir_entry *proc_dir = NULL;
2721
2722 /* Subdriver registry */
2723 static LIST_HEAD(tpacpi_all_drivers);
2724
2725
2726 /*
2727  * Module and infrastructure proble, init and exit handling
2728  */
2729
2730 #ifdef CONFIG_THINKPAD_ACPI_DEBUG
2731 static const char * __init str_supported(int is_supported)
2732 {
2733         static char text_unsupported[] __initdata = "not supported";
2734
2735         return (is_supported)? &text_unsupported[4] : &text_unsupported[0];
2736 }
2737 #endif /* CONFIG_THINKPAD_ACPI_DEBUG */
2738
2739 static int __init ibm_init(struct ibm_init_struct *iibm)
2740 {
2741         int ret;
2742         struct ibm_struct *ibm = iibm->data;
2743         struct proc_dir_entry *entry;
2744
2745         BUG_ON(ibm == NULL);
2746
2747         INIT_LIST_HEAD(&ibm->all_drivers);
2748
2749         if (ibm->flags.experimental && !experimental)
2750                 return 0;
2751
2752         dbg_printk(TPACPI_DBG_INIT,
2753                 "probing for %s\n", ibm->name);
2754
2755         if (iibm->init) {
2756                 ret = iibm->init(iibm);
2757                 if (ret > 0)
2758                         return 0;       /* probe failed */
2759                 if (ret)
2760                         return ret;
2761
2762                 ibm->flags.init_called = 1;
2763         }
2764
2765         if (ibm->acpi) {
2766                 if (ibm->acpi->hid) {
2767                         ret = register_tpacpi_subdriver(ibm);
2768                         if (ret)
2769                                 goto err_out;
2770                 }
2771
2772                 if (ibm->acpi->notify) {
2773                         ret = setup_acpi_notify(ibm);
2774                         if (ret == -ENODEV) {
2775                                 printk(IBM_NOTICE "disabling subdriver %s\n",
2776                                         ibm->name);
2777                                 ret = 0;
2778                                 goto err_out;
2779                         }
2780                         if (ret < 0)
2781                                 goto err_out;
2782                 }
2783         }
2784
2785         dbg_printk(TPACPI_DBG_INIT,
2786                 "%s installed\n", ibm->name);
2787
2788         if (ibm->read) {
2789                 entry = create_proc_entry(ibm->name,
2790                                           S_IFREG | S_IRUGO | S_IWUSR,
2791                                           proc_dir);
2792                 if (!entry) {
2793                         printk(IBM_ERR "unable to create proc entry %s\n",
2794                                ibm->name);
2795                         ret = -ENODEV;
2796                         goto err_out;
2797                 }
2798                 entry->owner = THIS_MODULE;
2799                 entry->data = ibm;
2800                 entry->read_proc = &dispatch_procfs_read;
2801                 if (ibm->write)
2802                         entry->write_proc = &dispatch_procfs_write;
2803                 ibm->flags.proc_created = 1;
2804         }
2805
2806         list_add_tail(&ibm->all_drivers, &tpacpi_all_drivers);
2807
2808         return 0;
2809
2810 err_out:
2811         dbg_printk(TPACPI_DBG_INIT,
2812                 "%s: at error exit path with result %d\n",
2813                 ibm->name, ret);
2814
2815         ibm_exit(ibm);
2816         return (ret < 0)? ret : 0;
2817 }
2818
2819 static void ibm_exit(struct ibm_struct *ibm)
2820 {
2821         dbg_printk(TPACPI_DBG_EXIT, "removing %s\n", ibm->name);
2822
2823         list_del_init(&ibm->all_drivers);
2824
2825         if (ibm->flags.acpi_notify_installed) {
2826                 dbg_printk(TPACPI_DBG_EXIT,
2827                         "%s: acpi_remove_notify_handler\n", ibm->name);
2828                 BUG_ON(!ibm->acpi);
2829                 acpi_remove_notify_handler(*ibm->acpi->handle,
2830                                            ibm->acpi->type,
2831                                            dispatch_acpi_notify);
2832                 ibm->flags.acpi_notify_installed = 0;
2833                 ibm->flags.acpi_notify_installed = 0;
2834         }
2835
2836         if (ibm->flags.proc_created) {
2837                 dbg_printk(TPACPI_DBG_EXIT,
2838                         "%s: remove_proc_entry\n", ibm->name);
2839                 remove_proc_entry(ibm->name, proc_dir);
2840                 ibm->flags.proc_created = 0;
2841         }
2842
2843         if (ibm->flags.acpi_driver_registered) {
2844                 dbg_printk(TPACPI_DBG_EXIT,
2845                         "%s: acpi_bus_unregister_driver\n", ibm->name);
2846                 BUG_ON(!ibm->acpi);
2847                 acpi_bus_unregister_driver(ibm->acpi->driver);
2848                 kfree(ibm->acpi->driver);
2849                 ibm->acpi->driver = NULL;
2850                 ibm->flags.acpi_driver_registered = 0;
2851         }
2852
2853         if (ibm->flags.init_called && ibm->exit) {
2854                 ibm->exit();
2855                 ibm->flags.init_called = 0;
2856         }
2857
2858         dbg_printk(TPACPI_DBG_INIT, "finished removing %s\n", ibm->name);
2859 }
2860
2861 /* Probing */
2862
2863 static char *ibm_thinkpad_ec_found = NULL;
2864
2865 static char* __init check_dmi_for_ec(void)
2866 {
2867         struct dmi_device *dev = NULL;
2868         char ec_fw_string[18];
2869
2870         /*
2871          * ThinkPad T23 or newer, A31 or newer, R50e or newer,
2872          * X32 or newer, all Z series;  Some models must have an
2873          * up-to-date BIOS or they will not be detected.
2874          *
2875          * See http://thinkwiki.org/wiki/List_of_DMI_IDs
2876          */
2877         while ((dev = dmi_find_device(DMI_DEV_TYPE_OEM_STRING, NULL, dev))) {
2878                 if (sscanf(dev->name,
2879                            "IBM ThinkPad Embedded Controller -[%17c",
2880                            ec_fw_string) == 1) {
2881                         ec_fw_string[sizeof(ec_fw_string) - 1] = 0;
2882                         ec_fw_string[strcspn(ec_fw_string, " ]")] = 0;
2883                         return kstrdup(ec_fw_string, GFP_KERNEL);
2884                 }
2885         }
2886         return NULL;
2887 }
2888
2889 static int __init probe_for_thinkpad(void)
2890 {
2891         int is_thinkpad;
2892
2893         if (acpi_disabled)
2894                 return -ENODEV;
2895
2896         /*
2897          * Non-ancient models have better DMI tagging, but very old models
2898          * don't.
2899          */
2900         is_thinkpad = dmi_name_in_vendors("ThinkPad");
2901
2902         /* ec is required because many other handles are relative to it */
2903         IBM_ACPIHANDLE_INIT(ec);
2904         if (!ec_handle) {
2905                 if (is_thinkpad)
2906                         printk(IBM_ERR
2907                                 "Not yet supported ThinkPad detected!\n");
2908                 return -ENODEV;
2909         }
2910
2911         /*
2912          * Risks a regression on very old machines, but reduces potential
2913          * false positives a damn great deal
2914          */
2915         if (!is_thinkpad)
2916                 is_thinkpad = dmi_name_in_vendors("IBM");
2917
2918         if (!is_thinkpad && !force_load)
2919                 return -ENODEV;
2920
2921         return 0;
2922 }
2923
2924
2925 /* Module init, exit, parameters */
2926
2927 static struct ibm_init_struct ibms_init[] __initdata = {
2928         {
2929                 .init = thinkpad_acpi_driver_init,
2930                 .data = &thinkpad_acpi_driver_data,
2931         },
2932         {
2933                 .init = hotkey_init,
2934                 .data = &hotkey_driver_data,
2935         },
2936         {
2937                 .init = bluetooth_init,
2938                 .data = &bluetooth_driver_data,
2939         },
2940         {
2941                 .init = wan_init,
2942                 .data = &wan_driver_data,
2943         },
2944         {
2945                 .init = video_init,
2946                 .data = &video_driver_data,
2947         },
2948         {
2949                 .init = light_init,
2950                 .data = &light_driver_data,
2951         },
2952 #ifdef CONFIG_THINKPAD_ACPI_DOCK
2953         {
2954                 .init = dock_init,
2955                 .data = &dock_driver_data[0],
2956         },
2957         {
2958                 .data = &dock_driver_data[1],
2959         },
2960 #endif
2961 #ifdef CONFIG_THINKPAD_ACPI_BAY
2962         {
2963                 .init = bay_init,
2964                 .data = &bay_driver_data,
2965         },
2966 #endif
2967         {
2968                 .init = cmos_init,
2969                 .data = &cmos_driver_data,
2970         },
2971         {
2972                 .init = led_init,
2973                 .data = &led_driver_data,
2974         },
2975         {
2976                 .init = beep_init,
2977                 .data = &beep_driver_data,
2978         },
2979         {
2980                 .init = thermal_init,
2981                 .data = &thermal_driver_data,
2982         },
2983         {
2984                 .data = &ecdump_driver_data,
2985         },
2986         {
2987                 .init = brightness_init,
2988                 .data = &brightness_driver_data,
2989         },
2990         {
2991                 .data = &volume_driver_data,
2992         },
2993         {
2994                 .init = fan_init,
2995                 .data = &fan_driver_data,
2996         },
2997 };
2998
2999 static int __init set_ibm_param(const char *val, struct kernel_param *kp)
3000 {
3001         unsigned int i;
3002         struct ibm_struct *ibm;
3003
3004         for (i = 0; i < ARRAY_SIZE(ibms_init); i++) {
3005                 ibm = ibms_init[i].data;
3006                 BUG_ON(ibm == NULL);
3007
3008                 if (strcmp(ibm->name, kp->name) == 0 && ibm->write) {
3009                         if (strlen(val) > sizeof(ibms_init[i].param) - 2)
3010                                 return -ENOSPC;
3011                         strcpy(ibms_init[i].param, val);
3012                         strcat(ibms_init[i].param, ",");
3013                         return 0;
3014                 }
3015         }
3016
3017         return -EINVAL;
3018 }
3019
3020 static int experimental;
3021 module_param(experimental, int, 0);
3022
3023 static u32 dbg_level;
3024 module_param_named(debug, dbg_level, uint, 0);
3025
3026 static int force_load;
3027 module_param(force_load, int, 0);
3028
3029 #define IBM_PARAM(feature) \
3030         module_param_call(feature, set_ibm_param, NULL, NULL, 0)
3031
3032 IBM_PARAM(hotkey);
3033 IBM_PARAM(bluetooth);
3034 IBM_PARAM(video);
3035 IBM_PARAM(light);
3036 #ifdef CONFIG_THINKPAD_ACPI_DOCK
3037 IBM_PARAM(dock);
3038 #endif
3039 #ifdef CONFIG_THINKPAD_ACPI_BAY
3040 IBM_PARAM(bay);
3041 #endif /* CONFIG_THINKPAD_ACPI_BAY */
3042 IBM_PARAM(cmos);
3043 IBM_PARAM(led);
3044 IBM_PARAM(beep);
3045 IBM_PARAM(ecdump);
3046 IBM_PARAM(brightness);
3047 IBM_PARAM(volume);
3048 IBM_PARAM(fan);
3049
3050 static int __init thinkpad_acpi_module_init(void)
3051 {
3052         int ret, i;
3053
3054         ret = probe_for_thinkpad();
3055         if (ret)
3056                 return ret;
3057
3058         ibm_thinkpad_ec_found = check_dmi_for_ec();
3059         IBM_ACPIHANDLE_INIT(ecrd);
3060         IBM_ACPIHANDLE_INIT(ecwr);
3061
3062         proc_dir = proc_mkdir(IBM_PROC_DIR, acpi_root_dir);
3063         if (!proc_dir) {
3064                 printk(IBM_ERR "unable to create proc dir " IBM_PROC_DIR);
3065                 thinkpad_acpi_module_exit();
3066                 return -ENODEV;
3067         }
3068         proc_dir->owner = THIS_MODULE;
3069
3070         for (i = 0; i < ARRAY_SIZE(ibms_init); i++) {
3071                 ret = ibm_init(&ibms_init[i]);
3072                 if (ret >= 0 && *ibms_init[i].param)
3073                         ret = ibms_init[i].data->write(ibms_init[i].param);
3074                 if (ret < 0) {
3075                         thinkpad_acpi_module_exit();
3076                         return ret;
3077                 }
3078         }
3079
3080         return 0;
3081 }
3082
3083 static void thinkpad_acpi_module_exit(void)
3084 {
3085         struct ibm_struct *ibm, *itmp;
3086
3087         list_for_each_entry_safe_reverse(ibm, itmp,
3088                                          &tpacpi_all_drivers,
3089                                          all_drivers) {
3090                 ibm_exit(ibm);
3091         }
3092
3093         dbg_printk(TPACPI_DBG_INIT, "finished subdriver exit path...\n");
3094
3095         if (proc_dir)
3096                 remove_proc_entry(IBM_PROC_DIR, acpi_root_dir);
3097
3098         kfree(ibm_thinkpad_ec_found);
3099 }
3100
3101 module_init(thinkpad_acpi_module_init);
3102 module_exit(thinkpad_acpi_module_exit);