git: 9front

Download patch

ref: 1bb08244b5f2790d724fcf6089bd07178149b5b6
parent: ca307b695eacf812877d3937d80d9a9e47664339
author: cinap_lenrek <cinap_lenrek@localhost>
date: Mon Aug 1 15:02:50 EDT 2011

usb: added buffer delay control

--- a/sys/src/9/pc/devusb.c
+++ b/sys/src/9/pc/devusb.c
@@ -88,6 +88,7 @@
 	CMdebugep,		/* debug n (set/clear debug for this ep) */
 	CMname,			/* name str (show up as #u/name as well) */
 	CMtmout,		/* timeout n (activate timeouts for ep) */
+	CMsampledelay,		/* maximum delay introduced by buffering (iso) */
 	CMpreset,		/* reset the port */
 
 	/* Hub feature selectors */
@@ -132,6 +133,7 @@
 	{CMclrhalt,	"clrhalt",	1},
 	{CMname,	"name",		2},
 	{CMtmout,	"timeout",	2},
+	{CMsampledelay,	"sampledelay",	2},
 	{CMpreset,	"reset",	1},
 };
 
@@ -1308,6 +1310,11 @@
 		ep->tmout = strtoul(cb->f[1], nil, 0);
 		if(ep->tmout != 0 && ep->tmout < Xfertmout)
 			ep->tmout = Xfertmout;
+		break;
+	case CMsampledelay:
+		if(ep->ttype != Tiso)
+			error("ctl ignored for this endpoint type");
+		ep->sampledelay = strtoul(cb->f[1], nil, 0);
 		break;
 	case CMpreset:
 		deprint("usb epctl %s\n", cb->f[0]);
--- a/sys/src/9/pc/usbohci.c
+++ b/sys/src/9/pc/usbohci.c
@@ -220,6 +220,7 @@
 	ulong	frno;		/* next frame number avail for I/O */
 	ulong	left;		/* remainder after rounding Hz to samples/ms */
 	int	nerrs;		/* consecutive errors on iso I/O */
+	int	delay;		/* maximum number of frames to buffer */
 };
 
 /*
@@ -1101,6 +1102,17 @@
 		iso->navail > iso->nframes / 2;
 }
 
+static int
+isodelay(void *a)
+{
+	Isoio *iso;
+
+	iso = a;
+	if(iso->state == Qclose || iso->err != nil || iso->delay == 0)
+		return 1;
+	return (iso->nframes - iso->navail) <= iso->delay;
+}
+
 /*
  * Service a completed/failed Td from the done queue.
  * It may be of any transfer type.
@@ -1780,6 +1792,7 @@
 
 	ctlr = ep->hp->aux;
 	iso = ep->aux;
+	iso->delay = (ep->sampledelay*ep->samplesz + ep->maxpkt-1) / ep->maxpkt;
 	iso->debug = ep->debug;
 
 	qlock(iso);
@@ -1819,6 +1832,11 @@
 			panic("episowrite: iso not running");
 		iunlock(ctlr);		/* We could page fault here */
 		nw = putsamples(ctlr, ep, iso, b+tot, count-tot);
+		ilock(ctlr);
+	}
+	while(isodelay(iso) == 0){
+		iunlock(ctlr);
+		sleep(iso, isodelay, iso);
 		ilock(ctlr);
 	}
 	if(iso->state != Qclose)
--- a/sys/src/9/pc/usbuhci.c
+++ b/sys/src/9/pc/usbuhci.c
@@ -195,6 +195,7 @@
 	int	debug;		/* debug flag from the endpoint */
 	Isoio*	next;		/* in list of active Isoios */
 	Td*	tdps[Nframes];	/* pointer to Td used for i-th frame or nil */
+	int	delay;		/* maximum number of bytes to buffer */
 };
 
 struct Tdpool
@@ -775,6 +776,29 @@
 		iso->tok == Tdtokout && iso->tdu->next != iso->tdi);
 }
 
+static int
+isodelay(void *a)
+{
+	Isoio *iso;
+	int delay;
+	Td *tdi;
+
+	iso = a;
+	if(iso->state == Qclose || iso->err || iso->delay == 0)
+		return 1;
+
+	delay = 0;
+	for(tdi = iso->tdi; tdi->next != iso->tdu; tdi = tdi->next){
+		if((tdi->csw & Tdactive) == 0)
+			continue;
+		delay += maxtdlen(tdi);
+		if(delay > iso->delay)
+			break;
+	}
+
+	return delay <= iso->delay;
+}
+
 static void
 tdisoinit(Isoio *iso, Td *td, long count)
 {
@@ -812,7 +836,6 @@
 	nframes = iso->nframes / 2;		/* limit how many we look */
 	if(nframes > 64)
 		nframes = 64;
-
 	for(i = 0; i < nframes && (tdi->csw & Tdactive) == 0; i++){
 		tdi->csw &= ~Tdioc;
 		err = tdi->csw & Tderrors;
@@ -839,7 +862,7 @@
 		}
 		tdi = tdi->next;
 	}
-	ddiprint("isointr: %d frames processed\n", nframes);
+	ddiprint("isointr: %d frames processed\n", i);
 	if(i == nframes)
 		tdi->csw |= Tdioc;
 	iso->tdi = tdi;
@@ -848,7 +871,6 @@
 			iso->tdi, iso->tdu);
 		wakeup(iso);
 	}
-
 }
 
 /*
@@ -1005,6 +1027,7 @@
 	char *err;
 
 	iso->debug = ep->debug;
+	iso->delay = ep->sampledelay * ep->samplesz;
 	diprint("uhci: episowrite: %#p ep%d.%d\n", iso, ep->dev->nb, ep->nb);
 
 	ctlr = ep->hp->aux;
@@ -1046,6 +1069,11 @@
 		nw = putsamples(iso, b+tot, count-tot);
 		ilock(ctlr);
 	}
+	while(isodelay(iso) == 0){
+		iunlock(ctlr);
+		sleep(iso, isodelay, iso);
+		ilock(ctlr);
+	}
 	if(iso->state != Qclose)
 		iso->state = Qdone;
 	iunlock(ctlr);
@@ -1678,7 +1706,7 @@
 	}
 	ltd->next = iso->tdps[iso->td0frno];
 	iso->tdi = iso->tdps[iso->td0frno];
-	iso->tdu = iso->tdi;	/* read: right now; write: 1s ahead */
+	iso->tdu = iso->tdi;
 	ilock(ctlr);
 	frno = iso->td0frno;
 	for(i = 0; i < iso->nframes; i++){
--- a/sys/src/9/port/usb.h
+++ b/sys/src/9/port/usb.h
@@ -170,6 +170,7 @@
 	long	samplesz;	/* sample size (iso) */
 	int	ntds;		/* nb. of Tds per µframe */
 	int	tmout;		/* 0 or timeout for transfers (ms) */
+	int	sampledelay;	/* maximum delay introduced by buffering (iso) */
 };
 
 /*
--- a/sys/src/9/port/usbehci.c
+++ b/sys/src/9/port/usbehci.c
@@ -215,6 +215,7 @@
 	ulong	maxsize;	/* ntds * ep->maxpkt */
 	long	nleft;		/* number of bytes left from last write */
 	int	debug;		/* debug flag from the endpoint */
+	int	delay;		/* max number of bytes to buffer */
 	int	hs;		/* is high speed? */
 	Isoio*	next;		/* in list of active Isoios */
 	ulong	td0frno;	/* first frame used in ctlr */
@@ -1291,6 +1292,43 @@
 }
 
 static int
+isodelay(void *a)
+{
+	Isoio *iso;
+	int delay;
+
+	iso = a;
+	if(iso->state == Qclose || iso->err || iso->delay == 0)
+		return 1;
+
+	delay = 0;
+	if(iso->hs){
+		Itd *i;
+
+		for(i = iso->tdi; i->next != iso->tdu; i = i->next){
+			if(!itdactive(i))
+				continue;
+			delay += i->mdata;
+			if(delay > iso->delay)
+				break;
+		}
+	} else {
+		Sitd *i;
+
+		for(i = iso->stdi; i->next != iso->stdu; i = i->next){
+			if((i->csw & Stdactive) == 0)
+				continue;
+			delay += i->mdata;
+			if(delay > iso->delay)
+				break;
+		}
+	}
+
+	return delay <= iso->delay;
+}
+
+
+static int
 isohsinterrupt(Ctlr *ctlr, Isoio *iso)
 {
 	int err, i, nframes, t;
@@ -1996,6 +2034,7 @@
 	int tot, nw;
 	char *err;
 
+	iso->delay = ep->sampledelay * ep->samplesz;
 	iso->debug = ep->debug;
 	diprint("ehci: episowrite: %#p ep%d.%d\n", iso, ep->dev->nb, ep->nb);
 
@@ -2037,6 +2076,11 @@
 			panic("episowrite: iso not running");
 		iunlock(ctlr);		/* We could page fault here */
 		nw = putsamples(iso, b+tot, count-tot);
+		ilock(ctlr);
+	}
+	while(isodelay(iso) == 0){
+		iunlock(ctlr);
+		sleep(iso, isodelay, iso);
 		ilock(ctlr);
 	}
 	if(iso->state != Qclose)
--- a/sys/src/cmd/nusb/audio/audio.c
+++ b/sys/src/cmd/nusb/audio/audio.c
@@ -14,6 +14,7 @@
 	int	maxfreq;
 };
 
+int audiodelay = 882;
 int audiofreq = 44100;
 int audiochan = 2;
 int audiores = 16;
@@ -85,15 +86,17 @@
 	b[1] = speed >> 8;
 	b[2] = speed >> 16;
 	if(usbcmd(d, Rh2d|Rclass|Rep, Rsetcur, 0x100, e->addr, b, 3) < 0)
-		fprint(2, "warning: set freq: %r");
+		fprint(2, "warning: set freq: %r\n");
 
 	if((d = openep(d, e->id)) == nil){
 		werrstr("openep: %r");
 		return nil;
 	}
-	devctl(d, "pollival %d", 1);
+	devctl(d, "pollival %d", a->interval);
 	devctl(d, "samplesz %d", audiochan*audiores/8);
+	devctl(d, "sampledelay %d", audiodelay);
 	devctl(d, "hz %d", speed);
+	devctl(d, "name audio");
 	return d;
 }
 
@@ -102,7 +105,7 @@
 {
 	char *msg;
 
-	msg = smprint("master 100 100\nspeed %d\n", audiofreq);
+	msg = smprint("master 100 100\nspeed %d\ndelay %d\n", audiofreq, audiodelay);
 	readstr(r, msg);
 	respond(r, nil);
 	free(msg);
@@ -112,7 +115,7 @@
 fswrite(Req *r)
 {
 	char msg[256], *f[4];
-	int nf;
+	int nf, speed;
 
 	snprint(msg, sizeof(msg), "%.*s", r->ifcall.count, r->ifcall.data);
 	nf = tokenize(msg, f, nelem(f));
@@ -122,17 +125,20 @@
 	}
 	if(strcmp(f[0], "speed") == 0){
 		Dev *d;
-		int speed;
 
 		speed = atoi(f[1]);
+Setup:
 		if((d = setupep(audiodev, audioep, speed)) == nil){
 			responderror(r);
 			return;
 		}
-		devctl(d, "name audio");
 		closedev(d);
 
 		audiofreq = speed;
+	} else if(strcmp(f[0], "delay") == 0){
+		audiodelay = atoi(f[1]);
+		speed = audiofreq;
+		goto Setup;
 	}
 	r->ofcall.count = r->ifcall.count;
 	respond(r, nil);
@@ -185,7 +191,6 @@
 	audioep = e;
 	if((d = setupep(audiodev, audioep, audiofreq)) == nil)
 		sysfatal("setupep: %r");
-	devctl(d, "name audio");
 	closedev(d);
 
 	fs.tree = alloctree(user, "usb", DMDIR|0555, nil);
--