Build on top of the simple mouse HID report descriptor with an enhanced version
that supports report IDs and feature reports for high resolution mouse
wheel control. As per the documentation structure.
Check: https://download.microsoft.com/download/b/d/1/bd1f7ef4-7d72-419e-bc5c-9f79ad7bb66e/wheel.docx
Changes:
- Increase HID descriptor length from 52 to 144 bytes
- Add report IDs (0x01 input, 0x02 feature)
- Implement feature reports for wheel/pan resolution multipliers
- Add AC Pan (horizontal scroll) usage
- Increase endpoint packet size from 4 to 6 bytes for pan byte
This enables guests to configure resolution multipliers (+-1, +-4, +-8, +-16)
to control scroll acceleration and precision.
Signed-off-by: Soumyajyotii Ssarkar <soumyajyotisarkar23@gmail.com>
---
hw/usb/dev-hid.c | 126 +++++++++++++++++++++++++++++++++++------------
1 file changed, 95 insertions(+), 31 deletions(-)
diff --git a/hw/usb/dev-hid.c b/hw/usb/dev-hid.c
index ae19d60203..49e23c2319 100644
--- a/hw/usb/dev-hid.c
+++ b/hw/usb/dev-hid.c
@@ -93,7 +93,7 @@ static const USBDescIface desc_iface_mouse = {
0x00, /* u8 country_code */
0x01, /* u8 num_descriptors */
USB_DT_REPORT, /* u8 type: Report */
- 52, 0, /* u16 len */
+ 144, 0, /* u16 len */
},
},
},
@@ -101,7 +101,7 @@ static const USBDescIface desc_iface_mouse = {
{
.bEndpointAddress = USB_DIR_IN | 0x01,
.bmAttributes = USB_ENDPOINT_XFER_INT,
- .wMaxPacketSize = 4,
+ .wMaxPacketSize = 6,
.bInterval = 0x0a,
},
},
@@ -124,7 +124,7 @@ static const USBDescIface desc_iface_mouse2 = {
0x00, /* u8 country_code */
0x01, /* u8 num_descriptors */
USB_DT_REPORT, /* u8 type: Report */
- 52, 0, /* u16 len */
+ 144, 0, /* u16 len */
},
},
},
@@ -132,7 +132,7 @@ static const USBDescIface desc_iface_mouse2 = {
{
.bEndpointAddress = USB_DIR_IN | 0x01,
.bmAttributes = USB_ENDPOINT_XFER_INT,
- .wMaxPacketSize = 4,
+ .wMaxPacketSize = 6,
.bInterval = 7, /* 2 ^ (8-1) * 125 usecs = 8 ms */
},
},
@@ -454,33 +454,97 @@ static const USBDesc desc_keyboard2 = {
};
static const uint8_t qemu_mouse_hid_report_descriptor[] = {
- 0x05, 0x01, /* Usage Page (Generic Desktop) */
- 0x09, 0x02, /* Usage (Mouse) */
- 0xa1, 0x01, /* Collection (Application) */
- 0x09, 0x01, /* Usage (Pointer) */
- 0xa1, 0x00, /* Collection (Physical) */
- 0x05, 0x09, /* Usage Page (Button) */
- 0x19, 0x01, /* Usage Minimum (1) */
- 0x29, 0x05, /* Usage Maximum (5) */
- 0x15, 0x00, /* Logical Minimum (0) */
- 0x25, 0x01, /* Logical Maximum (1) */
- 0x95, 0x05, /* Report Count (5) */
- 0x75, 0x01, /* Report Size (1) */
- 0x81, 0x02, /* Input (Data, Variable, Absolute) */
- 0x95, 0x01, /* Report Count (1) */
- 0x75, 0x03, /* Report Size (3) */
- 0x81, 0x01, /* Input (Constant) */
- 0x05, 0x01, /* Usage Page (Generic Desktop) */
- 0x09, 0x30, /* Usage (X) */
- 0x09, 0x31, /* Usage (Y) */
- 0x09, 0x38, /* Usage (Wheel) */
- 0x15, 0x81, /* Logical Minimum (-0x7f) */
- 0x25, 0x7f, /* Logical Maximum (0x7f) */
- 0x75, 0x08, /* Report Size (8) */
- 0x95, 0x03, /* Report Count (3) */
- 0x81, 0x06, /* Input (Data, Variable, Relative) */
- 0xc0, /* End Collection */
- 0xc0, /* End Collection */
+ 0x05, 0x01, /* Usage Page (Generic Desktop) */
+ 0x09, 0x02, /* Usage (Mouse) */
+ 0xA1, 0x01, /* Collection (Application) */
+
+ 0x09, 0x02, /* Usage (Mouse) */
+ 0xA1, 0x02, /* Collection (Logical) */
+
+ 0x85, 0x01, /* Report ID (0x01) */
+ 0x09, 0x01, /* Usage (Pointer) */
+ 0xA1, 0x00, /* Collection (Physical) */
+
+ 0x05, 0x09, /* Usage Page (Button) */
+ 0x19, 0x01, /* Usage Minimum (1) */
+ 0x29, 0x05, /* Usage Maximum (5) */
+ 0x15, 0x00, /* Logical Minimum (0) */
+ 0x25, 0x01, /* Logical Maximum (1) */
+ 0x95, 0x05, /* Report Count (5) */
+ 0x75, 0x01, /* Report Size (1) */
+ 0x81, 0x02, /* Input (Data,Var,Abs) */
+
+ 0x95, 0x01, /* Report Count (1) */
+ 0x75, 0x03, /* Report Size (3) */
+ 0x81, 0x01, /* Input (Const) */
+
+ 0x05, 0x01, /* Usage Page (Generic Desktop) */
+ 0x09, 0x30, /* Usage (X) */
+ 0x09, 0x31, /* Usage (Y) */
+ 0x95, 0x02, /* Report Count (2) */
+ 0x75, 0x08, /* Report Size (8) */
+ 0x15, 0x81, /* Logical Minimum (-127) */
+ 0x25, 0x7F, /* Logical Maximum (127) */
+ 0x81, 0x06, /* Input (Data,Var,Rel) */
+
+ /* Vertical wheel logical collection */
+ 0xA1, 0x02, /* Collection (Logical) */
+
+ 0x85, 0x02, /* Report ID (0x02) */
+ 0x09, 0x48, /* Usage (Resolution Multiplier) */
+ 0x15, 0x00, /* Logical Minimum (0) */
+ 0x25, 0x01, /* Logical Maximum (1) */
+ 0x35, 0x01, /* Physical Minimum (1) */
+ 0x45, 0x04, /* Physical Maximum (4) */
+ 0x75, 0x02, /* Report Size (2) */
+ 0x95, 0x01, /* Report Count (1) */
+ 0xB1, 0x02, /* Feature (Data,Var,Abs) */
+
+ 0x85, 0x01, /* Report ID (0x01) */
+ 0x09, 0x38, /* Usage (Wheel) */
+ 0x35, 0x00, /* Physical Minimum (0) */
+ 0x45, 0x00, /* Physical Maximum (0) */
+ 0x15, 0x81, /* Logical Minimum (-0x7f) */
+ 0x25, 0x7F, /* Logical Maximum (0x7f) */
+ 0x75, 0x08, /* Report Size (8) */
+ 0x95, 0x01, /* Report Count (1) */
+ 0x81, 0x06, /* Input (Data,Var,Rel) */
+
+ 0xC0, /* End Collection */
+
+ /* Horizontal wheel logical collection */
+ 0xA1, 0x02, /* Collection (Logical) */
+
+ 0x85, 0x02, /* Report ID (0x02) */
+ 0x09, 0x48, /* Usage (Resolution Multiplier) */
+ 0x15, 0x00, /* Logical Minimum (0) */
+ 0x25, 0x01, /* Logical Maximum (1) */
+ 0x35, 0x01, /* Physical Minimum (1) */
+ 0x45, 0x04, /* Physical Maximum (4) */
+ 0x75, 0x02, /* Report Size (2) */
+ 0x95, 0x01, /* Report Count (1) */
+ 0xB1, 0x02, /* Feature (Data,Var,Abs) */
+
+ 0x35, 0x00, /* Physical Minimum (0) */
+ 0x45, 0x00, /* Physical Maximum (0) */
+ 0x75, 0x04, /* Report Size (4) */
+ 0x95, 0x01, /* Report Count (1) */
+ 0xB1, 0x01, /* Feature (Const) */
+
+ 0x85, 0x01, /* Report ID (0x01) */
+ 0x05, 0x0C, /* Usage Page (Consumer Devices) */
+ 0x0A, 0x38, 0x02, /* Usage (AC Pan) */
+ 0x15, 0x81, /* Logical Minimum (-0x7f) */
+ 0x25, 0x7F, /* Logical Maximum (0x7f) */
+ 0x75, 0x08, /* Report Size (8) */
+ 0x95, 0x01, /* Report Count (1) */
+ 0x81, 0x06, /* Input (Data,Var,Rel) */
+
+ 0xC0, /* End Collection */
+
+ 0xC0, /* End Collection (Physical) */
+ 0xC0, /* End Collection (Logical) */
+ 0xC0 /* End Collection (Application) */
};
static const uint8_t qemu_tablet_hid_report_descriptor[] = {
--
2.53.0
© 2016 - 2026 Red Hat, Inc.