[RFC PATCH 4/5] usb/hid: handle mouse feature report for wheel/pan multipliers

Soumyajyotii Ssarkar posted 5 patches 1 week, 4 days ago
[RFC PATCH 4/5] usb/hid: handle mouse feature report for wheel/pan multipliers
Posted by Soumyajyotii Ssarkar 1 week, 4 days ago
Implement HID feature report handlers (GET_REPORT/SET_REPORT) for
report ID 0x02 to allow guests to configure wheel/pan resolution
multipliers.

Multiplier encoding:
- Bits [1:0]: wheel_multiplier (0=+-1, 1=+-4, 2=+-8, 3=+-16)
- Bits [3:2]: pan_multiplier (0=+-1, 1=+-4, 2=+-8, 3=+-16)

Supports flexible payload formats (with/without report ID byte).
Allows Windows guests to dynamically adjust scroll sensitivity without
driver installation.

Signed-off-by: Soumyajyotii Ssarkar <soumyajyotisarkar23@gmail.com>
---
 hw/usb/dev-hid.c       | 65 ++++++++++++++++++++++++++++++++++++------
 include/hw/input/hid.h |  2 ++
 2 files changed, 59 insertions(+), 8 deletions(-)

diff --git a/hw/usb/dev-hid.c b/hw/usb/dev-hid.c
index 49e23c2319..cdcf2a4a0e 100644
--- a/hw/usb/dev-hid.c
+++ b/hw/usb/dev-hid.c
@@ -672,17 +672,66 @@ static void usb_hid_handle_control(USBDevice *dev, USBPacket *p,
         }
         break;
     case HID_GET_REPORT:
-        if (hs->kind == HID_MOUSE || hs->kind == HID_TABLET) {
-            p->actual_length = hid_pointer_poll(hs, data, length);
-        } else if (hs->kind == HID_KEYBOARD) {
-            p->actual_length = hid_keyboard_poll(hs, data, length);
+        {
+            uint8_t mult;
+            uint8_t report_type = (value >> 8) & 0xFF;
+            uint8_t report_id = value & 0xFF;
+
+            if (report_type == 0x03 && report_id == 0x02 &&
+                hs->kind == HID_MOUSE) {
+
+                if (length < 1) {
+                    goto fail;
+                }
+
+                mult = ((hs->ptr.pan_multiplier & 0x03) << 2) |
+                       (hs->ptr.wheel_multiplier & 0x03);
+                if (length >= 2) {
+                    data[0] = 0x02;
+                    data[1] = mult;
+                    p->actual_length = 2;
+                } else {
+                    data[0] = mult;
+                    p->actual_length = 1;
+                }
+
+            } else if (hs->kind == HID_MOUSE || hs->kind == HID_TABLET) {
+                p->actual_length = hid_pointer_poll(hs, data, length);
+            } else if (hs->kind == HID_KEYBOARD) {
+                p->actual_length = hid_keyboard_poll(hs, data, length);
+            } else {
+                goto fail;
+            }
         }
         break;
     case HID_SET_REPORT:
-        if (hs->kind == HID_KEYBOARD) {
-            p->actual_length = hid_keyboard_write(hs, data, length);
-        } else {
-            goto fail;
+        {
+            uint8_t mult;
+            uint8_t report_type = (value >> 8) & 0xFF;
+            uint8_t report_id = value & 0xFF;
+
+            if (report_type == 0x03 && report_id == 0x02 &&
+                hs->kind == HID_MOUSE) {
+
+                if (length < 1) {
+                    goto fail;
+                }
+
+                if (length >= 2 && data[0] == 0x02) {
+                    mult = data[1];
+                } else {
+                    mult = data[0];
+                }
+
+                hs->ptr.wheel_multiplier = mult & 0x03;
+                hs->ptr.pan_multiplier = (mult >> 2) & 0x03;
+                p->actual_length = length;
+
+            } else if (hs->kind == HID_KEYBOARD) {
+                p->actual_length = hid_keyboard_write(hs, data, length);
+            } else {
+                goto fail;
+            }
         }
         break;
     case HID_GET_PROTOCOL:
diff --git a/include/hw/input/hid.h b/include/hw/input/hid.h
index 1bb1778ee7..1a1941d371 100644
--- a/include/hw/input/hid.h
+++ b/include/hw/input/hid.h
@@ -23,6 +23,8 @@ typedef void (*HIDEventFunc)(HIDState *s);
 typedef struct HIDMouseState {
     HIDPointerEvent queue[QUEUE_LENGTH];
     int mouse_grabbed;
+    uint8_t wheel_multiplier;
+    uint8_t pan_multiplier;
 } HIDMouseState;

 typedef struct HIDKeyboardState {
--
2.53.0