summaryrefslogtreecommitdiff
path: root/sys/src/cmd
diff options
context:
space:
mode:
authorcinap_lenrek <cinap_lenrek@felloff.net>2014-04-23 20:03:01 +0200
committercinap_lenrek <cinap_lenrek@felloff.net>2014-04-23 20:03:01 +0200
commit41908149de00ab5830c5c72ef3a300a050b2b3bf (patch)
tree21e8c4f1697b73705a50cf35f2cda257ec47acb2 /sys/src/cmd
parent07bf5a24ab5b702f8b4ee89fb501204aaaa5b17b (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.c2
-rw-r--r--sys/src/cmd/nusb/lib/parse.c33
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;