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