diff options
Diffstat (limited to 'sys/dev/usb/uhub.c')
-rw-r--r-- | sys/dev/usb/uhub.c | 45 |
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; |