From f533a07af155237a077f98acfccdaac8e2547aa0 Mon Sep 17 00:00:00 2001 From: Liang Yang Date: Mon, 8 Oct 2018 19:22:01 +0800 Subject: [PATCH] DM USB: xHCI: support multiple hubs in single layer This patch is used to enable multiple hubs in single layer under Flat Mode. Tracked-On: #1434 Signed-off-by: Liang Yang Signed-off-by: Xiaoguang Wu Acked-by: Yu Wang --- devicemodel/hw/pci/xhci.c | 142 ++++++++++++++++++++++++-- devicemodel/hw/platform/usb_pmapper.c | 55 +++++++--- devicemodel/hw/usb_core.c | 34 ++++++ devicemodel/include/usb_core.h | 11 ++ devicemodel/include/usb_pmapper.h | 2 - 5 files changed, 222 insertions(+), 22 deletions(-) diff --git a/devicemodel/hw/pci/xhci.c b/devicemodel/hw/pci/xhci.c index c96d7ded3..d088150e0 100755 --- a/devicemodel/hw/pci/xhci.c +++ b/devicemodel/hw/pci/xhci.c @@ -571,6 +571,112 @@ pci_xhci_get_native_port_index_by_vport(struct pci_xhci_vdev *xdev, return -1; } +static void +pci_xhci_clr_native_port_assigned(struct pci_xhci_vdev *xdev, + struct usb_native_devinfo *info) +{ + int i; + + assert(xdev); + assert(info); + assert(xdev->native_ports); + + i = pci_xhci_get_native_port_index_by_path(xdev, &info->path); + if (i >= 0) { + xdev->native_ports[i].state = VPORT_FREE; + xdev->native_ports[i].vport = 0; + } +} + +static int +pci_xhci_assign_hub_ports(struct pci_xhci_vdev *xdev, + struct usb_native_devinfo *info) +{ + int index; + uint8_t i; + struct usb_native_devinfo di; + struct usb_devpath *path; + + if (!xdev || !info || info->type != USB_TYPE_EXTHUB) + return -1; + + index = pci_xhci_get_native_port_index_by_path(xdev, &info->path); + if (index < 0) { + UPRINTF(LDBG, "cannot find hub %d-%s\r\n", info->path.bus, + usb_dev_path(&info->path)); + return -1; + } + + xdev->native_ports[index].info = *info; + UPRINTF(LDBG, "Found an USB hub %d-%s with %d port(s).\r\n", + info->path.bus, usb_dev_path(&info->path), + info->maxchild); + + path = &di.path; + for (i = 1; i <= info->maxchild; i++) { + + /* make a device path for hub ports */ + memcpy(path->path, info->path.path, info->path.depth); + memcpy(path->path + info->path.depth, &i, sizeof(i)); + memset(path->path + info->path.depth + 1, 0, + USB_MAX_TIERS - info->path.depth - 1); + path->depth = info->path.depth + 1; + path->bus = info->path.bus; + + /* set the device path as assigned */ + index = pci_xhci_set_native_port_assigned(xdev, &di); + if (index < 0) { + UPRINTF(LFTL, "too many USB devices\r\n"); + return -1; + } + UPRINTF(LDBG, "Add %d-%s as assigned port\r\n", + path->bus, usb_dev_path(path)); + } + return 0; +} + +static int +pci_xhci_unassign_hub_ports(struct pci_xhci_vdev *xdev, + struct usb_native_devinfo *info) +{ + uint8_t i, index; + struct usb_native_devinfo di, *oldinfo; + struct usb_devpath *path; + + if (!xdev || !info || info->type != USB_TYPE_EXTHUB) + return -1; + + index = pci_xhci_get_native_port_index_by_path(xdev, &info->path); + if (index < 0) { + UPRINTF(LFTL, "cannot find USB hub %d-%s\r\n", + info->path.bus, usb_dev_path(&info->path)); + return -1; + } + + oldinfo = &xdev->native_ports[index].info; + UPRINTF(LDBG, "Disconnect an USB hub %d-%s with %d port(s)\r\n", + oldinfo->path.bus, usb_dev_path(&oldinfo->path), + oldinfo->maxchild); + + path = &di.path; + for (i = 1; i <= oldinfo->maxchild; i++) { + + /* make a device path for hub ports */ + memcpy(path->path, oldinfo->path.path, oldinfo->path.depth); + memcpy(path->path + oldinfo->path.depth, &i, sizeof(i)); + memset(path->path + oldinfo->path.depth + 1, 0, + USB_MAX_TIERS - oldinfo->path.depth - 1); + path->depth = oldinfo->path.depth + 1; + path->bus = oldinfo->path.bus; + + /* clear the device path as not assigned */ + pci_xhci_clr_native_port_assigned(xdev, &di); + UPRINTF(LDBG, "Del %d-%s as assigned port\r\n", + path->bus, usb_dev_path(path)); + } + return 0; +} + static int pci_xhci_native_usb_dev_conn_cb(void *hci_data, void *dev_data) { @@ -579,6 +685,7 @@ pci_xhci_native_usb_dev_conn_cb(void *hci_data, void *dev_data) int vport; int need_intr = 1; int index; + int rc; xdev = hci_data; @@ -600,6 +707,15 @@ pci_xhci_native_usb_dev_conn_cb(void *hci_data, void *dev_data) di->path.bus, usb_dev_path(&di->path)); return 0; } + + if (di->type == USB_TYPE_EXTHUB) { + rc = pci_xhci_assign_hub_ports(xdev, di); + if (rc < 0) + UPRINTF(LFTL, "fail to assign ports of hub %d-%s\r\n", + di->path.bus, usb_dev_path(&di->path)); + return 0; + } + UPRINTF(LDBG, "%04x:%04x %d-%s belong to this vm.\r\n", di->vid, di->pid, di->path.bus, usb_dev_path(&di->path)); @@ -637,11 +753,12 @@ pci_xhci_native_usb_dev_disconn_cb(void *hci_data, void *dev_data) { struct pci_xhci_vdev *xdev; struct pci_xhci_dev_emu *edev; - struct usb_native_devinfo di; + struct usb_native_devinfo *di; uint8_t vport, slot; uint16_t state; int need_intr = 1; int index; + int rc; assert(hci_data); assert(dev_data); @@ -649,20 +766,29 @@ pci_xhci_native_usb_dev_disconn_cb(void *hci_data, void *dev_data) xdev = hci_data; assert(xdev->devices); - di = *((struct usb_native_devinfo *)dev_data); - if (!pci_xhci_is_valid_portnum(ROOTHUB_PORT(di.path))) { + di = dev_data; + if (!pci_xhci_is_valid_portnum(ROOTHUB_PORT(di->path))) { UPRINTF(LFTL, "invalid physical port %d\r\n", - ROOTHUB_PORT(di.path)); + ROOTHUB_PORT(di->path)); return -1; } - index = pci_xhci_get_native_port_index_by_path(xdev, &di.path); + index = pci_xhci_get_native_port_index_by_path(xdev, &di->path); if (index < 0) { UPRINTF(LFTL, "fail to find physical port %d\r\n", - ROOTHUB_PORT(di.path)); + ROOTHUB_PORT(di->path)); return -1; } + if (di->type == USB_TYPE_EXTHUB) { + rc = pci_xhci_unassign_hub_ports(xdev, di); + if (rc < 0) + UPRINTF(LFTL, "fail to unassign the ports of hub" + " %d-%s\r\n", di->path.bus, + usb_dev_path(&di->path)); + return 0; + } + state = xdev->native_ports[index].state; vport = xdev->native_ports[index].vport; @@ -674,8 +800,8 @@ pci_xhci_native_usb_dev_disconn_cb(void *hci_data, void *dev_data) * cleared for future connecting. */ UPRINTF(LFTL, "disconnect VPORT_CONNECTED device: " - "%d-%s vport %d\r\n", di.path.bus, - usb_dev_path(&di.path), vport); + "%d-%s vport %d\r\n", di->path.bus, + usb_dev_path(&di->path), vport); pci_xhci_disconnect_port(xdev, vport, 0); xdev->native_ports[index].state = VPORT_ASSIGNED; return 0; diff --git a/devicemodel/hw/platform/usb_pmapper.c b/devicemodel/hw/platform/usb_pmapper.c index 7672c9e4d..bbdb898f0 100755 --- a/devicemodel/hw/platform/usb_pmapper.c +++ b/devicemodel/hw/platform/usb_pmapper.c @@ -46,6 +46,24 @@ usb_get_native_devinfo(struct libusb_device *ldev, return false; } + /* set device type */ + if (ROOTHUB_PORT(info->path) == 0) + info->type = USB_TYPE_ROOTHUB; + else if (d.bDeviceClass == LIBUSB_CLASS_HUB) + info->type = USB_TYPE_EXTHUB; + else if (info->path.path[1] == 0) + info->type = USB_TYPE_ROOTHUB_SUBDEV; + else + info->type = USB_TYPE_EXTHUB_SUBDEV; + + if (info->type == USB_TYPE_EXTHUB) { + info->maxchild = usb_get_hub_port_num(&info->path); + if (info->maxchild < 0) + UPRINTF(LFTL, "fail to get count of numbers of hub" + " %d-%s\r\n", info->path.bus, + usb_dev_path(&info->path)); + } + info->pid = d.idProduct; info->vid = d.idVendor; info->bcd = d.bcdUSB; @@ -73,15 +91,36 @@ usb_dev_scan_dev() if (num_devs < 0) return -1; + /* first pass, process external hubs */ for (i = 0; i < num_devs; ++i) { ldev = devlist[i]; ret = usb_get_native_devinfo(ldev, &di, &d); if (ret == false) continue; + if (ROOTHUB_PORT(di.path) == 0) continue; - if (d.bDeviceClass == LIBUSB_CLASS_HUB) + + if (di.type != USB_TYPE_EXTHUB) + continue; + + if (g_ctx.conn_cb) + g_ctx.conn_cb(g_ctx.hci_data, &di); + } + + /* second pass, process devices */ + for (i = 0; i < num_devs; ++i) { + ldev = devlist[i]; + + ret = usb_get_native_devinfo(ldev, &di, &d); + if (ret == false) + continue; + + if (ROOTHUB_PORT(di.path) == 0) + continue; + + if (di.type == USB_TYPE_EXTHUB) continue; if (g_ctx.conn_cb) @@ -941,8 +980,8 @@ usb_dev_init(void *pdata, char *opt) int ver; assert(pdata); - di = pdata; + libusb_get_device_descriptor(di->priv_data, &desc); UPRINTF(LINF, "Found USB device: %d-%s\r\nPID(0x%X), VID(0x%X) CLASS" "(0x%X) SUBCLASS(0x%X) BCD(0x%X) SPEED(%d)\r\n", @@ -1088,7 +1127,6 @@ usb_dev_native_sys_conn_cb(struct libusb_context *ctx, struct libusb_device *ldev, libusb_hotplug_event event, void *pdata) { struct usb_native_devinfo di; - struct libusb_device_descriptor d; bool ret; UPRINTF(LDBG, "connect event\r\n"); @@ -1098,13 +1136,10 @@ usb_dev_native_sys_conn_cb(struct libusb_context *ctx, struct libusb_device return -1; } - ret = usb_get_native_devinfo(ldev, &di, &d); + ret = usb_get_native_devinfo(ldev, &di, NULL); if (ret == false) return 0; - if (d.bDeviceClass == LIBUSB_CLASS_HUB) - return 0; - if (g_ctx.conn_cb) g_ctx.conn_cb(g_ctx.hci_data, &di); @@ -1116,7 +1151,6 @@ usb_dev_native_sys_disconn_cb(struct libusb_context *ctx, struct libusb_device *ldev, libusb_hotplug_event event, void *pdata) { struct usb_native_devinfo di; - struct libusb_device_descriptor d; bool ret; UPRINTF(LDBG, "disconnect event\r\n"); @@ -1126,13 +1160,10 @@ usb_dev_native_sys_disconn_cb(struct libusb_context *ctx, struct libusb_device return -1; } - ret = usb_get_native_devinfo(ldev, &di, &d); + ret = usb_get_native_devinfo(ldev, &di, NULL); if (ret == false) return 0; - if (d.bDeviceClass == LIBUSB_CLASS_HUB) - return 0; - if (g_ctx.disconn_cb) g_ctx.disconn_cb(g_ctx.hci_data, &di); diff --git a/devicemodel/hw/usb_core.c b/devicemodel/hw/usb_core.c index 581267d66..c70d46d8e 100644 --- a/devicemodel/hw/usb_core.c +++ b/devicemodel/hw/usb_core.c @@ -264,3 +264,37 @@ usb_dev_path(struct usb_devpath *path) return output; } + +int +usb_get_hub_port_num(struct usb_devpath *path) +{ + int rc, fd; + char buf[128]; + char cnt[8]; + + if (!usb_native_is_bus_existed(path->bus)) + return -1; + + snprintf(buf, sizeof(buf), "%s/%d-%s/maxchild", NATIVE_USBSYS_DEVDIR, + path->bus, usb_dev_path(path)); + if (access(buf, R_OK)) { + UPRINTF(LWRN, "can't find maxchild file\r\n"); + return -1; + } + + fd = open(buf, O_RDONLY); + if (fd < 0) { + UPRINTF(LWRN, "fail to open maxchild file\r\n"); + return -1; + } + + rc = read(fd, &cnt, sizeof(cnt)); + if (rc < 0) { + UPRINTF(LWRN, "fail to read maxchild file\r\n"); + close(fd); + return -1; + } + + close(fd); + return atoi(cnt); +} diff --git a/devicemodel/include/usb_core.h b/devicemodel/include/usb_core.h index 795073dc8..554cfba4b 100644 --- a/devicemodel/include/usb_core.h +++ b/devicemodel/include/usb_core.h @@ -84,6 +84,14 @@ enum usb_xfer_blk_stat { USB_XFER_BLK_HANDLED }; +enum usb_native_devtype { + USB_TYPE_ROOTHUB, + USB_TYPE_EXTHUB, + USB_TYPE_ROOTHUB_SUBDEV, + USB_TYPE_EXTHUB_SUBDEV, + USB_TYPE_NONE +}; + #define USB_MAX_TIERS 7 struct usb_hci; @@ -174,9 +182,11 @@ struct usb_devpath { struct usb_native_devinfo { int speed; + int maxchild; uint16_t bcd; uint16_t pid; uint16_t vid; + enum usb_native_devtype type; struct usb_devpath path; void *priv_data; }; @@ -247,5 +257,6 @@ struct usb_data_xfer_block *usb_data_xfer_append(struct usb_data_xfer *xfer, int blen, void *hci_data, int ccs); +int usb_get_hub_port_num(struct usb_devpath *path); char *usb_dev_path(struct usb_devpath *path); #endif /* _USB_CORE_H_ */ diff --git a/devicemodel/include/usb_pmapper.h b/devicemodel/include/usb_pmapper.h index fe60bf7b3..43cb09fd8 100644 --- a/devicemodel/include/usb_pmapper.h +++ b/devicemodel/include/usb_pmapper.h @@ -119,6 +119,4 @@ int usb_dev_info(void *pdata, int type, void *value, int size); int usb_dev_request(void *pdata, struct usb_data_xfer *xfer); int usb_dev_reset(void *pdata); int usb_dev_data(void *pdata, struct usb_data_xfer *xfer, int dir, int epctx); -enum usb_native_dev_type usb_get_parent_dev_type(void *pdata, uint16_t *bus, - uint16_t *port); #endif