dcttech-usbrelay: support conn=vid.pid specs in addition to paths
authorGerhard Sittig <gerhard.sittig@gmx.net>
Fri, 23 Jul 2021 17:50:45 +0000 (19:50 +0200)
committerGerhard Sittig <gerhard.sittig@gmx.net>
Fri, 23 Jul 2021 17:58:46 +0000 (19:58 +0200)
Extend the scan code path, accept user provided conn= specs in the
"vid.pid" format. Everything else is assumed to be a hidapi compatible
"path" and may suffer from conn= parser limitations. Unfortunately the
hidapi API won't let us lookup paths from bus.addr specs which would
work when multiple cards need to be told apart.

src/hardware/dcttech-usbrelay/api.c
src/hardware/dcttech-usbrelay/protocol.h

index 38d2512fcaeaf47b99ddd633317747ff450753fb..a24025ec84376878d17c778bb4808f4fd622547a 100644 (file)
@@ -45,6 +45,7 @@ static const uint32_t devopts_cg[] = {
 static struct sr_dev_driver dcttech_usbrelay_driver_info;
 
 static struct sr_dev_inst *probe_device_common(const char *path,
+       uint16_t vid, uint16_t pid,
        const wchar_t *vendor, const wchar_t *product)
 {
        char nonws[16], *s, *endp;
@@ -80,7 +81,10 @@ static struct sr_dev_inst *probe_device_common(const char *path,
        sr_info("Relay count %lu from product string %s.", relay_count, nonws);
 
        /* Open device, need to communicate to identify. */
-       hid = hid_open_path(path);
+       if (vid && pid)
+               hid = hid_open(vid, pid, NULL);
+       else
+               hid = hid_open_path(path);
        if (!hid) {
                sr_err("Cannot open %s.", path);
                return NULL;
@@ -137,6 +141,8 @@ static struct sr_dev_inst *probe_device_common(const char *path,
        devc = g_malloc0(sizeof(*devc));
        sdi->priv = devc;
        devc->hid_path = g_strdup(path);
+       devc->usb_vid = vid;
+       devc->usb_pid = pid;
        devc->relay_count = relay_count;
        devc->relay_mask = (1U << relay_count) - 1;
        for (idx = 0; idx < devc->relay_count; idx++) {
@@ -154,33 +160,62 @@ static struct sr_dev_inst *probe_device_common(const char *path,
 
 static struct sr_dev_inst *probe_device_enum(struct hid_device_info *dev)
 {
-       return probe_device_common(dev->path,
+       return probe_device_common(dev->path, 0, 0,
                dev->manufacturer_string, dev->product_string);
 }
 
-static struct sr_dev_inst *probe_device_path(const char *path)
+static struct sr_dev_inst *probe_device_conn(const char *path)
 {
+       char vid_pid[12];
+       uint16_t vid, pid;
+       const char *s;
+       char *endp;
+       unsigned long num;
        hid_device *dev;
        gboolean ok;
        int ret;
        wchar_t vendor[32], product[32];
 
        /*
-        * TODO Accept different types of conn= specs? Either paths that
-        * hidapi(3) can open. Or bus.addr specs that we can check for
-        * during USB enumeration and derive a hidapi(3) compatible path
-        * from? Is some "unescaping" desirable for platforms which have
-        * colons in hidapi(3) paths that collide with how conn= specs
-        * are passed in sigrok? This would be the place to translate
-        * the 'path' to a canonical format.
+        * The hidapi(3) library's API strives for maximum portability,
+        * thus won't provide ways of getting a path from alternative
+        * presentations like VID:PID pairs, bus.addr specs, etc. The
+        * typical V-USB setup neither provides reliable serial numbers
+        * (that USB enumeration would cover). So this driver's support
+        * for conn= specs beyond Unix style path names is limited, too.
+        * This implementation tries "VID.PID" then assumes "path". The
+        * inability to even get the path for a successfully opened HID
+        * results in redundancy across the places which open devices.
         */
 
-       dev = hid_open_path(path);
+       /* Check for "<vid>.<pid>" specs. */
+       vid = pid = 0;
+       s = path;
+       ret = sr_atoul_base(s, &num, &endp, 16);
+       if (ret == SR_OK && endp && endp == s + 4 && *endp == '.' && num) {
+               vid = num;
+               s = ++endp;
+       }
+       ret = sr_atoul_base(s, &num, &endp, 16);
+       if (ret == SR_OK && endp && endp == s + 4 && *endp == '\0' && num) {
+               pid = num;
+               s = ++endp;
+       }
+       if (vid && pid) {
+               snprintf(vid_pid, sizeof(vid_pid), "%04x.%04x", vid, pid);
+               path = vid_pid;
+               sr_dbg("Using VID.PID %s.", path);
+       }
+
+       /* Open the device, get vendor and product strings. */
+       if (vid && pid)
+               dev = hid_open(vid, pid, NULL);
+       else
+               dev = hid_open_path(path);
        if (!dev) {
                sr_err("Cannot open %s.", path);
                return NULL;
        }
-
        ok = TRUE;
        ret = hid_get_manufacturer_string(dev, vendor, ARRAY_SIZE(vendor));
        if (ret != 0)
@@ -196,7 +231,7 @@ static struct sr_dev_inst *probe_device_path(const char *path)
        if (!ok)
                return NULL;
 
-       return probe_device_common(path, vendor, product);
+       return probe_device_common(path, vid, pid, vendor, product);
 }
 
 static GSList *scan(struct sr_dev_driver *di, GSList *options)
@@ -232,7 +267,7 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options)
         */
        if (conn) {
                sr_info("Checking HID path %s.", conn);
-               sdi = probe_device_path(conn);
+               sdi = probe_device_conn(conn);
                if (!sdi)
                        sr_warn("Failed to communicate to %s.", conn);
                else
@@ -291,7 +326,10 @@ static int dev_open(struct sr_dev_inst *sdi)
                devc->hid_dev = NULL;
        }
 
-       devc->hid_dev = hid_open_path(devc->hid_path);
+       if (devc->usb_vid && devc->usb_pid)
+               devc->hid_dev = hid_open(devc->usb_vid, devc->usb_pid, NULL);
+       else
+               devc->hid_dev = hid_open_path(devc->hid_path);
        if (!devc->hid_dev)
                return SR_ERR_IO;
 
index 45b8ec4bfca0ec7556ffdc6e24e7c53eb9b087bf..9e3d86df115534e80f9e13ebf70e0cd67492c046 100644 (file)
@@ -43,6 +43,7 @@
 
 struct dev_context {
        char *hid_path;
+       uint16_t usb_vid, usb_pid;
        hid_device *hid_dev;
        size_t relay_count;
        uint32_t relay_mask;