usb_claim_port() inserts a usb-hub when a device is plugged in and only one port is still free, so that more devices can follow. That is what a host controller with root ports wants.
It is wrong for a transport that carries exactly one device. The hub takes the last port, and the device that was being plugged in ends up behind the hub instead of on the port the controller watches. Add no_auto_hub for such a bus. It keeps the ports it registered, and -device fails with "no free ports" once they are used up. Signed-off-by: Jamin Lin <[email protected]> --- include/hw/usb/usb.h | 1 + hw/usb/bus.c | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/include/hw/usb/usb.h b/include/hw/usb/usb.h index cbd4711933..ab96812adb 100644 --- a/include/hw/usb/usb.h +++ b/include/hw/usb/usb.h @@ -484,6 +484,7 @@ struct USBBus { int busnr; int nfree; int nused; + bool no_auto_hub; QTAILQ_HEAD(, USBPort) free; QTAILQ_HEAD(, USBPort) used; QTAILQ_ENTRY(USBBus) next; diff --git a/hw/usb/bus.c b/hw/usb/bus.c index 5cc5ffec33..8a24b1837a 100644 --- a/hw/usb/bus.c +++ b/hw/usb/bus.c @@ -413,7 +413,8 @@ void usb_claim_port(USBDevice *dev, Error **errp) return; } } else { - if (bus->nfree == 1 && strcmp(object_get_typename(OBJECT(dev)), "usb-hub") != 0) { + if (bus->nfree == 1 && !bus->no_auto_hub && + strcmp(object_get_typename(OBJECT(dev)), "usb-hub") != 0) { /* Create a new hub and chain it on */ hub = USB_DEVICE(qdev_try_new("usb-hub")); if (hub) { -- 2.53.0
