Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v4.16-rc5 113 lines 3.4 kB view raw
1/* 2 * PEAQ 2-in-1 WMI hotkey driver 3 * Copyright (C) 2017 Hans de Goede <hdegoede@redhat.com> 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> 11#include <linux/dmi.h> 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 22MODULE_ALIAS("wmi:"PEAQ_DOLBY_BUTTON_GUID); 23 24static unsigned int peaq_ignore_events_counter; 25static 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 */ 34static 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 43 status = wmi_evaluate_method(PEAQ_DOLBY_BUTTON_GUID, 0, 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 55 if (peaq_ignore_events_counter && peaq_ignore_events_counter--) 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 68/* Some other devices (Shuttle XS35) use the same WMI GUID for other purposes */ 69static const struct dmi_system_id peaq_dmi_table[] __initconst = { 70 { 71 .matches = { 72 DMI_MATCH(DMI_SYS_VENDOR, "PEAQ"), 73 DMI_MATCH(DMI_PRODUCT_NAME, "PEAQ PMM C1010 MD99187"), 74 }, 75 }, 76 {} 77}; 78 79static int __init peaq_wmi_init(void) 80{ 81 /* WMI GUID is not unique, also check for a DMI match */ 82 if (!dmi_check_system(peaq_dmi_table)) 83 return -ENODEV; 84 85 if (!wmi_has_guid(PEAQ_DOLBY_BUTTON_GUID)) 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 103static void __exit peaq_wmi_exit(void) 104{ 105 input_unregister_polled_device(peaq_poll_dev); 106} 107 108module_init(peaq_wmi_init); 109module_exit(peaq_wmi_exit); 110 111MODULE_DESCRIPTION("PEAQ 2-in-1 WMI hotkey driver"); 112MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>"); 113MODULE_LICENSE("GPL");