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