diff options
author | Martin Pieuchot <mpi@cvs.openbsd.org> | 2014-11-11 20:57:28 +0000 |
---|---|---|
committer | Martin Pieuchot <mpi@cvs.openbsd.org> | 2014-11-11 20:57:28 +0000 |
commit | 3c90f409c3cd7c499fa942c9844729ff2d6b3a95 (patch) | |
tree | 70736c2073f11f2d902085c22c512ebac60a63b0 /sys/dev/usb | |
parent | c620a06f664f4a013dcd32b062a25817269d24cf (diff) |
When a bus is explored, do not probe the ports which status hasn't
changed. This saves a lot of I/O when attaching/detaching devices
and might help with some timing related problems.
Has been in snap for ten days, committing now so that people testing
xhci(4) test the same thing w/ snapshots and their own kernel.
Diffstat (limited to 'sys/dev/usb')
-rw-r--r-- | sys/dev/usb/uhub.c | 47 | ||||
-rw-r--r-- | sys/dev/usb/usbdivar.h | 4 |
2 files changed, 34 insertions, 17 deletions
diff --git a/sys/dev/usb/uhub.c b/sys/dev/usb/uhub.c index eaf940af634..06d34cbceb5 100644 --- a/sys/dev/usb/uhub.c +++ b/sys/dev/usb/uhub.c @@ -1,4 +1,4 @@ -/* $OpenBSD: uhub.c,v 1.77 2014/11/10 14:26:38 mpi Exp $ */ +/* $OpenBSD: uhub.c,v 1.78 2014/11/11 20:57:27 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 $ */ @@ -57,8 +57,11 @@ struct uhub_softc { struct device sc_dev; /* base device */ struct usbd_device *sc_hub; /* USB device */ struct usbd_pipe *sc_ipipe; /* interrupt pipe */ - u_int8_t *sc_statusbuf; /* per port status buffer */ - size_t sc_statuslen; /* status bufferlen */ + + uint32_t sc_status; /* status from last interrupt */ + uint8_t *sc_statusbuf; /* per port status buffer */ + size_t sc_statuslen; /* status bufferlen */ + u_char sc_running; }; #define UHUB_PROTO(sc) ((sc)->sc_hub->ddesc.bDeviceProtocol) @@ -366,18 +369,24 @@ uhub_explore(struct usbd_device *dev) for (port = 1; port <= dev->hub->nports; port++) { up = &dev->hub->ports[port-1]; - err = usbd_get_port_status(dev, port, &up->status); - if (err) { - DPRINTF("%s: get port %d status failed, error=%s\n", - sc->sc_dev.dv_xname, port, usbd_errstr(err)); - continue; - } - status = UGETW(up->status.wPortStatus); - change = UGETW(up->status.wPortChange); + reconnect = up->reattach; up->reattach = 0; - DPRINTF("%s: port %d status=0x%04x change=0x%04x\n", - sc->sc_dev.dv_xname, port, status, change); + change = 0; + status = 0; + + if ((sc->sc_status & (1 << port)) || reconnect) { + sc->sc_status &= ~(1 << port); + + if (usbd_get_port_status(dev, port, &up->status)) + continue; + + status = UGETW(up->status.wPortStatus); + change = UGETW(up->status.wPortChange); + DPRINTF("%s: port %d status=0x%04x change=0x%04x\n", + sc->sc_dev.dv_xname, port, status, change); + } + if (change & UPS_C_PORT_ENABLED) { usbd_clear_port_feature(dev, port, UHF_C_PORT_ENABLE); if (change & UPS_C_CONNECT_STATUS) { @@ -410,7 +419,7 @@ uhub_explore(struct usbd_device *dev) /* We have a connect status change, handle it. */ usbd_clear_port_feature(dev, port, UHF_C_PORT_CONNECTION); - /*usbd_clear_port_feature(dev, port, UHF_C_PORT_ENABLE);*/ + /* * If there is already a device on the port the change status * must mean that is has disconnected. Looking at the @@ -573,13 +582,21 @@ void uhub_intr(struct usbd_xfer *xfer, void *addr, usbd_status status) { struct uhub_softc *sc = addr; + uint32_t stats; + int i; 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); - else if (status == USBD_NORMAL_COMPLETION) + else if (status == USBD_NORMAL_COMPLETION) { + for (i = 0; i < xfer->actlen; i++) + stats |= (uint32_t)(xfer->buffer[i]) << (i * 8); + sc->sc_status |= stats; + usb_needs_explore(sc->sc_hub, 0); + } } diff --git a/sys/dev/usb/usbdivar.h b/sys/dev/usb/usbdivar.h index 769db491f01..526a09c5218 100644 --- a/sys/dev/usb/usbdivar.h +++ b/sys/dev/usb/usbdivar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: usbdivar.h,v 1.67 2014/11/10 14:26:38 mpi Exp $ */ +/* $OpenBSD: usbdivar.h,v 1.68 2014/11/11 20:57:27 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 $ */ @@ -183,7 +183,7 @@ struct usbd_pipe { struct usbd_xfer { struct usbd_pipe *pipe; void *priv; - void *buffer; + char *buffer; u_int32_t length; u_int32_t actlen; u_int16_t flags; |