[PATCH 3/4] usbip tools: use per vhci_hcd controller attributes

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Salvador Fandiño <salva@xxxxxxxxxx>

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 <salva@xxxxxxxxxx>
---
 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

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



[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux