diff options
Diffstat (limited to 'drivers/platform')
-rw-r--r-- | drivers/platform/x86/thinkpad_acpi.c | 478 |
1 files changed, 302 insertions, 176 deletions
diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index 66ba5f57d786..50aa4c112b28 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c | |||
@@ -22,7 +22,7 @@ | |||
22 | */ | 22 | */ |
23 | 23 | ||
24 | #define TPACPI_VERSION "0.23" | 24 | #define TPACPI_VERSION "0.23" |
25 | #define TPACPI_SYSFS_VERSION 0x020400 | 25 | #define TPACPI_SYSFS_VERSION 0x020500 |
26 | 26 | ||
27 | /* | 27 | /* |
28 | * Changelog: | 28 | * Changelog: |
@@ -1848,6 +1848,27 @@ static struct ibm_struct thinkpad_acpi_driver_data = { | |||
1848 | * Hotkey subdriver | 1848 | * Hotkey subdriver |
1849 | */ | 1849 | */ |
1850 | 1850 | ||
1851 | /* | ||
1852 | * ThinkPad firmware event model | ||
1853 | * | ||
1854 | * The ThinkPad firmware has two main event interfaces: normal ACPI | ||
1855 | * notifications (which follow the ACPI standard), and a private event | ||
1856 | * interface. | ||
1857 | * | ||
1858 | * The private event interface also issues events for the hotkeys. As | ||
1859 | * the driver gained features, the event handling code ended up being | ||
1860 | * built around the hotkey subdriver. This will need to be refactored | ||
1861 | * to a more formal event API eventually. | ||
1862 | * | ||
1863 | * Some "hotkeys" are actually supposed to be used as event reports, | ||
1864 | * such as "brightness has changed", "volume has changed", depending on | ||
1865 | * the ThinkPad model and how the firmware is operating. | ||
1866 | * | ||
1867 | * Unlike other classes, hotkey-class events have mask/unmask control on | ||
1868 | * non-ancient firmware. However, how it behaves changes a lot with the | ||
1869 | * firmware model and version. | ||
1870 | */ | ||
1871 | |||
1851 | enum { /* hot key scan codes (derived from ACPI DSDT) */ | 1872 | enum { /* hot key scan codes (derived from ACPI DSDT) */ |
1852 | TP_ACPI_HOTKEYSCAN_FNF1 = 0, | 1873 | TP_ACPI_HOTKEYSCAN_FNF1 = 0, |
1853 | TP_ACPI_HOTKEYSCAN_FNF2, | 1874 | TP_ACPI_HOTKEYSCAN_FNF2, |
@@ -1875,7 +1896,7 @@ enum { /* hot key scan codes (derived from ACPI DSDT) */ | |||
1875 | TP_ACPI_HOTKEYSCAN_THINKPAD, | 1896 | TP_ACPI_HOTKEYSCAN_THINKPAD, |
1876 | }; | 1897 | }; |
1877 | 1898 | ||
1878 | enum { /* Keys available through NVRAM polling */ | 1899 | enum { /* Keys/events available through NVRAM polling */ |
1879 | TPACPI_HKEY_NVRAM_KNOWN_MASK = 0x00fb88c0U, | 1900 | TPACPI_HKEY_NVRAM_KNOWN_MASK = 0x00fb88c0U, |
1880 | TPACPI_HKEY_NVRAM_GOOD_MASK = 0x00fb8000U, | 1901 | TPACPI_HKEY_NVRAM_GOOD_MASK = 0x00fb8000U, |
1881 | }; | 1902 | }; |
@@ -1930,8 +1951,11 @@ static struct task_struct *tpacpi_hotkey_task; | |||
1930 | static struct mutex hotkey_thread_mutex; | 1951 | static struct mutex hotkey_thread_mutex; |
1931 | 1952 | ||
1932 | /* | 1953 | /* |
1933 | * Acquire mutex to write poller control variables. | 1954 | * Acquire mutex to write poller control variables as an |
1934 | * Increment hotkey_config_change when changing them. | 1955 | * atomic block. |
1956 | * | ||
1957 | * Increment hotkey_config_change when changing them if you | ||
1958 | * want the kthread to forget old state. | ||
1935 | * | 1959 | * |
1936 | * See HOTKEY_CONFIG_CRITICAL_START/HOTKEY_CONFIG_CRITICAL_END | 1960 | * See HOTKEY_CONFIG_CRITICAL_START/HOTKEY_CONFIG_CRITICAL_END |
1937 | */ | 1961 | */ |
@@ -1942,6 +1966,11 @@ static unsigned int hotkey_config_change; | |||
1942 | * hotkey poller control variables | 1966 | * hotkey poller control variables |
1943 | * | 1967 | * |
1944 | * Must be atomic or readers will also need to acquire mutex | 1968 | * Must be atomic or readers will also need to acquire mutex |
1969 | * | ||
1970 | * HOTKEY_CONFIG_CRITICAL_START/HOTKEY_CONFIG_CRITICAL_END | ||
1971 | * should be used only when the changes need to be taken as | ||
1972 | * a block, OR when one needs to force the kthread to forget | ||
1973 | * old state. | ||
1945 | */ | 1974 | */ |
1946 | static u32 hotkey_source_mask; /* bit mask 0=ACPI,1=NVRAM */ | 1975 | static u32 hotkey_source_mask; /* bit mask 0=ACPI,1=NVRAM */ |
1947 | static unsigned int hotkey_poll_freq = 10; /* Hz */ | 1976 | static unsigned int hotkey_poll_freq = 10; /* Hz */ |
@@ -1972,10 +2001,12 @@ static enum { /* Reasons for waking up */ | |||
1972 | 2001 | ||
1973 | static int hotkey_autosleep_ack; | 2002 | static int hotkey_autosleep_ack; |
1974 | 2003 | ||
1975 | static u32 hotkey_orig_mask; | 2004 | static u32 hotkey_orig_mask; /* events the BIOS had enabled */ |
1976 | static u32 hotkey_all_mask; | 2005 | static u32 hotkey_all_mask; /* all events supported in fw */ |
1977 | static u32 hotkey_reserved_mask; | 2006 | static u32 hotkey_reserved_mask; /* events better left disabled */ |
1978 | static u32 hotkey_mask; | 2007 | static u32 hotkey_driver_mask; /* events needed by the driver */ |
2008 | static u32 hotkey_user_mask; /* events visible to userspace */ | ||
2009 | static u32 hotkey_acpi_mask; /* events enabled in firmware */ | ||
1979 | 2010 | ||
1980 | static unsigned int hotkey_report_mode; | 2011 | static unsigned int hotkey_report_mode; |
1981 | 2012 | ||
@@ -2017,24 +2048,53 @@ static int hotkey_get_tablet_mode(int *status) | |||
2017 | } | 2048 | } |
2018 | 2049 | ||
2019 | /* | 2050 | /* |
2051 | * Reads current event mask from firmware, and updates | ||
2052 | * hotkey_acpi_mask accordingly. Also resets any bits | ||
2053 | * from hotkey_user_mask that are unavailable to be | ||
2054 | * delivered (shadow requirement of the userspace ABI). | ||
2055 | * | ||
2020 | * Call with hotkey_mutex held | 2056 | * Call with hotkey_mutex held |
2021 | */ | 2057 | */ |
2022 | static int hotkey_mask_get(void) | 2058 | static int hotkey_mask_get(void) |
2023 | { | 2059 | { |
2024 | u32 m = 0; | ||
2025 | |||
2026 | if (tp_features.hotkey_mask) { | 2060 | if (tp_features.hotkey_mask) { |
2061 | u32 m = 0; | ||
2062 | |||
2027 | if (!acpi_evalf(hkey_handle, &m, "DHKN", "d")) | 2063 | if (!acpi_evalf(hkey_handle, &m, "DHKN", "d")) |
2028 | return -EIO; | 2064 | return -EIO; |
2065 | |||
2066 | hotkey_acpi_mask = m; | ||
2067 | } else { | ||
2068 | /* no mask support doesn't mean no event support... */ | ||
2069 | hotkey_acpi_mask = hotkey_all_mask; | ||
2029 | } | 2070 | } |
2030 | HOTKEY_CONFIG_CRITICAL_START | 2071 | |
2031 | hotkey_mask = m | (hotkey_source_mask & hotkey_mask); | 2072 | /* sync userspace-visible mask */ |
2032 | HOTKEY_CONFIG_CRITICAL_END | 2073 | hotkey_user_mask &= (hotkey_acpi_mask | hotkey_source_mask); |
2033 | 2074 | ||
2034 | return 0; | 2075 | return 0; |
2035 | } | 2076 | } |
2036 | 2077 | ||
2078 | void static hotkey_mask_warn_incomplete_mask(void) | ||
2079 | { | ||
2080 | /* log only what the user can fix... */ | ||
2081 | const u32 wantedmask = hotkey_driver_mask & | ||
2082 | ~(hotkey_acpi_mask | hotkey_source_mask) & | ||
2083 | (hotkey_all_mask | TPACPI_HKEY_NVRAM_KNOWN_MASK); | ||
2084 | |||
2085 | if (wantedmask) | ||
2086 | printk(TPACPI_NOTICE | ||
2087 | "required events 0x%08x not enabled!\n", | ||
2088 | wantedmask); | ||
2089 | } | ||
2090 | |||
2037 | /* | 2091 | /* |
2092 | * Set the firmware mask when supported | ||
2093 | * | ||
2094 | * Also calls hotkey_mask_get to update hotkey_acpi_mask. | ||
2095 | * | ||
2096 | * NOTE: does not set bits in hotkey_user_mask, but may reset them. | ||
2097 | * | ||
2038 | * Call with hotkey_mutex held | 2098 | * Call with hotkey_mutex held |
2039 | */ | 2099 | */ |
2040 | static int hotkey_mask_set(u32 mask) | 2100 | static int hotkey_mask_set(u32 mask) |
@@ -2042,66 +2102,69 @@ static int hotkey_mask_set(u32 mask) | |||
2042 | int i; | 2102 | int i; |
2043 | int rc = 0; | 2103 | int rc = 0; |
2044 | 2104 | ||
2045 | if (tp_features.hotkey_mask) { | 2105 | const u32 fwmask = mask & ~hotkey_source_mask; |
2046 | if (!tp_warned.hotkey_mask_ff && | ||
2047 | (mask == 0xffff || mask == 0xffffff || | ||
2048 | mask == 0xffffffff)) { | ||
2049 | tp_warned.hotkey_mask_ff = 1; | ||
2050 | printk(TPACPI_NOTICE | ||
2051 | "setting the hotkey mask to 0x%08x is likely " | ||
2052 | "not the best way to go about it\n", mask); | ||
2053 | printk(TPACPI_NOTICE | ||
2054 | "please consider using the driver defaults, " | ||
2055 | "and refer to up-to-date thinkpad-acpi " | ||
2056 | "documentation\n"); | ||
2057 | } | ||
2058 | 2106 | ||
2059 | HOTKEY_CONFIG_CRITICAL_START | 2107 | if (tp_features.hotkey_mask) { |
2060 | for (i = 0; i < 32; i++) { | 2108 | for (i = 0; i < 32; i++) { |
2061 | u32 m = 1 << i; | ||
2062 | /* enable in firmware mask only keys not in NVRAM | ||
2063 | * mode, but enable the key in the cached hotkey_mask | ||
2064 | * regardless of mode, or the key will end up | ||
2065 | * disabled by hotkey_mask_get() */ | ||
2066 | if (!acpi_evalf(hkey_handle, | 2109 | if (!acpi_evalf(hkey_handle, |
2067 | NULL, "MHKM", "vdd", i + 1, | 2110 | NULL, "MHKM", "vdd", i + 1, |
2068 | !!((mask & ~hotkey_source_mask) & m))) { | 2111 | !!(mask & (1 << i)))) { |
2069 | rc = -EIO; | 2112 | rc = -EIO; |
2070 | break; | 2113 | break; |
2071 | } else { | ||
2072 | hotkey_mask = (hotkey_mask & ~m) | (mask & m); | ||
2073 | } | 2114 | } |
2074 | } | 2115 | } |
2075 | HOTKEY_CONFIG_CRITICAL_END | 2116 | } |
2076 | 2117 | ||
2077 | /* hotkey_mask_get must be called unconditionally below */ | 2118 | /* |
2078 | if (!hotkey_mask_get() && !rc && | 2119 | * We *must* make an inconditional call to hotkey_mask_get to |
2079 | (hotkey_mask & ~hotkey_source_mask) != | 2120 | * refresh hotkey_acpi_mask and update hotkey_user_mask |
2080 | (mask & ~hotkey_source_mask)) { | 2121 | * |
2081 | printk(TPACPI_NOTICE | 2122 | * Take the opportunity to also log when we cannot _enable_ |
2082 | "requested hot key mask 0x%08x, but " | 2123 | * a given event. |
2083 | "firmware forced it to 0x%08x\n", | 2124 | */ |
2084 | mask, hotkey_mask); | 2125 | if (!hotkey_mask_get() && !rc && (fwmask & ~hotkey_acpi_mask)) { |
2085 | } | 2126 | printk(TPACPI_NOTICE |
2086 | } else { | 2127 | "asked for hotkey mask 0x%08x, but " |
2087 | #ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL | 2128 | "firmware forced it to 0x%08x\n", |
2088 | HOTKEY_CONFIG_CRITICAL_START | 2129 | fwmask, hotkey_acpi_mask); |
2089 | hotkey_mask = mask & hotkey_source_mask; | 2130 | } |
2090 | HOTKEY_CONFIG_CRITICAL_END | 2131 | |
2091 | hotkey_mask_get(); | 2132 | hotkey_mask_warn_incomplete_mask(); |
2092 | if (hotkey_mask != mask) { | 2133 | |
2093 | printk(TPACPI_NOTICE | 2134 | return rc; |
2094 | "requested hot key mask 0x%08x, " | 2135 | } |
2095 | "forced to 0x%08x (NVRAM poll mask is " | 2136 | |
2096 | "0x%08x): no firmware mask support\n", | 2137 | /* |
2097 | mask, hotkey_mask, hotkey_source_mask); | 2138 | * Sets hotkey_user_mask and tries to set the firmware mask |
2098 | } | 2139 | * |
2099 | #else | 2140 | * Call with hotkey_mutex held |
2100 | hotkey_mask_get(); | 2141 | */ |
2101 | rc = -ENXIO; | 2142 | static int hotkey_user_mask_set(const u32 mask) |
2102 | #endif /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */ | 2143 | { |
2144 | int rc; | ||
2145 | |||
2146 | /* Give people a chance to notice they are doing something that | ||
2147 | * is bound to go boom on their users sooner or later */ | ||
2148 | if (!tp_warned.hotkey_mask_ff && | ||
2149 | (mask == 0xffff || mask == 0xffffff || | ||
2150 | mask == 0xffffffff)) { | ||
2151 | tp_warned.hotkey_mask_ff = 1; | ||
2152 | printk(TPACPI_NOTICE | ||
2153 | "setting the hotkey mask to 0x%08x is likely " | ||
2154 | "not the best way to go about it\n", mask); | ||
2155 | printk(TPACPI_NOTICE | ||
2156 | "please consider using the driver defaults, " | ||
2157 | "and refer to up-to-date thinkpad-acpi " | ||
2158 | "documentation\n"); | ||
2103 | } | 2159 | } |
2104 | 2160 | ||
2161 | /* Try to enable what the user asked for, plus whatever we need. | ||
2162 | * this syncs everything but won't enable bits in hotkey_user_mask */ | ||
2163 | rc = hotkey_mask_set((mask | hotkey_driver_mask) & ~hotkey_source_mask); | ||
2164 | |||
2165 | /* Enable the available bits in hotkey_user_mask */ | ||
2166 | hotkey_user_mask = mask & (hotkey_acpi_mask | hotkey_source_mask); | ||
2167 | |||
2105 | return rc; | 2168 | return rc; |
2106 | } | 2169 | } |
2107 | 2170 | ||
@@ -2137,11 +2200,10 @@ static void tpacpi_input_send_tabletsw(void) | |||
2137 | } | 2200 | } |
2138 | } | 2201 | } |
2139 | 2202 | ||
2140 | static void tpacpi_input_send_key(unsigned int scancode) | 2203 | /* Do NOT call without validating scancode first */ |
2204 | static void tpacpi_input_send_key(const unsigned int scancode) | ||
2141 | { | 2205 | { |
2142 | unsigned int keycode; | 2206 | const unsigned int keycode = hotkey_keycode_map[scancode]; |
2143 | |||
2144 | keycode = hotkey_keycode_map[scancode]; | ||
2145 | 2207 | ||
2146 | if (keycode != KEY_RESERVED) { | 2208 | if (keycode != KEY_RESERVED) { |
2147 | mutex_lock(&tpacpi_inputdev_send_mutex); | 2209 | mutex_lock(&tpacpi_inputdev_send_mutex); |
@@ -2162,19 +2224,27 @@ static void tpacpi_input_send_key(unsigned int scancode) | |||
2162 | } | 2224 | } |
2163 | } | 2225 | } |
2164 | 2226 | ||
2227 | /* Do NOT call without validating scancode first */ | ||
2228 | static void tpacpi_input_send_key_masked(const unsigned int scancode) | ||
2229 | { | ||
2230 | if (hotkey_user_mask & (1 << scancode)) | ||
2231 | tpacpi_input_send_key(scancode); | ||
2232 | } | ||
2233 | |||
2165 | #ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL | 2234 | #ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL |
2166 | static struct tp_acpi_drv_struct ibm_hotkey_acpidriver; | 2235 | static struct tp_acpi_drv_struct ibm_hotkey_acpidriver; |
2167 | 2236 | ||
2237 | /* Do NOT call without validating scancode first */ | ||
2168 | static void tpacpi_hotkey_send_key(unsigned int scancode) | 2238 | static void tpacpi_hotkey_send_key(unsigned int scancode) |
2169 | { | 2239 | { |
2170 | tpacpi_input_send_key(scancode); | 2240 | tpacpi_input_send_key_masked(scancode); |
2171 | if (hotkey_report_mode < 2) { | 2241 | if (hotkey_report_mode < 2) { |
2172 | acpi_bus_generate_proc_event(ibm_hotkey_acpidriver.device, | 2242 | acpi_bus_generate_proc_event(ibm_hotkey_acpidriver.device, |
2173 | 0x80, 0x1001 + scancode); | 2243 | 0x80, 0x1001 + scancode); |
2174 | } | 2244 | } |
2175 | } | 2245 | } |
2176 | 2246 | ||
2177 | static void hotkey_read_nvram(struct tp_nvram_state *n, u32 m) | 2247 | static void hotkey_read_nvram(struct tp_nvram_state *n, const u32 m) |
2178 | { | 2248 | { |
2179 | u8 d; | 2249 | u8 d; |
2180 | 2250 | ||
@@ -2210,21 +2280,24 @@ static void hotkey_read_nvram(struct tp_nvram_state *n, u32 m) | |||
2210 | } | 2280 | } |
2211 | } | 2281 | } |
2212 | 2282 | ||
2283 | static void hotkey_compare_and_issue_event(struct tp_nvram_state *oldn, | ||
2284 | struct tp_nvram_state *newn, | ||
2285 | const u32 event_mask) | ||
2286 | { | ||
2287 | |||
2213 | #define TPACPI_COMPARE_KEY(__scancode, __member) \ | 2288 | #define TPACPI_COMPARE_KEY(__scancode, __member) \ |
2214 | do { \ | 2289 | do { \ |
2215 | if ((mask & (1 << __scancode)) && \ | 2290 | if ((event_mask & (1 << __scancode)) && \ |
2216 | oldn->__member != newn->__member) \ | 2291 | oldn->__member != newn->__member) \ |
2217 | tpacpi_hotkey_send_key(__scancode); \ | 2292 | tpacpi_hotkey_send_key(__scancode); \ |
2218 | } while (0) | 2293 | } while (0) |
2219 | 2294 | ||
2220 | #define TPACPI_MAY_SEND_KEY(__scancode) \ | 2295 | #define TPACPI_MAY_SEND_KEY(__scancode) \ |
2221 | do { if (mask & (1 << __scancode)) \ | 2296 | do { \ |
2222 | tpacpi_hotkey_send_key(__scancode); } while (0) | 2297 | if (event_mask & (1 << __scancode)) \ |
2298 | tpacpi_hotkey_send_key(__scancode); \ | ||
2299 | } while (0) | ||
2223 | 2300 | ||
2224 | static void hotkey_compare_and_issue_event(struct tp_nvram_state *oldn, | ||
2225 | struct tp_nvram_state *newn, | ||
2226 | u32 mask) | ||
2227 | { | ||
2228 | TPACPI_COMPARE_KEY(TP_ACPI_HOTKEYSCAN_THINKPAD, thinkpad_toggle); | 2301 | TPACPI_COMPARE_KEY(TP_ACPI_HOTKEYSCAN_THINKPAD, thinkpad_toggle); |
2229 | TPACPI_COMPARE_KEY(TP_ACPI_HOTKEYSCAN_FNSPACE, zoom_toggle); | 2302 | TPACPI_COMPARE_KEY(TP_ACPI_HOTKEYSCAN_FNSPACE, zoom_toggle); |
2230 | TPACPI_COMPARE_KEY(TP_ACPI_HOTKEYSCAN_FNF7, display_toggle); | 2303 | TPACPI_COMPARE_KEY(TP_ACPI_HOTKEYSCAN_FNF7, display_toggle); |
@@ -2270,15 +2343,22 @@ static void hotkey_compare_and_issue_event(struct tp_nvram_state *oldn, | |||
2270 | } | 2343 | } |
2271 | } | 2344 | } |
2272 | } | 2345 | } |
2273 | } | ||
2274 | 2346 | ||
2275 | #undef TPACPI_COMPARE_KEY | 2347 | #undef TPACPI_COMPARE_KEY |
2276 | #undef TPACPI_MAY_SEND_KEY | 2348 | #undef TPACPI_MAY_SEND_KEY |
2349 | } | ||
2277 | 2350 | ||
2351 | /* | ||
2352 | * Polling driver | ||
2353 | * | ||
2354 | * We track all events in hotkey_source_mask all the time, since | ||
2355 | * most of them are edge-based. We only issue those requested by | ||
2356 | * hotkey_user_mask or hotkey_driver_mask, though. | ||
2357 | */ | ||
2278 | static int hotkey_kthread(void *data) | 2358 | static int hotkey_kthread(void *data) |
2279 | { | 2359 | { |
2280 | struct tp_nvram_state s[2]; | 2360 | struct tp_nvram_state s[2]; |
2281 | u32 mask; | 2361 | u32 poll_mask, event_mask; |
2282 | unsigned int si, so; | 2362 | unsigned int si, so; |
2283 | unsigned long t; | 2363 | unsigned long t; |
2284 | unsigned int change_detector, must_reset; | 2364 | unsigned int change_detector, must_reset; |
@@ -2298,10 +2378,12 @@ static int hotkey_kthread(void *data) | |||
2298 | /* Initial state for compares */ | 2378 | /* Initial state for compares */ |
2299 | mutex_lock(&hotkey_thread_data_mutex); | 2379 | mutex_lock(&hotkey_thread_data_mutex); |
2300 | change_detector = hotkey_config_change; | 2380 | change_detector = hotkey_config_change; |
2301 | mask = hotkey_source_mask & hotkey_mask; | 2381 | poll_mask = hotkey_source_mask; |
2382 | event_mask = hotkey_source_mask & | ||
2383 | (hotkey_driver_mask | hotkey_user_mask); | ||
2302 | poll_freq = hotkey_poll_freq; | 2384 | poll_freq = hotkey_poll_freq; |
2303 | mutex_unlock(&hotkey_thread_data_mutex); | 2385 | mutex_unlock(&hotkey_thread_data_mutex); |
2304 | hotkey_read_nvram(&s[so], mask); | 2386 | hotkey_read_nvram(&s[so], poll_mask); |
2305 | 2387 | ||
2306 | while (!kthread_should_stop()) { | 2388 | while (!kthread_should_stop()) { |
2307 | if (t == 0) { | 2389 | if (t == 0) { |
@@ -2324,15 +2406,17 @@ static int hotkey_kthread(void *data) | |||
2324 | t = 0; | 2406 | t = 0; |
2325 | change_detector = hotkey_config_change; | 2407 | change_detector = hotkey_config_change; |
2326 | } | 2408 | } |
2327 | mask = hotkey_source_mask & hotkey_mask; | 2409 | poll_mask = hotkey_source_mask; |
2410 | event_mask = hotkey_source_mask & | ||
2411 | (hotkey_driver_mask | hotkey_user_mask); | ||
2328 | poll_freq = hotkey_poll_freq; | 2412 | poll_freq = hotkey_poll_freq; |
2329 | mutex_unlock(&hotkey_thread_data_mutex); | 2413 | mutex_unlock(&hotkey_thread_data_mutex); |
2330 | 2414 | ||
2331 | if (likely(mask)) { | 2415 | if (likely(poll_mask)) { |
2332 | hotkey_read_nvram(&s[si], mask); | 2416 | hotkey_read_nvram(&s[si], poll_mask); |
2333 | if (likely(si != so)) { | 2417 | if (likely(si != so)) { |
2334 | hotkey_compare_and_issue_event(&s[so], &s[si], | 2418 | hotkey_compare_and_issue_event(&s[so], &s[si], |
2335 | mask); | 2419 | event_mask); |
2336 | } | 2420 | } |
2337 | } | 2421 | } |
2338 | 2422 | ||
@@ -2364,10 +2448,12 @@ static void hotkey_poll_stop_sync(void) | |||
2364 | /* call with hotkey_mutex held */ | 2448 | /* call with hotkey_mutex held */ |
2365 | static void hotkey_poll_setup(bool may_warn) | 2449 | static void hotkey_poll_setup(bool may_warn) |
2366 | { | 2450 | { |
2367 | u32 hotkeys_to_poll = hotkey_source_mask & hotkey_mask; | 2451 | const u32 poll_driver_mask = hotkey_driver_mask & hotkey_source_mask; |
2452 | const u32 poll_user_mask = hotkey_user_mask & hotkey_source_mask; | ||
2368 | 2453 | ||
2369 | if (hotkeys_to_poll != 0 && hotkey_poll_freq > 0 && | 2454 | if (hotkey_poll_freq > 0 && |
2370 | (tpacpi_inputdev->users > 0 || hotkey_report_mode < 2)) { | 2455 | (poll_driver_mask || |
2456 | (poll_user_mask && tpacpi_inputdev->users > 0))) { | ||
2371 | if (!tpacpi_hotkey_task) { | 2457 | if (!tpacpi_hotkey_task) { |
2372 | tpacpi_hotkey_task = kthread_run(hotkey_kthread, | 2458 | tpacpi_hotkey_task = kthread_run(hotkey_kthread, |
2373 | NULL, TPACPI_NVRAM_KTHREAD_NAME); | 2459 | NULL, TPACPI_NVRAM_KTHREAD_NAME); |
@@ -2380,12 +2466,13 @@ static void hotkey_poll_setup(bool may_warn) | |||
2380 | } | 2466 | } |
2381 | } else { | 2467 | } else { |
2382 | hotkey_poll_stop_sync(); | 2468 | hotkey_poll_stop_sync(); |
2383 | if (may_warn && hotkeys_to_poll != 0 && | 2469 | if (may_warn && (poll_driver_mask || poll_user_mask) && |
2384 | hotkey_poll_freq == 0) { | 2470 | hotkey_poll_freq == 0) { |
2385 | printk(TPACPI_NOTICE | 2471 | printk(TPACPI_NOTICE |
2386 | "hot keys 0x%08x require polling, " | 2472 | "hot keys 0x%08x and/or events 0x%08x " |
2387 | "which is currently disabled\n", | 2473 | "require polling, which is currently " |
2388 | hotkeys_to_poll); | 2474 | "disabled\n", |
2475 | poll_user_mask, poll_driver_mask); | ||
2389 | } | 2476 | } |
2390 | } | 2477 | } |
2391 | } | 2478 | } |
@@ -2403,9 +2490,7 @@ static void hotkey_poll_set_freq(unsigned int freq) | |||
2403 | if (!freq) | 2490 | if (!freq) |
2404 | hotkey_poll_stop_sync(); | 2491 | hotkey_poll_stop_sync(); |
2405 | 2492 | ||
2406 | HOTKEY_CONFIG_CRITICAL_START | ||
2407 | hotkey_poll_freq = freq; | 2493 | hotkey_poll_freq = freq; |
2408 | HOTKEY_CONFIG_CRITICAL_END | ||
2409 | } | 2494 | } |
2410 | 2495 | ||
2411 | #else /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */ | 2496 | #else /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */ |
@@ -2440,7 +2525,8 @@ static int hotkey_inputdev_open(struct input_dev *dev) | |||
2440 | static void hotkey_inputdev_close(struct input_dev *dev) | 2525 | static void hotkey_inputdev_close(struct input_dev *dev) |
2441 | { | 2526 | { |
2442 | /* disable hotkey polling when possible */ | 2527 | /* disable hotkey polling when possible */ |
2443 | if (tpacpi_lifecycle == TPACPI_LIFE_RUNNING) | 2528 | if (tpacpi_lifecycle == TPACPI_LIFE_RUNNING && |
2529 | !(hotkey_source_mask & hotkey_driver_mask)) | ||
2444 | hotkey_poll_setup_safe(false); | 2530 | hotkey_poll_setup_safe(false); |
2445 | } | 2531 | } |
2446 | 2532 | ||
@@ -2488,15 +2574,7 @@ static ssize_t hotkey_mask_show(struct device *dev, | |||
2488 | struct device_attribute *attr, | 2574 | struct device_attribute *attr, |
2489 | char *buf) | 2575 | char *buf) |
2490 | { | 2576 | { |
2491 | int res; | 2577 | return snprintf(buf, PAGE_SIZE, "0x%08x\n", hotkey_user_mask); |
2492 | |||
2493 | if (mutex_lock_killable(&hotkey_mutex)) | ||
2494 | return -ERESTARTSYS; | ||
2495 | res = hotkey_mask_get(); | ||
2496 | mutex_unlock(&hotkey_mutex); | ||
2497 | |||
2498 | return (res)? | ||
2499 | res : snprintf(buf, PAGE_SIZE, "0x%08x\n", hotkey_mask); | ||
2500 | } | 2578 | } |
2501 | 2579 | ||
2502 | static ssize_t hotkey_mask_store(struct device *dev, | 2580 | static ssize_t hotkey_mask_store(struct device *dev, |
@@ -2512,7 +2590,7 @@ static ssize_t hotkey_mask_store(struct device *dev, | |||
2512 | if (mutex_lock_killable(&hotkey_mutex)) | 2590 | if (mutex_lock_killable(&hotkey_mutex)) |
2513 | return -ERESTARTSYS; | 2591 | return -ERESTARTSYS; |
2514 | 2592 | ||
2515 | res = hotkey_mask_set(t); | 2593 | res = hotkey_user_mask_set(t); |
2516 | 2594 | ||
2517 | #ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL | 2595 | #ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL |
2518 | hotkey_poll_setup(true); | 2596 | hotkey_poll_setup(true); |
@@ -2594,6 +2672,8 @@ static ssize_t hotkey_source_mask_store(struct device *dev, | |||
2594 | const char *buf, size_t count) | 2672 | const char *buf, size_t count) |
2595 | { | 2673 | { |
2596 | unsigned long t; | 2674 | unsigned long t; |
2675 | u32 r_ev; | ||
2676 | int rc; | ||
2597 | 2677 | ||
2598 | if (parse_strtoul(buf, 0xffffffffUL, &t) || | 2678 | if (parse_strtoul(buf, 0xffffffffUL, &t) || |
2599 | ((t & ~TPACPI_HKEY_NVRAM_KNOWN_MASK) != 0)) | 2679 | ((t & ~TPACPI_HKEY_NVRAM_KNOWN_MASK) != 0)) |
@@ -2606,14 +2686,28 @@ static ssize_t hotkey_source_mask_store(struct device *dev, | |||
2606 | hotkey_source_mask = t; | 2686 | hotkey_source_mask = t; |
2607 | HOTKEY_CONFIG_CRITICAL_END | 2687 | HOTKEY_CONFIG_CRITICAL_END |
2608 | 2688 | ||
2689 | rc = hotkey_mask_set((hotkey_user_mask | hotkey_driver_mask) & | ||
2690 | ~hotkey_source_mask); | ||
2609 | hotkey_poll_setup(true); | 2691 | hotkey_poll_setup(true); |
2610 | hotkey_mask_set(hotkey_mask); | 2692 | |
2693 | /* check if events needed by the driver got disabled */ | ||
2694 | r_ev = hotkey_driver_mask & ~(hotkey_acpi_mask & hotkey_all_mask) | ||
2695 | & ~hotkey_source_mask & TPACPI_HKEY_NVRAM_KNOWN_MASK; | ||
2611 | 2696 | ||
2612 | mutex_unlock(&hotkey_mutex); | 2697 | mutex_unlock(&hotkey_mutex); |
2613 | 2698 | ||
2699 | if (rc < 0) | ||
2700 | printk(TPACPI_ERR "hotkey_source_mask: failed to update the" | ||
2701 | "firmware event mask!\n"); | ||
2702 | |||
2703 | if (r_ev) | ||
2704 | printk(TPACPI_NOTICE "hotkey_source_mask: " | ||
2705 | "some important events were disabled: " | ||
2706 | "0x%04x\n", r_ev); | ||
2707 | |||
2614 | tpacpi_disclose_usertask("hotkey_source_mask", "set to 0x%08lx\n", t); | 2708 | tpacpi_disclose_usertask("hotkey_source_mask", "set to 0x%08lx\n", t); |
2615 | 2709 | ||
2616 | return count; | 2710 | return (rc < 0) ? rc : count; |
2617 | } | 2711 | } |
2618 | 2712 | ||
2619 | static struct device_attribute dev_attr_hotkey_source_mask = | 2713 | static struct device_attribute dev_attr_hotkey_source_mask = |
@@ -2731,9 +2825,8 @@ static struct device_attribute dev_attr_hotkey_wakeup_reason = | |||
2731 | 2825 | ||
2732 | static void hotkey_wakeup_reason_notify_change(void) | 2826 | static void hotkey_wakeup_reason_notify_change(void) |
2733 | { | 2827 | { |
2734 | if (tp_features.hotkey_mask) | 2828 | sysfs_notify(&tpacpi_pdev->dev.kobj, NULL, |
2735 | sysfs_notify(&tpacpi_pdev->dev.kobj, NULL, | 2829 | "wakeup_reason"); |
2736 | "wakeup_reason"); | ||
2737 | } | 2830 | } |
2738 | 2831 | ||
2739 | /* sysfs wakeup hotunplug_complete (pollable) -------------------------- */ | 2832 | /* sysfs wakeup hotunplug_complete (pollable) -------------------------- */ |
@@ -2750,9 +2843,8 @@ static struct device_attribute dev_attr_hotkey_wakeup_hotunplug_complete = | |||
2750 | 2843 | ||
2751 | static void hotkey_wakeup_hotunplug_complete_notify_change(void) | 2844 | static void hotkey_wakeup_hotunplug_complete_notify_change(void) |
2752 | { | 2845 | { |
2753 | if (tp_features.hotkey_mask) | 2846 | sysfs_notify(&tpacpi_pdev->dev.kobj, NULL, |
2754 | sysfs_notify(&tpacpi_pdev->dev.kobj, NULL, | 2847 | "wakeup_hotunplug_complete"); |
2755 | "wakeup_hotunplug_complete"); | ||
2756 | } | 2848 | } |
2757 | 2849 | ||
2758 | /* --------------------------------------------------------------------- */ | 2850 | /* --------------------------------------------------------------------- */ |
@@ -2760,27 +2852,19 @@ static void hotkey_wakeup_hotunplug_complete_notify_change(void) | |||
2760 | static struct attribute *hotkey_attributes[] __initdata = { | 2852 | static struct attribute *hotkey_attributes[] __initdata = { |
2761 | &dev_attr_hotkey_enable.attr, | 2853 | &dev_attr_hotkey_enable.attr, |
2762 | &dev_attr_hotkey_bios_enabled.attr, | 2854 | &dev_attr_hotkey_bios_enabled.attr, |
2855 | &dev_attr_hotkey_bios_mask.attr, | ||
2763 | &dev_attr_hotkey_report_mode.attr, | 2856 | &dev_attr_hotkey_report_mode.attr, |
2764 | #ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL | 2857 | &dev_attr_hotkey_wakeup_reason.attr, |
2858 | &dev_attr_hotkey_wakeup_hotunplug_complete.attr, | ||
2765 | &dev_attr_hotkey_mask.attr, | 2859 | &dev_attr_hotkey_mask.attr, |
2766 | &dev_attr_hotkey_all_mask.attr, | 2860 | &dev_attr_hotkey_all_mask.attr, |
2767 | &dev_attr_hotkey_recommended_mask.attr, | 2861 | &dev_attr_hotkey_recommended_mask.attr, |
2862 | #ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL | ||
2768 | &dev_attr_hotkey_source_mask.attr, | 2863 | &dev_attr_hotkey_source_mask.attr, |
2769 | &dev_attr_hotkey_poll_freq.attr, | 2864 | &dev_attr_hotkey_poll_freq.attr, |
2770 | #endif | 2865 | #endif |
2771 | }; | 2866 | }; |
2772 | 2867 | ||
2773 | static struct attribute *hotkey_mask_attributes[] __initdata = { | ||
2774 | &dev_attr_hotkey_bios_mask.attr, | ||
2775 | #ifndef CONFIG_THINKPAD_ACPI_HOTKEY_POLL | ||
2776 | &dev_attr_hotkey_mask.attr, | ||
2777 | &dev_attr_hotkey_all_mask.attr, | ||
2778 | &dev_attr_hotkey_recommended_mask.attr, | ||
2779 | #endif | ||
2780 | &dev_attr_hotkey_wakeup_reason.attr, | ||
2781 | &dev_attr_hotkey_wakeup_hotunplug_complete.attr, | ||
2782 | }; | ||
2783 | |||
2784 | /* | 2868 | /* |
2785 | * Sync both the hw and sw blocking state of all switches | 2869 | * Sync both the hw and sw blocking state of all switches |
2786 | */ | 2870 | */ |
@@ -2844,10 +2928,12 @@ static void hotkey_exit(void) | |||
2844 | kfree(hotkey_keycode_map); | 2928 | kfree(hotkey_keycode_map); |
2845 | 2929 | ||
2846 | dbg_printk(TPACPI_DBG_EXIT | TPACPI_DBG_HKEY, | 2930 | dbg_printk(TPACPI_DBG_EXIT | TPACPI_DBG_HKEY, |
2847 | "restoring original hot key mask\n"); | 2931 | "restoring original HKEY status and mask\n"); |
2848 | /* no short-circuit boolean operator below! */ | 2932 | /* yes, there is a bitwise or below, we want the |
2849 | if (((tp_features.hotkey_mask && hotkey_mask_set(hotkey_orig_mask)) | 2933 | * functions to be called even if one of them fail */ |
2850 | | hotkey_status_set(false)) != 0) | 2934 | if (((tp_features.hotkey_mask && |
2935 | hotkey_mask_set(hotkey_orig_mask)) | | ||
2936 | hotkey_status_set(false)) != 0) | ||
2851 | printk(TPACPI_ERR | 2937 | printk(TPACPI_ERR |
2852 | "failed to restore hot key mask " | 2938 | "failed to restore hot key mask " |
2853 | "to BIOS defaults\n"); | 2939 | "to BIOS defaults\n"); |
@@ -2862,6 +2948,35 @@ static void __init hotkey_unmap(const unsigned int scancode) | |||
2862 | } | 2948 | } |
2863 | } | 2949 | } |
2864 | 2950 | ||
2951 | /* | ||
2952 | * HKEY quirks: | ||
2953 | * TPACPI_HK_Q_INIMASK: Supports FN+F3,FN+F4,FN+F12 | ||
2954 | */ | ||
2955 | |||
2956 | #define TPACPI_HK_Q_INIMASK 0x0001 | ||
2957 | |||
2958 | static const struct tpacpi_quirk tpacpi_hotkey_qtable[] __initconst = { | ||
2959 | TPACPI_Q_IBM('I', 'H', TPACPI_HK_Q_INIMASK), /* 600E */ | ||
2960 | TPACPI_Q_IBM('I', 'N', TPACPI_HK_Q_INIMASK), /* 600E */ | ||
2961 | TPACPI_Q_IBM('I', 'D', TPACPI_HK_Q_INIMASK), /* 770, 770E, 770ED */ | ||
2962 | TPACPI_Q_IBM('I', 'W', TPACPI_HK_Q_INIMASK), /* A20m */ | ||
2963 | TPACPI_Q_IBM('I', 'V', TPACPI_HK_Q_INIMASK), /* A20p */ | ||
2964 | TPACPI_Q_IBM('1', '0', TPACPI_HK_Q_INIMASK), /* A21e, A22e */ | ||
2965 | TPACPI_Q_IBM('K', 'U', TPACPI_HK_Q_INIMASK), /* A21e */ | ||
2966 | TPACPI_Q_IBM('K', 'X', TPACPI_HK_Q_INIMASK), /* A21m, A22m */ | ||
2967 | TPACPI_Q_IBM('K', 'Y', TPACPI_HK_Q_INIMASK), /* A21p, A22p */ | ||
2968 | TPACPI_Q_IBM('1', 'B', TPACPI_HK_Q_INIMASK), /* A22e */ | ||
2969 | TPACPI_Q_IBM('1', '3', TPACPI_HK_Q_INIMASK), /* A22m */ | ||
2970 | TPACPI_Q_IBM('1', 'E', TPACPI_HK_Q_INIMASK), /* A30/p (0) */ | ||
2971 | TPACPI_Q_IBM('1', 'C', TPACPI_HK_Q_INIMASK), /* R30 */ | ||
2972 | TPACPI_Q_IBM('1', 'F', TPACPI_HK_Q_INIMASK), /* R31 */ | ||
2973 | TPACPI_Q_IBM('I', 'Y', TPACPI_HK_Q_INIMASK), /* T20 */ | ||
2974 | TPACPI_Q_IBM('K', 'Z', TPACPI_HK_Q_INIMASK), /* T21 */ | ||
2975 | TPACPI_Q_IBM('1', '6', TPACPI_HK_Q_INIMASK), /* T22 */ | ||
2976 | TPACPI_Q_IBM('I', 'Z', TPACPI_HK_Q_INIMASK), /* X20, X21 */ | ||
2977 | TPACPI_Q_IBM('1', 'D', TPACPI_HK_Q_INIMASK), /* X22, X23, X24 */ | ||
2978 | }; | ||
2979 | |||
2865 | static int __init hotkey_init(struct ibm_init_struct *iibm) | 2980 | static int __init hotkey_init(struct ibm_init_struct *iibm) |
2866 | { | 2981 | { |
2867 | /* Requirements for changing the default keymaps: | 2982 | /* Requirements for changing the default keymaps: |
@@ -2904,9 +3019,7 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) | |||
2904 | KEY_UNKNOWN, /* 0x0D: FN+INSERT */ | 3019 | KEY_UNKNOWN, /* 0x0D: FN+INSERT */ |
2905 | KEY_UNKNOWN, /* 0x0E: FN+DELETE */ | 3020 | KEY_UNKNOWN, /* 0x0E: FN+DELETE */ |
2906 | 3021 | ||
2907 | /* brightness: firmware always reacts to them, unless | 3022 | /* brightness: firmware always reacts to them */ |
2908 | * X.org did some tricks in the radeon BIOS scratch | ||
2909 | * registers of *some* models */ | ||
2910 | KEY_RESERVED, /* 0x0F: FN+HOME (brightness up) */ | 3023 | KEY_RESERVED, /* 0x0F: FN+HOME (brightness up) */ |
2911 | KEY_RESERVED, /* 0x10: FN+END (brightness down) */ | 3024 | KEY_RESERVED, /* 0x10: FN+END (brightness down) */ |
2912 | 3025 | ||
@@ -2981,6 +3094,8 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) | |||
2981 | int status; | 3094 | int status; |
2982 | int hkeyv; | 3095 | int hkeyv; |
2983 | 3096 | ||
3097 | unsigned long quirks; | ||
3098 | |||
2984 | vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_HKEY, | 3099 | vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_HKEY, |
2985 | "initializing hotkey subdriver\n"); | 3100 | "initializing hotkey subdriver\n"); |
2986 | 3101 | ||
@@ -3006,9 +3121,16 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) | |||
3006 | if (!tp_features.hotkey) | 3121 | if (!tp_features.hotkey) |
3007 | return 1; | 3122 | return 1; |
3008 | 3123 | ||
3124 | quirks = tpacpi_check_quirks(tpacpi_hotkey_qtable, | ||
3125 | ARRAY_SIZE(tpacpi_hotkey_qtable)); | ||
3126 | |||
3009 | tpacpi_disable_brightness_delay(); | 3127 | tpacpi_disable_brightness_delay(); |
3010 | 3128 | ||
3011 | hotkey_dev_attributes = create_attr_set(13, NULL); | 3129 | /* MUST have enough space for all attributes to be added to |
3130 | * hotkey_dev_attributes */ | ||
3131 | hotkey_dev_attributes = create_attr_set( | ||
3132 | ARRAY_SIZE(hotkey_attributes) + 2, | ||
3133 | NULL); | ||
3012 | if (!hotkey_dev_attributes) | 3134 | if (!hotkey_dev_attributes) |
3013 | return -ENOMEM; | 3135 | return -ENOMEM; |
3014 | res = add_many_to_attr_set(hotkey_dev_attributes, | 3136 | res = add_many_to_attr_set(hotkey_dev_attributes, |
@@ -3017,7 +3139,7 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) | |||
3017 | if (res) | 3139 | if (res) |
3018 | goto err_exit; | 3140 | goto err_exit; |
3019 | 3141 | ||
3020 | /* mask not supported on 570, 600e/x, 770e, 770x, A21e, A2xm/p, | 3142 | /* mask not supported on 600e/x, 770e, 770x, A21e, A2xm/p, |
3021 | A30, R30, R31, T20-22, X20-21, X22-24. Detected by checking | 3143 | A30, R30, R31, T20-22, X20-21, X22-24. Detected by checking |
3022 | for HKEY interface version 0x100 */ | 3144 | for HKEY interface version 0x100 */ |
3023 | if (acpi_evalf(hkey_handle, &hkeyv, "MHKV", "qd")) { | 3145 | if (acpi_evalf(hkey_handle, &hkeyv, "MHKV", "qd")) { |
@@ -3031,10 +3153,22 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) | |||
3031 | * MHKV 0x100 in A31, R40, R40e, | 3153 | * MHKV 0x100 in A31, R40, R40e, |
3032 | * T4x, X31, and later | 3154 | * T4x, X31, and later |
3033 | */ | 3155 | */ |
3034 | tp_features.hotkey_mask = 1; | ||
3035 | vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_HKEY, | 3156 | vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_HKEY, |
3036 | "firmware HKEY interface version: 0x%x\n", | 3157 | "firmware HKEY interface version: 0x%x\n", |
3037 | hkeyv); | 3158 | hkeyv); |
3159 | |||
3160 | /* Paranoia check AND init hotkey_all_mask */ | ||
3161 | if (!acpi_evalf(hkey_handle, &hotkey_all_mask, | ||
3162 | "MHKA", "qd")) { | ||
3163 | printk(TPACPI_ERR | ||
3164 | "missing MHKA handler, " | ||
3165 | "please report this to %s\n", | ||
3166 | TPACPI_MAIL); | ||
3167 | /* Fallback: pre-init for FN+F3,F4,F12 */ | ||
3168 | hotkey_all_mask = 0x080cU; | ||
3169 | } else { | ||
3170 | tp_features.hotkey_mask = 1; | ||
3171 | } | ||
3038 | } | 3172 | } |
3039 | } | 3173 | } |
3040 | 3174 | ||
@@ -3042,32 +3176,23 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) | |||
3042 | "hotkey masks are %s\n", | 3176 | "hotkey masks are %s\n", |
3043 | str_supported(tp_features.hotkey_mask)); | 3177 | str_supported(tp_features.hotkey_mask)); |
3044 | 3178 | ||
3045 | if (tp_features.hotkey_mask) { | 3179 | /* Init hotkey_all_mask if not initialized yet */ |
3046 | if (!acpi_evalf(hkey_handle, &hotkey_all_mask, | 3180 | if (!tp_features.hotkey_mask && !hotkey_all_mask && |
3047 | "MHKA", "qd")) { | 3181 | (quirks & TPACPI_HK_Q_INIMASK)) |
3048 | printk(TPACPI_ERR | 3182 | hotkey_all_mask = 0x080cU; /* FN+F12, FN+F4, FN+F3 */ |
3049 | "missing MHKA handler, " | ||
3050 | "please report this to %s\n", | ||
3051 | TPACPI_MAIL); | ||
3052 | /* FN+F12, FN+F4, FN+F3 */ | ||
3053 | hotkey_all_mask = 0x080cU; | ||
3054 | } | ||
3055 | } | ||
3056 | 3183 | ||
3057 | /* hotkey_source_mask *must* be zero for | 3184 | /* Init hotkey_acpi_mask and hotkey_orig_mask */ |
3058 | * the first hotkey_mask_get */ | ||
3059 | if (tp_features.hotkey_mask) { | 3185 | if (tp_features.hotkey_mask) { |
3186 | /* hotkey_source_mask *must* be zero for | ||
3187 | * the first hotkey_mask_get to return hotkey_orig_mask */ | ||
3060 | res = hotkey_mask_get(); | 3188 | res = hotkey_mask_get(); |
3061 | if (res) | 3189 | if (res) |
3062 | goto err_exit; | 3190 | goto err_exit; |
3063 | 3191 | ||
3064 | hotkey_orig_mask = hotkey_mask; | 3192 | hotkey_orig_mask = hotkey_acpi_mask; |
3065 | res = add_many_to_attr_set( | 3193 | } else { |
3066 | hotkey_dev_attributes, | 3194 | hotkey_orig_mask = hotkey_all_mask; |
3067 | hotkey_mask_attributes, | 3195 | hotkey_acpi_mask = hotkey_all_mask; |
3068 | ARRAY_SIZE(hotkey_mask_attributes)); | ||
3069 | if (res) | ||
3070 | goto err_exit; | ||
3071 | } | 3196 | } |
3072 | 3197 | ||
3073 | #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES | 3198 | #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES |
@@ -3181,14 +3306,9 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) | |||
3181 | } | 3306 | } |
3182 | 3307 | ||
3183 | #ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL | 3308 | #ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL |
3184 | if (tp_features.hotkey_mask) { | 3309 | hotkey_source_mask = TPACPI_HKEY_NVRAM_GOOD_MASK |
3185 | hotkey_source_mask = TPACPI_HKEY_NVRAM_GOOD_MASK | 3310 | & ~hotkey_all_mask |
3186 | & ~hotkey_all_mask | 3311 | & ~hotkey_reserved_mask; |
3187 | & ~hotkey_reserved_mask; | ||
3188 | } else { | ||
3189 | hotkey_source_mask = TPACPI_HKEY_NVRAM_GOOD_MASK | ||
3190 | & ~hotkey_reserved_mask; | ||
3191 | } | ||
3192 | 3312 | ||
3193 | vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_HKEY, | 3313 | vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_HKEY, |
3194 | "hotkey source mask 0x%08x, polling freq %u\n", | 3314 | "hotkey source mask 0x%08x, polling freq %u\n", |
@@ -3202,13 +3322,18 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) | |||
3202 | hotkey_exit(); | 3322 | hotkey_exit(); |
3203 | return res; | 3323 | return res; |
3204 | } | 3324 | } |
3205 | res = hotkey_mask_set(((hotkey_all_mask | hotkey_source_mask) | 3325 | res = hotkey_mask_set(((hotkey_all_mask & ~hotkey_reserved_mask) |
3206 | & ~hotkey_reserved_mask) | 3326 | | hotkey_driver_mask) |
3207 | | hotkey_orig_mask); | 3327 | & ~hotkey_source_mask); |
3208 | if (res < 0 && res != -ENXIO) { | 3328 | if (res < 0 && res != -ENXIO) { |
3209 | hotkey_exit(); | 3329 | hotkey_exit(); |
3210 | return res; | 3330 | return res; |
3211 | } | 3331 | } |
3332 | hotkey_user_mask = (hotkey_acpi_mask | hotkey_source_mask) | ||
3333 | & ~hotkey_reserved_mask; | ||
3334 | vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_HKEY, | ||
3335 | "initial masks: user=0x%08x, fw=0x%08x, poll=0x%08x\n", | ||
3336 | hotkey_user_mask, hotkey_acpi_mask, hotkey_source_mask); | ||
3212 | 3337 | ||
3213 | dbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_HKEY, | 3338 | dbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_HKEY, |
3214 | "legacy ibm/hotkey event reporting over procfs %s\n", | 3339 | "legacy ibm/hotkey event reporting over procfs %s\n", |
@@ -3243,7 +3368,7 @@ static bool hotkey_notify_hotkey(const u32 hkey, | |||
3243 | if (scancode > 0 && scancode < 0x21) { | 3368 | if (scancode > 0 && scancode < 0x21) { |
3244 | scancode--; | 3369 | scancode--; |
3245 | if (!(hotkey_source_mask & (1 << scancode))) { | 3370 | if (!(hotkey_source_mask & (1 << scancode))) { |
3246 | tpacpi_input_send_key(scancode); | 3371 | tpacpi_input_send_key_masked(scancode); |
3247 | *send_acpi_ev = false; | 3372 | *send_acpi_ev = false; |
3248 | } else { | 3373 | } else { |
3249 | *ignore_acpi_ev = true; | 3374 | *ignore_acpi_ev = true; |
@@ -3498,10 +3623,12 @@ static void hotkey_resume(void) | |||
3498 | { | 3623 | { |
3499 | tpacpi_disable_brightness_delay(); | 3624 | tpacpi_disable_brightness_delay(); |
3500 | 3625 | ||
3501 | if (hotkey_mask_get()) | 3626 | if (hotkey_status_set(true) < 0 || |
3627 | hotkey_mask_set(hotkey_acpi_mask) < 0) | ||
3502 | printk(TPACPI_ERR | 3628 | printk(TPACPI_ERR |
3503 | "error while trying to read hot key mask " | 3629 | "error while attempting to reset the event " |
3504 | "from firmware\n"); | 3630 | "firmware interface\n"); |
3631 | |||
3505 | tpacpi_send_radiosw_update(); | 3632 | tpacpi_send_radiosw_update(); |
3506 | hotkey_tablet_mode_notify_change(); | 3633 | hotkey_tablet_mode_notify_change(); |
3507 | hotkey_wakeup_reason_notify_change(); | 3634 | hotkey_wakeup_reason_notify_change(); |
@@ -3530,8 +3657,8 @@ static int hotkey_read(char *p) | |||
3530 | return res; | 3657 | return res; |
3531 | 3658 | ||
3532 | len += sprintf(p + len, "status:\t\t%s\n", enabled(status, 0)); | 3659 | len += sprintf(p + len, "status:\t\t%s\n", enabled(status, 0)); |
3533 | if (tp_features.hotkey_mask) { | 3660 | if (hotkey_all_mask) { |
3534 | len += sprintf(p + len, "mask:\t\t0x%08x\n", hotkey_mask); | 3661 | len += sprintf(p + len, "mask:\t\t0x%08x\n", hotkey_user_mask); |
3535 | len += sprintf(p + len, | 3662 | len += sprintf(p + len, |
3536 | "commands:\tenable, disable, reset, <mask>\n"); | 3663 | "commands:\tenable, disable, reset, <mask>\n"); |
3537 | } else { | 3664 | } else { |
@@ -3568,7 +3695,7 @@ static int hotkey_write(char *buf) | |||
3568 | if (mutex_lock_killable(&hotkey_mutex)) | 3695 | if (mutex_lock_killable(&hotkey_mutex)) |
3569 | return -ERESTARTSYS; | 3696 | return -ERESTARTSYS; |
3570 | 3697 | ||
3571 | mask = hotkey_mask; | 3698 | mask = hotkey_user_mask; |
3572 | 3699 | ||
3573 | res = 0; | 3700 | res = 0; |
3574 | while ((cmd = next_cmd(&buf))) { | 3701 | while ((cmd = next_cmd(&buf))) { |
@@ -3590,12 +3717,11 @@ static int hotkey_write(char *buf) | |||
3590 | } | 3717 | } |
3591 | } | 3718 | } |
3592 | 3719 | ||
3593 | if (!res) | 3720 | if (!res) { |
3594 | tpacpi_disclose_usertask("procfs hotkey", | 3721 | tpacpi_disclose_usertask("procfs hotkey", |
3595 | "set mask to 0x%08x\n", mask); | 3722 | "set mask to 0x%08x\n", mask); |
3596 | 3723 | res = hotkey_user_mask_set(mask); | |
3597 | if (!res && mask != hotkey_mask) | 3724 | } |
3598 | res = hotkey_mask_set(mask); | ||
3599 | 3725 | ||
3600 | errexit: | 3726 | errexit: |
3601 | mutex_unlock(&hotkey_mutex); | 3727 | mutex_unlock(&hotkey_mutex); |