-/* $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 $ */
{
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);
-/* $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 $ */
/*
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;
}
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__,
switch (act) {
case DVACT_QUIESCE:
- sc->sc_bus->dying = 1;
if (sc->sc_bus->root_hub != NULL)
usb_detach_roothub(sc);
break;
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;
{
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);
-/* $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 $ */
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;