summaryrefslogtreecommitdiff
path: root/drivers/staging/usbip/userspace/src/usbip_list.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/staging/usbip/userspace/src/usbip_list.c')
-rw-r--r--drivers/staging/usbip/userspace/src/usbip_list.c303
1 files changed, 303 insertions, 0 deletions
diff --git a/drivers/staging/usbip/userspace/src/usbip_list.c b/drivers/staging/usbip/userspace/src/usbip_list.c
new file mode 100644
index 000000000000..ed30d910e037
--- /dev/null
+++ b/drivers/staging/usbip/userspace/src/usbip_list.c
@@ -0,0 +1,303 @@
+/*
+ * Copyright (C) 2011 matt mooney <mfm@muteddisk.com>
+ * 2005-2007 Takahiro Hirofuchi
+ *
+ * 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 <sys/types.h>
+#include <sysfs/libsysfs.h>
+
+#include <errno.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <getopt.h>
+#include <netdb.h>
+#include <unistd.h>
+
+#include "usbip_common.h"
+#include "usbip_network.h"
+#include "usbip.h"
+
+static const char usbip_list_usage_string[] =
+ "usbip list [-p|--parsable] <args>\n"
+ " -p, --parsable Parsable list format\n"
+ " -r, --remote=<host> List the exportable USB devices on <host>\n"
+ " -l, --local List the local USB devices\n";
+
+void usbip_list_usage(void)
+{
+ printf("usage: %s", usbip_list_usage_string);
+}
+
+static int get_exported_devices(char *host, int sockfd)
+{
+ char product_name[100];
+ char class_name[100];
+ struct op_devlist_reply reply;
+ uint16_t code = OP_REP_DEVLIST;
+ struct usbip_usb_device udev;
+ struct usbip_usb_interface uintf;
+ unsigned int i;
+ int j, rc;
+
+ rc = usbip_net_send_op_common(sockfd, OP_REQ_DEVLIST, 0);
+ if (rc < 0) {
+ dbg("usbip_net_send_op_common failed");
+ return -1;
+ }
+
+ rc = usbip_net_recv_op_common(sockfd, &code);
+ if (rc < 0) {
+ dbg("usbip_net_recv_op_common failed");
+ return -1;
+ }
+
+ memset(&reply, 0, sizeof(reply));
+ rc = usbip_net_recv(sockfd, &reply, sizeof(reply));
+ if (rc < 0) {
+ dbg("usbip_net_recv_op_devlist failed");
+ return -1;
+ }
+ PACK_OP_DEVLIST_REPLY(0, &reply);
+ dbg("exportable devices: %d\n", reply.ndev);
+
+ if (reply.ndev == 0) {
+ info("no exportable devices found on %s", host);
+ return 0;
+ }
+
+ printf("Exportable USB devices\n");
+ printf("======================\n");
+ printf(" - %s\n", host);
+
+ for (i = 0; i < reply.ndev; i++) {
+ memset(&udev, 0, sizeof(udev));
+ rc = usbip_net_recv(sockfd, &udev, sizeof(udev));
+ if (rc < 0) {
+ dbg("usbip_net_recv failed: usbip_usb_device[%d]", i);
+ return -1;
+ }
+ usbip_net_pack_usb_device(0, &udev);
+
+ usbip_names_get_product(product_name, sizeof(product_name),
+ udev.idVendor, udev.idProduct);
+ usbip_names_get_class(class_name, sizeof(class_name),
+ udev.bDeviceClass, udev.bDeviceSubClass,
+ udev.bDeviceProtocol);
+ printf("%11s: %s\n", udev.busid, product_name);
+ printf("%11s: %s\n", "", udev.path);
+ printf("%11s: %s\n", "", class_name);
+
+ for (j = 0; j < udev.bNumInterfaces; j++) {
+ rc = usbip_net_recv(sockfd, &uintf, sizeof(uintf));
+ if (rc < 0) {
+ dbg("usbip_net_recv failed: usbip_usb_intf[%d]",
+ j);
+
+ return -1;
+ }
+ usbip_net_pack_usb_interface(0, &uintf);
+
+ usbip_names_get_class(class_name, sizeof(class_name),
+ uintf.bInterfaceClass,
+ uintf.bInterfaceSubClass,
+ uintf.bInterfaceProtocol);
+ printf("%11s: %2d - %s\n", "", j, class_name);
+ }
+ printf("\n");
+ }
+
+ return 0;
+}
+
+static int list_exported_devices(char *host)
+{
+ int rc;
+ int sockfd;
+
+ sockfd = usbip_net_tcp_connect(host, USBIP_PORT_STRING);
+ if (sockfd < 0) {
+ err("could not connect to %s:%s: %s", host,
+ USBIP_PORT_STRING, gai_strerror(sockfd));
+ return -1;
+ }
+ dbg("connected to %s:%s", host, USBIP_PORT_STRING);
+
+ rc = get_exported_devices(host, sockfd);
+ if (rc < 0) {
+ err("failed to get device list from %s", host);
+ return -1;
+ }
+
+ close(sockfd);
+
+ return 0;
+}
+
+static void print_device(char *busid, char *vendor, char *product,
+ bool parsable)
+{
+ if (parsable)
+ printf("busid=%s#usbid=%.4s:%.4s#", busid, vendor, product);
+ else
+ printf(" - busid %s (%.4s:%.4s)\n", busid, vendor, product);
+}
+
+static void print_interface(char *busid, char *driver, bool parsable)
+{
+ if (parsable)
+ printf("%s=%s#", busid, driver);
+ else
+ printf("%9s%s -> %s\n", "", busid, driver);
+}
+
+static int is_device(void *x)
+{
+ struct sysfs_attribute *devpath;
+ struct sysfs_device *dev = x;
+ int ret = 0;
+
+ devpath = sysfs_get_device_attr(dev, "devpath");
+ if (devpath && *devpath->value != '0')
+ ret = 1;
+
+ return ret;
+}
+
+static int devcmp(void *a, void *b)
+{
+ return strcmp(a, b);
+}
+
+static int list_devices(bool parsable)
+{
+ char bus_type[] = "usb";
+ char busid[SYSFS_BUS_ID_SIZE];
+ struct sysfs_bus *ubus;
+ struct sysfs_device *dev;
+ struct sysfs_device *intf;
+ struct sysfs_attribute *idVendor;
+ struct sysfs_attribute *idProduct;
+ struct sysfs_attribute *bConfValue;
+ struct sysfs_attribute *bNumIntfs;
+ struct dlist *devlist;
+ int i;
+ int ret = -1;
+
+ ubus = sysfs_open_bus(bus_type);
+ if (!ubus) {
+ err("could not open %s bus: %s", bus_type, strerror(errno));
+ return -1;
+ }
+
+ devlist = sysfs_get_bus_devices(ubus);
+ if (!devlist) {
+ err("could not get %s bus devices: %s", bus_type,
+ strerror(errno));
+ goto err_out;
+ }
+
+ /* remove interfaces and root hubs from device list */
+ dlist_filter_sort(devlist, is_device, devcmp);
+
+ if (!parsable) {
+ printf("Local USB devices\n");
+ printf("=================\n");
+ }
+ dlist_for_each_data(devlist, dev, struct sysfs_device) {
+ idVendor = sysfs_get_device_attr(dev, "idVendor");
+ idProduct = sysfs_get_device_attr(dev, "idProduct");
+ bConfValue = sysfs_get_device_attr(dev, "bConfigurationValue");
+ bNumIntfs = sysfs_get_device_attr(dev, "bNumInterfaces");
+ if (!idVendor || !idProduct || !bConfValue || !bNumIntfs) {
+ err("problem getting device attributes: %s",
+ strerror(errno));
+ goto err_out;
+ }
+
+ print_device(dev->bus_id, idVendor->value, idProduct->value,
+ parsable);
+
+ for (i = 0; i < atoi(bNumIntfs->value); i++) {
+ snprintf(busid, sizeof(busid), "%s:%.1s.%d",
+ dev->bus_id, bConfValue->value, i);
+ intf = sysfs_open_device(bus_type, busid);
+ if (!intf) {
+ err("could not open device interface: %s",
+ strerror(errno));
+ goto err_out;
+ }
+ print_interface(busid, intf->driver_name, parsable);
+ sysfs_close_device(intf);
+ }
+ printf("\n");
+ }
+
+ ret = 0;
+
+err_out:
+ sysfs_close_bus(ubus);
+
+ return ret;
+}
+
+int usbip_list(int argc, char *argv[])
+{
+ static const struct option opts[] = {
+ { "parsable", no_argument, NULL, 'p' },
+ { "remote", required_argument, NULL, 'r' },
+ { "local", no_argument, NULL, 'l' },
+ { NULL, 0, NULL, 0 }
+ };
+
+ bool parsable = false;
+ int opt;
+ int ret = -1;
+
+ if (usbip_names_init(USBIDS_FILE))
+ err("failed to open %s", USBIDS_FILE);
+
+ for (;;) {
+ opt = getopt_long(argc, argv, "pr:l", opts, NULL);
+
+ if (opt == -1)
+ break;
+
+ switch (opt) {
+ case 'p':
+ parsable = true;
+ break;
+ case 'r':
+ ret = list_exported_devices(optarg);
+ goto out;
+ case 'l':
+ ret = list_devices(parsable);
+ goto out;
+ default:
+ goto err_out;
+ }
+ }
+
+err_out:
+ usbip_list_usage();
+out:
+ usbip_names_free();
+
+ return ret;
+}