diff options
-rw-r--r-- | drivers/platform/x86/Kconfig | 1 | ||||
-rw-r--r-- | drivers/platform/x86/asus-laptop.c | 208 |
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 | ||
246 | struct key_entry { | ||
247 | char type; | ||
248 | u8 code; | ||
249 | u16 keycode; | ||
250 | }; | ||
251 | |||
252 | enum { KE_KEY, KE_END }; | ||
253 | |||
254 | static const struct key_entry asus_keymap[] = { | 247 | static 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 | */ |
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 | static void asus_input_notify(struct asus_laptop *asus, int event) | 1047 | static 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 | ||
1130 | static int asus_input_init(struct asus_laptop *asus) | 1053 | static 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 | |||
1083 | err_keymap: | ||
1084 | sparse_keymap_free(input); | ||
1085 | err_device: | ||
1086 | input_free_device(input); | ||
1087 | return error; | ||
1164 | } | 1088 | } |
1165 | 1089 | ||
1166 | static void asus_input_exit(struct asus_laptop *asus) | 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 | input_unregister_device(asus->inputdev); | 1094 | input_unregister_device(asus->inputdev); |
1095 | } | ||
1170 | } | 1096 | } |
1171 | 1097 | ||
1172 | /* | 1098 | /* |