diff options
| -rw-r--r-- | Documentation/laptops/thinkpad-acpi.txt | 46 | ||||
| -rw-r--r-- | drivers/platform/x86/thinkpad_acpi.c | 478 |
2 files changed, 328 insertions, 196 deletions
diff --git a/Documentation/laptops/thinkpad-acpi.txt b/Documentation/laptops/thinkpad-acpi.txt index f635fb09d620..aafcaa634191 100644 --- a/Documentation/laptops/thinkpad-acpi.txt +++ b/Documentation/laptops/thinkpad-acpi.txt | |||
| @@ -199,18 +199,22 @@ kind to allow it (and it often doesn't!). | |||
| 199 | 199 | ||
| 200 | Not all bits in the mask can be modified. Not all bits that can be | 200 | Not all bits in the mask can be modified. Not all bits that can be |
| 201 | modified do anything. Not all hot keys can be individually controlled | 201 | modified do anything. Not all hot keys can be individually controlled |
| 202 | by the mask. Some models do not support the mask at all, and in those | 202 | by the mask. Some models do not support the mask at all. The behaviour |
| 203 | models, hot keys cannot be controlled individually. The behaviour of | 203 | of the mask is, therefore, highly dependent on the ThinkPad model. |
| 204 | the mask is, therefore, highly dependent on the ThinkPad model. | 204 | |
| 205 | The driver will filter out any unmasked hotkeys, so even if the firmware | ||
| 206 | doesn't allow disabling an specific hotkey, the driver will not report | ||
| 207 | events for unmasked hotkeys. | ||
| 205 | 208 | ||
| 206 | Note that unmasking some keys prevents their default behavior. For | 209 | Note that unmasking some keys prevents their default behavior. For |
| 207 | example, if Fn+F5 is unmasked, that key will no longer enable/disable | 210 | example, if Fn+F5 is unmasked, that key will no longer enable/disable |
| 208 | Bluetooth by itself. | 211 | Bluetooth by itself in firmware. |
| 209 | 212 | ||
| 210 | Note also that not all Fn key combinations are supported through ACPI. | 213 | Note also that not all Fn key combinations are supported through ACPI |
| 211 | For example, on the X40, the brightness, volume and "Access IBM" buttons | 214 | depending on the ThinkPad model and firmware version. On those |
| 212 | do not generate ACPI events even with this driver. They *can* be used | 215 | ThinkPads, it is still possible to support some extra hotkeys by |
| 213 | through the "ThinkPad Buttons" utility, see http://www.nongnu.org/tpb/ | 216 | polling the "CMOS NVRAM" at least 10 times per second. The driver |
| 217 | attempts to enables this functionality automatically when required. | ||
| 214 | 218 | ||
| 215 | procfs notes: | 219 | procfs notes: |
| 216 | 220 | ||
| @@ -255,18 +259,11 @@ sysfs notes: | |||
| 255 | 1: does nothing | 259 | 1: does nothing |
| 256 | 260 | ||
| 257 | hotkey_mask: | 261 | hotkey_mask: |
| 258 | bit mask to enable driver-handling (and depending on | 262 | bit mask to enable reporting (and depending on |
| 259 | the firmware, ACPI event generation) for each hot key | 263 | the firmware, ACPI event generation) for each hot key |
| 260 | (see above). Returns the current status of the hot keys | 264 | (see above). Returns the current status of the hot keys |
| 261 | mask, and allows one to modify it. | 265 | mask, and allows one to modify it. |
| 262 | 266 | ||
| 263 | Note: when NVRAM polling is active, the firmware mask | ||
| 264 | will be different from the value returned by | ||
| 265 | hotkey_mask. The driver will retain enabled bits for | ||
| 266 | hotkeys that are under NVRAM polling even if the | ||
| 267 | firmware refuses them, and will not set these bits on | ||
| 268 | the firmware hot key mask. | ||
| 269 | |||
| 270 | hotkey_all_mask: | 267 | hotkey_all_mask: |
| 271 | bit mask that should enable event reporting for all | 268 | bit mask that should enable event reporting for all |
| 272 | supported hot keys, when echoed to hotkey_mask above. | 269 | supported hot keys, when echoed to hotkey_mask above. |
| @@ -279,7 +276,8 @@ sysfs notes: | |||
| 279 | bit mask that should enable event reporting for all | 276 | bit mask that should enable event reporting for all |
| 280 | supported hot keys, except those which are always | 277 | supported hot keys, except those which are always |
| 281 | handled by the firmware anyway. Echo it to | 278 | handled by the firmware anyway. Echo it to |
| 282 | hotkey_mask above, to use. | 279 | hotkey_mask above, to use. This is the default mask |
| 280 | used by the driver. | ||
| 283 | 281 | ||
| 284 | hotkey_source_mask: | 282 | hotkey_source_mask: |
| 285 | bit mask that selects which hot keys will the driver | 283 | bit mask that selects which hot keys will the driver |
| @@ -287,9 +285,10 @@ sysfs notes: | |||
| 287 | based on the capabilities reported by the ACPI firmware, | 285 | based on the capabilities reported by the ACPI firmware, |
| 288 | but it can be overridden at runtime. | 286 | but it can be overridden at runtime. |
| 289 | 287 | ||
| 290 | Hot keys whose bits are set in both hotkey_source_mask | 288 | Hot keys whose bits are set in hotkey_source_mask are |
| 291 | and also on hotkey_mask are polled for in NVRAM. Only a | 289 | polled for in NVRAM, and reported as hotkey events if |
| 292 | few hot keys are available through CMOS NVRAM polling. | 290 | enabled in hotkey_mask. Only a few hot keys are |
| 291 | available through CMOS NVRAM polling. | ||
| 293 | 292 | ||
| 294 | Warning: when in NVRAM mode, the volume up/down/mute | 293 | Warning: when in NVRAM mode, the volume up/down/mute |
| 295 | keys are synthesized according to changes in the mixer, | 294 | keys are synthesized according to changes in the mixer, |
| @@ -621,6 +620,8 @@ For Lenovo models *with* ACPI backlight control: | |||
| 621 | 2. Do *NOT* load up ACPI video, enable the hotkeys in thinkpad-acpi, | 620 | 2. Do *NOT* load up ACPI video, enable the hotkeys in thinkpad-acpi, |
| 622 | and map them to KEY_BRIGHTNESS_UP and KEY_BRIGHTNESS_DOWN. Process | 621 | and map them to KEY_BRIGHTNESS_UP and KEY_BRIGHTNESS_DOWN. Process |
| 623 | these keys on userspace somehow (e.g. by calling xbacklight). | 622 | these keys on userspace somehow (e.g. by calling xbacklight). |
| 623 | The driver will do this automatically if it detects that ACPI video | ||
| 624 | has been disabled. | ||
| 624 | 625 | ||
| 625 | 626 | ||
| 626 | Bluetooth | 627 | Bluetooth |
| @@ -1459,3 +1460,8 @@ Sysfs interface changelog: | |||
| 1459 | 0x020400: Marker for 16 LEDs support. Also, LEDs that are known | 1460 | 0x020400: Marker for 16 LEDs support. Also, LEDs that are known |
| 1460 | to not exist in a given model are not registered with | 1461 | to not exist in a given model are not registered with |
| 1461 | the LED sysfs class anymore. | 1462 | the LED sysfs class anymore. |
| 1463 | |||
| 1464 | 0x020500: Updated hotkey driver, hotkey_mask is always available | ||
| 1465 | and it is always able to disable hot keys. Very old | ||
| 1466 | thinkpads are properly supported. hotkey_bios_mask | ||
| 1467 | is deprecated and marked for removal. | ||
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); |
