Commit | Line | Data |
---|---|---|
a558ea42 ML |
1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* | |
3 | * Airplane mode button for AMD, HP & Xiaomi laptops | |
4 | * | |
5 | * Copyright (C) 2014-2017 Alex Hung <alex.hung@canonical.com> | |
6 | * Copyright (C) 2021 Advanced Micro Devices | |
7 | */ | |
8 | ||
9 | #include <linux/kernel.h> | |
10 | #include <linux/module.h> | |
11 | #include <linux/init.h> | |
12 | #include <linux/input.h> | |
13 | #include <linux/platform_device.h> | |
14 | #include <linux/acpi.h> | |
15 | #include <acpi/acpi_bus.h> | |
16 | ||
17 | MODULE_LICENSE("GPL"); | |
18 | MODULE_AUTHOR("Alex Hung"); | |
19 | MODULE_ALIAS("acpi*:HPQ6001:*"); | |
20 | MODULE_ALIAS("acpi*:WSTADEF:*"); | |
21 | MODULE_ALIAS("acpi*:AMDI0051:*"); | |
22 | ||
23 | static struct input_dev *wl_input_dev; | |
24 | ||
25 | static const struct acpi_device_id wl_ids[] = { | |
26 | {"HPQ6001", 0}, | |
27 | {"WSTADEF", 0}, | |
28 | {"AMDI0051", 0}, | |
29 | {"", 0}, | |
30 | }; | |
31 | ||
32 | static int wireless_input_setup(void) | |
33 | { | |
34 | int err; | |
35 | ||
36 | wl_input_dev = input_allocate_device(); | |
37 | if (!wl_input_dev) | |
38 | return -ENOMEM; | |
39 | ||
40 | wl_input_dev->name = "Wireless hotkeys"; | |
41 | wl_input_dev->phys = "hpq6001/input0"; | |
42 | wl_input_dev->id.bustype = BUS_HOST; | |
43 | wl_input_dev->evbit[0] = BIT(EV_KEY); | |
44 | set_bit(KEY_RFKILL, wl_input_dev->keybit); | |
45 | ||
46 | err = input_register_device(wl_input_dev); | |
47 | if (err) | |
48 | goto err_free_dev; | |
49 | ||
50 | return 0; | |
51 | ||
52 | err_free_dev: | |
53 | input_free_device(wl_input_dev); | |
54 | return err; | |
55 | } | |
56 | ||
57 | static void wireless_input_destroy(void) | |
58 | { | |
59 | input_unregister_device(wl_input_dev); | |
60 | } | |
61 | ||
62 | static void wl_notify(struct acpi_device *acpi_dev, u32 event) | |
63 | { | |
64 | if (event != 0x80) { | |
65 | pr_info("Received unknown event (0x%x)\n", event); | |
66 | return; | |
67 | } | |
68 | ||
69 | input_report_key(wl_input_dev, KEY_RFKILL, 1); | |
70 | input_sync(wl_input_dev); | |
71 | input_report_key(wl_input_dev, KEY_RFKILL, 0); | |
72 | input_sync(wl_input_dev); | |
73 | } | |
74 | ||
75 | static int wl_add(struct acpi_device *device) | |
76 | { | |
77 | int err; | |
78 | ||
79 | err = wireless_input_setup(); | |
80 | if (err) | |
23e9592b | 81 | pr_err("Failed to setup wireless hotkeys\n"); |
a558ea42 ML |
82 | |
83 | return err; | |
84 | } | |
85 | ||
86 | static int wl_remove(struct acpi_device *device) | |
87 | { | |
88 | wireless_input_destroy(); | |
89 | return 0; | |
90 | } | |
91 | ||
92 | static struct acpi_driver wl_driver = { | |
93 | .name = "wireless-hotkey", | |
94 | .owner = THIS_MODULE, | |
95 | .ids = wl_ids, | |
96 | .ops = { | |
97 | .add = wl_add, | |
98 | .remove = wl_remove, | |
99 | .notify = wl_notify, | |
100 | }, | |
101 | }; | |
102 | ||
103 | module_acpi_driver(wl_driver); |