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);
/*