From 48cd211d716be9d886a362bf2bf45ad89a99d586 Mon Sep 17 00:00:00 2001
From: PulkoMandy <pulkomandy@pulkomandy.tk>
Date: Sun, 31 Mar 2024 17:59:57 +0200
Subject: [PATCH] usb_hid: add quirk to enable 6th button on Elecom M-XT4DR
 trackball

Linux implementation: https://www.spinics.net/lists/kernel/msg2665216.html

In our case it is not possible to read the original descriptor from
quirk handlers, so, I had to hardcode it all. The descriptor is the same
as the original one with just 3 bytes changed (detailed in comments).

Other Elecom hardware requires similar quirks, but can have different
number of buttons, so I did not add it for now.

Change-Id: Ie24c8535f3b4535eb414a4e35a62696ea1f9056d
Reviewed-on: https://review.haiku-os.org/c/haiku/+/7580
Reviewed-by: waddlesplash <waddlesplash@gmail.com>
Tested-by: Commit checker robot <no-reply+buildbot@haiku-os.org>
---
 .../drivers/input/usb_hid/QuirkyDevices.cpp   | 123 ++++++++++++++++++
 1 file changed, 123 insertions(+)

diff --git a/src/add-ons/kernel/drivers/input/usb_hid/QuirkyDevices.cpp b/src/add-ons/kernel/drivers/input/usb_hid/QuirkyDevices.cpp
index 20d2b7e924..114bc316c9 100644
--- a/src/add-ons/kernel/drivers/input/usb_hid/QuirkyDevices.cpp
+++ b/src/add-ons/kernel/drivers/input/usb_hid/QuirkyDevices.cpp
@@ -89,6 +89,122 @@ sixaxis_build_descriptor(HIDWriter &writer)
 }
 
 
+static status_t
+elecom_build_descriptor(HIDWriter &writer)
+{
+	uint8 patchedDescriptor[] = {
+		0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
+		0x09, 0x02, // Usage (Mouse)
+		0xA1, 0x01, // Collection (Application)
+		0x09, 0x01, // Usage (Pointer)
+		0xA1, 0x00, // Collection (Physical)
+		0x85, 0x01, // Report ID (1)
+		0x95, 0x06, // Report Count (6) (is 5 in the original descriptor)
+		0x75, 0x01, // Report Size (1)
+		0x05, 0x09, // Usage Page (Button)
+		0x19, 0x01, // Usage Minimum (0x01)
+		0x29, 0x06, // Usage Maximum (0x06) (is 5 in the original descriptor)
+		0x15, 0x00, // Logical Minimum (0)
+		0x25, 0x01, // Logical Maximum (1)
+		0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
+		0x95, 0x01, // Report Count (1)
+		0x75, 0x02, // Report Size (2) (is 3 in the original descriptor)
+		0x81, 0x01, // Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
+		0x75, 0x10, // Report Size (16)
+		0x95, 0x02, // Report Count (2)
+		0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
+		0x09, 0x30, // Usage (X)
+		0x09, 0x31, // Usage (Y)
+		0x16, 0x00, 0x80,  // Logical Minimum (-32768)
+		0x26, 0xFF, 0x7F,  // Logical Maximum (32767)
+		0x81, 0x06,  // Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position)
+		0xC0,        // End Collection
+		0xA1, 0x00,  // Collection (Physical)
+		0x95, 0x01,  // Report Count (1)
+		0x75, 0x08,  // Report Size (8)
+		0x05, 0x01,  // Usage Page (Generic Desktop Ctrls)
+		0x09, 0x38,  // Usage (Wheel)
+		0x15, 0x81,  // Logical Minimum (-127)
+		0x25, 0x7F,  // Logical Maximum (127)
+		0x81, 0x06,  // Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position)
+		0xC0,        // End Collection
+		0xA1, 0x00,  // Collection (Physical)
+		0x95, 0x01,  // Report Count (1)
+		0x75, 0x08,  // Report Size (8)
+		0x05, 0x0C,  // Usage Page (Consumer)
+		0x0A, 0x38, 0x02,  // Usage (AC Pan)
+		0x15, 0x81,  // Logical Minimum (-127)
+		0x25, 0x7F,  // Logical Maximum (127)
+		0x81, 0x06,  // Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position)
+		0xC0,        // End Collection
+		0xC0,        // End Collection
+		0x06, 0x01, 0xFF,  // Usage Page (Vendor Defined 0xFF01)
+		0x09, 0x00,  // Usage (0x00)
+		0xA1, 0x01,  // Collection (Application)
+		0x85, 0x02,  // Report ID (2)
+		0x09, 0x00,  // Usage (0x00)
+		0x15, 0x00,  // Logical Minimum (0)
+		0x26, 0xFF, 0x00,  // Logical Maximum (255)
+		0x75, 0x08,  // Report Size (8)
+		0x95, 0x07,  // Report Count (7)
+		0x81, 0x02,  // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
+		0xC0,        // End Collection
+		0x05, 0x0C,  // Usage Page (Consumer)
+		0x09, 0x01,  // Usage (Consumer Control)
+		0xA1, 0x01,  // Collection (Application)
+		0x85, 0x05,  // Report ID (5)
+		0x19, 0x00,  // Usage Minimum (Unassigned)
+		0x2A, 0x3C, 0x02,  // Usage Maximum (AC Format)
+		0x15, 0x00,  // Logical Minimum (0)
+		0x26, 0x3C, 0x02,  // Logical Maximum (572)
+		0x95, 0x01,  // Report Count (1)
+		0x75, 0x10,  // Report Size (16)
+		0x81, 0x00,  // Input (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
+		0xC0,        // End Collection
+		0x05, 0x01,  // Usage Page (Generic Desktop Ctrls)
+		0x09, 0x80,  // Usage (Sys Control)
+		0xA1, 0x01,  // Collection (Application)
+		0x85, 0x03,  // Report ID (3)
+		0x19, 0x81,  // Usage Minimum (Sys Power Down)
+		0x29, 0x83,  // Usage Maximum (Sys Wake Up)
+		0x15, 0x00,  // Logical Minimum (0)
+		0x25, 0x01,  // Logical Maximum (1)
+		0x75, 0x01,  // Report Size (1)
+		0x95, 0x03,  // Report Count (3)
+		0x81, 0x02,  // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
+		0x95, 0x05,  // Report Count (5)
+		0x81, 0x01,  // Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
+		0xC0,        // End Collection
+		0x06, 0xBC, 0xFF,  // Usage Page (Vendor Defined 0xFFBC)
+		0x09, 0x88,  // Usage (0x88)
+		0xA1, 0x01,  // Collection (Application)
+		0x85, 0x04,  // Report ID (4)
+		0x95, 0x01,  // Report Count (1)
+		0x75, 0x08,  // Report Size (8)
+		0x15, 0x00,  // Logical Minimum (0)
+		0x26, 0xFF, 0x00,  // Logical Maximum (255)
+		0x19, 0x00,  // Usage Minimum (0x00)
+		0x2A, 0xFF, 0x00,  // Usage Maximum (0xFF)
+		0x81, 0x00,  // Input (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
+		0xC0,        // End Collection
+		0x06, 0x02, 0xFF,  // Usage Page (Vendor Defined 0xFF02)
+		0x09, 0x02,  // Usage (0x02)
+		0xA1, 0x01,  // Collection (Application)
+		0x85, 0x06,  // Report ID (6)
+		0x09, 0x02,  // Usage (0x02)
+		0x15, 0x00,  // Logical Minimum (0)
+		0x26, 0xFF, 0x00,  // Logical Maximum (255)
+		0x75, 0x08,  // Report Size (8)
+		0x95, 0x07,  // Report Count (7)
+		0xB1, 0x02,
+			// Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position, Non-volatile)
+		0xC0,        // End Collection
+	};
+
+	return writer.Write(&patchedDescriptor, sizeof(patchedDescriptor));
+}
+
+
 static status_t
 xbox360_build_descriptor(HIDWriter &writer)
 {
@@ -140,6 +256,13 @@ usb_hid_quirky_device gQuirkyDevices[] = {
 		sixaxis_init, sixaxis_build_descriptor
 	},
 
+	{
+		// Elecom trackball which has 6 buttons, and includes them in the report, but not in the
+		// report descriptor. Construct a report descriptor including all 6 buttons.
+		0x056e, 0x00fd, USB_INTERFACE_CLASS_HID, 0, 0,
+		NULL, elecom_build_descriptor
+	},
+
 	{
 		// XBOX 360 controllers aren't really HID (marked vendor specific).
 		// They therefore don't provide a HID/report descriptor either. The