]> sigrok.org Git - libsigrok.git/blobdiff - src/hardware/asix-sigma/protocol.c
asix-sigma: style nits, devc in routine signatures, long text lines
[libsigrok.git] / src / hardware / asix-sigma / protocol.c
index 1a667d48d74d44c3c341d3cc4c9620b783b087bd..9a45a2d95c4ae8355f99b410edb198ec35d10766 100644 (file)
 #include "protocol.h"
 
 /*
- * The ASIX Sigma supports arbitrary integer frequency divider in
- * the 50MHz mode. The divider is in range 1...256 , allowing for
- * very precise sampling rate selection. This driver supports only
- * a subset of the sampling rates.
+ * The ASIX SIGMA hardware supports fixed 200MHz and 100MHz sample rates
+ * (by means of separate firmware images). As well as 50MHz divided by
+ * an integer divider in the 1..256 range (by the "typical" firmware).
+ * Which translates to a strict lower boundary of around 195kHz.
+ *
+ * This driver "suggests" a subset of the available rates by listing a
+ * few discrete values, while setter routines accept any user specified
+ * rate that is supported by the hardware.
  */
 SR_PRIV const uint64_t samplerates[] = {
-       SR_KHZ(200),    /* div=250 */
-       SR_KHZ(250),    /* div=200 */
-       SR_KHZ(500),    /* div=100 */
-       SR_MHZ(1),      /* div=50  */
-       SR_MHZ(5),      /* div=10  */
-       SR_MHZ(10),     /* div=5   */
-       SR_MHZ(25),     /* div=2   */
-       SR_MHZ(50),     /* div=1   */
-       SR_MHZ(100),    /* Special FW needed */
-       SR_MHZ(200),    /* Special FW needed */
+       /* 50MHz and integer divider. 1/2/5 steps (where possible). */
+       SR_KHZ(200), SR_KHZ(500),
+       SR_MHZ(1), SR_MHZ(2), SR_MHZ(5),
+       SR_MHZ(10), SR_MHZ(25), SR_MHZ(50),
+       /* 100MHz/200MHz, fixed rates in special firmware. */
+       SR_MHZ(100), SR_MHZ(200),
 };
 
 SR_PRIV const size_t samplerates_count = ARRAY_SIZE(samplerates);
 
 static const char *firmware_files[] = {
-       "asix-sigma-50.fw", /* Up to 50MHz sample rate, 8bit divider. */
-       "asix-sigma-100.fw", /* 100MHz sample rate, fixed. */
-       "asix-sigma-200.fw", /* 200MHz sample rate, fixed. */
-       "asix-sigma-50sync.fw", /* Synchronous clock from external pin. */
-       "asix-sigma-phasor.fw", /* Frequency counter. */
+       [SIGMA_FW_50MHZ] = "asix-sigma-50.fw", /* 50MHz, 8bit divider. */
+       [SIGMA_FW_100MHZ] = "asix-sigma-100.fw", /* 100MHz, fixed. */
+       [SIGMA_FW_200MHZ] = "asix-sigma-200.fw", /* 200MHz, fixed. */
+       [SIGMA_FW_SYNC] = "asix-sigma-50sync.fw", /* Sync from external pin. */
+       [SIGMA_FW_FREQ] = "asix-sigma-phasor.fw", /* Frequency counter. */
 };
 
 #define SIGMA_FIRMWARE_SIZE_LIMIT (256 * 1024)
 
-static int sigma_read(void *buf, size_t size, struct dev_context *devc)
+static int sigma_read(struct dev_context *devc, void *buf, size_t size)
 {
        int ret;
 
        ret = ftdi_read_data(&devc->ftdic, (unsigned char *)buf, size);
        if (ret < 0) {
                sr_err("ftdi_read_data failed: %s",
-                      ftdi_get_error_string(&devc->ftdic));
+                       ftdi_get_error_string(&devc->ftdic));
        }
 
        return ret;
 }
 
-static int sigma_write(void *buf, size_t size, struct dev_context *devc)
+static int sigma_write(struct dev_context *devc, void *buf, size_t size)
 {
        int ret;
 
        ret = ftdi_write_data(&devc->ftdic, (unsigned char *)buf, size);
        if (ret < 0)
                sr_err("ftdi_write_data failed: %s",
-                      ftdi_get_error_string(&devc->ftdic));
+                       ftdi_get_error_string(&devc->ftdic));
        else if ((size_t) ret != size)
                sr_err("ftdi_write_data did not complete write.");
 
@@ -88,16 +88,15 @@ static int sigma_write(void *buf, size_t size, struct dev_context *devc)
  * NOTE: We chose the buffer size to be large enough to hold any write to the
  * device. We still print a message just in case.
  */
-SR_PRIV int sigma_write_register(uint8_t reg, uint8_t *data, size_t len,
-                                struct dev_context *devc)
+SR_PRIV int sigma_write_register(struct dev_context *devc,
+       uint8_t reg, uint8_t *data, size_t len)
 {
        size_t i;
        uint8_t buf[80];
        int idx = 0;
 
        if ((2 * len + 2) > sizeof(buf)) {
-               sr_err("Attempted to write %zu bytes, but buffer is too small.",
-                      len);
+               sr_err("Write buffer too small to write %zu bytes.", len);
                return SR_ERR_BUG;
        }
 
@@ -109,16 +108,17 @@ SR_PRIV int sigma_write_register(uint8_t reg, uint8_t *data, size_t len,
                buf[idx++] = REG_DATA_HIGH_WRITE | (data[i] >> 4);
        }
 
-       return sigma_write(buf, idx, devc);
+       return sigma_write(devc, buf, idx);
 }
 
-SR_PRIV int sigma_set_register(uint8_t reg, uint8_t value, struct dev_context *devc)
+SR_PRIV int sigma_set_register(struct dev_context *devc,
+       uint8_t reg, uint8_t value)
 {
-       return sigma_write_register(reg, &value, 1, devc);
+       return sigma_write_register(devc, reg, &value, sizeof(value));
 }
 
-static int sigma_read_register(uint8_t reg, uint8_t *data, size_t len,
-                              struct dev_context *devc)
+static int sigma_read_register(struct dev_context *devc,
+       uint8_t reg, uint8_t *data, size_t len)
 {
        uint8_t buf[3];
 
@@ -126,13 +126,13 @@ static int sigma_read_register(uint8_t reg, uint8_t *data, size_t len,
        buf[1] = REG_ADDR_HIGH | (reg >> 4);
        buf[2] = REG_READ_ADDR;
 
-       sigma_write(buf, sizeof(buf), devc);
+       sigma_write(devc, buf, sizeof(buf));
 
-       return sigma_read(data, len, devc);
+       return sigma_read(devc, data, len);
 }
 
-static int sigma_read_pos(uint32_t *stoppos, uint32_t *triggerpos,
-                         struct dev_context *devc)
+static int sigma_read_pos(struct dev_context *devc,
+       uint32_t *stoppos, uint32_t *triggerpos)
 {
        /*
         * Read 6 registers starting at trigger position LSB.
@@ -149,9 +149,9 @@ static int sigma_read_pos(uint32_t *stoppos, uint32_t *triggerpos,
        };
        uint8_t result[6];
 
-       sigma_write(buf, sizeof(buf), devc);
+       sigma_write(devc, buf, sizeof(buf));
 
-       sigma_read(result, sizeof(result), devc);
+       sigma_read(devc, result, sizeof(result));
 
        *triggerpos = result[0] | (result[1] << 8) | (result[2] << 16);
        *stoppos = result[3] | (result[4] << 8) | (result[5] << 16);
@@ -180,8 +180,8 @@ static int sigma_read_pos(uint32_t *stoppos, uint32_t *triggerpos,
        return 1;
 }
 
-static int sigma_read_dram(uint16_t startchunk, size_t numchunks,
-                          uint8_t *data, struct dev_context *devc)
+static int sigma_read_dram(struct dev_context *devc,
+       uint16_t startchunk, size_t numchunks, uint8_t *data)
 {
        uint8_t buf[4096];
        int idx;
@@ -193,7 +193,7 @@ static int sigma_read_dram(uint16_t startchunk, size_t numchunks,
        idx = 0;
        buf[idx++] = startchunk >> 8;
        buf[idx++] = startchunk & 0xff;
-       sigma_write_register(WRITE_MEMROW, buf, idx, devc);
+       sigma_write_register(devc, WRITE_MEMROW, buf, idx);
 
        /*
         * Access DRAM content. Fetch from DRAM to FPGA's internal RAM,
@@ -212,13 +212,14 @@ static int sigma_read_dram(uint16_t startchunk, size_t numchunks,
                if (!is_last)
                        buf[idx++] = REG_DRAM_WAIT_ACK;
        }
-       sigma_write(buf, idx, devc);
+       sigma_write(devc, buf, idx);
 
-       return sigma_read(data, numchunks * ROW_LENGTH_BYTES, devc);
+       return sigma_read(devc, data, numchunks * ROW_LENGTH_BYTES);
 }
 
 /* Upload trigger look-up tables to Sigma. */
-SR_PRIV int sigma_write_trigger_lut(struct triggerlut *lut, struct dev_context *devc)
+SR_PRIV int sigma_write_trigger_lut(struct dev_context *devc,
+       struct triggerlut *lut)
 {
        int i;
        uint8_t tmp[2];
@@ -264,14 +265,14 @@ SR_PRIV int sigma_write_trigger_lut(struct triggerlut *lut, struct dev_context *
                if (lut->m1d[3] & bit)
                        tmp[1] |= 0x80;
 
-               sigma_write_register(WRITE_TRIGGER_SELECT, tmp, sizeof(tmp),
-                                    devc);
-               sigma_set_register(WRITE_TRIGGER_SELECT2, 0x30 | i, devc);
+               sigma_write_register(devc, WRITE_TRIGGER_SELECT,
+                       tmp, sizeof(tmp));
+               sigma_set_register(devc, WRITE_TRIGGER_SELECT2, 0x30 | i);
        }
 
        /* Send the parameters */
-       sigma_write_register(WRITE_TRIGGER_SELECT, (uint8_t *) &lut->params,
-                            sizeof(lut->params), devc);
+       sigma_write_register(devc, WRITE_TRIGGER_SELECT,
+               (uint8_t *)&lut->params, sizeof(lut->params));
 
        return SR_OK;
 }
@@ -313,10 +314,16 @@ SR_PRIV int sigma_write_trigger_lut(struct triggerlut *lut, struct dev_context *
 /*
  * Initiate slave serial mode for configuration download. Which is done
  * by pulsing PROG_B and sensing INIT_B. Make sure CCLK is idle before
- * initiating the configuration download. Run a "suicide sequence" first
- * to terminate the regular FPGA operation before reconfiguration.
+ * initiating the configuration download.
+ *
+ * Run a "suicide sequence" first to terminate the regular FPGA operation
+ * before reconfiguration. The FTDI cable is single channel, and shares
+ * pins which are used for data communication in FIFO mode with pins that
+ * are used for FPGA configuration in bitbang mode. Hardware defaults for
+ * unconfigured hardware, and runtime conditions after FPGA configuration
+ * need to cooperate such that re-configuration of the FPGA can start.
  */
-static int sigma_fpga_init_bitbang(struct dev_context *devc)
+static int sigma_fpga_init_bitbang_once(struct dev_context *devc)
 {
        uint8_t suicide[] = {
                BB_PIN_D7 | BB_PIN_D2,
@@ -344,19 +351,21 @@ static int sigma_fpga_init_bitbang(struct dev_context *devc)
        uint8_t data;
 
        /* Section 2. part 1), do the FPGA suicide. */
-       sigma_write(suicide, sizeof(suicide), devc);
-       sigma_write(suicide, sizeof(suicide), devc);
-       sigma_write(suicide, sizeof(suicide), devc);
-       sigma_write(suicide, sizeof(suicide), devc);
+       sigma_write(devc, suicide, sizeof(suicide));
+       sigma_write(devc, suicide, sizeof(suicide));
+       sigma_write(devc, suicide, sizeof(suicide));
+       sigma_write(devc, suicide, sizeof(suicide));
+       g_usleep(10 * 1000);
 
        /* Section 2. part 2), pulse PROG. */
-       sigma_write(init_array, sizeof(init_array), devc);
+       sigma_write(devc, init_array, sizeof(init_array));
+       g_usleep(10 * 1000);
        ftdi_usb_purge_buffers(&devc->ftdic);
 
        /* Wait until the FPGA asserts INIT_B. */
        retries = 10;
        while (retries--) {
-               ret = sigma_read(&data, 1, devc);
+               ret = sigma_read(devc, &data, 1);
                if (ret < 0)
                        return ret;
                if (data & BB_PIN_INIT)
@@ -367,6 +376,27 @@ static int sigma_fpga_init_bitbang(struct dev_context *devc)
        return SR_ERR_TIMEOUT;
 }
 
+/*
+ * This is belt and braces. Re-run the bitbang initiation sequence a few
+ * times should first attempts fail. Failure is rare but can happen (was
+ * observed during driver development).
+ */
+static int sigma_fpga_init_bitbang(struct dev_context *devc)
+{
+       size_t retries;
+       int ret;
+
+       retries = 10;
+       while (retries--) {
+               ret = sigma_fpga_init_bitbang_once(devc);
+               if (ret == SR_OK)
+                       return ret;
+               if (ret != SR_ERR_TIMEOUT)
+                       return ret;
+       }
+       return ret;
+}
+
 /*
  * Configure the FPGA for logic-analyzer mode.
  */
@@ -379,7 +409,7 @@ static int sigma_fpga_init_la(struct dev_context *devc)
        uint8_t mode_regval = WMR_SDRAMINIT;
        uint8_t logic_mode_start[] = {
                /* Read ID register. */
-               REG_ADDR_LOW  | (READ_ID & 0xf),
+               REG_ADDR_LOW | (READ_ID & 0xf),
                REG_ADDR_HIGH | (READ_ID >> 4),
                REG_READ_ADDR,
 
@@ -406,8 +436,8 @@ static int sigma_fpga_init_la(struct dev_context *devc)
         * Send the command sequence which contains 3 READ requests.
         * Expect to see the corresponding 3 response bytes.
         */
-       sigma_write(logic_mode_start, sizeof(logic_mode_start), devc);
-       ret = sigma_read(result, ARRAY_SIZE(result), devc);
+       sigma_write(devc, logic_mode_start, sizeof(logic_mode_start));
+       ret = sigma_read(devc, result, ARRAY_SIZE(result));
        if (ret != ARRAY_SIZE(result))
                goto err;
        if (result[0] != 0xa6 || result[1] != 0x55 || result[2] != 0xaa)
@@ -426,7 +456,7 @@ err:
  * by the caller of this function.
  */
 static int sigma_fw_2_bitbang(struct sr_context *ctx, const char *name,
-                             uint8_t **bb_cmd, gsize *bb_cmd_size)
+       uint8_t **bb_cmd, gsize *bb_cmd_size)
 {
        uint8_t *firmware;
        size_t file_size;
@@ -495,8 +525,8 @@ static int sigma_fw_2_bitbang(struct sr_context *ctx, const char *name,
        return SR_OK;
 }
 
-static int upload_firmware(struct sr_context *ctx,
-               int firmware_idx, struct dev_context *devc)
+static int upload_firmware(struct sr_context *ctx, struct dev_context *devc,
+       enum sigma_firmware_idx firmware_idx)
 {
        int ret;
        unsigned char *buf;
@@ -504,24 +534,32 @@ static int upload_firmware(struct sr_context *ctx,
        size_t buf_size;
        const char *firmware;
 
-       /* Avoid downloading the same firmware multiple times. */
+       /* Check for valid firmware file selection. */
+       if (firmware_idx >= ARRAY_SIZE(firmware_files))
+               return SR_ERR_ARG;
        firmware = firmware_files[firmware_idx];
-       if (devc->cur_firmware == firmware_idx) {
+       if (!firmware || !*firmware)
+               return SR_ERR_ARG;
+
+       /* Avoid downloading the same firmware multiple times. */
+       if (devc->firmware_idx == firmware_idx) {
                sr_info("Not uploading firmware file '%s' again.", firmware);
                return SR_OK;
        }
 
+       devc->state.state = SIGMA_CONFIG;
+
        /* Set the cable to bitbang mode. */
        ret = ftdi_set_bitmode(&devc->ftdic, BB_PINMASK, BITMODE_BITBANG);
        if (ret < 0) {
                sr_err("ftdi_set_bitmode failed: %s",
-                      ftdi_get_error_string(&devc->ftdic));
+                       ftdi_get_error_string(&devc->ftdic));
                return SR_ERR;
        }
        ret = ftdi_set_baudrate(&devc->ftdic, BB_BITRATE);
        if (ret < 0) {
                sr_err("ftdi_set_baudrate failed: %s",
-                      ftdi_get_error_string(&devc->ftdic));
+                       ftdi_get_error_string(&devc->ftdic));
                return SR_ERR;
        }
 
@@ -533,14 +571,13 @@ static int upload_firmware(struct sr_context *ctx,
        /* Prepare wire format of the firmware image. */
        ret = sigma_fw_2_bitbang(ctx, firmware, &buf, &buf_size);
        if (ret != SR_OK) {
-               sr_err("An error occurred while reading the firmware: %s",
-                      firmware);
+               sr_err("Could not prepare file %s for download.", firmware);
                return ret;
        }
 
        /* Write the FPGA netlist to the cable. */
        sr_info("Uploading firmware file '%s'.", firmware);
-       sigma_write(buf, buf_size, devc);
+       sigma_write(devc, buf, buf_size);
 
        g_free(buf);
 
@@ -548,11 +585,11 @@ static int upload_firmware(struct sr_context *ctx,
        ret = ftdi_set_bitmode(&devc->ftdic, 0, BITMODE_RESET);
        if (ret < 0) {
                sr_err("ftdi_set_bitmode failed: %s",
-                      ftdi_get_error_string(&devc->ftdic));
+                       ftdi_get_error_string(&devc->ftdic));
                return SR_ERR;
        }
        ftdi_usb_purge_buffers(&devc->ftdic);
-       while (sigma_read(&pins, 1, devc) == 1)
+       while (sigma_read(devc, &pins, 1) == 1)
                ;
 
        /* Initialize the FPGA for logic-analyzer mode. */
@@ -561,55 +598,140 @@ static int upload_firmware(struct sr_context *ctx,
                return ret;
 
        /* Keep track of successful firmware download completion. */
-       devc->cur_firmware = firmware_idx;
+       devc->state.state = SIGMA_IDLE;
+       devc->firmware_idx = firmware_idx;
        sr_info("Firmware uploaded.");
 
        return SR_OK;
 }
 
 /*
- * Sigma doesn't support limiting the number of samples, so we have to
- * translate the number and the samplerate to an elapsed time.
+ * The driver supports user specified time or sample count limits. The
+ * device's hardware supports neither, and hardware compression prevents
+ * reliable detection of "fill levels" (currently reached sample counts)
+ * from register values during acquisition. That's why the driver needs
+ * to apply some heuristics:
+ *
+ * - The (optional) sample count limit and the (normalized) samplerate
+ *   get mapped to an estimated duration for these samples' acquisition.
+ * - The (optional) time limit gets checked as well. The lesser of the
+ *   two limits will terminate the data acquisition phase. The exact
+ *   sample count limit gets enforced in session feed submission paths.
+ * - Some slack needs to be given to account for hardware pipelines as
+ *   well as late storage of last chunks after compression thresholds
+ *   are tripped. The resulting data set will span at least the caller
+ *   specified period of time, which shall be perfectly acceptable.
  *
- * In addition we need to ensure that the last data cluster has passed
- * the hardware pipeline, and became available to the PC side. With RLE
- * compression up to 327ms could pass before another cluster accumulates
- * at 200kHz samplerate when input pins don't change.
+ * With RLE compression active, up to 64K sample periods can pass before
+ * a cluster accumulates. Which translates to 327ms at 200kHz. Add two
+ * times that period for good measure, one is not enough to flush the
+ * hardware pipeline (observation from an earlier experiment).
  */
-SR_PRIV uint64_t sigma_limit_samples_to_msec(const struct dev_context *devc,
-                                            uint64_t limit_samples)
+SR_PRIV int sigma_set_acquire_timeout(struct dev_context *devc)
 {
-       uint64_t limit_msec;
+       int ret;
+       GVariant *data;
+       uint64_t user_count, user_msecs;
        uint64_t worst_cluster_time_ms;
+       uint64_t count_msecs, acquire_msecs;
 
-       limit_msec = limit_samples * 1000 / devc->cur_samplerate;
-       worst_cluster_time_ms = 65536 * 1000 / devc->cur_samplerate;
-       /*
-        * One cluster time is not enough to flush pipeline when sampling
-        * grounded pins with 1 sample limit at 200kHz. Hence the 2* fix.
-        */
-       return limit_msec + 2 * worst_cluster_time_ms;
+       sr_sw_limits_init(&devc->acq_limits);
+
+       /* Get sample count limit, convert to msecs. */
+       ret = sr_sw_limits_config_get(&devc->cfg_limits,
+               SR_CONF_LIMIT_SAMPLES, &data);
+       if (ret != SR_OK)
+               return ret;
+       user_count = g_variant_get_uint64(data);
+       g_variant_unref(data);
+       count_msecs = 0;
+       if (user_count)
+               count_msecs = 1000 * user_count / devc->samplerate + 1;
+
+       /* Get time limit, which is in msecs. */
+       ret = sr_sw_limits_config_get(&devc->cfg_limits,
+               SR_CONF_LIMIT_MSEC, &data);
+       if (ret != SR_OK)
+               return ret;
+       user_msecs = g_variant_get_uint64(data);
+       g_variant_unref(data);
+
+       /* Get the lesser of them, with both being optional. */
+       acquire_msecs = ~0ull;
+       if (user_count && count_msecs < acquire_msecs)
+               acquire_msecs = count_msecs;
+       if (user_msecs && user_msecs < acquire_msecs)
+               acquire_msecs = user_msecs;
+       if (acquire_msecs == ~0ull)
+               return SR_OK;
+
+       /* Add some slack, and use that timeout for acquisition. */
+       worst_cluster_time_ms = 1000 * 65536 / devc->samplerate;
+       acquire_msecs += 2 * worst_cluster_time_ms;
+       data = g_variant_new_uint64(acquire_msecs);
+       ret = sr_sw_limits_config_set(&devc->acq_limits,
+               SR_CONF_LIMIT_MSEC, data);
+       g_variant_unref(data);
+       if (ret != SR_OK)
+               return ret;
+
+       sr_sw_limits_acquisition_start(&devc->acq_limits);
+       return SR_OK;
 }
 
-SR_PRIV int sigma_set_samplerate(const struct sr_dev_inst *sdi, uint64_t samplerate)
+/*
+ * Check whether a caller specified samplerate matches the device's
+ * hardware constraints (can be used for acquisition). Optionally yield
+ * a value that approximates the original spec.
+ *
+ * This routine assumes that input specs are in the 200kHz to 200MHz
+ * range of supported rates, and callers typically want to normalize a
+ * given value to the hardware capabilities. Values in the 50MHz range
+ * get rounded up by default, to avoid a more expensive check for the
+ * closest match, while higher sampling rate is always desirable during
+ * measurement. Input specs which exactly match hardware capabilities
+ * remain unaffected. Because 100/200MHz rates also limit the number of
+ * available channels, they are not suggested by this routine, instead
+ * callers need to pick them consciously.
+ */
+SR_PRIV int sigma_normalize_samplerate(uint64_t want_rate, uint64_t *have_rate)
+{
+       uint64_t div, rate;
+
+       /* Accept exact matches for 100/200MHz. */
+       if (want_rate == SR_MHZ(200) || want_rate == SR_MHZ(100)) {
+               if (have_rate)
+                       *have_rate = want_rate;
+               return SR_OK;
+       }
+
+       /* Accept 200kHz to 50MHz range, and map to near value. */
+       if (want_rate >= SR_KHZ(200) && want_rate <= SR_MHZ(50)) {
+               div = SR_MHZ(50) / want_rate;
+               rate = SR_MHZ(50) / div;
+               if (have_rate)
+                       *have_rate = rate;
+               return SR_OK;
+       }
+
+       return SR_ERR_ARG;
+}
+
+SR_PRIV int sigma_set_samplerate(const struct sr_dev_inst *sdi)
 {
        struct dev_context *devc;
        struct drv_context *drvc;
-       size_t i;
+       uint64_t samplerate;
        int ret;
        int num_channels;
 
        devc = sdi->priv;
        drvc = sdi->driver->context;
-       ret = SR_OK;
 
-       /* Reject rates that are not in the list of supported rates. */
-       for (i = 0; i < samplerates_count; i++) {
-               if (samplerates[i] == samplerate)
-                       break;
-       }
-       if (i >= samplerates_count || samplerates[i] == 0)
-               return SR_ERR_SAMPLERATE;
+       /* Accept any caller specified rate which the hardware supports. */
+       ret = sigma_normalize_samplerate(devc->samplerate, &samplerate);
+       if (ret != SR_OK)
+               return ret;
 
        /*
         * Depending on the samplerates of 200/100/50- MHz, specific
@@ -618,38 +740,24 @@ SR_PRIV int sigma_set_samplerate(const struct sr_dev_inst *sdi, uint64_t sampler
         */
        num_channels = devc->num_channels;
        if (samplerate <= SR_MHZ(50)) {
-               ret = upload_firmware(drvc->sr_ctx, 0, devc);
+               ret = upload_firmware(drvc->sr_ctx, devc, SIGMA_FW_50MHZ);
                num_channels = 16;
        } else if (samplerate == SR_MHZ(100)) {
-               ret = upload_firmware(drvc->sr_ctx, 1, devc);
+               ret = upload_firmware(drvc->sr_ctx, devc, SIGMA_FW_100MHZ);
                num_channels = 8;
        } else if (samplerate == SR_MHZ(200)) {
-               ret = upload_firmware(drvc->sr_ctx, 2, devc);
+               ret = upload_firmware(drvc->sr_ctx, devc, SIGMA_FW_200MHZ);
                num_channels = 4;
        }
 
        /*
-        * Derive the sample period from the sample rate as well as the
-        * number of samples that the device will communicate within
-        * an "event" (memory organization internal to the device).
+        * The samplerate affects the number of available logic channels
+        * as well as a sample memory layout detail (the number of samples
+        * which the device will communicate within an "event").
         */
        if (ret == SR_OK) {
                devc->num_channels = num_channels;
-               devc->cur_samplerate = samplerate;
                devc->samples_per_event = 16 / devc->num_channels;
-               devc->state.state = SIGMA_IDLE;
-       }
-
-       /*
-        * Support for "limit_samples" is implemented by stopping
-        * acquisition after a corresponding period of time.
-        * Re-calculate that period of time, in case the limit is
-        * set first and the samplerate gets (re-)configured later.
-        */
-       if (ret == SR_OK && devc->limit_samples) {
-               uint64_t msecs;
-               msecs = sigma_limit_samples_to_msec(devc, devc->limit_samples);
-               devc->limit_msec = msecs;
        }
 
        return ret;
@@ -674,7 +782,6 @@ struct submit_buffer {
        struct sr_dev_inst *sdi;
        struct sr_datafeed_packet packet;
        struct sr_datafeed_logic logic;
-       struct sr_sw_limits limit_samples;
 };
 
 static int alloc_submit_buffer(struct sr_dev_inst *sdi)
@@ -697,7 +804,7 @@ static int alloc_submit_buffer(struct sr_dev_inst *sdi)
        if (!buffer->sample_data)
                return SR_ERR_MALLOC;
        buffer->write_pointer = buffer->sample_data;
-       sr_sw_limits_init(&buffer->limit_samples);
+       sr_sw_limits_init(&devc->feed_limits);
 
        buffer->sdi = sdi;
        memset(&buffer->logic, 0, sizeof(buffer->logic));
@@ -710,26 +817,33 @@ static int alloc_submit_buffer(struct sr_dev_inst *sdi)
        return SR_OK;
 }
 
-static int setup_submit_buffer(struct dev_context *devc)
+static int setup_submit_limit(struct dev_context *devc)
 {
-       struct submit_buffer *buffer;
+       struct sr_sw_limits *limits;
        int ret;
        GVariant *data;
        uint64_t total;
 
-       buffer = devc->buffer;
+       limits = &devc->feed_limits;
+
+       ret = sr_sw_limits_config_get(&devc->cfg_limits,
+               SR_CONF_LIMIT_SAMPLES, &data);
+       if (ret != SR_OK)
+               return ret;
+       total = g_variant_get_uint64(data);
+       g_variant_unref(data);
 
-       total = devc->limit_samples;
+       sr_sw_limits_init(limits);
        if (total) {
                data = g_variant_new_uint64(total);
-               ret = sr_sw_limits_config_set(&buffer->limit_samples,
+               ret = sr_sw_limits_config_set(limits,
                        SR_CONF_LIMIT_SAMPLES, data);
                g_variant_unref(data);
                if (ret != SR_OK)
                        return ret;
        }
 
-       sr_sw_limits_acquisition_start(&buffer->limit_samples);
+       sr_sw_limits_acquisition_start(limits);
 
        return SR_OK;
 }
@@ -778,10 +892,12 @@ static int addto_submit_buffer(struct dev_context *devc,
        uint16_t sample, size_t count)
 {
        struct submit_buffer *buffer;
+       struct sr_sw_limits *limits;
        int ret;
 
        buffer = devc->buffer;
-       if (sr_sw_limits_check(&buffer->limit_samples))
+       limits = &devc->feed_limits;
+       if (sr_sw_limits_check(limits))
                count = 0;
 
        /*
@@ -798,8 +914,8 @@ static int addto_submit_buffer(struct dev_context *devc,
                        if (ret != SR_OK)
                                return ret;
                }
-               sr_sw_limits_update_samples_read(&buffer->limit_samples, 1);
-               if (sr_sw_limits_check(&buffer->limit_samples))
+               sr_sw_limits_update_samples_read(limits, 1);
+               if (sr_sw_limits_check(limits))
                        break;
        }
 
@@ -833,15 +949,15 @@ SR_PRIV int sigma_convert_trigger(const struct sr_dev_inst *sdi)
                stage = l->data;
                for (m = stage->matches; m; m = m->next) {
                        match = m->data;
+                       /* Ignore disabled channels with a trigger. */
                        if (!match->channel->enabled)
-                               /* Ignore disabled channels with a trigger. */
                                continue;
                        channelbit = 1 << (match->channel->index);
-                       if (devc->cur_samplerate >= SR_MHZ(100)) {
+                       if (devc->samplerate >= SR_MHZ(100)) {
                                /* Fast trigger support. */
                                if (trigger_set) {
                                        sr_err("Only a single pin trigger is "
-                                                       "supported in 100 and 200MHz mode.");
+                                               "supported in 100 and 200MHz mode.");
                                        return SR_ERR;
                                }
                                if (match->match == SR_TRIGGER_FALLING)
@@ -850,7 +966,7 @@ SR_PRIV int sigma_convert_trigger(const struct sr_dev_inst *sdi)
                                        devc->trigger.risingmask |= channelbit;
                                else {
                                        sr_err("Only rising/falling trigger is "
-                                                       "supported in 100 and 200MHz mode.");
+                                               "supported in 100 and 200MHz mode.");
                                        return SR_ERR;
                                }
 
@@ -877,8 +993,7 @@ SR_PRIV int sigma_convert_trigger(const struct sr_dev_inst *sdi)
                                 * does not permit ORed triggers.
                                 */
                                if (trigger_set > 1) {
-                                       sr_err("Only 1 rising/falling trigger "
-                                                  "is supported.");
+                                       sr_err("Only 1 rising/falling trigger is supported.");
                                        return SR_ERR;
                                }
                        }
@@ -890,7 +1005,7 @@ SR_PRIV int sigma_convert_trigger(const struct sr_dev_inst *sdi)
 
 /* Software trigger to determine exact trigger position. */
 static int get_trigger_offset(uint8_t *samples, uint16_t last_sample,
-                             struct sigma_trigger *t)
+       struct sigma_trigger *t)
 {
        int i;
        uint16_t sample = 0;
@@ -1051,8 +1166,9 @@ static void sigma_decode_dram_cluster(struct dev_context *devc,
        tsdiff = ts - ss->lastts;
        if (tsdiff > 0) {
                size_t count;
+               sample = ss->lastsample;
                count = tsdiff * devc->samples_per_event;
-               (void)check_and_submit_sample(devc, ss->lastsample, count, FALSE);
+               (void)check_and_submit_sample(devc, sample, count, FALSE);
        }
        ss->lastts = ts + EVENTS_PER_CLUSTER;
 
@@ -1066,7 +1182,7 @@ static void sigma_decode_dram_cluster(struct dev_context *devc,
        sample = 0;
        for (i = 0; i < events_in_cluster; i++) {
                item16 = sigma_dram_cluster_data(dram_cluster, i);
-               if (devc->cur_samplerate == SR_MHZ(200)) {
+               if (devc->samplerate == SR_MHZ(200)) {
                        sample = sigma_deinterlace_200mhz_data(item16, 0);
                        check_and_submit_sample(devc, sample, 1, triggered);
                        sample = sigma_deinterlace_200mhz_data(item16, 1);
@@ -1075,7 +1191,7 @@ static void sigma_decode_dram_cluster(struct dev_context *devc,
                        check_and_submit_sample(devc, sample, 1, triggered);
                        sample = sigma_deinterlace_200mhz_data(item16, 3);
                        check_and_submit_sample(devc, sample, 1, triggered);
-               } else if (devc->cur_samplerate == SR_MHZ(100)) {
+               } else if (devc->samplerate == SR_MHZ(100)) {
                        sample = sigma_deinterlace_100mhz_data(item16, 0);
                        check_and_submit_sample(devc, sample, 1, triggered);
                        sample = sigma_deinterlace_100mhz_data(item16, 1);
@@ -1114,7 +1230,7 @@ static int decode_chunk_ts(struct dev_context *devc,
 
        /* Check if trigger is in this chunk. */
        if (trigger_event < EVENTS_PER_ROW) {
-               if (devc->cur_samplerate <= SR_MHZ(50)) {
+               if (devc->samplerate <= SR_MHZ(50)) {
                        trigger_event -= MIN(EVENTS_PER_CLUSTER - 1,
                                             trigger_event);
                }
@@ -1170,22 +1286,22 @@ static int download_capture(struct sr_dev_inst *sdi)
         * clusters to DRAM regardless of whether pin state changes) and
         * raise the POSTTRIGGERED flag.
         */
-       sigma_set_register(WRITE_MODE, WMR_FORCESTOP | WMR_SDRAMWRITEEN, devc);
+       sigma_set_register(devc, WRITE_MODE, WMR_FORCESTOP | WMR_SDRAMWRITEEN);
        do {
-               if (sigma_read_register(READ_MODE, &modestatus, 1, devc) != 1) {
+               if (sigma_read_register(devc, READ_MODE, &modestatus, 1) != 1) {
                        sr_err("failed while waiting for RMR_POSTTRIGGERED bit");
                        return FALSE;
                }
        } while (!(modestatus & RMR_POSTTRIGGERED));
 
        /* Set SDRAM Read Enable. */
-       sigma_set_register(WRITE_MODE, WMR_SDRAMREADEN, devc);
+       sigma_set_register(devc, WRITE_MODE, WMR_SDRAMREADEN);
 
        /* Get the current position. */
-       sigma_read_pos(&stoppos, &triggerpos, devc);
+       sigma_read_pos(devc, &stoppos, &triggerpos);
 
        /* Check if trigger has fired. */
-       if (sigma_read_register(READ_MODE, &modestatus, 1, devc) != 1) {
+       if (sigma_read_register(devc, READ_MODE, &modestatus, 1) != 1) {
                sr_err("failed to read READ_MODE register");
                return FALSE;
        }
@@ -1196,8 +1312,6 @@ static int download_capture(struct sr_dev_inst *sdi)
                trg_event = triggerpos & 0x1ff;
        }
 
-       devc->sent_samples = 0;
-
        /*
         * Determine how many "DRAM lines" of 1024 bytes each we need to
         * retrieve from the Sigma hardware, so that we have a complete
@@ -1220,7 +1334,7 @@ static int download_capture(struct sr_dev_inst *sdi)
        ret = alloc_submit_buffer(sdi);
        if (ret != SR_OK)
                return FALSE;
-       ret = setup_submit_buffer(devc);
+       ret = setup_submit_limit(devc);
        if (ret != SR_OK)
                return FALSE;
        dl_lines_done = 0;
@@ -1230,8 +1344,8 @@ static int download_capture(struct sr_dev_inst *sdi)
 
                dl_line = dl_first_line + dl_lines_done;
                dl_line %= ROW_COUNT;
-               bufsz = sigma_read_dram(dl_line, dl_lines_curr,
-                                       (uint8_t *)dram_line, devc);
+               bufsz = sigma_read_dram(devc, dl_line, dl_lines_curr,
+                                       (uint8_t *)dram_line);
                /* TODO: Check bufsz. For now, just avoid compiler warnings. */
                (void)bufsz;
 
@@ -1278,18 +1392,9 @@ static int download_capture(struct sr_dev_inst *sdi)
 static int sigma_capture_mode(struct sr_dev_inst *sdi)
 {
        struct dev_context *devc;
-       uint64_t running_msec;
-       uint64_t current_time;
 
        devc = sdi->priv;
-
-       /*
-        * Check if the selected sampling duration passed. Sample count
-        * limits are covered by this enforced timeout as well.
-        */
-       current_time = g_get_monotonic_time();
-       running_msec = (current_time - devc->start_time) / 1000;
-       if (running_msec >= devc->limit_msec)
+       if (sr_sw_limits_check(&devc->acq_limits))
                return download_capture(sdi);
 
        return TRUE;
@@ -1349,7 +1454,7 @@ static void build_lut_entry(uint16_t value, uint16_t mask, uint16_t *entry)
 
 /* Add a logical function to LUT mask. */
 static void add_trigger_function(enum triggerop oper, enum triggerfunc func,
-                                int index, int neg, uint16_t *mask)
+       int index, int neg, uint16_t *mask)
 {
        int i, j;
        int x[2][2], tmp, a, b, aset, bset, rset;
@@ -1434,7 +1539,8 @@ static void add_trigger_function(enum triggerop oper, enum triggerfunc func,
  * simple pin change and state triggers. Only two transitions (rise/fall) can be
  * set at any time, but a full mask and value can be set (0/1).
  */
-SR_PRIV int sigma_build_basic_trigger(struct triggerlut *lut, struct dev_context *devc)
+SR_PRIV int sigma_build_basic_trigger(struct dev_context *devc,
+       struct triggerlut *lut)
 {
        int i,j;
        uint16_t masks[2] = { 0, 0 };