usbehci: add uframes control request to return uframes one at a time

front
aiju 2018-03-06 17:18:48 +00:00
parent 097879eace
commit 9226caf2a3
4 changed files with 82 additions and 33 deletions

View File

@ -398,6 +398,13 @@ Use
as the number of transactions per frame (or µframe), as reported
by the descriptor.
.TP
.BI uframes " n"
If
.I n
is set to 1 for an isochronous endpoint,
.IR read(2)
from the data file will not cross μframe boundaries.
.TP
.B clrhalt
Clear the halt condition for an endpoint.
Used to recover from a stall caused by a device to signal its driver

View File

@ -90,6 +90,7 @@ enum
CMtmout, /* timeout n (activate timeouts for ep) */
CMsampledelay, /* maximum delay introduced by buffering (iso) */
CMpreset, /* reset the port */
CMuframes, /* set uframe mode (iso) */
/* Hub feature selectors */
Rportenable = 1,
@ -135,6 +136,7 @@ static Cmdtab epctls[] =
{CMtmout, "timeout", 2},
{CMsampledelay, "sampledelay", 2},
{CMpreset, "reset", 1},
{CMuframes, "uframes", 2},
};
static Dirtab usbdir[] =
@ -291,9 +293,11 @@ seprintep(char *s, char *se, Ep *ep, int all)
s = seprint(s, se, " %s", usbmodename[ep->mode]);
s = seprint(s, se, " speed %s", spname[d->speed]);
s = seprint(s, se, " maxpkt %ld", ep->maxpkt);
s = seprint(s, se, " ntds %ld", ep->ntds);
s = seprint(s, se, " pollival %ld", ep->pollival);
s = seprint(s, se, " samplesz %ld", ep->samplesz);
s = seprint(s, se, " hz %ld", ep->hz);
s = seprint(s, se, " uframes %ld", ep->uframes);
s = seprint(s, se, " hub %d", ep->dev->hub);
s = seprint(s, se, " port %d", ep->dev->port);
s = seprint(s, se, " rootport %d", ep->dev->rootport);
@ -352,7 +356,7 @@ epalloc(Hci *hp)
ep->hp = hp;
ep->maxpkt = 8;
ep->ntds = 1;
ep->samplesz = ep->pollival = ep->hz = 0; /* make them void */
ep->uframes = ep->samplesz = ep->pollival = ep->hz = 0; /* make them void */
qunlock(&epslck);
return ep;
}
@ -523,6 +527,7 @@ newdevep(Ep *ep, int i, int tt, int mode)
nep->pollival = 10;
nep->samplesz = 4;
nep->hz = 44100;
nep->uframes = 0;
break;
}
deprint("newdevep ep%d.%d %#p\n", d->nb, nep->nb, nep);
@ -1336,6 +1341,17 @@ epctl(Ep *ep, Chan *c, void *a, long n)
setmaxpkt(ep, "hz");
qunlock(ep);
break;
case CMuframes:
if(ep->ttype != Tiso)
error("not an iso endpoint");
l = strtoul(cb->f[1], nil, 0);
deprint("usb uframes %s %d\n", cb->f[0], l);
if(l != 0 && l != 1)
error("uframes not in [0:1]");
qlock(ep);
ep->uframes = l;
qunlock(ep);
break;
case CMclrhalt:
qlock(ep);
deprint("usb epctl %s\n", cb->f[0]);

View File

@ -173,6 +173,7 @@ struct Ep
int ntds; /* nb. of Tds per µframe */
int tmout; /* 0 or timeout for transfers (ms) */
int sampledelay; /* maximum delay introduced by buffering (iso) */
int uframes; /* uframes mode (iso); 0 = normal behaviour, 1 = return only one uframe per read */
};
/*

View File

@ -218,6 +218,7 @@ struct Isoio
int hs; /* is high speed? */
Isoio* next; /* in list of active Isoios */
int ival; /* ep->pollival (/8 for HS) */
int uframes; /* ep->uframes */
ulong td0frno; /* first frame used in ctlr */
union{
Itd* tdi; /* next td processed by interrupt */
@ -267,6 +268,7 @@ struct Itd
Itd* next;
ulong ndata; /* number of bytes in data */
ulong mdata; /* max number of bytes in data */
ushort posi, posp;
uchar* data;
};
@ -844,8 +846,8 @@ seprintitd(char *s, char *se, Itd *td)
s = seprint(s, se, "itd %#p", td);
rw = (b1 & Itdin) ? "in" : "out";
s = seprint(s, se, " %s ep %uld dev %uld max %uld mult %uld",
rw, (b0>>8)&Epmax, (b0&Devmax), b1 & 0x7ff, b2 & 3);
s = seprint(s, se, " %s ep %uld dev %uld max %uld mult %uld mdata %uld pos (%ud,%ud)",
rw, (b0>>8)&Epmax, (b0&Devmax), b1 & 0x7ff, b2 & 3, td->mdata, td->posi, td->posp);
s = seprintlink(s, se, " link", td->link, 1);
s = seprint(s, se, "\n");
for(i = 0; i < nelem(td->csw); i++){
@ -1072,17 +1074,21 @@ isodump(Isoio* iso, int all)
if(iso->hs){
tdi = iso->tdi;
seprintitd(buf, buf+sizeof(buf), tdi);
print("\ttdi %s\n", buf);
print("\ttdi ");
putstrn(buf, strlen(buf));
tdu = iso->tdu;
seprintitd(buf, buf+sizeof(buf), tdu);
print("\ttdu %s\n", buf);
print("\ttdu ");
putstrn(buf, strlen(buf));
}else{
stdi = iso->stdi;
seprintsitd(buf, buf+sizeof(buf), stdi);
print("\tstdi %s\n", buf);
print("\tstdi ");
putstrn(buf, strlen(buf));
stdu = iso->stdu;
seprintsitd(buf, buf+sizeof(buf), stdu);
print("\tstdu %s\n", buf);
print("\tstdu ");
putstrn(buf, strlen(buf));
}
else
for(i = 0; i < Nisoframes; i++)
@ -1094,7 +1100,8 @@ isodump(Isoio* iso, int all)
print("i->");
if(td == iso->tdu)
print("i->");
print("[%d]\t%s", i, buf);
print("[%d]\t", i);
putstrn(buf, strlen(buf));
}else{
std = iso->sitdps[i];
seprintsitd(buf, buf+sizeof(buf), std);
@ -1102,7 +1109,8 @@ isodump(Isoio* iso, int all)
print("i->");
if(std == iso->stdu)
print("u->");
print("[%d]\t%s", i, buf);
print("[%d]\t", i);
putstrn(buf, strlen(buf));
}
}
@ -1247,6 +1255,7 @@ itdinit(Ctlr *ctlr, Isoio *iso, Itd *td)
* Also, all samples are packed early on each frame.
*/
size = td->ndata = td->mdata;
td->posi = td->posp = 0;
if(ctlr->dmaflush != nil)
(*ctlr->dmaflush)(1, td->data, size);
pa = PADDR(td->data);
@ -1270,6 +1279,11 @@ itdinit(Ctlr *ctlr, Isoio *iso, Itd *td)
size -= tsize;
pa += tsize;
}
if(iso->debug >= 3){
char buf[1024];
seprintitd(buf, buf + sizeof(buf), td);
putstrn(buf, strlen(buf));
}
coherence();
}
@ -1344,7 +1358,7 @@ isodelay(void *a)
static int
isohsinterrupt(Ctlr *ctlr, Isoio *iso)
{
int err, len, i, nframes, t;
int err, i, nframes, t;
Itd *tdi;
tdi = iso->tdi;
@ -1364,18 +1378,13 @@ isohsinterrupt(Ctlr *ctlr, Isoio *iso)
for(i = 0; i < nframes && itdactive(tdi) == 0; i++){
err = 0;
len = 0;
for(t = 0; t < nelem(tdi->csw); t++){
tdi->csw[t] &= ~Itdioc;
coherence();
err |= tdi->csw[t] & Itderrors;
if(err == 0 && iso->tok == Tdtokin)
len += (tdi->csw[t] >> Itdlenshift) & Itdlenmask;
}
if(err == 0) {
iso->nerrs = 0;
if(iso->tok == Tdtokin)
tdi->ndata = len;
} else if(iso->nerrs++ > iso->nframes/2){
if(iso->err == nil){
iso->err = ierrmsg(err);
@ -1875,31 +1884,46 @@ xdump(char* pref, void *qh)
static long
isohscpy(Ctlr *ctlr, Isoio* iso, uchar *b, long count)
{
int nr;
int len, nr;
long tot;
Itd *tdu;
uchar *dp;
for(tot = 0; iso->tdi != iso->tdu && tot < count; tot += nr){
ddiprint("hscpy: tdi %p tdu %p\n", iso->tdi, iso->tdu);
for(tot = 0; iso->tdi != iso->tdu && tot < count; ){
loop:
tdu = iso->tdu;
if(itdactive(tdu))
break;
nr = tdu->ndata;
if(tot + nr > count)
nr = count - tot;
if(nr > 0){
iunlock(ctlr); /* We could page fault here */
if(ctlr->dmaflush != nil)
(*ctlr->dmaflush)(0, tdu->data, tdu->mdata);
memmove(b+tot, tdu->data, nr);
ilock(ctlr);
if(iso->tdu != tdu)
continue;
if(nr < tdu->ndata)
memmove(tdu->data, tdu->data+nr, tdu->ndata - nr);
tdu->ndata -= nr;
coherence();
while(tdu->posi < 8 && tot < count){
len = tdu->csw[tdu->posi] >> Itdlenshift & Itdlenmask;
if((tdu->csw[tdu->posi] & Itderrors) != 0 || tdu->posp > len)
tdu->posp = len;
nr = len - tdu->posp;
if(nr > count - tot) nr = count - tot;
ddiprint("hscpy: tdi %p tdu %p posi %d posp %d len %d nr %d\n", iso->tdi, iso->tdu, tdu->posi, tdu->posp, len, nr);
dp = tdu->data + tdu->posi * iso->maxsize + tdu->posp;
if(nr > 0){
iunlock(ctlr);
if(ctlr->dmaflush != nil)
(*ctlr->dmaflush)(0, dp, nr);
memmove(b+tot, dp, nr);
ilock(ctlr);
if(iso->tdu != tdu || dp != tdu->data + tdu->posi * iso->maxsize + tdu->posp)
goto loop;
tot += nr;
tdu->posp += nr;
if(iso->uframes == 1)
count = tot;
coherence();
}
if(tdu->posp == len){
tdu->posp = 0;
tdu->posi++;
coherence();
}
}
if(tdu->ndata == 0){
if(tdu->posi == 8){
itdinit(ctlr, iso, tdu);
iso->tdu = tdu->next;
}
@ -2793,6 +2817,7 @@ isoopen(Ctlr *ctlr, Ep *ep)
}
if(iso->ival < 1)
error("bad pollival");
iso->uframes = ep->uframes;
iso->nframes = Nisoframes / iso->ival;
if(iso->nframes < 3)
error("ehci isoopen bug"); /* we need at least 3 tds */