diff options
-rw-r--r-- | drivers/platform/x86/msi-wmi.c | 65 |
1 files changed, 50 insertions, 15 deletions
diff --git a/drivers/platform/x86/msi-wmi.c b/drivers/platform/x86/msi-wmi.c index 739bd4d17c23..70222f265f68 100644 --- a/drivers/platform/x86/msi-wmi.c +++ b/drivers/platform/x86/msi-wmi.c | |||
@@ -37,17 +37,27 @@ MODULE_LICENSE("GPL"); | |||
37 | #define DRV_NAME "msi-wmi" | 37 | #define DRV_NAME "msi-wmi" |
38 | 38 | ||
39 | #define MSIWMI_BIOS_GUID "551A1F84-FBDD-4125-91DB-3EA8F44F1D45" | 39 | #define MSIWMI_BIOS_GUID "551A1F84-FBDD-4125-91DB-3EA8F44F1D45" |
40 | #define MSIWMI_EVENT_GUID "B6F3EEF2-3D2F-49DC-9DE3-85BCE18C62F2" | 40 | #define MSIWMI_MSI_EVENT_GUID "B6F3EEF2-3D2F-49DC-9DE3-85BCE18C62F2" |
41 | #define MSIWMI_WIND_EVENT_GUID "5B3CC38A-40D9-7245-8AE6-1145B751BE3F" | ||
41 | 42 | ||
42 | MODULE_ALIAS("wmi:" MSIWMI_BIOS_GUID); | 43 | MODULE_ALIAS("wmi:" MSIWMI_BIOS_GUID); |
43 | MODULE_ALIAS("wmi:" MSIWMI_EVENT_GUID); | 44 | MODULE_ALIAS("wmi:" MSIWMI_MSI_EVENT_GUID); |
45 | MODULE_ALIAS("wmi:" MSIWMI_WIND_EVENT_GUID); | ||
44 | 46 | ||
45 | enum msi_scancodes { | 47 | enum msi_scancodes { |
48 | /* Generic MSI keys (not present on MSI Wind) */ | ||
46 | MSI_KEY_BRIGHTNESSUP = 0xD0, | 49 | MSI_KEY_BRIGHTNESSUP = 0xD0, |
47 | MSI_KEY_BRIGHTNESSDOWN, | 50 | MSI_KEY_BRIGHTNESSDOWN, |
48 | MSI_KEY_VOLUMEUP, | 51 | MSI_KEY_VOLUMEUP, |
49 | MSI_KEY_VOLUMEDOWN, | 52 | MSI_KEY_VOLUMEDOWN, |
50 | MSI_KEY_MUTE, | 53 | MSI_KEY_MUTE, |
54 | /* MSI Wind keys */ | ||
55 | WIND_KEY_TOUCHPAD = 0x08, /* Fn+F3 touchpad toggle */ | ||
56 | WIND_KEY_BLUETOOTH = 0x56, /* Fn+F11 Bluetooth toggle */ | ||
57 | WIND_KEY_CAMERA, /* Fn+F6 webcam toggle */ | ||
58 | WIND_KEY_WLAN = 0x5f, /* Fn+F11 Wi-Fi toggle */ | ||
59 | WIND_KEY_TURBO, /* Fn+F10 turbo mode toggle */ | ||
60 | WIND_KEY_ECO = 0x69, /* Fn+F10 ECO mode toggle */ | ||
51 | }; | 61 | }; |
52 | static struct key_entry msi_wmi_keymap[] = { | 62 | static struct key_entry msi_wmi_keymap[] = { |
53 | { KE_KEY, MSI_KEY_BRIGHTNESSUP, {KEY_BRIGHTNESSUP} }, | 63 | { KE_KEY, MSI_KEY_BRIGHTNESSUP, {KEY_BRIGHTNESSUP} }, |
@@ -55,13 +65,34 @@ static struct key_entry msi_wmi_keymap[] = { | |||
55 | { KE_KEY, MSI_KEY_VOLUMEUP, {KEY_VOLUMEUP} }, | 65 | { KE_KEY, MSI_KEY_VOLUMEUP, {KEY_VOLUMEUP} }, |
56 | { KE_KEY, MSI_KEY_VOLUMEDOWN, {KEY_VOLUMEDOWN} }, | 66 | { KE_KEY, MSI_KEY_VOLUMEDOWN, {KEY_VOLUMEDOWN} }, |
57 | { KE_KEY, MSI_KEY_MUTE, {KEY_MUTE} }, | 67 | { KE_KEY, MSI_KEY_MUTE, {KEY_MUTE} }, |
68 | |||
69 | /* These keys work without WMI. Ignore them to avoid double keycodes */ | ||
70 | { KE_IGNORE, WIND_KEY_TOUCHPAD, {KEY_TOUCHPAD_TOGGLE} }, | ||
71 | { KE_IGNORE, WIND_KEY_BLUETOOTH, {KEY_BLUETOOTH} }, | ||
72 | { KE_IGNORE, WIND_KEY_CAMERA, {KEY_CAMERA} }, | ||
73 | { KE_IGNORE, WIND_KEY_WLAN, {KEY_WLAN} }, | ||
74 | |||
75 | /* These are unknown WMI events found on MSI Wind */ | ||
76 | { KE_IGNORE, 0x00 }, | ||
77 | { KE_IGNORE, 0x62 }, | ||
78 | { KE_IGNORE, 0x63 }, | ||
79 | |||
80 | /* These are MSI Wind keys that should be handled via WMI */ | ||
81 | { KE_KEY, WIND_KEY_TURBO, {KEY_PROG1} }, | ||
82 | { KE_KEY, WIND_KEY_ECO, {KEY_PROG2} }, | ||
83 | |||
58 | { KE_END, 0 } | 84 | { KE_END, 0 } |
59 | }; | 85 | }; |
60 | 86 | ||
61 | static ktime_t last_pressed; | 87 | static ktime_t last_pressed; |
62 | static bool quirk_last_pressed; | ||
63 | 88 | ||
64 | static const char *event_wmi_guid; | 89 | static const struct { |
90 | const char *guid; | ||
91 | bool quirk_last_pressed; | ||
92 | } *event_wmi, event_wmis[] = { | ||
93 | { MSIWMI_MSI_EVENT_GUID, true }, | ||
94 | { MSIWMI_WIND_EVENT_GUID, false }, | ||
95 | }; | ||
65 | 96 | ||
66 | static struct backlight_device *backlight; | 97 | static struct backlight_device *backlight; |
67 | 98 | ||
@@ -174,7 +205,7 @@ static void msi_wmi_notify(u32 value, void *context) | |||
174 | goto msi_wmi_notify_exit; | 205 | goto msi_wmi_notify_exit; |
175 | } | 206 | } |
176 | 207 | ||
177 | if (quirk_last_pressed) { | 208 | if (event_wmi->quirk_last_pressed) { |
178 | ktime_t cur = ktime_get_real(); | 209 | ktime_t cur = ktime_get_real(); |
179 | ktime_t diff = ktime_sub(cur, last_pressed); | 210 | ktime_t diff = ktime_sub(cur, last_pressed); |
180 | /* Ignore event if any event happened in a 50 ms | 211 | /* Ignore event if any event happened in a 50 ms |
@@ -265,15 +296,19 @@ err_free_dev: | |||
265 | static int __init msi_wmi_init(void) | 296 | static int __init msi_wmi_init(void) |
266 | { | 297 | { |
267 | int err; | 298 | int err; |
299 | int i; | ||
300 | |||
301 | for (i = 0; i < ARRAY_SIZE(event_wmis); i++) { | ||
302 | if (!wmi_has_guid(event_wmis[i].guid)) | ||
303 | continue; | ||
268 | 304 | ||
269 | if (wmi_has_guid(MSIWMI_EVENT_GUID)) { | ||
270 | err = msi_wmi_input_setup(); | 305 | err = msi_wmi_input_setup(); |
271 | if (err) { | 306 | if (err) { |
272 | pr_err("Unable to setup input device\n"); | 307 | pr_err("Unable to setup input device\n"); |
273 | return err; | 308 | return err; |
274 | } | 309 | } |
275 | 310 | ||
276 | err = wmi_install_notify_handler(MSIWMI_EVENT_GUID, | 311 | err = wmi_install_notify_handler(event_wmis[i].guid, |
277 | msi_wmi_notify, NULL); | 312 | msi_wmi_notify, NULL); |
278 | if (ACPI_FAILURE(err)) { | 313 | if (ACPI_FAILURE(err)) { |
279 | pr_err("Unable to setup WMI notify handler\n"); | 314 | pr_err("Unable to setup WMI notify handler\n"); |
@@ -281,8 +316,8 @@ static int __init msi_wmi_init(void) | |||
281 | } | 316 | } |
282 | 317 | ||
283 | pr_debug("Event handler installed\n"); | 318 | pr_debug("Event handler installed\n"); |
284 | event_wmi_guid = MSIWMI_EVENT_GUID; | 319 | event_wmi = &event_wmis[i]; |
285 | quirk_last_pressed = true; | 320 | break; |
286 | } | 321 | } |
287 | 322 | ||
288 | if (wmi_has_guid(MSIWMI_BIOS_GUID) && !acpi_video_backlight_support()) { | 323 | if (wmi_has_guid(MSIWMI_BIOS_GUID) && !acpi_video_backlight_support()) { |
@@ -294,7 +329,7 @@ static int __init msi_wmi_init(void) | |||
294 | pr_debug("Backlight device created\n"); | 329 | pr_debug("Backlight device created\n"); |
295 | } | 330 | } |
296 | 331 | ||
297 | if (!event_wmi_guid && !backlight) { | 332 | if (!event_wmi && !backlight) { |
298 | pr_err("This machine doesn't have neither MSI-hotkeys nor backlight through WMI\n"); | 333 | pr_err("This machine doesn't have neither MSI-hotkeys nor backlight through WMI\n"); |
299 | return -ENODEV; | 334 | return -ENODEV; |
300 | } | 335 | } |
@@ -302,10 +337,10 @@ static int __init msi_wmi_init(void) | |||
302 | return 0; | 337 | return 0; |
303 | 338 | ||
304 | err_uninstall_handler: | 339 | err_uninstall_handler: |
305 | if (event_wmi_guid) | 340 | if (event_wmi) |
306 | wmi_remove_notify_handler(event_wmi_guid); | 341 | wmi_remove_notify_handler(event_wmi->guid); |
307 | err_free_input: | 342 | err_free_input: |
308 | if (event_wmi_guid) { | 343 | if (event_wmi) { |
309 | sparse_keymap_free(msi_wmi_input_dev); | 344 | sparse_keymap_free(msi_wmi_input_dev); |
310 | input_unregister_device(msi_wmi_input_dev); | 345 | input_unregister_device(msi_wmi_input_dev); |
311 | } | 346 | } |
@@ -314,8 +349,8 @@ err_free_input: | |||
314 | 349 | ||
315 | static void __exit msi_wmi_exit(void) | 350 | static void __exit msi_wmi_exit(void) |
316 | { | 351 | { |
317 | if (event_wmi_guid) { | 352 | if (event_wmi) { |
318 | wmi_remove_notify_handler(event_wmi_guid); | 353 | wmi_remove_notify_handler(event_wmi->guid); |
319 | sparse_keymap_free(msi_wmi_input_dev); | 354 | sparse_keymap_free(msi_wmi_input_dev); |
320 | input_unregister_device(msi_wmi_input_dev); | 355 | input_unregister_device(msi_wmi_input_dev); |
321 | } | 356 | } |