aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/platform/x86
diff options
context:
space:
mode:
authorLee, Chun-Yi <joeyli.kernel@gmail.com>2010-12-06 21:29:20 -0500
committerMatthew Garrett <mjg@redhat.com>2011-01-07 17:03:47 -0500
commit3fdca87d10f1d45b1c034da343e68beb082f9b84 (patch)
treed22ecdf62d93a3e67c6830574b7d0c3eba84a827 /drivers/platform/x86
parente98062ed6dc46ed3270350e1040e19d44150d1d1 (diff)
acer-wmi: Add acer wmi hotkey events support
Add acer wmi hotkey event support. Install a wmi notify handler to transfer wmi event key to key code, then send out keycode through acer wmi input device to userland. Signed-off-by: Lee, Chun-Yi <jlee@novell.com> Acked-by: Dmitry Torokhov <dtor@mail.ru> Acked-by: Thomas Renninger <trenn@suse.de> Acked-by: Jiri Benc <jbenc@suse.cz> Signed-off-by: Carlos Corbacho <carlos@strangeworlds.co.uk> Cc: Corentin Chary <corentincj@iksaif.net> Signed-off-by: Matthew Garrett <mjg@redhat.com>
Diffstat (limited to 'drivers/platform/x86')
-rw-r--r--drivers/platform/x86/Kconfig2
-rw-r--r--drivers/platform/x86/acer-wmi.c139
2 files changed, 141 insertions, 0 deletions
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index fbee997d2c24..a122a0dac981 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -22,8 +22,10 @@ config ACER_WMI
22 depends on NEW_LEDS 22 depends on 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 depends on 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,
diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c
index c8c65375bfe2..a1c6141f463b 100644
--- a/drivers/platform/x86/acer-wmi.c
+++ b/drivers/platform/x86/acer-wmi.c
@@ -37,6 +37,8 @@
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>
40 42
41#include <acpi/acpi_drivers.h> 43#include <acpi/acpi_drivers.h>
42 44
@@ -48,6 +50,7 @@ MODULE_LICENSE("GPL");
48#define ACER_ERR KERN_ERR ACER_LOGPREFIX 50#define ACER_ERR KERN_ERR ACER_LOGPREFIX
49#define ACER_NOTICE KERN_NOTICE ACER_LOGPREFIX 51#define ACER_NOTICE KERN_NOTICE ACER_LOGPREFIX
50#define ACER_INFO KERN_INFO ACER_LOGPREFIX 52#define ACER_INFO KERN_INFO ACER_LOGPREFIX
53#define ACER_WARNING KERN_WARNING ACER_LOGPREFIX
51 54
52/* 55/*
53 * Magic Number 56 * Magic Number
@@ -83,8 +86,39 @@ MODULE_LICENSE("GPL");
83#define WMID_GUID1 "6AF4F258-B401-42fd-BE91-3D4AC2D7C0D3" 86#define WMID_GUID1 "6AF4F258-B401-42fd-BE91-3D4AC2D7C0D3"
84#define WMID_GUID2 "95764E09-FB56-4e83-B31A-37761F60994A" 87#define WMID_GUID2 "95764E09-FB56-4e83-B31A-37761F60994A"
85 88
89/*
90 * Acer ACPI event GUIDs
91 */
92#define ACERWMID_EVENT_GUID "676AA15E-6A47-4D9F-A2CC-1E6D18D14026"
93
86MODULE_ALIAS("wmi:67C3371D-95A3-4C37-BB61-DD47B491DAAB"); 94MODULE_ALIAS("wmi:67C3371D-95A3-4C37-BB61-DD47B491DAAB");
87MODULE_ALIAS("wmi:6AF4F258-B401-42fd-BE91-3D4AC2D7C0D3"); 95MODULE_ALIAS("wmi:6AF4F258-B401-42fd-BE91-3D4AC2D7C0D3");
96MODULE_ALIAS("wmi:676AA15E-6A47-4D9F-A2CC-1E6D18D14026");
97
98enum acer_wmi_event_ids {
99 WMID_HOTKEY_EVENT = 0x1,
100};
101
102static const struct key_entry acer_wmi_keymap[] = {
103 {KE_KEY, 0x01, {KEY_WLAN} }, /* WiFi */
104 {KE_KEY, 0x12, {KEY_BLUETOOTH} }, /* BT */
105 {KE_KEY, 0x21, {KEY_PROG1} }, /* Backup */
106 {KE_KEY, 0x22, {KEY_PROG2} }, /* Arcade */
107 {KE_KEY, 0x23, {KEY_PROG3} }, /* P_Key */
108 {KE_KEY, 0x24, {KEY_PROG4} }, /* Social networking_Key */
109 {KE_KEY, 0x64, {KEY_SWITCHVIDEOMODE} }, /* Display Switch */
110 {KE_KEY, 0x82, {KEY_F22} }, /* Touch Pad On/Off */
111 {KE_END, 0}
112};
113
114static struct input_dev *acer_wmi_input_dev;
115
116struct event_return_value {
117 u8 function;
118 u8 key_num;
119 u16 device_state;
120 u32 reserved;
121} __attribute__((packed));
88 122
89/* 123/*
90 * Interface capability flags 124 * Interface capability flags
@@ -1085,6 +1119,99 @@ static ssize_t show_interface(struct device *dev, struct device_attribute *attr,
1085 1119
1086static DEVICE_ATTR(interface, S_IRUGO, show_interface, NULL); 1120static DEVICE_ATTR(interface, S_IRUGO, show_interface, NULL);
1087 1121
1122static void acer_wmi_notify(u32 value, void *context)
1123{
1124 struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL };
1125 union acpi_object *obj;
1126 struct event_return_value return_value;
1127 acpi_status status;
1128
1129 status = wmi_get_event_data(value, &response);
1130 if (status != AE_OK) {
1131 printk(ACER_WARNING "bad event status 0x%x\n", status);
1132 return;
1133 }
1134
1135 obj = (union acpi_object *)response.pointer;
1136
1137 if (!obj)
1138 return;
1139 if (obj->type != ACPI_TYPE_BUFFER) {
1140 printk(ACER_WARNING "Unknown response received %d\n",
1141 obj->type);
1142 kfree(obj);
1143 return;
1144 }
1145 if (obj->buffer.length != 8) {
1146 printk(ACER_WARNING "Unknown buffer length %d\n",
1147 obj->buffer.length);
1148 kfree(obj);
1149 return;
1150 }
1151
1152 return_value = *((struct event_return_value *)obj->buffer.pointer);
1153 kfree(obj);
1154
1155 switch (return_value.function) {
1156 case WMID_HOTKEY_EVENT:
1157 if (!sparse_keymap_report_event(acer_wmi_input_dev,
1158 return_value.key_num, 1, true))
1159 printk(ACER_WARNING "Unknown key number - 0x%x\n",
1160 return_value.key_num);
1161 break;
1162 default:
1163 printk(ACER_WARNING "Unknown function number - %d - %d\n",
1164 return_value.function, return_value.key_num);
1165 break;
1166 }
1167}
1168
1169static int __init acer_wmi_input_setup(void)
1170{
1171 acpi_status status;
1172 int err;
1173
1174 acer_wmi_input_dev = input_allocate_device();
1175 if (!acer_wmi_input_dev)
1176 return -ENOMEM;
1177
1178 acer_wmi_input_dev->name = "Acer WMI hotkeys";
1179 acer_wmi_input_dev->phys = "wmi/input0";
1180 acer_wmi_input_dev->id.bustype = BUS_HOST;
1181
1182 err = sparse_keymap_setup(acer_wmi_input_dev, acer_wmi_keymap, NULL);
1183 if (err)
1184 goto err_free_dev;
1185
1186 status = wmi_install_notify_handler(ACERWMID_EVENT_GUID,
1187 acer_wmi_notify, NULL);
1188 if (ACPI_FAILURE(status)) {
1189 err = -EIO;
1190 goto err_free_keymap;
1191 }
1192
1193 err = input_register_device(acer_wmi_input_dev);
1194 if (err)
1195 goto err_uninstall_notifier;
1196
1197 return 0;
1198
1199err_uninstall_notifier:
1200 wmi_remove_notify_handler(ACERWMID_EVENT_GUID);
1201err_free_keymap:
1202 sparse_keymap_free(acer_wmi_input_dev);
1203err_free_dev:
1204 input_free_device(acer_wmi_input_dev);
1205 return err;
1206}
1207
1208static void acer_wmi_input_destroy(void)
1209{
1210 wmi_remove_notify_handler(ACERWMID_EVENT_GUID);
1211 sparse_keymap_free(acer_wmi_input_dev);
1212 input_unregister_device(acer_wmi_input_dev);
1213}
1214
1088/* 1215/*
1089 * debugfs functions 1216 * debugfs functions
1090 */ 1217 */
@@ -1327,6 +1454,12 @@ static int __init acer_wmi_init(void)
1327 "generic video driver\n"); 1454 "generic video driver\n");
1328 } 1455 }
1329 1456
1457 if (wmi_has_guid(ACERWMID_EVENT_GUID)) {
1458 err = acer_wmi_input_setup();
1459 if (err)
1460 return err;
1461 }
1462
1330 err = platform_driver_register(&acer_platform_driver); 1463 err = platform_driver_register(&acer_platform_driver);
1331 if (err) { 1464 if (err) {
1332 printk(ACER_ERR "Unable to register platform driver.\n"); 1465 printk(ACER_ERR "Unable to register platform driver.\n");
@@ -1368,11 +1501,17 @@ error_device_add:
1368error_device_alloc: 1501error_device_alloc:
1369 platform_driver_unregister(&acer_platform_driver); 1502 platform_driver_unregister(&acer_platform_driver);
1370error_platform_register: 1503error_platform_register:
1504 if (wmi_has_guid(ACERWMID_EVENT_GUID))
1505 acer_wmi_input_destroy();
1506
1371 return err; 1507 return err;
1372} 1508}
1373 1509
1374static void __exit acer_wmi_exit(void) 1510static void __exit acer_wmi_exit(void)
1375{ 1511{
1512 if (wmi_has_guid(ACERWMID_EVENT_GUID))
1513 acer_wmi_input_destroy();
1514
1376 remove_sysfs(acer_platform_device); 1515 remove_sysfs(acer_platform_device);
1377 remove_debugfs(); 1516 remove_debugfs();
1378 platform_device_unregister(acer_platform_device); 1517 platform_device_unregister(acer_platform_device);