diff options
| -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 -------------------------------------------------------------- */ |
