hid-elecom.c 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. * HID driver for ELECOM devices:
  4. * - BM084 Bluetooth Mouse
  5. * - EX-G Trackballs (M-XT3DRBK, M-XT3URBK, M-XT4DRBK)
  6. * - DEFT Trackballs (M-DT1DRBK, M-DT1URBK, M-DT2DRBK, M-DT2URBK)
  7. * - HUGE Trackballs (M-HT1DRBK, M-HT1URBK)
  8. *
  9. * Copyright (c) 2010 Richard Nauber <[email protected]>
  10. * Copyright (c) 2016 Yuxuan Shui <[email protected]>
  11. * Copyright (c) 2017 Diego Elio Pettenò <[email protected]>
  12. * Copyright (c) 2017 Alex Manoussakis <[email protected]>
  13. * Copyright (c) 2017 Tomasz Kramkowski <[email protected]>
  14. * Copyright (c) 2020 YOSHIOKA Takuma <[email protected]>
  15. * Copyright (c) 2022 Takahiro Fujii <[email protected]>
  16. */
  17. /*
  18. */
  19. #include <linux/device.h>
  20. #include <linux/hid.h>
  21. #include <linux/module.h>
  22. #include "hid-ids.h"
  23. /*
  24. * Certain ELECOM mice misreport their button count meaning that they only work
  25. * correctly with the ELECOM mouse assistant software which is unavailable for
  26. * Linux. A four extra INPUT reports and a FEATURE report are described by the
  27. * report descriptor but it does not appear that these enable software to
  28. * control what the extra buttons map to. The only simple and straightforward
  29. * solution seems to involve fixing up the report descriptor.
  30. */
  31. #define MOUSE_BUTTONS_MAX 8
  32. static void mouse_button_fixup(struct hid_device *hdev,
  33. __u8 *rdesc, unsigned int rsize,
  34. unsigned int button_bit_count,
  35. unsigned int padding_bit,
  36. unsigned int button_report_size,
  37. unsigned int button_usage_maximum,
  38. int nbuttons)
  39. {
  40. if (rsize < 32 || rdesc[button_bit_count] != 0x95 ||
  41. rdesc[button_report_size] != 0x75 ||
  42. rdesc[button_report_size + 1] != 0x01 ||
  43. rdesc[button_usage_maximum] != 0x29 || rdesc[padding_bit] != 0x75)
  44. return;
  45. hid_info(hdev, "Fixing up Elecom mouse button count\n");
  46. nbuttons = clamp(nbuttons, 0, MOUSE_BUTTONS_MAX);
  47. rdesc[button_bit_count + 1] = nbuttons;
  48. rdesc[button_usage_maximum + 1] = nbuttons;
  49. rdesc[padding_bit + 1] = MOUSE_BUTTONS_MAX - nbuttons;
  50. }
  51. static __u8 *elecom_report_fixup(struct hid_device *hdev, __u8 *rdesc,
  52. unsigned int *rsize)
  53. {
  54. switch (hdev->product) {
  55. case USB_DEVICE_ID_ELECOM_BM084:
  56. /* The BM084 Bluetooth mouse includes a non-existing horizontal
  57. * wheel in the HID descriptor. */
  58. if (*rsize >= 48 && rdesc[46] == 0x05 && rdesc[47] == 0x0c) {
  59. hid_info(hdev, "Fixing up Elecom BM084 report descriptor\n");
  60. rdesc[47] = 0x00;
  61. }
  62. break;
  63. case USB_DEVICE_ID_ELECOM_M_XGL20DLBK:
  64. /*
  65. * Report descriptor format:
  66. * 20: button bit count
  67. * 28: padding bit count
  68. * 22: button report size
  69. * 14: button usage maximum
  70. */
  71. mouse_button_fixup(hdev, rdesc, *rsize, 20, 28, 22, 14, 8);
  72. break;
  73. case USB_DEVICE_ID_ELECOM_M_XT3URBK:
  74. case USB_DEVICE_ID_ELECOM_M_XT3DRBK:
  75. case USB_DEVICE_ID_ELECOM_M_XT4DRBK:
  76. /*
  77. * Report descriptor format:
  78. * 12: button bit count
  79. * 30: padding bit count
  80. * 14: button report size
  81. * 20: button usage maximum
  82. */
  83. mouse_button_fixup(hdev, rdesc, *rsize, 12, 30, 14, 20, 6);
  84. break;
  85. case USB_DEVICE_ID_ELECOM_M_DT1URBK:
  86. case USB_DEVICE_ID_ELECOM_M_DT1DRBK:
  87. case USB_DEVICE_ID_ELECOM_M_HT1URBK:
  88. case USB_DEVICE_ID_ELECOM_M_HT1DRBK_010D:
  89. /*
  90. * Report descriptor format:
  91. * 12: button bit count
  92. * 30: padding bit count
  93. * 14: button report size
  94. * 20: button usage maximum
  95. */
  96. mouse_button_fixup(hdev, rdesc, *rsize, 12, 30, 14, 20, 8);
  97. break;
  98. case USB_DEVICE_ID_ELECOM_M_HT1DRBK_011C:
  99. /*
  100. * Report descriptor format:
  101. * 22: button bit count
  102. * 30: padding bit count
  103. * 24: button report size
  104. * 16: button usage maximum
  105. */
  106. mouse_button_fixup(hdev, rdesc, *rsize, 22, 30, 24, 16, 8);
  107. break;
  108. }
  109. return rdesc;
  110. }
  111. static const struct hid_device_id elecom_devices[] = {
  112. { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_BM084) },
  113. { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_XGL20DLBK) },
  114. { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_XT3URBK) },
  115. { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_XT3DRBK) },
  116. { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_XT4DRBK) },
  117. { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_DT1URBK) },
  118. { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_DT1DRBK) },
  119. { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_HT1URBK) },
  120. { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_HT1DRBK_010D) },
  121. { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_HT1DRBK_011C) },
  122. { }
  123. };
  124. MODULE_DEVICE_TABLE(hid, elecom_devices);
  125. static struct hid_driver elecom_driver = {
  126. .name = "elecom",
  127. .id_table = elecom_devices,
  128. .report_fixup = elecom_report_fixup
  129. };
  130. module_hid_driver(elecom_driver);
  131. MODULE_LICENSE("GPL");