ref: 9226caf2a3bf88258665f4e3786c6abb8820d308
parent: 097879eace30b438c8c20edd543f5752d0eec07b
author: aiju <devnull@localhost>
date: Tue Mar 6 12:18:48 EST 2018
usbehci: add uframes control request to return uframes one at a time
--- a/sys/man/3/usb
+++ b/sys/man/3/usb
@@ -398,6 +398,13 @@
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
--- a/sys/src/9/port/devusb.c
+++ b/sys/src/9/port/devusb.c
@@ -90,6 +90,7 @@
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 @@
{CMtmout, "timeout", 2},
{CMsampledelay, "sampledelay", 2},
{CMpreset, "reset", 1},
+ {CMuframes, "uframes", 2},
};
static Dirtab usbdir[] =
@@ -291,9 +293,11 @@
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 @@
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 @@
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);
@@ -1334,6 +1339,17 @@
qlock(ep);
ep->hz = l;
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:
--- a/sys/src/9/port/usb.h
+++ b/sys/src/9/port/usb.h
@@ -173,6 +173,7 @@
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 */
};
/*
--- a/sys/src/9/port/usbehci.c
+++ b/sys/src/9/port/usbehci.c
@@ -218,6 +218,7 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
* 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 @@
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 @@
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 @@
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 @@
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 @@
}
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 */