Commit db25f16d authored by Henrique de Moraes Holschuh's avatar Henrique de Moraes Holschuh Committed by Len Brown

thinkpad-acpi: hotkey poll fixes

Fix some locking, avoid exiting the kthread before kthread_stop() is
called on it, and clean up the hotkey poll routines a little bit.

Also, restore bits in the firmware mask after hotkey_source_mask is
changed.  Without this, we leave events disabled...
Signed-off-by: default avatarHenrique de Moraes Holschuh <hmh@hmh.eng.br>
Signed-off-by: default avatarLen Brown <len.brown@intel.com>
parent e675abaf
...@@ -1922,16 +1922,42 @@ struct tp_nvram_state { ...@@ -1922,16 +1922,42 @@ struct tp_nvram_state {
u8 volume_level; u8 volume_level;
}; };
/* kthread for the hotkey poller */
static struct task_struct *tpacpi_hotkey_task; static struct task_struct *tpacpi_hotkey_task;
static u32 hotkey_source_mask; /* bit mask 0=ACPI,1=NVRAM */
static int hotkey_poll_freq = 10; /* Hz */ /* Acquired while the poller kthread is running, use to sync start/stop */
static struct mutex hotkey_thread_mutex; static struct mutex hotkey_thread_mutex;
/*
* Acquire mutex to write poller control variables.
* Increment hotkey_config_change when changing them.
*
* See HOTKEY_CONFIG_CRITICAL_START/HOTKEY_CONFIG_CRITICAL_END
*/
static struct mutex hotkey_thread_data_mutex; static struct mutex hotkey_thread_data_mutex;
static unsigned int hotkey_config_change; static unsigned int hotkey_config_change;
/*
* hotkey poller control variables
*
* Must be atomic or readers will also need to acquire mutex
*/
static u32 hotkey_source_mask; /* bit mask 0=ACPI,1=NVRAM */
static unsigned int hotkey_poll_freq = 10; /* Hz */
#define HOTKEY_CONFIG_CRITICAL_START \
do { \
mutex_lock(&hotkey_thread_data_mutex); \
hotkey_config_change++; \
} while (0);
#define HOTKEY_CONFIG_CRITICAL_END \
mutex_unlock(&hotkey_thread_data_mutex);
#else /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */ #else /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */
#define hotkey_source_mask 0U #define hotkey_source_mask 0U
#define HOTKEY_CONFIG_CRITICAL_START
#define HOTKEY_CONFIG_CRITICAL_END
#endif /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */ #endif /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */
...@@ -1956,19 +1982,6 @@ static u16 *hotkey_keycode_map; ...@@ -1956,19 +1982,6 @@ static u16 *hotkey_keycode_map;
static struct attribute_set *hotkey_dev_attributes; static struct attribute_set *hotkey_dev_attributes;
#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL
#define HOTKEY_CONFIG_CRITICAL_START \
do { \
mutex_lock(&hotkey_thread_data_mutex); \
hotkey_config_change++; \
} while (0);
#define HOTKEY_CONFIG_CRITICAL_END \
mutex_unlock(&hotkey_thread_data_mutex);
#else
#define HOTKEY_CONFIG_CRITICAL_START
#define HOTKEY_CONFIG_CRITICAL_END
#endif /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */
/* HKEY.MHKG() return bits */ /* HKEY.MHKG() return bits */
#define TP_HOTKEY_TABLET_MASK (1 << 3) #define TP_HOTKEY_TABLET_MASK (1 << 3)
...@@ -2013,7 +2026,9 @@ static int hotkey_mask_get(void) ...@@ -2013,7 +2026,9 @@ static int hotkey_mask_get(void)
if (!acpi_evalf(hkey_handle, &m, "DHKN", "d")) if (!acpi_evalf(hkey_handle, &m, "DHKN", "d"))
return -EIO; return -EIO;
} }
HOTKEY_CONFIG_CRITICAL_START
hotkey_mask = m | (hotkey_source_mask & hotkey_mask); hotkey_mask = m | (hotkey_source_mask & hotkey_mask);
HOTKEY_CONFIG_CRITICAL_END
return 0; return 0;
} }
...@@ -2266,6 +2281,7 @@ static int hotkey_kthread(void *data) ...@@ -2266,6 +2281,7 @@ static int hotkey_kthread(void *data)
unsigned int si, so; unsigned int si, so;
unsigned long t; unsigned long t;
unsigned int change_detector, must_reset; unsigned int change_detector, must_reset;
unsigned int poll_freq;
mutex_lock(&hotkey_thread_mutex); mutex_lock(&hotkey_thread_mutex);
...@@ -2282,12 +2298,17 @@ static int hotkey_kthread(void *data) ...@@ -2282,12 +2298,17 @@ static int hotkey_kthread(void *data)
mutex_lock(&hotkey_thread_data_mutex); mutex_lock(&hotkey_thread_data_mutex);
change_detector = hotkey_config_change; change_detector = hotkey_config_change;
mask = hotkey_source_mask & hotkey_mask; mask = hotkey_source_mask & hotkey_mask;
poll_freq = hotkey_poll_freq;
mutex_unlock(&hotkey_thread_data_mutex); mutex_unlock(&hotkey_thread_data_mutex);
hotkey_read_nvram(&s[so], mask); hotkey_read_nvram(&s[so], mask);
while (!kthread_should_stop() && hotkey_poll_freq) { while (!kthread_should_stop()) {
if (t == 0) if (t == 0) {
t = 1000/hotkey_poll_freq; if (likely(poll_freq))
t = 1000/poll_freq;
else
t = 100; /* should never happen... */
}
t = msleep_interruptible(t); t = msleep_interruptible(t);
if (unlikely(kthread_should_stop())) if (unlikely(kthread_should_stop()))
break; break;
...@@ -2303,6 +2324,7 @@ static int hotkey_kthread(void *data) ...@@ -2303,6 +2324,7 @@ static int hotkey_kthread(void *data)
change_detector = hotkey_config_change; change_detector = hotkey_config_change;
} }
mask = hotkey_source_mask & hotkey_mask; mask = hotkey_source_mask & hotkey_mask;
poll_freq = hotkey_poll_freq;
mutex_unlock(&hotkey_thread_data_mutex); mutex_unlock(&hotkey_thread_data_mutex);
if (likely(mask)) { if (likely(mask)) {
...@@ -2322,6 +2344,7 @@ exit: ...@@ -2322,6 +2344,7 @@ exit:
return 0; return 0;
} }
/* call with hotkey_mutex held */
static void hotkey_poll_stop_sync(void) static void hotkey_poll_stop_sync(void)
{ {
if (tpacpi_hotkey_task) { if (tpacpi_hotkey_task) {
...@@ -2338,10 +2361,11 @@ static void hotkey_poll_stop_sync(void) ...@@ -2338,10 +2361,11 @@ static void hotkey_poll_stop_sync(void)
} }
/* call with hotkey_mutex held */ /* call with hotkey_mutex held */
static void hotkey_poll_setup(int may_warn) static void hotkey_poll_setup(bool may_warn)
{ {
if ((hotkey_source_mask & hotkey_mask) != 0 && u32 hotkeys_to_poll = hotkey_source_mask & hotkey_mask;
hotkey_poll_freq > 0 &&
if (hotkeys_to_poll != 0 && hotkey_poll_freq > 0 &&
(tpacpi_inputdev->users > 0 || hotkey_report_mode < 2)) { (tpacpi_inputdev->users > 0 || hotkey_report_mode < 2)) {
if (!tpacpi_hotkey_task) { if (!tpacpi_hotkey_task) {
tpacpi_hotkey_task = kthread_run(hotkey_kthread, tpacpi_hotkey_task = kthread_run(hotkey_kthread,
...@@ -2355,26 +2379,37 @@ static void hotkey_poll_setup(int may_warn) ...@@ -2355,26 +2379,37 @@ static void hotkey_poll_setup(int may_warn)
} }
} else { } else {
hotkey_poll_stop_sync(); hotkey_poll_stop_sync();
if (may_warn && if (may_warn && hotkeys_to_poll != 0 &&
hotkey_source_mask != 0 && hotkey_poll_freq == 0) { hotkey_poll_freq == 0) {
printk(TPACPI_NOTICE printk(TPACPI_NOTICE
"hot keys 0x%08x require polling, " "hot keys 0x%08x require polling, "
"which is currently disabled\n", "which is currently disabled\n",
hotkey_source_mask); hotkeys_to_poll);
} }
} }
} }
static void hotkey_poll_setup_safe(int may_warn) static void hotkey_poll_setup_safe(bool may_warn)
{ {
mutex_lock(&hotkey_mutex); mutex_lock(&hotkey_mutex);
hotkey_poll_setup(may_warn); hotkey_poll_setup(may_warn);
mutex_unlock(&hotkey_mutex); mutex_unlock(&hotkey_mutex);
} }
/* call with hotkey_mutex held */
static void hotkey_poll_set_freq(unsigned int freq)
{
if (!freq)
hotkey_poll_stop_sync();
HOTKEY_CONFIG_CRITICAL_START
hotkey_poll_freq = freq;
HOTKEY_CONFIG_CRITICAL_END
}
#else /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */ #else /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */
static void hotkey_poll_setup_safe(int __unused) static void hotkey_poll_setup_safe(bool __unused)
{ {
} }
...@@ -2392,7 +2427,7 @@ static int hotkey_inputdev_open(struct input_dev *dev) ...@@ -2392,7 +2427,7 @@ static int hotkey_inputdev_open(struct input_dev *dev)
case TPACPI_LIFE_EXITING: case TPACPI_LIFE_EXITING:
return -EBUSY; return -EBUSY;
case TPACPI_LIFE_RUNNING: case TPACPI_LIFE_RUNNING:
hotkey_poll_setup_safe(0); hotkey_poll_setup_safe(false);
return 0; return 0;
} }
...@@ -2405,7 +2440,7 @@ static void hotkey_inputdev_close(struct input_dev *dev) ...@@ -2405,7 +2440,7 @@ static void hotkey_inputdev_close(struct input_dev *dev)
{ {
/* disable hotkey polling when possible */ /* disable hotkey polling when possible */
if (tpacpi_lifecycle == TPACPI_LIFE_RUNNING) if (tpacpi_lifecycle == TPACPI_LIFE_RUNNING)
hotkey_poll_setup_safe(0); hotkey_poll_setup_safe(false);
} }
/* sysfs hotkey enable ------------------------------------------------- */ /* sysfs hotkey enable ------------------------------------------------- */
...@@ -2479,7 +2514,7 @@ static ssize_t hotkey_mask_store(struct device *dev, ...@@ -2479,7 +2514,7 @@ static ssize_t hotkey_mask_store(struct device *dev,
res = hotkey_mask_set(t); res = hotkey_mask_set(t);
#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL #ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL
hotkey_poll_setup(1); hotkey_poll_setup(true);
#endif #endif
mutex_unlock(&hotkey_mutex); mutex_unlock(&hotkey_mutex);
...@@ -2568,7 +2603,8 @@ static ssize_t hotkey_source_mask_store(struct device *dev, ...@@ -2568,7 +2603,8 @@ static ssize_t hotkey_source_mask_store(struct device *dev,
hotkey_source_mask = t; hotkey_source_mask = t;
HOTKEY_CONFIG_CRITICAL_END HOTKEY_CONFIG_CRITICAL_END
hotkey_poll_setup(1); hotkey_poll_setup(true);
hotkey_mask_set(hotkey_mask);
mutex_unlock(&hotkey_mutex); mutex_unlock(&hotkey_mutex);
...@@ -2601,9 +2637,9 @@ static ssize_t hotkey_poll_freq_store(struct device *dev, ...@@ -2601,9 +2637,9 @@ static ssize_t hotkey_poll_freq_store(struct device *dev,
if (mutex_lock_killable(&hotkey_mutex)) if (mutex_lock_killable(&hotkey_mutex))
return -ERESTARTSYS; return -ERESTARTSYS;
hotkey_poll_freq = t; hotkey_poll_set_freq(t);
hotkey_poll_setup(true);
hotkey_poll_setup(1);
mutex_unlock(&hotkey_mutex); mutex_unlock(&hotkey_mutex);
tpacpi_disclose_usertask("hotkey_poll_freq", "set to %lu\n", t); tpacpi_disclose_usertask("hotkey_poll_freq", "set to %lu\n", t);
...@@ -2794,7 +2830,9 @@ static void tpacpi_send_radiosw_update(void) ...@@ -2794,7 +2830,9 @@ static void tpacpi_send_radiosw_update(void)
static void hotkey_exit(void) static void hotkey_exit(void)
{ {
#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL #ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL
mutex_lock(&hotkey_mutex);
hotkey_poll_stop_sync(); hotkey_poll_stop_sync();
mutex_unlock(&hotkey_mutex);
#endif #endif
if (hotkey_dev_attributes) if (hotkey_dev_attributes)
...@@ -3031,7 +3069,7 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) ...@@ -3031,7 +3069,7 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
} }
vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_HKEY, vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_HKEY,
"hotkey source mask 0x%08x, polling freq %d\n", "hotkey source mask 0x%08x, polling freq %u\n",
hotkey_source_mask, hotkey_poll_freq); hotkey_source_mask, hotkey_poll_freq);
#endif #endif
...@@ -3169,7 +3207,7 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) ...@@ -3169,7 +3207,7 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
tpacpi_inputdev->open = &hotkey_inputdev_open; tpacpi_inputdev->open = &hotkey_inputdev_open;
tpacpi_inputdev->close = &hotkey_inputdev_close; tpacpi_inputdev->close = &hotkey_inputdev_close;
hotkey_poll_setup_safe(1); hotkey_poll_setup_safe(true);
tpacpi_send_radiosw_update(); tpacpi_send_radiosw_update();
tpacpi_input_send_tabletsw(); tpacpi_input_send_tabletsw();
...@@ -3457,7 +3495,7 @@ static void hotkey_resume(void) ...@@ -3457,7 +3495,7 @@ static void hotkey_resume(void)
hotkey_tablet_mode_notify_change(); hotkey_tablet_mode_notify_change();
hotkey_wakeup_reason_notify_change(); hotkey_wakeup_reason_notify_change();
hotkey_wakeup_hotunplug_complete_notify_change(); hotkey_wakeup_hotunplug_complete_notify_change();
hotkey_poll_setup_safe(0); hotkey_poll_setup_safe(false);
} }
/* procfs -------------------------------------------------------------- */ /* procfs -------------------------------------------------------------- */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment