aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/misc/thinkpad_acpi.c
diff options
context:
space:
mode:
authorHenrique de Moraes Holschuh <hmh@hmh.eng.br>2008-01-08 10:02:41 -0500
committerLen Brown <len.brown@intel.com>2008-02-01 22:26:06 -0500
commit01e88f25985d8ea5866c9a73d56b3a9a9145066f (patch)
treedb5869b85a28a0bf86e8427f54d4b2cd0a597126 /drivers/misc/thinkpad_acpi.c
parentb7c8c200bfbf523ea0a72fd8a5e39089c74da371 (diff)
ACPI: thinkpad-acpi: add CMOS NVRAM polling for hot keys (v9)
Older ThinkPad models do not export some of the hot keys over the event-based ACPI hot key interface. For these models, one has to poll the CMOS NVRAM to check the key state at a rate faster than the expected rate at which the user might repeatedly press the same hot key. This patch implements this functionality for many of the hotkeys in a transparent way: hot keys will now Just Work, and the driver knows the best approach (events or NVRAM polling) to employ, based on the HKEY.MHKA ACPI method. Also, the driver can turn off the polling when there are no users for the hot keys that need such polling. The NVRAM-based hot keys of the A3x series that have never been implemented by later models are not supported, to avoid changes in the keymap of the input devices that could cause headaches in the future. There is a Kconfig option to avoid compiling the NVRAM polling code, as it is not very small, and unlikely to be useful on any ThinkPad newer than a T40, X31 or R52. This feature is based on a previous effort by Richard Hughes. Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br> Cc: Richard Hughes <hughsient@gmail.com> Signed-off-by: Len Brown <len.brown@intel.com>
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 -------------------------------------------------------------- */