aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCorentin Chary <corentincj@iksaif.net>2010-01-25 16:50:11 -0500
committerCorentin Chary <corentincj@iksaif.net>2010-02-28 13:35:12 -0500
commit66a71dd1f7c4eee636867d381995b7e6ae489dc3 (patch)
treed628bb783696c10dd5604ec8efff2b7eb6fa98ad
parentd0930a2d42c5a28039d8cc2376a7dff4e59c5f7a (diff)
asus-laptop: switch to sparse keymap library
This patch is based on Dmitry Torokhov's patch with some modifications and cleanups. Signed-off-by: Corentin Chary <corentincj@iksaif.net>
-rw-r--r--drivers/platform/x86/Kconfig1
-rw-r--r--drivers/platform/x86/asus-laptop.c208
2 files changed, 68 insertions, 141 deletions
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index f526e735c5ab..7f5a222c2325 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -59,6 +59,7 @@ config ASUS_LAPTOP
59 select NEW_LEDS 59 select NEW_LEDS
60 select BACKLIGHT_CLASS_DEVICE 60 select BACKLIGHT_CLASS_DEVICE
61 depends on INPUT 61 depends on INPUT
62 select INPUT_SPARSEKMAP
62 ---help--- 63 ---help---
63 This is the new Linux driver for Asus laptops. It may also support some 64 This is the new Linux driver for Asus laptops. It may also support some
64 MEDION, JVC or VICTOR laptops. It makes all the extra buttons generate 65 MEDION, JVC or VICTOR laptops. It makes all the extra buttons generate
diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c
index bb8fb45c45e9..8042568528e5 100644
--- a/drivers/platform/x86/asus-laptop.c
+++ b/drivers/platform/x86/asus-laptop.c
@@ -49,6 +49,7 @@
49#include <acpi/acpi_bus.h> 49#include <acpi/acpi_bus.h>
50#include <asm/uaccess.h> 50#include <asm/uaccess.h>
51#include <linux/input.h> 51#include <linux/input.h>
52#include <linux/input/sparse-keymap.h>
52 53
53#define ASUS_LAPTOP_VERSION "0.42" 54#define ASUS_LAPTOP_VERSION "0.42"
54 55
@@ -243,52 +244,45 @@ struct asus_laptop {
243 u16 *keycode_map; 244 u16 *keycode_map;
244}; 245};
245 246
246struct key_entry {
247 char type;
248 u8 code;
249 u16 keycode;
250};
251
252enum { KE_KEY, KE_END };
253
254static const struct key_entry asus_keymap[] = { 247static const struct key_entry asus_keymap[] = {
255 {KE_KEY, 0x02, KEY_SCREENLOCK}, 248 {KE_KEY, 0x02, { KEY_SCREENLOCK } },
256 {KE_KEY, 0x05, KEY_WLAN}, 249 {KE_KEY, 0x05, { KEY_WLAN } },
257 {KE_KEY, 0x08, KEY_F13}, 250 {KE_KEY, 0x08, { KEY_F13 } },
258 {KE_KEY, 0x17, KEY_ZOOM}, 251 {KE_KEY, 0x17, { KEY_ZOOM } },
259 {KE_KEY, 0x1f, KEY_BATTERY}, 252 {KE_KEY, 0x1f, { KEY_BATTERY } },
260 {KE_KEY, 0x30, KEY_VOLUMEUP}, 253 {KE_KEY, 0x30, { KEY_VOLUMEUP } },
261 {KE_KEY, 0x31, KEY_VOLUMEDOWN}, 254 {KE_KEY, 0x31, { KEY_VOLUMEDOWN } },
262 {KE_KEY, 0x32, KEY_MUTE}, 255 {KE_KEY, 0x32, { KEY_MUTE } },
263 {KE_KEY, 0x33, KEY_SWITCHVIDEOMODE}, 256 {KE_KEY, 0x33, { KEY_SWITCHVIDEOMODE } },
264 {KE_KEY, 0x34, KEY_SWITCHVIDEOMODE}, 257 {KE_KEY, 0x34, { KEY_SWITCHVIDEOMODE } },
265 {KE_KEY, 0x40, KEY_PREVIOUSSONG}, 258 {KE_KEY, 0x40, { KEY_PREVIOUSSONG } },
266 {KE_KEY, 0x41, KEY_NEXTSONG}, 259 {KE_KEY, 0x41, { KEY_NEXTSONG } },
267 {KE_KEY, 0x43, KEY_STOPCD}, 260 {KE_KEY, 0x43, { KEY_STOPCD } },
268 {KE_KEY, 0x45, KEY_PLAYPAUSE}, 261 {KE_KEY, 0x45, { KEY_PLAYPAUSE } },
269 {KE_KEY, 0x4c, KEY_MEDIA}, 262 {KE_KEY, 0x4c, { KEY_MEDIA } },
270 {KE_KEY, 0x50, KEY_EMAIL}, 263 {KE_KEY, 0x50, { KEY_EMAIL } },
271 {KE_KEY, 0x51, KEY_WWW}, 264 {KE_KEY, 0x51, { KEY_WWW } },
272 {KE_KEY, 0x55, KEY_CALC}, 265 {KE_KEY, 0x55, { KEY_CALC } },
273 {KE_KEY, 0x5C, KEY_SCREENLOCK}, /* Screenlock */ 266 {KE_KEY, 0x5C, { KEY_SCREENLOCK } }, /* Screenlock */
274 {KE_KEY, 0x5D, KEY_WLAN}, 267 {KE_KEY, 0x5D, { KEY_WLAN } },
275 {KE_KEY, 0x5E, KEY_WLAN}, 268 {KE_KEY, 0x5E, { KEY_WLAN } },
276 {KE_KEY, 0x5F, KEY_WLAN}, 269 {KE_KEY, 0x5F, { KEY_WLAN } },
277 {KE_KEY, 0x60, KEY_SWITCHVIDEOMODE}, 270 {KE_KEY, 0x60, { KEY_SWITCHVIDEOMODE } },
278 {KE_KEY, 0x61, KEY_SWITCHVIDEOMODE}, 271 {KE_KEY, 0x61, { KEY_SWITCHVIDEOMODE } },
279 {KE_KEY, 0x62, KEY_SWITCHVIDEOMODE}, 272 {KE_KEY, 0x62, { KEY_SWITCHVIDEOMODE } },
280 {KE_KEY, 0x63, KEY_SWITCHVIDEOMODE}, 273 {KE_KEY, 0x63, { KEY_SWITCHVIDEOMODE } },
281 {KE_KEY, 0x6B, KEY_F13}, /* Lock Touchpad */ 274 {KE_KEY, 0x6B, { KEY_F13 } }, /* Lock Touchpad */
282 {KE_KEY, 0x82, KEY_CAMERA}, 275 {KE_KEY, 0x82, { KEY_CAMERA } },
283 {KE_KEY, 0x88, KEY_WLAN }, 276 {KE_KEY, 0x88, { KEY_WLAN } },
284 {KE_KEY, 0x8A, KEY_PROG1}, 277 {KE_KEY, 0x8A, { KEY_PROG1 } },
285 {KE_KEY, 0x95, KEY_MEDIA}, 278 {KE_KEY, 0x95, { KEY_MEDIA } },
286 {KE_KEY, 0x99, KEY_PHONE}, 279 {KE_KEY, 0x99, { KEY_PHONE } },
287 {KE_KEY, 0xc4, KEY_KBDILLUMUP}, 280 {KE_KEY, 0xc4, { KEY_KBDILLUMUP } },
288 {KE_KEY, 0xc5, KEY_KBDILLUMDOWN}, 281 {KE_KEY, 0xc5, { KEY_KBDILLUMDOWN } },
289 {KE_END, 0}, 282 {KE_END, 0},
290}; 283};
291 284
285
292/* 286/*
293 * This function evaluates an ACPI method, given an int as parameter, the 287 * This function evaluates an ACPI method, given an int as parameter, the
294 * method is searched within the scope of the handle, can be NULL. The output 288 * method is searched within the scope of the handle, can be NULL. The output
@@ -1050,123 +1044,55 @@ static ssize_t store_gps(struct device *dev, struct device_attribute *attr,
1050/* 1044/*
1051 * Input device (i.e. hotkeys) 1045 * Input device (i.e. hotkeys)
1052 */ 1046 */
1053static struct key_entry *asus_get_entry_by_scancode(struct asus_laptop *asus,
1054 int code)
1055{
1056 struct key_entry *key;
1057
1058 for (key = asus->keymap; key->type != KE_END; key++)
1059 if (code == key->code)
1060 return key;
1061
1062 return NULL;
1063}
1064
1065static struct key_entry *asus_get_entry_by_keycode(struct asus_laptop *asus,
1066 int code)
1067{
1068 struct key_entry *key;
1069
1070 for (key = asus->keymap; key->type != KE_END; key++)
1071 if (code == key->keycode && key->type == KE_KEY)
1072 return key;
1073
1074 return NULL;
1075}
1076
1077static int asus_getkeycode(struct input_dev *dev, int scancode, int *keycode)
1078{
1079 struct asus_laptop *asus = input_get_drvdata(dev);
1080 struct key_entry *key = asus_get_entry_by_scancode(asus, scancode);
1081
1082 if (key && key->type == KE_KEY) {
1083 *keycode = key->keycode;
1084 return 0;
1085 }
1086
1087 return -EINVAL;
1088}
1089
1090static int asus_setkeycode(struct input_dev *dev, int scancode, int keycode)
1091{
1092 struct asus_laptop *asus = input_get_drvdata(dev);
1093 struct key_entry *key;
1094 int old_keycode;
1095
1096 if (keycode < 0 || keycode > KEY_MAX)
1097 return -EINVAL;
1098
1099 key = asus_get_entry_by_scancode(asus, scancode);
1100 if (key && key->type == KE_KEY) {
1101 old_keycode = key->keycode;
1102 key->keycode = keycode;
1103 set_bit(keycode, dev->keybit);
1104 if (!asus_get_entry_by_keycode(asus, old_keycode))
1105 clear_bit(old_keycode, dev->keybit);
1106 return 0;
1107 }
1108
1109 return -EINVAL;
1110}
1111
1112static void asus_input_notify(struct asus_laptop *asus, int event) 1047static void asus_input_notify(struct asus_laptop *asus, int event)
1113{ 1048{
1114 struct key_entry *key; 1049 if (asus->inputdev)
1115 1050 sparse_keymap_report_event(asus->inputdev, event, 1, true);
1116 key = asus_get_entry_by_scancode(asus, event);
1117 if (!key)
1118 return ;
1119
1120 switch (key->type) {
1121 case KE_KEY:
1122 input_report_key(asus->inputdev, key->keycode, 1);
1123 input_sync(asus->inputdev);
1124 input_report_key(asus->inputdev, key->keycode, 0);
1125 input_sync(asus->inputdev);
1126 break;
1127 }
1128} 1051}
1129 1052
1130static int asus_input_init(struct asus_laptop *asus) 1053static int asus_input_init(struct asus_laptop *asus)
1131{ 1054{
1132 const struct key_entry *key; 1055 struct input_dev *input;
1133 int result; 1056 int error;
1134 1057
1135 asus->inputdev = input_allocate_device(); 1058 input = input_allocate_device();
1136 if (!asus->inputdev) { 1059 if (!input) {
1137 pr_info("Unable to allocate input device\n"); 1060 pr_info("Unable to allocate input device\n");
1138 return 0; 1061 return 0;
1139 } 1062 }
1140 asus->inputdev->name = "Asus Laptop extra buttons"; 1063 input->name = "Asus Laptop extra buttons";
1141 asus->inputdev->dev.parent = &asus->platform_device->dev; 1064 input->phys = ASUS_LAPTOP_FILE "/input0";
1142 asus->inputdev->phys = ASUS_LAPTOP_FILE "/input0"; 1065 input->id.bustype = BUS_HOST;
1143 asus->inputdev->id.bustype = BUS_HOST; 1066 input->dev.parent = &asus->platform_device->dev;
1144 asus->inputdev->getkeycode = asus_getkeycode; 1067 input_set_drvdata(input, asus);
1145 asus->inputdev->setkeycode = asus_setkeycode; 1068
1146 input_set_drvdata(asus->inputdev, asus); 1069 error = sparse_keymap_setup(input, asus_keymap, NULL);
1147 1070 if (error) {
1148 asus->keymap = kmemdup(asus_keymap, sizeof(asus_keymap), 1071 pr_err("Unable to setup input device keymap\n");
1149 GFP_KERNEL); 1072 goto err_keymap;
1150 for (key = asus->keymap; key->type != KE_END; key++) {
1151 switch (key->type) {
1152 case KE_KEY:
1153 set_bit(EV_KEY, asus->inputdev->evbit);
1154 set_bit(key->keycode, asus->inputdev->keybit);
1155 break;
1156 }
1157 } 1073 }
1158 result = input_register_device(asus->inputdev); 1074 error = input_register_device(input);
1159 if (result) { 1075 if (error) {
1160 pr_info("Unable to register input device\n"); 1076 pr_info("Unable to register input device\n");
1161 input_free_device(asus->inputdev); 1077 goto err_device;
1162 } 1078 }
1163 return result; 1079
1080 asus->inputdev = input;
1081 return 0;
1082
1083err_keymap:
1084 sparse_keymap_free(input);
1085err_device:
1086 input_free_device(input);
1087 return error;
1164} 1088}
1165 1089
1166static void asus_input_exit(struct asus_laptop *asus) 1090static void asus_input_exit(struct asus_laptop *asus)
1167{ 1091{
1168 if (asus->inputdev) 1092 if (asus->inputdev) {
1093 sparse_keymap_free(asus->inputdev);
1169 input_unregister_device(asus->inputdev); 1094 input_unregister_device(asus->inputdev);
1095 }
1170} 1096}
1171 1097
1172/* 1098/*