From 41908149de00ab5830c5c72ef3a300a050b2b3bf Mon Sep 17 00:00:00 2001 From: cinap_lenrek Date: Wed, 23 Apr 2014 20:03:01 +0200 Subject: [PATCH] nusb: resolve endpoint id conflict with different input and output types ftrvxmtrx repots devices that use the endpoint number for input and output of different types like: nusb/ether: parsedesc endpoint 5[7] 07 05 81 03 08 00 09 # ep1 in intr nusb/ether: parsedesc endpoint 5[7] 07 05 82 02 00 02 00 nusb/ether: parsedesc endpoint 5[7] 07 05 01 02 00 02 00 # ep1 out bulk the previous change tried to work arround this but had the concequence that only the lastly defined endpoint was usable. this change addresses the issue by allowing up to 32 endpoints per device (16 output + 16 input endpoints) in devusb. the hci driver will ignore the 4th bit and will only use the lower 4 bits as endpoint address when talking to the usb device. when we encounter a conflict, we map the input endpoint to the upper id range 16..31 and the output endpoint to id 0..15 so two distinct endpoints are created. --- sys/src/9/bcm/usbdwc.c | 4 ++-- sys/src/9/pc/usbohci.c | 6 +++--- sys/src/9/pc/usbuhci.c | 2 +- sys/src/9/port/usb.h | 2 +- sys/src/9/port/usbehci.c | 12 ++++++------ sys/src/cmd/nusb/lib/dev.c | 2 +- sys/src/cmd/nusb/lib/parse.c | 33 +++++++++++++++++++++++---------- 7 files changed, 37 insertions(+), 24 deletions(-) diff --git a/sys/src/9/bcm/usbdwc.c b/sys/src/9/bcm/usbdwc.c index 652b2ceea..a7292ba5f 100644 --- a/sys/src/9/bcm/usbdwc.c +++ b/sys/src/9/bcm/usbdwc.c @@ -115,10 +115,10 @@ chansetup(Hostchan *hc, Ep *ep) hcc = 0; break; default: - hcc = ep->dev->nb<dev->nb&Devmax)<maxpkt | 1<nb<maxpkt | 1<nb&Epmax)<ttype){ case Tctl: hcc |= Epctl; diff --git a/sys/src/9/pc/usbohci.c b/sys/src/9/pc/usbohci.c index d1068378d..fed5a0f2c 100644 --- a/sys/src/9/pc/usbohci.c +++ b/sys/src/9/pc/usbohci.c @@ -1719,7 +1719,7 @@ epctlio(Ep *ep, Ctlio *cio, void *a, long count) /* set the address if unset and out of configuration state */ if(ep->dev->state != Dconfig && ep->dev->state != Dreset) if(cio->usbid == 0){ - cio->usbid = (ep->nb<<7)|(ep->dev->nb & Devmax); + cio->usbid = (ep->nb&Epmax)<<7 | (ep->dev->nb&Devmax); edsetaddr(cio->ed, cio->usbid); } /* adjust maxpkt if the user has learned a different one */ @@ -1986,7 +1986,7 @@ isoopen(Ctlr *ctlr, Ep *ep) int i; iso = ep->aux; - iso->usbid = (ep->nb<<7)|(ep->dev->nb & Devmax); + iso->usbid = (ep->nb&Epmax)<<7 | (ep->dev->nb&Devmax); iso->bw = ep->hz * ep->samplesz; /* bytes/sec */ if(ep->mode != OWRITE){ print("ohci: bug: iso input streams not implemented\n"); @@ -2067,7 +2067,7 @@ epopen(Ep *ep) case Tintr: io = ep->aux = smalloc(sizeof(Qio)*2); io[OREAD].debug = io[OWRITE].debug = ep->debug; - usbid = (ep->nb<<7)|(ep->dev->nb & Devmax); + usbid = (ep->nb&Epmax)<<7 | (ep->dev->nb&Devmax); if(ep->mode != OREAD){ if(ep->toggle[OWRITE] != 0) io[OWRITE].toggle = Tddata1; diff --git a/sys/src/9/pc/usbuhci.c b/sys/src/9/pc/usbuhci.c index 986a91c9e..8b5d54b75 100644 --- a/sys/src/9/pc/usbuhci.c +++ b/sys/src/9/pc/usbuhci.c @@ -1791,7 +1791,7 @@ epopen(Ep *ep) case Tintr: io = ep->aux = smalloc(sizeof(Qio)*2); io[OREAD].debug = io[OWRITE].debug = ep->debug; - usbid = ((ep->nb&Epmax)<<7)|(ep->dev->nb &Devmax); + usbid = ((ep->nb&Epmax)<<7)|(ep->dev->nb&Devmax); if(ep->mode != OREAD){ if(ep->toggle[OWRITE] != 0) io[OWRITE].toggle = Tddata1; diff --git a/sys/src/9/port/usb.h b/sys/src/9/port/usb.h index 5758bdd20..8ee5e5138 100644 --- a/sys/src/9/port/usb.h +++ b/sys/src/9/port/usb.h @@ -17,7 +17,7 @@ typedef struct Hciimpl Hciimpl; /* Link to the controller impl. */ enum { /* fundamental constants */ - Ndeveps = 16, /* max nb. of endpoints per device */ + Ndeveps = 32, /* max nb. of endpoints per device (16 in + 16 out) */ /* tunable parameters */ Nhcis = 16, /* max nb. of HCIs */ diff --git a/sys/src/9/port/usbehci.c b/sys/src/9/port/usbehci.c index 45b48145a..2db838780 100644 --- a/sys/src/9/port/usbehci.c +++ b/sys/src/9/port/usbehci.c @@ -2578,7 +2578,7 @@ epctlio(Ep *ep, Ctlio *cio, void *a, long count) /* set the address if unset and out of configuration state */ if(ep->dev->state != Dconfig && ep->dev->state != Dreset) if(cio->usbid == 0){ - cio->usbid = (ep->nb&Epmax) << 7 | ep->dev->nb&Devmax; + cio->usbid = (ep->nb&Epmax)<<7 | (ep->dev->nb&Devmax); coherence(); qhsetaddr(cio->qh, cio->usbid); } @@ -2688,8 +2688,8 @@ isofsinit(Ep *ep, Isoio *iso) td->data = iso->data + i * ep->maxpkt; td->epc = ep->dev->port << Stdportshift; td->epc |= ep->dev->hub << Stdhubshift; - td->epc |= ep->nb << Stdepshift; - td->epc |= ep->dev->nb << Stddevshift; + td->epc |= (ep->nb&Epmax) << Stdepshift; + td->epc |= (ep->dev->nb&Devmax) << Stddevshift; td->mfs = 034 << Stdscmshift | 1 << Stdssmshift; if(ep->mode == OREAD){ td->epc |= Stdin; @@ -2743,7 +2743,7 @@ isohsinit(Ep *ep, Isoio *iso) td->buffer[p] = pa; pa += 0x1000; } - td->buffer[0] |= ep->nb << Itdepshift | ep->dev->nb << Itddevshift; + td->buffer[0] |= (ep->nb&Epmax)<dev->nb&Devmax)<mode == OREAD) td->buffer[1] |= Itdin; else @@ -2789,7 +2789,7 @@ isoopen(Ctlr *ctlr, Ep *ep) default: error("iso i/o is half-duplex"); } - iso->usbid = ep->nb << 7 | ep->dev->nb & Devmax; + iso->usbid = (ep->nb&Epmax)<<7 | (ep->dev->nb&Devmax); iso->state = Qidle; coherence(); iso->debug = ep->debug; @@ -2926,7 +2926,7 @@ epopen(Ep *ep) case Tintr: io = ep->aux = smalloc(sizeof(Qio)*2); io[OREAD].debug = io[OWRITE].debug = ep->debug; - usbid = (ep->nb&Epmax) << 7 | ep->dev->nb &Devmax; + usbid = (ep->nb&Epmax)<<7 | (ep->dev->nb&Devmax); assert(ep->pollival != 0); if(ep->mode != OREAD){ if(ep->toggle[OWRITE] != 0) diff --git a/sys/src/cmd/nusb/lib/dev.c b/sys/src/cmd/nusb/lib/dev.c index 8f8a64277..60d327e87 100644 --- a/sys/src/cmd/nusb/lib/dev.c +++ b/sys/src/cmd/nusb/lib/dev.c @@ -481,7 +481,7 @@ unstall(Dev *dev, Dev *ep, int dir) else dir = 0; r = Rh2d|Rstd|Rep; - if(usbcmd(dev, r, Rclearfeature, Fhalt, ep->id|dir, nil, 0)<0){ + if(usbcmd(dev, r, Rclearfeature, Fhalt, (ep->id&0xF)|dir, nil, 0)<0){ werrstr("unstall: %s: %r", ep->dir); return -1; } diff --git a/sys/src/cmd/nusb/lib/parse.c b/sys/src/cmd/nusb/lib/parse.c index cf942ed7c..d9c61f2b9 100644 --- a/sys/src/cmd/nusb/lib/parse.c +++ b/sys/src/cmd/nusb/lib/parse.c @@ -96,7 +96,7 @@ extern Ep* mkep(Usbdev *, int); static int parseendpt(Usbdev *d, Conf *c, Iface *ip, Altc *altc, uchar *b, int n, Ep **epp) { - int i, dir, epid, type; + int i, dir, epid, type, addr; Ep *ep; DEp *dep; @@ -109,25 +109,38 @@ parseendpt(Usbdev *d, Conf *c, Iface *ip, Altc *altc, uchar *b, int n, Ep **epp) altc->attrib = dep->bmAttributes; /* here? */ altc->interval = dep->bInterval; - epid = dep->bEndpointAddress & 0xF; - assert(epid < nelem(d->ep)); - if(dep->bEndpointAddress & 0x80) + type = dep->bmAttributes & 0x03; + addr = dep->bEndpointAddress; + if(addr & 0x80) dir = Ein; else dir = Eout; - type = dep->bmAttributes & 0x03; + epid = addr & 0xF; /* default map to 0..15 */ + assert(epid < nelem(d->ep)); ep = d->ep[epid]; if(ep == nil){ ep = mkep(d, epid); ep->dir = dir; - }else if((ep->addr & 0x80) != (dep->bEndpointAddress & 0x80) && ep->type == type) - ep->dir = Eboth; - else - ep->dir = dir; + }else if((ep->addr & 0x80) != (addr & 0x80)){ + if(ep->type == type) + ep->dir = Eboth; + else { + /* + * resolve conflict when same endpoint number + * is used for different input and output types. + * map input endpoint to 16..31 and output to 0..15. + */ + ep->id = ((ep->addr & 0x80) != 0)<<4 | (ep->addr & 0xF); + d->ep[ep->id] = ep; + epid = ep->id ^ 0x10; + ep = mkep(d, epid); + ep->dir = dir; + } + } ep->maxpkt = GET2(dep->wMaxPacketSize); ep->ntds = 1 + ((ep->maxpkt >> 11) & 3); ep->maxpkt &= 0x7FF; - ep->addr = dep->bEndpointAddress; + ep->addr = addr; ep->type = type; ep->isotype = (dep->bmAttributes>>2) & 0x03; ep->conf = c;