git: 9front

Download patch

ref: 787e49e3e618f5c0077e4a5870d5a6c0b3614c06
parent: 8931c1f6fab07a800eae4013e218c462ef816d74
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Sun Jun 21 17:36:50 EDT 2020

devusb: keep isochronous ep->hz consistent with maxpkt, ntds and pollival

The sample frequency is an artificial parameter used for
isochronous out transfers to better match the target
frequency (usually, a sound card).

when hz is set, devusb adjusts the endpoint's maxpkt to get
the requested frequency and a multiple of the samplesize per
packet.

however, when hz is not set, then we should calculate the
frequency from maxpkt, ntds and pollival, so all parameters
will be consistent with each other.

--- a/sys/src/9/port/devusb.c
+++ b/sys/src/9/port/devusb.c
@@ -525,8 +525,8 @@
 	case Tiso:
 		nep->tmout = Xfertmout;
 		nep->pollival = 10;
-		nep->samplesz = 4;
-		nep->hz = 44100;
+		nep->samplesz = 1;
+		nep->hz = 0;
 		nep->uframes = 0;
 		break;
 	}
@@ -859,6 +859,58 @@
 	return l / 1000UL;	/* in µs */
 }
 
+static void
+isotiming(Ep *ep)
+{
+	long spp, max;
+
+	switch(ep->dev->speed){
+	case Fullspeed:
+		max = 1024;
+		break;
+	case Highspeed:
+		max = 3*1024;
+		break;
+	case Superspeed:
+		max = 48*1024;
+		break;
+	default:
+		error(Egreg);
+		return;
+	}
+
+	if(ep->ntds <= 0)
+		error(Egreg);
+	max /= ep->ntds;
+	if(max < ep->samplesz)
+		error(Egreg);
+	if(ep->pollival <= 0)
+		error(Egreg);
+
+	if(ep->hz <= 0){
+		spp = ep->maxpkt / ep->samplesz;
+		spp *= ep->ntds;
+		if(ep->dev->speed == Fullspeed || ep->dev->speed == Lowspeed)
+			ep->hz = (1000 * spp) / ep->pollival;
+		else
+			ep->hz = (8000 * spp) / ep->pollival;
+		if(ep->hz <= 0)
+			error(Egreg);
+	}
+	if(ep->dev->speed == Fullspeed || ep->dev->speed == Lowspeed)
+		spp = (ep->hz * ep->pollival + 999) / 1000;
+	else
+		spp = (ep->hz * ep->pollival + 7999) / 8000;
+	spp /= ep->ntds;
+	ep->maxpkt = spp * ep->samplesz;
+	if(ep->maxpkt > max){
+		print("ep%d.%d: maxpkt %ld > %ld for %s, truncating\n",
+			ep->dev->nb, ep->nb,
+			ep->maxpkt, max, spname[ep->dev->speed]);
+		ep->maxpkt = max;
+	}
+}
+
 static Chan*
 usbopen(Chan *c, int omode)
 {
@@ -901,6 +953,9 @@
 		error(Enotconf);
 	ep->clrhalt = 0;
 	ep->rhrepl = -1;
+
+	if(ep->ttype == Tiso)
+		isotiming(ep);
 	if(ep->load == 0 && ep->dev->speed != Superspeed)
 		ep->load = usbload(ep->dev->speed, ep->maxpkt);
 	ep->hp->epopen(ep);
@@ -1159,40 +1214,6 @@
 	return n;
 }
 
-static void
-setmaxpkt(Ep *ep, char* s)
-{
-	long spp, max;	/* samples per packet */
-
-	if(ep->dev->speed == Fullspeed)
-		spp = (ep->hz * ep->pollival + 999) / 1000;
-	else
-		spp = (ep->hz * ep->pollival * ep->ntds + 7999) / 8000;
-	ep->maxpkt = spp * ep->samplesz;
-	deprint("usb: %s: setmaxpkt: hz %ld poll %ld"
-		" ntds %d %s speed -> spp %ld maxpkt %ld\n", s,
-		ep->hz, ep->pollival, ep->ntds, spname[ep->dev->speed],
-		spp, ep->maxpkt);
-	switch(ep->dev->speed){
-	case Fullspeed:
-		max = 1024;
-		break;
-	case Highspeed:
-		max = 3*1024;
-		break;
-	case Superspeed:
-		max = 48*1024;
-		break;
-	default:
-		return;
-	}
-	if(ep->maxpkt*ep->ntds > max){
-		print("usb: %s: maxpkt %ld > %ld for %s, truncating\n",
-			s, ep->maxpkt*ep->ntds, max, spname[ep->dev->speed]);
-		ep->maxpkt = max/ep->ntds;
-	}
-}
-
 /*
  * Many endpoint ctls. simply update the portable representation
  * of the endpoint. The actual controller driver will look
@@ -1287,6 +1308,7 @@
 			error("maxpkt not in [1:1024]");
 		qlock(ep);
 		ep->maxpkt = l;
+		ep->hz = 0; /* recalculate */
 		qunlock(ep);
 		break;
 	case CMntds:
@@ -1296,6 +1318,7 @@
 			error("ntds not in [1:3]");
 		qlock(ep);
 		ep->ntds = l;
+		ep->hz = 0; /* recalculate */
 		qunlock(ep);
 		break;
 	case CMpollival:
@@ -1313,8 +1336,7 @@
 		}
 		qlock(ep);
 		ep->pollival = l;
-		if(ep->ttype == Tiso)
-			setmaxpkt(ep, "pollival");
+		ep->hz = 0; /* recalculate */
 		qunlock(ep);
 		break;
 	case CMsamplesz:
@@ -1326,7 +1348,6 @@
 			error("samplesz not in [1:8]");
 		qlock(ep);
 		ep->samplesz = l;
-		setmaxpkt(ep, "samplesz");
 		qunlock(ep);
 		break;
 	case CMhz:
@@ -1334,11 +1355,10 @@
 			error("not an iso endpoint");
 		l = strtoul(cb->f[1], nil, 0);
 		deprint("usb epctl %s %d\n", cb->f[0], l);
-		if(l <= 0 || l > 100000)
-			error("hz not in [1:100000]");
+		if(l <= 0 || l > 1000000000)
+			error("hz not in [1:1000000000]");
 		qlock(ep);
 		ep->hz = l;
-		setmaxpkt(ep, "hz");
 		qunlock(ep);
 		break;
 	case CMuframes:
--