diff options
Diffstat (limited to 'sys/dev/usb')
-rw-r--r-- | sys/dev/usb/uhub.c | 5 | ||||
-rw-r--r-- | sys/dev/usb/usb.c | 36 | ||||
-rw-r--r-- | sys/dev/usb/usbdivar.h | 3 |
3 files changed, 27 insertions, 17 deletions
diff --git a/sys/dev/usb/uhub.c b/sys/dev/usb/uhub.c index 2ef5e6f8d9e..b5974247a7f 100644 --- a/sys/dev/usb/uhub.c +++ b/sys/dev/usb/uhub.c @@ -1,4 +1,4 @@ -/* $OpenBSD: uhub.c,v 1.66 2014/03/11 10:24:42 mpi Exp $ */ +/* $OpenBSD: uhub.c,v 1.67 2014/05/28 11:20:55 mpi Exp $ */ /* $NetBSD: uhub.c,v 1.64 2003/02/08 03:32:51 ichiro Exp $ */ /* $FreeBSD: src/sys/dev/usb/uhub.c,v 1.18 1999/11/17 22:33:43 n_hibma Exp $ */ @@ -546,6 +546,9 @@ uhub_intr(struct usbd_xfer *xfer, void *addr, usbd_status status) { struct uhub_softc *sc = addr; + if (usbd_is_dying(sc->sc_hub)) + return; + DPRINTF("%s: intr status=%d\n", sc->sc_dev.dv_xname, status); if (status == USBD_STALLED) usbd_clear_endpoint_stall_async(sc->sc_ipipe); diff --git a/sys/dev/usb/usb.c b/sys/dev/usb/usb.c index ff5c3b3d2a5..2397a2f308f 100644 --- a/sys/dev/usb/usb.c +++ b/sys/dev/usb/usb.c @@ -1,4 +1,4 @@ -/* $OpenBSD: usb.c,v 1.96 2014/05/11 16:33:21 mpi Exp $ */ +/* $OpenBSD: usb.c,v 1.97 2014/05/28 11:20:55 mpi Exp $ */ /* $NetBSD: usb.c,v 1.77 2003/01/01 00:10:26 thorpej Exp $ */ /* @@ -260,11 +260,15 @@ usb_attach_roothub(struct usb_softc *sc) void usb_detach_roothub(struct usb_softc *sc) { - /* Make all devices disconnect. */ - if (sc->sc_port.device != NULL) - usb_disconnect_port(&sc->sc_port, (struct device *)sc); + /* + * To avoid races with the usb task thread, mark the root hub + * as disconnecting and schedule an exploration task to detach + * it. + */ + sc->sc_bus->flags |= USB_BUS_DISCONNECTING; + usb_needs_explore(sc->sc_bus->root_hub, 0); - usb_rem_wait_task(sc->sc_bus->root_hub, &sc->sc_explore_task); + usb_wait_task(sc->sc_bus->root_hub, &sc->sc_explore_task); sc->sc_bus->root_hub = NULL; } @@ -840,7 +844,18 @@ usb_explore(void *v) usb_delay_ms(sc->sc_bus, pwrdly - waited_ms); } - sc->sc_bus->root_hub->hub->explore(sc->sc_bus->root_hub); + if (sc->sc_bus->flags & USB_BUS_DISCONNECTING) { + /* Prevent new tasks from being scheduled. */ + sc->sc_bus->dying = 1; + + /* Make all devices disconnect. */ + if (sc->sc_port.device != NULL) + usb_disconnect_port(&sc->sc_port, (struct device *)sc); + + sc->sc_bus->flags &= ~USB_BUS_DISCONNECTING; + } else { + sc->sc_bus->root_hub->hub->explore(sc->sc_bus->root_hub); + } if (sc->sc_bus->flags & USB_BUS_CONFIG_PENDING) { DPRINTF(("%s: %s: first explore done\n", __func__, @@ -896,7 +911,6 @@ usb_activate(struct device *self, int act) switch (act) { case DVACT_QUIESCE: - sc->sc_bus->dying = 1; if (sc->sc_bus->root_hub != NULL) usb_detach_roothub(sc); break; @@ -914,10 +928,6 @@ usb_activate(struct device *self, int act) usb_needs_explore(sc->sc_bus->root_hub, 0); sc->sc_bus->use_polling--; break; - case DVACT_DEACTIVATE: - rv = config_activate_children(self, act); - sc->sc_bus->dying = 1; - break; default: rv = config_activate_children(self, act); break; @@ -930,10 +940,6 @@ usb_detach(struct device *self, int flags) { struct usb_softc *sc = (struct usb_softc *)self; - DPRINTF(("usb_detach: start\n")); - - sc->sc_bus->dying = 1; - if (sc->sc_bus->root_hub != NULL) { usb_detach_roothub(sc); diff --git a/sys/dev/usb/usbdivar.h b/sys/dev/usb/usbdivar.h index ab2b9742e83..7cbeaafbe53 100644 --- a/sys/dev/usb/usbdivar.h +++ b/sys/dev/usb/usbdivar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: usbdivar.h,v 1.58 2014/03/29 18:09:31 guenther Exp $ */ +/* $OpenBSD: usbdivar.h,v 1.59 2014/05/28 11:20:55 mpi Exp $ */ /* $NetBSD: usbdivar.h,v 1.70 2002/07/11 21:14:36 augustss Exp $ */ /* $FreeBSD: src/sys/dev/usb/usbdivar.h,v 1.11 1999/11/17 22:33:51 n_hibma Exp $ */ @@ -105,6 +105,7 @@ struct usbd_bus { char dying; int flags; #define USB_BUS_CONFIG_PENDING 0x01 +#define USB_BUS_DISCONNECTING 0x02 struct device *usbctl; struct usb_device_stats stats; int intr_context; |