]>
Commit | Line | Data |
---|---|---|
13bb0fd5 HG |
1 | /* |
2 | * PEAQ 2-in-1 WMI hotkey driver | |
3 | * Copyright (C) 2017 Hans de Goede <[email protected]> | |
4 | * | |
5 | * This program is free software; you can redistribute it and/or modify | |
6 | * it under the terms of the GNU General Public License version 2 as | |
7 | * published by the Free Software Foundation. | |
8 | */ | |
9 | ||
10 | #include <linux/acpi.h> | |
3b952061 | 11 | #include <linux/dmi.h> |
13bb0fd5 HG |
12 | #include <linux/input-polldev.h> |
13 | #include <linux/kernel.h> | |
14 | #include <linux/module.h> | |
15 | ||
16 | #define PEAQ_DOLBY_BUTTON_GUID "ABBC0F6F-8EA1-11D1-00A0-C90629100000" | |
17 | #define PEAQ_DOLBY_BUTTON_METHOD_ID 5 | |
18 | #define PEAQ_POLL_INTERVAL_MS 250 | |
19 | #define PEAQ_POLL_IGNORE_MS 500 | |
20 | #define PEAQ_POLL_MAX_MS 1000 | |
21 | ||
22 | MODULE_ALIAS("wmi:"PEAQ_DOLBY_BUTTON_GUID); | |
23 | ||
24 | static unsigned int peaq_ignore_events_counter; | |
25 | static struct input_polled_dev *peaq_poll_dev; | |
26 | ||
27 | /* | |
28 | * The Dolby button (yes really a Dolby button) causes an ACPI variable to get | |
29 | * set on both press and release. The WMI method checks and clears that flag. | |
30 | * So for a press + release we will get back One from the WMI method either once | |
31 | * (if polling after the release) or twice (polling between press and release). | |
32 | * We ignore events for 0.5s after the first event to avoid reporting 2 presses. | |
33 | */ | |
34 | static void peaq_wmi_poll(struct input_polled_dev *dev) | |
35 | { | |
36 | union acpi_object obj; | |
37 | acpi_status status; | |
38 | u32 dummy = 0; | |
39 | ||
40 | struct acpi_buffer input = { sizeof(dummy), &dummy }; | |
41 | struct acpi_buffer output = { sizeof(obj), &obj }; | |
42 | ||
2cf7bdec | 43 | status = wmi_evaluate_method(PEAQ_DOLBY_BUTTON_GUID, 0, |
13bb0fd5 HG |
44 | PEAQ_DOLBY_BUTTON_METHOD_ID, |
45 | &input, &output); | |
46 | if (ACPI_FAILURE(status)) | |
47 | return; | |
48 | ||
49 | if (obj.type != ACPI_TYPE_INTEGER) { | |
50 | dev_err(&peaq_poll_dev->input->dev, | |
51 | "Error WMBC did not return an integer\n"); | |
52 | return; | |
53 | } | |
54 | ||
890f658c | 55 | if (peaq_ignore_events_counter && peaq_ignore_events_counter--) |
13bb0fd5 HG |
56 | return; |
57 | ||
58 | if (obj.integer.value) { | |
59 | input_event(peaq_poll_dev->input, EV_KEY, KEY_SOUND, 1); | |
60 | input_sync(peaq_poll_dev->input); | |
61 | input_event(peaq_poll_dev->input, EV_KEY, KEY_SOUND, 0); | |
62 | input_sync(peaq_poll_dev->input); | |
63 | peaq_ignore_events_counter = max(1u, | |
64 | PEAQ_POLL_IGNORE_MS / peaq_poll_dev->poll_interval); | |
65 | } | |
66 | } | |
67 | ||
3b952061 | 68 | /* Some other devices (Shuttle XS35) use the same WMI GUID for other purposes */ |
f6c7b803 | 69 | static const struct dmi_system_id peaq_dmi_table[] __initconst = { |
3b952061 HG |
70 | { |
71 | .matches = { | |
72 | DMI_MATCH(DMI_SYS_VENDOR, "PEAQ"), | |
73 | DMI_MATCH(DMI_PRODUCT_NAME, "PEAQ PMM C1010 MD99187"), | |
74 | }, | |
75 | }, | |
d6fa71f1 | 76 | {} |
3b952061 HG |
77 | }; |
78 | ||
13bb0fd5 HG |
79 | static int __init peaq_wmi_init(void) |
80 | { | |
3b952061 HG |
81 | /* WMI GUID is not unique, also check for a DMI match */ |
82 | if (!dmi_check_system(peaq_dmi_table)) | |
83 | return -ENODEV; | |
84 | ||
dfea7e18 | 85 | if (!wmi_has_guid(PEAQ_DOLBY_BUTTON_GUID)) |
13bb0fd5 HG |
86 | return -ENODEV; |
87 | ||
88 | peaq_poll_dev = input_allocate_polled_device(); | |
89 | if (!peaq_poll_dev) | |
90 | return -ENOMEM; | |
91 | ||
92 | peaq_poll_dev->poll = peaq_wmi_poll; | |
93 | peaq_poll_dev->poll_interval = PEAQ_POLL_INTERVAL_MS; | |
94 | peaq_poll_dev->poll_interval_max = PEAQ_POLL_MAX_MS; | |
95 | peaq_poll_dev->input->name = "PEAQ WMI hotkeys"; | |
96 | peaq_poll_dev->input->phys = "wmi/input0"; | |
97 | peaq_poll_dev->input->id.bustype = BUS_HOST; | |
98 | input_set_capability(peaq_poll_dev->input, EV_KEY, KEY_SOUND); | |
99 | ||
100 | return input_register_polled_device(peaq_poll_dev); | |
101 | } | |
102 | ||
103 | static void __exit peaq_wmi_exit(void) | |
104 | { | |
13bb0fd5 HG |
105 | input_unregister_polled_device(peaq_poll_dev); |
106 | } | |
107 | ||
108 | module_init(peaq_wmi_init); | |
109 | module_exit(peaq_wmi_exit); | |
110 | ||
111 | MODULE_DESCRIPTION("PEAQ 2-in-1 WMI hotkey driver"); | |
112 | MODULE_AUTHOR("Hans de Goede <[email protected]>"); | |
113 | MODULE_LICENSE("GPL"); |