From: Jamin Lin <jamin_lin@aspeedtech.com>
To: "Cédric Le Goater" <clg@kaod.org>,
"Peter Maydell" <peter.maydell@linaro.org>,
"Steven Lee" <steven_lee@aspeedtech.com>,
"Troy Lee" <leetroy@gmail.com>,
"Kane Chen" <kane_chen@aspeedtech.com>,
"Andrew Jeffery" <andrew@codeconstruct.com.au>,
"Joel Stanley" <joel@jms.id.au>,
"open list:ASPEED BMCs" <qemu-arm@nongnu.org>,
"open list:All patches CC here" <qemu-devel@nongnu.org>
Cc: Jamin Lin <jamin_lin@aspeedtech.com>, Troy Lee <troy_lee@aspeedtech.com>
Subject: [PATCH v3 2/8] hw/usb/redirect-server: Add a usbredir server device
Date: Mon, 12 Oct 2026 02:16:37 +0000 [thread overview]
Message-ID: <20261012021634.2006424-3-jamin_lin@aspeedtech.com> (raw)
In-Reply-To: <20261012021634.2006424-1-jamin_lin@aspeedtech.com>
Add "x-usb-redir-server". It exports a USB device from this QEMU to a
USB host in another QEMU, using the usbredir protocol. The other side is
the existing "usb-redir" device.
The name has an "x-" prefix because the device is experimental. It has
to sit on the sysbus so that qdev can find the USB bus it provides, and
that may change later, so the name is not fixed yet.
The exported device is plugged in with "-device <dev>,bus=<id>.0". So we
have to provide a USB bus. To find that bus, qdev starts at the main
system bus and walks down the tree. A device that is not on a bus is not
in the tree, so the bus it provides cannot be found. We have to sit on
the main system bus. That makes this a sysbus device, even though it has
no MMIO and no IRQ.
usbredir carries one device, not a bus. A hub cannot be exported because
the protocol has no device address field, so only the device on the
first port is redirected. To export several devices, run one
x-usb-redir-server per device, each with its own chardev.
The link to the remote host is a chardev, so this device cannot be
migrated. Its VMStateDescription says so with unmigratable.
Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
---
hw/usb/redirect-server.c | 143 +++++++++++++++++++++++++++++++++++++++
hw/usb/meson.build | 3 +-
2 files changed, 145 insertions(+), 1 deletion(-)
create mode 100644 hw/usb/redirect-server.c
diff --git a/hw/usb/redirect-server.c b/hw/usb/redirect-server.c
new file mode 100644
index 0000000000..bc883add0e
--- /dev/null
+++ b/hw/usb/redirect-server.c
@@ -0,0 +1,143 @@
+/*
+ * USB redirector, server side
+ *
+ * Copyright (c) 2026 ASPEED Technology Inc.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * 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.
+ *
+ * Architecture. 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 file)
+ * | ^
+ * 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
+ *
+ * This file 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 this file 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.
+ *
+ * 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.
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "qemu/module.h"
+#include "migration/vmstate.h"
+#include "hw/core/sysbus.h"
+#include "hw/usb/usb.h"
+#include "qom/object.h"
+
+#define TYPE_USB_REDIR_SERVER "x-usb-redir-server"
+OBJECT_DECLARE_SIMPLE_TYPE(USBRedirServer, USB_REDIR_SERVER)
+
+struct USBRedirServer {
+ SysBusDevice parent_obj;
+
+ /* USB bus */
+ USBBus bus;
+ USBPort port;
+};
+
+/*
+ * USB port ops
+ */
+
+static void usbredir_server_port_child_detach(USBPort *port, USBDevice *child)
+{
+ /* We only export the device on our own port. Nothing to do. */
+}
+
+static void usbredir_server_port_wakeup(USBPort *port)
+{
+ /* We do not pass remote wakeup to the host. Nothing to do. */
+}
+
+static USBPortOps usbredir_server_port_ops = {
+ .child_detach = usbredir_server_port_child_detach,
+ .wakeup = usbredir_server_port_wakeup,
+};
+
+/*
+ * USB bus ops
+ */
+
+static USBBusOps usbredir_server_bus_ops = {
+};
+
+/*
+ * Device registration
+ */
+
+static void usbredir_server_realize(DeviceState *dev, Error **errp)
+{
+ USBRedirServer *s = USB_REDIR_SERVER(dev);
+
+ /* One port: usbredir carries a single device. */
+ usb_bus_new(&s->bus, sizeof(s->bus), &usbredir_server_bus_ops, dev);
+ s->bus.no_auto_hub = true;
+ usb_register_port(&s->bus, &s->port, s, 0, &usbredir_server_port_ops,
+ USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL |
+ USB_SPEED_MASK_HIGH);
+}
+
+/*
+ * The link to the remote host is a chardev, and we cannot migrate
+ * that. So this device cannot be migrated either.
+ */
+static const VMStateDescription vmstate_usbredir_server = {
+ .name = TYPE_USB_REDIR_SERVER,
+ .unmigratable = 1,
+};
+
+static void usbredir_server_class_init(ObjectClass *klass, const void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->desc = "USB Redirection Server";
+ dc->realize = usbredir_server_realize;
+ dc->vmsd = &vmstate_usbredir_server;
+ set_bit(DEVICE_CATEGORY_USB, dc->categories);
+}
+
+static const TypeInfo usbredir_server_types[] = {
+ {
+ .name = TYPE_USB_REDIR_SERVER,
+ .parent = TYPE_DYNAMIC_SYS_BUS_DEVICE,
+ .instance_size = sizeof(USBRedirServer),
+ .class_init = usbredir_server_class_init,
+ },
+};
+module_obj(TYPE_USB_REDIR_SERVER);
+module_kconfig(USB);
+
+DEFINE_TYPES(usbredir_server_types)
diff --git a/hw/usb/meson.build b/hw/usb/meson.build
index 429dcd6a24..0061b935e6 100644
--- a/hw/usb/meson.build
+++ b/hw/usb/meson.build
@@ -78,7 +78,8 @@ endif
if usbredir.found()
usbredir_ss = ss.source_set()
usbredir_ss.add(when: 'CONFIG_USB',
- if_true: [usbredir, files('redirect.c', 'quirks.c')])
+ if_true: [usbredir, files('redirect.c', 'quirks.c',
+ 'redirect-server.c')])
hw_usb_modules += {'redirect': usbredir_ss}
endif
--
2.53.0
next prev parent reply other threads:[~2026-10-12 2:17 UTC|newest]
Thread overview: 17+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-12 2:16 [PATCH v3 0/8] hw/usb: Add a usbredir server transport Jamin Lin
2026-10-12 2:16 ` [PATCH v3 1/8] hw/usb/bus: Let a bus opt out of automatic hub insertion Jamin Lin
2026-10-12 2:16 ` Jamin Lin [this message]
2026-10-12 10:01 ` [PATCH v3 2/8] hw/usb/redirect-server: Add a usbredir server device marcandre.lureau
2026-10-12 2:16 ` [PATCH v3 3/8] hw/usb/redirect-server: Connect usbredirparser to a chardev Jamin Lin
2026-10-12 2:16 ` [PATCH v3 4/8] hw/usb/redirect-server: Announce the exported device Jamin Lin
2026-10-12 10:01 ` marcandre.lureau
2026-10-12 2:16 ` [PATCH v3 5/8] hw/usb/redirect-server: Implement control transfers Jamin Lin
2026-10-12 10:01 ` marcandre.lureau
2026-10-13 1:30 ` Jamin Lin
2026-10-12 2:16 ` [PATCH v3 6/8] hw/usb/redirect-server: Implement bulk and interrupt transfers Jamin Lin
2026-10-12 10:01 ` marcandre.lureau
2026-10-12 2:16 ` [PATCH v3 7/8] hw/usb/redirect-server: Stream interrupt IN endpoints Jamin Lin
2026-10-12 10:01 ` marcandre.lureau
2026-10-12 2:16 ` [PATCH v3 8/8] hw/arm/aspeed: Enable the usbredir server transport Jamin Lin
2026-10-12 10:01 ` marcandre.lureau
2026-10-12 2:19 ` [PATCH v3 0/8] hw/usb: Add a " Jamin Lin
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261012021634.2006424-3-jamin_lin@aspeedtech.com \
--to=jamin_lin@aspeedtech.com \
--cc=andrew@codeconstruct.com.au \
--cc=clg@kaod.org \
--cc=joel@jms.id.au \
--cc=kane_chen@aspeedtech.com \
--cc=leetroy@gmail.com \
--cc=peter.maydell@linaro.org \
--cc=qemu-arm@nongnu.org \
--cc=qemu-devel@nongnu.org \
--cc=steven_lee@aspeedtech.com \
--cc=troy_lee@aspeedtech.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.