diff options
author | cinap_lenrek <cinap_lenrek@felloff.net> | 2014-04-23 20:03:01 +0200 |
---|---|---|
committer | cinap_lenrek <cinap_lenrek@felloff.net> | 2014-04-23 20:03:01 +0200 |
commit | 41908149de00ab5830c5c72ef3a300a050b2b3bf (patch) | |
tree | 21e8c4f1697b73705a50cf35f2cda257ec47acb2 /sys/src/cmd | |
parent | 07bf5a24ab5b702f8b4ee89fb501204aaaa5b17b (diff) |
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.
Diffstat (limited to 'sys/src/cmd')
-rw-r--r-- | sys/src/cmd/nusb/lib/dev.c | 2 | ||||
-rw-r--r-- | sys/src/cmd/nusb/lib/parse.c | 33 |
2 files changed, 24 insertions, 11 deletions
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; |