From a7ea58f3814398ccfc154e2461f2a2011cc4a1bd Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Tue, 25 Apr 2017 14:23:41 +0300 Subject: tools: usb: testusb: update default vary for superspeed Currently, default vary will not accomodate superspeed endpoints causing unexpected babble errors in the IN direction. Let's update default 'vary' parameter so that we can maintain a "short-less" transfer as hinted at the comment. Reported-by: Ammy Yi Signed-off-by: Felipe Balbi --- tools/usb/testusb.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) (limited to 'tools') diff --git a/tools/usb/testusb.c b/tools/usb/testusb.c index 0692d99b6d8f..2d89b5f686b1 100644 --- a/tools/usb/testusb.c +++ b/tools/usb/testusb.c @@ -387,15 +387,17 @@ int main (int argc, char **argv) /* pick defaults that works with all speeds, without short packets. * * Best per-frame data rates: - * high speed, bulk 512 * 13 * 8 = 53248 - * interrupt 1024 * 3 * 8 = 24576 - * full speed, bulk/intr 64 * 19 = 1216 - * interrupt 64 * 1 = 64 - * low speed, interrupt 8 * 1 = 8 + * super speed,bulk 1024 * 16 * 8 = 131072 + * interrupt 1024 * 3 * 8 = 24576 + * high speed, bulk 512 * 13 * 8 = 53248 + * interrupt 1024 * 3 * 8 = 24576 + * full speed, bulk/intr 64 * 19 = 1216 + * interrupt 64 * 1 = 64 + * low speed, interrupt 8 * 1 = 8 */ param.iterations = 1000; param.length = 1024; - param.vary = 512; + param.vary = 1024; param.sglen = 32; /* for easy use when hotplugging */ @@ -457,7 +459,7 @@ usage: "\t-c iterations default 1000\n" "\t-s transfer length default 1024\n" "\t-g sglen default 32\n" - "\t-v vary default 512\n", + "\t-v vary default 1024\n", argv[0]); return 1; } -- cgit v1.2.3-59-g8ed1b From c3509715fc9484a48b69a9f0196b728c960840c9 Mon Sep 17 00:00:00 2001 From: Yuyang Du Date: Mon, 22 May 2017 18:20:15 +0800 Subject: usb: usbip tool: Check the return of get_nports() If we get nonpositive number of ports, there is no sense to continue, then fail gracefully. In addition, the commit 0775a9cbc694e8c72 ("usbip: vhci extension: modifications to vhci driver") introduced configurable numbers of controllers and ports, but we have a static port number maximum, MAXNPORT. If exceeded, the idev array will be overflown. We fix it by validating the nports to make sure the port number max is not exceeded. Reviewed-by: Krzysztof Opasiak Signed-off-by: Yuyang Du Acked-by: Shuah Khan Signed-off-by: Greg Kroah-Hartman --- tools/usb/usbip/libsrc/vhci_driver.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'tools') diff --git a/tools/usb/usbip/libsrc/vhci_driver.c b/tools/usb/usbip/libsrc/vhci_driver.c index f659c146cdc8..036b62be0fc7 100644 --- a/tools/usb/usbip/libsrc/vhci_driver.c +++ b/tools/usb/usbip/libsrc/vhci_driver.c @@ -220,9 +220,16 @@ int usbip_vhci_driver_open(void) } vhci_driver->nports = get_nports(); - dbg("available ports: %d", vhci_driver->nports); + if (vhci_driver->nports <= 0) { + err("no available ports"); + goto err; + } else if (vhci_driver->nports > MAXNPORT) { + err("port number exceeds %d", MAXNPORT); + goto err; + } + if (refresh_imported_device_list()) goto err; -- cgit v1.2.3-59-g8ed1b From aa3ecb9154acb99282f315fe6c34ce4b7eb4d67e Mon Sep 17 00:00:00 2001 From: Yuyang Du Date: Mon, 22 May 2017 18:20:16 +0800 Subject: usb: usbip tool: Add ncontrollers in vhci_driver structure A new field ncontrollers is added to the vhci_driver structure. And this field is stored by scanning the vhci_hcd* dirs in the platform udev. Suggested-and-reviewed-by: Krzysztof Opasiak Signed-off-by: Yuyang Du Acked-by: Shuah Khan Signed-off-by: Greg Kroah-Hartman --- tools/usb/usbip/libsrc/vhci_driver.c | 36 ++++++++++++++++++++++++++++++++++++ tools/usb/usbip/libsrc/vhci_driver.h | 1 + 2 files changed, 37 insertions(+) (limited to 'tools') diff --git a/tools/usb/usbip/libsrc/vhci_driver.c b/tools/usb/usbip/libsrc/vhci_driver.c index 036b62be0fc7..f6f3a19ba385 100644 --- a/tools/usb/usbip/libsrc/vhci_driver.c +++ b/tools/usb/usbip/libsrc/vhci_driver.c @@ -7,6 +7,7 @@ #include #include #include +#include #include "sysfs_utils.h" #undef PROGNAME @@ -134,6 +135,33 @@ static int get_nports(void) return (int)strtoul(attr_nports, NULL, 10); } +static int vhci_hcd_filter(const struct dirent *dirent) +{ + return strcmp(dirent->d_name, "vhci_hcd") >= 0; +} + +static int get_ncontrollers(void) +{ + struct dirent **namelist; + struct udev_device *platform; + int n; + + platform = udev_device_get_parent(vhci_driver->hc_device); + if (platform == NULL) + return -1; + + n = scandir(udev_device_get_syspath(platform), &namelist, vhci_hcd_filter, NULL); + if (n < 0) + err("scandir failed"); + else { + for (int i = 0; i < n; i++) + free(namelist[i]); + free(namelist); + } + + return n; +} + /* * Read the given port's record. * @@ -230,6 +258,14 @@ int usbip_vhci_driver_open(void) goto err; } + vhci_driver->ncontrollers = get_ncontrollers(); + dbg("available controllers: %d", vhci_driver->ncontrollers); + + if (vhci_driver->ncontrollers <=0) { + err("no available usb controllers"); + goto err; + } + if (refresh_imported_device_list()) goto err; diff --git a/tools/usb/usbip/libsrc/vhci_driver.h b/tools/usb/usbip/libsrc/vhci_driver.h index fa2316cf2cac..33add142c46e 100644 --- a/tools/usb/usbip/libsrc/vhci_driver.h +++ b/tools/usb/usbip/libsrc/vhci_driver.h @@ -31,6 +31,7 @@ struct usbip_vhci_driver { /* /sys/devices/platform/vhci_hcd */ struct udev_device *hc_device; + int ncontrollers; int nports; struct usbip_imported_device idev[MAXNPORT]; }; -- cgit v1.2.3-59-g8ed1b From fd92b7deb98a4edd31ffcc2d64cee36103805ff5 Mon Sep 17 00:00:00 2001 From: Yuyang Du Date: Mon, 22 May 2017 18:20:17 +0800 Subject: usb: usbip tool: Fix refresh_imported_device_list() The commit 0775a9cbc694e8c7 ("usbip: vhci extension: modifications to vhci driver") introduced multiple controllers, but the status of the ports are only extracted from the first status file, fix it. Reviewed-by: Krzysztof Opasiak Signed-off-by: Yuyang Du Acked-by: Shuah Khan Signed-off-by: Greg Kroah-Hartman --- tools/usb/usbip/libsrc/vhci_driver.c | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) (limited to 'tools') diff --git a/tools/usb/usbip/libsrc/vhci_driver.c b/tools/usb/usbip/libsrc/vhci_driver.c index f6f3a19ba385..aa82c4b17797 100644 --- a/tools/usb/usbip/libsrc/vhci_driver.c +++ b/tools/usb/usbip/libsrc/vhci_driver.c @@ -108,18 +108,33 @@ static int parse_status(const char *value) return 0; } +#define MAX_STATUS_NAME 16 + static int refresh_imported_device_list(void) { const char *attr_status; + char status[MAX_STATUS_NAME+1] = "status"; + int i, ret; - attr_status = udev_device_get_sysattr_value(vhci_driver->hc_device, - "status"); - if (!attr_status) { - err("udev_device_get_sysattr_value failed"); - return -1; + for (i = 0; i < vhci_driver->ncontrollers; i++) { + if (i > 0) + snprintf(status, sizeof(status), "status.%d", i); + + attr_status = udev_device_get_sysattr_value(vhci_driver->hc_device, + status); + if (!attr_status) { + err("udev_device_get_sysattr_value failed"); + return -1; + } + + dbg("controller %d", i); + + ret = parse_status(attr_status); + if (ret != 0) + return ret; } - return parse_status(attr_status); + return 0; } static int get_nports(void) -- cgit v1.2.3-59-g8ed1b From e55dea8ede2245918c537b9a252a1269f5d7b78b Mon Sep 17 00:00:00 2001 From: Yuyang Du Date: Mon, 22 May 2017 18:20:18 +0800 Subject: usb: usbip tool: Fix parse_status() In parse_status(), all nports number of idev's are initiated to 0 by memset(), it is simply wrong, because parse_status() reads the status sys file one by one, therefore, it can only update the according vhci_driver->idev's for it to parse. Reviewed-by: Krzysztof Opasiak Signed-off-by: Yuyang Du Acked-by: Shuah Khan Signed-off-by: Greg Kroah-Hartman --- tools/usb/usbip/libsrc/vhci_driver.c | 38 ++++++++++++++---------------------- tools/usb/usbip/src/usbip_attach.c | 2 ++ 2 files changed, 17 insertions(+), 23 deletions(-) (limited to 'tools') diff --git a/tools/usb/usbip/libsrc/vhci_driver.c b/tools/usb/usbip/libsrc/vhci_driver.c index aa82c4b17797..f519c73c6d99 100644 --- a/tools/usb/usbip/libsrc/vhci_driver.c +++ b/tools/usb/usbip/libsrc/vhci_driver.c @@ -36,18 +36,11 @@ err: return NULL; } - - static int parse_status(const char *value) { int ret = 0; char *c; - - for (int i = 0; i < vhci_driver->nports; i++) - memset(&vhci_driver->idev[i], 0, sizeof(vhci_driver->idev[i])); - - /* skip a header line */ c = strchr(value, '\n'); if (!c) @@ -58,6 +51,7 @@ static int parse_status(const char *value) int port, status, speed, devid; unsigned long socket; char lbusid[SYSFS_BUS_ID_SIZE]; + struct usbip_imported_device *idev; ret = sscanf(c, "%d %d %d %x %lx %31s\n", &port, &status, &speed, @@ -72,30 +66,28 @@ static int parse_status(const char *value) port, status, speed, devid); dbg("socket %lx lbusid %s", socket, lbusid); - /* if a device is connected, look at it */ - { - struct usbip_imported_device *idev = &vhci_driver->idev[port]; + idev = &vhci_driver->idev[port]; - idev->port = port; - idev->status = status; + memset(idev, 0, sizeof(*idev)); - idev->devid = devid; + idev->port = port; + idev->status = status; - idev->busnum = (devid >> 16); - idev->devnum = (devid & 0x0000ffff); + idev->devid = devid; - if (idev->status != VDEV_ST_NULL - && idev->status != VDEV_ST_NOTASSIGNED) { - idev = imported_device_init(idev, lbusid); - if (!idev) { - dbg("imported_device_init failed"); - return -1; - } + idev->busnum = (devid >> 16); + idev->devnum = (devid & 0x0000ffff); + + if (idev->status != VDEV_ST_NULL + && idev->status != VDEV_ST_NOTASSIGNED) { + idev = imported_device_init(idev, lbusid); + if (!idev) { + dbg("imported_device_init failed"); + return -1; } } - /* go to the next line */ c = strchr(c, '\n'); if (!c) diff --git a/tools/usb/usbip/src/usbip_attach.c b/tools/usb/usbip/src/usbip_attach.c index 70a6b507fb62..62a297ff647a 100644 --- a/tools/usb/usbip/src/usbip_attach.c +++ b/tools/usb/usbip/src/usbip_attach.c @@ -108,6 +108,8 @@ static int import_device(int sockfd, struct usbip_usb_device *udev) return -1; } + dbg("got free port %d", port); + rc = usbip_vhci_attach_device(port, sockfd, udev->busnum, udev->devnum, udev->speed); if (rc < 0) { -- cgit v1.2.3-59-g8ed1b From dff3565b8e1c0be6fc83ba47dcab45c149dcab5b Mon Sep 17 00:00:00 2001 From: Yuyang Du Date: Thu, 8 Jun 2017 13:04:08 +0800 Subject: usbip: vhci-hcd: Rework vhci_hcd_init A vhci struct is added as the platform-specific data to the vhci platform device, in order to get the vhci by its platform device. This is done in vhci_hcd_init(). Signed-off-by: Yuyang Du Acked-by: Shuah Khan Signed-off-by: Greg Kroah-Hartman --- drivers/usb/usbip/vhci_hcd.c | 51 ++++++++++++++++++++---------------- tools/usb/usbip/libsrc/vhci_driver.c | 2 +- tools/usb/usbip/libsrc/vhci_driver.h | 1 + 3 files changed, 30 insertions(+), 24 deletions(-) (limited to 'tools') diff --git a/drivers/usb/usbip/vhci_hcd.c b/drivers/usb/usbip/vhci_hcd.c index a445d237b0c3..893a5dedd0e5 100644 --- a/drivers/usb/usbip/vhci_hcd.c +++ b/drivers/usb/usbip/vhci_hcd.c @@ -1178,24 +1178,6 @@ static struct platform_driver vhci_driver = { }, }; -static int add_platform_device(int id) -{ - struct platform_device *pdev; - int dev_nr; - - if (id == 0) - dev_nr = -1; - else - dev_nr = id; - - pdev = platform_device_register_simple(driver_name, dev_nr, NULL, 0); - if (IS_ERR(pdev)) - return PTR_ERR(pdev); - - vhcis[id].pdev = pdev; - return 0; -} - static void del_platform_devices(void) { struct platform_device *pdev; @@ -1224,23 +1206,46 @@ static int __init vhci_hcd_init(void) if (vhcis == NULL) return -ENOMEM; + for (i = 0; i < vhci_num_controllers; i++) { + vhcis[i].pdev = platform_device_alloc(driver_name, i); + if (!vhcis[i].pdev) { + i--; + while (i >= 0) + platform_device_put(vhcis[i--].pdev); + ret = -ENOMEM; + goto err_device_alloc; + } + } + for (i = 0; i < vhci_num_controllers; i++) { + void *vhci = &vhcis[i]; + ret = platform_device_add_data(vhcis[i].pdev, &vhci, sizeof(void *)); + if (ret) + goto err_driver_register; + } + ret = platform_driver_register(&vhci_driver); if (ret) goto err_driver_register; for (i = 0; i < vhci_num_controllers; i++) { - ret = add_platform_device(i); - if (ret) - goto err_platform_device_register; + ret = platform_device_add(vhcis[i].pdev); + if (ret < 0) { + i--; + while (i >= 0) + platform_device_del(vhcis[i--].pdev); + goto err_add_hcd; + } } pr_info(DRIVER_DESC " v" USBIP_VERSION "\n"); return ret; -err_platform_device_register: - del_platform_devices(); +err_add_hcd: platform_driver_unregister(&vhci_driver); err_driver_register: + for (i = 0; i < vhci_num_controllers; i++) + platform_device_put(vhcis[i].pdev); +err_device_alloc: kfree(vhcis); return ret; } diff --git a/tools/usb/usbip/libsrc/vhci_driver.c b/tools/usb/usbip/libsrc/vhci_driver.c index f519c73c6d99..3d8189b4f539 100644 --- a/tools/usb/usbip/libsrc/vhci_driver.c +++ b/tools/usb/usbip/libsrc/vhci_driver.c @@ -248,7 +248,7 @@ int usbip_vhci_driver_open(void) vhci_driver->hc_device = udev_device_new_from_subsystem_sysname(udev_context, USBIP_VHCI_BUS_TYPE, - USBIP_VHCI_DRV_NAME); + USBIP_VHCI_DEVICE_NAME); if (!vhci_driver->hc_device) { err("udev_device_new_from_subsystem_sysname failed"); goto err; diff --git a/tools/usb/usbip/libsrc/vhci_driver.h b/tools/usb/usbip/libsrc/vhci_driver.h index 33add142c46e..dfe19c1c0245 100644 --- a/tools/usb/usbip/libsrc/vhci_driver.h +++ b/tools/usb/usbip/libsrc/vhci_driver.h @@ -11,6 +11,7 @@ #include "usbip_common.h" #define USBIP_VHCI_BUS_TYPE "platform" +#define USBIP_VHCI_DEVICE_NAME "vhci_hcd.0" #define MAXNPORT 128 struct usbip_imported_device { -- cgit v1.2.3-59-g8ed1b From 1c9de5bf428612458427943b724bea51abde520a Mon Sep 17 00:00:00 2001 From: Yuyang Du Date: Thu, 8 Jun 2017 13:04:10 +0800 Subject: usbip: vhci-hcd: Add USB3 SuperSpeed support This patch adds a USB3 HCD to an existing USB2 HCD and provides the support of SuperSpeed, in case the device can only be enumerated with SuperSpeed. The bulk of the added code in usb3_bos_desc and hub_control to support SuperSpeed is borrowed from the commit 1cd8fd2887e162ad ("usb: gadget: dummy_hcd: add SuperSpeed support"). With this patch, each vhci will have VHCI_HC_PORTS HighSpeed ports and VHCI_HC_PORTS SuperSpeed ports. Suggested-by: Krzysztof Opasiak Signed-off-by: Yuyang Du Acked-by: Shuah Khan Signed-off-by: Greg Kroah-Hartman --- drivers/usb/usbip/vhci.h | 7 +- drivers/usb/usbip/vhci_hcd.c | 323 ++++++++++++++++++++++++++++------- drivers/usb/usbip/vhci_sysfs.c | 109 ++++++++---- tools/usb/usbip/libsrc/vhci_driver.c | 23 ++- tools/usb/usbip/libsrc/vhci_driver.h | 8 +- tools/usb/usbip/src/usbip_attach.c | 3 +- 6 files changed, 370 insertions(+), 103 deletions(-) (limited to 'tools') diff --git a/drivers/usb/usbip/vhci.h b/drivers/usb/usbip/vhci.h index 8a979fc00ac1..db28eb531e8c 100644 --- a/drivers/usb/usbip/vhci.h +++ b/drivers/usb/usbip/vhci.h @@ -72,6 +72,11 @@ struct vhci_unlink { unsigned long unlink_seqnum; }; +enum hub_speed { + HUB_SPEED_HIGH = 0, + HUB_SPEED_SUPER, +}; + /* Number of supported ports. Value has an upperbound of USB_MAXCHILDREN */ #ifdef CONFIG_USBIP_VHCI_HC_PORTS #define VHCI_HC_PORTS CONFIG_USBIP_VHCI_HC_PORTS @@ -140,7 +145,7 @@ static inline __u32 port_to_rhport(__u32 port) static inline int port_to_pdev_nr(__u32 port) { - return port / VHCI_HC_PORTS; + return port / (VHCI_HC_PORTS * 2); } static inline struct vhci_hcd *hcd_to_vhci_hcd(struct usb_hcd *hcd) diff --git a/drivers/usb/usbip/vhci_hcd.c b/drivers/usb/usbip/vhci_hcd.c index c96dd44ff162..af42a6010205 100644 --- a/drivers/usb/usbip/vhci_hcd.c +++ b/drivers/usb/usbip/vhci_hcd.c @@ -232,6 +232,40 @@ done: return changed ? retval : 0; } +/* usb 3.0 root hub device descriptor */ +static struct { + struct usb_bos_descriptor bos; + struct usb_ss_cap_descriptor ss_cap; +} __packed usb3_bos_desc = { + + .bos = { + .bLength = USB_DT_BOS_SIZE, + .bDescriptorType = USB_DT_BOS, + .wTotalLength = cpu_to_le16(sizeof(usb3_bos_desc)), + .bNumDeviceCaps = 1, + }, + .ss_cap = { + .bLength = USB_DT_USB_SS_CAP_SIZE, + .bDescriptorType = USB_DT_DEVICE_CAPABILITY, + .bDevCapabilityType = USB_SS_CAP_TYPE, + .wSpeedSupported = cpu_to_le16(USB_5GBPS_OPERATION), + .bFunctionalitySupport = ilog2(USB_5GBPS_OPERATION), + }, +}; + +static inline void +ss_hub_descriptor(struct usb_hub_descriptor *desc) +{ + memset(desc, 0, sizeof *desc); + desc->bDescriptorType = USB_DT_SS_HUB; + desc->bDescLength = 12; + desc->wHubCharacteristics = cpu_to_le16( + HUB_CHAR_INDV_PORT_LPSM | HUB_CHAR_COMMON_OCPM); + desc->bNbrPorts = VHCI_HC_PORTS; + desc->u.ss.bHubHdrDecLat = 0x04; /* Worst case: 0.4 micro sec*/ + desc->u.ss.DeviceRemovable = 0xffff; +} + static inline void hub_descriptor(struct usb_hub_descriptor *desc) { int width; @@ -265,13 +299,15 @@ static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, /* * NOTE: - * wIndex shows the port number and begins from 1. + * wIndex (bits 0-7) shows the port number and begins from 1? */ + wIndex = ((__u8)(wIndex & 0x00ff)); usbip_dbg_vhci_rh("typeReq %x wValue %x wIndex %x\n", typeReq, wValue, wIndex); + if (wIndex > VHCI_HC_PORTS) pr_err("invalid port number %d\n", wIndex); - rhport = ((__u8)(wIndex & 0x00ff)) - 1; + rhport = wIndex - 1; vhci_hcd = hcd_to_vhci_hcd(hcd); vhci = vhci_hcd->vhci; @@ -291,34 +327,26 @@ static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, case ClearPortFeature: switch (wValue) { case USB_PORT_FEAT_SUSPEND: + if (hcd->speed == HCD_USB3) { + pr_err(" ClearPortFeature: USB_PORT_FEAT_SUSPEND req not " + "supported for USB 3.0 roothub\n"); + goto error; + } + usbip_dbg_vhci_rh( + " ClearPortFeature: USB_PORT_FEAT_SUSPEND\n"); if (vhci_hcd->port_status[rhport] & USB_PORT_STAT_SUSPEND) { /* 20msec signaling */ vhci_hcd->resuming = 1; - vhci_hcd->re_timeout = - jiffies + msecs_to_jiffies(20); + vhci_hcd->re_timeout = jiffies + msecs_to_jiffies(20); } break; case USB_PORT_FEAT_POWER: usbip_dbg_vhci_rh( " ClearPortFeature: USB_PORT_FEAT_POWER\n"); - vhci_hcd->port_status[rhport] = 0; - vhci_hcd->resuming = 0; - break; - case USB_PORT_FEAT_C_RESET: - usbip_dbg_vhci_rh( - " ClearPortFeature: USB_PORT_FEAT_C_RESET\n"); - switch (vhci_hcd->vdev[rhport].speed) { - case USB_SPEED_HIGH: - vhci_hcd->port_status[rhport] |= - USB_PORT_STAT_HIGH_SPEED; - break; - case USB_SPEED_LOW: - vhci_hcd->port_status[rhport] |= - USB_PORT_STAT_LOW_SPEED; - break; - default: - break; - } + if (hcd->speed == HCD_USB3) + vhci_hcd->port_status[rhport] &= ~USB_SS_PORT_STAT_POWER; + else + vhci_hcd->port_status[rhport] &= ~USB_PORT_STAT_POWER; break; default: usbip_dbg_vhci_rh(" ClearPortFeature: default %x\n", @@ -329,7 +357,26 @@ static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, break; case GetHubDescriptor: usbip_dbg_vhci_rh(" GetHubDescriptor\n"); - hub_descriptor((struct usb_hub_descriptor *) buf); + if (hcd->speed == HCD_USB3 && + (wLength < USB_DT_SS_HUB_SIZE || + wValue != (USB_DT_SS_HUB << 8))) { + pr_err("Wrong hub descriptor type for USB 3.0 roothub.\n"); + goto error; + } + if (hcd->speed == HCD_USB3) + ss_hub_descriptor((struct usb_hub_descriptor *) buf); + else + hub_descriptor((struct usb_hub_descriptor *) buf); + break; + case DeviceRequest | USB_REQ_GET_DESCRIPTOR: + if (hcd->speed != HCD_USB3) + goto error; + + if ((wValue >> 8) != USB_DT_BOS) + goto error; + + memcpy(buf, &usb3_bos_desc, sizeof(usb3_bos_desc)); + retval = sizeof(usb3_bos_desc); break; case GetHubStatus: usbip_dbg_vhci_rh(" GetHubStatus\n"); @@ -337,7 +384,7 @@ static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, break; case GetPortStatus: usbip_dbg_vhci_rh(" GetPortStatus port %x\n", wIndex); - if (wIndex > VHCI_HC_PORTS || wIndex < 1) { + if (wIndex < 1) { pr_err("invalid port number %d\n", wIndex); retval = -EPIPE; } @@ -348,20 +395,16 @@ static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, * complete it!! */ if (vhci_hcd->resuming && time_after(jiffies, vhci_hcd->re_timeout)) { - vhci_hcd->port_status[rhport] |= - (1 << USB_PORT_FEAT_C_SUSPEND); - vhci_hcd->port_status[rhport] &= - ~(1 << USB_PORT_FEAT_SUSPEND); + vhci_hcd->port_status[rhport] |= (1 << USB_PORT_FEAT_C_SUSPEND); + vhci_hcd->port_status[rhport] &= ~(1 << USB_PORT_FEAT_SUSPEND); vhci_hcd->resuming = 0; vhci_hcd->re_timeout = 0; } if ((vhci_hcd->port_status[rhport] & (1 << USB_PORT_FEAT_RESET)) != 0 && time_after(jiffies, vhci_hcd->re_timeout)) { - vhci_hcd->port_status[rhport] |= - (1 << USB_PORT_FEAT_C_RESET); - vhci_hcd->port_status[rhport] &= - ~(1 << USB_PORT_FEAT_RESET); + vhci_hcd->port_status[rhport] |= (1 << USB_PORT_FEAT_C_RESET); + vhci_hcd->port_status[rhport] &= ~(1 << USB_PORT_FEAT_RESET); vhci_hcd->re_timeout = 0; if (vhci_hcd->vdev[rhport].ud.status == @@ -373,6 +416,22 @@ static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, vhci_hcd->port_status[rhport] |= USB_PORT_STAT_ENABLE; } + + if (hcd->speed < HCD_USB3) { + switch (vhci_hcd->vdev[rhport].speed) { + case USB_SPEED_HIGH: + vhci_hcd->port_status[rhport] |= + USB_PORT_STAT_HIGH_SPEED; + break; + case USB_SPEED_LOW: + vhci_hcd->port_status[rhport] |= + USB_PORT_STAT_LOW_SPEED; + break; + default: + pr_err("vhci_device speed not set\n"); + break; + } + } } ((__le16 *) buf)[0] = cpu_to_le16(vhci_hcd->port_status[rhport]); ((__le16 *) buf)[1] = @@ -387,36 +446,119 @@ static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, break; case SetPortFeature: switch (wValue) { + case USB_PORT_FEAT_LINK_STATE: + usbip_dbg_vhci_rh( + " SetPortFeature: USB_PORT_FEAT_LINK_STATE\n"); + if (hcd->speed != HCD_USB3) { + pr_err("USB_PORT_FEAT_LINK_STATE req not " + "supported for USB 2.0 roothub\n"); + goto error; + } + /* + * Since this is dummy we don't have an actual link so + * there is nothing to do for the SET_LINK_STATE cmd + */ + break; + case USB_PORT_FEAT_U1_TIMEOUT: + usbip_dbg_vhci_rh( + " SetPortFeature: USB_PORT_FEAT_U1_TIMEOUT\n"); + case USB_PORT_FEAT_U2_TIMEOUT: + usbip_dbg_vhci_rh( + " SetPortFeature: USB_PORT_FEAT_U2_TIMEOUT\n"); + /* TODO: add suspend/resume support! */ + if (hcd->speed != HCD_USB3) { + pr_err("USB_PORT_FEAT_U1/2_TIMEOUT req not " + "supported for USB 2.0 roothub\n"); + goto error; + } + break; case USB_PORT_FEAT_SUSPEND: usbip_dbg_vhci_rh( " SetPortFeature: USB_PORT_FEAT_SUSPEND\n"); + /* Applicable only for USB2.0 hub */ + if (hcd->speed == HCD_USB3) { + pr_err("USB_PORT_FEAT_SUSPEND req not " + "supported for USB 3.0 roothub\n"); + goto error; + } + + vhci_hcd->port_status[rhport] |= USB_PORT_STAT_SUSPEND; + break; + case USB_PORT_FEAT_POWER: + usbip_dbg_vhci_rh( + " SetPortFeature: USB_PORT_FEAT_POWER\n"); + if (hcd->speed == HCD_USB3) + vhci_hcd->port_status[rhport] |= USB_SS_PORT_STAT_POWER; + else + vhci_hcd->port_status[rhport] |= USB_PORT_STAT_POWER; break; + case USB_PORT_FEAT_BH_PORT_RESET: + usbip_dbg_vhci_rh( + " SetPortFeature: USB_PORT_FEAT_BH_PORT_RESET\n"); + /* Applicable only for USB3.0 hub */ + if (hcd->speed != HCD_USB3) { + pr_err("USB_PORT_FEAT_BH_PORT_RESET req not " + "supported for USB 2.0 roothub\n"); + goto error; + } + /* FALLS THROUGH */ case USB_PORT_FEAT_RESET: usbip_dbg_vhci_rh( " SetPortFeature: USB_PORT_FEAT_RESET\n"); - /* if it's already running, disconnect first */ - if (vhci_hcd->port_status[rhport] & USB_PORT_STAT_ENABLE) { - vhci_hcd->port_status[rhport] &= - ~(USB_PORT_STAT_ENABLE | - USB_PORT_STAT_LOW_SPEED | - USB_PORT_STAT_HIGH_SPEED); - /* FIXME test that code path! */ + /* if it's already enabled, disable */ + if (hcd->speed == HCD_USB3) { + vhci_hcd->port_status[rhport] = 0; + vhci_hcd->port_status[rhport] = + (USB_SS_PORT_STAT_POWER | + USB_PORT_STAT_CONNECTION | + USB_PORT_STAT_RESET); + } else if (vhci_hcd->port_status[rhport] & USB_PORT_STAT_ENABLE) { + vhci_hcd->port_status[rhport] &= ~(USB_PORT_STAT_ENABLE + | USB_PORT_STAT_LOW_SPEED + | USB_PORT_STAT_HIGH_SPEED); } + /* 50msec reset signaling */ vhci_hcd->re_timeout = jiffies + msecs_to_jiffies(50); - /* FALLTHROUGH */ + /* FALLS THROUGH */ default: usbip_dbg_vhci_rh(" SetPortFeature: default %d\n", wValue); - vhci_hcd->port_status[rhport] |= (1 << wValue); - break; + if (hcd->speed == HCD_USB3) { + if ((vhci_hcd->port_status[rhport] & + USB_SS_PORT_STAT_POWER) != 0) { + vhci_hcd->port_status[rhport] |= (1 << wValue); + } + } else + if ((vhci_hcd->port_status[rhport] & + USB_PORT_STAT_POWER) != 0) { + vhci_hcd->port_status[rhport] |= (1 << wValue); + } + } + break; + case GetPortErrorCount: + usbip_dbg_vhci_rh(" GetPortErrorCount\n"); + if (hcd->speed != HCD_USB3) { + pr_err("GetPortErrorCount req not " + "supported for USB 2.0 roothub\n"); + goto error; + } + /* We'll always return 0 since this is a dummy hub */ + *(__le32 *) buf = cpu_to_le32(0); + break; + case SetHubDepth: + usbip_dbg_vhci_rh(" SetHubDepth\n"); + if (hcd->speed != HCD_USB3) { + pr_err("SetHubDepth req not supported for " + "USB 2.0 roothub\n"); + goto error; } break; - default: - pr_err("default: no such request\n"); - + pr_err("default hub control req: %04x v%04x i%04x l%d\n", + typeReq, wValue, wIndex, wLength); +error: /* "protocol stall" on error */ retval = -EPIPE; } @@ -433,6 +575,9 @@ static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, spin_unlock_irqrestore(&vhci->lock, flags); + if ((vhci_hcd->port_status[rhport] & PORT_C_MASK) != 0) + usb_hcd_poll_rh_status(hcd); + return retval; } @@ -471,8 +616,7 @@ static void vhci_tx_urb(struct urb *urb, struct vhci_device *vdev) spin_unlock_irqrestore(&vdev->priv_lock, flags); } -static int vhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, - gfp_t mem_flags) +static int vhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags) { struct vhci_hcd *vhci_hcd = hcd_to_vhci_hcd(hcd); struct vhci *vhci = vhci_hcd->vhci; @@ -850,7 +994,6 @@ static void vhci_shutdown_connection(struct usbip_device *ud) pr_info("disconnect device\n"); } - static void vhci_device_reset(struct usbip_device *ud) { struct vhci_device *vdev = container_of(ud, struct vhci_device, ud); @@ -926,12 +1069,22 @@ static int vhci_setup(struct usb_hcd *hcd) { struct vhci *vhci = *((void **)dev_get_platdata(hcd->self.controller)); hcd->self.sg_tablesize = ~0; - - vhci->vhci_hcd_hs = hcd_to_vhci_hcd(hcd); - vhci->vhci_hcd_hs->vhci = vhci; - hcd->speed = HCD_USB2; - hcd->self.root_hub->speed = USB_SPEED_HIGH; - + if (usb_hcd_is_primary_hcd(hcd)) { + vhci->vhci_hcd_hs = hcd_to_vhci_hcd(hcd); + vhci->vhci_hcd_hs->vhci = vhci; + /* + * Mark the first roothub as being USB 2.0. + * The USB 3.0 roothub will be registered later by + * vhci_hcd_probe() + */ + hcd->speed = HCD_USB2; + hcd->self.root_hub->speed = USB_SPEED_HIGH; + } else { + vhci->vhci_hcd_ss = hcd_to_vhci_hcd(hcd); + vhci->vhci_hcd_ss->vhci = vhci; + hcd->speed = HCD_USB3; + hcd->self.root_hub->speed = USB_SPEED_SUPER; + } return 0; } @@ -943,7 +1096,8 @@ static int vhci_start(struct usb_hcd *hcd) usbip_dbg_vhci_hc("enter vhci_start\n"); - spin_lock_init(&vhci_hcd->vhci->lock); + if (usb_hcd_is_primary_hcd(hcd)) + spin_lock_init(&vhci_hcd->vhci->lock); /* initialize private data of usb_hcd */ @@ -970,7 +1124,7 @@ static int vhci_start(struct usb_hcd *hcd) } /* vhci_hcd is now ready to be controlled through sysfs */ - if (id == 0) { + if (id == 0 && usb_hcd_is_primary_hcd(hcd)) { err = vhci_init_attr_group(); if (err) { pr_err("init attr group\n"); @@ -997,7 +1151,7 @@ static void vhci_stop(struct usb_hcd *hcd) /* 1. remove the userland interface of vhci_hcd */ id = hcd_name_to_id(hcd_name(hcd)); - if (id == 0) { + if (id == 0 && usb_hcd_is_primary_hcd(hcd)) { sysfs_remove_group(&hcd_dev(hcd)->kobj, &vhci_attr_group); vhci_finish_attr_group(); } @@ -1058,12 +1212,30 @@ static int vhci_bus_resume(struct usb_hcd *hcd) #define vhci_bus_resume NULL #endif +/* Change a group of bulk endpoints to support multiple stream IDs */ +static int vhci_alloc_streams(struct usb_hcd *hcd, struct usb_device *udev, + struct usb_host_endpoint **eps, unsigned int num_eps, + unsigned int num_streams, gfp_t mem_flags) +{ + dev_dbg(&hcd->self.root_hub->dev, "vhci_alloc_streams not implemented\n"); + return 0; +} + +/* Reverts a group of bulk endpoints back to not using stream IDs. */ +static int vhci_free_streams(struct usb_hcd *hcd, struct usb_device *udev, + struct usb_host_endpoint **eps, unsigned int num_eps, + gfp_t mem_flags) +{ + dev_dbg(&hcd->self.root_hub->dev, "vhci_free_streams not implemented\n"); + return 0; +} + static struct hc_driver vhci_hc_driver = { .description = driver_name, .product_desc = driver_desc, .hcd_priv_size = sizeof(struct vhci_hcd), - .flags = HCD_USB2, + .flags = HCD_USB3 | HCD_SHARED, .reset = vhci_setup, .start = vhci_start, @@ -1078,12 +1250,16 @@ static struct hc_driver vhci_hc_driver = { .hub_control = vhci_hub_control, .bus_suspend = vhci_bus_suspend, .bus_resume = vhci_bus_resume, + + .alloc_streams = vhci_alloc_streams, + .free_streams = vhci_free_streams, }; static int vhci_hcd_probe(struct platform_device *pdev) { struct vhci *vhci; struct usb_hcd *hcd_hs; + struct usb_hcd *hcd_ss; int ret; usbip_dbg_vhci_hc("name %s id %d\n", pdev->name, pdev->id); @@ -1094,7 +1270,7 @@ static int vhci_hcd_probe(struct platform_device *pdev) */ hcd_hs = usb_create_hcd(&vhci_hc_driver, &pdev->dev, dev_name(&pdev->dev)); if (!hcd_hs) { - pr_err("create hcd failed\n"); + pr_err("create primary hcd failed\n"); return -ENOMEM; } hcd_hs->has_tt = 1; @@ -1109,12 +1285,31 @@ static int vhci_hcd_probe(struct platform_device *pdev) goto put_usb2_hcd; } + hcd_ss = usb_create_shared_hcd(&vhci_hc_driver, &pdev->dev, + dev_name(&pdev->dev), hcd_hs); + if (!hcd_ss) { + ret = -ENOMEM; + pr_err("create shared hcd failed\n"); + goto remove_usb2_hcd; + } + + ret = usb_add_hcd(hcd_ss, 0, 0); + if (ret) { + pr_err("usb_add_hcd ss failed %d\n", ret); + goto put_usb3_hcd; + } + usbip_dbg_vhci_hc("bye\n"); return 0; +put_usb3_hcd: + usb_put_hcd(hcd_ss); +remove_usb2_hcd: + usb_remove_hcd(hcd_hs); put_usb2_hcd: usb_put_hcd(hcd_hs); vhci->vhci_hcd_hs = NULL; + vhci->vhci_hcd_ss = NULL; return ret; } @@ -1127,10 +1322,14 @@ static int vhci_hcd_remove(struct platform_device *pdev) * then reverses the effects of usb_add_hcd(), * invoking the HCD's stop() methods. */ + usb_remove_hcd(vhci_hcd_to_hcd(vhci->vhci_hcd_ss)); + usb_put_hcd(vhci_hcd_to_hcd(vhci->vhci_hcd_ss)); + usb_remove_hcd(vhci_hcd_to_hcd(vhci->vhci_hcd_hs)); usb_put_hcd(vhci_hcd_to_hcd(vhci->vhci_hcd_hs)); vhci->vhci_hcd_hs = NULL; + vhci->vhci_hcd_ss = NULL; return 0; } @@ -1142,7 +1341,7 @@ static int vhci_hcd_suspend(struct platform_device *pdev, pm_message_t state) { struct usb_hcd *hcd; struct vhci *vhci; - int rhport = 0; + int rhport; int connected = 0; int ret = 0; unsigned long flags; @@ -1161,6 +1360,10 @@ static int vhci_hcd_suspend(struct platform_device *pdev, pm_message_t state) if (vhci->vhci_hcd_hs->port_status[rhport] & USB_PORT_STAT_CONNECTION) connected += 1; + + if (vhci->vhci_hcd_ss->port_status[rhport] & + USB_PORT_STAT_CONNECTION) + connected += 1; } spin_unlock_irqrestore(&vhci->lock, flags); diff --git a/drivers/usb/usbip/vhci_sysfs.c b/drivers/usb/usbip/vhci_sysfs.c index 63e10a4ffeec..cac2319df742 100644 --- a/drivers/usb/usbip/vhci_sysfs.c +++ b/drivers/usb/usbip/vhci_sysfs.c @@ -29,6 +29,42 @@ /* TODO: refine locking ?*/ +/* + * output example: + * hub port sta spd dev socket local_busid + * hs 0000 004 000 00000000 c5a7bb80 1-2.3 + * ................................................ + * ss 0008 004 000 00000000 d8cee980 2-3.4 + * ................................................ + * + * IP address can be retrieved from a socket pointer address by looking + * up /proc/net/{tcp,tcp6}. Also, a userland program may remember a + * port number and its peer IP address. + */ +static void port_show_vhci(char **out, int hub, int port, struct vhci_device *vdev) +{ + if (hub == HUB_SPEED_HIGH) + *out += sprintf(*out, "hs %04u %03u ", + port, vdev->ud.status); + else /* hub == HUB_SPEED_SUPER */ + *out += sprintf(*out, "ss %04u %03u ", + port, vdev->ud.status); + + if (vdev->ud.status == VDEV_ST_USED) { + *out += sprintf(*out, "%03u %08x ", + vdev->speed, vdev->devid); + *out += sprintf(*out, "%16p %s", + vdev->ud.tcp_socket, + dev_name(&vdev->udev->dev)); + + } else { + *out += sprintf(*out, "000 00000000 "); + *out += sprintf(*out, "0000000000000000 0-0"); + } + + *out += sprintf(*out, "\n"); +} + /* Sysfs entry to show port status */ static ssize_t status_show_vhci(int pdev_nr, char *out) { @@ -51,37 +87,21 @@ static ssize_t status_show_vhci(int pdev_nr, char *out) spin_lock_irqsave(&vhci->lock, flags); - /* - * output example: - * port sta spd dev socket local_busid - * 0000 004 000 00000000 c5a7bb80 1-2.3 - * 0001 004 000 00000000 d8cee980 2-3.4 - * - * IP address can be retrieved from a socket pointer address by looking - * up /proc/net/{tcp,tcp6}. Also, a userland program may remember a - * port number and its peer IP address. - */ for (i = 0; i < VHCI_HC_PORTS; i++) { - struct vhci_device *vdev = &vhci_hcd->vdev[i]; + struct vhci_device *vdev = &vhci->vhci_hcd_hs->vdev[i]; spin_lock(&vdev->ud.lock); - out += sprintf(out, "%04u %03u ", - (pdev_nr * VHCI_HC_PORTS) + i, - vdev->ud.status); - - if (vdev->ud.status == VDEV_ST_USED) { - out += sprintf(out, "%03u %08x ", - vdev->speed, vdev->devid); - out += sprintf(out, "%16p %s", - vdev->ud.tcp_socket, - dev_name(&vdev->udev->dev)); - - } else { - out += sprintf(out, "000 00000000 "); - out += sprintf(out, "0000000000000000 0-0"); - } + port_show_vhci(&out, HUB_SPEED_HIGH, + pdev_nr * VHCI_HC_PORTS * 2 + i, vdev); + spin_unlock(&vdev->ud.lock); + } - out += sprintf(out, "\n"); + for (i = 0; i < VHCI_HC_PORTS; i++) { + struct vhci_device *vdev = &vhci->vhci_hcd_ss->vdev[i]; + + spin_lock(&vdev->ud.lock); + port_show_vhci(&out, HUB_SPEED_SUPER, + pdev_nr * VHCI_HC_PORTS * 2 + VHCI_HC_PORTS + i, vdev); spin_unlock(&vdev->ud.lock); } @@ -96,8 +116,16 @@ static ssize_t status_show_not_ready(int pdev_nr, char *out) int i = 0; for (i = 0; i < VHCI_HC_PORTS; i++) { - out += sprintf(out, "%04u %03u ", - (pdev_nr * VHCI_HC_PORTS) + i, + out += sprintf(out, "hs %04u %03u ", + (pdev_nr * VHCI_HC_PORTS * 2) + i, + VDEV_ST_NOTASSIGNED); + out += sprintf(out, "000 00000000 0000000000000000 0-0"); + out += sprintf(out, "\n"); + } + + for (i = 0; i < VHCI_HC_PORTS; i++) { + out += sprintf(out, "ss %04u %03u ", + (pdev_nr * VHCI_HC_PORTS * 2) + VHCI_HC_PORTS + i, VDEV_ST_NOTASSIGNED); out += sprintf(out, "000 00000000 0000000000000000 0-0"); out += sprintf(out, "\n"); @@ -129,7 +157,7 @@ static ssize_t status_show(struct device *dev, int pdev_nr; out += sprintf(out, - "port sta spd dev socket local_busid\n"); + "hub port sta spd dev socket local_busid\n"); pdev_nr = status_name_to_id(attr->attr.name); if (pdev_nr < 0) @@ -145,7 +173,10 @@ static ssize_t nports_show(struct device *dev, struct device_attribute *attr, { char *s = out; - out += sprintf(out, "%d\n", VHCI_HC_PORTS * vhci_num_controllers); + /* + * Half the ports are for SPEED_HIGH and half for SPEED_SUPER, thus the * 2. + */ + out += sprintf(out, "%d\n", VHCI_HC_PORTS * vhci_num_controllers * 2); return out - s; } static DEVICE_ATTR_RO(nports); @@ -200,6 +231,7 @@ static ssize_t store_detach(struct device *dev, struct device_attribute *attr, { __u32 port = 0, pdev_nr = 0, rhport = 0; struct usb_hcd *hcd; + struct vhci_hcd *vhci_hcd; int ret; if (kstrtoint(buf, 10, &port) < 0) @@ -217,7 +249,14 @@ static ssize_t store_detach(struct device *dev, struct device_attribute *attr, return -EAGAIN; } - ret = vhci_port_disconnect(hcd_to_vhci_hcd(hcd), rhport); + usbip_dbg_vhci_sysfs("rhport %d\n", rhport); + + if ((port / VHCI_HC_PORTS) % 2) + vhci_hcd = hcd_to_vhci_hcd(hcd)->vhci->vhci_hcd_ss; + else + vhci_hcd = hcd_to_vhci_hcd(hcd)->vhci->vhci_hcd_hs; + + ret = vhci_port_disconnect(vhci_hcd, rhport); if (ret < 0) return -EINVAL; @@ -301,7 +340,11 @@ static ssize_t store_attach(struct device *dev, struct device_attribute *attr, vhci_hcd = hcd_to_vhci_hcd(hcd); vhci = vhci_hcd->vhci; - vdev = &vhci_hcd->vdev[rhport]; + + if (speed == USB_SPEED_SUPER) + vdev = &vhci->vhci_hcd_ss->vdev[rhport]; + else + vdev = &vhci->vhci_hcd_hs->vdev[rhport]; /* Extract socket from fd. */ socket = sockfd_lookup(sockfd, &err); diff --git a/tools/usb/usbip/libsrc/vhci_driver.c b/tools/usb/usbip/libsrc/vhci_driver.c index 3d8189b4f539..9bd2cd71645d 100644 --- a/tools/usb/usbip/libsrc/vhci_driver.c +++ b/tools/usb/usbip/libsrc/vhci_driver.c @@ -52,9 +52,10 @@ static int parse_status(const char *value) unsigned long socket; char lbusid[SYSFS_BUS_ID_SIZE]; struct usbip_imported_device *idev; + char hub[3]; - ret = sscanf(c, "%d %d %d %x %lx %31s\n", - &port, &status, &speed, + ret = sscanf(c, "%2s %d %d %d %x %lx %31s\n", + hub, &port, &status, &speed, &devid, &socket, lbusid); if (ret < 5) { @@ -62,15 +63,19 @@ static int parse_status(const char *value) BUG(); } - dbg("port %d status %d speed %d devid %x", - port, status, speed, devid); + dbg("hub %s port %d status %d speed %d devid %x", + hub, port, status, speed, devid); dbg("socket %lx lbusid %s", socket, lbusid); /* if a device is connected, look at it */ idev = &vhci_driver->idev[port]; - memset(idev, 0, sizeof(*idev)); + if (strncmp("hs", hub, 2) == 0) + idev->hub = HUB_SPEED_HIGH; + else /* strncmp("ss", hub, 2) == 0 */ + idev->hub = HUB_SPEED_SUPER; + idev->port = port; idev->status = status; @@ -320,11 +325,15 @@ err: } -int usbip_vhci_get_free_port(void) +int usbip_vhci_get_free_port(uint32_t speed) { for (int i = 0; i < vhci_driver->nports; i++) { + if (speed == USB_SPEED_SUPER && + vhci_driver->idev[i].hub != HUB_SPEED_SUPER) + continue; + if (vhci_driver->idev[i].status == VDEV_ST_NULL) - return i; + return vhci_driver->idev[i].port; } return -1; diff --git a/tools/usb/usbip/libsrc/vhci_driver.h b/tools/usb/usbip/libsrc/vhci_driver.h index dfe19c1c0245..4898d3bafb10 100644 --- a/tools/usb/usbip/libsrc/vhci_driver.h +++ b/tools/usb/usbip/libsrc/vhci_driver.h @@ -14,7 +14,13 @@ #define USBIP_VHCI_DEVICE_NAME "vhci_hcd.0" #define MAXNPORT 128 +enum hub_speed { + HUB_SPEED_HIGH = 0, + HUB_SPEED_SUPER, +}; + struct usbip_imported_device { + enum hub_speed hub; uint8_t port; uint32_t status; @@ -46,7 +52,7 @@ void usbip_vhci_driver_close(void); int usbip_vhci_refresh_device_list(void); -int usbip_vhci_get_free_port(void); +int usbip_vhci_get_free_port(uint32_t speed); int usbip_vhci_attach_device2(uint8_t port, int sockfd, uint32_t devid, uint32_t speed); diff --git a/tools/usb/usbip/src/usbip_attach.c b/tools/usb/usbip/src/usbip_attach.c index 62a297ff647a..6e89768ffe30 100644 --- a/tools/usb/usbip/src/usbip_attach.c +++ b/tools/usb/usbip/src/usbip_attach.c @@ -94,6 +94,7 @@ static int import_device(int sockfd, struct usbip_usb_device *udev) { int rc; int port; + uint32_t speed = udev->speed; rc = usbip_vhci_driver_open(); if (rc < 0) { @@ -101,7 +102,7 @@ static int import_device(int sockfd, struct usbip_usb_device *udev) return -1; } - port = usbip_vhci_get_free_port(); + port = usbip_vhci_get_free_port(speed); if (port < 0) { err("no free port"); usbip_vhci_driver_close(); -- cgit v1.2.3-59-g8ed1b