On some laptops that have a Windows Precision Touchpad (imt) but also have a trackstick, imt was claiming all report ids of the ihidev device preventing the trackstick from attaching as a separate mouse (ims) device. (This probably doesn't affect Thinkpads because their trackstick attaches as a legacy pms device.)
Also, some touchpads don't have the "maximum number of contacts" or "button type" usages, so we can use some reasonable defaults here rather than failing to attach. I have confirmation that these fix the touchpad and trackstick on one Dell laptop and I'd like more testing to make sure they don't break other laptops. diff --git sys/dev/hid/hidmt.c sys/dev/hid/hidmt.c index 532da1b6627..8033c9cf446 100644 --- sys/dev/hid/hidmt.c +++ sys/dev/hid/hidmt.c @@ -138,31 +138,29 @@ hidmt_setup(struct device *self, struct hidmt *mt, void *desc, int dlen) } /* find maximum number of contacts being reported per input report */ - if (!hid_locate(desc, dlen, HID_USAGE2(HUP_DIGITIZERS, HUD_CONTACT_MAX), + mt->sc_num_contacts = HIDMT_MAX_CONTACTS; + if (hid_locate(desc, dlen, HID_USAGE2(HUP_DIGITIZERS, HUD_CONTACT_MAX), mt->sc_rep_cap, hid_feature, &cap, NULL)) { - printf("\n%s: can't find maximum contacts\n", self->dv_xname); - return 1; - } - - d = hid_get_udata(rep, capsize, &cap); - if (d > HIDMT_MAX_CONTACTS) { - printf("\n%s: contacts %d > max %d\n", self->dv_xname, d, - HIDMT_MAX_CONTACTS); - return 1; + d = hid_get_udata(rep, capsize, &cap); + if (d > HIDMT_MAX_CONTACTS) + printf("\n%s: contacts %d > max %d\n", self->dv_xname, + d, HIDMT_MAX_CONTACTS); + else + mt->sc_num_contacts = d; } - else - mt->sc_num_contacts = d; /* find whether this is a clickpad or not */ - if (!hid_locate(desc, dlen, HID_USAGE2(HUP_DIGITIZERS, HUD_BUTTON_TYPE), + if (hid_locate(desc, dlen, HID_USAGE2(HUP_DIGITIZERS, HUD_BUTTON_TYPE), mt->sc_rep_cap, hid_feature, &cap, NULL)) { - printf("\n%s: can't find button type\n", self->dv_xname); - return 1; + d = hid_get_udata(rep, capsize, &cap); + mt->sc_clickpad = (d == 0); + } else { + /* if there's not a 2nd button, this is probably a clickpad */ + if (!hid_locate(desc, dlen, HID_USAGE2(HUP_BUTTON, 2), + mt->sc_rep_input, hid_input, &cap, NULL)) + mt->sc_clickpad = 1; } - d = hid_get_udata(rep, capsize, &cap); - mt->sc_clickpad = (d == 0); - /* * Walk HID descriptor and store usages we care about to know what to * pluck out of input reports. diff --git sys/dev/i2c/ihidev.c sys/dev/i2c/ihidev.c index 4c63eb5bae2..789a2300a3f 100644 --- sys/dev/i2c/ihidev.c +++ sys/dev/i2c/ihidev.c @@ -173,17 +173,22 @@ ihidev_attach(struct device *parent, struct device *self, void *aux) iha.iaa = ia; iha.parent = sc; - /* Look for a driver claiming all report IDs first. */ - iha.reportid = IHIDEV_CLAIM_ALLREPORTID; + /* Look for a driver claiming multiple report IDs first. */ + iha.reportid = IHIDEV_CLAIM_MULTIPLEID; + iha.nclaims = 0; dev = config_found_sm((struct device *)sc, &iha, NULL, ihidev_submatch); if (dev != NULL) { - for (repid = 0; repid < sc->sc_nrepid; repid++) - sc->sc_subdevs[repid] = (struct ihidev *)dev; - return; + for (repid = 0; repid < iha.nclaims; repid++) { + sc->sc_subdevs[iha.claims[repid]] = + (struct ihidev *)dev; + } } for (repid = 0; repid < sc->sc_nrepid; repid++) { + if (sc->sc_subdevs[repid] != NULL) + continue; + if (hid_report_size(sc->sc_report, sc->sc_reportlen, hid_input, repid) == 0 && hid_report_size(sc->sc_report, sc->sc_reportlen, @@ -748,7 +753,7 @@ ihidev_print(void *aux, const char *pnp) if (pnp) printf("hid at %s", pnp); - if (iha->reportid != 0 && iha->reportid != IHIDEV_CLAIM_ALLREPORTID) + if (iha->reportid != 0) printf(" reportid %d", iha->reportid); return (UNCONF); diff --git sys/dev/i2c/ihidev.h sys/dev/i2c/ihidev.h index dde7cef5ab5..ad1f7ce83b8 100644 --- sys/dev/i2c/ihidev.h +++ sys/dev/i2c/ihidev.h @@ -112,7 +112,9 @@ struct ihidev_attach_arg { struct i2c_attach_args *iaa; struct ihidev_softc *parent; uint8_t reportid; -#define IHIDEV_CLAIM_ALLREPORTID 255 + uint8_t claims[16]; + uint8_t nclaims; +#define IHIDEV_CLAIM_MULTIPLEID 255 }; struct i2c_hid_report_request { diff --git sys/dev/i2c/imt.c sys/dev/i2c/imt.c index 38169837338..5a699921498 100644 --- sys/dev/i2c/imt.c +++ sys/dev/i2c/imt.c @@ -3,7 +3,7 @@ * HID-over-i2c multitouch trackpad driver for devices conforming to * Windows Precision Touchpad standard * - * https://msdn.microsoft.com/en-us/library/windows/hardware/dn467314%28v=vs.85%29.aspx + * https://docs.microsoft.com/en-us/windows-hardware/design/component-guidelines/windows-precision-touchpad-required-hid-top-level-collections * * Copyright (c) 2016 joshua stein <j...@openbsd.org> * @@ -79,13 +79,19 @@ int imt_match(struct device *parent, void *match, void *aux) { struct ihidev_attach_arg *iha = (struct ihidev_attach_arg *)aux; + struct imt_softc sc; int size; void *desc; - if (iha->reportid == IHIDEV_CLAIM_ALLREPORTID) { + if (iha->reportid == IHIDEV_CLAIM_MULTIPLEID) { ihidev_get_report_desc(iha->parent, &desc, &size); - if (imt_find_winptp_reports(iha->parent, desc, size, NULL)) + if (imt_find_winptp_reports(iha->parent, desc, size, &sc)) { + iha->claims[0] = sc.sc_rep_input; + iha->claims[1] = sc.sc_rep_config; + iha->claims[2] = sc.sc_rep_cap; + iha->nclaims = 3; return (IMATCH_DEVCLASS_DEVSUBCLASS); + } } return (IMATCH_NONE);