aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/platform/x86/asus-laptop.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/platform/x86/asus-laptop.c')
-rw-r--r--drivers/platform/x86/asus-laptop.c208
1 files changed, 67 insertions, 141 deletions
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/*