Skip to content

Commit a957b21

Browse files
authored
Add --sysdev/-y option for direct device node access (#600)
* Add --sysdev/-u option for direct device node access Only the device specified by the given device path will be accessed, instead of scanning the USB bus. Most useful if you use udev rules to create stable device node aliases for hubs, independent of bus topology. For instance, if your matching udev rules include SYMLINK+="MYSMARTHUB1" you can call uhubctl with --sysdev /dev/MYSMARTHUB1 instead of using -l and a non-stable bus location to specify it. Signed-off-by: Tormod Volden <debian.tormod@gmail.com>
1 parent 2dbc6ce commit a957b21

File tree

1 file changed

+63
-0
lines changed

1 file changed

+63
-0
lines changed

uhubctl.c

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,9 @@ static int opt_force = 0; /* force operation even on unsupported hubs */
223223
static int opt_nodesc = 0; /* skip querying device description */
224224
#if defined(__gnu_linux__) || defined(__linux__)
225225
static int opt_nosysfs = 0; /* don't use the Linux sysfs port disable interface, even if available */
226+
#if defined(LIBUSB_API_VERSION) && (LIBUSB_API_VERSION >= 0x01000107)
227+
static const char *opt_sysdev;
228+
#endif
226229
#endif
227230

228231
/* For Raspberry Pi detection and workarounds: */
@@ -232,8 +235,12 @@ static int is_rpi_5 = 0;
232235
static const char short_options[] =
233236
"l:L:n:a:p:d:r:w:s:hvefRN"
234237
#if defined(__gnu_linux__) || defined(__linux__)
238+
#if defined(LIBUSB_API_VERSION) && (LIBUSB_API_VERSION >= 0x01000107)
239+
"Sy:"
240+
#else
235241
"S"
236242
#endif
243+
#endif
237244
;
238245

239246
static const struct option long_options[] = {
@@ -251,6 +258,9 @@ static const struct option long_options[] = {
251258
{ "nodesc", no_argument, NULL, 'N' },
252259
#if defined(__gnu_linux__) || defined(__linux__)
253260
{ "nosysfs", no_argument, NULL, 'S' },
261+
#if defined(LIBUSB_API_VERSION) && (LIBUSB_API_VERSION >= 0x01000107)
262+
{ "sysdev", required_argument, NULL, 'y' },
263+
#endif
254264
#endif
255265
{ "reset", no_argument, NULL, 'R' },
256266
{ "version", no_argument, NULL, 'v' },
@@ -280,6 +290,9 @@ static int print_usage(void)
280290
"--nodesc, -N - do not query device description (helpful for unresponsive devices).\n"
281291
#if defined(__gnu_linux__) || defined(__linux__)
282292
"--nosysfs, -S - do not use the Linux sysfs port disable interface.\n"
293+
#if defined(LIBUSB_API_VERSION) && (LIBUSB_API_VERSION >= 0x01000107)
294+
"--sysdev, -y - open system device node instead of scanning.\n"
295+
#endif
283296
#endif
284297
"--reset, -R - reset hub after each power-on action, causing all devices to reassociate.\n"
285298
"--wait, -w - wait before repeat power off [%d ms].\n"
@@ -1099,6 +1112,11 @@ int main(int argc, char *argv[])
10991112
int rc;
11001113
int c = 0;
11011114
int option_index = 0;
1115+
#if defined(LIBUSB_API_VERSION) && (LIBUSB_API_VERSION >= 0x01000107) && \
1116+
(defined(__gnu_linux__) || defined(__linux__))
1117+
int sys_fd;
1118+
libusb_device_handle *sys_devh = NULL;
1119+
#endif
11021120

11031121
for (;;) {
11041122
c = getopt_long(argc, argv, short_options, long_options, &option_index);
@@ -1167,6 +1185,11 @@ int main(int argc, char *argv[])
11671185
case 'S':
11681186
opt_nosysfs = 1;
11691187
break;
1188+
#if defined(LIBUSB_API_VERSION) && (LIBUSB_API_VERSION >= 0x01000107)
1189+
case 'y':
1190+
opt_sysdev = optarg;
1191+
break;
1192+
#endif
11701193
#endif
11711194
case 'e':
11721195
opt_exact = 1;
@@ -1209,7 +1232,36 @@ int main(int argc, char *argv[])
12091232
exit(1);
12101233
}
12111234

1235+
#if defined(LIBUSB_API_VERSION) && (LIBUSB_API_VERSION >= 0x01000107) && \
1236+
(defined(__gnu_linux__) || defined(__linux__))
1237+
if (opt_sysdev) {
1238+
sys_fd = open(opt_sysdev, O_RDWR);
1239+
if (sys_fd < 0) {
1240+
fprintf(stderr, "Cannot open system node!\n");
1241+
rc = 1;
1242+
goto cleanup;
1243+
}
1244+
rc = libusb_wrap_sys_device(NULL, sys_fd, &sys_devh);
1245+
if (rc != 0) {
1246+
fprintf(stderr,
1247+
"Cannot use %s as USB hub device, failed to wrap system node!\n",
1248+
opt_sysdev);
1249+
rc = 1;
1250+
goto cleanup;
1251+
}
1252+
usb_devs = calloc(2, sizeof *usb_devs);
1253+
if (!usb_devs) {
1254+
fprintf(stderr, "Out of memory\n");
1255+
rc = 1;
1256+
goto cleanup;
1257+
}
1258+
usb_devs[0] = libusb_get_device(sys_devh);
1259+
} else {
1260+
rc = libusb_get_device_list(NULL, &usb_devs);
1261+
}
1262+
#else
12121263
rc = libusb_get_device_list(NULL, &usb_devs);
1264+
#endif
12131265
if (rc < 0) {
12141266
fprintf(stderr,
12151267
"Cannot enumerate USB devices!\n"
@@ -1315,8 +1367,19 @@ int main(int argc, char *argv[])
13151367
}
13161368
rc = 0;
13171369
cleanup:
1370+
#if defined(LIBUSB_API_VERSION) && (LIBUSB_API_VERSION >= 0x01000107) && \
1371+
(defined(__gnu_linux__) || defined(__linux__))
1372+
if (opt_sysdev && sys_fd >= 0) {
1373+
if (sys_devh)
1374+
libusb_close(sys_devh);
1375+
close(sys_fd);
1376+
free(usb_devs);
1377+
} else if (usb_devs)
1378+
libusb_free_device_list(usb_devs, 1);
1379+
#else
13181380
if (usb_devs)
13191381
libusb_free_device_list(usb_devs, 1);
1382+
#endif
13201383
usb_devs = NULL;
13211384
libusb_exit(NULL);
13221385
return rc;

0 commit comments

Comments
 (0)