Skip to content

Commit 8e5dbaf

Browse files
committed
dcttech-usbrelay: support conn=vid.pid specs in addition to paths
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.
1 parent 0498ef4 commit 8e5dbaf

File tree

2 files changed

+54
-15
lines changed

2 files changed

+54
-15
lines changed

src/hardware/dcttech-usbrelay/api.c

Lines changed: 53 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ static const uint32_t devopts_cg[] = {
4545
static struct sr_dev_driver dcttech_usbrelay_driver_info;
4646

4747
static struct sr_dev_inst *probe_device_common(const char *path,
48+
uint16_t vid, uint16_t pid,
4849
const wchar_t *vendor, const wchar_t *product)
4950
{
5051
char nonws[16], *s, *endp;
@@ -80,7 +81,10 @@ static struct sr_dev_inst *probe_device_common(const char *path,
8081
sr_info("Relay count %lu from product string %s.", relay_count, nonws);
8182

8283
/* Open device, need to communicate to identify. */
83-
hid = hid_open_path(path);
84+
if (vid && pid)
85+
hid = hid_open(vid, pid, NULL);
86+
else
87+
hid = hid_open_path(path);
8488
if (!hid) {
8589
sr_err("Cannot open %s.", path);
8690
return NULL;
@@ -137,6 +141,8 @@ static struct sr_dev_inst *probe_device_common(const char *path,
137141
devc = g_malloc0(sizeof(*devc));
138142
sdi->priv = devc;
139143
devc->hid_path = g_strdup(path);
144+
devc->usb_vid = vid;
145+
devc->usb_pid = pid;
140146
devc->relay_count = relay_count;
141147
devc->relay_mask = (1U << relay_count) - 1;
142148
for (idx = 0; idx < devc->relay_count; idx++) {
@@ -154,33 +160,62 @@ static struct sr_dev_inst *probe_device_common(const char *path,
154160

155161
static struct sr_dev_inst *probe_device_enum(struct hid_device_info *dev)
156162
{
157-
return probe_device_common(dev->path,
163+
return probe_device_common(dev->path, 0, 0,
158164
dev->manufacturer_string, dev->product_string);
159165
}
160166

161-
static struct sr_dev_inst *probe_device_path(const char *path)
167+
static struct sr_dev_inst *probe_device_conn(const char *path)
162168
{
169+
char vid_pid[12];
170+
uint16_t vid, pid;
171+
const char *s;
172+
char *endp;
173+
unsigned long num;
163174
hid_device *dev;
164175
gboolean ok;
165176
int ret;
166177
wchar_t vendor[32], product[32];
167178

168179
/*
169-
* TODO Accept different types of conn= specs? Either paths that
170-
* hidapi(3) can open. Or bus.addr specs that we can check for
171-
* during USB enumeration and derive a hidapi(3) compatible path
172-
* from? Is some "unescaping" desirable for platforms which have
173-
* colons in hidapi(3) paths that collide with how conn= specs
174-
* are passed in sigrok? This would be the place to translate
175-
* the 'path' to a canonical format.
180+
* The hidapi(3) library's API strives for maximum portability,
181+
* thus won't provide ways of getting a path from alternative
182+
* presentations like VID:PID pairs, bus.addr specs, etc. The
183+
* typical V-USB setup neither provides reliable serial numbers
184+
* (that USB enumeration would cover). So this driver's support
185+
* for conn= specs beyond Unix style path names is limited, too.
186+
* This implementation tries "VID.PID" then assumes "path". The
187+
* inability to even get the path for a successfully opened HID
188+
* results in redundancy across the places which open devices.
176189
*/
177190

178-
dev = hid_open_path(path);
191+
/* Check for "<vid>.<pid>" specs. */
192+
vid = pid = 0;
193+
s = path;
194+
ret = sr_atoul_base(s, &num, &endp, 16);
195+
if (ret == SR_OK && endp && endp == s + 4 && *endp == '.' && num) {
196+
vid = num;
197+
s = ++endp;
198+
}
199+
ret = sr_atoul_base(s, &num, &endp, 16);
200+
if (ret == SR_OK && endp && endp == s + 4 && *endp == '\0' && num) {
201+
pid = num;
202+
s = ++endp;
203+
}
204+
if (vid && pid) {
205+
snprintf(vid_pid, sizeof(vid_pid), "%04x.%04x", vid, pid);
206+
path = vid_pid;
207+
sr_dbg("Using VID.PID %s.", path);
208+
}
209+
210+
/* Open the device, get vendor and product strings. */
211+
if (vid && pid)
212+
dev = hid_open(vid, pid, NULL);
213+
else
214+
dev = hid_open_path(path);
179215
if (!dev) {
180216
sr_err("Cannot open %s.", path);
181217
return NULL;
182218
}
183-
184219
ok = TRUE;
185220
ret = hid_get_manufacturer_string(dev, vendor, ARRAY_SIZE(vendor));
186221
if (ret != 0)
@@ -196,7 +231,7 @@ static struct sr_dev_inst *probe_device_path(const char *path)
196231
if (!ok)
197232
return NULL;
198233

199-
return probe_device_common(path, vendor, product);
234+
return probe_device_common(path, vid, pid, vendor, product);
200235
}
201236

202237
static GSList *scan(struct sr_dev_driver *di, GSList *options)
@@ -232,7 +267,7 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options)
232267
*/
233268
if (conn) {
234269
sr_info("Checking HID path %s.", conn);
235-
sdi = probe_device_path(conn);
270+
sdi = probe_device_conn(conn);
236271
if (!sdi)
237272
sr_warn("Failed to communicate to %s.", conn);
238273
else
@@ -291,7 +326,10 @@ static int dev_open(struct sr_dev_inst *sdi)
291326
devc->hid_dev = NULL;
292327
}
293328

294-
devc->hid_dev = hid_open_path(devc->hid_path);
329+
if (devc->usb_vid && devc->usb_pid)
330+
devc->hid_dev = hid_open(devc->usb_vid, devc->usb_pid, NULL);
331+
else
332+
devc->hid_dev = hid_open_path(devc->hid_path);
295333
if (!devc->hid_dev)
296334
return SR_ERR_IO;
297335

src/hardware/dcttech-usbrelay/protocol.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343

4444
struct dev_context {
4545
char *hid_path;
46+
uint16_t usb_vid, usb_pid;
4647
hid_device *hid_dev;
4748
size_t relay_count;
4849
uint32_t relay_mask;

0 commit comments

Comments
 (0)