1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * toshiba_wmi.c - Toshiba WMI Hotkey Driver 4 * 5 * Copyright (C) 2015 Azael Avalos <coproscefalo@gmail.com> 6 */ 7 8 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 9 10 #include <linux/kernel.h> 11 #include <linux/module.h> 12 #include <linux/init.h> 13 #include <linux/types.h> 14 #include <linux/acpi.h> 15 #include <linux/input.h> 16 #include <linux/input/sparse-keymap.h> 17 #include <linux/dmi.h> 18 19 MODULE_AUTHOR("Azael Avalos"); 20 MODULE_DESCRIPTION("Toshiba WMI Hotkey Driver"); 21 MODULE_LICENSE("GPL"); 22 23 #define WMI_EVENT_GUID "59142400-C6A3-40FA-BADB-8A2652834100" 24 25 MODULE_ALIAS("wmi:"WMI_EVENT_GUID); 26 27 static struct input_dev *toshiba_wmi_input_dev; 28 29 static const struct key_entry toshiba_wmi_keymap[] __initconst = { 30 /* TODO: Add keymap values once found... */ 31 /*{ KE_KEY, 0x00, { KEY_ } },*/ 32 { KE_END, 0 } 33 }; 34 35 static void toshiba_wmi_notify(union acpi_object *obj, void *context) 36 { 37 if (!obj) 38 return; 39 40 /* TODO: Add proper checks once we have data */ 41 pr_debug("Unknown event received, obj type %x\n", obj->type); 42 } 43 44 static const struct dmi_system_id toshiba_wmi_dmi_table[] __initconst = { 45 { 46 .ident = "Toshiba laptop", 47 .matches = { 48 DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), 49 }, 50 }, 51 {} 52 }; 53 54 static int __init toshiba_wmi_input_setup(void) 55 { 56 acpi_status status; 57 int err; 58 59 toshiba_wmi_input_dev = input_allocate_device(); 60 if (!toshiba_wmi_input_dev) 61 return -ENOMEM; 62 63 toshiba_wmi_input_dev->name = "Toshiba WMI hotkeys"; 64 toshiba_wmi_input_dev->phys = "wmi/input0"; 65 toshiba_wmi_input_dev->id.bustype = BUS_HOST; 66 67 err = sparse_keymap_setup(toshiba_wmi_input_dev, 68 toshiba_wmi_keymap, NULL); 69 if (err) 70 goto err_free_dev; 71 72 status = wmi_install_notify_handler(WMI_EVENT_GUID, 73 toshiba_wmi_notify, NULL); 74 if (ACPI_FAILURE(status)) { 75 err = -EIO; 76 goto err_free_dev; 77 } 78 79 err = input_register_device(toshiba_wmi_input_dev); 80 if (err) 81 goto err_remove_notifier; 82 83 return 0; 84 85 err_remove_notifier: 86 wmi_remove_notify_handler(WMI_EVENT_GUID); 87 err_free_dev: 88 input_free_device(toshiba_wmi_input_dev); 89 return err; 90 } 91 92 static void toshiba_wmi_input_destroy(void) 93 { 94 wmi_remove_notify_handler(WMI_EVENT_GUID); 95 input_unregister_device(toshiba_wmi_input_dev); 96 } 97 98 static int __init toshiba_wmi_init(void) 99 { 100 int ret; 101 102 if (!wmi_has_guid(WMI_EVENT_GUID) || 103 !dmi_check_system(toshiba_wmi_dmi_table)) 104 return -ENODEV; 105 106 ret = toshiba_wmi_input_setup(); 107 if (ret) { 108 pr_err("Failed to setup input device\n"); 109 return ret; 110 } 111 112 pr_info("Toshiba WMI Hotkey Driver\n"); 113 114 return 0; 115 } 116 117 static void __exit toshiba_wmi_exit(void) 118 { 119 if (wmi_has_guid(WMI_EVENT_GUID)) 120 toshiba_wmi_input_destroy(); 121 } 122 123 module_init(toshiba_wmi_init); 124 module_exit(toshiba_wmi_exit); 125