eeepc-wmi.c 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. /*
  2. * Eee PC WMI hotkey driver
  3. *
  4. * Copyright(C) 2010 Intel Corporation.
  5. *
  6. * Portions based on wistron_btns.c:
  7. * Copyright (C) 2005 Miloslav Trmac <mitr@volny.cz>
  8. * Copyright (C) 2005 Bernhard Rosenkraenzer <bero@arklinux.org>
  9. * Copyright (C) 2005 Dmitry Torokhov <dtor@mail.ru>
  10. *
  11. * This program is free software; you can redistribute it and/or modify
  12. * it under the terms of the GNU General Public License as published by
  13. * the Free Software Foundation; either version 2 of the License, or
  14. * (at your option) any later version.
  15. *
  16. * This program is distributed in the hope that it will be useful,
  17. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  19. * GNU General Public License for more details.
  20. *
  21. * You should have received a copy of the GNU General Public License
  22. * along with this program; if not, write to the Free Software
  23. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  24. */
  25. #include <linux/kernel.h>
  26. #include <linux/module.h>
  27. #include <linux/init.h>
  28. #include <linux/types.h>
  29. #include <linux/slab.h>
  30. #include <linux/input.h>
  31. #include <linux/input/sparse-keymap.h>
  32. #include <acpi/acpi_bus.h>
  33. #include <acpi/acpi_drivers.h>
  34. MODULE_AUTHOR("Yong Wang <yong.y.wang@intel.com>");
  35. MODULE_DESCRIPTION("Eee PC WMI Hotkey Driver");
  36. MODULE_LICENSE("GPL");
  37. #define EEEPC_WMI_EVENT_GUID "ABBC0F72-8EA1-11D1-00A0-C90629100000"
  38. MODULE_ALIAS("wmi:"EEEPC_WMI_EVENT_GUID);
  39. #define NOTIFY_BRNUP_MIN 0x11
  40. #define NOTIFY_BRNUP_MAX 0x1f
  41. #define NOTIFY_BRNDOWN_MIN 0x20
  42. #define NOTIFY_BRNDOWN_MAX 0x2e
  43. static const struct key_entry eeepc_wmi_keymap[] = {
  44. /* Sleep already handled via generic ACPI code */
  45. { KE_KEY, 0x5d, { KEY_WLAN } },
  46. { KE_KEY, 0x32, { KEY_MUTE } },
  47. { KE_KEY, 0x31, { KEY_VOLUMEDOWN } },
  48. { KE_KEY, 0x30, { KEY_VOLUMEUP } },
  49. { KE_IGNORE, NOTIFY_BRNDOWN_MIN, { KEY_BRIGHTNESSDOWN } },
  50. { KE_IGNORE, NOTIFY_BRNUP_MIN, { KEY_BRIGHTNESSUP } },
  51. { KE_KEY, 0xcc, { KEY_SWITCHVIDEOMODE } },
  52. { KE_END, 0},
  53. };
  54. static struct input_dev *eeepc_wmi_input_dev;
  55. static void eeepc_wmi_notify(u32 value, void *context)
  56. {
  57. struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL };
  58. union acpi_object *obj;
  59. acpi_status status;
  60. int code;
  61. status = wmi_get_event_data(value, &response);
  62. if (status != AE_OK) {
  63. pr_err("EEEPC WMI: bad event status 0x%x\n", status);
  64. return;
  65. }
  66. obj = (union acpi_object *)response.pointer;
  67. if (obj && obj->type == ACPI_TYPE_INTEGER) {
  68. code = obj->integer.value;
  69. if (code >= NOTIFY_BRNUP_MIN && code <= NOTIFY_BRNUP_MAX)
  70. code = NOTIFY_BRNUP_MIN;
  71. else if (code >= NOTIFY_BRNDOWN_MIN && code <= NOTIFY_BRNDOWN_MAX)
  72. code = NOTIFY_BRNDOWN_MIN;
  73. if (!sparse_keymap_report_event(eeepc_wmi_input_dev,
  74. code, 1, true))
  75. pr_info("EEEPC WMI: Unknown key %x pressed\n", code);
  76. }
  77. kfree(obj);
  78. }
  79. static int eeepc_wmi_input_setup(void)
  80. {
  81. int err;
  82. eeepc_wmi_input_dev = input_allocate_device();
  83. if (!eeepc_wmi_input_dev)
  84. return -ENOMEM;
  85. eeepc_wmi_input_dev->name = "Eee PC WMI hotkeys";
  86. eeepc_wmi_input_dev->phys = "wmi/input0";
  87. eeepc_wmi_input_dev->id.bustype = BUS_HOST;
  88. err = sparse_keymap_setup(eeepc_wmi_input_dev, eeepc_wmi_keymap, NULL);
  89. if (err)
  90. goto err_free_dev;
  91. err = input_register_device(eeepc_wmi_input_dev);
  92. if (err)
  93. goto err_free_keymap;
  94. return 0;
  95. err_free_keymap:
  96. sparse_keymap_free(eeepc_wmi_input_dev);
  97. err_free_dev:
  98. input_free_device(eeepc_wmi_input_dev);
  99. return err;
  100. }
  101. static int __init eeepc_wmi_init(void)
  102. {
  103. int err;
  104. acpi_status status;
  105. if (!wmi_has_guid(EEEPC_WMI_EVENT_GUID)) {
  106. pr_warning("EEEPC WMI: No known WMI GUID found\n");
  107. return -ENODEV;
  108. }
  109. err = eeepc_wmi_input_setup();
  110. if (err)
  111. return err;
  112. status = wmi_install_notify_handler(EEEPC_WMI_EVENT_GUID,
  113. eeepc_wmi_notify, NULL);
  114. if (ACPI_FAILURE(status)) {
  115. sparse_keymap_free(eeepc_wmi_input_dev);
  116. input_unregister_device(eeepc_wmi_input_dev);
  117. pr_err("EEEPC WMI: Unable to register notify handler - %d\n",
  118. status);
  119. return -ENODEV;
  120. }
  121. return 0;
  122. }
  123. static void __exit eeepc_wmi_exit(void)
  124. {
  125. wmi_remove_notify_handler(EEEPC_WMI_EVENT_GUID);
  126. sparse_keymap_free(eeepc_wmi_input_dev);
  127. input_unregister_device(eeepc_wmi_input_dev);
  128. }
  129. module_init(eeepc_wmi_init);
  130. module_exit(eeepc_wmi_exit);