summaryrefslogtreecommitdiff
path: root/sys/dev/usb
diff options
context:
space:
mode:
authorMartin Pieuchot <mpi@cvs.openbsd.org>2014-10-05 08:40:30 +0000
committerMartin Pieuchot <mpi@cvs.openbsd.org>2014-10-05 08:40:30 +0000
commitbac9f1ab19a9cbc1a2d1b219787ea2d308a8f290 (patch)
tree84617ecae0533da1c4723547d218e566c0f06fa4 /sys/dev/usb
parent351118b943d7140258ed9034a10dc938a7a13926 (diff)
Do not re-establish the default pipe twice for every controller. Move
this hack in the drivers that need it. Tested by many, thanks! ok pirofti@, kettenis@
Diffstat (limited to 'sys/dev/usb')
-rw-r--r--sys/dev/usb/ehci.c39
-rw-r--r--sys/dev/usb/ohci.c39
-rw-r--r--sys/dev/usb/usb_subr.c28
3 files changed, 78 insertions, 28 deletions
diff --git a/sys/dev/usb/ehci.c b/sys/dev/usb/ehci.c
index 35b9d6c6365..50f889326ea 100644
--- a/sys/dev/usb/ehci.c
+++ b/sys/dev/usb/ehci.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ehci.c,v 1.168 2014/09/01 08:13:02 mpi Exp $ */
+/* $OpenBSD: ehci.c,v 1.169 2014/10/05 08:40:29 mpi Exp $ */
/* $NetBSD: ehci.c,v 1.66 2004/06/30 03:11:56 mycroft Exp $ */
/*
@@ -99,6 +99,7 @@ struct ehci_pipe {
u_int8_t ehci_reverse_bits(u_int8_t, int);
usbd_status ehci_open(struct usbd_pipe *);
+int ehci_setaddr(struct usbd_device *, int);
void ehci_poll(struct usbd_bus *);
void ehci_softintr(void *);
int ehci_intr1(struct ehci_softc *);
@@ -215,7 +216,7 @@ void ehci_dump_exfer(struct ehci_xfer *);
struct usbd_bus_methods ehci_bus_methods = {
.open_pipe = ehci_open,
- .dev_setaddr = usbd_set_address,
+ .dev_setaddr = ehci_setaddr,
.soft_intr = ehci_softintr,
.do_poll = ehci_poll,
.allocx = ehci_allocx,
@@ -605,6 +606,40 @@ ehci_pcd(struct ehci_softc *sc, struct usbd_xfer *xfer)
usb_transfer_complete(xfer);
}
+/*
+ * Work around the half configured control (default) pipe when setting
+ * the address of a device.
+ *
+ * Because a single QH is setup per endpoint in ehci_open(), and the
+ * control pipe is configured before we could have set the address
+ * of the device or read the wMaxPacketSize of the endpoint, we have
+ * to re-open the pipe twice here.
+ */
+int
+ehci_setaddr(struct usbd_device *dev, int addr)
+{
+ /* Root Hub */
+ if (dev->depth == 0)
+ return (0);
+
+ /* Re-establish the default pipe with the new max packet size. */
+ ehci_close_pipe(dev->default_pipe);
+ if (ehci_open(dev->default_pipe))
+ return (EINVAL);
+
+ if (usbd_set_address(dev, addr))
+ return (1);
+
+ dev->address = addr;
+
+ /* Re-establish the default pipe with the new address. */
+ ehci_close_pipe(dev->default_pipe);
+ if (ehci_open(dev->default_pipe))
+ return (EINVAL);
+
+ return (0);
+}
+
void
ehci_softintr(void *v)
{
diff --git a/sys/dev/usb/ohci.c b/sys/dev/usb/ohci.c
index 76c7aebd60c..789aa62a83c 100644
--- a/sys/dev/usb/ohci.c
+++ b/sys/dev/usb/ohci.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ohci.c,v 1.139 2014/08/10 11:18:57 mpi Exp $ */
+/* $OpenBSD: ohci.c,v 1.140 2014/10/05 08:40:29 mpi Exp $ */
/* $NetBSD: ohci.c,v 1.139 2003/02/22 05:24:16 tsutsui Exp $ */
/* $FreeBSD: src/sys/dev/usb/ohci.c,v 1.22 1999/11/17 22:33:40 n_hibma Exp $ */
@@ -88,6 +88,7 @@ usbd_status ohci_alloc_std_chain(struct ohci_softc *, u_int,
struct ohci_soft_td **);
usbd_status ohci_open(struct usbd_pipe *);
+int ohci_setaddr(struct usbd_device *, int);
void ohci_poll(struct usbd_bus *);
void ohci_softintr(void *);
void ohci_waitintr(struct ohci_softc *, struct usbd_xfer *);
@@ -232,7 +233,7 @@ struct ohci_pipe {
struct usbd_bus_methods ohci_bus_methods = {
.open_pipe = ohci_open,
- .dev_setaddr = usbd_set_address,
+ .dev_setaddr = ohci_setaddr,
.soft_intr = ohci_softintr,
.do_poll = ohci_poll,
.allocx = ohci_allocx,
@@ -2006,6 +2007,40 @@ ohci_open(struct usbd_pipe *pipe)
}
/*
+ * Work around the half configured control (default) pipe when setting
+ * the address of a device.
+ *
+ * Because a single ED is setup per endpoint in ohci_open(), and the
+ * control pipe is configured before we could have set the address
+ * of the device or read the wMaxPacketSize of the endpoint, we have
+ * to re-open the pipe twice here.
+ */
+int
+ohci_setaddr(struct usbd_device *dev, int addr)
+{
+ /* Root Hub */
+ if (dev->depth == 0)
+ return (0);
+
+ /* Re-establish the default pipe with the new max packet size. */
+ ohci_device_ctrl_close(dev->default_pipe);
+ if (ohci_open(dev->default_pipe))
+ return (EINVAL);
+
+ if (usbd_set_address(dev, addr))
+ return (1);
+
+ dev->address = addr;
+
+ /* Re-establish the default pipe with the new address. */
+ ohci_device_ctrl_close(dev->default_pipe);
+ if (ohci_open(dev->default_pipe))
+ return (EINVAL);
+
+ return (0);
+}
+
+/*
* Close a reqular pipe.
* Assumes that there are no pending transactions.
*/
diff --git a/sys/dev/usb/usb_subr.c b/sys/dev/usb/usb_subr.c
index 34c65604af8..6c3531fad22 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.109 2014/10/01 08:29:01 mpi Exp $ */
+/* $OpenBSD: usb_subr.c,v 1.110 2014/10/05 08:40:29 mpi 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 $ */
@@ -901,8 +901,8 @@ usbd_probe_and_attach(struct device *parent, struct usbd_device *dev, int port,
"error=%s\n", parent->dv_xname, port,
addr, usbd_errstr(err)));
#else
- printf("%s: port %d, set config at addr %d failed\n",
- parent->dv_xname, port, addr);
+ printf("%s: port %d, set config %d at addr %d failed\n",
+ parent->dv_xname, port, confi, addr);
#endif
goto fail;
@@ -1160,23 +1160,6 @@ usbd_new_device(struct device *parent, struct usbd_bus *bus, int depth,
USETW(dev->def_ep_desc.wMaxPacketSize, dd->bMaxPacketSize);
- /* Re-establish the default pipe with the new max packet size. */
- usbd_close_pipe(dev->default_pipe);
- err = usbd_setup_pipe(dev, 0, &dev->def_ep, USBD_DEFAULT_INTERVAL,
- &dev->default_pipe);
- if (err) {
- usb_free_device(dev);
- up->device = NULL;
- return (err);
- }
-
- err = usbd_reload_device_desc(dev);
- if (err) {
- usb_free_device(dev);
- up->device = NULL;
- return (err);
- }
-
/* Set the address if the HC didn't do it already. */
if (bus->methods->dev_setaddr != NULL &&
bus->methods->dev_setaddr(dev, addr)) {
@@ -1192,10 +1175,7 @@ usbd_new_device(struct device *parent, struct usbd_bus *bus, int depth,
dev->address = addr;
bus->devices[addr] = dev;
- /* Re-establish the default pipe with the new address. */
- usbd_close_pipe(dev->default_pipe);
- err = usbd_setup_pipe(dev, 0, &dev->def_ep, USBD_DEFAULT_INTERVAL,
- &dev->default_pipe);
+ err = usbd_reload_device_desc(dev);
if (err) {
usb_free_device(dev);
up->device = NULL;