tech-kern archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: qemu USB pass-through/NetBSD guest



On Tue, Feb 25, 2025 at 12:07:20PM +0100, Manuel Bouyer wrote:
> Hello,
> I'm trying to pass a USB device to a NetBSD guest (to ease driver
> developement). I'm using:
> qemu-system-x86_64 -audiodev oss,id=oss  -m 2G -accel nvmm -drive if=virtio,file=/home/bouyer/nvmm/tst-can.vnd,format=raw -netdev user,id=n1 -device virtio-net-pci,netdev=n1 -usb -device usb-host,bus=usb-bus.0,port=1,vendorid=0x1d50,productid=0x606f -chardev stdio,id=char0 -serial chardev:char0
> 
> If the guest is linux, the USB device is detected (and the appropriate
> driver loaded), so the qemu part is working (at last good enough for linux),
> but with a NetBSD guest this ends up with:
> [    75.292264] uhub0: autoconfiguration error: device problem, disabling port 1
> 
> Any idea before I start investigating uhci ?

I made progress on this; the attached patch allows the NetBSD guest to
see the passed device; although with a 1mn timeout.
This patch is inspired from linux, which, from what I understood, will
first do what we do (fetch descriptor before setting the address), and
if it fail retries with setting the address first.

The port reset causes the full descriptor fetch afterward, so the patch
avoids it if we had to first set the address.

Maybe it could help with some USB hubs or devices too ...

-- 
Manuel Bouyer <bouyer%antioche.eu.org@localhost>
     NetBSD: 26 ans d'experience feront toujours la difference
--
Index: usb_subr.c
===================================================================
RCS file: /cvsroot/src/sys/dev/usb/usb_subr.c,v
retrieving revision 1.277
diff -u -r1.277 usb_subr.c
--- usb_subr.c	6 Apr 2022 22:01:45 -0000	1.277
+++ usb_subr.c	26 Feb 2025 22:10:18 -0000
@@ -1383,12 +1383,18 @@
 	int addr;
 	int i;
 	int p;
+	int addr_valid;
 
 	KASSERT(usb_in_event_thread(parent));
 
-	if (bus->ub_methods->ubm_newdev != NULL)
-		return (bus->ub_methods->ubm_newdev)(parent, bus, depth, speed,
+	if (bus->ub_methods->ubm_newdev != NULL) {
+		err = (bus->ub_methods->ubm_newdev)(parent, bus, depth, speed,
 		    port, up);
+		if (err) {
+			DPRINTFN(1, "bus newdev %p  failed, error %d", bus->ub_methods->ubm_newdev, err, 0, 0);
+		}
+		return err;
+	}
 
 	addr = usbd_getnewaddr(bus);
 	if (addr < 0) {
@@ -1459,11 +1465,14 @@
 	err = usbd_setup_pipe_flags(dev, 0, &dev->ud_ep0, USBD_DEFAULT_INTERVAL,
 	    &dev->ud_pipe0, USBD_MPSAFE);
 	if (err) {
+		DPRINTFN(1, "usbd_setup_pipe_flags failed, error %d", err, 0, 0, 0);
 		usbd_remove_device(dev, up);
 		return err;
 	}
 
 	dd = &dev->ud_ddesc;
+	addr_valid = 0;
+getdesc_again:
 	/* Try a few times in case the device is slow (i.e. outside specs.) */
 	for (i = 0; i < 10; i++) {
 		/* Get the first 8 bytes of the device descriptor. */
@@ -1482,12 +1491,29 @@
 	if (err) {
 		DPRINTF("addr=%jd, getting first desc failed: %jd", addr, err,
 		    0, 0);
-		usbd_remove_device(dev, up);
-		return err;
+
+		if (addr_valid) {
+			usbd_remove_device(dev, up);
+			return err;
+		}
+		addr_valid++;
+		/* Set the address */
+		DPRINTFN(5, "setting device address=%jd", addr, 0, 0, 0);
+		err = usbd_set_address(dev, addr);
+		if (err) {
+			DPRINTF("set address %jd failed, err = %jd", addr, err, 0, 0);
+			err = USBD_SET_ADDR_FAILED;
+			usbd_remove_device(dev, up);
+			return err;
+		}
+		/* Allow device time to set new address */
+		usbd_delay_ms(dev, USB_SET_ADDRESS_SETTLE);
+		dev->ud_addr = addr;	/* new device address now */
+		goto getdesc_again;
 	}
 
 	/* Windows resets the port here, do likewise */
-	if (up->up_parent)
+	if (up->up_parent && addr_valid == 0)
 		usbd_reset_port(up->up_parent, port, &ps);
 
 	if (speed == USB_SPEED_HIGH) {


Home | Main Index | Thread Index | Old Index