summaryrefslogtreecommitdiffstats
path: root/sys/dev/usb/usb.c
diff options
context:
space:
mode:
authormpi <mpi@openbsd.org>2014-03-31 16:18:06 +0000
committermpi <mpi@openbsd.org>2014-03-31 16:18:06 +0000
commit1a5eb39058725496436445f930bc71140262cfe2 (patch)
tree63886967d5a289bbe3a3b6ab7a7a21269150f3f9 /sys/dev/usb/usb.c
parentssh has a target painted on it's back, so use -fstack-protector-all (diff)
downloadwireguard-openbsd-1a5eb39058725496436445f930bc71140262cfe2.tar.xz
wireguard-openbsd-1a5eb39058725496436445f930bc71140262cfe2.zip
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/usb.c')
-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;