+ /*
+ * 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.
+ */
+ 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;
+ }
+ sr_dbg("Device type: magic number is %hhu.", magic);
+
+ /* Select the FPGA bitstream depending on the model. */
+ switch (magic) {
+ case 2:
+ bitstream_fn = FPGA_FW_LA2016;
+ devc->max_samplerate = MAX_SAMPLE_RATE_LA2016;
+ break;
+ case 3:
+ bitstream_fn = FPGA_FW_LA1016;
+ devc->max_samplerate = MAX_SAMPLE_RATE_LA1016;
+ break;
+ case 8:
+ bitstream_fn = FPGA_FW_LA2016A;
+ devc->max_samplerate = MAX_SAMPLE_RATE_LA2016;
+ break;
+ case 9:
+ bitstream_fn = FPGA_FW_LA1016A;
+ devc->max_samplerate = MAX_SAMPLE_RATE_LA1016;
+ break;
+ default:
+ bitstream_fn = NULL;
+ break;
+ }
+ if (!bitstream_fn || !*bitstream_fn) {
+ sr_err("Cannot identify as one of the supported models.");