Navigation Menu

Skip to content

Commit

Permalink
DM USB: xHCI: fix USB hub disconnection issue
Browse files Browse the repository at this point in the history
When USB hub is disconnected, its connection status is not cleared
in the DM, this defect will cause the related assigned port could
not be used any more.

This patch is used fix this issue.

Signed-off-by: Xiaoguang Wu <xiaoguang.wu@intel.com>
Reviewed-by: Liang Yang <liang3.yang@intel.com>
Acked-by: Yu Wang <yu1.wang@intel.com>
Tracked-On: #1365
  • Loading branch information
xiaoguangwu authored and lijinxia committed Sep 29, 2018
1 parent 0d4a88e commit 6c9bae6
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 13 deletions.
38 changes: 29 additions & 9 deletions devicemodel/hw/pci/xhci.c
Expand Up @@ -630,7 +630,7 @@ pci_xhci_native_usb_dev_disconn_cb(void *hci_data, void *dev_data)
struct pci_xhci_dev_emu *edev;
struct usb_native_devinfo di;
struct usb_dev *udev;
uint8_t port, slot, native_port;
uint8_t port, slot;
uint8_t status;
int need_intr = 1;

Expand All @@ -640,34 +640,54 @@ pci_xhci_native_usb_dev_disconn_cb(void *hci_data, void *dev_data)
xdev = hci_data;
assert(xdev->devices);

native_port = *((uint8_t *)dev_data);
if (!pci_xhci_is_valid_portnum(native_port)) {
UPRINTF(LFTL, "invalid physical port %d\r\n", native_port);
di = *((struct usb_native_devinfo *)dev_data);
if (!pci_xhci_is_valid_portnum(di.port)) {
UPRINTF(LFTL, "invalid physical port %d\r\n", di.port);
return -1;
}

status = VPORT_STATE(xdev->port_map_tbl[di.bus][di.port]);
if (status == VPORT_HUB_CONNECTED) {
xdev->port_map_tbl[di.bus][di.port] =
VPORT_NUM_STATE(VPORT_ASSIGNED, 0);
return 0;
}

for (port = 1; port <= XHCI_MAX_DEVS; ++port) {
edev = xdev->devices[port];
if (!edev)
continue;

udev = edev->dev_instance;
if (udev->info.port == native_port) {
di = udev->info;
break;
if (udev->info.port == di.port) {
int old_t, new_t;
uint8_t old_ports[7]; /* max USB hub tiers are 7 */
uint8_t new_ports[7];

/* get tiers and port info */
old_t = libusb_get_port_numbers(udev->info.priv_data,
old_ports, sizeof(old_ports));
new_t = libusb_get_port_numbers(di.priv_data,
new_ports, sizeof(new_ports));

if (old_t == new_t &&
!memcmp(old_ports, new_ports, old_t)) {
di = udev->info;
break;
}
UPRINTF(LFTL, "multi-hub is not supported yet\r\n");
}
}

if (port == XHCI_MAX_DEVS + 1) {
UPRINTF(LFTL, "fail to find physical port %d\r\n", native_port);
UPRINTF(LFTL, "fail to find physical port %d\r\n", di.port);
return -1;
}

for (slot = 1; slot < XHCI_MAX_SLOTS; ++slot)
if (xdev->slots[slot] == edev)
break;

status = VPORT_STATE(xdev->port_map_tbl[di.bus][di.port]);
assert(status == VPORT_EMULATED || status == VPORT_CONNECTED);
xdev->port_map_tbl[di.bus][di.port] = VPORT_NUM_STATE(VPORT_ASSIGNED,
0);
Expand Down
19 changes: 15 additions & 4 deletions devicemodel/hw/platform/usb_pmapper.c
Expand Up @@ -1176,7 +1176,8 @@ static int
usb_dev_native_sys_disconn_cb(struct libusb_context *ctx, struct libusb_device
*ldev, libusb_hotplug_event event, void *pdata)
{
uint8_t port;
struct libusb_device_descriptor d;
struct usb_native_devinfo di;
uint16_t pport;
uint16_t pbus;
int rc;
Expand All @@ -1188,16 +1189,26 @@ usb_dev_native_sys_disconn_cb(struct libusb_context *ctx, struct libusb_device
return -1;
}

port = libusb_get_port_number(ldev);
libusb_get_device_descriptor(ldev, &d);
di.bus = libusb_get_bus_number(ldev);
di.speed = libusb_get_device_speed(ldev);

/* FIXME: * should use libusb_get_port_numbers here */
di.port = libusb_get_port_number(ldev);
di.pid = d.idProduct;
di.vid = d.idVendor;
di.bcd = d.bcdUSB;
di.priv_data = ldev;

rc = usb_get_parent_dev_type(ldev, &pbus, &pport);
if (rc == USB_TYPE_INVALID) {
UPRINTF(LWRN, "usb_get_parent_dev_type return %d\r\n", rc);
return 0;
} else if (rc == USB_HUB)
port += PORT_HUB_BASE;
di.port += PORT_HUB_BASE;

if (g_ctx.disconn_cb)
g_ctx.disconn_cb(g_ctx.hci_data, &port);
g_ctx.disconn_cb(g_ctx.hci_data, &di);

return 0;
}
Expand Down

0 comments on commit 6c9bae6

Please sign in to comment.