aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/platform/x86/Kconfig90
-rw-r--r--drivers/platform/x86/Makefile9
-rw-r--r--drivers/platform/x86/acer-wmi.c127
-rw-r--r--drivers/platform/x86/asus-laptop.c182
-rw-r--r--drivers/platform/x86/asus-nb-wmi.c98
-rw-r--r--drivers/platform/x86/asus-wmi.c1656
-rw-r--r--drivers/platform/x86/asus-wmi.h58
-rw-r--r--drivers/platform/x86/compal-laptop.c8
-rw-r--r--drivers/platform/x86/dell-wmi-aio.c171
-rw-r--r--drivers/platform/x86/eeepc-laptop.c2
-rw-r--r--drivers/platform/x86/eeepc-wmi.c912
-rw-r--r--drivers/platform/x86/hp-wmi.c312
-rw-r--r--drivers/platform/x86/ideapad-laptop.c2
-rw-r--r--drivers/platform/x86/intel_ips.c2
-rw-r--r--drivers/platform/x86/intel_mid_powerbtn.c148
-rw-r--r--drivers/platform/x86/intel_mid_thermal.c576
-rw-r--r--drivers/platform/x86/intel_rar_register.c2
-rw-r--r--drivers/platform/x86/intel_scu_ipc.c2
-rw-r--r--drivers/platform/x86/msi-laptop.c95
-rw-r--r--drivers/platform/x86/samsung-laptop.c832
-rw-r--r--drivers/platform/x86/sony-laptop.c501
-rw-r--r--drivers/platform/x86/thinkpad_acpi.c4
-rw-r--r--drivers/platform/x86/xo15-ebook.c180
23 files changed, 4754 insertions, 1215 deletions
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index 222dfb737b11..2ee442c2a5db 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -101,6 +101,19 @@ config DELL_WMI
101 To compile this driver as a module, choose M here: the module will 101 To compile this driver as a module, choose M here: the module will
102 be called dell-wmi. 102 be called dell-wmi.
103 103
104config DELL_WMI_AIO
105 tristate "WMI Hotkeys for Dell All-In-One series"
106 depends on ACPI_WMI
107 depends on INPUT
108 select INPUT_SPARSEKMAP
109 ---help---
110 Say Y here if you want to support WMI-based hotkeys on Dell
111 All-In-One machines.
112
113 To compile this driver as a module, choose M here: the module will
114 be called dell-wmi.
115
116
104config FUJITSU_LAPTOP 117config FUJITSU_LAPTOP
105 tristate "Fujitsu Laptop Extras" 118 tristate "Fujitsu Laptop Extras"
106 depends on ACPI 119 depends on ACPI
@@ -438,23 +451,53 @@ config EEEPC_LAPTOP
438 Bluetooth, backlight and allows powering on/off some other 451 Bluetooth, backlight and allows powering on/off some other
439 devices. 452 devices.
440 453
441 If you have an Eee PC laptop, say Y or M here. 454 If you have an Eee PC laptop, say Y or M here. If this driver
455 doesn't work on your Eee PC, try eeepc-wmi instead.
442 456
443config EEEPC_WMI 457config ASUS_WMI
444 tristate "Eee PC WMI Hotkey Driver (EXPERIMENTAL)" 458 tristate "ASUS WMI Driver (EXPERIMENTAL)"
445 depends on ACPI_WMI 459 depends on ACPI_WMI
446 depends on INPUT 460 depends on INPUT
461 depends on HWMON
447 depends on EXPERIMENTAL 462 depends on EXPERIMENTAL
448 depends on BACKLIGHT_CLASS_DEVICE 463 depends on BACKLIGHT_CLASS_DEVICE
449 depends on RFKILL || RFKILL = n 464 depends on RFKILL || RFKILL = n
465 depends on HOTPLUG_PCI
450 select INPUT_SPARSEKMAP 466 select INPUT_SPARSEKMAP
451 select LEDS_CLASS 467 select LEDS_CLASS
452 select NEW_LEDS 468 select NEW_LEDS
453 ---help--- 469 ---help---
454 Say Y here if you want to support WMI-based hotkeys on Eee PC laptops. 470 Say Y here if you have a WMI aware Asus laptop (like Eee PCs or new
471 Asus Notebooks).
455 472
456 To compile this driver as a module, choose M here: the module will 473 To compile this driver as a module, choose M here: the module will
457 be called eeepc-wmi. 474 be called asus-wmi.
475
476config ASUS_NB_WMI
477 tristate "Asus Notebook WMI Driver (EXPERIMENTAL)"
478 depends on ASUS_WMI
479 ---help---
480 This is a driver for newer Asus notebooks. It adds extra features
481 like wireless radio and bluetooth control, leds, hotkeys, backlight...
482
483 For more informations, see
484 <file:Documentation/ABI/testing/sysfs-platform-asus-wmi>
485
486 If you have an ACPI-WMI compatible Asus Notebook, say Y or M
487 here.
488
489config EEEPC_WMI
490 tristate "Eee PC WMI Driver (EXPERIMENTAL)"
491 depends on ASUS_WMI
492 ---help---
493 This is a driver for newer Eee PC laptops. It adds extra features
494 like wireless radio and bluetooth control, leds, hotkeys, backlight...
495
496 For more informations, see
497 <file:Documentation/ABI/testing/sysfs-platform-asus-wmi>
498
499 If you have an ACPI-WMI compatible Eee PC laptop (>= 1000), say Y or M
500 here.
458 501
459config ACPI_WMI 502config ACPI_WMI
460 tristate "WMI" 503 tristate "WMI"
@@ -616,6 +659,21 @@ config GPIO_INTEL_PMIC
616 Say Y here to support GPIO via the SCU IPC interface 659 Say Y here to support GPIO via the SCU IPC interface
617 on Intel MID platforms. 660 on Intel MID platforms.
618 661
662config INTEL_MID_POWER_BUTTON
663 tristate "power button driver for Intel MID platforms"
664 depends on INTEL_SCU_IPC && INPUT
665 help
666 This driver handles the power button on the Intel MID platforms.
667
668 If unsure, say N.
669
670config INTEL_MFLD_THERMAL
671 tristate "Thermal driver for Intel Medfield platform"
672 depends on INTEL_SCU_IPC && THERMAL
673 help
674 Say Y here to enable thermal driver support for the Intel Medfield
675 platform.
676
619config RAR_REGISTER 677config RAR_REGISTER
620 bool "Restricted Access Region Register Driver" 678 bool "Restricted Access Region Register Driver"
621 depends on PCI && X86_MRST 679 depends on PCI && X86_MRST
@@ -672,4 +730,26 @@ config XO1_RFKILL
672 Support for enabling/disabling the WLAN interface on the OLPC XO-1 730 Support for enabling/disabling the WLAN interface on the OLPC XO-1
673 laptop. 731 laptop.
674 732
733config XO15_EBOOK
734 tristate "OLPC XO-1.5 ebook switch"
735 depends on ACPI && INPUT
736 ---help---
737 Support for the ebook switch on the OLPC XO-1.5 laptop.
738
739 This switch is triggered as the screen is rotated and folded down to
740 convert the device into ebook form.
741
742config SAMSUNG_LAPTOP
743 tristate "Samsung Laptop driver"
744 depends on RFKILL && BACKLIGHT_CLASS_DEVICE && X86
745 ---help---
746 This module implements a driver for a wide range of different
747 Samsung laptops. It offers control over the different
748 function keys, wireless LED, LCD backlight level, and
749 sometimes provides a "performance_control" sysfs file to allow
750 the performance level of the laptop to be changed.
751
752 To compile this driver as a module, choose M here: the module
753 will be called samsung-laptop.
754
675endif # X86_PLATFORM_DEVICES 755endif # X86_PLATFORM_DEVICES
diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile
index 299aefb3e74c..029e8861d086 100644
--- a/drivers/platform/x86/Makefile
+++ b/drivers/platform/x86/Makefile
@@ -3,6 +3,8 @@
3# x86 Platform-Specific Drivers 3# x86 Platform-Specific Drivers
4# 4#
5obj-$(CONFIG_ASUS_LAPTOP) += asus-laptop.o 5obj-$(CONFIG_ASUS_LAPTOP) += asus-laptop.o
6obj-$(CONFIG_ASUS_WMI) += asus-wmi.o
7obj-$(CONFIG_ASUS_NB_WMI) += asus-nb-wmi.o
6obj-$(CONFIG_EEEPC_LAPTOP) += eeepc-laptop.o 8obj-$(CONFIG_EEEPC_LAPTOP) += eeepc-laptop.o
7obj-$(CONFIG_EEEPC_WMI) += eeepc-wmi.o 9obj-$(CONFIG_EEEPC_WMI) += eeepc-wmi.o
8obj-$(CONFIG_MSI_LAPTOP) += msi-laptop.o 10obj-$(CONFIG_MSI_LAPTOP) += msi-laptop.o
@@ -10,6 +12,7 @@ obj-$(CONFIG_ACPI_CMPC) += classmate-laptop.o
10obj-$(CONFIG_COMPAL_LAPTOP) += compal-laptop.o 12obj-$(CONFIG_COMPAL_LAPTOP) += compal-laptop.o
11obj-$(CONFIG_DELL_LAPTOP) += dell-laptop.o 13obj-$(CONFIG_DELL_LAPTOP) += dell-laptop.o
12obj-$(CONFIG_DELL_WMI) += dell-wmi.o 14obj-$(CONFIG_DELL_WMI) += dell-wmi.o
15obj-$(CONFIG_DELL_WMI_AIO) += dell-wmi-aio.o
13obj-$(CONFIG_ACER_WMI) += acer-wmi.o 16obj-$(CONFIG_ACER_WMI) += acer-wmi.o
14obj-$(CONFIG_ACERHDF) += acerhdf.o 17obj-$(CONFIG_ACERHDF) += acerhdf.o
15obj-$(CONFIG_HP_ACCEL) += hp_accel.o 18obj-$(CONFIG_HP_ACCEL) += hp_accel.o
@@ -29,9 +32,13 @@ obj-$(CONFIG_TOPSTAR_LAPTOP) += topstar-laptop.o
29obj-$(CONFIG_ACPI_TOSHIBA) += toshiba_acpi.o 32obj-$(CONFIG_ACPI_TOSHIBA) += toshiba_acpi.o
30obj-$(CONFIG_TOSHIBA_BT_RFKILL) += toshiba_bluetooth.o 33obj-$(CONFIG_TOSHIBA_BT_RFKILL) += toshiba_bluetooth.o
31obj-$(CONFIG_INTEL_SCU_IPC) += intel_scu_ipc.o 34obj-$(CONFIG_INTEL_SCU_IPC) += intel_scu_ipc.o
32obj-$(CONFIG_INTEL_SCU_IPC_UTIL)+= intel_scu_ipcutil.o 35obj-$(CONFIG_INTEL_SCU_IPC_UTIL) += intel_scu_ipcutil.o
36obj-$(CONFIG_INTEL_MFLD_THERMAL) += intel_mid_thermal.o
33obj-$(CONFIG_RAR_REGISTER) += intel_rar_register.o 37obj-$(CONFIG_RAR_REGISTER) += intel_rar_register.o
34obj-$(CONFIG_INTEL_IPS) += intel_ips.o 38obj-$(CONFIG_INTEL_IPS) += intel_ips.o
35obj-$(CONFIG_GPIO_INTEL_PMIC) += intel_pmic_gpio.o 39obj-$(CONFIG_GPIO_INTEL_PMIC) += intel_pmic_gpio.o
36obj-$(CONFIG_XO1_RFKILL) += xo1-rfkill.o 40obj-$(CONFIG_XO1_RFKILL) += xo1-rfkill.o
41obj-$(CONFIG_XO15_EBOOK) += xo15-ebook.o
37obj-$(CONFIG_IBM_RTL) += ibm_rtl.o 42obj-$(CONFIG_IBM_RTL) += ibm_rtl.o
43obj-$(CONFIG_SAMSUNG_LAPTOP) += samsung-laptop.o
44obj-$(CONFIG_INTEL_MFLD_THERMAL) += intel_mid_thermal.o
diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c
index c9784705f6ac..5ea6c3477d17 100644
--- a/drivers/platform/x86/acer-wmi.c
+++ b/drivers/platform/x86/acer-wmi.c
@@ -22,6 +22,8 @@
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 */ 23 */
24 24
25#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
26
25#include <linux/kernel.h> 27#include <linux/kernel.h>
26#include <linux/module.h> 28#include <linux/module.h>
27#include <linux/init.h> 29#include <linux/init.h>
@@ -46,12 +48,6 @@ MODULE_AUTHOR("Carlos Corbacho");
46MODULE_DESCRIPTION("Acer Laptop WMI Extras Driver"); 48MODULE_DESCRIPTION("Acer Laptop WMI Extras Driver");
47MODULE_LICENSE("GPL"); 49MODULE_LICENSE("GPL");
48 50
49#define ACER_LOGPREFIX "acer-wmi: "
50#define ACER_ERR KERN_ERR ACER_LOGPREFIX
51#define ACER_NOTICE KERN_NOTICE ACER_LOGPREFIX
52#define ACER_INFO KERN_INFO ACER_LOGPREFIX
53#define ACER_WARNING KERN_WARNING ACER_LOGPREFIX
54
55/* 51/*
56 * Magic Number 52 * Magic Number
57 * Meaning is unknown - this number is required for writing to ACPI for AMW0 53 * Meaning is unknown - this number is required for writing to ACPI for AMW0
@@ -84,7 +80,7 @@ MODULE_LICENSE("GPL");
84#define AMW0_GUID1 "67C3371D-95A3-4C37-BB61-DD47B491DAAB" 80#define AMW0_GUID1 "67C3371D-95A3-4C37-BB61-DD47B491DAAB"
85#define AMW0_GUID2 "431F16ED-0C2B-444C-B267-27DEB140CF9C" 81#define AMW0_GUID2 "431F16ED-0C2B-444C-B267-27DEB140CF9C"
86#define WMID_GUID1 "6AF4F258-B401-42FD-BE91-3D4AC2D7C0D3" 82#define WMID_GUID1 "6AF4F258-B401-42FD-BE91-3D4AC2D7C0D3"
87#define WMID_GUID2 "95764E09-FB56-4e83-B31A-37761F60994A" 83#define WMID_GUID2 "95764E09-FB56-4E83-B31A-37761F60994A"
88#define WMID_GUID3 "61EF69EA-865C-4BC3-A502-A0DEBA0CB531" 84#define WMID_GUID3 "61EF69EA-865C-4BC3-A502-A0DEBA0CB531"
89 85
90/* 86/*
@@ -93,7 +89,7 @@ MODULE_LICENSE("GPL");
93#define ACERWMID_EVENT_GUID "676AA15E-6A47-4D9F-A2CC-1E6D18D14026" 89#define ACERWMID_EVENT_GUID "676AA15E-6A47-4D9F-A2CC-1E6D18D14026"
94 90
95MODULE_ALIAS("wmi:67C3371D-95A3-4C37-BB61-DD47B491DAAB"); 91MODULE_ALIAS("wmi:67C3371D-95A3-4C37-BB61-DD47B491DAAB");
96MODULE_ALIAS("wmi:6AF4F258-B401-42fd-BE91-3D4AC2D7C0D3"); 92MODULE_ALIAS("wmi:6AF4F258-B401-42Fd-BE91-3D4AC2D7C0D3");
97MODULE_ALIAS("wmi:676AA15E-6A47-4D9F-A2CC-1E6D18D14026"); 93MODULE_ALIAS("wmi:676AA15E-6A47-4D9F-A2CC-1E6D18D14026");
98 94
99enum acer_wmi_event_ids { 95enum acer_wmi_event_ids {
@@ -108,7 +104,7 @@ static const struct key_entry acer_wmi_keymap[] = {
108 {KE_KEY, 0x23, {KEY_PROG3} }, /* P_Key */ 104 {KE_KEY, 0x23, {KEY_PROG3} }, /* P_Key */
109 {KE_KEY, 0x24, {KEY_PROG4} }, /* Social networking_Key */ 105 {KE_KEY, 0x24, {KEY_PROG4} }, /* Social networking_Key */
110 {KE_KEY, 0x64, {KEY_SWITCHVIDEOMODE} }, /* Display Switch */ 106 {KE_KEY, 0x64, {KEY_SWITCHVIDEOMODE} }, /* Display Switch */
111 {KE_KEY, 0x82, {KEY_F22} }, /* Touch Pad On/Off */ 107 {KE_KEY, 0x82, {KEY_TOUCHPAD_TOGGLE} }, /* Touch Pad On/Off */
112 {KE_END, 0} 108 {KE_END, 0}
113}; 109};
114 110
@@ -221,6 +217,7 @@ struct acer_debug {
221static struct rfkill *wireless_rfkill; 217static struct rfkill *wireless_rfkill;
222static struct rfkill *bluetooth_rfkill; 218static struct rfkill *bluetooth_rfkill;
223static struct rfkill *threeg_rfkill; 219static struct rfkill *threeg_rfkill;
220static bool rfkill_inited;
224 221
225/* Each low-level interface must define at least some of the following */ 222/* Each low-level interface must define at least some of the following */
226struct wmi_interface { 223struct wmi_interface {
@@ -845,7 +842,7 @@ static void type_aa_dmi_decode(const struct dmi_header *header, void *dummy)
845 has_type_aa = true; 842 has_type_aa = true;
846 type_aa = (struct hotkey_function_type_aa *) header; 843 type_aa = (struct hotkey_function_type_aa *) header;
847 844
848 printk(ACER_INFO "Function bitmap for Communication Button: 0x%x\n", 845 pr_info("Function bitmap for Communication Button: 0x%x\n",
849 type_aa->commun_func_bitmap); 846 type_aa->commun_func_bitmap);
850 847
851 if (type_aa->commun_func_bitmap & ACER_WMID3_GDS_WIRELESS) 848 if (type_aa->commun_func_bitmap & ACER_WMID3_GDS_WIRELESS)
@@ -991,6 +988,7 @@ static int __devinit acer_led_init(struct device *dev)
991 988
992static void acer_led_exit(void) 989static void acer_led_exit(void)
993{ 990{
991 set_u32(LED_OFF, ACER_CAP_MAILLED);
994 led_classdev_unregister(&mail_led); 992 led_classdev_unregister(&mail_led);
995} 993}
996 994
@@ -1036,7 +1034,7 @@ static int __devinit acer_backlight_init(struct device *dev)
1036 bd = backlight_device_register("acer-wmi", dev, NULL, &acer_bl_ops, 1034 bd = backlight_device_register("acer-wmi", dev, NULL, &acer_bl_ops,
1037 &props); 1035 &props);
1038 if (IS_ERR(bd)) { 1036 if (IS_ERR(bd)) {
1039 printk(ACER_ERR "Could not register Acer backlight device\n"); 1037 pr_err("Could not register Acer backlight device\n");
1040 acer_backlight_device = NULL; 1038 acer_backlight_device = NULL;
1041 return PTR_ERR(bd); 1039 return PTR_ERR(bd);
1042 } 1040 }
@@ -1083,8 +1081,7 @@ static acpi_status wmid3_get_device_status(u32 *value, u16 device)
1083 return AE_ERROR; 1081 return AE_ERROR;
1084 } 1082 }
1085 if (obj->buffer.length != 8) { 1083 if (obj->buffer.length != 8) {
1086 printk(ACER_WARNING "Unknown buffer length %d\n", 1084 pr_warning("Unknown buffer length %d\n", obj->buffer.length);
1087 obj->buffer.length);
1088 kfree(obj); 1085 kfree(obj);
1089 return AE_ERROR; 1086 return AE_ERROR;
1090 } 1087 }
@@ -1093,7 +1090,7 @@ static acpi_status wmid3_get_device_status(u32 *value, u16 device)
1093 kfree(obj); 1090 kfree(obj);
1094 1091
1095 if (return_value.error_code || return_value.ec_return_value) 1092 if (return_value.error_code || return_value.ec_return_value)
1096 printk(ACER_WARNING "Get Device Status failed: " 1093 pr_warning("Get Device Status failed: "
1097 "0x%x - 0x%x\n", return_value.error_code, 1094 "0x%x - 0x%x\n", return_value.error_code,
1098 return_value.ec_return_value); 1095 return_value.ec_return_value);
1099 else 1096 else
@@ -1161,9 +1158,13 @@ static int acer_rfkill_set(void *data, bool blocked)
1161{ 1158{
1162 acpi_status status; 1159 acpi_status status;
1163 u32 cap = (unsigned long)data; 1160 u32 cap = (unsigned long)data;
1164 status = set_u32(!blocked, cap); 1161
1165 if (ACPI_FAILURE(status)) 1162 if (rfkill_inited) {
1166 return -ENODEV; 1163 status = set_u32(!blocked, cap);
1164 if (ACPI_FAILURE(status))
1165 return -ENODEV;
1166 }
1167
1167 return 0; 1168 return 0;
1168} 1169}
1169 1170
@@ -1187,14 +1188,16 @@ static struct rfkill *acer_rfkill_register(struct device *dev,
1187 return ERR_PTR(-ENOMEM); 1188 return ERR_PTR(-ENOMEM);
1188 1189
1189 status = get_device_status(&state, cap); 1190 status = get_device_status(&state, cap);
1190 if (ACPI_SUCCESS(status))
1191 rfkill_init_sw_state(rfkill_dev, !state);
1192 1191
1193 err = rfkill_register(rfkill_dev); 1192 err = rfkill_register(rfkill_dev);
1194 if (err) { 1193 if (err) {
1195 rfkill_destroy(rfkill_dev); 1194 rfkill_destroy(rfkill_dev);
1196 return ERR_PTR(err); 1195 return ERR_PTR(err);
1197 } 1196 }
1197
1198 if (ACPI_SUCCESS(status))
1199 rfkill_set_sw_state(rfkill_dev, !state);
1200
1198 return rfkill_dev; 1201 return rfkill_dev;
1199} 1202}
1200 1203
@@ -1229,14 +1232,19 @@ static int acer_rfkill_init(struct device *dev)
1229 } 1232 }
1230 } 1233 }
1231 1234
1232 schedule_delayed_work(&acer_rfkill_work, round_jiffies_relative(HZ)); 1235 rfkill_inited = true;
1236
1237 if (ec_raw_mode || !wmi_has_guid(ACERWMID_EVENT_GUID))
1238 schedule_delayed_work(&acer_rfkill_work,
1239 round_jiffies_relative(HZ));
1233 1240
1234 return 0; 1241 return 0;
1235} 1242}
1236 1243
1237static void acer_rfkill_exit(void) 1244static void acer_rfkill_exit(void)
1238{ 1245{
1239 cancel_delayed_work_sync(&acer_rfkill_work); 1246 if (ec_raw_mode || !wmi_has_guid(ACERWMID_EVENT_GUID))
1247 cancel_delayed_work_sync(&acer_rfkill_work);
1240 1248
1241 rfkill_unregister(wireless_rfkill); 1249 rfkill_unregister(wireless_rfkill);
1242 rfkill_destroy(wireless_rfkill); 1250 rfkill_destroy(wireless_rfkill);
@@ -1309,7 +1317,7 @@ static void acer_wmi_notify(u32 value, void *context)
1309 1317
1310 status = wmi_get_event_data(value, &response); 1318 status = wmi_get_event_data(value, &response);
1311 if (status != AE_OK) { 1319 if (status != AE_OK) {
1312 printk(ACER_WARNING "bad event status 0x%x\n", status); 1320 pr_warning("bad event status 0x%x\n", status);
1313 return; 1321 return;
1314 } 1322 }
1315 1323
@@ -1318,14 +1326,12 @@ static void acer_wmi_notify(u32 value, void *context)
1318 if (!obj) 1326 if (!obj)
1319 return; 1327 return;
1320 if (obj->type != ACPI_TYPE_BUFFER) { 1328 if (obj->type != ACPI_TYPE_BUFFER) {
1321 printk(ACER_WARNING "Unknown response received %d\n", 1329 pr_warning("Unknown response received %d\n", obj->type);
1322 obj->type);
1323 kfree(obj); 1330 kfree(obj);
1324 return; 1331 return;
1325 } 1332 }
1326 if (obj->buffer.length != 8) { 1333 if (obj->buffer.length != 8) {
1327 printk(ACER_WARNING "Unknown buffer length %d\n", 1334 pr_warning("Unknown buffer length %d\n", obj->buffer.length);
1328 obj->buffer.length);
1329 kfree(obj); 1335 kfree(obj);
1330 return; 1336 return;
1331 } 1337 }
@@ -1335,13 +1341,26 @@ static void acer_wmi_notify(u32 value, void *context)
1335 1341
1336 switch (return_value.function) { 1342 switch (return_value.function) {
1337 case WMID_HOTKEY_EVENT: 1343 case WMID_HOTKEY_EVENT:
1344 if (return_value.device_state) {
1345 u16 device_state = return_value.device_state;
1346 pr_debug("deivces states: 0x%x\n", device_state);
1347 if (has_cap(ACER_CAP_WIRELESS))
1348 rfkill_set_sw_state(wireless_rfkill,
1349 !(device_state & ACER_WMID3_GDS_WIRELESS));
1350 if (has_cap(ACER_CAP_BLUETOOTH))
1351 rfkill_set_sw_state(bluetooth_rfkill,
1352 !(device_state & ACER_WMID3_GDS_BLUETOOTH));
1353 if (has_cap(ACER_CAP_THREEG))
1354 rfkill_set_sw_state(threeg_rfkill,
1355 !(device_state & ACER_WMID3_GDS_THREEG));
1356 }
1338 if (!sparse_keymap_report_event(acer_wmi_input_dev, 1357 if (!sparse_keymap_report_event(acer_wmi_input_dev,
1339 return_value.key_num, 1, true)) 1358 return_value.key_num, 1, true))
1340 printk(ACER_WARNING "Unknown key number - 0x%x\n", 1359 pr_warning("Unknown key number - 0x%x\n",
1341 return_value.key_num); 1360 return_value.key_num);
1342 break; 1361 break;
1343 default: 1362 default:
1344 printk(ACER_WARNING "Unknown function number - %d - %d\n", 1363 pr_warning("Unknown function number - %d - %d\n",
1345 return_value.function, return_value.key_num); 1364 return_value.function, return_value.key_num);
1346 break; 1365 break;
1347 } 1366 }
@@ -1370,8 +1389,7 @@ wmid3_set_lm_mode(struct lm_input_params *params,
1370 return AE_ERROR; 1389 return AE_ERROR;
1371 } 1390 }
1372 if (obj->buffer.length != 4) { 1391 if (obj->buffer.length != 4) {
1373 printk(ACER_WARNING "Unknown buffer length %d\n", 1392 pr_warning("Unknown buffer length %d\n", obj->buffer.length);
1374 obj->buffer.length);
1375 kfree(obj); 1393 kfree(obj);
1376 return AE_ERROR; 1394 return AE_ERROR;
1377 } 1395 }
@@ -1396,11 +1414,11 @@ static int acer_wmi_enable_ec_raw(void)
1396 status = wmid3_set_lm_mode(&params, &return_value); 1414 status = wmid3_set_lm_mode(&params, &return_value);
1397 1415
1398 if (return_value.error_code || return_value.ec_return_value) 1416 if (return_value.error_code || return_value.ec_return_value)
1399 printk(ACER_WARNING "Enabling EC raw mode failed: " 1417 pr_warning("Enabling EC raw mode failed: "
1400 "0x%x - 0x%x\n", return_value.error_code, 1418 "0x%x - 0x%x\n", return_value.error_code,
1401 return_value.ec_return_value); 1419 return_value.ec_return_value);
1402 else 1420 else
1403 printk(ACER_INFO "Enabled EC raw mode"); 1421 pr_info("Enabled EC raw mode");
1404 1422
1405 return status; 1423 return status;
1406} 1424}
@@ -1419,7 +1437,7 @@ static int acer_wmi_enable_lm(void)
1419 status = wmid3_set_lm_mode(&params, &return_value); 1437 status = wmid3_set_lm_mode(&params, &return_value);
1420 1438
1421 if (return_value.error_code || return_value.ec_return_value) 1439 if (return_value.error_code || return_value.ec_return_value)
1422 printk(ACER_WARNING "Enabling Launch Manager failed: " 1440 pr_warning("Enabling Launch Manager failed: "
1423 "0x%x - 0x%x\n", return_value.error_code, 1441 "0x%x - 0x%x\n", return_value.error_code,
1424 return_value.ec_return_value); 1442 return_value.ec_return_value);
1425 1443
@@ -1553,6 +1571,7 @@ pm_message_t state)
1553 1571
1554 if (has_cap(ACER_CAP_MAILLED)) { 1572 if (has_cap(ACER_CAP_MAILLED)) {
1555 get_u32(&value, ACER_CAP_MAILLED); 1573 get_u32(&value, ACER_CAP_MAILLED);
1574 set_u32(LED_OFF, ACER_CAP_MAILLED);
1556 data->mailled = value; 1575 data->mailled = value;
1557 } 1576 }
1558 1577
@@ -1580,6 +1599,17 @@ static int acer_platform_resume(struct platform_device *device)
1580 return 0; 1599 return 0;
1581} 1600}
1582 1601
1602static void acer_platform_shutdown(struct platform_device *device)
1603{
1604 struct acer_data *data = &interface->data;
1605
1606 if (!data)
1607 return;
1608
1609 if (has_cap(ACER_CAP_MAILLED))
1610 set_u32(LED_OFF, ACER_CAP_MAILLED);
1611}
1612
1583static struct platform_driver acer_platform_driver = { 1613static struct platform_driver acer_platform_driver = {
1584 .driver = { 1614 .driver = {
1585 .name = "acer-wmi", 1615 .name = "acer-wmi",
@@ -1589,6 +1619,7 @@ static struct platform_driver acer_platform_driver = {
1589 .remove = acer_platform_remove, 1619 .remove = acer_platform_remove,
1590 .suspend = acer_platform_suspend, 1620 .suspend = acer_platform_suspend,
1591 .resume = acer_platform_resume, 1621 .resume = acer_platform_resume,
1622 .shutdown = acer_platform_shutdown,
1592}; 1623};
1593 1624
1594static struct platform_device *acer_platform_device; 1625static struct platform_device *acer_platform_device;
@@ -1636,7 +1667,7 @@ static int create_debugfs(void)
1636{ 1667{
1637 interface->debug.root = debugfs_create_dir("acer-wmi", NULL); 1668 interface->debug.root = debugfs_create_dir("acer-wmi", NULL);
1638 if (!interface->debug.root) { 1669 if (!interface->debug.root) {
1639 printk(ACER_ERR "Failed to create debugfs directory"); 1670 pr_err("Failed to create debugfs directory");
1640 return -ENOMEM; 1671 return -ENOMEM;
1641 } 1672 }
1642 1673
@@ -1657,11 +1688,10 @@ static int __init acer_wmi_init(void)
1657{ 1688{
1658 int err; 1689 int err;
1659 1690
1660 printk(ACER_INFO "Acer Laptop ACPI-WMI Extras\n"); 1691 pr_info("Acer Laptop ACPI-WMI Extras\n");
1661 1692
1662 if (dmi_check_system(acer_blacklist)) { 1693 if (dmi_check_system(acer_blacklist)) {
1663 printk(ACER_INFO "Blacklisted hardware detected - " 1694 pr_info("Blacklisted hardware detected - not loading\n");
1664 "not loading\n");
1665 return -ENODEV; 1695 return -ENODEV;
1666 } 1696 }
1667 1697
@@ -1678,12 +1708,11 @@ static int __init acer_wmi_init(void)
1678 1708
1679 if (wmi_has_guid(WMID_GUID2) && interface) { 1709 if (wmi_has_guid(WMID_GUID2) && interface) {
1680 if (ACPI_FAILURE(WMID_set_capabilities())) { 1710 if (ACPI_FAILURE(WMID_set_capabilities())) {
1681 printk(ACER_ERR "Unable to detect available WMID " 1711 pr_err("Unable to detect available WMID devices\n");
1682 "devices\n");
1683 return -ENODEV; 1712 return -ENODEV;
1684 } 1713 }
1685 } else if (!wmi_has_guid(WMID_GUID2) && interface) { 1714 } else if (!wmi_has_guid(WMID_GUID2) && interface) {
1686 printk(ACER_ERR "No WMID device detection method found\n"); 1715 pr_err("No WMID device detection method found\n");
1687 return -ENODEV; 1716 return -ENODEV;
1688 } 1717 }
1689 1718
@@ -1691,8 +1720,7 @@ static int __init acer_wmi_init(void)
1691 interface = &AMW0_interface; 1720 interface = &AMW0_interface;
1692 1721
1693 if (ACPI_FAILURE(AMW0_set_capabilities())) { 1722 if (ACPI_FAILURE(AMW0_set_capabilities())) {
1694 printk(ACER_ERR "Unable to detect available AMW0 " 1723 pr_err("Unable to detect available AMW0 devices\n");
1695 "devices\n");
1696 return -ENODEV; 1724 return -ENODEV;
1697 } 1725 }
1698 } 1726 }
@@ -1701,8 +1729,7 @@ static int __init acer_wmi_init(void)
1701 AMW0_find_mailled(); 1729 AMW0_find_mailled();
1702 1730
1703 if (!interface) { 1731 if (!interface) {
1704 printk(ACER_INFO "No or unsupported WMI interface, unable to " 1732 pr_err("No or unsupported WMI interface, unable to load\n");
1705 "load\n");
1706 return -ENODEV; 1733 return -ENODEV;
1707 } 1734 }
1708 1735
@@ -1710,22 +1737,22 @@ static int __init acer_wmi_init(void)
1710 1737
1711 if (acpi_video_backlight_support() && has_cap(ACER_CAP_BRIGHTNESS)) { 1738 if (acpi_video_backlight_support() && has_cap(ACER_CAP_BRIGHTNESS)) {
1712 interface->capability &= ~ACER_CAP_BRIGHTNESS; 1739 interface->capability &= ~ACER_CAP_BRIGHTNESS;
1713 printk(ACER_INFO "Brightness must be controlled by " 1740 pr_info("Brightness must be controlled by "
1714 "generic video driver\n"); 1741 "generic video driver\n");
1715 } 1742 }
1716 1743
1717 if (wmi_has_guid(WMID_GUID3)) { 1744 if (wmi_has_guid(WMID_GUID3)) {
1718 if (ec_raw_mode) { 1745 if (ec_raw_mode) {
1719 if (ACPI_FAILURE(acer_wmi_enable_ec_raw())) { 1746 if (ACPI_FAILURE(acer_wmi_enable_ec_raw())) {
1720 printk(ACER_ERR "Cannot enable EC raw mode\n"); 1747 pr_err("Cannot enable EC raw mode\n");
1721 return -ENODEV; 1748 return -ENODEV;
1722 } 1749 }
1723 } else if (ACPI_FAILURE(acer_wmi_enable_lm())) { 1750 } else if (ACPI_FAILURE(acer_wmi_enable_lm())) {
1724 printk(ACER_ERR "Cannot enable Launch Manager mode\n"); 1751 pr_err("Cannot enable Launch Manager mode\n");
1725 return -ENODEV; 1752 return -ENODEV;
1726 } 1753 }
1727 } else if (ec_raw_mode) { 1754 } else if (ec_raw_mode) {
1728 printk(ACER_INFO "No WMID EC raw mode enable method\n"); 1755 pr_info("No WMID EC raw mode enable method\n");
1729 } 1756 }
1730 1757
1731 if (wmi_has_guid(ACERWMID_EVENT_GUID)) { 1758 if (wmi_has_guid(ACERWMID_EVENT_GUID)) {
@@ -1736,7 +1763,7 @@ static int __init acer_wmi_init(void)
1736 1763
1737 err = platform_driver_register(&acer_platform_driver); 1764 err = platform_driver_register(&acer_platform_driver);
1738 if (err) { 1765 if (err) {
1739 printk(ACER_ERR "Unable to register platform driver.\n"); 1766 pr_err("Unable to register platform driver.\n");
1740 goto error_platform_register; 1767 goto error_platform_register;
1741 } 1768 }
1742 1769
@@ -1791,7 +1818,7 @@ static void __exit acer_wmi_exit(void)
1791 platform_device_unregister(acer_platform_device); 1818 platform_device_unregister(acer_platform_device);
1792 platform_driver_unregister(&acer_platform_driver); 1819 platform_driver_unregister(&acer_platform_driver);
1793 1820
1794 printk(ACER_INFO "Acer Laptop WMI Extras unloaded\n"); 1821 pr_info("Acer Laptop WMI Extras unloaded\n");
1795 return; 1822 return;
1796} 1823}
1797 1824
diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c
index 5a6f7d7575d6..c53b3ff7978a 100644
--- a/drivers/platform/x86/asus-laptop.c
+++ b/drivers/platform/x86/asus-laptop.c
@@ -29,7 +29,7 @@
29 * John Belmonte - ACPI code for Toshiba laptop was a good starting point. 29 * John Belmonte - ACPI code for Toshiba laptop was a good starting point.
30 * Eric Burghard - LED display support for W1N 30 * Eric Burghard - LED display support for W1N
31 * Josh Green - Light Sens support 31 * Josh Green - Light Sens support
32 * Thomas Tuttle - His first patch for led support was very helpfull 32 * Thomas Tuttle - His first patch for led support was very helpful
33 * Sam Lin - GPS support 33 * Sam Lin - GPS support
34 */ 34 */
35 35
@@ -50,6 +50,7 @@
50#include <linux/input/sparse-keymap.h> 50#include <linux/input/sparse-keymap.h>
51#include <linux/rfkill.h> 51#include <linux/rfkill.h>
52#include <linux/slab.h> 52#include <linux/slab.h>
53#include <linux/dmi.h>
53#include <acpi/acpi_drivers.h> 54#include <acpi/acpi_drivers.h>
54#include <acpi/acpi_bus.h> 55#include <acpi/acpi_bus.h>
55 56
@@ -157,46 +158,9 @@ MODULE_PARM_DESC(wwan_status, "Set the wireless status on boot "
157#define METHOD_BRIGHTNESS_SET "SPLV" 158#define METHOD_BRIGHTNESS_SET "SPLV"
158#define METHOD_BRIGHTNESS_GET "GPLV" 159#define METHOD_BRIGHTNESS_GET "GPLV"
159 160
160/* Backlight */
161static acpi_handle lcd_switch_handle;
162static char *lcd_switch_paths[] = {
163 "\\_SB.PCI0.SBRG.EC0._Q10", /* All new models */
164 "\\_SB.PCI0.ISA.EC0._Q10", /* A1x */
165 "\\_SB.PCI0.PX40.ECD0._Q10", /* L3C */
166 "\\_SB.PCI0.PX40.EC0.Q10", /* M1A */
167 "\\_SB.PCI0.LPCB.EC0._Q10", /* P30 */
168 "\\_SB.PCI0.LPCB.EC0._Q0E", /* P30/P35 */
169 "\\_SB.PCI0.PX40.Q10", /* S1x */
170 "\\Q10"}; /* A2x, L2D, L3D, M2E */
171
172/* Display */ 161/* Display */
173#define METHOD_SWITCH_DISPLAY "SDSP" 162#define METHOD_SWITCH_DISPLAY "SDSP"
174 163
175static acpi_handle display_get_handle;
176static char *display_get_paths[] = {
177 /* A6B, A6K A6R A7D F3JM L4R M6R A3G M6A M6V VX-1 V6J V6V W3Z */
178 "\\_SB.PCI0.P0P1.VGA.GETD",
179 /* A3E A4K, A4D A4L A6J A7J A8J Z71V M9V S5A M5A z33A W1Jc W2V G1 */
180 "\\_SB.PCI0.P0P2.VGA.GETD",
181 /* A6V A6Q */
182 "\\_SB.PCI0.P0P3.VGA.GETD",
183 /* A6T, A6M */
184 "\\_SB.PCI0.P0PA.VGA.GETD",
185 /* L3C */
186 "\\_SB.PCI0.PCI1.VGAC.NMAP",
187 /* Z96F */
188 "\\_SB.PCI0.VGA.GETD",
189 /* A2D */
190 "\\ACTD",
191 /* A4G Z71A W1N W5A W5F M2N M3N M5N M6N S1N S5N */
192 "\\ADVG",
193 /* P30 */
194 "\\DNXT",
195 /* A2H D1 L2D L3D L3H L2E L5D L5C M1A M2E L4L W3V */
196 "\\INFB",
197 /* A3F A6F A3N A3L M6N W3N W6A */
198 "\\SSTE"};
199
200#define METHOD_ALS_CONTROL "ALSC" /* Z71A Z71V */ 164#define METHOD_ALS_CONTROL "ALSC" /* Z71A Z71V */
201#define METHOD_ALS_LEVEL "ALSL" /* Z71A Z71V */ 165#define METHOD_ALS_LEVEL "ALSL" /* Z71A Z71V */
202 166
@@ -246,7 +210,6 @@ struct asus_laptop {
246 210
247 int wireless_status; 211 int wireless_status;
248 bool have_rsts; 212 bool have_rsts;
249 int lcd_state;
250 213
251 struct rfkill *gps_rfkill; 214 struct rfkill *gps_rfkill;
252 215
@@ -559,48 +522,6 @@ error:
559/* 522/*
560 * Backlight device 523 * Backlight device
561 */ 524 */
562static int asus_lcd_status(struct asus_laptop *asus)
563{
564 return asus->lcd_state;
565}
566
567static int asus_lcd_set(struct asus_laptop *asus, int value)
568{
569 int lcd = 0;
570 acpi_status status = 0;
571
572 lcd = !!value;
573
574 if (lcd == asus_lcd_status(asus))
575 return 0;
576
577 if (!lcd_switch_handle)
578 return -ENODEV;
579
580 status = acpi_evaluate_object(lcd_switch_handle,
581 NULL, NULL, NULL);
582
583 if (ACPI_FAILURE(status)) {
584 pr_warning("Error switching LCD\n");
585 return -ENODEV;
586 }
587
588 asus->lcd_state = lcd;
589 return 0;
590}
591
592static void lcd_blank(struct asus_laptop *asus, int blank)
593{
594 struct backlight_device *bd = asus->backlight_device;
595
596 asus->lcd_state = (blank == FB_BLANK_UNBLANK);
597
598 if (bd) {
599 bd->props.power = blank;
600 backlight_update_status(bd);
601 }
602}
603
604static int asus_read_brightness(struct backlight_device *bd) 525static int asus_read_brightness(struct backlight_device *bd)
605{ 526{
606 struct asus_laptop *asus = bl_get_data(bd); 527 struct asus_laptop *asus = bl_get_data(bd);
@@ -628,16 +549,9 @@ static int asus_set_brightness(struct backlight_device *bd, int value)
628 549
629static int update_bl_status(struct backlight_device *bd) 550static int update_bl_status(struct backlight_device *bd)
630{ 551{
631 struct asus_laptop *asus = bl_get_data(bd);
632 int rv;
633 int value = bd->props.brightness; 552 int value = bd->props.brightness;
634 553
635 rv = asus_set_brightness(bd, value); 554 return asus_set_brightness(bd, value);
636 if (rv)
637 return rv;
638
639 value = (bd->props.power == FB_BLANK_UNBLANK) ? 1 : 0;
640 return asus_lcd_set(asus, value);
641} 555}
642 556
643static const struct backlight_ops asusbl_ops = { 557static const struct backlight_ops asusbl_ops = {
@@ -661,8 +575,7 @@ static int asus_backlight_init(struct asus_laptop *asus)
661 struct backlight_properties props; 575 struct backlight_properties props;
662 576
663 if (acpi_check_handle(asus->handle, METHOD_BRIGHTNESS_GET, NULL) || 577 if (acpi_check_handle(asus->handle, METHOD_BRIGHTNESS_GET, NULL) ||
664 acpi_check_handle(asus->handle, METHOD_BRIGHTNESS_SET, NULL) || 578 acpi_check_handle(asus->handle, METHOD_BRIGHTNESS_SET, NULL))
665 !lcd_switch_handle)
666 return 0; 579 return 0;
667 580
668 memset(&props, 0, sizeof(struct backlight_properties)); 581 memset(&props, 0, sizeof(struct backlight_properties));
@@ -971,41 +884,6 @@ static void asus_set_display(struct asus_laptop *asus, int value)
971 return; 884 return;
972} 885}
973 886
974static int read_display(struct asus_laptop *asus)
975{
976 unsigned long long value = 0;
977 acpi_status rv = AE_OK;
978
979 /*
980 * In most of the case, we know how to set the display, but sometime
981 * we can't read it
982 */
983 if (display_get_handle) {
984 rv = acpi_evaluate_integer(display_get_handle, NULL,
985 NULL, &value);
986 if (ACPI_FAILURE(rv))
987 pr_warning("Error reading display status\n");
988 }
989
990 value &= 0x0F; /* needed for some models, shouldn't hurt others */
991
992 return value;
993}
994
995/*
996 * Now, *this* one could be more user-friendly, but so far, no-one has
997 * complained. The significance of bits is the same as in store_disp()
998 */
999static ssize_t show_disp(struct device *dev,
1000 struct device_attribute *attr, char *buf)
1001{
1002 struct asus_laptop *asus = dev_get_drvdata(dev);
1003
1004 if (!display_get_handle)
1005 return -ENODEV;
1006 return sprintf(buf, "%d\n", read_display(asus));
1007}
1008
1009/* 887/*
1010 * Experimental support for display switching. As of now: 1 should activate 888 * Experimental support for display switching. As of now: 1 should activate
1011 * the LCD output, 2 should do for CRT, 4 for TV-Out and 8 for DVI. 889 * the LCD output, 2 should do for CRT, 4 for TV-Out and 8 for DVI.
@@ -1247,15 +1125,6 @@ static void asus_acpi_notify(struct acpi_device *device, u32 event)
1247 struct asus_laptop *asus = acpi_driver_data(device); 1125 struct asus_laptop *asus = acpi_driver_data(device);
1248 u16 count; 1126 u16 count;
1249 1127
1250 /*
1251 * We need to tell the backlight device when the backlight power is
1252 * switched
1253 */
1254 if (event == ATKD_LCD_ON)
1255 lcd_blank(asus, FB_BLANK_UNBLANK);
1256 else if (event == ATKD_LCD_OFF)
1257 lcd_blank(asus, FB_BLANK_POWERDOWN);
1258
1259 /* TODO Find a better way to handle events count. */ 1128 /* TODO Find a better way to handle events count. */
1260 count = asus->event_count[event % 128]++; 1129 count = asus->event_count[event % 128]++;
1261 acpi_bus_generate_proc_event(asus->device, event, count); 1130 acpi_bus_generate_proc_event(asus->device, event, count);
@@ -1282,7 +1151,7 @@ static DEVICE_ATTR(bluetooth, S_IRUGO | S_IWUSR,
1282 show_bluetooth, store_bluetooth); 1151 show_bluetooth, store_bluetooth);
1283static DEVICE_ATTR(wimax, S_IRUGO | S_IWUSR, show_wimax, store_wimax); 1152static DEVICE_ATTR(wimax, S_IRUGO | S_IWUSR, show_wimax, store_wimax);
1284static DEVICE_ATTR(wwan, S_IRUGO | S_IWUSR, show_wwan, store_wwan); 1153static DEVICE_ATTR(wwan, S_IRUGO | S_IWUSR, show_wwan, store_wwan);
1285static DEVICE_ATTR(display, S_IRUGO | S_IWUSR, show_disp, store_disp); 1154static DEVICE_ATTR(display, S_IWUSR, NULL, store_disp);
1286static DEVICE_ATTR(ledd, S_IRUGO | S_IWUSR, show_ledd, store_ledd); 1155static DEVICE_ATTR(ledd, S_IRUGO | S_IWUSR, show_ledd, store_ledd);
1287static DEVICE_ATTR(ls_level, S_IRUGO | S_IWUSR, show_lslvl, store_lslvl); 1156static DEVICE_ATTR(ls_level, S_IRUGO | S_IWUSR, show_lslvl, store_lslvl);
1288static DEVICE_ATTR(ls_switch, S_IRUGO | S_IWUSR, show_lssw, store_lssw); 1157static DEVICE_ATTR(ls_switch, S_IRUGO | S_IWUSR, show_lssw, store_lssw);
@@ -1393,26 +1262,6 @@ static struct platform_driver platform_driver = {
1393 } 1262 }
1394}; 1263};
1395 1264
1396static int asus_handle_init(char *name, acpi_handle * handle,
1397 char **paths, int num_paths)
1398{
1399 int i;
1400 acpi_status status;
1401
1402 for (i = 0; i < num_paths; i++) {
1403 status = acpi_get_handle(NULL, paths[i], handle);
1404 if (ACPI_SUCCESS(status))
1405 return 0;
1406 }
1407
1408 *handle = NULL;
1409 return -ENODEV;
1410}
1411
1412#define ASUS_HANDLE_INIT(object) \
1413 asus_handle_init(#object, &object##_handle, object##_paths, \
1414 ARRAY_SIZE(object##_paths))
1415
1416/* 1265/*
1417 * This function is used to initialize the context with right values. In this 1266 * This function is used to initialize the context with right values. In this
1418 * method, we can make all the detection we want, and modify the asus_laptop 1267 * method, we can make all the detection we want, and modify the asus_laptop
@@ -1498,10 +1347,6 @@ static int asus_laptop_get_info(struct asus_laptop *asus)
1498 if (!acpi_check_handle(asus->handle, METHOD_WL_STATUS, NULL)) 1347 if (!acpi_check_handle(asus->handle, METHOD_WL_STATUS, NULL))
1499 asus->have_rsts = true; 1348 asus->have_rsts = true;
1500 1349
1501 /* Scheduled for removal */
1502 ASUS_HANDLE_INIT(lcd_switch);
1503 ASUS_HANDLE_INIT(display_get);
1504
1505 kfree(model); 1350 kfree(model);
1506 1351
1507 return AE_OK; 1352 return AE_OK;
@@ -1553,10 +1398,23 @@ static int __devinit asus_acpi_init(struct asus_laptop *asus)
1553 asus_als_level(asus, asus->light_level); 1398 asus_als_level(asus, asus->light_level);
1554 } 1399 }
1555 1400
1556 asus->lcd_state = 1; /* LCD should be on when the module load */
1557 return result; 1401 return result;
1558} 1402}
1559 1403
1404static void __devinit asus_dmi_check(void)
1405{
1406 const char *model;
1407
1408 model = dmi_get_system_info(DMI_PRODUCT_NAME);
1409 if (!model)
1410 return;
1411
1412 /* On L1400B WLED control the sound card, don't mess with it ... */
1413 if (strncmp(model, "L1400B", 6) == 0) {
1414 wlan_status = -1;
1415 }
1416}
1417
1560static bool asus_device_present; 1418static bool asus_device_present;
1561 1419
1562static int __devinit asus_acpi_add(struct acpi_device *device) 1420static int __devinit asus_acpi_add(struct acpi_device *device)
@@ -1575,6 +1433,8 @@ static int __devinit asus_acpi_add(struct acpi_device *device)
1575 device->driver_data = asus; 1433 device->driver_data = asus;
1576 asus->device = device; 1434 asus->device = device;
1577 1435
1436 asus_dmi_check();
1437
1578 result = asus_acpi_init(asus); 1438 result = asus_acpi_init(asus);
1579 if (result) 1439 if (result)
1580 goto fail_platform; 1440 goto fail_platform;
diff --git a/drivers/platform/x86/asus-nb-wmi.c b/drivers/platform/x86/asus-nb-wmi.c
new file mode 100644
index 000000000000..0580d99b0798
--- /dev/null
+++ b/drivers/platform/x86/asus-nb-wmi.c
@@ -0,0 +1,98 @@
1/*
2 * Asus Notebooks WMI hotkey driver
3 *
4 * Copyright(C) 2010 Corentin Chary <corentin.chary@gmail.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
22
23#include <linux/kernel.h>
24#include <linux/module.h>
25#include <linux/init.h>
26#include <linux/input.h>
27#include <linux/input/sparse-keymap.h>
28
29#include "asus-wmi.h"
30
31#define ASUS_NB_WMI_FILE "asus-nb-wmi"
32
33MODULE_AUTHOR("Corentin Chary <corentincj@iksaif.net>");
34MODULE_DESCRIPTION("Asus Notebooks WMI Hotkey Driver");
35MODULE_LICENSE("GPL");
36
37#define ASUS_NB_WMI_EVENT_GUID "0B3CBB35-E3C2-45ED-91C2-4C5A6D195D1C"
38
39MODULE_ALIAS("wmi:"ASUS_NB_WMI_EVENT_GUID);
40
41static const struct key_entry asus_nb_wmi_keymap[] = {
42 { KE_KEY, 0x30, { KEY_VOLUMEUP } },
43 { KE_KEY, 0x31, { KEY_VOLUMEDOWN } },
44 { KE_KEY, 0x32, { KEY_MUTE } },
45 { KE_KEY, 0x33, { KEY_DISPLAYTOGGLE } }, /* LCD on */
46 { KE_KEY, 0x34, { KEY_DISPLAY_OFF } }, /* LCD off */
47 { KE_KEY, 0x40, { KEY_PREVIOUSSONG } },
48 { KE_KEY, 0x41, { KEY_NEXTSONG } },
49 { KE_KEY, 0x43, { KEY_STOPCD } },
50 { KE_KEY, 0x45, { KEY_PLAYPAUSE } },
51 { KE_KEY, 0x4c, { KEY_MEDIA } },
52 { KE_KEY, 0x50, { KEY_EMAIL } },
53 { KE_KEY, 0x51, { KEY_WWW } },
54 { KE_KEY, 0x55, { KEY_CALC } },
55 { KE_KEY, 0x5C, { KEY_F15 } }, /* Power Gear key */
56 { KE_KEY, 0x5D, { KEY_WLAN } },
57 { KE_KEY, 0x5E, { KEY_WLAN } },
58 { KE_KEY, 0x5F, { KEY_WLAN } },
59 { KE_KEY, 0x60, { KEY_SWITCHVIDEOMODE } },
60 { KE_KEY, 0x61, { KEY_SWITCHVIDEOMODE } },
61 { KE_KEY, 0x62, { KEY_SWITCHVIDEOMODE } },
62 { KE_KEY, 0x63, { KEY_SWITCHVIDEOMODE } },
63 { KE_KEY, 0x6B, { KEY_TOUCHPAD_TOGGLE } },
64 { KE_KEY, 0x7E, { KEY_BLUETOOTH } },
65 { KE_KEY, 0x7D, { KEY_BLUETOOTH } },
66 { KE_KEY, 0x82, { KEY_CAMERA } },
67 { KE_KEY, 0x88, { KEY_RFKILL } },
68 { KE_KEY, 0x8A, { KEY_PROG1 } },
69 { KE_KEY, 0x95, { KEY_MEDIA } },
70 { KE_KEY, 0x99, { KEY_PHONE } },
71 { KE_KEY, 0xb5, { KEY_CALC } },
72 { KE_KEY, 0xc4, { KEY_KBDILLUMUP } },
73 { KE_KEY, 0xc5, { KEY_KBDILLUMDOWN } },
74 { KE_END, 0},
75};
76
77static struct asus_wmi_driver asus_nb_wmi_driver = {
78 .name = ASUS_NB_WMI_FILE,
79 .owner = THIS_MODULE,
80 .event_guid = ASUS_NB_WMI_EVENT_GUID,
81 .keymap = asus_nb_wmi_keymap,
82 .input_name = "Asus WMI hotkeys",
83 .input_phys = ASUS_NB_WMI_FILE "/input0",
84};
85
86
87static int __init asus_nb_wmi_init(void)
88{
89 return asus_wmi_register_driver(&asus_nb_wmi_driver);
90}
91
92static void __exit asus_nb_wmi_exit(void)
93{
94 asus_wmi_unregister_driver(&asus_nb_wmi_driver);
95}
96
97module_init(asus_nb_wmi_init);
98module_exit(asus_nb_wmi_exit);
diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c
new file mode 100644
index 000000000000..efc776cb0c66
--- /dev/null
+++ b/drivers/platform/x86/asus-wmi.c
@@ -0,0 +1,1656 @@
1/*
2 * Asus PC WMI hotkey driver
3 *
4 * Copyright(C) 2010 Intel Corporation.
5 * Copyright(C) 2010-2011 Corentin Chary <corentin.chary@gmail.com>
6 *
7 * Portions based on wistron_btns.c:
8 * Copyright (C) 2005 Miloslav Trmac <mitr@volny.cz>
9 * Copyright (C) 2005 Bernhard Rosenkraenzer <bero@arklinux.org>
10 * Copyright (C) 2005 Dmitry Torokhov <dtor@mail.ru>
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 */
26
27#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
28
29#include <linux/kernel.h>
30#include <linux/module.h>
31#include <linux/init.h>
32#include <linux/types.h>
33#include <linux/slab.h>
34#include <linux/input.h>
35#include <linux/input/sparse-keymap.h>
36#include <linux/fb.h>
37#include <linux/backlight.h>
38#include <linux/leds.h>
39#include <linux/rfkill.h>
40#include <linux/pci.h>
41#include <linux/pci_hotplug.h>
42#include <linux/hwmon.h>
43#include <linux/hwmon-sysfs.h>
44#include <linux/debugfs.h>
45#include <linux/seq_file.h>
46#include <linux/platform_device.h>
47#include <acpi/acpi_bus.h>
48#include <acpi/acpi_drivers.h>
49
50#include "asus-wmi.h"
51
52MODULE_AUTHOR("Corentin Chary <corentincj@iksaif.net>, "
53 "Yong Wang <yong.y.wang@intel.com>");
54MODULE_DESCRIPTION("Asus Generic WMI Driver");
55MODULE_LICENSE("GPL");
56
57#define to_platform_driver(drv) \
58 (container_of((drv), struct platform_driver, driver))
59
60#define to_asus_wmi_driver(pdrv) \
61 (container_of((pdrv), struct asus_wmi_driver, platform_driver))
62
63#define ASUS_WMI_MGMT_GUID "97845ED0-4E6D-11DE-8A39-0800200C9A66"
64
65#define NOTIFY_BRNUP_MIN 0x11
66#define NOTIFY_BRNUP_MAX 0x1f
67#define NOTIFY_BRNDOWN_MIN 0x20
68#define NOTIFY_BRNDOWN_MAX 0x2e
69
70/* WMI Methods */
71#define ASUS_WMI_METHODID_SPEC 0x43455053 /* BIOS SPECification */
72#define ASUS_WMI_METHODID_SFBD 0x44424653 /* Set First Boot Device */
73#define ASUS_WMI_METHODID_GLCD 0x44434C47 /* Get LCD status */
74#define ASUS_WMI_METHODID_GPID 0x44495047 /* Get Panel ID?? (Resol) */
75#define ASUS_WMI_METHODID_QMOD 0x444F4D51 /* Quiet MODe */
76#define ASUS_WMI_METHODID_SPLV 0x4C425053 /* Set Panel Light Value */
77#define ASUS_WMI_METHODID_SFUN 0x4E554653 /* FUNCtionalities */
78#define ASUS_WMI_METHODID_SDSP 0x50534453 /* Set DiSPlay output */
79#define ASUS_WMI_METHODID_GDSP 0x50534447 /* Get DiSPlay output */
80#define ASUS_WMI_METHODID_DEVP 0x50564544 /* DEVice Policy */
81#define ASUS_WMI_METHODID_OSVR 0x5256534F /* OS VeRsion */
82#define ASUS_WMI_METHODID_DSTS 0x53544344 /* Device STatuS */
83#define ASUS_WMI_METHODID_DSTS2 0x53545344 /* Device STatuS #2*/
84#define ASUS_WMI_METHODID_BSTS 0x53545342 /* Bios STatuS ? */
85#define ASUS_WMI_METHODID_DEVS 0x53564544 /* DEVice Set */
86#define ASUS_WMI_METHODID_CFVS 0x53564643 /* CPU Frequency Volt Set */
87#define ASUS_WMI_METHODID_KBFT 0x5446424B /* KeyBoard FilTer */
88#define ASUS_WMI_METHODID_INIT 0x54494E49 /* INITialize */
89#define ASUS_WMI_METHODID_HKEY 0x59454B48 /* Hot KEY ?? */
90
91#define ASUS_WMI_UNSUPPORTED_METHOD 0xFFFFFFFE
92
93/* Wireless */
94#define ASUS_WMI_DEVID_HW_SWITCH 0x00010001
95#define ASUS_WMI_DEVID_WIRELESS_LED 0x00010002
96#define ASUS_WMI_DEVID_WLAN 0x00010011
97#define ASUS_WMI_DEVID_BLUETOOTH 0x00010013
98#define ASUS_WMI_DEVID_GPS 0x00010015
99#define ASUS_WMI_DEVID_WIMAX 0x00010017
100#define ASUS_WMI_DEVID_WWAN3G 0x00010019
101#define ASUS_WMI_DEVID_UWB 0x00010021
102
103/* Leds */
104/* 0x000200XX and 0x000400XX */
105
106/* Backlight and Brightness */
107#define ASUS_WMI_DEVID_BACKLIGHT 0x00050011
108#define ASUS_WMI_DEVID_BRIGHTNESS 0x00050012
109#define ASUS_WMI_DEVID_KBD_BACKLIGHT 0x00050021
110#define ASUS_WMI_DEVID_LIGHT_SENSOR 0x00050022 /* ?? */
111
112/* Misc */
113#define ASUS_WMI_DEVID_CAMERA 0x00060013
114
115/* Storage */
116#define ASUS_WMI_DEVID_CARDREADER 0x00080013
117
118/* Input */
119#define ASUS_WMI_DEVID_TOUCHPAD 0x00100011
120#define ASUS_WMI_DEVID_TOUCHPAD_LED 0x00100012
121
122/* Fan, Thermal */
123#define ASUS_WMI_DEVID_THERMAL_CTRL 0x00110011
124#define ASUS_WMI_DEVID_FAN_CTRL 0x00110012
125
126/* Power */
127#define ASUS_WMI_DEVID_PROCESSOR_STATE 0x00120012
128
129/* DSTS masks */
130#define ASUS_WMI_DSTS_STATUS_BIT 0x00000001
131#define ASUS_WMI_DSTS_UNKNOWN_BIT 0x00000002
132#define ASUS_WMI_DSTS_PRESENCE_BIT 0x00010000
133#define ASUS_WMI_DSTS_USER_BIT 0x00020000
134#define ASUS_WMI_DSTS_BIOS_BIT 0x00040000
135#define ASUS_WMI_DSTS_BRIGHTNESS_MASK 0x000000FF
136#define ASUS_WMI_DSTS_MAX_BRIGTH_MASK 0x0000FF00
137
138struct bios_args {
139 u32 arg0;
140 u32 arg1;
141} __packed;
142
143/*
144 * <platform>/ - debugfs root directory
145 * dev_id - current dev_id
146 * ctrl_param - current ctrl_param
147 * method_id - current method_id
148 * devs - call DEVS(dev_id, ctrl_param) and print result
149 * dsts - call DSTS(dev_id) and print result
150 * call - call method_id(dev_id, ctrl_param) and print result
151 */
152struct asus_wmi_debug {
153 struct dentry *root;
154 u32 method_id;
155 u32 dev_id;
156 u32 ctrl_param;
157};
158
159struct asus_rfkill {
160 struct asus_wmi *asus;
161 struct rfkill *rfkill;
162 u32 dev_id;
163};
164
165struct asus_wmi {
166 int dsts_id;
167 int spec;
168 int sfun;
169
170 struct input_dev *inputdev;
171 struct backlight_device *backlight_device;
172 struct device *hwmon_device;
173 struct platform_device *platform_device;
174
175 struct led_classdev tpd_led;
176 int tpd_led_wk;
177 struct workqueue_struct *led_workqueue;
178 struct work_struct tpd_led_work;
179
180 struct asus_rfkill wlan;
181 struct asus_rfkill bluetooth;
182 struct asus_rfkill wimax;
183 struct asus_rfkill wwan3g;
184
185 struct hotplug_slot *hotplug_slot;
186 struct mutex hotplug_lock;
187 struct mutex wmi_lock;
188 struct workqueue_struct *hotplug_workqueue;
189 struct work_struct hotplug_work;
190
191 struct asus_wmi_debug debug;
192
193 struct asus_wmi_driver *driver;
194};
195
196static int asus_wmi_input_init(struct asus_wmi *asus)
197{
198 int err;
199
200 asus->inputdev = input_allocate_device();
201 if (!asus->inputdev)
202 return -ENOMEM;
203
204 asus->inputdev->name = asus->driver->input_phys;
205 asus->inputdev->phys = asus->driver->input_name;
206 asus->inputdev->id.bustype = BUS_HOST;
207 asus->inputdev->dev.parent = &asus->platform_device->dev;
208
209 err = sparse_keymap_setup(asus->inputdev, asus->driver->keymap, NULL);
210 if (err)
211 goto err_free_dev;
212
213 err = input_register_device(asus->inputdev);
214 if (err)
215 goto err_free_keymap;
216
217 return 0;
218
219err_free_keymap:
220 sparse_keymap_free(asus->inputdev);
221err_free_dev:
222 input_free_device(asus->inputdev);
223 return err;
224}
225
226static void asus_wmi_input_exit(struct asus_wmi *asus)
227{
228 if (asus->inputdev) {
229 sparse_keymap_free(asus->inputdev);
230 input_unregister_device(asus->inputdev);
231 }
232
233 asus->inputdev = NULL;
234}
235
236static int asus_wmi_evaluate_method(u32 method_id, u32 arg0, u32 arg1,
237 u32 *retval)
238{
239 struct bios_args args = {
240 .arg0 = arg0,
241 .arg1 = arg1,
242 };
243 struct acpi_buffer input = { (acpi_size) sizeof(args), &args };
244 struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
245 acpi_status status;
246 union acpi_object *obj;
247 u32 tmp;
248
249 status = wmi_evaluate_method(ASUS_WMI_MGMT_GUID, 1, method_id,
250 &input, &output);
251
252 if (ACPI_FAILURE(status))
253 goto exit;
254
255 obj = (union acpi_object *)output.pointer;
256 if (obj && obj->type == ACPI_TYPE_INTEGER)
257 tmp = (u32) obj->integer.value;
258 else
259 tmp = 0;
260
261 if (retval)
262 *retval = tmp;
263
264 kfree(obj);
265
266exit:
267 if (ACPI_FAILURE(status))
268 return -EIO;
269
270 if (tmp == ASUS_WMI_UNSUPPORTED_METHOD)
271 return -ENODEV;
272
273 return 0;
274}
275
276static int asus_wmi_get_devstate(struct asus_wmi *asus, u32 dev_id, u32 *retval)
277{
278 return asus_wmi_evaluate_method(asus->dsts_id, dev_id, 0, retval);
279}
280
281static int asus_wmi_set_devstate(u32 dev_id, u32 ctrl_param,
282 u32 *retval)
283{
284 return asus_wmi_evaluate_method(ASUS_WMI_METHODID_DEVS, dev_id,
285 ctrl_param, retval);
286}
287
288/* Helper for special devices with magic return codes */
289static int asus_wmi_get_devstate_bits(struct asus_wmi *asus,
290 u32 dev_id, u32 mask)
291{
292 u32 retval = 0;
293 int err;
294
295 err = asus_wmi_get_devstate(asus, dev_id, &retval);
296
297 if (err < 0)
298 return err;
299
300 if (!(retval & ASUS_WMI_DSTS_PRESENCE_BIT))
301 return -ENODEV;
302
303 if (mask == ASUS_WMI_DSTS_STATUS_BIT) {
304 if (retval & ASUS_WMI_DSTS_UNKNOWN_BIT)
305 return -ENODEV;
306 }
307
308 return retval & mask;
309}
310
311static int asus_wmi_get_devstate_simple(struct asus_wmi *asus, u32 dev_id)
312{
313 return asus_wmi_get_devstate_bits(asus, dev_id,
314 ASUS_WMI_DSTS_STATUS_BIT);
315}
316
317/*
318 * LEDs
319 */
320/*
321 * These functions actually update the LED's, and are called from a
322 * workqueue. By doing this as separate work rather than when the LED
323 * subsystem asks, we avoid messing with the Asus ACPI stuff during a
324 * potentially bad time, such as a timer interrupt.
325 */
326static void tpd_led_update(struct work_struct *work)
327{
328 int ctrl_param;
329 struct asus_wmi *asus;
330
331 asus = container_of(work, struct asus_wmi, tpd_led_work);
332
333 ctrl_param = asus->tpd_led_wk;
334 asus_wmi_set_devstate(ASUS_WMI_DEVID_TOUCHPAD_LED, ctrl_param, NULL);
335}
336
337static void tpd_led_set(struct led_classdev *led_cdev,
338 enum led_brightness value)
339{
340 struct asus_wmi *asus;
341
342 asus = container_of(led_cdev, struct asus_wmi, tpd_led);
343
344 asus->tpd_led_wk = !!value;
345 queue_work(asus->led_workqueue, &asus->tpd_led_work);
346}
347
348static int read_tpd_led_state(struct asus_wmi *asus)
349{
350 return asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_TOUCHPAD_LED);
351}
352
353static enum led_brightness tpd_led_get(struct led_classdev *led_cdev)
354{
355 struct asus_wmi *asus;
356
357 asus = container_of(led_cdev, struct asus_wmi, tpd_led);
358
359 return read_tpd_led_state(asus);
360}
361
362static int asus_wmi_led_init(struct asus_wmi *asus)
363{
364 int rv;
365
366 if (read_tpd_led_state(asus) < 0)
367 return 0;
368
369 asus->led_workqueue = create_singlethread_workqueue("led_workqueue");
370 if (!asus->led_workqueue)
371 return -ENOMEM;
372 INIT_WORK(&asus->tpd_led_work, tpd_led_update);
373
374 asus->tpd_led.name = "asus::touchpad";
375 asus->tpd_led.brightness_set = tpd_led_set;
376 asus->tpd_led.brightness_get = tpd_led_get;
377 asus->tpd_led.max_brightness = 1;
378
379 rv = led_classdev_register(&asus->platform_device->dev, &asus->tpd_led);
380 if (rv) {
381 destroy_workqueue(asus->led_workqueue);
382 return rv;
383 }
384
385 return 0;
386}
387
388static void asus_wmi_led_exit(struct asus_wmi *asus)
389{
390 if (asus->tpd_led.dev)
391 led_classdev_unregister(&asus->tpd_led);
392 if (asus->led_workqueue)
393 destroy_workqueue(asus->led_workqueue);
394}
395
396/*
397 * PCI hotplug (for wlan rfkill)
398 */
399static bool asus_wlan_rfkill_blocked(struct asus_wmi *asus)
400{
401 int result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_WLAN);
402
403 if (result < 0)
404 return false;
405 return !result;
406}
407
408static void asus_rfkill_hotplug(struct asus_wmi *asus)
409{
410 struct pci_dev *dev;
411 struct pci_bus *bus;
412 bool blocked;
413 bool absent;
414 u32 l;
415
416 mutex_lock(&asus->wmi_lock);
417 blocked = asus_wlan_rfkill_blocked(asus);
418 mutex_unlock(&asus->wmi_lock);
419
420 mutex_lock(&asus->hotplug_lock);
421
422 if (asus->wlan.rfkill)
423 rfkill_set_sw_state(asus->wlan.rfkill, blocked);
424
425 if (asus->hotplug_slot) {
426 bus = pci_find_bus(0, 1);
427 if (!bus) {
428 pr_warning("Unable to find PCI bus 1?\n");
429 goto out_unlock;
430 }
431
432 if (pci_bus_read_config_dword(bus, 0, PCI_VENDOR_ID, &l)) {
433 pr_err("Unable to read PCI config space?\n");
434 goto out_unlock;
435 }
436 absent = (l == 0xffffffff);
437
438 if (blocked != absent) {
439 pr_warning("BIOS says wireless lan is %s, "
440 "but the pci device is %s\n",
441 blocked ? "blocked" : "unblocked",
442 absent ? "absent" : "present");
443 pr_warning("skipped wireless hotplug as probably "
444 "inappropriate for this model\n");
445 goto out_unlock;
446 }
447
448 if (!blocked) {
449 dev = pci_get_slot(bus, 0);
450 if (dev) {
451 /* Device already present */
452 pci_dev_put(dev);
453 goto out_unlock;
454 }
455 dev = pci_scan_single_device(bus, 0);
456 if (dev) {
457 pci_bus_assign_resources(bus);
458 if (pci_bus_add_device(dev))
459 pr_err("Unable to hotplug wifi\n");
460 }
461 } else {
462 dev = pci_get_slot(bus, 0);
463 if (dev) {
464 pci_remove_bus_device(dev);
465 pci_dev_put(dev);
466 }
467 }
468 }
469
470out_unlock:
471 mutex_unlock(&asus->hotplug_lock);
472}
473
474static void asus_rfkill_notify(acpi_handle handle, u32 event, void *data)
475{
476 struct asus_wmi *asus = data;
477
478 if (event != ACPI_NOTIFY_BUS_CHECK)
479 return;
480
481 /*
482 * We can't call directly asus_rfkill_hotplug because most
483 * of the time WMBC is still being executed and not reetrant.
484 * There is currently no way to tell ACPICA that we want this
485 * method to be serialized, we schedule a asus_rfkill_hotplug
486 * call later, in a safer context.
487 */
488 queue_work(asus->hotplug_workqueue, &asus->hotplug_work);
489}
490
491static int asus_register_rfkill_notifier(struct asus_wmi *asus, char *node)
492{
493 acpi_status status;
494 acpi_handle handle;
495
496 status = acpi_get_handle(NULL, node, &handle);
497
498 if (ACPI_SUCCESS(status)) {
499 status = acpi_install_notify_handler(handle,
500 ACPI_SYSTEM_NOTIFY,
501 asus_rfkill_notify, asus);
502 if (ACPI_FAILURE(status))
503 pr_warning("Failed to register notify on %s\n", node);
504 } else
505 return -ENODEV;
506
507 return 0;
508}
509
510static void asus_unregister_rfkill_notifier(struct asus_wmi *asus, char *node)
511{
512 acpi_status status = AE_OK;
513 acpi_handle handle;
514
515 status = acpi_get_handle(NULL, node, &handle);
516
517 if (ACPI_SUCCESS(status)) {
518 status = acpi_remove_notify_handler(handle,
519 ACPI_SYSTEM_NOTIFY,
520 asus_rfkill_notify);
521 if (ACPI_FAILURE(status))
522 pr_err("Error removing rfkill notify handler %s\n",
523 node);
524 }
525}
526
527static int asus_get_adapter_status(struct hotplug_slot *hotplug_slot,
528 u8 *value)
529{
530 struct asus_wmi *asus = hotplug_slot->private;
531 int result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_WLAN);
532
533 if (result < 0)
534 return result;
535
536 *value = !!result;
537 return 0;
538}
539
540static void asus_cleanup_pci_hotplug(struct hotplug_slot *hotplug_slot)
541{
542 kfree(hotplug_slot->info);
543 kfree(hotplug_slot);
544}
545
546static struct hotplug_slot_ops asus_hotplug_slot_ops = {
547 .owner = THIS_MODULE,
548 .get_adapter_status = asus_get_adapter_status,
549 .get_power_status = asus_get_adapter_status,
550};
551
552static void asus_hotplug_work(struct work_struct *work)
553{
554 struct asus_wmi *asus;
555
556 asus = container_of(work, struct asus_wmi, hotplug_work);
557 asus_rfkill_hotplug(asus);
558}
559
560static int asus_setup_pci_hotplug(struct asus_wmi *asus)
561{
562 int ret = -ENOMEM;
563 struct pci_bus *bus = pci_find_bus(0, 1);
564
565 if (!bus) {
566 pr_err("Unable to find wifi PCI bus\n");
567 return -ENODEV;
568 }
569
570 asus->hotplug_workqueue =
571 create_singlethread_workqueue("hotplug_workqueue");
572 if (!asus->hotplug_workqueue)
573 goto error_workqueue;
574
575 INIT_WORK(&asus->hotplug_work, asus_hotplug_work);
576
577 asus->hotplug_slot = kzalloc(sizeof(struct hotplug_slot), GFP_KERNEL);
578 if (!asus->hotplug_slot)
579 goto error_slot;
580
581 asus->hotplug_slot->info = kzalloc(sizeof(struct hotplug_slot_info),
582 GFP_KERNEL);
583 if (!asus->hotplug_slot->info)
584 goto error_info;
585
586 asus->hotplug_slot->private = asus;
587 asus->hotplug_slot->release = &asus_cleanup_pci_hotplug;
588 asus->hotplug_slot->ops = &asus_hotplug_slot_ops;
589 asus_get_adapter_status(asus->hotplug_slot,
590 &asus->hotplug_slot->info->adapter_status);
591
592 ret = pci_hp_register(asus->hotplug_slot, bus, 0, "asus-wifi");
593 if (ret) {
594 pr_err("Unable to register hotplug slot - %d\n", ret);
595 goto error_register;
596 }
597
598 return 0;
599
600error_register:
601 kfree(asus->hotplug_slot->info);
602error_info:
603 kfree(asus->hotplug_slot);
604 asus->hotplug_slot = NULL;
605error_slot:
606 destroy_workqueue(asus->hotplug_workqueue);
607error_workqueue:
608 return ret;
609}
610
611/*
612 * Rfkill devices
613 */
614static int asus_rfkill_set(void *data, bool blocked)
615{
616 struct asus_rfkill *priv = data;
617 u32 ctrl_param = !blocked;
618
619 return asus_wmi_set_devstate(priv->dev_id, ctrl_param, NULL);
620}
621
622static void asus_rfkill_query(struct rfkill *rfkill, void *data)
623{
624 struct asus_rfkill *priv = data;
625 int result;
626
627 result = asus_wmi_get_devstate_simple(priv->asus, priv->dev_id);
628
629 if (result < 0)
630 return;
631
632 rfkill_set_sw_state(priv->rfkill, !result);
633}
634
635static int asus_rfkill_wlan_set(void *data, bool blocked)
636{
637 struct asus_rfkill *priv = data;
638 struct asus_wmi *asus = priv->asus;
639 int ret;
640
641 /*
642 * This handler is enabled only if hotplug is enabled.
643 * In this case, the asus_wmi_set_devstate() will
644 * trigger a wmi notification and we need to wait
645 * this call to finish before being able to call
646 * any wmi method
647 */
648 mutex_lock(&asus->wmi_lock);
649 ret = asus_rfkill_set(data, blocked);
650 mutex_unlock(&asus->wmi_lock);
651 return ret;
652}
653
654static const struct rfkill_ops asus_rfkill_wlan_ops = {
655 .set_block = asus_rfkill_wlan_set,
656 .query = asus_rfkill_query,
657};
658
659static const struct rfkill_ops asus_rfkill_ops = {
660 .set_block = asus_rfkill_set,
661 .query = asus_rfkill_query,
662};
663
664static int asus_new_rfkill(struct asus_wmi *asus,
665 struct asus_rfkill *arfkill,
666 const char *name, enum rfkill_type type, int dev_id)
667{
668 int result = asus_wmi_get_devstate_simple(asus, dev_id);
669 struct rfkill **rfkill = &arfkill->rfkill;
670
671 if (result < 0)
672 return result;
673
674 arfkill->dev_id = dev_id;
675 arfkill->asus = asus;
676
677 if (dev_id == ASUS_WMI_DEVID_WLAN && asus->driver->hotplug_wireless)
678 *rfkill = rfkill_alloc(name, &asus->platform_device->dev, type,
679 &asus_rfkill_wlan_ops, arfkill);
680 else
681 *rfkill = rfkill_alloc(name, &asus->platform_device->dev, type,
682 &asus_rfkill_ops, arfkill);
683
684 if (!*rfkill)
685 return -EINVAL;
686
687 rfkill_init_sw_state(*rfkill, !result);
688 result = rfkill_register(*rfkill);
689 if (result) {
690 rfkill_destroy(*rfkill);
691 *rfkill = NULL;
692 return result;
693 }
694 return 0;
695}
696
697static void asus_wmi_rfkill_exit(struct asus_wmi *asus)
698{
699 asus_unregister_rfkill_notifier(asus, "\\_SB.PCI0.P0P5");
700 asus_unregister_rfkill_notifier(asus, "\\_SB.PCI0.P0P6");
701 asus_unregister_rfkill_notifier(asus, "\\_SB.PCI0.P0P7");
702 if (asus->wlan.rfkill) {
703 rfkill_unregister(asus->wlan.rfkill);
704 rfkill_destroy(asus->wlan.rfkill);
705 asus->wlan.rfkill = NULL;
706 }
707 /*
708 * Refresh pci hotplug in case the rfkill state was changed after
709 * asus_unregister_rfkill_notifier()
710 */
711 asus_rfkill_hotplug(asus);
712 if (asus->hotplug_slot)
713 pci_hp_deregister(asus->hotplug_slot);
714 if (asus->hotplug_workqueue)
715 destroy_workqueue(asus->hotplug_workqueue);
716
717 if (asus->bluetooth.rfkill) {
718 rfkill_unregister(asus->bluetooth.rfkill);
719 rfkill_destroy(asus->bluetooth.rfkill);
720 asus->bluetooth.rfkill = NULL;
721 }
722 if (asus->wimax.rfkill) {
723 rfkill_unregister(asus->wimax.rfkill);
724 rfkill_destroy(asus->wimax.rfkill);
725 asus->wimax.rfkill = NULL;
726 }
727 if (asus->wwan3g.rfkill) {
728 rfkill_unregister(asus->wwan3g.rfkill);
729 rfkill_destroy(asus->wwan3g.rfkill);
730 asus->wwan3g.rfkill = NULL;
731 }
732}
733
734static int asus_wmi_rfkill_init(struct asus_wmi *asus)
735{
736 int result = 0;
737
738 mutex_init(&asus->hotplug_lock);
739 mutex_init(&asus->wmi_lock);
740
741 result = asus_new_rfkill(asus, &asus->wlan, "asus-wlan",
742 RFKILL_TYPE_WLAN, ASUS_WMI_DEVID_WLAN);
743
744 if (result && result != -ENODEV)
745 goto exit;
746
747 result = asus_new_rfkill(asus, &asus->bluetooth,
748 "asus-bluetooth", RFKILL_TYPE_BLUETOOTH,
749 ASUS_WMI_DEVID_BLUETOOTH);
750
751 if (result && result != -ENODEV)
752 goto exit;
753
754 result = asus_new_rfkill(asus, &asus->wimax, "asus-wimax",
755 RFKILL_TYPE_WIMAX, ASUS_WMI_DEVID_WIMAX);
756
757 if (result && result != -ENODEV)
758 goto exit;
759
760 result = asus_new_rfkill(asus, &asus->wwan3g, "asus-wwan3g",
761 RFKILL_TYPE_WWAN, ASUS_WMI_DEVID_WWAN3G);
762
763 if (result && result != -ENODEV)
764 goto exit;
765
766 if (!asus->driver->hotplug_wireless)
767 goto exit;
768
769 result = asus_setup_pci_hotplug(asus);
770 /*
771 * If we get -EBUSY then something else is handling the PCI hotplug -
772 * don't fail in this case
773 */
774 if (result == -EBUSY)
775 result = 0;
776
777 asus_register_rfkill_notifier(asus, "\\_SB.PCI0.P0P5");
778 asus_register_rfkill_notifier(asus, "\\_SB.PCI0.P0P6");
779 asus_register_rfkill_notifier(asus, "\\_SB.PCI0.P0P7");
780 /*
781 * Refresh pci hotplug in case the rfkill state was changed during
782 * setup.
783 */
784 asus_rfkill_hotplug(asus);
785
786exit:
787 if (result && result != -ENODEV)
788 asus_wmi_rfkill_exit(asus);
789
790 if (result == -ENODEV)
791 result = 0;
792
793 return result;
794}
795
796/*
797 * Hwmon device
798 */
799static ssize_t asus_hwmon_pwm1(struct device *dev,
800 struct device_attribute *attr,
801 char *buf)
802{
803 struct asus_wmi *asus = dev_get_drvdata(dev);
804 u32 value;
805 int err;
806
807 err = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_FAN_CTRL, &value);
808
809 if (err < 0)
810 return err;
811
812 value |= 0xFF;
813
814 if (value == 1) /* Low Speed */
815 value = 85;
816 else if (value == 2)
817 value = 170;
818 else if (value == 3)
819 value = 255;
820 else if (value != 0) {
821 pr_err("Unknown fan speed %#x", value);
822 value = -1;
823 }
824
825 return sprintf(buf, "%d\n", value);
826}
827
828static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO, asus_hwmon_pwm1, NULL, 0);
829
830static ssize_t
831show_name(struct device *dev, struct device_attribute *attr, char *buf)
832{
833 return sprintf(buf, "asus\n");
834}
835static SENSOR_DEVICE_ATTR(name, S_IRUGO, show_name, NULL, 0);
836
837static struct attribute *hwmon_attributes[] = {
838 &sensor_dev_attr_pwm1.dev_attr.attr,
839 &sensor_dev_attr_name.dev_attr.attr,
840 NULL
841};
842
843static mode_t asus_hwmon_sysfs_is_visible(struct kobject *kobj,
844 struct attribute *attr, int idx)
845{
846 struct device *dev = container_of(kobj, struct device, kobj);
847 struct platform_device *pdev = to_platform_device(dev->parent);
848 struct asus_wmi *asus = platform_get_drvdata(pdev);
849 bool ok = true;
850 int dev_id = -1;
851 u32 value = ASUS_WMI_UNSUPPORTED_METHOD;
852
853 if (attr == &sensor_dev_attr_pwm1.dev_attr.attr)
854 dev_id = ASUS_WMI_DEVID_FAN_CTRL;
855
856 if (dev_id != -1) {
857 int err = asus_wmi_get_devstate(asus, dev_id, &value);
858
859 if (err < 0)
860 return err;
861 }
862
863 if (dev_id == ASUS_WMI_DEVID_FAN_CTRL) {
864 /*
865 * We need to find a better way, probably using sfun,
866 * bits or spec ...
867 * Currently we disable it if:
868 * - ASUS_WMI_UNSUPPORTED_METHOD is returned
869 * - reverved bits are non-zero
870 * - sfun and presence bit are not set
871 */
872 if (value != ASUS_WMI_UNSUPPORTED_METHOD || value & 0xFFF80000
873 || (!asus->sfun && !(value & ASUS_WMI_DSTS_PRESENCE_BIT)))
874 ok = false;
875 }
876
877 return ok ? attr->mode : 0;
878}
879
880static struct attribute_group hwmon_attribute_group = {
881 .is_visible = asus_hwmon_sysfs_is_visible,
882 .attrs = hwmon_attributes
883};
884
885static void asus_wmi_hwmon_exit(struct asus_wmi *asus)
886{
887 struct device *hwmon;
888
889 hwmon = asus->hwmon_device;
890 if (!hwmon)
891 return;
892 sysfs_remove_group(&hwmon->kobj, &hwmon_attribute_group);
893 hwmon_device_unregister(hwmon);
894 asus->hwmon_device = NULL;
895}
896
897static int asus_wmi_hwmon_init(struct asus_wmi *asus)
898{
899 struct device *hwmon;
900 int result;
901
902 hwmon = hwmon_device_register(&asus->platform_device->dev);
903 if (IS_ERR(hwmon)) {
904 pr_err("Could not register asus hwmon device\n");
905 return PTR_ERR(hwmon);
906 }
907 asus->hwmon_device = hwmon;
908 result = sysfs_create_group(&hwmon->kobj, &hwmon_attribute_group);
909 if (result)
910 asus_wmi_hwmon_exit(asus);
911 return result;
912}
913
914/*
915 * Backlight
916 */
917static int read_backlight_power(struct asus_wmi *asus)
918{
919 int ret = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_BACKLIGHT);
920
921 if (ret < 0)
922 return ret;
923
924 return ret ? FB_BLANK_UNBLANK : FB_BLANK_POWERDOWN;
925}
926
927static int read_brightness_max(struct asus_wmi *asus)
928{
929 u32 retval;
930 int err;
931
932 err = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_BRIGHTNESS, &retval);
933
934 if (err < 0)
935 return err;
936
937 retval = retval & ASUS_WMI_DSTS_MAX_BRIGTH_MASK;
938 retval >>= 8;
939
940 if (!retval)
941 return -ENODEV;
942
943 return retval;
944}
945
946static int read_brightness(struct backlight_device *bd)
947{
948 struct asus_wmi *asus = bl_get_data(bd);
949 u32 retval;
950 int err;
951
952 err = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_BRIGHTNESS, &retval);
953
954 if (err < 0)
955 return err;
956
957 return retval & ASUS_WMI_DSTS_BRIGHTNESS_MASK;
958}
959
960static int update_bl_status(struct backlight_device *bd)
961{
962 struct asus_wmi *asus = bl_get_data(bd);
963 u32 ctrl_param;
964 int power, err;
965
966 ctrl_param = bd->props.brightness;
967
968 err = asus_wmi_set_devstate(ASUS_WMI_DEVID_BRIGHTNESS,
969 ctrl_param, NULL);
970
971 if (err < 0)
972 return err;
973
974 power = read_backlight_power(asus);
975 if (power != -ENODEV && bd->props.power != power) {
976 ctrl_param = !!(bd->props.power == FB_BLANK_UNBLANK);
977 err = asus_wmi_set_devstate(ASUS_WMI_DEVID_BACKLIGHT,
978 ctrl_param, NULL);
979 }
980 return err;
981}
982
983static const struct backlight_ops asus_wmi_bl_ops = {
984 .get_brightness = read_brightness,
985 .update_status = update_bl_status,
986};
987
988static int asus_wmi_backlight_notify(struct asus_wmi *asus, int code)
989{
990 struct backlight_device *bd = asus->backlight_device;
991 int old = bd->props.brightness;
992 int new = old;
993
994 if (code >= NOTIFY_BRNUP_MIN && code <= NOTIFY_BRNUP_MAX)
995 new = code - NOTIFY_BRNUP_MIN + 1;
996 else if (code >= NOTIFY_BRNDOWN_MIN && code <= NOTIFY_BRNDOWN_MAX)
997 new = code - NOTIFY_BRNDOWN_MIN;
998
999 bd->props.brightness = new;
1000 backlight_update_status(bd);
1001 backlight_force_update(bd, BACKLIGHT_UPDATE_HOTKEY);
1002
1003 return old;
1004}
1005
1006static int asus_wmi_backlight_init(struct asus_wmi *asus)
1007{
1008 struct backlight_device *bd;
1009 struct backlight_properties props;
1010 int max;
1011 int power;
1012
1013 max = read_brightness_max(asus);
1014
1015 if (max == -ENODEV)
1016 max = 0;
1017 else if (max < 0)
1018 return max;
1019
1020 power = read_backlight_power(asus);
1021
1022 if (power == -ENODEV)
1023 power = FB_BLANK_UNBLANK;
1024 else if (power < 0)
1025 return power;
1026
1027 memset(&props, 0, sizeof(struct backlight_properties));
1028 props.max_brightness = max;
1029 bd = backlight_device_register(asus->driver->name,
1030 &asus->platform_device->dev, asus,
1031 &asus_wmi_bl_ops, &props);
1032 if (IS_ERR(bd)) {
1033 pr_err("Could not register backlight device\n");
1034 return PTR_ERR(bd);
1035 }
1036
1037 asus->backlight_device = bd;
1038
1039 bd->props.brightness = read_brightness(bd);
1040 bd->props.power = power;
1041 backlight_update_status(bd);
1042
1043 return 0;
1044}
1045
1046static void asus_wmi_backlight_exit(struct asus_wmi *asus)
1047{
1048 if (asus->backlight_device)
1049 backlight_device_unregister(asus->backlight_device);
1050
1051 asus->backlight_device = NULL;
1052}
1053
1054static void asus_wmi_notify(u32 value, void *context)
1055{
1056 struct asus_wmi *asus = context;
1057 struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL };
1058 union acpi_object *obj;
1059 acpi_status status;
1060 int code;
1061 int orig_code;
1062
1063 status = wmi_get_event_data(value, &response);
1064 if (status != AE_OK) {
1065 pr_err("bad event status 0x%x\n", status);
1066 return;
1067 }
1068
1069 obj = (union acpi_object *)response.pointer;
1070
1071 if (!obj || obj->type != ACPI_TYPE_INTEGER)
1072 goto exit;
1073
1074 code = obj->integer.value;
1075 orig_code = code;
1076
1077 if (code >= NOTIFY_BRNUP_MIN && code <= NOTIFY_BRNUP_MAX)
1078 code = NOTIFY_BRNUP_MIN;
1079 else if (code >= NOTIFY_BRNDOWN_MIN &&
1080 code <= NOTIFY_BRNDOWN_MAX)
1081 code = NOTIFY_BRNDOWN_MIN;
1082
1083 if (code == NOTIFY_BRNUP_MIN || code == NOTIFY_BRNDOWN_MIN) {
1084 if (!acpi_video_backlight_support())
1085 asus_wmi_backlight_notify(asus, orig_code);
1086 } else if (!sparse_keymap_report_event(asus->inputdev, code, 1, true))
1087 pr_info("Unknown key %x pressed\n", code);
1088
1089exit:
1090 kfree(obj);
1091}
1092
1093/*
1094 * Sys helpers
1095 */
1096static int parse_arg(const char *buf, unsigned long count, int *val)
1097{
1098 if (!count)
1099 return 0;
1100 if (sscanf(buf, "%i", val) != 1)
1101 return -EINVAL;
1102 return count;
1103}
1104
1105static ssize_t store_sys_wmi(struct asus_wmi *asus, int devid,
1106 const char *buf, size_t count)
1107{
1108 u32 retval;
1109 int rv, err, value;
1110
1111 value = asus_wmi_get_devstate_simple(asus, devid);
1112 if (value == -ENODEV) /* Check device presence */
1113 return value;
1114
1115 rv = parse_arg(buf, count, &value);
1116 err = asus_wmi_set_devstate(devid, value, &retval);
1117
1118 if (err < 0)
1119 return err;
1120
1121 return rv;
1122}
1123
1124static ssize_t show_sys_wmi(struct asus_wmi *asus, int devid, char *buf)
1125{
1126 int value = asus_wmi_get_devstate_simple(asus, devid);
1127
1128 if (value < 0)
1129 return value;
1130
1131 return sprintf(buf, "%d\n", value);
1132}
1133
1134#define ASUS_WMI_CREATE_DEVICE_ATTR(_name, _mode, _cm) \
1135 static ssize_t show_##_name(struct device *dev, \
1136 struct device_attribute *attr, \
1137 char *buf) \
1138 { \
1139 struct asus_wmi *asus = dev_get_drvdata(dev); \
1140 \
1141 return show_sys_wmi(asus, _cm, buf); \
1142 } \
1143 static ssize_t store_##_name(struct device *dev, \
1144 struct device_attribute *attr, \
1145 const char *buf, size_t count) \
1146 { \
1147 struct asus_wmi *asus = dev_get_drvdata(dev); \
1148 \
1149 return store_sys_wmi(asus, _cm, buf, count); \
1150 } \
1151 static struct device_attribute dev_attr_##_name = { \
1152 .attr = { \
1153 .name = __stringify(_name), \
1154 .mode = _mode }, \
1155 .show = show_##_name, \
1156 .store = store_##_name, \
1157 }
1158
1159ASUS_WMI_CREATE_DEVICE_ATTR(touchpad, 0644, ASUS_WMI_DEVID_TOUCHPAD);
1160ASUS_WMI_CREATE_DEVICE_ATTR(camera, 0644, ASUS_WMI_DEVID_CAMERA);
1161ASUS_WMI_CREATE_DEVICE_ATTR(cardr, 0644, ASUS_WMI_DEVID_CARDREADER);
1162
1163static ssize_t store_cpufv(struct device *dev, struct device_attribute *attr,
1164 const char *buf, size_t count)
1165{
1166 int value;
1167
1168 if (!count || sscanf(buf, "%i", &value) != 1)
1169 return -EINVAL;
1170 if (value < 0 || value > 2)
1171 return -EINVAL;
1172
1173 return asus_wmi_evaluate_method(ASUS_WMI_METHODID_CFVS, value, 0, NULL);
1174}
1175
1176static DEVICE_ATTR(cpufv, S_IRUGO | S_IWUSR, NULL, store_cpufv);
1177
1178static struct attribute *platform_attributes[] = {
1179 &dev_attr_cpufv.attr,
1180 &dev_attr_camera.attr,
1181 &dev_attr_cardr.attr,
1182 &dev_attr_touchpad.attr,
1183 NULL
1184};
1185
1186static mode_t asus_sysfs_is_visible(struct kobject *kobj,
1187 struct attribute *attr, int idx)
1188{
1189 struct device *dev = container_of(kobj, struct device, kobj);
1190 struct platform_device *pdev = to_platform_device(dev);
1191 struct asus_wmi *asus = platform_get_drvdata(pdev);
1192 bool ok = true;
1193 int devid = -1;
1194
1195 if (attr == &dev_attr_camera.attr)
1196 devid = ASUS_WMI_DEVID_CAMERA;
1197 else if (attr == &dev_attr_cardr.attr)
1198 devid = ASUS_WMI_DEVID_CARDREADER;
1199 else if (attr == &dev_attr_touchpad.attr)
1200 devid = ASUS_WMI_DEVID_TOUCHPAD;
1201
1202 if (devid != -1)
1203 ok = !(asus_wmi_get_devstate_simple(asus, devid) < 0);
1204
1205 return ok ? attr->mode : 0;
1206}
1207
1208static struct attribute_group platform_attribute_group = {
1209 .is_visible = asus_sysfs_is_visible,
1210 .attrs = platform_attributes
1211};
1212
1213static void asus_wmi_sysfs_exit(struct platform_device *device)
1214{
1215 sysfs_remove_group(&device->dev.kobj, &platform_attribute_group);
1216}
1217
1218static int asus_wmi_sysfs_init(struct platform_device *device)
1219{
1220 return sysfs_create_group(&device->dev.kobj, &platform_attribute_group);
1221}
1222
1223/*
1224 * Platform device
1225 */
1226static int __init asus_wmi_platform_init(struct asus_wmi *asus)
1227{
1228 int rv;
1229
1230 /* INIT enable hotkeys on some models */
1231 if (!asus_wmi_evaluate_method(ASUS_WMI_METHODID_INIT, 0, 0, &rv))
1232 pr_info("Initialization: %#x", rv);
1233
1234 /* We don't know yet what to do with this version... */
1235 if (!asus_wmi_evaluate_method(ASUS_WMI_METHODID_SPEC, 0, 0x9, &rv)) {
1236 pr_info("BIOS WMI version: %d.%d", rv >> 8, rv & 0xFF);
1237 asus->spec = rv;
1238 }
1239
1240 /*
1241 * The SFUN method probably allows the original driver to get the list
1242 * of features supported by a given model. For now, 0x0100 or 0x0800
1243 * bit signifies that the laptop is equipped with a Wi-Fi MiniPCI card.
1244 * The significance of others is yet to be found.
1245 */
1246 if (!asus_wmi_evaluate_method(ASUS_WMI_METHODID_SFUN, 0, 0, &rv)) {
1247 pr_info("SFUN value: %#x", rv);
1248 asus->sfun = rv;
1249 }
1250
1251 /*
1252 * Eee PC and Notebooks seems to have different method_id for DSTS,
1253 * but it may also be related to the BIOS's SPEC.
1254 * Note, on most Eeepc, there is no way to check if a method exist
1255 * or note, while on notebooks, they returns 0xFFFFFFFE on failure,
1256 * but once again, SPEC may probably be used for that kind of things.
1257 */
1258 if (!asus_wmi_evaluate_method(ASUS_WMI_METHODID_DSTS, 0, 0, NULL))
1259 asus->dsts_id = ASUS_WMI_METHODID_DSTS;
1260 else if (!asus_wmi_evaluate_method(ASUS_WMI_METHODID_DSTS2, 0, 0, NULL))
1261 asus->dsts_id = ASUS_WMI_METHODID_DSTS2;
1262
1263 if (!asus->dsts_id) {
1264 pr_err("Can't find DSTS");
1265 return -ENODEV;
1266 }
1267
1268 return asus_wmi_sysfs_init(asus->platform_device);
1269}
1270
1271static void asus_wmi_platform_exit(struct asus_wmi *asus)
1272{
1273 asus_wmi_sysfs_exit(asus->platform_device);
1274}
1275
1276/*
1277 * debugfs
1278 */
1279struct asus_wmi_debugfs_node {
1280 struct asus_wmi *asus;
1281 char *name;
1282 int (*show) (struct seq_file *m, void *data);
1283};
1284
1285static int show_dsts(struct seq_file *m, void *data)
1286{
1287 struct asus_wmi *asus = m->private;
1288 int err;
1289 u32 retval = -1;
1290
1291 err = asus_wmi_get_devstate(asus, asus->debug.dev_id, &retval);
1292
1293 if (err < 0)
1294 return err;
1295
1296 seq_printf(m, "DSTS(%#x) = %#x\n", asus->debug.dev_id, retval);
1297
1298 return 0;
1299}
1300
1301static int show_devs(struct seq_file *m, void *data)
1302{
1303 struct asus_wmi *asus = m->private;
1304 int err;
1305 u32 retval = -1;
1306
1307 err = asus_wmi_set_devstate(asus->debug.dev_id, asus->debug.ctrl_param,
1308 &retval);
1309
1310 if (err < 0)
1311 return err;
1312
1313 seq_printf(m, "DEVS(%#x, %#x) = %#x\n", asus->debug.dev_id,
1314 asus->debug.ctrl_param, retval);
1315
1316 return 0;
1317}
1318
1319static int show_call(struct seq_file *m, void *data)
1320{
1321 struct asus_wmi *asus = m->private;
1322 struct bios_args args = {
1323 .arg0 = asus->debug.dev_id,
1324 .arg1 = asus->debug.ctrl_param,
1325 };
1326 struct acpi_buffer input = { (acpi_size) sizeof(args), &args };
1327 struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
1328 union acpi_object *obj;
1329 acpi_status status;
1330
1331 status = wmi_evaluate_method(ASUS_WMI_MGMT_GUID,
1332 1, asus->debug.method_id,
1333 &input, &output);
1334
1335 if (ACPI_FAILURE(status))
1336 return -EIO;
1337
1338 obj = (union acpi_object *)output.pointer;
1339 if (obj && obj->type == ACPI_TYPE_INTEGER)
1340 seq_printf(m, "%#x(%#x, %#x) = %#x\n", asus->debug.method_id,
1341 asus->debug.dev_id, asus->debug.ctrl_param,
1342 (u32) obj->integer.value);
1343 else
1344 seq_printf(m, "%#x(%#x, %#x) = t:%d\n", asus->debug.method_id,
1345 asus->debug.dev_id, asus->debug.ctrl_param,
1346 obj ? obj->type : -1);
1347
1348 kfree(obj);
1349
1350 return 0;
1351}
1352
1353static struct asus_wmi_debugfs_node asus_wmi_debug_files[] = {
1354 {NULL, "devs", show_devs},
1355 {NULL, "dsts", show_dsts},
1356 {NULL, "call", show_call},
1357};
1358
1359static int asus_wmi_debugfs_open(struct inode *inode, struct file *file)
1360{
1361 struct asus_wmi_debugfs_node *node = inode->i_private;
1362
1363 return single_open(file, node->show, node->asus);
1364}
1365
1366static const struct file_operations asus_wmi_debugfs_io_ops = {
1367 .owner = THIS_MODULE,
1368 .open = asus_wmi_debugfs_open,
1369 .read = seq_read,
1370 .llseek = seq_lseek,
1371 .release = single_release,
1372};
1373
1374static void asus_wmi_debugfs_exit(struct asus_wmi *asus)
1375{
1376 debugfs_remove_recursive(asus->debug.root);
1377}
1378
1379static int asus_wmi_debugfs_init(struct asus_wmi *asus)
1380{
1381 struct dentry *dent;
1382 int i;
1383
1384 asus->debug.root = debugfs_create_dir(asus->driver->name, NULL);
1385 if (!asus->debug.root) {
1386 pr_err("failed to create debugfs directory");
1387 goto error_debugfs;
1388 }
1389
1390 dent = debugfs_create_x32("method_id", S_IRUGO | S_IWUSR,
1391 asus->debug.root, &asus->debug.method_id);
1392 if (!dent)
1393 goto error_debugfs;
1394
1395 dent = debugfs_create_x32("dev_id", S_IRUGO | S_IWUSR,
1396 asus->debug.root, &asus->debug.dev_id);
1397 if (!dent)
1398 goto error_debugfs;
1399
1400 dent = debugfs_create_x32("ctrl_param", S_IRUGO | S_IWUSR,
1401 asus->debug.root, &asus->debug.ctrl_param);
1402 if (!dent)
1403 goto error_debugfs;
1404
1405 for (i = 0; i < ARRAY_SIZE(asus_wmi_debug_files); i++) {
1406 struct asus_wmi_debugfs_node *node = &asus_wmi_debug_files[i];
1407
1408 node->asus = asus;
1409 dent = debugfs_create_file(node->name, S_IFREG | S_IRUGO,
1410 asus->debug.root, node,
1411 &asus_wmi_debugfs_io_ops);
1412 if (!dent) {
1413 pr_err("failed to create debug file: %s\n", node->name);
1414 goto error_debugfs;
1415 }
1416 }
1417
1418 return 0;
1419
1420error_debugfs:
1421 asus_wmi_debugfs_exit(asus);
1422 return -ENOMEM;
1423}
1424
1425/*
1426 * WMI Driver
1427 */
1428static int asus_wmi_add(struct platform_device *pdev)
1429{
1430 struct platform_driver *pdrv = to_platform_driver(pdev->dev.driver);
1431 struct asus_wmi_driver *wdrv = to_asus_wmi_driver(pdrv);
1432 struct asus_wmi *asus;
1433 acpi_status status;
1434 int err;
1435
1436 asus = kzalloc(sizeof(struct asus_wmi), GFP_KERNEL);
1437 if (!asus)
1438 return -ENOMEM;
1439
1440 asus->driver = wdrv;
1441 asus->platform_device = pdev;
1442 wdrv->platform_device = pdev;
1443 platform_set_drvdata(asus->platform_device, asus);
1444
1445 if (wdrv->quirks)
1446 wdrv->quirks(asus->driver);
1447
1448 err = asus_wmi_platform_init(asus);
1449 if (err)
1450 goto fail_platform;
1451
1452 err = asus_wmi_input_init(asus);
1453 if (err)
1454 goto fail_input;
1455
1456 err = asus_wmi_hwmon_init(asus);
1457 if (err)
1458 goto fail_hwmon;
1459
1460 err = asus_wmi_led_init(asus);
1461 if (err)
1462 goto fail_leds;
1463
1464 err = asus_wmi_rfkill_init(asus);
1465 if (err)
1466 goto fail_rfkill;
1467
1468 if (!acpi_video_backlight_support()) {
1469 err = asus_wmi_backlight_init(asus);
1470 if (err && err != -ENODEV)
1471 goto fail_backlight;
1472 } else
1473 pr_info("Backlight controlled by ACPI video driver\n");
1474
1475 status = wmi_install_notify_handler(asus->driver->event_guid,
1476 asus_wmi_notify, asus);
1477 if (ACPI_FAILURE(status)) {
1478 pr_err("Unable to register notify handler - %d\n", status);
1479 err = -ENODEV;
1480 goto fail_wmi_handler;
1481 }
1482
1483 err = asus_wmi_debugfs_init(asus);
1484 if (err)
1485 goto fail_debugfs;
1486
1487 return 0;
1488
1489fail_debugfs:
1490 wmi_remove_notify_handler(asus->driver->event_guid);
1491fail_wmi_handler:
1492 asus_wmi_backlight_exit(asus);
1493fail_backlight:
1494 asus_wmi_rfkill_exit(asus);
1495fail_rfkill:
1496 asus_wmi_led_exit(asus);
1497fail_leds:
1498 asus_wmi_hwmon_exit(asus);
1499fail_hwmon:
1500 asus_wmi_input_exit(asus);
1501fail_input:
1502 asus_wmi_platform_exit(asus);
1503fail_platform:
1504 kfree(asus);
1505 return err;
1506}
1507
1508static int asus_wmi_remove(struct platform_device *device)
1509{
1510 struct asus_wmi *asus;
1511
1512 asus = platform_get_drvdata(device);
1513 wmi_remove_notify_handler(asus->driver->event_guid);
1514 asus_wmi_backlight_exit(asus);
1515 asus_wmi_input_exit(asus);
1516 asus_wmi_hwmon_exit(asus);
1517 asus_wmi_led_exit(asus);
1518 asus_wmi_rfkill_exit(asus);
1519 asus_wmi_debugfs_exit(asus);
1520 asus_wmi_platform_exit(asus);
1521
1522 kfree(asus);
1523 return 0;
1524}
1525
1526/*
1527 * Platform driver - hibernate/resume callbacks
1528 */
1529static int asus_hotk_thaw(struct device *device)
1530{
1531 struct asus_wmi *asus = dev_get_drvdata(device);
1532
1533 if (asus->wlan.rfkill) {
1534 bool wlan;
1535
1536 /*
1537 * Work around bios bug - acpi _PTS turns off the wireless led
1538 * during suspend. Normally it restores it on resume, but
1539 * we should kick it ourselves in case hibernation is aborted.
1540 */
1541 wlan = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_WLAN);
1542 asus_wmi_set_devstate(ASUS_WMI_DEVID_WLAN, wlan, NULL);
1543 }
1544
1545 return 0;
1546}
1547
1548static int asus_hotk_restore(struct device *device)
1549{
1550 struct asus_wmi *asus = dev_get_drvdata(device);
1551 int bl;
1552
1553 /* Refresh both wlan rfkill state and pci hotplug */
1554 if (asus->wlan.rfkill)
1555 asus_rfkill_hotplug(asus);
1556
1557 if (asus->bluetooth.rfkill) {
1558 bl = !asus_wmi_get_devstate_simple(asus,
1559 ASUS_WMI_DEVID_BLUETOOTH);
1560 rfkill_set_sw_state(asus->bluetooth.rfkill, bl);
1561 }
1562 if (asus->wimax.rfkill) {
1563 bl = !asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_WIMAX);
1564 rfkill_set_sw_state(asus->wimax.rfkill, bl);
1565 }
1566 if (asus->wwan3g.rfkill) {
1567 bl = !asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_WWAN3G);
1568 rfkill_set_sw_state(asus->wwan3g.rfkill, bl);
1569 }
1570
1571 return 0;
1572}
1573
1574static const struct dev_pm_ops asus_pm_ops = {
1575 .thaw = asus_hotk_thaw,
1576 .restore = asus_hotk_restore,
1577};
1578
1579static int asus_wmi_probe(struct platform_device *pdev)
1580{
1581 struct platform_driver *pdrv = to_platform_driver(pdev->dev.driver);
1582 struct asus_wmi_driver *wdrv = to_asus_wmi_driver(pdrv);
1583 int ret;
1584
1585 if (!wmi_has_guid(ASUS_WMI_MGMT_GUID)) {
1586 pr_warning("Management GUID not found\n");
1587 return -ENODEV;
1588 }
1589
1590 if (wdrv->event_guid && !wmi_has_guid(wdrv->event_guid)) {
1591 pr_warning("Event GUID not found\n");
1592 return -ENODEV;
1593 }
1594
1595 if (wdrv->probe) {
1596 ret = wdrv->probe(pdev);
1597 if (ret)
1598 return ret;
1599 }
1600
1601 return asus_wmi_add(pdev);
1602}
1603
1604static bool used;
1605
1606int asus_wmi_register_driver(struct asus_wmi_driver *driver)
1607{
1608 struct platform_driver *platform_driver;
1609 struct platform_device *platform_device;
1610
1611 if (used)
1612 return -EBUSY;
1613
1614 platform_driver = &driver->platform_driver;
1615 platform_driver->remove = asus_wmi_remove;
1616 platform_driver->driver.owner = driver->owner;
1617 platform_driver->driver.name = driver->name;
1618 platform_driver->driver.pm = &asus_pm_ops;
1619
1620 platform_device = platform_create_bundle(platform_driver,
1621 asus_wmi_probe,
1622 NULL, 0, NULL, 0);
1623 if (IS_ERR(platform_device))
1624 return PTR_ERR(platform_device);
1625
1626 used = true;
1627 return 0;
1628}
1629EXPORT_SYMBOL_GPL(asus_wmi_register_driver);
1630
1631void asus_wmi_unregister_driver(struct asus_wmi_driver *driver)
1632{
1633 platform_device_unregister(driver->platform_device);
1634 platform_driver_unregister(&driver->platform_driver);
1635 used = false;
1636}
1637EXPORT_SYMBOL_GPL(asus_wmi_unregister_driver);
1638
1639static int __init asus_wmi_init(void)
1640{
1641 if (!wmi_has_guid(ASUS_WMI_MGMT_GUID)) {
1642 pr_info("Asus Management GUID not found");
1643 return -ENODEV;
1644 }
1645
1646 pr_info("ASUS WMI generic driver loaded");
1647 return 0;
1648}
1649
1650static void __exit asus_wmi_exit(void)
1651{
1652 pr_info("ASUS WMI generic driver unloaded");
1653}
1654
1655module_init(asus_wmi_init);
1656module_exit(asus_wmi_exit);
diff --git a/drivers/platform/x86/asus-wmi.h b/drivers/platform/x86/asus-wmi.h
new file mode 100644
index 000000000000..c044522c8766
--- /dev/null
+++ b/drivers/platform/x86/asus-wmi.h
@@ -0,0 +1,58 @@
1/*
2 * Asus PC WMI hotkey driver
3 *
4 * Copyright(C) 2010 Intel Corporation.
5 * Copyright(C) 2010-2011 Corentin Chary <corentin.chary@gmail.com>
6 *
7 * Portions based on wistron_btns.c:
8 * Copyright (C) 2005 Miloslav Trmac <mitr@volny.cz>
9 * Copyright (C) 2005 Bernhard Rosenkraenzer <bero@arklinux.org>
10 * Copyright (C) 2005 Dmitry Torokhov <dtor@mail.ru>
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 */
26
27#ifndef _ASUS_WMI_H_
28#define _ASUS_WMI_H_
29
30#include <linux/platform_device.h>
31
32struct module;
33struct key_entry;
34struct asus_wmi;
35
36struct asus_wmi_driver {
37 bool hotplug_wireless;
38
39 const char *name;
40 struct module *owner;
41
42 const char *event_guid;
43
44 const struct key_entry *keymap;
45 const char *input_name;
46 const char *input_phys;
47
48 int (*probe) (struct platform_device *device);
49 void (*quirks) (struct asus_wmi_driver *driver);
50
51 struct platform_driver platform_driver;
52 struct platform_device *platform_device;
53};
54
55int asus_wmi_register_driver(struct asus_wmi_driver *driver);
56void asus_wmi_unregister_driver(struct asus_wmi_driver *driver);
57
58#endif /* !_ASUS_WMI_H_ */
diff --git a/drivers/platform/x86/compal-laptop.c b/drivers/platform/x86/compal-laptop.c
index eb95878fa583..c16a27641ced 100644
--- a/drivers/platform/x86/compal-laptop.c
+++ b/drivers/platform/x86/compal-laptop.c
@@ -201,7 +201,7 @@ static bool extra_features;
201 * into 0x4F and read a few bytes from the output, like so: 201 * into 0x4F and read a few bytes from the output, like so:
202 * u8 writeData = 0x33; 202 * u8 writeData = 0x33;
203 * ec_transaction(0x4F, &writeData, 1, buffer, 32, 0); 203 * ec_transaction(0x4F, &writeData, 1, buffer, 32, 0);
204 * That address is labled "fan1 table information" in the service manual. 204 * That address is labelled "fan1 table information" in the service manual.
205 * It should be clear which value in 'buffer' changes). This seems to be 205 * It should be clear which value in 'buffer' changes). This seems to be
206 * related to fan speed. It isn't a proper 'realtime' fan speed value 206 * related to fan speed. It isn't a proper 'realtime' fan speed value
207 * though, because physically stopping or speeding up the fan doesn't 207 * though, because physically stopping or speeding up the fan doesn't
@@ -275,7 +275,7 @@ static int set_backlight_level(int level)
275 275
276 ec_write(BACKLIGHT_LEVEL_ADDR, level); 276 ec_write(BACKLIGHT_LEVEL_ADDR, level);
277 277
278 return 1; 278 return 0;
279} 279}
280 280
281static int get_backlight_level(void) 281static int get_backlight_level(void)
@@ -763,7 +763,7 @@ static int dmi_check_cb(const struct dmi_system_id *id)
763 printk(KERN_INFO DRIVER_NAME": Identified laptop model '%s'\n", 763 printk(KERN_INFO DRIVER_NAME": Identified laptop model '%s'\n",
764 id->ident); 764 id->ident);
765 extra_features = false; 765 extra_features = false;
766 return 0; 766 return 1;
767} 767}
768 768
769static int dmi_check_cb_extra(const struct dmi_system_id *id) 769static int dmi_check_cb_extra(const struct dmi_system_id *id)
@@ -772,7 +772,7 @@ static int dmi_check_cb_extra(const struct dmi_system_id *id)
772 "enabling extra features\n", 772 "enabling extra features\n",
773 id->ident); 773 id->ident);
774 extra_features = true; 774 extra_features = true;
775 return 0; 775 return 1;
776} 776}
777 777
778static struct dmi_system_id __initdata compal_dmi_table[] = { 778static struct dmi_system_id __initdata compal_dmi_table[] = {
diff --git a/drivers/platform/x86/dell-wmi-aio.c b/drivers/platform/x86/dell-wmi-aio.c
new file mode 100644
index 000000000000..0ed84573ae1f
--- /dev/null
+++ b/drivers/platform/x86/dell-wmi-aio.c
@@ -0,0 +1,171 @@
1/*
2 * WMI hotkeys support for Dell All-In-One series
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 */
18#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
19
20#include <linux/kernel.h>
21#include <linux/module.h>
22#include <linux/init.h>
23#include <linux/types.h>
24#include <linux/input.h>
25#include <linux/input/sparse-keymap.h>
26#include <acpi/acpi_drivers.h>
27#include <linux/acpi.h>
28#include <linux/string.h>
29
30MODULE_DESCRIPTION("WMI hotkeys driver for Dell All-In-One series");
31MODULE_LICENSE("GPL");
32
33#define EVENT_GUID1 "284A0E6B-380E-472A-921F-E52786257FB4"
34#define EVENT_GUID2 "02314822-307C-4F66-BF0E-48AEAEB26CC8"
35
36static const char *dell_wmi_aio_guids[] = {
37 EVENT_GUID1,
38 EVENT_GUID2,
39 NULL
40};
41
42MODULE_ALIAS("wmi:"EVENT_GUID1);
43MODULE_ALIAS("wmi:"EVENT_GUID2);
44
45static const struct key_entry dell_wmi_aio_keymap[] = {
46 { KE_KEY, 0xc0, { KEY_VOLUMEUP } },
47 { KE_KEY, 0xc1, { KEY_VOLUMEDOWN } },
48 { KE_END, 0 }
49};
50
51static struct input_dev *dell_wmi_aio_input_dev;
52
53static void dell_wmi_aio_notify(u32 value, void *context)
54{
55 struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL };
56 union acpi_object *obj;
57 acpi_status status;
58
59 status = wmi_get_event_data(value, &response);
60 if (status != AE_OK) {
61 pr_info("bad event status 0x%x\n", status);
62 return;
63 }
64
65 obj = (union acpi_object *)response.pointer;
66 if (obj) {
67 unsigned int scancode;
68
69 switch (obj->type) {
70 case ACPI_TYPE_INTEGER:
71 /* Most All-In-One correctly return integer scancode */
72 scancode = obj->integer.value;
73 sparse_keymap_report_event(dell_wmi_aio_input_dev,
74 scancode, 1, true);
75 break;
76 case ACPI_TYPE_BUFFER:
77 /* Broken machines return the scancode in a buffer */
78 if (obj->buffer.pointer && obj->buffer.length > 0) {
79 scancode = obj->buffer.pointer[0];
80 sparse_keymap_report_event(
81 dell_wmi_aio_input_dev,
82 scancode, 1, true);
83 }
84 break;
85 }
86 }
87 kfree(obj);
88}
89
90static int __init dell_wmi_aio_input_setup(void)
91{
92 int err;
93
94 dell_wmi_aio_input_dev = input_allocate_device();
95
96 if (!dell_wmi_aio_input_dev)
97 return -ENOMEM;
98
99 dell_wmi_aio_input_dev->name = "Dell AIO WMI hotkeys";
100 dell_wmi_aio_input_dev->phys = "wmi/input0";
101 dell_wmi_aio_input_dev->id.bustype = BUS_HOST;
102
103 err = sparse_keymap_setup(dell_wmi_aio_input_dev,
104 dell_wmi_aio_keymap, NULL);
105 if (err) {
106 pr_err("Unable to setup input device keymap\n");
107 goto err_free_dev;
108 }
109 err = input_register_device(dell_wmi_aio_input_dev);
110 if (err) {
111 pr_info("Unable to register input device\n");
112 goto err_free_keymap;
113 }
114 return 0;
115
116err_free_keymap:
117 sparse_keymap_free(dell_wmi_aio_input_dev);
118err_free_dev:
119 input_free_device(dell_wmi_aio_input_dev);
120 return err;
121}
122
123static const char *dell_wmi_aio_find(void)
124{
125 int i;
126
127 for (i = 0; dell_wmi_aio_guids[i] != NULL; i++)
128 if (wmi_has_guid(dell_wmi_aio_guids[i]))
129 return dell_wmi_aio_guids[i];
130
131 return NULL;
132}
133
134static int __init dell_wmi_aio_init(void)
135{
136 int err;
137 const char *guid;
138
139 guid = dell_wmi_aio_find();
140 if (!guid) {
141 pr_warning("No known WMI GUID found\n");
142 return -ENXIO;
143 }
144
145 err = dell_wmi_aio_input_setup();
146 if (err)
147 return err;
148
149 err = wmi_install_notify_handler(guid, dell_wmi_aio_notify, NULL);
150 if (err) {
151 pr_err("Unable to register notify handler - %d\n", err);
152 sparse_keymap_free(dell_wmi_aio_input_dev);
153 input_unregister_device(dell_wmi_aio_input_dev);
154 return err;
155 }
156
157 return 0;
158}
159
160static void __exit dell_wmi_aio_exit(void)
161{
162 const char *guid;
163
164 guid = dell_wmi_aio_find();
165 wmi_remove_notify_handler(guid);
166 sparse_keymap_free(dell_wmi_aio_input_dev);
167 input_unregister_device(dell_wmi_aio_input_dev);
168}
169
170module_init(dell_wmi_aio_init);
171module_exit(dell_wmi_aio_exit);
diff --git a/drivers/platform/x86/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c
index 6605beac0d0e..5f2dd386152b 100644
--- a/drivers/platform/x86/eeepc-laptop.c
+++ b/drivers/platform/x86/eeepc-laptop.c
@@ -1322,7 +1322,7 @@ static void cmsg_quirk(struct eeepc_laptop *eeepc, int cm, const char *name)
1322{ 1322{
1323 int dummy; 1323 int dummy;
1324 1324
1325 /* Some BIOSes do not report cm although it is avaliable. 1325 /* Some BIOSes do not report cm although it is available.
1326 Check if cm_getv[cm] works and, if yes, assume cm should be set. */ 1326 Check if cm_getv[cm] works and, if yes, assume cm should be set. */
1327 if (!(eeepc->cm_supported & (1 << cm)) 1327 if (!(eeepc->cm_supported & (1 << cm))
1328 && !read_acpi_int(eeepc->handle, cm_getv[cm], &dummy)) { 1328 && !read_acpi_int(eeepc->handle, cm_getv[cm], &dummy)) {
diff --git a/drivers/platform/x86/eeepc-wmi.c b/drivers/platform/x86/eeepc-wmi.c
index 4d38f98aa976..0ddc434fb93b 100644
--- a/drivers/platform/x86/eeepc-wmi.c
+++ b/drivers/platform/x86/eeepc-wmi.c
@@ -2,7 +2,7 @@
2 * Eee PC WMI hotkey driver 2 * Eee PC WMI hotkey driver
3 * 3 *
4 * Copyright(C) 2010 Intel Corporation. 4 * Copyright(C) 2010 Intel Corporation.
5 * Copyright(C) 2010 Corentin Chary <corentin.chary@gmail.com> 5 * Copyright(C) 2010-2011 Corentin Chary <corentin.chary@gmail.com>
6 * 6 *
7 * Portions based on wistron_btns.c: 7 * Portions based on wistron_btns.c:
8 * Copyright (C) 2005 Miloslav Trmac <mitr@volny.cz> 8 * Copyright (C) 2005 Miloslav Trmac <mitr@volny.cz>
@@ -29,841 +29,57 @@
29#include <linux/kernel.h> 29#include <linux/kernel.h>
30#include <linux/module.h> 30#include <linux/module.h>
31#include <linux/init.h> 31#include <linux/init.h>
32#include <linux/types.h>
33#include <linux/slab.h>
34#include <linux/input.h> 32#include <linux/input.h>
35#include <linux/input/sparse-keymap.h> 33#include <linux/input/sparse-keymap.h>
36#include <linux/fb.h> 34#include <linux/dmi.h>
37#include <linux/backlight.h>
38#include <linux/leds.h>
39#include <linux/rfkill.h>
40#include <linux/debugfs.h>
41#include <linux/seq_file.h>
42#include <linux/platform_device.h>
43#include <acpi/acpi_bus.h> 35#include <acpi/acpi_bus.h>
44#include <acpi/acpi_drivers.h> 36
37#include "asus-wmi.h"
45 38
46#define EEEPC_WMI_FILE "eeepc-wmi" 39#define EEEPC_WMI_FILE "eeepc-wmi"
47 40
48MODULE_AUTHOR("Yong Wang <yong.y.wang@intel.com>"); 41MODULE_AUTHOR("Corentin Chary <corentincj@iksaif.net>");
49MODULE_DESCRIPTION("Eee PC WMI Hotkey Driver"); 42MODULE_DESCRIPTION("Eee PC WMI Hotkey Driver");
50MODULE_LICENSE("GPL"); 43MODULE_LICENSE("GPL");
51 44
52#define EEEPC_ACPI_HID "ASUS010" /* old _HID used in eeepc-laptop */ 45#define EEEPC_ACPI_HID "ASUS010" /* old _HID used in eeepc-laptop */
53 46
54#define EEEPC_WMI_EVENT_GUID "ABBC0F72-8EA1-11D1-00A0-C90629100000" 47#define EEEPC_WMI_EVENT_GUID "ABBC0F72-8EA1-11D1-00A0-C90629100000"
55#define EEEPC_WMI_MGMT_GUID "97845ED0-4E6D-11DE-8A39-0800200C9A66"
56 48
57MODULE_ALIAS("wmi:"EEEPC_WMI_EVENT_GUID); 49MODULE_ALIAS("wmi:"EEEPC_WMI_EVENT_GUID);
58MODULE_ALIAS("wmi:"EEEPC_WMI_MGMT_GUID);
59
60#define NOTIFY_BRNUP_MIN 0x11
61#define NOTIFY_BRNUP_MAX 0x1f
62#define NOTIFY_BRNDOWN_MIN 0x20
63#define NOTIFY_BRNDOWN_MAX 0x2e
64 50
65#define EEEPC_WMI_METHODID_DEVS 0x53564544 51static bool hotplug_wireless;
66#define EEEPC_WMI_METHODID_DSTS 0x53544344
67#define EEEPC_WMI_METHODID_CFVS 0x53564643
68 52
69#define EEEPC_WMI_DEVID_BACKLIGHT 0x00050012 53module_param(hotplug_wireless, bool, 0444);
70#define EEEPC_WMI_DEVID_TPDLED 0x00100011 54MODULE_PARM_DESC(hotplug_wireless,
71#define EEEPC_WMI_DEVID_WLAN 0x00010011 55 "Enable hotplug for wireless device. "
72#define EEEPC_WMI_DEVID_BLUETOOTH 0x00010013 56 "If your laptop needs that, please report to "
73#define EEEPC_WMI_DEVID_WWAN3G 0x00010019 57 "acpi4asus-user@lists.sourceforge.net.");
74 58
75static const struct key_entry eeepc_wmi_keymap[] = { 59static const struct key_entry eeepc_wmi_keymap[] = {
76 /* Sleep already handled via generic ACPI code */ 60 /* Sleep already handled via generic ACPI code */
77 { KE_KEY, 0x5d, { KEY_WLAN } },
78 { KE_KEY, 0x32, { KEY_MUTE } },
79 { KE_KEY, 0x31, { KEY_VOLUMEDOWN } },
80 { KE_KEY, 0x30, { KEY_VOLUMEUP } }, 61 { KE_KEY, 0x30, { KEY_VOLUMEUP } },
81 { KE_IGNORE, NOTIFY_BRNDOWN_MIN, { KEY_BRIGHTNESSDOWN } }, 62 { KE_KEY, 0x31, { KEY_VOLUMEDOWN } },
82 { KE_IGNORE, NOTIFY_BRNUP_MIN, { KEY_BRIGHTNESSUP } }, 63 { KE_KEY, 0x32, { KEY_MUTE } },
64 { KE_KEY, 0x5c, { KEY_F15 } }, /* Power Gear key */
65 { KE_KEY, 0x5d, { KEY_WLAN } },
66 { KE_KEY, 0x6b, { KEY_TOUCHPAD_TOGGLE } }, /* Toggle Touchpad */
67 { KE_KEY, 0x82, { KEY_CAMERA } },
68 { KE_KEY, 0x83, { KEY_CAMERA_ZOOMIN } },
69 { KE_KEY, 0x88, { KEY_WLAN } },
83 { KE_KEY, 0xcc, { KEY_SWITCHVIDEOMODE } }, 70 { KE_KEY, 0xcc, { KEY_SWITCHVIDEOMODE } },
84 { KE_KEY, 0x6b, { KEY_F13 } }, /* Disable Touchpad */ 71 { KE_KEY, 0xe0, { KEY_PROG1 } }, /* Task Manager */
85 { KE_KEY, 0xe1, { KEY_F14 } }, 72 { KE_KEY, 0xe1, { KEY_F14 } }, /* Change Resolution */
86 { KE_KEY, 0xe9, { KEY_DISPLAY_OFF } }, 73 { KE_KEY, 0xe9, { KEY_BRIGHTNESS_ZERO } },
87 { KE_KEY, 0xe0, { KEY_PROG1 } }, 74 { KE_KEY, 0xeb, { KEY_CAMERA_ZOOMOUT } },
88 { KE_KEY, 0x5c, { KEY_F15 } }, 75 { KE_KEY, 0xec, { KEY_CAMERA_UP } },
76 { KE_KEY, 0xed, { KEY_CAMERA_DOWN } },
77 { KE_KEY, 0xee, { KEY_CAMERA_LEFT } },
78 { KE_KEY, 0xef, { KEY_CAMERA_RIGHT } },
89 { KE_END, 0}, 79 { KE_END, 0},
90}; 80};
91 81
92struct bios_args { 82static acpi_status eeepc_wmi_parse_device(acpi_handle handle, u32 level,
93 u32 dev_id;
94 u32 ctrl_param;
95};
96
97/*
98 * eeepc-wmi/ - debugfs root directory
99 * dev_id - current dev_id
100 * ctrl_param - current ctrl_param
101 * devs - call DEVS(dev_id, ctrl_param) and print result
102 * dsts - call DSTS(dev_id) and print result
103 */
104struct eeepc_wmi_debug {
105 struct dentry *root;
106 u32 dev_id;
107 u32 ctrl_param;
108};
109
110struct eeepc_wmi {
111 struct input_dev *inputdev;
112 struct backlight_device *backlight_device;
113 struct platform_device *platform_device;
114
115 struct led_classdev tpd_led;
116 int tpd_led_wk;
117 struct workqueue_struct *led_workqueue;
118 struct work_struct tpd_led_work;
119
120 struct rfkill *wlan_rfkill;
121 struct rfkill *bluetooth_rfkill;
122 struct rfkill *wwan3g_rfkill;
123
124 struct eeepc_wmi_debug debug;
125};
126
127/* Only used in eeepc_wmi_init() and eeepc_wmi_exit() */
128static struct platform_device *platform_device;
129
130static int eeepc_wmi_input_init(struct eeepc_wmi *eeepc)
131{
132 int err;
133
134 eeepc->inputdev = input_allocate_device();
135 if (!eeepc->inputdev)
136 return -ENOMEM;
137
138 eeepc->inputdev->name = "Eee PC WMI hotkeys";
139 eeepc->inputdev->phys = EEEPC_WMI_FILE "/input0";
140 eeepc->inputdev->id.bustype = BUS_HOST;
141 eeepc->inputdev->dev.parent = &eeepc->platform_device->dev;
142
143 err = sparse_keymap_setup(eeepc->inputdev, eeepc_wmi_keymap, NULL);
144 if (err)
145 goto err_free_dev;
146
147 err = input_register_device(eeepc->inputdev);
148 if (err)
149 goto err_free_keymap;
150
151 return 0;
152
153err_free_keymap:
154 sparse_keymap_free(eeepc->inputdev);
155err_free_dev:
156 input_free_device(eeepc->inputdev);
157 return err;
158}
159
160static void eeepc_wmi_input_exit(struct eeepc_wmi *eeepc)
161{
162 if (eeepc->inputdev) {
163 sparse_keymap_free(eeepc->inputdev);
164 input_unregister_device(eeepc->inputdev);
165 }
166
167 eeepc->inputdev = NULL;
168}
169
170static acpi_status eeepc_wmi_get_devstate(u32 dev_id, u32 *retval)
171{
172 struct acpi_buffer input = { (acpi_size)sizeof(u32), &dev_id };
173 struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
174 union acpi_object *obj;
175 acpi_status status;
176 u32 tmp;
177
178 status = wmi_evaluate_method(EEEPC_WMI_MGMT_GUID,
179 1, EEEPC_WMI_METHODID_DSTS, &input, &output);
180
181 if (ACPI_FAILURE(status))
182 return status;
183
184 obj = (union acpi_object *)output.pointer;
185 if (obj && obj->type == ACPI_TYPE_INTEGER)
186 tmp = (u32)obj->integer.value;
187 else
188 tmp = 0;
189
190 if (retval)
191 *retval = tmp;
192
193 kfree(obj);
194
195 return status;
196
197}
198
199static acpi_status eeepc_wmi_set_devstate(u32 dev_id, u32 ctrl_param,
200 u32 *retval)
201{
202 struct bios_args args = {
203 .dev_id = dev_id,
204 .ctrl_param = ctrl_param,
205 };
206 struct acpi_buffer input = { (acpi_size)sizeof(args), &args };
207 acpi_status status;
208
209 if (!retval) {
210 status = wmi_evaluate_method(EEEPC_WMI_MGMT_GUID, 1,
211 EEEPC_WMI_METHODID_DEVS,
212 &input, NULL);
213 } else {
214 struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
215 union acpi_object *obj;
216 u32 tmp;
217
218 status = wmi_evaluate_method(EEEPC_WMI_MGMT_GUID, 1,
219 EEEPC_WMI_METHODID_DEVS,
220 &input, &output);
221
222 if (ACPI_FAILURE(status))
223 return status;
224
225 obj = (union acpi_object *)output.pointer;
226 if (obj && obj->type == ACPI_TYPE_INTEGER)
227 tmp = (u32)obj->integer.value;
228 else
229 tmp = 0;
230
231 *retval = tmp;
232
233 kfree(obj);
234 }
235
236 return status;
237}
238
239/*
240 * LEDs
241 */
242/*
243 * These functions actually update the LED's, and are called from a
244 * workqueue. By doing this as separate work rather than when the LED
245 * subsystem asks, we avoid messing with the Eeepc ACPI stuff during a
246 * potentially bad time, such as a timer interrupt.
247 */
248static void tpd_led_update(struct work_struct *work)
249{
250 int ctrl_param;
251 struct eeepc_wmi *eeepc;
252
253 eeepc = container_of(work, struct eeepc_wmi, tpd_led_work);
254
255 ctrl_param = eeepc->tpd_led_wk;
256 eeepc_wmi_set_devstate(EEEPC_WMI_DEVID_TPDLED, ctrl_param, NULL);
257}
258
259static void tpd_led_set(struct led_classdev *led_cdev,
260 enum led_brightness value)
261{
262 struct eeepc_wmi *eeepc;
263
264 eeepc = container_of(led_cdev, struct eeepc_wmi, tpd_led);
265
266 eeepc->tpd_led_wk = !!value;
267 queue_work(eeepc->led_workqueue, &eeepc->tpd_led_work);
268}
269
270static int read_tpd_state(struct eeepc_wmi *eeepc)
271{
272 u32 retval;
273 acpi_status status;
274
275 status = eeepc_wmi_get_devstate(EEEPC_WMI_DEVID_TPDLED, &retval);
276
277 if (ACPI_FAILURE(status))
278 return -1;
279 else if (!retval || retval == 0x00060000)
280 /*
281 * if touchpad led is present, DSTS will set some bits,
282 * usually 0x00020000.
283 * 0x00060000 means that the device is not supported
284 */
285 return -ENODEV;
286 else
287 /* Status is stored in the first bit */
288 return retval & 0x1;
289}
290
291static enum led_brightness tpd_led_get(struct led_classdev *led_cdev)
292{
293 struct eeepc_wmi *eeepc;
294
295 eeepc = container_of(led_cdev, struct eeepc_wmi, tpd_led);
296
297 return read_tpd_state(eeepc);
298}
299
300static int eeepc_wmi_led_init(struct eeepc_wmi *eeepc)
301{
302 int rv;
303
304 if (read_tpd_state(eeepc) < 0)
305 return 0;
306
307 eeepc->led_workqueue = create_singlethread_workqueue("led_workqueue");
308 if (!eeepc->led_workqueue)
309 return -ENOMEM;
310 INIT_WORK(&eeepc->tpd_led_work, tpd_led_update);
311
312 eeepc->tpd_led.name = "eeepc::touchpad";
313 eeepc->tpd_led.brightness_set = tpd_led_set;
314 eeepc->tpd_led.brightness_get = tpd_led_get;
315 eeepc->tpd_led.max_brightness = 1;
316
317 rv = led_classdev_register(&eeepc->platform_device->dev,
318 &eeepc->tpd_led);
319 if (rv) {
320 destroy_workqueue(eeepc->led_workqueue);
321 return rv;
322 }
323
324 return 0;
325}
326
327static void eeepc_wmi_led_exit(struct eeepc_wmi *eeepc)
328{
329 if (eeepc->tpd_led.dev)
330 led_classdev_unregister(&eeepc->tpd_led);
331 if (eeepc->led_workqueue)
332 destroy_workqueue(eeepc->led_workqueue);
333}
334
335/*
336 * Rfkill devices
337 */
338static int eeepc_rfkill_set(void *data, bool blocked)
339{
340 int dev_id = (unsigned long)data;
341 u32 ctrl_param = !blocked;
342
343 return eeepc_wmi_set_devstate(dev_id, ctrl_param, NULL);
344}
345
346static void eeepc_rfkill_query(struct rfkill *rfkill, void *data)
347{
348 int dev_id = (unsigned long)data;
349 u32 retval;
350 acpi_status status;
351
352 status = eeepc_wmi_get_devstate(dev_id, &retval);
353
354 if (ACPI_FAILURE(status))
355 return ;
356
357 rfkill_set_sw_state(rfkill, !(retval & 0x1));
358}
359
360static const struct rfkill_ops eeepc_rfkill_ops = {
361 .set_block = eeepc_rfkill_set,
362 .query = eeepc_rfkill_query,
363};
364
365static int eeepc_new_rfkill(struct eeepc_wmi *eeepc,
366 struct rfkill **rfkill,
367 const char *name,
368 enum rfkill_type type, int dev_id)
369{
370 int result;
371 u32 retval;
372 acpi_status status;
373
374 status = eeepc_wmi_get_devstate(dev_id, &retval);
375
376 if (ACPI_FAILURE(status))
377 return -1;
378
379 /* If the device is present, DSTS will always set some bits
380 * 0x00070000 - 1110000000000000000 - device supported
381 * 0x00060000 - 1100000000000000000 - not supported
382 * 0x00020000 - 0100000000000000000 - device supported
383 * 0x00010000 - 0010000000000000000 - not supported / special mode ?
384 */
385 if (!retval || retval == 0x00060000)
386 return -ENODEV;
387
388 *rfkill = rfkill_alloc(name, &eeepc->platform_device->dev, type,
389 &eeepc_rfkill_ops, (void *)(long)dev_id);
390
391 if (!*rfkill)
392 return -EINVAL;
393
394 rfkill_init_sw_state(*rfkill, !(retval & 0x1));
395 result = rfkill_register(*rfkill);
396 if (result) {
397 rfkill_destroy(*rfkill);
398 *rfkill = NULL;
399 return result;
400 }
401 return 0;
402}
403
404static void eeepc_wmi_rfkill_exit(struct eeepc_wmi *eeepc)
405{
406 if (eeepc->wlan_rfkill) {
407 rfkill_unregister(eeepc->wlan_rfkill);
408 rfkill_destroy(eeepc->wlan_rfkill);
409 eeepc->wlan_rfkill = NULL;
410 }
411 if (eeepc->bluetooth_rfkill) {
412 rfkill_unregister(eeepc->bluetooth_rfkill);
413 rfkill_destroy(eeepc->bluetooth_rfkill);
414 eeepc->bluetooth_rfkill = NULL;
415 }
416 if (eeepc->wwan3g_rfkill) {
417 rfkill_unregister(eeepc->wwan3g_rfkill);
418 rfkill_destroy(eeepc->wwan3g_rfkill);
419 eeepc->wwan3g_rfkill = NULL;
420 }
421}
422
423static int eeepc_wmi_rfkill_init(struct eeepc_wmi *eeepc)
424{
425 int result = 0;
426
427 result = eeepc_new_rfkill(eeepc, &eeepc->wlan_rfkill,
428 "eeepc-wlan", RFKILL_TYPE_WLAN,
429 EEEPC_WMI_DEVID_WLAN);
430
431 if (result && result != -ENODEV)
432 goto exit;
433
434 result = eeepc_new_rfkill(eeepc, &eeepc->bluetooth_rfkill,
435 "eeepc-bluetooth", RFKILL_TYPE_BLUETOOTH,
436 EEEPC_WMI_DEVID_BLUETOOTH);
437
438 if (result && result != -ENODEV)
439 goto exit;
440
441 result = eeepc_new_rfkill(eeepc, &eeepc->wwan3g_rfkill,
442 "eeepc-wwan3g", RFKILL_TYPE_WWAN,
443 EEEPC_WMI_DEVID_WWAN3G);
444
445 if (result && result != -ENODEV)
446 goto exit;
447
448exit:
449 if (result && result != -ENODEV)
450 eeepc_wmi_rfkill_exit(eeepc);
451
452 if (result == -ENODEV)
453 result = 0;
454
455 return result;
456}
457
458/*
459 * Backlight
460 */
461static int read_brightness(struct backlight_device *bd)
462{
463 u32 retval;
464 acpi_status status;
465
466 status = eeepc_wmi_get_devstate(EEEPC_WMI_DEVID_BACKLIGHT, &retval);
467
468 if (ACPI_FAILURE(status))
469 return -1;
470 else
471 return retval & 0xFF;
472}
473
474static int update_bl_status(struct backlight_device *bd)
475{
476
477 u32 ctrl_param;
478 acpi_status status;
479
480 ctrl_param = bd->props.brightness;
481
482 status = eeepc_wmi_set_devstate(EEEPC_WMI_DEVID_BACKLIGHT,
483 ctrl_param, NULL);
484
485 if (ACPI_FAILURE(status))
486 return -1;
487 else
488 return 0;
489}
490
491static const struct backlight_ops eeepc_wmi_bl_ops = {
492 .get_brightness = read_brightness,
493 .update_status = update_bl_status,
494};
495
496static int eeepc_wmi_backlight_notify(struct eeepc_wmi *eeepc, int code)
497{
498 struct backlight_device *bd = eeepc->backlight_device;
499 int old = bd->props.brightness;
500 int new = old;
501
502 if (code >= NOTIFY_BRNUP_MIN && code <= NOTIFY_BRNUP_MAX)
503 new = code - NOTIFY_BRNUP_MIN + 1;
504 else if (code >= NOTIFY_BRNDOWN_MIN && code <= NOTIFY_BRNDOWN_MAX)
505 new = code - NOTIFY_BRNDOWN_MIN;
506
507 bd->props.brightness = new;
508 backlight_update_status(bd);
509 backlight_force_update(bd, BACKLIGHT_UPDATE_HOTKEY);
510
511 return old;
512}
513
514static int eeepc_wmi_backlight_init(struct eeepc_wmi *eeepc)
515{
516 struct backlight_device *bd;
517 struct backlight_properties props;
518
519 memset(&props, 0, sizeof(struct backlight_properties));
520 props.max_brightness = 15;
521 bd = backlight_device_register(EEEPC_WMI_FILE,
522 &eeepc->platform_device->dev, eeepc,
523 &eeepc_wmi_bl_ops, &props);
524 if (IS_ERR(bd)) {
525 pr_err("Could not register backlight device\n");
526 return PTR_ERR(bd);
527 }
528
529 eeepc->backlight_device = bd;
530
531 bd->props.brightness = read_brightness(bd);
532 bd->props.power = FB_BLANK_UNBLANK;
533 backlight_update_status(bd);
534
535 return 0;
536}
537
538static void eeepc_wmi_backlight_exit(struct eeepc_wmi *eeepc)
539{
540 if (eeepc->backlight_device)
541 backlight_device_unregister(eeepc->backlight_device);
542
543 eeepc->backlight_device = NULL;
544}
545
546static void eeepc_wmi_notify(u32 value, void *context)
547{
548 struct eeepc_wmi *eeepc = context;
549 struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL };
550 union acpi_object *obj;
551 acpi_status status;
552 int code;
553 int orig_code;
554
555 status = wmi_get_event_data(value, &response);
556 if (status != AE_OK) {
557 pr_err("bad event status 0x%x\n", status);
558 return;
559 }
560
561 obj = (union acpi_object *)response.pointer;
562
563 if (obj && obj->type == ACPI_TYPE_INTEGER) {
564 code = obj->integer.value;
565 orig_code = code;
566
567 if (code >= NOTIFY_BRNUP_MIN && code <= NOTIFY_BRNUP_MAX)
568 code = NOTIFY_BRNUP_MIN;
569 else if (code >= NOTIFY_BRNDOWN_MIN &&
570 code <= NOTIFY_BRNDOWN_MAX)
571 code = NOTIFY_BRNDOWN_MIN;
572
573 if (code == NOTIFY_BRNUP_MIN || code == NOTIFY_BRNDOWN_MIN) {
574 if (!acpi_video_backlight_support())
575 eeepc_wmi_backlight_notify(eeepc, orig_code);
576 }
577
578 if (!sparse_keymap_report_event(eeepc->inputdev,
579 code, 1, true))
580 pr_info("Unknown key %x pressed\n", code);
581 }
582
583 kfree(obj);
584}
585
586static ssize_t store_cpufv(struct device *dev, struct device_attribute *attr,
587 const char *buf, size_t count)
588{
589 int value;
590 struct acpi_buffer input = { (acpi_size)sizeof(value), &value };
591 acpi_status status;
592
593 if (!count || sscanf(buf, "%i", &value) != 1)
594 return -EINVAL;
595 if (value < 0 || value > 2)
596 return -EINVAL;
597
598 status = wmi_evaluate_method(EEEPC_WMI_MGMT_GUID,
599 1, EEEPC_WMI_METHODID_CFVS, &input, NULL);
600
601 if (ACPI_FAILURE(status))
602 return -EIO;
603 else
604 return count;
605}
606
607static DEVICE_ATTR(cpufv, S_IRUGO | S_IWUSR, NULL, store_cpufv);
608
609static struct attribute *platform_attributes[] = {
610 &dev_attr_cpufv.attr,
611 NULL
612};
613
614static struct attribute_group platform_attribute_group = {
615 .attrs = platform_attributes
616};
617
618static void eeepc_wmi_sysfs_exit(struct platform_device *device)
619{
620 sysfs_remove_group(&device->dev.kobj, &platform_attribute_group);
621}
622
623static int eeepc_wmi_sysfs_init(struct platform_device *device)
624{
625 return sysfs_create_group(&device->dev.kobj, &platform_attribute_group);
626}
627
628/*
629 * Platform device
630 */
631static int __init eeepc_wmi_platform_init(struct eeepc_wmi *eeepc)
632{
633 int err;
634
635 eeepc->platform_device = platform_device_alloc(EEEPC_WMI_FILE, -1);
636 if (!eeepc->platform_device)
637 return -ENOMEM;
638 platform_set_drvdata(eeepc->platform_device, eeepc);
639
640 err = platform_device_add(eeepc->platform_device);
641 if (err)
642 goto fail_platform_device;
643
644 err = eeepc_wmi_sysfs_init(eeepc->platform_device);
645 if (err)
646 goto fail_sysfs;
647 return 0;
648
649fail_sysfs:
650 platform_device_del(eeepc->platform_device);
651fail_platform_device:
652 platform_device_put(eeepc->platform_device);
653 return err;
654}
655
656static void eeepc_wmi_platform_exit(struct eeepc_wmi *eeepc)
657{
658 eeepc_wmi_sysfs_exit(eeepc->platform_device);
659 platform_device_unregister(eeepc->platform_device);
660}
661
662/*
663 * debugfs
664 */
665struct eeepc_wmi_debugfs_node {
666 struct eeepc_wmi *eeepc;
667 char *name;
668 int (*show)(struct seq_file *m, void *data);
669};
670
671static int show_dsts(struct seq_file *m, void *data)
672{
673 struct eeepc_wmi *eeepc = m->private;
674 acpi_status status;
675 u32 retval = -1;
676
677 status = eeepc_wmi_get_devstate(eeepc->debug.dev_id, &retval);
678
679 if (ACPI_FAILURE(status))
680 return -EIO;
681
682 seq_printf(m, "DSTS(%x) = %x\n", eeepc->debug.dev_id, retval);
683
684 return 0;
685}
686
687static int show_devs(struct seq_file *m, void *data)
688{
689 struct eeepc_wmi *eeepc = m->private;
690 acpi_status status;
691 u32 retval = -1;
692
693 status = eeepc_wmi_set_devstate(eeepc->debug.dev_id,
694 eeepc->debug.ctrl_param, &retval);
695 if (ACPI_FAILURE(status))
696 return -EIO;
697
698 seq_printf(m, "DEVS(%x, %x) = %x\n", eeepc->debug.dev_id,
699 eeepc->debug.ctrl_param, retval);
700
701 return 0;
702}
703
704static struct eeepc_wmi_debugfs_node eeepc_wmi_debug_files[] = {
705 { NULL, "devs", show_devs },
706 { NULL, "dsts", show_dsts },
707};
708
709static int eeepc_wmi_debugfs_open(struct inode *inode, struct file *file)
710{
711 struct eeepc_wmi_debugfs_node *node = inode->i_private;
712
713 return single_open(file, node->show, node->eeepc);
714}
715
716static const struct file_operations eeepc_wmi_debugfs_io_ops = {
717 .owner = THIS_MODULE,
718 .open = eeepc_wmi_debugfs_open,
719 .read = seq_read,
720 .llseek = seq_lseek,
721 .release = single_release,
722};
723
724static void eeepc_wmi_debugfs_exit(struct eeepc_wmi *eeepc)
725{
726 debugfs_remove_recursive(eeepc->debug.root);
727}
728
729static int eeepc_wmi_debugfs_init(struct eeepc_wmi *eeepc)
730{
731 struct dentry *dent;
732 int i;
733
734 eeepc->debug.root = debugfs_create_dir(EEEPC_WMI_FILE, NULL);
735 if (!eeepc->debug.root) {
736 pr_err("failed to create debugfs directory");
737 goto error_debugfs;
738 }
739
740 dent = debugfs_create_x32("dev_id", S_IRUGO|S_IWUSR,
741 eeepc->debug.root, &eeepc->debug.dev_id);
742 if (!dent)
743 goto error_debugfs;
744
745 dent = debugfs_create_x32("ctrl_param", S_IRUGO|S_IWUSR,
746 eeepc->debug.root, &eeepc->debug.ctrl_param);
747 if (!dent)
748 goto error_debugfs;
749
750 for (i = 0; i < ARRAY_SIZE(eeepc_wmi_debug_files); i++) {
751 struct eeepc_wmi_debugfs_node *node = &eeepc_wmi_debug_files[i];
752
753 node->eeepc = eeepc;
754 dent = debugfs_create_file(node->name, S_IFREG | S_IRUGO,
755 eeepc->debug.root, node,
756 &eeepc_wmi_debugfs_io_ops);
757 if (!dent) {
758 pr_err("failed to create debug file: %s\n", node->name);
759 goto error_debugfs;
760 }
761 }
762
763 return 0;
764
765error_debugfs:
766 eeepc_wmi_debugfs_exit(eeepc);
767 return -ENOMEM;
768}
769
770/*
771 * WMI Driver
772 */
773static struct platform_device * __init eeepc_wmi_add(void)
774{
775 struct eeepc_wmi *eeepc;
776 acpi_status status;
777 int err;
778
779 eeepc = kzalloc(sizeof(struct eeepc_wmi), GFP_KERNEL);
780 if (!eeepc)
781 return ERR_PTR(-ENOMEM);
782
783 /*
784 * Register the platform device first. It is used as a parent for the
785 * sub-devices below.
786 */
787 err = eeepc_wmi_platform_init(eeepc);
788 if (err)
789 goto fail_platform;
790
791 err = eeepc_wmi_input_init(eeepc);
792 if (err)
793 goto fail_input;
794
795 err = eeepc_wmi_led_init(eeepc);
796 if (err)
797 goto fail_leds;
798
799 err = eeepc_wmi_rfkill_init(eeepc);
800 if (err)
801 goto fail_rfkill;
802
803 if (!acpi_video_backlight_support()) {
804 err = eeepc_wmi_backlight_init(eeepc);
805 if (err)
806 goto fail_backlight;
807 } else
808 pr_info("Backlight controlled by ACPI video driver\n");
809
810 status = wmi_install_notify_handler(EEEPC_WMI_EVENT_GUID,
811 eeepc_wmi_notify, eeepc);
812 if (ACPI_FAILURE(status)) {
813 pr_err("Unable to register notify handler - %d\n",
814 status);
815 err = -ENODEV;
816 goto fail_wmi_handler;
817 }
818
819 err = eeepc_wmi_debugfs_init(eeepc);
820 if (err)
821 goto fail_debugfs;
822
823 return eeepc->platform_device;
824
825fail_debugfs:
826 wmi_remove_notify_handler(EEEPC_WMI_EVENT_GUID);
827fail_wmi_handler:
828 eeepc_wmi_backlight_exit(eeepc);
829fail_backlight:
830 eeepc_wmi_rfkill_exit(eeepc);
831fail_rfkill:
832 eeepc_wmi_led_exit(eeepc);
833fail_leds:
834 eeepc_wmi_input_exit(eeepc);
835fail_input:
836 eeepc_wmi_platform_exit(eeepc);
837fail_platform:
838 kfree(eeepc);
839 return ERR_PTR(err);
840}
841
842static int eeepc_wmi_remove(struct platform_device *device)
843{
844 struct eeepc_wmi *eeepc;
845
846 eeepc = platform_get_drvdata(device);
847 wmi_remove_notify_handler(EEEPC_WMI_EVENT_GUID);
848 eeepc_wmi_backlight_exit(eeepc);
849 eeepc_wmi_input_exit(eeepc);
850 eeepc_wmi_led_exit(eeepc);
851 eeepc_wmi_rfkill_exit(eeepc);
852 eeepc_wmi_debugfs_exit(eeepc);
853 eeepc_wmi_platform_exit(eeepc);
854
855 kfree(eeepc);
856 return 0;
857}
858
859static struct platform_driver platform_driver = {
860 .driver = {
861 .name = EEEPC_WMI_FILE,
862 .owner = THIS_MODULE,
863 },
864};
865
866static acpi_status __init eeepc_wmi_parse_device(acpi_handle handle, u32 level,
867 void *context, void **retval) 83 void *context, void **retval)
868{ 84{
869 pr_warning("Found legacy ATKD device (%s)", EEEPC_ACPI_HID); 85 pr_warning("Found legacy ATKD device (%s)", EEEPC_ACPI_HID);
@@ -871,7 +87,7 @@ static acpi_status __init eeepc_wmi_parse_device(acpi_handle handle, u32 level,
871 return AE_CTRL_TERMINATE; 87 return AE_CTRL_TERMINATE;
872} 88}
873 89
874static int __init eeepc_wmi_check_atkd(void) 90static int eeepc_wmi_check_atkd(void)
875{ 91{
876 acpi_status status; 92 acpi_status status;
877 bool found = false; 93 bool found = false;
@@ -884,16 +100,8 @@ static int __init eeepc_wmi_check_atkd(void)
884 return -1; 100 return -1;
885} 101}
886 102
887static int __init eeepc_wmi_init(void) 103static int eeepc_wmi_probe(struct platform_device *pdev)
888{ 104{
889 int err;
890
891 if (!wmi_has_guid(EEEPC_WMI_EVENT_GUID) ||
892 !wmi_has_guid(EEEPC_WMI_MGMT_GUID)) {
893 pr_warning("No known WMI GUID found\n");
894 return -ENODEV;
895 }
896
897 if (eeepc_wmi_check_atkd()) { 105 if (eeepc_wmi_check_atkd()) {
898 pr_warning("WMI device present, but legacy ATKD device is also " 106 pr_warning("WMI device present, but legacy ATKD device is also "
899 "present and enabled."); 107 "present and enabled.");
@@ -901,33 +109,59 @@ static int __init eeepc_wmi_init(void)
901 "acpi_osi=\"!Windows 2009\""); 109 "acpi_osi=\"!Windows 2009\"");
902 pr_warning("Can't load eeepc-wmi, use default acpi_osi " 110 pr_warning("Can't load eeepc-wmi, use default acpi_osi "
903 "(preferred) or eeepc-laptop"); 111 "(preferred) or eeepc-laptop");
904 return -ENODEV; 112 return -EBUSY;
905 } 113 }
114 return 0;
115}
906 116
907 platform_device = eeepc_wmi_add(); 117static void eeepc_dmi_check(struct asus_wmi_driver *driver)
908 if (IS_ERR(platform_device)) { 118{
909 err = PTR_ERR(platform_device); 119 const char *model;
910 goto fail_eeepc_wmi; 120
911 } 121 model = dmi_get_system_info(DMI_PRODUCT_NAME);
122 if (!model)
123 return;
912 124
913 err = platform_driver_register(&platform_driver); 125 /*
914 if (err) { 126 * Whitelist for wlan hotplug
915 pr_warning("Unable to register platform driver\n"); 127 *
916 goto fail_platform_driver; 128 * Asus 1000H needs the current hotplug code to handle
129 * Fn+F2 correctly. We may add other Asus here later, but
130 * it seems that most of the laptops supported by asus-wmi
131 * don't need to be on this list
132 */
133 if (strcmp(model, "1000H") == 0) {
134 driver->hotplug_wireless = true;
135 pr_info("wlan hotplug enabled\n");
917 } 136 }
137}
138
139static void eeepc_wmi_quirks(struct asus_wmi_driver *driver)
140{
141 driver->hotplug_wireless = hotplug_wireless;
142 eeepc_dmi_check(driver);
143}
144
145static struct asus_wmi_driver asus_wmi_driver = {
146 .name = EEEPC_WMI_FILE,
147 .owner = THIS_MODULE,
148 .event_guid = EEEPC_WMI_EVENT_GUID,
149 .keymap = eeepc_wmi_keymap,
150 .input_name = "Eee PC WMI hotkeys",
151 .input_phys = EEEPC_WMI_FILE "/input0",
152 .probe = eeepc_wmi_probe,
153 .quirks = eeepc_wmi_quirks,
154};
918 155
919 return 0;
920 156
921fail_platform_driver: 157static int __init eeepc_wmi_init(void)
922 eeepc_wmi_remove(platform_device); 158{
923fail_eeepc_wmi: 159 return asus_wmi_register_driver(&asus_wmi_driver);
924 return err;
925} 160}
926 161
927static void __exit eeepc_wmi_exit(void) 162static void __exit eeepc_wmi_exit(void)
928{ 163{
929 eeepc_wmi_remove(platform_device); 164 asus_wmi_unregister_driver(&asus_wmi_driver);
930 platform_driver_unregister(&platform_driver);
931} 165}
932 166
933module_init(eeepc_wmi_init); 167module_init(eeepc_wmi_init);
diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c
index 9e05af9c41cb..1bc4a7539ba9 100644
--- a/drivers/platform/x86/hp-wmi.c
+++ b/drivers/platform/x86/hp-wmi.c
@@ -2,6 +2,7 @@
2 * HP WMI hotkeys 2 * HP WMI hotkeys
3 * 3 *
4 * Copyright (C) 2008 Red Hat <mjg@redhat.com> 4 * Copyright (C) 2008 Red Hat <mjg@redhat.com>
5 * Copyright (C) 2010, 2011 Anssi Hannula <anssi.hannula@iki.fi>
5 * 6 *
6 * Portions based on wistron_btns.c: 7 * Portions based on wistron_btns.c:
7 * Copyright (C) 2005 Miloslav Trmac <mitr@volny.cz> 8 * Copyright (C) 2005 Miloslav Trmac <mitr@volny.cz>
@@ -51,6 +52,7 @@ MODULE_ALIAS("wmi:5FB7F034-2C63-45e9-BE91-3D44E2C707E4");
51#define HPWMI_HARDWARE_QUERY 0x4 52#define HPWMI_HARDWARE_QUERY 0x4
52#define HPWMI_WIRELESS_QUERY 0x5 53#define HPWMI_WIRELESS_QUERY 0x5
53#define HPWMI_HOTKEY_QUERY 0xc 54#define HPWMI_HOTKEY_QUERY 0xc
55#define HPWMI_WIRELESS2_QUERY 0x1b
54 56
55#define PREFIX "HP WMI: " 57#define PREFIX "HP WMI: "
56#define UNIMP "Unimplemented " 58#define UNIMP "Unimplemented "
@@ -86,7 +88,46 @@ struct bios_args {
86struct bios_return { 88struct bios_return {
87 u32 sigpass; 89 u32 sigpass;
88 u32 return_code; 90 u32 return_code;
89 u32 value; 91};
92
93enum hp_return_value {
94 HPWMI_RET_WRONG_SIGNATURE = 0x02,
95 HPWMI_RET_UNKNOWN_COMMAND = 0x03,
96 HPWMI_RET_UNKNOWN_CMDTYPE = 0x04,
97 HPWMI_RET_INVALID_PARAMETERS = 0x05,
98};
99
100enum hp_wireless2_bits {
101 HPWMI_POWER_STATE = 0x01,
102 HPWMI_POWER_SOFT = 0x02,
103 HPWMI_POWER_BIOS = 0x04,
104 HPWMI_POWER_HARD = 0x08,
105};
106
107#define IS_HWBLOCKED(x) ((x & (HPWMI_POWER_BIOS | HPWMI_POWER_HARD)) \
108 != (HPWMI_POWER_BIOS | HPWMI_POWER_HARD))
109#define IS_SWBLOCKED(x) !(x & HPWMI_POWER_SOFT)
110
111struct bios_rfkill2_device_state {
112 u8 radio_type;
113 u8 bus_type;
114 u16 vendor_id;
115 u16 product_id;
116 u16 subsys_vendor_id;
117 u16 subsys_product_id;
118 u8 rfkill_id;
119 u8 power;
120 u8 unknown[4];
121};
122
123/* 7 devices fit into the 128 byte buffer */
124#define HPWMI_MAX_RFKILL2_DEVICES 7
125
126struct bios_rfkill2_state {
127 u8 unknown[7];
128 u8 count;
129 u8 pad[8];
130 struct bios_rfkill2_device_state device[HPWMI_MAX_RFKILL2_DEVICES];
90}; 131};
91 132
92static const struct key_entry hp_wmi_keymap[] = { 133static const struct key_entry hp_wmi_keymap[] = {
@@ -108,6 +149,15 @@ static struct rfkill *wifi_rfkill;
108static struct rfkill *bluetooth_rfkill; 149static struct rfkill *bluetooth_rfkill;
109static struct rfkill *wwan_rfkill; 150static struct rfkill *wwan_rfkill;
110 151
152struct rfkill2_device {
153 u8 id;
154 int num;
155 struct rfkill *rfkill;
156};
157
158static int rfkill2_count;
159static struct rfkill2_device rfkill2[HPWMI_MAX_RFKILL2_DEVICES];
160
111static const struct dev_pm_ops hp_wmi_pm_ops = { 161static const struct dev_pm_ops hp_wmi_pm_ops = {
112 .resume = hp_wmi_resume_handler, 162 .resume = hp_wmi_resume_handler,
113 .restore = hp_wmi_resume_handler, 163 .restore = hp_wmi_resume_handler,
@@ -129,7 +179,8 @@ static struct platform_driver hp_wmi_driver = {
129 * query: The commandtype -> What should be queried 179 * query: The commandtype -> What should be queried
130 * write: The command -> 0 read, 1 write, 3 ODM specific 180 * write: The command -> 0 read, 1 write, 3 ODM specific
131 * buffer: Buffer used as input and/or output 181 * buffer: Buffer used as input and/or output
132 * buffersize: Size of buffer 182 * insize: Size of input buffer
183 * outsize: Size of output buffer
133 * 184 *
134 * returns zero on success 185 * returns zero on success
135 * an HP WMI query specific error code (which is positive) 186 * an HP WMI query specific error code (which is positive)
@@ -140,25 +191,29 @@ static struct platform_driver hp_wmi_driver = {
140 * size. E.g. Battery info query (0x7) is defined to have 1 byte input 191 * size. E.g. Battery info query (0x7) is defined to have 1 byte input
141 * and 128 byte output. The caller would do: 192 * and 128 byte output. The caller would do:
142 * buffer = kzalloc(128, GFP_KERNEL); 193 * buffer = kzalloc(128, GFP_KERNEL);
143 * ret = hp_wmi_perform_query(0x7, 0, buffer, 128) 194 * ret = hp_wmi_perform_query(0x7, 0, buffer, 1, 128)
144 */ 195 */
145static int hp_wmi_perform_query(int query, int write, u32 *buffer, 196static int hp_wmi_perform_query(int query, int write, void *buffer,
146 int buffersize) 197 int insize, int outsize)
147{ 198{
148 struct bios_return bios_return; 199 struct bios_return *bios_return;
149 acpi_status status; 200 int actual_outsize;
150 union acpi_object *obj; 201 union acpi_object *obj;
151 struct bios_args args = { 202 struct bios_args args = {
152 .signature = 0x55434553, 203 .signature = 0x55434553,
153 .command = write ? 0x2 : 0x1, 204 .command = write ? 0x2 : 0x1,
154 .commandtype = query, 205 .commandtype = query,
155 .datasize = buffersize, 206 .datasize = insize,
156 .data = *buffer, 207 .data = 0,
157 }; 208 };
158 struct acpi_buffer input = { sizeof(struct bios_args), &args }; 209 struct acpi_buffer input = { sizeof(struct bios_args), &args };
159 struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; 210 struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
160 211
161 status = wmi_evaluate_method(HPWMI_BIOS_GUID, 0, 0x3, &input, &output); 212 if (WARN_ON(insize > sizeof(args.data)))
213 return -EINVAL;
214 memcpy(&args.data, buffer, insize);
215
216 wmi_evaluate_method(HPWMI_BIOS_GUID, 0, 0x3, &input, &output);
162 217
163 obj = output.pointer; 218 obj = output.pointer;
164 219
@@ -169,10 +224,26 @@ static int hp_wmi_perform_query(int query, int write, u32 *buffer,
169 return -EINVAL; 224 return -EINVAL;
170 } 225 }
171 226
172 bios_return = *((struct bios_return *)obj->buffer.pointer); 227 bios_return = (struct bios_return *)obj->buffer.pointer;
173 228
174 memcpy(buffer, &bios_return.value, sizeof(bios_return.value)); 229 if (bios_return->return_code) {
230 if (bios_return->return_code != HPWMI_RET_UNKNOWN_CMDTYPE)
231 printk(KERN_WARNING PREFIX "query 0x%x returned "
232 "error 0x%x\n",
233 query, bios_return->return_code);
234 kfree(obj);
235 return bios_return->return_code;
236 }
237
238 if (!outsize) {
239 /* ignore output data */
240 kfree(obj);
241 return 0;
242 }
175 243
244 actual_outsize = min(outsize, (int)(obj->buffer.length - sizeof(*bios_return)));
245 memcpy(buffer, obj->buffer.pointer + sizeof(*bios_return), actual_outsize);
246 memset(buffer + actual_outsize, 0, outsize - actual_outsize);
176 kfree(obj); 247 kfree(obj);
177 return 0; 248 return 0;
178} 249}
@@ -181,7 +252,7 @@ static int hp_wmi_display_state(void)
181{ 252{
182 int state = 0; 253 int state = 0;
183 int ret = hp_wmi_perform_query(HPWMI_DISPLAY_QUERY, 0, &state, 254 int ret = hp_wmi_perform_query(HPWMI_DISPLAY_QUERY, 0, &state,
184 sizeof(state)); 255 sizeof(state), sizeof(state));
185 if (ret) 256 if (ret)
186 return -EINVAL; 257 return -EINVAL;
187 return state; 258 return state;
@@ -191,7 +262,7 @@ static int hp_wmi_hddtemp_state(void)
191{ 262{
192 int state = 0; 263 int state = 0;
193 int ret = hp_wmi_perform_query(HPWMI_HDDTEMP_QUERY, 0, &state, 264 int ret = hp_wmi_perform_query(HPWMI_HDDTEMP_QUERY, 0, &state,
194 sizeof(state)); 265 sizeof(state), sizeof(state));
195 if (ret) 266 if (ret)
196 return -EINVAL; 267 return -EINVAL;
197 return state; 268 return state;
@@ -201,7 +272,7 @@ static int hp_wmi_als_state(void)
201{ 272{
202 int state = 0; 273 int state = 0;
203 int ret = hp_wmi_perform_query(HPWMI_ALS_QUERY, 0, &state, 274 int ret = hp_wmi_perform_query(HPWMI_ALS_QUERY, 0, &state,
204 sizeof(state)); 275 sizeof(state), sizeof(state));
205 if (ret) 276 if (ret)
206 return -EINVAL; 277 return -EINVAL;
207 return state; 278 return state;
@@ -211,7 +282,7 @@ static int hp_wmi_dock_state(void)
211{ 282{
212 int state = 0; 283 int state = 0;
213 int ret = hp_wmi_perform_query(HPWMI_HARDWARE_QUERY, 0, &state, 284 int ret = hp_wmi_perform_query(HPWMI_HARDWARE_QUERY, 0, &state,
214 sizeof(state)); 285 sizeof(state), sizeof(state));
215 286
216 if (ret) 287 if (ret)
217 return -EINVAL; 288 return -EINVAL;
@@ -223,7 +294,7 @@ static int hp_wmi_tablet_state(void)
223{ 294{
224 int state = 0; 295 int state = 0;
225 int ret = hp_wmi_perform_query(HPWMI_HARDWARE_QUERY, 0, &state, 296 int ret = hp_wmi_perform_query(HPWMI_HARDWARE_QUERY, 0, &state,
226 sizeof(state)); 297 sizeof(state), sizeof(state));
227 if (ret) 298 if (ret)
228 return ret; 299 return ret;
229 300
@@ -237,7 +308,7 @@ static int hp_wmi_set_block(void *data, bool blocked)
237 int ret; 308 int ret;
238 309
239 ret = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, 310 ret = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1,
240 &query, sizeof(query)); 311 &query, sizeof(query), 0);
241 if (ret) 312 if (ret)
242 return -EINVAL; 313 return -EINVAL;
243 return 0; 314 return 0;
@@ -252,7 +323,8 @@ static bool hp_wmi_get_sw_state(enum hp_wmi_radio r)
252 int wireless = 0; 323 int wireless = 0;
253 int mask; 324 int mask;
254 hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 325 hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0,
255 &wireless, sizeof(wireless)); 326 &wireless, sizeof(wireless),
327 sizeof(wireless));
256 /* TBD: Pass error */ 328 /* TBD: Pass error */
257 329
258 mask = 0x200 << (r * 8); 330 mask = 0x200 << (r * 8);
@@ -268,7 +340,8 @@ static bool hp_wmi_get_hw_state(enum hp_wmi_radio r)
268 int wireless = 0; 340 int wireless = 0;
269 int mask; 341 int mask;
270 hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 342 hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0,
271 &wireless, sizeof(wireless)); 343 &wireless, sizeof(wireless),
344 sizeof(wireless));
272 /* TBD: Pass error */ 345 /* TBD: Pass error */
273 346
274 mask = 0x800 << (r * 8); 347 mask = 0x800 << (r * 8);
@@ -279,6 +352,51 @@ static bool hp_wmi_get_hw_state(enum hp_wmi_radio r)
279 return true; 352 return true;
280} 353}
281 354
355static int hp_wmi_rfkill2_set_block(void *data, bool blocked)
356{
357 int rfkill_id = (int)(long)data;
358 char buffer[4] = { 0x01, 0x00, rfkill_id, !blocked };
359
360 if (hp_wmi_perform_query(HPWMI_WIRELESS2_QUERY, 1,
361 buffer, sizeof(buffer), 0))
362 return -EINVAL;
363 return 0;
364}
365
366static const struct rfkill_ops hp_wmi_rfkill2_ops = {
367 .set_block = hp_wmi_rfkill2_set_block,
368};
369
370static int hp_wmi_rfkill2_refresh(void)
371{
372 int err, i;
373 struct bios_rfkill2_state state;
374
375 err = hp_wmi_perform_query(HPWMI_WIRELESS2_QUERY, 0, &state,
376 0, sizeof(state));
377 if (err)
378 return err;
379
380 for (i = 0; i < rfkill2_count; i++) {
381 int num = rfkill2[i].num;
382 struct bios_rfkill2_device_state *devstate;
383 devstate = &state.device[num];
384
385 if (num >= state.count ||
386 devstate->rfkill_id != rfkill2[i].id) {
387 printk(KERN_WARNING PREFIX "power configuration of "
388 "the wireless devices unexpectedly changed\n");
389 continue;
390 }
391
392 rfkill_set_states(rfkill2[i].rfkill,
393 IS_SWBLOCKED(devstate->power),
394 IS_HWBLOCKED(devstate->power));
395 }
396
397 return 0;
398}
399
282static ssize_t show_display(struct device *dev, struct device_attribute *attr, 400static ssize_t show_display(struct device *dev, struct device_attribute *attr,
283 char *buf) 401 char *buf)
284{ 402{
@@ -329,7 +447,7 @@ static ssize_t set_als(struct device *dev, struct device_attribute *attr,
329{ 447{
330 u32 tmp = simple_strtoul(buf, NULL, 10); 448 u32 tmp = simple_strtoul(buf, NULL, 10);
331 int ret = hp_wmi_perform_query(HPWMI_ALS_QUERY, 1, &tmp, 449 int ret = hp_wmi_perform_query(HPWMI_ALS_QUERY, 1, &tmp,
332 sizeof(tmp)); 450 sizeof(tmp), sizeof(tmp));
333 if (ret) 451 if (ret)
334 return -EINVAL; 452 return -EINVAL;
335 453
@@ -402,6 +520,7 @@ static void hp_wmi_notify(u32 value, void *context)
402 case HPWMI_BEZEL_BUTTON: 520 case HPWMI_BEZEL_BUTTON:
403 ret = hp_wmi_perform_query(HPWMI_HOTKEY_QUERY, 0, 521 ret = hp_wmi_perform_query(HPWMI_HOTKEY_QUERY, 0,
404 &key_code, 522 &key_code,
523 sizeof(key_code),
405 sizeof(key_code)); 524 sizeof(key_code));
406 if (ret) 525 if (ret)
407 break; 526 break;
@@ -412,6 +531,11 @@ static void hp_wmi_notify(u32 value, void *context)
412 key_code); 531 key_code);
413 break; 532 break;
414 case HPWMI_WIRELESS: 533 case HPWMI_WIRELESS:
534 if (rfkill2_count) {
535 hp_wmi_rfkill2_refresh();
536 break;
537 }
538
415 if (wifi_rfkill) 539 if (wifi_rfkill)
416 rfkill_set_states(wifi_rfkill, 540 rfkill_set_states(wifi_rfkill,
417 hp_wmi_get_sw_state(HPWMI_WIFI), 541 hp_wmi_get_sw_state(HPWMI_WIFI),
@@ -502,32 +626,16 @@ static void cleanup_sysfs(struct platform_device *device)
502 device_remove_file(&device->dev, &dev_attr_tablet); 626 device_remove_file(&device->dev, &dev_attr_tablet);
503} 627}
504 628
505static int __devinit hp_wmi_bios_setup(struct platform_device *device) 629static int __devinit hp_wmi_rfkill_setup(struct platform_device *device)
506{ 630{
507 int err; 631 int err;
508 int wireless = 0; 632 int wireless = 0;
509 633
510 err = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, &wireless, 634 err = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, &wireless,
511 sizeof(wireless)); 635 sizeof(wireless), sizeof(wireless));
512 if (err) 636 if (err)
513 return err; 637 return err;
514 638
515 err = device_create_file(&device->dev, &dev_attr_display);
516 if (err)
517 goto add_sysfs_error;
518 err = device_create_file(&device->dev, &dev_attr_hddtemp);
519 if (err)
520 goto add_sysfs_error;
521 err = device_create_file(&device->dev, &dev_attr_als);
522 if (err)
523 goto add_sysfs_error;
524 err = device_create_file(&device->dev, &dev_attr_dock);
525 if (err)
526 goto add_sysfs_error;
527 err = device_create_file(&device->dev, &dev_attr_tablet);
528 if (err)
529 goto add_sysfs_error;
530
531 if (wireless & 0x1) { 639 if (wireless & 0x1) {
532 wifi_rfkill = rfkill_alloc("hp-wifi", &device->dev, 640 wifi_rfkill = rfkill_alloc("hp-wifi", &device->dev,
533 RFKILL_TYPE_WLAN, 641 RFKILL_TYPE_WLAN,
@@ -573,14 +681,131 @@ static int __devinit hp_wmi_bios_setup(struct platform_device *device)
573 return 0; 681 return 0;
574register_wwan_err: 682register_wwan_err:
575 rfkill_destroy(wwan_rfkill); 683 rfkill_destroy(wwan_rfkill);
684 wwan_rfkill = NULL;
576 if (bluetooth_rfkill) 685 if (bluetooth_rfkill)
577 rfkill_unregister(bluetooth_rfkill); 686 rfkill_unregister(bluetooth_rfkill);
578register_bluetooth_error: 687register_bluetooth_error:
579 rfkill_destroy(bluetooth_rfkill); 688 rfkill_destroy(bluetooth_rfkill);
689 bluetooth_rfkill = NULL;
580 if (wifi_rfkill) 690 if (wifi_rfkill)
581 rfkill_unregister(wifi_rfkill); 691 rfkill_unregister(wifi_rfkill);
582register_wifi_error: 692register_wifi_error:
583 rfkill_destroy(wifi_rfkill); 693 rfkill_destroy(wifi_rfkill);
694 wifi_rfkill = NULL;
695 return err;
696}
697
698static int __devinit hp_wmi_rfkill2_setup(struct platform_device *device)
699{
700 int err, i;
701 struct bios_rfkill2_state state;
702 err = hp_wmi_perform_query(HPWMI_WIRELESS2_QUERY, 0, &state,
703 0, sizeof(state));
704 if (err)
705 return err;
706
707 if (state.count > HPWMI_MAX_RFKILL2_DEVICES) {
708 printk(KERN_WARNING PREFIX "unable to parse 0x1b query output\n");
709 return -EINVAL;
710 }
711
712 for (i = 0; i < state.count; i++) {
713 struct rfkill *rfkill;
714 enum rfkill_type type;
715 char *name;
716 switch (state.device[i].radio_type) {
717 case HPWMI_WIFI:
718 type = RFKILL_TYPE_WLAN;
719 name = "hp-wifi";
720 break;
721 case HPWMI_BLUETOOTH:
722 type = RFKILL_TYPE_BLUETOOTH;
723 name = "hp-bluetooth";
724 break;
725 case HPWMI_WWAN:
726 type = RFKILL_TYPE_WWAN;
727 name = "hp-wwan";
728 break;
729 default:
730 printk(KERN_WARNING PREFIX "unknown device type 0x%x\n",
731 state.device[i].radio_type);
732 continue;
733 }
734
735 if (!state.device[i].vendor_id) {
736 printk(KERN_WARNING PREFIX "zero device %d while %d "
737 "reported\n", i, state.count);
738 continue;
739 }
740
741 rfkill = rfkill_alloc(name, &device->dev, type,
742 &hp_wmi_rfkill2_ops, (void *)(long)i);
743 if (!rfkill) {
744 err = -ENOMEM;
745 goto fail;
746 }
747
748 rfkill2[rfkill2_count].id = state.device[i].rfkill_id;
749 rfkill2[rfkill2_count].num = i;
750 rfkill2[rfkill2_count].rfkill = rfkill;
751
752 rfkill_init_sw_state(rfkill,
753 IS_SWBLOCKED(state.device[i].power));
754 rfkill_set_hw_state(rfkill,
755 IS_HWBLOCKED(state.device[i].power));
756
757 if (!(state.device[i].power & HPWMI_POWER_BIOS))
758 printk(KERN_INFO PREFIX "device %s blocked by BIOS\n",
759 name);
760
761 err = rfkill_register(rfkill);
762 if (err) {
763 rfkill_destroy(rfkill);
764 goto fail;
765 }
766
767 rfkill2_count++;
768 }
769
770 return 0;
771fail:
772 for (; rfkill2_count > 0; rfkill2_count--) {
773 rfkill_unregister(rfkill2[rfkill2_count - 1].rfkill);
774 rfkill_destroy(rfkill2[rfkill2_count - 1].rfkill);
775 }
776 return err;
777}
778
779static int __devinit hp_wmi_bios_setup(struct platform_device *device)
780{
781 int err;
782
783 /* clear detected rfkill devices */
784 wifi_rfkill = NULL;
785 bluetooth_rfkill = NULL;
786 wwan_rfkill = NULL;
787 rfkill2_count = 0;
788
789 if (hp_wmi_rfkill_setup(device))
790 hp_wmi_rfkill2_setup(device);
791
792 err = device_create_file(&device->dev, &dev_attr_display);
793 if (err)
794 goto add_sysfs_error;
795 err = device_create_file(&device->dev, &dev_attr_hddtemp);
796 if (err)
797 goto add_sysfs_error;
798 err = device_create_file(&device->dev, &dev_attr_als);
799 if (err)
800 goto add_sysfs_error;
801 err = device_create_file(&device->dev, &dev_attr_dock);
802 if (err)
803 goto add_sysfs_error;
804 err = device_create_file(&device->dev, &dev_attr_tablet);
805 if (err)
806 goto add_sysfs_error;
807 return 0;
808
584add_sysfs_error: 809add_sysfs_error:
585 cleanup_sysfs(device); 810 cleanup_sysfs(device);
586 return err; 811 return err;
@@ -588,8 +813,14 @@ add_sysfs_error:
588 813
589static int __exit hp_wmi_bios_remove(struct platform_device *device) 814static int __exit hp_wmi_bios_remove(struct platform_device *device)
590{ 815{
816 int i;
591 cleanup_sysfs(device); 817 cleanup_sysfs(device);
592 818
819 for (i = 0; i < rfkill2_count; i++) {
820 rfkill_unregister(rfkill2[i].rfkill);
821 rfkill_destroy(rfkill2[i].rfkill);
822 }
823
593 if (wifi_rfkill) { 824 if (wifi_rfkill) {
594 rfkill_unregister(wifi_rfkill); 825 rfkill_unregister(wifi_rfkill);
595 rfkill_destroy(wifi_rfkill); 826 rfkill_destroy(wifi_rfkill);
@@ -622,6 +853,9 @@ static int hp_wmi_resume_handler(struct device *device)
622 input_sync(hp_wmi_input_dev); 853 input_sync(hp_wmi_input_dev);
623 } 854 }
624 855
856 if (rfkill2_count)
857 hp_wmi_rfkill2_refresh();
858
625 if (wifi_rfkill) 859 if (wifi_rfkill)
626 rfkill_set_states(wifi_rfkill, 860 rfkill_set_states(wifi_rfkill,
627 hp_wmi_get_sw_state(HPWMI_WIFI), 861 hp_wmi_get_sw_state(HPWMI_WIFI),
diff --git a/drivers/platform/x86/ideapad-laptop.c b/drivers/platform/x86/ideapad-laptop.c
index 114d95247cdf..21b101899bae 100644
--- a/drivers/platform/x86/ideapad-laptop.c
+++ b/drivers/platform/x86/ideapad-laptop.c
@@ -459,6 +459,8 @@ static void ideapad_acpi_notify(struct acpi_device *adevice, u32 event)
459 if (test_bit(vpc_bit, &vpc1)) { 459 if (test_bit(vpc_bit, &vpc1)) {
460 if (vpc_bit == 9) 460 if (vpc_bit == 9)
461 ideapad_sync_rfk_state(adevice); 461 ideapad_sync_rfk_state(adevice);
462 else if (vpc_bit == 4)
463 read_ec_data(handle, 0x12, &vpc2);
462 else 464 else
463 ideapad_input_report(priv, vpc_bit); 465 ideapad_input_report(priv, vpc_bit);
464 } 466 }
diff --git a/drivers/platform/x86/intel_ips.c b/drivers/platform/x86/intel_ips.c
index 1294a39373ba..85c8ad43c0c5 100644
--- a/drivers/platform/x86/intel_ips.c
+++ b/drivers/platform/x86/intel_ips.c
@@ -1111,7 +1111,7 @@ static int ips_monitor(void *data)
1111 last_msecs = jiffies_to_msecs(jiffies); 1111 last_msecs = jiffies_to_msecs(jiffies);
1112 expire = jiffies + msecs_to_jiffies(IPS_SAMPLE_PERIOD); 1112 expire = jiffies + msecs_to_jiffies(IPS_SAMPLE_PERIOD);
1113 1113
1114 __set_current_state(TASK_UNINTERRUPTIBLE); 1114 __set_current_state(TASK_INTERRUPTIBLE);
1115 mod_timer(&timer, expire); 1115 mod_timer(&timer, expire);
1116 schedule(); 1116 schedule();
1117 1117
diff --git a/drivers/platform/x86/intel_mid_powerbtn.c b/drivers/platform/x86/intel_mid_powerbtn.c
new file mode 100644
index 000000000000..213e79ba68d5
--- /dev/null
+++ b/drivers/platform/x86/intel_mid_powerbtn.c
@@ -0,0 +1,148 @@
1/*
2 * Power button driver for Medfield.
3 *
4 * Copyright (C) 2010 Intel Corp
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
18 */
19
20#include <linux/module.h>
21#include <linux/init.h>
22#include <linux/interrupt.h>
23#include <linux/slab.h>
24#include <linux/platform_device.h>
25#include <linux/input.h>
26#include <asm/intel_scu_ipc.h>
27
28#define DRIVER_NAME "msic_power_btn"
29
30#define MSIC_IRQ_STAT 0x02
31 #define MSIC_IRQ_PB (1 << 0)
32#define MSIC_PB_CONFIG 0x3e
33#define MSIC_PB_STATUS 0x3f
34 #define MSIC_PB_LEVEL (1 << 3) /* 1 - release, 0 - press */
35
36struct mfld_pb_priv {
37 struct input_dev *input;
38 unsigned int irq;
39};
40
41static irqreturn_t mfld_pb_isr(int irq, void *dev_id)
42{
43 struct mfld_pb_priv *priv = dev_id;
44 int ret;
45 u8 pbstat;
46
47 ret = intel_scu_ipc_ioread8(MSIC_PB_STATUS, &pbstat);
48 if (ret < 0)
49 return IRQ_HANDLED;
50
51 input_event(priv->input, EV_KEY, KEY_POWER, !(pbstat & MSIC_PB_LEVEL));
52 input_sync(priv->input);
53
54 return IRQ_HANDLED;
55}
56
57static int __devinit mfld_pb_probe(struct platform_device *pdev)
58{
59 struct mfld_pb_priv *priv;
60 struct input_dev *input;
61 int irq;
62 int error;
63
64 irq = platform_get_irq(pdev, 0);
65 if (irq < 0)
66 return -EINVAL;
67
68 priv = kzalloc(sizeof(struct mfld_pb_priv), GFP_KERNEL);
69 input = input_allocate_device();
70 if (!priv || !input) {
71 error = -ENOMEM;
72 goto err_free_mem;
73 }
74
75 priv->input = input;
76 priv->irq = irq;
77
78 input->name = pdev->name;
79 input->phys = "power-button/input0";
80 input->id.bustype = BUS_HOST;
81 input->dev.parent = &pdev->dev;
82
83 input_set_capability(input, EV_KEY, KEY_POWER);
84
85 error = request_threaded_irq(priv->irq, NULL, mfld_pb_isr,
86 0, DRIVER_NAME, priv);
87 if (error) {
88 dev_err(&pdev->dev,
89 "unable to request irq %d for mfld power button\n",
90 irq);
91 goto err_free_mem;
92 }
93
94 error = input_register_device(input);
95 if (error) {
96 dev_err(&pdev->dev,
97 "unable to register input dev, error %d\n", error);
98 goto err_free_irq;
99 }
100
101 platform_set_drvdata(pdev, priv);
102 return 0;
103
104err_free_irq:
105 free_irq(priv->irq, priv);
106err_free_mem:
107 input_free_device(input);
108 kfree(priv);
109 return error;
110}
111
112static int __devexit mfld_pb_remove(struct platform_device *pdev)
113{
114 struct mfld_pb_priv *priv = platform_get_drvdata(pdev);
115
116 free_irq(priv->irq, priv);
117 input_unregister_device(priv->input);
118 kfree(priv);
119
120 platform_set_drvdata(pdev, NULL);
121 return 0;
122}
123
124static struct platform_driver mfld_pb_driver = {
125 .driver = {
126 .name = DRIVER_NAME,
127 .owner = THIS_MODULE,
128 },
129 .probe = mfld_pb_probe,
130 .remove = __devexit_p(mfld_pb_remove),
131};
132
133static int __init mfld_pb_init(void)
134{
135 return platform_driver_register(&mfld_pb_driver);
136}
137module_init(mfld_pb_init);
138
139static void __exit mfld_pb_exit(void)
140{
141 platform_driver_unregister(&mfld_pb_driver);
142}
143module_exit(mfld_pb_exit);
144
145MODULE_AUTHOR("Hong Liu <hong.liu@intel.com>");
146MODULE_DESCRIPTION("Intel Medfield Power Button Driver");
147MODULE_LICENSE("GPL v2");
148MODULE_ALIAS("platform:" DRIVER_NAME);
diff --git a/drivers/platform/x86/intel_mid_thermal.c b/drivers/platform/x86/intel_mid_thermal.c
new file mode 100644
index 000000000000..6c12db503161
--- /dev/null
+++ b/drivers/platform/x86/intel_mid_thermal.c
@@ -0,0 +1,576 @@
1/*
2 * intel_mid_thermal.c - Intel MID platform thermal driver
3 *
4 * Copyright (C) 2011 Intel Corporation
5 *
6 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; version 2 of the License.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
20 *
21 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
22 * Author: Durgadoss R <durgadoss.r@intel.com>
23 */
24
25#define pr_fmt(fmt) "intel_mid_thermal: " fmt
26
27#include <linux/module.h>
28#include <linux/init.h>
29#include <linux/err.h>
30#include <linux/param.h>
31#include <linux/device.h>
32#include <linux/platform_device.h>
33#include <linux/slab.h>
34#include <linux/pm.h>
35#include <linux/thermal.h>
36
37#include <asm/intel_scu_ipc.h>
38
39/* Number of thermal sensors */
40#define MSIC_THERMAL_SENSORS 4
41
42/* ADC1 - thermal registers */
43#define MSIC_THERM_ADC1CNTL1 0x1C0
44#define MSIC_ADC_ENBL 0x10
45#define MSIC_ADC_START 0x08
46
47#define MSIC_THERM_ADC1CNTL3 0x1C2
48#define MSIC_ADCTHERM_ENBL 0x04
49#define MSIC_ADCRRDATA_ENBL 0x05
50#define MSIC_CHANL_MASK_VAL 0x0F
51
52#define MSIC_STOPBIT_MASK 16
53#define MSIC_ADCTHERM_MASK 4
54#define ADC_CHANLS_MAX 15 /* Number of ADC channels */
55#define ADC_LOOP_MAX (ADC_CHANLS_MAX - MSIC_THERMAL_SENSORS)
56
57/* ADC channel code values */
58#define SKIN_SENSOR0_CODE 0x08
59#define SKIN_SENSOR1_CODE 0x09
60#define SYS_SENSOR_CODE 0x0A
61#define MSIC_DIE_SENSOR_CODE 0x03
62
63#define SKIN_THERM_SENSOR0 0
64#define SKIN_THERM_SENSOR1 1
65#define SYS_THERM_SENSOR2 2
66#define MSIC_DIE_THERM_SENSOR3 3
67
68/* ADC code range */
69#define ADC_MAX 977
70#define ADC_MIN 162
71#define ADC_VAL0C 887
72#define ADC_VAL20C 720
73#define ADC_VAL40C 508
74#define ADC_VAL60C 315
75
76/* ADC base addresses */
77#define ADC_CHNL_START_ADDR 0x1C5 /* increments by 1 */
78#define ADC_DATA_START_ADDR 0x1D4 /* increments by 2 */
79
80/* MSIC die attributes */
81#define MSIC_DIE_ADC_MIN 488
82#define MSIC_DIE_ADC_MAX 1004
83
84/* This holds the address of the first free ADC channel,
85 * among the 15 channels
86 */
87static int channel_index;
88
89struct platform_info {
90 struct platform_device *pdev;
91 struct thermal_zone_device *tzd[MSIC_THERMAL_SENSORS];
92};
93
94struct thermal_device_info {
95 unsigned int chnl_addr;
96 int direct;
97 /* This holds the current temperature in millidegree celsius */
98 long curr_temp;
99};
100
101/**
102 * to_msic_die_temp - converts adc_val to msic_die temperature
103 * @adc_val: ADC value to be converted
104 *
105 * Can sleep
106 */
107static int to_msic_die_temp(uint16_t adc_val)
108{
109 return (368 * (adc_val) / 1000) - 220;
110}
111
112/**
113 * is_valid_adc - checks whether the adc code is within the defined range
114 * @min: minimum value for the sensor
115 * @max: maximum value for the sensor
116 *
117 * Can sleep
118 */
119static int is_valid_adc(uint16_t adc_val, uint16_t min, uint16_t max)
120{
121 return (adc_val >= min) && (adc_val <= max);
122}
123
124/**
125 * adc_to_temp - converts the ADC code to temperature in C
126 * @direct: true if ths channel is direct index
127 * @adc_val: the adc_val that needs to be converted
128 * @tp: temperature return value
129 *
130 * Linear approximation is used to covert the skin adc value into temperature.
131 * This technique is used to avoid very long look-up table to get
132 * the appropriate temp value from ADC value.
133 * The adc code vs sensor temp curve is split into five parts
134 * to achieve very close approximate temp value with less than
135 * 0.5C error
136 */
137static int adc_to_temp(int direct, uint16_t adc_val, unsigned long *tp)
138{
139 int temp;
140
141 /* Direct conversion for die temperature */
142 if (direct) {
143 if (is_valid_adc(adc_val, MSIC_DIE_ADC_MIN, MSIC_DIE_ADC_MAX)) {
144 *tp = to_msic_die_temp(adc_val) * 1000;
145 return 0;
146 }
147 return -ERANGE;
148 }
149
150 if (!is_valid_adc(adc_val, ADC_MIN, ADC_MAX))
151 return -ERANGE;
152
153 /* Linear approximation for skin temperature */
154 if (adc_val > ADC_VAL0C)
155 temp = 177 - (adc_val/5);
156 else if ((adc_val <= ADC_VAL0C) && (adc_val > ADC_VAL20C))
157 temp = 111 - (adc_val/8);
158 else if ((adc_val <= ADC_VAL20C) && (adc_val > ADC_VAL40C))
159 temp = 92 - (adc_val/10);
160 else if ((adc_val <= ADC_VAL40C) && (adc_val > ADC_VAL60C))
161 temp = 91 - (adc_val/10);
162 else
163 temp = 112 - (adc_val/6);
164
165 /* Convert temperature in celsius to milli degree celsius */
166 *tp = temp * 1000;
167 return 0;
168}
169
170/**
171 * mid_read_temp - read sensors for temperature
172 * @temp: holds the current temperature for the sensor after reading
173 *
174 * reads the adc_code from the channel and converts it to real
175 * temperature. The converted value is stored in temp.
176 *
177 * Can sleep
178 */
179static int mid_read_temp(struct thermal_zone_device *tzd, unsigned long *temp)
180{
181 struct thermal_device_info *td_info = tzd->devdata;
182 uint16_t adc_val, addr;
183 uint8_t data = 0;
184 int ret;
185 unsigned long curr_temp;
186
187
188 addr = td_info->chnl_addr;
189
190 /* Enable the msic for conversion before reading */
191 ret = intel_scu_ipc_iowrite8(MSIC_THERM_ADC1CNTL3, MSIC_ADCRRDATA_ENBL);
192 if (ret)
193 return ret;
194
195 /* Re-toggle the RRDATARD bit (temporary workaround) */
196 ret = intel_scu_ipc_iowrite8(MSIC_THERM_ADC1CNTL3, MSIC_ADCTHERM_ENBL);
197 if (ret)
198 return ret;
199
200 /* Read the higher bits of data */
201 ret = intel_scu_ipc_ioread8(addr, &data);
202 if (ret)
203 return ret;
204
205 /* Shift bits to accomodate the lower two data bits */
206 adc_val = (data << 2);
207 addr++;
208
209 ret = intel_scu_ipc_ioread8(addr, &data);/* Read lower bits */
210 if (ret)
211 return ret;
212
213 /* Adding lower two bits to the higher bits */
214 data &= 03;
215 adc_val += data;
216
217 /* Convert ADC value to temperature */
218 ret = adc_to_temp(td_info->direct, adc_val, &curr_temp);
219 if (ret == 0)
220 *temp = td_info->curr_temp = curr_temp;
221 return ret;
222}
223
224/**
225 * configure_adc - enables/disables the ADC for conversion
226 * @val: zero: disables the ADC non-zero:enables the ADC
227 *
228 * Enable/Disable the ADC depending on the argument
229 *
230 * Can sleep
231 */
232static int configure_adc(int val)
233{
234 int ret;
235 uint8_t data;
236
237 ret = intel_scu_ipc_ioread8(MSIC_THERM_ADC1CNTL1, &data);
238 if (ret)
239 return ret;
240
241 if (val) {
242 /* Enable and start the ADC */
243 data |= (MSIC_ADC_ENBL | MSIC_ADC_START);
244 } else {
245 /* Just stop the ADC */
246 data &= (~MSIC_ADC_START);
247 }
248
249 return intel_scu_ipc_iowrite8(MSIC_THERM_ADC1CNTL1, data);
250}
251
252/**
253 * set_up_therm_channel - enable thermal channel for conversion
254 * @base_addr: index of free msic ADC channel
255 *
256 * Enable all the three channels for conversion
257 *
258 * Can sleep
259 */
260static int set_up_therm_channel(u16 base_addr)
261{
262 int ret;
263
264 /* Enable all the sensor channels */
265 ret = intel_scu_ipc_iowrite8(base_addr, SKIN_SENSOR0_CODE);
266 if (ret)
267 return ret;
268
269 ret = intel_scu_ipc_iowrite8(base_addr + 1, SKIN_SENSOR1_CODE);
270 if (ret)
271 return ret;
272
273 ret = intel_scu_ipc_iowrite8(base_addr + 2, SYS_SENSOR_CODE);
274 if (ret)
275 return ret;
276
277 /* Since this is the last channel, set the stop bit
278 to 1 by ORing the DIE_SENSOR_CODE with 0x10 */
279 ret = intel_scu_ipc_iowrite8(base_addr + 3,
280 (MSIC_DIE_SENSOR_CODE | 0x10));
281 if (ret)
282 return ret;
283
284 /* Enable ADC and start it */
285 return configure_adc(1);
286}
287
288/**
289 * reset_stopbit - sets the stop bit to 0 on the given channel
290 * @addr: address of the channel
291 *
292 * Can sleep
293 */
294static int reset_stopbit(uint16_t addr)
295{
296 int ret;
297 uint8_t data;
298 ret = intel_scu_ipc_ioread8(addr, &data);
299 if (ret)
300 return ret;
301 /* Set the stop bit to zero */
302 return intel_scu_ipc_iowrite8(addr, (data & 0xEF));
303}
304
305/**
306 * find_free_channel - finds an empty channel for conversion
307 *
308 * If the ADC is not enabled then start using 0th channel
309 * itself. Otherwise find an empty channel by looking for a
310 * channel in which the stopbit is set to 1. returns the index
311 * of the first free channel if succeeds or an error code.
312 *
313 * Context: can sleep
314 *
315 * FIXME: Ultimately the channel allocator will move into the intel_scu_ipc
316 * code.
317 */
318static int find_free_channel(void)
319{
320 int ret;
321 int i;
322 uint8_t data;
323
324 /* check whether ADC is enabled */
325 ret = intel_scu_ipc_ioread8(MSIC_THERM_ADC1CNTL1, &data);
326 if (ret)
327 return ret;
328
329 if ((data & MSIC_ADC_ENBL) == 0)
330 return 0;
331
332 /* ADC is already enabled; Looking for an empty channel */
333 for (i = 0; i < ADC_CHANLS_MAX; i++) {
334 ret = intel_scu_ipc_ioread8(ADC_CHNL_START_ADDR + i, &data);
335 if (ret)
336 return ret;
337
338 if (data & MSIC_STOPBIT_MASK) {
339 ret = i;
340 break;
341 }
342 }
343 return (ret > ADC_LOOP_MAX) ? (-EINVAL) : ret;
344}
345
346/**
347 * mid_initialize_adc - initializing the ADC
348 * @dev: our device structure
349 *
350 * Initialize the ADC for reading thermistor values. Can sleep.
351 */
352static int mid_initialize_adc(struct device *dev)
353{
354 u8 data;
355 u16 base_addr;
356 int ret;
357
358 /*
359 * Ensure that adctherm is disabled before we
360 * initialize the ADC
361 */
362 ret = intel_scu_ipc_ioread8(MSIC_THERM_ADC1CNTL3, &data);
363 if (ret)
364 return ret;
365
366 if (data & MSIC_ADCTHERM_MASK)
367 dev_warn(dev, "ADCTHERM already set");
368
369 /* Index of the first channel in which the stop bit is set */
370 channel_index = find_free_channel();
371 if (channel_index < 0) {
372 dev_err(dev, "No free ADC channels");
373 return channel_index;
374 }
375
376 base_addr = ADC_CHNL_START_ADDR + channel_index;
377
378 if (!(channel_index == 0 || channel_index == ADC_LOOP_MAX)) {
379 /* Reset stop bit for channels other than 0 and 12 */
380 ret = reset_stopbit(base_addr);
381 if (ret)
382 return ret;
383
384 /* Index of the first free channel */
385 base_addr++;
386 channel_index++;
387 }
388
389 ret = set_up_therm_channel(base_addr);
390 if (ret) {
391 dev_err(dev, "unable to enable ADC");
392 return ret;
393 }
394 dev_dbg(dev, "ADC initialization successful");
395 return ret;
396}
397
398/**
399 * initialize_sensor - sets default temp and timer ranges
400 * @index: index of the sensor
401 *
402 * Context: can sleep
403 */
404static struct thermal_device_info *initialize_sensor(int index)
405{
406 struct thermal_device_info *td_info =
407 kzalloc(sizeof(struct thermal_device_info), GFP_KERNEL);
408
409 if (!td_info)
410 return NULL;
411
412 /* Set the base addr of the channel for this sensor */
413 td_info->chnl_addr = ADC_DATA_START_ADDR + 2 * (channel_index + index);
414 /* Sensor 3 is direct conversion */
415 if (index == 3)
416 td_info->direct = 1;
417 return td_info;
418}
419
420/**
421 * mid_thermal_resume - resume routine
422 * @pdev: platform device structure
423 *
424 * mid thermal resume: re-initializes the adc. Can sleep.
425 */
426static int mid_thermal_resume(struct platform_device *pdev)
427{
428 return mid_initialize_adc(&pdev->dev);
429}
430
431/**
432 * mid_thermal_suspend - suspend routine
433 * @pdev: platform device structure
434 *
435 * mid thermal suspend implements the suspend functionality
436 * by stopping the ADC. Can sleep.
437 */
438static int mid_thermal_suspend(struct platform_device *pdev, pm_message_t mesg)
439{
440 /*
441 * This just stops the ADC and does not disable it.
442 * temporary workaround until we have a generic ADC driver.
443 * If 0 is passed, it disables the ADC.
444 */
445 return configure_adc(0);
446}
447
448/**
449 * read_curr_temp - reads the current temperature and stores in temp
450 * @temp: holds the current temperature value after reading
451 *
452 * Can sleep
453 */
454static int read_curr_temp(struct thermal_zone_device *tzd, unsigned long *temp)
455{
456 WARN_ON(tzd == NULL);
457 return mid_read_temp(tzd, temp);
458}
459
460/* Can't be const */
461static struct thermal_zone_device_ops tzd_ops = {
462 .get_temp = read_curr_temp,
463};
464
465
466/**
467 * mid_thermal_probe - mfld thermal initialize
468 * @pdev: platform device structure
469 *
470 * mid thermal probe initializes the hardware and registers
471 * all the sensors with the generic thermal framework. Can sleep.
472 */
473static int mid_thermal_probe(struct platform_device *pdev)
474{
475 static char *name[MSIC_THERMAL_SENSORS] = {
476 "skin0", "skin1", "sys", "msicdie"
477 };
478
479 int ret;
480 int i;
481 struct platform_info *pinfo;
482
483 pinfo = kzalloc(sizeof(struct platform_info), GFP_KERNEL);
484 if (!pinfo)
485 return -ENOMEM;
486
487 /* Initializing the hardware */
488 ret = mid_initialize_adc(&pdev->dev);
489 if (ret) {
490 dev_err(&pdev->dev, "ADC init failed");
491 kfree(pinfo);
492 return ret;
493 }
494
495 /* Register each sensor with the generic thermal framework*/
496 for (i = 0; i < MSIC_THERMAL_SENSORS; i++) {
497 pinfo->tzd[i] = thermal_zone_device_register(name[i],
498 0, initialize_sensor(i),
499 &tzd_ops, 0, 0, 0, 0);
500 if (IS_ERR(pinfo->tzd[i]))
501 goto reg_fail;
502 }
503
504 pinfo->pdev = pdev;
505 platform_set_drvdata(pdev, pinfo);
506 return 0;
507
508reg_fail:
509 ret = PTR_ERR(pinfo->tzd[i]);
510 while (--i >= 0)
511 thermal_zone_device_unregister(pinfo->tzd[i]);
512 configure_adc(0);
513 kfree(pinfo);
514 return ret;
515}
516
517/**
518 * mid_thermal_remove - mfld thermal finalize
519 * @dev: platform device structure
520 *
521 * MLFD thermal remove unregisters all the sensors from the generic
522 * thermal framework. Can sleep.
523 */
524static int mid_thermal_remove(struct platform_device *pdev)
525{
526 int i;
527 struct platform_info *pinfo = platform_get_drvdata(pdev);
528
529 for (i = 0; i < MSIC_THERMAL_SENSORS; i++)
530 thermal_zone_device_unregister(pinfo->tzd[i]);
531
532 platform_set_drvdata(pdev, NULL);
533
534 /* Stop the ADC */
535 return configure_adc(0);
536}
537
538/*********************************************************************
539 * Driver initialisation and finalization
540 *********************************************************************/
541
542#define DRIVER_NAME "msic_sensor"
543
544static const struct platform_device_id therm_id_table[] = {
545 { DRIVER_NAME, 1 },
546 { }
547};
548
549static struct platform_driver mid_thermal_driver = {
550 .driver = {
551 .name = DRIVER_NAME,
552 .owner = THIS_MODULE,
553 },
554 .probe = mid_thermal_probe,
555 .suspend = mid_thermal_suspend,
556 .resume = mid_thermal_resume,
557 .remove = __devexit_p(mid_thermal_remove),
558 .id_table = therm_id_table,
559};
560
561static int __init mid_thermal_module_init(void)
562{
563 return platform_driver_register(&mid_thermal_driver);
564}
565
566static void __exit mid_thermal_module_exit(void)
567{
568 platform_driver_unregister(&mid_thermal_driver);
569}
570
571module_init(mid_thermal_module_init);
572module_exit(mid_thermal_module_exit);
573
574MODULE_AUTHOR("Durgadoss R <durgadoss.r@intel.com>");
575MODULE_DESCRIPTION("Intel Medfield Platform Thermal Driver");
576MODULE_LICENSE("GPL");
diff --git a/drivers/platform/x86/intel_rar_register.c b/drivers/platform/x86/intel_rar_register.c
index 2b11a33325e6..bde47e9080cd 100644
--- a/drivers/platform/x86/intel_rar_register.c
+++ b/drivers/platform/x86/intel_rar_register.c
@@ -485,7 +485,7 @@ EXPORT_SYMBOL(rar_lock);
485 * 485 *
486 * The register_rar function is to used by other device drivers 486 * The register_rar function is to used by other device drivers
487 * to ensure that this driver is ready. As we cannot be sure of 487 * to ensure that this driver is ready. As we cannot be sure of
488 * the compile/execute order of drivers in ther kernel, it is 488 * the compile/execute order of drivers in the kernel, it is
489 * best to give this driver a callback function to call when 489 * best to give this driver a callback function to call when
490 * it is ready to give out addresses. The callback function 490 * it is ready to give out addresses. The callback function
491 * would have those steps that continue the initialization of 491 * would have those steps that continue the initialization of
diff --git a/drivers/platform/x86/intel_scu_ipc.c b/drivers/platform/x86/intel_scu_ipc.c
index a91d510a798b..940accbe28d3 100644
--- a/drivers/platform/x86/intel_scu_ipc.c
+++ b/drivers/platform/x86/intel_scu_ipc.c
@@ -9,7 +9,7 @@
9 * as published by the Free Software Foundation; version 2 9 * as published by the Free Software Foundation; version 2
10 * of the License. 10 * of the License.
11 * 11 *
12 * SCU runing in ARC processor communicates with other entity running in IA 12 * SCU running in ARC processor communicates with other entity running in IA
13 * core through IPC mechanism which in turn messaging between IA core ad SCU. 13 * core through IPC mechanism which in turn messaging between IA core ad SCU.
14 * SCU has two IPC mechanism IPC-1 and IPC-2. IPC-1 is used between IA32 and 14 * SCU has two IPC mechanism IPC-1 and IPC-2. IPC-1 is used between IA32 and
15 * SCU where IPC-2 is used between P-Unit and SCU. This driver delas with 15 * SCU where IPC-2 is used between P-Unit and SCU. This driver delas with
diff --git a/drivers/platform/x86/msi-laptop.c b/drivers/platform/x86/msi-laptop.c
index 142d38579314..23fb2afda00b 100644
--- a/drivers/platform/x86/msi-laptop.c
+++ b/drivers/platform/x86/msi-laptop.c
@@ -51,6 +51,8 @@
51 * laptop as MSI S270. YMMV. 51 * laptop as MSI S270. YMMV.
52 */ 52 */
53 53
54#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
55
54#include <linux/module.h> 56#include <linux/module.h>
55#include <linux/kernel.h> 57#include <linux/kernel.h>
56#include <linux/init.h> 58#include <linux/init.h>
@@ -60,6 +62,8 @@
60#include <linux/platform_device.h> 62#include <linux/platform_device.h>
61#include <linux/rfkill.h> 63#include <linux/rfkill.h>
62#include <linux/i8042.h> 64#include <linux/i8042.h>
65#include <linux/input.h>
66#include <linux/input/sparse-keymap.h>
63 67
64#define MSI_DRIVER_VERSION "0.5" 68#define MSI_DRIVER_VERSION "0.5"
65 69
@@ -78,6 +82,9 @@
78#define MSI_STANDARD_EC_SCM_LOAD_ADDRESS 0x2d 82#define MSI_STANDARD_EC_SCM_LOAD_ADDRESS 0x2d
79#define MSI_STANDARD_EC_SCM_LOAD_MASK (1 << 0) 83#define MSI_STANDARD_EC_SCM_LOAD_MASK (1 << 0)
80 84
85#define MSI_STANDARD_EC_TOUCHPAD_ADDRESS 0xe4
86#define MSI_STANDARD_EC_TOUCHPAD_MASK (1 << 4)
87
81static int msi_laptop_resume(struct platform_device *device); 88static int msi_laptop_resume(struct platform_device *device);
82 89
83#define MSI_STANDARD_EC_DEVICES_EXISTS_ADDRESS 0x2f 90#define MSI_STANDARD_EC_DEVICES_EXISTS_ADDRESS 0x2f
@@ -90,6 +97,14 @@ static int auto_brightness;
90module_param(auto_brightness, int, 0); 97module_param(auto_brightness, int, 0);
91MODULE_PARM_DESC(auto_brightness, "Enable automatic brightness control (0: disabled; 1: enabled; 2: don't touch)"); 98MODULE_PARM_DESC(auto_brightness, "Enable automatic brightness control (0: disabled; 1: enabled; 2: don't touch)");
92 99
100static const struct key_entry msi_laptop_keymap[] = {
101 {KE_KEY, KEY_TOUCHPAD_ON, {KEY_TOUCHPAD_ON} }, /* Touch Pad On */
102 {KE_KEY, KEY_TOUCHPAD_OFF, {KEY_TOUCHPAD_OFF} },/* Touch Pad On */
103 {KE_END, 0}
104};
105
106static struct input_dev *msi_laptop_input_dev;
107
93static bool old_ec_model; 108static bool old_ec_model;
94static int wlan_s, bluetooth_s, threeg_s; 109static int wlan_s, bluetooth_s, threeg_s;
95static int threeg_exists; 110static int threeg_exists;
@@ -432,8 +447,7 @@ static struct platform_device *msipf_device;
432 447
433static int dmi_check_cb(const struct dmi_system_id *id) 448static int dmi_check_cb(const struct dmi_system_id *id)
434{ 449{
435 printk(KERN_INFO "msi-laptop: Identified laptop model '%s'.\n", 450 pr_info("Identified laptop model '%s'.\n", id->ident);
436 id->ident);
437 return 1; 451 return 1;
438} 452}
439 453
@@ -605,6 +619,21 @@ static void msi_update_rfkill(struct work_struct *ignored)
605} 619}
606static DECLARE_DELAYED_WORK(msi_rfkill_work, msi_update_rfkill); 620static DECLARE_DELAYED_WORK(msi_rfkill_work, msi_update_rfkill);
607 621
622static void msi_send_touchpad_key(struct work_struct *ignored)
623{
624 u8 rdata;
625 int result;
626
627 result = ec_read(MSI_STANDARD_EC_TOUCHPAD_ADDRESS, &rdata);
628 if (result < 0)
629 return;
630
631 sparse_keymap_report_event(msi_laptop_input_dev,
632 (rdata & MSI_STANDARD_EC_TOUCHPAD_MASK) ?
633 KEY_TOUCHPAD_ON : KEY_TOUCHPAD_OFF, 1, true);
634}
635static DECLARE_DELAYED_WORK(msi_touchpad_work, msi_send_touchpad_key);
636
608static bool msi_laptop_i8042_filter(unsigned char data, unsigned char str, 637static bool msi_laptop_i8042_filter(unsigned char data, unsigned char str,
609 struct serio *port) 638 struct serio *port)
610{ 639{
@@ -613,12 +642,17 @@ static bool msi_laptop_i8042_filter(unsigned char data, unsigned char str,
613 if (str & 0x20) 642 if (str & 0x20)
614 return false; 643 return false;
615 644
616 /* 0x54 wwan, 0x62 bluetooth, 0x76 wlan*/ 645 /* 0x54 wwan, 0x62 bluetooth, 0x76 wlan, 0xE4 touchpad toggle*/
617 if (unlikely(data == 0xe0)) { 646 if (unlikely(data == 0xe0)) {
618 extended = true; 647 extended = true;
619 return false; 648 return false;
620 } else if (unlikely(extended)) { 649 } else if (unlikely(extended)) {
650 extended = false;
621 switch (data) { 651 switch (data) {
652 case 0xE4:
653 schedule_delayed_work(&msi_touchpad_work,
654 round_jiffies_relative(0.5 * HZ));
655 break;
622 case 0x54: 656 case 0x54:
623 case 0x62: 657 case 0x62:
624 case 0x76: 658 case 0x76:
@@ -626,7 +660,6 @@ static bool msi_laptop_i8042_filter(unsigned char data, unsigned char str,
626 round_jiffies_relative(0.5 * HZ)); 660 round_jiffies_relative(0.5 * HZ));
627 break; 661 break;
628 } 662 }
629 extended = false;
630 } 663 }
631 664
632 return false; 665 return false;
@@ -731,6 +764,42 @@ static int msi_laptop_resume(struct platform_device *device)
731 return 0; 764 return 0;
732} 765}
733 766
767static int __init msi_laptop_input_setup(void)
768{
769 int err;
770
771 msi_laptop_input_dev = input_allocate_device();
772 if (!msi_laptop_input_dev)
773 return -ENOMEM;
774
775 msi_laptop_input_dev->name = "MSI Laptop hotkeys";
776 msi_laptop_input_dev->phys = "msi-laptop/input0";
777 msi_laptop_input_dev->id.bustype = BUS_HOST;
778
779 err = sparse_keymap_setup(msi_laptop_input_dev,
780 msi_laptop_keymap, NULL);
781 if (err)
782 goto err_free_dev;
783
784 err = input_register_device(msi_laptop_input_dev);
785 if (err)
786 goto err_free_keymap;
787
788 return 0;
789
790err_free_keymap:
791 sparse_keymap_free(msi_laptop_input_dev);
792err_free_dev:
793 input_free_device(msi_laptop_input_dev);
794 return err;
795}
796
797static void msi_laptop_input_destroy(void)
798{
799 sparse_keymap_free(msi_laptop_input_dev);
800 input_unregister_device(msi_laptop_input_dev);
801}
802
734static int load_scm_model_init(struct platform_device *sdev) 803static int load_scm_model_init(struct platform_device *sdev)
735{ 804{
736 u8 data; 805 u8 data;
@@ -759,16 +828,23 @@ static int load_scm_model_init(struct platform_device *sdev)
759 if (result < 0) 828 if (result < 0)
760 goto fail_rfkill; 829 goto fail_rfkill;
761 830
831 /* setup input device */
832 result = msi_laptop_input_setup();
833 if (result)
834 goto fail_input;
835
762 result = i8042_install_filter(msi_laptop_i8042_filter); 836 result = i8042_install_filter(msi_laptop_i8042_filter);
763 if (result) { 837 if (result) {
764 printk(KERN_ERR 838 pr_err("Unable to install key filter\n");
765 "msi-laptop: Unable to install key filter\n");
766 goto fail_filter; 839 goto fail_filter;
767 } 840 }
768 841
769 return 0; 842 return 0;
770 843
771fail_filter: 844fail_filter:
845 msi_laptop_input_destroy();
846
847fail_input:
772 rfkill_cleanup(); 848 rfkill_cleanup();
773 849
774fail_rfkill: 850fail_rfkill:
@@ -799,7 +875,7 @@ static int __init msi_init(void)
799 /* Register backlight stuff */ 875 /* Register backlight stuff */
800 876
801 if (acpi_video_backlight_support()) { 877 if (acpi_video_backlight_support()) {
802 printk(KERN_INFO "MSI: Brightness ignored, must be controlled " 878 pr_info("Brightness ignored, must be controlled "
803 "by ACPI video driver\n"); 879 "by ACPI video driver\n");
804 } else { 880 } else {
805 struct backlight_properties props; 881 struct backlight_properties props;
@@ -854,7 +930,7 @@ static int __init msi_init(void)
854 if (auto_brightness != 2) 930 if (auto_brightness != 2)
855 set_auto_brightness(auto_brightness); 931 set_auto_brightness(auto_brightness);
856 932
857 printk(KERN_INFO "msi-laptop: driver "MSI_DRIVER_VERSION" successfully loaded.\n"); 933 pr_info("driver "MSI_DRIVER_VERSION" successfully loaded.\n");
858 934
859 return 0; 935 return 0;
860 936
@@ -886,6 +962,7 @@ static void __exit msi_cleanup(void)
886{ 962{
887 if (load_scm_model) { 963 if (load_scm_model) {
888 i8042_remove_filter(msi_laptop_i8042_filter); 964 i8042_remove_filter(msi_laptop_i8042_filter);
965 msi_laptop_input_destroy();
889 cancel_delayed_work_sync(&msi_rfkill_work); 966 cancel_delayed_work_sync(&msi_rfkill_work);
890 rfkill_cleanup(); 967 rfkill_cleanup();
891 } 968 }
@@ -901,7 +978,7 @@ static void __exit msi_cleanup(void)
901 if (auto_brightness != 2) 978 if (auto_brightness != 2)
902 set_auto_brightness(1); 979 set_auto_brightness(1);
903 980
904 printk(KERN_INFO "msi-laptop: driver unloaded.\n"); 981 pr_info("driver unloaded.\n");
905} 982}
906 983
907module_init(msi_init); 984module_init(msi_init);
diff --git a/drivers/platform/x86/samsung-laptop.c b/drivers/platform/x86/samsung-laptop.c
new file mode 100644
index 000000000000..de434c6dc2d6
--- /dev/null
+++ b/drivers/platform/x86/samsung-laptop.c
@@ -0,0 +1,832 @@
1/*
2 * Samsung Laptop driver
3 *
4 * Copyright (C) 2009,2011 Greg Kroah-Hartman (gregkh@suse.de)
5 * Copyright (C) 2009,2011 Novell Inc.
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License version 2 as published by
9 * the Free Software Foundation.
10 *
11 */
12#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
13
14#include <linux/kernel.h>
15#include <linux/init.h>
16#include <linux/module.h>
17#include <linux/delay.h>
18#include <linux/pci.h>
19#include <linux/backlight.h>
20#include <linux/fb.h>
21#include <linux/dmi.h>
22#include <linux/platform_device.h>
23#include <linux/rfkill.h>
24
25/*
26 * This driver is needed because a number of Samsung laptops do not hook
27 * their control settings through ACPI. So we have to poke around in the
28 * BIOS to do things like brightness values, and "special" key controls.
29 */
30
31/*
32 * We have 0 - 8 as valid brightness levels. The specs say that level 0 should
33 * be reserved by the BIOS (which really doesn't make much sense), we tell
34 * userspace that the value is 0 - 7 and then just tell the hardware 1 - 8
35 */
36#define MAX_BRIGHT 0x07
37
38
39#define SABI_IFACE_MAIN 0x00
40#define SABI_IFACE_SUB 0x02
41#define SABI_IFACE_COMPLETE 0x04
42#define SABI_IFACE_DATA 0x05
43
44/* Structure to get data back to the calling function */
45struct sabi_retval {
46 u8 retval[20];
47};
48
49struct sabi_header_offsets {
50 u8 port;
51 u8 re_mem;
52 u8 iface_func;
53 u8 en_mem;
54 u8 data_offset;
55 u8 data_segment;
56};
57
58struct sabi_commands {
59 /*
60 * Brightness is 0 - 8, as described above.
61 * Value 0 is for the BIOS to use
62 */
63 u8 get_brightness;
64 u8 set_brightness;
65
66 /*
67 * first byte:
68 * 0x00 - wireless is off
69 * 0x01 - wireless is on
70 * second byte:
71 * 0x02 - 3G is off
72 * 0x03 - 3G is on
73 * TODO, verify 3G is correct, that doesn't seem right...
74 */
75 u8 get_wireless_button;
76 u8 set_wireless_button;
77
78 /* 0 is off, 1 is on */
79 u8 get_backlight;
80 u8 set_backlight;
81
82 /*
83 * 0x80 or 0x00 - no action
84 * 0x81 - recovery key pressed
85 */
86 u8 get_recovery_mode;
87 u8 set_recovery_mode;
88
89 /*
90 * on seclinux: 0 is low, 1 is high,
91 * on swsmi: 0 is normal, 1 is silent, 2 is turbo
92 */
93 u8 get_performance_level;
94 u8 set_performance_level;
95
96 /*
97 * Tell the BIOS that Linux is running on this machine.
98 * 81 is on, 80 is off
99 */
100 u8 set_linux;
101};
102
103struct sabi_performance_level {
104 const char *name;
105 u8 value;
106};
107
108struct sabi_config {
109 const char *test_string;
110 u16 main_function;
111 const struct sabi_header_offsets header_offsets;
112 const struct sabi_commands commands;
113 const struct sabi_performance_level performance_levels[4];
114 u8 min_brightness;
115 u8 max_brightness;
116};
117
118static const struct sabi_config sabi_configs[] = {
119 {
120 .test_string = "SECLINUX",
121
122 .main_function = 0x4c49,
123
124 .header_offsets = {
125 .port = 0x00,
126 .re_mem = 0x02,
127 .iface_func = 0x03,
128 .en_mem = 0x04,
129 .data_offset = 0x05,
130 .data_segment = 0x07,
131 },
132
133 .commands = {
134 .get_brightness = 0x00,
135 .set_brightness = 0x01,
136
137 .get_wireless_button = 0x02,
138 .set_wireless_button = 0x03,
139
140 .get_backlight = 0x04,
141 .set_backlight = 0x05,
142
143 .get_recovery_mode = 0x06,
144 .set_recovery_mode = 0x07,
145
146 .get_performance_level = 0x08,
147 .set_performance_level = 0x09,
148
149 .set_linux = 0x0a,
150 },
151
152 .performance_levels = {
153 {
154 .name = "silent",
155 .value = 0,
156 },
157 {
158 .name = "normal",
159 .value = 1,
160 },
161 { },
162 },
163 .min_brightness = 1,
164 .max_brightness = 8,
165 },
166 {
167 .test_string = "SwSmi@",
168
169 .main_function = 0x5843,
170
171 .header_offsets = {
172 .port = 0x00,
173 .re_mem = 0x04,
174 .iface_func = 0x02,
175 .en_mem = 0x03,
176 .data_offset = 0x05,
177 .data_segment = 0x07,
178 },
179
180 .commands = {
181 .get_brightness = 0x10,
182 .set_brightness = 0x11,
183
184 .get_wireless_button = 0x12,
185 .set_wireless_button = 0x13,
186
187 .get_backlight = 0x2d,
188 .set_backlight = 0x2e,
189
190 .get_recovery_mode = 0xff,
191 .set_recovery_mode = 0xff,
192
193 .get_performance_level = 0x31,
194 .set_performance_level = 0x32,
195
196 .set_linux = 0xff,
197 },
198
199 .performance_levels = {
200 {
201 .name = "normal",
202 .value = 0,
203 },
204 {
205 .name = "silent",
206 .value = 1,
207 },
208 {
209 .name = "overclock",
210 .value = 2,
211 },
212 { },
213 },
214 .min_brightness = 0,
215 .max_brightness = 8,
216 },
217 { },
218};
219
220static const struct sabi_config *sabi_config;
221
222static void __iomem *sabi;
223static void __iomem *sabi_iface;
224static void __iomem *f0000_segment;
225static struct backlight_device *backlight_device;
226static struct mutex sabi_mutex;
227static struct platform_device *sdev;
228static struct rfkill *rfk;
229
230static int force;
231module_param(force, bool, 0);
232MODULE_PARM_DESC(force,
233 "Disable the DMI check and forces the driver to be loaded");
234
235static int debug;
236module_param(debug, bool, S_IRUGO | S_IWUSR);
237MODULE_PARM_DESC(debug, "Debug enabled or not");
238
239static int sabi_get_command(u8 command, struct sabi_retval *sretval)
240{
241 int retval = 0;
242 u16 port = readw(sabi + sabi_config->header_offsets.port);
243 u8 complete, iface_data;
244
245 mutex_lock(&sabi_mutex);
246
247 /* enable memory to be able to write to it */
248 outb(readb(sabi + sabi_config->header_offsets.en_mem), port);
249
250 /* write out the command */
251 writew(sabi_config->main_function, sabi_iface + SABI_IFACE_MAIN);
252 writew(command, sabi_iface + SABI_IFACE_SUB);
253 writeb(0, sabi_iface + SABI_IFACE_COMPLETE);
254 outb(readb(sabi + sabi_config->header_offsets.iface_func), port);
255
256 /* write protect memory to make it safe */
257 outb(readb(sabi + sabi_config->header_offsets.re_mem), port);
258
259 /* see if the command actually succeeded */
260 complete = readb(sabi_iface + SABI_IFACE_COMPLETE);
261 iface_data = readb(sabi_iface + SABI_IFACE_DATA);
262 if (complete != 0xaa || iface_data == 0xff) {
263 pr_warn("SABI get command 0x%02x failed with completion flag 0x%02x and data 0x%02x\n",
264 command, complete, iface_data);
265 retval = -EINVAL;
266 goto exit;
267 }
268 /*
269 * Save off the data into a structure so the caller use it.
270 * Right now we only want the first 4 bytes,
271 * There are commands that need more, but not for the ones we
272 * currently care about.
273 */
274 sretval->retval[0] = readb(sabi_iface + SABI_IFACE_DATA);
275 sretval->retval[1] = readb(sabi_iface + SABI_IFACE_DATA + 1);
276 sretval->retval[2] = readb(sabi_iface + SABI_IFACE_DATA + 2);
277 sretval->retval[3] = readb(sabi_iface + SABI_IFACE_DATA + 3);
278
279exit:
280 mutex_unlock(&sabi_mutex);
281 return retval;
282
283}
284
285static int sabi_set_command(u8 command, u8 data)
286{
287 int retval = 0;
288 u16 port = readw(sabi + sabi_config->header_offsets.port);
289 u8 complete, iface_data;
290
291 mutex_lock(&sabi_mutex);
292
293 /* enable memory to be able to write to it */
294 outb(readb(sabi + sabi_config->header_offsets.en_mem), port);
295
296 /* write out the command */
297 writew(sabi_config->main_function, sabi_iface + SABI_IFACE_MAIN);
298 writew(command, sabi_iface + SABI_IFACE_SUB);
299 writeb(0, sabi_iface + SABI_IFACE_COMPLETE);
300 writeb(data, sabi_iface + SABI_IFACE_DATA);
301 outb(readb(sabi + sabi_config->header_offsets.iface_func), port);
302
303 /* write protect memory to make it safe */
304 outb(readb(sabi + sabi_config->header_offsets.re_mem), port);
305
306 /* see if the command actually succeeded */
307 complete = readb(sabi_iface + SABI_IFACE_COMPLETE);
308 iface_data = readb(sabi_iface + SABI_IFACE_DATA);
309 if (complete != 0xaa || iface_data == 0xff) {
310 pr_warn("SABI set command 0x%02x failed with completion flag 0x%02x and data 0x%02x\n",
311 command, complete, iface_data);
312 retval = -EINVAL;
313 }
314
315 mutex_unlock(&sabi_mutex);
316 return retval;
317}
318
319static void test_backlight(void)
320{
321 struct sabi_retval sretval;
322
323 sabi_get_command(sabi_config->commands.get_backlight, &sretval);
324 printk(KERN_DEBUG "backlight = 0x%02x\n", sretval.retval[0]);
325
326 sabi_set_command(sabi_config->commands.set_backlight, 0);
327 printk(KERN_DEBUG "backlight should be off\n");
328
329 sabi_get_command(sabi_config->commands.get_backlight, &sretval);
330 printk(KERN_DEBUG "backlight = 0x%02x\n", sretval.retval[0]);
331
332 msleep(1000);
333
334 sabi_set_command(sabi_config->commands.set_backlight, 1);
335 printk(KERN_DEBUG "backlight should be on\n");
336
337 sabi_get_command(sabi_config->commands.get_backlight, &sretval);
338 printk(KERN_DEBUG "backlight = 0x%02x\n", sretval.retval[0]);
339}
340
341static void test_wireless(void)
342{
343 struct sabi_retval sretval;
344
345 sabi_get_command(sabi_config->commands.get_wireless_button, &sretval);
346 printk(KERN_DEBUG "wireless led = 0x%02x\n", sretval.retval[0]);
347
348 sabi_set_command(sabi_config->commands.set_wireless_button, 0);
349 printk(KERN_DEBUG "wireless led should be off\n");
350
351 sabi_get_command(sabi_config->commands.get_wireless_button, &sretval);
352 printk(KERN_DEBUG "wireless led = 0x%02x\n", sretval.retval[0]);
353
354 msleep(1000);
355
356 sabi_set_command(sabi_config->commands.set_wireless_button, 1);
357 printk(KERN_DEBUG "wireless led should be on\n");
358
359 sabi_get_command(sabi_config->commands.get_wireless_button, &sretval);
360 printk(KERN_DEBUG "wireless led = 0x%02x\n", sretval.retval[0]);
361}
362
363static u8 read_brightness(void)
364{
365 struct sabi_retval sretval;
366 int user_brightness = 0;
367 int retval;
368
369 retval = sabi_get_command(sabi_config->commands.get_brightness,
370 &sretval);
371 if (!retval) {
372 user_brightness = sretval.retval[0];
373 if (user_brightness != 0)
374 user_brightness -= sabi_config->min_brightness;
375 }
376 return user_brightness;
377}
378
379static void set_brightness(u8 user_brightness)
380{
381 u8 user_level = user_brightness - sabi_config->min_brightness;
382
383 sabi_set_command(sabi_config->commands.set_brightness, user_level);
384}
385
386static int get_brightness(struct backlight_device *bd)
387{
388 return (int)read_brightness();
389}
390
391static int update_status(struct backlight_device *bd)
392{
393 set_brightness(bd->props.brightness);
394
395 if (bd->props.power == FB_BLANK_UNBLANK)
396 sabi_set_command(sabi_config->commands.set_backlight, 1);
397 else
398 sabi_set_command(sabi_config->commands.set_backlight, 0);
399 return 0;
400}
401
402static const struct backlight_ops backlight_ops = {
403 .get_brightness = get_brightness,
404 .update_status = update_status,
405};
406
407static int rfkill_set(void *data, bool blocked)
408{
409 /* Do something with blocked...*/
410 /*
411 * blocked == false is on
412 * blocked == true is off
413 */
414 if (blocked)
415 sabi_set_command(sabi_config->commands.set_wireless_button, 0);
416 else
417 sabi_set_command(sabi_config->commands.set_wireless_button, 1);
418
419 return 0;
420}
421
422static struct rfkill_ops rfkill_ops = {
423 .set_block = rfkill_set,
424};
425
426static int init_wireless(struct platform_device *sdev)
427{
428 int retval;
429
430 rfk = rfkill_alloc("samsung-wifi", &sdev->dev, RFKILL_TYPE_WLAN,
431 &rfkill_ops, NULL);
432 if (!rfk)
433 return -ENOMEM;
434
435 retval = rfkill_register(rfk);
436 if (retval) {
437 rfkill_destroy(rfk);
438 return -ENODEV;
439 }
440
441 return 0;
442}
443
444static void destroy_wireless(void)
445{
446 rfkill_unregister(rfk);
447 rfkill_destroy(rfk);
448}
449
450static ssize_t get_performance_level(struct device *dev,
451 struct device_attribute *attr, char *buf)
452{
453 struct sabi_retval sretval;
454 int retval;
455 int i;
456
457 /* Read the state */
458 retval = sabi_get_command(sabi_config->commands.get_performance_level,
459 &sretval);
460 if (retval)
461 return retval;
462
463 /* The logic is backwards, yeah, lots of fun... */
464 for (i = 0; sabi_config->performance_levels[i].name; ++i) {
465 if (sretval.retval[0] == sabi_config->performance_levels[i].value)
466 return sprintf(buf, "%s\n", sabi_config->performance_levels[i].name);
467 }
468 return sprintf(buf, "%s\n", "unknown");
469}
470
471static ssize_t set_performance_level(struct device *dev,
472 struct device_attribute *attr, const char *buf,
473 size_t count)
474{
475 if (count >= 1) {
476 int i;
477 for (i = 0; sabi_config->performance_levels[i].name; ++i) {
478 const struct sabi_performance_level *level =
479 &sabi_config->performance_levels[i];
480 if (!strncasecmp(level->name, buf, strlen(level->name))) {
481 sabi_set_command(sabi_config->commands.set_performance_level,
482 level->value);
483 break;
484 }
485 }
486 if (!sabi_config->performance_levels[i].name)
487 return -EINVAL;
488 }
489 return count;
490}
491static DEVICE_ATTR(performance_level, S_IWUSR | S_IRUGO,
492 get_performance_level, set_performance_level);
493
494
495static int __init dmi_check_cb(const struct dmi_system_id *id)
496{
497 pr_info("found laptop model '%s'\n",
498 id->ident);
499 return 1;
500}
501
502static struct dmi_system_id __initdata samsung_dmi_table[] = {
503 {
504 .ident = "N128",
505 .matches = {
506 DMI_MATCH(DMI_SYS_VENDOR,
507 "SAMSUNG ELECTRONICS CO., LTD."),
508 DMI_MATCH(DMI_PRODUCT_NAME, "N128"),
509 DMI_MATCH(DMI_BOARD_NAME, "N128"),
510 },
511 .callback = dmi_check_cb,
512 },
513 {
514 .ident = "N130",
515 .matches = {
516 DMI_MATCH(DMI_SYS_VENDOR,
517 "SAMSUNG ELECTRONICS CO., LTD."),
518 DMI_MATCH(DMI_PRODUCT_NAME, "N130"),
519 DMI_MATCH(DMI_BOARD_NAME, "N130"),
520 },
521 .callback = dmi_check_cb,
522 },
523 {
524 .ident = "X125",
525 .matches = {
526 DMI_MATCH(DMI_SYS_VENDOR,
527 "SAMSUNG ELECTRONICS CO., LTD."),
528 DMI_MATCH(DMI_PRODUCT_NAME, "X125"),
529 DMI_MATCH(DMI_BOARD_NAME, "X125"),
530 },
531 .callback = dmi_check_cb,
532 },
533 {
534 .ident = "X120/X170",
535 .matches = {
536 DMI_MATCH(DMI_SYS_VENDOR,
537 "SAMSUNG ELECTRONICS CO., LTD."),
538 DMI_MATCH(DMI_PRODUCT_NAME, "X120/X170"),
539 DMI_MATCH(DMI_BOARD_NAME, "X120/X170"),
540 },
541 .callback = dmi_check_cb,
542 },
543 {
544 .ident = "NC10",
545 .matches = {
546 DMI_MATCH(DMI_SYS_VENDOR,
547 "SAMSUNG ELECTRONICS CO., LTD."),
548 DMI_MATCH(DMI_PRODUCT_NAME, "NC10"),
549 DMI_MATCH(DMI_BOARD_NAME, "NC10"),
550 },
551 .callback = dmi_check_cb,
552 },
553 {
554 .ident = "NP-Q45",
555 .matches = {
556 DMI_MATCH(DMI_SYS_VENDOR,
557 "SAMSUNG ELECTRONICS CO., LTD."),
558 DMI_MATCH(DMI_PRODUCT_NAME, "SQ45S70S"),
559 DMI_MATCH(DMI_BOARD_NAME, "SQ45S70S"),
560 },
561 .callback = dmi_check_cb,
562 },
563 {
564 .ident = "X360",
565 .matches = {
566 DMI_MATCH(DMI_SYS_VENDOR,
567 "SAMSUNG ELECTRONICS CO., LTD."),
568 DMI_MATCH(DMI_PRODUCT_NAME, "X360"),
569 DMI_MATCH(DMI_BOARD_NAME, "X360"),
570 },
571 .callback = dmi_check_cb,
572 },
573 {
574 .ident = "R518",
575 .matches = {
576 DMI_MATCH(DMI_SYS_VENDOR,
577 "SAMSUNG ELECTRONICS CO., LTD."),
578 DMI_MATCH(DMI_PRODUCT_NAME, "R518"),
579 DMI_MATCH(DMI_BOARD_NAME, "R518"),
580 },
581 .callback = dmi_check_cb,
582 },
583 {
584 .ident = "R519/R719",
585 .matches = {
586 DMI_MATCH(DMI_SYS_VENDOR,
587 "SAMSUNG ELECTRONICS CO., LTD."),
588 DMI_MATCH(DMI_PRODUCT_NAME, "R519/R719"),
589 DMI_MATCH(DMI_BOARD_NAME, "R519/R719"),
590 },
591 .callback = dmi_check_cb,
592 },
593 {
594 .ident = "N150/N210/N220",
595 .matches = {
596 DMI_MATCH(DMI_SYS_VENDOR,
597 "SAMSUNG ELECTRONICS CO., LTD."),
598 DMI_MATCH(DMI_PRODUCT_NAME, "N150/N210/N220"),
599 DMI_MATCH(DMI_BOARD_NAME, "N150/N210/N220"),
600 },
601 .callback = dmi_check_cb,
602 },
603 {
604 .ident = "N150P/N210P/N220P",
605 .matches = {
606 DMI_MATCH(DMI_SYS_VENDOR,
607 "SAMSUNG ELECTRONICS CO., LTD."),
608 DMI_MATCH(DMI_PRODUCT_NAME, "N150P/N210P/N220P"),
609 DMI_MATCH(DMI_BOARD_NAME, "N150P/N210P/N220P"),
610 },
611 .callback = dmi_check_cb,
612 },
613 {
614 .ident = "R530/R730",
615 .matches = {
616 DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
617 DMI_MATCH(DMI_PRODUCT_NAME, "R530/R730"),
618 DMI_MATCH(DMI_BOARD_NAME, "R530/R730"),
619 },
620 .callback = dmi_check_cb,
621 },
622 {
623 .ident = "NF110/NF210/NF310",
624 .matches = {
625 DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
626 DMI_MATCH(DMI_PRODUCT_NAME, "NF110/NF210/NF310"),
627 DMI_MATCH(DMI_BOARD_NAME, "NF110/NF210/NF310"),
628 },
629 .callback = dmi_check_cb,
630 },
631 {
632 .ident = "N145P/N250P/N260P",
633 .matches = {
634 DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
635 DMI_MATCH(DMI_PRODUCT_NAME, "N145P/N250P/N260P"),
636 DMI_MATCH(DMI_BOARD_NAME, "N145P/N250P/N260P"),
637 },
638 .callback = dmi_check_cb,
639 },
640 {
641 .ident = "R70/R71",
642 .matches = {
643 DMI_MATCH(DMI_SYS_VENDOR,
644 "SAMSUNG ELECTRONICS CO., LTD."),
645 DMI_MATCH(DMI_PRODUCT_NAME, "R70/R71"),
646 DMI_MATCH(DMI_BOARD_NAME, "R70/R71"),
647 },
648 .callback = dmi_check_cb,
649 },
650 {
651 .ident = "P460",
652 .matches = {
653 DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
654 DMI_MATCH(DMI_PRODUCT_NAME, "P460"),
655 DMI_MATCH(DMI_BOARD_NAME, "P460"),
656 },
657 .callback = dmi_check_cb,
658 },
659 { },
660};
661MODULE_DEVICE_TABLE(dmi, samsung_dmi_table);
662
663static int find_signature(void __iomem *memcheck, const char *testStr)
664{
665 int i = 0;
666 int loca;
667
668 for (loca = 0; loca < 0xffff; loca++) {
669 char temp = readb(memcheck + loca);
670
671 if (temp == testStr[i]) {
672 if (i == strlen(testStr)-1)
673 break;
674 ++i;
675 } else {
676 i = 0;
677 }
678 }
679 return loca;
680}
681
682static int __init samsung_init(void)
683{
684 struct backlight_properties props;
685 struct sabi_retval sretval;
686 unsigned int ifaceP;
687 int i;
688 int loca;
689 int retval;
690
691 mutex_init(&sabi_mutex);
692
693 if (!force && !dmi_check_system(samsung_dmi_table))
694 return -ENODEV;
695
696 f0000_segment = ioremap_nocache(0xf0000, 0xffff);
697 if (!f0000_segment) {
698 pr_err("Can't map the segment at 0xf0000\n");
699 return -EINVAL;
700 }
701
702 /* Try to find one of the signatures in memory to find the header */
703 for (i = 0; sabi_configs[i].test_string != 0; ++i) {
704 sabi_config = &sabi_configs[i];
705 loca = find_signature(f0000_segment, sabi_config->test_string);
706 if (loca != 0xffff)
707 break;
708 }
709
710 if (loca == 0xffff) {
711 pr_err("This computer does not support SABI\n");
712 goto error_no_signature;
713 }
714
715 /* point to the SMI port Number */
716 loca += 1;
717 sabi = (f0000_segment + loca);
718
719 if (debug) {
720 printk(KERN_DEBUG "This computer supports SABI==%x\n",
721 loca + 0xf0000 - 6);
722 printk(KERN_DEBUG "SABI header:\n");
723 printk(KERN_DEBUG " SMI Port Number = 0x%04x\n",
724 readw(sabi + sabi_config->header_offsets.port));
725 printk(KERN_DEBUG " SMI Interface Function = 0x%02x\n",
726 readb(sabi + sabi_config->header_offsets.iface_func));
727 printk(KERN_DEBUG " SMI enable memory buffer = 0x%02x\n",
728 readb(sabi + sabi_config->header_offsets.en_mem));
729 printk(KERN_DEBUG " SMI restore memory buffer = 0x%02x\n",
730 readb(sabi + sabi_config->header_offsets.re_mem));
731 printk(KERN_DEBUG " SABI data offset = 0x%04x\n",
732 readw(sabi + sabi_config->header_offsets.data_offset));
733 printk(KERN_DEBUG " SABI data segment = 0x%04x\n",
734 readw(sabi + sabi_config->header_offsets.data_segment));
735 }
736
737 /* Get a pointer to the SABI Interface */
738 ifaceP = (readw(sabi + sabi_config->header_offsets.data_segment) & 0x0ffff) << 4;
739 ifaceP += readw(sabi + sabi_config->header_offsets.data_offset) & 0x0ffff;
740 sabi_iface = ioremap_nocache(ifaceP, 16);
741 if (!sabi_iface) {
742 pr_err("Can't remap %x\n", ifaceP);
743 goto exit;
744 }
745 if (debug) {
746 printk(KERN_DEBUG "ifaceP = 0x%08x\n", ifaceP);
747 printk(KERN_DEBUG "sabi_iface = %p\n", sabi_iface);
748
749 test_backlight();
750 test_wireless();
751
752 retval = sabi_get_command(sabi_config->commands.get_brightness,
753 &sretval);
754 printk(KERN_DEBUG "brightness = 0x%02x\n", sretval.retval[0]);
755 }
756
757 /* Turn on "Linux" mode in the BIOS */
758 if (sabi_config->commands.set_linux != 0xff) {
759 retval = sabi_set_command(sabi_config->commands.set_linux,
760 0x81);
761 if (retval) {
762 pr_warn("Linux mode was not set!\n");
763 goto error_no_platform;
764 }
765 }
766
767 /* knock up a platform device to hang stuff off of */
768 sdev = platform_device_register_simple("samsung", -1, NULL, 0);
769 if (IS_ERR(sdev))
770 goto error_no_platform;
771
772 /* create a backlight device to talk to this one */
773 memset(&props, 0, sizeof(struct backlight_properties));
774 props.max_brightness = sabi_config->max_brightness;
775 backlight_device = backlight_device_register("samsung", &sdev->dev,
776 NULL, &backlight_ops,
777 &props);
778 if (IS_ERR(backlight_device))
779 goto error_no_backlight;
780
781 backlight_device->props.brightness = read_brightness();
782 backlight_device->props.power = FB_BLANK_UNBLANK;
783 backlight_update_status(backlight_device);
784
785 retval = init_wireless(sdev);
786 if (retval)
787 goto error_no_rfk;
788
789 retval = device_create_file(&sdev->dev, &dev_attr_performance_level);
790 if (retval)
791 goto error_file_create;
792
793exit:
794 return 0;
795
796error_file_create:
797 destroy_wireless();
798
799error_no_rfk:
800 backlight_device_unregister(backlight_device);
801
802error_no_backlight:
803 platform_device_unregister(sdev);
804
805error_no_platform:
806 iounmap(sabi_iface);
807
808error_no_signature:
809 iounmap(f0000_segment);
810 return -EINVAL;
811}
812
813static void __exit samsung_exit(void)
814{
815 /* Turn off "Linux" mode in the BIOS */
816 if (sabi_config->commands.set_linux != 0xff)
817 sabi_set_command(sabi_config->commands.set_linux, 0x80);
818
819 device_remove_file(&sdev->dev, &dev_attr_performance_level);
820 backlight_device_unregister(backlight_device);
821 destroy_wireless();
822 iounmap(sabi_iface);
823 iounmap(f0000_segment);
824 platform_device_unregister(sdev);
825}
826
827module_init(samsung_init);
828module_exit(samsung_exit);
829
830MODULE_AUTHOR("Greg Kroah-Hartman <gregkh@suse.de>");
831MODULE_DESCRIPTION("Samsung Backlight driver");
832MODULE_LICENSE("GPL");
diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c
index 13d8d63bcca9..e642f5f29504 100644
--- a/drivers/platform/x86/sony-laptop.c
+++ b/drivers/platform/x86/sony-laptop.c
@@ -71,8 +71,9 @@
71#endif 71#endif
72 72
73#define DRV_PFX "sony-laptop: " 73#define DRV_PFX "sony-laptop: "
74#define dprintk(msg...) do { \ 74#define dprintk(msg...) do { \
75 if (debug) printk(KERN_WARNING DRV_PFX msg); \ 75 if (debug) \
76 pr_warn(DRV_PFX msg); \
76} while (0) 77} while (0)
77 78
78#define SONY_LAPTOP_DRIVER_VERSION "0.6" 79#define SONY_LAPTOP_DRIVER_VERSION "0.6"
@@ -124,6 +125,19 @@ MODULE_PARM_DESC(minor,
124 "default is -1 (automatic)"); 125 "default is -1 (automatic)");
125#endif 126#endif
126 127
128static int kbd_backlight; /* = 1 */
129module_param(kbd_backlight, int, 0444);
130MODULE_PARM_DESC(kbd_backlight,
131 "set this to 0 to disable keyboard backlight, "
132 "1 to enable it (default: 0)");
133
134static int kbd_backlight_timeout; /* = 0 */
135module_param(kbd_backlight_timeout, int, 0444);
136MODULE_PARM_DESC(kbd_backlight_timeout,
137 "set this to 0 to set the default 10 seconds timeout, "
138 "1 for 30 seconds, 2 for 60 seconds and 3 to disable timeout "
139 "(default: 0)");
140
127enum sony_nc_rfkill { 141enum sony_nc_rfkill {
128 SONY_WIFI, 142 SONY_WIFI,
129 SONY_BLUETOOTH, 143 SONY_BLUETOOTH,
@@ -402,7 +416,7 @@ static int sony_laptop_setup_input(struct acpi_device *acpi_device)
402 error = kfifo_alloc(&sony_laptop_input.fifo, 416 error = kfifo_alloc(&sony_laptop_input.fifo,
403 SONY_LAPTOP_BUF_SIZE, GFP_KERNEL); 417 SONY_LAPTOP_BUF_SIZE, GFP_KERNEL);
404 if (error) { 418 if (error) {
405 printk(KERN_ERR DRV_PFX "kfifo_alloc failed\n"); 419 pr_err(DRV_PFX "kfifo_alloc failed\n");
406 goto err_dec_users; 420 goto err_dec_users;
407 } 421 }
408 422
@@ -591,7 +605,7 @@ struct sony_nc_value {
591 int value; /* current setting */ 605 int value; /* current setting */
592 int valid; /* Has ever been set */ 606 int valid; /* Has ever been set */
593 int debug; /* active only in debug mode ? */ 607 int debug; /* active only in debug mode ? */
594 struct device_attribute devattr; /* sysfs atribute */ 608 struct device_attribute devattr; /* sysfs attribute */
595}; 609};
596 610
597#define SNC_HANDLE_NAMES(_name, _values...) \ 611#define SNC_HANDLE_NAMES(_name, _values...) \
@@ -686,7 +700,7 @@ static int acpi_callgetfunc(acpi_handle handle, char *name, int *result)
686 return 0; 700 return 0;
687 } 701 }
688 702
689 printk(KERN_WARNING DRV_PFX "acpi_callreadfunc failed\n"); 703 pr_warn(DRV_PFX "acpi_callreadfunc failed\n");
690 704
691 return -1; 705 return -1;
692} 706}
@@ -712,7 +726,7 @@ static int acpi_callsetfunc(acpi_handle handle, char *name, int value,
712 if (status == AE_OK) { 726 if (status == AE_OK) {
713 if (result != NULL) { 727 if (result != NULL) {
714 if (out_obj.type != ACPI_TYPE_INTEGER) { 728 if (out_obj.type != ACPI_TYPE_INTEGER) {
715 printk(KERN_WARNING DRV_PFX "acpi_evaluate_object bad " 729 pr_warn(DRV_PFX "acpi_evaluate_object bad "
716 "return type\n"); 730 "return type\n");
717 return -1; 731 return -1;
718 } 732 }
@@ -721,34 +735,103 @@ static int acpi_callsetfunc(acpi_handle handle, char *name, int value,
721 return 0; 735 return 0;
722 } 736 }
723 737
724 printk(KERN_WARNING DRV_PFX "acpi_evaluate_object failed\n"); 738 pr_warn(DRV_PFX "acpi_evaluate_object failed\n");
725 739
726 return -1; 740 return -1;
727} 741}
728 742
729static int sony_find_snc_handle(int handle) 743struct sony_nc_handles {
744 u16 cap[0x10];
745 struct device_attribute devattr;
746};
747
748static struct sony_nc_handles *handles;
749
750static ssize_t sony_nc_handles_show(struct device *dev,
751 struct device_attribute *attr, char *buffer)
752{
753 ssize_t len = 0;
754 int i;
755
756 for (i = 0; i < ARRAY_SIZE(handles->cap); i++) {
757 len += snprintf(buffer + len, PAGE_SIZE - len, "0x%.4x ",
758 handles->cap[i]);
759 }
760 len += snprintf(buffer + len, PAGE_SIZE - len, "\n");
761
762 return len;
763}
764
765static int sony_nc_handles_setup(struct platform_device *pd)
730{ 766{
731 int i; 767 int i;
732 int result; 768 int result;
733 769
734 for (i = 0x20; i < 0x30; i++) { 770 handles = kzalloc(sizeof(*handles), GFP_KERNEL);
735 acpi_callsetfunc(sony_nc_acpi_handle, "SN00", i, &result); 771 if (!handles)
736 if (result == handle) 772 return -ENOMEM;
737 return i-0x20; 773
774 sysfs_attr_init(&handles->devattr.attr);
775 handles->devattr.attr.name = "handles";
776 handles->devattr.attr.mode = S_IRUGO;
777 handles->devattr.show = sony_nc_handles_show;
778
779 for (i = 0; i < ARRAY_SIZE(handles->cap); i++) {
780 if (!acpi_callsetfunc(sony_nc_acpi_handle,
781 "SN00", i + 0x20, &result)) {
782 dprintk("caching handle 0x%.4x (offset: 0x%.2x)\n",
783 result, i);
784 handles->cap[i] = result;
785 }
786 }
787
788 /* allow reading capabilities via sysfs */
789 if (device_create_file(&pd->dev, &handles->devattr)) {
790 kfree(handles);
791 handles = NULL;
792 return -1;
793 }
794
795 return 0;
796}
797
798static int sony_nc_handles_cleanup(struct platform_device *pd)
799{
800 if (handles) {
801 device_remove_file(&pd->dev, &handles->devattr);
802 kfree(handles);
803 handles = NULL;
738 } 804 }
805 return 0;
806}
739 807
808static int sony_find_snc_handle(int handle)
809{
810 int i;
811 for (i = 0; i < 0x10; i++) {
812 if (handles->cap[i] == handle) {
813 dprintk("found handle 0x%.4x (offset: 0x%.2x)\n",
814 handle, i);
815 return i;
816 }
817 }
818 dprintk("handle 0x%.4x not found\n", handle);
740 return -1; 819 return -1;
741} 820}
742 821
743static int sony_call_snc_handle(int handle, int argument, int *result) 822static int sony_call_snc_handle(int handle, int argument, int *result)
744{ 823{
824 int ret = 0;
745 int offset = sony_find_snc_handle(handle); 825 int offset = sony_find_snc_handle(handle);
746 826
747 if (offset < 0) 827 if (offset < 0)
748 return -1; 828 return -1;
749 829
750 return acpi_callsetfunc(sony_nc_acpi_handle, "SN07", offset | argument, 830 ret = acpi_callsetfunc(sony_nc_acpi_handle, "SN07", offset | argument,
751 result); 831 result);
832 dprintk("called SN07 with 0x%.4x (result: 0x%.4x)\n", offset | argument,
833 *result);
834 return ret;
752} 835}
753 836
754/* 837/*
@@ -857,11 +940,39 @@ static int sony_backlight_get_brightness(struct backlight_device *bd)
857 return value - 1; 940 return value - 1;
858} 941}
859 942
860static struct backlight_device *sony_backlight_device; 943static int sony_nc_get_brightness_ng(struct backlight_device *bd)
944{
945 int result;
946 int *handle = (int *)bl_get_data(bd);
947
948 sony_call_snc_handle(*handle, 0x0200, &result);
949
950 return result & 0xff;
951}
952
953static int sony_nc_update_status_ng(struct backlight_device *bd)
954{
955 int value, result;
956 int *handle = (int *)bl_get_data(bd);
957
958 value = bd->props.brightness;
959 sony_call_snc_handle(*handle, 0x0100 | (value << 16), &result);
960
961 return sony_nc_get_brightness_ng(bd);
962}
963
861static const struct backlight_ops sony_backlight_ops = { 964static const struct backlight_ops sony_backlight_ops = {
965 .options = BL_CORE_SUSPENDRESUME,
862 .update_status = sony_backlight_update_status, 966 .update_status = sony_backlight_update_status,
863 .get_brightness = sony_backlight_get_brightness, 967 .get_brightness = sony_backlight_get_brightness,
864}; 968};
969static const struct backlight_ops sony_backlight_ng_ops = {
970 .options = BL_CORE_SUSPENDRESUME,
971 .update_status = sony_nc_update_status_ng,
972 .get_brightness = sony_nc_get_brightness_ng,
973};
974static int backlight_ng_handle;
975static struct backlight_device *sony_backlight_device;
865 976
866/* 977/*
867 * New SNC-only Vaios event mapping to driver known keys 978 * New SNC-only Vaios event mapping to driver known keys
@@ -972,7 +1083,7 @@ static void sony_nc_notify(struct acpi_device *device, u32 event)
972 } 1083 }
973 1084
974 if (!key_event->data) 1085 if (!key_event->data)
975 printk(KERN_INFO DRV_PFX 1086 pr_info(DRV_PFX
976 "Unknown event: 0x%x 0x%x\n", 1087 "Unknown event: 0x%x 0x%x\n",
977 key_handle, 1088 key_handle,
978 ev); 1089 ev);
@@ -996,7 +1107,7 @@ static acpi_status sony_walk_callback(acpi_handle handle, u32 level,
996 struct acpi_device_info *info; 1107 struct acpi_device_info *info;
997 1108
998 if (ACPI_SUCCESS(acpi_get_object_info(handle, &info))) { 1109 if (ACPI_SUCCESS(acpi_get_object_info(handle, &info))) {
999 printk(KERN_WARNING DRV_PFX "method: name: %4.4s, args %X\n", 1110 pr_warn(DRV_PFX "method: name: %4.4s, args %X\n",
1000 (char *)&info->name, info->param_count); 1111 (char *)&info->name, info->param_count);
1001 1112
1002 kfree(info); 1113 kfree(info);
@@ -1037,7 +1148,7 @@ static int sony_nc_resume(struct acpi_device *device)
1037 ret = acpi_callsetfunc(sony_nc_acpi_handle, *item->acpiset, 1148 ret = acpi_callsetfunc(sony_nc_acpi_handle, *item->acpiset,
1038 item->value, NULL); 1149 item->value, NULL);
1039 if (ret < 0) { 1150 if (ret < 0) {
1040 printk("%s: %d\n", __func__, ret); 1151 pr_err(DRV_PFX "%s: %d\n", __func__, ret);
1041 break; 1152 break;
1042 } 1153 }
1043 } 1154 }
@@ -1054,11 +1165,6 @@ static int sony_nc_resume(struct acpi_device *device)
1054 sony_nc_function_setup(device); 1165 sony_nc_function_setup(device);
1055 } 1166 }
1056 1167
1057 /* set the last requested brightness level */
1058 if (sony_backlight_device &&
1059 sony_backlight_update_status(sony_backlight_device) < 0)
1060 printk(KERN_WARNING DRV_PFX "unable to restore brightness level\n");
1061
1062 /* re-read rfkill state */ 1168 /* re-read rfkill state */
1063 sony_nc_rfkill_update(); 1169 sony_nc_rfkill_update();
1064 1170
@@ -1206,12 +1312,12 @@ static void sony_nc_rfkill_setup(struct acpi_device *device)
1206 1312
1207 device_enum = (union acpi_object *) buffer.pointer; 1313 device_enum = (union acpi_object *) buffer.pointer;
1208 if (!device_enum) { 1314 if (!device_enum) {
1209 pr_err("Invalid SN06 return object\n"); 1315 pr_err(DRV_PFX "No SN06 return object.");
1210 goto out_no_enum; 1316 goto out_no_enum;
1211 } 1317 }
1212 if (device_enum->type != ACPI_TYPE_BUFFER) { 1318 if (device_enum->type != ACPI_TYPE_BUFFER) {
1213 pr_err("Invalid SN06 return object type 0x%.2x\n", 1319 pr_err(DRV_PFX "Invalid SN06 return object 0x%.2x\n",
1214 device_enum->type); 1320 device_enum->type);
1215 goto out_no_enum; 1321 goto out_no_enum;
1216 } 1322 }
1217 1323
@@ -1245,6 +1351,209 @@ out_no_enum:
1245 return; 1351 return;
1246} 1352}
1247 1353
1354/* Keyboard backlight feature */
1355#define KBDBL_HANDLER 0x137
1356#define KBDBL_PRESENT 0xB00
1357#define SET_MODE 0xC00
1358#define SET_TIMEOUT 0xE00
1359
1360struct kbd_backlight {
1361 int mode;
1362 int timeout;
1363 struct device_attribute mode_attr;
1364 struct device_attribute timeout_attr;
1365};
1366
1367static struct kbd_backlight *kbdbl_handle;
1368
1369static ssize_t __sony_nc_kbd_backlight_mode_set(u8 value)
1370{
1371 int result;
1372
1373 if (value > 1)
1374 return -EINVAL;
1375
1376 if (sony_call_snc_handle(KBDBL_HANDLER,
1377 (value << 0x10) | SET_MODE, &result))
1378 return -EIO;
1379
1380 kbdbl_handle->mode = value;
1381
1382 return 0;
1383}
1384
1385static ssize_t sony_nc_kbd_backlight_mode_store(struct device *dev,
1386 struct device_attribute *attr,
1387 const char *buffer, size_t count)
1388{
1389 int ret = 0;
1390 unsigned long value;
1391
1392 if (count > 31)
1393 return -EINVAL;
1394
1395 if (strict_strtoul(buffer, 10, &value))
1396 return -EINVAL;
1397
1398 ret = __sony_nc_kbd_backlight_mode_set(value);
1399 if (ret < 0)
1400 return ret;
1401
1402 return count;
1403}
1404
1405static ssize_t sony_nc_kbd_backlight_mode_show(struct device *dev,
1406 struct device_attribute *attr, char *buffer)
1407{
1408 ssize_t count = 0;
1409 count = snprintf(buffer, PAGE_SIZE, "%d\n", kbdbl_handle->mode);
1410 return count;
1411}
1412
1413static int __sony_nc_kbd_backlight_timeout_set(u8 value)
1414{
1415 int result;
1416
1417 if (value > 3)
1418 return -EINVAL;
1419
1420 if (sony_call_snc_handle(KBDBL_HANDLER,
1421 (value << 0x10) | SET_TIMEOUT, &result))
1422 return -EIO;
1423
1424 kbdbl_handle->timeout = value;
1425
1426 return 0;
1427}
1428
1429static ssize_t sony_nc_kbd_backlight_timeout_store(struct device *dev,
1430 struct device_attribute *attr,
1431 const char *buffer, size_t count)
1432{
1433 int ret = 0;
1434 unsigned long value;
1435
1436 if (count > 31)
1437 return -EINVAL;
1438
1439 if (strict_strtoul(buffer, 10, &value))
1440 return -EINVAL;
1441
1442 ret = __sony_nc_kbd_backlight_timeout_set(value);
1443 if (ret < 0)
1444 return ret;
1445
1446 return count;
1447}
1448
1449static ssize_t sony_nc_kbd_backlight_timeout_show(struct device *dev,
1450 struct device_attribute *attr, char *buffer)
1451{
1452 ssize_t count = 0;
1453 count = snprintf(buffer, PAGE_SIZE, "%d\n", kbdbl_handle->timeout);
1454 return count;
1455}
1456
1457static int sony_nc_kbd_backlight_setup(struct platform_device *pd)
1458{
1459 int result;
1460
1461 if (sony_call_snc_handle(0x137, KBDBL_PRESENT, &result))
1462 return 0;
1463 if (!(result & 0x02))
1464 return 0;
1465
1466 kbdbl_handle = kzalloc(sizeof(*kbdbl_handle), GFP_KERNEL);
1467 if (!kbdbl_handle)
1468 return -ENOMEM;
1469
1470 sysfs_attr_init(&kbdbl_handle->mode_attr.attr);
1471 kbdbl_handle->mode_attr.attr.name = "kbd_backlight";
1472 kbdbl_handle->mode_attr.attr.mode = S_IRUGO | S_IWUSR;
1473 kbdbl_handle->mode_attr.show = sony_nc_kbd_backlight_mode_show;
1474 kbdbl_handle->mode_attr.store = sony_nc_kbd_backlight_mode_store;
1475
1476 sysfs_attr_init(&kbdbl_handle->timeout_attr.attr);
1477 kbdbl_handle->timeout_attr.attr.name = "kbd_backlight_timeout";
1478 kbdbl_handle->timeout_attr.attr.mode = S_IRUGO | S_IWUSR;
1479 kbdbl_handle->timeout_attr.show = sony_nc_kbd_backlight_timeout_show;
1480 kbdbl_handle->timeout_attr.store = sony_nc_kbd_backlight_timeout_store;
1481
1482 if (device_create_file(&pd->dev, &kbdbl_handle->mode_attr))
1483 goto outkzalloc;
1484
1485 if (device_create_file(&pd->dev, &kbdbl_handle->timeout_attr))
1486 goto outmode;
1487
1488 __sony_nc_kbd_backlight_mode_set(kbd_backlight);
1489 __sony_nc_kbd_backlight_timeout_set(kbd_backlight_timeout);
1490
1491 return 0;
1492
1493outmode:
1494 device_remove_file(&pd->dev, &kbdbl_handle->mode_attr);
1495outkzalloc:
1496 kfree(kbdbl_handle);
1497 kbdbl_handle = NULL;
1498 return -1;
1499}
1500
1501static int sony_nc_kbd_backlight_cleanup(struct platform_device *pd)
1502{
1503 if (kbdbl_handle) {
1504 device_remove_file(&pd->dev, &kbdbl_handle->mode_attr);
1505 device_remove_file(&pd->dev, &kbdbl_handle->timeout_attr);
1506 kfree(kbdbl_handle);
1507 }
1508 return 0;
1509}
1510
1511static void sony_nc_backlight_setup(void)
1512{
1513 acpi_handle unused;
1514 int max_brightness = 0;
1515 const struct backlight_ops *ops = NULL;
1516 struct backlight_properties props;
1517
1518 if (sony_find_snc_handle(0x12f) != -1) {
1519 backlight_ng_handle = 0x12f;
1520 ops = &sony_backlight_ng_ops;
1521 max_brightness = 0xff;
1522
1523 } else if (sony_find_snc_handle(0x137) != -1) {
1524 backlight_ng_handle = 0x137;
1525 ops = &sony_backlight_ng_ops;
1526 max_brightness = 0xff;
1527
1528 } else if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "GBRT",
1529 &unused))) {
1530 ops = &sony_backlight_ops;
1531 max_brightness = SONY_MAX_BRIGHTNESS - 1;
1532
1533 } else
1534 return;
1535
1536 memset(&props, 0, sizeof(struct backlight_properties));
1537 props.type = BACKLIGHT_PLATFORM;
1538 props.max_brightness = max_brightness;
1539 sony_backlight_device = backlight_device_register("sony", NULL,
1540 &backlight_ng_handle,
1541 ops, &props);
1542
1543 if (IS_ERR(sony_backlight_device)) {
1544 pr_warning(DRV_PFX "unable to register backlight device\n");
1545 sony_backlight_device = NULL;
1546 } else
1547 sony_backlight_device->props.brightness =
1548 ops->get_brightness(sony_backlight_device);
1549}
1550
1551static void sony_nc_backlight_cleanup(void)
1552{
1553 if (sony_backlight_device)
1554 backlight_device_unregister(sony_backlight_device);
1555}
1556
1248static int sony_nc_add(struct acpi_device *device) 1557static int sony_nc_add(struct acpi_device *device)
1249{ 1558{
1250 acpi_status status; 1559 acpi_status status;
@@ -1252,8 +1561,8 @@ static int sony_nc_add(struct acpi_device *device)
1252 acpi_handle handle; 1561 acpi_handle handle;
1253 struct sony_nc_value *item; 1562 struct sony_nc_value *item;
1254 1563
1255 printk(KERN_INFO DRV_PFX "%s v%s.\n", 1564 pr_info(DRV_PFX "%s v%s.\n", SONY_NC_DRIVER_NAME,
1256 SONY_NC_DRIVER_NAME, SONY_LAPTOP_DRIVER_VERSION); 1565 SONY_LAPTOP_DRIVER_VERSION);
1257 1566
1258 sony_nc_acpi_device = device; 1567 sony_nc_acpi_device = device;
1259 strcpy(acpi_device_class(device), "sony/hotkey"); 1568 strcpy(acpi_device_class(device), "sony/hotkey");
@@ -1269,13 +1578,18 @@ static int sony_nc_add(struct acpi_device *device)
1269 goto outwalk; 1578 goto outwalk;
1270 } 1579 }
1271 1580
1581 result = sony_pf_add();
1582 if (result)
1583 goto outpresent;
1584
1272 if (debug) { 1585 if (debug) {
1273 status = acpi_walk_namespace(ACPI_TYPE_METHOD, sony_nc_acpi_handle, 1586 status = acpi_walk_namespace(ACPI_TYPE_METHOD,
1274 1, sony_walk_callback, NULL, NULL, NULL); 1587 sony_nc_acpi_handle, 1, sony_walk_callback,
1588 NULL, NULL, NULL);
1275 if (ACPI_FAILURE(status)) { 1589 if (ACPI_FAILURE(status)) {
1276 printk(KERN_WARNING DRV_PFX "unable to walk acpi resources\n"); 1590 pr_warn(DRV_PFX "unable to walk acpi resources\n");
1277 result = -ENODEV; 1591 result = -ENODEV;
1278 goto outwalk; 1592 goto outpresent;
1279 } 1593 }
1280 } 1594 }
1281 1595
@@ -1288,6 +1602,12 @@ static int sony_nc_add(struct acpi_device *device)
1288 if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "SN00", 1602 if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "SN00",
1289 &handle))) { 1603 &handle))) {
1290 dprintk("Doing SNC setup\n"); 1604 dprintk("Doing SNC setup\n");
1605 result = sony_nc_handles_setup(sony_pf_device);
1606 if (result)
1607 goto outpresent;
1608 result = sony_nc_kbd_backlight_setup(sony_pf_device);
1609 if (result)
1610 goto outsnc;
1291 sony_nc_function_setup(device); 1611 sony_nc_function_setup(device);
1292 sony_nc_rfkill_setup(device); 1612 sony_nc_rfkill_setup(device);
1293 } 1613 }
@@ -1295,40 +1615,17 @@ static int sony_nc_add(struct acpi_device *device)
1295 /* setup input devices and helper fifo */ 1615 /* setup input devices and helper fifo */
1296 result = sony_laptop_setup_input(device); 1616 result = sony_laptop_setup_input(device);
1297 if (result) { 1617 if (result) {
1298 printk(KERN_ERR DRV_PFX 1618 pr_err(DRV_PFX "Unable to create input devices.\n");
1299 "Unable to create input devices.\n"); 1619 goto outkbdbacklight;
1300 goto outwalk;
1301 } 1620 }
1302 1621
1303 if (acpi_video_backlight_support()) { 1622 if (acpi_video_backlight_support()) {
1304 printk(KERN_INFO DRV_PFX "brightness ignored, must be " 1623 pr_info(DRV_PFX "brightness ignored, must be "
1305 "controlled by ACPI video driver\n"); 1624 "controlled by ACPI video driver\n");
1306 } else if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "GBRT", 1625 } else {
1307 &handle))) { 1626 sony_nc_backlight_setup();
1308 struct backlight_properties props;
1309 memset(&props, 0, sizeof(struct backlight_properties));
1310 props.type = BACKLIGHT_PLATFORM;
1311 props.max_brightness = SONY_MAX_BRIGHTNESS - 1;
1312 sony_backlight_device = backlight_device_register("sony", NULL,
1313 NULL,
1314 &sony_backlight_ops,
1315 &props);
1316
1317 if (IS_ERR(sony_backlight_device)) {
1318 printk(KERN_WARNING DRV_PFX "unable to register backlight device\n");
1319 sony_backlight_device = NULL;
1320 } else {
1321 sony_backlight_device->props.brightness =
1322 sony_backlight_get_brightness
1323 (sony_backlight_device);
1324 }
1325
1326 } 1627 }
1327 1628
1328 result = sony_pf_add();
1329 if (result)
1330 goto outbacklight;
1331
1332 /* create sony_pf sysfs attributes related to the SNC device */ 1629 /* create sony_pf sysfs attributes related to the SNC device */
1333 for (item = sony_nc_values; item->name; ++item) { 1630 for (item = sony_nc_values; item->name; ++item) {
1334 1631
@@ -1374,14 +1671,19 @@ static int sony_nc_add(struct acpi_device *device)
1374 for (item = sony_nc_values; item->name; ++item) { 1671 for (item = sony_nc_values; item->name; ++item) {
1375 device_remove_file(&sony_pf_device->dev, &item->devattr); 1672 device_remove_file(&sony_pf_device->dev, &item->devattr);
1376 } 1673 }
1377 sony_pf_remove(); 1674 sony_nc_backlight_cleanup();
1378
1379 outbacklight:
1380 if (sony_backlight_device)
1381 backlight_device_unregister(sony_backlight_device);
1382 1675
1383 sony_laptop_remove_input(); 1676 sony_laptop_remove_input();
1384 1677
1678 outkbdbacklight:
1679 sony_nc_kbd_backlight_cleanup(sony_pf_device);
1680
1681 outsnc:
1682 sony_nc_handles_cleanup(sony_pf_device);
1683
1684 outpresent:
1685 sony_pf_remove();
1686
1385 outwalk: 1687 outwalk:
1386 sony_nc_rfkill_cleanup(); 1688 sony_nc_rfkill_cleanup();
1387 return result; 1689 return result;
@@ -1391,8 +1693,7 @@ static int sony_nc_remove(struct acpi_device *device, int type)
1391{ 1693{
1392 struct sony_nc_value *item; 1694 struct sony_nc_value *item;
1393 1695
1394 if (sony_backlight_device) 1696 sony_nc_backlight_cleanup();
1395 backlight_device_unregister(sony_backlight_device);
1396 1697
1397 sony_nc_acpi_device = NULL; 1698 sony_nc_acpi_device = NULL;
1398 1699
@@ -1400,6 +1701,8 @@ static int sony_nc_remove(struct acpi_device *device, int type)
1400 device_remove_file(&sony_pf_device->dev, &item->devattr); 1701 device_remove_file(&sony_pf_device->dev, &item->devattr);
1401 } 1702 }
1402 1703
1704 sony_nc_kbd_backlight_cleanup(sony_pf_device);
1705 sony_nc_handles_cleanup(sony_pf_device);
1403 sony_pf_remove(); 1706 sony_pf_remove();
1404 sony_laptop_remove_input(); 1707 sony_laptop_remove_input();
1405 sony_nc_rfkill_cleanup(); 1708 sony_nc_rfkill_cleanup();
@@ -1438,7 +1741,6 @@ static struct acpi_driver sony_nc_driver = {
1438#define SONYPI_DEVICE_TYPE1 0x00000001 1741#define SONYPI_DEVICE_TYPE1 0x00000001
1439#define SONYPI_DEVICE_TYPE2 0x00000002 1742#define SONYPI_DEVICE_TYPE2 0x00000002
1440#define SONYPI_DEVICE_TYPE3 0x00000004 1743#define SONYPI_DEVICE_TYPE3 0x00000004
1441#define SONYPI_DEVICE_TYPE4 0x00000008
1442 1744
1443#define SONYPI_TYPE1_OFFSET 0x04 1745#define SONYPI_TYPE1_OFFSET 0x04
1444#define SONYPI_TYPE2_OFFSET 0x12 1746#define SONYPI_TYPE2_OFFSET 0x12
@@ -1584,8 +1886,8 @@ static struct sonypi_event sonypi_blueev[] = {
1584 1886
1585/* The set of possible wireless events */ 1887/* The set of possible wireless events */
1586static struct sonypi_event sonypi_wlessev[] = { 1888static struct sonypi_event sonypi_wlessev[] = {
1587 { 0x59, SONYPI_EVENT_WIRELESS_ON }, 1889 { 0x59, SONYPI_EVENT_IGNORE },
1588 { 0x5a, SONYPI_EVENT_WIRELESS_OFF }, 1890 { 0x5a, SONYPI_EVENT_IGNORE },
1589 { 0, 0 } 1891 { 0, 0 }
1590}; 1892};
1591 1893
@@ -1842,7 +2144,7 @@ out:
1842 if (pcidev) 2144 if (pcidev)
1843 pci_dev_put(pcidev); 2145 pci_dev_put(pcidev);
1844 2146
1845 printk(KERN_INFO DRV_PFX "detected Type%d model\n", 2147 pr_info(DRV_PFX "detected Type%d model\n",
1846 dev->model == SONYPI_DEVICE_TYPE1 ? 1 : 2148 dev->model == SONYPI_DEVICE_TYPE1 ? 1 :
1847 dev->model == SONYPI_DEVICE_TYPE2 ? 2 : 3); 2149 dev->model == SONYPI_DEVICE_TYPE2 ? 2 : 3);
1848} 2150}
@@ -1890,7 +2192,7 @@ static int __sony_pic_camera_ready(void)
1890static int __sony_pic_camera_off(void) 2192static int __sony_pic_camera_off(void)
1891{ 2193{
1892 if (!camera) { 2194 if (!camera) {
1893 printk(KERN_WARNING DRV_PFX "camera control not enabled\n"); 2195 pr_warn(DRV_PFX "camera control not enabled\n");
1894 return -ENODEV; 2196 return -ENODEV;
1895 } 2197 }
1896 2198
@@ -1910,7 +2212,7 @@ static int __sony_pic_camera_on(void)
1910 int i, j, x; 2212 int i, j, x;
1911 2213
1912 if (!camera) { 2214 if (!camera) {
1913 printk(KERN_WARNING DRV_PFX "camera control not enabled\n"); 2215 pr_warn(DRV_PFX "camera control not enabled\n");
1914 return -ENODEV; 2216 return -ENODEV;
1915 } 2217 }
1916 2218
@@ -1933,7 +2235,7 @@ static int __sony_pic_camera_on(void)
1933 } 2235 }
1934 2236
1935 if (j == 0) { 2237 if (j == 0) {
1936 printk(KERN_WARNING DRV_PFX "failed to power on camera\n"); 2238 pr_warn(DRV_PFX "failed to power on camera\n");
1937 return -ENODEV; 2239 return -ENODEV;
1938 } 2240 }
1939 2241
@@ -1989,7 +2291,7 @@ int sony_pic_camera_command(int command, u8 value)
1989 ITERATIONS_SHORT); 2291 ITERATIONS_SHORT);
1990 break; 2292 break;
1991 default: 2293 default:
1992 printk(KERN_ERR DRV_PFX "sony_pic_camera_command invalid: %d\n", 2294 pr_err(DRV_PFX "sony_pic_camera_command invalid: %d\n",
1993 command); 2295 command);
1994 break; 2296 break;
1995 } 2297 }
@@ -2396,7 +2698,7 @@ static int sonypi_compat_init(void)
2396 error = 2698 error =
2397 kfifo_alloc(&sonypi_compat.fifo, SONY_LAPTOP_BUF_SIZE, GFP_KERNEL); 2699 kfifo_alloc(&sonypi_compat.fifo, SONY_LAPTOP_BUF_SIZE, GFP_KERNEL);
2398 if (error) { 2700 if (error) {
2399 printk(KERN_ERR DRV_PFX "kfifo_alloc failed\n"); 2701 pr_err(DRV_PFX "kfifo_alloc failed\n");
2400 return error; 2702 return error;
2401 } 2703 }
2402 2704
@@ -2406,11 +2708,11 @@ static int sonypi_compat_init(void)
2406 sonypi_misc_device.minor = minor; 2708 sonypi_misc_device.minor = minor;
2407 error = misc_register(&sonypi_misc_device); 2709 error = misc_register(&sonypi_misc_device);
2408 if (error) { 2710 if (error) {
2409 printk(KERN_ERR DRV_PFX "misc_register failed\n"); 2711 pr_err(DRV_PFX "misc_register failed\n");
2410 goto err_free_kfifo; 2712 goto err_free_kfifo;
2411 } 2713 }
2412 if (minor == -1) 2714 if (minor == -1)
2413 printk(KERN_INFO DRV_PFX "device allocated minor is %d\n", 2715 pr_info(DRV_PFX "device allocated minor is %d\n",
2414 sonypi_misc_device.minor); 2716 sonypi_misc_device.minor);
2415 2717
2416 return 0; 2718 return 0;
@@ -2470,8 +2772,7 @@ sony_pic_read_possible_resource(struct acpi_resource *resource, void *context)
2470 } 2772 }
2471 for (i = 0; i < p->interrupt_count; i++) { 2773 for (i = 0; i < p->interrupt_count; i++) {
2472 if (!p->interrupts[i]) { 2774 if (!p->interrupts[i]) {
2473 printk(KERN_WARNING DRV_PFX 2775 pr_warn(DRV_PFX "Invalid IRQ %d\n",
2474 "Invalid IRQ %d\n",
2475 p->interrupts[i]); 2776 p->interrupts[i]);
2476 continue; 2777 continue;
2477 } 2778 }
@@ -2510,7 +2811,7 @@ sony_pic_read_possible_resource(struct acpi_resource *resource, void *context)
2510 ioport->io2.address_length); 2811 ioport->io2.address_length);
2511 } 2812 }
2512 else { 2813 else {
2513 printk(KERN_ERR DRV_PFX "Unknown SPIC Type, more than 2 IO Ports\n"); 2814 pr_err(DRV_PFX "Unknown SPIC Type, more than 2 IO Ports\n");
2514 return AE_ERROR; 2815 return AE_ERROR;
2515 } 2816 }
2516 return AE_OK; 2817 return AE_OK;
@@ -2538,7 +2839,7 @@ static int sony_pic_possible_resources(struct acpi_device *device)
2538 dprintk("Evaluating _STA\n"); 2839 dprintk("Evaluating _STA\n");
2539 result = acpi_bus_get_status(device); 2840 result = acpi_bus_get_status(device);
2540 if (result) { 2841 if (result) {
2541 printk(KERN_WARNING DRV_PFX "Unable to read status\n"); 2842 pr_warn(DRV_PFX "Unable to read status\n");
2542 goto end; 2843 goto end;
2543 } 2844 }
2544 2845
@@ -2554,8 +2855,7 @@ static int sony_pic_possible_resources(struct acpi_device *device)
2554 status = acpi_walk_resources(device->handle, METHOD_NAME__PRS, 2855 status = acpi_walk_resources(device->handle, METHOD_NAME__PRS,
2555 sony_pic_read_possible_resource, &spic_dev); 2856 sony_pic_read_possible_resource, &spic_dev);
2556 if (ACPI_FAILURE(status)) { 2857 if (ACPI_FAILURE(status)) {
2557 printk(KERN_WARNING DRV_PFX 2858 pr_warn(DRV_PFX "Failure evaluating %s\n",
2558 "Failure evaluating %s\n",
2559 METHOD_NAME__PRS); 2859 METHOD_NAME__PRS);
2560 result = -ENODEV; 2860 result = -ENODEV;
2561 } 2861 }
@@ -2669,7 +2969,7 @@ static int sony_pic_enable(struct acpi_device *device,
2669 2969
2670 /* check for total failure */ 2970 /* check for total failure */
2671 if (ACPI_FAILURE(status)) { 2971 if (ACPI_FAILURE(status)) {
2672 printk(KERN_ERR DRV_PFX "Error evaluating _SRS\n"); 2972 pr_err(DRV_PFX "Error evaluating _SRS\n");
2673 result = -ENODEV; 2973 result = -ENODEV;
2674 goto end; 2974 goto end;
2675 } 2975 }
@@ -2725,6 +3025,9 @@ static irqreturn_t sony_pic_irq(int irq, void *dev_id)
2725 if (ev == dev->event_types[i].events[j].data) { 3025 if (ev == dev->event_types[i].events[j].data) {
2726 device_event = 3026 device_event =
2727 dev->event_types[i].events[j].event; 3027 dev->event_types[i].events[j].event;
3028 /* some events may require ignoring */
3029 if (!device_event)
3030 return IRQ_HANDLED;
2728 goto found; 3031 goto found;
2729 } 3032 }
2730 } 3033 }
@@ -2744,7 +3047,6 @@ found:
2744 sony_laptop_report_input_event(device_event); 3047 sony_laptop_report_input_event(device_event);
2745 acpi_bus_generate_proc_event(dev->acpi_dev, 1, device_event); 3048 acpi_bus_generate_proc_event(dev->acpi_dev, 1, device_event);
2746 sonypi_compat_report_event(device_event); 3049 sonypi_compat_report_event(device_event);
2747
2748 return IRQ_HANDLED; 3050 return IRQ_HANDLED;
2749} 3051}
2750 3052
@@ -2759,7 +3061,7 @@ static int sony_pic_remove(struct acpi_device *device, int type)
2759 struct sony_pic_irq *irq, *tmp_irq; 3061 struct sony_pic_irq *irq, *tmp_irq;
2760 3062
2761 if (sony_pic_disable(device)) { 3063 if (sony_pic_disable(device)) {
2762 printk(KERN_ERR DRV_PFX "Couldn't disable device.\n"); 3064 pr_err(DRV_PFX "Couldn't disable device.\n");
2763 return -ENXIO; 3065 return -ENXIO;
2764 } 3066 }
2765 3067
@@ -2799,8 +3101,8 @@ static int sony_pic_add(struct acpi_device *device)
2799 struct sony_pic_ioport *io, *tmp_io; 3101 struct sony_pic_ioport *io, *tmp_io;
2800 struct sony_pic_irq *irq, *tmp_irq; 3102 struct sony_pic_irq *irq, *tmp_irq;
2801 3103
2802 printk(KERN_INFO DRV_PFX "%s v%s.\n", 3104 pr_info(DRV_PFX "%s v%s.\n", SONY_PIC_DRIVER_NAME,
2803 SONY_PIC_DRIVER_NAME, SONY_LAPTOP_DRIVER_VERSION); 3105 SONY_LAPTOP_DRIVER_VERSION);
2804 3106
2805 spic_dev.acpi_dev = device; 3107 spic_dev.acpi_dev = device;
2806 strcpy(acpi_device_class(device), "sony/hotkey"); 3108 strcpy(acpi_device_class(device), "sony/hotkey");
@@ -2810,16 +3112,14 @@ static int sony_pic_add(struct acpi_device *device)
2810 /* read _PRS resources */ 3112 /* read _PRS resources */
2811 result = sony_pic_possible_resources(device); 3113 result = sony_pic_possible_resources(device);
2812 if (result) { 3114 if (result) {
2813 printk(KERN_ERR DRV_PFX 3115 pr_err(DRV_PFX "Unable to read possible resources.\n");
2814 "Unable to read possible resources.\n");
2815 goto err_free_resources; 3116 goto err_free_resources;
2816 } 3117 }
2817 3118
2818 /* setup input devices and helper fifo */ 3119 /* setup input devices and helper fifo */
2819 result = sony_laptop_setup_input(device); 3120 result = sony_laptop_setup_input(device);
2820 if (result) { 3121 if (result) {
2821 printk(KERN_ERR DRV_PFX 3122 pr_err(DRV_PFX "Unable to create input devices.\n");
2822 "Unable to create input devices.\n");
2823 goto err_free_resources; 3123 goto err_free_resources;
2824 } 3124 }
2825 3125
@@ -2829,7 +3129,7 @@ static int sony_pic_add(struct acpi_device *device)
2829 /* request io port */ 3129 /* request io port */
2830 list_for_each_entry_reverse(io, &spic_dev.ioports, list) { 3130 list_for_each_entry_reverse(io, &spic_dev.ioports, list) {
2831 if (request_region(io->io1.minimum, io->io1.address_length, 3131 if (request_region(io->io1.minimum, io->io1.address_length,
2832 "Sony Programable I/O Device")) { 3132 "Sony Programmable I/O Device")) {
2833 dprintk("I/O port1: 0x%.4x (0x%.4x) + 0x%.2x\n", 3133 dprintk("I/O port1: 0x%.4x (0x%.4x) + 0x%.2x\n",
2834 io->io1.minimum, io->io1.maximum, 3134 io->io1.minimum, io->io1.maximum,
2835 io->io1.address_length); 3135 io->io1.address_length);
@@ -2837,7 +3137,7 @@ static int sony_pic_add(struct acpi_device *device)
2837 if (io->io2.minimum) { 3137 if (io->io2.minimum) {
2838 if (request_region(io->io2.minimum, 3138 if (request_region(io->io2.minimum,
2839 io->io2.address_length, 3139 io->io2.address_length,
2840 "Sony Programable I/O Device")) { 3140 "Sony Programmable I/O Device")) {
2841 dprintk("I/O port2: 0x%.4x (0x%.4x) + 0x%.2x\n", 3141 dprintk("I/O port2: 0x%.4x (0x%.4x) + 0x%.2x\n",
2842 io->io2.minimum, io->io2.maximum, 3142 io->io2.minimum, io->io2.maximum,
2843 io->io2.address_length); 3143 io->io2.address_length);
@@ -2860,7 +3160,7 @@ static int sony_pic_add(struct acpi_device *device)
2860 } 3160 }
2861 } 3161 }
2862 if (!spic_dev.cur_ioport) { 3162 if (!spic_dev.cur_ioport) {
2863 printk(KERN_ERR DRV_PFX "Failed to request_region.\n"); 3163 pr_err(DRV_PFX "Failed to request_region.\n");
2864 result = -ENODEV; 3164 result = -ENODEV;
2865 goto err_remove_compat; 3165 goto err_remove_compat;
2866 } 3166 }
@@ -2880,7 +3180,7 @@ static int sony_pic_add(struct acpi_device *device)
2880 } 3180 }
2881 } 3181 }
2882 if (!spic_dev.cur_irq) { 3182 if (!spic_dev.cur_irq) {
2883 printk(KERN_ERR DRV_PFX "Failed to request_irq.\n"); 3183 pr_err(DRV_PFX "Failed to request_irq.\n");
2884 result = -ENODEV; 3184 result = -ENODEV;
2885 goto err_release_region; 3185 goto err_release_region;
2886 } 3186 }
@@ -2888,7 +3188,7 @@ static int sony_pic_add(struct acpi_device *device)
2888 /* set resource status _SRS */ 3188 /* set resource status _SRS */
2889 result = sony_pic_enable(device, spic_dev.cur_ioport, spic_dev.cur_irq); 3189 result = sony_pic_enable(device, spic_dev.cur_ioport, spic_dev.cur_irq);
2890 if (result) { 3190 if (result) {
2891 printk(KERN_ERR DRV_PFX "Couldn't enable device.\n"); 3191 pr_err(DRV_PFX "Couldn't enable device.\n");
2892 goto err_free_irq; 3192 goto err_free_irq;
2893 } 3193 }
2894 3194
@@ -2997,8 +3297,7 @@ static int __init sony_laptop_init(void)
2997 if (!no_spic && dmi_check_system(sonypi_dmi_table)) { 3297 if (!no_spic && dmi_check_system(sonypi_dmi_table)) {
2998 result = acpi_bus_register_driver(&sony_pic_driver); 3298 result = acpi_bus_register_driver(&sony_pic_driver);
2999 if (result) { 3299 if (result) {
3000 printk(KERN_ERR DRV_PFX 3300 pr_err(DRV_PFX "Unable to register SPIC driver.");
3001 "Unable to register SPIC driver.");
3002 goto out; 3301 goto out;
3003 } 3302 }
3004 spic_drv_registered = 1; 3303 spic_drv_registered = 1;
@@ -3006,7 +3305,7 @@ static int __init sony_laptop_init(void)
3006 3305
3007 result = acpi_bus_register_driver(&sony_nc_driver); 3306 result = acpi_bus_register_driver(&sony_nc_driver);
3008 if (result) { 3307 if (result) {
3009 printk(KERN_ERR DRV_PFX "Unable to register SNC driver."); 3308 pr_err(DRV_PFX "Unable to register SNC driver.");
3010 goto out_unregister_pic; 3309 goto out_unregister_pic;
3011 } 3310 }
3012 3311
diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c
index 947bdcaa0ce9..a08561f5349e 100644
--- a/drivers/platform/x86/thinkpad_acpi.c
+++ b/drivers/platform/x86/thinkpad_acpi.c
@@ -2407,7 +2407,7 @@ static void hotkey_compare_and_issue_event(struct tp_nvram_state *oldn,
2407 * This code is supposed to duplicate the IBM firmware behaviour: 2407 * This code is supposed to duplicate the IBM firmware behaviour:
2408 * - Pressing MUTE issues mute hotkey message, even when already mute 2408 * - Pressing MUTE issues mute hotkey message, even when already mute
2409 * - Pressing Volume up/down issues volume up/down hotkey messages, 2409 * - Pressing Volume up/down issues volume up/down hotkey messages,
2410 * even when already at maximum or minumum volume 2410 * even when already at maximum or minimum volume
2411 * - The act of unmuting issues volume up/down notification, 2411 * - The act of unmuting issues volume up/down notification,
2412 * depending which key was used to unmute 2412 * depending which key was used to unmute
2413 * 2413 *
@@ -2990,7 +2990,7 @@ static void tpacpi_send_radiosw_update(void)
2990 * rfkill input events, or we will race the rfkill core input 2990 * rfkill input events, or we will race the rfkill core input
2991 * handler. 2991 * handler.
2992 * 2992 *
2993 * tpacpi_inputdev_send_mutex works as a syncronization point 2993 * tpacpi_inputdev_send_mutex works as a synchronization point
2994 * for the above. 2994 * for the above.
2995 * 2995 *
2996 * We optimize to avoid numerous calls to hotkey_get_wlsw. 2996 * We optimize to avoid numerous calls to hotkey_get_wlsw.
diff --git a/drivers/platform/x86/xo15-ebook.c b/drivers/platform/x86/xo15-ebook.c
new file mode 100644
index 000000000000..c1372ed9d2e9
--- /dev/null
+++ b/drivers/platform/x86/xo15-ebook.c
@@ -0,0 +1,180 @@
1/*
2 * OLPC XO-1.5 ebook switch driver
3 * (based on generic ACPI button driver)
4 *
5 * Copyright (C) 2009 Paul Fox <pgf@laptop.org>
6 * Copyright (C) 2010 One Laptop per Child
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or (at
11 * your option) any later version.
12 */
13
14#include <linux/kernel.h>
15#include <linux/module.h>
16#include <linux/init.h>
17#include <linux/types.h>
18#include <linux/input.h>
19#include <acpi/acpi_bus.h>
20#include <acpi/acpi_drivers.h>
21
22#define MODULE_NAME "xo15-ebook"
23#define PREFIX MODULE_NAME ": "
24
25#define XO15_EBOOK_CLASS MODULE_NAME
26#define XO15_EBOOK_TYPE_UNKNOWN 0x00
27#define XO15_EBOOK_NOTIFY_STATUS 0x80
28
29#define XO15_EBOOK_SUBCLASS "ebook"
30#define XO15_EBOOK_HID "XO15EBK"
31#define XO15_EBOOK_DEVICE_NAME "EBook Switch"
32
33ACPI_MODULE_NAME(MODULE_NAME);
34
35MODULE_DESCRIPTION("OLPC XO-1.5 ebook switch driver");
36MODULE_LICENSE("GPL");
37
38static const struct acpi_device_id ebook_device_ids[] = {
39 { XO15_EBOOK_HID, 0 },
40 { "", 0 },
41};
42MODULE_DEVICE_TABLE(acpi, ebook_device_ids);
43
44struct ebook_switch {
45 struct input_dev *input;
46 char phys[32]; /* for input device */
47};
48
49static int ebook_send_state(struct acpi_device *device)
50{
51 struct ebook_switch *button = acpi_driver_data(device);
52 unsigned long long state;
53 acpi_status status;
54
55 status = acpi_evaluate_integer(device->handle, "EBK", NULL, &state);
56 if (ACPI_FAILURE(status))
57 return -EIO;
58
59 /* input layer checks if event is redundant */
60 input_report_switch(button->input, SW_TABLET_MODE, !state);
61 input_sync(button->input);
62 return 0;
63}
64
65static void ebook_switch_notify(struct acpi_device *device, u32 event)
66{
67 switch (event) {
68 case ACPI_FIXED_HARDWARE_EVENT:
69 case XO15_EBOOK_NOTIFY_STATUS:
70 ebook_send_state(device);
71 break;
72 default:
73 ACPI_DEBUG_PRINT((ACPI_DB_INFO,
74 "Unsupported event [0x%x]\n", event));
75 break;
76 }
77}
78
79static int ebook_switch_resume(struct acpi_device *device)
80{
81 return ebook_send_state(device);
82}
83
84static int ebook_switch_add(struct acpi_device *device)
85{
86 struct ebook_switch *button;
87 struct input_dev *input;
88 const char *hid = acpi_device_hid(device);
89 char *name, *class;
90 int error;
91
92 button = kzalloc(sizeof(struct ebook_switch), GFP_KERNEL);
93 if (!button)
94 return -ENOMEM;
95
96 device->driver_data = button;
97
98 button->input = input = input_allocate_device();
99 if (!input) {
100 error = -ENOMEM;
101 goto err_free_button;
102 }
103
104 name = acpi_device_name(device);
105 class = acpi_device_class(device);
106
107 if (strcmp(hid, XO15_EBOOK_HID)) {
108 printk(KERN_ERR PREFIX "Unsupported hid [%s]\n", hid);
109 error = -ENODEV;
110 goto err_free_input;
111 }
112
113 strcpy(name, XO15_EBOOK_DEVICE_NAME);
114 sprintf(class, "%s/%s", XO15_EBOOK_CLASS, XO15_EBOOK_SUBCLASS);
115
116 snprintf(button->phys, sizeof(button->phys), "%s/button/input0", hid);
117
118 input->name = name;
119 input->phys = button->phys;
120 input->id.bustype = BUS_HOST;
121 input->dev.parent = &device->dev;
122
123 input->evbit[0] = BIT_MASK(EV_SW);
124 set_bit(SW_TABLET_MODE, input->swbit);
125
126 error = input_register_device(input);
127 if (error)
128 goto err_free_input;
129
130 ebook_send_state(device);
131
132 if (device->wakeup.flags.valid) {
133 /* Button's GPE is run-wake GPE */
134 acpi_enable_gpe(device->wakeup.gpe_device,
135 device->wakeup.gpe_number);
136 device_set_wakeup_enable(&device->dev, true);
137 }
138
139 return 0;
140
141 err_free_input:
142 input_free_device(input);
143 err_free_button:
144 kfree(button);
145 return error;
146}
147
148static int ebook_switch_remove(struct acpi_device *device, int type)
149{
150 struct ebook_switch *button = acpi_driver_data(device);
151
152 input_unregister_device(button->input);
153 kfree(button);
154 return 0;
155}
156
157static struct acpi_driver xo15_ebook_driver = {
158 .name = MODULE_NAME,
159 .class = XO15_EBOOK_CLASS,
160 .ids = ebook_device_ids,
161 .ops = {
162 .add = ebook_switch_add,
163 .resume = ebook_switch_resume,
164 .remove = ebook_switch_remove,
165 .notify = ebook_switch_notify,
166 },
167};
168
169static int __init xo15_ebook_init(void)
170{
171 return acpi_bus_register_driver(&xo15_ebook_driver);
172}
173
174static void __exit xo15_ebook_exit(void)
175{
176 acpi_bus_unregister_driver(&xo15_ebook_driver);
177}
178
179module_init(xo15_ebook_init);
180module_exit(xo15_ebook_exit);