shithub: riscv

Download patch

ref: a397bfd48c9b0f2f0d335752cb52f286afcf1ad7
parent: 0b4ace02c469484c9f2a42fdc79ffe1d123d04d8
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Mon Jul 24 19:47:55 EDT 2017

usb: fix wrong pollival calculation in setmaxpkt()

--- a/sys/src/9/port/devusb.c
+++ b/sys/src/9/port/devusb.c
@@ -1084,18 +1084,12 @@
 	return n;
 }
 
-static long
-pow2(int n)
-{
-	return 1 << n;
-}
-
 static void
 setmaxpkt(Ep *ep, char* s)
 {
-	long spp;	/* samples per packet */
+	long spp, max;	/* samples per packet */
 
-	if(ep->dev->speed == Highspeed)
+	if(ep->dev->speed == Highspeed || ep->dev->speed == Superspeed)
 		spp = (ep->hz * ep->pollival * ep->ntds + 7999) / 8000;
 	else
 		spp = (ep->hz * ep->pollival + 999) / 1000;
@@ -1104,10 +1098,25 @@
 		" ntds %d %s speed -> spp %ld maxpkt %ld\n", s,
 		ep->hz, ep->pollival, ep->ntds, spname[ep->dev->speed],
 		spp, ep->maxpkt);
-	if(ep->maxpkt > 1024){
-		print("usb: %s: maxpkt %ld > 1024. truncating\n", s, ep->maxpkt);
-		ep->maxpkt = 1024;
+
+	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;
+	}
 }
 
 /*
@@ -1164,7 +1173,7 @@
 			error("speed must be full|low|high");
 		nep = newdev(ep->hp, 0, 0);
 		nep->dev->speed = l;
-		if(nep->dev->speed  != Lowspeed)
+		if(nep->dev->speed != Lowspeed)
 			nep->maxpkt = 64;	/* assume full speed */
 		nep->dev->hub = d->addr;
 		nep->dev->port = atoi(cb->f[2]);
@@ -1214,14 +1223,14 @@
 			error("not an intr or iso endpoint");
 		l = strtoul(cb->f[1], nil, 0);
 		deprint("usb epctl %s %d\n", cb->f[0], l);
-		if(ep->ttype == Tiso ||
-		   (ep->ttype == Tintr && ep->dev->speed == Highspeed)){
+		if(ep->dev->speed == Highspeed || ep->dev->speed == Superspeed){
 			if(l < 1 || l > 16)
 				error("pollival power not in [1:16]");
-			l = pow2(l-1);
-		}else
+			l = 1 << l-1;
+		} else {
 			if(l < 1 || l > 255)
 				error("pollival not in [1:255]");
+		}
 		qlock(ep);
 		ep->pollival = l;
 		if(ep->ttype == Tiso)
--- a/sys/src/9/port/usb.h
+++ b/sys/src/9/port/usb.h
@@ -162,11 +162,11 @@
 	char*	info;		/* for humans to read */
 	long	maxpkt;		/* maximum packet size */
 	int	ttype;		/* tranfer type */
-	ulong	load;		/* in µs, for a fransfer of maxpkt bytes */
+	ulong	load;		/* in µs, for a transfer of maxpkt bytes */
 	void*	aux;		/* for controller specific info */
 	int	rhrepl;		/* fake root hub replies */
 	int	toggle[2];	/* saved toggles (while ep is not in use) */
-	long	pollival;		/* poll interval ([µ]frames; intr/iso) */
+	long	pollival;	/* poll interval ([µ]frames; intr/iso) */
 	long	hz;		/* poll frequency (iso) */
 	long	samplesz;	/* sample size (iso) */
 	int	ntds;		/* nb. of Tds per µframe */
--- a/sys/src/cmd/nusb/lib/dev.c
+++ b/sys/src/cmd/nusb/lib/dev.c
@@ -45,11 +45,6 @@
 		return nil;
 	}
 	ep = ud->ep[id];
-	mode = "rw";
-	if(ep->dir == Ein)
-		mode = "r";
-	if(ep->dir == Eout)
-		mode = "w";
 	snprint(name, sizeof(name), "/dev/usb/ep%d.%d", d->id, id);
 	if(access(name, AEXIST) == 0){
 		dprint(2, "%s: %s already exists; trying to open\n", argv0, name);
@@ -60,6 +55,11 @@
 		}
 		return epd;
 	}
+	mode = "rw";
+	if(ep->dir == Ein)
+		mode = "r";
+	if(ep->dir == Eout)
+		mode = "w";
 	if(devctl(d, "new %d %d %s", id, ep->type, mode) < 0){
 		dprint(2, "%s: %s: new: %r\n", argv0, d->dir);
 		return nil;
@@ -78,13 +78,6 @@
 		fprint(2, "%s: %s: openep: ntds: %r\n", argv0, epd->dir);
 	else
 		dprint(2, "%s: %s: ntds %d\n", argv0, epd->dir, ep->ntds);
-
-	/*
-	 * For iso endpoints and high speed interrupt endpoints the pollival is
-	 * actually 2ⁿ and not n.
-	 * The kernel usb driver must take that into account.
-	 * It's simpler this way.
-	 */
 
 	if(ac != nil && (ep->type == Eintr || ep->type == Eiso) && ac->interval != 0)
 		if(devctl(epd, "pollival %d", ac->interval) < 0)