shithub: riscv

Download patch

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;