]> sigrok.org Git - libsigrok.git/commitdiff
usb: move connection string parsing out of USB enumeration/search
authorGerhard Sittig <redacted>
Tue, 18 Jun 2019 16:36:29 +0000 (18:36 +0200)
committerGerhard Sittig <redacted>
Sun, 21 Aug 2022 15:45:11 +0000 (17:45 +0200)
The sr_usb_find() routine inspects an input specification in textual
format, as well as scans for USB devices that match the caller specified
address. Factor out the text parsing including range checks for address
numbers. This part of the source code also does not depend on the libusb
library's availability.

Adjust the sr_usb_find() routine's data types for result variables. This
commit changes user visible diagnostics messages, since text parsing and
USB device lookup happen in distinct locations and don't share knowledge.

src/libsigrok-internal.h
src/usb.c

index db74dcc27e515f04b364c9425b9c5b48a5cb7f9a..e1cae55993cf67501e9466342752f751866992b5 100644 (file)
@@ -2126,6 +2126,8 @@ SR_PRIV int ezusb_upload_firmware(struct sr_context *ctx, libusb_device *dev,
 
 /*--- usb.c -----------------------------------------------------------------*/
 
+SR_PRIV int sr_usb_split_conn(const char *conn,
+       uint16_t *vid, uint16_t *pid, uint8_t *bus, uint8_t *addr);
 #ifdef HAVE_LIBUSB_1_0
 SR_PRIV GSList *sr_usb_find(libusb_context *usb_ctx, const char *conn);
 SR_PRIV int sr_usb_open(libusb_context *usb_ctx, struct sr_usb_dev_inst *usb);
index 6bd9e8182960cc330164350ccc4f37facd8a7aea..feafe9d2a2ae0aefbb4389638f9e7676a643ba9f 100644 (file)
--- a/src/usb.c
+++ b/src/usb.c
@@ -297,68 +297,116 @@ static GSource *usb_source_new(struct sr_session *session,
 }
 
 /**
- * Find USB devices according to a connection string.
+ * Extract VID:PID or bus.addr from a connection string.
  *
- * @param usb_ctx libusb context to use while scanning.
- * @param conn Connection string specifying the device(s) to match. This
- * can be of the form "<bus>.<address>", or "<vendorid>.<productid>".
+ * @param[in] conn Connection string.
+ * @param[out] vid Pointer to extracted vendor ID. Can be #NULL.
+ * @param[out] pid Pointer to extracted product ID. Can be #NULL.
+ * @param[out] bus Pointer to extracted bus number. Can be #NULL.
+ * @param[out] addr Pointer to extracted device number. Can be #NULL.
  *
- * @return A GSList of struct sr_usb_dev_inst, with bus and address fields
- * matching the device that matched the connection string. The GSList and
- * its contents must be freed by the caller.
+ * @return SR_OK when parsing succeeded, SR_ERR* otherwise.
+ *
+ * @private
+ *
+ * The routine fills in the result variables, and returns the scan success
+ * in the return code. Callers can specify #NULL for variable references
+ * if they are not interested in specific aspects of the USB address.
  */
-SR_PRIV GSList *sr_usb_find(libusb_context *usb_ctx, const char *conn)
+SR_PRIV int sr_usb_split_conn(const char *conn,
+       uint16_t *vid, uint16_t *pid, uint8_t *bus, uint8_t *addr)
 {
-       struct sr_usb_dev_inst *usb;
-       struct libusb_device **devlist;
-       struct libusb_device_descriptor des;
-       GSList *devices;
+       gboolean valid;
        GRegex *reg;
        GMatchInfo *match;
-       int vid, pid, bus, addr, b, a, ret, i;
        char *mstr;
+       uint32_t num;
+
+       if (vid) *vid = 0;
+       if (pid) *pid = 0;
+       if (bus) *bus = 0;
+       if (addr) *addr = 0;
 
-       vid = pid = bus = addr = 0;
+       valid = TRUE;
        reg = g_regex_new(CONN_USB_VIDPID, 0, 0, NULL);
        if (g_regex_match(reg, conn, 0, &match)) {
-               if ((mstr = g_match_info_fetch(match, 1)))
-                       vid = strtoul(mstr, NULL, 16);
+               /* Found a VID:PID style pattern. */
+               if ((mstr = g_match_info_fetch(match, 1))) {
+                       num = strtoul(mstr, NULL, 16);
+                       if (num > 0xffff)
+                               valid = FALSE;
+                       if (vid)
+                               *vid = num & 0xffff;
+               }
                g_free(mstr);
 
-               if ((mstr = g_match_info_fetch(match, 2)))
-                       pid = strtoul(mstr, NULL, 16);
+               if ((mstr = g_match_info_fetch(match, 2))) {
+                       num = strtoul(mstr, NULL, 16);
+                       if (num > 0xffff)
+                               valid = FALSE;
+                       if (pid)
+                               *pid = num & 0xffff;
+               }
                g_free(mstr);
-               /* Trying to find USB device via VID:PID. */
        } else {
                g_match_info_unref(match);
                g_regex_unref(reg);
                reg = g_regex_new(CONN_USB_BUSADDR, 0, 0, NULL);
                if (g_regex_match(reg, conn, 0, &match)) {
-                       if ((mstr = g_match_info_fetch(match, 1)))
-                               bus = strtoul(mstr, NULL, 10);
+                       /* Found a bus.address style pattern. */
+                       if ((mstr = g_match_info_fetch(match, 1))) {
+                               num = strtoul(mstr, NULL, 10);
+                               if (num > 255)
+                                       valid = FALSE;
+                               if (bus)
+                                       *bus = num & 0xff;
+                       }
                        g_free(mstr);
 
-                       if ((mstr = g_match_info_fetch(match, 2)))
-                               addr = strtoul(mstr, NULL, 10);
+                       if ((mstr = g_match_info_fetch(match, 2))) {
+                               num = strtoul(mstr, NULL, 10);
+                               if (num > 127)
+                                       valid = FALSE;
+                               if (addr)
+                                       *addr = num & 0x7f;
+                       }
                        g_free(mstr);
-                       /* Trying to find USB device via bus.address. */
                }
        }
        g_match_info_unref(match);
        g_regex_unref(reg);
 
-       if (vid + pid + bus + addr == 0) {
-               sr_err("Neither VID:PID nor bus.address was specified.");
-               return NULL;
-       }
+       return valid ? SR_OK : SR_ERR_ARG;
+}
 
-       if (bus > 255) {
-               sr_err("Invalid bus specified: %d.", bus);
+/**
+ * Find USB devices according to a connection string.
+ *
+ * @param usb_ctx libusb context to use while scanning.
+ * @param conn Connection string specifying the device(s) to match. This
+ * can be of the form "<bus>.<address>", or "<vendorid>.<productid>".
+ *
+ * @return A GSList of struct sr_usb_dev_inst, with bus and address fields
+ * matching the device that matched the connection string. The GSList and
+ * its contents must be freed by the caller.
+ */
+SR_PRIV GSList *sr_usb_find(libusb_context *usb_ctx, const char *conn)
+{
+       struct sr_usb_dev_inst *usb;
+       struct libusb_device **devlist;
+       struct libusb_device_descriptor des;
+       GSList *devices;
+       uint16_t vid, pid;
+       uint8_t bus, addr;
+       int b, a, ret, i;
+
+       ret = sr_usb_split_conn(conn, &vid, &pid, &bus, &addr);
+       if (ret != SR_OK) {
+               sr_err("Invalid input, or neither VID:PID nor bus.address specified.");
                return NULL;
        }
-
-       if (addr > 127) {
-               sr_err("Invalid address specified: %d.", addr);
+       if (!(vid && pid) && !(bus && addr)) {
+               sr_err("Could neither determine VID:PID nor bus.address numbers.");
                return NULL;
        }
 
@@ -372,12 +420,12 @@ SR_PRIV GSList *sr_usb_find(libusb_context *usb_ctx, const char *conn)
                        continue;
                }
 
-               if (vid + pid && (des.idVendor != vid || des.idProduct != pid))
+               if (vid && pid && (des.idVendor != vid || des.idProduct != pid))
                        continue;
 
                b = libusb_get_bus_number(devlist[i]);
                a = libusb_get_device_address(devlist[i]);
-               if (bus + addr && (b != bus || a != addr))
+               if (bus && addr && (b != bus || a != addr))
                        continue;
 
                sr_dbg("Found USB device (VID:PID = %04x:%04x, bus.address = "