[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[RESEND PATCH 09/10] usb-hub: Add support for v2.0 hubs
From: |
Guenter Roeck |
Subject: |
[RESEND PATCH 09/10] usb-hub: Add support for v2.0 hubs |
Date: |
Tue, 12 Nov 2024 09:01:51 -0800 |
When adding a high speed USB device to the USB hub supported by qemu,
it is added in full speed mode. Here is an example for a storage device.
/: Bus 001.Port 001: Dev 001, Class=root_hub, Driver=platform-uhci/2p, 12M
|__ Port 002: Dev 002, If 0, Class=Hub, Driver=hub/8p, 12M
|__ Port 001: Dev 003, If 0, Class=Human Interface Device,
Driver=usbhid, 12M
|__ Port 002: Dev 004, If 0, Class=Human Interface Device,
Driver=usbhid, 12M
|__ Port 003: Dev 005, If 0, Class=Mass Storage, Driver=usb-storage, 12M
This also triggers messages such as
usb 1-2.3: new full-speed USB device number 5 using platform-uhci
usb 1-2.3: not running at top speed; connect to a high speed hub
when such devices are instantiated in the host (example from Linux).
Add basic support for USB v2.0 hubs to solve the problem. The usb_version
device parameter configures the USB version; version 1 is default for
compatibility reasons. Example:
-device usb-hub,bus=usb-bus.1,port=1,usb_version=2
This command line parameter can be used to attach devices to the hub in
high speed mode, as seen in the following example.
/: Bus 002.Port 001: Dev 001, Class=root_hub, Driver=ehci-platform/6p, 480M
|__ Port 001: Dev 002, If 0, Class=Hub, Driver=hub/8p, 480M
|__ Port 002: Dev 004, If 0, Class=Mass Storage, Driver=usb-storage,
480M
and
usb 2-1.2: new high-speed USB device number 4 using ehci-platform
usb 2-1.2: New USB device found, idVendor=46f4, idProduct=0001, bcdDevice= 0.00
To distinguish v1 from v2 instantiated hubs, the device version is set to
2.01 (from 1.01) if the hub ist instantiated as USB v2 hub. The product
name is set to "QEMU USB v2.0 Hub".
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
---
Changes since RFC:
- New patch
hw/usb/dev-hub.c | 84 +++++++++++++++++++++++++++++++++++++++++++-----
1 file changed, 76 insertions(+), 8 deletions(-)
diff --git a/hw/usb/dev-hub.c b/hw/usb/dev-hub.c
index 06e9537d03..4da91d151c 100644
--- a/hw/usb/dev-hub.c
+++ b/hw/usb/dev-hub.c
@@ -46,6 +46,7 @@ struct USBHubState {
USBDevice dev;
USBEndpoint *intr;
uint32_t num_ports;
+ uint32_t usb_version;
bool port_power;
QEMUTimer *port_timer;
USBHubPort ports[MAX_PORTS];
@@ -100,12 +101,14 @@ OBJECT_DECLARE_SIMPLE_TYPE(USBHubState, USB_HUB)
enum {
STR_MANUFACTURER = 1,
STR_PRODUCT,
+ STR_PRODUCT_V2,
STR_SERIALNUMBER,
};
static const USBDescStrings desc_strings = {
[STR_MANUFACTURER] = "QEMU",
[STR_PRODUCT] = "QEMU USB Hub",
+ [STR_PRODUCT_V2] = "QEMU USB v2.0 Hub",
[STR_SERIALNUMBER] = "314159",
};
@@ -123,6 +126,20 @@ static const USBDescIface desc_iface_hub = {
}
};
+static const USBDescIface desc_iface_hub_v2 = {
+ .bInterfaceNumber = 0,
+ .bNumEndpoints = 1,
+ .bInterfaceClass = USB_CLASS_HUB,
+ .eps = (USBDescEndpoint[]) {
+ {
+ .bEndpointAddress = USB_DIR_IN | 0x01,
+ .bmAttributes = USB_ENDPOINT_XFER_INT,
+ .wMaxPacketSize = 512,
+ .bInterval = 10,
+ },
+ }
+};
+
static const USBDescDevice desc_device_hub = {
.bcdUSB = 0x0110,
.bDeviceClass = USB_CLASS_HUB,
@@ -140,6 +157,23 @@ static const USBDescDevice desc_device_hub = {
},
};
+static const USBDescDevice desc_device_hub_v2 = {
+ .bcdUSB = 0x0200,
+ .bDeviceClass = USB_CLASS_HUB,
+ .bMaxPacketSize0 = 64,
+ .bNumConfigurations = 1,
+ .confs = (USBDescConfig[]) {
+ {
+ .bNumInterfaces = 1,
+ .bConfigurationValue = 1,
+ .bmAttributes = USB_CFG_ATT_ONE | USB_CFG_ATT_SELFPOWER |
+ USB_CFG_ATT_WAKEUP,
+ .nif = 1,
+ .ifs = &desc_iface_hub_v2,
+ },
+ },
+};
+
static const USBDesc desc_hub = {
.id = {
.idVendor = 0x0409,
@@ -153,6 +187,20 @@ static const USBDesc desc_hub = {
.str = desc_strings,
};
+static const USBDesc desc_hub_v2 = {
+ .id = {
+ .idVendor = 0x0409,
+ .idProduct = 0x55aa,
+ .bcdDevice = 0x0201,
+ .iManufacturer = STR_MANUFACTURER,
+ .iProduct = STR_PRODUCT_V2,
+ .iSerialNumber = STR_SERIALNUMBER,
+ },
+ .full = &desc_device_hub,
+ .high = &desc_device_hub_v2,
+ .str = desc_strings,
+};
+
static const uint8_t qemu_hub_hub_descriptor[] =
{
0x00, /* u8 bLength; patched in later */
@@ -195,15 +243,20 @@ static bool usb_hub_port_clear(USBHubPort *port, uint16_t
status)
return usb_hub_port_change(port, status);
}
-static bool usb_hub_port_update(USBHubPort *port)
+static bool usb_hub_port_update(USBHubState *s, USBHubPort *port)
{
bool notify = false;
if (port->port.dev && port->port.dev->attached) {
notify = usb_hub_port_set(port, PORT_STAT_CONNECTION);
- if (port->port.dev->speed == USB_SPEED_LOW) {
+ if (s->usb_version == 2 && port->port.dev->speed == USB_SPEED_HIGH) {
+ usb_hub_port_clear(port, PORT_STAT_LOW_SPEED);
+ usb_hub_port_set(port, PORT_STAT_HIGH_SPEED);
+ } else if (port->port.dev->speed == USB_SPEED_LOW) {
+ usb_hub_port_clear(port, PORT_STAT_HIGH_SPEED);
usb_hub_port_set(port, PORT_STAT_LOW_SPEED);
} else {
+ usb_hub_port_clear(port, PORT_STAT_HIGH_SPEED);
usb_hub_port_clear(port, PORT_STAT_LOW_SPEED);
}
}
@@ -217,7 +270,7 @@ static void usb_hub_port_update_timer(void *opaque)
int i;
for (i = 0; i < s->num_ports; i++) {
- notify |= usb_hub_port_update(&s->ports[i]);
+ notify |= usb_hub_port_update(s, &s->ports[i]);
}
if (notify) {
usb_wakeup(s->intr, 0);
@@ -230,7 +283,7 @@ static void usb_hub_attach(USBPort *port1)
USBHubPort *port = &s->ports[port1->index];
trace_usb_hub_attach(s->dev.addr, port1->index + 1);
- usb_hub_port_update(port);
+ usb_hub_port_update(s, port);
usb_wakeup(s->intr, 0);
}
@@ -318,7 +371,7 @@ static void usb_hub_handle_reset(USBDevice *dev)
port->wPortStatus = 0;
port->wPortChange = 0;
usb_hub_port_set(port, PORT_STAT_POWER);
- usb_hub_port_update(port);
+ usb_hub_port_update(s, port);
}
}
@@ -593,6 +646,19 @@ static void usb_hub_realize(USBDevice *dev, Error **errp)
USBHubPort *port;
int i;
+ switch (s->usb_version) {
+ case 1:
+ dev->usb_desc = &desc_hub;
+ break;
+ case 2:
+ dev->usb_desc = &desc_hub_v2;
+ break;
+ default:
+ error_setg(errp, "Unsupported usb version %d for usb hub",
+ s->usb_version);
+ return;
+ }
+
if (s->num_ports < 1 || s->num_ports > MAX_PORTS) {
error_setg(errp, "num_ports (%d) out of range (1..%d)",
s->num_ports, MAX_PORTS);
@@ -613,7 +679,8 @@ static void usb_hub_realize(USBDevice *dev, Error **errp)
port = &s->ports[i];
usb_register_port(usb_bus_from_device(dev),
&port->port, s, i, &usb_hub_port_ops,
- USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL);
+ USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL |
+ ((s->usb_version == 2) ? USB_SPEED_MASK_HIGH : 0));
usb_port_location(&port->port, dev->port, i+1);
}
usb_hub_handle_reset(dev);
@@ -650,7 +717,7 @@ static const VMStateDescription vmstate_usb_hub_port_timer
= {
static const VMStateDescription vmstate_usb_hub = {
.name = "usb-hub",
- .version_id = 1,
+ .version_id = 2,
.minimum_version_id = 1,
.fields = (const VMStateField[]) {
VMSTATE_USB_DEVICE(dev, USBHubState),
@@ -667,6 +734,7 @@ static const VMStateDescription vmstate_usb_hub = {
static Property usb_hub_properties[] = {
DEFINE_PROP_UINT32("ports", USBHubState, num_ports, 8),
DEFINE_PROP_BOOL("port-power", USBHubState, port_power, false),
+ DEFINE_PROP_UINT32("usb_version", USBHubState, usb_version, 1),
DEFINE_PROP_END_OF_LIST(),
};
@@ -677,12 +745,12 @@ static void usb_hub_class_initfn(ObjectClass *klass, void
*data)
uc->realize = usb_hub_realize;
uc->product_desc = "QEMU USB Hub";
- uc->usb_desc = &desc_hub;
uc->find_device = usb_hub_find_device;
uc->handle_reset = usb_hub_handle_reset;
uc->handle_control = usb_hub_handle_control;
uc->handle_data = usb_hub_handle_data;
uc->unrealize = usb_hub_unrealize;
+ uc->handle_attach = usb_desc_attach;
set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
dc->fw_name = "hub";
dc->vmsd = &vmstate_usb_hub;
--
2.45.2
- [RESEND PATCH 00/10] usb/uhci: Add UHCI sysbus support, and enable for AST machines, Guenter Roeck, 2024/11/12
- [RESEND PATCH 01/10] usb/uhci: checkpatch cleanup, Guenter Roeck, 2024/11/12
- [RESEND PATCH 02/10] usb/uhci: Introduce and use register defines, Guenter Roeck, 2024/11/12
- [RESEND PATCH 04/10] usb/uhci: enlarge uhci memory space, Guenter Roeck, 2024/11/12
- [RESEND PATCH 10/10] usb-hub: Fix handling port power control messages, Guenter Roeck, 2024/11/12
- [RESEND PATCH 06/10] usb/uhci: Add aspeed specific read and write functions, Guenter Roeck, 2024/11/12
- [RESEND PATCH 03/10] usb/uhci: Move PCI-related code into a separate file, Guenter Roeck, 2024/11/12
- [RESEND PATCH 07/10] aspeed: Add uhci support for ast2600, Guenter Roeck, 2024/11/12
- [RESEND PATCH 08/10] aspeed: Add uhci support for ast2400 and ast2500, Guenter Roeck, 2024/11/12
- [RESEND PATCH 09/10] usb-hub: Add support for v2.0 hubs,
Guenter Roeck <=
- [RESEND PATCH 05/10] usb/uhci: Add support for usb-uhci-sysbus, Guenter Roeck, 2024/11/12