code: plan9front

Download patch

ref: 76142255a117a21da665282e7c6754b8b389bbc7
parent: 8420d3ad6929c2f6963bcef80797f8cc2b3d90f8
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Wed Apr 12 17:35:21 EDT 2023

nusb/usbd: only fetch first 8 bytes of device descriptor for getmaxpkt() (thanks k0ga)

The first usb transaction we run on a device is reading the
device descriptor, but todo this we need to know the maximum
packet size on the control endpoint.

But the packet size itself is stored in the device descriptor
which needs to be read over the control endpoint.

We used to fetch up to 64 bytes of device descriptor, and
if that fails assume some default values.

But this seems to cause errors down the line for some devices
like k0gas usb keyboard.

The new way is to read *ONLY* the first 8 bytes (that contain
the bMaxPktSize0 field) and fetch the full device descriptor
later once we have set the correct packet size.

--- a/sys/src/cmd/nusb/usbd/hub.c
+++ b/sys/src/cmd/nusb/usbd/hub.c
@@ -326,19 +326,15 @@
 }
 
 static int
-getmaxpkt(Dev *d, int islow)
+getmaxpkt(Dev *d)
 {
-	uchar buf[64];	/* More room to try to get device-specific descriptors */
+	uchar buf[8];
 	DDev *dd;
 
 	if(d->isusb3)
 		return 512;
 	dd = (DDev*)buf;
-	if(islow)
-		dd->bMaxPacketSize0 = 8;
-	else
-		dd->bMaxPacketSize0 = 64;
-	if(usbcmd(d, Rd2h|Rstd|Rdev, Rgetdesc, Ddev<<8|0, 0, buf, sizeof(buf)) < 0)
+	if(usbcmd(d, Rd2h|Rstd|Rdev, Rgetdesc, Ddev<<8|0, 0, buf, sizeof(buf)) != sizeof(buf))
 		return -1;
 	return dd->bMaxPacketSize0;
 }
@@ -440,7 +436,7 @@
 		dprint(2, "%s: %s: port %d: set address: %r\n", argv0, d->dir, p);
 		goto Fail;
 	}
-	mp=getmaxpkt(nd, strcmp(sp, "low") == 0);
+	mp=getmaxpkt(nd);
 	if(mp < 0){
 		dprint(2, "%s: %s: port %d: getmaxpkt: %r\n", argv0, d->dir, p);
 		goto Fail;