diff options
Diffstat (limited to 'drivers/misc/thinkpad_acpi.c')
-rw-r--r-- | drivers/misc/thinkpad_acpi.c | 108 |
1 files changed, 104 insertions, 4 deletions
diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c index 4427c994bc7d..5c1bea1a6c37 100644 --- a/drivers/misc/thinkpad_acpi.c +++ b/drivers/misc/thinkpad_acpi.c | |||
@@ -730,7 +730,31 @@ static struct ibm_struct thinkpad_acpi_driver_data = { | |||
730 | static int hotkey_orig_status; | 730 | static int hotkey_orig_status; |
731 | static u32 hotkey_orig_mask; | 731 | static u32 hotkey_orig_mask; |
732 | static u32 hotkey_all_mask; | 732 | static u32 hotkey_all_mask; |
733 | static u32 hotkey_reserved_mask = 0x00778000; | 733 | static u32 hotkey_reserved_mask; |
734 | |||
735 | static u16 hotkey_keycode_map[] = { | ||
736 | /* Scan Codes 0x00 to 0x0B: ACPI HKEY FN+F1..F12 */ | ||
737 | KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, | ||
738 | KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, | ||
739 | KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, | ||
740 | /* Scan codes 0x0C to 0x0F: Other ACPI HKEY hot keys */ | ||
741 | KEY_UNKNOWN, /* 0x0C: FN+BACKSPACE */ | ||
742 | KEY_UNKNOWN, /* 0x0D: FN+INSERT */ | ||
743 | KEY_UNKNOWN, /* 0x0E: FN+DELETE */ | ||
744 | KEY_RESERVED, /* 0x0F: FN+HOME (brightness up) */ | ||
745 | /* Scan codes 0x10 to 0x1F: Extended ACPI HKEY hot keys */ | ||
746 | KEY_RESERVED, /* 0x10: FN+END (brightness down) */ | ||
747 | KEY_RESERVED, /* 0x11: FN+PGUP (thinklight toggle) */ | ||
748 | KEY_UNKNOWN, /* 0x12: FN+PGDOWN */ | ||
749 | KEY_ZOOM, /* 0x13: FN+SPACE (zoom) */ | ||
750 | KEY_RESERVED, /* 0x14: VOLUME UP */ | ||
751 | KEY_RESERVED, /* 0x15: VOLUME DOWN */ | ||
752 | KEY_RESERVED, /* 0x16: MUTE */ | ||
753 | KEY_VENDOR, /* 0x17: Thinkpad/AccessIBM/Lenovo */ | ||
754 | /* (assignments unknown, please report if found) */ | ||
755 | KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, | ||
756 | KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, | ||
757 | }; | ||
734 | 758 | ||
735 | static struct attribute_set *hotkey_dev_attributes; | 759 | static struct attribute_set *hotkey_dev_attributes; |
736 | 760 | ||
@@ -889,11 +913,13 @@ static struct attribute *hotkey_mask_attributes[] = { | |||
889 | 913 | ||
890 | static int __init hotkey_init(struct ibm_init_struct *iibm) | 914 | static int __init hotkey_init(struct ibm_init_struct *iibm) |
891 | { | 915 | { |
892 | int res; | 916 | int res, i; |
893 | int status; | 917 | int status; |
894 | 918 | ||
895 | vdbg_printk(TPACPI_DBG_INIT, "initializing hotkey subdriver\n"); | 919 | vdbg_printk(TPACPI_DBG_INIT, "initializing hotkey subdriver\n"); |
896 | 920 | ||
921 | BUG_ON(!tpacpi_inputdev); | ||
922 | |||
897 | IBM_ACPIHANDLE_INIT(hkey); | 923 | IBM_ACPIHANDLE_INIT(hkey); |
898 | mutex_init(&hotkey_mutex); | 924 | mutex_init(&hotkey_mutex); |
899 | 925 | ||
@@ -950,6 +976,23 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) | |||
950 | &tpacpi_pdev->dev.kobj); | 976 | &tpacpi_pdev->dev.kobj); |
951 | if (res) | 977 | if (res) |
952 | return res; | 978 | return res; |
979 | |||
980 | set_bit(EV_KEY, tpacpi_inputdev->evbit); | ||
981 | set_bit(EV_MSC, tpacpi_inputdev->evbit); | ||
982 | set_bit(MSC_SCAN, tpacpi_inputdev->mscbit); | ||
983 | tpacpi_inputdev->keycodesize = sizeof(hotkey_keycode_map[0]); | ||
984 | tpacpi_inputdev->keycodemax = ARRAY_SIZE(hotkey_keycode_map); | ||
985 | tpacpi_inputdev->keycode = &hotkey_keycode_map; | ||
986 | for (i = 0; i < ARRAY_SIZE(hotkey_keycode_map); i++) { | ||
987 | if (hotkey_keycode_map[i] != KEY_RESERVED) { | ||
988 | set_bit(hotkey_keycode_map[i], | ||
989 | tpacpi_inputdev->keybit); | ||
990 | } else { | ||
991 | if (i < sizeof(hotkey_reserved_mask)*8) | ||
992 | hotkey_reserved_mask |= 1 << i; | ||
993 | } | ||
994 | } | ||
995 | |||
953 | } | 996 | } |
954 | 997 | ||
955 | return (tp_features.hotkey)? 0 : 1; | 998 | return (tp_features.hotkey)? 0 : 1; |
@@ -972,12 +1015,69 @@ static void hotkey_exit(void) | |||
972 | } | 1015 | } |
973 | } | 1016 | } |
974 | 1017 | ||
1018 | static void tpacpi_input_send_key(unsigned int scancode, | ||
1019 | unsigned int keycode) | ||
1020 | { | ||
1021 | if (keycode != KEY_RESERVED) { | ||
1022 | input_report_key(tpacpi_inputdev, keycode, 1); | ||
1023 | if (keycode == KEY_UNKNOWN) | ||
1024 | input_event(tpacpi_inputdev, EV_MSC, MSC_SCAN, | ||
1025 | scancode); | ||
1026 | input_sync(tpacpi_inputdev); | ||
1027 | |||
1028 | input_report_key(tpacpi_inputdev, keycode, 0); | ||
1029 | if (keycode == KEY_UNKNOWN) | ||
1030 | input_event(tpacpi_inputdev, EV_MSC, MSC_SCAN, | ||
1031 | scancode); | ||
1032 | input_sync(tpacpi_inputdev); | ||
1033 | } | ||
1034 | } | ||
1035 | |||
975 | static void hotkey_notify(struct ibm_struct *ibm, u32 event) | 1036 | static void hotkey_notify(struct ibm_struct *ibm, u32 event) |
976 | { | 1037 | { |
977 | int hkey; | 1038 | u32 hkey; |
1039 | unsigned int keycode, scancode; | ||
1040 | int sendacpi = 1; | ||
978 | 1041 | ||
979 | if (event == 0x80 && acpi_evalf(hkey_handle, &hkey, "MHKP", "d")) { | 1042 | if (event == 0x80 && acpi_evalf(hkey_handle, &hkey, "MHKP", "d")) { |
980 | acpi_bus_generate_event(ibm->acpi->device, event, hkey); | 1043 | if (tpacpi_inputdev->users > 0) { |
1044 | switch (hkey >> 12) { | ||
1045 | case 1: | ||
1046 | /* 0x1000-0x1FFF: key presses */ | ||
1047 | scancode = hkey & 0xfff; | ||
1048 | if (scancode > 0 && scancode < 0x21) { | ||
1049 | scancode--; | ||
1050 | keycode = hotkey_keycode_map[scancode]; | ||
1051 | tpacpi_input_send_key(scancode, keycode); | ||
1052 | sendacpi = (keycode == KEY_RESERVED | ||
1053 | || keycode == KEY_UNKNOWN); | ||
1054 | } else { | ||
1055 | printk(IBM_ERR | ||
1056 | "hotkey 0x%04x out of range for keyboard map\n", | ||
1057 | hkey); | ||
1058 | } | ||
1059 | break; | ||
1060 | case 5: | ||
1061 | /* 0x5000-0x5FFF: LID */ | ||
1062 | /* we don't handle it through this path, just | ||
1063 | * eat up known LID events */ | ||
1064 | if (hkey != 0x5001 && hkey != 0x5002) { | ||
1065 | printk(IBM_ERR | ||
1066 | "unknown LID-related hotkey event: 0x%04x\n", | ||
1067 | hkey); | ||
1068 | } | ||
1069 | break; | ||
1070 | default: | ||
1071 | /* case 2: dock-related */ | ||
1072 | /* 0x2305 - T43 waking up due to bay lever eject while aslept */ | ||
1073 | /* case 3: ultra-bay related. maybe bay in dock? */ | ||
1074 | /* 0x3003 - T43 after wake up by bay lever eject (0x2305) */ | ||
1075 | printk(IBM_NOTICE "unhandled hotkey event 0x%04x\n", hkey); | ||
1076 | } | ||
1077 | } | ||
1078 | |||
1079 | if (sendacpi) | ||
1080 | acpi_bus_generate_event(ibm->acpi->device, event, hkey); | ||
981 | } else { | 1081 | } else { |
982 | printk(IBM_ERR "unknown hotkey notification event %d\n", event); | 1082 | printk(IBM_ERR "unknown hotkey notification event %d\n", event); |
983 | acpi_bus_generate_event(ibm->acpi->device, event, 0); | 1083 | acpi_bus_generate_event(ibm->acpi->device, event, 0); |