diff options
author | aiju <devnull@localhost> | 2018-03-06 17:18:48 +0000 |
---|---|---|
committer | aiju <devnull@localhost> | 2018-03-06 17:18:48 +0000 |
commit | 9226caf2a3bf88258665f4e3786c6abb8820d308 (patch) | |
tree | b4746f9fde85eeffc8457c8c55d0406e52060f7d /sys | |
parent | 097879eace30b438c8c20edd543f5752d0eec07b (diff) |
usbehci: add uframes control request to return uframes one at a time
Diffstat (limited to 'sys')
-rw-r--r-- | sys/man/3/usb | 7 | ||||
-rw-r--r-- | sys/src/9/port/devusb.c | 18 | ||||
-rw-r--r-- | sys/src/9/port/usb.h | 1 | ||||
-rw-r--r-- | sys/src/9/port/usbehci.c | 89 |
4 files changed, 82 insertions, 33 deletions
diff --git a/sys/man/3/usb b/sys/man/3/usb index 5cf446293..ba476c002 100644 --- a/sys/man/3/usb +++ b/sys/man/3/usb @@ -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 diff --git a/sys/src/9/port/devusb.c b/sys/src/9/port/devusb.c index 362d40ca9..87c246e45 100644 --- a/sys/src/9/port/devusb.c +++ b/sys/src/9/port/devusb.c @@ -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]); diff --git a/sys/src/9/port/usb.h b/sys/src/9/port/usb.h index 25258f318..e16121b99 100644 --- a/sys/src/9/port/usb.h +++ b/sys/src/9/port/usb.h @@ -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 */ }; /* diff --git a/sys/src/9/port/usbehci.c b/sys/src/9/port/usbehci.c index c8deead4c..a8120a516 100644 --- a/sys/src/9/port/usbehci.c +++ b/sys/src/9/port/usbehci.c @@ -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 */ |