git: c0a5ee953f41 - main - hms(4): improve scroll with IICHID_SAMPLING

From: Edward Tomasz Napierala <trasz_at_FreeBSD.org>
Date: Tue, 26 Nov 2024 10:48:05 UTC
The branch main has been updated by trasz:

URL: https://cgit.FreeBSD.org/src/commit/?id=c0a5ee953f41905038aadba7b7d0df2af6612e71

commit c0a5ee953f41905038aadba7b7d0df2af6612e71
Author:     Edward Tomasz Napierala <trasz@FreeBSD.org>
AuthorDate: 2024-11-25 15:08:10 +0000
Commit:     Edward Tomasz Napierala <trasz@FreeBSD.org>
CommitDate: 2024-11-26 10:28:51 +0000

    hms(4): improve scroll with IICHID_SAMPLING
    
    The current quirk is designed to discard duplicated data read from
    the chip.  Problem is, it also discards real events when they happen
    to be identical, which is the case with scroll wheel events;
    differently from X/Y they always move by fixed offset.  This results
    in two-finger scroll that would stop mid-way that could be fixed by
    manually setting dev.hms.0.drift_thresh to 0.
    
    To fix that, don't discard duplicates when there's wheel movement.
    For users with actual duplicates problem this will result in scroll
    suddenly becoming quite inertial, but it will stop moving at any touch,
    so shouldn't be terrible.
    
    PR:             kern/276709
    Reviewed By:    wulf
    Differential Revision:  https://reviews.freebsd.org/D47640
---
 sys/dev/hid/hms.c | 32 ++++++++++++++++++++++++++++++--
 1 file changed, 30 insertions(+), 2 deletions(-)

diff --git a/sys/dev/hid/hms.c b/sys/dev/hid/hms.c
index 0ac1b86c0735..dcb679407cca 100644
--- a/sys/dev/hid/hms.c
+++ b/sys/dev/hid/hms.c
@@ -122,6 +122,7 @@ struct hms_softc {
 	hid_size_t		isize;
 	uint32_t		drift_cnt;
 	uint32_t		drift_thresh;
+	struct hid_location	wheel_loc;
 #endif
 };
 
@@ -131,6 +132,7 @@ hms_intr(void *context, void *buf, hid_size_t len)
 {
 	struct hidmap *hm = context;
 	struct hms_softc *sc = device_get_softc(hm->dev);
+	int32_t wheel;
 
 	if (len > sc->isize)
 		len = sc->isize;
@@ -140,8 +142,18 @@ hms_intr(void *context, void *buf, hid_size_t len)
 	 * to return last report data in sampling mode even after touch has
 	 * been ended.  That results in cursor drift.  Filter out such a
 	 * reports through comparing with previous one.
+	 *
+	 * Except this results in dropping consecutive mouse wheel events,
+	 * because differently from cursor movement they always move by the
+	 * same amount.  So, don't do it when there's mouse wheel movement.
 	 */
-	if (len == sc->last_irsize && memcmp(buf, sc->last_ir, len) == 0) {
+	if (sc->wheel_loc.size != 0)
+		wheel = hid_get_data(buf, len, &sc->wheel_loc);
+	else
+		wheel = 0;
+
+	if (len == sc->last_irsize && memcmp(buf, sc->last_ir, len) == 0 &&
+	    wheel == 0) {
 		sc->drift_cnt++;
 		if (sc->drift_thresh != 0 && sc->drift_cnt >= sc->drift_thresh)
 			return;
@@ -285,9 +297,25 @@ hms_attach(device_t dev)
 	/* Count number of input usages of variable type mapped to buttons */
 	for (hi = sc->hm.hid_items;
 	     hi < sc->hm.hid_items + sc->hm.nhid_items;
-	     hi++)
+	     hi++) {
 		if (hi->type == HIDMAP_TYPE_VARIABLE && hi->evtype == EV_KEY)
 			nbuttons++;
+#ifdef IICHID_SAMPLING
+		/*
+		 * Make note of which part of the report descriptor is the wheel.
+		 */
+		if (hi->type == HIDMAP_TYPE_VARIABLE &&
+		    hi->evtype == EV_REL && hi->code == REL_WHEEL) {
+			sc->wheel_loc = hi->loc;
+			/*
+			 * Account for the leading Report ID byte
+			 * if it is a multi-report device.
+			 */
+			if (hi->id != 0)
+				sc->wheel_loc.pos += 8;
+		}
+#endif
+	}
 
 	/* announce information about the mouse */
 	device_printf(dev, "%d buttons and [%s%s%s%s%s] coordinates ID=%u\n",