aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
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
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')
-rw-r--r--drivers/acpi/Kconfig37
-rw-r--r--drivers/acpi/Makefile1
-rw-r--r--drivers/acpi/ibm_acpi.c2798
-rw-r--r--drivers/misc/Kconfig51
-rw-r--r--drivers/misc/Makefile1
-rw-r--r--drivers/misc/thinkpad_acpi.c4312
-rw-r--r--drivers/misc/thinkpad_acpi.h572
7 files changed, 4936 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);
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 75dbc584b574..a3c525b2616a 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -127,4 +127,55 @@ config SONY_LAPTOP_OLD
127 ---help--- 127 ---help---
128 Build the sonypi driver compatibility code into the sony-laptop driver. 128 Build the sonypi driver compatibility code into the sony-laptop driver.
129 129
130config THINKPAD_ACPI
131 tristate "ThinkPad ACPI Laptop Extras"
132 depends on X86 && ACPI
133 select BACKLIGHT_CLASS_DEVICE
134 select HWMON
135 ---help---
136 This is a driver for the IBM and Lenovo ThinkPad laptops. It adds
137 support for Fn-Fx key combinations, Bluetooth control, video
138 output switching, ThinkLight control, UltraBay eject and more.
139 For more information about this driver see
140 <file:Documentation/thinkpad-acpi.txt> and <http://ibm-acpi.sf.net/> .
141
142 This driver was formely known as ibm-acpi.
143
144 If you have an IBM or Lenovo ThinkPad laptop, say Y or M here.
145
146config THINKPAD_ACPI_DEBUG
147 bool "Verbose debug mode"
148 depends on THINKPAD_ACPI
149 default n
150 ---help---
151 Enables extra debugging information, at the expense of a slightly
152 increase in driver size.
153
154 If you are not sure, say N here.
155
156config THINKPAD_ACPI_DOCK
157 bool "Legacy Docking Station Support"
158 depends on THINKPAD_ACPI
159 depends on ACPI_DOCK=n
160 default n
161 ---help---
162 Allows the thinkpad_acpi driver to handle docking station events.
163 This support was made obsolete by the generic ACPI docking station
164 support (CONFIG_ACPI_DOCK). It will allow locking and removing the
165 laptop from the docking station, but will not properly connect PCI
166 devices.
167
168 If you are not sure, say N here.
169
170config THINKPAD_ACPI_BAY
171 bool "Legacy Removable Bay Support"
172 depends on THINKPAD_ACPI
173 default y
174 ---help---
175 Allows the thinkpad_acpi driver to handle removable bays. It will
176 eletrically disable the device in the bay, and also generate
177 notifications when the bay lever is ejected or inserted.
178
179 If you are not sure, say Y here.
180
130endmenu 181endmenu
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 7793ccd79049..e32516459138 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -12,3 +12,4 @@ obj-$(CONFIG_TIFM_CORE) += tifm_core.o
12obj-$(CONFIG_TIFM_7XX1) += tifm_7xx1.o 12obj-$(CONFIG_TIFM_7XX1) += tifm_7xx1.o
13obj-$(CONFIG_SGI_IOC4) += ioc4.o 13obj-$(CONFIG_SGI_IOC4) += ioc4.o
14obj-$(CONFIG_SONY_LAPTOP) += sony-laptop.o 14obj-$(CONFIG_SONY_LAPTOP) += sony-laptop.o
15obj-$(CONFIG_THINKPAD_ACPI) += thinkpad_acpi.o
diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c
new file mode 100644
index 000000000000..6c36a55cb3d1
--- /dev/null
+++ b/drivers/misc/thinkpad_acpi.c
@@ -0,0 +1,4312 @@
1/*
2 * thinkpad_acpi.c - ThinkPad ACPI Extras
3 *
4 *
5 * Copyright (C) 2004-2005 Borislav Deianov <borislav@users.sf.net>
6 * Copyright (C) 2006-2007 Henrique de Moraes Holschuh <hmh@hmh.eng.br>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 * 02110-1301, USA.
22 */
23
24#define IBM_VERSION "0.14"
25#define TPACPI_SYSFS_VERSION 0x000100
26
27/*
28 * Changelog:
29 * 2007-03-27 0.14 renamed to thinkpad_acpi and moved to
30 * drivers/misc.
31 *
32 * 2006-11-22 0.13 new maintainer
33 * changelog now lives in git commit history, and will
34 * not be updated further in-file.
35 *
36 * 2005-08-17 0.12 fix compilation on 2.6.13-rc kernels
37 * 2005-03-17 0.11 support for 600e, 770x
38 * thanks to Jamie Lentin <lentinj@dial.pipex.com>
39 * support for 770e, G41
40 * G40 and G41 don't have a thinklight
41 * temperatures no longer experimental
42 * experimental brightness control
43 * experimental volume control
44 * experimental fan enable/disable
45 * 2005-01-16 0.10 fix module loading on R30, R31
46 * 2005-01-16 0.9 support for 570, R30, R31
47 * ultrabay support on A22p, A3x
48 * limit arg for cmos, led, beep, drop experimental status
49 * more capable led control on A21e, A22p, T20-22, X20
50 * experimental temperatures and fan speed
51 * experimental embedded controller register dump
52 * mark more functions as __init, drop incorrect __exit
53 * use MODULE_VERSION
54 * thanks to Henrik Brix Andersen <brix@gentoo.org>
55 * fix parameter passing on module loading
56 * thanks to Rusty Russell <rusty@rustcorp.com.au>
57 * thanks to Jim Radford <radford@blackbean.org>
58 * 2004-11-08 0.8 fix init error case, don't return from a macro
59 * thanks to Chris Wright <chrisw@osdl.org>
60 * 2004-10-23 0.7 fix module loading on A21e, A22p, T20, T21, X20
61 * fix led control on A21e
62 * 2004-10-19 0.6 use acpi_bus_register_driver() to claim HKEY device
63 * 2004-10-18 0.5 thinklight support on A21e, G40, R32, T20, T21, X20
64 * proc file format changed
65 * video_switch command
66 * experimental cmos control
67 * experimental led control
68 * experimental acpi sounds
69 * 2004-09-16 0.4 support for module parameters
70 * hotkey mask can be prefixed by 0x
71 * video output switching
72 * video expansion control
73 * ultrabay eject support
74 * removed lcd brightness/on/off control, didn't work
75 * 2004-08-17 0.3 support for R40
76 * lcd off, brightness control
77 * thinklight on/off
78 * 2004-08-14 0.2 support for T series, X20
79 * bluetooth enable/disable
80 * hotkey events disabled by default
81 * removed fan control, currently useless
82 * 2004-08-09 0.1 initial release, support for X series
83 */
84
85#include "thinkpad_acpi.h"
86
87MODULE_AUTHOR("Borislav Deianov, Henrique de Moraes Holschuh");
88MODULE_DESCRIPTION(IBM_DESC);
89MODULE_VERSION(IBM_VERSION);
90MODULE_LICENSE("GPL");
91
92/* Please remove this in year 2009 */
93MODULE_ALIAS("ibm_acpi");
94
95#define __unused __attribute__ ((unused))
96
97/****************************************************************************
98 ****************************************************************************
99 *
100 * ACPI Helpers and device model
101 *
102 ****************************************************************************
103 ****************************************************************************/
104
105/*************************************************************************
106 * ACPI basic handles
107 */
108
109static acpi_handle root_handle = NULL;
110
111#define IBM_HANDLE(object, parent, paths...) \
112 static acpi_handle object##_handle; \
113 static acpi_handle *object##_parent = &parent##_handle; \
114 static char *object##_path; \
115 static char *object##_paths[] = { paths }
116
117IBM_HANDLE(ec, root, "\\_SB.PCI0.ISA.EC0", /* 240, 240x */
118 "\\_SB.PCI.ISA.EC", /* 570 */
119 "\\_SB.PCI0.ISA0.EC0", /* 600e/x, 770e, 770x */
120 "\\_SB.PCI0.ISA.EC", /* A21e, A2xm/p, T20-22, X20-21 */
121 "\\_SB.PCI0.AD4S.EC0", /* i1400, R30 */
122 "\\_SB.PCI0.ICH3.EC0", /* R31 */
123 "\\_SB.PCI0.LPC.EC", /* all others */
124 );
125
126IBM_HANDLE(ecrd, ec, "ECRD"); /* 570 */
127IBM_HANDLE(ecwr, ec, "ECWR"); /* 570 */
128
129
130/*************************************************************************
131 * Misc ACPI handles
132 */
133
134IBM_HANDLE(cmos, root, "\\UCMS", /* R50, R50e, R50p, R51, T4x, X31, X40 */
135 "\\CMOS", /* A3x, G4x, R32, T23, T30, X22-24, X30 */
136 "\\CMS", /* R40, R40e */
137 ); /* all others */
138
139IBM_HANDLE(hkey, ec, "\\_SB.HKEY", /* 600e/x, 770e, 770x */
140 "^HKEY", /* R30, R31 */
141 "HKEY", /* all others */
142 ); /* 570 */
143
144
145/*************************************************************************
146 * ACPI helpers
147 */
148
149static int acpi_evalf(acpi_handle handle,
150 void *res, char *method, char *fmt, ...)
151{
152 char *fmt0 = fmt;
153 struct acpi_object_list params;
154 union acpi_object in_objs[IBM_MAX_ACPI_ARGS];
155 struct acpi_buffer result, *resultp;
156 union acpi_object out_obj;
157 acpi_status status;
158 va_list ap;
159 char res_type;
160 int success;
161 int quiet;
162
163 if (!*fmt) {
164 printk(IBM_ERR "acpi_evalf() called with empty format\n");
165 return 0;
166 }
167
168 if (*fmt == 'q') {
169 quiet = 1;
170 fmt++;
171 } else
172 quiet = 0;
173
174 res_type = *(fmt++);
175
176 params.count = 0;
177 params.pointer = &in_objs[0];
178
179 va_start(ap, fmt);
180 while (*fmt) {
181 char c = *(fmt++);
182 switch (c) {
183 case 'd': /* int */
184 in_objs[params.count].integer.value = va_arg(ap, int);
185 in_objs[params.count++].type = ACPI_TYPE_INTEGER;
186 break;
187 /* add more types as needed */
188 default:
189 printk(IBM_ERR "acpi_evalf() called "
190 "with invalid format character '%c'\n", c);
191 return 0;
192 }
193 }
194 va_end(ap);
195
196 if (res_type != 'v') {
197 result.length = sizeof(out_obj);
198 result.pointer = &out_obj;
199 resultp = &result;
200 } else
201 resultp = NULL;
202
203 status = acpi_evaluate_object(handle, method, &params, resultp);
204
205 switch (res_type) {
206 case 'd': /* int */
207 if (res)
208 *(int *)res = out_obj.integer.value;
209 success = status == AE_OK && out_obj.type == ACPI_TYPE_INTEGER;
210 break;
211 case 'v': /* void */
212 success = status == AE_OK;
213 break;
214 /* add more types as needed */
215 default:
216 printk(IBM_ERR "acpi_evalf() called "
217 "with invalid format character '%c'\n", res_type);
218 return 0;
219 }
220
221 if (!success && !quiet)
222 printk(IBM_ERR "acpi_evalf(%s, %s, ...) failed: %d\n",
223 method, fmt0, status);
224
225 return success;
226}
227
228static void __unused acpi_print_int(acpi_handle handle, char *method)
229{
230 int i;
231
232 if (acpi_evalf(handle, &i, method, "d"))
233 printk(IBM_INFO "%s = 0x%x\n", method, i);
234 else
235 printk(IBM_ERR "error calling %s\n", method);
236}
237
238static int acpi_ec_read(int i, u8 * p)
239{
240 int v;
241
242 if (ecrd_handle) {
243 if (!acpi_evalf(ecrd_handle, &v, NULL, "dd", i))
244 return 0;
245 *p = v;
246 } else {
247 if (ec_read(i, p) < 0)
248 return 0;
249 }
250
251 return 1;
252}
253
254static int acpi_ec_write(int i, u8 v)
255{
256 if (ecwr_handle) {
257 if (!acpi_evalf(ecwr_handle, NULL, NULL, "vdd", i, v))
258 return 0;
259 } else {
260 if (ec_write(i, v) < 0)
261 return 0;
262 }
263
264 return 1;
265}
266
267static int _sta(acpi_handle handle)
268{
269 int status;
270
271 if (!handle || !acpi_evalf(handle, &status, "_STA", "d"))
272 status = 0;
273
274 return status;
275}
276
277static int issue_thinkpad_cmos_command(int cmos_cmd)
278{
279 if (!cmos_handle)
280 return -ENXIO;
281
282 if (!acpi_evalf(cmos_handle, NULL, NULL, "vd", cmos_cmd))
283 return -EIO;
284
285 return 0;
286}
287
288/*************************************************************************
289 * ACPI device model
290 */
291
292static void drv_acpi_handle_init(char *name,
293 acpi_handle *handle, acpi_handle parent,
294 char **paths, int num_paths, char **path)
295{
296 int i;
297 acpi_status status;
298
299 vdbg_printk(TPACPI_DBG_INIT, "trying to locate ACPI handle for %s\n",
300 name);
301
302 for (i = 0; i < num_paths; i++) {
303 status = acpi_get_handle(parent, paths[i], handle);
304 if (ACPI_SUCCESS(status)) {
305 *path = paths[i];
306 dbg_printk(TPACPI_DBG_INIT,
307 "Found ACPI handle %s for %s\n",
308 *path, name);
309 return;
310 }
311 }
312
313 vdbg_printk(TPACPI_DBG_INIT, "ACPI handle for %s not found\n",
314 name);
315 *handle = NULL;
316}
317
318static void dispatch_acpi_notify(acpi_handle handle, u32 event, void *data)
319{
320 struct ibm_struct *ibm = data;
321
322 if (!ibm || !ibm->acpi || !ibm->acpi->notify)
323 return;
324
325 ibm->acpi->notify(ibm, event);
326}
327
328static int __init setup_acpi_notify(struct ibm_struct *ibm)
329{
330 acpi_status status;
331 int rc;
332
333 BUG_ON(!ibm->acpi);
334
335 if (!*ibm->acpi->handle)
336 return 0;
337
338 vdbg_printk(TPACPI_DBG_INIT,
339 "setting up ACPI notify for %s\n", ibm->name);
340
341 rc = acpi_bus_get_device(*ibm->acpi->handle, &ibm->acpi->device);
342 if (rc < 0) {
343 printk(IBM_ERR "acpi_bus_get_device(%s) failed: %d\n",
344 ibm->name, rc);
345 return -ENODEV;
346 }
347
348 acpi_driver_data(ibm->acpi->device) = ibm;
349 sprintf(acpi_device_class(ibm->acpi->device), "%s/%s",
350 IBM_ACPI_EVENT_PREFIX,
351 ibm->name);
352
353 status = acpi_install_notify_handler(*ibm->acpi->handle,
354 ibm->acpi->type, dispatch_acpi_notify, ibm);
355 if (ACPI_FAILURE(status)) {
356 if (status == AE_ALREADY_EXISTS) {
357 printk(IBM_NOTICE "another device driver is already handling %s events\n",
358 ibm->name);
359 } else {
360 printk(IBM_ERR "acpi_install_notify_handler(%s) failed: %d\n",
361 ibm->name, status);
362 }
363 return -ENODEV;
364 }
365 ibm->flags.acpi_notify_installed = 1;
366 return 0;
367}
368
369static int __init tpacpi_device_add(struct acpi_device *device)
370{
371 return 0;
372}
373
374static int __init register_tpacpi_subdriver(struct ibm_struct *ibm)
375{
376 int rc;
377
378 dbg_printk(TPACPI_DBG_INIT,
379 "registering %s as an ACPI driver\n", ibm->name);
380
381 BUG_ON(!ibm->acpi);
382
383 ibm->acpi->driver = kzalloc(sizeof(struct acpi_driver), GFP_KERNEL);
384 if (!ibm->acpi->driver) {
385 printk(IBM_ERR "kzalloc(ibm->driver) failed\n");
386 return -ENOMEM;
387 }
388
389 sprintf(ibm->acpi->driver->name, "%s_%s", IBM_NAME, ibm->name);
390 ibm->acpi->driver->ids = ibm->acpi->hid;
391 ibm->acpi->driver->ops.add = &tpacpi_device_add;
392
393 rc = acpi_bus_register_driver(ibm->acpi->driver);
394 if (rc < 0) {
395 printk(IBM_ERR "acpi_bus_register_driver(%s) failed: %d\n",
396 ibm->acpi->hid, rc);
397 kfree(ibm->acpi->driver);
398 ibm->acpi->driver = NULL;
399 } else if (!rc)
400 ibm->flags.acpi_driver_registered = 1;
401
402 return rc;
403}
404
405
406/****************************************************************************
407 ****************************************************************************
408 *
409 * Procfs Helpers
410 *
411 ****************************************************************************
412 ****************************************************************************/
413
414static int dispatch_procfs_read(char *page, char **start, off_t off,
415 int count, int *eof, void *data)
416{
417 struct ibm_struct *ibm = data;
418 int len;
419
420 if (!ibm || !ibm->read)
421 return -EINVAL;
422
423 len = ibm->read(page);
424 if (len < 0)
425 return len;
426
427 if (len <= off + count)
428 *eof = 1;
429 *start = page + off;
430 len -= off;
431 if (len > count)
432 len = count;
433 if (len < 0)
434 len = 0;
435
436 return len;
437}
438
439static int dispatch_procfs_write(struct file *file,
440 const char __user * userbuf,
441 unsigned long count, void *data)
442{
443 struct ibm_struct *ibm = data;
444 char *kernbuf;
445 int ret;
446
447 if (!ibm || !ibm->write)
448 return -EINVAL;
449
450 kernbuf = kmalloc(count + 2, GFP_KERNEL);
451 if (!kernbuf)
452 return -ENOMEM;
453
454 if (copy_from_user(kernbuf, userbuf, count)) {
455 kfree(kernbuf);
456 return -EFAULT;
457 }
458
459 kernbuf[count] = 0;
460 strcat(kernbuf, ",");
461 ret = ibm->write(kernbuf);
462 if (ret == 0)
463 ret = count;
464
465 kfree(kernbuf);
466
467 return ret;
468}
469
470static char *next_cmd(char **cmds)
471{
472 char *start = *cmds;
473 char *end;
474
475 while ((end = strchr(start, ',')) && end == start)
476 start = end + 1;
477
478 if (!end)
479 return NULL;
480
481 *end = 0;
482 *cmds = end + 1;
483 return start;
484}
485
486
487/****************************************************************************
488 ****************************************************************************
489 *
490 * Device model: hwmon and platform
491 *
492 ****************************************************************************
493 ****************************************************************************/
494
495static struct platform_device *tpacpi_pdev = NULL;
496static struct class_device *tpacpi_hwmon = NULL;
497
498static struct platform_driver tpacpi_pdriver = {
499 .driver = {
500 .name = IBM_DRVR_NAME,
501 .owner = THIS_MODULE,
502 },
503};
504
505
506/*************************************************************************
507 * thinkpad-acpi driver attributes
508 */
509
510/* interface_version --------------------------------------------------- */
511static ssize_t tpacpi_driver_interface_version_show(
512 struct device_driver *drv,
513 char *buf)
514{
515 return snprintf(buf, PAGE_SIZE, "0x%08x\n", TPACPI_SYSFS_VERSION);
516}
517
518static DRIVER_ATTR(interface_version, S_IRUGO,
519 tpacpi_driver_interface_version_show, NULL);
520
521/* debug_level --------------------------------------------------------- */
522static ssize_t tpacpi_driver_debug_show(struct device_driver *drv,
523 char *buf)
524{
525 return snprintf(buf, PAGE_SIZE, "0x%04x\n", dbg_level);
526}
527
528static ssize_t tpacpi_driver_debug_store(struct device_driver *drv,
529 const char *buf, size_t count)
530{
531 unsigned long t;
532
533 if (parse_strtoul(buf, 0xffff, &t))
534 return -EINVAL;
535
536 dbg_level = t;
537
538 return count;
539}
540
541static DRIVER_ATTR(debug_level, S_IWUSR | S_IRUGO,
542 tpacpi_driver_debug_show, tpacpi_driver_debug_store);
543
544/* version ------------------------------------------------------------- */
545static ssize_t tpacpi_driver_version_show(struct device_driver *drv,
546 char *buf)
547{
548 return snprintf(buf, PAGE_SIZE, "%s v%s\n", IBM_DESC, IBM_VERSION);
549}
550
551static DRIVER_ATTR(version, S_IRUGO,
552 tpacpi_driver_version_show, NULL);
553
554/* --------------------------------------------------------------------- */
555
556static struct driver_attribute* tpacpi_driver_attributes[] = {
557 &driver_attr_debug_level, &driver_attr_version,
558 &driver_attr_interface_version,
559};
560
561static int __init tpacpi_create_driver_attributes(struct device_driver *drv)
562{
563 int i, res;
564
565 i = 0;
566 res = 0;
567 while (!res && i < ARRAY_SIZE(tpacpi_driver_attributes)) {
568 res = driver_create_file(drv, tpacpi_driver_attributes[i]);
569 i++;
570 }
571
572 return res;
573}
574
575static void tpacpi_remove_driver_attributes(struct device_driver *drv)
576{
577 int i;
578
579 for(i = 0; i < ARRAY_SIZE(tpacpi_driver_attributes); i++)
580 driver_remove_file(drv, tpacpi_driver_attributes[i]);
581}
582
583/*************************************************************************
584 * sysfs support helpers
585 */
586
587struct attribute_set_obj {
588 struct attribute_set s;
589 struct attribute *a;
590} __attribute__((packed));
591
592static struct attribute_set *create_attr_set(unsigned int max_members,
593 const char* name)
594{
595 struct attribute_set_obj *sobj;
596
597 if (max_members == 0)
598 return NULL;
599
600 /* Allocates space for implicit NULL at the end too */
601 sobj = kzalloc(sizeof(struct attribute_set_obj) +
602 max_members * sizeof(struct attribute *),
603 GFP_KERNEL);
604 if (!sobj)
605 return NULL;
606 sobj->s.max_members = max_members;
607 sobj->s.group.attrs = &sobj->a;
608 sobj->s.group.name = name;
609
610 return &sobj->s;
611}
612
613/* not multi-threaded safe, use it in a single thread per set */
614static int add_to_attr_set(struct attribute_set* s, struct attribute *attr)
615{
616 if (!s || !attr)
617 return -EINVAL;
618
619 if (s->members >= s->max_members)
620 return -ENOMEM;
621
622 s->group.attrs[s->members] = attr;
623 s->members++;
624
625 return 0;
626}
627
628static int add_many_to_attr_set(struct attribute_set* s,
629 struct attribute **attr,
630 unsigned int count)
631{
632 int i, res;
633
634 for (i = 0; i < count; i++) {
635 res = add_to_attr_set(s, attr[i]);
636 if (res)
637 return res;
638 }
639
640 return 0;
641}
642
643static void delete_attr_set(struct attribute_set* s, struct kobject *kobj)
644{
645 sysfs_remove_group(kobj, &s->group);
646 destroy_attr_set(s);
647}
648
649static int parse_strtoul(const char *buf,
650 unsigned long max, unsigned long *value)
651{
652 char *endp;
653
654 *value = simple_strtoul(buf, &endp, 0);
655 while (*endp && isspace(*endp))
656 endp++;
657 if (*endp || *value > max)
658 return -EINVAL;
659
660 return 0;
661}
662
663/****************************************************************************
664 ****************************************************************************
665 *
666 * Subdrivers
667 *
668 ****************************************************************************
669 ****************************************************************************/
670
671/*************************************************************************
672 * thinkpad-acpi init subdriver
673 */
674
675static int __init thinkpad_acpi_driver_init(struct ibm_init_struct *iibm)
676{
677 printk(IBM_INFO "%s v%s\n", IBM_DESC, IBM_VERSION);
678 printk(IBM_INFO "%s\n", IBM_URL);
679
680 if (ibm_thinkpad_ec_found)
681 printk(IBM_INFO "ThinkPad EC firmware %s\n",
682 ibm_thinkpad_ec_found);
683
684 return 0;
685}
686
687static int thinkpad_acpi_driver_read(char *p)
688{
689 int len = 0;
690
691 len += sprintf(p + len, "driver:\t\t%s\n", IBM_DESC);
692 len += sprintf(p + len, "version:\t%s\n", IBM_VERSION);
693
694 return len;
695}
696
697static struct ibm_struct thinkpad_acpi_driver_data = {
698 .name = "driver",
699 .read = thinkpad_acpi_driver_read,
700};
701
702/*************************************************************************
703 * Hotkey subdriver
704 */
705
706static int hotkey_orig_status;
707static int hotkey_orig_mask;
708
709static struct attribute_set *hotkey_dev_attributes = NULL;
710
711/* sysfs hotkey enable ------------------------------------------------- */
712static ssize_t hotkey_enable_show(struct device *dev,
713 struct device_attribute *attr,
714 char *buf)
715{
716 int res, status, mask;
717
718 res = hotkey_get(&status, &mask);
719 if (res)
720 return res;
721
722 return snprintf(buf, PAGE_SIZE, "%d\n", status);
723}
724
725static ssize_t hotkey_enable_store(struct device *dev,
726 struct device_attribute *attr,
727 const char *buf, size_t count)
728{
729 unsigned long t;
730 int res, status, mask;
731
732 if (parse_strtoul(buf, 1, &t))
733 return -EINVAL;
734
735 res = hotkey_get(&status, &mask);
736 if (!res)
737 res = hotkey_set(t, mask);
738
739 return (res) ? res : count;
740}
741
742static struct device_attribute dev_attr_hotkey_enable =
743 __ATTR(enable, S_IWUSR | S_IRUGO,
744 hotkey_enable_show, hotkey_enable_store);
745
746/* sysfs hotkey mask --------------------------------------------------- */
747static ssize_t hotkey_mask_show(struct device *dev,
748 struct device_attribute *attr,
749 char *buf)
750{
751 int res, status, mask;
752
753 res = hotkey_get(&status, &mask);
754 if (res)
755 return res;
756
757 return snprintf(buf, PAGE_SIZE, "0x%04x\n", mask);
758}
759
760static ssize_t hotkey_mask_store(struct device *dev,
761 struct device_attribute *attr,
762 const char *buf, size_t count)
763{
764 unsigned long t;
765 int res, status, mask;
766
767 if (parse_strtoul(buf, 0xffff, &t))
768 return -EINVAL;
769
770 res = hotkey_get(&status, &mask);
771 if (!res)
772 hotkey_set(status, t);
773
774 return (res) ? res : count;
775}
776
777static struct device_attribute dev_attr_hotkey_mask =
778 __ATTR(mask, S_IWUSR | S_IRUGO,
779 hotkey_mask_show, hotkey_mask_store);
780
781/* sysfs hotkey bios_enabled ------------------------------------------- */
782static ssize_t hotkey_bios_enabled_show(struct device *dev,
783 struct device_attribute *attr,
784 char *buf)
785{
786 return snprintf(buf, PAGE_SIZE, "%d\n", hotkey_orig_status);
787}
788
789static struct device_attribute dev_attr_hotkey_bios_enabled =
790 __ATTR(bios_enabled, S_IRUGO, hotkey_bios_enabled_show, NULL);
791
792/* sysfs hotkey bios_mask ---------------------------------------------- */
793static ssize_t hotkey_bios_mask_show(struct device *dev,
794 struct device_attribute *attr,
795 char *buf)
796{
797 return snprintf(buf, PAGE_SIZE, "0x%04x\n", hotkey_orig_mask);
798}
799
800static struct device_attribute dev_attr_hotkey_bios_mask =
801 __ATTR(bios_mask, S_IRUGO, hotkey_bios_mask_show, NULL);
802
803/* --------------------------------------------------------------------- */
804
805static struct attribute *hotkey_mask_attributes[] = {
806 &dev_attr_hotkey_mask.attr,
807 &dev_attr_hotkey_bios_enabled.attr,
808 &dev_attr_hotkey_bios_mask.attr,
809};
810
811static int __init hotkey_init(struct ibm_init_struct *iibm)
812{
813 int res;
814
815 vdbg_printk(TPACPI_DBG_INIT, "initializing hotkey subdriver\n");
816
817 IBM_ACPIHANDLE_INIT(hkey);
818 mutex_init(&hotkey_mutex);
819
820 /* hotkey not supported on 570 */
821 tp_features.hotkey = hkey_handle != NULL;
822
823 vdbg_printk(TPACPI_DBG_INIT, "hotkeys are %s\n",
824 str_supported(tp_features.hotkey));
825
826 if (tp_features.hotkey) {
827 hotkey_dev_attributes = create_attr_set(4,
828 TPACPI_HOTKEY_SYSFS_GROUP);
829 if (!hotkey_dev_attributes)
830 return -ENOMEM;
831 res = add_to_attr_set(hotkey_dev_attributes,
832 &dev_attr_hotkey_enable.attr);
833 if (res)
834 return res;
835
836 /* mask not supported on 570, 600e/x, 770e, 770x, A21e, A2xm/p,
837 A30, R30, R31, T20-22, X20-21, X22-24 */
838 tp_features.hotkey_mask =
839 acpi_evalf(hkey_handle, NULL, "DHKN", "qv");
840
841 vdbg_printk(TPACPI_DBG_INIT, "hotkey masks are %s\n",
842 str_supported(tp_features.hotkey_mask));
843
844 res = hotkey_get(&hotkey_orig_status, &hotkey_orig_mask);
845 if (!res && tp_features.hotkey_mask) {
846 res = add_many_to_attr_set(hotkey_dev_attributes,
847 hotkey_mask_attributes,
848 ARRAY_SIZE(hotkey_mask_attributes));
849 }
850 if (!res)
851 res = register_attr_set_with_sysfs(
852 hotkey_dev_attributes,
853 &tpacpi_pdev->dev.kobj);
854
855 if (res)
856 return res;
857 }
858
859 return (tp_features.hotkey)? 0 : 1;
860}
861
862static void hotkey_exit(void)
863{
864 int res;
865
866 if (tp_features.hotkey) {
867 dbg_printk(TPACPI_DBG_EXIT, "restoring original hotkey mask\n");
868 res = hotkey_set(hotkey_orig_status, hotkey_orig_mask);
869 if (res)
870 printk(IBM_ERR "failed to restore hotkey to BIOS defaults\n");
871 }
872
873 if (hotkey_dev_attributes) {
874 delete_attr_set(hotkey_dev_attributes, &tpacpi_pdev->dev.kobj);
875 hotkey_dev_attributes = NULL;
876 }
877}
878
879static void hotkey_notify(struct ibm_struct *ibm, u32 event)
880{
881 int hkey;
882
883 if (acpi_evalf(hkey_handle, &hkey, "MHKP", "d"))
884 acpi_bus_generate_event(ibm->acpi->device, event, hkey);
885 else {
886 printk(IBM_ERR "unknown hotkey event %d\n", event);
887 acpi_bus_generate_event(ibm->acpi->device, event, 0);
888 }
889}
890
891/*
892 * Call with hotkey_mutex held
893 */
894static int hotkey_get(int *status, int *mask)
895{
896 if (!acpi_evalf(hkey_handle, status, "DHKC", "d"))
897 return -EIO;
898
899 if (tp_features.hotkey_mask)
900 if (!acpi_evalf(hkey_handle, mask, "DHKN", "d"))
901 return -EIO;
902
903 return 0;
904}
905
906/*
907 * Call with hotkey_mutex held
908 */
909static int hotkey_set(int status, int mask)
910{
911 int i;
912
913 if (!acpi_evalf(hkey_handle, NULL, "MHKC", "vd", status))
914 return -EIO;
915
916 if (tp_features.hotkey_mask)
917 for (i = 0; i < 32; i++) {
918 int bit = ((1 << i) & mask) != 0;
919 if (!acpi_evalf(hkey_handle,
920 NULL, "MHKM", "vdd", i + 1, bit))
921 return -EIO;
922 }
923
924 return 0;
925}
926
927/* procfs -------------------------------------------------------------- */
928static int hotkey_read(char *p)
929{
930 int res, status, mask;
931 int len = 0;
932
933 if (!tp_features.hotkey) {
934 len += sprintf(p + len, "status:\t\tnot supported\n");
935 return len;
936 }
937
938 res = mutex_lock_interruptible(&hotkey_mutex);
939 if (res < 0)
940 return res;
941 res = hotkey_get(&status, &mask);
942 mutex_unlock(&hotkey_mutex);
943 if (res)
944 return res;
945
946 len += sprintf(p + len, "status:\t\t%s\n", enabled(status, 0));
947 if (tp_features.hotkey_mask) {
948 len += sprintf(p + len, "mask:\t\t0x%04x\n", mask);
949 len += sprintf(p + len,
950 "commands:\tenable, disable, reset, <mask>\n");
951 } else {
952 len += sprintf(p + len, "mask:\t\tnot supported\n");
953 len += sprintf(p + len, "commands:\tenable, disable, reset\n");
954 }
955
956 return len;
957}
958
959static int hotkey_write(char *buf)
960{
961 int res, status, mask;
962 char *cmd;
963 int do_cmd = 0;
964
965 if (!tp_features.hotkey)
966 return -ENODEV;
967
968 res = mutex_lock_interruptible(&hotkey_mutex);
969 if (res < 0)
970 return res;
971
972 res = hotkey_get(&status, &mask);
973 if (res)
974 goto errexit;
975
976 res = 0;
977 while ((cmd = next_cmd(&buf))) {
978 if (strlencmp(cmd, "enable") == 0) {
979 status = 1;
980 } else if (strlencmp(cmd, "disable") == 0) {
981 status = 0;
982 } else if (strlencmp(cmd, "reset") == 0) {
983 status = hotkey_orig_status;
984 mask = hotkey_orig_mask;
985 } else if (sscanf(cmd, "0x%x", &mask) == 1) {
986 /* mask set */
987 } else if (sscanf(cmd, "%x", &mask) == 1) {
988 /* mask set */
989 } else {
990 res = -EINVAL;
991 goto errexit;
992 }
993 do_cmd = 1;
994 }
995
996 if (do_cmd)
997 res = hotkey_set(status, mask);
998
999errexit:
1000 mutex_unlock(&hotkey_mutex);
1001 return res;
1002}
1003
1004static struct tp_acpi_drv_struct ibm_hotkey_acpidriver = {
1005 .hid = IBM_HKEY_HID,
1006 .notify = hotkey_notify,
1007 .handle = &hkey_handle,
1008 .type = ACPI_DEVICE_NOTIFY,
1009};
1010
1011static struct ibm_struct hotkey_driver_data = {
1012 .name = "hotkey",
1013 .read = hotkey_read,
1014 .write = hotkey_write,
1015 .exit = hotkey_exit,
1016 .acpi = &ibm_hotkey_acpidriver,
1017};
1018
1019/*************************************************************************
1020 * Bluetooth subdriver
1021 */
1022
1023/* sysfs bluetooth enable ---------------------------------------------- */
1024static ssize_t bluetooth_enable_show(struct device *dev,
1025 struct device_attribute *attr,
1026 char *buf)
1027{
1028 int status;
1029
1030 status = bluetooth_get_radiosw();
1031 if (status < 0)
1032 return status;
1033
1034 return snprintf(buf, PAGE_SIZE, "%d\n", status ? 1 : 0);
1035}
1036
1037static ssize_t bluetooth_enable_store(struct device *dev,
1038 struct device_attribute *attr,
1039 const char *buf, size_t count)
1040{
1041 unsigned long t;
1042 int res;
1043
1044 if (parse_strtoul(buf, 1, &t))
1045 return -EINVAL;
1046
1047 res = bluetooth_set_radiosw(t);
1048
1049 return (res) ? res : count;
1050}
1051
1052static struct device_attribute dev_attr_bluetooth_enable =
1053 __ATTR(enable, S_IWUSR | S_IRUGO,
1054 bluetooth_enable_show, bluetooth_enable_store);
1055
1056/* --------------------------------------------------------------------- */
1057
1058static struct attribute *bluetooth_attributes[] = {
1059 &dev_attr_bluetooth_enable.attr,
1060 NULL
1061};
1062
1063static const struct attribute_group bluetooth_attr_group = {
1064 .name = TPACPI_BLUETH_SYSFS_GROUP,
1065 .attrs = bluetooth_attributes,
1066};
1067
1068static int __init bluetooth_init(struct ibm_init_struct *iibm)
1069{
1070 int res;
1071 int status = 0;
1072
1073 vdbg_printk(TPACPI_DBG_INIT, "initializing bluetooth subdriver\n");
1074
1075 IBM_ACPIHANDLE_INIT(hkey);
1076
1077 /* bluetooth not supported on 570, 600e/x, 770e, 770x, A21e, A2xm/p,
1078 G4x, R30, R31, R40e, R50e, T20-22, X20-21 */
1079 tp_features.bluetooth = hkey_handle &&
1080 acpi_evalf(hkey_handle, &status, "GBDC", "qd");
1081
1082 vdbg_printk(TPACPI_DBG_INIT, "bluetooth is %s, status 0x%02x\n",
1083 str_supported(tp_features.bluetooth),
1084 status);
1085
1086 if (tp_features.bluetooth) {
1087 if (!(status & TP_ACPI_BLUETOOTH_HWPRESENT)) {
1088 /* no bluetooth hardware present in system */
1089 tp_features.bluetooth = 0;
1090 dbg_printk(TPACPI_DBG_INIT,
1091 "bluetooth hardware not installed\n");
1092 } else {
1093 res = sysfs_create_group(&tpacpi_pdev->dev.kobj,
1094 &bluetooth_attr_group);
1095 if (res)
1096 return res;
1097 }
1098 }
1099
1100 return (tp_features.bluetooth)? 0 : 1;
1101}
1102
1103static void bluetooth_exit(void)
1104{
1105 sysfs_remove_group(&tpacpi_pdev->dev.kobj,
1106 &bluetooth_attr_group);
1107}
1108
1109static int bluetooth_get_radiosw(void)
1110{
1111 int status;
1112
1113 if (!tp_features.bluetooth)
1114 return -ENODEV;
1115
1116 if (!acpi_evalf(hkey_handle, &status, "GBDC", "d"))
1117 return -EIO;
1118
1119 return ((status & TP_ACPI_BLUETOOTH_RADIOSSW) != 0);
1120}
1121
1122static int bluetooth_set_radiosw(int radio_on)
1123{
1124 int status;
1125
1126 if (!tp_features.bluetooth)
1127 return -ENODEV;
1128
1129 if (!acpi_evalf(hkey_handle, &status, "GBDC", "d"))
1130 return -EIO;
1131 if (radio_on)
1132 status |= TP_ACPI_BLUETOOTH_RADIOSSW;
1133 else
1134 status &= ~TP_ACPI_BLUETOOTH_RADIOSSW;
1135 if (!acpi_evalf(hkey_handle, NULL, "SBDC", "vd", status))
1136 return -EIO;
1137
1138 return 0;
1139}
1140
1141/* procfs -------------------------------------------------------------- */
1142static int bluetooth_read(char *p)
1143{
1144 int len = 0;
1145 int status = bluetooth_get_radiosw();
1146
1147 if (!tp_features.bluetooth)
1148 len += sprintf(p + len, "status:\t\tnot supported\n");
1149 else {
1150 len += sprintf(p + len, "status:\t\t%s\n",
1151 (status)? "enabled" : "disabled");
1152 len += sprintf(p + len, "commands:\tenable, disable\n");
1153 }
1154
1155 return len;
1156}
1157
1158static int bluetooth_write(char *buf)
1159{
1160 char *cmd;
1161
1162 if (!tp_features.bluetooth)
1163 return -ENODEV;
1164
1165 while ((cmd = next_cmd(&buf))) {
1166 if (strlencmp(cmd, "enable") == 0) {
1167 bluetooth_set_radiosw(1);
1168 } else if (strlencmp(cmd, "disable") == 0) {
1169 bluetooth_set_radiosw(0);
1170 } else
1171 return -EINVAL;
1172 }
1173
1174 return 0;
1175}
1176
1177static struct ibm_struct bluetooth_driver_data = {
1178 .name = "bluetooth",
1179 .read = bluetooth_read,
1180 .write = bluetooth_write,
1181 .exit = bluetooth_exit,
1182};
1183
1184/*************************************************************************
1185 * Wan subdriver
1186 */
1187
1188/* sysfs wan enable ---------------------------------------------------- */
1189static ssize_t wan_enable_show(struct device *dev,
1190 struct device_attribute *attr,
1191 char *buf)
1192{
1193 int status;
1194
1195 status = wan_get_radiosw();
1196 if (status < 0)
1197 return status;
1198
1199 return snprintf(buf, PAGE_SIZE, "%d\n", status ? 1 : 0);
1200}
1201
1202static ssize_t wan_enable_store(struct device *dev,
1203 struct device_attribute *attr,
1204 const char *buf, size_t count)
1205{
1206 unsigned long t;
1207 int res;
1208
1209 if (parse_strtoul(buf, 1, &t))
1210 return -EINVAL;
1211
1212 res = wan_set_radiosw(t);
1213
1214 return (res) ? res : count;
1215}
1216
1217static struct device_attribute dev_attr_wan_enable =
1218 __ATTR(enable, S_IWUSR | S_IRUGO,
1219 wan_enable_show, wan_enable_store);
1220
1221/* --------------------------------------------------------------------- */
1222
1223static struct attribute *wan_attributes[] = {
1224 &dev_attr_wan_enable.attr,
1225 NULL
1226};
1227
1228static const struct attribute_group wan_attr_group = {
1229 .name = TPACPI_WAN_SYSFS_GROUP,
1230 .attrs = wan_attributes,
1231};
1232
1233static int __init wan_init(struct ibm_init_struct *iibm)
1234{
1235 int res;
1236 int status = 0;
1237
1238 vdbg_printk(TPACPI_DBG_INIT, "initializing wan subdriver\n");
1239
1240 IBM_ACPIHANDLE_INIT(hkey);
1241
1242 tp_features.wan = hkey_handle &&
1243 acpi_evalf(hkey_handle, &status, "GWAN", "qd");
1244
1245 vdbg_printk(TPACPI_DBG_INIT, "wan is %s, status 0x%02x\n",
1246 str_supported(tp_features.wan),
1247 status);
1248
1249 if (tp_features.wan) {
1250 if (!(status & TP_ACPI_WANCARD_HWPRESENT)) {
1251 /* no wan hardware present in system */
1252 tp_features.wan = 0;
1253 dbg_printk(TPACPI_DBG_INIT,
1254 "wan hardware not installed\n");
1255 } else {
1256 res = sysfs_create_group(&tpacpi_pdev->dev.kobj,
1257 &wan_attr_group);
1258 if (res)
1259 return res;
1260 }
1261 }
1262
1263 return (tp_features.wan)? 0 : 1;
1264}
1265
1266static void wan_exit(void)
1267{
1268 sysfs_remove_group(&tpacpi_pdev->dev.kobj,
1269 &wan_attr_group);
1270}
1271
1272static int wan_get_radiosw(void)
1273{
1274 int status;
1275
1276 if (!tp_features.wan)
1277 return -ENODEV;
1278
1279 if (!acpi_evalf(hkey_handle, &status, "GWAN", "d"))
1280 return -EIO;
1281
1282 return ((status & TP_ACPI_WANCARD_RADIOSSW) != 0);
1283}
1284
1285static int wan_set_radiosw(int radio_on)
1286{
1287 int status;
1288
1289 if (!tp_features.wan)
1290 return -ENODEV;
1291
1292 if (!acpi_evalf(hkey_handle, &status, "GWAN", "d"))
1293 return -EIO;
1294 if (radio_on)
1295 status |= TP_ACPI_WANCARD_RADIOSSW;
1296 else
1297 status &= ~TP_ACPI_WANCARD_RADIOSSW;
1298 if (!acpi_evalf(hkey_handle, NULL, "SWAN", "vd", status))
1299 return -EIO;
1300
1301 return 0;
1302}
1303
1304/* procfs -------------------------------------------------------------- */
1305static int wan_read(char *p)
1306{
1307 int len = 0;
1308 int status = wan_get_radiosw();
1309
1310 if (!tp_features.wan)
1311 len += sprintf(p + len, "status:\t\tnot supported\n");
1312 else {
1313 len += sprintf(p + len, "status:\t\t%s\n",
1314 (status)? "enabled" : "disabled");
1315 len += sprintf(p + len, "commands:\tenable, disable\n");
1316 }
1317
1318 return len;
1319}
1320
1321static int wan_write(char *buf)
1322{
1323 char *cmd;
1324
1325 if (!tp_features.wan)
1326 return -ENODEV;
1327
1328 while ((cmd = next_cmd(&buf))) {
1329 if (strlencmp(cmd, "enable") == 0) {
1330 wan_set_radiosw(1);
1331 } else if (strlencmp(cmd, "disable") == 0) {
1332 wan_set_radiosw(0);
1333 } else
1334 return -EINVAL;
1335 }
1336
1337 return 0;
1338}
1339
1340static struct ibm_struct wan_driver_data = {
1341 .name = "wan",
1342 .read = wan_read,
1343 .write = wan_write,
1344 .exit = wan_exit,
1345 .flags.experimental = 1,
1346};
1347
1348/*************************************************************************
1349 * Video subdriver
1350 */
1351
1352static enum video_access_mode video_supported;
1353static int video_orig_autosw;
1354
1355IBM_HANDLE(vid, root, "\\_SB.PCI.AGP.VGA", /* 570 */
1356 "\\_SB.PCI0.AGP0.VID0", /* 600e/x, 770x */
1357 "\\_SB.PCI0.VID0", /* 770e */
1358 "\\_SB.PCI0.VID", /* A21e, G4x, R50e, X30, X40 */
1359 "\\_SB.PCI0.AGP.VID", /* all others */
1360 ); /* R30, R31 */
1361
1362IBM_HANDLE(vid2, root, "\\_SB.PCI0.AGPB.VID"); /* G41 */
1363
1364static int __init video_init(struct ibm_init_struct *iibm)
1365{
1366 int ivga;
1367
1368 vdbg_printk(TPACPI_DBG_INIT, "initializing video subdriver\n");
1369
1370 IBM_ACPIHANDLE_INIT(vid);
1371 IBM_ACPIHANDLE_INIT(vid2);
1372
1373 if (vid2_handle && acpi_evalf(NULL, &ivga, "\\IVGA", "d") && ivga)
1374 /* G41, assume IVGA doesn't change */
1375 vid_handle = vid2_handle;
1376
1377 if (!vid_handle)
1378 /* video switching not supported on R30, R31 */
1379 video_supported = TPACPI_VIDEO_NONE;
1380 else if (acpi_evalf(vid_handle, &video_orig_autosw, "SWIT", "qd"))
1381 /* 570 */
1382 video_supported = TPACPI_VIDEO_570;
1383 else if (acpi_evalf(vid_handle, &video_orig_autosw, "^VADL", "qd"))
1384 /* 600e/x, 770e, 770x */
1385 video_supported = TPACPI_VIDEO_770;
1386 else
1387 /* all others */
1388 video_supported = TPACPI_VIDEO_NEW;
1389
1390 vdbg_printk(TPACPI_DBG_INIT, "video is %s, mode %d\n",
1391 str_supported(video_supported != TPACPI_VIDEO_NONE),
1392 video_supported);
1393
1394 return (video_supported != TPACPI_VIDEO_NONE)? 0 : 1;
1395}
1396
1397static void video_exit(void)
1398{
1399 dbg_printk(TPACPI_DBG_EXIT,
1400 "restoring original video autoswitch mode\n");
1401 if (video_autosw_set(video_orig_autosw))
1402 printk(IBM_ERR "error while trying to restore original "
1403 "video autoswitch mode\n");
1404}
1405
1406static int video_outputsw_get(void)
1407{
1408 int status = 0;
1409 int i;
1410
1411 switch (video_supported) {
1412 case TPACPI_VIDEO_570:
1413 if (!acpi_evalf(NULL, &i, "\\_SB.PHS", "dd",
1414 TP_ACPI_VIDEO_570_PHSCMD))
1415 return -EIO;
1416 status = i & TP_ACPI_VIDEO_570_PHSMASK;
1417 break;
1418 case TPACPI_VIDEO_770:
1419 if (!acpi_evalf(NULL, &i, "\\VCDL", "d"))
1420 return -EIO;
1421 if (i)
1422 status |= TP_ACPI_VIDEO_S_LCD;
1423 if (!acpi_evalf(NULL, &i, "\\VCDC", "d"))
1424 return -EIO;
1425 if (i)
1426 status |= TP_ACPI_VIDEO_S_CRT;
1427 break;
1428 case TPACPI_VIDEO_NEW:
1429 if (!acpi_evalf(NULL, NULL, "\\VUPS", "vd", 1) ||
1430 !acpi_evalf(NULL, &i, "\\VCDC", "d"))
1431 return -EIO;
1432 if (i)
1433 status |= TP_ACPI_VIDEO_S_CRT;
1434
1435 if (!acpi_evalf(NULL, NULL, "\\VUPS", "vd", 0) ||
1436 !acpi_evalf(NULL, &i, "\\VCDL", "d"))
1437 return -EIO;
1438 if (i)
1439 status |= TP_ACPI_VIDEO_S_LCD;
1440 if (!acpi_evalf(NULL, &i, "\\VCDD", "d"))
1441 return -EIO;
1442 if (i)
1443 status |= TP_ACPI_VIDEO_S_DVI;
1444 break;
1445 default:
1446 return -ENOSYS;
1447 }
1448
1449 return status;
1450}
1451
1452static int video_outputsw_set(int status)
1453{
1454 int autosw;
1455 int res = 0;
1456
1457 switch (video_supported) {
1458 case TPACPI_VIDEO_570:
1459 res = acpi_evalf(NULL, NULL,
1460 "\\_SB.PHS2", "vdd",
1461 TP_ACPI_VIDEO_570_PHS2CMD,
1462 status | TP_ACPI_VIDEO_570_PHS2SET);
1463 break;
1464 case TPACPI_VIDEO_770:
1465 autosw = video_autosw_get();
1466 if (autosw < 0)
1467 return autosw;
1468
1469 res = video_autosw_set(1);
1470 if (res)
1471 return res;
1472 res = acpi_evalf(vid_handle, NULL,
1473 "ASWT", "vdd", status * 0x100, 0);
1474 if (!autosw && video_autosw_set(autosw)) {
1475 printk(IBM_ERR "video auto-switch left enabled due to error\n");
1476 return -EIO;
1477 }
1478 break;
1479 case TPACPI_VIDEO_NEW:
1480 res = acpi_evalf(NULL, NULL, "\\VUPS", "vd", 0x80) &&
1481 acpi_evalf(NULL, NULL, "\\VSDS", "vdd", status, 1);
1482 break;
1483 default:
1484 return -ENOSYS;
1485 }
1486
1487 return (res)? 0 : -EIO;
1488}
1489
1490static int video_autosw_get(void)
1491{
1492 int autosw = 0;
1493
1494 switch (video_supported) {
1495 case TPACPI_VIDEO_570:
1496 if (!acpi_evalf(vid_handle, &autosw, "SWIT", "d"))
1497 return -EIO;
1498 break;
1499 case TPACPI_VIDEO_770:
1500 case TPACPI_VIDEO_NEW:
1501 if (!acpi_evalf(vid_handle, &autosw, "^VDEE", "d"))
1502 return -EIO;
1503 break;
1504 default:
1505 return -ENOSYS;
1506 }
1507
1508 return autosw & 1;
1509}
1510
1511static int video_autosw_set(int enable)
1512{
1513 if (!acpi_evalf(vid_handle, NULL, "_DOS", "vd", (enable)? 1 : 0))
1514 return -EIO;
1515 return 0;
1516}
1517
1518static int video_outputsw_cycle(void)
1519{
1520 int autosw = video_autosw_get();
1521 int res;
1522
1523 if (autosw < 0)
1524 return autosw;
1525
1526 switch (video_supported) {
1527 case TPACPI_VIDEO_570:
1528 res = video_autosw_set(1);
1529 if (res)
1530 return res;
1531 res = acpi_evalf(ec_handle, NULL, "_Q16", "v");
1532 break;
1533 case TPACPI_VIDEO_770:
1534 case TPACPI_VIDEO_NEW:
1535 res = video_autosw_set(1);
1536 if (res)
1537 return res;
1538 res = acpi_evalf(vid_handle, NULL, "VSWT", "v");
1539 break;
1540 default:
1541 return -ENOSYS;
1542 }
1543 if (!autosw && video_autosw_set(autosw)) {
1544 printk(IBM_ERR "video auto-switch left enabled due to error\n");
1545 return -EIO;
1546 }
1547
1548 return (res)? 0 : -EIO;
1549}
1550
1551static int video_expand_toggle(void)
1552{
1553 switch (video_supported) {
1554 case TPACPI_VIDEO_570:
1555 return acpi_evalf(ec_handle, NULL, "_Q17", "v")?
1556 0 : -EIO;
1557 case TPACPI_VIDEO_770:
1558 return acpi_evalf(vid_handle, NULL, "VEXP", "v")?
1559 0 : -EIO;
1560 case TPACPI_VIDEO_NEW:
1561 return acpi_evalf(NULL, NULL, "\\VEXP", "v")?
1562 0 : -EIO;
1563 default:
1564 return -ENOSYS;
1565 }
1566 /* not reached */
1567}
1568
1569static int video_read(char *p)
1570{
1571 int status, autosw;
1572 int len = 0;
1573
1574 if (video_supported == TPACPI_VIDEO_NONE) {
1575 len += sprintf(p + len, "status:\t\tnot supported\n");
1576 return len;
1577 }
1578
1579 status = video_outputsw_get();
1580 if (status < 0)
1581 return status;
1582
1583 autosw = video_autosw_get();
1584 if (autosw < 0)
1585 return autosw;
1586
1587 len += sprintf(p + len, "status:\t\tsupported\n");
1588 len += sprintf(p + len, "lcd:\t\t%s\n", enabled(status, 0));
1589 len += sprintf(p + len, "crt:\t\t%s\n", enabled(status, 1));
1590 if (video_supported == TPACPI_VIDEO_NEW)
1591 len += sprintf(p + len, "dvi:\t\t%s\n", enabled(status, 3));
1592 len += sprintf(p + len, "auto:\t\t%s\n", enabled(autosw, 0));
1593 len += sprintf(p + len, "commands:\tlcd_enable, lcd_disable\n");
1594 len += sprintf(p + len, "commands:\tcrt_enable, crt_disable\n");
1595 if (video_supported == TPACPI_VIDEO_NEW)
1596 len += sprintf(p + len, "commands:\tdvi_enable, dvi_disable\n");
1597 len += sprintf(p + len, "commands:\tauto_enable, auto_disable\n");
1598 len += sprintf(p + len, "commands:\tvideo_switch, expand_toggle\n");
1599
1600 return len;
1601}
1602
1603static int video_write(char *buf)
1604{
1605 char *cmd;
1606 int enable, disable, status;
1607 int res;
1608
1609 if (video_supported == TPACPI_VIDEO_NONE)
1610 return -ENODEV;
1611
1612 enable = 0;
1613 disable = 0;
1614
1615 while ((cmd = next_cmd(&buf))) {
1616 if (strlencmp(cmd, "lcd_enable") == 0) {
1617 enable |= TP_ACPI_VIDEO_S_LCD;
1618 } else if (strlencmp(cmd, "lcd_disable") == 0) {
1619 disable |= TP_ACPI_VIDEO_S_LCD;
1620 } else if (strlencmp(cmd, "crt_enable") == 0) {
1621 enable |= TP_ACPI_VIDEO_S_CRT;
1622 } else if (strlencmp(cmd, "crt_disable") == 0) {
1623 disable |= TP_ACPI_VIDEO_S_CRT;
1624 } else if (video_supported == TPACPI_VIDEO_NEW &&
1625 strlencmp(cmd, "dvi_enable") == 0) {
1626 enable |= TP_ACPI_VIDEO_S_DVI;
1627 } else if (video_supported == TPACPI_VIDEO_NEW &&
1628 strlencmp(cmd, "dvi_disable") == 0) {
1629 disable |= TP_ACPI_VIDEO_S_DVI;
1630 } else if (strlencmp(cmd, "auto_enable") == 0) {
1631 res = video_autosw_set(1);
1632 if (res)
1633 return res;
1634 } else if (strlencmp(cmd, "auto_disable") == 0) {
1635 res = video_autosw_set(0);
1636 if (res)
1637 return res;
1638 } else if (strlencmp(cmd, "video_switch") == 0) {
1639 res = video_outputsw_cycle();
1640 if (res)
1641 return res;
1642 } else if (strlencmp(cmd, "expand_toggle") == 0) {
1643 res = video_expand_toggle();
1644 if (res)
1645 return res;
1646 } else
1647 return -EINVAL;
1648 }
1649
1650 if (enable || disable) {
1651 status = video_outputsw_get();
1652 if (status < 0)
1653 return status;
1654 res = video_outputsw_set((status & ~disable) | enable);
1655 if (res)
1656 return res;
1657 }
1658
1659 return 0;
1660}
1661
1662static struct ibm_struct video_driver_data = {
1663 .name = "video",
1664 .read = video_read,
1665 .write = video_write,
1666 .exit = video_exit,
1667};
1668
1669/*************************************************************************
1670 * Light (thinklight) subdriver
1671 */
1672
1673IBM_HANDLE(lght, root, "\\LGHT"); /* A21e, A2xm/p, T20-22, X20-21 */
1674IBM_HANDLE(ledb, ec, "LEDB"); /* G4x */
1675
1676static int __init light_init(struct ibm_init_struct *iibm)
1677{
1678 vdbg_printk(TPACPI_DBG_INIT, "initializing light subdriver\n");
1679
1680 IBM_ACPIHANDLE_INIT(ledb);
1681 IBM_ACPIHANDLE_INIT(lght);
1682 IBM_ACPIHANDLE_INIT(cmos);
1683
1684 /* light not supported on 570, 600e/x, 770e, 770x, G4x, R30, R31 */
1685 tp_features.light = (cmos_handle || lght_handle) && !ledb_handle;
1686
1687 if (tp_features.light)
1688 /* light status not supported on
1689 570, 600e/x, 770e, 770x, G4x, R30, R31, R32, X20 */
1690 tp_features.light_status =
1691 acpi_evalf(ec_handle, NULL, "KBLT", "qv");
1692
1693 vdbg_printk(TPACPI_DBG_INIT, "light is %s\n",
1694 str_supported(tp_features.light));
1695
1696 return (tp_features.light)? 0 : 1;
1697}
1698
1699static int light_read(char *p)
1700{
1701 int len = 0;
1702 int status = 0;
1703
1704 if (!tp_features.light) {
1705 len += sprintf(p + len, "status:\t\tnot supported\n");
1706 } else if (!tp_features.light_status) {
1707 len += sprintf(p + len, "status:\t\tunknown\n");
1708 len += sprintf(p + len, "commands:\ton, off\n");
1709 } else {
1710 if (!acpi_evalf(ec_handle, &status, "KBLT", "d"))
1711 return -EIO;
1712 len += sprintf(p + len, "status:\t\t%s\n", onoff(status, 0));
1713 len += sprintf(p + len, "commands:\ton, off\n");
1714 }
1715
1716 return len;
1717}
1718
1719static int light_write(char *buf)
1720{
1721 int cmos_cmd, lght_cmd;
1722 char *cmd;
1723 int success;
1724
1725 if (!tp_features.light)
1726 return -ENODEV;
1727
1728 while ((cmd = next_cmd(&buf))) {
1729 if (strlencmp(cmd, "on") == 0) {
1730 cmos_cmd = 0x0c;
1731 lght_cmd = 1;
1732 } else if (strlencmp(cmd, "off") == 0) {
1733 cmos_cmd = 0x0d;
1734 lght_cmd = 0;
1735 } else
1736 return -EINVAL;
1737
1738 success = cmos_handle ?
1739 acpi_evalf(cmos_handle, NULL, NULL, "vd", cmos_cmd) :
1740 acpi_evalf(lght_handle, NULL, NULL, "vd", lght_cmd);
1741 if (!success)
1742 return -EIO;
1743 }
1744
1745 return 0;
1746}
1747
1748static struct ibm_struct light_driver_data = {
1749 .name = "light",
1750 .read = light_read,
1751 .write = light_write,
1752};
1753
1754/*************************************************************************
1755 * Dock subdriver
1756 */
1757
1758#ifdef CONFIG_THINKPAD_ACPI_DOCK
1759
1760IBM_HANDLE(dock, root, "\\_SB.GDCK", /* X30, X31, X40 */
1761 "\\_SB.PCI0.DOCK", /* 600e/x,770e,770x,A2xm/p,T20-22,X20-21 */
1762 "\\_SB.PCI0.PCI1.DOCK", /* all others */
1763 "\\_SB.PCI.ISA.SLCE", /* 570 */
1764 ); /* A21e,G4x,R30,R31,R32,R40,R40e,R50e */
1765
1766/* don't list other alternatives as we install a notify handler on the 570 */
1767IBM_HANDLE(pci, root, "\\_SB.PCI"); /* 570 */
1768
1769static struct tp_acpi_drv_struct ibm_dock_acpidriver[2] = {
1770 {
1771 .notify = dock_notify,
1772 .handle = &dock_handle,
1773 .type = ACPI_SYSTEM_NOTIFY,
1774 },
1775 {
1776 .hid = IBM_PCI_HID,
1777 .notify = dock_notify,
1778 .handle = &pci_handle,
1779 .type = ACPI_SYSTEM_NOTIFY,
1780 },
1781};
1782
1783static struct ibm_struct dock_driver_data[2] = {
1784 {
1785 .name = "dock",
1786 .read = dock_read,
1787 .write = dock_write,
1788 .acpi = &ibm_dock_acpidriver[0],
1789 },
1790 {
1791 .name = "dock",
1792 .acpi = &ibm_dock_acpidriver[1],
1793 },
1794};
1795
1796#define dock_docked() (_sta(dock_handle) & 1)
1797
1798static int __init dock_init(struct ibm_init_struct *iibm)
1799{
1800 vdbg_printk(TPACPI_DBG_INIT, "initializing dock subdriver\n");
1801
1802 IBM_ACPIHANDLE_INIT(dock);
1803
1804 vdbg_printk(TPACPI_DBG_INIT, "dock is %s\n",
1805 str_supported(dock_handle != NULL));
1806
1807 return (dock_handle)? 0 : 1;
1808}
1809
1810static int __init dock_init2(struct ibm_init_struct *iibm)
1811{
1812 int dock2_needed;
1813
1814 vdbg_printk(TPACPI_DBG_INIT, "initializing dock subdriver part 2\n");
1815
1816 if (dock_driver_data[0].flags.acpi_driver_registered &&
1817 dock_driver_data[0].flags.acpi_notify_installed) {
1818 IBM_ACPIHANDLE_INIT(pci);
1819 dock2_needed = (pci_handle != NULL);
1820 vdbg_printk(TPACPI_DBG_INIT,
1821 "dock PCI handler for the TP 570 is %s\n",
1822 str_supported(dock2_needed));
1823 } else {
1824 vdbg_printk(TPACPI_DBG_INIT,
1825 "dock subdriver part 2 not required\n");
1826 dock2_needed = 0;
1827 }
1828
1829 return (dock2_needed)? 0 : 1;
1830}
1831
1832static void dock_notify(struct ibm_struct *ibm, u32 event)
1833{
1834 int docked = dock_docked();
1835 int pci = ibm->acpi->hid && strstr(ibm->acpi->hid, IBM_PCI_HID);
1836
1837 if (event == 1 && !pci) /* 570 */
1838 acpi_bus_generate_event(ibm->acpi->device, event, 1); /* button */
1839 else if (event == 1 && pci) /* 570 */
1840 acpi_bus_generate_event(ibm->acpi->device, event, 3); /* dock */
1841 else if (event == 3 && docked)
1842 acpi_bus_generate_event(ibm->acpi->device, event, 1); /* button */
1843 else if (event == 3 && !docked)
1844 acpi_bus_generate_event(ibm->acpi->device, event, 2); /* undock */
1845 else if (event == 0 && docked)
1846 acpi_bus_generate_event(ibm->acpi->device, event, 3); /* dock */
1847 else {
1848 printk(IBM_ERR "unknown dock event %d, status %d\n",
1849 event, _sta(dock_handle));
1850 acpi_bus_generate_event(ibm->acpi->device, event, 0); /* unknown */
1851 }
1852}
1853
1854static int dock_read(char *p)
1855{
1856 int len = 0;
1857 int docked = dock_docked();
1858
1859 if (!dock_handle)
1860 len += sprintf(p + len, "status:\t\tnot supported\n");
1861 else if (!docked)
1862 len += sprintf(p + len, "status:\t\tundocked\n");
1863 else {
1864 len += sprintf(p + len, "status:\t\tdocked\n");
1865 len += sprintf(p + len, "commands:\tdock, undock\n");
1866 }
1867
1868 return len;
1869}
1870
1871static int dock_write(char *buf)
1872{
1873 char *cmd;
1874
1875 if (!dock_docked())
1876 return -ENODEV;
1877
1878 while ((cmd = next_cmd(&buf))) {
1879 if (strlencmp(cmd, "undock") == 0) {
1880 if (!acpi_evalf(dock_handle, NULL, "_DCK", "vd", 0) ||
1881 !acpi_evalf(dock_handle, NULL, "_EJ0", "vd", 1))
1882 return -EIO;
1883 } else if (strlencmp(cmd, "dock") == 0) {
1884 if (!acpi_evalf(dock_handle, NULL, "_DCK", "vd", 1))
1885 return -EIO;
1886 } else
1887 return -EINVAL;
1888 }
1889
1890 return 0;
1891}
1892
1893#endif /* CONFIG_THINKPAD_ACPI_DOCK */
1894
1895/*************************************************************************
1896 * Bay subdriver
1897 */
1898
1899#ifdef CONFIG_THINKPAD_ACPI_BAY
1900IBM_HANDLE(bay, root, "\\_SB.PCI.IDE.SECN.MAST", /* 570 */
1901 "\\_SB.PCI0.IDE0.IDES.IDSM", /* 600e/x, 770e, 770x */
1902 "\\_SB.PCI0.SATA.SCND.MSTR", /* T60, X60, Z60 */
1903 "\\_SB.PCI0.IDE0.SCND.MSTR", /* all others */
1904 ); /* A21e, R30, R31 */
1905IBM_HANDLE(bay_ej, bay, "_EJ3", /* 600e/x, A2xm/p, A3x */
1906 "_EJ0", /* all others */
1907 ); /* 570,A21e,G4x,R30,R31,R32,R40e,R50e */
1908IBM_HANDLE(bay2, root, "\\_SB.PCI0.IDE0.PRIM.SLAV", /* A3x, R32 */
1909 "\\_SB.PCI0.IDE0.IDEP.IDPS", /* 600e/x, 770e, 770x */
1910 ); /* all others */
1911IBM_HANDLE(bay2_ej, bay2, "_EJ3", /* 600e/x, 770e, A3x */
1912 "_EJ0", /* 770x */
1913 ); /* all others */
1914
1915static int __init bay_init(struct ibm_init_struct *iibm)
1916{
1917 vdbg_printk(TPACPI_DBG_INIT, "initializing bay subdriver\n");
1918
1919 IBM_ACPIHANDLE_INIT(bay);
1920 if (bay_handle)
1921 IBM_ACPIHANDLE_INIT(bay_ej);
1922 IBM_ACPIHANDLE_INIT(bay2);
1923 if (bay2_handle)
1924 IBM_ACPIHANDLE_INIT(bay2_ej);
1925
1926 tp_features.bay_status = bay_handle &&
1927 acpi_evalf(bay_handle, NULL, "_STA", "qv");
1928 tp_features.bay_status2 = bay2_handle &&
1929 acpi_evalf(bay2_handle, NULL, "_STA", "qv");
1930
1931 tp_features.bay_eject = bay_handle && bay_ej_handle &&
1932 (strlencmp(bay_ej_path, "_EJ0") == 0 || experimental);
1933 tp_features.bay_eject2 = bay2_handle && bay2_ej_handle &&
1934 (strlencmp(bay2_ej_path, "_EJ0") == 0 || experimental);
1935
1936 vdbg_printk(TPACPI_DBG_INIT,
1937 "bay 1: status %s, eject %s; bay 2: status %s, eject %s\n",
1938 str_supported(tp_features.bay_status),
1939 str_supported(tp_features.bay_eject),
1940 str_supported(tp_features.bay_status2),
1941 str_supported(tp_features.bay_eject2));
1942
1943 return (tp_features.bay_status || tp_features.bay_eject ||
1944 tp_features.bay_status2 || tp_features.bay_eject2)? 0 : 1;
1945}
1946
1947static void bay_notify(struct ibm_struct *ibm, u32 event)
1948{
1949 acpi_bus_generate_event(ibm->acpi->device, event, 0);
1950}
1951
1952#define bay_occupied(b) (_sta(b##_handle) & 1)
1953
1954static int bay_read(char *p)
1955{
1956 int len = 0;
1957 int occupied = bay_occupied(bay);
1958 int occupied2 = bay_occupied(bay2);
1959 int eject, eject2;
1960
1961 len += sprintf(p + len, "status:\t\t%s\n",
1962 tp_features.bay_status ?
1963 (occupied ? "occupied" : "unoccupied") :
1964 "not supported");
1965 if (tp_features.bay_status2)
1966 len += sprintf(p + len, "status2:\t%s\n", occupied2 ?
1967 "occupied" : "unoccupied");
1968
1969 eject = tp_features.bay_eject && occupied;
1970 eject2 = tp_features.bay_eject2 && occupied2;
1971
1972 if (eject && eject2)
1973 len += sprintf(p + len, "commands:\teject, eject2\n");
1974 else if (eject)
1975 len += sprintf(p + len, "commands:\teject\n");
1976 else if (eject2)
1977 len += sprintf(p + len, "commands:\teject2\n");
1978
1979 return len;
1980}
1981
1982static int bay_write(char *buf)
1983{
1984 char *cmd;
1985
1986 if (!tp_features.bay_eject && !tp_features.bay_eject2)
1987 return -ENODEV;
1988
1989 while ((cmd = next_cmd(&buf))) {
1990 if (tp_features.bay_eject && strlencmp(cmd, "eject") == 0) {
1991 if (!acpi_evalf(bay_ej_handle, NULL, NULL, "vd", 1))
1992 return -EIO;
1993 } else if (tp_features.bay_eject2 &&
1994 strlencmp(cmd, "eject2") == 0) {
1995 if (!acpi_evalf(bay2_ej_handle, NULL, NULL, "vd", 1))
1996 return -EIO;
1997 } else
1998 return -EINVAL;
1999 }
2000
2001 return 0;
2002}
2003
2004static struct tp_acpi_drv_struct ibm_bay_acpidriver = {
2005 .notify = bay_notify,
2006 .handle = &bay_handle,
2007 .type = ACPI_SYSTEM_NOTIFY,
2008};
2009
2010static struct ibm_struct bay_driver_data = {
2011 .name = "bay",
2012 .read = bay_read,
2013 .write = bay_write,
2014 .acpi = &ibm_bay_acpidriver,
2015};
2016
2017#endif /* CONFIG_THINKPAD_ACPI_BAY */
2018
2019/*************************************************************************
2020 * CMOS subdriver
2021 */
2022
2023/* sysfs cmos_command -------------------------------------------------- */
2024static ssize_t cmos_command_store(struct device *dev,
2025 struct device_attribute *attr,
2026 const char *buf, size_t count)
2027{
2028 unsigned long cmos_cmd;
2029 int res;
2030
2031 if (parse_strtoul(buf, 21, &cmos_cmd))
2032 return -EINVAL;
2033
2034 res = issue_thinkpad_cmos_command(cmos_cmd);
2035 return (res)? res : count;
2036}
2037
2038static struct device_attribute dev_attr_cmos_command =
2039 __ATTR(cmos_command, S_IWUSR, NULL, cmos_command_store);
2040
2041/* --------------------------------------------------------------------- */
2042
2043static int __init cmos_init(struct ibm_init_struct *iibm)
2044{
2045 int res;
2046
2047 vdbg_printk(TPACPI_DBG_INIT,
2048 "initializing cmos commands subdriver\n");
2049
2050 IBM_ACPIHANDLE_INIT(cmos);
2051
2052 vdbg_printk(TPACPI_DBG_INIT, "cmos commands are %s\n",
2053 str_supported(cmos_handle != NULL));
2054
2055 res = device_create_file(&tpacpi_pdev->dev, &dev_attr_cmos_command);
2056 if (res)
2057 return res;
2058
2059 return (cmos_handle)? 0 : 1;
2060}
2061
2062static void cmos_exit(void)
2063{
2064 device_remove_file(&tpacpi_pdev->dev, &dev_attr_cmos_command);
2065}
2066
2067static int cmos_read(char *p)
2068{
2069 int len = 0;
2070
2071 /* cmos not supported on 570, 600e/x, 770e, 770x, A21e, A2xm/p,
2072 R30, R31, T20-22, X20-21 */
2073 if (!cmos_handle)
2074 len += sprintf(p + len, "status:\t\tnot supported\n");
2075 else {
2076 len += sprintf(p + len, "status:\t\tsupported\n");
2077 len += sprintf(p + len, "commands:\t<cmd> (<cmd> is 0-21)\n");
2078 }
2079
2080 return len;
2081}
2082
2083static int cmos_write(char *buf)
2084{
2085 char *cmd;
2086 int cmos_cmd, res;
2087
2088 while ((cmd = next_cmd(&buf))) {
2089 if (sscanf(cmd, "%u", &cmos_cmd) == 1 &&
2090 cmos_cmd >= 0 && cmos_cmd <= 21) {
2091 /* cmos_cmd set */
2092 } else
2093 return -EINVAL;
2094
2095 res = issue_thinkpad_cmos_command(cmos_cmd);
2096 if (res)
2097 return res;
2098 }
2099
2100 return 0;
2101}
2102
2103static struct ibm_struct cmos_driver_data = {
2104 .name = "cmos",
2105 .read = cmos_read,
2106 .write = cmos_write,
2107 .exit = cmos_exit,
2108};
2109
2110/*************************************************************************
2111 * LED subdriver
2112 */
2113
2114static enum led_access_mode led_supported;
2115
2116IBM_HANDLE(led, ec, "SLED", /* 570 */
2117 "SYSL", /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20-21 */
2118 "LED", /* all others */
2119 ); /* R30, R31 */
2120
2121static int __init led_init(struct ibm_init_struct *iibm)
2122{
2123 vdbg_printk(TPACPI_DBG_INIT, "initializing LED subdriver\n");
2124
2125 IBM_ACPIHANDLE_INIT(led);
2126
2127 if (!led_handle)
2128 /* led not supported on R30, R31 */
2129 led_supported = TPACPI_LED_NONE;
2130 else if (strlencmp(led_path, "SLED") == 0)
2131 /* 570 */
2132 led_supported = TPACPI_LED_570;
2133 else if (strlencmp(led_path, "SYSL") == 0)
2134 /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20-21 */
2135 led_supported = TPACPI_LED_OLD;
2136 else
2137 /* all others */
2138 led_supported = TPACPI_LED_NEW;
2139
2140 vdbg_printk(TPACPI_DBG_INIT, "LED commands are %s, mode %d\n",
2141 str_supported(led_supported), led_supported);
2142
2143 return (led_supported != TPACPI_LED_NONE)? 0 : 1;
2144}
2145
2146#define led_status(s) ((s) == 0 ? "off" : ((s) == 1 ? "on" : "blinking"))
2147
2148static int led_read(char *p)
2149{
2150 int len = 0;
2151
2152 if (!led_supported) {
2153 len += sprintf(p + len, "status:\t\tnot supported\n");
2154 return len;
2155 }
2156 len += sprintf(p + len, "status:\t\tsupported\n");
2157
2158 if (led_supported == TPACPI_LED_570) {
2159 /* 570 */
2160 int i, status;
2161 for (i = 0; i < 8; i++) {
2162 if (!acpi_evalf(ec_handle,
2163 &status, "GLED", "dd", 1 << i))
2164 return -EIO;
2165 len += sprintf(p + len, "%d:\t\t%s\n",
2166 i, led_status(status));
2167 }
2168 }
2169
2170 len += sprintf(p + len, "commands:\t"
2171 "<led> on, <led> off, <led> blink (<led> is 0-7)\n");
2172
2173 return len;
2174}
2175
2176/* off, on, blink */
2177static const int led_sled_arg1[] = { 0, 1, 3 };
2178static const int led_exp_hlbl[] = { 0, 0, 1 }; /* led# * */
2179static const int led_exp_hlcl[] = { 0, 1, 1 }; /* led# * */
2180static const int led_led_arg1[] = { 0, 0x80, 0xc0 };
2181
2182static int led_write(char *buf)
2183{
2184 char *cmd;
2185 int led, ind, ret;
2186
2187 if (!led_supported)
2188 return -ENODEV;
2189
2190 while ((cmd = next_cmd(&buf))) {
2191 if (sscanf(cmd, "%d", &led) != 1 || led < 0 || led > 7)
2192 return -EINVAL;
2193
2194 if (strstr(cmd, "off")) {
2195 ind = 0;
2196 } else if (strstr(cmd, "on")) {
2197 ind = 1;
2198 } else if (strstr(cmd, "blink")) {
2199 ind = 2;
2200 } else
2201 return -EINVAL;
2202
2203 if (led_supported == TPACPI_LED_570) {
2204 /* 570 */
2205 led = 1 << led;
2206 if (!acpi_evalf(led_handle, NULL, NULL, "vdd",
2207 led, led_sled_arg1[ind]))
2208 return -EIO;
2209 } else if (led_supported == TPACPI_LED_OLD) {
2210 /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20 */
2211 led = 1 << led;
2212 ret = ec_write(TPACPI_LED_EC_HLMS, led);
2213 if (ret >= 0)
2214 ret =
2215 ec_write(TPACPI_LED_EC_HLBL,
2216 led * led_exp_hlbl[ind]);
2217 if (ret >= 0)
2218 ret =
2219 ec_write(TPACPI_LED_EC_HLCL,
2220 led * led_exp_hlcl[ind]);
2221 if (ret < 0)
2222 return ret;
2223 } else {
2224 /* all others */
2225 if (!acpi_evalf(led_handle, NULL, NULL, "vdd",
2226 led, led_led_arg1[ind]))
2227 return -EIO;
2228 }
2229 }
2230
2231 return 0;
2232}
2233
2234static struct ibm_struct led_driver_data = {
2235 .name = "led",
2236 .read = led_read,
2237 .write = led_write,
2238};
2239
2240/*************************************************************************
2241 * Beep subdriver
2242 */
2243
2244IBM_HANDLE(beep, ec, "BEEP"); /* all except R30, R31 */
2245
2246static int __init beep_init(struct ibm_init_struct *iibm)
2247{
2248 vdbg_printk(TPACPI_DBG_INIT, "initializing beep subdriver\n");
2249
2250 IBM_ACPIHANDLE_INIT(beep);
2251
2252 vdbg_printk(TPACPI_DBG_INIT, "beep is %s\n",
2253 str_supported(beep_handle != NULL));
2254
2255 return (beep_handle)? 0 : 1;
2256}
2257
2258static int beep_read(char *p)
2259{
2260 int len = 0;
2261
2262 if (!beep_handle)
2263 len += sprintf(p + len, "status:\t\tnot supported\n");
2264 else {
2265 len += sprintf(p + len, "status:\t\tsupported\n");
2266 len += sprintf(p + len, "commands:\t<cmd> (<cmd> is 0-17)\n");
2267 }
2268
2269 return len;
2270}
2271
2272static int beep_write(char *buf)
2273{
2274 char *cmd;
2275 int beep_cmd;
2276
2277 if (!beep_handle)
2278 return -ENODEV;
2279
2280 while ((cmd = next_cmd(&buf))) {
2281 if (sscanf(cmd, "%u", &beep_cmd) == 1 &&
2282 beep_cmd >= 0 && beep_cmd <= 17) {
2283 /* beep_cmd set */
2284 } else
2285 return -EINVAL;
2286 if (!acpi_evalf(beep_handle, NULL, NULL, "vdd", beep_cmd, 0))
2287 return -EIO;
2288 }
2289
2290 return 0;
2291}
2292
2293static struct ibm_struct beep_driver_data = {
2294 .name = "beep",
2295 .read = beep_read,
2296 .write = beep_write,
2297};
2298
2299/*************************************************************************
2300 * Thermal subdriver
2301 */
2302
2303static enum thermal_access_mode thermal_read_mode;
2304
2305/* sysfs temp##_input -------------------------------------------------- */
2306
2307static ssize_t thermal_temp_input_show(struct device *dev,
2308 struct device_attribute *attr,
2309 char *buf)
2310{
2311 struct sensor_device_attribute *sensor_attr =
2312 to_sensor_dev_attr(attr);
2313 int idx = sensor_attr->index;
2314 s32 value;
2315 int res;
2316
2317 res = thermal_get_sensor(idx, &value);
2318 if (res)
2319 return res;
2320 if (value == TP_EC_THERMAL_TMP_NA * 1000)
2321 return -ENXIO;
2322
2323 return snprintf(buf, PAGE_SIZE, "%d\n", value);
2324}
2325
2326#define THERMAL_SENSOR_ATTR_TEMP(_idxA, _idxB) \
2327 SENSOR_ATTR(temp##_idxA##_input, S_IRUGO, thermal_temp_input_show, NULL, _idxB)
2328
2329static struct sensor_device_attribute sensor_dev_attr_thermal_temp_input[] = {
2330 THERMAL_SENSOR_ATTR_TEMP(1, 0),
2331 THERMAL_SENSOR_ATTR_TEMP(2, 1),
2332 THERMAL_SENSOR_ATTR_TEMP(3, 2),
2333 THERMAL_SENSOR_ATTR_TEMP(4, 3),
2334 THERMAL_SENSOR_ATTR_TEMP(5, 4),
2335 THERMAL_SENSOR_ATTR_TEMP(6, 5),
2336 THERMAL_SENSOR_ATTR_TEMP(7, 6),
2337 THERMAL_SENSOR_ATTR_TEMP(8, 7),
2338 THERMAL_SENSOR_ATTR_TEMP(9, 8),
2339 THERMAL_SENSOR_ATTR_TEMP(10, 9),
2340 THERMAL_SENSOR_ATTR_TEMP(11, 10),
2341 THERMAL_SENSOR_ATTR_TEMP(12, 11),
2342 THERMAL_SENSOR_ATTR_TEMP(13, 12),
2343 THERMAL_SENSOR_ATTR_TEMP(14, 13),
2344 THERMAL_SENSOR_ATTR_TEMP(15, 14),
2345 THERMAL_SENSOR_ATTR_TEMP(16, 15),
2346};
2347
2348#define THERMAL_ATTRS(X) \
2349 &sensor_dev_attr_thermal_temp_input[X].dev_attr.attr
2350
2351static struct attribute *thermal_temp_input_attr[] = {
2352 THERMAL_ATTRS(8),
2353 THERMAL_ATTRS(9),
2354 THERMAL_ATTRS(10),
2355 THERMAL_ATTRS(11),
2356 THERMAL_ATTRS(12),
2357 THERMAL_ATTRS(13),
2358 THERMAL_ATTRS(14),
2359 THERMAL_ATTRS(15),
2360 THERMAL_ATTRS(0),
2361 THERMAL_ATTRS(1),
2362 THERMAL_ATTRS(2),
2363 THERMAL_ATTRS(3),
2364 THERMAL_ATTRS(4),
2365 THERMAL_ATTRS(5),
2366 THERMAL_ATTRS(6),
2367 THERMAL_ATTRS(7),
2368 NULL
2369};
2370
2371static const struct attribute_group thermal_temp_input16_group = {
2372 .attrs = thermal_temp_input_attr
2373};
2374
2375static const struct attribute_group thermal_temp_input8_group = {
2376 .attrs = &thermal_temp_input_attr[8]
2377};
2378
2379#undef THERMAL_SENSOR_ATTR_TEMP
2380#undef THERMAL_ATTRS
2381
2382/* --------------------------------------------------------------------- */
2383
2384static int __init thermal_init(struct ibm_init_struct *iibm)
2385{
2386 u8 t, ta1, ta2;
2387 int i;
2388 int acpi_tmp7;
2389 int res;
2390
2391 vdbg_printk(TPACPI_DBG_INIT, "initializing thermal subdriver\n");
2392
2393 acpi_tmp7 = acpi_evalf(ec_handle, NULL, "TMP7", "qv");
2394
2395 if (ibm_thinkpad_ec_found && experimental) {
2396 /*
2397 * Direct EC access mode: sensors at registers
2398 * 0x78-0x7F, 0xC0-0xC7. Registers return 0x00 for
2399 * non-implemented, thermal sensors return 0x80 when
2400 * not available
2401 */
2402
2403 ta1 = ta2 = 0;
2404 for (i = 0; i < 8; i++) {
2405 if (acpi_ec_read(TP_EC_THERMAL_TMP0 + i, &t)) {
2406 ta1 |= t;
2407 } else {
2408 ta1 = 0;
2409 break;
2410 }
2411 if (acpi_ec_read(TP_EC_THERMAL_TMP8 + i, &t)) {
2412 ta2 |= t;
2413 } else {
2414 ta1 = 0;
2415 break;
2416 }
2417 }
2418 if (ta1 == 0) {
2419 /* This is sheer paranoia, but we handle it anyway */
2420 if (acpi_tmp7) {
2421 printk(IBM_ERR
2422 "ThinkPad ACPI EC access misbehaving, "
2423 "falling back to ACPI TMPx access mode\n");
2424 thermal_read_mode = TPACPI_THERMAL_ACPI_TMP07;
2425 } else {
2426 printk(IBM_ERR
2427 "ThinkPad ACPI EC access misbehaving, "
2428 "disabling thermal sensors access\n");
2429 thermal_read_mode = TPACPI_THERMAL_NONE;
2430 }
2431 } else {
2432 thermal_read_mode =
2433 (ta2 != 0) ?
2434 TPACPI_THERMAL_TPEC_16 : TPACPI_THERMAL_TPEC_8;
2435 }
2436 } else if (acpi_tmp7) {
2437 if (acpi_evalf(ec_handle, NULL, "UPDT", "qv")) {
2438 /* 600e/x, 770e, 770x */
2439 thermal_read_mode = TPACPI_THERMAL_ACPI_UPDT;
2440 } else {
2441 /* Standard ACPI TMPx access, max 8 sensors */
2442 thermal_read_mode = TPACPI_THERMAL_ACPI_TMP07;
2443 }
2444 } else {
2445 /* temperatures not supported on 570, G4x, R30, R31, R32 */
2446 thermal_read_mode = TPACPI_THERMAL_NONE;
2447 }
2448
2449 vdbg_printk(TPACPI_DBG_INIT, "thermal is %s, mode %d\n",
2450 str_supported(thermal_read_mode != TPACPI_THERMAL_NONE),
2451 thermal_read_mode);
2452
2453 switch(thermal_read_mode) {
2454 case TPACPI_THERMAL_TPEC_16:
2455 res = sysfs_create_group(&tpacpi_pdev->dev.kobj,
2456 &thermal_temp_input16_group);
2457 if (res)
2458 return res;
2459 break;
2460 case TPACPI_THERMAL_TPEC_8:
2461 case TPACPI_THERMAL_ACPI_TMP07:
2462 case TPACPI_THERMAL_ACPI_UPDT:
2463 res = sysfs_create_group(&tpacpi_pdev->dev.kobj,
2464 &thermal_temp_input8_group);
2465 if (res)
2466 return res;
2467 break;
2468 case TPACPI_THERMAL_NONE:
2469 default:
2470 return 1;
2471 }
2472
2473 return 0;
2474}
2475
2476static void thermal_exit(void)
2477{
2478 switch(thermal_read_mode) {
2479 case TPACPI_THERMAL_TPEC_16:
2480 sysfs_remove_group(&tpacpi_pdev->dev.kobj,
2481 &thermal_temp_input16_group);
2482 break;
2483 case TPACPI_THERMAL_TPEC_8:
2484 case TPACPI_THERMAL_ACPI_TMP07:
2485 case TPACPI_THERMAL_ACPI_UPDT:
2486 sysfs_remove_group(&tpacpi_pdev->dev.kobj,
2487 &thermal_temp_input16_group);
2488 break;
2489 case TPACPI_THERMAL_NONE:
2490 default:
2491 break;
2492 }
2493}
2494
2495/* idx is zero-based */
2496static int thermal_get_sensor(int idx, s32 *value)
2497{
2498 int t;
2499 s8 tmp;
2500 char tmpi[5];
2501
2502 t = TP_EC_THERMAL_TMP0;
2503
2504 switch (thermal_read_mode) {
2505#if TPACPI_MAX_THERMAL_SENSORS >= 16
2506 case TPACPI_THERMAL_TPEC_16:
2507 if (idx >= 8 && idx <= 15) {
2508 t = TP_EC_THERMAL_TMP8;
2509 idx -= 8;
2510 }
2511 /* fallthrough */
2512#endif
2513 case TPACPI_THERMAL_TPEC_8:
2514 if (idx <= 7) {
2515 if (!acpi_ec_read(t + idx, &tmp))
2516 return -EIO;
2517 *value = tmp * 1000;
2518 return 0;
2519 }
2520 break;
2521
2522 case TPACPI_THERMAL_ACPI_UPDT:
2523 if (idx <= 7) {
2524 snprintf(tmpi, sizeof(tmpi), "TMP%c", '0' + idx);
2525 if (!acpi_evalf(ec_handle, NULL, "UPDT", "v"))
2526 return -EIO;
2527 if (!acpi_evalf(ec_handle, &t, tmpi, "d"))
2528 return -EIO;
2529 *value = (t - 2732) * 100;
2530 return 0;
2531 }
2532 break;
2533
2534 case TPACPI_THERMAL_ACPI_TMP07:
2535 if (idx <= 7) {
2536 snprintf(tmpi, sizeof(tmpi), "TMP%c", '0' + idx);
2537 if (!acpi_evalf(ec_handle, &t, tmpi, "d"))
2538 return -EIO;
2539 *value = t * 1000;
2540 return 0;
2541 }
2542 break;
2543
2544 case TPACPI_THERMAL_NONE:
2545 default:
2546 return -ENOSYS;
2547 }
2548
2549 return -EINVAL;
2550}
2551
2552static int thermal_get_sensors(struct ibm_thermal_sensors_struct *s)
2553{
2554 int res, i;
2555 int n;
2556
2557 n = 8;
2558 i = 0;
2559
2560 if (!s)
2561 return -EINVAL;
2562
2563 if (thermal_read_mode == TPACPI_THERMAL_TPEC_16)
2564 n = 16;
2565
2566 for(i = 0 ; i < n; i++) {
2567 res = thermal_get_sensor(i, &s->temp[i]);
2568 if (res)
2569 return res;
2570 }
2571
2572 return n;
2573}
2574
2575static int thermal_read(char *p)
2576{
2577 int len = 0;
2578 int n, i;
2579 struct ibm_thermal_sensors_struct t;
2580
2581 n = thermal_get_sensors(&t);
2582 if (unlikely(n < 0))
2583 return n;
2584
2585 len += sprintf(p + len, "temperatures:\t");
2586
2587 if (n > 0) {
2588 for (i = 0; i < (n - 1); i++)
2589 len += sprintf(p + len, "%d ", t.temp[i] / 1000);
2590 len += sprintf(p + len, "%d\n", t.temp[i] / 1000);
2591 } else
2592 len += sprintf(p + len, "not supported\n");
2593
2594 return len;
2595}
2596
2597static struct ibm_struct thermal_driver_data = {
2598 .name = "thermal",
2599 .read = thermal_read,
2600 .exit = thermal_exit,
2601};
2602
2603/*************************************************************************
2604 * EC Dump subdriver
2605 */
2606
2607static u8 ecdump_regs[256];
2608
2609static int ecdump_read(char *p)
2610{
2611 int len = 0;
2612 int i, j;
2613 u8 v;
2614
2615 len += sprintf(p + len, "EC "
2616 " +00 +01 +02 +03 +04 +05 +06 +07"
2617 " +08 +09 +0a +0b +0c +0d +0e +0f\n");
2618 for (i = 0; i < 256; i += 16) {
2619 len += sprintf(p + len, "EC 0x%02x:", i);
2620 for (j = 0; j < 16; j++) {
2621 if (!acpi_ec_read(i + j, &v))
2622 break;
2623 if (v != ecdump_regs[i + j])
2624 len += sprintf(p + len, " *%02x", v);
2625 else
2626 len += sprintf(p + len, " %02x", v);
2627 ecdump_regs[i + j] = v;
2628 }
2629 len += sprintf(p + len, "\n");
2630 if (j != 16)
2631 break;
2632 }
2633
2634 /* These are way too dangerous to advertise openly... */
2635#if 0
2636 len += sprintf(p + len, "commands:\t0x<offset> 0x<value>"
2637 " (<offset> is 00-ff, <value> is 00-ff)\n");
2638 len += sprintf(p + len, "commands:\t0x<offset> <value> "
2639 " (<offset> is 00-ff, <value> is 0-255)\n");
2640#endif
2641 return len;
2642}
2643
2644static int ecdump_write(char *buf)
2645{
2646 char *cmd;
2647 int i, v;
2648
2649 while ((cmd = next_cmd(&buf))) {
2650 if (sscanf(cmd, "0x%x 0x%x", &i, &v) == 2) {
2651 /* i and v set */
2652 } else if (sscanf(cmd, "0x%x %u", &i, &v) == 2) {
2653 /* i and v set */
2654 } else
2655 return -EINVAL;
2656 if (i >= 0 && i < 256 && v >= 0 && v < 256) {
2657 if (!acpi_ec_write(i, v))
2658 return -EIO;
2659 } else
2660 return -EINVAL;
2661 }
2662
2663 return 0;
2664}
2665
2666static struct ibm_struct ecdump_driver_data = {
2667 .name = "ecdump",
2668 .read = ecdump_read,
2669 .write = ecdump_write,
2670 .flags.experimental = 1,
2671};
2672
2673/*************************************************************************
2674 * Backlight/brightness subdriver
2675 */
2676
2677static struct backlight_device *ibm_backlight_device = NULL;
2678
2679static struct backlight_ops ibm_backlight_data = {
2680 .get_brightness = brightness_get,
2681 .update_status = brightness_update_status,
2682};
2683
2684static int __init brightness_init(struct ibm_init_struct *iibm)
2685{
2686 int b;
2687
2688 vdbg_printk(TPACPI_DBG_INIT, "initializing brightness subdriver\n");
2689
2690 b = brightness_get(NULL);
2691 if (b < 0)
2692 return b;
2693
2694 ibm_backlight_device = backlight_device_register(
2695 TPACPI_BACKLIGHT_DEV_NAME, NULL, NULL,
2696 &ibm_backlight_data);
2697 if (IS_ERR(ibm_backlight_device)) {
2698 printk(IBM_ERR "Could not register backlight device\n");
2699 return PTR_ERR(ibm_backlight_device);
2700 }
2701 vdbg_printk(TPACPI_DBG_INIT, "brightness is supported\n");
2702
2703 ibm_backlight_device->props.max_brightness = 7;
2704 ibm_backlight_device->props.brightness = b;
2705 backlight_update_status(ibm_backlight_device);
2706
2707 return 0;
2708}
2709
2710static void brightness_exit(void)
2711{
2712 if (ibm_backlight_device) {
2713 vdbg_printk(TPACPI_DBG_EXIT,
2714 "calling backlight_device_unregister()\n");
2715 backlight_device_unregister(ibm_backlight_device);
2716 ibm_backlight_device = NULL;
2717 }
2718}
2719
2720static int brightness_update_status(struct backlight_device *bd)
2721{
2722 return brightness_set(
2723 (bd->props.fb_blank == FB_BLANK_UNBLANK &&
2724 bd->props.power == FB_BLANK_UNBLANK) ?
2725 bd->props.brightness : 0);
2726}
2727
2728static int brightness_get(struct backlight_device *bd)
2729{
2730 u8 level;
2731 if (!acpi_ec_read(brightness_offset, &level))
2732 return -EIO;
2733
2734 level &= 0x7;
2735
2736 return level;
2737}
2738
2739static int brightness_set(int value)
2740{
2741 int cmos_cmd, inc, i;
2742 int current_value = brightness_get(NULL);
2743
2744 value &= 7;
2745
2746 cmos_cmd = value > current_value ? TP_CMOS_BRIGHTNESS_UP : TP_CMOS_BRIGHTNESS_DOWN;
2747 inc = value > current_value ? 1 : -1;
2748 for (i = current_value; i != value; i += inc) {
2749 if (issue_thinkpad_cmos_command(cmos_cmd))
2750 return -EIO;
2751 if (!acpi_ec_write(brightness_offset, i + inc))
2752 return -EIO;
2753 }
2754
2755 return 0;
2756}
2757
2758static int brightness_read(char *p)
2759{
2760 int len = 0;
2761 int level;
2762
2763 if ((level = brightness_get(NULL)) < 0) {
2764 len += sprintf(p + len, "level:\t\tunreadable\n");
2765 } else {
2766 len += sprintf(p + len, "level:\t\t%d\n", level & 0x7);
2767 len += sprintf(p + len, "commands:\tup, down\n");
2768 len += sprintf(p + len, "commands:\tlevel <level>"
2769 " (<level> is 0-7)\n");
2770 }
2771
2772 return len;
2773}
2774
2775static int brightness_write(char *buf)
2776{
2777 int level;
2778 int new_level;
2779 char *cmd;
2780
2781 while ((cmd = next_cmd(&buf))) {
2782 if ((level = brightness_get(NULL)) < 0)
2783 return level;
2784 level &= 7;
2785
2786 if (strlencmp(cmd, "up") == 0) {
2787 new_level = level == 7 ? 7 : level + 1;
2788 } else if (strlencmp(cmd, "down") == 0) {
2789 new_level = level == 0 ? 0 : level - 1;
2790 } else if (sscanf(cmd, "level %d", &new_level) == 1 &&
2791 new_level >= 0 && new_level <= 7) {
2792 /* new_level set */
2793 } else
2794 return -EINVAL;
2795
2796 brightness_set(new_level);
2797 }
2798
2799 return 0;
2800}
2801
2802static struct ibm_struct brightness_driver_data = {
2803 .name = "brightness",
2804 .read = brightness_read,
2805 .write = brightness_write,
2806 .exit = brightness_exit,
2807};
2808
2809/*************************************************************************
2810 * Volume subdriver
2811 */
2812
2813static int volume_read(char *p)
2814{
2815 int len = 0;
2816 u8 level;
2817
2818 if (!acpi_ec_read(volume_offset, &level)) {
2819 len += sprintf(p + len, "level:\t\tunreadable\n");
2820 } else {
2821 len += sprintf(p + len, "level:\t\t%d\n", level & 0xf);
2822 len += sprintf(p + len, "mute:\t\t%s\n", onoff(level, 6));
2823 len += sprintf(p + len, "commands:\tup, down, mute\n");
2824 len += sprintf(p + len, "commands:\tlevel <level>"
2825 " (<level> is 0-15)\n");
2826 }
2827
2828 return len;
2829}
2830
2831static int volume_write(char *buf)
2832{
2833 int cmos_cmd, inc, i;
2834 u8 level, mute;
2835 int new_level, new_mute;
2836 char *cmd;
2837
2838 while ((cmd = next_cmd(&buf))) {
2839 if (!acpi_ec_read(volume_offset, &level))
2840 return -EIO;
2841 new_mute = mute = level & 0x40;
2842 new_level = level = level & 0xf;
2843
2844 if (strlencmp(cmd, "up") == 0) {
2845 if (mute)
2846 new_mute = 0;
2847 else
2848 new_level = level == 15 ? 15 : level + 1;
2849 } else if (strlencmp(cmd, "down") == 0) {
2850 if (mute)
2851 new_mute = 0;
2852 else
2853 new_level = level == 0 ? 0 : level - 1;
2854 } else if (sscanf(cmd, "level %d", &new_level) == 1 &&
2855 new_level >= 0 && new_level <= 15) {
2856 /* new_level set */
2857 } else if (strlencmp(cmd, "mute") == 0) {
2858 new_mute = 0x40;
2859 } else
2860 return -EINVAL;
2861
2862 if (new_level != level) { /* mute doesn't change */
2863 cmos_cmd = new_level > level ? TP_CMOS_VOLUME_UP : TP_CMOS_VOLUME_DOWN;
2864 inc = new_level > level ? 1 : -1;
2865
2866 if (mute && (issue_thinkpad_cmos_command(cmos_cmd) ||
2867 !acpi_ec_write(volume_offset, level)))
2868 return -EIO;
2869
2870 for (i = level; i != new_level; i += inc)
2871 if (issue_thinkpad_cmos_command(cmos_cmd) ||
2872 !acpi_ec_write(volume_offset, i + inc))
2873 return -EIO;
2874
2875 if (mute && (issue_thinkpad_cmos_command(TP_CMOS_VOLUME_MUTE) ||
2876 !acpi_ec_write(volume_offset,
2877 new_level + mute)))
2878 return -EIO;
2879 }
2880
2881 if (new_mute != mute) { /* level doesn't change */
2882 cmos_cmd = new_mute ? TP_CMOS_VOLUME_MUTE : TP_CMOS_VOLUME_UP;
2883
2884 if (issue_thinkpad_cmos_command(cmos_cmd) ||
2885 !acpi_ec_write(volume_offset, level + new_mute))
2886 return -EIO;
2887 }
2888 }
2889
2890 return 0;
2891}
2892
2893static struct ibm_struct volume_driver_data = {
2894 .name = "volume",
2895 .read = volume_read,
2896 .write = volume_write,
2897};
2898
2899/*************************************************************************
2900 * Fan subdriver
2901 */
2902
2903/*
2904 * FAN ACCESS MODES
2905 *
2906 * TPACPI_FAN_RD_ACPI_GFAN:
2907 * ACPI GFAN method: returns fan level
2908 *
2909 * see TPACPI_FAN_WR_ACPI_SFAN
2910 * EC 0x2f (HFSP) not available if GFAN exists
2911 *
2912 * TPACPI_FAN_WR_ACPI_SFAN:
2913 * ACPI SFAN method: sets fan level, 0 (stop) to 7 (max)
2914 *
2915 * EC 0x2f (HFSP) might be available *for reading*, but do not use
2916 * it for writing.
2917 *
2918 * TPACPI_FAN_WR_TPEC:
2919 * ThinkPad EC register 0x2f (HFSP): fan control loop mode
2920 * Supported on almost all ThinkPads
2921 *
2922 * Fan speed changes of any sort (including those caused by the
2923 * disengaged mode) are usually done slowly by the firmware as the
2924 * maximum ammount of fan duty cycle change per second seems to be
2925 * limited.
2926 *
2927 * Reading is not available if GFAN exists.
2928 * Writing is not available if SFAN exists.
2929 *
2930 * Bits
2931 * 7 automatic mode engaged;
2932 * (default operation mode of the ThinkPad)
2933 * fan level is ignored in this mode.
2934 * 6 full speed mode (takes precedence over bit 7);
2935 * not available on all thinkpads. May disable
2936 * the tachometer while the fan controller ramps up
2937 * the speed (which can take up to a few *minutes*).
2938 * Speeds up fan to 100% duty-cycle, which is far above
2939 * the standard RPM levels. It is not impossible that
2940 * it could cause hardware damage.
2941 * 5-3 unused in some models. Extra bits for fan level
2942 * in others, but still useless as all values above
2943 * 7 map to the same speed as level 7 in these models.
2944 * 2-0 fan level (0..7 usually)
2945 * 0x00 = stop
2946 * 0x07 = max (set when temperatures critical)
2947 * Some ThinkPads may have other levels, see
2948 * TPACPI_FAN_WR_ACPI_FANS (X31/X40/X41)
2949 *
2950 * FIRMWARE BUG: on some models, EC 0x2f might not be initialized at
2951 * boot. Apparently the EC does not intialize it, so unless ACPI DSDT
2952 * does so, its initial value is meaningless (0x07).
2953 *
2954 * For firmware bugs, refer to:
2955 * http://thinkwiki.org/wiki/Embedded_Controller_Firmware#Firmware_Issues
2956 *
2957 * ----
2958 *
2959 * ThinkPad EC register 0x84 (LSB), 0x85 (MSB):
2960 * Main fan tachometer reading (in RPM)
2961 *
2962 * This register is present on all ThinkPads with a new-style EC, and
2963 * it is known not to be present on the A21m/e, and T22, as there is
2964 * something else in offset 0x84 according to the ACPI DSDT. Other
2965 * ThinkPads from this same time period (and earlier) probably lack the
2966 * tachometer as well.
2967 *
2968 * Unfortunately a lot of ThinkPads with new-style ECs but whose firwmare
2969 * was never fixed by IBM to report the EC firmware version string
2970 * probably support the tachometer (like the early X models), so
2971 * detecting it is quite hard. We need more data to know for sure.
2972 *
2973 * FIRMWARE BUG: always read 0x84 first, otherwise incorrect readings
2974 * might result.
2975 *
2976 * FIRMWARE BUG: may go stale while the EC is switching to full speed
2977 * mode.
2978 *
2979 * For firmware bugs, refer to:
2980 * http://thinkwiki.org/wiki/Embedded_Controller_Firmware#Firmware_Issues
2981 *
2982 * TPACPI_FAN_WR_ACPI_FANS:
2983 * ThinkPad X31, X40, X41. Not available in the X60.
2984 *
2985 * FANS ACPI handle: takes three arguments: low speed, medium speed,
2986 * high speed. ACPI DSDT seems to map these three speeds to levels
2987 * as follows: STOP LOW LOW MED MED HIGH HIGH HIGH HIGH
2988 * (this map is stored on FAN0..FAN8 as "0,1,1,2,2,3,3,3,3")
2989 *
2990 * The speeds are stored on handles
2991 * (FANA:FAN9), (FANC:FANB), (FANE:FAND).
2992 *
2993 * There are three default speed sets, acessible as handles:
2994 * FS1L,FS1M,FS1H; FS2L,FS2M,FS2H; FS3L,FS3M,FS3H
2995 *
2996 * ACPI DSDT switches which set is in use depending on various
2997 * factors.
2998 *
2999 * TPACPI_FAN_WR_TPEC is also available and should be used to
3000 * command the fan. The X31/X40/X41 seems to have 8 fan levels,
3001 * but the ACPI tables just mention level 7.
3002 */
3003
3004static enum fan_status_access_mode fan_status_access_mode;
3005static enum fan_control_access_mode fan_control_access_mode;
3006static enum fan_control_commands fan_control_commands;
3007
3008static u8 fan_control_initial_status;
3009static u8 fan_control_desired_level;
3010
3011static void fan_watchdog_fire(struct work_struct *ignored);
3012static int fan_watchdog_maxinterval;
3013static DECLARE_DELAYED_WORK(fan_watchdog_task, fan_watchdog_fire);
3014
3015IBM_HANDLE(fans, ec, "FANS"); /* X31, X40, X41 */
3016IBM_HANDLE(gfan, ec, "GFAN", /* 570 */
3017 "\\FSPD", /* 600e/x, 770e, 770x */
3018 ); /* all others */
3019IBM_HANDLE(sfan, ec, "SFAN", /* 570 */
3020 "JFNS", /* 770x-JL */
3021 ); /* all others */
3022
3023/*
3024 * SYSFS fan layout: hwmon compatible (device)
3025 *
3026 * pwm*_enable:
3027 * 0: "disengaged" mode
3028 * 1: manual mode
3029 * 2: native EC "auto" mode (recommended, hardware default)
3030 *
3031 * pwm*: set speed in manual mode, ignored otherwise.
3032 * 0 is level 0; 255 is level 7. Intermediate points done with linear
3033 * interpolation.
3034 *
3035 * fan*_input: tachometer reading, RPM
3036 *
3037 *
3038 * SYSFS fan layout: extensions
3039 *
3040 * fan_watchdog (driver):
3041 * fan watchdog interval in seconds, 0 disables (default), max 120
3042 */
3043
3044/* sysfs fan pwm1_enable ----------------------------------------------- */
3045static ssize_t fan_pwm1_enable_show(struct device *dev,
3046 struct device_attribute *attr,
3047 char *buf)
3048{
3049 int res, mode;
3050 u8 status;
3051
3052 res = fan_get_status_safe(&status);
3053 if (res)
3054 return res;
3055
3056 if (unlikely(tp_features.fan_ctrl_status_undef)) {
3057 if (status != fan_control_initial_status) {
3058 tp_features.fan_ctrl_status_undef = 0;
3059 } else {
3060 /* Return most likely status. In fact, it
3061 * might be the only possible status */
3062 status = TP_EC_FAN_AUTO;
3063 }
3064 }
3065
3066 if (status & TP_EC_FAN_FULLSPEED) {
3067 mode = 0;
3068 } else if (status & TP_EC_FAN_AUTO) {
3069 mode = 2;
3070 } else
3071 mode = 1;
3072
3073 return snprintf(buf, PAGE_SIZE, "%d\n", mode);
3074}
3075
3076static ssize_t fan_pwm1_enable_store(struct device *dev,
3077 struct device_attribute *attr,
3078 const char *buf, size_t count)
3079{
3080 unsigned long t;
3081 int res, level;
3082
3083 if (parse_strtoul(buf, 2, &t))
3084 return -EINVAL;
3085
3086 switch (t) {
3087 case 0:
3088 level = TP_EC_FAN_FULLSPEED;
3089 break;
3090 case 1:
3091 level = TPACPI_FAN_LAST_LEVEL;
3092 break;
3093 case 2:
3094 level = TP_EC_FAN_AUTO;
3095 break;
3096 case 3:
3097 /* reserved for software-controlled auto mode */
3098 return -ENOSYS;
3099 default:
3100 return -EINVAL;
3101 }
3102
3103 res = fan_set_level_safe(level);
3104 if (res == -ENXIO)
3105 return -EINVAL;
3106 else if (res < 0)
3107 return res;
3108
3109 fan_watchdog_reset();
3110
3111 return count;
3112}
3113
3114static struct device_attribute dev_attr_fan_pwm1_enable =
3115 __ATTR(pwm1_enable, S_IWUSR | S_IRUGO,
3116 fan_pwm1_enable_show, fan_pwm1_enable_store);
3117
3118/* sysfs fan pwm1 ------------------------------------------------------ */
3119static ssize_t fan_pwm1_show(struct device *dev,
3120 struct device_attribute *attr,
3121 char *buf)
3122{
3123 int res;
3124 u8 status;
3125
3126 res = fan_get_status_safe(&status);
3127 if (res)
3128 return res;
3129
3130 if (unlikely(tp_features.fan_ctrl_status_undef)) {
3131 if (status != fan_control_initial_status) {
3132 tp_features.fan_ctrl_status_undef = 0;
3133 } else {
3134 status = TP_EC_FAN_AUTO;
3135 }
3136 }
3137
3138 if ((status &
3139 (TP_EC_FAN_AUTO | TP_EC_FAN_FULLSPEED)) != 0)
3140 status = fan_control_desired_level;
3141
3142 if (status > 7)
3143 status = 7;
3144
3145 return snprintf(buf, PAGE_SIZE, "%u\n", (status * 255) / 7);
3146}
3147
3148static ssize_t fan_pwm1_store(struct device *dev,
3149 struct device_attribute *attr,
3150 const char *buf, size_t count)
3151{
3152 unsigned long s;
3153 int rc;
3154 u8 status, newlevel;
3155
3156 if (parse_strtoul(buf, 255, &s))
3157 return -EINVAL;
3158
3159 /* scale down from 0-255 to 0-7 */
3160 newlevel = (s >> 5) & 0x07;
3161
3162 rc = mutex_lock_interruptible(&fan_mutex);
3163 if (rc < 0)
3164 return rc;
3165
3166 rc = fan_get_status(&status);
3167 if (!rc && (status &
3168 (TP_EC_FAN_AUTO | TP_EC_FAN_FULLSPEED)) == 0) {
3169 rc = fan_set_level(newlevel);
3170 if (rc == -ENXIO)
3171 rc = -EINVAL;
3172 else if (!rc) {
3173 fan_update_desired_level(newlevel);
3174 fan_watchdog_reset();
3175 }
3176 }
3177
3178 mutex_unlock(&fan_mutex);
3179 return (rc)? rc : count;
3180}
3181
3182static struct device_attribute dev_attr_fan_pwm1 =
3183 __ATTR(pwm1, S_IWUSR | S_IRUGO,
3184 fan_pwm1_show, fan_pwm1_store);
3185
3186/* sysfs fan fan1_input ------------------------------------------------ */
3187static ssize_t fan_fan1_input_show(struct device *dev,
3188 struct device_attribute *attr,
3189 char *buf)
3190{
3191 int res;
3192 unsigned int speed;
3193
3194 res = fan_get_speed(&speed);
3195 if (res < 0)
3196 return res;
3197
3198 return snprintf(buf, PAGE_SIZE, "%u\n", speed);
3199}
3200
3201static struct device_attribute dev_attr_fan_fan1_input =
3202 __ATTR(fan1_input, S_IRUGO,
3203 fan_fan1_input_show, NULL);
3204
3205/* sysfs fan fan_watchdog (driver) ------------------------------------- */
3206static ssize_t fan_fan_watchdog_show(struct device_driver *drv,
3207 char *buf)
3208{
3209 return snprintf(buf, PAGE_SIZE, "%u\n", fan_watchdog_maxinterval);
3210}
3211
3212static ssize_t fan_fan_watchdog_store(struct device_driver *drv,
3213 const char *buf, size_t count)
3214{
3215 unsigned long t;
3216
3217 if (parse_strtoul(buf, 120, &t))
3218 return -EINVAL;
3219
3220 if (!fan_control_allowed)
3221 return -EPERM;
3222
3223 fan_watchdog_maxinterval = t;
3224 fan_watchdog_reset();
3225
3226 return count;
3227}
3228
3229static DRIVER_ATTR(fan_watchdog, S_IWUSR | S_IRUGO,
3230 fan_fan_watchdog_show, fan_fan_watchdog_store);
3231
3232/* --------------------------------------------------------------------- */
3233static struct attribute *fan_attributes[] = {
3234 &dev_attr_fan_pwm1_enable.attr, &dev_attr_fan_pwm1.attr,
3235 &dev_attr_fan_fan1_input.attr,
3236 NULL
3237};
3238
3239static const struct attribute_group fan_attr_group = {
3240 .attrs = fan_attributes,
3241};
3242
3243static int __init fan_init(struct ibm_init_struct *iibm)
3244{
3245 int rc;
3246
3247 vdbg_printk(TPACPI_DBG_INIT, "initializing fan subdriver\n");
3248
3249 mutex_init(&fan_mutex);
3250 fan_status_access_mode = TPACPI_FAN_NONE;
3251 fan_control_access_mode = TPACPI_FAN_WR_NONE;
3252 fan_control_commands = 0;
3253 fan_watchdog_maxinterval = 0;
3254 tp_features.fan_ctrl_status_undef = 0;
3255 fan_control_desired_level = 7;
3256
3257 IBM_ACPIHANDLE_INIT(fans);
3258 IBM_ACPIHANDLE_INIT(gfan);
3259 IBM_ACPIHANDLE_INIT(sfan);
3260
3261 if (gfan_handle) {
3262 /* 570, 600e/x, 770e, 770x */
3263 fan_status_access_mode = TPACPI_FAN_RD_ACPI_GFAN;
3264 } else {
3265 /* all other ThinkPads: note that even old-style
3266 * ThinkPad ECs supports the fan control register */
3267 if (likely(acpi_ec_read(fan_status_offset,
3268 &fan_control_initial_status))) {
3269 fan_status_access_mode = TPACPI_FAN_RD_TPEC;
3270
3271 /* In some ThinkPads, neither the EC nor the ACPI
3272 * DSDT initialize the fan status, and it ends up
3273 * being set to 0x07 when it *could* be either
3274 * 0x07 or 0x80.
3275 *
3276 * Enable for TP-1Y (T43), TP-78 (R51e),
3277 * TP-76 (R52), TP-70 (T43, R52), which are known
3278 * to be buggy. */
3279 if (fan_control_initial_status == 0x07 &&
3280 ibm_thinkpad_ec_found &&
3281 ((ibm_thinkpad_ec_found[0] == '1' &&
3282 ibm_thinkpad_ec_found[1] == 'Y') ||
3283 (ibm_thinkpad_ec_found[0] == '7' &&
3284 (ibm_thinkpad_ec_found[1] == '6' ||
3285 ibm_thinkpad_ec_found[1] == '8' ||
3286 ibm_thinkpad_ec_found[1] == '0'))
3287 )) {
3288 printk(IBM_NOTICE
3289 "fan_init: initial fan status is "
3290 "unknown, assuming it is in auto "
3291 "mode\n");
3292 tp_features.fan_ctrl_status_undef = 1;
3293 }
3294 } else {
3295 printk(IBM_ERR
3296 "ThinkPad ACPI EC access misbehaving, "
3297 "fan status and control unavailable\n");
3298 return 1;
3299 }
3300 }
3301
3302 if (sfan_handle) {
3303 /* 570, 770x-JL */
3304 fan_control_access_mode = TPACPI_FAN_WR_ACPI_SFAN;
3305 fan_control_commands |=
3306 TPACPI_FAN_CMD_LEVEL | TPACPI_FAN_CMD_ENABLE;
3307 } else {
3308 if (!gfan_handle) {
3309 /* gfan without sfan means no fan control */
3310 /* all other models implement TP EC 0x2f control */
3311
3312 if (fans_handle) {
3313 /* X31, X40, X41 */
3314 fan_control_access_mode =
3315 TPACPI_FAN_WR_ACPI_FANS;
3316 fan_control_commands |=
3317 TPACPI_FAN_CMD_SPEED |
3318 TPACPI_FAN_CMD_LEVEL |
3319 TPACPI_FAN_CMD_ENABLE;
3320 } else {
3321 fan_control_access_mode = TPACPI_FAN_WR_TPEC;
3322 fan_control_commands |=
3323 TPACPI_FAN_CMD_LEVEL |
3324 TPACPI_FAN_CMD_ENABLE;
3325 }
3326 }
3327 }
3328
3329 vdbg_printk(TPACPI_DBG_INIT, "fan is %s, modes %d, %d\n",
3330 str_supported(fan_status_access_mode != TPACPI_FAN_NONE ||
3331 fan_control_access_mode != TPACPI_FAN_WR_NONE),
3332 fan_status_access_mode, fan_control_access_mode);
3333
3334 /* fan control master switch */
3335 if (!fan_control_allowed) {
3336 fan_control_access_mode = TPACPI_FAN_WR_NONE;
3337 fan_control_commands = 0;
3338 dbg_printk(TPACPI_DBG_INIT,
3339 "fan control features disabled by parameter\n");
3340 }
3341
3342 /* update fan_control_desired_level */
3343 if (fan_status_access_mode != TPACPI_FAN_NONE)
3344 fan_get_status_safe(NULL);
3345
3346 if (fan_status_access_mode != TPACPI_FAN_NONE ||
3347 fan_control_access_mode != TPACPI_FAN_WR_NONE) {
3348 rc = sysfs_create_group(&tpacpi_pdev->dev.kobj,
3349 &fan_attr_group);
3350 if (!(rc < 0))
3351 rc = driver_create_file(&tpacpi_pdriver.driver,
3352 &driver_attr_fan_watchdog);
3353 if (rc < 0)
3354 return rc;
3355 return 0;
3356 } else
3357 return 1;
3358}
3359
3360/*
3361 * Call with fan_mutex held
3362 */
3363static void fan_update_desired_level(u8 status)
3364{
3365 if ((status &
3366 (TP_EC_FAN_AUTO | TP_EC_FAN_FULLSPEED)) == 0) {
3367 if (status > 7)
3368 fan_control_desired_level = 7;
3369 else
3370 fan_control_desired_level = status;
3371 }
3372}
3373
3374static int fan_get_status(u8 *status)
3375{
3376 u8 s;
3377
3378 /* TODO:
3379 * Add TPACPI_FAN_RD_ACPI_FANS ? */
3380
3381 switch (fan_status_access_mode) {
3382 case TPACPI_FAN_RD_ACPI_GFAN:
3383 /* 570, 600e/x, 770e, 770x */
3384
3385 if (unlikely(!acpi_evalf(gfan_handle, &s, NULL, "d")))
3386 return -EIO;
3387
3388 if (likely(status))
3389 *status = s & 0x07;
3390
3391 break;
3392
3393 case TPACPI_FAN_RD_TPEC:
3394 /* all except 570, 600e/x, 770e, 770x */
3395 if (unlikely(!acpi_ec_read(fan_status_offset, &s)))
3396 return -EIO;
3397
3398 if (likely(status))
3399 *status = s;
3400
3401 break;
3402
3403 default:
3404 return -ENXIO;
3405 }
3406
3407 return 0;
3408}
3409
3410static int fan_get_status_safe(u8 *status)
3411{
3412 int rc;
3413 u8 s;
3414
3415 rc = mutex_lock_interruptible(&fan_mutex);
3416 if (rc < 0)
3417 return rc;
3418 rc = fan_get_status(&s);
3419 if (!rc)
3420 fan_update_desired_level(s);
3421 mutex_unlock(&fan_mutex);
3422
3423 if (status)
3424 *status = s;
3425
3426 return rc;
3427}
3428
3429static void fan_exit(void)
3430{
3431 vdbg_printk(TPACPI_DBG_EXIT, "cancelling any pending fan watchdog tasks\n");
3432
3433 /* FIXME: can we really do this unconditionally? */
3434 sysfs_remove_group(&tpacpi_pdev->dev.kobj, &fan_attr_group);
3435 driver_remove_file(&tpacpi_pdriver.driver, &driver_attr_fan_watchdog);
3436
3437 cancel_delayed_work(&fan_watchdog_task);
3438 flush_scheduled_work();
3439}
3440
3441static int fan_get_speed(unsigned int *speed)
3442{
3443 u8 hi, lo;
3444
3445 switch (fan_status_access_mode) {
3446 case TPACPI_FAN_RD_TPEC:
3447 /* all except 570, 600e/x, 770e, 770x */
3448 if (unlikely(!acpi_ec_read(fan_rpm_offset, &lo) ||
3449 !acpi_ec_read(fan_rpm_offset + 1, &hi)))
3450 return -EIO;
3451
3452 if (likely(speed))
3453 *speed = (hi << 8) | lo;
3454
3455 break;
3456
3457 default:
3458 return -ENXIO;
3459 }
3460
3461 return 0;
3462}
3463
3464static void fan_watchdog_fire(struct work_struct *ignored)
3465{
3466 int rc;
3467
3468 printk(IBM_NOTICE "fan watchdog: enabling fan\n");
3469 rc = fan_set_enable();
3470 if (rc < 0) {
3471 printk(IBM_ERR "fan watchdog: error %d while enabling fan, "
3472 "will try again later...\n", -rc);
3473 /* reschedule for later */
3474 fan_watchdog_reset();
3475 }
3476}
3477
3478static void fan_watchdog_reset(void)
3479{
3480 static int fan_watchdog_active = 0;
3481
3482 if (fan_control_access_mode == TPACPI_FAN_WR_NONE)
3483 return;
3484
3485 if (fan_watchdog_active)
3486 cancel_delayed_work(&fan_watchdog_task);
3487
3488 if (fan_watchdog_maxinterval > 0) {
3489 fan_watchdog_active = 1;
3490 if (!schedule_delayed_work(&fan_watchdog_task,
3491 msecs_to_jiffies(fan_watchdog_maxinterval
3492 * 1000))) {
3493 printk(IBM_ERR "failed to schedule the fan watchdog, "
3494 "watchdog will not trigger\n");
3495 }
3496 } else
3497 fan_watchdog_active = 0;
3498}
3499
3500static int fan_set_level(int level)
3501{
3502 if (!fan_control_allowed)
3503 return -EPERM;
3504
3505 switch (fan_control_access_mode) {
3506 case TPACPI_FAN_WR_ACPI_SFAN:
3507 if (level >= 0 && level <= 7) {
3508 if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", level))
3509 return -EIO;
3510 } else
3511 return -EINVAL;
3512 break;
3513
3514 case TPACPI_FAN_WR_ACPI_FANS:
3515 case TPACPI_FAN_WR_TPEC:
3516 if ((level != TP_EC_FAN_AUTO) &&
3517 (level != TP_EC_FAN_FULLSPEED) &&
3518 ((level < 0) || (level > 7)))
3519 return -EINVAL;
3520
3521 /* safety net should the EC not support AUTO
3522 * or FULLSPEED mode bits and just ignore them */
3523 if (level & TP_EC_FAN_FULLSPEED)
3524 level |= 7; /* safety min speed 7 */
3525 else if (level & TP_EC_FAN_FULLSPEED)
3526 level |= 4; /* safety min speed 4 */
3527
3528 if (!acpi_ec_write(fan_status_offset, level))
3529 return -EIO;
3530 else
3531 tp_features.fan_ctrl_status_undef = 0;
3532 break;
3533
3534 default:
3535 return -ENXIO;
3536 }
3537 return 0;
3538}
3539
3540static int fan_set_level_safe(int level)
3541{
3542 int rc;
3543
3544 if (!fan_control_allowed)
3545 return -EPERM;
3546
3547 rc = mutex_lock_interruptible(&fan_mutex);
3548 if (rc < 0)
3549 return rc;
3550
3551 if (level == TPACPI_FAN_LAST_LEVEL)
3552 level = fan_control_desired_level;
3553
3554 rc = fan_set_level(level);
3555 if (!rc)
3556 fan_update_desired_level(level);
3557
3558 mutex_unlock(&fan_mutex);
3559 return rc;
3560}
3561
3562static int fan_set_enable(void)
3563{
3564 u8 s;
3565 int rc;
3566
3567 if (!fan_control_allowed)
3568 return -EPERM;
3569
3570 rc = mutex_lock_interruptible(&fan_mutex);
3571 if (rc < 0)
3572 return rc;
3573
3574 switch (fan_control_access_mode) {
3575 case TPACPI_FAN_WR_ACPI_FANS:
3576 case TPACPI_FAN_WR_TPEC:
3577 rc = fan_get_status(&s);
3578 if (rc < 0)
3579 break;
3580
3581 /* Don't go out of emergency fan mode */
3582 if (s != 7) {
3583 s &= 0x07;
3584 s |= TP_EC_FAN_AUTO | 4; /* min fan speed 4 */
3585 }
3586
3587 if (!acpi_ec_write(fan_status_offset, s))
3588 rc = -EIO;
3589 else {
3590 tp_features.fan_ctrl_status_undef = 0;
3591 rc = 0;
3592 }
3593 break;
3594
3595 case TPACPI_FAN_WR_ACPI_SFAN:
3596 rc = fan_get_status(&s);
3597 if (rc < 0)
3598 break;
3599
3600 s &= 0x07;
3601
3602 /* Set fan to at least level 4 */
3603 s |= 4;
3604
3605 if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", s))
3606 rc= -EIO;
3607 else
3608 rc = 0;
3609 break;
3610
3611 default:
3612 rc = -ENXIO;
3613 }
3614
3615 mutex_unlock(&fan_mutex);
3616 return rc;
3617}
3618
3619static int fan_set_disable(void)
3620{
3621 int rc;
3622
3623 if (!fan_control_allowed)
3624 return -EPERM;
3625
3626 rc = mutex_lock_interruptible(&fan_mutex);
3627 if (rc < 0)
3628 return rc;
3629
3630 rc = 0;
3631 switch (fan_control_access_mode) {
3632 case TPACPI_FAN_WR_ACPI_FANS:
3633 case TPACPI_FAN_WR_TPEC:
3634 if (!acpi_ec_write(fan_status_offset, 0x00))
3635 rc = -EIO;
3636 else {
3637 fan_control_desired_level = 0;
3638 tp_features.fan_ctrl_status_undef = 0;
3639 }
3640 break;
3641
3642 case TPACPI_FAN_WR_ACPI_SFAN:
3643 if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", 0x00))
3644 rc = -EIO;
3645 else
3646 fan_control_desired_level = 0;
3647 break;
3648
3649 default:
3650 rc = -ENXIO;
3651 }
3652
3653
3654 mutex_unlock(&fan_mutex);
3655 return rc;
3656}
3657
3658static int fan_set_speed(int speed)
3659{
3660 int rc;
3661
3662 if (!fan_control_allowed)
3663 return -EPERM;
3664
3665 rc = mutex_lock_interruptible(&fan_mutex);
3666 if (rc < 0)
3667 return rc;
3668
3669 rc = 0;
3670 switch (fan_control_access_mode) {
3671 case TPACPI_FAN_WR_ACPI_FANS:
3672 if (speed >= 0 && speed <= 65535) {
3673 if (!acpi_evalf(fans_handle, NULL, NULL, "vddd",
3674 speed, speed, speed))
3675 rc = -EIO;
3676 } else
3677 rc = -EINVAL;
3678 break;
3679
3680 default:
3681 rc = -ENXIO;
3682 }
3683
3684 mutex_unlock(&fan_mutex);
3685 return rc;
3686}
3687
3688static int fan_read(char *p)
3689{
3690 int len = 0;
3691 int rc;
3692 u8 status;
3693 unsigned int speed = 0;
3694
3695 switch (fan_status_access_mode) {
3696 case TPACPI_FAN_RD_ACPI_GFAN:
3697 /* 570, 600e/x, 770e, 770x */
3698 if ((rc = fan_get_status_safe(&status)) < 0)
3699 return rc;
3700
3701 len += sprintf(p + len, "status:\t\t%s\n"
3702 "level:\t\t%d\n",
3703 (status != 0) ? "enabled" : "disabled", status);
3704 break;
3705
3706 case TPACPI_FAN_RD_TPEC:
3707 /* all except 570, 600e/x, 770e, 770x */
3708 if ((rc = fan_get_status_safe(&status)) < 0)
3709 return rc;
3710
3711 if (unlikely(tp_features.fan_ctrl_status_undef)) {
3712 if (status != fan_control_initial_status)
3713 tp_features.fan_ctrl_status_undef = 0;
3714 else
3715 /* Return most likely status. In fact, it
3716 * might be the only possible status */
3717 status = TP_EC_FAN_AUTO;
3718 }
3719
3720 len += sprintf(p + len, "status:\t\t%s\n",
3721 (status != 0) ? "enabled" : "disabled");
3722
3723 if ((rc = fan_get_speed(&speed)) < 0)
3724 return rc;
3725
3726 len += sprintf(p + len, "speed:\t\t%d\n", speed);
3727
3728 if (status & TP_EC_FAN_FULLSPEED)
3729 /* Disengaged mode takes precedence */
3730 len += sprintf(p + len, "level:\t\tdisengaged\n");
3731 else if (status & TP_EC_FAN_AUTO)
3732 len += sprintf(p + len, "level:\t\tauto\n");
3733 else
3734 len += sprintf(p + len, "level:\t\t%d\n", status);
3735 break;
3736
3737 case TPACPI_FAN_NONE:
3738 default:
3739 len += sprintf(p + len, "status:\t\tnot supported\n");
3740 }
3741
3742 if (fan_control_commands & TPACPI_FAN_CMD_LEVEL) {
3743 len += sprintf(p + len, "commands:\tlevel <level>");
3744
3745 switch (fan_control_access_mode) {
3746 case TPACPI_FAN_WR_ACPI_SFAN:
3747 len += sprintf(p + len, " (<level> is 0-7)\n");
3748 break;
3749
3750 default:
3751 len += sprintf(p + len, " (<level> is 0-7, "
3752 "auto, disengaged, full-speed)\n");
3753 break;
3754 }
3755 }
3756
3757 if (fan_control_commands & TPACPI_FAN_CMD_ENABLE)
3758 len += sprintf(p + len, "commands:\tenable, disable\n"
3759 "commands:\twatchdog <timeout> (<timeout> is 0 (off), "
3760 "1-120 (seconds))\n");
3761
3762 if (fan_control_commands & TPACPI_FAN_CMD_SPEED)
3763 len += sprintf(p + len, "commands:\tspeed <speed>"
3764 " (<speed> is 0-65535)\n");
3765
3766 return len;
3767}
3768
3769static int fan_write_cmd_level(const char *cmd, int *rc)
3770{
3771 int level;
3772
3773 if (strlencmp(cmd, "level auto") == 0)
3774 level = TP_EC_FAN_AUTO;
3775 else if ((strlencmp(cmd, "level disengaged") == 0) |
3776 (strlencmp(cmd, "level full-speed") == 0))
3777 level = TP_EC_FAN_FULLSPEED;
3778 else if (sscanf(cmd, "level %d", &level) != 1)
3779 return 0;
3780
3781 if ((*rc = fan_set_level_safe(level)) == -ENXIO)
3782 printk(IBM_ERR "level command accepted for unsupported "
3783 "access mode %d", fan_control_access_mode);
3784
3785 return 1;
3786}
3787
3788static int fan_write_cmd_enable(const char *cmd, int *rc)
3789{
3790 if (strlencmp(cmd, "enable") != 0)
3791 return 0;
3792
3793 if ((*rc = fan_set_enable()) == -ENXIO)
3794 printk(IBM_ERR "enable command accepted for unsupported "
3795 "access mode %d", fan_control_access_mode);
3796
3797 return 1;
3798}
3799
3800static int fan_write_cmd_disable(const char *cmd, int *rc)
3801{
3802 if (strlencmp(cmd, "disable") != 0)
3803 return 0;
3804
3805 if ((*rc = fan_set_disable()) == -ENXIO)
3806 printk(IBM_ERR "disable command accepted for unsupported "
3807 "access mode %d", fan_control_access_mode);
3808
3809 return 1;
3810}
3811
3812static int fan_write_cmd_speed(const char *cmd, int *rc)
3813{
3814 int speed;
3815
3816 /* TODO:
3817 * Support speed <low> <medium> <high> ? */
3818
3819 if (sscanf(cmd, "speed %d", &speed) != 1)
3820 return 0;
3821
3822 if ((*rc = fan_set_speed(speed)) == -ENXIO)
3823 printk(IBM_ERR "speed command accepted for unsupported "
3824 "access mode %d", fan_control_access_mode);
3825
3826 return 1;
3827}
3828
3829static int fan_write_cmd_watchdog(const char *cmd, int *rc)
3830{
3831 int interval;
3832
3833 if (sscanf(cmd, "watchdog %d", &interval) != 1)
3834 return 0;
3835
3836 if (interval < 0 || interval > 120)
3837 *rc = -EINVAL;
3838 else
3839 fan_watchdog_maxinterval = interval;
3840
3841 return 1;
3842}
3843
3844static int fan_write(char *buf)
3845{
3846 char *cmd;
3847 int rc = 0;
3848
3849 while (!rc && (cmd = next_cmd(&buf))) {
3850 if (!((fan_control_commands & TPACPI_FAN_CMD_LEVEL) &&
3851 fan_write_cmd_level(cmd, &rc)) &&
3852 !((fan_control_commands & TPACPI_FAN_CMD_ENABLE) &&
3853 (fan_write_cmd_enable(cmd, &rc) ||
3854 fan_write_cmd_disable(cmd, &rc) ||
3855 fan_write_cmd_watchdog(cmd, &rc))) &&
3856 !((fan_control_commands & TPACPI_FAN_CMD_SPEED) &&
3857 fan_write_cmd_speed(cmd, &rc))
3858 )
3859 rc = -EINVAL;
3860 else if (!rc)
3861 fan_watchdog_reset();
3862 }
3863
3864 return rc;
3865}
3866
3867static struct ibm_struct fan_driver_data = {
3868 .name = "fan",
3869 .read = fan_read,
3870 .write = fan_write,
3871 .exit = fan_exit,
3872};
3873
3874/****************************************************************************
3875 ****************************************************************************
3876 *
3877 * Infrastructure
3878 *
3879 ****************************************************************************
3880 ****************************************************************************/
3881
3882/* /proc support */
3883static struct proc_dir_entry *proc_dir = NULL;
3884
3885/* Subdriver registry */
3886static LIST_HEAD(tpacpi_all_drivers);
3887
3888
3889/*
3890 * Module and infrastructure proble, init and exit handling
3891 */
3892
3893#ifdef CONFIG_THINKPAD_ACPI_DEBUG
3894static const char * __init str_supported(int is_supported)
3895{
3896 static char text_unsupported[] __initdata = "not supported";
3897
3898 return (is_supported)? &text_unsupported[4] : &text_unsupported[0];
3899}
3900#endif /* CONFIG_THINKPAD_ACPI_DEBUG */
3901
3902static int __init ibm_init(struct ibm_init_struct *iibm)
3903{
3904 int ret;
3905 struct ibm_struct *ibm = iibm->data;
3906 struct proc_dir_entry *entry;
3907
3908 BUG_ON(ibm == NULL);
3909
3910 INIT_LIST_HEAD(&ibm->all_drivers);
3911
3912 if (ibm->flags.experimental && !experimental)
3913 return 0;
3914
3915 dbg_printk(TPACPI_DBG_INIT,
3916 "probing for %s\n", ibm->name);
3917
3918 if (iibm->init) {
3919 ret = iibm->init(iibm);
3920 if (ret > 0)
3921 return 0; /* probe failed */
3922 if (ret)
3923 return ret;
3924
3925 ibm->flags.init_called = 1;
3926 }
3927
3928 if (ibm->acpi) {
3929 if (ibm->acpi->hid) {
3930 ret = register_tpacpi_subdriver(ibm);
3931 if (ret)
3932 goto err_out;
3933 }
3934
3935 if (ibm->acpi->notify) {
3936 ret = setup_acpi_notify(ibm);
3937 if (ret == -ENODEV) {
3938 printk(IBM_NOTICE "disabling subdriver %s\n",
3939 ibm->name);
3940 ret = 0;
3941 goto err_out;
3942 }
3943 if (ret < 0)
3944 goto err_out;
3945 }
3946 }
3947
3948 dbg_printk(TPACPI_DBG_INIT,
3949 "%s installed\n", ibm->name);
3950
3951 if (ibm->read) {
3952 entry = create_proc_entry(ibm->name,
3953 S_IFREG | S_IRUGO | S_IWUSR,
3954 proc_dir);
3955 if (!entry) {
3956 printk(IBM_ERR "unable to create proc entry %s\n",
3957 ibm->name);
3958 ret = -ENODEV;
3959 goto err_out;
3960 }
3961 entry->owner = THIS_MODULE;
3962 entry->data = ibm;
3963 entry->read_proc = &dispatch_procfs_read;
3964 if (ibm->write)
3965 entry->write_proc = &dispatch_procfs_write;
3966 ibm->flags.proc_created = 1;
3967 }
3968
3969 list_add_tail(&ibm->all_drivers, &tpacpi_all_drivers);
3970
3971 return 0;
3972
3973err_out:
3974 dbg_printk(TPACPI_DBG_INIT,
3975 "%s: at error exit path with result %d\n",
3976 ibm->name, ret);
3977
3978 ibm_exit(ibm);
3979 return (ret < 0)? ret : 0;
3980}
3981
3982static void ibm_exit(struct ibm_struct *ibm)
3983{
3984 dbg_printk(TPACPI_DBG_EXIT, "removing %s\n", ibm->name);
3985
3986 list_del_init(&ibm->all_drivers);
3987
3988 if (ibm->flags.acpi_notify_installed) {
3989 dbg_printk(TPACPI_DBG_EXIT,
3990 "%s: acpi_remove_notify_handler\n", ibm->name);
3991 BUG_ON(!ibm->acpi);
3992 acpi_remove_notify_handler(*ibm->acpi->handle,
3993 ibm->acpi->type,
3994 dispatch_acpi_notify);
3995 ibm->flags.acpi_notify_installed = 0;
3996 ibm->flags.acpi_notify_installed = 0;
3997 }
3998
3999 if (ibm->flags.proc_created) {
4000 dbg_printk(TPACPI_DBG_EXIT,
4001 "%s: remove_proc_entry\n", ibm->name);
4002 remove_proc_entry(ibm->name, proc_dir);
4003 ibm->flags.proc_created = 0;
4004 }
4005
4006 if (ibm->flags.acpi_driver_registered) {
4007 dbg_printk(TPACPI_DBG_EXIT,
4008 "%s: acpi_bus_unregister_driver\n", ibm->name);
4009 BUG_ON(!ibm->acpi);
4010 acpi_bus_unregister_driver(ibm->acpi->driver);
4011 kfree(ibm->acpi->driver);
4012 ibm->acpi->driver = NULL;
4013 ibm->flags.acpi_driver_registered = 0;
4014 }
4015
4016 if (ibm->flags.init_called && ibm->exit) {
4017 ibm->exit();
4018 ibm->flags.init_called = 0;
4019 }
4020
4021 dbg_printk(TPACPI_DBG_INIT, "finished removing %s\n", ibm->name);
4022}
4023
4024/* Probing */
4025
4026static char *ibm_thinkpad_ec_found = NULL;
4027
4028static char* __init check_dmi_for_ec(void)
4029{
4030 struct dmi_device *dev = NULL;
4031 char ec_fw_string[18];
4032
4033 /*
4034 * ThinkPad T23 or newer, A31 or newer, R50e or newer,
4035 * X32 or newer, all Z series; Some models must have an
4036 * up-to-date BIOS or they will not be detected.
4037 *
4038 * See http://thinkwiki.org/wiki/List_of_DMI_IDs
4039 */
4040 while ((dev = dmi_find_device(DMI_DEV_TYPE_OEM_STRING, NULL, dev))) {
4041 if (sscanf(dev->name,
4042 "IBM ThinkPad Embedded Controller -[%17c",
4043 ec_fw_string) == 1) {
4044 ec_fw_string[sizeof(ec_fw_string) - 1] = 0;
4045 ec_fw_string[strcspn(ec_fw_string, " ]")] = 0;
4046 return kstrdup(ec_fw_string, GFP_KERNEL);
4047 }
4048 }
4049 return NULL;
4050}
4051
4052static int __init probe_for_thinkpad(void)
4053{
4054 int is_thinkpad;
4055
4056 if (acpi_disabled)
4057 return -ENODEV;
4058
4059 /*
4060 * Non-ancient models have better DMI tagging, but very old models
4061 * don't.
4062 */
4063 is_thinkpad = dmi_name_in_vendors("ThinkPad");
4064
4065 /* ec is required because many other handles are relative to it */
4066 IBM_ACPIHANDLE_INIT(ec);
4067 if (!ec_handle) {
4068 if (is_thinkpad)
4069 printk(IBM_ERR
4070 "Not yet supported ThinkPad detected!\n");
4071 return -ENODEV;
4072 }
4073
4074 /*
4075 * Risks a regression on very old machines, but reduces potential
4076 * false positives a damn great deal
4077 */
4078 if (!is_thinkpad)
4079 is_thinkpad = dmi_name_in_vendors("IBM");
4080
4081 if (!is_thinkpad && !force_load)
4082 return -ENODEV;
4083
4084 return 0;
4085}
4086
4087
4088/* Module init, exit, parameters */
4089
4090static struct ibm_init_struct ibms_init[] __initdata = {
4091 {
4092 .init = thinkpad_acpi_driver_init,
4093 .data = &thinkpad_acpi_driver_data,
4094 },
4095 {
4096 .init = hotkey_init,
4097 .data = &hotkey_driver_data,
4098 },
4099 {
4100 .init = bluetooth_init,
4101 .data = &bluetooth_driver_data,
4102 },
4103 {
4104 .init = wan_init,
4105 .data = &wan_driver_data,
4106 },
4107 {
4108 .init = video_init,
4109 .data = &video_driver_data,
4110 },
4111 {
4112 .init = light_init,
4113 .data = &light_driver_data,
4114 },
4115#ifdef CONFIG_THINKPAD_ACPI_DOCK
4116 {
4117 .init = dock_init,
4118 .data = &dock_driver_data[0],
4119 },
4120 {
4121 .init = dock_init2,
4122 .data = &dock_driver_data[1],
4123 },
4124#endif
4125#ifdef CONFIG_THINKPAD_ACPI_BAY
4126 {
4127 .init = bay_init,
4128 .data = &bay_driver_data,
4129 },
4130#endif
4131 {
4132 .init = cmos_init,
4133 .data = &cmos_driver_data,
4134 },
4135 {
4136 .init = led_init,
4137 .data = &led_driver_data,
4138 },
4139 {
4140 .init = beep_init,
4141 .data = &beep_driver_data,
4142 },
4143 {
4144 .init = thermal_init,
4145 .data = &thermal_driver_data,
4146 },
4147 {
4148 .data = &ecdump_driver_data,
4149 },
4150 {
4151 .init = brightness_init,
4152 .data = &brightness_driver_data,
4153 },
4154 {
4155 .data = &volume_driver_data,
4156 },
4157 {
4158 .init = fan_init,
4159 .data = &fan_driver_data,
4160 },
4161};
4162
4163static int __init set_ibm_param(const char *val, struct kernel_param *kp)
4164{
4165 unsigned int i;
4166 struct ibm_struct *ibm;
4167
4168 for (i = 0; i < ARRAY_SIZE(ibms_init); i++) {
4169 ibm = ibms_init[i].data;
4170 BUG_ON(ibm == NULL);
4171
4172 if (strcmp(ibm->name, kp->name) == 0 && ibm->write) {
4173 if (strlen(val) > sizeof(ibms_init[i].param) - 2)
4174 return -ENOSPC;
4175 strcpy(ibms_init[i].param, val);
4176 strcat(ibms_init[i].param, ",");
4177 return 0;
4178 }
4179 }
4180
4181 return -EINVAL;
4182}
4183
4184static int experimental;
4185module_param(experimental, int, 0);
4186
4187static u32 dbg_level;
4188module_param_named(debug, dbg_level, uint, 0);
4189
4190static int force_load;
4191module_param(force_load, int, 0);
4192
4193static int fan_control_allowed;
4194module_param_named(fan_control, fan_control_allowed, int, 0);
4195
4196#define IBM_PARAM(feature) \
4197 module_param_call(feature, set_ibm_param, NULL, NULL, 0)
4198
4199IBM_PARAM(hotkey);
4200IBM_PARAM(bluetooth);
4201IBM_PARAM(video);
4202IBM_PARAM(light);
4203#ifdef CONFIG_THINKPAD_ACPI_DOCK
4204IBM_PARAM(dock);
4205#endif
4206#ifdef CONFIG_THINKPAD_ACPI_BAY
4207IBM_PARAM(bay);
4208#endif /* CONFIG_THINKPAD_ACPI_BAY */
4209IBM_PARAM(cmos);
4210IBM_PARAM(led);
4211IBM_PARAM(beep);
4212IBM_PARAM(ecdump);
4213IBM_PARAM(brightness);
4214IBM_PARAM(volume);
4215IBM_PARAM(fan);
4216
4217static int __init thinkpad_acpi_module_init(void)
4218{
4219 int ret, i;
4220
4221 /* Driver-level probe */
4222 ret = probe_for_thinkpad();
4223 if (ret)
4224 return ret;
4225
4226 /* Driver initialization */
4227 ibm_thinkpad_ec_found = check_dmi_for_ec();
4228 IBM_ACPIHANDLE_INIT(ecrd);
4229 IBM_ACPIHANDLE_INIT(ecwr);
4230
4231 proc_dir = proc_mkdir(IBM_PROC_DIR, acpi_root_dir);
4232 if (!proc_dir) {
4233 printk(IBM_ERR "unable to create proc dir " IBM_PROC_DIR);
4234 thinkpad_acpi_module_exit();
4235 return -ENODEV;
4236 }
4237 proc_dir->owner = THIS_MODULE;
4238
4239 ret = platform_driver_register(&tpacpi_pdriver);
4240 if (ret) {
4241 printk(IBM_ERR "unable to register platform driver\n");
4242 thinkpad_acpi_module_exit();
4243 return ret;
4244 }
4245 ret = tpacpi_create_driver_attributes(&tpacpi_pdriver.driver);
4246 if (ret) {
4247 printk(IBM_ERR "unable to create sysfs driver attributes\n");
4248 thinkpad_acpi_module_exit();
4249 return ret;
4250 }
4251
4252
4253 /* Device initialization */
4254 tpacpi_pdev = platform_device_register_simple(IBM_DRVR_NAME, -1,
4255 NULL, 0);
4256 if (IS_ERR(tpacpi_pdev)) {
4257 ret = PTR_ERR(tpacpi_pdev);
4258 tpacpi_pdev = NULL;
4259 printk(IBM_ERR "unable to register platform device\n");
4260 thinkpad_acpi_module_exit();
4261 return ret;
4262 }
4263 tpacpi_hwmon = hwmon_device_register(&tpacpi_pdev->dev);
4264 if (IS_ERR(tpacpi_hwmon)) {
4265 ret = PTR_ERR(tpacpi_hwmon);
4266 tpacpi_hwmon = NULL;
4267 printk(IBM_ERR "unable to register hwmon device\n");
4268 thinkpad_acpi_module_exit();
4269 return ret;
4270 }
4271 for (i = 0; i < ARRAY_SIZE(ibms_init); i++) {
4272 ret = ibm_init(&ibms_init[i]);
4273 if (ret >= 0 && *ibms_init[i].param)
4274 ret = ibms_init[i].data->write(ibms_init[i].param);
4275 if (ret < 0) {
4276 thinkpad_acpi_module_exit();
4277 return ret;
4278 }
4279 }
4280
4281 return 0;
4282}
4283
4284static void thinkpad_acpi_module_exit(void)
4285{
4286 struct ibm_struct *ibm, *itmp;
4287
4288 list_for_each_entry_safe_reverse(ibm, itmp,
4289 &tpacpi_all_drivers,
4290 all_drivers) {
4291 ibm_exit(ibm);
4292 }
4293
4294 dbg_printk(TPACPI_DBG_INIT, "finished subdriver exit path...\n");
4295
4296 if (tpacpi_hwmon)
4297 hwmon_device_unregister(tpacpi_hwmon);
4298
4299 if (tpacpi_pdev)
4300 platform_device_unregister(tpacpi_pdev);
4301
4302 tpacpi_remove_driver_attributes(&tpacpi_pdriver.driver);
4303 platform_driver_unregister(&tpacpi_pdriver);
4304
4305 if (proc_dir)
4306 remove_proc_entry(IBM_PROC_DIR, acpi_root_dir);
4307
4308 kfree(ibm_thinkpad_ec_found);
4309}
4310
4311module_init(thinkpad_acpi_module_init);
4312module_exit(thinkpad_acpi_module_exit);
diff --git a/drivers/misc/thinkpad_acpi.h b/drivers/misc/thinkpad_acpi.h
new file mode 100644
index 000000000000..440145a02617
--- /dev/null
+++ b/drivers/misc/thinkpad_acpi.h
@@ -0,0 +1,572 @@
1/*
2 * thinkpad_acpi.h - ThinkPad ACPI Extras
3 *
4 *
5 * Copyright (C) 2004-2005 Borislav Deianov <borislav@users.sf.net>
6 * Copyright (C) 2006-2007 Henrique de Moraes Holschuh <hmh@hmh.eng.br>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 * 02110-1301, USA.
22 */
23
24#ifndef __THINKPAD_ACPI_H__
25#define __THINKPAD_ACPI_H__
26
27#include <linux/kernel.h>
28#include <linux/module.h>
29#include <linux/init.h>
30#include <linux/types.h>
31#include <linux/string.h>
32#include <linux/list.h>
33#include <linux/mutex.h>
34
35#include <linux/proc_fs.h>
36#include <linux/sysfs.h>
37#include <linux/backlight.h>
38#include <linux/fb.h>
39#include <linux/platform_device.h>
40#include <linux/hwmon.h>
41#include <linux/hwmon-sysfs.h>
42#include <asm/uaccess.h>
43
44#include <linux/dmi.h>
45#include <linux/jiffies.h>
46#include <linux/workqueue.h>
47
48#include <acpi/acpi_drivers.h>
49#include <acpi/acnamesp.h>
50
51
52/****************************************************************************
53 * Main driver
54 */
55
56#define IBM_NAME "thinkpad"
57#define IBM_DESC "ThinkPad ACPI Extras"
58#define IBM_FILE "thinkpad_acpi"
59#define IBM_URL "http://ibm-acpi.sf.net/"
60#define IBM_MAIL "ibm-acpi-devel@lists.sourceforge.net"
61
62#define IBM_PROC_DIR "ibm"
63#define IBM_ACPI_EVENT_PREFIX "ibm"
64#define IBM_DRVR_NAME IBM_FILE
65
66#define IBM_LOG IBM_FILE ": "
67#define IBM_ERR KERN_ERR IBM_LOG
68#define IBM_NOTICE KERN_NOTICE IBM_LOG
69#define IBM_INFO KERN_INFO IBM_LOG
70#define IBM_DEBUG KERN_DEBUG IBM_LOG
71
72#define IBM_MAX_ACPI_ARGS 3
73
74/* ThinkPad CMOS commands */
75#define TP_CMOS_VOLUME_DOWN 0
76#define TP_CMOS_VOLUME_UP 1
77#define TP_CMOS_VOLUME_MUTE 2
78#define TP_CMOS_BRIGHTNESS_UP 4
79#define TP_CMOS_BRIGHTNESS_DOWN 5
80
81#define onoff(status,bit) ((status) & (1 << (bit)) ? "on" : "off")
82#define enabled(status,bit) ((status) & (1 << (bit)) ? "enabled" : "disabled")
83#define strlencmp(a,b) (strncmp((a), (b), strlen(b)))
84
85/* Debugging */
86#define TPACPI_DBG_ALL 0xffff
87#define TPACPI_DBG_ALL 0xffff
88#define TPACPI_DBG_INIT 0x0001
89#define TPACPI_DBG_EXIT 0x0002
90#define dbg_printk(a_dbg_level, format, arg...) \
91 do { if (dbg_level & a_dbg_level) \
92 printk(IBM_DEBUG "%s: " format, __func__ , ## arg); } while (0)
93#ifdef CONFIG_THINKPAD_ACPI_DEBUG
94#define vdbg_printk(a_dbg_level, format, arg...) \
95 dbg_printk(a_dbg_level, format, ## arg)
96static const char *str_supported(int is_supported);
97#else
98#define vdbg_printk(a_dbg_level, format, arg...)
99#endif
100
101/* ACPI HIDs */
102#define IBM_HKEY_HID "IBM0068"
103#define IBM_PCI_HID "PNP0A03"
104
105/* ACPI helpers */
106static int __must_check acpi_evalf(acpi_handle handle,
107 void *res, char *method, char *fmt, ...);
108static int __must_check acpi_ec_read(int i, u8 * p);
109static int __must_check acpi_ec_write(int i, u8 v);
110static int __must_check _sta(acpi_handle handle);
111
112/* ACPI handles */
113static acpi_handle root_handle; /* root namespace */
114static acpi_handle ec_handle; /* EC */
115static acpi_handle ecrd_handle, ecwr_handle; /* 570 EC access */
116static acpi_handle cmos_handle, hkey_handle; /* basic thinkpad handles */
117
118static void drv_acpi_handle_init(char *name,
119 acpi_handle *handle, acpi_handle parent,
120 char **paths, int num_paths, char **path);
121#define IBM_ACPIHANDLE_INIT(object) \
122 drv_acpi_handle_init(#object, &object##_handle, *object##_parent, \
123 object##_paths, ARRAY_SIZE(object##_paths), &object##_path)
124
125/* ThinkPad ACPI helpers */
126static int issue_thinkpad_cmos_command(int cmos_cmd);
127
128/* procfs support */
129static struct proc_dir_entry *proc_dir;
130
131/* procfs helpers */
132static int dispatch_procfs_read(char *page, char **start, off_t off,
133 int count, int *eof, void *data);
134static int dispatch_procfs_write(struct file *file,
135 const char __user * userbuf,
136 unsigned long count, void *data);
137static char *next_cmd(char **cmds);
138
139/* sysfs support */
140struct attribute_set {
141 unsigned int members, max_members;
142 struct attribute_group group;
143};
144
145static struct attribute_set *create_attr_set(unsigned int max_members,
146 const char* name);
147#define destroy_attr_set(_set) \
148 kfree(_set);
149static int add_to_attr_set(struct attribute_set* s, struct attribute *attr);
150static int add_many_to_attr_set(struct attribute_set* s,
151 struct attribute **attr,
152 unsigned int count);
153#define register_attr_set_with_sysfs(_attr_set, _kobj) \
154 sysfs_create_group(_kobj, &_attr_set->group)
155static void delete_attr_set(struct attribute_set* s, struct kobject *kobj);
156
157static int parse_strtoul(const char *buf, unsigned long max,
158 unsigned long *value);
159
160/* Device model */
161static struct platform_device *tpacpi_pdev;
162static struct class_device *tpacpi_hwmon;
163static struct platform_driver tpacpi_pdriver;
164static int tpacpi_create_driver_attributes(struct device_driver *drv);
165static void tpacpi_remove_driver_attributes(struct device_driver *drv);
166
167/* Module */
168static int experimental;
169static u32 dbg_level;
170static int force_load;
171static char *ibm_thinkpad_ec_found;
172
173static char* check_dmi_for_ec(void);
174static int thinkpad_acpi_module_init(void);
175static void thinkpad_acpi_module_exit(void);
176
177
178/****************************************************************************
179 * Subdrivers
180 */
181
182struct ibm_struct;
183
184struct tp_acpi_drv_struct {
185 char *hid;
186 struct acpi_driver *driver;
187
188 void (*notify) (struct ibm_struct *, u32);
189 acpi_handle *handle;
190 u32 type;
191 struct acpi_device *device;
192};
193
194struct ibm_struct {
195 char *name;
196
197 int (*read) (char *);
198 int (*write) (char *);
199 void (*exit) (void);
200
201 struct list_head all_drivers;
202
203 struct tp_acpi_drv_struct *acpi;
204
205 struct {
206 u8 acpi_driver_registered:1;
207 u8 acpi_notify_installed:1;
208 u8 proc_created:1;
209 u8 init_called:1;
210 u8 experimental:1;
211 } flags;
212};
213
214struct ibm_init_struct {
215 char param[32];
216
217 int (*init) (struct ibm_init_struct *);
218 struct ibm_struct *data;
219};
220
221static struct {
222#ifdef CONFIG_THINKPAD_ACPI_BAY
223 u16 bay_status:1;
224 u16 bay_eject:1;
225 u16 bay_status2:1;
226 u16 bay_eject2:1;
227#endif
228 u16 bluetooth:1;
229 u16 hotkey:1;
230 u16 hotkey_mask:1;
231 u16 light:1;
232 u16 light_status:1;
233 u16 wan:1;
234 u16 fan_ctrl_status_undef:1;
235} tp_features;
236
237static struct list_head tpacpi_all_drivers;
238
239static struct ibm_init_struct ibms_init[];
240static int set_ibm_param(const char *val, struct kernel_param *kp);
241static int ibm_init(struct ibm_init_struct *iibm);
242static void ibm_exit(struct ibm_struct *ibm);
243
244
245/*
246 * procfs master subdriver
247 */
248static int thinkpad_acpi_driver_init(struct ibm_init_struct *iibm);
249static int thinkpad_acpi_driver_read(char *p);
250
251
252/*
253 * Bay subdriver
254 */
255
256#ifdef CONFIG_THINKPAD_ACPI_BAY
257static acpi_handle bay_handle, bay_ej_handle;
258static acpi_handle bay2_handle, bay2_ej_handle;
259
260static int bay_init(struct ibm_init_struct *iibm);
261static void bay_notify(struct ibm_struct *ibm, u32 event);
262static int bay_read(char *p);
263static int bay_write(char *buf);
264#endif /* CONFIG_THINKPAD_ACPI_BAY */
265
266
267/*
268 * Beep subdriver
269 */
270
271static acpi_handle beep_handle;
272
273static int beep_read(char *p);
274static int beep_write(char *buf);
275
276
277/*
278 * Bluetooth subdriver
279 */
280
281#define TPACPI_BLUETH_SYSFS_GROUP "bluetooth"
282
283enum {
284 /* ACPI GBDC/SBDC bits */
285 TP_ACPI_BLUETOOTH_HWPRESENT = 0x01, /* Bluetooth hw available */
286 TP_ACPI_BLUETOOTH_RADIOSSW = 0x02, /* Bluetooth radio enabled */
287 TP_ACPI_BLUETOOTH_UNK = 0x04, /* unknown function */
288};
289
290static int bluetooth_init(struct ibm_init_struct *iibm);
291static int bluetooth_get_radiosw(void);
292static int bluetooth_set_radiosw(int radio_on);
293static int bluetooth_read(char *p);
294static int bluetooth_write(char *buf);
295
296
297/*
298 * Brightness (backlight) subdriver
299 */
300
301#define TPACPI_BACKLIGHT_DEV_NAME "thinkpad_screen"
302
303static struct backlight_device *ibm_backlight_device;
304static int brightness_offset = 0x31;
305
306static int brightness_init(struct ibm_init_struct *iibm);
307static void brightness_exit(void);
308static int brightness_get(struct backlight_device *bd);
309static int brightness_set(int value);
310static int brightness_update_status(struct backlight_device *bd);
311static int brightness_read(char *p);
312static int brightness_write(char *buf);
313
314
315/*
316 * CMOS subdriver
317 */
318
319static int cmos_read(char *p);
320static int cmos_write(char *buf);
321
322
323/*
324 * Dock subdriver
325 */
326
327#ifdef CONFIG_THINKPAD_ACPI_DOCK
328static acpi_handle pci_handle;
329static acpi_handle dock_handle;
330
331static void dock_notify(struct ibm_struct *ibm, u32 event);
332static int dock_read(char *p);
333static int dock_write(char *buf);
334#endif /* CONFIG_THINKPAD_ACPI_DOCK */
335
336
337/*
338 * EC dump subdriver
339 */
340
341static int ecdump_read(char *p) ;
342static int ecdump_write(char *buf);
343
344
345/*
346 * Fan subdriver
347 */
348
349enum { /* Fan control constants */
350 fan_status_offset = 0x2f, /* EC register 0x2f */
351 fan_rpm_offset = 0x84, /* EC register 0x84: LSB, 0x85 MSB (RPM)
352 * 0x84 must be read before 0x85 */
353
354 TP_EC_FAN_FULLSPEED = 0x40, /* EC fan mode: full speed */
355 TP_EC_FAN_AUTO = 0x80, /* EC fan mode: auto fan control */
356
357 TPACPI_FAN_LAST_LEVEL = 0x100, /* Use cached last-seen fan level */
358};
359
360enum fan_status_access_mode {
361 TPACPI_FAN_NONE = 0, /* No fan status or control */
362 TPACPI_FAN_RD_ACPI_GFAN, /* Use ACPI GFAN */
363 TPACPI_FAN_RD_TPEC, /* Use ACPI EC regs 0x2f, 0x84-0x85 */
364};
365
366enum fan_control_access_mode {
367 TPACPI_FAN_WR_NONE = 0, /* No fan control */
368 TPACPI_FAN_WR_ACPI_SFAN, /* Use ACPI SFAN */
369 TPACPI_FAN_WR_TPEC, /* Use ACPI EC reg 0x2f */
370 TPACPI_FAN_WR_ACPI_FANS, /* Use ACPI FANS and EC reg 0x2f */
371};
372
373enum fan_control_commands {
374 TPACPI_FAN_CMD_SPEED = 0x0001, /* speed command */
375 TPACPI_FAN_CMD_LEVEL = 0x0002, /* level command */
376 TPACPI_FAN_CMD_ENABLE = 0x0004, /* enable/disable cmd,
377 * and also watchdog cmd */
378};
379
380static int fan_control_allowed;
381
382static enum fan_status_access_mode fan_status_access_mode;
383static enum fan_control_access_mode fan_control_access_mode;
384static enum fan_control_commands fan_control_commands;
385static u8 fan_control_initial_status;
386static u8 fan_control_desired_level;
387static int fan_watchdog_maxinterval;
388
389static struct mutex fan_mutex;
390
391static acpi_handle fans_handle, gfan_handle, sfan_handle;
392
393static int fan_init(struct ibm_init_struct *iibm);
394static void fan_exit(void);
395static int fan_get_status(u8 *status);
396static int fan_get_status_safe(u8 *status);
397static int fan_get_speed(unsigned int *speed);
398static void fan_update_desired_level(u8 status);
399static void fan_watchdog_fire(struct work_struct *ignored);
400static void fan_watchdog_reset(void);
401static int fan_set_level(int level);
402static int fan_set_level_safe(int level);
403static int fan_set_enable(void);
404static int fan_set_disable(void);
405static int fan_set_speed(int speed);
406static int fan_read(char *p);
407static int fan_write(char *buf);
408static int fan_write_cmd_level(const char *cmd, int *rc);
409static int fan_write_cmd_enable(const char *cmd, int *rc);
410static int fan_write_cmd_disable(const char *cmd, int *rc);
411static int fan_write_cmd_speed(const char *cmd, int *rc);
412static int fan_write_cmd_watchdog(const char *cmd, int *rc);
413
414
415/*
416 * Hotkey subdriver
417 */
418
419#define TPACPI_HOTKEY_SYSFS_GROUP "hotkey"
420
421static int hotkey_orig_status;
422static int hotkey_orig_mask;
423
424static struct mutex hotkey_mutex;
425
426static int hotkey_init(struct ibm_init_struct *iibm);
427static void hotkey_exit(void);
428static int hotkey_get(int *status, int *mask);
429static int hotkey_set(int status, int mask);
430static void hotkey_notify(struct ibm_struct *ibm, u32 event);
431static int hotkey_read(char *p);
432static int hotkey_write(char *buf);
433
434
435/*
436 * LED subdriver
437 */
438
439enum led_access_mode {
440 TPACPI_LED_NONE = 0,
441 TPACPI_LED_570, /* 570 */
442 TPACPI_LED_OLD, /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20-21 */
443 TPACPI_LED_NEW, /* all others */
444};
445
446enum { /* For TPACPI_LED_OLD */
447 TPACPI_LED_EC_HLCL = 0x0c, /* EC reg to get led to power on */
448 TPACPI_LED_EC_HLBL = 0x0d, /* EC reg to blink a lit led */
449 TPACPI_LED_EC_HLMS = 0x0e, /* EC reg to select led to command */
450};
451
452static enum led_access_mode led_supported;
453static acpi_handle led_handle;
454
455static int led_init(struct ibm_init_struct *iibm);
456static int led_read(char *p);
457static int led_write(char *buf);
458
459/*
460 * Light (thinklight) subdriver
461 */
462
463static acpi_handle lght_handle, ledb_handle;
464
465static int light_init(struct ibm_init_struct *iibm);
466static int light_read(char *p);
467static int light_write(char *buf);
468
469
470/*
471 * Thermal subdriver
472 */
473
474enum thermal_access_mode {
475 TPACPI_THERMAL_NONE = 0, /* No thermal support */
476 TPACPI_THERMAL_ACPI_TMP07, /* Use ACPI TMP0-7 */
477 TPACPI_THERMAL_ACPI_UPDT, /* Use ACPI TMP0-7 with UPDT */
478 TPACPI_THERMAL_TPEC_8, /* Use ACPI EC regs, 8 sensors */
479 TPACPI_THERMAL_TPEC_16, /* Use ACPI EC regs, 16 sensors */
480};
481
482enum { /* TPACPI_THERMAL_TPEC_* */
483 TP_EC_THERMAL_TMP0 = 0x78, /* ACPI EC regs TMP 0..7 */
484 TP_EC_THERMAL_TMP8 = 0xC0, /* ACPI EC regs TMP 8..15 */
485 TP_EC_THERMAL_TMP_NA = -128, /* ACPI EC sensor not available */
486};
487
488#define TPACPI_MAX_THERMAL_SENSORS 16 /* Max thermal sensors supported */
489struct ibm_thermal_sensors_struct {
490 s32 temp[TPACPI_MAX_THERMAL_SENSORS];
491};
492
493static enum thermal_access_mode thermal_read_mode;
494
495static int thermal_init(struct ibm_init_struct *iibm);
496static int thermal_get_sensor(int idx, s32 *value);
497static int thermal_get_sensors(struct ibm_thermal_sensors_struct *s);
498static int thermal_read(char *p);
499
500
501/*
502 * Video subdriver
503 */
504
505enum video_access_mode {
506 TPACPI_VIDEO_NONE = 0,
507 TPACPI_VIDEO_570, /* 570 */
508 TPACPI_VIDEO_770, /* 600e/x, 770e, 770x */
509 TPACPI_VIDEO_NEW, /* all others */
510};
511
512enum { /* video status flags, based on VIDEO_570 */
513 TP_ACPI_VIDEO_S_LCD = 0x01, /* LCD output enabled */
514 TP_ACPI_VIDEO_S_CRT = 0x02, /* CRT output enabled */
515 TP_ACPI_VIDEO_S_DVI = 0x08, /* DVI output enabled */
516};
517
518enum { /* TPACPI_VIDEO_570 constants */
519 TP_ACPI_VIDEO_570_PHSCMD = 0x87, /* unknown magic constant :( */
520 TP_ACPI_VIDEO_570_PHSMASK = 0x03, /* PHS bits that map to
521 * video_status_flags */
522 TP_ACPI_VIDEO_570_PHS2CMD = 0x8b, /* unknown magic constant :( */
523 TP_ACPI_VIDEO_570_PHS2SET = 0x80, /* unknown magic constant :( */
524};
525
526static enum video_access_mode video_supported;
527static int video_orig_autosw;
528static acpi_handle vid_handle, vid2_handle;
529
530static int video_init(struct ibm_init_struct *iibm);
531static void video_exit(void);
532static int video_outputsw_get(void);
533static int video_outputsw_set(int status);
534static int video_autosw_get(void);
535static int video_autosw_set(int enable);
536static int video_outputsw_cycle(void);
537static int video_expand_toggle(void);
538static int video_read(char *p);
539static int video_write(char *buf);
540
541
542/*
543 * Volume subdriver
544 */
545
546static int volume_offset = 0x30;
547
548static int volume_read(char *p);
549static int volume_write(char *buf);
550
551
552/*
553 * Wan subdriver
554 */
555
556#define TPACPI_WAN_SYSFS_GROUP "wwan"
557
558enum {
559 /* ACPI GWAN/SWAN bits */
560 TP_ACPI_WANCARD_HWPRESENT = 0x01, /* Wan hw available */
561 TP_ACPI_WANCARD_RADIOSSW = 0x02, /* Wan radio enabled */
562 TP_ACPI_WANCARD_UNK = 0x04, /* unknown function */
563};
564
565static int wan_init(struct ibm_init_struct *iibm);
566static int wan_get_radiosw(void);
567static int wan_set_radiosw(int radio_on);
568static int wan_read(char *p);
569static int wan_write(char *buf);
570
571
572#endif /* __THINKPAD_ACPI_H */