[PATCH] librtlsdr: Allow device specification with an USB path

Alexander Motzkau a.motzkau at web.de
Sat Jun 20 21:45:21 UTC 2020


I'm using a Raspberry with two similar devices but different antennas.
Specifying the device via index didn't work, because the enumeration of
devices changed from time to time. Therefore I implemented functions to
give a USB path instead. This path looks the same as the Linux kernel
uses (eg. "4-1.2") and contains the USB bus and port numbers.

I'll hope you'll find my patch acceptable.

Best Regards,
Alex


Add functions to query devices via path, and path from a device.
The path is formatted similar to Linux USB device names (bus number,
hyphen, ports separated by dots, eg. "4-1.2").
---
 include/rtl-sdr.h             |  25 +++++++
 src/convenience/convenience.c |  10 +++
 src/librtlsdr.c               | 121 ++++++++++++++++++++++++++++++++++
 3 files changed, 156 insertions(+)

diff --git a/include/rtl-sdr.h b/include/rtl-sdr.h
index d64701e..e6ce33a 100644
--- a/include/rtl-sdr.h
+++ b/include/rtl-sdr.h
@@ -49,6 +49,31 @@ RTLSDR_API int rtlsdr_get_device_usb_strings(uint32_t index,
 					     char *product,
 					     char *serial);

+/*!
+ * Get device index by USB path string.
+ *
+ * The path string has the format "bus-port.port..."
+ * (i.e. the bus number, followed by a hyphen, then
+ * followed by the port numbers separated by dots).
+ *
+ * \param path path string of the device
+ * \return device index of the device with the given path
+ * \return -1 if no matching device was found.
+ */
+RTLSDR_API int rtlsdr_get_index_by_path(const char *path);
+
+/*!
+ * Get the USB path.
+ *
+ * NOTE: The buffer should provide space for at least 32 bytes.
+ *
+ * \param index the device index
+ * \param buf buffer where the path will be written
+ * \param len size of the buffer
+ * \return 0 on success
+ */
+RTLSDR_API int rtlsdr_get_device_path(uint32_t index, char *buf, size_t len);
+
 /*!
  * Get device index by USB serial string descriptor.
  *
diff --git a/src/convenience/convenience.c b/src/convenience/convenience.c
index 00cc2cc..55f82e2 100644
--- a/src/convenience/convenience.c
+++ b/src/convenience/convenience.c
@@ -268,6 +268,16 @@ int verbose_device_search(char *s)
 			device, rtlsdr_get_device_name((uint32_t)device));
 		return device;
 	}
+	/* does string match a path */
+	if (s2[0] == '-') {
+		i = rtlsdr_get_index_by_path(s);
+		if (i >= 0) {
+			device = i;
+			fprintf(stderr, "Using device %d: %s\n",
+				device, rtlsdr_get_device_name((uint32_t)device));
+			return device;
+		}
+	}
 	/* does string exact match a serial */
 	for (i = 0; i < device_count; i++) {
 		rtlsdr_get_device_usb_strings(i, vendor, product, serial);
diff --git a/src/librtlsdr.c b/src/librtlsdr.c
index 0146298..e3f03d7 100644
--- a/src/librtlsdr.c
+++ b/src/librtlsdr.c
@@ -1414,6 +1414,127 @@ int rtlsdr_get_device_usb_strings(uint32_t index, char *manufact,
 	return r;
 }

+static void get_device_path(libusb_device *dev, char *buf, size_t len)
+{
+	uint8_t port_numbers[16];
+	int port_entries;
+	int i, count;
+
+	count = snprintf(buf, len, "%d-", (int)libusb_get_bus_number(dev));
+	if (count < 0) {
+		buf[0] = 0;
+		return;
+	}
+	else if ((size_t)count >= len) {
+		buf[len-1] = 0;
+		return;
+	}
+
+	len -= count;
+	buf += count;
+
+	port_entries = libusb_get_port_numbers(dev, port_numbers, sizeof(port_numbers)/sizeof(port_numbers[0]));
+	if (port_entries < 0)
+		return;
+
+	for (i = 0; i < port_entries; i++) {
+		count = snprintf(buf, len, i ? ".%d" : "%d", (int) port_numbers[i]);
+
+		if (count < 0) {
+			buf[0] = 0;
+			break;
+		}
+		else if ((size_t)count >= len) {
+			buf[len-1] = 0;
+			break;
+		}
+
+		len -= count;
+		buf += count;
+	}
+
+	if (!port_entries && len > 1) {
+		buf[0] = '0';
+		buf[1] = 0;
+	}
+}
+
+int rtlsdr_get_index_by_path(const char *path)
+{
+	libusb_context *ctx;
+	libusb_device **list;
+	struct libusb_device_descriptor dd;
+	ssize_t cnt;
+	int i,r,pos;
+
+	r = libusb_init(&ctx);
+
+	if(r < 0)
+		return -1;
+
+	cnt = libusb_get_device_list(ctx, &list);
+
+	pos = 0;
+	for (i = 0; i < cnt; i++) {
+		libusb_get_device_descriptor(list[i], &dd);
+
+		if (find_known_device(dd.idVendor, dd.idProduct)) {
+			char buf[64];
+			get_device_path(list[i], buf, sizeof(buf));
+
+			if (!strncmp(path, buf, sizeof(buf))) {
+				libusb_free_device_list(list, 1);
+				libusb_exit(ctx);
+
+				return pos;
+			}
+
+			pos++;
+		}
+	}
+
+	libusb_free_device_list(list, 1);
+	libusb_exit(ctx);
+
+	return -1;
+}
+
+int rtlsdr_get_device_path(uint32_t index, char *buf, size_t len)
+{
+	libusb_context *ctx;
+	libusb_device **list;
+	struct libusb_device_descriptor dd;
+	int i,r;
+	uint32_t device_count = 0;
+	ssize_t cnt;
+
+	r = libusb_init(&ctx);
+	if(r < 0)
+		return r;
+
+	cnt = libusb_get_device_list(ctx, &list);
+
+	r = LIBUSB_ERROR_NO_DEVICE;
+	for (i = 0; i < cnt; i++) {
+		libusb_get_device_descriptor(list[i], &dd);
+
+		if (find_known_device(dd.idVendor, dd.idProduct)) {
+			device_count++;
+
+			if (index == device_count - 1) {
+				get_device_path(list[i], buf, len);
+				r = 0;
+				break;
+			}
+		}
+	}
+
+	libusb_free_device_list(list, 1);
+	libusb_exit(ctx);
+
+	return r;
+}
+
 int rtlsdr_get_index_by_serial(const char *serial)
 {
 	int i, cnt, r;
--
2.20.1



More information about the osmocom-sdr mailing list