On a particular laptop with a touchpad behind ihidev, dwiic would 
report a timeout every time it had to fetch touch data:

    dwiic0: timed out reading remaining 2

On re-reading the i2c HID spec, the size supplied by wMaxInputLength 
is already supposed to account for the size and report id bytes so 
we shouldn't be adding them after the fact.  Otherwise ihidev would 
ask for more data than can be available and, on this laptop anyway, 
dwiic would have to wait for this transaction to timeout and fail.

This fix matches how the Linux i2c-hid driver operates.  I've tested 
this on 3 laptops with touchpads and touchscreens and it doesn't 
cause any regressions here while fixing the touchpad on one of them.  
I'd appreciate tests on other laptops to make sure it doesn't break 
anything and perhaps fixes your issue if you've also seen constant 
dwiic timeouts.



Index: sys/dev/i2c/ihidev.c
===================================================================
RCS file: /cvs/src/sys/dev/i2c/ihidev.c,v
retrieving revision 1.23
diff -u -p -u -p -r1.23 ihidev.c
--- sys/dev/i2c/ihidev.c        9 Jul 2020 21:01:55 -0000       1.23
+++ sys/dev/i2c/ihidev.c        23 Aug 2021 02:38:21 -0000
@@ -106,7 +106,6 @@ ihidev_attach(struct device *parent, str
        struct device *dev;
        int repid, repsz;
        int repsizes[256];
-       int isize;
 
        sc->sc_tag = ia->ia_tag;
        sc->sc_addr = ia->ia_addr;
@@ -158,12 +157,8 @@ ihidev_attach(struct device *parent, str
                repsz = hid_report_size(sc->sc_report, sc->sc_reportlen,
                    hid_input, repid);
                repsizes[repid] = repsz;
-
-               isize = repsz + 2; /* two bytes for the length */
-               isize += (sc->sc_nrepid != 1); /* one byte for the report ID */
-               if (isize > sc->sc_isize)
-                       sc->sc_isize = isize;
-
+               if (repsz > sc->sc_isize)
+                       sc->sc_isize = repsz;
                if (repsz != 0)
                        DPRINTF(("%s: repid %d size %d\n", sc->sc_dev.dv_xname,
                            repid, repsz));
@@ -648,7 +643,7 @@ ihidev_intr(void *arg)
 
        iic_acquire_bus(sc->sc_tag, I2C_F_POLL);
        res = iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr, NULL, 0,
-           sc->sc_ibuf, sc->sc_isize, I2C_F_POLL);
+           sc->sc_ibuf, letoh16(sc->hid_desc.wMaxInputLength), I2C_F_POLL);
        iic_release_bus(sc->sc_tag, I2C_F_POLL);
 
        /*

Reply via email to