Skip to content

Commit 6c9bae6

Browse files
xiaoguangwulijinxia
authored andcommitted
DM USB: xHCI: fix USB hub disconnection issue
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
1 parent 0d4a88e commit 6c9bae6

File tree

2 files changed

+44
-13
lines changed

2 files changed

+44
-13
lines changed

devicemodel/hw/pci/xhci.c

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -630,7 +630,7 @@ pci_xhci_native_usb_dev_disconn_cb(void *hci_data, void *dev_data)
630630
struct pci_xhci_dev_emu *edev;
631631
struct usb_native_devinfo di;
632632
struct usb_dev *udev;
633-
uint8_t port, slot, native_port;
633+
uint8_t port, slot;
634634
uint8_t status;
635635
int need_intr = 1;
636636

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

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

649+
status = VPORT_STATE(xdev->port_map_tbl[di.bus][di.port]);
650+
if (status == VPORT_HUB_CONNECTED) {
651+
xdev->port_map_tbl[di.bus][di.port] =
652+
VPORT_NUM_STATE(VPORT_ASSIGNED, 0);
653+
return 0;
654+
}
655+
649656
for (port = 1; port <= XHCI_MAX_DEVS; ++port) {
650657
edev = xdev->devices[port];
651658
if (!edev)
652659
continue;
653660

654661
udev = edev->dev_instance;
655-
if (udev->info.port == native_port) {
656-
di = udev->info;
657-
break;
662+
if (udev->info.port == di.port) {
663+
int old_t, new_t;
664+
uint8_t old_ports[7]; /* max USB hub tiers are 7 */
665+
uint8_t new_ports[7];
666+
667+
/* get tiers and port info */
668+
old_t = libusb_get_port_numbers(udev->info.priv_data,
669+
old_ports, sizeof(old_ports));
670+
new_t = libusb_get_port_numbers(di.priv_data,
671+
new_ports, sizeof(new_ports));
672+
673+
if (old_t == new_t &&
674+
!memcmp(old_ports, new_ports, old_t)) {
675+
di = udev->info;
676+
break;
677+
}
678+
UPRINTF(LFTL, "multi-hub is not supported yet\r\n");
658679
}
659680
}
660681

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

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

670-
status = VPORT_STATE(xdev->port_map_tbl[di.bus][di.port]);
671691
assert(status == VPORT_EMULATED || status == VPORT_CONNECTED);
672692
xdev->port_map_tbl[di.bus][di.port] = VPORT_NUM_STATE(VPORT_ASSIGNED,
673693
0);

devicemodel/hw/platform/usb_pmapper.c

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1176,7 +1176,8 @@ static int
11761176
usb_dev_native_sys_disconn_cb(struct libusb_context *ctx, struct libusb_device
11771177
*ldev, libusb_hotplug_event event, void *pdata)
11781178
{
1179-
uint8_t port;
1179+
struct libusb_device_descriptor d;
1180+
struct usb_native_devinfo di;
11801181
uint16_t pport;
11811182
uint16_t pbus;
11821183
int rc;
@@ -1188,16 +1189,26 @@ usb_dev_native_sys_disconn_cb(struct libusb_context *ctx, struct libusb_device
11881189
return -1;
11891190
}
11901191

1191-
port = libusb_get_port_number(ldev);
1192+
libusb_get_device_descriptor(ldev, &d);
1193+
di.bus = libusb_get_bus_number(ldev);
1194+
di.speed = libusb_get_device_speed(ldev);
1195+
1196+
/* FIXME: * should use libusb_get_port_numbers here */
1197+
di.port = libusb_get_port_number(ldev);
1198+
di.pid = d.idProduct;
1199+
di.vid = d.idVendor;
1200+
di.bcd = d.bcdUSB;
1201+
di.priv_data = ldev;
1202+
11921203
rc = usb_get_parent_dev_type(ldev, &pbus, &pport);
11931204
if (rc == USB_TYPE_INVALID) {
11941205
UPRINTF(LWRN, "usb_get_parent_dev_type return %d\r\n", rc);
11951206
return 0;
11961207
} else if (rc == USB_HUB)
1197-
port += PORT_HUB_BASE;
1208+
di.port += PORT_HUB_BASE;
11981209

11991210
if (g_ctx.disconn_cb)
1200-
g_ctx.disconn_cb(g_ctx.hci_data, &port);
1211+
g_ctx.disconn_cb(g_ctx.hci_data, &di);
12011212

12021213
return 0;
12031214
}

0 commit comments

Comments
 (0)