]> sigrok.org Git - libsigrok.git/commitdiff
sysclk-lwla: Implement support for LWLA1016
authorDaniel Elstner <redacted>
Sun, 22 Nov 2015 16:45:54 +0000 (17:45 +0100)
committerUwe Hermann <redacted>
Thu, 26 Nov 2015 20:44:31 +0000 (21:44 +0100)
Refactor the sysclk-lwla driver to separate the generic logic from
the model-specific implementation. Based on this, implement support
for the SysClk LWLA1016 device.

Makefile.am
src/hardware/sysclk-lwla/api.c
src/hardware/sysclk-lwla/lwla.c
src/hardware/sysclk-lwla/lwla.h
src/hardware/sysclk-lwla/lwla1016.c [new file with mode: 0644]
src/hardware/sysclk-lwla/lwla1034.c [new file with mode: 0644]
src/hardware/sysclk-lwla/protocol.c
src/hardware/sysclk-lwla/protocol.h

index 27216608aa65ce5063b7759478604cee6a3e0c25..4ea3b8a1f9c18359335a0ca70b36de7fbf6e579f 100644 (file)
@@ -406,6 +406,8 @@ if HW_SYSCLK_LWLA
 libsigrok_la_SOURCES += \
        src/hardware/sysclk-lwla/lwla.h \
        src/hardware/sysclk-lwla/lwla.c \
+       src/hardware/sysclk-lwla/lwla1016.c \
+       src/hardware/sysclk-lwla/lwla1034.c \
        src/hardware/sysclk-lwla/protocol.h \
        src/hardware/sysclk-lwla/protocol.c \
        src/hardware/sysclk-lwla/api.c
index 1b9f1bce44dbc7b772b697f7e3b812d6d2c34d84..be62551ba350a59f90cbf2c9fe9d0ae654f60fed 100644 (file)
 #include "libsigrok-internal.h"
 #include "protocol.h"
 
+/* Supported device scan options.
+ */
 static const uint32_t scanopts[] = {
        SR_CONF_CONN,
 };
 
-static const uint32_t devopts[] = {
+/* Driver capabilities.
+ */
+static const uint32_t drvopts[] = {
        SR_CONF_LOGIC_ANALYZER,
-       SR_CONF_LIMIT_SAMPLES | SR_CONF_GET | SR_CONF_SET,
-       SR_CONF_LIMIT_MSEC | SR_CONF_GET | SR_CONF_SET,
-       SR_CONF_SAMPLERATE | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST,
-       SR_CONF_EXTERNAL_CLOCK | SR_CONF_GET | SR_CONF_SET,
-       SR_CONF_CLOCK_EDGE | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST,
-       SR_CONF_TRIGGER_MATCH | SR_CONF_LIST,
-       SR_CONF_TRIGGER_SOURCE | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST,
-       SR_CONF_TRIGGER_SLOPE | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST,
 };
 
+/* Supported trigger match conditions.
+ */
 static const int32_t trigger_matches[] = {
        SR_TRIGGER_ZERO,
        SR_TRIGGER_ONE,
@@ -49,56 +47,53 @@ static const int32_t trigger_matches[] = {
        SR_TRIGGER_FALLING,
 };
 
-/* The hardware supports more samplerates than these, but these are the
- * options hardcoded into the vendor's Windows GUI.
+/* Names assigned to available trigger sources.
  */
-static const uint64_t samplerates[] = {
-       SR_MHZ(125), SR_MHZ(100),
-       SR_MHZ(50),  SR_MHZ(20),  SR_MHZ(10),
-       SR_MHZ(5),   SR_MHZ(2),   SR_MHZ(1),
-       SR_KHZ(500), SR_KHZ(200), SR_KHZ(100),
-       SR_KHZ(50),  SR_KHZ(20),  SR_KHZ(10),
-       SR_KHZ(5),   SR_KHZ(2),   SR_KHZ(1),
-       SR_HZ(500),  SR_HZ(200),  SR_HZ(100),
+static const char *const trigger_source_names[] = {
+       [TRIGGER_CHANNELS] = "CH",
+       [TRIGGER_EXT_TRG] = "TRG",
 };
 
-/* Names assigned to available trigger sources.  Indices must match
- * trigger_source enum values.
+/* Names assigned to available edge slope choices.
  */
-static const char *const trigger_source_names[] = { "CH", "TRG" };
+static const char *const signal_edge_names[] = {
+       [EDGE_POSITIVE] = "r",
+       [EDGE_NEGATIVE] = "f",
+};
 
-/* Names assigned to available trigger slope choices.  Indices must
- * match the signal_edge enum values.
+/* Initialize the SysClk LWLA driver.
  */
-static const char *const signal_edge_names[] = { "r", "f" };
-
 static int init(struct sr_dev_driver *di, struct sr_context *sr_ctx)
 {
        return std_init(sr_ctx, di, LOG_PREFIX);
 }
 
-static struct sr_dev_inst *dev_inst_new(void)
+/* Create a new sigrok device instance for the indicated LWLA model.
+ */
+static struct sr_dev_inst *dev_inst_new(const struct model_info *model)
 {
        struct sr_dev_inst *sdi;
        struct dev_context *devc;
        int i;
        char name[8];
 
-       /* Allocate memory for our private driver context. */
+       /* Initialize private device context. */
        devc = g_malloc0(sizeof(struct dev_context));
+       devc->model = model;
+       devc->active_fpga_config = FPGA_NOCONF;
+       devc->cfg_rle = TRUE;
+       devc->samplerate = model->samplerates[0];
+       devc->channel_mask = (UINT64_C(1) << model->num_channels) - 1;
 
-       /* Register the device with libsigrok. */
+       /* Create sigrok device instance. */
        sdi = g_malloc0(sizeof(struct sr_dev_inst));
        sdi->status = SR_ST_INACTIVE;
        sdi->vendor = g_strdup(VENDOR_NAME);
-       sdi->model = g_strdup(MODEL_NAME);
-
-       /* Enable all channels to match the default channel configuration. */
-       devc->channel_mask = ALL_CHANNELS_MASK;
-       devc->samplerate = DEFAULT_SAMPLERATE;
-
+       sdi->model = g_strdup(model->name);
        sdi->priv = devc;
-       for (i = 0; i < NUM_CHANNELS; ++i) {
+
+       /* Generate list of logic channels. */
+       for (i = 0; i < model->num_channels; i++) {
                /* The LWLA series simply number channels from CH1 to CHxx. */
                g_snprintf(name, sizeof(name), "CH%d", i + 1);
                sr_channel_new(sdi, i, SR_CHANNEL_LOGIC, TRUE, name);
@@ -107,17 +102,76 @@ static struct sr_dev_inst *dev_inst_new(void)
        return sdi;
 }
 
+/* Create a new device instance for a libusb device if it is a SysClk LWLA
+ * device and also matches the connection specification.
+ */
+static struct sr_dev_inst *dev_inst_new_matching(GSList *conn_matches,
+                                                libusb_device *dev)
+{
+       GSList *node;
+       struct sr_usb_dev_inst *usb;
+       const struct model_info *model;
+       struct sr_dev_inst *sdi;
+       struct libusb_device_descriptor des;
+       int bus, address;
+       unsigned int vid, pid;
+       int ret;
+
+       bus = libusb_get_bus_number(dev);
+       address = libusb_get_device_address(dev);
+
+       for (node = conn_matches; node != NULL; node = node->next) {
+               usb = node->data;
+               if (usb && usb->bus == bus && usb->address == address)
+                       break; /* found */
+       }
+       if (conn_matches && !node)
+               return NULL; /* no match */
+
+       ret = libusb_get_device_descriptor(dev, &des);
+       if (ret != 0) {
+               sr_err("Failed to get USB device descriptor: %s.",
+                       libusb_error_name(ret));
+               return NULL;
+       }
+       vid = des.idVendor;
+       pid = des.idProduct;
+
+       /* Create sigrok device instance. */
+       if (vid == USB_VID_SYSCLK && pid == USB_PID_LWLA1016) {
+               model = &lwla1016_info;
+       } else if (vid == USB_VID_SYSCLK && pid == USB_PID_LWLA1034) {
+               model = &lwla1034_info;
+       } else {
+               if (conn_matches)
+                       sr_warn("USB device %d.%d (%04x:%04x) is not a"
+                               " SysClk LWLA.", bus, address, vid, pid);
+               return NULL;
+       }
+       sdi = dev_inst_new(model);
+
+       sdi->inst_type = SR_INST_USB;
+       sdi->conn = sr_usb_dev_inst_new(bus, address, NULL);
+
+       return sdi;
+}
+
+/* Scan for SysClk LWLA devices and create a device instance for each one.
+ */
 static GSList *scan(struct sr_dev_driver *di, GSList *options)
 {
-       GSList *usb_devices, *devices, *node;
+       GSList *conn_devices, *devices, *node;
        struct drv_context *drvc;
        struct sr_dev_inst *sdi;
-       struct sr_usb_dev_inst *usb;
        struct sr_config *src;
        const char *conn;
+       libusb_device **devlist;
+       ssize_t num_devs, i;
 
        drvc = di->context;
-       conn = USB_VID_PID;
+       conn = NULL;
+       conn_devices = NULL;
+       devices = NULL;
 
        for (node = options; node != NULL; node = node->next) {
                src = node->data;
@@ -126,32 +180,41 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options)
                        break;
                }
        }
-       usb_devices = sr_usb_find(drvc->sr_ctx->libusb_ctx, conn);
-       devices = NULL;
+       if (conn) {
+               /* Find devices matching the connection specification. */
+               conn_devices = sr_usb_find(drvc->sr_ctx->libusb_ctx, conn);
+       }
 
-       for (node = usb_devices; node != NULL; node = node->next) {
-               usb = node->data;
+       /* List all libusb devices. */
+       num_devs = libusb_get_device_list(drvc->sr_ctx->libusb_ctx, &devlist);
+       if (num_devs < 0) {
+               sr_err("Failed to list USB devices: %s.",
+                       libusb_error_name(num_devs));
+               g_slist_free_full(conn_devices,
+                       (GDestroyNotify)&sr_usb_dev_inst_free);
+               return NULL;
+       }
 
-               /* Create sigrok device instance. */
-               sdi = dev_inst_new();
-               if (!sdi) {
-                       sr_usb_dev_inst_free(usb);
-                       continue;
-               }
-               sdi->driver = di;
-               sdi->inst_type = SR_INST_USB;
-               sdi->conn = usb;
+       /* Scan the USB device list for matching LWLA devices. */
+       for (i = 0; i < num_devs; i++) {
+               sdi = dev_inst_new_matching(conn_devices, devlist[i]);
+               if (!sdi)
+                       continue; /* no match */
 
                /* Register device instance with driver. */
+               sdi->driver = di;
                drvc->instances = g_slist_append(drvc->instances, sdi);
                devices = g_slist_append(devices, sdi);
        }
 
-       g_slist_free(usb_devices);
+       libusb_free_device_list(devlist, 1);
+       g_slist_free_full(conn_devices, (GDestroyNotify)&sr_usb_dev_inst_free);
 
        return devices;
 }
 
+/* Return the list of devices found during scan.
+ */
 static GSList *dev_list(const struct sr_dev_driver *di)
 {
        struct drv_context *drvc;
@@ -161,30 +224,42 @@ static GSList *dev_list(const struct sr_dev_driver *di)
        return drvc->instances;
 }
 
+/* Destroy the private device context.
+ */
 static void clear_dev_context(void *priv)
 {
        struct dev_context *devc;
 
        devc = priv;
 
+       if (devc->acquisition) {
+               sr_err("Cannot clear device context during acquisition!");
+               return; /* leak and pray */
+       }
        sr_dbg("Device context cleared.");
 
-       lwla_free_acquisition_state(devc->acquisition);
        g_free(devc);
 }
 
+/* Destroy all device instances.
+ */
 static int dev_clear(const struct sr_dev_driver *di)
 {
        return std_dev_clear(di, &clear_dev_context);
 }
 
+/* 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;
 
        drvc = sdi->driver->context;
+       devc = sdi->priv;
+       usb = sdi->conn;
 
        if (!drvc) {
                sr_err("Driver was not initialized.");
@@ -194,7 +269,6 @@ static int dev_open(struct sr_dev_inst *sdi)
                sr_err("Device already open.");
                return SR_ERR;
        }
-       usb = sdi->conn;
 
        ret = sr_usb_open(drvc->sr_ctx->libusb_ctx, usb);
        if (ret != SR_OK)
@@ -219,42 +293,58 @@ static int dev_open(struct sr_dev_inst *sdi)
                sr_usb_close(usb);
                return SR_ERR;
        }
+
        sdi->status = SR_ST_ACTIVE;
 
-       ret = lwla_init_device(sdi);
+       devc->active_fpga_config = FPGA_NOCONF;
+       devc->state = STATE_IDLE;
+
+       ret = (*devc->model->apply_fpga_config)(sdi);
+
+       if (ret == SR_OK)
+               ret = (*devc->model->device_init_check)(sdi);
+
        if (ret != SR_OK) {
-               sr_usb_close(usb);
                sdi->status = SR_ST_INACTIVE;
+               sr_usb_close(usb);
        }
        return ret;
 }
 
+/* Shutdown and close device.
+ */
 static int dev_close(struct sr_dev_inst *sdi)
 {
-       struct sr_usb_dev_inst *usb;
+       struct drv_context *drvc;
        struct dev_context *devc;
+       struct sr_usb_dev_inst *usb;
        int ret;
 
-       if (!sdi->driver->context) {
+       drvc = sdi->driver->context;
+       devc = sdi->priv;
+       usb = sdi->conn;
+
+       if (!drvc) {
                sr_err("Driver was not initialized.");
                return SR_ERR;
        }
-       usb = sdi->conn;
-       devc = sdi->priv;
-
-       if (sdi->status == SR_ST_INACTIVE)
+       if (sdi->status == SR_ST_INACTIVE) {
+               sr_dbg("Device already closed.");
                return SR_OK;
-
-       if (devc && devc->acquisition) {
-               sr_err("Attempt to close device during acquisition.");
-               return SR_ERR;
        }
+       if (devc->acquisition) {
+               sr_err("Cannot close device during acquisition!");
+               /* Request stop, leak handle, and prepare for the worst. */
+               devc->cancel_requested = TRUE;
+               return SR_ERR_BUG;
+       }
+
        sdi->status = SR_ST_INACTIVE;
 
-       /* Trigger download of the shutdown bitstream. */
-       ret = lwla_set_clock_config(sdi);
+       /* Download of the shutdown bitstream, if any. */
+       ret = (*devc->model->apply_fpga_config)(sdi);
        if (ret != SR_OK)
-               sr_err("Unable to shut down device.");
+               sr_warn("Unable to shut down device.");
 
        libusb_release_interface(usb->devhdl, USB_INTERFACE);
        sr_usb_close(usb);
@@ -262,11 +352,22 @@ static int dev_close(struct sr_dev_inst *sdi)
        return ret;
 }
 
-static int cleanup(const struct sr_dev_driver *di)
+/* Check whether the device options contain a specific key.
+ * Also match against get/set/list bits if specified.
+ */
+static int has_devopt(const struct model_info *model, uint32_t key)
 {
-       return dev_clear(di);
+       unsigned int i;
+
+       for (i = 0; i < model->num_devopts; i++) {
+               if ((model->devopts[i] & (SR_CONF_MASK | key)) == key)
+                       return TRUE;
+       }
+       return FALSE;
 }
 
+/* Read device configuration setting.
+ */
 static int config_get(uint32_t key, GVariant **data, const struct sr_dev_inst *sdi,
                      const struct sr_channel_group *cg)
 {
@@ -280,6 +381,9 @@ static int config_get(uint32_t key, GVariant **data, const struct sr_dev_inst *s
 
        devc = sdi->priv;
 
+       if (!has_devopt(devc->model, key | SR_CONF_GET))
+               return SR_ERR_NA;
+
        switch (key) {
        case SR_CONF_SAMPLERATE:
                *data = g_variant_new_uint64(devc->samplerate);
@@ -290,6 +394,9 @@ static int config_get(uint32_t key, GVariant **data, const struct sr_dev_inst *s
        case SR_CONF_LIMIT_SAMPLES:
                *data = g_variant_new_uint64(devc->limit_samples);
                break;
+       case SR_CONF_RLE:
+               *data = g_variant_new_boolean(devc->cfg_rle);
+               break;
        case SR_CONF_EXTERNAL_CLOCK:
                *data = g_variant_new_boolean(devc->cfg_clock_source
                                                == CLOCK_EXT_CLK);
@@ -313,7 +420,8 @@ static int config_get(uint32_t key, GVariant **data, const struct sr_dev_inst *s
                *data = g_variant_new_string(signal_edge_names[idx]);
                break;
        default:
-               return SR_ERR_NA;
+               /* Must not happen for a key listed in devopts. */
+               return SR_ERR_BUG;
        }
 
        return SR_OK;
@@ -339,6 +447,8 @@ static int lookup_index(GVariant *value, const char *const *table, int len)
        return -1;
 }
 
+/* Write device configuration setting.
+ */
 static int config_set(uint32_t key, GVariant *data, const struct sr_dev_inst *sdi,
                      const struct sr_channel_group *cg)
 {
@@ -348,15 +458,19 @@ static int config_set(uint32_t key, GVariant *data, const struct sr_dev_inst *sd
 
        (void)cg;
 
+       if (!sdi)
+               return SR_ERR_ARG;
+
        devc = sdi->priv;
-       if (!devc)
-               return SR_ERR_DEV_CLOSED;
+
+       if (!has_devopt(devc->model, key | SR_CONF_SET))
+               return SR_ERR_NA;
 
        switch (key) {
        case SR_CONF_SAMPLERATE:
                value = g_variant_get_uint64(data);
-               if (value < samplerates[ARRAY_SIZE(samplerates) - 1]
-                               || value > samplerates[0])
+               if (value < devc->model->samplerates[devc->model->num_samplerates - 1]
+                               || value > devc->model->samplerates[0])
                        return SR_ERR_SAMPLERATE;
                devc->samplerate = value;
                break;
@@ -372,6 +486,9 @@ static int config_set(uint32_t key, GVariant *data, const struct sr_dev_inst *sd
                        return SR_ERR_ARG;
                devc->limit_samples = value;
                break;
+       case SR_CONF_RLE:
+               devc->cfg_rle = g_variant_get_boolean(data);
+               break;
        case SR_CONF_EXTERNAL_CLOCK:
                devc->cfg_clock_source = (g_variant_get_boolean(data))
                        ? CLOCK_EXT_CLK : CLOCK_INTERNAL;
@@ -398,30 +515,35 @@ static int config_set(uint32_t key, GVariant *data, const struct sr_dev_inst *sd
                devc->cfg_trigger_slope = idx;
                break;
        default:
-               return SR_ERR_NA;
+               /* Must not happen for a key listed in devopts. */
+               return SR_ERR_BUG;
        }
 
        return SR_OK;
 }
 
+/* Apply channel configuration change.
+ */
 static int config_channel_set(const struct sr_dev_inst *sdi,
-               struct sr_channel *ch, unsigned int changes)
+                             struct sr_channel *ch, unsigned int changes)
 {
        uint64_t channel_bit;
        struct dev_context *devc;
 
+       if (!sdi)
+               return SR_ERR_ARG;
+
        devc = sdi->priv;
-       if (!devc)
-               return SR_ERR_DEV_CLOSED;
 
-       if (ch->index < 0 || ch->index >= NUM_CHANNELS) {
+       if (ch->index < 0 || ch->index >= devc->model->num_channels) {
                sr_err("Channel index %d out of range.", ch->index);
                return SR_ERR_BUG;
        }
-       channel_bit = (uint64_t)1 << ch->index;
 
        if ((changes & SR_CHANNEL_SET_ENABLED) != 0) {
-               /* Enable or disable input channel for this channel. */
+               channel_bit = UINT64_C(1) << ch->index;
+
+               /* Enable or disable logic input for this channel. */
                if (ch->enabled)
                        devc->channel_mask |= channel_bit;
                else
@@ -431,6 +553,8 @@ static int config_channel_set(const struct sr_dev_inst *sdi,
        return SR_OK;
 }
 
+/* Derive trigger masks from the session's trigger configuration.
+ */
 static int prepare_trigger_masks(const struct sr_dev_inst *sdi)
 {
        uint64_t trigger_mask;
@@ -442,6 +566,7 @@ static int prepare_trigger_masks(const struct sr_dev_inst *sdi)
        struct sr_trigger_stage *stage;
        struct sr_trigger_match *match;
        const GSList *node;
+       int idx;
 
        devc = sdi->priv;
 
@@ -465,7 +590,13 @@ static int prepare_trigger_masks(const struct sr_dev_inst *sdi)
                if (!match->channel->enabled)
                        continue; /* ignore disabled channel */
 
-               channel_bit = (uint64_t)1 << match->channel->index;
+               idx = match->channel->index;
+
+               if (idx < 0 || idx >= devc->model->num_channels) {
+                       sr_err("Channel index %d out of range.", idx);
+                       return SR_ERR_BUG; /* should not happen */
+               }
+               channel_bit = UINT64_C(1) << idx;
                trigger_mask |= channel_bit;
 
                switch (match->match) {
@@ -481,8 +612,7 @@ static int prepare_trigger_masks(const struct sr_dev_inst *sdi)
                        trigger_edge_mask |= channel_bit;
                        break;
                default:
-                       sr_err("Unsupported trigger match for CH%d.",
-                               match->channel->index + 1);
+                       sr_err("Unsupported trigger match for CH%d.", idx + 1);
                        return SR_ERR_ARG;
                }
        }
@@ -493,56 +623,94 @@ static int prepare_trigger_masks(const struct sr_dev_inst *sdi)
        return SR_OK;
 }
 
+/* Apply current device configuration to the hardware.
+ */
 static int config_commit(const struct sr_dev_inst *sdi)
 {
        struct dev_context *devc;
-       int rc;
+       int ret;
+
+       devc = sdi->priv;
 
        if (sdi->status != SR_ST_ACTIVE)
                return SR_ERR_DEV_CLOSED;
 
-       devc = sdi->priv;
        if (devc->acquisition) {
                sr_err("Acquisition still in progress?");
                return SR_ERR;
        }
-       rc = prepare_trigger_masks(sdi);
-       if (rc != SR_OK)
-               return rc;
 
-       return lwla_set_clock_config(sdi);
+       ret = prepare_trigger_masks(sdi);
+       if (ret != SR_OK)
+               return ret;
+
+       ret = (*devc->model->apply_fpga_config)(sdi);
+       if (ret != SR_OK) {
+               sr_err("Failed to apply FPGA configuration.");
+               return ret;
+       }
+
+       return SR_OK;
 }
 
-static int config_list(uint32_t key, GVariant **data, const struct sr_dev_inst *sdi,
+/* List available choices for a configuration setting.
+ */
+static int config_list(uint32_t key, GVariant **data,
+                      const struct sr_dev_inst *sdi,
                       const struct sr_channel_group *cg)
 {
+       struct dev_context *devc;
        GVariant *gvar;
        GVariantBuilder gvb;
 
-       (void)sdi;
        (void)cg;
 
-       switch (key) {
-       case SR_CONF_SCAN_OPTIONS:
+       if (key == SR_CONF_SCAN_OPTIONS) {
                *data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
-                               scanopts, ARRAY_SIZE(scanopts), sizeof(uint32_t));
-               break;
-       case SR_CONF_DEVICE_OPTIONS:
+                                                 scanopts, ARRAY_SIZE(scanopts),
+                                                 sizeof(scanopts[0]));
+               return SR_OK;
+       }
+       if (!sdi) {
+               if (key != SR_CONF_DEVICE_OPTIONS)
+                       return SR_ERR_ARG;
+
+               /* List driver capabilities. */
                *data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
-                               devopts, ARRAY_SIZE(devopts), sizeof(uint32_t));
-               break;
+                                                 drvopts, ARRAY_SIZE(drvopts),
+                                                 sizeof(drvopts[0]));
+               return SR_OK;
+       }
+
+       devc = sdi->priv;
+
+       /* 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]));
+               return SR_OK;
+       }
+
+       if (!has_devopt(devc->model, key | SR_CONF_LIST))
+               return SR_ERR_NA;
+
+       switch (key) {
        case SR_CONF_SAMPLERATE:
-               g_variant_builder_init(&gvb, G_VARIANT_TYPE("a{sv}"));
-               gvar = g_variant_new_fixed_array(G_VARIANT_TYPE("t"),
-                               samplerates, ARRAY_SIZE(samplerates),
-                               sizeof(uint64_t));
+               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]));
                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(int32_t));
+                                                 trigger_matches,
+                                                 ARRAY_SIZE(trigger_matches),
+                                                 sizeof(trigger_matches[0]));
                break;
        case SR_CONF_TRIGGER_SOURCE:
                *data = g_variant_new_strv(trigger_source_names,
@@ -554,68 +722,31 @@ static int config_list(uint32_t key, GVariant **data, const struct sr_dev_inst *
                                           ARRAY_SIZE(signal_edge_names));
                break;
        default:
-               return SR_ERR_NA;
+               /* Must not happen for a key listed in devopts. */
+               return SR_ERR_BUG;
        }
 
        return SR_OK;
 }
 
+/* Set up the device hardware to begin capturing samples as soon as the
+ * configured trigger conditions are met, or immediately if no triggers
+ * are configured.
+ */
 static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data)
 {
-       struct drv_context *drvc;
-       struct dev_context *devc;
-       struct acquisition_state *acq;
-       int ret;
-
        (void)cb_data;
 
        if (sdi->status != SR_ST_ACTIVE)
                return SR_ERR_DEV_CLOSED;
 
-       devc = sdi->priv;
-       drvc = sdi->driver->context;
-
-       if (devc->acquisition) {
-               sr_err("Acquisition still in progress?");
-               return SR_ERR;
-       }
-       acq = lwla_alloc_acquisition_state();
-       if (!acq)
-               return SR_ERR_MALLOC;
-
-       devc->cancel_requested = FALSE;
-       devc->stopping_in_progress = FALSE;
-       devc->transfer_error = FALSE;
-
        sr_info("Starting acquisition.");
 
-       devc->acquisition = acq;
-       ret = lwla_setup_acquisition(sdi);
-       if (ret != SR_OK) {
-               sr_err("Failed to set up acquisition.");
-               devc->acquisition = NULL;
-               lwla_free_acquisition_state(acq);
-               return ret;
-       }
-
-       ret = lwla_start_acquisition(sdi);
-       if (ret != SR_OK) {
-               sr_err("Failed to start acquisition.");
-               devc->acquisition = NULL;
-               lwla_free_acquisition_state(acq);
-               return ret;
-       }
-       usb_source_add(sdi->session, drvc->sr_ctx, 100, &lwla_receive_data,
-                      (struct sr_dev_inst *)sdi);
-
-       sr_info("Waiting for data.");
-
-       /* Send header packet to the session bus. */
-       std_session_send_df_header(sdi, LOG_PREFIX);
-
-       return SR_OK;
+       return lwla_start_acquisition(sdi);
 }
 
+/* Request that a running capture operation be stopped.
+ */
 static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
 {
        struct dev_context *devc;
@@ -626,19 +757,21 @@ static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
        if (sdi->status != SR_ST_ACTIVE)
                return SR_ERR_DEV_CLOSED;
 
-       if (devc->acquisition && !devc->cancel_requested) {
+       if (devc->state != STATE_IDLE && !devc->cancel_requested) {
                devc->cancel_requested = TRUE;
                sr_dbg("Stopping acquisition.");
        }
        return SR_OK;
 }
 
+/* SysClk LWLA driver descriptor.
+ */
 SR_PRIV struct sr_dev_driver sysclk_lwla_driver_info = {
        .name = "sysclk-lwla",
        .longname = "SysClk LWLA series",
        .api_version = 1,
        .init = init,
-       .cleanup = cleanup,
+       .cleanup = dev_clear,
        .scan = scan,
        .dev_list = dev_list,
        .dev_clear = dev_clear,
index aee9d060503f37bff3c0008242f6bae079e4cb65..0623f51168b1a7d3b3b58d22c0b4055607e8d80d 100644 (file)
@@ -95,7 +95,7 @@ SR_PRIV int lwla_send_bitstream(struct sr_context *ctx,
        sr_info("Downloading FPGA bitstream '%s'.", name);
 
        /* Transfer the entire bitstream in one URB. */
-       ret = libusb_bulk_transfer(usb->devhdl, EP_BITSTREAM,
+       ret = libusb_bulk_transfer(usb->devhdl, EP_CONFIG,
                                   stream, length, &xfer_len, USB_TIMEOUT_MS);
        g_free(stream);
 
@@ -191,33 +191,6 @@ SR_PRIV int lwla_read_reg(const struct sr_usb_dev_inst *usb,
        return ret;
 }
 
-SR_PRIV int lwla_read_long_reg(const struct sr_usb_dev_inst *usb,
-                              uint32_t addr, uint64_t *value)
-{
-       uint32_t low, high, dummy;
-       int ret;
-
-       ret = lwla_write_reg(usb, REG_LONG_ADDR, addr);
-       if (ret != SR_OK)
-               return ret;
-
-       ret = lwla_read_reg(usb, REG_LONG_STROBE, &dummy);
-       if (ret != SR_OK)
-               return ret;
-
-       ret = lwla_read_reg(usb, REG_LONG_HIGH, &high);
-       if (ret != SR_OK)
-               return ret;
-
-       ret = lwla_read_reg(usb, REG_LONG_LOW, &low);
-       if (ret != SR_OK)
-               return ret;
-
-       *value = ((uint64_t)high << 32) | low;
-
-       return SR_OK;
-}
-
 SR_PRIV int lwla_write_reg(const struct sr_usb_dev_inst *usb,
                           uint16_t reg, uint32_t value)
 {
@@ -232,7 +205,7 @@ SR_PRIV int lwla_write_reg(const struct sr_usb_dev_inst *usb,
 }
 
 SR_PRIV int lwla_write_regs(const struct sr_usb_dev_inst *usb,
-                           const struct regval_pair *regvals, int count)
+                           const struct regval *regvals, int count)
 {
        int i;
        int ret;
index 9eb69566c6e89dabfdc1c2c18f787ed9c3f5cc50..7bd5886415519524131774f8b30dd9cba81ca79f 100644 (file)
@@ -47,83 +47,111 @@ struct sr_usb_dev_inst;
 #define LWLA_WORD_2(val) GUINT16_TO_LE(((val) >> 48) & 0xFFFF)
 #define LWLA_WORD_3(val) GUINT16_TO_LE(((val) >> 32) & 0xFFFF)
 
+/* Maximum number of 16-bit words sent at a time during acquisition.
+ * Used for allocating the libusb transfer buffer.
+ */
+#define MAX_ACQ_SEND_LEN16     64 /* 43 for capture setup plus stuffing */
+
+/* Maximum number of 32-bit words received at a time during acquisition.
+ * This is a multiple of the endpoint buffer size to avoid transfer overflow
+ * conditions.
+ */
+#define MAX_ACQ_RECV_LEN32     (2 * 512 / 4)
+
+/* Maximum length of a register read/write sequence.
+ */
+#define MAX_REG_SEQ_LEN                16
+
+/* Logic datafeed packet size in bytes.
+ * This is a multiple of both 4 and 5 to match any model's unit size
+ * and memory granularity.
+ */
+#define PACKET_SIZE            (5000 * 4 * 5)
+
 /** USB device end points.
  */
-enum {
-       EP_COMMAND   = 2,
-       EP_BITSTREAM = 4,
-       EP_REPLY     = 6 | LIBUSB_ENDPOINT_IN
+enum usb_endpoint {
+       EP_COMMAND = 2,
+       EP_CONFIG  = 4,
+       EP_REPLY   = 6 | LIBUSB_ENDPOINT_IN
 };
 
 /** LWLA protocol command ID codes.
  */
-enum {
+enum command_id {
        CMD_READ_REG    = 1,
        CMD_WRITE_REG   = 2,
-       CMD_READ_MEM    = 6,
-       CMD_CAP_SETUP   = 7,
-       CMD_CAP_STATUS  = 8,
+       CMD_READ_MEM32  = 3,
+       CMD_READ_MEM36  = 6,
+       CMD_WRITE_LREGS = 7,
+       CMD_READ_LREGS  = 8,
 };
 
 /** LWLA capture state flags.
+ * The bit positions are the same as in the LWLA1016 control register.
  */
 enum {
-       STATUS_CAPTURING = 1 << 1,
-       STATUS_TRIGGERED = 1 << 4,
-       STATUS_MEM_AVAIL = 1 << 5,
-       STATUS_FLAG_MASK = 0x3F
+       STATUS_CAPTURING = 1 << 2,
+       STATUS_TRIGGERED = 1 << 5,
+       STATUS_MEM_AVAIL = 1 << 6,
 };
 
-/** LWLA1034 register addresses.
+/** LWLA1034 run-length encoding states.
  */
-enum {
-       REG_MEM_CTRL    = 0x1074, /* capture buffer control */
-       REG_MEM_FILL    = 0x1078, /* capture buffer fill level */
-       REG_MEM_START   = 0x107C, /* capture buffer start address */
-
-       REG_DIV_BYPASS  = 0x1094, /* bypass clock divider flag */
-
-       REG_LONG_STROBE = 0x10B0, /* long register read/write strobe */
-       REG_LONG_ADDR   = 0x10B4, /* long register address */
-       REG_LONG_LOW    = 0x10B8, /* long register low word */
-       REG_LONG_HIGH   = 0x10BC, /* long register high word */
-
-       REG_FREQ_CH1    = 0x10C0, /* channel 1 live frequency */
-       REG_FREQ_CH2    = 0x10C4, /* channel 2 live frequency */
-       REG_FREQ_CH3    = 0x10C8, /* channel 3 live frequency */
-       REG_FREQ_CH4    = 0x10CC, /* channel 4 live frequency */
-};
-
-/** Flag bits for REG_MEM_CTRL.
- */
-enum {
-       MEM_CTRL_WRITE   = 1 << 0, /* "wr1rd0" bit */
-       MEM_CTRL_CLR_IDX = 1 << 1, /* "clr_idx" bit */
+enum rle_state {
+       RLE_STATE_DATA,
+       RLE_STATE_LEN
 };
 
-/* LWLA1034 long register addresses.
+/** Register address/value pair.
  */
-enum {
-       LREG_CAP_CTRL = 10,  /* capture control bits */
-       LREG_TEST_ID  = 100, /* constant test ID */
+struct regval {
+       unsigned int reg;
+       uint32_t val;
 };
 
-/** Flag bits for LREG_CAP_CTRL.
+/** LWLA sample acquisition and decompression state.
  */
-enum {
-       CAP_CTRL_TRG_EN       = 1 << 0, /* "trg_en" bit */
-       CAP_CTRL_CLR_TIMEBASE = 1 << 2, /* "do_clr_timebase" bit */
-       CAP_CTRL_FLUSH_FIFO   = 1 << 4, /* "flush_fifo" bit */
-       CAP_CTRL_CLR_FIFOFULL = 1 << 5, /* "clr_fifo32_ful" bit */
-       CAP_CTRL_CLR_COUNTER  = 1 << 6, /* "clr_cntr0" bit */
+struct acquisition_state {
+       uint64_t samples_max;   /* maximum number of samples to process */
+       uint64_t samples_done;  /* number of samples sent to the session bus */
+       uint64_t duration_max;  /* maximum capture duration in milliseconds */
+       uint64_t duration_now;  /* running capture duration since trigger */
+
+       uint64_t sample;        /* last sample read from capture memory */
+       uint64_t run_len;       /* remaining run length of current sample */
+
+       struct libusb_transfer *xfer_in;        /* USB in transfer record */
+       struct libusb_transfer *xfer_out;       /* USB out transfer record */
+
+       size_t mem_addr_fill;   /* capture memory fill level */
+       size_t mem_addr_done;   /* position up to which data was received */
+       size_t mem_addr_next;   /* start address for next async read */
+       size_t mem_addr_stop;   /* end of memory range to be read */
+       size_t in_index;        /* position in read transfer buffer */
+       size_t out_index;       /* position in logic packet buffer */
+       enum rle_state rle;     /* RLE decoding state */
+
+       gboolean rle_enabled;   /* capturing in timing-state mode */
+       gboolean clock_boost;   /* switch to faster clock during capture */
+       unsigned int status;    /* last received device status */
+
+       unsigned int reg_seq_pos;       /* index of next register/value pair */
+       unsigned int reg_seq_len;       /* length of register/value sequence */
+
+       struct regval reg_sequence[MAX_REG_SEQ_LEN];    /* register buffer */
+       uint32_t xfer_buf_in[MAX_ACQ_RECV_LEN32];       /* USB in buffer */
+       uint16_t xfer_buf_out[MAX_ACQ_SEND_LEN16];      /* USB out buffer */
+       uint8_t out_packet[PACKET_SIZE];                /* logic payload */
 };
 
-/** Register/value pair.
- */
-struct regval_pair {
-       unsigned int reg;
-       unsigned int val;
-};
+static inline void lwla_queue_regval(struct acquisition_state *acq,
+                                    unsigned int reg, uint32_t value)
+{
+       acq->reg_sequence[acq->reg_seq_len].reg = reg;
+       acq->reg_sequence[acq->reg_seq_len].val = value;
+       acq->reg_seq_len++;
+}
 
 SR_PRIV int lwla_send_bitstream(struct sr_context *ctx,
                                const struct sr_usb_dev_inst *usb,
@@ -138,13 +166,10 @@ SR_PRIV int lwla_receive_reply(const struct sr_usb_dev_inst *usb,
 SR_PRIV int lwla_read_reg(const struct sr_usb_dev_inst *usb,
                          uint16_t reg, uint32_t *value);
 
-SR_PRIV int lwla_read_long_reg(const struct sr_usb_dev_inst *usb,
-                              uint32_t addr, uint64_t *value);
-
 SR_PRIV int lwla_write_reg(const struct sr_usb_dev_inst *usb,
                           uint16_t reg, uint32_t value);
 
 SR_PRIV int lwla_write_regs(const struct sr_usb_dev_inst *usb,
-                           const struct regval_pair *regvals, int count);
+                           const struct regval *regvals, int count);
 
 #endif
diff --git a/src/hardware/sysclk-lwla/lwla1016.c b/src/hardware/sysclk-lwla/lwla1016.c
new file mode 100644 (file)
index 0000000..b803194
--- /dev/null
@@ -0,0 +1,415 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2015 Daniel Elstner <daniel.kitta@gmail.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include "lwla.h"
+#include "protocol.h"
+
+/* Number of logic channels.
+ */
+#define NUM_CHANNELS   16
+
+/* Unit size for the sigrok logic datafeed.
+ */
+#define UNIT_SIZE      ((NUM_CHANNELS + 7) / 8)
+
+/* Size of the acquisition buffer in device memory units.
+ */
+#define MEMORY_DEPTH   (256 * 1024)    /* 256k x 32 bit */
+
+/* Capture memory read start address.
+ */
+#define READ_START_ADDR                2
+
+/* Number of device memory units (32 bit) to read at a time.
+ */
+#define READ_CHUNK_LEN32       250
+
+/** LWLA1016 register addresses.
+ */
+enum reg_addr {
+       REG_CHAN_MASK   = 0x1000, /* bit mask of enabled channels */
+
+       REG_DURATION    = 0x1010, /* capture duration in ms */
+
+       REG_MEM_WR_PTR  = 0x1070,
+       REG_MEM_RD_PTR  = 0x1074,
+       REG_MEM_DATA    = 0x1078,
+       REG_MEM_CTRL    = 0x107C,
+
+       REG_CAP_COUNT   = 0x10B0,
+
+       REG_TEST_ID     = 0x10B4, /* read */
+       REG_TRG_SEL     = 0x10B4, /* write */
+
+       REG_CAP_CTRL    = 0x10B8,
+
+       REG_CAP_TOTAL   = 0x10BC, /* read */
+       REG_DIV_COUNT   = 0x10BC, /* write */
+};
+
+/** Flag bits for REG_MEM_CTRL.
+ */
+enum mem_ctrl_flag {
+       MEM_CTRL_RESET  = 1 << 0,
+       MEM_CTRL_WRITE  = 1 << 1,
+};
+
+/** Flag bits for REG_CAP_CTRL.
+ */
+enum cap_ctrl_flag {
+       CAP_CTRL_FIFO32_FULL    = 1 << 0, /* "fifo32_ful" bit */
+       CAP_CTRL_FIFO64_FULL    = 1 << 1, /* "fifo64_ful" bit */
+       CAP_CTRL_TRG_EN         = 1 << 2, /* "trg_en" bit */
+       CAP_CTRL_CLR_TIMEBASE   = 1 << 3, /* "do_clr_timebase" bit */
+       CAP_CTRL_FIFO_EMPTY     = 1 << 4, /* "fifo_empty" bit */
+       CAP_CTRL_SAMPLE_EN      = 1 << 5, /* "sample_en" bit */
+       CAP_CTRL_CNTR_NOT_ENDR  = 1 << 6, /* "cntr_not_endr" bit */
+};
+
+/* Available FPGA configurations.
+ */
+enum fpga_config {
+       FPGA_100 = 0,   /* 100 MS/s, no compression */
+       FPGA_100_TS,    /* 100 MS/s, timing-state mode */
+};
+
+/* FPGA bitstream resource filenames.
+ */
+static const char bitstream_map[][32] = {
+       [FPGA_100]      = "sysclk-lwla1016-100.rbf",
+       [FPGA_100_TS]   = "sysclk-lwla1016-100-ts.rbf",
+};
+
+/* Demangle incoming sample data from the transfer buffer.
+ */
+static void read_response(struct acquisition_state *acq)
+{
+       uint32_t *in_p, *out_p;
+       size_t words_left, num_words;
+       size_t max_samples, run_samples;
+       size_t i;
+
+       words_left = MIN(acq->mem_addr_next, acq->mem_addr_stop)
+                       - acq->mem_addr_done;
+       /* Calculate number of samples to write into packet. */
+       max_samples = MIN(acq->samples_max - acq->samples_done,
+                         PACKET_SIZE / UNIT_SIZE - acq->out_index);
+       run_samples = MIN(max_samples, 2 * words_left);
+
+       /* Round up in case the samples limit is an odd number. */
+       num_words = (run_samples + 1) / 2;
+       /*
+        * Without RLE the output index will always be a multiple of two
+        * samples (at least before reaching the samples limit), thus 32-bit
+        * alignment is guaranteed.
+        */
+       out_p = (uint32_t *)&acq->out_packet[acq->out_index * UNIT_SIZE];
+       in_p  = &acq->xfer_buf_in[acq->in_index];
+       /*
+        * Transfer two samples at a time, taking care to swap the 16-bit
+        * halves of each input word but keeping the samples themselves in
+        * the original Little Endian order.
+        */
+       for (i = 0; i < num_words; i++)
+               out_p[i] = LROTATE(in_p[i], 16);
+
+       acq->in_index += num_words;
+       acq->mem_addr_done += num_words;
+       acq->out_index += run_samples;
+       acq->samples_done += run_samples;
+}
+
+/* Demangle and decompress incoming sample data from the transfer buffer.
+ */
+static void read_response_rle(struct acquisition_state *acq)
+{
+       uint32_t *in_p;
+       uint16_t *out_p;
+       size_t words_left;
+       size_t max_samples, run_samples;
+       size_t wi, ri;
+       uint32_t word;
+       uint16_t sample;
+
+       words_left = MIN(acq->mem_addr_next, acq->mem_addr_stop)
+                       - acq->mem_addr_done;
+       in_p = &acq->xfer_buf_in[acq->in_index];
+
+       for (wi = 0;; wi++) {
+               /* Calculate number of samples to write into packet. */
+               max_samples = MIN(acq->samples_max - acq->samples_done,
+                                 PACKET_SIZE / UNIT_SIZE - acq->out_index);
+               run_samples = MIN(max_samples, acq->run_len);
+
+               /* Expand run-length samples into session packet. */
+               sample = acq->sample;
+               out_p = &((uint16_t *)acq->out_packet)[acq->out_index];
+
+               for (ri = 0; ri < run_samples; ri++)
+                       out_p[ri] = GUINT16_TO_LE(sample);
+
+               acq->run_len -= run_samples;
+               acq->out_index += run_samples;
+               acq->samples_done += run_samples;
+
+               if (run_samples == max_samples)
+                       break; /* packet full or sample limit reached */
+               if (wi >= words_left)
+                       break; /* done with current transfer */
+
+               word = GUINT32_FROM_LE(in_p[wi]);
+               acq->sample = word >> 16;
+               acq->run_len = (word & 0xFFFF) + 1;
+       }
+       acq->in_index += wi;
+       acq->mem_addr_done += wi;
+}
+
+/* Select and transfer FPGA bitstream for the current configuration.
+ */
+static int apply_fpga_config(const struct sr_dev_inst *sdi)
+{
+       struct dev_context *devc;
+       struct drv_context *drvc;
+       int config;
+       int ret;
+
+       devc = sdi->priv;
+       drvc = sdi->driver->context;
+
+       if (sdi->status == SR_ST_INACTIVE)
+               return SR_OK; /* the LWLA1016 has no off state */
+
+       config = (devc->cfg_rle) ? FPGA_100_TS : FPGA_100;
+
+       if (config == devc->active_fpga_config)
+               return SR_OK; /* no change */
+
+       ret = lwla_send_bitstream(drvc->sr_ctx, sdi->conn,
+                                 bitstream_map[config]);
+       devc->active_fpga_config = (ret == SR_OK) ? config : FPGA_NOCONF;
+
+       return ret;
+}
+
+/* Perform initialization self test.
+ */
+static int device_init_check(const struct sr_dev_inst *sdi)
+{
+       uint32_t value;
+       int ret;
+
+       ret = lwla_read_reg(sdi->conn, REG_TEST_ID, &value);
+       if (ret != SR_OK)
+               return ret;
+
+       /* Ignore the value returned by the first read. */
+       ret = lwla_read_reg(sdi->conn, REG_TEST_ID, &value);
+       if (ret != SR_OK)
+               return ret;
+
+       if (value != 0x12345678) {
+               sr_err("Received invalid test word 0x%08X.", value);
+               return SR_ERR;
+       }
+       return SR_OK;
+}
+
+static int setup_acquisition(const struct sr_dev_inst *sdi)
+{
+       struct dev_context *devc;
+       struct sr_usb_dev_inst *usb;
+       struct acquisition_state *acq;
+       uint32_t divider_count;
+       int ret;
+
+       devc = sdi->priv;
+       usb  = sdi->conn;
+       acq  = devc->acquisition;
+
+       acq->reg_seq_pos = 0;
+       acq->reg_seq_len = 0;
+
+       lwla_queue_regval(acq, REG_CHAN_MASK, devc->channel_mask);
+
+       if (devc->samplerate > 0 && devc->samplerate < SR_MHZ(100))
+               divider_count = SR_MHZ(100) / devc->samplerate - 1;
+       else
+               divider_count = 0;
+
+       lwla_queue_regval(acq, REG_DIV_COUNT, divider_count);
+
+       lwla_queue_regval(acq, REG_CAP_CTRL, 0);
+       lwla_queue_regval(acq, REG_DURATION, 0);
+
+       lwla_queue_regval(acq, REG_MEM_CTRL, MEM_CTRL_RESET);
+       lwla_queue_regval(acq, REG_MEM_CTRL, 0);
+       lwla_queue_regval(acq, REG_MEM_CTRL, MEM_CTRL_WRITE);
+
+       lwla_queue_regval(acq, REG_CAP_CTRL,
+               CAP_CTRL_FIFO32_FULL | CAP_CTRL_FIFO64_FULL);
+
+       lwla_queue_regval(acq, REG_CAP_CTRL, CAP_CTRL_FIFO_EMPTY);
+       lwla_queue_regval(acq, REG_CAP_CTRL, 0);
+
+       lwla_queue_regval(acq, REG_CAP_COUNT, MEMORY_DEPTH - 5);
+
+       lwla_queue_regval(acq, REG_TRG_SEL,
+               ((devc->trigger_edge_mask & 0xFFFF) << 16)
+               | (devc->trigger_values & 0xFFFF));
+
+       ret = lwla_write_regs(usb, acq->reg_sequence, acq->reg_seq_len);
+       acq->reg_seq_len = 0;
+
+       return ret;
+}
+
+static int prepare_request(const struct sr_dev_inst *sdi)
+{
+       struct dev_context *devc;
+       struct acquisition_state *acq;
+       size_t count;
+
+       devc = sdi->priv;
+       acq  = devc->acquisition;
+
+       acq->xfer_out->length = 0;
+       acq->reg_seq_pos = 0;
+       acq->reg_seq_len = 0;
+
+       switch (devc->state) {
+       case STATE_START_CAPTURE:
+               lwla_queue_regval(acq, REG_CAP_CTRL, CAP_CTRL_TRG_EN
+                               | ((devc->trigger_mask & 0xFFFF) << 16));
+               break;
+       case STATE_STOP_CAPTURE:
+               lwla_queue_regval(acq, REG_CAP_CTRL, 0);
+               lwla_queue_regval(acq, REG_DIV_COUNT, 0);
+               break;
+       case STATE_READ_PREPARE:
+               lwla_queue_regval(acq, REG_MEM_CTRL, 0);
+               break;
+       case STATE_READ_FINISH:
+               lwla_queue_regval(acq, REG_MEM_CTRL, MEM_CTRL_RESET);
+               lwla_queue_regval(acq, REG_MEM_CTRL, 0);
+               break;
+       case STATE_STATUS_REQUEST:
+               lwla_queue_regval(acq, REG_CAP_CTRL, 0);
+               lwla_queue_regval(acq, REG_MEM_WR_PTR, 0);
+               lwla_queue_regval(acq, REG_DURATION, 0);
+               break;
+       case STATE_LENGTH_REQUEST:
+               lwla_queue_regval(acq, REG_CAP_COUNT, 0);
+               break;
+       case STATE_READ_REQUEST:
+               /* Always read a multiple of 8 device words. */
+               count = MIN(READ_CHUNK_LEN32,
+                           acq->mem_addr_stop - acq->mem_addr_next);
+
+               acq->xfer_buf_out[0] = LWLA_WORD(CMD_READ_MEM32);
+               acq->xfer_buf_out[1] = LWLA_WORD_0(acq->mem_addr_next);
+               acq->xfer_buf_out[2] = LWLA_WORD_1(acq->mem_addr_next);
+               acq->xfer_buf_out[3] = LWLA_WORD_0(count);
+               acq->xfer_buf_out[4] = LWLA_WORD_1(count);
+               acq->xfer_out->length = 5 * sizeof(acq->xfer_buf_out[0]);
+
+               acq->mem_addr_next += count;
+               break;
+       default:
+               sr_err("BUG: unhandled request state %d.", devc->state);
+               return SR_ERR_BUG;
+       }
+
+       return SR_OK;
+}
+
+static int handle_response(const struct sr_dev_inst *sdi)
+{
+       struct dev_context *devc;
+       struct acquisition_state *acq;
+       int expect_len;
+
+       devc = sdi->priv;
+       acq  = devc->acquisition;
+
+       switch (devc->state) {
+       case STATE_STATUS_REQUEST:
+               acq->status = acq->reg_sequence[0].val & 0x7F;
+               acq->mem_addr_fill = acq->reg_sequence[1].val;
+               acq->duration_now  = acq->reg_sequence[2].val;
+               break;
+       case STATE_LENGTH_REQUEST:
+               acq->mem_addr_next = READ_START_ADDR;
+               acq->mem_addr_stop = acq->reg_sequence[0].val + READ_START_ADDR - 1;
+               break;
+       case STATE_READ_REQUEST:
+               expect_len = (acq->mem_addr_next - acq->mem_addr_done
+                               + acq->in_index) * sizeof(acq->xfer_buf_in[0]);
+               if (acq->xfer_in->actual_length != expect_len) {
+                       sr_err("Received size %d does not match expected size %d.",
+                              acq->xfer_in->actual_length, expect_len);
+                       devc->transfer_error = TRUE;
+                       return SR_ERR;
+               }
+               if (acq->rle_enabled)
+                       read_response_rle(acq);
+               else
+                       read_response(acq);
+               break;
+       default:
+               sr_err("BUG: unhandled response state %d.", devc->state);
+               return SR_ERR_BUG;
+       }
+
+       return SR_OK;
+}
+
+/* Model descriptor for the LWLA1016.
+ */
+SR_PRIV const struct model_info lwla1016_info = {
+       .name = "LWLA1016",
+       .num_channels = NUM_CHANNELS,
+
+       .num_devopts = 5,
+       .devopts = {
+               SR_CONF_LIMIT_SAMPLES | SR_CONF_GET | SR_CONF_SET,
+               SR_CONF_LIMIT_MSEC | SR_CONF_GET | SR_CONF_SET,
+               SR_CONF_SAMPLERATE | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST,
+               SR_CONF_TRIGGER_MATCH | SR_CONF_LIST,
+               SR_CONF_RLE | SR_CONF_GET | SR_CONF_SET,
+       },
+       .num_samplerates = 19,
+       .samplerates = {
+               SR_MHZ(100),
+               SR_MHZ(50),  SR_MHZ(20),  SR_MHZ(10),
+               SR_MHZ(5),   SR_MHZ(2),   SR_MHZ(1),
+               SR_KHZ(500), SR_KHZ(200), SR_KHZ(100),
+               SR_KHZ(50),  SR_KHZ(20),  SR_KHZ(10),
+               SR_KHZ(5),   SR_KHZ(2),   SR_KHZ(1),
+               SR_HZ(500),  SR_HZ(200),  SR_HZ(100),
+       },
+
+       .apply_fpga_config = &apply_fpga_config,
+       .device_init_check = &device_init_check,
+       .setup_acquisition = &setup_acquisition,
+
+       .prepare_request = &prepare_request,
+       .handle_response = &handle_response,
+};
diff --git a/src/hardware/sysclk-lwla/lwla1034.c b/src/hardware/sysclk-lwla/lwla1034.c
new file mode 100644 (file)
index 0000000..bc49f79
--- /dev/null
@@ -0,0 +1,544 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2015 Daniel Elstner <daniel.kitta@gmail.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include "lwla.h"
+#include "protocol.h"
+
+/* Number of logic channels.
+ */
+#define NUM_CHANNELS   34
+
+/* Bit mask covering all logic channels.
+ */
+#define ALL_CHANNELS_MASK      ((UINT64_C(1) << NUM_CHANNELS) - 1)
+
+/* Unit size for the sigrok logic datafeed.
+ */
+#define UNIT_SIZE      ((NUM_CHANNELS + 7) / 8)
+
+/* Size of the acquisition buffer in device memory units.
+ */
+#define MEMORY_DEPTH   (256 * 1024)    /* 256k x 36 bit */
+
+/* Capture memory read start address.
+ */
+#define READ_START_ADDR                4
+
+/* Number of device memory units (36 bit) to read at a time. Slices of 8
+ * consecutive 36-bit words are mapped to 9 32-bit words each, so the chunk
+ * length should be a multiple of 8 to ensure alignment to slice boundaries.
+ *
+ * Experimentation has shown that reading chunks larger than about 1024 bytes
+ * is unreliable. The threshold seems to relate to the buffer size on the FX2
+ * USB chip: The configured endpoint buffer size is 512, and with double or
+ * triple buffering enabled a multiple of 512 bytes can be kept in fly.
+ *
+ * The vendor software limits reads to 120 words (15 slices, 540 bytes) at
+ * a time. So far, it appears safe to increase this to 224 words (28 slices,
+ * 1008 bytes), thus making the most of two 512 byte buffers.
+ */
+#define READ_CHUNK_LEN36       (28 * 8)
+
+/* Bit mask for the RLE repeat-count-follows flag. */
+#define RLE_FLAG_LEN_FOLLOWS   (UINT64_C(1) << 35)
+
+/** LWLA1034 register addresses.
+ */
+enum reg_addr {
+       REG_MEM_CTRL    = 0x1074, /* capture buffer control */
+       REG_MEM_FILL    = 0x1078, /* capture buffer fill level */
+       REG_MEM_START   = 0x107C, /* capture buffer start address */
+
+       REG_CLK_BOOST   = 0x1094, /* logic clock boost flag */
+
+       REG_LONG_STROBE = 0x10B0, /* long register read/write strobe */
+       REG_LONG_ADDR   = 0x10B4, /* long register address */
+       REG_LONG_LOW    = 0x10B8, /* long register low word */
+       REG_LONG_HIGH   = 0x10BC, /* long register high word */
+};
+
+/** Flag bits for REG_MEM_CTRL.
+ */
+enum mem_ctrl_flag {
+       MEM_CTRL_WRITE   = 1 << 0, /* "wr1rd0" bit */
+       MEM_CTRL_CLR_IDX = 1 << 1, /* "clr_idx" bit */
+};
+
+/* LWLA1034 long register addresses.
+ */
+enum long_reg_addr {
+       LREG_CHAN_MASK  = 0,    /* channel enable mask */
+       LREG_DIV_COUNT  = 1,    /* clock divider max count */
+       LREG_TRG_VALUE  = 2,    /* trigger level/slope bits */
+       LREG_TRG_TYPE   = 3,    /* trigger type bits (level or edge) */
+       LREG_TRG_ENABLE = 4,    /* trigger enable mask */
+       LREG_MEM_FILL   = 5,    /* capture memory fill level or limit */
+
+       LREG_DURATION   = 7,    /* elapsed time in ms (0.8 ms at 125 MS/s) */
+       LREG_CHAN_STATE = 8,    /* current logic levels at the inputs */
+       LREG_STATUS     = 9,    /* capture status flags */
+
+       LREG_CAP_CTRL   = 10,   /* capture control bits */
+       LREG_TEST_ID    = 100,  /* constant test ID */
+};
+
+/** Flag bits for LREG_CAP_CTRL.
+ */
+enum cap_ctrl_flag {
+       CAP_CTRL_TRG_EN       = 1 << 0, /* "trg_en" bit */
+       CAP_CTRL_CLR_TIMEBASE = 1 << 2, /* "do_clr_timebase" bit */
+       CAP_CTRL_FLUSH_FIFO   = 1 << 4, /* "flush_fifo" bit */
+       CAP_CTRL_CLR_FIFOFULL = 1 << 5, /* "clr_fifo32_ful" bit */
+       CAP_CTRL_CLR_COUNTER  = 1 << 6, /* "clr_cntr0" bit */
+};
+
+/* Available FPGA configurations.
+ */
+enum fpga_config {
+       FPGA_OFF = 0,   /* FPGA shutdown config */
+       FPGA_INT,       /* internal clock config */
+       FPGA_EXTPOS,    /* external clock, rising edge config */
+       FPGA_EXTNEG,    /* external clock, falling edge config */
+};
+
+/* FPGA bitstream resource filenames.
+ */
+static const char bitstream_map[][32] = {
+       [FPGA_OFF]      = "sysclk-lwla1034-off.rbf",
+       [FPGA_INT]      = "sysclk-lwla1034-int.rbf",
+       [FPGA_EXTPOS]   = "sysclk-lwla1034-extpos.rbf",
+       [FPGA_EXTNEG]   = "sysclk-lwla1034-extneg.rbf",
+};
+
+/* Read 64-bit long register.
+ */
+static int read_long_reg(const struct sr_usb_dev_inst *usb,
+                        uint32_t addr, uint64_t *value)
+{
+       uint32_t low, high, dummy;
+       int ret;
+
+       ret = lwla_write_reg(usb, REG_LONG_ADDR, addr);
+       if (ret != SR_OK)
+               return ret;
+
+       ret = lwla_read_reg(usb, REG_LONG_STROBE, &dummy);
+       if (ret != SR_OK)
+               return ret;
+
+       ret = lwla_read_reg(usb, REG_LONG_HIGH, &high);
+       if (ret != SR_OK)
+               return ret;
+
+       ret = lwla_read_reg(usb, REG_LONG_LOW, &low);
+       if (ret != SR_OK)
+               return ret;
+
+       *value = ((uint64_t)high << 32) | low;
+
+       return SR_OK;
+}
+
+/* Queue access sequence for a long register write.
+ */
+static void queue_long_regval(struct acquisition_state *acq,
+                             uint32_t addr, uint64_t value)
+{
+       lwla_queue_regval(acq, REG_LONG_ADDR, addr);
+       lwla_queue_regval(acq, REG_LONG_LOW, value & 0xFFFFFFFF);
+       lwla_queue_regval(acq, REG_LONG_HIGH, value >> 32);
+       lwla_queue_regval(acq, REG_LONG_STROBE, 0);
+}
+
+/* Helper to fill in the long register bulk write command.
+ */
+static inline void bulk_long_set(struct acquisition_state *acq,
+                                size_t idx, uint64_t value)
+{
+       acq->xfer_buf_out[4 * idx + 3] = LWLA_WORD_0(value);
+       acq->xfer_buf_out[4 * idx + 4] = LWLA_WORD_1(value);
+       acq->xfer_buf_out[4 * idx + 5] = LWLA_WORD_2(value);
+       acq->xfer_buf_out[4 * idx + 6] = LWLA_WORD_3(value);
+}
+
+/* Helper for dissecting the response to a long register bulk read.
+ */
+static inline uint64_t bulk_long_get(const struct acquisition_state *acq,
+                                    size_t idx)
+{
+       uint64_t low, high;
+
+       low  = LWLA_TO_UINT32(acq->xfer_buf_in[2 * idx]);
+       high = LWLA_TO_UINT32(acq->xfer_buf_in[2 * idx + 1]);
+
+       return (high << 32) | low;
+}
+
+/* Demangle and decompress incoming sample data from the transfer buffer.
+ * The data chunk is taken from the acquisition state, and is expected to
+ * contain a multiple of 8 packed 36-bit words.
+ */
+static void read_response(struct acquisition_state *acq)
+{
+       uint64_t sample, high_nibbles, word;
+       uint32_t *slice;
+       uint8_t *out_p;
+       size_t words_left;
+       size_t max_samples, run_samples;
+       size_t wi, ri, si;
+
+       /* Number of 36-bit words remaining in the transfer buffer. */
+       words_left = MIN(acq->mem_addr_next, acq->mem_addr_stop)
+                       - acq->mem_addr_done;
+
+       for (wi = 0;; wi++) {
+               /* Calculate number of samples to write into packet. */
+               max_samples = MIN(acq->samples_max - acq->samples_done,
+                                 PACKET_SIZE / UNIT_SIZE - acq->out_index);
+               run_samples = MIN(max_samples, acq->run_len);
+
+               /* Expand run-length samples into session packet. */
+               sample = acq->sample;
+               out_p = &acq->out_packet[acq->out_index * UNIT_SIZE];
+
+               for (ri = 0; ri < run_samples; ri++) {
+                       out_p[0] =  sample        & 0xFF;
+                       out_p[1] = (sample >>  8) & 0xFF;
+                       out_p[2] = (sample >> 16) & 0xFF;
+                       out_p[3] = (sample >> 24) & 0xFF;
+                       out_p[4] = (sample >> 32) & 0xFF;
+                       out_p += UNIT_SIZE;
+               }
+               acq->run_len -= run_samples;
+               acq->out_index += run_samples;
+               acq->samples_done += run_samples;
+
+               if (run_samples == max_samples)
+                       break; /* packet full or sample limit reached */
+               if (wi >= words_left)
+                       break; /* done with current transfer */
+
+               /* Get the current slice of 8 packed 36-bit words. */
+               slice = &acq->xfer_buf_in[(acq->in_index + wi) / 8 * 9];
+               si = (acq->in_index + wi) % 8; /* word index within slice */
+
+               /* Extract the next 36-bit word. */
+               high_nibbles = LWLA_TO_UINT32(slice[8]);
+               word = LWLA_TO_UINT32(slice[si]);
+               word |= (high_nibbles << (4 * si + 4)) & (UINT64_C(0xF) << 32);
+
+               if (acq->rle == RLE_STATE_DATA) {
+                       acq->sample = word & ALL_CHANNELS_MASK;
+                       acq->run_len = ((word >> NUM_CHANNELS) & 1) + 1;
+                       acq->rle = ((word & RLE_FLAG_LEN_FOLLOWS) != 0)
+                                       ? RLE_STATE_LEN : RLE_STATE_DATA;
+               } else {
+                       acq->run_len += word << 1;
+                       acq->rle = RLE_STATE_DATA;
+               }
+       }
+       acq->in_index += wi;
+       acq->mem_addr_done += wi;
+}
+
+/* Select and transfer FPGA bitstream for the current configuration.
+ */
+static int apply_fpga_config(const struct sr_dev_inst *sdi)
+{
+       struct dev_context *devc;
+       struct drv_context *drvc;
+       int config;
+       int ret;
+
+       devc = sdi->priv;
+       drvc = sdi->driver->context;
+
+       if (sdi->status == SR_ST_INACTIVE)
+               config = FPGA_OFF;
+       else if (devc->cfg_clock_source == CLOCK_INTERNAL)
+               config = FPGA_INT;
+       else if (devc->cfg_clock_edge == EDGE_POSITIVE)
+               config = FPGA_EXTPOS;
+       else
+               config = FPGA_EXTNEG;
+
+       if (config == devc->active_fpga_config)
+               return SR_OK; /* no change */
+
+       ret = lwla_send_bitstream(drvc->sr_ctx, sdi->conn,
+                                 bitstream_map[config]);
+       devc->active_fpga_config = (ret == SR_OK) ? config : FPGA_NOCONF;
+
+       return ret;
+}
+
+/* Perform initialization self test.
+ */
+static int device_init_check(const struct sr_dev_inst *sdi)
+{
+       uint64_t value;
+       int ret;
+
+       ret = read_long_reg(sdi->conn, LREG_TEST_ID, &value);
+       if (ret != SR_OK)
+               return ret;
+
+       /* Ignore the value returned by the first read. */
+       ret = read_long_reg(sdi->conn, LREG_TEST_ID, &value);
+       if (ret != SR_OK)
+               return ret;
+
+       if (value != UINT64_C(0x1234567887654321)) {
+               sr_err("Received invalid test word 0x%016" PRIX64 ".", value);
+               return SR_ERR;
+       }
+       return SR_OK;
+}
+
+/* Set up the device in preparation for an acquisition session.
+ */
+static int setup_acquisition(const struct sr_dev_inst *sdi)
+{
+       uint64_t divider_count;
+       uint64_t trigger_mask;
+       struct dev_context *devc;
+       struct sr_usb_dev_inst *usb;
+       struct acquisition_state *acq;
+       int ret;
+
+       devc = sdi->priv;
+       usb  = sdi->conn;
+       acq  = devc->acquisition;
+
+       acq->reg_seq_pos = 0;
+       acq->reg_seq_len = 0;
+
+       lwla_queue_regval(acq, REG_MEM_CTRL, MEM_CTRL_CLR_IDX);
+       lwla_queue_regval(acq, REG_MEM_CTRL, MEM_CTRL_WRITE);
+
+       queue_long_regval(acq, LREG_CAP_CTRL,
+               CAP_CTRL_CLR_TIMEBASE | CAP_CTRL_FLUSH_FIFO |
+               CAP_CTRL_CLR_FIFOFULL | CAP_CTRL_CLR_COUNTER);
+
+       lwla_queue_regval(acq, REG_CLK_BOOST, acq->clock_boost);
+
+       ret = lwla_write_regs(usb, acq->reg_sequence, acq->reg_seq_len);
+       acq->reg_seq_len = 0;
+
+       if (ret != SR_OK)
+               return ret;
+
+       acq->xfer_buf_out[0] = LWLA_WORD(CMD_WRITE_LREGS);
+       acq->xfer_buf_out[1] = LWLA_WORD(0);
+       acq->xfer_buf_out[2] = LWLA_WORD(LREG_STATUS + 1);
+
+       bulk_long_set(acq, LREG_CHAN_MASK, devc->channel_mask);
+
+       if (devc->samplerate > 0 && devc->samplerate <= SR_MHZ(100)
+                       && !acq->clock_boost)
+               divider_count = SR_MHZ(100) / devc->samplerate - 1;
+       else
+               divider_count = 0;
+
+       bulk_long_set(acq, LREG_DIV_COUNT, divider_count);
+       bulk_long_set(acq, LREG_TRG_VALUE, devc->trigger_values);
+       bulk_long_set(acq, LREG_TRG_TYPE,  devc->trigger_edge_mask);
+
+       trigger_mask = devc->trigger_mask;
+
+       /* Set bits to select external TRG input edge. */
+       if (devc->cfg_trigger_source == TRIGGER_EXT_TRG)
+               switch (devc->cfg_trigger_slope) {
+               case EDGE_POSITIVE:
+                       trigger_mask |= UINT64_C(1) << 35;
+                       break;
+               case EDGE_NEGATIVE:
+                       trigger_mask |= UINT64_C(1) << 34;
+                       break;
+               }
+
+       bulk_long_set(acq, LREG_TRG_ENABLE, trigger_mask);
+
+       /* Set the capture memory full threshold. This is slightly less
+        * than the actual maximum, most likely in order to compensate for
+        * pipeline latency.
+        */
+       bulk_long_set(acq, LREG_MEM_FILL, MEMORY_DEPTH - 16);
+
+       /* Fill remaining words with zeroes. */
+       bulk_long_set(acq, 6, 0);
+       bulk_long_set(acq, LREG_DURATION, 0);
+       bulk_long_set(acq, LREG_CHAN_STATE, 0);
+       bulk_long_set(acq, LREG_STATUS, 0);
+
+       return lwla_send_command(sdi->conn, acq->xfer_buf_out,
+                                3 + (LREG_STATUS + 1) * 4);
+}
+
+static int prepare_request(const struct sr_dev_inst *sdi)
+{
+       struct dev_context *devc;
+       struct acquisition_state *acq;
+       size_t count;
+
+       devc = sdi->priv;
+       acq  = devc->acquisition;
+
+       acq->xfer_out->length = 0;
+       acq->reg_seq_pos = 0;
+       acq->reg_seq_len = 0;
+
+       switch (devc->state) {
+       case STATE_START_CAPTURE:
+               queue_long_regval(acq, LREG_CAP_CTRL, CAP_CTRL_TRG_EN);
+               break;
+       case STATE_STOP_CAPTURE:
+               queue_long_regval(acq, LREG_CAP_CTRL, 0);
+               lwla_queue_regval(acq, REG_CLK_BOOST, 0);
+               break;
+       case STATE_READ_PREPARE:
+               lwla_queue_regval(acq, REG_CLK_BOOST, 1);
+               lwla_queue_regval(acq, REG_MEM_CTRL, MEM_CTRL_CLR_IDX);
+               lwla_queue_regval(acq, REG_MEM_START, READ_START_ADDR);
+               break;
+       case STATE_READ_FINISH:
+               lwla_queue_regval(acq, REG_CLK_BOOST, 0);
+               break;
+       case STATE_STATUS_REQUEST:
+               acq->xfer_buf_out[0] = LWLA_WORD(CMD_READ_LREGS);
+               acq->xfer_buf_out[1] = LWLA_WORD(0);
+               acq->xfer_buf_out[2] = LWLA_WORD(LREG_STATUS + 1);
+               acq->xfer_out->length = 3 * sizeof(acq->xfer_buf_out[0]);
+               break;
+       case STATE_LENGTH_REQUEST:
+               lwla_queue_regval(acq, REG_MEM_FILL, 0);
+               break;
+       case STATE_READ_REQUEST:
+               /* Always read a multiple of 8 device words. */
+               count = MIN(READ_CHUNK_LEN36, acq->mem_addr_stop
+                                       - acq->mem_addr_next + 7) / 8 * 8;
+
+               acq->xfer_buf_out[0] = LWLA_WORD(CMD_READ_MEM36);
+               acq->xfer_buf_out[1] = LWLA_WORD_0(acq->mem_addr_next);
+               acq->xfer_buf_out[2] = LWLA_WORD_1(acq->mem_addr_next);
+               acq->xfer_buf_out[3] = LWLA_WORD_0(count);
+               acq->xfer_buf_out[4] = LWLA_WORD_1(count);
+               acq->xfer_out->length = 5 * sizeof(acq->xfer_buf_out[0]);
+
+               acq->mem_addr_next += count;
+               break;
+       default:
+               sr_err("BUG: unhandled request state %d.", devc->state);
+               return SR_ERR_BUG;
+       }
+
+       return SR_OK;
+}
+
+static int handle_response(const struct sr_dev_inst *sdi)
+{
+       struct dev_context *devc;
+       struct acquisition_state *acq;
+       int expect_len;
+
+       devc = sdi->priv;
+       acq  = devc->acquisition;
+
+       switch (devc->state) {
+       case STATE_STATUS_REQUEST:
+               if (acq->xfer_in->actual_length != (LREG_STATUS + 1) * 8) {
+                       sr_err("Received size %d doesn't match expected size %d.",
+                              acq->xfer_in->actual_length, (LREG_STATUS + 1) * 8);
+                       return SR_ERR;
+               }
+               acq->mem_addr_fill = bulk_long_get(acq, LREG_MEM_FILL) & 0xFFFFFFFF;
+               acq->duration_now  = bulk_long_get(acq, LREG_DURATION);
+               /* Shift left by one so the bit positions match the LWLA1016. */
+               acq->status = (bulk_long_get(acq, LREG_STATUS) & 0x3F) << 1;
+               /*
+                * It seems that the 125 MS/s mode is implemented simply by
+                * running the FPGA logic at a 25% higher clock rate. As a
+                * result, the millisecond counter for the capture duration
+                * is also off by 25%, and thus needs to be corrected here.
+                */
+               if (acq->clock_boost)
+                       acq->duration_now = acq->duration_now * 4 / 5;
+               break;
+       case STATE_LENGTH_REQUEST:
+               acq->mem_addr_next = READ_START_ADDR;
+               acq->mem_addr_stop = acq->reg_sequence[0].val;
+               break;
+       case STATE_READ_REQUEST:
+               /* Expect a multiple of 8 36-bit words packed into 9 32-bit
+                * words. */
+               expect_len = (acq->mem_addr_next - acq->mem_addr_done
+                       + acq->in_index + 7) / 8 * 9 * sizeof(acq->xfer_buf_in[0]);
+
+               if (acq->xfer_in->actual_length != expect_len) {
+                       sr_err("Received size %d does not match expected size %d.",
+                              acq->xfer_in->actual_length, expect_len);
+                       devc->transfer_error = TRUE;
+                       return SR_ERR;
+               }
+               read_response(acq);
+               break;
+       default:
+               sr_err("BUG: unhandled response state %d.", devc->state);
+               return SR_ERR_BUG;
+       }
+
+       return SR_OK;
+}
+
+/** Model descriptor for the LWLA1034.
+ */
+SR_PRIV const struct model_info lwla1034_info = {
+       .name = "LWLA1034",
+       .num_channels = NUM_CHANNELS,
+
+       .num_devopts = 8,
+       .devopts = {
+               SR_CONF_LIMIT_SAMPLES | SR_CONF_GET | SR_CONF_SET,
+               SR_CONF_LIMIT_MSEC | SR_CONF_GET | SR_CONF_SET,
+               SR_CONF_SAMPLERATE | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST,
+               SR_CONF_TRIGGER_MATCH | SR_CONF_LIST,
+               SR_CONF_EXTERNAL_CLOCK | SR_CONF_GET | SR_CONF_SET,
+               SR_CONF_CLOCK_EDGE | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST,
+               SR_CONF_TRIGGER_SOURCE | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST,
+               SR_CONF_TRIGGER_SLOPE | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST,
+       },
+       .num_samplerates = 20,
+       .samplerates = {
+               SR_MHZ(125), SR_MHZ(100),
+               SR_MHZ(50),  SR_MHZ(20),  SR_MHZ(10),
+               SR_MHZ(5),   SR_MHZ(2),   SR_MHZ(1),
+               SR_KHZ(500), SR_KHZ(200), SR_KHZ(100),
+               SR_KHZ(50),  SR_KHZ(20),  SR_KHZ(10),
+               SR_KHZ(5),   SR_KHZ(2),   SR_KHZ(1),
+               SR_HZ(500),  SR_HZ(200),  SR_HZ(100),
+       },
+
+       .apply_fpga_config = &apply_fpga_config,
+       .device_init_check = &device_init_check,
+       .setup_acquisition = &setup_acquisition,
+
+       .prepare_request = &prepare_request,
+       .handle_response = &handle_response,
+};
index ba676f69a72c7804bfc6aed3b2bdcca359ce1fa8..46a9d6c9d56a7dc37e443f1127e34d6d69b78e92 100644 (file)
 
 #include <config.h>
 #include <string.h>
+#include "lwla.h"
 #include "protocol.h"
 
-/* Bit mask for the RLE repeat-count-follows flag. */
-#define RLE_FLAG_LEN_FOLLOWS ((uint64_t)1 << 35)
-
-/* Start address of capture status memory area to read. */
-#define CAP_STAT_ADDR 5
-
-/* Number of 64-bit words read from the capture status memory. */
-#define CAP_STAT_LEN 5
-
-/* The bitstream filenames are indexed by the clock_config enumeration.
+/* Status polling interval during acquisition.
  */
-static const char bitstream_map[][32] = {
-       "sysclk-lwla1034-off.rbf",
-       "sysclk-lwla1034-int.rbf",
-       "sysclk-lwla1034-extpos.rbf",
-       "sysclk-lwla1034-extneg.rbf",
-};
+#define POLL_INTERVAL 100 /* ms */
 
 /* Submit an already filled-in USB transfer.
  */
@@ -57,237 +44,129 @@ static int submit_transfer(struct dev_context *devc,
        return SR_OK;
 }
 
-/* Set up the LWLA in preparation for an acquisition session.
+/* Set up transfer for the next register in a write sequence.
  */
-static int capture_setup(const struct sr_dev_inst *sdi)
+static void next_reg_write(struct acquisition_state *acq)
 {
-       struct dev_context *devc;
-       struct acquisition_state *acq;
-       uint64_t divider_count;
-       uint64_t trigger_mask;
-       uint64_t memory_limit;
-       uint16_t command[3 + (10 * 4)];
-
-       devc = sdi->priv;
-       acq  = devc->acquisition;
-
-       command[0] = LWLA_WORD(CMD_CAP_SETUP);
-       command[1] = LWLA_WORD(0); /* address */
-       command[2] = LWLA_WORD(10); /* length */
-
-       command[3] = LWLA_WORD_0(devc->channel_mask);
-       command[4] = LWLA_WORD_1(devc->channel_mask);
-       command[5] = LWLA_WORD_2(devc->channel_mask);
-       command[6] = LWLA_WORD_3(devc->channel_mask);
-
-       /* Set the clock divide counter maximum for samplerates of up to
-        * 100 MHz. At the highest samplerate of 125 MHz the clock divider
-        * is bypassed.
-        */
-       if (!acq->bypass_clockdiv && devc->samplerate > 0)
-               divider_count = SR_MHZ(100) / devc->samplerate - 1;
-       else
-               divider_count = 0;
-
-       command[7]  = LWLA_WORD_0(divider_count);
-       command[8]  = LWLA_WORD_1(divider_count);
-       command[9]  = LWLA_WORD_2(divider_count);
-       command[10] = LWLA_WORD_3(divider_count);
-
-       command[11] = LWLA_WORD_0(devc->trigger_values);
-       command[12] = LWLA_WORD_1(devc->trigger_values);
-       command[13] = LWLA_WORD_2(devc->trigger_values);
-       command[14] = LWLA_WORD_3(devc->trigger_values);
-
-       command[15] = LWLA_WORD_0(devc->trigger_edge_mask);
-       command[16] = LWLA_WORD_1(devc->trigger_edge_mask);
-       command[17] = LWLA_WORD_2(devc->trigger_edge_mask);
-       command[18] = LWLA_WORD_3(devc->trigger_edge_mask);
-
-       trigger_mask = devc->trigger_mask;
-       /* Set bits to select external TRG input edge. */
-       if (devc->cfg_trigger_source == TRIGGER_EXT_TRG)
-               switch (devc->cfg_trigger_slope) {
-               case EDGE_POSITIVE:
-                       trigger_mask |= (uint64_t)1 << 35;
-                       break;
-               case EDGE_NEGATIVE:
-                       trigger_mask |= (uint64_t)1 << 34;
-                       break;
-               }
-
-       command[19] = LWLA_WORD_0(trigger_mask);
-       command[20] = LWLA_WORD_1(trigger_mask);
-       command[21] = LWLA_WORD_2(trigger_mask);
-       command[22] = LWLA_WORD_3(trigger_mask);
-
-       /* Set the capture memory full threshold. This is slightly less
-        * than the actual maximum, most likely in order to compensate for
-        * pipeline latency.
-        */
-       memory_limit = MEMORY_DEPTH - 16;
+       struct regval *regval;
 
-       command[23] = LWLA_WORD_0(memory_limit);
-       command[24] = LWLA_WORD_1(memory_limit);
-       command[25] = LWLA_WORD_2(memory_limit);
-       command[26] = LWLA_WORD_3(memory_limit);
+       regval = &acq->reg_sequence[acq->reg_seq_pos];
 
-       /* Fill remaining words with zeroes. */
-       memset(&command[27], 0, sizeof(command) - 27 * sizeof(command[0]));
+       acq->xfer_buf_out[0] = LWLA_WORD(CMD_WRITE_REG);
+       acq->xfer_buf_out[1] = LWLA_WORD(regval->reg);
+       acq->xfer_buf_out[2] = LWLA_WORD_0(regval->val);
+       acq->xfer_buf_out[3] = LWLA_WORD_1(regval->val);
 
-       return lwla_send_command(sdi->conn, command, ARRAY_SIZE(command));
+       acq->xfer_out->length = 4 * sizeof(acq->xfer_buf_out[0]);
 }
 
-/* Issue a register write command as an asynchronous USB transfer.
+/* Set up transfer for the next register in a read sequence.
  */
-static int issue_write_reg(const struct sr_dev_inst *sdi,
-                          unsigned int reg, unsigned int value)
+static void next_reg_read(struct acquisition_state *acq)
 {
-       struct dev_context *devc;
-       struct acquisition_state *acq;
-
-       devc = sdi->priv;
-       acq  = devc->acquisition;
+       unsigned int addr;
 
-       acq->xfer_buf_out[0] = LWLA_WORD(CMD_WRITE_REG);
-       acq->xfer_buf_out[1] = LWLA_WORD(reg);
-       acq->xfer_buf_out[2] = LWLA_WORD_0(value);
-       acq->xfer_buf_out[3] = LWLA_WORD_1(value);
+       addr = acq->reg_sequence[acq->reg_seq_pos].reg;
 
-       acq->xfer_out->length = 4 * sizeof(uint16_t);
+       acq->xfer_buf_out[0] = LWLA_WORD(CMD_READ_REG);
+       acq->xfer_buf_out[1] = LWLA_WORD(addr);
 
-       return submit_transfer(devc, acq->xfer_out);
+       acq->xfer_out->length = 2 * sizeof(acq->xfer_buf_out[0]);
 }
 
-/* Issue a register write command as an asynchronous USB transfer for the
- * next register/value pair of the currently active register write sequence.
+/* Decode the response to a register read request.
  */
-static int issue_next_write_reg(const struct sr_dev_inst *sdi)
+static int read_reg_response(struct acquisition_state *acq)
 {
-       struct dev_context *devc;
-       struct regval_pair *regval;
-       int ret;
+       uint32_t value;
 
-       devc = sdi->priv;
-
-       if (devc->reg_write_pos >= devc->reg_write_len) {
-               sr_err("Already written all registers in sequence.");
-               return SR_ERR_BUG;
+       if (acq->xfer_in->actual_length != 4) {
+               sr_err("Received size %d doesn't match expected size 4.",
+                      acq->xfer_in->actual_length);
+               return SR_ERR;
        }
-       regval = &devc->reg_write_seq[devc->reg_write_pos];
-
-       ret = issue_write_reg(sdi, regval->reg, regval->val);
-       if (ret != SR_OK)
-               return ret;
+       value = LWLA_TO_UINT32(acq->xfer_buf_in[0]);
+       acq->reg_sequence[acq->reg_seq_pos].val = value;
 
-       ++devc->reg_write_pos;
        return SR_OK;
 }
 
-/* Issue a capture status request as an asynchronous USB transfer.
+/* Enter a new state and submit the corresponding request to the device.
  */
-static void request_capture_status(const struct sr_dev_inst *sdi)
+static int submit_request(const struct sr_dev_inst *sdi,
+                         enum protocol_state state)
 {
        struct dev_context *devc;
        struct acquisition_state *acq;
+       int ret;
 
        devc = sdi->priv;
        acq  = devc->acquisition;
 
-       acq->xfer_buf_out[0] = LWLA_WORD(CMD_CAP_STATUS);
-       acq->xfer_buf_out[1] = LWLA_WORD(CAP_STAT_ADDR);
-       acq->xfer_buf_out[2] = LWLA_WORD(CAP_STAT_LEN);
-
-       acq->xfer_out->length = 3 * sizeof(uint16_t);
-
-       if (submit_transfer(devc, acq->xfer_out) == SR_OK)
-               devc->state = STATE_STATUS_REQUEST;
-}
+       devc->state = state;
 
-/* Issue a request for the capture buffer fill level as
- * an asynchronous USB transfer.
- */
-static void request_capture_length(const struct sr_dev_inst *sdi)
-{
-       struct dev_context *devc;
-       struct acquisition_state *acq;
+       acq->xfer_out->length = 0;
+       acq->reg_seq_pos = 0;
+       acq->reg_seq_len = 0;
 
-       devc = sdi->priv;
-       acq  = devc->acquisition;
+       /* Perform the model-specific action for the new state. */
+       ret = (*devc->model->prepare_request)(sdi);
 
-       acq->xfer_buf_out[0] = LWLA_WORD(CMD_READ_REG);
-       acq->xfer_buf_out[1] = LWLA_WORD(REG_MEM_FILL);
+       if (ret != SR_OK) {
+               devc->transfer_error = TRUE;
+               return ret;
+       }
 
-       acq->xfer_out->length = 2 * sizeof(uint16_t);
+       if (acq->reg_seq_pos < acq->reg_seq_len) {
+               if ((state & STATE_EXPECT_RESPONSE) != 0)
+                       next_reg_read(acq);
+               else
+                       next_reg_write(acq);
+       }
 
-       if (submit_transfer(devc, acq->xfer_out) == SR_OK)
-               devc->state = STATE_LENGTH_REQUEST;
+       return submit_transfer(devc, acq->xfer_out);
 }
 
-/* Initiate the capture memory read operation:  Reset the acquisition state
- * and start a sequence of register writes in order to set up the device for
- * reading from the capture buffer.
+/* Evaluate and act on the response to a capture status request.
  */
-static void issue_read_start(const struct sr_dev_inst *sdi)
+static void handle_status_response(const struct sr_dev_inst *sdi)
 {
        struct dev_context *devc;
        struct acquisition_state *acq;
-       struct regval_pair *regvals;
+       unsigned int old_status;
 
        devc = sdi->priv;
        acq  = devc->acquisition;
+       old_status = acq->status;
 
-       /* Reset RLE state. */
-       acq->rle = RLE_STATE_DATA;
-       acq->sample  = 0;
-       acq->run_len = 0;
-
-       acq->samples_done = 0;
-
-       /* For some reason, the start address is 4 rather than 0. */
-       acq->mem_addr_done = 4;
-       acq->mem_addr_next = 4;
-       acq->mem_addr_stop = acq->mem_addr_fill;
-
-       /* Sample position in the packet output buffer. */
-       acq->out_index = 0;
-
-       regvals = devc->reg_write_seq;
-
-       regvals[0].reg = REG_DIV_BYPASS;
-       regvals[0].val = 1;
-
-       regvals[1].reg = REG_MEM_CTRL;
-       regvals[1].val = MEM_CTRL_CLR_IDX;
-
-       regvals[2].reg = REG_MEM_START;
-       regvals[2].val = 4;
-
-       devc->reg_write_pos = 0;
-       devc->reg_write_len = 3;
+       if ((*devc->model->handle_response)(sdi) != SR_OK) {
+               devc->transfer_error = TRUE;
+               return;
+       }
+       devc->state = STATE_STATUS_WAIT;
 
-       if (issue_next_write_reg(sdi) == SR_OK)
-               devc->state = STATE_READ_PREPARE;
-}
+       sr_spew("Captured %zu words, %" PRIu64 " ms, status 0x%02X.",
+               acq->mem_addr_fill, acq->duration_now, acq->status);
 
-/* Issue a command as an asynchronous USB transfer which returns the device
- * to normal state after a read operation.  Sets a new device context state
- * on success.
- */
-static void issue_read_end(const struct sr_dev_inst *sdi)
-{
-       struct dev_context *devc;
-
-       devc = sdi->priv;
+       if ((~old_status & acq->status & STATUS_TRIGGERED) != 0)
+               sr_info("Capture triggered.");
 
-       if (issue_write_reg(sdi, REG_DIV_BYPASS, 0) == SR_OK)
-               devc->state = STATE_READ_END;
+       if (acq->duration_now >= acq->duration_max) {
+               sr_dbg("Time limit reached, stopping capture.");
+               submit_request(sdi, STATE_STOP_CAPTURE);
+       } else if ((acq->status & STATUS_TRIGGERED) == 0) {
+               sr_spew("Waiting for trigger.");
+       } else if ((acq->status & STATUS_MEM_AVAIL) == 0) {
+               sr_dbg("Capture memory filled.");
+               submit_request(sdi, STATE_LENGTH_REQUEST);
+       } else if ((acq->status & STATUS_CAPTURING) != 0) {
+               sr_spew("Sampling in progress.");
+       }
 }
 
-/* Decode an incoming response to a buffer fill level request and act on it
- * as appropriate.  Note that this function changes the device context state.
+/* Evaluate and act on the response to a capture length request.
  */
-static void process_capture_length(const struct sr_dev_inst *sdi)
+static void handle_length_response(const struct sr_dev_inst *sdi)
 {
        struct dev_context *devc;
        struct acquisition_state *acq;
@@ -295,319 +174,171 @@ static void process_capture_length(const struct sr_dev_inst *sdi)
        devc = sdi->priv;
        acq  = devc->acquisition;
 
-       if (acq->xfer_in->actual_length != 4) {
-               sr_err("Received size %d doesn't match expected size 4.",
-                      acq->xfer_in->actual_length);
+       if ((*devc->model->handle_response)(sdi) != SR_OK) {
                devc->transfer_error = TRUE;
                return;
        }
-       acq->mem_addr_fill = LWLA_TO_UINT32(acq->xfer_buf_in[0]);
-
-       sr_dbg("%zu words in capture buffer.", acq->mem_addr_fill);
-
-       if (acq->mem_addr_fill > 0 && !devc->cancel_requested)
-               issue_read_start(sdi);
-       else
-               issue_read_end(sdi);
-}
-
-/* Initiate a sequence of register write commands with the effect of
- * cancelling a running capture operation.  This sets a new device state
- * if issuing the first command succeeds.
- */
-static void issue_stop_capture(const struct sr_dev_inst *sdi)
-{
-       struct dev_context *devc;
-       struct regval_pair *regvals;
-
-       devc = sdi->priv;
+       acq->rle = RLE_STATE_DATA;
+       acq->sample = 0;
+       acq->run_len = 0;
+       acq->samples_done = 0;
+       acq->mem_addr_done = acq->mem_addr_next;
+       acq->out_index = 0;
 
-       if (devc->stopping_in_progress)
+       if (acq->mem_addr_next >= acq->mem_addr_stop) {
+               submit_request(sdi, STATE_READ_FINISH);
                return;
-
-       regvals = devc->reg_write_seq;
-
-       regvals[0].reg = REG_LONG_ADDR;
-       regvals[0].val = LREG_CAP_CTRL;
-
-       regvals[1].reg = REG_LONG_LOW;
-       regvals[1].val = 0;
-
-       regvals[2].reg = REG_LONG_HIGH;
-       regvals[2].val = 0;
-
-       regvals[3].reg = REG_LONG_STROBE;
-       regvals[3].val = 0;
-
-       regvals[4].reg = REG_DIV_BYPASS;
-       regvals[4].val = 0;
-
-       devc->reg_write_pos = 0;
-       devc->reg_write_len = 5;
-
-       if (issue_next_write_reg(sdi) == SR_OK) {
-               devc->stopping_in_progress = TRUE;
-               devc->state = STATE_STOP_CAPTURE;
        }
+       sr_dbg("%zu words in capture buffer.",
+              acq->mem_addr_stop - acq->mem_addr_next);
+
+       submit_request(sdi, STATE_READ_PREPARE);
 }
 
-/* Decode an incoming capture status response and act on it as appropriate.
- * Note that this function changes the device state.
+/* Evaluate and act on the response to a capture length request.
  */
-static void process_capture_status(const struct sr_dev_inst *sdi)
+static void handle_read_response(const struct sr_dev_inst *sdi)
 {
-       uint64_t duration;
        struct dev_context *devc;
        struct acquisition_state *acq;
-       unsigned int mem_fill;
-       unsigned int flags;
+       struct sr_datafeed_packet packet;
+       struct sr_datafeed_logic logic;
+       size_t end_addr;
 
        devc = sdi->priv;
        acq  = devc->acquisition;
 
-       if (acq->xfer_in->actual_length != CAP_STAT_LEN * 8) {
-               sr_err("Received size %d doesn't match expected size %d.",
-                      acq->xfer_in->actual_length, CAP_STAT_LEN * 8);
-               devc->transfer_error = TRUE;
-               return;
-       }
-
-       mem_fill = LWLA_TO_UINT32(acq->xfer_buf_in[0]);
-       duration = LWLA_TO_UINT32(acq->xfer_buf_in[4])
-               | ((uint64_t)LWLA_TO_UINT32(acq->xfer_buf_in[5]) << 32);
-       flags = LWLA_TO_UINT32(acq->xfer_buf_in[8]) & STATUS_FLAG_MASK;
+       /* Prepare session packet. */
+       packet.type    = SR_DF_LOGIC;
+       packet.payload = &logic;
+       logic.unitsize = (devc->model->num_channels + 7) / 8;
+       logic.data     = acq->out_packet;
 
-       /* The LWLA1034 runs at 125 MHz if the clock divider is bypassed.
-        * However, the time base used for the duration is apparently not
-        * adjusted for this "boost" mode.  Whereas normally the duration
-        * unit is 1 ms, it is 0.8 ms when the clock divider is bypassed.
-        * As 0.8 = 100 MHz / 125 MHz, it seems that the internal cycle
-        * counter period is the same as at the 100 MHz setting.
+       end_addr = MIN(acq->mem_addr_next, acq->mem_addr_stop);
+       acq->in_index = 0;
+       /*
+        * Repeatedly call the model-specific read response handler until
+        * all data received in the transfer has been accounted for.
         */
-       if (acq->bypass_clockdiv)
-               acq->duration_now = duration * 4 / 5;
-       else
-               acq->duration_now = duration;
-
-       sr_spew("Captured %u words, %" PRIu64 " ms, flags 0x%02X.",
-               mem_fill, acq->duration_now, flags);
+       while (!devc->cancel_requested
+                       && (acq->run_len > 0 || acq->mem_addr_done < end_addr)
+                       && acq->samples_done < acq->samples_max) {
 
-       if ((flags & STATUS_TRIGGERED) > (acq->capture_flags & STATUS_TRIGGERED))
-               sr_info("Capture triggered.");
-
-       acq->capture_flags = flags;
+               if ((*devc->model->handle_response)(sdi) != SR_OK) {
+                       devc->transfer_error = TRUE;
+                       return;
+               }
+               if (acq->out_index * logic.unitsize >= PACKET_SIZE) {
+                       /* Send off full logic packet. */
+                       logic.length = acq->out_index * logic.unitsize;
+                       sr_session_send(sdi, &packet);
+                       acq->out_index = 0;
+               }
+       }
 
-       if (acq->duration_now >= acq->duration_max) {
-               sr_dbg("Time limit reached, stopping capture.");
-               issue_stop_capture(sdi);
+       if (!devc->cancel_requested
+                       && acq->samples_done < acq->samples_max
+                       && acq->mem_addr_next < acq->mem_addr_stop) {
+               /* Request the next block. */
+               submit_request(sdi, STATE_READ_REQUEST);
                return;
        }
-       devc->state = STATE_STATUS_WAIT;
 
-       if ((acq->capture_flags & STATUS_TRIGGERED) == 0) {
-               sr_spew("Waiting for trigger.");
-       } else if ((acq->capture_flags & STATUS_MEM_AVAIL) == 0) {
-               sr_dbg("Capture memory filled.");
-               request_capture_length(sdi);
-       } else if ((acq->capture_flags & STATUS_CAPTURING) != 0) {
-               sr_spew("Sampling in progress.");
+       /* Send partially filled packet as it is the last one. */
+       if (!devc->cancel_requested && acq->out_index > 0) {
+               logic.length = acq->out_index * logic.unitsize;
+               sr_session_send(sdi, &packet);
+               acq->out_index = 0;
        }
+       submit_request(sdi, STATE_READ_FINISH);
 }
 
-/* Issue a capture buffer read request as an asynchronous USB transfer.
- * The address and size of the memory area to read are derived from the
- * current acquisition state.
+/* Destroy and unset the acquisition state record.
  */
-static void request_read_mem(const struct sr_dev_inst *sdi)
+static void clear_acquisition_state(const struct sr_dev_inst *sdi)
 {
        struct dev_context *devc;
        struct acquisition_state *acq;
-       size_t count;
 
        devc = sdi->priv;
        acq  = devc->acquisition;
 
-       if (acq->mem_addr_next >= acq->mem_addr_stop)
-               return;
-
-       /* Always read a multiple of 8 device words. */
-       count = (acq->mem_addr_stop - acq->mem_addr_next + 7) / 8 * 8;
-       count = MIN(count, READ_CHUNK_LEN);
-
-       acq->xfer_buf_out[0] = LWLA_WORD(CMD_READ_MEM);
-       acq->xfer_buf_out[1] = LWLA_WORD_0(acq->mem_addr_next);
-       acq->xfer_buf_out[2] = LWLA_WORD_1(acq->mem_addr_next);
-       acq->xfer_buf_out[3] = LWLA_WORD_0(count);
-       acq->xfer_buf_out[4] = LWLA_WORD_1(count);
-
-       acq->xfer_out->length = 5 * sizeof(uint16_t);
+       devc->acquisition = NULL;
 
-       if (submit_transfer(devc, acq->xfer_out) == SR_OK) {
-               acq->mem_addr_next += count;
-               devc->state = STATE_READ_REQUEST;
+       if (acq) {
+               libusb_free_transfer(acq->xfer_out);
+               libusb_free_transfer(acq->xfer_in);
+               g_free(acq);
        }
 }
 
-/* Demangle and decompress incoming sample data from the capture buffer.
- * The data chunk is taken from the acquisition state, and is expected to
- * contain a multiple of 8 device words.
- * All data currently in the acquisition buffer will be processed.  Packets
- * of decoded samples are sent off to the session bus whenever the output
- * buffer becomes full while decoding.
+/* USB I/O source callback.
  */
-static int process_sample_data(const struct sr_dev_inst *sdi)
+static int transfer_event(int fd, int revents, void *cb_data)
 {
-       uint64_t sample;
-       uint64_t high_nibbles;
-       uint64_t word;
+       const struct sr_dev_inst *sdi;
        struct dev_context *devc;
-       struct acquisition_state *acq;
-       uint8_t *out_p;
-       uint32_t *slice;
+       struct drv_context *drvc;
+       struct timeval tv;
        struct sr_datafeed_packet packet;
-       struct sr_datafeed_logic logic;
-       size_t expect_len;
-       size_t actual_len;
-       size_t out_max_samples;
-       size_t out_run_samples;
-       size_t ri;
-       size_t in_words_left;
-       size_t si;
+       int ret;
 
-       devc = sdi->priv;
-       acq  = devc->acquisition;
+       (void)fd;
 
-       if (acq->mem_addr_done >= acq->mem_addr_stop
-                       || acq->samples_done >= acq->samples_max)
-               return SR_OK;
+       sdi  = cb_data;
+       devc = sdi->priv;
+       drvc = sdi->driver->context;
 
-       in_words_left = MIN(acq->mem_addr_stop - acq->mem_addr_done,
-                           READ_CHUNK_LEN);
-       expect_len = LWLA1034_MEMBUF_LEN(in_words_left) * sizeof(uint32_t);
-       actual_len = acq->xfer_in->actual_length;
+       if (!devc || !drvc)
+               return G_SOURCE_REMOVE;
 
-       if (actual_len != expect_len) {
-               sr_err("Received size %zu does not match expected size %zu.",
-                      actual_len, expect_len);
+       /* Handle pending USB events without blocking. */
+       tv.tv_sec  = 0;
+       tv.tv_usec = 0;
+       ret = libusb_handle_events_timeout_completed(drvc->sr_ctx->libusb_ctx,
+                                                    &tv, NULL);
+       if (ret != 0) {
+               sr_err("Event handling failed: %s.", libusb_error_name(ret));
                devc->transfer_error = TRUE;
-               return SR_ERR;
        }
-       acq->mem_addr_done += in_words_left;
 
-       /* Prepare session packet. */
-       packet.type    = SR_DF_LOGIC;
-       packet.payload = &logic;
-       logic.unitsize = UNIT_SIZE;
-       logic.data     = acq->out_packet;
-
-       slice = acq->xfer_buf_in;
-       si = 0; /* word index within slice */
-
-       for (;;) {
-               /* Calculate number of samples to write into packet. */
-               out_max_samples = MIN(acq->samples_max - acq->samples_done,
-                                     PACKET_LENGTH - acq->out_index);
-               out_run_samples = MIN(acq->run_len, out_max_samples);
-
-               /* Expand run-length samples into session packet. */
-               sample = acq->sample;
-               out_p = &acq->out_packet[acq->out_index * UNIT_SIZE];
-
-               for (ri = 0; ri < out_run_samples; ++ri) {
-                       out_p[0] =  sample        & 0xFF;
-                       out_p[1] = (sample >>  8) & 0xFF;
-                       out_p[2] = (sample >> 16) & 0xFF;
-                       out_p[3] = (sample >> 24) & 0xFF;
-                       out_p[4] = (sample >> 32) & 0xFF;
-                       out_p += UNIT_SIZE;
-               }
-               acq->run_len -= out_run_samples;
-               acq->out_index += out_run_samples;
-               acq->samples_done += out_run_samples;
-
-               /* Packet full or sample count limit reached? */
-               if (out_run_samples == out_max_samples) {
-                       logic.length = acq->out_index * UNIT_SIZE;
-                       sr_session_send(sdi, &packet);
-                       acq->out_index = 0;
-
-                       if (acq->samples_done >= acq->samples_max)
-                               return SR_OK; /* sample limit reached */
-                       if (acq->run_len > 0)
-                               continue; /* need another packet */
-               }
-
-               if (in_words_left == 0)
-                       break; /* done with current chunk */
-
-               /* Now work on the current slice. */
-               high_nibbles = LWLA_TO_UINT32(slice[8]);
-               word = LWLA_TO_UINT32(slice[si]);
-               word |= (high_nibbles << (4 * si + 4)) & ((uint64_t)0xF << 32);
-
-               if (acq->rle == RLE_STATE_DATA) {
-                       acq->sample = word & ALL_CHANNELS_MASK;
-                       acq->run_len = ((word >> NUM_CHANNELS) & 1) + 1;
-                       if (word & RLE_FLAG_LEN_FOLLOWS)
-                               acq->rle = RLE_STATE_LEN;
-               } else {
-                       acq->run_len += word << 1;
-                       acq->rle = RLE_STATE_DATA;
-               }
-
-               /* Move to next word. */
-               si = (si + 1) % 8;
-               if (si == 0)
-                       slice += 9;
-               --in_words_left;
-       }
-
-       /* Send out partially filled packet if this was the last chunk. */
-       if (acq->mem_addr_done >= acq->mem_addr_stop && acq->out_index > 0) {
-               logic.length = acq->out_index * UNIT_SIZE;
-               sr_session_send(sdi, &packet);
-               acq->out_index = 0;
+       if (!devc->transfer_error && devc->state == STATE_STATUS_WAIT) {
+               if (devc->cancel_requested)
+                       submit_request(sdi, STATE_STOP_CAPTURE);
+               else if (revents == 0) /* status poll timeout */
+                       submit_request(sdi, STATE_STATUS_REQUEST);
        }
-       return SR_OK;
-}
-
-/* Finish an acquisition session.  This sends the end packet to the session
- * bus and removes the listener for asynchronous USB transfers.
- */
-static void end_acquisition(struct sr_dev_inst *sdi)
-{
-       struct drv_context *drvc;
-       struct dev_context *devc;
-       struct sr_datafeed_packet packet;
 
-       drvc = sdi->driver->context;
-       devc = sdi->priv;
+       /* Stop processing events if an error occurred on a transfer. */
+       if (devc->transfer_error)
+               devc->state = STATE_IDLE;
 
-       if (devc->state == STATE_IDLE)
-               return;
+       if (devc->state != STATE_IDLE)
+               return G_SOURCE_CONTINUE;
 
-       devc->state = STATE_IDLE;
+       sr_info("Acquisition stopped.");
 
-       /* Remove USB file descriptors from polling. */
-       usb_source_remove(sdi->session, drvc->sr_ctx);
+       /* We are done, clean up and send end packet to session bus. */
+       clear_acquisition_state(sdi);
 
        packet.type = SR_DF_END;
+       packet.payload = NULL;
        sr_session_send(sdi, &packet);
 
-       lwla_free_acquisition_state(devc->acquisition);
-       devc->acquisition = NULL;
-       devc->cancel_requested = FALSE;
+       return G_SOURCE_REMOVE;
 }
 
 /* USB output transfer completion callback.
  */
-static void LIBUSB_CALL receive_transfer_out(struct libusb_transfer *transfer)
+static void LIBUSB_CALL transfer_out_completed(struct libusb_transfer *transfer)
 {
-       struct sr_dev_inst *sdi;
+       const struct sr_dev_inst *sdi;
        struct dev_context *devc;
+       struct acquisition_state *acq;
 
        sdi  = transfer->user_data;
        devc = sdi->priv;
+       acq  = devc->acquisition;
 
        if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
                sr_err("Transfer to device failed: %d.", transfer->status);
@@ -615,49 +346,57 @@ static void LIBUSB_CALL receive_transfer_out(struct libusb_transfer *transfer)
                return;
        }
 
-       if (devc->reg_write_pos < devc->reg_write_len) {
-               issue_next_write_reg(sdi);
-       } else {
-               switch (devc->state) {
-               case STATE_START_CAPTURE:
+       /* If this was a read request, wait for the response. */
+       if ((devc->state & STATE_EXPECT_RESPONSE) != 0) {
+               submit_transfer(devc, acq->xfer_in);
+               return;
+       }
+       if (acq->reg_seq_pos < acq->reg_seq_len)
+               acq->reg_seq_pos++; /* register write completed */
+
+       /* Repeat until all queued registers have been written. */
+       if (acq->reg_seq_pos < acq->reg_seq_len && !devc->cancel_requested) {
+               next_reg_write(acq);
+               submit_transfer(devc, acq->xfer_out);
+               return;
+       }
+
+       switch (devc->state) {
+       case STATE_START_CAPTURE:
+               sr_info("Acquisition started.");
+
+               if (!devc->cancel_requested)
                        devc->state = STATE_STATUS_WAIT;
-                       break;
-               case STATE_STATUS_REQUEST:
-                       devc->state = STATE_STATUS_RESPONSE;
-                       submit_transfer(devc, devc->acquisition->xfer_in);
-                       break;
-               case STATE_STOP_CAPTURE:
-                       if (!devc->cancel_requested)
-                               request_capture_length(sdi);
-                       else
-                               end_acquisition(sdi);
-                       break;
-               case STATE_LENGTH_REQUEST:
-                       devc->state = STATE_LENGTH_RESPONSE;
-                       submit_transfer(devc, devc->acquisition->xfer_in);
-                       break;
-               case STATE_READ_PREPARE:
-                       request_read_mem(sdi);
-                       break;
-               case STATE_READ_REQUEST:
-                       devc->state = STATE_READ_RESPONSE;
-                       submit_transfer(devc, devc->acquisition->xfer_in);
-                       break;
-               case STATE_READ_END:
-                       end_acquisition(sdi);
-                       break;
-               default:
-                       sr_err("Unexpected device state %d.", devc->state);
-                       break;
-               }
+               else
+                       submit_request(sdi, STATE_STOP_CAPTURE);
+               break;
+       case STATE_STOP_CAPTURE:
+               if (!devc->cancel_requested)
+                       submit_request(sdi, STATE_LENGTH_REQUEST);
+               else
+                       devc->state = STATE_IDLE;
+               break;
+       case STATE_READ_PREPARE:
+               if (acq->mem_addr_next < acq->mem_addr_stop && !devc->cancel_requested)
+                       submit_request(sdi, STATE_READ_REQUEST);
+               else
+                       submit_request(sdi, STATE_READ_FINISH);
+               break;
+       case STATE_READ_FINISH:
+               devc->state = STATE_IDLE;
+               break;
+       default:
+               sr_err("Unexpected device state %d.", devc->state);
+               devc->transfer_error = TRUE;
+               break;
        }
 }
 
 /* USB input transfer completion callback.
  */
-static void LIBUSB_CALL receive_transfer_in(struct libusb_transfer *transfer)
+static void LIBUSB_CALL transfer_in_completed(struct libusb_transfer *transfer)
 {
-       struct sr_dev_inst *sdi;
+       const struct sr_dev_inst *sdi;
        struct dev_context *devc;
        struct acquisition_state *acq;
 
@@ -666,112 +405,101 @@ static void LIBUSB_CALL receive_transfer_in(struct libusb_transfer *transfer)
        acq  = devc->acquisition;
 
        if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
-               sr_err("Transfer from device failed: %d.", transfer->status);
+               sr_err("Transfer from device failed (state %d): %s.",
+                      devc->state, libusb_error_name(transfer->status));
+               devc->transfer_error = TRUE;
+               return;
+       }
+       if ((devc->state & STATE_EXPECT_RESPONSE) == 0) {
+               sr_err("Unexpected completion of input transfer (state %d).",
+                      devc->state);
                devc->transfer_error = TRUE;
                return;
        }
 
+       if (acq->reg_seq_pos < acq->reg_seq_len && !devc->cancel_requested) {
+               /* Complete register read sequence. */
+               if (read_reg_response(acq) != SR_OK) {
+                       devc->transfer_error = TRUE;
+                       return;
+               }
+               /* Repeat until all queued registers have been read. */
+               if (++acq->reg_seq_pos < acq->reg_seq_len) {
+                       next_reg_read(acq);
+                       submit_transfer(devc, acq->xfer_out);
+                       return;
+               }
+       }
+
        switch (devc->state) {
-       case STATE_STATUS_RESPONSE:
-               process_capture_status(sdi);
-               break;
-       case STATE_LENGTH_RESPONSE:
-               process_capture_length(sdi);
+       case STATE_STATUS_REQUEST:
+               if (devc->cancel_requested)
+                       submit_request(sdi, STATE_STOP_CAPTURE);
+               else
+                       handle_status_response(sdi);
                break;
-       case STATE_READ_RESPONSE:
-               if (process_sample_data(sdi) == SR_OK
-                               && acq->mem_addr_next < acq->mem_addr_stop
-                               && acq->samples_done < acq->samples_max)
-                       request_read_mem(sdi);
+       case STATE_LENGTH_REQUEST:
+               if (devc->cancel_requested)
+                       submit_request(sdi, STATE_READ_FINISH);
                else
-                       issue_read_end(sdi);
+                       handle_length_response(sdi);
+               break;
+       case STATE_READ_REQUEST:
+               handle_read_response(sdi);
                break;
        default:
                sr_err("Unexpected device state %d.", devc->state);
+               devc->transfer_error = TRUE;
                break;
        }
 }
 
-/* Initialize the LWLA.  This downloads a bitstream into the FPGA
- * and executes a simple device test sequence.
+/* Set up the acquisition state record.
  */
-SR_PRIV int lwla_init_device(const struct sr_dev_inst *sdi)
+static int init_acquisition_state(const struct sr_dev_inst *sdi)
 {
-       uint64_t value;
        struct dev_context *devc;
-       int ret;
+       struct sr_usb_dev_inst *usb;
+       struct acquisition_state *acq;
 
        devc = sdi->priv;
+       usb  = sdi->conn;
 
-       /* Force reload of bitstream */
-       devc->cur_clock_config = CONF_CLOCK_NONE;
-
-       ret = lwla_set_clock_config(sdi);
-       if (ret != SR_OK)
-               return ret;
-
-       ret = lwla_read_long_reg(sdi->conn, LREG_TEST_ID, &value);
-       if (ret != SR_OK)
-               return ret;
-
-       /* Ignore the value returned by the first read */
-       ret = lwla_read_long_reg(sdi->conn, LREG_TEST_ID, &value);
-       if (ret != SR_OK)
-               return ret;
-
-       if (value != UINT64_C(0x1234567887654321)) {
-               sr_err("Received invalid test word 0x%016" PRIX64 ".", value);
+       if (devc->acquisition) {
+               sr_err("Acquisition still in progress?");
+               return SR_ERR;
+       }
+       if (devc->cfg_clock_source == CLOCK_INTERNAL && devc->samplerate == 0) {
+               sr_err("Samplerate not set.");
                return SR_ERR;
        }
-       return SR_OK;
-}
-
-/* Select the LWLA clock configuration.  If the clock source changed from
- * the previous setting, this will download a new bitstream to the FPGA.
- */
-SR_PRIV int lwla_set_clock_config(const struct sr_dev_inst *sdi)
-{
-       struct dev_context *devc;
-       struct drv_context *drvc;
-       int ret;
-       enum clock_config choice;
 
-       devc = sdi->priv;
-       drvc = sdi->driver->context;
+       acq = g_try_malloc0(sizeof(struct acquisition_state));
+       if (!acq)
+               return SR_ERR_MALLOC;
 
-       if (sdi->status == SR_ST_INACTIVE)
-               choice = CONF_CLOCK_NONE;
-       else if (devc->cfg_clock_source == CLOCK_INTERNAL)
-               choice = CONF_CLOCK_INT;
-       else if (devc->cfg_clock_edge == EDGE_POSITIVE)
-               choice = CONF_CLOCK_EXT_RISE;
-       else
-               choice = CONF_CLOCK_EXT_FALL;
-
-       if (choice != devc->cur_clock_config) {
-               devc->cur_clock_config = CONF_CLOCK_NONE;
-               ret = lwla_send_bitstream(drvc->sr_ctx, sdi->conn,
-                                         bitstream_map[choice]);
-               if (ret == SR_OK)
-                       devc->cur_clock_config = choice;
-               return ret;
+       acq->xfer_in = libusb_alloc_transfer(0);
+       if (!acq->xfer_in) {
+               g_free(acq);
+               return SR_ERR_MALLOC;
+       }
+       acq->xfer_out = libusb_alloc_transfer(0);
+       if (!acq->xfer_out) {
+               libusb_free_transfer(acq->xfer_in);
+               g_free(acq);
+               return SR_ERR_MALLOC;
        }
-       return SR_OK;
-}
 
-/* Configure the LWLA in preparation for an acquisition session.
- */
-SR_PRIV int lwla_setup_acquisition(const struct sr_dev_inst *sdi)
-{
-       struct dev_context *devc;
-       struct sr_usb_dev_inst *usb;
-       struct acquisition_state *acq;
-       struct regval_pair regvals[7];
-       int ret;
+       libusb_fill_bulk_transfer(acq->xfer_out, usb->devhdl, EP_COMMAND,
+                                 (unsigned char *)acq->xfer_buf_out, 0,
+                                 &transfer_out_completed,
+                                 (struct sr_dev_inst *)sdi, USB_TIMEOUT_MS);
 
-       devc = sdi->priv;
-       usb  = sdi->conn;
-       acq  = devc->acquisition;
+       libusb_fill_bulk_transfer(acq->xfer_in, usb->devhdl, EP_REPLY,
+                                 (unsigned char *)acq->xfer_buf_in,
+                                 sizeof(acq->xfer_buf_in),
+                                 &transfer_in_completed,
+                                 (struct sr_dev_inst *)sdi, USB_TIMEOUT_MS);
 
        if (devc->limit_msec > 0) {
                acq->duration_max = devc->limit_msec;
@@ -790,10 +518,8 @@ SR_PRIV int lwla_setup_acquisition(const struct sr_dev_inst *sdi)
        if (devc->cfg_clock_source == CLOCK_INTERNAL) {
                sr_info("Internal clock, samplerate %" PRIu64 ".",
                        devc->samplerate);
-               if (devc->samplerate == 0)
-                       return SR_ERR_BUG;
-               /* At 125 MHz, the clock divider is bypassed. */
-               acq->bypass_clockdiv = (devc->samplerate > SR_MHZ(100));
+               /* Ramp up clock speed to enable samplerates above 100 MS/s. */
+               acq->clock_boost = (devc->samplerate > SR_MHZ(100));
 
                /* If only one of the limits is set, derive the other one. */
                if (devc->limit_msec == 0 && devc->limit_samples > 0)
@@ -803,170 +529,62 @@ SR_PRIV int lwla_setup_acquisition(const struct sr_dev_inst *sdi)
                        acq->samples_max = devc->limit_msec
                                        * devc->samplerate / 1000;
        } else {
-               acq->bypass_clockdiv = TRUE;
+               acq->clock_boost = TRUE;
 
-               if (devc->cfg_clock_edge == EDGE_NEGATIVE)
-                       sr_info("External clock, falling edge.");
-               else
+               if (devc->cfg_clock_edge == EDGE_POSITIVE)
                        sr_info("External clock, rising edge.");
+               else
+                       sr_info("External clock, falling edge.");
        }
 
-       regvals[0].reg = REG_MEM_CTRL;
-       regvals[0].val = MEM_CTRL_CLR_IDX;
-
-       regvals[1].reg = REG_MEM_CTRL;
-       regvals[1].val = MEM_CTRL_WRITE;
-
-       regvals[2].reg = REG_LONG_ADDR;
-       regvals[2].val = LREG_CAP_CTRL;
-
-       regvals[3].reg = REG_LONG_LOW;
-       regvals[3].val = CAP_CTRL_CLR_TIMEBASE | CAP_CTRL_FLUSH_FIFO
-                      | CAP_CTRL_CLR_FIFOFULL | CAP_CTRL_CLR_COUNTER;
-       regvals[4].reg = REG_LONG_HIGH;
-       regvals[4].val = 0;
+       acq->rle_enabled = devc->cfg_rle;
+       devc->acquisition = acq;
 
-       regvals[5].reg = REG_LONG_STROBE;
-       regvals[5].val = 0;
-
-       regvals[6].reg = REG_DIV_BYPASS;
-       regvals[6].val = acq->bypass_clockdiv;
-
-       ret = lwla_write_regs(usb, regvals, ARRAY_SIZE(regvals));
-       if (ret != SR_OK)
-               return ret;
-
-       return capture_setup(sdi);
+       return SR_OK;
 }
 
-/* Start the capture operation on the LWLA device.  Beginning with this
- * function, all USB transfers will be asynchronous until the end of the
- * acquisition session.
- */
 SR_PRIV int lwla_start_acquisition(const struct sr_dev_inst *sdi)
 {
+       struct drv_context *drvc;
        struct dev_context *devc;
-       struct sr_usb_dev_inst *usb;
-       struct acquisition_state *acq;
-       struct regval_pair *regvals;
+       int ret;
 
+       drvc = sdi->driver->context;
        devc = sdi->priv;
-       usb  = sdi->conn;
-       acq  = devc->acquisition;
-
-       acq->duration_now  = 0;
-       acq->mem_addr_fill = 0;
-       acq->capture_flags = 0;
 
-       libusb_fill_bulk_transfer(acq->xfer_out, usb->devhdl, EP_COMMAND,
-                                 (unsigned char *)acq->xfer_buf_out, 0,
-                                 &receive_transfer_out,
-                                 (struct sr_dev_inst *)sdi, USB_TIMEOUT_MS);
-
-       libusb_fill_bulk_transfer(acq->xfer_in, usb->devhdl, EP_REPLY,
-                                 (unsigned char *)acq->xfer_buf_in,
-                                 sizeof acq->xfer_buf_in,
-                                 &receive_transfer_in,
-                                 (struct sr_dev_inst *)sdi, USB_TIMEOUT_MS);
-
-       regvals = devc->reg_write_seq;
-
-       regvals[0].reg = REG_LONG_ADDR;
-       regvals[0].val = LREG_CAP_CTRL;
-
-       regvals[1].reg = REG_LONG_LOW;
-       regvals[1].val = CAP_CTRL_TRG_EN;
-
-       regvals[2].reg = REG_LONG_HIGH;
-       regvals[2].val = 0;
-
-       regvals[3].reg = REG_LONG_STROBE;
-       regvals[3].val = 0;
-
-       devc->reg_write_pos = 0;
-       devc->reg_write_len = 4;
-
-       devc->state = STATE_START_CAPTURE;
-
-       return issue_next_write_reg(sdi);
-}
-
-/* Allocate an acquisition state object.
- */
-SR_PRIV struct acquisition_state *lwla_alloc_acquisition_state(void)
-{
-       struct acquisition_state *acq;
+       if (devc->state != STATE_IDLE) {
+               sr_err("Not in idle state, cannot start acquisition.");
+               return SR_ERR;
+       }
+       devc->cancel_requested = FALSE;
+       devc->transfer_error = FALSE;
 
-       acq = g_malloc0(sizeof(struct acquisition_state));
+       ret = init_acquisition_state(sdi);
+       if (ret != SR_OK)
+               return ret;
 
-       acq->xfer_in = libusb_alloc_transfer(0);
-       if (!acq->xfer_in) {
-               sr_err("Transfer malloc failed.");
-               g_free(acq);
-               return NULL;
+       ret = (*devc->model->setup_acquisition)(sdi);
+       if (ret != SR_OK) {
+               sr_err("Failed to set up device for acquisition.");
+               clear_acquisition_state(sdi);
+               return ret;
        }
-
-       acq->xfer_out = libusb_alloc_transfer(0);
-       if (!acq->xfer_out) {
-               sr_err("Transfer malloc failed.");
-               libusb_free_transfer(acq->xfer_in);
-               g_free(acq);
-               return NULL;
+       /* Register event source for asynchronous USB I/O. */
+       ret = usb_source_add(sdi->session, drvc->sr_ctx, POLL_INTERVAL,
+                            &transfer_event, (struct sr_dev_inst *)sdi);
+       if (ret != SR_OK) {
+               clear_acquisition_state(sdi);
+               return ret;
        }
+       ret = submit_request(sdi, STATE_START_CAPTURE);
 
-       return acq;
-}
-
-/* Deallocate an acquisition state object.
- */
-SR_PRIV void lwla_free_acquisition_state(struct acquisition_state *acq)
-{
-       if (acq) {
-               libusb_free_transfer(acq->xfer_out);
-               libusb_free_transfer(acq->xfer_in);
-               g_free(acq);
+       if (ret == SR_OK) {
+               /* Send header packet to the session bus. */
+               ret = std_session_send_df_header(sdi, LOG_PREFIX);
        }
-}
-
-/* USB I/O source callback.
- */
-SR_PRIV int lwla_receive_data(int fd, int revents, void *cb_data)
-{
-       struct sr_dev_inst *sdi;
-       struct dev_context *devc;
-       struct drv_context *drvc;
-       struct timeval tv;
-       int ret;
-
-       (void)fd;
-
-       sdi  = cb_data;
-       devc = sdi->priv;
-       drvc = sdi->driver->context;
-
-       if (!devc || !drvc)
-               return FALSE;
-
-       /* No timeout: return immediately. */
-       tv.tv_sec  = 0;
-       tv.tv_usec = 0;
-
-       ret = libusb_handle_events_timeout_completed(drvc->sr_ctx->libusb_ctx,
-                                                    &tv, NULL);
-       if (ret != 0)
-               sr_err("Event handling failed: %s.", libusb_error_name(ret));
-
-       /* If no event flags are set the timeout must have expired. */
-       if (revents == 0 && devc->state == STATE_STATUS_WAIT) {
-               if (devc->cancel_requested)
-                       issue_stop_capture(sdi);
-               else
-                       request_capture_status(sdi);
+       if (ret != SR_OK) {
+               usb_source_remove(sdi->session, drvc->sr_ctx);
+               clear_acquisition_state(sdi);
        }
-
-       /* Check if an error occurred on a transfer. */
-       if (devc->transfer_error)
-               end_acquisition(sdi);
-
-       return TRUE;
+       return ret;
 }
index aedac6ee325374212827fbacbf4ef98b1287fbcd..355b5c0a1a9d66f1a0d79a05ae0fa73a15afe35e 100644 (file)
 #include <stdint.h>
 #include <glib.h>
 #include <libsigrok/libsigrok.h>
-#include "libsigrok-internal.h"
-#include "lwla.h"
+#include <libsigrok-internal.h>
 
-/* For now, only the LWLA1034 is supported.
- */
 #define VENDOR_NAME    "SysClk"
-#define MODEL_NAME     "LWLA1034"
-
-#define USB_VID_PID    "2961.6689"
-#define USB_CONFIG     1
-#define USB_INTERFACE  0
-#define USB_TIMEOUT_MS 3000
-
-#define NUM_CHANNELS   34
-
-/* Bit mask covering all 34 channels.
- */
-#define ALL_CHANNELS_MASK (((uint64_t)1 << NUM_CHANNELS) - 1)
-
-/** Unit and packet size for the sigrok logic datafeed.
- */
-#define UNIT_SIZE      ((NUM_CHANNELS + 7) / 8)
-#define PACKET_LENGTH  (10 * 1000)     /* units */
 
-/** Size of the acquisition buffer in device memory units.
+/* Maximum configurable sample count limit.
+ * Due to compression, there is no meaningful hardware limit the driver
+ * could report. So this value is less than 2^64-1 for no reason other
+ * than to safeguard against integer overflows.
  */
-#define MEMORY_DEPTH   (256 * 1024)    /* 256k x 36 bit */
+#define MAX_LIMIT_SAMPLES      (UINT64_C(1000) * 1000 * 1000 * 1000)
 
-/** Number of device memory units (36 bit) to read at a time.  Slices of 8
- * consecutive 36-bit words are mapped to 9 32-bit words each, so the chunk
- * length should be a multiple of 8 to ensure alignment to slice boundaries.
- *
- * Experimentation has shown that reading chunks larger than about 1024 bytes
- * is unreliable.  The threshold seems to relate to the buffer size on the FX2
- * USB chip:  The configured endpoint buffer size is 512, and with double or
- * triple buffering enabled a multiple of 512 bytes can be kept in fly.
- *
- * The vendor software limits reads to 120 words (15 slices, 540 bytes) at
- * a time.  So far, it appears safe to increase this to 224 words (28 slices,
- * 1008 bytes), thus making the most of two 512 byte buffers.
- */
-#define READ_CHUNK_LEN (28 * 8)
-
-/** Calculate the required buffer size in 32-bit units for reading a given
- * number of device memory words.  Rounded to a multiple of 8 device words.
+/* Maximum configurable acquisition time limit.
+ * Due to compression, there is no hardware limit that would be meaningful
+ * in practice. However, the LWLA1016 reports the elapsed time as a 32-bit
+ * value, so keep this below 2^32.
  */
-#define LWLA1034_MEMBUF_LEN(count) (((count) + 7) / 8 * 9)
+#define MAX_LIMIT_MSEC         (1000 * 1000 * 1000)
 
-/** Maximum number of 16-bit words sent at a time during acquisition.
- * Used for allocating the libusb transfer buffer.
- */
-#define MAX_ACQ_SEND_WORDS     8 /* 5 for memory read request plus stuffing */
-
-/** Maximum number of 32-bit words received at a time during acquisition.
- * Round to the next multiple of the endpoint buffer size to avoid nasty
- * transfer overflow conditions on hiccups.
- */
-#define MAX_ACQ_RECV_LEN       ((READ_CHUNK_LEN / 8 * 9 + 127) / 128 * 128)
+struct acquisition_state;
 
-/** Maximum length of a register write sequence.
+/* USB vendor and product IDs.
  */
-#define MAX_REG_WRITE_SEQ_LEN   5
-
-/** Default configured samplerate.
- */
-#define DEFAULT_SAMPLERATE     SR_MHZ(125)
-
-/** Maximum configurable sample count limit.
- */
-#define MAX_LIMIT_SAMPLES      (UINT64_C(1) << 48)
-
-/** Maximum configurable capture duration in milliseconds.
- */
-#define MAX_LIMIT_MSEC         (UINT64_C(1) << 32)
+enum {
+       USB_VID_SYSCLK   = 0x2961,
+       USB_PID_LWLA1016 = 0x6688,
+       USB_PID_LWLA1034 = 0x6689,
+};
 
-/** LWLA1034 FPGA clock configurations.
+/* USB device characteristics.
  */
-enum clock_config {
-       CONF_CLOCK_NONE,
-       CONF_CLOCK_INT,
-       CONF_CLOCK_EXT_RISE,
-       CONF_CLOCK_EXT_FALL,
+enum {
+       USB_CONFIG      = 1,
+       USB_INTERFACE   = 0,
+       USB_TIMEOUT_MS  = 3000,
 };
 
-/** Available clock sources.
+/** LWLA1034 clock sources.
  */
 enum clock_source {
-       CLOCK_INTERNAL,
+       CLOCK_INTERNAL = 0,
        CLOCK_EXT_CLK,
 };
 
-/** Available trigger sources.
+/** LWLA1034 trigger sources.
  */
 enum trigger_source {
        TRIGGER_CHANNELS = 0,
        TRIGGER_EXT_TRG,
 };
 
-/** Available edge choices for the external clock and trigger inputs.
+/** Edge choices for the LWLA1034 external clock and trigger inputs.
  */
 enum signal_edge {
        EDGE_POSITIVE = 0,
        EDGE_NEGATIVE,
 };
 
-/** LWLA device states.
+/* Common indicator for no or unknown FPGA config. */
+enum {
+       FPGA_NOCONF = -1,
+};
+
+/** Acquisition protocol states.
  */
-enum device_state {
+enum protocol_state {
+       /* idle states */
        STATE_IDLE = 0,
-
-       STATE_START_CAPTURE,
-
        STATE_STATUS_WAIT,
-       STATE_STATUS_REQUEST,
-       STATE_STATUS_RESPONSE,
-
+       /* device command states */
+       STATE_START_CAPTURE,
        STATE_STOP_CAPTURE,
-
-       STATE_LENGTH_REQUEST,
-       STATE_LENGTH_RESPONSE,
-
        STATE_READ_PREPARE,
+       STATE_READ_FINISH,
+       /* command followed by response */
+       STATE_EXPECT_RESPONSE = 1 << 3,
+       STATE_STATUS_REQUEST = STATE_EXPECT_RESPONSE,
+       STATE_LENGTH_REQUEST,
        STATE_READ_REQUEST,
-       STATE_READ_RESPONSE,
-       STATE_READ_END,
-};
-
-/** LWLA run-length encoding states.
- */
-enum rle_state {
-       RLE_STATE_DATA,
-       RLE_STATE_LEN
-};
-
-/** LWLA sample acquisition and decompression state.
- */
-struct acquisition_state {
-       uint64_t sample;
-       uint64_t run_len;
-
-       /** Maximum number of samples to process. */
-       uint64_t samples_max;
-       /** Number of samples sent to the session bus. */
-       uint64_t samples_done;
-
-       /** Maximum duration of capture, in milliseconds. */
-       uint64_t duration_max;
-       /** Running capture duration since trigger event. */
-       uint64_t duration_now;
-
-       /** Capture memory fill level. */
-       size_t mem_addr_fill;
-
-       size_t mem_addr_done;
-       size_t mem_addr_next;
-       size_t mem_addr_stop;
-
-       size_t out_index;
-
-       struct libusb_transfer *xfer_in;
-       struct libusb_transfer *xfer_out;
-
-       unsigned int capture_flags;
-
-       enum rle_state rle;
-
-       /** Whether to bypass the clock divider. */
-       gboolean bypass_clockdiv;
-
-       /* Payload data buffers for incoming and outgoing transfers. */
-       uint32_t xfer_buf_in[MAX_ACQ_RECV_LEN];
-       uint16_t xfer_buf_out[MAX_ACQ_SEND_WORDS];
-
-       /* Payload buffer for sigrok logic packets. */
-       uint8_t out_packet[PACKET_LENGTH * UNIT_SIZE];
 };
 
 /** Private, per-device-instance driver context.
  */
 struct dev_context {
-       /** The samplerate selected by the user. */
-       uint64_t samplerate;
-
-       /** The maximum sampling duration, in milliseconds. */
-       uint64_t limit_msec;
+       uint64_t samplerate;    /* requested samplerate */
 
-       /** The maximum number of samples to acquire. */
-       uint64_t limit_samples;
+       uint64_t limit_msec;    /* requested capture duration in ms */
+       uint64_t limit_samples; /* requested capture length in samples */
 
-       /** Channels to use. */
-       uint64_t channel_mask;
+       uint64_t channel_mask;  /* bit mask of enabled channels */
 
-       uint64_t trigger_mask;
-       uint64_t trigger_edge_mask;
-       uint64_t trigger_values;
+       uint64_t trigger_mask;          /* trigger enable mask */
+       uint64_t trigger_edge_mask;     /* trigger type mask */
+       uint64_t trigger_values;        /* trigger level/slope bits */
 
-       struct acquisition_state *acquisition;
+       const struct model_info *model;         /* device model descriptor */
+       struct acquisition_state *acquisition;  /* running capture state */
+       int active_fpga_config;                 /* FPGA configuration index */
 
-       struct regval_pair reg_write_seq[MAX_REG_WRITE_SEQ_LEN];
-       int reg_write_pos;
-       int reg_write_len;
+       enum protocol_state state;      /* async protocol state */
+       gboolean cancel_requested;      /* stop after current transfer */
+       gboolean transfer_error;        /* error during device communication */
 
-       enum device_state state;
+       gboolean cfg_rle;                       /* RLE compression setting */
+       enum clock_source cfg_clock_source;     /* clock source setting */
+       enum signal_edge cfg_clock_edge;        /* ext clock edge setting */
+       enum trigger_source cfg_trigger_source; /* trigger source setting */
+       enum signal_edge cfg_trigger_slope;     /* ext trigger slope setting */
 
-       /** The currently active clock configuration of the device. */
-       enum clock_config cur_clock_config;
+};
 
-       /** Clock source configuration setting. */
-       enum clock_source cfg_clock_source;
-       /** Clock edge configuration setting. */
-       enum signal_edge cfg_clock_edge;
+/** LWLA model descriptor.
+ */
+struct model_info {
+       char name[12];
+       int num_channels;
 
-       /** Trigger source configuration setting. */
-       enum trigger_source cfg_trigger_source;
-       /** Trigger slope configuration setting. */
-       enum signal_edge cfg_trigger_slope;
+       unsigned int num_devopts;
+       uint32_t devopts[8];
 
-       /** Whether a running acquisition should be canceled. */
-       gboolean cancel_requested;
+       unsigned int num_samplerates;
+       uint64_t samplerates[20];
 
-       /* Indicates that stopping the acquisition is currently in progress. */
-       gboolean stopping_in_progress;
+       int (*apply_fpga_config)(const struct sr_dev_inst *sdi);
+       int (*device_init_check)(const struct sr_dev_inst *sdi);
+       int (*setup_acquisition)(const struct sr_dev_inst *sdi);
 
-       /* Indicates whether a transfer failed. */
-       gboolean transfer_error;
+       int (*prepare_request)(const struct sr_dev_inst *sdi);
+       int (*handle_response)(const struct sr_dev_inst *sdi);
 };
 
-SR_PRIV struct acquisition_state *lwla_alloc_acquisition_state(void);
-SR_PRIV void lwla_free_acquisition_state(struct acquisition_state *acq);
+SR_PRIV const struct model_info lwla1016_info;
+SR_PRIV const struct model_info lwla1034_info;
 
-SR_PRIV int lwla_init_device(const struct sr_dev_inst *sdi);
-SR_PRIV int lwla_set_clock_config(const struct sr_dev_inst *sdi);
-SR_PRIV int lwla_setup_acquisition(const struct sr_dev_inst *sdi);
 SR_PRIV int lwla_start_acquisition(const struct sr_dev_inst *sdi);
-SR_PRIV int lwla_abort_acquisition(const struct sr_dev_inst *sdi);
-
-SR_PRIV int lwla_receive_data(int fd, int revents, void *cb_data);
 
 #endif