aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/dev/hid/hms.c71
-rw-r--r--sys/modules/hid/hms/Makefile1
2 files changed, 71 insertions, 1 deletions
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>