1319349Sjkim// SPDX-License-Identifier: GPL-2.0-or-later 2234949Sbapt/* 3234949Sbapt * HID driver for ELECOM devices: 4319349Sjkim * - BM084 Bluetooth Mouse 5234949Sbapt * - EX-G Trackballs (M-XT3DRBK, M-XT3URBK, M-XT4DRBK) 6234949Sbapt * - DEFT Trackballs (M-DT1DRBK, M-DT1URBK, M-DT2DRBK, M-DT2URBK) 7234949Sbapt * - HUGE Trackballs (M-HT1DRBK, M-HT1URBK) 8234949Sbapt * 9234949Sbapt * Copyright (c) 2010 Richard Nauber <Richard.Nauber@gmail.com> 10234949Sbapt * Copyright (c) 2016 Yuxuan Shui <yshuiv7@gmail.com> 11234949Sbapt * Copyright (c) 2017 Diego Elio Petten�� <flameeyes@flameeyes.eu> 12234949Sbapt * Copyright (c) 2017 Alex Manoussakis <amanou@gnu.org> 13234949Sbapt * Copyright (c) 2017 Tomasz Kramkowski <tk@the-tk.com> 14234949Sbapt * Copyright (c) 2020 YOSHIOKA Takuma <lo48576@hard-wi.red> 15234949Sbapt * Copyright (c) 2022 Takahiro Fujii <fujii@xaxxi.net> 16234949Sbapt */ 17234949Sbapt 18234949Sbapt/* 19234949Sbapt */ 20234949Sbapt 21234949Sbapt#include <linux/device.h> 22234949Sbapt#include <linux/hid.h> 23234949Sbapt#include <linux/module.h> 24234949Sbapt 25234949Sbapt#include "hid-ids.h" 26234949Sbapt 27234949Sbapt/* 28234949Sbapt * Certain ELECOM mice misreport their button count meaning that they only work 29234949Sbapt * correctly with the ELECOM mouse assistant software which is unavailable for 30234949Sbapt * Linux. A four extra INPUT reports and a FEATURE report are described by the 31268811Sbapt * report descriptor but it does not appear that these enable software to 32251143Sbapt * control what the extra buttons map to. The only simple and straightforward 33251143Sbapt * solution seems to involve fixing up the report descriptor. 34251143Sbapt */ 35251143Sbapt#define MOUSE_BUTTONS_MAX 8 36251143Sbaptstatic void mouse_button_fixup(struct hid_device *hdev, 37251143Sbapt __u8 *rdesc, unsigned int rsize, 38251143Sbapt unsigned int button_bit_count, 39251143Sbapt unsigned int padding_bit, 40268811Sbapt unsigned int button_report_size, 41251143Sbapt unsigned int button_usage_maximum, 42251143Sbapt int nbuttons) 43251143Sbapt{ 44251143Sbapt if (rsize < 32 || rdesc[button_bit_count] != 0x95 || 45251143Sbapt rdesc[button_report_size] != 0x75 || 46251143Sbapt rdesc[button_report_size + 1] != 0x01 || 47251143Sbapt rdesc[button_usage_maximum] != 0x29 || rdesc[padding_bit] != 0x75) 48251143Sbapt return; 49251143Sbapt hid_info(hdev, "Fixing up Elecom mouse button count\n"); 50251143Sbapt nbuttons = clamp(nbuttons, 0, MOUSE_BUTTONS_MAX); 51251143Sbapt rdesc[button_bit_count + 1] = nbuttons; 52251143Sbapt rdesc[button_usage_maximum + 1] = nbuttons; 53251143Sbapt rdesc[padding_bit + 1] = MOUSE_BUTTONS_MAX - nbuttons; 54251143Sbapt} 55251143Sbapt 56251143Sbaptstatic __u8 *elecom_report_fixup(struct hid_device *hdev, __u8 *rdesc, 57296240Sjkim unsigned int *rsize) 58234949Sbapt{ 59234949Sbapt switch (hdev->product) { 60234949Sbapt case USB_DEVICE_ID_ELECOM_BM084: 61234949Sbapt /* The BM084 Bluetooth mouse includes a non-existing horizontal 62234949Sbapt * wheel in the HID descriptor. */ 63234949Sbapt if (*rsize >= 48 && rdesc[46] == 0x05 && rdesc[47] == 0x0c) { 64234949Sbapt hid_info(hdev, "Fixing up Elecom BM084 report descriptor\n"); 65234949Sbapt rdesc[47] = 0x00; 66234949Sbapt } 67234949Sbapt break; 68234949Sbapt case USB_DEVICE_ID_ELECOM_M_XGL20DLBK: 69234949Sbapt /* 70234949Sbapt * Report descriptor format: 71234949Sbapt * 20: button bit count 72234949Sbapt * 28: padding bit count 73234949Sbapt * 22: button report size 74234949Sbapt * 14: button usage maximum 75296240Sjkim */ 76296240Sjkim mouse_button_fixup(hdev, rdesc, *rsize, 20, 28, 22, 14, 8); 77296240Sjkim break; 78234949Sbapt case USB_DEVICE_ID_ELECOM_M_XT3URBK: 79296240Sjkim case USB_DEVICE_ID_ELECOM_M_XT3DRBK: 80234949Sbapt case USB_DEVICE_ID_ELECOM_M_XT4DRBK: 81234949Sbapt /* 82272655Sbapt * Report descriptor format: 83234949Sbapt * 12: button bit count 84234949Sbapt * 30: padding bit count 85234949Sbapt * 14: button report size 86234949Sbapt * 20: button usage maximum 87234949Sbapt */ 88234949Sbapt mouse_button_fixup(hdev, rdesc, *rsize, 12, 30, 14, 20, 6); 89234949Sbapt break; 90234949Sbapt case USB_DEVICE_ID_ELECOM_M_DT1URBK: 91234949Sbapt case USB_DEVICE_ID_ELECOM_M_DT1DRBK: 92234949Sbapt case USB_DEVICE_ID_ELECOM_M_HT1URBK: 93234949Sbapt case USB_DEVICE_ID_ELECOM_M_HT1DRBK_010D: 94234949Sbapt /* 95234949Sbapt * Report descriptor format: 96296240Sjkim * 12: button bit count 97234949Sbapt * 30: padding bit count 98296240Sjkim * 14: button report size 99296240Sjkim * 20: button usage maximum 100296240Sjkim */ 101234949Sbapt mouse_button_fixup(hdev, rdesc, *rsize, 12, 30, 14, 20, 8); 102234949Sbapt break; 103234949Sbapt case USB_DEVICE_ID_ELECOM_M_HT1DRBK_011C: 104234949Sbapt /* 105234949Sbapt * Report descriptor format: 106234949Sbapt * 22: button bit count 107234949Sbapt * 30: padding bit count 108234949Sbapt * 24: button report size 109296240Sjkim * 16: button usage maximum 110234949Sbapt */ 111234949Sbapt mouse_button_fixup(hdev, rdesc, *rsize, 22, 30, 24, 16, 8); 112234949Sbapt break; 113234949Sbapt } 114296240Sjkim return rdesc; 115234949Sbapt} 116234949Sbapt 117234949Sbaptstatic const struct hid_device_id elecom_devices[] = { 118234949Sbapt { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_BM084) }, 119272655Sbapt { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_XGL20DLBK) }, 120234949Sbapt { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_XT3URBK) }, 121234949Sbapt { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_XT3DRBK) }, 122234949Sbapt { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_XT4DRBK) }, 123234949Sbapt { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_DT1URBK) }, 124234949Sbapt { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_DT1DRBK) }, 125234949Sbapt { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_HT1URBK) }, 126234949Sbapt { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_HT1DRBK_010D) }, 127234949Sbapt { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_HT1DRBK_011C) }, 128234949Sbapt { } 129234949Sbapt}; 130234949SbaptMODULE_DEVICE_TABLE(hid, elecom_devices); 131234949Sbapt 132234949Sbaptstatic struct hid_driver elecom_driver = { 133234949Sbapt .name = "elecom", 134234949Sbapt .id_table = elecom_devices, 135234949Sbapt .report_fixup = elecom_report_fixup 136234949Sbapt}; 137234949Sbaptmodule_hid_driver(elecom_driver); 138234949Sbapt 139234949SbaptMODULE_LICENSE("GPL"); 140234949Sbapt