aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi/ibm_acpi.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@woody.osdl.org>2006-12-22 21:46:56 -0500
committerLinus Torvalds <torvalds@woody.osdl.org>2006-12-22 21:46:56 -0500
commit18ed1c051317ac3a685120cead2adb192b802347 (patch)
treec08a9147119a6cb69114166c7107f6b0bba6e2ab /drivers/acpi/ibm_acpi.c
parentdab6df63086762629936e8b89a5984bae39724f6 (diff)
parent36bcbec7ce21e2e8b3143b11a05747330abeca70 (diff)
Merge branch 'release' of git://git.kernel.org/pub/scm/linux/kernel/git/lenb/linux-acpi-2.6
* 'release' of git://git.kernel.org/pub/scm/linux/kernel/git/lenb/linux-acpi-2.6: (68 commits) ACPI: replace kmalloc+memset with kzalloc ACPI: Add support for acpi_load_table/acpi_unload_table_id fbdev: update after backlight argument change ACPI: video: Add dev argument for backlight_device_register ACPI: Implement acpi_video_get_next_level() ACPI: Kconfig - depend on PM rather than selecting it ACPI: fix NULL check in drivers/acpi/osl.c ACPI: make drivers/acpi/ec.c:ec_ecdt static ACPI: prevent processor module from loading on failures ACPI: fix single linked list manipulation ACPI: ibm_acpi: allow clean removal ACPI: fix git automerge failure ACPI: ibm_acpi: respond to workqueue update ACPI: dock: add uevent to indicate change in device status ACPI: ec: Lindent once again ACPI: ec: Change #define to enums there possible. ACPI: ec: Style changes. ACPI: ec: Acquire Global Lock under EC mutex. ACPI: ec: Drop udelay() from poll mode. Loop by reading status field instead. ACPI: ec: Rename gpe_bit to gpe ...
Diffstat (limited to 'drivers/acpi/ibm_acpi.c')
-rw-r--r--drivers/acpi/ibm_acpi.c1049
1 files changed, 891 insertions, 158 deletions
diff --git a/drivers/acpi/ibm_acpi.c b/drivers/acpi/ibm_acpi.c
index 5a8445959f67..b72d13d11a27 100644
--- a/drivers/acpi/ibm_acpi.c
+++ b/drivers/acpi/ibm_acpi.c
@@ -3,6 +3,7 @@
3 * 3 *
4 * 4 *
5 * Copyright (C) 2004-2005 Borislav Deianov <borislav@users.sf.net> 5 * Copyright (C) 2004-2005 Borislav Deianov <borislav@users.sf.net>
6 * Copyright (C) 2006 Henrique de Moraes Holschuh <hmh@hmh.eng.br>
6 * 7 *
7 * This program is free software; you can redistribute it and/or modify 8 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by 9 * it under the terms of the GNU General Public License as published by
@@ -19,10 +20,14 @@
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */ 21 */
21 22
22#define IBM_VERSION "0.12a" 23#define IBM_VERSION "0.13"
23 24
24/* 25/*
25 * Changelog: 26 * Changelog:
27 *
28 * 2006-11-22 0.13 new maintainer
29 * changelog now lives in git commit history, and will
30 * not be updated further in-file.
26 * 31 *
27 * 2005-08-17 0.12 fix compilation on 2.6.13-rc kernels 32 * 2005-08-17 0.12 fix compilation on 2.6.13-rc kernels
28 * 2005-03-17 0.11 support for 600e, 770x 33 * 2005-03-17 0.11 support for 600e, 770x
@@ -77,9 +82,16 @@
77#include <linux/module.h> 82#include <linux/module.h>
78#include <linux/init.h> 83#include <linux/init.h>
79#include <linux/types.h> 84#include <linux/types.h>
85#include <linux/string.h>
86
80#include <linux/proc_fs.h> 87#include <linux/proc_fs.h>
88#include <linux/backlight.h>
81#include <asm/uaccess.h> 89#include <asm/uaccess.h>
82 90
91#include <linux/dmi.h>
92#include <linux/jiffies.h>
93#include <linux/workqueue.h>
94
83#include <acpi/acpi_drivers.h> 95#include <acpi/acpi_drivers.h>
84#include <acpi/acnamesp.h> 96#include <acpi/acnamesp.h>
85 97
@@ -88,7 +100,7 @@
88#define IBM_FILE "ibm_acpi" 100#define IBM_FILE "ibm_acpi"
89#define IBM_URL "http://ibm-acpi.sf.net/" 101#define IBM_URL "http://ibm-acpi.sf.net/"
90 102
91MODULE_AUTHOR("Borislav Deianov"); 103MODULE_AUTHOR("Borislav Deianov, Henrique de Moraes Holschuh");
92MODULE_DESCRIPTION(IBM_DESC); 104MODULE_DESCRIPTION(IBM_DESC);
93MODULE_VERSION(IBM_VERSION); 105MODULE_VERSION(IBM_VERSION);
94MODULE_LICENSE("GPL"); 106MODULE_LICENSE("GPL");
@@ -116,28 +128,6 @@ static acpi_handle root_handle = NULL;
116 static char *object##_path; \ 128 static char *object##_path; \
117 static char *object##_paths[] = { paths } 129 static char *object##_paths[] = { paths }
118 130
119/*
120 * The following models are supported to various degrees:
121 *
122 * 570, 600e, 600x, 770e, 770x
123 * A20m, A21e, A21m, A21p, A22p, A30, A30p, A31, A31p
124 * G40, G41
125 * R30, R31, R32, R40, R40e, R50, R50e, R50p, R51
126 * T20, T21, T22, T23, T30, T40, T40p, T41, T41p, T42, T42p, T43
127 * X20, X21, X22, X23, X24, X30, X31, X40
128 *
129 * The following models have no supported features:
130 *
131 * 240, 240x, i1400
132 *
133 * Still missing DSDTs for the following models:
134 *
135 * A20p, A22e, A22m
136 * R52
137 * S31
138 * T43p
139 */
140
141IBM_HANDLE(ec, root, "\\_SB.PCI0.ISA.EC0", /* 240, 240x */ 131IBM_HANDLE(ec, root, "\\_SB.PCI0.ISA.EC0", /* 240, 240x */
142 "\\_SB.PCI.ISA.EC", /* 570 */ 132 "\\_SB.PCI.ISA.EC", /* 570 */
143 "\\_SB.PCI0.ISA0.EC0", /* 600e/x, 770e, 770x */ 133 "\\_SB.PCI0.ISA0.EC0", /* 600e/x, 770e, 770x */
@@ -167,8 +157,10 @@ IBM_HANDLE(dock, root, "\\_SB.GDCK", /* X30, X31, X40 */
167 "\\_SB.PCI.ISA.SLCE", /* 570 */ 157 "\\_SB.PCI.ISA.SLCE", /* 570 */
168 ); /* A21e,G4x,R30,R31,R32,R40,R40e,R50e */ 158 ); /* A21e,G4x,R30,R31,R32,R40,R40e,R50e */
169#endif 159#endif
160#ifdef CONFIG_ACPI_IBM_BAY
170IBM_HANDLE(bay, root, "\\_SB.PCI.IDE.SECN.MAST", /* 570 */ 161IBM_HANDLE(bay, root, "\\_SB.PCI.IDE.SECN.MAST", /* 570 */
171 "\\_SB.PCI0.IDE0.IDES.IDSM", /* 600e/x, 770e, 770x */ 162 "\\_SB.PCI0.IDE0.IDES.IDSM", /* 600e/x, 770e, 770x */
163 "\\_SB.PCI0.SATA.SCND.MSTR", /* T60, X60, Z60 */
172 "\\_SB.PCI0.IDE0.SCND.MSTR", /* all others */ 164 "\\_SB.PCI0.IDE0.SCND.MSTR", /* all others */
173 ); /* A21e, R30, R31 */ 165 ); /* A21e, R30, R31 */
174 166
@@ -183,6 +175,7 @@ IBM_HANDLE(bay2, root, "\\_SB.PCI0.IDE0.PRIM.SLAV", /* A3x, R32 */
183IBM_HANDLE(bay2_ej, bay2, "_EJ3", /* 600e/x, 770e, A3x */ 175IBM_HANDLE(bay2_ej, bay2, "_EJ3", /* 600e/x, 770e, A3x */
184 "_EJ0", /* 770x */ 176 "_EJ0", /* 770x */
185 ); /* all others */ 177 ); /* all others */
178#endif
186 179
187/* don't list other alternatives as we install a notify handler on the 570 */ 180/* don't list other alternatives as we install a notify handler on the 570 */
188IBM_HANDLE(pci, root, "\\_SB.PCI"); /* 570 */ 181IBM_HANDLE(pci, root, "\\_SB.PCI"); /* 570 */
@@ -203,7 +196,7 @@ IBM_HANDLE(led, ec, "SLED", /* 570 */
203IBM_HANDLE(beep, ec, "BEEP"); /* all except R30, R31 */ 196IBM_HANDLE(beep, ec, "BEEP"); /* all except R30, R31 */
204IBM_HANDLE(ecrd, ec, "ECRD"); /* 570 */ 197IBM_HANDLE(ecrd, ec, "ECRD"); /* 570 */
205IBM_HANDLE(ecwr, ec, "ECWR"); /* 570 */ 198IBM_HANDLE(ecwr, ec, "ECWR"); /* 570 */
206IBM_HANDLE(fans, ec, "FANS"); /* X31, X40 */ 199IBM_HANDLE(fans, ec, "FANS"); /* X31, X40, X41 */
207 200
208IBM_HANDLE(gfan, ec, "GFAN", /* 570 */ 201IBM_HANDLE(gfan, ec, "GFAN", /* 570 */
209 "\\FSPD", /* 600e/x, 770e, 770x */ 202 "\\FSPD", /* 600e/x, 770e, 770x */
@@ -216,6 +209,152 @@ IBM_HANDLE(sfan, ec, "SFAN", /* 570 */
216#define IBM_HKEY_HID "IBM0068" 209#define IBM_HKEY_HID "IBM0068"
217#define IBM_PCI_HID "PNP0A03" 210#define IBM_PCI_HID "PNP0A03"
218 211
212enum thermal_access_mode {
213 IBMACPI_THERMAL_NONE = 0, /* No thermal support */
214 IBMACPI_THERMAL_ACPI_TMP07, /* Use ACPI TMP0-7 */
215 IBMACPI_THERMAL_ACPI_UPDT, /* Use ACPI TMP0-7 with UPDT */
216 IBMACPI_THERMAL_TPEC_8, /* Use ACPI EC regs, 8 sensors */
217 IBMACPI_THERMAL_TPEC_16, /* Use ACPI EC regs, 16 sensors */
218};
219
220#define IBMACPI_MAX_THERMAL_SENSORS 16 /* Max thermal sensors supported */
221struct ibm_thermal_sensors_struct {
222 s32 temp[IBMACPI_MAX_THERMAL_SENSORS];
223};
224
225/*
226 * FAN ACCESS MODES
227 *
228 * IBMACPI_FAN_RD_ACPI_GFAN:
229 * ACPI GFAN method: returns fan level
230 *
231 * see IBMACPI_FAN_WR_ACPI_SFAN
232 * EC 0x2f not available if GFAN exists
233 *
234 * IBMACPI_FAN_WR_ACPI_SFAN:
235 * ACPI SFAN method: sets fan level, 0 (stop) to 7 (max)
236 *
237 * EC 0x2f might be available *for reading*, but never for writing.
238 *
239 * IBMACPI_FAN_WR_TPEC:
240 * ThinkPad EC register 0x2f (HFSP): fan control loop mode Supported
241 * on almost all ThinkPads
242 *
243 * Fan speed changes of any sort (including those caused by the
244 * disengaged mode) are usually done slowly by the firmware as the
245 * maximum ammount of fan duty cycle change per second seems to be
246 * limited.
247 *
248 * Reading is not available if GFAN exists.
249 * Writing is not available if SFAN exists.
250 *
251 * Bits
252 * 7 automatic mode engaged;
253 * (default operation mode of the ThinkPad)
254 * fan level is ignored in this mode.
255 * 6 disengage mode (takes precedence over bit 7);
256 * not available on all thinkpads. May disable
257 * the tachometer, and speeds up fan to 100% duty-cycle,
258 * which speeds it up far above the standard RPM
259 * levels. It is not impossible that it could cause
260 * hardware damage.
261 * 5-3 unused in some models. Extra bits for fan level
262 * in others, but still useless as all values above
263 * 7 map to the same speed as level 7 in these models.
264 * 2-0 fan level (0..7 usually)
265 * 0x00 = stop
266 * 0x07 = max (set when temperatures critical)
267 * Some ThinkPads may have other levels, see
268 * IBMACPI_FAN_WR_ACPI_FANS (X31/X40/X41)
269 *
270 * FIRMWARE BUG: on some models, EC 0x2f might not be initialized at
271 * boot. Apparently the EC does not intialize it, so unless ACPI DSDT
272 * does so, its initial value is meaningless (0x07).
273 *
274 * For firmware bugs, refer to:
275 * http://thinkwiki.org/wiki/Embedded_Controller_Firmware#Firmware_Issues
276 *
277 * ----
278 *
279 * ThinkPad EC register 0x84 (LSB), 0x85 (MSB):
280 * Main fan tachometer reading (in RPM)
281 *
282 * This register is present on all ThinkPads with a new-style EC, and
283 * it is known not to be present on the A21m/e, and T22, as there is
284 * something else in offset 0x84 according to the ACPI DSDT. Other
285 * ThinkPads from this same time period (and earlier) probably lack the
286 * tachometer as well.
287 *
288 * Unfortunately a lot of ThinkPads with new-style ECs but whose firwmare
289 * was never fixed by IBM to report the EC firmware version string
290 * probably support the tachometer (like the early X models), so
291 * detecting it is quite hard. We need more data to know for sure.
292 *
293 * FIRMWARE BUG: always read 0x84 first, otherwise incorrect readings
294 * might result.
295 *
296 * FIRMWARE BUG: when EC 0x2f bit 6 is set (disengaged mode), this
297 * register is not invalidated in ThinkPads that disable tachometer
298 * readings. Thus, the tachometer readings go stale.
299 *
300 * For firmware bugs, refer to:
301 * http://thinkwiki.org/wiki/Embedded_Controller_Firmware#Firmware_Issues
302 *
303 * IBMACPI_FAN_WR_ACPI_FANS:
304 * ThinkPad X31, X40, X41. Not available in the X60.
305 *
306 * FANS ACPI handle: takes three arguments: low speed, medium speed,
307 * high speed. ACPI DSDT seems to map these three speeds to levels
308 * as follows: STOP LOW LOW MED MED HIGH HIGH HIGH HIGH
309 * (this map is stored on FAN0..FAN8 as "0,1,1,2,2,3,3,3,3")
310 *
311 * The speeds are stored on handles
312 * (FANA:FAN9), (FANC:FANB), (FANE:FAND).
313 *
314 * There are three default speed sets, acessible as handles:
315 * FS1L,FS1M,FS1H; FS2L,FS2M,FS2H; FS3L,FS3M,FS3H
316 *
317 * ACPI DSDT switches which set is in use depending on various
318 * factors.
319 *
320 * IBMACPI_FAN_WR_TPEC is also available and should be used to
321 * command the fan. The X31/X40/X41 seems to have 8 fan levels,
322 * but the ACPI tables just mention level 7.
323 */
324
325enum fan_status_access_mode {
326 IBMACPI_FAN_NONE = 0, /* No fan status or control */
327 IBMACPI_FAN_RD_ACPI_GFAN, /* Use ACPI GFAN */
328 IBMACPI_FAN_RD_TPEC, /* Use ACPI EC regs 0x2f, 0x84-0x85 */
329};
330
331enum fan_control_access_mode {
332 IBMACPI_FAN_WR_NONE = 0, /* No fan control */
333 IBMACPI_FAN_WR_ACPI_SFAN, /* Use ACPI SFAN */
334 IBMACPI_FAN_WR_TPEC, /* Use ACPI EC reg 0x2f */
335 IBMACPI_FAN_WR_ACPI_FANS, /* Use ACPI FANS and EC reg 0x2f */
336};
337
338enum fan_control_commands {
339 IBMACPI_FAN_CMD_SPEED = 0x0001, /* speed command */
340 IBMACPI_FAN_CMD_LEVEL = 0x0002, /* level command */
341 IBMACPI_FAN_CMD_ENABLE = 0x0004, /* enable/disable cmd,
342 * and also watchdog cmd */
343};
344
345enum { /* Fan control constants */
346 fan_status_offset = 0x2f, /* EC register 0x2f */
347 fan_rpm_offset = 0x84, /* EC register 0x84: LSB, 0x85 MSB (RPM)
348 * 0x84 must be read before 0x85 */
349
350 IBMACPI_FAN_EC_DISENGAGED = 0x40, /* EC mode: tachometer
351 * disengaged */
352 IBMACPI_FAN_EC_AUTO = 0x80, /* EC mode: auto fan
353 * control */
354};
355
356static char *ibm_thinkpad_ec_found = NULL;
357
219struct ibm_struct { 358struct ibm_struct {
220 char *name; 359 char *name;
221 char param[32]; 360 char param[32];
@@ -243,6 +382,8 @@ struct ibm_struct {
243 382
244static struct proc_dir_entry *proc_dir = NULL; 383static struct proc_dir_entry *proc_dir = NULL;
245 384
385static struct backlight_device *ibm_backlight_device = NULL;
386
246#define onoff(status,bit) ((status) & (1 << (bit)) ? "on" : "off") 387#define onoff(status,bit) ((status) & (1 << (bit)) ? "on" : "off")
247#define enabled(status,bit) ((status) & (1 << (bit)) ? "enabled" : "disabled") 388#define enabled(status,bit) ((status) & (1 << (bit)) ? "enabled" : "disabled")
248#define strlencmp(a,b) (strncmp((a), (b), strlen(b))) 389#define strlencmp(a,b) (strncmp((a), (b), strlen(b)))
@@ -581,8 +722,7 @@ static int wan_status(void)
581{ 722{
582 int status; 723 int status;
583 724
584 if (!wan_supported || 725 if (!wan_supported || !acpi_evalf(hkey_handle, &status, "GWAN", "d"))
585 !acpi_evalf(hkey_handle, &status, "GWAN", "d"))
586 status = 0; 726 status = 0;
587 727
588 return status; 728 return status;
@@ -630,12 +770,15 @@ static int wan_write(char *buf)
630 return 0; 770 return 0;
631} 771}
632 772
633static int video_supported; 773enum video_access_mode {
634static int video_orig_autosw; 774 IBMACPI_VIDEO_NONE = 0,
775 IBMACPI_VIDEO_570, /* 570 */
776 IBMACPI_VIDEO_770, /* 600e/x, 770e, 770x */
777 IBMACPI_VIDEO_NEW, /* all others */
778};
635 779
636#define VIDEO_570 1 780static enum video_access_mode video_supported;
637#define VIDEO_770 2 781static int video_orig_autosw;
638#define VIDEO_NEW 3
639 782
640static int video_init(void) 783static int video_init(void)
641{ 784{
@@ -647,16 +790,16 @@ static int video_init(void)
647 790
648 if (!vid_handle) 791 if (!vid_handle)
649 /* video switching not supported on R30, R31 */ 792 /* video switching not supported on R30, R31 */
650 video_supported = 0; 793 video_supported = IBMACPI_VIDEO_NONE;
651 else if (acpi_evalf(vid_handle, &video_orig_autosw, "SWIT", "qd")) 794 else if (acpi_evalf(vid_handle, &video_orig_autosw, "SWIT", "qd"))
652 /* 570 */ 795 /* 570 */
653 video_supported = VIDEO_570; 796 video_supported = IBMACPI_VIDEO_570;
654 else if (acpi_evalf(vid_handle, &video_orig_autosw, "^VADL", "qd")) 797 else if (acpi_evalf(vid_handle, &video_orig_autosw, "^VADL", "qd"))
655 /* 600e/x, 770e, 770x */ 798 /* 600e/x, 770e, 770x */
656 video_supported = VIDEO_770; 799 video_supported = IBMACPI_VIDEO_770;
657 else 800 else
658 /* all others */ 801 /* all others */
659 video_supported = VIDEO_NEW; 802 video_supported = IBMACPI_VIDEO_NEW;
660 803
661 return 0; 804 return 0;
662} 805}
@@ -666,15 +809,15 @@ static int video_status(void)
666 int status = 0; 809 int status = 0;
667 int i; 810 int i;
668 811
669 if (video_supported == VIDEO_570) { 812 if (video_supported == IBMACPI_VIDEO_570) {
670 if (acpi_evalf(NULL, &i, "\\_SB.PHS", "dd", 0x87)) 813 if (acpi_evalf(NULL, &i, "\\_SB.PHS", "dd", 0x87))
671 status = i & 3; 814 status = i & 3;
672 } else if (video_supported == VIDEO_770) { 815 } else if (video_supported == IBMACPI_VIDEO_770) {
673 if (acpi_evalf(NULL, &i, "\\VCDL", "d")) 816 if (acpi_evalf(NULL, &i, "\\VCDL", "d"))
674 status |= 0x01 * i; 817 status |= 0x01 * i;
675 if (acpi_evalf(NULL, &i, "\\VCDC", "d")) 818 if (acpi_evalf(NULL, &i, "\\VCDC", "d"))
676 status |= 0x02 * i; 819 status |= 0x02 * i;
677 } else if (video_supported == VIDEO_NEW) { 820 } else if (video_supported == IBMACPI_VIDEO_NEW) {
678 acpi_evalf(NULL, NULL, "\\VUPS", "vd", 1); 821 acpi_evalf(NULL, NULL, "\\VUPS", "vd", 1);
679 if (acpi_evalf(NULL, &i, "\\VCDC", "d")) 822 if (acpi_evalf(NULL, &i, "\\VCDC", "d"))
680 status |= 0x02 * i; 823 status |= 0x02 * i;
@@ -693,9 +836,10 @@ static int video_autosw(void)
693{ 836{
694 int autosw = 0; 837 int autosw = 0;
695 838
696 if (video_supported == VIDEO_570) 839 if (video_supported == IBMACPI_VIDEO_570)
697 acpi_evalf(vid_handle, &autosw, "SWIT", "d"); 840 acpi_evalf(vid_handle, &autosw, "SWIT", "d");
698 else if (video_supported == VIDEO_770 || video_supported == VIDEO_NEW) 841 else if (video_supported == IBMACPI_VIDEO_770 ||
842 video_supported == IBMACPI_VIDEO_NEW)
699 acpi_evalf(vid_handle, &autosw, "^VDEE", "d"); 843 acpi_evalf(vid_handle, &autosw, "^VDEE", "d");
700 844
701 return autosw & 1; 845 return autosw & 1;
@@ -715,12 +859,12 @@ static int video_read(char *p)
715 len += sprintf(p + len, "status:\t\tsupported\n"); 859 len += sprintf(p + len, "status:\t\tsupported\n");
716 len += sprintf(p + len, "lcd:\t\t%s\n", enabled(status, 0)); 860 len += sprintf(p + len, "lcd:\t\t%s\n", enabled(status, 0));
717 len += sprintf(p + len, "crt:\t\t%s\n", enabled(status, 1)); 861 len += sprintf(p + len, "crt:\t\t%s\n", enabled(status, 1));
718 if (video_supported == VIDEO_NEW) 862 if (video_supported == IBMACPI_VIDEO_NEW)
719 len += sprintf(p + len, "dvi:\t\t%s\n", enabled(status, 3)); 863 len += sprintf(p + len, "dvi:\t\t%s\n", enabled(status, 3));
720 len += sprintf(p + len, "auto:\t\t%s\n", enabled(autosw, 0)); 864 len += sprintf(p + len, "auto:\t\t%s\n", enabled(autosw, 0));
721 len += sprintf(p + len, "commands:\tlcd_enable, lcd_disable\n"); 865 len += sprintf(p + len, "commands:\tlcd_enable, lcd_disable\n");
722 len += sprintf(p + len, "commands:\tcrt_enable, crt_disable\n"); 866 len += sprintf(p + len, "commands:\tcrt_enable, crt_disable\n");
723 if (video_supported == VIDEO_NEW) 867 if (video_supported == IBMACPI_VIDEO_NEW)
724 len += sprintf(p + len, "commands:\tdvi_enable, dvi_disable\n"); 868 len += sprintf(p + len, "commands:\tdvi_enable, dvi_disable\n");
725 len += sprintf(p + len, "commands:\tauto_enable, auto_disable\n"); 869 len += sprintf(p + len, "commands:\tauto_enable, auto_disable\n");
726 len += sprintf(p + len, "commands:\tvideo_switch, expand_toggle\n"); 870 len += sprintf(p + len, "commands:\tvideo_switch, expand_toggle\n");
@@ -735,7 +879,7 @@ static int video_switch(void)
735 879
736 if (!acpi_evalf(vid_handle, NULL, "_DOS", "vd", 1)) 880 if (!acpi_evalf(vid_handle, NULL, "_DOS", "vd", 1))
737 return -EIO; 881 return -EIO;
738 ret = video_supported == VIDEO_570 ? 882 ret = video_supported == IBMACPI_VIDEO_570 ?
739 acpi_evalf(ec_handle, NULL, "_Q16", "v") : 883 acpi_evalf(ec_handle, NULL, "_Q16", "v") :
740 acpi_evalf(vid_handle, NULL, "VSWT", "v"); 884 acpi_evalf(vid_handle, NULL, "VSWT", "v");
741 acpi_evalf(vid_handle, NULL, "_DOS", "vd", autosw); 885 acpi_evalf(vid_handle, NULL, "_DOS", "vd", autosw);
@@ -745,9 +889,9 @@ static int video_switch(void)
745 889
746static int video_expand(void) 890static int video_expand(void)
747{ 891{
748 if (video_supported == VIDEO_570) 892 if (video_supported == IBMACPI_VIDEO_570)
749 return acpi_evalf(ec_handle, NULL, "_Q17", "v"); 893 return acpi_evalf(ec_handle, NULL, "_Q17", "v");
750 else if (video_supported == VIDEO_770) 894 else if (video_supported == IBMACPI_VIDEO_770)
751 return acpi_evalf(vid_handle, NULL, "VEXP", "v"); 895 return acpi_evalf(vid_handle, NULL, "VEXP", "v");
752 else 896 else
753 return acpi_evalf(NULL, NULL, "\\VEXP", "v"); 897 return acpi_evalf(NULL, NULL, "\\VEXP", "v");
@@ -757,10 +901,10 @@ static int video_switch2(int status)
757{ 901{
758 int ret; 902 int ret;
759 903
760 if (video_supported == VIDEO_570) { 904 if (video_supported == IBMACPI_VIDEO_570) {
761 ret = acpi_evalf(NULL, NULL, 905 ret = acpi_evalf(NULL, NULL,
762 "\\_SB.PHS2", "vdd", 0x8b, status | 0x80); 906 "\\_SB.PHS2", "vdd", 0x8b, status | 0x80);
763 } else if (video_supported == VIDEO_770) { 907 } else if (video_supported == IBMACPI_VIDEO_770) {
764 int autosw = video_autosw(); 908 int autosw = video_autosw();
765 if (!acpi_evalf(vid_handle, NULL, "_DOS", "vd", 1)) 909 if (!acpi_evalf(vid_handle, NULL, "_DOS", "vd", 1))
766 return -EIO; 910 return -EIO;
@@ -796,10 +940,10 @@ static int video_write(char *buf)
796 enable |= 0x02; 940 enable |= 0x02;
797 } else if (strlencmp(cmd, "crt_disable") == 0) { 941 } else if (strlencmp(cmd, "crt_disable") == 0) {
798 disable |= 0x02; 942 disable |= 0x02;
799 } else if (video_supported == VIDEO_NEW && 943 } else if (video_supported == IBMACPI_VIDEO_NEW &&
800 strlencmp(cmd, "dvi_enable") == 0) { 944 strlencmp(cmd, "dvi_enable") == 0) {
801 enable |= 0x08; 945 enable |= 0x08;
802 } else if (video_supported == VIDEO_NEW && 946 } else if (video_supported == IBMACPI_VIDEO_NEW &&
803 strlencmp(cmd, "dvi_disable") == 0) { 947 strlencmp(cmd, "dvi_disable") == 0) {
804 disable |= 0x08; 948 disable |= 0x08;
805 } else if (strlencmp(cmd, "auto_enable") == 0) { 949 } else if (strlencmp(cmd, "auto_enable") == 0) {
@@ -898,6 +1042,7 @@ static int light_write(char *buf)
898 return 0; 1042 return 0;
899} 1043}
900 1044
1045#if defined(CONFIG_ACPI_IBM_DOCK) || defined(CONFIG_ACPI_IBM_BAY)
901static int _sta(acpi_handle handle) 1046static int _sta(acpi_handle handle)
902{ 1047{
903 int status; 1048 int status;
@@ -907,6 +1052,7 @@ static int _sta(acpi_handle handle)
907 1052
908 return status; 1053 return status;
909} 1054}
1055#endif
910#ifdef CONFIG_ACPI_IBM_DOCK 1056#ifdef CONFIG_ACPI_IBM_DOCK
911#define dock_docked() (_sta(dock_handle) & 1) 1057#define dock_docked() (_sta(dock_handle) & 1)
912 1058
@@ -972,6 +1118,7 @@ static void dock_notify(struct ibm_struct *ibm, u32 event)
972} 1118}
973#endif 1119#endif
974 1120
1121#ifdef CONFIG_ACPI_IBM_BAY
975static int bay_status_supported; 1122static int bay_status_supported;
976static int bay_status2_supported; 1123static int bay_status2_supported;
977static int bay_eject_supported; 1124static int bay_eject_supported;
@@ -1047,6 +1194,7 @@ static void bay_notify(struct ibm_struct *ibm, u32 event)
1047{ 1194{
1048 acpi_bus_generate_event(ibm->device, event, 0); 1195 acpi_bus_generate_event(ibm->device, event, 0);
1049} 1196}
1197#endif
1050 1198
1051static int cmos_read(char *p) 1199static int cmos_read(char *p)
1052{ 1200{
@@ -1094,26 +1242,28 @@ static int cmos_write(char *buf)
1094 return 0; 1242 return 0;
1095} 1243}
1096 1244
1097static int led_supported; 1245enum led_access_mode {
1098 1246 IBMACPI_LED_NONE = 0,
1099#define LED_570 1 1247 IBMACPI_LED_570, /* 570 */
1100#define LED_OLD 2 1248 IBMACPI_LED_OLD, /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20-21 */
1101#define LED_NEW 3 1249 IBMACPI_LED_NEW, /* all others */
1250};
1251static enum led_access_mode led_supported;
1102 1252
1103static int led_init(void) 1253static int led_init(void)
1104{ 1254{
1105 if (!led_handle) 1255 if (!led_handle)
1106 /* led not supported on R30, R31 */ 1256 /* led not supported on R30, R31 */
1107 led_supported = 0; 1257 led_supported = IBMACPI_LED_NONE;
1108 else if (strlencmp(led_path, "SLED") == 0) 1258 else if (strlencmp(led_path, "SLED") == 0)
1109 /* 570 */ 1259 /* 570 */
1110 led_supported = LED_570; 1260 led_supported = IBMACPI_LED_570;
1111 else if (strlencmp(led_path, "SYSL") == 0) 1261 else if (strlencmp(led_path, "SYSL") == 0)
1112 /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20-21 */ 1262 /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20-21 */
1113 led_supported = LED_OLD; 1263 led_supported = IBMACPI_LED_OLD;
1114 else 1264 else
1115 /* all others */ 1265 /* all others */
1116 led_supported = LED_NEW; 1266 led_supported = IBMACPI_LED_NEW;
1117 1267
1118 return 0; 1268 return 0;
1119} 1269}
@@ -1130,7 +1280,7 @@ static int led_read(char *p)
1130 } 1280 }
1131 len += sprintf(p + len, "status:\t\tsupported\n"); 1281 len += sprintf(p + len, "status:\t\tsupported\n");
1132 1282
1133 if (led_supported == LED_570) { 1283 if (led_supported == IBMACPI_LED_570) {
1134 /* 570 */ 1284 /* 570 */
1135 int i, status; 1285 int i, status;
1136 for (i = 0; i < 8; i++) { 1286 for (i = 0; i < 8; i++) {
@@ -1179,13 +1329,13 @@ static int led_write(char *buf)
1179 } else 1329 } else
1180 return -EINVAL; 1330 return -EINVAL;
1181 1331
1182 if (led_supported == LED_570) { 1332 if (led_supported == IBMACPI_LED_570) {
1183 /* 570 */ 1333 /* 570 */
1184 led = 1 << led; 1334 led = 1 << led;
1185 if (!acpi_evalf(led_handle, NULL, NULL, "vdd", 1335 if (!acpi_evalf(led_handle, NULL, NULL, "vdd",
1186 led, led_sled_arg1[ind])) 1336 led, led_sled_arg1[ind]))
1187 return -EIO; 1337 return -EIO;
1188 } else if (led_supported == LED_OLD) { 1338 } else if (led_supported == IBMACPI_LED_OLD) {
1189 /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20 */ 1339 /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20 */
1190 led = 1 << led; 1340 led = 1 << led;
1191 ret = ec_write(EC_HLMS, led); 1341 ret = ec_write(EC_HLMS, led);
@@ -1272,50 +1422,142 @@ static int acpi_ec_write(int i, u8 v)
1272 return 1; 1422 return 1;
1273} 1423}
1274 1424
1275static int thermal_tmp_supported; 1425static enum thermal_access_mode thermal_read_mode;
1276static int thermal_updt_supported;
1277 1426
1278static int thermal_init(void) 1427static int thermal_init(void)
1279{ 1428{
1280 /* temperatures not supported on 570, G4x, R30, R31, R32 */ 1429 u8 t, ta1, ta2;
1281 thermal_tmp_supported = acpi_evalf(ec_handle, NULL, "TMP7", "qv"); 1430 int i;
1431 int acpi_tmp7 = acpi_evalf(ec_handle, NULL, "TMP7", "qv");
1432
1433 if (ibm_thinkpad_ec_found && experimental) {
1434 /*
1435 * Direct EC access mode: sensors at registers
1436 * 0x78-0x7F, 0xC0-0xC7. Registers return 0x00 for
1437 * non-implemented, thermal sensors return 0x80 when
1438 * not available
1439 */
1282 1440
1283 /* 600e/x, 770e, 770x */ 1441 ta1 = ta2 = 0;
1284 thermal_updt_supported = acpi_evalf(ec_handle, NULL, "UPDT", "qv"); 1442 for (i = 0; i < 8; i++) {
1443 if (likely(acpi_ec_read(0x78 + i, &t))) {
1444 ta1 |= t;
1445 } else {
1446 ta1 = 0;
1447 break;
1448 }
1449 if (likely(acpi_ec_read(0xC0 + i, &t))) {
1450 ta2 |= t;
1451 } else {
1452 ta1 = 0;
1453 break;
1454 }
1455 }
1456 if (ta1 == 0) {
1457 /* This is sheer paranoia, but we handle it anyway */
1458 if (acpi_tmp7) {
1459 printk(IBM_ERR
1460 "ThinkPad ACPI EC access misbehaving, "
1461 "falling back to ACPI TMPx access mode\n");
1462 thermal_read_mode = IBMACPI_THERMAL_ACPI_TMP07;
1463 } else {
1464 printk(IBM_ERR
1465 "ThinkPad ACPI EC access misbehaving, "
1466 "disabling thermal sensors access\n");
1467 thermal_read_mode = IBMACPI_THERMAL_NONE;
1468 }
1469 } else {
1470 thermal_read_mode =
1471 (ta2 != 0) ?
1472 IBMACPI_THERMAL_TPEC_16 : IBMACPI_THERMAL_TPEC_8;
1473 }
1474 } else if (acpi_tmp7) {
1475 if (acpi_evalf(ec_handle, NULL, "UPDT", "qv")) {
1476 /* 600e/x, 770e, 770x */
1477 thermal_read_mode = IBMACPI_THERMAL_ACPI_UPDT;
1478 } else {
1479 /* Standard ACPI TMPx access, max 8 sensors */
1480 thermal_read_mode = IBMACPI_THERMAL_ACPI_TMP07;
1481 }
1482 } else {
1483 /* temperatures not supported on 570, G4x, R30, R31, R32 */
1484 thermal_read_mode = IBMACPI_THERMAL_NONE;
1485 }
1285 1486
1286 return 0; 1487 return 0;
1287} 1488}
1288 1489
1289static int thermal_read(char *p) 1490static int thermal_get_sensors(struct ibm_thermal_sensors_struct *s)
1290{ 1491{
1291 int len = 0; 1492 int i, t;
1493 s8 tmp;
1494 char tmpi[] = "TMPi";
1292 1495
1293 if (!thermal_tmp_supported) 1496 if (!s)
1294 len += sprintf(p + len, "temperatures:\tnot supported\n"); 1497 return -EINVAL;
1295 else {
1296 int i, t;
1297 char tmpi[] = "TMPi";
1298 s8 tmp[8];
1299 1498
1300 if (thermal_updt_supported) 1499 switch (thermal_read_mode) {
1301 if (!acpi_evalf(ec_handle, NULL, "UPDT", "v")) 1500#if IBMACPI_MAX_THERMAL_SENSORS >= 16
1501 case IBMACPI_THERMAL_TPEC_16:
1502 for (i = 0; i < 8; i++) {
1503 if (!acpi_ec_read(0xC0 + i, &tmp))
1504 return -EIO;
1505 s->temp[i + 8] = tmp * 1000;
1506 }
1507 /* fallthrough */
1508#endif
1509 case IBMACPI_THERMAL_TPEC_8:
1510 for (i = 0; i < 8; i++) {
1511 if (!acpi_ec_read(0x78 + i, &tmp))
1302 return -EIO; 1512 return -EIO;
1513 s->temp[i] = tmp * 1000;
1514 }
1515 return (thermal_read_mode == IBMACPI_THERMAL_TPEC_16) ? 16 : 8;
1303 1516
1517 case IBMACPI_THERMAL_ACPI_UPDT:
1518 if (!acpi_evalf(ec_handle, NULL, "UPDT", "v"))
1519 return -EIO;
1304 for (i = 0; i < 8; i++) { 1520 for (i = 0; i < 8; i++) {
1305 tmpi[3] = '0' + i; 1521 tmpi[3] = '0' + i;
1306 if (!acpi_evalf(ec_handle, &t, tmpi, "d")) 1522 if (!acpi_evalf(ec_handle, &t, tmpi, "d"))
1307 return -EIO; 1523 return -EIO;
1308 if (thermal_updt_supported) 1524 s->temp[i] = (t - 2732) * 100;
1309 tmp[i] = (t - 2732 + 5) / 10;
1310 else
1311 tmp[i] = t;
1312 } 1525 }
1526 return 8;
1313 1527
1314 len += sprintf(p + len, 1528 case IBMACPI_THERMAL_ACPI_TMP07:
1315 "temperatures:\t%d %d %d %d %d %d %d %d\n", 1529 for (i = 0; i < 8; i++) {
1316 tmp[0], tmp[1], tmp[2], tmp[3], 1530 tmpi[3] = '0' + i;
1317 tmp[4], tmp[5], tmp[6], tmp[7]); 1531 if (!acpi_evalf(ec_handle, &t, tmpi, "d"))
1532 return -EIO;
1533 s->temp[i] = t * 1000;
1534 }
1535 return 8;
1536
1537 case IBMACPI_THERMAL_NONE:
1538 default:
1539 return 0;
1318 } 1540 }
1541}
1542
1543static int thermal_read(char *p)
1544{
1545 int len = 0;
1546 int n, i;
1547 struct ibm_thermal_sensors_struct t;
1548
1549 n = thermal_get_sensors(&t);
1550 if (unlikely(n < 0))
1551 return n;
1552
1553 len += sprintf(p + len, "temperatures:\t");
1554
1555 if (n > 0) {
1556 for (i = 0; i < (n - 1); i++)
1557 len += sprintf(p + len, "%d ", t.temp[i] / 1000);
1558 len += sprintf(p + len, "%d\n", t.temp[i] / 1000);
1559 } else
1560 len += sprintf(p + len, "not supported\n");
1319 1561
1320 return len; 1562 return len;
1321} 1563}
@@ -1381,12 +1623,23 @@ static int ecdump_write(char *buf)
1381 1623
1382static int brightness_offset = 0x31; 1624static int brightness_offset = 0x31;
1383 1625
1626static int brightness_get(struct backlight_device *bd)
1627{
1628 u8 level;
1629 if (!acpi_ec_read(brightness_offset, &level))
1630 return -EIO;
1631
1632 level &= 0x7;
1633
1634 return level;
1635}
1636
1384static int brightness_read(char *p) 1637static int brightness_read(char *p)
1385{ 1638{
1386 int len = 0; 1639 int len = 0;
1387 u8 level; 1640 int level;
1388 1641
1389 if (!acpi_ec_read(brightness_offset, &level)) { 1642 if ((level = brightness_get(NULL)) < 0) {
1390 len += sprintf(p + len, "level:\t\tunreadable\n"); 1643 len += sprintf(p + len, "level:\t\tunreadable\n");
1391 } else { 1644 } else {
1392 len += sprintf(p + len, "level:\t\t%d\n", level & 0x7); 1645 len += sprintf(p + len, "level:\t\t%d\n", level & 0x7);
@@ -1401,16 +1654,34 @@ static int brightness_read(char *p)
1401#define BRIGHTNESS_UP 4 1654#define BRIGHTNESS_UP 4
1402#define BRIGHTNESS_DOWN 5 1655#define BRIGHTNESS_DOWN 5
1403 1656
1404static int brightness_write(char *buf) 1657static int brightness_set(int value)
1405{ 1658{
1406 int cmos_cmd, inc, i; 1659 int cmos_cmd, inc, i;
1407 u8 level; 1660 int current_value = brightness_get(NULL);
1661
1662 value &= 7;
1663
1664 cmos_cmd = value > current_value ? BRIGHTNESS_UP : BRIGHTNESS_DOWN;
1665 inc = value > current_value ? 1 : -1;
1666 for (i = current_value; i != value; i += inc) {
1667 if (!cmos_eval(cmos_cmd))
1668 return -EIO;
1669 if (!acpi_ec_write(brightness_offset, i + inc))
1670 return -EIO;
1671 }
1672
1673 return 0;
1674}
1675
1676static int brightness_write(char *buf)
1677{
1678 int level;
1408 int new_level; 1679 int new_level;
1409 char *cmd; 1680 char *cmd;
1410 1681
1411 while ((cmd = next_cmd(&buf))) { 1682 while ((cmd = next_cmd(&buf))) {
1412 if (!acpi_ec_read(brightness_offset, &level)) 1683 if ((level = brightness_get(NULL)) < 0)
1413 return -EIO; 1684 return level;
1414 level &= 7; 1685 level &= 7;
1415 1686
1416 if (strlencmp(cmd, "up") == 0) { 1687 if (strlencmp(cmd, "up") == 0) {
@@ -1423,19 +1694,44 @@ static int brightness_write(char *buf)
1423 } else 1694 } else
1424 return -EINVAL; 1695 return -EINVAL;
1425 1696
1426 cmos_cmd = new_level > level ? BRIGHTNESS_UP : BRIGHTNESS_DOWN; 1697 brightness_set(new_level);
1427 inc = new_level > level ? 1 : -1;
1428 for (i = level; i != new_level; i += inc) {
1429 if (!cmos_eval(cmos_cmd))
1430 return -EIO;
1431 if (!acpi_ec_write(brightness_offset, i + inc))
1432 return -EIO;
1433 }
1434 } 1698 }
1435 1699
1436 return 0; 1700 return 0;
1437} 1701}
1438 1702
1703static int brightness_update_status(struct backlight_device *bd)
1704{
1705 return brightness_set(bd->props->brightness);
1706}
1707
1708static struct backlight_properties ibm_backlight_data = {
1709 .owner = THIS_MODULE,
1710 .get_brightness = brightness_get,
1711 .update_status = brightness_update_status,
1712 .max_brightness = 7,
1713};
1714
1715static int brightness_init(void)
1716{
1717 ibm_backlight_device = backlight_device_register("ibm", NULL, NULL,
1718 &ibm_backlight_data);
1719 if (IS_ERR(ibm_backlight_device)) {
1720 printk(IBM_ERR "Could not register backlight device\n");
1721 return PTR_ERR(ibm_backlight_device);
1722 }
1723
1724 return 0;
1725}
1726
1727static void brightness_exit(void)
1728{
1729 if (ibm_backlight_device) {
1730 backlight_device_unregister(ibm_backlight_device);
1731 ibm_backlight_device = NULL;
1732 }
1733}
1734
1439static int volume_offset = 0x30; 1735static int volume_offset = 0x30;
1440 1736
1441static int volume_read(char *p) 1737static int volume_read(char *p)
@@ -1522,86 +1818,482 @@ static int volume_write(char *buf)
1522 return 0; 1818 return 0;
1523} 1819}
1524 1820
1525static int fan_status_offset = 0x2f; 1821static enum fan_status_access_mode fan_status_access_mode;
1526static int fan_rpm_offset = 0x84; 1822static enum fan_control_access_mode fan_control_access_mode;
1823static enum fan_control_commands fan_control_commands;
1527 1824
1528static int fan_read(char *p) 1825static int fan_control_status_known;
1826static u8 fan_control_initial_status;
1827
1828static void fan_watchdog_fire(struct work_struct *ignored);
1829static int fan_watchdog_maxinterval;
1830static DECLARE_DELAYED_WORK(fan_watchdog_task, fan_watchdog_fire);
1831
1832static int fan_init(void)
1529{ 1833{
1530 int len = 0; 1834 fan_status_access_mode = IBMACPI_FAN_NONE;
1531 int s; 1835 fan_control_access_mode = IBMACPI_FAN_WR_NONE;
1532 u8 lo, hi, status; 1836 fan_control_commands = 0;
1837 fan_control_status_known = 1;
1838 fan_watchdog_maxinterval = 0;
1533 1839
1534 if (gfan_handle) { 1840 if (gfan_handle) {
1535 /* 570, 600e/x, 770e, 770x */ 1841 /* 570, 600e/x, 770e, 770x */
1536 if (!acpi_evalf(gfan_handle, &s, NULL, "d")) 1842 fan_status_access_mode = IBMACPI_FAN_RD_ACPI_GFAN;
1537 return -EIO; 1843 } else {
1844 /* all other ThinkPads: note that even old-style
1845 * ThinkPad ECs supports the fan control register */
1846 if (likely(acpi_ec_read(fan_status_offset,
1847 &fan_control_initial_status))) {
1848 fan_status_access_mode = IBMACPI_FAN_RD_TPEC;
1849
1850 /* In some ThinkPads, neither the EC nor the ACPI
1851 * DSDT initialize the fan status, and it ends up
1852 * being set to 0x07 when it *could* be either
1853 * 0x07 or 0x80.
1854 *
1855 * Enable for TP-1Y (T43), TP-78 (R51e),
1856 * TP-76 (R52), TP-70 (T43, R52), which are known
1857 * to be buggy. */
1858 if (fan_control_initial_status == 0x07 &&
1859 ibm_thinkpad_ec_found &&
1860 ((ibm_thinkpad_ec_found[0] == '1' &&
1861 ibm_thinkpad_ec_found[1] == 'Y') ||
1862 (ibm_thinkpad_ec_found[0] == '7' &&
1863 (ibm_thinkpad_ec_found[1] == '6' ||
1864 ibm_thinkpad_ec_found[1] == '8' ||
1865 ibm_thinkpad_ec_found[1] == '0'))
1866 )) {
1867 printk(IBM_NOTICE
1868 "fan_init: initial fan status is "
1869 "unknown, assuming it is in auto "
1870 "mode\n");
1871 fan_control_status_known = 0;
1872 }
1873 } else {
1874 printk(IBM_ERR
1875 "ThinkPad ACPI EC access misbehaving, "
1876 "fan status and control unavailable\n");
1877 return 0;
1878 }
1879 }
1538 1880
1539 len += sprintf(p + len, "level:\t\t%d\n", s); 1881 if (sfan_handle) {
1882 /* 570, 770x-JL */
1883 fan_control_access_mode = IBMACPI_FAN_WR_ACPI_SFAN;
1884 fan_control_commands |=
1885 IBMACPI_FAN_CMD_LEVEL | IBMACPI_FAN_CMD_ENABLE;
1540 } else { 1886 } else {
1887 if (!gfan_handle) {
1888 /* gfan without sfan means no fan control */
1889 /* all other models implement TP EC 0x2f control */
1890
1891 if (fans_handle) {
1892 /* X31, X40, X41 */
1893 fan_control_access_mode =
1894 IBMACPI_FAN_WR_ACPI_FANS;
1895 fan_control_commands |=
1896 IBMACPI_FAN_CMD_SPEED |
1897 IBMACPI_FAN_CMD_LEVEL |
1898 IBMACPI_FAN_CMD_ENABLE;
1899 } else {
1900 fan_control_access_mode = IBMACPI_FAN_WR_TPEC;
1901 fan_control_commands |=
1902 IBMACPI_FAN_CMD_LEVEL |
1903 IBMACPI_FAN_CMD_ENABLE;
1904 }
1905 }
1906 }
1907
1908 return 0;
1909}
1910
1911static int fan_get_status(u8 *status)
1912{
1913 u8 s;
1914
1915 /* TODO:
1916 * Add IBMACPI_FAN_RD_ACPI_FANS ? */
1917
1918 switch (fan_status_access_mode) {
1919 case IBMACPI_FAN_RD_ACPI_GFAN:
1920 /* 570, 600e/x, 770e, 770x */
1921
1922 if (unlikely(!acpi_evalf(gfan_handle, &s, NULL, "d")))
1923 return -EIO;
1924
1925 if (likely(status))
1926 *status = s & 0x07;
1927
1928 break;
1929
1930 case IBMACPI_FAN_RD_TPEC:
1541 /* all except 570, 600e/x, 770e, 770x */ 1931 /* all except 570, 600e/x, 770e, 770x */
1542 if (!acpi_ec_read(fan_status_offset, &status)) 1932 if (unlikely(!acpi_ec_read(fan_status_offset, &s)))
1543 len += sprintf(p + len, "status:\t\tunreadable\n"); 1933 return -EIO;
1544 else
1545 len += sprintf(p + len, "status:\t\t%s\n",
1546 enabled(status, 7));
1547 1934
1548 if (!acpi_ec_read(fan_rpm_offset, &lo) || 1935 if (likely(status))
1549 !acpi_ec_read(fan_rpm_offset + 1, &hi)) 1936 *status = s;
1550 len += sprintf(p + len, "speed:\t\tunreadable\n"); 1937
1551 else 1938 break;
1552 len += sprintf(p + len, "speed:\t\t%d\n", 1939
1553 (hi << 8) + lo); 1940 default:
1941 return -ENXIO;
1554 } 1942 }
1555 1943
1556 if (sfan_handle) 1944 return 0;
1557 /* 570, 770x-JL */ 1945}
1558 len += sprintf(p + len, "commands:\tlevel <level>" 1946
1559 " (<level> is 0-7)\n"); 1947static int fan_get_speed(unsigned int *speed)
1560 if (!gfan_handle) 1948{
1949 u8 hi, lo;
1950
1951 switch (fan_status_access_mode) {
1952 case IBMACPI_FAN_RD_TPEC:
1561 /* all except 570, 600e/x, 770e, 770x */ 1953 /* all except 570, 600e/x, 770e, 770x */
1562 len += sprintf(p + len, "commands:\tenable, disable\n"); 1954 if (unlikely(!acpi_ec_read(fan_rpm_offset, &lo) ||
1563 if (fans_handle) 1955 !acpi_ec_read(fan_rpm_offset + 1, &hi)))
1564 /* X31, X40 */ 1956 return -EIO;
1957
1958 if (likely(speed))
1959 *speed = (hi << 8) | lo;
1960
1961 break;
1962
1963 default:
1964 return -ENXIO;
1965 }
1966
1967 return 0;
1968}
1969
1970static void fan_exit(void)
1971{
1972 cancel_delayed_work(&fan_watchdog_task);
1973 flush_scheduled_work();
1974}
1975
1976static void fan_watchdog_reset(void)
1977{
1978 static int fan_watchdog_active = 0;
1979
1980 if (fan_watchdog_active)
1981 cancel_delayed_work(&fan_watchdog_task);
1982
1983 if (fan_watchdog_maxinterval > 0) {
1984 fan_watchdog_active = 1;
1985 if (!schedule_delayed_work(&fan_watchdog_task,
1986 msecs_to_jiffies(fan_watchdog_maxinterval
1987 * 1000))) {
1988 printk(IBM_ERR "failed to schedule the fan watchdog, "
1989 "watchdog will not trigger\n");
1990 }
1991 } else
1992 fan_watchdog_active = 0;
1993}
1994
1995static int fan_read(char *p)
1996{
1997 int len = 0;
1998 int rc;
1999 u8 status;
2000 unsigned int speed = 0;
2001
2002 switch (fan_status_access_mode) {
2003 case IBMACPI_FAN_RD_ACPI_GFAN:
2004 /* 570, 600e/x, 770e, 770x */
2005 if ((rc = fan_get_status(&status)) < 0)
2006 return rc;
2007
2008 len += sprintf(p + len, "status:\t\t%s\n"
2009 "level:\t\t%d\n",
2010 (status != 0) ? "enabled" : "disabled", status);
2011 break;
2012
2013 case IBMACPI_FAN_RD_TPEC:
2014 /* all except 570, 600e/x, 770e, 770x */
2015 if ((rc = fan_get_status(&status)) < 0)
2016 return rc;
2017
2018 if (unlikely(!fan_control_status_known)) {
2019 if (status != fan_control_initial_status)
2020 fan_control_status_known = 1;
2021 else
2022 /* Return most likely status. In fact, it
2023 * might be the only possible status */
2024 status = IBMACPI_FAN_EC_AUTO;
2025 }
2026
2027 len += sprintf(p + len, "status:\t\t%s\n",
2028 (status != 0) ? "enabled" : "disabled");
2029
2030 /* No ThinkPad boots on disengaged mode, we can safely
2031 * assume the tachometer is online if fan control status
2032 * was unknown */
2033 if ((rc = fan_get_speed(&speed)) < 0)
2034 return rc;
2035
2036 len += sprintf(p + len, "speed:\t\t%d\n", speed);
2037
2038 if (status & IBMACPI_FAN_EC_DISENGAGED)
2039 /* Disengaged mode takes precedence */
2040 len += sprintf(p + len, "level:\t\tdisengaged\n");
2041 else if (status & IBMACPI_FAN_EC_AUTO)
2042 len += sprintf(p + len, "level:\t\tauto\n");
2043 else
2044 len += sprintf(p + len, "level:\t\t%d\n", status);
2045 break;
2046
2047 case IBMACPI_FAN_NONE:
2048 default:
2049 len += sprintf(p + len, "status:\t\tnot supported\n");
2050 }
2051
2052 if (fan_control_commands & IBMACPI_FAN_CMD_LEVEL) {
2053 len += sprintf(p + len, "commands:\tlevel <level>");
2054
2055 switch (fan_control_access_mode) {
2056 case IBMACPI_FAN_WR_ACPI_SFAN:
2057 len += sprintf(p + len, " (<level> is 0-7)\n");
2058 break;
2059
2060 default:
2061 len += sprintf(p + len, " (<level> is 0-7, "
2062 "auto, disengaged)\n");
2063 break;
2064 }
2065 }
2066
2067 if (fan_control_commands & IBMACPI_FAN_CMD_ENABLE)
2068 len += sprintf(p + len, "commands:\tenable, disable\n"
2069 "commands:\twatchdog <timeout> (<timeout> is 0 (off), "
2070 "1-120 (seconds))\n");
2071
2072 if (fan_control_commands & IBMACPI_FAN_CMD_SPEED)
1565 len += sprintf(p + len, "commands:\tspeed <speed>" 2073 len += sprintf(p + len, "commands:\tspeed <speed>"
1566 " (<speed> is 0-65535)\n"); 2074 " (<speed> is 0-65535)\n");
1567 2075
1568 return len; 2076 return len;
1569} 2077}
1570 2078
1571static int fan_write(char *buf) 2079static int fan_set_level(int level)
1572{ 2080{
1573 char *cmd; 2081 switch (fan_control_access_mode) {
1574 int level, speed; 2082 case IBMACPI_FAN_WR_ACPI_SFAN:
1575 2083 if (level >= 0 && level <= 7) {
1576 while ((cmd = next_cmd(&buf))) {
1577 if (sfan_handle &&
1578 sscanf(cmd, "level %d", &level) == 1 &&
1579 level >= 0 && level <= 7) {
1580 /* 570, 770x-JL */
1581 if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", level)) 2084 if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", level))
1582 return -EIO; 2085 return -EIO;
1583 } else if (!gfan_handle && strlencmp(cmd, "enable") == 0) { 2086 } else
1584 /* all except 570, 600e/x, 770e, 770x */ 2087 return -EINVAL;
1585 if (!acpi_ec_write(fan_status_offset, 0x80)) 2088 break;
1586 return -EIO; 2089
1587 } else if (!gfan_handle && strlencmp(cmd, "disable") == 0) { 2090 case IBMACPI_FAN_WR_ACPI_FANS:
1588 /* all except 570, 600e/x, 770e, 770x */ 2091 case IBMACPI_FAN_WR_TPEC:
1589 if (!acpi_ec_write(fan_status_offset, 0x00)) 2092 if ((level != IBMACPI_FAN_EC_AUTO) &&
1590 return -EIO; 2093 (level != IBMACPI_FAN_EC_DISENGAGED) &&
1591 } else if (fans_handle && 2094 ((level < 0) || (level > 7)))
1592 sscanf(cmd, "speed %d", &speed) == 1 && 2095 return -EINVAL;
1593 speed >= 0 && speed <= 65535) { 2096
1594 /* X31, X40 */ 2097 if (!acpi_ec_write(fan_status_offset, level))
2098 return -EIO;
2099 else
2100 fan_control_status_known = 1;
2101 break;
2102
2103 default:
2104 return -ENXIO;
2105 }
2106 return 0;
2107}
2108
2109static int fan_set_enable(void)
2110{
2111 u8 s;
2112 int rc;
2113
2114 switch (fan_control_access_mode) {
2115 case IBMACPI_FAN_WR_ACPI_FANS:
2116 case IBMACPI_FAN_WR_TPEC:
2117 if ((rc = fan_get_status(&s)) < 0)
2118 return rc;
2119
2120 /* Don't go out of emergency fan mode */
2121 if (s != 7)
2122 s = IBMACPI_FAN_EC_AUTO;
2123
2124 if (!acpi_ec_write(fan_status_offset, s))
2125 return -EIO;
2126 else
2127 fan_control_status_known = 1;
2128 break;
2129
2130 case IBMACPI_FAN_WR_ACPI_SFAN:
2131 if ((rc = fan_get_status(&s)) < 0)
2132 return rc;
2133
2134 s &= 0x07;
2135
2136 /* Set fan to at least level 4 */
2137 if (s < 4)
2138 s = 4;
2139
2140 if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", s))
2141 return -EIO;
2142 break;
2143
2144 default:
2145 return -ENXIO;
2146 }
2147 return 0;
2148}
2149
2150static int fan_set_disable(void)
2151{
2152 switch (fan_control_access_mode) {
2153 case IBMACPI_FAN_WR_ACPI_FANS:
2154 case IBMACPI_FAN_WR_TPEC:
2155 if (!acpi_ec_write(fan_status_offset, 0x00))
2156 return -EIO;
2157 else
2158 fan_control_status_known = 1;
2159 break;
2160
2161 case IBMACPI_FAN_WR_ACPI_SFAN:
2162 if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", 0x00))
2163 return -EIO;
2164 break;
2165
2166 default:
2167 return -ENXIO;
2168 }
2169 return 0;
2170}
2171
2172static int fan_set_speed(int speed)
2173{
2174 switch (fan_control_access_mode) {
2175 case IBMACPI_FAN_WR_ACPI_FANS:
2176 if (speed >= 0 && speed <= 65535) {
1595 if (!acpi_evalf(fans_handle, NULL, NULL, "vddd", 2177 if (!acpi_evalf(fans_handle, NULL, NULL, "vddd",
1596 speed, speed, speed)) 2178 speed, speed, speed))
1597 return -EIO; 2179 return -EIO;
1598 } else 2180 } else
1599 return -EINVAL; 2181 return -EINVAL;
1600 } 2182 break;
1601 2183
2184 default:
2185 return -ENXIO;
2186 }
1602 return 0; 2187 return 0;
1603} 2188}
1604 2189
2190static int fan_write_cmd_level(const char *cmd, int *rc)
2191{
2192 int level;
2193
2194 if (strlencmp(cmd, "level auto") == 0)
2195 level = IBMACPI_FAN_EC_AUTO;
2196 else if (strlencmp(cmd, "level disengaged") == 0)
2197 level = IBMACPI_FAN_EC_DISENGAGED;
2198 else if (sscanf(cmd, "level %d", &level) != 1)
2199 return 0;
2200
2201 if ((*rc = fan_set_level(level)) == -ENXIO)
2202 printk(IBM_ERR "level command accepted for unsupported "
2203 "access mode %d", fan_control_access_mode);
2204
2205 return 1;
2206}
2207
2208static int fan_write_cmd_enable(const char *cmd, int *rc)
2209{
2210 if (strlencmp(cmd, "enable") != 0)
2211 return 0;
2212
2213 if ((*rc = fan_set_enable()) == -ENXIO)
2214 printk(IBM_ERR "enable command accepted for unsupported "
2215 "access mode %d", fan_control_access_mode);
2216
2217 return 1;
2218}
2219
2220static int fan_write_cmd_disable(const char *cmd, int *rc)
2221{
2222 if (strlencmp(cmd, "disable") != 0)
2223 return 0;
2224
2225 if ((*rc = fan_set_disable()) == -ENXIO)
2226 printk(IBM_ERR "disable command accepted for unsupported "
2227 "access mode %d", fan_control_access_mode);
2228
2229 return 1;
2230}
2231
2232static int fan_write_cmd_speed(const char *cmd, int *rc)
2233{
2234 int speed;
2235
2236 /* TODO:
2237 * Support speed <low> <medium> <high> ? */
2238
2239 if (sscanf(cmd, "speed %d", &speed) != 1)
2240 return 0;
2241
2242 if ((*rc = fan_set_speed(speed)) == -ENXIO)
2243 printk(IBM_ERR "speed command accepted for unsupported "
2244 "access mode %d", fan_control_access_mode);
2245
2246 return 1;
2247}
2248
2249static int fan_write_cmd_watchdog(const char *cmd, int *rc)
2250{
2251 int interval;
2252
2253 if (sscanf(cmd, "watchdog %d", &interval) != 1)
2254 return 0;
2255
2256 if (interval < 0 || interval > 120)
2257 *rc = -EINVAL;
2258 else
2259 fan_watchdog_maxinterval = interval;
2260
2261 return 1;
2262}
2263
2264static int fan_write(char *buf)
2265{
2266 char *cmd;
2267 int rc = 0;
2268
2269 while (!rc && (cmd = next_cmd(&buf))) {
2270 if (!((fan_control_commands & IBMACPI_FAN_CMD_LEVEL) &&
2271 fan_write_cmd_level(cmd, &rc)) &&
2272 !((fan_control_commands & IBMACPI_FAN_CMD_ENABLE) &&
2273 (fan_write_cmd_enable(cmd, &rc) ||
2274 fan_write_cmd_disable(cmd, &rc) ||
2275 fan_write_cmd_watchdog(cmd, &rc))) &&
2276 !((fan_control_commands & IBMACPI_FAN_CMD_SPEED) &&
2277 fan_write_cmd_speed(cmd, &rc))
2278 )
2279 rc = -EINVAL;
2280 else if (!rc)
2281 fan_watchdog_reset();
2282 }
2283
2284 return rc;
2285}
2286
2287static void fan_watchdog_fire(struct work_struct *ignored)
2288{
2289 printk(IBM_NOTICE "fan watchdog: enabling fan\n");
2290 if (fan_set_enable()) {
2291 printk(IBM_ERR "fan watchdog: error while enabling fan\n");
2292 /* reschedule for later */
2293 fan_watchdog_reset();
2294 }
2295}
2296
1605static struct ibm_struct ibms[] = { 2297static struct ibm_struct ibms[] = {
1606 { 2298 {
1607 .name = "driver", 2299 .name = "driver",
@@ -1662,6 +2354,7 @@ static struct ibm_struct ibms[] = {
1662 .type = ACPI_SYSTEM_NOTIFY, 2354 .type = ACPI_SYSTEM_NOTIFY,
1663 }, 2355 },
1664#endif 2356#endif
2357#ifdef CONFIG_ACPI_IBM_BAY
1665 { 2358 {
1666 .name = "bay", 2359 .name = "bay",
1667 .init = bay_init, 2360 .init = bay_init,
@@ -1671,6 +2364,7 @@ static struct ibm_struct ibms[] = {
1671 .handle = &bay_handle, 2364 .handle = &bay_handle,
1672 .type = ACPI_SYSTEM_NOTIFY, 2365 .type = ACPI_SYSTEM_NOTIFY,
1673 }, 2366 },
2367#endif
1674 { 2368 {
1675 .name = "cmos", 2369 .name = "cmos",
1676 .read = cmos_read, 2370 .read = cmos_read,
@@ -1702,6 +2396,8 @@ static struct ibm_struct ibms[] = {
1702 .name = "brightness", 2396 .name = "brightness",
1703 .read = brightness_read, 2397 .read = brightness_read,
1704 .write = brightness_write, 2398 .write = brightness_write,
2399 .init = brightness_init,
2400 .exit = brightness_exit,
1705 }, 2401 },
1706 { 2402 {
1707 .name = "volume", 2403 .name = "volume",
@@ -1712,6 +2408,8 @@ static struct ibm_struct ibms[] = {
1712 .name = "fan", 2408 .name = "fan",
1713 .read = fan_read, 2409 .read = fan_read,
1714 .write = fan_write, 2410 .write = fan_write,
2411 .init = fan_init,
2412 .exit = fan_exit,
1715 .experimental = 1, 2413 .experimental = 1,
1716 }, 2414 },
1717}; 2415};
@@ -1719,7 +2417,7 @@ static struct ibm_struct ibms[] = {
1719static int dispatch_read(char *page, char **start, off_t off, int count, 2417static int dispatch_read(char *page, char **start, off_t off, int count,
1720 int *eof, void *data) 2418 int *eof, void *data)
1721{ 2419{
1722 struct ibm_struct *ibm = (struct ibm_struct *)data; 2420 struct ibm_struct *ibm = data;
1723 int len; 2421 int len;
1724 2422
1725 if (!ibm || !ibm->read) 2423 if (!ibm || !ibm->read)
@@ -1744,7 +2442,7 @@ static int dispatch_read(char *page, char **start, off_t off, int count,
1744static int dispatch_write(struct file *file, const char __user * userbuf, 2442static int dispatch_write(struct file *file, const char __user * userbuf,
1745 unsigned long count, void *data) 2443 unsigned long count, void *data)
1746{ 2444{
1747 struct ibm_struct *ibm = (struct ibm_struct *)data; 2445 struct ibm_struct *ibm = data;
1748 char *kernbuf; 2446 char *kernbuf;
1749 int ret; 2447 int ret;
1750 2448
@@ -1773,7 +2471,7 @@ static int dispatch_write(struct file *file, const char __user * userbuf,
1773 2471
1774static void dispatch_notify(acpi_handle handle, u32 event, void *data) 2472static void dispatch_notify(acpi_handle handle, u32 event, void *data)
1775{ 2473{
1776 struct ibm_struct *ibm = (struct ibm_struct *)data; 2474 struct ibm_struct *ibm = data;
1777 2475
1778 if (!ibm || !ibm->notify) 2476 if (!ibm || !ibm->notify)
1779 return; 2477 return;
@@ -1805,7 +2503,7 @@ static int __init setup_notify(struct ibm_struct *ibm)
1805 ibm->name, status); 2503 ibm->name, status);
1806 return -ENODEV; 2504 return -ENODEV;
1807 } 2505 }
1808 2506 ibm->notify_installed = 1;
1809 return 0; 2507 return 0;
1810} 2508}
1811 2509
@@ -1818,14 +2516,13 @@ static int __init register_driver(struct ibm_struct *ibm)
1818{ 2516{
1819 int ret; 2517 int ret;
1820 2518
1821 ibm->driver = kmalloc(sizeof(struct acpi_driver), GFP_KERNEL); 2519 ibm->driver = kzalloc(sizeof(struct acpi_driver), GFP_KERNEL);
1822 if (!ibm->driver) { 2520 if (!ibm->driver) {
1823 printk(IBM_ERR "kmalloc(ibm->driver) failed\n"); 2521 printk(IBM_ERR "kmalloc(ibm->driver) failed\n");
1824 return -1; 2522 return -1;
1825 } 2523 }
1826 2524
1827 memset(ibm->driver, 0, sizeof(struct acpi_driver)); 2525 sprintf(ibm->driver->name, "%s_%s", IBM_NAME, ibm->name);
1828 sprintf(ibm->driver->name, "%s/%s", IBM_NAME, ibm->name);
1829 ibm->driver->ids = ibm->hid; 2526 ibm->driver->ids = ibm->hid;
1830 ibm->driver->ops.add = &ibm_device_add; 2527 ibm->driver->ops.add = &ibm_device_add;
1831 2528
@@ -1882,7 +2579,6 @@ static int __init ibm_init(struct ibm_struct *ibm)
1882 ret = setup_notify(ibm); 2579 ret = setup_notify(ibm);
1883 if (ret < 0) 2580 if (ret < 0)
1884 return ret; 2581 return ret;
1885 ibm->notify_installed = 1;
1886 } 2582 }
1887 2583
1888 return 0; 2584 return 0;
@@ -1954,7 +2650,9 @@ IBM_PARAM(light);
1954#ifdef CONFIG_ACPI_IBM_DOCK 2650#ifdef CONFIG_ACPI_IBM_DOCK
1955IBM_PARAM(dock); 2651IBM_PARAM(dock);
1956#endif 2652#endif
2653#ifdef CONFIG_ACPI_IBM_BAY
1957IBM_PARAM(bay); 2654IBM_PARAM(bay);
2655#endif
1958IBM_PARAM(cmos); 2656IBM_PARAM(cmos);
1959IBM_PARAM(led); 2657IBM_PARAM(led);
1960IBM_PARAM(beep); 2658IBM_PARAM(beep);
@@ -1971,6 +2669,33 @@ static void acpi_ibm_exit(void)
1971 ibm_exit(&ibms[i]); 2669 ibm_exit(&ibms[i]);
1972 2670
1973 remove_proc_entry(IBM_DIR, acpi_root_dir); 2671 remove_proc_entry(IBM_DIR, acpi_root_dir);
2672
2673 if (ibm_thinkpad_ec_found)
2674 kfree(ibm_thinkpad_ec_found);
2675}
2676
2677static char* __init check_dmi_for_ec(void)
2678{
2679 struct dmi_device *dev = NULL;
2680 char ec_fw_string[18];
2681
2682 /*
2683 * ThinkPad T23 or newer, A31 or newer, R50e or newer,
2684 * X32 or newer, all Z series; Some models must have an
2685 * up-to-date BIOS or they will not be detected.
2686 *
2687 * See http://thinkwiki.org/wiki/List_of_DMI_IDs
2688 */
2689 while ((dev = dmi_find_device(DMI_DEV_TYPE_OEM_STRING, NULL, dev))) {
2690 if (sscanf(dev->name,
2691 "IBM ThinkPad Embedded Controller -[%17c",
2692 ec_fw_string) == 1) {
2693 ec_fw_string[sizeof(ec_fw_string) - 1] = 0;
2694 ec_fw_string[strcspn(ec_fw_string, " ]")] = 0;
2695 return kstrdup(ec_fw_string, GFP_KERNEL);
2696 }
2697 }
2698 return NULL;
1974} 2699}
1975 2700
1976static int __init acpi_ibm_init(void) 2701static int __init acpi_ibm_init(void)
@@ -1992,6 +2717,12 @@ static int __init acpi_ibm_init(void)
1992 return -ENODEV; 2717 return -ENODEV;
1993 } 2718 }
1994 2719
2720 /* Models with newer firmware report the EC in DMI */
2721 ibm_thinkpad_ec_found = check_dmi_for_ec();
2722 if (ibm_thinkpad_ec_found)
2723 printk(IBM_INFO "ThinkPad EC firmware %s\n",
2724 ibm_thinkpad_ec_found);
2725
1995 /* these handles are not required */ 2726 /* these handles are not required */
1996 IBM_HANDLE_INIT(vid); 2727 IBM_HANDLE_INIT(vid);
1997 IBM_HANDLE_INIT(vid2); 2728 IBM_HANDLE_INIT(vid2);
@@ -2004,12 +2735,14 @@ static int __init acpi_ibm_init(void)
2004 IBM_HANDLE_INIT(dock); 2735 IBM_HANDLE_INIT(dock);
2005#endif 2736#endif
2006 IBM_HANDLE_INIT(pci); 2737 IBM_HANDLE_INIT(pci);
2738#ifdef CONFIG_ACPI_IBM_BAY
2007 IBM_HANDLE_INIT(bay); 2739 IBM_HANDLE_INIT(bay);
2008 if (bay_handle) 2740 if (bay_handle)
2009 IBM_HANDLE_INIT(bay_ej); 2741 IBM_HANDLE_INIT(bay_ej);
2010 IBM_HANDLE_INIT(bay2); 2742 IBM_HANDLE_INIT(bay2);
2011 if (bay2_handle) 2743 if (bay2_handle)
2012 IBM_HANDLE_INIT(bay2_ej); 2744 IBM_HANDLE_INIT(bay2_ej);
2745#endif
2013 IBM_HANDLE_INIT(beep); 2746 IBM_HANDLE_INIT(beep);
2014 IBM_HANDLE_INIT(ecrd); 2747 IBM_HANDLE_INIT(ecrd);
2015 IBM_HANDLE_INIT(ecwr); 2748 IBM_HANDLE_INIT(ecwr);