git: 3e954a8bc64e - main - hms: Workaround idle mouse drift in I2C sampling mode.

Vladimir Kondratyev wulf at FreeBSD.org
Wed Jan 20 20:10:44 UTC 2021


The branch main has been updated by wulf:

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

commit 3e954a8bc64ebc21893eedba0f2f1159c242c9b6
Author:     Vladimir Kondratyev <wulf at FreeBSD.org>
AuthorDate: 2021-01-20 20:10:07 +0000
Commit:     Vladimir Kondratyev <wulf at FreeBSD.org>
CommitDate: 2021-01-20 20:10:07 +0000

    hms: Workaround idle mouse drift in I2C sampling mode.
    
    Many I2C "compatibility" mouse devices found on touchpads continue to
    return last report data in sampling mode after touch has been ended.
    That results in cursor drift.  Filter out such a reports with comparing
    content of current report with content of previous one.
    
    Reported by:    many
    Tested by:      omatsuda, gllb (github.com)
    Obtained from:  sysutils/iichid
---
 sys/dev/hid/hms.c            | 71 +++++++++++++++++++++++++++++++++++++++++++-
 sys/modules/hid/hms/Makefile |  1 +
 2 files changed, 71 insertions(+), 1 deletion(-)

diff --git a/sys/dev/hid/hms.c b/sys/dev/hid/hms.c
index 7f3455ff2725..94267b3fcd52 100644
--- a/sys/dev/hid/hms.c
+++ b/sys/dev/hid/hms.c
@@ -32,6 +32,8 @@ __FBSDID("$FreeBSD$");
  * HID spec: https://www.usb.org/sites/default/files/documents/hid1_11.pdf
  */
 
+#include "opt_hid.h"
+
 #include <sys/param.h>
 #include <sys/bus.h>
 #include <sys/kernel.h>
@@ -65,6 +67,9 @@ enum {
 };
 
 static hidmap_cb_t	hms_final_cb;
+#ifdef IICHID_SAMPLING
+static hid_intr_t	hms_intr;
+#endif
 
 #define HMS_MAP_BUT_RG(usage_from, usage_to, code)	\
 	{ HIDMAP_KEY_RANGE(HUP_BUTTON, usage_from, usage_to, code) }
@@ -110,8 +115,46 @@ static const struct hid_device_id hms_devs[] = {
 struct hms_softc {
 	struct hidmap		hm;
 	HIDMAP_CAPS(caps, hms_map);
+#ifdef IICHID_SAMPLING
+	bool			iichid_sampling;
+	void			*last_ir;
+	hid_size_t		last_irsize;
+	hid_size_t		isize;
+	uint32_t		drift_cnt;
+	uint32_t		drift_thresh;
+#endif
 };
 
+#ifdef IICHID_SAMPLING
+static void
+hms_intr(void *context, void *buf, hid_size_t len)
+{
+	struct hidmap *hm = context;
+	struct hms_softc *sc = device_get_softc(hm->dev);
+
+	if (len > sc->isize)
+		len = sc->isize;
+
+	/*
+	 * Many I2C "compatibility" mouse devices found on touchpads continue
+	 * 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.
+	 */
+	if (len == sc->last_irsize && memcmp(buf, sc->last_ir, len) == 0) {
+		sc->drift_cnt++;
+		if (sc->drift_thresh != 0 && sc->drift_cnt >= sc->drift_thresh)
+			return;
+	} else {
+		sc->drift_cnt = 0;
+		sc->last_irsize = len;
+		bcopy(buf, sc->last_ir, len);
+	}
+
+	hidmap_intr(context, buf, len);
+}
+#endif
+
 static int
 hms_final_cb(HIDMAP_CB_ARGS)
 {
@@ -124,6 +167,11 @@ hms_final_cb(HIDMAP_CB_ARGS)
 			evdev_support_prop(evdev, INPUT_PROP_DIRECT);
 		else
 			evdev_support_prop(evdev, INPUT_PROP_POINTER);
+#ifdef IICHID_SAMPLING
+		/* Overload interrupt handler to skip identical reports */
+		if (sc->iichid_sampling)
+			hidbus_set_intr(sc->hm.dev, hms_intr, &sc->hm);
+#endif
 	}
 
 	/* Do not execute callback at interrupt handler and detach */
@@ -212,6 +260,21 @@ hms_attach(device_t dev)
 	else
 		HIDMAP_ADD_MAP(&sc->hm, hms_map_wheel, cap_wheel);
 
+#ifdef IICHID_SAMPLING
+	if (hid_test_quirk(hw, HQ_IICHID_SAMPLING) &&
+	    hidmap_test_cap(sc->caps, HMS_REL_X) &&
+	    hidmap_test_cap(sc->caps, HMS_REL_Y)) {
+		sc->iichid_sampling = true;
+		sc->isize = hid_report_size_max(d_ptr, d_len, hid_input, NULL);
+		sc->last_ir = malloc(sc->isize, M_DEVBUF, M_WAITOK | M_ZERO);
+		sc->drift_thresh = 2;
+		SYSCTL_ADD_U32(device_get_sysctl_ctx(dev),
+		    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
+		    "drift_thresh", CTLFLAG_RW, &sc->drift_thresh, 0,
+		    "drift detection threshhold");
+	}
+#endif
+
 	error = hidmap_attach(&sc->hm);
 	if (error)
 		return (error);
@@ -243,8 +306,14 @@ static int
 hms_detach(device_t dev)
 {
 	struct hms_softc *sc = device_get_softc(dev);
+	int error;
 
-	return (hidmap_detach(&sc->hm));
+	error = hidmap_detach(&sc->hm);
+#ifdef IICHID_SAMPLING
+	if (error == 0)
+		free(sc->last_ir, M_DEVBUF);
+#endif
+	return (error);
 }
 
 static devclass_t hms_devclass;
diff --git a/sys/modules/hid/hms/Makefile b/sys/modules/hid/hms/Makefile
index 71fbd2a77b89..29514b86385b 100644
--- a/sys/modules/hid/hms/Makefile
+++ b/sys/modules/hid/hms/Makefile
@@ -4,6 +4,7 @@
 
 KMOD=	hms
 SRCS=	hms.c
+SRCS+=	opt_hid.h
 SRCS+=	bus_if.h device_if.h
 
 .include <bsd.kmod.mk>


More information about the dev-commits-src-all mailing list