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 * - HUGE Plus Trackball (M-HT1MRBK) 9 * 10 * Copyright (c) 2010 Richard Nauber <Richard.Nauber@gmail.com> 11 * Copyright (c) 2016 Yuxuan Shui <yshuiv7@gmail.com> 12 * Copyright (c) 2017 Diego Elio Pettenò <flameeyes@flameeyes.eu> 13 * Copyright (c) 2017 Alex Manoussakis <amanou@gnu.org> 14 * Copyright (c) 2017 Tomasz Kramkowski <tk@the-tk.com> 15 * Copyright (c) 2020 YOSHIOKA Takuma <lo48576@hard-wi.red> 16 * Copyright (c) 2022 Takahiro Fujii <fujii@xaxxi.net> 17 */ 18 19 /* 20 */ 21 22 #include <linux/device.h> 23 #include <linux/hid.h> 24 #include <linux/module.h> 25 26 #include "hid-ids.h" 27 28 /* 29 * Certain ELECOM mice misreport their button count meaning that they only work 30 * correctly with the ELECOM mouse assistant software which is unavailable for 31 * Linux. A four extra INPUT reports and a FEATURE report are described by the 32 * report descriptor but it does not appear that these enable software to 33 * control what the extra buttons map to. The only simple and straightforward 34 * solution seems to involve fixing up the report descriptor. 35 */ 36 #define MOUSE_BUTTONS_MAX 8 37 static void mouse_button_fixup(struct hid_device *hdev, 38 __u8 *rdesc, unsigned int rsize, 39 unsigned int button_bit_count, 40 unsigned int padding_bit, 41 unsigned int button_report_size, 42 unsigned int button_usage_maximum, 43 int nbuttons) 44 { 45 if (rsize < 32 || rdesc[button_bit_count] != 0x95 || 46 rdesc[button_report_size] != 0x75 || 47 rdesc[button_report_size + 1] != 0x01 || 48 rdesc[button_usage_maximum] != 0x29 || rdesc[padding_bit] != 0x75) 49 return; 50 hid_info(hdev, "Fixing up Elecom mouse button count\n"); 51 nbuttons = clamp(nbuttons, 0, MOUSE_BUTTONS_MAX); 52 rdesc[button_bit_count + 1] = nbuttons; 53 rdesc[button_usage_maximum + 1] = nbuttons; 54 rdesc[padding_bit + 1] = MOUSE_BUTTONS_MAX - nbuttons; 55 } 56 57 static const __u8 *elecom_report_fixup(struct hid_device *hdev, __u8 *rdesc, 58 unsigned int *rsize) 59 { 60 switch (hdev->product) { 61 case USB_DEVICE_ID_ELECOM_BM084: 62 /* The BM084 Bluetooth mouse includes a non-existing horizontal 63 * wheel in the HID descriptor. */ 64 if (*rsize >= 48 && rdesc[46] == 0x05 && rdesc[47] == 0x0c) { 65 hid_info(hdev, "Fixing up Elecom BM084 report descriptor\n"); 66 rdesc[47] = 0x00; 67 } 68 break; 69 case USB_DEVICE_ID_ELECOM_M_XGL20DLBK: 70 /* 71 * Report descriptor format: 72 * 20: button bit count 73 * 28: padding bit count 74 * 22: button report size 75 * 14: button usage maximum 76 */ 77 mouse_button_fixup(hdev, rdesc, *rsize, 20, 28, 22, 14, 8); 78 break; 79 case USB_DEVICE_ID_ELECOM_M_XT3URBK_00FB: 80 case USB_DEVICE_ID_ELECOM_M_XT3URBK_018F: 81 case USB_DEVICE_ID_ELECOM_M_XT3DRBK_00FC: 82 case USB_DEVICE_ID_ELECOM_M_XT4DRBK: 83 /* 84 * Report descriptor format: 85 * 12: button bit count 86 * 30: padding bit count 87 * 14: button report size 88 * 20: button usage maximum 89 */ 90 mouse_button_fixup(hdev, rdesc, *rsize, 12, 30, 14, 20, 6); 91 break; 92 case USB_DEVICE_ID_ELECOM_M_DT1URBK: 93 case USB_DEVICE_ID_ELECOM_M_DT1DRBK: 94 case USB_DEVICE_ID_ELECOM_M_HT1URBK_010C: 95 case USB_DEVICE_ID_ELECOM_M_HT1URBK_019B: 96 case USB_DEVICE_ID_ELECOM_M_HT1DRBK_010D: 97 /* 98 * Report descriptor format: 99 * 12: button bit count 100 * 30: padding bit count 101 * 14: button report size 102 * 20: button usage maximum 103 */ 104 mouse_button_fixup(hdev, rdesc, *rsize, 12, 30, 14, 20, 8); 105 break; 106 case USB_DEVICE_ID_ELECOM_M_XT3DRBK_018C: 107 /* 108 * Report descriptor format: 109 * 22: button bit count 110 * 30: padding bit count 111 * 24: button report size 112 * 16: button usage maximum 113 */ 114 mouse_button_fixup(hdev, rdesc, *rsize, 22, 30, 24, 16, 6); 115 break; 116 case USB_DEVICE_ID_ELECOM_M_DT2DRBK: 117 case USB_DEVICE_ID_ELECOM_M_HT1DRBK_011C: 118 /* 119 * Report descriptor format: 120 * 22: button bit count 121 * 30: padding bit count 122 * 24: button report size 123 * 16: button usage maximum 124 */ 125 mouse_button_fixup(hdev, rdesc, *rsize, 22, 30, 24, 16, 8); 126 break; 127 case USB_DEVICE_ID_ELECOM_M_HT1MRBK: 128 case USB_DEVICE_ID_ELECOM_M_HT1MRBK_01AB: 129 case USB_DEVICE_ID_ELECOM_M_HT1MRBK_01AC: 130 /* 131 * Report descriptor format: 132 * 24: button bit count 133 * 28: padding bit count 134 * 22: button report size 135 * 16: button usage maximum 136 */ 137 mouse_button_fixup(hdev, rdesc, *rsize, 24, 28, 22, 16, 8); 138 break; 139 } 140 return rdesc; 141 } 142 143 static const struct hid_device_id elecom_devices[] = { 144 { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_BM084) }, 145 { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_HT1MRBK_01AC) }, 146 { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_XGL20DLBK) }, 147 { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_XT3URBK_00FB) }, 148 { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_XT3URBK_018F) }, 149 { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_XT3DRBK_00FC) }, 150 { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_XT3DRBK_018C) }, 151 { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_XT4DRBK) }, 152 { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_DT1URBK) }, 153 { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_DT1DRBK) }, 154 { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_DT2DRBK) }, 155 { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_HT1URBK_010C) }, 156 { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_HT1URBK_019B) }, 157 { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_HT1DRBK_010D) }, 158 { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_HT1DRBK_011C) }, 159 { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_HT1MRBK) }, 160 { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_HT1MRBK_01AB) }, 161 { } 162 }; 163 MODULE_DEVICE_TABLE(hid, elecom_devices); 164 165 static struct hid_driver elecom_driver = { 166 .name = "elecom", 167 .id_table = elecom_devices, 168 .report_fixup = elecom_report_fixup 169 }; 170 module_hid_driver(elecom_driver); 171 172 MODULE_DESCRIPTION("HID driver for ELECOM devices"); 173 MODULE_LICENSE("GPL"); 174