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) 81 pr_err("Failed to setup wireless hotkeys\n"); 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); 104