dell-wmi-aio.c 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. * WMI hotkeys support for Dell All-In-One series
  4. */
  5. #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  6. #include <linux/kernel.h>
  7. #include <linux/module.h>
  8. #include <linux/init.h>
  9. #include <linux/types.h>
  10. #include <linux/input.h>
  11. #include <linux/input/sparse-keymap.h>
  12. #include <linux/acpi.h>
  13. #include <linux/string.h>
  14. MODULE_DESCRIPTION("WMI hotkeys driver for Dell All-In-One series");
  15. MODULE_LICENSE("GPL");
  16. #define EVENT_GUID1 "284A0E6B-380E-472A-921F-E52786257FB4"
  17. #define EVENT_GUID2 "02314822-307C-4F66-BF0E-48AEAEB26CC8"
  18. struct dell_wmi_event {
  19. u16 length;
  20. /* 0x000: A hot key pressed or an event occurred
  21. * 0x00F: A sequence of hot keys are pressed */
  22. u16 type;
  23. u16 event[];
  24. };
  25. static const char *dell_wmi_aio_guids[] = {
  26. EVENT_GUID1,
  27. EVENT_GUID2,
  28. NULL
  29. };
  30. MODULE_ALIAS("wmi:"EVENT_GUID1);
  31. MODULE_ALIAS("wmi:"EVENT_GUID2);
  32. static const struct key_entry dell_wmi_aio_keymap[] = {
  33. { KE_KEY, 0xc0, { KEY_VOLUMEUP } },
  34. { KE_KEY, 0xc1, { KEY_VOLUMEDOWN } },
  35. { KE_KEY, 0xe030, { KEY_VOLUMEUP } },
  36. { KE_KEY, 0xe02e, { KEY_VOLUMEDOWN } },
  37. { KE_KEY, 0xe020, { KEY_MUTE } },
  38. { KE_KEY, 0xe027, { KEY_DISPLAYTOGGLE } },
  39. { KE_KEY, 0xe006, { KEY_BRIGHTNESSUP } },
  40. { KE_KEY, 0xe005, { KEY_BRIGHTNESSDOWN } },
  41. { KE_KEY, 0xe00b, { KEY_SWITCHVIDEOMODE } },
  42. { KE_END, 0 }
  43. };
  44. static struct input_dev *dell_wmi_aio_input_dev;
  45. /*
  46. * The new WMI event data format will follow the dell_wmi_event structure
  47. * So, we will check if the buffer matches the format
  48. */
  49. static bool dell_wmi_aio_event_check(u8 *buffer, int length)
  50. {
  51. struct dell_wmi_event *event = (struct dell_wmi_event *)buffer;
  52. if (event == NULL || length < 6)
  53. return false;
  54. if ((event->type == 0 || event->type == 0xf) &&
  55. event->length >= 2)
  56. return true;
  57. return false;
  58. }
  59. static void dell_wmi_aio_notify(u32 value, void *context)
  60. {
  61. struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL };
  62. union acpi_object *obj;
  63. struct dell_wmi_event *event;
  64. acpi_status status;
  65. status = wmi_get_event_data(value, &response);
  66. if (status != AE_OK) {
  67. pr_info("bad event status 0x%x\n", status);
  68. return;
  69. }
  70. obj = (union acpi_object *)response.pointer;
  71. if (obj) {
  72. unsigned int scancode = 0;
  73. switch (obj->type) {
  74. case ACPI_TYPE_INTEGER:
  75. /* Most All-In-One correctly return integer scancode */
  76. scancode = obj->integer.value;
  77. sparse_keymap_report_event(dell_wmi_aio_input_dev,
  78. scancode, 1, true);
  79. break;
  80. case ACPI_TYPE_BUFFER:
  81. if (dell_wmi_aio_event_check(obj->buffer.pointer,
  82. obj->buffer.length)) {
  83. event = (struct dell_wmi_event *)
  84. obj->buffer.pointer;
  85. scancode = event->event[0];
  86. } else {
  87. /* Broken machines return the scancode in a
  88. buffer */
  89. if (obj->buffer.pointer &&
  90. obj->buffer.length > 0)
  91. scancode = obj->buffer.pointer[0];
  92. }
  93. if (scancode)
  94. sparse_keymap_report_event(
  95. dell_wmi_aio_input_dev,
  96. scancode, 1, true);
  97. break;
  98. }
  99. }
  100. kfree(obj);
  101. }
  102. static int __init dell_wmi_aio_input_setup(void)
  103. {
  104. int err;
  105. dell_wmi_aio_input_dev = input_allocate_device();
  106. if (!dell_wmi_aio_input_dev)
  107. return -ENOMEM;
  108. dell_wmi_aio_input_dev->name = "Dell AIO WMI hotkeys";
  109. dell_wmi_aio_input_dev->phys = "wmi/input0";
  110. dell_wmi_aio_input_dev->id.bustype = BUS_HOST;
  111. err = sparse_keymap_setup(dell_wmi_aio_input_dev,
  112. dell_wmi_aio_keymap, NULL);
  113. if (err) {
  114. pr_err("Unable to setup input device keymap\n");
  115. goto err_free_dev;
  116. }
  117. err = input_register_device(dell_wmi_aio_input_dev);
  118. if (err) {
  119. pr_info("Unable to register input device\n");
  120. goto err_free_dev;
  121. }
  122. return 0;
  123. err_free_dev:
  124. input_free_device(dell_wmi_aio_input_dev);
  125. return err;
  126. }
  127. static const char *dell_wmi_aio_find(void)
  128. {
  129. int i;
  130. for (i = 0; dell_wmi_aio_guids[i] != NULL; i++)
  131. if (wmi_has_guid(dell_wmi_aio_guids[i]))
  132. return dell_wmi_aio_guids[i];
  133. return NULL;
  134. }
  135. static int __init dell_wmi_aio_init(void)
  136. {
  137. int err;
  138. const char *guid;
  139. guid = dell_wmi_aio_find();
  140. if (!guid) {
  141. pr_warn("No known WMI GUID found\n");
  142. return -ENXIO;
  143. }
  144. err = dell_wmi_aio_input_setup();
  145. if (err)
  146. return err;
  147. err = wmi_install_notify_handler(guid, dell_wmi_aio_notify, NULL);
  148. if (err) {
  149. pr_err("Unable to register notify handler - %d\n", err);
  150. input_unregister_device(dell_wmi_aio_input_dev);
  151. return err;
  152. }
  153. return 0;
  154. }
  155. static void __exit dell_wmi_aio_exit(void)
  156. {
  157. const char *guid;
  158. guid = dell_wmi_aio_find();
  159. wmi_remove_notify_handler(guid);
  160. input_unregister_device(dell_wmi_aio_input_dev);
  161. }
  162. module_init(dell_wmi_aio_init);
  163. module_exit(dell_wmi_aio_exit);