From ba68bd4190ad5d27171f0f803072fc237aed5cfc Mon Sep 17 00:00:00 2001 From: Xiaoguang Wu Date: Fri, 28 Sep 2018 22:01:56 +0800 Subject: [PATCH] DM USB: xHCI: fix enumeration error after rebooting When the physical USB device is disconnected before DM's emulation is ready, the virtual connection state is not cleared properly. This will cause the DM refuse to do emulation for future physical connection. This patch clears those states mentioned above and hence fix the issue. Signed-off-by: Xiaoguang Wu Reviewed-by: Liang Yang Acked-by: Yu Wang Tracked-On: #1367 --- devicemodel/hw/pci/xhci.c | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/devicemodel/hw/pci/xhci.c b/devicemodel/hw/pci/xhci.c index 349d63b4d..c28e08a94 100644 --- a/devicemodel/hw/pci/xhci.c +++ b/devicemodel/hw/pci/xhci.c @@ -631,7 +631,7 @@ pci_xhci_native_usb_dev_disconn_cb(void *hci_data, void *dev_data) struct usb_native_devinfo di; struct usb_dev *udev; uint8_t port, slot; - uint8_t status; + uint16_t status; int need_intr = 1; assert(hci_data); @@ -646,8 +646,8 @@ pci_xhci_native_usb_dev_disconn_cb(void *hci_data, void *dev_data) return -1; } - status = VPORT_STATE(xdev->port_map_tbl[di.bus][di.port]); - if (status == VPORT_HUB_CONNECTED) { + status = xdev->port_map_tbl[di.bus][di.port]; + if (VPORT_STATE(status) == VPORT_HUB_CONNECTED) { xdev->port_map_tbl[di.bus][di.port] = VPORT_NUM_STATE(VPORT_ASSIGNED, 0); return 0; @@ -679,7 +679,23 @@ pci_xhci_native_usb_dev_disconn_cb(void *hci_data, void *dev_data) } } - if (port == XHCI_MAX_DEVS + 1) { + if (port > XHCI_MAX_DEVS) { + if (VPORT_STATE(status) == VPORT_CONNECTED && + VPORT_NUM(status) > 0) { + /* + * When this place is reached, it means the physical + * USB device is disconnected before the emulation + * procedure is started. The related states should be + * cleared for future connecting. + */ + UPRINTF(LFTL, "disconnect VPORT_CONNECTED device: " + "%d-%d vport %d\r\n", di.bus, di.port, + VPORT_NUM(status)); + pci_xhci_disconnect_port(xdev, VPORT_NUM(status), 0); + xdev->port_map_tbl[di.bus][di.port] = VPORT_NUM_STATE( + VPORT_ASSIGNED, 0); + } + UPRINTF(LFTL, "fail to find physical port %d\r\n", di.port); return -1; }