shithub: riscv

Download patch

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 */