aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/ABI/testing/sysfs-platform-ideapad-laptop6
-rw-r--r--MAINTAINERS8
-rw-r--r--drivers/platform/x86/Kconfig27
-rw-r--r--drivers/platform/x86/Makefile1
-rw-r--r--drivers/platform/x86/acer-wmi.c429
-rw-r--r--drivers/platform/x86/classmate-laptop.c19
-rw-r--r--drivers/platform/x86/compal-laptop.c8
-rw-r--r--drivers/platform/x86/eeepc-laptop.c11
-rw-r--r--drivers/platform/x86/eeepc-wmi.c609
-rw-r--r--drivers/platform/x86/fujitsu-laptop.c2
-rw-r--r--drivers/platform/x86/ideapad-laptop.c259
-rw-r--r--drivers/platform/x86/intel_ips.c2
-rw-r--r--drivers/platform/x86/intel_pmic_gpio.c6
-rw-r--r--drivers/platform/x86/intel_scu_ipc.c4
-rw-r--r--drivers/platform/x86/intel_scu_ipcutil.c133
-rw-r--r--drivers/platform/x86/sony-laptop.c12
-rw-r--r--drivers/platform/x86/thinkpad_acpi.c3
-rw-r--r--drivers/platform/x86/wmi.c133
-rw-r--r--include/linux/sonypi.h1
19 files changed, 1431 insertions, 242 deletions
diff --git a/Documentation/ABI/testing/sysfs-platform-ideapad-laptop b/Documentation/ABI/testing/sysfs-platform-ideapad-laptop
new file mode 100644
index 000000000000..807fca2ae2a4
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-platform-ideapad-laptop
@@ -0,0 +1,6 @@
1What: /sys/devices/platform/ideapad/camera_power
2Date: Dec 2010
3KernelVersion: 2.6.37
4Contact: "Ike Panhc <ike.pan@canonical.com>"
5Description:
6 Control the power of camera module. 1 means on, 0 means off.
diff --git a/MAINTAINERS b/MAINTAINERS
index 9e4d4ca690e2..5181828012ce 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2271,6 +2271,14 @@ W: http://acpi4asus.sf.net
2271S: Maintained 2271S: Maintained
2272F: drivers/platform/x86/eeepc-laptop.c 2272F: drivers/platform/x86/eeepc-laptop.c
2273 2273
2274EEEPC WMI EXTRAS DRIVER
2275M: Corentin Chary <corentincj@iksaif.net>
2276L: acpi4asus-user@lists.sourceforge.net
2277L: platform-driver-x86@vger.kernel.org
2278W: http://acpi4asus.sf.net
2279S: Maintained
2280F: drivers/platform/x86/eeepc-wmi.c
2281
2274EFIFB FRAMEBUFFER DRIVER 2282EFIFB FRAMEBUFFER DRIVER
2275L: linux-fbdev@vger.kernel.org 2283L: linux-fbdev@vger.kernel.org
2276M: Peter Jones <pjones@redhat.com> 2284M: Peter Jones <pjones@redhat.com>
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index faec777b1ed4..d163bc2e2b9e 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -18,12 +18,14 @@ if X86_PLATFORM_DEVICES
18config ACER_WMI 18config ACER_WMI
19 tristate "Acer WMI Laptop Extras" 19 tristate "Acer WMI Laptop Extras"
20 depends on ACPI 20 depends on ACPI
21 depends on LEDS_CLASS 21 select LEDS_CLASS
22 depends on NEW_LEDS 22 select NEW_LEDS
23 depends on BACKLIGHT_CLASS_DEVICE 23 depends on BACKLIGHT_CLASS_DEVICE
24 depends on SERIO_I8042 24 depends on SERIO_I8042
25 depends on INPUT
25 depends on RFKILL || RFKILL = n 26 depends on RFKILL || RFKILL = n
26 select ACPI_WMI 27 depends on ACPI_WMI
28 select INPUT_SPARSEKMAP
27 ---help--- 29 ---help---
28 This is a driver for newer Acer (and Wistron) laptops. It adds 30 This is a driver for newer Acer (and Wistron) laptops. It adds
29 wireless radio and bluetooth control, and on some laptops, 31 wireless radio and bluetooth control, and on some laptops,
@@ -131,7 +133,7 @@ config TC1100_WMI
131 depends on !X86_64 133 depends on !X86_64
132 depends on EXPERIMENTAL 134 depends on EXPERIMENTAL
133 depends on ACPI 135 depends on ACPI
134 select ACPI_WMI 136 depends on ACPI_WMI
135 ---help--- 137 ---help---
136 This is a driver for the WMI extensions (wireless and bluetooth power 138 This is a driver for the WMI extensions (wireless and bluetooth power
137 control) of the HP Compaq TC1100 tablet. 139 control) of the HP Compaq TC1100 tablet.
@@ -226,6 +228,7 @@ config IDEAPAD_LAPTOP
226 tristate "Lenovo IdeaPad Laptop Extras" 228 tristate "Lenovo IdeaPad Laptop Extras"
227 depends on ACPI 229 depends on ACPI
228 depends on RFKILL 230 depends on RFKILL
231 select INPUT_SPARSEKMAP
229 help 232 help
230 This is a driver for the rfkill switches on Lenovo IdeaPad netbooks. 233 This is a driver for the rfkill switches on Lenovo IdeaPad netbooks.
231 234
@@ -425,7 +428,10 @@ config EEEPC_WMI
425 depends on INPUT 428 depends on INPUT
426 depends on EXPERIMENTAL 429 depends on EXPERIMENTAL
427 depends on BACKLIGHT_CLASS_DEVICE 430 depends on BACKLIGHT_CLASS_DEVICE
431 depends on RFKILL || RFKILL = n
428 select INPUT_SPARSEKMAP 432 select INPUT_SPARSEKMAP
433 select LEDS_CLASS
434 select NEW_LEDS
429 ---help--- 435 ---help---
430 Say Y here if you want to support WMI-based hotkeys on Eee PC laptops. 436 Say Y here if you want to support WMI-based hotkeys on Eee PC laptops.
431 437
@@ -510,8 +516,8 @@ config TOPSTAR_LAPTOP
510config ACPI_TOSHIBA 516config ACPI_TOSHIBA
511 tristate "Toshiba Laptop Extras" 517 tristate "Toshiba Laptop Extras"
512 depends on ACPI 518 depends on ACPI
513 depends on LEDS_CLASS 519 select LEDS_CLASS
514 depends on NEW_LEDS 520 select NEW_LEDS
515 depends on BACKLIGHT_CLASS_DEVICE 521 depends on BACKLIGHT_CLASS_DEVICE
516 depends on INPUT 522 depends on INPUT
517 depends on RFKILL || RFKILL = n 523 depends on RFKILL || RFKILL = n
@@ -576,6 +582,15 @@ config INTEL_SCU_IPC
576 some embedded Intel x86 platforms. This is not needed for PC-type 582 some embedded Intel x86 platforms. This is not needed for PC-type
577 machines. 583 machines.
578 584
585config INTEL_SCU_IPC_UTIL
586 tristate "Intel SCU IPC utility driver"
587 depends on INTEL_SCU_IPC
588 default y
589 ---help---
590 The IPC Util driver provides an interface with the SCU enabling
591 low level access for debug work and updating the firmware. Say
592 N unless you will be doing this on an Intel MID platform.
593
579config GPIO_INTEL_PMIC 594config GPIO_INTEL_PMIC
580 bool "Intel PMIC GPIO support" 595 bool "Intel PMIC GPIO support"
581 depends on INTEL_SCU_IPC && GPIOLIB 596 depends on INTEL_SCU_IPC && GPIOLIB
diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile
index 9950ccc940b5..4ec4ff8f9182 100644
--- a/drivers/platform/x86/Makefile
+++ b/drivers/platform/x86/Makefile
@@ -28,6 +28,7 @@ obj-$(CONFIG_TOPSTAR_LAPTOP) += topstar-laptop.o
28obj-$(CONFIG_ACPI_TOSHIBA) += toshiba_acpi.o 28obj-$(CONFIG_ACPI_TOSHIBA) += toshiba_acpi.o
29obj-$(CONFIG_TOSHIBA_BT_RFKILL) += toshiba_bluetooth.o 29obj-$(CONFIG_TOSHIBA_BT_RFKILL) += toshiba_bluetooth.o
30obj-$(CONFIG_INTEL_SCU_IPC) += intel_scu_ipc.o 30obj-$(CONFIG_INTEL_SCU_IPC) += intel_scu_ipc.o
31obj-$(CONFIG_INTEL_SCU_IPC_UTIL)+= intel_scu_ipcutil.o
31obj-$(CONFIG_RAR_REGISTER) += intel_rar_register.o 32obj-$(CONFIG_RAR_REGISTER) += intel_rar_register.o
32obj-$(CONFIG_INTEL_IPS) += intel_ips.o 33obj-$(CONFIG_INTEL_IPS) += intel_ips.o
33obj-$(CONFIG_GPIO_INTEL_PMIC) += intel_pmic_gpio.o 34obj-$(CONFIG_GPIO_INTEL_PMIC) += intel_pmic_gpio.o
diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c
index c8c65375bfe2..ee40d681edd0 100644
--- a/drivers/platform/x86/acer-wmi.c
+++ b/drivers/platform/x86/acer-wmi.c
@@ -37,6 +37,9 @@
37#include <linux/workqueue.h> 37#include <linux/workqueue.h>
38#include <linux/debugfs.h> 38#include <linux/debugfs.h>
39#include <linux/slab.h> 39#include <linux/slab.h>
40#include <linux/input.h>
41#include <linux/input/sparse-keymap.h>
42#include <linux/dmi.h>
40 43
41#include <acpi/acpi_drivers.h> 44#include <acpi/acpi_drivers.h>
42 45
@@ -48,6 +51,7 @@ MODULE_LICENSE("GPL");
48#define ACER_ERR KERN_ERR ACER_LOGPREFIX 51#define ACER_ERR KERN_ERR ACER_LOGPREFIX
49#define ACER_NOTICE KERN_NOTICE ACER_LOGPREFIX 52#define ACER_NOTICE KERN_NOTICE ACER_LOGPREFIX
50#define ACER_INFO KERN_INFO ACER_LOGPREFIX 53#define ACER_INFO KERN_INFO ACER_LOGPREFIX
54#define ACER_WARNING KERN_WARNING ACER_LOGPREFIX
51 55
52/* 56/*
53 * Magic Number 57 * Magic Number
@@ -82,9 +86,82 @@ MODULE_LICENSE("GPL");
82#define AMW0_GUID2 "431F16ED-0C2B-444C-B267-27DEB140CF9C" 86#define AMW0_GUID2 "431F16ED-0C2B-444C-B267-27DEB140CF9C"
83#define WMID_GUID1 "6AF4F258-B401-42fd-BE91-3D4AC2D7C0D3" 87#define WMID_GUID1 "6AF4F258-B401-42fd-BE91-3D4AC2D7C0D3"
84#define WMID_GUID2 "95764E09-FB56-4e83-B31A-37761F60994A" 88#define WMID_GUID2 "95764E09-FB56-4e83-B31A-37761F60994A"
89#define WMID_GUID3 "61EF69EA-865C-4BC3-A502-A0DEBA0CB531"
90
91/*
92 * Acer ACPI event GUIDs
93 */
94#define ACERWMID_EVENT_GUID "676AA15E-6A47-4D9F-A2CC-1E6D18D14026"
85 95
86MODULE_ALIAS("wmi:67C3371D-95A3-4C37-BB61-DD47B491DAAB"); 96MODULE_ALIAS("wmi:67C3371D-95A3-4C37-BB61-DD47B491DAAB");
87MODULE_ALIAS("wmi:6AF4F258-B401-42fd-BE91-3D4AC2D7C0D3"); 97MODULE_ALIAS("wmi:6AF4F258-B401-42fd-BE91-3D4AC2D7C0D3");
98MODULE_ALIAS("wmi:676AA15E-6A47-4D9F-A2CC-1E6D18D14026");
99
100enum acer_wmi_event_ids {
101 WMID_HOTKEY_EVENT = 0x1,
102};
103
104static const struct key_entry acer_wmi_keymap[] = {
105 {KE_KEY, 0x01, {KEY_WLAN} }, /* WiFi */
106 {KE_KEY, 0x12, {KEY_BLUETOOTH} }, /* BT */
107 {KE_KEY, 0x21, {KEY_PROG1} }, /* Backup */
108 {KE_KEY, 0x22, {KEY_PROG2} }, /* Arcade */
109 {KE_KEY, 0x23, {KEY_PROG3} }, /* P_Key */
110 {KE_KEY, 0x24, {KEY_PROG4} }, /* Social networking_Key */
111 {KE_KEY, 0x64, {KEY_SWITCHVIDEOMODE} }, /* Display Switch */
112 {KE_KEY, 0x82, {KEY_F22} }, /* Touch Pad On/Off */
113 {KE_END, 0}
114};
115
116static struct input_dev *acer_wmi_input_dev;
117
118struct event_return_value {
119 u8 function;
120 u8 key_num;
121 u16 device_state;
122 u32 reserved;
123} __attribute__((packed));
124
125/*
126 * GUID3 Get Device Status device flags
127 */
128#define ACER_WMID3_GDS_WIRELESS (1<<0) /* WiFi */
129#define ACER_WMID3_GDS_THREEG (1<<6) /* 3G */
130#define ACER_WMID3_GDS_BLUETOOTH (1<<11) /* BT */
131
132struct lm_input_params {
133 u8 function_num; /* Function Number */
134 u16 commun_devices; /* Communication type devices default status */
135 u16 devices; /* Other type devices default status */
136 u8 lm_status; /* Launch Manager Status */
137 u16 reserved;
138} __attribute__((packed));
139
140struct lm_return_value {
141 u8 error_code; /* Error Code */
142 u8 ec_return_value; /* EC Return Value */
143 u16 reserved;
144} __attribute__((packed));
145
146struct wmid3_gds_input_param { /* Get Device Status input parameter */
147 u8 function_num; /* Function Number */
148 u8 hotkey_number; /* Hotkey Number */
149 u16 devices; /* Get Device */
150} __attribute__((packed));
151
152struct wmid3_gds_return_value { /* Get Device Status return value*/
153 u8 error_code; /* Error Code */
154 u8 ec_return_value; /* EC Return Value */
155 u16 devices; /* Current Device Status */
156 u32 reserved;
157} __attribute__((packed));
158
159struct hotkey_function_type_aa {
160 u8 type;
161 u8 length;
162 u16 handle;
163 u16 commun_func_bitmap;
164} __attribute__((packed));
88 165
89/* 166/*
90 * Interface capability flags 167 * Interface capability flags
@@ -116,15 +193,19 @@ static int mailled = -1;
116static int brightness = -1; 193static int brightness = -1;
117static int threeg = -1; 194static int threeg = -1;
118static int force_series; 195static int force_series;
196static bool ec_raw_mode;
197static bool has_type_aa;
119 198
120module_param(mailled, int, 0444); 199module_param(mailled, int, 0444);
121module_param(brightness, int, 0444); 200module_param(brightness, int, 0444);
122module_param(threeg, int, 0444); 201module_param(threeg, int, 0444);
123module_param(force_series, int, 0444); 202module_param(force_series, int, 0444);
203module_param(ec_raw_mode, bool, 0444);
124MODULE_PARM_DESC(mailled, "Set initial state of Mail LED"); 204MODULE_PARM_DESC(mailled, "Set initial state of Mail LED");
125MODULE_PARM_DESC(brightness, "Set initial LCD backlight brightness"); 205MODULE_PARM_DESC(brightness, "Set initial LCD backlight brightness");
126MODULE_PARM_DESC(threeg, "Set initial state of 3G hardware"); 206MODULE_PARM_DESC(threeg, "Set initial state of 3G hardware");
127MODULE_PARM_DESC(force_series, "Force a different laptop series"); 207MODULE_PARM_DESC(force_series, "Force a different laptop series");
208MODULE_PARM_DESC(ec_raw_mode, "Enable EC raw mode");
128 209
129struct acer_data { 210struct acer_data {
130 int mailled; 211 int mailled;
@@ -140,6 +221,7 @@ struct acer_debug {
140 221
141static struct rfkill *wireless_rfkill; 222static struct rfkill *wireless_rfkill;
142static struct rfkill *bluetooth_rfkill; 223static struct rfkill *bluetooth_rfkill;
224static struct rfkill *threeg_rfkill;
143 225
144/* Each low-level interface must define at least some of the following */ 226/* Each low-level interface must define at least some of the following */
145struct wmi_interface { 227struct wmi_interface {
@@ -753,6 +835,28 @@ static acpi_status WMID_set_u32(u32 value, u32 cap, struct wmi_interface *iface)
753 return WMI_execute_u32(method_id, (u32)value, NULL); 835 return WMI_execute_u32(method_id, (u32)value, NULL);
754} 836}
755 837
838static void type_aa_dmi_decode(const struct dmi_header *header, void *dummy)
839{
840 struct hotkey_function_type_aa *type_aa;
841
842 /* We are looking for OEM-specific Type AAh */
843 if (header->type != 0xAA)
844 return;
845
846 has_type_aa = true;
847 type_aa = (struct hotkey_function_type_aa *) header;
848
849 printk(ACER_INFO "Function bitmap for Communication Button: 0x%x\n",
850 type_aa->commun_func_bitmap);
851
852 if (type_aa->commun_func_bitmap & ACER_WMID3_GDS_WIRELESS)
853 interface->capability |= ACER_CAP_WIRELESS;
854 if (type_aa->commun_func_bitmap & ACER_WMID3_GDS_THREEG)
855 interface->capability |= ACER_CAP_THREEG;
856 if (type_aa->commun_func_bitmap & ACER_WMID3_GDS_BLUETOOTH)
857 interface->capability |= ACER_CAP_BLUETOOTH;
858}
859
756static acpi_status WMID_set_capabilities(void) 860static acpi_status WMID_set_capabilities(void)
757{ 861{
758 struct acpi_buffer out = {ACPI_ALLOCATE_BUFFER, NULL}; 862 struct acpi_buffer out = {ACPI_ALLOCATE_BUFFER, NULL};
@@ -773,16 +877,17 @@ static acpi_status WMID_set_capabilities(void)
773 return AE_ERROR; 877 return AE_ERROR;
774 } 878 }
775 879
776 /* Not sure on the meaning of the relevant bits yet to detect these */ 880 dmi_walk(type_aa_dmi_decode, NULL);
777 interface->capability |= ACER_CAP_WIRELESS; 881 if (!has_type_aa) {
778 interface->capability |= ACER_CAP_THREEG; 882 interface->capability |= ACER_CAP_WIRELESS;
883 interface->capability |= ACER_CAP_THREEG;
884 if (devices & 0x10)
885 interface->capability |= ACER_CAP_BLUETOOTH;
886 }
779 887
780 /* WMID always provides brightness methods */ 888 /* WMID always provides brightness methods */
781 interface->capability |= ACER_CAP_BRIGHTNESS; 889 interface->capability |= ACER_CAP_BRIGHTNESS;
782 890
783 if (devices & 0x10)
784 interface->capability |= ACER_CAP_BLUETOOTH;
785
786 if (!(devices & 0x20)) 891 if (!(devices & 0x20))
787 max_brightness = 0x9; 892 max_brightness = 0x9;
788 893
@@ -861,7 +966,8 @@ static void __init acer_commandline_init(void)
861 * capability isn't available on the given interface 966 * capability isn't available on the given interface
862 */ 967 */
863 set_u32(mailled, ACER_CAP_MAILLED); 968 set_u32(mailled, ACER_CAP_MAILLED);
864 set_u32(threeg, ACER_CAP_THREEG); 969 if (!has_type_aa)
970 set_u32(threeg, ACER_CAP_THREEG);
865 set_u32(brightness, ACER_CAP_BRIGHTNESS); 971 set_u32(brightness, ACER_CAP_BRIGHTNESS);
866} 972}
867 973
@@ -948,6 +1054,79 @@ static void acer_backlight_exit(void)
948 backlight_device_unregister(acer_backlight_device); 1054 backlight_device_unregister(acer_backlight_device);
949} 1055}
950 1056
1057static acpi_status wmid3_get_device_status(u32 *value, u16 device)
1058{
1059 struct wmid3_gds_return_value return_value;
1060 acpi_status status;
1061 union acpi_object *obj;
1062 struct wmid3_gds_input_param params = {
1063 .function_num = 0x1,
1064 .hotkey_number = 0x01,
1065 .devices = device,
1066 };
1067 struct acpi_buffer input = {
1068 sizeof(struct wmid3_gds_input_param),
1069 &params
1070 };
1071 struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
1072
1073 status = wmi_evaluate_method(WMID_GUID3, 0, 0x2, &input, &output);
1074 if (ACPI_FAILURE(status))
1075 return status;
1076
1077 obj = output.pointer;
1078
1079 if (!obj)
1080 return AE_ERROR;
1081 else if (obj->type != ACPI_TYPE_BUFFER) {
1082 kfree(obj);
1083 return AE_ERROR;
1084 }
1085 if (obj->buffer.length != 8) {
1086 printk(ACER_WARNING "Unknown buffer length %d\n",
1087 obj->buffer.length);
1088 kfree(obj);
1089 return AE_ERROR;
1090 }
1091
1092 return_value = *((struct wmid3_gds_return_value *)obj->buffer.pointer);
1093 kfree(obj);
1094
1095 if (return_value.error_code || return_value.ec_return_value)
1096 printk(ACER_WARNING "Get Device Status failed: "
1097 "0x%x - 0x%x\n", return_value.error_code,
1098 return_value.ec_return_value);
1099 else
1100 *value = !!(return_value.devices & device);
1101
1102 return status;
1103}
1104
1105static acpi_status get_device_status(u32 *value, u32 cap)
1106{
1107 if (wmi_has_guid(WMID_GUID3)) {
1108 u16 device;
1109
1110 switch (cap) {
1111 case ACER_CAP_WIRELESS:
1112 device = ACER_WMID3_GDS_WIRELESS;
1113 break;
1114 case ACER_CAP_BLUETOOTH:
1115 device = ACER_WMID3_GDS_BLUETOOTH;
1116 break;
1117 case ACER_CAP_THREEG:
1118 device = ACER_WMID3_GDS_THREEG;
1119 break;
1120 default:
1121 return AE_ERROR;
1122 }
1123 return wmid3_get_device_status(value, device);
1124
1125 } else {
1126 return get_u32(value, cap);
1127 }
1128}
1129
951/* 1130/*
952 * Rfkill devices 1131 * Rfkill devices
953 */ 1132 */
@@ -968,6 +1147,13 @@ static void acer_rfkill_update(struct work_struct *ignored)
968 rfkill_set_sw_state(bluetooth_rfkill, !state); 1147 rfkill_set_sw_state(bluetooth_rfkill, !state);
969 } 1148 }
970 1149
1150 if (has_cap(ACER_CAP_THREEG) && wmi_has_guid(WMID_GUID3)) {
1151 status = wmid3_get_device_status(&state,
1152 ACER_WMID3_GDS_THREEG);
1153 if (ACPI_SUCCESS(status))
1154 rfkill_set_sw_state(threeg_rfkill, !state);
1155 }
1156
971 schedule_delayed_work(&acer_rfkill_work, round_jiffies_relative(HZ)); 1157 schedule_delayed_work(&acer_rfkill_work, round_jiffies_relative(HZ));
972} 1158}
973 1159
@@ -991,6 +1177,8 @@ static struct rfkill *acer_rfkill_register(struct device *dev,
991{ 1177{
992 int err; 1178 int err;
993 struct rfkill *rfkill_dev; 1179 struct rfkill *rfkill_dev;
1180 u32 state;
1181 acpi_status status;
994 1182
995 rfkill_dev = rfkill_alloc(name, dev, type, 1183 rfkill_dev = rfkill_alloc(name, dev, type,
996 &acer_rfkill_ops, 1184 &acer_rfkill_ops,
@@ -998,6 +1186,10 @@ static struct rfkill *acer_rfkill_register(struct device *dev,
998 if (!rfkill_dev) 1186 if (!rfkill_dev)
999 return ERR_PTR(-ENOMEM); 1187 return ERR_PTR(-ENOMEM);
1000 1188
1189 status = get_device_status(&state, cap);
1190 if (ACPI_SUCCESS(status))
1191 rfkill_init_sw_state(rfkill_dev, !state);
1192
1001 err = rfkill_register(rfkill_dev); 1193 err = rfkill_register(rfkill_dev);
1002 if (err) { 1194 if (err) {
1003 rfkill_destroy(rfkill_dev); 1195 rfkill_destroy(rfkill_dev);
@@ -1024,6 +1216,19 @@ static int acer_rfkill_init(struct device *dev)
1024 } 1216 }
1025 } 1217 }
1026 1218
1219 if (has_cap(ACER_CAP_THREEG)) {
1220 threeg_rfkill = acer_rfkill_register(dev,
1221 RFKILL_TYPE_WWAN, "acer-threeg",
1222 ACER_CAP_THREEG);
1223 if (IS_ERR(threeg_rfkill)) {
1224 rfkill_unregister(wireless_rfkill);
1225 rfkill_destroy(wireless_rfkill);
1226 rfkill_unregister(bluetooth_rfkill);
1227 rfkill_destroy(bluetooth_rfkill);
1228 return PTR_ERR(threeg_rfkill);
1229 }
1230 }
1231
1027 schedule_delayed_work(&acer_rfkill_work, round_jiffies_relative(HZ)); 1232 schedule_delayed_work(&acer_rfkill_work, round_jiffies_relative(HZ));
1028 1233
1029 return 0; 1234 return 0;
@@ -1040,6 +1245,11 @@ static void acer_rfkill_exit(void)
1040 rfkill_unregister(bluetooth_rfkill); 1245 rfkill_unregister(bluetooth_rfkill);
1041 rfkill_destroy(bluetooth_rfkill); 1246 rfkill_destroy(bluetooth_rfkill);
1042 } 1247 }
1248
1249 if (has_cap(ACER_CAP_THREEG)) {
1250 rfkill_unregister(threeg_rfkill);
1251 rfkill_destroy(threeg_rfkill);
1252 }
1043 return; 1253 return;
1044} 1254}
1045 1255
@@ -1050,7 +1260,12 @@ static ssize_t show_bool_threeg(struct device *dev,
1050 struct device_attribute *attr, char *buf) 1260 struct device_attribute *attr, char *buf)
1051{ 1261{
1052 u32 result; \ 1262 u32 result; \
1053 acpi_status status = get_u32(&result, ACER_CAP_THREEG); 1263 acpi_status status;
1264 if (wmi_has_guid(WMID_GUID3))
1265 status = wmid3_get_device_status(&result,
1266 ACER_WMID3_GDS_THREEG);
1267 else
1268 status = get_u32(&result, ACER_CAP_THREEG);
1054 if (ACPI_SUCCESS(status)) 1269 if (ACPI_SUCCESS(status))
1055 return sprintf(buf, "%u\n", result); 1270 return sprintf(buf, "%u\n", result);
1056 return sprintf(buf, "Read error\n"); 1271 return sprintf(buf, "Read error\n");
@@ -1085,6 +1300,178 @@ static ssize_t show_interface(struct device *dev, struct device_attribute *attr,
1085 1300
1086static DEVICE_ATTR(interface, S_IRUGO, show_interface, NULL); 1301static DEVICE_ATTR(interface, S_IRUGO, show_interface, NULL);
1087 1302
1303static void acer_wmi_notify(u32 value, void *context)
1304{
1305 struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL };
1306 union acpi_object *obj;
1307 struct event_return_value return_value;
1308 acpi_status status;
1309
1310 status = wmi_get_event_data(value, &response);
1311 if (status != AE_OK) {
1312 printk(ACER_WARNING "bad event status 0x%x\n", status);
1313 return;
1314 }
1315
1316 obj = (union acpi_object *)response.pointer;
1317
1318 if (!obj)
1319 return;
1320 if (obj->type != ACPI_TYPE_BUFFER) {
1321 printk(ACER_WARNING "Unknown response received %d\n",
1322 obj->type);
1323 kfree(obj);
1324 return;
1325 }
1326 if (obj->buffer.length != 8) {
1327 printk(ACER_WARNING "Unknown buffer length %d\n",
1328 obj->buffer.length);
1329 kfree(obj);
1330 return;
1331 }
1332
1333 return_value = *((struct event_return_value *)obj->buffer.pointer);
1334 kfree(obj);
1335
1336 switch (return_value.function) {
1337 case WMID_HOTKEY_EVENT:
1338 if (!sparse_keymap_report_event(acer_wmi_input_dev,
1339 return_value.key_num, 1, true))
1340 printk(ACER_WARNING "Unknown key number - 0x%x\n",
1341 return_value.key_num);
1342 break;
1343 default:
1344 printk(ACER_WARNING "Unknown function number - %d - %d\n",
1345 return_value.function, return_value.key_num);
1346 break;
1347 }
1348}
1349
1350static acpi_status
1351wmid3_set_lm_mode(struct lm_input_params *params,
1352 struct lm_return_value *return_value)
1353{
1354 acpi_status status;
1355 union acpi_object *obj;
1356
1357 struct acpi_buffer input = { sizeof(struct lm_input_params), params };
1358 struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
1359
1360 status = wmi_evaluate_method(WMID_GUID3, 0, 0x1, &input, &output);
1361 if (ACPI_FAILURE(status))
1362 return status;
1363
1364 obj = output.pointer;
1365
1366 if (!obj)
1367 return AE_ERROR;
1368 else if (obj->type != ACPI_TYPE_BUFFER) {
1369 kfree(obj);
1370 return AE_ERROR;
1371 }
1372 if (obj->buffer.length != 4) {
1373 printk(ACER_WARNING "Unknown buffer length %d\n",
1374 obj->buffer.length);
1375 kfree(obj);
1376 return AE_ERROR;
1377 }
1378
1379 *return_value = *((struct lm_return_value *)obj->buffer.pointer);
1380 kfree(obj);
1381
1382 return status;
1383}
1384
1385static int acer_wmi_enable_ec_raw(void)
1386{
1387 struct lm_return_value return_value;
1388 acpi_status status;
1389 struct lm_input_params params = {
1390 .function_num = 0x1,
1391 .commun_devices = 0xFFFF,
1392 .devices = 0xFFFF,
1393 .lm_status = 0x00, /* Launch Manager Deactive */
1394 };
1395
1396 status = wmid3_set_lm_mode(&params, &return_value);
1397
1398 if (return_value.error_code || return_value.ec_return_value)
1399 printk(ACER_WARNING "Enabling EC raw mode failed: "
1400 "0x%x - 0x%x\n", return_value.error_code,
1401 return_value.ec_return_value);
1402 else
1403 printk(ACER_INFO "Enabled EC raw mode");
1404
1405 return status;
1406}
1407
1408static int acer_wmi_enable_lm(void)
1409{
1410 struct lm_return_value return_value;
1411 acpi_status status;
1412 struct lm_input_params params = {
1413 .function_num = 0x1,
1414 .commun_devices = 0xFFFF,
1415 .devices = 0xFFFF,
1416 .lm_status = 0x01, /* Launch Manager Active */
1417 };
1418
1419 status = wmid3_set_lm_mode(&params, &return_value);
1420
1421 if (return_value.error_code || return_value.ec_return_value)
1422 printk(ACER_WARNING "Enabling Launch Manager failed: "
1423 "0x%x - 0x%x\n", return_value.error_code,
1424 return_value.ec_return_value);
1425
1426 return status;
1427}
1428
1429static int __init acer_wmi_input_setup(void)
1430{
1431 acpi_status status;
1432 int err;
1433
1434 acer_wmi_input_dev = input_allocate_device();
1435 if (!acer_wmi_input_dev)
1436 return -ENOMEM;
1437
1438 acer_wmi_input_dev->name = "Acer WMI hotkeys";
1439 acer_wmi_input_dev->phys = "wmi/input0";
1440 acer_wmi_input_dev->id.bustype = BUS_HOST;
1441
1442 err = sparse_keymap_setup(acer_wmi_input_dev, acer_wmi_keymap, NULL);
1443 if (err)
1444 goto err_free_dev;
1445
1446 status = wmi_install_notify_handler(ACERWMID_EVENT_GUID,
1447 acer_wmi_notify, NULL);
1448 if (ACPI_FAILURE(status)) {
1449 err = -EIO;
1450 goto err_free_keymap;
1451 }
1452
1453 err = input_register_device(acer_wmi_input_dev);
1454 if (err)
1455 goto err_uninstall_notifier;
1456
1457 return 0;
1458
1459err_uninstall_notifier:
1460 wmi_remove_notify_handler(ACERWMID_EVENT_GUID);
1461err_free_keymap:
1462 sparse_keymap_free(acer_wmi_input_dev);
1463err_free_dev:
1464 input_free_device(acer_wmi_input_dev);
1465 return err;
1466}
1467
1468static void acer_wmi_input_destroy(void)
1469{
1470 wmi_remove_notify_handler(ACERWMID_EVENT_GUID);
1471 sparse_keymap_free(acer_wmi_input_dev);
1472 input_unregister_device(acer_wmi_input_dev);
1473}
1474
1088/* 1475/*
1089 * debugfs functions 1476 * debugfs functions
1090 */ 1477 */
@@ -1327,6 +1714,26 @@ static int __init acer_wmi_init(void)
1327 "generic video driver\n"); 1714 "generic video driver\n");
1328 } 1715 }
1329 1716
1717 if (wmi_has_guid(WMID_GUID3)) {
1718 if (ec_raw_mode) {
1719 if (ACPI_FAILURE(acer_wmi_enable_ec_raw())) {
1720 printk(ACER_ERR "Cannot enable EC raw mode\n");
1721 return -ENODEV;
1722 }
1723 } else if (ACPI_FAILURE(acer_wmi_enable_lm())) {
1724 printk(ACER_ERR "Cannot enable Launch Manager mode\n");
1725 return -ENODEV;
1726 }
1727 } else if (ec_raw_mode) {
1728 printk(ACER_INFO "No WMID EC raw mode enable method\n");
1729 }
1730
1731 if (wmi_has_guid(ACERWMID_EVENT_GUID)) {
1732 err = acer_wmi_input_setup();
1733 if (err)
1734 return err;
1735 }
1736
1330 err = platform_driver_register(&acer_platform_driver); 1737 err = platform_driver_register(&acer_platform_driver);
1331 if (err) { 1738 if (err) {
1332 printk(ACER_ERR "Unable to register platform driver.\n"); 1739 printk(ACER_ERR "Unable to register platform driver.\n");
@@ -1368,11 +1775,17 @@ error_device_add:
1368error_device_alloc: 1775error_device_alloc:
1369 platform_driver_unregister(&acer_platform_driver); 1776 platform_driver_unregister(&acer_platform_driver);
1370error_platform_register: 1777error_platform_register:
1778 if (wmi_has_guid(ACERWMID_EVENT_GUID))
1779 acer_wmi_input_destroy();
1780
1371 return err; 1781 return err;
1372} 1782}
1373 1783
1374static void __exit acer_wmi_exit(void) 1784static void __exit acer_wmi_exit(void)
1375{ 1785{
1786 if (wmi_has_guid(ACERWMID_EVENT_GUID))
1787 acer_wmi_input_destroy();
1788
1376 remove_sysfs(acer_platform_device); 1789 remove_sysfs(acer_platform_device);
1377 remove_debugfs(); 1790 remove_debugfs();
1378 platform_device_unregister(acer_platform_device); 1791 platform_device_unregister(acer_platform_device);
diff --git a/drivers/platform/x86/classmate-laptop.c b/drivers/platform/x86/classmate-laptop.c
index 341cbfef93ee..911135425224 100644
--- a/drivers/platform/x86/classmate-laptop.c
+++ b/drivers/platform/x86/classmate-laptop.c
@@ -522,18 +522,20 @@ static int cmpc_rfkill_block(void *data, bool blocked)
522 acpi_status status; 522 acpi_status status;
523 acpi_handle handle; 523 acpi_handle handle;
524 unsigned long long state; 524 unsigned long long state;
525 bool is_blocked;
525 526
526 handle = data; 527 handle = data;
527 status = cmpc_get_rfkill_wlan(handle, &state); 528 status = cmpc_get_rfkill_wlan(handle, &state);
528 if (ACPI_FAILURE(status)) 529 if (ACPI_FAILURE(status))
529 return -ENODEV; 530 return -ENODEV;
530 if (blocked) 531 /* Check if we really need to call cmpc_set_rfkill_wlan */
531 state &= ~1; 532 is_blocked = state & 1 ? false : true;
532 else 533 if (is_blocked != blocked) {
533 state |= 1; 534 state = blocked ? 0 : 1;
534 status = cmpc_set_rfkill_wlan(handle, state); 535 status = cmpc_set_rfkill_wlan(handle, state);
535 if (ACPI_FAILURE(status)) 536 if (ACPI_FAILURE(status))
536 return -ENODEV; 537 return -ENODEV;
538 }
537 return 0; 539 return 0;
538} 540}
539 541
@@ -653,8 +655,9 @@ static void cmpc_keys_handler(struct acpi_device *dev, u32 event)
653 655
654 if ((event & 0x0F) < ARRAY_SIZE(cmpc_keys_codes)) 656 if ((event & 0x0F) < ARRAY_SIZE(cmpc_keys_codes))
655 code = cmpc_keys_codes[event & 0x0F]; 657 code = cmpc_keys_codes[event & 0x0F];
656 inputdev = dev_get_drvdata(&dev->dev);; 658 inputdev = dev_get_drvdata(&dev->dev);
657 input_report_key(inputdev, code, !(event & 0x10)); 659 input_report_key(inputdev, code, !(event & 0x10));
660 input_sync(inputdev);
658} 661}
659 662
660static void cmpc_keys_idev_init(struct input_dev *inputdev) 663static void cmpc_keys_idev_init(struct input_dev *inputdev)
diff --git a/drivers/platform/x86/compal-laptop.c b/drivers/platform/x86/compal-laptop.c
index 097083cac413..034572b980c9 100644
--- a/drivers/platform/x86/compal-laptop.c
+++ b/drivers/platform/x86/compal-laptop.c
@@ -872,6 +872,14 @@ static struct dmi_system_id __initdata compal_dmi_table[] = {
872 }, 872 },
873 .callback = dmi_check_cb_extra 873 .callback = dmi_check_cb_extra
874 }, 874 },
875 {
876 .ident = "KHLB2",
877 .matches = {
878 DMI_MATCH(DMI_BOARD_NAME, "KHLB2"),
879 DMI_MATCH(DMI_BOARD_VERSION, "REFERENCE"),
880 },
881 .callback = dmi_check_cb_extra
882 },
875 { } 883 { }
876}; 884};
877 885
diff --git a/drivers/platform/x86/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c
index b2edfdcdcb84..e9fc530e7dc2 100644
--- a/drivers/platform/x86/eeepc-laptop.c
+++ b/drivers/platform/x86/eeepc-laptop.c
@@ -529,6 +529,15 @@ static void tpd_led_set(struct led_classdev *led_cdev,
529 queue_work(eeepc->led_workqueue, &eeepc->tpd_led_work); 529 queue_work(eeepc->led_workqueue, &eeepc->tpd_led_work);
530} 530}
531 531
532static enum led_brightness tpd_led_get(struct led_classdev *led_cdev)
533{
534 struct eeepc_laptop *eeepc;
535
536 eeepc = container_of(led_cdev, struct eeepc_laptop, tpd_led);
537
538 return get_acpi(eeepc, CM_ASL_TPD);
539}
540
532static int eeepc_led_init(struct eeepc_laptop *eeepc) 541static int eeepc_led_init(struct eeepc_laptop *eeepc)
533{ 542{
534 int rv; 543 int rv;
@@ -543,6 +552,8 @@ static int eeepc_led_init(struct eeepc_laptop *eeepc)
543 552
544 eeepc->tpd_led.name = "eeepc::touchpad"; 553 eeepc->tpd_led.name = "eeepc::touchpad";
545 eeepc->tpd_led.brightness_set = tpd_led_set; 554 eeepc->tpd_led.brightness_set = tpd_led_set;
555 if (get_acpi(eeepc, CM_ASL_TPD) >= 0) /* if method is available */
556 eeepc->tpd_led.brightness_get = tpd_led_get;
546 eeepc->tpd_led.max_brightness = 1; 557 eeepc->tpd_led.max_brightness = 1;
547 558
548 rv = led_classdev_register(&eeepc->platform_device->dev, 559 rv = led_classdev_register(&eeepc->platform_device->dev,
diff --git a/drivers/platform/x86/eeepc-wmi.c b/drivers/platform/x86/eeepc-wmi.c
index 0d50fbbe2478..4d38f98aa976 100644
--- a/drivers/platform/x86/eeepc-wmi.c
+++ b/drivers/platform/x86/eeepc-wmi.c
@@ -2,6 +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 * 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>
@@ -34,6 +35,10 @@
34#include <linux/input/sparse-keymap.h> 35#include <linux/input/sparse-keymap.h>
35#include <linux/fb.h> 36#include <linux/fb.h>
36#include <linux/backlight.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>
37#include <linux/platform_device.h> 42#include <linux/platform_device.h>
38#include <acpi/acpi_bus.h> 43#include <acpi/acpi_bus.h>
39#include <acpi/acpi_drivers.h> 44#include <acpi/acpi_drivers.h>
@@ -44,6 +49,8 @@ MODULE_AUTHOR("Yong Wang <yong.y.wang@intel.com>");
44MODULE_DESCRIPTION("Eee PC WMI Hotkey Driver"); 49MODULE_DESCRIPTION("Eee PC WMI Hotkey Driver");
45MODULE_LICENSE("GPL"); 50MODULE_LICENSE("GPL");
46 51
52#define EEEPC_ACPI_HID "ASUS010" /* old _HID used in eeepc-laptop */
53
47#define EEEPC_WMI_EVENT_GUID "ABBC0F72-8EA1-11D1-00A0-C90629100000" 54#define EEEPC_WMI_EVENT_GUID "ABBC0F72-8EA1-11D1-00A0-C90629100000"
48#define EEEPC_WMI_MGMT_GUID "97845ED0-4E6D-11DE-8A39-0800200C9A66" 55#define EEEPC_WMI_MGMT_GUID "97845ED0-4E6D-11DE-8A39-0800200C9A66"
49 56
@@ -60,6 +67,10 @@ MODULE_ALIAS("wmi:"EEEPC_WMI_MGMT_GUID);
60#define EEEPC_WMI_METHODID_CFVS 0x53564643 67#define EEEPC_WMI_METHODID_CFVS 0x53564643
61 68
62#define EEEPC_WMI_DEVID_BACKLIGHT 0x00050012 69#define EEEPC_WMI_DEVID_BACKLIGHT 0x00050012
70#define EEEPC_WMI_DEVID_TPDLED 0x00100011
71#define EEEPC_WMI_DEVID_WLAN 0x00010011
72#define EEEPC_WMI_DEVID_BLUETOOTH 0x00010013
73#define EEEPC_WMI_DEVID_WWAN3G 0x00010019
63 74
64static const struct key_entry eeepc_wmi_keymap[] = { 75static const struct key_entry eeepc_wmi_keymap[] = {
65 /* Sleep already handled via generic ACPI code */ 76 /* Sleep already handled via generic ACPI code */
@@ -83,11 +94,37 @@ struct bios_args {
83 u32 ctrl_param; 94 u32 ctrl_param;
84}; 95};
85 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
86struct eeepc_wmi { 110struct eeepc_wmi {
87 struct input_dev *inputdev; 111 struct input_dev *inputdev;
88 struct backlight_device *backlight_device; 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;
89}; 125};
90 126
127/* Only used in eeepc_wmi_init() and eeepc_wmi_exit() */
91static struct platform_device *platform_device; 128static struct platform_device *platform_device;
92 129
93static int eeepc_wmi_input_init(struct eeepc_wmi *eeepc) 130static int eeepc_wmi_input_init(struct eeepc_wmi *eeepc)
@@ -101,7 +138,7 @@ static int eeepc_wmi_input_init(struct eeepc_wmi *eeepc)
101 eeepc->inputdev->name = "Eee PC WMI hotkeys"; 138 eeepc->inputdev->name = "Eee PC WMI hotkeys";
102 eeepc->inputdev->phys = EEEPC_WMI_FILE "/input0"; 139 eeepc->inputdev->phys = EEEPC_WMI_FILE "/input0";
103 eeepc->inputdev->id.bustype = BUS_HOST; 140 eeepc->inputdev->id.bustype = BUS_HOST;
104 eeepc->inputdev->dev.parent = &platform_device->dev; 141 eeepc->inputdev->dev.parent = &eeepc->platform_device->dev;
105 142
106 err = sparse_keymap_setup(eeepc->inputdev, eeepc_wmi_keymap, NULL); 143 err = sparse_keymap_setup(eeepc->inputdev, eeepc_wmi_keymap, NULL);
107 if (err) 144 if (err)
@@ -130,7 +167,7 @@ static void eeepc_wmi_input_exit(struct eeepc_wmi *eeepc)
130 eeepc->inputdev = NULL; 167 eeepc->inputdev = NULL;
131} 168}
132 169
133static acpi_status eeepc_wmi_get_devstate(u32 dev_id, u32 *ctrl_param) 170static acpi_status eeepc_wmi_get_devstate(u32 dev_id, u32 *retval)
134{ 171{
135 struct acpi_buffer input = { (acpi_size)sizeof(u32), &dev_id }; 172 struct acpi_buffer input = { (acpi_size)sizeof(u32), &dev_id };
136 struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; 173 struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
@@ -150,8 +187,8 @@ static acpi_status eeepc_wmi_get_devstate(u32 dev_id, u32 *ctrl_param)
150 else 187 else
151 tmp = 0; 188 tmp = 0;
152 189
153 if (ctrl_param) 190 if (retval)
154 *ctrl_param = tmp; 191 *retval = tmp;
155 192
156 kfree(obj); 193 kfree(obj);
157 194
@@ -159,7 +196,8 @@ static acpi_status eeepc_wmi_get_devstate(u32 dev_id, u32 *ctrl_param)
159 196
160} 197}
161 198
162static acpi_status eeepc_wmi_set_devstate(u32 dev_id, u32 ctrl_param) 199static acpi_status eeepc_wmi_set_devstate(u32 dev_id, u32 ctrl_param,
200 u32 *retval)
163{ 201{
164 struct bios_args args = { 202 struct bios_args args = {
165 .dev_id = dev_id, 203 .dev_id = dev_id,
@@ -168,34 +206,281 @@ static acpi_status eeepc_wmi_set_devstate(u32 dev_id, u32 ctrl_param)
168 struct acpi_buffer input = { (acpi_size)sizeof(args), &args }; 206 struct acpi_buffer input = { (acpi_size)sizeof(args), &args };
169 acpi_status status; 207 acpi_status status;
170 208
171 status = wmi_evaluate_method(EEEPC_WMI_MGMT_GUID, 209 if (!retval) {
172 1, EEEPC_WMI_METHODID_DEVS, &input, NULL); 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 }
173 235
174 return status; 236 return status;
175} 237}
176 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 */
177static int read_brightness(struct backlight_device *bd) 461static int read_brightness(struct backlight_device *bd)
178{ 462{
179 static u32 ctrl_param; 463 u32 retval;
180 acpi_status status; 464 acpi_status status;
181 465
182 status = eeepc_wmi_get_devstate(EEEPC_WMI_DEVID_BACKLIGHT, &ctrl_param); 466 status = eeepc_wmi_get_devstate(EEEPC_WMI_DEVID_BACKLIGHT, &retval);
183 467
184 if (ACPI_FAILURE(status)) 468 if (ACPI_FAILURE(status))
185 return -1; 469 return -1;
186 else 470 else
187 return ctrl_param & 0xFF; 471 return retval & 0xFF;
188} 472}
189 473
190static int update_bl_status(struct backlight_device *bd) 474static int update_bl_status(struct backlight_device *bd)
191{ 475{
192 476
193 static u32 ctrl_param; 477 u32 ctrl_param;
194 acpi_status status; 478 acpi_status status;
195 479
196 ctrl_param = bd->props.brightness; 480 ctrl_param = bd->props.brightness;
197 481
198 status = eeepc_wmi_set_devstate(EEEPC_WMI_DEVID_BACKLIGHT, ctrl_param); 482 status = eeepc_wmi_set_devstate(EEEPC_WMI_DEVID_BACKLIGHT,
483 ctrl_param, NULL);
199 484
200 if (ACPI_FAILURE(status)) 485 if (ACPI_FAILURE(status))
201 return -1; 486 return -1;
@@ -234,7 +519,7 @@ static int eeepc_wmi_backlight_init(struct eeepc_wmi *eeepc)
234 memset(&props, 0, sizeof(struct backlight_properties)); 519 memset(&props, 0, sizeof(struct backlight_properties));
235 props.max_brightness = 15; 520 props.max_brightness = 15;
236 bd = backlight_device_register(EEEPC_WMI_FILE, 521 bd = backlight_device_register(EEEPC_WMI_FILE,
237 &platform_device->dev, eeepc, 522 &eeepc->platform_device->dev, eeepc,
238 &eeepc_wmi_bl_ops, &props); 523 &eeepc_wmi_bl_ops, &props);
239 if (IS_ERR(bd)) { 524 if (IS_ERR(bd)) {
240 pr_err("Could not register backlight device\n"); 525 pr_err("Could not register backlight device\n");
@@ -321,65 +606,240 @@ static ssize_t store_cpufv(struct device *dev, struct device_attribute *attr,
321 606
322static DEVICE_ATTR(cpufv, S_IRUGO | S_IWUSR, NULL, store_cpufv); 607static DEVICE_ATTR(cpufv, S_IRUGO | S_IWUSR, NULL, store_cpufv);
323 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
324static void eeepc_wmi_sysfs_exit(struct platform_device *device) 618static void eeepc_wmi_sysfs_exit(struct platform_device *device)
325{ 619{
326 device_remove_file(&device->dev, &dev_attr_cpufv); 620 sysfs_remove_group(&device->dev.kobj, &platform_attribute_group);
327} 621}
328 622
329static int eeepc_wmi_sysfs_init(struct platform_device *device) 623static int eeepc_wmi_sysfs_init(struct platform_device *device)
330{ 624{
331 int retval = -ENOMEM; 625 return sysfs_create_group(&device->dev.kobj, &platform_attribute_group);
626}
332 627
333 retval = device_create_file(&device->dev, &dev_attr_cpufv); 628/*
334 if (retval) 629 * Platform device
335 goto error_sysfs; 630 */
631static int __init eeepc_wmi_platform_init(struct eeepc_wmi *eeepc)
632{
633 int err;
336 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;
337 return 0; 647 return 0;
338 648
339error_sysfs: 649fail_sysfs:
340 eeepc_wmi_sysfs_exit(platform_device); 650 platform_device_del(eeepc->platform_device);
341 return retval; 651fail_platform_device:
652 platform_device_put(eeepc->platform_device);
653 return err;
342} 654}
343 655
344static int __devinit eeepc_wmi_platform_probe(struct platform_device *device) 656static void eeepc_wmi_platform_exit(struct eeepc_wmi *eeepc)
345{ 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 {
346 struct eeepc_wmi *eeepc; 666 struct eeepc_wmi *eeepc;
347 int err; 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;
348 acpi_status status; 674 acpi_status status;
675 u32 retval = -1;
349 676
350 eeepc = platform_get_drvdata(device); 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;
351 790
352 err = eeepc_wmi_input_init(eeepc); 791 err = eeepc_wmi_input_init(eeepc);
353 if (err) 792 if (err)
354 goto error_input; 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;
355 802
356 if (!acpi_video_backlight_support()) { 803 if (!acpi_video_backlight_support()) {
357 err = eeepc_wmi_backlight_init(eeepc); 804 err = eeepc_wmi_backlight_init(eeepc);
358 if (err) 805 if (err)
359 goto error_backlight; 806 goto fail_backlight;
360 } else 807 } else
361 pr_info("Backlight controlled by ACPI video driver\n"); 808 pr_info("Backlight controlled by ACPI video driver\n");
362 809
363 status = wmi_install_notify_handler(EEEPC_WMI_EVENT_GUID, 810 status = wmi_install_notify_handler(EEEPC_WMI_EVENT_GUID,
364 eeepc_wmi_notify, eeepc); 811 eeepc_wmi_notify, eeepc);
365 if (ACPI_FAILURE(status)) { 812 if (ACPI_FAILURE(status)) {
366 pr_err("Unable to register notify handler - %d\n", 813 pr_err("Unable to register notify handler - %d\n",
367 status); 814 status);
368 err = -ENODEV; 815 err = -ENODEV;
369 goto error_wmi; 816 goto fail_wmi_handler;
370 } 817 }
371 818
372 return 0; 819 err = eeepc_wmi_debugfs_init(eeepc);
820 if (err)
821 goto fail_debugfs;
373 822
374error_wmi: 823 return eeepc->platform_device;
824
825fail_debugfs:
826 wmi_remove_notify_handler(EEEPC_WMI_EVENT_GUID);
827fail_wmi_handler:
375 eeepc_wmi_backlight_exit(eeepc); 828 eeepc_wmi_backlight_exit(eeepc);
376error_backlight: 829fail_backlight:
830 eeepc_wmi_rfkill_exit(eeepc);
831fail_rfkill:
832 eeepc_wmi_led_exit(eeepc);
833fail_leds:
377 eeepc_wmi_input_exit(eeepc); 834 eeepc_wmi_input_exit(eeepc);
378error_input: 835fail_input:
379 return err; 836 eeepc_wmi_platform_exit(eeepc);
837fail_platform:
838 kfree(eeepc);
839 return ERR_PTR(err);
380} 840}
381 841
382static int __devexit eeepc_wmi_platform_remove(struct platform_device *device) 842static int eeepc_wmi_remove(struct platform_device *device)
383{ 843{
384 struct eeepc_wmi *eeepc; 844 struct eeepc_wmi *eeepc;
385 845
@@ -387,7 +847,12 @@ static int __devexit eeepc_wmi_platform_remove(struct platform_device *device)
387 wmi_remove_notify_handler(EEEPC_WMI_EVENT_GUID); 847 wmi_remove_notify_handler(EEEPC_WMI_EVENT_GUID);
388 eeepc_wmi_backlight_exit(eeepc); 848 eeepc_wmi_backlight_exit(eeepc);
389 eeepc_wmi_input_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);
390 854
855 kfree(eeepc);
391 return 0; 856 return 0;
392} 857}
393 858
@@ -396,13 +861,31 @@ static struct platform_driver platform_driver = {
396 .name = EEEPC_WMI_FILE, 861 .name = EEEPC_WMI_FILE,
397 .owner = THIS_MODULE, 862 .owner = THIS_MODULE,
398 }, 863 },
399 .probe = eeepc_wmi_platform_probe,
400 .remove = __devexit_p(eeepc_wmi_platform_remove),
401}; 864};
402 865
866static acpi_status __init eeepc_wmi_parse_device(acpi_handle handle, u32 level,
867 void *context, void **retval)
868{
869 pr_warning("Found legacy ATKD device (%s)", EEEPC_ACPI_HID);
870 *(bool *)context = true;
871 return AE_CTRL_TERMINATE;
872}
873
874static int __init eeepc_wmi_check_atkd(void)
875{
876 acpi_status status;
877 bool found = false;
878
879 status = acpi_get_devices(EEEPC_ACPI_HID, eeepc_wmi_parse_device,
880 &found, NULL);
881
882 if (ACPI_FAILURE(status) || !found)
883 return 0;
884 return -1;
885}
886
403static int __init eeepc_wmi_init(void) 887static int __init eeepc_wmi_init(void)
404{ 888{
405 struct eeepc_wmi *eeepc;
406 int err; 889 int err;
407 890
408 if (!wmi_has_guid(EEEPC_WMI_EVENT_GUID) || 891 if (!wmi_has_guid(EEEPC_WMI_EVENT_GUID) ||
@@ -411,58 +894,40 @@ static int __init eeepc_wmi_init(void)
411 return -ENODEV; 894 return -ENODEV;
412 } 895 }
413 896
414 eeepc = kzalloc(sizeof(struct eeepc_wmi), GFP_KERNEL); 897 if (eeepc_wmi_check_atkd()) {
415 if (!eeepc) 898 pr_warning("WMI device present, but legacy ATKD device is also "
416 return -ENOMEM; 899 "present and enabled.");
417 900 pr_warning("You probably booted with acpi_osi=\"Linux\" or "
418 platform_device = platform_device_alloc(EEEPC_WMI_FILE, -1); 901 "acpi_osi=\"!Windows 2009\"");
419 if (!platform_device) { 902 pr_warning("Can't load eeepc-wmi, use default acpi_osi "
420 pr_warning("Unable to allocate platform device\n"); 903 "(preferred) or eeepc-laptop");
421 err = -ENOMEM; 904 return -ENODEV;
422 goto fail_platform;
423 } 905 }
424 906
425 err = platform_device_add(platform_device); 907 platform_device = eeepc_wmi_add();
426 if (err) { 908 if (IS_ERR(platform_device)) {
427 pr_warning("Unable to add platform device\n"); 909 err = PTR_ERR(platform_device);
428 goto put_dev; 910 goto fail_eeepc_wmi;
429 } 911 }
430 912
431 platform_set_drvdata(platform_device, eeepc);
432
433 err = platform_driver_register(&platform_driver); 913 err = platform_driver_register(&platform_driver);
434 if (err) { 914 if (err) {
435 pr_warning("Unable to register platform driver\n"); 915 pr_warning("Unable to register platform driver\n");
436 goto del_dev; 916 goto fail_platform_driver;
437 } 917 }
438 918
439 err = eeepc_wmi_sysfs_init(platform_device);
440 if (err)
441 goto del_sysfs;
442
443 return 0; 919 return 0;
444 920
445del_sysfs: 921fail_platform_driver:
446 eeepc_wmi_sysfs_exit(platform_device); 922 eeepc_wmi_remove(platform_device);
447del_dev: 923fail_eeepc_wmi:
448 platform_device_del(platform_device);
449put_dev:
450 platform_device_put(platform_device);
451fail_platform:
452 kfree(eeepc);
453
454 return err; 924 return err;
455} 925}
456 926
457static void __exit eeepc_wmi_exit(void) 927static void __exit eeepc_wmi_exit(void)
458{ 928{
459 struct eeepc_wmi *eeepc; 929 eeepc_wmi_remove(platform_device);
460
461 eeepc_wmi_sysfs_exit(platform_device);
462 eeepc = platform_get_drvdata(platform_device);
463 platform_driver_unregister(&platform_driver); 930 platform_driver_unregister(&platform_driver);
464 platform_device_unregister(platform_device);
465 kfree(eeepc);
466} 931}
467 932
468module_init(eeepc_wmi_init); 933module_init(eeepc_wmi_init);
diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c
index f44cd2620ff9..ad88b2ec34a1 100644
--- a/drivers/platform/x86/fujitsu-laptop.c
+++ b/drivers/platform/x86/fujitsu-laptop.c
@@ -1240,7 +1240,7 @@ MODULE_ALIAS("dmi:*:svnFUJITSUSIEMENS:*:pvr:rvnFUJITSU:rnFJNB1D3:*:cvrS6410:*");
1240MODULE_ALIAS("dmi:*:svnFUJITSUSIEMENS:*:pvr:rvnFUJITSU:rnFJNB1E6:*:cvrS6420:*"); 1240MODULE_ALIAS("dmi:*:svnFUJITSUSIEMENS:*:pvr:rvnFUJITSU:rnFJNB1E6:*:cvrS6420:*");
1241MODULE_ALIAS("dmi:*:svnFUJITSU:*:pvr:rvnFUJITSU:rnFJNB19C:*:cvrS7020:*"); 1241MODULE_ALIAS("dmi:*:svnFUJITSU:*:pvr:rvnFUJITSU:rnFJNB19C:*:cvrS7020:*");
1242 1242
1243static struct pnp_device_id pnp_ids[] = { 1243static struct pnp_device_id pnp_ids[] __used = {
1244 {.id = "FUJ02bf"}, 1244 {.id = "FUJ02bf"},
1245 {.id = "FUJ02B1"}, 1245 {.id = "FUJ02B1"},
1246 {.id = "FUJ02E3"}, 1246 {.id = "FUJ02E3"},
diff --git a/drivers/platform/x86/ideapad-laptop.c b/drivers/platform/x86/ideapad-laptop.c
index 5ff12205aa6b..114d95247cdf 100644
--- a/drivers/platform/x86/ideapad-laptop.c
+++ b/drivers/platform/x86/ideapad-laptop.c
@@ -1,5 +1,5 @@
1/* 1/*
2 * ideapad_acpi.c - Lenovo IdeaPad ACPI Extras 2 * ideapad-laptop.c - Lenovo IdeaPad ACPI Extras
3 * 3 *
4 * Copyright © 2010 Intel Corporation 4 * Copyright © 2010 Intel Corporation
5 * Copyright © 2010 David Woodhouse <dwmw2@infradead.org> 5 * Copyright © 2010 David Woodhouse <dwmw2@infradead.org>
@@ -27,31 +27,19 @@
27#include <acpi/acpi_bus.h> 27#include <acpi/acpi_bus.h>
28#include <acpi/acpi_drivers.h> 28#include <acpi/acpi_drivers.h>
29#include <linux/rfkill.h> 29#include <linux/rfkill.h>
30#include <linux/platform_device.h>
31#include <linux/input.h>
32#include <linux/input/sparse-keymap.h>
30 33
31#define IDEAPAD_DEV_CAMERA 0 34#define IDEAPAD_RFKILL_DEV_NUM (3)
32#define IDEAPAD_DEV_WLAN 1
33#define IDEAPAD_DEV_BLUETOOTH 2
34#define IDEAPAD_DEV_3G 3
35#define IDEAPAD_DEV_KILLSW 4
36 35
37struct ideapad_private { 36struct ideapad_private {
38 acpi_handle handle; 37 struct rfkill *rfk[IDEAPAD_RFKILL_DEV_NUM];
39 struct rfkill *rfk[5]; 38 struct platform_device *platform_device;
40} *ideapad_priv; 39 struct input_dev *inputdev;
41
42static struct {
43 char *name;
44 int cfgbit;
45 int opcode;
46 int type;
47} ideapad_rfk_data[] = {
48 { "ideapad_camera", 19, 0x1E, NUM_RFKILL_TYPES },
49 { "ideapad_wlan", 18, 0x15, RFKILL_TYPE_WLAN },
50 { "ideapad_bluetooth", 16, 0x17, RFKILL_TYPE_BLUETOOTH },
51 { "ideapad_3g", 17, 0x20, RFKILL_TYPE_WWAN },
52 { "ideapad_killsw", 0, 0, RFKILL_TYPE_WLAN }
53}; 40};
54 41
42static acpi_handle ideapad_handle;
55static bool no_bt_rfkill; 43static bool no_bt_rfkill;
56module_param(no_bt_rfkill, bool, 0444); 44module_param(no_bt_rfkill, bool, 0444);
57MODULE_PARM_DESC(no_bt_rfkill, "No rfkill for bluetooth."); 45MODULE_PARM_DESC(no_bt_rfkill, "No rfkill for bluetooth.");
@@ -163,17 +151,17 @@ static int write_ec_cmd(acpi_handle handle, int cmd, unsigned long data)
163 pr_err("timeout in write_ec_cmd\n"); 151 pr_err("timeout in write_ec_cmd\n");
164 return -1; 152 return -1;
165} 153}
166/* the above is ACPI helpers */
167 154
155/*
156 * camera power
157 */
168static ssize_t show_ideapad_cam(struct device *dev, 158static ssize_t show_ideapad_cam(struct device *dev,
169 struct device_attribute *attr, 159 struct device_attribute *attr,
170 char *buf) 160 char *buf)
171{ 161{
172 struct ideapad_private *priv = dev_get_drvdata(dev);
173 acpi_handle handle = priv->handle;
174 unsigned long result; 162 unsigned long result;
175 163
176 if (read_ec_data(handle, 0x1D, &result)) 164 if (read_ec_data(ideapad_handle, 0x1D, &result))
177 return sprintf(buf, "-1\n"); 165 return sprintf(buf, "-1\n");
178 return sprintf(buf, "%lu\n", result); 166 return sprintf(buf, "%lu\n", result);
179} 167}
@@ -182,15 +170,13 @@ static ssize_t store_ideapad_cam(struct device *dev,
182 struct device_attribute *attr, 170 struct device_attribute *attr,
183 const char *buf, size_t count) 171 const char *buf, size_t count)
184{ 172{
185 struct ideapad_private *priv = dev_get_drvdata(dev);
186 acpi_handle handle = priv->handle;
187 int ret, state; 173 int ret, state;
188 174
189 if (!count) 175 if (!count)
190 return 0; 176 return 0;
191 if (sscanf(buf, "%i", &state) != 1) 177 if (sscanf(buf, "%i", &state) != 1)
192 return -EINVAL; 178 return -EINVAL;
193 ret = write_ec_cmd(handle, 0x1E, state); 179 ret = write_ec_cmd(ideapad_handle, 0x1E, state);
194 if (ret < 0) 180 if (ret < 0)
195 return ret; 181 return ret;
196 return count; 182 return count;
@@ -198,16 +184,27 @@ static ssize_t store_ideapad_cam(struct device *dev,
198 184
199static DEVICE_ATTR(camera_power, 0644, show_ideapad_cam, store_ideapad_cam); 185static DEVICE_ATTR(camera_power, 0644, show_ideapad_cam, store_ideapad_cam);
200 186
187/*
188 * Rfkill
189 */
190struct ideapad_rfk_data {
191 char *name;
192 int cfgbit;
193 int opcode;
194 int type;
195};
196
197const struct ideapad_rfk_data ideapad_rfk_data[] = {
198 { "ideapad_wlan", 18, 0x15, RFKILL_TYPE_WLAN },
199 { "ideapad_bluetooth", 16, 0x17, RFKILL_TYPE_BLUETOOTH },
200 { "ideapad_3g", 17, 0x20, RFKILL_TYPE_WWAN },
201};
202
201static int ideapad_rfk_set(void *data, bool blocked) 203static int ideapad_rfk_set(void *data, bool blocked)
202{ 204{
203 int device = (unsigned long)data; 205 unsigned long opcode = (unsigned long)data;
204 206
205 if (device == IDEAPAD_DEV_KILLSW) 207 return write_ec_cmd(ideapad_handle, opcode, !blocked);
206 return -EINVAL;
207
208 return write_ec_cmd(ideapad_priv->handle,
209 ideapad_rfk_data[device].opcode,
210 !blocked);
211} 208}
212 209
213static struct rfkill_ops ideapad_rfk_ops = { 210static struct rfkill_ops ideapad_rfk_ops = {
@@ -217,20 +214,20 @@ static struct rfkill_ops ideapad_rfk_ops = {
217static void ideapad_sync_rfk_state(struct acpi_device *adevice) 214static void ideapad_sync_rfk_state(struct acpi_device *adevice)
218{ 215{
219 struct ideapad_private *priv = dev_get_drvdata(&adevice->dev); 216 struct ideapad_private *priv = dev_get_drvdata(&adevice->dev);
220 acpi_handle handle = priv->handle;
221 unsigned long hw_blocked; 217 unsigned long hw_blocked;
222 int i; 218 int i;
223 219
224 if (read_ec_data(handle, 0x23, &hw_blocked)) 220 if (read_ec_data(ideapad_handle, 0x23, &hw_blocked))
225 return; 221 return;
226 hw_blocked = !hw_blocked; 222 hw_blocked = !hw_blocked;
227 223
228 for (i = IDEAPAD_DEV_WLAN; i <= IDEAPAD_DEV_KILLSW; i++) 224 for (i = 0; i < IDEAPAD_RFKILL_DEV_NUM; i++)
229 if (priv->rfk[i]) 225 if (priv->rfk[i])
230 rfkill_set_hw_state(priv->rfk[i], hw_blocked); 226 rfkill_set_hw_state(priv->rfk[i], hw_blocked);
231} 227}
232 228
233static int ideapad_register_rfkill(struct acpi_device *adevice, int dev) 229static int __devinit ideapad_register_rfkill(struct acpi_device *adevice,
230 int dev)
234{ 231{
235 struct ideapad_private *priv = dev_get_drvdata(&adevice->dev); 232 struct ideapad_private *priv = dev_get_drvdata(&adevice->dev);
236 int ret; 233 int ret;
@@ -239,7 +236,7 @@ static int ideapad_register_rfkill(struct acpi_device *adevice, int dev)
239 if (no_bt_rfkill && 236 if (no_bt_rfkill &&
240 (ideapad_rfk_data[dev].type == RFKILL_TYPE_BLUETOOTH)) { 237 (ideapad_rfk_data[dev].type == RFKILL_TYPE_BLUETOOTH)) {
241 /* Force to enable bluetooth when no_bt_rfkill=1 */ 238 /* Force to enable bluetooth when no_bt_rfkill=1 */
242 write_ec_cmd(ideapad_priv->handle, 239 write_ec_cmd(ideapad_handle,
243 ideapad_rfk_data[dev].opcode, 1); 240 ideapad_rfk_data[dev].opcode, 1);
244 return 0; 241 return 0;
245 } 242 }
@@ -250,7 +247,7 @@ static int ideapad_register_rfkill(struct acpi_device *adevice, int dev)
250 if (!priv->rfk[dev]) 247 if (!priv->rfk[dev])
251 return -ENOMEM; 248 return -ENOMEM;
252 249
253 if (read_ec_data(ideapad_priv->handle, ideapad_rfk_data[dev].opcode-1, 250 if (read_ec_data(ideapad_handle, ideapad_rfk_data[dev].opcode-1,
254 &sw_blocked)) { 251 &sw_blocked)) {
255 rfkill_init_sw_state(priv->rfk[dev], 0); 252 rfkill_init_sw_state(priv->rfk[dev], 0);
256 } else { 253 } else {
@@ -266,7 +263,8 @@ static int ideapad_register_rfkill(struct acpi_device *adevice, int dev)
266 return 0; 263 return 0;
267} 264}
268 265
269static void ideapad_unregister_rfkill(struct acpi_device *adevice, int dev) 266static void __devexit ideapad_unregister_rfkill(struct acpi_device *adevice,
267 int dev)
270{ 268{
271 struct ideapad_private *priv = dev_get_drvdata(&adevice->dev); 269 struct ideapad_private *priv = dev_get_drvdata(&adevice->dev);
272 270
@@ -277,73 +275,177 @@ static void ideapad_unregister_rfkill(struct acpi_device *adevice, int dev)
277 rfkill_destroy(priv->rfk[dev]); 275 rfkill_destroy(priv->rfk[dev]);
278} 276}
279 277
278/*
279 * Platform device
280 */
281static struct attribute *ideapad_attributes[] = {
282 &dev_attr_camera_power.attr,
283 NULL
284};
285
286static struct attribute_group ideapad_attribute_group = {
287 .attrs = ideapad_attributes
288};
289
290static int __devinit ideapad_platform_init(struct ideapad_private *priv)
291{
292 int result;
293
294 priv->platform_device = platform_device_alloc("ideapad", -1);
295 if (!priv->platform_device)
296 return -ENOMEM;
297 platform_set_drvdata(priv->platform_device, priv);
298
299 result = platform_device_add(priv->platform_device);
300 if (result)
301 goto fail_platform_device;
302
303 result = sysfs_create_group(&priv->platform_device->dev.kobj,
304 &ideapad_attribute_group);
305 if (result)
306 goto fail_sysfs;
307 return 0;
308
309fail_sysfs:
310 platform_device_del(priv->platform_device);
311fail_platform_device:
312 platform_device_put(priv->platform_device);
313 return result;
314}
315
316static void ideapad_platform_exit(struct ideapad_private *priv)
317{
318 sysfs_remove_group(&priv->platform_device->dev.kobj,
319 &ideapad_attribute_group);
320 platform_device_unregister(priv->platform_device);
321}
322
323/*
324 * input device
325 */
326static const struct key_entry ideapad_keymap[] = {
327 { KE_KEY, 0x06, { KEY_SWITCHVIDEOMODE } },
328 { KE_KEY, 0x0D, { KEY_WLAN } },
329 { KE_END, 0 },
330};
331
332static int __devinit ideapad_input_init(struct ideapad_private *priv)
333{
334 struct input_dev *inputdev;
335 int error;
336
337 inputdev = input_allocate_device();
338 if (!inputdev) {
339 pr_info("Unable to allocate input device\n");
340 return -ENOMEM;
341 }
342
343 inputdev->name = "Ideapad extra buttons";
344 inputdev->phys = "ideapad/input0";
345 inputdev->id.bustype = BUS_HOST;
346 inputdev->dev.parent = &priv->platform_device->dev;
347
348 error = sparse_keymap_setup(inputdev, ideapad_keymap, NULL);
349 if (error) {
350 pr_err("Unable to setup input device keymap\n");
351 goto err_free_dev;
352 }
353
354 error = input_register_device(inputdev);
355 if (error) {
356 pr_err("Unable to register input device\n");
357 goto err_free_keymap;
358 }
359
360 priv->inputdev = inputdev;
361 return 0;
362
363err_free_keymap:
364 sparse_keymap_free(inputdev);
365err_free_dev:
366 input_free_device(inputdev);
367 return error;
368}
369
370static void __devexit ideapad_input_exit(struct ideapad_private *priv)
371{
372 sparse_keymap_free(priv->inputdev);
373 input_unregister_device(priv->inputdev);
374 priv->inputdev = NULL;
375}
376
377static void ideapad_input_report(struct ideapad_private *priv,
378 unsigned long scancode)
379{
380 sparse_keymap_report_event(priv->inputdev, scancode, 1, true);
381}
382
383/*
384 * module init/exit
385 */
280static const struct acpi_device_id ideapad_device_ids[] = { 386static const struct acpi_device_id ideapad_device_ids[] = {
281 { "VPC2004", 0}, 387 { "VPC2004", 0},
282 { "", 0}, 388 { "", 0},
283}; 389};
284MODULE_DEVICE_TABLE(acpi, ideapad_device_ids); 390MODULE_DEVICE_TABLE(acpi, ideapad_device_ids);
285 391
286static int ideapad_acpi_add(struct acpi_device *adevice) 392static int __devinit ideapad_acpi_add(struct acpi_device *adevice)
287{ 393{
288 int i, cfg; 394 int ret, i, cfg;
289 int devs_present[5];
290 struct ideapad_private *priv; 395 struct ideapad_private *priv;
291 396
292 if (read_method_int(adevice->handle, "_CFG", &cfg)) 397 if (read_method_int(adevice->handle, "_CFG", &cfg))
293 return -ENODEV; 398 return -ENODEV;
294 399
295 for (i = IDEAPAD_DEV_CAMERA; i < IDEAPAD_DEV_KILLSW; i++) {
296 if (test_bit(ideapad_rfk_data[i].cfgbit, (unsigned long *)&cfg))
297 devs_present[i] = 1;
298 else
299 devs_present[i] = 0;
300 }
301
302 /* The hardware switch is always present */
303 devs_present[IDEAPAD_DEV_KILLSW] = 1;
304
305 priv = kzalloc(sizeof(*priv), GFP_KERNEL); 400 priv = kzalloc(sizeof(*priv), GFP_KERNEL);
306 if (!priv) 401 if (!priv)
307 return -ENOMEM; 402 return -ENOMEM;
403 dev_set_drvdata(&adevice->dev, priv);
404 ideapad_handle = adevice->handle;
308 405
309 if (devs_present[IDEAPAD_DEV_CAMERA]) { 406 ret = ideapad_platform_init(priv);
310 int ret = device_create_file(&adevice->dev, &dev_attr_camera_power); 407 if (ret)
311 if (ret) { 408 goto platform_failed;
312 kfree(priv);
313 return ret;
314 }
315 }
316 409
317 priv->handle = adevice->handle; 410 ret = ideapad_input_init(priv);
318 dev_set_drvdata(&adevice->dev, priv); 411 if (ret)
319 ideapad_priv = priv; 412 goto input_failed;
320 for (i = IDEAPAD_DEV_WLAN; i <= IDEAPAD_DEV_KILLSW; i++) {
321 if (!devs_present[i])
322 continue;
323 413
324 ideapad_register_rfkill(adevice, i); 414 for (i = 0; i < IDEAPAD_RFKILL_DEV_NUM; i++) {
415 if (test_bit(ideapad_rfk_data[i].cfgbit, (unsigned long *)&cfg))
416 ideapad_register_rfkill(adevice, i);
417 else
418 priv->rfk[i] = NULL;
325 } 419 }
326 ideapad_sync_rfk_state(adevice); 420 ideapad_sync_rfk_state(adevice);
421
327 return 0; 422 return 0;
423
424input_failed:
425 ideapad_platform_exit(priv);
426platform_failed:
427 kfree(priv);
428 return ret;
328} 429}
329 430
330static int ideapad_acpi_remove(struct acpi_device *adevice, int type) 431static int __devexit ideapad_acpi_remove(struct acpi_device *adevice, int type)
331{ 432{
332 struct ideapad_private *priv = dev_get_drvdata(&adevice->dev); 433 struct ideapad_private *priv = dev_get_drvdata(&adevice->dev);
333 int i; 434 int i;
334 435
335 device_remove_file(&adevice->dev, &dev_attr_camera_power); 436 for (i = 0; i < IDEAPAD_RFKILL_DEV_NUM; i++)
336
337 for (i = IDEAPAD_DEV_WLAN; i <= IDEAPAD_DEV_KILLSW; i++)
338 ideapad_unregister_rfkill(adevice, i); 437 ideapad_unregister_rfkill(adevice, i);
339 438 ideapad_input_exit(priv);
439 ideapad_platform_exit(priv);
340 dev_set_drvdata(&adevice->dev, NULL); 440 dev_set_drvdata(&adevice->dev, NULL);
341 kfree(priv); 441 kfree(priv);
442
342 return 0; 443 return 0;
343} 444}
344 445
345static void ideapad_acpi_notify(struct acpi_device *adevice, u32 event) 446static void ideapad_acpi_notify(struct acpi_device *adevice, u32 event)
346{ 447{
448 struct ideapad_private *priv = dev_get_drvdata(&adevice->dev);
347 acpi_handle handle = adevice->handle; 449 acpi_handle handle = adevice->handle;
348 unsigned long vpc1, vpc2, vpc_bit; 450 unsigned long vpc1, vpc2, vpc_bit;
349 451
@@ -357,6 +459,8 @@ static void ideapad_acpi_notify(struct acpi_device *adevice, u32 event)
357 if (test_bit(vpc_bit, &vpc1)) { 459 if (test_bit(vpc_bit, &vpc1)) {
358 if (vpc_bit == 9) 460 if (vpc_bit == 9)
359 ideapad_sync_rfk_state(adevice); 461 ideapad_sync_rfk_state(adevice);
462 else
463 ideapad_input_report(priv, vpc_bit);
360 } 464 }
361 } 465 }
362} 466}
@@ -371,19 +475,14 @@ static struct acpi_driver ideapad_acpi_driver = {
371 .owner = THIS_MODULE, 475 .owner = THIS_MODULE,
372}; 476};
373 477
374
375static int __init ideapad_acpi_module_init(void) 478static int __init ideapad_acpi_module_init(void)
376{ 479{
377 acpi_bus_register_driver(&ideapad_acpi_driver); 480 return acpi_bus_register_driver(&ideapad_acpi_driver);
378
379 return 0;
380} 481}
381 482
382
383static void __exit ideapad_acpi_module_exit(void) 483static void __exit ideapad_acpi_module_exit(void)
384{ 484{
385 acpi_bus_unregister_driver(&ideapad_acpi_driver); 485 acpi_bus_unregister_driver(&ideapad_acpi_driver);
386
387} 486}
388 487
389MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>"); 488MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
diff --git a/drivers/platform/x86/intel_ips.c b/drivers/platform/x86/intel_ips.c
index f0b3ad13c273..1294a39373ba 100644
--- a/drivers/platform/x86/intel_ips.c
+++ b/drivers/platform/x86/intel_ips.c
@@ -1474,7 +1474,7 @@ ips_gpu_turbo_enabled(struct ips_driver *ips)
1474} 1474}
1475 1475
1476void 1476void
1477ips_link_to_i915_driver() 1477ips_link_to_i915_driver(void)
1478{ 1478{
1479 /* We can't cleanly get at the various ips_driver structs from 1479 /* We can't cleanly get at the various ips_driver structs from
1480 * this caller (the i915 driver), so just set a flag saying 1480 * this caller (the i915 driver), so just set a flag saying
diff --git a/drivers/platform/x86/intel_pmic_gpio.c b/drivers/platform/x86/intel_pmic_gpio.c
index e61db9dfebef..930e62762365 100644
--- a/drivers/platform/x86/intel_pmic_gpio.c
+++ b/drivers/platform/x86/intel_pmic_gpio.c
@@ -244,7 +244,11 @@ static void pmic_irq_handler(unsigned irq, struct irq_desc *desc)
244 generic_handle_irq(pg->irq_base + gpio); 244 generic_handle_irq(pg->irq_base + gpio);
245 } 245 }
246 } 246 }
247 desc->chip->eoi(irq); 247
248 if (desc->chip->irq_eoi)
249 desc->chip->irq_eoi(irq_get_irq_data(irq));
250 else
251 dev_warn(pg->chip.dev, "missing EOI handler for irq %d\n", irq);
248} 252}
249 253
250static int __devinit platform_pmic_gpio_probe(struct platform_device *pdev) 254static int __devinit platform_pmic_gpio_probe(struct platform_device *pdev)
diff --git a/drivers/platform/x86/intel_scu_ipc.c b/drivers/platform/x86/intel_scu_ipc.c
index ca35b0ce944a..1752ef006d26 100644
--- a/drivers/platform/x86/intel_scu_ipc.c
+++ b/drivers/platform/x86/intel_scu_ipc.c
@@ -497,7 +497,7 @@ int intel_scu_ipc_i2c_cntrl(u32 addr, u32 *data)
497 "intel_scu_ipc: I2C INVALID_CMD = 0x%x\n", cmd); 497 "intel_scu_ipc: I2C INVALID_CMD = 0x%x\n", cmd);
498 498
499 mutex_unlock(&ipclock); 499 mutex_unlock(&ipclock);
500 return -1; 500 return -EIO;
501 } 501 }
502 mutex_unlock(&ipclock); 502 mutex_unlock(&ipclock);
503 return 0; 503 return 0;
@@ -642,7 +642,7 @@ update_end:
642 642
643 if (status == IPC_FW_UPDATE_SUCCESS) 643 if (status == IPC_FW_UPDATE_SUCCESS)
644 return 0; 644 return 0;
645 return -1; 645 return -EIO;
646} 646}
647EXPORT_SYMBOL(intel_scu_ipc_fw_update); 647EXPORT_SYMBOL(intel_scu_ipc_fw_update);
648 648
diff --git a/drivers/platform/x86/intel_scu_ipcutil.c b/drivers/platform/x86/intel_scu_ipcutil.c
new file mode 100644
index 000000000000..ba3231d0819e
--- /dev/null
+++ b/drivers/platform/x86/intel_scu_ipcutil.c
@@ -0,0 +1,133 @@
1/*
2 * intel_scu_ipc.c: Driver for the Intel SCU IPC mechanism
3 *
4 * (C) Copyright 2008-2010 Intel Corporation
5 * Author: Sreedhara DS (sreedhara.ds@intel.com)
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; version 2
10 * of the License.
11 *
12 * This driver provides ioctl interfaces to call intel scu ipc driver api
13 */
14
15#include <linux/module.h>
16#include <linux/kernel.h>
17#include <linux/errno.h>
18#include <linux/types.h>
19#include <linux/fs.h>
20#include <linux/fcntl.h>
21#include <linux/sched.h>
22#include <linux/uaccess.h>
23#include <linux/slab.h>
24#include <linux/init.h>
25#include <asm/intel_scu_ipc.h>
26
27static u32 major;
28
29#define MAX_FW_SIZE 264192
30
31/* ioctl commnds */
32#define INTE_SCU_IPC_REGISTER_READ 0
33#define INTE_SCU_IPC_REGISTER_WRITE 1
34#define INTE_SCU_IPC_REGISTER_UPDATE 2
35#define INTE_SCU_IPC_FW_UPDATE 0xA2
36
37struct scu_ipc_data {
38 u32 count; /* No. of registers */
39 u16 addr[5]; /* Register addresses */
40 u8 data[5]; /* Register data */
41 u8 mask; /* Valid for read-modify-write */
42};
43
44/**
45 * scu_reg_access - implement register access ioctls
46 * @cmd: command we are doing (read/write/update)
47 * @data: kernel copy of ioctl data
48 *
49 * Allow the user to perform register accesses on the SCU via the
50 * kernel interface
51 */
52
53static int scu_reg_access(u32 cmd, struct scu_ipc_data *data)
54{
55 int count = data->count;
56
57 if (count == 0 || count == 3 || count > 4)
58 return -EINVAL;
59
60 switch (cmd) {
61 case INTE_SCU_IPC_REGISTER_READ:
62 return intel_scu_ipc_readv(data->addr, data->data, count);
63 case INTE_SCU_IPC_REGISTER_WRITE:
64 return intel_scu_ipc_writev(data->addr, data->data, count);
65 case INTE_SCU_IPC_REGISTER_UPDATE:
66 return intel_scu_ipc_update_register(data->addr[0],
67 data->data[0], data->mask);
68 default:
69 return -ENOTTY;
70 }
71}
72
73/**
74 * scu_ipc_ioctl - control ioctls for the SCU
75 * @fp: file handle of the SCU device
76 * @cmd: ioctl coce
77 * @arg: pointer to user passed structure
78 *
79 * Support the I/O and firmware flashing interfaces of the SCU
80 */
81static long scu_ipc_ioctl(struct file *fp, unsigned int cmd,
82 unsigned long arg)
83{
84 int ret;
85 struct scu_ipc_data data;
86 void __user *argp = (void __user *)arg;
87
88 if (!capable(CAP_SYS_RAWIO))
89 return -EPERM;
90
91 if (cmd == INTE_SCU_IPC_FW_UPDATE) {
92 u8 *fwbuf = kmalloc(MAX_FW_SIZE, GFP_KERNEL);
93 if (fwbuf == NULL)
94 return -ENOMEM;
95 if (copy_from_user(fwbuf, (u8 *)arg, MAX_FW_SIZE)) {
96 kfree(fwbuf);
97 return -EFAULT;
98 }
99 ret = intel_scu_ipc_fw_update(fwbuf, MAX_FW_SIZE);
100 kfree(fwbuf);
101 return ret;
102 } else {
103 if (copy_from_user(&data, argp, sizeof(struct scu_ipc_data)))
104 return -EFAULT;
105 ret = scu_reg_access(cmd, &data);
106 if (ret < 0)
107 return ret;
108 if (copy_to_user(argp, &data, sizeof(struct scu_ipc_data)))
109 return -EFAULT;
110 return 0;
111 }
112}
113
114static const struct file_operations scu_ipc_fops = {
115 .unlocked_ioctl = scu_ipc_ioctl,
116};
117
118static int __init ipc_module_init(void)
119{
120 return register_chrdev(0, "intel_mid_scu", &scu_ipc_fops);
121}
122
123static void __exit ipc_module_exit(void)
124{
125 unregister_chrdev(major, "intel_mid_scu");
126}
127
128module_init(ipc_module_init);
129module_exit(ipc_module_exit);
130
131MODULE_LICENSE("GPL V2");
132MODULE_DESCRIPTION("Utility driver for intel scu ipc");
133MODULE_AUTHOR("Sreedhara <sreedhara.ds@intel.com>");
diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c
index f200677851b8..b4a95bb2f232 100644
--- a/drivers/platform/x86/sony-laptop.c
+++ b/drivers/platform/x86/sony-laptop.c
@@ -235,6 +235,7 @@ static int sony_laptop_input_index[] = {
235 57, /* 70 SONYPI_EVENT_VOLUME_DEC_PRESSED */ 235 57, /* 70 SONYPI_EVENT_VOLUME_DEC_PRESSED */
236 -1, /* 71 SONYPI_EVENT_BRIGHTNESS_PRESSED */ 236 -1, /* 71 SONYPI_EVENT_BRIGHTNESS_PRESSED */
237 58, /* 72 SONYPI_EVENT_MEDIA_PRESSED */ 237 58, /* 72 SONYPI_EVENT_MEDIA_PRESSED */
238 59, /* 72 SONYPI_EVENT_VENDOR_PRESSED */
238}; 239};
239 240
240static int sony_laptop_input_keycode_map[] = { 241static int sony_laptop_input_keycode_map[] = {
@@ -297,6 +298,7 @@ static int sony_laptop_input_keycode_map[] = {
297 KEY_VOLUMEUP, /* 56 SONYPI_EVENT_VOLUME_INC_PRESSED */ 298 KEY_VOLUMEUP, /* 56 SONYPI_EVENT_VOLUME_INC_PRESSED */
298 KEY_VOLUMEDOWN, /* 57 SONYPI_EVENT_VOLUME_DEC_PRESSED */ 299 KEY_VOLUMEDOWN, /* 57 SONYPI_EVENT_VOLUME_DEC_PRESSED */
299 KEY_MEDIA, /* 58 SONYPI_EVENT_MEDIA_PRESSED */ 300 KEY_MEDIA, /* 58 SONYPI_EVENT_MEDIA_PRESSED */
301 KEY_VENDOR, /* 59 SONYPI_EVENT_VENDOR_PRESSED */
300}; 302};
301 303
302/* release buttons after a short delay if pressed */ 304/* release buttons after a short delay if pressed */
@@ -894,10 +896,18 @@ static struct sony_nc_event sony_100_events[] = {
894 { 0x0A, SONYPI_EVENT_FNKEY_RELEASED }, 896 { 0x0A, SONYPI_EVENT_FNKEY_RELEASED },
895 { 0x8C, SONYPI_EVENT_FNKEY_F12 }, 897 { 0x8C, SONYPI_EVENT_FNKEY_F12 },
896 { 0x0C, SONYPI_EVENT_FNKEY_RELEASED }, 898 { 0x0C, SONYPI_EVENT_FNKEY_RELEASED },
899 { 0x9d, SONYPI_EVENT_ZOOM_PRESSED },
900 { 0x1d, SONYPI_EVENT_ANYBUTTON_RELEASED },
897 { 0x9f, SONYPI_EVENT_CD_EJECT_PRESSED }, 901 { 0x9f, SONYPI_EVENT_CD_EJECT_PRESSED },
898 { 0x1f, SONYPI_EVENT_ANYBUTTON_RELEASED }, 902 { 0x1f, SONYPI_EVENT_ANYBUTTON_RELEASED },
899 { 0xa1, SONYPI_EVENT_MEDIA_PRESSED }, 903 { 0xa1, SONYPI_EVENT_MEDIA_PRESSED },
900 { 0x21, SONYPI_EVENT_ANYBUTTON_RELEASED }, 904 { 0x21, SONYPI_EVENT_ANYBUTTON_RELEASED },
905 { 0xa4, SONYPI_EVENT_CD_EJECT_PRESSED },
906 { 0x24, SONYPI_EVENT_ANYBUTTON_RELEASED },
907 { 0xa5, SONYPI_EVENT_VENDOR_PRESSED },
908 { 0x25, SONYPI_EVENT_ANYBUTTON_RELEASED },
909 { 0xa6, SONYPI_EVENT_HELP_PRESSED },
910 { 0x26, SONYPI_EVENT_ANYBUTTON_RELEASED },
901 { 0, 0 }, 911 { 0, 0 },
902}; 912};
903 913
@@ -1131,7 +1141,7 @@ static int sony_nc_setup_rfkill(struct acpi_device *device,
1131 return err; 1141 return err;
1132} 1142}
1133 1143
1134static void sony_nc_rfkill_update() 1144static void sony_nc_rfkill_update(void)
1135{ 1145{
1136 enum sony_nc_rfkill i; 1146 enum sony_nc_rfkill i;
1137 int result; 1147 int result;
diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c
index e8c21994b36d..a974ca383cb9 100644
--- a/drivers/platform/x86/thinkpad_acpi.c
+++ b/drivers/platform/x86/thinkpad_acpi.c
@@ -589,6 +589,7 @@ static int acpi_evalf(acpi_handle handle,
589 default: 589 default:
590 printk(TPACPI_ERR "acpi_evalf() called " 590 printk(TPACPI_ERR "acpi_evalf() called "
591 "with invalid format character '%c'\n", c); 591 "with invalid format character '%c'\n", c);
592 va_end(ap);
592 return 0; 593 return 0;
593 } 594 }
594 } 595 }
@@ -6345,7 +6346,7 @@ static int __init brightness_init(struct ibm_init_struct *iibm)
6345 "as change notification\n"); 6346 "as change notification\n");
6346 tpacpi_hotkey_driver_mask_set(hotkey_driver_mask 6347 tpacpi_hotkey_driver_mask_set(hotkey_driver_mask
6347 | TP_ACPI_HKEY_BRGHTUP_MASK 6348 | TP_ACPI_HKEY_BRGHTUP_MASK
6348 | TP_ACPI_HKEY_BRGHTDWN_MASK);; 6349 | TP_ACPI_HKEY_BRGHTDWN_MASK);
6349 return 0; 6350 return 0;
6350} 6351}
6351 6352
diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c
index aecd9a9b549f..05cc79672a8b 100644
--- a/drivers/platform/x86/wmi.c
+++ b/drivers/platform/x86/wmi.c
@@ -549,21 +549,34 @@ acpi_status wmi_install_notify_handler(const char *guid,
549wmi_notify_handler handler, void *data) 549wmi_notify_handler handler, void *data)
550{ 550{
551 struct wmi_block *block; 551 struct wmi_block *block;
552 acpi_status status; 552 acpi_status status = AE_NOT_EXIST;
553 char tmp[16], guid_input[16];
554 struct list_head *p;
553 555
554 if (!guid || !handler) 556 if (!guid || !handler)
555 return AE_BAD_PARAMETER; 557 return AE_BAD_PARAMETER;
556 558
557 if (!find_guid(guid, &block)) 559 wmi_parse_guid(guid, tmp);
558 return AE_NOT_EXIST; 560 wmi_swap_bytes(tmp, guid_input);
559 561
560 if (block->handler && block->handler != wmi_notify_debug) 562 list_for_each(p, &wmi_block_list) {
561 return AE_ALREADY_ACQUIRED; 563 acpi_status wmi_status;
564 block = list_entry(p, struct wmi_block, list);
562 565
563 block->handler = handler; 566 if (memcmp(block->gblock.guid, guid_input, 16) == 0) {
564 block->handler_data = data; 567 if (block->handler &&
568 block->handler != wmi_notify_debug)
569 return AE_ALREADY_ACQUIRED;
565 570
566 status = wmi_method_enable(block, 1); 571 block->handler = handler;
572 block->handler_data = data;
573
574 wmi_status = wmi_method_enable(block, 1);
575 if ((wmi_status != AE_OK) ||
576 ((wmi_status == AE_OK) && (status == AE_NOT_EXIST)))
577 status = wmi_status;
578 }
579 }
567 580
568 return status; 581 return status;
569} 582}
@@ -577,24 +590,40 @@ EXPORT_SYMBOL_GPL(wmi_install_notify_handler);
577acpi_status wmi_remove_notify_handler(const char *guid) 590acpi_status wmi_remove_notify_handler(const char *guid)
578{ 591{
579 struct wmi_block *block; 592 struct wmi_block *block;
580 acpi_status status = AE_OK; 593 acpi_status status = AE_NOT_EXIST;
594 char tmp[16], guid_input[16];
595 struct list_head *p;
581 596
582 if (!guid) 597 if (!guid)
583 return AE_BAD_PARAMETER; 598 return AE_BAD_PARAMETER;
584 599
585 if (!find_guid(guid, &block)) 600 wmi_parse_guid(guid, tmp);
586 return AE_NOT_EXIST; 601 wmi_swap_bytes(tmp, guid_input);
587 602
588 if (!block->handler || block->handler == wmi_notify_debug) 603 list_for_each(p, &wmi_block_list) {
589 return AE_NULL_ENTRY; 604 acpi_status wmi_status;
605 block = list_entry(p, struct wmi_block, list);
590 606
591 if (debug_event) { 607 if (memcmp(block->gblock.guid, guid_input, 16) == 0) {
592 block->handler = wmi_notify_debug; 608 if (!block->handler ||
593 } else { 609 block->handler == wmi_notify_debug)
594 status = wmi_method_enable(block, 0); 610 return AE_NULL_ENTRY;
595 block->handler = NULL; 611
596 block->handler_data = NULL; 612 if (debug_event) {
613 block->handler = wmi_notify_debug;
614 status = AE_OK;
615 } else {
616 wmi_status = wmi_method_enable(block, 0);
617 block->handler = NULL;
618 block->handler_data = NULL;
619 if ((wmi_status != AE_OK) ||
620 ((wmi_status == AE_OK) &&
621 (status == AE_NOT_EXIST)))
622 status = wmi_status;
623 }
624 }
597 } 625 }
626
598 return status; 627 return status;
599} 628}
600EXPORT_SYMBOL_GPL(wmi_remove_notify_handler); 629EXPORT_SYMBOL_GPL(wmi_remove_notify_handler);
@@ -705,22 +734,11 @@ static struct class wmi_class = {
705 .dev_attrs = wmi_dev_attrs, 734 .dev_attrs = wmi_dev_attrs,
706}; 735};
707 736
708static struct wmi_block *wmi_create_device(const struct guid_block *gblock, 737static int wmi_create_device(const struct guid_block *gblock,
709 acpi_handle handle) 738 struct wmi_block *wblock, acpi_handle handle)
710{ 739{
711 struct wmi_block *wblock;
712 int error;
713 char guid_string[37]; 740 char guid_string[37];
714 741
715 wblock = kzalloc(sizeof(struct wmi_block), GFP_KERNEL);
716 if (!wblock) {
717 error = -ENOMEM;
718 goto err_out;
719 }
720
721 wblock->handle = handle;
722 wblock->gblock = *gblock;
723
724 wblock->dev.class = &wmi_class; 742 wblock->dev.class = &wmi_class;
725 743
726 wmi_gtoa(gblock->guid, guid_string); 744 wmi_gtoa(gblock->guid, guid_string);
@@ -728,17 +746,7 @@ static struct wmi_block *wmi_create_device(const struct guid_block *gblock,
728 746
729 dev_set_drvdata(&wblock->dev, wblock); 747 dev_set_drvdata(&wblock->dev, wblock);
730 748
731 error = device_register(&wblock->dev); 749 return device_register(&wblock->dev);
732 if (error)
733 goto err_free;
734
735 list_add_tail(&wblock->list, &wmi_block_list);
736 return wblock;
737
738err_free:
739 kfree(wblock);
740err_out:
741 return ERR_PTR(error);
742} 750}
743 751
744static void wmi_free_devices(void) 752static void wmi_free_devices(void)
@@ -747,7 +755,8 @@ static void wmi_free_devices(void)
747 755
748 /* Delete devices for all the GUIDs */ 756 /* Delete devices for all the GUIDs */
749 list_for_each_entry_safe(wblock, next, &wmi_block_list, list) 757 list_for_each_entry_safe(wblock, next, &wmi_block_list, list)
750 device_unregister(&wblock->dev); 758 if (wblock->dev.class)
759 device_unregister(&wblock->dev);
751} 760}
752 761
753static bool guid_already_parsed(const char *guid_string) 762static bool guid_already_parsed(const char *guid_string)
@@ -770,7 +779,6 @@ static acpi_status parse_wdg(acpi_handle handle)
770 union acpi_object *obj; 779 union acpi_object *obj;
771 const struct guid_block *gblock; 780 const struct guid_block *gblock;
772 struct wmi_block *wblock; 781 struct wmi_block *wblock;
773 char guid_string[37];
774 acpi_status status; 782 acpi_status status;
775 int retval; 783 int retval;
776 u32 i, total; 784 u32 i, total;
@@ -792,28 +800,31 @@ static acpi_status parse_wdg(acpi_handle handle)
792 total = obj->buffer.length / sizeof(struct guid_block); 800 total = obj->buffer.length / sizeof(struct guid_block);
793 801
794 for (i = 0; i < total; i++) { 802 for (i = 0; i < total; i++) {
803 if (debug_dump_wdg)
804 wmi_dump_wdg(&gblock[i]);
805
806 wblock = kzalloc(sizeof(struct wmi_block), GFP_KERNEL);
807 if (!wblock)
808 return AE_NO_MEMORY;
809
810 wblock->handle = handle;
811 wblock->gblock = gblock[i];
812
795 /* 813 /*
796 Some WMI devices, like those for nVidia hooks, have a 814 Some WMI devices, like those for nVidia hooks, have a
797 duplicate GUID. It's not clear what we should do in this 815 duplicate GUID. It's not clear what we should do in this
798 case yet, so for now, we'll just ignore the duplicate. 816 case yet, so for now, we'll just ignore the duplicate
799 Anyone who wants to add support for that device can come 817 for device creation.
800 up with a better workaround for the mess then.
801 */ 818 */
802 if (guid_already_parsed(gblock[i].guid) == true) { 819 if (!guid_already_parsed(gblock[i].guid)) {
803 wmi_gtoa(gblock[i].guid, guid_string); 820 retval = wmi_create_device(&gblock[i], wblock, handle);
804 pr_info("Skipping duplicate GUID %s\n", guid_string); 821 if (retval) {
805 continue; 822 wmi_free_devices();
823 goto out_free_pointer;
824 }
806 } 825 }
807 826
808 if (debug_dump_wdg) 827 list_add_tail(&wblock->list, &wmi_block_list);
809 wmi_dump_wdg(&gblock[i]);
810
811 wblock = wmi_create_device(&gblock[i], handle);
812 if (IS_ERR(wblock)) {
813 retval = PTR_ERR(wblock);
814 wmi_free_devices();
815 break;
816 }
817 828
818 if (debug_event) { 829 if (debug_event) {
819 wblock->handler = wmi_notify_debug; 830 wblock->handler = wmi_notify_debug;
diff --git a/include/linux/sonypi.h b/include/linux/sonypi.h
index 4f95c1aac2fd..0e6dc3891942 100644
--- a/include/linux/sonypi.h
+++ b/include/linux/sonypi.h
@@ -112,6 +112,7 @@
112#define SONYPI_EVENT_VOLUME_DEC_PRESSED 70 112#define SONYPI_EVENT_VOLUME_DEC_PRESSED 70
113#define SONYPI_EVENT_BRIGHTNESS_PRESSED 71 113#define SONYPI_EVENT_BRIGHTNESS_PRESSED 71
114#define SONYPI_EVENT_MEDIA_PRESSED 72 114#define SONYPI_EVENT_MEDIA_PRESSED 72
115#define SONYPI_EVENT_VENDOR_PRESSED 73
115 116
116/* get/set brightness */ 117/* get/set brightness */
117#define SONYPI_IOCGBRT _IOR('v', 0, __u8) 118#define SONYPI_IOCGBRT _IOR('v', 0, __u8)