0001
0002
0003
0004
0005
0006
0007 #include <linux/acpi.h>
0008 #include <linux/dmi.h>
0009 #include <linux/input.h>
0010 #include <linux/kernel.h>
0011 #include <linux/module.h>
0012
0013 #define PEAQ_DOLBY_BUTTON_GUID "ABBC0F6F-8EA1-11D1-00A0-C90629100000"
0014 #define PEAQ_DOLBY_BUTTON_METHOD_ID 5
0015 #define PEAQ_POLL_INTERVAL_MS 250
0016 #define PEAQ_POLL_IGNORE_MS 500
0017 #define PEAQ_POLL_MAX_MS 1000
0018
0019 MODULE_ALIAS("wmi:"PEAQ_DOLBY_BUTTON_GUID);
0020
0021 static struct input_dev *peaq_poll_dev;
0022
0023
0024
0025
0026
0027
0028
0029
0030 static void peaq_wmi_poll(struct input_dev *input_dev)
0031 {
0032 static unsigned long last_event_time;
0033 static bool had_events;
0034 union acpi_object obj;
0035 acpi_status status;
0036 u32 dummy = 0;
0037
0038 struct acpi_buffer input = { sizeof(dummy), &dummy };
0039 struct acpi_buffer output = { sizeof(obj), &obj };
0040
0041 status = wmi_evaluate_method(PEAQ_DOLBY_BUTTON_GUID, 0,
0042 PEAQ_DOLBY_BUTTON_METHOD_ID,
0043 &input, &output);
0044 if (ACPI_FAILURE(status))
0045 return;
0046
0047 if (obj.type != ACPI_TYPE_INTEGER) {
0048 dev_err(&input_dev->dev,
0049 "Error WMBC did not return an integer\n");
0050 return;
0051 }
0052
0053 if (!obj.integer.value)
0054 return;
0055
0056 if (had_events && time_before(jiffies, last_event_time +
0057 msecs_to_jiffies(PEAQ_POLL_IGNORE_MS)))
0058 return;
0059
0060 input_event(input_dev, EV_KEY, KEY_SOUND, 1);
0061 input_sync(input_dev);
0062 input_event(input_dev, EV_KEY, KEY_SOUND, 0);
0063 input_sync(input_dev);
0064
0065 last_event_time = jiffies;
0066 had_events = true;
0067 }
0068
0069
0070 static const struct dmi_system_id peaq_dmi_table[] __initconst = {
0071 {
0072 .matches = {
0073 DMI_MATCH(DMI_SYS_VENDOR, "PEAQ"),
0074 DMI_MATCH(DMI_PRODUCT_NAME, "PEAQ PMM C1010 MD99187"),
0075 },
0076 },
0077 {}
0078 };
0079
0080 static int __init peaq_wmi_init(void)
0081 {
0082 int err;
0083
0084
0085 if (!dmi_check_system(peaq_dmi_table))
0086 return -ENODEV;
0087
0088 if (!wmi_has_guid(PEAQ_DOLBY_BUTTON_GUID))
0089 return -ENODEV;
0090
0091 peaq_poll_dev = input_allocate_device();
0092 if (!peaq_poll_dev)
0093 return -ENOMEM;
0094
0095 peaq_poll_dev->name = "PEAQ WMI hotkeys";
0096 peaq_poll_dev->phys = "wmi/input0";
0097 peaq_poll_dev->id.bustype = BUS_HOST;
0098 input_set_capability(peaq_poll_dev, EV_KEY, KEY_SOUND);
0099
0100 err = input_setup_polling(peaq_poll_dev, peaq_wmi_poll);
0101 if (err)
0102 goto err_out;
0103
0104 input_set_poll_interval(peaq_poll_dev, PEAQ_POLL_INTERVAL_MS);
0105 input_set_max_poll_interval(peaq_poll_dev, PEAQ_POLL_MAX_MS);
0106
0107 err = input_register_device(peaq_poll_dev);
0108 if (err)
0109 goto err_out;
0110
0111 return 0;
0112
0113 err_out:
0114 input_free_device(peaq_poll_dev);
0115 return err;
0116 }
0117
0118 static void __exit peaq_wmi_exit(void)
0119 {
0120 input_unregister_device(peaq_poll_dev);
0121 }
0122
0123 module_init(peaq_wmi_init);
0124 module_exit(peaq_wmi_exit);
0125
0126 MODULE_DESCRIPTION("PEAQ 2-in-1 WMI hotkey driver");
0127 MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
0128 MODULE_LICENSE("GPL");