Keep track of the per-port status change notifications coming in
through the interrupt pipe; during exploration check only the ports where we got such a notification. This speeds up things. (I believe we should go a step further and use a thread per hub instead of per bus. If power management gets implemented, we should be able to react quickly on a resume event.) Try to simplify the logics in the explore function a bit. (The reattach thing was hacked in badly, not sure whether I broke it. Only used by if_atu.) Clean up some dead code.
This commit is contained in:
parent
dc9d1127cc
commit
82d96e1fac
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: uhub.c,v 1.86 2007/03/13 13:51:55 drochner Exp $ */
|
||||
/* $NetBSD: uhub.c,v 1.87 2007/03/15 15:29:09 drochner Exp $ */
|
||||
/* $FreeBSD: src/sys/dev/usb/uhub.c,v 1.18 1999/11/17 22:33:43 n_hibma Exp $ */
|
||||
|
||||
/*
|
||||
@ -43,7 +43,7 @@
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: uhub.c,v 1.86 2007/03/13 13:51:55 drochner Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: uhub.c,v 1.87 2007/03/15 15:29:09 drochner Exp $");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
@ -79,19 +79,25 @@ struct uhub_softc {
|
||||
usbd_device_handle sc_hub; /* USB device */
|
||||
int sc_proto; /* device protocol */
|
||||
usbd_pipe_handle sc_ipipe; /* interrupt pipe */
|
||||
|
||||
/* XXX second buffer needed because we can't suspend pipes yet */
|
||||
u_int8_t *sc_statusbuf;
|
||||
u_int8_t *sc_status;
|
||||
size_t sc_statuslen;
|
||||
int sc_explorepending;
|
||||
|
||||
u_char sc_running;
|
||||
};
|
||||
|
||||
#define UHUB_IS_HIGH_SPEED(sc) ((sc)->sc_proto != UDPROTO_FSHUB)
|
||||
#define UHUB_IS_SINGLE_TT(sc) ((sc)->sc_proto == UDPROTO_HSHUBSTT)
|
||||
|
||||
#define PORTSTAT_ISSET(sc, port) \
|
||||
((sc)->sc_status[(port) / 8] & (1 << ((port) % 8)))
|
||||
|
||||
Static usbd_status uhub_explore(usbd_device_handle hub);
|
||||
Static void uhub_intr(usbd_xfer_handle, usbd_private_handle,usbd_status);
|
||||
|
||||
#if defined(__FreeBSD__)
|
||||
Static bus_child_detached_t uhub_child_detached;
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* We need two attachment points:
|
||||
@ -152,7 +158,6 @@ USB_ATTACH(uhub)
|
||||
#if 0 /* notyet */
|
||||
struct usbd_tt *tts = NULL;
|
||||
#endif
|
||||
size_t statuslen;
|
||||
|
||||
DPRINTFN(1,("uhub_attach\n"));
|
||||
sc->sc_hub = dev;
|
||||
@ -247,14 +252,21 @@ USB_ATTACH(uhub)
|
||||
goto bad;
|
||||
}
|
||||
|
||||
statuslen = (nports + 1 + 7) / 8;
|
||||
sc->sc_status = malloc(statuslen, M_USBDEV, M_NOWAIT);
|
||||
sc->sc_statuslen = (nports + 1 + 7) / 8;
|
||||
sc->sc_statusbuf = malloc(sc->sc_statuslen, M_USBDEV, M_NOWAIT);
|
||||
if (!sc->sc_statusbuf)
|
||||
goto bad;
|
||||
sc->sc_status = malloc(sc->sc_statuslen, M_USBDEV, M_NOWAIT);
|
||||
if (!sc->sc_status)
|
||||
goto bad;
|
||||
|
||||
/* force initial scan */
|
||||
memset(sc->sc_status, 0xff, sc->sc_statuslen);
|
||||
sc->sc_explorepending = 1;
|
||||
|
||||
err = usbd_open_pipe_intr(iface, ed->bEndpointAddress,
|
||||
USBD_SHORT_XFER_OK, &sc->sc_ipipe, sc, sc->sc_status,
|
||||
statuslen, uhub_intr, USBD_DEFAULT_INTERVAL);
|
||||
USBD_SHORT_XFER_OK, &sc->sc_ipipe, sc, sc->sc_statusbuf,
|
||||
sc->sc_statuslen, uhub_intr, USBD_DEFAULT_INTERVAL);
|
||||
if (err) {
|
||||
printf("%s: cannot open interrupt pipe\n",
|
||||
USBDEVNAME(sc->sc_dev));
|
||||
@ -375,18 +387,31 @@ uhub_explore(usbd_device_handle dev)
|
||||
|
||||
for (port = 1; port <= hd->bNbrPorts; port++) {
|
||||
up = &dev->hub->ports[port-1];
|
||||
err = usbd_get_port_status(dev, port, &up->status);
|
||||
if (err) {
|
||||
DPRINTF(("uhub_explore: get port status failed, "
|
||||
"error=%s\n", usbd_errstr(err)));
|
||||
continue;
|
||||
}
|
||||
status = UGETW(up->status.wPortStatus);
|
||||
change = UGETW(up->status.wPortChange);
|
||||
|
||||
/* reattach is needed after firmware upload */
|
||||
reconnect = up->reattach;
|
||||
up->reattach = 0;
|
||||
DPRINTFN(3,("uhub_explore: %s port %d status 0x%04x 0x%04x\n",
|
||||
USBDEVNAME(sc->sc_dev), port, status, change));
|
||||
|
||||
status = change = 0;
|
||||
|
||||
/* don't check if no change summary notification */
|
||||
if (PORTSTAT_ISSET(sc, port) || reconnect) {
|
||||
err = usbd_get_port_status(dev, port, &up->status);
|
||||
if (err) {
|
||||
DPRINTF(("uhub_explore: get port stat failed, "
|
||||
"error=%s\n", usbd_errstr(err)));
|
||||
continue;
|
||||
}
|
||||
status = UGETW(up->status.wPortStatus);
|
||||
change = UGETW(up->status.wPortChange);
|
||||
}
|
||||
if (!change && !reconnect) {
|
||||
/* No status change, just do recursive explore. */
|
||||
if (up->device != NULL && up->device->hub != NULL)
|
||||
up->device->hub->explore(up->device);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (change & UPS_C_PORT_ENABLED) {
|
||||
DPRINTF(("uhub_explore: C_PORT_ENABLED\n"));
|
||||
usbd_clear_port_feature(dev, port, UHF_C_PORT_ENABLE);
|
||||
@ -411,27 +436,17 @@ uhub_explore(usbd_device_handle dev)
|
||||
USBDEVNAME(sc->sc_dev), port);
|
||||
}
|
||||
}
|
||||
if (!reconnect && !(change & UPS_C_CONNECT_STATUS)) {
|
||||
DPRINTFN(3,("uhub_explore: port=%d !C_CONNECT_"
|
||||
"STATUS\n", port));
|
||||
/* No status change, just do recursive explore. */
|
||||
if (up->device != NULL && up->device->hub != NULL)
|
||||
up->device->hub->explore(up->device);
|
||||
#if 0 && defined(DIAGNOSTIC)
|
||||
if (up->device == NULL &&
|
||||
(status & UPS_CURRENT_CONNECT_STATUS))
|
||||
printf("%s: connected, no device\n",
|
||||
USBDEVNAME(sc->sc_dev));
|
||||
#endif
|
||||
|
||||
/* XXX handle overcurrent and resume events! */
|
||||
|
||||
if (!(change & UPS_C_CONNECT_STATUS))
|
||||
continue;
|
||||
}
|
||||
|
||||
/* We have a connect status change, handle it. */
|
||||
|
||||
DPRINTF(("uhub_explore: status change hub=%d port=%d\n",
|
||||
dev->address, port));
|
||||
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
|
||||
@ -488,15 +503,6 @@ uhub_explore(usbd_device_handle dev)
|
||||
continue;
|
||||
}
|
||||
|
||||
#if 0
|
||||
if (UHUB_IS_HIGH_SPEED(sc) && !(status & UPS_HIGH_SPEED)) {
|
||||
printf("%s: port %d, transaction translation not "
|
||||
"implemented, low/full speed device ignored\n",
|
||||
USBDEVNAME(sc->sc_dev), port);
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Figure out device speed */
|
||||
if (status & UPS_HIGH_SPEED)
|
||||
speed = USB_SPEED_HIGH;
|
||||
@ -530,6 +536,8 @@ uhub_explore(usbd_device_handle dev)
|
||||
up->device->hub->explore(up->device);
|
||||
}
|
||||
}
|
||||
/* enable status change notifications again */
|
||||
sc->sc_explorepending = 0;
|
||||
return (USBD_NORMAL_COMPLETION);
|
||||
}
|
||||
|
||||
@ -652,15 +660,20 @@ uhub_intr(usbd_xfer_handle xfer, usbd_private_handle addr,
|
||||
{
|
||||
struct uhub_softc *sc = addr;
|
||||
|
||||
#if 0
|
||||
void *buf; int cnt;
|
||||
usbd_get_xfer_status(xfer, NULL, &buf, &cnt, NULL);
|
||||
#endif
|
||||
DPRINTFN(5,("uhub_intr: sc=%p\n", sc));
|
||||
|
||||
if (status == USBD_STALLED)
|
||||
usbd_clear_endpoint_stall_async(sc->sc_ipipe);
|
||||
else if (status == USBD_NORMAL_COMPLETION)
|
||||
else if (status == USBD_NORMAL_COMPLETION &&
|
||||
!sc->sc_explorepending) {
|
||||
/*
|
||||
* Make sure the status is not overwritten in between.
|
||||
* XXX we should suspend the pipe instead
|
||||
*/
|
||||
memcpy(sc->sc_status, sc->sc_statusbuf, sc->sc_statuslen);
|
||||
sc->sc_explorepending = 1;
|
||||
usb_needs_explore(sc->sc_hub);
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(__FreeBSD__)
|
||||
|
Loading…
Reference in New Issue
Block a user