staging: usbip: userspace tools v1.0.0
authormatt mooney <mfm@muteddisk.com>
Thu, 26 May 2011 13:17:11 +0000 (06:17 -0700)
committerGreg Kroah-Hartman <gregkh@suse.de>
Tue, 7 Jun 2011 20:56:12 +0000 (13:56 -0700)
The new and improved (well somewhat, with a ways to go) userspace utility.

    mfm:pts/8[~/tmp/userspace]
    May26 05:18:31 % ./src/usbip help
    usage: usbip [--debug] [version]
                 [help] <command> <args>

      attach     Attach a remote USB device
      detach     Detach a remote USB device
      list       List exported or local USB devices
      bind       Bind device to usbip-host.ko
      unbind     Unbind device from usbip-host.ko

This first commit of the userspace `usbip' utility uses to same
implementation as the old tools, `usbip' and  `usbip_bind_driver'.
Nothing significant has changed so compatibility with windows has
_not_ been broken. However, the tools remain broken in many ways
due to the old implementation.

Signed-off-by: matt mooney <mfm@muteddisk.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
12 files changed:
drivers/staging/usbip/userspace/configure.ac
drivers/staging/usbip/userspace/src/Makefile.am
drivers/staging/usbip/userspace/src/bind-driver.c [deleted file]
drivers/staging/usbip/userspace/src/usbip.c
drivers/staging/usbip/userspace/src/usbip.h [new file with mode: 0644]
drivers/staging/usbip/userspace/src/usbip_attach.c [new file with mode: 0644]
drivers/staging/usbip/userspace/src/usbip_bind.c [new file with mode: 0644]
drivers/staging/usbip/userspace/src/usbip_detach.c [new file with mode: 0644]
drivers/staging/usbip/userspace/src/usbip_list.c [new file with mode: 0644]
drivers/staging/usbip/userspace/src/usbip_unbind.c [new file with mode: 0644]
drivers/staging/usbip/userspace/src/utils.c
drivers/staging/usbip/userspace/src/utils.h

index e3afa15..e7d801b 100644 (file)
@@ -1,8 +1,8 @@
 dnl Process this file with autoconf to produce a configure script.
 
 AC_PREREQ(2.59)
-AC_INIT([usbip], [0.1.8], [usbip-devel@lists.sourceforge.net])
-AC_DEFINE([USBIP_VERSION], [0x000106], [numeric version number])
+AC_INIT([usbip], [1.0.0], [usbip-devel@lists.sourceforge.net])
+AC_DEFINE([USBIP_VERSION], [0x00000100], [binary-coded decimal version number])
 
 CURRENT=0
 REVISION=1
index 05a7aa5..52741c8 100644 (file)
@@ -2,9 +2,10 @@ AM_CPPFLAGS := -I$(top_srcdir)/libsrc -DUSBIDS_FILE='"@USBIDS_DIR@/usb.ids"'
 AM_CFLAGS   := @EXTRA_CFLAGS@ @PACKAGE_CFLAGS@
 LDADD       := $(top_srcdir)/libsrc/libusbip.la @PACKAGE_LIBS@
 
-sbin_PROGRAMS := usbip usbipd usbip_bind_driver
+sbin_PROGRAMS := usbip usbipd
 
-usbip_SOURCES := usbip.c usbip_network.c usbip_network.h
-usbipd_SOURCES := usbipd.c usbip_network.c usbip_network.h
-usbip_bind_driver_SOURCES := bind-driver.c utils.c utils.h \
-                            usbip_network.h usbip_network.c
+usbip_SOURCES := usbip.c utils.c usbip_network.c \
+                usbip_attach.c usbip_detach.c usbip_list.c \
+                usbip_bind.c usbip_unbind.c
+
+usbipd_SOURCES := usbipd.c usbip_network.c
diff --git a/drivers/staging/usbip/userspace/src/bind-driver.c b/drivers/staging/usbip/userspace/src/bind-driver.c
deleted file mode 100644 (file)
index 1396ff9..0000000
+++ /dev/null
@@ -1,652 +0,0 @@
-/*
- *
- * Copyright (C) 2005-2007 Takahiro Hirofuchi
- */
-
-#define _GNU_SOURCE
-#include <getopt.h>
-#include <glib.h>
-
-#include "usbip.h"
-#include "utils.h"
-
-static const struct option longopts[] = {
-       {"usbip",       required_argument,      NULL, 'u'},
-       {"other",       required_argument,      NULL, 'o'},
-       {"list",        no_argument,            NULL, 'l'},
-       {"list2",       no_argument,            NULL, 'L'},
-       {"help",        no_argument,            NULL, 'h'},
-#if 0
-       {"allusbip",    no_argument,            NULL, 'a'},
-       {"export-to",   required_argument,      NULL, 'e'},
-       {"unexport",    required_argument,      NULL, 'x'},
-       {"busid",       required_argument,      NULL, 'b'},
-#endif
-
-       {NULL,          0,                      NULL,  0}
-};
-
-static void show_help(void)
-{
-       printf("Usage: usbip_bind_driver [OPTION]\n");
-       printf("Change driver binding for USB/IP.\n");
-       printf("  --usbip busid        make a device exportable\n");
-       printf("  --other busid        use a device by a local driver\n");
-       printf("  --list               print usb devices and their drivers\n");
-       printf("  --list2              print usb devices and their drivers in parseable mode\n");
-#if 0
-       printf("  --allusbip           make all devices exportable\n");
-       printf("  --export-to host     export the device to 'host'\n");
-       printf("  --unexport host      unexport a device previously exported to 'host'\n");
-       printf("  --busid busid        the busid used for --export-to\n");
-#endif
-}
-
-static int modify_match_busid(char *busid, int add)
-{
-       int fd;
-       int ret;
-       char buff[BUS_ID_SIZE + 4];
-       char sysfs_mntpath[SYSFS_PATH_MAX];
-       char match_busid_path[SYSFS_PATH_MAX];
-
-       ret = sysfs_get_mnt_path(sysfs_mntpath, SYSFS_PATH_MAX);
-       if (ret < 0) {
-               err("sysfs must be mounted");
-               return -1;
-       }
-
-       snprintf(match_busid_path, sizeof(match_busid_path),
-                "%s/%s/usb/%s/%s/match_busid", sysfs_mntpath, SYSFS_BUS_NAME,
-                SYSFS_DRIVERS_NAME, USBIP_HOST_DRV_NAME);
-
-       /* BUS_IS_SIZE includes NULL termination? */
-       if (strnlen(busid, BUS_ID_SIZE) > BUS_ID_SIZE - 1) {
-               g_warning("too long busid");
-               return -1;
-       }
-
-       fd = open(match_busid_path, O_WRONLY);
-       if (fd < 0)
-               return -1;
-
-       if (add)
-               snprintf(buff, BUS_ID_SIZE + 4, "add %s", busid);
-       else
-               snprintf(buff, BUS_ID_SIZE + 4, "del %s", busid);
-
-       g_debug("write \"%s\" to %s", buff, match_busid_path);
-
-       ret = write(fd, buff, sizeof(buff));
-       if (ret < 0) {
-               close(fd);
-               return -1;
-       }
-
-       close(fd);
-
-       return 0;
-}
-
-static const char unbind_path_format[] = "/sys/bus/usb/devices/%s/driver/unbind";
-
-/* buggy driver may cause dead lock */
-static int unbind_interface_busid(char *busid)
-{
-       char unbind_path[PATH_MAX];
-       int fd;
-       int ret;
-
-       snprintf(unbind_path, sizeof(unbind_path), unbind_path_format, busid);
-
-       fd = open(unbind_path, O_WRONLY);
-       if (fd < 0) {
-               g_warning("opening unbind_path failed: %d", fd);
-               return -1;
-       }
-
-       ret = write(fd, busid, strnlen(busid, BUS_ID_SIZE));
-       if (ret < 0) {
-               g_warning("write to unbind_path failed: %d", ret);
-               close(fd);
-               return -1;
-       }
-
-       close(fd);
-
-       return 0;
-}
-
-static int unbind_interface(char *busid, int configvalue, int interface)
-{
-       char inf_busid[BUS_ID_SIZE];
-       g_debug("unbinding interface");
-
-       snprintf(inf_busid, BUS_ID_SIZE, "%s:%d.%d", busid, configvalue, interface);
-
-       return unbind_interface_busid(inf_busid);
-}
-
-
-static const char bind_path_format[] = "/sys/bus/usb/drivers/%s/bind";
-
-static int bind_interface_busid(char *busid, char *driver)
-{
-       char bind_path[PATH_MAX];
-       int fd;
-       int ret;
-
-       snprintf(bind_path, sizeof(bind_path), bind_path_format, driver);
-
-       fd = open(bind_path, O_WRONLY);
-       if (fd < 0)
-               return -1;
-
-       ret = write(fd, busid, strnlen(busid, BUS_ID_SIZE));
-       if (ret < 0) {
-               close(fd);
-               return -1;
-       }
-
-       close(fd);
-
-       return 0;
-}
-
-static int bind_interface(char *busid, int configvalue, int interface, char *driver)
-{
-       char inf_busid[BUS_ID_SIZE];
-
-       snprintf(inf_busid, BUS_ID_SIZE, "%s:%d.%d", busid, configvalue, interface);
-
-       return bind_interface_busid(inf_busid, driver);
-}
-
-static int unbind(char *busid)
-{
-       int configvalue = 0;
-       int ninterface = 0;
-       int devclass = 0;
-       int i;
-       int failed = 0;
-
-       configvalue = read_bConfigurationValue(busid);
-       ninterface  = read_bNumInterfaces(busid);
-       devclass  = read_bDeviceClass(busid);
-
-       if (configvalue < 0 || ninterface < 0 || devclass < 0) {
-               g_warning("read config and ninf value, removed?");
-               return -1;
-       }
-
-       if (devclass == 0x09) {
-               g_message("skip unbinding of hub");
-               return -1;
-       }
-
-       for (i = 0; i < ninterface; i++) {
-               char driver[PATH_MAX];
-               int ret;
-
-               bzero(&driver, sizeof(driver));
-
-               getdriver(busid, configvalue, i, driver, PATH_MAX-1);
-
-               g_debug(" %s:%d.%d      -> %s ", busid, configvalue, i, driver);
-
-               if (!strncmp("none", driver, PATH_MAX))
-                       continue; /* unbound interface */
-
-#if 0
-               if (!strncmp("usbip", driver, PATH_MAX))
-                       continue; /* already bound to usbip */
-#endif
-
-               /* unbinding */
-               ret = unbind_interface(busid, configvalue, i);
-               if (ret < 0) {
-                       g_warning("unbind driver at %s:%d.%d failed",
-                                       busid, configvalue, i);
-                       failed = 1;
-               }
-       }
-
-       if (failed)
-               return -1;
-       else
-               return 0;
-}
-
-/* call at unbound state */
-static int bind_to_usbip(char *busid)
-{
-       int configvalue = 0;
-       int ninterface = 0;
-       int i;
-       int failed = 0;
-
-       configvalue = read_bConfigurationValue(busid);
-       ninterface  = read_bNumInterfaces(busid);
-
-       if (configvalue < 0 || ninterface < 0) {
-               g_warning("read config and ninf value, removed?");
-               return -1;
-       }
-
-       for (i = 0; i < ninterface; i++) {
-               int ret;
-
-               ret = bind_interface(busid, configvalue, i,
-                                    USBIP_HOST_DRV_NAME);
-               if (ret < 0) {
-                       g_warning("bind usbip at %s:%d.%d, failed",
-                                       busid, configvalue, i);
-                       failed = 1;
-                       /* need to contine binding at other interfaces */
-               }
-       }
-
-       if (failed)
-               return -1;
-       else
-               return 0;
-}
-
-
-static int use_device_by_usbip(char *busid)
-{
-       int ret;
-
-       ret = unbind(busid);
-       if (ret < 0) {
-               g_warning("unbind drivers of %s, failed", busid);
-               return -1;
-       }
-
-       ret = modify_match_busid(busid, 1);
-       if (ret < 0) {
-               g_warning("add %s to match_busid, failed", busid);
-               return -1;
-       }
-
-       ret = bind_to_usbip(busid);
-       if (ret < 0) {
-               g_warning("bind usbip to %s, failed", busid);
-               modify_match_busid(busid, 0);
-               return -1;
-       }
-
-       g_message("bind %s to usbip, complete!", busid);
-
-       return 0;
-}
-
-
-
-static int use_device_by_other(char *busid)
-{
-       int ret;
-       int config;
-
-       /* read and write the same config value to kick probing */
-       config = read_bConfigurationValue(busid);
-       if (config < 0) {
-               g_warning("read bConfigurationValue of %s, failed", busid);
-               return -1;
-       }
-
-       ret = modify_match_busid(busid, 0);
-       if (ret < 0) {
-               g_warning("del %s to match_busid, failed", busid);
-               return -1;
-       }
-
-       ret = write_bConfigurationValue(busid, config);
-       if (ret < 0) {
-               g_warning("read bConfigurationValue of %s, failed", busid);
-               return -1;
-       }
-
-       g_message("bind %s to other drivers than usbip, complete!", busid);
-
-       return 0;
-}
-
-
-#include <sys/types.h>
-#include <regex.h>
-
-#include <errno.h>
-#include <string.h>
-#include <stdio.h>
-
-
-
-static int is_usb_device(char *busid)
-{
-       int ret;
-
-       regex_t regex;
-       regmatch_t pmatch[1];
-
-       ret = regcomp(&regex, "^[0-9]+-[0-9]+(\\.[0-9]+)*$", REG_NOSUB|REG_EXTENDED);
-       if (ret < 0)
-               g_error("regcomp: %s\n", strerror(errno));
-
-       ret = regexec(&regex, busid, 0, pmatch, 0);
-       if (ret)
-               return 0;       /* not matched */
-
-       return 1;
-}
-
-
-#include <dirent.h>
-static int show_devices(void)
-{
-       DIR *dir;
-
-       dir = opendir("/sys/bus/usb/devices/");
-       if (!dir)
-               g_error("opendir: %s", strerror(errno));
-
-       printf("List USB devices\n");
-       for (;;) {
-               struct dirent *dirent;
-               char *busid;
-
-               dirent = readdir(dir);
-               if (!dirent)
-                       break;
-
-               busid = dirent->d_name;
-
-               if (is_usb_device(busid)) {
-                       char name[100] = {'\0'};
-                       char driver[100] =  {'\0'};
-                       int conf, ninf = 0;
-                       int i;
-
-                       conf = read_bConfigurationValue(busid);
-                       ninf = read_bNumInterfaces(busid);
-
-                       getdevicename(busid, name, sizeof(name));
-
-                       printf(" - busid %s (%s)\n", busid, name);
-
-                       for (i = 0; i < ninf; i++) {
-                               getdriver(busid, conf, i, driver, sizeof(driver));
-                               printf("         %s:%d.%d -> %s\n", busid, conf, i, driver);
-                       }
-                       printf("\n");
-               }
-       }
-
-       closedir(dir);
-
-       return 0;
-}
-
-static int show_devices2(void)
-{
-       DIR *dir;
-
-       dir = opendir("/sys/bus/usb/devices/");
-       if (!dir)
-               g_error("opendir: %s", strerror(errno));
-
-       for (;;) {
-               struct dirent *dirent;
-               char *busid;
-
-               dirent = readdir(dir);
-               if (!dirent)
-                       break;
-
-               busid = dirent->d_name;
-
-               if (is_usb_device(busid)) {
-                       char name[100] = {'\0'};
-                       char driver[100] =  {'\0'};
-                       int conf, ninf = 0;
-                       int i;
-
-                       conf = read_bConfigurationValue(busid);
-                       ninf = read_bNumInterfaces(busid);
-
-                       getdevicename(busid, name, sizeof(name));
-
-                       printf("busid=%s#usbid=%s#", busid, name);
-
-                       for (i = 0; i < ninf; i++) {
-                               getdriver(busid, conf, i, driver, sizeof(driver));
-                               printf("%s:%d.%d=%s#", busid, conf, i, driver);
-                       }
-                       printf("\n");
-               }
-       }
-
-       closedir(dir);
-
-       return 0;
-}
-
-
-#if 0
-static int export_to(char *host, char *busid) {
-
-       int ret;
-
-       if( host == NULL ) {
-               printf( "no host given\n\n");
-               show_help();
-               return -1;
-       }
-       if( busid == NULL ) {
-               /* XXX print device list and ask for busnumber, if none is
-                * given */
-               printf( "no busid given, use --busid switch\n\n");
-               show_help();
-               return -1;
-       }
-
-
-       ret = use_device_by_usbip(busid);
-       if( ret != 0 ) {
-               printf( "could not bind driver to usbip\n");
-               return -1;
-       }
-
-       printf( "DEBUG: exporting device '%s' to '%s'\n", busid, host );
-       ret = export_busid_to_host(host, busid); /* usbip_export.[ch] */
-       if( ret != 0 ) {
-               printf( "could not export device to host\n" );
-               printf( "   host: %s, device: %s\n", host, busid );
-               use_device_by_other(busid);
-               return -1;
-       }
-
-       return 0;
-}
-
-static int unexport_from(char *host, char *busid) {
-
-       int ret;
-
-       if (!host || !busid)
-               g_error("no host or no busid\n");
-
-       g_message("unexport_from: host: '%s', busid: '%s'", host, busid);
-
-       ret = unexport_busid_from_host(host, busid); /* usbip_export.[ch] */
-       if( ret != 0 ) {
-               err( "could not unexport device from host\n" );
-               err( "   host: %s, device: %s\n", host, busid );
-       }
-
-       ret = use_device_by_other(busid);
-       if (ret < 0)
-               g_error("could not unbind device from usbip\n");
-
-       return 0;
-}
-
-
-static int allusbip(void)
-{
-       DIR *dir;
-
-       dir = opendir("/sys/bus/usb/devices/");
-       if (!dir)
-               g_error("opendir: %s", strerror(errno));
-
-       for (;;) {
-               struct dirent *dirent;
-               char *busid;
-
-               dirent = readdir(dir);
-               if (!dirent)
-                       break;
-
-               busid = dirent->d_name;
-
-               if (!is_usb_device(busid))
-                       continue;
-
-               {
-                       char name[PATH_MAX];
-                       int conf, ninf = 0;
-                       int i;
-                       int be_local = 0;
-
-                       conf = read_bConfigurationValue(busid);
-                       ninf = read_bNumInterfaces(busid);
-
-                       getdevicename(busid, name, sizeof(name));
-
-                       for (i = 0; i < ninf; i++) {
-                               char driver[PATH_MAX];
-
-                               getdriver(busid, conf, i, driver, sizeof(driver));
-#if 0
-                               if (strncmp(driver, "usbhid", 6) == 0 || strncmp(driver, "usb-storage", 11) == 0) {
-                                       be_local = 1;
-                                       break;
-                               }
-#endif
-                       }
-
-                       if (be_local == 0)
-                               use_device_by_usbip(busid);
-               }
-       }
-
-       closedir(dir);
-
-       return 0;
-}
-#endif
-
-int main(int argc, char **argv)
-{
-       char *busid = NULL;
-       char *remote_host __attribute__((unused)) = NULL;
-
-       enum {
-               cmd_unknown = 0,
-               cmd_use_by_usbip,
-               cmd_use_by_other,
-               cmd_list,
-               cmd_list2,
-               cmd_allusbip,
-               cmd_export_to,
-               cmd_unexport,
-               cmd_help,
-       } cmd = cmd_unknown;
-
-       if (geteuid() != 0)
-               g_warning("running non-root?");
-
-       for (;;) {
-               int c;
-               int index = 0;
-
-               c = getopt_long(argc, argv, "u:o:hlLae:x:b:", longopts, &index);
-               if (c == -1)
-                       break;
-
-               switch (c) {
-                       case 'u':
-                               cmd = cmd_use_by_usbip;
-                               busid = optarg;
-                               break;
-                       case 'o' :
-                               cmd = cmd_use_by_other;
-                               busid = optarg;
-                               break;
-                       case 'l' :
-                               cmd = cmd_list;
-                               break;
-                       case 'L' :
-                               cmd = cmd_list2;
-                               break;
-                       case 'a' :
-                               cmd = cmd_allusbip;
-                               break;
-                       case 'b':
-                               busid = optarg;
-                               break;
-                       case 'e':
-                               cmd = cmd_export_to;
-                               remote_host = optarg;
-                               break;
-                       case 'x':
-                               cmd = cmd_unexport;
-                               remote_host = optarg;
-                               break;
-                       case 'h': /* fallthrough */
-                       case '?':
-                               cmd = cmd_help;
-                               break;
-                       default:
-                               g_error("getopt");
-               }
-
-               //if (cmd)
-               //      break;
-       }
-
-       switch (cmd) {
-               case cmd_use_by_usbip:
-                       use_device_by_usbip(busid);
-                       break;
-               case cmd_use_by_other:
-                       use_device_by_other(busid);
-                       break;
-               case cmd_list:
-                       show_devices();
-                       break;
-               case cmd_list2:
-                       show_devices2();
-                       break;
-#if 0
-               case cmd_allusbip:
-                       allusbip();
-                       break;
-               case cmd_export_to:
-                       export_to(remote_host, busid);
-                       break;
-               case cmd_unexport:
-                       unexport_from(remote_host, busid);
-                       break;
-#endif
-               case cmd_help: /* fallthrough */
-               case cmd_unknown:
-                       show_help();
-                       break;
-               default:
-                       g_error("NOT REACHED");
-       }
-
-       return 0;
-}
index c73b355..8940cd0 100644 (file)
 /*
+ * command structure borrowed from udev
+ * (git://git.kernel.org/pub/scm/linux/hotplug/udev.git)
  *
- * Copyright (C) 2005-2007 Takahiro Hirofuchi
+ * 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/>.
  */
 
-#ifdef HAVE_CONFIG_H
-#include "../config.h"
-#endif
-
-#include "usbip.h"
-#include "usbip_network.h"
-#include <ctype.h>
-#include <sys/types.h>
-#include <sys/stat.h>
+#include <stdio.h>
 #include <stdlib.h>
-#include <fcntl.h>
-#include <glib.h>
-
-static const char version[] = PACKAGE_STRING;
-
-
-/* /sys/devices/platform/vhci_hcd/usb6/6-1/6-1:1.1  -> 1 */
-static int get_interface_number(char *path)
-{
-       char *c;
-
-       c = strstr(path, vhci_driver->hc_device->bus_id);
-       if (!c)
-               return -1;      /* hc exist? */
-       c++;
-       /* -> usb6/6-1/6-1:1.1 */
-
-       c = strchr(c, '/');
-       if (!c)
-               return -1;      /* hc exist? */
-       c++;
-       /* -> 6-1/6-1:1.1 */
-
-       c = strchr(c, '/');
-       if (!c)
-               return -1;      /* no interface path */
-       c++;
-       /* -> 6-1:1.1 */
-
-       c = strchr(c, ':');
-       if (!c)
-               return -1;      /* no configuration? */
-       c++;
-       /* -> 1.1 */
-
-       c = strchr(c, '.');
-       if (!c)
-               return -1;      /* no interface? */
-       c++;
-       /* -> 1 */
-
-
-       return atoi(c);
-}
-
-
-static struct sysfs_device *open_usb_interface(struct usb_device *udev, int i)
-{
-       struct sysfs_device *suinf;
-       char busid[SYSFS_BUS_ID_SIZE];
-
-       snprintf(busid, SYSFS_BUS_ID_SIZE, "%s:%d.%d",
-                       udev->busid, udev->bConfigurationValue, i);
-
-       suinf = sysfs_open_device("usb", busid);
-       if (!suinf)
-               err("sysfs_open_device %s", busid);
-
-       return suinf;
-}
-
-
-#define MAX_BUFF 100
-static int record_connection(char *host, char *port, char *busid, int rhport)
-{
-       int fd;
-       char path[PATH_MAX+1];
-       char buff[MAX_BUFF+1];
-       int ret;
-
-       mkdir(VHCI_STATE_PATH, 0700);
 
-       snprintf(path, PATH_MAX, VHCI_STATE_PATH"/port%d", rhport);
-
-       fd = open(path, O_WRONLY|O_CREAT|O_TRUNC, S_IRWXU);
-       if (fd < 0)
-               return -1;
-
-       snprintf(buff, MAX_BUFF, "%s %s %s\n",
-                       host, port, busid);
-
-       ret = write(fd, buff, strlen(buff));
-       if (ret != (ssize_t) strlen(buff)) {
-               close(fd);
-               return -1;
-       }
-
-       close(fd);
-
-       return 0;
-}
-
-static int read_record(int rhport, char *host, char *port, char *busid)
-{
-       FILE *file;
-       char path[PATH_MAX+1];
-
-       snprintf(path, PATH_MAX, VHCI_STATE_PATH"/port%d", rhport);
-
-       file = fopen(path, "r");
-       if (!file) {
-               err("fopen");
-               return -1;
-       }
+#include <getopt.h>
 
-       if (fscanf(file, "%s %s %s\n", host, port, busid) != 3) {
-               err("fscanf");
-               fclose(file);
-               return -1;
-       }
+#include "usbip_common.h"
+#include "usbip.h"
 
-       fclose(file);
+static int usbip_help(int argc, char *argv[]);
+static int usbip_version(int argc, char *argv[]);
 
-       return 0;
-}
+static const char usbip_version_string[] = PACKAGE_STRING;
 
+static const char usbip_usage_string[] =
+       "usbip [--debug] [version]\n"
+       "             [help] <command> <args>\n";
 
-int usbip_vhci_imported_device_dump(struct usbip_imported_device *idev)
+static void usbip_usage(void)
 {
-       char product_name[100];
-       char host[NI_MAXHOST] = "unknown host";
-       char serv[NI_MAXSERV] = "unknown port";
-       char remote_busid[SYSFS_BUS_ID_SIZE];
-       int ret;
-
-       if (idev->status == VDEV_ST_NULL || idev->status == VDEV_ST_NOTASSIGNED) {
-               info("Port %02d: <%s>", idev->port, usbip_status_string(idev->status));
-               return 0;
-       }
-
-       ret = read_record(idev->port, host, serv, remote_busid);
-       if (ret) {
-               err("read_record");
-               return -1;
-       }
-
-       info("Port %02d: <%s> at %s", idev->port,
-                       usbip_status_string(idev->status), usbip_speed_string(idev->udev.speed));
-
-       usbip_names_get_product(product_name, sizeof(product_name),
-                       idev->udev.idVendor, idev->udev.idProduct);
-
-       info("       %s",  product_name);
-
-       info("%10s -> usbip://%s:%s/%s  (remote devid %08x (bus/dev %03d/%03d))",
-                       idev->udev.busid, host, serv, remote_busid,
-                       idev->devid,
-                       idev->busnum, idev->devnum);
-
-       for (int i=0; i < idev->udev.bNumInterfaces; i++) {
-               /* show interface information */
-               struct sysfs_device *suinf;
-
-               suinf = open_usb_interface(&idev->udev, i);
-               if (!suinf)
-                       continue;
-
-               info("       %6s used by %-17s", suinf->bus_id, suinf->driver_name);
-               sysfs_close_device(suinf);
-
-               /* show class device information */
-               struct usbip_class_device *cdev;
-
-               dlist_for_each_data(idev->cdev_list, cdev,
-                                   struct usbip_class_device) {
-                       int ifnum = get_interface_number(cdev->dev_path);
-                       if (ifnum == i) {
-                               info("           %s", cdev->class_path);
-                       }
-               }
-       }
-
-       return 0;
+       printf("usage: %s", usbip_usage_string);
 }
 
+struct command {
+       const char *name;
+       int (*fn)(int argc, char *argv[]);
+       const char *help;
+       void (*usage)(void);
+};
 
+static const struct command cmds[] = {
+       {
+               .name  = "help",
+               .fn    = usbip_help,
+               .help  = NULL,
+               .usage = NULL
+       },
+       {
+               .name  = "version",
+               .fn    = usbip_version,
+               .help  = NULL,
+               .usage = NULL
+       },
+       {
+               .name  = "attach",
+               .fn    = usbip_attach,
+               .help  = "Attach a remote USB device",
+               .usage = usbip_attach_usage
+       },
+       {
+               .name  = "detach",
+               .fn    = usbip_detach,
+               .help  = "Detach a remote USB device",
+               .usage = usbip_detach_usage
+       },
+       {
+               .name  = "list",
+               .fn    = usbip_list,
+               .help  = "List exported or local USB devices",
+               .usage = usbip_list_usage
+       },
+       {
+               .name  = "bind",
+               .fn    = usbip_bind,
+               .help  = "Bind device to " USBIP_HOST_DRV_NAME ".ko",
+               .usage = usbip_bind_usage
+       },
+       {
+               .name  = "unbind",
+               .fn    = usbip_unbind,
+               .help  = "Unbind device from " USBIP_HOST_DRV_NAME ".ko",
+               .usage = usbip_unbind_usage
+       },
+       { NULL, NULL, NULL, NULL }
+};
 
-
-static int query_exported_devices(int sockfd)
+static int usbip_help(int argc, char *argv[])
 {
-       int ret;
-       struct op_devlist_reply rep;
-       uint16_t code = OP_REP_DEVLIST;
-
-       bzero(&rep, sizeof(rep));
-
-       ret = usbip_send_op_common(sockfd, OP_REQ_DEVLIST, 0);
-       if (ret < 0) {
-               err("send op_common");
-               return -1;
-       }
-
-       ret = usbip_recv_op_common(sockfd, &code);
-       if (ret < 0) {
-               err("recv op_common");
-               return -1;
-       }
-
-       ret = usbip_recv(sockfd, (void *) &rep, sizeof(rep));
-       if (ret < 0) {
-               err("recv op_devlist");
-               return -1;
-       }
-
-       PACK_OP_DEVLIST_REPLY(0, &rep);
-       dbg("exportable %d devices", rep.ndev);
-
-       for (unsigned int i=0; i < rep.ndev; i++) {
-               char product_name[100];
-               char class_name[100];
-               struct usb_device udev;
+       const struct command *cmd;
+       int i;
+       int ret = 0;
 
-               bzero(&udev, sizeof(udev));
-
-               ret = usbip_recv(sockfd, (void *) &udev, sizeof(udev));
-               if (ret < 0) {
-                       err("recv usb_device[%d]", i);
-                       return -1;
-               }
-               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);
-
-               info("%8s: %s", udev.busid, product_name);
-               info("%8s: %s", " ", udev.path);
-               info("%8s: %s", " ", class_name);
-
-               for (int j=0; j < udev.bNumInterfaces; j++) {
-                       struct usb_interface uinf;
-
-                       ret = usbip_recv(sockfd, (void *) &uinf, sizeof(uinf));
-                       if (ret < 0) {
-                               err("recv usb_interface[%d]", j);
-                               return -1;
+       if (argc > 1 && argv++) {
+               for (i = 0; cmds[i].name != NULL; i++)
+                       if (!strcmp(cmds[i].name, argv[0]) && cmds[i].usage) {
+                               cmds[i].usage();
+                               goto done;
                        }
-
-                       pack_usb_interface(0, &uinf);
-                       usbip_names_get_class(class_name, sizeof(class_name), uinf.bInterfaceClass,
-                                       uinf.bInterfaceSubClass, uinf.bInterfaceProtocol);
-
-                       info("%8s: %2d - %s", " ", j, class_name);
-               }
-
-               info(" ");
-       }
-
-       return rep.ndev;
-}
-
-static int import_device(int sockfd, struct usb_device *udev)
-{
-       int ret;
-       int port;
-
-       ret = usbip_vhci_driver_open();
-       if (ret < 0) {
-               err("open vhci_driver");
-               return -1;
-       }
-
-       port = usbip_vhci_get_free_port();
-       if (port < 0) {
-               err("no free port");
-               usbip_vhci_driver_close();
-               return -1;
-       }
-
-       ret = usbip_vhci_attach_device(port, sockfd, udev->busnum,
-                       udev->devnum, udev->speed);
-       if (ret < 0) {
-               err("import device");
-               usbip_vhci_driver_close();
-               return -1;
-       }
-
-       usbip_vhci_driver_close();
-
-       return port;
-}
-
-
-static int query_import_device(int sockfd, char *busid)
-{
-       int ret;
-       struct op_import_request request;
-       struct op_import_reply   reply;
-       uint16_t code = OP_REP_IMPORT;
-
-       bzero(&request, sizeof(request));
-       bzero(&reply, sizeof(reply));
-
-
-       /* send a request */
-       ret = usbip_send_op_common(sockfd, OP_REQ_IMPORT, 0);
-       if (ret < 0) {
-               err("send op_common");
-               return -1;
-       }
-
-       strncpy(request.busid, busid, SYSFS_BUS_ID_SIZE-1);
-
-       PACK_OP_IMPORT_REQUEST(0, &request);
-
-       ret = usbip_send(sockfd, (void *) &request, sizeof(request));
-       if (ret < 0) {
-               err("send op_import_request");
-               return -1;
+               ret = -1;
        }
 
-
-       /* recieve a reply */
-       ret = usbip_recv_op_common(sockfd, &code);
-       if (ret < 0) {
-               err("recv op_common");
-               return -1;
-       }
-
-       ret = usbip_recv(sockfd, (void *) &reply, sizeof(reply));
-       if (ret < 0) {
-               err("recv op_import_reply");
-               return -1;
-       }
-
-       PACK_OP_IMPORT_REPLY(0, &reply);
-
-
-       /* check the reply */
-       if (strncmp(reply.udev.busid, busid, SYSFS_BUS_ID_SIZE)) {
-               err("recv different busid %s", reply.udev.busid);
-               return -1;
-       }
-
-
-       /* import a device */
-       return import_device(sockfd, &reply.udev);
-}
-
-static int attach_device(char *host, char *busid)
-{
-       int sockfd;
-       int ret;
-       int rhport;
-
-       sockfd = tcp_connect(host, USBIP_PORT_STRING);
-       if (sockfd < 0) {
-               err("tcp connect");
-               return -1;
-       }
-
-       rhport = query_import_device(sockfd, busid);
-       if (rhport < 0) {
-               err("query");
-               return -1;
-       }
-
-       close(sockfd);
-
-       ret = record_connection(host, USBIP_PORT_STRING,
-                       busid, rhport);
-       if (ret < 0) {
-               err("record connection");
-               return -1;
-       }
-
-       return 0;
-}
-
-static int detach_port(char *port)
-{
-       int ret;
-       uint8_t portnum;
-
-       for (unsigned int i=0; i < strlen(port); i++)
-               if (!isdigit(port[i])) {
-                       err("invalid port %s", port);
-                       return -1;
-               }
-
-       /* check max port */
-
-       portnum = atoi(port);
-
-       ret = usbip_vhci_driver_open();
-       if (ret < 0) {
-               err("open vhci_driver");
-               return -1;
-       }
-
-       ret = usbip_vhci_detach_device(portnum);
-       if (ret < 0)
-               return -1;
-
-       usbip_vhci_driver_close();
-
+       usbip_usage();
+       printf("\n");
+       for (cmd = cmds; cmd->name != NULL; cmd++)
+               if (cmd->help != NULL)
+                       printf("  %-10s %s\n", cmd->name, cmd->help);
+       printf("\n");
+done:
        return ret;
 }
 
-static int show_exported_devices(char *host)
+static int usbip_version(int argc, char *argv[])
 {
-       int ret;
-       int sockfd;
-
-       sockfd = tcp_connect(host, USBIP_PORT_STRING);
-       if (sockfd < 0) {
-               err("- %s failed", host);
-               return -1;
-       }
-
-       info("- %s", host);
-
-       ret = query_exported_devices(sockfd);
-       if (ret < 0) {
-               err("query");
-               return -1;
-       }
+       (void) argc;
+       (void) argv;
 
-       close(sockfd);
+       printf("%s\n", usbip_version_string);
        return 0;
 }
 
-static int attach_exported_devices(char *host, int sockfd)
+static int run_command(const struct command *cmd, int argc, char *argv[])
 {
-       int ret;
-       struct op_devlist_reply rep;
-       uint16_t code = OP_REP_DEVLIST;
-
-       bzero(&rep, sizeof(rep));
-
-       ret = usbip_send_op_common(sockfd, OP_REQ_DEVLIST, 0);
-       if(ret < 0) {
-               err("send op_common");
-               return -1;
-       }
-
-       ret = usbip_recv_op_common(sockfd, &code);
-       if(ret < 0) {
-               err("recv op_common");
-               return -1;
-       }
-
-       ret = usbip_recv(sockfd, (void *) &rep, sizeof(rep));
-       if(ret < 0) {
-               err("recv op_devlist");
-               return -1;
-       }
-
-       PACK_OP_DEVLIST_REPLY(0, &rep);
-       dbg("exportable %d devices", rep.ndev);
-
-       for(unsigned int i=0; i < rep.ndev; i++) {
-               char product_name[100];
-               char class_name[100];
-               struct usb_device udev;
-
-               bzero(&udev, sizeof(udev));
-
-               ret = usbip_recv(sockfd, (void *) &udev, sizeof(udev));
-               if(ret < 0) {
-                       err("recv usb_device[%d]", i);
-                       return -1;
-               }
-               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);
-
-               dbg("Attaching usb port %s from host %s on usbip, with deviceid: %s", udev.busid, host, product_name);
-
-               for (int j=0; j < udev.bNumInterfaces; j++) {
-                       struct usb_interface uinf;
-
-                       ret = usbip_recv(sockfd, (void *) &uinf, sizeof(uinf));
-                       if (ret < 0) {
-                               err("recv usb_interface[%d]", j);
-                               return -1;
-                       }
-
-                       pack_usb_interface(0, &uinf);
-                       usbip_names_get_class(class_name, sizeof(class_name), uinf.bInterfaceClass,
-                                       uinf.bInterfaceSubClass, uinf.bInterfaceProtocol);
-
-                       dbg("interface %2d - %s", j, class_name);
-               }
-
-               attach_device(host, udev.busid);
-       }
-
-       return rep.ndev;
-}
-
-static int attach_devices_all(char *host)
-{
-       int ret;
-       int sockfd;
-
-       sockfd = tcp_connect(host, USBIP_PORT_STRING);
-       if(sockfd < 0) {
-               err("- %s failed", host);
-               return -1;
-       }
-
-       info("- %s", host);
-
-       ret = attach_exported_devices(host, sockfd);
-       if(ret < 0) {
-               err("query");
-               return -1;
-       }
-
-       close(sockfd);
-       return 0;
-}
-
-
-const char help_message[] = "\
-Usage: usbip [options]                         \n\
-       -a, --attach [host] [bus_id]            \n\
-               Attach a remote USB device.     \n\
-                                               \n\
-       -x, --attachall [host]          \n\
-               Attach all remote USB devices on the specific host.     \n\
-                                               \n\
-       -d, --detach [ports]                    \n\
-               Detach an imported USB device.  \n\
-                                               \n\
-       -l, --list [hosts]                      \n\
-               List exported USB devices.      \n\
-                                               \n\
-       -p, --port                              \n\
-               List virtual USB port status.   \n\
-                                               \n\
-       -D, --debug                             \n\
-               Print debugging information.    \n\
-                                               \n\
-       -v, --version                           \n\
-               Show version.                   \n\
-                                               \n\
-       -h, --help                              \n\
-               Print this help.                \n";
-
-static void show_help(void)
-{
-       printf("%s", help_message);
-}
-
-static int show_port_status(void)
-{
-       int ret;
-       struct usbip_imported_device *idev;
-
-       ret = usbip_vhci_driver_open();
-       if (ret < 0)
-               return ret;
-
-       for (int i = 0; i < vhci_driver->nports; i++) {
-               idev = &vhci_driver->idev[i];
-
-               if (usbip_vhci_imported_device_dump(idev) < 0)
-                       ret = -1;
-       }
-
-       usbip_vhci_driver_close();
-
-       return ret;
+       dbg("running command: `%s'\n", cmd->name);
+       return cmd->fn(argc, argv);
 }
 
-#define _GNU_SOURCE
-#include <getopt.h>
-static const struct option longopts[] = {
-       {"attach",      no_argument,    NULL, 'a'},
-       {"attachall",   no_argument,    NULL, 'x'},
-       {"detach",      no_argument,    NULL, 'd'},
-       {"port",        no_argument,    NULL, 'p'},
-       {"list",        no_argument,    NULL, 'l'},
-       {"version",     no_argument,    NULL, 'v'},
-       {"help",        no_argument,    NULL, 'h'},
-       {"debug",       no_argument,    NULL, 'D'},
-       {"syslog",      no_argument,    NULL, 'S'},
-       {NULL,          0,              NULL,  0}
-};
-
 int main(int argc, char *argv[])
 {
-       int ret;
-
-       enum {
-               cmd_attach = 1,
-               cmd_attachall,
-               cmd_detach,
-               cmd_port,
-               cmd_list,
-               cmd_help,
-               cmd_version
-       } cmd = 0;
-
-       usbip_use_stderr = 1;
-
-       if (geteuid() != 0)
-               g_warning("running non-root?");
-
-       ret = usbip_names_init(USBIDS_FILE);
-       if (ret)
-               notice("failed to open %s", USBIDS_FILE);
+       static const struct option opts[] = {
+               { "debug", no_argument, NULL, 'd' },
+               { NULL, 0, NULL, 0 }
+       };
+       char *cmd;
+       int opt;
+       int i, rc = -1;
 
+       opterr = 0;
        for (;;) {
-               int c;
-               int index = 0;
-
-               c = getopt_long(argc, argv, "adplvhDSx", longopts, &index);
+               opt = getopt_long(argc, argv, "+d", opts, NULL);
 
-               if (c == -1)
+               if (opt == -1)
                        break;
 
-               switch(c) {
-                       case 'a':
-                               if (!cmd)
-                                       cmd = cmd_attach;
-                               else
-                                       cmd = cmd_help;
-                               break;
-                       case 'd':
-                               if (!cmd)
-                                       cmd = cmd_detach;
-                               else
-                                       cmd = cmd_help;
-                               break;
-                       case 'p':
-                               if (!cmd)
-                                       cmd = cmd_port;
-                               else cmd = cmd_help;
-                               break;
-                       case 'l':
-                               if (!cmd)
-                                       cmd = cmd_list;
-                               else
-                                       cmd = cmd_help;
-                               break;
-                       case 'v':
-                               if (!cmd)
-                                       cmd = cmd_version;
-                               else
-                                       cmd = cmd_help;
-                               break;
-                       case 'x':
-                               if(!cmd)
-                                       cmd = cmd_attachall;
-                               else
-                                       cmd = cmd_help;
-                               break;
-                       case 'h':
-                               cmd = cmd_help;
-                               break;
-                       case 'D':
-                               usbip_use_debug = 1;
-                               break;
-                       case 'S':
-                               usbip_use_syslog = 1;
-                               break;
-                       case '?':
-                               break;
-
-                       default:
-                               err("getopt");
-               }
-       }
-
-       ret = 0;
-       switch(cmd) {
-               case cmd_attach:
-                       if (optind == argc - 2)
-                               ret = attach_device(argv[optind], argv[optind+1]);
-                       else
-                               show_help();
-                       break;
-               case cmd_detach:
-                       while (optind < argc)
-                               ret = detach_port(argv[optind++]);
-                       break;
-               case cmd_port:
-                       ret = show_port_status();
-                       break;
-               case cmd_list:
-                       while (optind < argc)
-                               ret = show_exported_devices(argv[optind++]);
-                       break;
-               case cmd_attachall:
-                       while(optind < argc)
-                               ret = attach_devices_all(argv[optind++]);
-                       break;
-               case cmd_version:
-                       printf("%s\n", version);
-                       break;
-               case cmd_help:
-                       show_help();
+               switch (opt) {
+               case 'd':
+                       usbip_use_debug = 1;
+                       usbip_use_stderr = 1;
                        break;
                default:
-                       show_help();
+                       goto err_out;
+               }
        }
 
+       cmd = argv[optind];
+       if (cmd) {
+               for (i = 0; cmds[i].name != NULL; i++)
+                       if (!strcmp(cmds[i].name, cmd)) {
+                               argc -= optind;
+                               argv += optind;
+                               optind = 0;
+                               rc = run_command(&cmds[i], argc, argv);
+                               goto out;
+                       }
+       }
 
-       usbip_names_free();
-
-       exit((ret == 0) ? EXIT_SUCCESS : EXIT_FAILURE);
+err_out:
+       usbip_usage();
+out:
+       return (rc > -1 ? EXIT_SUCCESS : EXIT_FAILURE);
 }
diff --git a/drivers/staging/usbip/userspace/src/usbip.h b/drivers/staging/usbip/userspace/src/usbip.h
new file mode 100644 (file)
index 0000000..14d4a47
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * 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/>.
+ */
+
+#ifndef __USBIP_H
+#define __USBIP_H
+
+#ifdef HAVE_CONFIG_H
+#include "../config.h"
+#endif
+
+/* usbip commands */
+int usbip_attach(int argc, char *argv[]);
+int usbip_detach(int argc, char *argv[]);
+int usbip_list(int argc, char *argv[]);
+int usbip_bind(int argc, char *argv[]);
+int usbip_unbind(int argc, char *argv[]);
+
+void usbip_attach_usage(void);
+void usbip_detach_usage(void);
+void usbip_list_usage(void);
+void usbip_bind_usage(void);
+void usbip_unbind_usage(void);
+
+#endif /* __USBIP_H */
diff --git a/drivers/staging/usbip/userspace/src/usbip_attach.c b/drivers/staging/usbip/userspace/src/usbip_attach.c
new file mode 100644 (file)
index 0000000..671d23c
--- /dev/null
@@ -0,0 +1,228 @@
+/*
+ * 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/stat.h>
+#include <sysfs/libsysfs.h>
+
+#include <limits.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <fcntl.h>
+#include <getopt.h>
+#include <unistd.h>
+
+#include "vhci_driver.h"
+#include "usbip_common.h"
+#include "usbip_network.h"
+#include "usbip.h"
+
+static const char usbip_attach_usage_string[] =
+       "usbip attach <args>\n"
+       "    -h, --host=<host>      The machine with exported USB devices\n"
+       "    -b, --busid=<busid>    Busid of the device on <host>\n";
+
+void usbip_attach_usage(void)
+{
+       printf("usage: %s", usbip_attach_usage_string);
+}
+
+#define MAX_BUFF 100
+static int record_connection(char *host, char *port, char *busid, int rhport)
+{
+       int fd;
+       char path[PATH_MAX+1];
+       char buff[MAX_BUFF+1];
+       int ret;
+
+       mkdir(VHCI_STATE_PATH, 0700);
+
+       snprintf(path, PATH_MAX, VHCI_STATE_PATH"/port%d", rhport);
+
+       fd = open(path, O_WRONLY|O_CREAT|O_TRUNC, S_IRWXU);
+       if (fd < 0)
+               return -1;
+
+       snprintf(buff, MAX_BUFF, "%s %s %s\n",
+                       host, port, busid);
+
+       ret = write(fd, buff, strlen(buff));
+       if (ret != (ssize_t) strlen(buff)) {
+               close(fd);
+               return -1;
+       }
+
+       close(fd);
+
+       return 0;
+}
+
+static int import_device(int sockfd, struct usb_device *udev)
+{
+       int rc;
+       int port;
+
+       rc = usbip_vhci_driver_open();
+       if (rc < 0) {
+               err("open vhci_driver");
+               return -1;
+       }
+
+       port = usbip_vhci_get_free_port();
+       if (port < 0) {
+               err("no free port");
+               usbip_vhci_driver_close();
+               return -1;
+       }
+
+       rc = usbip_vhci_attach_device(port, sockfd, udev->busnum,
+                                     udev->devnum, udev->speed);
+       if (rc < 0) {
+               err("import device");
+               usbip_vhci_driver_close();
+               return -1;
+       }
+
+       usbip_vhci_driver_close();
+
+       return port;
+}
+
+static int query_import_device(int sockfd, char *busid)
+{
+       int rc;
+       struct op_import_request request;
+       struct op_import_reply   reply;
+       uint16_t code = OP_REP_IMPORT;
+
+       memset(&request, 0, sizeof(request));
+       memset(&reply, 0, sizeof(reply));
+
+       /* send a request */
+       rc = usbip_send_op_common(sockfd, OP_REQ_IMPORT, 0);
+       if (rc < 0) {
+               err("send op_common");
+               return -1;
+       }
+
+       strncpy(request.busid, busid, SYSFS_BUS_ID_SIZE-1);
+
+       PACK_OP_IMPORT_REQUEST(0, &request);
+
+       rc = usbip_send(sockfd, (void *) &request, sizeof(request));
+       if (rc < 0) {
+               err("send op_import_request");
+               return -1;
+       }
+
+       /* recieve a reply */
+       rc = usbip_recv_op_common(sockfd, &code);
+       if (rc < 0) {
+               err("recv op_common");
+               return -1;
+       }
+
+       rc = usbip_recv(sockfd, (void *) &reply, sizeof(reply));
+       if (rc < 0) {
+               err("recv op_import_reply");
+               return -1;
+       }
+
+       PACK_OP_IMPORT_REPLY(0, &reply);
+
+       /* check the reply */
+       if (strncmp(reply.udev.busid, busid, SYSFS_BUS_ID_SIZE)) {
+               err("recv different busid %s", reply.udev.busid);
+               return -1;
+       }
+
+       /* import a device */
+       return import_device(sockfd, &reply.udev);
+}
+
+static int attach_device(char *host, char *busid)
+{
+       int sockfd;
+       int rc;
+       int rhport;
+
+       sockfd = usbip_net_tcp_connect(host, USBIP_PORT_STRING);
+       if (sockfd < 0) {
+               err("tcp connect");
+               return -1;
+       }
+
+       rhport = query_import_device(sockfd, busid);
+       if (rhport < 0) {
+               err("query");
+               return -1;
+       }
+
+       close(sockfd);
+
+       rc = record_connection(host, USBIP_PORT_STRING, busid, rhport);
+       if (rc < 0) {
+               err("record connection");
+               return -1;
+       }
+
+       return 0;
+}
+
+int usbip_attach(int argc, char *argv[])
+{
+       static const struct option opts[] = {
+               { "host", required_argument, NULL, 'h' },
+               { "busid", required_argument, NULL, 'b' },
+               { NULL, 0, NULL, 0 }
+       };
+       char *host = NULL;
+       char *busid = NULL;
+       int opt;
+       int ret = -1;
+
+       for (;;) {
+               opt = getopt_long(argc, argv, "h:b:", opts, NULL);
+
+               if (opt == -1)
+                       break;
+
+               switch (opt) {
+               case 'h':
+                       host = optarg;
+                       break;
+               case 'b':
+                       busid = optarg;
+                       break;
+               default:
+                       goto err_out;
+               }
+       }
+
+       if (!host || !busid)
+               goto err_out;
+
+       ret = attach_device(host, busid);
+       goto out;
+
+err_out:
+       usbip_attach_usage();
+out:
+       return ret;
+}
diff --git a/drivers/staging/usbip/userspace/src/usbip_bind.c b/drivers/staging/usbip/userspace/src/usbip_bind.c
new file mode 100644 (file)
index 0000000..26cfbad
--- /dev/null
@@ -0,0 +1,261 @@
+/*
+ * 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 <sysfs/libsysfs.h>
+
+#include <stdio.h>
+#include <string.h>
+
+#include <getopt.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "usbip_common.h"
+#include "utils.h"
+#include "usbip.h"
+
+static const char usbip_bind_usage_string[] =
+       "usbip bind <args>\n"
+       "    -b, --busid=<busid>    Bind " USBIP_HOST_DRV_NAME ".ko to device "
+       "on <busid>\n";
+
+void usbip_bind_usage(void)
+{
+       printf("usage: %s", usbip_bind_usage_string);
+}
+
+static const char unbind_path_format[] = "/sys/bus/usb/devices/%s/driver/unbind";
+
+/* buggy driver may cause dead lock */
+static int unbind_interface_busid(char *busid)
+{
+       char unbind_path[SYSFS_PATH_MAX];
+       int fd;
+       int ret;
+
+       snprintf(unbind_path, sizeof(unbind_path), unbind_path_format, busid);
+
+       fd = open(unbind_path, O_WRONLY);
+       if (fd < 0) {
+               dbg("opening unbind_path failed: %d", fd);
+               return -1;
+       }
+
+       ret = write(fd, busid, strnlen(busid, BUS_ID_SIZE));
+       if (ret < 0) {
+               dbg("write to unbind_path failed: %d", ret);
+               close(fd);
+               return -1;
+       }
+
+       close(fd);
+
+       return 0;
+}
+
+static int unbind_interface(char *busid, int configvalue, int interface)
+{
+       char inf_busid[BUS_ID_SIZE];
+       dbg("unbinding interface");
+
+       snprintf(inf_busid, BUS_ID_SIZE, "%s:%d.%d", busid, configvalue, interface);
+
+       return unbind_interface_busid(inf_busid);
+}
+
+static int unbind(char *busid)
+{
+       int configvalue = 0;
+       int ninterface = 0;
+       int devclass = 0;
+       int i;
+       int failed = 0;
+
+       configvalue = read_bConfigurationValue(busid);
+       ninterface  = read_bNumInterfaces(busid);
+       devclass  = read_bDeviceClass(busid);
+
+       if (configvalue < 0 || ninterface < 0 || devclass < 0) {
+               dbg("read config and ninf value, removed?");
+               return -1;
+       }
+
+       if (devclass == 0x09) {
+               dbg("skip unbinding of hub");
+               return -1;
+       }
+
+       for (i = 0; i < ninterface; i++) {
+               char driver[PATH_MAX];
+               int ret;
+
+               memset(&driver, 0, sizeof(driver));
+
+               getdriver(busid, configvalue, i, driver, PATH_MAX-1);
+
+               dbg(" %s:%d.%d  -> %s ", busid, configvalue, i, driver);
+
+               if (!strncmp("none", driver, PATH_MAX))
+                       continue; /* unbound interface */
+
+#if 0
+               if (!strncmp("usbip", driver, PATH_MAX))
+                       continue; /* already bound to usbip */
+#endif
+
+               /* unbinding */
+               ret = unbind_interface(busid, configvalue, i);
+               if (ret < 0) {
+                       dbg("unbind driver at %s:%d.%d failed",
+                           busid, configvalue, i);
+                       failed = 1;
+               }
+       }
+
+       if (failed)
+               return -1;
+       else
+               return 0;
+}
+
+static const char bind_path_format[] = "/sys/bus/usb/drivers/%s/bind";
+
+static int bind_interface_busid(char *busid, char *driver)
+{
+       char bind_path[PATH_MAX];
+       int fd;
+       int ret;
+
+       snprintf(bind_path, sizeof(bind_path), bind_path_format, driver);
+
+       fd = open(bind_path, O_WRONLY);
+       if (fd < 0)
+               return -1;
+
+       ret = write(fd, busid, strnlen(busid, BUS_ID_SIZE));
+       if (ret < 0) {
+               close(fd);
+               return -1;
+       }
+
+       close(fd);
+
+       return 0;
+}
+
+static int bind_interface(char *busid, int configvalue, int interface, char *driver)
+{
+       char inf_busid[BUS_ID_SIZE];
+
+       snprintf(inf_busid, BUS_ID_SIZE, "%s:%d.%d", busid, configvalue, interface);
+
+       return bind_interface_busid(inf_busid, driver);
+}
+
+/* call at unbound state */
+static int bind_to_usbip(char *busid)
+{
+       int configvalue = 0;
+       int ninterface = 0;
+       int i;
+       int failed = 0;
+
+       configvalue = read_bConfigurationValue(busid);
+       ninterface  = read_bNumInterfaces(busid);
+
+       if (configvalue < 0 || ninterface < 0) {
+               dbg("read config and ninf value, removed?");
+               return -1;
+       }
+
+       for (i = 0; i < ninterface; i++) {
+               int ret;
+
+               ret = bind_interface(busid, configvalue, i,
+                                    USBIP_HOST_DRV_NAME);
+               if (ret < 0) {
+                       dbg("bind usbip at %s:%d.%d, failed",
+                           busid, configvalue, i);
+                       failed = 1;
+                       /* need to contine binding at other interfaces */
+               }
+       }
+
+       if (failed)
+               return -1;
+       else
+               return 0;
+}
+
+static int use_device_by_usbip(char *busid)
+{
+       int ret;
+
+       ret = unbind(busid);
+       if (ret < 0) {
+               dbg("unbind drivers of %s, failed", busid);
+               return -1;
+       }
+
+       ret = modify_match_busid(busid, 1);
+       if (ret < 0) {
+               dbg("add %s to match_busid, failed", busid);
+               return -1;
+       }
+
+       ret = bind_to_usbip(busid);
+       if (ret < 0) {
+               dbg("bind usbip to %s, failed", busid);
+               modify_match_busid(busid, 0);
+               return -1;
+       }
+
+       dbg("bind %s complete!", busid);
+
+       return 0;
+}
+
+int usbip_bind(int argc, char *argv[])
+{
+       static const struct option opts[] = {
+               { "busid", required_argument, NULL, 'b' },
+               { NULL, 0, NULL, 0 }
+       };
+       int opt;
+       int ret = -1;
+
+       for (;;) {
+               opt = getopt_long(argc, argv, "b:", opts, NULL);
+
+               if (opt == -1)
+                       break;
+
+               switch (opt) {
+               case 'b':
+                       ret = use_device_by_usbip(optarg);
+                       goto out;
+               default:
+                       goto err_out;
+               }
+       }
+
+err_out:
+       usbip_bind_usage();
+out:
+       return ret;
+}
diff --git a/drivers/staging/usbip/userspace/src/usbip_detach.c b/drivers/staging/usbip/userspace/src/usbip_detach.c
new file mode 100644 (file)
index 0000000..89bf3c1
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ * 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 <sysfs/libsysfs.h>
+
+#include <ctype.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <getopt.h>
+#include <unistd.h>
+
+#include "vhci_driver.h"
+#include "usbip_common.h"
+#include "usbip_network.h"
+#include "usbip.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";
+
+void usbip_detach_usage(void)
+{
+       printf("usage: %s", usbip_detach_usage_string);
+}
+
+static int detach_port(char *port)
+{
+       int ret;
+       uint8_t portnum;
+
+       for (unsigned int i=0; i < strlen(port); i++)
+               if (!isdigit(port[i])) {
+                       err("invalid port %s", port);
+                       return -1;
+               }
+
+       /* check max port */
+
+       portnum = atoi(port);
+
+       ret = usbip_vhci_driver_open();
+       if (ret < 0) {
+               err("open vhci_driver");
+               return -1;
+       }
+
+       ret = usbip_vhci_detach_device(portnum);
+       if (ret < 0)
+               return -1;
+
+       usbip_vhci_driver_close();
+
+       return ret;
+}
+
+int usbip_detach(int argc, char *argv[])
+{
+       static const struct option opts[] = {
+               { "port", required_argument, NULL, 'p' },
+               { NULL, 0, NULL, 0 }
+       };
+       int opt;
+       int ret = -1;
+
+       for (;;) {
+               opt = getopt_long(argc, argv, "p:", opts, NULL);
+
+               if (opt == -1)
+                       break;
+
+               switch (opt) {
+               case 'p':
+                       ret = detach_port(optarg);
+                       goto out;
+               default:
+                       goto err_out;
+               }
+       }
+
+err_out:
+       usbip_detach_usage();
+out:
+       return ret;
+}
diff --git a/drivers/staging/usbip/userspace/src/usbip_list.c b/drivers/staging/usbip/userspace/src/usbip_list.c
new file mode 100644 (file)
index 0000000..72236ae
--- /dev/null
@@ -0,0 +1,306 @@
+/*
+ * 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 <string.h>
+
+#include <dirent.h>
+#include <getopt.h>
+#include <netdb.h>
+#include <regex.h>
+#include <unistd.h>
+
+#include "usbip_common.h"
+#include "usbip_network.h"
+#include "utils.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 exported 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 query_exported_devices(int sockfd)
+{
+       int ret;
+       struct op_devlist_reply rep;
+       uint16_t code = OP_REP_DEVLIST;
+
+       memset(&rep, 0, sizeof(rep));
+
+       ret = usbip_send_op_common(sockfd, OP_REQ_DEVLIST, 0);
+       if (ret < 0) {
+               err("send op_common");
+               return -1;
+       }
+
+       ret = usbip_recv_op_common(sockfd, &code);
+       if (ret < 0) {
+               err("recv op_common");
+               return -1;
+       }
+
+       ret = usbip_recv(sockfd, (void *) &rep, sizeof(rep));
+       if (ret < 0) {
+               err("recv op_devlist");
+               return -1;
+       }
+
+       PACK_OP_DEVLIST_REPLY(0, &rep);
+       dbg("exportable %d devices", rep.ndev);
+
+       for (unsigned int i=0; i < rep.ndev; i++) {
+               char product_name[100];
+               char class_name[100];
+               struct usb_device udev;
+
+               memset(&udev, 0, sizeof(udev));
+
+               ret = usbip_recv(sockfd, (void *) &udev, sizeof(udev));
+               if (ret < 0) {
+                       err("recv usb_device[%d]", i);
+                       return -1;
+               }
+               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("%8s: %s\n", udev.busid, product_name);
+               printf("%8s: %s\n", " ", udev.path);
+               printf("%8s: %s\n", " ", class_name);
+
+               for (int j=0; j < udev.bNumInterfaces; j++) {
+                       struct usb_interface uinf;
+
+                       ret = usbip_recv(sockfd, (void *) &uinf, sizeof(uinf));
+                       if (ret < 0) {
+                               err("recv usb_interface[%d]", j);
+                               return -1;
+                       }
+
+                       pack_usb_interface(0, &uinf);
+                       usbip_names_get_class(class_name, sizeof(class_name),
+                                             uinf.bInterfaceClass,
+                                             uinf.bInterfaceSubClass,
+                                             uinf.bInterfaceProtocol);
+
+                       printf("%8s: %2d - %s\n", " ", j, class_name);
+               }
+
+               printf("\n");
+       }
+
+       return rep.ndev;
+}
+
+static int show_exported_devices(char *host)
+{
+       int ret;
+       int sockfd;
+
+       sockfd = usbip_net_tcp_connect(host, USBIP_PORT_STRING);
+       if (sockfd < 0) {
+               err("unable to connect to %s port %s: %s\n", host,
+                   USBIP_PORT_STRING, gai_strerror(sockfd));
+               return -1;
+       }
+       dbg("connected to %s port %s\n", host, USBIP_PORT_STRING);
+
+       printf("- %s\n", host);
+
+       ret = query_exported_devices(sockfd);
+       if (ret < 0) {
+               err("query");
+               return -1;
+       }
+
+       close(sockfd);
+       return 0;
+}
+
+static int is_usb_device(char *busid)
+{
+       int ret;
+
+       regex_t regex;
+       regmatch_t pmatch[1];
+
+       ret = regcomp(&regex, "^[0-9]+-[0-9]+(\\.[0-9]+)*$", REG_NOSUB|REG_EXTENDED);
+       if (ret < 0)
+               err("regcomp: %s\n", strerror(errno));
+
+       ret = regexec(&regex, busid, 0, pmatch, 0);
+       if (ret)
+               return 0;       /* not matched */
+
+       return 1;
+}
+
+static int show_devices(void)
+{
+       DIR *dir;
+
+       dir = opendir("/sys/bus/usb/devices/");
+       if (!dir)
+               err("opendir: %s", strerror(errno));
+
+       printf("List USB devices\n");
+       for (;;) {
+               struct dirent *dirent;
+               char *busid;
+
+               dirent = readdir(dir);
+               if (!dirent)
+                       break;
+
+               busid = dirent->d_name;
+
+               if (is_usb_device(busid)) {
+                       char name[100] = {'\0'};
+                       char driver[100] =  {'\0'};
+                       int conf, ninf = 0;
+                       int i;
+
+                       conf = read_bConfigurationValue(busid);
+                       ninf = read_bNumInterfaces(busid);
+
+                       getdevicename(busid, name, sizeof(name));
+
+                       printf(" - busid %s (%s)\n", busid, name);
+
+                       for (i = 0; i < ninf; i++) {
+                               getdriver(busid, conf, i, driver,
+                                         sizeof(driver));
+                               printf("         %s:%d.%d -> %s\n", busid, conf,
+                                      i, driver);
+                       }
+                       printf("\n");
+               }
+       }
+
+       closedir(dir);
+
+       return 0;
+}
+
+static int show_devices2(void)
+{
+       DIR *dir;
+
+       dir = opendir("/sys/bus/usb/devices/");
+       if (!dir)
+               err("opendir: %s", strerror(errno));
+
+       for (;;) {
+               struct dirent *dirent;
+               char *busid;
+
+               dirent = readdir(dir);
+               if (!dirent)
+                       break;
+
+               busid = dirent->d_name;
+
+               if (is_usb_device(busid)) {
+                       char name[100] = {'\0'};
+                       char driver[100] =  {'\0'};
+                       int conf, ninf = 0;
+                       int i;
+
+                       conf = read_bConfigurationValue(busid);
+                       ninf = read_bNumInterfaces(busid);
+
+                       getdevicename(busid, name, sizeof(name));
+
+                       printf("busid=%s#usbid=%s#", busid, name);
+
+                       for (i = 0; i < ninf; i++) {
+                               getdriver(busid, conf, i, driver, sizeof(driver));
+                               printf("%s:%d.%d=%s#", busid, conf, i, driver);
+                       }
+                       printf("\n");
+               }
+       }
+
+       closedir(dir);
+
+       return 0;
+}
+
+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 is_parsable = false;
+       int opt;
+       int ret = -1;
+
+       if (usbip_names_init(USBIDS_FILE))
+               err("failed to open %s\n", USBIDS_FILE);
+
+       for (;;) {
+               opt = getopt_long(argc, argv, "pr:l", opts, NULL);
+
+               if (opt == -1)
+                       break;
+
+               switch (opt) {
+               case 'p':
+                       is_parsable = true;
+                       break;
+               case 'r':
+                       ret = show_exported_devices(optarg);
+                       goto out;
+               case 'l':
+                       if (is_parsable)
+                               ret = show_devices2();
+                       else
+                               ret = show_devices();
+                       goto out;
+               default:
+                       goto err_out;
+               }
+       }
+
+err_out:
+       usbip_list_usage();
+out:
+       usbip_names_free();
+
+       return ret;
+}
diff --git a/drivers/staging/usbip/userspace/src/usbip_unbind.c b/drivers/staging/usbip/userspace/src/usbip_unbind.c
new file mode 100644 (file)
index 0000000..9978d38
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * 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 <stdio.h>
+
+#include <getopt.h>
+#include <unistd.h>
+
+#include "usbip_common.h"
+#include "utils.h"
+#include "usbip.h"
+
+static const char usbip_unbind_usage_string[] =
+       "usbip unbind <args>\n"
+       "    -b, --busid=<busid>    Unbind " USBIP_HOST_DRV_NAME ".ko from "
+       "device on <busid>\n";
+
+void usbip_unbind_usage(void)
+{
+       printf("usage: %s", usbip_unbind_usage_string);
+}
+
+static int use_device_by_other(char *busid)
+{
+       int rc;
+       int config;
+
+       /* read and write the same config value to kick probing */
+       config = read_bConfigurationValue(busid);
+       if (config < 0) {
+               dbg("read bConfigurationValue of %s, failed", busid);
+               return -1;
+       }
+
+       rc = modify_match_busid(busid, 0);
+       if (rc < 0) {
+               dbg("del %s to match_busid, failed", busid);
+               return -1;
+       }
+
+       rc = write_bConfigurationValue(busid, config);
+       if (rc < 0) {
+               dbg("read bConfigurationValue of %s, failed", busid);
+               return -1;
+       }
+
+       info("bind %s to other drivers than usbip, complete!", busid);
+
+       return 0;
+}
+
+int usbip_unbind(int argc, char *argv[])
+{
+       static const struct option opts[] = {
+               { "busid", required_argument, NULL, 'b' },
+               { NULL, 0, NULL, 0 }
+       };
+       int opt;
+       int ret = -1;
+
+       for (;;) {
+               opt = getopt_long(argc, argv, "b:", opts, NULL);
+
+               if (opt == -1)
+                       break;
+
+               switch (opt) {
+               case 'b':
+                       ret = use_device_by_other(optarg);
+                       goto out;
+               default:
+                       goto err_out;
+               }
+       }
+
+err_out:
+       usbip_unbind_usage();
+out:
+       return ret;
+}
index 8f44108..6f91557 100644 (file)
@@ -3,8 +3,61 @@
  * Copyright (C) 2005-2007 Takahiro Hirofuchi
  */
 
+#include <sysfs/libsysfs.h>
+#include <fcntl.h>
+#include <libgen.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "usbip_common.h"
 #include "utils.h"
 
+int modify_match_busid(char *busid, int add)
+{
+       int fd;
+       int ret;
+       char buff[BUS_ID_SIZE + 4];
+       char sysfs_mntpath[SYSFS_PATH_MAX];
+       char match_busid_path[SYSFS_PATH_MAX];
+
+       ret = sysfs_get_mnt_path(sysfs_mntpath, SYSFS_PATH_MAX);
+       if (ret < 0) {
+               err("sysfs must be mounted");
+               return -1;
+       }
+
+       snprintf(match_busid_path, sizeof(match_busid_path),
+                "%s/%s/usb/%s/%s/match_busid", sysfs_mntpath, SYSFS_BUS_NAME,
+                SYSFS_DRIVERS_NAME, USBIP_HOST_DRV_NAME);
+
+       /* BUS_IS_SIZE includes NULL termination? */
+       if (strnlen(busid, BUS_ID_SIZE) > BUS_ID_SIZE - 1) {
+               dbg("busid is too long");
+               return -1;
+       }
+
+       fd = open(match_busid_path, O_WRONLY);
+       if (fd < 0)
+               return -1;
+
+       if (add)
+               snprintf(buff, BUS_ID_SIZE + 4, "add %s", busid);
+       else
+               snprintf(buff, BUS_ID_SIZE + 4, "del %s", busid);
+
+       dbg("write \"%s\" to %s", buff, match_busid_path);
+
+       ret = write(fd, buff, sizeof(buff));
+       if (ret < 0) {
+               close(fd);
+               return -1;
+       }
+
+       close(fd);
+
+       return 0;
+}
+
 int read_integer(char *path)
 {
        char buff[100];
@@ -36,7 +89,7 @@ int read_string(char *path, char *string, size_t len)
        int ret = 0;
        char  *p;
 
-       bzero(string, len);
+       memset(string, 0, len);
 
        fd = open(path, O_RDONLY);
        if (fd < 0) {
@@ -122,15 +175,16 @@ int getdriver(char *busid, int conf, int infnum, char *driver, size_t len)
 {
        char path[PATH_MAX];
        char linkto[PATH_MAX];
+       const char none[] = "none";
        int ret;
 
        snprintf(path, PATH_MAX, "/sys/bus/usb/devices/%s:%d.%d/driver", busid, conf, infnum);
 
        /* readlink does not add NULL */
-       bzero(linkto, sizeof(linkto));
+       memset(linkto, 0, sizeof(linkto));
        ret = readlink(path, linkto, sizeof(linkto)-1);
        if (ret < 0) {
-               strncpy(driver, "none", len);
+               strncpy(driver, none, len);
                return -1;
        } else {
                strncpy(driver, basename(linkto), len);
index 6c29ae9..423716d 100644 (file)
@@ -25,6 +25,7 @@
 /* Be sync to kernel header */
 #define BUS_ID_SIZE 20
 
+int modify_match_busid(char *busid, int add);
 int read_string(char *path, char *, size_t len);
 int read_integer(char *path);
 int getdevicename(char *busid, char *name, size_t len);