Originally, USB/IP transmits requests and response PDUs for preparation 
to transfer URBs in user space, after completion of the preparation, 
URBs are transmitted in kernel space.

To make easy to introduce application network protocols like WebSocket, 
the driver, usbip_ux.ko, forwards URBs to USB/IP user space utilities. 
Then, the utilities exchange URBs in userspace.

To do so, tools/usb/usbip/libsrc/usbip_ux.c includes tx/rx threads to 
read/wite URBs from usbip_ux.ko and transfer URBs in userspace. When 
usbip_ux.ko is installed, /dev/usbip-ux will be found, then the threads 
will be started. Otherwise, threads will not be started and original 
kernel space transmission is valid.

Signed-off-by: Nobuo Iwata <nobuo.iw...@fujixerox.co.jp>
---
 tools/usb/usbip/libsrc/Makefile.am     |   1 +
 tools/usb/usbip/libsrc/usbip_ux.c      | 244 +++++++++++++++++++++++++
 tools/usb/usbip/libsrc/usbip_ux.h      |  30 +++
 tools/usb/usbip/libsrc/vhci_driver.c   |  10 +-
 tools/usb/usbip/src/usbip_attach.c     |  30 ++-
 tools/usb/usbip/src/usbip_connect.c    |  18 +-
 tools/usb/usbip/src/usbip_disconnect.c |  11 +-
 tools/usb/usbip/src/usbipd.c           |   5 +-
 tools/usb/usbip/src/usbipd_app.c       |  14 ++
 tools/usb/usbip/src/usbipd_dev.c       |  30 ++-
 10 files changed, 370 insertions(+), 23 deletions(-)

diff --git a/tools/usb/usbip/libsrc/Makefile.am 
b/tools/usb/usbip/libsrc/Makefile.am
index 7c8f8a4..5754425 100644
--- a/tools/usb/usbip/libsrc/Makefile.am
+++ b/tools/usb/usbip/libsrc/Makefile.am
@@ -5,4 +5,5 @@ libusbip_la_LDFLAGS  = -version-info @LIBUSBIP_VERSION@
 lib_LTLIBRARIES := libusbip.la
 libusbip_la_SOURCES := names.c names.h usbip_host_driver.c usbip_host_driver.h 
\
                       usbip_common.c usbip_common.h vhci_driver.c 
vhci_driver.h \
+                      usbip_ux.c usbip_ux.h \
                       sysfs_utils.c sysfs_utils.h
diff --git a/tools/usb/usbip/libsrc/usbip_ux.c 
b/tools/usb/usbip/libsrc/usbip_ux.c
new file mode 100644
index 0000000..3ac45a72
--- /dev/null
+++ b/tools/usb/usbip/libsrc/usbip_ux.c
@@ -0,0 +1,244 @@
+/*
+ * Copyright (C) 2015 Nobuo Iwata
+ *
+ * USB/IP URB transmission in userspace.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include "usbip_common.h"
+#include "usbip_ux.h"
+
+#undef  PROGNAME
+#define PROGNAME "libusbip"
+
+#define DEVNAME "/dev/" USBIP_UX_DEV_NAME
+
+#define BLEN 1500
+
+#ifdef DEBUG
+void dump_buff(char *buff, size_t bufflen, char *label)
+{
+#define DUMP_BUFF 80
+#define WORK_BUFF 16
+       size_t i = 0, j;
+       char b[DUMP_BUFF];
+       char bb[WORK_BUFF];
+
+       dbg("dump %s for %zd bytes", label, bufflen);
+       for(i=0;i<bufflen;i++) {
+               j = i % 16;
+               if (j == 0) {
+                       b[0] = 0;
+                       sprintf(bb, "%04zx  %02x", i, *(buff+i) & 0xff);
+               } else if (j == 8) {
+                       sprintf(bb, "  %02x", *(buff+i) & 0xff);
+               } else {
+                       sprintf(bb, " %02x", *(buff+i) & 0xff);
+               }
+               strncat(b, bb, WORK_BUFF);
+               if (j == 15 || i == bufflen-1) {
+                       dbg("%s", b);
+               }
+       }
+}
+#else
+#define dump_buff(buff, bufflen, label) while(0){}
+#endif
+
+static void *usbip_ux_rx(void *arg)
+{
+       usbip_ux_t *ux = (usbip_ux_t*)arg;
+       ssize_t received, written, ret;
+       int good = 1;
+       char buf[BLEN];
+
+       while(good) {
+               received = recv(ux->sockfd, buf, BLEN, 0);
+               if (received == 0) {
+                       dbg("connection closed on sock:%p", ux->kaddr.sock);
+                       break;
+               } else if (received < 0) {
+                       dbg("receive error on sock:%p", ux->kaddr.sock);
+                       break;
+               }
+               dump_buff(buf, received, "ux received");
+               written = 0;
+               while(written < received) {
+                       ret = write(ux->devfd, buf+written, received-written);
+                       if (ret < 0) {
+                               dbg("write error for sock:%p", ux->kaddr.sock);
+                               good = 0;
+                               break;
+                       }
+                       written += ret;
+               }
+       }
+       dbg("end of ux-rx for sock:%p", ux->kaddr.sock);
+       ioctl(ux->devfd, USBIP_UX_IOCINTR);
+       return 0;
+}
+
+static void *usbip_ux_tx(void *arg)
+{
+       usbip_ux_t *ux = (usbip_ux_t*)arg;
+       ssize_t sent, reads;
+       char buf[BLEN];
+
+       for(;;) {
+               reads = read(ux->devfd, buf, BLEN);
+               if (reads == 0) {
+#ifdef DEBUG
+                       dbg("end of read on sock:%p continue.", ux->kaddr.sock);
+#endif
+                       sched_yield();
+                       continue;
+               } else  if (reads < 0) {
+                       dbg("read error on sock:%p", ux->kaddr.sock);
+                       break;
+               }
+               dump_buff(buf, reads, "ux sending");
+               sent = send(ux->sockfd, buf, reads, 0);
+               if (sent < 0) {
+                       dbg("connection closed on sock:%p", ux->kaddr.sock);
+                       break;
+               } else if (sent < reads) {
+                       dbg("send error on sock:%p %zd < %zd", ux->kaddr.sock,
+                               sent, reads);
+                       break;
+               }
+       }
+       dbg("end of ux-tx for sock:%p", ux->kaddr.sock);
+       shutdown(ux->sockfd, SHUT_RDWR);
+       return 0;
+}
+
+/*
+ * Setup user space mode.
+ * Null will be set in ux if usbip_ux.ko is not installed.
+ */
+int usbip_ux_setup(int sockfd, usbip_ux_t **uxp)
+{
+       usbip_ux_t *ux;
+       int fd, ret;
+       
+       *uxp = NULL;
+
+       fd = open(DEVNAME, O_RDWR);
+       if (fd < 0) {
+               dbg("failed to open %s", DEVNAME);
+               dbg("URBs will be transferred in kernel space");
+               return 0;
+       }
+       ux = (usbip_ux_t*)malloc(sizeof(usbip_ux_t));
+       if (ux == NULL) {
+               dbg("failed to alloc ux data");
+               goto err_close;
+       }
+       ux->devfd = fd;
+       ux->started = 0;
+       ux->sockfd = sockfd;
+       ret = ioctl(ux->devfd, USBIP_UX_IOCSETSOCKFD, sockfd);
+       if (ret) {
+               dbg("failed to set sock fd");
+               goto err_free;
+       }
+       ret = ioctl(ux->devfd, USBIP_UX_IOCGETKADDR, &ux->kaddr);
+       if (ret) {
+               dbg("failed to get kaddr");
+               goto err_free;
+       }
+       dbg("successfully prepared userspace transmission sock:%p ux:%p pid:%d",
+                ux->kaddr.sock, ux->kaddr.ux, getpid());
+       *uxp = ux;
+       return 0;
+err_free:
+       free(ux);
+err_close:
+       close(ux->devfd);
+       return -1;
+}
+
+/*
+ * Only for error handling before start.
+ */
+void usbip_ux_cleanup(usbip_ux_t **ux)
+{
+       if (*ux == NULL) return;
+       close((*ux)->devfd);
+       free(*ux);
+       *ux = NULL;
+}
+
+/*
+ * Starts transmission threads.
+ */
+int usbip_ux_start(usbip_ux_t *ux)
+{
+       int ret;
+
+       if (ux == NULL) return 0;
+       ret = pthread_create(&ux->rx, NULL, usbip_ux_rx, ux);
+       if (ret) {
+               dbg("failed to start recv thread");
+               goto err;
+       }
+       ret = pthread_create(&ux->tx, NULL, usbip_ux_tx, ux);
+       if (ret) {
+               dbg("failed to start send thread");
+               goto err;
+       }
+       ux->started = 1;
+       dbg("successfully started userspace transmission");
+       return 0;
+err:
+       close(ux->devfd);
+       return -1;
+}
+
+/*
+ * Waits end of usespace transmission.
+ * Will return on following conditions.
+ * 1) Detached or unbound
+ * 2) Broken connection
+ * 3) Closed usbip-ux device
+ */
+void usbip_ux_join(usbip_ux_t *ux)
+{
+       if (ux == NULL) return;
+       dbg("waiting on userspace transmission threads");
+       pthread_join((ux)->tx, NULL);
+       pthread_join((ux)->rx, NULL);
+}
+
+void usbip_ux_interrupt(usbip_ux_t *ux)
+{
+       if (ux == NULL) return;
+       ioctl((ux)->devfd, USBIP_UX_IOCINTR);
+}
+
+void usbip_ux_interrupt_pgrp(void)
+{
+       int fd;
+
+       fd = open(DEVNAME, O_RDWR);
+       if (fd < 0) {
+               dbg("failed to open %s", DEVNAME);
+               return;
+       }
+       ioctl(fd, USBIP_UX_IOCINTRPGRP);
+       close(fd);
+}
+
+int usbip_ux_installed(void)
+{
+       struct stat buf;
+
+       if (stat(DEVNAME, &buf)) {
+               return 0;
+       }
+       return 1;
+}
diff --git a/tools/usb/usbip/libsrc/usbip_ux.h 
b/tools/usb/usbip/libsrc/usbip_ux.h
new file mode 100644
index 0000000..943008e
--- /dev/null
+++ b/tools/usb/usbip/libsrc/usbip_ux.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2015 Nobuo Iwata
+ *
+ * USB/IP URB transmission in userspace.
+ */
+
+#ifndef __USBIP_UX_H
+#define __USBIP_UX_H
+
+#include <pthread.h>
+#include <linux/usbip_ux.h>
+#include "usbip_common.h"
+
+typedef struct usbip_ux {
+       int sockfd;
+       int devfd;
+       int started;
+       pthread_t tx, rx;
+       struct usbip_ux_kaddr kaddr;
+} usbip_ux_t;
+
+int usbip_ux_setup(int sockfd, usbip_ux_t **uxp);
+void usbip_ux_cleanup(usbip_ux_t **ux);
+int usbip_ux_start(usbip_ux_t *ux);
+void usbip_ux_join(usbip_ux_t *ux);
+void usbip_ux_interrupt(usbip_ux_t *ux);
+void usbip_ux_interrupt_pgrp();
+int usbip_ux_installed(void);
+
+#endif /* !__USBIP_UX_H */
diff --git a/tools/usb/usbip/libsrc/vhci_driver.c 
b/tools/usb/usbip/libsrc/vhci_driver.c
index 4952cbd..a390047 100644
--- a/tools/usb/usbip/libsrc/vhci_driver.c
+++ b/tools/usb/usbip/libsrc/vhci_driver.c
@@ -58,21 +58,21 @@ static int parse_status(const char *value)
 
        while (*c != '\0') {
                int port, status, speed, devid;
-               unsigned long socket;
+               unsigned long socket, ux;
                char lbusid[SYSFS_BUS_ID_SIZE];
 
-               ret = sscanf(c, "%d %d %d %x %lx %31s\n",
+               ret = sscanf(c, "%d %d %d %x %lx %lx %31s\n",
                                &port, &status, &speed,
-                               &devid, &socket, lbusid);
+                               &devid, &socket, &ux, lbusid);
 
-               if (ret < 5) {
+               if (ret < 7) {
                        dbg("sscanf failed: %d", ret);
                        BUG();
                }
 
                dbg("port %d status %d speed %d devid %x",
                                port, status, speed, devid);
-               dbg("socket %lx lbusid %s", socket, lbusid);
+               dbg("socket %lx ux %lx lbusid %s", socket, ux, lbusid);
 
 
                /* if a device is connected, look at it */
diff --git a/tools/usb/usbip/src/usbip_attach.c 
b/tools/usb/usbip/src/usbip_attach.c
index 0817e92..0441e17 100644
--- a/tools/usb/usbip/src/usbip_attach.c
+++ b/tools/usb/usbip/src/usbip_attach.c
@@ -32,6 +32,7 @@
 #include "vhci_driver.h"
 #include "usbip_common.h"
 #include "usbip_network.h"
+#include "usbip_ux.h"
 #include "usbip.h"
 
 static const char usbip_attach_usage_string[] =
@@ -130,31 +131,48 @@ static int query_import_device(int sockfd, char *busid)
 static int attach_device(char *host, char *busid)
 {
        int sockfd;
+       usbip_ux_t *ux;
        int rc;
        int rhport;
 
        sockfd = usbip_net_tcp_connect(host, usbip_port_string);
        if (sockfd < 0) {
                err("tcp connect");
-               return -1;
+               goto err_out;
+       }
+
+       rc = usbip_ux_setup(sockfd, &ux);
+       if (rc) {
+               err("ux setup");
+               goto err_close_conn;
        }
 
        rhport = query_import_device(sockfd, busid);
        if (rhport < 0) {
                err("query");
-               close(sockfd);
-               return -1;
+               goto err_cleanup_ux;
        }
 
-       close(sockfd);
-
        rc = usbip_vhci_create_record(host, usbip_port_string, busid, rhport);
        if (rc < 0) {
                err("record connection");
-               return -1;
+               goto err_cleanup_ux;
+       }
+
+       if (ux != NULL) {
+               usbip_ux_start(ux);
+               usbip_ux_join(ux);
        }
+       usbip_ux_cleanup(&ux);
+       close(sockfd);
 
        return 0;
+err_cleanup_ux:
+       usbip_ux_cleanup(&ux);
+err_close_conn:
+       close(sockfd);
+err_out:
+       return -1;
 }
 
 int usbip_attach(int argc, char *argv[])
diff --git a/tools/usb/usbip/src/usbip_connect.c 
b/tools/usb/usbip/src/usbip_connect.c
index ab6d84a..89caf93 100644
--- a/tools/usb/usbip/src/usbip_connect.c
+++ b/tools/usb/usbip/src/usbip_connect.c
@@ -30,6 +30,7 @@
 #include "usbip_host_driver.h"
 #include "usbip_common.h"
 #include "usbip_network.h"
+#include "usbip_ux.h"
 #include "usbip.h"
 
 static const char usbip_connect_usage_string[] =
@@ -140,6 +141,7 @@ static int export_device(char *busid, int sockfd)
 static int connect_device(char *host, char *busid)
 {
        int sockfd;
+       usbip_ux_t *ux;
        int rc;
 
        rc = usbip_bind_device(busid);
@@ -154,15 +156,29 @@ static int connect_device(char *host, char *busid)
                goto err_unbind_device;
        }
 
+       rc = usbip_ux_setup(sockfd, &ux);
+       if (rc) {
+               err("ux setup");
+               goto err_close_conn;
+       }
+
        rc = export_device(busid, sockfd);
        if (rc < 0) {
                err("export");
-               goto err_close_conn;
+               goto err_cleanup_ux;
        }
 
+       if (ux != NULL) {
+               usbip_ux_start(ux);
+               usbip_ux_join(ux);
+               usbip_unbind_device(busid);
+       }
+       usbip_ux_cleanup(&ux);
        close(sockfd);
 
        return 0;
+err_cleanup_ux:
+       usbip_ux_cleanup(&ux);
 err_close_conn:
        close(sockfd);
 err_unbind_device:
diff --git a/tools/usb/usbip/src/usbip_disconnect.c 
b/tools/usb/usbip/src/usbip_disconnect.c
index b9cbe1d..8adabe6 100644
--- a/tools/usb/usbip/src/usbip_disconnect.c
+++ b/tools/usb/usbip/src/usbip_disconnect.c
@@ -30,6 +30,7 @@
 #include "usbip_host_driver.h"
 #include "usbip_common.h"
 #include "usbip_network.h"
+#include "usbip_ux.h"
 #include "usbip.h"
 
 static const char usbip_disconnect_usage_string[] =
@@ -150,10 +151,12 @@ static int disconnect_device(char *host, char *busid)
 
        close(sockfd);
 
-       rc = usbip_unbind_device(busid);
-       if (rc) {
-               err("unbind");
-               return -1;
+       if (!usbip_ux_installed()) {
+               rc = usbip_unbind_device(busid);
+               if (rc) {
+                       err("unbind");
+                       return -1;
+               }
        }
 
        return 0;
diff --git a/tools/usb/usbip/src/usbipd.c b/tools/usb/usbip/src/usbipd.c
index d0ed815..3337328 100644
--- a/tools/usb/usbip/src/usbipd.c
+++ b/tools/usb/usbip/src/usbipd.c
@@ -43,6 +43,7 @@
 
 #include "usbip_common.h"
 #include "usbip_network.h"
+#include "usbip_ux.h"
 #include "list.h"
 
 extern char *usbip_progname;
@@ -55,7 +56,7 @@ extern char *usbip_default_pid_file;
 
 static const char usbip_version_string[] = PACKAGE_STRING;
 
-static const char usbipd_help_string[] =
+static const char usbipd_help_string =
        "usage: %s [options]\n"
        "\n"
        "       -4, --ipv4\n"
@@ -152,6 +153,7 @@ int process_request(int listenfd)
        if (childpid == 0) {
                close(listenfd);
                usbip_recv_pdu(connfd, host, port);
+               close(connfd);
                exit(0);
        }
        close(connfd);
@@ -254,6 +256,7 @@ static struct addrinfo *do_getaddrinfo(char *host, int 
ai_family)
 static void signal_handler(int i)
 {
        dbg("received '%s' signal", strsignal(i));
+       usbip_ux_interrupt_pgrp();
 }
 
 static void set_signal(void)
diff --git a/tools/usb/usbip/src/usbipd_app.c b/tools/usb/usbip/src/usbipd_app.c
index f029b64..16af965 100644
--- a/tools/usb/usbip/src/usbipd_app.c
+++ b/tools/usb/usbip/src/usbipd_app.c
@@ -32,6 +32,7 @@
 #include "vhci_driver.h"
 #include "usbip_common.h"
 #include "usbip_network.h"
+#include "usbip_ux.h"
 
 char *usbip_progname = "usbipa";
 char *usbip_default_pid_file = "/var/run/usbipa";
@@ -78,6 +79,7 @@ static int recv_request_export(int sockfd, char *host, char 
*port)
 {
        struct op_export_request req;
        struct op_export_reply reply;
+       usbip_ux_t *ux;
        int rhport = 0;
        int error = 0;
        int rc;
@@ -92,6 +94,12 @@ static int recv_request_export(int sockfd, char *host, char 
*port)
        }
        PACK_OP_EXPORT_REQUEST(0, &req);
 
+       rc = usbip_ux_setup(sockfd, &ux);
+       if (rc) {
+               dbg("usbip_ux_setup failed: export");
+               return -1;
+       }
+
        rhport = import_device(sockfd, &req.udev);
        if (rhport < 0) {
                dbg("export request busid %s: failed", req.udev.busid);
@@ -126,6 +134,12 @@ static int recv_request_export(int sockfd, char *host, 
char *port)
 
        dbg("export request busid %s: complete", req.udev.busid);
 
+       if (ux != NULL) {
+               usbip_ux_start(ux);
+               usbip_ux_join(ux);
+       }
+       usbip_ux_cleanup(&ux);
+
        return 0;
 }
 
diff --git a/tools/usb/usbip/src/usbipd_dev.c b/tools/usb/usbip/src/usbipd_dev.c
index 7991e3e..7d124c2 100644
--- a/tools/usb/usbip/src/usbipd_dev.c
+++ b/tools/usb/usbip/src/usbipd_dev.c
@@ -36,6 +36,7 @@
 #include "usbip_host_driver.h"
 #include "usbip_common.h"
 #include "usbip_network.h"
+#include "usbip_ux.h"
 #include "list.h"
 
 char *usbip_progname = "usbipd";
@@ -62,6 +63,7 @@ static int recv_request_import(int sockfd)
        struct op_common reply;
        struct usbip_exported_device *edev;
        struct usbip_usb_device pdu_udev;
+       usbip_ux_t *ux;
        struct list_head *i;
        int found = 0;
        int error = 0;
@@ -87,13 +89,20 @@ static int recv_request_import(int sockfd)
        }
 
        if (found) {
-               /* should set TCP_NODELAY for usbip */
-               usbip_net_set_nodelay(sockfd);
-
-               /* export device needs a TCP/IP socket descriptor */
-               rc = usbip_host_export_device(edev, sockfd);
-               if (rc < 0)
+               rc = usbip_ux_setup(sockfd, &ux);
+               if (rc) {
                        error = 1;
+               } else {
+                       /* should set TCP_NODELAY for usbip */
+                       usbip_net_set_nodelay(sockfd);
+
+                       /* export device needs a TCP/IP socket descriptor */
+                       rc = usbip_host_export_device(edev, sockfd);
+                       if (rc < 0) {
+                               usbip_ux_cleanup(&ux);
+                               error = 1;
+                       }
+               }
        } else {
                info("requested device not found: %s", req.busid);
                error = 1;
@@ -103,11 +112,13 @@ static int recv_request_import(int sockfd)
                                      (!error ? ST_OK : ST_NA));
        if (rc < 0) {
                dbg("usbip_net_send_op_common failed: %#0x", OP_REP_IMPORT);
+               usbip_ux_cleanup(&ux);
                return -1;
        }
 
        if (error) {
                dbg("import request busid %s: failed", req.busid);
+               usbip_ux_cleanup(&ux);
                return -1;
        }
 
@@ -117,11 +128,18 @@ static int recv_request_import(int sockfd)
        rc = usbip_net_send(sockfd, &pdu_udev, sizeof(pdu_udev));
        if (rc < 0) {
                dbg("usbip_net_send failed: devinfo");
+               usbip_ux_cleanup(&ux);
                return -1;
        }
 
        dbg("import request busid %s: complete", req.busid);
 
+       if (ux != NULL) {
+               usbip_ux_start(ux);
+               usbip_ux_join(ux);
+       }
+       usbip_ux_cleanup(&ux);
+
        return 0;
 }
 
-- 
2.1.0

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to