On Wed, 17 Mar 2021 at 09:19:05 -0500, joshua stein wrote: > On Wed, 17 Mar 2021 at 07:41:53 +0100, Anton Lindqvist wrote: > > I'm wondering if the umt device is detached more than once since it > > claims multiple report ids. I ran into the same problem while developing > > uhidpp: > > > > https://github.com/openbsd/src/blob/master/sys/dev/usb/uhidpp.c#L437-L443 > > > > Also, the output of `show registers` in ddb would be helpful. > > > > Something like this is probably needed (maybe also for > uhidev_activate):
Here's an updated version with feedback from Anton and a similar fix for uhidev_activate. Edd, can you test whether this fixes the panic for you and if possible, if the machine suspends/resumes properly with the touchpad attached (if it did before)? diff --git sys/dev/usb/uhidev.c sys/dev/usb/uhidev.c index d777cfb6e45..dd43b1bb000 100644 --- sys/dev/usb/uhidev.c +++ sys/dev/usb/uhidev.c @@ -382,17 +382,32 @@ int uhidev_activate(struct device *self, int act) { struct uhidev_softc *sc = (struct uhidev_softc *)self; - int i, rv = 0, r; + int i, j, already, rv = 0, r; switch (act) { case DVACT_DEACTIVATE: - for (i = 0; i < sc->sc_nrepid; i++) - if (sc->sc_subdevs[i] != NULL) { + for (i = 0; i < sc->sc_nrepid; i++) { + if (sc->sc_subdevs[i] == NULL) + continue; + + /* + * Only notify devices attached to multiple report ids + * once. + */ + for (already = 0, j = 0; j < i; j++) { + if (sc->sc_subdevs[i] == sc->sc_subdevs[j]) { + already = 1; + break; + } + } + + if (!already) { r = config_deactivate( &sc->sc_subdevs[i]->sc_dev); if (r && r != EOPNOTSUPP) rv = r; } + } usbd_deactivate(sc->sc_udev); break; } @@ -403,7 +418,7 @@ int uhidev_detach(struct device *self, int flags) { struct uhidev_softc *sc = (struct uhidev_softc *)self; - int i, rv = 0; + int i, j, rv = 0; DPRINTF(("uhidev_detach: sc=%p flags=%d\n", sc, flags)); @@ -420,19 +435,20 @@ uhidev_detach(struct device *self, int flags) if (sc->sc_repdesc != NULL) free(sc->sc_repdesc, M_USBDEV, sc->sc_repdesc_size); - /* - * XXX Check if we have only one children claiming all the Report - * IDs, this is a hack since we need a dev -> Report ID mapping - * for uhidev_intr(). - */ - if (sc->sc_nrepid > 1 && sc->sc_subdevs[0] != NULL && - sc->sc_subdevs[0] == sc->sc_subdevs[1]) - return (config_detach(&sc->sc_subdevs[0]->sc_dev, flags)); - for (i = 0; i < sc->sc_nrepid; i++) { - if (sc->sc_subdevs[i] != NULL) { - rv |= config_detach(&sc->sc_subdevs[i]->sc_dev, flags); - sc->sc_subdevs[i] = NULL; + if (sc->sc_subdevs[i] == NULL) + continue; + + rv |= config_detach(&sc->sc_subdevs[i]->sc_dev, flags); + sc->sc_subdevs[i] = NULL; + + /* + * Nullify without detaching any other instances of this device + * found on other report ids. + */ + for (j = i + 1; j < sc->sc_nrepid; j++) { + if (sc->sc_subdevs[i] == sc->sc_subdevs[j]) + sc->sc_subdevs[j] = NULL; } }