aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/misc
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@woody.linux-foundation.org>2008-02-07 12:45:58 -0500
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2008-02-07 12:45:58 -0500
commitf0f1b3364ae7f48084bdf2837fb979ff59622523 (patch)
treee5ef68c0071f44178cc8d1948b64e216d57422aa /drivers/misc
parent4383f18b7f94a4d668c5eec68645c75d44556235 (diff)
parentb7143156c9ceee1a072c57aac8729d2dec5b3bf1 (diff)
Merge branch 'release' of git://git.kernel.org/pub/scm/linux/kernel/git/lenb/linux-acpi-2.6
* 'release' of git://git.kernel.org/pub/scm/linux/kernel/git/lenb/linux-acpi-2.6: (112 commits) ACPI: fix build warning Revert "cpuidle: build fix for non-x86" ACPI: update intrd DSDT override console messages ACPI: update DSDT override documentation ACPI: Add "acpi_no_initrd_override" kernel parameter ACPI: its a directory not a folder.... ACPI: misc cleanups ACPI: add missing prink prefix strings ACPI: cleanup acpi.h ACPICA: fix CONFIG_ACPI_DEBUG_FUNC_TRACE build ACPI: video: Ignore ACPI video devices that aren't present in hardware ACPI: video: reset brightness on resume ACPI: video: call ACPI notifier chain for ACPI video notifications ACPI: create notifier chain to get hotkey events to graphics driver ACPI: video: delete unused display switch on hotkey event code ACPI: video: create "brightness_switch_enabled" modparam cpuidle: Add a poll_idle method ACPI: cpuidle: Support C1 idle time accounting ACPI: enable MWAIT for C1 idle ACPI: idle: Fix acpi_safe_halt usages and interrupt enabling/disabling ...
Diffstat (limited to 'drivers/misc')
-rw-r--r--drivers/misc/Kconfig53
-rw-r--r--drivers/misc/Makefile3
-rw-r--r--drivers/misc/acer-wmi.c1109
-rw-r--r--drivers/misc/asus-laptop.c26
-rw-r--r--drivers/misc/intel_menlow.c526
-rw-r--r--drivers/misc/sony-laptop.c445
-rw-r--r--drivers/misc/tc1100-wmi.c290
-rw-r--r--drivers/misc/thinkpad_acpi.c3256
-rw-r--r--drivers/misc/thinkpad_acpi.h606
9 files changed, 4448 insertions, 1866 deletions
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index b5e67c0ff433..78cd33861766 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -92,6 +92,22 @@ config TIFM_7XX1
92 To compile this driver as a module, choose M here: the module will 92 To compile this driver as a module, choose M here: the module will
93 be called tifm_7xx1. 93 be called tifm_7xx1.
94 94
95config ACER_WMI
96 tristate "Acer WMI Laptop Extras (EXPERIMENTAL)"
97 depends on X86
98 depends on EXPERIMENTAL
99 depends on ACPI
100 depends on ACPI_WMI
101 depends on LEDS_CLASS
102 depends on BACKLIGHT_CLASS_DEVICE
103 ---help---
104 This is a driver for newer Acer (and Wistron) laptops. It adds
105 wireless radio and bluetooth control, and on some laptops,
106 exposes the mail LED and LCD backlight.
107
108 If you have an ACPI-WMI compatible Acer/ Wistron laptop, say Y or M
109 here.
110
95config ASUS_LAPTOP 111config ASUS_LAPTOP
96 tristate "Asus Laptop Extras (EXPERIMENTAL)" 112 tristate "Asus Laptop Extras (EXPERIMENTAL)"
97 depends on X86 113 depends on X86
@@ -126,6 +142,15 @@ config FUJITSU_LAPTOP
126 142
127 If you have a Fujitsu laptop, say Y or M here. 143 If you have a Fujitsu laptop, say Y or M here.
128 144
145config TC1100_WMI
146 tristate "HP Compaq TC1100 Tablet WMI Extras"
147 depends on X86 && !X86_64
148 depends on ACPI
149 depends on ACPI_WMI
150 ---help---
151 This is a driver for the WMI extensions (wireless and bluetooth power
152 control) of the HP Compaq TC1100 tablet.
153
129config MSI_LAPTOP 154config MSI_LAPTOP
130 tristate "MSI Laptop Extras" 155 tristate "MSI Laptop Extras"
131 depends on X86 156 depends on X86
@@ -219,6 +244,25 @@ config THINKPAD_ACPI_BAY
219 244
220 If you are not sure, say Y here. 245 If you are not sure, say Y here.
221 246
247config THINKPAD_ACPI_HOTKEY_POLL
248 bool "Suport NVRAM polling for hot keys"
249 depends on THINKPAD_ACPI
250 default y
251 ---help---
252 Some thinkpad models benefit from NVRAM polling to detect a few of
253 the hot key press events. If you know your ThinkPad model does not
254 need to do NVRAM polling to support any of the hot keys you use,
255 unselecting this option will save about 1kB of memory.
256
257 ThinkPads T40 and newer, R52 and newer, and X31 and newer are
258 unlikely to need NVRAM polling in their latest BIOS versions.
259
260 NVRAM polling can detect at most the following keys: ThinkPad/Access
261 IBM, Zoom, Switch Display (fn+F7), ThinkLight, Volume up/down/mute,
262 Brightness up/down, Display Expand (fn+F8), Hibernate (fn+F12).
263
264 If you are not sure, say Y here. The driver enables polling only if
265 it is strictly necessary to do so.
222 266
223config ATMEL_SSC 267config ATMEL_SSC
224 tristate "Device driver for Atmel SSC peripheral" 268 tristate "Device driver for Atmel SSC peripheral"
@@ -232,4 +276,13 @@ config ATMEL_SSC
232 276
233 If unsure, say N. 277 If unsure, say N.
234 278
279config INTEL_MENLOW
280 tristate "Thermal Management driver for Intel menlow platform"
281 depends on ACPI_THERMAL
282 ---help---
283 ACPI thermal management enhancement driver on
284 Intel Menlow platform.
285
286 If unsure, say N.
287
235endif # MISC_DEVICES 288endif # MISC_DEVICES
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 87f2685d728f..1f41654aae4d 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -6,8 +6,10 @@ obj- := misc.o # Dummy rule to force built-in.o to be made
6obj-$(CONFIG_IBM_ASM) += ibmasm/ 6obj-$(CONFIG_IBM_ASM) += ibmasm/
7obj-$(CONFIG_HDPU_FEATURES) += hdpuftrs/ 7obj-$(CONFIG_HDPU_FEATURES) += hdpuftrs/
8obj-$(CONFIG_MSI_LAPTOP) += msi-laptop.o 8obj-$(CONFIG_MSI_LAPTOP) += msi-laptop.o
9obj-$(CONFIG_ACER_WMI) += acer-wmi.o
9obj-$(CONFIG_ASUS_LAPTOP) += asus-laptop.o 10obj-$(CONFIG_ASUS_LAPTOP) += asus-laptop.o
10obj-$(CONFIG_ATMEL_SSC) += atmel-ssc.o 11obj-$(CONFIG_ATMEL_SSC) += atmel-ssc.o
12obj-$(CONFIG_TC1100_WMI) += tc1100-wmi.o
11obj-$(CONFIG_LKDTM) += lkdtm.o 13obj-$(CONFIG_LKDTM) += lkdtm.o
12obj-$(CONFIG_TIFM_CORE) += tifm_core.o 14obj-$(CONFIG_TIFM_CORE) += tifm_core.o
13obj-$(CONFIG_TIFM_7XX1) += tifm_7xx1.o 15obj-$(CONFIG_TIFM_7XX1) += tifm_7xx1.o
@@ -17,3 +19,4 @@ obj-$(CONFIG_SONY_LAPTOP) += sony-laptop.o
17obj-$(CONFIG_THINKPAD_ACPI) += thinkpad_acpi.o 19obj-$(CONFIG_THINKPAD_ACPI) += thinkpad_acpi.o
18obj-$(CONFIG_FUJITSU_LAPTOP) += fujitsu-laptop.o 20obj-$(CONFIG_FUJITSU_LAPTOP) += fujitsu-laptop.o
19obj-$(CONFIG_EEPROM_93CX6) += eeprom_93cx6.o 21obj-$(CONFIG_EEPROM_93CX6) += eeprom_93cx6.o
22obj-$(CONFIG_INTEL_MENLOW) += intel_menlow.o
diff --git a/drivers/misc/acer-wmi.c b/drivers/misc/acer-wmi.c
new file mode 100644
index 000000000000..a4d677504250
--- /dev/null
+++ b/drivers/misc/acer-wmi.c
@@ -0,0 +1,1109 @@
1/*
2 * Acer WMI Laptop Extras
3 *
4 * Copyright (C) 2007-2008 Carlos Corbacho <carlos@strangeworlds.co.uk>
5 *
6 * Based on acer_acpi:
7 * Copyright (C) 2005-2007 E.M. Smith
8 * Copyright (C) 2007-2008 Carlos Corbacho <cathectic@gmail.com>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 */
24
25#define ACER_WMI_VERSION "0.1"
26
27#include <linux/kernel.h>
28#include <linux/module.h>
29#include <linux/init.h>
30#include <linux/types.h>
31#include <linux/dmi.h>
32#include <linux/backlight.h>
33#include <linux/leds.h>
34#include <linux/platform_device.h>
35#include <linux/acpi.h>
36#include <linux/i8042.h>
37
38#include <acpi/acpi_drivers.h>
39
40MODULE_AUTHOR("Carlos Corbacho");
41MODULE_DESCRIPTION("Acer Laptop WMI Extras Driver");
42MODULE_LICENSE("GPL");
43
44#define ACER_LOGPREFIX "acer-wmi: "
45#define ACER_ERR KERN_ERR ACER_LOGPREFIX
46#define ACER_NOTICE KERN_NOTICE ACER_LOGPREFIX
47#define ACER_INFO KERN_INFO ACER_LOGPREFIX
48
49/*
50 * The following defines quirks to get some specific functions to work
51 * which are known to not be supported over ACPI-WMI (such as the mail LED
52 * on WMID based Acer's)
53 */
54struct acer_quirks {
55 const char *vendor;
56 const char *model;
57 u16 quirks;
58};
59
60/*
61 * Magic Number
62 * Meaning is unknown - this number is required for writing to ACPI for AMW0
63 * (it's also used in acerhk when directly accessing the BIOS)
64 */
65#define ACER_AMW0_WRITE 0x9610
66
67/*
68 * Bit masks for the AMW0 interface
69 */
70#define ACER_AMW0_WIRELESS_MASK 0x35
71#define ACER_AMW0_BLUETOOTH_MASK 0x34
72#define ACER_AMW0_MAILLED_MASK 0x31
73
74/*
75 * Method IDs for WMID interface
76 */
77#define ACER_WMID_GET_WIRELESS_METHODID 1
78#define ACER_WMID_GET_BLUETOOTH_METHODID 2
79#define ACER_WMID_GET_BRIGHTNESS_METHODID 3
80#define ACER_WMID_SET_WIRELESS_METHODID 4
81#define ACER_WMID_SET_BLUETOOTH_METHODID 5
82#define ACER_WMID_SET_BRIGHTNESS_METHODID 6
83#define ACER_WMID_GET_THREEG_METHODID 10
84#define ACER_WMID_SET_THREEG_METHODID 11
85
86/*
87 * Acer ACPI method GUIDs
88 */
89#define AMW0_GUID1 "67C3371D-95A3-4C37-BB61-DD47B491DAAB"
90#define WMID_GUID1 "6AF4F258-B401-42fd-BE91-3D4AC2D7C0D3"
91#define WMID_GUID2 "95764E09-FB56-4e83-B31A-37761F60994A"
92
93MODULE_ALIAS("wmi:67C3371D-95A3-4C37-BB61-DD47B491DAAB");
94MODULE_ALIAS("wmi:6AF4F258-B401-42fd-BE91-3D4AC2D7C0D3");
95
96/* Temporary workaround until the WMI sysfs interface goes in */
97MODULE_ALIAS("dmi:*:*Acer*:*:");
98
99/*
100 * Interface capability flags
101 */
102#define ACER_CAP_MAILLED (1<<0)
103#define ACER_CAP_WIRELESS (1<<1)
104#define ACER_CAP_BLUETOOTH (1<<2)
105#define ACER_CAP_BRIGHTNESS (1<<3)
106#define ACER_CAP_THREEG (1<<4)
107#define ACER_CAP_ANY (0xFFFFFFFF)
108
109/*
110 * Interface type flags
111 */
112enum interface_flags {
113 ACER_AMW0,
114 ACER_AMW0_V2,
115 ACER_WMID,
116};
117
118#define ACER_DEFAULT_WIRELESS 0
119#define ACER_DEFAULT_BLUETOOTH 0
120#define ACER_DEFAULT_MAILLED 0
121#define ACER_DEFAULT_THREEG 0
122
123static int max_brightness = 0xF;
124
125static int wireless = -1;
126static int bluetooth = -1;
127static int mailled = -1;
128static int brightness = -1;
129static int threeg = -1;
130static int force_series;
131
132module_param(mailled, int, 0444);
133module_param(wireless, int, 0444);
134module_param(bluetooth, int, 0444);
135module_param(brightness, int, 0444);
136module_param(threeg, int, 0444);
137module_param(force_series, int, 0444);
138MODULE_PARM_DESC(wireless, "Set initial state of Wireless hardware");
139MODULE_PARM_DESC(bluetooth, "Set initial state of Bluetooth hardware");
140MODULE_PARM_DESC(mailled, "Set initial state of Mail LED");
141MODULE_PARM_DESC(brightness, "Set initial LCD backlight brightness");
142MODULE_PARM_DESC(threeg, "Set initial state of 3G hardware");
143MODULE_PARM_DESC(force_series, "Force a different laptop series");
144
145struct acer_data {
146 int mailled;
147 int wireless;
148 int bluetooth;
149 int threeg;
150 int brightness;
151};
152
153/* Each low-level interface must define at least some of the following */
154struct wmi_interface {
155 /* The WMI device type */
156 u32 type;
157
158 /* The capabilities this interface provides */
159 u32 capability;
160
161 /* Private data for the current interface */
162 struct acer_data data;
163};
164
165/* The static interface pointer, points to the currently detected interface */
166static struct wmi_interface *interface;
167
168/*
169 * Embedded Controller quirks
170 * Some laptops require us to directly access the EC to either enable or query
171 * features that are not available through WMI.
172 */
173
174struct quirk_entry {
175 u8 wireless;
176 u8 mailled;
177 u8 brightness;
178 u8 bluetooth;
179};
180
181static struct quirk_entry *quirks;
182
183static void set_quirks(void)
184{
185 if (quirks->mailled)
186 interface->capability |= ACER_CAP_MAILLED;
187
188 if (quirks->brightness)
189 interface->capability |= ACER_CAP_BRIGHTNESS;
190}
191
192static int dmi_matched(const struct dmi_system_id *dmi)
193{
194 quirks = dmi->driver_data;
195 return 0;
196}
197
198static struct quirk_entry quirk_unknown = {
199};
200
201static struct quirk_entry quirk_acer_travelmate_2490 = {
202 .mailled = 1,
203};
204
205/* This AMW0 laptop has no bluetooth */
206static struct quirk_entry quirk_medion_md_98300 = {
207 .wireless = 1,
208};
209
210static struct dmi_system_id acer_quirks[] = {
211 {
212 .callback = dmi_matched,
213 .ident = "Acer Aspire 3100",
214 .matches = {
215 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
216 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 3100"),
217 },
218 .driver_data = &quirk_acer_travelmate_2490,
219 },
220 {
221 .callback = dmi_matched,
222 .ident = "Acer Aspire 5100",
223 .matches = {
224 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
225 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5100"),
226 },
227 .driver_data = &quirk_acer_travelmate_2490,
228 },
229 {
230 .callback = dmi_matched,
231 .ident = "Acer Aspire 5630",
232 .matches = {
233 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
234 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5630"),
235 },
236 .driver_data = &quirk_acer_travelmate_2490,
237 },
238 {
239 .callback = dmi_matched,
240 .ident = "Acer Aspire 5650",
241 .matches = {
242 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
243 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5650"),
244 },
245 .driver_data = &quirk_acer_travelmate_2490,
246 },
247 {
248 .callback = dmi_matched,
249 .ident = "Acer Aspire 5680",
250 .matches = {
251 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
252 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5680"),
253 },
254 .driver_data = &quirk_acer_travelmate_2490,
255 },
256 {
257 .callback = dmi_matched,
258 .ident = "Acer Aspire 9110",
259 .matches = {
260 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
261 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 9110"),
262 },
263 .driver_data = &quirk_acer_travelmate_2490,
264 },
265 {
266 .callback = dmi_matched,
267 .ident = "Acer TravelMate 2490",
268 .matches = {
269 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
270 DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 2490"),
271 },
272 .driver_data = &quirk_acer_travelmate_2490,
273 },
274 {
275 .callback = dmi_matched,
276 .ident = "Medion MD 98300",
277 .matches = {
278 DMI_MATCH(DMI_SYS_VENDOR, "MEDION"),
279 DMI_MATCH(DMI_PRODUCT_NAME, "WAM2030"),
280 },
281 .driver_data = &quirk_medion_md_98300,
282 },
283 {}
284};
285
286/* Find which quirks are needed for a particular vendor/ model pair */
287static void find_quirks(void)
288{
289 if (!force_series) {
290 dmi_check_system(acer_quirks);
291 } else if (force_series == 2490) {
292 quirks = &quirk_acer_travelmate_2490;
293 }
294
295 if (quirks == NULL)
296 quirks = &quirk_unknown;
297
298 set_quirks();
299}
300
301/*
302 * General interface convenience methods
303 */
304
305static bool has_cap(u32 cap)
306{
307 if ((interface->capability & cap) != 0)
308 return 1;
309
310 return 0;
311}
312
313/*
314 * AMW0 (V1) interface
315 */
316struct wmab_args {
317 u32 eax;
318 u32 ebx;
319 u32 ecx;
320 u32 edx;
321};
322
323struct wmab_ret {
324 u32 eax;
325 u32 ebx;
326 u32 ecx;
327 u32 edx;
328 u32 eex;
329};
330
331static acpi_status wmab_execute(struct wmab_args *regbuf,
332struct acpi_buffer *result)
333{
334 struct acpi_buffer input;
335 acpi_status status;
336 input.length = sizeof(struct wmab_args);
337 input.pointer = (u8 *)regbuf;
338
339 status = wmi_evaluate_method(AMW0_GUID1, 1, 1, &input, result);
340
341 return status;
342}
343
344static acpi_status AMW0_get_u32(u32 *value, u32 cap,
345struct wmi_interface *iface)
346{
347 int err;
348 u8 result;
349
350 switch (cap) {
351 case ACER_CAP_MAILLED:
352 switch (quirks->mailled) {
353 default:
354 err = ec_read(0xA, &result);
355 if (err)
356 return AE_ERROR;
357 *value = (result >> 7) & 0x1;
358 return AE_OK;
359 }
360 break;
361 case ACER_CAP_WIRELESS:
362 switch (quirks->wireless) {
363 case 1:
364 err = ec_read(0x7B, &result);
365 if (err)
366 return AE_ERROR;
367 *value = result & 0x1;
368 return AE_OK;
369 default:
370 err = ec_read(0xA, &result);
371 if (err)
372 return AE_ERROR;
373 *value = (result >> 2) & 0x1;
374 return AE_OK;
375 }
376 break;
377 case ACER_CAP_BLUETOOTH:
378 switch (quirks->bluetooth) {
379 default:
380 err = ec_read(0xA, &result);
381 if (err)
382 return AE_ERROR;
383 *value = (result >> 4) & 0x1;
384 return AE_OK;
385 }
386 break;
387 case ACER_CAP_BRIGHTNESS:
388 switch (quirks->brightness) {
389 default:
390 err = ec_read(0x83, &result);
391 if (err)
392 return AE_ERROR;
393 *value = result;
394 return AE_OK;
395 }
396 break;
397 default:
398 return AE_BAD_ADDRESS;
399 }
400 return AE_OK;
401}
402
403static acpi_status AMW0_set_u32(u32 value, u32 cap, struct wmi_interface *iface)
404{
405 struct wmab_args args;
406
407 args.eax = ACER_AMW0_WRITE;
408 args.ebx = value ? (1<<8) : 0;
409 args.ecx = args.edx = 0;
410
411 switch (cap) {
412 case ACER_CAP_MAILLED:
413 if (value > 1)
414 return AE_BAD_PARAMETER;
415 args.ebx |= ACER_AMW0_MAILLED_MASK;
416 break;
417 case ACER_CAP_WIRELESS:
418 if (value > 1)
419 return AE_BAD_PARAMETER;
420 args.ebx |= ACER_AMW0_WIRELESS_MASK;
421 break;
422 case ACER_CAP_BLUETOOTH:
423 if (value > 1)
424 return AE_BAD_PARAMETER;
425 args.ebx |= ACER_AMW0_BLUETOOTH_MASK;
426 break;
427 case ACER_CAP_BRIGHTNESS:
428 if (value > max_brightness)
429 return AE_BAD_PARAMETER;
430 switch (quirks->brightness) {
431 case 1:
432 return ec_write(0x83, value);
433 default:
434 return AE_BAD_ADDRESS;
435 break;
436 }
437 default:
438 return AE_BAD_ADDRESS;
439 }
440
441 /* Actually do the set */
442 return wmab_execute(&args, NULL);
443}
444
445static acpi_status AMW0_find_mailled(void)
446{
447 struct wmab_args args;
448 struct wmab_ret ret;
449 acpi_status status = AE_OK;
450 struct acpi_buffer out = { ACPI_ALLOCATE_BUFFER, NULL };
451 union acpi_object *obj;
452
453 args.eax = 0x86;
454 args.ebx = args.ecx = args.edx = 0;
455
456 status = wmab_execute(&args, &out);
457 if (ACPI_FAILURE(status))
458 return status;
459
460 obj = (union acpi_object *) out.pointer;
461 if (obj && obj->type == ACPI_TYPE_BUFFER &&
462 obj->buffer.length == sizeof(struct wmab_ret)) {
463 ret = *((struct wmab_ret *) obj->buffer.pointer);
464 } else {
465 return AE_ERROR;
466 }
467
468 if (ret.eex & 0x1)
469 interface->capability |= ACER_CAP_MAILLED;
470
471 kfree(out.pointer);
472
473 return AE_OK;
474}
475
476static acpi_status AMW0_set_capabilities(void)
477{
478 struct wmab_args args;
479 struct wmab_ret ret;
480 acpi_status status = AE_OK;
481 struct acpi_buffer out = { ACPI_ALLOCATE_BUFFER, NULL };
482 union acpi_object *obj;
483
484 args.eax = ACER_AMW0_WRITE;
485 args.ecx = args.edx = 0;
486
487 args.ebx = 0xa2 << 8;
488 args.ebx |= ACER_AMW0_WIRELESS_MASK;
489
490 status = wmab_execute(&args, &out);
491 if (ACPI_FAILURE(status))
492 return status;
493
494 obj = (union acpi_object *) out.pointer;
495 if (obj && obj->type == ACPI_TYPE_BUFFER &&
496 obj->buffer.length == sizeof(struct wmab_ret)) {
497 ret = *((struct wmab_ret *) obj->buffer.pointer);
498 } else {
499 return AE_ERROR;
500 }
501
502 if (ret.eax & 0x1)
503 interface->capability |= ACER_CAP_WIRELESS;
504
505 args.ebx = 2 << 8;
506 args.ebx |= ACER_AMW0_BLUETOOTH_MASK;
507
508 status = wmab_execute(&args, &out);
509 if (ACPI_FAILURE(status))
510 return status;
511
512 obj = (union acpi_object *) out.pointer;
513 if (obj && obj->type == ACPI_TYPE_BUFFER
514 && obj->buffer.length == sizeof(struct wmab_ret)) {
515 ret = *((struct wmab_ret *) obj->buffer.pointer);
516 } else {
517 return AE_ERROR;
518 }
519
520 if (ret.eax & 0x1)
521 interface->capability |= ACER_CAP_BLUETOOTH;
522
523 kfree(out.pointer);
524
525 /*
526 * This appears to be safe to enable, since all Wistron based laptops
527 * appear to use the same EC register for brightness, even if they
528 * differ for wireless, etc
529 */
530 interface->capability |= ACER_CAP_BRIGHTNESS;
531
532 return AE_OK;
533}
534
535static struct wmi_interface AMW0_interface = {
536 .type = ACER_AMW0,
537};
538
539static struct wmi_interface AMW0_V2_interface = {
540 .type = ACER_AMW0_V2,
541};
542
543/*
544 * New interface (The WMID interface)
545 */
546static acpi_status
547WMI_execute_u32(u32 method_id, u32 in, u32 *out)
548{
549 struct acpi_buffer input = { (acpi_size) sizeof(u32), (void *)(&in) };
550 struct acpi_buffer result = { ACPI_ALLOCATE_BUFFER, NULL };
551 union acpi_object *obj;
552 u32 tmp;
553 acpi_status status;
554
555 status = wmi_evaluate_method(WMID_GUID1, 1, method_id, &input, &result);
556
557 if (ACPI_FAILURE(status))
558 return status;
559
560 obj = (union acpi_object *) result.pointer;
561 if (obj && obj->type == ACPI_TYPE_BUFFER &&
562 obj->buffer.length == sizeof(u32)) {
563 tmp = *((u32 *) obj->buffer.pointer);
564 } else {
565 tmp = 0;
566 }
567
568 if (out)
569 *out = tmp;
570
571 kfree(result.pointer);
572
573 return status;
574}
575
576static acpi_status WMID_get_u32(u32 *value, u32 cap,
577struct wmi_interface *iface)
578{
579 acpi_status status;
580 u8 tmp;
581 u32 result, method_id = 0;
582
583 switch (cap) {
584 case ACER_CAP_WIRELESS:
585 method_id = ACER_WMID_GET_WIRELESS_METHODID;
586 break;
587 case ACER_CAP_BLUETOOTH:
588 method_id = ACER_WMID_GET_BLUETOOTH_METHODID;
589 break;
590 case ACER_CAP_BRIGHTNESS:
591 method_id = ACER_WMID_GET_BRIGHTNESS_METHODID;
592 break;
593 case ACER_CAP_THREEG:
594 method_id = ACER_WMID_GET_THREEG_METHODID;
595 break;
596 case ACER_CAP_MAILLED:
597 if (quirks->mailled == 1) {
598 ec_read(0x9f, &tmp);
599 *value = tmp & 0x1;
600 return 0;
601 }
602 default:
603 return AE_BAD_ADDRESS;
604 }
605 status = WMI_execute_u32(method_id, 0, &result);
606
607 if (ACPI_SUCCESS(status))
608 *value = (u8)result;
609
610 return status;
611}
612
613static acpi_status WMID_set_u32(u32 value, u32 cap, struct wmi_interface *iface)
614{
615 u32 method_id = 0;
616 char param;
617
618 switch (cap) {
619 case ACER_CAP_BRIGHTNESS:
620 if (value > max_brightness)
621 return AE_BAD_PARAMETER;
622 method_id = ACER_WMID_SET_BRIGHTNESS_METHODID;
623 break;
624 case ACER_CAP_WIRELESS:
625 if (value > 1)
626 return AE_BAD_PARAMETER;
627 method_id = ACER_WMID_SET_WIRELESS_METHODID;
628 break;
629 case ACER_CAP_BLUETOOTH:
630 if (value > 1)
631 return AE_BAD_PARAMETER;
632 method_id = ACER_WMID_SET_BLUETOOTH_METHODID;
633 break;
634 case ACER_CAP_THREEG:
635 if (value > 1)
636 return AE_BAD_PARAMETER;
637 method_id = ACER_WMID_SET_THREEG_METHODID;
638 break;
639 case ACER_CAP_MAILLED:
640 if (value > 1)
641 return AE_BAD_PARAMETER;
642 if (quirks->mailled == 1) {
643 param = value ? 0x92 : 0x93;
644 i8042_command(&param, 0x1059);
645 return 0;
646 }
647 break;
648 default:
649 return AE_BAD_ADDRESS;
650 }
651 return WMI_execute_u32(method_id, (u32)value, NULL);
652}
653
654static acpi_status WMID_set_capabilities(void)
655{
656 struct acpi_buffer out = {ACPI_ALLOCATE_BUFFER, NULL};
657 union acpi_object *obj;
658 acpi_status status;
659 u32 devices;
660
661 status = wmi_query_block(WMID_GUID2, 1, &out);
662 if (ACPI_FAILURE(status))
663 return status;
664
665 obj = (union acpi_object *) out.pointer;
666 if (obj && obj->type == ACPI_TYPE_BUFFER &&
667 obj->buffer.length == sizeof(u32)) {
668 devices = *((u32 *) obj->buffer.pointer);
669 } else {
670 return AE_ERROR;
671 }
672
673 /* Not sure on the meaning of the relevant bits yet to detect these */
674 interface->capability |= ACER_CAP_WIRELESS;
675 interface->capability |= ACER_CAP_THREEG;
676
677 /* WMID always provides brightness methods */
678 interface->capability |= ACER_CAP_BRIGHTNESS;
679
680 if (devices & 0x10)
681 interface->capability |= ACER_CAP_BLUETOOTH;
682
683 if (!(devices & 0x20))
684 max_brightness = 0x9;
685
686 return status;
687}
688
689static struct wmi_interface wmid_interface = {
690 .type = ACER_WMID,
691};
692
693/*
694 * Generic Device (interface-independent)
695 */
696
697static acpi_status get_u32(u32 *value, u32 cap)
698{
699 acpi_status status = AE_BAD_ADDRESS;
700
701 switch (interface->type) {
702 case ACER_AMW0:
703 status = AMW0_get_u32(value, cap, interface);
704 break;
705 case ACER_AMW0_V2:
706 if (cap == ACER_CAP_MAILLED) {
707 status = AMW0_get_u32(value, cap, interface);
708 break;
709 }
710 case ACER_WMID:
711 status = WMID_get_u32(value, cap, interface);
712 break;
713 }
714
715 return status;
716}
717
718static acpi_status set_u32(u32 value, u32 cap)
719{
720 if (interface->capability & cap) {
721 switch (interface->type) {
722 case ACER_AMW0:
723 return AMW0_set_u32(value, cap, interface);
724 case ACER_AMW0_V2:
725 case ACER_WMID:
726 return WMID_set_u32(value, cap, interface);
727 default:
728 return AE_BAD_PARAMETER;
729 }
730 }
731 return AE_BAD_PARAMETER;
732}
733
734static void __init acer_commandline_init(void)
735{
736 /*
737 * These will all fail silently if the value given is invalid, or the
738 * capability isn't available on the given interface
739 */
740 set_u32(mailled, ACER_CAP_MAILLED);
741 set_u32(wireless, ACER_CAP_WIRELESS);
742 set_u32(bluetooth, ACER_CAP_BLUETOOTH);
743 set_u32(threeg, ACER_CAP_THREEG);
744 set_u32(brightness, ACER_CAP_BRIGHTNESS);
745}
746
747/*
748 * LED device (Mail LED only, no other LEDs known yet)
749 */
750static void mail_led_set(struct led_classdev *led_cdev,
751enum led_brightness value)
752{
753 set_u32(value, ACER_CAP_MAILLED);
754}
755
756static struct led_classdev mail_led = {
757 .name = "acer-mail:green",
758 .brightness_set = mail_led_set,
759};
760
761static int __init acer_led_init(struct device *dev)
762{
763 return led_classdev_register(dev, &mail_led);
764}
765
766static void acer_led_exit(void)
767{
768 led_classdev_unregister(&mail_led);
769}
770
771/*
772 * Backlight device
773 */
774static struct backlight_device *acer_backlight_device;
775
776static int read_brightness(struct backlight_device *bd)
777{
778 u32 value;
779 get_u32(&value, ACER_CAP_BRIGHTNESS);
780 return value;
781}
782
783static int update_bl_status(struct backlight_device *bd)
784{
785 set_u32(bd->props.brightness, ACER_CAP_BRIGHTNESS);
786 return 0;
787}
788
789static struct backlight_ops acer_bl_ops = {
790 .get_brightness = read_brightness,
791 .update_status = update_bl_status,
792};
793
794static int __init acer_backlight_init(struct device *dev)
795{
796 struct backlight_device *bd;
797
798 bd = backlight_device_register("acer-wmi", dev, NULL, &acer_bl_ops);
799 if (IS_ERR(bd)) {
800 printk(ACER_ERR "Could not register Acer backlight device\n");
801 acer_backlight_device = NULL;
802 return PTR_ERR(bd);
803 }
804
805 acer_backlight_device = bd;
806
807 bd->props.max_brightness = max_brightness;
808 bd->props.brightness = read_brightness(NULL);
809 backlight_update_status(bd);
810 return 0;
811}
812
813static void __exit acer_backlight_exit(void)
814{
815 backlight_device_unregister(acer_backlight_device);
816}
817
818/*
819 * Read/ write bool sysfs macro
820 */
821#define show_set_bool(value, cap) \
822static ssize_t \
823show_bool_##value(struct device *dev, struct device_attribute *attr, \
824 char *buf) \
825{ \
826 u32 result; \
827 acpi_status status = get_u32(&result, cap); \
828 if (ACPI_SUCCESS(status)) \
829 return sprintf(buf, "%u\n", result); \
830 return sprintf(buf, "Read error\n"); \
831} \
832\
833static ssize_t \
834set_bool_##value(struct device *dev, struct device_attribute *attr, \
835 const char *buf, size_t count) \
836{ \
837 u32 tmp = simple_strtoul(buf, NULL, 10); \
838 acpi_status status = set_u32(tmp, cap); \
839 if (ACPI_FAILURE(status)) \
840 return -EINVAL; \
841 return count; \
842} \
843static DEVICE_ATTR(value, S_IWUGO | S_IRUGO | S_IWUSR, \
844 show_bool_##value, set_bool_##value);
845
846show_set_bool(wireless, ACER_CAP_WIRELESS);
847show_set_bool(bluetooth, ACER_CAP_BLUETOOTH);
848show_set_bool(threeg, ACER_CAP_THREEG);
849
850/*
851 * Read interface sysfs macro
852 */
853static ssize_t show_interface(struct device *dev, struct device_attribute *attr,
854 char *buf)
855{
856 switch (interface->type) {
857 case ACER_AMW0:
858 return sprintf(buf, "AMW0\n");
859 case ACER_AMW0_V2:
860 return sprintf(buf, "AMW0 v2\n");
861 case ACER_WMID:
862 return sprintf(buf, "WMID\n");
863 default:
864 return sprintf(buf, "Error!\n");
865 }
866}
867
868static DEVICE_ATTR(interface, S_IWUGO | S_IRUGO | S_IWUSR,
869 show_interface, NULL);
870
871/*
872 * Platform device
873 */
874static int __devinit acer_platform_probe(struct platform_device *device)
875{
876 int err;
877
878 if (has_cap(ACER_CAP_MAILLED)) {
879 err = acer_led_init(&device->dev);
880 if (err)
881 goto error_mailled;
882 }
883
884 if (has_cap(ACER_CAP_BRIGHTNESS)) {
885 err = acer_backlight_init(&device->dev);
886 if (err)
887 goto error_brightness;
888 }
889
890 return 0;
891
892error_brightness:
893 acer_led_exit();
894error_mailled:
895 return err;
896}
897
898static int acer_platform_remove(struct platform_device *device)
899{
900 if (has_cap(ACER_CAP_MAILLED))
901 acer_led_exit();
902 if (has_cap(ACER_CAP_BRIGHTNESS))
903 acer_backlight_exit();
904 return 0;
905}
906
907static int acer_platform_suspend(struct platform_device *dev,
908pm_message_t state)
909{
910 u32 value;
911 struct acer_data *data = &interface->data;
912
913 if (!data)
914 return -ENOMEM;
915
916 if (has_cap(ACER_CAP_WIRELESS)) {
917 get_u32(&value, ACER_CAP_WIRELESS);
918 data->wireless = value;
919 }
920
921 if (has_cap(ACER_CAP_BLUETOOTH)) {
922 get_u32(&value, ACER_CAP_BLUETOOTH);
923 data->bluetooth = value;
924 }
925
926 if (has_cap(ACER_CAP_MAILLED)) {
927 get_u32(&value, ACER_CAP_MAILLED);
928 data->mailled = value;
929 }
930
931 if (has_cap(ACER_CAP_BRIGHTNESS)) {
932 get_u32(&value, ACER_CAP_BRIGHTNESS);
933 data->brightness = value;
934 }
935
936 return 0;
937}
938
939static int acer_platform_resume(struct platform_device *device)
940{
941 struct acer_data *data = &interface->data;
942
943 if (!data)
944 return -ENOMEM;
945
946 if (has_cap(ACER_CAP_WIRELESS))
947 set_u32(data->wireless, ACER_CAP_WIRELESS);
948
949 if (has_cap(ACER_CAP_BLUETOOTH))
950 set_u32(data->bluetooth, ACER_CAP_BLUETOOTH);
951
952 if (has_cap(ACER_CAP_THREEG))
953 set_u32(data->threeg, ACER_CAP_THREEG);
954
955 if (has_cap(ACER_CAP_MAILLED))
956 set_u32(data->mailled, ACER_CAP_MAILLED);
957
958 if (has_cap(ACER_CAP_BRIGHTNESS))
959 set_u32(data->brightness, ACER_CAP_BRIGHTNESS);
960
961 return 0;
962}
963
964static struct platform_driver acer_platform_driver = {
965 .driver = {
966 .name = "acer-wmi",
967 .owner = THIS_MODULE,
968 },
969 .probe = acer_platform_probe,
970 .remove = acer_platform_remove,
971 .suspend = acer_platform_suspend,
972 .resume = acer_platform_resume,
973};
974
975static struct platform_device *acer_platform_device;
976
977static int remove_sysfs(struct platform_device *device)
978{
979 if (has_cap(ACER_CAP_WIRELESS))
980 device_remove_file(&device->dev, &dev_attr_wireless);
981
982 if (has_cap(ACER_CAP_BLUETOOTH))
983 device_remove_file(&device->dev, &dev_attr_bluetooth);
984
985 if (has_cap(ACER_CAP_THREEG))
986 device_remove_file(&device->dev, &dev_attr_threeg);
987
988 device_remove_file(&device->dev, &dev_attr_interface);
989
990 return 0;
991}
992
993static int create_sysfs(void)
994{
995 int retval = -ENOMEM;
996
997 if (has_cap(ACER_CAP_WIRELESS)) {
998 retval = device_create_file(&acer_platform_device->dev,
999 &dev_attr_wireless);
1000 if (retval)
1001 goto error_sysfs;
1002 }
1003
1004 if (has_cap(ACER_CAP_BLUETOOTH)) {
1005 retval = device_create_file(&acer_platform_device->dev,
1006 &dev_attr_bluetooth);
1007 if (retval)
1008 goto error_sysfs;
1009 }
1010
1011 if (has_cap(ACER_CAP_THREEG)) {
1012 retval = device_create_file(&acer_platform_device->dev,
1013 &dev_attr_threeg);
1014 if (retval)
1015 goto error_sysfs;
1016 }
1017
1018 retval = device_create_file(&acer_platform_device->dev,
1019 &dev_attr_interface);
1020 if (retval)
1021 goto error_sysfs;
1022
1023 return 0;
1024
1025error_sysfs:
1026 remove_sysfs(acer_platform_device);
1027 return retval;
1028}
1029
1030static int __init acer_wmi_init(void)
1031{
1032 int err;
1033
1034 printk(ACER_INFO "Acer Laptop ACPI-WMI Extras version %s\n",
1035 ACER_WMI_VERSION);
1036
1037 /*
1038 * Detect which ACPI-WMI interface we're using.
1039 */
1040 if (wmi_has_guid(AMW0_GUID1) && wmi_has_guid(WMID_GUID1))
1041 interface = &AMW0_V2_interface;
1042
1043 if (!wmi_has_guid(AMW0_GUID1) && wmi_has_guid(WMID_GUID1))
1044 interface = &wmid_interface;
1045
1046 if (wmi_has_guid(WMID_GUID2) && interface) {
1047 if (ACPI_FAILURE(WMID_set_capabilities())) {
1048 printk(ACER_ERR "Unable to detect available devices\n");
1049 return -ENODEV;
1050 }
1051 } else if (!wmi_has_guid(WMID_GUID2) && interface) {
1052 printk(ACER_ERR "Unable to detect available devices\n");
1053 return -ENODEV;
1054 }
1055
1056 if (wmi_has_guid(AMW0_GUID1) && !wmi_has_guid(WMID_GUID1)) {
1057 interface = &AMW0_interface;
1058
1059 if (ACPI_FAILURE(AMW0_set_capabilities())) {
1060 printk(ACER_ERR "Unable to detect available devices\n");
1061 return -ENODEV;
1062 }
1063 }
1064
1065 if (wmi_has_guid(AMW0_GUID1)) {
1066 if (ACPI_FAILURE(AMW0_find_mailled()))
1067 printk(ACER_ERR "Unable to detect mail LED\n");
1068 }
1069
1070 find_quirks();
1071
1072 if (!interface) {
1073 printk(ACER_ERR "No or unsupported WMI interface, unable to ");
1074 printk(KERN_CONT "load.\n");
1075 return -ENODEV;
1076 }
1077
1078 if (platform_driver_register(&acer_platform_driver)) {
1079 printk(ACER_ERR "Unable to register platform driver.\n");
1080 goto error_platform_register;
1081 }
1082 acer_platform_device = platform_device_alloc("acer-wmi", -1);
1083 platform_device_add(acer_platform_device);
1084
1085 err = create_sysfs();
1086 if (err)
1087 return err;
1088
1089 /* Override any initial settings with values from the commandline */
1090 acer_commandline_init();
1091
1092 return 0;
1093
1094error_platform_register:
1095 return -ENODEV;
1096}
1097
1098static void __exit acer_wmi_exit(void)
1099{
1100 remove_sysfs(acer_platform_device);
1101 platform_device_del(acer_platform_device);
1102 platform_driver_unregister(&acer_platform_driver);
1103
1104 printk(ACER_INFO "Acer Laptop WMI Extras unloaded\n");
1105 return;
1106}
1107
1108module_init(acer_wmi_init);
1109module_exit(acer_wmi_exit);
diff --git a/drivers/misc/asus-laptop.c b/drivers/misc/asus-laptop.c
index 3a36a294e91b..7c6dfd03de9f 100644
--- a/drivers/misc/asus-laptop.c
+++ b/drivers/misc/asus-laptop.c
@@ -254,7 +254,7 @@ ASUS_LED(gled, "gaming");
254 * method is searched within the scope of the handle, can be NULL. The output 254 * method is searched within the scope of the handle, can be NULL. The output
255 * of the method is written is output, which can also be NULL 255 * of the method is written is output, which can also be NULL
256 * 256 *
257 * returns 1 if write is successful, 0 else. 257 * returns 0 if write is successful, -1 else.
258 */ 258 */
259static int write_acpi_int(acpi_handle handle, const char *method, int val, 259static int write_acpi_int(acpi_handle handle, const char *method, int val,
260 struct acpi_buffer *output) 260 struct acpi_buffer *output)
@@ -263,13 +263,19 @@ static int write_acpi_int(acpi_handle handle, const char *method, int val,
263 union acpi_object in_obj; //the only param we use 263 union acpi_object in_obj; //the only param we use
264 acpi_status status; 264 acpi_status status;
265 265
266 if (!handle)
267 return 0;
268
266 params.count = 1; 269 params.count = 1;
267 params.pointer = &in_obj; 270 params.pointer = &in_obj;
268 in_obj.type = ACPI_TYPE_INTEGER; 271 in_obj.type = ACPI_TYPE_INTEGER;
269 in_obj.integer.value = val; 272 in_obj.integer.value = val;
270 273
271 status = acpi_evaluate_object(handle, (char *)method, &params, output); 274 status = acpi_evaluate_object(handle, (char *)method, &params, output);
272 return (status == AE_OK); 275 if (status == AE_OK)
276 return 0;
277 else
278 return -1;
273} 279}
274 280
275static int read_wireless_status(int mask) 281static int read_wireless_status(int mask)
@@ -321,7 +327,7 @@ static void write_status(acpi_handle handle, int out, int mask)
321 327
322 switch (mask) { 328 switch (mask) {
323 case MLED_ON: 329 case MLED_ON:
324 out = !out & 0x1; 330 out = !(out & 0x1);
325 break; 331 break;
326 case GLED_ON: 332 case GLED_ON:
327 out = (out & 0x1) + 1; 333 out = (out & 0x1) + 1;
@@ -335,7 +341,7 @@ static void write_status(acpi_handle handle, int out, int mask)
335 break; 341 break;
336 } 342 }
337 343
338 if (handle && !write_acpi_int(handle, NULL, out, NULL)) 344 if (write_acpi_int(handle, NULL, out, NULL))
339 printk(ASUS_WARNING " write failed %x\n", mask); 345 printk(ASUS_WARNING " write failed %x\n", mask);
340} 346}
341 347
@@ -415,7 +421,7 @@ static int set_brightness(struct backlight_device *bd, int value)
415 value = (0 < value) ? ((15 < value) ? 15 : value) : 0; 421 value = (0 < value) ? ((15 < value) ? 15 : value) : 0;
416 /* 0 <= value <= 15 */ 422 /* 0 <= value <= 15 */
417 423
418 if (!write_acpi_int(brightness_set_handle, NULL, value, NULL)) { 424 if (write_acpi_int(brightness_set_handle, NULL, value, NULL)) {
419 printk(ASUS_WARNING "Error changing brightness\n"); 425 printk(ASUS_WARNING "Error changing brightness\n");
420 ret = -EIO; 426 ret = -EIO;
421 } 427 }
@@ -545,7 +551,7 @@ static ssize_t store_ledd(struct device *dev, struct device_attribute *attr,
545 551
546 rv = parse_arg(buf, count, &value); 552 rv = parse_arg(buf, count, &value);
547 if (rv > 0) { 553 if (rv > 0) {
548 if (!write_acpi_int(ledd_set_handle, NULL, value, NULL)) 554 if (write_acpi_int(ledd_set_handle, NULL, value, NULL))
549 printk(ASUS_WARNING "LED display write failed\n"); 555 printk(ASUS_WARNING "LED display write failed\n");
550 else 556 else
551 hotk->ledd_status = (u32) value; 557 hotk->ledd_status = (u32) value;
@@ -590,7 +596,7 @@ static ssize_t store_bluetooth(struct device *dev,
590static void set_display(int value) 596static void set_display(int value)
591{ 597{
592 /* no sanity check needed for now */ 598 /* no sanity check needed for now */
593 if (!write_acpi_int(display_set_handle, NULL, value, NULL)) 599 if (write_acpi_int(display_set_handle, NULL, value, NULL))
594 printk(ASUS_WARNING "Error setting display\n"); 600 printk(ASUS_WARNING "Error setting display\n");
595 return; 601 return;
596} 602}
@@ -647,7 +653,7 @@ static ssize_t store_disp(struct device *dev, struct device_attribute *attr,
647 */ 653 */
648static void set_light_sens_switch(int value) 654static void set_light_sens_switch(int value)
649{ 655{
650 if (!write_acpi_int(ls_switch_handle, NULL, value, NULL)) 656 if (write_acpi_int(ls_switch_handle, NULL, value, NULL))
651 printk(ASUS_WARNING "Error setting light sensor switch\n"); 657 printk(ASUS_WARNING "Error setting light sensor switch\n");
652 hotk->light_switch = value; 658 hotk->light_switch = value;
653} 659}
@@ -672,7 +678,7 @@ static ssize_t store_lssw(struct device *dev, struct device_attribute *attr,
672 678
673static void set_light_sens_level(int value) 679static void set_light_sens_level(int value)
674{ 680{
675 if (!write_acpi_int(ls_level_handle, NULL, value, NULL)) 681 if (write_acpi_int(ls_level_handle, NULL, value, NULL))
676 printk(ASUS_WARNING "Error setting light sensor level\n"); 682 printk(ASUS_WARNING "Error setting light sensor level\n");
677 hotk->light_level = value; 683 hotk->light_level = value;
678} 684}
@@ -860,7 +866,7 @@ static int asus_hotk_get_info(void)
860 printk(ASUS_WARNING "Couldn't get the DSDT table header\n"); 866 printk(ASUS_WARNING "Couldn't get the DSDT table header\n");
861 867
862 /* We have to write 0 on init this far for all ASUS models */ 868 /* We have to write 0 on init this far for all ASUS models */
863 if (!write_acpi_int(hotk->handle, "INIT", 0, &buffer)) { 869 if (write_acpi_int(hotk->handle, "INIT", 0, &buffer)) {
864 printk(ASUS_ERR "Hotkey initialization failed\n"); 870 printk(ASUS_ERR "Hotkey initialization failed\n");
865 return -ENODEV; 871 return -ENODEV;
866 } 872 }
diff --git a/drivers/misc/intel_menlow.c b/drivers/misc/intel_menlow.c
new file mode 100644
index 000000000000..f70984ab1e1b
--- /dev/null
+++ b/drivers/misc/intel_menlow.c
@@ -0,0 +1,526 @@
1/*
2 * intel_menlow.c - Intel menlow Driver for thermal management extension
3 *
4 * Copyright (C) 2008 Intel Corp
5 * Copyright (C) 2008 Sujith Thomas <sujith.thomas@intel.com>
6 * Copyright (C) 2008 Zhang Rui <rui.zhang@intel.com>
7 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; version 2 of the License.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
21 *
22 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
23 *
24 * This driver creates the sys I/F for programming the sensors.
25 * It also implements the driver for intel menlow memory controller (hardware
26 * id is INT0002) which makes use of the platform specific ACPI methods
27 * to get/set bandwidth.
28 */
29
30#include <linux/kernel.h>
31#include <linux/module.h>
32#include <linux/init.h>
33#include <linux/types.h>
34#include <linux/pci.h>
35#include <linux/pm.h>
36
37#include <linux/thermal.h>
38#include <acpi/acpi_bus.h>
39#include <acpi/acpi_drivers.h>
40
41MODULE_AUTHOR("Thomas Sujith");
42MODULE_AUTHOR("Zhang Rui");
43MODULE_DESCRIPTION("Intel Menlow platform specific driver");
44MODULE_LICENSE("GPL");
45
46/*
47 * Memory controller device control
48 */
49
50#define MEMORY_GET_BANDWIDTH "GTHS"
51#define MEMORY_SET_BANDWIDTH "STHS"
52#define MEMORY_ARG_CUR_BANDWIDTH 1
53#define MEMORY_ARG_MAX_BANDWIDTH 0
54
55static int memory_get_int_max_bandwidth(struct thermal_cooling_device *cdev,
56 unsigned long *max_state)
57{
58 struct acpi_device *device = cdev->devdata;
59 acpi_handle handle = device->handle;
60 unsigned long value;
61 struct acpi_object_list arg_list;
62 union acpi_object arg;
63 acpi_status status = AE_OK;
64
65 arg_list.count = 1;
66 arg_list.pointer = &arg;
67 arg.type = ACPI_TYPE_INTEGER;
68 arg.integer.value = MEMORY_ARG_MAX_BANDWIDTH;
69 status = acpi_evaluate_integer(handle, MEMORY_GET_BANDWIDTH,
70 &arg_list, &value);
71 if (ACPI_FAILURE(status))
72 return -EFAULT;
73
74 *max_state = value - 1;
75 return 0;
76}
77
78static int memory_get_max_bandwidth(struct thermal_cooling_device *cdev,
79 char *buf)
80{
81 unsigned long value;
82 if (memory_get_int_max_bandwidth(cdev, &value))
83 return -EINVAL;
84
85 return sprintf(buf, "%ld\n", value);
86}
87
88static int memory_get_cur_bandwidth(struct thermal_cooling_device *cdev,
89 char *buf)
90{
91 struct acpi_device *device = cdev->devdata;
92 acpi_handle handle = device->handle;
93 unsigned long value;
94 struct acpi_object_list arg_list;
95 union acpi_object arg;
96 acpi_status status = AE_OK;
97
98 arg_list.count = 1;
99 arg_list.pointer = &arg;
100 arg.type = ACPI_TYPE_INTEGER;
101 arg.integer.value = MEMORY_ARG_CUR_BANDWIDTH;
102 status = acpi_evaluate_integer(handle, MEMORY_GET_BANDWIDTH,
103 &arg_list, &value);
104 if (ACPI_FAILURE(status))
105 return -EFAULT;
106
107 return sprintf(buf, "%ld\n", value);
108}
109
110static int memory_set_cur_bandwidth(struct thermal_cooling_device *cdev,
111 unsigned int state)
112{
113 struct acpi_device *device = cdev->devdata;
114 acpi_handle handle = device->handle;
115 struct acpi_object_list arg_list;
116 union acpi_object arg;
117 acpi_status status;
118 int temp;
119 unsigned long max_state;
120
121 if (memory_get_int_max_bandwidth(cdev, &max_state))
122 return -EFAULT;
123
124 if (max_state < 0 || state > max_state)
125 return -EINVAL;
126
127 arg_list.count = 1;
128 arg_list.pointer = &arg;
129 arg.type = ACPI_TYPE_INTEGER;
130 arg.integer.value = state;
131
132 status =
133 acpi_evaluate_integer(handle, MEMORY_SET_BANDWIDTH, &arg_list,
134 (unsigned long *)&temp);
135
136 printk(KERN_INFO
137 "Bandwidth value was %d: status is %d\n", state, status);
138 if (ACPI_FAILURE(status))
139 return -EFAULT;
140
141 return 0;
142}
143
144static struct thermal_cooling_device_ops memory_cooling_ops = {
145 .get_max_state = memory_get_max_bandwidth,
146 .get_cur_state = memory_get_cur_bandwidth,
147 .set_cur_state = memory_set_cur_bandwidth,
148};
149
150/*
151 * Memory Device Management
152 */
153static int intel_menlow_memory_add(struct acpi_device *device)
154{
155 int result = -ENODEV;
156 acpi_status status = AE_OK;
157 acpi_handle dummy;
158 struct thermal_cooling_device *cdev;
159
160 if (!device)
161 return -EINVAL;
162
163 status = acpi_get_handle(device->handle, MEMORY_GET_BANDWIDTH, &dummy);
164 if (ACPI_FAILURE(status))
165 goto end;
166
167 status = acpi_get_handle(device->handle, MEMORY_SET_BANDWIDTH, &dummy);
168 if (ACPI_FAILURE(status))
169 goto end;
170
171 cdev = thermal_cooling_device_register("Memory controller", device,
172 &memory_cooling_ops);
173 acpi_driver_data(device) = cdev;
174 if (!cdev)
175 result = -ENODEV;
176 else {
177 result = sysfs_create_link(&device->dev.kobj,
178 &cdev->device.kobj, "thermal_cooling");
179 if (result)
180 goto unregister;
181
182 result = sysfs_create_link(&cdev->device.kobj,
183 &device->dev.kobj, "device");
184 if (result) {
185 sysfs_remove_link(&device->dev.kobj, "thermal_cooling");
186 goto unregister;
187 }
188 }
189
190 end:
191 return result;
192
193 unregister:
194 thermal_cooling_device_unregister(cdev);
195 return result;
196
197}
198
199static int intel_menlow_memory_remove(struct acpi_device *device, int type)
200{
201 struct thermal_cooling_device *cdev = acpi_driver_data(device);
202
203 if (!device || !cdev)
204 return -EINVAL;
205
206 sysfs_remove_link(&device->dev.kobj, "thermal_cooling");
207 sysfs_remove_link(&cdev->device.kobj, "device");
208 thermal_cooling_device_unregister(cdev);
209
210 return 0;
211}
212
213const static struct acpi_device_id intel_menlow_memory_ids[] = {
214 {"INT0002", 0},
215 {"", 0},
216};
217
218static struct acpi_driver intel_menlow_memory_driver = {
219 .name = "intel_menlow_thermal_control",
220 .ids = intel_menlow_memory_ids,
221 .ops = {
222 .add = intel_menlow_memory_add,
223 .remove = intel_menlow_memory_remove,
224 },
225};
226
227/*
228 * Sensor control on menlow platform
229 */
230
231#define THERMAL_AUX0 0
232#define THERMAL_AUX1 1
233#define GET_AUX0 "GAX0"
234#define GET_AUX1 "GAX1"
235#define SET_AUX0 "SAX0"
236#define SET_AUX1 "SAX1"
237
238struct intel_menlow_attribute {
239 struct device_attribute attr;
240 struct device *device;
241 acpi_handle handle;
242 struct list_head node;
243};
244
245static LIST_HEAD(intel_menlow_attr_list);
246static DEFINE_MUTEX(intel_menlow_attr_lock);
247
248/*
249 * sensor_get_auxtrip - get the current auxtrip value from sensor
250 * @name: Thermalzone name
251 * @auxtype : AUX0/AUX1
252 * @buf: syfs buffer
253 */
254static int sensor_get_auxtrip(acpi_handle handle, int index, int *value)
255{
256 acpi_status status;
257
258 if ((index != 0 && index != 1) || !value)
259 return -EINVAL;
260
261 status = acpi_evaluate_integer(handle, index ? GET_AUX1 : GET_AUX0,
262 NULL, (unsigned long *)value);
263 if (ACPI_FAILURE(status))
264 return -EIO;
265
266 return 0;
267}
268
269/*
270 * sensor_set_auxtrip - set the new auxtrip value to sensor
271 * @name: Thermalzone name
272 * @auxtype : AUX0/AUX1
273 * @buf: syfs buffer
274 */
275static int sensor_set_auxtrip(acpi_handle handle, int index, int value)
276{
277 acpi_status status;
278 union acpi_object arg = {
279 ACPI_TYPE_INTEGER
280 };
281 struct acpi_object_list args = {
282 1, &arg
283 };
284 int temp;
285
286 if (index != 0 && index != 1)
287 return -EINVAL;
288
289 status = acpi_evaluate_integer(handle, index ? GET_AUX0 : GET_AUX1,
290 NULL, (unsigned long *)&temp);
291 if (ACPI_FAILURE(status))
292 return -EIO;
293 if ((index && value < temp) || (!index && value > temp))
294 return -EINVAL;
295
296 arg.integer.value = value;
297 status = acpi_evaluate_integer(handle, index ? SET_AUX1 : SET_AUX0,
298 &args, (unsigned long *)&temp);
299 if (ACPI_FAILURE(status))
300 return -EIO;
301
302 /* do we need to check the return value of SAX0/SAX1 ? */
303
304 return 0;
305}
306
307#define to_intel_menlow_attr(_attr) \
308 container_of(_attr, struct intel_menlow_attribute, attr)
309
310static ssize_t aux0_show(struct device *dev,
311 struct device_attribute *dev_attr, char *buf)
312{
313 struct intel_menlow_attribute *attr = to_intel_menlow_attr(dev_attr);
314 int value;
315 int result;
316
317 result = sensor_get_auxtrip(attr->handle, 0, &value);
318
319 return result ? result : sprintf(buf, "%lu", KELVIN_TO_CELSIUS(value));
320}
321
322static ssize_t aux1_show(struct device *dev,
323 struct device_attribute *dev_attr, char *buf)
324{
325 struct intel_menlow_attribute *attr = to_intel_menlow_attr(dev_attr);
326 int value;
327 int result;
328
329 result = sensor_get_auxtrip(attr->handle, 1, &value);
330
331 return result ? result : sprintf(buf, "%lu", KELVIN_TO_CELSIUS(value));
332}
333
334static ssize_t aux0_store(struct device *dev,
335 struct device_attribute *dev_attr,
336 const char *buf, size_t count)
337{
338 struct intel_menlow_attribute *attr = to_intel_menlow_attr(dev_attr);
339 int value;
340 int result;
341
342 /*Sanity check; should be a positive integer */
343 if (!sscanf(buf, "%d", &value))
344 return -EINVAL;
345
346 if (value < 0)
347 return -EINVAL;
348
349 result = sensor_set_auxtrip(attr->handle, 0, CELSIUS_TO_KELVIN(value));
350 return result ? result : count;
351}
352
353static ssize_t aux1_store(struct device *dev,
354 struct device_attribute *dev_attr,
355 const char *buf, size_t count)
356{
357 struct intel_menlow_attribute *attr = to_intel_menlow_attr(dev_attr);
358 int value;
359 int result;
360
361 /*Sanity check; should be a positive integer */
362 if (!sscanf(buf, "%d", &value))
363 return -EINVAL;
364
365 if (value < 0)
366 return -EINVAL;
367
368 result = sensor_set_auxtrip(attr->handle, 1, CELSIUS_TO_KELVIN(value));
369 return result ? result : count;
370}
371
372/* BIOS can enable/disable the thermal user application in dabney platform */
373#define BIOS_ENABLED "\\_TZ.GSTS"
374static ssize_t bios_enabled_show(struct device *dev,
375 struct device_attribute *attr, char *buf)
376{
377 acpi_status status;
378 unsigned long bios_enabled;
379
380 status = acpi_evaluate_integer(NULL, BIOS_ENABLED, NULL, &bios_enabled);
381 if (ACPI_FAILURE(status))
382 return -ENODEV;
383
384 return sprintf(buf, "%s\n", bios_enabled ? "enabled" : "disabled");
385}
386
387static int intel_menlow_add_one_attribute(char *name, int mode, void *show,
388 void *store, struct device *dev,
389 acpi_handle handle)
390{
391 struct intel_menlow_attribute *attr;
392 int result;
393
394 attr = kzalloc(sizeof(struct intel_menlow_attribute), GFP_KERNEL);
395 if (!attr)
396 return -ENOMEM;
397
398 attr->attr.attr.name = name;
399 attr->attr.attr.mode = mode;
400 attr->attr.show = show;
401 attr->attr.store = store;
402 attr->device = dev;
403 attr->handle = handle;
404
405 result = device_create_file(dev, &attr->attr);
406 if (result)
407 return result;
408
409 mutex_lock(&intel_menlow_attr_lock);
410 list_add_tail(&attr->node, &intel_menlow_attr_list);
411 mutex_unlock(&intel_menlow_attr_lock);
412
413 return 0;
414}
415
416static acpi_status intel_menlow_register_sensor(acpi_handle handle, u32 lvl,
417 void *context, void **rv)
418{
419 acpi_status status;
420 acpi_handle dummy;
421 struct thermal_zone_device *thermal;
422 int result;
423
424 result = acpi_bus_get_private_data(handle, (void **)&thermal);
425 if (result)
426 return 0;
427
428 /* _TZ must have the AUX0/1 methods */
429 status = acpi_get_handle(handle, GET_AUX0, &dummy);
430 if (ACPI_FAILURE(status))
431 goto not_found;
432
433 status = acpi_get_handle(handle, SET_AUX0, &dummy);
434 if (ACPI_FAILURE(status))
435 goto not_found;
436
437 result = intel_menlow_add_one_attribute("aux0", 0644,
438 aux0_show, aux0_store,
439 &thermal->device, handle);
440 if (result)
441 return AE_ERROR;
442
443 status = acpi_get_handle(handle, GET_AUX1, &dummy);
444 if (ACPI_FAILURE(status))
445 goto not_found;
446
447 status = acpi_get_handle(handle, SET_AUX1, &dummy);
448 if (ACPI_FAILURE(status))
449 goto not_found;
450
451 result = intel_menlow_add_one_attribute("aux1", 0644,
452 aux1_show, aux1_store,
453 &thermal->device, handle);
454 if (result)
455 return AE_ERROR;
456
457 /*
458 * create the "dabney_enabled" attribute which means the user app
459 * should be loaded or not
460 */
461
462 result = intel_menlow_add_one_attribute("bios_enabled", 0444,
463 bios_enabled_show, NULL,
464 &thermal->device, handle);
465 if (result)
466 return AE_ERROR;
467
468 not_found:
469 if (status == AE_NOT_FOUND)
470 return AE_OK;
471 else
472 return status;
473}
474
475static void intel_menlow_unregister_sensor(void)
476{
477 struct intel_menlow_attribute *pos, *next;
478
479 mutex_lock(&intel_menlow_attr_lock);
480 list_for_each_entry_safe(pos, next, &intel_menlow_attr_list, node) {
481 list_del(&pos->node);
482 device_remove_file(pos->device, &pos->attr);
483 kfree(pos);
484 }
485 mutex_unlock(&intel_menlow_attr_lock);
486
487 return;
488}
489
490static int __init intel_menlow_module_init(void)
491{
492 int result = -ENODEV;
493 acpi_status status;
494 unsigned long enable;
495
496 if (acpi_disabled)
497 return result;
498
499 /* Looking for the \_TZ.GSTS method */
500 status = acpi_evaluate_integer(NULL, BIOS_ENABLED, NULL, &enable);
501 if (ACPI_FAILURE(status) || !enable)
502 return -ENODEV;
503
504 /* Looking for ACPI device MEM0 with hardware id INT0002 */
505 result = acpi_bus_register_driver(&intel_menlow_memory_driver);
506 if (result)
507 return result;
508
509 /* Looking for sensors in each ACPI thermal zone */
510 status = acpi_walk_namespace(ACPI_TYPE_THERMAL, ACPI_ROOT_OBJECT,
511 ACPI_UINT32_MAX,
512 intel_menlow_register_sensor, NULL, NULL);
513 if (ACPI_FAILURE(status))
514 return -ENODEV;
515
516 return 0;
517}
518
519static void __exit intel_menlow_module_exit(void)
520{
521 acpi_bus_unregister_driver(&intel_menlow_memory_driver);
522 intel_menlow_unregister_sensor();
523}
524
525module_init(intel_menlow_module_init);
526module_exit(intel_menlow_module_exit);
diff --git a/drivers/misc/sony-laptop.c b/drivers/misc/sony-laptop.c
index b0f68031b49d..899e3f75f288 100644
--- a/drivers/misc/sony-laptop.c
+++ b/drivers/misc/sony-laptop.c
@@ -73,7 +73,7 @@
73 if (debug) printk(KERN_WARNING DRV_PFX msg); \ 73 if (debug) printk(KERN_WARNING DRV_PFX msg); \
74} while (0) 74} while (0)
75 75
76#define SONY_LAPTOP_DRIVER_VERSION "0.5" 76#define SONY_LAPTOP_DRIVER_VERSION "0.6"
77 77
78#define SONY_NC_CLASS "sony-nc" 78#define SONY_NC_CLASS "sony-nc"
79#define SONY_NC_HID "SNY5001" 79#define SONY_NC_HID "SNY5001"
@@ -146,68 +146,70 @@ struct sony_laptop_keypress {
146 * and input layer indexes in the keymap 146 * and input layer indexes in the keymap
147 */ 147 */
148static int sony_laptop_input_index[] = { 148static int sony_laptop_input_index[] = {
149 -1, /* no event */ 149 -1, /* 0 no event */
150 -1, /* SONYPI_EVENT_JOGDIAL_DOWN */ 150 -1, /* 1 SONYPI_EVENT_JOGDIAL_DOWN */
151 -1, /* SONYPI_EVENT_JOGDIAL_UP */ 151 -1, /* 2 SONYPI_EVENT_JOGDIAL_UP */
152 -1, /* SONYPI_EVENT_JOGDIAL_DOWN_PRESSED */ 152 -1, /* 3 SONYPI_EVENT_JOGDIAL_DOWN_PRESSED */
153 -1, /* SONYPI_EVENT_JOGDIAL_UP_PRESSED */ 153 -1, /* 4 SONYPI_EVENT_JOGDIAL_UP_PRESSED */
154 -1, /* SONYPI_EVENT_JOGDIAL_PRESSED */ 154 -1, /* 5 SONYPI_EVENT_JOGDIAL_PRESSED */
155 -1, /* SONYPI_EVENT_JOGDIAL_RELEASED */ 155 -1, /* 6 SONYPI_EVENT_JOGDIAL_RELEASED */
156 0, /* SONYPI_EVENT_CAPTURE_PRESSED */ 156 0, /* 7 SONYPI_EVENT_CAPTURE_PRESSED */
157 1, /* SONYPI_EVENT_CAPTURE_RELEASED */ 157 1, /* 8 SONYPI_EVENT_CAPTURE_RELEASED */
158 2, /* SONYPI_EVENT_CAPTURE_PARTIALPRESSED */ 158 2, /* 9 SONYPI_EVENT_CAPTURE_PARTIALPRESSED */
159 3, /* SONYPI_EVENT_CAPTURE_PARTIALRELEASED */ 159 3, /* 10 SONYPI_EVENT_CAPTURE_PARTIALRELEASED */
160 4, /* SONYPI_EVENT_FNKEY_ESC */ 160 4, /* 11 SONYPI_EVENT_FNKEY_ESC */
161 5, /* SONYPI_EVENT_FNKEY_F1 */ 161 5, /* 12 SONYPI_EVENT_FNKEY_F1 */
162 6, /* SONYPI_EVENT_FNKEY_F2 */ 162 6, /* 13 SONYPI_EVENT_FNKEY_F2 */
163 7, /* SONYPI_EVENT_FNKEY_F3 */ 163 7, /* 14 SONYPI_EVENT_FNKEY_F3 */
164 8, /* SONYPI_EVENT_FNKEY_F4 */ 164 8, /* 15 SONYPI_EVENT_FNKEY_F4 */
165 9, /* SONYPI_EVENT_FNKEY_F5 */ 165 9, /* 16 SONYPI_EVENT_FNKEY_F5 */
166 10, /* SONYPI_EVENT_FNKEY_F6 */ 166 10, /* 17 SONYPI_EVENT_FNKEY_F6 */
167 11, /* SONYPI_EVENT_FNKEY_F7 */ 167 11, /* 18 SONYPI_EVENT_FNKEY_F7 */
168 12, /* SONYPI_EVENT_FNKEY_F8 */ 168 12, /* 19 SONYPI_EVENT_FNKEY_F8 */
169 13, /* SONYPI_EVENT_FNKEY_F9 */ 169 13, /* 20 SONYPI_EVENT_FNKEY_F9 */
170 14, /* SONYPI_EVENT_FNKEY_F10 */ 170 14, /* 21 SONYPI_EVENT_FNKEY_F10 */
171 15, /* SONYPI_EVENT_FNKEY_F11 */ 171 15, /* 22 SONYPI_EVENT_FNKEY_F11 */
172 16, /* SONYPI_EVENT_FNKEY_F12 */ 172 16, /* 23 SONYPI_EVENT_FNKEY_F12 */
173 17, /* SONYPI_EVENT_FNKEY_1 */ 173 17, /* 24 SONYPI_EVENT_FNKEY_1 */
174 18, /* SONYPI_EVENT_FNKEY_2 */ 174 18, /* 25 SONYPI_EVENT_FNKEY_2 */
175 19, /* SONYPI_EVENT_FNKEY_D */ 175 19, /* 26 SONYPI_EVENT_FNKEY_D */
176 20, /* SONYPI_EVENT_FNKEY_E */ 176 20, /* 27 SONYPI_EVENT_FNKEY_E */
177 21, /* SONYPI_EVENT_FNKEY_F */ 177 21, /* 28 SONYPI_EVENT_FNKEY_F */
178 22, /* SONYPI_EVENT_FNKEY_S */ 178 22, /* 29 SONYPI_EVENT_FNKEY_S */
179 23, /* SONYPI_EVENT_FNKEY_B */ 179 23, /* 30 SONYPI_EVENT_FNKEY_B */
180 24, /* SONYPI_EVENT_BLUETOOTH_PRESSED */ 180 24, /* 31 SONYPI_EVENT_BLUETOOTH_PRESSED */
181 25, /* SONYPI_EVENT_PKEY_P1 */ 181 25, /* 32 SONYPI_EVENT_PKEY_P1 */
182 26, /* SONYPI_EVENT_PKEY_P2 */ 182 26, /* 33 SONYPI_EVENT_PKEY_P2 */
183 27, /* SONYPI_EVENT_PKEY_P3 */ 183 27, /* 34 SONYPI_EVENT_PKEY_P3 */
184 28, /* SONYPI_EVENT_BACK_PRESSED */ 184 28, /* 35 SONYPI_EVENT_BACK_PRESSED */
185 -1, /* SONYPI_EVENT_LID_CLOSED */ 185 -1, /* 36 SONYPI_EVENT_LID_CLOSED */
186 -1, /* SONYPI_EVENT_LID_OPENED */ 186 -1, /* 37 SONYPI_EVENT_LID_OPENED */
187 29, /* SONYPI_EVENT_BLUETOOTH_ON */ 187 29, /* 38 SONYPI_EVENT_BLUETOOTH_ON */
188 30, /* SONYPI_EVENT_BLUETOOTH_OFF */ 188 30, /* 39 SONYPI_EVENT_BLUETOOTH_OFF */
189 31, /* SONYPI_EVENT_HELP_PRESSED */ 189 31, /* 40 SONYPI_EVENT_HELP_PRESSED */
190 32, /* SONYPI_EVENT_FNKEY_ONLY */ 190 32, /* 41 SONYPI_EVENT_FNKEY_ONLY */
191 33, /* SONYPI_EVENT_JOGDIAL_FAST_DOWN */ 191 33, /* 42 SONYPI_EVENT_JOGDIAL_FAST_DOWN */
192 34, /* SONYPI_EVENT_JOGDIAL_FAST_UP */ 192 34, /* 43 SONYPI_EVENT_JOGDIAL_FAST_UP */
193 35, /* SONYPI_EVENT_JOGDIAL_FAST_DOWN_PRESSED */ 193 35, /* 44 SONYPI_EVENT_JOGDIAL_FAST_DOWN_PRESSED */
194 36, /* SONYPI_EVENT_JOGDIAL_FAST_UP_PRESSED */ 194 36, /* 45 SONYPI_EVENT_JOGDIAL_FAST_UP_PRESSED */
195 37, /* SONYPI_EVENT_JOGDIAL_VFAST_DOWN */ 195 37, /* 46 SONYPI_EVENT_JOGDIAL_VFAST_DOWN */
196 38, /* SONYPI_EVENT_JOGDIAL_VFAST_UP */ 196 38, /* 47 SONYPI_EVENT_JOGDIAL_VFAST_UP */
197 39, /* SONYPI_EVENT_JOGDIAL_VFAST_DOWN_PRESSED */ 197 39, /* 48 SONYPI_EVENT_JOGDIAL_VFAST_DOWN_PRESSED */
198 40, /* SONYPI_EVENT_JOGDIAL_VFAST_UP_PRESSED */ 198 40, /* 49 SONYPI_EVENT_JOGDIAL_VFAST_UP_PRESSED */
199 41, /* SONYPI_EVENT_ZOOM_PRESSED */ 199 41, /* 50 SONYPI_EVENT_ZOOM_PRESSED */
200 42, /* SONYPI_EVENT_THUMBPHRASE_PRESSED */ 200 42, /* 51 SONYPI_EVENT_THUMBPHRASE_PRESSED */
201 43, /* SONYPI_EVENT_MEYE_FACE */ 201 43, /* 52 SONYPI_EVENT_MEYE_FACE */
202 44, /* SONYPI_EVENT_MEYE_OPPOSITE */ 202 44, /* 53 SONYPI_EVENT_MEYE_OPPOSITE */
203 45, /* SONYPI_EVENT_MEMORYSTICK_INSERT */ 203 45, /* 54 SONYPI_EVENT_MEMORYSTICK_INSERT */
204 46, /* SONYPI_EVENT_MEMORYSTICK_EJECT */ 204 46, /* 55 SONYPI_EVENT_MEMORYSTICK_EJECT */
205 -1, /* SONYPI_EVENT_ANYBUTTON_RELEASED */ 205 -1, /* 56 SONYPI_EVENT_ANYBUTTON_RELEASED */
206 -1, /* SONYPI_EVENT_BATTERY_INSERT */ 206 -1, /* 57 SONYPI_EVENT_BATTERY_INSERT */
207 -1, /* SONYPI_EVENT_BATTERY_REMOVE */ 207 -1, /* 58 SONYPI_EVENT_BATTERY_REMOVE */
208 -1, /* SONYPI_EVENT_FNKEY_RELEASED */ 208 -1, /* 59 SONYPI_EVENT_FNKEY_RELEASED */
209 47, /* SONYPI_EVENT_WIRELESS_ON */ 209 47, /* 60 SONYPI_EVENT_WIRELESS_ON */
210 48, /* SONYPI_EVENT_WIRELESS_OFF */ 210 48, /* 61 SONYPI_EVENT_WIRELESS_OFF */
211 49, /* 62 SONYPI_EVENT_ZOOM_IN_PRESSED */
212 50, /* 63 SONYPI_EVENT_ZOOM_OUT_PRESSED */
211}; 213};
212 214
213static int sony_laptop_input_keycode_map[] = { 215static int sony_laptop_input_keycode_map[] = {
@@ -260,6 +262,8 @@ static int sony_laptop_input_keycode_map[] = {
260 KEY_RESERVED, /* 46 SONYPI_EVENT_MEMORYSTICK_EJECT */ 262 KEY_RESERVED, /* 46 SONYPI_EVENT_MEMORYSTICK_EJECT */
261 KEY_WLAN, /* 47 SONYPI_EVENT_WIRELESS_ON */ 263 KEY_WLAN, /* 47 SONYPI_EVENT_WIRELESS_ON */
262 KEY_WLAN, /* 48 SONYPI_EVENT_WIRELESS_OFF */ 264 KEY_WLAN, /* 48 SONYPI_EVENT_WIRELESS_OFF */
265 KEY_ZOOMIN, /* 49 SONYPI_EVENT_ZOOM_IN_PRESSED */
266 KEY_ZOOMOUT /* 50 SONYPI_EVENT_ZOOM_OUT_PRESSED */
263}; 267};
264 268
265/* release buttons after a short delay if pressed */ 269/* release buttons after a short delay if pressed */
@@ -311,7 +315,7 @@ static void sony_laptop_report_input_event(u8 event)
311 break; 315 break;
312 316
313 default: 317 default:
314 if (event > ARRAY_SIZE (sony_laptop_input_keycode_map)) { 318 if (event > ARRAY_SIZE(sony_laptop_input_index)) {
315 dprintk("sony_laptop_report_input_event, event not known: %d\n", event); 319 dprintk("sony_laptop_report_input_event, event not known: %d\n", event);
316 break; 320 break;
317 } 321 }
@@ -875,6 +879,15 @@ static const struct dmi_system_id sony_nc_ids[] = {
875 DMI_MATCH(DMI_PRODUCT_NAME, "VGN-C"), 879 DMI_MATCH(DMI_PRODUCT_NAME, "VGN-C"),
876 }, 880 },
877 }, 881 },
882 {
883 .ident = "Sony Vaio N Series",
884 .callback = sony_nc_C_enable,
885 .driver_data = sony_C_events,
886 .matches = {
887 DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
888 DMI_MATCH(DMI_PRODUCT_NAME, "VGN-N"),
889 },
890 },
878 { } 891 { }
879}; 892};
880 893
@@ -1169,10 +1182,12 @@ static struct acpi_driver sony_nc_driver = {
1169#define SONYPI_DEVICE_TYPE1 0x00000001 1182#define SONYPI_DEVICE_TYPE1 0x00000001
1170#define SONYPI_DEVICE_TYPE2 0x00000002 1183#define SONYPI_DEVICE_TYPE2 0x00000002
1171#define SONYPI_DEVICE_TYPE3 0x00000004 1184#define SONYPI_DEVICE_TYPE3 0x00000004
1185#define SONYPI_DEVICE_TYPE4 0x00000008
1172 1186
1173#define SONYPI_TYPE1_OFFSET 0x04 1187#define SONYPI_TYPE1_OFFSET 0x04
1174#define SONYPI_TYPE2_OFFSET 0x12 1188#define SONYPI_TYPE2_OFFSET 0x12
1175#define SONYPI_TYPE3_OFFSET 0x12 1189#define SONYPI_TYPE3_OFFSET 0x12
1190#define SONYPI_TYPE4_OFFSET 0x12
1176 1191
1177struct sony_pic_ioport { 1192struct sony_pic_ioport {
1178 struct acpi_resource_io io1; 1193 struct acpi_resource_io io1;
@@ -1185,18 +1200,33 @@ struct sony_pic_irq {
1185 struct list_head list; 1200 struct list_head list;
1186}; 1201};
1187 1202
1203struct sonypi_eventtypes {
1204 u8 data;
1205 unsigned long mask;
1206 struct sonypi_event *events;
1207};
1208
1209struct device_ctrl {
1210 int model;
1211 int (*handle_irq)(const u8, const u8);
1212 u16 evport_offset;
1213 u8 has_camera;
1214 u8 has_bluetooth;
1215 u8 has_wwan;
1216 struct sonypi_eventtypes *event_types;
1217};
1218
1188struct sony_pic_dev { 1219struct sony_pic_dev {
1189 int model; 1220 struct device_ctrl *control;
1190 u16 evport_offset;
1191 u8 camera_power;
1192 u8 bluetooth_power;
1193 u8 wwan_power;
1194 struct acpi_device *acpi_dev; 1221 struct acpi_device *acpi_dev;
1195 struct sony_pic_irq *cur_irq; 1222 struct sony_pic_irq *cur_irq;
1196 struct sony_pic_ioport *cur_ioport; 1223 struct sony_pic_ioport *cur_ioport;
1197 struct list_head interrupts; 1224 struct list_head interrupts;
1198 struct list_head ioports; 1225 struct list_head ioports;
1199 struct mutex lock; 1226 struct mutex lock;
1227 u8 camera_power;
1228 u8 bluetooth_power;
1229 u8 wwan_power;
1200}; 1230};
1201 1231
1202static struct sony_pic_dev spic_dev = { 1232static struct sony_pic_dev spic_dev = {
@@ -1253,6 +1283,7 @@ static struct sonypi_event sonypi_joggerev[] = {
1253static struct sonypi_event sonypi_captureev[] = { 1283static struct sonypi_event sonypi_captureev[] = {
1254 { 0x05, SONYPI_EVENT_CAPTURE_PARTIALPRESSED }, 1284 { 0x05, SONYPI_EVENT_CAPTURE_PARTIALPRESSED },
1255 { 0x07, SONYPI_EVENT_CAPTURE_PRESSED }, 1285 { 0x07, SONYPI_EVENT_CAPTURE_PRESSED },
1286 { 0x40, SONYPI_EVENT_CAPTURE_PRESSED },
1256 { 0x01, SONYPI_EVENT_CAPTURE_PARTIALRELEASED }, 1287 { 0x01, SONYPI_EVENT_CAPTURE_PARTIALRELEASED },
1257 { 0, 0 } 1288 { 0, 0 }
1258}; 1289};
@@ -1289,7 +1320,6 @@ static struct sonypi_event sonypi_pkeyev[] = {
1289 { 0x01, SONYPI_EVENT_PKEY_P1 }, 1320 { 0x01, SONYPI_EVENT_PKEY_P1 },
1290 { 0x02, SONYPI_EVENT_PKEY_P2 }, 1321 { 0x02, SONYPI_EVENT_PKEY_P2 },
1291 { 0x04, SONYPI_EVENT_PKEY_P3 }, 1322 { 0x04, SONYPI_EVENT_PKEY_P3 },
1292 { 0x5c, SONYPI_EVENT_PKEY_P1 },
1293 { 0, 0 } 1323 { 0, 0 }
1294}; 1324};
1295 1325
@@ -1331,6 +1361,8 @@ static struct sonypi_event sonypi_lidev[] = {
1331/* The set of possible zoom events */ 1361/* The set of possible zoom events */
1332static struct sonypi_event sonypi_zoomev[] = { 1362static struct sonypi_event sonypi_zoomev[] = {
1333 { 0x39, SONYPI_EVENT_ZOOM_PRESSED }, 1363 { 0x39, SONYPI_EVENT_ZOOM_PRESSED },
1364 { 0x10, SONYPI_EVENT_ZOOM_IN_PRESSED },
1365 { 0x20, SONYPI_EVENT_ZOOM_OUT_PRESSED },
1334 { 0, 0 } 1366 { 0, 0 }
1335}; 1367};
1336 1368
@@ -1361,76 +1393,58 @@ static struct sonypi_event sonypi_batteryev[] = {
1361 { 0, 0 } 1393 { 0, 0 }
1362}; 1394};
1363 1395
1364static struct sonypi_eventtypes { 1396static struct sonypi_eventtypes type1_events[] = {
1365 int model; 1397 { 0, 0xffffffff, sonypi_releaseev },
1366 u8 data; 1398 { 0x70, SONYPI_MEYE_MASK, sonypi_meyeev },
1367 unsigned long mask; 1399 { 0x30, SONYPI_LID_MASK, sonypi_lidev },
1368 struct sonypi_event * events; 1400 { 0x60, SONYPI_CAPTURE_MASK, sonypi_captureev },
1369} sony_pic_eventtypes[] = { 1401 { 0x10, SONYPI_JOGGER_MASK, sonypi_joggerev },
1370 { SONYPI_DEVICE_TYPE1, 0, 0xffffffff, sonypi_releaseev }, 1402 { 0x20, SONYPI_FNKEY_MASK, sonypi_fnkeyev },
1371 { SONYPI_DEVICE_TYPE1, 0x70, SONYPI_MEYE_MASK, sonypi_meyeev }, 1403 { 0x30, SONYPI_BLUETOOTH_MASK, sonypi_blueev },
1372 { SONYPI_DEVICE_TYPE1, 0x30, SONYPI_LID_MASK, sonypi_lidev }, 1404 { 0x40, SONYPI_PKEY_MASK, sonypi_pkeyev },
1373 { SONYPI_DEVICE_TYPE1, 0x60, SONYPI_CAPTURE_MASK, sonypi_captureev }, 1405 { 0x30, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev },
1374 { SONYPI_DEVICE_TYPE1, 0x10, SONYPI_JOGGER_MASK, sonypi_joggerev }, 1406 { 0x40, SONYPI_BATTERY_MASK, sonypi_batteryev },
1375 { SONYPI_DEVICE_TYPE1, 0x20, SONYPI_FNKEY_MASK, sonypi_fnkeyev }, 1407 { 0 },
1376 { SONYPI_DEVICE_TYPE1, 0x30, SONYPI_BLUETOOTH_MASK, sonypi_blueev }, 1408};
1377 { SONYPI_DEVICE_TYPE1, 0x40, SONYPI_PKEY_MASK, sonypi_pkeyev }, 1409static struct sonypi_eventtypes type2_events[] = {
1378 { SONYPI_DEVICE_TYPE1, 0x30, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev }, 1410 { 0, 0xffffffff, sonypi_releaseev },
1379 { SONYPI_DEVICE_TYPE1, 0x40, SONYPI_BATTERY_MASK, sonypi_batteryev }, 1411 { 0x38, SONYPI_LID_MASK, sonypi_lidev },
1380 1412 { 0x11, SONYPI_JOGGER_MASK, sonypi_joggerev },
1381 { SONYPI_DEVICE_TYPE2, 0, 0xffffffff, sonypi_releaseev }, 1413 { 0x61, SONYPI_CAPTURE_MASK, sonypi_captureev },
1382 { SONYPI_DEVICE_TYPE2, 0x38, SONYPI_LID_MASK, sonypi_lidev }, 1414 { 0x21, SONYPI_FNKEY_MASK, sonypi_fnkeyev },
1383 { SONYPI_DEVICE_TYPE2, 0x11, SONYPI_JOGGER_MASK, sonypi_joggerev }, 1415 { 0x31, SONYPI_BLUETOOTH_MASK, sonypi_blueev },
1384 { SONYPI_DEVICE_TYPE2, 0x61, SONYPI_CAPTURE_MASK, sonypi_captureev }, 1416 { 0x08, SONYPI_PKEY_MASK, sonypi_pkeyev },
1385 { SONYPI_DEVICE_TYPE2, 0x21, SONYPI_FNKEY_MASK, sonypi_fnkeyev }, 1417 { 0x11, SONYPI_BACK_MASK, sonypi_backev },
1386 { SONYPI_DEVICE_TYPE2, 0x31, SONYPI_BLUETOOTH_MASK, sonypi_blueev }, 1418 { 0x21, SONYPI_HELP_MASK, sonypi_helpev },
1387 { SONYPI_DEVICE_TYPE2, 0x08, SONYPI_PKEY_MASK, sonypi_pkeyev }, 1419 { 0x21, SONYPI_ZOOM_MASK, sonypi_zoomev },
1388 { SONYPI_DEVICE_TYPE2, 0x11, SONYPI_BACK_MASK, sonypi_backev }, 1420 { 0x20, SONYPI_THUMBPHRASE_MASK, sonypi_thumbphraseev },
1389 { SONYPI_DEVICE_TYPE2, 0x21, SONYPI_HELP_MASK, sonypi_helpev }, 1421 { 0x31, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev },
1390 { SONYPI_DEVICE_TYPE2, 0x21, SONYPI_ZOOM_MASK, sonypi_zoomev }, 1422 { 0x41, SONYPI_BATTERY_MASK, sonypi_batteryev },
1391 { SONYPI_DEVICE_TYPE2, 0x20, SONYPI_THUMBPHRASE_MASK, sonypi_thumbphraseev }, 1423 { 0x31, SONYPI_PKEY_MASK, sonypi_pkeyev },
1392 { SONYPI_DEVICE_TYPE2, 0x31, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev }, 1424 { 0 },
1393 { SONYPI_DEVICE_TYPE2, 0x41, SONYPI_BATTERY_MASK, sonypi_batteryev }, 1425};
1394 { SONYPI_DEVICE_TYPE2, 0x31, SONYPI_PKEY_MASK, sonypi_pkeyev }, 1426static struct sonypi_eventtypes type3_events[] = {
1395 1427 { 0, 0xffffffff, sonypi_releaseev },
1396 { SONYPI_DEVICE_TYPE3, 0, 0xffffffff, sonypi_releaseev }, 1428 { 0x21, SONYPI_FNKEY_MASK, sonypi_fnkeyev },
1397 { SONYPI_DEVICE_TYPE3, 0x21, SONYPI_FNKEY_MASK, sonypi_fnkeyev }, 1429 { 0x31, SONYPI_WIRELESS_MASK, sonypi_wlessev },
1398 { SONYPI_DEVICE_TYPE3, 0x31, SONYPI_WIRELESS_MASK, sonypi_wlessev }, 1430 { 0x31, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev },
1399 { SONYPI_DEVICE_TYPE3, 0x31, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev }, 1431 { 0x41, SONYPI_BATTERY_MASK, sonypi_batteryev },
1400 { SONYPI_DEVICE_TYPE3, 0x41, SONYPI_BATTERY_MASK, sonypi_batteryev }, 1432 { 0x31, SONYPI_PKEY_MASK, sonypi_pkeyev },
1401 { SONYPI_DEVICE_TYPE3, 0x31, SONYPI_PKEY_MASK, sonypi_pkeyev }, 1433 { 0 },
1402 { 0 } 1434};
1435static struct sonypi_eventtypes type4_events[] = {
1436 { 0, 0xffffffff, sonypi_releaseev },
1437 { 0x21, SONYPI_FNKEY_MASK, sonypi_fnkeyev },
1438 { 0x31, SONYPI_WIRELESS_MASK, sonypi_wlessev },
1439 { 0x31, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev },
1440 { 0x41, SONYPI_BATTERY_MASK, sonypi_batteryev },
1441 { 0x05, SONYPI_PKEY_MASK, sonypi_pkeyev },
1442 { 0x05, SONYPI_ZOOM_MASK, sonypi_zoomev },
1443 { 0x05, SONYPI_CAPTURE_MASK, sonypi_captureev },
1444 { 0 },
1403}; 1445};
1404 1446
1405static int sony_pic_detect_device_type(void) 1447/* low level spic calls */
1406{
1407 struct pci_dev *pcidev;
1408 int model = 0;
1409
1410 if ((pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
1411 PCI_DEVICE_ID_INTEL_82371AB_3, NULL)))
1412 model = SONYPI_DEVICE_TYPE1;
1413
1414 else if ((pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
1415 PCI_DEVICE_ID_INTEL_ICH6_1, NULL)))
1416 model = SONYPI_DEVICE_TYPE3;
1417
1418 else if ((pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
1419 PCI_DEVICE_ID_INTEL_ICH7_1, NULL)))
1420 model = SONYPI_DEVICE_TYPE3;
1421
1422 else
1423 model = SONYPI_DEVICE_TYPE2;
1424
1425 if (pcidev)
1426 pci_dev_put(pcidev);
1427
1428 printk(KERN_INFO DRV_PFX "detected Type%d model\n",
1429 model == SONYPI_DEVICE_TYPE1 ? 1 :
1430 model == SONYPI_DEVICE_TYPE2 ? 2 : 3);
1431 return model;
1432}
1433
1434#define ITERATIONS_LONG 10000 1448#define ITERATIONS_LONG 10000
1435#define ITERATIONS_SHORT 10 1449#define ITERATIONS_SHORT 10
1436#define wait_on_command(command, iterations) { \ 1450#define wait_on_command(command, iterations) { \
@@ -1451,7 +1465,7 @@ static u8 sony_pic_call1(u8 dev)
1451 outb(dev, spic_dev.cur_ioport->io1.minimum + 4); 1465 outb(dev, spic_dev.cur_ioport->io1.minimum + 4);
1452 v1 = inb_p(spic_dev.cur_ioport->io1.minimum + 4); 1466 v1 = inb_p(spic_dev.cur_ioport->io1.minimum + 4);
1453 v2 = inb_p(spic_dev.cur_ioport->io1.minimum); 1467 v2 = inb_p(spic_dev.cur_ioport->io1.minimum);
1454 dprintk("sony_pic_call1: 0x%.4x\n", (v2 << 8) | v1); 1468 dprintk("sony_pic_call1(0x%.2x): 0x%.4x\n", dev, (v2 << 8) | v1);
1455 return v2; 1469 return v2;
1456} 1470}
1457 1471
@@ -1466,7 +1480,7 @@ static u8 sony_pic_call2(u8 dev, u8 fn)
1466 ITERATIONS_LONG); 1480 ITERATIONS_LONG);
1467 outb(fn, spic_dev.cur_ioport->io1.minimum); 1481 outb(fn, spic_dev.cur_ioport->io1.minimum);
1468 v1 = inb_p(spic_dev.cur_ioport->io1.minimum); 1482 v1 = inb_p(spic_dev.cur_ioport->io1.minimum);
1469 dprintk("sony_pic_call2: 0x%.4x\n", v1); 1483 dprintk("sony_pic_call2(0x%.2x - 0x%.2x): 0x%.4x\n", dev, fn, v1);
1470 return v1; 1484 return v1;
1471} 1485}
1472 1486
@@ -1481,10 +1495,105 @@ static u8 sony_pic_call3(u8 dev, u8 fn, u8 v)
1481 wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2, ITERATIONS_LONG); 1495 wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2, ITERATIONS_LONG);
1482 outb(v, spic_dev.cur_ioport->io1.minimum); 1496 outb(v, spic_dev.cur_ioport->io1.minimum);
1483 v1 = inb_p(spic_dev.cur_ioport->io1.minimum); 1497 v1 = inb_p(spic_dev.cur_ioport->io1.minimum);
1484 dprintk("sony_pic_call3: 0x%.4x\n", v1); 1498 dprintk("sony_pic_call3(0x%.2x - 0x%.2x - 0x%.2x): 0x%.4x\n",
1499 dev, fn, v, v1);
1485 return v1; 1500 return v1;
1486} 1501}
1487 1502
1503/*
1504 * minidrivers for SPIC models
1505 */
1506static int type4_handle_irq(const u8 data_mask, const u8 ev)
1507{
1508 /*
1509 * 0x31 could mean we have to take some extra action and wait for
1510 * the next irq for some Type4 models, it will generate a new
1511 * irq and we can read new data from the device:
1512 * - 0x5c and 0x5f requires 0xA0
1513 * - 0x61 requires 0xB3
1514 */
1515 if (data_mask == 0x31) {
1516 if (ev == 0x5c || ev == 0x5f)
1517 sony_pic_call1(0xA0);
1518 else if (ev == 0x61)
1519 sony_pic_call1(0xB3);
1520 return 0;
1521 }
1522 return 1;
1523}
1524
1525static struct device_ctrl spic_types[] = {
1526 {
1527 .model = SONYPI_DEVICE_TYPE1,
1528 .handle_irq = NULL,
1529 .evport_offset = SONYPI_TYPE1_OFFSET,
1530 .event_types = type1_events,
1531 },
1532 {
1533 .model = SONYPI_DEVICE_TYPE2,
1534 .handle_irq = NULL,
1535 .evport_offset = SONYPI_TYPE2_OFFSET,
1536 .event_types = type2_events,
1537 },
1538 {
1539 .model = SONYPI_DEVICE_TYPE3,
1540 .handle_irq = NULL,
1541 .evport_offset = SONYPI_TYPE3_OFFSET,
1542 .event_types = type3_events,
1543 },
1544 {
1545 .model = SONYPI_DEVICE_TYPE4,
1546 .handle_irq = type4_handle_irq,
1547 .evport_offset = SONYPI_TYPE4_OFFSET,
1548 .event_types = type4_events,
1549 },
1550};
1551
1552static void sony_pic_detect_device_type(struct sony_pic_dev *dev)
1553{
1554 struct pci_dev *pcidev;
1555
1556 pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
1557 PCI_DEVICE_ID_INTEL_82371AB_3, NULL);
1558 if (pcidev) {
1559 dev->control = &spic_types[0];
1560 goto out;
1561 }
1562
1563 pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
1564 PCI_DEVICE_ID_INTEL_ICH6_1, NULL);
1565 if (pcidev) {
1566 dev->control = &spic_types[2];
1567 goto out;
1568 }
1569
1570 pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
1571 PCI_DEVICE_ID_INTEL_ICH7_1, NULL);
1572 if (pcidev) {
1573 dev->control = &spic_types[3];
1574 goto out;
1575 }
1576
1577 pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
1578 PCI_DEVICE_ID_INTEL_ICH8_4, NULL);
1579 if (pcidev) {
1580 dev->control = &spic_types[3];
1581 goto out;
1582 }
1583
1584 /* default */
1585 dev->control = &spic_types[1];
1586
1587out:
1588 if (pcidev)
1589 pci_dev_put(pcidev);
1590
1591 printk(KERN_INFO DRV_PFX "detected Type%d model\n",
1592 dev->control->model == SONYPI_DEVICE_TYPE1 ? 1 :
1593 dev->control->model == SONYPI_DEVICE_TYPE2 ? 2 :
1594 dev->control->model == SONYPI_DEVICE_TYPE3 ? 3 : 4);
1595}
1596
1488/* camera tests and poweron/poweroff */ 1597/* camera tests and poweron/poweroff */
1489#define SONYPI_CAMERA_PICTURE 5 1598#define SONYPI_CAMERA_PICTURE 5
1490#define SONYPI_CAMERA_CONTROL 0x10 1599#define SONYPI_CAMERA_CONTROL 0x10
@@ -2253,7 +2362,7 @@ static int sony_pic_enable(struct acpi_device *device,
2253 buffer.pointer = resource; 2362 buffer.pointer = resource;
2254 2363
2255 /* setup Type 1 resources */ 2364 /* setup Type 1 resources */
2256 if (spic_dev.model == SONYPI_DEVICE_TYPE1) { 2365 if (spic_dev.control->model == SONYPI_DEVICE_TYPE1) {
2257 2366
2258 /* setup io resources */ 2367 /* setup io resources */
2259 resource->res1.type = ACPI_RESOURCE_TYPE_IO; 2368 resource->res1.type = ACPI_RESOURCE_TYPE_IO;
@@ -2335,39 +2444,49 @@ static irqreturn_t sony_pic_irq(int irq, void *dev_id)
2335 if (dev->cur_ioport->io2.minimum) 2444 if (dev->cur_ioport->io2.minimum)
2336 data_mask = inb_p(dev->cur_ioport->io2.minimum); 2445 data_mask = inb_p(dev->cur_ioport->io2.minimum);
2337 else 2446 else
2338 data_mask = inb_p(dev->cur_ioport->io1.minimum + dev->evport_offset); 2447 data_mask = inb_p(dev->cur_ioport->io1.minimum +
2448 dev->control->evport_offset);
2339 2449
2340 dprintk("event ([%.2x] [%.2x]) at port 0x%.4x(+0x%.2x)\n", 2450 dprintk("event ([%.2x] [%.2x]) at port 0x%.4x(+0x%.2x)\n",
2341 ev, data_mask, dev->cur_ioport->io1.minimum, dev->evport_offset); 2451 ev, data_mask, dev->cur_ioport->io1.minimum,
2452 dev->control->evport_offset);
2342 2453
2343 if (ev == 0x00 || ev == 0xff) 2454 if (ev == 0x00 || ev == 0xff)
2344 return IRQ_HANDLED; 2455 return IRQ_HANDLED;
2345 2456
2346 for (i = 0; sony_pic_eventtypes[i].model; i++) { 2457 for (i = 0; dev->control->event_types[i].mask; i++) {
2347
2348 if (spic_dev.model != sony_pic_eventtypes[i].model)
2349 continue;
2350 2458
2351 if ((data_mask & sony_pic_eventtypes[i].data) != 2459 if ((data_mask & dev->control->event_types[i].data) !=
2352 sony_pic_eventtypes[i].data) 2460 dev->control->event_types[i].data)
2353 continue; 2461 continue;
2354 2462
2355 if (!(mask & sony_pic_eventtypes[i].mask)) 2463 if (!(mask & dev->control->event_types[i].mask))
2356 continue; 2464 continue;
2357 2465
2358 for (j = 0; sony_pic_eventtypes[i].events[j].event; j++) { 2466 for (j = 0; dev->control->event_types[i].events[j].event; j++) {
2359 if (ev == sony_pic_eventtypes[i].events[j].data) { 2467 if (ev == dev->control->event_types[i].events[j].data) {
2360 device_event = 2468 device_event =
2361 sony_pic_eventtypes[i].events[j].event; 2469 dev->control->
2470 event_types[i].events[j].event;
2362 goto found; 2471 goto found;
2363 } 2472 }
2364 } 2473 }
2365 } 2474 }
2475 /* Still not able to decode the event try to pass
2476 * it over to the minidriver
2477 */
2478 if (dev->control->handle_irq &&
2479 dev->control->handle_irq(data_mask, ev) == 0)
2480 return IRQ_HANDLED;
2481
2482 dprintk("unknown event ([%.2x] [%.2x]) at port 0x%.4x(+0x%.2x)\n",
2483 ev, data_mask, dev->cur_ioport->io1.minimum,
2484 dev->control->evport_offset);
2366 return IRQ_HANDLED; 2485 return IRQ_HANDLED;
2367 2486
2368found: 2487found:
2369 sony_laptop_report_input_event(device_event); 2488 sony_laptop_report_input_event(device_event);
2370 acpi_bus_generate_proc_event(spic_dev.acpi_dev, 1, device_event); 2489 acpi_bus_generate_proc_event(dev->acpi_dev, 1, device_event);
2371 sonypi_compat_report_event(device_event); 2490 sonypi_compat_report_event(device_event);
2372 2491
2373 return IRQ_HANDLED; 2492 return IRQ_HANDLED;
@@ -2429,23 +2548,9 @@ static int sony_pic_add(struct acpi_device *device)
2429 2548
2430 spic_dev.acpi_dev = device; 2549 spic_dev.acpi_dev = device;
2431 strcpy(acpi_device_class(device), "sony/hotkey"); 2550 strcpy(acpi_device_class(device), "sony/hotkey");
2432 spic_dev.model = sony_pic_detect_device_type(); 2551 sony_pic_detect_device_type(&spic_dev);
2433 mutex_init(&spic_dev.lock); 2552 mutex_init(&spic_dev.lock);
2434 2553
2435 /* model specific characteristics */
2436 switch(spic_dev.model) {
2437 case SONYPI_DEVICE_TYPE1:
2438 spic_dev.evport_offset = SONYPI_TYPE1_OFFSET;
2439 break;
2440 case SONYPI_DEVICE_TYPE3:
2441 spic_dev.evport_offset = SONYPI_TYPE3_OFFSET;
2442 break;
2443 case SONYPI_DEVICE_TYPE2:
2444 default:
2445 spic_dev.evport_offset = SONYPI_TYPE2_OFFSET;
2446 break;
2447 }
2448
2449 /* read _PRS resources */ 2554 /* read _PRS resources */
2450 result = sony_pic_possible_resources(device); 2555 result = sony_pic_possible_resources(device);
2451 if (result) { 2556 if (result) {
diff --git a/drivers/misc/tc1100-wmi.c b/drivers/misc/tc1100-wmi.c
new file mode 100644
index 000000000000..f25e4c974dcf
--- /dev/null
+++ b/drivers/misc/tc1100-wmi.c
@@ -0,0 +1,290 @@
1/*
2 * HP Compaq TC1100 Tablet WMI Extras Driver
3 *
4 * Copyright (C) 2007 Carlos Corbacho <carlos@strangeworlds.co.uk>
5 * Copyright (C) 2004 Jamey Hicks <jamey.hicks@hp.com>
6 * Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
7 * Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
8 *
9 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or (at
14 * your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful, but
17 * WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License along
22 * with this program; if not, write to the Free Software Foundation, Inc.,
23 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
24 *
25 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
26 */
27
28#include <linux/kernel.h>
29#include <linux/module.h>
30#include <linux/init.h>
31#include <linux/types.h>
32#include <acpi/acpi.h>
33#include <acpi/actypes.h>
34#include <acpi/acpi_bus.h>
35#include <acpi/acpi_drivers.h>
36#include <linux/platform_device.h>
37
38#define GUID "C364AC71-36DB-495A-8494-B439D472A505"
39
40#define TC1100_INSTANCE_WIRELESS 1
41#define TC1100_INSTANCE_JOGDIAL 2
42
43#define TC1100_LOGPREFIX "tc1100-wmi: "
44#define TC1100_INFO KERN_INFO TC1100_LOGPREFIX
45
46MODULE_AUTHOR("Jamey Hicks, Carlos Corbacho");
47MODULE_DESCRIPTION("HP Compaq TC1100 Tablet WMI Extras");
48MODULE_LICENSE("GPL");
49MODULE_ALIAS("wmi:C364AC71-36DB-495A-8494-B439D472A505");
50
51static int tc1100_probe(struct platform_device *device);
52static int tc1100_remove(struct platform_device *device);
53static int tc1100_suspend(struct platform_device *device, pm_message_t state);
54static int tc1100_resume(struct platform_device *device);
55
56static struct platform_driver tc1100_driver = {
57 .driver = {
58 .name = "tc1100-wmi",
59 .owner = THIS_MODULE,
60 },
61 .probe = tc1100_probe,
62 .remove = tc1100_remove,
63 .suspend = tc1100_suspend,
64 .resume = tc1100_resume,
65};
66
67static struct platform_device *tc1100_device;
68
69struct tc1100_data {
70 u32 wireless;
71 u32 jogdial;
72};
73
74static struct tc1100_data suspend_data;
75
76/* --------------------------------------------------------------------------
77 Device Management
78 -------------------------------------------------------------------------- */
79
80static int get_state(u32 *out, u8 instance)
81{
82 u32 tmp;
83 acpi_status status;
84 struct acpi_buffer result = { ACPI_ALLOCATE_BUFFER, NULL };
85 union acpi_object *obj;
86
87 if (!out)
88 return -EINVAL;
89
90 if (instance > 2)
91 return -ENODEV;
92
93 status = wmi_query_block(GUID, instance, &result);
94 if (ACPI_FAILURE(status))
95 return -ENODEV;
96
97 obj = (union acpi_object *) result.pointer;
98 if (obj && obj->type == ACPI_TYPE_BUFFER &&
99 obj->buffer.length == sizeof(u32)) {
100 tmp = *((u32 *) obj->buffer.pointer);
101 } else {
102 tmp = 0;
103 }
104
105 if (result.length > 0 && result.pointer)
106 kfree(result.pointer);
107
108 switch (instance) {
109 case TC1100_INSTANCE_WIRELESS:
110 *out = (tmp == 3) ? 1 : 0;
111 return 0;
112 case TC1100_INSTANCE_JOGDIAL:
113 *out = (tmp == 1) ? 1 : 0;
114 return 0;
115 default:
116 return -ENODEV;
117 }
118}
119
120static int set_state(u32 *in, u8 instance)
121{
122 u32 value;
123 acpi_status status;
124 struct acpi_buffer input;
125
126 if (!in)
127 return -EINVAL;
128
129 if (instance > 2)
130 return -ENODEV;
131
132 switch (instance) {
133 case TC1100_INSTANCE_WIRELESS:
134 value = (*in) ? 1 : 2;
135 break;
136 case TC1100_INSTANCE_JOGDIAL:
137 value = (*in) ? 0 : 1;
138 break;
139 default:
140 return -ENODEV;
141 }
142
143 input.length = sizeof(u32);
144 input.pointer = &value;
145
146 status = wmi_set_block(GUID, instance, &input);
147 if (ACPI_FAILURE(status))
148 return -ENODEV;
149
150 return 0;
151}
152
153/* --------------------------------------------------------------------------
154 FS Interface (/sys)
155 -------------------------------------------------------------------------- */
156
157/*
158 * Read/ write bool sysfs macro
159 */
160#define show_set_bool(value, instance) \
161static ssize_t \
162show_bool_##value(struct device *dev, struct device_attribute *attr, \
163 char *buf) \
164{ \
165 u32 result; \
166 acpi_status status = get_state(&result, instance); \
167 if (ACPI_SUCCESS(status)) \
168 return sprintf(buf, "%d\n", result); \
169 return sprintf(buf, "Read error\n"); \
170} \
171\
172static ssize_t \
173set_bool_##value(struct device *dev, struct device_attribute *attr, \
174 const char *buf, size_t count) \
175{ \
176 u32 tmp = simple_strtoul(buf, NULL, 10); \
177 acpi_status status = set_state(&tmp, instance); \
178 if (ACPI_FAILURE(status)) \
179 return -EINVAL; \
180 return count; \
181} \
182static DEVICE_ATTR(value, S_IWUGO | S_IRUGO | S_IWUSR, \
183 show_bool_##value, set_bool_##value);
184
185show_set_bool(wireless, TC1100_INSTANCE_WIRELESS);
186show_set_bool(jogdial, TC1100_INSTANCE_JOGDIAL);
187
188static void remove_fs(void)
189{
190 device_remove_file(&tc1100_device->dev, &dev_attr_wireless);
191 device_remove_file(&tc1100_device->dev, &dev_attr_jogdial);
192}
193
194static int add_fs(void)
195{
196 int ret;
197
198 ret = device_create_file(&tc1100_device->dev, &dev_attr_wireless);
199 if (ret)
200 goto add_sysfs_error;
201
202 ret = device_create_file(&tc1100_device->dev, &dev_attr_jogdial);
203 if (ret)
204 goto add_sysfs_error;
205
206 return ret;
207
208add_sysfs_error:
209 remove_fs();
210 return ret;
211}
212
213/* --------------------------------------------------------------------------
214 Driver Model
215 -------------------------------------------------------------------------- */
216
217static int tc1100_probe(struct platform_device *device)
218{
219 int result = 0;
220
221 result = add_fs();
222 return result;
223}
224
225
226static int tc1100_remove(struct platform_device *device)
227{
228 remove_fs();
229 return 0;
230}
231
232static int tc1100_suspend(struct platform_device *dev, pm_message_t state)
233{
234 int ret;
235
236 ret = get_state(&suspend_data.wireless, TC1100_INSTANCE_WIRELESS);
237 if (ret)
238 return ret;
239
240 ret = get_state(&suspend_data.jogdial, TC1100_INSTANCE_JOGDIAL);
241 if (ret)
242 return ret;
243
244 return ret;
245}
246
247static int tc1100_resume(struct platform_device *dev)
248{
249 int ret;
250
251 ret = set_state(&suspend_data.wireless, TC1100_INSTANCE_WIRELESS);
252 if (ret)
253 return ret;
254
255 ret = set_state(&suspend_data.jogdial, TC1100_INSTANCE_JOGDIAL);
256 if (ret)
257 return ret;
258
259 return ret;
260}
261
262static int __init tc1100_init(void)
263{
264 int result = 0;
265
266 if (!wmi_has_guid(GUID))
267 return -ENODEV;
268
269 result = platform_driver_register(&tc1100_driver);
270 if (result)
271 return result;
272
273 tc1100_device = platform_device_alloc("tc1100-wmi", -1);
274 platform_device_add(tc1100_device);
275
276 printk(TC1100_INFO "HP Compaq TC1100 Tablet WMI Extras loaded\n");
277
278 return result;
279}
280
281static void __exit tc1100_exit(void)
282{
283 platform_device_del(tc1100_device);
284 platform_driver_unregister(&tc1100_driver);
285
286 printk(TC1100_INFO "HP Compaq TC1100 Tablet WMI Extras unloaded\n");
287}
288
289module_init(tc1100_init);
290module_exit(tc1100_exit);
diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c
index cf56647a6ca4..7ba1acad5402 100644
--- a/drivers/misc/thinkpad_acpi.c
+++ b/drivers/misc/thinkpad_acpi.c
@@ -3,7 +3,7 @@
3 * 3 *
4 * 4 *
5 * Copyright (C) 2004-2005 Borislav Deianov <borislav@users.sf.net> 5 * Copyright (C) 2004-2005 Borislav Deianov <borislav@users.sf.net>
6 * Copyright (C) 2006-2007 Henrique de Moraes Holschuh <hmh@hmh.eng.br> 6 * Copyright (C) 2006-2008 Henrique de Moraes Holschuh <hmh@hmh.eng.br>
7 * 7 *
8 * This program is free software; you can redistribute it and/or modify 8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by 9 * it under the terms of the GNU General Public License as published by
@@ -21,11 +21,13 @@
21 * 02110-1301, USA. 21 * 02110-1301, USA.
22 */ 22 */
23 23
24#define IBM_VERSION "0.17" 24#define TPACPI_VERSION "0.19"
25#define TPACPI_SYSFS_VERSION 0x020000 25#define TPACPI_SYSFS_VERSION 0x020200
26 26
27/* 27/*
28 * Changelog: 28 * Changelog:
29 * 2007-10-20 changelog trimmed down
30 *
29 * 2007-03-27 0.14 renamed to thinkpad_acpi and moved to 31 * 2007-03-27 0.14 renamed to thinkpad_acpi and moved to
30 * drivers/misc. 32 * drivers/misc.
31 * 33 *
@@ -33,89 +35,219 @@
33 * changelog now lives in git commit history, and will 35 * changelog now lives in git commit history, and will
34 * not be updated further in-file. 36 * not be updated further in-file.
35 * 37 *
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 * 2005-03-17 0.11 support for 600e, 770x
38 * thanks to Jamie Lentin <lentinj@dial.pipex.com> 39 * thanks to Jamie Lentin <lentinj@dial.pipex.com>
39 * support for 770e, G41 40 *
40 * G40 and G41 don't have a thinklight 41 * 2005-01-16 0.9 use MODULE_VERSION
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> 42 * thanks to Henrik Brix Andersen <brix@gentoo.org>
55 * fix parameter passing on module loading 43 * fix parameter passing on module loading
56 * thanks to Rusty Russell <rusty@rustcorp.com.au> 44 * thanks to Rusty Russell <rusty@rustcorp.com.au>
57 * thanks to Jim Radford <radford@blackbean.org> 45 * thanks to Jim Radford <radford@blackbean.org>
58 * 2004-11-08 0.8 fix init error case, don't return from a macro 46 * 2004-11-08 0.8 fix init error case, don't return from a macro
59 * thanks to Chris Wright <chrisw@osdl.org> 47 * 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 */ 48 */
84 49
85#include "thinkpad_acpi.h" 50#include <linux/kernel.h>
51#include <linux/module.h>
52#include <linux/init.h>
53#include <linux/types.h>
54#include <linux/string.h>
55#include <linux/list.h>
56#include <linux/mutex.h>
57#include <linux/kthread.h>
58#include <linux/freezer.h>
59#include <linux/delay.h>
60
61#include <linux/nvram.h>
62#include <linux/proc_fs.h>
63#include <linux/sysfs.h>
64#include <linux/backlight.h>
65#include <linux/fb.h>
66#include <linux/platform_device.h>
67#include <linux/hwmon.h>
68#include <linux/hwmon-sysfs.h>
69#include <linux/input.h>
70#include <asm/uaccess.h>
71
72#include <linux/dmi.h>
73#include <linux/jiffies.h>
74#include <linux/workqueue.h>
75
76#include <acpi/acpi_drivers.h>
77#include <acpi/acnamesp.h>
78
79#include <linux/pci_ids.h>
80
81
82/* ThinkPad CMOS commands */
83#define TP_CMOS_VOLUME_DOWN 0
84#define TP_CMOS_VOLUME_UP 1
85#define TP_CMOS_VOLUME_MUTE 2
86#define TP_CMOS_BRIGHTNESS_UP 4
87#define TP_CMOS_BRIGHTNESS_DOWN 5
88
89/* NVRAM Addresses */
90enum tp_nvram_addr {
91 TP_NVRAM_ADDR_HK2 = 0x57,
92 TP_NVRAM_ADDR_THINKLIGHT = 0x58,
93 TP_NVRAM_ADDR_VIDEO = 0x59,
94 TP_NVRAM_ADDR_BRIGHTNESS = 0x5e,
95 TP_NVRAM_ADDR_MIXER = 0x60,
96};
86 97
87MODULE_AUTHOR("Borislav Deianov, Henrique de Moraes Holschuh"); 98/* NVRAM bit masks */
88MODULE_DESCRIPTION(IBM_DESC); 99enum {
89MODULE_VERSION(IBM_VERSION); 100 TP_NVRAM_MASK_HKT_THINKPAD = 0x08,
90MODULE_LICENSE("GPL"); 101 TP_NVRAM_MASK_HKT_ZOOM = 0x20,
102 TP_NVRAM_MASK_HKT_DISPLAY = 0x40,
103 TP_NVRAM_MASK_HKT_HIBERNATE = 0x80,
104 TP_NVRAM_MASK_THINKLIGHT = 0x10,
105 TP_NVRAM_MASK_HKT_DISPEXPND = 0x30,
106 TP_NVRAM_MASK_HKT_BRIGHTNESS = 0x20,
107 TP_NVRAM_MASK_LEVEL_BRIGHTNESS = 0x0f,
108 TP_NVRAM_POS_LEVEL_BRIGHTNESS = 0,
109 TP_NVRAM_MASK_MUTE = 0x40,
110 TP_NVRAM_MASK_HKT_VOLUME = 0x80,
111 TP_NVRAM_MASK_LEVEL_VOLUME = 0x0f,
112 TP_NVRAM_POS_LEVEL_VOLUME = 0,
113};
91 114
92/* Please remove this in year 2009 */ 115/* ACPI HIDs */
93MODULE_ALIAS("ibm_acpi"); 116#define TPACPI_ACPI_HKEY_HID "IBM0068"
94 117
95/* 118/* Input IDs */
96 * DMI matching for module autoloading 119#define TPACPI_HKEY_INPUT_PRODUCT 0x5054 /* "TP" */
97 * 120#define TPACPI_HKEY_INPUT_VERSION 0x4101
98 * See http://thinkwiki.org/wiki/List_of_DMI_IDs 121
99 * See http://thinkwiki.org/wiki/BIOS_Upgrade_Downloads 122
100 * 123/****************************************************************************
101 * Only models listed in thinkwiki will be supported, so add yours 124 * Main driver
102 * if it is not there yet.
103 */ 125 */
104#define IBM_BIOS_MODULE_ALIAS(__type) \
105 MODULE_ALIAS("dmi:bvnIBM:bvr" __type "ET??WW")
106 126
107/* Non-ancient thinkpads */ 127#define TPACPI_NAME "thinkpad"
108MODULE_ALIAS("dmi:bvnIBM:*:svnIBM:*:pvrThinkPad*:rvnIBM:*"); 128#define TPACPI_DESC "ThinkPad ACPI Extras"
109MODULE_ALIAS("dmi:bvnLENOVO:*:svnLENOVO:*:pvrThinkPad*:rvnLENOVO:*"); 129#define TPACPI_FILE TPACPI_NAME "_acpi"
130#define TPACPI_URL "http://ibm-acpi.sf.net/"
131#define TPACPI_MAIL "ibm-acpi-devel@lists.sourceforge.net"
132
133#define TPACPI_PROC_DIR "ibm"
134#define TPACPI_ACPI_EVENT_PREFIX "ibm"
135#define TPACPI_DRVR_NAME TPACPI_FILE
136#define TPACPI_HWMON_DRVR_NAME TPACPI_NAME "_hwmon"
137
138#define TPACPI_MAX_ACPI_ARGS 3
139
140/* Debugging */
141#define TPACPI_LOG TPACPI_FILE ": "
142#define TPACPI_ERR KERN_ERR TPACPI_LOG
143#define TPACPI_NOTICE KERN_NOTICE TPACPI_LOG
144#define TPACPI_INFO KERN_INFO TPACPI_LOG
145#define TPACPI_DEBUG KERN_DEBUG TPACPI_LOG
146
147#define TPACPI_DBG_ALL 0xffff
148#define TPACPI_DBG_ALL 0xffff
149#define TPACPI_DBG_INIT 0x0001
150#define TPACPI_DBG_EXIT 0x0002
151#define dbg_printk(a_dbg_level, format, arg...) \
152 do { if (dbg_level & a_dbg_level) \
153 printk(TPACPI_DEBUG "%s: " format, __func__ , ## arg); \
154 } while (0)
155#ifdef CONFIG_THINKPAD_ACPI_DEBUG
156#define vdbg_printk(a_dbg_level, format, arg...) \
157 dbg_printk(a_dbg_level, format, ## arg)
158static const char *str_supported(int is_supported);
159#else
160#define vdbg_printk(a_dbg_level, format, arg...)
161#endif
110 162
111/* Ancient thinkpad BIOSes have to be identified by 163#define onoff(status, bit) ((status) & (1 << (bit)) ? "on" : "off")
112 * BIOS type or model number, and there are far less 164#define enabled(status, bit) ((status) & (1 << (bit)) ? "enabled" : "disabled")
113 * BIOS types than model numbers... */ 165#define strlencmp(a, b) (strncmp((a), (b), strlen(b)))
114IBM_BIOS_MODULE_ALIAS("I[B,D,H,I,M,N,O,T,W,V,Y,Z]"); 166
115IBM_BIOS_MODULE_ALIAS("1[0,3,6,8,A-G,I,K,M-P,S,T]"); 167
116IBM_BIOS_MODULE_ALIAS("K[U,X-Z]"); 168/****************************************************************************
169 * Driver-wide structs and misc. variables
170 */
171
172struct ibm_struct;
173
174struct tp_acpi_drv_struct {
175 const struct acpi_device_id *hid;
176 struct acpi_driver *driver;
117 177
118#define __unused __attribute__ ((unused)) 178 void (*notify) (struct ibm_struct *, u32);
179 acpi_handle *handle;
180 u32 type;
181 struct acpi_device *device;
182};
183
184struct ibm_struct {
185 char *name;
186
187 int (*read) (char *);
188 int (*write) (char *);
189 void (*exit) (void);
190 void (*resume) (void);
191 void (*suspend) (pm_message_t state);
192
193 struct list_head all_drivers;
194
195 struct tp_acpi_drv_struct *acpi;
196
197 struct {
198 u8 acpi_driver_registered:1;
199 u8 acpi_notify_installed:1;
200 u8 proc_created:1;
201 u8 init_called:1;
202 u8 experimental:1;
203 } flags;
204};
205
206struct ibm_init_struct {
207 char param[32];
208
209 int (*init) (struct ibm_init_struct *);
210 struct ibm_struct *data;
211};
212
213static struct {
214#ifdef CONFIG_THINKPAD_ACPI_BAY
215 u32 bay_status:1;
216 u32 bay_eject:1;
217 u32 bay_status2:1;
218 u32 bay_eject2:1;
219#endif
220 u32 bluetooth:1;
221 u32 hotkey:1;
222 u32 hotkey_mask:1;
223 u32 hotkey_wlsw:1;
224 u32 light:1;
225 u32 light_status:1;
226 u32 bright_16levels:1;
227 u32 wan:1;
228 u32 fan_ctrl_status_undef:1;
229 u32 input_device_registered:1;
230 u32 platform_drv_registered:1;
231 u32 platform_drv_attrs_registered:1;
232 u32 sensors_pdrv_registered:1;
233 u32 sensors_pdrv_attrs_registered:1;
234 u32 sensors_pdev_attrs_registered:1;
235 u32 hotkey_poll_active:1;
236} tp_features;
237
238struct thinkpad_id_data {
239 unsigned int vendor; /* ThinkPad vendor:
240 * PCI_VENDOR_ID_IBM/PCI_VENDOR_ID_LENOVO */
241
242 char *bios_version_str; /* Something like 1ZET51WW (1.03z) */
243 char *ec_version_str; /* Something like 1ZHT51WW-1.04a */
244
245 u16 bios_model; /* Big Endian, TP-1Y = 0x5931, 0 = unknown */
246 u16 ec_model;
247
248 char *model_str;
249};
250static struct thinkpad_id_data thinkpad_id;
119 251
120static enum { 252static enum {
121 TPACPI_LIFE_INIT = 0, 253 TPACPI_LIFE_INIT = 0,
@@ -123,6 +255,9 @@ static enum {
123 TPACPI_LIFE_EXITING, 255 TPACPI_LIFE_EXITING,
124} tpacpi_lifecycle; 256} tpacpi_lifecycle;
125 257
258static int experimental;
259static u32 dbg_level;
260
126/**************************************************************************** 261/****************************************************************************
127 **************************************************************************** 262 ****************************************************************************
128 * 263 *
@@ -137,13 +272,13 @@ static enum {
137 272
138static acpi_handle root_handle; 273static acpi_handle root_handle;
139 274
140#define IBM_HANDLE(object, parent, paths...) \ 275#define TPACPI_HANDLE(object, parent, paths...) \
141 static acpi_handle object##_handle; \ 276 static acpi_handle object##_handle; \
142 static acpi_handle *object##_parent = &parent##_handle; \ 277 static acpi_handle *object##_parent = &parent##_handle; \
143 static char *object##_path; \ 278 static char *object##_path; \
144 static char *object##_paths[] = { paths } 279 static char *object##_paths[] = { paths }
145 280
146IBM_HANDLE(ec, root, "\\_SB.PCI0.ISA.EC0", /* 240, 240x */ 281TPACPI_HANDLE(ec, root, "\\_SB.PCI0.ISA.EC0", /* 240, 240x */
147 "\\_SB.PCI.ISA.EC", /* 570 */ 282 "\\_SB.PCI.ISA.EC", /* 570 */
148 "\\_SB.PCI0.ISA0.EC0", /* 600e/x, 770e, 770x */ 283 "\\_SB.PCI0.ISA0.EC0", /* 600e/x, 770e, 770x */
149 "\\_SB.PCI0.ISA.EC", /* A21e, A2xm/p, T20-22, X20-21 */ 284 "\\_SB.PCI0.ISA.EC", /* A21e, A2xm/p, T20-22, X20-21 */
@@ -152,20 +287,16 @@ IBM_HANDLE(ec, root, "\\_SB.PCI0.ISA.EC0", /* 240, 240x */
152 "\\_SB.PCI0.LPC.EC", /* all others */ 287 "\\_SB.PCI0.LPC.EC", /* all others */
153 ); 288 );
154 289
155IBM_HANDLE(ecrd, ec, "ECRD"); /* 570 */ 290TPACPI_HANDLE(ecrd, ec, "ECRD"); /* 570 */
156IBM_HANDLE(ecwr, ec, "ECWR"); /* 570 */ 291TPACPI_HANDLE(ecwr, ec, "ECWR"); /* 570 */
157
158
159/*************************************************************************
160 * Misc ACPI handles
161 */
162 292
163IBM_HANDLE(cmos, root, "\\UCMS", /* R50, R50e, R50p, R51, T4x, X31, X40 */ 293TPACPI_HANDLE(cmos, root, "\\UCMS", /* R50, R50e, R50p, R51, */
294 /* T4x, X31, X40 */
164 "\\CMOS", /* A3x, G4x, R32, T23, T30, X22-24, X30 */ 295 "\\CMOS", /* A3x, G4x, R32, T23, T30, X22-24, X30 */
165 "\\CMS", /* R40, R40e */ 296 "\\CMS", /* R40, R40e */
166 ); /* all others */ 297 ); /* all others */
167 298
168IBM_HANDLE(hkey, ec, "\\_SB.HKEY", /* 600e/x, 770e, 770x */ 299TPACPI_HANDLE(hkey, ec, "\\_SB.HKEY", /* 600e/x, 770e, 770x */
169 "^HKEY", /* R30, R31 */ 300 "^HKEY", /* R30, R31 */
170 "HKEY", /* all others */ 301 "HKEY", /* all others */
171 ); /* 570 */ 302 ); /* 570 */
@@ -180,7 +311,7 @@ static int acpi_evalf(acpi_handle handle,
180{ 311{
181 char *fmt0 = fmt; 312 char *fmt0 = fmt;
182 struct acpi_object_list params; 313 struct acpi_object_list params;
183 union acpi_object in_objs[IBM_MAX_ACPI_ARGS]; 314 union acpi_object in_objs[TPACPI_MAX_ACPI_ARGS];
184 struct acpi_buffer result, *resultp; 315 struct acpi_buffer result, *resultp;
185 union acpi_object out_obj; 316 union acpi_object out_obj;
186 acpi_status status; 317 acpi_status status;
@@ -190,7 +321,7 @@ static int acpi_evalf(acpi_handle handle,
190 int quiet; 321 int quiet;
191 322
192 if (!*fmt) { 323 if (!*fmt) {
193 printk(IBM_ERR "acpi_evalf() called with empty format\n"); 324 printk(TPACPI_ERR "acpi_evalf() called with empty format\n");
194 return 0; 325 return 0;
195 } 326 }
196 327
@@ -215,7 +346,7 @@ static int acpi_evalf(acpi_handle handle,
215 break; 346 break;
216 /* add more types as needed */ 347 /* add more types as needed */
217 default: 348 default:
218 printk(IBM_ERR "acpi_evalf() called " 349 printk(TPACPI_ERR "acpi_evalf() called "
219 "with invalid format character '%c'\n", c); 350 "with invalid format character '%c'\n", c);
220 return 0; 351 return 0;
221 } 352 }
@@ -242,29 +373,19 @@ static int acpi_evalf(acpi_handle handle,
242 break; 373 break;
243 /* add more types as needed */ 374 /* add more types as needed */
244 default: 375 default:
245 printk(IBM_ERR "acpi_evalf() called " 376 printk(TPACPI_ERR "acpi_evalf() called "
246 "with invalid format character '%c'\n", res_type); 377 "with invalid format character '%c'\n", res_type);
247 return 0; 378 return 0;
248 } 379 }
249 380
250 if (!success && !quiet) 381 if (!success && !quiet)
251 printk(IBM_ERR "acpi_evalf(%s, %s, ...) failed: %d\n", 382 printk(TPACPI_ERR "acpi_evalf(%s, %s, ...) failed: %d\n",
252 method, fmt0, status); 383 method, fmt0, status);
253 384
254 return success; 385 return success;
255} 386}
256 387
257static void __unused acpi_print_int(acpi_handle handle, char *method) 388static int acpi_ec_read(int i, u8 *p)
258{
259 int i;
260
261 if (acpi_evalf(handle, &i, method, "d"))
262 printk(IBM_INFO "%s = 0x%x\n", method, i);
263 else
264 printk(IBM_ERR "error calling %s\n", method);
265}
266
267static int acpi_ec_read(int i, u8 * p)
268{ 389{
269 int v; 390 int v;
270 391
@@ -293,6 +414,7 @@ static int acpi_ec_write(int i, u8 v)
293 return 1; 414 return 1;
294} 415}
295 416
417#if defined(CONFIG_THINKPAD_ACPI_DOCK) || defined(CONFIG_THINKPAD_ACPI_BAY)
296static int _sta(acpi_handle handle) 418static int _sta(acpi_handle handle)
297{ 419{
298 int status; 420 int status;
@@ -302,6 +424,7 @@ static int _sta(acpi_handle handle)
302 424
303 return status; 425 return status;
304} 426}
427#endif
305 428
306static int issue_thinkpad_cmos_command(int cmos_cmd) 429static int issue_thinkpad_cmos_command(int cmos_cmd)
307{ 430{
@@ -318,6 +441,10 @@ static int issue_thinkpad_cmos_command(int cmos_cmd)
318 * ACPI device model 441 * ACPI device model
319 */ 442 */
320 443
444#define TPACPI_ACPIHANDLE_INIT(object) \
445 drv_acpi_handle_init(#object, &object##_handle, *object##_parent, \
446 object##_paths, ARRAY_SIZE(object##_paths), &object##_path)
447
321static void drv_acpi_handle_init(char *name, 448static void drv_acpi_handle_init(char *name,
322 acpi_handle *handle, acpi_handle parent, 449 acpi_handle *handle, acpi_handle parent,
323 char **paths, int num_paths, char **path) 450 char **paths, int num_paths, char **path)
@@ -372,25 +499,27 @@ static int __init setup_acpi_notify(struct ibm_struct *ibm)
372 499
373 rc = acpi_bus_get_device(*ibm->acpi->handle, &ibm->acpi->device); 500 rc = acpi_bus_get_device(*ibm->acpi->handle, &ibm->acpi->device);
374 if (rc < 0) { 501 if (rc < 0) {
375 printk(IBM_ERR "acpi_bus_get_device(%s) failed: %d\n", 502 printk(TPACPI_ERR "acpi_bus_get_device(%s) failed: %d\n",
376 ibm->name, rc); 503 ibm->name, rc);
377 return -ENODEV; 504 return -ENODEV;
378 } 505 }
379 506
380 acpi_driver_data(ibm->acpi->device) = ibm; 507 acpi_driver_data(ibm->acpi->device) = ibm;
381 sprintf(acpi_device_class(ibm->acpi->device), "%s/%s", 508 sprintf(acpi_device_class(ibm->acpi->device), "%s/%s",
382 IBM_ACPI_EVENT_PREFIX, 509 TPACPI_ACPI_EVENT_PREFIX,
383 ibm->name); 510 ibm->name);
384 511
385 status = acpi_install_notify_handler(*ibm->acpi->handle, 512 status = acpi_install_notify_handler(*ibm->acpi->handle,
386 ibm->acpi->type, dispatch_acpi_notify, ibm); 513 ibm->acpi->type, dispatch_acpi_notify, ibm);
387 if (ACPI_FAILURE(status)) { 514 if (ACPI_FAILURE(status)) {
388 if (status == AE_ALREADY_EXISTS) { 515 if (status == AE_ALREADY_EXISTS) {
389 printk(IBM_NOTICE "another device driver is already handling %s events\n", 516 printk(TPACPI_NOTICE
390 ibm->name); 517 "another device driver is already "
518 "handling %s events\n", ibm->name);
391 } else { 519 } else {
392 printk(IBM_ERR "acpi_install_notify_handler(%s) failed: %d\n", 520 printk(TPACPI_ERR
393 ibm->name, status); 521 "acpi_install_notify_handler(%s) failed: %d\n",
522 ibm->name, status);
394 } 523 }
395 return -ENODEV; 524 return -ENODEV;
396 } 525 }
@@ -414,18 +543,18 @@ static int __init register_tpacpi_subdriver(struct ibm_struct *ibm)
414 543
415 ibm->acpi->driver = kzalloc(sizeof(struct acpi_driver), GFP_KERNEL); 544 ibm->acpi->driver = kzalloc(sizeof(struct acpi_driver), GFP_KERNEL);
416 if (!ibm->acpi->driver) { 545 if (!ibm->acpi->driver) {
417 printk(IBM_ERR "kzalloc(ibm->driver) failed\n"); 546 printk(TPACPI_ERR "kzalloc(ibm->driver) failed\n");
418 return -ENOMEM; 547 return -ENOMEM;
419 } 548 }
420 549
421 sprintf(ibm->acpi->driver->name, "%s_%s", IBM_NAME, ibm->name); 550 sprintf(ibm->acpi->driver->name, "%s_%s", TPACPI_NAME, ibm->name);
422 ibm->acpi->driver->ids = ibm->acpi->hid; 551 ibm->acpi->driver->ids = ibm->acpi->hid;
423 552
424 ibm->acpi->driver->ops.add = &tpacpi_device_add; 553 ibm->acpi->driver->ops.add = &tpacpi_device_add;
425 554
426 rc = acpi_bus_register_driver(ibm->acpi->driver); 555 rc = acpi_bus_register_driver(ibm->acpi->driver);
427 if (rc < 0) { 556 if (rc < 0) {
428 printk(IBM_ERR "acpi_bus_register_driver(%s) failed: %d\n", 557 printk(TPACPI_ERR "acpi_bus_register_driver(%s) failed: %d\n",
429 ibm->name, rc); 558 ibm->name, rc);
430 kfree(ibm->acpi->driver); 559 kfree(ibm->acpi->driver);
431 ibm->acpi->driver = NULL; 560 ibm->acpi->driver = NULL;
@@ -470,7 +599,7 @@ static int dispatch_procfs_read(char *page, char **start, off_t off,
470} 599}
471 600
472static int dispatch_procfs_write(struct file *file, 601static int dispatch_procfs_write(struct file *file,
473 const char __user * userbuf, 602 const char __user *userbuf,
474 unsigned long count, void *data) 603 unsigned long count, void *data)
475{ 604{
476 struct ibm_struct *ibm = data; 605 struct ibm_struct *ibm = data;
@@ -530,7 +659,22 @@ static struct platform_device *tpacpi_sensors_pdev;
530static struct device *tpacpi_hwmon; 659static struct device *tpacpi_hwmon;
531static struct input_dev *tpacpi_inputdev; 660static struct input_dev *tpacpi_inputdev;
532static struct mutex tpacpi_inputdev_send_mutex; 661static struct mutex tpacpi_inputdev_send_mutex;
662static LIST_HEAD(tpacpi_all_drivers);
663
664static int tpacpi_suspend_handler(struct platform_device *pdev,
665 pm_message_t state)
666{
667 struct ibm_struct *ibm, *itmp;
668
669 list_for_each_entry_safe(ibm, itmp,
670 &tpacpi_all_drivers,
671 all_drivers) {
672 if (ibm->suspend)
673 (ibm->suspend)(state);
674 }
533 675
676 return 0;
677}
534 678
535static int tpacpi_resume_handler(struct platform_device *pdev) 679static int tpacpi_resume_handler(struct platform_device *pdev)
536{ 680{
@@ -548,107 +692,36 @@ static int tpacpi_resume_handler(struct platform_device *pdev)
548 692
549static struct platform_driver tpacpi_pdriver = { 693static struct platform_driver tpacpi_pdriver = {
550 .driver = { 694 .driver = {
551 .name = IBM_DRVR_NAME, 695 .name = TPACPI_DRVR_NAME,
552 .owner = THIS_MODULE, 696 .owner = THIS_MODULE,
553 }, 697 },
698 .suspend = tpacpi_suspend_handler,
554 .resume = tpacpi_resume_handler, 699 .resume = tpacpi_resume_handler,
555}; 700};
556 701
557static struct platform_driver tpacpi_hwmon_pdriver = { 702static struct platform_driver tpacpi_hwmon_pdriver = {
558 .driver = { 703 .driver = {
559 .name = IBM_HWMON_DRVR_NAME, 704 .name = TPACPI_HWMON_DRVR_NAME,
560 .owner = THIS_MODULE, 705 .owner = THIS_MODULE,
561 }, 706 },
562}; 707};
563 708
564/************************************************************************* 709/*************************************************************************
565 * thinkpad-acpi driver attributes 710 * sysfs support helpers
566 */ 711 */
567 712
568/* interface_version --------------------------------------------------- */ 713struct attribute_set {
569static ssize_t tpacpi_driver_interface_version_show( 714 unsigned int members, max_members;
570 struct device_driver *drv, 715 struct attribute_group group;
571 char *buf)
572{
573 return snprintf(buf, PAGE_SIZE, "0x%08x\n", TPACPI_SYSFS_VERSION);
574}
575
576static DRIVER_ATTR(interface_version, S_IRUGO,
577 tpacpi_driver_interface_version_show, NULL);
578
579/* debug_level --------------------------------------------------------- */
580static ssize_t tpacpi_driver_debug_show(struct device_driver *drv,
581 char *buf)
582{
583 return snprintf(buf, PAGE_SIZE, "0x%04x\n", dbg_level);
584}
585
586static ssize_t tpacpi_driver_debug_store(struct device_driver *drv,
587 const char *buf, size_t count)
588{
589 unsigned long t;
590
591 if (parse_strtoul(buf, 0xffff, &t))
592 return -EINVAL;
593
594 dbg_level = t;
595
596 return count;
597}
598
599static DRIVER_ATTR(debug_level, S_IWUSR | S_IRUGO,
600 tpacpi_driver_debug_show, tpacpi_driver_debug_store);
601
602/* version ------------------------------------------------------------- */
603static ssize_t tpacpi_driver_version_show(struct device_driver *drv,
604 char *buf)
605{
606 return snprintf(buf, PAGE_SIZE, "%s v%s\n", IBM_DESC, IBM_VERSION);
607}
608
609static DRIVER_ATTR(version, S_IRUGO,
610 tpacpi_driver_version_show, NULL);
611
612/* --------------------------------------------------------------------- */
613
614static struct driver_attribute* tpacpi_driver_attributes[] = {
615 &driver_attr_debug_level, &driver_attr_version,
616 &driver_attr_interface_version,
617}; 716};
618 717
619static int __init tpacpi_create_driver_attributes(struct device_driver *drv)
620{
621 int i, res;
622
623 i = 0;
624 res = 0;
625 while (!res && i < ARRAY_SIZE(tpacpi_driver_attributes)) {
626 res = driver_create_file(drv, tpacpi_driver_attributes[i]);
627 i++;
628 }
629
630 return res;
631}
632
633static void tpacpi_remove_driver_attributes(struct device_driver *drv)
634{
635 int i;
636
637 for(i = 0; i < ARRAY_SIZE(tpacpi_driver_attributes); i++)
638 driver_remove_file(drv, tpacpi_driver_attributes[i]);
639}
640
641/*************************************************************************
642 * sysfs support helpers
643 */
644
645struct attribute_set_obj { 718struct attribute_set_obj {
646 struct attribute_set s; 719 struct attribute_set s;
647 struct attribute *a; 720 struct attribute *a;
648} __attribute__((packed)); 721} __attribute__((packed));
649 722
650static struct attribute_set *create_attr_set(unsigned int max_members, 723static struct attribute_set *create_attr_set(unsigned int max_members,
651 const char* name) 724 const char *name)
652{ 725{
653 struct attribute_set_obj *sobj; 726 struct attribute_set_obj *sobj;
654 727
@@ -668,8 +741,11 @@ static struct attribute_set *create_attr_set(unsigned int max_members,
668 return &sobj->s; 741 return &sobj->s;
669} 742}
670 743
744#define destroy_attr_set(_set) \
745 kfree(_set);
746
671/* not multi-threaded safe, use it in a single thread per set */ 747/* not multi-threaded safe, use it in a single thread per set */
672static int add_to_attr_set(struct attribute_set* s, struct attribute *attr) 748static int add_to_attr_set(struct attribute_set *s, struct attribute *attr)
673{ 749{
674 if (!s || !attr) 750 if (!s || !attr)
675 return -EINVAL; 751 return -EINVAL;
@@ -683,7 +759,7 @@ static int add_to_attr_set(struct attribute_set* s, struct attribute *attr)
683 return 0; 759 return 0;
684} 760}
685 761
686static int add_many_to_attr_set(struct attribute_set* s, 762static int add_many_to_attr_set(struct attribute_set *s,
687 struct attribute **attr, 763 struct attribute **attr,
688 unsigned int count) 764 unsigned int count)
689{ 765{
@@ -698,12 +774,15 @@ static int add_many_to_attr_set(struct attribute_set* s,
698 return 0; 774 return 0;
699} 775}
700 776
701static void delete_attr_set(struct attribute_set* s, struct kobject *kobj) 777static void delete_attr_set(struct attribute_set *s, struct kobject *kobj)
702{ 778{
703 sysfs_remove_group(kobj, &s->group); 779 sysfs_remove_group(kobj, &s->group);
704 destroy_attr_set(s); 780 destroy_attr_set(s);
705} 781}
706 782
783#define register_attr_set_with_sysfs(_attr_set, _kobj) \
784 sysfs_create_group(_kobj, &_attr_set->group)
785
707static int parse_strtoul(const char *buf, 786static int parse_strtoul(const char *buf,
708 unsigned long max, unsigned long *value) 787 unsigned long max, unsigned long *value)
709{ 788{
@@ -720,6 +799,84 @@ static int parse_strtoul(const char *buf,
720 return 0; 799 return 0;
721} 800}
722 801
802/*************************************************************************
803 * thinkpad-acpi driver attributes
804 */
805
806/* interface_version --------------------------------------------------- */
807static ssize_t tpacpi_driver_interface_version_show(
808 struct device_driver *drv,
809 char *buf)
810{
811 return snprintf(buf, PAGE_SIZE, "0x%08x\n", TPACPI_SYSFS_VERSION);
812}
813
814static DRIVER_ATTR(interface_version, S_IRUGO,
815 tpacpi_driver_interface_version_show, NULL);
816
817/* debug_level --------------------------------------------------------- */
818static ssize_t tpacpi_driver_debug_show(struct device_driver *drv,
819 char *buf)
820{
821 return snprintf(buf, PAGE_SIZE, "0x%04x\n", dbg_level);
822}
823
824static ssize_t tpacpi_driver_debug_store(struct device_driver *drv,
825 const char *buf, size_t count)
826{
827 unsigned long t;
828
829 if (parse_strtoul(buf, 0xffff, &t))
830 return -EINVAL;
831
832 dbg_level = t;
833
834 return count;
835}
836
837static DRIVER_ATTR(debug_level, S_IWUSR | S_IRUGO,
838 tpacpi_driver_debug_show, tpacpi_driver_debug_store);
839
840/* version ------------------------------------------------------------- */
841static ssize_t tpacpi_driver_version_show(struct device_driver *drv,
842 char *buf)
843{
844 return snprintf(buf, PAGE_SIZE, "%s v%s\n",
845 TPACPI_DESC, TPACPI_VERSION);
846}
847
848static DRIVER_ATTR(version, S_IRUGO,
849 tpacpi_driver_version_show, NULL);
850
851/* --------------------------------------------------------------------- */
852
853static struct driver_attribute *tpacpi_driver_attributes[] = {
854 &driver_attr_debug_level, &driver_attr_version,
855 &driver_attr_interface_version,
856};
857
858static int __init tpacpi_create_driver_attributes(struct device_driver *drv)
859{
860 int i, res;
861
862 i = 0;
863 res = 0;
864 while (!res && i < ARRAY_SIZE(tpacpi_driver_attributes)) {
865 res = driver_create_file(drv, tpacpi_driver_attributes[i]);
866 i++;
867 }
868
869 return res;
870}
871
872static void tpacpi_remove_driver_attributes(struct device_driver *drv)
873{
874 int i;
875
876 for (i = 0; i < ARRAY_SIZE(tpacpi_driver_attributes); i++)
877 driver_remove_file(drv, tpacpi_driver_attributes[i]);
878}
879
723/**************************************************************************** 880/****************************************************************************
724 **************************************************************************** 881 ****************************************************************************
725 * 882 *
@@ -734,17 +891,17 @@ static int parse_strtoul(const char *buf,
734 891
735static int __init thinkpad_acpi_driver_init(struct ibm_init_struct *iibm) 892static int __init thinkpad_acpi_driver_init(struct ibm_init_struct *iibm)
736{ 893{
737 printk(IBM_INFO "%s v%s\n", IBM_DESC, IBM_VERSION); 894 printk(TPACPI_INFO "%s v%s\n", TPACPI_DESC, TPACPI_VERSION);
738 printk(IBM_INFO "%s\n", IBM_URL); 895 printk(TPACPI_INFO "%s\n", TPACPI_URL);
739 896
740 printk(IBM_INFO "ThinkPad BIOS %s, EC %s\n", 897 printk(TPACPI_INFO "ThinkPad BIOS %s, EC %s\n",
741 (thinkpad_id.bios_version_str) ? 898 (thinkpad_id.bios_version_str) ?
742 thinkpad_id.bios_version_str : "unknown", 899 thinkpad_id.bios_version_str : "unknown",
743 (thinkpad_id.ec_version_str) ? 900 (thinkpad_id.ec_version_str) ?
744 thinkpad_id.ec_version_str : "unknown"); 901 thinkpad_id.ec_version_str : "unknown");
745 902
746 if (thinkpad_id.vendor && thinkpad_id.model_str) 903 if (thinkpad_id.vendor && thinkpad_id.model_str)
747 printk(IBM_INFO "%s %s\n", 904 printk(TPACPI_INFO "%s %s\n",
748 (thinkpad_id.vendor == PCI_VENDOR_ID_IBM) ? 905 (thinkpad_id.vendor == PCI_VENDOR_ID_IBM) ?
749 "IBM" : ((thinkpad_id.vendor == 906 "IBM" : ((thinkpad_id.vendor ==
750 PCI_VENDOR_ID_LENOVO) ? 907 PCI_VENDOR_ID_LENOVO) ?
@@ -758,8 +915,8 @@ static int thinkpad_acpi_driver_read(char *p)
758{ 915{
759 int len = 0; 916 int len = 0;
760 917
761 len += sprintf(p + len, "driver:\t\t%s\n", IBM_DESC); 918 len += sprintf(p + len, "driver:\t\t%s\n", TPACPI_DESC);
762 len += sprintf(p + len, "version:\t%s\n", IBM_VERSION); 919 len += sprintf(p + len, "version:\t%s\n", TPACPI_VERSION);
763 920
764 return len; 921 return len;
765} 922}
@@ -773,15 +930,129 @@ static struct ibm_struct thinkpad_acpi_driver_data = {
773 * Hotkey subdriver 930 * Hotkey subdriver
774 */ 931 */
775 932
933enum { /* hot key scan codes (derived from ACPI DSDT) */
934 TP_ACPI_HOTKEYSCAN_FNF1 = 0,
935 TP_ACPI_HOTKEYSCAN_FNF2,
936 TP_ACPI_HOTKEYSCAN_FNF3,
937 TP_ACPI_HOTKEYSCAN_FNF4,
938 TP_ACPI_HOTKEYSCAN_FNF5,
939 TP_ACPI_HOTKEYSCAN_FNF6,
940 TP_ACPI_HOTKEYSCAN_FNF7,
941 TP_ACPI_HOTKEYSCAN_FNF8,
942 TP_ACPI_HOTKEYSCAN_FNF9,
943 TP_ACPI_HOTKEYSCAN_FNF10,
944 TP_ACPI_HOTKEYSCAN_FNF11,
945 TP_ACPI_HOTKEYSCAN_FNF12,
946 TP_ACPI_HOTKEYSCAN_FNBACKSPACE,
947 TP_ACPI_HOTKEYSCAN_FNINSERT,
948 TP_ACPI_HOTKEYSCAN_FNDELETE,
949 TP_ACPI_HOTKEYSCAN_FNHOME,
950 TP_ACPI_HOTKEYSCAN_FNEND,
951 TP_ACPI_HOTKEYSCAN_FNPAGEUP,
952 TP_ACPI_HOTKEYSCAN_FNPAGEDOWN,
953 TP_ACPI_HOTKEYSCAN_FNSPACE,
954 TP_ACPI_HOTKEYSCAN_VOLUMEUP,
955 TP_ACPI_HOTKEYSCAN_VOLUMEDOWN,
956 TP_ACPI_HOTKEYSCAN_MUTE,
957 TP_ACPI_HOTKEYSCAN_THINKPAD,
958};
959
960enum { /* Keys available through NVRAM polling */
961 TPACPI_HKEY_NVRAM_KNOWN_MASK = 0x00fb88c0U,
962 TPACPI_HKEY_NVRAM_GOOD_MASK = 0x00fb8000U,
963};
964
965enum { /* Positions of some of the keys in hotkey masks */
966 TP_ACPI_HKEY_DISPSWTCH_MASK = 1 << TP_ACPI_HOTKEYSCAN_FNF7,
967 TP_ACPI_HKEY_DISPXPAND_MASK = 1 << TP_ACPI_HOTKEYSCAN_FNF8,
968 TP_ACPI_HKEY_HIBERNATE_MASK = 1 << TP_ACPI_HOTKEYSCAN_FNF12,
969 TP_ACPI_HKEY_BRGHTUP_MASK = 1 << TP_ACPI_HOTKEYSCAN_FNHOME,
970 TP_ACPI_HKEY_BRGHTDWN_MASK = 1 << TP_ACPI_HOTKEYSCAN_FNEND,
971 TP_ACPI_HKEY_THNKLGHT_MASK = 1 << TP_ACPI_HOTKEYSCAN_FNPAGEUP,
972 TP_ACPI_HKEY_ZOOM_MASK = 1 << TP_ACPI_HOTKEYSCAN_FNSPACE,
973 TP_ACPI_HKEY_VOLUP_MASK = 1 << TP_ACPI_HOTKEYSCAN_VOLUMEUP,
974 TP_ACPI_HKEY_VOLDWN_MASK = 1 << TP_ACPI_HOTKEYSCAN_VOLUMEDOWN,
975 TP_ACPI_HKEY_MUTE_MASK = 1 << TP_ACPI_HOTKEYSCAN_MUTE,
976 TP_ACPI_HKEY_THINKPAD_MASK = 1 << TP_ACPI_HOTKEYSCAN_THINKPAD,
977};
978
979enum { /* NVRAM to ACPI HKEY group map */
980 TP_NVRAM_HKEY_GROUP_HK2 = TP_ACPI_HKEY_THINKPAD_MASK |
981 TP_ACPI_HKEY_ZOOM_MASK |
982 TP_ACPI_HKEY_DISPSWTCH_MASK |
983 TP_ACPI_HKEY_HIBERNATE_MASK,
984 TP_NVRAM_HKEY_GROUP_BRIGHTNESS = TP_ACPI_HKEY_BRGHTUP_MASK |
985 TP_ACPI_HKEY_BRGHTDWN_MASK,
986 TP_NVRAM_HKEY_GROUP_VOLUME = TP_ACPI_HKEY_VOLUP_MASK |
987 TP_ACPI_HKEY_VOLDWN_MASK |
988 TP_ACPI_HKEY_MUTE_MASK,
989};
990
991#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL
992struct tp_nvram_state {
993 u16 thinkpad_toggle:1;
994 u16 zoom_toggle:1;
995 u16 display_toggle:1;
996 u16 thinklight_toggle:1;
997 u16 hibernate_toggle:1;
998 u16 displayexp_toggle:1;
999 u16 display_state:1;
1000 u16 brightness_toggle:1;
1001 u16 volume_toggle:1;
1002 u16 mute:1;
1003
1004 u8 brightness_level;
1005 u8 volume_level;
1006};
1007
1008static struct task_struct *tpacpi_hotkey_task;
1009static u32 hotkey_source_mask; /* bit mask 0=ACPI,1=NVRAM */
1010static int hotkey_poll_freq = 10; /* Hz */
1011static struct mutex hotkey_thread_mutex;
1012static struct mutex hotkey_thread_data_mutex;
1013static unsigned int hotkey_config_change;
1014
1015#else /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */
1016
1017#define hotkey_source_mask 0U
1018
1019#endif /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */
1020
1021static struct mutex hotkey_mutex;
1022
1023static enum { /* Reasons for waking up */
1024 TP_ACPI_WAKEUP_NONE = 0, /* None or unknown */
1025 TP_ACPI_WAKEUP_BAYEJ, /* Bay ejection request */
1026 TP_ACPI_WAKEUP_UNDOCK, /* Undock request */
1027} hotkey_wakeup_reason;
1028
1029static int hotkey_autosleep_ack;
1030
776static int hotkey_orig_status; 1031static int hotkey_orig_status;
777static u32 hotkey_orig_mask; 1032static u32 hotkey_orig_mask;
778static u32 hotkey_all_mask; 1033static u32 hotkey_all_mask;
779static u32 hotkey_reserved_mask; 1034static u32 hotkey_reserved_mask;
1035static u32 hotkey_mask;
1036
1037static unsigned int hotkey_report_mode;
780 1038
781static u16 *hotkey_keycode_map; 1039static u16 *hotkey_keycode_map;
782 1040
783static struct attribute_set *hotkey_dev_attributes; 1041static struct attribute_set *hotkey_dev_attributes;
784 1042
1043#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL
1044#define HOTKEY_CONFIG_CRITICAL_START \
1045 do { \
1046 mutex_lock(&hotkey_thread_data_mutex); \
1047 hotkey_config_change++; \
1048 } while (0);
1049#define HOTKEY_CONFIG_CRITICAL_END \
1050 mutex_unlock(&hotkey_thread_data_mutex);
1051#else
1052#define HOTKEY_CONFIG_CRITICAL_START
1053#define HOTKEY_CONFIG_CRITICAL_END
1054#endif /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */
1055
785static int hotkey_get_wlsw(int *status) 1056static int hotkey_get_wlsw(int *status)
786{ 1057{
787 if (!acpi_evalf(hkey_handle, status, "WLSW", "d")) 1058 if (!acpi_evalf(hkey_handle, status, "WLSW", "d"))
@@ -789,15 +1060,400 @@ static int hotkey_get_wlsw(int *status)
789 return 0; 1060 return 0;
790} 1061}
791 1062
1063/*
1064 * Call with hotkey_mutex held
1065 */
1066static int hotkey_mask_get(void)
1067{
1068 u32 m = 0;
1069
1070 if (tp_features.hotkey_mask) {
1071 if (!acpi_evalf(hkey_handle, &m, "DHKN", "d"))
1072 return -EIO;
1073 }
1074 hotkey_mask = m | (hotkey_source_mask & hotkey_mask);
1075
1076 return 0;
1077}
1078
1079/*
1080 * Call with hotkey_mutex held
1081 */
1082static int hotkey_mask_set(u32 mask)
1083{
1084 int i;
1085 int rc = 0;
1086
1087 if (tp_features.hotkey_mask) {
1088 HOTKEY_CONFIG_CRITICAL_START
1089 for (i = 0; i < 32; i++) {
1090 u32 m = 1 << i;
1091 /* enable in firmware mask only keys not in NVRAM
1092 * mode, but enable the key in the cached hotkey_mask
1093 * regardless of mode, or the key will end up
1094 * disabled by hotkey_mask_get() */
1095 if (!acpi_evalf(hkey_handle,
1096 NULL, "MHKM", "vdd", i + 1,
1097 !!((mask & ~hotkey_source_mask) & m))) {
1098 rc = -EIO;
1099 break;
1100 } else {
1101 hotkey_mask = (hotkey_mask & ~m) | (mask & m);
1102 }
1103 }
1104 HOTKEY_CONFIG_CRITICAL_END
1105
1106 /* hotkey_mask_get must be called unconditionally below */
1107 if (!hotkey_mask_get() && !rc &&
1108 (hotkey_mask & ~hotkey_source_mask) !=
1109 (mask & ~hotkey_source_mask)) {
1110 printk(TPACPI_NOTICE
1111 "requested hot key mask 0x%08x, but "
1112 "firmware forced it to 0x%08x\n",
1113 mask, hotkey_mask);
1114 }
1115 } else {
1116#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL
1117 HOTKEY_CONFIG_CRITICAL_START
1118 hotkey_mask = mask & hotkey_source_mask;
1119 HOTKEY_CONFIG_CRITICAL_END
1120 hotkey_mask_get();
1121 if (hotkey_mask != mask) {
1122 printk(TPACPI_NOTICE
1123 "requested hot key mask 0x%08x, "
1124 "forced to 0x%08x (NVRAM poll mask is "
1125 "0x%08x): no firmware mask support\n",
1126 mask, hotkey_mask, hotkey_source_mask);
1127 }
1128#else
1129 hotkey_mask_get();
1130 rc = -ENXIO;
1131#endif /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */
1132 }
1133
1134 return rc;
1135}
1136
1137static int hotkey_status_get(int *status)
1138{
1139 if (!acpi_evalf(hkey_handle, status, "DHKC", "d"))
1140 return -EIO;
1141
1142 return 0;
1143}
1144
1145static int hotkey_status_set(int status)
1146{
1147 if (!acpi_evalf(hkey_handle, NULL, "MHKC", "vd", status))
1148 return -EIO;
1149
1150 return 0;
1151}
1152
1153static void tpacpi_input_send_radiosw(void)
1154{
1155 int wlsw;
1156
1157 mutex_lock(&tpacpi_inputdev_send_mutex);
1158
1159 if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&wlsw)) {
1160 input_report_switch(tpacpi_inputdev,
1161 SW_RADIO, !!wlsw);
1162 input_sync(tpacpi_inputdev);
1163 }
1164
1165 mutex_unlock(&tpacpi_inputdev_send_mutex);
1166}
1167
1168static void tpacpi_input_send_key(unsigned int scancode)
1169{
1170 unsigned int keycode;
1171
1172 keycode = hotkey_keycode_map[scancode];
1173
1174 if (keycode != KEY_RESERVED) {
1175 mutex_lock(&tpacpi_inputdev_send_mutex);
1176
1177 input_report_key(tpacpi_inputdev, keycode, 1);
1178 if (keycode == KEY_UNKNOWN)
1179 input_event(tpacpi_inputdev, EV_MSC, MSC_SCAN,
1180 scancode);
1181 input_sync(tpacpi_inputdev);
1182
1183 input_report_key(tpacpi_inputdev, keycode, 0);
1184 if (keycode == KEY_UNKNOWN)
1185 input_event(tpacpi_inputdev, EV_MSC, MSC_SCAN,
1186 scancode);
1187 input_sync(tpacpi_inputdev);
1188
1189 mutex_unlock(&tpacpi_inputdev_send_mutex);
1190 }
1191}
1192
1193#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL
1194static struct tp_acpi_drv_struct ibm_hotkey_acpidriver;
1195
1196static void tpacpi_hotkey_send_key(unsigned int scancode)
1197{
1198 tpacpi_input_send_key(scancode);
1199 if (hotkey_report_mode < 2) {
1200 acpi_bus_generate_proc_event(ibm_hotkey_acpidriver.device,
1201 0x80, 0x1001 + scancode);
1202 }
1203}
1204
1205static void hotkey_read_nvram(struct tp_nvram_state *n, u32 m)
1206{
1207 u8 d;
1208
1209 if (m & TP_NVRAM_HKEY_GROUP_HK2) {
1210 d = nvram_read_byte(TP_NVRAM_ADDR_HK2);
1211 n->thinkpad_toggle = !!(d & TP_NVRAM_MASK_HKT_THINKPAD);
1212 n->zoom_toggle = !!(d & TP_NVRAM_MASK_HKT_ZOOM);
1213 n->display_toggle = !!(d & TP_NVRAM_MASK_HKT_DISPLAY);
1214 n->hibernate_toggle = !!(d & TP_NVRAM_MASK_HKT_HIBERNATE);
1215 }
1216 if (m & TP_ACPI_HKEY_THNKLGHT_MASK) {
1217 d = nvram_read_byte(TP_NVRAM_ADDR_THINKLIGHT);
1218 n->thinklight_toggle = !!(d & TP_NVRAM_MASK_THINKLIGHT);
1219 }
1220 if (m & TP_ACPI_HKEY_DISPXPAND_MASK) {
1221 d = nvram_read_byte(TP_NVRAM_ADDR_VIDEO);
1222 n->displayexp_toggle =
1223 !!(d & TP_NVRAM_MASK_HKT_DISPEXPND);
1224 }
1225 if (m & TP_NVRAM_HKEY_GROUP_BRIGHTNESS) {
1226 d = nvram_read_byte(TP_NVRAM_ADDR_BRIGHTNESS);
1227 n->brightness_level = (d & TP_NVRAM_MASK_LEVEL_BRIGHTNESS)
1228 >> TP_NVRAM_POS_LEVEL_BRIGHTNESS;
1229 n->brightness_toggle =
1230 !!(d & TP_NVRAM_MASK_HKT_BRIGHTNESS);
1231 }
1232 if (m & TP_NVRAM_HKEY_GROUP_VOLUME) {
1233 d = nvram_read_byte(TP_NVRAM_ADDR_MIXER);
1234 n->volume_level = (d & TP_NVRAM_MASK_LEVEL_VOLUME)
1235 >> TP_NVRAM_POS_LEVEL_VOLUME;
1236 n->mute = !!(d & TP_NVRAM_MASK_MUTE);
1237 n->volume_toggle = !!(d & TP_NVRAM_MASK_HKT_VOLUME);
1238 }
1239}
1240
1241#define TPACPI_COMPARE_KEY(__scancode, __member) \
1242 do { \
1243 if ((mask & (1 << __scancode)) && \
1244 oldn->__member != newn->__member) \
1245 tpacpi_hotkey_send_key(__scancode); \
1246 } while (0)
1247
1248#define TPACPI_MAY_SEND_KEY(__scancode) \
1249 do { if (mask & (1 << __scancode)) \
1250 tpacpi_hotkey_send_key(__scancode); } while (0)
1251
1252static void hotkey_compare_and_issue_event(struct tp_nvram_state *oldn,
1253 struct tp_nvram_state *newn,
1254 u32 mask)
1255{
1256 TPACPI_COMPARE_KEY(TP_ACPI_HOTKEYSCAN_THINKPAD, thinkpad_toggle);
1257 TPACPI_COMPARE_KEY(TP_ACPI_HOTKEYSCAN_FNSPACE, zoom_toggle);
1258 TPACPI_COMPARE_KEY(TP_ACPI_HOTKEYSCAN_FNF7, display_toggle);
1259 TPACPI_COMPARE_KEY(TP_ACPI_HOTKEYSCAN_FNF12, hibernate_toggle);
1260
1261 TPACPI_COMPARE_KEY(TP_ACPI_HOTKEYSCAN_FNPAGEUP, thinklight_toggle);
1262
1263 TPACPI_COMPARE_KEY(TP_ACPI_HOTKEYSCAN_FNF8, displayexp_toggle);
1264
1265 /* handle volume */
1266 if (oldn->volume_toggle != newn->volume_toggle) {
1267 if (oldn->mute != newn->mute) {
1268 TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_MUTE);
1269 }
1270 if (oldn->volume_level > newn->volume_level) {
1271 TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_VOLUMEDOWN);
1272 } else if (oldn->volume_level < newn->volume_level) {
1273 TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_VOLUMEUP);
1274 } else if (oldn->mute == newn->mute) {
1275 /* repeated key presses that didn't change state */
1276 if (newn->mute) {
1277 TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_MUTE);
1278 } else if (newn->volume_level != 0) {
1279 TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_VOLUMEUP);
1280 } else {
1281 TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_VOLUMEDOWN);
1282 }
1283 }
1284 }
1285
1286 /* handle brightness */
1287 if (oldn->brightness_toggle != newn->brightness_toggle) {
1288 if (oldn->brightness_level < newn->brightness_level) {
1289 TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_FNHOME);
1290 } else if (oldn->brightness_level > newn->brightness_level) {
1291 TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_FNEND);
1292 } else {
1293 /* repeated key presses that didn't change state */
1294 if (newn->brightness_level != 0) {
1295 TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_FNHOME);
1296 } else {
1297 TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_FNEND);
1298 }
1299 }
1300 }
1301}
1302
1303#undef TPACPI_COMPARE_KEY
1304#undef TPACPI_MAY_SEND_KEY
1305
1306static int hotkey_kthread(void *data)
1307{
1308 struct tp_nvram_state s[2];
1309 u32 mask;
1310 unsigned int si, so;
1311 unsigned long t;
1312 unsigned int change_detector, must_reset;
1313
1314 mutex_lock(&hotkey_thread_mutex);
1315
1316 if (tpacpi_lifecycle == TPACPI_LIFE_EXITING)
1317 goto exit;
1318
1319 set_freezable();
1320
1321 so = 0;
1322 si = 1;
1323 t = 0;
1324
1325 /* Initial state for compares */
1326 mutex_lock(&hotkey_thread_data_mutex);
1327 change_detector = hotkey_config_change;
1328 mask = hotkey_source_mask & hotkey_mask;
1329 mutex_unlock(&hotkey_thread_data_mutex);
1330 hotkey_read_nvram(&s[so], mask);
1331
1332 while (!kthread_should_stop() && hotkey_poll_freq) {
1333 if (t == 0)
1334 t = 1000/hotkey_poll_freq;
1335 t = msleep_interruptible(t);
1336 if (unlikely(kthread_should_stop()))
1337 break;
1338 must_reset = try_to_freeze();
1339 if (t > 0 && !must_reset)
1340 continue;
1341
1342 mutex_lock(&hotkey_thread_data_mutex);
1343 if (must_reset || hotkey_config_change != change_detector) {
1344 /* forget old state on thaw or config change */
1345 si = so;
1346 t = 0;
1347 change_detector = hotkey_config_change;
1348 }
1349 mask = hotkey_source_mask & hotkey_mask;
1350 mutex_unlock(&hotkey_thread_data_mutex);
1351
1352 if (likely(mask)) {
1353 hotkey_read_nvram(&s[si], mask);
1354 if (likely(si != so)) {
1355 hotkey_compare_and_issue_event(&s[so], &s[si],
1356 mask);
1357 }
1358 }
1359
1360 so = si;
1361 si ^= 1;
1362 }
1363
1364exit:
1365 mutex_unlock(&hotkey_thread_mutex);
1366 return 0;
1367}
1368
1369static void hotkey_poll_stop_sync(void)
1370{
1371 if (tpacpi_hotkey_task) {
1372 if (frozen(tpacpi_hotkey_task) ||
1373 freezing(tpacpi_hotkey_task))
1374 thaw_process(tpacpi_hotkey_task);
1375
1376 kthread_stop(tpacpi_hotkey_task);
1377 tpacpi_hotkey_task = NULL;
1378 mutex_lock(&hotkey_thread_mutex);
1379 /* at this point, the thread did exit */
1380 mutex_unlock(&hotkey_thread_mutex);
1381 }
1382}
1383
1384/* call with hotkey_mutex held */
1385static void hotkey_poll_setup(int may_warn)
1386{
1387 if ((hotkey_source_mask & hotkey_mask) != 0 &&
1388 hotkey_poll_freq > 0 &&
1389 (tpacpi_inputdev->users > 0 || hotkey_report_mode < 2)) {
1390 if (!tpacpi_hotkey_task) {
1391 tpacpi_hotkey_task = kthread_run(hotkey_kthread,
1392 NULL,
1393 TPACPI_FILE "d");
1394 if (IS_ERR(tpacpi_hotkey_task)) {
1395 tpacpi_hotkey_task = NULL;
1396 printk(TPACPI_ERR
1397 "could not create kernel thread "
1398 "for hotkey polling\n");
1399 }
1400 }
1401 } else {
1402 hotkey_poll_stop_sync();
1403 if (may_warn &&
1404 hotkey_source_mask != 0 && hotkey_poll_freq == 0) {
1405 printk(TPACPI_NOTICE
1406 "hot keys 0x%08x require polling, "
1407 "which is currently disabled\n",
1408 hotkey_source_mask);
1409 }
1410 }
1411}
1412
1413static void hotkey_poll_setup_safe(int may_warn)
1414{
1415 mutex_lock(&hotkey_mutex);
1416 hotkey_poll_setup(may_warn);
1417 mutex_unlock(&hotkey_mutex);
1418}
1419
1420static int hotkey_inputdev_open(struct input_dev *dev)
1421{
1422 switch (tpacpi_lifecycle) {
1423 case TPACPI_LIFE_INIT:
1424 /*
1425 * hotkey_init will call hotkey_poll_setup_safe
1426 * at the appropriate moment
1427 */
1428 return 0;
1429 case TPACPI_LIFE_EXITING:
1430 return -EBUSY;
1431 case TPACPI_LIFE_RUNNING:
1432 hotkey_poll_setup_safe(0);
1433 return 0;
1434 }
1435
1436 /* Should only happen if tpacpi_lifecycle is corrupt */
1437 BUG();
1438 return -EBUSY;
1439}
1440
1441static void hotkey_inputdev_close(struct input_dev *dev)
1442{
1443 /* disable hotkey polling when possible */
1444 if (tpacpi_lifecycle == TPACPI_LIFE_RUNNING)
1445 hotkey_poll_setup_safe(0);
1446}
1447#endif /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */
1448
792/* sysfs hotkey enable ------------------------------------------------- */ 1449/* sysfs hotkey enable ------------------------------------------------- */
793static ssize_t hotkey_enable_show(struct device *dev, 1450static ssize_t hotkey_enable_show(struct device *dev,
794 struct device_attribute *attr, 1451 struct device_attribute *attr,
795 char *buf) 1452 char *buf)
796{ 1453{
797 int res, status; 1454 int res, status;
798 u32 mask;
799 1455
800 res = hotkey_get(&status, &mask); 1456 res = hotkey_status_get(&status);
801 if (res) 1457 if (res)
802 return res; 1458 return res;
803 1459
@@ -809,15 +1465,12 @@ static ssize_t hotkey_enable_store(struct device *dev,
809 const char *buf, size_t count) 1465 const char *buf, size_t count)
810{ 1466{
811 unsigned long t; 1467 unsigned long t;
812 int res, status; 1468 int res;
813 u32 mask;
814 1469
815 if (parse_strtoul(buf, 1, &t)) 1470 if (parse_strtoul(buf, 1, &t))
816 return -EINVAL; 1471 return -EINVAL;
817 1472
818 res = hotkey_get(&status, &mask); 1473 res = hotkey_status_set(t);
819 if (!res)
820 res = hotkey_set(t, mask);
821 1474
822 return (res) ? res : count; 1475 return (res) ? res : count;
823} 1476}
@@ -831,14 +1484,15 @@ static ssize_t hotkey_mask_show(struct device *dev,
831 struct device_attribute *attr, 1484 struct device_attribute *attr,
832 char *buf) 1485 char *buf)
833{ 1486{
834 int res, status; 1487 int res;
835 u32 mask;
836 1488
837 res = hotkey_get(&status, &mask); 1489 if (mutex_lock_interruptible(&hotkey_mutex))
838 if (res) 1490 return -ERESTARTSYS;
839 return res; 1491 res = hotkey_mask_get();
1492 mutex_unlock(&hotkey_mutex);
840 1493
841 return snprintf(buf, PAGE_SIZE, "0x%08x\n", mask); 1494 return (res)?
1495 res : snprintf(buf, PAGE_SIZE, "0x%08x\n", hotkey_mask);
842} 1496}
843 1497
844static ssize_t hotkey_mask_store(struct device *dev, 1498static ssize_t hotkey_mask_store(struct device *dev,
@@ -846,15 +1500,21 @@ static ssize_t hotkey_mask_store(struct device *dev,
846 const char *buf, size_t count) 1500 const char *buf, size_t count)
847{ 1501{
848 unsigned long t; 1502 unsigned long t;
849 int res, status; 1503 int res;
850 u32 mask;
851 1504
852 if (parse_strtoul(buf, 0xffffffffUL, &t)) 1505 if (parse_strtoul(buf, 0xffffffffUL, &t))
853 return -EINVAL; 1506 return -EINVAL;
854 1507
855 res = hotkey_get(&status, &mask); 1508 if (mutex_lock_interruptible(&hotkey_mutex))
856 if (!res) 1509 return -ERESTARTSYS;
857 hotkey_set(status, t); 1510
1511 res = hotkey_mask_set(t);
1512
1513#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL
1514 hotkey_poll_setup(1);
1515#endif
1516
1517 mutex_unlock(&hotkey_mutex);
858 1518
859 return (res) ? res : count; 1519 return (res) ? res : count;
860} 1520}
@@ -890,7 +1550,8 @@ static ssize_t hotkey_all_mask_show(struct device *dev,
890 struct device_attribute *attr, 1550 struct device_attribute *attr,
891 char *buf) 1551 char *buf)
892{ 1552{
893 return snprintf(buf, PAGE_SIZE, "0x%08x\n", hotkey_all_mask); 1553 return snprintf(buf, PAGE_SIZE, "0x%08x\n",
1554 hotkey_all_mask | hotkey_source_mask);
894} 1555}
895 1556
896static struct device_attribute dev_attr_hotkey_all_mask = 1557static struct device_attribute dev_attr_hotkey_all_mask =
@@ -902,14 +1563,87 @@ static ssize_t hotkey_recommended_mask_show(struct device *dev,
902 char *buf) 1563 char *buf)
903{ 1564{
904 return snprintf(buf, PAGE_SIZE, "0x%08x\n", 1565 return snprintf(buf, PAGE_SIZE, "0x%08x\n",
905 hotkey_all_mask & ~hotkey_reserved_mask); 1566 (hotkey_all_mask | hotkey_source_mask)
1567 & ~hotkey_reserved_mask);
906} 1568}
907 1569
908static struct device_attribute dev_attr_hotkey_recommended_mask = 1570static struct device_attribute dev_attr_hotkey_recommended_mask =
909 __ATTR(hotkey_recommended_mask, S_IRUGO, 1571 __ATTR(hotkey_recommended_mask, S_IRUGO,
910 hotkey_recommended_mask_show, NULL); 1572 hotkey_recommended_mask_show, NULL);
911 1573
912/* sysfs hotkey radio_sw ----------------------------------------------- */ 1574#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL
1575
1576/* sysfs hotkey hotkey_source_mask ------------------------------------- */
1577static ssize_t hotkey_source_mask_show(struct device *dev,
1578 struct device_attribute *attr,
1579 char *buf)
1580{
1581 return snprintf(buf, PAGE_SIZE, "0x%08x\n", hotkey_source_mask);
1582}
1583
1584static ssize_t hotkey_source_mask_store(struct device *dev,
1585 struct device_attribute *attr,
1586 const char *buf, size_t count)
1587{
1588 unsigned long t;
1589
1590 if (parse_strtoul(buf, 0xffffffffUL, &t) ||
1591 ((t & ~TPACPI_HKEY_NVRAM_KNOWN_MASK) != 0))
1592 return -EINVAL;
1593
1594 if (mutex_lock_interruptible(&hotkey_mutex))
1595 return -ERESTARTSYS;
1596
1597 HOTKEY_CONFIG_CRITICAL_START
1598 hotkey_source_mask = t;
1599 HOTKEY_CONFIG_CRITICAL_END
1600
1601 hotkey_poll_setup(1);
1602
1603 mutex_unlock(&hotkey_mutex);
1604
1605 return count;
1606}
1607
1608static struct device_attribute dev_attr_hotkey_source_mask =
1609 __ATTR(hotkey_source_mask, S_IWUSR | S_IRUGO,
1610 hotkey_source_mask_show, hotkey_source_mask_store);
1611
1612/* sysfs hotkey hotkey_poll_freq --------------------------------------- */
1613static ssize_t hotkey_poll_freq_show(struct device *dev,
1614 struct device_attribute *attr,
1615 char *buf)
1616{
1617 return snprintf(buf, PAGE_SIZE, "%d\n", hotkey_poll_freq);
1618}
1619
1620static ssize_t hotkey_poll_freq_store(struct device *dev,
1621 struct device_attribute *attr,
1622 const char *buf, size_t count)
1623{
1624 unsigned long t;
1625
1626 if (parse_strtoul(buf, 25, &t))
1627 return -EINVAL;
1628
1629 if (mutex_lock_interruptible(&hotkey_mutex))
1630 return -ERESTARTSYS;
1631
1632 hotkey_poll_freq = t;
1633
1634 hotkey_poll_setup(1);
1635 mutex_unlock(&hotkey_mutex);
1636
1637 return count;
1638}
1639
1640static struct device_attribute dev_attr_hotkey_poll_freq =
1641 __ATTR(hotkey_poll_freq, S_IWUSR | S_IRUGO,
1642 hotkey_poll_freq_show, hotkey_poll_freq_store);
1643
1644#endif /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */
1645
1646/* sysfs hotkey radio_sw (pollable) ------------------------------------ */
913static ssize_t hotkey_radio_sw_show(struct device *dev, 1647static ssize_t hotkey_radio_sw_show(struct device *dev,
914 struct device_attribute *attr, 1648 struct device_attribute *attr,
915 char *buf) 1649 char *buf)
@@ -925,6 +1659,13 @@ static ssize_t hotkey_radio_sw_show(struct device *dev,
925static struct device_attribute dev_attr_hotkey_radio_sw = 1659static struct device_attribute dev_attr_hotkey_radio_sw =
926 __ATTR(hotkey_radio_sw, S_IRUGO, hotkey_radio_sw_show, NULL); 1660 __ATTR(hotkey_radio_sw, S_IRUGO, hotkey_radio_sw_show, NULL);
927 1661
1662static void hotkey_radio_sw_notify_change(void)
1663{
1664 if (tp_features.hotkey_wlsw)
1665 sysfs_notify(&tpacpi_pdev->dev.kobj, NULL,
1666 "hotkey_radio_sw");
1667}
1668
928/* sysfs hotkey report_mode -------------------------------------------- */ 1669/* sysfs hotkey report_mode -------------------------------------------- */
929static ssize_t hotkey_report_mode_show(struct device *dev, 1670static ssize_t hotkey_report_mode_show(struct device *dev,
930 struct device_attribute *attr, 1671 struct device_attribute *attr,
@@ -937,43 +1678,132 @@ static ssize_t hotkey_report_mode_show(struct device *dev,
937static struct device_attribute dev_attr_hotkey_report_mode = 1678static struct device_attribute dev_attr_hotkey_report_mode =
938 __ATTR(hotkey_report_mode, S_IRUGO, hotkey_report_mode_show, NULL); 1679 __ATTR(hotkey_report_mode, S_IRUGO, hotkey_report_mode_show, NULL);
939 1680
1681/* sysfs wakeup reason (pollable) -------------------------------------- */
1682static ssize_t hotkey_wakeup_reason_show(struct device *dev,
1683 struct device_attribute *attr,
1684 char *buf)
1685{
1686 return snprintf(buf, PAGE_SIZE, "%d\n", hotkey_wakeup_reason);
1687}
1688
1689static struct device_attribute dev_attr_hotkey_wakeup_reason =
1690 __ATTR(wakeup_reason, S_IRUGO, hotkey_wakeup_reason_show, NULL);
1691
1692void hotkey_wakeup_reason_notify_change(void)
1693{
1694 if (tp_features.hotkey_mask)
1695 sysfs_notify(&tpacpi_pdev->dev.kobj, NULL,
1696 "wakeup_reason");
1697}
1698
1699/* sysfs wakeup hotunplug_complete (pollable) -------------------------- */
1700static ssize_t hotkey_wakeup_hotunplug_complete_show(struct device *dev,
1701 struct device_attribute *attr,
1702 char *buf)
1703{
1704 return snprintf(buf, PAGE_SIZE, "%d\n", hotkey_autosleep_ack);
1705}
1706
1707static struct device_attribute dev_attr_hotkey_wakeup_hotunplug_complete =
1708 __ATTR(wakeup_hotunplug_complete, S_IRUGO,
1709 hotkey_wakeup_hotunplug_complete_show, NULL);
1710
1711void hotkey_wakeup_hotunplug_complete_notify_change(void)
1712{
1713 if (tp_features.hotkey_mask)
1714 sysfs_notify(&tpacpi_pdev->dev.kobj, NULL,
1715 "wakeup_hotunplug_complete");
1716}
1717
940/* --------------------------------------------------------------------- */ 1718/* --------------------------------------------------------------------- */
941 1719
942static struct attribute *hotkey_attributes[] __initdata = { 1720static struct attribute *hotkey_attributes[] __initdata = {
943 &dev_attr_hotkey_enable.attr, 1721 &dev_attr_hotkey_enable.attr,
1722 &dev_attr_hotkey_bios_enabled.attr,
944 &dev_attr_hotkey_report_mode.attr, 1723 &dev_attr_hotkey_report_mode.attr,
1724#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL
1725 &dev_attr_hotkey_mask.attr,
1726 &dev_attr_hotkey_all_mask.attr,
1727 &dev_attr_hotkey_recommended_mask.attr,
1728 &dev_attr_hotkey_source_mask.attr,
1729 &dev_attr_hotkey_poll_freq.attr,
1730#endif
945}; 1731};
946 1732
947static struct attribute *hotkey_mask_attributes[] __initdata = { 1733static struct attribute *hotkey_mask_attributes[] __initdata = {
948 &dev_attr_hotkey_mask.attr,
949 &dev_attr_hotkey_bios_enabled.attr,
950 &dev_attr_hotkey_bios_mask.attr, 1734 &dev_attr_hotkey_bios_mask.attr,
1735#ifndef CONFIG_THINKPAD_ACPI_HOTKEY_POLL
1736 &dev_attr_hotkey_mask.attr,
951 &dev_attr_hotkey_all_mask.attr, 1737 &dev_attr_hotkey_all_mask.attr,
952 &dev_attr_hotkey_recommended_mask.attr, 1738 &dev_attr_hotkey_recommended_mask.attr,
1739#endif
1740 &dev_attr_hotkey_wakeup_reason.attr,
1741 &dev_attr_hotkey_wakeup_hotunplug_complete.attr,
953}; 1742};
954 1743
955static int __init hotkey_init(struct ibm_init_struct *iibm) 1744static int __init hotkey_init(struct ibm_init_struct *iibm)
956{ 1745{
957 1746 /* Requirements for changing the default keymaps:
1747 *
1748 * 1. Many of the keys are mapped to KEY_RESERVED for very
1749 * good reasons. Do not change them unless you have deep
1750 * knowledge on the IBM and Lenovo ThinkPad firmware for
1751 * the various ThinkPad models. The driver behaves
1752 * differently for KEY_RESERVED: such keys have their
1753 * hot key mask *unset* in mask_recommended, and also
1754 * in the initial hot key mask programmed into the
1755 * firmware at driver load time, which means the firm-
1756 * ware may react very differently if you change them to
1757 * something else;
1758 *
1759 * 2. You must be subscribed to the linux-thinkpad and
1760 * ibm-acpi-devel mailing lists, and you should read the
1761 * list archives since 2007 if you want to change the
1762 * keymaps. This requirement exists so that you will
1763 * know the past history of problems with the thinkpad-
1764 * acpi driver keymaps, and also that you will be
1765 * listening to any bug reports;
1766 *
1767 * 3. Do not send thinkpad-acpi specific patches directly to
1768 * for merging, *ever*. Send them to the linux-acpi
1769 * mailinglist for comments. Merging is to be done only
1770 * through acpi-test and the ACPI maintainer.
1771 *
1772 * If the above is too much to ask, don't change the keymap.
1773 * Ask the thinkpad-acpi maintainer to do it, instead.
1774 */
958 static u16 ibm_keycode_map[] __initdata = { 1775 static u16 ibm_keycode_map[] __initdata = {
959 /* Scan Codes 0x00 to 0x0B: ACPI HKEY FN+F1..F12 */ 1776 /* Scan Codes 0x00 to 0x0B: ACPI HKEY FN+F1..F12 */
960 KEY_FN_F1, KEY_FN_F2, KEY_COFFEE, KEY_SLEEP, 1777 KEY_FN_F1, KEY_FN_F2, KEY_COFFEE, KEY_SLEEP,
961 KEY_WLAN, KEY_FN_F6, KEY_SWITCHVIDEOMODE, KEY_FN_F8, 1778 KEY_WLAN, KEY_FN_F6, KEY_SWITCHVIDEOMODE, KEY_FN_F8,
962 KEY_FN_F9, KEY_FN_F10, KEY_FN_F11, KEY_SUSPEND, 1779 KEY_FN_F9, KEY_FN_F10, KEY_FN_F11, KEY_SUSPEND,
963 /* Scan codes 0x0C to 0x0F: Other ACPI HKEY hot keys */ 1780
1781 /* Scan codes 0x0C to 0x1F: Other ACPI HKEY hot keys */
964 KEY_UNKNOWN, /* 0x0C: FN+BACKSPACE */ 1782 KEY_UNKNOWN, /* 0x0C: FN+BACKSPACE */
965 KEY_UNKNOWN, /* 0x0D: FN+INSERT */ 1783 KEY_UNKNOWN, /* 0x0D: FN+INSERT */
966 KEY_UNKNOWN, /* 0x0E: FN+DELETE */ 1784 KEY_UNKNOWN, /* 0x0E: FN+DELETE */
1785
1786 /* brightness: firmware always reacts to them, unless
1787 * X.org did some tricks in the radeon BIOS scratch
1788 * registers of *some* models */
967 KEY_RESERVED, /* 0x0F: FN+HOME (brightness up) */ 1789 KEY_RESERVED, /* 0x0F: FN+HOME (brightness up) */
968 /* Scan codes 0x10 to 0x1F: Extended ACPI HKEY hot keys */
969 KEY_RESERVED, /* 0x10: FN+END (brightness down) */ 1790 KEY_RESERVED, /* 0x10: FN+END (brightness down) */
1791
1792 /* Thinklight: firmware always react to it */
970 KEY_RESERVED, /* 0x11: FN+PGUP (thinklight toggle) */ 1793 KEY_RESERVED, /* 0x11: FN+PGUP (thinklight toggle) */
1794
971 KEY_UNKNOWN, /* 0x12: FN+PGDOWN */ 1795 KEY_UNKNOWN, /* 0x12: FN+PGDOWN */
972 KEY_ZOOM, /* 0x13: FN+SPACE (zoom) */ 1796 KEY_ZOOM, /* 0x13: FN+SPACE (zoom) */
1797
1798 /* Volume: firmware always react to it and reprograms
1799 * the built-in *extra* mixer. Never map it to control
1800 * another mixer by default. */
973 KEY_RESERVED, /* 0x14: VOLUME UP */ 1801 KEY_RESERVED, /* 0x14: VOLUME UP */
974 KEY_RESERVED, /* 0x15: VOLUME DOWN */ 1802 KEY_RESERVED, /* 0x15: VOLUME DOWN */
975 KEY_RESERVED, /* 0x16: MUTE */ 1803 KEY_RESERVED, /* 0x16: MUTE */
1804
976 KEY_VENDOR, /* 0x17: Thinkpad/AccessIBM/Lenovo */ 1805 KEY_VENDOR, /* 0x17: Thinkpad/AccessIBM/Lenovo */
1806
977 /* (assignments unknown, please report if found) */ 1807 /* (assignments unknown, please report if found) */
978 KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, 1808 KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,
979 KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, 1809 KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,
@@ -983,20 +1813,37 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
983 KEY_FN_F1, KEY_COFFEE, KEY_BATTERY, KEY_SLEEP, 1813 KEY_FN_F1, KEY_COFFEE, KEY_BATTERY, KEY_SLEEP,
984 KEY_WLAN, KEY_FN_F6, KEY_SWITCHVIDEOMODE, KEY_FN_F8, 1814 KEY_WLAN, KEY_FN_F6, KEY_SWITCHVIDEOMODE, KEY_FN_F8,
985 KEY_FN_F9, KEY_FN_F10, KEY_FN_F11, KEY_SUSPEND, 1815 KEY_FN_F9, KEY_FN_F10, KEY_FN_F11, KEY_SUSPEND,
986 /* Scan codes 0x0C to 0x0F: Other ACPI HKEY hot keys */ 1816
1817 /* Scan codes 0x0C to 0x1F: Other ACPI HKEY hot keys */
987 KEY_UNKNOWN, /* 0x0C: FN+BACKSPACE */ 1818 KEY_UNKNOWN, /* 0x0C: FN+BACKSPACE */
988 KEY_UNKNOWN, /* 0x0D: FN+INSERT */ 1819 KEY_UNKNOWN, /* 0x0D: FN+INSERT */
989 KEY_UNKNOWN, /* 0x0E: FN+DELETE */ 1820 KEY_UNKNOWN, /* 0x0E: FN+DELETE */
1821
990 KEY_RESERVED, /* 0x0F: FN+HOME (brightness up) */ 1822 KEY_RESERVED, /* 0x0F: FN+HOME (brightness up) */
991 /* Scan codes 0x10 to 0x1F: Extended ACPI HKEY hot keys */
992 KEY_RESERVED, /* 0x10: FN+END (brightness down) */ 1823 KEY_RESERVED, /* 0x10: FN+END (brightness down) */
1824
993 KEY_RESERVED, /* 0x11: FN+PGUP (thinklight toggle) */ 1825 KEY_RESERVED, /* 0x11: FN+PGUP (thinklight toggle) */
1826
994 KEY_UNKNOWN, /* 0x12: FN+PGDOWN */ 1827 KEY_UNKNOWN, /* 0x12: FN+PGDOWN */
995 KEY_ZOOM, /* 0x13: FN+SPACE (zoom) */ 1828 KEY_ZOOM, /* 0x13: FN+SPACE (zoom) */
1829
1830 /* Volume: z60/z61, T60 (BIOS version?): firmware always
1831 * react to it and reprograms the built-in *extra* mixer.
1832 * Never map it to control another mixer by default.
1833 *
1834 * T60?, T61, R60?, R61: firmware and EC tries to send
1835 * these over the regular keyboard, so these are no-ops,
1836 * but there are still weird bugs re. MUTE, so do not
1837 * change unless you get test reports from all Lenovo
1838 * models. May cause the BIOS to interfere with the
1839 * HDA mixer.
1840 */
996 KEY_RESERVED, /* 0x14: VOLUME UP */ 1841 KEY_RESERVED, /* 0x14: VOLUME UP */
997 KEY_RESERVED, /* 0x15: VOLUME DOWN */ 1842 KEY_RESERVED, /* 0x15: VOLUME DOWN */
998 KEY_RESERVED, /* 0x16: MUTE */ 1843 KEY_RESERVED, /* 0x16: MUTE */
1844
999 KEY_VENDOR, /* 0x17: Thinkpad/AccessIBM/Lenovo */ 1845 KEY_VENDOR, /* 0x17: Thinkpad/AccessIBM/Lenovo */
1846
1000 /* (assignments unknown, please report if found) */ 1847 /* (assignments unknown, please report if found) */
1001 KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, 1848 KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,
1002 KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, 1849 KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,
@@ -1013,10 +1860,17 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
1013 vdbg_printk(TPACPI_DBG_INIT, "initializing hotkey subdriver\n"); 1860 vdbg_printk(TPACPI_DBG_INIT, "initializing hotkey subdriver\n");
1014 1861
1015 BUG_ON(!tpacpi_inputdev); 1862 BUG_ON(!tpacpi_inputdev);
1863 BUG_ON(tpacpi_inputdev->open != NULL ||
1864 tpacpi_inputdev->close != NULL);
1016 1865
1017 IBM_ACPIHANDLE_INIT(hkey); 1866 TPACPI_ACPIHANDLE_INIT(hkey);
1018 mutex_init(&hotkey_mutex); 1867 mutex_init(&hotkey_mutex);
1019 1868
1869#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL
1870 mutex_init(&hotkey_thread_mutex);
1871 mutex_init(&hotkey_thread_data_mutex);
1872#endif
1873
1020 /* hotkey not supported on 570 */ 1874 /* hotkey not supported on 570 */
1021 tp_features.hotkey = hkey_handle != NULL; 1875 tp_features.hotkey = hkey_handle != NULL;
1022 1876
@@ -1024,7 +1878,7 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
1024 str_supported(tp_features.hotkey)); 1878 str_supported(tp_features.hotkey));
1025 1879
1026 if (tp_features.hotkey) { 1880 if (tp_features.hotkey) {
1027 hotkey_dev_attributes = create_attr_set(8, NULL); 1881 hotkey_dev_attributes = create_attr_set(12, NULL);
1028 if (!hotkey_dev_attributes) 1882 if (!hotkey_dev_attributes)
1029 return -ENOMEM; 1883 return -ENOMEM;
1030 res = add_many_to_attr_set(hotkey_dev_attributes, 1884 res = add_many_to_attr_set(hotkey_dev_attributes,
@@ -1038,15 +1892,15 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
1038 for HKEY interface version 0x100 */ 1892 for HKEY interface version 0x100 */
1039 if (acpi_evalf(hkey_handle, &hkeyv, "MHKV", "qd")) { 1893 if (acpi_evalf(hkey_handle, &hkeyv, "MHKV", "qd")) {
1040 if ((hkeyv >> 8) != 1) { 1894 if ((hkeyv >> 8) != 1) {
1041 printk(IBM_ERR "unknown version of the " 1895 printk(TPACPI_ERR "unknown version of the "
1042 "HKEY interface: 0x%x\n", hkeyv); 1896 "HKEY interface: 0x%x\n", hkeyv);
1043 printk(IBM_ERR "please report this to %s\n", 1897 printk(TPACPI_ERR "please report this to %s\n",
1044 IBM_MAIL); 1898 TPACPI_MAIL);
1045 } else { 1899 } else {
1046 /* 1900 /*
1047 * MHKV 0x100 in A31, R40, R40e, 1901 * MHKV 0x100 in A31, R40, R40e,
1048 * T4x, X31, and later 1902 * T4x, X31, and later
1049 * */ 1903 */
1050 tp_features.hotkey_mask = 1; 1904 tp_features.hotkey_mask = 1;
1051 } 1905 }
1052 } 1906 }
@@ -1057,25 +1911,46 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
1057 if (tp_features.hotkey_mask) { 1911 if (tp_features.hotkey_mask) {
1058 if (!acpi_evalf(hkey_handle, &hotkey_all_mask, 1912 if (!acpi_evalf(hkey_handle, &hotkey_all_mask,
1059 "MHKA", "qd")) { 1913 "MHKA", "qd")) {
1060 printk(IBM_ERR 1914 printk(TPACPI_ERR
1061 "missing MHKA handler, " 1915 "missing MHKA handler, "
1062 "please report this to %s\n", 1916 "please report this to %s\n",
1063 IBM_MAIL); 1917 TPACPI_MAIL);
1064 hotkey_all_mask = 0x080cU; /* FN+F12, FN+F4, FN+F3 */ 1918 /* FN+F12, FN+F4, FN+F3 */
1919 hotkey_all_mask = 0x080cU;
1065 } 1920 }
1066 } 1921 }
1067 1922
1068 res = hotkey_get(&hotkey_orig_status, &hotkey_orig_mask); 1923 /* hotkey_source_mask *must* be zero for
1924 * the first hotkey_mask_get */
1925 res = hotkey_status_get(&hotkey_orig_status);
1069 if (!res && tp_features.hotkey_mask) { 1926 if (!res && tp_features.hotkey_mask) {
1070 res = add_many_to_attr_set(hotkey_dev_attributes, 1927 res = hotkey_mask_get();
1071 hotkey_mask_attributes, 1928 hotkey_orig_mask = hotkey_mask;
1072 ARRAY_SIZE(hotkey_mask_attributes)); 1929 if (!res) {
1930 res = add_many_to_attr_set(
1931 hotkey_dev_attributes,
1932 hotkey_mask_attributes,
1933 ARRAY_SIZE(hotkey_mask_attributes));
1934 }
1935 }
1936
1937#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL
1938 if (tp_features.hotkey_mask) {
1939 hotkey_source_mask = TPACPI_HKEY_NVRAM_GOOD_MASK
1940 & ~hotkey_all_mask;
1941 } else {
1942 hotkey_source_mask = TPACPI_HKEY_NVRAM_GOOD_MASK;
1073 } 1943 }
1074 1944
1945 vdbg_printk(TPACPI_DBG_INIT,
1946 "hotkey source mask 0x%08x, polling freq %d\n",
1947 hotkey_source_mask, hotkey_poll_freq);
1948#endif
1949
1075 /* Not all thinkpads have a hardware radio switch */ 1950 /* Not all thinkpads have a hardware radio switch */
1076 if (!res && acpi_evalf(hkey_handle, &status, "WLSW", "qd")) { 1951 if (!res && acpi_evalf(hkey_handle, &status, "WLSW", "qd")) {
1077 tp_features.hotkey_wlsw = 1; 1952 tp_features.hotkey_wlsw = 1;
1078 printk(IBM_INFO 1953 printk(TPACPI_INFO
1079 "radio switch found; radios are %s\n", 1954 "radio switch found; radios are %s\n",
1080 enabled(status, 0)); 1955 enabled(status, 0));
1081 res = add_to_attr_set(hotkey_dev_attributes, 1956 res = add_to_attr_set(hotkey_dev_attributes,
@@ -1094,7 +1969,8 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
1094 hotkey_keycode_map = kmalloc(TPACPI_HOTKEY_MAP_SIZE, 1969 hotkey_keycode_map = kmalloc(TPACPI_HOTKEY_MAP_SIZE,
1095 GFP_KERNEL); 1970 GFP_KERNEL);
1096 if (!hotkey_keycode_map) { 1971 if (!hotkey_keycode_map) {
1097 printk(IBM_ERR "failed to allocate memory for key map\n"); 1972 printk(TPACPI_ERR
1973 "failed to allocate memory for key map\n");
1098 return -ENOMEM; 1974 return -ENOMEM;
1099 } 1975 }
1100 1976
@@ -1133,15 +2009,26 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
1133 2009
1134 dbg_printk(TPACPI_DBG_INIT, 2010 dbg_printk(TPACPI_DBG_INIT,
1135 "enabling hot key handling\n"); 2011 "enabling hot key handling\n");
1136 res = hotkey_set(1, (hotkey_all_mask & ~hotkey_reserved_mask) 2012 res = hotkey_status_set(1);
1137 | hotkey_orig_mask);
1138 if (res) 2013 if (res)
1139 return res; 2014 return res;
2015 res = hotkey_mask_set(((hotkey_all_mask | hotkey_source_mask)
2016 & ~hotkey_reserved_mask)
2017 | hotkey_orig_mask);
2018 if (res < 0 && res != -ENXIO)
2019 return res;
1140 2020
1141 dbg_printk(TPACPI_DBG_INIT, 2021 dbg_printk(TPACPI_DBG_INIT,
1142 "legacy hot key reporting over procfs %s\n", 2022 "legacy hot key reporting over procfs %s\n",
1143 (hotkey_report_mode < 2) ? 2023 (hotkey_report_mode < 2) ?
1144 "enabled" : "disabled"); 2024 "enabled" : "disabled");
2025
2026#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL
2027 tpacpi_inputdev->open = &hotkey_inputdev_open;
2028 tpacpi_inputdev->close = &hotkey_inputdev_close;
2029
2030 hotkey_poll_setup_safe(1);
2031#endif
1145 } 2032 }
1146 2033
1147 return (tp_features.hotkey)? 0 : 1; 2034 return (tp_features.hotkey)? 0 : 1;
@@ -1149,13 +2036,19 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
1149 2036
1150static void hotkey_exit(void) 2037static void hotkey_exit(void)
1151{ 2038{
1152 int res; 2039#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL
2040 hotkey_poll_stop_sync();
2041#endif
1153 2042
1154 if (tp_features.hotkey) { 2043 if (tp_features.hotkey) {
1155 dbg_printk(TPACPI_DBG_EXIT, "restoring original hotkey mask\n"); 2044 dbg_printk(TPACPI_DBG_EXIT,
1156 res = hotkey_set(hotkey_orig_status, hotkey_orig_mask); 2045 "restoring original hot key mask\n");
1157 if (res) 2046 /* no short-circuit boolean operator below! */
1158 printk(IBM_ERR "failed to restore hotkey to BIOS defaults\n"); 2047 if ((hotkey_mask_set(hotkey_orig_mask) |
2048 hotkey_status_set(hotkey_orig_status)) != 0)
2049 printk(TPACPI_ERR
2050 "failed to restore hot key mask "
2051 "to BIOS defaults\n");
1159 } 2052 }
1160 2053
1161 if (hotkey_dev_attributes) { 2054 if (hotkey_dev_attributes) {
@@ -1164,62 +2057,28 @@ static void hotkey_exit(void)
1164 } 2057 }
1165} 2058}
1166 2059
1167static void tpacpi_input_send_key(unsigned int scancode,
1168 unsigned int keycode)
1169{
1170 if (keycode != KEY_RESERVED) {
1171 mutex_lock(&tpacpi_inputdev_send_mutex);
1172
1173 input_report_key(tpacpi_inputdev, keycode, 1);
1174 if (keycode == KEY_UNKNOWN)
1175 input_event(tpacpi_inputdev, EV_MSC, MSC_SCAN,
1176 scancode);
1177 input_sync(tpacpi_inputdev);
1178
1179 input_report_key(tpacpi_inputdev, keycode, 0);
1180 if (keycode == KEY_UNKNOWN)
1181 input_event(tpacpi_inputdev, EV_MSC, MSC_SCAN,
1182 scancode);
1183 input_sync(tpacpi_inputdev);
1184
1185 mutex_unlock(&tpacpi_inputdev_send_mutex);
1186 }
1187}
1188
1189static void tpacpi_input_send_radiosw(void)
1190{
1191 int wlsw;
1192
1193 mutex_lock(&tpacpi_inputdev_send_mutex);
1194
1195 if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&wlsw)) {
1196 input_report_switch(tpacpi_inputdev,
1197 SW_RADIO, !!wlsw);
1198 input_sync(tpacpi_inputdev);
1199 }
1200
1201 mutex_unlock(&tpacpi_inputdev_send_mutex);
1202}
1203
1204static void hotkey_notify(struct ibm_struct *ibm, u32 event) 2060static void hotkey_notify(struct ibm_struct *ibm, u32 event)
1205{ 2061{
1206 u32 hkey; 2062 u32 hkey;
1207 unsigned int keycode, scancode; 2063 unsigned int scancode;
1208 int send_acpi_ev; 2064 int send_acpi_ev;
1209 int ignore_acpi_ev; 2065 int ignore_acpi_ev;
2066 int unk_ev;
1210 2067
1211 if (event != 0x80) { 2068 if (event != 0x80) {
1212 printk(IBM_ERR "unknown HKEY notification event %d\n", event); 2069 printk(TPACPI_ERR
2070 "unknown HKEY notification event %d\n", event);
1213 /* forward it to userspace, maybe it knows how to handle it */ 2071 /* forward it to userspace, maybe it knows how to handle it */
1214 acpi_bus_generate_netlink_event(ibm->acpi->device->pnp.device_class, 2072 acpi_bus_generate_netlink_event(
1215 ibm->acpi->device->dev.bus_id, 2073 ibm->acpi->device->pnp.device_class,
1216 event, 0); 2074 ibm->acpi->device->dev.bus_id,
2075 event, 0);
1217 return; 2076 return;
1218 } 2077 }
1219 2078
1220 while (1) { 2079 while (1) {
1221 if (!acpi_evalf(hkey_handle, &hkey, "MHKP", "d")) { 2080 if (!acpi_evalf(hkey_handle, &hkey, "MHKP", "d")) {
1222 printk(IBM_ERR "failed to retrieve HKEY event\n"); 2081 printk(TPACPI_ERR "failed to retrieve HKEY event\n");
1223 return; 2082 return;
1224 } 2083 }
1225 2084
@@ -1228,8 +2087,9 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event)
1228 return; 2087 return;
1229 } 2088 }
1230 2089
1231 send_acpi_ev = 0; 2090 send_acpi_ev = 1;
1232 ignore_acpi_ev = 0; 2091 ignore_acpi_ev = 0;
2092 unk_ev = 0;
1233 2093
1234 switch (hkey >> 12) { 2094 switch (hkey >> 12) {
1235 case 1: 2095 case 1:
@@ -1237,104 +2097,139 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event)
1237 scancode = hkey & 0xfff; 2097 scancode = hkey & 0xfff;
1238 if (scancode > 0 && scancode < 0x21) { 2098 if (scancode > 0 && scancode < 0x21) {
1239 scancode--; 2099 scancode--;
1240 keycode = hotkey_keycode_map[scancode]; 2100 if (!(hotkey_source_mask & (1 << scancode))) {
1241 tpacpi_input_send_key(scancode, keycode); 2101 tpacpi_input_send_key(scancode);
2102 send_acpi_ev = 0;
2103 } else {
2104 ignore_acpi_ev = 1;
2105 }
1242 } else { 2106 } else {
1243 printk(IBM_ERR 2107 unk_ev = 1;
1244 "hotkey 0x%04x out of range for keyboard map\n",
1245 hkey);
1246 send_acpi_ev = 1;
1247 } 2108 }
1248 break; 2109 break;
1249 case 5: 2110 case 2:
1250 /* 0x5000-0x5FFF: LID */ 2111 /* Wakeup reason */
1251 /* we don't handle it through this path, just 2112 switch (hkey) {
1252 * eat up known LID events */ 2113 case 0x2304: /* suspend, undock */
1253 if (hkey != 0x5001 && hkey != 0x5002) { 2114 case 0x2404: /* hibernation, undock */
1254 printk(IBM_ERR 2115 hotkey_wakeup_reason = TP_ACPI_WAKEUP_UNDOCK;
1255 "unknown LID-related HKEY event: 0x%04x\n", 2116 ignore_acpi_ev = 1;
1256 hkey); 2117 break;
1257 send_acpi_ev = 1; 2118 case 0x2305: /* suspend, bay eject */
2119 case 0x2405: /* hibernation, bay eject */
2120 hotkey_wakeup_reason = TP_ACPI_WAKEUP_BAYEJ;
2121 ignore_acpi_ev = 1;
2122 break;
2123 default:
2124 unk_ev = 1;
2125 }
2126 if (hotkey_wakeup_reason != TP_ACPI_WAKEUP_NONE) {
2127 printk(TPACPI_INFO
2128 "woke up due to a hot-unplug "
2129 "request...\n");
2130 hotkey_wakeup_reason_notify_change();
2131 }
2132 break;
2133 case 3:
2134 /* bay-related wakeups */
2135 if (hkey == 0x3003) {
2136 hotkey_autosleep_ack = 1;
2137 printk(TPACPI_INFO
2138 "bay ejected\n");
2139 hotkey_wakeup_hotunplug_complete_notify_change();
1258 } else { 2140 } else {
2141 unk_ev = 1;
2142 }
2143 break;
2144 case 4:
2145 /* dock-related wakeups */
2146 if (hkey == 0x4003) {
2147 hotkey_autosleep_ack = 1;
2148 printk(TPACPI_INFO
2149 "undocked\n");
2150 hotkey_wakeup_hotunplug_complete_notify_change();
2151 } else {
2152 unk_ev = 1;
2153 }
2154 break;
2155 case 5:
2156 /* 0x5000-0x5FFF: human interface helpers */
2157 switch (hkey) {
2158 case 0x5010: /* Lenovo new BIOS: brightness changed */
2159 case 0x5009: /* X61t: swivel up (tablet mode) */
2160 case 0x500a: /* X61t: swivel down (normal mode) */
2161 case 0x500b: /* X61t: tablet pen inserted into bay */
2162 case 0x500c: /* X61t: tablet pen removed from bay */
2163 break;
2164 case 0x5001:
2165 case 0x5002:
2166 /* LID switch events. Do not propagate */
1259 ignore_acpi_ev = 1; 2167 ignore_acpi_ev = 1;
2168 break;
2169 default:
2170 unk_ev = 1;
1260 } 2171 }
1261 break; 2172 break;
1262 case 7: 2173 case 7:
1263 /* 0x7000-0x7FFF: misc */ 2174 /* 0x7000-0x7FFF: misc */
1264 if (tp_features.hotkey_wlsw && hkey == 0x7000) { 2175 if (tp_features.hotkey_wlsw && hkey == 0x7000) {
1265 tpacpi_input_send_radiosw(); 2176 tpacpi_input_send_radiosw();
2177 hotkey_radio_sw_notify_change();
2178 send_acpi_ev = 0;
1266 break; 2179 break;
1267 } 2180 }
1268 /* fallthrough to default */ 2181 /* fallthrough to default */
1269 default: 2182 default:
1270 /* case 2: dock-related */ 2183 unk_ev = 1;
1271 /* 0x2305 - T43 waking up due to bay lever eject while aslept */ 2184 }
1272 /* case 3: ultra-bay related. maybe bay in dock? */ 2185 if (unk_ev) {
1273 /* 0x3003 - T43 after wake up by bay lever eject (0x2305) */ 2186 printk(TPACPI_NOTICE
1274 printk(IBM_NOTICE "unhandled HKEY event 0x%04x\n", hkey); 2187 "unhandled HKEY event 0x%04x\n", hkey);
1275 send_acpi_ev = 1;
1276 } 2188 }
1277 2189
1278 /* Legacy events */ 2190 /* Legacy events */
1279 if (!ignore_acpi_ev && (send_acpi_ev || hotkey_report_mode < 2)) { 2191 if (!ignore_acpi_ev &&
1280 acpi_bus_generate_proc_event(ibm->acpi->device, event, hkey); 2192 (send_acpi_ev || hotkey_report_mode < 2)) {
2193 acpi_bus_generate_proc_event(ibm->acpi->device,
2194 event, hkey);
1281 } 2195 }
1282 2196
1283 /* netlink events */ 2197 /* netlink events */
1284 if (!ignore_acpi_ev && send_acpi_ev) { 2198 if (!ignore_acpi_ev && send_acpi_ev) {
1285 acpi_bus_generate_netlink_event(ibm->acpi->device->pnp.device_class, 2199 acpi_bus_generate_netlink_event(
1286 ibm->acpi->device->dev.bus_id, 2200 ibm->acpi->device->pnp.device_class,
1287 event, hkey); 2201 ibm->acpi->device->dev.bus_id,
2202 event, hkey);
1288 } 2203 }
1289 } 2204 }
1290} 2205}
1291 2206
1292static void hotkey_resume(void) 2207static void hotkey_suspend(pm_message_t state)
1293{ 2208{
1294 tpacpi_input_send_radiosw(); 2209 /* Do these on suspend, we get the events on early resume! */
2210 hotkey_wakeup_reason = TP_ACPI_WAKEUP_NONE;
2211 hotkey_autosleep_ack = 0;
1295} 2212}
1296 2213
1297/* 2214static void hotkey_resume(void)
1298 * Call with hotkey_mutex held
1299 */
1300static int hotkey_get(int *status, u32 *mask)
1301{
1302 if (!acpi_evalf(hkey_handle, status, "DHKC", "d"))
1303 return -EIO;
1304
1305 if (tp_features.hotkey_mask)
1306 if (!acpi_evalf(hkey_handle, mask, "DHKN", "d"))
1307 return -EIO;
1308
1309 return 0;
1310}
1311
1312/*
1313 * Call with hotkey_mutex held
1314 */
1315static int hotkey_set(int status, u32 mask)
1316{ 2215{
1317 int i; 2216 if (hotkey_mask_get())
1318 2217 printk(TPACPI_ERR
1319 if (!acpi_evalf(hkey_handle, NULL, "MHKC", "vd", status)) 2218 "error while trying to read hot key mask "
1320 return -EIO; 2219 "from firmware\n");
1321 2220 tpacpi_input_send_radiosw();
1322 if (tp_features.hotkey_mask) 2221 hotkey_radio_sw_notify_change();
1323 for (i = 0; i < 32; i++) { 2222 hotkey_wakeup_reason_notify_change();
1324 int bit = ((1 << i) & mask) != 0; 2223 hotkey_wakeup_hotunplug_complete_notify_change();
1325 if (!acpi_evalf(hkey_handle, 2224#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL
1326 NULL, "MHKM", "vdd", i + 1, bit)) 2225 hotkey_poll_setup_safe(0);
1327 return -EIO; 2226#endif
1328 }
1329
1330 return 0;
1331} 2227}
1332 2228
1333/* procfs -------------------------------------------------------------- */ 2229/* procfs -------------------------------------------------------------- */
1334static int hotkey_read(char *p) 2230static int hotkey_read(char *p)
1335{ 2231{
1336 int res, status; 2232 int res, status;
1337 u32 mask;
1338 int len = 0; 2233 int len = 0;
1339 2234
1340 if (!tp_features.hotkey) { 2235 if (!tp_features.hotkey) {
@@ -1344,14 +2239,16 @@ static int hotkey_read(char *p)
1344 2239
1345 if (mutex_lock_interruptible(&hotkey_mutex)) 2240 if (mutex_lock_interruptible(&hotkey_mutex))
1346 return -ERESTARTSYS; 2241 return -ERESTARTSYS;
1347 res = hotkey_get(&status, &mask); 2242 res = hotkey_status_get(&status);
2243 if (!res)
2244 res = hotkey_mask_get();
1348 mutex_unlock(&hotkey_mutex); 2245 mutex_unlock(&hotkey_mutex);
1349 if (res) 2246 if (res)
1350 return res; 2247 return res;
1351 2248
1352 len += sprintf(p + len, "status:\t\t%s\n", enabled(status, 0)); 2249 len += sprintf(p + len, "status:\t\t%s\n", enabled(status, 0));
1353 if (tp_features.hotkey_mask) { 2250 if (tp_features.hotkey_mask) {
1354 len += sprintf(p + len, "mask:\t\t0x%08x\n", mask); 2251 len += sprintf(p + len, "mask:\t\t0x%08x\n", hotkey_mask);
1355 len += sprintf(p + len, 2252 len += sprintf(p + len,
1356 "commands:\tenable, disable, reset, <mask>\n"); 2253 "commands:\tenable, disable, reset, <mask>\n");
1357 } else { 2254 } else {
@@ -1367,7 +2264,6 @@ static int hotkey_write(char *buf)
1367 int res, status; 2264 int res, status;
1368 u32 mask; 2265 u32 mask;
1369 char *cmd; 2266 char *cmd;
1370 int do_cmd = 0;
1371 2267
1372 if (!tp_features.hotkey) 2268 if (!tp_features.hotkey)
1373 return -ENODEV; 2269 return -ENODEV;
@@ -1375,9 +2271,8 @@ static int hotkey_write(char *buf)
1375 if (mutex_lock_interruptible(&hotkey_mutex)) 2271 if (mutex_lock_interruptible(&hotkey_mutex))
1376 return -ERESTARTSYS; 2272 return -ERESTARTSYS;
1377 2273
1378 res = hotkey_get(&status, &mask); 2274 status = -1;
1379 if (res) 2275 mask = hotkey_mask;
1380 goto errexit;
1381 2276
1382 res = 0; 2277 res = 0;
1383 while ((cmd = next_cmd(&buf))) { 2278 while ((cmd = next_cmd(&buf))) {
@@ -1396,11 +2291,12 @@ static int hotkey_write(char *buf)
1396 res = -EINVAL; 2291 res = -EINVAL;
1397 goto errexit; 2292 goto errexit;
1398 } 2293 }
1399 do_cmd = 1;
1400 } 2294 }
2295 if (status != -1)
2296 res = hotkey_status_set(status);
1401 2297
1402 if (do_cmd) 2298 if (!res && mask != hotkey_mask)
1403 res = hotkey_set(status, mask); 2299 res = hotkey_mask_set(mask);
1404 2300
1405errexit: 2301errexit:
1406 mutex_unlock(&hotkey_mutex); 2302 mutex_unlock(&hotkey_mutex);
@@ -1408,7 +2304,7 @@ errexit:
1408} 2304}
1409 2305
1410static const struct acpi_device_id ibm_htk_device_ids[] = { 2306static const struct acpi_device_id ibm_htk_device_ids[] = {
1411 {IBM_HKEY_HID, 0}, 2307 {TPACPI_ACPI_HKEY_HID, 0},
1412 {"", 0}, 2308 {"", 0},
1413}; 2309};
1414 2310
@@ -1425,6 +2321,7 @@ static struct ibm_struct hotkey_driver_data = {
1425 .write = hotkey_write, 2321 .write = hotkey_write,
1426 .exit = hotkey_exit, 2322 .exit = hotkey_exit,
1427 .resume = hotkey_resume, 2323 .resume = hotkey_resume,
2324 .suspend = hotkey_suspend,
1428 .acpi = &ibm_hotkey_acpidriver, 2325 .acpi = &ibm_hotkey_acpidriver,
1429}; 2326};
1430 2327
@@ -1432,6 +2329,16 @@ static struct ibm_struct hotkey_driver_data = {
1432 * Bluetooth subdriver 2329 * Bluetooth subdriver
1433 */ 2330 */
1434 2331
2332enum {
2333 /* ACPI GBDC/SBDC bits */
2334 TP_ACPI_BLUETOOTH_HWPRESENT = 0x01, /* Bluetooth hw available */
2335 TP_ACPI_BLUETOOTH_RADIOSSW = 0x02, /* Bluetooth radio enabled */
2336 TP_ACPI_BLUETOOTH_UNK = 0x04, /* unknown function */
2337};
2338
2339static int bluetooth_get_radiosw(void);
2340static int bluetooth_set_radiosw(int radio_on);
2341
1435/* sysfs bluetooth enable ---------------------------------------------- */ 2342/* sysfs bluetooth enable ---------------------------------------------- */
1436static ssize_t bluetooth_enable_show(struct device *dev, 2343static ssize_t bluetooth_enable_show(struct device *dev,
1437 struct device_attribute *attr, 2344 struct device_attribute *attr,
@@ -1483,7 +2390,7 @@ static int __init bluetooth_init(struct ibm_init_struct *iibm)
1483 2390
1484 vdbg_printk(TPACPI_DBG_INIT, "initializing bluetooth subdriver\n"); 2391 vdbg_printk(TPACPI_DBG_INIT, "initializing bluetooth subdriver\n");
1485 2392
1486 IBM_ACPIHANDLE_INIT(hkey); 2393 TPACPI_ACPIHANDLE_INIT(hkey);
1487 2394
1488 /* bluetooth not supported on 570, 600e/x, 770e, 770x, A21e, A2xm/p, 2395 /* bluetooth not supported on 570, 600e/x, 770e, 770x, A21e, A2xm/p,
1489 G4x, R30, R31, R40e, R50e, T20-22, X20-21 */ 2396 G4x, R30, R31, R40e, R50e, T20-22, X20-21 */
@@ -1596,6 +2503,16 @@ static struct ibm_struct bluetooth_driver_data = {
1596 * Wan subdriver 2503 * Wan subdriver
1597 */ 2504 */
1598 2505
2506enum {
2507 /* ACPI GWAN/SWAN bits */
2508 TP_ACPI_WANCARD_HWPRESENT = 0x01, /* Wan hw available */
2509 TP_ACPI_WANCARD_RADIOSSW = 0x02, /* Wan radio enabled */
2510 TP_ACPI_WANCARD_UNK = 0x04, /* unknown function */
2511};
2512
2513static int wan_get_radiosw(void);
2514static int wan_set_radiosw(int radio_on);
2515
1599/* sysfs wan enable ---------------------------------------------------- */ 2516/* sysfs wan enable ---------------------------------------------------- */
1600static ssize_t wan_enable_show(struct device *dev, 2517static ssize_t wan_enable_show(struct device *dev,
1601 struct device_attribute *attr, 2518 struct device_attribute *attr,
@@ -1647,7 +2564,7 @@ static int __init wan_init(struct ibm_init_struct *iibm)
1647 2564
1648 vdbg_printk(TPACPI_DBG_INIT, "initializing wan subdriver\n"); 2565 vdbg_printk(TPACPI_DBG_INIT, "initializing wan subdriver\n");
1649 2566
1650 IBM_ACPIHANDLE_INIT(hkey); 2567 TPACPI_ACPIHANDLE_INIT(hkey);
1651 2568
1652 tp_features.wan = hkey_handle && 2569 tp_features.wan = hkey_handle &&
1653 acpi_evalf(hkey_handle, &status, "GWAN", "qd"); 2570 acpi_evalf(hkey_handle, &status, "GWAN", "qd");
@@ -1759,17 +2676,41 @@ static struct ibm_struct wan_driver_data = {
1759 * Video subdriver 2676 * Video subdriver
1760 */ 2677 */
1761 2678
2679enum video_access_mode {
2680 TPACPI_VIDEO_NONE = 0,
2681 TPACPI_VIDEO_570, /* 570 */
2682 TPACPI_VIDEO_770, /* 600e/x, 770e, 770x */
2683 TPACPI_VIDEO_NEW, /* all others */
2684};
2685
2686enum { /* video status flags, based on VIDEO_570 */
2687 TP_ACPI_VIDEO_S_LCD = 0x01, /* LCD output enabled */
2688 TP_ACPI_VIDEO_S_CRT = 0x02, /* CRT output enabled */
2689 TP_ACPI_VIDEO_S_DVI = 0x08, /* DVI output enabled */
2690};
2691
2692enum { /* TPACPI_VIDEO_570 constants */
2693 TP_ACPI_VIDEO_570_PHSCMD = 0x87, /* unknown magic constant :( */
2694 TP_ACPI_VIDEO_570_PHSMASK = 0x03, /* PHS bits that map to
2695 * video_status_flags */
2696 TP_ACPI_VIDEO_570_PHS2CMD = 0x8b, /* unknown magic constant :( */
2697 TP_ACPI_VIDEO_570_PHS2SET = 0x80, /* unknown magic constant :( */
2698};
2699
1762static enum video_access_mode video_supported; 2700static enum video_access_mode video_supported;
1763static int video_orig_autosw; 2701static int video_orig_autosw;
1764 2702
1765IBM_HANDLE(vid, root, "\\_SB.PCI.AGP.VGA", /* 570 */ 2703static int video_autosw_get(void);
2704static int video_autosw_set(int enable);
2705
2706TPACPI_HANDLE(vid, root, "\\_SB.PCI.AGP.VGA", /* 570 */
1766 "\\_SB.PCI0.AGP0.VID0", /* 600e/x, 770x */ 2707 "\\_SB.PCI0.AGP0.VID0", /* 600e/x, 770x */
1767 "\\_SB.PCI0.VID0", /* 770e */ 2708 "\\_SB.PCI0.VID0", /* 770e */
1768 "\\_SB.PCI0.VID", /* A21e, G4x, R50e, X30, X40 */ 2709 "\\_SB.PCI0.VID", /* A21e, G4x, R50e, X30, X40 */
1769 "\\_SB.PCI0.AGP.VID", /* all others */ 2710 "\\_SB.PCI0.AGP.VID", /* all others */
1770 ); /* R30, R31 */ 2711 ); /* R30, R31 */
1771 2712
1772IBM_HANDLE(vid2, root, "\\_SB.PCI0.AGPB.VID"); /* G41 */ 2713TPACPI_HANDLE(vid2, root, "\\_SB.PCI0.AGPB.VID"); /* G41 */
1773 2714
1774static int __init video_init(struct ibm_init_struct *iibm) 2715static int __init video_init(struct ibm_init_struct *iibm)
1775{ 2716{
@@ -1777,8 +2718,8 @@ static int __init video_init(struct ibm_init_struct *iibm)
1777 2718
1778 vdbg_printk(TPACPI_DBG_INIT, "initializing video subdriver\n"); 2719 vdbg_printk(TPACPI_DBG_INIT, "initializing video subdriver\n");
1779 2720
1780 IBM_ACPIHANDLE_INIT(vid); 2721 TPACPI_ACPIHANDLE_INIT(vid);
1781 IBM_ACPIHANDLE_INIT(vid2); 2722 TPACPI_ACPIHANDLE_INIT(vid2);
1782 2723
1783 if (vid2_handle && acpi_evalf(NULL, &ivga, "\\IVGA", "d") && ivga) 2724 if (vid2_handle && acpi_evalf(NULL, &ivga, "\\IVGA", "d") && ivga)
1784 /* G41, assume IVGA doesn't change */ 2725 /* G41, assume IVGA doesn't change */
@@ -1809,7 +2750,7 @@ static void video_exit(void)
1809 dbg_printk(TPACPI_DBG_EXIT, 2750 dbg_printk(TPACPI_DBG_EXIT,
1810 "restoring original video autoswitch mode\n"); 2751 "restoring original video autoswitch mode\n");
1811 if (video_autosw_set(video_orig_autosw)) 2752 if (video_autosw_set(video_orig_autosw))
1812 printk(IBM_ERR "error while trying to restore original " 2753 printk(TPACPI_ERR "error while trying to restore original "
1813 "video autoswitch mode\n"); 2754 "video autoswitch mode\n");
1814} 2755}
1815 2756
@@ -1882,13 +2823,14 @@ static int video_outputsw_set(int status)
1882 res = acpi_evalf(vid_handle, NULL, 2823 res = acpi_evalf(vid_handle, NULL,
1883 "ASWT", "vdd", status * 0x100, 0); 2824 "ASWT", "vdd", status * 0x100, 0);
1884 if (!autosw && video_autosw_set(autosw)) { 2825 if (!autosw && video_autosw_set(autosw)) {
1885 printk(IBM_ERR "video auto-switch left enabled due to error\n"); 2826 printk(TPACPI_ERR
2827 "video auto-switch left enabled due to error\n");
1886 return -EIO; 2828 return -EIO;
1887 } 2829 }
1888 break; 2830 break;
1889 case TPACPI_VIDEO_NEW: 2831 case TPACPI_VIDEO_NEW:
1890 res = acpi_evalf(NULL, NULL, "\\VUPS", "vd", 0x80) && 2832 res = acpi_evalf(NULL, NULL, "\\VUPS", "vd", 0x80) &&
1891 acpi_evalf(NULL, NULL, "\\VSDS", "vdd", status, 1); 2833 acpi_evalf(NULL, NULL, "\\VSDS", "vdd", status, 1);
1892 break; 2834 break;
1893 default: 2835 default:
1894 return -ENOSYS; 2836 return -ENOSYS;
@@ -1951,7 +2893,8 @@ static int video_outputsw_cycle(void)
1951 return -ENOSYS; 2893 return -ENOSYS;
1952 } 2894 }
1953 if (!autosw && video_autosw_set(autosw)) { 2895 if (!autosw && video_autosw_set(autosw)) {
1954 printk(IBM_ERR "video auto-switch left enabled due to error\n"); 2896 printk(TPACPI_ERR
2897 "video auto-switch left enabled due to error\n");
1955 return -EIO; 2898 return -EIO;
1956 } 2899 }
1957 2900
@@ -2080,16 +3023,16 @@ static struct ibm_struct video_driver_data = {
2080 * Light (thinklight) subdriver 3023 * Light (thinklight) subdriver
2081 */ 3024 */
2082 3025
2083IBM_HANDLE(lght, root, "\\LGHT"); /* A21e, A2xm/p, T20-22, X20-21 */ 3026TPACPI_HANDLE(lght, root, "\\LGHT"); /* A21e, A2xm/p, T20-22, X20-21 */
2084IBM_HANDLE(ledb, ec, "LEDB"); /* G4x */ 3027TPACPI_HANDLE(ledb, ec, "LEDB"); /* G4x */
2085 3028
2086static int __init light_init(struct ibm_init_struct *iibm) 3029static int __init light_init(struct ibm_init_struct *iibm)
2087{ 3030{
2088 vdbg_printk(TPACPI_DBG_INIT, "initializing light subdriver\n"); 3031 vdbg_printk(TPACPI_DBG_INIT, "initializing light subdriver\n");
2089 3032
2090 IBM_ACPIHANDLE_INIT(ledb); 3033 TPACPI_ACPIHANDLE_INIT(ledb);
2091 IBM_ACPIHANDLE_INIT(lght); 3034 TPACPI_ACPIHANDLE_INIT(lght);
2092 IBM_ACPIHANDLE_INIT(cmos); 3035 TPACPI_ACPIHANDLE_INIT(cmos);
2093 3036
2094 /* light not supported on 570, 600e/x, 770e, 770x, G4x, R30, R31 */ 3037 /* light not supported on 570, 600e/x, 770e, 770x, G4x, R30, R31 */
2095 tp_features.light = (cmos_handle || lght_handle) && !ledb_handle; 3038 tp_features.light = (cmos_handle || lght_handle) && !ledb_handle;
@@ -2167,14 +3110,18 @@ static struct ibm_struct light_driver_data = {
2167 3110
2168#ifdef CONFIG_THINKPAD_ACPI_DOCK 3111#ifdef CONFIG_THINKPAD_ACPI_DOCK
2169 3112
2170IBM_HANDLE(dock, root, "\\_SB.GDCK", /* X30, X31, X40 */ 3113static void dock_notify(struct ibm_struct *ibm, u32 event);
3114static int dock_read(char *p);
3115static int dock_write(char *buf);
3116
3117TPACPI_HANDLE(dock, root, "\\_SB.GDCK", /* X30, X31, X40 */
2171 "\\_SB.PCI0.DOCK", /* 600e/x,770e,770x,A2xm/p,T20-22,X20-21 */ 3118 "\\_SB.PCI0.DOCK", /* 600e/x,770e,770x,A2xm/p,T20-22,X20-21 */
2172 "\\_SB.PCI0.PCI1.DOCK", /* all others */ 3119 "\\_SB.PCI0.PCI1.DOCK", /* all others */
2173 "\\_SB.PCI.ISA.SLCE", /* 570 */ 3120 "\\_SB.PCI.ISA.SLCE", /* 570 */
2174 ); /* A21e,G4x,R30,R31,R32,R40,R40e,R50e */ 3121 ); /* A21e,G4x,R30,R31,R32,R40,R40e,R50e */
2175 3122
2176/* don't list other alternatives as we install a notify handler on the 570 */ 3123/* don't list other alternatives as we install a notify handler on the 570 */
2177IBM_HANDLE(pci, root, "\\_SB.PCI"); /* 570 */ 3124TPACPI_HANDLE(pci, root, "\\_SB.PCI"); /* 570 */
2178 3125
2179static const struct acpi_device_id ibm_pci_device_ids[] = { 3126static const struct acpi_device_id ibm_pci_device_ids[] = {
2180 {PCI_ROOT_HID_STRING, 0}, 3127 {PCI_ROOT_HID_STRING, 0},
@@ -2217,7 +3164,7 @@ static int __init dock_init(struct ibm_init_struct *iibm)
2217{ 3164{
2218 vdbg_printk(TPACPI_DBG_INIT, "initializing dock subdriver\n"); 3165 vdbg_printk(TPACPI_DBG_INIT, "initializing dock subdriver\n");
2219 3166
2220 IBM_ACPIHANDLE_INIT(dock); 3167 TPACPI_ACPIHANDLE_INIT(dock);
2221 3168
2222 vdbg_printk(TPACPI_DBG_INIT, "dock is %s\n", 3169 vdbg_printk(TPACPI_DBG_INIT, "dock is %s\n",
2223 str_supported(dock_handle != NULL)); 3170 str_supported(dock_handle != NULL));
@@ -2233,7 +3180,7 @@ static int __init dock_init2(struct ibm_init_struct *iibm)
2233 3180
2234 if (dock_driver_data[0].flags.acpi_driver_registered && 3181 if (dock_driver_data[0].flags.acpi_driver_registered &&
2235 dock_driver_data[0].flags.acpi_notify_installed) { 3182 dock_driver_data[0].flags.acpi_notify_installed) {
2236 IBM_ACPIHANDLE_INIT(pci); 3183 TPACPI_ACPIHANDLE_INIT(pci);
2237 dock2_needed = (pci_handle != NULL); 3184 dock2_needed = (pci_handle != NULL);
2238 vdbg_printk(TPACPI_DBG_INIT, 3185 vdbg_printk(TPACPI_DBG_INIT,
2239 "dock PCI handler for the TP 570 is %s\n", 3186 "dock PCI handler for the TP 570 is %s\n",
@@ -2265,7 +3212,7 @@ static void dock_notify(struct ibm_struct *ibm, u32 event)
2265 else if (event == 0 && docked) 3212 else if (event == 0 && docked)
2266 data = 3; /* dock */ 3213 data = 3; /* dock */
2267 else { 3214 else {
2268 printk(IBM_ERR "unknown dock event %d, status %d\n", 3215 printk(TPACPI_ERR "unknown dock event %d, status %d\n",
2269 event, _sta(dock_handle)); 3216 event, _sta(dock_handle));
2270 data = 0; /* unknown */ 3217 data = 0; /* unknown */
2271 } 3218 }
@@ -2321,18 +3268,19 @@ static int dock_write(char *buf)
2321 */ 3268 */
2322 3269
2323#ifdef CONFIG_THINKPAD_ACPI_BAY 3270#ifdef CONFIG_THINKPAD_ACPI_BAY
2324IBM_HANDLE(bay, root, "\\_SB.PCI.IDE.SECN.MAST", /* 570 */ 3271
3272TPACPI_HANDLE(bay, root, "\\_SB.PCI.IDE.SECN.MAST", /* 570 */
2325 "\\_SB.PCI0.IDE0.IDES.IDSM", /* 600e/x, 770e, 770x */ 3273 "\\_SB.PCI0.IDE0.IDES.IDSM", /* 600e/x, 770e, 770x */
2326 "\\_SB.PCI0.SATA.SCND.MSTR", /* T60, X60, Z60 */ 3274 "\\_SB.PCI0.SATA.SCND.MSTR", /* T60, X60, Z60 */
2327 "\\_SB.PCI0.IDE0.SCND.MSTR", /* all others */ 3275 "\\_SB.PCI0.IDE0.SCND.MSTR", /* all others */
2328 ); /* A21e, R30, R31 */ 3276 ); /* A21e, R30, R31 */
2329IBM_HANDLE(bay_ej, bay, "_EJ3", /* 600e/x, A2xm/p, A3x */ 3277TPACPI_HANDLE(bay_ej, bay, "_EJ3", /* 600e/x, A2xm/p, A3x */
2330 "_EJ0", /* all others */ 3278 "_EJ0", /* all others */
2331 ); /* 570,A21e,G4x,R30,R31,R32,R40e,R50e */ 3279 ); /* 570,A21e,G4x,R30,R31,R32,R40e,R50e */
2332IBM_HANDLE(bay2, root, "\\_SB.PCI0.IDE0.PRIM.SLAV", /* A3x, R32 */ 3280TPACPI_HANDLE(bay2, root, "\\_SB.PCI0.IDE0.PRIM.SLAV", /* A3x, R32 */
2333 "\\_SB.PCI0.IDE0.IDEP.IDPS", /* 600e/x, 770e, 770x */ 3281 "\\_SB.PCI0.IDE0.IDEP.IDPS", /* 600e/x, 770e, 770x */
2334 ); /* all others */ 3282 ); /* all others */
2335IBM_HANDLE(bay2_ej, bay2, "_EJ3", /* 600e/x, 770e, A3x */ 3283TPACPI_HANDLE(bay2_ej, bay2, "_EJ3", /* 600e/x, 770e, A3x */
2336 "_EJ0", /* 770x */ 3284 "_EJ0", /* 770x */
2337 ); /* all others */ 3285 ); /* all others */
2338 3286
@@ -2340,12 +3288,12 @@ static int __init bay_init(struct ibm_init_struct *iibm)
2340{ 3288{
2341 vdbg_printk(TPACPI_DBG_INIT, "initializing bay subdriver\n"); 3289 vdbg_printk(TPACPI_DBG_INIT, "initializing bay subdriver\n");
2342 3290
2343 IBM_ACPIHANDLE_INIT(bay); 3291 TPACPI_ACPIHANDLE_INIT(bay);
2344 if (bay_handle) 3292 if (bay_handle)
2345 IBM_ACPIHANDLE_INIT(bay_ej); 3293 TPACPI_ACPIHANDLE_INIT(bay_ej);
2346 IBM_ACPIHANDLE_INIT(bay2); 3294 TPACPI_ACPIHANDLE_INIT(bay2);
2347 if (bay2_handle) 3295 if (bay2_handle)
2348 IBM_ACPIHANDLE_INIT(bay2_ej); 3296 TPACPI_ACPIHANDLE_INIT(bay2_ej);
2349 3297
2350 tp_features.bay_status = bay_handle && 3298 tp_features.bay_status = bay_handle &&
2351 acpi_evalf(bay_handle, NULL, "_STA", "qv"); 3299 acpi_evalf(bay_handle, NULL, "_STA", "qv");
@@ -2474,7 +3422,7 @@ static int __init cmos_init(struct ibm_init_struct *iibm)
2474 vdbg_printk(TPACPI_DBG_INIT, 3422 vdbg_printk(TPACPI_DBG_INIT,
2475 "initializing cmos commands subdriver\n"); 3423 "initializing cmos commands subdriver\n");
2476 3424
2477 IBM_ACPIHANDLE_INIT(cmos); 3425 TPACPI_ACPIHANDLE_INIT(cmos);
2478 3426
2479 vdbg_printk(TPACPI_DBG_INIT, "cmos commands are %s\n", 3427 vdbg_printk(TPACPI_DBG_INIT, "cmos commands are %s\n",
2480 str_supported(cmos_handle != NULL)); 3428 str_supported(cmos_handle != NULL));
@@ -2538,10 +3486,24 @@ static struct ibm_struct cmos_driver_data = {
2538 * LED subdriver 3486 * LED subdriver
2539 */ 3487 */
2540 3488
3489enum led_access_mode {
3490 TPACPI_LED_NONE = 0,
3491 TPACPI_LED_570, /* 570 */
3492 TPACPI_LED_OLD, /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20-21 */
3493 TPACPI_LED_NEW, /* all others */
3494};
3495
3496enum { /* For TPACPI_LED_OLD */
3497 TPACPI_LED_EC_HLCL = 0x0c, /* EC reg to get led to power on */
3498 TPACPI_LED_EC_HLBL = 0x0d, /* EC reg to blink a lit led */
3499 TPACPI_LED_EC_HLMS = 0x0e, /* EC reg to select led to command */
3500};
3501
2541static enum led_access_mode led_supported; 3502static enum led_access_mode led_supported;
2542 3503
2543IBM_HANDLE(led, ec, "SLED", /* 570 */ 3504TPACPI_HANDLE(led, ec, "SLED", /* 570 */
2544 "SYSL", /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20-21 */ 3505 "SYSL", /* 600e/x, 770e, 770x, A21e, A2xm/p, */
3506 /* T20-22, X20-21 */
2545 "LED", /* all others */ 3507 "LED", /* all others */
2546 ); /* R30, R31 */ 3508 ); /* R30, R31 */
2547 3509
@@ -2549,7 +3511,7 @@ static int __init led_init(struct ibm_init_struct *iibm)
2549{ 3511{
2550 vdbg_printk(TPACPI_DBG_INIT, "initializing LED subdriver\n"); 3512 vdbg_printk(TPACPI_DBG_INIT, "initializing LED subdriver\n");
2551 3513
2552 IBM_ACPIHANDLE_INIT(led); 3514 TPACPI_ACPIHANDLE_INIT(led);
2553 3515
2554 if (!led_handle) 3516 if (!led_handle)
2555 /* led not supported on R30, R31 */ 3517 /* led not supported on R30, R31 */
@@ -2638,13 +3600,11 @@ static int led_write(char *buf)
2638 led = 1 << led; 3600 led = 1 << led;
2639 ret = ec_write(TPACPI_LED_EC_HLMS, led); 3601 ret = ec_write(TPACPI_LED_EC_HLMS, led);
2640 if (ret >= 0) 3602 if (ret >= 0)
2641 ret = 3603 ret = ec_write(TPACPI_LED_EC_HLBL,
2642 ec_write(TPACPI_LED_EC_HLBL, 3604 led * led_exp_hlbl[ind]);
2643 led * led_exp_hlbl[ind]);
2644 if (ret >= 0) 3605 if (ret >= 0)
2645 ret = 3606 ret = ec_write(TPACPI_LED_EC_HLCL,
2646 ec_write(TPACPI_LED_EC_HLCL, 3607 led * led_exp_hlcl[ind]);
2647 led * led_exp_hlcl[ind]);
2648 if (ret < 0) 3608 if (ret < 0)
2649 return ret; 3609 return ret;
2650 } else { 3610 } else {
@@ -2668,13 +3628,13 @@ static struct ibm_struct led_driver_data = {
2668 * Beep subdriver 3628 * Beep subdriver
2669 */ 3629 */
2670 3630
2671IBM_HANDLE(beep, ec, "BEEP"); /* all except R30, R31 */ 3631TPACPI_HANDLE(beep, ec, "BEEP"); /* all except R30, R31 */
2672 3632
2673static int __init beep_init(struct ibm_init_struct *iibm) 3633static int __init beep_init(struct ibm_init_struct *iibm)
2674{ 3634{
2675 vdbg_printk(TPACPI_DBG_INIT, "initializing beep subdriver\n"); 3635 vdbg_printk(TPACPI_DBG_INIT, "initializing beep subdriver\n");
2676 3636
2677 IBM_ACPIHANDLE_INIT(beep); 3637 TPACPI_ACPIHANDLE_INIT(beep);
2678 3638
2679 vdbg_printk(TPACPI_DBG_INIT, "beep is %s\n", 3639 vdbg_printk(TPACPI_DBG_INIT, "beep is %s\n",
2680 str_supported(beep_handle != NULL)); 3640 str_supported(beep_handle != NULL));
@@ -2727,8 +3687,109 @@ static struct ibm_struct beep_driver_data = {
2727 * Thermal subdriver 3687 * Thermal subdriver
2728 */ 3688 */
2729 3689
3690enum thermal_access_mode {
3691 TPACPI_THERMAL_NONE = 0, /* No thermal support */
3692 TPACPI_THERMAL_ACPI_TMP07, /* Use ACPI TMP0-7 */
3693 TPACPI_THERMAL_ACPI_UPDT, /* Use ACPI TMP0-7 with UPDT */
3694 TPACPI_THERMAL_TPEC_8, /* Use ACPI EC regs, 8 sensors */
3695 TPACPI_THERMAL_TPEC_16, /* Use ACPI EC regs, 16 sensors */
3696};
3697
3698enum { /* TPACPI_THERMAL_TPEC_* */
3699 TP_EC_THERMAL_TMP0 = 0x78, /* ACPI EC regs TMP 0..7 */
3700 TP_EC_THERMAL_TMP8 = 0xC0, /* ACPI EC regs TMP 8..15 */
3701 TP_EC_THERMAL_TMP_NA = -128, /* ACPI EC sensor not available */
3702};
3703
3704#define TPACPI_MAX_THERMAL_SENSORS 16 /* Max thermal sensors supported */
3705struct ibm_thermal_sensors_struct {
3706 s32 temp[TPACPI_MAX_THERMAL_SENSORS];
3707};
3708
2730static enum thermal_access_mode thermal_read_mode; 3709static enum thermal_access_mode thermal_read_mode;
2731 3710
3711/* idx is zero-based */
3712static int thermal_get_sensor(int idx, s32 *value)
3713{
3714 int t;
3715 s8 tmp;
3716 char tmpi[5];
3717
3718 t = TP_EC_THERMAL_TMP0;
3719
3720 switch (thermal_read_mode) {
3721#if TPACPI_MAX_THERMAL_SENSORS >= 16
3722 case TPACPI_THERMAL_TPEC_16:
3723 if (idx >= 8 && idx <= 15) {
3724 t = TP_EC_THERMAL_TMP8;
3725 idx -= 8;
3726 }
3727 /* fallthrough */
3728#endif
3729 case TPACPI_THERMAL_TPEC_8:
3730 if (idx <= 7) {
3731 if (!acpi_ec_read(t + idx, &tmp))
3732 return -EIO;
3733 *value = tmp * 1000;
3734 return 0;
3735 }
3736 break;
3737
3738 case TPACPI_THERMAL_ACPI_UPDT:
3739 if (idx <= 7) {
3740 snprintf(tmpi, sizeof(tmpi), "TMP%c", '0' + idx);
3741 if (!acpi_evalf(ec_handle, NULL, "UPDT", "v"))
3742 return -EIO;
3743 if (!acpi_evalf(ec_handle, &t, tmpi, "d"))
3744 return -EIO;
3745 *value = (t - 2732) * 100;
3746 return 0;
3747 }
3748 break;
3749
3750 case TPACPI_THERMAL_ACPI_TMP07:
3751 if (idx <= 7) {
3752 snprintf(tmpi, sizeof(tmpi), "TMP%c", '0' + idx);
3753 if (!acpi_evalf(ec_handle, &t, tmpi, "d"))
3754 return -EIO;
3755 if (t > 127 || t < -127)
3756 t = TP_EC_THERMAL_TMP_NA;
3757 *value = t * 1000;
3758 return 0;
3759 }
3760 break;
3761
3762 case TPACPI_THERMAL_NONE:
3763 default:
3764 return -ENOSYS;
3765 }
3766
3767 return -EINVAL;
3768}
3769
3770static int thermal_get_sensors(struct ibm_thermal_sensors_struct *s)
3771{
3772 int res, i;
3773 int n;
3774
3775 n = 8;
3776 i = 0;
3777
3778 if (!s)
3779 return -EINVAL;
3780
3781 if (thermal_read_mode == TPACPI_THERMAL_TPEC_16)
3782 n = 16;
3783
3784 for (i = 0 ; i < n; i++) {
3785 res = thermal_get_sensor(i, &s->temp[i]);
3786 if (res)
3787 return res;
3788 }
3789
3790 return n;
3791}
3792
2732/* sysfs temp##_input -------------------------------------------------- */ 3793/* sysfs temp##_input -------------------------------------------------- */
2733 3794
2734static ssize_t thermal_temp_input_show(struct device *dev, 3795static ssize_t thermal_temp_input_show(struct device *dev,
@@ -2751,7 +3812,8 @@ static ssize_t thermal_temp_input_show(struct device *dev,
2751} 3812}
2752 3813
2753#define THERMAL_SENSOR_ATTR_TEMP(_idxA, _idxB) \ 3814#define THERMAL_SENSOR_ATTR_TEMP(_idxA, _idxB) \
2754 SENSOR_ATTR(temp##_idxA##_input, S_IRUGO, thermal_temp_input_show, NULL, _idxB) 3815 SENSOR_ATTR(temp##_idxA##_input, S_IRUGO, \
3816 thermal_temp_input_show, NULL, _idxB)
2755 3817
2756static struct sensor_device_attribute sensor_dev_attr_thermal_temp_input[] = { 3818static struct sensor_device_attribute sensor_dev_attr_thermal_temp_input[] = {
2757 THERMAL_SENSOR_ATTR_TEMP(1, 0), 3819 THERMAL_SENSOR_ATTR_TEMP(1, 0),
@@ -2845,12 +3907,13 @@ static int __init thermal_init(struct ibm_init_struct *iibm)
2845 if (ta1 == 0) { 3907 if (ta1 == 0) {
2846 /* This is sheer paranoia, but we handle it anyway */ 3908 /* This is sheer paranoia, but we handle it anyway */
2847 if (acpi_tmp7) { 3909 if (acpi_tmp7) {
2848 printk(IBM_ERR 3910 printk(TPACPI_ERR
2849 "ThinkPad ACPI EC access misbehaving, " 3911 "ThinkPad ACPI EC access misbehaving, "
2850 "falling back to ACPI TMPx access mode\n"); 3912 "falling back to ACPI TMPx access "
3913 "mode\n");
2851 thermal_read_mode = TPACPI_THERMAL_ACPI_TMP07; 3914 thermal_read_mode = TPACPI_THERMAL_ACPI_TMP07;
2852 } else { 3915 } else {
2853 printk(IBM_ERR 3916 printk(TPACPI_ERR
2854 "ThinkPad ACPI EC access misbehaving, " 3917 "ThinkPad ACPI EC access misbehaving, "
2855 "disabling thermal sensors access\n"); 3918 "disabling thermal sensors access\n");
2856 thermal_read_mode = TPACPI_THERMAL_NONE; 3919 thermal_read_mode = TPACPI_THERMAL_NONE;
@@ -2877,7 +3940,7 @@ static int __init thermal_init(struct ibm_init_struct *iibm)
2877 str_supported(thermal_read_mode != TPACPI_THERMAL_NONE), 3940 str_supported(thermal_read_mode != TPACPI_THERMAL_NONE),
2878 thermal_read_mode); 3941 thermal_read_mode);
2879 3942
2880 switch(thermal_read_mode) { 3943 switch (thermal_read_mode) {
2881 case TPACPI_THERMAL_TPEC_16: 3944 case TPACPI_THERMAL_TPEC_16:
2882 res = sysfs_create_group(&tpacpi_sensors_pdev->dev.kobj, 3945 res = sysfs_create_group(&tpacpi_sensors_pdev->dev.kobj,
2883 &thermal_temp_input16_group); 3946 &thermal_temp_input16_group);
@@ -2902,7 +3965,7 @@ static int __init thermal_init(struct ibm_init_struct *iibm)
2902 3965
2903static void thermal_exit(void) 3966static void thermal_exit(void)
2904{ 3967{
2905 switch(thermal_read_mode) { 3968 switch (thermal_read_mode) {
2906 case TPACPI_THERMAL_TPEC_16: 3969 case TPACPI_THERMAL_TPEC_16:
2907 sysfs_remove_group(&tpacpi_sensors_pdev->dev.kobj, 3970 sysfs_remove_group(&tpacpi_sensors_pdev->dev.kobj,
2908 &thermal_temp_input16_group); 3971 &thermal_temp_input16_group);
@@ -2919,88 +3982,6 @@ static void thermal_exit(void)
2919 } 3982 }
2920} 3983}
2921 3984
2922/* idx is zero-based */
2923static int thermal_get_sensor(int idx, s32 *value)
2924{
2925 int t;
2926 s8 tmp;
2927 char tmpi[5];
2928
2929 t = TP_EC_THERMAL_TMP0;
2930
2931 switch (thermal_read_mode) {
2932#if TPACPI_MAX_THERMAL_SENSORS >= 16
2933 case TPACPI_THERMAL_TPEC_16:
2934 if (idx >= 8 && idx <= 15) {
2935 t = TP_EC_THERMAL_TMP8;
2936 idx -= 8;
2937 }
2938 /* fallthrough */
2939#endif
2940 case TPACPI_THERMAL_TPEC_8:
2941 if (idx <= 7) {
2942 if (!acpi_ec_read(t + idx, &tmp))
2943 return -EIO;
2944 *value = tmp * 1000;
2945 return 0;
2946 }
2947 break;
2948
2949 case TPACPI_THERMAL_ACPI_UPDT:
2950 if (idx <= 7) {
2951 snprintf(tmpi, sizeof(tmpi), "TMP%c", '0' + idx);
2952 if (!acpi_evalf(ec_handle, NULL, "UPDT", "v"))
2953 return -EIO;
2954 if (!acpi_evalf(ec_handle, &t, tmpi, "d"))
2955 return -EIO;
2956 *value = (t - 2732) * 100;
2957 return 0;
2958 }
2959 break;
2960
2961 case TPACPI_THERMAL_ACPI_TMP07:
2962 if (idx <= 7) {
2963 snprintf(tmpi, sizeof(tmpi), "TMP%c", '0' + idx);
2964 if (!acpi_evalf(ec_handle, &t, tmpi, "d"))
2965 return -EIO;
2966 if (t > 127 || t < -127)
2967 t = TP_EC_THERMAL_TMP_NA;
2968 *value = t * 1000;
2969 return 0;
2970 }
2971 break;
2972
2973 case TPACPI_THERMAL_NONE:
2974 default:
2975 return -ENOSYS;
2976 }
2977
2978 return -EINVAL;
2979}
2980
2981static int thermal_get_sensors(struct ibm_thermal_sensors_struct *s)
2982{
2983 int res, i;
2984 int n;
2985
2986 n = 8;
2987 i = 0;
2988
2989 if (!s)
2990 return -EINVAL;
2991
2992 if (thermal_read_mode == TPACPI_THERMAL_TPEC_16)
2993 n = 16;
2994
2995 for(i = 0 ; i < n; i++) {
2996 res = thermal_get_sensor(i, &s->temp[i]);
2997 if (res)
2998 return res;
2999 }
3000
3001 return n;
3002}
3003
3004static int thermal_read(char *p) 3985static int thermal_read(char *p)
3005{ 3986{
3006 int len = 0; 3987 int len = 0;
@@ -3103,14 +4084,110 @@ static struct ibm_struct ecdump_driver_data = {
3103 * Backlight/brightness subdriver 4084 * Backlight/brightness subdriver
3104 */ 4085 */
3105 4086
4087#define TPACPI_BACKLIGHT_DEV_NAME "thinkpad_screen"
4088
3106static struct backlight_device *ibm_backlight_device; 4089static struct backlight_device *ibm_backlight_device;
4090static int brightness_offset = 0x31;
4091static int brightness_mode;
4092static unsigned int brightness_enable = 2; /* 2 = auto, 0 = no, 1 = yes */
4093
4094static struct mutex brightness_mutex;
4095
4096/*
4097 * ThinkPads can read brightness from two places: EC 0x31, or
4098 * CMOS NVRAM byte 0x5E, bits 0-3.
4099 */
4100static int brightness_get(struct backlight_device *bd)
4101{
4102 u8 lec = 0, lcmos = 0, level = 0;
4103
4104 if (brightness_mode & 1) {
4105 if (!acpi_ec_read(brightness_offset, &lec))
4106 return -EIO;
4107 lec &= (tp_features.bright_16levels)? 0x0f : 0x07;
4108 level = lec;
4109 };
4110 if (brightness_mode & 2) {
4111 lcmos = (nvram_read_byte(TP_NVRAM_ADDR_BRIGHTNESS)
4112 & TP_NVRAM_MASK_LEVEL_BRIGHTNESS)
4113 >> TP_NVRAM_POS_LEVEL_BRIGHTNESS;
4114 lcmos &= (tp_features.bright_16levels)? 0x0f : 0x07;
4115 level = lcmos;
4116 }
4117
4118 if (brightness_mode == 3 && lec != lcmos) {
4119 printk(TPACPI_ERR
4120 "CMOS NVRAM (%u) and EC (%u) do not agree "
4121 "on display brightness level\n",
4122 (unsigned int) lcmos,
4123 (unsigned int) lec);
4124 return -EIO;
4125 }
4126
4127 return level;
4128}
4129
4130/* May return EINTR which can always be mapped to ERESTARTSYS */
4131static int brightness_set(int value)
4132{
4133 int cmos_cmd, inc, i, res;
4134 int current_value;
4135
4136 if (value > ((tp_features.bright_16levels)? 15 : 7))
4137 return -EINVAL;
4138
4139 res = mutex_lock_interruptible(&brightness_mutex);
4140 if (res < 0)
4141 return res;
4142
4143 current_value = brightness_get(NULL);
4144 if (current_value < 0) {
4145 res = current_value;
4146 goto errout;
4147 }
4148
4149 cmos_cmd = value > current_value ?
4150 TP_CMOS_BRIGHTNESS_UP :
4151 TP_CMOS_BRIGHTNESS_DOWN;
4152 inc = (value > current_value)? 1 : -1;
4153
4154 res = 0;
4155 for (i = current_value; i != value; i += inc) {
4156 if ((brightness_mode & 2) &&
4157 issue_thinkpad_cmos_command(cmos_cmd)) {
4158 res = -EIO;
4159 goto errout;
4160 }
4161 if ((brightness_mode & 1) &&
4162 !acpi_ec_write(brightness_offset, i + inc)) {
4163 res = -EIO;
4164 goto errout;;
4165 }
4166 }
4167
4168errout:
4169 mutex_unlock(&brightness_mutex);
4170 return res;
4171}
4172
4173/* sysfs backlight class ----------------------------------------------- */
4174
4175static int brightness_update_status(struct backlight_device *bd)
4176{
4177 /* it is the backlight class's job (caller) to handle
4178 * EINTR and other errors properly */
4179 return brightness_set(
4180 (bd->props.fb_blank == FB_BLANK_UNBLANK &&
4181 bd->props.power == FB_BLANK_UNBLANK) ?
4182 bd->props.brightness : 0);
4183}
3107 4184
3108static struct backlight_ops ibm_backlight_data = { 4185static struct backlight_ops ibm_backlight_data = {
3109 .get_brightness = brightness_get, 4186 .get_brightness = brightness_get,
3110 .update_status = brightness_update_status, 4187 .update_status = brightness_update_status,
3111}; 4188};
3112 4189
3113static struct mutex brightness_mutex; 4190/* --------------------------------------------------------------------- */
3114 4191
3115static int __init tpacpi_query_bcll_levels(acpi_handle handle) 4192static int __init tpacpi_query_bcll_levels(acpi_handle handle)
3116{ 4193{
@@ -3121,8 +4198,8 @@ static int __init tpacpi_query_bcll_levels(acpi_handle handle)
3121 if (ACPI_SUCCESS(acpi_evaluate_object(handle, NULL, NULL, &buffer))) { 4198 if (ACPI_SUCCESS(acpi_evaluate_object(handle, NULL, NULL, &buffer))) {
3122 obj = (union acpi_object *)buffer.pointer; 4199 obj = (union acpi_object *)buffer.pointer;
3123 if (!obj || (obj->type != ACPI_TYPE_PACKAGE)) { 4200 if (!obj || (obj->type != ACPI_TYPE_PACKAGE)) {
3124 printk(IBM_ERR "Unknown BCLL data, " 4201 printk(TPACPI_ERR "Unknown BCLL data, "
3125 "please report this to %s\n", IBM_MAIL); 4202 "please report this to %s\n", TPACPI_MAIL);
3126 rc = 0; 4203 rc = 0;
3127 } else { 4204 } else {
3128 rc = obj->package.count; 4205 rc = obj->package.count;
@@ -3160,14 +4237,15 @@ static int __init brightness_check_levels(void)
3160 void *found_node = NULL; 4237 void *found_node = NULL;
3161 4238
3162 if (!vid_handle) { 4239 if (!vid_handle) {
3163 IBM_ACPIHANDLE_INIT(vid); 4240 TPACPI_ACPIHANDLE_INIT(vid);
3164 } 4241 }
3165 if (!vid_handle) 4242 if (!vid_handle)
3166 return 0; 4243 return 0;
3167 4244
3168 /* Search for a BCLL package with 16 levels */ 4245 /* Search for a BCLL package with 16 levels */
3169 status = acpi_walk_namespace(ACPI_TYPE_PACKAGE, vid_handle, 3, 4246 status = acpi_walk_namespace(ACPI_TYPE_PACKAGE, vid_handle, 3,
3170 brightness_find_bcll, NULL, &found_node); 4247 brightness_find_bcll, NULL,
4248 &found_node);
3171 4249
3172 return (ACPI_SUCCESS(status) && found_node != NULL); 4250 return (ACPI_SUCCESS(status) && found_node != NULL);
3173} 4251}
@@ -3193,14 +4271,14 @@ static int __init brightness_check_std_acpi_support(void)
3193 void *found_node = NULL; 4271 void *found_node = NULL;
3194 4272
3195 if (!vid_handle) { 4273 if (!vid_handle) {
3196 IBM_ACPIHANDLE_INIT(vid); 4274 TPACPI_ACPIHANDLE_INIT(vid);
3197 } 4275 }
3198 if (!vid_handle) 4276 if (!vid_handle)
3199 return 0; 4277 return 0;
3200 4278
3201 /* Search for a _BCL method, but don't execute it */ 4279 /* Search for a _BCL method, but don't execute it */
3202 status = acpi_walk_namespace(ACPI_TYPE_METHOD, vid_handle, 3, 4280 status = acpi_walk_namespace(ACPI_TYPE_METHOD, vid_handle, 3,
3203 brightness_find_bcl, NULL, &found_node); 4281 brightness_find_bcl, NULL, &found_node);
3204 4282
3205 return (ACPI_SUCCESS(status) && found_node != NULL); 4283 return (ACPI_SUCCESS(status) && found_node != NULL);
3206} 4284}
@@ -3215,12 +4293,14 @@ static int __init brightness_init(struct ibm_init_struct *iibm)
3215 4293
3216 if (!brightness_enable) { 4294 if (!brightness_enable) {
3217 dbg_printk(TPACPI_DBG_INIT, 4295 dbg_printk(TPACPI_DBG_INIT,
3218 "brightness support disabled by module parameter\n"); 4296 "brightness support disabled by "
4297 "module parameter\n");
3219 return 1; 4298 return 1;
3220 } else if (brightness_enable > 1) { 4299 } else if (brightness_enable > 1) {
3221 if (brightness_check_std_acpi_support()) { 4300 if (brightness_check_std_acpi_support()) {
3222 printk(IBM_NOTICE 4301 printk(TPACPI_NOTICE
3223 "standard ACPI backlight interface available, not loading native one...\n"); 4302 "standard ACPI backlight interface "
4303 "available, not loading native one...\n");
3224 return 1; 4304 return 1;
3225 } 4305 }
3226 } 4306 }
@@ -3247,13 +4327,14 @@ static int __init brightness_init(struct ibm_init_struct *iibm)
3247 return 1; 4327 return 1;
3248 4328
3249 if (tp_features.bright_16levels) 4329 if (tp_features.bright_16levels)
3250 printk(IBM_INFO "detected a 16-level brightness capable ThinkPad\n"); 4330 printk(TPACPI_INFO
4331 "detected a 16-level brightness capable ThinkPad\n");
3251 4332
3252 ibm_backlight_device = backlight_device_register( 4333 ibm_backlight_device = backlight_device_register(
3253 TPACPI_BACKLIGHT_DEV_NAME, NULL, NULL, 4334 TPACPI_BACKLIGHT_DEV_NAME, NULL, NULL,
3254 &ibm_backlight_data); 4335 &ibm_backlight_data);
3255 if (IS_ERR(ibm_backlight_device)) { 4336 if (IS_ERR(ibm_backlight_device)) {
3256 printk(IBM_ERR "Could not register backlight device\n"); 4337 printk(TPACPI_ERR "Could not register backlight device\n");
3257 return PTR_ERR(ibm_backlight_device); 4338 return PTR_ERR(ibm_backlight_device);
3258 } 4339 }
3259 vdbg_printk(TPACPI_DBG_INIT, "brightness is supported\n"); 4340 vdbg_printk(TPACPI_DBG_INIT, "brightness is supported\n");
@@ -3276,99 +4357,13 @@ static void brightness_exit(void)
3276 } 4357 }
3277} 4358}
3278 4359
3279static int brightness_update_status(struct backlight_device *bd)
3280{
3281 /* it is the backlight class's job (caller) to handle
3282 * EINTR and other errors properly */
3283 return brightness_set(
3284 (bd->props.fb_blank == FB_BLANK_UNBLANK &&
3285 bd->props.power == FB_BLANK_UNBLANK) ?
3286 bd->props.brightness : 0);
3287}
3288
3289/*
3290 * ThinkPads can read brightness from two places: EC 0x31, or
3291 * CMOS NVRAM byte 0x5E, bits 0-3.
3292 */
3293static int brightness_get(struct backlight_device *bd)
3294{
3295 u8 lec = 0, lcmos = 0, level = 0;
3296
3297 if (brightness_mode & 1) {
3298 if (!acpi_ec_read(brightness_offset, &lec))
3299 return -EIO;
3300 lec &= (tp_features.bright_16levels)? 0x0f : 0x07;
3301 level = lec;
3302 };
3303 if (brightness_mode & 2) {
3304 lcmos = (nvram_read_byte(TP_NVRAM_ADDR_BRIGHTNESS)
3305 & TP_NVRAM_MASK_LEVEL_BRIGHTNESS)
3306 >> TP_NVRAM_POS_LEVEL_BRIGHTNESS;
3307 lcmos &= (tp_features.bright_16levels)? 0x0f : 0x07;
3308 level = lcmos;
3309 }
3310
3311 if (brightness_mode == 3 && lec != lcmos) {
3312 printk(IBM_ERR
3313 "CMOS NVRAM (%u) and EC (%u) do not agree "
3314 "on display brightness level\n",
3315 (unsigned int) lcmos,
3316 (unsigned int) lec);
3317 return -EIO;
3318 }
3319
3320 return level;
3321}
3322
3323/* May return EINTR which can always be mapped to ERESTARTSYS */
3324static int brightness_set(int value)
3325{
3326 int cmos_cmd, inc, i, res;
3327 int current_value;
3328
3329 if (value > ((tp_features.bright_16levels)? 15 : 7))
3330 return -EINVAL;
3331
3332 res = mutex_lock_interruptible(&brightness_mutex);
3333 if (res < 0)
3334 return res;
3335
3336 current_value = brightness_get(NULL);
3337 if (current_value < 0) {
3338 res = current_value;
3339 goto errout;
3340 }
3341
3342 cmos_cmd = value > current_value ?
3343 TP_CMOS_BRIGHTNESS_UP :
3344 TP_CMOS_BRIGHTNESS_DOWN;
3345 inc = (value > current_value)? 1 : -1;
3346
3347 res = 0;
3348 for (i = current_value; i != value; i += inc) {
3349 if ((brightness_mode & 2) &&
3350 issue_thinkpad_cmos_command(cmos_cmd)) {
3351 res = -EIO;
3352 goto errout;
3353 }
3354 if ((brightness_mode & 1) &&
3355 !acpi_ec_write(brightness_offset, i + inc)) {
3356 res = -EIO;
3357 goto errout;;
3358 }
3359 }
3360
3361errout:
3362 mutex_unlock(&brightness_mutex);
3363 return res;
3364}
3365
3366static int brightness_read(char *p) 4360static int brightness_read(char *p)
3367{ 4361{
3368 int len = 0; 4362 int len = 0;
3369 int level; 4363 int level;
3370 4364
3371 if ((level = brightness_get(NULL)) < 0) { 4365 level = brightness_get(NULL);
4366 if (level < 0) {
3372 len += sprintf(p + len, "level:\t\tunreadable\n"); 4367 len += sprintf(p + len, "level:\t\tunreadable\n");
3373 } else { 4368 } else {
3374 len += sprintf(p + len, "level:\t\t%d\n", level); 4369 len += sprintf(p + len, "level:\t\t%d\n", level);
@@ -3425,6 +4420,8 @@ static struct ibm_struct brightness_driver_data = {
3425 * Volume subdriver 4420 * Volume subdriver
3426 */ 4421 */
3427 4422
4423static int volume_offset = 0x30;
4424
3428static int volume_read(char *p) 4425static int volume_read(char *p)
3429{ 4426{
3430 int len = 0; 4427 int len = 0;
@@ -3474,8 +4471,11 @@ static int volume_write(char *buf)
3474 } else 4471 } else
3475 return -EINVAL; 4472 return -EINVAL;
3476 4473
3477 if (new_level != level) { /* mute doesn't change */ 4474 if (new_level != level) {
3478 cmos_cmd = new_level > level ? TP_CMOS_VOLUME_UP : TP_CMOS_VOLUME_DOWN; 4475 /* mute doesn't change */
4476
4477 cmos_cmd = (new_level > level) ?
4478 TP_CMOS_VOLUME_UP : TP_CMOS_VOLUME_DOWN;
3479 inc = new_level > level ? 1 : -1; 4479 inc = new_level > level ? 1 : -1;
3480 4480
3481 if (mute && (issue_thinkpad_cmos_command(cmos_cmd) || 4481 if (mute && (issue_thinkpad_cmos_command(cmos_cmd) ||
@@ -3487,14 +4487,18 @@ static int volume_write(char *buf)
3487 !acpi_ec_write(volume_offset, i + inc)) 4487 !acpi_ec_write(volume_offset, i + inc))
3488 return -EIO; 4488 return -EIO;
3489 4489
3490 if (mute && (issue_thinkpad_cmos_command(TP_CMOS_VOLUME_MUTE) || 4490 if (mute &&
3491 !acpi_ec_write(volume_offset, 4491 (issue_thinkpad_cmos_command(TP_CMOS_VOLUME_MUTE) ||
3492 new_level + mute))) 4492 !acpi_ec_write(volume_offset, new_level + mute))) {
3493 return -EIO; 4493 return -EIO;
4494 }
3494 } 4495 }
3495 4496
3496 if (new_mute != mute) { /* level doesn't change */ 4497 if (new_mute != mute) {
3497 cmos_cmd = new_mute ? TP_CMOS_VOLUME_MUTE : TP_CMOS_VOLUME_UP; 4498 /* level doesn't change */
4499
4500 cmos_cmd = (new_mute) ?
4501 TP_CMOS_VOLUME_MUTE : TP_CMOS_VOLUME_UP;
3498 4502
3499 if (issue_thinkpad_cmos_command(cmos_cmd) || 4503 if (issue_thinkpad_cmos_command(cmos_cmd) ||
3500 !acpi_ec_write(volume_offset, level + new_mute)) 4504 !acpi_ec_write(volume_offset, level + new_mute))
@@ -3616,26 +4620,377 @@ static struct ibm_struct volume_driver_data = {
3616 * but the ACPI tables just mention level 7. 4620 * but the ACPI tables just mention level 7.
3617 */ 4621 */
3618 4622
4623enum { /* Fan control constants */
4624 fan_status_offset = 0x2f, /* EC register 0x2f */
4625 fan_rpm_offset = 0x84, /* EC register 0x84: LSB, 0x85 MSB (RPM)
4626 * 0x84 must be read before 0x85 */
4627
4628 TP_EC_FAN_FULLSPEED = 0x40, /* EC fan mode: full speed */
4629 TP_EC_FAN_AUTO = 0x80, /* EC fan mode: auto fan control */
4630
4631 TPACPI_FAN_LAST_LEVEL = 0x100, /* Use cached last-seen fan level */
4632};
4633
4634enum fan_status_access_mode {
4635 TPACPI_FAN_NONE = 0, /* No fan status or control */
4636 TPACPI_FAN_RD_ACPI_GFAN, /* Use ACPI GFAN */
4637 TPACPI_FAN_RD_TPEC, /* Use ACPI EC regs 0x2f, 0x84-0x85 */
4638};
4639
4640enum fan_control_access_mode {
4641 TPACPI_FAN_WR_NONE = 0, /* No fan control */
4642 TPACPI_FAN_WR_ACPI_SFAN, /* Use ACPI SFAN */
4643 TPACPI_FAN_WR_TPEC, /* Use ACPI EC reg 0x2f */
4644 TPACPI_FAN_WR_ACPI_FANS, /* Use ACPI FANS and EC reg 0x2f */
4645};
4646
4647enum fan_control_commands {
4648 TPACPI_FAN_CMD_SPEED = 0x0001, /* speed command */
4649 TPACPI_FAN_CMD_LEVEL = 0x0002, /* level command */
4650 TPACPI_FAN_CMD_ENABLE = 0x0004, /* enable/disable cmd,
4651 * and also watchdog cmd */
4652};
4653
4654static int fan_control_allowed;
4655
3619static enum fan_status_access_mode fan_status_access_mode; 4656static enum fan_status_access_mode fan_status_access_mode;
3620static enum fan_control_access_mode fan_control_access_mode; 4657static enum fan_control_access_mode fan_control_access_mode;
3621static enum fan_control_commands fan_control_commands; 4658static enum fan_control_commands fan_control_commands;
3622 4659
3623static u8 fan_control_initial_status; 4660static u8 fan_control_initial_status;
3624static u8 fan_control_desired_level; 4661static u8 fan_control_desired_level;
4662static int fan_watchdog_maxinterval;
4663
4664static struct mutex fan_mutex;
3625 4665
3626static void fan_watchdog_fire(struct work_struct *ignored); 4666static void fan_watchdog_fire(struct work_struct *ignored);
3627static int fan_watchdog_maxinterval;
3628static DECLARE_DELAYED_WORK(fan_watchdog_task, fan_watchdog_fire); 4667static DECLARE_DELAYED_WORK(fan_watchdog_task, fan_watchdog_fire);
3629 4668
3630IBM_HANDLE(fans, ec, "FANS"); /* X31, X40, X41 */ 4669TPACPI_HANDLE(fans, ec, "FANS"); /* X31, X40, X41 */
3631IBM_HANDLE(gfan, ec, "GFAN", /* 570 */ 4670TPACPI_HANDLE(gfan, ec, "GFAN", /* 570 */
3632 "\\FSPD", /* 600e/x, 770e, 770x */ 4671 "\\FSPD", /* 600e/x, 770e, 770x */
3633 ); /* all others */ 4672 ); /* all others */
3634IBM_HANDLE(sfan, ec, "SFAN", /* 570 */ 4673TPACPI_HANDLE(sfan, ec, "SFAN", /* 570 */
3635 "JFNS", /* 770x-JL */ 4674 "JFNS", /* 770x-JL */
3636 ); /* all others */ 4675 ); /* all others */
3637 4676
3638/* 4677/*
4678 * Call with fan_mutex held
4679 */
4680static void fan_update_desired_level(u8 status)
4681{
4682 if ((status &
4683 (TP_EC_FAN_AUTO | TP_EC_FAN_FULLSPEED)) == 0) {
4684 if (status > 7)
4685 fan_control_desired_level = 7;
4686 else
4687 fan_control_desired_level = status;
4688 }
4689}
4690
4691static int fan_get_status(u8 *status)
4692{
4693 u8 s;
4694
4695 /* TODO:
4696 * Add TPACPI_FAN_RD_ACPI_FANS ? */
4697
4698 switch (fan_status_access_mode) {
4699 case TPACPI_FAN_RD_ACPI_GFAN:
4700 /* 570, 600e/x, 770e, 770x */
4701
4702 if (unlikely(!acpi_evalf(gfan_handle, &s, NULL, "d")))
4703 return -EIO;
4704
4705 if (likely(status))
4706 *status = s & 0x07;
4707
4708 break;
4709
4710 case TPACPI_FAN_RD_TPEC:
4711 /* all except 570, 600e/x, 770e, 770x */
4712 if (unlikely(!acpi_ec_read(fan_status_offset, &s)))
4713 return -EIO;
4714
4715 if (likely(status))
4716 *status = s;
4717
4718 break;
4719
4720 default:
4721 return -ENXIO;
4722 }
4723
4724 return 0;
4725}
4726
4727static int fan_get_status_safe(u8 *status)
4728{
4729 int rc;
4730 u8 s;
4731
4732 if (mutex_lock_interruptible(&fan_mutex))
4733 return -ERESTARTSYS;
4734 rc = fan_get_status(&s);
4735 if (!rc)
4736 fan_update_desired_level(s);
4737 mutex_unlock(&fan_mutex);
4738
4739 if (status)
4740 *status = s;
4741
4742 return rc;
4743}
4744
4745static int fan_get_speed(unsigned int *speed)
4746{
4747 u8 hi, lo;
4748
4749 switch (fan_status_access_mode) {
4750 case TPACPI_FAN_RD_TPEC:
4751 /* all except 570, 600e/x, 770e, 770x */
4752 if (unlikely(!acpi_ec_read(fan_rpm_offset, &lo) ||
4753 !acpi_ec_read(fan_rpm_offset + 1, &hi)))
4754 return -EIO;
4755
4756 if (likely(speed))
4757 *speed = (hi << 8) | lo;
4758
4759 break;
4760
4761 default:
4762 return -ENXIO;
4763 }
4764
4765 return 0;
4766}
4767
4768static int fan_set_level(int level)
4769{
4770 if (!fan_control_allowed)
4771 return -EPERM;
4772
4773 switch (fan_control_access_mode) {
4774 case TPACPI_FAN_WR_ACPI_SFAN:
4775 if (level >= 0 && level <= 7) {
4776 if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", level))
4777 return -EIO;
4778 } else
4779 return -EINVAL;
4780 break;
4781
4782 case TPACPI_FAN_WR_ACPI_FANS:
4783 case TPACPI_FAN_WR_TPEC:
4784 if ((level != TP_EC_FAN_AUTO) &&
4785 (level != TP_EC_FAN_FULLSPEED) &&
4786 ((level < 0) || (level > 7)))
4787 return -EINVAL;
4788
4789 /* safety net should the EC not support AUTO
4790 * or FULLSPEED mode bits and just ignore them */
4791 if (level & TP_EC_FAN_FULLSPEED)
4792 level |= 7; /* safety min speed 7 */
4793 else if (level & TP_EC_FAN_AUTO)
4794 level |= 4; /* safety min speed 4 */
4795
4796 if (!acpi_ec_write(fan_status_offset, level))
4797 return -EIO;
4798 else
4799 tp_features.fan_ctrl_status_undef = 0;
4800 break;
4801
4802 default:
4803 return -ENXIO;
4804 }
4805 return 0;
4806}
4807
4808static int fan_set_level_safe(int level)
4809{
4810 int rc;
4811
4812 if (!fan_control_allowed)
4813 return -EPERM;
4814
4815 if (mutex_lock_interruptible(&fan_mutex))
4816 return -ERESTARTSYS;
4817
4818 if (level == TPACPI_FAN_LAST_LEVEL)
4819 level = fan_control_desired_level;
4820
4821 rc = fan_set_level(level);
4822 if (!rc)
4823 fan_update_desired_level(level);
4824
4825 mutex_unlock(&fan_mutex);
4826 return rc;
4827}
4828
4829static int fan_set_enable(void)
4830{
4831 u8 s;
4832 int rc;
4833
4834 if (!fan_control_allowed)
4835 return -EPERM;
4836
4837 if (mutex_lock_interruptible(&fan_mutex))
4838 return -ERESTARTSYS;
4839
4840 switch (fan_control_access_mode) {
4841 case TPACPI_FAN_WR_ACPI_FANS:
4842 case TPACPI_FAN_WR_TPEC:
4843 rc = fan_get_status(&s);
4844 if (rc < 0)
4845 break;
4846
4847 /* Don't go out of emergency fan mode */
4848 if (s != 7) {
4849 s &= 0x07;
4850 s |= TP_EC_FAN_AUTO | 4; /* min fan speed 4 */
4851 }
4852
4853 if (!acpi_ec_write(fan_status_offset, s))
4854 rc = -EIO;
4855 else {
4856 tp_features.fan_ctrl_status_undef = 0;
4857 rc = 0;
4858 }
4859 break;
4860
4861 case TPACPI_FAN_WR_ACPI_SFAN:
4862 rc = fan_get_status(&s);
4863 if (rc < 0)
4864 break;
4865
4866 s &= 0x07;
4867
4868 /* Set fan to at least level 4 */
4869 s |= 4;
4870
4871 if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", s))
4872 rc = -EIO;
4873 else
4874 rc = 0;
4875 break;
4876
4877 default:
4878 rc = -ENXIO;
4879 }
4880
4881 mutex_unlock(&fan_mutex);
4882 return rc;
4883}
4884
4885static int fan_set_disable(void)
4886{
4887 int rc;
4888
4889 if (!fan_control_allowed)
4890 return -EPERM;
4891
4892 if (mutex_lock_interruptible(&fan_mutex))
4893 return -ERESTARTSYS;
4894
4895 rc = 0;
4896 switch (fan_control_access_mode) {
4897 case TPACPI_FAN_WR_ACPI_FANS:
4898 case TPACPI_FAN_WR_TPEC:
4899 if (!acpi_ec_write(fan_status_offset, 0x00))
4900 rc = -EIO;
4901 else {
4902 fan_control_desired_level = 0;
4903 tp_features.fan_ctrl_status_undef = 0;
4904 }
4905 break;
4906
4907 case TPACPI_FAN_WR_ACPI_SFAN:
4908 if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", 0x00))
4909 rc = -EIO;
4910 else
4911 fan_control_desired_level = 0;
4912 break;
4913
4914 default:
4915 rc = -ENXIO;
4916 }
4917
4918
4919 mutex_unlock(&fan_mutex);
4920 return rc;
4921}
4922
4923static int fan_set_speed(int speed)
4924{
4925 int rc;
4926
4927 if (!fan_control_allowed)
4928 return -EPERM;
4929
4930 if (mutex_lock_interruptible(&fan_mutex))
4931 return -ERESTARTSYS;
4932
4933 rc = 0;
4934 switch (fan_control_access_mode) {
4935 case TPACPI_FAN_WR_ACPI_FANS:
4936 if (speed >= 0 && speed <= 65535) {
4937 if (!acpi_evalf(fans_handle, NULL, NULL, "vddd",
4938 speed, speed, speed))
4939 rc = -EIO;
4940 } else
4941 rc = -EINVAL;
4942 break;
4943
4944 default:
4945 rc = -ENXIO;
4946 }
4947
4948 mutex_unlock(&fan_mutex);
4949 return rc;
4950}
4951
4952static void fan_watchdog_reset(void)
4953{
4954 static int fan_watchdog_active;
4955
4956 if (fan_control_access_mode == TPACPI_FAN_WR_NONE)
4957 return;
4958
4959 if (fan_watchdog_active)
4960 cancel_delayed_work(&fan_watchdog_task);
4961
4962 if (fan_watchdog_maxinterval > 0 &&
4963 tpacpi_lifecycle != TPACPI_LIFE_EXITING) {
4964 fan_watchdog_active = 1;
4965 if (!schedule_delayed_work(&fan_watchdog_task,
4966 msecs_to_jiffies(fan_watchdog_maxinterval
4967 * 1000))) {
4968 printk(TPACPI_ERR
4969 "failed to schedule the fan watchdog, "
4970 "watchdog will not trigger\n");
4971 }
4972 } else
4973 fan_watchdog_active = 0;
4974}
4975
4976static void fan_watchdog_fire(struct work_struct *ignored)
4977{
4978 int rc;
4979
4980 if (tpacpi_lifecycle != TPACPI_LIFE_RUNNING)
4981 return;
4982
4983 printk(TPACPI_NOTICE "fan watchdog: enabling fan\n");
4984 rc = fan_set_enable();
4985 if (rc < 0) {
4986 printk(TPACPI_ERR "fan watchdog: error %d while enabling fan, "
4987 "will try again later...\n", -rc);
4988 /* reschedule for later */
4989 fan_watchdog_reset();
4990 }
4991}
4992
4993/*
3639 * SYSFS fan layout: hwmon compatible (device) 4994 * SYSFS fan layout: hwmon compatible (device)
3640 * 4995 *
3641 * pwm*_enable: 4996 * pwm*_enable:
@@ -3868,9 +5223,9 @@ static int __init fan_init(struct ibm_init_struct *iibm)
3868 tp_features.fan_ctrl_status_undef = 0; 5223 tp_features.fan_ctrl_status_undef = 0;
3869 fan_control_desired_level = 7; 5224 fan_control_desired_level = 7;
3870 5225
3871 IBM_ACPIHANDLE_INIT(fans); 5226 TPACPI_ACPIHANDLE_INIT(fans);
3872 IBM_ACPIHANDLE_INIT(gfan); 5227 TPACPI_ACPIHANDLE_INIT(gfan);
3873 IBM_ACPIHANDLE_INIT(sfan); 5228 TPACPI_ACPIHANDLE_INIT(sfan);
3874 5229
3875 if (gfan_handle) { 5230 if (gfan_handle) {
3876 /* 570, 600e/x, 770e, 770x */ 5231 /* 570, 600e/x, 770e, 770x */
@@ -3896,16 +5251,16 @@ static int __init fan_init(struct ibm_init_struct *iibm)
3896 case 0x3837: /* TP-78 */ 5251 case 0x3837: /* TP-78 */
3897 case 0x3637: /* TP-76 */ 5252 case 0x3637: /* TP-76 */
3898 case 0x3037: /* TP-70 */ 5253 case 0x3037: /* TP-70 */
3899 printk(IBM_NOTICE 5254 printk(TPACPI_NOTICE
3900 "fan_init: initial fan status is " 5255 "fan_init: initial fan status "
3901 "unknown, assuming it is in auto " 5256 "is unknown, assuming it is "
3902 "mode\n"); 5257 "in auto mode\n");
3903 tp_features.fan_ctrl_status_undef = 1; 5258 tp_features.fan_ctrl_status_undef = 1;
3904 ;; 5259 ;;
3905 } 5260 }
3906 } 5261 }
3907 } else { 5262 } else {
3908 printk(IBM_ERR 5263 printk(TPACPI_ERR
3909 "ThinkPad ACPI EC access misbehaving, " 5264 "ThinkPad ACPI EC access misbehaving, "
3910 "fan status and control unavailable\n"); 5265 "fan status and control unavailable\n");
3911 return 1; 5266 return 1;
@@ -3970,333 +5325,20 @@ static int __init fan_init(struct ibm_init_struct *iibm)
3970 return 1; 5325 return 1;
3971} 5326}
3972 5327
3973/*
3974 * Call with fan_mutex held
3975 */
3976static void fan_update_desired_level(u8 status)
3977{
3978 if ((status &
3979 (TP_EC_FAN_AUTO | TP_EC_FAN_FULLSPEED)) == 0) {
3980 if (status > 7)
3981 fan_control_desired_level = 7;
3982 else
3983 fan_control_desired_level = status;
3984 }
3985}
3986
3987static int fan_get_status(u8 *status)
3988{
3989 u8 s;
3990
3991 /* TODO:
3992 * Add TPACPI_FAN_RD_ACPI_FANS ? */
3993
3994 switch (fan_status_access_mode) {
3995 case TPACPI_FAN_RD_ACPI_GFAN:
3996 /* 570, 600e/x, 770e, 770x */
3997
3998 if (unlikely(!acpi_evalf(gfan_handle, &s, NULL, "d")))
3999 return -EIO;
4000
4001 if (likely(status))
4002 *status = s & 0x07;
4003
4004 break;
4005
4006 case TPACPI_FAN_RD_TPEC:
4007 /* all except 570, 600e/x, 770e, 770x */
4008 if (unlikely(!acpi_ec_read(fan_status_offset, &s)))
4009 return -EIO;
4010
4011 if (likely(status))
4012 *status = s;
4013
4014 break;
4015
4016 default:
4017 return -ENXIO;
4018 }
4019
4020 return 0;
4021}
4022
4023static int fan_get_status_safe(u8 *status)
4024{
4025 int rc;
4026 u8 s;
4027
4028 if (mutex_lock_interruptible(&fan_mutex))
4029 return -ERESTARTSYS;
4030 rc = fan_get_status(&s);
4031 if (!rc)
4032 fan_update_desired_level(s);
4033 mutex_unlock(&fan_mutex);
4034
4035 if (status)
4036 *status = s;
4037
4038 return rc;
4039}
4040
4041static void fan_exit(void) 5328static void fan_exit(void)
4042{ 5329{
4043 vdbg_printk(TPACPI_DBG_EXIT, "cancelling any pending fan watchdog tasks\n"); 5330 vdbg_printk(TPACPI_DBG_EXIT,
5331 "cancelling any pending fan watchdog tasks\n");
4044 5332
4045 /* FIXME: can we really do this unconditionally? */ 5333 /* FIXME: can we really do this unconditionally? */
4046 sysfs_remove_group(&tpacpi_sensors_pdev->dev.kobj, &fan_attr_group); 5334 sysfs_remove_group(&tpacpi_sensors_pdev->dev.kobj, &fan_attr_group);
4047 driver_remove_file(&tpacpi_hwmon_pdriver.driver, &driver_attr_fan_watchdog); 5335 driver_remove_file(&tpacpi_hwmon_pdriver.driver,
5336 &driver_attr_fan_watchdog);
4048 5337
4049 cancel_delayed_work(&fan_watchdog_task); 5338 cancel_delayed_work(&fan_watchdog_task);
4050 flush_scheduled_work(); 5339 flush_scheduled_work();
4051} 5340}
4052 5341
4053static int fan_get_speed(unsigned int *speed)
4054{
4055 u8 hi, lo;
4056
4057 switch (fan_status_access_mode) {
4058 case TPACPI_FAN_RD_TPEC:
4059 /* all except 570, 600e/x, 770e, 770x */
4060 if (unlikely(!acpi_ec_read(fan_rpm_offset, &lo) ||
4061 !acpi_ec_read(fan_rpm_offset + 1, &hi)))
4062 return -EIO;
4063
4064 if (likely(speed))
4065 *speed = (hi << 8) | lo;
4066
4067 break;
4068
4069 default:
4070 return -ENXIO;
4071 }
4072
4073 return 0;
4074}
4075
4076static void fan_watchdog_fire(struct work_struct *ignored)
4077{
4078 int rc;
4079
4080 if (tpacpi_lifecycle != TPACPI_LIFE_RUNNING)
4081 return;
4082
4083 printk(IBM_NOTICE "fan watchdog: enabling fan\n");
4084 rc = fan_set_enable();
4085 if (rc < 0) {
4086 printk(IBM_ERR "fan watchdog: error %d while enabling fan, "
4087 "will try again later...\n", -rc);
4088 /* reschedule for later */
4089 fan_watchdog_reset();
4090 }
4091}
4092
4093static void fan_watchdog_reset(void)
4094{
4095 static int fan_watchdog_active;
4096
4097 if (fan_control_access_mode == TPACPI_FAN_WR_NONE)
4098 return;
4099
4100 if (fan_watchdog_active)
4101 cancel_delayed_work(&fan_watchdog_task);
4102
4103 if (fan_watchdog_maxinterval > 0 &&
4104 tpacpi_lifecycle != TPACPI_LIFE_EXITING) {
4105 fan_watchdog_active = 1;
4106 if (!schedule_delayed_work(&fan_watchdog_task,
4107 msecs_to_jiffies(fan_watchdog_maxinterval
4108 * 1000))) {
4109 printk(IBM_ERR "failed to schedule the fan watchdog, "
4110 "watchdog will not trigger\n");
4111 }
4112 } else
4113 fan_watchdog_active = 0;
4114}
4115
4116static int fan_set_level(int level)
4117{
4118 if (!fan_control_allowed)
4119 return -EPERM;
4120
4121 switch (fan_control_access_mode) {
4122 case TPACPI_FAN_WR_ACPI_SFAN:
4123 if (level >= 0 && level <= 7) {
4124 if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", level))
4125 return -EIO;
4126 } else
4127 return -EINVAL;
4128 break;
4129
4130 case TPACPI_FAN_WR_ACPI_FANS:
4131 case TPACPI_FAN_WR_TPEC:
4132 if ((level != TP_EC_FAN_AUTO) &&
4133 (level != TP_EC_FAN_FULLSPEED) &&
4134 ((level < 0) || (level > 7)))
4135 return -EINVAL;
4136
4137 /* safety net should the EC not support AUTO
4138 * or FULLSPEED mode bits and just ignore them */
4139 if (level & TP_EC_FAN_FULLSPEED)
4140 level |= 7; /* safety min speed 7 */
4141 else if (level & TP_EC_FAN_FULLSPEED)
4142 level |= 4; /* safety min speed 4 */
4143
4144 if (!acpi_ec_write(fan_status_offset, level))
4145 return -EIO;
4146 else
4147 tp_features.fan_ctrl_status_undef = 0;
4148 break;
4149
4150 default:
4151 return -ENXIO;
4152 }
4153 return 0;
4154}
4155
4156static int fan_set_level_safe(int level)
4157{
4158 int rc;
4159
4160 if (!fan_control_allowed)
4161 return -EPERM;
4162
4163 if (mutex_lock_interruptible(&fan_mutex))
4164 return -ERESTARTSYS;
4165
4166 if (level == TPACPI_FAN_LAST_LEVEL)
4167 level = fan_control_desired_level;
4168
4169 rc = fan_set_level(level);
4170 if (!rc)
4171 fan_update_desired_level(level);
4172
4173 mutex_unlock(&fan_mutex);
4174 return rc;
4175}
4176
4177static int fan_set_enable(void)
4178{
4179 u8 s;
4180 int rc;
4181
4182 if (!fan_control_allowed)
4183 return -EPERM;
4184
4185 if (mutex_lock_interruptible(&fan_mutex))
4186 return -ERESTARTSYS;
4187
4188 switch (fan_control_access_mode) {
4189 case TPACPI_FAN_WR_ACPI_FANS:
4190 case TPACPI_FAN_WR_TPEC:
4191 rc = fan_get_status(&s);
4192 if (rc < 0)
4193 break;
4194
4195 /* Don't go out of emergency fan mode */
4196 if (s != 7) {
4197 s &= 0x07;
4198 s |= TP_EC_FAN_AUTO | 4; /* min fan speed 4 */
4199 }
4200
4201 if (!acpi_ec_write(fan_status_offset, s))
4202 rc = -EIO;
4203 else {
4204 tp_features.fan_ctrl_status_undef = 0;
4205 rc = 0;
4206 }
4207 break;
4208
4209 case TPACPI_FAN_WR_ACPI_SFAN:
4210 rc = fan_get_status(&s);
4211 if (rc < 0)
4212 break;
4213
4214 s &= 0x07;
4215
4216 /* Set fan to at least level 4 */
4217 s |= 4;
4218
4219 if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", s))
4220 rc= -EIO;
4221 else
4222 rc = 0;
4223 break;
4224
4225 default:
4226 rc = -ENXIO;
4227 }
4228
4229 mutex_unlock(&fan_mutex);
4230 return rc;
4231}
4232
4233static int fan_set_disable(void)
4234{
4235 int rc;
4236
4237 if (!fan_control_allowed)
4238 return -EPERM;
4239
4240 if (mutex_lock_interruptible(&fan_mutex))
4241 return -ERESTARTSYS;
4242
4243 rc = 0;
4244 switch (fan_control_access_mode) {
4245 case TPACPI_FAN_WR_ACPI_FANS:
4246 case TPACPI_FAN_WR_TPEC:
4247 if (!acpi_ec_write(fan_status_offset, 0x00))
4248 rc = -EIO;
4249 else {
4250 fan_control_desired_level = 0;
4251 tp_features.fan_ctrl_status_undef = 0;
4252 }
4253 break;
4254
4255 case TPACPI_FAN_WR_ACPI_SFAN:
4256 if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", 0x00))
4257 rc = -EIO;
4258 else
4259 fan_control_desired_level = 0;
4260 break;
4261
4262 default:
4263 rc = -ENXIO;
4264 }
4265
4266
4267 mutex_unlock(&fan_mutex);
4268 return rc;
4269}
4270
4271static int fan_set_speed(int speed)
4272{
4273 int rc;
4274
4275 if (!fan_control_allowed)
4276 return -EPERM;
4277
4278 if (mutex_lock_interruptible(&fan_mutex))
4279 return -ERESTARTSYS;
4280
4281 rc = 0;
4282 switch (fan_control_access_mode) {
4283 case TPACPI_FAN_WR_ACPI_FANS:
4284 if (speed >= 0 && speed <= 65535) {
4285 if (!acpi_evalf(fans_handle, NULL, NULL, "vddd",
4286 speed, speed, speed))
4287 rc = -EIO;
4288 } else
4289 rc = -EINVAL;
4290 break;
4291
4292 default:
4293 rc = -ENXIO;
4294 }
4295
4296 mutex_unlock(&fan_mutex);
4297 return rc;
4298}
4299
4300static int fan_read(char *p) 5342static int fan_read(char *p)
4301{ 5343{
4302 int len = 0; 5344 int len = 0;
@@ -4307,7 +5349,8 @@ static int fan_read(char *p)
4307 switch (fan_status_access_mode) { 5349 switch (fan_status_access_mode) {
4308 case TPACPI_FAN_RD_ACPI_GFAN: 5350 case TPACPI_FAN_RD_ACPI_GFAN:
4309 /* 570, 600e/x, 770e, 770x */ 5351 /* 570, 600e/x, 770e, 770x */
4310 if ((rc = fan_get_status_safe(&status)) < 0) 5352 rc = fan_get_status_safe(&status);
5353 if (rc < 0)
4311 return rc; 5354 return rc;
4312 5355
4313 len += sprintf(p + len, "status:\t\t%s\n" 5356 len += sprintf(p + len, "status:\t\t%s\n"
@@ -4317,7 +5360,8 @@ static int fan_read(char *p)
4317 5360
4318 case TPACPI_FAN_RD_TPEC: 5361 case TPACPI_FAN_RD_TPEC:
4319 /* all except 570, 600e/x, 770e, 770x */ 5362 /* all except 570, 600e/x, 770e, 770x */
4320 if ((rc = fan_get_status_safe(&status)) < 0) 5363 rc = fan_get_status_safe(&status);
5364 if (rc < 0)
4321 return rc; 5365 return rc;
4322 5366
4323 if (unlikely(tp_features.fan_ctrl_status_undef)) { 5367 if (unlikely(tp_features.fan_ctrl_status_undef)) {
@@ -4332,7 +5376,8 @@ static int fan_read(char *p)
4332 len += sprintf(p + len, "status:\t\t%s\n", 5376 len += sprintf(p + len, "status:\t\t%s\n",
4333 (status != 0) ? "enabled" : "disabled"); 5377 (status != 0) ? "enabled" : "disabled");
4334 5378
4335 if ((rc = fan_get_speed(&speed)) < 0) 5379 rc = fan_get_speed(&speed);
5380 if (rc < 0)
4336 return rc; 5381 return rc;
4337 5382
4338 len += sprintf(p + len, "speed:\t\t%d\n", speed); 5383 len += sprintf(p + len, "speed:\t\t%d\n", speed);
@@ -4368,8 +5413,8 @@ static int fan_read(char *p)
4368 5413
4369 if (fan_control_commands & TPACPI_FAN_CMD_ENABLE) 5414 if (fan_control_commands & TPACPI_FAN_CMD_ENABLE)
4370 len += sprintf(p + len, "commands:\tenable, disable\n" 5415 len += sprintf(p + len, "commands:\tenable, disable\n"
4371 "commands:\twatchdog <timeout> (<timeout> is 0 (off), " 5416 "commands:\twatchdog <timeout> (<timeout> "
4372 "1-120 (seconds))\n"); 5417 "is 0 (off), 1-120 (seconds))\n");
4373 5418
4374 if (fan_control_commands & TPACPI_FAN_CMD_SPEED) 5419 if (fan_control_commands & TPACPI_FAN_CMD_SPEED)
4375 len += sprintf(p + len, "commands:\tspeed <speed>" 5420 len += sprintf(p + len, "commands:\tspeed <speed>"
@@ -4385,13 +5430,14 @@ static int fan_write_cmd_level(const char *cmd, int *rc)
4385 if (strlencmp(cmd, "level auto") == 0) 5430 if (strlencmp(cmd, "level auto") == 0)
4386 level = TP_EC_FAN_AUTO; 5431 level = TP_EC_FAN_AUTO;
4387 else if ((strlencmp(cmd, "level disengaged") == 0) | 5432 else if ((strlencmp(cmd, "level disengaged") == 0) |
4388 (strlencmp(cmd, "level full-speed") == 0)) 5433 (strlencmp(cmd, "level full-speed") == 0))
4389 level = TP_EC_FAN_FULLSPEED; 5434 level = TP_EC_FAN_FULLSPEED;
4390 else if (sscanf(cmd, "level %d", &level) != 1) 5435 else if (sscanf(cmd, "level %d", &level) != 1)
4391 return 0; 5436 return 0;
4392 5437
4393 if ((*rc = fan_set_level_safe(level)) == -ENXIO) 5438 *rc = fan_set_level_safe(level);
4394 printk(IBM_ERR "level command accepted for unsupported " 5439 if (*rc == -ENXIO)
5440 printk(TPACPI_ERR "level command accepted for unsupported "
4395 "access mode %d", fan_control_access_mode); 5441 "access mode %d", fan_control_access_mode);
4396 5442
4397 return 1; 5443 return 1;
@@ -4402,8 +5448,9 @@ static int fan_write_cmd_enable(const char *cmd, int *rc)
4402 if (strlencmp(cmd, "enable") != 0) 5448 if (strlencmp(cmd, "enable") != 0)
4403 return 0; 5449 return 0;
4404 5450
4405 if ((*rc = fan_set_enable()) == -ENXIO) 5451 *rc = fan_set_enable();
4406 printk(IBM_ERR "enable command accepted for unsupported " 5452 if (*rc == -ENXIO)
5453 printk(TPACPI_ERR "enable command accepted for unsupported "
4407 "access mode %d", fan_control_access_mode); 5454 "access mode %d", fan_control_access_mode);
4408 5455
4409 return 1; 5456 return 1;
@@ -4414,8 +5461,9 @@ static int fan_write_cmd_disable(const char *cmd, int *rc)
4414 if (strlencmp(cmd, "disable") != 0) 5461 if (strlencmp(cmd, "disable") != 0)
4415 return 0; 5462 return 0;
4416 5463
4417 if ((*rc = fan_set_disable()) == -ENXIO) 5464 *rc = fan_set_disable();
4418 printk(IBM_ERR "disable command accepted for unsupported " 5465 if (*rc == -ENXIO)
5466 printk(TPACPI_ERR "disable command accepted for unsupported "
4419 "access mode %d", fan_control_access_mode); 5467 "access mode %d", fan_control_access_mode);
4420 5468
4421 return 1; 5469 return 1;
@@ -4431,8 +5479,9 @@ static int fan_write_cmd_speed(const char *cmd, int *rc)
4431 if (sscanf(cmd, "speed %d", &speed) != 1) 5479 if (sscanf(cmd, "speed %d", &speed) != 1)
4432 return 0; 5480 return 0;
4433 5481
4434 if ((*rc = fan_set_speed(speed)) == -ENXIO) 5482 *rc = fan_set_speed(speed);
4435 printk(IBM_ERR "speed command accepted for unsupported " 5483 if (*rc == -ENXIO)
5484 printk(TPACPI_ERR "speed command accepted for unsupported "
4436 "access mode %d", fan_control_access_mode); 5485 "access mode %d", fan_control_access_mode);
4437 5486
4438 return 1; 5487 return 1;
@@ -4496,7 +5545,7 @@ static ssize_t thinkpad_acpi_pdev_name_show(struct device *dev,
4496 struct device_attribute *attr, 5545 struct device_attribute *attr,
4497 char *buf) 5546 char *buf)
4498{ 5547{
4499 return snprintf(buf, PAGE_SIZE, "%s\n", IBM_NAME); 5548 return snprintf(buf, PAGE_SIZE, "%s\n", TPACPI_NAME);
4500} 5549}
4501 5550
4502static struct device_attribute dev_attr_thinkpad_acpi_pdev_name = 5551static struct device_attribute dev_attr_thinkpad_acpi_pdev_name =
@@ -4507,14 +5556,12 @@ static struct device_attribute dev_attr_thinkpad_acpi_pdev_name =
4507/* /proc support */ 5556/* /proc support */
4508static struct proc_dir_entry *proc_dir; 5557static struct proc_dir_entry *proc_dir;
4509 5558
4510/* Subdriver registry */
4511static LIST_HEAD(tpacpi_all_drivers);
4512
4513
4514/* 5559/*
4515 * Module and infrastructure proble, init and exit handling 5560 * Module and infrastructure proble, init and exit handling
4516 */ 5561 */
4517 5562
5563static int force_load;
5564
4518#ifdef CONFIG_THINKPAD_ACPI_DEBUG 5565#ifdef CONFIG_THINKPAD_ACPI_DEBUG
4519static const char * __init str_supported(int is_supported) 5566static const char * __init str_supported(int is_supported)
4520{ 5567{
@@ -4524,6 +5571,48 @@ static const char * __init str_supported(int is_supported)
4524} 5571}
4525#endif /* CONFIG_THINKPAD_ACPI_DEBUG */ 5572#endif /* CONFIG_THINKPAD_ACPI_DEBUG */
4526 5573
5574static void ibm_exit(struct ibm_struct *ibm)
5575{
5576 dbg_printk(TPACPI_DBG_EXIT, "removing %s\n", ibm->name);
5577
5578 list_del_init(&ibm->all_drivers);
5579
5580 if (ibm->flags.acpi_notify_installed) {
5581 dbg_printk(TPACPI_DBG_EXIT,
5582 "%s: acpi_remove_notify_handler\n", ibm->name);
5583 BUG_ON(!ibm->acpi);
5584 acpi_remove_notify_handler(*ibm->acpi->handle,
5585 ibm->acpi->type,
5586 dispatch_acpi_notify);
5587 ibm->flags.acpi_notify_installed = 0;
5588 ibm->flags.acpi_notify_installed = 0;
5589 }
5590
5591 if (ibm->flags.proc_created) {
5592 dbg_printk(TPACPI_DBG_EXIT,
5593 "%s: remove_proc_entry\n", ibm->name);
5594 remove_proc_entry(ibm->name, proc_dir);
5595 ibm->flags.proc_created = 0;
5596 }
5597
5598 if (ibm->flags.acpi_driver_registered) {
5599 dbg_printk(TPACPI_DBG_EXIT,
5600 "%s: acpi_bus_unregister_driver\n", ibm->name);
5601 BUG_ON(!ibm->acpi);
5602 acpi_bus_unregister_driver(ibm->acpi->driver);
5603 kfree(ibm->acpi->driver);
5604 ibm->acpi->driver = NULL;
5605 ibm->flags.acpi_driver_registered = 0;
5606 }
5607
5608 if (ibm->flags.init_called && ibm->exit) {
5609 ibm->exit();
5610 ibm->flags.init_called = 0;
5611 }
5612
5613 dbg_printk(TPACPI_DBG_INIT, "finished removing %s\n", ibm->name);
5614}
5615
4527static int __init ibm_init(struct ibm_init_struct *iibm) 5616static int __init ibm_init(struct ibm_init_struct *iibm)
4528{ 5617{
4529 int ret; 5618 int ret;
@@ -4560,7 +5649,7 @@ static int __init ibm_init(struct ibm_init_struct *iibm)
4560 if (ibm->acpi->notify) { 5649 if (ibm->acpi->notify) {
4561 ret = setup_acpi_notify(ibm); 5650 ret = setup_acpi_notify(ibm);
4562 if (ret == -ENODEV) { 5651 if (ret == -ENODEV) {
4563 printk(IBM_NOTICE "disabling subdriver %s\n", 5652 printk(TPACPI_NOTICE "disabling subdriver %s\n",
4564 ibm->name); 5653 ibm->name);
4565 ret = 0; 5654 ret = 0;
4566 goto err_out; 5655 goto err_out;
@@ -4578,7 +5667,7 @@ static int __init ibm_init(struct ibm_init_struct *iibm)
4578 S_IFREG | S_IRUGO | S_IWUSR, 5667 S_IFREG | S_IRUGO | S_IWUSR,
4579 proc_dir); 5668 proc_dir);
4580 if (!entry) { 5669 if (!entry) {
4581 printk(IBM_ERR "unable to create proc entry %s\n", 5670 printk(TPACPI_ERR "unable to create proc entry %s\n",
4582 ibm->name); 5671 ibm->name);
4583 ret = -ENODEV; 5672 ret = -ENODEV;
4584 goto err_out; 5673 goto err_out;
@@ -4604,48 +5693,6 @@ err_out:
4604 return (ret < 0)? ret : 0; 5693 return (ret < 0)? ret : 0;
4605} 5694}
4606 5695
4607static void ibm_exit(struct ibm_struct *ibm)
4608{
4609 dbg_printk(TPACPI_DBG_EXIT, "removing %s\n", ibm->name);
4610
4611 list_del_init(&ibm->all_drivers);
4612
4613 if (ibm->flags.acpi_notify_installed) {
4614 dbg_printk(TPACPI_DBG_EXIT,
4615 "%s: acpi_remove_notify_handler\n", ibm->name);
4616 BUG_ON(!ibm->acpi);
4617 acpi_remove_notify_handler(*ibm->acpi->handle,
4618 ibm->acpi->type,
4619 dispatch_acpi_notify);
4620 ibm->flags.acpi_notify_installed = 0;
4621 ibm->flags.acpi_notify_installed = 0;
4622 }
4623
4624 if (ibm->flags.proc_created) {
4625 dbg_printk(TPACPI_DBG_EXIT,
4626 "%s: remove_proc_entry\n", ibm->name);
4627 remove_proc_entry(ibm->name, proc_dir);
4628 ibm->flags.proc_created = 0;
4629 }
4630
4631 if (ibm->flags.acpi_driver_registered) {
4632 dbg_printk(TPACPI_DBG_EXIT,
4633 "%s: acpi_bus_unregister_driver\n", ibm->name);
4634 BUG_ON(!ibm->acpi);
4635 acpi_bus_unregister_driver(ibm->acpi->driver);
4636 kfree(ibm->acpi->driver);
4637 ibm->acpi->driver = NULL;
4638 ibm->flags.acpi_driver_registered = 0;
4639 }
4640
4641 if (ibm->flags.init_called && ibm->exit) {
4642 ibm->exit();
4643 ibm->flags.init_called = 0;
4644 }
4645
4646 dbg_printk(TPACPI_DBG_INIT, "finished removing %s\n", ibm->name);
4647}
4648
4649/* Probing */ 5696/* Probing */
4650 5697
4651static void __init get_thinkpad_model_data(struct thinkpad_id_data *tp) 5698static void __init get_thinkpad_model_data(struct thinkpad_id_data *tp)
@@ -4715,10 +5762,10 @@ static int __init probe_for_thinkpad(void)
4715 is_thinkpad = (thinkpad_id.model_str != NULL); 5762 is_thinkpad = (thinkpad_id.model_str != NULL);
4716 5763
4717 /* ec is required because many other handles are relative to it */ 5764 /* ec is required because many other handles are relative to it */
4718 IBM_ACPIHANDLE_INIT(ec); 5765 TPACPI_ACPIHANDLE_INIT(ec);
4719 if (!ec_handle) { 5766 if (!ec_handle) {
4720 if (is_thinkpad) 5767 if (is_thinkpad)
4721 printk(IBM_ERR 5768 printk(TPACPI_ERR
4722 "Not yet supported ThinkPad detected!\n"); 5769 "Not yet supported ThinkPad detected!\n");
4723 return -ENODEV; 5770 return -ENODEV;
4724 } 5771 }
@@ -4839,47 +5886,110 @@ static int __init set_ibm_param(const char *val, struct kernel_param *kp)
4839 return -EINVAL; 5886 return -EINVAL;
4840} 5887}
4841 5888
4842static int experimental;
4843module_param(experimental, int, 0); 5889module_param(experimental, int, 0);
5890MODULE_PARM_DESC(experimental,
5891 "Enables experimental features when non-zero");
4844 5892
4845static u32 dbg_level;
4846module_param_named(debug, dbg_level, uint, 0); 5893module_param_named(debug, dbg_level, uint, 0);
5894MODULE_PARM_DESC(debug, "Sets debug level bit-mask");
4847 5895
4848static int force_load;
4849module_param(force_load, bool, 0); 5896module_param(force_load, bool, 0);
5897MODULE_PARM_DESC(force_load,
5898 "Attempts to load the driver even on a "
5899 "mis-identified ThinkPad when true");
4850 5900
4851static int fan_control_allowed;
4852module_param_named(fan_control, fan_control_allowed, bool, 0); 5901module_param_named(fan_control, fan_control_allowed, bool, 0);
5902MODULE_PARM_DESC(fan_control,
5903 "Enables setting fan parameters features when true");
4853 5904
4854static int brightness_mode;
4855module_param_named(brightness_mode, brightness_mode, int, 0); 5905module_param_named(brightness_mode, brightness_mode, int, 0);
5906MODULE_PARM_DESC(brightness_mode,
5907 "Selects brightness control strategy: "
5908 "0=auto, 1=EC, 2=CMOS, 3=both");
4856 5909
4857static unsigned int brightness_enable = 2; /* 2 = auto, 0 = no, 1 = yes */
4858module_param(brightness_enable, uint, 0); 5910module_param(brightness_enable, uint, 0);
5911MODULE_PARM_DESC(brightness_enable,
5912 "Enables backlight control when 1, disables when 0");
4859 5913
4860static unsigned int hotkey_report_mode;
4861module_param(hotkey_report_mode, uint, 0); 5914module_param(hotkey_report_mode, uint, 0);
4862 5915MODULE_PARM_DESC(hotkey_report_mode,
4863#define IBM_PARAM(feature) \ 5916 "used for backwards compatibility with userspace, "
4864 module_param_call(feature, set_ibm_param, NULL, NULL, 0) 5917 "see documentation");
4865 5918
4866IBM_PARAM(hotkey); 5919#define TPACPI_PARAM(feature) \
4867IBM_PARAM(bluetooth); 5920 module_param_call(feature, set_ibm_param, NULL, NULL, 0); \
4868IBM_PARAM(video); 5921 MODULE_PARM_DESC(feature, "Simulates thinkpad-aci procfs command " \
4869IBM_PARAM(light); 5922 "at module load, see documentation")
5923
5924TPACPI_PARAM(hotkey);
5925TPACPI_PARAM(bluetooth);
5926TPACPI_PARAM(video);
5927TPACPI_PARAM(light);
4870#ifdef CONFIG_THINKPAD_ACPI_DOCK 5928#ifdef CONFIG_THINKPAD_ACPI_DOCK
4871IBM_PARAM(dock); 5929TPACPI_PARAM(dock);
4872#endif 5930#endif
4873#ifdef CONFIG_THINKPAD_ACPI_BAY 5931#ifdef CONFIG_THINKPAD_ACPI_BAY
4874IBM_PARAM(bay); 5932TPACPI_PARAM(bay);
4875#endif /* CONFIG_THINKPAD_ACPI_BAY */ 5933#endif /* CONFIG_THINKPAD_ACPI_BAY */
4876IBM_PARAM(cmos); 5934TPACPI_PARAM(cmos);
4877IBM_PARAM(led); 5935TPACPI_PARAM(led);
4878IBM_PARAM(beep); 5936TPACPI_PARAM(beep);
4879IBM_PARAM(ecdump); 5937TPACPI_PARAM(ecdump);
4880IBM_PARAM(brightness); 5938TPACPI_PARAM(brightness);
4881IBM_PARAM(volume); 5939TPACPI_PARAM(volume);
4882IBM_PARAM(fan); 5940TPACPI_PARAM(fan);
5941
5942static void thinkpad_acpi_module_exit(void)
5943{
5944 struct ibm_struct *ibm, *itmp;
5945
5946 tpacpi_lifecycle = TPACPI_LIFE_EXITING;
5947
5948 list_for_each_entry_safe_reverse(ibm, itmp,
5949 &tpacpi_all_drivers,
5950 all_drivers) {
5951 ibm_exit(ibm);
5952 }
5953
5954 dbg_printk(TPACPI_DBG_INIT, "finished subdriver exit path...\n");
5955
5956 if (tpacpi_inputdev) {
5957 if (tp_features.input_device_registered)
5958 input_unregister_device(tpacpi_inputdev);
5959 else
5960 input_free_device(tpacpi_inputdev);
5961 }
5962
5963 if (tpacpi_hwmon)
5964 hwmon_device_unregister(tpacpi_hwmon);
5965
5966 if (tp_features.sensors_pdev_attrs_registered)
5967 device_remove_file(&tpacpi_sensors_pdev->dev,
5968 &dev_attr_thinkpad_acpi_pdev_name);
5969 if (tpacpi_sensors_pdev)
5970 platform_device_unregister(tpacpi_sensors_pdev);
5971 if (tpacpi_pdev)
5972 platform_device_unregister(tpacpi_pdev);
5973
5974 if (tp_features.sensors_pdrv_attrs_registered)
5975 tpacpi_remove_driver_attributes(&tpacpi_hwmon_pdriver.driver);
5976 if (tp_features.platform_drv_attrs_registered)
5977 tpacpi_remove_driver_attributes(&tpacpi_pdriver.driver);
5978
5979 if (tp_features.sensors_pdrv_registered)
5980 platform_driver_unregister(&tpacpi_hwmon_pdriver);
5981
5982 if (tp_features.platform_drv_registered)
5983 platform_driver_unregister(&tpacpi_pdriver);
5984
5985 if (proc_dir)
5986 remove_proc_entry(TPACPI_PROC_DIR, acpi_root_dir);
5987
5988 kfree(thinkpad_id.bios_version_str);
5989 kfree(thinkpad_id.ec_version_str);
5990 kfree(thinkpad_id.model_str);
5991}
5992
4883 5993
4884static int __init thinkpad_acpi_module_init(void) 5994static int __init thinkpad_acpi_module_init(void)
4885{ 5995{
@@ -4902,12 +6012,13 @@ static int __init thinkpad_acpi_module_init(void)
4902 6012
4903 /* Driver initialization */ 6013 /* Driver initialization */
4904 6014
4905 IBM_ACPIHANDLE_INIT(ecrd); 6015 TPACPI_ACPIHANDLE_INIT(ecrd);
4906 IBM_ACPIHANDLE_INIT(ecwr); 6016 TPACPI_ACPIHANDLE_INIT(ecwr);
4907 6017
4908 proc_dir = proc_mkdir(IBM_PROC_DIR, acpi_root_dir); 6018 proc_dir = proc_mkdir(TPACPI_PROC_DIR, acpi_root_dir);
4909 if (!proc_dir) { 6019 if (!proc_dir) {
4910 printk(IBM_ERR "unable to create proc dir " IBM_PROC_DIR); 6020 printk(TPACPI_ERR
6021 "unable to create proc dir " TPACPI_PROC_DIR);
4911 thinkpad_acpi_module_exit(); 6022 thinkpad_acpi_module_exit();
4912 return -ENODEV; 6023 return -ENODEV;
4913 } 6024 }
@@ -4915,7 +6026,8 @@ static int __init thinkpad_acpi_module_init(void)
4915 6026
4916 ret = platform_driver_register(&tpacpi_pdriver); 6027 ret = platform_driver_register(&tpacpi_pdriver);
4917 if (ret) { 6028 if (ret) {
4918 printk(IBM_ERR "unable to register main platform driver\n"); 6029 printk(TPACPI_ERR
6030 "unable to register main platform driver\n");
4919 thinkpad_acpi_module_exit(); 6031 thinkpad_acpi_module_exit();
4920 return ret; 6032 return ret;
4921 } 6033 }
@@ -4923,7 +6035,8 @@ static int __init thinkpad_acpi_module_init(void)
4923 6035
4924 ret = platform_driver_register(&tpacpi_hwmon_pdriver); 6036 ret = platform_driver_register(&tpacpi_hwmon_pdriver);
4925 if (ret) { 6037 if (ret) {
4926 printk(IBM_ERR "unable to register hwmon platform driver\n"); 6038 printk(TPACPI_ERR
6039 "unable to register hwmon platform driver\n");
4927 thinkpad_acpi_module_exit(); 6040 thinkpad_acpi_module_exit();
4928 return ret; 6041 return ret;
4929 } 6042 }
@@ -4932,10 +6045,12 @@ static int __init thinkpad_acpi_module_init(void)
4932 ret = tpacpi_create_driver_attributes(&tpacpi_pdriver.driver); 6045 ret = tpacpi_create_driver_attributes(&tpacpi_pdriver.driver);
4933 if (!ret) { 6046 if (!ret) {
4934 tp_features.platform_drv_attrs_registered = 1; 6047 tp_features.platform_drv_attrs_registered = 1;
4935 ret = tpacpi_create_driver_attributes(&tpacpi_hwmon_pdriver.driver); 6048 ret = tpacpi_create_driver_attributes(
6049 &tpacpi_hwmon_pdriver.driver);
4936 } 6050 }
4937 if (ret) { 6051 if (ret) {
4938 printk(IBM_ERR "unable to create sysfs driver attributes\n"); 6052 printk(TPACPI_ERR
6053 "unable to create sysfs driver attributes\n");
4939 thinkpad_acpi_module_exit(); 6054 thinkpad_acpi_module_exit();
4940 return ret; 6055 return ret;
4941 } 6056 }
@@ -4943,30 +6058,31 @@ static int __init thinkpad_acpi_module_init(void)
4943 6058
4944 6059
4945 /* Device initialization */ 6060 /* Device initialization */
4946 tpacpi_pdev = platform_device_register_simple(IBM_DRVR_NAME, -1, 6061 tpacpi_pdev = platform_device_register_simple(TPACPI_DRVR_NAME, -1,
4947 NULL, 0); 6062 NULL, 0);
4948 if (IS_ERR(tpacpi_pdev)) { 6063 if (IS_ERR(tpacpi_pdev)) {
4949 ret = PTR_ERR(tpacpi_pdev); 6064 ret = PTR_ERR(tpacpi_pdev);
4950 tpacpi_pdev = NULL; 6065 tpacpi_pdev = NULL;
4951 printk(IBM_ERR "unable to register platform device\n"); 6066 printk(TPACPI_ERR "unable to register platform device\n");
4952 thinkpad_acpi_module_exit(); 6067 thinkpad_acpi_module_exit();
4953 return ret; 6068 return ret;
4954 } 6069 }
4955 tpacpi_sensors_pdev = platform_device_register_simple( 6070 tpacpi_sensors_pdev = platform_device_register_simple(
4956 IBM_HWMON_DRVR_NAME, 6071 TPACPI_HWMON_DRVR_NAME,
4957 -1, NULL, 0); 6072 -1, NULL, 0);
4958 if (IS_ERR(tpacpi_sensors_pdev)) { 6073 if (IS_ERR(tpacpi_sensors_pdev)) {
4959 ret = PTR_ERR(tpacpi_sensors_pdev); 6074 ret = PTR_ERR(tpacpi_sensors_pdev);
4960 tpacpi_sensors_pdev = NULL; 6075 tpacpi_sensors_pdev = NULL;
4961 printk(IBM_ERR "unable to register hwmon platform device\n"); 6076 printk(TPACPI_ERR
6077 "unable to register hwmon platform device\n");
4962 thinkpad_acpi_module_exit(); 6078 thinkpad_acpi_module_exit();
4963 return ret; 6079 return ret;
4964 } 6080 }
4965 ret = device_create_file(&tpacpi_sensors_pdev->dev, 6081 ret = device_create_file(&tpacpi_sensors_pdev->dev,
4966 &dev_attr_thinkpad_acpi_pdev_name); 6082 &dev_attr_thinkpad_acpi_pdev_name);
4967 if (ret) { 6083 if (ret) {
4968 printk(IBM_ERR 6084 printk(TPACPI_ERR
4969 "unable to create sysfs hwmon device attributes\n"); 6085 "unable to create sysfs hwmon device attributes\n");
4970 thinkpad_acpi_module_exit(); 6086 thinkpad_acpi_module_exit();
4971 return ret; 6087 return ret;
4972 } 6088 }
@@ -4975,20 +6091,20 @@ static int __init thinkpad_acpi_module_init(void)
4975 if (IS_ERR(tpacpi_hwmon)) { 6091 if (IS_ERR(tpacpi_hwmon)) {
4976 ret = PTR_ERR(tpacpi_hwmon); 6092 ret = PTR_ERR(tpacpi_hwmon);
4977 tpacpi_hwmon = NULL; 6093 tpacpi_hwmon = NULL;
4978 printk(IBM_ERR "unable to register hwmon device\n"); 6094 printk(TPACPI_ERR "unable to register hwmon device\n");
4979 thinkpad_acpi_module_exit(); 6095 thinkpad_acpi_module_exit();
4980 return ret; 6096 return ret;
4981 } 6097 }
4982 mutex_init(&tpacpi_inputdev_send_mutex); 6098 mutex_init(&tpacpi_inputdev_send_mutex);
4983 tpacpi_inputdev = input_allocate_device(); 6099 tpacpi_inputdev = input_allocate_device();
4984 if (!tpacpi_inputdev) { 6100 if (!tpacpi_inputdev) {
4985 printk(IBM_ERR "unable to allocate input device\n"); 6101 printk(TPACPI_ERR "unable to allocate input device\n");
4986 thinkpad_acpi_module_exit(); 6102 thinkpad_acpi_module_exit();
4987 return -ENOMEM; 6103 return -ENOMEM;
4988 } else { 6104 } else {
4989 /* Prepare input device, but don't register */ 6105 /* Prepare input device, but don't register */
4990 tpacpi_inputdev->name = "ThinkPad Extra Buttons"; 6106 tpacpi_inputdev->name = "ThinkPad Extra Buttons";
4991 tpacpi_inputdev->phys = IBM_DRVR_NAME "/input0"; 6107 tpacpi_inputdev->phys = TPACPI_DRVR_NAME "/input0";
4992 tpacpi_inputdev->id.bustype = BUS_HOST; 6108 tpacpi_inputdev->id.bustype = BUS_HOST;
4993 tpacpi_inputdev->id.vendor = (thinkpad_id.vendor) ? 6109 tpacpi_inputdev->id.vendor = (thinkpad_id.vendor) ?
4994 thinkpad_id.vendor : 6110 thinkpad_id.vendor :
@@ -5007,7 +6123,7 @@ static int __init thinkpad_acpi_module_init(void)
5007 } 6123 }
5008 ret = input_register_device(tpacpi_inputdev); 6124 ret = input_register_device(tpacpi_inputdev);
5009 if (ret < 0) { 6125 if (ret < 0) {
5010 printk(IBM_ERR "unable to register input device\n"); 6126 printk(TPACPI_ERR "unable to register input device\n");
5011 thinkpad_acpi_module_exit(); 6127 thinkpad_acpi_module_exit();
5012 return ret; 6128 return ret;
5013 } else { 6129 } else {
@@ -5018,56 +6134,36 @@ static int __init thinkpad_acpi_module_init(void)
5018 return 0; 6134 return 0;
5019} 6135}
5020 6136
5021static void thinkpad_acpi_module_exit(void) 6137/* Please remove this in year 2009 */
5022{ 6138MODULE_ALIAS("ibm_acpi");
5023 struct ibm_struct *ibm, *itmp;
5024
5025 tpacpi_lifecycle = TPACPI_LIFE_EXITING;
5026
5027 list_for_each_entry_safe_reverse(ibm, itmp,
5028 &tpacpi_all_drivers,
5029 all_drivers) {
5030 ibm_exit(ibm);
5031 }
5032
5033 dbg_printk(TPACPI_DBG_INIT, "finished subdriver exit path...\n");
5034
5035 if (tpacpi_inputdev) {
5036 if (tp_features.input_device_registered)
5037 input_unregister_device(tpacpi_inputdev);
5038 else
5039 input_free_device(tpacpi_inputdev);
5040 }
5041
5042 if (tpacpi_hwmon)
5043 hwmon_device_unregister(tpacpi_hwmon);
5044
5045 if (tp_features.sensors_pdev_attrs_registered)
5046 device_remove_file(&tpacpi_sensors_pdev->dev,
5047 &dev_attr_thinkpad_acpi_pdev_name);
5048 if (tpacpi_sensors_pdev)
5049 platform_device_unregister(tpacpi_sensors_pdev);
5050 if (tpacpi_pdev)
5051 platform_device_unregister(tpacpi_pdev);
5052
5053 if (tp_features.sensors_pdrv_attrs_registered)
5054 tpacpi_remove_driver_attributes(&tpacpi_hwmon_pdriver.driver);
5055 if (tp_features.platform_drv_attrs_registered)
5056 tpacpi_remove_driver_attributes(&tpacpi_pdriver.driver);
5057 6139
5058 if (tp_features.sensors_pdrv_registered) 6140/*
5059 platform_driver_unregister(&tpacpi_hwmon_pdriver); 6141 * DMI matching for module autoloading
6142 *
6143 * See http://thinkwiki.org/wiki/List_of_DMI_IDs
6144 * See http://thinkwiki.org/wiki/BIOS_Upgrade_Downloads
6145 *
6146 * Only models listed in thinkwiki will be supported, so add yours
6147 * if it is not there yet.
6148 */
6149#define IBM_BIOS_MODULE_ALIAS(__type) \
6150 MODULE_ALIAS("dmi:bvnIBM:bvr" __type "ET??WW")
5060 6151
5061 if (tp_features.platform_drv_registered) 6152/* Non-ancient thinkpads */
5062 platform_driver_unregister(&tpacpi_pdriver); 6153MODULE_ALIAS("dmi:bvnIBM:*:svnIBM:*:pvrThinkPad*:rvnIBM:*");
6154MODULE_ALIAS("dmi:bvnLENOVO:*:svnLENOVO:*:pvrThinkPad*:rvnLENOVO:*");
5063 6155
5064 if (proc_dir) 6156/* Ancient thinkpad BIOSes have to be identified by
5065 remove_proc_entry(IBM_PROC_DIR, acpi_root_dir); 6157 * BIOS type or model number, and there are far less
6158 * BIOS types than model numbers... */
6159IBM_BIOS_MODULE_ALIAS("I[B,D,H,I,M,N,O,T,W,V,Y,Z]");
6160IBM_BIOS_MODULE_ALIAS("1[0,3,6,8,A-G,I,K,M-P,S,T]");
6161IBM_BIOS_MODULE_ALIAS("K[U,X-Z]");
5066 6162
5067 kfree(thinkpad_id.bios_version_str); 6163MODULE_AUTHOR("Borislav Deianov, Henrique de Moraes Holschuh");
5068 kfree(thinkpad_id.ec_version_str); 6164MODULE_DESCRIPTION(TPACPI_DESC);
5069 kfree(thinkpad_id.model_str); 6165MODULE_VERSION(TPACPI_VERSION);
5070} 6166MODULE_LICENSE("GPL");
5071 6167
5072module_init(thinkpad_acpi_module_init); 6168module_init(thinkpad_acpi_module_init);
5073module_exit(thinkpad_acpi_module_exit); 6169module_exit(thinkpad_acpi_module_exit);
diff --git a/drivers/misc/thinkpad_acpi.h b/drivers/misc/thinkpad_acpi.h
deleted file mode 100644
index 8fba2bbe345e..000000000000
--- a/drivers/misc/thinkpad_acpi.h
+++ /dev/null
@@ -1,606 +0,0 @@
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/nvram.h>
36#include <linux/proc_fs.h>
37#include <linux/sysfs.h>
38#include <linux/backlight.h>
39#include <linux/fb.h>
40#include <linux/platform_device.h>
41#include <linux/hwmon.h>
42#include <linux/hwmon-sysfs.h>
43#include <linux/input.h>
44#include <asm/uaccess.h>
45
46#include <linux/dmi.h>
47#include <linux/jiffies.h>
48#include <linux/workqueue.h>
49
50#include <acpi/acpi_drivers.h>
51#include <acpi/acnamesp.h>
52
53#include <linux/pci_ids.h>
54
55/****************************************************************************
56 * Main driver
57 */
58
59#define IBM_NAME "thinkpad"
60#define IBM_DESC "ThinkPad ACPI Extras"
61#define IBM_FILE IBM_NAME "_acpi"
62#define IBM_URL "http://ibm-acpi.sf.net/"
63#define IBM_MAIL "ibm-acpi-devel@lists.sourceforge.net"
64
65#define IBM_PROC_DIR "ibm"
66#define IBM_ACPI_EVENT_PREFIX "ibm"
67#define IBM_DRVR_NAME IBM_FILE
68#define IBM_HWMON_DRVR_NAME IBM_NAME "_hwmon"
69
70#define IBM_LOG IBM_FILE ": "
71#define IBM_ERR KERN_ERR IBM_LOG
72#define IBM_NOTICE KERN_NOTICE IBM_LOG
73#define IBM_INFO KERN_INFO IBM_LOG
74#define IBM_DEBUG KERN_DEBUG IBM_LOG
75
76#define IBM_MAX_ACPI_ARGS 3
77
78/* ThinkPad CMOS commands */
79#define TP_CMOS_VOLUME_DOWN 0
80#define TP_CMOS_VOLUME_UP 1
81#define TP_CMOS_VOLUME_MUTE 2
82#define TP_CMOS_BRIGHTNESS_UP 4
83#define TP_CMOS_BRIGHTNESS_DOWN 5
84
85/* ThinkPad CMOS NVRAM constants */
86#define TP_NVRAM_ADDR_BRIGHTNESS 0x5e
87#define TP_NVRAM_MASK_LEVEL_BRIGHTNESS 0x0f
88#define TP_NVRAM_POS_LEVEL_BRIGHTNESS 0
89
90#define onoff(status,bit) ((status) & (1 << (bit)) ? "on" : "off")
91#define enabled(status,bit) ((status) & (1 << (bit)) ? "enabled" : "disabled")
92#define strlencmp(a,b) (strncmp((a), (b), strlen(b)))
93
94/* Debugging */
95#define TPACPI_DBG_ALL 0xffff
96#define TPACPI_DBG_ALL 0xffff
97#define TPACPI_DBG_INIT 0x0001
98#define TPACPI_DBG_EXIT 0x0002
99#define dbg_printk(a_dbg_level, format, arg...) \
100 do { if (dbg_level & a_dbg_level) \
101 printk(IBM_DEBUG "%s: " format, __func__ , ## arg); } while (0)
102#ifdef CONFIG_THINKPAD_ACPI_DEBUG
103#define vdbg_printk(a_dbg_level, format, arg...) \
104 dbg_printk(a_dbg_level, format, ## arg)
105static const char *str_supported(int is_supported);
106#else
107#define vdbg_printk(a_dbg_level, format, arg...)
108#endif
109
110/* Input IDs */
111#define TPACPI_HKEY_INPUT_VENDOR PCI_VENDOR_ID_IBM
112#define TPACPI_HKEY_INPUT_PRODUCT 0x5054 /* "TP" */
113#define TPACPI_HKEY_INPUT_VERSION 0x4101
114
115/* ACPI HIDs */
116#define IBM_HKEY_HID "IBM0068"
117
118/* ACPI helpers */
119static int __must_check acpi_evalf(acpi_handle handle,
120 void *res, char *method, char *fmt, ...);
121static int __must_check acpi_ec_read(int i, u8 * p);
122static int __must_check acpi_ec_write(int i, u8 v);
123static int __must_check _sta(acpi_handle handle);
124
125/* ACPI handles */
126static acpi_handle root_handle; /* root namespace */
127static acpi_handle ec_handle; /* EC */
128static acpi_handle ecrd_handle, ecwr_handle; /* 570 EC access */
129static acpi_handle cmos_handle, hkey_handle; /* basic thinkpad handles */
130
131static void drv_acpi_handle_init(char *name,
132 acpi_handle *handle, acpi_handle parent,
133 char **paths, int num_paths, char **path);
134#define IBM_ACPIHANDLE_INIT(object) \
135 drv_acpi_handle_init(#object, &object##_handle, *object##_parent, \
136 object##_paths, ARRAY_SIZE(object##_paths), &object##_path)
137
138/* ThinkPad ACPI helpers */
139static int issue_thinkpad_cmos_command(int cmos_cmd);
140
141/* procfs support */
142static struct proc_dir_entry *proc_dir;
143
144/* procfs helpers */
145static int dispatch_procfs_read(char *page, char **start, off_t off,
146 int count, int *eof, void *data);
147static int dispatch_procfs_write(struct file *file,
148 const char __user * userbuf,
149 unsigned long count, void *data);
150static char *next_cmd(char **cmds);
151
152/* sysfs support */
153struct attribute_set {
154 unsigned int members, max_members;
155 struct attribute_group group;
156};
157
158static struct attribute_set *create_attr_set(unsigned int max_members,
159 const char* name);
160#define destroy_attr_set(_set) \
161 kfree(_set);
162static int add_to_attr_set(struct attribute_set* s, struct attribute *attr);
163static int add_many_to_attr_set(struct attribute_set* s,
164 struct attribute **attr,
165 unsigned int count);
166#define register_attr_set_with_sysfs(_attr_set, _kobj) \
167 sysfs_create_group(_kobj, &_attr_set->group)
168static void delete_attr_set(struct attribute_set* s, struct kobject *kobj);
169
170static int parse_strtoul(const char *buf, unsigned long max,
171 unsigned long *value);
172
173/* Device model */
174static struct platform_device *tpacpi_pdev;
175static struct platform_device *tpacpi_sensors_pdev;
176static struct device *tpacpi_hwmon;
177static struct platform_driver tpacpi_pdriver;
178static struct input_dev *tpacpi_inputdev;
179static int tpacpi_create_driver_attributes(struct device_driver *drv);
180static void tpacpi_remove_driver_attributes(struct device_driver *drv);
181
182/* Module */
183static int experimental;
184static u32 dbg_level;
185static int force_load;
186static unsigned int hotkey_report_mode;
187
188static int thinkpad_acpi_module_init(void);
189static void thinkpad_acpi_module_exit(void);
190
191
192/****************************************************************************
193 * Subdrivers
194 */
195
196struct ibm_struct;
197
198struct tp_acpi_drv_struct {
199 const struct acpi_device_id *hid;
200 struct acpi_driver *driver;
201
202 void (*notify) (struct ibm_struct *, u32);
203 acpi_handle *handle;
204 u32 type;
205 struct acpi_device *device;
206};
207
208struct ibm_struct {
209 char *name;
210
211 int (*read) (char *);
212 int (*write) (char *);
213 void (*exit) (void);
214 void (*resume) (void);
215
216 struct list_head all_drivers;
217
218 struct tp_acpi_drv_struct *acpi;
219
220 struct {
221 u8 acpi_driver_registered:1;
222 u8 acpi_notify_installed:1;
223 u8 proc_created:1;
224 u8 init_called:1;
225 u8 experimental:1;
226 } flags;
227};
228
229struct ibm_init_struct {
230 char param[32];
231
232 int (*init) (struct ibm_init_struct *);
233 struct ibm_struct *data;
234};
235
236static struct {
237#ifdef CONFIG_THINKPAD_ACPI_BAY
238 u32 bay_status:1;
239 u32 bay_eject:1;
240 u32 bay_status2:1;
241 u32 bay_eject2:1;
242#endif
243 u32 bluetooth:1;
244 u32 hotkey:1;
245 u32 hotkey_mask:1;
246 u32 hotkey_wlsw:1;
247 u32 light:1;
248 u32 light_status:1;
249 u32 bright_16levels:1;
250 u32 wan:1;
251 u32 fan_ctrl_status_undef:1;
252 u32 input_device_registered:1;
253 u32 platform_drv_registered:1;
254 u32 platform_drv_attrs_registered:1;
255 u32 sensors_pdrv_registered:1;
256 u32 sensors_pdrv_attrs_registered:1;
257 u32 sensors_pdev_attrs_registered:1;
258} tp_features;
259
260struct thinkpad_id_data {
261 unsigned int vendor; /* ThinkPad vendor:
262 * PCI_VENDOR_ID_IBM/PCI_VENDOR_ID_LENOVO */
263
264 char *bios_version_str; /* Something like 1ZET51WW (1.03z) */
265 char *ec_version_str; /* Something like 1ZHT51WW-1.04a */
266
267 u16 bios_model; /* Big Endian, TP-1Y = 0x5931, 0 = unknown */
268 u16 ec_model;
269
270 char *model_str;
271};
272
273static struct thinkpad_id_data thinkpad_id;
274
275static struct list_head tpacpi_all_drivers;
276
277static struct ibm_init_struct ibms_init[];
278static int set_ibm_param(const char *val, struct kernel_param *kp);
279static int ibm_init(struct ibm_init_struct *iibm);
280static void ibm_exit(struct ibm_struct *ibm);
281
282
283/*
284 * procfs master subdriver
285 */
286static int thinkpad_acpi_driver_init(struct ibm_init_struct *iibm);
287static int thinkpad_acpi_driver_read(char *p);
288
289
290/*
291 * Bay subdriver
292 */
293
294#ifdef CONFIG_THINKPAD_ACPI_BAY
295static acpi_handle bay_handle, bay_ej_handle;
296static acpi_handle bay2_handle, bay2_ej_handle;
297
298static int bay_init(struct ibm_init_struct *iibm);
299static void bay_notify(struct ibm_struct *ibm, u32 event);
300static int bay_read(char *p);
301static int bay_write(char *buf);
302#endif /* CONFIG_THINKPAD_ACPI_BAY */
303
304
305/*
306 * Beep subdriver
307 */
308
309static acpi_handle beep_handle;
310
311static int beep_read(char *p);
312static int beep_write(char *buf);
313
314
315/*
316 * Bluetooth subdriver
317 */
318
319enum {
320 /* ACPI GBDC/SBDC bits */
321 TP_ACPI_BLUETOOTH_HWPRESENT = 0x01, /* Bluetooth hw available */
322 TP_ACPI_BLUETOOTH_RADIOSSW = 0x02, /* Bluetooth radio enabled */
323 TP_ACPI_BLUETOOTH_UNK = 0x04, /* unknown function */
324};
325
326static int bluetooth_init(struct ibm_init_struct *iibm);
327static int bluetooth_get_radiosw(void);
328static int bluetooth_set_radiosw(int radio_on);
329static int bluetooth_read(char *p);
330static int bluetooth_write(char *buf);
331
332
333/*
334 * Brightness (backlight) subdriver
335 */
336
337#define TPACPI_BACKLIGHT_DEV_NAME "thinkpad_screen"
338
339static struct backlight_device *ibm_backlight_device;
340static int brightness_offset = 0x31;
341static int brightness_mode;
342static unsigned int brightness_enable; /* 0 = no, 1 = yes, 2 = auto */
343
344static int brightness_init(struct ibm_init_struct *iibm);
345static void brightness_exit(void);
346static int brightness_get(struct backlight_device *bd);
347static int brightness_set(int value);
348static int brightness_update_status(struct backlight_device *bd);
349static int brightness_read(char *p);
350static int brightness_write(char *buf);
351
352
353/*
354 * CMOS subdriver
355 */
356
357static int cmos_read(char *p);
358static int cmos_write(char *buf);
359
360
361/*
362 * Dock subdriver
363 */
364
365#ifdef CONFIG_THINKPAD_ACPI_DOCK
366static acpi_handle pci_handle;
367static acpi_handle dock_handle;
368
369static void dock_notify(struct ibm_struct *ibm, u32 event);
370static int dock_read(char *p);
371static int dock_write(char *buf);
372#endif /* CONFIG_THINKPAD_ACPI_DOCK */
373
374
375/*
376 * EC dump subdriver
377 */
378
379static int ecdump_read(char *p) ;
380static int ecdump_write(char *buf);
381
382
383/*
384 * Fan subdriver
385 */
386
387enum { /* Fan control constants */
388 fan_status_offset = 0x2f, /* EC register 0x2f */
389 fan_rpm_offset = 0x84, /* EC register 0x84: LSB, 0x85 MSB (RPM)
390 * 0x84 must be read before 0x85 */
391
392 TP_EC_FAN_FULLSPEED = 0x40, /* EC fan mode: full speed */
393 TP_EC_FAN_AUTO = 0x80, /* EC fan mode: auto fan control */
394
395 TPACPI_FAN_LAST_LEVEL = 0x100, /* Use cached last-seen fan level */
396};
397
398enum fan_status_access_mode {
399 TPACPI_FAN_NONE = 0, /* No fan status or control */
400 TPACPI_FAN_RD_ACPI_GFAN, /* Use ACPI GFAN */
401 TPACPI_FAN_RD_TPEC, /* Use ACPI EC regs 0x2f, 0x84-0x85 */
402};
403
404enum fan_control_access_mode {
405 TPACPI_FAN_WR_NONE = 0, /* No fan control */
406 TPACPI_FAN_WR_ACPI_SFAN, /* Use ACPI SFAN */
407 TPACPI_FAN_WR_TPEC, /* Use ACPI EC reg 0x2f */
408 TPACPI_FAN_WR_ACPI_FANS, /* Use ACPI FANS and EC reg 0x2f */
409};
410
411enum fan_control_commands {
412 TPACPI_FAN_CMD_SPEED = 0x0001, /* speed command */
413 TPACPI_FAN_CMD_LEVEL = 0x0002, /* level command */
414 TPACPI_FAN_CMD_ENABLE = 0x0004, /* enable/disable cmd,
415 * and also watchdog cmd */
416};
417
418static int fan_control_allowed;
419
420static enum fan_status_access_mode fan_status_access_mode;
421static enum fan_control_access_mode fan_control_access_mode;
422static enum fan_control_commands fan_control_commands;
423static u8 fan_control_initial_status;
424static u8 fan_control_desired_level;
425static int fan_watchdog_maxinterval;
426
427static struct mutex fan_mutex;
428
429static acpi_handle fans_handle, gfan_handle, sfan_handle;
430
431static int fan_init(struct ibm_init_struct *iibm);
432static void fan_exit(void);
433static int fan_get_status(u8 *status);
434static int fan_get_status_safe(u8 *status);
435static int fan_get_speed(unsigned int *speed);
436static void fan_update_desired_level(u8 status);
437static void fan_watchdog_fire(struct work_struct *ignored);
438static void fan_watchdog_reset(void);
439static int fan_set_level(int level);
440static int fan_set_level_safe(int level);
441static int fan_set_enable(void);
442static int fan_set_disable(void);
443static int fan_set_speed(int speed);
444static int fan_read(char *p);
445static int fan_write(char *buf);
446static int fan_write_cmd_level(const char *cmd, int *rc);
447static int fan_write_cmd_enable(const char *cmd, int *rc);
448static int fan_write_cmd_disable(const char *cmd, int *rc);
449static int fan_write_cmd_speed(const char *cmd, int *rc);
450static int fan_write_cmd_watchdog(const char *cmd, int *rc);
451
452
453/*
454 * Hotkey subdriver
455 */
456
457static int hotkey_orig_status;
458static u32 hotkey_orig_mask;
459
460static struct mutex hotkey_mutex;
461
462static int hotkey_init(struct ibm_init_struct *iibm);
463static void hotkey_exit(void);
464static int hotkey_get(int *status, u32 *mask);
465static int hotkey_set(int status, u32 mask);
466static void hotkey_notify(struct ibm_struct *ibm, u32 event);
467static int hotkey_read(char *p);
468static int hotkey_write(char *buf);
469
470
471/*
472 * LED subdriver
473 */
474
475enum led_access_mode {
476 TPACPI_LED_NONE = 0,
477 TPACPI_LED_570, /* 570 */
478 TPACPI_LED_OLD, /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20-21 */
479 TPACPI_LED_NEW, /* all others */
480};
481
482enum { /* For TPACPI_LED_OLD */
483 TPACPI_LED_EC_HLCL = 0x0c, /* EC reg to get led to power on */
484 TPACPI_LED_EC_HLBL = 0x0d, /* EC reg to blink a lit led */
485 TPACPI_LED_EC_HLMS = 0x0e, /* EC reg to select led to command */
486};
487
488static enum led_access_mode led_supported;
489static acpi_handle led_handle;
490
491static int led_init(struct ibm_init_struct *iibm);
492static int led_read(char *p);
493static int led_write(char *buf);
494
495/*
496 * Light (thinklight) subdriver
497 */
498
499static acpi_handle lght_handle, ledb_handle;
500
501static int light_init(struct ibm_init_struct *iibm);
502static int light_read(char *p);
503static int light_write(char *buf);
504
505
506/*
507 * Thermal subdriver
508 */
509
510enum thermal_access_mode {
511 TPACPI_THERMAL_NONE = 0, /* No thermal support */
512 TPACPI_THERMAL_ACPI_TMP07, /* Use ACPI TMP0-7 */
513 TPACPI_THERMAL_ACPI_UPDT, /* Use ACPI TMP0-7 with UPDT */
514 TPACPI_THERMAL_TPEC_8, /* Use ACPI EC regs, 8 sensors */
515 TPACPI_THERMAL_TPEC_16, /* Use ACPI EC regs, 16 sensors */
516};
517
518enum { /* TPACPI_THERMAL_TPEC_* */
519 TP_EC_THERMAL_TMP0 = 0x78, /* ACPI EC regs TMP 0..7 */
520 TP_EC_THERMAL_TMP8 = 0xC0, /* ACPI EC regs TMP 8..15 */
521 TP_EC_THERMAL_TMP_NA = -128, /* ACPI EC sensor not available */
522};
523
524#define TPACPI_MAX_THERMAL_SENSORS 16 /* Max thermal sensors supported */
525struct ibm_thermal_sensors_struct {
526 s32 temp[TPACPI_MAX_THERMAL_SENSORS];
527};
528
529static enum thermal_access_mode thermal_read_mode;
530
531static int thermal_init(struct ibm_init_struct *iibm);
532static int thermal_get_sensor(int idx, s32 *value);
533static int thermal_get_sensors(struct ibm_thermal_sensors_struct *s);
534static int thermal_read(char *p);
535
536
537/*
538 * Video subdriver
539 */
540
541enum video_access_mode {
542 TPACPI_VIDEO_NONE = 0,
543 TPACPI_VIDEO_570, /* 570 */
544 TPACPI_VIDEO_770, /* 600e/x, 770e, 770x */
545 TPACPI_VIDEO_NEW, /* all others */
546};
547
548enum { /* video status flags, based on VIDEO_570 */
549 TP_ACPI_VIDEO_S_LCD = 0x01, /* LCD output enabled */
550 TP_ACPI_VIDEO_S_CRT = 0x02, /* CRT output enabled */
551 TP_ACPI_VIDEO_S_DVI = 0x08, /* DVI output enabled */
552};
553
554enum { /* TPACPI_VIDEO_570 constants */
555 TP_ACPI_VIDEO_570_PHSCMD = 0x87, /* unknown magic constant :( */
556 TP_ACPI_VIDEO_570_PHSMASK = 0x03, /* PHS bits that map to
557 * video_status_flags */
558 TP_ACPI_VIDEO_570_PHS2CMD = 0x8b, /* unknown magic constant :( */
559 TP_ACPI_VIDEO_570_PHS2SET = 0x80, /* unknown magic constant :( */
560};
561
562static enum video_access_mode video_supported;
563static int video_orig_autosw;
564static acpi_handle vid_handle, vid2_handle;
565
566static int video_init(struct ibm_init_struct *iibm);
567static void video_exit(void);
568static int video_outputsw_get(void);
569static int video_outputsw_set(int status);
570static int video_autosw_get(void);
571static int video_autosw_set(int enable);
572static int video_outputsw_cycle(void);
573static int video_expand_toggle(void);
574static int video_read(char *p);
575static int video_write(char *buf);
576
577
578/*
579 * Volume subdriver
580 */
581
582static int volume_offset = 0x30;
583
584static int volume_read(char *p);
585static int volume_write(char *buf);
586
587
588/*
589 * Wan subdriver
590 */
591
592enum {
593 /* ACPI GWAN/SWAN bits */
594 TP_ACPI_WANCARD_HWPRESENT = 0x01, /* Wan hw available */
595 TP_ACPI_WANCARD_RADIOSSW = 0x02, /* Wan radio enabled */
596 TP_ACPI_WANCARD_UNK = 0x04, /* unknown function */
597};
598
599static int wan_init(struct ibm_init_struct *iibm);
600static int wan_get_radiosw(void);
601static int wan_set_radiosw(int radio_on);
602static int wan_read(char *p);
603static int wan_write(char *buf);
604
605
606#endif /* __THINKPAD_ACPI_H */