ref: aaf6d7c5586d442c0bc10ed50558b984faeb51aa
parent: a397bfd48c9b0f2f0d335752cb52f286afcf1ad7
author: cinap_lenrek <[email protected]>
date: Mon Jul 24 19:48:50 EDT 2017
usbxhci: basic iso write support (usb soundcard playback)
--- a/sys/src/9/pc/usbxhci.c
+++ b/sys/src/9/pc/usbxhci.c
@@ -213,6 +213,8 @@
Ring er[1]; /* event ring segment */
Ring cr[1]; /* command ring segment */
+ u32int mfwrap;
+
QLock slotlock;
Slot **slot; /* slots by slot id */
@@ -232,8 +234,15 @@
struct Epio
{
QLock;
- Block *cb;
+
Ring *ring;
+ Block *b;
+
+ /* iso */
+ int nleft;
+ u32int frame;
+ u32int incr;
+ u32int tdsz;
};
static char Ebadlen[] = "bad usb request length";
@@ -252,6 +261,18 @@
*((u64int*)reg) = pa;
}
+static u32int
+mfindex(Ctlr *ctlr)
+{
+ u32int lo, hi;
+
+ do {
+ hi = ctlr->mfwrap;
+ lo = ctlr->rts[MFINDEX];
+ } while(hi != ctlr->mfwrap);
+ return (lo & (1<<14)-1) | hi<<14;
+}
+
static void
freering(Ring *r)
{
@@ -370,7 +391,9 @@
irs[IMOD] = 0;
}
- ctlr->opr[USBCMD] = RUNSTOP|INTE|HSEE;
+ ctlr->mfwrap = 0;
+
+ ctlr->opr[USBCMD] = RUNSTOP|INTE|HSEE|EWE;
while(ctlr->opr[USBSTS] & (CNR|HCH))
tsleep(&up->sleep, return0, nil, 10);
}
@@ -512,16 +535,18 @@
completering(Ring *r, u32int *er)
{
Wait *w, **wp;
- u32int *td;
+ u32int *td, x;
u64int pa;
pa = (*(u64int*)er) & ~15ULL;
ilock(r);
- while((int)(r->wp - r->rp) > 0){
- td = &r->base[4*(r->rp++ & r->mask)];
- if((u64int)PADDR(td) == pa)
+ for(x = r->rp; (int)(r->wp - x) > 0; x++){
+ td = &r->base[4*(x++ & r->mask)];
+ if((u64int)PADDR(td) == pa){
+ r->rp = x;
break;
+ }
}
wp = &r->pending;
@@ -564,9 +589,6 @@
if((((x>>ring->shift)^td[3])&1) == 0)
break;
- if(0) iprint("xhci interrupt: event %ud: %ux %ux %ux %ux\n",
- x, td[0], td[1], td[2], td[3]);
-
switch(td[3] & 0xFC00){
case ER_CMDCOMPL:
completering(ctlr->cr, td);
@@ -580,16 +602,21 @@
break;
completering(&slot->epr[(td[3]>>16)-1&31], td);
break;
+ case ER_MFINDEXWRAP:
+ ctlr->mfwrap++;
+ break;
case ER_HCE:
- iprint("xhci: host controller error: %ux %ux %ux %ux\n", td[0], td[1], td[2], td[3]);
+ iprint("xhci: host controller error: %ux %ux %ux %ux\n",
+ td[0], td[1], td[2], td[3]);
break;
case ER_PORTSC:
+ break;
case ER_BWREQ:
case ER_DOORBELL:
case ER_DEVNOTE:
- case ER_MFINDEXWRAP:
default:
- break;
+ iprint("xhci: event %ud: %ux %ux %ux %ux\n",
+ x, td[0], td[1], td[2], td[3]);
}
}
@@ -679,6 +706,7 @@
{
Ctlr *ctlr;
Slot *slot;
+ Ring *ring;
Epio *io;
if(ep->dev->isroot)
@@ -699,15 +727,17 @@
w = slot->ibase;
memset(w, 0, 32<<ctlr->csz);
w[1] = 1;
- if(io[OREAD].ring != nil){
- w[0] |= 1 << io[OREAD].ring->id;
- if(io[OREAD].ring->id == slot->nep)
+ if((ring = io[OREAD].ring) != nil){
+ w[0] |= 1 << ring->id;
+ if(ring->id == slot->nep)
slot->nep--;
+ ctlrcmd(ctlr, CR_STOPEP | (ring->id<<16) | (slot->id<<24), 0, 0, nil);
}
- if(io[OWRITE].ring != nil){
- w[0] |= 1 << io[OWRITE].ring->id;
- if(io[OWRITE].ring->id == slot->nep)
+ if((ring = io[OWRITE].ring) != nil){
+ w[0] |= 1 << ring->id;
+ if(ring->id == slot->nep)
slot->nep--;
+ ctlrcmd(ctlr, CR_STOPEP | (ring->id<<16) | (slot->id<<24), 0, 0, nil);
}
/* (input) slot context */
@@ -723,7 +753,8 @@
freering(io[OREAD].ring);
freering(io[OWRITE].ring);
}
- freeb(io[OREAD].cb);
+ freeb(io[OREAD].b);
+ freeb(io[OWRITE].b);
free(io);
}
@@ -732,7 +763,7 @@
{
int ival;
- if(ep->ttype == Tintr && (ep->dev->speed == Fullspeed || ep->dev->speed == Lowspeed)){
+ if(ep->dev->speed == Lowspeed || ep->dev->speed == Fullspeed){
for(ival=3; ival < 11 && (1<<ival) < ep->pollival; ival++)
;
} else {
@@ -744,10 +775,26 @@
if(ep->ttype != Tiso)
w[1] |= 3<<1;
*((u64int*)&w[2]) = PADDR(r->base) | 1;
+
w[4] = ep->maxpkt;
+ if(ep->ttype == Tintr || ep->ttype == Tiso)
+ w[4] |= (ep->maxpkt*ep->ntds)<<16;
}
static void
+initisoio(Epio *io, Ep *ep)
+{
+ if(io->ring == nil)
+ return;
+ io->frame = 0;
+ io->incr = (ep->hz<<8)/1000;
+ io->tdsz = (io->incr+255>>8)*ep->samplesz;
+ if(io->tdsz > ep->maxpkt*ep->ntds)
+ error(Egreg);
+ io->b = allocb((io->ring->mask+1)*io->tdsz);
+}
+
+static void
initep(Ep *ep)
{
Epio *io;
@@ -816,6 +863,10 @@
PADDR(slot->ibase), nil)) != nil){
error(err);
}
+ if(ep->ttype == Tiso){
+ initisoio(io+OWRITE, ep);
+ initisoio(io+OREAD, ep);
+ }
poperror();
}
@@ -957,6 +1008,77 @@
}
static long
+isoread(Ep *, uchar *, long)
+{
+ error(Egreg);
+ return 0;
+}
+
+static long
+isowrite(Ep *ep, uchar *p, long n)
+{
+ uchar *s, *d;
+ Ctlr *ctlr;
+ Epio *io;
+ u32int x;
+ long m;
+
+ s = p;
+ io = (Epio*)ep->aux + OWRITE;
+ qlock(io);
+ if(waserror()){
+ qunlock(io);
+ nexterror();
+ }
+
+ ctlr = ep->hp->aux;
+ for(x = io->frame;; x++){
+ for(;;){
+ m = (int)(io->ring->wp - io->ring->rp);
+ if(m <= 0)
+ x = 10 + mfindex(ctlr)/8;
+ if(m < io->ring->mask-1)
+ break;
+ coherence();
+ *io->ring->doorbell = io->ring->id;
+ tsleep(&up->sleep, return0, nil, 5);
+ }
+ m = ((io->incr + (x*io->incr&255))>>8)*ep->samplesz;
+ d = io->b->rp + (x&io->ring->mask)*io->tdsz;
+ m -= io->nleft, d += io->nleft;
+ if(n < m){
+ memmove(d, p, n);
+ p += n;
+ io->nleft += n;
+ break;
+ }
+ memmove(d, p, m);
+ p += m, n -= m;
+ m += io->nleft, d -= io->nleft;
+ io->nleft = 0;
+
+ ilock(io->ring);
+ queuetd(io->ring, TR_ISOCH | (x & 0x7ff)<<20 | 1<<5, m, PADDR(d), nil);
+ iunlock(io->ring);
+ }
+ io->frame = x;
+ coherence();
+ *io->ring->doorbell = io->ring->id;
+ qunlock(io);
+ poperror();
+
+ for(;;){
+ int d = (int)(x - mfindex(ctlr)/8);
+ d -= ep->sampledelay*1000 / ep->hz;
+ if(d < 5)
+ break;
+ tsleep(&up->sleep, return0, nil, d);
+ }
+
+ return p - s;
+}
+
+static long
epread(Ep *ep, void *va, long n)
{
Epio *io;
@@ -965,21 +1087,21 @@
Wait ws[1];
p = va;
- io = (Epio*)ep->aux + OREAD;
-
if(ep->ttype == Tctl){
+ io = (Epio*)ep->aux + OREAD;
qlock(io);
- if(io->cb == nil || BLEN(io->cb) == 0){
+ if(io->b == nil || BLEN(io->b) == 0){
qunlock(io);
return 0;
}
- if(n > BLEN(io->cb))
- n = BLEN(io->cb);
- memmove(p, io->cb->rp, n);
- io->cb->rp += n;
+ if(n > BLEN(io->b))
+ n = BLEN(io->b);
+ memmove(p, io->b->rp, n);
+ io->b->rp += n;
qunlock(io);
return n;
- }
+ } else if(ep->ttype == Tiso)
+ return isoread(ep, p, n);
if((uintptr)p <= KZERO){
Block *b;
@@ -996,6 +1118,7 @@
return n;
}
+ io = (Epio*)ep->aux + OREAD;
qlock(io);
if((err = unstall(io->ring)) != nil){
qunlock(io);
@@ -1041,20 +1164,20 @@
qunlock(io);
nexterror();
}
- if(io->cb != nil){
- freeb(io->cb);
- io->cb = nil;
+ if(io->b != nil){
+ freeb(io->b);
+ io->b = nil;
}
len = GET2(&p[6]);
dir = (p[0] & Rd2h) != 0;
if(len > 0){
- io->cb = allocb(len);
+ io->b = allocb(len);
if(dir == 0){ /* out */
assert(len >= n-8);
- memmove(io->cb->wp, p+8, n-8);
+ memmove(io->b->wp, p+8, n-8);
} else {
- memset(io->cb->wp, 0, len);
- io->cb->wp += len;
+ memset(io->b->wp, 0, len);
+ io->b->wp += len;
}
}
@@ -1080,7 +1203,7 @@
(u64int)(GET2(&p[4]) | len<<16)<<32, &ws[0]);
if(len > 0)
queuetd(ring, TR_DATASTAGE | dir<<16 | 1<<5, len,
- PADDR(io->cb->rp), &ws[1]);
+ PADDR(io->b->rp), &ws[1]);
queuetd(ring, TR_STATUSSTAGE | (len == 0 || !dir)<<16 | 1<<5, 0, 0, &ws[2]);
iunlock(ring);
@@ -1090,9 +1213,9 @@
if((err = waittd((Ctlr*)ep->hp->aux, &ws[1], ep->tmout, nil)) != nil)
error(err);
if(dir != 0){
- io->cb->wp -= (ws[1].er[2] & 0xFFFFFF);
- if(io->cb->wp < io->cb->rp)
- io->cb->wp = io->cb->rp;
+ io->b->wp -= (ws[1].er[2] & 0xFFFFFF);
+ if(io->b->wp < io->b->rp)
+ io->b->wp = io->b->rp;
}
}
if((err = waittd((Ctlr*)ep->hp->aux, &ws[2], ep->tmout, nil)) != nil)
@@ -1101,7 +1224,8 @@
poperror();
return n;
- }
+ } else if(ep->ttype == Tiso)
+ return isowrite(ep, p, n);
if((uintptr)p <= KZERO){
Block *b;