cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

peaq-wmi.c (3284B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * PEAQ 2-in-1 WMI hotkey driver
      4 * Copyright (C) 2017 Hans de Goede <hdegoede@redhat.com>
      5 */
      6
      7#include <linux/acpi.h>
      8#include <linux/dmi.h>
      9#include <linux/input.h>
     10#include <linux/kernel.h>
     11#include <linux/module.h>
     12
     13#define PEAQ_DOLBY_BUTTON_GUID		"ABBC0F6F-8EA1-11D1-00A0-C90629100000"
     14#define PEAQ_DOLBY_BUTTON_METHOD_ID	5
     15#define PEAQ_POLL_INTERVAL_MS		250
     16#define PEAQ_POLL_IGNORE_MS		500
     17#define PEAQ_POLL_MAX_MS		1000
     18
     19MODULE_ALIAS("wmi:"PEAQ_DOLBY_BUTTON_GUID);
     20
     21static struct input_dev *peaq_poll_dev;
     22
     23/*
     24 * The Dolby button (yes really a Dolby button) causes an ACPI variable to get
     25 * set on both press and release. The WMI method checks and clears that flag.
     26 * So for a press + release we will get back One from the WMI method either once
     27 * (if polling after the release) or twice (polling between press and release).
     28 * We ignore events for 0.5s after the first event to avoid reporting 2 presses.
     29 */
     30static void peaq_wmi_poll(struct input_dev *input_dev)
     31{
     32	static unsigned long last_event_time;
     33	static bool had_events;
     34	union acpi_object obj;
     35	acpi_status status;
     36	u32 dummy = 0;
     37
     38	struct acpi_buffer input = { sizeof(dummy), &dummy };
     39	struct acpi_buffer output = { sizeof(obj), &obj };
     40
     41	status = wmi_evaluate_method(PEAQ_DOLBY_BUTTON_GUID, 0,
     42				     PEAQ_DOLBY_BUTTON_METHOD_ID,
     43				     &input, &output);
     44	if (ACPI_FAILURE(status))
     45		return;
     46
     47	if (obj.type != ACPI_TYPE_INTEGER) {
     48		dev_err(&input_dev->dev,
     49			"Error WMBC did not return an integer\n");
     50		return;
     51	}
     52
     53	if (!obj.integer.value)
     54		return;
     55
     56	if (had_events && time_before(jiffies, last_event_time +
     57					msecs_to_jiffies(PEAQ_POLL_IGNORE_MS)))
     58		return;
     59
     60	input_event(input_dev, EV_KEY, KEY_SOUND, 1);
     61	input_sync(input_dev);
     62	input_event(input_dev, EV_KEY, KEY_SOUND, 0);
     63	input_sync(input_dev);
     64
     65	last_event_time = jiffies;
     66	had_events = true;
     67}
     68
     69/* Some other devices (Shuttle XS35) use the same WMI GUID for other purposes */
     70static const struct dmi_system_id peaq_dmi_table[] __initconst = {
     71	{
     72		.matches = {
     73			DMI_MATCH(DMI_SYS_VENDOR, "PEAQ"),
     74			DMI_MATCH(DMI_PRODUCT_NAME, "PEAQ PMM C1010 MD99187"),
     75		},
     76	},
     77	{}
     78};
     79
     80static int __init peaq_wmi_init(void)
     81{
     82	int err;
     83
     84	/* WMI GUID is not unique, also check for a DMI match */
     85	if (!dmi_check_system(peaq_dmi_table))
     86		return -ENODEV;
     87
     88	if (!wmi_has_guid(PEAQ_DOLBY_BUTTON_GUID))
     89		return -ENODEV;
     90
     91	peaq_poll_dev = input_allocate_device();
     92	if (!peaq_poll_dev)
     93		return -ENOMEM;
     94
     95	peaq_poll_dev->name = "PEAQ WMI hotkeys";
     96	peaq_poll_dev->phys = "wmi/input0";
     97	peaq_poll_dev->id.bustype = BUS_HOST;
     98	input_set_capability(peaq_poll_dev, EV_KEY, KEY_SOUND);
     99
    100	err = input_setup_polling(peaq_poll_dev, peaq_wmi_poll);
    101	if (err)
    102		goto err_out;
    103
    104	input_set_poll_interval(peaq_poll_dev, PEAQ_POLL_INTERVAL_MS);
    105	input_set_max_poll_interval(peaq_poll_dev, PEAQ_POLL_MAX_MS);
    106
    107	err = input_register_device(peaq_poll_dev);
    108	if (err)
    109		goto err_out;
    110
    111	return 0;
    112
    113err_out:
    114	input_free_device(peaq_poll_dev);
    115	return err;
    116}
    117
    118static void __exit peaq_wmi_exit(void)
    119{
    120	input_unregister_device(peaq_poll_dev);
    121}
    122
    123module_init(peaq_wmi_init);
    124module_exit(peaq_wmi_exit);
    125
    126MODULE_DESCRIPTION("PEAQ 2-in-1 WMI hotkey driver");
    127MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
    128MODULE_LICENSE("GPL");