aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/platform/x86
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/platform/x86')
-rw-r--r--drivers/platform/x86/Kconfig34
-rw-r--r--drivers/platform/x86/Makefile1
-rw-r--r--drivers/platform/x86/acerhdf.c602
-rw-r--r--drivers/platform/x86/asus-laptop.c111
-rw-r--r--drivers/platform/x86/asus_acpi.c30
-rw-r--r--drivers/platform/x86/dell-wmi.c56
-rw-r--r--drivers/platform/x86/eeepc-laptop.c126
-rw-r--r--drivers/platform/x86/hp-wmi.c87
-rw-r--r--drivers/platform/x86/thinkpad_acpi.c411
9 files changed, 1279 insertions, 179 deletions
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index c682ac536415..7232fe7104aa 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -34,10 +34,27 @@ config ACER_WMI
34 If you have an ACPI-WMI compatible Acer/ Wistron laptop, say Y or M 34 If you have an ACPI-WMI compatible Acer/ Wistron laptop, say Y or M
35 here. 35 here.
36 36
37config ACERHDF
38 tristate "Acer Aspire One temperature and fan driver"
39 depends on THERMAL && THERMAL_HWMON && ACPI
40 ---help---
41 This is a driver for Acer Aspire One netbooks. It allows to access
42 the temperature sensor and to control the fan.
43
44 After loading this driver the BIOS is still in control of the fan.
45 To let the kernel handle the fan, do:
46 echo -n enabled > /sys/class/thermal/thermal_zone0/mode
47
48 For more information about this driver see
49 <http://piie.net/files/acerhdf_README.txt>
50
51 If you have an Acer Aspire One netbook, say Y or M
52 here.
53
37config ASUS_LAPTOP 54config ASUS_LAPTOP
38 tristate "Asus Laptop Extras (EXPERIMENTAL)" 55 tristate "Asus Laptop Extras"
39 depends on ACPI 56 depends on ACPI
40 depends on EXPERIMENTAL && !ACPI_ASUS 57 depends on !ACPI_ASUS
41 select LEDS_CLASS 58 select LEDS_CLASS
42 select NEW_LEDS 59 select NEW_LEDS
43 select BACKLIGHT_CLASS_DEVICE 60 select BACKLIGHT_CLASS_DEVICE
@@ -45,12 +62,12 @@ config ASUS_LAPTOP
45 ---help--- 62 ---help---
46 This is the new Linux driver for Asus laptops. It may also support some 63 This is the new Linux driver for Asus laptops. It may also support some
47 MEDION, JVC or VICTOR laptops. It makes all the extra buttons generate 64 MEDION, JVC or VICTOR laptops. It makes all the extra buttons generate
48 standard ACPI events that go through /proc/acpi/events. It also adds 65 standard ACPI events and input events. It also adds
49 support for video output switching, LCD backlight control, Bluetooth and 66 support for video output switching, LCD backlight control, Bluetooth and
50 Wlan control, and most importantly, allows you to blink those fancy LEDs. 67 Wlan control, and most importantly, allows you to blink those fancy LEDs.
51 68
52 For more information and a userspace daemon for handling the extra 69 For more information and a userspace daemon for handling the extra
53 buttons see <http://acpi4asus.sf.net/>. 70 buttons see <http://acpi4asus.sf.net>.
54 71
55 If you have an ACPI-compatible ASUS laptop, say Y or M here. 72 If you have an ACPI-compatible ASUS laptop, say Y or M here.
56 73
@@ -342,7 +359,10 @@ config EEEPC_LAPTOP
342 select HWMON 359 select HWMON
343 ---help--- 360 ---help---
344 This driver supports the Fn-Fx keys on Eee PC laptops. 361 This driver supports the Fn-Fx keys on Eee PC laptops.
345 It also adds the ability to switch camera/wlan on/off. 362
363 It also gives access to some extra laptop functionalities like
364 Bluetooth, backlight and allows powering on/off some other
365 devices.
346 366
347 If you have an Eee PC laptop, say Y or M here. 367 If you have an Eee PC laptop, say Y or M here.
348 368
@@ -369,7 +389,7 @@ config ACPI_WMI
369 any ACPI-WMI devices. 389 any ACPI-WMI devices.
370 390
371config ACPI_ASUS 391config ACPI_ASUS
372 tristate "ASUS/Medion Laptop Extras" 392 tristate "ASUS/Medion Laptop Extras (DEPRECATED)"
373 depends on ACPI 393 depends on ACPI
374 select BACKLIGHT_CLASS_DEVICE 394 select BACKLIGHT_CLASS_DEVICE
375 ---help--- 395 ---help---
@@ -390,7 +410,7 @@ config ACPI_ASUS
390 parameters. 410 parameters.
391 411
392 More information and a userspace daemon for handling the extra buttons 412 More information and a userspace daemon for handling the extra buttons
393 at <http://sourceforge.net/projects/acpi4asus/>. 413 at <http://acpi4asus.sf.net>.
394 414
395 If you have an ACPI-compatible ASUS laptop, say Y or M here. This 415 If you have an ACPI-compatible ASUS laptop, say Y or M here. This
396 driver is still under development, so if your laptop is unsupported or 416 driver is still under development, so if your laptop is unsupported or
diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile
index e40c7bd1b87e..641b8bfa5538 100644
--- a/drivers/platform/x86/Makefile
+++ b/drivers/platform/x86/Makefile
@@ -9,6 +9,7 @@ obj-$(CONFIG_COMPAL_LAPTOP) += compal-laptop.o
9obj-$(CONFIG_DELL_LAPTOP) += dell-laptop.o 9obj-$(CONFIG_DELL_LAPTOP) += dell-laptop.o
10obj-$(CONFIG_DELL_WMI) += dell-wmi.o 10obj-$(CONFIG_DELL_WMI) += dell-wmi.o
11obj-$(CONFIG_ACER_WMI) += acer-wmi.o 11obj-$(CONFIG_ACER_WMI) += acer-wmi.o
12obj-$(CONFIG_ACERHDF) += acerhdf.o
12obj-$(CONFIG_HP_WMI) += hp-wmi.o 13obj-$(CONFIG_HP_WMI) += hp-wmi.o
13obj-$(CONFIG_TC1100_WMI) += tc1100-wmi.o 14obj-$(CONFIG_TC1100_WMI) += tc1100-wmi.o
14obj-$(CONFIG_SONY_LAPTOP) += sony-laptop.o 15obj-$(CONFIG_SONY_LAPTOP) += sony-laptop.o
diff --git a/drivers/platform/x86/acerhdf.c b/drivers/platform/x86/acerhdf.c
new file mode 100644
index 000000000000..bdfee177eefb
--- /dev/null
+++ b/drivers/platform/x86/acerhdf.c
@@ -0,0 +1,602 @@
1/*
2 * acerhdf - A driver which monitors the temperature
3 * of the aspire one netbook, turns on/off the fan
4 * as soon as the upper/lower threshold is reached.
5 *
6 * (C) 2009 - Peter Feuerer peter (a) piie.net
7 * http://piie.net
8 * 2009 Borislav Petkov <petkovbb@gmail.com>
9 *
10 * Inspired by and many thanks to:
11 * o acerfand - Rachel Greenham
12 * o acer_ec.pl - Michael Kurz michi.kurz (at) googlemail.com
13 * - Petr Tomasek tomasek (#) etf,cuni,cz
14 * - Carlos Corbacho cathectic (at) gmail.com
15 * o lkml - Matthew Garrett
16 * - Borislav Petkov
17 * - Andreas Mohr
18 *
19 * This program is free software; you can redistribute it and/or modify
20 * it under the terms of the GNU General Public License as published by
21 * the Free Software Foundation; either version 2 of the License, or
22 * (at your option) any later version.
23 *
24 * This program is distributed in the hope that it will be useful,
25 * but WITHOUT ANY WARRANTY; without even the implied warranty of
26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27 * GNU General Public License for more details.
28 *
29 * You should have received a copy of the GNU General Public License
30 * along with this program; if not, write to the Free Software
31 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
32 */
33
34#define pr_fmt(fmt) "acerhdf: " fmt
35
36#include <linux/kernel.h>
37#include <linux/module.h>
38#include <linux/fs.h>
39#include <linux/dmi.h>
40#include <acpi/acpi_drivers.h>
41#include <linux/sched.h>
42#include <linux/thermal.h>
43#include <linux/platform_device.h>
44
45/*
46 * The driver is started with "kernel mode off" by default. That means, the BIOS
47 * is still in control of the fan. In this mode the driver allows to read the
48 * temperature of the cpu and a userspace tool may take over control of the fan.
49 * If the driver is switched to "kernel mode" (e.g. via module parameter) the
50 * driver is in full control of the fan. If you want the module to be started in
51 * kernel mode by default, define the following:
52 */
53#undef START_IN_KERNEL_MODE
54
55#define DRV_VER "0.5.13"
56
57/*
58 * According to the Atom N270 datasheet,
59 * (http://download.intel.com/design/processor/datashts/320032.pdf) the
60 * CPU's optimal operating limits denoted in junction temperature as
61 * measured by the on-die thermal monitor are within 0 <= Tj <= 90. So,
62 * assume 89°C is critical temperature.
63 */
64#define ACERHDF_TEMP_CRIT 89
65#define ACERHDF_FAN_OFF 0
66#define ACERHDF_FAN_AUTO 1
67
68/*
69 * No matter what value the user puts into the fanon variable, turn on the fan
70 * at 80 degree Celsius to prevent hardware damage
71 */
72#define ACERHDF_MAX_FANON 80
73
74/*
75 * Maximum interval between two temperature checks is 15 seconds, as the die
76 * can get hot really fast under heavy load (plus we shouldn't forget about
77 * possible impact of _external_ aggressive sources such as heaters, sun etc.)
78 */
79#define ACERHDF_MAX_INTERVAL 15
80
81#ifdef START_IN_KERNEL_MODE
82static int kernelmode = 1;
83#else
84static int kernelmode;
85#endif
86
87static unsigned int interval = 10;
88static unsigned int fanon = 63;
89static unsigned int fanoff = 58;
90static unsigned int verbose;
91static unsigned int fanstate = ACERHDF_FAN_AUTO;
92static char force_bios[16];
93static unsigned int prev_interval;
94struct thermal_zone_device *thz_dev;
95struct thermal_cooling_device *cl_dev;
96struct platform_device *acerhdf_dev;
97
98module_param(kernelmode, uint, 0);
99MODULE_PARM_DESC(kernelmode, "Kernel mode fan control on / off");
100module_param(interval, uint, 0600);
101MODULE_PARM_DESC(interval, "Polling interval of temperature check");
102module_param(fanon, uint, 0600);
103MODULE_PARM_DESC(fanon, "Turn the fan on above this temperature");
104module_param(fanoff, uint, 0600);
105MODULE_PARM_DESC(fanoff, "Turn the fan off below this temperature");
106module_param(verbose, uint, 0600);
107MODULE_PARM_DESC(verbose, "Enable verbose dmesg output");
108module_param_string(force_bios, force_bios, 16, 0);
109MODULE_PARM_DESC(force_bios, "Force BIOS version and omit BIOS check");
110
111/* BIOS settings */
112struct bios_settings_t {
113 const char *vendor;
114 const char *version;
115 unsigned char fanreg;
116 unsigned char tempreg;
117 unsigned char fancmd[2]; /* fan off and auto commands */
118};
119
120/* Register addresses and values for different BIOS versions */
121static const struct bios_settings_t bios_tbl[] = {
122 {"Acer", "v0.3109", 0x55, 0x58, {0x1f, 0x00} },
123 {"Acer", "v0.3114", 0x55, 0x58, {0x1f, 0x00} },
124 {"Acer", "v0.3301", 0x55, 0x58, {0xaf, 0x00} },
125 {"Acer", "v0.3304", 0x55, 0x58, {0xaf, 0x00} },
126 {"Acer", "v0.3305", 0x55, 0x58, {0xaf, 0x00} },
127 {"Acer", "v0.3308", 0x55, 0x58, {0x21, 0x00} },
128 {"Acer", "v0.3309", 0x55, 0x58, {0x21, 0x00} },
129 {"Acer", "v0.3310", 0x55, 0x58, {0x21, 0x00} },
130 {"Gateway", "v0.3103", 0x55, 0x58, {0x21, 0x00} },
131 {"Packard Bell", "v0.3105", 0x55, 0x58, {0x21, 0x00} },
132 {"", "", 0, 0, {0, 0} }
133};
134
135static const struct bios_settings_t *bios_cfg __read_mostly;
136
137
138static int acerhdf_get_temp(int *temp)
139{
140 u8 read_temp;
141
142 if (ec_read(bios_cfg->tempreg, &read_temp))
143 return -EINVAL;
144
145 *temp = read_temp;
146
147 return 0;
148}
149
150static int acerhdf_get_fanstate(int *state)
151{
152 u8 fan;
153 bool tmp;
154
155 if (ec_read(bios_cfg->fanreg, &fan))
156 return -EINVAL;
157
158 tmp = (fan == bios_cfg->fancmd[ACERHDF_FAN_OFF]);
159 *state = tmp ? ACERHDF_FAN_OFF : ACERHDF_FAN_AUTO;
160
161 return 0;
162}
163
164static void acerhdf_change_fanstate(int state)
165{
166 unsigned char cmd;
167
168 if (verbose)
169 pr_notice("fan %s\n", (state == ACERHDF_FAN_OFF) ?
170 "OFF" : "ON");
171
172 if ((state != ACERHDF_FAN_OFF) && (state != ACERHDF_FAN_AUTO)) {
173 pr_err("invalid fan state %d requested, setting to auto!\n",
174 state);
175 state = ACERHDF_FAN_AUTO;
176 }
177
178 cmd = bios_cfg->fancmd[state];
179 fanstate = state;
180
181 ec_write(bios_cfg->fanreg, cmd);
182}
183
184static void acerhdf_check_param(struct thermal_zone_device *thermal)
185{
186 if (fanon > ACERHDF_MAX_FANON) {
187 pr_err("fanon temperature too high, set to %d\n",
188 ACERHDF_MAX_FANON);
189 fanon = ACERHDF_MAX_FANON;
190 }
191
192 if (kernelmode && prev_interval != interval) {
193 if (interval > ACERHDF_MAX_INTERVAL) {
194 pr_err("interval too high, set to %d\n",
195 ACERHDF_MAX_INTERVAL);
196 interval = ACERHDF_MAX_INTERVAL;
197 }
198 if (verbose)
199 pr_notice("interval changed to: %d\n",
200 interval);
201 thermal->polling_delay = interval*1000;
202 prev_interval = interval;
203 }
204}
205
206/*
207 * This is the thermal zone callback which does the delayed polling of the fan
208 * state. We do check /sysfs-originating settings here in acerhdf_check_param()
209 * as late as the polling interval is since we can't do that in the respective
210 * accessors of the module parameters.
211 */
212static int acerhdf_get_ec_temp(struct thermal_zone_device *thermal,
213 unsigned long *t)
214{
215 int temp, err = 0;
216
217 acerhdf_check_param(thermal);
218
219 err = acerhdf_get_temp(&temp);
220 if (err)
221 return err;
222
223 if (verbose)
224 pr_notice("temp %d\n", temp);
225
226 *t = temp;
227 return 0;
228}
229
230static int acerhdf_bind(struct thermal_zone_device *thermal,
231 struct thermal_cooling_device *cdev)
232{
233 /* if the cooling device is the one from acerhdf bind it */
234 if (cdev != cl_dev)
235 return 0;
236
237 if (thermal_zone_bind_cooling_device(thermal, 0, cdev)) {
238 pr_err("error binding cooling dev\n");
239 return -EINVAL;
240 }
241 return 0;
242}
243
244static int acerhdf_unbind(struct thermal_zone_device *thermal,
245 struct thermal_cooling_device *cdev)
246{
247 if (cdev != cl_dev)
248 return 0;
249
250 if (thermal_zone_unbind_cooling_device(thermal, 0, cdev)) {
251 pr_err("error unbinding cooling dev\n");
252 return -EINVAL;
253 }
254 return 0;
255}
256
257static inline void acerhdf_revert_to_bios_mode(void)
258{
259 acerhdf_change_fanstate(ACERHDF_FAN_AUTO);
260 kernelmode = 0;
261 if (thz_dev)
262 thz_dev->polling_delay = 0;
263 pr_notice("kernel mode fan control OFF\n");
264}
265static inline void acerhdf_enable_kernelmode(void)
266{
267 kernelmode = 1;
268
269 thz_dev->polling_delay = interval*1000;
270 thermal_zone_device_update(thz_dev);
271 pr_notice("kernel mode fan control ON\n");
272}
273
274static int acerhdf_get_mode(struct thermal_zone_device *thermal,
275 enum thermal_device_mode *mode)
276{
277 if (verbose)
278 pr_notice("kernel mode fan control %d\n", kernelmode);
279
280 *mode = (kernelmode) ? THERMAL_DEVICE_ENABLED
281 : THERMAL_DEVICE_DISABLED;
282
283 return 0;
284}
285
286/*
287 * set operation mode;
288 * enabled: the thermal layer of the kernel takes care about
289 * the temperature and the fan.
290 * disabled: the BIOS takes control of the fan.
291 */
292static int acerhdf_set_mode(struct thermal_zone_device *thermal,
293 enum thermal_device_mode mode)
294{
295 if (mode == THERMAL_DEVICE_DISABLED && kernelmode)
296 acerhdf_revert_to_bios_mode();
297 else if (mode == THERMAL_DEVICE_ENABLED && !kernelmode)
298 acerhdf_enable_kernelmode();
299
300 return 0;
301}
302
303static int acerhdf_get_trip_type(struct thermal_zone_device *thermal, int trip,
304 enum thermal_trip_type *type)
305{
306 if (trip == 0)
307 *type = THERMAL_TRIP_ACTIVE;
308
309 return 0;
310}
311
312static int acerhdf_get_trip_temp(struct thermal_zone_device *thermal, int trip,
313 unsigned long *temp)
314{
315 if (trip == 0)
316 *temp = fanon;
317
318 return 0;
319}
320
321static int acerhdf_get_crit_temp(struct thermal_zone_device *thermal,
322 unsigned long *temperature)
323{
324 *temperature = ACERHDF_TEMP_CRIT;
325 return 0;
326}
327
328/* bind callback functions to thermalzone */
329struct thermal_zone_device_ops acerhdf_dev_ops = {
330 .bind = acerhdf_bind,
331 .unbind = acerhdf_unbind,
332 .get_temp = acerhdf_get_ec_temp,
333 .get_mode = acerhdf_get_mode,
334 .set_mode = acerhdf_set_mode,
335 .get_trip_type = acerhdf_get_trip_type,
336 .get_trip_temp = acerhdf_get_trip_temp,
337 .get_crit_temp = acerhdf_get_crit_temp,
338};
339
340
341/*
342 * cooling device callback functions
343 * get maximal fan cooling state
344 */
345static int acerhdf_get_max_state(struct thermal_cooling_device *cdev,
346 unsigned long *state)
347{
348 *state = 1;
349
350 return 0;
351}
352
353static int acerhdf_get_cur_state(struct thermal_cooling_device *cdev,
354 unsigned long *state)
355{
356 int err = 0, tmp;
357
358 err = acerhdf_get_fanstate(&tmp);
359 if (err)
360 return err;
361
362 *state = (tmp == ACERHDF_FAN_AUTO) ? 1 : 0;
363 return 0;
364}
365
366/* change current fan state - is overwritten when running in kernel mode */
367static int acerhdf_set_cur_state(struct thermal_cooling_device *cdev,
368 unsigned long state)
369{
370 int cur_temp, cur_state, err = 0;
371
372 if (!kernelmode)
373 return 0;
374
375 err = acerhdf_get_temp(&cur_temp);
376 if (err) {
377 pr_err("error reading temperature, hand off control to BIOS\n");
378 goto err_out;
379 }
380
381 err = acerhdf_get_fanstate(&cur_state);
382 if (err) {
383 pr_err("error reading fan state, hand off control to BIOS\n");
384 goto err_out;
385 }
386
387 if (state == 0) {
388 /* turn fan off only if below fanoff temperature */
389 if ((cur_state == ACERHDF_FAN_AUTO) &&
390 (cur_temp < fanoff))
391 acerhdf_change_fanstate(ACERHDF_FAN_OFF);
392 } else {
393 if (cur_state == ACERHDF_FAN_OFF)
394 acerhdf_change_fanstate(ACERHDF_FAN_AUTO);
395 }
396 return 0;
397
398err_out:
399 acerhdf_revert_to_bios_mode();
400 return -EINVAL;
401}
402
403/* bind fan callbacks to fan device */
404struct thermal_cooling_device_ops acerhdf_cooling_ops = {
405 .get_max_state = acerhdf_get_max_state,
406 .get_cur_state = acerhdf_get_cur_state,
407 .set_cur_state = acerhdf_set_cur_state,
408};
409
410/* suspend / resume functionality */
411static int acerhdf_suspend(struct platform_device *dev, pm_message_t state)
412{
413 if (kernelmode)
414 acerhdf_change_fanstate(ACERHDF_FAN_AUTO);
415
416 if (verbose)
417 pr_notice("going suspend\n");
418
419 return 0;
420}
421
422static int acerhdf_resume(struct platform_device *device)
423{
424 if (verbose)
425 pr_notice("resuming\n");
426
427 return 0;
428}
429
430static int __devinit acerhdf_probe(struct platform_device *device)
431{
432 return 0;
433}
434
435static int acerhdf_remove(struct platform_device *device)
436{
437 return 0;
438}
439
440struct platform_driver acerhdf_drv = {
441 .driver = {
442 .name = "acerhdf",
443 .owner = THIS_MODULE,
444 },
445 .probe = acerhdf_probe,
446 .remove = acerhdf_remove,
447 .suspend = acerhdf_suspend,
448 .resume = acerhdf_resume,
449};
450
451
452/* check hardware */
453static int acerhdf_check_hardware(void)
454{
455 char const *vendor, *version, *product;
456 int i;
457
458 /* get BIOS data */
459 vendor = dmi_get_system_info(DMI_SYS_VENDOR);
460 version = dmi_get_system_info(DMI_BIOS_VERSION);
461 product = dmi_get_system_info(DMI_PRODUCT_NAME);
462
463 pr_info("Acer Aspire One Fan driver, v.%s\n", DRV_VER);
464
465 if (!force_bios[0]) {
466 if (strncmp(product, "AO", 2)) {
467 pr_err("no Aspire One hardware found\n");
468 return -EINVAL;
469 }
470 } else {
471 pr_info("forcing BIOS version: %s\n", version);
472 version = force_bios;
473 kernelmode = 0;
474 }
475
476 if (verbose)
477 pr_info("BIOS info: %s %s, product: %s\n",
478 vendor, version, product);
479
480 /* search BIOS version and vendor in BIOS settings table */
481 for (i = 0; bios_tbl[i].version[0]; i++) {
482 if (!strcmp(bios_tbl[i].vendor, vendor) &&
483 !strcmp(bios_tbl[i].version, version)) {
484 bios_cfg = &bios_tbl[i];
485 break;
486 }
487 }
488
489 if (!bios_cfg) {
490 pr_err("unknown (unsupported) BIOS version %s/%s, "
491 "please report, aborting!\n", vendor, version);
492 return -EINVAL;
493 }
494
495 /*
496 * if started with kernel mode off, prevent the kernel from switching
497 * off the fan
498 */
499 if (!kernelmode) {
500 pr_notice("Fan control off, to enable do:\n");
501 pr_notice("echo -n \"enabled\" > "
502 "/sys/class/thermal/thermal_zone0/mode\n");
503 }
504
505 return 0;
506}
507
508static int acerhdf_register_platform(void)
509{
510 int err = 0;
511
512 err = platform_driver_register(&acerhdf_drv);
513 if (err)
514 return err;
515
516 acerhdf_dev = platform_device_alloc("acerhdf", -1);
517 platform_device_add(acerhdf_dev);
518
519 return 0;
520}
521
522static void acerhdf_unregister_platform(void)
523{
524 if (!acerhdf_dev)
525 return;
526
527 platform_device_del(acerhdf_dev);
528 platform_driver_unregister(&acerhdf_drv);
529}
530
531static int acerhdf_register_thermal(void)
532{
533 cl_dev = thermal_cooling_device_register("acerhdf-fan", NULL,
534 &acerhdf_cooling_ops);
535
536 if (IS_ERR(cl_dev))
537 return -EINVAL;
538
539 thz_dev = thermal_zone_device_register("acerhdf", 1, NULL,
540 &acerhdf_dev_ops, 0, 0, 0,
541 (kernelmode) ? interval*1000 : 0);
542 if (IS_ERR(thz_dev))
543 return -EINVAL;
544
545 return 0;
546}
547
548static void acerhdf_unregister_thermal(void)
549{
550 if (cl_dev) {
551 thermal_cooling_device_unregister(cl_dev);
552 cl_dev = NULL;
553 }
554
555 if (thz_dev) {
556 thermal_zone_device_unregister(thz_dev);
557 thz_dev = NULL;
558 }
559}
560
561static int __init acerhdf_init(void)
562{
563 int err = 0;
564
565 err = acerhdf_check_hardware();
566 if (err)
567 goto out_err;
568
569 err = acerhdf_register_platform();
570 if (err)
571 goto err_unreg;
572
573 err = acerhdf_register_thermal();
574 if (err)
575 goto err_unreg;
576
577 return 0;
578
579err_unreg:
580 acerhdf_unregister_thermal();
581 acerhdf_unregister_platform();
582
583out_err:
584 return -ENODEV;
585}
586
587static void __exit acerhdf_exit(void)
588{
589 acerhdf_change_fanstate(ACERHDF_FAN_AUTO);
590 acerhdf_unregister_thermal();
591 acerhdf_unregister_platform();
592}
593
594MODULE_LICENSE("GPL");
595MODULE_AUTHOR("Peter Feuerer");
596MODULE_DESCRIPTION("Aspire One temperature and fan driver");
597MODULE_ALIAS("dmi:*:*Acer*:*:");
598MODULE_ALIAS("dmi:*:*Gateway*:*:");
599MODULE_ALIAS("dmi:*:*Packard Bell*:*:");
600
601module_init(acerhdf_init);
602module_exit(acerhdf_exit);
diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c
index bfc1a8892a32..db657bbeec90 100644
--- a/drivers/platform/x86/asus-laptop.c
+++ b/drivers/platform/x86/asus-laptop.c
@@ -33,6 +33,8 @@
33 * Sam Lin - GPS support 33 * Sam Lin - GPS support
34 */ 34 */
35 35
36#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
37
36#include <linux/kernel.h> 38#include <linux/kernel.h>
37#include <linux/module.h> 39#include <linux/module.h>
38#include <linux/init.h> 40#include <linux/init.h>
@@ -53,9 +55,10 @@
53#define ASUS_HOTK_NAME "Asus Laptop Support" 55#define ASUS_HOTK_NAME "Asus Laptop Support"
54#define ASUS_HOTK_CLASS "hotkey" 56#define ASUS_HOTK_CLASS "hotkey"
55#define ASUS_HOTK_DEVICE_NAME "Hotkey" 57#define ASUS_HOTK_DEVICE_NAME "Hotkey"
56#define ASUS_HOTK_FILE "asus-laptop" 58#define ASUS_HOTK_FILE KBUILD_MODNAME
57#define ASUS_HOTK_PREFIX "\\_SB.ATKD." 59#define ASUS_HOTK_PREFIX "\\_SB.ATKD."
58 60
61
59/* 62/*
60 * Some events we use, same for all Asus 63 * Some events we use, same for all Asus
61 */ 64 */
@@ -207,13 +210,17 @@ MODULE_DEVICE_TABLE(acpi, asus_device_ids);
207 210
208static int asus_hotk_add(struct acpi_device *device); 211static int asus_hotk_add(struct acpi_device *device);
209static int asus_hotk_remove(struct acpi_device *device, int type); 212static int asus_hotk_remove(struct acpi_device *device, int type);
213static void asus_hotk_notify(struct acpi_device *device, u32 event);
214
210static struct acpi_driver asus_hotk_driver = { 215static struct acpi_driver asus_hotk_driver = {
211 .name = ASUS_HOTK_NAME, 216 .name = ASUS_HOTK_NAME,
212 .class = ASUS_HOTK_CLASS, 217 .class = ASUS_HOTK_CLASS,
213 .ids = asus_device_ids, 218 .ids = asus_device_ids,
219 .flags = ACPI_DRIVER_ALL_NOTIFY_EVENTS,
214 .ops = { 220 .ops = {
215 .add = asus_hotk_add, 221 .add = asus_hotk_add,
216 .remove = asus_hotk_remove, 222 .remove = asus_hotk_remove,
223 .notify = asus_hotk_notify,
217 }, 224 },
218}; 225};
219 226
@@ -323,7 +330,7 @@ static int read_wireless_status(int mask)
323 330
324 rv = acpi_evaluate_integer(wireless_status_handle, NULL, NULL, &status); 331 rv = acpi_evaluate_integer(wireless_status_handle, NULL, NULL, &status);
325 if (ACPI_FAILURE(rv)) 332 if (ACPI_FAILURE(rv))
326 printk(ASUS_WARNING "Error reading Wireless status\n"); 333 pr_warning("Error reading Wireless status\n");
327 else 334 else
328 return (status & mask) ? 1 : 0; 335 return (status & mask) ? 1 : 0;
329 336
@@ -337,7 +344,7 @@ static int read_gps_status(void)
337 344
338 rv = acpi_evaluate_integer(gps_status_handle, NULL, NULL, &status); 345 rv = acpi_evaluate_integer(gps_status_handle, NULL, NULL, &status);
339 if (ACPI_FAILURE(rv)) 346 if (ACPI_FAILURE(rv))
340 printk(ASUS_WARNING "Error reading GPS status\n"); 347 pr_warning("Error reading GPS status\n");
341 else 348 else
342 return status ? 1 : 0; 349 return status ? 1 : 0;
343 350
@@ -377,7 +384,7 @@ static void write_status(acpi_handle handle, int out, int mask)
377 } 384 }
378 385
379 if (write_acpi_int(handle, NULL, out, NULL)) 386 if (write_acpi_int(handle, NULL, out, NULL))
380 printk(ASUS_WARNING " write failed %x\n", mask); 387 pr_warning(" write failed %x\n", mask);
381} 388}
382 389
383/* /sys/class/led handlers */ 390/* /sys/class/led handlers */
@@ -420,7 +427,7 @@ static int set_lcd_state(int value)
420 NULL, NULL, NULL); 427 NULL, NULL, NULL);
421 428
422 if (ACPI_FAILURE(status)) 429 if (ACPI_FAILURE(status))
423 printk(ASUS_WARNING "Error switching LCD\n"); 430 pr_warning("Error switching LCD\n");
424 } 431 }
425 432
426 write_status(NULL, lcd, LCD_ON); 433 write_status(NULL, lcd, LCD_ON);
@@ -444,7 +451,7 @@ static int read_brightness(struct backlight_device *bd)
444 451
445 rv = acpi_evaluate_integer(brightness_get_handle, NULL, NULL, &value); 452 rv = acpi_evaluate_integer(brightness_get_handle, NULL, NULL, &value);
446 if (ACPI_FAILURE(rv)) 453 if (ACPI_FAILURE(rv))
447 printk(ASUS_WARNING "Error reading brightness\n"); 454 pr_warning("Error reading brightness\n");
448 455
449 return value; 456 return value;
450} 457}
@@ -457,7 +464,7 @@ static int set_brightness(struct backlight_device *bd, int value)
457 /* 0 <= value <= 15 */ 464 /* 0 <= value <= 15 */
458 465
459 if (write_acpi_int(brightness_set_handle, NULL, value, NULL)) { 466 if (write_acpi_int(brightness_set_handle, NULL, value, NULL)) {
460 printk(ASUS_WARNING "Error changing brightness\n"); 467 pr_warning("Error changing brightness\n");
461 ret = -EIO; 468 ret = -EIO;
462 } 469 }
463 470
@@ -587,7 +594,7 @@ static ssize_t store_ledd(struct device *dev, struct device_attribute *attr,
587 rv = parse_arg(buf, count, &value); 594 rv = parse_arg(buf, count, &value);
588 if (rv > 0) { 595 if (rv > 0) {
589 if (write_acpi_int(ledd_set_handle, NULL, value, NULL)) 596 if (write_acpi_int(ledd_set_handle, NULL, value, NULL))
590 printk(ASUS_WARNING "LED display write failed\n"); 597 pr_warning("LED display write failed\n");
591 else 598 else
592 hotk->ledd_status = (u32) value; 599 hotk->ledd_status = (u32) value;
593 } 600 }
@@ -632,7 +639,7 @@ static void set_display(int value)
632{ 639{
633 /* no sanity check needed for now */ 640 /* no sanity check needed for now */
634 if (write_acpi_int(display_set_handle, NULL, value, NULL)) 641 if (write_acpi_int(display_set_handle, NULL, value, NULL))
635 printk(ASUS_WARNING "Error setting display\n"); 642 pr_warning("Error setting display\n");
636 return; 643 return;
637} 644}
638 645
@@ -647,7 +654,7 @@ static int read_display(void)
647 rv = acpi_evaluate_integer(display_get_handle, NULL, 654 rv = acpi_evaluate_integer(display_get_handle, NULL,
648 NULL, &value); 655 NULL, &value);
649 if (ACPI_FAILURE(rv)) 656 if (ACPI_FAILURE(rv))
650 printk(ASUS_WARNING "Error reading display status\n"); 657 pr_warning("Error reading display status\n");
651 } 658 }
652 659
653 value &= 0x0F; /* needed for some models, shouldn't hurt others */ 660 value &= 0x0F; /* needed for some models, shouldn't hurt others */
@@ -689,7 +696,7 @@ static ssize_t store_disp(struct device *dev, struct device_attribute *attr,
689static void set_light_sens_switch(int value) 696static void set_light_sens_switch(int value)
690{ 697{
691 if (write_acpi_int(ls_switch_handle, NULL, value, NULL)) 698 if (write_acpi_int(ls_switch_handle, NULL, value, NULL))
692 printk(ASUS_WARNING "Error setting light sensor switch\n"); 699 pr_warning("Error setting light sensor switch\n");
693 hotk->light_switch = value; 700 hotk->light_switch = value;
694} 701}
695 702
@@ -714,7 +721,7 @@ static ssize_t store_lssw(struct device *dev, struct device_attribute *attr,
714static void set_light_sens_level(int value) 721static void set_light_sens_level(int value)
715{ 722{
716 if (write_acpi_int(ls_level_handle, NULL, value, NULL)) 723 if (write_acpi_int(ls_level_handle, NULL, value, NULL))
717 printk(ASUS_WARNING "Error setting light sensor level\n"); 724 pr_warning("Error setting light sensor level\n");
718 hotk->light_level = value; 725 hotk->light_level = value;
719} 726}
720 727
@@ -812,7 +819,7 @@ static int asus_setkeycode(struct input_dev *dev, int scancode, int keycode)
812 return -EINVAL; 819 return -EINVAL;
813} 820}
814 821
815static void asus_hotk_notify(acpi_handle handle, u32 event, void *data) 822static void asus_hotk_notify(struct acpi_device *device, u32 event)
816{ 823{
817 static struct key_entry *key; 824 static struct key_entry *key;
818 u16 count; 825 u16 count;
@@ -975,11 +982,11 @@ static int asus_hotk_get_info(void)
975 */ 982 */
976 status = acpi_get_table(ACPI_SIG_DSDT, 1, &asus_info); 983 status = acpi_get_table(ACPI_SIG_DSDT, 1, &asus_info);
977 if (ACPI_FAILURE(status)) 984 if (ACPI_FAILURE(status))
978 printk(ASUS_WARNING "Couldn't get the DSDT table header\n"); 985 pr_warning("Couldn't get the DSDT table header\n");
979 986
980 /* We have to write 0 on init this far for all ASUS models */ 987 /* We have to write 0 on init this far for all ASUS models */
981 if (write_acpi_int(hotk->handle, "INIT", 0, &buffer)) { 988 if (write_acpi_int(hotk->handle, "INIT", 0, &buffer)) {
982 printk(ASUS_ERR "Hotkey initialization failed\n"); 989 pr_err("Hotkey initialization failed\n");
983 return -ENODEV; 990 return -ENODEV;
984 } 991 }
985 992
@@ -987,9 +994,9 @@ static int asus_hotk_get_info(void)
987 status = 994 status =
988 acpi_evaluate_integer(hotk->handle, "BSTS", NULL, &bsts_result); 995 acpi_evaluate_integer(hotk->handle, "BSTS", NULL, &bsts_result);
989 if (ACPI_FAILURE(status)) 996 if (ACPI_FAILURE(status))
990 printk(ASUS_WARNING "Error calling BSTS\n"); 997 pr_warning("Error calling BSTS\n");
991 else if (bsts_result) 998 else if (bsts_result)
992 printk(ASUS_NOTICE "BSTS called, 0x%02x returned\n", 999 pr_notice("BSTS called, 0x%02x returned\n",
993 (uint) bsts_result); 1000 (uint) bsts_result);
994 1001
995 /* This too ... */ 1002 /* This too ... */
@@ -1020,7 +1027,7 @@ static int asus_hotk_get_info(void)
1020 return -ENOMEM; 1027 return -ENOMEM;
1021 1028
1022 if (*string) 1029 if (*string)
1023 printk(ASUS_NOTICE " %s model detected\n", string); 1030 pr_notice(" %s model detected\n", string);
1024 1031
1025 ASUS_HANDLE_INIT(mled_set); 1032 ASUS_HANDLE_INIT(mled_set);
1026 ASUS_HANDLE_INIT(tled_set); 1033 ASUS_HANDLE_INIT(tled_set);
@@ -1077,7 +1084,7 @@ static int asus_input_init(void)
1077 1084
1078 hotk->inputdev = input_allocate_device(); 1085 hotk->inputdev = input_allocate_device();
1079 if (!hotk->inputdev) { 1086 if (!hotk->inputdev) {
1080 printk(ASUS_INFO "Unable to allocate input device\n"); 1087 pr_info("Unable to allocate input device\n");
1081 return 0; 1088 return 0;
1082 } 1089 }
1083 hotk->inputdev->name = "Asus Laptop extra buttons"; 1090 hotk->inputdev->name = "Asus Laptop extra buttons";
@@ -1096,7 +1103,7 @@ static int asus_input_init(void)
1096 } 1103 }
1097 result = input_register_device(hotk->inputdev); 1104 result = input_register_device(hotk->inputdev);
1098 if (result) { 1105 if (result) {
1099 printk(ASUS_INFO "Unable to register input device\n"); 1106 pr_info("Unable to register input device\n");
1100 input_free_device(hotk->inputdev); 1107 input_free_device(hotk->inputdev);
1101 } 1108 }
1102 return result; 1109 return result;
@@ -1113,7 +1120,7 @@ static int asus_hotk_check(void)
1113 if (hotk->device->status.present) { 1120 if (hotk->device->status.present) {
1114 result = asus_hotk_get_info(); 1121 result = asus_hotk_get_info();
1115 } else { 1122 } else {
1116 printk(ASUS_ERR "Hotkey device not present, aborting\n"); 1123 pr_err("Hotkey device not present, aborting\n");
1117 return -EINVAL; 1124 return -EINVAL;
1118 } 1125 }
1119 1126
@@ -1124,13 +1131,12 @@ static int asus_hotk_found;
1124 1131
1125static int asus_hotk_add(struct acpi_device *device) 1132static int asus_hotk_add(struct acpi_device *device)
1126{ 1133{
1127 acpi_status status = AE_OK;
1128 int result; 1134 int result;
1129 1135
1130 if (!device) 1136 if (!device)
1131 return -EINVAL; 1137 return -EINVAL;
1132 1138
1133 printk(ASUS_NOTICE "Asus Laptop Support version %s\n", 1139 pr_notice("Asus Laptop Support version %s\n",
1134 ASUS_LAPTOP_VERSION); 1140 ASUS_LAPTOP_VERSION);
1135 1141
1136 hotk = kzalloc(sizeof(struct asus_hotk), GFP_KERNEL); 1142 hotk = kzalloc(sizeof(struct asus_hotk), GFP_KERNEL);
@@ -1149,15 +1155,6 @@ static int asus_hotk_add(struct acpi_device *device)
1149 1155
1150 asus_hotk_add_fs(); 1156 asus_hotk_add_fs();
1151 1157
1152 /*
1153 * We install the handler, it will receive the hotk in parameter, so, we
1154 * could add other data to the hotk struct
1155 */
1156 status = acpi_install_notify_handler(hotk->handle, ACPI_ALL_NOTIFY,
1157 asus_hotk_notify, hotk);
1158 if (ACPI_FAILURE(status))
1159 printk(ASUS_ERR "Error installing notify handler\n");
1160
1161 asus_hotk_found = 1; 1158 asus_hotk_found = 1;
1162 1159
1163 /* WLED and BLED are on by default */ 1160 /* WLED and BLED are on by default */
@@ -1198,16 +1195,9 @@ end:
1198 1195
1199static int asus_hotk_remove(struct acpi_device *device, int type) 1196static int asus_hotk_remove(struct acpi_device *device, int type)
1200{ 1197{
1201 acpi_status status = 0;
1202
1203 if (!device || !acpi_driver_data(device)) 1198 if (!device || !acpi_driver_data(device))
1204 return -EINVAL; 1199 return -EINVAL;
1205 1200
1206 status = acpi_remove_notify_handler(hotk->handle, ACPI_ALL_NOTIFY,
1207 asus_hotk_notify);
1208 if (ACPI_FAILURE(status))
1209 printk(ASUS_ERR "Error removing notify handler\n");
1210
1211 kfree(hotk->name); 1201 kfree(hotk->name);
1212 kfree(hotk); 1202 kfree(hotk);
1213 1203
@@ -1260,8 +1250,7 @@ static int asus_backlight_init(struct device *dev)
1260 bd = backlight_device_register(ASUS_HOTK_FILE, dev, 1250 bd = backlight_device_register(ASUS_HOTK_FILE, dev,
1261 NULL, &asusbl_ops); 1251 NULL, &asusbl_ops);
1262 if (IS_ERR(bd)) { 1252 if (IS_ERR(bd)) {
1263 printk(ASUS_ERR 1253 pr_err("Could not register asus backlight device\n");
1264 "Could not register asus backlight device\n");
1265 asus_backlight_device = NULL; 1254 asus_backlight_device = NULL;
1266 return PTR_ERR(bd); 1255 return PTR_ERR(bd);
1267 } 1256 }
@@ -1334,7 +1323,6 @@ out:
1334 1323
1335static int __init asus_laptop_init(void) 1324static int __init asus_laptop_init(void)
1336{ 1325{
1337 struct device *dev;
1338 int result; 1326 int result;
1339 1327
1340 if (acpi_disabled) 1328 if (acpi_disabled)
@@ -1356,24 +1344,10 @@ static int __init asus_laptop_init(void)
1356 return -ENODEV; 1344 return -ENODEV;
1357 } 1345 }
1358 1346
1359 dev = acpi_get_physical_device(hotk->device->handle);
1360
1361 if (!acpi_video_backlight_support()) {
1362 result = asus_backlight_init(dev);
1363 if (result)
1364 goto fail_backlight;
1365 } else
1366 printk(ASUS_INFO "Brightness ignored, must be controlled by "
1367 "ACPI video driver\n");
1368
1369 result = asus_input_init(); 1347 result = asus_input_init();
1370 if (result) 1348 if (result)
1371 goto fail_input; 1349 goto fail_input;
1372 1350
1373 result = asus_led_init(dev);
1374 if (result)
1375 goto fail_led;
1376
1377 /* Register platform stuff */ 1351 /* Register platform stuff */
1378 result = platform_driver_register(&asuspf_driver); 1352 result = platform_driver_register(&asuspf_driver);
1379 if (result) 1353 if (result)
@@ -1394,8 +1368,27 @@ static int __init asus_laptop_init(void)
1394 if (result) 1368 if (result)
1395 goto fail_sysfs; 1369 goto fail_sysfs;
1396 1370
1371 result = asus_led_init(&asuspf_device->dev);
1372 if (result)
1373 goto fail_led;
1374
1375 if (!acpi_video_backlight_support()) {
1376 result = asus_backlight_init(&asuspf_device->dev);
1377 if (result)
1378 goto fail_backlight;
1379 } else
1380 pr_info("Brightness ignored, must be controlled by "
1381 "ACPI video driver\n");
1382
1397 return 0; 1383 return 0;
1398 1384
1385fail_backlight:
1386 asus_led_exit();
1387
1388fail_led:
1389 sysfs_remove_group(&asuspf_device->dev.kobj,
1390 &asuspf_attribute_group);
1391
1399fail_sysfs: 1392fail_sysfs:
1400 platform_device_del(asuspf_device); 1393 platform_device_del(asuspf_device);
1401 1394
@@ -1406,15 +1399,9 @@ fail_platform_device1:
1406 platform_driver_unregister(&asuspf_driver); 1399 platform_driver_unregister(&asuspf_driver);
1407 1400
1408fail_platform_driver: 1401fail_platform_driver:
1409 asus_led_exit();
1410
1411fail_led:
1412 asus_input_exit(); 1402 asus_input_exit();
1413 1403
1414fail_input: 1404fail_input:
1415 asus_backlight_exit();
1416
1417fail_backlight:
1418 1405
1419 return result; 1406 return result;
1420} 1407}
diff --git a/drivers/platform/x86/asus_acpi.c b/drivers/platform/x86/asus_acpi.c
index ba1f7497e4b9..ddf5240ade8c 100644
--- a/drivers/platform/x86/asus_acpi.c
+++ b/drivers/platform/x86/asus_acpi.c
@@ -455,6 +455,8 @@ static struct asus_hotk *hotk;
455 */ 455 */
456static int asus_hotk_add(struct acpi_device *device); 456static int asus_hotk_add(struct acpi_device *device);
457static int asus_hotk_remove(struct acpi_device *device, int type); 457static int asus_hotk_remove(struct acpi_device *device, int type);
458static void asus_hotk_notify(struct acpi_device *device, u32 event);
459
458static const struct acpi_device_id asus_device_ids[] = { 460static const struct acpi_device_id asus_device_ids[] = {
459 {"ATK0100", 0}, 461 {"ATK0100", 0},
460 {"", 0}, 462 {"", 0},
@@ -465,9 +467,11 @@ static struct acpi_driver asus_hotk_driver = {
465 .name = "asus_acpi", 467 .name = "asus_acpi",
466 .class = ACPI_HOTK_CLASS, 468 .class = ACPI_HOTK_CLASS,
467 .ids = asus_device_ids, 469 .ids = asus_device_ids,
470 .flags = ACPI_DRIVER_ALL_NOTIFY_EVENTS,
468 .ops = { 471 .ops = {
469 .add = asus_hotk_add, 472 .add = asus_hotk_add,
470 .remove = asus_hotk_remove, 473 .remove = asus_hotk_remove,
474 .notify = asus_hotk_notify,
471 }, 475 },
472}; 476};
473 477
@@ -1101,12 +1105,20 @@ static int asus_hotk_remove_fs(struct acpi_device *device)
1101 return 0; 1105 return 0;
1102} 1106}
1103 1107
1104static void asus_hotk_notify(acpi_handle handle, u32 event, void *data) 1108static void asus_hotk_notify(struct acpi_device *device, u32 event)
1105{ 1109{
1106 /* TODO Find a better way to handle events count. */ 1110 /* TODO Find a better way to handle events count. */
1107 if (!hotk) 1111 if (!hotk)
1108 return; 1112 return;
1109 1113
1114 /*
1115 * The BIOS *should* be sending us device events, but apparently
1116 * Asus uses system events instead, so just ignore any device
1117 * events we get.
1118 */
1119 if (event > ACPI_MAX_SYS_NOTIFY)
1120 return;
1121
1110 if ((event & ~((u32) BR_UP)) < 16) 1122 if ((event & ~((u32) BR_UP)) < 16)
1111 hotk->brightness = (event & ~((u32) BR_UP)); 1123 hotk->brightness = (event & ~((u32) BR_UP));
1112 else if ((event & ~((u32) BR_DOWN)) < 16) 1124 else if ((event & ~((u32) BR_DOWN)) < 16)
@@ -1346,15 +1358,6 @@ static int asus_hotk_add(struct acpi_device *device)
1346 if (result) 1358 if (result)
1347 goto end; 1359 goto end;
1348 1360
1349 /*
1350 * We install the handler, it will receive the hotk in parameter, so, we
1351 * could add other data to the hotk struct
1352 */
1353 status = acpi_install_notify_handler(hotk->handle, ACPI_SYSTEM_NOTIFY,
1354 asus_hotk_notify, hotk);
1355 if (ACPI_FAILURE(status))
1356 printk(KERN_ERR " Error installing notify handler\n");
1357
1358 /* For laptops without GPLV: init the hotk->brightness value */ 1361 /* For laptops without GPLV: init the hotk->brightness value */
1359 if ((!hotk->methods->brightness_get) 1362 if ((!hotk->methods->brightness_get)
1360 && (!hotk->methods->brightness_status) 1363 && (!hotk->methods->brightness_status)
@@ -1389,16 +1392,9 @@ end:
1389 1392
1390static int asus_hotk_remove(struct acpi_device *device, int type) 1393static int asus_hotk_remove(struct acpi_device *device, int type)
1391{ 1394{
1392 acpi_status status = 0;
1393
1394 if (!device || !acpi_driver_data(device)) 1395 if (!device || !acpi_driver_data(device))
1395 return -EINVAL; 1396 return -EINVAL;
1396 1397
1397 status = acpi_remove_notify_handler(hotk->handle, ACPI_SYSTEM_NOTIFY,
1398 asus_hotk_notify);
1399 if (ACPI_FAILURE(status))
1400 printk(KERN_ERR "Asus ACPI: Error removing notify handler\n");
1401
1402 asus_hotk_remove_fs(device); 1398 asus_hotk_remove_fs(device);
1403 1399
1404 kfree(hotk); 1400 kfree(hotk);
diff --git a/drivers/platform/x86/dell-wmi.c b/drivers/platform/x86/dell-wmi.c
index 2fab94162147..0f900cc9fa7a 100644
--- a/drivers/platform/x86/dell-wmi.c
+++ b/drivers/platform/x86/dell-wmi.c
@@ -46,10 +46,53 @@ struct key_entry {
46 u16 keycode; 46 u16 keycode;
47}; 47};
48 48
49enum { KE_KEY, KE_SW, KE_END }; 49enum { KE_KEY, KE_SW, KE_IGNORE, KE_END };
50
51/*
52 * Certain keys are flagged as KE_IGNORE. All of these are either
53 * notifications (rather than requests for change) or are also sent
54 * via the keyboard controller so should not be sent again.
55 */
50 56
51static struct key_entry dell_wmi_keymap[] = { 57static struct key_entry dell_wmi_keymap[] = {
52 {KE_KEY, 0xe045, KEY_PROG1}, 58 {KE_KEY, 0xe045, KEY_PROG1},
59 {KE_KEY, 0xe009, KEY_EJECTCD},
60
61 /* These also contain the brightness level at offset 6 */
62 {KE_KEY, 0xe006, KEY_BRIGHTNESSUP},
63 {KE_KEY, 0xe005, KEY_BRIGHTNESSDOWN},
64
65 /* Battery health status button */
66 {KE_KEY, 0xe007, KEY_BATTERY},
67
68 /* This is actually for all radios. Although physically a
69 * switch, the notification does not provide an indication of
70 * state and so it should be reported as a key */
71 {KE_KEY, 0xe008, KEY_WLAN},
72
73 /* The next device is at offset 6, the active devices are at
74 offset 8 and the attached devices at offset 10 */
75 {KE_KEY, 0xe00b, KEY_DISPLAYTOGGLE},
76
77 {KE_IGNORE, 0xe00c, KEY_KBDILLUMTOGGLE},
78
79 /* BIOS error detected */
80 {KE_IGNORE, 0xe00d, KEY_RESERVED},
81
82 /* Wifi Catcher */
83 {KE_KEY, 0xe011, KEY_PROG2},
84
85 /* Ambient light sensor toggle */
86 {KE_IGNORE, 0xe013, KEY_RESERVED},
87
88 {KE_IGNORE, 0xe020, KEY_MUTE},
89 {KE_IGNORE, 0xe02e, KEY_VOLUMEDOWN},
90 {KE_IGNORE, 0xe030, KEY_VOLUMEUP},
91 {KE_IGNORE, 0xe033, KEY_KBDILLUMUP},
92 {KE_IGNORE, 0xe034, KEY_KBDILLUMDOWN},
93 {KE_IGNORE, 0xe03a, KEY_CAPSLOCK},
94 {KE_IGNORE, 0xe045, KEY_NUMLOCK},
95 {KE_IGNORE, 0xe046, KEY_SCROLLLOCK},
53 {KE_END, 0} 96 {KE_END, 0}
54}; 97};
55 98
@@ -122,15 +165,20 @@ static void dell_wmi_notify(u32 value, void *context)
122 165
123 if (obj && obj->type == ACPI_TYPE_BUFFER) { 166 if (obj && obj->type == ACPI_TYPE_BUFFER) {
124 int *buffer = (int *)obj->buffer.pointer; 167 int *buffer = (int *)obj->buffer.pointer;
125 key = dell_wmi_get_entry_by_scancode(buffer[1]); 168 /*
169 * The upper bytes of the event may contain
170 * additional information, so mask them off for the
171 * scancode lookup
172 */
173 key = dell_wmi_get_entry_by_scancode(buffer[1] & 0xFFFF);
126 if (key) { 174 if (key) {
127 input_report_key(dell_wmi_input_dev, key->keycode, 1); 175 input_report_key(dell_wmi_input_dev, key->keycode, 1);
128 input_sync(dell_wmi_input_dev); 176 input_sync(dell_wmi_input_dev);
129 input_report_key(dell_wmi_input_dev, key->keycode, 0); 177 input_report_key(dell_wmi_input_dev, key->keycode, 0);
130 input_sync(dell_wmi_input_dev); 178 input_sync(dell_wmi_input_dev);
131 } else 179 } else if (buffer[1] & 0xFFFF)
132 printk(KERN_INFO "dell-wmi: Unknown key %x pressed\n", 180 printk(KERN_INFO "dell-wmi: Unknown key %x pressed\n",
133 buffer[1]); 181 buffer[1] & 0xFFFF);
134 } 182 }
135} 183}
136 184
diff --git a/drivers/platform/x86/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c
index 8153b3e59189..4207b26ff990 100644
--- a/drivers/platform/x86/eeepc-laptop.c
+++ b/drivers/platform/x86/eeepc-laptop.c
@@ -62,7 +62,10 @@ enum {
62 DISABLE_ASL_GPS = 0x0020, 62 DISABLE_ASL_GPS = 0x0020,
63 DISABLE_ASL_DISPLAYSWITCH = 0x0040, 63 DISABLE_ASL_DISPLAYSWITCH = 0x0040,
64 DISABLE_ASL_MODEM = 0x0080, 64 DISABLE_ASL_MODEM = 0x0080,
65 DISABLE_ASL_CARDREADER = 0x0100 65 DISABLE_ASL_CARDREADER = 0x0100,
66 DISABLE_ASL_3G = 0x0200,
67 DISABLE_ASL_WIMAX = 0x0400,
68 DISABLE_ASL_HWCF = 0x0800
66}; 69};
67 70
68enum { 71enum {
@@ -87,7 +90,13 @@ enum {
87 CM_ASL_USBPORT3, 90 CM_ASL_USBPORT3,
88 CM_ASL_MODEM, 91 CM_ASL_MODEM,
89 CM_ASL_CARDREADER, 92 CM_ASL_CARDREADER,
90 CM_ASL_LID 93 CM_ASL_3G,
94 CM_ASL_WIMAX,
95 CM_ASL_HWCF,
96 CM_ASL_LID,
97 CM_ASL_TYPE,
98 CM_ASL_PANELPOWER, /*P901*/
99 CM_ASL_TPD
91}; 100};
92 101
93static const char *cm_getv[] = { 102static const char *cm_getv[] = {
@@ -96,7 +105,8 @@ static const char *cm_getv[] = {
96 NULL, "PBLG", NULL, NULL, 105 NULL, "PBLG", NULL, NULL,
97 "CFVG", NULL, NULL, NULL, 106 "CFVG", NULL, NULL, NULL,
98 "USBG", NULL, NULL, "MODG", 107 "USBG", NULL, NULL, "MODG",
99 "CRDG", "LIDG" 108 "CRDG", "M3GG", "WIMG", "HWCF",
109 "LIDG", "TYPE", "PBPG", "TPDG"
100}; 110};
101 111
102static const char *cm_setv[] = { 112static const char *cm_setv[] = {
@@ -105,7 +115,8 @@ static const char *cm_setv[] = {
105 "SDSP", "PBLS", "HDPS", NULL, 115 "SDSP", "PBLS", "HDPS", NULL,
106 "CFVS", NULL, NULL, NULL, 116 "CFVS", NULL, NULL, NULL,
107 "USBG", NULL, NULL, "MODS", 117 "USBG", NULL, NULL, "MODS",
108 "CRDS", NULL 118 "CRDS", "M3GS", "WIMS", NULL,
119 NULL, NULL, "PBPS", "TPDS"
109}; 120};
110 121
111#define EEEPC_EC "\\_SB.PCI0.SBRG.EC0." 122#define EEEPC_EC "\\_SB.PCI0.SBRG.EC0."
@@ -181,6 +192,7 @@ static struct key_entry eeepc_keymap[] = {
181static int eeepc_hotk_add(struct acpi_device *device); 192static int eeepc_hotk_add(struct acpi_device *device);
182static int eeepc_hotk_remove(struct acpi_device *device, int type); 193static int eeepc_hotk_remove(struct acpi_device *device, int type);
183static int eeepc_hotk_resume(struct acpi_device *device); 194static int eeepc_hotk_resume(struct acpi_device *device);
195static void eeepc_hotk_notify(struct acpi_device *device, u32 event);
184 196
185static const struct acpi_device_id eeepc_device_ids[] = { 197static const struct acpi_device_id eeepc_device_ids[] = {
186 {EEEPC_HOTK_HID, 0}, 198 {EEEPC_HOTK_HID, 0},
@@ -192,10 +204,12 @@ static struct acpi_driver eeepc_hotk_driver = {
192 .name = EEEPC_HOTK_NAME, 204 .name = EEEPC_HOTK_NAME,
193 .class = EEEPC_HOTK_CLASS, 205 .class = EEEPC_HOTK_CLASS,
194 .ids = eeepc_device_ids, 206 .ids = eeepc_device_ids,
207 .flags = ACPI_DRIVER_ALL_NOTIFY_EVENTS,
195 .ops = { 208 .ops = {
196 .add = eeepc_hotk_add, 209 .add = eeepc_hotk_add,
197 .remove = eeepc_hotk_remove, 210 .remove = eeepc_hotk_remove,
198 .resume = eeepc_hotk_resume, 211 .resume = eeepc_hotk_resume,
212 .notify = eeepc_hotk_notify,
199 }, 213 },
200}; 214};
201 215
@@ -318,6 +332,15 @@ static const struct rfkill_ops eeepc_rfkill_ops = {
318 .set_block = eeepc_rfkill_set, 332 .set_block = eeepc_rfkill_set,
319}; 333};
320 334
335static void __init eeepc_enable_camera(void)
336{
337 /*
338 * If the following call to set_acpi() fails, it's because there's no
339 * camera so we can ignore the error.
340 */
341 set_acpi(CM_ASL_CAMERA, 1);
342}
343
321/* 344/*
322 * Sys helpers 345 * Sys helpers
323 */ 346 */
@@ -369,13 +392,88 @@ static ssize_t show_sys_acpi(int cm, char *buf)
369EEEPC_CREATE_DEVICE_ATTR(camera, CM_ASL_CAMERA); 392EEEPC_CREATE_DEVICE_ATTR(camera, CM_ASL_CAMERA);
370EEEPC_CREATE_DEVICE_ATTR(cardr, CM_ASL_CARDREADER); 393EEEPC_CREATE_DEVICE_ATTR(cardr, CM_ASL_CARDREADER);
371EEEPC_CREATE_DEVICE_ATTR(disp, CM_ASL_DISPLAYSWITCH); 394EEEPC_CREATE_DEVICE_ATTR(disp, CM_ASL_DISPLAYSWITCH);
372EEEPC_CREATE_DEVICE_ATTR(cpufv, CM_ASL_CPUFV); 395
396struct eeepc_cpufv {
397 int num;
398 int cur;
399};
400
401static int get_cpufv(struct eeepc_cpufv *c)
402{
403 c->cur = get_acpi(CM_ASL_CPUFV);
404 c->num = (c->cur >> 8) & 0xff;
405 c->cur &= 0xff;
406 if (c->cur < 0 || c->num <= 0 || c->num > 12)
407 return -ENODEV;
408 return 0;
409}
410
411static ssize_t show_available_cpufv(struct device *dev,
412 struct device_attribute *attr,
413 char *buf)
414{
415 struct eeepc_cpufv c;
416 int i;
417 ssize_t len = 0;
418
419 if (get_cpufv(&c))
420 return -ENODEV;
421 for (i = 0; i < c.num; i++)
422 len += sprintf(buf + len, "%d ", i);
423 len += sprintf(buf + len, "\n");
424 return len;
425}
426
427static ssize_t show_cpufv(struct device *dev,
428 struct device_attribute *attr,
429 char *buf)
430{
431 struct eeepc_cpufv c;
432
433 if (get_cpufv(&c))
434 return -ENODEV;
435 return sprintf(buf, "%#x\n", (c.num << 8) | c.cur);
436}
437
438static ssize_t store_cpufv(struct device *dev,
439 struct device_attribute *attr,
440 const char *buf, size_t count)
441{
442 struct eeepc_cpufv c;
443 int rv, value;
444
445 if (get_cpufv(&c))
446 return -ENODEV;
447 rv = parse_arg(buf, count, &value);
448 if (rv < 0)
449 return rv;
450 if (!rv || value < 0 || value >= c.num)
451 return -EINVAL;
452 set_acpi(CM_ASL_CPUFV, value);
453 return rv;
454}
455
456static struct device_attribute dev_attr_cpufv = {
457 .attr = {
458 .name = "cpufv",
459 .mode = 0644 },
460 .show = show_cpufv,
461 .store = store_cpufv
462};
463
464static struct device_attribute dev_attr_available_cpufv = {
465 .attr = {
466 .name = "available_cpufv",
467 .mode = 0444 },
468 .show = show_available_cpufv
469};
373 470
374static struct attribute *platform_attributes[] = { 471static struct attribute *platform_attributes[] = {
375 &dev_attr_camera.attr, 472 &dev_attr_camera.attr,
376 &dev_attr_cardr.attr, 473 &dev_attr_cardr.attr,
377 &dev_attr_disp.attr, 474 &dev_attr_disp.attr,
378 &dev_attr_cpufv.attr, 475 &dev_attr_cpufv.attr,
476 &dev_attr_available_cpufv.attr,
379 NULL 477 NULL
380}; 478};
381 479
@@ -558,7 +656,7 @@ static void eeepc_rfkill_notify(acpi_handle handle, u32 event, void *data)
558 eeepc_rfkill_hotplug(); 656 eeepc_rfkill_hotplug();
559} 657}
560 658
561static void eeepc_hotk_notify(acpi_handle handle, u32 event, void *data) 659static void eeepc_hotk_notify(struct acpi_device *device, u32 event)
562{ 660{
563 static struct key_entry *key; 661 static struct key_entry *key;
564 u16 count; 662 u16 count;
@@ -566,6 +664,8 @@ static void eeepc_hotk_notify(acpi_handle handle, u32 event, void *data)
566 664
567 if (!ehotk) 665 if (!ehotk)
568 return; 666 return;
667 if (event > ACPI_MAX_SYS_NOTIFY)
668 return;
569 if (event >= NOTIFY_BRN_MIN && event <= NOTIFY_BRN_MAX) 669 if (event >= NOTIFY_BRN_MIN && event <= NOTIFY_BRN_MAX)
570 brn = notify_brn(); 670 brn = notify_brn();
571 count = ehotk->event_count[event % 128]++; 671 count = ehotk->event_count[event % 128]++;
@@ -646,7 +746,6 @@ static void eeepc_unregister_rfkill_notifier(char *node)
646 746
647static int eeepc_hotk_add(struct acpi_device *device) 747static int eeepc_hotk_add(struct acpi_device *device)
648{ 748{
649 acpi_status status = AE_OK;
650 int result; 749 int result;
651 750
652 if (!device) 751 if (!device)
@@ -664,10 +763,6 @@ static int eeepc_hotk_add(struct acpi_device *device)
664 result = eeepc_hotk_check(); 763 result = eeepc_hotk_check();
665 if (result) 764 if (result)
666 goto ehotk_fail; 765 goto ehotk_fail;
667 status = acpi_install_notify_handler(ehotk->handle, ACPI_SYSTEM_NOTIFY,
668 eeepc_hotk_notify, ehotk);
669 if (ACPI_FAILURE(status))
670 printk(EEEPC_ERR "Error installing notify handler\n");
671 766
672 eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P6"); 767 eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P6");
673 eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P7"); 768 eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P7");
@@ -725,14 +820,8 @@ static int eeepc_hotk_add(struct acpi_device *device)
725 820
726static int eeepc_hotk_remove(struct acpi_device *device, int type) 821static int eeepc_hotk_remove(struct acpi_device *device, int type)
727{ 822{
728 acpi_status status = 0;
729
730 if (!device || !acpi_driver_data(device)) 823 if (!device || !acpi_driver_data(device))
731 return -EINVAL; 824 return -EINVAL;
732 status = acpi_remove_notify_handler(ehotk->handle, ACPI_SYSTEM_NOTIFY,
733 eeepc_hotk_notify);
734 if (ACPI_FAILURE(status))
735 printk(EEEPC_ERR "Error removing notify handler\n");
736 825
737 eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P6"); 826 eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P6");
738 eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P7"); 827 eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P7");
@@ -989,6 +1078,9 @@ static int __init eeepc_laptop_init(void)
989 result = eeepc_hwmon_init(dev); 1078 result = eeepc_hwmon_init(dev);
990 if (result) 1079 if (result)
991 goto fail_hwmon; 1080 goto fail_hwmon;
1081
1082 eeepc_enable_camera();
1083
992 /* Register platform stuff */ 1084 /* Register platform stuff */
993 result = platform_driver_register(&platform_driver); 1085 result = platform_driver_register(&platform_driver);
994 if (result) 1086 if (result)
diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c
index 16fffe44e333..4ac2311c00af 100644
--- a/drivers/platform/x86/hp-wmi.c
+++ b/drivers/platform/x86/hp-wmi.c
@@ -47,7 +47,7 @@ MODULE_ALIAS("wmi:5FB7F034-2C63-45e9-BE91-3D44E2C707E4");
47#define HPWMI_DISPLAY_QUERY 0x1 47#define HPWMI_DISPLAY_QUERY 0x1
48#define HPWMI_HDDTEMP_QUERY 0x2 48#define HPWMI_HDDTEMP_QUERY 0x2
49#define HPWMI_ALS_QUERY 0x3 49#define HPWMI_ALS_QUERY 0x3
50#define HPWMI_DOCK_QUERY 0x4 50#define HPWMI_HARDWARE_QUERY 0x4
51#define HPWMI_WIRELESS_QUERY 0x5 51#define HPWMI_WIRELESS_QUERY 0x5
52#define HPWMI_HOTKEY_QUERY 0xc 52#define HPWMI_HOTKEY_QUERY 0xc
53 53
@@ -75,10 +75,9 @@ struct key_entry {
75 u16 keycode; 75 u16 keycode;
76}; 76};
77 77
78enum { KE_KEY, KE_SW, KE_END }; 78enum { KE_KEY, KE_END };
79 79
80static struct key_entry hp_wmi_keymap[] = { 80static struct key_entry hp_wmi_keymap[] = {
81 {KE_SW, 0x01, SW_DOCK},
82 {KE_KEY, 0x02, KEY_BRIGHTNESSUP}, 81 {KE_KEY, 0x02, KEY_BRIGHTNESSUP},
83 {KE_KEY, 0x03, KEY_BRIGHTNESSDOWN}, 82 {KE_KEY, 0x03, KEY_BRIGHTNESSDOWN},
84 {KE_KEY, 0x20e6, KEY_PROG1}, 83 {KE_KEY, 0x20e6, KEY_PROG1},
@@ -151,7 +150,22 @@ static int hp_wmi_als_state(void)
151 150
152static int hp_wmi_dock_state(void) 151static int hp_wmi_dock_state(void)
153{ 152{
154 return hp_wmi_perform_query(HPWMI_DOCK_QUERY, 0, 0); 153 int ret = hp_wmi_perform_query(HPWMI_HARDWARE_QUERY, 0, 0);
154
155 if (ret < 0)
156 return ret;
157
158 return ret & 0x1;
159}
160
161static int hp_wmi_tablet_state(void)
162{
163 int ret = hp_wmi_perform_query(HPWMI_HARDWARE_QUERY, 0, 0);
164
165 if (ret < 0)
166 return ret;
167
168 return (ret & 0x4) ? 1 : 0;
155} 169}
156 170
157static int hp_wmi_set_block(void *data, bool blocked) 171static int hp_wmi_set_block(void *data, bool blocked)
@@ -232,6 +246,15 @@ static ssize_t show_dock(struct device *dev, struct device_attribute *attr,
232 return sprintf(buf, "%d\n", value); 246 return sprintf(buf, "%d\n", value);
233} 247}
234 248
249static ssize_t show_tablet(struct device *dev, struct device_attribute *attr,
250 char *buf)
251{
252 int value = hp_wmi_tablet_state();
253 if (value < 0)
254 return -EINVAL;
255 return sprintf(buf, "%d\n", value);
256}
257
235static ssize_t set_als(struct device *dev, struct device_attribute *attr, 258static ssize_t set_als(struct device *dev, struct device_attribute *attr,
236 const char *buf, size_t count) 259 const char *buf, size_t count)
237{ 260{
@@ -244,6 +267,7 @@ static DEVICE_ATTR(display, S_IRUGO, show_display, NULL);
244static DEVICE_ATTR(hddtemp, S_IRUGO, show_hddtemp, NULL); 267static DEVICE_ATTR(hddtemp, S_IRUGO, show_hddtemp, NULL);
245static DEVICE_ATTR(als, S_IRUGO | S_IWUSR, show_als, set_als); 268static DEVICE_ATTR(als, S_IRUGO | S_IWUSR, show_als, set_als);
246static DEVICE_ATTR(dock, S_IRUGO, show_dock, NULL); 269static DEVICE_ATTR(dock, S_IRUGO, show_dock, NULL);
270static DEVICE_ATTR(tablet, S_IRUGO, show_tablet, NULL);
247 271
248static struct key_entry *hp_wmi_get_entry_by_scancode(int code) 272static struct key_entry *hp_wmi_get_entry_by_scancode(int code)
249{ 273{
@@ -326,13 +350,13 @@ static void hp_wmi_notify(u32 value, void *context)
326 key->keycode, 0); 350 key->keycode, 0);
327 input_sync(hp_wmi_input_dev); 351 input_sync(hp_wmi_input_dev);
328 break; 352 break;
329 case KE_SW:
330 input_report_switch(hp_wmi_input_dev,
331 key->keycode,
332 hp_wmi_dock_state());
333 input_sync(hp_wmi_input_dev);
334 break;
335 } 353 }
354 } else if (eventcode == 0x1) {
355 input_report_switch(hp_wmi_input_dev, SW_DOCK,
356 hp_wmi_dock_state());
357 input_report_switch(hp_wmi_input_dev, SW_TABLET_MODE,
358 hp_wmi_tablet_state());
359 input_sync(hp_wmi_input_dev);
336 } else if (eventcode == 0x5) { 360 } else if (eventcode == 0x5) {
337 if (wifi_rfkill) 361 if (wifi_rfkill)
338 rfkill_set_sw_state(wifi_rfkill, 362 rfkill_set_sw_state(wifi_rfkill,
@@ -369,18 +393,19 @@ static int __init hp_wmi_input_setup(void)
369 set_bit(EV_KEY, hp_wmi_input_dev->evbit); 393 set_bit(EV_KEY, hp_wmi_input_dev->evbit);
370 set_bit(key->keycode, hp_wmi_input_dev->keybit); 394 set_bit(key->keycode, hp_wmi_input_dev->keybit);
371 break; 395 break;
372 case KE_SW:
373 set_bit(EV_SW, hp_wmi_input_dev->evbit);
374 set_bit(key->keycode, hp_wmi_input_dev->swbit);
375
376 /* Set initial dock state */
377 input_report_switch(hp_wmi_input_dev, key->keycode,
378 hp_wmi_dock_state());
379 input_sync(hp_wmi_input_dev);
380 break;
381 } 396 }
382 } 397 }
383 398
399 set_bit(EV_SW, hp_wmi_input_dev->evbit);
400 set_bit(SW_DOCK, hp_wmi_input_dev->swbit);
401 set_bit(SW_TABLET_MODE, hp_wmi_input_dev->swbit);
402
403 /* Set initial hardware state */
404 input_report_switch(hp_wmi_input_dev, SW_DOCK, hp_wmi_dock_state());
405 input_report_switch(hp_wmi_input_dev, SW_TABLET_MODE,
406 hp_wmi_tablet_state());
407 input_sync(hp_wmi_input_dev);
408
384 err = input_register_device(hp_wmi_input_dev); 409 err = input_register_device(hp_wmi_input_dev);
385 410
386 if (err) { 411 if (err) {
@@ -397,6 +422,7 @@ static void cleanup_sysfs(struct platform_device *device)
397 device_remove_file(&device->dev, &dev_attr_hddtemp); 422 device_remove_file(&device->dev, &dev_attr_hddtemp);
398 device_remove_file(&device->dev, &dev_attr_als); 423 device_remove_file(&device->dev, &dev_attr_als);
399 device_remove_file(&device->dev, &dev_attr_dock); 424 device_remove_file(&device->dev, &dev_attr_dock);
425 device_remove_file(&device->dev, &dev_attr_tablet);
400} 426}
401 427
402static int __init hp_wmi_bios_setup(struct platform_device *device) 428static int __init hp_wmi_bios_setup(struct platform_device *device)
@@ -416,6 +442,9 @@ static int __init hp_wmi_bios_setup(struct platform_device *device)
416 err = device_create_file(&device->dev, &dev_attr_dock); 442 err = device_create_file(&device->dev, &dev_attr_dock);
417 if (err) 443 if (err)
418 goto add_sysfs_error; 444 goto add_sysfs_error;
445 err = device_create_file(&device->dev, &dev_attr_tablet);
446 if (err)
447 goto add_sysfs_error;
419 448
420 if (wireless & 0x1) { 449 if (wireless & 0x1) {
421 wifi_rfkill = rfkill_alloc("hp-wifi", &device->dev, 450 wifi_rfkill = rfkill_alloc("hp-wifi", &device->dev,
@@ -485,23 +514,17 @@ static int __exit hp_wmi_bios_remove(struct platform_device *device)
485 514
486static int hp_wmi_resume_handler(struct platform_device *device) 515static int hp_wmi_resume_handler(struct platform_device *device)
487{ 516{
488 struct key_entry *key;
489
490 /* 517 /*
491 * Docking state may have changed while suspended, so trigger 518 * Hardware state may have changed while suspended, so trigger
492 * an input event for the current state. As this is a switch, 519 * input events for the current state. As this is a switch,
493 * the input layer will only actually pass it on if the state 520 * the input layer will only actually pass it on if the state
494 * changed. 521 * changed.
495 */ 522 */
496 for (key = hp_wmi_keymap; key->type != KE_END; key++) { 523
497 switch (key->type) { 524 input_report_switch(hp_wmi_input_dev, SW_DOCK, hp_wmi_dock_state());
498 case KE_SW: 525 input_report_switch(hp_wmi_input_dev, SW_TABLET_MODE,
499 input_report_switch(hp_wmi_input_dev, key->keycode, 526 hp_wmi_tablet_state());
500 hp_wmi_dock_state()); 527 input_sync(hp_wmi_input_dev);
501 input_sync(hp_wmi_input_dev);
502 break;
503 }
504 }
505 528
506 return 0; 529 return 0;
507} 530}
diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c
index 40d64c03278c..a463fd72c495 100644
--- a/drivers/platform/x86/thinkpad_acpi.c
+++ b/drivers/platform/x86/thinkpad_acpi.c
@@ -22,7 +22,7 @@
22 */ 22 */
23 23
24#define TPACPI_VERSION "0.23" 24#define TPACPI_VERSION "0.23"
25#define TPACPI_SYSFS_VERSION 0x020300 25#define TPACPI_SYSFS_VERSION 0x020400
26 26
27/* 27/*
28 * Changelog: 28 * Changelog:
@@ -257,6 +257,8 @@ static struct {
257 u32 wan:1; 257 u32 wan:1;
258 u32 uwb:1; 258 u32 uwb:1;
259 u32 fan_ctrl_status_undef:1; 259 u32 fan_ctrl_status_undef:1;
260 u32 second_fan:1;
261 u32 beep_needs_two_args:1;
260 u32 input_device_registered:1; 262 u32 input_device_registered:1;
261 u32 platform_drv_registered:1; 263 u32 platform_drv_registered:1;
262 u32 platform_drv_attrs_registered:1; 264 u32 platform_drv_attrs_registered:1;
@@ -277,8 +279,10 @@ struct thinkpad_id_data {
277 char *bios_version_str; /* Something like 1ZET51WW (1.03z) */ 279 char *bios_version_str; /* Something like 1ZET51WW (1.03z) */
278 char *ec_version_str; /* Something like 1ZHT51WW-1.04a */ 280 char *ec_version_str; /* Something like 1ZHT51WW-1.04a */
279 281
280 u16 bios_model; /* Big Endian, TP-1Y = 0x5931, 0 = unknown */ 282 u16 bios_model; /* 1Y = 0x5931, 0 = unknown */
281 u16 ec_model; 283 u16 ec_model;
284 u16 bios_release; /* 1ZETK1WW = 0x314b, 0 = unknown */
285 u16 ec_release;
282 286
283 char *model_str; /* ThinkPad T43 */ 287 char *model_str; /* ThinkPad T43 */
284 char *nummodel_str; /* 9384A9C for a 9384-A9C model */ 288 char *nummodel_str; /* 9384A9C for a 9384-A9C model */
@@ -355,6 +359,73 @@ static void tpacpi_log_usertask(const char * const what)
355 } \ 359 } \
356 } while (0) 360 } while (0)
357 361
362/*
363 * Quirk handling helpers
364 *
365 * ThinkPad IDs and versions seen in the field so far
366 * are two-characters from the set [0-9A-Z], i.e. base 36.
367 *
368 * We use values well outside that range as specials.
369 */
370
371#define TPACPI_MATCH_ANY 0xffffU
372#define TPACPI_MATCH_UNKNOWN 0U
373
374/* TPID('1', 'Y') == 0x5931 */
375#define TPID(__c1, __c2) (((__c2) << 8) | (__c1))
376
377#define TPACPI_Q_IBM(__id1, __id2, __quirk) \
378 { .vendor = PCI_VENDOR_ID_IBM, \
379 .bios = TPID(__id1, __id2), \
380 .ec = TPACPI_MATCH_ANY, \
381 .quirks = (__quirk) }
382
383#define TPACPI_Q_LNV(__id1, __id2, __quirk) \
384 { .vendor = PCI_VENDOR_ID_LENOVO, \
385 .bios = TPID(__id1, __id2), \
386 .ec = TPACPI_MATCH_ANY, \
387 .quirks = (__quirk) }
388
389struct tpacpi_quirk {
390 unsigned int vendor;
391 u16 bios;
392 u16 ec;
393 unsigned long quirks;
394};
395
396/**
397 * tpacpi_check_quirks() - search BIOS/EC version on a list
398 * @qlist: array of &struct tpacpi_quirk
399 * @qlist_size: number of elements in @qlist
400 *
401 * Iterates over a quirks list until one is found that matches the
402 * ThinkPad's vendor, BIOS and EC model.
403 *
404 * Returns 0 if nothing matches, otherwise returns the quirks field of
405 * the matching &struct tpacpi_quirk entry.
406 *
407 * The match criteria is: vendor, ec and bios much match.
408 */
409static unsigned long __init tpacpi_check_quirks(
410 const struct tpacpi_quirk *qlist,
411 unsigned int qlist_size)
412{
413 while (qlist_size) {
414 if ((qlist->vendor == thinkpad_id.vendor ||
415 qlist->vendor == TPACPI_MATCH_ANY) &&
416 (qlist->bios == thinkpad_id.bios_model ||
417 qlist->bios == TPACPI_MATCH_ANY) &&
418 (qlist->ec == thinkpad_id.ec_model ||
419 qlist->ec == TPACPI_MATCH_ANY))
420 return qlist->quirks;
421
422 qlist_size--;
423 qlist++;
424 }
425 return 0;
426}
427
428
358/**************************************************************************** 429/****************************************************************************
359 **************************************************************************** 430 ****************************************************************************
360 * 431 *
@@ -2880,7 +2951,7 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
2880 /* update bright_acpimode... */ 2951 /* update bright_acpimode... */
2881 tpacpi_check_std_acpi_brightness_support(); 2952 tpacpi_check_std_acpi_brightness_support();
2882 2953
2883 if (tp_features.bright_acpimode) { 2954 if (tp_features.bright_acpimode && acpi_video_backlight_support()) {
2884 printk(TPACPI_INFO 2955 printk(TPACPI_INFO
2885 "This ThinkPad has standard ACPI backlight " 2956 "This ThinkPad has standard ACPI backlight "
2886 "brightness control, supported by the ACPI " 2957 "brightness control, supported by the ACPI "
@@ -4773,7 +4844,7 @@ TPACPI_HANDLE(led, ec, "SLED", /* 570 */
4773 "LED", /* all others */ 4844 "LED", /* all others */
4774 ); /* R30, R31 */ 4845 ); /* R30, R31 */
4775 4846
4776#define TPACPI_LED_NUMLEDS 8 4847#define TPACPI_LED_NUMLEDS 16
4777static struct tpacpi_led_classdev *tpacpi_leds; 4848static struct tpacpi_led_classdev *tpacpi_leds;
4778static enum led_status_t tpacpi_led_state_cache[TPACPI_LED_NUMLEDS]; 4849static enum led_status_t tpacpi_led_state_cache[TPACPI_LED_NUMLEDS];
4779static const char * const tpacpi_led_names[TPACPI_LED_NUMLEDS] = { 4850static const char * const tpacpi_led_names[TPACPI_LED_NUMLEDS] = {
@@ -4786,15 +4857,20 @@ static const char * const tpacpi_led_names[TPACPI_LED_NUMLEDS] = {
4786 "tpacpi::dock_batt", 4857 "tpacpi::dock_batt",
4787 "tpacpi::unknown_led", 4858 "tpacpi::unknown_led",
4788 "tpacpi::standby", 4859 "tpacpi::standby",
4860 "tpacpi::dock_status1",
4861 "tpacpi::dock_status2",
4862 "tpacpi::unknown_led2",
4863 "tpacpi::unknown_led3",
4864 "tpacpi::thinkvantage",
4789}; 4865};
4790#define TPACPI_SAFE_LEDS 0x0081U 4866#define TPACPI_SAFE_LEDS 0x1081U
4791 4867
4792static inline bool tpacpi_is_led_restricted(const unsigned int led) 4868static inline bool tpacpi_is_led_restricted(const unsigned int led)
4793{ 4869{
4794#ifdef CONFIG_THINKPAD_ACPI_UNSAFE_LEDS 4870#ifdef CONFIG_THINKPAD_ACPI_UNSAFE_LEDS
4795 return false; 4871 return false;
4796#else 4872#else
4797 return (TPACPI_SAFE_LEDS & (1 << led)) == 0; 4873 return (1U & (TPACPI_SAFE_LEDS >> led)) == 0;
4798#endif 4874#endif
4799} 4875}
4800 4876
@@ -4956,6 +5032,10 @@ static int __init tpacpi_init_led(unsigned int led)
4956 5032
4957 tpacpi_leds[led].led = led; 5033 tpacpi_leds[led].led = led;
4958 5034
5035 /* LEDs with no name don't get registered */
5036 if (!tpacpi_led_names[led])
5037 return 0;
5038
4959 tpacpi_leds[led].led_classdev.brightness_set = &led_sysfs_set; 5039 tpacpi_leds[led].led_classdev.brightness_set = &led_sysfs_set;
4960 tpacpi_leds[led].led_classdev.blink_set = &led_sysfs_blink_set; 5040 tpacpi_leds[led].led_classdev.blink_set = &led_sysfs_blink_set;
4961 if (led_supported == TPACPI_LED_570) 5041 if (led_supported == TPACPI_LED_570)
@@ -4974,10 +5054,59 @@ static int __init tpacpi_init_led(unsigned int led)
4974 return rc; 5054 return rc;
4975} 5055}
4976 5056
5057static const struct tpacpi_quirk led_useful_qtable[] __initconst = {
5058 TPACPI_Q_IBM('1', 'E', 0x009f), /* A30 */
5059 TPACPI_Q_IBM('1', 'N', 0x009f), /* A31 */
5060 TPACPI_Q_IBM('1', 'G', 0x009f), /* A31 */
5061
5062 TPACPI_Q_IBM('1', 'I', 0x0097), /* T30 */
5063 TPACPI_Q_IBM('1', 'R', 0x0097), /* T40, T41, T42, R50, R51 */
5064 TPACPI_Q_IBM('7', '0', 0x0097), /* T43, R52 */
5065 TPACPI_Q_IBM('1', 'Y', 0x0097), /* T43 */
5066 TPACPI_Q_IBM('1', 'W', 0x0097), /* R50e */
5067 TPACPI_Q_IBM('1', 'V', 0x0097), /* R51 */
5068 TPACPI_Q_IBM('7', '8', 0x0097), /* R51e */
5069 TPACPI_Q_IBM('7', '6', 0x0097), /* R52 */
5070
5071 TPACPI_Q_IBM('1', 'K', 0x00bf), /* X30 */
5072 TPACPI_Q_IBM('1', 'Q', 0x00bf), /* X31, X32 */
5073 TPACPI_Q_IBM('1', 'U', 0x00bf), /* X40 */
5074 TPACPI_Q_IBM('7', '4', 0x00bf), /* X41 */
5075 TPACPI_Q_IBM('7', '5', 0x00bf), /* X41t */
5076
5077 TPACPI_Q_IBM('7', '9', 0x1f97), /* T60 (1) */
5078 TPACPI_Q_IBM('7', '7', 0x1f97), /* Z60* (1) */
5079 TPACPI_Q_IBM('7', 'F', 0x1f97), /* Z61* (1) */
5080 TPACPI_Q_IBM('7', 'B', 0x1fb7), /* X60 (1) */
5081
5082 /* (1) - may have excess leds enabled on MSB */
5083
5084 /* Defaults (order matters, keep last, don't reorder!) */
5085 { /* Lenovo */
5086 .vendor = PCI_VENDOR_ID_LENOVO,
5087 .bios = TPACPI_MATCH_ANY, .ec = TPACPI_MATCH_ANY,
5088 .quirks = 0x1fffU,
5089 },
5090 { /* IBM ThinkPads with no EC version string */
5091 .vendor = PCI_VENDOR_ID_IBM,
5092 .bios = TPACPI_MATCH_ANY, .ec = TPACPI_MATCH_UNKNOWN,
5093 .quirks = 0x00ffU,
5094 },
5095 { /* IBM ThinkPads with EC version string */
5096 .vendor = PCI_VENDOR_ID_IBM,
5097 .bios = TPACPI_MATCH_ANY, .ec = TPACPI_MATCH_ANY,
5098 .quirks = 0x00bfU,
5099 },
5100};
5101
5102#undef TPACPI_LEDQ_IBM
5103#undef TPACPI_LEDQ_LNV
5104
4977static int __init led_init(struct ibm_init_struct *iibm) 5105static int __init led_init(struct ibm_init_struct *iibm)
4978{ 5106{
4979 unsigned int i; 5107 unsigned int i;
4980 int rc; 5108 int rc;
5109 unsigned long useful_leds;
4981 5110
4982 vdbg_printk(TPACPI_DBG_INIT, "initializing LED subdriver\n"); 5111 vdbg_printk(TPACPI_DBG_INIT, "initializing LED subdriver\n");
4983 5112
@@ -4999,6 +5128,9 @@ static int __init led_init(struct ibm_init_struct *iibm)
4999 vdbg_printk(TPACPI_DBG_INIT, "LED commands are %s, mode %d\n", 5128 vdbg_printk(TPACPI_DBG_INIT, "LED commands are %s, mode %d\n",
5000 str_supported(led_supported), led_supported); 5129 str_supported(led_supported), led_supported);
5001 5130
5131 if (led_supported == TPACPI_LED_NONE)
5132 return 1;
5133
5002 tpacpi_leds = kzalloc(sizeof(*tpacpi_leds) * TPACPI_LED_NUMLEDS, 5134 tpacpi_leds = kzalloc(sizeof(*tpacpi_leds) * TPACPI_LED_NUMLEDS,
5003 GFP_KERNEL); 5135 GFP_KERNEL);
5004 if (!tpacpi_leds) { 5136 if (!tpacpi_leds) {
@@ -5006,8 +5138,12 @@ static int __init led_init(struct ibm_init_struct *iibm)
5006 return -ENOMEM; 5138 return -ENOMEM;
5007 } 5139 }
5008 5140
5141 useful_leds = tpacpi_check_quirks(led_useful_qtable,
5142 ARRAY_SIZE(led_useful_qtable));
5143
5009 for (i = 0; i < TPACPI_LED_NUMLEDS; i++) { 5144 for (i = 0; i < TPACPI_LED_NUMLEDS; i++) {
5010 if (!tpacpi_is_led_restricted(i)) { 5145 if (!tpacpi_is_led_restricted(i) &&
5146 test_bit(i, &useful_leds)) {
5011 rc = tpacpi_init_led(i); 5147 rc = tpacpi_init_led(i);
5012 if (rc < 0) { 5148 if (rc < 0) {
5013 led_exit(); 5149 led_exit();
@@ -5017,12 +5153,11 @@ static int __init led_init(struct ibm_init_struct *iibm)
5017 } 5153 }
5018 5154
5019#ifdef CONFIG_THINKPAD_ACPI_UNSAFE_LEDS 5155#ifdef CONFIG_THINKPAD_ACPI_UNSAFE_LEDS
5020 if (led_supported != TPACPI_LED_NONE) 5156 printk(TPACPI_NOTICE
5021 printk(TPACPI_NOTICE 5157 "warning: userspace override of important "
5022 "warning: userspace override of important " 5158 "firmware LEDs is enabled\n");
5023 "firmware LEDs is enabled\n");
5024#endif 5159#endif
5025 return (led_supported != TPACPI_LED_NONE)? 0 : 1; 5160 return 0;
5026} 5161}
5027 5162
5028#define str_led_status(s) \ 5163#define str_led_status(s) \
@@ -5052,7 +5187,7 @@ static int led_read(char *p)
5052 } 5187 }
5053 5188
5054 len += sprintf(p + len, "commands:\t" 5189 len += sprintf(p + len, "commands:\t"
5055 "<led> on, <led> off, <led> blink (<led> is 0-7)\n"); 5190 "<led> on, <led> off, <led> blink (<led> is 0-15)\n");
5056 5191
5057 return len; 5192 return len;
5058} 5193}
@@ -5067,7 +5202,7 @@ static int led_write(char *buf)
5067 return -ENODEV; 5202 return -ENODEV;
5068 5203
5069 while ((cmd = next_cmd(&buf))) { 5204 while ((cmd = next_cmd(&buf))) {
5070 if (sscanf(cmd, "%d", &led) != 1 || led < 0 || led > 7) 5205 if (sscanf(cmd, "%d", &led) != 1 || led < 0 || led > 15)
5071 return -EINVAL; 5206 return -EINVAL;
5072 5207
5073 if (strstr(cmd, "off")) { 5208 if (strstr(cmd, "off")) {
@@ -5101,8 +5236,17 @@ static struct ibm_struct led_driver_data = {
5101 5236
5102TPACPI_HANDLE(beep, ec, "BEEP"); /* all except R30, R31 */ 5237TPACPI_HANDLE(beep, ec, "BEEP"); /* all except R30, R31 */
5103 5238
5239#define TPACPI_BEEP_Q1 0x0001
5240
5241static const struct tpacpi_quirk beep_quirk_table[] __initconst = {
5242 TPACPI_Q_IBM('I', 'M', TPACPI_BEEP_Q1), /* 570 */
5243 TPACPI_Q_IBM('I', 'U', TPACPI_BEEP_Q1), /* 570E - unverified */
5244};
5245
5104static int __init beep_init(struct ibm_init_struct *iibm) 5246static int __init beep_init(struct ibm_init_struct *iibm)
5105{ 5247{
5248 unsigned long quirks;
5249
5106 vdbg_printk(TPACPI_DBG_INIT, "initializing beep subdriver\n"); 5250 vdbg_printk(TPACPI_DBG_INIT, "initializing beep subdriver\n");
5107 5251
5108 TPACPI_ACPIHANDLE_INIT(beep); 5252 TPACPI_ACPIHANDLE_INIT(beep);
@@ -5110,6 +5254,11 @@ static int __init beep_init(struct ibm_init_struct *iibm)
5110 vdbg_printk(TPACPI_DBG_INIT, "beep is %s\n", 5254 vdbg_printk(TPACPI_DBG_INIT, "beep is %s\n",
5111 str_supported(beep_handle != NULL)); 5255 str_supported(beep_handle != NULL));
5112 5256
5257 quirks = tpacpi_check_quirks(beep_quirk_table,
5258 ARRAY_SIZE(beep_quirk_table));
5259
5260 tp_features.beep_needs_two_args = !!(quirks & TPACPI_BEEP_Q1);
5261
5113 return (beep_handle)? 0 : 1; 5262 return (beep_handle)? 0 : 1;
5114} 5263}
5115 5264
@@ -5141,8 +5290,15 @@ static int beep_write(char *buf)
5141 /* beep_cmd set */ 5290 /* beep_cmd set */
5142 } else 5291 } else
5143 return -EINVAL; 5292 return -EINVAL;
5144 if (!acpi_evalf(beep_handle, NULL, NULL, "vdd", beep_cmd, 0)) 5293 if (tp_features.beep_needs_two_args) {
5145 return -EIO; 5294 if (!acpi_evalf(beep_handle, NULL, NULL, "vdd",
5295 beep_cmd, 0))
5296 return -EIO;
5297 } else {
5298 if (!acpi_evalf(beep_handle, NULL, NULL, "vd",
5299 beep_cmd))
5300 return -EIO;
5301 }
5146 } 5302 }
5147 5303
5148 return 0; 5304 return 0;
@@ -5569,6 +5725,10 @@ static struct ibm_struct ecdump_driver_data = {
5569 * Bit 3-0: backlight brightness level 5725 * Bit 3-0: backlight brightness level
5570 * 5726 *
5571 * brightness_get_raw returns status data in the HBRV layout 5727 * brightness_get_raw returns status data in the HBRV layout
5728 *
5729 * WARNING: The X61 has been verified to use HBRV for something else, so
5730 * this should be used _only_ on IBM ThinkPads, and maybe with some careful
5731 * testing on the very early *60 Lenovo models...
5572 */ 5732 */
5573 5733
5574enum { 5734enum {
@@ -5869,6 +6029,12 @@ static int __init brightness_init(struct ibm_init_struct *iibm)
5869 brightness_mode); 6029 brightness_mode);
5870 } 6030 }
5871 6031
6032 /* Safety */
6033 if (thinkpad_id.vendor != PCI_VENDOR_ID_IBM &&
6034 (brightness_mode == TPACPI_BRGHT_MODE_ECNVRAM ||
6035 brightness_mode == TPACPI_BRGHT_MODE_EC))
6036 return -EINVAL;
6037
5872 if (tpacpi_brightness_get_raw(&b) < 0) 6038 if (tpacpi_brightness_get_raw(&b) < 0)
5873 return 1; 6039 return 1;
5874 6040
@@ -6161,6 +6327,21 @@ static struct ibm_struct volume_driver_data = {
6161 * For firmware bugs, refer to: 6327 * For firmware bugs, refer to:
6162 * http://thinkwiki.org/wiki/Embedded_Controller_Firmware#Firmware_Issues 6328 * http://thinkwiki.org/wiki/Embedded_Controller_Firmware#Firmware_Issues
6163 * 6329 *
6330 * ----
6331 *
6332 * ThinkPad EC register 0x31 bit 0 (only on select models)
6333 *
6334 * When bit 0 of EC register 0x31 is zero, the tachometer registers
6335 * show the speed of the main fan. When bit 0 of EC register 0x31
6336 * is one, the tachometer registers show the speed of the auxiliary
6337 * fan.
6338 *
6339 * Fan control seems to affect both fans, regardless of the state
6340 * of this bit.
6341 *
6342 * So far, only the firmware for the X60/X61 non-tablet versions
6343 * seem to support this (firmware TP-7M).
6344 *
6164 * TPACPI_FAN_WR_ACPI_FANS: 6345 * TPACPI_FAN_WR_ACPI_FANS:
6165 * ThinkPad X31, X40, X41. Not available in the X60. 6346 * ThinkPad X31, X40, X41. Not available in the X60.
6166 * 6347 *
@@ -6187,6 +6368,8 @@ enum { /* Fan control constants */
6187 fan_status_offset = 0x2f, /* EC register 0x2f */ 6368 fan_status_offset = 0x2f, /* EC register 0x2f */
6188 fan_rpm_offset = 0x84, /* EC register 0x84: LSB, 0x85 MSB (RPM) 6369 fan_rpm_offset = 0x84, /* EC register 0x84: LSB, 0x85 MSB (RPM)
6189 * 0x84 must be read before 0x85 */ 6370 * 0x84 must be read before 0x85 */
6371 fan_select_offset = 0x31, /* EC register 0x31 (Firmware 7M)
6372 bit 0 selects which fan is active */
6190 6373
6191 TP_EC_FAN_FULLSPEED = 0x40, /* EC fan mode: full speed */ 6374 TP_EC_FAN_FULLSPEED = 0x40, /* EC fan mode: full speed */
6192 TP_EC_FAN_AUTO = 0x80, /* EC fan mode: auto fan control */ 6375 TP_EC_FAN_AUTO = 0x80, /* EC fan mode: auto fan control */
@@ -6249,30 +6432,18 @@ TPACPI_HANDLE(sfan, ec, "SFAN", /* 570 */
6249 * We assume 0x07 really means auto mode while this quirk is active, 6432 * We assume 0x07 really means auto mode while this quirk is active,
6250 * as this is far more likely than the ThinkPad being in level 7, 6433 * as this is far more likely than the ThinkPad being in level 7,
6251 * which is only used by the firmware during thermal emergencies. 6434 * which is only used by the firmware during thermal emergencies.
6435 *
6436 * Enable for TP-1Y (T43), TP-78 (R51e), TP-76 (R52),
6437 * TP-70 (T43, R52), which are known to be buggy.
6252 */ 6438 */
6253 6439
6254static void fan_quirk1_detect(void) 6440static void fan_quirk1_setup(void)
6255{ 6441{
6256 /* In some ThinkPads, neither the EC nor the ACPI
6257 * DSDT initialize the HFSP register, and it ends up
6258 * being initially set to 0x07 when it *could* be
6259 * either 0x07 or 0x80.
6260 *
6261 * Enable for TP-1Y (T43), TP-78 (R51e),
6262 * TP-76 (R52), TP-70 (T43, R52), which are known
6263 * to be buggy. */
6264 if (fan_control_initial_status == 0x07) { 6442 if (fan_control_initial_status == 0x07) {
6265 switch (thinkpad_id.ec_model) { 6443 printk(TPACPI_NOTICE
6266 case 0x5931: /* TP-1Y */ 6444 "fan_init: initial fan status is unknown, "
6267 case 0x3837: /* TP-78 */ 6445 "assuming it is in auto mode\n");
6268 case 0x3637: /* TP-76 */ 6446 tp_features.fan_ctrl_status_undef = 1;
6269 case 0x3037: /* TP-70 */
6270 printk(TPACPI_NOTICE
6271 "fan_init: initial fan status is unknown, "
6272 "assuming it is in auto mode\n");
6273 tp_features.fan_ctrl_status_undef = 1;
6274 ;;
6275 }
6276 } 6447 }
6277} 6448}
6278 6449
@@ -6292,6 +6463,38 @@ static void fan_quirk1_handle(u8 *fan_status)
6292 } 6463 }
6293} 6464}
6294 6465
6466/* Select main fan on X60/X61, NOOP on others */
6467static bool fan_select_fan1(void)
6468{
6469 if (tp_features.second_fan) {
6470 u8 val;
6471
6472 if (ec_read(fan_select_offset, &val) < 0)
6473 return false;
6474 val &= 0xFEU;
6475 if (ec_write(fan_select_offset, val) < 0)
6476 return false;
6477 }
6478 return true;
6479}
6480
6481/* Select secondary fan on X60/X61 */
6482static bool fan_select_fan2(void)
6483{
6484 u8 val;
6485
6486 if (!tp_features.second_fan)
6487 return false;
6488
6489 if (ec_read(fan_select_offset, &val) < 0)
6490 return false;
6491 val |= 0x01U;
6492 if (ec_write(fan_select_offset, val) < 0)
6493 return false;
6494
6495 return true;
6496}
6497
6295/* 6498/*
6296 * Call with fan_mutex held 6499 * Call with fan_mutex held
6297 */ 6500 */
@@ -6369,6 +6572,8 @@ static int fan_get_speed(unsigned int *speed)
6369 switch (fan_status_access_mode) { 6572 switch (fan_status_access_mode) {
6370 case TPACPI_FAN_RD_TPEC: 6573 case TPACPI_FAN_RD_TPEC:
6371 /* all except 570, 600e/x, 770e, 770x */ 6574 /* all except 570, 600e/x, 770e, 770x */
6575 if (unlikely(!fan_select_fan1()))
6576 return -EIO;
6372 if (unlikely(!acpi_ec_read(fan_rpm_offset, &lo) || 6577 if (unlikely(!acpi_ec_read(fan_rpm_offset, &lo) ||
6373 !acpi_ec_read(fan_rpm_offset + 1, &hi))) 6578 !acpi_ec_read(fan_rpm_offset + 1, &hi)))
6374 return -EIO; 6579 return -EIO;
@@ -6385,6 +6590,34 @@ static int fan_get_speed(unsigned int *speed)
6385 return 0; 6590 return 0;
6386} 6591}
6387 6592
6593static int fan2_get_speed(unsigned int *speed)
6594{
6595 u8 hi, lo;
6596 bool rc;
6597
6598 switch (fan_status_access_mode) {
6599 case TPACPI_FAN_RD_TPEC:
6600 /* all except 570, 600e/x, 770e, 770x */
6601 if (unlikely(!fan_select_fan2()))
6602 return -EIO;
6603 rc = !acpi_ec_read(fan_rpm_offset, &lo) ||
6604 !acpi_ec_read(fan_rpm_offset + 1, &hi);
6605 fan_select_fan1(); /* play it safe */
6606 if (rc)
6607 return -EIO;
6608
6609 if (likely(speed))
6610 *speed = (hi << 8) | lo;
6611
6612 break;
6613
6614 default:
6615 return -ENXIO;
6616 }
6617
6618 return 0;
6619}
6620
6388static int fan_set_level(int level) 6621static int fan_set_level(int level)
6389{ 6622{
6390 if (!fan_control_allowed) 6623 if (!fan_control_allowed)
@@ -6790,6 +7023,25 @@ static struct device_attribute dev_attr_fan_fan1_input =
6790 __ATTR(fan1_input, S_IRUGO, 7023 __ATTR(fan1_input, S_IRUGO,
6791 fan_fan1_input_show, NULL); 7024 fan_fan1_input_show, NULL);
6792 7025
7026/* sysfs fan fan2_input ------------------------------------------------ */
7027static ssize_t fan_fan2_input_show(struct device *dev,
7028 struct device_attribute *attr,
7029 char *buf)
7030{
7031 int res;
7032 unsigned int speed;
7033
7034 res = fan2_get_speed(&speed);
7035 if (res < 0)
7036 return res;
7037
7038 return snprintf(buf, PAGE_SIZE, "%u\n", speed);
7039}
7040
7041static struct device_attribute dev_attr_fan_fan2_input =
7042 __ATTR(fan2_input, S_IRUGO,
7043 fan_fan2_input_show, NULL);
7044
6793/* sysfs fan fan_watchdog (hwmon driver) ------------------------------- */ 7045/* sysfs fan fan_watchdog (hwmon driver) ------------------------------- */
6794static ssize_t fan_fan_watchdog_show(struct device_driver *drv, 7046static ssize_t fan_fan_watchdog_show(struct device_driver *drv,
6795 char *buf) 7047 char *buf)
@@ -6823,6 +7075,7 @@ static DRIVER_ATTR(fan_watchdog, S_IWUSR | S_IRUGO,
6823static struct attribute *fan_attributes[] = { 7075static struct attribute *fan_attributes[] = {
6824 &dev_attr_fan_pwm1_enable.attr, &dev_attr_fan_pwm1.attr, 7076 &dev_attr_fan_pwm1_enable.attr, &dev_attr_fan_pwm1.attr,
6825 &dev_attr_fan_fan1_input.attr, 7077 &dev_attr_fan_fan1_input.attr,
7078 NULL, /* for fan2_input */
6826 NULL 7079 NULL
6827}; 7080};
6828 7081
@@ -6830,9 +7083,36 @@ static const struct attribute_group fan_attr_group = {
6830 .attrs = fan_attributes, 7083 .attrs = fan_attributes,
6831}; 7084};
6832 7085
7086#define TPACPI_FAN_Q1 0x0001 /* Unitialized HFSP */
7087#define TPACPI_FAN_2FAN 0x0002 /* EC 0x31 bit 0 selects fan2 */
7088
7089#define TPACPI_FAN_QI(__id1, __id2, __quirks) \
7090 { .vendor = PCI_VENDOR_ID_IBM, \
7091 .bios = TPACPI_MATCH_ANY, \
7092 .ec = TPID(__id1, __id2), \
7093 .quirks = __quirks }
7094
7095#define TPACPI_FAN_QL(__id1, __id2, __quirks) \
7096 { .vendor = PCI_VENDOR_ID_LENOVO, \
7097 .bios = TPACPI_MATCH_ANY, \
7098 .ec = TPID(__id1, __id2), \
7099 .quirks = __quirks }
7100
7101static const struct tpacpi_quirk fan_quirk_table[] __initconst = {
7102 TPACPI_FAN_QI('1', 'Y', TPACPI_FAN_Q1),
7103 TPACPI_FAN_QI('7', '8', TPACPI_FAN_Q1),
7104 TPACPI_FAN_QI('7', '6', TPACPI_FAN_Q1),
7105 TPACPI_FAN_QI('7', '0', TPACPI_FAN_Q1),
7106 TPACPI_FAN_QL('7', 'M', TPACPI_FAN_2FAN),
7107};
7108
7109#undef TPACPI_FAN_QL
7110#undef TPACPI_FAN_QI
7111
6833static int __init fan_init(struct ibm_init_struct *iibm) 7112static int __init fan_init(struct ibm_init_struct *iibm)
6834{ 7113{
6835 int rc; 7114 int rc;
7115 unsigned long quirks;
6836 7116
6837 vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_FAN, 7117 vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_FAN,
6838 "initializing fan subdriver\n"); 7118 "initializing fan subdriver\n");
@@ -6843,12 +7123,16 @@ static int __init fan_init(struct ibm_init_struct *iibm)
6843 fan_control_commands = 0; 7123 fan_control_commands = 0;
6844 fan_watchdog_maxinterval = 0; 7124 fan_watchdog_maxinterval = 0;
6845 tp_features.fan_ctrl_status_undef = 0; 7125 tp_features.fan_ctrl_status_undef = 0;
7126 tp_features.second_fan = 0;
6846 fan_control_desired_level = 7; 7127 fan_control_desired_level = 7;
6847 7128
6848 TPACPI_ACPIHANDLE_INIT(fans); 7129 TPACPI_ACPIHANDLE_INIT(fans);
6849 TPACPI_ACPIHANDLE_INIT(gfan); 7130 TPACPI_ACPIHANDLE_INIT(gfan);
6850 TPACPI_ACPIHANDLE_INIT(sfan); 7131 TPACPI_ACPIHANDLE_INIT(sfan);
6851 7132
7133 quirks = tpacpi_check_quirks(fan_quirk_table,
7134 ARRAY_SIZE(fan_quirk_table));
7135
6852 if (gfan_handle) { 7136 if (gfan_handle) {
6853 /* 570, 600e/x, 770e, 770x */ 7137 /* 570, 600e/x, 770e, 770x */
6854 fan_status_access_mode = TPACPI_FAN_RD_ACPI_GFAN; 7138 fan_status_access_mode = TPACPI_FAN_RD_ACPI_GFAN;
@@ -6858,7 +7142,13 @@ static int __init fan_init(struct ibm_init_struct *iibm)
6858 if (likely(acpi_ec_read(fan_status_offset, 7142 if (likely(acpi_ec_read(fan_status_offset,
6859 &fan_control_initial_status))) { 7143 &fan_control_initial_status))) {
6860 fan_status_access_mode = TPACPI_FAN_RD_TPEC; 7144 fan_status_access_mode = TPACPI_FAN_RD_TPEC;
6861 fan_quirk1_detect(); 7145 if (quirks & TPACPI_FAN_Q1)
7146 fan_quirk1_setup();
7147 if (quirks & TPACPI_FAN_2FAN) {
7148 tp_features.second_fan = 1;
7149 dbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_FAN,
7150 "secondary fan support enabled\n");
7151 }
6862 } else { 7152 } else {
6863 printk(TPACPI_ERR 7153 printk(TPACPI_ERR
6864 "ThinkPad ACPI EC access misbehaving, " 7154 "ThinkPad ACPI EC access misbehaving, "
@@ -6914,6 +7204,11 @@ static int __init fan_init(struct ibm_init_struct *iibm)
6914 7204
6915 if (fan_status_access_mode != TPACPI_FAN_NONE || 7205 if (fan_status_access_mode != TPACPI_FAN_NONE ||
6916 fan_control_access_mode != TPACPI_FAN_WR_NONE) { 7206 fan_control_access_mode != TPACPI_FAN_WR_NONE) {
7207 if (tp_features.second_fan) {
7208 /* attach second fan tachometer */
7209 fan_attributes[ARRAY_SIZE(fan_attributes)-2] =
7210 &dev_attr_fan_fan2_input.attr;
7211 }
6917 rc = sysfs_create_group(&tpacpi_sensors_pdev->dev.kobj, 7212 rc = sysfs_create_group(&tpacpi_sensors_pdev->dev.kobj,
6918 &fan_attr_group); 7213 &fan_attr_group);
6919 if (rc < 0) 7214 if (rc < 0)
@@ -7385,6 +7680,24 @@ err_out:
7385 7680
7386/* Probing */ 7681/* Probing */
7387 7682
7683static bool __pure __init tpacpi_is_fw_digit(const char c)
7684{
7685 return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z');
7686}
7687
7688/* Most models: xxyTkkWW (#.##c); Ancient 570/600 and -SL lacks (#.##c) */
7689static bool __pure __init tpacpi_is_valid_fw_id(const char* const s,
7690 const char t)
7691{
7692 return s && strlen(s) >= 8 &&
7693 tpacpi_is_fw_digit(s[0]) &&
7694 tpacpi_is_fw_digit(s[1]) &&
7695 s[2] == t && s[3] == 'T' &&
7696 tpacpi_is_fw_digit(s[4]) &&
7697 tpacpi_is_fw_digit(s[5]) &&
7698 s[6] == 'W' && s[7] == 'W';
7699}
7700
7388/* returns 0 - probe ok, or < 0 - probe error. 7701/* returns 0 - probe ok, or < 0 - probe error.
7389 * Probe ok doesn't mean thinkpad found. 7702 * Probe ok doesn't mean thinkpad found.
7390 * On error, kfree() cleanup on tp->* is not performed, caller must do it */ 7703 * On error, kfree() cleanup on tp->* is not performed, caller must do it */
@@ -7411,10 +7724,15 @@ static int __must_check __init get_thinkpad_model_data(
7411 tp->bios_version_str = kstrdup(s, GFP_KERNEL); 7724 tp->bios_version_str = kstrdup(s, GFP_KERNEL);
7412 if (s && !tp->bios_version_str) 7725 if (s && !tp->bios_version_str)
7413 return -ENOMEM; 7726 return -ENOMEM;
7414 if (!tp->bios_version_str) 7727
7728 /* Really ancient ThinkPad 240X will fail this, which is fine */
7729 if (!tpacpi_is_valid_fw_id(tp->bios_version_str, 'E'))
7415 return 0; 7730 return 0;
7731
7416 tp->bios_model = tp->bios_version_str[0] 7732 tp->bios_model = tp->bios_version_str[0]
7417 | (tp->bios_version_str[1] << 8); 7733 | (tp->bios_version_str[1] << 8);
7734 tp->bios_release = (tp->bios_version_str[4] << 8)
7735 | tp->bios_version_str[5];
7418 7736
7419 /* 7737 /*
7420 * ThinkPad T23 or newer, A31 or newer, R50e or newer, 7738 * ThinkPad T23 or newer, A31 or newer, R50e or newer,
@@ -7433,8 +7751,21 @@ static int __must_check __init get_thinkpad_model_data(
7433 tp->ec_version_str = kstrdup(ec_fw_string, GFP_KERNEL); 7751 tp->ec_version_str = kstrdup(ec_fw_string, GFP_KERNEL);
7434 if (!tp->ec_version_str) 7752 if (!tp->ec_version_str)
7435 return -ENOMEM; 7753 return -ENOMEM;
7436 tp->ec_model = ec_fw_string[0] 7754
7437 | (ec_fw_string[1] << 8); 7755 if (tpacpi_is_valid_fw_id(ec_fw_string, 'H')) {
7756 tp->ec_model = ec_fw_string[0]
7757 | (ec_fw_string[1] << 8);
7758 tp->ec_release = (ec_fw_string[4] << 8)
7759 | ec_fw_string[5];
7760 } else {
7761 printk(TPACPI_NOTICE
7762 "ThinkPad firmware release %s "
7763 "doesn't match the known patterns\n",
7764 ec_fw_string);
7765 printk(TPACPI_NOTICE
7766 "please report this to %s\n",
7767 TPACPI_MAIL);
7768 }
7438 break; 7769 break;
7439 } 7770 }
7440 } 7771 }