#include <config.h>
#include "protocol.h"
+#define SCAN_EXPECTED_VENDOR 0x0403
+
static const uint32_t scanopts[] = {
SR_CONF_CONN,
};
static GSList *scan(struct sr_dev_driver *di, GSList *options)
{
- int i, ret, model;
struct drv_context *drvc;
- GSList *devices, *conn_devices, *l;
+ GSList *devices;
+ const char *conn;
+ int ret;
+ GSList *conn_devices, *l;
+ size_t i;
struct sr_usb_dev_inst *usb;
- struct sr_config *src;
+ uint8_t bus, addr;
struct libusb_device_descriptor des;
libusb_device **devlist;
struct libusb_device_handle *hdl;
- const char *conn;
char product[64], serial_num[64], connection_id[64];
+ int model;
drvc = di->context;
+ devices = NULL;
conn = NULL;
- for (l = options; l; l = l->next) {
- src = l->data;
- switch (src->key) {
- case SR_CONF_CONN:
- conn = g_variant_get_string(src->data, NULL);
- break;
- }
- }
+ (void)sr_serial_extract_options(options, &conn, NULL);
+ conn_devices = NULL;
if (conn)
conn_devices = sr_usb_find(drvc->sr_ctx->libusb_ctx, conn);
- else
- conn_devices = NULL;
- devices = NULL;
libusb_get_device_list(drvc->sr_ctx->libusb_ctx, &devlist);
-
for (i = 0; devlist[i]; i++) {
+ bus = libusb_get_bus_number(devlist[i]);
+ addr = libusb_get_device_address(devlist[i]);
if (conn) {
+ /* Check if the connection matches the user spec. */
for (l = conn_devices; l; l = l->next) {
usb = l->data;
- if (usb->bus == libusb_get_bus_number(devlist[i])
- && usb->address == libusb_get_device_address(devlist[i]))
+ if (usb->bus == bus && usb->address == addr)
break;
}
if (!l)
- /* This device matched none of the ones that
- * matched the conn specification. */
continue;
}
libusb_get_device_descriptor(devlist[i], &des);
+ /*
+ * In theory we'd accept any USB device with a matching
+ * product string. In practice the enumeration takes a
+ * shortcut and only inspects devices when their USB VID
+ * matches the expectation. This avoids access to flaky
+ * devices which are unrelated to measurement purposes
+ * yet cause trouble when accessed including segfaults,
+ * while libusb won't transparently handle their flaws.
+ *
+ * See https://sigrok.org/bugzilla/show_bug.cgi?id=1115
+ * and https://github.com/sigrokproject/libsigrok/pull/166
+ * for a discussion.
+ */
+ if (des.idVendor != SCAN_EXPECTED_VENDOR)
+ continue;
+
if ((ret = libusb_open(devlist[i], &hdl)) < 0)
continue;
continue;
}
- usb_get_port_path(devlist[i], connection_id, sizeof(connection_id));
-
libusb_close(hdl);
- if (!strcmp(product, "ChronoVu LA8")) {
+ if (usb_get_port_path(devlist[i], connection_id, sizeof(connection_id)) < 0)
+ continue;
+
+ if (!strcmp(product, "ChronoVu LA8"))
model = 0;
- } else if (!strcmp(product, "ChronoVu LA16")) {
+ else if (!strcmp(product, "ChronoVu LA16"))
model = 1;
- } else {
- sr_spew("Unknown iProduct string '%s'.", product);
- continue;
- }
+ else
+ continue; /* Unknown iProduct string, ignore. */
sr_dbg("Found %s (%04x:%04x, %d.%d, %s).",
product, des.idVendor, des.idProduct,
sr_dbg("Failed to add device: %d.", ret);
}
}
-
libusb_free_device_list(devlist, 1);
g_slist_free_full(conn_devices, (GDestroyNotify)sr_usb_dev_inst_free);
goto err_ftdi_free;
}
- if ((ret = ftdi_usb_purge_buffers(devc->ftdic)) < 0) {
+ if ((ret = PURGE_FTDI_BOTH(devc->ftdic)) < 0) {
sr_err("Failed to purge FTDI buffers (%d): %s.",
ret, ftdi_get_error_string(devc->ftdic));
goto err_ftdi_free;
{
struct dev_context *devc;
struct sr_usb_dev_inst *usb;
- char str[128];
(void)cg;
case SR_CONF_CONN:
if (!sdi || !(usb = sdi->conn))
return SR_ERR_ARG;
- snprintf(str, 128, "%d.%d", usb->bus, usb->address);
- *data = g_variant_new_string(str);
+ *data = g_variant_new_printf("%d.%d", usb->bus, usb->address);
break;
case SR_CONF_SAMPLERATE:
if (!sdi)
return SR_ERR;
break;
case SR_CONF_LIMIT_MSEC:
- if (g_variant_get_uint64(data) == 0)
- return SR_ERR_ARG;
devc->limit_msec = g_variant_get_uint64(data);
break;
case SR_CONF_LIMIT_SAMPLES:
- if (g_variant_get_uint64(data) == 0)
- return SR_ERR_ARG;
devc->limit_samples = g_variant_get_uint64(data);
break;
default:
static int config_list(uint32_t key, GVariant **data,
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
{
- GVariant *grange[2];
struct dev_context *devc;
devc = (sdi) ? sdi->priv : NULL;
*data = std_gvar_samplerates(ARRAY_AND_SIZE(devc->samplerates));
break;
case SR_CONF_LIMIT_SAMPLES:
- if (!devc->prof)
+ if (!devc || !devc->prof)
return SR_ERR_BUG;
- grange[0] = g_variant_new_uint64(0);
- if (devc->prof->model == CHRONOVU_LA8)
- grange[1] = g_variant_new_uint64(MAX_NUM_SAMPLES);
- else
- grange[1] = g_variant_new_uint64(MAX_NUM_SAMPLES / 2);
- *data = g_variant_new_tuple(grange, 2);
+ *data = std_gvar_tuple_u64(0, (devc->prof->model == CHRONOVU_LA8) ? MAX_NUM_SAMPLES : MAX_NUM_SAMPLES / 2);
break;
case SR_CONF_TRIGGER_MATCH:
- if (!devc->prof)
+ if (!devc || !devc->prof)
return SR_ERR_BUG;
*data = std_gvar_array_i32(trigger_matches, devc->prof->num_trigger_matches);
break;