aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/misc/thinkpad_acpi.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/misc/thinkpad_acpi.c')
-rw-r--r--drivers/misc/thinkpad_acpi.c505
1 files changed, 492 insertions, 13 deletions
diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c
index e7ac1c8a5541..9ff9142ce063 100644
--- a/drivers/misc/thinkpad_acpi.c
+++ b/drivers/misc/thinkpad_acpi.c
@@ -22,7 +22,7 @@
22 */ 22 */
23 23
24#define IBM_VERSION "0.17" 24#define IBM_VERSION "0.17"
25#define TPACPI_SYSFS_VERSION 0x020000 25#define TPACPI_SYSFS_VERSION 0x020101
26 26
27/* 27/*
28 * Changelog: 28 * Changelog:
@@ -773,6 +773,67 @@ static struct ibm_struct thinkpad_acpi_driver_data = {
773 * Hotkey subdriver 773 * Hotkey subdriver
774 */ 774 */
775 775
776enum { /* Keys available through NVRAM polling */
777 TPACPI_HKEY_NVRAM_KNOWN_MASK = 0x00fb88c0U,
778 TPACPI_HKEY_NVRAM_GOOD_MASK = 0x00fb8000U,
779};
780
781enum { /* Positions of some of the keys in hotkey masks */
782 TP_ACPI_HKEY_DISPSWTCH_MASK = 1 << TP_ACPI_HOTKEYSCAN_FNF7,
783 TP_ACPI_HKEY_DISPXPAND_MASK = 1 << TP_ACPI_HOTKEYSCAN_FNF8,
784 TP_ACPI_HKEY_HIBERNATE_MASK = 1 << TP_ACPI_HOTKEYSCAN_FNF12,
785 TP_ACPI_HKEY_BRGHTUP_MASK = 1 << TP_ACPI_HOTKEYSCAN_FNHOME,
786 TP_ACPI_HKEY_BRGHTDWN_MASK = 1 << TP_ACPI_HOTKEYSCAN_FNEND,
787 TP_ACPI_HKEY_THNKLGHT_MASK = 1 << TP_ACPI_HOTKEYSCAN_FNPAGEUP,
788 TP_ACPI_HKEY_ZOOM_MASK = 1 << TP_ACPI_HOTKEYSCAN_FNSPACE,
789 TP_ACPI_HKEY_VOLUP_MASK = 1 << TP_ACPI_HOTKEYSCAN_VOLUMEUP,
790 TP_ACPI_HKEY_VOLDWN_MASK = 1 << TP_ACPI_HOTKEYSCAN_VOLUMEDOWN,
791 TP_ACPI_HKEY_MUTE_MASK = 1 << TP_ACPI_HOTKEYSCAN_MUTE,
792 TP_ACPI_HKEY_THINKPAD_MASK = 1 << TP_ACPI_HOTKEYSCAN_THINKPAD,
793};
794
795enum { /* NVRAM to ACPI HKEY group map */
796 TP_NVRAM_HKEY_GROUP_HK2 = TP_ACPI_HKEY_THINKPAD_MASK |
797 TP_ACPI_HKEY_ZOOM_MASK |
798 TP_ACPI_HKEY_DISPSWTCH_MASK |
799 TP_ACPI_HKEY_HIBERNATE_MASK,
800 TP_NVRAM_HKEY_GROUP_BRIGHTNESS = TP_ACPI_HKEY_BRGHTUP_MASK |
801 TP_ACPI_HKEY_BRGHTDWN_MASK,
802 TP_NVRAM_HKEY_GROUP_VOLUME = TP_ACPI_HKEY_VOLUP_MASK |
803 TP_ACPI_HKEY_VOLDWN_MASK |
804 TP_ACPI_HKEY_MUTE_MASK,
805};
806
807#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL
808struct tp_nvram_state {
809 u16 thinkpad_toggle:1;
810 u16 zoom_toggle:1;
811 u16 display_toggle:1;
812 u16 thinklight_toggle:1;
813 u16 hibernate_toggle:1;
814 u16 displayexp_toggle:1;
815 u16 display_state:1;
816 u16 brightness_toggle:1;
817 u16 volume_toggle:1;
818 u16 mute:1;
819
820 u8 brightness_level;
821 u8 volume_level;
822};
823
824static struct task_struct *tpacpi_hotkey_task;
825static u32 hotkey_source_mask; /* bit mask 0=ACPI,1=NVRAM */
826static int hotkey_poll_freq = 10; /* Hz */
827static struct mutex hotkey_thread_mutex;
828static struct mutex hotkey_thread_data_mutex;
829static unsigned int hotkey_config_change;
830
831#else /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */
832
833#define hotkey_source_mask 0U
834
835#endif /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */
836
776static int hotkey_orig_status; 837static int hotkey_orig_status;
777static u32 hotkey_orig_mask; 838static u32 hotkey_orig_mask;
778static u32 hotkey_all_mask; 839static u32 hotkey_all_mask;
@@ -783,6 +844,17 @@ static u16 *hotkey_keycode_map;
783 844
784static struct attribute_set *hotkey_dev_attributes; 845static struct attribute_set *hotkey_dev_attributes;
785 846
847#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL
848#define HOTKEY_CONFIG_CRITICAL_START \
849 mutex_lock(&hotkey_thread_data_mutex); \
850 hotkey_config_change++;
851#define HOTKEY_CONFIG_CRITICAL_END \
852 mutex_unlock(&hotkey_thread_data_mutex);
853#else
854#define HOTKEY_CONFIG_CRITICAL_START
855#define HOTKEY_CONFIG_CRITICAL_END
856#endif /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */
857
786static int hotkey_get_wlsw(int *status) 858static int hotkey_get_wlsw(int *status)
787{ 859{
788 if (!acpi_evalf(hkey_handle, status, "WLSW", "d")) 860 if (!acpi_evalf(hkey_handle, status, "WLSW", "d"))
@@ -795,10 +867,13 @@ static int hotkey_get_wlsw(int *status)
795 */ 867 */
796static int hotkey_mask_get(void) 868static int hotkey_mask_get(void)
797{ 869{
870 u32 m = 0;
871
798 if (tp_features.hotkey_mask) { 872 if (tp_features.hotkey_mask) {
799 if (!acpi_evalf(hkey_handle, &hotkey_mask, "DHKN", "d")) 873 if (!acpi_evalf(hkey_handle, &m, "DHKN", "d"))
800 return -EIO; 874 return -EIO;
801 } 875 }
876 hotkey_mask = m | (hotkey_source_mask & hotkey_mask);
802 877
803 return 0; 878 return 0;
804} 879}
@@ -812,25 +887,50 @@ static int hotkey_mask_set(u32 mask)
812 int rc = 0; 887 int rc = 0;
813 888
814 if (tp_features.hotkey_mask) { 889 if (tp_features.hotkey_mask) {
890 HOTKEY_CONFIG_CRITICAL_START
815 for (i = 0; i < 32; i++) { 891 for (i = 0; i < 32; i++) {
816 u32 m = 1 << i; 892 u32 m = 1 << i;
893 /* enable in firmware mask only keys not in NVRAM
894 * mode, but enable the key in the cached hotkey_mask
895 * regardless of mode, or the key will end up
896 * disabled by hotkey_mask_get() */
817 if (!acpi_evalf(hkey_handle, 897 if (!acpi_evalf(hkey_handle,
818 NULL, "MHKM", "vdd", i + 1, 898 NULL, "MHKM", "vdd", i + 1,
819 !!(mask & m))) { 899 !!((mask & ~hotkey_source_mask) & m))) {
820 rc = -EIO; 900 rc = -EIO;
821 break; 901 break;
822 } else { 902 } else {
823 hotkey_mask = (hotkey_mask & ~m) | (mask & m); 903 hotkey_mask = (hotkey_mask & ~m) | (mask & m);
824 } 904 }
825 } 905 }
906 HOTKEY_CONFIG_CRITICAL_END
826 907
827 /* hotkey_mask_get must be called unconditionally below */ 908 /* hotkey_mask_get must be called unconditionally below */
828 if (!hotkey_mask_get() && !rc && hotkey_mask != mask) { 909 if (!hotkey_mask_get() && !rc &&
910 (hotkey_mask & ~hotkey_source_mask) !=
911 (mask & ~hotkey_source_mask)) {
829 printk(IBM_NOTICE 912 printk(IBM_NOTICE
830 "requested hot key mask 0x%08x, but " 913 "requested hot key mask 0x%08x, but "
831 "firmware forced it to 0x%08x\n", 914 "firmware forced it to 0x%08x\n",
832 mask, hotkey_mask); 915 mask, hotkey_mask);
833 } 916 }
917 } else {
918#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL
919 HOTKEY_CONFIG_CRITICAL_START
920 hotkey_mask = mask & hotkey_source_mask;
921 HOTKEY_CONFIG_CRITICAL_END
922 hotkey_mask_get();
923 if (hotkey_mask != mask) {
924 printk(IBM_NOTICE
925 "requested hot key mask 0x%08x, "
926 "forced to 0x%08x (NVRAM poll mask is "
927 "0x%08x): no firmware mask support\n",
928 mask, hotkey_mask, hotkey_source_mask);
929 }
930#else
931 hotkey_mask_get();
932 rc = -ENXIO;
933#endif /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */
834 } 934 }
835 935
836 return rc; 936 return rc;
@@ -892,6 +992,256 @@ static void tpacpi_input_send_key(unsigned int scancode)
892 } 992 }
893} 993}
894 994
995#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL
996static struct tp_acpi_drv_struct ibm_hotkey_acpidriver;
997
998static void tpacpi_hotkey_send_key(unsigned int scancode)
999{
1000 tpacpi_input_send_key(scancode);
1001 if (hotkey_report_mode < 2) {
1002 acpi_bus_generate_proc_event(ibm_hotkey_acpidriver.device,
1003 0x80, 0x1001 + scancode);
1004 }
1005}
1006
1007static void hotkey_read_nvram(struct tp_nvram_state *n, u32 m)
1008{
1009 u8 d;
1010
1011 if (m & TP_NVRAM_HKEY_GROUP_HK2) {
1012 d = nvram_read_byte(TP_NVRAM_ADDR_HK2);
1013 n->thinkpad_toggle = !!(d & TP_NVRAM_MASK_HKT_THINKPAD);
1014 n->zoom_toggle = !!(d & TP_NVRAM_MASK_HKT_ZOOM);
1015 n->display_toggle = !!(d & TP_NVRAM_MASK_HKT_DISPLAY);
1016 n->hibernate_toggle = !!(d & TP_NVRAM_MASK_HKT_HIBERNATE);
1017 }
1018 if (m & TP_ACPI_HKEY_THNKLGHT_MASK) {
1019 d = nvram_read_byte(TP_NVRAM_ADDR_THINKLIGHT);
1020 n->thinklight_toggle = !!(d & TP_NVRAM_MASK_THINKLIGHT);
1021 }
1022 if (m & TP_ACPI_HKEY_DISPXPAND_MASK) {
1023 d = nvram_read_byte(TP_NVRAM_ADDR_VIDEO);
1024 n->displayexp_toggle =
1025 !!(d & TP_NVRAM_MASK_HKT_DISPEXPND);
1026 }
1027 if (m & TP_NVRAM_HKEY_GROUP_BRIGHTNESS) {
1028 d = nvram_read_byte(TP_NVRAM_ADDR_BRIGHTNESS);
1029 n->brightness_level = (d & TP_NVRAM_MASK_LEVEL_BRIGHTNESS)
1030 >> TP_NVRAM_POS_LEVEL_BRIGHTNESS;
1031 n->brightness_toggle =
1032 !!(d & TP_NVRAM_MASK_HKT_BRIGHTNESS);
1033 }
1034 if (m & TP_NVRAM_HKEY_GROUP_VOLUME) {
1035 d = nvram_read_byte(TP_NVRAM_ADDR_MIXER);
1036 n->volume_level = (d & TP_NVRAM_MASK_LEVEL_VOLUME)
1037 >> TP_NVRAM_POS_LEVEL_VOLUME;
1038 n->mute = !!(d & TP_NVRAM_MASK_MUTE);
1039 n->volume_toggle = !!(d & TP_NVRAM_MASK_HKT_VOLUME);
1040 }
1041}
1042
1043#define TPACPI_COMPARE_KEY(__scancode, __member) \
1044 do { if ((mask & (1 << __scancode)) && oldn->__member != newn->__member) \
1045 tpacpi_hotkey_send_key(__scancode); } while (0)
1046
1047#define TPACPI_MAY_SEND_KEY(__scancode) \
1048 do { if (mask & (1 << __scancode)) \
1049 tpacpi_hotkey_send_key(__scancode); } while (0)
1050
1051static void hotkey_compare_and_issue_event(struct tp_nvram_state *oldn,
1052 struct tp_nvram_state *newn,
1053 u32 mask)
1054{
1055 TPACPI_COMPARE_KEY(TP_ACPI_HOTKEYSCAN_THINKPAD, thinkpad_toggle);
1056 TPACPI_COMPARE_KEY(TP_ACPI_HOTKEYSCAN_FNSPACE, zoom_toggle);
1057 TPACPI_COMPARE_KEY(TP_ACPI_HOTKEYSCAN_FNF7, display_toggle);
1058 TPACPI_COMPARE_KEY(TP_ACPI_HOTKEYSCAN_FNF12, hibernate_toggle);
1059
1060 TPACPI_COMPARE_KEY(TP_ACPI_HOTKEYSCAN_FNPAGEUP, thinklight_toggle);
1061
1062 TPACPI_COMPARE_KEY(TP_ACPI_HOTKEYSCAN_FNF8, displayexp_toggle);
1063
1064 /* handle volume */
1065 if (oldn->volume_toggle != newn->volume_toggle) {
1066 if (oldn->mute != newn->mute) {
1067 TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_MUTE);
1068 }
1069 if (oldn->volume_level > newn->volume_level) {
1070 TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_VOLUMEDOWN);
1071 } else if (oldn->volume_level < newn->volume_level) {
1072 TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_VOLUMEUP);
1073 } else if (oldn->mute == newn->mute) {
1074 /* repeated key presses that didn't change state */
1075 if (newn->mute) {
1076 TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_MUTE);
1077 } else if (newn->volume_level != 0) {
1078 TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_VOLUMEUP);
1079 } else {
1080 TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_VOLUMEDOWN);
1081 }
1082 }
1083 }
1084
1085 /* handle brightness */
1086 if (oldn->brightness_toggle != newn->brightness_toggle) {
1087 if (oldn->brightness_level < newn->brightness_level) {
1088 TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_FNHOME);
1089 } else if (oldn->brightness_level > newn->brightness_level) {
1090 TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_FNEND);
1091 } else {
1092 /* repeated key presses that didn't change state */
1093 if (newn->brightness_level != 0) {
1094 TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_FNHOME);
1095 } else {
1096 TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_FNEND);
1097 }
1098 }
1099 }
1100}
1101
1102#undef TPACPI_COMPARE_KEY
1103#undef TPACPI_MAY_SEND_KEY
1104
1105static int hotkey_kthread(void *data)
1106{
1107 struct tp_nvram_state s[2];
1108 u32 mask;
1109 unsigned int si, so;
1110 unsigned long t;
1111 unsigned int change_detector, must_reset;
1112
1113 mutex_lock(&hotkey_thread_mutex);
1114
1115 if (tpacpi_lifecycle == TPACPI_LIFE_EXITING)
1116 goto exit;
1117
1118 set_freezable();
1119
1120 so = 0;
1121 si = 1;
1122 t = 0;
1123
1124 /* Initial state for compares */
1125 mutex_lock(&hotkey_thread_data_mutex);
1126 change_detector = hotkey_config_change;
1127 mask = hotkey_source_mask & hotkey_mask;
1128 mutex_unlock(&hotkey_thread_data_mutex);
1129 hotkey_read_nvram(&s[so], mask);
1130
1131 while (!kthread_should_stop() && hotkey_poll_freq) {
1132 if (t == 0)
1133 t = 1000/hotkey_poll_freq;
1134 t = msleep_interruptible(t);
1135 if (unlikely(kthread_should_stop()))
1136 break;
1137 must_reset = try_to_freeze();
1138 if (t > 0 && !must_reset)
1139 continue;
1140
1141 mutex_lock(&hotkey_thread_data_mutex);
1142 if (must_reset || hotkey_config_change != change_detector) {
1143 /* forget old state on thaw or config change */
1144 si = so;
1145 t = 0;
1146 change_detector = hotkey_config_change;
1147 }
1148 mask = hotkey_source_mask & hotkey_mask;
1149 mutex_unlock(&hotkey_thread_data_mutex);
1150
1151 if (likely(mask)) {
1152 hotkey_read_nvram(&s[si], mask);
1153 if (likely(si != so)) {
1154 hotkey_compare_and_issue_event(&s[so], &s[si],
1155 mask);
1156 }
1157 }
1158
1159 so = si;
1160 si ^= 1;
1161 }
1162
1163exit:
1164 mutex_unlock(&hotkey_thread_mutex);
1165 return 0;
1166}
1167
1168static void hotkey_poll_stop_sync(void)
1169{
1170 if (tpacpi_hotkey_task) {
1171 if (frozen(tpacpi_hotkey_task) ||
1172 freezing(tpacpi_hotkey_task))
1173 thaw_process(tpacpi_hotkey_task);
1174
1175 kthread_stop(tpacpi_hotkey_task);
1176 tpacpi_hotkey_task = NULL;
1177 mutex_lock(&hotkey_thread_mutex);
1178 /* at this point, the thread did exit */
1179 mutex_unlock(&hotkey_thread_mutex);
1180 }
1181}
1182
1183/* call with hotkey_mutex held */
1184static void hotkey_poll_setup(int may_warn)
1185{
1186 if ((hotkey_source_mask & hotkey_mask) != 0 &&
1187 hotkey_poll_freq > 0 &&
1188 (tpacpi_inputdev->users > 0 || hotkey_report_mode < 2)) {
1189 if (!tpacpi_hotkey_task) {
1190 tpacpi_hotkey_task = kthread_run(hotkey_kthread,
1191 NULL, IBM_FILE "d");
1192 if (IS_ERR(tpacpi_hotkey_task)) {
1193 tpacpi_hotkey_task = NULL;
1194 printk(IBM_ERR "could not create kernel thread "
1195 "for hotkey polling\n");
1196 }
1197 }
1198 } else {
1199 hotkey_poll_stop_sync();
1200 if (may_warn &&
1201 hotkey_source_mask != 0 && hotkey_poll_freq == 0) {
1202 printk(IBM_NOTICE "hot keys 0x%08x require polling, "
1203 "which is currently disabled\n",
1204 hotkey_source_mask);
1205 }
1206 }
1207}
1208
1209static void hotkey_poll_setup_safe(int may_warn)
1210{
1211 mutex_lock(&hotkey_mutex);
1212 hotkey_poll_setup(may_warn);
1213 mutex_unlock(&hotkey_mutex);
1214}
1215
1216static int hotkey_inputdev_open(struct input_dev *dev)
1217{
1218 switch (tpacpi_lifecycle) {
1219 case TPACPI_LIFE_INIT:
1220 /*
1221 * hotkey_init will call hotkey_poll_setup_safe
1222 * at the appropriate moment
1223 */
1224 return 0;
1225 case TPACPI_LIFE_EXITING:
1226 return -EBUSY;
1227 case TPACPI_LIFE_RUNNING:
1228 hotkey_poll_setup_safe(0);
1229 return 0;
1230 }
1231
1232 /* Should only happen if tpacpi_lifecycle is corrupt */
1233 BUG();
1234 return -EBUSY;
1235}
1236
1237static void hotkey_inputdev_close(struct input_dev *dev)
1238{
1239 /* disable hotkey polling when possible */
1240 if (tpacpi_lifecycle == TPACPI_LIFE_RUNNING)
1241 hotkey_poll_setup_safe(0);
1242}
1243#endif /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */
1244
895/* sysfs hotkey enable ------------------------------------------------- */ 1245/* sysfs hotkey enable ------------------------------------------------- */
896static ssize_t hotkey_enable_show(struct device *dev, 1246static ssize_t hotkey_enable_show(struct device *dev,
897 struct device_attribute *attr, 1247 struct device_attribute *attr,
@@ -955,6 +1305,11 @@ static ssize_t hotkey_mask_store(struct device *dev,
955 return -ERESTARTSYS; 1305 return -ERESTARTSYS;
956 1306
957 res = hotkey_mask_set(t); 1307 res = hotkey_mask_set(t);
1308
1309#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL
1310 hotkey_poll_setup(1);
1311#endif
1312
958 mutex_unlock(&hotkey_mutex); 1313 mutex_unlock(&hotkey_mutex);
959 1314
960 return (res) ? res : count; 1315 return (res) ? res : count;
@@ -991,7 +1346,8 @@ static ssize_t hotkey_all_mask_show(struct device *dev,
991 struct device_attribute *attr, 1346 struct device_attribute *attr,
992 char *buf) 1347 char *buf)
993{ 1348{
994 return snprintf(buf, PAGE_SIZE, "0x%08x\n", hotkey_all_mask); 1349 return snprintf(buf, PAGE_SIZE, "0x%08x\n",
1350 hotkey_all_mask | hotkey_source_mask);
995} 1351}
996 1352
997static struct device_attribute dev_attr_hotkey_all_mask = 1353static struct device_attribute dev_attr_hotkey_all_mask =
@@ -1003,13 +1359,86 @@ static ssize_t hotkey_recommended_mask_show(struct device *dev,
1003 char *buf) 1359 char *buf)
1004{ 1360{
1005 return snprintf(buf, PAGE_SIZE, "0x%08x\n", 1361 return snprintf(buf, PAGE_SIZE, "0x%08x\n",
1006 hotkey_all_mask & ~hotkey_reserved_mask); 1362 (hotkey_all_mask | hotkey_source_mask)
1363 & ~hotkey_reserved_mask);
1007} 1364}
1008 1365
1009static struct device_attribute dev_attr_hotkey_recommended_mask = 1366static struct device_attribute dev_attr_hotkey_recommended_mask =
1010 __ATTR(hotkey_recommended_mask, S_IRUGO, 1367 __ATTR(hotkey_recommended_mask, S_IRUGO,
1011 hotkey_recommended_mask_show, NULL); 1368 hotkey_recommended_mask_show, NULL);
1012 1369
1370#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL
1371
1372/* sysfs hotkey hotkey_source_mask ------------------------------------- */
1373static ssize_t hotkey_source_mask_show(struct device *dev,
1374 struct device_attribute *attr,
1375 char *buf)
1376{
1377 return snprintf(buf, PAGE_SIZE, "0x%08x\n", hotkey_source_mask);
1378}
1379
1380static ssize_t hotkey_source_mask_store(struct device *dev,
1381 struct device_attribute *attr,
1382 const char *buf, size_t count)
1383{
1384 unsigned long t;
1385
1386 if (parse_strtoul(buf, 0xffffffffUL, &t) ||
1387 ((t & ~TPACPI_HKEY_NVRAM_KNOWN_MASK) != 0))
1388 return -EINVAL;
1389
1390 if (mutex_lock_interruptible(&hotkey_mutex))
1391 return -ERESTARTSYS;
1392
1393 HOTKEY_CONFIG_CRITICAL_START
1394 hotkey_source_mask = t;
1395 HOTKEY_CONFIG_CRITICAL_END
1396
1397 hotkey_poll_setup(1);
1398
1399 mutex_unlock(&hotkey_mutex);
1400
1401 return count;
1402}
1403
1404static struct device_attribute dev_attr_hotkey_source_mask =
1405 __ATTR(hotkey_source_mask, S_IWUSR | S_IRUGO,
1406 hotkey_source_mask_show, hotkey_source_mask_store);
1407
1408/* sysfs hotkey hotkey_poll_freq --------------------------------------- */
1409static ssize_t hotkey_poll_freq_show(struct device *dev,
1410 struct device_attribute *attr,
1411 char *buf)
1412{
1413 return snprintf(buf, PAGE_SIZE, "%d\n", hotkey_poll_freq);
1414}
1415
1416static ssize_t hotkey_poll_freq_store(struct device *dev,
1417 struct device_attribute *attr,
1418 const char *buf, size_t count)
1419{
1420 unsigned long t;
1421
1422 if (parse_strtoul(buf, 25, &t))
1423 return -EINVAL;
1424
1425 if (mutex_lock_interruptible(&hotkey_mutex))
1426 return -ERESTARTSYS;
1427
1428 hotkey_poll_freq = t;
1429
1430 hotkey_poll_setup(1);
1431 mutex_unlock(&hotkey_mutex);
1432
1433 return count;
1434}
1435
1436static struct device_attribute dev_attr_hotkey_poll_freq =
1437 __ATTR(hotkey_poll_freq, S_IWUSR | S_IRUGO,
1438 hotkey_poll_freq_show, hotkey_poll_freq_store);
1439
1440#endif /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */
1441
1013/* sysfs hotkey radio_sw ----------------------------------------------- */ 1442/* sysfs hotkey radio_sw ----------------------------------------------- */
1014static ssize_t hotkey_radio_sw_show(struct device *dev, 1443static ssize_t hotkey_radio_sw_show(struct device *dev,
1015 struct device_attribute *attr, 1444 struct device_attribute *attr,
@@ -1042,15 +1471,24 @@ static struct device_attribute dev_attr_hotkey_report_mode =
1042 1471
1043static struct attribute *hotkey_attributes[] __initdata = { 1472static struct attribute *hotkey_attributes[] __initdata = {
1044 &dev_attr_hotkey_enable.attr, 1473 &dev_attr_hotkey_enable.attr,
1474 &dev_attr_hotkey_bios_enabled.attr,
1045 &dev_attr_hotkey_report_mode.attr, 1475 &dev_attr_hotkey_report_mode.attr,
1476#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL
1477 &dev_attr_hotkey_mask.attr,
1478 &dev_attr_hotkey_all_mask.attr,
1479 &dev_attr_hotkey_recommended_mask.attr,
1480 &dev_attr_hotkey_source_mask.attr,
1481 &dev_attr_hotkey_poll_freq.attr,
1482#endif
1046}; 1483};
1047 1484
1048static struct attribute *hotkey_mask_attributes[] __initdata = { 1485static struct attribute *hotkey_mask_attributes[] __initdata = {
1049 &dev_attr_hotkey_mask.attr,
1050 &dev_attr_hotkey_bios_enabled.attr,
1051 &dev_attr_hotkey_bios_mask.attr, 1486 &dev_attr_hotkey_bios_mask.attr,
1487#ifndef CONFIG_THINKPAD_ACPI_HOTKEY_POLL
1488 &dev_attr_hotkey_mask.attr,
1052 &dev_attr_hotkey_all_mask.attr, 1489 &dev_attr_hotkey_all_mask.attr,
1053 &dev_attr_hotkey_recommended_mask.attr, 1490 &dev_attr_hotkey_recommended_mask.attr,
1491#endif
1054}; 1492};
1055 1493
1056static int __init hotkey_init(struct ibm_init_struct *iibm) 1494static int __init hotkey_init(struct ibm_init_struct *iibm)
@@ -1172,10 +1610,17 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
1172 vdbg_printk(TPACPI_DBG_INIT, "initializing hotkey subdriver\n"); 1610 vdbg_printk(TPACPI_DBG_INIT, "initializing hotkey subdriver\n");
1173 1611
1174 BUG_ON(!tpacpi_inputdev); 1612 BUG_ON(!tpacpi_inputdev);
1613 BUG_ON(tpacpi_inputdev->open != NULL ||
1614 tpacpi_inputdev->close != NULL);
1175 1615
1176 IBM_ACPIHANDLE_INIT(hkey); 1616 IBM_ACPIHANDLE_INIT(hkey);
1177 mutex_init(&hotkey_mutex); 1617 mutex_init(&hotkey_mutex);
1178 1618
1619#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL
1620 mutex_init(&hotkey_thread_mutex);
1621 mutex_init(&hotkey_thread_data_mutex);
1622#endif
1623
1179 /* hotkey not supported on 570 */ 1624 /* hotkey not supported on 570 */
1180 tp_features.hotkey = hkey_handle != NULL; 1625 tp_features.hotkey = hkey_handle != NULL;
1181 1626
@@ -1183,7 +1628,7 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
1183 str_supported(tp_features.hotkey)); 1628 str_supported(tp_features.hotkey));
1184 1629
1185 if (tp_features.hotkey) { 1630 if (tp_features.hotkey) {
1186 hotkey_dev_attributes = create_attr_set(8, NULL); 1631 hotkey_dev_attributes = create_attr_set(10, NULL);
1187 if (!hotkey_dev_attributes) 1632 if (!hotkey_dev_attributes)
1188 return -ENOMEM; 1633 return -ENOMEM;
1189 res = add_many_to_attr_set(hotkey_dev_attributes, 1634 res = add_many_to_attr_set(hotkey_dev_attributes,
@@ -1205,7 +1650,7 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
1205 /* 1650 /*
1206 * MHKV 0x100 in A31, R40, R40e, 1651 * MHKV 0x100 in A31, R40, R40e,
1207 * T4x, X31, and later 1652 * T4x, X31, and later
1208 * */ 1653 */
1209 tp_features.hotkey_mask = 1; 1654 tp_features.hotkey_mask = 1;
1210 } 1655 }
1211 } 1656 }
@@ -1224,6 +1669,8 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
1224 } 1669 }
1225 } 1670 }
1226 1671
1672 /* hotkey_source_mask *must* be zero for
1673 * the first hotkey_mask_get */
1227 res = hotkey_status_get(&hotkey_orig_status); 1674 res = hotkey_status_get(&hotkey_orig_status);
1228 if (!res && tp_features.hotkey_mask) { 1675 if (!res && tp_features.hotkey_mask) {
1229 res = hotkey_mask_get(); 1676 res = hotkey_mask_get();
@@ -1236,6 +1683,19 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
1236 } 1683 }
1237 } 1684 }
1238 1685
1686#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL
1687 if (tp_features.hotkey_mask) {
1688 hotkey_source_mask = TPACPI_HKEY_NVRAM_GOOD_MASK
1689 & ~hotkey_all_mask;
1690 } else {
1691 hotkey_source_mask = TPACPI_HKEY_NVRAM_GOOD_MASK;
1692 }
1693
1694 vdbg_printk(TPACPI_DBG_INIT,
1695 "hotkey source mask 0x%08x, polling freq %d\n",
1696 hotkey_source_mask, hotkey_poll_freq);
1697#endif
1698
1239 /* Not all thinkpads have a hardware radio switch */ 1699 /* Not all thinkpads have a hardware radio switch */
1240 if (!res && acpi_evalf(hkey_handle, &status, "WLSW", "qd")) { 1700 if (!res && acpi_evalf(hkey_handle, &status, "WLSW", "qd")) {
1241 tp_features.hotkey_wlsw = 1; 1701 tp_features.hotkey_wlsw = 1;
@@ -1300,15 +1760,23 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
1300 res = hotkey_status_set(1); 1760 res = hotkey_status_set(1);
1301 if (res) 1761 if (res)
1302 return res; 1762 return res;
1303 res = hotkey_mask_set((hotkey_all_mask & ~hotkey_reserved_mask) 1763 res = hotkey_mask_set(((hotkey_all_mask | hotkey_source_mask)
1764 & ~hotkey_reserved_mask)
1304 | hotkey_orig_mask); 1765 | hotkey_orig_mask);
1305 if (res) 1766 if (res < 0 && res != -ENXIO)
1306 return res; 1767 return res;
1307 1768
1308 dbg_printk(TPACPI_DBG_INIT, 1769 dbg_printk(TPACPI_DBG_INIT,
1309 "legacy hot key reporting over procfs %s\n", 1770 "legacy hot key reporting over procfs %s\n",
1310 (hotkey_report_mode < 2) ? 1771 (hotkey_report_mode < 2) ?
1311 "enabled" : "disabled"); 1772 "enabled" : "disabled");
1773
1774#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL
1775 tpacpi_inputdev->open = &hotkey_inputdev_open;
1776 tpacpi_inputdev->close = &hotkey_inputdev_close;
1777
1778 hotkey_poll_setup_safe(1);
1779#endif
1312 } 1780 }
1313 1781
1314 return (tp_features.hotkey)? 0 : 1; 1782 return (tp_features.hotkey)? 0 : 1;
@@ -1316,6 +1784,10 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
1316 1784
1317static void hotkey_exit(void) 1785static void hotkey_exit(void)
1318{ 1786{
1787#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL
1788 hotkey_poll_stop_sync();
1789#endif
1790
1319 if (tp_features.hotkey) { 1791 if (tp_features.hotkey) {
1320 dbg_printk(TPACPI_DBG_EXIT, "restoring original hot key mask\n"); 1792 dbg_printk(TPACPI_DBG_EXIT, "restoring original hot key mask\n");
1321 /* no short-circuit boolean operator below! */ 1793 /* no short-circuit boolean operator below! */
@@ -1366,7 +1838,11 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event)
1366 scancode = hkey & 0xfff; 1838 scancode = hkey & 0xfff;
1367 if (scancode > 0 && scancode < 0x21) { 1839 if (scancode > 0 && scancode < 0x21) {
1368 scancode--; 1840 scancode--;
1369 tpacpi_input_send_key(scancode); 1841 if (!(hotkey_source_mask & (1 << scancode))) {
1842 tpacpi_input_send_key(scancode);
1843 } else {
1844 ignore_acpi_ev = 1;
1845 }
1370 } else { 1846 } else {
1371 printk(IBM_ERR 1847 printk(IBM_ERR
1372 "hotkey 0x%04x out of range for keyboard map\n", 1848 "hotkey 0x%04x out of range for keyboard map\n",
@@ -1422,6 +1898,9 @@ static void hotkey_resume(void)
1422 if (hotkey_mask_get()) 1898 if (hotkey_mask_get())
1423 printk(IBM_ERR "error while trying to read hot key mask from firmware\n"); 1899 printk(IBM_ERR "error while trying to read hot key mask from firmware\n");
1424 tpacpi_input_send_radiosw(); 1900 tpacpi_input_send_radiosw();
1901#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL
1902 hotkey_poll_setup_safe(0);
1903#endif
1425} 1904}
1426 1905
1427/* procfs -------------------------------------------------------------- */ 1906/* procfs -------------------------------------------------------------- */