+ /* Handle USB reception. Drives sample data download. */
+ memset(&tv, 0, sizeof(tv));
+ libusb_handle_events_timeout(drvc->sr_ctx->libusb_ctx, &tv);
+
+ /*
+ * Periodically flush acquisition data in streaming mode.
+ * Without this nudge, previously received and accumulated data
+ * keeps sitting in queues and is not seen by applications.
+ */
+ if (devc->continuous && devc->stream.flush_period_ms) {
+ uint64_t now, elapsed;
+ now = g_get_monotonic_time();
+ if (!devc->stream.last_flushed)
+ devc->stream.last_flushed = now;
+ elapsed = now - devc->stream.last_flushed;
+ elapsed /= 1000;
+ if (elapsed >= devc->stream.flush_period_ms) {
+ sr_dbg("Stream mode, flushing.");
+ feed_queue_logic_flush(devc->feed_queue);
+ devc->stream.last_flushed = now;
+ }
+ }
+
+ /* Postprocess completion of sample data download. */
+ if (devc->download_finished) {
+ sr_dbg("Download finished, post processing.");
+
+ la2016_stop_acquisition(sdi);
+ usb_source_remove(sdi->session, drvc->sr_ctx);
+
+ la2016_usbxfer_cancel_all(sdi);
+ memset(&tv, 0, sizeof(tv));
+ libusb_handle_events_timeout(drvc->sr_ctx->libusb_ctx, &tv);
+
+ feed_queue_logic_flush(devc->feed_queue);
+ feed_queue_logic_free(devc->feed_queue);
+ devc->feed_queue = NULL;
+ if (devc->frame_begin_sent) {
+ std_session_send_df_frame_end(sdi);
+ devc->frame_begin_sent = FALSE;
+ }
+ std_session_send_df_end(sdi);
+
+ sr_dbg("Download finished, done post processing.");
+ }
+
+ return TRUE;
+}
+
+SR_PRIV int la2016_identify_device(const struct sr_dev_inst *sdi,
+ gboolean show_message)
+{
+ struct dev_context *devc;
+ uint8_t buf[8]; /* Larger size of manuf date and device type magic. */
+ size_t rdoff, rdlen;
+ const uint8_t *rdptr;
+ uint8_t date_yy, date_mm;
+ uint8_t dinv_yy, dinv_mm;
+ uint8_t magic;
+ size_t model_idx;
+ const struct kingst_model *model;
+ int ret;
+
+ devc = sdi->priv;
+
+ /*
+ * Four EEPROM bytes at offset 0x20 are the manufacturing date,
+ * year and month in BCD format, followed by inverted values for
+ * consistency checks. For example bytes 20 04 df fb translate
+ * to 2020-04. This information can help identify the vintage of
+ * devices when unknown magic numbers are seen.
+ */
+ rdoff = 0x20;
+ rdlen = 4 * sizeof(uint8_t);
+ ret = ctrl_in(sdi, CMD_EEPROM, rdoff, 0, buf, rdlen);
+ if (ret != SR_OK && !show_message) {
+ /* Non-fatal weak attempt during probe. Not worth logging. */
+ sr_dbg("Cannot access EEPROM.");
+ return SR_ERR_IO;
+ } else if (ret != SR_OK) {
+ /* Failed attempt in regular use. Non-fatal. Worth logging. */
+ sr_err("Cannot read manufacture date in EEPROM.");
+ } else {
+ if (sr_log_loglevel_get() >= SR_LOG_SPEW) {
+ GString *txt;
+ txt = sr_hexdump_new(buf, rdlen);
+ sr_spew("Manufacture date bytes %s.", txt->str);
+ sr_hexdump_free(txt);
+ }
+ rdptr = &buf[0];
+ date_yy = read_u8_inc(&rdptr);
+ date_mm = read_u8_inc(&rdptr);
+ dinv_yy = read_u8_inc(&rdptr);
+ dinv_mm = read_u8_inc(&rdptr);
+ sr_info("Manufacture date: 20%02hx-%02hx.", date_yy, date_mm);
+ if ((date_mm ^ dinv_mm) != 0xff || (date_yy ^ dinv_yy) != 0xff)
+ sr_warn("Manufacture date fails checksum test.");
+ }
+
+ /*
+ * Several Kingst logic analyzer devices share the same USB VID
+ * and PID. The product ID determines which MCU firmware to load.
+ * The MCU firmware provides access to EEPROM content which then
+ * allows to identify the device model. Which in turn determines
+ * which FPGA bitstream to load. Eight bytes at offset 0x08 are
+ * to get inspected.
+ *
+ * EEPROM content for model identification is kept redundantly
+ * in memory. The values are stored in verbatim and in inverted
+ * form, multiple copies are kept at different offsets. Example
+ * data:
+ *
+ * magic 0x08
+ * | ~magic 0xf7
+ * | |
+ * 08f7000008f710ef
+ * | |
+ * | ~magic backup
+ * magic backup
+ *
+ * Exclusively inspecting the magic byte appears to be sufficient,
+ * other fields seem to be 'don't care'.
+ *
+ * magic 2 == LA2016 using "kingst-la2016-fpga.bitstream"
+ * magic 3 == LA1016 using "kingst-la1016-fpga.bitstream"
+ * magic 8 == LA2016a using "kingst-la2016a1-fpga.bitstream"
+ * (latest v1.3.0 PCB, perhaps others)
+ * magic 9 == LA1016a using "kingst-la1016a1-fpga.bitstream"
+ * (latest v1.3.0 PCB, perhaps others)
+ *
+ * When EEPROM content does not match the hardware configuration
+ * (the board layout), the software may load but yield incorrect
+ * results (like swapped channels). The FPGA bitstream itself
+ * will authenticate with IC U10 and fail when its capabilities
+ * do not match the hardware model. An LA1016 won't become a
+ * LA2016 by faking its EEPROM content.
+ */
+ devc->identify_magic = 0;
+ rdoff = 0x08;
+ rdlen = 8 * sizeof(uint8_t);
+ ret = ctrl_in(sdi, CMD_EEPROM, rdoff, 0, &buf, rdlen);
+ if (ret != SR_OK) {
+ sr_err("Cannot read EEPROM device identifier bytes.");