summaryrefslogtreecommitdiffstats
path: root/tools/usb/usbip
diff options
context:
space:
mode:
Diffstat (limited to 'tools/usb/usbip')
-rw-r--r--tools/usb/usbip/README59
-rw-r--r--tools/usb/usbip/libsrc/usbip_common.c9
-rw-r--r--tools/usb/usbip/libsrc/usbip_host_common.c28
-rw-r--r--tools/usb/usbip/libsrc/vhci_driver.c155
-rw-r--r--tools/usb/usbip/libsrc/vhci_driver.h10
-rw-r--r--tools/usb/usbip/src/usbip.c2
-rw-r--r--tools/usb/usbip/src/usbip_attach.c5
-rwxr-xr-xtools/usb/usbip/vudc/vudc_server_example.sh107
8 files changed, 308 insertions, 67 deletions
diff --git a/tools/usb/usbip/README b/tools/usb/usbip/README
index 831f49fea3ce..7844490fc603 100644
--- a/tools/usb/usbip/README
+++ b/tools/usb/usbip/README
@@ -4,10 +4,33 @@
# Copyright (C) 2011 matt mooney <mfm@muteddisk.com>
# 2005-2008 Takahiro Hirofuchi
+[Overview]
+USB/IP protocol allows to pass USB device from server to client over the
+network. Server is a machine which provides (shares) a USB device. Client is
+a machine which uses USB device provided by server over the network.
+The USB device may be either physical device connected to a server or
+software entity created on a server using USB gadget subsystem.
+Whole project consists of four parts:
+
+ - usbip-vhci
+ A client side kernel module which provides a virtual USB Host Controller
+ and allows to import a USB device from a remote machine.
+
+ - usbip-host (stub driver)
+ A server side module which provides a USB device driver which can be
+ bound to a physical USB device to make it exportable.
+
+ - usbip-vudc
+ A server side module which provides a virtual USB Device Controller and allows
+ to export a USB device created using USB Gadget Subsystem.
+
+ - usbip-utils
+ A set of userspace tools used to handle connection and management.
+ Used on both sides.
[Requirements]
- USB/IP device drivers
- Found in the staging directory of the Linux kernel.
+ Found in the drivers/usb/usbip/ directory of the Linux kernel tree.
- libudev >= 2.0
libudev library
@@ -36,6 +59,10 @@
[Usage]
+On a server side there are two entities which can be shared.
+First of them is physical usb device connected to the machine.
+To make it available below steps should be executed:
+
server:# (Physically attach your USB device.)
server:# insmod usbip-core.ko
@@ -52,6 +79,30 @@
- The USB device 1-2 is now exportable to other hosts!
- Use `usbip unbind --busid 1-2' to stop exporting the device.
+Second of shareable entities is USB Gadget created using USB Gadget Subsystem
+on a server machine. To make it available below steps should be executed:
+
+ server:# (Create your USB gadget)
+ - Currently the most preferable way of creating a new USB gadget
+ is ConfigFS Composite Gadget. Please refer to its documentation
+ for details.
+ - See vudc_server_example.sh for a short example of USB gadget creation
+
+ server:# insmod usbip-core.ko
+ server:# insmod usbip-vudc.ko
+ - To create more than one instance of vudc use num module param
+
+ server:# (Bind gadget to one of available vudc)
+ - Assign your new gadget to USB/IP UDC
+ - Using ConfigFS interface you may do this simply by:
+ server:# cd /sys/kernel/config/usb_gadget/<gadget_name>
+ server:# echo "usbip-vudc.0" > UDC
+
+ server:# usbipd -D --device
+ - Start usbip daemon.
+
+To attach new device to client machine below commands should be used:
+
client:# insmod usbip-core.ko
client:# insmod vhci-hcd.ko
@@ -60,6 +111,8 @@
client:# usbip attach --remote <host> --busid 1-2
- Connect the remote USB device.
+ - When using vudc on a server side busid is really vudc instance name.
+ For example: usbip-vudc.0
client:# usbip port
- Show virtual port status.
@@ -191,7 +244,9 @@ Detach the imported device:
- See 'Debug Tips' on the project wiki.
- http://usbip.wiki.sourceforge.net/how-to-debug-usbip
- usbip-host.ko must be bound to the target device.
- - See /proc/bus/usb/devices and find "Driver=..." lines of the device.
+ - See /sys/kernel/debug/usb/devices and find "Driver=..." lines of the device.
+ - Target USB gadget must be bound to vudc
+ (using USB gadget susbsys, not usbip bind command)
- Shutdown firewall.
- usbip now uses TCP port 3240.
- Disable SELinux.
diff --git a/tools/usb/usbip/libsrc/usbip_common.c b/tools/usb/usbip/libsrc/usbip_common.c
index ac73710473de..1517a232ab18 100644
--- a/tools/usb/usbip/libsrc/usbip_common.c
+++ b/tools/usb/usbip/libsrc/usbip_common.c
@@ -215,9 +215,16 @@ int read_usb_interface(struct usbip_usb_device *udev, int i,
struct usbip_usb_interface *uinf)
{
char busid[SYSFS_BUS_ID_SIZE];
+ int size;
struct udev_device *sif;
- sprintf(busid, "%s:%d.%d", udev->busid, udev->bConfigurationValue, i);
+ size = snprintf(busid, sizeof(busid), "%s:%d.%d",
+ udev->busid, udev->bConfigurationValue, i);
+ if (size < 0 || (unsigned int)size >= sizeof(busid)) {
+ err("busid length %i >= %lu or < 0", size,
+ (long unsigned)sizeof(busid));
+ return -1;
+ }
sif = udev_device_new_from_subsystem_sysname(udev_context, "usb", busid);
if (!sif) {
diff --git a/tools/usb/usbip/libsrc/usbip_host_common.c b/tools/usb/usbip/libsrc/usbip_host_common.c
index 9d415228883d..6ff7b601f854 100644
--- a/tools/usb/usbip/libsrc/usbip_host_common.c
+++ b/tools/usb/usbip/libsrc/usbip_host_common.c
@@ -40,13 +40,20 @@ struct udev *udev_context;
static int32_t read_attr_usbip_status(struct usbip_usb_device *udev)
{
char status_attr_path[SYSFS_PATH_MAX];
+ int size;
int fd;
int length;
char status;
int value = 0;
- snprintf(status_attr_path, SYSFS_PATH_MAX, "%s/usbip_status",
- udev->path);
+ size = snprintf(status_attr_path, sizeof(status_attr_path),
+ "%s/usbip_status", udev->path);
+ if (size < 0 || (unsigned int)size >= sizeof(status_attr_path)) {
+ err("usbip_status path length %i >= %lu or < 0", size,
+ (long unsigned)sizeof(status_attr_path));
+ return -1;
+ }
+
fd = open(status_attr_path, O_RDONLY);
if (fd < 0) {
@@ -218,6 +225,7 @@ int usbip_export_device(struct usbip_exported_device *edev, int sockfd)
{
char attr_name[] = "usbip_sockfd";
char sockfd_attr_path[SYSFS_PATH_MAX];
+ int size;
char sockfd_buff[30];
int ret;
@@ -237,10 +245,20 @@ int usbip_export_device(struct usbip_exported_device *edev, int sockfd)
}
/* only the first interface is true */
- snprintf(sockfd_attr_path, sizeof(sockfd_attr_path), "%s/%s",
- edev->udev.path, attr_name);
+ size = snprintf(sockfd_attr_path, sizeof(sockfd_attr_path), "%s/%s",
+ edev->udev.path, attr_name);
+ if (size < 0 || (unsigned int)size >= sizeof(sockfd_attr_path)) {
+ err("exported device path length %i >= %lu or < 0", size,
+ (long unsigned)sizeof(sockfd_attr_path));
+ return -1;
+ }
- snprintf(sockfd_buff, sizeof(sockfd_buff), "%d\n", sockfd);
+ size = snprintf(sockfd_buff, sizeof(sockfd_buff), "%d\n", sockfd);
+ if (size < 0 || (unsigned int)size >= sizeof(sockfd_buff)) {
+ err("socket length %i >= %lu or < 0", size,
+ (long unsigned)sizeof(sockfd_buff));
+ return -1;
+ }
ret = write_sysfs_attribute(sockfd_attr_path, sockfd_buff,
strlen(sockfd_buff));
diff --git a/tools/usb/usbip/libsrc/vhci_driver.c b/tools/usb/usbip/libsrc/vhci_driver.c
index ad9204773533..9bd2cd71645d 100644
--- a/tools/usb/usbip/libsrc/vhci_driver.c
+++ b/tools/usb/usbip/libsrc/vhci_driver.c
@@ -7,6 +7,7 @@
#include <limits.h>
#include <netdb.h>
#include <libudev.h>
+#include <dirent.h>
#include "sysfs_utils.h"
#undef PROGNAME
@@ -35,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)
@@ -57,9 +51,11 @@ 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;
+ 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) {
@@ -67,34 +63,36 @@ 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 */
- {
- struct usbip_imported_device *idev = &vhci_driver->idev[port];
+ idev = &vhci_driver->idev[port];
+ memset(idev, 0, sizeof(*idev));
- idev->port = port;
- idev->status = status;
+ if (strncmp("hs", hub, 2) == 0)
+ idev->hub = HUB_SPEED_HIGH;
+ else /* strncmp("ss", hub, 2) == 0 */
+ idev->hub = HUB_SPEED_SUPER;
- 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)
@@ -107,49 +105,73 @@ 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)
{
- char *c;
- int nports = 0;
- const char *attr_status;
+ const char *attr_nports;
- attr_status = udev_device_get_sysattr_value(vhci_driver->hc_device,
- "status");
- if (!attr_status) {
- err("udev_device_get_sysattr_value failed");
+ attr_nports = udev_device_get_sysattr_value(vhci_driver->hc_device, "nports");
+ if (!attr_nports) {
+ err("udev_device_get_sysattr_value nports failed");
return -1;
}
- /* skip a header line */
- c = strchr(attr_status, '\n');
- if (!c)
- return 0;
- c++;
+ return (int)strtoul(attr_nports, NULL, 10);
+}
- while (*c != '\0') {
- /* go to the next line */
- c = strchr(c, '\n');
- if (!c)
- return nports;
- c++;
- nports += 1;
+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 nports;
+ return n;
}
/*
@@ -231,16 +253,31 @@ 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;
}
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;
+ }
+
+ 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;
@@ -288,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 fa2316cf2cac..4898d3bafb10 100644
--- a/tools/usb/usbip/libsrc/vhci_driver.h
+++ b/tools/usb/usbip/libsrc/vhci_driver.h
@@ -11,9 +11,16 @@
#include "usbip_common.h"
#define USBIP_VHCI_BUS_TYPE "platform"
+#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;
@@ -31,6 +38,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];
};
@@ -44,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.c b/tools/usb/usbip/src/usbip.c
index d7599d943529..73d8eee8130b 100644
--- a/tools/usb/usbip/src/usbip.c
+++ b/tools/usb/usbip/src/usbip.c
@@ -176,6 +176,8 @@ int main(int argc, char *argv[])
break;
case '?':
printf("usbip: invalid option\n");
+ /* Terminate after printing error */
+ /* FALLTHRU */
default:
usbip_usage();
goto out;
diff --git a/tools/usb/usbip/src/usbip_attach.c b/tools/usb/usbip/src/usbip_attach.c
index 70a6b507fb62..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,13 +102,15 @@ 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();
return -1;
}
+ dbg("got free port %d", port);
+
rc = usbip_vhci_attach_device(port, sockfd, udev->busnum,
udev->devnum, udev->speed);
if (rc < 0) {
diff --git a/tools/usb/usbip/vudc/vudc_server_example.sh b/tools/usb/usbip/vudc/vudc_server_example.sh
new file mode 100755
index 000000000000..2736be64f203
--- /dev/null
+++ b/tools/usb/usbip/vudc/vudc_server_example.sh
@@ -0,0 +1,107 @@
+#!/bin/bash
+
+################################################################################
+# This is free and unencumbered software released into the public domain.
+#
+# Anyone is free to copy, modify, publish, use, compile, sell, or
+# distribute this software, either in source code form or as a compiled
+# binary, for any purpose, commercial or non-commercial, and by any
+# means.
+#
+# In jurisdictions that recognize copyright laws, the author or authors
+# of this software dedicate any and all copyright interest in the
+# software to the public domain. We make this dedication for the benefit
+# of the public at large and to the detriment of our heirs and
+# successors. We intend this dedication to be an overt act of
+# relinquishment in perpetuity of all present and future rights to this
+# software under copyright law.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+# IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+# OTHER DEALINGS IN THE SOFTWARE.
+#
+# For more information, please refer to <http://unlicense.org/>
+################################################################################
+
+################################################################################
+# This is a sample script which shows how to use vUDC with ConfigFS gadgets
+################################################################################
+
+# Stop script on error
+set -e
+
+################################################################################
+# Create your USB gadget
+# You may use bare ConfigFS interface (as below)
+# or libusbgx or gt toool
+# Instead of ConfigFS gadgets you may use any of legacy gadgets.
+################################################################################
+CONFIGFS_MOUNT_POINT="/sys/kernel/config"
+GADGET_NAME="g1"
+ID_VENDOR="0x1d6b"
+ID_PRODUCT="0x0104"
+
+cd ${CONFIGFS_MOUNT_POINT}/usb_gadget
+# Create a new USB gadget
+mkdir ${GADGET_NAME}
+cd ${GADGET_NAME}
+
+# This gadget contains one function - ACM (serial port over USB)
+FUNC_DIR="functions/acm.ser0"
+mkdir ${FUNC_DIR}
+
+# Just one configuration
+mkdir configs/c.1
+ln -s ${FUNC_DIR} configs/c.1
+
+# Set our gadget identity
+echo ${ID_VENDOR} > idVendor
+echo ${ID_PRODUCT} > idProduct
+
+################################################################################
+# Load vudc-module if vudc is not available
+# You may change value of num param to get more than one vUDC instance
+################################################################################
+[[ -d /sys/class/udc/usbip-vudc.0 ]] || modprobe usbip-vudc num=1
+
+################################################################################
+# Bind gadget to our vUDC
+# By default we bind to first one but you may change this if you would like
+# to use more than one instance
+################################################################################
+echo "usbip-vudc.0" > UDC
+
+################################################################################
+# Let's now run our usbip daemon in a USB device mode
+################################################################################
+usbipd --device &
+
+################################################################################
+# Now your USB gadget is available using USB/IP protocol.
+# To prepare your client, you should ensure that usbip-vhci module is inside
+# your kernel. If it's not then you can load it:
+#
+# $ modprobe usbip-vhci
+#
+# To check availability of your gadget you may try to list devices exported
+# on a remote server:
+#
+# $ modprobe usbip-vhci
+# $ usbip list -r $SERVER_IP
+# Exportable USB devices
+# ======================
+# usbipd: info: request 0x8005(6): complete
+# - 127.0.0.1
+# usbip-vudc.0: Linux Foundation : unknown product (1d6b:0104)
+# : /sys/devices/platform/usbip-vudc.0
+# : (Defined at Interface level) (00/00/00)
+#
+# To attach this device to your client you may use:
+#
+# $ usbip attach -r $SERVER_IP -d usbip-vudc.0
+#
+################################################################################
OpenPOWER on IntegriCloud