summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/dev/usb/ehci.c24
-rw-r--r--sys/dev/usb/uhub.c45
-rw-r--r--sys/dev/usb/usb_subr.c33
-rw-r--r--sys/dev/usb/usbdivar.h9
4 files changed, 92 insertions, 19 deletions
diff --git a/sys/dev/usb/ehci.c b/sys/dev/usb/ehci.c
index 349ca7a8fee..0e7e86a552b 100644
--- a/sys/dev/usb/ehci.c
+++ b/sys/dev/usb/ehci.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ehci.c,v 1.44 2005/03/13 02:32:57 pascoe Exp $ */
+/* $OpenBSD: ehci.c,v 1.45 2005/03/13 02:54:04 pascoe Exp $ */
/* $NetBSD: ehci.c,v 1.66 2004/06/30 03:11:56 mycroft Exp $ */
/*
@@ -1336,6 +1336,7 @@ ehci_open(usbd_pipe_handle pipe)
usbd_status err;
int s;
int ival, speed, naks;
+ int hshubaddr, hshubport;
DPRINTFN(1, ("ehci_open: pipe=%p, addr=%d, endpt=%d (%d)\n",
pipe, addr, ed->bEndpointAddress, sc->sc_addr));
@@ -1343,6 +1344,14 @@ ehci_open(usbd_pipe_handle pipe)
if (sc->sc_dying)
return (USBD_IOERROR);
+ if (dev->myhsport) {
+ hshubaddr = dev->myhsport->parent->address;
+ hshubport = dev->myhsport->portno;
+ } else {
+ hshubaddr = 0;
+ hshubport = 0;
+ }
+
epipe->nexttoggle = 0;
if (addr == sc->sc_addr) {
@@ -1366,6 +1375,15 @@ ehci_open(usbd_pipe_handle pipe)
case USB_SPEED_HIGH: speed = EHCI_QH_SPEED_HIGH; break;
default: panic("ehci_open: bad device speed %d", dev->speed);
}
+ if (speed != EHCI_QH_SPEED_HIGH && xfertype == UE_ISOCHRONOUS) {
+ printf("%s: *** WARNING: opening low/full speed isochronous "
+ "device, this does not work yet.\n",
+ USBDEVNAME(sc->sc_bus.bdev));
+ DPRINTFN(1,("ehci_open: hshubaddr=%d hshubport=%d\n",
+ hshubaddr, hshubport));
+ return (USBD_INVAL);
+ }
+
naks = 8; /* XXX */
sqh = ehci_alloc_sqh(sc);
if (sqh == NULL)
@@ -1383,7 +1401,9 @@ ehci_open(usbd_pipe_handle pipe)
);
sqh->qh.qh_endphub = htole32(
EHCI_QH_SET_MULT(1) |
- /* XXX TT stuff */
+ EHCI_QH_SET_HUBA(hshubaddr) |
+ EHCI_QH_SET_PORT(hshubport) |
+ EHCI_QH_SET_CMASK(0x1c) | /* XXX */
EHCI_QH_SET_SMASK(xfertype == UE_INTERRUPT ? 0x01 : 0)
);
sqh->qh.qh_curqtd = EHCI_NULL;
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;
diff --git a/sys/dev/usb/usb_subr.c b/sys/dev/usb/usb_subr.c
index dd66a79118e..9023bf131c5 100644
--- a/sys/dev/usb/usb_subr.c
+++ b/sys/dev/usb/usb_subr.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: usb_subr.c,v 1.32 2004/12/12 06:13:15 dlg Exp $ */
+/* $OpenBSD: usb_subr.c,v 1.33 2005/03/13 02:54:04 pascoe Exp $ */
/* $NetBSD: usb_subr.c,v 1.103 2003/01/10 11:19:13 augustss Exp $ */
/* $FreeBSD: src/sys/dev/usb/usb_subr.c,v 1.18 1999/11/17 22:33:47 n_hibma Exp $ */
@@ -991,12 +991,13 @@ usbd_status
usbd_new_device(device_ptr_t parent, usbd_bus_handle bus, int depth,
int speed, int port, struct usbd_port *up)
{
- usbd_device_handle dev;
+ usbd_device_handle dev, adev;
struct usbd_device *hub;
usb_device_descriptor_t *dd;
usbd_status err;
int addr;
int i;
+ int p;
DPRINTF(("usbd_new_device bus=%p port=%d depth=%d speed=%d\n",
bus, port, depth, speed));
@@ -1031,11 +1032,27 @@ usbd_new_device(device_ptr_t parent, usbd_bus_handle bus, int depth,
dev->depth = depth;
dev->powersrc = up;
dev->myhub = up->parent;
- for (hub = up->parent;
+
+ up->device = dev;
+
+ /* Locate port on upstream high speed hub */
+ for (adev = dev, hub = up->parent;
hub != NULL && hub->speed != USB_SPEED_HIGH;
- hub = hub->myhub)
+ adev = hub, hub = hub->myhub)
;
- dev->myhighhub = hub;
+ if (hub) {
+ for (p = 0; p < hub->hub->hubdesc.bNbrPorts; p++) {
+ if (hub->hub->ports[p].device == adev) {
+ dev->myhsport = &hub->hub->ports[p];
+ goto found;
+ }
+ }
+ panic("usbd_new_device: cannot find HS port\n");
+ found:
+ DPRINTFN(1,("usbd_new_device: high speed port %d\n", p));
+ } else {
+ dev->myhsport = NULL;
+ }
dev->speed = speed;
dev->langid = USBD_NOLANG;
dev->cookie.cookie = ++usb_cookie_no;
@@ -1048,7 +1065,6 @@ usbd_new_device(device_ptr_t parent, usbd_bus_handle bus, int depth,
return (err);
}
- up->device = dev;
dd = &dev->ddesc;
/* Try a few times in case the device is slow (i.e. outside specs.) */
for (i = 0; i < 5; i++) {
@@ -1163,8 +1179,8 @@ usbd_remove_device(usbd_device_handle dev, struct usbd_port *up)
if (dev->default_pipe != NULL)
usbd_kill_pipe(dev->default_pipe);
- up->device = 0;
- dev->bus->devices[dev->address] = 0;
+ up->device = NULL;
+ dev->bus->devices[dev->address] = NULL;
free(dev, M_USB);
}
@@ -1389,6 +1405,7 @@ usb_disconnect_port(struct usbd_port *up, device_ptr_t parent)
printf(" port %d", up->portno);
printf(" (addr %d) disconnected\n", dev->address);
config_detach(dev->subdevs[i], DETACH_FORCE);
+ dev->subdevs[i] = 0;
}
}
diff --git a/sys/dev/usb/usbdivar.h b/sys/dev/usb/usbdivar.h
index ed0ca70b983..78136b3462d 100644
--- a/sys/dev/usb/usbdivar.h
+++ b/sys/dev/usb/usbdivar.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: usbdivar.h,v 1.22 2004/12/12 05:21:14 dlg Exp $ */
+/* $OpenBSD: usbdivar.h,v 1.23 2005/03/13 02:54:04 pascoe 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 $ */
@@ -74,6 +74,10 @@ struct usbd_pipe_methods {
void (*done)(usbd_xfer_handle xfer);
};
+struct usbd_tt {
+ struct usbd_hub *hub;
+};
+
struct usbd_port {
usb_port_status_t status;
u_int16_t power; /* mA of current on port */
@@ -83,6 +87,7 @@ struct usbd_port {
u_int8_t reattach;
struct usbd_device *device; /* Connected device */
struct usbd_device *parent; /* The ports hub */
+ struct usbd_tt *tt; /* Transaction translator (if any) */
};
struct usbd_hub {
@@ -145,7 +150,7 @@ struct usbd_device {
usb_event_cookie_t cookie; /* unique connection id */
struct usbd_port *powersrc; /* upstream hub port, or 0 */
struct usbd_device *myhub; /* upstream hub */
- struct usbd_device *myhighhub; /* closest high speed hub */
+ struct usbd_port *myhsport; /* closest high speed port */
struct usbd_endpoint def_ep; /* for pipe 0 */
usb_endpoint_descriptor_t def_ep_desc; /* for pipe 0 */
struct usbd_interface *ifaces; /* array of all interfaces */