diff options
author | Martin Pieuchot <mpi@cvs.openbsd.org> | 2014-10-05 08:40:30 +0000 |
---|---|---|
committer | Martin Pieuchot <mpi@cvs.openbsd.org> | 2014-10-05 08:40:30 +0000 |
commit | bac9f1ab19a9cbc1a2d1b219787ea2d308a8f290 (patch) | |
tree | 84617ecae0533da1c4723547d218e566c0f06fa4 /sys/dev/usb | |
parent | 351118b943d7140258ed9034a10dc938a7a13926 (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.c | 39 | ||||
-rw-r--r-- | sys/dev/usb/ohci.c | 39 | ||||
-rw-r--r-- | sys/dev/usb/usb_subr.c | 28 |
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; |