> Subject: [PATCH v5 0/8] hw/usb: Add a usbredir server transport
>
> This series adds a usbredir server transport to redirect a USB device emulated
> in one QEMU instance to a USB host controller emulated in another one over
> the usbredir protocol.
>
> The v1 series included both the usbredir server transport and the ASPEED
> AST1030 USB Device Controller (UDC) support. Following review feedback, this
> series contains only the usbredir server transport. The ASPEED
> AST1030 UDC support will be sent separately.
>
> This work is part of a larger plan to model USB device-side support on ASPEED
> BMC/BIC SoCs, which has three goals:
>
> 1. Model the ASPEED UDC (AST2600 / AST1030). The AST2600 also has USB
> host
> (EHCI) controllers, so that work targets the AST2600 UDC: its gadget can
> be attached to the SoC's own EHCI bus, letting the guest enumerate its
> own gadget and exercise the UDC end-to-end. [Done]
>
> https://lore.kernel.org/qemu-devel/20260902021542.3194812-1-jamin_lin@as
> peedtech.com/
>
> 2. AST1030 UDC. The AST1030 has no USB host controller, so testing its UDC
> needs a second QEMU instance. The UDC gadget is redirected out of the
> guest with libusbredir and attached to another QEMU that runs a USB host
> (a VMM, or an AST2600 / AST2700 guest). [this series]
>
> 3. ASPEED vHub, as a longer-term goal towards BMC KVM / Virtual Media
> support in QEMU. [future]
>
> This series implements goal 2.
>
> The transport
> =============
>
> x-usb-redir-server exports a locally emulated USB device to a remote USB host
> over the usbredir protocol, so a device emulated in one QEMU instance can be
> enumerated by a host controller emulated in another one.
>
> The left column is a request going to the device. The right column is the
> answer coming back. The middle hop carries usbredir messages over a socket.
> The top and bottom hops carry USBPackets inside QEMU.
>
> remote QEMU: guest driver -> EHCI/XHCI
> | ^
> USBPacket | | USBPacket
> v |
> "usb-redir" (the client)
> | ^
> usbredir | chardev socket | usbredir
> v |
> x-usb-redir-server (the server, this series)
> | ^
> USBPacket | | USBPacket
> v |
> any USBDevice, "-device <dev>,bus=<id>.0"
>
> "usb-redir" (hw/usb/redirect.c) is the client:
> - it takes a USBPacket from the remote guest and writes it to the socket
> as a usbredir message
> - it reads the answer from the socket and completes the USBPacket
>
> x-usb-redir-server is the server. It does the same thing, but backwards:
> - it reads a usbredir message from the socket and runs it as a USBPacket
> on the bus below
> - it takes the result of that USBPacket and writes it back to the same
> socket as a usbredir message, for the client to read
>
> A USB device has to sit on a USB bus, and in QEMU a USB bus is always made
> by a host controller. So x-usb-redir-server makes one and acts as the host
> controller on this side. It models no real chip: its cable is the chardev socket.
> The real host is in the other QEMU.
>
> The type name has an "x-" prefix because the device is experimental. It has to
> sit on the sysbus so that "-device <dev>,bus=<id>.0" can find the USB bus it
> provides, and that may change later.
>
> usbredir carries one device, not a bus. A hub cannot be exported: the protocol
> has no device address field. To export several devices, run one
> x-usb-redir-server per device, each with its own chardev.
>
> Testing
> =======
>
> A plain usb-storage device was used to test the transport. The storage device is
> attached to x-usb-redir-server and exported over a Unix socket:
>
> $ qemu-system-aarch64 ...
> -chardev socket,id=usbredir0,path=/tmp/usbredir0.sock,server=on,wait=off
> -device x-usb-redir-server,id=usbredir0,chardev=usbredir0
> -drive id=usbdisk,if=none,file=image0.ext4,format=raw
> -device usb-storage,bus=usbredir0.0,id=mystorage,drive=usbdisk
>
> The exported device can then be attached to EHCI bus 3 of an AST2700 guest
> using the existing usb-redir client:
>
> -chardev socket,id=storage,path=/tmp/usbredir0.sock,reconnect-ms=1000
> \
> -device usb-redir,chardev=storage,bus=usb-bus.3
>
> The AST2700 Linux guest enumerates the redirected USB storage device:
>
> root@ast2700-default:~# lsusb
> unable to initialize usb spec
> Bus 001 Device 001: ID 1d6b:0001 Linux 6.18.36-v00.08.03-gaf2f426c5786
> uhci_hcd Generic UHCI Host Controller Bus 002 Device 001: ID 1d6b:0002
> Linux 6.18.36-v00.08.03-gaf2f426c5786 ehci_hcd EHCI Host Controller Bus 002
> Device 002: ID 46f4:0001 QEMU QEMU USB HARDDRIVE
>
> This also demonstrates that x-usb-redir-server is not specific to the ASPEED
> UDC. Any USBDevice can be attached to its USB bus and exported to a host
> controller in another QEMU instance.
>
> v1:
> 1. Add a usbredir server device
> 2. Announce the exported device
> 3. Implement control transfers
> 4. Implement bulk and interrupt transfers
> 5. Stream interrupt IN endpoints
>
> v2:
> 1. Split the original series into USB and ASPEED parts as suggested
> during review.
> 2. Keep this series focused on the usbredir server transport.
> 3. Move the ASPEED UDC changes, AST1030 UDC support and its functional
> test to a separate series.
>
> v3:
> 1. Move include/hw/usb/redirect-server.h into redirect-server.c.
> 2. Drop the announce timer. The firmware does not toggle the pull-up,
> and the delay would be machine specific anyway.
> 3. Rename the type to "x-usb-redir-server" to mark it experimental.
>
> v4:
> 1. ep_info now says what the host chose, both the configuration and the
> alternate setting. Keep every configuration descriptor, not just the last
> one.
> 2. look at the request type too, not only the number
> 3. wait for the endpoint's bInterval before asking the device
> again.
>
> Patch 7 lost its Reviewed-by because it changed. It used to ask the device again
> from a bottom half, which runs as soon as the main loop comes back. So there
> was no wait at all.
>
> A keyboard answers NAK while no key is down, and the retry timer paces that,
> so it looked fine. usb-net's status endpoint answers every time.
> The loop never stopped: ask, answer, ask again, about 17000 times a second.
> The same main loop runs the guest's timers, and it had no room left. The guest
> stopped feeding its watchdog, and the watchdog reset the machine.
>
> bInterval is the rate the endpoint asks to be polled at, and the rate a real host
> controller uses. The stream now waits for it.
>
> v5:
> 1. Use a separate timer and bottom half for each endpoint.
>
> Jamin Lin (8):
> hw/usb/bus: Let a bus opt out of automatic hub insertion
> hw/usb/redirect-server: Add a usbredir server device
> hw/usb/redirect-server: Connect usbredirparser to a chardev
> hw/usb/redirect-server: Announce the exported device
> hw/usb/redirect-server: Implement control transfers
> hw/usb/redirect-server: Implement bulk and interrupt transfers
> hw/usb/redirect-server: Stream interrupt IN endpoints
> hw/arm/aspeed: Enable the usbredir server transport
>
> include/hw/usb/usb.h | 1 +
> hw/arm/aspeed.c | 7 +
> hw/usb/bus.c | 3 +-
> hw/usb/redirect-server.c | 1812
> ++++++++++++++++++++++++++++++++++++++
> hw/usb/meson.build | 3 +-
> hw/usb/trace-events | 31 +
> 6 files changed, 1855 insertions(+), 2 deletions(-) create mode 100644
> hw/usb/redirect-server.c
>
> --
> 2.43.0
Patch 3 does not build on current master since
13d2f5e4b0 ("chardev: add CHR_EVENT_RESIZE")
QEMUChrEvent gained a value and the switch does not handle it. I will
fix it and send v5.
Sorry for the noise.
Jamin
On 10/16/26 08:31, Jamin Lin wrote:
>
>
>> Subject: [PATCH v5 0/8] hw/usb: Add a usbredir server transport
>>
>> This series adds a usbredir server transport to redirect a USB device emulated
>> in one QEMU instance to a USB host controller emulated in another one over
>> the usbredir protocol.
>>
>> The v1 series included both the usbredir server transport and the ASPEED
>> AST1030 USB Device Controller (UDC) support. Following review feedback, this
>> series contains only the usbredir server transport. The ASPEED
>> AST1030 UDC support will be sent separately.
>>
>> This work is part of a larger plan to model USB device-side support on ASPEED
>> BMC/BIC SoCs, which has three goals:
>>
>> 1. Model the ASPEED UDC (AST2600 / AST1030). The AST2600 also has USB
>> host
>> (EHCI) controllers, so that work targets the AST2600 UDC: its gadget can
>> be attached to the SoC's own EHCI bus, letting the guest enumerate its
>> own gadget and exercise the UDC end-to-end. [Done]
>>
>> https://lore.kernel.org/qemu-devel/20260902021542.3194812-1-jamin_lin@as
>> peedtech.com/
>>
>> 2. AST1030 UDC. The AST1030 has no USB host controller, so testing its UDC
>> needs a second QEMU instance. The UDC gadget is redirected out of the
>> guest with libusbredir and attached to another QEMU that runs a USB host
>> (a VMM, or an AST2600 / AST2700 guest). [this series]
>>
>> 3. ASPEED vHub, as a longer-term goal towards BMC KVM / Virtual Media
>> support in QEMU. [future]
>>
>> This series implements goal 2.
>>
>> The transport
>> =============
>>
>> x-usb-redir-server exports a locally emulated USB device to a remote USB host
>> over the usbredir protocol, so a device emulated in one QEMU instance can be
>> enumerated by a host controller emulated in another one.
>>
>> The left column is a request going to the device. The right column is the
>> answer coming back. The middle hop carries usbredir messages over a socket.
>> The top and bottom hops carry USBPackets inside QEMU.
>>
>> remote QEMU: guest driver -> EHCI/XHCI
>> | ^
>> USBPacket | | USBPacket
>> v |
>> "usb-redir" (the client)
>> | ^
>> usbredir | chardev socket | usbredir
>> v |
>> x-usb-redir-server (the server, this series)
>> | ^
>> USBPacket | | USBPacket
>> v |
>> any USBDevice, "-device <dev>,bus=<id>.0"
>>
>> "usb-redir" (hw/usb/redirect.c) is the client:
>> - it takes a USBPacket from the remote guest and writes it to the socket
>> as a usbredir message
>> - it reads the answer from the socket and completes the USBPacket
>>
>> x-usb-redir-server is the server. It does the same thing, but backwards:
>> - it reads a usbredir message from the socket and runs it as a USBPacket
>> on the bus below
>> - it takes the result of that USBPacket and writes it back to the same
>> socket as a usbredir message, for the client to read
>>
>> A USB device has to sit on a USB bus, and in QEMU a USB bus is always made
>> by a host controller. So x-usb-redir-server makes one and acts as the host
>> controller on this side. It models no real chip: its cable is the chardev socket.
>> The real host is in the other QEMU.
>>
>> The type name has an "x-" prefix because the device is experimental. It has to
>> sit on the sysbus so that "-device <dev>,bus=<id>.0" can find the USB bus it
>> provides, and that may change later.
>>
>> usbredir carries one device, not a bus. A hub cannot be exported: the protocol
>> has no device address field. To export several devices, run one
>> x-usb-redir-server per device, each with its own chardev.
>>
>> Testing
>> =======
>>
>> A plain usb-storage device was used to test the transport. The storage device is
>> attached to x-usb-redir-server and exported over a Unix socket:
>>
>> $ qemu-system-aarch64 ...
>> -chardev socket,id=usbredir0,path=/tmp/usbredir0.sock,server=on,wait=off
>> -device x-usb-redir-server,id=usbredir0,chardev=usbredir0
>> -drive id=usbdisk,if=none,file=image0.ext4,format=raw
>> -device usb-storage,bus=usbredir0.0,id=mystorage,drive=usbdisk
>>
>> The exported device can then be attached to EHCI bus 3 of an AST2700 guest
>> using the existing usb-redir client:
>>
>> -chardev socket,id=storage,path=/tmp/usbredir0.sock,reconnect-ms=1000
>> \
>> -device usb-redir,chardev=storage,bus=usb-bus.3
>>
>> The AST2700 Linux guest enumerates the redirected USB storage device:
>>
>> root@ast2700-default:~# lsusb
>> unable to initialize usb spec
>> Bus 001 Device 001: ID 1d6b:0001 Linux 6.18.36-v00.08.03-gaf2f426c5786
>> uhci_hcd Generic UHCI Host Controller Bus 002 Device 001: ID 1d6b:0002
>> Linux 6.18.36-v00.08.03-gaf2f426c5786 ehci_hcd EHCI Host Controller Bus 002
>> Device 002: ID 46f4:0001 QEMU QEMU USB HARDDRIVE
>>
>> This also demonstrates that x-usb-redir-server is not specific to the ASPEED
>> UDC. Any USBDevice can be attached to its USB bus and exported to a host
>> controller in another QEMU instance.
>>
>> v1:
>> 1. Add a usbredir server device
>> 2. Announce the exported device
>> 3. Implement control transfers
>> 4. Implement bulk and interrupt transfers
>> 5. Stream interrupt IN endpoints
>>
>> v2:
>> 1. Split the original series into USB and ASPEED parts as suggested
>> during review.
>> 2. Keep this series focused on the usbredir server transport.
>> 3. Move the ASPEED UDC changes, AST1030 UDC support and its functional
>> test to a separate series.
>>
>> v3:
>> 1. Move include/hw/usb/redirect-server.h into redirect-server.c.
>> 2. Drop the announce timer. The firmware does not toggle the pull-up,
>> and the delay would be machine specific anyway.
>> 3. Rename the type to "x-usb-redir-server" to mark it experimental.
>>
>> v4:
>> 1. ep_info now says what the host chose, both the configuration and the
>> alternate setting. Keep every configuration descriptor, not just the last
>> one.
>> 2. look at the request type too, not only the number
>> 3. wait for the endpoint's bInterval before asking the device
>> again.
>>
>> Patch 7 lost its Reviewed-by because it changed. It used to ask the device again
>> from a bottom half, which runs as soon as the main loop comes back. So there
>> was no wait at all.
>>
>> A keyboard answers NAK while no key is down, and the retry timer paces that,
>> so it looked fine. usb-net's status endpoint answers every time.
>> The loop never stopped: ask, answer, ask again, about 17000 times a second.
>> The same main loop runs the guest's timers, and it had no room left. The guest
>> stopped feeding its watchdog, and the watchdog reset the machine.
>>
>> bInterval is the rate the endpoint asks to be polled at, and the rate a real host
>> controller uses. The stream now waits for it.
>>
>> v5:
>> 1. Use a separate timer and bottom half for each endpoint.
>>
>> Jamin Lin (8):
>> hw/usb/bus: Let a bus opt out of automatic hub insertion
>> hw/usb/redirect-server: Add a usbredir server device
>> hw/usb/redirect-server: Connect usbredirparser to a chardev
>> hw/usb/redirect-server: Announce the exported device
>> hw/usb/redirect-server: Implement control transfers
>> hw/usb/redirect-server: Implement bulk and interrupt transfers
>> hw/usb/redirect-server: Stream interrupt IN endpoints
>> hw/arm/aspeed: Enable the usbredir server transport
>>
>> include/hw/usb/usb.h | 1 +
>> hw/arm/aspeed.c | 7 +
>> hw/usb/bus.c | 3 +-
>> hw/usb/redirect-server.c | 1812
>> ++++++++++++++++++++++++++++++++++++++
>> hw/usb/meson.build | 3 +-
>> hw/usb/trace-events | 31 +
>> 6 files changed, 1855 insertions(+), 2 deletions(-) create mode 100644
>> hw/usb/redirect-server.c
>>
>> --
>> 2.43.0
>
>
> Patch 3 does not build on current master since
>
> 13d2f5e4b0 ("chardev: add CHR_EVENT_RESIZE")
>
> QEMUChrEvent gained a value and the switch does not handle it. I will
> fix it and send v5.
yes. That's an easy fix. Please let people take a look first before
sending a v6.
C.
© 2016 - 2026 Red Hat, Inc.