diff options
author | Henrique de Moraes Holschuh <hmh@hmh.eng.br> | 2009-09-12 14:22:14 -0400 |
---|---|---|
committer | Len Brown <len.brown@intel.com> | 2009-09-19 00:53:04 -0400 |
commit | db25f16d1dcce8de12f2f5daf884cda02196b28c (patch) | |
tree | 12abde8e97c57de182d9a0b8f6689664546d09f6 /drivers/platform | |
parent | e675abafcc0df38125e6e94a9ba91c92fe774f52 (diff) |
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: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
Signed-off-by: Len Brown <len.brown@intel.com>
Diffstat (limited to 'drivers/platform')
-rw-r--r-- | drivers/platform/x86/thinkpad_acpi.c | 108 |
1 files changed, 73 insertions, 35 deletions
diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index d69ab3f0bdbc..679a73b43191 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c | |||
@@ -1922,16 +1922,42 @@ struct tp_nvram_state { | |||
1922 | u8 volume_level; | 1922 | u8 volume_level; |
1923 | }; | 1923 | }; |
1924 | 1924 | ||
1925 | /* kthread for the hotkey poller */ | ||
1925 | static struct task_struct *tpacpi_hotkey_task; | 1926 | static struct task_struct *tpacpi_hotkey_task; |
1926 | static u32 hotkey_source_mask; /* bit mask 0=ACPI,1=NVRAM */ | 1927 | |
1927 | static int hotkey_poll_freq = 10; /* Hz */ | 1928 | /* Acquired while the poller kthread is running, use to sync start/stop */ |
1928 | static struct mutex hotkey_thread_mutex; | 1929 | static struct mutex hotkey_thread_mutex; |
1930 | |||
1931 | /* | ||
1932 | * Acquire mutex to write poller control variables. | ||
1933 | * Increment hotkey_config_change when changing them. | ||
1934 | * | ||
1935 | * See HOTKEY_CONFIG_CRITICAL_START/HOTKEY_CONFIG_CRITICAL_END | ||
1936 | */ | ||
1929 | static struct mutex hotkey_thread_data_mutex; | 1937 | static struct mutex hotkey_thread_data_mutex; |
1930 | static unsigned int hotkey_config_change; | 1938 | static unsigned int hotkey_config_change; |
1931 | 1939 | ||
1940 | /* | ||
1941 | * hotkey poller control variables | ||
1942 | * | ||
1943 | * Must be atomic or readers will also need to acquire mutex | ||
1944 | */ | ||
1945 | static u32 hotkey_source_mask; /* bit mask 0=ACPI,1=NVRAM */ | ||
1946 | static unsigned int hotkey_poll_freq = 10; /* Hz */ | ||
1947 | |||
1948 | #define HOTKEY_CONFIG_CRITICAL_START \ | ||
1949 | do { \ | ||
1950 | mutex_lock(&hotkey_thread_data_mutex); \ | ||
1951 | hotkey_config_change++; \ | ||
1952 | } while (0); | ||
1953 | #define HOTKEY_CONFIG_CRITICAL_END \ | ||
1954 | mutex_unlock(&hotkey_thread_data_mutex); | ||
1955 | |||
1932 | #else /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */ | 1956 | #else /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */ |
1933 | 1957 | ||
1934 | #define hotkey_source_mask 0U | 1958 | #define hotkey_source_mask 0U |
1959 | #define HOTKEY_CONFIG_CRITICAL_START | ||
1960 | #define HOTKEY_CONFIG_CRITICAL_END | ||
1935 | 1961 | ||
1936 | #endif /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */ | 1962 | #endif /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */ |
1937 | 1963 | ||
@@ -1956,19 +1982,6 @@ static u16 *hotkey_keycode_map; | |||
1956 | 1982 | ||
1957 | static struct attribute_set *hotkey_dev_attributes; | 1983 | static struct attribute_set *hotkey_dev_attributes; |
1958 | 1984 | ||
1959 | #ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL | ||
1960 | #define HOTKEY_CONFIG_CRITICAL_START \ | ||
1961 | do { \ | ||
1962 | mutex_lock(&hotkey_thread_data_mutex); \ | ||
1963 | hotkey_config_change++; \ | ||
1964 | } while (0); | ||
1965 | #define HOTKEY_CONFIG_CRITICAL_END \ | ||
1966 | mutex_unlock(&hotkey_thread_data_mutex); | ||
1967 | #else | ||
1968 | #define HOTKEY_CONFIG_CRITICAL_START | ||
1969 | #define HOTKEY_CONFIG_CRITICAL_END | ||
1970 | #endif /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */ | ||
1971 | |||
1972 | /* HKEY.MHKG() return bits */ | 1985 | /* HKEY.MHKG() return bits */ |
1973 | #define TP_HOTKEY_TABLET_MASK (1 << 3) | 1986 | #define TP_HOTKEY_TABLET_MASK (1 << 3) |
1974 | 1987 | ||
@@ -2013,7 +2026,9 @@ static int hotkey_mask_get(void) | |||
2013 | if (!acpi_evalf(hkey_handle, &m, "DHKN", "d")) | 2026 | if (!acpi_evalf(hkey_handle, &m, "DHKN", "d")) |
2014 | return -EIO; | 2027 | return -EIO; |
2015 | } | 2028 | } |
2029 | HOTKEY_CONFIG_CRITICAL_START | ||
2016 | hotkey_mask = m | (hotkey_source_mask & hotkey_mask); | 2030 | hotkey_mask = m | (hotkey_source_mask & hotkey_mask); |
2031 | HOTKEY_CONFIG_CRITICAL_END | ||
2017 | 2032 | ||
2018 | return 0; | 2033 | return 0; |
2019 | } | 2034 | } |
@@ -2266,6 +2281,7 @@ static int hotkey_kthread(void *data) | |||
2266 | unsigned int si, so; | 2281 | unsigned int si, so; |
2267 | unsigned long t; | 2282 | unsigned long t; |
2268 | unsigned int change_detector, must_reset; | 2283 | unsigned int change_detector, must_reset; |
2284 | unsigned int poll_freq; | ||
2269 | 2285 | ||
2270 | mutex_lock(&hotkey_thread_mutex); | 2286 | mutex_lock(&hotkey_thread_mutex); |
2271 | 2287 | ||
@@ -2282,12 +2298,17 @@ static int hotkey_kthread(void *data) | |||
2282 | mutex_lock(&hotkey_thread_data_mutex); | 2298 | mutex_lock(&hotkey_thread_data_mutex); |
2283 | change_detector = hotkey_config_change; | 2299 | change_detector = hotkey_config_change; |
2284 | mask = hotkey_source_mask & hotkey_mask; | 2300 | mask = hotkey_source_mask & hotkey_mask; |
2301 | poll_freq = hotkey_poll_freq; | ||
2285 | mutex_unlock(&hotkey_thread_data_mutex); | 2302 | mutex_unlock(&hotkey_thread_data_mutex); |
2286 | hotkey_read_nvram(&s[so], mask); | 2303 | hotkey_read_nvram(&s[so], mask); |
2287 | 2304 | ||
2288 | while (!kthread_should_stop() && hotkey_poll_freq) { | 2305 | while (!kthread_should_stop()) { |
2289 | if (t == 0) | 2306 | if (t == 0) { |
2290 | t = 1000/hotkey_poll_freq; | 2307 | if (likely(poll_freq)) |
2308 | t = 1000/poll_freq; | ||
2309 | else | ||
2310 | t = 100; /* should never happen... */ | ||
2311 | } | ||
2291 | t = msleep_interruptible(t); | 2312 | t = msleep_interruptible(t); |
2292 | if (unlikely(kthread_should_stop())) | 2313 | if (unlikely(kthread_should_stop())) |
2293 | break; | 2314 | break; |
@@ -2303,6 +2324,7 @@ static int hotkey_kthread(void *data) | |||
2303 | change_detector = hotkey_config_change; | 2324 | change_detector = hotkey_config_change; |
2304 | } | 2325 | } |
2305 | mask = hotkey_source_mask & hotkey_mask; | 2326 | mask = hotkey_source_mask & hotkey_mask; |
2327 | poll_freq = hotkey_poll_freq; | ||
2306 | mutex_unlock(&hotkey_thread_data_mutex); | 2328 | mutex_unlock(&hotkey_thread_data_mutex); |
2307 | 2329 | ||
2308 | if (likely(mask)) { | 2330 | if (likely(mask)) { |
@@ -2322,6 +2344,7 @@ exit: | |||
2322 | return 0; | 2344 | return 0; |
2323 | } | 2345 | } |
2324 | 2346 | ||
2347 | /* call with hotkey_mutex held */ | ||
2325 | static void hotkey_poll_stop_sync(void) | 2348 | static void hotkey_poll_stop_sync(void) |
2326 | { | 2349 | { |
2327 | if (tpacpi_hotkey_task) { | 2350 | if (tpacpi_hotkey_task) { |
@@ -2338,10 +2361,11 @@ static void hotkey_poll_stop_sync(void) | |||
2338 | } | 2361 | } |
2339 | 2362 | ||
2340 | /* call with hotkey_mutex held */ | 2363 | /* call with hotkey_mutex held */ |
2341 | static void hotkey_poll_setup(int may_warn) | 2364 | static void hotkey_poll_setup(bool may_warn) |
2342 | { | 2365 | { |
2343 | if ((hotkey_source_mask & hotkey_mask) != 0 && | 2366 | u32 hotkeys_to_poll = hotkey_source_mask & hotkey_mask; |
2344 | hotkey_poll_freq > 0 && | 2367 | |
2368 | if (hotkeys_to_poll != 0 && hotkey_poll_freq > 0 && | ||
2345 | (tpacpi_inputdev->users > 0 || hotkey_report_mode < 2)) { | 2369 | (tpacpi_inputdev->users > 0 || hotkey_report_mode < 2)) { |
2346 | if (!tpacpi_hotkey_task) { | 2370 | if (!tpacpi_hotkey_task) { |
2347 | tpacpi_hotkey_task = kthread_run(hotkey_kthread, | 2371 | tpacpi_hotkey_task = kthread_run(hotkey_kthread, |
@@ -2355,26 +2379,37 @@ static void hotkey_poll_setup(int may_warn) | |||
2355 | } | 2379 | } |
2356 | } else { | 2380 | } else { |
2357 | hotkey_poll_stop_sync(); | 2381 | hotkey_poll_stop_sync(); |
2358 | if (may_warn && | 2382 | if (may_warn && hotkeys_to_poll != 0 && |
2359 | hotkey_source_mask != 0 && hotkey_poll_freq == 0) { | 2383 | hotkey_poll_freq == 0) { |
2360 | printk(TPACPI_NOTICE | 2384 | printk(TPACPI_NOTICE |
2361 | "hot keys 0x%08x require polling, " | 2385 | "hot keys 0x%08x require polling, " |
2362 | "which is currently disabled\n", | 2386 | "which is currently disabled\n", |
2363 | hotkey_source_mask); | 2387 | hotkeys_to_poll); |
2364 | } | 2388 | } |
2365 | } | 2389 | } |
2366 | } | 2390 | } |
2367 | 2391 | ||
2368 | static void hotkey_poll_setup_safe(int may_warn) | 2392 | static void hotkey_poll_setup_safe(bool may_warn) |
2369 | { | 2393 | { |
2370 | mutex_lock(&hotkey_mutex); | 2394 | mutex_lock(&hotkey_mutex); |
2371 | hotkey_poll_setup(may_warn); | 2395 | hotkey_poll_setup(may_warn); |
2372 | mutex_unlock(&hotkey_mutex); | 2396 | mutex_unlock(&hotkey_mutex); |
2373 | } | 2397 | } |
2374 | 2398 | ||
2399 | /* call with hotkey_mutex held */ | ||
2400 | static void hotkey_poll_set_freq(unsigned int freq) | ||
2401 | { | ||
2402 | if (!freq) | ||
2403 | hotkey_poll_stop_sync(); | ||
2404 | |||
2405 | HOTKEY_CONFIG_CRITICAL_START | ||
2406 | hotkey_poll_freq = freq; | ||
2407 | HOTKEY_CONFIG_CRITICAL_END | ||
2408 | } | ||
2409 | |||
2375 | #else /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */ | 2410 | #else /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */ |
2376 | 2411 | ||
2377 | static void hotkey_poll_setup_safe(int __unused) | 2412 | static void hotkey_poll_setup_safe(bool __unused) |
2378 | { | 2413 | { |
2379 | } | 2414 | } |
2380 | 2415 | ||
@@ -2392,7 +2427,7 @@ static int hotkey_inputdev_open(struct input_dev *dev) | |||
2392 | case TPACPI_LIFE_EXITING: | 2427 | case TPACPI_LIFE_EXITING: |
2393 | return -EBUSY; | 2428 | return -EBUSY; |
2394 | case TPACPI_LIFE_RUNNING: | 2429 | case TPACPI_LIFE_RUNNING: |
2395 | hotkey_poll_setup_safe(0); | 2430 | hotkey_poll_setup_safe(false); |
2396 | return 0; | 2431 | return 0; |
2397 | } | 2432 | } |
2398 | 2433 | ||
@@ -2405,7 +2440,7 @@ static void hotkey_inputdev_close(struct input_dev *dev) | |||
2405 | { | 2440 | { |
2406 | /* disable hotkey polling when possible */ | 2441 | /* disable hotkey polling when possible */ |
2407 | if (tpacpi_lifecycle == TPACPI_LIFE_RUNNING) | 2442 | if (tpacpi_lifecycle == TPACPI_LIFE_RUNNING) |
2408 | hotkey_poll_setup_safe(0); | 2443 | hotkey_poll_setup_safe(false); |
2409 | } | 2444 | } |
2410 | 2445 | ||
2411 | /* sysfs hotkey enable ------------------------------------------------- */ | 2446 | /* sysfs hotkey enable ------------------------------------------------- */ |
@@ -2479,7 +2514,7 @@ static ssize_t hotkey_mask_store(struct device *dev, | |||
2479 | res = hotkey_mask_set(t); | 2514 | res = hotkey_mask_set(t); |
2480 | 2515 | ||
2481 | #ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL | 2516 | #ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL |
2482 | hotkey_poll_setup(1); | 2517 | hotkey_poll_setup(true); |
2483 | #endif | 2518 | #endif |
2484 | 2519 | ||
2485 | mutex_unlock(&hotkey_mutex); | 2520 | mutex_unlock(&hotkey_mutex); |
@@ -2568,7 +2603,8 @@ static ssize_t hotkey_source_mask_store(struct device *dev, | |||
2568 | hotkey_source_mask = t; | 2603 | hotkey_source_mask = t; |
2569 | HOTKEY_CONFIG_CRITICAL_END | 2604 | HOTKEY_CONFIG_CRITICAL_END |
2570 | 2605 | ||
2571 | hotkey_poll_setup(1); | 2606 | hotkey_poll_setup(true); |
2607 | hotkey_mask_set(hotkey_mask); | ||
2572 | 2608 | ||
2573 | mutex_unlock(&hotkey_mutex); | 2609 | mutex_unlock(&hotkey_mutex); |
2574 | 2610 | ||
@@ -2601,9 +2637,9 @@ static ssize_t hotkey_poll_freq_store(struct device *dev, | |||
2601 | if (mutex_lock_killable(&hotkey_mutex)) | 2637 | if (mutex_lock_killable(&hotkey_mutex)) |
2602 | return -ERESTARTSYS; | 2638 | return -ERESTARTSYS; |
2603 | 2639 | ||
2604 | hotkey_poll_freq = t; | 2640 | hotkey_poll_set_freq(t); |
2641 | hotkey_poll_setup(true); | ||
2605 | 2642 | ||
2606 | hotkey_poll_setup(1); | ||
2607 | mutex_unlock(&hotkey_mutex); | 2643 | mutex_unlock(&hotkey_mutex); |
2608 | 2644 | ||
2609 | tpacpi_disclose_usertask("hotkey_poll_freq", "set to %lu\n", t); | 2645 | tpacpi_disclose_usertask("hotkey_poll_freq", "set to %lu\n", t); |
@@ -2794,7 +2830,9 @@ static void tpacpi_send_radiosw_update(void) | |||
2794 | static void hotkey_exit(void) | 2830 | static void hotkey_exit(void) |
2795 | { | 2831 | { |
2796 | #ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL | 2832 | #ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL |
2833 | mutex_lock(&hotkey_mutex); | ||
2797 | hotkey_poll_stop_sync(); | 2834 | hotkey_poll_stop_sync(); |
2835 | mutex_unlock(&hotkey_mutex); | ||
2798 | #endif | 2836 | #endif |
2799 | 2837 | ||
2800 | if (hotkey_dev_attributes) | 2838 | if (hotkey_dev_attributes) |
@@ -3031,7 +3069,7 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) | |||
3031 | } | 3069 | } |
3032 | 3070 | ||
3033 | vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_HKEY, | 3071 | vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_HKEY, |
3034 | "hotkey source mask 0x%08x, polling freq %d\n", | 3072 | "hotkey source mask 0x%08x, polling freq %u\n", |
3035 | hotkey_source_mask, hotkey_poll_freq); | 3073 | hotkey_source_mask, hotkey_poll_freq); |
3036 | #endif | 3074 | #endif |
3037 | 3075 | ||
@@ -3169,7 +3207,7 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) | |||
3169 | tpacpi_inputdev->open = &hotkey_inputdev_open; | 3207 | tpacpi_inputdev->open = &hotkey_inputdev_open; |
3170 | tpacpi_inputdev->close = &hotkey_inputdev_close; | 3208 | tpacpi_inputdev->close = &hotkey_inputdev_close; |
3171 | 3209 | ||
3172 | hotkey_poll_setup_safe(1); | 3210 | hotkey_poll_setup_safe(true); |
3173 | tpacpi_send_radiosw_update(); | 3211 | tpacpi_send_radiosw_update(); |
3174 | tpacpi_input_send_tabletsw(); | 3212 | tpacpi_input_send_tabletsw(); |
3175 | 3213 | ||
@@ -3457,7 +3495,7 @@ static void hotkey_resume(void) | |||
3457 | hotkey_tablet_mode_notify_change(); | 3495 | hotkey_tablet_mode_notify_change(); |
3458 | hotkey_wakeup_reason_notify_change(); | 3496 | hotkey_wakeup_reason_notify_change(); |
3459 | hotkey_wakeup_hotunplug_complete_notify_change(); | 3497 | hotkey_wakeup_hotunplug_complete_notify_change(); |
3460 | hotkey_poll_setup_safe(0); | 3498 | hotkey_poll_setup_safe(false); |
3461 | } | 3499 | } |
3462 | 3500 | ||
3463 | /* procfs -------------------------------------------------------------- */ | 3501 | /* procfs -------------------------------------------------------------- */ |