Add patches accepted for 2.6.22-rc1 (not released yet)
[linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git] / releases / upstream / 2.6.22-rc1 / 0004-ACPI-ibm-acpi-organize-code.patch
blob8a9cdd3e72dc2bd60b405d68da139b30d9984ae0
1 From 56b6aeb05890f219895197f5166637b3d7a6f679 Mon Sep 17 00:00:00 2001
2 From: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
3 Date: Fri, 23 Mar 2007 17:33:57 -0300
4 Subject: ACPI: ibm-acpi: organize code
6 Shuffle code around to better organize the driver code inside the
7 ibm-acpi.c file.
9 This patch adds no functional changes. It is pure fluff that will make me
10 a bit more productive.
12 Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
13 Signed-off-by: Len Brown <len.brown@intel.com>
14 ---
15 drivers/acpi/ibm_acpi.c | 1398 +++++++++++++++++++++++++----------------------
16 1 files changed, 757 insertions(+), 641 deletions(-)
18 diff --git a/drivers/acpi/ibm_acpi.c b/drivers/acpi/ibm_acpi.c
19 index e2da954..984ec81 100644
20 --- a/drivers/acpi/ibm_acpi.c
21 +++ b/drivers/acpi/ibm_acpi.c
22 @@ -87,8 +87,17 @@ MODULE_LICENSE("GPL");
24 #define __unused __attribute__ ((unused))
26 -static int experimental;
27 -module_param(experimental, int, 0);
28 +/****************************************************************************
29 + ****************************************************************************
30 + *
31 + * ACPI Helpers and device model
32 + *
33 + ****************************************************************************
34 + ****************************************************************************/
36 +/*************************************************************************
37 + * ACPI basic handles
38 + */
40 static acpi_handle root_handle = NULL;
42 @@ -105,183 +114,31 @@ IBM_HANDLE(ec, root, "\\_SB.PCI0.ISA.EC0", /* 240, 240x */
43 "\\_SB.PCI0.AD4S.EC0", /* i1400, R30 */
44 "\\_SB.PCI0.ICH3.EC0", /* R31 */
45 "\\_SB.PCI0.LPC.EC", /* all others */
46 - );
47 + );
49 -IBM_HANDLE(vid, root, "\\_SB.PCI.AGP.VGA", /* 570 */
50 - "\\_SB.PCI0.AGP0.VID0", /* 600e/x, 770x */
51 - "\\_SB.PCI0.VID0", /* 770e */
52 - "\\_SB.PCI0.VID", /* A21e, G4x, R50e, X30, X40 */
53 - "\\_SB.PCI0.AGP.VID", /* all others */
54 - ); /* R30, R31 */
55 +IBM_HANDLE(ecrd, ec, "ECRD"); /* 570 */
56 +IBM_HANDLE(ecwr, ec, "ECWR"); /* 570 */
58 -IBM_HANDLE(vid2, root, "\\_SB.PCI0.AGPB.VID"); /* G41 */
60 +/*************************************************************************
61 + * Misc ACPI handles
62 + */
64 IBM_HANDLE(cmos, root, "\\UCMS", /* R50, R50e, R50p, R51, T4x, X31, X40 */
65 "\\CMOS", /* A3x, G4x, R32, T23, T30, X22-24, X30 */
66 "\\CMS", /* R40, R40e */
67 - ); /* all others */
68 -#ifdef CONFIG_ACPI_IBM_DOCK
69 -IBM_HANDLE(dock, root, "\\_SB.GDCK", /* X30, X31, X40 */
70 - "\\_SB.PCI0.DOCK", /* 600e/x,770e,770x,A2xm/p,T20-22,X20-21 */
71 - "\\_SB.PCI0.PCI1.DOCK", /* all others */
72 - "\\_SB.PCI.ISA.SLCE", /* 570 */
73 - ); /* A21e,G4x,R30,R31,R32,R40,R40e,R50e */
74 -#endif
75 -#ifdef CONFIG_ACPI_IBM_BAY
76 -IBM_HANDLE(bay, root, "\\_SB.PCI.IDE.SECN.MAST", /* 570 */
77 - "\\_SB.PCI0.IDE0.IDES.IDSM", /* 600e/x, 770e, 770x */
78 - "\\_SB.PCI0.SATA.SCND.MSTR", /* T60, X60, Z60 */
79 - "\\_SB.PCI0.IDE0.SCND.MSTR", /* all others */
80 - ); /* A21e, R30, R31 */
82 -IBM_HANDLE(bay_ej, bay, "_EJ3", /* 600e/x, A2xm/p, A3x */
83 - "_EJ0", /* all others */
84 - ); /* 570,A21e,G4x,R30,R31,R32,R40e,R50e */
86 -IBM_HANDLE(bay2, root, "\\_SB.PCI0.IDE0.PRIM.SLAV", /* A3x, R32 */
87 - "\\_SB.PCI0.IDE0.IDEP.IDPS", /* 600e/x, 770e, 770x */
88 - ); /* all others */
90 -IBM_HANDLE(bay2_ej, bay2, "_EJ3", /* 600e/x, 770e, A3x */
91 - "_EJ0", /* 770x */
92 - ); /* all others */
93 -#endif /* CONFIG_ACPI_IBM_BAY */
95 -/* don't list other alternatives as we install a notify handler on the 570 */
96 -IBM_HANDLE(pci, root, "\\_SB.PCI"); /* 570 */
97 + ); /* all others */
99 IBM_HANDLE(hkey, ec, "\\_SB.HKEY", /* 600e/x, 770e, 770x */
100 "^HKEY", /* R30, R31 */
101 "HKEY", /* all others */
102 - ); /* 570 */
103 + ); /* 570 */
105 -IBM_HANDLE(lght, root, "\\LGHT"); /* A21e, A2xm/p, T20-22, X20-21 */
106 -IBM_HANDLE(ledb, ec, "LEDB"); /* G4x */
108 -IBM_HANDLE(led, ec, "SLED", /* 570 */
109 - "SYSL", /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20-21 */
110 - "LED", /* all others */
111 - ); /* R30, R31 */
113 -IBM_HANDLE(beep, ec, "BEEP"); /* all except R30, R31 */
114 -IBM_HANDLE(ecrd, ec, "ECRD"); /* 570 */
115 -IBM_HANDLE(ecwr, ec, "ECWR"); /* 570 */
116 -IBM_HANDLE(fans, ec, "FANS"); /* X31, X40, X41 */
118 -IBM_HANDLE(gfan, ec, "GFAN", /* 570 */
119 - "\\FSPD", /* 600e/x, 770e, 770x */
120 - ); /* all others */
122 -IBM_HANDLE(sfan, ec, "SFAN", /* 570 */
123 - "JFNS", /* 770x-JL */
124 - ); /* all others */
127 - * FAN ACCESS MODES
129 - * IBMACPI_FAN_RD_ACPI_GFAN:
130 - * ACPI GFAN method: returns fan level
132 - * see IBMACPI_FAN_WR_ACPI_SFAN
133 - * EC 0x2f not available if GFAN exists
135 - * IBMACPI_FAN_WR_ACPI_SFAN:
136 - * ACPI SFAN method: sets fan level, 0 (stop) to 7 (max)
138 - * EC 0x2f might be available *for reading*, but never for writing.
140 - * IBMACPI_FAN_WR_TPEC:
141 - * ThinkPad EC register 0x2f (HFSP): fan control loop mode Supported
142 - * on almost all ThinkPads
144 - * Fan speed changes of any sort (including those caused by the
145 - * disengaged mode) are usually done slowly by the firmware as the
146 - * maximum ammount of fan duty cycle change per second seems to be
147 - * limited.
149 - * Reading is not available if GFAN exists.
150 - * Writing is not available if SFAN exists.
152 - * Bits
153 - * 7 automatic mode engaged;
154 - * (default operation mode of the ThinkPad)
155 - * fan level is ignored in this mode.
156 - * 6 disengage mode (takes precedence over bit 7);
157 - * not available on all thinkpads. May disable
158 - * the tachometer, and speeds up fan to 100% duty-cycle,
159 - * which speeds it up far above the standard RPM
160 - * levels. It is not impossible that it could cause
161 - * hardware damage.
162 - * 5-3 unused in some models. Extra bits for fan level
163 - * in others, but still useless as all values above
164 - * 7 map to the same speed as level 7 in these models.
165 - * 2-0 fan level (0..7 usually)
166 - * 0x00 = stop
167 - * 0x07 = max (set when temperatures critical)
168 - * Some ThinkPads may have other levels, see
169 - * IBMACPI_FAN_WR_ACPI_FANS (X31/X40/X41)
171 - * FIRMWARE BUG: on some models, EC 0x2f might not be initialized at
172 - * boot. Apparently the EC does not intialize it, so unless ACPI DSDT
173 - * does so, its initial value is meaningless (0x07).
175 - * For firmware bugs, refer to:
176 - * http://thinkwiki.org/wiki/Embedded_Controller_Firmware#Firmware_Issues
178 - * ----
180 - * ThinkPad EC register 0x84 (LSB), 0x85 (MSB):
181 - * Main fan tachometer reading (in RPM)
183 - * This register is present on all ThinkPads with a new-style EC, and
184 - * it is known not to be present on the A21m/e, and T22, as there is
185 - * something else in offset 0x84 according to the ACPI DSDT. Other
186 - * ThinkPads from this same time period (and earlier) probably lack the
187 - * tachometer as well.
189 - * Unfortunately a lot of ThinkPads with new-style ECs but whose firwmare
190 - * was never fixed by IBM to report the EC firmware version string
191 - * probably support the tachometer (like the early X models), so
192 - * detecting it is quite hard. We need more data to know for sure.
194 - * FIRMWARE BUG: always read 0x84 first, otherwise incorrect readings
195 - * might result.
197 - * FIRMWARE BUG: when EC 0x2f bit 6 is set (disengaged mode), this
198 - * register is not invalidated in ThinkPads that disable tachometer
199 - * readings. Thus, the tachometer readings go stale.
201 - * For firmware bugs, refer to:
202 - * http://thinkwiki.org/wiki/Embedded_Controller_Firmware#Firmware_Issues
204 - * IBMACPI_FAN_WR_ACPI_FANS:
205 - * ThinkPad X31, X40, X41. Not available in the X60.
207 - * FANS ACPI handle: takes three arguments: low speed, medium speed,
208 - * high speed. ACPI DSDT seems to map these three speeds to levels
209 - * as follows: STOP LOW LOW MED MED HIGH HIGH HIGH HIGH
210 - * (this map is stored on FAN0..FAN8 as "0,1,1,2,2,3,3,3,3")
212 - * The speeds are stored on handles
213 - * (FANA:FAN9), (FANC:FANB), (FANE:FAND).
215 - * There are three default speed sets, acessible as handles:
216 - * FS1L,FS1M,FS1H; FS2L,FS2M,FS2H; FS3L,FS3M,FS3H
218 - * ACPI DSDT switches which set is in use depending on various
219 - * factors.
221 - * IBMACPI_FAN_WR_TPEC is also available and should be used to
222 - * command the fan. The X31/X40/X41 seems to have 8 fan levels,
223 - * but the ACPI tables just mention level 7.
224 +/*************************************************************************
225 + * ACPI helpers
228 -static char *ibm_thinkpad_ec_found = NULL;
230 -static struct proc_dir_entry *proc_dir = NULL;
232 -static struct backlight_device *ibm_backlight_device = NULL;
234 static int acpi_evalf(acpi_handle handle,
235 void *res, char *method, char *fmt, ...)
237 @@ -371,6 +228,203 @@ static void __unused acpi_print_int(acpi_handle handle, char *method)
238 printk(IBM_ERR "error calling %s\n", method);
241 +static int acpi_ec_read(int i, u8 * p)
243 + int v;
245 + if (ecrd_handle) {
246 + if (!acpi_evalf(ecrd_handle, &v, NULL, "dd", i))
247 + return 0;
248 + *p = v;
249 + } else {
250 + if (ec_read(i, p) < 0)
251 + return 0;
254 + return 1;
257 +static int acpi_ec_write(int i, u8 v)
259 + if (ecwr_handle) {
260 + if (!acpi_evalf(ecwr_handle, NULL, NULL, "vdd", i, v))
261 + return 0;
262 + } else {
263 + if (ec_write(i, v) < 0)
264 + return 0;
267 + return 1;
270 +static int _sta(acpi_handle handle)
272 + int status;
274 + if (!handle || !acpi_evalf(handle, &status, "_STA", "d"))
275 + status = 0;
277 + return status;
280 +/*************************************************************************
281 + * ACPI device model
282 + */
284 +static void __init ibm_handle_init(char *name,
285 + acpi_handle * handle, acpi_handle parent,
286 + char **paths, int num_paths, char **path)
288 + int i;
289 + acpi_status status;
291 + for (i = 0; i < num_paths; i++) {
292 + status = acpi_get_handle(parent, paths[i], handle);
293 + if (ACPI_SUCCESS(status)) {
294 + *path = paths[i];
295 + return;
299 + *handle = NULL;
302 +static void dispatch_notify(acpi_handle handle, u32 event, void *data)
304 + struct ibm_struct *ibm = data;
306 + if (!ibm || !ibm->notify)
307 + return;
309 + ibm->notify(ibm, event);
312 +static int __init setup_notify(struct ibm_struct *ibm)
314 + acpi_status status;
315 + int ret;
317 + if (!*ibm->handle)
318 + return 0;
320 + ret = acpi_bus_get_device(*ibm->handle, &ibm->device);
321 + if (ret < 0) {
322 + printk(IBM_ERR "%s device not present\n", ibm->name);
323 + return -ENODEV;
326 + acpi_driver_data(ibm->device) = ibm;
327 + sprintf(acpi_device_class(ibm->device), "%s/%s", IBM_NAME, ibm->name);
329 + status = acpi_install_notify_handler(*ibm->handle, ibm->type,
330 + dispatch_notify, ibm);
331 + if (ACPI_FAILURE(status)) {
332 + if (status == AE_ALREADY_EXISTS) {
333 + printk(IBM_NOTICE "another device driver is already handling %s events\n",
334 + ibm->name);
335 + } else {
336 + printk(IBM_ERR "acpi_install_notify_handler(%s) failed: %d\n",
337 + ibm->name, status);
339 + return -ENODEV;
341 + ibm->notify_installed = 1;
342 + return 0;
345 +static int __init ibm_device_add(struct acpi_device *device)
347 + return 0;
350 +static int __init register_ibmacpi_subdriver(struct ibm_struct *ibm)
352 + int ret;
354 + ibm->driver = kzalloc(sizeof(struct acpi_driver), GFP_KERNEL);
355 + if (!ibm->driver) {
356 + printk(IBM_ERR "kmalloc(ibm->driver) failed\n");
357 + return -1;
360 + sprintf(ibm->driver->name, "%s_%s", IBM_NAME, ibm->name);
361 + ibm->driver->ids = ibm->hid;
362 + ibm->driver->ops.add = &ibm_device_add;
364 + ret = acpi_bus_register_driver(ibm->driver);
365 + if (ret < 0) {
366 + printk(IBM_ERR "acpi_bus_register_driver(%s) failed: %d\n",
367 + ibm->hid, ret);
368 + kfree(ibm->driver);
371 + return ret;
375 +/****************************************************************************
376 + ****************************************************************************
378 + * Procfs Helpers
380 + ****************************************************************************
381 + ****************************************************************************/
383 +static int dispatch_read(char *page, char **start, off_t off, int count,
384 + int *eof, void *data)
386 + struct ibm_struct *ibm = data;
387 + int len;
389 + if (!ibm || !ibm->read)
390 + return -EINVAL;
392 + len = ibm->read(page);
393 + if (len < 0)
394 + return len;
396 + if (len <= off + count)
397 + *eof = 1;
398 + *start = page + off;
399 + len -= off;
400 + if (len > count)
401 + len = count;
402 + if (len < 0)
403 + len = 0;
405 + return len;
408 +static int dispatch_write(struct file *file, const char __user * userbuf,
409 + unsigned long count, void *data)
411 + struct ibm_struct *ibm = data;
412 + char *kernbuf;
413 + int ret;
415 + if (!ibm || !ibm->write)
416 + return -EINVAL;
418 + kernbuf = kmalloc(count + 2, GFP_KERNEL);
419 + if (!kernbuf)
420 + return -ENOMEM;
422 + if (copy_from_user(kernbuf, userbuf, count)) {
423 + kfree(kernbuf);
424 + return -EFAULT;
427 + kernbuf[count] = 0;
428 + strcat(kernbuf, ",");
429 + ret = ibm->write(kernbuf);
430 + if (ret == 0)
431 + ret = count;
433 + kfree(kernbuf);
435 + return ret;
438 static char *next_cmd(char **cmds)
440 char *start = *cmds;
441 @@ -387,6 +441,19 @@ static char *next_cmd(char **cmds)
442 return start;
446 +/****************************************************************************
447 + ****************************************************************************
449 + * Subdrivers
451 + ****************************************************************************
452 + ****************************************************************************/
454 +/*************************************************************************
455 + * ibm-acpi init subdriver
456 + */
458 static int ibm_acpi_driver_init(void)
460 printk(IBM_INFO "%s v%s\n", IBM_DESC, IBM_VERSION);
461 @@ -409,11 +476,51 @@ static int ibm_acpi_driver_read(char *p)
462 return len;
465 +/*************************************************************************
466 + * Hotkey subdriver
467 + */
469 static int hotkey_supported;
470 static int hotkey_mask_supported;
471 static int hotkey_orig_status;
472 static int hotkey_orig_mask;
474 +static int hotkey_init(void)
476 + /* hotkey not supported on 570 */
477 + hotkey_supported = hkey_handle != NULL;
479 + if (hotkey_supported) {
480 + /* mask not supported on 570, 600e/x, 770e, 770x, A21e, A2xm/p,
481 + A30, R30, R31, T20-22, X20-21, X22-24 */
482 + hotkey_mask_supported =
483 + acpi_evalf(hkey_handle, NULL, "DHKN", "qv");
485 + if (!hotkey_get(&hotkey_orig_status, &hotkey_orig_mask))
486 + return -ENODEV;
489 + return 0;
492 +static void hotkey_exit(void)
494 + if (hotkey_supported)
495 + hotkey_set(hotkey_orig_status, hotkey_orig_mask);
498 +static void hotkey_notify(struct ibm_struct *ibm, u32 event)
500 + int hkey;
502 + if (acpi_evalf(hkey_handle, &hkey, "MHKP", "d"))
503 + acpi_bus_generate_event(ibm->device, event, hkey);
504 + else {
505 + printk(IBM_ERR "unknown hotkey event %d\n", event);
506 + acpi_bus_generate_event(ibm->device, event, 0);
510 static int hotkey_get(int *status, int *mask)
512 if (!acpi_evalf(hkey_handle, status, "DHKC", "d"))
513 @@ -444,24 +551,6 @@ static int hotkey_set(int status, int mask)
514 return 1;
517 -static int hotkey_init(void)
519 - /* hotkey not supported on 570 */
520 - hotkey_supported = hkey_handle != NULL;
522 - if (hotkey_supported) {
523 - /* mask not supported on 570, 600e/x, 770e, 770x, A21e, A2xm/p,
524 - A30, R30, R31, T20-22, X20-21, X22-24 */
525 - hotkey_mask_supported =
526 - acpi_evalf(hkey_handle, NULL, "DHKN", "qv");
528 - if (!hotkey_get(&hotkey_orig_status, &hotkey_orig_mask))
529 - return -ENODEV;
532 - return 0;
535 static int hotkey_read(char *p)
537 int status, mask;
538 @@ -523,23 +612,9 @@ static int hotkey_write(char *buf)
539 return 0;
542 -static void hotkey_exit(void)
544 - if (hotkey_supported)
545 - hotkey_set(hotkey_orig_status, hotkey_orig_mask);
548 -static void hotkey_notify(struct ibm_struct *ibm, u32 event)
550 - int hkey;
552 - if (acpi_evalf(hkey_handle, &hkey, "MHKP", "d"))
553 - acpi_bus_generate_event(ibm->device, event, hkey);
554 - else {
555 - printk(IBM_ERR "unknown hotkey event %d\n", event);
556 - acpi_bus_generate_event(ibm->device, event, 0);
559 +/*************************************************************************
560 + * Bluetooth subdriver
561 + */
563 static int bluetooth_supported;
565 @@ -606,6 +681,10 @@ static int bluetooth_write(char *buf)
566 return 0;
569 +/*************************************************************************
570 + * Wan subdriver
571 + */
573 static int wan_supported;
575 static int wan_init(void)
576 @@ -668,9 +747,22 @@ static int wan_write(char *buf)
577 return 0;
580 +/*************************************************************************
581 + * Video subdriver
582 + */
584 static enum video_access_mode video_supported;
585 static int video_orig_autosw;
587 +IBM_HANDLE(vid, root, "\\_SB.PCI.AGP.VGA", /* 570 */
588 + "\\_SB.PCI0.AGP0.VID0", /* 600e/x, 770x */
589 + "\\_SB.PCI0.VID0", /* 770e */
590 + "\\_SB.PCI0.VID", /* A21e, G4x, R50e, X30, X40 */
591 + "\\_SB.PCI0.AGP.VID", /* all others */
592 + ); /* R30, R31 */
594 +IBM_HANDLE(vid2, root, "\\_SB.PCI0.AGPB.VID"); /* G41 */
596 static int video_init(void)
598 int ivga;
599 @@ -695,6 +787,11 @@ static int video_init(void)
600 return 0;
603 +static void video_exit(void)
605 + acpi_evalf(vid_handle, NULL, "_DOS", "vd", video_orig_autosw);
608 static int video_status(void)
610 int status = 0;
611 @@ -736,33 +833,6 @@ static int video_autosw(void)
612 return autosw & 1;
615 -static int video_read(char *p)
617 - int status = video_status();
618 - int autosw = video_autosw();
619 - int len = 0;
621 - if (!video_supported) {
622 - len += sprintf(p + len, "status:\t\tnot supported\n");
623 - return len;
626 - len += sprintf(p + len, "status:\t\tsupported\n");
627 - len += sprintf(p + len, "lcd:\t\t%s\n", enabled(status, 0));
628 - len += sprintf(p + len, "crt:\t\t%s\n", enabled(status, 1));
629 - if (video_supported == IBMACPI_VIDEO_NEW)
630 - len += sprintf(p + len, "dvi:\t\t%s\n", enabled(status, 3));
631 - len += sprintf(p + len, "auto:\t\t%s\n", enabled(autosw, 0));
632 - len += sprintf(p + len, "commands:\tlcd_enable, lcd_disable\n");
633 - len += sprintf(p + len, "commands:\tcrt_enable, crt_disable\n");
634 - if (video_supported == IBMACPI_VIDEO_NEW)
635 - len += sprintf(p + len, "commands:\tdvi_enable, dvi_disable\n");
636 - len += sprintf(p + len, "commands:\tauto_enable, auto_disable\n");
637 - len += sprintf(p + len, "commands:\tvideo_switch, expand_toggle\n");
639 - return len;
642 static int video_switch(void)
644 int autosw = video_autosw();
645 @@ -812,6 +882,33 @@ static int video_switch2(int status)
646 return ret;
649 +static int video_read(char *p)
651 + int status = video_status();
652 + int autosw = video_autosw();
653 + int len = 0;
655 + if (!video_supported) {
656 + len += sprintf(p + len, "status:\t\tnot supported\n");
657 + return len;
660 + len += sprintf(p + len, "status:\t\tsupported\n");
661 + len += sprintf(p + len, "lcd:\t\t%s\n", enabled(status, 0));
662 + len += sprintf(p + len, "crt:\t\t%s\n", enabled(status, 1));
663 + if (video_supported == IBMACPI_VIDEO_NEW)
664 + len += sprintf(p + len, "dvi:\t\t%s\n", enabled(status, 3));
665 + len += sprintf(p + len, "auto:\t\t%s\n", enabled(autosw, 0));
666 + len += sprintf(p + len, "commands:\tlcd_enable, lcd_disable\n");
667 + len += sprintf(p + len, "commands:\tcrt_enable, crt_disable\n");
668 + if (video_supported == IBMACPI_VIDEO_NEW)
669 + len += sprintf(p + len, "commands:\tdvi_enable, dvi_disable\n");
670 + len += sprintf(p + len, "commands:\tauto_enable, auto_disable\n");
671 + len += sprintf(p + len, "commands:\tvideo_switch, expand_toggle\n");
673 + return len;
676 static int video_write(char *buf)
678 char *cmd;
679 @@ -862,14 +959,16 @@ static int video_write(char *buf)
680 return 0;
683 -static void video_exit(void)
685 - acpi_evalf(vid_handle, NULL, "_DOS", "vd", video_orig_autosw);
687 +/*************************************************************************
688 + * Light (thinklight) subdriver
689 + */
691 static int light_supported;
692 static int light_status_supported;
694 +IBM_HANDLE(lght, root, "\\LGHT"); /* A21e, A2xm/p, T20-22, X20-21 */
695 +IBM_HANDLE(ledb, ec, "LEDB"); /* G4x */
697 static int light_init(void)
699 /* light not supported on 570, 600e/x, 770e, 770x, G4x, R30, R31 */
700 @@ -933,21 +1032,45 @@ static int light_write(char *buf)
701 return 0;
704 -#if defined(CONFIG_ACPI_IBM_DOCK) || defined(CONFIG_ACPI_IBM_BAY)
705 -static int _sta(acpi_handle handle)
707 - int status;
709 - if (!handle || !acpi_evalf(handle, &status, "_STA", "d"))
710 - status = 0;
711 +/*************************************************************************
712 + * Dock subdriver
713 + */
715 - return status;
717 -#endif
718 +/* don't list other alternatives as we install a notify handler on the 570 */
719 +IBM_HANDLE(pci, root, "\\_SB.PCI"); /* 570 */
721 #ifdef CONFIG_ACPI_IBM_DOCK
723 +IBM_HANDLE(dock, root, "\\_SB.GDCK", /* X30, X31, X40 */
724 + "\\_SB.PCI0.DOCK", /* 600e/x,770e,770x,A2xm/p,T20-22,X20-21 */
725 + "\\_SB.PCI0.PCI1.DOCK", /* all others */
726 + "\\_SB.PCI.ISA.SLCE", /* 570 */
727 + ); /* A21e,G4x,R30,R31,R32,R40,R40e,R50e */
729 #define dock_docked() (_sta(dock_handle) & 1)
731 +static void dock_notify(struct ibm_struct *ibm, u32 event)
733 + int docked = dock_docked();
734 + int pci = ibm->hid && strstr(ibm->hid, IBM_PCI_HID);
736 + if (event == 1 && !pci) /* 570 */
737 + acpi_bus_generate_event(ibm->device, event, 1); /* button */
738 + else if (event == 1 && pci) /* 570 */
739 + acpi_bus_generate_event(ibm->device, event, 3); /* dock */
740 + else if (event == 3 && docked)
741 + acpi_bus_generate_event(ibm->device, event, 1); /* button */
742 + else if (event == 3 && !docked)
743 + acpi_bus_generate_event(ibm->device, event, 2); /* undock */
744 + else if (event == 0 && docked)
745 + acpi_bus_generate_event(ibm->device, event, 3); /* dock */
746 + else {
747 + printk(IBM_ERR "unknown dock event %d, status %d\n",
748 + event, _sta(dock_handle));
749 + acpi_bus_generate_event(ibm->device, event, 0); /* unknown */
753 static int dock_read(char *p)
755 int len = 0;
756 @@ -987,28 +1110,11 @@ static int dock_write(char *buf)
757 return 0;
760 -static void dock_notify(struct ibm_struct *ibm, u32 event)
762 - int docked = dock_docked();
763 - int pci = ibm->hid && strstr(ibm->hid, IBM_PCI_HID);
764 +#endif /* CONFIG_ACPI_IBM_DOCK */
766 - if (event == 1 && !pci) /* 570 */
767 - acpi_bus_generate_event(ibm->device, event, 1); /* button */
768 - else if (event == 1 && pci) /* 570 */
769 - acpi_bus_generate_event(ibm->device, event, 3); /* dock */
770 - else if (event == 3 && docked)
771 - acpi_bus_generate_event(ibm->device, event, 1); /* button */
772 - else if (event == 3 && !docked)
773 - acpi_bus_generate_event(ibm->device, event, 2); /* undock */
774 - else if (event == 0 && docked)
775 - acpi_bus_generate_event(ibm->device, event, 3); /* dock */
776 - else {
777 - printk(IBM_ERR "unknown dock event %d, status %d\n",
778 - event, _sta(dock_handle));
779 - acpi_bus_generate_event(ibm->device, event, 0); /* unknown */
782 -#endif
783 +/*************************************************************************
784 + * Bay subdriver
785 + */
787 #ifdef CONFIG_ACPI_IBM_BAY
788 static int bay_status_supported;
789 @@ -1016,6 +1122,21 @@ static int bay_status2_supported;
790 static int bay_eject_supported;
791 static int bay_eject2_supported;
793 +IBM_HANDLE(bay, root, "\\_SB.PCI.IDE.SECN.MAST", /* 570 */
794 + "\\_SB.PCI0.IDE0.IDES.IDSM", /* 600e/x, 770e, 770x */
795 + "\\_SB.PCI0.SATA.SCND.MSTR", /* T60, X60, Z60 */
796 + "\\_SB.PCI0.IDE0.SCND.MSTR", /* all others */
797 + ); /* A21e, R30, R31 */
798 +IBM_HANDLE(bay_ej, bay, "_EJ3", /* 600e/x, A2xm/p, A3x */
799 + "_EJ0", /* all others */
800 + ); /* 570,A21e,G4x,R30,R31,R32,R40e,R50e */
801 +IBM_HANDLE(bay2, root, "\\_SB.PCI0.IDE0.PRIM.SLAV", /* A3x, R32 */
802 + "\\_SB.PCI0.IDE0.IDEP.IDPS", /* 600e/x, 770e, 770x */
803 + ); /* all others */
804 +IBM_HANDLE(bay2_ej, bay2, "_EJ3", /* 600e/x, 770e, A3x */
805 + "_EJ0", /* 770x */
806 + ); /* all others */
808 static int bay_init(void)
810 bay_status_supported = bay_handle &&
811 @@ -1031,6 +1152,11 @@ static int bay_init(void)
812 return 0;
815 +static void bay_notify(struct ibm_struct *ibm, u32 event)
817 + acpi_bus_generate_event(ibm->device, event, 0);
820 #define bay_occupied(b) (_sta(b##_handle) & 1)
822 static int bay_read(char *p)
823 @@ -1081,12 +1207,19 @@ static int bay_write(char *buf)
825 return 0;
827 +#endif /* CONFIG_ACPI_IBM_BAY */
829 -static void bay_notify(struct ibm_struct *ibm, u32 event)
830 +/*************************************************************************
831 + * CMOS subdriver
832 + */
834 +static int cmos_eval(int cmos_cmd)
836 - acpi_bus_generate_event(ibm->device, event, 0);
837 + if (cmos_handle)
838 + return acpi_evalf(cmos_handle, NULL, NULL, "vd", cmos_cmd);
839 + else
840 + return 1;
842 -#endif /* CONFIG_ACPI_IBM_BAY */
844 static int cmos_read(char *p)
846 @@ -1104,14 +1237,6 @@ static int cmos_read(char *p)
847 return len;
850 -static int cmos_eval(int cmos_cmd)
852 - if (cmos_handle)
853 - return acpi_evalf(cmos_handle, NULL, NULL, "vd", cmos_cmd);
854 - else
855 - return 1;
858 static int cmos_write(char *buf)
860 char *cmd;
861 @@ -1134,8 +1259,18 @@ static int cmos_write(char *buf)
862 return 0;
866 +/*************************************************************************
867 + * LED subdriver
868 + */
870 static enum led_access_mode led_supported;
872 +IBM_HANDLE(led, ec, "SLED", /* 570 */
873 + "SYSL", /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20-21 */
874 + "LED", /* all others */
875 + ); /* R30, R31 */
877 static int led_init(void)
879 if (!led_handle)
880 @@ -1242,6 +1377,12 @@ static int led_write(char *buf)
881 return 0;
884 +/*************************************************************************
885 + * Beep subdriver
886 + */
888 +IBM_HANDLE(beep, ec, "BEEP"); /* all except R30, R31 */
890 static int beep_read(char *p)
892 int len = 0;
893 @@ -1277,34 +1418,9 @@ static int beep_write(char *buf)
894 return 0;
897 -static int acpi_ec_read(int i, u8 * p)
899 - int v;
901 - if (ecrd_handle) {
902 - if (!acpi_evalf(ecrd_handle, &v, NULL, "dd", i))
903 - return 0;
904 - *p = v;
905 - } else {
906 - if (ec_read(i, p) < 0)
907 - return 0;
910 - return 1;
913 -static int acpi_ec_write(int i, u8 v)
915 - if (ecwr_handle) {
916 - if (!acpi_evalf(ecwr_handle, NULL, NULL, "vdd", i, v))
917 - return 0;
918 - } else {
919 - if (ec_write(i, v) < 0)
920 - return 0;
923 - return 1;
925 +/*************************************************************************
926 + * Thermal subdriver
927 + */
929 static enum thermal_access_mode thermal_read_mode;
931 @@ -1446,6 +1562,10 @@ static int thermal_read(char *p)
932 return len;
935 +/*************************************************************************
936 + * EC Dump subdriver
937 + */
939 static u8 ecdump_regs[256];
941 static int ecdump_read(char *p)
942 @@ -1505,6 +1625,55 @@ static int ecdump_write(char *buf)
943 return 0;
946 +/*************************************************************************
947 + * Backlight/brightness subdriver
948 + */
950 +static struct backlight_device *ibm_backlight_device = NULL;
952 +static struct backlight_ops ibm_backlight_data = {
953 + .get_brightness = brightness_get,
954 + .update_status = brightness_update_status,
957 +static int brightness_init(void)
959 + int b;
961 + b = brightness_get(NULL);
962 + if (b < 0)
963 + return b;
965 + ibm_backlight_device = backlight_device_register("ibm", NULL, NULL,
966 + &ibm_backlight_data);
967 + if (IS_ERR(ibm_backlight_device)) {
968 + printk(IBM_ERR "Could not register backlight device\n");
969 + return PTR_ERR(ibm_backlight_device);
972 + ibm_backlight_device->props.max_brightness = 7;
973 + ibm_backlight_device->props.brightness = b;
974 + backlight_update_status(ibm_backlight_device);
976 + return 0;
979 +static void brightness_exit(void)
981 + if (ibm_backlight_device) {
982 + backlight_device_unregister(ibm_backlight_device);
983 + ibm_backlight_device = NULL;
987 +static int brightness_update_status(struct backlight_device *bd)
989 + return brightness_set(
990 + (bd->props.fb_blank == FB_BLANK_UNBLANK &&
991 + bd->props.power == FB_BLANK_UNBLANK) ?
992 + bd->props.brightness : 0);
995 static int brightness_get(struct backlight_device *bd)
997 u8 level;
998 @@ -1516,23 +1685,6 @@ static int brightness_get(struct backlight_device *bd)
999 return level;
1002 -static int brightness_read(char *p)
1004 - int len = 0;
1005 - int level;
1007 - if ((level = brightness_get(NULL)) < 0) {
1008 - len += sprintf(p + len, "level:\t\tunreadable\n");
1009 - } else {
1010 - len += sprintf(p + len, "level:\t\t%d\n", level & 0x7);
1011 - len += sprintf(p + len, "commands:\tup, down\n");
1012 - len += sprintf(p + len, "commands:\tlevel <level>"
1013 - " (<level> is 0-7)\n");
1016 - return len;
1019 static int brightness_set(int value)
1021 int cmos_cmd, inc, i;
1022 @@ -1540,8 +1692,7 @@ static int brightness_set(int value)
1024 value &= 7;
1026 - cmos_cmd = value > current_value ?
1027 - TP_CMOS_BRIGHTNESS_UP : TP_CMOS_BRIGHTNESS_DOWN;
1028 + cmos_cmd = value > current_value ? TP_CMOS_BRIGHTNESS_UP : TP_CMOS_BRIGHTNESS_DOWN;
1029 inc = value > current_value ? 1 : -1;
1030 for (i = current_value; i != value; i += inc) {
1031 if (!cmos_eval(cmos_cmd))
1032 @@ -1553,6 +1704,23 @@ static int brightness_set(int value)
1033 return 0;
1036 +static int brightness_read(char *p)
1038 + int len = 0;
1039 + int level;
1041 + if ((level = brightness_get(NULL)) < 0) {
1042 + len += sprintf(p + len, "level:\t\tunreadable\n");
1043 + } else {
1044 + len += sprintf(p + len, "level:\t\t%d\n", level & 0x7);
1045 + len += sprintf(p + len, "commands:\tup, down\n");
1046 + len += sprintf(p + len, "commands:\tlevel <level>"
1047 + " (<level> is 0-7)\n");
1050 + return len;
1053 static int brightness_write(char *buf)
1055 int level;
1056 @@ -1580,48 +1748,9 @@ static int brightness_write(char *buf)
1057 return 0;
1060 -static int brightness_update_status(struct backlight_device *bd)
1062 - return brightness_set(
1063 - (bd->props.fb_blank == FB_BLANK_UNBLANK &&
1064 - bd->props.power == FB_BLANK_UNBLANK) ?
1065 - bd->props.brightness : 0);
1068 -static struct backlight_ops ibm_backlight_data = {
1069 - .get_brightness = brightness_get,
1070 - .update_status = brightness_update_status,
1073 -static int brightness_init(void)
1075 - int b;
1077 - b = brightness_get(NULL);
1078 - if (b < 0)
1079 - return b;
1081 - ibm_backlight_device = backlight_device_register("ibm", NULL, NULL,
1082 - &ibm_backlight_data);
1083 - if (IS_ERR(ibm_backlight_device)) {
1084 - printk(IBM_ERR "Could not register backlight device\n");
1085 - return PTR_ERR(ibm_backlight_device);
1088 - ibm_backlight_device->props.max_brightness = 7;
1089 - ibm_backlight_device->props.brightness = b;
1090 - backlight_update_status(ibm_backlight_device);
1092 - return 0;
1095 -static void brightness_exit(void)
1097 - if (ibm_backlight_device) {
1098 - backlight_device_unregister(ibm_backlight_device);
1099 - ibm_backlight_device = NULL;
1102 +/*************************************************************************
1103 + * Volume subdriver
1104 + */
1106 static int volume_read(char *p)
1108 @@ -1673,8 +1802,7 @@ static int volume_write(char *buf)
1109 return -EINVAL;
1111 if (new_level != level) { /* mute doesn't change */
1112 - cmos_cmd = new_level > level ?
1113 - TP_CMOS_VOLUME_UP : TP_CMOS_VOLUME_DOWN;
1114 + cmos_cmd = new_level > level ? TP_CMOS_VOLUME_UP : TP_CMOS_VOLUME_DOWN;
1115 inc = new_level > level ? 1 : -1;
1117 if (mute && (!cmos_eval(cmos_cmd) ||
1118 @@ -1693,8 +1821,7 @@ static int volume_write(char *buf)
1121 if (new_mute != mute) { /* level doesn't change */
1122 - cmos_cmd = new_mute ?
1123 - TP_CMOS_VOLUME_MUTE : TP_CMOS_VOLUME_UP;
1124 + cmos_cmd = new_mute ? TP_CMOS_VOLUME_MUTE : TP_CMOS_VOLUME_UP;
1126 if (!cmos_eval(cmos_cmd) ||
1127 !acpi_ec_write(volume_offset, level + new_mute))
1128 @@ -1705,6 +1832,111 @@ static int volume_write(char *buf)
1129 return 0;
1133 +/*************************************************************************
1134 + * Fan subdriver
1135 + */
1138 + * FAN ACCESS MODES
1140 + * IBMACPI_FAN_RD_ACPI_GFAN:
1141 + * ACPI GFAN method: returns fan level
1143 + * see IBMACPI_FAN_WR_ACPI_SFAN
1144 + * EC 0x2f not available if GFAN exists
1146 + * IBMACPI_FAN_WR_ACPI_SFAN:
1147 + * ACPI SFAN method: sets fan level, 0 (stop) to 7 (max)
1149 + * EC 0x2f might be available *for reading*, but never for writing.
1151 + * IBMACPI_FAN_WR_TPEC:
1152 + * ThinkPad EC register 0x2f (HFSP): fan control loop mode Supported
1153 + * on almost all ThinkPads
1155 + * Fan speed changes of any sort (including those caused by the
1156 + * disengaged mode) are usually done slowly by the firmware as the
1157 + * maximum ammount of fan duty cycle change per second seems to be
1158 + * limited.
1160 + * Reading is not available if GFAN exists.
1161 + * Writing is not available if SFAN exists.
1163 + * Bits
1164 + * 7 automatic mode engaged;
1165 + * (default operation mode of the ThinkPad)
1166 + * fan level is ignored in this mode.
1167 + * 6 disengage mode (takes precedence over bit 7);
1168 + * not available on all thinkpads. May disable
1169 + * the tachometer, and speeds up fan to 100% duty-cycle,
1170 + * which speeds it up far above the standard RPM
1171 + * levels. It is not impossible that it could cause
1172 + * hardware damage.
1173 + * 5-3 unused in some models. Extra bits for fan level
1174 + * in others, but still useless as all values above
1175 + * 7 map to the same speed as level 7 in these models.
1176 + * 2-0 fan level (0..7 usually)
1177 + * 0x00 = stop
1178 + * 0x07 = max (set when temperatures critical)
1179 + * Some ThinkPads may have other levels, see
1180 + * IBMACPI_FAN_WR_ACPI_FANS (X31/X40/X41)
1182 + * FIRMWARE BUG: on some models, EC 0x2f might not be initialized at
1183 + * boot. Apparently the EC does not intialize it, so unless ACPI DSDT
1184 + * does so, its initial value is meaningless (0x07).
1186 + * For firmware bugs, refer to:
1187 + * http://thinkwiki.org/wiki/Embedded_Controller_Firmware#Firmware_Issues
1189 + * ----
1191 + * ThinkPad EC register 0x84 (LSB), 0x85 (MSB):
1192 + * Main fan tachometer reading (in RPM)
1194 + * This register is present on all ThinkPads with a new-style EC, and
1195 + * it is known not to be present on the A21m/e, and T22, as there is
1196 + * something else in offset 0x84 according to the ACPI DSDT. Other
1197 + * ThinkPads from this same time period (and earlier) probably lack the
1198 + * tachometer as well.
1200 + * Unfortunately a lot of ThinkPads with new-style ECs but whose firwmare
1201 + * was never fixed by IBM to report the EC firmware version string
1202 + * probably support the tachometer (like the early X models), so
1203 + * detecting it is quite hard. We need more data to know for sure.
1205 + * FIRMWARE BUG: always read 0x84 first, otherwise incorrect readings
1206 + * might result.
1208 + * FIRMWARE BUG: when EC 0x2f bit 6 is set (disengaged mode), this
1209 + * register is not invalidated in ThinkPads that disable tachometer
1210 + * readings. Thus, the tachometer readings go stale.
1212 + * For firmware bugs, refer to:
1213 + * http://thinkwiki.org/wiki/Embedded_Controller_Firmware#Firmware_Issues
1215 + * IBMACPI_FAN_WR_ACPI_FANS:
1216 + * ThinkPad X31, X40, X41. Not available in the X60.
1218 + * FANS ACPI handle: takes three arguments: low speed, medium speed,
1219 + * high speed. ACPI DSDT seems to map these three speeds to levels
1220 + * as follows: STOP LOW LOW MED MED HIGH HIGH HIGH HIGH
1221 + * (this map is stored on FAN0..FAN8 as "0,1,1,2,2,3,3,3,3")
1223 + * The speeds are stored on handles
1224 + * (FANA:FAN9), (FANC:FANB), (FANE:FAND).
1226 + * There are three default speed sets, acessible as handles:
1227 + * FS1L,FS1M,FS1H; FS2L,FS2M,FS2H; FS3L,FS3M,FS3H
1229 + * ACPI DSDT switches which set is in use depending on various
1230 + * factors.
1232 + * IBMACPI_FAN_WR_TPEC is also available and should be used to
1233 + * command the fan. The X31/X40/X41 seems to have 8 fan levels,
1234 + * but the ACPI tables just mention level 7.
1235 + */
1237 static enum fan_status_access_mode fan_status_access_mode;
1238 static enum fan_control_access_mode fan_control_access_mode;
1239 static enum fan_control_commands fan_control_commands;
1240 @@ -1716,6 +1948,14 @@ static void fan_watchdog_fire(struct work_struct *ignored);
1241 static int fan_watchdog_maxinterval;
1242 static DECLARE_DELAYED_WORK(fan_watchdog_task, fan_watchdog_fire);
1244 +IBM_HANDLE(fans, ec, "FANS"); /* X31, X40, X41 */
1245 +IBM_HANDLE(gfan, ec, "GFAN", /* 570 */
1246 + "\\FSPD", /* 600e/x, 770e, 770x */
1247 + ); /* all others */
1248 +IBM_HANDLE(sfan, ec, "SFAN", /* 570 */
1249 + "JFNS", /* 770x-JL */
1250 + ); /* all others */
1252 static int fan_init(void)
1254 fan_status_access_mode = IBMACPI_FAN_NONE;
1255 @@ -1831,6 +2071,12 @@ static int fan_get_status(u8 *status)
1256 return 0;
1259 +static void fan_exit(void)
1261 + cancel_delayed_work(&fan_watchdog_task);
1262 + flush_scheduled_work();
1265 static int fan_get_speed(unsigned int *speed)
1267 u8 hi, lo;
1268 @@ -1854,10 +2100,14 @@ static int fan_get_speed(unsigned int *speed)
1269 return 0;
1272 -static void fan_exit(void)
1273 +static void fan_watchdog_fire(struct work_struct *ignored)
1275 - cancel_delayed_work(&fan_watchdog_task);
1276 - flush_scheduled_work();
1277 + printk(IBM_NOTICE "fan watchdog: enabling fan\n");
1278 + if (fan_set_enable()) {
1279 + printk(IBM_ERR "fan watchdog: error while enabling fan\n");
1280 + /* reschedule for later */
1281 + fan_watchdog_reset();
1285 static void fan_watchdog_reset(void)
1286 @@ -1879,90 +2129,6 @@ static void fan_watchdog_reset(void)
1287 fan_watchdog_active = 0;
1290 -static int fan_read(char *p)
1292 - int len = 0;
1293 - int rc;
1294 - u8 status;
1295 - unsigned int speed = 0;
1297 - switch (fan_status_access_mode) {
1298 - case IBMACPI_FAN_RD_ACPI_GFAN:
1299 - /* 570, 600e/x, 770e, 770x */
1300 - if ((rc = fan_get_status(&status)) < 0)
1301 - return rc;
1303 - len += sprintf(p + len, "status:\t\t%s\n"
1304 - "level:\t\t%d\n",
1305 - (status != 0) ? "enabled" : "disabled", status);
1306 - break;
1308 - case IBMACPI_FAN_RD_TPEC:
1309 - /* all except 570, 600e/x, 770e, 770x */
1310 - if ((rc = fan_get_status(&status)) < 0)
1311 - return rc;
1313 - if (unlikely(!fan_control_status_known)) {
1314 - if (status != fan_control_initial_status)
1315 - fan_control_status_known = 1;
1316 - else
1317 - /* Return most likely status. In fact, it
1318 - * might be the only possible status */
1319 - status = IBMACPI_FAN_EC_AUTO;
1322 - len += sprintf(p + len, "status:\t\t%s\n",
1323 - (status != 0) ? "enabled" : "disabled");
1325 - /* No ThinkPad boots on disengaged mode, we can safely
1326 - * assume the tachometer is online if fan control status
1327 - * was unknown */
1328 - if ((rc = fan_get_speed(&speed)) < 0)
1329 - return rc;
1331 - len += sprintf(p + len, "speed:\t\t%d\n", speed);
1333 - if (status & IBMACPI_FAN_EC_DISENGAGED)
1334 - /* Disengaged mode takes precedence */
1335 - len += sprintf(p + len, "level:\t\tdisengaged\n");
1336 - else if (status & IBMACPI_FAN_EC_AUTO)
1337 - len += sprintf(p + len, "level:\t\tauto\n");
1338 - else
1339 - len += sprintf(p + len, "level:\t\t%d\n", status);
1340 - break;
1342 - case IBMACPI_FAN_NONE:
1343 - default:
1344 - len += sprintf(p + len, "status:\t\tnot supported\n");
1347 - if (fan_control_commands & IBMACPI_FAN_CMD_LEVEL) {
1348 - len += sprintf(p + len, "commands:\tlevel <level>");
1350 - switch (fan_control_access_mode) {
1351 - case IBMACPI_FAN_WR_ACPI_SFAN:
1352 - len += sprintf(p + len, " (<level> is 0-7)\n");
1353 - break;
1355 - default:
1356 - len += sprintf(p + len, " (<level> is 0-7, "
1357 - "auto, disengaged)\n");
1358 - break;
1362 - if (fan_control_commands & IBMACPI_FAN_CMD_ENABLE)
1363 - len += sprintf(p + len, "commands:\tenable, disable\n"
1364 - "commands:\twatchdog <timeout> (<timeout> is 0 (off), "
1365 - "1-120 (seconds))\n");
1367 - if (fan_control_commands & IBMACPI_FAN_CMD_SPEED)
1368 - len += sprintf(p + len, "commands:\tspeed <speed>"
1369 - " (<speed> is 0-65535)\n");
1371 - return len;
1374 static int fan_set_level(int level)
1376 switch (fan_control_access_mode) {
1377 @@ -2074,6 +2240,90 @@ static int fan_set_speed(int speed)
1378 return 0;
1381 +static int fan_read(char *p)
1383 + int len = 0;
1384 + int rc;
1385 + u8 status;
1386 + unsigned int speed = 0;
1388 + switch (fan_status_access_mode) {
1389 + case IBMACPI_FAN_RD_ACPI_GFAN:
1390 + /* 570, 600e/x, 770e, 770x */
1391 + if ((rc = fan_get_status(&status)) < 0)
1392 + return rc;
1394 + len += sprintf(p + len, "status:\t\t%s\n"
1395 + "level:\t\t%d\n",
1396 + (status != 0) ? "enabled" : "disabled", status);
1397 + break;
1399 + case IBMACPI_FAN_RD_TPEC:
1400 + /* all except 570, 600e/x, 770e, 770x */
1401 + if ((rc = fan_get_status(&status)) < 0)
1402 + return rc;
1404 + if (unlikely(!fan_control_status_known)) {
1405 + if (status != fan_control_initial_status)
1406 + fan_control_status_known = 1;
1407 + else
1408 + /* Return most likely status. In fact, it
1409 + * might be the only possible status */
1410 + status = IBMACPI_FAN_EC_AUTO;
1413 + len += sprintf(p + len, "status:\t\t%s\n",
1414 + (status != 0) ? "enabled" : "disabled");
1416 + /* No ThinkPad boots on disengaged mode, we can safely
1417 + * assume the tachometer is online if fan control status
1418 + * was unknown */
1419 + if ((rc = fan_get_speed(&speed)) < 0)
1420 + return rc;
1422 + len += sprintf(p + len, "speed:\t\t%d\n", speed);
1424 + if (status & IBMACPI_FAN_EC_DISENGAGED)
1425 + /* Disengaged mode takes precedence */
1426 + len += sprintf(p + len, "level:\t\tdisengaged\n");
1427 + else if (status & IBMACPI_FAN_EC_AUTO)
1428 + len += sprintf(p + len, "level:\t\tauto\n");
1429 + else
1430 + len += sprintf(p + len, "level:\t\t%d\n", status);
1431 + break;
1433 + case IBMACPI_FAN_NONE:
1434 + default:
1435 + len += sprintf(p + len, "status:\t\tnot supported\n");
1438 + if (fan_control_commands & IBMACPI_FAN_CMD_LEVEL) {
1439 + len += sprintf(p + len, "commands:\tlevel <level>");
1441 + switch (fan_control_access_mode) {
1442 + case IBMACPI_FAN_WR_ACPI_SFAN:
1443 + len += sprintf(p + len, " (<level> is 0-7)\n");
1444 + break;
1446 + default:
1447 + len += sprintf(p + len, " (<level> is 0-7, "
1448 + "auto, disengaged)\n");
1449 + break;
1453 + if (fan_control_commands & IBMACPI_FAN_CMD_ENABLE)
1454 + len += sprintf(p + len, "commands:\tenable, disable\n"
1455 + "commands:\twatchdog <timeout> (<timeout> is 0 (off), "
1456 + "1-120 (seconds))\n");
1458 + if (fan_control_commands & IBMACPI_FAN_CMD_SPEED)
1459 + len += sprintf(p + len, "commands:\tspeed <speed>"
1460 + " (<speed> is 0-65535)\n");
1462 + return len;
1465 static int fan_write_cmd_level(const char *cmd, int *rc)
1467 int level;
1468 @@ -2171,16 +2421,18 @@ static int fan_write(char *buf)
1469 return rc;
1472 -static void fan_watchdog_fire(struct work_struct *ignored)
1474 - printk(IBM_NOTICE "fan watchdog: enabling fan\n");
1475 - if (fan_set_enable()) {
1476 - printk(IBM_ERR "fan watchdog: error while enabling fan\n");
1477 - /* reschedule for later */
1478 - fan_watchdog_reset();
1481 +/****************************************************************************
1482 + ****************************************************************************
1484 + * Infrastructure
1486 + ****************************************************************************
1487 + ****************************************************************************/
1489 +/* /proc support */
1490 +static struct proc_dir_entry *proc_dir = NULL;
1492 +/* Subdriver registry */
1493 static struct ibm_struct ibms[] = {
1495 .name = "driver",
1496 @@ -2301,132 +2553,9 @@ static struct ibm_struct ibms[] = {
1500 -static int dispatch_read(char *page, char **start, off_t off, int count,
1501 - int *eof, void *data)
1503 - struct ibm_struct *ibm = data;
1504 - int len;
1506 - if (!ibm || !ibm->read)
1507 - return -EINVAL;
1509 - len = ibm->read(page);
1510 - if (len < 0)
1511 - return len;
1513 - if (len <= off + count)
1514 - *eof = 1;
1515 - *start = page + off;
1516 - len -= off;
1517 - if (len > count)
1518 - len = count;
1519 - if (len < 0)
1520 - len = 0;
1522 - return len;
1525 -static int dispatch_write(struct file *file, const char __user * userbuf,
1526 - unsigned long count, void *data)
1528 - struct ibm_struct *ibm = data;
1529 - char *kernbuf;
1530 - int ret;
1532 - if (!ibm || !ibm->write)
1533 - return -EINVAL;
1535 - kernbuf = kmalloc(count + 2, GFP_KERNEL);
1536 - if (!kernbuf)
1537 - return -ENOMEM;
1539 - if (copy_from_user(kernbuf, userbuf, count)) {
1540 - kfree(kernbuf);
1541 - return -EFAULT;
1544 - kernbuf[count] = 0;
1545 - strcat(kernbuf, ",");
1546 - ret = ibm->write(kernbuf);
1547 - if (ret == 0)
1548 - ret = count;
1550 - kfree(kernbuf);
1552 - return ret;
1555 -static void dispatch_notify(acpi_handle handle, u32 event, void *data)
1557 - struct ibm_struct *ibm = data;
1559 - if (!ibm || !ibm->notify)
1560 - return;
1562 - ibm->notify(ibm, event);
1565 -static int __init setup_notify(struct ibm_struct *ibm)
1567 - acpi_status status;
1568 - int ret;
1570 - if (!*ibm->handle)
1571 - return 0;
1573 - ret = acpi_bus_get_device(*ibm->handle, &ibm->device);
1574 - if (ret < 0) {
1575 - printk(IBM_ERR "%s device not present\n", ibm->name);
1576 - return -ENODEV;
1579 - acpi_driver_data(ibm->device) = ibm;
1580 - sprintf(acpi_device_class(ibm->device), "%s/%s", IBM_NAME, ibm->name);
1582 - status = acpi_install_notify_handler(*ibm->handle, ibm->type,
1583 - dispatch_notify, ibm);
1584 - if (ACPI_FAILURE(status)) {
1585 - if (status == AE_ALREADY_EXISTS) {
1586 - printk(IBM_NOTICE "another device driver is already handling %s events\n",
1587 - ibm->name);
1588 - } else {
1589 - printk(IBM_ERR "acpi_install_notify_handler(%s) failed: %d\n",
1590 - ibm->name, status);
1592 - return -ENODEV;
1594 - ibm->notify_installed = 1;
1595 - return 0;
1598 -static int __init ibm_device_add(struct acpi_device *device)
1600 - return 0;
1603 -static int __init register_ibmacpi_subdriver(struct ibm_struct *ibm)
1605 - int ret;
1607 - ibm->driver = kzalloc(sizeof(struct acpi_driver), GFP_KERNEL);
1608 - if (!ibm->driver) {
1609 - printk(IBM_ERR "kmalloc(ibm->driver) failed\n");
1610 - return -1;
1613 - sprintf(ibm->driver->name, "%s_%s", IBM_NAME, ibm->name);
1614 - ibm->driver->ids = ibm->hid;
1615 - ibm->driver->ops.add = &ibm_device_add;
1617 - ret = acpi_bus_register_driver(ibm->driver);
1618 - if (ret < 0) {
1619 - printk(IBM_ERR "acpi_bus_register_driver(%s) failed: %d\n",
1620 - ibm->hid, ret);
1621 - kfree(ibm->driver);
1624 - return ret;
1627 + * Module and infrastructure proble, init and exit handling
1628 + */
1630 static int __init ibm_init(struct ibm_struct *ibm)
1632 @@ -2500,27 +2629,35 @@ static void ibm_exit(struct ibm_struct *ibm)
1636 -static void __init ibm_handle_init(char *name,
1637 - acpi_handle * handle, acpi_handle parent,
1638 - char **paths, int num_paths, char **path)
1639 +/* Probing */
1641 +static char *ibm_thinkpad_ec_found = NULL;
1643 +static char* __init check_dmi_for_ec(void)
1645 - int i;
1646 - acpi_status status;
1647 + struct dmi_device *dev = NULL;
1648 + char ec_fw_string[18];
1650 - for (i = 0; i < num_paths; i++) {
1651 - status = acpi_get_handle(parent, paths[i], handle);
1652 - if (ACPI_SUCCESS(status)) {
1653 - *path = paths[i];
1654 - return;
1655 + /*
1656 + * ThinkPad T23 or newer, A31 or newer, R50e or newer,
1657 + * X32 or newer, all Z series; Some models must have an
1658 + * up-to-date BIOS or they will not be detected.
1660 + * See http://thinkwiki.org/wiki/List_of_DMI_IDs
1661 + */
1662 + while ((dev = dmi_find_device(DMI_DEV_TYPE_OEM_STRING, NULL, dev))) {
1663 + if (sscanf(dev->name,
1664 + "IBM ThinkPad Embedded Controller -[%17c",
1665 + ec_fw_string) == 1) {
1666 + ec_fw_string[sizeof(ec_fw_string) - 1] = 0;
1667 + ec_fw_string[strcspn(ec_fw_string, " ]")] = 0;
1668 + return kstrdup(ec_fw_string, GFP_KERNEL);
1672 - *handle = NULL;
1673 + return NULL;
1676 -#define IBM_HANDLE_INIT(object) \
1677 - ibm_handle_init(#object, &object##_handle, *object##_parent, \
1678 - object##_paths, ARRAY_SIZE(object##_paths), &object##_path)
1679 +/* Module init, exit, parameters */
1681 static int __init set_ibm_param(const char *val, struct kernel_param *kp)
1683 @@ -2538,6 +2675,9 @@ static int __init set_ibm_param(const char *val, struct kernel_param *kp)
1684 return -EINVAL;
1687 +static int experimental;
1688 +module_param(experimental, int, 0);
1690 #define IBM_PARAM(feature) \
1691 module_param_call(feature, set_ibm_param, NULL, NULL, 0)
1693 @@ -2559,44 +2699,6 @@ IBM_PARAM(brightness);
1694 IBM_PARAM(volume);
1695 IBM_PARAM(fan);
1697 -static void acpi_ibm_exit(void)
1699 - int i;
1701 - for (i = ARRAY_SIZE(ibms) - 1; i >= 0; i--)
1702 - ibm_exit(&ibms[i]);
1704 - if (proc_dir)
1705 - remove_proc_entry(IBM_DIR, acpi_root_dir);
1707 - if (ibm_thinkpad_ec_found)
1708 - kfree(ibm_thinkpad_ec_found);
1711 -static char* __init check_dmi_for_ec(void)
1713 - struct dmi_device *dev = NULL;
1714 - char ec_fw_string[18];
1716 - /*
1717 - * ThinkPad T23 or newer, A31 or newer, R50e or newer,
1718 - * X32 or newer, all Z series; Some models must have an
1719 - * up-to-date BIOS or they will not be detected.
1721 - * See http://thinkwiki.org/wiki/List_of_DMI_IDs
1722 - */
1723 - while ((dev = dmi_find_device(DMI_DEV_TYPE_OEM_STRING, NULL, dev))) {
1724 - if (sscanf(dev->name,
1725 - "IBM ThinkPad Embedded Controller -[%17c",
1726 - ec_fw_string) == 1) {
1727 - ec_fw_string[sizeof(ec_fw_string) - 1] = 0;
1728 - ec_fw_string[strcspn(ec_fw_string, " ]")] = 0;
1729 - return kstrdup(ec_fw_string, GFP_KERNEL);
1732 - return NULL;
1735 static int __init acpi_ibm_init(void)
1737 int ret, i;
1738 @@ -2662,5 +2764,19 @@ static int __init acpi_ibm_init(void)
1739 return 0;
1742 +static void acpi_ibm_exit(void)
1744 + int i;
1746 + for (i = ARRAY_SIZE(ibms) - 1; i >= 0; i--)
1747 + ibm_exit(&ibms[i]);
1749 + if (proc_dir)
1750 + remove_proc_entry(IBM_DIR, acpi_root_dir);
1752 + if (ibm_thinkpad_ec_found)
1753 + kfree(ibm_thinkpad_ec_found);
1756 module_init(acpi_ibm_init);
1757 module_exit(acpi_ibm_exit);
1759 1.5.1