diff options
Diffstat (limited to 'drivers/misc/thinkpad_acpi.c')
-rw-r--r-- | drivers/misc/thinkpad_acpi.c | 142 |
1 files changed, 86 insertions, 56 deletions
diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c index bb8956d0c104..3d849d13657d 100644 --- a/drivers/misc/thinkpad_acpi.c +++ b/drivers/misc/thinkpad_acpi.c | |||
@@ -906,9 +906,26 @@ static ssize_t hotkey_radio_sw_show(struct device *dev, | |||
906 | static struct device_attribute dev_attr_hotkey_radio_sw = | 906 | static struct device_attribute dev_attr_hotkey_radio_sw = |
907 | __ATTR(hotkey_radio_sw, S_IRUGO, hotkey_radio_sw_show, NULL); | 907 | __ATTR(hotkey_radio_sw, S_IRUGO, hotkey_radio_sw_show, NULL); |
908 | 908 | ||
909 | /* sysfs hotkey report_mode -------------------------------------------- */ | ||
910 | static ssize_t hotkey_report_mode_show(struct device *dev, | ||
911 | struct device_attribute *attr, | ||
912 | char *buf) | ||
913 | { | ||
914 | return snprintf(buf, PAGE_SIZE, "%d\n", | ||
915 | (hotkey_report_mode != 0) ? hotkey_report_mode : 1); | ||
916 | } | ||
917 | |||
918 | static struct device_attribute dev_attr_hotkey_report_mode = | ||
919 | __ATTR(hotkey_report_mode, S_IRUGO, hotkey_report_mode_show, NULL); | ||
920 | |||
909 | /* --------------------------------------------------------------------- */ | 921 | /* --------------------------------------------------------------------- */ |
910 | 922 | ||
911 | static struct attribute *hotkey_mask_attributes[] = { | 923 | static struct attribute *hotkey_attributes[] __initdata = { |
924 | &dev_attr_hotkey_enable.attr, | ||
925 | &dev_attr_hotkey_report_mode.attr, | ||
926 | }; | ||
927 | |||
928 | static struct attribute *hotkey_mask_attributes[] __initdata = { | ||
912 | &dev_attr_hotkey_mask.attr, | 929 | &dev_attr_hotkey_mask.attr, |
913 | &dev_attr_hotkey_bios_enabled.attr, | 930 | &dev_attr_hotkey_bios_enabled.attr, |
914 | &dev_attr_hotkey_bios_mask.attr, | 931 | &dev_attr_hotkey_bios_mask.attr, |
@@ -987,11 +1004,12 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) | |||
987 | str_supported(tp_features.hotkey)); | 1004 | str_supported(tp_features.hotkey)); |
988 | 1005 | ||
989 | if (tp_features.hotkey) { | 1006 | if (tp_features.hotkey) { |
990 | hotkey_dev_attributes = create_attr_set(7, NULL); | 1007 | hotkey_dev_attributes = create_attr_set(8, NULL); |
991 | if (!hotkey_dev_attributes) | 1008 | if (!hotkey_dev_attributes) |
992 | return -ENOMEM; | 1009 | return -ENOMEM; |
993 | res = add_to_attr_set(hotkey_dev_attributes, | 1010 | res = add_many_to_attr_set(hotkey_dev_attributes, |
994 | &dev_attr_hotkey_enable.attr); | 1011 | hotkey_attributes, |
1012 | ARRAY_SIZE(hotkey_attributes)); | ||
995 | if (res) | 1013 | if (res) |
996 | return res; | 1014 | return res; |
997 | 1015 | ||
@@ -1055,11 +1073,6 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) | |||
1055 | TPACPI_HOTKEY_MAP_SIZE); | 1073 | TPACPI_HOTKEY_MAP_SIZE); |
1056 | } | 1074 | } |
1057 | 1075 | ||
1058 | #ifndef CONFIG_THINKPAD_ACPI_INPUT_ENABLED | ||
1059 | for (i = 0; i < 12; i++) | ||
1060 | hotkey_keycode_map[i] = KEY_UNKNOWN; | ||
1061 | #endif /* ! CONFIG_THINKPAD_ACPI_INPUT_ENABLED */ | ||
1062 | |||
1063 | set_bit(EV_KEY, tpacpi_inputdev->evbit); | 1076 | set_bit(EV_KEY, tpacpi_inputdev->evbit); |
1064 | set_bit(EV_MSC, tpacpi_inputdev->evbit); | 1077 | set_bit(EV_MSC, tpacpi_inputdev->evbit); |
1065 | set_bit(MSC_SCAN, tpacpi_inputdev->mscbit); | 1078 | set_bit(MSC_SCAN, tpacpi_inputdev->mscbit); |
@@ -1081,14 +1094,17 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) | |||
1081 | set_bit(SW_RADIO, tpacpi_inputdev->swbit); | 1094 | set_bit(SW_RADIO, tpacpi_inputdev->swbit); |
1082 | } | 1095 | } |
1083 | 1096 | ||
1084 | #ifdef CONFIG_THINKPAD_ACPI_INPUT_ENABLED | ||
1085 | dbg_printk(TPACPI_DBG_INIT, | 1097 | dbg_printk(TPACPI_DBG_INIT, |
1086 | "enabling hot key handling\n"); | 1098 | "enabling hot key handling\n"); |
1087 | res = hotkey_set(1, (hotkey_all_mask & ~hotkey_reserved_mask) | 1099 | res = hotkey_set(1, (hotkey_all_mask & ~hotkey_reserved_mask) |
1088 | | hotkey_orig_mask); | 1100 | | hotkey_orig_mask); |
1089 | if (res) | 1101 | if (res) |
1090 | return res; | 1102 | return res; |
1091 | #endif /* CONFIG_THINKPAD_ACPI_INPUT_ENABLED */ | 1103 | |
1104 | dbg_printk(TPACPI_DBG_INIT, | ||
1105 | "legacy hot key reporting over procfs %s\n", | ||
1106 | (hotkey_report_mode < 2) ? | ||
1107 | "enabled" : "disabled"); | ||
1092 | } | 1108 | } |
1093 | 1109 | ||
1094 | return (tp_features.hotkey)? 0 : 1; | 1110 | return (tp_features.hotkey)? 0 : 1; |
@@ -1142,58 +1158,65 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event) | |||
1142 | { | 1158 | { |
1143 | u32 hkey; | 1159 | u32 hkey; |
1144 | unsigned int keycode, scancode; | 1160 | unsigned int keycode, scancode; |
1145 | int sendacpi = 1; | 1161 | int send_acpi_ev = 0; |
1146 | 1162 | ||
1147 | if (event == 0x80 && acpi_evalf(hkey_handle, &hkey, "MHKP", "d")) { | 1163 | if (event == 0x80 && acpi_evalf(hkey_handle, &hkey, "MHKP", "d")) { |
1148 | if (tpacpi_inputdev->users > 0) { | 1164 | switch (hkey >> 12) { |
1149 | switch (hkey >> 12) { | 1165 | case 1: |
1150 | case 1: | 1166 | /* 0x1000-0x1FFF: key presses */ |
1151 | /* 0x1000-0x1FFF: key presses */ | 1167 | scancode = hkey & 0xfff; |
1152 | scancode = hkey & 0xfff; | 1168 | if (scancode > 0 && scancode < 0x21) { |
1153 | if (scancode > 0 && scancode < 0x21) { | 1169 | scancode--; |
1154 | scancode--; | 1170 | keycode = hotkey_keycode_map[scancode]; |
1155 | keycode = hotkey_keycode_map[scancode]; | 1171 | tpacpi_input_send_key(scancode, keycode); |
1156 | tpacpi_input_send_key(scancode, keycode); | 1172 | } else { |
1157 | sendacpi = (keycode == KEY_RESERVED | 1173 | printk(IBM_ERR |
1158 | || keycode == KEY_UNKNOWN); | 1174 | "hotkey 0x%04x out of range for keyboard map\n", |
1159 | } else { | 1175 | hkey); |
1160 | printk(IBM_ERR | 1176 | send_acpi_ev = 1; |
1161 | "hotkey 0x%04x out of range for keyboard map\n", | 1177 | } |
1162 | hkey); | 1178 | break; |
1163 | } | 1179 | case 5: |
1164 | break; | 1180 | /* 0x5000-0x5FFF: LID */ |
1165 | case 5: | 1181 | /* we don't handle it through this path, just |
1166 | /* 0x5000-0x5FFF: LID */ | 1182 | * eat up known LID events */ |
1167 | /* we don't handle it through this path, just | 1183 | if (hkey != 0x5001 && hkey != 0x5002) { |
1168 | * eat up known LID events */ | 1184 | printk(IBM_ERR |
1169 | if (hkey != 0x5001 && hkey != 0x5002) { | 1185 | "unknown LID-related hotkey event: 0x%04x\n", |
1170 | printk(IBM_ERR | 1186 | hkey); |
1171 | "unknown LID-related hotkey event: 0x%04x\n", | 1187 | send_acpi_ev = 1; |
1172 | hkey); | 1188 | } |
1173 | } | 1189 | break; |
1190 | case 7: | ||
1191 | /* 0x7000-0x7FFF: misc */ | ||
1192 | if (tp_features.hotkey_wlsw && hkey == 0x7000) { | ||
1193 | tpacpi_input_send_radiosw(); | ||
1174 | break; | 1194 | break; |
1175 | case 7: | ||
1176 | /* 0x7000-0x7FFF: misc */ | ||
1177 | if (tp_features.hotkey_wlsw && hkey == 0x7000) { | ||
1178 | tpacpi_input_send_radiosw(); | ||
1179 | sendacpi = 0; | ||
1180 | break; | ||
1181 | } | ||
1182 | /* fallthrough to default */ | ||
1183 | default: | ||
1184 | /* case 2: dock-related */ | ||
1185 | /* 0x2305 - T43 waking up due to bay lever eject while aslept */ | ||
1186 | /* case 3: ultra-bay related. maybe bay in dock? */ | ||
1187 | /* 0x3003 - T43 after wake up by bay lever eject (0x2305) */ | ||
1188 | printk(IBM_NOTICE "unhandled hotkey event 0x%04x\n", hkey); | ||
1189 | } | 1195 | } |
1196 | /* fallthrough to default */ | ||
1197 | default: | ||
1198 | /* case 2: dock-related */ | ||
1199 | /* 0x2305 - T43 waking up due to bay lever eject while aslept */ | ||
1200 | /* case 3: ultra-bay related. maybe bay in dock? */ | ||
1201 | /* 0x3003 - T43 after wake up by bay lever eject (0x2305) */ | ||
1202 | printk(IBM_NOTICE "unhandled HKEY event 0x%04x\n", hkey); | ||
1203 | send_acpi_ev = 1; | ||
1190 | } | 1204 | } |
1191 | |||
1192 | if (sendacpi) | ||
1193 | acpi_bus_generate_proc_event(ibm->acpi->device, event, hkey); | ||
1194 | } else { | 1205 | } else { |
1195 | printk(IBM_ERR "unknown hotkey notification event %d\n", event); | 1206 | printk(IBM_ERR "unknown hotkey notification event %d\n", event); |
1196 | acpi_bus_generate_proc_event(ibm->acpi->device, event, 0); | 1207 | hkey = 0; |
1208 | send_acpi_ev = 1; | ||
1209 | } | ||
1210 | |||
1211 | /* Legacy events */ | ||
1212 | if (send_acpi_ev || hotkey_report_mode < 2) | ||
1213 | acpi_bus_generate_proc_event(ibm->acpi->device, event, hkey); | ||
1214 | |||
1215 | /* netlink events */ | ||
1216 | if (send_acpi_ev) { | ||
1217 | acpi_bus_generate_netlink_event(ibm->acpi->device->pnp.device_class, | ||
1218 | ibm->acpi->device->dev.bus_id, | ||
1219 | event, hkey); | ||
1197 | } | 1220 | } |
1198 | } | 1221 | } |
1199 | 1222 | ||
@@ -4623,6 +4646,9 @@ module_param_named(fan_control, fan_control_allowed, bool, 0); | |||
4623 | static int brightness_mode; | 4646 | static int brightness_mode; |
4624 | module_param_named(brightness_mode, brightness_mode, int, 0); | 4647 | module_param_named(brightness_mode, brightness_mode, int, 0); |
4625 | 4648 | ||
4649 | static unsigned int hotkey_report_mode; | ||
4650 | module_param(hotkey_report_mode, uint, 0); | ||
4651 | |||
4626 | #define IBM_PARAM(feature) \ | 4652 | #define IBM_PARAM(feature) \ |
4627 | module_param_call(feature, set_ibm_param, NULL, NULL, 0) | 4653 | module_param_call(feature, set_ibm_param, NULL, NULL, 0) |
4628 | 4654 | ||
@@ -4648,6 +4674,10 @@ static int __init thinkpad_acpi_module_init(void) | |||
4648 | { | 4674 | { |
4649 | int ret, i; | 4675 | int ret, i; |
4650 | 4676 | ||
4677 | /* Parameter checking */ | ||
4678 | if (hotkey_report_mode > 2) | ||
4679 | return -EINVAL; | ||
4680 | |||
4651 | /* Driver-level probe */ | 4681 | /* Driver-level probe */ |
4652 | 4682 | ||
4653 | get_thinkpad_model_data(&thinkpad_id); | 4683 | get_thinkpad_model_data(&thinkpad_id); |