+ /*
+ * 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;
+ if ((ret = ctrl_in(sdi, CMD_EEPROM, 0x08, 0, &buf, sizeof(buf))) != SR_OK) {
+ sr_err("Cannot read EEPROM device identifier bytes.");
+ return ret;
+ }
+ if ((buf[0] ^ buf[1]) == 0xff) {
+ /* Primary copy of magic passes complement check. */
+ sr_dbg("Using primary copy of device type magic number.");
+ magic = buf[0];
+ } else if ((buf[4] ^ buf[5]) == 0xff) {
+ /* Backup copy of magic passes complement check. */
+ sr_dbg("Using backup copy of device type magic number.");
+ magic = buf[4];
+ } else {
+ sr_err("Cannot find consistent device type identification.");
+ magic = 0;
+ }
+ devc->identify_magic = magic;
+
+ devc->model = NULL;
+ for (model_idx = 0; model_idx < ARRAY_SIZE(models); model_idx++) {
+ model = &models[model_idx];
+ if (model->magic != magic)
+ continue;
+ devc->model = model;
+ sr_info("EEPROM magic %d, model '%s'.", (int)magic, model->name);
+ devc->fpga_bitstream = g_strdup_printf(FPGA_FWFILE_FMT,
+ model->fpga_stem);
+ sr_info("Max %zu channels at %" PRIu64 "MHz samplerate.",
+ model->channel_count, model->samplerate / SR_MHZ(1));
+ sr_info("FPGA bitstream file '%s'.", devc->fpga_bitstream);
+ break;
+ }
+ if (!devc->model) {
+ sr_spew("Device type: magic number is %hhu.", magic);
+ sr_err("Cannot identify as one of the supported models.");