Extend command "usbip bind" with: * flag "-c" to wait for busid to connect and then bind, instead of returning error. * flag "-d", to wait for busid to disconnect before exit. Today manual steps is required to re-export usb device when re-connected. With above flags enabled, it's possible to permanently "export" usb devices with help of example systemd or other process supervisors, or with a simple while-loop in bash. Signed-off-by: Lars Gunnarsson <gunnarsson.lars@xxxxxxxxx> --- tools/usb/usbip/src/usbip_bind.c | 62 +++++++++++++++++++++++++++----- 1 file changed, 53 insertions(+), 9 deletions(-) diff --git a/tools/usb/usbip/src/usbip_bind.c b/tools/usb/usbip/src/usbip_bind.c index f1cf9225a69c..907c81f2160c 100644 --- a/tools/usb/usbip/src/usbip_bind.c +++ b/tools/usb/usbip/src/usbip_bind.c @@ -14,6 +14,7 @@ #include <getopt.h> #include "usbip_common.h" +#include "usbip_monitor.h" #include "utils.h" #include "usbip.h" #include "sysfs_utils.h" @@ -24,10 +25,18 @@ enum unbind_status { UNBIND_ST_FAILED }; +typedef struct { + char *busid; + char monitor_connect; + char monitor_disconnect; +} bind_options; + 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"; + " -b, --busid=<busid> Bind " USBIP_HOST_DRV_NAME ".ko to device\n" + " on <busid>\n" + " -c, --monitor-connect Wait until bus is available before binding\n" + " -d, --monitor-disconnect Wait until bus is disconnected before exit\n"; void usbip_bind_usage(void) { @@ -127,19 +136,32 @@ static int unbind_other(char *busid) return status; } -static int bind_device(char *busid) +static int bind_device(bind_options options) { int rc; struct udev *udev; struct udev_device *dev; const char *devpath; + usbip_monitor_t *monitor = NULL; + char *busid = options.busid; + + if (options.monitor_disconnect || options.monitor_connect) { + monitor = usbip_monitor_new(); + usbip_monitor_set_busid(monitor, options.busid); + } /* Check whether the device with this bus ID exists. */ udev = udev_new(); dev = udev_device_new_from_subsystem_sysname(udev, "usb", busid); if (!dev) { - err("device with the specified bus ID does not exist"); - return -1; + if (options.monitor_connect) { + info("device on busid %s: awaiting connect", busid); + usbip_monitor_await_usb_bind(monitor, USBIP_USB_DRV_NAME); + dev = udev_device_new_from_subsystem_sysname(udev, "usb", busid); + } else { + err("device with the specified bus ID does not exist"); + return -1; + } } devpath = udev_device_get_devpath(dev); udev_unref(udev); @@ -174,7 +196,14 @@ static int bind_device(char *busid) return -1; } - info("bind device on busid %s: complete", busid); + info("device on busid %s: bind complete", busid); + + if (options.monitor_disconnect) { + info("device on busid %s: await disconnect", busid); + usbip_monitor_await_usb_bind(monitor, USBIP_HOST_DRV_NAME); + usbip_monitor_await_usb_unbind(monitor); + usbip_monitor_delete(monitor); + } return 0; } @@ -183,27 +212,42 @@ int usbip_bind(int argc, char *argv[]) { static const struct option opts[] = { { "busid", required_argument, NULL, 'b' }, + { "monitor-connect", no_argument, NULL, 'c' }, + { "monitor-disconnect", no_argument, NULL, 'd' }, { NULL, 0, NULL, 0 } }; + bind_options options = {}; int opt; int ret = -1; for (;;) { - opt = getopt_long(argc, argv, "b:", opts, NULL); + opt = getopt_long(argc, argv, "b:cd", opts, NULL); if (opt == -1) break; switch (opt) { case 'b': - ret = bind_device(optarg); - goto out; + options.busid = optarg; + break; + case 'c': + options.monitor_connect = 1; + break; + case 'd': + options.monitor_disconnect = 1; + break; default: goto err_out; } } + if (!options.busid) + goto err_out; + + ret = bind_device(options); + goto out; + err_out: usbip_bind_usage(); out: -- 2.25.1