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

Reply via email to