aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/platform
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/platform')
-rw-r--r--drivers/platform/x86/Kconfig10
-rw-r--r--drivers/platform/x86/Makefile1
-rw-r--r--drivers/platform/x86/acerhdf.c121
-rw-r--r--drivers/platform/x86/asus-laptop.c227
-rw-r--r--drivers/platform/x86/eeepc-laptop.c340
-rw-r--r--drivers/platform/x86/fujitsu-laptop.c109
-rw-r--r--drivers/platform/x86/hp-wmi.c15
-rw-r--r--drivers/platform/x86/sony-laptop.c7
-rw-r--r--drivers/platform/x86/thinkpad_acpi.c382
-rw-r--r--drivers/platform/x86/topstar-laptop.c265
-rw-r--r--drivers/platform/x86/wmi.c1
11 files changed, 1102 insertions, 376 deletions
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index 77c6097ced80..55ca39dea42e 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -99,6 +99,7 @@ config FUJITSU_LAPTOP
99 depends on ACPI 99 depends on ACPI
100 depends on INPUT 100 depends on INPUT
101 depends on BACKLIGHT_CLASS_DEVICE 101 depends on BACKLIGHT_CLASS_DEVICE
102 depends on LEDS_CLASS || LEDS_CLASS=n
102 ---help--- 103 ---help---
103 This is a driver for laptops built by Fujitsu: 104 This is a driver for laptops built by Fujitsu:
104 105
@@ -396,6 +397,15 @@ config ACPI_ASUS
396 NOTE: This driver is deprecated and will probably be removed soon, 397 NOTE: This driver is deprecated and will probably be removed soon,
397 use asus-laptop instead. 398 use asus-laptop instead.
398 399
400config TOPSTAR_LAPTOP
401 tristate "Topstar Laptop Extras"
402 depends on ACPI
403 depends on INPUT
404 ---help---
405 This driver adds support for hotkeys found on Topstar laptops.
406
407 If you have a Topstar laptop, say Y or M here.
408
399config ACPI_TOSHIBA 409config ACPI_TOSHIBA
400 tristate "Toshiba Laptop Extras" 410 tristate "Toshiba Laptop Extras"
401 depends on ACPI 411 depends on ACPI
diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile
index 641b8bfa5538..d1c16210a512 100644
--- a/drivers/platform/x86/Makefile
+++ b/drivers/platform/x86/Makefile
@@ -19,4 +19,5 @@ obj-$(CONFIG_PANASONIC_LAPTOP) += panasonic-laptop.o
19obj-$(CONFIG_INTEL_MENLOW) += intel_menlow.o 19obj-$(CONFIG_INTEL_MENLOW) += intel_menlow.o
20obj-$(CONFIG_ACPI_WMI) += wmi.o 20obj-$(CONFIG_ACPI_WMI) += wmi.o
21obj-$(CONFIG_ACPI_ASUS) += asus_acpi.o 21obj-$(CONFIG_ACPI_ASUS) += asus_acpi.o
22obj-$(CONFIG_TOPSTAR_LAPTOP) += topstar-laptop.o
22obj-$(CONFIG_ACPI_TOSHIBA) += toshiba_acpi.o 23obj-$(CONFIG_ACPI_TOSHIBA) += toshiba_acpi.o
diff --git a/drivers/platform/x86/acerhdf.c b/drivers/platform/x86/acerhdf.c
index bdfee177eefb..0a8f735f6c4a 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.13" 55#define DRV_VER "0.5.17"
56 56
57/* 57/*
58 * According to the Atom N270 datasheet, 58 * According to the Atom N270 datasheet,
@@ -90,6 +90,7 @@ static unsigned int fanoff = 58;
90static unsigned int verbose; 90static unsigned int verbose;
91static unsigned int fanstate = ACERHDF_FAN_AUTO; 91static unsigned int fanstate = ACERHDF_FAN_AUTO;
92static char force_bios[16]; 92static char force_bios[16];
93static char force_product[16];
93static unsigned int prev_interval; 94static unsigned int prev_interval;
94struct thermal_zone_device *thz_dev; 95struct thermal_zone_device *thz_dev;
95struct thermal_cooling_device *cl_dev; 96struct thermal_cooling_device *cl_dev;
@@ -107,34 +108,62 @@ module_param(verbose, uint, 0600);
107MODULE_PARM_DESC(verbose, "Enable verbose dmesg output"); 108MODULE_PARM_DESC(verbose, "Enable verbose dmesg output");
108module_param_string(force_bios, force_bios, 16, 0); 109module_param_string(force_bios, force_bios, 16, 0);
109MODULE_PARM_DESC(force_bios, "Force BIOS version and omit BIOS check"); 110MODULE_PARM_DESC(force_bios, "Force BIOS version and omit BIOS check");
111module_param_string(force_product, force_product, 16, 0);
112MODULE_PARM_DESC(force_product, "Force BIOS product and omit BIOS check");
113
114/*
115 * cmd_off: to switch the fan completely 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 * the fan speed depending on the temperature
118 */
119struct fancmd {
120 u8 cmd_off;
121 u8 cmd_auto;
122};
110 123
111/* BIOS settings */ 124/* BIOS settings */
112struct bios_settings_t { 125struct bios_settings_t {
113 const char *vendor; 126 const char *vendor;
127 const char *product;
114 const char *version; 128 const char *version;
115 unsigned char fanreg; 129 unsigned char fanreg;
116 unsigned char tempreg; 130 unsigned char tempreg;
117 unsigned char fancmd[2]; /* fan off and auto commands */ 131 struct fancmd cmd;
118}; 132};
119 133
120/* Register addresses and values for different BIOS versions */ 134/* Register addresses and values for different BIOS versions */
121static const struct bios_settings_t bios_tbl[] = { 135static const struct bios_settings_t bios_tbl[] = {
122 {"Acer", "v0.3109", 0x55, 0x58, {0x1f, 0x00} }, 136 /* AOA110 */
123 {"Acer", "v0.3114", 0x55, 0x58, {0x1f, 0x00} }, 137 {"Acer", "AOA110", "v0.3109", 0x55, 0x58, {0x1f, 0x00} },
124 {"Acer", "v0.3301", 0x55, 0x58, {0xaf, 0x00} }, 138 {"Acer", "AOA110", "v0.3114", 0x55, 0x58, {0x1f, 0x00} },
125 {"Acer", "v0.3304", 0x55, 0x58, {0xaf, 0x00} }, 139 {"Acer", "AOA110", "v0.3301", 0x55, 0x58, {0xaf, 0x00} },
126 {"Acer", "v0.3305", 0x55, 0x58, {0xaf, 0x00} }, 140 {"Acer", "AOA110", "v0.3304", 0x55, 0x58, {0xaf, 0x00} },
127 {"Acer", "v0.3308", 0x55, 0x58, {0x21, 0x00} }, 141 {"Acer", "AOA110", "v0.3305", 0x55, 0x58, {0xaf, 0x00} },
128 {"Acer", "v0.3309", 0x55, 0x58, {0x21, 0x00} }, 142 {"Acer", "AOA110", "v0.3307", 0x55, 0x58, {0xaf, 0x00} },
129 {"Acer", "v0.3310", 0x55, 0x58, {0x21, 0x00} }, 143 {"Acer", "AOA110", "v0.3308", 0x55, 0x58, {0x21, 0x00} },
130 {"Gateway", "v0.3103", 0x55, 0x58, {0x21, 0x00} }, 144 {"Acer", "AOA110", "v0.3309", 0x55, 0x58, {0x21, 0x00} },
131 {"Packard Bell", "v0.3105", 0x55, 0x58, {0x21, 0x00} }, 145 {"Acer", "AOA110", "v0.3310", 0x55, 0x58, {0x21, 0x00} },
132 {"", "", 0, 0, {0, 0} } 146 /* AOA150 */
147 {"Acer", "AOA150", "v0.3114", 0x55, 0x58, {0x20, 0x00} },
148 {"Acer", "AOA150", "v0.3301", 0x55, 0x58, {0x20, 0x00} },
149 {"Acer", "AOA150", "v0.3304", 0x55, 0x58, {0x20, 0x00} },
150 {"Acer", "AOA150", "v0.3305", 0x55, 0x58, {0x20, 0x00} },
151 {"Acer", "AOA150", "v0.3307", 0x55, 0x58, {0x20, 0x00} },
152 {"Acer", "AOA150", "v0.3308", 0x55, 0x58, {0x20, 0x00} },
153 {"Acer", "AOA150", "v0.3309", 0x55, 0x58, {0x20, 0x00} },
154 {"Acer", "AOA150", "v0.3310", 0x55, 0x58, {0x20, 0x00} },
155 /* special BIOS / other */
156 {"Gateway", "AOA110", "v0.3103", 0x55, 0x58, {0x21, 0x00} },
157 {"Gateway", "AOA150", "v0.3103", 0x55, 0x58, {0x20, 0x00} },
158 {"Packard Bell", "DOA150", "v0.3104", 0x55, 0x58, {0x21, 0x00} },
159 {"Packard Bell", "AOA110", "v0.3105", 0x55, 0x58, {0x21, 0x00} },
160 {"Packard Bell", "AOA150", "v0.3105", 0x55, 0x58, {0x20, 0x00} },
161 /* pewpew-terminator */
162 {"", "", "", 0, 0, {0, 0} }
133}; 163};
134 164
135static const struct bios_settings_t *bios_cfg __read_mostly; 165static const struct bios_settings_t *bios_cfg __read_mostly;
136 166
137
138static int acerhdf_get_temp(int *temp) 167static int acerhdf_get_temp(int *temp)
139{ 168{
140 u8 read_temp; 169 u8 read_temp;
@@ -150,13 +179,14 @@ static int acerhdf_get_temp(int *temp)
150static int acerhdf_get_fanstate(int *state) 179static int acerhdf_get_fanstate(int *state)
151{ 180{
152 u8 fan; 181 u8 fan;
153 bool tmp;
154 182
155 if (ec_read(bios_cfg->fanreg, &fan)) 183 if (ec_read(bios_cfg->fanreg, &fan))
156 return -EINVAL; 184 return -EINVAL;
157 185
158 tmp = (fan == bios_cfg->fancmd[ACERHDF_FAN_OFF]); 186 if (fan != bios_cfg->cmd.cmd_off)
159 *state = tmp ? ACERHDF_FAN_OFF : ACERHDF_FAN_AUTO; 187 *state = ACERHDF_FAN_AUTO;
188 else
189 *state = ACERHDF_FAN_OFF;
160 190
161 return 0; 191 return 0;
162} 192}
@@ -175,7 +205,8 @@ static void acerhdf_change_fanstate(int state)
175 state = ACERHDF_FAN_AUTO; 205 state = ACERHDF_FAN_AUTO;
176 } 206 }
177 207
178 cmd = bios_cfg->fancmd[state]; 208 cmd = (state == ACERHDF_FAN_OFF) ? bios_cfg->cmd.cmd_off
209 : bios_cfg->cmd.cmd_auto;
179 fanstate = state; 210 fanstate = state;
180 211
181 ec_write(bios_cfg->fanreg, cmd); 212 ec_write(bios_cfg->fanreg, cmd);
@@ -408,7 +439,7 @@ struct thermal_cooling_device_ops acerhdf_cooling_ops = {
408}; 439};
409 440
410/* suspend / resume functionality */ 441/* suspend / resume functionality */
411static int acerhdf_suspend(struct platform_device *dev, pm_message_t state) 442static int acerhdf_suspend(struct device *dev)
412{ 443{
413 if (kernelmode) 444 if (kernelmode)
414 acerhdf_change_fanstate(ACERHDF_FAN_AUTO); 445 acerhdf_change_fanstate(ACERHDF_FAN_AUTO);
@@ -419,14 +450,6 @@ static int acerhdf_suspend(struct platform_device *dev, pm_message_t state)
419 return 0; 450 return 0;
420} 451}
421 452
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) 453static int __devinit acerhdf_probe(struct platform_device *device)
431{ 454{
432 return 0; 455 return 0;
@@ -437,15 +460,19 @@ static int acerhdf_remove(struct platform_device *device)
437 return 0; 460 return 0;
438} 461}
439 462
440struct platform_driver acerhdf_drv = { 463static struct dev_pm_ops acerhdf_pm_ops = {
464 .suspend = acerhdf_suspend,
465 .freeze = acerhdf_suspend,
466};
467
468static struct platform_driver acerhdf_driver = {
441 .driver = { 469 .driver = {
442 .name = "acerhdf", 470 .name = "acerhdf",
443 .owner = THIS_MODULE, 471 .owner = THIS_MODULE,
472 .pm = &acerhdf_pm_ops,
444 }, 473 },
445 .probe = acerhdf_probe, 474 .probe = acerhdf_probe,
446 .remove = acerhdf_remove, 475 .remove = acerhdf_remove,
447 .suspend = acerhdf_suspend,
448 .resume = acerhdf_resume,
449}; 476};
450 477
451 478
@@ -454,32 +481,40 @@ static int acerhdf_check_hardware(void)
454{ 481{
455 char const *vendor, *version, *product; 482 char const *vendor, *version, *product;
456 int i; 483 int i;
484 unsigned long prod_len = 0;
457 485
458 /* get BIOS data */ 486 /* get BIOS data */
459 vendor = dmi_get_system_info(DMI_SYS_VENDOR); 487 vendor = dmi_get_system_info(DMI_SYS_VENDOR);
460 version = dmi_get_system_info(DMI_BIOS_VERSION); 488 version = dmi_get_system_info(DMI_BIOS_VERSION);
461 product = dmi_get_system_info(DMI_PRODUCT_NAME); 489 product = dmi_get_system_info(DMI_PRODUCT_NAME);
462 490
491
463 pr_info("Acer Aspire One Fan driver, v.%s\n", DRV_VER); 492 pr_info("Acer Aspire One Fan driver, v.%s\n", DRV_VER);
464 493
465 if (!force_bios[0]) { 494 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; 495 version = force_bios;
496 pr_info("forcing BIOS version: %s\n", version);
497 kernelmode = 0;
498 }
499
500 if (force_product[0]) {
501 product = force_product;
502 pr_info("forcing BIOS product: %s\n", product);
473 kernelmode = 0; 503 kernelmode = 0;
474 } 504 }
475 505
506 prod_len = strlen(product);
507
476 if (verbose) 508 if (verbose)
477 pr_info("BIOS info: %s %s, product: %s\n", 509 pr_info("BIOS info: %s %s, product: %s\n",
478 vendor, version, product); 510 vendor, version, product);
479 511
480 /* search BIOS version and vendor in BIOS settings table */ 512 /* search BIOS version and vendor in BIOS settings table */
481 for (i = 0; bios_tbl[i].version[0]; i++) { 513 for (i = 0; bios_tbl[i].version[0]; i++) {
482 if (!strcmp(bios_tbl[i].vendor, vendor) && 514 if (strlen(bios_tbl[i].product) >= prod_len &&
515 !strncmp(bios_tbl[i].product, product,
516 strlen(bios_tbl[i].product)) &&
517 !strcmp(bios_tbl[i].vendor, vendor) &&
483 !strcmp(bios_tbl[i].version, version)) { 518 !strcmp(bios_tbl[i].version, version)) {
484 bios_cfg = &bios_tbl[i]; 519 bios_cfg = &bios_tbl[i];
485 break; 520 break;
@@ -487,8 +522,8 @@ static int acerhdf_check_hardware(void)
487 } 522 }
488 523
489 if (!bios_cfg) { 524 if (!bios_cfg) {
490 pr_err("unknown (unsupported) BIOS version %s/%s, " 525 pr_err("unknown (unsupported) BIOS version %s/%s/%s, "
491 "please report, aborting!\n", vendor, version); 526 "please report, aborting!\n", vendor, product, version);
492 return -EINVAL; 527 return -EINVAL;
493 } 528 }
494 529
@@ -509,7 +544,7 @@ static int acerhdf_register_platform(void)
509{ 544{
510 int err = 0; 545 int err = 0;
511 546
512 err = platform_driver_register(&acerhdf_drv); 547 err = platform_driver_register(&acerhdf_driver);
513 if (err) 548 if (err)
514 return err; 549 return err;
515 550
@@ -525,7 +560,7 @@ static void acerhdf_unregister_platform(void)
525 return; 560 return;
526 561
527 platform_device_del(acerhdf_dev); 562 platform_device_del(acerhdf_dev);
528 platform_driver_unregister(&acerhdf_drv); 563 platform_driver_unregister(&acerhdf_driver);
529} 564}
530 565
531static int acerhdf_register_thermal(void) 566static int acerhdf_register_thermal(void)
diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c
index db657bbeec90..b39d2bb3e75b 100644
--- a/drivers/platform/x86/asus-laptop.c
+++ b/drivers/platform/x86/asus-laptop.c
@@ -77,15 +77,16 @@
77 * Flags for hotk status 77 * Flags for hotk status
78 * WL_ON and BT_ON are also used for wireless_status() 78 * WL_ON and BT_ON are also used for wireless_status()
79 */ 79 */
80#define WL_ON 0x01 //internal Wifi 80#define WL_ON 0x01 /* internal Wifi */
81#define BT_ON 0x02 //internal Bluetooth 81#define BT_ON 0x02 /* internal Bluetooth */
82#define MLED_ON 0x04 //mail LED 82#define MLED_ON 0x04 /* mail LED */
83#define TLED_ON 0x08 //touchpad LED 83#define TLED_ON 0x08 /* touchpad LED */
84#define RLED_ON 0x10 //Record LED 84#define RLED_ON 0x10 /* Record LED */
85#define PLED_ON 0x20 //Phone LED 85#define PLED_ON 0x20 /* Phone LED */
86#define GLED_ON 0x40 //Gaming LED 86#define GLED_ON 0x40 /* Gaming LED */
87#define LCD_ON 0x80 //LCD backlight 87#define LCD_ON 0x80 /* LCD backlight */
88#define GPS_ON 0x100 //GPS 88#define GPS_ON 0x100 /* GPS */
89#define KEY_ON 0x200 /* Keyboard backlight */
89 90
90#define ASUS_LOG ASUS_HOTK_FILE ": " 91#define ASUS_LOG ASUS_HOTK_FILE ": "
91#define ASUS_ERR KERN_ERR ASUS_LOG 92#define ASUS_ERR KERN_ERR ASUS_LOG
@@ -98,7 +99,8 @@ MODULE_AUTHOR("Julien Lerouge, Karol Kozimor, Corentin Chary");
98MODULE_DESCRIPTION(ASUS_HOTK_NAME); 99MODULE_DESCRIPTION(ASUS_HOTK_NAME);
99MODULE_LICENSE("GPL"); 100MODULE_LICENSE("GPL");
100 101
101/* WAPF defines the behavior of the Fn+Fx wlan key 102/*
103 * WAPF defines the behavior of the Fn+Fx wlan key
102 * The significance of values is yet to be found, but 104 * The significance of values is yet to be found, but
103 * most of the time: 105 * most of the time:
104 * 0x0 will do nothing 106 * 0x0 will do nothing
@@ -125,7 +127,8 @@ ASUS_HANDLE(gled_set, ASUS_HOTK_PREFIX "GLED"); /* G1, G2 (probably) */
125/* LEDD */ 127/* LEDD */
126ASUS_HANDLE(ledd_set, ASUS_HOTK_PREFIX "SLCM"); 128ASUS_HANDLE(ledd_set, ASUS_HOTK_PREFIX "SLCM");
127 129
128/* Bluetooth and WLAN 130/*
131 * Bluetooth and WLAN
129 * WLED and BLED are not handled like other XLED, because in some dsdt 132 * WLED and BLED are not handled like other XLED, because in some dsdt
130 * they also control the WLAN/Bluetooth device. 133 * they also control the WLAN/Bluetooth device.
131 */ 134 */
@@ -149,22 +152,32 @@ ASUS_HANDLE(lcd_switch, "\\_SB.PCI0.SBRG.EC0._Q10", /* All new models */
149 152
150/* Display */ 153/* Display */
151ASUS_HANDLE(display_set, ASUS_HOTK_PREFIX "SDSP"); 154ASUS_HANDLE(display_set, ASUS_HOTK_PREFIX "SDSP");
152ASUS_HANDLE(display_get, "\\_SB.PCI0.P0P1.VGA.GETD", /* A6B, A6K A6R A7D F3JM L4R M6R A3G 155ASUS_HANDLE(display_get,
153 M6A M6V VX-1 V6J V6V W3Z */ 156 /* A6B, A6K A6R A7D F3JM L4R M6R A3G M6A M6V VX-1 V6J V6V W3Z */
154 "\\_SB.PCI0.P0P2.VGA.GETD", /* A3E A4K, A4D A4L A6J A7J A8J Z71V M9V 157 "\\_SB.PCI0.P0P1.VGA.GETD",
155 S5A M5A z33A W1Jc W2V G1 */ 158 /* A3E A4K, A4D A4L A6J A7J A8J Z71V M9V S5A M5A z33A W1Jc W2V G1 */
156 "\\_SB.PCI0.P0P3.VGA.GETD", /* A6V A6Q */ 159 "\\_SB.PCI0.P0P2.VGA.GETD",
157 "\\_SB.PCI0.P0PA.VGA.GETD", /* A6T, A6M */ 160 /* A6V A6Q */
158 "\\_SB.PCI0.PCI1.VGAC.NMAP", /* L3C */ 161 "\\_SB.PCI0.P0P3.VGA.GETD",
159 "\\_SB.PCI0.VGA.GETD", /* Z96F */ 162 /* A6T, A6M */
160 "\\ACTD", /* A2D */ 163 "\\_SB.PCI0.P0PA.VGA.GETD",
161 "\\ADVG", /* A4G Z71A W1N W5A W5F M2N M3N M5N M6N S1N S5N */ 164 /* L3C */
162 "\\DNXT", /* P30 */ 165 "\\_SB.PCI0.PCI1.VGAC.NMAP",
163 "\\INFB", /* A2H D1 L2D L3D L3H L2E L5D L5C M1A M2E L4L W3V */ 166 /* Z96F */
164 "\\SSTE"); /* A3F A6F A3N A3L M6N W3N W6A */ 167 "\\_SB.PCI0.VGA.GETD",
165 168 /* A2D */
166ASUS_HANDLE(ls_switch, ASUS_HOTK_PREFIX "ALSC"); /* Z71A Z71V */ 169 "\\ACTD",
167ASUS_HANDLE(ls_level, ASUS_HOTK_PREFIX "ALSL"); /* Z71A Z71V */ 170 /* A4G Z71A W1N W5A W5F M2N M3N M5N M6N S1N S5N */
171 "\\ADVG",
172 /* P30 */
173 "\\DNXT",
174 /* A2H D1 L2D L3D L3H L2E L5D L5C M1A M2E L4L W3V */
175 "\\INFB",
176 /* A3F A6F A3N A3L M6N W3N W6A */
177 "\\SSTE");
178
179ASUS_HANDLE(ls_switch, ASUS_HOTK_PREFIX "ALSC"); /* Z71A Z71V */
180ASUS_HANDLE(ls_level, ASUS_HOTK_PREFIX "ALSL"); /* Z71A Z71V */
168 181
169/* GPS */ 182/* GPS */
170/* R2H use different handle for GPS on/off */ 183/* R2H use different handle for GPS on/off */
@@ -172,19 +185,23 @@ ASUS_HANDLE(gps_on, ASUS_HOTK_PREFIX "SDON"); /* R2H */
172ASUS_HANDLE(gps_off, ASUS_HOTK_PREFIX "SDOF"); /* R2H */ 185ASUS_HANDLE(gps_off, ASUS_HOTK_PREFIX "SDOF"); /* R2H */
173ASUS_HANDLE(gps_status, ASUS_HOTK_PREFIX "GPST"); 186ASUS_HANDLE(gps_status, ASUS_HOTK_PREFIX "GPST");
174 187
188/* Keyboard light */
189ASUS_HANDLE(kled_set, ASUS_HOTK_PREFIX "SLKB");
190ASUS_HANDLE(kled_get, ASUS_HOTK_PREFIX "GLKB");
191
175/* 192/*
176 * This is the main structure, we can use it to store anything interesting 193 * This is the main structure, we can use it to store anything interesting
177 * about the hotk device 194 * about the hotk device
178 */ 195 */
179struct asus_hotk { 196struct asus_hotk {
180 char *name; //laptop name 197 char *name; /* laptop name */
181 struct acpi_device *device; //the device we are in 198 struct acpi_device *device; /* the device we are in */
182 acpi_handle handle; //the handle of the hotk device 199 acpi_handle handle; /* the handle of the hotk device */
183 char status; //status of the hotk, for LEDs, ... 200 char status; /* status of the hotk, for LEDs, ... */
184 u32 ledd_status; //status of the LED display 201 u32 ledd_status; /* status of the LED display */
185 u8 light_level; //light sensor level 202 u8 light_level; /* light sensor level */
186 u8 light_switch; //light sensor switch value 203 u8 light_switch; /* light sensor switch value */
187 u16 event_count[128]; //count for each event TODO make this better 204 u16 event_count[128]; /* count for each event TODO make this better */
188 struct input_dev *inputdev; 205 struct input_dev *inputdev;
189 u16 *keycode_map; 206 u16 *keycode_map;
190}; 207};
@@ -237,28 +254,35 @@ static struct backlight_ops asusbl_ops = {
237 .update_status = update_bl_status, 254 .update_status = update_bl_status,
238}; 255};
239 256
240/* These functions actually update the LED's, and are called from a 257/*
258 * These functions actually update the LED's, and are called from a
241 * workqueue. By doing this as separate work rather than when the LED 259 * workqueue. By doing this as separate work rather than when the LED
242 * subsystem asks, we avoid messing with the Asus ACPI stuff during a 260 * subsystem asks, we avoid messing with the Asus ACPI stuff during a
243 * potentially bad time, such as a timer interrupt. */ 261 * potentially bad time, such as a timer interrupt.
262 */
244static struct workqueue_struct *led_workqueue; 263static struct workqueue_struct *led_workqueue;
245 264
246#define ASUS_LED(object, ledname) \ 265#define ASUS_LED(object, ledname, max) \
247 static void object##_led_set(struct led_classdev *led_cdev, \ 266 static void object##_led_set(struct led_classdev *led_cdev, \
248 enum led_brightness value); \ 267 enum led_brightness value); \
268 static enum led_brightness object##_led_get( \
269 struct led_classdev *led_cdev); \
249 static void object##_led_update(struct work_struct *ignored); \ 270 static void object##_led_update(struct work_struct *ignored); \
250 static int object##_led_wk; \ 271 static int object##_led_wk; \
251 static DECLARE_WORK(object##_led_work, object##_led_update); \ 272 static DECLARE_WORK(object##_led_work, object##_led_update); \
252 static struct led_classdev object##_led = { \ 273 static struct led_classdev object##_led = { \
253 .name = "asus::" ledname, \ 274 .name = "asus::" ledname, \
254 .brightness_set = object##_led_set, \ 275 .brightness_set = object##_led_set, \
276 .brightness_get = object##_led_get, \
277 .max_brightness = max \
255 } 278 }
256 279
257ASUS_LED(mled, "mail"); 280ASUS_LED(mled, "mail", 1);
258ASUS_LED(tled, "touchpad"); 281ASUS_LED(tled, "touchpad", 1);
259ASUS_LED(rled, "record"); 282ASUS_LED(rled, "record", 1);
260ASUS_LED(pled, "phone"); 283ASUS_LED(pled, "phone", 1);
261ASUS_LED(gled, "gaming"); 284ASUS_LED(gled, "gaming", 1);
285ASUS_LED(kled, "kbd_backlight", 3);
262 286
263struct key_entry { 287struct key_entry {
264 char type; 288 char type;
@@ -278,16 +302,23 @@ static struct key_entry asus_keymap[] = {
278 {KE_KEY, 0x41, KEY_NEXTSONG}, 302 {KE_KEY, 0x41, KEY_NEXTSONG},
279 {KE_KEY, 0x43, KEY_STOPCD}, 303 {KE_KEY, 0x43, KEY_STOPCD},
280 {KE_KEY, 0x45, KEY_PLAYPAUSE}, 304 {KE_KEY, 0x45, KEY_PLAYPAUSE},
305 {KE_KEY, 0x4c, KEY_MEDIA},
281 {KE_KEY, 0x50, KEY_EMAIL}, 306 {KE_KEY, 0x50, KEY_EMAIL},
282 {KE_KEY, 0x51, KEY_WWW}, 307 {KE_KEY, 0x51, KEY_WWW},
308 {KE_KEY, 0x55, KEY_CALC},
283 {KE_KEY, 0x5C, KEY_SCREENLOCK}, /* Screenlock */ 309 {KE_KEY, 0x5C, KEY_SCREENLOCK}, /* Screenlock */
284 {KE_KEY, 0x5D, KEY_WLAN}, 310 {KE_KEY, 0x5D, KEY_WLAN},
311 {KE_KEY, 0x5E, KEY_WLAN},
312 {KE_KEY, 0x5F, KEY_WLAN},
313 {KE_KEY, 0x60, KEY_SWITCHVIDEOMODE},
285 {KE_KEY, 0x61, KEY_SWITCHVIDEOMODE}, 314 {KE_KEY, 0x61, KEY_SWITCHVIDEOMODE},
286 {KE_KEY, 0x6B, BTN_TOUCH}, /* Lock Mouse */ 315 {KE_KEY, 0x6B, BTN_TOUCH}, /* Lock Mouse */
287 {KE_KEY, 0x82, KEY_CAMERA}, 316 {KE_KEY, 0x82, KEY_CAMERA},
288 {KE_KEY, 0x8A, KEY_PROG1}, 317 {KE_KEY, 0x8A, KEY_PROG1},
289 {KE_KEY, 0x95, KEY_MEDIA}, 318 {KE_KEY, 0x95, KEY_MEDIA},
290 {KE_KEY, 0x99, KEY_PHONE}, 319 {KE_KEY, 0x99, KEY_PHONE},
320 {KE_KEY, 0xc4, KEY_KBDILLUMUP},
321 {KE_KEY, 0xc5, KEY_KBDILLUMDOWN},
291 {KE_END, 0}, 322 {KE_END, 0},
292}; 323};
293 324
@@ -301,8 +332,8 @@ static struct key_entry asus_keymap[] = {
301static int write_acpi_int(acpi_handle handle, const char *method, int val, 332static int write_acpi_int(acpi_handle handle, const char *method, int val,
302 struct acpi_buffer *output) 333 struct acpi_buffer *output)
303{ 334{
304 struct acpi_object_list params; //list of input parameters (an int here) 335 struct acpi_object_list params; /* list of input parameters (an int) */
305 union acpi_object in_obj; //the only param we use 336 union acpi_object in_obj; /* the only param we use */
306 acpi_status status; 337 acpi_status status;
307 338
308 if (!handle) 339 if (!handle)
@@ -399,6 +430,11 @@ static void write_status(acpi_handle handle, int out, int mask)
399 { \ 430 { \
400 int value = object##_led_wk; \ 431 int value = object##_led_wk; \
401 write_status(object##_set_handle, value, (mask)); \ 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; \
402 } 438 }
403 439
404ASUS_LED_HANDLER(mled, MLED_ON); 440ASUS_LED_HANDLER(mled, MLED_ON);
@@ -407,6 +443,60 @@ ASUS_LED_HANDLER(rled, RLED_ON);
407ASUS_LED_HANDLER(tled, TLED_ON); 443ASUS_LED_HANDLER(tled, TLED_ON);
408ASUS_LED_HANDLER(gled, GLED_ON); 444ASUS_LED_HANDLER(gled, GLED_ON);
409 445
446/*
447 * Keyboard backlight
448 */
449static int get_kled_lvl(void)
450{
451 unsigned long long kblv;
452 struct acpi_object_list params;
453 union acpi_object in_obj;
454 acpi_status rv;
455
456 params.count = 1;
457 params.pointer = &in_obj;
458 in_obj.type = ACPI_TYPE_INTEGER;
459 in_obj.integer.value = 2;
460
461 rv = acpi_evaluate_integer(kled_get_handle, NULL, &params, &kblv);
462 if (ACPI_FAILURE(rv)) {
463 pr_warning("Error reading kled level\n");
464 return 0;
465 }
466 return kblv;
467}
468
469static int set_kled_lvl(int kblv)
470{
471 if (kblv > 0)
472 kblv = (1 << 7) | (kblv & 0x7F);
473 else
474 kblv = 0;
475
476 if (write_acpi_int(kled_set_handle, NULL, kblv, NULL)) {
477 pr_warning("Keyboard LED display write failed\n");
478 return -EINVAL;
479 }
480 return 0;
481}
482
483static void kled_led_set(struct led_classdev *led_cdev,
484 enum led_brightness value)
485{
486 kled_led_wk = value;
487 queue_work(led_workqueue, &kled_led_work);
488}
489
490static void kled_led_update(struct work_struct *ignored)
491{
492 set_kled_lvl(kled_led_wk);
493}
494
495static enum led_brightness kled_led_get(struct led_classdev *led_cdev)
496{
497 return get_kled_lvl();
498}
499
410static int get_lcd_state(void) 500static int get_lcd_state(void)
411{ 501{
412 return read_status(LCD_ON); 502 return read_status(LCD_ON);
@@ -498,7 +588,7 @@ static ssize_t show_infos(struct device *dev,
498{ 588{
499 int len = 0; 589 int len = 0;
500 unsigned long long temp; 590 unsigned long long temp;
501 char buf[16]; //enough for all info 591 char buf[16]; /* enough for all info */
502 acpi_status rv = AE_OK; 592 acpi_status rv = AE_OK;
503 593
504 /* 594 /*
@@ -516,7 +606,17 @@ static ssize_t show_infos(struct device *dev,
516 */ 606 */
517 rv = acpi_evaluate_integer(hotk->handle, "SFUN", NULL, &temp); 607 rv = acpi_evaluate_integer(hotk->handle, "SFUN", NULL, &temp);
518 if (!ACPI_FAILURE(rv)) 608 if (!ACPI_FAILURE(rv))
519 len += sprintf(page + len, "SFUN value : 0x%04x\n", 609 len += sprintf(page + len, "SFUN value : %#x\n",
610 (uint) temp);
611 /*
612 * The HWRS method return informations about the hardware.
613 * 0x80 bit is for WLAN, 0x100 for Bluetooth.
614 * The significance of others is yet to be found.
615 * If we don't find the method, we assume the device are present.
616 */
617 rv = acpi_evaluate_integer(hotk->handle, "HRWS", NULL, &temp);
618 if (!ACPI_FAILURE(rv))
619 len += sprintf(page + len, "HRWS value : %#x\n",
520 (uint) temp); 620 (uint) temp);
521 /* 621 /*
522 * Another value for userspace: the ASYM method returns 0x02 for 622 * Another value for userspace: the ASYM method returns 0x02 for
@@ -527,7 +627,7 @@ static ssize_t show_infos(struct device *dev,
527 */ 627 */
528 rv = acpi_evaluate_integer(hotk->handle, "ASYM", NULL, &temp); 628 rv = acpi_evaluate_integer(hotk->handle, "ASYM", NULL, &temp);
529 if (!ACPI_FAILURE(rv)) 629 if (!ACPI_FAILURE(rv))
530 len += sprintf(page + len, "ASYM value : 0x%04x\n", 630 len += sprintf(page + len, "ASYM value : %#x\n",
531 (uint) temp); 631 (uint) temp);
532 if (asus_info) { 632 if (asus_info) {
533 snprintf(buf, 16, "%d", asus_info->length); 633 snprintf(buf, 16, "%d", asus_info->length);
@@ -648,8 +748,10 @@ static int read_display(void)
648 unsigned long long value = 0; 748 unsigned long long value = 0;
649 acpi_status rv = AE_OK; 749 acpi_status rv = AE_OK;
650 750
651 /* In most of the case, we know how to set the display, but sometime 751 /*
652 we can't read it */ 752 * In most of the case, we know how to set the display, but sometime
753 * we can't read it
754 */
653 if (display_get_handle) { 755 if (display_get_handle) {
654 rv = acpi_evaluate_integer(display_get_handle, NULL, 756 rv = acpi_evaluate_integer(display_get_handle, NULL,
655 NULL, &value); 757 NULL, &value);
@@ -1037,6 +1139,9 @@ static int asus_hotk_get_info(void)
1037 1139
1038 ASUS_HANDLE_INIT(ledd_set); 1140 ASUS_HANDLE_INIT(ledd_set);
1039 1141
1142 ASUS_HANDLE_INIT(kled_set);
1143 ASUS_HANDLE_INIT(kled_get);
1144
1040 /* 1145 /*
1041 * The HWRS method return informations about the hardware. 1146 * The HWRS method return informations about the hardware.
1042 * 0x80 bit is for WLAN, 0x100 for Bluetooth. 1147 * 0x80 bit is for WLAN, 0x100 for Bluetooth.
@@ -1063,8 +1168,10 @@ static int asus_hotk_get_info(void)
1063 ASUS_HANDLE_INIT(display_set); 1168 ASUS_HANDLE_INIT(display_set);
1064 ASUS_HANDLE_INIT(display_get); 1169 ASUS_HANDLE_INIT(display_get);
1065 1170
1066 /* There is a lot of models with "ALSL", but a few get 1171 /*
1067 a real light sens, so we need to check it. */ 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 */
1068 if (!ASUS_HANDLE_INIT(ls_switch)) 1175 if (!ASUS_HANDLE_INIT(ls_switch))
1069 ASUS_HANDLE_INIT(ls_level); 1176 ASUS_HANDLE_INIT(ls_level);
1070 1177
@@ -1168,6 +1275,10 @@ static int asus_hotk_add(struct acpi_device *device)
1168 /* LCD Backlight is on by default */ 1275 /* LCD Backlight is on by default */
1169 write_status(NULL, 1, LCD_ON); 1276 write_status(NULL, 1, LCD_ON);
1170 1277
1278 /* Keyboard Backlight is on by default */
1279 if (kled_set_handle)
1280 set_kled_lvl(1);
1281
1171 /* LED display is off by default */ 1282 /* LED display is off by default */
1172 hotk->ledd_status = 0xFFF; 1283 hotk->ledd_status = 0xFFF;
1173 1284
@@ -1222,6 +1333,7 @@ static void asus_led_exit(void)
1222 ASUS_LED_UNREGISTER(pled); 1333 ASUS_LED_UNREGISTER(pled);
1223 ASUS_LED_UNREGISTER(rled); 1334 ASUS_LED_UNREGISTER(rled);
1224 ASUS_LED_UNREGISTER(gled); 1335 ASUS_LED_UNREGISTER(gled);
1336 ASUS_LED_UNREGISTER(kled);
1225} 1337}
1226 1338
1227static void asus_input_exit(void) 1339static void asus_input_exit(void)
@@ -1301,13 +1413,20 @@ static int asus_led_init(struct device *dev)
1301 if (rv) 1413 if (rv)
1302 goto out4; 1414 goto out4;
1303 1415
1416 if (kled_set_handle && kled_get_handle)
1417 rv = ASUS_LED_REGISTER(kled, dev);
1418 if (rv)
1419 goto out5;
1420
1304 led_workqueue = create_singlethread_workqueue("led_workqueue"); 1421 led_workqueue = create_singlethread_workqueue("led_workqueue");
1305 if (!led_workqueue) 1422 if (!led_workqueue)
1306 goto out5; 1423 goto out6;
1307 1424
1308 return 0; 1425 return 0;
1309out5: 1426out6:
1310 rv = -ENOMEM; 1427 rv = -ENOMEM;
1428 ASUS_LED_UNREGISTER(kled);
1429out5:
1311 ASUS_LED_UNREGISTER(gled); 1430 ASUS_LED_UNREGISTER(gled);
1312out4: 1431out4:
1313 ASUS_LED_UNREGISTER(pled); 1432 ASUS_LED_UNREGISTER(pled);
diff --git a/drivers/platform/x86/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c
index 222ffb892f22..da3c08b3dcc1 100644
--- a/drivers/platform/x86/eeepc-laptop.c
+++ b/drivers/platform/x86/eeepc-laptop.c
@@ -142,18 +142,28 @@ struct eeepc_hotk {
142 struct rfkill *wlan_rfkill; 142 struct rfkill *wlan_rfkill;
143 struct rfkill *bluetooth_rfkill; 143 struct rfkill *bluetooth_rfkill;
144 struct rfkill *wwan3g_rfkill; 144 struct rfkill *wwan3g_rfkill;
145 struct rfkill *wimax_rfkill;
145 struct hotplug_slot *hotplug_slot; 146 struct hotplug_slot *hotplug_slot;
146 struct work_struct hotplug_work; 147 struct mutex hotplug_lock;
147}; 148};
148 149
149/* The actual device the driver binds to */ 150/* The actual device the driver binds to */
150static struct eeepc_hotk *ehotk; 151static struct eeepc_hotk *ehotk;
151 152
152/* Platform device/driver */ 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
153static struct platform_driver platform_driver = { 162static struct platform_driver platform_driver = {
154 .driver = { 163 .driver = {
155 .name = EEEPC_HOTK_FILE, 164 .name = EEEPC_HOTK_FILE,
156 .owner = THIS_MODULE, 165 .owner = THIS_MODULE,
166 .pm = &eeepc_pm_ops,
157 } 167 }
158}; 168};
159 169
@@ -192,7 +202,6 @@ static struct key_entry eeepc_keymap[] = {
192 */ 202 */
193static int eeepc_hotk_add(struct acpi_device *device); 203static int eeepc_hotk_add(struct acpi_device *device);
194static int eeepc_hotk_remove(struct acpi_device *device, int type); 204static int eeepc_hotk_remove(struct acpi_device *device, int type);
195static int eeepc_hotk_resume(struct acpi_device *device);
196static void eeepc_hotk_notify(struct acpi_device *device, u32 event); 205static void eeepc_hotk_notify(struct acpi_device *device, u32 event);
197 206
198static const struct acpi_device_id eeepc_device_ids[] = { 207static const struct acpi_device_id eeepc_device_ids[] = {
@@ -209,7 +218,6 @@ static struct acpi_driver eeepc_hotk_driver = {
209 .ops = { 218 .ops = {
210 .add = eeepc_hotk_add, 219 .add = eeepc_hotk_add,
211 .remove = eeepc_hotk_remove, 220 .remove = eeepc_hotk_remove,
212 .resume = eeepc_hotk_resume,
213 .notify = eeepc_hotk_notify, 221 .notify = eeepc_hotk_notify,
214 }, 222 },
215}; 223};
@@ -579,7 +587,6 @@ static void cmsg_quirks(void)
579 587
580static int eeepc_hotk_check(void) 588static int eeepc_hotk_check(void)
581{ 589{
582 const struct key_entry *key;
583 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; 590 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
584 int result; 591 int result;
585 592
@@ -604,31 +611,6 @@ static int eeepc_hotk_check(void)
604 pr_info("Get control methods supported: 0x%x\n", 611 pr_info("Get control methods supported: 0x%x\n",
605 ehotk->cm_supported); 612 ehotk->cm_supported);
606 } 613 }
607 ehotk->inputdev = input_allocate_device();
608 if (!ehotk->inputdev) {
609 pr_info("Unable to allocate input device\n");
610 return 0;
611 }
612 ehotk->inputdev->name = "Asus EeePC extra buttons";
613 ehotk->inputdev->phys = EEEPC_HOTK_FILE "/input0";
614 ehotk->inputdev->id.bustype = BUS_HOST;
615 ehotk->inputdev->getkeycode = eeepc_getkeycode;
616 ehotk->inputdev->setkeycode = eeepc_setkeycode;
617
618 for (key = eeepc_keymap; key->type != KE_END; key++) {
619 switch (key->type) {
620 case KE_KEY:
621 set_bit(EV_KEY, ehotk->inputdev->evbit);
622 set_bit(key->keycode, ehotk->inputdev->keybit);
623 break;
624 }
625 }
626 result = input_register_device(ehotk->inputdev);
627 if (result) {
628 pr_info("Unable to register input device\n");
629 input_free_device(ehotk->inputdev);
630 return 0;
631 }
632 } else { 614 } else {
633 pr_err("Hotkey device not present, aborting\n"); 615 pr_err("Hotkey device not present, aborting\n");
634 return -EINVAL; 616 return -EINVAL;
@@ -661,40 +643,48 @@ static int eeepc_get_adapter_status(struct hotplug_slot *hotplug_slot,
661 return 0; 643 return 0;
662} 644}
663 645
664static void eeepc_hotplug_work(struct work_struct *work) 646static void eeepc_rfkill_hotplug(void)
665{ 647{
666 struct pci_dev *dev; 648 struct pci_dev *dev;
667 struct pci_bus *bus = pci_find_bus(0, 1); 649 struct pci_bus *bus;
668 bool blocked; 650 bool blocked = eeepc_wlan_rfkill_blocked();
669 651
670 if (!bus) { 652 if (ehotk->wlan_rfkill)
671 pr_warning("Unable to find PCI bus 1?\n"); 653 rfkill_set_sw_state(ehotk->wlan_rfkill, blocked);
672 return;
673 }
674 654
675 blocked = eeepc_wlan_rfkill_blocked(); 655 mutex_lock(&ehotk->hotplug_lock);
676 if (!blocked) { 656
677 dev = pci_get_slot(bus, 0); 657 if (ehotk->hotplug_slot) {
678 if (dev) { 658 bus = pci_find_bus(0, 1);
679 /* Device already present */ 659 if (!bus) {
680 pci_dev_put(dev); 660 pr_warning("Unable to find PCI bus 1?\n");
681 return; 661 goto out_unlock;
682 }
683 dev = pci_scan_single_device(bus, 0);
684 if (dev) {
685 pci_bus_assign_resources(bus);
686 if (pci_bus_add_device(dev))
687 pr_err("Unable to hotplug wifi\n");
688 } 662 }
689 } else { 663
690 dev = pci_get_slot(bus, 0); 664 if (!blocked) {
691 if (dev) { 665 dev = pci_get_slot(bus, 0);
692 pci_remove_bus_device(dev); 666 if (dev) {
693 pci_dev_put(dev); 667 /* Device already present */
668 pci_dev_put(dev);
669 goto out_unlock;
670 }
671 dev = pci_scan_single_device(bus, 0);
672 if (dev) {
673 pci_bus_assign_resources(bus);
674 if (pci_bus_add_device(dev))
675 pr_err("Unable to hotplug wifi\n");
676 }
677 } else {
678 dev = pci_get_slot(bus, 0);
679 if (dev) {
680 pci_remove_bus_device(dev);
681 pci_dev_put(dev);
682 }
694 } 683 }
695 } 684 }
696 685
697 rfkill_set_sw_state(ehotk->wlan_rfkill, blocked); 686out_unlock:
687 mutex_unlock(&ehotk->hotplug_lock);
698} 688}
699 689
700static void eeepc_rfkill_notify(acpi_handle handle, u32 event, void *data) 690static void eeepc_rfkill_notify(acpi_handle handle, u32 event, void *data)
@@ -702,7 +692,7 @@ static void eeepc_rfkill_notify(acpi_handle handle, u32 event, void *data)
702 if (event != ACPI_NOTIFY_BUS_CHECK) 692 if (event != ACPI_NOTIFY_BUS_CHECK)
703 return; 693 return;
704 694
705 schedule_work(&ehotk->hotplug_work); 695 eeepc_rfkill_hotplug();
706} 696}
707 697
708static void eeepc_hotk_notify(struct acpi_device *device, u32 event) 698static void eeepc_hotk_notify(struct acpi_device *device, u32 event)
@@ -839,66 +829,38 @@ error_slot:
839 return ret; 829 return ret;
840} 830}
841 831
842static int eeepc_hotk_add(struct acpi_device *device) 832static int eeepc_hotk_thaw(struct device *device)
843{
844 int result;
845
846 if (!device)
847 return -EINVAL;
848 pr_notice(EEEPC_HOTK_NAME "\n");
849 ehotk = kzalloc(sizeof(struct eeepc_hotk), GFP_KERNEL);
850 if (!ehotk)
851 return -ENOMEM;
852 ehotk->init_flag = DISABLE_ASL_WLAN | DISABLE_ASL_DISPLAYSWITCH;
853 ehotk->handle = device->handle;
854 strcpy(acpi_device_name(device), EEEPC_HOTK_DEVICE_NAME);
855 strcpy(acpi_device_class(device), EEEPC_HOTK_CLASS);
856 device->driver_data = ehotk;
857 ehotk->device = device;
858 result = eeepc_hotk_check();
859 if (result)
860 goto ehotk_fail;
861
862 return 0;
863
864 ehotk_fail:
865 kfree(ehotk);
866 ehotk = NULL;
867
868 return result;
869}
870
871static int eeepc_hotk_remove(struct acpi_device *device, int type)
872{
873 if (!device || !acpi_driver_data(device))
874 return -EINVAL;
875
876 kfree(ehotk);
877 return 0;
878}
879
880static int eeepc_hotk_resume(struct acpi_device *device)
881{ 833{
882 if (ehotk->wlan_rfkill) { 834 if (ehotk->wlan_rfkill) {
883 bool wlan; 835 bool wlan;
884 836
885 /* Workaround - it seems that _PTS disables the wireless 837 /*
886 without notification or changing the value read by WLAN. 838 * Work around bios bug - acpi _PTS turns off the wireless led
887 Normally this is fine because the correct value is restored 839 * during suspend. Normally it restores it on resume, but
888 from the non-volatile storage on resume, but we need to do 840 * we should kick it ourselves in case hibernation is aborted.
889 it ourself if case suspend is aborted, or we lose wireless.
890 */ 841 */
891 wlan = get_acpi(CM_ASL_WLAN); 842 wlan = get_acpi(CM_ASL_WLAN);
892 set_acpi(CM_ASL_WLAN, wlan); 843 set_acpi(CM_ASL_WLAN, wlan);
844 }
893 845
894 rfkill_set_sw_state(ehotk->wlan_rfkill, wlan != 1); 846 return 0;
847}
895 848
896 schedule_work(&ehotk->hotplug_work); 849static int eeepc_hotk_restore(struct device *device)
897 } 850{
851 /* Refresh both wlan rfkill state and pci hotplug */
852 if (ehotk->wlan_rfkill)
853 eeepc_rfkill_hotplug();
898 854
899 if (ehotk->bluetooth_rfkill) 855 if (ehotk->bluetooth_rfkill)
900 rfkill_set_sw_state(ehotk->bluetooth_rfkill, 856 rfkill_set_sw_state(ehotk->bluetooth_rfkill,
901 get_acpi(CM_ASL_BLUETOOTH) != 1); 857 get_acpi(CM_ASL_BLUETOOTH) != 1);
858 if (ehotk->wwan3g_rfkill)
859 rfkill_set_sw_state(ehotk->wwan3g_rfkill,
860 get_acpi(CM_ASL_3G) != 1);
861 if (ehotk->wimax_rfkill)
862 rfkill_set_sw_state(ehotk->wimax_rfkill,
863 get_acpi(CM_ASL_WIMAX) != 1);
902 864
903 return 0; 865 return 0;
904} 866}
@@ -1019,16 +981,37 @@ static void eeepc_backlight_exit(void)
1019 981
1020static void eeepc_rfkill_exit(void) 982static void eeepc_rfkill_exit(void)
1021{ 983{
984 eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P5");
1022 eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P6"); 985 eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P6");
1023 eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P7"); 986 eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P7");
1024 if (ehotk->wlan_rfkill) 987 if (ehotk->wlan_rfkill) {
1025 rfkill_unregister(ehotk->wlan_rfkill); 988 rfkill_unregister(ehotk->wlan_rfkill);
1026 if (ehotk->bluetooth_rfkill) 989 rfkill_destroy(ehotk->wlan_rfkill);
1027 rfkill_unregister(ehotk->bluetooth_rfkill); 990 ehotk->wlan_rfkill = NULL;
1028 if (ehotk->wwan3g_rfkill) 991 }
1029 rfkill_unregister(ehotk->wwan3g_rfkill); 992 /*
993 * Refresh pci hotplug in case the rfkill state was changed after
994 * eeepc_unregister_rfkill_notifier()
995 */
996 eeepc_rfkill_hotplug();
1030 if (ehotk->hotplug_slot) 997 if (ehotk->hotplug_slot)
1031 pci_hp_deregister(ehotk->hotplug_slot); 998 pci_hp_deregister(ehotk->hotplug_slot);
999
1000 if (ehotk->bluetooth_rfkill) {
1001 rfkill_unregister(ehotk->bluetooth_rfkill);
1002 rfkill_destroy(ehotk->bluetooth_rfkill);
1003 ehotk->bluetooth_rfkill = NULL;
1004 }
1005 if (ehotk->wwan3g_rfkill) {
1006 rfkill_unregister(ehotk->wwan3g_rfkill);
1007 rfkill_destroy(ehotk->wwan3g_rfkill);
1008 ehotk->wwan3g_rfkill = NULL;
1009 }
1010 if (ehotk->wimax_rfkill) {
1011 rfkill_unregister(ehotk->wimax_rfkill);
1012 rfkill_destroy(ehotk->wimax_rfkill);
1013 ehotk->wimax_rfkill = NULL;
1014 }
1032} 1015}
1033 1016
1034static void eeepc_input_exit(void) 1017static void eeepc_input_exit(void)
@@ -1050,19 +1033,6 @@ static void eeepc_hwmon_exit(void)
1050 eeepc_hwmon_device = NULL; 1033 eeepc_hwmon_device = NULL;
1051} 1034}
1052 1035
1053static void __exit eeepc_laptop_exit(void)
1054{
1055 eeepc_backlight_exit();
1056 eeepc_rfkill_exit();
1057 eeepc_input_exit();
1058 eeepc_hwmon_exit();
1059 acpi_bus_unregister_driver(&eeepc_hotk_driver);
1060 sysfs_remove_group(&platform_device->dev.kobj,
1061 &platform_attribute_group);
1062 platform_device_unregister(platform_device);
1063 platform_driver_unregister(&platform_driver);
1064}
1065
1066static int eeepc_new_rfkill(struct rfkill **rfkill, 1036static int eeepc_new_rfkill(struct rfkill **rfkill,
1067 const char *name, struct device *dev, 1037 const char *name, struct device *dev,
1068 enum rfkill_type type, int cm) 1038 enum rfkill_type type, int cm)
@@ -1094,10 +1064,7 @@ static int eeepc_rfkill_init(struct device *dev)
1094{ 1064{
1095 int result = 0; 1065 int result = 0;
1096 1066
1097 INIT_WORK(&ehotk->hotplug_work, eeepc_hotplug_work); 1067 mutex_init(&ehotk->hotplug_lock);
1098
1099 eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P6");
1100 eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P7");
1101 1068
1102 result = eeepc_new_rfkill(&ehotk->wlan_rfkill, 1069 result = eeepc_new_rfkill(&ehotk->wlan_rfkill,
1103 "eeepc-wlan", dev, 1070 "eeepc-wlan", dev,
@@ -1120,6 +1087,13 @@ static int eeepc_rfkill_init(struct device *dev)
1120 if (result && result != -ENODEV) 1087 if (result && result != -ENODEV)
1121 goto exit; 1088 goto exit;
1122 1089
1090 result = eeepc_new_rfkill(&ehotk->wimax_rfkill,
1091 "eeepc-wimax", dev,
1092 RFKILL_TYPE_WIMAX, CM_ASL_WIMAX);
1093
1094 if (result && result != -ENODEV)
1095 goto exit;
1096
1123 result = eeepc_setup_pci_hotplug(); 1097 result = eeepc_setup_pci_hotplug();
1124 /* 1098 /*
1125 * If we get -EBUSY then something else is handling the PCI hotplug - 1099 * If we get -EBUSY then something else is handling the PCI hotplug -
@@ -1128,6 +1102,15 @@ static int eeepc_rfkill_init(struct device *dev)
1128 if (result == -EBUSY) 1102 if (result == -EBUSY)
1129 result = 0; 1103 result = 0;
1130 1104
1105 eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P5");
1106 eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P6");
1107 eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P7");
1108 /*
1109 * Refresh pci hotplug in case the rfkill state was changed during
1110 * setup.
1111 */
1112 eeepc_rfkill_hotplug();
1113
1131exit: 1114exit:
1132 if (result && result != -ENODEV) 1115 if (result && result != -ENODEV)
1133 eeepc_rfkill_exit(); 1116 eeepc_rfkill_exit();
@@ -1172,21 +1155,61 @@ static int eeepc_hwmon_init(struct device *dev)
1172 return result; 1155 return result;
1173} 1156}
1174 1157
1175static int __init eeepc_laptop_init(void) 1158static int eeepc_input_init(struct device *dev)
1176{ 1159{
1177 struct device *dev; 1160 const struct key_entry *key;
1178 int result; 1161 int result;
1179 1162
1180 if (acpi_disabled) 1163 ehotk->inputdev = input_allocate_device();
1181 return -ENODEV; 1164 if (!ehotk->inputdev) {
1182 result = acpi_bus_register_driver(&eeepc_hotk_driver); 1165 pr_info("Unable to allocate input device\n");
1183 if (result < 0) 1166 return -ENOMEM;
1167 }
1168 ehotk->inputdev->name = "Asus EeePC extra buttons";
1169 ehotk->inputdev->dev.parent = dev;
1170 ehotk->inputdev->phys = EEEPC_HOTK_FILE "/input0";
1171 ehotk->inputdev->id.bustype = BUS_HOST;
1172 ehotk->inputdev->getkeycode = eeepc_getkeycode;
1173 ehotk->inputdev->setkeycode = eeepc_setkeycode;
1174
1175 for (key = eeepc_keymap; key->type != KE_END; key++) {
1176 switch (key->type) {
1177 case KE_KEY:
1178 set_bit(EV_KEY, ehotk->inputdev->evbit);
1179 set_bit(key->keycode, ehotk->inputdev->keybit);
1180 break;
1181 }
1182 }
1183 result = input_register_device(ehotk->inputdev);
1184 if (result) {
1185 pr_info("Unable to register input device\n");
1186 input_free_device(ehotk->inputdev);
1184 return result; 1187 return result;
1185 if (!ehotk) {
1186 acpi_bus_unregister_driver(&eeepc_hotk_driver);
1187 return -ENODEV;
1188 } 1188 }
1189 return 0;
1190}
1191
1192static int eeepc_hotk_add(struct acpi_device *device)
1193{
1194 struct device *dev;
1195 int result;
1189 1196
1197 if (!device)
1198 return -EINVAL;
1199 pr_notice(EEEPC_HOTK_NAME "\n");
1200 ehotk = kzalloc(sizeof(struct eeepc_hotk), GFP_KERNEL);
1201 if (!ehotk)
1202 return -ENOMEM;
1203 ehotk->init_flag = DISABLE_ASL_WLAN | DISABLE_ASL_DISPLAYSWITCH;
1204 ehotk->handle = device->handle;
1205 strcpy(acpi_device_name(device), EEEPC_HOTK_DEVICE_NAME);
1206 strcpy(acpi_device_class(device), EEEPC_HOTK_CLASS);
1207 device->driver_data = ehotk;
1208 ehotk->device = device;
1209
1210 result = eeepc_hotk_check();
1211 if (result)
1212 goto fail_platform_driver;
1190 eeepc_enable_camera(); 1213 eeepc_enable_camera();
1191 1214
1192 /* Register platform stuff */ 1215 /* Register platform stuff */
@@ -1216,6 +1239,10 @@ static int __init eeepc_laptop_init(void)
1216 pr_info("Backlight controlled by ACPI video " 1239 pr_info("Backlight controlled by ACPI video "
1217 "driver\n"); 1240 "driver\n");
1218 1241
1242 result = eeepc_input_init(dev);
1243 if (result)
1244 goto fail_input;
1245
1219 result = eeepc_hwmon_init(dev); 1246 result = eeepc_hwmon_init(dev);
1220 if (result) 1247 if (result)
1221 goto fail_hwmon; 1248 goto fail_hwmon;
@@ -1225,9 +1252,12 @@ static int __init eeepc_laptop_init(void)
1225 goto fail_rfkill; 1252 goto fail_rfkill;
1226 1253
1227 return 0; 1254 return 0;
1255
1228fail_rfkill: 1256fail_rfkill:
1229 eeepc_hwmon_exit(); 1257 eeepc_hwmon_exit();
1230fail_hwmon: 1258fail_hwmon:
1259 eeepc_input_exit();
1260fail_input:
1231 eeepc_backlight_exit(); 1261 eeepc_backlight_exit();
1232fail_backlight: 1262fail_backlight:
1233 sysfs_remove_group(&platform_device->dev.kobj, 1263 sysfs_remove_group(&platform_device->dev.kobj,
@@ -1239,9 +1269,49 @@ fail_platform_device2:
1239fail_platform_device1: 1269fail_platform_device1:
1240 platform_driver_unregister(&platform_driver); 1270 platform_driver_unregister(&platform_driver);
1241fail_platform_driver: 1271fail_platform_driver:
1242 eeepc_input_exit(); 1272 kfree(ehotk);
1273
1243 return result; 1274 return result;
1244} 1275}
1245 1276
1277static int eeepc_hotk_remove(struct acpi_device *device, int type)
1278{
1279 if (!device || !acpi_driver_data(device))
1280 return -EINVAL;
1281
1282 eeepc_backlight_exit();
1283 eeepc_rfkill_exit();
1284 eeepc_input_exit();
1285 eeepc_hwmon_exit();
1286 sysfs_remove_group(&platform_device->dev.kobj,
1287 &platform_attribute_group);
1288 platform_device_unregister(platform_device);
1289 platform_driver_unregister(&platform_driver);
1290
1291 kfree(ehotk);
1292 return 0;
1293}
1294
1295static int __init eeepc_laptop_init(void)
1296{
1297 int result;
1298
1299 if (acpi_disabled)
1300 return -ENODEV;
1301 result = acpi_bus_register_driver(&eeepc_hotk_driver);
1302 if (result < 0)
1303 return result;
1304 if (!ehotk) {
1305 acpi_bus_unregister_driver(&eeepc_hotk_driver);
1306 return -ENODEV;
1307 }
1308 return 0;
1309}
1310
1311static void __exit eeepc_laptop_exit(void)
1312{
1313 acpi_bus_unregister_driver(&eeepc_hotk_driver);
1314}
1315
1246module_init(eeepc_laptop_init); 1316module_init(eeepc_laptop_init);
1247module_exit(eeepc_laptop_exit); 1317module_exit(eeepc_laptop_exit);
diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c
index 218b9a16ac3f..f35aee5c2149 100644
--- a/drivers/platform/x86/fujitsu-laptop.c
+++ b/drivers/platform/x86/fujitsu-laptop.c
@@ -66,11 +66,11 @@
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#ifdef CONFIG_LEDS_CLASS 69#if defined(CONFIG_LEDS_CLASS) || defined(CONFIG_LEDS_CLASS_MODULE)
70#include <linux/leds.h> 70#include <linux/leds.h>
71#endif 71#endif
72 72
73#define FUJITSU_DRIVER_VERSION "0.5.0" 73#define FUJITSU_DRIVER_VERSION "0.6.0"
74 74
75#define FUJITSU_LCD_N_LEVELS 8 75#define FUJITSU_LCD_N_LEVELS 8
76 76
@@ -96,7 +96,7 @@
96/* FUNC interface - responses */ 96/* FUNC interface - responses */
97#define UNSUPPORTED_CMD 0x80000000 97#define UNSUPPORTED_CMD 0x80000000
98 98
99#ifdef CONFIG_LEDS_CLASS 99#if defined(CONFIG_LEDS_CLASS) || defined(CONFIG_LEDS_CLASS_MODULE)
100/* FUNC interface - LED control */ 100/* FUNC interface - LED control */
101#define FUNC_LED_OFF 0x1 101#define FUNC_LED_OFF 0x1
102#define FUNC_LED_ON 0x30001 102#define FUNC_LED_ON 0x30001
@@ -176,7 +176,7 @@ static struct fujitsu_hotkey_t *fujitsu_hotkey;
176 176
177static void acpi_fujitsu_hotkey_notify(struct acpi_device *device, u32 event); 177static void acpi_fujitsu_hotkey_notify(struct acpi_device *device, u32 event);
178 178
179#ifdef CONFIG_LEDS_CLASS 179#if defined(CONFIG_LEDS_CLASS) || defined(CONFIG_LEDS_CLASS_MODULE)
180static enum led_brightness logolamp_get(struct led_classdev *cdev); 180static enum led_brightness logolamp_get(struct led_classdev *cdev);
181static void logolamp_set(struct led_classdev *cdev, 181static void logolamp_set(struct led_classdev *cdev,
182 enum led_brightness brightness); 182 enum led_brightness brightness);
@@ -257,7 +257,7 @@ static int call_fext_func(int cmd, int arg0, int arg1, int arg2)
257 return out_obj.integer.value; 257 return out_obj.integer.value;
258} 258}
259 259
260#ifdef CONFIG_LEDS_CLASS 260#if defined(CONFIG_LEDS_CLASS) || defined(CONFIG_LEDS_CLASS_MODULE)
261/* LED class callbacks */ 261/* LED class callbacks */
262 262
263static void logolamp_set(struct led_classdev *cdev, 263static void logolamp_set(struct led_classdev *cdev,
@@ -324,9 +324,6 @@ static int set_lcd_level(int level)
324 if (level < 0 || level >= fujitsu->max_brightness) 324 if (level < 0 || level >= fujitsu->max_brightness)
325 return -EINVAL; 325 return -EINVAL;
326 326
327 if (!fujitsu)
328 return -EINVAL;
329
330 status = acpi_get_handle(fujitsu->acpi_handle, "SBLL", &handle); 327 status = acpi_get_handle(fujitsu->acpi_handle, "SBLL", &handle);
331 if (ACPI_FAILURE(status)) { 328 if (ACPI_FAILURE(status)) {
332 vdbg_printk(FUJLAPTOP_DBG_ERROR, "SBLL not present\n"); 329 vdbg_printk(FUJLAPTOP_DBG_ERROR, "SBLL not present\n");
@@ -355,9 +352,6 @@ static int set_lcd_level_alt(int level)
355 if (level < 0 || level >= fujitsu->max_brightness) 352 if (level < 0 || level >= fujitsu->max_brightness)
356 return -EINVAL; 353 return -EINVAL;
357 354
358 if (!fujitsu)
359 return -EINVAL;
360
361 status = acpi_get_handle(fujitsu->acpi_handle, "SBL2", &handle); 355 status = acpi_get_handle(fujitsu->acpi_handle, "SBL2", &handle);
362 if (ACPI_FAILURE(status)) { 356 if (ACPI_FAILURE(status)) {
363 vdbg_printk(FUJLAPTOP_DBG_ERROR, "SBL2 not present\n"); 357 vdbg_printk(FUJLAPTOP_DBG_ERROR, "SBL2 not present\n");
@@ -697,10 +691,10 @@ static int acpi_fujitsu_add(struct acpi_device *device)
697 result = acpi_bus_get_power(fujitsu->acpi_handle, &state); 691 result = acpi_bus_get_power(fujitsu->acpi_handle, &state);
698 if (result) { 692 if (result) {
699 printk(KERN_ERR "Error reading power state\n"); 693 printk(KERN_ERR "Error reading power state\n");
700 goto end; 694 goto err_unregister_input_dev;
701 } 695 }
702 696
703 printk(KERN_INFO PREFIX "%s [%s] (%s)\n", 697 printk(KERN_INFO "ACPI: %s [%s] (%s)\n",
704 acpi_device_name(device), acpi_device_bid(device), 698 acpi_device_name(device), acpi_device_bid(device),
705 !device->power.state ? "on" : "off"); 699 !device->power.state ? "on" : "off");
706 700
@@ -728,25 +722,22 @@ static int acpi_fujitsu_add(struct acpi_device *device)
728 722
729 return result; 723 return result;
730 724
731end: 725err_unregister_input_dev:
726 input_unregister_device(input);
732err_free_input_dev: 727err_free_input_dev:
733 input_free_device(input); 728 input_free_device(input);
734err_stop: 729err_stop:
735
736 return result; 730 return result;
737} 731}
738 732
739static int acpi_fujitsu_remove(struct acpi_device *device, int type) 733static int acpi_fujitsu_remove(struct acpi_device *device, int type)
740{ 734{
741 struct fujitsu_t *fujitsu = NULL; 735 struct fujitsu_t *fujitsu = acpi_driver_data(device);
736 struct input_dev *input = fujitsu->input;
742 737
743 if (!device || !acpi_driver_data(device)) 738 input_unregister_device(input);
744 return -EINVAL;
745 739
746 fujitsu = acpi_driver_data(device); 740 input_free_device(input);
747
748 if (!device || !acpi_driver_data(device))
749 return -EINVAL;
750 741
751 fujitsu->acpi_handle = NULL; 742 fujitsu->acpi_handle = NULL;
752 743
@@ -871,10 +862,10 @@ static int acpi_fujitsu_hotkey_add(struct acpi_device *device)
871 result = acpi_bus_get_power(fujitsu_hotkey->acpi_handle, &state); 862 result = acpi_bus_get_power(fujitsu_hotkey->acpi_handle, &state);
872 if (result) { 863 if (result) {
873 printk(KERN_ERR "Error reading power state\n"); 864 printk(KERN_ERR "Error reading power state\n");
874 goto end; 865 goto err_unregister_input_dev;
875 } 866 }
876 867
877 printk(KERN_INFO PREFIX "%s [%s] (%s)\n", 868 printk(KERN_INFO "ACPI: %s [%s] (%s)\n",
878 acpi_device_name(device), acpi_device_bid(device), 869 acpi_device_name(device), acpi_device_bid(device),
879 !device->power.state ? "on" : "off"); 870 !device->power.state ? "on" : "off");
880 871
@@ -911,7 +902,7 @@ static int acpi_fujitsu_hotkey_add(struct acpi_device *device)
911 printk(KERN_INFO "fujitsu-laptop: BTNI: [0x%x]\n", 902 printk(KERN_INFO "fujitsu-laptop: BTNI: [0x%x]\n",
912 call_fext_func(FUNC_BUTTONS, 0x0, 0x0, 0x0)); 903 call_fext_func(FUNC_BUTTONS, 0x0, 0x0, 0x0));
913 904
914 #ifdef CONFIG_LEDS_CLASS 905#if defined(CONFIG_LEDS_CLASS) || defined(CONFIG_LEDS_CLASS_MODULE)
915 if (call_fext_func(FUNC_LEDS, 0x0, 0x0, 0x0) & LOGOLAMP_POWERON) { 906 if (call_fext_func(FUNC_LEDS, 0x0, 0x0, 0x0) & LOGOLAMP_POWERON) {
916 result = led_classdev_register(&fujitsu->pf_device->dev, 907 result = led_classdev_register(&fujitsu->pf_device->dev,
917 &logolamp_led); 908 &logolamp_led);
@@ -934,33 +925,41 @@ static int acpi_fujitsu_hotkey_add(struct acpi_device *device)
934 "LED handler for keyboard lamps, error %i\n", result); 925 "LED handler for keyboard lamps, error %i\n", result);
935 } 926 }
936 } 927 }
937 #endif 928#endif
938 929
939 return result; 930 return result;
940 931
941end: 932err_unregister_input_dev:
933 input_unregister_device(input);
942err_free_input_dev: 934err_free_input_dev:
943 input_free_device(input); 935 input_free_device(input);
944err_free_fifo: 936err_free_fifo:
945 kfifo_free(fujitsu_hotkey->fifo); 937 kfifo_free(fujitsu_hotkey->fifo);
946err_stop: 938err_stop:
947
948 return result; 939 return result;
949} 940}
950 941
951static int acpi_fujitsu_hotkey_remove(struct acpi_device *device, int type) 942static int acpi_fujitsu_hotkey_remove(struct acpi_device *device, int type)
952{ 943{
953 struct fujitsu_hotkey_t *fujitsu_hotkey = NULL; 944 struct fujitsu_hotkey_t *fujitsu_hotkey = acpi_driver_data(device);
945 struct input_dev *input = fujitsu_hotkey->input;
954 946
955 if (!device || !acpi_driver_data(device)) 947#ifdef CONFIG_LEDS_CLASS
956 return -EINVAL; 948 if (fujitsu_hotkey->logolamp_registered)
949 led_classdev_unregister(&logolamp_led);
957 950
958 fujitsu_hotkey = acpi_driver_data(device); 951 if (fujitsu_hotkey->kblamps_registered)
952 led_classdev_unregister(&kblamps_led);
953#endif
959 954
960 fujitsu_hotkey->acpi_handle = NULL; 955 input_unregister_device(input);
956
957 input_free_device(input);
961 958
962 kfifo_free(fujitsu_hotkey->fifo); 959 kfifo_free(fujitsu_hotkey->fifo);
963 960
961 fujitsu_hotkey->acpi_handle = NULL;
962
964 return 0; 963 return 0;
965} 964}
966 965
@@ -1130,8 +1129,11 @@ static int __init fujitsu_init(void)
1130 fujitsu->bl_device = 1129 fujitsu->bl_device =
1131 backlight_device_register("fujitsu-laptop", NULL, NULL, 1130 backlight_device_register("fujitsu-laptop", NULL, NULL,
1132 &fujitsubl_ops); 1131 &fujitsubl_ops);
1133 if (IS_ERR(fujitsu->bl_device)) 1132 if (IS_ERR(fujitsu->bl_device)) {
1134 return PTR_ERR(fujitsu->bl_device); 1133 ret = PTR_ERR(fujitsu->bl_device);
1134 fujitsu->bl_device = NULL;
1135 goto fail_sysfs_group;
1136 }
1135 max_brightness = fujitsu->max_brightness; 1137 max_brightness = fujitsu->max_brightness;
1136 fujitsu->bl_device->props.max_brightness = max_brightness - 1; 1138 fujitsu->bl_device->props.max_brightness = max_brightness - 1;
1137 fujitsu->bl_device->props.brightness = fujitsu->brightness_level; 1139 fujitsu->bl_device->props.brightness = fujitsu->brightness_level;
@@ -1171,32 +1173,22 @@ static int __init fujitsu_init(void)
1171 return 0; 1173 return 0;
1172 1174
1173fail_hotkey1: 1175fail_hotkey1:
1174
1175 kfree(fujitsu_hotkey); 1176 kfree(fujitsu_hotkey);
1176
1177fail_hotkey: 1177fail_hotkey:
1178
1179 platform_driver_unregister(&fujitsupf_driver); 1178 platform_driver_unregister(&fujitsupf_driver);
1180
1181fail_backlight: 1179fail_backlight:
1182
1183 if (fujitsu->bl_device) 1180 if (fujitsu->bl_device)
1184 backlight_device_unregister(fujitsu->bl_device); 1181 backlight_device_unregister(fujitsu->bl_device);
1185 1182fail_sysfs_group:
1183 sysfs_remove_group(&fujitsu->pf_device->dev.kobj,
1184 &fujitsupf_attribute_group);
1186fail_platform_device2: 1185fail_platform_device2:
1187
1188 platform_device_del(fujitsu->pf_device); 1186 platform_device_del(fujitsu->pf_device);
1189
1190fail_platform_device1: 1187fail_platform_device1:
1191
1192 platform_device_put(fujitsu->pf_device); 1188 platform_device_put(fujitsu->pf_device);
1193
1194fail_platform_driver: 1189fail_platform_driver:
1195
1196 acpi_bus_unregister_driver(&acpi_fujitsu_driver); 1190 acpi_bus_unregister_driver(&acpi_fujitsu_driver);
1197
1198fail_acpi: 1191fail_acpi:
1199
1200 kfree(fujitsu); 1192 kfree(fujitsu);
1201 1193
1202 return ret; 1194 return ret;
@@ -1204,28 +1196,23 @@ fail_acpi:
1204 1196
1205static void __exit fujitsu_cleanup(void) 1197static void __exit fujitsu_cleanup(void)
1206{ 1198{
1207 #ifdef CONFIG_LEDS_CLASS 1199 acpi_bus_unregister_driver(&acpi_fujitsu_hotkey_driver);
1208 if (fujitsu_hotkey->logolamp_registered != 0)
1209 led_classdev_unregister(&logolamp_led);
1210 1200
1211 if (fujitsu_hotkey->kblamps_registered != 0) 1201 kfree(fujitsu_hotkey);
1212 led_classdev_unregister(&kblamps_led);
1213 #endif
1214 1202
1215 sysfs_remove_group(&fujitsu->pf_device->dev.kobj,
1216 &fujitsupf_attribute_group);
1217 platform_device_unregister(fujitsu->pf_device);
1218 platform_driver_unregister(&fujitsupf_driver); 1203 platform_driver_unregister(&fujitsupf_driver);
1204
1219 if (fujitsu->bl_device) 1205 if (fujitsu->bl_device)
1220 backlight_device_unregister(fujitsu->bl_device); 1206 backlight_device_unregister(fujitsu->bl_device);
1221 1207
1222 acpi_bus_unregister_driver(&acpi_fujitsu_driver); 1208 sysfs_remove_group(&fujitsu->pf_device->dev.kobj,
1209 &fujitsupf_attribute_group);
1223 1210
1224 kfree(fujitsu); 1211 platform_device_unregister(fujitsu->pf_device);
1225 1212
1226 acpi_bus_unregister_driver(&acpi_fujitsu_hotkey_driver); 1213 acpi_bus_unregister_driver(&acpi_fujitsu_driver);
1227 1214
1228 kfree(fujitsu_hotkey); 1215 kfree(fujitsu);
1229 1216
1230 printk(KERN_INFO "fujitsu-laptop: driver unloaded.\n"); 1217 printk(KERN_INFO "fujitsu-laptop: driver unloaded.\n");
1231} 1218}
diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c
index a750192d6d4f..c2842171cec6 100644
--- a/drivers/platform/x86/hp-wmi.c
+++ b/drivers/platform/x86/hp-wmi.c
@@ -53,7 +53,7 @@ MODULE_ALIAS("wmi:5FB7F034-2C63-45e9-BE91-3D44E2C707E4");
53 53
54static int __init hp_wmi_bios_setup(struct platform_device *device); 54static int __init hp_wmi_bios_setup(struct platform_device *device);
55static int __exit hp_wmi_bios_remove(struct platform_device *device); 55static int __exit hp_wmi_bios_remove(struct platform_device *device);
56static int hp_wmi_resume_handler(struct platform_device *device); 56static int hp_wmi_resume_handler(struct device *device);
57 57
58struct bios_args { 58struct bios_args {
59 u32 signature; 59 u32 signature;
@@ -94,14 +94,19 @@ static struct rfkill *wifi_rfkill;
94static struct rfkill *bluetooth_rfkill; 94static struct rfkill *bluetooth_rfkill;
95static struct rfkill *wwan_rfkill; 95static struct rfkill *wwan_rfkill;
96 96
97static struct dev_pm_ops hp_wmi_pm_ops = {
98 .resume = hp_wmi_resume_handler,
99 .restore = hp_wmi_resume_handler,
100};
101
97static struct platform_driver hp_wmi_driver = { 102static struct platform_driver hp_wmi_driver = {
98 .driver = { 103 .driver = {
99 .name = "hp-wmi", 104 .name = "hp-wmi",
100 .owner = THIS_MODULE, 105 .owner = THIS_MODULE,
106 .pm = &hp_wmi_pm_ops,
101 }, 107 },
102 .probe = hp_wmi_bios_setup, 108 .probe = hp_wmi_bios_setup,
103 .remove = hp_wmi_bios_remove, 109 .remove = hp_wmi_bios_remove,
104 .resume = hp_wmi_resume_handler,
105}; 110};
106 111
107static int hp_wmi_perform_query(int query, int write, int value) 112static int hp_wmi_perform_query(int query, int write, int value)
@@ -512,7 +517,7 @@ static int __exit hp_wmi_bios_remove(struct platform_device *device)
512 return 0; 517 return 0;
513} 518}
514 519
515static int hp_wmi_resume_handler(struct platform_device *device) 520static int hp_wmi_resume_handler(struct device *device)
516{ 521{
517 /* 522 /*
518 * Hardware state may have changed while suspended, so trigger 523 * Hardware state may have changed while suspended, so trigger
diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c
index dafaa4a92df5..f9f68e0e7344 100644
--- a/drivers/platform/x86/sony-laptop.c
+++ b/drivers/platform/x86/sony-laptop.c
@@ -976,15 +976,12 @@ static acpi_status sony_walk_callback(acpi_handle handle, u32 level,
976 void *context, void **return_value) 976 void *context, void **return_value)
977{ 977{
978 struct acpi_device_info *info; 978 struct acpi_device_info *info;
979 struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
980
981 if (ACPI_SUCCESS(acpi_get_object_info(handle, &buffer))) {
982 info = buffer.pointer;
983 979
980 if (ACPI_SUCCESS(acpi_get_object_info(handle, &info))) {
984 printk(KERN_WARNING DRV_PFX "method: name: %4.4s, args %X\n", 981 printk(KERN_WARNING DRV_PFX "method: name: %4.4s, args %X\n",
985 (char *)&info->name, info->param_count); 982 (char *)&info->name, info->param_count);
986 983
987 kfree(buffer.pointer); 984 kfree(info);
988 } 985 }
989 986
990 return AE_OK; 987 return AE_OK;
diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c
index e85600852502..f78d27503925 100644
--- a/drivers/platform/x86/thinkpad_acpi.c
+++ b/drivers/platform/x86/thinkpad_acpi.c
@@ -1278,6 +1278,7 @@ static void tpacpi_destroy_rfkill(const enum tpacpi_rfk_id id)
1278 tp_rfk = tpacpi_rfkill_switches[id]; 1278 tp_rfk = tpacpi_rfkill_switches[id];
1279 if (tp_rfk) { 1279 if (tp_rfk) {
1280 rfkill_unregister(tp_rfk->rfkill); 1280 rfkill_unregister(tp_rfk->rfkill);
1281 rfkill_destroy(tp_rfk->rfkill);
1281 tpacpi_rfkill_switches[id] = NULL; 1282 tpacpi_rfkill_switches[id] = NULL;
1282 kfree(tp_rfk); 1283 kfree(tp_rfk);
1283 } 1284 }
@@ -1601,6 +1602,196 @@ static void tpacpi_remove_driver_attributes(struct device_driver *drv)
1601#endif 1602#endif
1602} 1603}
1603 1604
1605/*************************************************************************
1606 * Firmware Data
1607 */
1608
1609/*
1610 * Table of recommended minimum BIOS versions
1611 *
1612 * Reasons for listing:
1613 * 1. Stable BIOS, listed because the unknown ammount of
1614 * bugs and bad ACPI behaviour on older versions
1615 *
1616 * 2. BIOS or EC fw with known bugs that trigger on Linux
1617 *
1618 * 3. BIOS with known reduced functionality in older versions
1619 *
1620 * We recommend the latest BIOS and EC version.
1621 * We only support the latest BIOS and EC fw version as a rule.
1622 *
1623 * Sources: IBM ThinkPad Public Web Documents (update changelogs),
1624 * Information from users in ThinkWiki
1625 *
1626 * WARNING: we use this table also to detect that the machine is
1627 * a ThinkPad in some cases, so don't remove entries lightly.
1628 */
1629
1630#define TPV_Q(__v, __id1, __id2, __bv1, __bv2) \
1631 { .vendor = (__v), \
1632 .bios = TPID(__id1, __id2), \
1633 .ec = TPACPI_MATCH_ANY, \
1634 .quirks = TPACPI_MATCH_ANY << 16 \
1635 | (__bv1) << 8 | (__bv2) }
1636
1637#define TPV_Q_X(__v, __bid1, __bid2, __bv1, __bv2, \
1638 __eid1, __eid2, __ev1, __ev2) \
1639 { .vendor = (__v), \
1640 .bios = TPID(__bid1, __bid2), \
1641 .ec = TPID(__eid1, __eid2), \
1642 .quirks = (__ev1) << 24 | (__ev2) << 16 \
1643 | (__bv1) << 8 | (__bv2) }
1644
1645#define TPV_QI0(__id1, __id2, __bv1, __bv2) \
1646 TPV_Q(PCI_VENDOR_ID_IBM, __id1, __id2, __bv1, __bv2)
1647
1648#define TPV_QI1(__id1, __id2, __bv1, __bv2, __ev1, __ev2) \
1649 TPV_Q_X(PCI_VENDOR_ID_IBM, __id1, __id2, \
1650 __bv1, __bv2, __id1, __id2, __ev1, __ev2)
1651
1652#define TPV_QI2(__bid1, __bid2, __bv1, __bv2, \
1653 __eid1, __eid2, __ev1, __ev2) \
1654 TPV_Q_X(PCI_VENDOR_ID_IBM, __bid1, __bid2, \
1655 __bv1, __bv2, __eid1, __eid2, __ev1, __ev2)
1656
1657#define TPV_QL0(__id1, __id2, __bv1, __bv2) \
1658 TPV_Q(PCI_VENDOR_ID_LENOVO, __id1, __id2, __bv1, __bv2)
1659
1660#define TPV_QL1(__id1, __id2, __bv1, __bv2, __ev1, __ev2) \
1661 TPV_Q_X(PCI_VENDOR_ID_LENOVO, __id1, __id2, \
1662 __bv1, __bv2, __id1, __id2, __ev1, __ev2)
1663
1664#define TPV_QL2(__bid1, __bid2, __bv1, __bv2, \
1665 __eid1, __eid2, __ev1, __ev2) \
1666 TPV_Q_X(PCI_VENDOR_ID_LENOVO, __bid1, __bid2, \
1667 __bv1, __bv2, __eid1, __eid2, __ev1, __ev2)
1668
1669static const struct tpacpi_quirk tpacpi_bios_version_qtable[] __initconst = {
1670 /* Numeric models ------------------ */
1671 /* FW MODEL BIOS VERS */
1672 TPV_QI0('I', 'M', '6', '5'), /* 570 */
1673 TPV_QI0('I', 'U', '2', '6'), /* 570E */
1674 TPV_QI0('I', 'B', '5', '4'), /* 600 */
1675 TPV_QI0('I', 'H', '4', '7'), /* 600E */
1676 TPV_QI0('I', 'N', '3', '6'), /* 600E */
1677 TPV_QI0('I', 'T', '5', '5'), /* 600X */
1678 TPV_QI0('I', 'D', '4', '8'), /* 770, 770E, 770ED */
1679 TPV_QI0('I', 'I', '4', '2'), /* 770X */
1680 TPV_QI0('I', 'O', '2', '3'), /* 770Z */
1681
1682 /* A-series ------------------------- */
1683 /* FW MODEL BIOS VERS EC VERS */
1684 TPV_QI0('I', 'W', '5', '9'), /* A20m */
1685 TPV_QI0('I', 'V', '6', '9'), /* A20p */
1686 TPV_QI0('1', '0', '2', '6'), /* A21e, A22e */
1687 TPV_QI0('K', 'U', '3', '6'), /* A21e */
1688 TPV_QI0('K', 'X', '3', '6'), /* A21m, A22m */
1689 TPV_QI0('K', 'Y', '3', '8'), /* A21p, A22p */
1690 TPV_QI0('1', 'B', '1', '7'), /* A22e */
1691 TPV_QI0('1', '3', '2', '0'), /* A22m */
1692 TPV_QI0('1', 'E', '7', '3'), /* A30/p (0) */
1693 TPV_QI1('1', 'G', '4', '1', '1', '7'), /* A31/p (0) */
1694 TPV_QI1('1', 'N', '1', '6', '0', '7'), /* A31/p (0) */
1695
1696 /* G-series ------------------------- */
1697 /* FW MODEL BIOS VERS */
1698 TPV_QI0('1', 'T', 'A', '6'), /* G40 */
1699 TPV_QI0('1', 'X', '5', '7'), /* G41 */
1700
1701 /* R-series, T-series --------------- */
1702 /* FW MODEL BIOS VERS EC VERS */
1703 TPV_QI0('1', 'C', 'F', '0'), /* R30 */
1704 TPV_QI0('1', 'F', 'F', '1'), /* R31 */
1705 TPV_QI0('1', 'M', '9', '7'), /* R32 */
1706 TPV_QI0('1', 'O', '6', '1'), /* R40 */
1707 TPV_QI0('1', 'P', '6', '5'), /* R40 */
1708 TPV_QI0('1', 'S', '7', '0'), /* R40e */
1709 TPV_QI1('1', 'R', 'D', 'R', '7', '1'), /* R50/p, R51,
1710 T40/p, T41/p, T42/p (1) */
1711 TPV_QI1('1', 'V', '7', '1', '2', '8'), /* R50e, R51 (1) */
1712 TPV_QI1('7', '8', '7', '1', '0', '6'), /* R51e (1) */
1713 TPV_QI1('7', '6', '6', '9', '1', '6'), /* R52 (1) */
1714 TPV_QI1('7', '0', '6', '9', '2', '8'), /* R52, T43 (1) */
1715
1716 TPV_QI0('I', 'Y', '6', '1'), /* T20 */
1717 TPV_QI0('K', 'Z', '3', '4'), /* T21 */
1718 TPV_QI0('1', '6', '3', '2'), /* T22 */
1719 TPV_QI1('1', 'A', '6', '4', '2', '3'), /* T23 (0) */
1720 TPV_QI1('1', 'I', '7', '1', '2', '0'), /* T30 (0) */
1721 TPV_QI1('1', 'Y', '6', '5', '2', '9'), /* T43/p (1) */
1722
1723 TPV_QL1('7', '9', 'E', '3', '5', '0'), /* T60/p */
1724 TPV_QL1('7', 'C', 'D', '2', '2', '2'), /* R60, R60i */
1725 TPV_QL0('7', 'E', 'D', '0'), /* R60e, R60i */
1726
1727 /* BIOS FW BIOS VERS EC FW EC VERS */
1728 TPV_QI2('1', 'W', '9', '0', '1', 'V', '2', '8'), /* R50e (1) */
1729 TPV_QL2('7', 'I', '3', '4', '7', '9', '5', '0'), /* T60/p wide */
1730
1731 /* X-series ------------------------- */
1732 /* FW MODEL BIOS VERS EC VERS */
1733 TPV_QI0('I', 'Z', '9', 'D'), /* X20, X21 */
1734 TPV_QI0('1', 'D', '7', '0'), /* X22, X23, X24 */
1735 TPV_QI1('1', 'K', '4', '8', '1', '8'), /* X30 (0) */
1736 TPV_QI1('1', 'Q', '9', '7', '2', '3'), /* X31, X32 (0) */
1737 TPV_QI1('1', 'U', 'D', '3', 'B', '2'), /* X40 (0) */
1738 TPV_QI1('7', '4', '6', '4', '2', '7'), /* X41 (0) */
1739 TPV_QI1('7', '5', '6', '0', '2', '0'), /* X41t (0) */
1740
1741 TPV_QL0('7', 'B', 'D', '7'), /* X60/s */
1742 TPV_QL0('7', 'J', '3', '0'), /* X60t */
1743
1744 /* (0) - older versions lack DMI EC fw string and functionality */
1745 /* (1) - older versions known to lack functionality */
1746};
1747
1748#undef TPV_QL1
1749#undef TPV_QL0
1750#undef TPV_QI2
1751#undef TPV_QI1
1752#undef TPV_QI0
1753#undef TPV_Q_X
1754#undef TPV_Q
1755
1756static void __init tpacpi_check_outdated_fw(void)
1757{
1758 unsigned long fwvers;
1759 u16 ec_version, bios_version;
1760
1761 fwvers = tpacpi_check_quirks(tpacpi_bios_version_qtable,
1762 ARRAY_SIZE(tpacpi_bios_version_qtable));
1763
1764 if (!fwvers)
1765 return;
1766
1767 bios_version = fwvers & 0xffffU;
1768 ec_version = (fwvers >> 16) & 0xffffU;
1769
1770 /* note that unknown versions are set to 0x0000 and we use that */
1771 if ((bios_version > thinkpad_id.bios_release) ||
1772 (ec_version > thinkpad_id.ec_release &&
1773 ec_version != TPACPI_MATCH_ANY)) {
1774 /*
1775 * The changelogs would let us track down the exact
1776 * reason, but it is just too much of a pain to track
1777 * it. We only list BIOSes that are either really
1778 * broken, or really stable to begin with, so it is
1779 * best if the user upgrades the firmware anyway.
1780 */
1781 printk(TPACPI_WARN
1782 "WARNING: Outdated ThinkPad BIOS/EC firmware\n");
1783 printk(TPACPI_WARN
1784 "WARNING: This firmware may be missing critical bug "
1785 "fixes and/or important features\n");
1786 }
1787}
1788
1789static bool __init tpacpi_is_fw_known(void)
1790{
1791 return tpacpi_check_quirks(tpacpi_bios_version_qtable,
1792 ARRAY_SIZE(tpacpi_bios_version_qtable)) != 0;
1793}
1794
1604/**************************************************************************** 1795/****************************************************************************
1605 **************************************************************************** 1796 ****************************************************************************
1606 * 1797 *
@@ -1634,6 +1825,7 @@ static int __init thinkpad_acpi_driver_init(struct ibm_init_struct *iibm)
1634 (thinkpad_id.nummodel_str) ? 1825 (thinkpad_id.nummodel_str) ?
1635 thinkpad_id.nummodel_str : "unknown"); 1826 thinkpad_id.nummodel_str : "unknown");
1636 1827
1828 tpacpi_check_outdated_fw();
1637 return 0; 1829 return 0;
1638} 1830}
1639 1831
@@ -1731,16 +1923,42 @@ struct tp_nvram_state {
1731 u8 volume_level; 1923 u8 volume_level;
1732}; 1924};
1733 1925
1926/* kthread for the hotkey poller */
1734static struct task_struct *tpacpi_hotkey_task; 1927static struct task_struct *tpacpi_hotkey_task;
1735static u32 hotkey_source_mask; /* bit mask 0=ACPI,1=NVRAM */ 1928
1736static int hotkey_poll_freq = 10; /* Hz */ 1929/* Acquired while the poller kthread is running, use to sync start/stop */
1737static struct mutex hotkey_thread_mutex; 1930static struct mutex hotkey_thread_mutex;
1931
1932/*
1933 * Acquire mutex to write poller control variables.
1934 * Increment hotkey_config_change when changing them.
1935 *
1936 * See HOTKEY_CONFIG_CRITICAL_START/HOTKEY_CONFIG_CRITICAL_END
1937 */
1738static struct mutex hotkey_thread_data_mutex; 1938static struct mutex hotkey_thread_data_mutex;
1739static unsigned int hotkey_config_change; 1939static unsigned int hotkey_config_change;
1740 1940
1941/*
1942 * hotkey poller control variables
1943 *
1944 * Must be atomic or readers will also need to acquire mutex
1945 */
1946static u32 hotkey_source_mask; /* bit mask 0=ACPI,1=NVRAM */
1947static unsigned int hotkey_poll_freq = 10; /* Hz */
1948
1949#define HOTKEY_CONFIG_CRITICAL_START \
1950 do { \
1951 mutex_lock(&hotkey_thread_data_mutex); \
1952 hotkey_config_change++; \
1953 } while (0);
1954#define HOTKEY_CONFIG_CRITICAL_END \
1955 mutex_unlock(&hotkey_thread_data_mutex);
1956
1741#else /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */ 1957#else /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */
1742 1958
1743#define hotkey_source_mask 0U 1959#define hotkey_source_mask 0U
1960#define HOTKEY_CONFIG_CRITICAL_START
1961#define HOTKEY_CONFIG_CRITICAL_END
1744 1962
1745#endif /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */ 1963#endif /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */
1746 1964
@@ -1765,19 +1983,6 @@ static u16 *hotkey_keycode_map;
1765 1983
1766static struct attribute_set *hotkey_dev_attributes; 1984static struct attribute_set *hotkey_dev_attributes;
1767 1985
1768#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL
1769#define HOTKEY_CONFIG_CRITICAL_START \
1770 do { \
1771 mutex_lock(&hotkey_thread_data_mutex); \
1772 hotkey_config_change++; \
1773 } while (0);
1774#define HOTKEY_CONFIG_CRITICAL_END \
1775 mutex_unlock(&hotkey_thread_data_mutex);
1776#else
1777#define HOTKEY_CONFIG_CRITICAL_START
1778#define HOTKEY_CONFIG_CRITICAL_END
1779#endif /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */
1780
1781/* HKEY.MHKG() return bits */ 1986/* HKEY.MHKG() return bits */
1782#define TP_HOTKEY_TABLET_MASK (1 << 3) 1987#define TP_HOTKEY_TABLET_MASK (1 << 3)
1783 1988
@@ -1822,7 +2027,9 @@ static int hotkey_mask_get(void)
1822 if (!acpi_evalf(hkey_handle, &m, "DHKN", "d")) 2027 if (!acpi_evalf(hkey_handle, &m, "DHKN", "d"))
1823 return -EIO; 2028 return -EIO;
1824 } 2029 }
2030 HOTKEY_CONFIG_CRITICAL_START
1825 hotkey_mask = m | (hotkey_source_mask & hotkey_mask); 2031 hotkey_mask = m | (hotkey_source_mask & hotkey_mask);
2032 HOTKEY_CONFIG_CRITICAL_END
1826 2033
1827 return 0; 2034 return 0;
1828} 2035}
@@ -2075,6 +2282,7 @@ static int hotkey_kthread(void *data)
2075 unsigned int si, so; 2282 unsigned int si, so;
2076 unsigned long t; 2283 unsigned long t;
2077 unsigned int change_detector, must_reset; 2284 unsigned int change_detector, must_reset;
2285 unsigned int poll_freq;
2078 2286
2079 mutex_lock(&hotkey_thread_mutex); 2287 mutex_lock(&hotkey_thread_mutex);
2080 2288
@@ -2091,12 +2299,17 @@ static int hotkey_kthread(void *data)
2091 mutex_lock(&hotkey_thread_data_mutex); 2299 mutex_lock(&hotkey_thread_data_mutex);
2092 change_detector = hotkey_config_change; 2300 change_detector = hotkey_config_change;
2093 mask = hotkey_source_mask & hotkey_mask; 2301 mask = hotkey_source_mask & hotkey_mask;
2302 poll_freq = hotkey_poll_freq;
2094 mutex_unlock(&hotkey_thread_data_mutex); 2303 mutex_unlock(&hotkey_thread_data_mutex);
2095 hotkey_read_nvram(&s[so], mask); 2304 hotkey_read_nvram(&s[so], mask);
2096 2305
2097 while (!kthread_should_stop() && hotkey_poll_freq) { 2306 while (!kthread_should_stop()) {
2098 if (t == 0) 2307 if (t == 0) {
2099 t = 1000/hotkey_poll_freq; 2308 if (likely(poll_freq))
2309 t = 1000/poll_freq;
2310 else
2311 t = 100; /* should never happen... */
2312 }
2100 t = msleep_interruptible(t); 2313 t = msleep_interruptible(t);
2101 if (unlikely(kthread_should_stop())) 2314 if (unlikely(kthread_should_stop()))
2102 break; 2315 break;
@@ -2112,6 +2325,7 @@ static int hotkey_kthread(void *data)
2112 change_detector = hotkey_config_change; 2325 change_detector = hotkey_config_change;
2113 } 2326 }
2114 mask = hotkey_source_mask & hotkey_mask; 2327 mask = hotkey_source_mask & hotkey_mask;
2328 poll_freq = hotkey_poll_freq;
2115 mutex_unlock(&hotkey_thread_data_mutex); 2329 mutex_unlock(&hotkey_thread_data_mutex);
2116 2330
2117 if (likely(mask)) { 2331 if (likely(mask)) {
@@ -2131,6 +2345,7 @@ exit:
2131 return 0; 2345 return 0;
2132} 2346}
2133 2347
2348/* call with hotkey_mutex held */
2134static void hotkey_poll_stop_sync(void) 2349static void hotkey_poll_stop_sync(void)
2135{ 2350{
2136 if (tpacpi_hotkey_task) { 2351 if (tpacpi_hotkey_task) {
@@ -2147,10 +2362,11 @@ static void hotkey_poll_stop_sync(void)
2147} 2362}
2148 2363
2149/* call with hotkey_mutex held */ 2364/* call with hotkey_mutex held */
2150static void hotkey_poll_setup(int may_warn) 2365static void hotkey_poll_setup(bool may_warn)
2151{ 2366{
2152 if ((hotkey_source_mask & hotkey_mask) != 0 && 2367 u32 hotkeys_to_poll = hotkey_source_mask & hotkey_mask;
2153 hotkey_poll_freq > 0 && 2368
2369 if (hotkeys_to_poll != 0 && hotkey_poll_freq > 0 &&
2154 (tpacpi_inputdev->users > 0 || hotkey_report_mode < 2)) { 2370 (tpacpi_inputdev->users > 0 || hotkey_report_mode < 2)) {
2155 if (!tpacpi_hotkey_task) { 2371 if (!tpacpi_hotkey_task) {
2156 tpacpi_hotkey_task = kthread_run(hotkey_kthread, 2372 tpacpi_hotkey_task = kthread_run(hotkey_kthread,
@@ -2164,26 +2380,37 @@ static void hotkey_poll_setup(int may_warn)
2164 } 2380 }
2165 } else { 2381 } else {
2166 hotkey_poll_stop_sync(); 2382 hotkey_poll_stop_sync();
2167 if (may_warn && 2383 if (may_warn && hotkeys_to_poll != 0 &&
2168 hotkey_source_mask != 0 && hotkey_poll_freq == 0) { 2384 hotkey_poll_freq == 0) {
2169 printk(TPACPI_NOTICE 2385 printk(TPACPI_NOTICE
2170 "hot keys 0x%08x require polling, " 2386 "hot keys 0x%08x require polling, "
2171 "which is currently disabled\n", 2387 "which is currently disabled\n",
2172 hotkey_source_mask); 2388 hotkeys_to_poll);
2173 } 2389 }
2174 } 2390 }
2175} 2391}
2176 2392
2177static void hotkey_poll_setup_safe(int may_warn) 2393static void hotkey_poll_setup_safe(bool may_warn)
2178{ 2394{
2179 mutex_lock(&hotkey_mutex); 2395 mutex_lock(&hotkey_mutex);
2180 hotkey_poll_setup(may_warn); 2396 hotkey_poll_setup(may_warn);
2181 mutex_unlock(&hotkey_mutex); 2397 mutex_unlock(&hotkey_mutex);
2182} 2398}
2183 2399
2400/* call with hotkey_mutex held */
2401static void hotkey_poll_set_freq(unsigned int freq)
2402{
2403 if (!freq)
2404 hotkey_poll_stop_sync();
2405
2406 HOTKEY_CONFIG_CRITICAL_START
2407 hotkey_poll_freq = freq;
2408 HOTKEY_CONFIG_CRITICAL_END
2409}
2410
2184#else /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */ 2411#else /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */
2185 2412
2186static void hotkey_poll_setup_safe(int __unused) 2413static void hotkey_poll_setup_safe(bool __unused)
2187{ 2414{
2188} 2415}
2189 2416
@@ -2201,7 +2428,7 @@ static int hotkey_inputdev_open(struct input_dev *dev)
2201 case TPACPI_LIFE_EXITING: 2428 case TPACPI_LIFE_EXITING:
2202 return -EBUSY; 2429 return -EBUSY;
2203 case TPACPI_LIFE_RUNNING: 2430 case TPACPI_LIFE_RUNNING:
2204 hotkey_poll_setup_safe(0); 2431 hotkey_poll_setup_safe(false);
2205 return 0; 2432 return 0;
2206 } 2433 }
2207 2434
@@ -2214,7 +2441,7 @@ static void hotkey_inputdev_close(struct input_dev *dev)
2214{ 2441{
2215 /* disable hotkey polling when possible */ 2442 /* disable hotkey polling when possible */
2216 if (tpacpi_lifecycle == TPACPI_LIFE_RUNNING) 2443 if (tpacpi_lifecycle == TPACPI_LIFE_RUNNING)
2217 hotkey_poll_setup_safe(0); 2444 hotkey_poll_setup_safe(false);
2218} 2445}
2219 2446
2220/* sysfs hotkey enable ------------------------------------------------- */ 2447/* sysfs hotkey enable ------------------------------------------------- */
@@ -2288,7 +2515,7 @@ static ssize_t hotkey_mask_store(struct device *dev,
2288 res = hotkey_mask_set(t); 2515 res = hotkey_mask_set(t);
2289 2516
2290#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL 2517#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL
2291 hotkey_poll_setup(1); 2518 hotkey_poll_setup(true);
2292#endif 2519#endif
2293 2520
2294 mutex_unlock(&hotkey_mutex); 2521 mutex_unlock(&hotkey_mutex);
@@ -2318,6 +2545,8 @@ static ssize_t hotkey_bios_mask_show(struct device *dev,
2318 struct device_attribute *attr, 2545 struct device_attribute *attr,
2319 char *buf) 2546 char *buf)
2320{ 2547{
2548 printk_deprecated_attribute("hotkey_bios_mask",
2549 "This attribute is useless.");
2321 return snprintf(buf, PAGE_SIZE, "0x%08x\n", hotkey_orig_mask); 2550 return snprintf(buf, PAGE_SIZE, "0x%08x\n", hotkey_orig_mask);
2322} 2551}
2323 2552
@@ -2377,7 +2606,8 @@ static ssize_t hotkey_source_mask_store(struct device *dev,
2377 hotkey_source_mask = t; 2606 hotkey_source_mask = t;
2378 HOTKEY_CONFIG_CRITICAL_END 2607 HOTKEY_CONFIG_CRITICAL_END
2379 2608
2380 hotkey_poll_setup(1); 2609 hotkey_poll_setup(true);
2610 hotkey_mask_set(hotkey_mask);
2381 2611
2382 mutex_unlock(&hotkey_mutex); 2612 mutex_unlock(&hotkey_mutex);
2383 2613
@@ -2410,9 +2640,9 @@ static ssize_t hotkey_poll_freq_store(struct device *dev,
2410 if (mutex_lock_killable(&hotkey_mutex)) 2640 if (mutex_lock_killable(&hotkey_mutex))
2411 return -ERESTARTSYS; 2641 return -ERESTARTSYS;
2412 2642
2413 hotkey_poll_freq = t; 2643 hotkey_poll_set_freq(t);
2644 hotkey_poll_setup(true);
2414 2645
2415 hotkey_poll_setup(1);
2416 mutex_unlock(&hotkey_mutex); 2646 mutex_unlock(&hotkey_mutex);
2417 2647
2418 tpacpi_disclose_usertask("hotkey_poll_freq", "set to %lu\n", t); 2648 tpacpi_disclose_usertask("hotkey_poll_freq", "set to %lu\n", t);
@@ -2603,7 +2833,9 @@ static void tpacpi_send_radiosw_update(void)
2603static void hotkey_exit(void) 2833static void hotkey_exit(void)
2604{ 2834{
2605#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL 2835#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL
2836 mutex_lock(&hotkey_mutex);
2606 hotkey_poll_stop_sync(); 2837 hotkey_poll_stop_sync();
2838 mutex_unlock(&hotkey_mutex);
2607#endif 2839#endif
2608 2840
2609 if (hotkey_dev_attributes) 2841 if (hotkey_dev_attributes)
@@ -2623,6 +2855,15 @@ static void hotkey_exit(void)
2623 } 2855 }
2624} 2856}
2625 2857
2858static void __init hotkey_unmap(const unsigned int scancode)
2859{
2860 if (hotkey_keycode_map[scancode] != KEY_RESERVED) {
2861 clear_bit(hotkey_keycode_map[scancode],
2862 tpacpi_inputdev->keybit);
2863 hotkey_keycode_map[scancode] = KEY_RESERVED;
2864 }
2865}
2866
2626static int __init hotkey_init(struct ibm_init_struct *iibm) 2867static int __init hotkey_init(struct ibm_init_struct *iibm)
2627{ 2868{
2628 /* Requirements for changing the default keymaps: 2869 /* Requirements for changing the default keymaps:
@@ -2701,11 +2942,11 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
2701 KEY_UNKNOWN, /* 0x0D: FN+INSERT */ 2942 KEY_UNKNOWN, /* 0x0D: FN+INSERT */
2702 KEY_UNKNOWN, /* 0x0E: FN+DELETE */ 2943 KEY_UNKNOWN, /* 0x0E: FN+DELETE */
2703 2944
2704 /* These either have to go through ACPI video, or 2945 /* These should be enabled --only-- when ACPI video
2705 * act like in the IBM ThinkPads, so don't ever 2946 * is disabled (i.e. in "vendor" mode), and are handled
2706 * enable them by default */ 2947 * in a special way by the init code */
2707 KEY_RESERVED, /* 0x0F: FN+HOME (brightness up) */ 2948 KEY_BRIGHTNESSUP, /* 0x0F: FN+HOME (brightness up) */
2708 KEY_RESERVED, /* 0x10: FN+END (brightness down) */ 2949 KEY_BRIGHTNESSDOWN, /* 0x10: FN+END (brightness down) */
2709 2950
2710 KEY_RESERVED, /* 0x11: FN+PGUP (thinklight toggle) */ 2951 KEY_RESERVED, /* 0x11: FN+PGUP (thinklight toggle) */
2711 2952
@@ -2831,19 +3072,6 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
2831 goto err_exit; 3072 goto err_exit;
2832 } 3073 }
2833 3074
2834#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL
2835 if (tp_features.hotkey_mask) {
2836 hotkey_source_mask = TPACPI_HKEY_NVRAM_GOOD_MASK
2837 & ~hotkey_all_mask;
2838 } else {
2839 hotkey_source_mask = TPACPI_HKEY_NVRAM_GOOD_MASK;
2840 }
2841
2842 vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_HKEY,
2843 "hotkey source mask 0x%08x, polling freq %d\n",
2844 hotkey_source_mask, hotkey_poll_freq);
2845#endif
2846
2847#ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES 3075#ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES
2848 if (dbg_wlswemul) { 3076 if (dbg_wlswemul) {
2849 tp_features.hotkey_wlsw = 1; 3077 tp_features.hotkey_wlsw = 1;
@@ -2944,17 +3172,31 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
2944 "Disabling thinkpad-acpi brightness events " 3172 "Disabling thinkpad-acpi brightness events "
2945 "by default...\n"); 3173 "by default...\n");
2946 3174
2947 /* The hotkey_reserved_mask change below is not 3175 /* Disable brightness up/down on Lenovo thinkpads when
2948 * necessary while the keys are at KEY_RESERVED in the 3176 * ACPI is handling them, otherwise it is plain impossible
2949 * default map, but better safe than sorry, leave it 3177 * for userspace to do something even remotely sane */
2950 * here as a marker of what we have to do, especially
2951 * when we finally become able to set this at runtime
2952 * on response to X.org requests */
2953 hotkey_reserved_mask |= 3178 hotkey_reserved_mask |=
2954 (1 << TP_ACPI_HOTKEYSCAN_FNHOME) 3179 (1 << TP_ACPI_HOTKEYSCAN_FNHOME)
2955 | (1 << TP_ACPI_HOTKEYSCAN_FNEND); 3180 | (1 << TP_ACPI_HOTKEYSCAN_FNEND);
3181 hotkey_unmap(TP_ACPI_HOTKEYSCAN_FNHOME);
3182 hotkey_unmap(TP_ACPI_HOTKEYSCAN_FNEND);
2956 } 3183 }
2957 3184
3185#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL
3186 if (tp_features.hotkey_mask) {
3187 hotkey_source_mask = TPACPI_HKEY_NVRAM_GOOD_MASK
3188 & ~hotkey_all_mask
3189 & ~hotkey_reserved_mask;
3190 } else {
3191 hotkey_source_mask = TPACPI_HKEY_NVRAM_GOOD_MASK
3192 & ~hotkey_reserved_mask;
3193 }
3194
3195 vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_HKEY,
3196 "hotkey source mask 0x%08x, polling freq %u\n",
3197 hotkey_source_mask, hotkey_poll_freq);
3198#endif
3199
2958 dbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_HKEY, 3200 dbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_HKEY,
2959 "enabling firmware HKEY event interface...\n"); 3201 "enabling firmware HKEY event interface...\n");
2960 res = hotkey_status_set(true); 3202 res = hotkey_status_set(true);
@@ -2978,7 +3220,7 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
2978 tpacpi_inputdev->open = &hotkey_inputdev_open; 3220 tpacpi_inputdev->open = &hotkey_inputdev_open;
2979 tpacpi_inputdev->close = &hotkey_inputdev_close; 3221 tpacpi_inputdev->close = &hotkey_inputdev_close;
2980 3222
2981 hotkey_poll_setup_safe(1); 3223 hotkey_poll_setup_safe(true);
2982 tpacpi_send_radiosw_update(); 3224 tpacpi_send_radiosw_update();
2983 tpacpi_input_send_tabletsw(); 3225 tpacpi_input_send_tabletsw();
2984 3226
@@ -3266,7 +3508,7 @@ static void hotkey_resume(void)
3266 hotkey_tablet_mode_notify_change(); 3508 hotkey_tablet_mode_notify_change();
3267 hotkey_wakeup_reason_notify_change(); 3509 hotkey_wakeup_reason_notify_change();
3268 hotkey_wakeup_hotunplug_complete_notify_change(); 3510 hotkey_wakeup_hotunplug_complete_notify_change();
3269 hotkey_poll_setup_safe(0); 3511 hotkey_poll_setup_safe(false);
3270} 3512}
3271 3513
3272/* procfs -------------------------------------------------------------- */ 3514/* procfs -------------------------------------------------------------- */
@@ -3338,7 +3580,8 @@ static int hotkey_write(char *buf)
3338 hotkey_enabledisable_warn(0); 3580 hotkey_enabledisable_warn(0);
3339 res = -EPERM; 3581 res = -EPERM;
3340 } else if (strlencmp(cmd, "reset") == 0) { 3582 } else if (strlencmp(cmd, "reset") == 0) {
3341 mask = hotkey_orig_mask; 3583 mask = (hotkey_all_mask | hotkey_source_mask)
3584 & ~hotkey_reserved_mask;
3342 } else if (sscanf(cmd, "0x%x", &mask) == 1) { 3585 } else if (sscanf(cmd, "0x%x", &mask) == 1) {
3343 /* mask set */ 3586 /* mask set */
3344 } else if (sscanf(cmd, "%x", &mask) == 1) { 3587 } else if (sscanf(cmd, "%x", &mask) == 1) {
@@ -5655,16 +5898,16 @@ static const struct tpacpi_quirk brightness_quirk_table[] __initconst = {
5655 /* Models with ATI GPUs known to require ECNVRAM mode */ 5898 /* Models with ATI GPUs known to require ECNVRAM mode */
5656 TPACPI_Q_IBM('1', 'Y', TPACPI_BRGHT_Q_EC), /* T43/p ATI */ 5899 TPACPI_Q_IBM('1', 'Y', TPACPI_BRGHT_Q_EC), /* T43/p ATI */
5657 5900
5658 /* Models with ATI GPUs (waiting confirmation) */ 5901 /* Models with ATI GPUs that can use ECNVRAM */
5659 TPACPI_Q_IBM('1', 'R', TPACPI_BRGHT_Q_ASK|TPACPI_BRGHT_Q_EC), 5902 TPACPI_Q_IBM('1', 'R', TPACPI_BRGHT_Q_EC),
5660 TPACPI_Q_IBM('1', 'Q', TPACPI_BRGHT_Q_ASK|TPACPI_BRGHT_Q_EC), 5903 TPACPI_Q_IBM('1', 'Q', TPACPI_BRGHT_Q_ASK|TPACPI_BRGHT_Q_EC),
5661 TPACPI_Q_IBM('7', '6', TPACPI_BRGHT_Q_ASK|TPACPI_BRGHT_Q_EC), 5904 TPACPI_Q_IBM('7', '6', TPACPI_BRGHT_Q_ASK|TPACPI_BRGHT_Q_EC),
5662 TPACPI_Q_IBM('7', '8', TPACPI_BRGHT_Q_ASK|TPACPI_BRGHT_Q_EC), 5905 TPACPI_Q_IBM('7', '8', TPACPI_BRGHT_Q_ASK|TPACPI_BRGHT_Q_EC),
5663 5906
5664 /* Models with Intel Extreme Graphics 2 (waiting confirmation) */ 5907 /* Models with Intel Extreme Graphics 2 */
5908 TPACPI_Q_IBM('1', 'U', TPACPI_BRGHT_Q_NOEC),
5665 TPACPI_Q_IBM('1', 'V', TPACPI_BRGHT_Q_ASK|TPACPI_BRGHT_Q_NOEC), 5909 TPACPI_Q_IBM('1', 'V', TPACPI_BRGHT_Q_ASK|TPACPI_BRGHT_Q_NOEC),
5666 TPACPI_Q_IBM('1', 'W', TPACPI_BRGHT_Q_ASK|TPACPI_BRGHT_Q_NOEC), 5910 TPACPI_Q_IBM('1', 'W', TPACPI_BRGHT_Q_ASK|TPACPI_BRGHT_Q_NOEC),
5667 TPACPI_Q_IBM('1', 'U', TPACPI_BRGHT_Q_ASK|TPACPI_BRGHT_Q_NOEC),
5668 5911
5669 /* Models with Intel GMA900 */ 5912 /* Models with Intel GMA900 */
5670 TPACPI_Q_IBM('7', '0', TPACPI_BRGHT_Q_NOEC), /* T43, R52 */ 5913 TPACPI_Q_IBM('7', '0', TPACPI_BRGHT_Q_NOEC), /* T43, R52 */
@@ -7524,9 +7767,11 @@ static int __init probe_for_thinkpad(void)
7524 7767
7525 /* 7768 /*
7526 * Non-ancient models have better DMI tagging, but very old models 7769 * Non-ancient models have better DMI tagging, but very old models
7527 * don't. 7770 * don't. tpacpi_is_fw_known() is a cheat to help in that case.
7528 */ 7771 */
7529 is_thinkpad = (thinkpad_id.model_str != NULL); 7772 is_thinkpad = (thinkpad_id.model_str != NULL) ||
7773 (thinkpad_id.ec_model != 0) ||
7774 tpacpi_is_fw_known();
7530 7775
7531 /* ec is required because many other handles are relative to it */ 7776 /* ec is required because many other handles are relative to it */
7532 TPACPI_ACPIHANDLE_INIT(ec); 7777 TPACPI_ACPIHANDLE_INIT(ec);
@@ -7537,13 +7782,6 @@ static int __init probe_for_thinkpad(void)
7537 return -ENODEV; 7782 return -ENODEV;
7538 } 7783 }
7539 7784
7540 /*
7541 * Risks a regression on very old machines, but reduces potential
7542 * false positives a damn great deal
7543 */
7544 if (!is_thinkpad)
7545 is_thinkpad = (thinkpad_id.vendor == PCI_VENDOR_ID_IBM);
7546
7547 if (!is_thinkpad && !force_load) 7785 if (!is_thinkpad && !force_load)
7548 return -ENODEV; 7786 return -ENODEV;
7549 7787
diff --git a/drivers/platform/x86/topstar-laptop.c b/drivers/platform/x86/topstar-laptop.c
new file mode 100644
index 000000000000..02f3d4e9e666
--- /dev/null
+++ b/drivers/platform/x86/topstar-laptop.c
@@ -0,0 +1,265 @@
1/*
2 * ACPI driver for Topstar notebooks (hotkeys support only)
3 *
4 * Copyright (c) 2009 Herton Ronaldo Krzesinski <herton@mandriva.com.br>
5 *
6 * Implementation inspired by existing x86 platform drivers, in special
7 * asus/eepc/fujitsu-laptop, thanks to their authors
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
14#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
15
16#include <linux/kernel.h>
17#include <linux/module.h>
18#include <linux/init.h>
19#include <linux/acpi.h>
20#include <linux/input.h>
21
22#define ACPI_TOPSTAR_CLASS "topstar"
23
24struct topstar_hkey {
25 struct input_dev *inputdev;
26};
27
28struct tps_key_entry {
29 u8 code;
30 u16 keycode;
31};
32
33static struct tps_key_entry topstar_keymap[] = {
34 { 0x80, KEY_BRIGHTNESSUP },
35 { 0x81, KEY_BRIGHTNESSDOWN },
36 { 0x83, KEY_VOLUMEUP },
37 { 0x84, KEY_VOLUMEDOWN },
38 { 0x85, KEY_MUTE },
39 { 0x86, KEY_SWITCHVIDEOMODE },
40 { 0x87, KEY_F13 }, /* touchpad enable/disable key */
41 { 0x88, KEY_WLAN },
42 { 0x8a, KEY_WWW },
43 { 0x8b, KEY_MAIL },
44 { 0x8c, KEY_MEDIA },
45 { 0x96, KEY_F14 }, /* G key? */
46 { }
47};
48
49static struct tps_key_entry *tps_get_key_by_scancode(int code)
50{
51 struct tps_key_entry *key;
52
53 for (key = topstar_keymap; key->code; key++)
54 if (code == key->code)
55 return key;
56
57 return NULL;
58}
59
60static struct tps_key_entry *tps_get_key_by_keycode(int code)
61{
62 struct tps_key_entry *key;
63
64 for (key = topstar_keymap; key->code; key++)
65 if (code == key->keycode)
66 return key;
67
68 return NULL;
69}
70
71static void acpi_topstar_notify(struct acpi_device *device, u32 event)
72{
73 struct tps_key_entry *key;
74 static bool dup_evnt[2];
75 bool *dup;
76 struct topstar_hkey *hkey = acpi_driver_data(device);
77
78 /* 0x83 and 0x84 key events comes duplicated... */
79 if (event == 0x83 || event == 0x84) {
80 dup = &dup_evnt[event - 0x83];
81 if (*dup) {
82 *dup = false;
83 return;
84 }
85 *dup = true;
86 }
87
88 /*
89 * 'G key' generate two event codes, convert to only
90 * one event/key code for now (3G switch?)
91 */
92 if (event == 0x97)
93 event = 0x96;
94
95 key = tps_get_key_by_scancode(event);
96 if (key) {
97 input_report_key(hkey->inputdev, key->keycode, 1);
98 input_sync(hkey->inputdev);
99 input_report_key(hkey->inputdev, key->keycode, 0);
100 input_sync(hkey->inputdev);
101 return;
102 }
103
104 /* Known non hotkey events don't handled or that we don't care yet */
105 if (event == 0x8e || event == 0x8f || event == 0x90)
106 return;
107
108 pr_info("unknown event = 0x%02x\n", event);
109}
110
111static int acpi_topstar_fncx_switch(struct acpi_device *device, bool state)
112{
113 acpi_status status;
114 union acpi_object fncx_params[1] = {
115 { .type = ACPI_TYPE_INTEGER }
116 };
117 struct acpi_object_list fncx_arg_list = { 1, &fncx_params[0] };
118
119 fncx_params[0].integer.value = state ? 0x86 : 0x87;
120 status = acpi_evaluate_object(device->handle, "FNCX", &fncx_arg_list, NULL);
121 if (ACPI_FAILURE(status)) {
122 pr_err("Unable to switch FNCX notifications\n");
123 return -ENODEV;
124 }
125
126 return 0;
127}
128
129static int topstar_getkeycode(struct input_dev *dev, int scancode, int *keycode)
130{
131 struct tps_key_entry *key = tps_get_key_by_scancode(scancode);
132
133 if (!key)
134 return -EINVAL;
135
136 *keycode = key->keycode;
137 return 0;
138}
139
140static int topstar_setkeycode(struct input_dev *dev, int scancode, int keycode)
141{
142 struct tps_key_entry *key;
143 int old_keycode;
144
145 if (keycode < 0 || keycode > KEY_MAX)
146 return -EINVAL;
147
148 key = tps_get_key_by_scancode(scancode);
149
150 if (!key)
151 return -EINVAL;
152
153 old_keycode = key->keycode;
154 key->keycode = keycode;
155 set_bit(keycode, dev->keybit);
156 if (!tps_get_key_by_keycode(old_keycode))
157 clear_bit(old_keycode, dev->keybit);
158 return 0;
159}
160
161static int acpi_topstar_init_hkey(struct topstar_hkey *hkey)
162{
163 struct tps_key_entry *key;
164
165 hkey->inputdev = input_allocate_device();
166 if (!hkey->inputdev) {
167 pr_err("Unable to allocate input device\n");
168 return -ENODEV;
169 }
170 hkey->inputdev->name = "Topstar Laptop extra buttons";
171 hkey->inputdev->phys = "topstar/input0";
172 hkey->inputdev->id.bustype = BUS_HOST;
173 hkey->inputdev->getkeycode = topstar_getkeycode;
174 hkey->inputdev->setkeycode = topstar_setkeycode;
175 for (key = topstar_keymap; key->code; key++) {
176 set_bit(EV_KEY, hkey->inputdev->evbit);
177 set_bit(key->keycode, hkey->inputdev->keybit);
178 }
179 if (input_register_device(hkey->inputdev)) {
180 pr_err("Unable to register input device\n");
181 input_free_device(hkey->inputdev);
182 return -ENODEV;
183 }
184
185 return 0;
186}
187
188static int acpi_topstar_add(struct acpi_device *device)
189{
190 struct topstar_hkey *tps_hkey;
191
192 tps_hkey = kzalloc(sizeof(struct topstar_hkey), GFP_KERNEL);
193 if (!tps_hkey)
194 return -ENOMEM;
195
196 strcpy(acpi_device_name(device), "Topstar TPSACPI");
197 strcpy(acpi_device_class(device), ACPI_TOPSTAR_CLASS);
198
199 if (acpi_topstar_fncx_switch(device, true))
200 goto add_err;
201
202 if (acpi_topstar_init_hkey(tps_hkey))
203 goto add_err;
204
205 device->driver_data = tps_hkey;
206 return 0;
207
208add_err:
209 kfree(tps_hkey);
210 return -ENODEV;
211}
212
213static int acpi_topstar_remove(struct acpi_device *device, int type)
214{
215 struct topstar_hkey *tps_hkey = acpi_driver_data(device);
216
217 acpi_topstar_fncx_switch(device, false);
218
219 input_unregister_device(tps_hkey->inputdev);
220 kfree(tps_hkey);
221
222 return 0;
223}
224
225static const struct acpi_device_id topstar_device_ids[] = {
226 { "TPSACPI01", 0 },
227 { "", 0 },
228};
229MODULE_DEVICE_TABLE(acpi, topstar_device_ids);
230
231static struct acpi_driver acpi_topstar_driver = {
232 .name = "Topstar laptop ACPI driver",
233 .class = ACPI_TOPSTAR_CLASS,
234 .ids = topstar_device_ids,
235 .ops = {
236 .add = acpi_topstar_add,
237 .remove = acpi_topstar_remove,
238 .notify = acpi_topstar_notify,
239 },
240};
241
242static int __init topstar_laptop_init(void)
243{
244 int ret;
245
246 ret = acpi_bus_register_driver(&acpi_topstar_driver);
247 if (ret < 0)
248 return ret;
249
250 printk(KERN_INFO "Topstar Laptop ACPI extras driver loaded\n");
251
252 return 0;
253}
254
255static void __exit topstar_laptop_exit(void)
256{
257 acpi_bus_unregister_driver(&acpi_topstar_driver);
258}
259
260module_init(topstar_laptop_init);
261module_exit(topstar_laptop_exit);
262
263MODULE_AUTHOR("Herton Ronaldo Krzesinski");
264MODULE_DESCRIPTION("Topstar Laptop ACPI Extras driver");
265MODULE_LICENSE("GPL");
diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c
index f215a5919192..177f8d767df4 100644
--- a/drivers/platform/x86/wmi.c
+++ b/drivers/platform/x86/wmi.c
@@ -42,7 +42,6 @@ MODULE_LICENSE("GPL");
42 42
43#define ACPI_WMI_CLASS "wmi" 43#define ACPI_WMI_CLASS "wmi"
44 44
45#undef PREFIX
46#define PREFIX "ACPI: WMI: " 45#define PREFIX "ACPI: WMI: "
47 46
48static DEFINE_MUTEX(wmi_data_lock); 47static DEFINE_MUTEX(wmi_data_lock);