diff options
author | Martin Pieuchot <mpi@cvs.openbsd.org> | 2014-03-31 16:18:07 +0000 |
---|---|---|
committer | Martin Pieuchot <mpi@cvs.openbsd.org> | 2014-03-31 16:18:07 +0000 |
commit | 88cbf99a0b9a91663e6669b9cb54c66acacd413c (patch) | |
tree | ca671ccf1b9e6ffa2844e82eedae65be35cfa29b /sys/dev/usb | |
parent | 94227fdaeb807779420752640de378e417756c3b (diff) |
Force the detach of all USB devices by disconnecting the root hubs
before suspending the machine.
Prior to this commit, devices were logically disconnected after
resuming the machine leading to funny races since the controller
was reset in between.
ok deraadt@
Diffstat (limited to 'sys/dev/usb')
-rw-r--r-- | sys/dev/usb/usb.c | 101 |
1 files changed, 61 insertions, 40 deletions
diff --git a/sys/dev/usb/usb.c b/sys/dev/usb/usb.c index d15ecf68f2d..15a43b62bcd 100644 --- a/sys/dev/usb/usb.c +++ b/sys/dev/usb/usb.c @@ -1,4 +1,4 @@ -/* $OpenBSD: usb.c,v 1.94 2014/03/08 11:49:19 mpi Exp $ */ +/* $OpenBSD: usb.c,v 1.95 2014/03/31 16:18:06 mpi Exp $ */ /* $NetBSD: usb.c,v 1.77 2003/01/01 00:10:26 thorpej Exp $ */ /* @@ -92,6 +92,7 @@ struct usb_softc { struct device sc_dev; /* base device */ struct usbd_bus *sc_bus; /* USB controller */ struct usbd_port sc_port; /* dummy port for root hub */ + int sc_speed; struct usb_task sc_explore_task; @@ -125,6 +126,9 @@ void usb_attach(struct device *, struct device *, void *); int usb_detach(struct device *, int); int usb_activate(struct device *, int); +int usb_attach_roothub(struct usb_softc *); +void usb_detach_roothub(struct usb_softc *); + struct cfdriver usb_cd = { NULL, "usb", DV_DULL }; @@ -147,10 +151,7 @@ void usb_attach(struct device *parent, struct device *self, void *aux) { struct usb_softc *sc = (struct usb_softc *)self; - struct usbd_device *dev; - usbd_status err; int usbrev; - int speed; if (usb_nbuses == 0) { rw_init(&usbpalock, "usbpalock"); @@ -171,13 +172,13 @@ usb_attach(struct device *parent, struct device *self, void *aux) switch (usbrev) { case USBREV_1_0: case USBREV_1_1: - speed = USB_SPEED_FULL; + sc->sc_speed = USB_SPEED_FULL; break; case USBREV_2_0: - speed = USB_SPEED_HIGH; + sc->sc_speed = USB_SPEED_HIGH; break; case USBREV_3_0: - speed = USB_SPEED_SUPER; + sc->sc_speed = USB_SPEED_SUPER; break; default: printf(", not supported\n"); @@ -206,17 +207,10 @@ usb_attach(struct device *parent, struct device *self, void *aux) return; } - err = usbd_new_device(&sc->sc_dev, sc->sc_bus, 0, speed, 0, - &sc->sc_port); - if (!err) { - dev = sc->sc_port.device; - if (dev->hub == NULL) { - sc->sc_bus->dying = 1; - printf("%s: root device is not a hub\n", - sc->sc_dev.dv_xname); - return; - } - sc->sc_bus->root_hub = dev; + + + if (!usb_attach_roothub(sc)) { + struct usbd_device *dev = sc->sc_bus->root_hub; #if 1 /* * Turning this code off will delay attachment of USB devices @@ -226,11 +220,8 @@ usb_attach(struct device *parent, struct device *self, void *aux) if (cold && (sc->sc_dev.dv_cfdata->cf_flags & 1)) dev->hub->explore(sc->sc_bus->root_hub); #endif - } else { - printf("%s: root hub problem, error=%d\n", - sc->sc_dev.dv_xname, err); - sc->sc_bus->dying = 1; } + if (cold) sc->sc_bus->use_polling--; @@ -243,6 +234,41 @@ usb_attach(struct device *parent, struct device *self, void *aux) } } +int +usb_attach_roothub(struct usb_softc *sc) +{ + struct usbd_device *dev; + + if (usbd_new_device(&sc->sc_dev, sc->sc_bus, 0, sc->sc_speed, 0, + &sc->sc_port)) { + printf("%s: root hub problem\n", sc->sc_dev.dv_xname); + sc->sc_bus->dying = 1; + return (1); + } + + dev = sc->sc_port.device; + if (dev->hub == NULL) { + printf("%s: root device is not a hub\n", sc->sc_dev.dv_xname); + sc->sc_bus->dying = 1; + return (1); + } + sc->sc_bus->root_hub = dev; + + return (0); +} + +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); + + usb_rem_wait_task(sc->sc_bus->root_hub, &sc->sc_explore_task); + + sc->sc_bus->root_hub = NULL; +} + void usb_create_task_threads(void *arg) { @@ -866,23 +892,22 @@ int usb_activate(struct device *self, int act) { struct usb_softc *sc = (struct usb_softc *)self; - struct usbd_device *dev = sc->sc_port.device; - int i, rv = 0, r; + int rv = 0; switch (act) { - case DVACT_DEACTIVATE: + case DVACT_QUIESCE: sc->sc_bus->dying = 1; - if (dev != NULL && dev->cdesc != NULL && - dev->subdevs != NULL) { - for (i = 0; dev->subdevs[i]; i++) { - r = config_deactivate(dev->subdevs[i]); - if (r) - rv = r; - } - } + if (sc->sc_bus->root_hub != NULL) + usb_detach_roothub(sc); break; - case DVACT_RESUME: - usb_needs_explore(sc->sc_bus->root_hub, 0); + case DVACT_WAKEUP: + sc->sc_bus->dying = 0; + if (!usb_attach_roothub(sc)) + usb_needs_explore(sc->sc_bus->root_hub, 0); + break; + case DVACT_DEACTIVATE: + rv = config_activate_children(self, act); + sc->sc_bus->dying = 1; break; default: rv = config_activate_children(self, act); @@ -901,11 +926,7 @@ usb_detach(struct device *self, int flags) sc->sc_bus->dying = 1; if (sc->sc_bus->root_hub != NULL) { - /* Make all devices disconnect. */ - if (sc->sc_port.device != NULL) - usb_disconnect_port(&sc->sc_port, self); - - usb_rem_wait_task(sc->sc_bus->root_hub, &sc->sc_explore_task); + usb_detach_roothub(sc); if (--usb_nbuses == 0) { usb_run_tasks = usb_run_abort_tasks = 0; |