#include <stdlib.h>
#include <string.h>
#include <libsigrok/libsigrok.h>
-#include "libsigrok-internal.h"
+#include <libsigrok-internal.h>
#include "protocol.h"
/* Supported device scan options.
const struct model_info *model;
struct sr_dev_inst *sdi;
struct libusb_device_descriptor des;
- int bus, address;
+ int bus, address, ret;
unsigned int vid, pid;
- int ret;
bus = libusb_get_bus_number(dev);
address = libusb_get_device_address(dev);
*/
static GSList *dev_list(const struct sr_dev_driver *di)
{
- struct drv_context *drvc;
-
- drvc = di->context;
-
- return drvc->instances;
+ return ((struct drv_context *)(di->context))->instances;
}
/* Destroy the private device context.
if (devc->acquisition) {
sr_err("Cannot clear device context during acquisition!");
- return; /* leak and pray */
+ return; /* Leak and pray. */
}
sr_dbg("Device context cleared.");
return std_dev_clear(di, &clear_dev_context);
}
+/* Drain any pending data from the USB transfer buffers on the device.
+ * This may be necessary e.g. after a crash or generally to clean up after
+ * an abnormal condition.
+ */
+static int drain_usb(struct sr_usb_dev_inst *usb, unsigned int endpoint)
+{
+ int drained, xfer_len, ret;
+ unsigned char buf[512];
+ const unsigned int drain_timeout_ms = 10;
+
+ drained = 0;
+ do {
+ xfer_len = 0;
+ ret = libusb_bulk_transfer(usb->devhdl, endpoint,
+ buf, sizeof(buf), &xfer_len,
+ drain_timeout_ms);
+ drained += xfer_len;
+ } while (ret == LIBUSB_SUCCESS && xfer_len != 0);
+
+ if (ret != LIBUSB_SUCCESS && ret != LIBUSB_ERROR_TIMEOUT) {
+ sr_err("Failed to drain USB endpoint %u: %s.",
+ endpoint & (LIBUSB_ENDPOINT_IN - 1),
+ libusb_error_name(ret));
+ return SR_ERR;
+ }
+ if (drained > 0) {
+ sr_warn("Drained %d bytes from USB endpoint %u.",
+ drained, endpoint & (LIBUSB_ENDPOINT_IN - 1));
+ }
+
+ return SR_OK;
+}
+
/* Open and initialize device.
*/
static int dev_open(struct sr_dev_inst *sdi)
struct drv_context *drvc;
struct dev_context *devc;
struct sr_usb_dev_inst *usb;
- int ret;
+ int i, ret;
drvc = sdi->driver->context;
devc = sdi->priv;
return SR_ERR;
}
- ret = sr_usb_open(drvc->sr_ctx->libusb_ctx, usb);
- if (ret != SR_OK)
- return ret;
+ /* Try the whole shebang three times, fingers crossed. */
+ for (i = 0; i < 3; i++) {
+ ret = sr_usb_open(drvc->sr_ctx->libusb_ctx, usb);
+ if (ret != SR_OK)
+ return ret;
- ret = libusb_set_configuration(usb->devhdl, USB_CONFIG);
- if (ret != 0) {
- sr_err("Failed to set USB configuration: %s.",
- libusb_error_name(ret));
- sr_usb_close(usb);
- return SR_ERR;
- }
+ ret = libusb_set_configuration(usb->devhdl, USB_CONFIG);
+ if (ret != LIBUSB_SUCCESS) {
+ sr_err("Failed to set USB configuration: %s.",
+ libusb_error_name(ret));
+ sr_usb_close(usb);
+ return SR_ERR;
+ }
- ret = libusb_claim_interface(usb->devhdl, USB_INTERFACE);
- if (ret < 0) {
- sr_err("Failed to claim interface: %s.",
- libusb_error_name(ret));
- sr_usb_close(usb);
- return SR_ERR;
- }
+ ret = libusb_claim_interface(usb->devhdl, USB_INTERFACE);
+ if (ret != LIBUSB_SUCCESS) {
+ sr_err("Failed to claim interface: %s.",
+ libusb_error_name(ret));
+ sr_usb_close(usb);
+ return SR_ERR;
+ }
- sdi->status = SR_ST_ACTIVE;
+ ret = drain_usb(usb, EP_REPLY);
+ if (ret != SR_OK) {
+ sr_usb_close(usb);
+ return ret;
+ }
+ /* This delay appears to be necessary for reliable operation. */
+ g_usleep(30 * 1000);
- devc->active_fpga_config = FPGA_NOCONF;
- devc->state = STATE_IDLE;
+ sdi->status = SR_ST_ACTIVE;
- ret = (*devc->model->apply_fpga_config)(sdi);
+ devc->active_fpga_config = FPGA_NOCONF;
+ devc->short_transfer_quirk = FALSE;
+ devc->state = STATE_IDLE;
- if (ret == SR_OK)
- ret = (*devc->model->device_init_check)(sdi);
+ ret = (*devc->model->apply_fpga_config)(sdi);
- if (ret != SR_OK) {
+ if (ret == SR_OK)
+ ret = (*devc->model->device_init_check)(sdi);
+ if (ret == SR_OK)
+ break;
+
+ /* Rinse and repeat. */
sdi->status = SR_ST_INACTIVE;
sr_usb_close(usb);
}
+
+ if (ret == SR_OK && devc->short_transfer_quirk)
+ sr_warn("Short transfer quirk detected! "
+ "Memory reads will be slow.");
return ret;
}
if ((model->devopts[i] & (SR_CONF_MASK | key)) == key)
return TRUE;
}
+
return FALSE;
}
return -1;
/* Linear search is fine for very small tables. */
- for (i = 0; i < len; ++i) {
+ for (i = 0; i < len; i++) {
if (strcmp(entry, table[i]) == 0)
return i;
}
+
return -1;
}
*/
static int prepare_trigger_masks(const struct sr_dev_inst *sdi)
{
- uint64_t trigger_mask;
- uint64_t trigger_values;
- uint64_t trigger_edge_mask;
- uint64_t channel_bit;
+ uint64_t trigger_mask, trigger_values, trigger_edge_mask;
+ uint64_t level_bit, type_bit;
struct dev_context *devc;
struct sr_trigger *trigger;
struct sr_trigger_stage *stage;
struct sr_trigger_match *match;
const GSList *node;
int idx;
+ enum sr_trigger_matches trg;
devc = sdi->priv;
match = node->data;
if (!match->channel->enabled)
- continue; /* ignore disabled channel */
+ continue; /* Ignore disabled channel. */
idx = match->channel->index;
+ trg = match->match;
if (idx < 0 || idx >= devc->model->num_channels) {
sr_err("Channel index %d out of range.", idx);
- return SR_ERR_BUG; /* should not happen */
+ return SR_ERR_BUG; /* Should not happen. */
}
- channel_bit = UINT64_C(1) << idx;
- trigger_mask |= channel_bit;
-
- switch (match->match) {
- case SR_TRIGGER_ZERO:
- break;
- case SR_TRIGGER_ONE:
- trigger_values |= channel_bit;
- break;
- case SR_TRIGGER_RISING:
- trigger_values |= channel_bit;
- /* Fall through for edge mask. */
- case SR_TRIGGER_FALLING:
- trigger_edge_mask |= channel_bit;
- break;
- default:
+ if (trg != SR_TRIGGER_ZERO
+ && trg != SR_TRIGGER_ONE
+ && trg != SR_TRIGGER_RISING
+ && trg != SR_TRIGGER_FALLING) {
sr_err("Unsupported trigger match for CH%d.", idx + 1);
return SR_ERR_ARG;
}
+ level_bit = (trg == SR_TRIGGER_ONE
+ || trg == SR_TRIGGER_RISING) ? 1 : 0;
+ type_bit = (trg == SR_TRIGGER_RISING
+ || trg == SR_TRIGGER_FALLING) ? 1 : 0;
+
+ trigger_mask |= UINT64_C(1) << idx;
+ trigger_values |= level_bit << idx;
+ trigger_edge_mask |= type_bit << idx;
}
devc->trigger_mask = trigger_mask;
devc->trigger_values = trigger_values;
if (key == SR_CONF_SCAN_OPTIONS) {
*data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
- scanopts, ARRAY_SIZE(scanopts),
- sizeof(scanopts[0]));
+ scanopts, ARRAY_SIZE(scanopts), sizeof(scanopts[0]));
return SR_OK;
}
if (!sdi) {
/* List driver capabilities. */
*data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
- drvopts, ARRAY_SIZE(drvopts),
- sizeof(drvopts[0]));
+ drvopts, ARRAY_SIZE(drvopts), sizeof(drvopts[0]));
return SR_OK;
}
/* List the model's device options. */
if (key == SR_CONF_DEVICE_OPTIONS) {
*data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
- devc->model->devopts,
- devc->model->num_devopts,
- sizeof(devc->model->devopts[0]));
+ devc->model->devopts, devc->model->num_devopts,
+ sizeof(devc->model->devopts[0]));
return SR_OK;
}
case SR_CONF_SAMPLERATE:
g_variant_builder_init(&gvb, G_VARIANT_TYPE_VARDICT);
gvar = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT64,
- devc->model->samplerates,
- devc->model->num_samplerates,
- sizeof(devc->model->samplerates[0]));
+ devc->model->samplerates, devc->model->num_samplerates,
+ sizeof(devc->model->samplerates[0]));
g_variant_builder_add(&gvb, "{sv}", "samplerates", gvar);
*data = g_variant_builder_end(&gvb);
break;
case SR_CONF_TRIGGER_MATCH:
*data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
- trigger_matches,
- ARRAY_SIZE(trigger_matches),
- sizeof(trigger_matches[0]));
+ trigger_matches, ARRAY_SIZE(trigger_matches),
+ sizeof(trigger_matches[0]));
break;
case SR_CONF_TRIGGER_SOURCE:
*data = g_variant_new_strv(trigger_source_names,
- ARRAY_SIZE(trigger_source_names));
+ ARRAY_SIZE(trigger_source_names));
break;
case SR_CONF_TRIGGER_SLOPE:
case SR_CONF_CLOCK_EDGE:
*data = g_variant_new_strv(signal_edge_names,
- ARRAY_SIZE(signal_edge_names));
+ ARRAY_SIZE(signal_edge_names));
break;
default:
/* Must not happen for a key listed in devopts. */
struct dev_context *devc;
(void)cb_data;
+
devc = sdi->priv;
if (sdi->status != SR_ST_ACTIVE)
devc->cancel_requested = TRUE;
sr_dbg("Stopping acquisition.");
}
+
return SR_OK;
}