114991fc7SAzael Avalos /* 214991fc7SAzael Avalos * toshiba_wmi.c - Toshiba WMI Hotkey Driver 314991fc7SAzael Avalos * 414991fc7SAzael Avalos * Copyright (C) 2015 Azael Avalos <coproscefalo@gmail.com> 514991fc7SAzael Avalos * 614991fc7SAzael Avalos * This program is free software; you can redistribute it and/or modify 714991fc7SAzael Avalos * it under the terms of the GNU General Public License as published by 814991fc7SAzael Avalos * the Free Software Foundation; either version 2 of the License, or 914991fc7SAzael Avalos * (at your option) any later version. 1014991fc7SAzael Avalos * 1114991fc7SAzael Avalos * This program is distributed in the hope that it will be useful, 1214991fc7SAzael Avalos * but WITHOUT ANY WARRANTY; without even the implied warranty of 1314991fc7SAzael Avalos * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1414991fc7SAzael Avalos * GNU General Public License for more details. 1514991fc7SAzael Avalos * 1614991fc7SAzael Avalos */ 1714991fc7SAzael Avalos 1814991fc7SAzael Avalos #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 1914991fc7SAzael Avalos 2014991fc7SAzael Avalos #include <linux/kernel.h> 2114991fc7SAzael Avalos #include <linux/module.h> 2214991fc7SAzael Avalos #include <linux/init.h> 2314991fc7SAzael Avalos #include <linux/types.h> 2414991fc7SAzael Avalos #include <linux/acpi.h> 2514991fc7SAzael Avalos #include <linux/input.h> 2614991fc7SAzael Avalos #include <linux/input/sparse-keymap.h> 271c80e960SAzael Avalos #include <linux/dmi.h> 2814991fc7SAzael Avalos 2914991fc7SAzael Avalos MODULE_AUTHOR("Azael Avalos"); 3014991fc7SAzael Avalos MODULE_DESCRIPTION("Toshiba WMI Hotkey Driver"); 3114991fc7SAzael Avalos MODULE_LICENSE("GPL"); 3214991fc7SAzael Avalos 331c80e960SAzael Avalos #define WMI_EVENT_GUID "59142400-C6A3-40FA-BADB-8A2652834100" 3414991fc7SAzael Avalos 351c80e960SAzael Avalos MODULE_ALIAS("wmi:"WMI_EVENT_GUID); 3614991fc7SAzael Avalos 3714991fc7SAzael Avalos static struct input_dev *toshiba_wmi_input_dev; 3814991fc7SAzael Avalos 3914991fc7SAzael Avalos static const struct key_entry toshiba_wmi_keymap[] __initconst = { 4014991fc7SAzael Avalos /* TODO: Add keymap values once found... */ 4114991fc7SAzael Avalos /*{ KE_KEY, 0x00, { KEY_ } },*/ 4214991fc7SAzael Avalos { KE_END, 0 } 4314991fc7SAzael Avalos }; 4414991fc7SAzael Avalos 4514991fc7SAzael Avalos static void toshiba_wmi_notify(u32 value, void *context) 4614991fc7SAzael Avalos { 4714991fc7SAzael Avalos struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL }; 4814991fc7SAzael Avalos union acpi_object *obj; 4914991fc7SAzael Avalos acpi_status status; 5014991fc7SAzael Avalos 5114991fc7SAzael Avalos status = wmi_get_event_data(value, &response); 5214991fc7SAzael Avalos if (ACPI_FAILURE(status)) { 5314991fc7SAzael Avalos pr_err("Bad event status 0x%x\n", status); 5414991fc7SAzael Avalos return; 5514991fc7SAzael Avalos } 5614991fc7SAzael Avalos 5714991fc7SAzael Avalos obj = (union acpi_object *)response.pointer; 5814991fc7SAzael Avalos if (!obj) 5914991fc7SAzael Avalos return; 6014991fc7SAzael Avalos 6114991fc7SAzael Avalos /* TODO: Add proper checks once we have data */ 6214991fc7SAzael Avalos pr_debug("Unknown event received, obj type %x\n", obj->type); 6314991fc7SAzael Avalos 6414991fc7SAzael Avalos kfree(response.pointer); 6514991fc7SAzael Avalos } 6614991fc7SAzael Avalos 671c80e960SAzael Avalos static struct dmi_system_id toshiba_wmi_dmi_table[] __initdata = { 681c80e960SAzael Avalos { 691c80e960SAzael Avalos .ident = "Toshiba laptop", 701c80e960SAzael Avalos .matches = { 711c80e960SAzael Avalos DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), 721c80e960SAzael Avalos }, 731c80e960SAzael Avalos }, 741c80e960SAzael Avalos {} 751c80e960SAzael Avalos }; 761c80e960SAzael Avalos 7714991fc7SAzael Avalos static int __init toshiba_wmi_input_setup(void) 7814991fc7SAzael Avalos { 7914991fc7SAzael Avalos acpi_status status; 8014991fc7SAzael Avalos int err; 8114991fc7SAzael Avalos 8214991fc7SAzael Avalos toshiba_wmi_input_dev = input_allocate_device(); 8314991fc7SAzael Avalos if (!toshiba_wmi_input_dev) 8414991fc7SAzael Avalos return -ENOMEM; 8514991fc7SAzael Avalos 8614991fc7SAzael Avalos toshiba_wmi_input_dev->name = "Toshiba WMI hotkeys"; 8714991fc7SAzael Avalos toshiba_wmi_input_dev->phys = "wmi/input0"; 8814991fc7SAzael Avalos toshiba_wmi_input_dev->id.bustype = BUS_HOST; 8914991fc7SAzael Avalos 9014991fc7SAzael Avalos err = sparse_keymap_setup(toshiba_wmi_input_dev, 9114991fc7SAzael Avalos toshiba_wmi_keymap, NULL); 9214991fc7SAzael Avalos if (err) 9314991fc7SAzael Avalos goto err_free_dev; 9414991fc7SAzael Avalos 951c80e960SAzael Avalos status = wmi_install_notify_handler(WMI_EVENT_GUID, 9614991fc7SAzael Avalos toshiba_wmi_notify, NULL); 9714991fc7SAzael Avalos if (ACPI_FAILURE(status)) { 9814991fc7SAzael Avalos err = -EIO; 9914991fc7SAzael Avalos goto err_free_keymap; 10014991fc7SAzael Avalos } 10114991fc7SAzael Avalos 10214991fc7SAzael Avalos err = input_register_device(toshiba_wmi_input_dev); 10314991fc7SAzael Avalos if (err) 10414991fc7SAzael Avalos goto err_remove_notifier; 10514991fc7SAzael Avalos 10614991fc7SAzael Avalos return 0; 10714991fc7SAzael Avalos 10814991fc7SAzael Avalos err_remove_notifier: 1091c80e960SAzael Avalos wmi_remove_notify_handler(WMI_EVENT_GUID); 11014991fc7SAzael Avalos err_free_keymap: 11114991fc7SAzael Avalos sparse_keymap_free(toshiba_wmi_input_dev); 11214991fc7SAzael Avalos err_free_dev: 11314991fc7SAzael Avalos input_free_device(toshiba_wmi_input_dev); 11414991fc7SAzael Avalos return err; 11514991fc7SAzael Avalos } 11614991fc7SAzael Avalos 11714991fc7SAzael Avalos static void toshiba_wmi_input_destroy(void) 11814991fc7SAzael Avalos { 1191c80e960SAzael Avalos wmi_remove_notify_handler(WMI_EVENT_GUID); 12014991fc7SAzael Avalos sparse_keymap_free(toshiba_wmi_input_dev); 12114991fc7SAzael Avalos input_unregister_device(toshiba_wmi_input_dev); 12214991fc7SAzael Avalos } 12314991fc7SAzael Avalos 12414991fc7SAzael Avalos static int __init toshiba_wmi_init(void) 12514991fc7SAzael Avalos { 12614991fc7SAzael Avalos int ret; 12714991fc7SAzael Avalos 1281c80e960SAzael Avalos if (!wmi_has_guid(WMI_EVENT_GUID) || 1291c80e960SAzael Avalos !dmi_check_system(toshiba_wmi_dmi_table)) 13014991fc7SAzael Avalos return -ENODEV; 13114991fc7SAzael Avalos 13214991fc7SAzael Avalos ret = toshiba_wmi_input_setup(); 13314991fc7SAzael Avalos if (ret) { 13414991fc7SAzael Avalos pr_err("Failed to setup input device\n"); 13514991fc7SAzael Avalos return ret; 13614991fc7SAzael Avalos } 13714991fc7SAzael Avalos 13814991fc7SAzael Avalos pr_info("Toshiba WMI Hotkey Driver\n"); 13914991fc7SAzael Avalos 14014991fc7SAzael Avalos return 0; 14114991fc7SAzael Avalos } 14214991fc7SAzael Avalos 14314991fc7SAzael Avalos static void __exit toshiba_wmi_exit(void) 14414991fc7SAzael Avalos { 1451c80e960SAzael Avalos if (wmi_has_guid(WMI_EVENT_GUID)) 14614991fc7SAzael Avalos toshiba_wmi_input_destroy(); 14714991fc7SAzael Avalos } 14814991fc7SAzael Avalos 14914991fc7SAzael Avalos module_init(toshiba_wmi_init); 15014991fc7SAzael Avalos module_exit(toshiba_wmi_exit); 151