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 v6.12 124 lines 2.8 kB view raw
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 17MODULE_DESCRIPTION("Airplane mode button for AMD, HP & Xiaomi laptops"); 18MODULE_LICENSE("GPL"); 19MODULE_AUTHOR("Alex Hung"); 20MODULE_ALIAS("acpi*:HPQ6001:*"); 21MODULE_ALIAS("acpi*:WSTADEF:*"); 22MODULE_ALIAS("acpi*:AMDI0051:*"); 23MODULE_ALIAS("acpi*:LGEX0815:*"); 24 25struct wl_button { 26 struct input_dev *input_dev; 27 char phys[32]; 28}; 29 30static const struct acpi_device_id wl_ids[] = { 31 {"HPQ6001", 0}, 32 {"WSTADEF", 0}, 33 {"AMDI0051", 0}, 34 {"LGEX0815", 0}, 35 {"", 0}, 36}; 37 38static int wireless_input_setup(struct acpi_device *device) 39{ 40 struct wl_button *button = acpi_driver_data(device); 41 int err; 42 43 button->input_dev = input_allocate_device(); 44 if (!button->input_dev) 45 return -ENOMEM; 46 47 snprintf(button->phys, sizeof(button->phys), "%s/input0", acpi_device_hid(device)); 48 49 button->input_dev->name = "Wireless hotkeys"; 50 button->input_dev->phys = button->phys; 51 button->input_dev->id.bustype = BUS_HOST; 52 button->input_dev->evbit[0] = BIT(EV_KEY); 53 set_bit(KEY_RFKILL, button->input_dev->keybit); 54 55 err = input_register_device(button->input_dev); 56 if (err) 57 goto err_free_dev; 58 59 return 0; 60 61err_free_dev: 62 input_free_device(button->input_dev); 63 return err; 64} 65 66static void wireless_input_destroy(struct acpi_device *device) 67{ 68 struct wl_button *button = acpi_driver_data(device); 69 70 input_unregister_device(button->input_dev); 71 kfree(button); 72} 73 74static void wl_notify(struct acpi_device *acpi_dev, u32 event) 75{ 76 struct wl_button *button = acpi_driver_data(acpi_dev); 77 78 if (event != 0x80) { 79 pr_info("Received unknown event (0x%x)\n", event); 80 return; 81 } 82 83 input_report_key(button->input_dev, KEY_RFKILL, 1); 84 input_sync(button->input_dev); 85 input_report_key(button->input_dev, KEY_RFKILL, 0); 86 input_sync(button->input_dev); 87} 88 89static int wl_add(struct acpi_device *device) 90{ 91 struct wl_button *button; 92 int err; 93 94 button = kzalloc(sizeof(struct wl_button), GFP_KERNEL); 95 if (!button) 96 return -ENOMEM; 97 98 device->driver_data = button; 99 100 err = wireless_input_setup(device); 101 if (err) { 102 pr_err("Failed to setup wireless hotkeys\n"); 103 kfree(button); 104 } 105 106 return err; 107} 108 109static void wl_remove(struct acpi_device *device) 110{ 111 wireless_input_destroy(device); 112} 113 114static struct acpi_driver wl_driver = { 115 .name = "wireless-hotkey", 116 .ids = wl_ids, 117 .ops = { 118 .add = wl_add, 119 .remove = wl_remove, 120 .notify = wl_notify, 121 }, 122}; 123 124module_acpi_driver(wl_driver);