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