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.
This commit is contained in:
cinap_lenrek 2014-04-23 20:03:01 +02:00
parent 07bf5a24ab
commit 41908149de
7 changed files with 37 additions and 24 deletions

View file

@ -115,10 +115,10 @@ chansetup(Hostchan *hc, Ep *ep)
hcc = 0;
break;
default:
hcc = ep->dev->nb<<ODevaddr;
hcc = (ep->dev->nb&Devmax)<<ODevaddr;
break;
}
hcc |= ep->maxpkt | 1<<OMulticnt | ep->nb<<OEpnum;
hcc |= ep->maxpkt | 1<<OMulticnt | (ep->nb&Epmax)<<OEpnum;
switch(ep->ttype){
case Tctl:
hcc |= Epctl;

View file

@ -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;

View file

@ -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;

View file

@ -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 */

View file

@ -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)<<Itdepshift | (ep->dev->nb&Devmax)<<Itddevshift;
if(ep->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)

View file

@ -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;
}

View file

@ -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;