Commit 66a71dd1f7c4eee636867d381995b7e6ae489dc3
1 parent
d0930a2d42
Exists in
master
and in
7 other branches
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>
Showing 2 changed files with 68 additions and 141 deletions Side-by-side Diff
drivers/platform/x86/Kconfig
| ... | ... | @@ -59,6 +59,7 @@ |
| 59 | 59 | select NEW_LEDS |
| 60 | 60 | select BACKLIGHT_CLASS_DEVICE |
| 61 | 61 | depends on INPUT |
| 62 | + select INPUT_SPARSEKMAP | |
| 62 | 63 | ---help--- |
| 63 | 64 | This is the new Linux driver for Asus laptops. It may also support some |
| 64 | 65 | MEDION, JVC or VICTOR laptops. It makes all the extra buttons generate |
drivers/platform/x86/asus-laptop.c
| ... | ... | @@ -49,6 +49,7 @@ |
| 49 | 49 | #include <acpi/acpi_bus.h> |
| 50 | 50 | #include <asm/uaccess.h> |
| 51 | 51 | #include <linux/input.h> |
| 52 | +#include <linux/input/sparse-keymap.h> | |
| 52 | 53 | |
| 53 | 54 | #define ASUS_LAPTOP_VERSION "0.42" |
| 54 | 55 | |
| 55 | 56 | |
| 56 | 57 | |
| ... | ... | @@ -243,52 +244,45 @@ |
| 243 | 244 | u16 *keycode_map; |
| 244 | 245 | }; |
| 245 | 246 | |
| 246 | -struct key_entry { | |
| 247 | - char type; | |
| 248 | - u8 code; | |
| 249 | - u16 keycode; | |
| 250 | -}; | |
| 251 | - | |
| 252 | -enum { KE_KEY, KE_END }; | |
| 253 | - | |
| 254 | 247 | static const struct key_entry asus_keymap[] = { |
| 255 | - {KE_KEY, 0x02, KEY_SCREENLOCK}, | |
| 256 | - {KE_KEY, 0x05, KEY_WLAN}, | |
| 257 | - {KE_KEY, 0x08, KEY_F13}, | |
| 258 | - {KE_KEY, 0x17, KEY_ZOOM}, | |
| 259 | - {KE_KEY, 0x1f, KEY_BATTERY}, | |
| 260 | - {KE_KEY, 0x30, KEY_VOLUMEUP}, | |
| 261 | - {KE_KEY, 0x31, KEY_VOLUMEDOWN}, | |
| 262 | - {KE_KEY, 0x32, KEY_MUTE}, | |
| 263 | - {KE_KEY, 0x33, KEY_SWITCHVIDEOMODE}, | |
| 264 | - {KE_KEY, 0x34, KEY_SWITCHVIDEOMODE}, | |
| 265 | - {KE_KEY, 0x40, KEY_PREVIOUSSONG}, | |
| 266 | - {KE_KEY, 0x41, KEY_NEXTSONG}, | |
| 267 | - {KE_KEY, 0x43, KEY_STOPCD}, | |
| 268 | - {KE_KEY, 0x45, KEY_PLAYPAUSE}, | |
| 269 | - {KE_KEY, 0x4c, KEY_MEDIA}, | |
| 270 | - {KE_KEY, 0x50, KEY_EMAIL}, | |
| 271 | - {KE_KEY, 0x51, KEY_WWW}, | |
| 272 | - {KE_KEY, 0x55, KEY_CALC}, | |
| 273 | - {KE_KEY, 0x5C, KEY_SCREENLOCK}, /* Screenlock */ | |
| 274 | - {KE_KEY, 0x5D, KEY_WLAN}, | |
| 275 | - {KE_KEY, 0x5E, KEY_WLAN}, | |
| 276 | - {KE_KEY, 0x5F, KEY_WLAN}, | |
| 277 | - {KE_KEY, 0x60, KEY_SWITCHVIDEOMODE}, | |
| 278 | - {KE_KEY, 0x61, KEY_SWITCHVIDEOMODE}, | |
| 279 | - {KE_KEY, 0x62, KEY_SWITCHVIDEOMODE}, | |
| 280 | - {KE_KEY, 0x63, KEY_SWITCHVIDEOMODE}, | |
| 281 | - {KE_KEY, 0x6B, KEY_F13}, /* Lock Touchpad */ | |
| 282 | - {KE_KEY, 0x82, KEY_CAMERA}, | |
| 283 | - {KE_KEY, 0x88, KEY_WLAN }, | |
| 284 | - {KE_KEY, 0x8A, KEY_PROG1}, | |
| 285 | - {KE_KEY, 0x95, KEY_MEDIA}, | |
| 286 | - {KE_KEY, 0x99, KEY_PHONE}, | |
| 287 | - {KE_KEY, 0xc4, KEY_KBDILLUMUP}, | |
| 288 | - {KE_KEY, 0xc5, KEY_KBDILLUMDOWN}, | |
| 248 | + {KE_KEY, 0x02, { KEY_SCREENLOCK } }, | |
| 249 | + {KE_KEY, 0x05, { KEY_WLAN } }, | |
| 250 | + {KE_KEY, 0x08, { KEY_F13 } }, | |
| 251 | + {KE_KEY, 0x17, { KEY_ZOOM } }, | |
| 252 | + {KE_KEY, 0x1f, { KEY_BATTERY } }, | |
| 253 | + {KE_KEY, 0x30, { KEY_VOLUMEUP } }, | |
| 254 | + {KE_KEY, 0x31, { KEY_VOLUMEDOWN } }, | |
| 255 | + {KE_KEY, 0x32, { KEY_MUTE } }, | |
| 256 | + {KE_KEY, 0x33, { KEY_SWITCHVIDEOMODE } }, | |
| 257 | + {KE_KEY, 0x34, { KEY_SWITCHVIDEOMODE } }, | |
| 258 | + {KE_KEY, 0x40, { KEY_PREVIOUSSONG } }, | |
| 259 | + {KE_KEY, 0x41, { KEY_NEXTSONG } }, | |
| 260 | + {KE_KEY, 0x43, { KEY_STOPCD } }, | |
| 261 | + {KE_KEY, 0x45, { KEY_PLAYPAUSE } }, | |
| 262 | + {KE_KEY, 0x4c, { KEY_MEDIA } }, | |
| 263 | + {KE_KEY, 0x50, { KEY_EMAIL } }, | |
| 264 | + {KE_KEY, 0x51, { KEY_WWW } }, | |
| 265 | + {KE_KEY, 0x55, { KEY_CALC } }, | |
| 266 | + {KE_KEY, 0x5C, { KEY_SCREENLOCK } }, /* Screenlock */ | |
| 267 | + {KE_KEY, 0x5D, { KEY_WLAN } }, | |
| 268 | + {KE_KEY, 0x5E, { KEY_WLAN } }, | |
| 269 | + {KE_KEY, 0x5F, { KEY_WLAN } }, | |
| 270 | + {KE_KEY, 0x60, { KEY_SWITCHVIDEOMODE } }, | |
| 271 | + {KE_KEY, 0x61, { KEY_SWITCHVIDEOMODE } }, | |
| 272 | + {KE_KEY, 0x62, { KEY_SWITCHVIDEOMODE } }, | |
| 273 | + {KE_KEY, 0x63, { KEY_SWITCHVIDEOMODE } }, | |
| 274 | + {KE_KEY, 0x6B, { KEY_F13 } }, /* Lock Touchpad */ | |
| 275 | + {KE_KEY, 0x82, { KEY_CAMERA } }, | |
| 276 | + {KE_KEY, 0x88, { KEY_WLAN } }, | |
| 277 | + {KE_KEY, 0x8A, { KEY_PROG1 } }, | |
| 278 | + {KE_KEY, 0x95, { KEY_MEDIA } }, | |
| 279 | + {KE_KEY, 0x99, { KEY_PHONE } }, | |
| 280 | + {KE_KEY, 0xc4, { KEY_KBDILLUMUP } }, | |
| 281 | + {KE_KEY, 0xc5, { KEY_KBDILLUMDOWN } }, | |
| 289 | 282 | {KE_END, 0}, |
| 290 | 283 | }; |
| 291 | 284 | |
| 285 | + | |
| 292 | 286 | /* |
| 293 | 287 | * This function evaluates an ACPI method, given an int as parameter, the |
| 294 | 288 | * method is searched within the scope of the handle, can be NULL. The output |
| 295 | 289 | |
| 296 | 290 | |
| 297 | 291 | |
| 298 | 292 | |
| 299 | 293 | |
| 300 | 294 | |
| 301 | 295 | |
| 302 | 296 | |
| 303 | 297 | |
| 304 | 298 | |
| ... | ... | @@ -1050,123 +1044,55 @@ |
| 1050 | 1044 | /* |
| 1051 | 1045 | * Input device (i.e. hotkeys) |
| 1052 | 1046 | */ |
| 1053 | -static 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 | - | |
| 1065 | -static 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 | - | |
| 1077 | -static 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 | - | |
| 1090 | -static 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 | - | |
| 1112 | 1047 | static void asus_input_notify(struct asus_laptop *asus, int event) |
| 1113 | 1048 | { |
| 1114 | - struct key_entry *key; | |
| 1115 | - | |
| 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 | - } | |
| 1049 | + if (asus->inputdev) | |
| 1050 | + sparse_keymap_report_event(asus->inputdev, event, 1, true); | |
| 1128 | 1051 | } |
| 1129 | 1052 | |
| 1130 | 1053 | static int asus_input_init(struct asus_laptop *asus) |
| 1131 | 1054 | { |
| 1132 | - const struct key_entry *key; | |
| 1133 | - int result; | |
| 1055 | + struct input_dev *input; | |
| 1056 | + int error; | |
| 1134 | 1057 | |
| 1135 | - asus->inputdev = input_allocate_device(); | |
| 1136 | - if (!asus->inputdev) { | |
| 1058 | + input = input_allocate_device(); | |
| 1059 | + if (!input) { | |
| 1137 | 1060 | pr_info("Unable to allocate input device\n"); |
| 1138 | 1061 | return 0; |
| 1139 | 1062 | } |
| 1140 | - asus->inputdev->name = "Asus Laptop extra buttons"; | |
| 1141 | - asus->inputdev->dev.parent = &asus->platform_device->dev; | |
| 1142 | - asus->inputdev->phys = ASUS_LAPTOP_FILE "/input0"; | |
| 1143 | - asus->inputdev->id.bustype = BUS_HOST; | |
| 1144 | - asus->inputdev->getkeycode = asus_getkeycode; | |
| 1145 | - asus->inputdev->setkeycode = asus_setkeycode; | |
| 1146 | - input_set_drvdata(asus->inputdev, asus); | |
| 1063 | + input->name = "Asus Laptop extra buttons"; | |
| 1064 | + input->phys = ASUS_LAPTOP_FILE "/input0"; | |
| 1065 | + input->id.bustype = BUS_HOST; | |
| 1066 | + input->dev.parent = &asus->platform_device->dev; | |
| 1067 | + input_set_drvdata(input, asus); | |
| 1147 | 1068 | |
| 1148 | - asus->keymap = kmemdup(asus_keymap, sizeof(asus_keymap), | |
| 1149 | - GFP_KERNEL); | |
| 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 | - } | |
| 1069 | + error = sparse_keymap_setup(input, asus_keymap, NULL); | |
| 1070 | + if (error) { | |
| 1071 | + pr_err("Unable to setup input device keymap\n"); | |
| 1072 | + goto err_keymap; | |
| 1157 | 1073 | } |
| 1158 | - result = input_register_device(asus->inputdev); | |
| 1159 | - if (result) { | |
| 1074 | + error = input_register_device(input); | |
| 1075 | + if (error) { | |
| 1160 | 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 | + | |
| 1083 | +err_keymap: | |
| 1084 | + sparse_keymap_free(input); | |
| 1085 | +err_device: | |
| 1086 | + input_free_device(input); | |
| 1087 | + return error; | |
| 1164 | 1088 | } |
| 1165 | 1089 | |
| 1166 | 1090 | static 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 | 1094 | input_unregister_device(asus->inputdev); |
| 1095 | + } | |
| 1170 | 1096 | } |
| 1171 | 1097 | |
| 1172 | 1098 | /* |