1 /* 2 * toshiba_wmi.c - Toshiba WMI Hotkey Driver 3 * 4 * Copyright (C) 2015 Azael Avalos <coproscefalo@gmail.com> 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 */ 17 18 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 19 20 #include <linux/kernel.h> 21 #include <linux/module.h> 22 #include <linux/init.h> 23 #include <linux/types.h> 24 #include <linux/acpi.h> 25 #include <linux/input.h> 26 #include <linux/input/sparse-keymap.h> 27 28 MODULE_AUTHOR("Azael Avalos"); 29 MODULE_DESCRIPTION("Toshiba WMI Hotkey Driver"); 30 MODULE_LICENSE("GPL"); 31 32 #define TOSHIBA_WMI_EVENT_GUID "59142400-C6A3-40FA-BADB-8A2652834100" 33 34 MODULE_ALIAS("wmi:"TOSHIBA_WMI_EVENT_GUID); 35 36 static struct input_dev *toshiba_wmi_input_dev; 37 38 static const struct key_entry toshiba_wmi_keymap[] __initconst = { 39 /* TODO: Add keymap values once found... */ 40 /*{ KE_KEY, 0x00, { KEY_ } },*/ 41 { KE_END, 0 } 42 }; 43 44 static void toshiba_wmi_notify(u32 value, void *context) 45 { 46 struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL }; 47 union acpi_object *obj; 48 acpi_status status; 49 50 status = wmi_get_event_data(value, &response); 51 if (ACPI_FAILURE(status)) { 52 pr_err("Bad event status 0x%x\n", status); 53 return; 54 } 55 56 obj = (union acpi_object *)response.pointer; 57 if (!obj) 58 return; 59 60 /* TODO: Add proper checks once we have data */ 61 pr_debug("Unknown event received, obj type %x\n", obj->type); 62 63 kfree(response.pointer); 64 } 65 66 static int __init toshiba_wmi_input_setup(void) 67 { 68 acpi_status status; 69 int err; 70 71 toshiba_wmi_input_dev = input_allocate_device(); 72 if (!toshiba_wmi_input_dev) 73 return -ENOMEM; 74 75 toshiba_wmi_input_dev->name = "Toshiba WMI hotkeys"; 76 toshiba_wmi_input_dev->phys = "wmi/input0"; 77 toshiba_wmi_input_dev->id.bustype = BUS_HOST; 78 79 err = sparse_keymap_setup(toshiba_wmi_input_dev, 80 toshiba_wmi_keymap, NULL); 81 if (err) 82 goto err_free_dev; 83 84 status = wmi_install_notify_handler(TOSHIBA_WMI_EVENT_GUID, 85 toshiba_wmi_notify, NULL); 86 if (ACPI_FAILURE(status)) { 87 err = -EIO; 88 goto err_free_keymap; 89 } 90 91 err = input_register_device(toshiba_wmi_input_dev); 92 if (err) 93 goto err_remove_notifier; 94 95 return 0; 96 97 err_remove_notifier: 98 wmi_remove_notify_handler(TOSHIBA_WMI_EVENT_GUID); 99 err_free_keymap: 100 sparse_keymap_free(toshiba_wmi_input_dev); 101 err_free_dev: 102 input_free_device(toshiba_wmi_input_dev); 103 return err; 104 } 105 106 static void toshiba_wmi_input_destroy(void) 107 { 108 wmi_remove_notify_handler(TOSHIBA_WMI_EVENT_GUID); 109 sparse_keymap_free(toshiba_wmi_input_dev); 110 input_unregister_device(toshiba_wmi_input_dev); 111 } 112 113 static int __init toshiba_wmi_init(void) 114 { 115 int ret; 116 117 if (!wmi_has_guid(TOSHIBA_WMI_EVENT_GUID)) 118 return -ENODEV; 119 120 ret = toshiba_wmi_input_setup(); 121 if (ret) { 122 pr_err("Failed to setup input device\n"); 123 return ret; 124 } 125 126 pr_info("Toshiba WMI Hotkey Driver\n"); 127 128 return 0; 129 } 130 131 static void __exit toshiba_wmi_exit(void) 132 { 133 if (wmi_has_guid(TOSHIBA_WMI_EVENT_GUID)) 134 toshiba_wmi_input_destroy(); 135 } 136 137 module_init(toshiba_wmi_init); 138 module_exit(toshiba_wmi_exit); 139