From f22c1463c7cd47cceebc5771563a54cd1963f8ba Mon Sep 17 00:00:00 2001 From: mpi Date: Wed, 15 Jan 2014 11:10:40 +0000 Subject: [PATCH] Remove a hack to update the address and packet length for every device request and instead re-open the default pipe with updated values when attaching a new device, adapted from FreeBSD r162977. This fixes a problem where the controller could have cached the previous values and would fail to get the device descriptor, leaving the device unrecognized with a message like: "device problem, disabling port n". --- sys/dev/usb/ehci.c | 16 ++-------------- sys/dev/usb/ohci.c | 14 ++------------ sys/dev/usb/usb_subr.c | 21 +++++++++++++++++++-- 3 files changed, 23 insertions(+), 28 deletions(-) diff --git a/sys/dev/usb/ehci.c b/sys/dev/usb/ehci.c index 68809c35efb..ed6dcb24069 100644 --- a/sys/dev/usb/ehci.c +++ b/sys/dev/usb/ehci.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ehci.c,v 1.139 2013/12/06 21:03:04 deraadt Exp $ */ +/* $OpenBSD: ehci.c,v 1.140 2014/01/15 11:10:40 mpi Exp $ */ /* $NetBSD: ehci.c,v 1.66 2004/06/30 03:11:56 mycroft Exp $ */ /* @@ -3052,7 +3052,6 @@ ehci_device_request(struct usbd_xfer *xfer) usb_device_request_t *req = &xfer->request; struct usbd_device *dev = epipe->pipe.device; struct ehci_softc *sc = (struct ehci_softc *)dev->bus; - int addr = dev->address; struct ehci_soft_qtd *setup, *stat, *next; struct ehci_soft_qh *sqh; int isread; @@ -3066,7 +3065,7 @@ ehci_device_request(struct usbd_xfer *xfer) DPRINTFN(3,("ehci_device_request: type=0x%02x, request=0x%02x, " "wValue=0x%04x, wIndex=0x%04x len=%u, addr=%d, endpt=%d\n", req->bmRequestType, req->bRequest, UGETW(req->wValue), - UGETW(req->wIndex), len, addr, + UGETW(req->wIndex), len, dev->address, epipe->pipe.endpoint->edesc->bEndpointAddress)); setup = ehci_alloc_sqtd(sc); @@ -3083,17 +3082,6 @@ ehci_device_request(struct usbd_xfer *xfer) sqh = epipe->sqh; epipe->u.ctl.length = len; - /* Update device address and length since they may have changed - during the setup of the control pipe in usbd_new_device(). */ - /* XXX This only needs to be done once, but it's too early in open. */ - /* XXXX Should not touch ED here! */ - sqh->qh.qh_endp = - (sqh->qh.qh_endp & htole32(~(EHCI_QH_ADDRMASK | EHCI_QH_MPLMASK))) | - htole32( - EHCI_QH_SET_ADDR(addr) | - EHCI_QH_SET_MPL(UGETW(epipe->pipe.endpoint->edesc->wMaxPacketSize)) - ); - /* Set up data transaction */ if (len != 0) { struct ehci_soft_qtd *end; diff --git a/sys/dev/usb/ohci.c b/sys/dev/usb/ohci.c index b76fb02ced6..29b7c30adb9 100644 --- a/sys/dev/usb/ohci.c +++ b/sys/dev/usb/ohci.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ohci.c,v 1.118 2013/12/09 01:02:06 brad Exp $ */ +/* $OpenBSD: ohci.c,v 1.119 2014/01/15 11:10:40 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 $ */ @@ -1607,7 +1607,6 @@ ohci_device_request(struct usbd_xfer *xfer) usb_device_request_t *req = &xfer->request; struct usbd_device *dev = opipe->pipe.device; struct ohci_softc *sc = (struct ohci_softc *)dev->bus; - int addr = dev->address; struct ohci_soft_td *setup, *stat, *next, *tail; struct ohci_soft_ed *sed; int isread; @@ -1621,7 +1620,7 @@ ohci_device_request(struct usbd_xfer *xfer) DPRINTFN(3,("ohci_device_control type=0x%02x, request=0x%02x, " "wValue=0x%04x, wIndex=0x%04x len=%u, addr=%d, endpt=%d\n", req->bmRequestType, req->bRequest, UGETW(req->wValue), - UGETW(req->wIndex), len, addr, + UGETW(req->wIndex), len, dev->address, opipe->pipe.endpoint->edesc->bEndpointAddress)); setup = opipe->tail.td; @@ -1640,15 +1639,6 @@ ohci_device_request(struct usbd_xfer *xfer) sed = opipe->sed; opipe->u.ctl.length = len; - /* Update device address and length since they may have changed - during the setup of the control pipe in usbd_new_device(). */ - /* XXX This only needs to be done once, but it's too early in open. */ - /* XXXX Should not touch ED here! */ - sed->ed.ed_flags = htole32( - (letoh32(sed->ed.ed_flags) & ~(OHCI_ED_ADDRMASK | OHCI_ED_MAXPMASK)) | - OHCI_ED_SET_FA(addr) | - OHCI_ED_SET_MAXP(UGETW(opipe->pipe.endpoint->edesc->wMaxPacketSize))); - next = stat; /* Set up data transaction */ diff --git a/sys/dev/usb/usb_subr.c b/sys/dev/usb/usb_subr.c index ad96f4e882d..b14092ce6df 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.95 2013/11/19 14:04:07 pirofti Exp $ */ +/* $OpenBSD: usb_subr.c,v 1.96 2014/01/15 11:10:40 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 $ */ @@ -1164,6 +1164,15 @@ 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_abort_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); + return (err); + } + err = usbd_reload_device_desc(dev); if (err) { DPRINTFN(-1, ("usbd_new_device: addr=%d, getting full desc " @@ -1187,9 +1196,17 @@ usbd_new_device(struct device *parent, struct usbd_bus *bus, int depth, dev->address = addr; /* New device address now */ bus->devices[addr] = dev; + /* Re-establish the default pipe with the new address. */ + usbd_abort_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); + return (err); + } + /* send disown request to handover 2.0 to 1.1. */ if (dev->quirks->uq_flags & UQ_EHCI_NEEDTO_DISOWN) { - /* only effective when the target device is on ehci */ if (dev->bus->usbrev == USBREV_2_0) { DPRINTF(("%s: disown request issues to dev:%p on usb2.0 bus\n", -- 2.20.1