linux/drivers/platform/x86/toshiba-wmi.c
<<
>>
Prefs
   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#include <linux/dmi.h>
  28
  29MODULE_AUTHOR("Azael Avalos");
  30MODULE_DESCRIPTION("Toshiba WMI Hotkey Driver");
  31MODULE_LICENSE("GPL");
  32
  33#define WMI_EVENT_GUID  "59142400-C6A3-40FA-BADB-8A2652834100"
  34
  35MODULE_ALIAS("wmi:"WMI_EVENT_GUID);
  36
  37static struct input_dev *toshiba_wmi_input_dev;
  38
  39static const struct key_entry toshiba_wmi_keymap[] __initconst = {
  40        /* TODO: Add keymap values once found... */
  41        /*{ KE_KEY, 0x00, { KEY_ } },*/
  42        { KE_END, 0 }
  43};
  44
  45static void toshiba_wmi_notify(u32 value, void *context)
  46{
  47        struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL };
  48        union acpi_object *obj;
  49        acpi_status status;
  50
  51        status = wmi_get_event_data(value, &response);
  52        if (ACPI_FAILURE(status)) {
  53                pr_err("Bad event status 0x%x\n", status);
  54                return;
  55        }
  56
  57        obj = (union acpi_object *)response.pointer;
  58        if (!obj)
  59                return;
  60
  61        /* TODO: Add proper checks once we have data */
  62        pr_debug("Unknown event received, obj type %x\n", obj->type);
  63
  64        kfree(response.pointer);
  65}
  66
  67static struct dmi_system_id toshiba_wmi_dmi_table[] __initdata = {
  68        {
  69                .ident = "Toshiba laptop",
  70                .matches = {
  71                        DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
  72                },
  73        },
  74        {}
  75};
  76
  77static int __init toshiba_wmi_input_setup(void)
  78{
  79        acpi_status status;
  80        int err;
  81
  82        toshiba_wmi_input_dev = input_allocate_device();
  83        if (!toshiba_wmi_input_dev)
  84                return -ENOMEM;
  85
  86        toshiba_wmi_input_dev->name = "Toshiba WMI hotkeys";
  87        toshiba_wmi_input_dev->phys = "wmi/input0";
  88        toshiba_wmi_input_dev->id.bustype = BUS_HOST;
  89
  90        err = sparse_keymap_setup(toshiba_wmi_input_dev,
  91                                  toshiba_wmi_keymap, NULL);
  92        if (err)
  93                goto err_free_dev;
  94
  95        status = wmi_install_notify_handler(WMI_EVENT_GUID,
  96                                            toshiba_wmi_notify, NULL);
  97        if (ACPI_FAILURE(status)) {
  98                err = -EIO;
  99                goto err_free_dev;
 100        }
 101
 102        err = input_register_device(toshiba_wmi_input_dev);
 103        if (err)
 104                goto err_remove_notifier;
 105
 106        return 0;
 107
 108 err_remove_notifier:
 109        wmi_remove_notify_handler(WMI_EVENT_GUID);
 110 err_free_dev:
 111        input_free_device(toshiba_wmi_input_dev);
 112        return err;
 113}
 114
 115static void toshiba_wmi_input_destroy(void)
 116{
 117        wmi_remove_notify_handler(WMI_EVENT_GUID);
 118        input_unregister_device(toshiba_wmi_input_dev);
 119}
 120
 121static int __init toshiba_wmi_init(void)
 122{
 123        int ret;
 124
 125        if (!wmi_has_guid(WMI_EVENT_GUID) ||
 126            !dmi_check_system(toshiba_wmi_dmi_table))
 127                return -ENODEV;
 128
 129        ret = toshiba_wmi_input_setup();
 130        if (ret) {
 131                pr_err("Failed to setup input device\n");
 132                return ret;
 133        }
 134
 135        pr_info("Toshiba WMI Hotkey Driver\n");
 136
 137        return 0;
 138}
 139
 140static void __exit toshiba_wmi_exit(void)
 141{
 142        if (wmi_has_guid(WMI_EVENT_GUID))
 143                toshiba_wmi_input_destroy();
 144}
 145
 146module_init(toshiba_wmi_init);
 147module_exit(toshiba_wmi_exit);
 148