summaryrefslogtreecommitdiff
path: root/sys/dev/usb
diff options
context:
space:
mode:
authorMartin Pieuchot <mpi@cvs.openbsd.org>2014-11-11 20:57:28 +0000
committerMartin Pieuchot <mpi@cvs.openbsd.org>2014-11-11 20:57:28 +0000
commit3c90f409c3cd7c499fa942c9844729ff2d6b3a95 (patch)
tree70736c2073f11f2d902085c22c512ebac60a63b0 /sys/dev/usb
parentc620a06f664f4a013dcd32b062a25817269d24cf (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.c47
-rw-r--r--sys/dev/usb/usbdivar.h4
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;