diff options
-rw-r--r-- | sys/dev/hid/hms.c | 71 | ||||
-rw-r--r-- | sys/modules/hid/hms/Makefile | 1 |
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> |