summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Gwynne <dlg@cvs.openbsd.org>2004-12-09 11:49:56 +0000
committerDavid Gwynne <dlg@cvs.openbsd.org>2004-12-09 11:49:56 +0000
commitd18484417b6d2f8acc96a6660af0dfc2e171dad6 (patch)
treec0c12b591c2119741a79a81b70dc98999e69fd21
parent5dc6ce44b18f8a46b4bd8c52a5079fa8ccdd6b39 (diff)
code to let us cause a detach and reattach of a device from software
ok deraadt@
-rw-r--r--sys/dev/usb/uhub.c82
-rw-r--r--sys/dev/usb/usbdivar.h3
2 files changed, 83 insertions, 2 deletions
diff --git a/sys/dev/usb/uhub.c b/sys/dev/usb/uhub.c
index f7e0b5bc69b..56033142051 100644
--- a/sys/dev/usb/uhub.c
+++ b/sys/dev/usb/uhub.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: uhub.c,v 1.26 2004/07/11 05:32:38 deraadt Exp $ */
+/* $OpenBSD: uhub.c,v 1.27 2004/12/09 11:49:55 dlg 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 $ */
@@ -83,6 +83,7 @@ struct uhub_softc {
};
Static usbd_status uhub_explore(usbd_device_handle hub);
+Static usbd_status uhub_reset_device(usbd_device_handle, int);
Static void uhub_intr(usbd_xfer_handle, usbd_private_handle,usbd_status);
#if defined(__FreeBSD__)
@@ -211,6 +212,7 @@ USB_ATTACH(uhub)
dev->hub = hub;
dev->hub->hubsoftc = sc;
hub->explore = uhub_explore;
+ hub->reset_device = uhub_reset_device;
hub->hubdesc = hubdesc;
DPRINTFN(1,("usbhub_init_hub: selfpowered=%d, parent=%p, "
@@ -323,6 +325,84 @@ USB_ATTACH(uhub)
USB_ATTACH_ERROR_RETURN;
}
+Static usbd_status
+uhub_reset_device(usbd_device_handle dev, int port)
+{
+ struct uhub_softc *sc = dev->hub->hubsoftc;
+ struct usbd_port *up;
+ int status, change;
+ int speed;
+ usbd_status err;
+
+ DPRINTFN(10, ("uhub_reset_device port=%d\n", port));
+
+ if (!sc->sc_running)
+ return (USBD_NOT_STARTED);
+
+ up = &dev->hub->ports[port-1];
+
+ /* Disconnect */
+ DPRINTF(("uhub_reset_device: disconnecting device on port %d\n", port));
+ usb_disconnect_port(up, USBDEV(sc->sc_dev));
+ usbd_clear_port_feature(dev, port, UHF_C_PORT_CONNECTION);
+
+ /* Wait for maximum device power up time. */
+ usbd_delay_ms(dev, USB_PORT_POWERUP_DELAY);
+
+ /* Reset port, which implies enabling it. */
+ err = usbd_reset_port(dev, port, &up->status);
+ if (err) {
+ printf("%s: port %d reset failed\n",
+ USBDEVNAME(sc->sc_dev), port);
+ return(err);
+ }
+
+ /* connect */
+ err = usbd_get_port_status(dev, port, &up->status);
+ if (err) {
+ DPRINTF(("uhub_reset_device: get port status failed, "
+ "error=%s\n", usbd_errstr(err)));
+ return (err);
+ }
+ status = UGETW(up->status.wPortStatus);
+ change = UGETW(up->status.wPortChange);
+
+ /* Figure out device speed */
+ if (status & UPS_HIGH_SPEED)
+ speed = USB_SPEED_HIGH;
+ else if (status & UPS_LOW_SPEED)
+ speed = USB_SPEED_LOW;
+ else
+ speed = USB_SPEED_FULL;
+ /* Get device info and set its address. */
+ err = usbd_new_device(USBDEV(sc->sc_dev), dev->bus, dev->depth + 1,
+ speed, port, up);
+ /* XXX retry a few times? */
+ if (err) {
+ DPRINTFN(-1,("uhub_explore: usb_new_device failed, "
+ "error=%s\n", usbd_errstr(err)));
+ /* Avoid addressing problems by disabling. */
+ /* usbd_reset_port(dev, port, &up->status); */
+
+ /*
+ * The unit refused to accept a new address, or had
+ * some other serious problem. Since we cannot leave
+ * at 0 we have to disable the port instead.
+ */
+ printf("%s: device problem, disabling port %d\n",
+ USBDEVNAME(sc->sc_dev), port);
+ usbd_clear_port_feature(dev, port, UHF_PORT_ENABLE);
+ } else {
+ /* The port set up succeeded, reset error count. */
+ up->restartcnt = 0;
+
+ if (up->device->hub)
+ up->device->hub->explore(up->device);
+ }
+
+ return (USBD_NORMAL_COMPLETION);
+}
+
usbd_status
uhub_explore(usbd_device_handle dev)
{
diff --git a/sys/dev/usb/usbdivar.h b/sys/dev/usb/usbdivar.h
index fa323578859..be9534447f7 100644
--- a/sys/dev/usb/usbdivar.h
+++ b/sys/dev/usb/usbdivar.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: usbdivar.h,v 1.19 2003/07/08 13:19:09 nate Exp $ */
+/* $OpenBSD: usbdivar.h,v 1.20 2004/12/09 11:49:55 dlg 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 $ */
@@ -86,6 +86,7 @@ struct usbd_port {
struct usbd_hub {
usbd_status (*explore)(usbd_device_handle hub);
+ usbd_status (*reset_device)(usbd_device_handle, int);
void *hubsoftc;
usb_hub_descriptor_t hubdesc;
struct usbd_port ports[1];