Hi Jamin,
On 2026-08-28 11:04, Jamin Lin wrote:
Present the UDC gadget side to a USB host controller as a USB device
(TYPE_ASPEED_UDC_GADGET). This is a normal QEMU USB device, so it can be
attached to any USB host controller bus, not only the BMC's own EHCI. It
links back to its controller through the "udc" property.
This patch implements the control endpoint (EP0), which is enough for the
host to enumerate the gadget. Host control transfers are handled
asynchronously: the SETUP packet is mirrored into the SETUP data buffer,
the EP0 interrupt is raised and the host packet is parked (USB_RET_ASYNC).
The guest gadget driver then drives the data and status stages by writing
UDC_EP0_CTRL; that moves data to/from the driver's DMA buffer and completes
the parked packet back to the host.
SET_ADDRESS is the exception: it is applied synchronously, because the host
controller keeps the transfer bound to address 0 until it completes.
The gadget connects to / disconnects from the host bus when the driver
sets or clears the upstream-enable (pull-up) bit, and is detached on reset.
Signed-off-by: Jamin Lin <[email protected]>
---
include/hw/usb/aspeed-udc.h | 28 +++
hw/usb/aspeed-udc.c | 360 +++++++++++++++++++++++++++++++++++-
hw/usb/trace-events | 5 +
3 files changed, 390 insertions(+), 3 deletions(-)
diff --git a/include/hw/usb/aspeed-udc.h b/include/hw/usb/aspeed-udc.h
index 58fed5f9a2..ab9d016c61 100644
--- a/include/hw/usb/aspeed-udc.h
+++ b/include/hw/usb/aspeed-udc.h
@@ -10,11 +10,19 @@
#define HW_USB_ASPEED_UDC_H
#include "hw/core/sysbus.h"
+#include "hw/usb/usb.h"
#include "qom/object.h"
#define TYPE_ASPEED_UDC "aspeed.udc"
OBJECT_DECLARE_SIMPLE_TYPE(AspeedUDCState, ASPEED_UDC)
+/*
+ * The gadget side of the controller is presented to a USB host controller's
+ * bus as a single USB device that delegates back to the AspeedUDCState.
+ */
+#define TYPE_ASPEED_UDC_GADGET "aspeed.udc-gadget"
+OBJECT_DECLARE_SIMPLE_TYPE(AspeedUDCGadget, ASPEED_UDC_GADGET)
+
/*
* Register map: root/global block at 0x000 - 0x087, then one 0x10 byte bank
* per programmable endpoint from 0x200.
@@ -36,14 +44,34 @@ typedef struct AspeedUDCEP {
int index;
} AspeedUDCEP;
+struct AspeedUDCGadget {
+ USBDevice parent_obj;
+ AspeedUDCState *udc;
+};
+
struct AspeedUDCState {
SysBusDevice parent_obj;
MemoryRegion udc_container;
MemoryRegion root_mr;
+ MemoryRegion *dram_mr;
+ AddressSpace dram_as;
uint32_t regs[ASPEED_UDC_ROOT_NR_REGS];
AspeedUDCEP ep[ASPEED_UDC_NUM_EP];
qemu_irq irq;
+
+ /* gadget USB device bound to this controller (set at its realize) */
+ AspeedUDCGadget *usbgadget;
Do you mind exposing this as a link property (and using the
proper methods to set it)?
+
+ /*
+ * In-flight EP0 control transfer (host side), deferred until the guest
+ * gadget driver responds via MMIO.
+ */
+ USBPacket *ep0_packet;
+ uint32_t ep0_setup_len;
+ uint32_t ep0_offset;
+ uint8_t *ep0_data;
+ bool ep0_dir_in;
};