Xen-Devel Archive on lore.kernel.org
 help / color / mirror / Atom feed
From: Jamin Lin <jamin_lin@aspeedtech.com>
To: "berrange@redhat.com" <berrange@redhat.com>,
	"junjie.cao@linux.dev" <junjie.cao@linux.dev>,
	"kraxel@redhat.com" <kraxel@redhat.com>,
	"marcandre.lureau@redhat.com" <marcandre.lureau@redhat.com>,
	"clg@kaod.org" <clg@kaod.org>,
	"junjie.cao@intel.com" <junjie.cao@intel.com>,
	"Pierrick Bouvier" <pierrick.bouvier@oss.qualcomm.com>,
	"Peter Maydell" <peter.maydell@linaro.org>,
	"Kane Chen" <kane_chen@aspeedtech.com>,
	"Philippe Mathieu-Daudé" <philmd@oss.qualcomm.com>,
	"Tyrone Ting" <kfting@nuvoton.com>,
	"Hao Wu" <wuhaotsh@google.com>, "Zhao Liu" <zhao1.liu@intel.com>,
	"Richard Henderson" <richard.henderson@linaro.org>,
	"Helge Deller" <deller@gmx.de>,
	"Stefano Stabellini" <sstabellini@kernel.org>,
	"Anthony PERARD" <anthony@xenproject.org>,
	"Edgar E. Iglesias" <edgar.iglesias@gmail.com>,
	"open list:All patches CC here" <qemu-devel@nongnu.org>,
	"open list:ASPEED BMCs" <qemu-arm@nongnu.org>,
	"open list:X86 Xen CPUs" <xen-devel@lists.xenproject.org>
Cc: Jamin Lin <jamin_lin@aspeedtech.com>, Troy Lee <troy_lee@aspeedtech.com>
Subject: [PATCH v9 13/19] hw/usb/redirect-server: Announce the exported device
Date: Tue, 10 Nov 2026 07:28:38 +0000	[thread overview]
Message-ID: <20261110072818.2883349-14-jamin_lin@aspeedtech.com> (raw)
In-Reply-To: <20261110072818.2883349-1-jamin_lin@aspeedtech.com>

Send device_connect when a device is attached and the host has greeted
us, device_disconnect when it goes away, and handle the bus reset the
host sends before enumerating.

device_connect carries no identity. The peer asks the device itself with
GET_DESCRIPTOR as soon as it enumerates, so anything we put there would
be made up. The speed is real: it comes from the device on our port.

Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
---
 hw/usb/redirect-server.c | 136 ++++++++++++++++++++++++++++++++++++++-
 hw/usb/trace-events      |   6 ++
 2 files changed, 141 insertions(+), 1 deletion(-)

diff --git a/hw/usb/redirect-server.c b/hw/usb/redirect-server.c
index 5abaf7e01e..5a3b01c337 100644
--- a/hw/usb/redirect-server.c
+++ b/hw/usb/redirect-server.c
@@ -56,6 +56,7 @@
 #include "qemu/main-loop.h"
 #include "qemu/module.h"
 #include "migration/vmstate.h"
+#include "qemu/cutils.h"
 #include "hw/core/sysbus.h"
 #include "hw/usb/usb.h"
 #include "chardev/char-fe.h"
@@ -85,17 +86,91 @@ struct USBRedirServer {
     /* usbredir over the chardev */
     struct usbredirparser *parser;
     QEMUBH *chardev_close_bh;
+    QEMUBH *announce_bh;
     const uint8_t *read_buf;
     int read_buf_size;
     bool in_write;
     guint watch;
     bool host_connected;
+    bool device_announced;
 };
 
+/*
+ * The device is whatever USBDevice the user plugged into our port with
+ * "-device <device>,bus=<id>.0". NULL until then.
+ */
+static USBDevice *usbredir_server_device(USBRedirServer *s)
+{
+    return s->port.dev;
+}
+
+/*
+ * Device announcement
+ */
+
+static uint8_t usbredir_server_speed(USBDevice *device)
+{
+    switch (device->speed) {
+    case USB_SPEED_LOW:
+        return usb_redir_speed_low;
+    case USB_SPEED_FULL:
+        return usb_redir_speed_full;
+    default:
+        return usb_redir_speed_high;
+    }
+}
+
+static void usbredir_server_announce_bh(void *opaque)
+{
+    USBRedirServer *s = opaque;
+    USBDevice *device = usbredir_server_device(s);
+    struct usb_redir_device_connect_header conn = {};
+
+    if (!s->host_connected || s->device_announced ||
+        !device || !device->attached) {
+        return;
+    }
+    s->device_announced = true;
+    conn.speed = usbredir_server_speed(device);
+
+    usbredirparser_send_device_connect(s->parser, &conn);
+    usbredirparser_do_write(s->parser);
+}
+
 /*
  * USB port ops
  */
 
+static void usbredir_server_port_attach(USBPort *port)
+{
+    USBRedirServer *s = port->opaque;
+
+    trace_usbredir_server_attach();
+
+    /*
+     * usb_attach() sets the state to ATTACHED after this returns.
+     * A device needs DEFAULT state before it can serve a request.
+     * The BH runs after usb_attach(), so the device stays in DEFAULT.
+     */
+    qemu_bh_schedule(s->announce_bh);
+}
+
+static void usbredir_server_port_detach(USBPort *port)
+{
+    USBRedirServer *s = port->opaque;
+
+    trace_usbredir_server_detach(s->device_announced);
+
+    qemu_bh_cancel(s->announce_bh);
+
+    if (s->host_connected && s->parser && s->device_announced) {
+        trace_usbredir_server_disconnect();
+        usbredirparser_send_device_disconnect(s->parser);
+        usbredirparser_do_write(s->parser);
+    }
+    s->device_announced = false;
+}
+
 static void usbredir_server_port_child_detach(USBPort *port, USBDevice *child)
 {
     /* We only export the device on our own port. Nothing to do. */
@@ -107,6 +182,8 @@ static void usbredir_server_port_wakeup(USBPort *port)
 }
 
 static USBPortOps usbredir_server_port_ops = {
+    .attach = usbredir_server_port_attach,
+    .detach = usbredir_server_port_detach,
     .child_detach = usbredir_server_port_child_detach,
     .wakeup = usbredir_server_port_wakeup,
 };
@@ -211,13 +288,53 @@ static int usbredir_server_write(void *priv, uint8_t *data, int count)
     return ret;
 }
 
-/* The remote host greets us once the socket is up. */
+/*
+ * usbredirparser message callbacks
+ */
+
 static void usbredir_server_hello(void *priv,
                                   struct usb_redir_hello_header *hello)
 {
     USBRedirServer *s = priv;
+    char version[sizeof(hello->version) + 1];
+
+    pstrcpy(version, sizeof(version), hello->version);
+    trace_usbredir_server_hello(version);
 
     s->host_connected = true;
+    qemu_bh_schedule(s->announce_bh);
+}
+
+static void usbredir_server_reset(void *priv)
+{
+    USBRedirServer *s = priv;
+    USBDevice *device = usbredir_server_device(s);
+
+    trace_usbredir_server_bus_reset(device && device->attached);
+    usb_device_reset(device);
+}
+
+static void usbredir_server_filter_reject(void *priv)
+{
+    trace_usbredir_server_filter_reject();
+}
+
+static void usbredir_server_filter_filter(void *priv,
+    struct usbredirfilter_rule *rules, int rules_count)
+{
+    /* We accept any host. The callback owns the rules, so free them. */
+    free(rules);
+}
+
+static void usbredir_server_device_disconnect_ack(void *priv)
+{
+    /* The host saw our device_disconnect. Nothing to do. */
+}
+
+static void usbredir_server_interface_info(void *priv,
+    struct usb_redir_interface_info_header *hdr)
+{
+    /* The host should not send this to a device. Nothing to do. */
 }
 
 /*
@@ -241,6 +358,14 @@ static void usbredir_server_create_parser(USBRedirServer *s)
 
     /* Callbacks for messages the remote host sends to us */
     s->parser->hello_func = usbredir_server_hello;
+    s->parser->reset_func = usbredir_server_reset;
+
+    /* The parser calls these directly, so they must not be NULL. */
+    s->parser->filter_reject_func = usbredir_server_filter_reject;
+    s->parser->filter_filter_func = usbredir_server_filter_filter;
+    s->parser->device_disconnect_ack_func =
+        usbredir_server_device_disconnect_ack;
+    s->parser->interface_info_func = usbredir_server_interface_info;
 
     /* Capabilities: 64-bit IDs, connect_device_version, ep_info sizes */
     usbredirparser_caps_set_cap(caps, usb_redir_cap_connect_device_version);
@@ -268,7 +393,9 @@ static void usbredir_server_create_parser(USBRedirServer *s)
 static void usbredir_server_destroy_parser(USBRedirServer *s)
 {
     s->host_connected = false;
+    s->device_announced = false;
 
+    qemu_bh_cancel(s->announce_bh);
     g_clear_handle_id(&s->watch, g_source_remove);
 
     if (s->parser) {
@@ -372,6 +499,8 @@ static void usbredir_server_realize(DeviceState *dev, Error **errp)
 
     s->chardev_close_bh = qemu_bh_new_guarded(usbredir_server_chardev_close_bh,
                                               s, &dev->mem_reentrancy_guard);
+    s->announce_bh = qemu_bh_new_guarded(usbredir_server_announce_bh, s,
+                                         &dev->mem_reentrancy_guard);
 
     qemu_chr_fe_set_handlers(&s->cs,
                              usbredir_server_chardev_can_read,
@@ -391,6 +520,11 @@ static void usbredir_server_unrealize(DeviceState *dev)
         qemu_bh_delete(s->chardev_close_bh);
         s->chardev_close_bh = NULL;
     }
+
+    if (s->announce_bh) {
+        qemu_bh_delete(s->announce_bh);
+        s->announce_bh = NULL;
+    }
 }
 
 static const Property usbredir_server_props[] = {
diff --git a/hw/usb/trace-events b/hw/usb/trace-events
index d141661673..075a9d9eae 100644
--- a/hw/usb/trace-events
+++ b/hw/usb/trace-events
@@ -399,3 +399,9 @@ usbredir_server_chardev_open(void) "chardev opened"
 usbredir_server_chardev_close(void) "chardev closed"
 usbredir_server_write_recursion(void) "recursive write, leaving it queued"
 usbredir_server_log(const char *msg) "%s"
+usbredir_server_hello(const char *version) "peer is %s"
+usbredir_server_attach(void) "device attached"
+usbredir_server_detach(bool announced) "device detached, was announced %d"
+usbredir_server_disconnect(void) "device_disconnect sent"
+usbredir_server_bus_reset(bool attached) "bus reset, attached %d"
+usbredir_server_filter_reject(void) "host rejected our device"
-- 
2.43.0


  parent reply	other threads:[~2026-11-10  7:29 UTC|newest]

Thread overview: 20+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-11-10  7:28 [PATCH v9 00/19] hw/usb: Add a usbredir server transport Jamin Lin
2026-11-10  7:28 ` [PATCH v9 01/19] hw/usb/bus: Add an auto-hub flag to the USB bus Jamin Lin
2026-11-10  7:28 ` [PATCH v9 02/19] hw/usb/hcd-xhci: Add an auto-hub property and leave it off Jamin Lin
2026-11-10  7:28 ` [PATCH v9 03/19] hw/usb/hcd-ehci: " Jamin Lin
2026-11-10  7:28 ` [PATCH v9 04/19] hw/usb/hcd-uhci: " Jamin Lin
2026-11-10  7:28 ` [PATCH v9 05/19] hw/usb/hcd-ohci: " Jamin Lin
2026-11-10  7:28 ` [PATCH v9 06/19] hw/usb/hcd-dwc2: " Jamin Lin
2026-11-10  7:28 ` [PATCH v9 07/19] hw/usb/xen-usb: Do not insert an automatic hub Jamin Lin
2026-11-10  7:28 ` [PATCH v9 08/19] hw/arm/npcm7xx: Keep the " Jamin Lin
2026-11-10  7:28 ` [PATCH v9 09/19] hw/usb/bus: Turn off the automatic hub by default Jamin Lin
2026-11-10  7:28 ` [PATCH v9 10/19] docs/system/devices/usb: Note the automatic hub change Jamin Lin
2026-11-10  7:28 ` [PATCH v9 11/19] hw/usb/redirect-server: Add a usbredir server device Jamin Lin
2026-11-10  7:28 ` [PATCH v9 12/19] hw/usb/redirect-server: Connect usbredirparser to a chardev Jamin Lin
2026-11-10  7:28 ` Jamin Lin [this message]
2026-11-10  7:28 ` [PATCH v9 14/19] hw/usb/redirect-server: Implement control transfers Jamin Lin
2026-11-10  7:28 ` [PATCH v9 15/19] hw/usb/redirect-server: Send device and interface information Jamin Lin
2026-11-10  7:28 ` [PATCH v9 16/19] hw/usb/redirect-server: Implement bulk and interrupt transfers Jamin Lin
2026-11-10  7:28 ` [PATCH v9 17/19] hw/usb/redirect-server: Stream interrupt IN endpoints Jamin Lin
2026-11-10  7:28 ` [PATCH v9 18/19] hw/usb/redirect-server: Implement isochronous OUT transfers Jamin Lin
2026-11-10  7:28 ` [PATCH v9 19/19] hw/arm/aspeed: Enable the usbredir server transport 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=20261110072818.2883349-14-jamin_lin@aspeedtech.com \
    --to=jamin_lin@aspeedtech.com \
    --cc=anthony@xenproject.org \
    --cc=berrange@redhat.com \
    --cc=clg@kaod.org \
    --cc=deller@gmx.de \
    --cc=edgar.iglesias@gmail.com \
    --cc=junjie.cao@intel.com \
    --cc=junjie.cao@linux.dev \
    --cc=kane_chen@aspeedtech.com \
    --cc=kfting@nuvoton.com \
    --cc=kraxel@redhat.com \
    --cc=marcandre.lureau@redhat.com \
    --cc=peter.maydell@linaro.org \
    --cc=philmd@oss.qualcomm.com \
    --cc=pierrick.bouvier@oss.qualcomm.com \
    --cc=qemu-arm@nongnu.org \
    --cc=qemu-devel@nongnu.org \
    --cc=richard.henderson@linaro.org \
    --cc=sstabellini@kernel.org \
    --cc=troy_lee@aspeedtech.com \
    --cc=wuhaotsh@google.com \
    --cc=xen-devel@lists.xenproject.org \
    --cc=zhao1.liu@intel.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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox