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> 2714991fc7SAzael Avalos 2814991fc7SAzael Avalos MODULE_AUTHOR("Azael Avalos"); 2914991fc7SAzael Avalos MODULE_DESCRIPTION("Toshiba WMI Hotkey Driver"); 3014991fc7SAzael Avalos MODULE_LICENSE("GPL"); 3114991fc7SAzael Avalos 3214991fc7SAzael Avalos #define TOSHIBA_WMI_EVENT_GUID "59142400-C6A3-40FA-BADB-8A2652834100" 3314991fc7SAzael Avalos 3414991fc7SAzael Avalos MODULE_ALIAS("wmi:"TOSHIBA_WMI_EVENT_GUID); 3514991fc7SAzael Avalos 3614991fc7SAzael Avalos static struct input_dev *toshiba_wmi_input_dev; 3714991fc7SAzael Avalos 3814991fc7SAzael Avalos static const struct key_entry toshiba_wmi_keymap[] __initconst = { 3914991fc7SAzael Avalos /* TODO: Add keymap values once found... */ 4014991fc7SAzael Avalos /*{ KE_KEY, 0x00, { KEY_ } },*/ 4114991fc7SAzael Avalos { KE_END, 0 } 4214991fc7SAzael Avalos }; 4314991fc7SAzael Avalos 4414991fc7SAzael Avalos static void toshiba_wmi_notify(u32 value, void *context) 4514991fc7SAzael Avalos { 4614991fc7SAzael Avalos struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL }; 4714991fc7SAzael Avalos union acpi_object *obj; 4814991fc7SAzael Avalos acpi_status status; 4914991fc7SAzael Avalos 5014991fc7SAzael Avalos status = wmi_get_event_data(value, &response); 5114991fc7SAzael Avalos if (ACPI_FAILURE(status)) { 5214991fc7SAzael Avalos pr_err("Bad event status 0x%x\n", status); 5314991fc7SAzael Avalos return; 5414991fc7SAzael Avalos } 5514991fc7SAzael Avalos 5614991fc7SAzael Avalos obj = (union acpi_object *)response.pointer; 5714991fc7SAzael Avalos if (!obj) 5814991fc7SAzael Avalos return; 5914991fc7SAzael Avalos 6014991fc7SAzael Avalos /* TODO: Add proper checks once we have data */ 6114991fc7SAzael Avalos pr_debug("Unknown event received, obj type %x\n", obj->type); 6214991fc7SAzael Avalos 6314991fc7SAzael Avalos kfree(response.pointer); 6414991fc7SAzael Avalos } 6514991fc7SAzael Avalos 6614991fc7SAzael Avalos static int __init toshiba_wmi_input_setup(void) 6714991fc7SAzael Avalos { 6814991fc7SAzael Avalos acpi_status status; 6914991fc7SAzael Avalos int err; 7014991fc7SAzael Avalos 7114991fc7SAzael Avalos toshiba_wmi_input_dev = input_allocate_device(); 7214991fc7SAzael Avalos if (!toshiba_wmi_input_dev) 7314991fc7SAzael Avalos return -ENOMEM; 7414991fc7SAzael Avalos 7514991fc7SAzael Avalos toshiba_wmi_input_dev->name = "Toshiba WMI hotkeys"; 7614991fc7SAzael Avalos toshiba_wmi_input_dev->phys = "wmi/input0"; 7714991fc7SAzael Avalos toshiba_wmi_input_dev->id.bustype = BUS_HOST; 7814991fc7SAzael Avalos 7914991fc7SAzael Avalos err = sparse_keymap_setup(toshiba_wmi_input_dev, 8014991fc7SAzael Avalos toshiba_wmi_keymap, NULL); 8114991fc7SAzael Avalos if (err) 8214991fc7SAzael Avalos goto err_free_dev; 8314991fc7SAzael Avalos 8414991fc7SAzael Avalos status = wmi_install_notify_handler(TOSHIBA_WMI_EVENT_GUID, 8514991fc7SAzael Avalos toshiba_wmi_notify, NULL); 8614991fc7SAzael Avalos if (ACPI_FAILURE(status)) { 8714991fc7SAzael Avalos err = -EIO; 8814991fc7SAzael Avalos goto err_free_keymap; 8914991fc7SAzael Avalos } 9014991fc7SAzael Avalos 9114991fc7SAzael Avalos err = input_register_device(toshiba_wmi_input_dev); 9214991fc7SAzael Avalos if (err) 9314991fc7SAzael Avalos goto err_remove_notifier; 9414991fc7SAzael Avalos 9514991fc7SAzael Avalos return 0; 9614991fc7SAzael Avalos 9714991fc7SAzael Avalos err_remove_notifier: 9814991fc7SAzael Avalos wmi_remove_notify_handler(TOSHIBA_WMI_EVENT_GUID); 9914991fc7SAzael Avalos err_free_keymap: 10014991fc7SAzael Avalos sparse_keymap_free(toshiba_wmi_input_dev); 10114991fc7SAzael Avalos err_free_dev: 10214991fc7SAzael Avalos input_free_device(toshiba_wmi_input_dev); 10314991fc7SAzael Avalos return err; 10414991fc7SAzael Avalos } 10514991fc7SAzael Avalos 10614991fc7SAzael Avalos static void toshiba_wmi_input_destroy(void) 10714991fc7SAzael Avalos { 10814991fc7SAzael Avalos wmi_remove_notify_handler(TOSHIBA_WMI_EVENT_GUID); 10914991fc7SAzael Avalos sparse_keymap_free(toshiba_wmi_input_dev); 11014991fc7SAzael Avalos input_unregister_device(toshiba_wmi_input_dev); 11114991fc7SAzael Avalos } 11214991fc7SAzael Avalos 11314991fc7SAzael Avalos static int __init toshiba_wmi_init(void) 11414991fc7SAzael Avalos { 11514991fc7SAzael Avalos int ret; 11614991fc7SAzael Avalos 11714991fc7SAzael Avalos if (!wmi_has_guid(TOSHIBA_WMI_EVENT_GUID)) 11814991fc7SAzael Avalos return -ENODEV; 11914991fc7SAzael Avalos 12014991fc7SAzael Avalos ret = toshiba_wmi_input_setup(); 12114991fc7SAzael Avalos if (ret) { 12214991fc7SAzael Avalos pr_err("Failed to setup input device\n"); 12314991fc7SAzael Avalos return ret; 12414991fc7SAzael Avalos } 12514991fc7SAzael Avalos 12614991fc7SAzael Avalos pr_info("Toshiba WMI Hotkey Driver\n"); 12714991fc7SAzael Avalos 12814991fc7SAzael Avalos return 0; 12914991fc7SAzael Avalos } 13014991fc7SAzael Avalos 13114991fc7SAzael Avalos static void __exit toshiba_wmi_exit(void) 13214991fc7SAzael Avalos { 13314991fc7SAzael Avalos if (wmi_has_guid(TOSHIBA_WMI_EVENT_GUID)) 13414991fc7SAzael Avalos toshiba_wmi_input_destroy(); 13514991fc7SAzael Avalos } 13614991fc7SAzael Avalos 13714991fc7SAzael Avalos module_init(toshiba_wmi_init); 13814991fc7SAzael Avalos module_exit(toshiba_wmi_exit); 139