From: Salvador Fandiño <sa...@qindel.com>

Now every vhci_hcd device is controlled by its own sysfs attributes
(before all of them were controlled by vhci_hcd.0 attributes). This
patch addapts the usbip tools to use the new interface through
libusbip.

The user visible changes are as follows:

- The files containing port information are named as "port$ix-$port"
(they were "port$port" before), as port numbers are local to the
vhci_hcd device now.

- Command "usbip port" by default only list ports attached to
"vhci_hcd.0", the new flag "--vhci-ix" can be used to list other
device. The flag "--all" is also available for listing all the devices
(it has not been made the default because it inserts per vhci_hcd
device headers, changing the output format).

Signed-off-by: Salvador Fandiño <sa...@qindel.com>
---
 tools/usb/usbip/src/Makefile.am       |   3 +-
 tools/usb/usbip/src/usbip_attach.c    | 101 ++++++++++++++++--------
 tools/usb/usbip/src/usbip_detach.c    |  57 ++++++++------
 tools/usb/usbip/src/usbip_enumerate.c |  55 +++++++++++++
 tools/usb/usbip/src/usbip_enumerate.h |  25 ++++++
 tools/usb/usbip/src/usbip_port.c      | 143 +++++++++++++++++++++++++++++-----
 tools/usb/usbip/src/utils.c           |  16 ++++
 tools/usb/usbip/src/utils.h           |   1 +
 8 files changed, 322 insertions(+), 79 deletions(-)
 create mode 100644 tools/usb/usbip/src/usbip_enumerate.c
 create mode 100644 tools/usb/usbip/src/usbip_enumerate.h

diff --git a/tools/usb/usbip/src/Makefile.am b/tools/usb/usbip/src/Makefile.am
index e26f39e0579d..50436aaa3900 100644
--- a/tools/usb/usbip/src/Makefile.am
+++ b/tools/usb/usbip/src/Makefile.am
@@ -7,6 +7,7 @@ sbin_PROGRAMS := usbip usbipd
 
 usbip_SOURCES := usbip.h utils.h usbip.c utils.c usbip_network.c \
                 usbip_attach.c usbip_detach.c usbip_list.c \
-                usbip_bind.c usbip_unbind.c usbip_port.c
+                usbip_bind.c usbip_unbind.c usbip_port.c \
+                usbip_enumerate.c
 
 usbipd_SOURCES := usbip_network.h usbipd.c usbip_network.c
diff --git a/tools/usb/usbip/src/usbip_attach.c 
b/tools/usb/usbip/src/usbip_attach.c
index 7f07b2d50f59..3901dd507451 100644
--- a/tools/usb/usbip/src/usbip_attach.c
+++ b/tools/usb/usbip/src/usbip_attach.c
@@ -35,6 +35,7 @@
 #include "usbip_common.h"
 #include "usbip_network.h"
 #include "usbip.h"
+#include "usbip_enumerate.h"
 
 static const char usbip_attach_usage_string[] =
        "usbip attach <args>\n"
@@ -48,7 +49,8 @@ void usbip_attach_usage(void)
 }
 
 #define MAX_BUFF 100
-static int record_connection(char *host, char *port, char *busid, int rhport)
+static int record_connection(char *host, char *port,
+                            char *busid, int vhci_ix, int rhport)
 {
        int fd;
        char path[PATH_MAX+1];
@@ -70,7 +72,7 @@ static int record_connection(char *host, char *port, char 
*busid, int rhport)
                        return -1;
        }
 
-       snprintf(path, PATH_MAX, VHCI_STATE_PATH"/port%d", rhport);
+       snprintf(path, PATH_MAX, VHCI_STATE_PATH"/port%d-%d", vhci_ix, rhport);
 
        fd = open(path, O_WRONLY|O_CREAT|O_TRUNC, S_IRWXU);
        if (fd < 0)
@@ -90,46 +92,78 @@ static int record_connection(char *host, char *port, char 
*busid, int rhport)
        return 0;
 }
 
-static int import_device(int sockfd, struct usbip_usb_device *udev)
+static int import_device(int sockfd, struct usbip_usb_device *udev,
+                        int *pvhci_ix, int *pport)
 {
-       int rc;
-       int port;
        uint32_t speed = udev->speed;
+       int rc = -1;
 
-       rc = usbip_vhci_driver_open();
-       if (rc < 0) {
-               err("open vhci_driver");
-               goto err_out;
+       struct udev_enumerate *enumerate;
+       struct udev_list_entry *list, *entry;
+
+       enumerate = vhci_enumerate();
+       if (!enumerate) {
+               err("unable to list vhci_hcd drivers");
+               return -1;
+       }
+
+       list = udev_enumerate_get_list_entry(enumerate);
+       if (!list) {
+               err("unable to list vhci_hcd drivers");
+               return -1;
        }
 
-       do {
-               port = usbip_vhci_get_free_port(speed);
-               if (port < 0) {
-                       err("no free port");
-                       goto err_driver_close;
+       udev_list_entry_foreach(entry, list) {
+               const char *path = udev_list_entry_get_name(entry);
+               int port, vhci_ix;
+
+               if (usbip_vhci_driver_open_path(path) < 0)
+                       continue;
+
+               vhci_ix = usbip_vhci_driver_ix();
+
+               /* Between the moment we read and parse the status
+                * files and the one we try to attach a socket to the
+                * port, the later one may become occupied from some
+                * other process. In order to avoid that race
+                * condition, we retry on EBUSY errors. On any other
+                * error we just jump to the next vhci_hcd device
+                */
+               while (1) {
+                       port = usbip_vhci_get_free_port(speed);
+                       if (port < 0)
+                               break;
+
+                       dbg("got free port %d at %s", port, path);
+                       rc = usbip_vhci_attach_device(port, sockfd,
+                                                     udev->busnum,
+                                                     udev->devnum,
+                                                     speed);
+
+                       if (rc >= 0 || errno != EBUSY)
+                               break;
+
+                       usbip_vhci_refresh_device_list();
                }
 
-               dbg("got free port %d", port);
+               usbip_vhci_driver_close();
 
-               rc = usbip_vhci_attach_device(port, sockfd, udev->busnum,
-                                             udev->devnum, udev->speed);
-               if (rc < 0 && errno != EBUSY) {
-                       err("import device");
-                       goto err_driver_close;
+               if (rc >= 0) {
+                       *pport = port;
+                       *pvhci_ix = vhci_ix;
+                       goto done;
                }
-       } while (rc < 0);
-
-       usbip_vhci_driver_close();
+       }
+       err("import device failed");
 
-       return port;
+done:
+       udev_enumerate_unref(enumerate);
 
-err_driver_close:
-       usbip_vhci_driver_close();
-err_out:
-       return -1;
+       return rc;
 }
 
-static int query_import_device(int sockfd, char *busid)
+static int query_import_device(int sockfd, char *busid,
+                              int *pvhci_ix, int *pport)
 {
        int rc;
        struct op_import_request request;
@@ -178,7 +212,7 @@ static int query_import_device(int sockfd, char *busid)
        }
 
        /* import a device */
-       return import_device(sockfd, &reply.udev);
+       return import_device(sockfd, &reply.udev, pvhci_ix, pport);
 }
 
 static int attach_device(char *host, char *busid)
@@ -186,6 +220,7 @@ static int attach_device(char *host, char *busid)
        int sockfd;
        int rc;
        int rhport;
+       int vhci_ix;
 
        sockfd = usbip_net_tcp_connect(host, usbip_port_string);
        if (sockfd < 0) {
@@ -193,15 +228,15 @@ static int attach_device(char *host, char *busid)
                return -1;
        }
 
-       rhport = query_import_device(sockfd, busid);
-       if (rhport < 0) {
+       rc = query_import_device(sockfd, busid, &vhci_ix, &rhport);
+       if (rc < 0) {
                err("query");
                return -1;
        }
 
        close(sockfd);
 
-       rc = record_connection(host, usbip_port_string, busid, rhport);
+       rc = record_connection(host, usbip_port_string, busid, vhci_ix, rhport);
        if (rc < 0) {
                err("record connection");
                return -1;
diff --git a/tools/usb/usbip/src/usbip_detach.c 
b/tools/usb/usbip/src/usbip_detach.c
index 9db9d21bb2ec..06ad88d9959b 100644
--- a/tools/usb/usbip/src/usbip_detach.c
+++ b/tools/usb/usbip/src/usbip_detach.c
@@ -30,49 +30,39 @@
 #include "usbip_common.h"
 #include "usbip_network.h"
 #include "usbip.h"
+#include "utils.h"
 
 static const char usbip_detach_usage_string[] =
        "usbip detach <args>\n"
-       "    -p, --port=<port>    " USBIP_VHCI_DRV_NAME
-       " port the device is on\n";
+       "    -i, --vhci-ix=<ix>   index of the "
+       USBIP_VHCI_DRV_NAME
+       " the device is on (defaults to 0)\n"
+       "    -p, --port=<port>    port the device is on\n";
 
 void usbip_detach_usage(void)
 {
        printf("usage: %s", usbip_detach_usage_string);
 }
 
-static int detach_port(char *port)
+static int detach_port(int vhci_ix, int port)
 {
        int ret;
-       uint8_t portnum;
        char path[PATH_MAX+1];
 
-       unsigned int port_len = strlen(port);
-
-       for (unsigned int i = 0; i < port_len; i++)
-               if (!isdigit(port[i])) {
-                       err("invalid port %s", port);
-                       return -1;
-               }
-
-       /* check max port */
-
-       portnum = atoi(port);
-
        /* remove the port state file */
 
-       snprintf(path, PATH_MAX, VHCI_STATE_PATH"/port%d", portnum);
+       snprintf(path, PATH_MAX, VHCI_STATE_PATH"/port%d-%d", vhci_ix, port);
 
        remove(path);
        rmdir(VHCI_STATE_PATH);
 
-       ret = usbip_vhci_driver_open();
+       ret = usbip_vhci_driver_open_ix(vhci_ix);
        if (ret < 0) {
                err("open vhci_driver");
                return -1;
        }
 
-       ret = usbip_vhci_detach_device(portnum);
+       ret = usbip_vhci_detach_device(port);
        if (ret < 0)
                return -1;
 
@@ -85,28 +75,45 @@ int usbip_detach(int argc, char *argv[])
 {
        static const struct option opts[] = {
                { "port", required_argument, NULL, 'p' },
+               { "vhci-ix", 0, NULL, 'i' },
                { NULL, 0, NULL, 0 }
        };
        int opt;
-       int ret = -1;
+       int port = -1;
+       int vhci_ix = 0;
 
        for (;;) {
-               opt = getopt_long(argc, argv, "p:", opts, NULL);
+               opt = getopt_long(argc, argv, "p:i:", opts, NULL);
 
                if (opt == -1)
                        break;
 
                switch (opt) {
                case 'p':
-                       ret = detach_port(optarg);
-                       goto out;
+                       if (atoi_with_check(optarg, &port) < 0) {
+                               err("bad port number");
+                               return -1;
+                       }
+                       break;
+               case 'i':
+                       if (atoi_with_check(optarg, &vhci_ix) < 0) {
+                               err("bad vhci index");
+                               return -1;
+                       }
+                       break;
                default:
                        goto err_out;
                }
        }
+       if (optind < argc)
+               goto err_out;
+
+       if (port < 0)
+               goto err_out;
+
+       return detach_port(vhci_ix, port);
 
 err_out:
        usbip_detach_usage();
-out:
-       return ret;
+       return -1;
 }
diff --git a/tools/usb/usbip/src/usbip_enumerate.c 
b/tools/usb/usbip/src/usbip_enumerate.c
new file mode 100644
index 000000000000..b6197435b476
--- /dev/null
+++ b/tools/usb/usbip/src/usbip_enumerate.c
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2018 Qindel Formación y Servicios SL
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <libudev.h>
+
+#include "usbip_enumerate.h"
+#include "vhci_driver.h"
+
+struct udev_enumerate *vhci_enumerate(void)
+{
+       struct udev *udev_context = NULL;
+       struct udev_enumerate *enumerate = NULL;
+       int rc;
+
+       udev_context = udev_new();
+       if (!udev_context) {
+               err("udev_new failed");
+               return NULL;
+       }
+
+       enumerate = udev_enumerate_new(udev_context);
+       if (!enumerate) {
+               err("udev_enumerate_new failed");
+               goto err;
+       }
+
+       udev_enumerate_add_match_subsystem(enumerate, USBIP_VHCI_BUS_TYPE);
+       udev_enumerate_add_match_sysname(enumerate,
+                                        USBIP_VHCI_DEVICE_NAME_PATTERN);
+       rc = udev_enumerate_scan_devices(enumerate);
+       if (rc < 0) {
+               err("udev_enumerate_scan_devices failed: %d", rc);
+               udev_enumerate_unref(enumerate);
+               enumerate = NULL;
+       }
+
+err:
+       udev_unref(udev_context);
+
+       return enumerate;
+}
diff --git a/tools/usb/usbip/src/usbip_enumerate.h 
b/tools/usb/usbip/src/usbip_enumerate.h
new file mode 100644
index 000000000000..ce1f4e6941d0
--- /dev/null
+++ b/tools/usb/usbip/src/usbip_enumerate.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2018 Qindel Formacion y Servicios SL
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __USBIP_ENUMERATE_H
+#define __USBIP_ENUMERATE_H
+
+#include <libudev.h>
+
+struct udev_enumerate *vhci_enumerate(void);
+
+#endif /* __USBIP_ENUMERATE_H */
diff --git a/tools/usb/usbip/src/usbip_port.c b/tools/usb/usbip/src/usbip_port.c
index 7bd74fb3a9cd..a981a73b7dfb 100644
--- a/tools/usb/usbip/src/usbip_port.c
+++ b/tools/usb/usbip/src/usbip_port.c
@@ -13,54 +13,157 @@
  * GNU General Public License for more details.
  */
 
+#include <getopt.h>
+
 #include "vhci_driver.h"
 #include "usbip_common.h"
+#include "usbip_enumerate.h"
+#include "utils.h"
+
+static const char usbip_port_usage_string[] =
+       "usbip port <args>\n"
+       "    -i, --vhci-ix=<ix>   index of the "
+       USBIP_VHCI_DRV_NAME
+       " the device is on (defaults to 0)\n"
+       "    -a, --all            list the ports from all the available "
+       USBIP_VHCI_DRV_NAME "'s\n";
+
+void usbip_port_usage(void)
+{
+       printf("usage: %s", usbip_port_usage_string);
+}
 
 static int list_imported_devices(void)
 {
        int i;
        struct usbip_imported_device *idev;
-       int ret;
+       int ret = 0;
+
+       for (i = 0; i < vhci_driver->nports; i++) {
+               idev = &vhci_driver->idev[i];
 
+               if (usbip_vhci_imported_device_dump(idev) < 0) {
+                       err("unable to list device %d", i);
+                       ret = -1;
+               }
+       }
+       return ret;
+}
+
+static void list_imported_devices_header(void)
+{
+       printf("Imported USB devices\n");
+       printf("====================\n");
+}
+
+static int list_imported_devices_ix(int vhci_ix)
+{
+       int ret;
        if (usbip_names_init(USBIDS_FILE))
                err("failed to open %s", USBIDS_FILE);
 
-       ret = usbip_vhci_driver_open();
+       ret = usbip_vhci_driver_open_ix(vhci_ix);
        if (ret < 0) {
                err("open vhci_driver");
                goto err_names_free;
        }
 
-       printf("Imported USB devices\n");
-       printf("====================\n");
+       list_imported_devices_header();
+       ret = list_imported_devices();
+       usbip_vhci_driver_close();
+err_names_free:
+       usbip_names_free();
+       return ret;
+}
 
-       for (i = 0; i < vhci_driver->nports; i++) {
-               idev = &vhci_driver->idev[i];
+static int list_imported_devices_all(void)
+{
+       struct udev_enumerate *enumerate = NULL;
+       struct udev_list_entry *list, *entry;
+       int rc = 0;
+
+       if (usbip_names_init(USBIDS_FILE))
+               err("failed to open %s", USBIDS_FILE);
 
-               if (usbip_vhci_imported_device_dump(idev) < 0)
-                       goto err_driver_close;
+       enumerate = vhci_enumerate();
+       if (!enumerate) {
+               err("Unable to list vhci_hcd drivers");
+               return -1;
        }
 
-       usbip_vhci_driver_close();
-       usbip_names_free();
+       list = udev_enumerate_get_list_entry(enumerate);
+       if (!list) {
+               err("Unable to list vhci_hcd drivers");
+               return -1;
+       }
 
-       return ret;
+       list_imported_devices_header();
 
-err_driver_close:
-       usbip_vhci_driver_close();
-err_names_free:
+       udev_list_entry_foreach(entry, list) {
+               const char *path = udev_list_entry_get_name(entry);
+               int i;
+               int len = printf("VHCI: %s\n", path);
+
+               /* write a line of dashes */
+               for (i = 1; i < len; i++)
+                       putchar('-');
+               putchar('\n');
+
+               if (usbip_vhci_driver_open_path(path) < 0) {
+                       err("usbip_vhci_driver_open_path");
+                       rc = -1;
+                       continue;
+               }
+               if (list_imported_devices() < 0)
+                       rc = -1;
+               usbip_vhci_driver_close();
+       }
        usbip_names_free();
-       return -1;
+       udev_enumerate_unref(enumerate);
+
+       return rc;
 }
 
 int usbip_port_show(__attribute__((unused)) int argc,
                    __attribute__((unused)) char *argv[])
 {
-       int ret;
+       int vhci_ix = 0;
+       int all = 0;
+       static const struct option opts[] = {
+               { "vhci-ix", 0, NULL, 'i' },
+               { "all", 0, NULL, 'a' },
+               { NULL, 0, NULL, 0 }
+       };
 
-       ret = list_imported_devices();
-       if (ret < 0)
-               err("list imported devices");
+       for (;;) {
+               int opt = getopt_long(argc, argv, "i:a", opts, NULL);
 
-       return ret;
+               if (opt == -1)
+                       break;
+               switch (opt) {
+               case 'i':
+                       if (atoi_with_check(optarg, &vhci_ix) < 0) {
+                               err("Bad vhci index");
+                               return -1;
+                       }
+                       break;
+               case 'a':
+                       all = 1;
+                       break;
+               default:
+                       goto err_out;
+               }
+       }
+
+       if (optind < argc)
+               goto err_out;
+
+       if (all)
+               return list_imported_devices_all();
+       else
+               return list_imported_devices_ix(vhci_ix);
+
+err_out:
+       usbip_port_usage();
+       return -1;
 }
diff --git a/tools/usb/usbip/src/utils.c b/tools/usb/usbip/src/utils.c
index 3d7b42e77299..0c55ab4f3d98 100644
--- a/tools/usb/usbip/src/utils.c
+++ b/tools/usb/usbip/src/utils.c
@@ -19,6 +19,8 @@
 #include <errno.h>
 #include <stdio.h>
 #include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
 
 #include "usbip_common.h"
 #include "utils.h"
@@ -53,3 +55,17 @@ int modify_match_busid(char *busid, int add)
 
        return 0;
 }
+
+int atoi_with_check(const char *str, int *pi)
+{
+       ssize_t len = strlen(str);
+
+       for (ssize_t i = 0; i < len; i++) {
+               if (!isdigit(str[i])) {
+                       err("%s is not a number", str);
+                       return -1;
+               }
+       }
+       *pi = atoi(str);
+       return 0;
+}
diff --git a/tools/usb/usbip/src/utils.h b/tools/usb/usbip/src/utils.h
index 5916fd3e02a6..a07d03c9bb12 100644
--- a/tools/usb/usbip/src/utils.h
+++ b/tools/usb/usbip/src/utils.h
@@ -20,6 +20,7 @@
 #define __UTILS_H
 
 int modify_match_busid(char *busid, int add);
+int atoi_with_check(const char *str, int *pi);
 
 #endif /* __UTILS_H */
 
-- 
2.14.1

Reply via email to