summaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
authorMartin Pieuchot <mpi@cvs.openbsd.org>2014-03-31 16:18:07 +0000
committerMartin Pieuchot <mpi@cvs.openbsd.org>2014-03-31 16:18:07 +0000
commit88cbf99a0b9a91663e6669b9cb54c66acacd413c (patch)
treeca671ccf1b9e6ffa2844e82eedae65be35cfa29b /sys/dev
parent94227fdaeb807779420752640de378e417756c3b (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')
-rw-r--r--sys/dev/usb/usb.c101
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;