aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/platform
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/platform')
-rw-r--r--drivers/platform/Kconfig2
-rw-r--r--drivers/platform/x86/Kconfig96
-rw-r--r--drivers/platform/x86/Makefile4
-rw-r--r--drivers/platform/x86/acer-wmi.c13
-rw-r--r--drivers/platform/x86/acerhdf.c119
-rw-r--r--drivers/platform/x86/asus-laptop.c1744
-rw-r--r--drivers/platform/x86/asus_acpi.c351
-rw-r--r--drivers/platform/x86/classmate-laptop.c629
-rw-r--r--drivers/platform/x86/compal-laptop.c259
-rw-r--r--drivers/platform/x86/dell-laptop.c353
-rw-r--r--drivers/platform/x86/dell-wmi.c189
-rw-r--r--drivers/platform/x86/eeepc-laptop.c1512
-rw-r--r--drivers/platform/x86/eeepc-wmi.c413
-rw-r--r--drivers/platform/x86/fujitsu-laptop.c53
-rw-r--r--drivers/platform/x86/hp-wmi.c180
-rw-r--r--drivers/platform/x86/intel_menlow.c4
-rw-r--r--drivers/platform/x86/msi-laptop.c367
-rw-r--r--drivers/platform/x86/msi-wmi.c294
-rw-r--r--drivers/platform/x86/panasonic-laptop.c44
-rw-r--r--drivers/platform/x86/sony-laptop.c239
-rw-r--r--drivers/platform/x86/tc1100-wmi.c116
-rw-r--r--drivers/platform/x86/thinkpad_acpi.c1313
-rw-r--r--drivers/platform/x86/topstar-laptop.c14
-rw-r--r--drivers/platform/x86/toshiba_acpi.c475
-rw-r--r--drivers/platform/x86/toshiba_bluetooth.c144
-rw-r--r--drivers/platform/x86/wmi.c220
26 files changed, 6493 insertions, 2654 deletions
diff --git a/drivers/platform/Kconfig b/drivers/platform/Kconfig
index 9652c3fe7f5e..8390dca2b4e1 100644
--- a/drivers/platform/Kconfig
+++ b/drivers/platform/Kconfig
@@ -1,5 +1,3 @@
1# drivers/platform/Kconfig
2
3if X86 1if X86
4source "drivers/platform/x86/Kconfig" 2source "drivers/platform/x86/Kconfig"
5endif 3endif
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index 55ca39dea42e..6c3320d75055 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -59,6 +59,8 @@ config ASUS_LAPTOP
59 select NEW_LEDS 59 select NEW_LEDS
60 select BACKLIGHT_CLASS_DEVICE 60 select BACKLIGHT_CLASS_DEVICE
61 depends on INPUT 61 depends on INPUT
62 depends on RFKILL || RFKILL = n
63 select INPUT_SPARSEKMAP
62 ---help--- 64 ---help---
63 This is the new Linux driver for Asus laptops. It may also support some 65 This is the new Linux driver for Asus laptops. It may also support some
64 MEDION, JVC or VICTOR laptops. It makes all the extra buttons generate 66 MEDION, JVC or VICTOR laptops. It makes all the extra buttons generate
@@ -79,6 +81,7 @@ config DELL_LAPTOP
79 depends on BACKLIGHT_CLASS_DEVICE 81 depends on BACKLIGHT_CLASS_DEVICE
80 depends on RFKILL || RFKILL = n 82 depends on RFKILL || RFKILL = n
81 depends on POWER_SUPPLY 83 depends on POWER_SUPPLY
84 depends on SERIO_I8042
82 default n 85 default n
83 ---help--- 86 ---help---
84 This driver adds support for rfkill and backlight control to Dell 87 This driver adds support for rfkill and backlight control to Dell
@@ -147,6 +150,7 @@ config MSI_LAPTOP
147 tristate "MSI Laptop Extras" 150 tristate "MSI Laptop Extras"
148 depends on ACPI 151 depends on ACPI
149 depends on BACKLIGHT_CLASS_DEVICE 152 depends on BACKLIGHT_CLASS_DEVICE
153 depends on RFKILL
150 ---help--- 154 ---help---
151 This is a driver for laptops built by MSI (MICRO-STAR 155 This is a driver for laptops built by MSI (MICRO-STAR
152 INTERNATIONAL): 156 INTERNATIONAL):
@@ -176,6 +180,7 @@ config COMPAL_LAPTOP
176 tristate "Compal Laptop Extras" 180 tristate "Compal Laptop Extras"
177 depends on ACPI 181 depends on ACPI
178 depends on BACKLIGHT_CLASS_DEVICE 182 depends on BACKLIGHT_CLASS_DEVICE
183 depends on RFKILL
179 ---help--- 184 ---help---
180 This is a driver for laptops built by Compal: 185 This is a driver for laptops built by Compal:
181 186
@@ -231,8 +236,36 @@ config THINKPAD_ACPI
231 236
232 This driver was formerly known as ibm-acpi. 237 This driver was formerly known as ibm-acpi.
233 238
239 Extra functionality will be available if the rfkill (CONFIG_RFKILL)
240 and/or ALSA (CONFIG_SND) subsystems are available in the kernel.
241 Note that if you want ThinkPad-ACPI to be built-in instead of
242 modular, ALSA and rfkill will also have to be built-in.
243
234 If you have an IBM or Lenovo ThinkPad laptop, say Y or M here. 244 If you have an IBM or Lenovo ThinkPad laptop, say Y or M here.
235 245
246config THINKPAD_ACPI_ALSA_SUPPORT
247 bool "Console audio control ALSA interface"
248 depends on THINKPAD_ACPI
249 depends on SND
250 depends on SND = y || THINKPAD_ACPI = SND
251 default y
252 ---help---
253 Enables monitoring of the built-in console audio output control
254 (headphone and speakers), which is operated by the mute and (in
255 some ThinkPad models) volume hotkeys.
256
257 If this option is enabled, ThinkPad-ACPI will export an ALSA card
258 with a single read-only mixer control, which should be used for
259 on-screen-display feedback purposes by the Desktop Environment.
260
261 Optionally, the driver will also allow software control (the
262 ALSA mixer will be made read-write). Please refer to the driver
263 documentation for details.
264
265 All IBM models have both volume and mute control. Newer Lenovo
266 models only have mute control (the volume hotkeys are just normal
267 keys and volume control is done through the main HDA mixer).
268
236config THINKPAD_ACPI_DEBUGFACILITIES 269config THINKPAD_ACPI_DEBUGFACILITIES
237 bool "Maintainer debug facilities" 270 bool "Maintainer debug facilities"
238 depends on THINKPAD_ACPI 271 depends on THINKPAD_ACPI
@@ -291,9 +324,15 @@ config THINKPAD_ACPI_VIDEO
291 server running, phase of the moon, and the current mood of 324 server running, phase of the moon, and the current mood of
292 Schroedinger's cat. If you can use X.org's RandR to control 325 Schroedinger's cat. If you can use X.org's RandR to control
293 your ThinkPad's video output ports instead of this feature, 326 your ThinkPad's video output ports instead of this feature,
294 don't think twice: do it and say N here to save some memory. 327 don't think twice: do it and say N here to save memory and avoid
328 bad interactions with X.org.
329
330 NOTE: access to this feature is limited to processes with the
331 CAP_SYS_ADMIN capability, to avoid local DoS issues in platforms
332 where it interacts badly with X.org.
295 333
296 If you are not sure, say Y here. 334 If you are not sure, say Y here but do try to check if you could
335 be using X.org RandR instead.
297 336
298config THINKPAD_ACPI_HOTKEY_POLL 337config THINKPAD_ACPI_HOTKEY_POLL
299 bool "Support NVRAM polling for hot keys" 338 bool "Support NVRAM polling for hot keys"
@@ -334,6 +373,9 @@ config EEEPC_LAPTOP
334 depends on HOTPLUG_PCI 373 depends on HOTPLUG_PCI
335 select BACKLIGHT_CLASS_DEVICE 374 select BACKLIGHT_CLASS_DEVICE
336 select HWMON 375 select HWMON
376 select LEDS_CLASS
377 select NEW_LEDS
378 select INPUT_SPARSEKMAP
337 ---help--- 379 ---help---
338 This driver supports the Fn-Fx keys on Eee PC laptops. 380 This driver supports the Fn-Fx keys on Eee PC laptops.
339 381
@@ -343,6 +385,17 @@ config EEEPC_LAPTOP
343 385
344 If you have an Eee PC laptop, say Y or M here. 386 If you have an Eee PC laptop, say Y or M here.
345 387
388config EEEPC_WMI
389 tristate "Eee PC WMI Hotkey Driver (EXPERIMENTAL)"
390 depends on ACPI_WMI
391 depends on INPUT
392 depends on EXPERIMENTAL
393 select INPUT_SPARSEKMAP
394 ---help---
395 Say Y here if you want to support WMI-based hotkeys on Eee PC laptops.
396
397 To compile this driver as a module, choose M here: the module will
398 be called eeepc-wmi.
346 399
347config ACPI_WMI 400config ACPI_WMI
348 tristate "WMI" 401 tristate "WMI"
@@ -365,6 +418,18 @@ config ACPI_WMI
365 It is safe to enable this driver even if your DSDT doesn't define 418 It is safe to enable this driver even if your DSDT doesn't define
366 any ACPI-WMI devices. 419 any ACPI-WMI devices.
367 420
421config MSI_WMI
422 tristate "MSI WMI extras"
423 depends on ACPI_WMI
424 depends on INPUT
425 depends on BACKLIGHT_CLASS_DEVICE
426 select INPUT_SPARSEKMAP
427 help
428 Say Y here if you want to support WMI-based hotkeys on MSI laptops.
429
430 To compile this driver as a module, choose M here: the module will
431 be called msi-wmi.
432
368config ACPI_ASUS 433config ACPI_ASUS
369 tristate "ASUS/Medion Laptop Extras (DEPRECATED)" 434 tristate "ASUS/Medion Laptop Extras (DEPRECATED)"
370 depends on ACPI 435 depends on ACPI
@@ -435,4 +500,31 @@ config ACPI_TOSHIBA
435 500
436 If you have a legacy free Toshiba laptop (such as the Libretto L1 501 If you have a legacy free Toshiba laptop (such as the Libretto L1
437 series), say Y. 502 series), say Y.
503
504config TOSHIBA_BT_RFKILL
505 tristate "Toshiba Bluetooth RFKill switch support"
506 depends on ACPI
507 ---help---
508 This driver adds support for Bluetooth events for the RFKill
509 switch on modern Toshiba laptops with full ACPI support and
510 an RFKill switch.
511
512 This driver handles RFKill events for the TOS6205 Bluetooth,
513 and re-enables it when the switch is set back to the 'on'
514 position.
515
516 If you have a modern Toshiba laptop with a Bluetooth and an
517 RFKill switch (such as the Portege R500), say Y.
518
519config ACPI_CMPC
520 tristate "CMPC Laptop Extras"
521 depends on X86 && ACPI
522 select INPUT
523 select BACKLIGHT_CLASS_DEVICE
524 default n
525 help
526 Support for Intel Classmate PC ACPI devices, including some
527 keys as input device, backlight device, tablet and accelerometer
528 devices.
529
438endif # X86_PLATFORM_DEVICES 530endif # X86_PLATFORM_DEVICES
diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile
index d1c16210a512..a906490e3530 100644
--- a/drivers/platform/x86/Makefile
+++ b/drivers/platform/x86/Makefile
@@ -4,7 +4,9 @@
4# 4#
5obj-$(CONFIG_ASUS_LAPTOP) += asus-laptop.o 5obj-$(CONFIG_ASUS_LAPTOP) += asus-laptop.o
6obj-$(CONFIG_EEEPC_LAPTOP) += eeepc-laptop.o 6obj-$(CONFIG_EEEPC_LAPTOP) += eeepc-laptop.o
7obj-$(CONFIG_EEEPC_WMI) += eeepc-wmi.o
7obj-$(CONFIG_MSI_LAPTOP) += msi-laptop.o 8obj-$(CONFIG_MSI_LAPTOP) += msi-laptop.o
9obj-$(CONFIG_ACPI_CMPC) += classmate-laptop.o
8obj-$(CONFIG_COMPAL_LAPTOP) += compal-laptop.o 10obj-$(CONFIG_COMPAL_LAPTOP) += compal-laptop.o
9obj-$(CONFIG_DELL_LAPTOP) += dell-laptop.o 11obj-$(CONFIG_DELL_LAPTOP) += dell-laptop.o
10obj-$(CONFIG_DELL_WMI) += dell-wmi.o 12obj-$(CONFIG_DELL_WMI) += dell-wmi.o
@@ -18,6 +20,8 @@ obj-$(CONFIG_FUJITSU_LAPTOP) += fujitsu-laptop.o
18obj-$(CONFIG_PANASONIC_LAPTOP) += panasonic-laptop.o 20obj-$(CONFIG_PANASONIC_LAPTOP) += panasonic-laptop.o
19obj-$(CONFIG_INTEL_MENLOW) += intel_menlow.o 21obj-$(CONFIG_INTEL_MENLOW) += intel_menlow.o
20obj-$(CONFIG_ACPI_WMI) += wmi.o 22obj-$(CONFIG_ACPI_WMI) += wmi.o
23obj-$(CONFIG_MSI_WMI) += msi-wmi.o
21obj-$(CONFIG_ACPI_ASUS) += asus_acpi.o 24obj-$(CONFIG_ACPI_ASUS) += asus_acpi.o
22obj-$(CONFIG_TOPSTAR_LAPTOP) += topstar-laptop.o 25obj-$(CONFIG_TOPSTAR_LAPTOP) += topstar-laptop.o
23obj-$(CONFIG_ACPI_TOSHIBA) += toshiba_acpi.o 26obj-$(CONFIG_ACPI_TOSHIBA) += toshiba_acpi.o
27obj-$(CONFIG_TOSHIBA_BT_RFKILL) += toshiba_bluetooth.o
diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c
index 454970d2d701..1ea6c434d330 100644
--- a/drivers/platform/x86/acer-wmi.c
+++ b/drivers/platform/x86/acer-wmi.c
@@ -36,6 +36,7 @@
36#include <linux/rfkill.h> 36#include <linux/rfkill.h>
37#include <linux/workqueue.h> 37#include <linux/workqueue.h>
38#include <linux/debugfs.h> 38#include <linux/debugfs.h>
39#include <linux/slab.h>
39 40
40#include <acpi/acpi_drivers.h> 41#include <acpi/acpi_drivers.h>
41 42
@@ -96,9 +97,6 @@ struct acer_quirks {
96MODULE_ALIAS("wmi:67C3371D-95A3-4C37-BB61-DD47B491DAAB"); 97MODULE_ALIAS("wmi:67C3371D-95A3-4C37-BB61-DD47B491DAAB");
97MODULE_ALIAS("wmi:6AF4F258-B401-42fd-BE91-3D4AC2D7C0D3"); 98MODULE_ALIAS("wmi:6AF4F258-B401-42fd-BE91-3D4AC2D7C0D3");
98 99
99/* Temporary workaround until the WMI sysfs interface goes in */
100MODULE_ALIAS("dmi:*:*Acer*:*:");
101
102/* 100/*
103 * Interface capability flags 101 * Interface capability flags
104 */ 102 */
@@ -925,9 +923,13 @@ static struct backlight_ops acer_bl_ops = {
925 923
926static int __devinit acer_backlight_init(struct device *dev) 924static int __devinit acer_backlight_init(struct device *dev)
927{ 925{
926 struct backlight_properties props;
928 struct backlight_device *bd; 927 struct backlight_device *bd;
929 928
930 bd = backlight_device_register("acer-wmi", dev, NULL, &acer_bl_ops); 929 memset(&props, 0, sizeof(struct backlight_properties));
930 props.max_brightness = max_brightness;
931 bd = backlight_device_register("acer-wmi", dev, NULL, &acer_bl_ops,
932 &props);
931 if (IS_ERR(bd)) { 933 if (IS_ERR(bd)) {
932 printk(ACER_ERR "Could not register Acer backlight device\n"); 934 printk(ACER_ERR "Could not register Acer backlight device\n");
933 acer_backlight_device = NULL; 935 acer_backlight_device = NULL;
@@ -937,8 +939,7 @@ static int __devinit acer_backlight_init(struct device *dev)
937 acer_backlight_device = bd; 939 acer_backlight_device = bd;
938 940
939 bd->props.power = FB_BLANK_UNBLANK; 941 bd->props.power = FB_BLANK_UNBLANK;
940 bd->props.brightness = max_brightness; 942 bd->props.brightness = read_brightness(bd);
941 bd->props.max_brightness = max_brightness;
942 backlight_update_status(bd); 943 backlight_update_status(bd);
943 return 0; 944 return 0;
944} 945}
diff --git a/drivers/platform/x86/acerhdf.c b/drivers/platform/x86/acerhdf.c
index ab64522aaa64..7b2384d674d0 100644
--- a/drivers/platform/x86/acerhdf.c
+++ b/drivers/platform/x86/acerhdf.c
@@ -52,7 +52,7 @@
52 */ 52 */
53#undef START_IN_KERNEL_MODE 53#undef START_IN_KERNEL_MODE
54 54
55#define DRV_VER "0.5.18" 55#define DRV_VER "0.5.22"
56 56
57/* 57/*
58 * According to the Atom N270 datasheet, 58 * According to the Atom N270 datasheet,
@@ -112,12 +112,14 @@ module_param_string(force_product, force_product, 16, 0);
112MODULE_PARM_DESC(force_product, "Force BIOS product and omit BIOS check"); 112MODULE_PARM_DESC(force_product, "Force BIOS product and omit BIOS check");
113 113
114/* 114/*
115 * cmd_off: to switch the fan completely off / to check if the fan is off 115 * cmd_off: to switch the fan completely off
116 * chk_off: to check if the fan is off
116 * cmd_auto: to set the BIOS in control of the fan. The BIOS regulates then 117 * cmd_auto: to set the BIOS in control of the fan. The BIOS regulates then
117 * the fan speed depending on the temperature 118 * the fan speed depending on the temperature
118 */ 119 */
119struct fancmd { 120struct fancmd {
120 u8 cmd_off; 121 u8 cmd_off;
122 u8 chk_off;
121 u8 cmd_auto; 123 u8 cmd_auto;
122}; 124};
123 125
@@ -134,32 +136,47 @@ struct bios_settings_t {
134/* Register addresses and values for different BIOS versions */ 136/* Register addresses and values for different BIOS versions */
135static const struct bios_settings_t bios_tbl[] = { 137static const struct bios_settings_t bios_tbl[] = {
136 /* AOA110 */ 138 /* AOA110 */
137 {"Acer", "AOA110", "v0.3109", 0x55, 0x58, {0x1f, 0x00} }, 139 {"Acer", "AOA110", "v0.3109", 0x55, 0x58, {0x1f, 0x1f, 0x00} },
138 {"Acer", "AOA110", "v0.3114", 0x55, 0x58, {0x1f, 0x00} }, 140 {"Acer", "AOA110", "v0.3114", 0x55, 0x58, {0x1f, 0x1f, 0x00} },
139 {"Acer", "AOA110", "v0.3301", 0x55, 0x58, {0xaf, 0x00} }, 141 {"Acer", "AOA110", "v0.3301", 0x55, 0x58, {0xaf, 0xaf, 0x00} },
140 {"Acer", "AOA110", "v0.3304", 0x55, 0x58, {0xaf, 0x00} }, 142 {"Acer", "AOA110", "v0.3304", 0x55, 0x58, {0xaf, 0xaf, 0x00} },
141 {"Acer", "AOA110", "v0.3305", 0x55, 0x58, {0xaf, 0x00} }, 143 {"Acer", "AOA110", "v0.3305", 0x55, 0x58, {0xaf, 0xaf, 0x00} },
142 {"Acer", "AOA110", "v0.3307", 0x55, 0x58, {0xaf, 0x00} }, 144 {"Acer", "AOA110", "v0.3307", 0x55, 0x58, {0xaf, 0xaf, 0x00} },
143 {"Acer", "AOA110", "v0.3308", 0x55, 0x58, {0x21, 0x00} }, 145 {"Acer", "AOA110", "v0.3308", 0x55, 0x58, {0x21, 0x21, 0x00} },
144 {"Acer", "AOA110", "v0.3309", 0x55, 0x58, {0x21, 0x00} }, 146 {"Acer", "AOA110", "v0.3309", 0x55, 0x58, {0x21, 0x21, 0x00} },
145 {"Acer", "AOA110", "v0.3310", 0x55, 0x58, {0x21, 0x00} }, 147 {"Acer", "AOA110", "v0.3310", 0x55, 0x58, {0x21, 0x21, 0x00} },
146 /* AOA150 */ 148 /* AOA150 */
147 {"Acer", "AOA150", "v0.3114", 0x55, 0x58, {0x20, 0x00} }, 149 {"Acer", "AOA150", "v0.3114", 0x55, 0x58, {0x20, 0x20, 0x00} },
148 {"Acer", "AOA150", "v0.3301", 0x55, 0x58, {0x20, 0x00} }, 150 {"Acer", "AOA150", "v0.3301", 0x55, 0x58, {0x20, 0x20, 0x00} },
149 {"Acer", "AOA150", "v0.3304", 0x55, 0x58, {0x20, 0x00} }, 151 {"Acer", "AOA150", "v0.3304", 0x55, 0x58, {0x20, 0x20, 0x00} },
150 {"Acer", "AOA150", "v0.3305", 0x55, 0x58, {0x20, 0x00} }, 152 {"Acer", "AOA150", "v0.3305", 0x55, 0x58, {0x20, 0x20, 0x00} },
151 {"Acer", "AOA150", "v0.3307", 0x55, 0x58, {0x20, 0x00} }, 153 {"Acer", "AOA150", "v0.3307", 0x55, 0x58, {0x20, 0x20, 0x00} },
152 {"Acer", "AOA150", "v0.3308", 0x55, 0x58, {0x20, 0x00} }, 154 {"Acer", "AOA150", "v0.3308", 0x55, 0x58, {0x20, 0x20, 0x00} },
153 {"Acer", "AOA150", "v0.3309", 0x55, 0x58, {0x20, 0x00} }, 155 {"Acer", "AOA150", "v0.3309", 0x55, 0x58, {0x20, 0x20, 0x00} },
154 {"Acer", "AOA150", "v0.3310", 0x55, 0x58, {0x20, 0x00} }, 156 {"Acer", "AOA150", "v0.3310", 0x55, 0x58, {0x20, 0x20, 0x00} },
155 /* special BIOS / other */ 157 /* Acer 1410 */
156 {"Gateway", "AOA110", "v0.3103", 0x55, 0x58, {0x21, 0x00} }, 158 {"Acer", "Aspire 1410", "v0.3120", 0x55, 0x58, {0x9e, 0x9e, 0x00} },
157 {"Gateway", "AOA150", "v0.3103", 0x55, 0x58, {0x20, 0x00} }, 159 {"Acer", "Aspire 1410", "v1.3303", 0x55, 0x58, {0x9e, 0x9e, 0x00} },
158 {"Packard Bell", "DOA150", "v0.3104", 0x55, 0x58, {0x21, 0x00} }, 160 /* Acer 1810xx */
159 {"Packard Bell", "AOA110", "v0.3105", 0x55, 0x58, {0x21, 0x00} }, 161 {"Acer", "Aspire 1810TZ", "v0.3120", 0x55, 0x58, {0x9e, 0x9e, 0x00} },
160 {"Packard Bell", "AOA150", "v0.3105", 0x55, 0x58, {0x20, 0x00} }, 162 {"Acer", "Aspire 1810T", "v0.3120", 0x55, 0x58, {0x9e, 0x9e, 0x00} },
163 {"Acer", "Aspire 1810T", "v1.3303", 0x55, 0x58, {0x9e, 0x9e, 0x00} },
164 {"Acer", "Aspire 1810TZ", "v1.3303", 0x55, 0x58, {0x9e, 0x9e, 0x00} },
165 /* Gateway */
166 {"Gateway", "AOA110", "v0.3103", 0x55, 0x58, {0x21, 0x21, 0x00} },
167 {"Gateway", "AOA150", "v0.3103", 0x55, 0x58, {0x20, 0x20, 0x00} },
168 {"Gateway", "LT31", "v1.3103", 0x55, 0x58, {0x10, 0x0f, 0x00} },
169 {"Gateway", "LT31", "v1.3201", 0x55, 0x58, {0x10, 0x0f, 0x00} },
170 {"Gateway", "LT31", "v1.3302", 0x55, 0x58, {0x10, 0x0f, 0x00} },
171 /* Packard Bell */
172 {"Packard Bell", "DOA150", "v0.3104", 0x55, 0x58, {0x21, 0x21, 0x00} },
173 {"Packard Bell", "DOA150", "v0.3105", 0x55, 0x58, {0x20, 0x20, 0x00} },
174 {"Packard Bell", "AOA110", "v0.3105", 0x55, 0x58, {0x21, 0x21, 0x00} },
175 {"Packard Bell", "AOA150", "v0.3105", 0x55, 0x58, {0x20, 0x20, 0x00} },
176 {"Packard Bell", "DOTMU", "v1.3303", 0x55, 0x58, {0x9e, 0x9e, 0x00} },
177 {"Packard Bell", "DOTMU", "v0.3120", 0x55, 0x58, {0x9e, 0x9e, 0x00} },
161 /* pewpew-terminator */ 178 /* pewpew-terminator */
162 {"", "", "", 0, 0, {0, 0} } 179 {"", "", "", 0, 0, {0, 0, 0} }
163}; 180};
164 181
165static const struct bios_settings_t *bios_cfg __read_mostly; 182static const struct bios_settings_t *bios_cfg __read_mostly;
@@ -183,7 +200,7 @@ static int acerhdf_get_fanstate(int *state)
183 if (ec_read(bios_cfg->fanreg, &fan)) 200 if (ec_read(bios_cfg->fanreg, &fan))
184 return -EINVAL; 201 return -EINVAL;
185 202
186 if (fan != bios_cfg->cmd.cmd_off) 203 if (fan != bios_cfg->cmd.chk_off)
187 *state = ACERHDF_FAN_AUTO; 204 *state = ACERHDF_FAN_AUTO;
188 else 205 else
189 *state = ACERHDF_FAN_OFF; 206 *state = ACERHDF_FAN_OFF;
@@ -460,7 +477,7 @@ static int acerhdf_remove(struct platform_device *device)
460 return 0; 477 return 0;
461} 478}
462 479
463static struct dev_pm_ops acerhdf_pm_ops = { 480static const struct dev_pm_ops acerhdf_pm_ops = {
464 .suspend = acerhdf_suspend, 481 .suspend = acerhdf_suspend,
465 .freeze = acerhdf_suspend, 482 .freeze = acerhdf_suspend,
466}; 483};
@@ -475,13 +492,26 @@ static struct platform_driver acerhdf_driver = {
475 .remove = acerhdf_remove, 492 .remove = acerhdf_remove,
476}; 493};
477 494
495/* checks if str begins with start */
496static int str_starts_with(const char *str, const char *start)
497{
498 unsigned long str_len = 0, start_len = 0;
499
500 str_len = strlen(str);
501 start_len = strlen(start);
502
503 if (str_len >= start_len &&
504 !strncmp(str, start, start_len))
505 return 1;
506
507 return 0;
508}
478 509
479/* check hardware */ 510/* check hardware */
480static int acerhdf_check_hardware(void) 511static int acerhdf_check_hardware(void)
481{ 512{
482 char const *vendor, *version, *product; 513 char const *vendor, *version, *product;
483 int i; 514 const struct bios_settings_t *bt = NULL;
484 unsigned long prod_len = 0;
485 515
486 /* get BIOS data */ 516 /* get BIOS data */
487 vendor = dmi_get_system_info(DMI_SYS_VENDOR); 517 vendor = dmi_get_system_info(DMI_SYS_VENDOR);
@@ -503,20 +533,20 @@ static int acerhdf_check_hardware(void)
503 kernelmode = 0; 533 kernelmode = 0;
504 } 534 }
505 535
506 prod_len = strlen(product);
507
508 if (verbose) 536 if (verbose)
509 pr_info("BIOS info: %s %s, product: %s\n", 537 pr_info("BIOS info: %s %s, product: %s\n",
510 vendor, version, product); 538 vendor, version, product);
511 539
512 /* search BIOS version and vendor in BIOS settings table */ 540 /* search BIOS version and vendor in BIOS settings table */
513 for (i = 0; bios_tbl[i].version[0]; i++) { 541 for (bt = bios_tbl; bt->vendor[0]; bt++) {
514 if (strlen(bios_tbl[i].product) >= prod_len && 542 /*
515 !strncmp(bios_tbl[i].product, product, 543 * check if actual hardware BIOS vendor, product and version
516 strlen(bios_tbl[i].product)) && 544 * IDs start with the strings of BIOS table entry
517 !strcmp(bios_tbl[i].vendor, vendor) && 545 */
518 !strcmp(bios_tbl[i].version, version)) { 546 if (str_starts_with(vendor, bt->vendor) &&
519 bios_cfg = &bios_tbl[i]; 547 str_starts_with(product, bt->product) &&
548 str_starts_with(version, bt->version)) {
549 bios_cfg = bt;
520 break; 550 break;
521 } 551 }
522 } 552 }
@@ -629,9 +659,14 @@ static void __exit acerhdf_exit(void)
629MODULE_LICENSE("GPL"); 659MODULE_LICENSE("GPL");
630MODULE_AUTHOR("Peter Feuerer"); 660MODULE_AUTHOR("Peter Feuerer");
631MODULE_DESCRIPTION("Aspire One temperature and fan driver"); 661MODULE_DESCRIPTION("Aspire One temperature and fan driver");
632MODULE_ALIAS("dmi:*:*Acer*:*:"); 662MODULE_ALIAS("dmi:*:*Acer*:pnAOA*:");
633MODULE_ALIAS("dmi:*:*Gateway*:*:"); 663MODULE_ALIAS("dmi:*:*Acer*:pnAspire 1410*:");
634MODULE_ALIAS("dmi:*:*Packard Bell*:*:"); 664MODULE_ALIAS("dmi:*:*Acer*:pnAspire 1810*:");
665MODULE_ALIAS("dmi:*:*Gateway*:pnAOA*:");
666MODULE_ALIAS("dmi:*:*Gateway*:pnLT31*:");
667MODULE_ALIAS("dmi:*:*Packard Bell*:pnAOA*:");
668MODULE_ALIAS("dmi:*:*Packard Bell*:pnDOA*:");
669MODULE_ALIAS("dmi:*:*Packard Bell*:pnDOTMU*:");
635 670
636module_init(acerhdf_init); 671module_init(acerhdf_init);
637module_exit(acerhdf_exit); 672module_exit(acerhdf_exit);
diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c
index b39d2bb3e75b..efe8f6388906 100644
--- a/drivers/platform/x86/asus-laptop.c
+++ b/drivers/platform/x86/asus-laptop.c
@@ -45,58 +45,24 @@
45#include <linux/fb.h> 45#include <linux/fb.h>
46#include <linux/leds.h> 46#include <linux/leds.h>
47#include <linux/platform_device.h> 47#include <linux/platform_device.h>
48#include <linux/uaccess.h>
49#include <linux/input.h>
50#include <linux/input/sparse-keymap.h>
51#include <linux/rfkill.h>
52#include <linux/slab.h>
48#include <acpi/acpi_drivers.h> 53#include <acpi/acpi_drivers.h>
49#include <acpi/acpi_bus.h> 54#include <acpi/acpi_bus.h>
50#include <asm/uaccess.h>
51#include <linux/input.h>
52
53#define ASUS_LAPTOP_VERSION "0.42"
54
55#define ASUS_HOTK_NAME "Asus Laptop Support"
56#define ASUS_HOTK_CLASS "hotkey"
57#define ASUS_HOTK_DEVICE_NAME "Hotkey"
58#define ASUS_HOTK_FILE KBUILD_MODNAME
59#define ASUS_HOTK_PREFIX "\\_SB.ATKD."
60 55
56#define ASUS_LAPTOP_VERSION "0.42"
61 57
62/* 58#define ASUS_LAPTOP_NAME "Asus Laptop Support"
63 * Some events we use, same for all Asus 59#define ASUS_LAPTOP_CLASS "hotkey"
64 */ 60#define ASUS_LAPTOP_DEVICE_NAME "Hotkey"
65#define ATKD_BR_UP 0x10 61#define ASUS_LAPTOP_FILE KBUILD_MODNAME
66#define ATKD_BR_DOWN 0x20 62#define ASUS_LAPTOP_PREFIX "\\_SB.ATKD."
67#define ATKD_LCD_ON 0x33
68#define ATKD_LCD_OFF 0x34
69
70/*
71 * Known bits returned by \_SB.ATKD.HWRS
72 */
73#define WL_HWRS 0x80
74#define BT_HWRS 0x100
75
76/*
77 * Flags for hotk status
78 * WL_ON and BT_ON are also used for wireless_status()
79 */
80#define WL_ON 0x01 /* internal Wifi */
81#define BT_ON 0x02 /* internal Bluetooth */
82#define MLED_ON 0x04 /* mail LED */
83#define TLED_ON 0x08 /* touchpad LED */
84#define RLED_ON 0x10 /* Record LED */
85#define PLED_ON 0x20 /* Phone LED */
86#define GLED_ON 0x40 /* Gaming LED */
87#define LCD_ON 0x80 /* LCD backlight */
88#define GPS_ON 0x100 /* GPS */
89#define KEY_ON 0x200 /* Keyboard backlight */
90
91#define ASUS_LOG ASUS_HOTK_FILE ": "
92#define ASUS_ERR KERN_ERR ASUS_LOG
93#define ASUS_WARNING KERN_WARNING ASUS_LOG
94#define ASUS_NOTICE KERN_NOTICE ASUS_LOG
95#define ASUS_INFO KERN_INFO ASUS_LOG
96#define ASUS_DEBUG KERN_DEBUG ASUS_LOG
97 63
98MODULE_AUTHOR("Julien Lerouge, Karol Kozimor, Corentin Chary"); 64MODULE_AUTHOR("Julien Lerouge, Karol Kozimor, Corentin Chary");
99MODULE_DESCRIPTION(ASUS_HOTK_NAME); 65MODULE_DESCRIPTION(ASUS_LAPTOP_NAME);
100MODULE_LICENSE("GPL"); 66MODULE_LICENSE("GPL");
101 67
102/* 68/*
@@ -113,215 +79,209 @@ static uint wapf = 1;
113module_param(wapf, uint, 0644); 79module_param(wapf, uint, 0644);
114MODULE_PARM_DESC(wapf, "WAPF value"); 80MODULE_PARM_DESC(wapf, "WAPF value");
115 81
116#define ASUS_HANDLE(object, paths...) \ 82static int wlan_status = 1;
117 static acpi_handle object##_handle = NULL; \ 83static int bluetooth_status = 1;
118 static char *object##_paths[] = { paths } 84
85module_param(wlan_status, int, 0644);
86MODULE_PARM_DESC(wlan_status, "Set the wireless status on boot "
87 "(0 = disabled, 1 = enabled, -1 = don't do anything). "
88 "default is 1");
89
90module_param(bluetooth_status, int, 0644);
91MODULE_PARM_DESC(bluetooth_status, "Set the wireless status on boot "
92 "(0 = disabled, 1 = enabled, -1 = don't do anything). "
93 "default is 1");
94
95/*
96 * Some events we use, same for all Asus
97 */
98#define ATKD_BR_UP 0x10 /* (event & ~ATKD_BR_UP) = brightness level */
99#define ATKD_BR_DOWN 0x20 /* (event & ~ATKD_BR_DOWN) = britghness level */
100#define ATKD_BR_MIN ATKD_BR_UP
101#define ATKD_BR_MAX (ATKD_BR_DOWN | 0xF) /* 0x2f */
102#define ATKD_LCD_ON 0x33
103#define ATKD_LCD_OFF 0x34
104
105/*
106 * Known bits returned by \_SB.ATKD.HWRS
107 */
108#define WL_HWRS 0x80
109#define BT_HWRS 0x100
110
111/*
112 * Flags for hotk status
113 * WL_ON and BT_ON are also used for wireless_status()
114 */
115#define WL_RSTS 0x01 /* internal Wifi */
116#define BT_RSTS 0x02 /* internal Bluetooth */
119 117
120/* LED */ 118/* LED */
121ASUS_HANDLE(mled_set, ASUS_HOTK_PREFIX "MLED"); 119#define METHOD_MLED "MLED"
122ASUS_HANDLE(tled_set, ASUS_HOTK_PREFIX "TLED"); 120#define METHOD_TLED "TLED"
123ASUS_HANDLE(rled_set, ASUS_HOTK_PREFIX "RLED"); /* W1JC */ 121#define METHOD_RLED "RLED" /* W1JC */
124ASUS_HANDLE(pled_set, ASUS_HOTK_PREFIX "PLED"); /* A7J */ 122#define METHOD_PLED "PLED" /* A7J */
125ASUS_HANDLE(gled_set, ASUS_HOTK_PREFIX "GLED"); /* G1, G2 (probably) */ 123#define METHOD_GLED "GLED" /* G1, G2 (probably) */
126 124
127/* LEDD */ 125/* LEDD */
128ASUS_HANDLE(ledd_set, ASUS_HOTK_PREFIX "SLCM"); 126#define METHOD_LEDD "SLCM"
129 127
130/* 128/*
131 * Bluetooth and WLAN 129 * Bluetooth and WLAN
132 * WLED and BLED are not handled like other XLED, because in some dsdt 130 * WLED and BLED are not handled like other XLED, because in some dsdt
133 * they also control the WLAN/Bluetooth device. 131 * they also control the WLAN/Bluetooth device.
134 */ 132 */
135ASUS_HANDLE(wl_switch, ASUS_HOTK_PREFIX "WLED"); 133#define METHOD_WLAN "WLED"
136ASUS_HANDLE(bt_switch, ASUS_HOTK_PREFIX "BLED"); 134#define METHOD_BLUETOOTH "BLED"
137ASUS_HANDLE(wireless_status, ASUS_HOTK_PREFIX "RSTS"); /* All new models */ 135#define METHOD_WL_STATUS "RSTS"
138 136
139/* Brightness */ 137/* Brightness */
140ASUS_HANDLE(brightness_set, ASUS_HOTK_PREFIX "SPLV"); 138#define METHOD_BRIGHTNESS_SET "SPLV"
141ASUS_HANDLE(brightness_get, ASUS_HOTK_PREFIX "GPLV"); 139#define METHOD_BRIGHTNESS_GET "GPLV"
142 140
143/* Backlight */ 141/* Backlight */
144ASUS_HANDLE(lcd_switch, "\\_SB.PCI0.SBRG.EC0._Q10", /* All new models */ 142static acpi_handle lcd_switch_handle;
145 "\\_SB.PCI0.ISA.EC0._Q10", /* A1x */ 143static char *lcd_switch_paths[] = {
146 "\\_SB.PCI0.PX40.ECD0._Q10", /* L3C */ 144 "\\_SB.PCI0.SBRG.EC0._Q10", /* All new models */
147 "\\_SB.PCI0.PX40.EC0.Q10", /* M1A */ 145 "\\_SB.PCI0.ISA.EC0._Q10", /* A1x */
148 "\\_SB.PCI0.LPCB.EC0._Q10", /* P30 */ 146 "\\_SB.PCI0.PX40.ECD0._Q10", /* L3C */
149 "\\_SB.PCI0.LPCB.EC0._Q0E", /* P30/P35 */ 147 "\\_SB.PCI0.PX40.EC0.Q10", /* M1A */
150 "\\_SB.PCI0.PX40.Q10", /* S1x */ 148 "\\_SB.PCI0.LPCB.EC0._Q10", /* P30 */
151 "\\Q10"); /* A2x, L2D, L3D, M2E */ 149 "\\_SB.PCI0.LPCB.EC0._Q0E", /* P30/P35 */
150 "\\_SB.PCI0.PX40.Q10", /* S1x */
151 "\\Q10"}; /* A2x, L2D, L3D, M2E */
152 152
153/* Display */ 153/* Display */
154ASUS_HANDLE(display_set, ASUS_HOTK_PREFIX "SDSP"); 154#define METHOD_SWITCH_DISPLAY "SDSP"
155ASUS_HANDLE(display_get, 155
156 /* A6B, A6K A6R A7D F3JM L4R M6R A3G M6A M6V VX-1 V6J V6V W3Z */ 156static acpi_handle display_get_handle;
157 "\\_SB.PCI0.P0P1.VGA.GETD", 157static char *display_get_paths[] = {
158 /* A3E A4K, A4D A4L A6J A7J A8J Z71V M9V S5A M5A z33A W1Jc W2V G1 */ 158 /* A6B, A6K A6R A7D F3JM L4R M6R A3G M6A M6V VX-1 V6J V6V W3Z */
159 "\\_SB.PCI0.P0P2.VGA.GETD", 159 "\\_SB.PCI0.P0P1.VGA.GETD",
160 /* A6V A6Q */ 160 /* A3E A4K, A4D A4L A6J A7J A8J Z71V M9V S5A M5A z33A W1Jc W2V G1 */
161 "\\_SB.PCI0.P0P3.VGA.GETD", 161 "\\_SB.PCI0.P0P2.VGA.GETD",
162 /* A6T, A6M */ 162 /* A6V A6Q */
163 "\\_SB.PCI0.P0PA.VGA.GETD", 163 "\\_SB.PCI0.P0P3.VGA.GETD",
164 /* L3C */ 164 /* A6T, A6M */
165 "\\_SB.PCI0.PCI1.VGAC.NMAP", 165 "\\_SB.PCI0.P0PA.VGA.GETD",
166 /* Z96F */ 166 /* L3C */
167 "\\_SB.PCI0.VGA.GETD", 167 "\\_SB.PCI0.PCI1.VGAC.NMAP",
168 /* A2D */ 168 /* Z96F */
169 "\\ACTD", 169 "\\_SB.PCI0.VGA.GETD",
170 /* A4G Z71A W1N W5A W5F M2N M3N M5N M6N S1N S5N */ 170 /* A2D */
171 "\\ADVG", 171 "\\ACTD",
172 /* P30 */ 172 /* A4G Z71A W1N W5A W5F M2N M3N M5N M6N S1N S5N */
173 "\\DNXT", 173 "\\ADVG",
174 /* A2H D1 L2D L3D L3H L2E L5D L5C M1A M2E L4L W3V */ 174 /* P30 */
175 "\\INFB", 175 "\\DNXT",
176 /* A3F A6F A3N A3L M6N W3N W6A */ 176 /* A2H D1 L2D L3D L3H L2E L5D L5C M1A M2E L4L W3V */
177 "\\SSTE"); 177 "\\INFB",
178 178 /* A3F A6F A3N A3L M6N W3N W6A */
179ASUS_HANDLE(ls_switch, ASUS_HOTK_PREFIX "ALSC"); /* Z71A Z71V */ 179 "\\SSTE"};
180ASUS_HANDLE(ls_level, ASUS_HOTK_PREFIX "ALSL"); /* Z71A Z71V */ 180
181#define METHOD_ALS_CONTROL "ALSC" /* Z71A Z71V */
182#define METHOD_ALS_LEVEL "ALSL" /* Z71A Z71V */
181 183
182/* GPS */ 184/* GPS */
183/* R2H use different handle for GPS on/off */ 185/* R2H use different handle for GPS on/off */
184ASUS_HANDLE(gps_on, ASUS_HOTK_PREFIX "SDON"); /* R2H */ 186#define METHOD_GPS_ON "SDON"
185ASUS_HANDLE(gps_off, ASUS_HOTK_PREFIX "SDOF"); /* R2H */ 187#define METHOD_GPS_OFF "SDOF"
186ASUS_HANDLE(gps_status, ASUS_HOTK_PREFIX "GPST"); 188#define METHOD_GPS_STATUS "GPST"
187 189
188/* Keyboard light */ 190/* Keyboard light */
189ASUS_HANDLE(kled_set, ASUS_HOTK_PREFIX "SLKB"); 191#define METHOD_KBD_LIGHT_SET "SLKB"
190ASUS_HANDLE(kled_get, ASUS_HOTK_PREFIX "GLKB"); 192#define METHOD_KBD_LIGHT_GET "GLKB"
191 193
192/* 194/*
193 * This is the main structure, we can use it to store anything interesting 195 * Define a specific led structure to keep the main structure clean
194 * about the hotk device
195 */ 196 */
196struct asus_hotk { 197struct asus_led {
197 char *name; /* laptop name */ 198 int wk;
198 struct acpi_device *device; /* the device we are in */ 199 struct work_struct work;
199 acpi_handle handle; /* the handle of the hotk device */ 200 struct led_classdev led;
200 char status; /* status of the hotk, for LEDs, ... */ 201 struct asus_laptop *asus;
201 u32 ledd_status; /* status of the LED display */ 202 const char *method;
202 u8 light_level; /* light sensor level */
203 u8 light_switch; /* light sensor switch value */
204 u16 event_count[128]; /* count for each event TODO make this better */
205 struct input_dev *inputdev;
206 u16 *keycode_map;
207}; 203};
208 204
209/* 205/*
210 * This header is made available to allow proper configuration given model, 206 * This is the main structure, we can use it to store anything interesting
211 * revision number , ... this info cannot go in struct asus_hotk because it is 207 * about the hotk device
212 * available before the hotk
213 */
214static struct acpi_table_header *asus_info;
215
216/* The actual device the driver binds to */
217static struct asus_hotk *hotk;
218
219/*
220 * The hotkey driver declaration
221 */ 208 */
222static const struct acpi_device_id asus_device_ids[] = { 209struct asus_laptop {
223 {"ATK0100", 0}, 210 char *name; /* laptop name */
224 {"", 0},
225};
226MODULE_DEVICE_TABLE(acpi, asus_device_ids);
227 211
228static int asus_hotk_add(struct acpi_device *device); 212 struct acpi_table_header *dsdt_info;
229static int asus_hotk_remove(struct acpi_device *device, int type); 213 struct platform_device *platform_device;
230static void asus_hotk_notify(struct acpi_device *device, u32 event); 214 struct acpi_device *device; /* the device we are in */
215 struct backlight_device *backlight_device;
231 216
232static struct acpi_driver asus_hotk_driver = { 217 struct input_dev *inputdev;
233 .name = ASUS_HOTK_NAME, 218 struct key_entry *keymap;
234 .class = ASUS_HOTK_CLASS,
235 .ids = asus_device_ids,
236 .flags = ACPI_DRIVER_ALL_NOTIFY_EVENTS,
237 .ops = {
238 .add = asus_hotk_add,
239 .remove = asus_hotk_remove,
240 .notify = asus_hotk_notify,
241 },
242};
243 219
244/* The backlight device /sys/class/backlight */ 220 struct asus_led mled;
245static struct backlight_device *asus_backlight_device; 221 struct asus_led tled;
222 struct asus_led rled;
223 struct asus_led pled;
224 struct asus_led gled;
225 struct asus_led kled;
226 struct workqueue_struct *led_workqueue;
246 227
247/* 228 int wireless_status;
248 * The backlight class declaration 229 bool have_rsts;
249 */ 230 int lcd_state;
250static int read_brightness(struct backlight_device *bd);
251static int update_bl_status(struct backlight_device *bd);
252static struct backlight_ops asusbl_ops = {
253 .get_brightness = read_brightness,
254 .update_status = update_bl_status,
255};
256 231
257/* 232 struct rfkill *gps_rfkill;
258 * These functions actually update the LED's, and are called from a
259 * workqueue. By doing this as separate work rather than when the LED
260 * subsystem asks, we avoid messing with the Asus ACPI stuff during a
261 * potentially bad time, such as a timer interrupt.
262 */
263static struct workqueue_struct *led_workqueue;
264
265#define ASUS_LED(object, ledname, max) \
266 static void object##_led_set(struct led_classdev *led_cdev, \
267 enum led_brightness value); \
268 static enum led_brightness object##_led_get( \
269 struct led_classdev *led_cdev); \
270 static void object##_led_update(struct work_struct *ignored); \
271 static int object##_led_wk; \
272 static DECLARE_WORK(object##_led_work, object##_led_update); \
273 static struct led_classdev object##_led = { \
274 .name = "asus::" ledname, \
275 .brightness_set = object##_led_set, \
276 .brightness_get = object##_led_get, \
277 .max_brightness = max \
278 }
279 233
280ASUS_LED(mled, "mail", 1); 234 acpi_handle handle; /* the handle of the hotk device */
281ASUS_LED(tled, "touchpad", 1); 235 u32 ledd_status; /* status of the LED display */
282ASUS_LED(rled, "record", 1); 236 u8 light_level; /* light sensor level */
283ASUS_LED(pled, "phone", 1); 237 u8 light_switch; /* light sensor switch value */
284ASUS_LED(gled, "gaming", 1); 238 u16 event_count[128]; /* count for each event TODO make this better */
285ASUS_LED(kled, "kbd_backlight", 3); 239 u16 *keycode_map;
286
287struct key_entry {
288 char type;
289 u8 code;
290 u16 keycode;
291}; 240};
292 241
293enum { KE_KEY, KE_END }; 242static const struct key_entry asus_keymap[] = {
294 243 /* Lenovo SL Specific keycodes */
295static struct key_entry asus_keymap[] = { 244 {KE_KEY, 0x02, { KEY_SCREENLOCK } },
296 {KE_KEY, 0x30, KEY_VOLUMEUP}, 245 {KE_KEY, 0x05, { KEY_WLAN } },
297 {KE_KEY, 0x31, KEY_VOLUMEDOWN}, 246 {KE_KEY, 0x08, { KEY_F13 } },
298 {KE_KEY, 0x32, KEY_MUTE}, 247 {KE_KEY, 0x17, { KEY_ZOOM } },
299 {KE_KEY, 0x33, KEY_SWITCHVIDEOMODE}, 248 {KE_KEY, 0x1f, { KEY_BATTERY } },
300 {KE_KEY, 0x34, KEY_SWITCHVIDEOMODE}, 249 /* End of Lenovo SL Specific keycodes */
301 {KE_KEY, 0x40, KEY_PREVIOUSSONG}, 250 {KE_KEY, 0x30, { KEY_VOLUMEUP } },
302 {KE_KEY, 0x41, KEY_NEXTSONG}, 251 {KE_KEY, 0x31, { KEY_VOLUMEDOWN } },
303 {KE_KEY, 0x43, KEY_STOPCD}, 252 {KE_KEY, 0x32, { KEY_MUTE } },
304 {KE_KEY, 0x45, KEY_PLAYPAUSE}, 253 {KE_KEY, 0x33, { KEY_SWITCHVIDEOMODE } },
305 {KE_KEY, 0x4c, KEY_MEDIA}, 254 {KE_KEY, 0x34, { KEY_SWITCHVIDEOMODE } },
306 {KE_KEY, 0x50, KEY_EMAIL}, 255 {KE_KEY, 0x40, { KEY_PREVIOUSSONG } },
307 {KE_KEY, 0x51, KEY_WWW}, 256 {KE_KEY, 0x41, { KEY_NEXTSONG } },
308 {KE_KEY, 0x55, KEY_CALC}, 257 {KE_KEY, 0x43, { KEY_STOPCD } },
309 {KE_KEY, 0x5C, KEY_SCREENLOCK}, /* Screenlock */ 258 {KE_KEY, 0x45, { KEY_PLAYPAUSE } },
310 {KE_KEY, 0x5D, KEY_WLAN}, 259 {KE_KEY, 0x4c, { KEY_MEDIA } },
311 {KE_KEY, 0x5E, KEY_WLAN}, 260 {KE_KEY, 0x50, { KEY_EMAIL } },
312 {KE_KEY, 0x5F, KEY_WLAN}, 261 {KE_KEY, 0x51, { KEY_WWW } },
313 {KE_KEY, 0x60, KEY_SWITCHVIDEOMODE}, 262 {KE_KEY, 0x55, { KEY_CALC } },
314 {KE_KEY, 0x61, KEY_SWITCHVIDEOMODE}, 263 {KE_KEY, 0x5C, { KEY_SCREENLOCK } }, /* Screenlock */
315 {KE_KEY, 0x6B, BTN_TOUCH}, /* Lock Mouse */ 264 {KE_KEY, 0x5D, { KEY_WLAN } },
316 {KE_KEY, 0x82, KEY_CAMERA}, 265 {KE_KEY, 0x5E, { KEY_WLAN } },
317 {KE_KEY, 0x8A, KEY_PROG1}, 266 {KE_KEY, 0x5F, { KEY_WLAN } },
318 {KE_KEY, 0x95, KEY_MEDIA}, 267 {KE_KEY, 0x60, { KEY_SWITCHVIDEOMODE } },
319 {KE_KEY, 0x99, KEY_PHONE}, 268 {KE_KEY, 0x61, { KEY_SWITCHVIDEOMODE } },
320 {KE_KEY, 0xc4, KEY_KBDILLUMUP}, 269 {KE_KEY, 0x62, { KEY_SWITCHVIDEOMODE } },
321 {KE_KEY, 0xc5, KEY_KBDILLUMDOWN}, 270 {KE_KEY, 0x63, { KEY_SWITCHVIDEOMODE } },
271 {KE_KEY, 0x6B, { KEY_F13 } }, /* Lock Touchpad */
272 {KE_KEY, 0x7E, { KEY_BLUETOOTH } },
273 {KE_KEY, 0x7D, { KEY_BLUETOOTH } },
274 {KE_KEY, 0x82, { KEY_CAMERA } },
275 {KE_KEY, 0x88, { KEY_WLAN } },
276 {KE_KEY, 0x8A, { KEY_PROG1 } },
277 {KE_KEY, 0x95, { KEY_MEDIA } },
278 {KE_KEY, 0x99, { KEY_PHONE } },
279 {KE_KEY, 0xc4, { KEY_KBDILLUMUP } },
280 {KE_KEY, 0xc5, { KEY_KBDILLUMDOWN } },
322 {KE_END, 0}, 281 {KE_END, 0},
323}; 282};
324 283
284
325/* 285/*
326 * This function evaluates an ACPI method, given an int as parameter, the 286 * This function evaluates an ACPI method, given an int as parameter, the
327 * method is searched within the scope of the handle, can be NULL. The output 287 * method is searched within the scope of the handle, can be NULL. The output
@@ -329,8 +289,8 @@ static struct key_entry asus_keymap[] = {
329 * 289 *
330 * returns 0 if write is successful, -1 else. 290 * returns 0 if write is successful, -1 else.
331 */ 291 */
332static int write_acpi_int(acpi_handle handle, const char *method, int val, 292static int write_acpi_int_ret(acpi_handle handle, const char *method, int val,
333 struct acpi_buffer *output) 293 struct acpi_buffer *output)
334{ 294{
335 struct acpi_object_list params; /* list of input parameters (an int) */ 295 struct acpi_object_list params; /* list of input parameters (an int) */
336 union acpi_object in_obj; /* the only param we use */ 296 union acpi_object in_obj; /* the only param we use */
@@ -351,102 +311,82 @@ static int write_acpi_int(acpi_handle handle, const char *method, int val,
351 return -1; 311 return -1;
352} 312}
353 313
354static int read_wireless_status(int mask) 314static int write_acpi_int(acpi_handle handle, const char *method, int val)
355{ 315{
356 unsigned long long status; 316 return write_acpi_int_ret(handle, method, val, NULL);
357 acpi_status rv = AE_OK; 317}
358 318
359 if (!wireless_status_handle) 319static int acpi_check_handle(acpi_handle handle, const char *method,
360 return (hotk->status & mask) ? 1 : 0; 320 acpi_handle *ret)
321{
322 acpi_status status;
361 323
362 rv = acpi_evaluate_integer(wireless_status_handle, NULL, NULL, &status); 324 if (method == NULL)
363 if (ACPI_FAILURE(rv)) 325 return -ENODEV;
364 pr_warning("Error reading Wireless status\n"); 326
365 else 327 if (ret)
366 return (status & mask) ? 1 : 0; 328 status = acpi_get_handle(handle, (char *)method,
329 ret);
330 else {
331 acpi_handle dummy;
367 332
368 return (hotk->status & mask) ? 1 : 0; 333 status = acpi_get_handle(handle, (char *)method,
334 &dummy);
335 }
336
337 if (status != AE_OK) {
338 if (ret)
339 pr_warning("Error finding %s\n", method);
340 return -ENODEV;
341 }
342 return 0;
369} 343}
370 344
371static int read_gps_status(void) 345/* Generic LED function */
346static int asus_led_set(struct asus_laptop *asus, const char *method,
347 int value)
372{ 348{
373 unsigned long long status; 349 if (!strcmp(method, METHOD_MLED))
374 acpi_status rv = AE_OK; 350 value = !value;
375 351 else if (!strcmp(method, METHOD_GLED))
376 rv = acpi_evaluate_integer(gps_status_handle, NULL, NULL, &status); 352 value = !value + 1;
377 if (ACPI_FAILURE(rv))
378 pr_warning("Error reading GPS status\n");
379 else 353 else
380 return status ? 1 : 0; 354 value = !!value;
381 355
382 return (hotk->status & GPS_ON) ? 1 : 0; 356 return write_acpi_int(asus->handle, method, value);
383} 357}
384 358
385/* Generic LED functions */ 359/*
386static int read_status(int mask) 360 * LEDs
361 */
362/* /sys/class/led handlers */
363static void asus_led_cdev_set(struct led_classdev *led_cdev,
364 enum led_brightness value)
387{ 365{
388 /* There is a special method for both wireless devices */ 366 struct asus_led *led = container_of(led_cdev, struct asus_led, led);
389 if (mask == BT_ON || mask == WL_ON) 367 struct asus_laptop *asus = led->asus;
390 return read_wireless_status(mask);
391 else if (mask == GPS_ON)
392 return read_gps_status();
393 368
394 return (hotk->status & mask) ? 1 : 0; 369 led->wk = !!value;
370 queue_work(asus->led_workqueue, &led->work);
395} 371}
396 372
397static void write_status(acpi_handle handle, int out, int mask) 373static void asus_led_cdev_update(struct work_struct *work)
398{ 374{
399 hotk->status = (out) ? (hotk->status | mask) : (hotk->status & ~mask); 375 struct asus_led *led = container_of(work, struct asus_led, work);
376 struct asus_laptop *asus = led->asus;
400 377
401 switch (mask) { 378 asus_led_set(asus, led->method, led->wk);
402 case MLED_ON:
403 out = !(out & 0x1);
404 break;
405 case GLED_ON:
406 out = (out & 0x1) + 1;
407 break;
408 case GPS_ON:
409 handle = (out) ? gps_on_handle : gps_off_handle;
410 out = 0x02;
411 break;
412 default:
413 out &= 0x1;
414 break;
415 }
416
417 if (write_acpi_int(handle, NULL, out, NULL))
418 pr_warning(" write failed %x\n", mask);
419} 379}
420 380
421/* /sys/class/led handlers */ 381static enum led_brightness asus_led_cdev_get(struct led_classdev *led_cdev)
422#define ASUS_LED_HANDLER(object, mask) \ 382{
423 static void object##_led_set(struct led_classdev *led_cdev, \ 383 return led_cdev->brightness;
424 enum led_brightness value) \ 384}
425 { \
426 object##_led_wk = (value > 0) ? 1 : 0; \
427 queue_work(led_workqueue, &object##_led_work); \
428 } \
429 static void object##_led_update(struct work_struct *ignored) \
430 { \
431 int value = object##_led_wk; \
432 write_status(object##_set_handle, value, (mask)); \
433 } \
434 static enum led_brightness object##_led_get( \
435 struct led_classdev *led_cdev) \
436 { \
437 return led_cdev->brightness; \
438 }
439
440ASUS_LED_HANDLER(mled, MLED_ON);
441ASUS_LED_HANDLER(pled, PLED_ON);
442ASUS_LED_HANDLER(rled, RLED_ON);
443ASUS_LED_HANDLER(tled, TLED_ON);
444ASUS_LED_HANDLER(gled, GLED_ON);
445 385
446/* 386/*
447 * Keyboard backlight 387 * Keyboard backlight (also a LED)
448 */ 388 */
449static int get_kled_lvl(void) 389static int asus_kled_lvl(struct asus_laptop *asus)
450{ 390{
451 unsigned long long kblv; 391 unsigned long long kblv;
452 struct acpi_object_list params; 392 struct acpi_object_list params;
@@ -458,75 +398,183 @@ static int get_kled_lvl(void)
458 in_obj.type = ACPI_TYPE_INTEGER; 398 in_obj.type = ACPI_TYPE_INTEGER;
459 in_obj.integer.value = 2; 399 in_obj.integer.value = 2;
460 400
461 rv = acpi_evaluate_integer(kled_get_handle, NULL, &params, &kblv); 401 rv = acpi_evaluate_integer(asus->handle, METHOD_KBD_LIGHT_GET,
402 &params, &kblv);
462 if (ACPI_FAILURE(rv)) { 403 if (ACPI_FAILURE(rv)) {
463 pr_warning("Error reading kled level\n"); 404 pr_warning("Error reading kled level\n");
464 return 0; 405 return -ENODEV;
465 } 406 }
466 return kblv; 407 return kblv;
467} 408}
468 409
469static int set_kled_lvl(int kblv) 410static int asus_kled_set(struct asus_laptop *asus, int kblv)
470{ 411{
471 if (kblv > 0) 412 if (kblv > 0)
472 kblv = (1 << 7) | (kblv & 0x7F); 413 kblv = (1 << 7) | (kblv & 0x7F);
473 else 414 else
474 kblv = 0; 415 kblv = 0;
475 416
476 if (write_acpi_int(kled_set_handle, NULL, kblv, NULL)) { 417 if (write_acpi_int(asus->handle, METHOD_KBD_LIGHT_SET, kblv)) {
477 pr_warning("Keyboard LED display write failed\n"); 418 pr_warning("Keyboard LED display write failed\n");
478 return -EINVAL; 419 return -EINVAL;
479 } 420 }
480 return 0; 421 return 0;
481} 422}
482 423
483static void kled_led_set(struct led_classdev *led_cdev, 424static void asus_kled_cdev_set(struct led_classdev *led_cdev,
484 enum led_brightness value) 425 enum led_brightness value)
485{ 426{
486 kled_led_wk = value; 427 struct asus_led *led = container_of(led_cdev, struct asus_led, led);
487 queue_work(led_workqueue, &kled_led_work); 428 struct asus_laptop *asus = led->asus;
429
430 led->wk = value;
431 queue_work(asus->led_workqueue, &led->work);
488} 432}
489 433
490static void kled_led_update(struct work_struct *ignored) 434static void asus_kled_cdev_update(struct work_struct *work)
491{ 435{
492 set_kled_lvl(kled_led_wk); 436 struct asus_led *led = container_of(work, struct asus_led, work);
437 struct asus_laptop *asus = led->asus;
438
439 asus_kled_set(asus, led->wk);
493} 440}
494 441
495static enum led_brightness kled_led_get(struct led_classdev *led_cdev) 442static enum led_brightness asus_kled_cdev_get(struct led_classdev *led_cdev)
496{ 443{
497 return get_kled_lvl(); 444 struct asus_led *led = container_of(led_cdev, struct asus_led, led);
445 struct asus_laptop *asus = led->asus;
446
447 return asus_kled_lvl(asus);
498} 448}
499 449
500static int get_lcd_state(void) 450static void asus_led_exit(struct asus_laptop *asus)
501{ 451{
502 return read_status(LCD_ON); 452 if (asus->mled.led.dev)
453 led_classdev_unregister(&asus->mled.led);
454 if (asus->tled.led.dev)
455 led_classdev_unregister(&asus->tled.led);
456 if (asus->pled.led.dev)
457 led_classdev_unregister(&asus->pled.led);
458 if (asus->rled.led.dev)
459 led_classdev_unregister(&asus->rled.led);
460 if (asus->gled.led.dev)
461 led_classdev_unregister(&asus->gled.led);
462 if (asus->kled.led.dev)
463 led_classdev_unregister(&asus->kled.led);
464 if (asus->led_workqueue) {
465 destroy_workqueue(asus->led_workqueue);
466 asus->led_workqueue = NULL;
467 }
503} 468}
504 469
505static int set_lcd_state(int value) 470/* Ugly macro, need to fix that later */
471static int asus_led_register(struct asus_laptop *asus,
472 struct asus_led *led,
473 const char *name, const char *method)
474{
475 struct led_classdev *led_cdev = &led->led;
476
477 if (!method || acpi_check_handle(asus->handle, method, NULL))
478 return 0; /* Led not present */
479
480 led->asus = asus;
481 led->method = method;
482
483 INIT_WORK(&led->work, asus_led_cdev_update);
484 led_cdev->name = name;
485 led_cdev->brightness_set = asus_led_cdev_set;
486 led_cdev->brightness_get = asus_led_cdev_get;
487 led_cdev->max_brightness = 1;
488 return led_classdev_register(&asus->platform_device->dev, led_cdev);
489}
490
491static int asus_led_init(struct asus_laptop *asus)
492{
493 int r;
494
495 /*
496 * Functions that actually update the LED's are called from a
497 * workqueue. By doing this as separate work rather than when the LED
498 * subsystem asks, we avoid messing with the Asus ACPI stuff during a
499 * potentially bad time, such as a timer interrupt.
500 */
501 asus->led_workqueue = create_singlethread_workqueue("led_workqueue");
502 if (!asus->led_workqueue)
503 return -ENOMEM;
504
505 r = asus_led_register(asus, &asus->mled, "asus::mail", METHOD_MLED);
506 if (r)
507 goto error;
508 r = asus_led_register(asus, &asus->tled, "asus::touchpad", METHOD_TLED);
509 if (r)
510 goto error;
511 r = asus_led_register(asus, &asus->rled, "asus::record", METHOD_RLED);
512 if (r)
513 goto error;
514 r = asus_led_register(asus, &asus->pled, "asus::phone", METHOD_PLED);
515 if (r)
516 goto error;
517 r = asus_led_register(asus, &asus->gled, "asus::gaming", METHOD_GLED);
518 if (r)
519 goto error;
520 if (!acpi_check_handle(asus->handle, METHOD_KBD_LIGHT_SET, NULL) &&
521 !acpi_check_handle(asus->handle, METHOD_KBD_LIGHT_GET, NULL)) {
522 struct asus_led *led = &asus->kled;
523 struct led_classdev *cdev = &led->led;
524
525 led->asus = asus;
526
527 INIT_WORK(&led->work, asus_kled_cdev_update);
528 cdev->name = "asus::kbd_backlight";
529 cdev->brightness_set = asus_kled_cdev_set;
530 cdev->brightness_get = asus_kled_cdev_get;
531 cdev->max_brightness = 3;
532 r = led_classdev_register(&asus->platform_device->dev, cdev);
533 }
534error:
535 if (r)
536 asus_led_exit(asus);
537 return r;
538}
539
540/*
541 * Backlight device
542 */
543static int asus_lcd_status(struct asus_laptop *asus)
544{
545 return asus->lcd_state;
546}
547
548static int asus_lcd_set(struct asus_laptop *asus, int value)
506{ 549{
507 int lcd = 0; 550 int lcd = 0;
508 acpi_status status = 0; 551 acpi_status status = 0;
509 552
510 lcd = value ? 1 : 0; 553 lcd = !!value;
511 554
512 if (lcd == get_lcd_state()) 555 if (lcd == asus_lcd_status(asus))
513 return 0; 556 return 0;
514 557
515 if (lcd_switch_handle) { 558 if (!lcd_switch_handle)
516 status = acpi_evaluate_object(lcd_switch_handle, 559 return -ENODEV;
517 NULL, NULL, NULL); 560
561 status = acpi_evaluate_object(lcd_switch_handle,
562 NULL, NULL, NULL);
518 563
519 if (ACPI_FAILURE(status)) 564 if (ACPI_FAILURE(status)) {
520 pr_warning("Error switching LCD\n"); 565 pr_warning("Error switching LCD\n");
566 return -ENODEV;
521 } 567 }
522 568
523 write_status(NULL, lcd, LCD_ON); 569 asus->lcd_state = lcd;
524 return 0; 570 return 0;
525} 571}
526 572
527static void lcd_blank(int blank) 573static void lcd_blank(struct asus_laptop *asus, int blank)
528{ 574{
529 struct backlight_device *bd = asus_backlight_device; 575 struct backlight_device *bd = asus->backlight_device;
576
577 asus->lcd_state = (blank == FB_BLANK_UNBLANK);
530 578
531 if (bd) { 579 if (bd) {
532 bd->props.power = blank; 580 bd->props.power = blank;
@@ -534,44 +582,94 @@ static void lcd_blank(int blank)
534 } 582 }
535} 583}
536 584
537static int read_brightness(struct backlight_device *bd) 585static int asus_read_brightness(struct backlight_device *bd)
538{ 586{
587 struct asus_laptop *asus = bl_get_data(bd);
539 unsigned long long value; 588 unsigned long long value;
540 acpi_status rv = AE_OK; 589 acpi_status rv = AE_OK;
541 590
542 rv = acpi_evaluate_integer(brightness_get_handle, NULL, NULL, &value); 591 rv = acpi_evaluate_integer(asus->handle, METHOD_BRIGHTNESS_GET,
592 NULL, &value);
543 if (ACPI_FAILURE(rv)) 593 if (ACPI_FAILURE(rv))
544 pr_warning("Error reading brightness\n"); 594 pr_warning("Error reading brightness\n");
545 595
546 return value; 596 return value;
547} 597}
548 598
549static int set_brightness(struct backlight_device *bd, int value) 599static int asus_set_brightness(struct backlight_device *bd, int value)
550{ 600{
551 int ret = 0; 601 struct asus_laptop *asus = bl_get_data(bd);
552
553 value = (0 < value) ? ((15 < value) ? 15 : value) : 0;
554 /* 0 <= value <= 15 */
555 602
556 if (write_acpi_int(brightness_set_handle, NULL, value, NULL)) { 603 if (write_acpi_int(asus->handle, METHOD_BRIGHTNESS_SET, value)) {
557 pr_warning("Error changing brightness\n"); 604 pr_warning("Error changing brightness\n");
558 ret = -EIO; 605 return -EIO;
559 } 606 }
560 607 return 0;
561 return ret;
562} 608}
563 609
564static int update_bl_status(struct backlight_device *bd) 610static int update_bl_status(struct backlight_device *bd)
565{ 611{
612 struct asus_laptop *asus = bl_get_data(bd);
566 int rv; 613 int rv;
567 int value = bd->props.brightness; 614 int value = bd->props.brightness;
568 615
569 rv = set_brightness(bd, value); 616 rv = asus_set_brightness(bd, value);
570 if (rv) 617 if (rv)
571 return rv; 618 return rv;
572 619
573 value = (bd->props.power == FB_BLANK_UNBLANK) ? 1 : 0; 620 value = (bd->props.power == FB_BLANK_UNBLANK) ? 1 : 0;
574 return set_lcd_state(value); 621 return asus_lcd_set(asus, value);
622}
623
624static struct backlight_ops asusbl_ops = {
625 .get_brightness = asus_read_brightness,
626 .update_status = update_bl_status,
627};
628
629static int asus_backlight_notify(struct asus_laptop *asus)
630{
631 struct backlight_device *bd = asus->backlight_device;
632 int old = bd->props.brightness;
633
634 backlight_force_update(bd, BACKLIGHT_UPDATE_HOTKEY);
635
636 return old;
637}
638
639static int asus_backlight_init(struct asus_laptop *asus)
640{
641 struct backlight_device *bd;
642 struct device *dev = &asus->platform_device->dev;
643 struct backlight_properties props;
644
645 if (!acpi_check_handle(asus->handle, METHOD_BRIGHTNESS_GET, NULL) &&
646 !acpi_check_handle(asus->handle, METHOD_BRIGHTNESS_SET, NULL) &&
647 lcd_switch_handle) {
648 memset(&props, 0, sizeof(struct backlight_properties));
649 props.max_brightness = 15;
650
651 bd = backlight_device_register(ASUS_LAPTOP_FILE, dev,
652 asus, &asusbl_ops, &props);
653 if (IS_ERR(bd)) {
654 pr_err("Could not register asus backlight device\n");
655 asus->backlight_device = NULL;
656 return PTR_ERR(bd);
657 }
658
659 asus->backlight_device = bd;
660
661 bd->props.power = FB_BLANK_UNBLANK;
662 bd->props.brightness = asus_read_brightness(bd);
663 backlight_update_status(bd);
664 }
665 return 0;
666}
667
668static void asus_backlight_exit(struct asus_laptop *asus)
669{
670 if (asus->backlight_device)
671 backlight_device_unregister(asus->backlight_device);
672 asus->backlight_device = NULL;
575} 673}
576 674
577/* 675/*
@@ -586,25 +684,26 @@ static int update_bl_status(struct backlight_device *bd)
586static ssize_t show_infos(struct device *dev, 684static ssize_t show_infos(struct device *dev,
587 struct device_attribute *attr, char *page) 685 struct device_attribute *attr, char *page)
588{ 686{
687 struct asus_laptop *asus = dev_get_drvdata(dev);
589 int len = 0; 688 int len = 0;
590 unsigned long long temp; 689 unsigned long long temp;
591 char buf[16]; /* enough for all info */ 690 char buf[16]; /* enough for all info */
592 acpi_status rv = AE_OK; 691 acpi_status rv = AE_OK;
593 692
594 /* 693 /*
595 * We use the easy way, we don't care of off and count, so we don't set eof 694 * We use the easy way, we don't care of off and count,
596 * to 1 695 * so we don't set eof to 1
597 */ 696 */
598 697
599 len += sprintf(page, ASUS_HOTK_NAME " " ASUS_LAPTOP_VERSION "\n"); 698 len += sprintf(page, ASUS_LAPTOP_NAME " " ASUS_LAPTOP_VERSION "\n");
600 len += sprintf(page + len, "Model reference : %s\n", hotk->name); 699 len += sprintf(page + len, "Model reference : %s\n", asus->name);
601 /* 700 /*
602 * The SFUN method probably allows the original driver to get the list 701 * The SFUN method probably allows the original driver to get the list
603 * of features supported by a given model. For now, 0x0100 or 0x0800 702 * of features supported by a given model. For now, 0x0100 or 0x0800
604 * bit signifies that the laptop is equipped with a Wi-Fi MiniPCI card. 703 * bit signifies that the laptop is equipped with a Wi-Fi MiniPCI card.
605 * The significance of others is yet to be found. 704 * The significance of others is yet to be found.
606 */ 705 */
607 rv = acpi_evaluate_integer(hotk->handle, "SFUN", NULL, &temp); 706 rv = acpi_evaluate_integer(asus->handle, "SFUN", NULL, &temp);
608 if (!ACPI_FAILURE(rv)) 707 if (!ACPI_FAILURE(rv))
609 len += sprintf(page + len, "SFUN value : %#x\n", 708 len += sprintf(page + len, "SFUN value : %#x\n",
610 (uint) temp); 709 (uint) temp);
@@ -614,7 +713,7 @@ static ssize_t show_infos(struct device *dev,
614 * The significance of others is yet to be found. 713 * The significance of others is yet to be found.
615 * If we don't find the method, we assume the device are present. 714 * If we don't find the method, we assume the device are present.
616 */ 715 */
617 rv = acpi_evaluate_integer(hotk->handle, "HRWS", NULL, &temp); 716 rv = acpi_evaluate_integer(asus->handle, "HRWS", NULL, &temp);
618 if (!ACPI_FAILURE(rv)) 717 if (!ACPI_FAILURE(rv))
619 len += sprintf(page + len, "HRWS value : %#x\n", 718 len += sprintf(page + len, "HRWS value : %#x\n",
620 (uint) temp); 719 (uint) temp);
@@ -625,26 +724,26 @@ static ssize_t show_infos(struct device *dev,
625 * Note: since not all the laptops provide this method, errors are 724 * Note: since not all the laptops provide this method, errors are
626 * silently ignored. 725 * silently ignored.
627 */ 726 */
628 rv = acpi_evaluate_integer(hotk->handle, "ASYM", NULL, &temp); 727 rv = acpi_evaluate_integer(asus->handle, "ASYM", NULL, &temp);
629 if (!ACPI_FAILURE(rv)) 728 if (!ACPI_FAILURE(rv))
630 len += sprintf(page + len, "ASYM value : %#x\n", 729 len += sprintf(page + len, "ASYM value : %#x\n",
631 (uint) temp); 730 (uint) temp);
632 if (asus_info) { 731 if (asus->dsdt_info) {
633 snprintf(buf, 16, "%d", asus_info->length); 732 snprintf(buf, 16, "%d", asus->dsdt_info->length);
634 len += sprintf(page + len, "DSDT length : %s\n", buf); 733 len += sprintf(page + len, "DSDT length : %s\n", buf);
635 snprintf(buf, 16, "%d", asus_info->checksum); 734 snprintf(buf, 16, "%d", asus->dsdt_info->checksum);
636 len += sprintf(page + len, "DSDT checksum : %s\n", buf); 735 len += sprintf(page + len, "DSDT checksum : %s\n", buf);
637 snprintf(buf, 16, "%d", asus_info->revision); 736 snprintf(buf, 16, "%d", asus->dsdt_info->revision);
638 len += sprintf(page + len, "DSDT revision : %s\n", buf); 737 len += sprintf(page + len, "DSDT revision : %s\n", buf);
639 snprintf(buf, 7, "%s", asus_info->oem_id); 738 snprintf(buf, 7, "%s", asus->dsdt_info->oem_id);
640 len += sprintf(page + len, "OEM id : %s\n", buf); 739 len += sprintf(page + len, "OEM id : %s\n", buf);
641 snprintf(buf, 9, "%s", asus_info->oem_table_id); 740 snprintf(buf, 9, "%s", asus->dsdt_info->oem_table_id);
642 len += sprintf(page + len, "OEM table id : %s\n", buf); 741 len += sprintf(page + len, "OEM table id : %s\n", buf);
643 snprintf(buf, 16, "%x", asus_info->oem_revision); 742 snprintf(buf, 16, "%x", asus->dsdt_info->oem_revision);
644 len += sprintf(page + len, "OEM revision : 0x%s\n", buf); 743 len += sprintf(page + len, "OEM revision : 0x%s\n", buf);
645 snprintf(buf, 5, "%s", asus_info->asl_compiler_id); 744 snprintf(buf, 5, "%s", asus->dsdt_info->asl_compiler_id);
646 len += sprintf(page + len, "ASL comp vendor id : %s\n", buf); 745 len += sprintf(page + len, "ASL comp vendor id : %s\n", buf);
647 snprintf(buf, 16, "%x", asus_info->asl_compiler_revision); 746 snprintf(buf, 16, "%x", asus->dsdt_info->asl_compiler_revision);
648 len += sprintf(page + len, "ASL comp revision : 0x%s\n", buf); 747 len += sprintf(page + len, "ASL comp revision : 0x%s\n", buf);
649 } 748 }
650 749
@@ -662,8 +761,9 @@ static int parse_arg(const char *buf, unsigned long count, int *val)
662 return count; 761 return count;
663} 762}
664 763
665static ssize_t store_status(const char *buf, size_t count, 764static ssize_t sysfs_acpi_set(struct asus_laptop *asus,
666 acpi_handle handle, int mask) 765 const char *buf, size_t count,
766 const char *method)
667{ 767{
668 int rv, value; 768 int rv, value;
669 int out = 0; 769 int out = 0;
@@ -672,8 +772,8 @@ static ssize_t store_status(const char *buf, size_t count,
672 if (rv > 0) 772 if (rv > 0)
673 out = value ? 1 : 0; 773 out = value ? 1 : 0;
674 774
675 write_status(handle, out, mask); 775 if (write_acpi_int(asus->handle, method, value))
676 776 return -ENODEV;
677 return rv; 777 return rv;
678} 778}
679 779
@@ -683,67 +783,116 @@ static ssize_t store_status(const char *buf, size_t count,
683static ssize_t show_ledd(struct device *dev, 783static ssize_t show_ledd(struct device *dev,
684 struct device_attribute *attr, char *buf) 784 struct device_attribute *attr, char *buf)
685{ 785{
686 return sprintf(buf, "0x%08x\n", hotk->ledd_status); 786 struct asus_laptop *asus = dev_get_drvdata(dev);
787
788 return sprintf(buf, "0x%08x\n", asus->ledd_status);
687} 789}
688 790
689static ssize_t store_ledd(struct device *dev, struct device_attribute *attr, 791static ssize_t store_ledd(struct device *dev, struct device_attribute *attr,
690 const char *buf, size_t count) 792 const char *buf, size_t count)
691{ 793{
794 struct asus_laptop *asus = dev_get_drvdata(dev);
692 int rv, value; 795 int rv, value;
693 796
694 rv = parse_arg(buf, count, &value); 797 rv = parse_arg(buf, count, &value);
695 if (rv > 0) { 798 if (rv > 0) {
696 if (write_acpi_int(ledd_set_handle, NULL, value, NULL)) 799 if (write_acpi_int(asus->handle, METHOD_LEDD, value))
697 pr_warning("LED display write failed\n"); 800 pr_warning("LED display write failed\n");
698 else 801 else
699 hotk->ledd_status = (u32) value; 802 asus->ledd_status = (u32) value;
700 } 803 }
701 return rv; 804 return rv;
702} 805}
703 806
704/* 807/*
808 * Wireless
809 */
810static int asus_wireless_status(struct asus_laptop *asus, int mask)
811{
812 unsigned long long status;
813 acpi_status rv = AE_OK;
814
815 if (!asus->have_rsts)
816 return (asus->wireless_status & mask) ? 1 : 0;
817
818 rv = acpi_evaluate_integer(asus->handle, METHOD_WL_STATUS,
819 NULL, &status);
820 if (ACPI_FAILURE(rv)) {
821 pr_warning("Error reading Wireless status\n");
822 return -EINVAL;
823 }
824 return !!(status & mask);
825}
826
827/*
705 * WLAN 828 * WLAN
706 */ 829 */
830static int asus_wlan_set(struct asus_laptop *asus, int status)
831{
832 if (write_acpi_int(asus->handle, METHOD_WLAN, !!status)) {
833 pr_warning("Error setting wlan status to %d", status);
834 return -EIO;
835 }
836 return 0;
837}
838
707static ssize_t show_wlan(struct device *dev, 839static ssize_t show_wlan(struct device *dev,
708 struct device_attribute *attr, char *buf) 840 struct device_attribute *attr, char *buf)
709{ 841{
710 return sprintf(buf, "%d\n", read_status(WL_ON)); 842 struct asus_laptop *asus = dev_get_drvdata(dev);
843
844 return sprintf(buf, "%d\n", asus_wireless_status(asus, WL_RSTS));
711} 845}
712 846
713static ssize_t store_wlan(struct device *dev, struct device_attribute *attr, 847static ssize_t store_wlan(struct device *dev, struct device_attribute *attr,
714 const char *buf, size_t count) 848 const char *buf, size_t count)
715{ 849{
716 return store_status(buf, count, wl_switch_handle, WL_ON); 850 struct asus_laptop *asus = dev_get_drvdata(dev);
851
852 return sysfs_acpi_set(asus, buf, count, METHOD_WLAN);
717} 853}
718 854
719/* 855/*
720 * Bluetooth 856 * Bluetooth
721 */ 857 */
858static int asus_bluetooth_set(struct asus_laptop *asus, int status)
859{
860 if (write_acpi_int(asus->handle, METHOD_BLUETOOTH, !!status)) {
861 pr_warning("Error setting bluetooth status to %d", status);
862 return -EIO;
863 }
864 return 0;
865}
866
722static ssize_t show_bluetooth(struct device *dev, 867static ssize_t show_bluetooth(struct device *dev,
723 struct device_attribute *attr, char *buf) 868 struct device_attribute *attr, char *buf)
724{ 869{
725 return sprintf(buf, "%d\n", read_status(BT_ON)); 870 struct asus_laptop *asus = dev_get_drvdata(dev);
871
872 return sprintf(buf, "%d\n", asus_wireless_status(asus, BT_RSTS));
726} 873}
727 874
728static ssize_t store_bluetooth(struct device *dev, 875static ssize_t store_bluetooth(struct device *dev,
729 struct device_attribute *attr, const char *buf, 876 struct device_attribute *attr, const char *buf,
730 size_t count) 877 size_t count)
731{ 878{
732 return store_status(buf, count, bt_switch_handle, BT_ON); 879 struct asus_laptop *asus = dev_get_drvdata(dev);
880
881 return sysfs_acpi_set(asus, buf, count, METHOD_BLUETOOTH);
733} 882}
734 883
735/* 884/*
736 * Display 885 * Display
737 */ 886 */
738static void set_display(int value) 887static void asus_set_display(struct asus_laptop *asus, int value)
739{ 888{
740 /* no sanity check needed for now */ 889 /* no sanity check needed for now */
741 if (write_acpi_int(display_set_handle, NULL, value, NULL)) 890 if (write_acpi_int(asus->handle, METHOD_SWITCH_DISPLAY, value))
742 pr_warning("Error setting display\n"); 891 pr_warning("Error setting display\n");
743 return; 892 return;
744} 893}
745 894
746static int read_display(void) 895static int read_display(struct asus_laptop *asus)
747{ 896{
748 unsigned long long value = 0; 897 unsigned long long value = 0;
749 acpi_status rv = AE_OK; 898 acpi_status rv = AE_OK;
@@ -759,7 +908,7 @@ static int read_display(void)
759 pr_warning("Error reading display status\n"); 908 pr_warning("Error reading display status\n");
760 } 909 }
761 910
762 value &= 0x0F; /* needed for some models, shouldn't hurt others */ 911 value &= 0x0F; /* needed for some models, shouldn't hurt others */
763 912
764 return value; 913 return value;
765} 914}
@@ -771,7 +920,11 @@ static int read_display(void)
771static ssize_t show_disp(struct device *dev, 920static ssize_t show_disp(struct device *dev,
772 struct device_attribute *attr, char *buf) 921 struct device_attribute *attr, char *buf)
773{ 922{
774 return sprintf(buf, "%d\n", read_display()); 923 struct asus_laptop *asus = dev_get_drvdata(dev);
924
925 if (!display_get_handle)
926 return -ENODEV;
927 return sprintf(buf, "%d\n", read_display(asus));
775} 928}
776 929
777/* 930/*
@@ -784,65 +937,72 @@ static ssize_t show_disp(struct device *dev,
784static ssize_t store_disp(struct device *dev, struct device_attribute *attr, 937static ssize_t store_disp(struct device *dev, struct device_attribute *attr,
785 const char *buf, size_t count) 938 const char *buf, size_t count)
786{ 939{
940 struct asus_laptop *asus = dev_get_drvdata(dev);
787 int rv, value; 941 int rv, value;
788 942
789 rv = parse_arg(buf, count, &value); 943 rv = parse_arg(buf, count, &value);
790 if (rv > 0) 944 if (rv > 0)
791 set_display(value); 945 asus_set_display(asus, value);
792 return rv; 946 return rv;
793} 947}
794 948
795/* 949/*
796 * Light Sens 950 * Light Sens
797 */ 951 */
798static void set_light_sens_switch(int value) 952static void asus_als_switch(struct asus_laptop *asus, int value)
799{ 953{
800 if (write_acpi_int(ls_switch_handle, NULL, value, NULL)) 954 if (write_acpi_int(asus->handle, METHOD_ALS_CONTROL, value))
801 pr_warning("Error setting light sensor switch\n"); 955 pr_warning("Error setting light sensor switch\n");
802 hotk->light_switch = value; 956 asus->light_switch = value;
803} 957}
804 958
805static ssize_t show_lssw(struct device *dev, 959static ssize_t show_lssw(struct device *dev,
806 struct device_attribute *attr, char *buf) 960 struct device_attribute *attr, char *buf)
807{ 961{
808 return sprintf(buf, "%d\n", hotk->light_switch); 962 struct asus_laptop *asus = dev_get_drvdata(dev);
963
964 return sprintf(buf, "%d\n", asus->light_switch);
809} 965}
810 966
811static ssize_t store_lssw(struct device *dev, struct device_attribute *attr, 967static ssize_t store_lssw(struct device *dev, struct device_attribute *attr,
812 const char *buf, size_t count) 968 const char *buf, size_t count)
813{ 969{
970 struct asus_laptop *asus = dev_get_drvdata(dev);
814 int rv, value; 971 int rv, value;
815 972
816 rv = parse_arg(buf, count, &value); 973 rv = parse_arg(buf, count, &value);
817 if (rv > 0) 974 if (rv > 0)
818 set_light_sens_switch(value ? 1 : 0); 975 asus_als_switch(asus, value ? 1 : 0);
819 976
820 return rv; 977 return rv;
821} 978}
822 979
823static void set_light_sens_level(int value) 980static void asus_als_level(struct asus_laptop *asus, int value)
824{ 981{
825 if (write_acpi_int(ls_level_handle, NULL, value, NULL)) 982 if (write_acpi_int(asus->handle, METHOD_ALS_LEVEL, value))
826 pr_warning("Error setting light sensor level\n"); 983 pr_warning("Error setting light sensor level\n");
827 hotk->light_level = value; 984 asus->light_level = value;
828} 985}
829 986
830static ssize_t show_lslvl(struct device *dev, 987static ssize_t show_lslvl(struct device *dev,
831 struct device_attribute *attr, char *buf) 988 struct device_attribute *attr, char *buf)
832{ 989{
833 return sprintf(buf, "%d\n", hotk->light_level); 990 struct asus_laptop *asus = dev_get_drvdata(dev);
991
992 return sprintf(buf, "%d\n", asus->light_level);
834} 993}
835 994
836static ssize_t store_lslvl(struct device *dev, struct device_attribute *attr, 995static ssize_t store_lslvl(struct device *dev, struct device_attribute *attr,
837 const char *buf, size_t count) 996 const char *buf, size_t count)
838{ 997{
998 struct asus_laptop *asus = dev_get_drvdata(dev);
839 int rv, value; 999 int rv, value;
840 1000
841 rv = parse_arg(buf, count, &value); 1001 rv = parse_arg(buf, count, &value);
842 if (rv > 0) { 1002 if (rv > 0) {
843 value = (0 < value) ? ((15 < value) ? 15 : value) : 0; 1003 value = (0 < value) ? ((15 < value) ? 15 : value) : 0;
844 /* 0 <= value <= 15 */ 1004 /* 0 <= value <= 15 */
845 set_light_sens_level(value); 1005 asus_als_level(asus, value);
846 } 1006 }
847 1007
848 return rv; 1008 return rv;
@@ -851,197 +1011,309 @@ static ssize_t store_lslvl(struct device *dev, struct device_attribute *attr,
851/* 1011/*
852 * GPS 1012 * GPS
853 */ 1013 */
1014static int asus_gps_status(struct asus_laptop *asus)
1015{
1016 unsigned long long status;
1017 acpi_status rv = AE_OK;
1018
1019 rv = acpi_evaluate_integer(asus->handle, METHOD_GPS_STATUS,
1020 NULL, &status);
1021 if (ACPI_FAILURE(rv)) {
1022 pr_warning("Error reading GPS status\n");
1023 return -ENODEV;
1024 }
1025 return !!status;
1026}
1027
1028static int asus_gps_switch(struct asus_laptop *asus, int status)
1029{
1030 const char *meth = status ? METHOD_GPS_ON : METHOD_GPS_OFF;
1031
1032 if (write_acpi_int(asus->handle, meth, 0x02))
1033 return -ENODEV;
1034 return 0;
1035}
1036
854static ssize_t show_gps(struct device *dev, 1037static ssize_t show_gps(struct device *dev,
855 struct device_attribute *attr, char *buf) 1038 struct device_attribute *attr, char *buf)
856{ 1039{
857 return sprintf(buf, "%d\n", read_status(GPS_ON)); 1040 struct asus_laptop *asus = dev_get_drvdata(dev);
1041
1042 return sprintf(buf, "%d\n", asus_gps_status(asus));
858} 1043}
859 1044
860static ssize_t store_gps(struct device *dev, struct device_attribute *attr, 1045static ssize_t store_gps(struct device *dev, struct device_attribute *attr,
861 const char *buf, size_t count) 1046 const char *buf, size_t count)
862{ 1047{
863 return store_status(buf, count, NULL, GPS_ON); 1048 struct asus_laptop *asus = dev_get_drvdata(dev);
1049 int rv, value;
1050 int ret;
1051
1052 rv = parse_arg(buf, count, &value);
1053 if (rv <= 0)
1054 return -EINVAL;
1055 ret = asus_gps_switch(asus, !!value);
1056 if (ret)
1057 return ret;
1058 rfkill_set_sw_state(asus->gps_rfkill, !value);
1059 return rv;
864} 1060}
865 1061
866/* 1062/*
867 * Hotkey functions 1063 * rfkill
868 */ 1064 */
869static struct key_entry *asus_get_entry_by_scancode(int code) 1065static int asus_gps_rfkill_set(void *data, bool blocked)
870{ 1066{
871 struct key_entry *key; 1067 acpi_handle handle = data;
872
873 for (key = asus_keymap; key->type != KE_END; key++)
874 if (code == key->code)
875 return key;
876 1068
877 return NULL; 1069 return asus_gps_switch(handle, !blocked);
878} 1070}
879 1071
880static struct key_entry *asus_get_entry_by_keycode(int code) 1072static const struct rfkill_ops asus_gps_rfkill_ops = {
881{ 1073 .set_block = asus_gps_rfkill_set,
882 struct key_entry *key; 1074};
883
884 for (key = asus_keymap; key->type != KE_END; key++)
885 if (code == key->keycode && key->type == KE_KEY)
886 return key;
887 1075
888 return NULL; 1076static void asus_rfkill_exit(struct asus_laptop *asus)
1077{
1078 if (asus->gps_rfkill) {
1079 rfkill_unregister(asus->gps_rfkill);
1080 rfkill_destroy(asus->gps_rfkill);
1081 asus->gps_rfkill = NULL;
1082 }
889} 1083}
890 1084
891static int asus_getkeycode(struct input_dev *dev, int scancode, int *keycode) 1085static int asus_rfkill_init(struct asus_laptop *asus)
892{ 1086{
893 struct key_entry *key = asus_get_entry_by_scancode(scancode); 1087 int result;
894 1088
895 if (key && key->type == KE_KEY) { 1089 if (acpi_check_handle(asus->handle, METHOD_GPS_ON, NULL) ||
896 *keycode = key->keycode; 1090 acpi_check_handle(asus->handle, METHOD_GPS_OFF, NULL) ||
1091 acpi_check_handle(asus->handle, METHOD_GPS_STATUS, NULL))
897 return 0; 1092 return 0;
1093
1094 asus->gps_rfkill = rfkill_alloc("asus-gps", &asus->platform_device->dev,
1095 RFKILL_TYPE_GPS,
1096 &asus_gps_rfkill_ops, NULL);
1097 if (!asus->gps_rfkill)
1098 return -EINVAL;
1099
1100 result = rfkill_register(asus->gps_rfkill);
1101 if (result) {
1102 rfkill_destroy(asus->gps_rfkill);
1103 asus->gps_rfkill = NULL;
898 } 1104 }
899 1105
900 return -EINVAL; 1106 return result;
901} 1107}
902 1108
903static int asus_setkeycode(struct input_dev *dev, int scancode, int keycode) 1109/*
1110 * Input device (i.e. hotkeys)
1111 */
1112static void asus_input_notify(struct asus_laptop *asus, int event)
904{ 1113{
905 struct key_entry *key; 1114 if (asus->inputdev)
906 int old_keycode; 1115 sparse_keymap_report_event(asus->inputdev, event, 1, true);
1116}
907 1117
908 if (keycode < 0 || keycode > KEY_MAX) 1118static int asus_input_init(struct asus_laptop *asus)
909 return -EINVAL; 1119{
1120 struct input_dev *input;
1121 int error;
910 1122
911 key = asus_get_entry_by_scancode(scancode); 1123 input = input_allocate_device();
912 if (key && key->type == KE_KEY) { 1124 if (!input) {
913 old_keycode = key->keycode; 1125 pr_info("Unable to allocate input device\n");
914 key->keycode = keycode;
915 set_bit(keycode, dev->keybit);
916 if (!asus_get_entry_by_keycode(old_keycode))
917 clear_bit(old_keycode, dev->keybit);
918 return 0; 1126 return 0;
919 } 1127 }
1128 input->name = "Asus Laptop extra buttons";
1129 input->phys = ASUS_LAPTOP_FILE "/input0";
1130 input->id.bustype = BUS_HOST;
1131 input->dev.parent = &asus->platform_device->dev;
1132 input_set_drvdata(input, asus);
1133
1134 error = sparse_keymap_setup(input, asus_keymap, NULL);
1135 if (error) {
1136 pr_err("Unable to setup input device keymap\n");
1137 goto err_keymap;
1138 }
1139 error = input_register_device(input);
1140 if (error) {
1141 pr_info("Unable to register input device\n");
1142 goto err_device;
1143 }
920 1144
921 return -EINVAL; 1145 asus->inputdev = input;
1146 return 0;
1147
1148err_keymap:
1149 sparse_keymap_free(input);
1150err_device:
1151 input_free_device(input);
1152 return error;
922} 1153}
923 1154
924static void asus_hotk_notify(struct acpi_device *device, u32 event) 1155static void asus_input_exit(struct asus_laptop *asus)
925{ 1156{
926 static struct key_entry *key; 1157 if (asus->inputdev) {
927 u16 count; 1158 sparse_keymap_free(asus->inputdev);
1159 input_unregister_device(asus->inputdev);
1160 }
1161}
928 1162
929 /* TODO Find a better way to handle events count. */ 1163/*
930 if (!hotk) 1164 * ACPI driver
931 return; 1165 */
1166static void asus_acpi_notify(struct acpi_device *device, u32 event)
1167{
1168 struct asus_laptop *asus = acpi_driver_data(device);
1169 u16 count;
932 1170
933 /* 1171 /*
934 * We need to tell the backlight device when the backlight power is 1172 * We need to tell the backlight device when the backlight power is
935 * switched 1173 * switched
936 */ 1174 */
937 if (event == ATKD_LCD_ON) { 1175 if (event == ATKD_LCD_ON)
938 write_status(NULL, 1, LCD_ON); 1176 lcd_blank(asus, FB_BLANK_UNBLANK);
939 lcd_blank(FB_BLANK_UNBLANK); 1177 else if (event == ATKD_LCD_OFF)
940 } else if (event == ATKD_LCD_OFF) { 1178 lcd_blank(asus, FB_BLANK_POWERDOWN);
941 write_status(NULL, 0, LCD_ON);
942 lcd_blank(FB_BLANK_POWERDOWN);
943 }
944 1179
945 count = hotk->event_count[event % 128]++; 1180 /* TODO Find a better way to handle events count. */
946 acpi_bus_generate_proc_event(hotk->device, event, count); 1181 count = asus->event_count[event % 128]++;
947 acpi_bus_generate_netlink_event(hotk->device->pnp.device_class, 1182 acpi_bus_generate_proc_event(asus->device, event, count);
948 dev_name(&hotk->device->dev), event, 1183 acpi_bus_generate_netlink_event(asus->device->pnp.device_class,
1184 dev_name(&asus->device->dev), event,
949 count); 1185 count);
950 1186
951 if (hotk->inputdev) { 1187 /* Brightness events are special */
952 key = asus_get_entry_by_scancode(event); 1188 if (event >= ATKD_BR_MIN && event <= ATKD_BR_MAX) {
953 if (!key) 1189
954 return ; 1190 /* Ignore them completely if the acpi video driver is used */
955 1191 if (asus->backlight_device != NULL) {
956 switch (key->type) { 1192 /* Update the backlight device. */
957 case KE_KEY: 1193 asus_backlight_notify(asus);
958 input_report_key(hotk->inputdev, key->keycode, 1);
959 input_sync(hotk->inputdev);
960 input_report_key(hotk->inputdev, key->keycode, 0);
961 input_sync(hotk->inputdev);
962 break;
963 } 1194 }
1195 return ;
964 } 1196 }
1197 asus_input_notify(asus, event);
965} 1198}
966 1199
967#define ASUS_CREATE_DEVICE_ATTR(_name) \ 1200static DEVICE_ATTR(infos, S_IRUGO, show_infos, NULL);
968 struct device_attribute dev_attr_##_name = { \ 1201static DEVICE_ATTR(wlan, S_IRUGO | S_IWUSR, show_wlan, store_wlan);
969 .attr = { \ 1202static DEVICE_ATTR(bluetooth, S_IRUGO | S_IWUSR, show_bluetooth,
970 .name = __stringify(_name), \ 1203 store_bluetooth);
971 .mode = 0 }, \ 1204static DEVICE_ATTR(display, S_IRUGO | S_IWUSR, show_disp, store_disp);
972 .show = NULL, \ 1205static DEVICE_ATTR(ledd, S_IRUGO | S_IWUSR, show_ledd, store_ledd);
973 .store = NULL, \ 1206static DEVICE_ATTR(ls_level, S_IRUGO | S_IWUSR, show_lslvl, store_lslvl);
1207static DEVICE_ATTR(ls_switch, S_IRUGO | S_IWUSR, show_lssw, store_lssw);
1208static DEVICE_ATTR(gps, S_IRUGO | S_IWUSR, show_gps, store_gps);
1209
1210static void asus_sysfs_exit(struct asus_laptop *asus)
1211{
1212 struct platform_device *device = asus->platform_device;
1213
1214 device_remove_file(&device->dev, &dev_attr_infos);
1215 device_remove_file(&device->dev, &dev_attr_wlan);
1216 device_remove_file(&device->dev, &dev_attr_bluetooth);
1217 device_remove_file(&device->dev, &dev_attr_display);
1218 device_remove_file(&device->dev, &dev_attr_ledd);
1219 device_remove_file(&device->dev, &dev_attr_ls_switch);
1220 device_remove_file(&device->dev, &dev_attr_ls_level);
1221 device_remove_file(&device->dev, &dev_attr_gps);
1222}
1223
1224static int asus_sysfs_init(struct asus_laptop *asus)
1225{
1226 struct platform_device *device = asus->platform_device;
1227 int err;
1228
1229 err = device_create_file(&device->dev, &dev_attr_infos);
1230 if (err)
1231 return err;
1232
1233 if (!acpi_check_handle(asus->handle, METHOD_WLAN, NULL)) {
1234 err = device_create_file(&device->dev, &dev_attr_wlan);
1235 if (err)
1236 return err;
974 } 1237 }
975 1238
976#define ASUS_SET_DEVICE_ATTR(_name, _mode, _show, _store) \ 1239 if (!acpi_check_handle(asus->handle, METHOD_BLUETOOTH, NULL)) {
977 do { \ 1240 err = device_create_file(&device->dev, &dev_attr_bluetooth);
978 dev_attr_##_name.attr.mode = _mode; \ 1241 if (err)
979 dev_attr_##_name.show = _show; \ 1242 return err;
980 dev_attr_##_name.store = _store; \ 1243 }
981 } while(0)
982
983static ASUS_CREATE_DEVICE_ATTR(infos);
984static ASUS_CREATE_DEVICE_ATTR(wlan);
985static ASUS_CREATE_DEVICE_ATTR(bluetooth);
986static ASUS_CREATE_DEVICE_ATTR(display);
987static ASUS_CREATE_DEVICE_ATTR(ledd);
988static ASUS_CREATE_DEVICE_ATTR(ls_switch);
989static ASUS_CREATE_DEVICE_ATTR(ls_level);
990static ASUS_CREATE_DEVICE_ATTR(gps);
991
992static struct attribute *asuspf_attributes[] = {
993 &dev_attr_infos.attr,
994 &dev_attr_wlan.attr,
995 &dev_attr_bluetooth.attr,
996 &dev_attr_display.attr,
997 &dev_attr_ledd.attr,
998 &dev_attr_ls_switch.attr,
999 &dev_attr_ls_level.attr,
1000 &dev_attr_gps.attr,
1001 NULL
1002};
1003 1244
1004static struct attribute_group asuspf_attribute_group = { 1245 if (!acpi_check_handle(asus->handle, METHOD_SWITCH_DISPLAY, NULL)) {
1005 .attrs = asuspf_attributes 1246 err = device_create_file(&device->dev, &dev_attr_display);
1006}; 1247 if (err)
1248 return err;
1249 }
1007 1250
1008static struct platform_driver asuspf_driver = { 1251 if (!acpi_check_handle(asus->handle, METHOD_LEDD, NULL)) {
1009 .driver = { 1252 err = device_create_file(&device->dev, &dev_attr_ledd);
1010 .name = ASUS_HOTK_FILE, 1253 if (err)
1011 .owner = THIS_MODULE, 1254 return err;
1012 } 1255 }
1013};
1014 1256
1015static struct platform_device *asuspf_device; 1257 if (!acpi_check_handle(asus->handle, METHOD_ALS_CONTROL, NULL) &&
1258 !acpi_check_handle(asus->handle, METHOD_ALS_LEVEL, NULL)) {
1259 err = device_create_file(&device->dev, &dev_attr_ls_switch);
1260 if (err)
1261 return err;
1262 err = device_create_file(&device->dev, &dev_attr_ls_level);
1263 if (err)
1264 return err;
1265 }
1016 1266
1017static void asus_hotk_add_fs(void) 1267 if (!acpi_check_handle(asus->handle, METHOD_GPS_ON, NULL) &&
1018{ 1268 !acpi_check_handle(asus->handle, METHOD_GPS_OFF, NULL) &&
1019 ASUS_SET_DEVICE_ATTR(infos, 0444, show_infos, NULL); 1269 !acpi_check_handle(asus->handle, METHOD_GPS_STATUS, NULL)) {
1270 err = device_create_file(&device->dev, &dev_attr_gps);
1271 if (err)
1272 return err;
1273 }
1020 1274
1021 if (wl_switch_handle) 1275 return err;
1022 ASUS_SET_DEVICE_ATTR(wlan, 0644, show_wlan, store_wlan); 1276}
1023 1277
1024 if (bt_switch_handle) 1278static int asus_platform_init(struct asus_laptop *asus)
1025 ASUS_SET_DEVICE_ATTR(bluetooth, 0644, 1279{
1026 show_bluetooth, store_bluetooth); 1280 int err;
1027 1281
1028 if (display_set_handle && display_get_handle) 1282 asus->platform_device = platform_device_alloc(ASUS_LAPTOP_FILE, -1);
1029 ASUS_SET_DEVICE_ATTR(display, 0644, show_disp, store_disp); 1283 if (!asus->platform_device)
1030 else if (display_set_handle) 1284 return -ENOMEM;
1031 ASUS_SET_DEVICE_ATTR(display, 0200, NULL, store_disp); 1285 platform_set_drvdata(asus->platform_device, asus);
1032 1286
1033 if (ledd_set_handle) 1287 err = platform_device_add(asus->platform_device);
1034 ASUS_SET_DEVICE_ATTR(ledd, 0644, show_ledd, store_ledd); 1288 if (err)
1289 goto fail_platform_device;
1035 1290
1036 if (ls_switch_handle && ls_level_handle) { 1291 err = asus_sysfs_init(asus);
1037 ASUS_SET_DEVICE_ATTR(ls_level, 0644, show_lslvl, store_lslvl); 1292 if (err)
1038 ASUS_SET_DEVICE_ATTR(ls_switch, 0644, show_lssw, store_lssw); 1293 goto fail_sysfs;
1039 } 1294 return 0;
1040 1295
1041 if (gps_status_handle && gps_on_handle && gps_off_handle) 1296fail_sysfs:
1042 ASUS_SET_DEVICE_ATTR(gps, 0644, show_gps, store_gps); 1297 asus_sysfs_exit(asus);
1298 platform_device_del(asus->platform_device);
1299fail_platform_device:
1300 platform_device_put(asus->platform_device);
1301 return err;
1302}
1303
1304static void asus_platform_exit(struct asus_laptop *asus)
1305{
1306 asus_sysfs_exit(asus);
1307 platform_device_unregister(asus->platform_device);
1043} 1308}
1044 1309
1310static struct platform_driver platform_driver = {
1311 .driver = {
1312 .name = ASUS_LAPTOP_FILE,
1313 .owner = THIS_MODULE,
1314 }
1315};
1316
1045static int asus_handle_init(char *name, acpi_handle * handle, 1317static int asus_handle_init(char *name, acpi_handle * handle,
1046 char **paths, int num_paths) 1318 char **paths, int num_paths)
1047{ 1319{
@@ -1063,10 +1335,11 @@ static int asus_handle_init(char *name, acpi_handle * handle,
1063 ARRAY_SIZE(object##_paths)) 1335 ARRAY_SIZE(object##_paths))
1064 1336
1065/* 1337/*
1066 * This function is used to initialize the hotk with right values. In this 1338 * This function is used to initialize the context with right values. In this
1067 * method, we can make all the detection we want, and modify the hotk struct 1339 * method, we can make all the detection we want, and modify the asus_laptop
1340 * struct
1068 */ 1341 */
1069static int asus_hotk_get_info(void) 1342static int asus_laptop_get_info(struct asus_laptop *asus)
1070{ 1343{
1071 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; 1344 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
1072 union acpi_object *model = NULL; 1345 union acpi_object *model = NULL;
@@ -1079,22 +1352,21 @@ static int asus_hotk_get_info(void)
1079 * models, but late enough to allow acpi_bus_register_driver() to fail 1352 * models, but late enough to allow acpi_bus_register_driver() to fail
1080 * before doing anything ACPI-specific. Should we encounter a machine, 1353 * before doing anything ACPI-specific. Should we encounter a machine,
1081 * which needs special handling (i.e. its hotkey device has a different 1354 * which needs special handling (i.e. its hotkey device has a different
1082 * HID), this bit will be moved. A global variable asus_info contains 1355 * HID), this bit will be moved.
1083 * the DSDT header.
1084 */ 1356 */
1085 status = acpi_get_table(ACPI_SIG_DSDT, 1, &asus_info); 1357 status = acpi_get_table(ACPI_SIG_DSDT, 1, &asus->dsdt_info);
1086 if (ACPI_FAILURE(status)) 1358 if (ACPI_FAILURE(status))
1087 pr_warning("Couldn't get the DSDT table header\n"); 1359 pr_warning("Couldn't get the DSDT table header\n");
1088 1360
1089 /* We have to write 0 on init this far for all ASUS models */ 1361 /* We have to write 0 on init this far for all ASUS models */
1090 if (write_acpi_int(hotk->handle, "INIT", 0, &buffer)) { 1362 if (write_acpi_int_ret(asus->handle, "INIT", 0, &buffer)) {
1091 pr_err("Hotkey initialization failed\n"); 1363 pr_err("Hotkey initialization failed\n");
1092 return -ENODEV; 1364 return -ENODEV;
1093 } 1365 }
1094 1366
1095 /* This needs to be called for some laptops to init properly */ 1367 /* This needs to be called for some laptops to init properly */
1096 status = 1368 status =
1097 acpi_evaluate_integer(hotk->handle, "BSTS", NULL, &bsts_result); 1369 acpi_evaluate_integer(asus->handle, "BSTS", NULL, &bsts_result);
1098 if (ACPI_FAILURE(status)) 1370 if (ACPI_FAILURE(status))
1099 pr_warning("Error calling BSTS\n"); 1371 pr_warning("Error calling BSTS\n");
1100 else if (bsts_result) 1372 else if (bsts_result)
@@ -1102,8 +1374,8 @@ static int asus_hotk_get_info(void)
1102 (uint) bsts_result); 1374 (uint) bsts_result);
1103 1375
1104 /* This too ... */ 1376 /* This too ... */
1105 write_acpi_int(hotk->handle, "CWAP", wapf, NULL); 1377 if (write_acpi_int(asus->handle, "CWAP", wapf))
1106 1378 pr_err("Error calling CWAP(%d)\n", wapf);
1107 /* 1379 /*
1108 * Try to match the object returned by INIT to the specific model. 1380 * Try to match the object returned by INIT to the specific model.
1109 * Handle every possible object (or the lack of thereof) the DSDT 1381 * Handle every possible object (or the lack of thereof) the DSDT
@@ -1124,406 +1396,210 @@ static int asus_hotk_get_info(void)
1124 break; 1396 break;
1125 } 1397 }
1126 } 1398 }
1127 hotk->name = kstrdup(string, GFP_KERNEL); 1399 asus->name = kstrdup(string, GFP_KERNEL);
1128 if (!hotk->name) 1400 if (!asus->name)
1129 return -ENOMEM; 1401 return -ENOMEM;
1130 1402
1131 if (*string) 1403 if (*string)
1132 pr_notice(" %s model detected\n", string); 1404 pr_notice(" %s model detected\n", string);
1133 1405
1134 ASUS_HANDLE_INIT(mled_set);
1135 ASUS_HANDLE_INIT(tled_set);
1136 ASUS_HANDLE_INIT(rled_set);
1137 ASUS_HANDLE_INIT(pled_set);
1138 ASUS_HANDLE_INIT(gled_set);
1139
1140 ASUS_HANDLE_INIT(ledd_set);
1141
1142 ASUS_HANDLE_INIT(kled_set);
1143 ASUS_HANDLE_INIT(kled_get);
1144
1145 /* 1406 /*
1146 * The HWRS method return informations about the hardware. 1407 * The HWRS method return informations about the hardware.
1147 * 0x80 bit is for WLAN, 0x100 for Bluetooth. 1408 * 0x80 bit is for WLAN, 0x100 for Bluetooth.
1148 * The significance of others is yet to be found. 1409 * The significance of others is yet to be found.
1149 * If we don't find the method, we assume the device are present.
1150 */ 1410 */
1151 status = 1411 status =
1152 acpi_evaluate_integer(hotk->handle, "HRWS", NULL, &hwrs_result); 1412 acpi_evaluate_integer(asus->handle, "HRWS", NULL, &hwrs_result);
1153 if (ACPI_FAILURE(status)) 1413 if (!ACPI_FAILURE(status))
1154 hwrs_result = WL_HWRS | BT_HWRS; 1414 pr_notice(" HRWS returned %x", (int)hwrs_result);
1155
1156 if (hwrs_result & WL_HWRS)
1157 ASUS_HANDLE_INIT(wl_switch);
1158 if (hwrs_result & BT_HWRS)
1159 ASUS_HANDLE_INIT(bt_switch);
1160 1415
1161 ASUS_HANDLE_INIT(wireless_status); 1416 if (!acpi_check_handle(asus->handle, METHOD_WL_STATUS, NULL))
1162 1417 asus->have_rsts = true;
1163 ASUS_HANDLE_INIT(brightness_set);
1164 ASUS_HANDLE_INIT(brightness_get);
1165 1418
1419 /* Scheduled for removal */
1166 ASUS_HANDLE_INIT(lcd_switch); 1420 ASUS_HANDLE_INIT(lcd_switch);
1167
1168 ASUS_HANDLE_INIT(display_set);
1169 ASUS_HANDLE_INIT(display_get); 1421 ASUS_HANDLE_INIT(display_get);
1170 1422
1171 /*
1172 * There is a lot of models with "ALSL", but a few get
1173 * a real light sens, so we need to check it.
1174 */
1175 if (!ASUS_HANDLE_INIT(ls_switch))
1176 ASUS_HANDLE_INIT(ls_level);
1177
1178 ASUS_HANDLE_INIT(gps_on);
1179 ASUS_HANDLE_INIT(gps_off);
1180 ASUS_HANDLE_INIT(gps_status);
1181
1182 kfree(model); 1423 kfree(model);
1183 1424
1184 return AE_OK; 1425 return AE_OK;
1185} 1426}
1186 1427
1187static int asus_input_init(void) 1428static bool asus_device_present;
1188{
1189 const struct key_entry *key;
1190 int result;
1191
1192 hotk->inputdev = input_allocate_device();
1193 if (!hotk->inputdev) {
1194 pr_info("Unable to allocate input device\n");
1195 return 0;
1196 }
1197 hotk->inputdev->name = "Asus Laptop extra buttons";
1198 hotk->inputdev->phys = ASUS_HOTK_FILE "/input0";
1199 hotk->inputdev->id.bustype = BUS_HOST;
1200 hotk->inputdev->getkeycode = asus_getkeycode;
1201 hotk->inputdev->setkeycode = asus_setkeycode;
1202
1203 for (key = asus_keymap; key->type != KE_END; key++) {
1204 switch (key->type) {
1205 case KE_KEY:
1206 set_bit(EV_KEY, hotk->inputdev->evbit);
1207 set_bit(key->keycode, hotk->inputdev->keybit);
1208 break;
1209 }
1210 }
1211 result = input_register_device(hotk->inputdev);
1212 if (result) {
1213 pr_info("Unable to register input device\n");
1214 input_free_device(hotk->inputdev);
1215 }
1216 return result;
1217}
1218 1429
1219static int asus_hotk_check(void) 1430static int __devinit asus_acpi_init(struct asus_laptop *asus)
1220{ 1431{
1221 int result = 0; 1432 int result = 0;
1222 1433
1223 result = acpi_bus_get_status(hotk->device); 1434 result = acpi_bus_get_status(asus->device);
1224 if (result) 1435 if (result)
1225 return result; 1436 return result;
1226 1437 if (!asus->device->status.present) {
1227 if (hotk->device->status.present) {
1228 result = asus_hotk_get_info();
1229 } else {
1230 pr_err("Hotkey device not present, aborting\n"); 1438 pr_err("Hotkey device not present, aborting\n");
1231 return -EINVAL; 1439 return -ENODEV;
1232 } 1440 }
1233 1441
1234 return result; 1442 result = asus_laptop_get_info(asus);
1235}
1236
1237static int asus_hotk_found;
1238
1239static int asus_hotk_add(struct acpi_device *device)
1240{
1241 int result;
1242
1243 if (!device)
1244 return -EINVAL;
1245
1246 pr_notice("Asus Laptop Support version %s\n",
1247 ASUS_LAPTOP_VERSION);
1248
1249 hotk = kzalloc(sizeof(struct asus_hotk), GFP_KERNEL);
1250 if (!hotk)
1251 return -ENOMEM;
1252
1253 hotk->handle = device->handle;
1254 strcpy(acpi_device_name(device), ASUS_HOTK_DEVICE_NAME);
1255 strcpy(acpi_device_class(device), ASUS_HOTK_CLASS);
1256 device->driver_data = hotk;
1257 hotk->device = device;
1258
1259 result = asus_hotk_check();
1260 if (result) 1443 if (result)
1261 goto end; 1444 return result;
1262
1263 asus_hotk_add_fs();
1264
1265 asus_hotk_found = 1;
1266 1445
1267 /* WLED and BLED are on by default */ 1446 /* WLED and BLED are on by default */
1268 write_status(bt_switch_handle, 1, BT_ON); 1447 if (bluetooth_status >= 0)
1269 write_status(wl_switch_handle, 1, WL_ON); 1448 asus_bluetooth_set(asus, !!bluetooth_status);
1270
1271 /* If the h/w switch is off, we need to check the real status */
1272 write_status(NULL, read_status(BT_ON), BT_ON);
1273 write_status(NULL, read_status(WL_ON), WL_ON);
1274 1449
1275 /* LCD Backlight is on by default */ 1450 if (wlan_status >= 0)
1276 write_status(NULL, 1, LCD_ON); 1451 asus_wlan_set(asus, !!wlan_status);
1277 1452
1278 /* Keyboard Backlight is on by default */ 1453 /* Keyboard Backlight is on by default */
1279 if (kled_set_handle) 1454 if (!acpi_check_handle(asus->handle, METHOD_KBD_LIGHT_SET, NULL))
1280 set_kled_lvl(1); 1455 asus_kled_set(asus, 1);
1281 1456
1282 /* LED display is off by default */ 1457 /* LED display is off by default */
1283 hotk->ledd_status = 0xFFF; 1458 asus->ledd_status = 0xFFF;
1284 1459
1285 /* Set initial values of light sensor and level */ 1460 /* Set initial values of light sensor and level */
1286 hotk->light_switch = 1; /* Default to light sensor disabled */ 1461 asus->light_switch = 0; /* Default to light sensor disabled */
1287 hotk->light_level = 0; /* level 5 for sensor sensitivity */ 1462 asus->light_level = 5; /* level 5 for sensor sensitivity */
1288
1289 if (ls_switch_handle)
1290 set_light_sens_switch(hotk->light_switch);
1291 1463
1292 if (ls_level_handle) 1464 if (!acpi_check_handle(asus->handle, METHOD_ALS_CONTROL, NULL) &&
1293 set_light_sens_level(hotk->light_level); 1465 !acpi_check_handle(asus->handle, METHOD_ALS_LEVEL, NULL)) {
1294 1466 asus_als_switch(asus, asus->light_switch);
1295 /* GPS is on by default */ 1467 asus_als_level(asus, asus->light_level);
1296 write_status(NULL, 1, GPS_ON);
1297
1298end:
1299 if (result) {
1300 kfree(hotk->name);
1301 kfree(hotk);
1302 } 1468 }
1303 1469
1470 asus->lcd_state = 1; /* LCD should be on when the module load */
1304 return result; 1471 return result;
1305} 1472}
1306 1473
1307static int asus_hotk_remove(struct acpi_device *device, int type) 1474static int __devinit asus_acpi_add(struct acpi_device *device)
1308{ 1475{
1309 if (!device || !acpi_driver_data(device)) 1476 struct asus_laptop *asus;
1310 return -EINVAL; 1477 int result;
1311
1312 kfree(hotk->name);
1313 kfree(hotk);
1314
1315 return 0;
1316}
1317
1318static void asus_backlight_exit(void)
1319{
1320 if (asus_backlight_device)
1321 backlight_device_unregister(asus_backlight_device);
1322}
1323
1324#define ASUS_LED_UNREGISTER(object) \
1325 if (object##_led.dev) \
1326 led_classdev_unregister(&object##_led)
1327 1478
1328static void asus_led_exit(void) 1479 pr_notice("Asus Laptop Support version %s\n",
1329{ 1480 ASUS_LAPTOP_VERSION);
1330 destroy_workqueue(led_workqueue); 1481 asus = kzalloc(sizeof(struct asus_laptop), GFP_KERNEL);
1331 ASUS_LED_UNREGISTER(mled); 1482 if (!asus)
1332 ASUS_LED_UNREGISTER(tled); 1483 return -ENOMEM;
1333 ASUS_LED_UNREGISTER(pled); 1484 asus->handle = device->handle;
1334 ASUS_LED_UNREGISTER(rled); 1485 strcpy(acpi_device_name(device), ASUS_LAPTOP_DEVICE_NAME);
1335 ASUS_LED_UNREGISTER(gled); 1486 strcpy(acpi_device_class(device), ASUS_LAPTOP_CLASS);
1336 ASUS_LED_UNREGISTER(kled); 1487 device->driver_data = asus;
1337} 1488 asus->device = device;
1338 1489
1339static void asus_input_exit(void) 1490 result = asus_acpi_init(asus);
1340{ 1491 if (result)
1341 if (hotk->inputdev) 1492 goto fail_platform;
1342 input_unregister_device(hotk->inputdev);
1343}
1344 1493
1345static void __exit asus_laptop_exit(void) 1494 /*
1346{ 1495 * Register the platform device first. It is used as a parent for the
1347 asus_backlight_exit(); 1496 * sub-devices below.
1348 asus_led_exit(); 1497 */
1349 asus_input_exit(); 1498 result = asus_platform_init(asus);
1499 if (result)
1500 goto fail_platform;
1350 1501
1351 acpi_bus_unregister_driver(&asus_hotk_driver); 1502 if (!acpi_video_backlight_support()) {
1352 sysfs_remove_group(&asuspf_device->dev.kobj, &asuspf_attribute_group); 1503 result = asus_backlight_init(asus);
1353 platform_device_unregister(asuspf_device); 1504 if (result)
1354 platform_driver_unregister(&asuspf_driver); 1505 goto fail_backlight;
1355} 1506 } else
1507 pr_info("Backlight controlled by ACPI video driver\n");
1356 1508
1357static int asus_backlight_init(struct device *dev) 1509 result = asus_input_init(asus);
1358{ 1510 if (result)
1359 struct backlight_device *bd; 1511 goto fail_input;
1360 1512
1361 if (brightness_set_handle && lcd_switch_handle) { 1513 result = asus_led_init(asus);
1362 bd = backlight_device_register(ASUS_HOTK_FILE, dev, 1514 if (result)
1363 NULL, &asusbl_ops); 1515 goto fail_led;
1364 if (IS_ERR(bd)) {
1365 pr_err("Could not register asus backlight device\n");
1366 asus_backlight_device = NULL;
1367 return PTR_ERR(bd);
1368 }
1369 1516
1370 asus_backlight_device = bd; 1517 result = asus_rfkill_init(asus);
1518 if (result)
1519 goto fail_rfkill;
1371 1520
1372 bd->props.max_brightness = 15; 1521 asus_device_present = true;
1373 bd->props.brightness = read_brightness(NULL);
1374 bd->props.power = FB_BLANK_UNBLANK;
1375 backlight_update_status(bd);
1376 }
1377 return 0; 1522 return 0;
1378}
1379 1523
1380static int asus_led_register(acpi_handle handle, 1524fail_rfkill:
1381 struct led_classdev *ldev, struct device *dev) 1525 asus_led_exit(asus);
1382{ 1526fail_led:
1383 if (!handle) 1527 asus_input_exit(asus);
1384 return 0; 1528fail_input:
1529 asus_backlight_exit(asus);
1530fail_backlight:
1531 asus_platform_exit(asus);
1532fail_platform:
1533 kfree(asus->name);
1534 kfree(asus);
1385 1535
1386 return led_classdev_register(dev, ldev); 1536 return result;
1387} 1537}
1388 1538
1389#define ASUS_LED_REGISTER(object, device) \ 1539static int asus_acpi_remove(struct acpi_device *device, int type)
1390 asus_led_register(object##_set_handle, &object##_led, device)
1391
1392static int asus_led_init(struct device *dev)
1393{ 1540{
1394 int rv; 1541 struct asus_laptop *asus = acpi_driver_data(device);
1395
1396 rv = ASUS_LED_REGISTER(mled, dev);
1397 if (rv)
1398 goto out;
1399
1400 rv = ASUS_LED_REGISTER(tled, dev);
1401 if (rv)
1402 goto out1;
1403
1404 rv = ASUS_LED_REGISTER(rled, dev);
1405 if (rv)
1406 goto out2;
1407
1408 rv = ASUS_LED_REGISTER(pled, dev);
1409 if (rv)
1410 goto out3;
1411
1412 rv = ASUS_LED_REGISTER(gled, dev);
1413 if (rv)
1414 goto out4;
1415 1542
1416 if (kled_set_handle && kled_get_handle) 1543 asus_backlight_exit(asus);
1417 rv = ASUS_LED_REGISTER(kled, dev); 1544 asus_rfkill_exit(asus);
1418 if (rv) 1545 asus_led_exit(asus);
1419 goto out5; 1546 asus_input_exit(asus);
1420 1547 asus_platform_exit(asus);
1421 led_workqueue = create_singlethread_workqueue("led_workqueue");
1422 if (!led_workqueue)
1423 goto out6;
1424 1548
1549 kfree(asus->name);
1550 kfree(asus);
1425 return 0; 1551 return 0;
1426out6:
1427 rv = -ENOMEM;
1428 ASUS_LED_UNREGISTER(kled);
1429out5:
1430 ASUS_LED_UNREGISTER(gled);
1431out4:
1432 ASUS_LED_UNREGISTER(pled);
1433out3:
1434 ASUS_LED_UNREGISTER(rled);
1435out2:
1436 ASUS_LED_UNREGISTER(tled);
1437out1:
1438 ASUS_LED_UNREGISTER(mled);
1439out:
1440 return rv;
1441} 1552}
1442 1553
1554static const struct acpi_device_id asus_device_ids[] = {
1555 {"ATK0100", 0},
1556 {"ATK0101", 0},
1557 {"", 0},
1558};
1559MODULE_DEVICE_TABLE(acpi, asus_device_ids);
1560
1561static struct acpi_driver asus_acpi_driver = {
1562 .name = ASUS_LAPTOP_NAME,
1563 .class = ASUS_LAPTOP_CLASS,
1564 .owner = THIS_MODULE,
1565 .ids = asus_device_ids,
1566 .flags = ACPI_DRIVER_ALL_NOTIFY_EVENTS,
1567 .ops = {
1568 .add = asus_acpi_add,
1569 .remove = asus_acpi_remove,
1570 .notify = asus_acpi_notify,
1571 },
1572};
1573
1443static int __init asus_laptop_init(void) 1574static int __init asus_laptop_init(void)
1444{ 1575{
1445 int result; 1576 int result;
1446 1577
1447 if (acpi_disabled) 1578 result = platform_driver_register(&platform_driver);
1448 return -ENODEV;
1449
1450 result = acpi_bus_register_driver(&asus_hotk_driver);
1451 if (result < 0) 1579 if (result < 0)
1452 return result; 1580 return result;
1453 1581
1454 /* 1582 result = acpi_bus_register_driver(&asus_acpi_driver);
1455 * This is a bit of a kludge. We only want this module loaded 1583 if (result < 0)
1456 * for ASUS systems, but there's currently no way to probe the 1584 goto fail_acpi_driver;
1457 * ACPI namespace for ASUS HIDs. So we just return failure if 1585 if (!asus_device_present) {
1458 * we didn't find one, which will cause the module to be 1586 result = -ENODEV;
1459 * unloaded. 1587 goto fail_no_device;
1460 */
1461 if (!asus_hotk_found) {
1462 acpi_bus_unregister_driver(&asus_hotk_driver);
1463 return -ENODEV;
1464 }
1465
1466 result = asus_input_init();
1467 if (result)
1468 goto fail_input;
1469
1470 /* Register platform stuff */
1471 result = platform_driver_register(&asuspf_driver);
1472 if (result)
1473 goto fail_platform_driver;
1474
1475 asuspf_device = platform_device_alloc(ASUS_HOTK_FILE, -1);
1476 if (!asuspf_device) {
1477 result = -ENOMEM;
1478 goto fail_platform_device1;
1479 } 1588 }
1480
1481 result = platform_device_add(asuspf_device);
1482 if (result)
1483 goto fail_platform_device2;
1484
1485 result = sysfs_create_group(&asuspf_device->dev.kobj,
1486 &asuspf_attribute_group);
1487 if (result)
1488 goto fail_sysfs;
1489
1490 result = asus_led_init(&asuspf_device->dev);
1491 if (result)
1492 goto fail_led;
1493
1494 if (!acpi_video_backlight_support()) {
1495 result = asus_backlight_init(&asuspf_device->dev);
1496 if (result)
1497 goto fail_backlight;
1498 } else
1499 pr_info("Brightness ignored, must be controlled by "
1500 "ACPI video driver\n");
1501
1502 return 0; 1589 return 0;
1503 1590
1504fail_backlight: 1591fail_no_device:
1505 asus_led_exit(); 1592 acpi_bus_unregister_driver(&asus_acpi_driver);
1506 1593fail_acpi_driver:
1507fail_led: 1594 platform_driver_unregister(&platform_driver);
1508 sysfs_remove_group(&asuspf_device->dev.kobj,
1509 &asuspf_attribute_group);
1510
1511fail_sysfs:
1512 platform_device_del(asuspf_device);
1513
1514fail_platform_device2:
1515 platform_device_put(asuspf_device);
1516
1517fail_platform_device1:
1518 platform_driver_unregister(&asuspf_driver);
1519
1520fail_platform_driver:
1521 asus_input_exit();
1522
1523fail_input:
1524
1525 return result; 1595 return result;
1526} 1596}
1527 1597
1598static void __exit asus_laptop_exit(void)
1599{
1600 acpi_bus_unregister_driver(&asus_acpi_driver);
1601 platform_driver_unregister(&platform_driver);
1602}
1603
1528module_init(asus_laptop_init); 1604module_init(asus_laptop_init);
1529module_exit(asus_laptop_exit); 1605module_exit(asus_laptop_exit);
diff --git a/drivers/platform/x86/asus_acpi.c b/drivers/platform/x86/asus_acpi.c
index ddf5240ade8c..92fd30c9379c 100644
--- a/drivers/platform/x86/asus_acpi.c
+++ b/drivers/platform/x86/asus_acpi.c
@@ -32,9 +32,11 @@
32 32
33#include <linux/kernel.h> 33#include <linux/kernel.h>
34#include <linux/module.h> 34#include <linux/module.h>
35#include <linux/slab.h>
35#include <linux/init.h> 36#include <linux/init.h>
36#include <linux/types.h> 37#include <linux/types.h>
37#include <linux/proc_fs.h> 38#include <linux/proc_fs.h>
39#include <linux/seq_file.h>
38#include <linux/backlight.h> 40#include <linux/backlight.h>
39#include <acpi/acpi_drivers.h> 41#include <acpi/acpi_drivers.h>
40#include <acpi/acpi_bus.h> 42#include <acpi/acpi_bus.h>
@@ -466,6 +468,7 @@ MODULE_DEVICE_TABLE(acpi, asus_device_ids);
466static struct acpi_driver asus_hotk_driver = { 468static struct acpi_driver asus_hotk_driver = {
467 .name = "asus_acpi", 469 .name = "asus_acpi",
468 .class = ACPI_HOTK_CLASS, 470 .class = ACPI_HOTK_CLASS,
471 .owner = THIS_MODULE,
469 .ids = asus_device_ids, 472 .ids = asus_device_ids,
470 .flags = ACPI_DRIVER_ALL_NOTIFY_EVENTS, 473 .flags = ACPI_DRIVER_ALL_NOTIFY_EVENTS,
471 .ops = { 474 .ops = {
@@ -512,26 +515,12 @@ static int read_acpi_int(acpi_handle handle, const char *method, int *val)
512 return (status == AE_OK) && (out_obj.type == ACPI_TYPE_INTEGER); 515 return (status == AE_OK) && (out_obj.type == ACPI_TYPE_INTEGER);
513} 516}
514 517
515/* 518static int asus_info_proc_show(struct seq_file *m, void *v)
516 * We write our info in page, we begin at offset off and cannot write more
517 * than count bytes. We set eof to 1 if we handle those 2 values. We return the
518 * number of bytes written in page
519 */
520static int
521proc_read_info(char *page, char **start, off_t off, int count, int *eof,
522 void *data)
523{ 519{
524 int len = 0;
525 int temp; 520 int temp;
526 char buf[16]; /* enough for all info */
527 /*
528 * We use the easy way, we don't care of off and count,
529 * so we don't set eof to 1
530 */
531 521
532 len += sprintf(page, ACPI_HOTK_NAME " " ASUS_ACPI_VERSION "\n"); 522 seq_printf(m, ACPI_HOTK_NAME " " ASUS_ACPI_VERSION "\n");
533 len += sprintf(page + len, "Model reference : %s\n", 523 seq_printf(m, "Model reference : %s\n", hotk->methods->name);
534 hotk->methods->name);
535 /* 524 /*
536 * The SFUN method probably allows the original driver to get the list 525 * The SFUN method probably allows the original driver to get the list
537 * of features supported by a given model. For now, 0x0100 or 0x0800 526 * of features supported by a given model. For now, 0x0100 or 0x0800
@@ -539,8 +528,7 @@ proc_read_info(char *page, char **start, off_t off, int count, int *eof,
539 * The significance of others is yet to be found. 528 * The significance of others is yet to be found.
540 */ 529 */
541 if (read_acpi_int(hotk->handle, "SFUN", &temp)) 530 if (read_acpi_int(hotk->handle, "SFUN", &temp))
542 len += 531 seq_printf(m, "SFUN value : 0x%04x\n", temp);
543 sprintf(page + len, "SFUN value : 0x%04x\n", temp);
544 /* 532 /*
545 * Another value for userspace: the ASYM method returns 0x02 for 533 * Another value for userspace: the ASYM method returns 0x02 for
546 * battery low and 0x04 for battery critical, its readings tend to be 534 * battery low and 0x04 for battery critical, its readings tend to be
@@ -549,30 +537,34 @@ proc_read_info(char *page, char **start, off_t off, int count, int *eof,
549 * silently ignored. 537 * silently ignored.
550 */ 538 */
551 if (read_acpi_int(hotk->handle, "ASYM", &temp)) 539 if (read_acpi_int(hotk->handle, "ASYM", &temp))
552 len += 540 seq_printf(m, "ASYM value : 0x%04x\n", temp);
553 sprintf(page + len, "ASYM value : 0x%04x\n", temp);
554 if (asus_info) { 541 if (asus_info) {
555 snprintf(buf, 16, "%d", asus_info->length); 542 seq_printf(m, "DSDT length : %d\n", asus_info->length);
556 len += sprintf(page + len, "DSDT length : %s\n", buf); 543 seq_printf(m, "DSDT checksum : %d\n", asus_info->checksum);
557 snprintf(buf, 16, "%d", asus_info->checksum); 544 seq_printf(m, "DSDT revision : %d\n", asus_info->revision);
558 len += sprintf(page + len, "DSDT checksum : %s\n", buf); 545 seq_printf(m, "OEM id : %.*s\n", ACPI_OEM_ID_SIZE, asus_info->oem_id);
559 snprintf(buf, 16, "%d", asus_info->revision); 546 seq_printf(m, "OEM table id : %.*s\n", ACPI_OEM_TABLE_ID_SIZE, asus_info->oem_table_id);
560 len += sprintf(page + len, "DSDT revision : %s\n", buf); 547 seq_printf(m, "OEM revision : 0x%x\n", asus_info->oem_revision);
561 snprintf(buf, 7, "%s", asus_info->oem_id); 548 seq_printf(m, "ASL comp vendor id : %.*s\n", ACPI_NAME_SIZE, asus_info->asl_compiler_id);
562 len += sprintf(page + len, "OEM id : %s\n", buf); 549 seq_printf(m, "ASL comp revision : 0x%x\n", asus_info->asl_compiler_revision);
563 snprintf(buf, 9, "%s", asus_info->oem_table_id);
564 len += sprintf(page + len, "OEM table id : %s\n", buf);
565 snprintf(buf, 16, "%x", asus_info->oem_revision);
566 len += sprintf(page + len, "OEM revision : 0x%s\n", buf);
567 snprintf(buf, 5, "%s", asus_info->asl_compiler_id);
568 len += sprintf(page + len, "ASL comp vendor id : %s\n", buf);
569 snprintf(buf, 16, "%x", asus_info->asl_compiler_revision);
570 len += sprintf(page + len, "ASL comp revision : 0x%s\n", buf);
571 } 550 }
572 551
573 return len; 552 return 0;
553}
554
555static int asus_info_proc_open(struct inode *inode, struct file *file)
556{
557 return single_open(file, asus_info_proc_show, NULL);
574} 558}
575 559
560static const struct file_operations asus_info_proc_fops = {
561 .owner = THIS_MODULE,
562 .open = asus_info_proc_open,
563 .read = seq_read,
564 .llseek = seq_lseek,
565 .release = single_release,
566};
567
576/* 568/*
577 * /proc handlers 569 * /proc handlers
578 * We write our info in page, we begin at offset off and cannot write more 570 * We write our info in page, we begin at offset off and cannot write more
@@ -638,34 +630,48 @@ write_led(const char __user *buffer, unsigned long count,
638/* 630/*
639 * Proc handlers for MLED 631 * Proc handlers for MLED
640 */ 632 */
641static int 633static int mled_proc_show(struct seq_file *m, void *v)
642proc_read_mled(char *page, char **start, off_t off, int count, int *eof,
643 void *data)
644{ 634{
645 return sprintf(page, "%d\n", 635 seq_printf(m, "%d\n", read_led(hotk->methods->mled_status, MLED_ON));
646 read_led(hotk->methods->mled_status, MLED_ON)); 636 return 0;
647} 637}
648 638
649static int 639static int mled_proc_open(struct inode *inode, struct file *file)
650proc_write_mled(struct file *file, const char __user *buffer, 640{
651 unsigned long count, void *data) 641 return single_open(file, mled_proc_show, NULL);
642}
643
644static ssize_t mled_proc_write(struct file *file, const char __user *buffer,
645 size_t count, loff_t *pos)
652{ 646{
653 return write_led(buffer, count, hotk->methods->mt_mled, MLED_ON, 1); 647 return write_led(buffer, count, hotk->methods->mt_mled, MLED_ON, 1);
654} 648}
655 649
650static const struct file_operations mled_proc_fops = {
651 .owner = THIS_MODULE,
652 .open = mled_proc_open,
653 .read = seq_read,
654 .llseek = seq_lseek,
655 .release = single_release,
656 .write = mled_proc_write,
657};
658
656/* 659/*
657 * Proc handlers for LED display 660 * Proc handlers for LED display
658 */ 661 */
659static int 662static int ledd_proc_show(struct seq_file *m, void *v)
660proc_read_ledd(char *page, char **start, off_t off, int count, int *eof,
661 void *data)
662{ 663{
663 return sprintf(page, "0x%08x\n", hotk->ledd_status); 664 seq_printf(m, "0x%08x\n", hotk->ledd_status);
665 return 0;
664} 666}
665 667
666static int 668static int ledd_proc_open(struct inode *inode, struct file *file)
667proc_write_ledd(struct file *file, const char __user *buffer, 669{
668 unsigned long count, void *data) 670 return single_open(file, ledd_proc_show, NULL);
671}
672
673static ssize_t ledd_proc_write(struct file *file, const char __user *buffer,
674 size_t count, loff_t *pos)
669{ 675{
670 int rv, value; 676 int rv, value;
671 677
@@ -681,61 +687,104 @@ proc_write_ledd(struct file *file, const char __user *buffer,
681 return rv; 687 return rv;
682} 688}
683 689
690static const struct file_operations ledd_proc_fops = {
691 .owner = THIS_MODULE,
692 .open = ledd_proc_open,
693 .read = seq_read,
694 .llseek = seq_lseek,
695 .release = single_release,
696 .write = ledd_proc_write,
697};
698
684/* 699/*
685 * Proc handlers for WLED 700 * Proc handlers for WLED
686 */ 701 */
687static int 702static int wled_proc_show(struct seq_file *m, void *v)
688proc_read_wled(char *page, char **start, off_t off, int count, int *eof,
689 void *data)
690{ 703{
691 return sprintf(page, "%d\n", 704 seq_printf(m, "%d\n", read_led(hotk->methods->wled_status, WLED_ON));
692 read_led(hotk->methods->wled_status, WLED_ON)); 705 return 0;
693} 706}
694 707
695static int 708static int wled_proc_open(struct inode *inode, struct file *file)
696proc_write_wled(struct file *file, const char __user *buffer, 709{
697 unsigned long count, void *data) 710 return single_open(file, wled_proc_show, NULL);
711}
712
713static ssize_t wled_proc_write(struct file *file, const char __user *buffer,
714 size_t count, loff_t *pos)
698{ 715{
699 return write_led(buffer, count, hotk->methods->mt_wled, WLED_ON, 0); 716 return write_led(buffer, count, hotk->methods->mt_wled, WLED_ON, 0);
700} 717}
701 718
719static const struct file_operations wled_proc_fops = {
720 .owner = THIS_MODULE,
721 .open = wled_proc_open,
722 .read = seq_read,
723 .llseek = seq_lseek,
724 .release = single_release,
725 .write = wled_proc_write,
726};
727
702/* 728/*
703 * Proc handlers for Bluetooth 729 * Proc handlers for Bluetooth
704 */ 730 */
705static int 731static int bluetooth_proc_show(struct seq_file *m, void *v)
706proc_read_bluetooth(char *page, char **start, off_t off, int count, int *eof,
707 void *data)
708{ 732{
709 return sprintf(page, "%d\n", read_led(hotk->methods->bt_status, BT_ON)); 733 seq_printf(m, "%d\n", read_led(hotk->methods->bt_status, BT_ON));
734 return 0;
710} 735}
711 736
712static int 737static int bluetooth_proc_open(struct inode *inode, struct file *file)
713proc_write_bluetooth(struct file *file, const char __user *buffer, 738{
714 unsigned long count, void *data) 739 return single_open(file, bluetooth_proc_show, NULL);
740}
741
742static ssize_t bluetooth_proc_write(struct file *file,
743 const char __user *buffer, size_t count, loff_t *pos)
715{ 744{
716 /* Note: mt_bt_switch controls both internal Bluetooth adapter's 745 /* Note: mt_bt_switch controls both internal Bluetooth adapter's
717 presence and its LED */ 746 presence and its LED */
718 return write_led(buffer, count, hotk->methods->mt_bt_switch, BT_ON, 0); 747 return write_led(buffer, count, hotk->methods->mt_bt_switch, BT_ON, 0);
719} 748}
720 749
750static const struct file_operations bluetooth_proc_fops = {
751 .owner = THIS_MODULE,
752 .open = bluetooth_proc_open,
753 .read = seq_read,
754 .llseek = seq_lseek,
755 .release = single_release,
756 .write = bluetooth_proc_write,
757};
758
721/* 759/*
722 * Proc handlers for TLED 760 * Proc handlers for TLED
723 */ 761 */
724static int 762static int tled_proc_show(struct seq_file *m, void *v)
725proc_read_tled(char *page, char **start, off_t off, int count, int *eof,
726 void *data)
727{ 763{
728 return sprintf(page, "%d\n", 764 seq_printf(m, "%d\n", read_led(hotk->methods->tled_status, TLED_ON));
729 read_led(hotk->methods->tled_status, TLED_ON)); 765 return 0;
730} 766}
731 767
732static int 768static int tled_proc_open(struct inode *inode, struct file *file)
733proc_write_tled(struct file *file, const char __user *buffer, 769{
734 unsigned long count, void *data) 770 return single_open(file, tled_proc_show, NULL);
771}
772
773static ssize_t tled_proc_write(struct file *file, const char __user *buffer,
774 size_t count, loff_t *pos)
735{ 775{
736 return write_led(buffer, count, hotk->methods->mt_tled, TLED_ON, 0); 776 return write_led(buffer, count, hotk->methods->mt_tled, TLED_ON, 0);
737} 777}
738 778
779static const struct file_operations tled_proc_fops = {
780 .owner = THIS_MODULE,
781 .open = tled_proc_open,
782 .read = seq_read,
783 .llseek = seq_lseek,
784 .release = single_release,
785 .write = tled_proc_write,
786};
787
739static int get_lcd_state(void) 788static int get_lcd_state(void)
740{ 789{
741 int lcd = 0; 790 int lcd = 0;
@@ -828,16 +877,19 @@ static int set_lcd_state(int value)
828 877
829} 878}
830 879
831static int 880static int lcd_proc_show(struct seq_file *m, void *v)
832proc_read_lcd(char *page, char **start, off_t off, int count, int *eof,
833 void *data)
834{ 881{
835 return sprintf(page, "%d\n", get_lcd_state()); 882 seq_printf(m, "%d\n", get_lcd_state());
883 return 0;
836} 884}
837 885
838static int 886static int lcd_proc_open(struct inode *inode, struct file *file)
839proc_write_lcd(struct file *file, const char __user *buffer, 887{
840 unsigned long count, void *data) 888 return single_open(file, lcd_proc_show, NULL);
889}
890
891static ssize_t lcd_proc_write(struct file *file, const char __user *buffer,
892 size_t count, loff_t *pos)
841{ 893{
842 int rv, value; 894 int rv, value;
843 895
@@ -847,6 +899,15 @@ proc_write_lcd(struct file *file, const char __user *buffer,
847 return rv; 899 return rv;
848} 900}
849 901
902static const struct file_operations lcd_proc_fops = {
903 .owner = THIS_MODULE,
904 .open = lcd_proc_open,
905 .read = seq_read,
906 .llseek = seq_lseek,
907 .release = single_release,
908 .write = lcd_proc_write,
909};
910
850static int read_brightness(struct backlight_device *bd) 911static int read_brightness(struct backlight_device *bd)
851{ 912{
852 int value; 913 int value;
@@ -906,16 +967,19 @@ static int set_brightness_status(struct backlight_device *bd)
906 return set_brightness(bd->props.brightness); 967 return set_brightness(bd->props.brightness);
907} 968}
908 969
909static int 970static int brn_proc_show(struct seq_file *m, void *v)
910proc_read_brn(char *page, char **start, off_t off, int count, int *eof,
911 void *data)
912{ 971{
913 return sprintf(page, "%d\n", read_brightness(NULL)); 972 seq_printf(m, "%d\n", read_brightness(NULL));
973 return 0;
914} 974}
915 975
916static int 976static int brn_proc_open(struct inode *inode, struct file *file)
917proc_write_brn(struct file *file, const char __user *buffer, 977{
918 unsigned long count, void *data) 978 return single_open(file, brn_proc_show, NULL);
979}
980
981static ssize_t brn_proc_write(struct file *file, const char __user *buffer,
982 size_t count, loff_t *pos)
919{ 983{
920 int rv, value; 984 int rv, value;
921 985
@@ -928,6 +992,15 @@ proc_write_brn(struct file *file, const char __user *buffer,
928 return rv; 992 return rv;
929} 993}
930 994
995static const struct file_operations brn_proc_fops = {
996 .owner = THIS_MODULE,
997 .open = brn_proc_open,
998 .read = seq_read,
999 .llseek = seq_lseek,
1000 .release = single_release,
1001 .write = brn_proc_write,
1002};
1003
931static void set_display(int value) 1004static void set_display(int value)
932{ 1005{
933 /* no sanity check needed for now */ 1006 /* no sanity check needed for now */
@@ -941,9 +1014,7 @@ static void set_display(int value)
941 * Now, *this* one could be more user-friendly, but so far, no-one has 1014 * Now, *this* one could be more user-friendly, but so far, no-one has
942 * complained. The significance of bits is the same as in proc_write_disp() 1015 * complained. The significance of bits is the same as in proc_write_disp()
943 */ 1016 */
944static int 1017static int disp_proc_show(struct seq_file *m, void *v)
945proc_read_disp(char *page, char **start, off_t off, int count, int *eof,
946 void *data)
947{ 1018{
948 int value = 0; 1019 int value = 0;
949 1020
@@ -951,7 +1022,13 @@ proc_read_disp(char *page, char **start, off_t off, int count, int *eof,
951 printk(KERN_WARNING 1022 printk(KERN_WARNING
952 "Asus ACPI: Error reading display status\n"); 1023 "Asus ACPI: Error reading display status\n");
953 value &= 0x07; /* needed for some models, shouldn't hurt others */ 1024 value &= 0x07; /* needed for some models, shouldn't hurt others */
954 return sprintf(page, "%d\n", value); 1025 seq_printf(m, "%d\n", value);
1026 return 0;
1027}
1028
1029static int disp_proc_open(struct inode *inode, struct file *file)
1030{
1031 return single_open(file, disp_proc_show, NULL);
955} 1032}
956 1033
957/* 1034/*
@@ -960,9 +1037,8 @@ proc_read_disp(char *page, char **start, off_t off, int count, int *eof,
960 * (bitwise) of these will suffice. I never actually tested 3 displays hooked 1037 * (bitwise) of these will suffice. I never actually tested 3 displays hooked
961 * up simultaneously, so be warned. See the acpi4asus README for more info. 1038 * up simultaneously, so be warned. See the acpi4asus README for more info.
962 */ 1039 */
963static int 1040static ssize_t disp_proc_write(struct file *file, const char __user *buffer,
964proc_write_disp(struct file *file, const char __user *buffer, 1041 size_t count, loff_t *pos)
965 unsigned long count, void *data)
966{ 1042{
967 int rv, value; 1043 int rv, value;
968 1044
@@ -972,25 +1048,27 @@ proc_write_disp(struct file *file, const char __user *buffer,
972 return rv; 1048 return rv;
973} 1049}
974 1050
975typedef int (proc_readfunc) (char *page, char **start, off_t off, int count, 1051static const struct file_operations disp_proc_fops = {
976 int *eof, void *data); 1052 .owner = THIS_MODULE,
977typedef int (proc_writefunc) (struct file *file, const char __user *buffer, 1053 .open = disp_proc_open,
978 unsigned long count, void *data); 1054 .read = seq_read,
1055 .llseek = seq_lseek,
1056 .release = single_release,
1057 .write = disp_proc_write,
1058};
979 1059
980static int 1060static int
981asus_proc_add(char *name, proc_writefunc *writefunc, 1061asus_proc_add(char *name, const struct file_operations *proc_fops, mode_t mode,
982 proc_readfunc *readfunc, mode_t mode,
983 struct acpi_device *device) 1062 struct acpi_device *device)
984{ 1063{
985 struct proc_dir_entry *proc = 1064 struct proc_dir_entry *proc;
986 create_proc_entry(name, mode, acpi_device_dir(device)); 1065
1066 proc = proc_create_data(name, mode, acpi_device_dir(device),
1067 proc_fops, acpi_driver_data(device));
987 if (!proc) { 1068 if (!proc) {
988 printk(KERN_WARNING " Unable to create %s fs entry\n", name); 1069 printk(KERN_WARNING " Unable to create %s fs entry\n", name);
989 return -1; 1070 return -1;
990 } 1071 }
991 proc->write_proc = writefunc;
992 proc->read_proc = readfunc;
993 proc->data = acpi_driver_data(device);
994 proc->uid = asus_uid; 1072 proc->uid = asus_uid;
995 proc->gid = asus_gid; 1073 proc->gid = asus_gid;
996 return 0; 1074 return 0;
@@ -1019,10 +1097,9 @@ static int asus_hotk_add_fs(struct acpi_device *device)
1019 if (!acpi_device_dir(device)) 1097 if (!acpi_device_dir(device))
1020 return -ENODEV; 1098 return -ENODEV;
1021 1099
1022 proc = create_proc_entry(PROC_INFO, mode, acpi_device_dir(device)); 1100 proc = proc_create(PROC_INFO, mode, acpi_device_dir(device),
1101 &asus_info_proc_fops);
1023 if (proc) { 1102 if (proc) {
1024 proc->read_proc = proc_read_info;
1025 proc->data = acpi_driver_data(device);
1026 proc->uid = asus_uid; 1103 proc->uid = asus_uid;
1027 proc->gid = asus_gid; 1104 proc->gid = asus_gid;
1028 } else { 1105 } else {
@@ -1031,28 +1108,23 @@ static int asus_hotk_add_fs(struct acpi_device *device)
1031 } 1108 }
1032 1109
1033 if (hotk->methods->mt_wled) { 1110 if (hotk->methods->mt_wled) {
1034 asus_proc_add(PROC_WLED, &proc_write_wled, &proc_read_wled, 1111 asus_proc_add(PROC_WLED, &wled_proc_fops, mode, device);
1035 mode, device);
1036 } 1112 }
1037 1113
1038 if (hotk->methods->mt_ledd) { 1114 if (hotk->methods->mt_ledd) {
1039 asus_proc_add(PROC_LEDD, &proc_write_ledd, &proc_read_ledd, 1115 asus_proc_add(PROC_LEDD, &ledd_proc_fops, mode, device);
1040 mode, device);
1041 } 1116 }
1042 1117
1043 if (hotk->methods->mt_mled) { 1118 if (hotk->methods->mt_mled) {
1044 asus_proc_add(PROC_MLED, &proc_write_mled, &proc_read_mled, 1119 asus_proc_add(PROC_MLED, &mled_proc_fops, mode, device);
1045 mode, device);
1046 } 1120 }
1047 1121
1048 if (hotk->methods->mt_tled) { 1122 if (hotk->methods->mt_tled) {
1049 asus_proc_add(PROC_TLED, &proc_write_tled, &proc_read_tled, 1123 asus_proc_add(PROC_TLED, &tled_proc_fops, mode, device);
1050 mode, device);
1051 } 1124 }
1052 1125
1053 if (hotk->methods->mt_bt_switch) { 1126 if (hotk->methods->mt_bt_switch) {
1054 asus_proc_add(PROC_BT, &proc_write_bluetooth, 1127 asus_proc_add(PROC_BT, &bluetooth_proc_fops, mode, device);
1055 &proc_read_bluetooth, mode, device);
1056 } 1128 }
1057 1129
1058 /* 1130 /*
@@ -1060,19 +1132,16 @@ static int asus_hotk_add_fs(struct acpi_device *device)
1060 * accessible from the keyboard 1132 * accessible from the keyboard
1061 */ 1133 */
1062 if (hotk->methods->mt_lcd_switch && hotk->methods->lcd_status) { 1134 if (hotk->methods->mt_lcd_switch && hotk->methods->lcd_status) {
1063 asus_proc_add(PROC_LCD, &proc_write_lcd, &proc_read_lcd, mode, 1135 asus_proc_add(PROC_LCD, &lcd_proc_fops, mode, device);
1064 device);
1065 } 1136 }
1066 1137
1067 if ((hotk->methods->brightness_up && hotk->methods->brightness_down) || 1138 if ((hotk->methods->brightness_up && hotk->methods->brightness_down) ||
1068 (hotk->methods->brightness_get && hotk->methods->brightness_set)) { 1139 (hotk->methods->brightness_get && hotk->methods->brightness_set)) {
1069 asus_proc_add(PROC_BRN, &proc_write_brn, &proc_read_brn, mode, 1140 asus_proc_add(PROC_BRN, &brn_proc_fops, mode, device);
1070 device);
1071 } 1141 }
1072 1142
1073 if (hotk->methods->display_set) { 1143 if (hotk->methods->display_set) {
1074 asus_proc_add(PROC_DISP, &proc_write_disp, &proc_read_disp, 1144 asus_proc_add(PROC_DISP, &disp_proc_fops, mode, device);
1075 mode, device);
1076 } 1145 }
1077 1146
1078 return 0; 1147 return 0;
@@ -1157,9 +1226,8 @@ static int asus_model_match(char *model)
1157 else if (strncmp(model, "M2N", 3) == 0 || 1226 else if (strncmp(model, "M2N", 3) == 0 ||
1158 strncmp(model, "M3N", 3) == 0 || 1227 strncmp(model, "M3N", 3) == 0 ||
1159 strncmp(model, "M5N", 3) == 0 || 1228 strncmp(model, "M5N", 3) == 0 ||
1160 strncmp(model, "M6N", 3) == 0 ||
1161 strncmp(model, "S1N", 3) == 0 || 1229 strncmp(model, "S1N", 3) == 0 ||
1162 strncmp(model, "S5N", 3) == 0 || strncmp(model, "W1N", 3) == 0) 1230 strncmp(model, "S5N", 3) == 0)
1163 return xxN; 1231 return xxN;
1164 else if (strncmp(model, "M1", 2) == 0) 1232 else if (strncmp(model, "M1", 2) == 0)
1165 return M1A; 1233 return M1A;
@@ -1334,9 +1402,6 @@ static int asus_hotk_add(struct acpi_device *device)
1334 acpi_status status = AE_OK; 1402 acpi_status status = AE_OK;
1335 int result; 1403 int result;
1336 1404
1337 if (!device)
1338 return -EINVAL;
1339
1340 printk(KERN_NOTICE "Asus Laptop ACPI Extras version %s\n", 1405 printk(KERN_NOTICE "Asus Laptop ACPI Extras version %s\n",
1341 ASUS_ACPI_VERSION); 1406 ASUS_ACPI_VERSION);
1342 1407
@@ -1392,9 +1457,6 @@ end:
1392 1457
1393static int asus_hotk_remove(struct acpi_device *device, int type) 1458static int asus_hotk_remove(struct acpi_device *device, int type)
1394{ 1459{
1395 if (!device || !acpi_driver_data(device))
1396 return -EINVAL;
1397
1398 asus_hotk_remove_fs(device); 1460 asus_hotk_remove_fs(device);
1399 1461
1400 kfree(hotk); 1462 kfree(hotk);
@@ -1420,23 +1482,20 @@ static void asus_acpi_exit(void)
1420 1482
1421static int __init asus_acpi_init(void) 1483static int __init asus_acpi_init(void)
1422{ 1484{
1485 struct backlight_properties props;
1423 int result; 1486 int result;
1424 1487
1425 if (acpi_disabled) 1488 result = acpi_bus_register_driver(&asus_hotk_driver);
1426 return -ENODEV; 1489 if (result < 0)
1490 return result;
1427 1491
1428 asus_proc_dir = proc_mkdir(PROC_ASUS, acpi_root_dir); 1492 asus_proc_dir = proc_mkdir(PROC_ASUS, acpi_root_dir);
1429 if (!asus_proc_dir) { 1493 if (!asus_proc_dir) {
1430 printk(KERN_ERR "Asus ACPI: Unable to create /proc entry\n"); 1494 printk(KERN_ERR "Asus ACPI: Unable to create /proc entry\n");
1495 acpi_bus_unregister_driver(&asus_hotk_driver);
1431 return -ENODEV; 1496 return -ENODEV;
1432 } 1497 }
1433 1498
1434 result = acpi_bus_register_driver(&asus_hotk_driver);
1435 if (result < 0) {
1436 remove_proc_entry(PROC_ASUS, acpi_root_dir);
1437 return result;
1438 }
1439
1440 /* 1499 /*
1441 * This is a bit of a kludge. We only want this module loaded 1500 * This is a bit of a kludge. We only want this module loaded
1442 * for ASUS systems, but there's currently no way to probe the 1501 * for ASUS systems, but there's currently no way to probe the
@@ -1450,15 +1509,17 @@ static int __init asus_acpi_init(void)
1450 return -ENODEV; 1509 return -ENODEV;
1451 } 1510 }
1452 1511
1512 memset(&props, 0, sizeof(struct backlight_properties));
1513 props.max_brightness = 15;
1453 asus_backlight_device = backlight_device_register("asus", NULL, NULL, 1514 asus_backlight_device = backlight_device_register("asus", NULL, NULL,
1454 &asus_backlight_data); 1515 &asus_backlight_data,
1516 &props);
1455 if (IS_ERR(asus_backlight_device)) { 1517 if (IS_ERR(asus_backlight_device)) {
1456 printk(KERN_ERR "Could not register asus backlight device\n"); 1518 printk(KERN_ERR "Could not register asus backlight device\n");
1457 asus_backlight_device = NULL; 1519 asus_backlight_device = NULL;
1458 asus_acpi_exit(); 1520 asus_acpi_exit();
1459 return -ENODEV; 1521 return -ENODEV;
1460 } 1522 }
1461 asus_backlight_device->props.max_brightness = 15;
1462 1523
1463 return 0; 1524 return 0;
1464} 1525}
diff --git a/drivers/platform/x86/classmate-laptop.c b/drivers/platform/x86/classmate-laptop.c
new file mode 100644
index 000000000000..7f9e5ddc9498
--- /dev/null
+++ b/drivers/platform/x86/classmate-laptop.c
@@ -0,0 +1,629 @@
1/*
2 * Copyright (C) 2009 Thadeu Lima de Souza Cascardo <cascardo@holoscopio.com>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 */
18
19
20#include <linux/init.h>
21#include <linux/module.h>
22#include <linux/slab.h>
23#include <linux/workqueue.h>
24#include <acpi/acpi_drivers.h>
25#include <linux/backlight.h>
26#include <linux/input.h>
27
28MODULE_LICENSE("GPL");
29
30
31struct cmpc_accel {
32 int sensitivity;
33};
34
35#define CMPC_ACCEL_SENSITIVITY_DEFAULT 5
36
37
38#define CMPC_ACCEL_HID "ACCE0000"
39#define CMPC_TABLET_HID "TBLT0000"
40#define CMPC_BL_HID "IPML200"
41#define CMPC_KEYS_HID "FnBT0000"
42
43/*
44 * Generic input device code.
45 */
46
47typedef void (*input_device_init)(struct input_dev *dev);
48
49static int cmpc_add_acpi_notify_device(struct acpi_device *acpi, char *name,
50 input_device_init idev_init)
51{
52 struct input_dev *inputdev;
53 int error;
54
55 inputdev = input_allocate_device();
56 if (!inputdev)
57 return -ENOMEM;
58 inputdev->name = name;
59 inputdev->dev.parent = &acpi->dev;
60 idev_init(inputdev);
61 error = input_register_device(inputdev);
62 if (error) {
63 input_free_device(inputdev);
64 return error;
65 }
66 dev_set_drvdata(&acpi->dev, inputdev);
67 return 0;
68}
69
70static int cmpc_remove_acpi_notify_device(struct acpi_device *acpi)
71{
72 struct input_dev *inputdev = dev_get_drvdata(&acpi->dev);
73 input_unregister_device(inputdev);
74 return 0;
75}
76
77/*
78 * Accelerometer code.
79 */
80static acpi_status cmpc_start_accel(acpi_handle handle)
81{
82 union acpi_object param[2];
83 struct acpi_object_list input;
84 acpi_status status;
85
86 param[0].type = ACPI_TYPE_INTEGER;
87 param[0].integer.value = 0x3;
88 param[1].type = ACPI_TYPE_INTEGER;
89 input.count = 2;
90 input.pointer = param;
91 status = acpi_evaluate_object(handle, "ACMD", &input, NULL);
92 return status;
93}
94
95static acpi_status cmpc_stop_accel(acpi_handle handle)
96{
97 union acpi_object param[2];
98 struct acpi_object_list input;
99 acpi_status status;
100
101 param[0].type = ACPI_TYPE_INTEGER;
102 param[0].integer.value = 0x4;
103 param[1].type = ACPI_TYPE_INTEGER;
104 input.count = 2;
105 input.pointer = param;
106 status = acpi_evaluate_object(handle, "ACMD", &input, NULL);
107 return status;
108}
109
110static acpi_status cmpc_accel_set_sensitivity(acpi_handle handle, int val)
111{
112 union acpi_object param[2];
113 struct acpi_object_list input;
114
115 param[0].type = ACPI_TYPE_INTEGER;
116 param[0].integer.value = 0x02;
117 param[1].type = ACPI_TYPE_INTEGER;
118 param[1].integer.value = val;
119 input.count = 2;
120 input.pointer = param;
121 return acpi_evaluate_object(handle, "ACMD", &input, NULL);
122}
123
124static acpi_status cmpc_get_accel(acpi_handle handle,
125 unsigned char *x,
126 unsigned char *y,
127 unsigned char *z)
128{
129 union acpi_object param[2];
130 struct acpi_object_list input;
131 struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, 0 };
132 unsigned char *locs;
133 acpi_status status;
134
135 param[0].type = ACPI_TYPE_INTEGER;
136 param[0].integer.value = 0x01;
137 param[1].type = ACPI_TYPE_INTEGER;
138 input.count = 2;
139 input.pointer = param;
140 status = acpi_evaluate_object(handle, "ACMD", &input, &output);
141 if (ACPI_SUCCESS(status)) {
142 union acpi_object *obj;
143 obj = output.pointer;
144 locs = obj->buffer.pointer;
145 *x = locs[0];
146 *y = locs[1];
147 *z = locs[2];
148 kfree(output.pointer);
149 }
150 return status;
151}
152
153static void cmpc_accel_handler(struct acpi_device *dev, u32 event)
154{
155 if (event == 0x81) {
156 unsigned char x, y, z;
157 acpi_status status;
158
159 status = cmpc_get_accel(dev->handle, &x, &y, &z);
160 if (ACPI_SUCCESS(status)) {
161 struct input_dev *inputdev = dev_get_drvdata(&dev->dev);
162
163 input_report_abs(inputdev, ABS_X, x);
164 input_report_abs(inputdev, ABS_Y, y);
165 input_report_abs(inputdev, ABS_Z, z);
166 input_sync(inputdev);
167 }
168 }
169}
170
171static ssize_t cmpc_accel_sensitivity_show(struct device *dev,
172 struct device_attribute *attr,
173 char *buf)
174{
175 struct acpi_device *acpi;
176 struct input_dev *inputdev;
177 struct cmpc_accel *accel;
178
179 acpi = to_acpi_device(dev);
180 inputdev = dev_get_drvdata(&acpi->dev);
181 accel = dev_get_drvdata(&inputdev->dev);
182
183 return sprintf(buf, "%d\n", accel->sensitivity);
184}
185
186static ssize_t cmpc_accel_sensitivity_store(struct device *dev,
187 struct device_attribute *attr,
188 const char *buf, size_t count)
189{
190 struct acpi_device *acpi;
191 struct input_dev *inputdev;
192 struct cmpc_accel *accel;
193 unsigned long sensitivity;
194 int r;
195
196 acpi = to_acpi_device(dev);
197 inputdev = dev_get_drvdata(&acpi->dev);
198 accel = dev_get_drvdata(&inputdev->dev);
199
200 r = strict_strtoul(buf, 0, &sensitivity);
201 if (r)
202 return r;
203
204 accel->sensitivity = sensitivity;
205 cmpc_accel_set_sensitivity(acpi->handle, sensitivity);
206
207 return strnlen(buf, count);
208}
209
210struct device_attribute cmpc_accel_sensitivity_attr = {
211 .attr = { .name = "sensitivity", .mode = 0660 },
212 .show = cmpc_accel_sensitivity_show,
213 .store = cmpc_accel_sensitivity_store
214};
215
216static int cmpc_accel_open(struct input_dev *input)
217{
218 struct acpi_device *acpi;
219
220 acpi = to_acpi_device(input->dev.parent);
221 if (ACPI_SUCCESS(cmpc_start_accel(acpi->handle)))
222 return 0;
223 return -EIO;
224}
225
226static void cmpc_accel_close(struct input_dev *input)
227{
228 struct acpi_device *acpi;
229
230 acpi = to_acpi_device(input->dev.parent);
231 cmpc_stop_accel(acpi->handle);
232}
233
234static void cmpc_accel_idev_init(struct input_dev *inputdev)
235{
236 set_bit(EV_ABS, inputdev->evbit);
237 input_set_abs_params(inputdev, ABS_X, 0, 255, 8, 0);
238 input_set_abs_params(inputdev, ABS_Y, 0, 255, 8, 0);
239 input_set_abs_params(inputdev, ABS_Z, 0, 255, 8, 0);
240 inputdev->open = cmpc_accel_open;
241 inputdev->close = cmpc_accel_close;
242}
243
244static int cmpc_accel_add(struct acpi_device *acpi)
245{
246 int error;
247 struct input_dev *inputdev;
248 struct cmpc_accel *accel;
249
250 accel = kmalloc(sizeof(*accel), GFP_KERNEL);
251 if (!accel)
252 return -ENOMEM;
253
254 accel->sensitivity = CMPC_ACCEL_SENSITIVITY_DEFAULT;
255 cmpc_accel_set_sensitivity(acpi->handle, accel->sensitivity);
256
257 error = device_create_file(&acpi->dev, &cmpc_accel_sensitivity_attr);
258 if (error)
259 goto failed_file;
260
261 error = cmpc_add_acpi_notify_device(acpi, "cmpc_accel",
262 cmpc_accel_idev_init);
263 if (error)
264 goto failed_input;
265
266 inputdev = dev_get_drvdata(&acpi->dev);
267 dev_set_drvdata(&inputdev->dev, accel);
268
269 return 0;
270
271failed_input:
272 device_remove_file(&acpi->dev, &cmpc_accel_sensitivity_attr);
273failed_file:
274 kfree(accel);
275 return error;
276}
277
278static int cmpc_accel_remove(struct acpi_device *acpi, int type)
279{
280 struct input_dev *inputdev;
281 struct cmpc_accel *accel;
282
283 inputdev = dev_get_drvdata(&acpi->dev);
284 accel = dev_get_drvdata(&inputdev->dev);
285
286 device_remove_file(&acpi->dev, &cmpc_accel_sensitivity_attr);
287 return cmpc_remove_acpi_notify_device(acpi);
288}
289
290static const struct acpi_device_id cmpc_accel_device_ids[] = {
291 {CMPC_ACCEL_HID, 0},
292 {"", 0}
293};
294
295static struct acpi_driver cmpc_accel_acpi_driver = {
296 .owner = THIS_MODULE,
297 .name = "cmpc_accel",
298 .class = "cmpc_accel",
299 .ids = cmpc_accel_device_ids,
300 .ops = {
301 .add = cmpc_accel_add,
302 .remove = cmpc_accel_remove,
303 .notify = cmpc_accel_handler,
304 }
305};
306
307
308/*
309 * Tablet mode code.
310 */
311static acpi_status cmpc_get_tablet(acpi_handle handle,
312 unsigned long long *value)
313{
314 union acpi_object param;
315 struct acpi_object_list input;
316 unsigned long long output;
317 acpi_status status;
318
319 param.type = ACPI_TYPE_INTEGER;
320 param.integer.value = 0x01;
321 input.count = 1;
322 input.pointer = &param;
323 status = acpi_evaluate_integer(handle, "TCMD", &input, &output);
324 if (ACPI_SUCCESS(status))
325 *value = output;
326 return status;
327}
328
329static void cmpc_tablet_handler(struct acpi_device *dev, u32 event)
330{
331 unsigned long long val = 0;
332 struct input_dev *inputdev = dev_get_drvdata(&dev->dev);
333
334 if (event == 0x81) {
335 if (ACPI_SUCCESS(cmpc_get_tablet(dev->handle, &val)))
336 input_report_switch(inputdev, SW_TABLET_MODE, !val);
337 }
338}
339
340static void cmpc_tablet_idev_init(struct input_dev *inputdev)
341{
342 unsigned long long val = 0;
343 struct acpi_device *acpi;
344
345 set_bit(EV_SW, inputdev->evbit);
346 set_bit(SW_TABLET_MODE, inputdev->swbit);
347
348 acpi = to_acpi_device(inputdev->dev.parent);
349 if (ACPI_SUCCESS(cmpc_get_tablet(acpi->handle, &val)))
350 input_report_switch(inputdev, SW_TABLET_MODE, !val);
351}
352
353static int cmpc_tablet_add(struct acpi_device *acpi)
354{
355 return cmpc_add_acpi_notify_device(acpi, "cmpc_tablet",
356 cmpc_tablet_idev_init);
357}
358
359static int cmpc_tablet_remove(struct acpi_device *acpi, int type)
360{
361 return cmpc_remove_acpi_notify_device(acpi);
362}
363
364static int cmpc_tablet_resume(struct acpi_device *acpi)
365{
366 struct input_dev *inputdev = dev_get_drvdata(&acpi->dev);
367 unsigned long long val = 0;
368 if (ACPI_SUCCESS(cmpc_get_tablet(acpi->handle, &val)))
369 input_report_switch(inputdev, SW_TABLET_MODE, !val);
370 return 0;
371}
372
373static const struct acpi_device_id cmpc_tablet_device_ids[] = {
374 {CMPC_TABLET_HID, 0},
375 {"", 0}
376};
377
378static struct acpi_driver cmpc_tablet_acpi_driver = {
379 .owner = THIS_MODULE,
380 .name = "cmpc_tablet",
381 .class = "cmpc_tablet",
382 .ids = cmpc_tablet_device_ids,
383 .ops = {
384 .add = cmpc_tablet_add,
385 .remove = cmpc_tablet_remove,
386 .resume = cmpc_tablet_resume,
387 .notify = cmpc_tablet_handler,
388 }
389};
390
391
392/*
393 * Backlight code.
394 */
395
396static acpi_status cmpc_get_brightness(acpi_handle handle,
397 unsigned long long *value)
398{
399 union acpi_object param;
400 struct acpi_object_list input;
401 unsigned long long output;
402 acpi_status status;
403
404 param.type = ACPI_TYPE_INTEGER;
405 param.integer.value = 0xC0;
406 input.count = 1;
407 input.pointer = &param;
408 status = acpi_evaluate_integer(handle, "GRDI", &input, &output);
409 if (ACPI_SUCCESS(status))
410 *value = output;
411 return status;
412}
413
414static acpi_status cmpc_set_brightness(acpi_handle handle,
415 unsigned long long value)
416{
417 union acpi_object param[2];
418 struct acpi_object_list input;
419 acpi_status status;
420 unsigned long long output;
421
422 param[0].type = ACPI_TYPE_INTEGER;
423 param[0].integer.value = 0xC0;
424 param[1].type = ACPI_TYPE_INTEGER;
425 param[1].integer.value = value;
426 input.count = 2;
427 input.pointer = param;
428 status = acpi_evaluate_integer(handle, "GWRI", &input, &output);
429 return status;
430}
431
432static int cmpc_bl_get_brightness(struct backlight_device *bd)
433{
434 acpi_status status;
435 acpi_handle handle;
436 unsigned long long brightness;
437
438 handle = bl_get_data(bd);
439 status = cmpc_get_brightness(handle, &brightness);
440 if (ACPI_SUCCESS(status))
441 return brightness;
442 else
443 return -1;
444}
445
446static int cmpc_bl_update_status(struct backlight_device *bd)
447{
448 acpi_status status;
449 acpi_handle handle;
450
451 handle = bl_get_data(bd);
452 status = cmpc_set_brightness(handle, bd->props.brightness);
453 if (ACPI_SUCCESS(status))
454 return 0;
455 else
456 return -1;
457}
458
459static const struct backlight_ops cmpc_bl_ops = {
460 .get_brightness = cmpc_bl_get_brightness,
461 .update_status = cmpc_bl_update_status
462};
463
464static int cmpc_bl_add(struct acpi_device *acpi)
465{
466 struct backlight_properties props;
467 struct backlight_device *bd;
468
469 memset(&props, 0, sizeof(struct backlight_properties));
470 props.max_brightness = 7;
471 bd = backlight_device_register("cmpc_bl", &acpi->dev, acpi->handle,
472 &cmpc_bl_ops, &props);
473 if (IS_ERR(bd))
474 return PTR_ERR(bd);
475 dev_set_drvdata(&acpi->dev, bd);
476 return 0;
477}
478
479static int cmpc_bl_remove(struct acpi_device *acpi, int type)
480{
481 struct backlight_device *bd;
482
483 bd = dev_get_drvdata(&acpi->dev);
484 backlight_device_unregister(bd);
485 return 0;
486}
487
488static const struct acpi_device_id cmpc_bl_device_ids[] = {
489 {CMPC_BL_HID, 0},
490 {"", 0}
491};
492
493static struct acpi_driver cmpc_bl_acpi_driver = {
494 .owner = THIS_MODULE,
495 .name = "cmpc",
496 .class = "cmpc",
497 .ids = cmpc_bl_device_ids,
498 .ops = {
499 .add = cmpc_bl_add,
500 .remove = cmpc_bl_remove
501 }
502};
503
504
505/*
506 * Extra keys code.
507 */
508static int cmpc_keys_codes[] = {
509 KEY_UNKNOWN,
510 KEY_WLAN,
511 KEY_SWITCHVIDEOMODE,
512 KEY_BRIGHTNESSDOWN,
513 KEY_BRIGHTNESSUP,
514 KEY_VENDOR,
515 KEY_UNKNOWN,
516 KEY_CAMERA,
517 KEY_BACK,
518 KEY_FORWARD,
519 KEY_MAX
520};
521
522static void cmpc_keys_handler(struct acpi_device *dev, u32 event)
523{
524 struct input_dev *inputdev;
525 int code = KEY_MAX;
526
527 if ((event & 0x0F) < ARRAY_SIZE(cmpc_keys_codes))
528 code = cmpc_keys_codes[event & 0x0F];
529 inputdev = dev_get_drvdata(&dev->dev);;
530 input_report_key(inputdev, code, !(event & 0x10));
531}
532
533static void cmpc_keys_idev_init(struct input_dev *inputdev)
534{
535 int i;
536
537 set_bit(EV_KEY, inputdev->evbit);
538 for (i = 0; cmpc_keys_codes[i] != KEY_MAX; i++)
539 set_bit(cmpc_keys_codes[i], inputdev->keybit);
540}
541
542static int cmpc_keys_add(struct acpi_device *acpi)
543{
544 return cmpc_add_acpi_notify_device(acpi, "cmpc_keys",
545 cmpc_keys_idev_init);
546}
547
548static int cmpc_keys_remove(struct acpi_device *acpi, int type)
549{
550 return cmpc_remove_acpi_notify_device(acpi);
551}
552
553static const struct acpi_device_id cmpc_keys_device_ids[] = {
554 {CMPC_KEYS_HID, 0},
555 {"", 0}
556};
557
558static struct acpi_driver cmpc_keys_acpi_driver = {
559 .owner = THIS_MODULE,
560 .name = "cmpc_keys",
561 .class = "cmpc_keys",
562 .ids = cmpc_keys_device_ids,
563 .ops = {
564 .add = cmpc_keys_add,
565 .remove = cmpc_keys_remove,
566 .notify = cmpc_keys_handler,
567 }
568};
569
570
571/*
572 * General init/exit code.
573 */
574
575static int cmpc_init(void)
576{
577 int r;
578
579 r = acpi_bus_register_driver(&cmpc_keys_acpi_driver);
580 if (r)
581 goto failed_keys;
582
583 r = acpi_bus_register_driver(&cmpc_bl_acpi_driver);
584 if (r)
585 goto failed_bl;
586
587 r = acpi_bus_register_driver(&cmpc_tablet_acpi_driver);
588 if (r)
589 goto failed_tablet;
590
591 r = acpi_bus_register_driver(&cmpc_accel_acpi_driver);
592 if (r)
593 goto failed_accel;
594
595 return r;
596
597failed_accel:
598 acpi_bus_unregister_driver(&cmpc_tablet_acpi_driver);
599
600failed_tablet:
601 acpi_bus_unregister_driver(&cmpc_bl_acpi_driver);
602
603failed_bl:
604 acpi_bus_unregister_driver(&cmpc_keys_acpi_driver);
605
606failed_keys:
607 return r;
608}
609
610static void cmpc_exit(void)
611{
612 acpi_bus_unregister_driver(&cmpc_accel_acpi_driver);
613 acpi_bus_unregister_driver(&cmpc_tablet_acpi_driver);
614 acpi_bus_unregister_driver(&cmpc_bl_acpi_driver);
615 acpi_bus_unregister_driver(&cmpc_keys_acpi_driver);
616}
617
618module_init(cmpc_init);
619module_exit(cmpc_exit);
620
621static const struct acpi_device_id cmpc_device_ids[] = {
622 {CMPC_ACCEL_HID, 0},
623 {CMPC_TABLET_HID, 0},
624 {CMPC_BL_HID, 0},
625 {CMPC_KEYS_HID, 0},
626 {"", 0}
627};
628
629MODULE_DEVICE_TABLE(acpi, cmpc_device_ids);
diff --git a/drivers/platform/x86/compal-laptop.c b/drivers/platform/x86/compal-laptop.c
index 11003bba10d3..71ff1545a93e 100644
--- a/drivers/platform/x86/compal-laptop.c
+++ b/drivers/platform/x86/compal-laptop.c
@@ -26,17 +26,8 @@
26/* 26/*
27 * comapl-laptop.c - Compal laptop support. 27 * comapl-laptop.c - Compal laptop support.
28 * 28 *
29 * This driver exports a few files in /sys/devices/platform/compal-laptop/: 29 * The driver registers itself with the rfkill subsystem and
30 * 30 * the Linux backlight control subsystem.
31 * wlan - wlan subsystem state: contains 0 or 1 (rw)
32 *
33 * bluetooth - Bluetooth subsystem state: contains 0 or 1 (rw)
34 *
35 * raw - raw value taken from embedded controller register (ro)
36 *
37 * In addition to these platform device attributes the driver
38 * registers itself in the Linux backlight control subsystem and is
39 * available to userspace under /sys/class/backlight/compal-laptop/.
40 * 31 *
41 * This driver might work on other laptops produced by Compal. If you 32 * This driver might work on other laptops produced by Compal. If you
42 * want to try it you can pass force=1 as argument to the module which 33 * want to try it you can pass force=1 as argument to the module which
@@ -51,7 +42,7 @@
51#include <linux/dmi.h> 42#include <linux/dmi.h>
52#include <linux/backlight.h> 43#include <linux/backlight.h>
53#include <linux/platform_device.h> 44#include <linux/platform_device.h>
54#include <linux/autoconf.h> 45#include <linux/rfkill.h>
55 46
56#define COMPAL_DRIVER_VERSION "0.2.6" 47#define COMPAL_DRIVER_VERSION "0.2.6"
57 48
@@ -64,6 +55,10 @@
64#define WLAN_MASK 0x01 55#define WLAN_MASK 0x01
65#define BT_MASK 0x02 56#define BT_MASK 0x02
66 57
58static struct rfkill *wifi_rfkill;
59static struct rfkill *bt_rfkill;
60static struct platform_device *compal_device;
61
67static int force; 62static int force;
68module_param(force, bool, 0); 63module_param(force, bool, 0);
69MODULE_PARM_DESC(force, "Force driver load, ignore DMI data"); 64MODULE_PARM_DESC(force, "Force driver load, ignore DMI data");
@@ -89,65 +84,75 @@ static int get_lcd_level(void)
89 return (int) result; 84 return (int) result;
90} 85}
91 86
92static int set_wlan_state(int state) 87static int compal_rfkill_set(void *data, bool blocked)
93{ 88{
89 unsigned long radio = (unsigned long) data;
94 u8 result, value; 90 u8 result, value;
95 91
96 ec_read(COMPAL_EC_COMMAND_WIRELESS, &result); 92 ec_read(COMPAL_EC_COMMAND_WIRELESS, &result);
97 93
98 if ((result & KILLSWITCH_MASK) == 0) 94 if (!blocked)
99 return -EINVAL; 95 value = (u8) (result | radio);
100 else { 96 else
101 if (state) 97 value = (u8) (result & ~radio);
102 value = (u8) (result | WLAN_MASK); 98 ec_write(COMPAL_EC_COMMAND_WIRELESS, value);
103 else
104 value = (u8) (result & ~WLAN_MASK);
105 ec_write(COMPAL_EC_COMMAND_WIRELESS, value);
106 }
107 99
108 return 0; 100 return 0;
109} 101}
110 102
111static int set_bluetooth_state(int state) 103static void compal_rfkill_poll(struct rfkill *rfkill, void *data)
112{ 104{
113 u8 result, value; 105 u8 result;
106 bool hw_blocked;
114 107
115 ec_read(COMPAL_EC_COMMAND_WIRELESS, &result); 108 ec_read(COMPAL_EC_COMMAND_WIRELESS, &result);
116 109
117 if ((result & KILLSWITCH_MASK) == 0) 110 hw_blocked = !(result & KILLSWITCH_MASK);
118 return -EINVAL; 111 rfkill_set_hw_state(rfkill, hw_blocked);
119 else {
120 if (state)
121 value = (u8) (result | BT_MASK);
122 else
123 value = (u8) (result & ~BT_MASK);
124 ec_write(COMPAL_EC_COMMAND_WIRELESS, value);
125 }
126
127 return 0;
128} 112}
129 113
130static int get_wireless_state(int *wlan, int *bluetooth) 114static const struct rfkill_ops compal_rfkill_ops = {
115 .poll = compal_rfkill_poll,
116 .set_block = compal_rfkill_set,
117};
118
119static int setup_rfkill(void)
131{ 120{
132 u8 result; 121 int ret;
133 122
134 ec_read(COMPAL_EC_COMMAND_WIRELESS, &result); 123 wifi_rfkill = rfkill_alloc("compal-wifi", &compal_device->dev,
124 RFKILL_TYPE_WLAN, &compal_rfkill_ops,
125 (void *) WLAN_MASK);
126 if (!wifi_rfkill)
127 return -ENOMEM;
135 128
136 if (wlan) { 129 ret = rfkill_register(wifi_rfkill);
137 if ((result & KILLSWITCH_MASK) == 0) 130 if (ret)
138 *wlan = 0; 131 goto err_wifi;
139 else
140 *wlan = result & WLAN_MASK;
141 }
142 132
143 if (bluetooth) { 133 bt_rfkill = rfkill_alloc("compal-bluetooth", &compal_device->dev,
144 if ((result & KILLSWITCH_MASK) == 0) 134 RFKILL_TYPE_BLUETOOTH, &compal_rfkill_ops,
145 *bluetooth = 0; 135 (void *) BT_MASK);
146 else 136 if (!bt_rfkill) {
147 *bluetooth = (result & BT_MASK) >> 1; 137 ret = -ENOMEM;
138 goto err_allocate_bt;
148 } 139 }
140 ret = rfkill_register(bt_rfkill);
141 if (ret)
142 goto err_register_bt;
149 143
150 return 0; 144 return 0;
145
146err_register_bt:
147 rfkill_destroy(bt_rfkill);
148
149err_allocate_bt:
150 rfkill_unregister(wifi_rfkill);
151
152err_wifi:
153 rfkill_destroy(wifi_rfkill);
154
155 return ret;
151} 156}
152 157
153/* Backlight device stuff */ 158/* Backlight device stuff */
@@ -170,86 +175,6 @@ static struct backlight_ops compalbl_ops = {
170 175
171static struct backlight_device *compalbl_device; 176static struct backlight_device *compalbl_device;
172 177
173/* Platform device */
174
175static ssize_t show_wlan(struct device *dev,
176 struct device_attribute *attr, char *buf)
177{
178 int ret, enabled;
179
180 ret = get_wireless_state(&enabled, NULL);
181 if (ret < 0)
182 return ret;
183
184 return sprintf(buf, "%i\n", enabled);
185}
186
187static ssize_t show_raw(struct device *dev,
188 struct device_attribute *attr, char *buf)
189{
190 u8 result;
191
192 ec_read(COMPAL_EC_COMMAND_WIRELESS, &result);
193
194 return sprintf(buf, "%i\n", result);
195}
196
197static ssize_t show_bluetooth(struct device *dev,
198 struct device_attribute *attr, char *buf)
199{
200 int ret, enabled;
201
202 ret = get_wireless_state(NULL, &enabled);
203 if (ret < 0)
204 return ret;
205
206 return sprintf(buf, "%i\n", enabled);
207}
208
209static ssize_t store_wlan_state(struct device *dev,
210 struct device_attribute *attr, const char *buf, size_t count)
211{
212 int state, ret;
213
214 if (sscanf(buf, "%i", &state) != 1 || (state < 0 || state > 1))
215 return -EINVAL;
216
217 ret = set_wlan_state(state);
218 if (ret < 0)
219 return ret;
220
221 return count;
222}
223
224static ssize_t store_bluetooth_state(struct device *dev,
225 struct device_attribute *attr, const char *buf, size_t count)
226{
227 int state, ret;
228
229 if (sscanf(buf, "%i", &state) != 1 || (state < 0 || state > 1))
230 return -EINVAL;
231
232 ret = set_bluetooth_state(state);
233 if (ret < 0)
234 return ret;
235
236 return count;
237}
238
239static DEVICE_ATTR(bluetooth, 0644, show_bluetooth, store_bluetooth_state);
240static DEVICE_ATTR(wlan, 0644, show_wlan, store_wlan_state);
241static DEVICE_ATTR(raw, 0444, show_raw, NULL);
242
243static struct attribute *compal_attributes[] = {
244 &dev_attr_bluetooth.attr,
245 &dev_attr_wlan.attr,
246 &dev_attr_raw.attr,
247 NULL
248};
249
250static struct attribute_group compal_attribute_group = {
251 .attrs = compal_attributes
252};
253 178
254static struct platform_driver compal_driver = { 179static struct platform_driver compal_driver = {
255 .driver = { 180 .driver = {
@@ -258,8 +183,6 @@ static struct platform_driver compal_driver = {
258 } 183 }
259}; 184};
260 185
261static struct platform_device *compal_device;
262
263/* Initialization */ 186/* Initialization */
264 187
265static int dmi_check_cb(const struct dmi_system_id *id) 188static int dmi_check_cb(const struct dmi_system_id *id)
@@ -311,6 +234,47 @@ static struct dmi_system_id __initdata compal_dmi_table[] = {
311 }, 234 },
312 .callback = dmi_check_cb 235 .callback = dmi_check_cb
313 }, 236 },
237 {
238 .ident = "Dell Mini 9",
239 .matches = {
240 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
241 DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 910"),
242 },
243 .callback = dmi_check_cb
244 },
245 {
246 .ident = "Dell Mini 10",
247 .matches = {
248 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
249 DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1010"),
250 },
251 .callback = dmi_check_cb
252 },
253 {
254 .ident = "Dell Mini 10v",
255 .matches = {
256 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
257 DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1011"),
258 },
259 .callback = dmi_check_cb
260 },
261 {
262 .ident = "Dell Inspiron 11z",
263 .matches = {
264 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
265 DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1110"),
266 },
267 .callback = dmi_check_cb
268 },
269 {
270 .ident = "Dell Mini 12",
271 .matches = {
272 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
273 DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1210"),
274 },
275 .callback = dmi_check_cb
276 },
277
314 { } 278 { }
315}; 279};
316 280
@@ -327,12 +291,15 @@ static int __init compal_init(void)
327 /* Register backlight stuff */ 291 /* Register backlight stuff */
328 292
329 if (!acpi_video_backlight_support()) { 293 if (!acpi_video_backlight_support()) {
330 compalbl_device = backlight_device_register("compal-laptop", NULL, NULL, 294 struct backlight_properties props;
331 &compalbl_ops); 295 memset(&props, 0, sizeof(struct backlight_properties));
296 props.max_brightness = COMPAL_LCD_LEVEL_MAX - 1;
297 compalbl_device = backlight_device_register("compal-laptop",
298 NULL, NULL,
299 &compalbl_ops,
300 &props);
332 if (IS_ERR(compalbl_device)) 301 if (IS_ERR(compalbl_device))
333 return PTR_ERR(compalbl_device); 302 return PTR_ERR(compalbl_device);
334
335 compalbl_device->props.max_brightness = COMPAL_LCD_LEVEL_MAX-1;
336 } 303 }
337 304
338 ret = platform_driver_register(&compal_driver); 305 ret = platform_driver_register(&compal_driver);
@@ -349,23 +316,21 @@ static int __init compal_init(void)
349 316
350 ret = platform_device_add(compal_device); 317 ret = platform_device_add(compal_device);
351 if (ret) 318 if (ret)
352 goto fail_platform_device1; 319 goto fail_platform_device;
353 320
354 ret = sysfs_create_group(&compal_device->dev.kobj, 321 ret = setup_rfkill();
355 &compal_attribute_group);
356 if (ret) 322 if (ret)
357 goto fail_platform_device2; 323 goto fail_rfkill;
358 324
359 printk(KERN_INFO "compal-laptop: driver "COMPAL_DRIVER_VERSION 325 printk(KERN_INFO "compal-laptop: driver "COMPAL_DRIVER_VERSION
360 " successfully loaded.\n"); 326 " successfully loaded.\n");
361 327
362 return 0; 328 return 0;
363 329
364fail_platform_device2: 330fail_rfkill:
365
366 platform_device_del(compal_device); 331 platform_device_del(compal_device);
367 332
368fail_platform_device1: 333fail_platform_device:
369 334
370 platform_device_put(compal_device); 335 platform_device_put(compal_device);
371 336
@@ -383,10 +348,13 @@ fail_backlight:
383static void __exit compal_cleanup(void) 348static void __exit compal_cleanup(void)
384{ 349{
385 350
386 sysfs_remove_group(&compal_device->dev.kobj, &compal_attribute_group);
387 platform_device_unregister(compal_device); 351 platform_device_unregister(compal_device);
388 platform_driver_unregister(&compal_driver); 352 platform_driver_unregister(&compal_driver);
389 backlight_device_unregister(compalbl_device); 353 backlight_device_unregister(compalbl_device);
354 rfkill_unregister(wifi_rfkill);
355 rfkill_destroy(wifi_rfkill);
356 rfkill_unregister(bt_rfkill);
357 rfkill_destroy(bt_rfkill);
390 358
391 printk(KERN_INFO "compal-laptop: driver unloaded.\n"); 359 printk(KERN_INFO "compal-laptop: driver unloaded.\n");
392} 360}
@@ -404,3 +372,8 @@ MODULE_ALIAS("dmi:*:rnIFL90:rvrREFERENCE:*");
404MODULE_ALIAS("dmi:*:rnIFL91:rvrIFT00:*"); 372MODULE_ALIAS("dmi:*:rnIFL91:rvrIFT00:*");
405MODULE_ALIAS("dmi:*:rnJFL92:rvrIFT00:*"); 373MODULE_ALIAS("dmi:*:rnJFL92:rvrIFT00:*");
406MODULE_ALIAS("dmi:*:rnIFT00:rvrIFT00:*"); 374MODULE_ALIAS("dmi:*:rnIFT00:rvrIFT00:*");
375MODULE_ALIAS("dmi:*:svnDellInc.:pnInspiron910:*");
376MODULE_ALIAS("dmi:*:svnDellInc.:pnInspiron1010:*");
377MODULE_ALIAS("dmi:*:svnDellInc.:pnInspiron1011:*");
378MODULE_ALIAS("dmi:*:svnDellInc.:pnInspiron1110:*");
379MODULE_ALIAS("dmi:*:svnDellInc.:pnInspiron1210:*");
diff --git a/drivers/platform/x86/dell-laptop.c b/drivers/platform/x86/dell-laptop.c
index 74909c4aaeea..661e3ac4d5b1 100644
--- a/drivers/platform/x86/dell-laptop.c
+++ b/drivers/platform/x86/dell-laptop.c
@@ -22,6 +22,9 @@
22#include <linux/rfkill.h> 22#include <linux/rfkill.h>
23#include <linux/power_supply.h> 23#include <linux/power_supply.h>
24#include <linux/acpi.h> 24#include <linux/acpi.h>
25#include <linux/mm.h>
26#include <linux/i8042.h>
27#include <linux/slab.h>
25#include "../../firmware/dcdbas.h" 28#include "../../firmware/dcdbas.h"
26 29
27#define BRIGHTNESS_TOKEN 0x7d 30#define BRIGHTNESS_TOKEN 0x7d
@@ -58,6 +61,14 @@ static int da_command_code;
58static int da_num_tokens; 61static int da_num_tokens;
59static struct calling_interface_token *da_tokens; 62static struct calling_interface_token *da_tokens;
60 63
64static struct platform_driver platform_driver = {
65 .driver = {
66 .name = "dell-laptop",
67 .owner = THIS_MODULE,
68 }
69};
70
71static struct platform_device *platform_device;
61static struct backlight_device *dell_backlight_device; 72static struct backlight_device *dell_backlight_device;
62static struct rfkill *wifi_rfkill; 73static struct rfkill *wifi_rfkill;
63static struct rfkill *bluetooth_rfkill; 74static struct rfkill *bluetooth_rfkill;
@@ -71,10 +82,74 @@ static const struct dmi_system_id __initdata dell_device_table[] = {
71 DMI_MATCH(DMI_CHASSIS_TYPE, "8"), 82 DMI_MATCH(DMI_CHASSIS_TYPE, "8"),
72 }, 83 },
73 }, 84 },
85 {
86 .ident = "Dell Computer Corporation",
87 .matches = {
88 DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
89 DMI_MATCH(DMI_CHASSIS_TYPE, "8"),
90 },
91 },
74 { } 92 { }
75}; 93};
76 94
77static void parse_da_table(const struct dmi_header *dm) 95static struct dmi_system_id __devinitdata dell_blacklist[] = {
96 /* Supported by compal-laptop */
97 {
98 .ident = "Dell Mini 9",
99 .matches = {
100 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
101 DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 910"),
102 },
103 },
104 {
105 .ident = "Dell Mini 10",
106 .matches = {
107 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
108 DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1010"),
109 },
110 },
111 {
112 .ident = "Dell Mini 10v",
113 .matches = {
114 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
115 DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1011"),
116 },
117 },
118 {
119 .ident = "Dell Inspiron 11z",
120 .matches = {
121 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
122 DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1110"),
123 },
124 },
125 {
126 .ident = "Dell Mini 12",
127 .matches = {
128 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
129 DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1210"),
130 },
131 },
132 {}
133};
134
135static struct calling_interface_buffer *buffer;
136static struct page *bufferpage;
137static DEFINE_MUTEX(buffer_mutex);
138
139static int hwswitch_state;
140
141static void get_buffer(void)
142{
143 mutex_lock(&buffer_mutex);
144 memset(buffer, 0, sizeof(struct calling_interface_buffer));
145}
146
147static void release_buffer(void)
148{
149 mutex_unlock(&buffer_mutex);
150}
151
152static void __init parse_da_table(const struct dmi_header *dm)
78{ 153{
79 /* Final token is a terminator, so we don't want to copy it */ 154 /* Final token is a terminator, so we don't want to copy it */
80 int tokens = (dm->length-11)/sizeof(struct calling_interface_token)-1; 155 int tokens = (dm->length-11)/sizeof(struct calling_interface_token)-1;
@@ -103,7 +178,7 @@ static void parse_da_table(const struct dmi_header *dm)
103 da_num_tokens += tokens; 178 da_num_tokens += tokens;
104} 179}
105 180
106static void find_tokens(const struct dmi_header *dm, void *dummy) 181static void __init find_tokens(const struct dmi_header *dm, void *dummy)
107{ 182{
108 switch (dm->type) { 183 switch (dm->type) {
109 case 0xd4: /* Indexed IO */ 184 case 0xd4: /* Indexed IO */
@@ -152,6 +227,8 @@ dell_send_request(struct calling_interface_buffer *buffer, int class,
152/* Derived from information in DellWirelessCtl.cpp: 227/* Derived from information in DellWirelessCtl.cpp:
153 Class 17, select 11 is radio control. It returns an array of 32-bit values. 228 Class 17, select 11 is radio control. It returns an array of 32-bit values.
154 229
230 Input byte 0 = 0: Wireless information
231
155 result[0]: return code 232 result[0]: return code
156 result[1]: 233 result[1]:
157 Bit 0: Hardware switch supported 234 Bit 0: Hardware switch supported
@@ -172,33 +249,62 @@ dell_send_request(struct calling_interface_buffer *buffer, int class,
172 Bits 20-31: Reserved 249 Bits 20-31: Reserved
173 result[2]: NVRAM size in bytes 250 result[2]: NVRAM size in bytes
174 result[3]: NVRAM format version number 251 result[3]: NVRAM format version number
252
253 Input byte 0 = 2: Wireless switch configuration
254 result[0]: return code
255 result[1]:
256 Bit 0: Wifi controlled by switch
257 Bit 1: Bluetooth controlled by switch
258 Bit 2: WWAN controlled by switch
259 Bits 3-6: Reserved
260 Bit 7: Wireless switch config locked
261 Bit 8: Wifi locator enabled
262 Bits 9-14: Reserved
263 Bit 15: Wifi locator setting locked
264 Bits 16-31: Reserved
175*/ 265*/
176 266
177static int dell_rfkill_set(void *data, bool blocked) 267static int dell_rfkill_set(void *data, bool blocked)
178{ 268{
179 struct calling_interface_buffer buffer;
180 int disable = blocked ? 1 : 0; 269 int disable = blocked ? 1 : 0;
181 unsigned long radio = (unsigned long)data; 270 unsigned long radio = (unsigned long)data;
271 int hwswitch_bit = (unsigned long)data - 1;
272 int ret = 0;
182 273
183 memset(&buffer, 0, sizeof(struct calling_interface_buffer)); 274 get_buffer();
184 buffer.input[0] = (1 | (radio<<8) | (disable << 16)); 275 dell_send_request(buffer, 17, 11);
185 dell_send_request(&buffer, 17, 11);
186 276
187 return 0; 277 /* If the hardware switch controls this radio, and the hardware
278 switch is disabled, don't allow changing the software state */
279 if ((hwswitch_state & BIT(hwswitch_bit)) &&
280 !(buffer->output[1] & BIT(16))) {
281 ret = -EINVAL;
282 goto out;
283 }
284
285 buffer->input[0] = (1 | (radio<<8) | (disable << 16));
286 dell_send_request(buffer, 17, 11);
287
288out:
289 release_buffer();
290 return ret;
188} 291}
189 292
190static void dell_rfkill_query(struct rfkill *rfkill, void *data) 293static void dell_rfkill_query(struct rfkill *rfkill, void *data)
191{ 294{
192 struct calling_interface_buffer buffer;
193 int status; 295 int status;
194 int bit = (unsigned long)data + 16; 296 int bit = (unsigned long)data + 16;
297 int hwswitch_bit = (unsigned long)data - 1;
195 298
196 memset(&buffer, 0, sizeof(struct calling_interface_buffer)); 299 get_buffer();
197 dell_send_request(&buffer, 17, 11); 300 dell_send_request(buffer, 17, 11);
198 status = buffer.output[1]; 301 status = buffer->output[1];
302 release_buffer();
199 303
200 if (status & BIT(bit)) 304 rfkill_set_sw_state(rfkill, !!(status & BIT(bit)));
201 rfkill_set_hw_state(rfkill, !!(status & BIT(16))); 305
306 if (hwswitch_state & (BIT(hwswitch_bit)))
307 rfkill_set_hw_state(rfkill, !(status & BIT(16)));
202} 308}
203 309
204static const struct rfkill_ops dell_rfkill_ops = { 310static const struct rfkill_ops dell_rfkill_ops = {
@@ -206,18 +312,40 @@ static const struct rfkill_ops dell_rfkill_ops = {
206 .query = dell_rfkill_query, 312 .query = dell_rfkill_query,
207}; 313};
208 314
209static int dell_setup_rfkill(void) 315static void dell_update_rfkill(struct work_struct *ignored)
316{
317 if (wifi_rfkill)
318 dell_rfkill_query(wifi_rfkill, (void *)1);
319 if (bluetooth_rfkill)
320 dell_rfkill_query(bluetooth_rfkill, (void *)2);
321 if (wwan_rfkill)
322 dell_rfkill_query(wwan_rfkill, (void *)3);
323}
324static DECLARE_DELAYED_WORK(dell_rfkill_work, dell_update_rfkill);
325
326
327static int __init dell_setup_rfkill(void)
210{ 328{
211 struct calling_interface_buffer buffer;
212 int status; 329 int status;
213 int ret; 330 int ret;
214 331
215 memset(&buffer, 0, sizeof(struct calling_interface_buffer)); 332 if (dmi_check_system(dell_blacklist)) {
216 dell_send_request(&buffer, 17, 11); 333 printk(KERN_INFO "dell-laptop: Blacklisted hardware detected - "
217 status = buffer.output[1]; 334 "not enabling rfkill\n");
335 return 0;
336 }
337
338 get_buffer();
339 dell_send_request(buffer, 17, 11);
340 status = buffer->output[1];
341 buffer->input[0] = 0x2;
342 dell_send_request(buffer, 17, 11);
343 hwswitch_state = buffer->output[1];
344 release_buffer();
218 345
219 if ((status & (1<<2|1<<8)) == (1<<2|1<<8)) { 346 if ((status & (1<<2|1<<8)) == (1<<2|1<<8)) {
220 wifi_rfkill = rfkill_alloc("dell-wifi", NULL, RFKILL_TYPE_WLAN, 347 wifi_rfkill = rfkill_alloc("dell-wifi", &platform_device->dev,
348 RFKILL_TYPE_WLAN,
221 &dell_rfkill_ops, (void *) 1); 349 &dell_rfkill_ops, (void *) 1);
222 if (!wifi_rfkill) { 350 if (!wifi_rfkill) {
223 ret = -ENOMEM; 351 ret = -ENOMEM;
@@ -229,7 +357,8 @@ static int dell_setup_rfkill(void)
229 } 357 }
230 358
231 if ((status & (1<<3|1<<9)) == (1<<3|1<<9)) { 359 if ((status & (1<<3|1<<9)) == (1<<3|1<<9)) {
232 bluetooth_rfkill = rfkill_alloc("dell-bluetooth", NULL, 360 bluetooth_rfkill = rfkill_alloc("dell-bluetooth",
361 &platform_device->dev,
233 RFKILL_TYPE_BLUETOOTH, 362 RFKILL_TYPE_BLUETOOTH,
234 &dell_rfkill_ops, (void *) 2); 363 &dell_rfkill_ops, (void *) 2);
235 if (!bluetooth_rfkill) { 364 if (!bluetooth_rfkill) {
@@ -242,7 +371,9 @@ static int dell_setup_rfkill(void)
242 } 371 }
243 372
244 if ((status & (1<<4|1<<10)) == (1<<4|1<<10)) { 373 if ((status & (1<<4|1<<10)) == (1<<4|1<<10)) {
245 wwan_rfkill = rfkill_alloc("dell-wwan", NULL, RFKILL_TYPE_WWAN, 374 wwan_rfkill = rfkill_alloc("dell-wwan",
375 &platform_device->dev,
376 RFKILL_TYPE_WWAN,
246 &dell_rfkill_ops, (void *) 3); 377 &dell_rfkill_ops, (void *) 3);
247 if (!wwan_rfkill) { 378 if (!wwan_rfkill) {
248 ret = -ENOMEM; 379 ret = -ENOMEM;
@@ -268,41 +399,67 @@ err_wifi:
268 return ret; 399 return ret;
269} 400}
270 401
402static void dell_cleanup_rfkill(void)
403{
404 if (wifi_rfkill) {
405 rfkill_unregister(wifi_rfkill);
406 rfkill_destroy(wifi_rfkill);
407 }
408 if (bluetooth_rfkill) {
409 rfkill_unregister(bluetooth_rfkill);
410 rfkill_destroy(bluetooth_rfkill);
411 }
412 if (wwan_rfkill) {
413 rfkill_unregister(wwan_rfkill);
414 rfkill_destroy(wwan_rfkill);
415 }
416}
417
271static int dell_send_intensity(struct backlight_device *bd) 418static int dell_send_intensity(struct backlight_device *bd)
272{ 419{
273 struct calling_interface_buffer buffer; 420 int ret = 0;
274 421
275 memset(&buffer, 0, sizeof(struct calling_interface_buffer)); 422 get_buffer();
276 buffer.input[0] = find_token_location(BRIGHTNESS_TOKEN); 423 buffer->input[0] = find_token_location(BRIGHTNESS_TOKEN);
277 buffer.input[1] = bd->props.brightness; 424 buffer->input[1] = bd->props.brightness;
278 425
279 if (buffer.input[0] == -1) 426 if (buffer->input[0] == -1) {
280 return -ENODEV; 427 ret = -ENODEV;
428 goto out;
429 }
281 430
282 if (power_supply_is_system_supplied() > 0) 431 if (power_supply_is_system_supplied() > 0)
283 dell_send_request(&buffer, 1, 2); 432 dell_send_request(buffer, 1, 2);
284 else 433 else
285 dell_send_request(&buffer, 1, 1); 434 dell_send_request(buffer, 1, 1);
286 435
436out:
437 release_buffer();
287 return 0; 438 return 0;
288} 439}
289 440
290static int dell_get_intensity(struct backlight_device *bd) 441static int dell_get_intensity(struct backlight_device *bd)
291{ 442{
292 struct calling_interface_buffer buffer; 443 int ret = 0;
293 444
294 memset(&buffer, 0, sizeof(struct calling_interface_buffer)); 445 get_buffer();
295 buffer.input[0] = find_token_location(BRIGHTNESS_TOKEN); 446 buffer->input[0] = find_token_location(BRIGHTNESS_TOKEN);
296 447
297 if (buffer.input[0] == -1) 448 if (buffer->input[0] == -1) {
298 return -ENODEV; 449 ret = -ENODEV;
450 goto out;
451 }
299 452
300 if (power_supply_is_system_supplied() > 0) 453 if (power_supply_is_system_supplied() > 0)
301 dell_send_request(&buffer, 0, 2); 454 dell_send_request(buffer, 0, 2);
302 else 455 else
303 dell_send_request(&buffer, 0, 1); 456 dell_send_request(buffer, 0, 1);
304 457
305 return buffer.output[1]; 458out:
459 release_buffer();
460 if (ret)
461 return ret;
462 return buffer->output[1];
306} 463}
307 464
308static struct backlight_ops dell_ops = { 465static struct backlight_ops dell_ops = {
@@ -310,9 +467,32 @@ static struct backlight_ops dell_ops = {
310 .update_status = dell_send_intensity, 467 .update_status = dell_send_intensity,
311}; 468};
312 469
470bool dell_laptop_i8042_filter(unsigned char data, unsigned char str,
471 struct serio *port)
472{
473 static bool extended;
474
475 if (str & 0x20)
476 return false;
477
478 if (unlikely(data == 0xe0)) {
479 extended = true;
480 return false;
481 } else if (unlikely(extended)) {
482 switch (data) {
483 case 0x8:
484 schedule_delayed_work(&dell_rfkill_work,
485 round_jiffies_relative(HZ));
486 break;
487 }
488 extended = false;
489 }
490
491 return false;
492}
493
313static int __init dell_init(void) 494static int __init dell_init(void)
314{ 495{
315 struct calling_interface_buffer buffer;
316 int max_intensity = 0; 496 int max_intensity = 0;
317 int ret; 497 int ret;
318 498
@@ -326,11 +506,41 @@ static int __init dell_init(void)
326 return -ENODEV; 506 return -ENODEV;
327 } 507 }
328 508
509 ret = platform_driver_register(&platform_driver);
510 if (ret)
511 goto fail_platform_driver;
512 platform_device = platform_device_alloc("dell-laptop", -1);
513 if (!platform_device) {
514 ret = -ENOMEM;
515 goto fail_platform_device1;
516 }
517 ret = platform_device_add(platform_device);
518 if (ret)
519 goto fail_platform_device2;
520
521 /*
522 * Allocate buffer below 4GB for SMI data--only 32-bit physical addr
523 * is passed to SMI handler.
524 */
525 bufferpage = alloc_page(GFP_KERNEL | GFP_DMA32);
526
527 if (!bufferpage)
528 goto fail_buffer;
529 buffer = page_address(bufferpage);
530 mutex_init(&buffer_mutex);
531
329 ret = dell_setup_rfkill(); 532 ret = dell_setup_rfkill();
330 533
331 if (ret) { 534 if (ret) {
332 printk(KERN_WARNING "dell-laptop: Unable to setup rfkill\n"); 535 printk(KERN_WARNING "dell-laptop: Unable to setup rfkill\n");
333 goto out; 536 goto fail_rfkill;
537 }
538
539 ret = i8042_install_filter(dell_laptop_i8042_filter);
540 if (ret) {
541 printk(KERN_WARNING
542 "dell-laptop: Unable to install key filter\n");
543 goto fail_filter;
334 } 544 }
335 545
336#ifdef CONFIG_ACPI 546#ifdef CONFIG_ACPI
@@ -341,53 +551,67 @@ static int __init dell_init(void)
341 return 0; 551 return 0;
342#endif 552#endif
343 553
344 memset(&buffer, 0, sizeof(struct calling_interface_buffer)); 554 get_buffer();
345 buffer.input[0] = find_token_location(BRIGHTNESS_TOKEN); 555 buffer->input[0] = find_token_location(BRIGHTNESS_TOKEN);
346 556 if (buffer->input[0] != -1) {
347 if (buffer.input[0] != -1) { 557 dell_send_request(buffer, 0, 2);
348 dell_send_request(&buffer, 0, 2); 558 max_intensity = buffer->output[3];
349 max_intensity = buffer.output[3];
350 } 559 }
560 release_buffer();
351 561
352 if (max_intensity) { 562 if (max_intensity) {
353 dell_backlight_device = backlight_device_register( 563 struct backlight_properties props;
354 "dell_backlight", 564 memset(&props, 0, sizeof(struct backlight_properties));
355 NULL, NULL, 565 props.max_brightness = max_intensity;
356 &dell_ops); 566 dell_backlight_device = backlight_device_register("dell_backlight",
567 &platform_device->dev,
568 NULL,
569 &dell_ops,
570 &props);
357 571
358 if (IS_ERR(dell_backlight_device)) { 572 if (IS_ERR(dell_backlight_device)) {
359 ret = PTR_ERR(dell_backlight_device); 573 ret = PTR_ERR(dell_backlight_device);
360 dell_backlight_device = NULL; 574 dell_backlight_device = NULL;
361 goto out; 575 goto fail_backlight;
362 } 576 }
363 577
364 dell_backlight_device->props.max_brightness = max_intensity;
365 dell_backlight_device->props.brightness = 578 dell_backlight_device->props.brightness =
366 dell_get_intensity(dell_backlight_device); 579 dell_get_intensity(dell_backlight_device);
367 backlight_update_status(dell_backlight_device); 580 backlight_update_status(dell_backlight_device);
368 } 581 }
369 582
370 return 0; 583 return 0;
371out: 584
372 if (wifi_rfkill) 585fail_backlight:
373 rfkill_unregister(wifi_rfkill); 586 i8042_remove_filter(dell_laptop_i8042_filter);
374 if (bluetooth_rfkill) 587 cancel_delayed_work_sync(&dell_rfkill_work);
375 rfkill_unregister(bluetooth_rfkill); 588fail_filter:
376 if (wwan_rfkill) 589 dell_cleanup_rfkill();
377 rfkill_unregister(wwan_rfkill); 590fail_rfkill:
591 free_page((unsigned long)bufferpage);
592fail_buffer:
593 platform_device_del(platform_device);
594fail_platform_device2:
595 platform_device_put(platform_device);
596fail_platform_device1:
597 platform_driver_unregister(&platform_driver);
598fail_platform_driver:
378 kfree(da_tokens); 599 kfree(da_tokens);
379 return ret; 600 return ret;
380} 601}
381 602
382static void __exit dell_exit(void) 603static void __exit dell_exit(void)
383{ 604{
605 i8042_remove_filter(dell_laptop_i8042_filter);
606 cancel_delayed_work_sync(&dell_rfkill_work);
384 backlight_device_unregister(dell_backlight_device); 607 backlight_device_unregister(dell_backlight_device);
385 if (wifi_rfkill) 608 dell_cleanup_rfkill();
386 rfkill_unregister(wifi_rfkill); 609 if (platform_device) {
387 if (bluetooth_rfkill) 610 platform_device_unregister(platform_device);
388 rfkill_unregister(bluetooth_rfkill); 611 platform_driver_unregister(&platform_driver);
389 if (wwan_rfkill) 612 }
390 rfkill_unregister(wwan_rfkill); 613 kfree(da_tokens);
614 free_page((unsigned long)buffer);
391} 615}
392 616
393module_init(dell_init); 617module_init(dell_init);
@@ -397,3 +621,4 @@ MODULE_AUTHOR("Matthew Garrett <mjg@redhat.com>");
397MODULE_DESCRIPTION("Dell laptop driver"); 621MODULE_DESCRIPTION("Dell laptop driver");
398MODULE_LICENSE("GPL"); 622MODULE_LICENSE("GPL");
399MODULE_ALIAS("dmi:*svnDellInc.:*:ct8:*"); 623MODULE_ALIAS("dmi:*svnDellInc.:*:ct8:*");
624MODULE_ALIAS("dmi:*svnDellComputerCorporation.:*:ct8:*");
diff --git a/drivers/platform/x86/dell-wmi.c b/drivers/platform/x86/dell-wmi.c
index 0f900cc9fa7a..66f53c3c35e8 100644
--- a/drivers/platform/x86/dell-wmi.c
+++ b/drivers/platform/x86/dell-wmi.c
@@ -26,11 +26,13 @@
26#include <linux/kernel.h> 26#include <linux/kernel.h>
27#include <linux/module.h> 27#include <linux/module.h>
28#include <linux/init.h> 28#include <linux/init.h>
29#include <linux/slab.h>
29#include <linux/types.h> 30#include <linux/types.h>
30#include <linux/input.h> 31#include <linux/input.h>
31#include <acpi/acpi_drivers.h> 32#include <acpi/acpi_drivers.h>
32#include <linux/acpi.h> 33#include <linux/acpi.h>
33#include <linux/string.h> 34#include <linux/string.h>
35#include <linux/dmi.h>
34 36
35MODULE_AUTHOR("Matthew Garrett <mjg@redhat.com>"); 37MODULE_AUTHOR("Matthew Garrett <mjg@redhat.com>");
36MODULE_DESCRIPTION("Dell laptop WMI hotkeys driver"); 38MODULE_DESCRIPTION("Dell laptop WMI hotkeys driver");
@@ -38,6 +40,8 @@ MODULE_LICENSE("GPL");
38 40
39#define DELL_EVENT_GUID "9DBB5994-A997-11DA-B012-B622A1EF5492" 41#define DELL_EVENT_GUID "9DBB5994-A997-11DA-B012-B622A1EF5492"
40 42
43static int acpi_video;
44
41MODULE_ALIAS("wmi:"DELL_EVENT_GUID); 45MODULE_ALIAS("wmi:"DELL_EVENT_GUID);
42 46
43struct key_entry { 47struct key_entry {
@@ -54,7 +58,7 @@ enum { KE_KEY, KE_SW, KE_IGNORE, KE_END };
54 * via the keyboard controller so should not be sent again. 58 * via the keyboard controller so should not be sent again.
55 */ 59 */
56 60
57static struct key_entry dell_wmi_keymap[] = { 61static struct key_entry dell_legacy_wmi_keymap[] = {
58 {KE_KEY, 0xe045, KEY_PROG1}, 62 {KE_KEY, 0xe045, KEY_PROG1},
59 {KE_KEY, 0xe009, KEY_EJECTCD}, 63 {KE_KEY, 0xe009, KEY_EJECTCD},
60 64
@@ -72,7 +76,7 @@ static struct key_entry dell_wmi_keymap[] = {
72 76
73 /* The next device is at offset 6, the active devices are at 77 /* The next device is at offset 6, the active devices are at
74 offset 8 and the attached devices at offset 10 */ 78 offset 8 and the attached devices at offset 10 */
75 {KE_KEY, 0xe00b, KEY_DISPLAYTOGGLE}, 79 {KE_KEY, 0xe00b, KEY_SWITCHVIDEOMODE},
76 80
77 {KE_IGNORE, 0xe00c, KEY_KBDILLUMTOGGLE}, 81 {KE_IGNORE, 0xe00c, KEY_KBDILLUMTOGGLE},
78 82
@@ -96,9 +100,50 @@ static struct key_entry dell_wmi_keymap[] = {
96 {KE_END, 0} 100 {KE_END, 0}
97}; 101};
98 102
103static bool dell_new_hk_type;
104
105struct dell_new_keymap_entry {
106 u16 scancode;
107 u16 keycode;
108};
109
110struct dell_hotkey_table {
111 struct dmi_header header;
112 struct dell_new_keymap_entry keymap[];
113
114};
115
116static struct key_entry *dell_new_wmi_keymap;
117
118static u16 bios_to_linux_keycode[256] = {
119
120 KEY_MEDIA, KEY_NEXTSONG, KEY_PLAYPAUSE, KEY_PREVIOUSSONG,
121 KEY_STOPCD, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,
122 KEY_WWW, KEY_UNKNOWN, KEY_VOLUMEDOWN, KEY_MUTE,
123 KEY_VOLUMEUP, KEY_UNKNOWN, KEY_BATTERY, KEY_EJECTCD,
124 KEY_UNKNOWN, KEY_SLEEP, KEY_PROG1, KEY_BRIGHTNESSDOWN,
125 KEY_BRIGHTNESSUP, KEY_UNKNOWN, KEY_KBDILLUMTOGGLE,
126 KEY_UNKNOWN, KEY_SWITCHVIDEOMODE, KEY_UNKNOWN, KEY_UNKNOWN,
127 KEY_SWITCHVIDEOMODE, KEY_UNKNOWN, KEY_UNKNOWN, KEY_PROG2,
128 KEY_UNKNOWN, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
129 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
130 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
131 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
132 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
133 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
134 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
135 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
136 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
137 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
138 KEY_PROG3
139};
140
141
142static struct key_entry *dell_wmi_keymap = dell_legacy_wmi_keymap;
143
99static struct input_dev *dell_wmi_input_dev; 144static struct input_dev *dell_wmi_input_dev;
100 145
101static struct key_entry *dell_wmi_get_entry_by_scancode(int code) 146static struct key_entry *dell_wmi_get_entry_by_scancode(unsigned int code)
102{ 147{
103 struct key_entry *key; 148 struct key_entry *key;
104 149
@@ -109,7 +154,7 @@ static struct key_entry *dell_wmi_get_entry_by_scancode(int code)
109 return NULL; 154 return NULL;
110} 155}
111 156
112static struct key_entry *dell_wmi_get_entry_by_keycode(int keycode) 157static struct key_entry *dell_wmi_get_entry_by_keycode(unsigned int keycode)
113{ 158{
114 struct key_entry *key; 159 struct key_entry *key;
115 160
@@ -120,8 +165,8 @@ static struct key_entry *dell_wmi_get_entry_by_keycode(int keycode)
120 return NULL; 165 return NULL;
121} 166}
122 167
123static int dell_wmi_getkeycode(struct input_dev *dev, int scancode, 168static int dell_wmi_getkeycode(struct input_dev *dev,
124 int *keycode) 169 unsigned int scancode, unsigned int *keycode)
125{ 170{
126 struct key_entry *key = dell_wmi_get_entry_by_scancode(scancode); 171 struct key_entry *key = dell_wmi_get_entry_by_scancode(scancode);
127 172
@@ -133,13 +178,11 @@ static int dell_wmi_getkeycode(struct input_dev *dev, int scancode,
133 return -EINVAL; 178 return -EINVAL;
134} 179}
135 180
136static int dell_wmi_setkeycode(struct input_dev *dev, int scancode, int keycode) 181static int dell_wmi_setkeycode(struct input_dev *dev,
182 unsigned int scancode, unsigned int keycode)
137{ 183{
138 struct key_entry *key; 184 struct key_entry *key;
139 int old_keycode; 185 unsigned int old_keycode;
140
141 if (keycode < 0 || keycode > KEY_MAX)
142 return -EINVAL;
143 186
144 key = dell_wmi_get_entry_by_scancode(scancode); 187 key = dell_wmi_get_entry_by_scancode(scancode);
145 if (key && key->type == KE_KEY) { 188 if (key && key->type == KE_KEY) {
@@ -158,30 +201,91 @@ static void dell_wmi_notify(u32 value, void *context)
158 struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL }; 201 struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL };
159 static struct key_entry *key; 202 static struct key_entry *key;
160 union acpi_object *obj; 203 union acpi_object *obj;
204 acpi_status status;
161 205
162 wmi_get_event_data(value, &response); 206 status = wmi_get_event_data(value, &response);
207 if (status != AE_OK) {
208 printk(KERN_INFO "dell-wmi: bad event status 0x%x\n", status);
209 return;
210 }
163 211
164 obj = (union acpi_object *)response.pointer; 212 obj = (union acpi_object *)response.pointer;
165 213
166 if (obj && obj->type == ACPI_TYPE_BUFFER) { 214 if (obj && obj->type == ACPI_TYPE_BUFFER) {
167 int *buffer = (int *)obj->buffer.pointer; 215 int reported_key;
168 /* 216 u16 *buffer_entry = (u16 *)obj->buffer.pointer;
169 * The upper bytes of the event may contain 217 if (dell_new_hk_type && (buffer_entry[1] != 0x10)) {
170 * additional information, so mask them off for the 218 printk(KERN_INFO "dell-wmi: Received unknown WMI event"
171 * scancode lookup 219 " (0x%x)\n", buffer_entry[1]);
172 */ 220 kfree(obj);
173 key = dell_wmi_get_entry_by_scancode(buffer[1] & 0xFFFF); 221 return;
174 if (key) { 222 }
223
224 if (dell_new_hk_type)
225 reported_key = (int)buffer_entry[2];
226 else
227 reported_key = (int)buffer_entry[1] & 0xffff;
228
229 key = dell_wmi_get_entry_by_scancode(reported_key);
230
231 if (!key) {
232 printk(KERN_INFO "dell-wmi: Unknown key %x pressed\n",
233 reported_key);
234 } else if ((key->keycode == KEY_BRIGHTNESSUP ||
235 key->keycode == KEY_BRIGHTNESSDOWN) && acpi_video) {
236 /* Don't report brightness notifications that will also
237 * come via ACPI */
238 ;
239 } else {
175 input_report_key(dell_wmi_input_dev, key->keycode, 1); 240 input_report_key(dell_wmi_input_dev, key->keycode, 1);
176 input_sync(dell_wmi_input_dev); 241 input_sync(dell_wmi_input_dev);
177 input_report_key(dell_wmi_input_dev, key->keycode, 0); 242 input_report_key(dell_wmi_input_dev, key->keycode, 0);
178 input_sync(dell_wmi_input_dev); 243 input_sync(dell_wmi_input_dev);
179 } else if (buffer[1] & 0xFFFF) 244 }
180 printk(KERN_INFO "dell-wmi: Unknown key %x pressed\n",
181 buffer[1] & 0xFFFF);
182 } 245 }
246 kfree(obj);
183} 247}
184 248
249
250static void setup_new_hk_map(const struct dmi_header *dm)
251{
252
253 int i;
254 int hotkey_num = (dm->length-4)/sizeof(struct dell_new_keymap_entry);
255 struct dell_hotkey_table *table =
256 container_of(dm, struct dell_hotkey_table, header);
257
258 dell_new_wmi_keymap = kzalloc((hotkey_num+1) *
259 sizeof(struct key_entry), GFP_KERNEL);
260
261 for (i = 0; i < hotkey_num; i++) {
262 dell_new_wmi_keymap[i].type = KE_KEY;
263 dell_new_wmi_keymap[i].code = table->keymap[i].scancode;
264 dell_new_wmi_keymap[i].keycode =
265 (table->keymap[i].keycode > 255) ? 0 :
266 bios_to_linux_keycode[table->keymap[i].keycode];
267 }
268
269 dell_new_wmi_keymap[i].type = KE_END;
270 dell_new_wmi_keymap[i].code = 0;
271 dell_new_wmi_keymap[i].keycode = 0;
272
273 dell_wmi_keymap = dell_new_wmi_keymap;
274
275}
276
277
278static void find_hk_type(const struct dmi_header *dm, void *dummy)
279{
280
281 if ((dm->type == 0xb2) && (dm->length > 6)) {
282 dell_new_hk_type = true;
283 setup_new_hk_map(dm);
284 }
285
286}
287
288
185static int __init dell_wmi_input_setup(void) 289static int __init dell_wmi_input_setup(void)
186{ 290{
187 struct key_entry *key; 291 struct key_entry *key;
@@ -224,34 +328,37 @@ static int __init dell_wmi_input_setup(void)
224static int __init dell_wmi_init(void) 328static int __init dell_wmi_init(void)
225{ 329{
226 int err; 330 int err;
331 acpi_status status;
227 332
228 if (wmi_has_guid(DELL_EVENT_GUID)) { 333 if (!wmi_has_guid(DELL_EVENT_GUID)) {
229 err = dell_wmi_input_setup(); 334 printk(KERN_WARNING "dell-wmi: No known WMI GUID found\n");
335 return -ENODEV;
336 }
230 337
231 if (err) 338 dmi_walk(find_hk_type, NULL);
232 return err; 339 acpi_video = acpi_video_backlight_support();
233 340
234 err = wmi_install_notify_handler(DELL_EVENT_GUID, 341 err = dell_wmi_input_setup();
235 dell_wmi_notify, NULL); 342 if (err)
236 if (err) { 343 return err;
237 input_unregister_device(dell_wmi_input_dev);
238 printk(KERN_ERR "dell-wmi: Unable to register"
239 " notify handler - %d\n", err);
240 return err;
241 }
242 344
243 } else 345 status = wmi_install_notify_handler(DELL_EVENT_GUID,
244 printk(KERN_WARNING "dell-wmi: No known WMI GUID found\n"); 346 dell_wmi_notify, NULL);
347 if (ACPI_FAILURE(status)) {
348 input_unregister_device(dell_wmi_input_dev);
349 printk(KERN_ERR
350 "dell-wmi: Unable to register notify handler - %d\n",
351 status);
352 return -ENODEV;
353 }
245 354
246 return 0; 355 return 0;
247} 356}
248 357
249static void __exit dell_wmi_exit(void) 358static void __exit dell_wmi_exit(void)
250{ 359{
251 if (wmi_has_guid(DELL_EVENT_GUID)) { 360 wmi_remove_notify_handler(DELL_EVENT_GUID);
252 wmi_remove_notify_handler(DELL_EVENT_GUID); 361 input_unregister_device(dell_wmi_input_dev);
253 input_unregister_device(dell_wmi_input_dev);
254 }
255} 362}
256 363
257module_init(dell_wmi_init); 364module_init(dell_wmi_init);
diff --git a/drivers/platform/x86/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c
index 4226e5352738..0306174ba875 100644
--- a/drivers/platform/x86/eeepc-laptop.c
+++ b/drivers/platform/x86/eeepc-laptop.c
@@ -1,5 +1,5 @@
1/* 1/*
2 * eepc-laptop.c - Asus Eee PC extras 2 * eeepc-laptop.c - Asus Eee PC extras
3 * 3 *
4 * Based on asus_acpi.c as patched for the Eee PC by Asus: 4 * Based on asus_acpi.c as patched for the Eee PC by Asus:
5 * ftp://ftp.asus.com/pub/ASUS/EeePC/701/ASUS_ACPI_071126.rar 5 * ftp://ftp.asus.com/pub/ASUS/EeePC/701/ASUS_ACPI_071126.rar
@@ -27,27 +27,41 @@
27#include <linux/fb.h> 27#include <linux/fb.h>
28#include <linux/hwmon.h> 28#include <linux/hwmon.h>
29#include <linux/hwmon-sysfs.h> 29#include <linux/hwmon-sysfs.h>
30#include <linux/slab.h>
30#include <acpi/acpi_drivers.h> 31#include <acpi/acpi_drivers.h>
31#include <acpi/acpi_bus.h> 32#include <acpi/acpi_bus.h>
32#include <linux/uaccess.h> 33#include <linux/uaccess.h>
33#include <linux/input.h> 34#include <linux/input.h>
35#include <linux/input/sparse-keymap.h>
34#include <linux/rfkill.h> 36#include <linux/rfkill.h>
35#include <linux/pci.h> 37#include <linux/pci.h>
36#include <linux/pci_hotplug.h> 38#include <linux/pci_hotplug.h>
39#include <linux/leds.h>
40#include <linux/dmi.h>
37 41
38#define EEEPC_LAPTOP_VERSION "0.1" 42#define EEEPC_LAPTOP_VERSION "0.1"
43#define EEEPC_LAPTOP_NAME "Eee PC Hotkey Driver"
44#define EEEPC_LAPTOP_FILE "eeepc"
39 45
40#define EEEPC_HOTK_NAME "Eee PC Hotkey Driver" 46#define EEEPC_ACPI_CLASS "hotkey"
41#define EEEPC_HOTK_FILE "eeepc" 47#define EEEPC_ACPI_DEVICE_NAME "Hotkey"
42#define EEEPC_HOTK_CLASS "hotkey" 48#define EEEPC_ACPI_HID "ASUS010"
43#define EEEPC_HOTK_DEVICE_NAME "Hotkey"
44#define EEEPC_HOTK_HID "ASUS010"
45 49
50MODULE_AUTHOR("Corentin Chary, Eric Cooper");
51MODULE_DESCRIPTION(EEEPC_LAPTOP_NAME);
52MODULE_LICENSE("GPL");
53
54static bool hotplug_disabled;
55
56module_param(hotplug_disabled, bool, 0644);
57MODULE_PARM_DESC(hotplug_disabled,
58 "Disable hotplug for wireless device. "
59 "If your laptop need that, please report to "
60 "acpi4asus-user@lists.sourceforge.net.");
46 61
47/* 62/*
48 * Definitions for Asus EeePC 63 * Definitions for Asus EeePC
49 */ 64 */
50#define NOTIFY_WLAN_ON 0x10
51#define NOTIFY_BRN_MIN 0x20 65#define NOTIFY_BRN_MIN 0x20
52#define NOTIFY_BRN_MAX 0x2f 66#define NOTIFY_BRN_MAX 0x2f
53 67
@@ -117,145 +131,63 @@ static const char *cm_setv[] = {
117 NULL, NULL, "PBPS", "TPDS" 131 NULL, NULL, "PBPS", "TPDS"
118}; 132};
119 133
120#define EEEPC_EC "\\_SB.PCI0.SBRG.EC0." 134static const struct key_entry eeepc_keymap[] = {
121 135 { KE_KEY, 0x10, { KEY_WLAN } },
122#define EEEPC_EC_FAN_PWM EEEPC_EC "SC02" /* Fan PWM duty cycle (%) */ 136 { KE_KEY, 0x11, { KEY_WLAN } },
123#define EEEPC_EC_SC02 0x63 137 { KE_KEY, 0x12, { KEY_PROG1 } },
124#define EEEPC_EC_FAN_HRPM EEEPC_EC "SC05" /* High byte, fan speed (RPM) */ 138 { KE_KEY, 0x13, { KEY_MUTE } },
125#define EEEPC_EC_FAN_LRPM EEEPC_EC "SC06" /* Low byte, fan speed (RPM) */ 139 { KE_KEY, 0x14, { KEY_VOLUMEDOWN } },
126#define EEEPC_EC_FAN_CTRL EEEPC_EC "SFB3" /* Byte containing SF25 */ 140 { KE_KEY, 0x15, { KEY_VOLUMEUP } },
127#define EEEPC_EC_SFB3 0xD3 141 { KE_KEY, 0x16, { KEY_DISPLAY_OFF } },
142 { KE_KEY, 0x1a, { KEY_COFFEE } },
143 { KE_KEY, 0x1b, { KEY_ZOOM } },
144 { KE_KEY, 0x1c, { KEY_PROG2 } },
145 { KE_KEY, 0x1d, { KEY_PROG3 } },
146 { KE_KEY, NOTIFY_BRN_MIN, { KEY_BRIGHTNESSDOWN } },
147 { KE_KEY, NOTIFY_BRN_MAX, { KEY_BRIGHTNESSUP } },
148 { KE_KEY, 0x30, { KEY_SWITCHVIDEOMODE } },
149 { KE_KEY, 0x31, { KEY_SWITCHVIDEOMODE } },
150 { KE_KEY, 0x32, { KEY_SWITCHVIDEOMODE } },
151 { KE_KEY, 0x37, { KEY_F13 } }, /* Disable Touchpad */
152 { KE_KEY, 0x38, { KEY_F14 } },
153 { KE_END, 0 },
154};
128 155
129/* 156/*
130 * This is the main structure, we can use it to store useful information 157 * This is the main structure, we can use it to store useful information
131 * about the hotk device
132 */ 158 */
133struct eeepc_hotk { 159struct eeepc_laptop {
134 struct acpi_device *device; /* the device we are in */ 160 acpi_handle handle; /* the handle of the acpi device */
135 acpi_handle handle; /* the handle of the hotk device */
136 u32 cm_supported; /* the control methods supported 161 u32 cm_supported; /* the control methods supported
137 by this BIOS */ 162 by this BIOS */
138 uint init_flag; /* Init flags */ 163 bool cpufv_disabled;
164 bool hotplug_disabled;
139 u16 event_count[128]; /* count for each event */ 165 u16 event_count[128]; /* count for each event */
166
167 struct platform_device *platform_device;
168 struct device *hwmon_device;
169 struct backlight_device *backlight_device;
170
140 struct input_dev *inputdev; 171 struct input_dev *inputdev;
141 u16 *keycode_map; 172
142 struct rfkill *wlan_rfkill; 173 struct rfkill *wlan_rfkill;
143 struct rfkill *bluetooth_rfkill; 174 struct rfkill *bluetooth_rfkill;
144 struct rfkill *wwan3g_rfkill; 175 struct rfkill *wwan3g_rfkill;
145 struct rfkill *wimax_rfkill; 176 struct rfkill *wimax_rfkill;
177
146 struct hotplug_slot *hotplug_slot; 178 struct hotplug_slot *hotplug_slot;
147 struct mutex hotplug_lock; 179 struct mutex hotplug_lock;
148};
149
150/* The actual device the driver binds to */
151static struct eeepc_hotk *ehotk;
152
153/* Platform device/driver */
154static int eeepc_hotk_thaw(struct device *device);
155static int eeepc_hotk_restore(struct device *device);
156
157static struct dev_pm_ops eeepc_pm_ops = {
158 .thaw = eeepc_hotk_thaw,
159 .restore = eeepc_hotk_restore,
160};
161
162static struct platform_driver platform_driver = {
163 .driver = {
164 .name = EEEPC_HOTK_FILE,
165 .owner = THIS_MODULE,
166 .pm = &eeepc_pm_ops,
167 }
168};
169
170static struct platform_device *platform_device;
171
172struct key_entry {
173 char type;
174 u8 code;
175 u16 keycode;
176};
177
178enum { KE_KEY, KE_END };
179
180static struct key_entry eeepc_keymap[] = {
181 /* Sleep already handled via generic ACPI code */
182 {KE_KEY, 0x10, KEY_WLAN },
183 {KE_KEY, 0x11, KEY_WLAN },
184 {KE_KEY, 0x12, KEY_PROG1 },
185 {KE_KEY, 0x13, KEY_MUTE },
186 {KE_KEY, 0x14, KEY_VOLUMEDOWN },
187 {KE_KEY, 0x15, KEY_VOLUMEUP },
188 {KE_KEY, 0x1a, KEY_COFFEE },
189 {KE_KEY, 0x1b, KEY_ZOOM },
190 {KE_KEY, 0x1c, KEY_PROG2 },
191 {KE_KEY, 0x1d, KEY_PROG3 },
192 {KE_KEY, NOTIFY_BRN_MIN, KEY_BRIGHTNESSDOWN },
193 {KE_KEY, NOTIFY_BRN_MIN + 2, KEY_BRIGHTNESSUP },
194 {KE_KEY, 0x30, KEY_SWITCHVIDEOMODE },
195 {KE_KEY, 0x31, KEY_SWITCHVIDEOMODE },
196 {KE_KEY, 0x32, KEY_SWITCHVIDEOMODE },
197 {KE_END, 0},
198};
199
200/*
201 * The hotkey driver declaration
202 */
203static int eeepc_hotk_add(struct acpi_device *device);
204static int eeepc_hotk_remove(struct acpi_device *device, int type);
205static void eeepc_hotk_notify(struct acpi_device *device, u32 event);
206
207static const struct acpi_device_id eeepc_device_ids[] = {
208 {EEEPC_HOTK_HID, 0},
209 {"", 0},
210};
211MODULE_DEVICE_TABLE(acpi, eeepc_device_ids);
212
213static struct acpi_driver eeepc_hotk_driver = {
214 .name = EEEPC_HOTK_NAME,
215 .class = EEEPC_HOTK_CLASS,
216 .ids = eeepc_device_ids,
217 .flags = ACPI_DRIVER_ALL_NOTIFY_EVENTS,
218 .ops = {
219 .add = eeepc_hotk_add,
220 .remove = eeepc_hotk_remove,
221 .notify = eeepc_hotk_notify,
222 },
223};
224
225/* PCI hotplug ops */
226static int eeepc_get_adapter_status(struct hotplug_slot *slot, u8 *value);
227 180
228static struct hotplug_slot_ops eeepc_hotplug_slot_ops = { 181 struct led_classdev tpd_led;
229 .owner = THIS_MODULE, 182 int tpd_led_wk;
230 .get_adapter_status = eeepc_get_adapter_status, 183 struct workqueue_struct *led_workqueue;
231 .get_power_status = eeepc_get_adapter_status, 184 struct work_struct tpd_led_work;
232}; 185};
233 186
234/* The backlight device /sys/class/backlight */
235static struct backlight_device *eeepc_backlight_device;
236
237/* The hwmon device */
238static struct device *eeepc_hwmon_device;
239
240/*
241 * The backlight class declaration
242 */
243static int read_brightness(struct backlight_device *bd);
244static int update_bl_status(struct backlight_device *bd);
245static struct backlight_ops eeepcbl_ops = {
246 .get_brightness = read_brightness,
247 .update_status = update_bl_status,
248};
249
250MODULE_AUTHOR("Corentin Chary, Eric Cooper");
251MODULE_DESCRIPTION(EEEPC_HOTK_NAME);
252MODULE_LICENSE("GPL");
253
254/* 187/*
255 * ACPI Helpers 188 * ACPI Helpers
256 */ 189 */
257static int write_acpi_int(acpi_handle handle, const char *method, int val, 190static int write_acpi_int(acpi_handle handle, const char *method, int val)
258 struct acpi_buffer *output)
259{ 191{
260 struct acpi_object_list params; 192 struct acpi_object_list params;
261 union acpi_object in_obj; 193 union acpi_object in_obj;
@@ -266,7 +198,7 @@ static int write_acpi_int(acpi_handle handle, const char *method, int val,
266 in_obj.type = ACPI_TYPE_INTEGER; 198 in_obj.type = ACPI_TYPE_INTEGER;
267 in_obj.integer.value = val; 199 in_obj.integer.value = val;
268 200
269 status = acpi_evaluate_object(handle, (char *)method, &params, output); 201 status = acpi_evaluate_object(handle, (char *)method, &params, NULL);
270 return (status == AE_OK ? 0 : -1); 202 return (status == AE_OK ? 0 : -1);
271} 203}
272 204
@@ -285,81 +217,56 @@ static int read_acpi_int(acpi_handle handle, const char *method, int *val)
285 } 217 }
286} 218}
287 219
288static int set_acpi(int cm, int value) 220static int set_acpi(struct eeepc_laptop *eeepc, int cm, int value)
289{ 221{
290 if (ehotk->cm_supported & (0x1 << cm)) { 222 const char *method = cm_setv[cm];
291 const char *method = cm_setv[cm];
292 if (method == NULL)
293 return -ENODEV;
294 if (write_acpi_int(ehotk->handle, method, value, NULL))
295 pr_warning("Error writing %s\n", method);
296 }
297 return 0;
298}
299
300static int get_acpi(int cm)
301{
302 int value = -ENODEV;
303 if ((ehotk->cm_supported & (0x1 << cm))) {
304 const char *method = cm_getv[cm];
305 if (method == NULL)
306 return -ENODEV;
307 if (read_acpi_int(ehotk->handle, method, &value))
308 pr_warning("Error reading %s\n", method);
309 }
310 return value;
311}
312 223
313/* 224 if (method == NULL)
314 * Backlight 225 return -ENODEV;
315 */ 226 if ((eeepc->cm_supported & (0x1 << cm)) == 0)
316static int read_brightness(struct backlight_device *bd) 227 return -ENODEV;
317{
318 return get_acpi(CM_ASL_PANELBRIGHT);
319}
320 228
321static int set_brightness(struct backlight_device *bd, int value) 229 if (write_acpi_int(eeepc->handle, method, value))
322{ 230 pr_warning("Error writing %s\n", method);
323 value = max(0, min(15, value)); 231 return 0;
324 return set_acpi(CM_ASL_PANELBRIGHT, value);
325} 232}
326 233
327static int update_bl_status(struct backlight_device *bd) 234static int get_acpi(struct eeepc_laptop *eeepc, int cm)
328{ 235{
329 return set_brightness(bd, bd->props.brightness); 236 const char *method = cm_getv[cm];
330} 237 int value;
331 238
332/* 239 if (method == NULL)
333 * Rfkill helpers 240 return -ENODEV;
334 */ 241 if ((eeepc->cm_supported & (0x1 << cm)) == 0)
242 return -ENODEV;
335 243
336static bool eeepc_wlan_rfkill_blocked(void) 244 if (read_acpi_int(eeepc->handle, method, &value))
337{ 245 pr_warning("Error reading %s\n", method);
338 if (get_acpi(CM_ASL_WLAN) == 1) 246 return value;
339 return false;
340 return true;
341} 247}
342 248
343static int eeepc_rfkill_set(void *data, bool blocked) 249static int acpi_setter_handle(struct eeepc_laptop *eeepc, int cm,
250 acpi_handle *handle)
344{ 251{
345 unsigned long asl = (unsigned long)data; 252 const char *method = cm_setv[cm];
346 return set_acpi(asl, !blocked); 253 acpi_status status;
347}
348 254
349static const struct rfkill_ops eeepc_rfkill_ops = { 255 if (method == NULL)
350 .set_block = eeepc_rfkill_set, 256 return -ENODEV;
351}; 257 if ((eeepc->cm_supported & (0x1 << cm)) == 0)
258 return -ENODEV;
352 259
353static void __devinit eeepc_enable_camera(void) 260 status = acpi_get_handle(eeepc->handle, (char *)method,
354{ 261 handle);
355 /* 262 if (status != AE_OK) {
356 * If the following call to set_acpi() fails, it's because there's no 263 pr_warning("Error finding %s\n", method);
357 * camera so we can ignore the error. 264 return -ENODEV;
358 */ 265 }
359 if (get_acpi(CM_ASL_CAMERA) == 0) 266 return 0;
360 set_acpi(CM_ASL_CAMERA, 1);
361} 267}
362 268
269
363/* 270/*
364 * Sys helpers 271 * Sys helpers
365 */ 272 */
@@ -372,60 +279,63 @@ static int parse_arg(const char *buf, unsigned long count, int *val)
372 return count; 279 return count;
373} 280}
374 281
375static ssize_t store_sys_acpi(int cm, const char *buf, size_t count) 282static ssize_t store_sys_acpi(struct device *dev, int cm,
283 const char *buf, size_t count)
376{ 284{
285 struct eeepc_laptop *eeepc = dev_get_drvdata(dev);
377 int rv, value; 286 int rv, value;
378 287
379 rv = parse_arg(buf, count, &value); 288 rv = parse_arg(buf, count, &value);
380 if (rv > 0) 289 if (rv > 0)
381 value = set_acpi(cm, value); 290 value = set_acpi(eeepc, cm, value);
382 if (value < 0) 291 if (value < 0)
383 return value; 292 return -EIO;
384 return rv; 293 return rv;
385} 294}
386 295
387static ssize_t show_sys_acpi(int cm, char *buf) 296static ssize_t show_sys_acpi(struct device *dev, int cm, char *buf)
388{ 297{
389 int value = get_acpi(cm); 298 struct eeepc_laptop *eeepc = dev_get_drvdata(dev);
299 int value = get_acpi(eeepc, cm);
390 300
391 if (value < 0) 301 if (value < 0)
392 return value; 302 return -EIO;
393 return sprintf(buf, "%d\n", value); 303 return sprintf(buf, "%d\n", value);
394} 304}
395 305
396#define EEEPC_CREATE_DEVICE_ATTR(_name, _cm) \ 306#define EEEPC_CREATE_DEVICE_ATTR(_name, _mode, _cm) \
397 static ssize_t show_##_name(struct device *dev, \ 307 static ssize_t show_##_name(struct device *dev, \
398 struct device_attribute *attr, \ 308 struct device_attribute *attr, \
399 char *buf) \ 309 char *buf) \
400 { \ 310 { \
401 return show_sys_acpi(_cm, buf); \ 311 return show_sys_acpi(dev, _cm, buf); \
402 } \ 312 } \
403 static ssize_t store_##_name(struct device *dev, \ 313 static ssize_t store_##_name(struct device *dev, \
404 struct device_attribute *attr, \ 314 struct device_attribute *attr, \
405 const char *buf, size_t count) \ 315 const char *buf, size_t count) \
406 { \ 316 { \
407 return store_sys_acpi(_cm, buf, count); \ 317 return store_sys_acpi(dev, _cm, buf, count); \
408 } \ 318 } \
409 static struct device_attribute dev_attr_##_name = { \ 319 static struct device_attribute dev_attr_##_name = { \
410 .attr = { \ 320 .attr = { \
411 .name = __stringify(_name), \ 321 .name = __stringify(_name), \
412 .mode = 0644 }, \ 322 .mode = _mode }, \
413 .show = show_##_name, \ 323 .show = show_##_name, \
414 .store = store_##_name, \ 324 .store = store_##_name, \
415 } 325 }
416 326
417EEEPC_CREATE_DEVICE_ATTR(camera, CM_ASL_CAMERA); 327EEEPC_CREATE_DEVICE_ATTR(camera, 0644, CM_ASL_CAMERA);
418EEEPC_CREATE_DEVICE_ATTR(cardr, CM_ASL_CARDREADER); 328EEEPC_CREATE_DEVICE_ATTR(cardr, 0644, CM_ASL_CARDREADER);
419EEEPC_CREATE_DEVICE_ATTR(disp, CM_ASL_DISPLAYSWITCH); 329EEEPC_CREATE_DEVICE_ATTR(disp, 0200, CM_ASL_DISPLAYSWITCH);
420 330
421struct eeepc_cpufv { 331struct eeepc_cpufv {
422 int num; 332 int num;
423 int cur; 333 int cur;
424}; 334};
425 335
426static int get_cpufv(struct eeepc_cpufv *c) 336static int get_cpufv(struct eeepc_laptop *eeepc, struct eeepc_cpufv *c)
427{ 337{
428 c->cur = get_acpi(CM_ASL_CPUFV); 338 c->cur = get_acpi(eeepc, CM_ASL_CPUFV);
429 c->num = (c->cur >> 8) & 0xff; 339 c->num = (c->cur >> 8) & 0xff;
430 c->cur &= 0xff; 340 c->cur &= 0xff;
431 if (c->cur < 0 || c->num <= 0 || c->num > 12) 341 if (c->cur < 0 || c->num <= 0 || c->num > 12)
@@ -437,11 +347,12 @@ static ssize_t show_available_cpufv(struct device *dev,
437 struct device_attribute *attr, 347 struct device_attribute *attr,
438 char *buf) 348 char *buf)
439{ 349{
350 struct eeepc_laptop *eeepc = dev_get_drvdata(dev);
440 struct eeepc_cpufv c; 351 struct eeepc_cpufv c;
441 int i; 352 int i;
442 ssize_t len = 0; 353 ssize_t len = 0;
443 354
444 if (get_cpufv(&c)) 355 if (get_cpufv(eeepc, &c))
445 return -ENODEV; 356 return -ENODEV;
446 for (i = 0; i < c.num; i++) 357 for (i = 0; i < c.num; i++)
447 len += sprintf(buf + len, "%d ", i); 358 len += sprintf(buf + len, "%d ", i);
@@ -453,9 +364,10 @@ static ssize_t show_cpufv(struct device *dev,
453 struct device_attribute *attr, 364 struct device_attribute *attr,
454 char *buf) 365 char *buf)
455{ 366{
367 struct eeepc_laptop *eeepc = dev_get_drvdata(dev);
456 struct eeepc_cpufv c; 368 struct eeepc_cpufv c;
457 369
458 if (get_cpufv(&c)) 370 if (get_cpufv(eeepc, &c))
459 return -ENODEV; 371 return -ENODEV;
460 return sprintf(buf, "%#x\n", (c.num << 8) | c.cur); 372 return sprintf(buf, "%#x\n", (c.num << 8) | c.cur);
461} 373}
@@ -464,20 +376,58 @@ static ssize_t store_cpufv(struct device *dev,
464 struct device_attribute *attr, 376 struct device_attribute *attr,
465 const char *buf, size_t count) 377 const char *buf, size_t count)
466{ 378{
379 struct eeepc_laptop *eeepc = dev_get_drvdata(dev);
467 struct eeepc_cpufv c; 380 struct eeepc_cpufv c;
468 int rv, value; 381 int rv, value;
469 382
470 if (get_cpufv(&c)) 383 if (eeepc->cpufv_disabled)
384 return -EPERM;
385 if (get_cpufv(eeepc, &c))
471 return -ENODEV; 386 return -ENODEV;
472 rv = parse_arg(buf, count, &value); 387 rv = parse_arg(buf, count, &value);
473 if (rv < 0) 388 if (rv < 0)
474 return rv; 389 return rv;
475 if (!rv || value < 0 || value >= c.num) 390 if (!rv || value < 0 || value >= c.num)
476 return -EINVAL; 391 return -EINVAL;
477 set_acpi(CM_ASL_CPUFV, value); 392 set_acpi(eeepc, CM_ASL_CPUFV, value);
478 return rv; 393 return rv;
479} 394}
480 395
396static ssize_t show_cpufv_disabled(struct device *dev,
397 struct device_attribute *attr,
398 char *buf)
399{
400 struct eeepc_laptop *eeepc = dev_get_drvdata(dev);
401
402 return sprintf(buf, "%d\n", eeepc->cpufv_disabled);
403}
404
405static ssize_t store_cpufv_disabled(struct device *dev,
406 struct device_attribute *attr,
407 const char *buf, size_t count)
408{
409 struct eeepc_laptop *eeepc = dev_get_drvdata(dev);
410 int rv, value;
411
412 rv = parse_arg(buf, count, &value);
413 if (rv < 0)
414 return rv;
415
416 switch (value) {
417 case 0:
418 if (eeepc->cpufv_disabled)
419 pr_warning("cpufv enabled (not officially supported "
420 "on this model)\n");
421 eeepc->cpufv_disabled = false;
422 return rv;
423 case 1:
424 return -EPERM;
425 default:
426 return -EINVAL;
427 }
428}
429
430
481static struct device_attribute dev_attr_cpufv = { 431static struct device_attribute dev_attr_cpufv = {
482 .attr = { 432 .attr = {
483 .name = "cpufv", 433 .name = "cpufv",
@@ -493,12 +443,22 @@ static struct device_attribute dev_attr_available_cpufv = {
493 .show = show_available_cpufv 443 .show = show_available_cpufv
494}; 444};
495 445
446static struct device_attribute dev_attr_cpufv_disabled = {
447 .attr = {
448 .name = "cpufv_disabled",
449 .mode = 0644 },
450 .show = show_cpufv_disabled,
451 .store = store_cpufv_disabled
452};
453
454
496static struct attribute *platform_attributes[] = { 455static struct attribute *platform_attributes[] = {
497 &dev_attr_camera.attr, 456 &dev_attr_camera.attr,
498 &dev_attr_cardr.attr, 457 &dev_attr_cardr.attr,
499 &dev_attr_disp.attr, 458 &dev_attr_disp.attr,
500 &dev_attr_cpufv.attr, 459 &dev_attr_cpufv.attr,
501 &dev_attr_available_cpufv.attr, 460 &dev_attr_available_cpufv.attr,
461 &dev_attr_cpufv_disabled.attr,
502 NULL 462 NULL
503}; 463};
504 464
@@ -506,162 +466,149 @@ static struct attribute_group platform_attribute_group = {
506 .attrs = platform_attributes 466 .attrs = platform_attributes
507}; 467};
508 468
509/* 469static int eeepc_platform_init(struct eeepc_laptop *eeepc)
510 * Hotkey functions
511 */
512static struct key_entry *eepc_get_entry_by_scancode(int code)
513{ 470{
514 struct key_entry *key; 471 int result;
515
516 for (key = eeepc_keymap; key->type != KE_END; key++)
517 if (code == key->code)
518 return key;
519 472
520 return NULL; 473 eeepc->platform_device = platform_device_alloc(EEEPC_LAPTOP_FILE, -1);
521} 474 if (!eeepc->platform_device)
475 return -ENOMEM;
476 platform_set_drvdata(eeepc->platform_device, eeepc);
522 477
523static struct key_entry *eepc_get_entry_by_keycode(int code) 478 result = platform_device_add(eeepc->platform_device);
524{ 479 if (result)
525 struct key_entry *key; 480 goto fail_platform_device;
526 481
527 for (key = eeepc_keymap; key->type != KE_END; key++) 482 result = sysfs_create_group(&eeepc->platform_device->dev.kobj,
528 if (code == key->keycode && key->type == KE_KEY) 483 &platform_attribute_group);
529 return key; 484 if (result)
485 goto fail_sysfs;
486 return 0;
530 487
531 return NULL; 488fail_sysfs:
489 platform_device_del(eeepc->platform_device);
490fail_platform_device:
491 platform_device_put(eeepc->platform_device);
492 return result;
532} 493}
533 494
534static int eeepc_getkeycode(struct input_dev *dev, int scancode, int *keycode) 495static void eeepc_platform_exit(struct eeepc_laptop *eeepc)
535{ 496{
536 struct key_entry *key = eepc_get_entry_by_scancode(scancode); 497 sysfs_remove_group(&eeepc->platform_device->dev.kobj,
498 &platform_attribute_group);
499 platform_device_unregister(eeepc->platform_device);
500}
537 501
538 if (key && key->type == KE_KEY) { 502/*
539 *keycode = key->keycode; 503 * LEDs
540 return 0; 504 */
541 } 505/*
506 * These functions actually update the LED's, and are called from a
507 * workqueue. By doing this as separate work rather than when the LED
508 * subsystem asks, we avoid messing with the Asus ACPI stuff during a
509 * potentially bad time, such as a timer interrupt.
510 */
511static void tpd_led_update(struct work_struct *work)
512 {
513 struct eeepc_laptop *eeepc;
514
515 eeepc = container_of(work, struct eeepc_laptop, tpd_led_work);
542 516
543 return -EINVAL; 517 set_acpi(eeepc, CM_ASL_TPD, eeepc->tpd_led_wk);
544} 518}
545 519
546static int eeepc_setkeycode(struct input_dev *dev, int scancode, int keycode) 520static void tpd_led_set(struct led_classdev *led_cdev,
521 enum led_brightness value)
547{ 522{
548 struct key_entry *key; 523 struct eeepc_laptop *eeepc;
549 int old_keycode;
550 524
551 if (keycode < 0 || keycode > KEY_MAX) 525 eeepc = container_of(led_cdev, struct eeepc_laptop, tpd_led);
552 return -EINVAL;
553 526
554 key = eepc_get_entry_by_scancode(scancode); 527 eeepc->tpd_led_wk = (value > 0) ? 1 : 0;
555 if (key && key->type == KE_KEY) { 528 queue_work(eeepc->led_workqueue, &eeepc->tpd_led_work);
556 old_keycode = key->keycode;
557 key->keycode = keycode;
558 set_bit(keycode, dev->keybit);
559 if (!eepc_get_entry_by_keycode(old_keycode))
560 clear_bit(old_keycode, dev->keybit);
561 return 0;
562 }
563
564 return -EINVAL;
565} 529}
566 530
567static void cmsg_quirk(int cm, const char *name) 531static int eeepc_led_init(struct eeepc_laptop *eeepc)
568{ 532{
569 int dummy; 533 int rv;
570 534
571 /* Some BIOSes do not report cm although it is avaliable. 535 if (get_acpi(eeepc, CM_ASL_TPD) == -ENODEV)
572 Check if cm_getv[cm] works and, if yes, assume cm should be set. */ 536 return 0;
573 if (!(ehotk->cm_supported & (1 << cm))
574 && !read_acpi_int(ehotk->handle, cm_getv[cm], &dummy)) {
575 pr_info("%s (%x) not reported by BIOS,"
576 " enabling anyway\n", name, 1 << cm);
577 ehotk->cm_supported |= 1 << cm;
578 }
579}
580 537
581static void cmsg_quirks(void) 538 eeepc->led_workqueue = create_singlethread_workqueue("led_workqueue");
582{ 539 if (!eeepc->led_workqueue)
583 cmsg_quirk(CM_ASL_LID, "LID"); 540 return -ENOMEM;
584 cmsg_quirk(CM_ASL_TYPE, "TYPE"); 541 INIT_WORK(&eeepc->tpd_led_work, tpd_led_update);
585 cmsg_quirk(CM_ASL_PANELPOWER, "PANELPOWER");
586 cmsg_quirk(CM_ASL_TPD, "TPD");
587}
588 542
589static int eeepc_hotk_check(void) 543 eeepc->tpd_led.name = "eeepc::touchpad";
590{ 544 eeepc->tpd_led.brightness_set = tpd_led_set;
591 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; 545 eeepc->tpd_led.max_brightness = 1;
592 int result;
593 546
594 result = acpi_bus_get_status(ehotk->device); 547 rv = led_classdev_register(&eeepc->platform_device->dev,
595 if (result) 548 &eeepc->tpd_led);
596 return result; 549 if (rv) {
597 if (ehotk->device->status.present) { 550 destroy_workqueue(eeepc->led_workqueue);
598 if (write_acpi_int(ehotk->handle, "INIT", ehotk->init_flag, 551 return rv;
599 &buffer)) {
600 pr_err("Hotkey initialization failed\n");
601 return -ENODEV;
602 } else {
603 pr_notice("Hotkey init flags 0x%x\n", ehotk->init_flag);
604 }
605 /* get control methods supported */
606 if (read_acpi_int(ehotk->handle, "CMSG"
607 , &ehotk->cm_supported)) {
608 pr_err("Get control methods supported failed\n");
609 return -ENODEV;
610 } else {
611 cmsg_quirks();
612 pr_info("Get control methods supported: 0x%x\n",
613 ehotk->cm_supported);
614 }
615 } else {
616 pr_err("Hotkey device not present, aborting\n");
617 return -EINVAL;
618 } 552 }
553
619 return 0; 554 return 0;
620} 555}
621 556
622static int notify_brn(void) 557static void eeepc_led_exit(struct eeepc_laptop *eeepc)
623{ 558{
624 /* returns the *previous* brightness, or -1 */ 559 if (eeepc->tpd_led.dev)
625 struct backlight_device *bd = eeepc_backlight_device; 560 led_classdev_unregister(&eeepc->tpd_led);
626 if (bd) { 561 if (eeepc->led_workqueue)
627 int old = bd->props.brightness; 562 destroy_workqueue(eeepc->led_workqueue);
628 backlight_force_update(bd, BACKLIGHT_UPDATE_HOTKEY);
629 return old;
630 }
631 return -1;
632} 563}
633 564
634static int eeepc_get_adapter_status(struct hotplug_slot *hotplug_slot,
635 u8 *value)
636{
637 int val = get_acpi(CM_ASL_WLAN);
638
639 if (val == 1 || val == 0)
640 *value = val;
641 else
642 return -EINVAL;
643 565
644 return 0; 566/*
567 * PCI hotplug (for wlan rfkill)
568 */
569static bool eeepc_wlan_rfkill_blocked(struct eeepc_laptop *eeepc)
570{
571 if (get_acpi(eeepc, CM_ASL_WLAN) == 1)
572 return false;
573 return true;
645} 574}
646 575
647static void eeepc_rfkill_hotplug(void) 576static void eeepc_rfkill_hotplug(struct eeepc_laptop *eeepc)
648{ 577{
649 struct pci_dev *dev; 578 struct pci_dev *dev;
650 struct pci_bus *bus; 579 struct pci_bus *bus;
651 bool blocked = eeepc_wlan_rfkill_blocked(); 580 bool blocked = eeepc_wlan_rfkill_blocked(eeepc);
581 bool absent;
582 u32 l;
652 583
653 if (ehotk->wlan_rfkill) 584 if (eeepc->wlan_rfkill)
654 rfkill_set_sw_state(ehotk->wlan_rfkill, blocked); 585 rfkill_set_sw_state(eeepc->wlan_rfkill, blocked);
655 586
656 mutex_lock(&ehotk->hotplug_lock); 587 mutex_lock(&eeepc->hotplug_lock);
657 588
658 if (ehotk->hotplug_slot) { 589 if (eeepc->hotplug_slot) {
659 bus = pci_find_bus(0, 1); 590 bus = pci_find_bus(0, 1);
660 if (!bus) { 591 if (!bus) {
661 pr_warning("Unable to find PCI bus 1?\n"); 592 pr_warning("Unable to find PCI bus 1?\n");
662 goto out_unlock; 593 goto out_unlock;
663 } 594 }
664 595
596 if (pci_bus_read_config_dword(bus, 0, PCI_VENDOR_ID, &l)) {
597 pr_err("Unable to read PCI config space?\n");
598 goto out_unlock;
599 }
600 absent = (l == 0xffffffff);
601
602 if (blocked != absent) {
603 pr_warning("BIOS says wireless lan is %s, "
604 "but the pci device is %s\n",
605 blocked ? "blocked" : "unblocked",
606 absent ? "absent" : "present");
607 pr_warning("skipped wireless hotplug as probably "
608 "inappropriate for this model\n");
609 goto out_unlock;
610 }
611
665 if (!blocked) { 612 if (!blocked) {
666 dev = pci_get_slot(bus, 0); 613 dev = pci_get_slot(bus, 0);
667 if (dev) { 614 if (dev) {
@@ -685,69 +632,23 @@ static void eeepc_rfkill_hotplug(void)
685 } 632 }
686 633
687out_unlock: 634out_unlock:
688 mutex_unlock(&ehotk->hotplug_lock); 635 mutex_unlock(&eeepc->hotplug_lock);
689} 636}
690 637
691static void eeepc_rfkill_notify(acpi_handle handle, u32 event, void *data) 638static void eeepc_rfkill_notify(acpi_handle handle, u32 event, void *data)
692{ 639{
640 struct eeepc_laptop *eeepc = data;
641
693 if (event != ACPI_NOTIFY_BUS_CHECK) 642 if (event != ACPI_NOTIFY_BUS_CHECK)
694 return; 643 return;
695 644
696 eeepc_rfkill_hotplug(); 645 eeepc_rfkill_hotplug(eeepc);
697}
698
699static void eeepc_hotk_notify(struct acpi_device *device, u32 event)
700{
701 static struct key_entry *key;
702 u16 count;
703 int brn = -ENODEV;
704
705 if (!ehotk)
706 return;
707 if (event > ACPI_MAX_SYS_NOTIFY)
708 return;
709 if (event >= NOTIFY_BRN_MIN && event <= NOTIFY_BRN_MAX)
710 brn = notify_brn();
711 count = ehotk->event_count[event % 128]++;
712 acpi_bus_generate_proc_event(ehotk->device, event, count);
713 acpi_bus_generate_netlink_event(ehotk->device->pnp.device_class,
714 dev_name(&ehotk->device->dev), event,
715 count);
716 if (ehotk->inputdev) {
717 if (brn != -ENODEV) {
718 /* brightness-change events need special
719 * handling for conversion to key events
720 */
721 if (brn < 0)
722 brn = event;
723 else
724 brn += NOTIFY_BRN_MIN;
725 if (event < brn)
726 event = NOTIFY_BRN_MIN; /* brightness down */
727 else if (event > brn)
728 event = NOTIFY_BRN_MIN + 2; /* ... up */
729 else
730 event = NOTIFY_BRN_MIN + 1; /* ... unchanged */
731 }
732 key = eepc_get_entry_by_scancode(event);
733 if (key) {
734 switch (key->type) {
735 case KE_KEY:
736 input_report_key(ehotk->inputdev, key->keycode,
737 1);
738 input_sync(ehotk->inputdev);
739 input_report_key(ehotk->inputdev, key->keycode,
740 0);
741 input_sync(ehotk->inputdev);
742 break;
743 }
744 }
745 }
746} 646}
747 647
748static int eeepc_register_rfkill_notifier(char *node) 648static int eeepc_register_rfkill_notifier(struct eeepc_laptop *eeepc,
649 char *node)
749{ 650{
750 acpi_status status = AE_OK; 651 acpi_status status;
751 acpi_handle handle; 652 acpi_handle handle;
752 653
753 status = acpi_get_handle(NULL, node, &handle); 654 status = acpi_get_handle(NULL, node, &handle);
@@ -756,7 +657,7 @@ static int eeepc_register_rfkill_notifier(char *node)
756 status = acpi_install_notify_handler(handle, 657 status = acpi_install_notify_handler(handle,
757 ACPI_SYSTEM_NOTIFY, 658 ACPI_SYSTEM_NOTIFY,
758 eeepc_rfkill_notify, 659 eeepc_rfkill_notify,
759 NULL); 660 eeepc);
760 if (ACPI_FAILURE(status)) 661 if (ACPI_FAILURE(status))
761 pr_warning("Failed to register notify on %s\n", node); 662 pr_warning("Failed to register notify on %s\n", node);
762 } else 663 } else
@@ -765,7 +666,8 @@ static int eeepc_register_rfkill_notifier(char *node)
765 return 0; 666 return 0;
766} 667}
767 668
768static void eeepc_unregister_rfkill_notifier(char *node) 669static void eeepc_unregister_rfkill_notifier(struct eeepc_laptop *eeepc,
670 char *node)
769{ 671{
770 acpi_status status = AE_OK; 672 acpi_status status = AE_OK;
771 acpi_handle handle; 673 acpi_handle handle;
@@ -782,13 +684,33 @@ static void eeepc_unregister_rfkill_notifier(char *node)
782 } 684 }
783} 685}
784 686
687static int eeepc_get_adapter_status(struct hotplug_slot *hotplug_slot,
688 u8 *value)
689{
690 struct eeepc_laptop *eeepc = hotplug_slot->private;
691 int val = get_acpi(eeepc, CM_ASL_WLAN);
692
693 if (val == 1 || val == 0)
694 *value = val;
695 else
696 return -EINVAL;
697
698 return 0;
699}
700
785static void eeepc_cleanup_pci_hotplug(struct hotplug_slot *hotplug_slot) 701static void eeepc_cleanup_pci_hotplug(struct hotplug_slot *hotplug_slot)
786{ 702{
787 kfree(hotplug_slot->info); 703 kfree(hotplug_slot->info);
788 kfree(hotplug_slot); 704 kfree(hotplug_slot);
789} 705}
790 706
791static int eeepc_setup_pci_hotplug(void) 707static struct hotplug_slot_ops eeepc_hotplug_slot_ops = {
708 .owner = THIS_MODULE,
709 .get_adapter_status = eeepc_get_adapter_status,
710 .get_power_status = eeepc_get_adapter_status,
711};
712
713static int eeepc_setup_pci_hotplug(struct eeepc_laptop *eeepc)
792{ 714{
793 int ret = -ENOMEM; 715 int ret = -ENOMEM;
794 struct pci_bus *bus = pci_find_bus(0, 1); 716 struct pci_bus *bus = pci_find_bus(0, 1);
@@ -798,22 +720,22 @@ static int eeepc_setup_pci_hotplug(void)
798 return -ENODEV; 720 return -ENODEV;
799 } 721 }
800 722
801 ehotk->hotplug_slot = kzalloc(sizeof(struct hotplug_slot), GFP_KERNEL); 723 eeepc->hotplug_slot = kzalloc(sizeof(struct hotplug_slot), GFP_KERNEL);
802 if (!ehotk->hotplug_slot) 724 if (!eeepc->hotplug_slot)
803 goto error_slot; 725 goto error_slot;
804 726
805 ehotk->hotplug_slot->info = kzalloc(sizeof(struct hotplug_slot_info), 727 eeepc->hotplug_slot->info = kzalloc(sizeof(struct hotplug_slot_info),
806 GFP_KERNEL); 728 GFP_KERNEL);
807 if (!ehotk->hotplug_slot->info) 729 if (!eeepc->hotplug_slot->info)
808 goto error_info; 730 goto error_info;
809 731
810 ehotk->hotplug_slot->private = ehotk; 732 eeepc->hotplug_slot->private = eeepc;
811 ehotk->hotplug_slot->release = &eeepc_cleanup_pci_hotplug; 733 eeepc->hotplug_slot->release = &eeepc_cleanup_pci_hotplug;
812 ehotk->hotplug_slot->ops = &eeepc_hotplug_slot_ops; 734 eeepc->hotplug_slot->ops = &eeepc_hotplug_slot_ops;
813 eeepc_get_adapter_status(ehotk->hotplug_slot, 735 eeepc_get_adapter_status(eeepc->hotplug_slot,
814 &ehotk->hotplug_slot->info->adapter_status); 736 &eeepc->hotplug_slot->info->adapter_status);
815 737
816 ret = pci_hp_register(ehotk->hotplug_slot, bus, 0, "eeepc-wifi"); 738 ret = pci_hp_register(eeepc->hotplug_slot, bus, 0, "eeepc-wifi");
817 if (ret) { 739 if (ret) {
818 pr_err("Unable to register hotplug slot - %d\n", ret); 740 pr_err("Unable to register hotplug slot - %d\n", ret);
819 goto error_register; 741 goto error_register;
@@ -822,17 +744,159 @@ static int eeepc_setup_pci_hotplug(void)
822 return 0; 744 return 0;
823 745
824error_register: 746error_register:
825 kfree(ehotk->hotplug_slot->info); 747 kfree(eeepc->hotplug_slot->info);
826error_info: 748error_info:
827 kfree(ehotk->hotplug_slot); 749 kfree(eeepc->hotplug_slot);
828 ehotk->hotplug_slot = NULL; 750 eeepc->hotplug_slot = NULL;
829error_slot: 751error_slot:
830 return ret; 752 return ret;
831} 753}
832 754
755/*
756 * Rfkill devices
757 */
758static int eeepc_rfkill_set(void *data, bool blocked)
759{
760 acpi_handle handle = data;
761
762 return write_acpi_int(handle, NULL, !blocked);
763}
764
765static const struct rfkill_ops eeepc_rfkill_ops = {
766 .set_block = eeepc_rfkill_set,
767};
768
769static int eeepc_new_rfkill(struct eeepc_laptop *eeepc,
770 struct rfkill **rfkill,
771 const char *name,
772 enum rfkill_type type, int cm)
773{
774 acpi_handle handle;
775 int result;
776
777 result = acpi_setter_handle(eeepc, cm, &handle);
778 if (result < 0)
779 return result;
780
781 *rfkill = rfkill_alloc(name, &eeepc->platform_device->dev, type,
782 &eeepc_rfkill_ops, handle);
783
784 if (!*rfkill)
785 return -EINVAL;
786
787 rfkill_init_sw_state(*rfkill, get_acpi(eeepc, cm) != 1);
788 result = rfkill_register(*rfkill);
789 if (result) {
790 rfkill_destroy(*rfkill);
791 *rfkill = NULL;
792 return result;
793 }
794 return 0;
795}
796
797static void eeepc_rfkill_exit(struct eeepc_laptop *eeepc)
798{
799 eeepc_unregister_rfkill_notifier(eeepc, "\\_SB.PCI0.P0P5");
800 eeepc_unregister_rfkill_notifier(eeepc, "\\_SB.PCI0.P0P6");
801 eeepc_unregister_rfkill_notifier(eeepc, "\\_SB.PCI0.P0P7");
802 if (eeepc->wlan_rfkill) {
803 rfkill_unregister(eeepc->wlan_rfkill);
804 rfkill_destroy(eeepc->wlan_rfkill);
805 eeepc->wlan_rfkill = NULL;
806 }
807 /*
808 * Refresh pci hotplug in case the rfkill state was changed after
809 * eeepc_unregister_rfkill_notifier()
810 */
811 eeepc_rfkill_hotplug(eeepc);
812 if (eeepc->hotplug_slot)
813 pci_hp_deregister(eeepc->hotplug_slot);
814
815 if (eeepc->bluetooth_rfkill) {
816 rfkill_unregister(eeepc->bluetooth_rfkill);
817 rfkill_destroy(eeepc->bluetooth_rfkill);
818 eeepc->bluetooth_rfkill = NULL;
819 }
820 if (eeepc->wwan3g_rfkill) {
821 rfkill_unregister(eeepc->wwan3g_rfkill);
822 rfkill_destroy(eeepc->wwan3g_rfkill);
823 eeepc->wwan3g_rfkill = NULL;
824 }
825 if (eeepc->wimax_rfkill) {
826 rfkill_unregister(eeepc->wimax_rfkill);
827 rfkill_destroy(eeepc->wimax_rfkill);
828 eeepc->wimax_rfkill = NULL;
829 }
830}
831
832static int eeepc_rfkill_init(struct eeepc_laptop *eeepc)
833{
834 int result = 0;
835
836 mutex_init(&eeepc->hotplug_lock);
837
838 result = eeepc_new_rfkill(eeepc, &eeepc->wlan_rfkill,
839 "eeepc-wlan", RFKILL_TYPE_WLAN,
840 CM_ASL_WLAN);
841
842 if (result && result != -ENODEV)
843 goto exit;
844
845 result = eeepc_new_rfkill(eeepc, &eeepc->bluetooth_rfkill,
846 "eeepc-bluetooth", RFKILL_TYPE_BLUETOOTH,
847 CM_ASL_BLUETOOTH);
848
849 if (result && result != -ENODEV)
850 goto exit;
851
852 result = eeepc_new_rfkill(eeepc, &eeepc->wwan3g_rfkill,
853 "eeepc-wwan3g", RFKILL_TYPE_WWAN,
854 CM_ASL_3G);
855
856 if (result && result != -ENODEV)
857 goto exit;
858
859 result = eeepc_new_rfkill(eeepc, &eeepc->wimax_rfkill,
860 "eeepc-wimax", RFKILL_TYPE_WIMAX,
861 CM_ASL_WIMAX);
862
863 if (result && result != -ENODEV)
864 goto exit;
865
866 if (eeepc->hotplug_disabled)
867 return 0;
868
869 result = eeepc_setup_pci_hotplug(eeepc);
870 /*
871 * If we get -EBUSY then something else is handling the PCI hotplug -
872 * don't fail in this case
873 */
874 if (result == -EBUSY)
875 result = 0;
876
877 eeepc_register_rfkill_notifier(eeepc, "\\_SB.PCI0.P0P5");
878 eeepc_register_rfkill_notifier(eeepc, "\\_SB.PCI0.P0P6");
879 eeepc_register_rfkill_notifier(eeepc, "\\_SB.PCI0.P0P7");
880 /*
881 * Refresh pci hotplug in case the rfkill state was changed during
882 * setup.
883 */
884 eeepc_rfkill_hotplug(eeepc);
885
886exit:
887 if (result && result != -ENODEV)
888 eeepc_rfkill_exit(eeepc);
889 return result;
890}
891
892/*
893 * Platform driver - hibernate/resume callbacks
894 */
833static int eeepc_hotk_thaw(struct device *device) 895static int eeepc_hotk_thaw(struct device *device)
834{ 896{
835 if (ehotk->wlan_rfkill) { 897 struct eeepc_laptop *eeepc = dev_get_drvdata(device);
898
899 if (eeepc->wlan_rfkill) {
836 bool wlan; 900 bool wlan;
837 901
838 /* 902 /*
@@ -840,8 +904,8 @@ static int eeepc_hotk_thaw(struct device *device)
840 * during suspend. Normally it restores it on resume, but 904 * during suspend. Normally it restores it on resume, but
841 * we should kick it ourselves in case hibernation is aborted. 905 * we should kick it ourselves in case hibernation is aborted.
842 */ 906 */
843 wlan = get_acpi(CM_ASL_WLAN); 907 wlan = get_acpi(eeepc, CM_ASL_WLAN);
844 set_acpi(CM_ASL_WLAN, wlan); 908 set_acpi(eeepc, CM_ASL_WLAN, wlan);
845 } 909 }
846 910
847 return 0; 911 return 0;
@@ -849,70 +913,96 @@ static int eeepc_hotk_thaw(struct device *device)
849 913
850static int eeepc_hotk_restore(struct device *device) 914static int eeepc_hotk_restore(struct device *device)
851{ 915{
916 struct eeepc_laptop *eeepc = dev_get_drvdata(device);
917
852 /* Refresh both wlan rfkill state and pci hotplug */ 918 /* Refresh both wlan rfkill state and pci hotplug */
853 if (ehotk->wlan_rfkill) 919 if (eeepc->wlan_rfkill)
854 eeepc_rfkill_hotplug(); 920 eeepc_rfkill_hotplug(eeepc);
855 921
856 if (ehotk->bluetooth_rfkill) 922 if (eeepc->bluetooth_rfkill)
857 rfkill_set_sw_state(ehotk->bluetooth_rfkill, 923 rfkill_set_sw_state(eeepc->bluetooth_rfkill,
858 get_acpi(CM_ASL_BLUETOOTH) != 1); 924 get_acpi(eeepc, CM_ASL_BLUETOOTH) != 1);
859 if (ehotk->wwan3g_rfkill) 925 if (eeepc->wwan3g_rfkill)
860 rfkill_set_sw_state(ehotk->wwan3g_rfkill, 926 rfkill_set_sw_state(eeepc->wwan3g_rfkill,
861 get_acpi(CM_ASL_3G) != 1); 927 get_acpi(eeepc, CM_ASL_3G) != 1);
862 if (ehotk->wimax_rfkill) 928 if (eeepc->wimax_rfkill)
863 rfkill_set_sw_state(ehotk->wimax_rfkill, 929 rfkill_set_sw_state(eeepc->wimax_rfkill,
864 get_acpi(CM_ASL_WIMAX) != 1); 930 get_acpi(eeepc, CM_ASL_WIMAX) != 1);
865 931
866 return 0; 932 return 0;
867} 933}
868 934
935static const struct dev_pm_ops eeepc_pm_ops = {
936 .thaw = eeepc_hotk_thaw,
937 .restore = eeepc_hotk_restore,
938};
939
940static struct platform_driver platform_driver = {
941 .driver = {
942 .name = EEEPC_LAPTOP_FILE,
943 .owner = THIS_MODULE,
944 .pm = &eeepc_pm_ops,
945 }
946};
947
869/* 948/*
870 * Hwmon 949 * Hwmon device
871 */ 950 */
951
952#define EEEPC_EC_SC00 0x61
953#define EEEPC_EC_FAN_PWM (EEEPC_EC_SC00 + 2) /* Fan PWM duty cycle (%) */
954#define EEEPC_EC_FAN_HRPM (EEEPC_EC_SC00 + 5) /* High byte, fan speed (RPM) */
955#define EEEPC_EC_FAN_LRPM (EEEPC_EC_SC00 + 6) /* Low byte, fan speed (RPM) */
956
957#define EEEPC_EC_SFB0 0xD0
958#define EEEPC_EC_FAN_CTRL (EEEPC_EC_SFB0 + 3) /* Byte containing SF25 */
959
872static int eeepc_get_fan_pwm(void) 960static int eeepc_get_fan_pwm(void)
873{ 961{
874 int value = 0; 962 u8 value = 0;
875 963
876 read_acpi_int(NULL, EEEPC_EC_FAN_PWM, &value); 964 ec_read(EEEPC_EC_FAN_PWM, &value);
877 value = value * 255 / 100; 965 return value * 255 / 100;
878 return (value);
879} 966}
880 967
881static void eeepc_set_fan_pwm(int value) 968static void eeepc_set_fan_pwm(int value)
882{ 969{
883 value = SENSORS_LIMIT(value, 0, 255); 970 value = SENSORS_LIMIT(value, 0, 255);
884 value = value * 100 / 255; 971 value = value * 100 / 255;
885 ec_write(EEEPC_EC_SC02, value); 972 ec_write(EEEPC_EC_FAN_PWM, value);
886} 973}
887 974
888static int eeepc_get_fan_rpm(void) 975static int eeepc_get_fan_rpm(void)
889{ 976{
890 int high = 0; 977 u8 high = 0;
891 int low = 0; 978 u8 low = 0;
892 979
893 read_acpi_int(NULL, EEEPC_EC_FAN_HRPM, &high); 980 ec_read(EEEPC_EC_FAN_HRPM, &high);
894 read_acpi_int(NULL, EEEPC_EC_FAN_LRPM, &low); 981 ec_read(EEEPC_EC_FAN_LRPM, &low);
895 return (high << 8 | low); 982 return high << 8 | low;
896} 983}
897 984
898static int eeepc_get_fan_ctrl(void) 985static int eeepc_get_fan_ctrl(void)
899{ 986{
900 int value = 0; 987 u8 value = 0;
901 988
902 read_acpi_int(NULL, EEEPC_EC_FAN_CTRL, &value); 989 ec_read(EEEPC_EC_FAN_CTRL, &value);
903 return ((value & 0x02 ? 1 : 0)); 990 if (value & 0x02)
991 return 1; /* manual */
992 else
993 return 2; /* automatic */
904} 994}
905 995
906static void eeepc_set_fan_ctrl(int manual) 996static void eeepc_set_fan_ctrl(int manual)
907{ 997{
908 int value = 0; 998 u8 value = 0;
909 999
910 read_acpi_int(NULL, EEEPC_EC_FAN_CTRL, &value); 1000 ec_read(EEEPC_EC_FAN_CTRL, &value);
911 if (manual) 1001 if (manual == 1)
912 value |= 0x02; 1002 value |= 0x02;
913 else 1003 else
914 value &= ~0x02; 1004 value &= ~0x02;
915 ec_write(EEEPC_EC_SFB3, value); 1005 ec_write(EEEPC_EC_FAN_CTRL, value);
916} 1006}
917 1007
918static ssize_t store_sys_hwmon(void (*set)(int), const char *buf, size_t count) 1008static ssize_t store_sys_hwmon(void (*set)(int), const char *buf, size_t count)
@@ -970,348 +1060,464 @@ static struct attribute_group hwmon_attribute_group = {
970 .attrs = hwmon_attributes 1060 .attrs = hwmon_attributes
971}; 1061};
972 1062
973/* 1063static void eeepc_hwmon_exit(struct eeepc_laptop *eeepc)
974 * exit/init
975 */
976static void eeepc_backlight_exit(void)
977{ 1064{
978 if (eeepc_backlight_device) 1065 struct device *hwmon;
979 backlight_device_unregister(eeepc_backlight_device); 1066
980 eeepc_backlight_device = NULL; 1067 hwmon = eeepc->hwmon_device;
1068 if (!hwmon)
1069 return;
1070 sysfs_remove_group(&hwmon->kobj,
1071 &hwmon_attribute_group);
1072 hwmon_device_unregister(hwmon);
1073 eeepc->hwmon_device = NULL;
981} 1074}
982 1075
983static void eeepc_rfkill_exit(void) 1076static int eeepc_hwmon_init(struct eeepc_laptop *eeepc)
984{ 1077{
985 eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P5"); 1078 struct device *hwmon;
986 eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P6"); 1079 int result;
987 eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P7"); 1080
988 if (ehotk->wlan_rfkill) { 1081 hwmon = hwmon_device_register(&eeepc->platform_device->dev);
989 rfkill_unregister(ehotk->wlan_rfkill); 1082 if (IS_ERR(hwmon)) {
990 rfkill_destroy(ehotk->wlan_rfkill); 1083 pr_err("Could not register eeepc hwmon device\n");
991 ehotk->wlan_rfkill = NULL; 1084 eeepc->hwmon_device = NULL;
992 } 1085 return PTR_ERR(hwmon);
993 /*
994 * Refresh pci hotplug in case the rfkill state was changed after
995 * eeepc_unregister_rfkill_notifier()
996 */
997 eeepc_rfkill_hotplug();
998 if (ehotk->hotplug_slot)
999 pci_hp_deregister(ehotk->hotplug_slot);
1000
1001 if (ehotk->bluetooth_rfkill) {
1002 rfkill_unregister(ehotk->bluetooth_rfkill);
1003 rfkill_destroy(ehotk->bluetooth_rfkill);
1004 ehotk->bluetooth_rfkill = NULL;
1005 }
1006 if (ehotk->wwan3g_rfkill) {
1007 rfkill_unregister(ehotk->wwan3g_rfkill);
1008 rfkill_destroy(ehotk->wwan3g_rfkill);
1009 ehotk->wwan3g_rfkill = NULL;
1010 }
1011 if (ehotk->wimax_rfkill) {
1012 rfkill_unregister(ehotk->wimax_rfkill);
1013 rfkill_destroy(ehotk->wimax_rfkill);
1014 ehotk->wimax_rfkill = NULL;
1015 } 1086 }
1087 eeepc->hwmon_device = hwmon;
1088 result = sysfs_create_group(&hwmon->kobj,
1089 &hwmon_attribute_group);
1090 if (result)
1091 eeepc_hwmon_exit(eeepc);
1092 return result;
1016} 1093}
1017 1094
1018static void eeepc_input_exit(void) 1095/*
1096 * Backlight device
1097 */
1098static int read_brightness(struct backlight_device *bd)
1019{ 1099{
1020 if (ehotk->inputdev) 1100 struct eeepc_laptop *eeepc = bl_get_data(bd);
1021 input_unregister_device(ehotk->inputdev); 1101
1102 return get_acpi(eeepc, CM_ASL_PANELBRIGHT);
1022} 1103}
1023 1104
1024static void eeepc_hwmon_exit(void) 1105static int set_brightness(struct backlight_device *bd, int value)
1025{ 1106{
1026 struct device *hwmon; 1107 struct eeepc_laptop *eeepc = bl_get_data(bd);
1027 1108
1028 hwmon = eeepc_hwmon_device; 1109 return set_acpi(eeepc, CM_ASL_PANELBRIGHT, value);
1029 if (!hwmon)
1030 return ;
1031 sysfs_remove_group(&hwmon->kobj,
1032 &hwmon_attribute_group);
1033 hwmon_device_unregister(hwmon);
1034 eeepc_hwmon_device = NULL;
1035} 1110}
1036 1111
1037static int eeepc_new_rfkill(struct rfkill **rfkill, 1112static int update_bl_status(struct backlight_device *bd)
1038 const char *name, struct device *dev,
1039 enum rfkill_type type, int cm)
1040{ 1113{
1041 int result; 1114 return set_brightness(bd, bd->props.brightness);
1115}
1042 1116
1043 result = get_acpi(cm); 1117static struct backlight_ops eeepcbl_ops = {
1044 if (result < 0) 1118 .get_brightness = read_brightness,
1045 return result; 1119 .update_status = update_bl_status,
1120};
1046 1121
1047 *rfkill = rfkill_alloc(name, dev, type, 1122static int eeepc_backlight_notify(struct eeepc_laptop *eeepc)
1048 &eeepc_rfkill_ops, (void *)(unsigned long)cm); 1123{
1124 struct backlight_device *bd = eeepc->backlight_device;
1125 int old = bd->props.brightness;
1049 1126
1050 if (!*rfkill) 1127 backlight_force_update(bd, BACKLIGHT_UPDATE_HOTKEY);
1051 return -EINVAL;
1052 1128
1053 rfkill_init_sw_state(*rfkill, get_acpi(cm) != 1); 1129 return old;
1054 result = rfkill_register(*rfkill); 1130}
1055 if (result) { 1131
1056 rfkill_destroy(*rfkill); 1132static int eeepc_backlight_init(struct eeepc_laptop *eeepc)
1057 *rfkill = NULL; 1133{
1058 return result; 1134 struct backlight_properties props;
1135 struct backlight_device *bd;
1136
1137 memset(&props, 0, sizeof(struct backlight_properties));
1138 props.max_brightness = 15;
1139 bd = backlight_device_register(EEEPC_LAPTOP_FILE,
1140 &eeepc->platform_device->dev, eeepc,
1141 &eeepcbl_ops, &props);
1142 if (IS_ERR(bd)) {
1143 pr_err("Could not register eeepc backlight device\n");
1144 eeepc->backlight_device = NULL;
1145 return PTR_ERR(bd);
1059 } 1146 }
1147 eeepc->backlight_device = bd;
1148 bd->props.brightness = read_brightness(bd);
1149 bd->props.power = FB_BLANK_UNBLANK;
1150 backlight_update_status(bd);
1060 return 0; 1151 return 0;
1061} 1152}
1062 1153
1154static void eeepc_backlight_exit(struct eeepc_laptop *eeepc)
1155{
1156 if (eeepc->backlight_device)
1157 backlight_device_unregister(eeepc->backlight_device);
1158 eeepc->backlight_device = NULL;
1159}
1063 1160
1064static int eeepc_rfkill_init(struct device *dev) 1161
1162/*
1163 * Input device (i.e. hotkeys)
1164 */
1165static int eeepc_input_init(struct eeepc_laptop *eeepc)
1065{ 1166{
1066 int result = 0; 1167 struct input_dev *input;
1168 int error;
1067 1169
1068 mutex_init(&ehotk->hotplug_lock); 1170 input = input_allocate_device();
1171 if (!input) {
1172 pr_info("Unable to allocate input device\n");
1173 return -ENOMEM;
1174 }
1069 1175
1070 result = eeepc_new_rfkill(&ehotk->wlan_rfkill, 1176 input->name = "Asus EeePC extra buttons";
1071 "eeepc-wlan", dev, 1177 input->phys = EEEPC_LAPTOP_FILE "/input0";
1072 RFKILL_TYPE_WLAN, CM_ASL_WLAN); 1178 input->id.bustype = BUS_HOST;
1179 input->dev.parent = &eeepc->platform_device->dev;
1073 1180
1074 if (result && result != -ENODEV) 1181 error = sparse_keymap_setup(input, eeepc_keymap, NULL);
1075 goto exit; 1182 if (error) {
1183 pr_err("Unable to setup input device keymap\n");
1184 goto err_free_dev;
1185 }
1076 1186
1077 result = eeepc_new_rfkill(&ehotk->bluetooth_rfkill, 1187 error = input_register_device(input);
1078 "eeepc-bluetooth", dev, 1188 if (error) {
1079 RFKILL_TYPE_BLUETOOTH, CM_ASL_BLUETOOTH); 1189 pr_err("Unable to register input device\n");
1190 goto err_free_keymap;
1191 }
1080 1192
1081 if (result && result != -ENODEV) 1193 eeepc->inputdev = input;
1082 goto exit; 1194 return 0;
1083 1195
1084 result = eeepc_new_rfkill(&ehotk->wwan3g_rfkill, 1196 err_free_keymap:
1085 "eeepc-wwan3g", dev, 1197 sparse_keymap_free(input);
1086 RFKILL_TYPE_WWAN, CM_ASL_3G); 1198 err_free_dev:
1199 input_free_device(input);
1200 return error;
1201}
1087 1202
1088 if (result && result != -ENODEV) 1203static void eeepc_input_exit(struct eeepc_laptop *eeepc)
1089 goto exit; 1204{
1205 if (eeepc->inputdev) {
1206 sparse_keymap_free(eeepc->inputdev);
1207 input_unregister_device(eeepc->inputdev);
1208 }
1209}
1090 1210
1091 result = eeepc_new_rfkill(&ehotk->wimax_rfkill, 1211/*
1092 "eeepc-wimax", dev, 1212 * ACPI driver
1093 RFKILL_TYPE_WIMAX, CM_ASL_WIMAX); 1213 */
1214static void eeepc_acpi_notify(struct acpi_device *device, u32 event)
1215{
1216 struct eeepc_laptop *eeepc = acpi_driver_data(device);
1217 u16 count;
1094 1218
1095 if (result && result != -ENODEV) 1219 if (event > ACPI_MAX_SYS_NOTIFY)
1096 goto exit; 1220 return;
1221 count = eeepc->event_count[event % 128]++;
1222 acpi_bus_generate_proc_event(device, event, count);
1223 acpi_bus_generate_netlink_event(device->pnp.device_class,
1224 dev_name(&device->dev), event,
1225 count);
1226
1227 /* Brightness events are special */
1228 if (event >= NOTIFY_BRN_MIN && event <= NOTIFY_BRN_MAX) {
1229
1230 /* Ignore them completely if the acpi video driver is used */
1231 if (eeepc->backlight_device != NULL) {
1232 int old_brightness, new_brightness;
1233
1234 /* Update the backlight device. */
1235 old_brightness = eeepc_backlight_notify(eeepc);
1236
1237 /* Convert event to keypress (obsolescent hack) */
1238 new_brightness = event - NOTIFY_BRN_MIN;
1239
1240 if (new_brightness < old_brightness) {
1241 event = NOTIFY_BRN_MIN; /* brightness down */
1242 } else if (new_brightness > old_brightness) {
1243 event = NOTIFY_BRN_MAX; /* brightness up */
1244 } else {
1245 /*
1246 * no change in brightness - already at min/max,
1247 * event will be desired value (or else ignored)
1248 */
1249 }
1250 sparse_keymap_report_event(eeepc->inputdev, event,
1251 1, true);
1252 }
1253 } else {
1254 /* Everything else is a bona-fide keypress event */
1255 sparse_keymap_report_event(eeepc->inputdev, event, 1, true);
1256 }
1257}
1258
1259static void eeepc_dmi_check(struct eeepc_laptop *eeepc)
1260{
1261 const char *model;
1262
1263 model = dmi_get_system_info(DMI_PRODUCT_NAME);
1264 if (!model)
1265 return;
1097 1266
1098 result = eeepc_setup_pci_hotplug();
1099 /* 1267 /*
1100 * If we get -EBUSY then something else is handling the PCI hotplug - 1268 * Blacklist for setting cpufv (cpu speed).
1101 * don't fail in this case 1269 *
1270 * EeePC 4G ("701") implements CFVS, but it is not supported
1271 * by the pre-installed OS, and the original option to change it
1272 * in the BIOS setup screen was removed in later versions.
1273 *
1274 * Judging by the lack of "Super Hybrid Engine" on Asus product pages,
1275 * this applies to all "701" models (4G/4G Surf/2G Surf).
1276 *
1277 * So Asus made a deliberate decision not to support it on this model.
1278 * We have several reports that using it can cause the system to hang
1279 *
1280 * The hang has also been reported on a "702" (Model name "8G"?).
1281 *
1282 * We avoid dmi_check_system() / dmi_match(), because they use
1283 * substring matching. We don't want to affect the "701SD"
1284 * and "701SDX" models, because they do support S.H.E.
1102 */ 1285 */
1103 if (result == -EBUSY) 1286 if (strcmp(model, "701") == 0 || strcmp(model, "702") == 0) {
1104 result = 0; 1287 eeepc->cpufv_disabled = true;
1288 pr_info("model %s does not officially support setting cpu "
1289 "speed\n", model);
1290 pr_info("cpufv disabled to avoid instability\n");
1291 }
1105 1292
1106 eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P5");
1107 eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P6");
1108 eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P7");
1109 /* 1293 /*
1110 * Refresh pci hotplug in case the rfkill state was changed during 1294 * Blacklist for wlan hotplug
1111 * setup. 1295 *
1296 * Eeepc 1005HA doesn't work like others models and don't need the
1297 * hotplug code. In fact, current hotplug code seems to unplug another
1298 * device...
1112 */ 1299 */
1113 eeepc_rfkill_hotplug(); 1300 if (strcmp(model, "1005HA") == 0 || strcmp(model, "1201N") == 0 ||
1114 1301 strcmp(model, "1005PE") == 0) {
1115exit: 1302 eeepc->hotplug_disabled = true;
1116 if (result && result != -ENODEV) 1303 pr_info("wlan hotplug disabled\n");
1117 eeepc_rfkill_exit(); 1304 }
1118 return result;
1119} 1305}
1120 1306
1121static int eeepc_backlight_init(struct device *dev) 1307static void cmsg_quirk(struct eeepc_laptop *eeepc, int cm, const char *name)
1122{ 1308{
1123 struct backlight_device *bd; 1309 int dummy;
1124 1310
1125 bd = backlight_device_register(EEEPC_HOTK_FILE, dev, 1311 /* Some BIOSes do not report cm although it is avaliable.
1126 NULL, &eeepcbl_ops); 1312 Check if cm_getv[cm] works and, if yes, assume cm should be set. */
1127 if (IS_ERR(bd)) { 1313 if (!(eeepc->cm_supported & (1 << cm))
1128 pr_err("Could not register eeepc backlight device\n"); 1314 && !read_acpi_int(eeepc->handle, cm_getv[cm], &dummy)) {
1129 eeepc_backlight_device = NULL; 1315 pr_info("%s (%x) not reported by BIOS,"
1130 return PTR_ERR(bd); 1316 " enabling anyway\n", name, 1 << cm);
1317 eeepc->cm_supported |= 1 << cm;
1131 } 1318 }
1132 eeepc_backlight_device = bd;
1133 bd->props.max_brightness = 15;
1134 bd->props.brightness = read_brightness(NULL);
1135 bd->props.power = FB_BLANK_UNBLANK;
1136 backlight_update_status(bd);
1137 return 0;
1138} 1319}
1139 1320
1140static int eeepc_hwmon_init(struct device *dev) 1321static void cmsg_quirks(struct eeepc_laptop *eeepc)
1141{ 1322{
1142 struct device *hwmon; 1323 cmsg_quirk(eeepc, CM_ASL_LID, "LID");
1143 int result; 1324 cmsg_quirk(eeepc, CM_ASL_TYPE, "TYPE");
1144 1325 cmsg_quirk(eeepc, CM_ASL_PANELPOWER, "PANELPOWER");
1145 hwmon = hwmon_device_register(dev); 1326 cmsg_quirk(eeepc, CM_ASL_TPD, "TPD");
1146 if (IS_ERR(hwmon)) {
1147 pr_err("Could not register eeepc hwmon device\n");
1148 eeepc_hwmon_device = NULL;
1149 return PTR_ERR(hwmon);
1150 }
1151 eeepc_hwmon_device = hwmon;
1152 result = sysfs_create_group(&hwmon->kobj,
1153 &hwmon_attribute_group);
1154 if (result)
1155 eeepc_hwmon_exit();
1156 return result;
1157} 1327}
1158 1328
1159static int eeepc_input_init(struct device *dev) 1329static int eeepc_acpi_init(struct eeepc_laptop *eeepc,
1330 struct acpi_device *device)
1160{ 1331{
1161 const struct key_entry *key; 1332 unsigned int init_flags;
1162 int result; 1333 int result;
1163 1334
1164 ehotk->inputdev = input_allocate_device(); 1335 result = acpi_bus_get_status(device);
1165 if (!ehotk->inputdev) { 1336 if (result)
1166 pr_info("Unable to allocate input device\n"); 1337 return result;
1167 return -ENOMEM; 1338 if (!device->status.present) {
1339 pr_err("Hotkey device not present, aborting\n");
1340 return -ENODEV;
1168 } 1341 }
1169 ehotk->inputdev->name = "Asus EeePC extra buttons"; 1342
1170 ehotk->inputdev->dev.parent = dev; 1343 init_flags = DISABLE_ASL_WLAN | DISABLE_ASL_DISPLAYSWITCH;
1171 ehotk->inputdev->phys = EEEPC_HOTK_FILE "/input0"; 1344 pr_notice("Hotkey init flags 0x%x\n", init_flags);
1172 ehotk->inputdev->id.bustype = BUS_HOST; 1345
1173 ehotk->inputdev->getkeycode = eeepc_getkeycode; 1346 if (write_acpi_int(eeepc->handle, "INIT", init_flags)) {
1174 ehotk->inputdev->setkeycode = eeepc_setkeycode; 1347 pr_err("Hotkey initialization failed\n");
1175 1348 return -ENODEV;
1176 for (key = eeepc_keymap; key->type != KE_END; key++) {
1177 switch (key->type) {
1178 case KE_KEY:
1179 set_bit(EV_KEY, ehotk->inputdev->evbit);
1180 set_bit(key->keycode, ehotk->inputdev->keybit);
1181 break;
1182 }
1183 } 1349 }
1184 result = input_register_device(ehotk->inputdev); 1350
1185 if (result) { 1351 /* get control methods supported */
1186 pr_info("Unable to register input device\n"); 1352 if (read_acpi_int(eeepc->handle, "CMSG", &eeepc->cm_supported)) {
1187 input_free_device(ehotk->inputdev); 1353 pr_err("Get control methods supported failed\n");
1188 return result; 1354 return -ENODEV;
1189 } 1355 }
1356 cmsg_quirks(eeepc);
1357 pr_info("Get control methods supported: 0x%x\n", eeepc->cm_supported);
1358
1190 return 0; 1359 return 0;
1191} 1360}
1192 1361
1193static int __devinit eeepc_hotk_add(struct acpi_device *device) 1362static void __devinit eeepc_enable_camera(struct eeepc_laptop *eeepc)
1194{ 1363{
1195 struct device *dev; 1364 /*
1365 * If the following call to set_acpi() fails, it's because there's no
1366 * camera so we can ignore the error.
1367 */
1368 if (get_acpi(eeepc, CM_ASL_CAMERA) == 0)
1369 set_acpi(eeepc, CM_ASL_CAMERA, 1);
1370}
1371
1372static bool eeepc_device_present;
1373
1374static int __devinit eeepc_acpi_add(struct acpi_device *device)
1375{
1376 struct eeepc_laptop *eeepc;
1196 int result; 1377 int result;
1197 1378
1198 if (!device) 1379 pr_notice(EEEPC_LAPTOP_NAME "\n");
1199 return -EINVAL; 1380 eeepc = kzalloc(sizeof(struct eeepc_laptop), GFP_KERNEL);
1200 pr_notice(EEEPC_HOTK_NAME "\n"); 1381 if (!eeepc)
1201 ehotk = kzalloc(sizeof(struct eeepc_hotk), GFP_KERNEL);
1202 if (!ehotk)
1203 return -ENOMEM; 1382 return -ENOMEM;
1204 ehotk->init_flag = DISABLE_ASL_WLAN | DISABLE_ASL_DISPLAYSWITCH; 1383 eeepc->handle = device->handle;
1205 ehotk->handle = device->handle; 1384 strcpy(acpi_device_name(device), EEEPC_ACPI_DEVICE_NAME);
1206 strcpy(acpi_device_name(device), EEEPC_HOTK_DEVICE_NAME); 1385 strcpy(acpi_device_class(device), EEEPC_ACPI_CLASS);
1207 strcpy(acpi_device_class(device), EEEPC_HOTK_CLASS); 1386 device->driver_data = eeepc;
1208 device->driver_data = ehotk;
1209 ehotk->device = device;
1210
1211 result = eeepc_hotk_check();
1212 if (result)
1213 goto fail_platform_driver;
1214 eeepc_enable_camera();
1215 1387
1216 /* Register platform stuff */ 1388 eeepc->hotplug_disabled = hotplug_disabled;
1217 result = platform_driver_register(&platform_driver); 1389
1218 if (result) 1390 eeepc_dmi_check(eeepc);
1219 goto fail_platform_driver; 1391
1220 platform_device = platform_device_alloc(EEEPC_HOTK_FILE, -1); 1392 result = eeepc_acpi_init(eeepc, device);
1221 if (!platform_device) {
1222 result = -ENOMEM;
1223 goto fail_platform_device1;
1224 }
1225 result = platform_device_add(platform_device);
1226 if (result)
1227 goto fail_platform_device2;
1228 result = sysfs_create_group(&platform_device->dev.kobj,
1229 &platform_attribute_group);
1230 if (result) 1393 if (result)
1231 goto fail_sysfs; 1394 goto fail_platform;
1395 eeepc_enable_camera(eeepc);
1232 1396
1233 dev = &platform_device->dev; 1397 /*
1398 * Register the platform device first. It is used as a parent for the
1399 * sub-devices below.
1400 *
1401 * Note that if there are multiple instances of this ACPI device it
1402 * will bail out, because the platform device is registered with a
1403 * fixed name. Of course it doesn't make sense to have more than one,
1404 * and machine-specific scripts find the fixed name convenient. But
1405 * It's also good for us to exclude multiple instances because both
1406 * our hwmon and our wlan rfkill subdevice use global ACPI objects
1407 * (the EC and the wlan PCI slot respectively).
1408 */
1409 result = eeepc_platform_init(eeepc);
1410 if (result)
1411 goto fail_platform;
1234 1412
1235 if (!acpi_video_backlight_support()) { 1413 if (!acpi_video_backlight_support()) {
1236 result = eeepc_backlight_init(dev); 1414 result = eeepc_backlight_init(eeepc);
1237 if (result) 1415 if (result)
1238 goto fail_backlight; 1416 goto fail_backlight;
1239 } else 1417 } else
1240 pr_info("Backlight controlled by ACPI video " 1418 pr_info("Backlight controlled by ACPI video driver\n");
1241 "driver\n");
1242 1419
1243 result = eeepc_input_init(dev); 1420 result = eeepc_input_init(eeepc);
1244 if (result) 1421 if (result)
1245 goto fail_input; 1422 goto fail_input;
1246 1423
1247 result = eeepc_hwmon_init(dev); 1424 result = eeepc_hwmon_init(eeepc);
1248 if (result) 1425 if (result)
1249 goto fail_hwmon; 1426 goto fail_hwmon;
1250 1427
1251 result = eeepc_rfkill_init(dev); 1428 result = eeepc_led_init(eeepc);
1429 if (result)
1430 goto fail_led;
1431
1432 result = eeepc_rfkill_init(eeepc);
1252 if (result) 1433 if (result)
1253 goto fail_rfkill; 1434 goto fail_rfkill;
1254 1435
1436 eeepc_device_present = true;
1255 return 0; 1437 return 0;
1256 1438
1257fail_rfkill: 1439fail_rfkill:
1258 eeepc_hwmon_exit(); 1440 eeepc_led_exit(eeepc);
1441fail_led:
1442 eeepc_hwmon_exit(eeepc);
1259fail_hwmon: 1443fail_hwmon:
1260 eeepc_input_exit(); 1444 eeepc_input_exit(eeepc);
1261fail_input: 1445fail_input:
1262 eeepc_backlight_exit(); 1446 eeepc_backlight_exit(eeepc);
1263fail_backlight: 1447fail_backlight:
1264 sysfs_remove_group(&platform_device->dev.kobj, 1448 eeepc_platform_exit(eeepc);
1265 &platform_attribute_group); 1449fail_platform:
1266fail_sysfs: 1450 kfree(eeepc);
1267 platform_device_del(platform_device);
1268fail_platform_device2:
1269 platform_device_put(platform_device);
1270fail_platform_device1:
1271 platform_driver_unregister(&platform_driver);
1272fail_platform_driver:
1273 kfree(ehotk);
1274 1451
1275 return result; 1452 return result;
1276} 1453}
1277 1454
1278static int eeepc_hotk_remove(struct acpi_device *device, int type) 1455static int eeepc_acpi_remove(struct acpi_device *device, int type)
1279{ 1456{
1280 if (!device || !acpi_driver_data(device)) 1457 struct eeepc_laptop *eeepc = acpi_driver_data(device);
1281 return -EINVAL;
1282 1458
1283 eeepc_backlight_exit(); 1459 eeepc_backlight_exit(eeepc);
1284 eeepc_rfkill_exit(); 1460 eeepc_rfkill_exit(eeepc);
1285 eeepc_input_exit(); 1461 eeepc_input_exit(eeepc);
1286 eeepc_hwmon_exit(); 1462 eeepc_hwmon_exit(eeepc);
1287 sysfs_remove_group(&platform_device->dev.kobj, 1463 eeepc_led_exit(eeepc);
1288 &platform_attribute_group); 1464 eeepc_platform_exit(eeepc);
1289 platform_device_unregister(platform_device);
1290 platform_driver_unregister(&platform_driver);
1291 1465
1292 kfree(ehotk); 1466 kfree(eeepc);
1293 return 0; 1467 return 0;
1294} 1468}
1295 1469
1470
1471static const struct acpi_device_id eeepc_device_ids[] = {
1472 {EEEPC_ACPI_HID, 0},
1473 {"", 0},
1474};
1475MODULE_DEVICE_TABLE(acpi, eeepc_device_ids);
1476
1477static struct acpi_driver eeepc_acpi_driver = {
1478 .name = EEEPC_LAPTOP_NAME,
1479 .class = EEEPC_ACPI_CLASS,
1480 .owner = THIS_MODULE,
1481 .ids = eeepc_device_ids,
1482 .flags = ACPI_DRIVER_ALL_NOTIFY_EVENTS,
1483 .ops = {
1484 .add = eeepc_acpi_add,
1485 .remove = eeepc_acpi_remove,
1486 .notify = eeepc_acpi_notify,
1487 },
1488};
1489
1490
1296static int __init eeepc_laptop_init(void) 1491static int __init eeepc_laptop_init(void)
1297{ 1492{
1298 int result; 1493 int result;
1299 1494
1300 if (acpi_disabled) 1495 result = platform_driver_register(&platform_driver);
1301 return -ENODEV;
1302 result = acpi_bus_register_driver(&eeepc_hotk_driver);
1303 if (result < 0) 1496 if (result < 0)
1304 return result; 1497 return result;
1305 if (!ehotk) { 1498
1306 acpi_bus_unregister_driver(&eeepc_hotk_driver); 1499 result = acpi_bus_register_driver(&eeepc_acpi_driver);
1307 return -ENODEV; 1500 if (result < 0)
1501 goto fail_acpi_driver;
1502
1503 if (!eeepc_device_present) {
1504 result = -ENODEV;
1505 goto fail_no_device;
1308 } 1506 }
1507
1309 return 0; 1508 return 0;
1509
1510fail_no_device:
1511 acpi_bus_unregister_driver(&eeepc_acpi_driver);
1512fail_acpi_driver:
1513 platform_driver_unregister(&platform_driver);
1514 return result;
1310} 1515}
1311 1516
1312static void __exit eeepc_laptop_exit(void) 1517static void __exit eeepc_laptop_exit(void)
1313{ 1518{
1314 acpi_bus_unregister_driver(&eeepc_hotk_driver); 1519 acpi_bus_unregister_driver(&eeepc_acpi_driver);
1520 platform_driver_unregister(&platform_driver);
1315} 1521}
1316 1522
1317module_init(eeepc_laptop_init); 1523module_init(eeepc_laptop_init);
diff --git a/drivers/platform/x86/eeepc-wmi.c b/drivers/platform/x86/eeepc-wmi.c
new file mode 100644
index 000000000000..b227eb469f49
--- /dev/null
+++ b/drivers/platform/x86/eeepc-wmi.c
@@ -0,0 +1,413 @@
1/*
2 * Eee PC WMI hotkey driver
3 *
4 * Copyright(C) 2010 Intel Corporation.
5 *
6 * Portions based on wistron_btns.c:
7 * Copyright (C) 2005 Miloslav Trmac <mitr@volny.cz>
8 * Copyright (C) 2005 Bernhard Rosenkraenzer <bero@arklinux.org>
9 * Copyright (C) 2005 Dmitry Torokhov <dtor@mail.ru>
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
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 */
25
26#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
27
28#include <linux/kernel.h>
29#include <linux/module.h>
30#include <linux/init.h>
31#include <linux/types.h>
32#include <linux/slab.h>
33#include <linux/input.h>
34#include <linux/input/sparse-keymap.h>
35#include <linux/fb.h>
36#include <linux/backlight.h>
37#include <linux/platform_device.h>
38#include <acpi/acpi_bus.h>
39#include <acpi/acpi_drivers.h>
40
41#define EEEPC_WMI_FILE "eeepc-wmi"
42
43MODULE_AUTHOR("Yong Wang <yong.y.wang@intel.com>");
44MODULE_DESCRIPTION("Eee PC WMI Hotkey Driver");
45MODULE_LICENSE("GPL");
46
47#define EEEPC_WMI_EVENT_GUID "ABBC0F72-8EA1-11D1-00A0-C90629100000"
48#define EEEPC_WMI_MGMT_GUID "97845ED0-4E6D-11DE-8A39-0800200C9A66"
49
50MODULE_ALIAS("wmi:"EEEPC_WMI_EVENT_GUID);
51MODULE_ALIAS("wmi:"EEEPC_WMI_MGMT_GUID);
52
53#define NOTIFY_BRNUP_MIN 0x11
54#define NOTIFY_BRNUP_MAX 0x1f
55#define NOTIFY_BRNDOWN_MIN 0x20
56#define NOTIFY_BRNDOWN_MAX 0x2e
57
58#define EEEPC_WMI_METHODID_DEVS 0x53564544
59#define EEEPC_WMI_METHODID_DSTS 0x53544344
60
61#define EEEPC_WMI_DEVID_BACKLIGHT 0x00050012
62
63static const struct key_entry eeepc_wmi_keymap[] = {
64 /* Sleep already handled via generic ACPI code */
65 { KE_KEY, 0x5d, { KEY_WLAN } },
66 { KE_KEY, 0x32, { KEY_MUTE } },
67 { KE_KEY, 0x31, { KEY_VOLUMEDOWN } },
68 { KE_KEY, 0x30, { KEY_VOLUMEUP } },
69 { KE_IGNORE, NOTIFY_BRNDOWN_MIN, { KEY_BRIGHTNESSDOWN } },
70 { KE_IGNORE, NOTIFY_BRNUP_MIN, { KEY_BRIGHTNESSUP } },
71 { KE_KEY, 0xcc, { KEY_SWITCHVIDEOMODE } },
72 { KE_END, 0},
73};
74
75struct bios_args {
76 u32 dev_id;
77 u32 ctrl_param;
78};
79
80struct eeepc_wmi {
81 struct input_dev *inputdev;
82 struct backlight_device *backlight_device;
83};
84
85static struct platform_device *platform_device;
86
87static int eeepc_wmi_input_init(struct eeepc_wmi *eeepc)
88{
89 int err;
90
91 eeepc->inputdev = input_allocate_device();
92 if (!eeepc->inputdev)
93 return -ENOMEM;
94
95 eeepc->inputdev->name = "Eee PC WMI hotkeys";
96 eeepc->inputdev->phys = EEEPC_WMI_FILE "/input0";
97 eeepc->inputdev->id.bustype = BUS_HOST;
98 eeepc->inputdev->dev.parent = &platform_device->dev;
99
100 err = sparse_keymap_setup(eeepc->inputdev, eeepc_wmi_keymap, NULL);
101 if (err)
102 goto err_free_dev;
103
104 err = input_register_device(eeepc->inputdev);
105 if (err)
106 goto err_free_keymap;
107
108 return 0;
109
110err_free_keymap:
111 sparse_keymap_free(eeepc->inputdev);
112err_free_dev:
113 input_free_device(eeepc->inputdev);
114 return err;
115}
116
117static void eeepc_wmi_input_exit(struct eeepc_wmi *eeepc)
118{
119 if (eeepc->inputdev) {
120 sparse_keymap_free(eeepc->inputdev);
121 input_unregister_device(eeepc->inputdev);
122 }
123
124 eeepc->inputdev = NULL;
125}
126
127static acpi_status eeepc_wmi_get_devstate(u32 dev_id, u32 *ctrl_param)
128{
129 struct acpi_buffer input = { (acpi_size)sizeof(u32), &dev_id };
130 struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
131 union acpi_object *obj;
132 acpi_status status;
133 u32 tmp;
134
135 status = wmi_evaluate_method(EEEPC_WMI_MGMT_GUID,
136 1, EEEPC_WMI_METHODID_DSTS, &input, &output);
137
138 if (ACPI_FAILURE(status))
139 return status;
140
141 obj = (union acpi_object *)output.pointer;
142 if (obj && obj->type == ACPI_TYPE_INTEGER)
143 tmp = (u32)obj->integer.value;
144 else
145 tmp = 0;
146
147 if (ctrl_param)
148 *ctrl_param = tmp;
149
150 kfree(obj);
151
152 return status;
153
154}
155
156static acpi_status eeepc_wmi_set_devstate(u32 dev_id, u32 ctrl_param)
157{
158 struct bios_args args = {
159 .dev_id = dev_id,
160 .ctrl_param = ctrl_param,
161 };
162 struct acpi_buffer input = { (acpi_size)sizeof(args), &args };
163 acpi_status status;
164
165 status = wmi_evaluate_method(EEEPC_WMI_MGMT_GUID,
166 1, EEEPC_WMI_METHODID_DEVS, &input, NULL);
167
168 return status;
169}
170
171static int read_brightness(struct backlight_device *bd)
172{
173 static u32 ctrl_param;
174 acpi_status status;
175
176 status = eeepc_wmi_get_devstate(EEEPC_WMI_DEVID_BACKLIGHT, &ctrl_param);
177
178 if (ACPI_FAILURE(status))
179 return -1;
180 else
181 return ctrl_param & 0xFF;
182}
183
184static int update_bl_status(struct backlight_device *bd)
185{
186
187 static u32 ctrl_param;
188 acpi_status status;
189
190 ctrl_param = bd->props.brightness;
191
192 status = eeepc_wmi_set_devstate(EEEPC_WMI_DEVID_BACKLIGHT, ctrl_param);
193
194 if (ACPI_FAILURE(status))
195 return -1;
196 else
197 return 0;
198}
199
200static const struct backlight_ops eeepc_wmi_bl_ops = {
201 .get_brightness = read_brightness,
202 .update_status = update_bl_status,
203};
204
205static int eeepc_wmi_backlight_notify(struct eeepc_wmi *eeepc, int code)
206{
207 struct backlight_device *bd = eeepc->backlight_device;
208 int old = bd->props.brightness;
209 int new;
210
211 if (code >= NOTIFY_BRNUP_MIN && code <= NOTIFY_BRNUP_MAX)
212 new = code - NOTIFY_BRNUP_MIN + 1;
213 else if (code >= NOTIFY_BRNDOWN_MIN && code <= NOTIFY_BRNDOWN_MAX)
214 new = code - NOTIFY_BRNDOWN_MIN;
215
216 bd->props.brightness = new;
217 backlight_update_status(bd);
218 backlight_force_update(bd, BACKLIGHT_UPDATE_HOTKEY);
219
220 return old;
221}
222
223static int eeepc_wmi_backlight_init(struct eeepc_wmi *eeepc)
224{
225 struct backlight_device *bd;
226 struct backlight_properties props;
227
228 memset(&props, 0, sizeof(struct backlight_properties));
229 props.max_brightness = 15;
230 bd = backlight_device_register(EEEPC_WMI_FILE,
231 &platform_device->dev, eeepc,
232 &eeepc_wmi_bl_ops, &props);
233 if (IS_ERR(bd)) {
234 pr_err("Could not register backlight device\n");
235 return PTR_ERR(bd);
236 }
237
238 eeepc->backlight_device = bd;
239
240 bd->props.brightness = read_brightness(bd);
241 bd->props.power = FB_BLANK_UNBLANK;
242 backlight_update_status(bd);
243
244 return 0;
245}
246
247static void eeepc_wmi_backlight_exit(struct eeepc_wmi *eeepc)
248{
249 if (eeepc->backlight_device)
250 backlight_device_unregister(eeepc->backlight_device);
251
252 eeepc->backlight_device = NULL;
253}
254
255static void eeepc_wmi_notify(u32 value, void *context)
256{
257 struct eeepc_wmi *eeepc = context;
258 struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL };
259 union acpi_object *obj;
260 acpi_status status;
261 int code;
262 int orig_code;
263
264 status = wmi_get_event_data(value, &response);
265 if (status != AE_OK) {
266 pr_err("bad event status 0x%x\n", status);
267 return;
268 }
269
270 obj = (union acpi_object *)response.pointer;
271
272 if (obj && obj->type == ACPI_TYPE_INTEGER) {
273 code = obj->integer.value;
274 orig_code = code;
275
276 if (code >= NOTIFY_BRNUP_MIN && code <= NOTIFY_BRNUP_MAX)
277 code = NOTIFY_BRNUP_MIN;
278 else if (code >= NOTIFY_BRNDOWN_MIN &&
279 code <= NOTIFY_BRNDOWN_MAX)
280 code = NOTIFY_BRNDOWN_MIN;
281
282 if (code == NOTIFY_BRNUP_MIN || code == NOTIFY_BRNDOWN_MIN) {
283 if (!acpi_video_backlight_support())
284 eeepc_wmi_backlight_notify(eeepc, orig_code);
285 }
286
287 if (!sparse_keymap_report_event(eeepc->inputdev,
288 code, 1, true))
289 pr_info("Unknown key %x pressed\n", code);
290 }
291
292 kfree(obj);
293}
294
295static int __devinit eeepc_wmi_platform_probe(struct platform_device *device)
296{
297 struct eeepc_wmi *eeepc;
298 int err;
299 acpi_status status;
300
301 eeepc = platform_get_drvdata(device);
302
303 err = eeepc_wmi_input_init(eeepc);
304 if (err)
305 goto error_input;
306
307 if (!acpi_video_backlight_support()) {
308 err = eeepc_wmi_backlight_init(eeepc);
309 if (err)
310 goto error_backlight;
311 } else
312 pr_info("Backlight controlled by ACPI video driver\n");
313
314 status = wmi_install_notify_handler(EEEPC_WMI_EVENT_GUID,
315 eeepc_wmi_notify, eeepc);
316 if (ACPI_FAILURE(status)) {
317 pr_err("Unable to register notify handler - %d\n",
318 status);
319 err = -ENODEV;
320 goto error_wmi;
321 }
322
323 return 0;
324
325error_wmi:
326 eeepc_wmi_backlight_exit(eeepc);
327error_backlight:
328 eeepc_wmi_input_exit(eeepc);
329error_input:
330 return err;
331}
332
333static int __devexit eeepc_wmi_platform_remove(struct platform_device *device)
334{
335 struct eeepc_wmi *eeepc;
336
337 eeepc = platform_get_drvdata(device);
338 wmi_remove_notify_handler(EEEPC_WMI_EVENT_GUID);
339 eeepc_wmi_backlight_exit(eeepc);
340 eeepc_wmi_input_exit(eeepc);
341
342 return 0;
343}
344
345static struct platform_driver platform_driver = {
346 .driver = {
347 .name = EEEPC_WMI_FILE,
348 .owner = THIS_MODULE,
349 },
350 .probe = eeepc_wmi_platform_probe,
351 .remove = __devexit_p(eeepc_wmi_platform_remove),
352};
353
354static int __init eeepc_wmi_init(void)
355{
356 struct eeepc_wmi *eeepc;
357 int err;
358
359 if (!wmi_has_guid(EEEPC_WMI_EVENT_GUID) ||
360 !wmi_has_guid(EEEPC_WMI_MGMT_GUID)) {
361 pr_warning("No known WMI GUID found\n");
362 return -ENODEV;
363 }
364
365 eeepc = kzalloc(sizeof(struct eeepc_wmi), GFP_KERNEL);
366 if (!eeepc)
367 return -ENOMEM;
368
369 platform_device = platform_device_alloc(EEEPC_WMI_FILE, -1);
370 if (!platform_device) {
371 pr_warning("Unable to allocate platform device\n");
372 err = -ENOMEM;
373 goto fail_platform;
374 }
375
376 err = platform_device_add(platform_device);
377 if (err) {
378 pr_warning("Unable to add platform device\n");
379 goto put_dev;
380 }
381
382 platform_set_drvdata(platform_device, eeepc);
383
384 err = platform_driver_register(&platform_driver);
385 if (err) {
386 pr_warning("Unable to register platform driver\n");
387 goto del_dev;
388 }
389
390 return 0;
391
392del_dev:
393 platform_device_del(platform_device);
394put_dev:
395 platform_device_put(platform_device);
396fail_platform:
397 kfree(eeepc);
398
399 return err;
400}
401
402static void __exit eeepc_wmi_exit(void)
403{
404 struct eeepc_wmi *eeepc;
405
406 eeepc = platform_get_drvdata(platform_device);
407 platform_driver_unregister(&platform_driver);
408 platform_device_unregister(platform_device);
409 kfree(eeepc);
410}
411
412module_init(eeepc_wmi_init);
413module_exit(eeepc_wmi_exit);
diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c
index bcd4ba8be7db..47b4fd75aa34 100644
--- a/drivers/platform/x86/fujitsu-laptop.c
+++ b/drivers/platform/x86/fujitsu-laptop.c
@@ -66,6 +66,7 @@
66#include <linux/kfifo.h> 66#include <linux/kfifo.h>
67#include <linux/video_output.h> 67#include <linux/video_output.h>
68#include <linux/platform_device.h> 68#include <linux/platform_device.h>
69#include <linux/slab.h>
69#if defined(CONFIG_LEDS_CLASS) || defined(CONFIG_LEDS_CLASS_MODULE) 70#if defined(CONFIG_LEDS_CLASS) || defined(CONFIG_LEDS_CLASS_MODULE)
70#include <linux/leds.h> 71#include <linux/leds.h>
71#endif 72#endif
@@ -164,7 +165,7 @@ struct fujitsu_hotkey_t {
164 struct input_dev *input; 165 struct input_dev *input;
165 char phys[32]; 166 char phys[32];
166 struct platform_device *pf_device; 167 struct platform_device *pf_device;
167 struct kfifo *fifo; 168 struct kfifo fifo;
168 spinlock_t fifo_lock; 169 spinlock_t fifo_lock;
169 int rfkill_supported; 170 int rfkill_supported;
170 int rfkill_state; 171 int rfkill_state;
@@ -376,8 +377,8 @@ static int get_lcd_level(void)
376 377
377 status = 378 status =
378 acpi_evaluate_integer(fujitsu->acpi_handle, "GBLL", NULL, &state); 379 acpi_evaluate_integer(fujitsu->acpi_handle, "GBLL", NULL, &state);
379 if (status < 0) 380 if (ACPI_FAILURE(status))
380 return status; 381 return 0;
381 382
382 fujitsu->brightness_level = state & 0x0fffffff; 383 fujitsu->brightness_level = state & 0x0fffffff;
383 384
@@ -398,8 +399,8 @@ static int get_max_brightness(void)
398 399
399 status = 400 status =
400 acpi_evaluate_integer(fujitsu->acpi_handle, "RBLL", NULL, &state); 401 acpi_evaluate_integer(fujitsu->acpi_handle, "RBLL", NULL, &state);
401 if (status < 0) 402 if (ACPI_FAILURE(status))
402 return status; 403 return -1;
403 404
404 fujitsu->max_brightness = state; 405 fujitsu->max_brightness = state;
405 406
@@ -824,12 +825,10 @@ static int acpi_fujitsu_hotkey_add(struct acpi_device *device)
824 825
825 /* kfifo */ 826 /* kfifo */
826 spin_lock_init(&fujitsu_hotkey->fifo_lock); 827 spin_lock_init(&fujitsu_hotkey->fifo_lock);
827 fujitsu_hotkey->fifo = 828 error = kfifo_alloc(&fujitsu_hotkey->fifo, RINGBUFFERSIZE * sizeof(int),
828 kfifo_alloc(RINGBUFFERSIZE * sizeof(int), GFP_KERNEL, 829 GFP_KERNEL);
829 &fujitsu_hotkey->fifo_lock); 830 if (error) {
830 if (IS_ERR(fujitsu_hotkey->fifo)) {
831 printk(KERN_ERR "kfifo_alloc failed\n"); 831 printk(KERN_ERR "kfifo_alloc failed\n");
832 error = PTR_ERR(fujitsu_hotkey->fifo);
833 goto err_stop; 832 goto err_stop;
834 } 833 }
835 834
@@ -934,7 +933,7 @@ err_unregister_input_dev:
934err_free_input_dev: 933err_free_input_dev:
935 input_free_device(input); 934 input_free_device(input);
936err_free_fifo: 935err_free_fifo:
937 kfifo_free(fujitsu_hotkey->fifo); 936 kfifo_free(&fujitsu_hotkey->fifo);
938err_stop: 937err_stop:
939 return result; 938 return result;
940} 939}
@@ -956,7 +955,7 @@ static int acpi_fujitsu_hotkey_remove(struct acpi_device *device, int type)
956 955
957 input_free_device(input); 956 input_free_device(input);
958 957
959 kfifo_free(fujitsu_hotkey->fifo); 958 kfifo_free(&fujitsu_hotkey->fifo);
960 959
961 fujitsu_hotkey->acpi_handle = NULL; 960 fujitsu_hotkey->acpi_handle = NULL;
962 961
@@ -1008,9 +1007,10 @@ static void acpi_fujitsu_hotkey_notify(struct acpi_device *device, u32 event)
1008 vdbg_printk(FUJLAPTOP_DBG_TRACE, 1007 vdbg_printk(FUJLAPTOP_DBG_TRACE,
1009 "Push keycode into ringbuffer [%d]\n", 1008 "Push keycode into ringbuffer [%d]\n",
1010 keycode); 1009 keycode);
1011 status = kfifo_put(fujitsu_hotkey->fifo, 1010 status = kfifo_in_locked(&fujitsu_hotkey->fifo,
1012 (unsigned char *)&keycode, 1011 (unsigned char *)&keycode,
1013 sizeof(keycode)); 1012 sizeof(keycode),
1013 &fujitsu_hotkey->fifo_lock);
1014 if (status != sizeof(keycode)) { 1014 if (status != sizeof(keycode)) {
1015 vdbg_printk(FUJLAPTOP_DBG_WARN, 1015 vdbg_printk(FUJLAPTOP_DBG_WARN,
1016 "Could not push keycode [0x%x]\n", 1016 "Could not push keycode [0x%x]\n",
@@ -1021,11 +1021,12 @@ static void acpi_fujitsu_hotkey_notify(struct acpi_device *device, u32 event)
1021 } 1021 }
1022 } else if (keycode == 0) { 1022 } else if (keycode == 0) {
1023 while ((status = 1023 while ((status =
1024 kfifo_get 1024 kfifo_out_locked(
1025 (fujitsu_hotkey->fifo, (unsigned char *) 1025 &fujitsu_hotkey->fifo,
1026 &keycode_r, 1026 (unsigned char *) &keycode_r,
1027 sizeof 1027 sizeof(keycode_r),
1028 (keycode_r))) == sizeof(keycode_r)) { 1028 &fujitsu_hotkey->fifo_lock))
1029 == sizeof(keycode_r)) {
1029 input_report_key(input, keycode_r, 0); 1030 input_report_key(input, keycode_r, 0);
1030 input_sync(input); 1031 input_sync(input);
1031 vdbg_printk(FUJLAPTOP_DBG_TRACE, 1032 vdbg_printk(FUJLAPTOP_DBG_TRACE,
@@ -1126,16 +1127,20 @@ static int __init fujitsu_init(void)
1126 /* Register backlight stuff */ 1127 /* Register backlight stuff */
1127 1128
1128 if (!acpi_video_backlight_support()) { 1129 if (!acpi_video_backlight_support()) {
1129 fujitsu->bl_device = 1130 struct backlight_properties props;
1130 backlight_device_register("fujitsu-laptop", NULL, NULL, 1131
1131 &fujitsubl_ops); 1132 memset(&props, 0, sizeof(struct backlight_properties));
1133 max_brightness = fujitsu->max_brightness;
1134 props.max_brightness = max_brightness - 1;
1135 fujitsu->bl_device = backlight_device_register("fujitsu-laptop",
1136 NULL, NULL,
1137 &fujitsubl_ops,
1138 &props);
1132 if (IS_ERR(fujitsu->bl_device)) { 1139 if (IS_ERR(fujitsu->bl_device)) {
1133 ret = PTR_ERR(fujitsu->bl_device); 1140 ret = PTR_ERR(fujitsu->bl_device);
1134 fujitsu->bl_device = NULL; 1141 fujitsu->bl_device = NULL;
1135 goto fail_sysfs_group; 1142 goto fail_sysfs_group;
1136 } 1143 }
1137 max_brightness = fujitsu->max_brightness;
1138 fujitsu->bl_device->props.max_brightness = max_brightness - 1;
1139 fujitsu->bl_device->props.brightness = fujitsu->brightness_level; 1144 fujitsu->bl_device->props.brightness = fujitsu->brightness_level;
1140 } 1145 }
1141 1146
diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c
index c2842171cec6..51c07a05a7bc 100644
--- a/drivers/platform/x86/hp-wmi.c
+++ b/drivers/platform/x86/hp-wmi.c
@@ -26,6 +26,7 @@
26#include <linux/kernel.h> 26#include <linux/kernel.h>
27#include <linux/module.h> 27#include <linux/module.h>
28#include <linux/init.h> 28#include <linux/init.h>
29#include <linux/slab.h>
29#include <linux/types.h> 30#include <linux/types.h>
30#include <linux/input.h> 31#include <linux/input.h>
31#include <acpi/acpi_drivers.h> 32#include <acpi/acpi_drivers.h>
@@ -51,7 +52,13 @@ MODULE_ALIAS("wmi:5FB7F034-2C63-45e9-BE91-3D44E2C707E4");
51#define HPWMI_WIRELESS_QUERY 0x5 52#define HPWMI_WIRELESS_QUERY 0x5
52#define HPWMI_HOTKEY_QUERY 0xc 53#define HPWMI_HOTKEY_QUERY 0xc
53 54
54static int __init hp_wmi_bios_setup(struct platform_device *device); 55enum hp_wmi_radio {
56 HPWMI_WIFI = 0,
57 HPWMI_BLUETOOTH = 1,
58 HPWMI_WWAN = 2,
59};
60
61static int __devinit hp_wmi_bios_setup(struct platform_device *device);
55static int __exit hp_wmi_bios_remove(struct platform_device *device); 62static int __exit hp_wmi_bios_remove(struct platform_device *device);
56static int hp_wmi_resume_handler(struct device *device); 63static int hp_wmi_resume_handler(struct device *device);
57 64
@@ -83,6 +90,7 @@ static struct key_entry hp_wmi_keymap[] = {
83 {KE_KEY, 0x20e6, KEY_PROG1}, 90 {KE_KEY, 0x20e6, KEY_PROG1},
84 {KE_KEY, 0x2142, KEY_MEDIA}, 91 {KE_KEY, 0x2142, KEY_MEDIA},
85 {KE_KEY, 0x213b, KEY_INFO}, 92 {KE_KEY, 0x213b, KEY_INFO},
93 {KE_KEY, 0x2169, KEY_DIRECTION},
86 {KE_KEY, 0x231b, KEY_HELP}, 94 {KE_KEY, 0x231b, KEY_HELP},
87 {KE_END, 0} 95 {KE_END, 0}
88}; 96};
@@ -94,7 +102,7 @@ static struct rfkill *wifi_rfkill;
94static struct rfkill *bluetooth_rfkill; 102static struct rfkill *bluetooth_rfkill;
95static struct rfkill *wwan_rfkill; 103static struct rfkill *wwan_rfkill;
96 104
97static struct dev_pm_ops hp_wmi_pm_ops = { 105static const struct dev_pm_ops hp_wmi_pm_ops = {
98 .resume = hp_wmi_resume_handler, 106 .resume = hp_wmi_resume_handler,
99 .restore = hp_wmi_resume_handler, 107 .restore = hp_wmi_resume_handler,
100}; 108};
@@ -128,10 +136,15 @@ static int hp_wmi_perform_query(int query, int write, int value)
128 136
129 obj = output.pointer; 137 obj = output.pointer;
130 138
131 if (!obj || obj->type != ACPI_TYPE_BUFFER) 139 if (!obj)
140 return -EINVAL;
141 else if (obj->type != ACPI_TYPE_BUFFER) {
142 kfree(obj);
132 return -EINVAL; 143 return -EINVAL;
144 }
133 145
134 bios_return = *((struct bios_return *)obj->buffer.pointer); 146 bios_return = *((struct bios_return *)obj->buffer.pointer);
147 kfree(obj);
135 if (bios_return.return_code > 0) 148 if (bios_return.return_code > 0)
136 return bios_return.return_code * -1; 149 return bios_return.return_code * -1;
137 else 150 else
@@ -175,8 +188,8 @@ static int hp_wmi_tablet_state(void)
175 188
176static int hp_wmi_set_block(void *data, bool blocked) 189static int hp_wmi_set_block(void *data, bool blocked)
177{ 190{
178 unsigned long b = (unsigned long) data; 191 enum hp_wmi_radio r = (enum hp_wmi_radio) data;
179 int query = BIT(b + 8) | ((!blocked) << b); 192 int query = BIT(r + 8) | ((!blocked) << r);
180 193
181 return hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, query); 194 return hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, query);
182} 195}
@@ -185,31 +198,23 @@ static const struct rfkill_ops hp_wmi_rfkill_ops = {
185 .set_block = hp_wmi_set_block, 198 .set_block = hp_wmi_set_block,
186}; 199};
187 200
188static bool hp_wmi_wifi_state(void) 201static bool hp_wmi_get_sw_state(enum hp_wmi_radio r)
189{ 202{
190 int wireless = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 0); 203 int wireless = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 0);
204 int mask = 0x200 << (r * 8);
191 205
192 if (wireless & 0x100) 206 if (wireless & mask)
193 return false; 207 return false;
194 else 208 else
195 return true; 209 return true;
196} 210}
197 211
198static bool hp_wmi_bluetooth_state(void) 212static bool hp_wmi_get_hw_state(enum hp_wmi_radio r)
199{ 213{
200 int wireless = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 0); 214 int wireless = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 0);
215 int mask = 0x800 << (r * 8);
201 216
202 if (wireless & 0x10000) 217 if (wireless & mask)
203 return false;
204 else
205 return true;
206}
207
208static bool hp_wmi_wwan_state(void)
209{
210 int wireless = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 0);
211
212 if (wireless & 0x1000000)
213 return false; 218 return false;
214 else 219 else
215 return true; 220 return true;
@@ -274,7 +279,7 @@ static DEVICE_ATTR(als, S_IRUGO | S_IWUSR, show_als, set_als);
274static DEVICE_ATTR(dock, S_IRUGO, show_dock, NULL); 279static DEVICE_ATTR(dock, S_IRUGO, show_dock, NULL);
275static DEVICE_ATTR(tablet, S_IRUGO, show_tablet, NULL); 280static DEVICE_ATTR(tablet, S_IRUGO, show_tablet, NULL);
276 281
277static struct key_entry *hp_wmi_get_entry_by_scancode(int code) 282static struct key_entry *hp_wmi_get_entry_by_scancode(unsigned int code)
278{ 283{
279 struct key_entry *key; 284 struct key_entry *key;
280 285
@@ -285,7 +290,7 @@ static struct key_entry *hp_wmi_get_entry_by_scancode(int code)
285 return NULL; 290 return NULL;
286} 291}
287 292
288static struct key_entry *hp_wmi_get_entry_by_keycode(int keycode) 293static struct key_entry *hp_wmi_get_entry_by_keycode(unsigned int keycode)
289{ 294{
290 struct key_entry *key; 295 struct key_entry *key;
291 296
@@ -296,7 +301,8 @@ static struct key_entry *hp_wmi_get_entry_by_keycode(int keycode)
296 return NULL; 301 return NULL;
297} 302}
298 303
299static int hp_wmi_getkeycode(struct input_dev *dev, int scancode, int *keycode) 304static int hp_wmi_getkeycode(struct input_dev *dev,
305 unsigned int scancode, unsigned int *keycode)
300{ 306{
301 struct key_entry *key = hp_wmi_get_entry_by_scancode(scancode); 307 struct key_entry *key = hp_wmi_get_entry_by_scancode(scancode);
302 308
@@ -308,13 +314,11 @@ static int hp_wmi_getkeycode(struct input_dev *dev, int scancode, int *keycode)
308 return -EINVAL; 314 return -EINVAL;
309} 315}
310 316
311static int hp_wmi_setkeycode(struct input_dev *dev, int scancode, int keycode) 317static int hp_wmi_setkeycode(struct input_dev *dev,
318 unsigned int scancode, unsigned int keycode)
312{ 319{
313 struct key_entry *key; 320 struct key_entry *key;
314 int old_keycode; 321 unsigned int old_keycode;
315
316 if (keycode < 0 || keycode > KEY_MAX)
317 return -EINVAL;
318 322
319 key = hp_wmi_get_entry_by_scancode(scancode); 323 key = hp_wmi_get_entry_by_scancode(scancode);
320 if (key && key->type == KE_KEY) { 324 if (key && key->type == KE_KEY) {
@@ -334,49 +338,62 @@ static void hp_wmi_notify(u32 value, void *context)
334 struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL }; 338 struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL };
335 static struct key_entry *key; 339 static struct key_entry *key;
336 union acpi_object *obj; 340 union acpi_object *obj;
341 int eventcode;
342 acpi_status status;
337 343
338 wmi_get_event_data(value, &response); 344 status = wmi_get_event_data(value, &response);
345 if (status != AE_OK) {
346 printk(KERN_INFO "hp-wmi: bad event status 0x%x\n", status);
347 return;
348 }
339 349
340 obj = (union acpi_object *)response.pointer; 350 obj = (union acpi_object *)response.pointer;
341 351
342 if (obj && obj->type == ACPI_TYPE_BUFFER && obj->buffer.length == 8) { 352 if (!obj || obj->type != ACPI_TYPE_BUFFER || obj->buffer.length != 8) {
343 int eventcode = *((u8 *) obj->buffer.pointer); 353 printk(KERN_INFO "HP WMI: Unknown response received\n");
344 if (eventcode == 0x4) 354 kfree(obj);
345 eventcode = hp_wmi_perform_query(HPWMI_HOTKEY_QUERY, 0, 355 return;
346 0); 356 }
347 key = hp_wmi_get_entry_by_scancode(eventcode); 357
348 if (key) { 358 eventcode = *((u8 *) obj->buffer.pointer);
349 switch (key->type) { 359 kfree(obj);
350 case KE_KEY: 360 if (eventcode == 0x4)
351 input_report_key(hp_wmi_input_dev, 361 eventcode = hp_wmi_perform_query(HPWMI_HOTKEY_QUERY, 0,
352 key->keycode, 1); 362 0);
353 input_sync(hp_wmi_input_dev); 363 key = hp_wmi_get_entry_by_scancode(eventcode);
354 input_report_key(hp_wmi_input_dev, 364 if (key) {
355 key->keycode, 0); 365 switch (key->type) {
356 input_sync(hp_wmi_input_dev); 366 case KE_KEY:
357 break; 367 input_report_key(hp_wmi_input_dev,
358 } 368 key->keycode, 1);
359 } else if (eventcode == 0x1) {
360 input_report_switch(hp_wmi_input_dev, SW_DOCK,
361 hp_wmi_dock_state());
362 input_report_switch(hp_wmi_input_dev, SW_TABLET_MODE,
363 hp_wmi_tablet_state());
364 input_sync(hp_wmi_input_dev); 369 input_sync(hp_wmi_input_dev);
365 } else if (eventcode == 0x5) { 370 input_report_key(hp_wmi_input_dev,
366 if (wifi_rfkill) 371 key->keycode, 0);
367 rfkill_set_sw_state(wifi_rfkill, 372 input_sync(hp_wmi_input_dev);
368 hp_wmi_wifi_state()); 373 break;
369 if (bluetooth_rfkill) 374 }
370 rfkill_set_sw_state(bluetooth_rfkill, 375 } else if (eventcode == 0x1) {
371 hp_wmi_bluetooth_state()); 376 input_report_switch(hp_wmi_input_dev, SW_DOCK,
372 if (wwan_rfkill) 377 hp_wmi_dock_state());
373 rfkill_set_sw_state(wwan_rfkill, 378 input_report_switch(hp_wmi_input_dev, SW_TABLET_MODE,
374 hp_wmi_wwan_state()); 379 hp_wmi_tablet_state());
375 } else 380 input_sync(hp_wmi_input_dev);
376 printk(KERN_INFO "HP WMI: Unknown key pressed - %x\n", 381 } else if (eventcode == 0x5) {
377 eventcode); 382 if (wifi_rfkill)
383 rfkill_set_states(wifi_rfkill,
384 hp_wmi_get_sw_state(HPWMI_WIFI),
385 hp_wmi_get_hw_state(HPWMI_WIFI));
386 if (bluetooth_rfkill)
387 rfkill_set_states(bluetooth_rfkill,
388 hp_wmi_get_sw_state(HPWMI_BLUETOOTH),
389 hp_wmi_get_hw_state(HPWMI_BLUETOOTH));
390 if (wwan_rfkill)
391 rfkill_set_states(wwan_rfkill,
392 hp_wmi_get_sw_state(HPWMI_WWAN),
393 hp_wmi_get_hw_state(HPWMI_WWAN));
378 } else 394 } else
379 printk(KERN_INFO "HP WMI: Unknown response received\n"); 395 printk(KERN_INFO "HP WMI: Unknown key pressed - %x\n",
396 eventcode);
380} 397}
381 398
382static int __init hp_wmi_input_setup(void) 399static int __init hp_wmi_input_setup(void)
@@ -430,7 +447,7 @@ static void cleanup_sysfs(struct platform_device *device)
430 device_remove_file(&device->dev, &dev_attr_tablet); 447 device_remove_file(&device->dev, &dev_attr_tablet);
431} 448}
432 449
433static int __init hp_wmi_bios_setup(struct platform_device *device) 450static int __devinit hp_wmi_bios_setup(struct platform_device *device)
434{ 451{
435 int err; 452 int err;
436 int wireless = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 0); 453 int wireless = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 0);
@@ -455,7 +472,11 @@ static int __init hp_wmi_bios_setup(struct platform_device *device)
455 wifi_rfkill = rfkill_alloc("hp-wifi", &device->dev, 472 wifi_rfkill = rfkill_alloc("hp-wifi", &device->dev,
456 RFKILL_TYPE_WLAN, 473 RFKILL_TYPE_WLAN,
457 &hp_wmi_rfkill_ops, 474 &hp_wmi_rfkill_ops,
458 (void *) 0); 475 (void *) HPWMI_WIFI);
476 rfkill_init_sw_state(wifi_rfkill,
477 hp_wmi_get_sw_state(HPWMI_WIFI));
478 rfkill_set_hw_state(wifi_rfkill,
479 hp_wmi_get_hw_state(HPWMI_WIFI));
459 err = rfkill_register(wifi_rfkill); 480 err = rfkill_register(wifi_rfkill);
460 if (err) 481 if (err)
461 goto register_wifi_error; 482 goto register_wifi_error;
@@ -465,7 +486,11 @@ static int __init hp_wmi_bios_setup(struct platform_device *device)
465 bluetooth_rfkill = rfkill_alloc("hp-bluetooth", &device->dev, 486 bluetooth_rfkill = rfkill_alloc("hp-bluetooth", &device->dev,
466 RFKILL_TYPE_BLUETOOTH, 487 RFKILL_TYPE_BLUETOOTH,
467 &hp_wmi_rfkill_ops, 488 &hp_wmi_rfkill_ops,
468 (void *) 1); 489 (void *) HPWMI_BLUETOOTH);
490 rfkill_init_sw_state(bluetooth_rfkill,
491 hp_wmi_get_sw_state(HPWMI_BLUETOOTH));
492 rfkill_set_hw_state(bluetooth_rfkill,
493 hp_wmi_get_hw_state(HPWMI_BLUETOOTH));
469 err = rfkill_register(bluetooth_rfkill); 494 err = rfkill_register(bluetooth_rfkill);
470 if (err) 495 if (err)
471 goto register_bluetooth_error; 496 goto register_bluetooth_error;
@@ -475,7 +500,11 @@ static int __init hp_wmi_bios_setup(struct platform_device *device)
475 wwan_rfkill = rfkill_alloc("hp-wwan", &device->dev, 500 wwan_rfkill = rfkill_alloc("hp-wwan", &device->dev,
476 RFKILL_TYPE_WWAN, 501 RFKILL_TYPE_WWAN,
477 &hp_wmi_rfkill_ops, 502 &hp_wmi_rfkill_ops,
478 (void *) 2); 503 (void *) HPWMI_WWAN);
504 rfkill_init_sw_state(wwan_rfkill,
505 hp_wmi_get_sw_state(HPWMI_WWAN));
506 rfkill_set_hw_state(wwan_rfkill,
507 hp_wmi_get_hw_state(HPWMI_WWAN));
479 err = rfkill_register(wwan_rfkill); 508 err = rfkill_register(wwan_rfkill);
480 if (err) 509 if (err)
481 goto register_wwan_err; 510 goto register_wwan_err;
@@ -533,6 +562,19 @@ static int hp_wmi_resume_handler(struct device *device)
533 input_sync(hp_wmi_input_dev); 562 input_sync(hp_wmi_input_dev);
534 } 563 }
535 564
565 if (wifi_rfkill)
566 rfkill_set_states(wifi_rfkill,
567 hp_wmi_get_sw_state(HPWMI_WIFI),
568 hp_wmi_get_hw_state(HPWMI_WIFI));
569 if (bluetooth_rfkill)
570 rfkill_set_states(bluetooth_rfkill,
571 hp_wmi_get_sw_state(HPWMI_BLUETOOTH),
572 hp_wmi_get_hw_state(HPWMI_BLUETOOTH));
573 if (wwan_rfkill)
574 rfkill_set_states(wwan_rfkill,
575 hp_wmi_get_sw_state(HPWMI_WWAN),
576 hp_wmi_get_hw_state(HPWMI_WWAN));
577
536 return 0; 578 return 0;
537} 579}
538 580
@@ -543,7 +585,7 @@ static int __init hp_wmi_init(void)
543 if (wmi_has_guid(HPWMI_EVENT_GUID)) { 585 if (wmi_has_guid(HPWMI_EVENT_GUID)) {
544 err = wmi_install_notify_handler(HPWMI_EVENT_GUID, 586 err = wmi_install_notify_handler(HPWMI_EVENT_GUID,
545 hp_wmi_notify, NULL); 587 hp_wmi_notify, NULL);
546 if (!err) 588 if (ACPI_SUCCESS(err))
547 hp_wmi_input_setup(); 589 hp_wmi_input_setup();
548 } 590 }
549 591
diff --git a/drivers/platform/x86/intel_menlow.c b/drivers/platform/x86/intel_menlow.c
index 29432a50be45..2f795ce2b939 100644
--- a/drivers/platform/x86/intel_menlow.c
+++ b/drivers/platform/x86/intel_menlow.c
@@ -30,6 +30,7 @@
30#include <linux/kernel.h> 30#include <linux/kernel.h>
31#include <linux/module.h> 31#include <linux/module.h>
32#include <linux/init.h> 32#include <linux/init.h>
33#include <linux/slab.h>
33#include <linux/types.h> 34#include <linux/types.h>
34#include <linux/pci.h> 35#include <linux/pci.h>
35#include <linux/pm.h> 36#include <linux/pm.h>
@@ -396,6 +397,7 @@ static int intel_menlow_add_one_attribute(char *name, int mode, void *show,
396 if (!attr) 397 if (!attr)
397 return -ENOMEM; 398 return -ENOMEM;
398 399
400 sysfs_attr_init(&attr->attr.attr); /* That is consistent naming :D */
399 attr->attr.attr.name = name; 401 attr->attr.attr.name = name;
400 attr->attr.attr.mode = mode; 402 attr->attr.attr.mode = mode;
401 attr->attr.show = show; 403 attr->attr.show = show;
@@ -510,7 +512,7 @@ static int __init intel_menlow_module_init(void)
510 /* Looking for sensors in each ACPI thermal zone */ 512 /* Looking for sensors in each ACPI thermal zone */
511 status = acpi_walk_namespace(ACPI_TYPE_THERMAL, ACPI_ROOT_OBJECT, 513 status = acpi_walk_namespace(ACPI_TYPE_THERMAL, ACPI_ROOT_OBJECT,
512 ACPI_UINT32_MAX, 514 ACPI_UINT32_MAX,
513 intel_menlow_register_sensor, NULL, NULL); 515 intel_menlow_register_sensor, NULL, NULL, NULL);
514 if (ACPI_FAILURE(status)) 516 if (ACPI_FAILURE(status))
515 return -ENODEV; 517 return -ENODEV;
516 518
diff --git a/drivers/platform/x86/msi-laptop.c b/drivers/platform/x86/msi-laptop.c
index 759763d18e4c..996223a7c009 100644
--- a/drivers/platform/x86/msi-laptop.c
+++ b/drivers/platform/x86/msi-laptop.c
@@ -58,6 +58,7 @@
58#include <linux/dmi.h> 58#include <linux/dmi.h>
59#include <linux/backlight.h> 59#include <linux/backlight.h>
60#include <linux/platform_device.h> 60#include <linux/platform_device.h>
61#include <linux/rfkill.h>
61 62
62#define MSI_DRIVER_VERSION "0.5" 63#define MSI_DRIVER_VERSION "0.5"
63 64
@@ -66,6 +67,20 @@
66#define MSI_EC_COMMAND_WIRELESS 0x10 67#define MSI_EC_COMMAND_WIRELESS 0x10
67#define MSI_EC_COMMAND_LCD_LEVEL 0x11 68#define MSI_EC_COMMAND_LCD_LEVEL 0x11
68 69
70#define MSI_STANDARD_EC_COMMAND_ADDRESS 0x2e
71#define MSI_STANDARD_EC_BLUETOOTH_MASK (1 << 0)
72#define MSI_STANDARD_EC_WEBCAM_MASK (1 << 1)
73#define MSI_STANDARD_EC_WLAN_MASK (1 << 3)
74#define MSI_STANDARD_EC_3G_MASK (1 << 4)
75
76/* For set SCM load flag to disable BIOS fn key */
77#define MSI_STANDARD_EC_SCM_LOAD_ADDRESS 0x2d
78#define MSI_STANDARD_EC_SCM_LOAD_MASK (1 << 0)
79
80static int msi_laptop_resume(struct platform_device *device);
81
82#define MSI_STANDARD_EC_DEVICES_EXISTS_ADDRESS 0x2f
83
69static int force; 84static int force;
70module_param(force, bool, 0); 85module_param(force, bool, 0);
71MODULE_PARM_DESC(force, "Force driver load, ignore DMI data"); 86MODULE_PARM_DESC(force, "Force driver load, ignore DMI data");
@@ -74,6 +89,23 @@ static int auto_brightness;
74module_param(auto_brightness, int, 0); 89module_param(auto_brightness, int, 0);
75MODULE_PARM_DESC(auto_brightness, "Enable automatic brightness control (0: disabled; 1: enabled; 2: don't touch)"); 90MODULE_PARM_DESC(auto_brightness, "Enable automatic brightness control (0: disabled; 1: enabled; 2: don't touch)");
76 91
92static bool old_ec_model;
93static int wlan_s, bluetooth_s, threeg_s;
94static int threeg_exists;
95
96/* Some MSI 3G netbook only have one fn key to control Wlan/Bluetooth/3G,
97 * those netbook will load the SCM (windows app) to disable the original
98 * Wlan/Bluetooth control by BIOS when user press fn key, then control
99 * Wlan/Bluetooth/3G by SCM (software control by OS). Without SCM, user
100 * cann't on/off 3G module on those 3G netbook.
101 * On Linux, msi-laptop driver will do the same thing to disable the
102 * original BIOS control, then might need use HAL or other userland
103 * application to do the software control that simulate with SCM.
104 * e.g. MSI N034 netbook
105 */
106static bool load_scm_model;
107static struct rfkill *rfk_wlan, *rfk_bluetooth, *rfk_threeg;
108
77/* Hardware access */ 109/* Hardware access */
78 110
79static int set_lcd_level(int level) 111static int set_lcd_level(int level)
@@ -130,6 +162,35 @@ static int set_auto_brightness(int enable)
130 return ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, wdata, 2, NULL, 0, 1); 162 return ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, wdata, 2, NULL, 0, 1);
131} 163}
132 164
165static ssize_t set_device_state(const char *buf, size_t count, u8 mask)
166{
167 int status;
168 u8 wdata = 0, rdata;
169 int result;
170
171 if (sscanf(buf, "%i", &status) != 1 || (status < 0 || status > 1))
172 return -EINVAL;
173
174 /* read current device state */
175 result = ec_read(MSI_STANDARD_EC_COMMAND_ADDRESS, &rdata);
176 if (result < 0)
177 return -EINVAL;
178
179 if (!!(rdata & mask) != status) {
180 /* reverse device bit */
181 if (rdata & mask)
182 wdata = rdata & ~mask;
183 else
184 wdata = rdata | mask;
185
186 result = ec_write(MSI_STANDARD_EC_COMMAND_ADDRESS, wdata);
187 if (result < 0)
188 return -EINVAL;
189 }
190
191 return count;
192}
193
133static int get_wireless_state(int *wlan, int *bluetooth) 194static int get_wireless_state(int *wlan, int *bluetooth)
134{ 195{
135 u8 wdata = 0, rdata; 196 u8 wdata = 0, rdata;
@@ -148,6 +209,38 @@ static int get_wireless_state(int *wlan, int *bluetooth)
148 return 0; 209 return 0;
149} 210}
150 211
212static int get_wireless_state_ec_standard(void)
213{
214 u8 rdata;
215 int result;
216
217 result = ec_read(MSI_STANDARD_EC_COMMAND_ADDRESS, &rdata);
218 if (result < 0)
219 return -1;
220
221 wlan_s = !!(rdata & MSI_STANDARD_EC_WLAN_MASK);
222
223 bluetooth_s = !!(rdata & MSI_STANDARD_EC_BLUETOOTH_MASK);
224
225 threeg_s = !!(rdata & MSI_STANDARD_EC_3G_MASK);
226
227 return 0;
228}
229
230static int get_threeg_exists(void)
231{
232 u8 rdata;
233 int result;
234
235 result = ec_read(MSI_STANDARD_EC_DEVICES_EXISTS_ADDRESS, &rdata);
236 if (result < 0)
237 return -1;
238
239 threeg_exists = !!(rdata & MSI_STANDARD_EC_3G_MASK);
240
241 return 0;
242}
243
151/* Backlight device stuff */ 244/* Backlight device stuff */
152 245
153static int bl_get_brightness(struct backlight_device *b) 246static int bl_get_brightness(struct backlight_device *b)
@@ -176,26 +269,71 @@ static ssize_t show_wlan(struct device *dev,
176 269
177 int ret, enabled; 270 int ret, enabled;
178 271
179 ret = get_wireless_state(&enabled, NULL); 272 if (old_ec_model) {
273 ret = get_wireless_state(&enabled, NULL);
274 } else {
275 ret = get_wireless_state_ec_standard();
276 enabled = wlan_s;
277 }
180 if (ret < 0) 278 if (ret < 0)
181 return ret; 279 return ret;
182 280
183 return sprintf(buf, "%i\n", enabled); 281 return sprintf(buf, "%i\n", enabled);
184} 282}
185 283
284static ssize_t store_wlan(struct device *dev,
285 struct device_attribute *attr, const char *buf, size_t count)
286{
287 return set_device_state(buf, count, MSI_STANDARD_EC_WLAN_MASK);
288}
289
186static ssize_t show_bluetooth(struct device *dev, 290static ssize_t show_bluetooth(struct device *dev,
187 struct device_attribute *attr, char *buf) 291 struct device_attribute *attr, char *buf)
188{ 292{
189 293
190 int ret, enabled; 294 int ret, enabled;
191 295
192 ret = get_wireless_state(NULL, &enabled); 296 if (old_ec_model) {
297 ret = get_wireless_state(NULL, &enabled);
298 } else {
299 ret = get_wireless_state_ec_standard();
300 enabled = bluetooth_s;
301 }
193 if (ret < 0) 302 if (ret < 0)
194 return ret; 303 return ret;
195 304
196 return sprintf(buf, "%i\n", enabled); 305 return sprintf(buf, "%i\n", enabled);
197} 306}
198 307
308static ssize_t store_bluetooth(struct device *dev,
309 struct device_attribute *attr, const char *buf, size_t count)
310{
311 return set_device_state(buf, count, MSI_STANDARD_EC_BLUETOOTH_MASK);
312}
313
314static ssize_t show_threeg(struct device *dev,
315 struct device_attribute *attr, char *buf)
316{
317
318 int ret;
319
320 /* old msi ec not support 3G */
321 if (old_ec_model)
322 return -1;
323
324 ret = get_wireless_state_ec_standard();
325 if (ret < 0)
326 return ret;
327
328 return sprintf(buf, "%i\n", threeg_s);
329}
330
331static ssize_t store_threeg(struct device *dev,
332 struct device_attribute *attr, const char *buf, size_t count)
333{
334 return set_device_state(buf, count, MSI_STANDARD_EC_3G_MASK);
335}
336
199static ssize_t show_lcd_level(struct device *dev, 337static ssize_t show_lcd_level(struct device *dev,
200 struct device_attribute *attr, char *buf) 338 struct device_attribute *attr, char *buf)
201{ 339{
@@ -258,6 +396,7 @@ static DEVICE_ATTR(lcd_level, 0644, show_lcd_level, store_lcd_level);
258static DEVICE_ATTR(auto_brightness, 0644, show_auto_brightness, store_auto_brightness); 396static DEVICE_ATTR(auto_brightness, 0644, show_auto_brightness, store_auto_brightness);
259static DEVICE_ATTR(bluetooth, 0444, show_bluetooth, NULL); 397static DEVICE_ATTR(bluetooth, 0444, show_bluetooth, NULL);
260static DEVICE_ATTR(wlan, 0444, show_wlan, NULL); 398static DEVICE_ATTR(wlan, 0444, show_wlan, NULL);
399static DEVICE_ATTR(threeg, 0444, show_threeg, NULL);
261 400
262static struct attribute *msipf_attributes[] = { 401static struct attribute *msipf_attributes[] = {
263 &dev_attr_lcd_level.attr, 402 &dev_attr_lcd_level.attr,
@@ -275,7 +414,8 @@ static struct platform_driver msipf_driver = {
275 .driver = { 414 .driver = {
276 .name = "msi-laptop-pf", 415 .name = "msi-laptop-pf",
277 .owner = THIS_MODULE, 416 .owner = THIS_MODULE,
278 } 417 },
418 .resume = msi_laptop_resume,
279}; 419};
280 420
281static struct platform_device *msipf_device; 421static struct platform_device *msipf_device;
@@ -332,6 +472,192 @@ static struct dmi_system_id __initdata msi_dmi_table[] = {
332 { } 472 { }
333}; 473};
334 474
475static struct dmi_system_id __initdata msi_load_scm_models_dmi_table[] = {
476 {
477 .ident = "MSI N034",
478 .matches = {
479 DMI_MATCH(DMI_SYS_VENDOR,
480 "MICRO-STAR INTERNATIONAL CO., LTD"),
481 DMI_MATCH(DMI_PRODUCT_NAME, "MS-N034"),
482 DMI_MATCH(DMI_CHASSIS_VENDOR,
483 "MICRO-STAR INTERNATIONAL CO., LTD")
484 },
485 .callback = dmi_check_cb
486 },
487 { }
488};
489
490static int rfkill_bluetooth_set(void *data, bool blocked)
491{
492 /* Do something with blocked...*/
493 /*
494 * blocked == false is on
495 * blocked == true is off
496 */
497 if (blocked)
498 set_device_state("0", 0, MSI_STANDARD_EC_BLUETOOTH_MASK);
499 else
500 set_device_state("1", 0, MSI_STANDARD_EC_BLUETOOTH_MASK);
501
502 return 0;
503}
504
505static int rfkill_wlan_set(void *data, bool blocked)
506{
507 if (blocked)
508 set_device_state("0", 0, MSI_STANDARD_EC_WLAN_MASK);
509 else
510 set_device_state("1", 0, MSI_STANDARD_EC_WLAN_MASK);
511
512 return 0;
513}
514
515static int rfkill_threeg_set(void *data, bool blocked)
516{
517 if (blocked)
518 set_device_state("0", 0, MSI_STANDARD_EC_3G_MASK);
519 else
520 set_device_state("1", 0, MSI_STANDARD_EC_3G_MASK);
521
522 return 0;
523}
524
525static struct rfkill_ops rfkill_bluetooth_ops = {
526 .set_block = rfkill_bluetooth_set
527};
528
529static struct rfkill_ops rfkill_wlan_ops = {
530 .set_block = rfkill_wlan_set
531};
532
533static struct rfkill_ops rfkill_threeg_ops = {
534 .set_block = rfkill_threeg_set
535};
536
537static void rfkill_cleanup(void)
538{
539 if (rfk_bluetooth) {
540 rfkill_unregister(rfk_bluetooth);
541 rfkill_destroy(rfk_bluetooth);
542 }
543
544 if (rfk_threeg) {
545 rfkill_unregister(rfk_threeg);
546 rfkill_destroy(rfk_threeg);
547 }
548
549 if (rfk_wlan) {
550 rfkill_unregister(rfk_wlan);
551 rfkill_destroy(rfk_wlan);
552 }
553}
554
555static int rfkill_init(struct platform_device *sdev)
556{
557 /* add rfkill */
558 int retval;
559
560 rfk_bluetooth = rfkill_alloc("msi-bluetooth", &sdev->dev,
561 RFKILL_TYPE_BLUETOOTH,
562 &rfkill_bluetooth_ops, NULL);
563 if (!rfk_bluetooth) {
564 retval = -ENOMEM;
565 goto err_bluetooth;
566 }
567 retval = rfkill_register(rfk_bluetooth);
568 if (retval)
569 goto err_bluetooth;
570
571 rfk_wlan = rfkill_alloc("msi-wlan", &sdev->dev, RFKILL_TYPE_WLAN,
572 &rfkill_wlan_ops, NULL);
573 if (!rfk_wlan) {
574 retval = -ENOMEM;
575 goto err_wlan;
576 }
577 retval = rfkill_register(rfk_wlan);
578 if (retval)
579 goto err_wlan;
580
581 if (threeg_exists) {
582 rfk_threeg = rfkill_alloc("msi-threeg", &sdev->dev,
583 RFKILL_TYPE_WWAN, &rfkill_threeg_ops, NULL);
584 if (!rfk_threeg) {
585 retval = -ENOMEM;
586 goto err_threeg;
587 }
588 retval = rfkill_register(rfk_threeg);
589 if (retval)
590 goto err_threeg;
591 }
592
593 return 0;
594
595err_threeg:
596 rfkill_destroy(rfk_threeg);
597 if (rfk_wlan)
598 rfkill_unregister(rfk_wlan);
599err_wlan:
600 rfkill_destroy(rfk_wlan);
601 if (rfk_bluetooth)
602 rfkill_unregister(rfk_bluetooth);
603err_bluetooth:
604 rfkill_destroy(rfk_bluetooth);
605
606 return retval;
607}
608
609static int msi_laptop_resume(struct platform_device *device)
610{
611 u8 data;
612 int result;
613
614 if (!load_scm_model)
615 return 0;
616
617 /* set load SCM to disable hardware control by fn key */
618 result = ec_read(MSI_STANDARD_EC_SCM_LOAD_ADDRESS, &data);
619 if (result < 0)
620 return result;
621
622 result = ec_write(MSI_STANDARD_EC_SCM_LOAD_ADDRESS,
623 data | MSI_STANDARD_EC_SCM_LOAD_MASK);
624 if (result < 0)
625 return result;
626
627 return 0;
628}
629
630static int load_scm_model_init(struct platform_device *sdev)
631{
632 u8 data;
633 int result;
634
635 /* allow userland write sysfs file */
636 dev_attr_bluetooth.store = store_bluetooth;
637 dev_attr_wlan.store = store_wlan;
638 dev_attr_threeg.store = store_threeg;
639 dev_attr_bluetooth.attr.mode |= S_IWUSR;
640 dev_attr_wlan.attr.mode |= S_IWUSR;
641 dev_attr_threeg.attr.mode |= S_IWUSR;
642
643 /* disable hardware control by fn key */
644 result = ec_read(MSI_STANDARD_EC_SCM_LOAD_ADDRESS, &data);
645 if (result < 0)
646 return result;
647
648 result = ec_write(MSI_STANDARD_EC_SCM_LOAD_ADDRESS,
649 data | MSI_STANDARD_EC_SCM_LOAD_MASK);
650 if (result < 0)
651 return result;
652
653 /* initial rfkill */
654 result = rfkill_init(sdev);
655 if (result < 0)
656 return result;
657
658 return 0;
659}
660
335static int __init msi_init(void) 661static int __init msi_init(void)
336{ 662{
337 int ret; 663 int ret;
@@ -339,8 +665,14 @@ static int __init msi_init(void)
339 if (acpi_disabled) 665 if (acpi_disabled)
340 return -ENODEV; 666 return -ENODEV;
341 667
342 if (!force && !dmi_check_system(msi_dmi_table)) 668 if (force || dmi_check_system(msi_dmi_table))
343 return -ENODEV; 669 old_ec_model = 1;
670
671 if (!old_ec_model)
672 get_threeg_exists();
673
674 if (!old_ec_model && dmi_check_system(msi_load_scm_models_dmi_table))
675 load_scm_model = 1;
344 676
345 if (auto_brightness < 0 || auto_brightness > 2) 677 if (auto_brightness < 0 || auto_brightness > 2)
346 return -EINVAL; 678 return -EINVAL;
@@ -351,11 +683,14 @@ static int __init msi_init(void)
351 printk(KERN_INFO "MSI: Brightness ignored, must be controlled " 683 printk(KERN_INFO "MSI: Brightness ignored, must be controlled "
352 "by ACPI video driver\n"); 684 "by ACPI video driver\n");
353 } else { 685 } else {
686 struct backlight_properties props;
687 memset(&props, 0, sizeof(struct backlight_properties));
688 props.max_brightness = MSI_LCD_LEVEL_MAX - 1;
354 msibl_device = backlight_device_register("msi-laptop-bl", NULL, 689 msibl_device = backlight_device_register("msi-laptop-bl", NULL,
355 NULL, &msibl_ops); 690 NULL, &msibl_ops,
691 &props);
356 if (IS_ERR(msibl_device)) 692 if (IS_ERR(msibl_device))
357 return PTR_ERR(msibl_device); 693 return PTR_ERR(msibl_device);
358 msibl_device->props.max_brightness = MSI_LCD_LEVEL_MAX-1;
359 } 694 }
360 695
361 ret = platform_driver_register(&msipf_driver); 696 ret = platform_driver_register(&msipf_driver);
@@ -374,10 +709,23 @@ static int __init msi_init(void)
374 if (ret) 709 if (ret)
375 goto fail_platform_device1; 710 goto fail_platform_device1;
376 711
712 if (load_scm_model && (load_scm_model_init(msipf_device) < 0)) {
713 ret = -EINVAL;
714 goto fail_platform_device1;
715 }
716
377 ret = sysfs_create_group(&msipf_device->dev.kobj, &msipf_attribute_group); 717 ret = sysfs_create_group(&msipf_device->dev.kobj, &msipf_attribute_group);
378 if (ret) 718 if (ret)
379 goto fail_platform_device2; 719 goto fail_platform_device2;
380 720
721 if (!old_ec_model) {
722 if (threeg_exists)
723 ret = device_create_file(&msipf_device->dev,
724 &dev_attr_threeg);
725 if (ret)
726 goto fail_platform_device2;
727 }
728
381 /* Disable automatic brightness control by default because 729 /* Disable automatic brightness control by default because
382 * this module was probably loaded to do brightness control in 730 * this module was probably loaded to do brightness control in
383 * software. */ 731 * software. */
@@ -412,10 +760,14 @@ static void __exit msi_cleanup(void)
412{ 760{
413 761
414 sysfs_remove_group(&msipf_device->dev.kobj, &msipf_attribute_group); 762 sysfs_remove_group(&msipf_device->dev.kobj, &msipf_attribute_group);
763 if (!old_ec_model && threeg_exists)
764 device_remove_file(&msipf_device->dev, &dev_attr_threeg);
415 platform_device_unregister(msipf_device); 765 platform_device_unregister(msipf_device);
416 platform_driver_unregister(&msipf_driver); 766 platform_driver_unregister(&msipf_driver);
417 backlight_device_unregister(msibl_device); 767 backlight_device_unregister(msibl_device);
418 768
769 rfkill_cleanup();
770
419 /* Enable automatic brightness control again */ 771 /* Enable automatic brightness control again */
420 if (auto_brightness != 2) 772 if (auto_brightness != 2)
421 set_auto_brightness(1); 773 set_auto_brightness(1);
@@ -435,3 +787,4 @@ MODULE_ALIAS("dmi:*:svnMICRO-STARINT'LCO.,LTD:pnMS-1013:pvr0131*:cvnMICRO-STARIN
435MODULE_ALIAS("dmi:*:svnMicro-StarInternational:pnMS-1058:pvr0581:rvnMSI:rnMS-1058:*:ct10:*"); 787MODULE_ALIAS("dmi:*:svnMicro-StarInternational:pnMS-1058:pvr0581:rvnMSI:rnMS-1058:*:ct10:*");
436MODULE_ALIAS("dmi:*:svnMicro-StarInternational:pnMS-1412:*:rvnMSI:rnMS-1412:*:cvnMICRO-STARINT'LCO.,LTD:ct10:*"); 788MODULE_ALIAS("dmi:*:svnMicro-StarInternational:pnMS-1412:*:rvnMSI:rnMS-1412:*:cvnMICRO-STARINT'LCO.,LTD:ct10:*");
437MODULE_ALIAS("dmi:*:svnNOTEBOOK:pnSAM2000:pvr0131*:cvnMICRO-STARINT'LCO.,LTD:ct10:*"); 789MODULE_ALIAS("dmi:*:svnNOTEBOOK:pnSAM2000:pvr0131*:cvnMICRO-STARINT'LCO.,LTD:ct10:*");
790MODULE_ALIAS("dmi:*:svnMICRO-STARINTERNATIONAL*:pnMS-N034:*");
diff --git a/drivers/platform/x86/msi-wmi.c b/drivers/platform/x86/msi-wmi.c
new file mode 100644
index 000000000000..d1736009636f
--- /dev/null
+++ b/drivers/platform/x86/msi-wmi.c
@@ -0,0 +1,294 @@
1/*
2 * MSI WMI hotkeys
3 *
4 * Copyright (C) 2009 Novell <trenn@suse.de>
5 *
6 * Most stuff taken over from hp-wmi
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 */
22
23
24#include <linux/kernel.h>
25#include <linux/input.h>
26#include <linux/input/sparse-keymap.h>
27#include <linux/acpi.h>
28#include <linux/backlight.h>
29#include <linux/slab.h>
30
31MODULE_AUTHOR("Thomas Renninger <trenn@suse.de>");
32MODULE_DESCRIPTION("MSI laptop WMI hotkeys driver");
33MODULE_LICENSE("GPL");
34
35MODULE_ALIAS("wmi:551A1F84-FBDD-4125-91DB-3EA8F44F1D45");
36MODULE_ALIAS("wmi:B6F3EEF2-3D2F-49DC-9DE3-85BCE18C62F2");
37
38#define DRV_NAME "msi-wmi"
39#define DRV_PFX DRV_NAME ": "
40
41#define MSIWMI_BIOS_GUID "551A1F84-FBDD-4125-91DB-3EA8F44F1D45"
42#define MSIWMI_EVENT_GUID "B6F3EEF2-3D2F-49DC-9DE3-85BCE18C62F2"
43
44#define dprintk(msg...) pr_debug(DRV_PFX msg)
45
46#define KEYCODE_BASE 0xD0
47#define MSI_WMI_BRIGHTNESSUP KEYCODE_BASE
48#define MSI_WMI_BRIGHTNESSDOWN (KEYCODE_BASE + 1)
49#define MSI_WMI_VOLUMEUP (KEYCODE_BASE + 2)
50#define MSI_WMI_VOLUMEDOWN (KEYCODE_BASE + 3)
51static struct key_entry msi_wmi_keymap[] = {
52 { KE_KEY, MSI_WMI_BRIGHTNESSUP, {KEY_BRIGHTNESSUP} },
53 { KE_KEY, MSI_WMI_BRIGHTNESSDOWN, {KEY_BRIGHTNESSDOWN} },
54 { KE_KEY, MSI_WMI_VOLUMEUP, {KEY_VOLUMEUP} },
55 { KE_KEY, MSI_WMI_VOLUMEDOWN, {KEY_VOLUMEDOWN} },
56 { KE_END, 0}
57};
58static ktime_t last_pressed[ARRAY_SIZE(msi_wmi_keymap) - 1];
59
60struct backlight_device *backlight;
61
62static int backlight_map[] = { 0x00, 0x33, 0x66, 0x99, 0xCC, 0xFF };
63
64static struct input_dev *msi_wmi_input_dev;
65
66static int msi_wmi_query_block(int instance, int *ret)
67{
68 acpi_status status;
69 union acpi_object *obj;
70
71 struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
72
73 status = wmi_query_block(MSIWMI_BIOS_GUID, instance, &output);
74
75 obj = output.pointer;
76
77 if (!obj || obj->type != ACPI_TYPE_INTEGER) {
78 if (obj) {
79 printk(KERN_ERR DRV_PFX "query block returned object "
80 "type: %d - buffer length:%d\n", obj->type,
81 obj->type == ACPI_TYPE_BUFFER ?
82 obj->buffer.length : 0);
83 }
84 kfree(obj);
85 return -EINVAL;
86 }
87 *ret = obj->integer.value;
88 kfree(obj);
89 return 0;
90}
91
92static int msi_wmi_set_block(int instance, int value)
93{
94 acpi_status status;
95
96 struct acpi_buffer input = { sizeof(int), &value };
97
98 dprintk("Going to set block of instance: %d - value: %d\n",
99 instance, value);
100
101 status = wmi_set_block(MSIWMI_BIOS_GUID, instance, &input);
102
103 return ACPI_SUCCESS(status) ? 0 : 1;
104}
105
106static int bl_get(struct backlight_device *bd)
107{
108 int level, err, ret;
109
110 /* Instance 1 is "get backlight", cmp with DSDT */
111 err = msi_wmi_query_block(1, &ret);
112 if (err) {
113 printk(KERN_ERR DRV_PFX "Could not query backlight: %d\n", err);
114 return -EINVAL;
115 }
116 dprintk("Get: Query block returned: %d\n", ret);
117 for (level = 0; level < ARRAY_SIZE(backlight_map); level++) {
118 if (backlight_map[level] == ret) {
119 dprintk("Current backlight level: 0x%X - index: %d\n",
120 backlight_map[level], level);
121 break;
122 }
123 }
124 if (level == ARRAY_SIZE(backlight_map)) {
125 printk(KERN_ERR DRV_PFX "get: Invalid brightness value: 0x%X\n",
126 ret);
127 return -EINVAL;
128 }
129 return level;
130}
131
132static int bl_set_status(struct backlight_device *bd)
133{
134 int bright = bd->props.brightness;
135 if (bright >= ARRAY_SIZE(backlight_map) || bright < 0)
136 return -EINVAL;
137
138 /* Instance 0 is "set backlight" */
139 return msi_wmi_set_block(0, backlight_map[bright]);
140}
141
142static const struct backlight_ops msi_backlight_ops = {
143 .get_brightness = bl_get,
144 .update_status = bl_set_status,
145};
146
147static void msi_wmi_notify(u32 value, void *context)
148{
149 struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL };
150 static struct key_entry *key;
151 union acpi_object *obj;
152 ktime_t cur;
153 acpi_status status;
154
155 status = wmi_get_event_data(value, &response);
156 if (status != AE_OK) {
157 printk(KERN_INFO DRV_PFX "bad event status 0x%x\n", status);
158 return;
159 }
160
161 obj = (union acpi_object *)response.pointer;
162
163 if (obj && obj->type == ACPI_TYPE_INTEGER) {
164 int eventcode = obj->integer.value;
165 dprintk("Eventcode: 0x%x\n", eventcode);
166 key = sparse_keymap_entry_from_scancode(msi_wmi_input_dev,
167 eventcode);
168 if (key) {
169 ktime_t diff;
170 cur = ktime_get_real();
171 diff = ktime_sub(cur, last_pressed[key->code -
172 KEYCODE_BASE]);
173 /* Ignore event if the same event happened in a 50 ms
174 timeframe -> Key press may result in 10-20 GPEs */
175 if (ktime_to_us(diff) < 1000 * 50) {
176 dprintk("Suppressed key event 0x%X - "
177 "Last press was %lld us ago\n",
178 key->code, ktime_to_us(diff));
179 return;
180 }
181 last_pressed[key->code - KEYCODE_BASE] = cur;
182
183 if (key->type == KE_KEY &&
184 /* Brightness is served via acpi video driver */
185 (!acpi_video_backlight_support() ||
186 (key->code != MSI_WMI_BRIGHTNESSUP &&
187 key->code != MSI_WMI_BRIGHTNESSDOWN))) {
188 dprintk("Send key: 0x%X - "
189 "Input layer keycode: %d\n", key->code,
190 key->keycode);
191 sparse_keymap_report_entry(msi_wmi_input_dev,
192 key, 1, true);
193 }
194 } else
195 printk(KERN_INFO "Unknown key pressed - %x\n",
196 eventcode);
197 } else
198 printk(KERN_INFO DRV_PFX "Unknown event received\n");
199 kfree(response.pointer);
200}
201
202static int __init msi_wmi_input_setup(void)
203{
204 int err;
205
206 msi_wmi_input_dev = input_allocate_device();
207 if (!msi_wmi_input_dev)
208 return -ENOMEM;
209
210 msi_wmi_input_dev->name = "MSI WMI hotkeys";
211 msi_wmi_input_dev->phys = "wmi/input0";
212 msi_wmi_input_dev->id.bustype = BUS_HOST;
213
214 err = sparse_keymap_setup(msi_wmi_input_dev, msi_wmi_keymap, NULL);
215 if (err)
216 goto err_free_dev;
217
218 err = input_register_device(msi_wmi_input_dev);
219
220 if (err)
221 goto err_free_keymap;
222
223 memset(last_pressed, 0, sizeof(last_pressed));
224
225 return 0;
226
227err_free_keymap:
228 sparse_keymap_free(msi_wmi_input_dev);
229err_free_dev:
230 input_free_device(msi_wmi_input_dev);
231 return err;
232}
233
234static int __init msi_wmi_init(void)
235{
236 int err;
237
238 if (!wmi_has_guid(MSIWMI_EVENT_GUID)) {
239 printk(KERN_ERR
240 "This machine doesn't have MSI-hotkeys through WMI\n");
241 return -ENODEV;
242 }
243 err = wmi_install_notify_handler(MSIWMI_EVENT_GUID,
244 msi_wmi_notify, NULL);
245 if (ACPI_FAILURE(err))
246 return -EINVAL;
247
248 err = msi_wmi_input_setup();
249 if (err)
250 goto err_uninstall_notifier;
251
252 if (!acpi_video_backlight_support()) {
253 struct backlight_properties props;
254 memset(&props, 0, sizeof(struct backlight_properties));
255 props.max_brightness = ARRAY_SIZE(backlight_map) - 1;
256 backlight = backlight_device_register(DRV_NAME, NULL, NULL,
257 &msi_backlight_ops,
258 &props);
259 if (IS_ERR(backlight)) {
260 err = PTR_ERR(backlight);
261 goto err_free_input;
262 }
263
264 err = bl_get(NULL);
265 if (err < 0)
266 goto err_free_backlight;
267
268 backlight->props.brightness = err;
269 }
270 dprintk("Event handler installed\n");
271
272 return 0;
273
274err_free_backlight:
275 backlight_device_unregister(backlight);
276err_free_input:
277 input_unregister_device(msi_wmi_input_dev);
278err_uninstall_notifier:
279 wmi_remove_notify_handler(MSIWMI_EVENT_GUID);
280 return err;
281}
282
283static void __exit msi_wmi_exit(void)
284{
285 if (wmi_has_guid(MSIWMI_EVENT_GUID)) {
286 wmi_remove_notify_handler(MSIWMI_EVENT_GUID);
287 sparse_keymap_free(msi_wmi_input_dev);
288 input_unregister_device(msi_wmi_input_dev);
289 backlight_device_unregister(backlight);
290 }
291}
292
293module_init(msi_wmi_init);
294module_exit(msi_wmi_exit);
diff --git a/drivers/platform/x86/panasonic-laptop.c b/drivers/platform/x86/panasonic-laptop.c
index fe7cf0188acc..2fb9a32926f8 100644
--- a/drivers/platform/x86/panasonic-laptop.c
+++ b/drivers/platform/x86/panasonic-laptop.c
@@ -124,6 +124,7 @@
124#include <linux/ctype.h> 124#include <linux/ctype.h>
125#include <linux/seq_file.h> 125#include <linux/seq_file.h>
126#include <linux/uaccess.h> 126#include <linux/uaccess.h>
127#include <linux/slab.h>
127#include <acpi/acpi_bus.h> 128#include <acpi/acpi_bus.h>
128#include <acpi/acpi_drivers.h> 129#include <acpi/acpi_drivers.h>
129#include <linux/input.h> 130#include <linux/input.h>
@@ -200,7 +201,7 @@ static struct acpi_driver acpi_pcc_driver = {
200}; 201};
201 202
202#define KEYMAP_SIZE 11 203#define KEYMAP_SIZE 11
203static const int initial_keymap[KEYMAP_SIZE] = { 204static const unsigned int initial_keymap[KEYMAP_SIZE] = {
204 /* 0 */ KEY_RESERVED, 205 /* 0 */ KEY_RESERVED,
205 /* 1 */ KEY_BRIGHTNESSDOWN, 206 /* 1 */ KEY_BRIGHTNESSDOWN,
206 /* 2 */ KEY_BRIGHTNESSUP, 207 /* 2 */ KEY_BRIGHTNESSUP,
@@ -222,7 +223,7 @@ struct pcc_acpi {
222 struct acpi_device *device; 223 struct acpi_device *device;
223 struct input_dev *input_dev; 224 struct input_dev *input_dev;
224 struct backlight_device *backlight; 225 struct backlight_device *backlight;
225 int keymap[KEYMAP_SIZE]; 226 unsigned int keymap[KEYMAP_SIZE];
226}; 227};
227 228
228struct pcc_keyinput { 229struct pcc_keyinput {
@@ -352,7 +353,7 @@ static int bl_set_status(struct backlight_device *bd)
352 return acpi_pcc_write_sset(pcc, SINF_DC_CUR_BRIGHT, bright); 353 return acpi_pcc_write_sset(pcc, SINF_DC_CUR_BRIGHT, bright);
353} 354}
354 355
355static struct backlight_ops pcc_backlight_ops = { 356static const struct backlight_ops pcc_backlight_ops = {
356 .get_brightness = bl_get, 357 .get_brightness = bl_get,
357 .update_status = bl_set_status, 358 .update_status = bl_set_status,
358}; 359};
@@ -445,7 +446,8 @@ static struct attribute_group pcc_attr_group = {
445 446
446/* hotkey input device driver */ 447/* hotkey input device driver */
447 448
448static int pcc_getkeycode(struct input_dev *dev, int scancode, int *keycode) 449static int pcc_getkeycode(struct input_dev *dev,
450 unsigned int scancode, unsigned int *keycode)
449{ 451{
450 struct pcc_acpi *pcc = input_get_drvdata(dev); 452 struct pcc_acpi *pcc = input_get_drvdata(dev);
451 453
@@ -457,7 +459,7 @@ static int pcc_getkeycode(struct input_dev *dev, int scancode, int *keycode)
457 return 0; 459 return 0;
458} 460}
459 461
460static int keymap_get_by_keycode(struct pcc_acpi *pcc, int keycode) 462static int keymap_get_by_keycode(struct pcc_acpi *pcc, unsigned int keycode)
461{ 463{
462 int i; 464 int i;
463 465
@@ -469,7 +471,8 @@ static int keymap_get_by_keycode(struct pcc_acpi *pcc, int keycode)
469 return 0; 471 return 0;
470} 472}
471 473
472static int pcc_setkeycode(struct input_dev *dev, int scancode, int keycode) 474static int pcc_setkeycode(struct input_dev *dev,
475 unsigned int scancode, unsigned int keycode)
473{ 476{
474 struct pcc_acpi *pcc = input_get_drvdata(dev); 477 struct pcc_acpi *pcc = input_get_drvdata(dev);
475 int oldkeycode; 478 int oldkeycode;
@@ -477,9 +480,6 @@ static int pcc_setkeycode(struct input_dev *dev, int scancode, int keycode)
477 if (scancode >= ARRAY_SIZE(pcc->keymap)) 480 if (scancode >= ARRAY_SIZE(pcc->keymap))
478 return -EINVAL; 481 return -EINVAL;
479 482
480 if (keycode < 0 || keycode > KEY_MAX)
481 return -EINVAL;
482
483 oldkeycode = pcc->keymap[scancode]; 483 oldkeycode = pcc->keymap[scancode];
484 pcc->keymap[scancode] = keycode; 484 pcc->keymap[scancode] = keycode;
485 485
@@ -601,6 +601,7 @@ static int acpi_pcc_hotkey_resume(struct acpi_device *device)
601 601
602static int acpi_pcc_hotkey_add(struct acpi_device *device) 602static int acpi_pcc_hotkey_add(struct acpi_device *device)
603{ 603{
604 struct backlight_properties props;
604 struct pcc_acpi *pcc; 605 struct pcc_acpi *pcc;
605 int num_sifr, result; 606 int num_sifr, result;
606 607
@@ -638,24 +639,25 @@ static int acpi_pcc_hotkey_add(struct acpi_device *device)
638 if (result) { 639 if (result) {
639 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, 640 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
640 "Error installing keyinput handler\n")); 641 "Error installing keyinput handler\n"));
641 goto out_sinf; 642 goto out_hotkey;
642 } 643 }
643 644
644 /* initialize backlight */
645 pcc->backlight = backlight_device_register("panasonic", NULL, pcc,
646 &pcc_backlight_ops);
647 if (IS_ERR(pcc->backlight))
648 goto out_input;
649
650 if (!acpi_pcc_retrieve_biosdata(pcc, pcc->sinf)) { 645 if (!acpi_pcc_retrieve_biosdata(pcc, pcc->sinf)) {
651 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, 646 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
652 "Couldn't retrieve BIOS data\n")); 647 "Couldn't retrieve BIOS data\n"));
653 goto out_backlight; 648 goto out_input;
649 }
650 /* initialize backlight */
651 memset(&props, 0, sizeof(struct backlight_properties));
652 props.max_brightness = pcc->sinf[SINF_AC_MAX_BRIGHT];
653 pcc->backlight = backlight_device_register("panasonic", NULL, pcc,
654 &pcc_backlight_ops, &props);
655 if (IS_ERR(pcc->backlight)) {
656 result = PTR_ERR(pcc->backlight);
657 goto out_sinf;
654 } 658 }
655 659
656 /* read the initial brightness setting from the hardware */ 660 /* read the initial brightness setting from the hardware */
657 pcc->backlight->props.max_brightness =
658 pcc->sinf[SINF_AC_MAX_BRIGHT];
659 pcc->backlight->props.brightness = pcc->sinf[SINF_AC_CUR_BRIGHT]; 661 pcc->backlight->props.brightness = pcc->sinf[SINF_AC_CUR_BRIGHT];
660 662
661 /* read the initial sticky key mode from the hardware */ 663 /* read the initial sticky key mode from the hardware */
@@ -670,12 +672,12 @@ static int acpi_pcc_hotkey_add(struct acpi_device *device)
670 672
671out_backlight: 673out_backlight:
672 backlight_device_unregister(pcc->backlight); 674 backlight_device_unregister(pcc->backlight);
675out_sinf:
676 kfree(pcc->sinf);
673out_input: 677out_input:
674 input_unregister_device(pcc->input_dev); 678 input_unregister_device(pcc->input_dev);
675 /* no need to input_free_device() since core input API refcount and 679 /* no need to input_free_device() since core input API refcount and
676 * free()s the device */ 680 * free()s the device */
677out_sinf:
678 kfree(pcc->sinf);
679out_hotkey: 681out_hotkey:
680 kfree(pcc); 682 kfree(pcc);
681 683
diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c
index a2a742c8ff7e..1387c5f9c24d 100644
--- a/drivers/platform/x86/sony-laptop.c
+++ b/drivers/platform/x86/sony-laptop.c
@@ -58,6 +58,7 @@
58#include <linux/kfifo.h> 58#include <linux/kfifo.h>
59#include <linux/workqueue.h> 59#include <linux/workqueue.h>
60#include <linux/acpi.h> 60#include <linux/acpi.h>
61#include <linux/slab.h>
61#include <acpi/acpi_drivers.h> 62#include <acpi/acpi_drivers.h>
62#include <acpi/acpi_bus.h> 63#include <acpi/acpi_bus.h>
63#include <asm/uaccess.h> 64#include <asm/uaccess.h>
@@ -131,6 +132,7 @@ enum sony_nc_rfkill {
131 N_SONY_RFKILL, 132 N_SONY_RFKILL,
132}; 133};
133 134
135static int sony_rfkill_handle;
134static struct rfkill *sony_rfkill_devices[N_SONY_RFKILL]; 136static struct rfkill *sony_rfkill_devices[N_SONY_RFKILL];
135static int sony_rfkill_address[N_SONY_RFKILL] = {0x300, 0x500, 0x700, 0x900}; 137static int sony_rfkill_address[N_SONY_RFKILL] = {0x300, 0x500, 0x700, 0x900};
136static void sony_nc_rfkill_update(void); 138static void sony_nc_rfkill_update(void);
@@ -142,9 +144,9 @@ struct sony_laptop_input_s {
142 atomic_t users; 144 atomic_t users;
143 struct input_dev *jog_dev; 145 struct input_dev *jog_dev;
144 struct input_dev *key_dev; 146 struct input_dev *key_dev;
145 struct kfifo *fifo; 147 struct kfifo fifo;
146 spinlock_t fifo_lock; 148 spinlock_t fifo_lock;
147 struct workqueue_struct *wq; 149 struct timer_list release_key_timer;
148}; 150};
149 151
150static struct sony_laptop_input_s sony_laptop_input = { 152static struct sony_laptop_input_s sony_laptop_input = {
@@ -232,6 +234,7 @@ static int sony_laptop_input_index[] = {
232 56, /* 69 SONYPI_EVENT_VOLUME_INC_PRESSED */ 234 56, /* 69 SONYPI_EVENT_VOLUME_INC_PRESSED */
233 57, /* 70 SONYPI_EVENT_VOLUME_DEC_PRESSED */ 235 57, /* 70 SONYPI_EVENT_VOLUME_DEC_PRESSED */
234 -1, /* 71 SONYPI_EVENT_BRIGHTNESS_PRESSED */ 236 -1, /* 71 SONYPI_EVENT_BRIGHTNESS_PRESSED */
237 58, /* 72 SONYPI_EVENT_MEDIA_PRESSED */
235}; 238};
236 239
237static int sony_laptop_input_keycode_map[] = { 240static int sony_laptop_input_keycode_map[] = {
@@ -293,22 +296,30 @@ static int sony_laptop_input_keycode_map[] = {
293 KEY_F15, /* 55 SONYPI_EVENT_SETTINGKEY_PRESSED */ 296 KEY_F15, /* 55 SONYPI_EVENT_SETTINGKEY_PRESSED */
294 KEY_VOLUMEUP, /* 56 SONYPI_EVENT_VOLUME_INC_PRESSED */ 297 KEY_VOLUMEUP, /* 56 SONYPI_EVENT_VOLUME_INC_PRESSED */
295 KEY_VOLUMEDOWN, /* 57 SONYPI_EVENT_VOLUME_DEC_PRESSED */ 298 KEY_VOLUMEDOWN, /* 57 SONYPI_EVENT_VOLUME_DEC_PRESSED */
299 KEY_MEDIA, /* 58 SONYPI_EVENT_MEDIA_PRESSED */
296}; 300};
297 301
298/* release buttons after a short delay if pressed */ 302/* release buttons after a short delay if pressed */
299static void do_sony_laptop_release_key(struct work_struct *work) 303static void do_sony_laptop_release_key(unsigned long unused)
300{ 304{
301 struct sony_laptop_keypress kp; 305 struct sony_laptop_keypress kp;
306 unsigned long flags;
307
308 spin_lock_irqsave(&sony_laptop_input.fifo_lock, flags);
302 309
303 while (kfifo_get(sony_laptop_input.fifo, (unsigned char *)&kp, 310 if (kfifo_out(&sony_laptop_input.fifo,
304 sizeof(kp)) == sizeof(kp)) { 311 (unsigned char *)&kp, sizeof(kp)) == sizeof(kp)) {
305 msleep(10);
306 input_report_key(kp.dev, kp.key, 0); 312 input_report_key(kp.dev, kp.key, 0);
307 input_sync(kp.dev); 313 input_sync(kp.dev);
308 } 314 }
315
316 /* If there is something in the fifo schedule next release. */
317 if (kfifo_len(&sony_laptop_input.fifo) != 0)
318 mod_timer(&sony_laptop_input.release_key_timer,
319 jiffies + msecs_to_jiffies(10));
320
321 spin_unlock_irqrestore(&sony_laptop_input.fifo_lock, flags);
309} 322}
310static DECLARE_WORK(sony_laptop_release_key_work,
311 do_sony_laptop_release_key);
312 323
313/* forward event to the input subsystem */ 324/* forward event to the input subsystem */
314static void sony_laptop_report_input_event(u8 event) 325static void sony_laptop_report_input_event(u8 event)
@@ -362,12 +373,13 @@ static void sony_laptop_report_input_event(u8 event)
362 /* we emit the scancode so we can always remap the key */ 373 /* we emit the scancode so we can always remap the key */
363 input_event(kp.dev, EV_MSC, MSC_SCAN, event); 374 input_event(kp.dev, EV_MSC, MSC_SCAN, event);
364 input_sync(kp.dev); 375 input_sync(kp.dev);
365 kfifo_put(sony_laptop_input.fifo,
366 (unsigned char *)&kp, sizeof(kp));
367 376
368 if (!work_pending(&sony_laptop_release_key_work)) 377 /* schedule key release */
369 queue_work(sony_laptop_input.wq, 378 kfifo_in_locked(&sony_laptop_input.fifo,
370 &sony_laptop_release_key_work); 379 (unsigned char *)&kp, sizeof(kp),
380 &sony_laptop_input.fifo_lock);
381 mod_timer(&sony_laptop_input.release_key_timer,
382 jiffies + msecs_to_jiffies(10));
371 } else 383 } else
372 dprintk("unknown input event %.2x\n", event); 384 dprintk("unknown input event %.2x\n", event);
373} 385}
@@ -385,29 +397,21 @@ static int sony_laptop_setup_input(struct acpi_device *acpi_device)
385 397
386 /* kfifo */ 398 /* kfifo */
387 spin_lock_init(&sony_laptop_input.fifo_lock); 399 spin_lock_init(&sony_laptop_input.fifo_lock);
388 sony_laptop_input.fifo = 400 error = kfifo_alloc(&sony_laptop_input.fifo,
389 kfifo_alloc(SONY_LAPTOP_BUF_SIZE, GFP_KERNEL, 401 SONY_LAPTOP_BUF_SIZE, GFP_KERNEL);
390 &sony_laptop_input.fifo_lock); 402 if (error) {
391 if (IS_ERR(sony_laptop_input.fifo)) {
392 printk(KERN_ERR DRV_PFX "kfifo_alloc failed\n"); 403 printk(KERN_ERR DRV_PFX "kfifo_alloc failed\n");
393 error = PTR_ERR(sony_laptop_input.fifo);
394 goto err_dec_users; 404 goto err_dec_users;
395 } 405 }
396 406
397 /* init workqueue */ 407 setup_timer(&sony_laptop_input.release_key_timer,
398 sony_laptop_input.wq = create_singlethread_workqueue("sony-laptop"); 408 do_sony_laptop_release_key, 0);
399 if (!sony_laptop_input.wq) {
400 printk(KERN_ERR DRV_PFX
401 "Unable to create workqueue.\n");
402 error = -ENXIO;
403 goto err_free_kfifo;
404 }
405 409
406 /* input keys */ 410 /* input keys */
407 key_dev = input_allocate_device(); 411 key_dev = input_allocate_device();
408 if (!key_dev) { 412 if (!key_dev) {
409 error = -ENOMEM; 413 error = -ENOMEM;
410 goto err_destroy_wq; 414 goto err_free_kfifo;
411 } 415 }
412 416
413 key_dev->name = "Sony Vaio Keys"; 417 key_dev->name = "Sony Vaio Keys";
@@ -416,18 +420,15 @@ static int sony_laptop_setup_input(struct acpi_device *acpi_device)
416 key_dev->dev.parent = &acpi_device->dev; 420 key_dev->dev.parent = &acpi_device->dev;
417 421
418 /* Initialize the Input Drivers: special keys */ 422 /* Initialize the Input Drivers: special keys */
419 set_bit(EV_KEY, key_dev->evbit); 423 input_set_capability(key_dev, EV_MSC, MSC_SCAN);
420 set_bit(EV_MSC, key_dev->evbit); 424
421 set_bit(MSC_SCAN, key_dev->mscbit); 425 __set_bit(EV_KEY, key_dev->evbit);
422 key_dev->keycodesize = sizeof(sony_laptop_input_keycode_map[0]); 426 key_dev->keycodesize = sizeof(sony_laptop_input_keycode_map[0]);
423 key_dev->keycodemax = ARRAY_SIZE(sony_laptop_input_keycode_map); 427 key_dev->keycodemax = ARRAY_SIZE(sony_laptop_input_keycode_map);
424 key_dev->keycode = &sony_laptop_input_keycode_map; 428 key_dev->keycode = &sony_laptop_input_keycode_map;
425 for (i = 0; i < ARRAY_SIZE(sony_laptop_input_keycode_map); i++) { 429 for (i = 0; i < ARRAY_SIZE(sony_laptop_input_keycode_map); i++)
426 if (sony_laptop_input_keycode_map[i] != KEY_RESERVED) { 430 __set_bit(sony_laptop_input_keycode_map[i], key_dev->keybit);
427 set_bit(sony_laptop_input_keycode_map[i], 431 __clear_bit(KEY_RESERVED, key_dev->keybit);
428 key_dev->keybit);
429 }
430 }
431 432
432 error = input_register_device(key_dev); 433 error = input_register_device(key_dev);
433 if (error) 434 if (error)
@@ -447,9 +448,8 @@ static int sony_laptop_setup_input(struct acpi_device *acpi_device)
447 jog_dev->id.vendor = PCI_VENDOR_ID_SONY; 448 jog_dev->id.vendor = PCI_VENDOR_ID_SONY;
448 key_dev->dev.parent = &acpi_device->dev; 449 key_dev->dev.parent = &acpi_device->dev;
449 450
450 jog_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL); 451 input_set_capability(jog_dev, EV_KEY, BTN_MIDDLE);
451 jog_dev->keybit[BIT_WORD(BTN_MOUSE)] = BIT_MASK(BTN_MIDDLE); 452 input_set_capability(jog_dev, EV_REL, REL_WHEEL);
452 jog_dev->relbit[0] = BIT_MASK(REL_WHEEL);
453 453
454 error = input_register_device(jog_dev); 454 error = input_register_device(jog_dev);
455 if (error) 455 if (error)
@@ -470,11 +470,8 @@ err_unregister_keydev:
470err_free_keydev: 470err_free_keydev:
471 input_free_device(key_dev); 471 input_free_device(key_dev);
472 472
473err_destroy_wq:
474 destroy_workqueue(sony_laptop_input.wq);
475
476err_free_kfifo: 473err_free_kfifo:
477 kfifo_free(sony_laptop_input.fifo); 474 kfifo_free(&sony_laptop_input.fifo);
478 475
479err_dec_users: 476err_dec_users:
480 atomic_dec(&sony_laptop_input.users); 477 atomic_dec(&sony_laptop_input.users);
@@ -483,12 +480,23 @@ err_dec_users:
483 480
484static void sony_laptop_remove_input(void) 481static void sony_laptop_remove_input(void)
485{ 482{
486 /* cleanup only after the last user has gone */ 483 struct sony_laptop_keypress kp = { NULL };
484
485 /* Cleanup only after the last user has gone */
487 if (!atomic_dec_and_test(&sony_laptop_input.users)) 486 if (!atomic_dec_and_test(&sony_laptop_input.users))
488 return; 487 return;
489 488
490 /* flush workqueue first */ 489 del_timer_sync(&sony_laptop_input.release_key_timer);
491 flush_workqueue(sony_laptop_input.wq); 490
491 /*
492 * Generate key-up events for remaining keys. Note that we don't
493 * need locking since nobody is adding new events to the kfifo.
494 */
495 while (kfifo_out(&sony_laptop_input.fifo,
496 (unsigned char *)&kp, sizeof(kp)) == sizeof(kp)) {
497 input_report_key(kp.dev, kp.key, 0);
498 input_sync(kp.dev);
499 }
492 500
493 /* destroy input devs */ 501 /* destroy input devs */
494 input_unregister_device(sony_laptop_input.key_dev); 502 input_unregister_device(sony_laptop_input.key_dev);
@@ -499,8 +507,7 @@ static void sony_laptop_remove_input(void)
499 sony_laptop_input.jog_dev = NULL; 507 sony_laptop_input.jog_dev = NULL;
500 } 508 }
501 509
502 destroy_workqueue(sony_laptop_input.wq); 510 kfifo_free(&sony_laptop_input.fifo);
503 kfifo_free(sony_laptop_input.fifo);
504} 511}
505 512
506/*********** Platform Device ***********/ 513/*********** Platform Device ***********/
@@ -890,6 +897,8 @@ static struct sony_nc_event sony_100_events[] = {
890 { 0x0C, SONYPI_EVENT_FNKEY_RELEASED }, 897 { 0x0C, SONYPI_EVENT_FNKEY_RELEASED },
891 { 0x9f, SONYPI_EVENT_CD_EJECT_PRESSED }, 898 { 0x9f, SONYPI_EVENT_CD_EJECT_PRESSED },
892 { 0x1f, SONYPI_EVENT_ANYBUTTON_RELEASED }, 899 { 0x1f, SONYPI_EVENT_ANYBUTTON_RELEASED },
900 { 0xa1, SONYPI_EVENT_MEDIA_PRESSED },
901 { 0x21, SONYPI_EVENT_ANYBUTTON_RELEASED },
893 { 0, 0 }, 902 { 0, 0 },
894}; 903};
895 904
@@ -961,7 +970,7 @@ static void sony_nc_notify(struct acpi_device *device, u32 event)
961 else 970 else
962 sony_laptop_report_input_event(ev); 971 sony_laptop_report_input_event(ev);
963 } 972 }
964 } else if (sony_find_snc_handle(0x124) == ev) { 973 } else if (sony_find_snc_handle(sony_rfkill_handle) == ev) {
965 sony_nc_rfkill_update(); 974 sony_nc_rfkill_update();
966 return; 975 return;
967 } 976 }
@@ -1067,7 +1076,7 @@ static int sony_nc_rfkill_set(void *data, bool blocked)
1067 if (!blocked) 1076 if (!blocked)
1068 argument |= 0xff0000; 1077 argument |= 0xff0000;
1069 1078
1070 return sony_call_snc_handle(0x124, argument, &result); 1079 return sony_call_snc_handle(sony_rfkill_handle, argument, &result);
1071} 1080}
1072 1081
1073static const struct rfkill_ops sony_rfkill_ops = { 1082static const struct rfkill_ops sony_rfkill_ops = {
@@ -1110,7 +1119,7 @@ static int sony_nc_setup_rfkill(struct acpi_device *device,
1110 if (!rfk) 1119 if (!rfk)
1111 return -ENOMEM; 1120 return -ENOMEM;
1112 1121
1113 sony_call_snc_handle(0x124, 0x200, &result); 1122 sony_call_snc_handle(sony_rfkill_handle, 0x200, &result);
1114 hwblock = !(result & 0x1); 1123 hwblock = !(result & 0x1);
1115 rfkill_set_hw_state(rfk, hwblock); 1124 rfkill_set_hw_state(rfk, hwblock);
1116 1125
@@ -1129,7 +1138,7 @@ static void sony_nc_rfkill_update()
1129 int result; 1138 int result;
1130 bool hwblock; 1139 bool hwblock;
1131 1140
1132 sony_call_snc_handle(0x124, 0x200, &result); 1141 sony_call_snc_handle(sony_rfkill_handle, 0x200, &result);
1133 hwblock = !(result & 0x1); 1142 hwblock = !(result & 0x1);
1134 1143
1135 for (i = 0; i < N_SONY_RFKILL; i++) { 1144 for (i = 0; i < N_SONY_RFKILL; i++) {
@@ -1145,36 +1154,82 @@ static void sony_nc_rfkill_update()
1145 continue; 1154 continue;
1146 } 1155 }
1147 1156
1148 sony_call_snc_handle(0x124, argument, &result); 1157 sony_call_snc_handle(sony_rfkill_handle, argument, &result);
1149 rfkill_set_states(sony_rfkill_devices[i], 1158 rfkill_set_states(sony_rfkill_devices[i],
1150 !(result & 0xf), false); 1159 !(result & 0xf), false);
1151 } 1160 }
1152} 1161}
1153 1162
1154static int sony_nc_rfkill_setup(struct acpi_device *device) 1163static void sony_nc_rfkill_setup(struct acpi_device *device)
1155{ 1164{
1156 int result, ret; 1165 int offset;
1166 u8 dev_code, i;
1167 acpi_status status;
1168 struct acpi_object_list params;
1169 union acpi_object in_obj;
1170 union acpi_object *device_enum;
1171 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
1157 1172
1158 if (sony_find_snc_handle(0x124) == -1) 1173 offset = sony_find_snc_handle(0x124);
1159 return -1; 1174 if (offset == -1) {
1175 offset = sony_find_snc_handle(0x135);
1176 if (offset == -1)
1177 return;
1178 else
1179 sony_rfkill_handle = 0x135;
1180 } else
1181 sony_rfkill_handle = 0x124;
1182 dprintk("Found rkfill handle: 0x%.4x\n", sony_rfkill_handle);
1160 1183
1161 ret = sony_call_snc_handle(0x124, 0xb00, &result); 1184 /* need to read the whole buffer returned by the acpi call to SN06
1162 if (ret) { 1185 * here otherwise we may miss some features
1163 printk(KERN_INFO DRV_PFX 1186 */
1164 "Unable to enumerate rfkill devices: %x\n", ret); 1187 params.count = 1;
1165 return ret; 1188 params.pointer = &in_obj;
1189 in_obj.type = ACPI_TYPE_INTEGER;
1190 in_obj.integer.value = offset;
1191 status = acpi_evaluate_object(sony_nc_acpi_handle, "SN06", &params,
1192 &buffer);
1193 if (ACPI_FAILURE(status)) {
1194 dprintk("Radio device enumeration failed\n");
1195 return;
1196 }
1197
1198 device_enum = (union acpi_object *) buffer.pointer;
1199 if (!device_enum || device_enum->type != ACPI_TYPE_BUFFER) {
1200 printk(KERN_ERR "Invalid SN06 return object 0x%.2x\n",
1201 device_enum->type);
1202 goto out_no_enum;
1166 } 1203 }
1167 1204
1168 if (result & 0x1) 1205 /* the buffer is filled with magic numbers describing the devices
1169 sony_nc_setup_rfkill(device, SONY_WIFI); 1206 * available, 0xff terminates the enumeration
1170 if (result & 0x2) 1207 */
1171 sony_nc_setup_rfkill(device, SONY_BLUETOOTH); 1208 for (i = 0; i < device_enum->buffer.length; i++) {
1172 if (result & 0x1c)
1173 sony_nc_setup_rfkill(device, SONY_WWAN);
1174 if (result & 0x20)
1175 sony_nc_setup_rfkill(device, SONY_WIMAX);
1176 1209
1177 return 0; 1210 dev_code = *(device_enum->buffer.pointer + i);
1211 if (dev_code == 0xff)
1212 break;
1213
1214 dprintk("Radio devices, looking at 0x%.2x\n", dev_code);
1215
1216 if (dev_code == 0 && !sony_rfkill_devices[SONY_WIFI])
1217 sony_nc_setup_rfkill(device, SONY_WIFI);
1218
1219 if (dev_code == 0x10 && !sony_rfkill_devices[SONY_BLUETOOTH])
1220 sony_nc_setup_rfkill(device, SONY_BLUETOOTH);
1221
1222 if ((0xf0 & dev_code) == 0x20 &&
1223 !sony_rfkill_devices[SONY_WWAN])
1224 sony_nc_setup_rfkill(device, SONY_WWAN);
1225
1226 if (dev_code == 0x30 && !sony_rfkill_devices[SONY_WIMAX])
1227 sony_nc_setup_rfkill(device, SONY_WIMAX);
1228 }
1229
1230out_no_enum:
1231 kfree(buffer.pointer);
1232 return;
1178} 1233}
1179 1234
1180static int sony_nc_add(struct acpi_device *device) 1235static int sony_nc_add(struct acpi_device *device)
@@ -1203,7 +1258,7 @@ static int sony_nc_add(struct acpi_device *device)
1203 1258
1204 if (debug) { 1259 if (debug) {
1205 status = acpi_walk_namespace(ACPI_TYPE_METHOD, sony_nc_acpi_handle, 1260 status = acpi_walk_namespace(ACPI_TYPE_METHOD, sony_nc_acpi_handle,
1206 1, sony_walk_callback, NULL, NULL); 1261 1, sony_walk_callback, NULL, NULL, NULL);
1207 if (ACPI_FAILURE(status)) { 1262 if (ACPI_FAILURE(status)) {
1208 printk(KERN_WARNING DRV_PFX "unable to walk acpi resources\n"); 1263 printk(KERN_WARNING DRV_PFX "unable to walk acpi resources\n");
1209 result = -ENODEV; 1264 result = -ENODEV;
@@ -1237,9 +1292,13 @@ static int sony_nc_add(struct acpi_device *device)
1237 "controlled by ACPI video driver\n"); 1292 "controlled by ACPI video driver\n");
1238 } else if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "GBRT", 1293 } else if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "GBRT",
1239 &handle))) { 1294 &handle))) {
1295 struct backlight_properties props;
1296 memset(&props, 0, sizeof(struct backlight_properties));
1297 props.max_brightness = SONY_MAX_BRIGHTNESS - 1;
1240 sony_backlight_device = backlight_device_register("sony", NULL, 1298 sony_backlight_device = backlight_device_register("sony", NULL,
1241 NULL, 1299 NULL,
1242 &sony_backlight_ops); 1300 &sony_backlight_ops,
1301 &props);
1243 1302
1244 if (IS_ERR(sony_backlight_device)) { 1303 if (IS_ERR(sony_backlight_device)) {
1245 printk(KERN_WARNING DRV_PFX "unable to register backlight device\n"); 1304 printk(KERN_WARNING DRV_PFX "unable to register backlight device\n");
@@ -1248,8 +1307,6 @@ static int sony_nc_add(struct acpi_device *device)
1248 sony_backlight_device->props.brightness = 1307 sony_backlight_device->props.brightness =
1249 sony_backlight_get_brightness 1308 sony_backlight_get_brightness
1250 (sony_backlight_device); 1309 (sony_backlight_device);
1251 sony_backlight_device->props.max_brightness =
1252 SONY_MAX_BRIGHTNESS - 1;
1253 } 1310 }
1254 1311
1255 } 1312 }
@@ -2079,7 +2136,7 @@ static struct attribute_group spic_attribute_group = {
2079 2136
2080struct sonypi_compat_s { 2137struct sonypi_compat_s {
2081 struct fasync_struct *fifo_async; 2138 struct fasync_struct *fifo_async;
2082 struct kfifo *fifo; 2139 struct kfifo fifo;
2083 spinlock_t fifo_lock; 2140 spinlock_t fifo_lock;
2084 wait_queue_head_t fifo_proc_list; 2141 wait_queue_head_t fifo_proc_list;
2085 atomic_t open_count; 2142 atomic_t open_count;
@@ -2104,12 +2161,12 @@ static int sonypi_misc_open(struct inode *inode, struct file *file)
2104 /* Flush input queue on first open */ 2161 /* Flush input queue on first open */
2105 unsigned long flags; 2162 unsigned long flags;
2106 2163
2107 spin_lock_irqsave(sonypi_compat.fifo->lock, flags); 2164 spin_lock_irqsave(&sonypi_compat.fifo_lock, flags);
2108 2165
2109 if (atomic_inc_return(&sonypi_compat.open_count) == 1) 2166 if (atomic_inc_return(&sonypi_compat.open_count) == 1)
2110 __kfifo_reset(sonypi_compat.fifo); 2167 kfifo_reset(&sonypi_compat.fifo);
2111 2168
2112 spin_unlock_irqrestore(sonypi_compat.fifo->lock, flags); 2169 spin_unlock_irqrestore(&sonypi_compat.fifo_lock, flags);
2113 2170
2114 return 0; 2171 return 0;
2115} 2172}
@@ -2120,17 +2177,18 @@ static ssize_t sonypi_misc_read(struct file *file, char __user *buf,
2120 ssize_t ret; 2177 ssize_t ret;
2121 unsigned char c; 2178 unsigned char c;
2122 2179
2123 if ((kfifo_len(sonypi_compat.fifo) == 0) && 2180 if ((kfifo_len(&sonypi_compat.fifo) == 0) &&
2124 (file->f_flags & O_NONBLOCK)) 2181 (file->f_flags & O_NONBLOCK))
2125 return -EAGAIN; 2182 return -EAGAIN;
2126 2183
2127 ret = wait_event_interruptible(sonypi_compat.fifo_proc_list, 2184 ret = wait_event_interruptible(sonypi_compat.fifo_proc_list,
2128 kfifo_len(sonypi_compat.fifo) != 0); 2185 kfifo_len(&sonypi_compat.fifo) != 0);
2129 if (ret) 2186 if (ret)
2130 return ret; 2187 return ret;
2131 2188
2132 while (ret < count && 2189 while (ret < count &&
2133 (kfifo_get(sonypi_compat.fifo, &c, sizeof(c)) == sizeof(c))) { 2190 (kfifo_out_locked(&sonypi_compat.fifo, &c, sizeof(c),
2191 &sonypi_compat.fifo_lock) == sizeof(c))) {
2134 if (put_user(c, buf++)) 2192 if (put_user(c, buf++))
2135 return -EFAULT; 2193 return -EFAULT;
2136 ret++; 2194 ret++;
@@ -2147,7 +2205,7 @@ static ssize_t sonypi_misc_read(struct file *file, char __user *buf,
2147static unsigned int sonypi_misc_poll(struct file *file, poll_table *wait) 2205static unsigned int sonypi_misc_poll(struct file *file, poll_table *wait)
2148{ 2206{
2149 poll_wait(file, &sonypi_compat.fifo_proc_list, wait); 2207 poll_wait(file, &sonypi_compat.fifo_proc_list, wait);
2150 if (kfifo_len(sonypi_compat.fifo)) 2208 if (kfifo_len(&sonypi_compat.fifo))
2151 return POLLIN | POLLRDNORM; 2209 return POLLIN | POLLRDNORM;
2152 return 0; 2210 return 0;
2153} 2211}
@@ -2309,7 +2367,8 @@ static struct miscdevice sonypi_misc_device = {
2309 2367
2310static void sonypi_compat_report_event(u8 event) 2368static void sonypi_compat_report_event(u8 event)
2311{ 2369{
2312 kfifo_put(sonypi_compat.fifo, (unsigned char *)&event, sizeof(event)); 2370 kfifo_in_locked(&sonypi_compat.fifo, (unsigned char *)&event,
2371 sizeof(event), &sonypi_compat.fifo_lock);
2313 kill_fasync(&sonypi_compat.fifo_async, SIGIO, POLL_IN); 2372 kill_fasync(&sonypi_compat.fifo_async, SIGIO, POLL_IN);
2314 wake_up_interruptible(&sonypi_compat.fifo_proc_list); 2373 wake_up_interruptible(&sonypi_compat.fifo_proc_list);
2315} 2374}
@@ -2319,11 +2378,11 @@ static int sonypi_compat_init(void)
2319 int error; 2378 int error;
2320 2379
2321 spin_lock_init(&sonypi_compat.fifo_lock); 2380 spin_lock_init(&sonypi_compat.fifo_lock);
2322 sonypi_compat.fifo = kfifo_alloc(SONY_LAPTOP_BUF_SIZE, GFP_KERNEL, 2381 error =
2323 &sonypi_compat.fifo_lock); 2382 kfifo_alloc(&sonypi_compat.fifo, SONY_LAPTOP_BUF_SIZE, GFP_KERNEL);
2324 if (IS_ERR(sonypi_compat.fifo)) { 2383 if (error) {
2325 printk(KERN_ERR DRV_PFX "kfifo_alloc failed\n"); 2384 printk(KERN_ERR DRV_PFX "kfifo_alloc failed\n");
2326 return PTR_ERR(sonypi_compat.fifo); 2385 return error;
2327 } 2386 }
2328 2387
2329 init_waitqueue_head(&sonypi_compat.fifo_proc_list); 2388 init_waitqueue_head(&sonypi_compat.fifo_proc_list);
@@ -2342,14 +2401,14 @@ static int sonypi_compat_init(void)
2342 return 0; 2401 return 0;
2343 2402
2344err_free_kfifo: 2403err_free_kfifo:
2345 kfifo_free(sonypi_compat.fifo); 2404 kfifo_free(&sonypi_compat.fifo);
2346 return error; 2405 return error;
2347} 2406}
2348 2407
2349static void sonypi_compat_exit(void) 2408static void sonypi_compat_exit(void)
2350{ 2409{
2351 misc_deregister(&sonypi_misc_device); 2410 misc_deregister(&sonypi_misc_device);
2352 kfifo_free(sonypi_compat.fifo); 2411 kfifo_free(&sonypi_compat.fifo);
2353} 2412}
2354#else 2413#else
2355static int sonypi_compat_init(void) { return 0; } 2414static int sonypi_compat_init(void) { return 0; }
diff --git a/drivers/platform/x86/tc1100-wmi.c b/drivers/platform/x86/tc1100-wmi.c
index 44166003d4ef..1fe0f1feff71 100644
--- a/drivers/platform/x86/tc1100-wmi.c
+++ b/drivers/platform/x86/tc1100-wmi.c
@@ -27,6 +27,7 @@
27 27
28#include <linux/kernel.h> 28#include <linux/kernel.h>
29#include <linux/module.h> 29#include <linux/module.h>
30#include <linux/slab.h>
30#include <linux/init.h> 31#include <linux/init.h>
31#include <linux/types.h> 32#include <linux/types.h>
32#include <acpi/acpi.h> 33#include <acpi/acpi.h>
@@ -47,22 +48,6 @@ MODULE_DESCRIPTION("HP Compaq TC1100 Tablet WMI Extras");
47MODULE_LICENSE("GPL"); 48MODULE_LICENSE("GPL");
48MODULE_ALIAS("wmi:C364AC71-36DB-495A-8494-B439D472A505"); 49MODULE_ALIAS("wmi:C364AC71-36DB-495A-8494-B439D472A505");
49 50
50static int tc1100_probe(struct platform_device *device);
51static int tc1100_remove(struct platform_device *device);
52static int tc1100_suspend(struct platform_device *device, pm_message_t state);
53static int tc1100_resume(struct platform_device *device);
54
55static struct platform_driver tc1100_driver = {
56 .driver = {
57 .name = "tc1100-wmi",
58 .owner = THIS_MODULE,
59 },
60 .probe = tc1100_probe,
61 .remove = tc1100_remove,
62 .suspend = tc1100_suspend,
63 .resume = tc1100_resume,
64};
65
66static struct platform_device *tc1100_device; 51static struct platform_device *tc1100_device;
67 52
68struct tc1100_data { 53struct tc1100_data {
@@ -183,51 +168,35 @@ static DEVICE_ATTR(value, S_IWUGO | S_IRUGO | S_IWUSR, \
183show_set_bool(wireless, TC1100_INSTANCE_WIRELESS); 168show_set_bool(wireless, TC1100_INSTANCE_WIRELESS);
184show_set_bool(jogdial, TC1100_INSTANCE_JOGDIAL); 169show_set_bool(jogdial, TC1100_INSTANCE_JOGDIAL);
185 170
186static void remove_fs(void) 171static struct attribute *tc1100_attributes[] = {
187{ 172 &dev_attr_wireless.attr,
188 device_remove_file(&tc1100_device->dev, &dev_attr_wireless); 173 &dev_attr_jogdial.attr,
189 device_remove_file(&tc1100_device->dev, &dev_attr_jogdial); 174 NULL
190} 175};
191
192static int add_fs(void)
193{
194 int ret;
195
196 ret = device_create_file(&tc1100_device->dev, &dev_attr_wireless);
197 if (ret)
198 goto add_sysfs_error;
199
200 ret = device_create_file(&tc1100_device->dev, &dev_attr_jogdial);
201 if (ret)
202 goto add_sysfs_error;
203
204 return ret;
205 176
206add_sysfs_error: 177static struct attribute_group tc1100_attribute_group = {
207 remove_fs(); 178 .attrs = tc1100_attributes,
208 return ret; 179};
209}
210 180
211/* -------------------------------------------------------------------------- 181/* --------------------------------------------------------------------------
212 Driver Model 182 Driver Model
213 -------------------------------------------------------------------------- */ 183 -------------------------------------------------------------------------- */
214 184
215static int tc1100_probe(struct platform_device *device) 185static int __init tc1100_probe(struct platform_device *device)
216{ 186{
217 int result = 0; 187 return sysfs_create_group(&device->dev.kobj, &tc1100_attribute_group);
218
219 result = add_fs();
220 return result;
221} 188}
222 189
223 190
224static int tc1100_remove(struct platform_device *device) 191static int __devexit tc1100_remove(struct platform_device *device)
225{ 192{
226 remove_fs(); 193 sysfs_remove_group(&device->dev.kobj, &tc1100_attribute_group);
194
227 return 0; 195 return 0;
228} 196}
229 197
230static int tc1100_suspend(struct platform_device *dev, pm_message_t state) 198#ifdef CONFIG_PM
199static int tc1100_suspend(struct device *dev)
231{ 200{
232 int ret; 201 int ret;
233 202
@@ -239,10 +208,10 @@ static int tc1100_suspend(struct platform_device *dev, pm_message_t state)
239 if (ret) 208 if (ret)
240 return ret; 209 return ret;
241 210
242 return ret; 211 return 0;
243} 212}
244 213
245static int tc1100_resume(struct platform_device *dev) 214static int tc1100_resume(struct device *dev)
246{ 215{
247 int ret; 216 int ret;
248 217
@@ -254,34 +223,61 @@ static int tc1100_resume(struct platform_device *dev)
254 if (ret) 223 if (ret)
255 return ret; 224 return ret;
256 225
257 return ret; 226 return 0;
258} 227}
259 228
229static const struct dev_pm_ops tc1100_pm_ops = {
230 .suspend = tc1100_suspend,
231 .resume = tc1100_resume,
232 .freeze = tc1100_suspend,
233 .restore = tc1100_resume,
234};
235#endif
236
237static struct platform_driver tc1100_driver = {
238 .driver = {
239 .name = "tc1100-wmi",
240 .owner = THIS_MODULE,
241#ifdef CONFIG_PM
242 .pm = &tc1100_pm_ops,
243#endif
244 },
245 .remove = __devexit_p(tc1100_remove),
246};
247
260static int __init tc1100_init(void) 248static int __init tc1100_init(void)
261{ 249{
262 int result = 0; 250 int error;
263 251
264 if (!wmi_has_guid(GUID)) 252 if (!wmi_has_guid(GUID))
265 return -ENODEV; 253 return -ENODEV;
266 254
267 result = platform_driver_register(&tc1100_driver);
268 if (result)
269 return result;
270
271 tc1100_device = platform_device_alloc("tc1100-wmi", -1); 255 tc1100_device = platform_device_alloc("tc1100-wmi", -1);
272 platform_device_add(tc1100_device); 256 if (!tc1100_device)
257 return -ENOMEM;
258
259 error = platform_device_add(tc1100_device);
260 if (error)
261 goto err_device_put;
262
263 error = platform_driver_probe(&tc1100_driver, tc1100_probe);
264 if (error)
265 goto err_device_del;
273 266
274 printk(TC1100_INFO "HP Compaq TC1100 Tablet WMI Extras loaded\n"); 267 printk(TC1100_INFO "HP Compaq TC1100 Tablet WMI Extras loaded\n");
268 return 0;
275 269
276 return result; 270 err_device_del:
271 platform_device_del(tc1100_device);
272 err_device_put:
273 platform_device_put(tc1100_device);
274 return error;
277} 275}
278 276
279static void __exit tc1100_exit(void) 277static void __exit tc1100_exit(void)
280{ 278{
281 platform_device_del(tc1100_device); 279 platform_device_unregister(tc1100_device);
282 platform_driver_unregister(&tc1100_driver); 280 platform_driver_unregister(&tc1100_driver);
283
284 printk(TC1100_INFO "HP Compaq TC1100 Tablet WMI Extras unloaded\n");
285} 281}
286 282
287module_init(tc1100_init); 283module_init(tc1100_init);
diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c
index a848c7e20aeb..63290b33c879 100644
--- a/drivers/platform/x86/thinkpad_acpi.c
+++ b/drivers/platform/x86/thinkpad_acpi.c
@@ -21,8 +21,8 @@
21 * 02110-1301, USA. 21 * 02110-1301, USA.
22 */ 22 */
23 23
24#define TPACPI_VERSION "0.23" 24#define TPACPI_VERSION "0.24"
25#define TPACPI_SYSFS_VERSION 0x020500 25#define TPACPI_SYSFS_VERSION 0x020700
26 26
27/* 27/*
28 * Changelog: 28 * Changelog:
@@ -58,9 +58,11 @@
58#include <linux/kthread.h> 58#include <linux/kthread.h>
59#include <linux/freezer.h> 59#include <linux/freezer.h>
60#include <linux/delay.h> 60#include <linux/delay.h>
61#include <linux/slab.h>
61 62
62#include <linux/nvram.h> 63#include <linux/nvram.h>
63#include <linux/proc_fs.h> 64#include <linux/proc_fs.h>
65#include <linux/seq_file.h>
64#include <linux/sysfs.h> 66#include <linux/sysfs.h>
65#include <linux/backlight.h> 67#include <linux/backlight.h>
66#include <linux/fb.h> 68#include <linux/fb.h>
@@ -76,6 +78,10 @@
76#include <linux/jiffies.h> 78#include <linux/jiffies.h>
77#include <linux/workqueue.h> 79#include <linux/workqueue.h>
78 80
81#include <sound/core.h>
82#include <sound/control.h>
83#include <sound/initval.h>
84
79#include <acpi/acpi_drivers.h> 85#include <acpi/acpi_drivers.h>
80 86
81#include <linux/pci_ids.h> 87#include <linux/pci_ids.h>
@@ -231,6 +237,7 @@ enum tpacpi_hkey_event_t {
231#define TPACPI_DBG_HKEY 0x0008 237#define TPACPI_DBG_HKEY 0x0008
232#define TPACPI_DBG_FAN 0x0010 238#define TPACPI_DBG_FAN 0x0010
233#define TPACPI_DBG_BRGHT 0x0020 239#define TPACPI_DBG_BRGHT 0x0020
240#define TPACPI_DBG_MIXER 0x0040
234 241
235#define onoff(status, bit) ((status) & (1 << (bit)) ? "on" : "off") 242#define onoff(status, bit) ((status) & (1 << (bit)) ? "on" : "off")
236#define enabled(status, bit) ((status) & (1 << (bit)) ? "enabled" : "disabled") 243#define enabled(status, bit) ((status) & (1 << (bit)) ? "enabled" : "disabled")
@@ -256,7 +263,7 @@ struct tp_acpi_drv_struct {
256struct ibm_struct { 263struct ibm_struct {
257 char *name; 264 char *name;
258 265
259 int (*read) (char *); 266 int (*read) (struct seq_file *);
260 int (*write) (char *); 267 int (*write) (char *);
261 void (*exit) (void); 268 void (*exit) (void);
262 void (*resume) (void); 269 void (*resume) (void);
@@ -280,6 +287,7 @@ struct ibm_init_struct {
280 char param[32]; 287 char param[32];
281 288
282 int (*init) (struct ibm_init_struct *); 289 int (*init) (struct ibm_init_struct *);
290 mode_t base_procfs_mode;
283 struct ibm_struct *data; 291 struct ibm_struct *data;
284}; 292};
285 293
@@ -298,6 +306,7 @@ static struct {
298 u32 fan_ctrl_status_undef:1; 306 u32 fan_ctrl_status_undef:1;
299 u32 second_fan:1; 307 u32 second_fan:1;
300 u32 beep_needs_two_args:1; 308 u32 beep_needs_two_args:1;
309 u32 mixer_no_level_control:1;
301 u32 input_device_registered:1; 310 u32 input_device_registered:1;
302 u32 platform_drv_registered:1; 311 u32 platform_drv_registered:1;
303 u32 platform_drv_attrs_registered:1; 312 u32 platform_drv_attrs_registered:1;
@@ -309,6 +318,7 @@ static struct {
309 318
310static struct { 319static struct {
311 u16 hotkey_mask_ff:1; 320 u16 hotkey_mask_ff:1;
321 u16 volume_ctrl_forbidden:1;
312} tp_warned; 322} tp_warned;
313 323
314struct thinkpad_id_data { 324struct thinkpad_id_data {
@@ -425,6 +435,12 @@ static void tpacpi_log_usertask(const char * const what)
425 .ec = TPACPI_MATCH_ANY, \ 435 .ec = TPACPI_MATCH_ANY, \
426 .quirks = (__quirk) } 436 .quirks = (__quirk) }
427 437
438#define TPACPI_QEC_LNV(__id1, __id2, __quirk) \
439 { .vendor = PCI_VENDOR_ID_LENOVO, \
440 .bios = TPACPI_MATCH_ANY, \
441 .ec = TPID(__id1, __id2), \
442 .quirks = (__quirk) }
443
428struct tpacpi_quirk { 444struct tpacpi_quirk {
429 unsigned int vendor; 445 unsigned int vendor;
430 u16 bios; 446 u16 bios;
@@ -776,36 +792,25 @@ static int __init register_tpacpi_subdriver(struct ibm_struct *ibm)
776 **************************************************************************** 792 ****************************************************************************
777 ****************************************************************************/ 793 ****************************************************************************/
778 794
779static int dispatch_procfs_read(char *page, char **start, off_t off, 795static int dispatch_proc_show(struct seq_file *m, void *v)
780 int count, int *eof, void *data)
781{ 796{
782 struct ibm_struct *ibm = data; 797 struct ibm_struct *ibm = m->private;
783 int len;
784 798
785 if (!ibm || !ibm->read) 799 if (!ibm || !ibm->read)
786 return -EINVAL; 800 return -EINVAL;
801 return ibm->read(m);
802}
787 803
788 len = ibm->read(page); 804static int dispatch_proc_open(struct inode *inode, struct file *file)
789 if (len < 0) 805{
790 return len; 806 return single_open(file, dispatch_proc_show, PDE(inode)->data);
791
792 if (len <= off + count)
793 *eof = 1;
794 *start = page + off;
795 len -= off;
796 if (len > count)
797 len = count;
798 if (len < 0)
799 len = 0;
800
801 return len;
802} 807}
803 808
804static int dispatch_procfs_write(struct file *file, 809static ssize_t dispatch_proc_write(struct file *file,
805 const char __user *userbuf, 810 const char __user *userbuf,
806 unsigned long count, void *data) 811 size_t count, loff_t *pos)
807{ 812{
808 struct ibm_struct *ibm = data; 813 struct ibm_struct *ibm = PDE(file->f_path.dentry->d_inode)->data;
809 char *kernbuf; 814 char *kernbuf;
810 int ret; 815 int ret;
811 816
@@ -834,6 +839,15 @@ static int dispatch_procfs_write(struct file *file,
834 return ret; 839 return ret;
835} 840}
836 841
842static const struct file_operations dispatch_proc_fops = {
843 .owner = THIS_MODULE,
844 .open = dispatch_proc_open,
845 .read = seq_read,
846 .llseek = seq_lseek,
847 .release = single_release,
848 .write = dispatch_proc_write,
849};
850
837static char *next_cmd(char **cmds) 851static char *next_cmd(char **cmds)
838{ 852{
839 char *start = *cmds; 853 char *start = *cmds;
@@ -1006,11 +1020,8 @@ static int parse_strtoul(const char *buf,
1006{ 1020{
1007 char *endp; 1021 char *endp;
1008 1022
1009 while (*buf && isspace(*buf)) 1023 *value = simple_strtoul(skip_spaces(buf), &endp, 0);
1010 buf++; 1024 endp = skip_spaces(endp);
1011 *value = simple_strtoul(buf, &endp, 0);
1012 while (*endp && isspace(*endp))
1013 endp++;
1014 if (*endp || *value > max) 1025 if (*endp || *value > max)
1015 return -EINVAL; 1026 return -EINVAL;
1016 1027
@@ -1087,7 +1098,7 @@ static int __init tpacpi_check_std_acpi_brightness_support(void)
1087 */ 1098 */
1088 1099
1089 status = acpi_walk_namespace(ACPI_TYPE_METHOD, vid_handle, 3, 1100 status = acpi_walk_namespace(ACPI_TYPE_METHOD, vid_handle, 3,
1090 tpacpi_acpi_walk_find_bcl, NULL, 1101 tpacpi_acpi_walk_find_bcl, NULL, NULL,
1091 &bcl_ptr); 1102 &bcl_ptr);
1092 1103
1093 if (ACPI_SUCCESS(status) && bcl_levels > 2) { 1104 if (ACPI_SUCCESS(status) && bcl_levels > 2) {
@@ -1264,6 +1275,7 @@ static int __init tpacpi_new_rfkill(const enum tpacpi_rfk_id id,
1264 struct tpacpi_rfk *atp_rfk; 1275 struct tpacpi_rfk *atp_rfk;
1265 int res; 1276 int res;
1266 bool sw_state = false; 1277 bool sw_state = false;
1278 bool hw_state;
1267 int sw_status; 1279 int sw_status;
1268 1280
1269 BUG_ON(id >= TPACPI_RFK_SW_MAX || tpacpi_rfkill_switches[id]); 1281 BUG_ON(id >= TPACPI_RFK_SW_MAX || tpacpi_rfkill_switches[id]);
@@ -1298,7 +1310,8 @@ static int __init tpacpi_new_rfkill(const enum tpacpi_rfk_id id,
1298 rfkill_init_sw_state(atp_rfk->rfkill, sw_state); 1310 rfkill_init_sw_state(atp_rfk->rfkill, sw_state);
1299 } 1311 }
1300 } 1312 }
1301 rfkill_set_hw_state(atp_rfk->rfkill, tpacpi_rfk_check_hwblock_state()); 1313 hw_state = tpacpi_rfk_check_hwblock_state();
1314 rfkill_set_hw_state(atp_rfk->rfkill, hw_state);
1302 1315
1303 res = rfkill_register(atp_rfk->rfkill); 1316 res = rfkill_register(atp_rfk->rfkill);
1304 if (res < 0) { 1317 if (res < 0) {
@@ -1311,6 +1324,9 @@ static int __init tpacpi_new_rfkill(const enum tpacpi_rfk_id id,
1311 } 1324 }
1312 1325
1313 tpacpi_rfkill_switches[id] = atp_rfk; 1326 tpacpi_rfkill_switches[id] = atp_rfk;
1327
1328 printk(TPACPI_INFO "rfkill switch %s: radio is %sblocked\n",
1329 name, (sw_state || hw_state) ? "" : "un");
1314 return 0; 1330 return 0;
1315} 1331}
1316 1332
@@ -1383,12 +1399,10 @@ static ssize_t tpacpi_rfk_sysfs_enable_store(const enum tpacpi_rfk_id id,
1383} 1399}
1384 1400
1385/* procfs -------------------------------------------------------------- */ 1401/* procfs -------------------------------------------------------------- */
1386static int tpacpi_rfk_procfs_read(const enum tpacpi_rfk_id id, char *p) 1402static int tpacpi_rfk_procfs_read(const enum tpacpi_rfk_id id, struct seq_file *m)
1387{ 1403{
1388 int len = 0;
1389
1390 if (id >= TPACPI_RFK_SW_MAX) 1404 if (id >= TPACPI_RFK_SW_MAX)
1391 len += sprintf(p + len, "status:\t\tnot supported\n"); 1405 seq_printf(m, "status:\t\tnot supported\n");
1392 else { 1406 else {
1393 int status; 1407 int status;
1394 1408
@@ -1402,13 +1416,13 @@ static int tpacpi_rfk_procfs_read(const enum tpacpi_rfk_id id, char *p)
1402 return status; 1416 return status;
1403 } 1417 }
1404 1418
1405 len += sprintf(p + len, "status:\t\t%s\n", 1419 seq_printf(m, "status:\t\t%s\n",
1406 (status == TPACPI_RFK_RADIO_ON) ? 1420 (status == TPACPI_RFK_RADIO_ON) ?
1407 "enabled" : "disabled"); 1421 "enabled" : "disabled");
1408 len += sprintf(p + len, "commands:\tenable, disable\n"); 1422 seq_printf(m, "commands:\tenable, disable\n");
1409 } 1423 }
1410 1424
1411 return len; 1425 return 0;
1412} 1426}
1413 1427
1414static int tpacpi_rfk_procfs_write(const enum tpacpi_rfk_id id, char *buf) 1428static int tpacpi_rfk_procfs_write(const enum tpacpi_rfk_id id, char *buf)
@@ -1655,7 +1669,7 @@ static void tpacpi_remove_driver_attributes(struct device_driver *drv)
1655 * Table of recommended minimum BIOS versions 1669 * Table of recommended minimum BIOS versions
1656 * 1670 *
1657 * Reasons for listing: 1671 * Reasons for listing:
1658 * 1. Stable BIOS, listed because the unknown ammount of 1672 * 1. Stable BIOS, listed because the unknown amount of
1659 * bugs and bad ACPI behaviour on older versions 1673 * bugs and bad ACPI behaviour on older versions
1660 * 1674 *
1661 * 2. BIOS or EC fw with known bugs that trigger on Linux 1675 * 2. BIOS or EC fw with known bugs that trigger on Linux
@@ -1779,7 +1793,7 @@ static const struct tpacpi_quirk tpacpi_bios_version_qtable[] __initconst = {
1779 1793
1780 TPV_QL1('7', '9', 'E', '3', '5', '0'), /* T60/p */ 1794 TPV_QL1('7', '9', 'E', '3', '5', '0'), /* T60/p */
1781 TPV_QL1('7', 'C', 'D', '2', '2', '2'), /* R60, R60i */ 1795 TPV_QL1('7', 'C', 'D', '2', '2', '2'), /* R60, R60i */
1782 TPV_QL0('7', 'E', 'D', '0'), /* R60e, R60i */ 1796 TPV_QL1('7', 'E', 'D', '0', '1', '5'), /* R60e, R60i */
1783 1797
1784 /* BIOS FW BIOS VERS EC FW EC VERS */ 1798 /* BIOS FW BIOS VERS EC FW EC VERS */
1785 TPV_QI2('1', 'W', '9', '0', '1', 'V', '2', '8'), /* R50e (1) */ 1799 TPV_QI2('1', 'W', '9', '0', '1', 'V', '2', '8'), /* R50e (1) */
@@ -1795,8 +1809,8 @@ static const struct tpacpi_quirk tpacpi_bios_version_qtable[] __initconst = {
1795 TPV_QI1('7', '4', '6', '4', '2', '7'), /* X41 (0) */ 1809 TPV_QI1('7', '4', '6', '4', '2', '7'), /* X41 (0) */
1796 TPV_QI1('7', '5', '6', '0', '2', '0'), /* X41t (0) */ 1810 TPV_QI1('7', '5', '6', '0', '2', '0'), /* X41t (0) */
1797 1811
1798 TPV_QL0('7', 'B', 'D', '7'), /* X60/s */ 1812 TPV_QL1('7', 'B', 'D', '7', '4', '0'), /* X60/s */
1799 TPV_QL0('7', 'J', '3', '0'), /* X60t */ 1813 TPV_QL1('7', 'J', '3', '0', '1', '3'), /* X60t */
1800 1814
1801 /* (0) - older versions lack DMI EC fw string and functionality */ 1815 /* (0) - older versions lack DMI EC fw string and functionality */
1802 /* (1) - older versions known to lack functionality */ 1816 /* (1) - older versions known to lack functionality */
@@ -1886,14 +1900,11 @@ static int __init thinkpad_acpi_driver_init(struct ibm_init_struct *iibm)
1886 return 0; 1900 return 0;
1887} 1901}
1888 1902
1889static int thinkpad_acpi_driver_read(char *p) 1903static int thinkpad_acpi_driver_read(struct seq_file *m)
1890{ 1904{
1891 int len = 0; 1905 seq_printf(m, "driver:\t\t%s\n", TPACPI_DESC);
1892 1906 seq_printf(m, "version:\t%s\n", TPACPI_VERSION);
1893 len += sprintf(p + len, "driver:\t\t%s\n", TPACPI_DESC); 1907 return 0;
1894 len += sprintf(p + len, "version:\t%s\n", TPACPI_VERSION);
1895
1896 return len;
1897} 1908}
1898 1909
1899static struct ibm_struct thinkpad_acpi_driver_data = { 1910static struct ibm_struct thinkpad_acpi_driver_data = {
@@ -2073,6 +2084,7 @@ static struct attribute_set *hotkey_dev_attributes;
2073 2084
2074static void tpacpi_driver_event(const unsigned int hkey_event); 2085static void tpacpi_driver_event(const unsigned int hkey_event);
2075static void hotkey_driver_event(const unsigned int scancode); 2086static void hotkey_driver_event(const unsigned int scancode);
2087static void hotkey_poll_setup(const bool may_warn);
2076 2088
2077/* HKEY.MHKG() return bits */ 2089/* HKEY.MHKG() return bits */
2078#define TP_HOTKEY_TABLET_MASK (1 << 3) 2090#define TP_HOTKEY_TABLET_MASK (1 << 3)
@@ -2189,7 +2201,8 @@ static int hotkey_mask_set(u32 mask)
2189 fwmask, hotkey_acpi_mask); 2201 fwmask, hotkey_acpi_mask);
2190 } 2202 }
2191 2203
2192 hotkey_mask_warn_incomplete_mask(); 2204 if (tpacpi_lifecycle != TPACPI_LIFE_EXITING)
2205 hotkey_mask_warn_incomplete_mask();
2193 2206
2194 return rc; 2207 return rc;
2195} 2208}
@@ -2254,6 +2267,8 @@ static int tpacpi_hotkey_driver_mask_set(const u32 mask)
2254 2267
2255 rc = hotkey_mask_set((hotkey_acpi_mask | hotkey_driver_mask) & 2268 rc = hotkey_mask_set((hotkey_acpi_mask | hotkey_driver_mask) &
2256 ~hotkey_source_mask); 2269 ~hotkey_source_mask);
2270 hotkey_poll_setup(true);
2271
2257 mutex_unlock(&hotkey_mutex); 2272 mutex_unlock(&hotkey_mutex);
2258 2273
2259 return rc; 2274 return rc;
@@ -2538,7 +2553,7 @@ static void hotkey_poll_stop_sync(void)
2538} 2553}
2539 2554
2540/* call with hotkey_mutex held */ 2555/* call with hotkey_mutex held */
2541static void hotkey_poll_setup(bool may_warn) 2556static void hotkey_poll_setup(const bool may_warn)
2542{ 2557{
2543 const u32 poll_driver_mask = hotkey_driver_mask & hotkey_source_mask; 2558 const u32 poll_driver_mask = hotkey_driver_mask & hotkey_source_mask;
2544 const u32 poll_user_mask = hotkey_user_mask & hotkey_source_mask; 2559 const u32 poll_user_mask = hotkey_user_mask & hotkey_source_mask;
@@ -2569,7 +2584,7 @@ static void hotkey_poll_setup(bool may_warn)
2569 } 2584 }
2570} 2585}
2571 2586
2572static void hotkey_poll_setup_safe(bool may_warn) 2587static void hotkey_poll_setup_safe(const bool may_warn)
2573{ 2588{
2574 mutex_lock(&hotkey_mutex); 2589 mutex_lock(&hotkey_mutex);
2575 hotkey_poll_setup(may_warn); 2590 hotkey_poll_setup(may_warn);
@@ -2587,7 +2602,11 @@ static void hotkey_poll_set_freq(unsigned int freq)
2587 2602
2588#else /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */ 2603#else /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */
2589 2604
2590static void hotkey_poll_setup_safe(bool __unused) 2605static void hotkey_poll_setup(const bool __unused)
2606{
2607}
2608
2609static void hotkey_poll_setup_safe(const bool __unused)
2591{ 2610{
2592} 2611}
2593 2612
@@ -2597,16 +2616,11 @@ static int hotkey_inputdev_open(struct input_dev *dev)
2597{ 2616{
2598 switch (tpacpi_lifecycle) { 2617 switch (tpacpi_lifecycle) {
2599 case TPACPI_LIFE_INIT: 2618 case TPACPI_LIFE_INIT:
2600 /*
2601 * hotkey_init will call hotkey_poll_setup_safe
2602 * at the appropriate moment
2603 */
2604 return 0;
2605 case TPACPI_LIFE_EXITING:
2606 return -EBUSY;
2607 case TPACPI_LIFE_RUNNING: 2619 case TPACPI_LIFE_RUNNING:
2608 hotkey_poll_setup_safe(false); 2620 hotkey_poll_setup_safe(false);
2609 return 0; 2621 return 0;
2622 case TPACPI_LIFE_EXITING:
2623 return -EBUSY;
2610 } 2624 }
2611 2625
2612 /* Should only happen if tpacpi_lifecycle is corrupt */ 2626 /* Should only happen if tpacpi_lifecycle is corrupt */
@@ -2617,7 +2631,7 @@ static int hotkey_inputdev_open(struct input_dev *dev)
2617static void hotkey_inputdev_close(struct input_dev *dev) 2631static void hotkey_inputdev_close(struct input_dev *dev)
2618{ 2632{
2619 /* disable hotkey polling when possible */ 2633 /* disable hotkey polling when possible */
2620 if (tpacpi_lifecycle == TPACPI_LIFE_RUNNING && 2634 if (tpacpi_lifecycle != TPACPI_LIFE_EXITING &&
2621 !(hotkey_source_mask & hotkey_driver_mask)) 2635 !(hotkey_source_mask & hotkey_driver_mask))
2622 hotkey_poll_setup_safe(false); 2636 hotkey_poll_setup_safe(false);
2623} 2637}
@@ -3185,6 +3199,8 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
3185 int res, i; 3199 int res, i;
3186 int status; 3200 int status;
3187 int hkeyv; 3201 int hkeyv;
3202 bool radiosw_state = false;
3203 bool tabletsw_state = false;
3188 3204
3189 unsigned long quirks; 3205 unsigned long quirks;
3190 3206
@@ -3290,6 +3306,7 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
3290#ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES 3306#ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES
3291 if (dbg_wlswemul) { 3307 if (dbg_wlswemul) {
3292 tp_features.hotkey_wlsw = 1; 3308 tp_features.hotkey_wlsw = 1;
3309 radiosw_state = !!tpacpi_wlsw_emulstate;
3293 printk(TPACPI_INFO 3310 printk(TPACPI_INFO
3294 "radio switch emulation enabled\n"); 3311 "radio switch emulation enabled\n");
3295 } else 3312 } else
@@ -3297,6 +3314,7 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
3297 /* Not all thinkpads have a hardware radio switch */ 3314 /* Not all thinkpads have a hardware radio switch */
3298 if (acpi_evalf(hkey_handle, &status, "WLSW", "qd")) { 3315 if (acpi_evalf(hkey_handle, &status, "WLSW", "qd")) {
3299 tp_features.hotkey_wlsw = 1; 3316 tp_features.hotkey_wlsw = 1;
3317 radiosw_state = !!status;
3300 printk(TPACPI_INFO 3318 printk(TPACPI_INFO
3301 "radio switch found; radios are %s\n", 3319 "radio switch found; radios are %s\n",
3302 enabled(status, 0)); 3320 enabled(status, 0));
@@ -3308,11 +3326,11 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
3308 /* For X41t, X60t, X61t Tablets... */ 3326 /* For X41t, X60t, X61t Tablets... */
3309 if (!res && acpi_evalf(hkey_handle, &status, "MHKG", "qd")) { 3327 if (!res && acpi_evalf(hkey_handle, &status, "MHKG", "qd")) {
3310 tp_features.hotkey_tablet = 1; 3328 tp_features.hotkey_tablet = 1;
3329 tabletsw_state = !!(status & TP_HOTKEY_TABLET_MASK);
3311 printk(TPACPI_INFO 3330 printk(TPACPI_INFO
3312 "possible tablet mode switch found; " 3331 "possible tablet mode switch found; "
3313 "ThinkPad in %s mode\n", 3332 "ThinkPad in %s mode\n",
3314 (status & TP_HOTKEY_TABLET_MASK)? 3333 (tabletsw_state) ? "tablet" : "laptop");
3315 "tablet" : "laptop");
3316 res = add_to_attr_set(hotkey_dev_attributes, 3334 res = add_to_attr_set(hotkey_dev_attributes,
3317 &dev_attr_hotkey_tablet_mode.attr); 3335 &dev_attr_hotkey_tablet_mode.attr);
3318 } 3336 }
@@ -3347,16 +3365,14 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
3347 TPACPI_HOTKEY_MAP_SIZE); 3365 TPACPI_HOTKEY_MAP_SIZE);
3348 } 3366 }
3349 3367
3350 set_bit(EV_KEY, tpacpi_inputdev->evbit); 3368 input_set_capability(tpacpi_inputdev, EV_MSC, MSC_SCAN);
3351 set_bit(EV_MSC, tpacpi_inputdev->evbit);
3352 set_bit(MSC_SCAN, tpacpi_inputdev->mscbit);
3353 tpacpi_inputdev->keycodesize = TPACPI_HOTKEY_MAP_TYPESIZE; 3369 tpacpi_inputdev->keycodesize = TPACPI_HOTKEY_MAP_TYPESIZE;
3354 tpacpi_inputdev->keycodemax = TPACPI_HOTKEY_MAP_LEN; 3370 tpacpi_inputdev->keycodemax = TPACPI_HOTKEY_MAP_LEN;
3355 tpacpi_inputdev->keycode = hotkey_keycode_map; 3371 tpacpi_inputdev->keycode = hotkey_keycode_map;
3356 for (i = 0; i < TPACPI_HOTKEY_MAP_LEN; i++) { 3372 for (i = 0; i < TPACPI_HOTKEY_MAP_LEN; i++) {
3357 if (hotkey_keycode_map[i] != KEY_RESERVED) { 3373 if (hotkey_keycode_map[i] != KEY_RESERVED) {
3358 set_bit(hotkey_keycode_map[i], 3374 input_set_capability(tpacpi_inputdev, EV_KEY,
3359 tpacpi_inputdev->keybit); 3375 hotkey_keycode_map[i]);
3360 } else { 3376 } else {
3361 if (i < sizeof(hotkey_reserved_mask)*8) 3377 if (i < sizeof(hotkey_reserved_mask)*8)
3362 hotkey_reserved_mask |= 1 << i; 3378 hotkey_reserved_mask |= 1 << i;
@@ -3364,12 +3380,14 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
3364 } 3380 }
3365 3381
3366 if (tp_features.hotkey_wlsw) { 3382 if (tp_features.hotkey_wlsw) {
3367 set_bit(EV_SW, tpacpi_inputdev->evbit); 3383 input_set_capability(tpacpi_inputdev, EV_SW, SW_RFKILL_ALL);
3368 set_bit(SW_RFKILL_ALL, tpacpi_inputdev->swbit); 3384 input_report_switch(tpacpi_inputdev,
3385 SW_RFKILL_ALL, radiosw_state);
3369 } 3386 }
3370 if (tp_features.hotkey_tablet) { 3387 if (tp_features.hotkey_tablet) {
3371 set_bit(EV_SW, tpacpi_inputdev->evbit); 3388 input_set_capability(tpacpi_inputdev, EV_SW, SW_TABLET_MODE);
3372 set_bit(SW_TABLET_MODE, tpacpi_inputdev->swbit); 3389 input_report_switch(tpacpi_inputdev,
3390 SW_TABLET_MODE, tabletsw_state);
3373 } 3391 }
3374 3392
3375 /* Do not issue duplicate brightness change events to 3393 /* Do not issue duplicate brightness change events to
@@ -3436,8 +3454,6 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
3436 tpacpi_inputdev->close = &hotkey_inputdev_close; 3454 tpacpi_inputdev->close = &hotkey_inputdev_close;
3437 3455
3438 hotkey_poll_setup_safe(true); 3456 hotkey_poll_setup_safe(true);
3439 tpacpi_send_radiosw_update();
3440 tpacpi_input_send_tabletsw();
3441 3457
3442 return 0; 3458 return 0;
3443 3459
@@ -3545,49 +3561,57 @@ static bool hotkey_notify_usrevent(const u32 hkey,
3545 } 3561 }
3546} 3562}
3547 3563
3564static void thermal_dump_all_sensors(void);
3565
3548static bool hotkey_notify_thermal(const u32 hkey, 3566static bool hotkey_notify_thermal(const u32 hkey,
3549 bool *send_acpi_ev, 3567 bool *send_acpi_ev,
3550 bool *ignore_acpi_ev) 3568 bool *ignore_acpi_ev)
3551{ 3569{
3570 bool known = true;
3571
3552 /* 0x6000-0x6FFF: thermal alarms */ 3572 /* 0x6000-0x6FFF: thermal alarms */
3553 *send_acpi_ev = true; 3573 *send_acpi_ev = true;
3554 *ignore_acpi_ev = false; 3574 *ignore_acpi_ev = false;
3555 3575
3556 switch (hkey) { 3576 switch (hkey) {
3577 case TP_HKEY_EV_THM_TABLE_CHANGED:
3578 printk(TPACPI_INFO
3579 "EC reports that Thermal Table has changed\n");
3580 /* recommended action: do nothing, we don't have
3581 * Lenovo ATM information */
3582 return true;
3557 case TP_HKEY_EV_ALARM_BAT_HOT: 3583 case TP_HKEY_EV_ALARM_BAT_HOT:
3558 printk(TPACPI_CRIT 3584 printk(TPACPI_CRIT
3559 "THERMAL ALARM: battery is too hot!\n"); 3585 "THERMAL ALARM: battery is too hot!\n");
3560 /* recommended action: warn user through gui */ 3586 /* recommended action: warn user through gui */
3561 return true; 3587 break;
3562 case TP_HKEY_EV_ALARM_BAT_XHOT: 3588 case TP_HKEY_EV_ALARM_BAT_XHOT:
3563 printk(TPACPI_ALERT 3589 printk(TPACPI_ALERT
3564 "THERMAL EMERGENCY: battery is extremely hot!\n"); 3590 "THERMAL EMERGENCY: battery is extremely hot!\n");
3565 /* recommended action: immediate sleep/hibernate */ 3591 /* recommended action: immediate sleep/hibernate */
3566 return true; 3592 break;
3567 case TP_HKEY_EV_ALARM_SENSOR_HOT: 3593 case TP_HKEY_EV_ALARM_SENSOR_HOT:
3568 printk(TPACPI_CRIT 3594 printk(TPACPI_CRIT
3569 "THERMAL ALARM: " 3595 "THERMAL ALARM: "
3570 "a sensor reports something is too hot!\n"); 3596 "a sensor reports something is too hot!\n");
3571 /* recommended action: warn user through gui, that */ 3597 /* recommended action: warn user through gui, that */
3572 /* some internal component is too hot */ 3598 /* some internal component is too hot */
3573 return true; 3599 break;
3574 case TP_HKEY_EV_ALARM_SENSOR_XHOT: 3600 case TP_HKEY_EV_ALARM_SENSOR_XHOT:
3575 printk(TPACPI_ALERT 3601 printk(TPACPI_ALERT
3576 "THERMAL EMERGENCY: " 3602 "THERMAL EMERGENCY: "
3577 "a sensor reports something is extremely hot!\n"); 3603 "a sensor reports something is extremely hot!\n");
3578 /* recommended action: immediate sleep/hibernate */ 3604 /* recommended action: immediate sleep/hibernate */
3579 return true; 3605 break;
3580 case TP_HKEY_EV_THM_TABLE_CHANGED:
3581 printk(TPACPI_INFO
3582 "EC reports that Thermal Table has changed\n");
3583 /* recommended action: do nothing, we don't have
3584 * Lenovo ATM information */
3585 return true;
3586 default: 3606 default:
3587 printk(TPACPI_ALERT 3607 printk(TPACPI_ALERT
3588 "THERMAL ALERT: unknown thermal alarm received\n"); 3608 "THERMAL ALERT: unknown thermal alarm received\n");
3589 return false; 3609 known = false;
3590 } 3610 }
3611
3612 thermal_dump_all_sensors();
3613
3614 return known;
3591} 3615}
3592 3616
3593static void hotkey_notify(struct ibm_struct *ibm, u32 event) 3617static void hotkey_notify(struct ibm_struct *ibm, u32 event)
@@ -3635,13 +3659,19 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event)
3635 break; 3659 break;
3636 case 3: 3660 case 3:
3637 /* 0x3000-0x3FFF: bay-related wakeups */ 3661 /* 0x3000-0x3FFF: bay-related wakeups */
3638 if (hkey == TP_HKEY_EV_BAYEJ_ACK) { 3662 switch (hkey) {
3663 case TP_HKEY_EV_BAYEJ_ACK:
3639 hotkey_autosleep_ack = 1; 3664 hotkey_autosleep_ack = 1;
3640 printk(TPACPI_INFO 3665 printk(TPACPI_INFO
3641 "bay ejected\n"); 3666 "bay ejected\n");
3642 hotkey_wakeup_hotunplug_complete_notify_change(); 3667 hotkey_wakeup_hotunplug_complete_notify_change();
3643 known_ev = true; 3668 known_ev = true;
3644 } else { 3669 break;
3670 case TP_HKEY_EV_OPTDRV_EJ:
3671 /* FIXME: kick libata if SATA link offline */
3672 known_ev = true;
3673 break;
3674 default:
3645 known_ev = false; 3675 known_ev = false;
3646 } 3676 }
3647 break; 3677 break;
@@ -3730,14 +3760,13 @@ static void hotkey_resume(void)
3730} 3760}
3731 3761
3732/* procfs -------------------------------------------------------------- */ 3762/* procfs -------------------------------------------------------------- */
3733static int hotkey_read(char *p) 3763static int hotkey_read(struct seq_file *m)
3734{ 3764{
3735 int res, status; 3765 int res, status;
3736 int len = 0;
3737 3766
3738 if (!tp_features.hotkey) { 3767 if (!tp_features.hotkey) {
3739 len += sprintf(p + len, "status:\t\tnot supported\n"); 3768 seq_printf(m, "status:\t\tnot supported\n");
3740 return len; 3769 return 0;
3741 } 3770 }
3742 3771
3743 if (mutex_lock_killable(&hotkey_mutex)) 3772 if (mutex_lock_killable(&hotkey_mutex))
@@ -3749,17 +3778,16 @@ static int hotkey_read(char *p)
3749 if (res) 3778 if (res)
3750 return res; 3779 return res;
3751 3780
3752 len += sprintf(p + len, "status:\t\t%s\n", enabled(status, 0)); 3781 seq_printf(m, "status:\t\t%s\n", enabled(status, 0));
3753 if (hotkey_all_mask) { 3782 if (hotkey_all_mask) {
3754 len += sprintf(p + len, "mask:\t\t0x%08x\n", hotkey_user_mask); 3783 seq_printf(m, "mask:\t\t0x%08x\n", hotkey_user_mask);
3755 len += sprintf(p + len, 3784 seq_printf(m, "commands:\tenable, disable, reset, <mask>\n");
3756 "commands:\tenable, disable, reset, <mask>\n");
3757 } else { 3785 } else {
3758 len += sprintf(p + len, "mask:\t\tnot supported\n"); 3786 seq_printf(m, "mask:\t\tnot supported\n");
3759 len += sprintf(p + len, "commands:\tenable, disable, reset\n"); 3787 seq_printf(m, "commands:\tenable, disable, reset\n");
3760 } 3788 }
3761 3789
3762 return len; 3790 return 0;
3763} 3791}
3764 3792
3765static void hotkey_enabledisable_warn(bool enable) 3793static void hotkey_enabledisable_warn(bool enable)
@@ -3852,7 +3880,7 @@ enum {
3852 TP_ACPI_BLUETOOTH_HWPRESENT = 0x01, /* Bluetooth hw available */ 3880 TP_ACPI_BLUETOOTH_HWPRESENT = 0x01, /* Bluetooth hw available */
3853 TP_ACPI_BLUETOOTH_RADIOSSW = 0x02, /* Bluetooth radio enabled */ 3881 TP_ACPI_BLUETOOTH_RADIOSSW = 0x02, /* Bluetooth radio enabled */
3854 TP_ACPI_BLUETOOTH_RESUMECTRL = 0x04, /* Bluetooth state at resume: 3882 TP_ACPI_BLUETOOTH_RESUMECTRL = 0x04, /* Bluetooth state at resume:
3855 off / last state */ 3883 0 = disable, 1 = enable */
3856}; 3884};
3857 3885
3858enum { 3886enum {
@@ -3866,15 +3894,6 @@ enum {
3866 3894
3867#define TPACPI_RFK_BLUETOOTH_SW_NAME "tpacpi_bluetooth_sw" 3895#define TPACPI_RFK_BLUETOOTH_SW_NAME "tpacpi_bluetooth_sw"
3868 3896
3869static void bluetooth_suspend(pm_message_t state)
3870{
3871 /* Try to make sure radio will resume powered off */
3872 if (!acpi_evalf(NULL, NULL, "\\BLTH", "vd",
3873 TP_ACPI_BLTH_PWR_OFF_ON_RESUME))
3874 vdbg_printk(TPACPI_DBG_RFKILL,
3875 "bluetooth power down on resume request failed\n");
3876}
3877
3878static int bluetooth_get_status(void) 3897static int bluetooth_get_status(void)
3879{ 3898{
3880 int status; 3899 int status;
@@ -3907,9 +3926,9 @@ static int bluetooth_set_status(enum tpacpi_rfkill_state state)
3907 } 3926 }
3908#endif 3927#endif
3909 3928
3910 /* We make sure to keep TP_ACPI_BLUETOOTH_RESUMECTRL off */
3911 if (state == TPACPI_RFK_RADIO_ON) 3929 if (state == TPACPI_RFK_RADIO_ON)
3912 status = TP_ACPI_BLUETOOTH_RADIOSSW; 3930 status = TP_ACPI_BLUETOOTH_RADIOSSW
3931 | TP_ACPI_BLUETOOTH_RESUMECTRL;
3913 else 3932 else
3914 status = 0; 3933 status = 0;
3915 3934
@@ -4035,9 +4054,9 @@ static int __init bluetooth_init(struct ibm_init_struct *iibm)
4035} 4054}
4036 4055
4037/* procfs -------------------------------------------------------------- */ 4056/* procfs -------------------------------------------------------------- */
4038static int bluetooth_read(char *p) 4057static int bluetooth_read(struct seq_file *m)
4039{ 4058{
4040 return tpacpi_rfk_procfs_read(TPACPI_RFK_BLUETOOTH_SW_ID, p); 4059 return tpacpi_rfk_procfs_read(TPACPI_RFK_BLUETOOTH_SW_ID, m);
4041} 4060}
4042 4061
4043static int bluetooth_write(char *buf) 4062static int bluetooth_write(char *buf)
@@ -4050,7 +4069,6 @@ static struct ibm_struct bluetooth_driver_data = {
4050 .read = bluetooth_read, 4069 .read = bluetooth_read,
4051 .write = bluetooth_write, 4070 .write = bluetooth_write,
4052 .exit = bluetooth_exit, 4071 .exit = bluetooth_exit,
4053 .suspend = bluetooth_suspend,
4054 .shutdown = bluetooth_shutdown, 4072 .shutdown = bluetooth_shutdown,
4055}; 4073};
4056 4074
@@ -4063,20 +4081,11 @@ enum {
4063 TP_ACPI_WANCARD_HWPRESENT = 0x01, /* Wan hw available */ 4081 TP_ACPI_WANCARD_HWPRESENT = 0x01, /* Wan hw available */
4064 TP_ACPI_WANCARD_RADIOSSW = 0x02, /* Wan radio enabled */ 4082 TP_ACPI_WANCARD_RADIOSSW = 0x02, /* Wan radio enabled */
4065 TP_ACPI_WANCARD_RESUMECTRL = 0x04, /* Wan state at resume: 4083 TP_ACPI_WANCARD_RESUMECTRL = 0x04, /* Wan state at resume:
4066 off / last state */ 4084 0 = disable, 1 = enable */
4067}; 4085};
4068 4086
4069#define TPACPI_RFK_WWAN_SW_NAME "tpacpi_wwan_sw" 4087#define TPACPI_RFK_WWAN_SW_NAME "tpacpi_wwan_sw"
4070 4088
4071static void wan_suspend(pm_message_t state)
4072{
4073 /* Try to make sure radio will resume powered off */
4074 if (!acpi_evalf(NULL, NULL, "\\WGSV", "qvd",
4075 TP_ACPI_WGSV_PWR_OFF_ON_RESUME))
4076 vdbg_printk(TPACPI_DBG_RFKILL,
4077 "WWAN power down on resume request failed\n");
4078}
4079
4080static int wan_get_status(void) 4089static int wan_get_status(void)
4081{ 4090{
4082 int status; 4091 int status;
@@ -4109,9 +4118,9 @@ static int wan_set_status(enum tpacpi_rfkill_state state)
4109 } 4118 }
4110#endif 4119#endif
4111 4120
4112 /* We make sure to keep TP_ACPI_WANCARD_RESUMECTRL off */
4113 if (state == TPACPI_RFK_RADIO_ON) 4121 if (state == TPACPI_RFK_RADIO_ON)
4114 status = TP_ACPI_WANCARD_RADIOSSW; 4122 status = TP_ACPI_WANCARD_RADIOSSW
4123 | TP_ACPI_WANCARD_RESUMECTRL;
4115 else 4124 else
4116 status = 0; 4125 status = 0;
4117 4126
@@ -4236,9 +4245,9 @@ static int __init wan_init(struct ibm_init_struct *iibm)
4236} 4245}
4237 4246
4238/* procfs -------------------------------------------------------------- */ 4247/* procfs -------------------------------------------------------------- */
4239static int wan_read(char *p) 4248static int wan_read(struct seq_file *m)
4240{ 4249{
4241 return tpacpi_rfk_procfs_read(TPACPI_RFK_WWAN_SW_ID, p); 4250 return tpacpi_rfk_procfs_read(TPACPI_RFK_WWAN_SW_ID, m);
4242} 4251}
4243 4252
4244static int wan_write(char *buf) 4253static int wan_write(char *buf)
@@ -4251,7 +4260,6 @@ static struct ibm_struct wan_driver_data = {
4251 .read = wan_read, 4260 .read = wan_read,
4252 .write = wan_write, 4261 .write = wan_write,
4253 .exit = wan_exit, 4262 .exit = wan_exit,
4254 .suspend = wan_suspend,
4255 .shutdown = wan_shutdown, 4263 .shutdown = wan_shutdown,
4256}; 4264};
4257 4265
@@ -4614,16 +4622,19 @@ static int video_expand_toggle(void)
4614 /* not reached */ 4622 /* not reached */
4615} 4623}
4616 4624
4617static int video_read(char *p) 4625static int video_read(struct seq_file *m)
4618{ 4626{
4619 int status, autosw; 4627 int status, autosw;
4620 int len = 0;
4621 4628
4622 if (video_supported == TPACPI_VIDEO_NONE) { 4629 if (video_supported == TPACPI_VIDEO_NONE) {
4623 len += sprintf(p + len, "status:\t\tnot supported\n"); 4630 seq_printf(m, "status:\t\tnot supported\n");
4624 return len; 4631 return 0;
4625 } 4632 }
4626 4633
4634 /* Even reads can crash X.org, so... */
4635 if (!capable(CAP_SYS_ADMIN))
4636 return -EPERM;
4637
4627 status = video_outputsw_get(); 4638 status = video_outputsw_get();
4628 if (status < 0) 4639 if (status < 0)
4629 return status; 4640 return status;
@@ -4632,20 +4643,20 @@ static int video_read(char *p)
4632 if (autosw < 0) 4643 if (autosw < 0)
4633 return autosw; 4644 return autosw;
4634 4645
4635 len += sprintf(p + len, "status:\t\tsupported\n"); 4646 seq_printf(m, "status:\t\tsupported\n");
4636 len += sprintf(p + len, "lcd:\t\t%s\n", enabled(status, 0)); 4647 seq_printf(m, "lcd:\t\t%s\n", enabled(status, 0));
4637 len += sprintf(p + len, "crt:\t\t%s\n", enabled(status, 1)); 4648 seq_printf(m, "crt:\t\t%s\n", enabled(status, 1));
4638 if (video_supported == TPACPI_VIDEO_NEW) 4649 if (video_supported == TPACPI_VIDEO_NEW)
4639 len += sprintf(p + len, "dvi:\t\t%s\n", enabled(status, 3)); 4650 seq_printf(m, "dvi:\t\t%s\n", enabled(status, 3));
4640 len += sprintf(p + len, "auto:\t\t%s\n", enabled(autosw, 0)); 4651 seq_printf(m, "auto:\t\t%s\n", enabled(autosw, 0));
4641 len += sprintf(p + len, "commands:\tlcd_enable, lcd_disable\n"); 4652 seq_printf(m, "commands:\tlcd_enable, lcd_disable\n");
4642 len += sprintf(p + len, "commands:\tcrt_enable, crt_disable\n"); 4653 seq_printf(m, "commands:\tcrt_enable, crt_disable\n");
4643 if (video_supported == TPACPI_VIDEO_NEW) 4654 if (video_supported == TPACPI_VIDEO_NEW)
4644 len += sprintf(p + len, "commands:\tdvi_enable, dvi_disable\n"); 4655 seq_printf(m, "commands:\tdvi_enable, dvi_disable\n");
4645 len += sprintf(p + len, "commands:\tauto_enable, auto_disable\n"); 4656 seq_printf(m, "commands:\tauto_enable, auto_disable\n");
4646 len += sprintf(p + len, "commands:\tvideo_switch, expand_toggle\n"); 4657 seq_printf(m, "commands:\tvideo_switch, expand_toggle\n");
4647 4658
4648 return len; 4659 return 0;
4649} 4660}
4650 4661
4651static int video_write(char *buf) 4662static int video_write(char *buf)
@@ -4657,6 +4668,10 @@ static int video_write(char *buf)
4657 if (video_supported == TPACPI_VIDEO_NONE) 4668 if (video_supported == TPACPI_VIDEO_NONE)
4658 return -ENODEV; 4669 return -ENODEV;
4659 4670
4671 /* Even reads can crash X.org, let alone writes... */
4672 if (!capable(CAP_SYS_ADMIN))
4673 return -EPERM;
4674
4660 enable = 0; 4675 enable = 0;
4661 disable = 0; 4676 disable = 0;
4662 4677
@@ -4837,25 +4852,24 @@ static void light_exit(void)
4837 flush_workqueue(tpacpi_wq); 4852 flush_workqueue(tpacpi_wq);
4838} 4853}
4839 4854
4840static int light_read(char *p) 4855static int light_read(struct seq_file *m)
4841{ 4856{
4842 int len = 0;
4843 int status; 4857 int status;
4844 4858
4845 if (!tp_features.light) { 4859 if (!tp_features.light) {
4846 len += sprintf(p + len, "status:\t\tnot supported\n"); 4860 seq_printf(m, "status:\t\tnot supported\n");
4847 } else if (!tp_features.light_status) { 4861 } else if (!tp_features.light_status) {
4848 len += sprintf(p + len, "status:\t\tunknown\n"); 4862 seq_printf(m, "status:\t\tunknown\n");
4849 len += sprintf(p + len, "commands:\ton, off\n"); 4863 seq_printf(m, "commands:\ton, off\n");
4850 } else { 4864 } else {
4851 status = light_get_status(); 4865 status = light_get_status();
4852 if (status < 0) 4866 if (status < 0)
4853 return status; 4867 return status;
4854 len += sprintf(p + len, "status:\t\t%s\n", onoff(status, 0)); 4868 seq_printf(m, "status:\t\t%s\n", onoff(status, 0));
4855 len += sprintf(p + len, "commands:\ton, off\n"); 4869 seq_printf(m, "commands:\ton, off\n");
4856 } 4870 }
4857 4871
4858 return len; 4872 return 0;
4859} 4873}
4860 4874
4861static int light_write(char *buf) 4875static int light_write(char *buf)
@@ -4933,20 +4947,18 @@ static void cmos_exit(void)
4933 device_remove_file(&tpacpi_pdev->dev, &dev_attr_cmos_command); 4947 device_remove_file(&tpacpi_pdev->dev, &dev_attr_cmos_command);
4934} 4948}
4935 4949
4936static int cmos_read(char *p) 4950static int cmos_read(struct seq_file *m)
4937{ 4951{
4938 int len = 0;
4939
4940 /* cmos not supported on 570, 600e/x, 770e, 770x, A21e, A2xm/p, 4952 /* cmos not supported on 570, 600e/x, 770e, 770x, A21e, A2xm/p,
4941 R30, R31, T20-22, X20-21 */ 4953 R30, R31, T20-22, X20-21 */
4942 if (!cmos_handle) 4954 if (!cmos_handle)
4943 len += sprintf(p + len, "status:\t\tnot supported\n"); 4955 seq_printf(m, "status:\t\tnot supported\n");
4944 else { 4956 else {
4945 len += sprintf(p + len, "status:\t\tsupported\n"); 4957 seq_printf(m, "status:\t\tsupported\n");
4946 len += sprintf(p + len, "commands:\t<cmd> (<cmd> is 0-21)\n"); 4958 seq_printf(m, "commands:\t<cmd> (<cmd> is 0-21)\n");
4947 } 4959 }
4948 4960
4949 return len; 4961 return 0;
4950} 4962}
4951 4963
4952static int cmos_write(char *buf) 4964static int cmos_write(char *buf)
@@ -5321,15 +5333,13 @@ static int __init led_init(struct ibm_init_struct *iibm)
5321 ((s) == TPACPI_LED_OFF ? "off" : \ 5333 ((s) == TPACPI_LED_OFF ? "off" : \
5322 ((s) == TPACPI_LED_ON ? "on" : "blinking")) 5334 ((s) == TPACPI_LED_ON ? "on" : "blinking"))
5323 5335
5324static int led_read(char *p) 5336static int led_read(struct seq_file *m)
5325{ 5337{
5326 int len = 0;
5327
5328 if (!led_supported) { 5338 if (!led_supported) {
5329 len += sprintf(p + len, "status:\t\tnot supported\n"); 5339 seq_printf(m, "status:\t\tnot supported\n");
5330 return len; 5340 return 0;
5331 } 5341 }
5332 len += sprintf(p + len, "status:\t\tsupported\n"); 5342 seq_printf(m, "status:\t\tsupported\n");
5333 5343
5334 if (led_supported == TPACPI_LED_570) { 5344 if (led_supported == TPACPI_LED_570) {
5335 /* 570 */ 5345 /* 570 */
@@ -5338,15 +5348,15 @@ static int led_read(char *p)
5338 status = led_get_status(i); 5348 status = led_get_status(i);
5339 if (status < 0) 5349 if (status < 0)
5340 return -EIO; 5350 return -EIO;
5341 len += sprintf(p + len, "%d:\t\t%s\n", 5351 seq_printf(m, "%d:\t\t%s\n",
5342 i, str_led_status(status)); 5352 i, str_led_status(status));
5343 } 5353 }
5344 } 5354 }
5345 5355
5346 len += sprintf(p + len, "commands:\t" 5356 seq_printf(m, "commands:\t"
5347 "<led> on, <led> off, <led> blink (<led> is 0-15)\n"); 5357 "<led> on, <led> off, <led> blink (<led> is 0-15)\n");
5348 5358
5349 return len; 5359 return 0;
5350} 5360}
5351 5361
5352static int led_write(char *buf) 5362static int led_write(char *buf)
@@ -5419,18 +5429,16 @@ static int __init beep_init(struct ibm_init_struct *iibm)
5419 return (beep_handle)? 0 : 1; 5429 return (beep_handle)? 0 : 1;
5420} 5430}
5421 5431
5422static int beep_read(char *p) 5432static int beep_read(struct seq_file *m)
5423{ 5433{
5424 int len = 0;
5425
5426 if (!beep_handle) 5434 if (!beep_handle)
5427 len += sprintf(p + len, "status:\t\tnot supported\n"); 5435 seq_printf(m, "status:\t\tnot supported\n");
5428 else { 5436 else {
5429 len += sprintf(p + len, "status:\t\tsupported\n"); 5437 seq_printf(m, "status:\t\tsupported\n");
5430 len += sprintf(p + len, "commands:\t<cmd> (<cmd> is 0-17)\n"); 5438 seq_printf(m, "commands:\t<cmd> (<cmd> is 0-17)\n");
5431 } 5439 }
5432 5440
5433 return len; 5441 return 0;
5434} 5442}
5435 5443
5436static int beep_write(char *buf) 5444static int beep_write(char *buf)
@@ -5483,8 +5491,11 @@ enum { /* TPACPI_THERMAL_TPEC_* */
5483 TP_EC_THERMAL_TMP0 = 0x78, /* ACPI EC regs TMP 0..7 */ 5491 TP_EC_THERMAL_TMP0 = 0x78, /* ACPI EC regs TMP 0..7 */
5484 TP_EC_THERMAL_TMP8 = 0xC0, /* ACPI EC regs TMP 8..15 */ 5492 TP_EC_THERMAL_TMP8 = 0xC0, /* ACPI EC regs TMP 8..15 */
5485 TP_EC_THERMAL_TMP_NA = -128, /* ACPI EC sensor not available */ 5493 TP_EC_THERMAL_TMP_NA = -128, /* ACPI EC sensor not available */
5494
5495 TPACPI_THERMAL_SENSOR_NA = -128000, /* Sensor not available */
5486}; 5496};
5487 5497
5498
5488#define TPACPI_MAX_THERMAL_SENSORS 16 /* Max thermal sensors supported */ 5499#define TPACPI_MAX_THERMAL_SENSORS 16 /* Max thermal sensors supported */
5489struct ibm_thermal_sensors_struct { 5500struct ibm_thermal_sensors_struct {
5490 s32 temp[TPACPI_MAX_THERMAL_SENSORS]; 5501 s32 temp[TPACPI_MAX_THERMAL_SENSORS];
@@ -5574,6 +5585,28 @@ static int thermal_get_sensors(struct ibm_thermal_sensors_struct *s)
5574 return n; 5585 return n;
5575} 5586}
5576 5587
5588static void thermal_dump_all_sensors(void)
5589{
5590 int n, i;
5591 struct ibm_thermal_sensors_struct t;
5592
5593 n = thermal_get_sensors(&t);
5594 if (n <= 0)
5595 return;
5596
5597 printk(TPACPI_NOTICE
5598 "temperatures (Celsius):");
5599
5600 for (i = 0; i < n; i++) {
5601 if (t.temp[i] != TPACPI_THERMAL_SENSOR_NA)
5602 printk(KERN_CONT " %d", (int)(t.temp[i] / 1000));
5603 else
5604 printk(KERN_CONT " N/A");
5605 }
5606
5607 printk(KERN_CONT "\n");
5608}
5609
5577/* sysfs temp##_input -------------------------------------------------- */ 5610/* sysfs temp##_input -------------------------------------------------- */
5578 5611
5579static ssize_t thermal_temp_input_show(struct device *dev, 5612static ssize_t thermal_temp_input_show(struct device *dev,
@@ -5589,7 +5622,7 @@ static ssize_t thermal_temp_input_show(struct device *dev,
5589 res = thermal_get_sensor(idx, &value); 5622 res = thermal_get_sensor(idx, &value);
5590 if (res) 5623 if (res)
5591 return res; 5624 return res;
5592 if (value == TP_EC_THERMAL_TMP_NA * 1000) 5625 if (value == TPACPI_THERMAL_SENSOR_NA)
5593 return -ENXIO; 5626 return -ENXIO;
5594 5627
5595 return snprintf(buf, PAGE_SIZE, "%d\n", value); 5628 return snprintf(buf, PAGE_SIZE, "%d\n", value);
@@ -5758,7 +5791,7 @@ static void thermal_exit(void)
5758 case TPACPI_THERMAL_ACPI_TMP07: 5791 case TPACPI_THERMAL_ACPI_TMP07:
5759 case TPACPI_THERMAL_ACPI_UPDT: 5792 case TPACPI_THERMAL_ACPI_UPDT:
5760 sysfs_remove_group(&tpacpi_sensors_pdev->dev.kobj, 5793 sysfs_remove_group(&tpacpi_sensors_pdev->dev.kobj,
5761 &thermal_temp_input16_group); 5794 &thermal_temp_input8_group);
5762 break; 5795 break;
5763 case TPACPI_THERMAL_NONE: 5796 case TPACPI_THERMAL_NONE:
5764 default: 5797 default:
@@ -5766,9 +5799,8 @@ static void thermal_exit(void)
5766 } 5799 }
5767} 5800}
5768 5801
5769static int thermal_read(char *p) 5802static int thermal_read(struct seq_file *m)
5770{ 5803{
5771 int len = 0;
5772 int n, i; 5804 int n, i;
5773 struct ibm_thermal_sensors_struct t; 5805 struct ibm_thermal_sensors_struct t;
5774 5806
@@ -5776,16 +5808,16 @@ static int thermal_read(char *p)
5776 if (unlikely(n < 0)) 5808 if (unlikely(n < 0))
5777 return n; 5809 return n;
5778 5810
5779 len += sprintf(p + len, "temperatures:\t"); 5811 seq_printf(m, "temperatures:\t");
5780 5812
5781 if (n > 0) { 5813 if (n > 0) {
5782 for (i = 0; i < (n - 1); i++) 5814 for (i = 0; i < (n - 1); i++)
5783 len += sprintf(p + len, "%d ", t.temp[i] / 1000); 5815 seq_printf(m, "%d ", t.temp[i] / 1000);
5784 len += sprintf(p + len, "%d\n", t.temp[i] / 1000); 5816 seq_printf(m, "%d\n", t.temp[i] / 1000);
5785 } else 5817 } else
5786 len += sprintf(p + len, "not supported\n"); 5818 seq_printf(m, "not supported\n");
5787 5819
5788 return len; 5820 return 0;
5789} 5821}
5790 5822
5791static struct ibm_struct thermal_driver_data = { 5823static struct ibm_struct thermal_driver_data = {
@@ -5800,39 +5832,38 @@ static struct ibm_struct thermal_driver_data = {
5800 5832
5801static u8 ecdump_regs[256]; 5833static u8 ecdump_regs[256];
5802 5834
5803static int ecdump_read(char *p) 5835static int ecdump_read(struct seq_file *m)
5804{ 5836{
5805 int len = 0;
5806 int i, j; 5837 int i, j;
5807 u8 v; 5838 u8 v;
5808 5839
5809 len += sprintf(p + len, "EC " 5840 seq_printf(m, "EC "
5810 " +00 +01 +02 +03 +04 +05 +06 +07" 5841 " +00 +01 +02 +03 +04 +05 +06 +07"
5811 " +08 +09 +0a +0b +0c +0d +0e +0f\n"); 5842 " +08 +09 +0a +0b +0c +0d +0e +0f\n");
5812 for (i = 0; i < 256; i += 16) { 5843 for (i = 0; i < 256; i += 16) {
5813 len += sprintf(p + len, "EC 0x%02x:", i); 5844 seq_printf(m, "EC 0x%02x:", i);
5814 for (j = 0; j < 16; j++) { 5845 for (j = 0; j < 16; j++) {
5815 if (!acpi_ec_read(i + j, &v)) 5846 if (!acpi_ec_read(i + j, &v))
5816 break; 5847 break;
5817 if (v != ecdump_regs[i + j]) 5848 if (v != ecdump_regs[i + j])
5818 len += sprintf(p + len, " *%02x", v); 5849 seq_printf(m, " *%02x", v);
5819 else 5850 else
5820 len += sprintf(p + len, " %02x", v); 5851 seq_printf(m, " %02x", v);
5821 ecdump_regs[i + j] = v; 5852 ecdump_regs[i + j] = v;
5822 } 5853 }
5823 len += sprintf(p + len, "\n"); 5854 seq_putc(m, '\n');
5824 if (j != 16) 5855 if (j != 16)
5825 break; 5856 break;
5826 } 5857 }
5827 5858
5828 /* These are way too dangerous to advertise openly... */ 5859 /* These are way too dangerous to advertise openly... */
5829#if 0 5860#if 0
5830 len += sprintf(p + len, "commands:\t0x<offset> 0x<value>" 5861 seq_printf(m, "commands:\t0x<offset> 0x<value>"
5831 " (<offset> is 00-ff, <value> is 00-ff)\n"); 5862 " (<offset> is 00-ff, <value> is 00-ff)\n");
5832 len += sprintf(p + len, "commands:\t0x<offset> <value> " 5863 seq_printf(m, "commands:\t0x<offset> <value> "
5833 " (<offset> is 00-ff, <value> is 0-255)\n"); 5864 " (<offset> is 00-ff, <value> is 0-255)\n");
5834#endif 5865#endif
5835 return len; 5866 return 0;
5836} 5867}
5837 5868
5838static int ecdump_write(char *buf) 5869static int ecdump_write(char *buf)
@@ -6095,6 +6126,12 @@ static int brightness_get(struct backlight_device *bd)
6095 return status & TP_EC_BACKLIGHT_LVLMSK; 6126 return status & TP_EC_BACKLIGHT_LVLMSK;
6096} 6127}
6097 6128
6129static void tpacpi_brightness_notify_change(void)
6130{
6131 backlight_force_update(ibm_backlight_device,
6132 BACKLIGHT_UPDATE_HOTKEY);
6133}
6134
6098static struct backlight_ops ibm_backlight_data = { 6135static struct backlight_ops ibm_backlight_data = {
6099 .get_brightness = brightness_get, 6136 .get_brightness = brightness_get,
6100 .update_status = brightness_update_status, 6137 .update_status = brightness_update_status,
@@ -6116,15 +6153,15 @@ static const struct tpacpi_quirk brightness_quirk_table[] __initconst = {
6116 TPACPI_Q_IBM('1', 'Y', TPACPI_BRGHT_Q_EC), /* T43/p ATI */ 6153 TPACPI_Q_IBM('1', 'Y', TPACPI_BRGHT_Q_EC), /* T43/p ATI */
6117 6154
6118 /* Models with ATI GPUs that can use ECNVRAM */ 6155 /* Models with ATI GPUs that can use ECNVRAM */
6119 TPACPI_Q_IBM('1', 'R', TPACPI_BRGHT_Q_EC), 6156 TPACPI_Q_IBM('1', 'R', TPACPI_BRGHT_Q_EC), /* R50,51 T40-42 */
6120 TPACPI_Q_IBM('1', 'Q', TPACPI_BRGHT_Q_ASK|TPACPI_BRGHT_Q_EC), 6157 TPACPI_Q_IBM('1', 'Q', TPACPI_BRGHT_Q_ASK|TPACPI_BRGHT_Q_EC),
6121 TPACPI_Q_IBM('7', '6', TPACPI_BRGHT_Q_ASK|TPACPI_BRGHT_Q_EC), 6158 TPACPI_Q_IBM('7', '6', TPACPI_BRGHT_Q_EC), /* R52 */
6122 TPACPI_Q_IBM('7', '8', TPACPI_BRGHT_Q_ASK|TPACPI_BRGHT_Q_EC), 6159 TPACPI_Q_IBM('7', '8', TPACPI_BRGHT_Q_ASK|TPACPI_BRGHT_Q_EC),
6123 6160
6124 /* Models with Intel Extreme Graphics 2 */ 6161 /* Models with Intel Extreme Graphics 2 */
6125 TPACPI_Q_IBM('1', 'U', TPACPI_BRGHT_Q_NOEC), 6162 TPACPI_Q_IBM('1', 'U', TPACPI_BRGHT_Q_NOEC), /* X40 */
6126 TPACPI_Q_IBM('1', 'V', TPACPI_BRGHT_Q_ASK|TPACPI_BRGHT_Q_NOEC), 6163 TPACPI_Q_IBM('1', 'V', TPACPI_BRGHT_Q_ASK|TPACPI_BRGHT_Q_EC),
6127 TPACPI_Q_IBM('1', 'W', TPACPI_BRGHT_Q_ASK|TPACPI_BRGHT_Q_NOEC), 6164 TPACPI_Q_IBM('1', 'W', TPACPI_BRGHT_Q_ASK|TPACPI_BRGHT_Q_EC),
6128 6165
6129 /* Models with Intel GMA900 */ 6166 /* Models with Intel GMA900 */
6130 TPACPI_Q_IBM('7', '0', TPACPI_BRGHT_Q_NOEC), /* T43, R52 */ 6167 TPACPI_Q_IBM('7', '0', TPACPI_BRGHT_Q_NOEC), /* T43, R52 */
@@ -6134,6 +6171,7 @@ static const struct tpacpi_quirk brightness_quirk_table[] __initconst = {
6134 6171
6135static int __init brightness_init(struct ibm_init_struct *iibm) 6172static int __init brightness_init(struct ibm_init_struct *iibm)
6136{ 6173{
6174 struct backlight_properties props;
6137 int b; 6175 int b;
6138 unsigned long quirks; 6176 unsigned long quirks;
6139 6177
@@ -6223,9 +6261,12 @@ static int __init brightness_init(struct ibm_init_struct *iibm)
6223 printk(TPACPI_INFO 6261 printk(TPACPI_INFO
6224 "detected a 16-level brightness capable ThinkPad\n"); 6262 "detected a 16-level brightness capable ThinkPad\n");
6225 6263
6226 ibm_backlight_device = backlight_device_register( 6264 memset(&props, 0, sizeof(struct backlight_properties));
6227 TPACPI_BACKLIGHT_DEV_NAME, NULL, NULL, 6265 props.max_brightness = (tp_features.bright_16levels) ? 15 : 7;
6228 &ibm_backlight_data); 6266 ibm_backlight_device = backlight_device_register(TPACPI_BACKLIGHT_DEV_NAME,
6267 NULL, NULL,
6268 &ibm_backlight_data,
6269 &props);
6229 if (IS_ERR(ibm_backlight_device)) { 6270 if (IS_ERR(ibm_backlight_device)) {
6230 int rc = PTR_ERR(ibm_backlight_device); 6271 int rc = PTR_ERR(ibm_backlight_device);
6231 ibm_backlight_device = NULL; 6272 ibm_backlight_device = NULL;
@@ -6244,11 +6285,15 @@ static int __init brightness_init(struct ibm_init_struct *iibm)
6244 "or not on your ThinkPad\n", TPACPI_MAIL); 6285 "or not on your ThinkPad\n", TPACPI_MAIL);
6245 } 6286 }
6246 6287
6247 ibm_backlight_device->props.max_brightness =
6248 (tp_features.bright_16levels)? 15 : 7;
6249 ibm_backlight_device->props.brightness = b & TP_EC_BACKLIGHT_LVLMSK; 6288 ibm_backlight_device->props.brightness = b & TP_EC_BACKLIGHT_LVLMSK;
6250 backlight_update_status(ibm_backlight_device); 6289 backlight_update_status(ibm_backlight_device);
6251 6290
6291 vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_BRGHT,
6292 "brightness: registering brightness hotkeys "
6293 "as change notification\n");
6294 tpacpi_hotkey_driver_mask_set(hotkey_driver_mask
6295 | TP_ACPI_HKEY_BRGHTUP_MASK
6296 | TP_ACPI_HKEY_BRGHTDWN_MASK);;
6252 return 0; 6297 return 0;
6253} 6298}
6254 6299
@@ -6273,23 +6318,22 @@ static void brightness_exit(void)
6273 tpacpi_brightness_checkpoint_nvram(); 6318 tpacpi_brightness_checkpoint_nvram();
6274} 6319}
6275 6320
6276static int brightness_read(char *p) 6321static int brightness_read(struct seq_file *m)
6277{ 6322{
6278 int len = 0;
6279 int level; 6323 int level;
6280 6324
6281 level = brightness_get(NULL); 6325 level = brightness_get(NULL);
6282 if (level < 0) { 6326 if (level < 0) {
6283 len += sprintf(p + len, "level:\t\tunreadable\n"); 6327 seq_printf(m, "level:\t\tunreadable\n");
6284 } else { 6328 } else {
6285 len += sprintf(p + len, "level:\t\t%d\n", level); 6329 seq_printf(m, "level:\t\t%d\n", level);
6286 len += sprintf(p + len, "commands:\tup, down\n"); 6330 seq_printf(m, "commands:\tup, down\n");
6287 len += sprintf(p + len, "commands:\tlevel <level>" 6331 seq_printf(m, "commands:\tlevel <level>"
6288 " (<level> is 0-%d)\n", 6332 " (<level> is 0-%d)\n",
6289 (tp_features.bright_16levels) ? 15 : 7); 6333 (tp_features.bright_16levels) ? 15 : 7);
6290 } 6334 }
6291 6335
6292 return len; 6336 return 0;
6293} 6337}
6294 6338
6295static int brightness_write(char *buf) 6339static int brightness_write(char *buf)
@@ -6325,6 +6369,9 @@ static int brightness_write(char *buf)
6325 * Doing it this way makes the syscall restartable in case of EINTR 6369 * Doing it this way makes the syscall restartable in case of EINTR
6326 */ 6370 */
6327 rc = brightness_set(level); 6371 rc = brightness_set(level);
6372 if (!rc && ibm_backlight_device)
6373 backlight_force_update(ibm_backlight_device,
6374 BACKLIGHT_UPDATE_SYSFS);
6328 return (rc == -EINTR)? -ERESTARTSYS : rc; 6375 return (rc == -EINTR)? -ERESTARTSYS : rc;
6329} 6376}
6330 6377
@@ -6341,101 +6388,704 @@ static struct ibm_struct brightness_driver_data = {
6341 * Volume subdriver 6388 * Volume subdriver
6342 */ 6389 */
6343 6390
6344static int volume_offset = 0x30; 6391/*
6392 * IBM ThinkPads have a simple volume controller with MUTE gating.
6393 * Very early Lenovo ThinkPads follow the IBM ThinkPad spec.
6394 *
6395 * Since the *61 series (and probably also the later *60 series), Lenovo
6396 * ThinkPads only implement the MUTE gate.
6397 *
6398 * EC register 0x30
6399 * Bit 6: MUTE (1 mutes sound)
6400 * Bit 3-0: Volume
6401 * Other bits should be zero as far as we know.
6402 *
6403 * This is also stored in CMOS NVRAM, byte 0x60, bit 6 (MUTE), and
6404 * bits 3-0 (volume). Other bits in NVRAM may have other functions,
6405 * such as bit 7 which is used to detect repeated presses of MUTE,
6406 * and we leave them unchanged.
6407 */
6408
6409#ifdef CONFIG_THINKPAD_ACPI_ALSA_SUPPORT
6410
6411#define TPACPI_ALSA_DRVNAME "ThinkPad EC"
6412#define TPACPI_ALSA_SHRTNAME "ThinkPad Console Audio Control"
6413#define TPACPI_ALSA_MIXERNAME TPACPI_ALSA_SHRTNAME
6345 6414
6346static int volume_read(char *p) 6415static int alsa_index = ~((1 << (SNDRV_CARDS - 3)) - 1); /* last three slots */
6416static char *alsa_id = "ThinkPadEC";
6417static int alsa_enable = SNDRV_DEFAULT_ENABLE1;
6418
6419struct tpacpi_alsa_data {
6420 struct snd_card *card;
6421 struct snd_ctl_elem_id *ctl_mute_id;
6422 struct snd_ctl_elem_id *ctl_vol_id;
6423};
6424
6425static struct snd_card *alsa_card;
6426
6427enum {
6428 TP_EC_AUDIO = 0x30,
6429
6430 /* TP_EC_AUDIO bits */
6431 TP_EC_AUDIO_MUTESW = 6,
6432
6433 /* TP_EC_AUDIO bitmasks */
6434 TP_EC_AUDIO_LVL_MSK = 0x0F,
6435 TP_EC_AUDIO_MUTESW_MSK = (1 << TP_EC_AUDIO_MUTESW),
6436
6437 /* Maximum volume */
6438 TP_EC_VOLUME_MAX = 14,
6439};
6440
6441enum tpacpi_volume_access_mode {
6442 TPACPI_VOL_MODE_AUTO = 0, /* Not implemented yet */
6443 TPACPI_VOL_MODE_EC, /* Pure EC control */
6444 TPACPI_VOL_MODE_UCMS_STEP, /* UCMS step-based control: N/A */
6445 TPACPI_VOL_MODE_ECNVRAM, /* EC control w/ NVRAM store */
6446 TPACPI_VOL_MODE_MAX
6447};
6448
6449enum tpacpi_volume_capabilities {
6450 TPACPI_VOL_CAP_AUTO = 0, /* Use white/blacklist */
6451 TPACPI_VOL_CAP_VOLMUTE, /* Output vol and mute */
6452 TPACPI_VOL_CAP_MUTEONLY, /* Output mute only */
6453 TPACPI_VOL_CAP_MAX
6454};
6455
6456static enum tpacpi_volume_access_mode volume_mode =
6457 TPACPI_VOL_MODE_MAX;
6458
6459static enum tpacpi_volume_capabilities volume_capabilities;
6460static int volume_control_allowed;
6461
6462/*
6463 * Used to syncronize writers to TP_EC_AUDIO and
6464 * TP_NVRAM_ADDR_MIXER, as we need to do read-modify-write
6465 */
6466static struct mutex volume_mutex;
6467
6468static void tpacpi_volume_checkpoint_nvram(void)
6347{ 6469{
6348 int len = 0; 6470 u8 lec = 0;
6349 u8 level; 6471 u8 b_nvram;
6472 u8 ec_mask;
6473
6474 if (volume_mode != TPACPI_VOL_MODE_ECNVRAM)
6475 return;
6476 if (!volume_control_allowed)
6477 return;
6478
6479 vdbg_printk(TPACPI_DBG_MIXER,
6480 "trying to checkpoint mixer state to NVRAM...\n");
6481
6482 if (tp_features.mixer_no_level_control)
6483 ec_mask = TP_EC_AUDIO_MUTESW_MSK;
6484 else
6485 ec_mask = TP_EC_AUDIO_MUTESW_MSK | TP_EC_AUDIO_LVL_MSK;
6486
6487 if (mutex_lock_killable(&volume_mutex) < 0)
6488 return;
6350 6489
6351 if (!acpi_ec_read(volume_offset, &level)) { 6490 if (unlikely(!acpi_ec_read(TP_EC_AUDIO, &lec)))
6352 len += sprintf(p + len, "level:\t\tunreadable\n"); 6491 goto unlock;
6492 lec &= ec_mask;
6493 b_nvram = nvram_read_byte(TP_NVRAM_ADDR_MIXER);
6494
6495 if (lec != (b_nvram & ec_mask)) {
6496 /* NVRAM needs update */
6497 b_nvram &= ~ec_mask;
6498 b_nvram |= lec;
6499 nvram_write_byte(b_nvram, TP_NVRAM_ADDR_MIXER);
6500 dbg_printk(TPACPI_DBG_MIXER,
6501 "updated NVRAM mixer status to 0x%02x (0x%02x)\n",
6502 (unsigned int) lec, (unsigned int) b_nvram);
6353 } else { 6503 } else {
6354 len += sprintf(p + len, "level:\t\t%d\n", level & 0xf); 6504 vdbg_printk(TPACPI_DBG_MIXER,
6355 len += sprintf(p + len, "mute:\t\t%s\n", onoff(level, 6)); 6505 "NVRAM mixer status already is 0x%02x (0x%02x)\n",
6356 len += sprintf(p + len, "commands:\tup, down, mute\n"); 6506 (unsigned int) lec, (unsigned int) b_nvram);
6357 len += sprintf(p + len, "commands:\tlevel <level>"
6358 " (<level> is 0-15)\n");
6359 } 6507 }
6360 6508
6361 return len; 6509unlock:
6510 mutex_unlock(&volume_mutex);
6362} 6511}
6363 6512
6364static int volume_write(char *buf) 6513static int volume_get_status_ec(u8 *status)
6365{ 6514{
6366 int cmos_cmd, inc, i; 6515 u8 s;
6367 u8 level, mute;
6368 int new_level, new_mute;
6369 char *cmd;
6370 6516
6371 while ((cmd = next_cmd(&buf))) { 6517 if (!acpi_ec_read(TP_EC_AUDIO, &s))
6372 if (!acpi_ec_read(volume_offset, &level)) 6518 return -EIO;
6373 return -EIO;
6374 new_mute = mute = level & 0x40;
6375 new_level = level = level & 0xf;
6376 6519
6377 if (strlencmp(cmd, "up") == 0) { 6520 *status = s;
6378 if (mute)
6379 new_mute = 0;
6380 else
6381 new_level = level == 15 ? 15 : level + 1;
6382 } else if (strlencmp(cmd, "down") == 0) {
6383 if (mute)
6384 new_mute = 0;
6385 else
6386 new_level = level == 0 ? 0 : level - 1;
6387 } else if (sscanf(cmd, "level %d", &new_level) == 1 &&
6388 new_level >= 0 && new_level <= 15) {
6389 /* new_level set */
6390 } else if (strlencmp(cmd, "mute") == 0) {
6391 new_mute = 0x40;
6392 } else
6393 return -EINVAL;
6394 6521
6395 if (new_level != level) { 6522 dbg_printk(TPACPI_DBG_MIXER, "status 0x%02x\n", s);
6396 /* mute doesn't change */
6397 6523
6398 cmos_cmd = (new_level > level) ? 6524 return 0;
6399 TP_CMOS_VOLUME_UP : TP_CMOS_VOLUME_DOWN; 6525}
6400 inc = new_level > level ? 1 : -1;
6401 6526
6402 if (mute && (issue_thinkpad_cmos_command(cmos_cmd) || 6527static int volume_get_status(u8 *status)
6403 !acpi_ec_write(volume_offset, level))) 6528{
6404 return -EIO; 6529 return volume_get_status_ec(status);
6530}
6405 6531
6406 for (i = level; i != new_level; i += inc) 6532static int volume_set_status_ec(const u8 status)
6407 if (issue_thinkpad_cmos_command(cmos_cmd) || 6533{
6408 !acpi_ec_write(volume_offset, i + inc)) 6534 if (!acpi_ec_write(TP_EC_AUDIO, status))
6409 return -EIO; 6535 return -EIO;
6410 6536
6411 if (mute && 6537 dbg_printk(TPACPI_DBG_MIXER, "set EC mixer to 0x%02x\n", status);
6412 (issue_thinkpad_cmos_command(TP_CMOS_VOLUME_MUTE) || 6538
6413 !acpi_ec_write(volume_offset, new_level + mute))) { 6539 return 0;
6414 return -EIO; 6540}
6415 } 6541
6542static int volume_set_status(const u8 status)
6543{
6544 return volume_set_status_ec(status);
6545}
6546
6547/* returns < 0 on error, 0 on no change, 1 on change */
6548static int __volume_set_mute_ec(const bool mute)
6549{
6550 int rc;
6551 u8 s, n;
6552
6553 if (mutex_lock_killable(&volume_mutex) < 0)
6554 return -EINTR;
6555
6556 rc = volume_get_status_ec(&s);
6557 if (rc)
6558 goto unlock;
6559
6560 n = (mute) ? s | TP_EC_AUDIO_MUTESW_MSK :
6561 s & ~TP_EC_AUDIO_MUTESW_MSK;
6562
6563 if (n != s) {
6564 rc = volume_set_status_ec(n);
6565 if (!rc)
6566 rc = 1;
6567 }
6568
6569unlock:
6570 mutex_unlock(&volume_mutex);
6571 return rc;
6572}
6573
6574static int volume_alsa_set_mute(const bool mute)
6575{
6576 dbg_printk(TPACPI_DBG_MIXER, "ALSA: trying to %smute\n",
6577 (mute) ? "" : "un");
6578 return __volume_set_mute_ec(mute);
6579}
6580
6581static int volume_set_mute(const bool mute)
6582{
6583 int rc;
6584
6585 dbg_printk(TPACPI_DBG_MIXER, "trying to %smute\n",
6586 (mute) ? "" : "un");
6587
6588 rc = __volume_set_mute_ec(mute);
6589 return (rc < 0) ? rc : 0;
6590}
6591
6592/* returns < 0 on error, 0 on no change, 1 on change */
6593static int __volume_set_volume_ec(const u8 vol)
6594{
6595 int rc;
6596 u8 s, n;
6597
6598 if (vol > TP_EC_VOLUME_MAX)
6599 return -EINVAL;
6600
6601 if (mutex_lock_killable(&volume_mutex) < 0)
6602 return -EINTR;
6603
6604 rc = volume_get_status_ec(&s);
6605 if (rc)
6606 goto unlock;
6607
6608 n = (s & ~TP_EC_AUDIO_LVL_MSK) | vol;
6609
6610 if (n != s) {
6611 rc = volume_set_status_ec(n);
6612 if (!rc)
6613 rc = 1;
6614 }
6615
6616unlock:
6617 mutex_unlock(&volume_mutex);
6618 return rc;
6619}
6620
6621static int volume_alsa_set_volume(const u8 vol)
6622{
6623 dbg_printk(TPACPI_DBG_MIXER,
6624 "ALSA: trying to set volume level to %hu\n", vol);
6625 return __volume_set_volume_ec(vol);
6626}
6627
6628static void volume_alsa_notify_change(void)
6629{
6630 struct tpacpi_alsa_data *d;
6631
6632 if (alsa_card && alsa_card->private_data) {
6633 d = alsa_card->private_data;
6634 if (d->ctl_mute_id)
6635 snd_ctl_notify(alsa_card,
6636 SNDRV_CTL_EVENT_MASK_VALUE,
6637 d->ctl_mute_id);
6638 if (d->ctl_vol_id)
6639 snd_ctl_notify(alsa_card,
6640 SNDRV_CTL_EVENT_MASK_VALUE,
6641 d->ctl_vol_id);
6642 }
6643}
6644
6645static int volume_alsa_vol_info(struct snd_kcontrol *kcontrol,
6646 struct snd_ctl_elem_info *uinfo)
6647{
6648 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
6649 uinfo->count = 1;
6650 uinfo->value.integer.min = 0;
6651 uinfo->value.integer.max = TP_EC_VOLUME_MAX;
6652 return 0;
6653}
6654
6655static int volume_alsa_vol_get(struct snd_kcontrol *kcontrol,
6656 struct snd_ctl_elem_value *ucontrol)
6657{
6658 u8 s;
6659 int rc;
6660
6661 rc = volume_get_status(&s);
6662 if (rc < 0)
6663 return rc;
6664
6665 ucontrol->value.integer.value[0] = s & TP_EC_AUDIO_LVL_MSK;
6666 return 0;
6667}
6668
6669static int volume_alsa_vol_put(struct snd_kcontrol *kcontrol,
6670 struct snd_ctl_elem_value *ucontrol)
6671{
6672 return volume_alsa_set_volume(ucontrol->value.integer.value[0]);
6673}
6674
6675#define volume_alsa_mute_info snd_ctl_boolean_mono_info
6676
6677static int volume_alsa_mute_get(struct snd_kcontrol *kcontrol,
6678 struct snd_ctl_elem_value *ucontrol)
6679{
6680 u8 s;
6681 int rc;
6682
6683 rc = volume_get_status(&s);
6684 if (rc < 0)
6685 return rc;
6686
6687 ucontrol->value.integer.value[0] =
6688 (s & TP_EC_AUDIO_MUTESW_MSK) ? 0 : 1;
6689 return 0;
6690}
6691
6692static int volume_alsa_mute_put(struct snd_kcontrol *kcontrol,
6693 struct snd_ctl_elem_value *ucontrol)
6694{
6695 return volume_alsa_set_mute(!ucontrol->value.integer.value[0]);
6696}
6697
6698static struct snd_kcontrol_new volume_alsa_control_vol __devinitdata = {
6699 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6700 .name = "Console Playback Volume",
6701 .index = 0,
6702 .access = SNDRV_CTL_ELEM_ACCESS_READ,
6703 .info = volume_alsa_vol_info,
6704 .get = volume_alsa_vol_get,
6705};
6706
6707static struct snd_kcontrol_new volume_alsa_control_mute __devinitdata = {
6708 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6709 .name = "Console Playback Switch",
6710 .index = 0,
6711 .access = SNDRV_CTL_ELEM_ACCESS_READ,
6712 .info = volume_alsa_mute_info,
6713 .get = volume_alsa_mute_get,
6714};
6715
6716static void volume_suspend(pm_message_t state)
6717{
6718 tpacpi_volume_checkpoint_nvram();
6719}
6720
6721static void volume_resume(void)
6722{
6723 volume_alsa_notify_change();
6724}
6725
6726static void volume_shutdown(void)
6727{
6728 tpacpi_volume_checkpoint_nvram();
6729}
6730
6731static void volume_exit(void)
6732{
6733 if (alsa_card) {
6734 snd_card_free(alsa_card);
6735 alsa_card = NULL;
6736 }
6737
6738 tpacpi_volume_checkpoint_nvram();
6739}
6740
6741static int __init volume_create_alsa_mixer(void)
6742{
6743 struct snd_card *card;
6744 struct tpacpi_alsa_data *data;
6745 struct snd_kcontrol *ctl_vol;
6746 struct snd_kcontrol *ctl_mute;
6747 int rc;
6748
6749 rc = snd_card_create(alsa_index, alsa_id, THIS_MODULE,
6750 sizeof(struct tpacpi_alsa_data), &card);
6751 if (rc < 0 || !card) {
6752 printk(TPACPI_ERR
6753 "Failed to create ALSA card structures: %d\n", rc);
6754 return 1;
6755 }
6756
6757 BUG_ON(!card->private_data);
6758 data = card->private_data;
6759 data->card = card;
6760
6761 strlcpy(card->driver, TPACPI_ALSA_DRVNAME,
6762 sizeof(card->driver));
6763 strlcpy(card->shortname, TPACPI_ALSA_SHRTNAME,
6764 sizeof(card->shortname));
6765 snprintf(card->mixername, sizeof(card->mixername), "ThinkPad EC %s",
6766 (thinkpad_id.ec_version_str) ?
6767 thinkpad_id.ec_version_str : "(unknown)");
6768 snprintf(card->longname, sizeof(card->longname),
6769 "%s at EC reg 0x%02x, fw %s", card->shortname, TP_EC_AUDIO,
6770 (thinkpad_id.ec_version_str) ?
6771 thinkpad_id.ec_version_str : "unknown");
6772
6773 if (volume_control_allowed) {
6774 volume_alsa_control_vol.put = volume_alsa_vol_put;
6775 volume_alsa_control_vol.access =
6776 SNDRV_CTL_ELEM_ACCESS_READWRITE;
6777
6778 volume_alsa_control_mute.put = volume_alsa_mute_put;
6779 volume_alsa_control_mute.access =
6780 SNDRV_CTL_ELEM_ACCESS_READWRITE;
6781 }
6782
6783 if (!tp_features.mixer_no_level_control) {
6784 ctl_vol = snd_ctl_new1(&volume_alsa_control_vol, NULL);
6785 rc = snd_ctl_add(card, ctl_vol);
6786 if (rc < 0) {
6787 printk(TPACPI_ERR
6788 "Failed to create ALSA volume control: %d\n",
6789 rc);
6790 goto err_exit;
6416 } 6791 }
6792 data->ctl_vol_id = &ctl_vol->id;
6793 }
6417 6794
6418 if (new_mute != mute) { 6795 ctl_mute = snd_ctl_new1(&volume_alsa_control_mute, NULL);
6419 /* level doesn't change */ 6796 rc = snd_ctl_add(card, ctl_mute);
6797 if (rc < 0) {
6798 printk(TPACPI_ERR "Failed to create ALSA mute control: %d\n",
6799 rc);
6800 goto err_exit;
6801 }
6802 data->ctl_mute_id = &ctl_mute->id;
6420 6803
6421 cmos_cmd = (new_mute) ? 6804 snd_card_set_dev(card, &tpacpi_pdev->dev);
6422 TP_CMOS_VOLUME_MUTE : TP_CMOS_VOLUME_UP; 6805 rc = snd_card_register(card);
6806 if (rc < 0) {
6807 printk(TPACPI_ERR "Failed to register ALSA card: %d\n", rc);
6808 goto err_exit;
6809 }
6423 6810
6424 if (issue_thinkpad_cmos_command(cmos_cmd) || 6811 alsa_card = card;
6425 !acpi_ec_write(volume_offset, level + new_mute)) 6812 return 0;
6426 return -EIO; 6813
6814err_exit:
6815 snd_card_free(card);
6816 return 1;
6817}
6818
6819#define TPACPI_VOL_Q_MUTEONLY 0x0001 /* Mute-only control available */
6820#define TPACPI_VOL_Q_LEVEL 0x0002 /* Volume control available */
6821
6822static const struct tpacpi_quirk volume_quirk_table[] __initconst = {
6823 /* Whitelist volume level on all IBM by default */
6824 { .vendor = PCI_VENDOR_ID_IBM,
6825 .bios = TPACPI_MATCH_ANY,
6826 .ec = TPACPI_MATCH_ANY,
6827 .quirks = TPACPI_VOL_Q_LEVEL },
6828
6829 /* Lenovo models with volume control (needs confirmation) */
6830 TPACPI_QEC_LNV('7', 'C', TPACPI_VOL_Q_LEVEL), /* R60/i */
6831 TPACPI_QEC_LNV('7', 'E', TPACPI_VOL_Q_LEVEL), /* R60e/i */
6832 TPACPI_QEC_LNV('7', '9', TPACPI_VOL_Q_LEVEL), /* T60/p */
6833 TPACPI_QEC_LNV('7', 'B', TPACPI_VOL_Q_LEVEL), /* X60/s */
6834 TPACPI_QEC_LNV('7', 'J', TPACPI_VOL_Q_LEVEL), /* X60t */
6835 TPACPI_QEC_LNV('7', '7', TPACPI_VOL_Q_LEVEL), /* Z60 */
6836 TPACPI_QEC_LNV('7', 'F', TPACPI_VOL_Q_LEVEL), /* Z61 */
6837
6838 /* Whitelist mute-only on all Lenovo by default */
6839 { .vendor = PCI_VENDOR_ID_LENOVO,
6840 .bios = TPACPI_MATCH_ANY,
6841 .ec = TPACPI_MATCH_ANY,
6842 .quirks = TPACPI_VOL_Q_MUTEONLY }
6843};
6844
6845static int __init volume_init(struct ibm_init_struct *iibm)
6846{
6847 unsigned long quirks;
6848 int rc;
6849
6850 vdbg_printk(TPACPI_DBG_INIT, "initializing volume subdriver\n");
6851
6852 mutex_init(&volume_mutex);
6853
6854 /*
6855 * Check for module parameter bogosity, note that we
6856 * init volume_mode to TPACPI_VOL_MODE_MAX in order to be
6857 * able to detect "unspecified"
6858 */
6859 if (volume_mode > TPACPI_VOL_MODE_MAX)
6860 return -EINVAL;
6861
6862 if (volume_mode == TPACPI_VOL_MODE_UCMS_STEP) {
6863 printk(TPACPI_ERR
6864 "UCMS step volume mode not implemented, "
6865 "please contact %s\n", TPACPI_MAIL);
6866 return 1;
6867 }
6868
6869 if (volume_capabilities >= TPACPI_VOL_CAP_MAX)
6870 return -EINVAL;
6871
6872 /*
6873 * The ALSA mixer is our primary interface.
6874 * When disabled, don't install the subdriver at all
6875 */
6876 if (!alsa_enable) {
6877 vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_MIXER,
6878 "ALSA mixer disabled by parameter, "
6879 "not loading volume subdriver...\n");
6880 return 1;
6881 }
6882
6883 quirks = tpacpi_check_quirks(volume_quirk_table,
6884 ARRAY_SIZE(volume_quirk_table));
6885
6886 switch (volume_capabilities) {
6887 case TPACPI_VOL_CAP_AUTO:
6888 if (quirks & TPACPI_VOL_Q_MUTEONLY)
6889 tp_features.mixer_no_level_control = 1;
6890 else if (quirks & TPACPI_VOL_Q_LEVEL)
6891 tp_features.mixer_no_level_control = 0;
6892 else
6893 return 1; /* no mixer */
6894 break;
6895 case TPACPI_VOL_CAP_VOLMUTE:
6896 tp_features.mixer_no_level_control = 0;
6897 break;
6898 case TPACPI_VOL_CAP_MUTEONLY:
6899 tp_features.mixer_no_level_control = 1;
6900 break;
6901 default:
6902 return 1;
6903 }
6904
6905 if (volume_capabilities != TPACPI_VOL_CAP_AUTO)
6906 dbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_MIXER,
6907 "using user-supplied volume_capabilities=%d\n",
6908 volume_capabilities);
6909
6910 if (volume_mode == TPACPI_VOL_MODE_AUTO ||
6911 volume_mode == TPACPI_VOL_MODE_MAX) {
6912 volume_mode = TPACPI_VOL_MODE_ECNVRAM;
6913
6914 dbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_MIXER,
6915 "driver auto-selected volume_mode=%d\n",
6916 volume_mode);
6917 } else {
6918 dbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_MIXER,
6919 "using user-supplied volume_mode=%d\n",
6920 volume_mode);
6921 }
6922
6923 vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_MIXER,
6924 "mute is supported, volume control is %s\n",
6925 str_supported(!tp_features.mixer_no_level_control));
6926
6927 rc = volume_create_alsa_mixer();
6928 if (rc) {
6929 printk(TPACPI_ERR
6930 "Could not create the ALSA mixer interface\n");
6931 return rc;
6932 }
6933
6934 printk(TPACPI_INFO
6935 "Console audio control enabled, mode: %s\n",
6936 (volume_control_allowed) ?
6937 "override (read/write)" :
6938 "monitor (read only)");
6939
6940 vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_MIXER,
6941 "registering volume hotkeys as change notification\n");
6942 tpacpi_hotkey_driver_mask_set(hotkey_driver_mask
6943 | TP_ACPI_HKEY_VOLUP_MASK
6944 | TP_ACPI_HKEY_VOLDWN_MASK
6945 | TP_ACPI_HKEY_MUTE_MASK);
6946
6947 return 0;
6948}
6949
6950static int volume_read(struct seq_file *m)
6951{
6952 u8 status;
6953
6954 if (volume_get_status(&status) < 0) {
6955 seq_printf(m, "level:\t\tunreadable\n");
6956 } else {
6957 if (tp_features.mixer_no_level_control)
6958 seq_printf(m, "level:\t\tunsupported\n");
6959 else
6960 seq_printf(m, "level:\t\t%d\n",
6961 status & TP_EC_AUDIO_LVL_MSK);
6962
6963 seq_printf(m, "mute:\t\t%s\n",
6964 onoff(status, TP_EC_AUDIO_MUTESW));
6965
6966 if (volume_control_allowed) {
6967 seq_printf(m, "commands:\tunmute, mute\n");
6968 if (!tp_features.mixer_no_level_control) {
6969 seq_printf(m,
6970 "commands:\tup, down\n");
6971 seq_printf(m,
6972 "commands:\tlevel <level>"
6973 " (<level> is 0-%d)\n",
6974 TP_EC_VOLUME_MAX);
6975 }
6427 } 6976 }
6428 } 6977 }
6429 6978
6430 return 0; 6979 return 0;
6431} 6980}
6432 6981
6982static int volume_write(char *buf)
6983{
6984 u8 s;
6985 u8 new_level, new_mute;
6986 int l;
6987 char *cmd;
6988 int rc;
6989
6990 /*
6991 * We do allow volume control at driver startup, so that the
6992 * user can set initial state through the volume=... parameter hack.
6993 */
6994 if (!volume_control_allowed && tpacpi_lifecycle != TPACPI_LIFE_INIT) {
6995 if (unlikely(!tp_warned.volume_ctrl_forbidden)) {
6996 tp_warned.volume_ctrl_forbidden = 1;
6997 printk(TPACPI_NOTICE
6998 "Console audio control in monitor mode, "
6999 "changes are not allowed.\n");
7000 printk(TPACPI_NOTICE
7001 "Use the volume_control=1 module parameter "
7002 "to enable volume control\n");
7003 }
7004 return -EPERM;
7005 }
7006
7007 rc = volume_get_status(&s);
7008 if (rc < 0)
7009 return rc;
7010
7011 new_level = s & TP_EC_AUDIO_LVL_MSK;
7012 new_mute = s & TP_EC_AUDIO_MUTESW_MSK;
7013
7014 while ((cmd = next_cmd(&buf))) {
7015 if (!tp_features.mixer_no_level_control) {
7016 if (strlencmp(cmd, "up") == 0) {
7017 if (new_mute)
7018 new_mute = 0;
7019 else if (new_level < TP_EC_VOLUME_MAX)
7020 new_level++;
7021 continue;
7022 } else if (strlencmp(cmd, "down") == 0) {
7023 if (new_mute)
7024 new_mute = 0;
7025 else if (new_level > 0)
7026 new_level--;
7027 continue;
7028 } else if (sscanf(cmd, "level %u", &l) == 1 &&
7029 l >= 0 && l <= TP_EC_VOLUME_MAX) {
7030 new_level = l;
7031 continue;
7032 }
7033 }
7034 if (strlencmp(cmd, "mute") == 0)
7035 new_mute = TP_EC_AUDIO_MUTESW_MSK;
7036 else if (strlencmp(cmd, "unmute") == 0)
7037 new_mute = 0;
7038 else
7039 return -EINVAL;
7040 }
7041
7042 if (tp_features.mixer_no_level_control) {
7043 tpacpi_disclose_usertask("procfs volume", "%smute\n",
7044 new_mute ? "" : "un");
7045 rc = volume_set_mute(!!new_mute);
7046 } else {
7047 tpacpi_disclose_usertask("procfs volume",
7048 "%smute and set level to %d\n",
7049 new_mute ? "" : "un", new_level);
7050 rc = volume_set_status(new_mute | new_level);
7051 }
7052 volume_alsa_notify_change();
7053
7054 return (rc == -EINTR) ? -ERESTARTSYS : rc;
7055}
7056
6433static struct ibm_struct volume_driver_data = { 7057static struct ibm_struct volume_driver_data = {
6434 .name = "volume", 7058 .name = "volume",
6435 .read = volume_read, 7059 .read = volume_read,
6436 .write = volume_write, 7060 .write = volume_write,
7061 .exit = volume_exit,
7062 .suspend = volume_suspend,
7063 .resume = volume_resume,
7064 .shutdown = volume_shutdown,
7065};
7066
7067#else /* !CONFIG_THINKPAD_ACPI_ALSA_SUPPORT */
7068
7069#define alsa_card NULL
7070
7071static void inline volume_alsa_notify_change(void)
7072{
7073}
7074
7075static int __init volume_init(struct ibm_init_struct *iibm)
7076{
7077 printk(TPACPI_INFO
7078 "volume: disabled as there is no ALSA support in this kernel\n");
7079
7080 return 1;
7081}
7082
7083static struct ibm_struct volume_driver_data = {
7084 .name = "volume",
6437}; 7085};
6438 7086
7087#endif /* CONFIG_THINKPAD_ACPI_ALSA_SUPPORT */
7088
6439/************************************************************************* 7089/*************************************************************************
6440 * Fan subdriver 7090 * Fan subdriver
6441 */ 7091 */
@@ -6461,7 +7111,7 @@ static struct ibm_struct volume_driver_data = {
6461 * 7111 *
6462 * Fan speed changes of any sort (including those caused by the 7112 * Fan speed changes of any sort (including those caused by the
6463 * disengaged mode) are usually done slowly by the firmware as the 7113 * disengaged mode) are usually done slowly by the firmware as the
6464 * maximum ammount of fan duty cycle change per second seems to be 7114 * maximum amount of fan duty cycle change per second seems to be
6465 * limited. 7115 * limited.
6466 * 7116 *
6467 * Reading is not available if GFAN exists. 7117 * Reading is not available if GFAN exists.
@@ -6545,7 +7195,7 @@ static struct ibm_struct volume_driver_data = {
6545 * The speeds are stored on handles 7195 * The speeds are stored on handles
6546 * (FANA:FAN9), (FANC:FANB), (FANE:FAND). 7196 * (FANA:FAN9), (FANC:FANB), (FANE:FAND).
6547 * 7197 *
6548 * There are three default speed sets, acessible as handles: 7198 * There are three default speed sets, accessible as handles:
6549 * FS1L,FS1M,FS1H; FS2L,FS2M,FS2H; FS3L,FS3M,FS3H 7199 * FS1L,FS1M,FS1H; FS2L,FS2M,FS2H; FS3L,FS3M,FS3H
6550 * 7200 *
6551 * ACPI DSDT switches which set is in use depending on various 7201 * ACPI DSDT switches which set is in use depending on various
@@ -7510,9 +8160,8 @@ static void fan_resume(void)
7510 } 8160 }
7511} 8161}
7512 8162
7513static int fan_read(char *p) 8163static int fan_read(struct seq_file *m)
7514{ 8164{
7515 int len = 0;
7516 int rc; 8165 int rc;
7517 u8 status; 8166 u8 status;
7518 unsigned int speed = 0; 8167 unsigned int speed = 0;
@@ -7524,7 +8173,7 @@ static int fan_read(char *p)
7524 if (rc < 0) 8173 if (rc < 0)
7525 return rc; 8174 return rc;
7526 8175
7527 len += sprintf(p + len, "status:\t\t%s\n" 8176 seq_printf(m, "status:\t\t%s\n"
7528 "level:\t\t%d\n", 8177 "level:\t\t%d\n",
7529 (status != 0) ? "enabled" : "disabled", status); 8178 (status != 0) ? "enabled" : "disabled", status);
7530 break; 8179 break;
@@ -7535,54 +8184,54 @@ static int fan_read(char *p)
7535 if (rc < 0) 8184 if (rc < 0)
7536 return rc; 8185 return rc;
7537 8186
7538 len += sprintf(p + len, "status:\t\t%s\n", 8187 seq_printf(m, "status:\t\t%s\n",
7539 (status != 0) ? "enabled" : "disabled"); 8188 (status != 0) ? "enabled" : "disabled");
7540 8189
7541 rc = fan_get_speed(&speed); 8190 rc = fan_get_speed(&speed);
7542 if (rc < 0) 8191 if (rc < 0)
7543 return rc; 8192 return rc;
7544 8193
7545 len += sprintf(p + len, "speed:\t\t%d\n", speed); 8194 seq_printf(m, "speed:\t\t%d\n", speed);
7546 8195
7547 if (status & TP_EC_FAN_FULLSPEED) 8196 if (status & TP_EC_FAN_FULLSPEED)
7548 /* Disengaged mode takes precedence */ 8197 /* Disengaged mode takes precedence */
7549 len += sprintf(p + len, "level:\t\tdisengaged\n"); 8198 seq_printf(m, "level:\t\tdisengaged\n");
7550 else if (status & TP_EC_FAN_AUTO) 8199 else if (status & TP_EC_FAN_AUTO)
7551 len += sprintf(p + len, "level:\t\tauto\n"); 8200 seq_printf(m, "level:\t\tauto\n");
7552 else 8201 else
7553 len += sprintf(p + len, "level:\t\t%d\n", status); 8202 seq_printf(m, "level:\t\t%d\n", status);
7554 break; 8203 break;
7555 8204
7556 case TPACPI_FAN_NONE: 8205 case TPACPI_FAN_NONE:
7557 default: 8206 default:
7558 len += sprintf(p + len, "status:\t\tnot supported\n"); 8207 seq_printf(m, "status:\t\tnot supported\n");
7559 } 8208 }
7560 8209
7561 if (fan_control_commands & TPACPI_FAN_CMD_LEVEL) { 8210 if (fan_control_commands & TPACPI_FAN_CMD_LEVEL) {
7562 len += sprintf(p + len, "commands:\tlevel <level>"); 8211 seq_printf(m, "commands:\tlevel <level>");
7563 8212
7564 switch (fan_control_access_mode) { 8213 switch (fan_control_access_mode) {
7565 case TPACPI_FAN_WR_ACPI_SFAN: 8214 case TPACPI_FAN_WR_ACPI_SFAN:
7566 len += sprintf(p + len, " (<level> is 0-7)\n"); 8215 seq_printf(m, " (<level> is 0-7)\n");
7567 break; 8216 break;
7568 8217
7569 default: 8218 default:
7570 len += sprintf(p + len, " (<level> is 0-7, " 8219 seq_printf(m, " (<level> is 0-7, "
7571 "auto, disengaged, full-speed)\n"); 8220 "auto, disengaged, full-speed)\n");
7572 break; 8221 break;
7573 } 8222 }
7574 } 8223 }
7575 8224
7576 if (fan_control_commands & TPACPI_FAN_CMD_ENABLE) 8225 if (fan_control_commands & TPACPI_FAN_CMD_ENABLE)
7577 len += sprintf(p + len, "commands:\tenable, disable\n" 8226 seq_printf(m, "commands:\tenable, disable\n"
7578 "commands:\twatchdog <timeout> (<timeout> " 8227 "commands:\twatchdog <timeout> (<timeout> "
7579 "is 0 (off), 1-120 (seconds))\n"); 8228 "is 0 (off), 1-120 (seconds))\n");
7580 8229
7581 if (fan_control_commands & TPACPI_FAN_CMD_SPEED) 8230 if (fan_control_commands & TPACPI_FAN_CMD_SPEED)
7582 len += sprintf(p + len, "commands:\tspeed <speed>" 8231 seq_printf(m, "commands:\tspeed <speed>"
7583 " (<speed> is 0-65535)\n"); 8232 " (<speed> is 0-65535)\n");
7584 8233
7585 return len; 8234 return 0;
7586} 8235}
7587 8236
7588static int fan_write_cmd_level(const char *cmd, int *rc) 8237static int fan_write_cmd_level(const char *cmd, int *rc)
@@ -7724,10 +8373,23 @@ static struct ibm_struct fan_driver_data = {
7724 */ 8373 */
7725static void tpacpi_driver_event(const unsigned int hkey_event) 8374static void tpacpi_driver_event(const unsigned int hkey_event)
7726{ 8375{
8376 if (ibm_backlight_device) {
8377 switch (hkey_event) {
8378 case TP_HKEY_EV_BRGHT_UP:
8379 case TP_HKEY_EV_BRGHT_DOWN:
8380 tpacpi_brightness_notify_change();
8381 }
8382 }
8383 if (alsa_card) {
8384 switch (hkey_event) {
8385 case TP_HKEY_EV_VOL_UP:
8386 case TP_HKEY_EV_VOL_DOWN:
8387 case TP_HKEY_EV_VOL_MUTE:
8388 volume_alsa_notify_change();
8389 }
8390 }
7727} 8391}
7728 8392
7729
7730
7731static void hotkey_driver_event(const unsigned int scancode) 8393static void hotkey_driver_event(const unsigned int scancode)
7732{ 8394{
7733 tpacpi_driver_event(TP_HKEY_EV_HOTKEY_BASE + scancode); 8395 tpacpi_driver_event(TP_HKEY_EV_HOTKEY_BASE + scancode);
@@ -7856,19 +8518,20 @@ static int __init ibm_init(struct ibm_init_struct *iibm)
7856 "%s installed\n", ibm->name); 8518 "%s installed\n", ibm->name);
7857 8519
7858 if (ibm->read) { 8520 if (ibm->read) {
7859 entry = create_proc_entry(ibm->name, 8521 mode_t mode = iibm->base_procfs_mode;
7860 S_IFREG | S_IRUGO | S_IWUSR, 8522
7861 proc_dir); 8523 if (!mode)
8524 mode = S_IRUGO;
8525 if (ibm->write)
8526 mode |= S_IWUSR;
8527 entry = proc_create_data(ibm->name, mode, proc_dir,
8528 &dispatch_proc_fops, ibm);
7862 if (!entry) { 8529 if (!entry) {
7863 printk(TPACPI_ERR "unable to create proc entry %s\n", 8530 printk(TPACPI_ERR "unable to create proc entry %s\n",
7864 ibm->name); 8531 ibm->name);
7865 ret = -ENODEV; 8532 ret = -ENODEV;
7866 goto err_out; 8533 goto err_out;
7867 } 8534 }
7868 entry->data = ibm;
7869 entry->read_proc = &dispatch_procfs_read;
7870 if (ibm->write)
7871 entry->write_proc = &dispatch_procfs_write;
7872 ibm->flags.proc_created = 1; 8535 ibm->flags.proc_created = 1;
7873 } 8536 }
7874 8537
@@ -8049,6 +8712,7 @@ static struct ibm_init_struct ibms_init[] __initdata = {
8049#ifdef CONFIG_THINKPAD_ACPI_VIDEO 8712#ifdef CONFIG_THINKPAD_ACPI_VIDEO
8050 { 8713 {
8051 .init = video_init, 8714 .init = video_init,
8715 .base_procfs_mode = S_IRUSR,
8052 .data = &video_driver_data, 8716 .data = &video_driver_data,
8053 }, 8717 },
8054#endif 8718#endif
@@ -8080,6 +8744,7 @@ static struct ibm_init_struct ibms_init[] __initdata = {
8080 .data = &brightness_driver_data, 8744 .data = &brightness_driver_data,
8081 }, 8745 },
8082 { 8746 {
8747 .init = volume_init,
8083 .data = &volume_driver_data, 8748 .data = &volume_driver_data,
8084 }, 8749 },
8085 { 8750 {
@@ -8115,36 +8780,61 @@ static int __init set_ibm_param(const char *val, struct kernel_param *kp)
8115 return -EINVAL; 8780 return -EINVAL;
8116} 8781}
8117 8782
8118module_param(experimental, int, 0); 8783module_param(experimental, int, 0444);
8119MODULE_PARM_DESC(experimental, 8784MODULE_PARM_DESC(experimental,
8120 "Enables experimental features when non-zero"); 8785 "Enables experimental features when non-zero");
8121 8786
8122module_param_named(debug, dbg_level, uint, 0); 8787module_param_named(debug, dbg_level, uint, 0);
8123MODULE_PARM_DESC(debug, "Sets debug level bit-mask"); 8788MODULE_PARM_DESC(debug, "Sets debug level bit-mask");
8124 8789
8125module_param(force_load, bool, 0); 8790module_param(force_load, bool, 0444);
8126MODULE_PARM_DESC(force_load, 8791MODULE_PARM_DESC(force_load,
8127 "Attempts to load the driver even on a " 8792 "Attempts to load the driver even on a "
8128 "mis-identified ThinkPad when true"); 8793 "mis-identified ThinkPad when true");
8129 8794
8130module_param_named(fan_control, fan_control_allowed, bool, 0); 8795module_param_named(fan_control, fan_control_allowed, bool, 0444);
8131MODULE_PARM_DESC(fan_control, 8796MODULE_PARM_DESC(fan_control,
8132 "Enables setting fan parameters features when true"); 8797 "Enables setting fan parameters features when true");
8133 8798
8134module_param_named(brightness_mode, brightness_mode, uint, 0); 8799module_param_named(brightness_mode, brightness_mode, uint, 0444);
8135MODULE_PARM_DESC(brightness_mode, 8800MODULE_PARM_DESC(brightness_mode,
8136 "Selects brightness control strategy: " 8801 "Selects brightness control strategy: "
8137 "0=auto, 1=EC, 2=UCMS, 3=EC+NVRAM"); 8802 "0=auto, 1=EC, 2=UCMS, 3=EC+NVRAM");
8138 8803
8139module_param(brightness_enable, uint, 0); 8804module_param(brightness_enable, uint, 0444);
8140MODULE_PARM_DESC(brightness_enable, 8805MODULE_PARM_DESC(brightness_enable,
8141 "Enables backlight control when 1, disables when 0"); 8806 "Enables backlight control when 1, disables when 0");
8142 8807
8143module_param(hotkey_report_mode, uint, 0); 8808module_param(hotkey_report_mode, uint, 0444);
8144MODULE_PARM_DESC(hotkey_report_mode, 8809MODULE_PARM_DESC(hotkey_report_mode,
8145 "used for backwards compatibility with userspace, " 8810 "used for backwards compatibility with userspace, "
8146 "see documentation"); 8811 "see documentation");
8147 8812
8813#ifdef CONFIG_THINKPAD_ACPI_ALSA_SUPPORT
8814module_param_named(volume_mode, volume_mode, uint, 0444);
8815MODULE_PARM_DESC(volume_mode,
8816 "Selects volume control strategy: "
8817 "0=auto, 1=EC, 2=N/A, 3=EC+NVRAM");
8818
8819module_param_named(volume_capabilities, volume_capabilities, uint, 0444);
8820MODULE_PARM_DESC(volume_capabilities,
8821 "Selects the mixer capabilites: "
8822 "0=auto, 1=volume and mute, 2=mute only");
8823
8824module_param_named(volume_control, volume_control_allowed, bool, 0444);
8825MODULE_PARM_DESC(volume_control,
8826 "Enables software override for the console audio "
8827 "control when true");
8828
8829/* ALSA module API parameters */
8830module_param_named(index, alsa_index, int, 0444);
8831MODULE_PARM_DESC(index, "ALSA index for the ACPI EC Mixer");
8832module_param_named(id, alsa_id, charp, 0444);
8833MODULE_PARM_DESC(id, "ALSA id for the ACPI EC Mixer");
8834module_param_named(enable, alsa_enable, bool, 0444);
8835MODULE_PARM_DESC(enable, "Enable the ALSA interface for the ACPI EC Mixer");
8836#endif /* CONFIG_THINKPAD_ACPI_ALSA_SUPPORT */
8837
8148#define TPACPI_PARAM(feature) \ 8838#define TPACPI_PARAM(feature) \
8149 module_param_call(feature, set_ibm_param, NULL, NULL, 0); \ 8839 module_param_call(feature, set_ibm_param, NULL, NULL, 0); \
8150 MODULE_PARM_DESC(feature, "Simulates thinkpad-acpi procfs command " \ 8840 MODULE_PARM_DESC(feature, "Simulates thinkpad-acpi procfs command " \
@@ -8163,25 +8853,25 @@ TPACPI_PARAM(volume);
8163TPACPI_PARAM(fan); 8853TPACPI_PARAM(fan);
8164 8854
8165#ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES 8855#ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES
8166module_param(dbg_wlswemul, uint, 0); 8856module_param(dbg_wlswemul, uint, 0444);
8167MODULE_PARM_DESC(dbg_wlswemul, "Enables WLSW emulation"); 8857MODULE_PARM_DESC(dbg_wlswemul, "Enables WLSW emulation");
8168module_param_named(wlsw_state, tpacpi_wlsw_emulstate, bool, 0); 8858module_param_named(wlsw_state, tpacpi_wlsw_emulstate, bool, 0);
8169MODULE_PARM_DESC(wlsw_state, 8859MODULE_PARM_DESC(wlsw_state,
8170 "Initial state of the emulated WLSW switch"); 8860 "Initial state of the emulated WLSW switch");
8171 8861
8172module_param(dbg_bluetoothemul, uint, 0); 8862module_param(dbg_bluetoothemul, uint, 0444);
8173MODULE_PARM_DESC(dbg_bluetoothemul, "Enables bluetooth switch emulation"); 8863MODULE_PARM_DESC(dbg_bluetoothemul, "Enables bluetooth switch emulation");
8174module_param_named(bluetooth_state, tpacpi_bluetooth_emulstate, bool, 0); 8864module_param_named(bluetooth_state, tpacpi_bluetooth_emulstate, bool, 0);
8175MODULE_PARM_DESC(bluetooth_state, 8865MODULE_PARM_DESC(bluetooth_state,
8176 "Initial state of the emulated bluetooth switch"); 8866 "Initial state of the emulated bluetooth switch");
8177 8867
8178module_param(dbg_wwanemul, uint, 0); 8868module_param(dbg_wwanemul, uint, 0444);
8179MODULE_PARM_DESC(dbg_wwanemul, "Enables WWAN switch emulation"); 8869MODULE_PARM_DESC(dbg_wwanemul, "Enables WWAN switch emulation");
8180module_param_named(wwan_state, tpacpi_wwan_emulstate, bool, 0); 8870module_param_named(wwan_state, tpacpi_wwan_emulstate, bool, 0);
8181MODULE_PARM_DESC(wwan_state, 8871MODULE_PARM_DESC(wwan_state,
8182 "Initial state of the emulated WWAN switch"); 8872 "Initial state of the emulated WWAN switch");
8183 8873
8184module_param(dbg_uwbemul, uint, 0); 8874module_param(dbg_uwbemul, uint, 0444);
8185MODULE_PARM_DESC(dbg_uwbemul, "Enables UWB switch emulation"); 8875MODULE_PARM_DESC(dbg_uwbemul, "Enables UWB switch emulation");
8186module_param_named(uwb_state, tpacpi_uwb_emulstate, bool, 0); 8876module_param_named(uwb_state, tpacpi_uwb_emulstate, bool, 0);
8187MODULE_PARM_DESC(uwb_state, 8877MODULE_PARM_DESC(uwb_state,
@@ -8374,6 +9064,7 @@ static int __init thinkpad_acpi_module_init(void)
8374 PCI_VENDOR_ID_IBM; 9064 PCI_VENDOR_ID_IBM;
8375 tpacpi_inputdev->id.product = TPACPI_HKEY_INPUT_PRODUCT; 9065 tpacpi_inputdev->id.product = TPACPI_HKEY_INPUT_PRODUCT;
8376 tpacpi_inputdev->id.version = TPACPI_HKEY_INPUT_VERSION; 9066 tpacpi_inputdev->id.version = TPACPI_HKEY_INPUT_VERSION;
9067 tpacpi_inputdev->dev.parent = &tpacpi_pdev->dev;
8377 } 9068 }
8378 for (i = 0; i < ARRAY_SIZE(ibms_init); i++) { 9069 for (i = 0; i < ARRAY_SIZE(ibms_init); i++) {
8379 ret = ibm_init(&ibms_init[i]); 9070 ret = ibm_init(&ibms_init[i]);
@@ -8384,6 +9075,9 @@ static int __init thinkpad_acpi_module_init(void)
8384 return ret; 9075 return ret;
8385 } 9076 }
8386 } 9077 }
9078
9079 tpacpi_lifecycle = TPACPI_LIFE_RUNNING;
9080
8387 ret = input_register_device(tpacpi_inputdev); 9081 ret = input_register_device(tpacpi_inputdev);
8388 if (ret < 0) { 9082 if (ret < 0) {
8389 printk(TPACPI_ERR "unable to register input device\n"); 9083 printk(TPACPI_ERR "unable to register input device\n");
@@ -8393,7 +9087,6 @@ static int __init thinkpad_acpi_module_init(void)
8393 tp_features.input_device_registered = 1; 9087 tp_features.input_device_registered = 1;
8394 } 9088 }
8395 9089
8396 tpacpi_lifecycle = TPACPI_LIFE_RUNNING;
8397 return 0; 9090 return 0;
8398} 9091}
8399 9092
diff --git a/drivers/platform/x86/topstar-laptop.c b/drivers/platform/x86/topstar-laptop.c
index 02f3d4e9e666..ff4b476f1950 100644
--- a/drivers/platform/x86/topstar-laptop.c
+++ b/drivers/platform/x86/topstar-laptop.c
@@ -16,6 +16,7 @@
16#include <linux/kernel.h> 16#include <linux/kernel.h>
17#include <linux/module.h> 17#include <linux/module.h>
18#include <linux/init.h> 18#include <linux/init.h>
19#include <linux/slab.h>
19#include <linux/acpi.h> 20#include <linux/acpi.h>
20#include <linux/input.h> 21#include <linux/input.h>
21 22
@@ -46,7 +47,7 @@ static struct tps_key_entry topstar_keymap[] = {
46 { } 47 { }
47}; 48};
48 49
49static struct tps_key_entry *tps_get_key_by_scancode(int code) 50static struct tps_key_entry *tps_get_key_by_scancode(unsigned int code)
50{ 51{
51 struct tps_key_entry *key; 52 struct tps_key_entry *key;
52 53
@@ -57,7 +58,7 @@ static struct tps_key_entry *tps_get_key_by_scancode(int code)
57 return NULL; 58 return NULL;
58} 59}
59 60
60static struct tps_key_entry *tps_get_key_by_keycode(int code) 61static struct tps_key_entry *tps_get_key_by_keycode(unsigned int code)
61{ 62{
62 struct tps_key_entry *key; 63 struct tps_key_entry *key;
63 64
@@ -126,7 +127,8 @@ static int acpi_topstar_fncx_switch(struct acpi_device *device, bool state)
126 return 0; 127 return 0;
127} 128}
128 129
129static int topstar_getkeycode(struct input_dev *dev, int scancode, int *keycode) 130static int topstar_getkeycode(struct input_dev *dev,
131 unsigned int scancode, unsigned int *keycode)
130{ 132{
131 struct tps_key_entry *key = tps_get_key_by_scancode(scancode); 133 struct tps_key_entry *key = tps_get_key_by_scancode(scancode);
132 134
@@ -137,14 +139,12 @@ static int topstar_getkeycode(struct input_dev *dev, int scancode, int *keycode)
137 return 0; 139 return 0;
138} 140}
139 141
140static int topstar_setkeycode(struct input_dev *dev, int scancode, int keycode) 142static int topstar_setkeycode(struct input_dev *dev,
143 unsigned int scancode, unsigned int keycode)
141{ 144{
142 struct tps_key_entry *key; 145 struct tps_key_entry *key;
143 int old_keycode; 146 int old_keycode;
144 147
145 if (keycode < 0 || keycode > KEY_MAX)
146 return -EINVAL;
147
148 key = tps_get_key_by_scancode(scancode); 148 key = tps_get_key_by_scancode(scancode);
149 149
150 if (!key) 150 if (!key)
diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c
index 51c0a8bee414..37aa14798551 100644
--- a/drivers/platform/x86/toshiba_acpi.c
+++ b/drivers/platform/x86/toshiba_acpi.c
@@ -42,9 +42,12 @@
42#include <linux/init.h> 42#include <linux/init.h>
43#include <linux/types.h> 43#include <linux/types.h>
44#include <linux/proc_fs.h> 44#include <linux/proc_fs.h>
45#include <linux/seq_file.h>
45#include <linux/backlight.h> 46#include <linux/backlight.h>
46#include <linux/platform_device.h> 47#include <linux/platform_device.h>
47#include <linux/rfkill.h> 48#include <linux/rfkill.h>
49#include <linux/input.h>
50#include <linux/slab.h>
48 51
49#include <asm/uaccess.h> 52#include <asm/uaccess.h>
50 53
@@ -61,9 +64,10 @@ MODULE_LICENSE("GPL");
61 64
62/* Toshiba ACPI method paths */ 65/* Toshiba ACPI method paths */
63#define METHOD_LCD_BRIGHTNESS "\\_SB_.PCI0.VGA_.LCD_._BCM" 66#define METHOD_LCD_BRIGHTNESS "\\_SB_.PCI0.VGA_.LCD_._BCM"
64#define METHOD_HCI_1 "\\_SB_.VALD.GHCI" 67#define TOSH_INTERFACE_1 "\\_SB_.VALD"
65#define METHOD_HCI_2 "\\_SB_.VALZ.GHCI" 68#define TOSH_INTERFACE_2 "\\_SB_.VALZ"
66#define METHOD_VIDEO_OUT "\\_SB_.VALX.DSSX" 69#define METHOD_VIDEO_OUT "\\_SB_.VALX.DSSX"
70#define GHCI_METHOD ".GHCI"
67 71
68/* Toshiba HCI interface definitions 72/* Toshiba HCI interface definitions
69 * 73 *
@@ -115,6 +119,36 @@ static const struct acpi_device_id toshiba_device_ids[] = {
115}; 119};
116MODULE_DEVICE_TABLE(acpi, toshiba_device_ids); 120MODULE_DEVICE_TABLE(acpi, toshiba_device_ids);
117 121
122struct key_entry {
123 char type;
124 u16 code;
125 u16 keycode;
126};
127
128enum {KE_KEY, KE_END};
129
130static struct key_entry toshiba_acpi_keymap[] = {
131 {KE_KEY, 0x101, KEY_MUTE},
132 {KE_KEY, 0x13b, KEY_COFFEE},
133 {KE_KEY, 0x13c, KEY_BATTERY},
134 {KE_KEY, 0x13d, KEY_SLEEP},
135 {KE_KEY, 0x13e, KEY_SUSPEND},
136 {KE_KEY, 0x13f, KEY_SWITCHVIDEOMODE},
137 {KE_KEY, 0x140, KEY_BRIGHTNESSDOWN},
138 {KE_KEY, 0x141, KEY_BRIGHTNESSUP},
139 {KE_KEY, 0x142, KEY_WLAN},
140 {KE_KEY, 0x143, KEY_PROG1},
141 {KE_KEY, 0xb05, KEY_PROG2},
142 {KE_KEY, 0xb06, KEY_WWW},
143 {KE_KEY, 0xb07, KEY_MAIL},
144 {KE_KEY, 0xb30, KEY_STOP},
145 {KE_KEY, 0xb31, KEY_PREVIOUSSONG},
146 {KE_KEY, 0xb32, KEY_NEXTSONG},
147 {KE_KEY, 0xb33, KEY_PLAYPAUSE},
148 {KE_KEY, 0xb5a, KEY_MEDIA},
149 {KE_END, 0, 0},
150};
151
118/* utility 152/* utility
119 */ 153 */
120 154
@@ -250,6 +284,8 @@ static acpi_status hci_read2(u32 reg, u32 *out1, u32 *out2, u32 *result)
250struct toshiba_acpi_dev { 284struct toshiba_acpi_dev {
251 struct platform_device *p_dev; 285 struct platform_device *p_dev;
252 struct rfkill *bt_rfk; 286 struct rfkill *bt_rfk;
287 struct input_dev *hotkey_dev;
288 acpi_handle handle;
253 289
254 const char *bt_name; 290 const char *bt_name;
255 291
@@ -357,63 +393,6 @@ static int force_fan;
357static int last_key_event; 393static int last_key_event;
358static int key_event_valid; 394static int key_event_valid;
359 395
360typedef struct _ProcItem {
361 const char *name;
362 char *(*read_func) (char *);
363 unsigned long (*write_func) (const char *, unsigned long);
364} ProcItem;
365
366/* proc file handlers
367 */
368
369static int
370dispatch_read(char *page, char **start, off_t off, int count, int *eof,
371 ProcItem * item)
372{
373 char *p = page;
374 int len;
375
376 if (off == 0)
377 p = item->read_func(p);
378
379 /* ISSUE: I don't understand this code */
380 len = (p - page);
381 if (len <= off + count)
382 *eof = 1;
383 *start = page + off;
384 len -= off;
385 if (len > count)
386 len = count;
387 if (len < 0)
388 len = 0;
389 return len;
390}
391
392static int
393dispatch_write(struct file *file, const char __user * buffer,
394 unsigned long count, ProcItem * item)
395{
396 int result;
397 char *tmp_buffer;
398
399 /* Arg buffer points to userspace memory, which can't be accessed
400 * directly. Since we're making a copy, zero-terminate the
401 * destination so that sscanf can be used on it safely.
402 */
403 tmp_buffer = kmalloc(count + 1, GFP_KERNEL);
404 if (!tmp_buffer)
405 return -ENOMEM;
406
407 if (copy_from_user(tmp_buffer, buffer, count)) {
408 result = -EFAULT;
409 } else {
410 tmp_buffer[count] = 0;
411 result = item->write_func(tmp_buffer, count);
412 }
413 kfree(tmp_buffer);
414 return result;
415}
416
417static int get_lcd(struct backlight_device *bd) 396static int get_lcd(struct backlight_device *bd)
418{ 397{
419 u32 hci_result; 398 u32 hci_result;
@@ -426,19 +405,24 @@ static int get_lcd(struct backlight_device *bd)
426 return -EFAULT; 405 return -EFAULT;
427} 406}
428 407
429static char *read_lcd(char *p) 408static int lcd_proc_show(struct seq_file *m, void *v)
430{ 409{
431 int value = get_lcd(NULL); 410 int value = get_lcd(NULL);
432 411
433 if (value >= 0) { 412 if (value >= 0) {
434 p += sprintf(p, "brightness: %d\n", value); 413 seq_printf(m, "brightness: %d\n", value);
435 p += sprintf(p, "brightness_levels: %d\n", 414 seq_printf(m, "brightness_levels: %d\n",
436 HCI_LCD_BRIGHTNESS_LEVELS); 415 HCI_LCD_BRIGHTNESS_LEVELS);
437 } else { 416 } else {
438 printk(MY_ERR "Error reading LCD brightness\n"); 417 printk(MY_ERR "Error reading LCD brightness\n");
439 } 418 }
440 419
441 return p; 420 return 0;
421}
422
423static int lcd_proc_open(struct inode *inode, struct file *file)
424{
425 return single_open(file, lcd_proc_show, NULL);
442} 426}
443 427
444static int set_lcd(int value) 428static int set_lcd(int value)
@@ -458,12 +442,20 @@ static int set_lcd_status(struct backlight_device *bd)
458 return set_lcd(bd->props.brightness); 442 return set_lcd(bd->props.brightness);
459} 443}
460 444
461static unsigned long write_lcd(const char *buffer, unsigned long count) 445static ssize_t lcd_proc_write(struct file *file, const char __user *buf,
446 size_t count, loff_t *pos)
462{ 447{
448 char cmd[42];
449 size_t len;
463 int value; 450 int value;
464 int ret; 451 int ret;
465 452
466 if (sscanf(buffer, " brightness : %i", &value) == 1 && 453 len = min(count, sizeof(cmd) - 1);
454 if (copy_from_user(cmd, buf, len))
455 return -EFAULT;
456 cmd[len] = '\0';
457
458 if (sscanf(cmd, " brightness : %i", &value) == 1 &&
467 value >= 0 && value < HCI_LCD_BRIGHTNESS_LEVELS) { 459 value >= 0 && value < HCI_LCD_BRIGHTNESS_LEVELS) {
468 ret = set_lcd(value); 460 ret = set_lcd(value);
469 if (ret == 0) 461 if (ret == 0)
@@ -474,7 +466,16 @@ static unsigned long write_lcd(const char *buffer, unsigned long count)
474 return ret; 466 return ret;
475} 467}
476 468
477static char *read_video(char *p) 469static const struct file_operations lcd_proc_fops = {
470 .owner = THIS_MODULE,
471 .open = lcd_proc_open,
472 .read = seq_read,
473 .llseek = seq_lseek,
474 .release = single_release,
475 .write = lcd_proc_write,
476};
477
478static int video_proc_show(struct seq_file *m, void *v)
478{ 479{
479 u32 hci_result; 480 u32 hci_result;
480 u32 value; 481 u32 value;
@@ -484,18 +485,25 @@ static char *read_video(char *p)
484 int is_lcd = (value & HCI_VIDEO_OUT_LCD) ? 1 : 0; 485 int is_lcd = (value & HCI_VIDEO_OUT_LCD) ? 1 : 0;
485 int is_crt = (value & HCI_VIDEO_OUT_CRT) ? 1 : 0; 486 int is_crt = (value & HCI_VIDEO_OUT_CRT) ? 1 : 0;
486 int is_tv = (value & HCI_VIDEO_OUT_TV) ? 1 : 0; 487 int is_tv = (value & HCI_VIDEO_OUT_TV) ? 1 : 0;
487 p += sprintf(p, "lcd_out: %d\n", is_lcd); 488 seq_printf(m, "lcd_out: %d\n", is_lcd);
488 p += sprintf(p, "crt_out: %d\n", is_crt); 489 seq_printf(m, "crt_out: %d\n", is_crt);
489 p += sprintf(p, "tv_out: %d\n", is_tv); 490 seq_printf(m, "tv_out: %d\n", is_tv);
490 } else { 491 } else {
491 printk(MY_ERR "Error reading video out status\n"); 492 printk(MY_ERR "Error reading video out status\n");
492 } 493 }
493 494
494 return p; 495 return 0;
495} 496}
496 497
497static unsigned long write_video(const char *buffer, unsigned long count) 498static int video_proc_open(struct inode *inode, struct file *file)
498{ 499{
500 return single_open(file, video_proc_show, NULL);
501}
502
503static ssize_t video_proc_write(struct file *file, const char __user *buf,
504 size_t count, loff_t *pos)
505{
506 char *cmd, *buffer;
499 int value; 507 int value;
500 int remain = count; 508 int remain = count;
501 int lcd_out = -1; 509 int lcd_out = -1;
@@ -504,6 +512,17 @@ static unsigned long write_video(const char *buffer, unsigned long count)
504 u32 hci_result; 512 u32 hci_result;
505 u32 video_out; 513 u32 video_out;
506 514
515 cmd = kmalloc(count + 1, GFP_KERNEL);
516 if (!cmd)
517 return -ENOMEM;
518 if (copy_from_user(cmd, buf, count)) {
519 kfree(cmd);
520 return -EFAULT;
521 }
522 cmd[count] = '\0';
523
524 buffer = cmd;
525
507 /* scan expression. Multiple expressions may be delimited with ; 526 /* scan expression. Multiple expressions may be delimited with ;
508 * 527 *
509 * NOTE: to keep scanning simple, invalid fields are ignored 528 * NOTE: to keep scanning simple, invalid fields are ignored
@@ -523,6 +542,8 @@ static unsigned long write_video(const char *buffer, unsigned long count)
523 while (remain && *(buffer - 1) != ';'); 542 while (remain && *(buffer - 1) != ';');
524 } 543 }
525 544
545 kfree(cmd);
546
526 hci_read1(HCI_VIDEO_OUT, &video_out, &hci_result); 547 hci_read1(HCI_VIDEO_OUT, &video_out, &hci_result);
527 if (hci_result == HCI_SUCCESS) { 548 if (hci_result == HCI_SUCCESS) {
528 unsigned int new_video_out = video_out; 549 unsigned int new_video_out = video_out;
@@ -543,28 +564,50 @@ static unsigned long write_video(const char *buffer, unsigned long count)
543 return count; 564 return count;
544} 565}
545 566
546static char *read_fan(char *p) 567static const struct file_operations video_proc_fops = {
568 .owner = THIS_MODULE,
569 .open = video_proc_open,
570 .read = seq_read,
571 .llseek = seq_lseek,
572 .release = single_release,
573 .write = video_proc_write,
574};
575
576static int fan_proc_show(struct seq_file *m, void *v)
547{ 577{
548 u32 hci_result; 578 u32 hci_result;
549 u32 value; 579 u32 value;
550 580
551 hci_read1(HCI_FAN, &value, &hci_result); 581 hci_read1(HCI_FAN, &value, &hci_result);
552 if (hci_result == HCI_SUCCESS) { 582 if (hci_result == HCI_SUCCESS) {
553 p += sprintf(p, "running: %d\n", (value > 0)); 583 seq_printf(m, "running: %d\n", (value > 0));
554 p += sprintf(p, "force_on: %d\n", force_fan); 584 seq_printf(m, "force_on: %d\n", force_fan);
555 } else { 585 } else {
556 printk(MY_ERR "Error reading fan status\n"); 586 printk(MY_ERR "Error reading fan status\n");
557 } 587 }
558 588
559 return p; 589 return 0;
590}
591
592static int fan_proc_open(struct inode *inode, struct file *file)
593{
594 return single_open(file, fan_proc_show, NULL);
560} 595}
561 596
562static unsigned long write_fan(const char *buffer, unsigned long count) 597static ssize_t fan_proc_write(struct file *file, const char __user *buf,
598 size_t count, loff_t *pos)
563{ 599{
600 char cmd[42];
601 size_t len;
564 int value; 602 int value;
565 u32 hci_result; 603 u32 hci_result;
566 604
567 if (sscanf(buffer, " force_on : %i", &value) == 1 && 605 len = min(count, sizeof(cmd) - 1);
606 if (copy_from_user(cmd, buf, len))
607 return -EFAULT;
608 cmd[len] = '\0';
609
610 if (sscanf(cmd, " force_on : %i", &value) == 1 &&
568 value >= 0 && value <= 1) { 611 value >= 0 && value <= 1) {
569 hci_write1(HCI_FAN, value, &hci_result); 612 hci_write1(HCI_FAN, value, &hci_result);
570 if (hci_result != HCI_SUCCESS) 613 if (hci_result != HCI_SUCCESS)
@@ -578,7 +621,16 @@ static unsigned long write_fan(const char *buffer, unsigned long count)
578 return count; 621 return count;
579} 622}
580 623
581static char *read_keys(char *p) 624static const struct file_operations fan_proc_fops = {
625 .owner = THIS_MODULE,
626 .open = fan_proc_open,
627 .read = seq_read,
628 .llseek = seq_lseek,
629 .release = single_release,
630 .write = fan_proc_write,
631};
632
633static int keys_proc_show(struct seq_file *m, void *v)
582{ 634{
583 u32 hci_result; 635 u32 hci_result;
584 u32 value; 636 u32 value;
@@ -602,18 +654,30 @@ static char *read_keys(char *p)
602 } 654 }
603 } 655 }
604 656
605 p += sprintf(p, "hotkey_ready: %d\n", key_event_valid); 657 seq_printf(m, "hotkey_ready: %d\n", key_event_valid);
606 p += sprintf(p, "hotkey: 0x%04x\n", last_key_event); 658 seq_printf(m, "hotkey: 0x%04x\n", last_key_event);
659end:
660 return 0;
661}
607 662
608 end: 663static int keys_proc_open(struct inode *inode, struct file *file)
609 return p; 664{
665 return single_open(file, keys_proc_show, NULL);
610} 666}
611 667
612static unsigned long write_keys(const char *buffer, unsigned long count) 668static ssize_t keys_proc_write(struct file *file, const char __user *buf,
669 size_t count, loff_t *pos)
613{ 670{
671 char cmd[42];
672 size_t len;
614 int value; 673 int value;
615 674
616 if (sscanf(buffer, " hotkey_ready : %i", &value) == 1 && value == 0) { 675 len = min(count, sizeof(cmd) - 1);
676 if (copy_from_user(cmd, buf, len))
677 return -EFAULT;
678 cmd[len] = '\0';
679
680 if (sscanf(cmd, " hotkey_ready : %i", &value) == 1 && value == 0) {
617 key_event_valid = 0; 681 key_event_valid = 0;
618 } else { 682 } else {
619 return -EINVAL; 683 return -EINVAL;
@@ -622,52 +686,58 @@ static unsigned long write_keys(const char *buffer, unsigned long count)
622 return count; 686 return count;
623} 687}
624 688
625static char *read_version(char *p) 689static const struct file_operations keys_proc_fops = {
690 .owner = THIS_MODULE,
691 .open = keys_proc_open,
692 .read = seq_read,
693 .llseek = seq_lseek,
694 .release = single_release,
695 .write = keys_proc_write,
696};
697
698static int version_proc_show(struct seq_file *m, void *v)
699{
700 seq_printf(m, "driver: %s\n", TOSHIBA_ACPI_VERSION);
701 seq_printf(m, "proc_interface: %d\n", PROC_INTERFACE_VERSION);
702 return 0;
703}
704
705static int version_proc_open(struct inode *inode, struct file *file)
626{ 706{
627 p += sprintf(p, "driver: %s\n", TOSHIBA_ACPI_VERSION); 707 return single_open(file, version_proc_show, PDE(inode)->data);
628 p += sprintf(p, "proc_interface: %d\n",
629 PROC_INTERFACE_VERSION);
630 return p;
631} 708}
632 709
710static const struct file_operations version_proc_fops = {
711 .owner = THIS_MODULE,
712 .open = version_proc_open,
713 .read = seq_read,
714 .llseek = seq_lseek,
715 .release = single_release,
716};
717
633/* proc and module init 718/* proc and module init
634 */ 719 */
635 720
636#define PROC_TOSHIBA "toshiba" 721#define PROC_TOSHIBA "toshiba"
637 722
638static ProcItem proc_items[] = {
639 {"lcd", read_lcd, write_lcd},
640 {"video", read_video, write_video},
641 {"fan", read_fan, write_fan},
642 {"keys", read_keys, write_keys},
643 {"version", read_version, NULL},
644 {NULL}
645};
646
647static acpi_status __init add_device(void) 723static acpi_status __init add_device(void)
648{ 724{
649 struct proc_dir_entry *proc; 725 proc_create("lcd", S_IRUGO | S_IWUSR, toshiba_proc_dir, &lcd_proc_fops);
650 ProcItem *item; 726 proc_create("video", S_IRUGO | S_IWUSR, toshiba_proc_dir, &video_proc_fops);
651 727 proc_create("fan", S_IRUGO | S_IWUSR, toshiba_proc_dir, &fan_proc_fops);
652 for (item = proc_items; item->name; ++item) { 728 proc_create("keys", S_IRUGO | S_IWUSR, toshiba_proc_dir, &keys_proc_fops);
653 proc = create_proc_read_entry(item->name, 729 proc_create("version", S_IRUGO, toshiba_proc_dir, &version_proc_fops);
654 S_IFREG | S_IRUGO | S_IWUSR,
655 toshiba_proc_dir,
656 (read_proc_t *) dispatch_read,
657 item);
658 if (proc && item->write_func)
659 proc->write_proc = (write_proc_t *) dispatch_write;
660 }
661 730
662 return AE_OK; 731 return AE_OK;
663} 732}
664 733
665static acpi_status remove_device(void) 734static acpi_status remove_device(void)
666{ 735{
667 ProcItem *item; 736 remove_proc_entry("lcd", toshiba_proc_dir);
668 737 remove_proc_entry("video", toshiba_proc_dir);
669 for (item = proc_items; item->name; ++item) 738 remove_proc_entry("fan", toshiba_proc_dir);
670 remove_proc_entry(item->name, toshiba_proc_dir); 739 remove_proc_entry("keys", toshiba_proc_dir);
740 remove_proc_entry("version", toshiba_proc_dir);
671 return AE_OK; 741 return AE_OK;
672} 742}
673 743
@@ -676,8 +746,158 @@ static struct backlight_ops toshiba_backlight_data = {
676 .update_status = set_lcd_status, 746 .update_status = set_lcd_status,
677}; 747};
678 748
749static struct key_entry *toshiba_acpi_get_entry_by_scancode(unsigned int code)
750{
751 struct key_entry *key;
752
753 for (key = toshiba_acpi_keymap; key->type != KE_END; key++)
754 if (code == key->code)
755 return key;
756
757 return NULL;
758}
759
760static struct key_entry *toshiba_acpi_get_entry_by_keycode(unsigned int code)
761{
762 struct key_entry *key;
763
764 for (key = toshiba_acpi_keymap; key->type != KE_END; key++)
765 if (code == key->keycode && key->type == KE_KEY)
766 return key;
767
768 return NULL;
769}
770
771static int toshiba_acpi_getkeycode(struct input_dev *dev,
772 unsigned int scancode, unsigned int *keycode)
773{
774 struct key_entry *key = toshiba_acpi_get_entry_by_scancode(scancode);
775
776 if (key && key->type == KE_KEY) {
777 *keycode = key->keycode;
778 return 0;
779 }
780
781 return -EINVAL;
782}
783
784static int toshiba_acpi_setkeycode(struct input_dev *dev,
785 unsigned int scancode, unsigned int keycode)
786{
787 struct key_entry *key;
788 unsigned int old_keycode;
789
790 key = toshiba_acpi_get_entry_by_scancode(scancode);
791 if (key && key->type == KE_KEY) {
792 old_keycode = key->keycode;
793 key->keycode = keycode;
794 set_bit(keycode, dev->keybit);
795 if (!toshiba_acpi_get_entry_by_keycode(old_keycode))
796 clear_bit(old_keycode, dev->keybit);
797 return 0;
798 }
799
800 return -EINVAL;
801}
802
803static void toshiba_acpi_notify(acpi_handle handle, u32 event, void *context)
804{
805 u32 hci_result, value;
806 struct key_entry *key;
807
808 if (event != 0x80)
809 return;
810 do {
811 hci_read1(HCI_SYSTEM_EVENT, &value, &hci_result);
812 if (hci_result == HCI_SUCCESS) {
813 if (value == 0x100)
814 continue;
815 /* act on key press; ignore key release */
816 if (value & 0x80)
817 continue;
818
819 key = toshiba_acpi_get_entry_by_scancode
820 (value);
821 if (!key) {
822 printk(MY_INFO "Unknown key %x\n",
823 value);
824 continue;
825 }
826 input_report_key(toshiba_acpi.hotkey_dev,
827 key->keycode, 1);
828 input_sync(toshiba_acpi.hotkey_dev);
829 input_report_key(toshiba_acpi.hotkey_dev,
830 key->keycode, 0);
831 input_sync(toshiba_acpi.hotkey_dev);
832 } else if (hci_result == HCI_NOT_SUPPORTED) {
833 /* This is a workaround for an unresolved issue on
834 * some machines where system events sporadically
835 * become disabled. */
836 hci_write1(HCI_SYSTEM_EVENT, 1, &hci_result);
837 printk(MY_NOTICE "Re-enabled hotkeys\n");
838 }
839 } while (hci_result != HCI_EMPTY);
840}
841
842static int toshiba_acpi_setup_keyboard(char *device)
843{
844 acpi_status status;
845 acpi_handle handle;
846 int result;
847 const struct key_entry *key;
848
849 status = acpi_get_handle(NULL, device, &handle);
850 if (ACPI_FAILURE(status)) {
851 printk(MY_INFO "Unable to get notification device\n");
852 return -ENODEV;
853 }
854
855 toshiba_acpi.handle = handle;
856
857 status = acpi_evaluate_object(handle, "ENAB", NULL, NULL);
858 if (ACPI_FAILURE(status)) {
859 printk(MY_INFO "Unable to enable hotkeys\n");
860 return -ENODEV;
861 }
862
863 status = acpi_install_notify_handler(handle, ACPI_DEVICE_NOTIFY,
864 toshiba_acpi_notify, NULL);
865 if (ACPI_FAILURE(status)) {
866 printk(MY_INFO "Unable to install hotkey notification\n");
867 return -ENODEV;
868 }
869
870 toshiba_acpi.hotkey_dev = input_allocate_device();
871 if (!toshiba_acpi.hotkey_dev) {
872 printk(MY_INFO "Unable to register input device\n");
873 return -ENOMEM;
874 }
875
876 toshiba_acpi.hotkey_dev->name = "Toshiba input device";
877 toshiba_acpi.hotkey_dev->phys = device;
878 toshiba_acpi.hotkey_dev->id.bustype = BUS_HOST;
879 toshiba_acpi.hotkey_dev->getkeycode = toshiba_acpi_getkeycode;
880 toshiba_acpi.hotkey_dev->setkeycode = toshiba_acpi_setkeycode;
881
882 for (key = toshiba_acpi_keymap; key->type != KE_END; key++) {
883 set_bit(EV_KEY, toshiba_acpi.hotkey_dev->evbit);
884 set_bit(key->keycode, toshiba_acpi.hotkey_dev->keybit);
885 }
886
887 result = input_register_device(toshiba_acpi.hotkey_dev);
888 if (result) {
889 printk(MY_INFO "Unable to register input device\n");
890 return result;
891 }
892
893 return 0;
894}
895
679static void toshiba_acpi_exit(void) 896static void toshiba_acpi_exit(void)
680{ 897{
898 if (toshiba_acpi.hotkey_dev)
899 input_unregister_device(toshiba_acpi.hotkey_dev);
900
681 if (toshiba_acpi.bt_rfk) { 901 if (toshiba_acpi.bt_rfk) {
682 rfkill_unregister(toshiba_acpi.bt_rfk); 902 rfkill_unregister(toshiba_acpi.bt_rfk);
683 rfkill_destroy(toshiba_acpi.bt_rfk); 903 rfkill_destroy(toshiba_acpi.bt_rfk);
@@ -691,6 +911,9 @@ static void toshiba_acpi_exit(void)
691 if (toshiba_proc_dir) 911 if (toshiba_proc_dir)
692 remove_proc_entry(PROC_TOSHIBA, acpi_root_dir); 912 remove_proc_entry(PROC_TOSHIBA, acpi_root_dir);
693 913
914 acpi_remove_notify_handler(toshiba_acpi.handle, ACPI_DEVICE_NOTIFY,
915 toshiba_acpi_notify);
916
694 platform_device_unregister(toshiba_acpi.p_dev); 917 platform_device_unregister(toshiba_acpi.p_dev);
695 918
696 return; 919 return;
@@ -702,16 +925,21 @@ static int __init toshiba_acpi_init(void)
702 u32 hci_result; 925 u32 hci_result;
703 bool bt_present; 926 bool bt_present;
704 int ret = 0; 927 int ret = 0;
928 struct backlight_properties props;
705 929
706 if (acpi_disabled) 930 if (acpi_disabled)
707 return -ENODEV; 931 return -ENODEV;
708 932
709 /* simple device detection: look for HCI method */ 933 /* simple device detection: look for HCI method */
710 if (is_valid_acpi_path(METHOD_HCI_1)) 934 if (is_valid_acpi_path(TOSH_INTERFACE_1 GHCI_METHOD)) {
711 method_hci = METHOD_HCI_1; 935 method_hci = TOSH_INTERFACE_1 GHCI_METHOD;
712 else if (is_valid_acpi_path(METHOD_HCI_2)) 936 if (toshiba_acpi_setup_keyboard(TOSH_INTERFACE_1))
713 method_hci = METHOD_HCI_2; 937 printk(MY_INFO "Unable to activate hotkeys\n");
714 else 938 } else if (is_valid_acpi_path(TOSH_INTERFACE_2 GHCI_METHOD)) {
939 method_hci = TOSH_INTERFACE_2 GHCI_METHOD;
940 if (toshiba_acpi_setup_keyboard(TOSH_INTERFACE_2))
941 printk(MY_INFO "Unable to activate hotkeys\n");
942 } else
715 return -ENODEV; 943 return -ENODEV;
716 944
717 printk(MY_INFO "Toshiba Laptop ACPI Extras version %s\n", 945 printk(MY_INFO "Toshiba Laptop ACPI Extras version %s\n",
@@ -748,10 +976,12 @@ static int __init toshiba_acpi_init(void)
748 } 976 }
749 } 977 }
750 978
979 props.max_brightness = HCI_LCD_BRIGHTNESS_LEVELS - 1;
751 toshiba_backlight_device = backlight_device_register("toshiba", 980 toshiba_backlight_device = backlight_device_register("toshiba",
752 &toshiba_acpi.p_dev->dev, 981 &toshiba_acpi.p_dev->dev,
753 NULL, 982 NULL,
754 &toshiba_backlight_data); 983 &toshiba_backlight_data,
984 &props);
755 if (IS_ERR(toshiba_backlight_device)) { 985 if (IS_ERR(toshiba_backlight_device)) {
756 ret = PTR_ERR(toshiba_backlight_device); 986 ret = PTR_ERR(toshiba_backlight_device);
757 987
@@ -760,7 +990,6 @@ static int __init toshiba_acpi_init(void)
760 toshiba_acpi_exit(); 990 toshiba_acpi_exit();
761 return ret; 991 return ret;
762 } 992 }
763 toshiba_backlight_device->props.max_brightness = HCI_LCD_BRIGHTNESS_LEVELS - 1;
764 993
765 /* Register rfkill switch for Bluetooth */ 994 /* Register rfkill switch for Bluetooth */
766 if (hci_get_bt_present(&bt_present) == HCI_SUCCESS && bt_present) { 995 if (hci_get_bt_present(&bt_present) == HCI_SUCCESS && bt_present) {
diff --git a/drivers/platform/x86/toshiba_bluetooth.c b/drivers/platform/x86/toshiba_bluetooth.c
new file mode 100644
index 000000000000..944068611919
--- /dev/null
+++ b/drivers/platform/x86/toshiba_bluetooth.c
@@ -0,0 +1,144 @@
1/*
2 * Toshiba Bluetooth Enable Driver
3 *
4 * Copyright (C) 2009 Jes Sorensen <Jes.Sorensen@gmail.com>
5 *
6 * Thanks to Matthew Garrett for background info on ACPI innards which
7 * normal people aren't meant to understand :-)
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 version 2 as
11 * published by the Free Software Foundation.
12 *
13 * Note the Toshiba Bluetooth RFKill switch seems to be a strange
14 * fish. It only provides a BT event when the switch is flipped to
15 * the 'on' position. When flipping it to 'off', the USB device is
16 * simply pulled away underneath us, without any BT event being
17 * delivered.
18 */
19
20#include <linux/kernel.h>
21#include <linux/module.h>
22#include <linux/init.h>
23#include <linux/types.h>
24#include <acpi/acpi_bus.h>
25#include <acpi/acpi_drivers.h>
26
27MODULE_AUTHOR("Jes Sorensen <Jes.Sorensen@gmail.com>");
28MODULE_DESCRIPTION("Toshiba Laptop ACPI Bluetooth Enable Driver");
29MODULE_LICENSE("GPL");
30
31
32static int toshiba_bt_rfkill_add(struct acpi_device *device);
33static int toshiba_bt_rfkill_remove(struct acpi_device *device, int type);
34static void toshiba_bt_rfkill_notify(struct acpi_device *device, u32 event);
35static int toshiba_bt_resume(struct acpi_device *device);
36
37static const struct acpi_device_id bt_device_ids[] = {
38 { "TOS6205", 0},
39 { "", 0},
40};
41MODULE_DEVICE_TABLE(acpi, bt_device_ids);
42
43static struct acpi_driver toshiba_bt_rfkill_driver = {
44 .name = "Toshiba BT",
45 .class = "Toshiba",
46 .ids = bt_device_ids,
47 .ops = {
48 .add = toshiba_bt_rfkill_add,
49 .remove = toshiba_bt_rfkill_remove,
50 .notify = toshiba_bt_rfkill_notify,
51 .resume = toshiba_bt_resume,
52 },
53 .owner = THIS_MODULE,
54};
55
56
57static int toshiba_bluetooth_enable(acpi_handle handle)
58{
59 acpi_status res1, res2;
60 u64 result;
61
62 /*
63 * Query ACPI to verify RFKill switch is set to 'on'.
64 * If not, we return silently, no need to report it as
65 * an error.
66 */
67 res1 = acpi_evaluate_integer(handle, "BTST", NULL, &result);
68 if (ACPI_FAILURE(res1))
69 return res1;
70 if (!(result & 0x01))
71 return 0;
72
73 printk(KERN_INFO "toshiba_bluetooth: Re-enabling Toshiba Bluetooth\n");
74 res1 = acpi_evaluate_object(handle, "AUSB", NULL, NULL);
75 res2 = acpi_evaluate_object(handle, "BTPO", NULL, NULL);
76 if (!ACPI_FAILURE(res1) || !ACPI_FAILURE(res2))
77 return 0;
78
79 printk(KERN_WARNING "toshiba_bluetooth: Failed to re-enable "
80 "Toshiba Bluetooth\n");
81
82 return -ENODEV;
83}
84
85static void toshiba_bt_rfkill_notify(struct acpi_device *device, u32 event)
86{
87 toshiba_bluetooth_enable(device->handle);
88}
89
90static int toshiba_bt_resume(struct acpi_device *device)
91{
92 return toshiba_bluetooth_enable(device->handle);
93}
94
95static int toshiba_bt_rfkill_add(struct acpi_device *device)
96{
97 acpi_status status;
98 u64 bt_present;
99 int result = -ENODEV;
100
101 /*
102 * Some Toshiba laptops may have a fake TOS6205 device in
103 * their ACPI BIOS, so query the _STA method to see if there
104 * is really anything there, before trying to enable it.
105 */
106 status = acpi_evaluate_integer(device->handle, "_STA", NULL,
107 &bt_present);
108
109 if (!ACPI_FAILURE(status) && bt_present) {
110 printk(KERN_INFO "Detected Toshiba ACPI Bluetooth device - "
111 "installing RFKill handler\n");
112 result = toshiba_bluetooth_enable(device->handle);
113 }
114
115 return result;
116}
117
118static int __init toshiba_bt_rfkill_init(void)
119{
120 int result;
121
122 result = acpi_bus_register_driver(&toshiba_bt_rfkill_driver);
123 if (result < 0) {
124 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
125 "Error registering driver\n"));
126 return result;
127 }
128
129 return 0;
130}
131
132static int toshiba_bt_rfkill_remove(struct acpi_device *device, int type)
133{
134 /* clean up */
135 return 0;
136}
137
138static void __exit toshiba_bt_rfkill_exit(void)
139{
140 acpi_bus_unregister_driver(&toshiba_bt_rfkill_driver);
141}
142
143module_init(toshiba_bt_rfkill_init);
144module_exit(toshiba_bt_rfkill_exit);
diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c
index 177f8d767df4..39ec5b6c2e3a 100644
--- a/drivers/platform/x86/wmi.c
+++ b/drivers/platform/x86/wmi.c
@@ -30,8 +30,10 @@
30#include <linux/kernel.h> 30#include <linux/kernel.h>
31#include <linux/init.h> 31#include <linux/init.h>
32#include <linux/types.h> 32#include <linux/types.h>
33#include <linux/device.h>
33#include <linux/list.h> 34#include <linux/list.h>
34#include <linux/acpi.h> 35#include <linux/acpi.h>
36#include <linux/slab.h>
35#include <acpi/acpi_bus.h> 37#include <acpi/acpi_bus.h>
36#include <acpi/acpi_drivers.h> 38#include <acpi/acpi_drivers.h>
37 39
@@ -65,6 +67,7 @@ struct wmi_block {
65 acpi_handle handle; 67 acpi_handle handle;
66 wmi_notify_handler handler; 68 wmi_notify_handler handler;
67 void *handler_data; 69 void *handler_data;
70 struct device *dev;
68}; 71};
69 72
70static struct wmi_block wmi_blocks; 73static struct wmi_block wmi_blocks;
@@ -195,6 +198,34 @@ static bool wmi_parse_guid(const u8 *src, u8 *dest)
195 return true; 198 return true;
196} 199}
197 200
201/*
202 * Convert a raw GUID to the ACII string representation
203 */
204static int wmi_gtoa(const char *in, char *out)
205{
206 int i;
207
208 for (i = 3; i >= 0; i--)
209 out += sprintf(out, "%02X", in[i] & 0xFF);
210
211 out += sprintf(out, "-");
212 out += sprintf(out, "%02X", in[5] & 0xFF);
213 out += sprintf(out, "%02X", in[4] & 0xFF);
214 out += sprintf(out, "-");
215 out += sprintf(out, "%02X", in[7] & 0xFF);
216 out += sprintf(out, "%02X", in[6] & 0xFF);
217 out += sprintf(out, "-");
218 out += sprintf(out, "%02X", in[8] & 0xFF);
219 out += sprintf(out, "%02X", in[9] & 0xFF);
220 out += sprintf(out, "-");
221
222 for (i = 10; i <= 15; i++)
223 out += sprintf(out, "%02X", in[i] & 0xFF);
224
225 out = '\0';
226 return 0;
227}
228
198static bool find_guid(const char *guid_string, struct wmi_block **out) 229static bool find_guid(const char *guid_string, struct wmi_block **out)
199{ 230{
200 char tmp[16], guid_input[16]; 231 char tmp[16], guid_input[16];
@@ -462,8 +493,7 @@ wmi_notify_handler handler, void *data)
462 if (!guid || !handler) 493 if (!guid || !handler)
463 return AE_BAD_PARAMETER; 494 return AE_BAD_PARAMETER;
464 495
465 find_guid(guid, &block); 496 if (!find_guid(guid, &block))
466 if (!block)
467 return AE_NOT_EXIST; 497 return AE_NOT_EXIST;
468 498
469 if (block->handler) 499 if (block->handler)
@@ -491,8 +521,7 @@ acpi_status wmi_remove_notify_handler(const char *guid)
491 if (!guid) 521 if (!guid)
492 return AE_BAD_PARAMETER; 522 return AE_BAD_PARAMETER;
493 523
494 find_guid(guid, &block); 524 if (!find_guid(guid, &block))
495 if (!block)
496 return AE_NOT_EXIST; 525 return AE_NOT_EXIST;
497 526
498 if (!block->handler) 527 if (!block->handler)
@@ -510,8 +539,8 @@ EXPORT_SYMBOL_GPL(wmi_remove_notify_handler);
510/** 539/**
511 * wmi_get_event_data - Get WMI data associated with an event 540 * wmi_get_event_data - Get WMI data associated with an event
512 * 541 *
513 * @event - Event to find 542 * @event: Event to find
514 * &out - Buffer to hold event data 543 * @out: Buffer to hold event data. out->pointer should be freed with kfree()
515 * 544 *
516 * Returns extra data associated with an event in WMI. 545 * Returns extra data associated with an event in WMI.
517 */ 546 */
@@ -555,6 +584,154 @@ bool wmi_has_guid(const char *guid_string)
555EXPORT_SYMBOL_GPL(wmi_has_guid); 584EXPORT_SYMBOL_GPL(wmi_has_guid);
556 585
557/* 586/*
587 * sysfs interface
588 */
589static ssize_t show_modalias(struct device *dev, struct device_attribute *attr,
590 char *buf)
591{
592 char guid_string[37];
593 struct wmi_block *wblock;
594
595 wblock = dev_get_drvdata(dev);
596 if (!wblock)
597 return -ENOMEM;
598
599 wmi_gtoa(wblock->gblock.guid, guid_string);
600
601 return sprintf(buf, "wmi:%s\n", guid_string);
602}
603static DEVICE_ATTR(modalias, S_IRUGO, show_modalias, NULL);
604
605static int wmi_dev_uevent(struct device *dev, struct kobj_uevent_env *env)
606{
607 char guid_string[37];
608
609 struct wmi_block *wblock;
610
611 if (add_uevent_var(env, "MODALIAS="))
612 return -ENOMEM;
613
614 wblock = dev_get_drvdata(dev);
615 if (!wblock)
616 return -ENOMEM;
617
618 wmi_gtoa(wblock->gblock.guid, guid_string);
619
620 strcpy(&env->buf[env->buflen - 1], "wmi:");
621 memcpy(&env->buf[env->buflen - 1 + 4], guid_string, 36);
622 env->buflen += 40;
623
624 return 0;
625}
626
627static void wmi_dev_free(struct device *dev)
628{
629 kfree(dev);
630}
631
632static struct class wmi_class = {
633 .name = "wmi",
634 .dev_release = wmi_dev_free,
635 .dev_uevent = wmi_dev_uevent,
636};
637
638static int wmi_create_devs(void)
639{
640 int result;
641 char guid_string[37];
642 struct guid_block *gblock;
643 struct wmi_block *wblock;
644 struct list_head *p;
645 struct device *guid_dev;
646
647 /* Create devices for all the GUIDs */
648 list_for_each(p, &wmi_blocks.list) {
649 wblock = list_entry(p, struct wmi_block, list);
650
651 guid_dev = kzalloc(sizeof(struct device), GFP_KERNEL);
652 if (!guid_dev)
653 return -ENOMEM;
654
655 wblock->dev = guid_dev;
656
657 guid_dev->class = &wmi_class;
658 dev_set_drvdata(guid_dev, wblock);
659
660 gblock = &wblock->gblock;
661
662 wmi_gtoa(gblock->guid, guid_string);
663 dev_set_name(guid_dev, guid_string);
664
665 result = device_register(guid_dev);
666 if (result)
667 return result;
668
669 result = device_create_file(guid_dev, &dev_attr_modalias);
670 if (result)
671 return result;
672 }
673
674 return 0;
675}
676
677static void wmi_remove_devs(void)
678{
679 struct guid_block *gblock;
680 struct wmi_block *wblock;
681 struct list_head *p;
682 struct device *guid_dev;
683
684 /* Delete devices for all the GUIDs */
685 list_for_each(p, &wmi_blocks.list) {
686 wblock = list_entry(p, struct wmi_block, list);
687
688 guid_dev = wblock->dev;
689 gblock = &wblock->gblock;
690
691 device_remove_file(guid_dev, &dev_attr_modalias);
692
693 device_unregister(guid_dev);
694 }
695}
696
697static void wmi_class_exit(void)
698{
699 wmi_remove_devs();
700 class_unregister(&wmi_class);
701}
702
703static int wmi_class_init(void)
704{
705 int ret;
706
707 ret = class_register(&wmi_class);
708 if (ret)
709 return ret;
710
711 ret = wmi_create_devs();
712 if (ret)
713 wmi_class_exit();
714
715 return ret;
716}
717
718static bool guid_already_parsed(const char *guid_string)
719{
720 struct guid_block *gblock;
721 struct wmi_block *wblock;
722 struct list_head *p;
723
724 list_for_each(p, &wmi_blocks.list) {
725 wblock = list_entry(p, struct wmi_block, list);
726 gblock = &wblock->gblock;
727
728 if (strncmp(gblock->guid, guid_string, 16) == 0)
729 return true;
730 }
731 return false;
732}
733
734/*
558 * Parse the _WDG method for the GUID data blocks 735 * Parse the _WDG method for the GUID data blocks
559 */ 736 */
560static __init acpi_status parse_wdg(acpi_handle handle) 737static __init acpi_status parse_wdg(acpi_handle handle)
@@ -563,6 +740,7 @@ static __init acpi_status parse_wdg(acpi_handle handle)
563 union acpi_object *obj; 740 union acpi_object *obj;
564 struct guid_block *gblock; 741 struct guid_block *gblock;
565 struct wmi_block *wblock; 742 struct wmi_block *wblock;
743 char guid_string[37];
566 acpi_status status; 744 acpi_status status;
567 u32 i, total; 745 u32 i, total;
568 746
@@ -585,6 +763,19 @@ static __init acpi_status parse_wdg(acpi_handle handle)
585 memcpy(gblock, obj->buffer.pointer, obj->buffer.length); 763 memcpy(gblock, obj->buffer.pointer, obj->buffer.length);
586 764
587 for (i = 0; i < total; i++) { 765 for (i = 0; i < total; i++) {
766 /*
767 Some WMI devices, like those for nVidia hooks, have a
768 duplicate GUID. It's not clear what we should do in this
769 case yet, so for now, we'll just ignore the duplicate.
770 Anyone who wants to add support for that device can come
771 up with a better workaround for the mess then.
772 */
773 if (guid_already_parsed(gblock[i].guid) == true) {
774 wmi_gtoa(gblock[i].guid, guid_string);
775 printk(KERN_INFO PREFIX "Skipping duplicate GUID %s\n",
776 guid_string);
777 continue;
778 }
588 wblock = kzalloc(sizeof(struct wmi_block), GFP_KERNEL); 779 wblock = kzalloc(sizeof(struct wmi_block), GFP_KERNEL);
589 if (!wblock) 780 if (!wblock)
590 return AE_NO_MEMORY; 781 return AE_NO_MEMORY;
@@ -606,7 +797,7 @@ static __init acpi_status parse_wdg(acpi_handle handle)
606 */ 797 */
607static acpi_status 798static acpi_status
608acpi_wmi_ec_space_handler(u32 function, acpi_physical_address address, 799acpi_wmi_ec_space_handler(u32 function, acpi_physical_address address,
609 u32 bits, acpi_integer * value, 800 u32 bits, u64 *value,
610 void *handler_context, void *region_context) 801 void *handler_context, void *region_context)
611{ 802{
612 int result = 0, i = 0; 803 int result = 0, i = 0;
@@ -623,7 +814,7 @@ acpi_wmi_ec_space_handler(u32 function, acpi_physical_address address,
623 814
624 if (function == ACPI_READ) { 815 if (function == ACPI_READ) {
625 result = ec_read(address, &temp); 816 result = ec_read(address, &temp);
626 (*value) |= ((acpi_integer)temp) << i; 817 (*value) |= ((u64)temp) << i;
627 } else { 818 } else {
628 temp = 0xff & ((*value) >> i); 819 temp = 0xff & ((*value) >> i);
629 result = ec_write(address, temp); 820 result = ec_write(address, temp);
@@ -709,10 +900,17 @@ static int __init acpi_wmi_init(void)
709 900
710 if (result < 0) { 901 if (result < 0) {
711 printk(KERN_INFO PREFIX "Error loading mapper\n"); 902 printk(KERN_INFO PREFIX "Error loading mapper\n");
712 } else { 903 return -ENODEV;
713 printk(KERN_INFO PREFIX "Mapper loaded\n"); 904 }
905
906 result = wmi_class_init();
907 if (result) {
908 acpi_bus_unregister_driver(&acpi_wmi_driver);
909 return result;
714 } 910 }
715 911
912 printk(KERN_INFO PREFIX "Mapper loaded\n");
913
716 return result; 914 return result;
717} 915}
718 916
@@ -721,6 +919,8 @@ static void __exit acpi_wmi_exit(void)
721 struct list_head *p, *tmp; 919 struct list_head *p, *tmp;
722 struct wmi_block *wblock; 920 struct wmi_block *wblock;
723 921
922 wmi_class_exit();
923
724 acpi_bus_unregister_driver(&acpi_wmi_driver); 924 acpi_bus_unregister_driver(&acpi_wmi_driver);
725 925
726 list_for_each_safe(p, tmp, &wmi_blocks.list) { 926 list_for_each_safe(p, tmp, &wmi_blocks.list) {