diff options
Diffstat (limited to 'drivers/misc/thinkpad_acpi.c')
| -rw-r--r-- | drivers/misc/thinkpad_acpi.c | 494 |
1 files changed, 259 insertions, 235 deletions
diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c index a0ce0b2fa03e..b5969298f3d3 100644 --- a/drivers/misc/thinkpad_acpi.c +++ b/drivers/misc/thinkpad_acpi.c | |||
| @@ -1293,7 +1293,7 @@ static void tpacpi_input_send_radiosw(void) | |||
| 1293 | mutex_lock(&tpacpi_inputdev_send_mutex); | 1293 | mutex_lock(&tpacpi_inputdev_send_mutex); |
| 1294 | 1294 | ||
| 1295 | input_report_switch(tpacpi_inputdev, | 1295 | input_report_switch(tpacpi_inputdev, |
| 1296 | SW_RADIO, !!wlsw); | 1296 | SW_RFKILL_ALL, !!wlsw); |
| 1297 | input_sync(tpacpi_inputdev); | 1297 | input_sync(tpacpi_inputdev); |
| 1298 | 1298 | ||
| 1299 | mutex_unlock(&tpacpi_inputdev_send_mutex); | 1299 | mutex_unlock(&tpacpi_inputdev_send_mutex); |
| @@ -1921,6 +1921,29 @@ static struct attribute *hotkey_mask_attributes[] __initdata = { | |||
| 1921 | &dev_attr_hotkey_wakeup_hotunplug_complete.attr, | 1921 | &dev_attr_hotkey_wakeup_hotunplug_complete.attr, |
| 1922 | }; | 1922 | }; |
| 1923 | 1923 | ||
| 1924 | static void hotkey_exit(void) | ||
| 1925 | { | ||
| 1926 | #ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL | ||
| 1927 | hotkey_poll_stop_sync(); | ||
| 1928 | #endif | ||
| 1929 | |||
| 1930 | if (hotkey_dev_attributes) | ||
| 1931 | delete_attr_set(hotkey_dev_attributes, &tpacpi_pdev->dev.kobj); | ||
| 1932 | |||
| 1933 | kfree(hotkey_keycode_map); | ||
| 1934 | |||
| 1935 | if (tp_features.hotkey) { | ||
| 1936 | dbg_printk(TPACPI_DBG_EXIT, | ||
| 1937 | "restoring original hot key mask\n"); | ||
| 1938 | /* no short-circuit boolean operator below! */ | ||
| 1939 | if ((hotkey_mask_set(hotkey_orig_mask) | | ||
| 1940 | hotkey_status_set(hotkey_orig_status)) != 0) | ||
| 1941 | printk(TPACPI_ERR | ||
| 1942 | "failed to restore hot key mask " | ||
| 1943 | "to BIOS defaults\n"); | ||
| 1944 | } | ||
| 1945 | } | ||
| 1946 | |||
| 1924 | static int __init hotkey_init(struct ibm_init_struct *iibm) | 1947 | static int __init hotkey_init(struct ibm_init_struct *iibm) |
| 1925 | { | 1948 | { |
| 1926 | /* Requirements for changing the default keymaps: | 1949 | /* Requirements for changing the default keymaps: |
| @@ -2060,226 +2083,220 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) | |||
| 2060 | vdbg_printk(TPACPI_DBG_INIT, "hotkeys are %s\n", | 2083 | vdbg_printk(TPACPI_DBG_INIT, "hotkeys are %s\n", |
| 2061 | str_supported(tp_features.hotkey)); | 2084 | str_supported(tp_features.hotkey)); |
| 2062 | 2085 | ||
| 2063 | if (tp_features.hotkey) { | 2086 | if (!tp_features.hotkey) |
| 2064 | hotkey_dev_attributes = create_attr_set(13, NULL); | 2087 | return 1; |
| 2065 | if (!hotkey_dev_attributes) | ||
| 2066 | return -ENOMEM; | ||
| 2067 | res = add_many_to_attr_set(hotkey_dev_attributes, | ||
| 2068 | hotkey_attributes, | ||
| 2069 | ARRAY_SIZE(hotkey_attributes)); | ||
| 2070 | if (res) | ||
| 2071 | return res; | ||
| 2072 | 2088 | ||
| 2073 | /* mask not supported on 570, 600e/x, 770e, 770x, A21e, A2xm/p, | 2089 | hotkey_dev_attributes = create_attr_set(13, NULL); |
| 2074 | A30, R30, R31, T20-22, X20-21, X22-24. Detected by checking | 2090 | if (!hotkey_dev_attributes) |
| 2075 | for HKEY interface version 0x100 */ | 2091 | return -ENOMEM; |
| 2076 | if (acpi_evalf(hkey_handle, &hkeyv, "MHKV", "qd")) { | 2092 | res = add_many_to_attr_set(hotkey_dev_attributes, |
| 2077 | if ((hkeyv >> 8) != 1) { | 2093 | hotkey_attributes, |
| 2078 | printk(TPACPI_ERR "unknown version of the " | 2094 | ARRAY_SIZE(hotkey_attributes)); |
| 2079 | "HKEY interface: 0x%x\n", hkeyv); | 2095 | if (res) |
| 2080 | printk(TPACPI_ERR "please report this to %s\n", | 2096 | goto err_exit; |
| 2081 | TPACPI_MAIL); | 2097 | |
| 2082 | } else { | 2098 | /* mask not supported on 570, 600e/x, 770e, 770x, A21e, A2xm/p, |
| 2083 | /* | 2099 | A30, R30, R31, T20-22, X20-21, X22-24. Detected by checking |
| 2084 | * MHKV 0x100 in A31, R40, R40e, | 2100 | for HKEY interface version 0x100 */ |
| 2085 | * T4x, X31, and later | 2101 | if (acpi_evalf(hkey_handle, &hkeyv, "MHKV", "qd")) { |
| 2086 | */ | 2102 | if ((hkeyv >> 8) != 1) { |
| 2087 | tp_features.hotkey_mask = 1; | 2103 | printk(TPACPI_ERR "unknown version of the " |
| 2088 | } | 2104 | "HKEY interface: 0x%x\n", hkeyv); |
| 2105 | printk(TPACPI_ERR "please report this to %s\n", | ||
| 2106 | TPACPI_MAIL); | ||
| 2107 | } else { | ||
| 2108 | /* | ||
| 2109 | * MHKV 0x100 in A31, R40, R40e, | ||
| 2110 | * T4x, X31, and later | ||
| 2111 | */ | ||
| 2112 | tp_features.hotkey_mask = 1; | ||
| 2089 | } | 2113 | } |
| 2114 | } | ||
| 2090 | 2115 | ||
| 2091 | vdbg_printk(TPACPI_DBG_INIT, "hotkey masks are %s\n", | 2116 | vdbg_printk(TPACPI_DBG_INIT, "hotkey masks are %s\n", |
| 2092 | str_supported(tp_features.hotkey_mask)); | 2117 | str_supported(tp_features.hotkey_mask)); |
| 2093 | 2118 | ||
| 2094 | if (tp_features.hotkey_mask) { | 2119 | if (tp_features.hotkey_mask) { |
| 2095 | if (!acpi_evalf(hkey_handle, &hotkey_all_mask, | 2120 | if (!acpi_evalf(hkey_handle, &hotkey_all_mask, |
| 2096 | "MHKA", "qd")) { | 2121 | "MHKA", "qd")) { |
| 2097 | printk(TPACPI_ERR | 2122 | printk(TPACPI_ERR |
| 2098 | "missing MHKA handler, " | 2123 | "missing MHKA handler, " |
| 2099 | "please report this to %s\n", | 2124 | "please report this to %s\n", |
| 2100 | TPACPI_MAIL); | 2125 | TPACPI_MAIL); |
| 2101 | /* FN+F12, FN+F4, FN+F3 */ | 2126 | /* FN+F12, FN+F4, FN+F3 */ |
| 2102 | hotkey_all_mask = 0x080cU; | 2127 | hotkey_all_mask = 0x080cU; |
| 2103 | } | ||
| 2104 | } | 2128 | } |
| 2129 | } | ||
| 2105 | 2130 | ||
| 2106 | /* hotkey_source_mask *must* be zero for | 2131 | /* hotkey_source_mask *must* be zero for |
| 2107 | * the first hotkey_mask_get */ | 2132 | * the first hotkey_mask_get */ |
| 2108 | res = hotkey_status_get(&hotkey_orig_status); | 2133 | res = hotkey_status_get(&hotkey_orig_status); |
| 2109 | if (!res && tp_features.hotkey_mask) { | 2134 | if (res) |
| 2110 | res = hotkey_mask_get(); | 2135 | goto err_exit; |
| 2111 | hotkey_orig_mask = hotkey_mask; | 2136 | |
| 2112 | if (!res) { | 2137 | if (tp_features.hotkey_mask) { |
| 2113 | res = add_many_to_attr_set( | 2138 | res = hotkey_mask_get(); |
| 2114 | hotkey_dev_attributes, | 2139 | if (res) |
| 2115 | hotkey_mask_attributes, | 2140 | goto err_exit; |
| 2116 | ARRAY_SIZE(hotkey_mask_attributes)); | 2141 | |
| 2117 | } | 2142 | hotkey_orig_mask = hotkey_mask; |
| 2118 | } | 2143 | res = add_many_to_attr_set( |
| 2144 | hotkey_dev_attributes, | ||
| 2145 | hotkey_mask_attributes, | ||
| 2146 | ARRAY_SIZE(hotkey_mask_attributes)); | ||
| 2147 | if (res) | ||
| 2148 | goto err_exit; | ||
| 2149 | } | ||
| 2119 | 2150 | ||
| 2120 | #ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL | 2151 | #ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL |
| 2121 | if (tp_features.hotkey_mask) { | 2152 | if (tp_features.hotkey_mask) { |
| 2122 | hotkey_source_mask = TPACPI_HKEY_NVRAM_GOOD_MASK | 2153 | hotkey_source_mask = TPACPI_HKEY_NVRAM_GOOD_MASK |
| 2123 | & ~hotkey_all_mask; | 2154 | & ~hotkey_all_mask; |
| 2124 | } else { | 2155 | } else { |
| 2125 | hotkey_source_mask = TPACPI_HKEY_NVRAM_GOOD_MASK; | 2156 | hotkey_source_mask = TPACPI_HKEY_NVRAM_GOOD_MASK; |
| 2126 | } | 2157 | } |
| 2127 | 2158 | ||
| 2128 | vdbg_printk(TPACPI_DBG_INIT, | 2159 | vdbg_printk(TPACPI_DBG_INIT, |
| 2129 | "hotkey source mask 0x%08x, polling freq %d\n", | 2160 | "hotkey source mask 0x%08x, polling freq %d\n", |
| 2130 | hotkey_source_mask, hotkey_poll_freq); | 2161 | hotkey_source_mask, hotkey_poll_freq); |
| 2131 | #endif | 2162 | #endif |
| 2132 | 2163 | ||
| 2133 | /* Not all thinkpads have a hardware radio switch */ | 2164 | /* Not all thinkpads have a hardware radio switch */ |
| 2134 | if (!res && acpi_evalf(hkey_handle, &status, "WLSW", "qd")) { | 2165 | if (acpi_evalf(hkey_handle, &status, "WLSW", "qd")) { |
| 2135 | tp_features.hotkey_wlsw = 1; | 2166 | tp_features.hotkey_wlsw = 1; |
| 2136 | printk(TPACPI_INFO | 2167 | printk(TPACPI_INFO |
| 2137 | "radio switch found; radios are %s\n", | 2168 | "radio switch found; radios are %s\n", |
| 2138 | enabled(status, 0)); | 2169 | enabled(status, 0)); |
| 2139 | res = add_to_attr_set(hotkey_dev_attributes, | 2170 | res = add_to_attr_set(hotkey_dev_attributes, |
| 2140 | &dev_attr_hotkey_radio_sw.attr); | 2171 | &dev_attr_hotkey_radio_sw.attr); |
| 2141 | } | 2172 | } |
| 2142 | 2173 | ||
| 2143 | /* For X41t, X60t, X61t Tablets... */ | 2174 | /* For X41t, X60t, X61t Tablets... */ |
| 2144 | if (!res && acpi_evalf(hkey_handle, &status, "MHKG", "qd")) { | 2175 | if (!res && acpi_evalf(hkey_handle, &status, "MHKG", "qd")) { |
| 2145 | tp_features.hotkey_tablet = 1; | 2176 | tp_features.hotkey_tablet = 1; |
| 2146 | printk(TPACPI_INFO | 2177 | printk(TPACPI_INFO |
| 2147 | "possible tablet mode switch found; " | 2178 | "possible tablet mode switch found; " |
| 2148 | "ThinkPad in %s mode\n", | 2179 | "ThinkPad in %s mode\n", |
| 2149 | (status & TP_HOTKEY_TABLET_MASK)? | 2180 | (status & TP_HOTKEY_TABLET_MASK)? |
| 2150 | "tablet" : "laptop"); | 2181 | "tablet" : "laptop"); |
| 2151 | res = add_to_attr_set(hotkey_dev_attributes, | 2182 | res = add_to_attr_set(hotkey_dev_attributes, |
| 2152 | &dev_attr_hotkey_tablet_mode.attr); | 2183 | &dev_attr_hotkey_tablet_mode.attr); |
| 2153 | } | 2184 | } |
| 2154 | 2185 | ||
| 2155 | if (!res) | 2186 | if (!res) |
| 2156 | res = register_attr_set_with_sysfs( | 2187 | res = register_attr_set_with_sysfs( |
| 2157 | hotkey_dev_attributes, | 2188 | hotkey_dev_attributes, |
| 2158 | &tpacpi_pdev->dev.kobj); | 2189 | &tpacpi_pdev->dev.kobj); |
| 2159 | if (res) | 2190 | if (res) |
| 2160 | return res; | 2191 | goto err_exit; |
| 2161 | 2192 | ||
| 2162 | /* Set up key map */ | 2193 | /* Set up key map */ |
| 2163 | 2194 | ||
| 2164 | hotkey_keycode_map = kmalloc(TPACPI_HOTKEY_MAP_SIZE, | 2195 | hotkey_keycode_map = kmalloc(TPACPI_HOTKEY_MAP_SIZE, |
| 2165 | GFP_KERNEL); | 2196 | GFP_KERNEL); |
| 2166 | if (!hotkey_keycode_map) { | 2197 | if (!hotkey_keycode_map) { |
| 2167 | printk(TPACPI_ERR | 2198 | printk(TPACPI_ERR |
| 2168 | "failed to allocate memory for key map\n"); | 2199 | "failed to allocate memory for key map\n"); |
| 2169 | return -ENOMEM; | 2200 | res = -ENOMEM; |
| 2170 | } | 2201 | goto err_exit; |
| 2202 | } | ||
| 2171 | 2203 | ||
| 2172 | if (thinkpad_id.vendor == PCI_VENDOR_ID_LENOVO) { | 2204 | if (thinkpad_id.vendor == PCI_VENDOR_ID_LENOVO) { |
| 2173 | dbg_printk(TPACPI_DBG_INIT, | 2205 | dbg_printk(TPACPI_DBG_INIT, |
| 2174 | "using Lenovo default hot key map\n"); | 2206 | "using Lenovo default hot key map\n"); |
| 2175 | memcpy(hotkey_keycode_map, &lenovo_keycode_map, | 2207 | memcpy(hotkey_keycode_map, &lenovo_keycode_map, |
| 2176 | TPACPI_HOTKEY_MAP_SIZE); | 2208 | TPACPI_HOTKEY_MAP_SIZE); |
| 2209 | } else { | ||
| 2210 | dbg_printk(TPACPI_DBG_INIT, | ||
| 2211 | "using IBM default hot key map\n"); | ||
| 2212 | memcpy(hotkey_keycode_map, &ibm_keycode_map, | ||
| 2213 | TPACPI_HOTKEY_MAP_SIZE); | ||
| 2214 | } | ||
| 2215 | |||
| 2216 | set_bit(EV_KEY, tpacpi_inputdev->evbit); | ||
| 2217 | set_bit(EV_MSC, tpacpi_inputdev->evbit); | ||
| 2218 | set_bit(MSC_SCAN, tpacpi_inputdev->mscbit); | ||
| 2219 | tpacpi_inputdev->keycodesize = TPACPI_HOTKEY_MAP_TYPESIZE; | ||
| 2220 | tpacpi_inputdev->keycodemax = TPACPI_HOTKEY_MAP_LEN; | ||
| 2221 | tpacpi_inputdev->keycode = hotkey_keycode_map; | ||
| 2222 | for (i = 0; i < TPACPI_HOTKEY_MAP_LEN; i++) { | ||
| 2223 | if (hotkey_keycode_map[i] != KEY_RESERVED) { | ||
| 2224 | set_bit(hotkey_keycode_map[i], | ||
| 2225 | tpacpi_inputdev->keybit); | ||
| 2177 | } else { | 2226 | } else { |
| 2178 | dbg_printk(TPACPI_DBG_INIT, | 2227 | if (i < sizeof(hotkey_reserved_mask)*8) |
| 2179 | "using IBM default hot key map\n"); | 2228 | hotkey_reserved_mask |= 1 << i; |
| 2180 | memcpy(hotkey_keycode_map, &ibm_keycode_map, | ||
| 2181 | TPACPI_HOTKEY_MAP_SIZE); | ||
| 2182 | } | ||
| 2183 | |||
| 2184 | set_bit(EV_KEY, tpacpi_inputdev->evbit); | ||
| 2185 | set_bit(EV_MSC, tpacpi_inputdev->evbit); | ||
| 2186 | set_bit(MSC_SCAN, tpacpi_inputdev->mscbit); | ||
| 2187 | tpacpi_inputdev->keycodesize = TPACPI_HOTKEY_MAP_TYPESIZE; | ||
| 2188 | tpacpi_inputdev->keycodemax = TPACPI_HOTKEY_MAP_LEN; | ||
| 2189 | tpacpi_inputdev->keycode = hotkey_keycode_map; | ||
| 2190 | for (i = 0; i < TPACPI_HOTKEY_MAP_LEN; i++) { | ||
| 2191 | if (hotkey_keycode_map[i] != KEY_RESERVED) { | ||
| 2192 | set_bit(hotkey_keycode_map[i], | ||
| 2193 | tpacpi_inputdev->keybit); | ||
| 2194 | } else { | ||
| 2195 | if (i < sizeof(hotkey_reserved_mask)*8) | ||
| 2196 | hotkey_reserved_mask |= 1 << i; | ||
| 2197 | } | ||
| 2198 | } | ||
| 2199 | |||
| 2200 | if (tp_features.hotkey_wlsw) { | ||
| 2201 | set_bit(EV_SW, tpacpi_inputdev->evbit); | ||
| 2202 | set_bit(SW_RADIO, tpacpi_inputdev->swbit); | ||
| 2203 | } | ||
| 2204 | if (tp_features.hotkey_tablet) { | ||
| 2205 | set_bit(EV_SW, tpacpi_inputdev->evbit); | ||
| 2206 | set_bit(SW_TABLET_MODE, tpacpi_inputdev->swbit); | ||
| 2207 | } | 2229 | } |
| 2230 | } | ||
| 2208 | 2231 | ||
| 2209 | /* Do not issue duplicate brightness change events to | 2232 | if (tp_features.hotkey_wlsw) { |
| 2210 | * userspace */ | 2233 | set_bit(EV_SW, tpacpi_inputdev->evbit); |
| 2211 | if (!tp_features.bright_acpimode) | 2234 | set_bit(SW_RFKILL_ALL, tpacpi_inputdev->swbit); |
| 2212 | /* update bright_acpimode... */ | 2235 | } |
| 2213 | tpacpi_check_std_acpi_brightness_support(); | 2236 | if (tp_features.hotkey_tablet) { |
| 2214 | 2237 | set_bit(EV_SW, tpacpi_inputdev->evbit); | |
| 2215 | if (tp_features.bright_acpimode) { | 2238 | set_bit(SW_TABLET_MODE, tpacpi_inputdev->swbit); |
| 2216 | printk(TPACPI_INFO | 2239 | } |
| 2217 | "This ThinkPad has standard ACPI backlight " | ||
| 2218 | "brightness control, supported by the ACPI " | ||
| 2219 | "video driver\n"); | ||
| 2220 | printk(TPACPI_NOTICE | ||
| 2221 | "Disabling thinkpad-acpi brightness events " | ||
| 2222 | "by default...\n"); | ||
| 2223 | |||
| 2224 | /* The hotkey_reserved_mask change below is not | ||
| 2225 | * necessary while the keys are at KEY_RESERVED in the | ||
| 2226 | * default map, but better safe than sorry, leave it | ||
| 2227 | * here as a marker of what we have to do, especially | ||
| 2228 | * when we finally become able to set this at runtime | ||
| 2229 | * on response to X.org requests */ | ||
| 2230 | hotkey_reserved_mask |= | ||
| 2231 | (1 << TP_ACPI_HOTKEYSCAN_FNHOME) | ||
| 2232 | | (1 << TP_ACPI_HOTKEYSCAN_FNEND); | ||
| 2233 | } | ||
| 2234 | 2240 | ||
| 2235 | dbg_printk(TPACPI_DBG_INIT, | 2241 | /* Do not issue duplicate brightness change events to |
| 2236 | "enabling hot key handling\n"); | 2242 | * userspace */ |
| 2237 | res = hotkey_status_set(1); | 2243 | if (!tp_features.bright_acpimode) |
| 2238 | if (res) | 2244 | /* update bright_acpimode... */ |
| 2239 | return res; | 2245 | tpacpi_check_std_acpi_brightness_support(); |
| 2240 | res = hotkey_mask_set(((hotkey_all_mask | hotkey_source_mask) | ||
| 2241 | & ~hotkey_reserved_mask) | ||
| 2242 | | hotkey_orig_mask); | ||
| 2243 | if (res < 0 && res != -ENXIO) | ||
| 2244 | return res; | ||
| 2245 | 2246 | ||
| 2246 | dbg_printk(TPACPI_DBG_INIT, | 2247 | if (tp_features.bright_acpimode) { |
| 2247 | "legacy hot key reporting over procfs %s\n", | 2248 | printk(TPACPI_INFO |
| 2248 | (hotkey_report_mode < 2) ? | 2249 | "This ThinkPad has standard ACPI backlight " |
| 2249 | "enabled" : "disabled"); | 2250 | "brightness control, supported by the ACPI " |
| 2251 | "video driver\n"); | ||
| 2252 | printk(TPACPI_NOTICE | ||
| 2253 | "Disabling thinkpad-acpi brightness events " | ||
| 2254 | "by default...\n"); | ||
| 2255 | |||
| 2256 | /* The hotkey_reserved_mask change below is not | ||
| 2257 | * necessary while the keys are at KEY_RESERVED in the | ||
| 2258 | * default map, but better safe than sorry, leave it | ||
| 2259 | * here as a marker of what we have to do, especially | ||
| 2260 | * when we finally become able to set this at runtime | ||
| 2261 | * on response to X.org requests */ | ||
| 2262 | hotkey_reserved_mask |= | ||
| 2263 | (1 << TP_ACPI_HOTKEYSCAN_FNHOME) | ||
| 2264 | | (1 << TP_ACPI_HOTKEYSCAN_FNEND); | ||
| 2265 | } | ||
| 2266 | |||
| 2267 | dbg_printk(TPACPI_DBG_INIT, "enabling hot key handling\n"); | ||
| 2268 | res = hotkey_status_set(1); | ||
| 2269 | if (res) { | ||
| 2270 | hotkey_exit(); | ||
| 2271 | return res; | ||
| 2272 | } | ||
| 2273 | res = hotkey_mask_set(((hotkey_all_mask | hotkey_source_mask) | ||
| 2274 | & ~hotkey_reserved_mask) | ||
| 2275 | | hotkey_orig_mask); | ||
| 2276 | if (res < 0 && res != -ENXIO) { | ||
| 2277 | hotkey_exit(); | ||
| 2278 | return res; | ||
| 2279 | } | ||
| 2250 | 2280 | ||
| 2251 | tpacpi_inputdev->open = &hotkey_inputdev_open; | 2281 | dbg_printk(TPACPI_DBG_INIT, |
| 2252 | tpacpi_inputdev->close = &hotkey_inputdev_close; | 2282 | "legacy hot key reporting over procfs %s\n", |
| 2283 | (hotkey_report_mode < 2) ? | ||
| 2284 | "enabled" : "disabled"); | ||
| 2253 | 2285 | ||
| 2254 | hotkey_poll_setup_safe(1); | 2286 | tpacpi_inputdev->open = &hotkey_inputdev_open; |
| 2255 | tpacpi_input_send_radiosw(); | 2287 | tpacpi_inputdev->close = &hotkey_inputdev_close; |
| 2256 | tpacpi_input_send_tabletsw(); | ||
| 2257 | } | ||
| 2258 | 2288 | ||
| 2259 | return (tp_features.hotkey)? 0 : 1; | 2289 | hotkey_poll_setup_safe(1); |
| 2260 | } | 2290 | tpacpi_input_send_radiosw(); |
| 2291 | tpacpi_input_send_tabletsw(); | ||
| 2261 | 2292 | ||
| 2262 | static void hotkey_exit(void) | 2293 | return 0; |
| 2263 | { | ||
| 2264 | #ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL | ||
| 2265 | hotkey_poll_stop_sync(); | ||
| 2266 | #endif | ||
| 2267 | 2294 | ||
| 2268 | if (tp_features.hotkey) { | 2295 | err_exit: |
| 2269 | dbg_printk(TPACPI_DBG_EXIT, | 2296 | delete_attr_set(hotkey_dev_attributes, &tpacpi_pdev->dev.kobj); |
| 2270 | "restoring original hot key mask\n"); | 2297 | hotkey_dev_attributes = NULL; |
| 2271 | /* no short-circuit boolean operator below! */ | ||
| 2272 | if ((hotkey_mask_set(hotkey_orig_mask) | | ||
| 2273 | hotkey_status_set(hotkey_orig_status)) != 0) | ||
| 2274 | printk(TPACPI_ERR | ||
| 2275 | "failed to restore hot key mask " | ||
| 2276 | "to BIOS defaults\n"); | ||
| 2277 | } | ||
| 2278 | 2298 | ||
| 2279 | if (hotkey_dev_attributes) { | 2299 | return (res < 0)? res : 1; |
| 2280 | delete_attr_set(hotkey_dev_attributes, &tpacpi_pdev->dev.kobj); | ||
| 2281 | hotkey_dev_attributes = NULL; | ||
| 2282 | } | ||
| 2283 | } | 2300 | } |
| 2284 | 2301 | ||
| 2285 | static void hotkey_notify(struct ibm_struct *ibm, u32 event) | 2302 | static void hotkey_notify(struct ibm_struct *ibm, u32 event) |
| @@ -3319,7 +3336,7 @@ static struct tpacpi_led_classdev tpacpi_led_thinklight = { | |||
| 3319 | 3336 | ||
| 3320 | static int __init light_init(struct ibm_init_struct *iibm) | 3337 | static int __init light_init(struct ibm_init_struct *iibm) |
| 3321 | { | 3338 | { |
| 3322 | int rc = 0; | 3339 | int rc; |
| 3323 | 3340 | ||
| 3324 | vdbg_printk(TPACPI_DBG_INIT, "initializing light subdriver\n"); | 3341 | vdbg_printk(TPACPI_DBG_INIT, "initializing light subdriver\n"); |
| 3325 | 3342 | ||
| @@ -3337,20 +3354,23 @@ static int __init light_init(struct ibm_init_struct *iibm) | |||
| 3337 | tp_features.light_status = | 3354 | tp_features.light_status = |
| 3338 | acpi_evalf(ec_handle, NULL, "KBLT", "qv"); | 3355 | acpi_evalf(ec_handle, NULL, "KBLT", "qv"); |
| 3339 | 3356 | ||
| 3340 | vdbg_printk(TPACPI_DBG_INIT, "light is %s\n", | 3357 | vdbg_printk(TPACPI_DBG_INIT, "light is %s, light status is %s\n", |
| 3341 | str_supported(tp_features.light)); | 3358 | str_supported(tp_features.light), |
| 3359 | str_supported(tp_features.light_status)); | ||
| 3342 | 3360 | ||
| 3343 | if (tp_features.light) { | 3361 | if (!tp_features.light) |
| 3344 | rc = led_classdev_register(&tpacpi_pdev->dev, | 3362 | return 1; |
| 3345 | &tpacpi_led_thinklight.led_classdev); | 3363 | |
| 3346 | } | 3364 | rc = led_classdev_register(&tpacpi_pdev->dev, |
| 3365 | &tpacpi_led_thinklight.led_classdev); | ||
| 3347 | 3366 | ||
| 3348 | if (rc < 0) { | 3367 | if (rc < 0) { |
| 3349 | tp_features.light = 0; | 3368 | tp_features.light = 0; |
| 3350 | tp_features.light_status = 0; | 3369 | tp_features.light_status = 0; |
| 3351 | } else { | 3370 | } else { |
| 3352 | rc = (tp_features.light)? 0 : 1; | 3371 | rc = 0; |
| 3353 | } | 3372 | } |
| 3373 | |||
| 3354 | return rc; | 3374 | return rc; |
| 3355 | } | 3375 | } |
| 3356 | 3376 | ||
| @@ -3833,7 +3853,7 @@ static const char * const tpacpi_led_names[TPACPI_LED_NUMLEDS] = { | |||
| 3833 | "tpacpi::standby", | 3853 | "tpacpi::standby", |
| 3834 | }; | 3854 | }; |
| 3835 | 3855 | ||
| 3836 | static int led_get_status(unsigned int led) | 3856 | static int led_get_status(const unsigned int led) |
| 3837 | { | 3857 | { |
| 3838 | int status; | 3858 | int status; |
| 3839 | enum led_status_t led_s; | 3859 | enum led_status_t led_s; |
| @@ -3857,41 +3877,42 @@ static int led_get_status(unsigned int led) | |||
| 3857 | /* not reached */ | 3877 | /* not reached */ |
| 3858 | } | 3878 | } |
| 3859 | 3879 | ||
| 3860 | static int led_set_status(unsigned int led, enum led_status_t ledstatus) | 3880 | static int led_set_status(const unsigned int led, |
| 3881 | const enum led_status_t ledstatus) | ||
| 3861 | { | 3882 | { |
| 3862 | /* off, on, blink. Index is led_status_t */ | 3883 | /* off, on, blink. Index is led_status_t */ |
| 3863 | static const int led_sled_arg1[] = { 0, 1, 3 }; | 3884 | static const unsigned int led_sled_arg1[] = { 0, 1, 3 }; |
| 3864 | static const int led_exp_hlbl[] = { 0, 0, 1 }; /* led# * */ | 3885 | static const unsigned int led_led_arg1[] = { 0, 0x80, 0xc0 }; |
| 3865 | static const int led_exp_hlcl[] = { 0, 1, 1 }; /* led# * */ | ||
| 3866 | static const int led_led_arg1[] = { 0, 0x80, 0xc0 }; | ||
| 3867 | 3886 | ||
| 3868 | int rc = 0; | 3887 | int rc = 0; |
| 3869 | 3888 | ||
| 3870 | switch (led_supported) { | 3889 | switch (led_supported) { |
| 3871 | case TPACPI_LED_570: | 3890 | case TPACPI_LED_570: |
| 3872 | /* 570 */ | 3891 | /* 570 */ |
| 3873 | led = 1 << led; | 3892 | if (led > 7) |
| 3874 | if (!acpi_evalf(led_handle, NULL, NULL, "vdd", | 3893 | return -EINVAL; |
| 3875 | led, led_sled_arg1[ledstatus])) | 3894 | if (!acpi_evalf(led_handle, NULL, NULL, "vdd", |
| 3876 | rc = -EIO; | 3895 | (1 << led), led_sled_arg1[ledstatus])) |
| 3877 | break; | 3896 | rc = -EIO; |
| 3897 | break; | ||
| 3878 | case TPACPI_LED_OLD: | 3898 | case TPACPI_LED_OLD: |
| 3879 | /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20 */ | 3899 | /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20 */ |
| 3880 | led = 1 << led; | 3900 | if (led > 7) |
| 3881 | rc = ec_write(TPACPI_LED_EC_HLMS, led); | 3901 | return -EINVAL; |
| 3882 | if (rc >= 0) | 3902 | rc = ec_write(TPACPI_LED_EC_HLMS, (1 << led)); |
| 3883 | rc = ec_write(TPACPI_LED_EC_HLBL, | 3903 | if (rc >= 0) |
| 3884 | led * led_exp_hlbl[ledstatus]); | 3904 | rc = ec_write(TPACPI_LED_EC_HLBL, |
| 3885 | if (rc >= 0) | 3905 | (ledstatus == TPACPI_LED_BLINK) << led); |
| 3886 | rc = ec_write(TPACPI_LED_EC_HLCL, | 3906 | if (rc >= 0) |
| 3887 | led * led_exp_hlcl[ledstatus]); | 3907 | rc = ec_write(TPACPI_LED_EC_HLCL, |
| 3888 | break; | 3908 | (ledstatus != TPACPI_LED_OFF) << led); |
| 3909 | break; | ||
| 3889 | case TPACPI_LED_NEW: | 3910 | case TPACPI_LED_NEW: |
| 3890 | /* all others */ | 3911 | /* all others */ |
| 3891 | if (!acpi_evalf(led_handle, NULL, NULL, "vdd", | 3912 | if (!acpi_evalf(led_handle, NULL, NULL, "vdd", |
| 3892 | led, led_led_arg1[ledstatus])) | 3913 | led, led_led_arg1[ledstatus])) |
| 3893 | rc = -EIO; | 3914 | rc = -EIO; |
| 3894 | break; | 3915 | break; |
| 3895 | default: | 3916 | default: |
| 3896 | rc = -ENXIO; | 3917 | rc = -ENXIO; |
| 3897 | } | 3918 | } |
| @@ -3978,7 +3999,6 @@ static void led_exit(void) | |||
| 3978 | } | 3999 | } |
| 3979 | 4000 | ||
| 3980 | kfree(tpacpi_leds); | 4001 | kfree(tpacpi_leds); |
| 3981 | tpacpi_leds = NULL; | ||
| 3982 | } | 4002 | } |
| 3983 | 4003 | ||
| 3984 | static int __init led_init(struct ibm_init_struct *iibm) | 4004 | static int __init led_init(struct ibm_init_struct *iibm) |
| @@ -4802,7 +4822,6 @@ static void brightness_exit(void) | |||
| 4802 | vdbg_printk(TPACPI_DBG_EXIT, | 4822 | vdbg_printk(TPACPI_DBG_EXIT, |
| 4803 | "calling backlight_device_unregister()\n"); | 4823 | "calling backlight_device_unregister()\n"); |
| 4804 | backlight_device_unregister(ibm_backlight_device); | 4824 | backlight_device_unregister(ibm_backlight_device); |
| 4805 | ibm_backlight_device = NULL; | ||
| 4806 | } | 4825 | } |
| 4807 | } | 4826 | } |
| 4808 | 4827 | ||
| @@ -5764,11 +5783,16 @@ static int __init fan_init(struct ibm_init_struct *iibm) | |||
| 5764 | fan_control_access_mode != TPACPI_FAN_WR_NONE) { | 5783 | fan_control_access_mode != TPACPI_FAN_WR_NONE) { |
| 5765 | rc = sysfs_create_group(&tpacpi_sensors_pdev->dev.kobj, | 5784 | rc = sysfs_create_group(&tpacpi_sensors_pdev->dev.kobj, |
| 5766 | &fan_attr_group); | 5785 | &fan_attr_group); |
| 5767 | if (!(rc < 0)) | ||
| 5768 | rc = driver_create_file(&tpacpi_hwmon_pdriver.driver, | ||
| 5769 | &driver_attr_fan_watchdog); | ||
| 5770 | if (rc < 0) | 5786 | if (rc < 0) |
| 5771 | return rc; | 5787 | return rc; |
| 5788 | |||
| 5789 | rc = driver_create_file(&tpacpi_hwmon_pdriver.driver, | ||
| 5790 | &driver_attr_fan_watchdog); | ||
| 5791 | if (rc < 0) { | ||
| 5792 | sysfs_remove_group(&tpacpi_sensors_pdev->dev.kobj, | ||
| 5793 | &fan_attr_group); | ||
| 5794 | return rc; | ||
| 5795 | } | ||
| 5772 | return 0; | 5796 | return 0; |
| 5773 | } else | 5797 | } else |
| 5774 | return 1; | 5798 | return 1; |
