diff options
| author | Corentin Chary <corentincj@iksaif.net> | 2009-01-20 10:17:43 -0500 |
|---|---|---|
| committer | Len Brown <len.brown@intel.com> | 2009-01-20 14:35:06 -0500 |
| commit | 034ce90a8d1051deaeb31bae7f26ff1440a5b988 (patch) | |
| tree | 3d22036fe7bf5a0cae4206c34efdada7c5d3fcd8 | |
| parent | 2a7dc0d8c60325e9bf820900bf919430e5a419ab (diff) | |
asus-laptop: hotkeys via the generic input interface
This patch is based on eeepc-laptop.c and the patchs
from Nicolas Trangez and Daniel Nascimento (mainly for the keymap).
Signed-off-by: Corentin Chary <corentincj@iksaif.net>
Signed-off-by: Len Brown <len.brown@intel.com>
| -rw-r--r-- | drivers/platform/x86/asus-laptop.c | 155 |
1 files changed, 154 insertions, 1 deletions
diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c index 1b7a28c1da73..53dbfb420627 100644 --- a/drivers/platform/x86/asus-laptop.c +++ b/drivers/platform/x86/asus-laptop.c | |||
| @@ -46,6 +46,7 @@ | |||
| 46 | #include <acpi/acpi_drivers.h> | 46 | #include <acpi/acpi_drivers.h> |
| 47 | #include <acpi/acpi_bus.h> | 47 | #include <acpi/acpi_bus.h> |
| 48 | #include <asm/uaccess.h> | 48 | #include <asm/uaccess.h> |
| 49 | #include <linux/input.h> | ||
| 49 | 50 | ||
| 50 | #define ASUS_LAPTOP_VERSION "0.42" | 51 | #define ASUS_LAPTOP_VERSION "0.42" |
| 51 | 52 | ||
| @@ -181,6 +182,8 @@ struct asus_hotk { | |||
| 181 | u8 light_level; //light sensor level | 182 | u8 light_level; //light sensor level |
| 182 | u8 light_switch; //light sensor switch value | 183 | u8 light_switch; //light sensor switch value |
| 183 | u16 event_count[128]; //count for each event TODO make this better | 184 | u16 event_count[128]; //count for each event TODO make this better |
| 185 | struct input_dev *inputdev; | ||
| 186 | u16 *keycode_map; | ||
| 184 | }; | 187 | }; |
| 185 | 188 | ||
| 186 | /* | 189 | /* |
| @@ -250,6 +253,37 @@ ASUS_LED(rled, "record"); | |||
| 250 | ASUS_LED(pled, "phone"); | 253 | ASUS_LED(pled, "phone"); |
| 251 | ASUS_LED(gled, "gaming"); | 254 | ASUS_LED(gled, "gaming"); |
| 252 | 255 | ||
| 256 | struct key_entry { | ||
| 257 | char type; | ||
| 258 | u8 code; | ||
| 259 | u16 keycode; | ||
| 260 | }; | ||
| 261 | |||
| 262 | enum { KE_KEY, KE_END }; | ||
| 263 | |||
| 264 | static struct key_entry asus_keymap[] = { | ||
| 265 | {KE_KEY, 0x30, KEY_VOLUMEUP}, | ||
| 266 | {KE_KEY, 0x31, KEY_VOLUMEDOWN}, | ||
| 267 | {KE_KEY, 0x32, KEY_MUTE}, | ||
| 268 | {KE_KEY, 0x33, KEY_SWITCHVIDEOMODE}, | ||
| 269 | {KE_KEY, 0x34, KEY_SWITCHVIDEOMODE}, | ||
| 270 | {KE_KEY, 0x40, KEY_PREVIOUSSONG}, | ||
| 271 | {KE_KEY, 0x41, KEY_NEXTSONG}, | ||
| 272 | {KE_KEY, 0x43, KEY_STOP}, | ||
| 273 | {KE_KEY, 0x45, KEY_PLAYPAUSE}, | ||
| 274 | {KE_KEY, 0x50, KEY_EMAIL}, | ||
| 275 | {KE_KEY, 0x51, KEY_WWW}, | ||
| 276 | {KE_KEY, 0x5C, BTN_EXTRA}, /* Performance */ | ||
| 277 | {KE_KEY, 0x5D, KEY_WLAN}, | ||
| 278 | {KE_KEY, 0x61, KEY_SWITCHVIDEOMODE}, | ||
| 279 | {KE_KEY, 0x6B, BTN_TOUCH}, /* Lock Mouse */ | ||
| 280 | {KE_KEY, 0x82, KEY_CAMERA}, | ||
| 281 | {KE_KEY, 0x8A, KEY_TV}, | ||
| 282 | {KE_KEY, 0x95, KEY_MEDIA}, | ||
| 283 | {KE_KEY, 0x99, KEY_PHONE}, | ||
| 284 | {KE_END, 0}, | ||
| 285 | }; | ||
| 286 | |||
| 253 | /* | 287 | /* |
| 254 | * This function evaluates an ACPI method, given an int as parameter, the | 288 | * This function evaluates an ACPI method, given an int as parameter, the |
| 255 | * method is searched within the scope of the handle, can be NULL. The output | 289 | * method is searched within the scope of the handle, can be NULL. The output |
| @@ -720,8 +754,68 @@ static ssize_t store_gps(struct device *dev, struct device_attribute *attr, | |||
| 720 | return store_status(buf, count, NULL, GPS_ON); | 754 | return store_status(buf, count, NULL, GPS_ON); |
| 721 | } | 755 | } |
| 722 | 756 | ||
| 757 | /* | ||
| 758 | * Hotkey functions | ||
| 759 | */ | ||
| 760 | static struct key_entry *asus_get_entry_by_scancode(int code) | ||
| 761 | { | ||
| 762 | struct key_entry *key; | ||
| 763 | |||
| 764 | for (key = asus_keymap; key->type != KE_END; key++) | ||
| 765 | if (code == key->code) | ||
| 766 | return key; | ||
| 767 | |||
| 768 | return NULL; | ||
| 769 | } | ||
| 770 | |||
| 771 | static struct key_entry *asus_get_entry_by_keycode(int code) | ||
| 772 | { | ||
| 773 | struct key_entry *key; | ||
| 774 | |||
| 775 | for (key = asus_keymap; key->type != KE_END; key++) | ||
| 776 | if (code == key->keycode && key->type == KE_KEY) | ||
| 777 | return key; | ||
| 778 | |||
| 779 | return NULL; | ||
| 780 | } | ||
| 781 | |||
| 782 | static int asus_getkeycode(struct input_dev *dev, int scancode, int *keycode) | ||
| 783 | { | ||
| 784 | struct key_entry *key = asus_get_entry_by_scancode(scancode); | ||
| 785 | |||
| 786 | if (key && key->type == KE_KEY) { | ||
| 787 | *keycode = key->keycode; | ||
| 788 | return 0; | ||
| 789 | } | ||
| 790 | |||
| 791 | return -EINVAL; | ||
| 792 | } | ||
| 793 | |||
| 794 | static int asus_setkeycode(struct input_dev *dev, int scancode, int keycode) | ||
| 795 | { | ||
| 796 | struct key_entry *key; | ||
| 797 | int old_keycode; | ||
| 798 | |||
| 799 | if (keycode < 0 || keycode > KEY_MAX) | ||
| 800 | return -EINVAL; | ||
| 801 | |||
| 802 | key = asus_get_entry_by_scancode(scancode); | ||
| 803 | if (key && key->type == KE_KEY) { | ||
| 804 | old_keycode = key->keycode; | ||
| 805 | key->keycode = keycode; | ||
| 806 | set_bit(keycode, dev->keybit); | ||
| 807 | if (!asus_get_entry_by_keycode(old_keycode)) | ||
| 808 | clear_bit(old_keycode, dev->keybit); | ||
| 809 | return 0; | ||
| 810 | } | ||
| 811 | |||
| 812 | return -EINVAL; | ||
| 813 | } | ||
| 814 | |||
| 723 | static void asus_hotk_notify(acpi_handle handle, u32 event, void *data) | 815 | static void asus_hotk_notify(acpi_handle handle, u32 event, void *data) |
| 724 | { | 816 | { |
| 817 | static struct key_entry *key; | ||
| 818 | |||
| 725 | /* TODO Find a better way to handle events count. */ | 819 | /* TODO Find a better way to handle events count. */ |
| 726 | if (!hotk) | 820 | if (!hotk) |
| 727 | return; | 821 | return; |
| @@ -742,7 +836,20 @@ static void asus_hotk_notify(acpi_handle handle, u32 event, void *data) | |||
| 742 | dev_name(&hotk->device->dev), event, | 836 | dev_name(&hotk->device->dev), event, |
| 743 | hotk->event_count[event % 128]++); | 837 | hotk->event_count[event % 128]++); |
| 744 | 838 | ||
| 745 | return; | 839 | if (hotk->inputdev) { |
| 840 | key = asus_get_entry_by_scancode(event); | ||
| 841 | if (!key) | ||
| 842 | return ; | ||
| 843 | |||
| 844 | switch (key->type) { | ||
| 845 | case KE_KEY: | ||
| 846 | input_report_key(hotk->inputdev, key->keycode, 1); | ||
| 847 | input_sync(hotk->inputdev); | ||
| 848 | input_report_key(hotk->inputdev, key->keycode, 0); | ||
| 849 | input_sync(hotk->inputdev); | ||
| 850 | break; | ||
| 851 | } | ||
| 852 | } | ||
| 746 | } | 853 | } |
| 747 | 854 | ||
| 748 | #define ASUS_CREATE_DEVICE_ATTR(_name) \ | 855 | #define ASUS_CREATE_DEVICE_ATTR(_name) \ |
| @@ -960,6 +1067,38 @@ static int asus_hotk_get_info(void) | |||
| 960 | return AE_OK; | 1067 | return AE_OK; |
| 961 | } | 1068 | } |
| 962 | 1069 | ||
| 1070 | static int asus_input_init(void) | ||
| 1071 | { | ||
| 1072 | const struct key_entry *key; | ||
| 1073 | int result; | ||
| 1074 | |||
| 1075 | hotk->inputdev = input_allocate_device(); | ||
| 1076 | if (!hotk->inputdev) { | ||
| 1077 | printk(ASUS_INFO "Unable to allocate input device\n"); | ||
| 1078 | return 0; | ||
| 1079 | } | ||
| 1080 | hotk->inputdev->name = "Asus Laptop extra buttons"; | ||
| 1081 | hotk->inputdev->phys = ASUS_HOTK_FILE "/input0"; | ||
| 1082 | hotk->inputdev->id.bustype = BUS_HOST; | ||
| 1083 | hotk->inputdev->getkeycode = asus_getkeycode; | ||
| 1084 | hotk->inputdev->setkeycode = asus_setkeycode; | ||
| 1085 | |||
| 1086 | for (key = asus_keymap; key->type != KE_END; key++) { | ||
| 1087 | switch (key->type) { | ||
| 1088 | case KE_KEY: | ||
| 1089 | set_bit(EV_KEY, hotk->inputdev->evbit); | ||
| 1090 | set_bit(key->keycode, hotk->inputdev->keybit); | ||
| 1091 | break; | ||
| 1092 | } | ||
| 1093 | } | ||
| 1094 | result = input_register_device(hotk->inputdev); | ||
| 1095 | if (result) { | ||
| 1096 | printk(ASUS_INFO "Unable to register input device\n"); | ||
| 1097 | input_free_device(hotk->inputdev); | ||
| 1098 | } | ||
| 1099 | return result; | ||
| 1100 | } | ||
| 1101 | |||
| 963 | static int asus_hotk_check(void) | 1102 | static int asus_hotk_check(void) |
| 964 | { | 1103 | { |
| 965 | int result = 0; | 1104 | int result = 0; |
| @@ -1092,10 +1231,17 @@ static void asus_led_exit(void) | |||
| 1092 | ASUS_LED_UNREGISTER(gled); | 1231 | ASUS_LED_UNREGISTER(gled); |
| 1093 | } | 1232 | } |
| 1094 | 1233 | ||
| 1234 | static void asus_input_exit(void) | ||
| 1235 | { | ||
| 1236 | if (hotk->inputdev) | ||
| 1237 | input_unregister_device(hotk->inputdev); | ||
| 1238 | } | ||
| 1239 | |||
| 1095 | static void __exit asus_laptop_exit(void) | 1240 | static void __exit asus_laptop_exit(void) |
| 1096 | { | 1241 | { |
| 1097 | asus_backlight_exit(); | 1242 | asus_backlight_exit(); |
| 1098 | asus_led_exit(); | 1243 | asus_led_exit(); |
| 1244 | asus_input_exit(); | ||
| 1099 | 1245 | ||
| 1100 | acpi_bus_unregister_driver(&asus_hotk_driver); | 1246 | acpi_bus_unregister_driver(&asus_hotk_driver); |
| 1101 | sysfs_remove_group(&asuspf_device->dev.kobj, &asuspf_attribute_group); | 1247 | sysfs_remove_group(&asuspf_device->dev.kobj, &asuspf_attribute_group); |
| @@ -1217,6 +1363,10 @@ static int __init asus_laptop_init(void) | |||
| 1217 | printk(ASUS_INFO "Brightness ignored, must be controlled by " | 1363 | printk(ASUS_INFO "Brightness ignored, must be controlled by " |
| 1218 | "ACPI video driver\n"); | 1364 | "ACPI video driver\n"); |
| 1219 | 1365 | ||
| 1366 | result = asus_input_init(); | ||
| 1367 | if (result) | ||
| 1368 | goto fail_input; | ||
| 1369 | |||
| 1220 | result = asus_led_init(dev); | 1370 | result = asus_led_init(dev); |
| 1221 | if (result) | 1371 | if (result) |
| 1222 | goto fail_led; | 1372 | goto fail_led; |
| @@ -1256,6 +1406,9 @@ static int __init asus_laptop_init(void) | |||
| 1256 | asus_led_exit(); | 1406 | asus_led_exit(); |
| 1257 | 1407 | ||
| 1258 | fail_led: | 1408 | fail_led: |
| 1409 | asus_input_exit(); | ||
| 1410 | |||
| 1411 | fail_input: | ||
| 1259 | asus_backlight_exit(); | 1412 | asus_backlight_exit(); |
| 1260 | 1413 | ||
| 1261 | fail_backlight: | 1414 | fail_backlight: |
