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