summaryrefslogtreecommitdiff
path: root/sys/dev/usb/uhub.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/usb/uhub.c')
-rw-r--r--sys/dev/usb/uhub.c45
1 files changed, 38 insertions, 7 deletions
diff --git a/sys/dev/usb/uhub.c b/sys/dev/usb/uhub.c
index 259eee8372d..09be18efd31 100644
--- a/sys/dev/usb/uhub.c
+++ b/sys/dev/usb/uhub.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: uhub.c,v 1.29 2004/12/12 05:21:14 dlg Exp $ */
+/* $OpenBSD: uhub.c,v 1.30 2005/03/13 02:54:04 pascoe 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 $ */
@@ -81,6 +81,9 @@ struct uhub_softc {
u_int8_t sc_status[1]; /* XXX more ports */
u_char sc_running;
};
+#define UHUB_PROTO(sc) ((sc)->sc_hub->ddesc.bDeviceProtocol)
+#define UHUB_IS_HIGH_SPEED(sc) (UHUB_PROTO(sc) != UDPROTO_FSHUB)
+#define UHUB_IS_SINGLE_TT(sc) (UHUB_PROTO(sc) == UDPROTO_HSHUBSTT)
Static usbd_status uhub_explore(usbd_device_handle hub);
Static void uhub_intr(usbd_xfer_handle, usbd_private_handle,usbd_status);
@@ -152,12 +155,13 @@ USB_ATTACH(uhub)
usbd_device_handle dev = uaa->device;
char devinfo[1024];
usbd_status err;
- struct usbd_hub *hub;
+ struct usbd_hub *hub = NULL;
usb_device_request_t req;
usb_hub_descriptor_t hubdesc;
int p, port, nports, nremov, pwrdly;
usbd_interface_handle iface;
usb_endpoint_descriptor_t *ed;
+ struct usbd_tt *tts = NULL;
DPRINTFN(1,("uhub_attach\n"));
sc->sc_hub = dev;
@@ -165,6 +169,13 @@ USB_ATTACH(uhub)
USB_ATTACH_SETUP;
printf("%s: %s\n", USBDEVNAME(sc->sc_dev), devinfo);
+ if (UHUB_IS_HIGH_SPEED(sc)) {
+ printf("%s: %s transaction translator%s\n",
+ USBDEVNAME(sc->sc_dev),
+ UHUB_IS_SINGLE_TT(sc) ? "single" : "multiple",
+ UHUB_IS_SINGLE_TT(sc) ? "" : "s");
+ }
+
err = usbd_set_config_index(dev, 0, 1);
if (err) {
DPRINTF(("%s: configuration failed, error=%s\n",
@@ -204,6 +215,11 @@ USB_ATTACH(uhub)
USBDEVNAME(sc->sc_dev), nports, nports != 1 ? "s" : "",
nremov, dev->self_powered ? "self" : "bus");
+ if (nports == 0) {
+ printf("%s: no ports, hub ignored\n", USBDEVNAME(sc->sc_dev));
+ goto bad;
+ }
+
hub = malloc(sizeof(*hub) + (nports-1) * sizeof(struct usbd_port),
M_USBDEV, M_NOWAIT);
if (hub == NULL)
@@ -281,10 +297,16 @@ USB_ATTACH(uhub)
* proceed with device attachment
*/
+ if (UHUB_IS_HIGH_SPEED(sc)) {
+ tts = malloc((UHUB_IS_SINGLE_TT(sc) ? 1 : nports) *
+ sizeof (struct usbd_tt), M_USBDEV, M_NOWAIT);
+ if (!tts)
+ goto bad;
+ }
/* Set up data structures */
for (p = 0; p < nports; p++) {
struct usbd_port *up = &hub->ports[p];
- up->device = 0;
+ up->device = NULL;
up->parent = dev;
up->portno = p+1;
if (dev->self_powered)
@@ -294,6 +316,12 @@ USB_ATTACH(uhub)
up->power = USB_MIN_POWER;
up->restartcnt = 0;
up->reattach = 0;
+ if (UHUB_IS_HIGH_SPEED(sc)) {
+ up->tt = &tts[UHUB_IS_SINGLE_TT(sc) ? 0 : p];
+ up->tt->hub = hub;
+ } else {
+ up->tt = NULL;
+ }
}
/* XXX should check for none, individual, or ganged power? */
@@ -319,8 +347,9 @@ USB_ATTACH(uhub)
USB_ATTACH_SUCCESS_RETURN;
bad:
- free(hub, M_USBDEV);
- dev->hub = 0;
+ if (hub)
+ free(hub, M_USBDEV);
+ dev->hub = NULL;
USB_ATTACH_ERROR_RETURN;
}
@@ -346,8 +375,6 @@ uhub_explore(usbd_device_handle dev)
for(port = 1; port <= hd->bNbrPorts; port++) {
up = &dev->hub->ports[port-1];
- reconnect = up->reattach;
- up->reattach = 0;
err = usbd_get_port_status(dev, port, &up->status);
if (err) {
DPRINTF(("uhub_explore: get port status failed, "
@@ -356,6 +383,8 @@ uhub_explore(usbd_device_handle dev)
}
status = UGETW(up->status.wPortStatus);
change = UGETW(up->status.wPortChange);
+ 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));
if (change & UPS_C_PORT_ENABLED) {
@@ -558,6 +587,8 @@ USB_DETACH(uhub)
usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_hub,
USBDEV(sc->sc_dev));
+ if (hub->ports[0].tt)
+ free(hub->ports[0].tt, M_USBDEV);
free(hub, M_USBDEV);
sc->sc_hub->hub = NULL;