view fteeprom/ftee-decode.c @ 67:742c41f44658

doc/FTDI-chip-ID: new article
author Mychaela Falconia <falcon@freecalypso.org>
date Wed, 13 Sep 2023 00:43:14 +0000
parents 225dc1d9f2f1
children
line wrap: on
line source

/*
 * This program reads an FTDI EEPROM image from a file (or from stdin)
 * and performs some basic decoding on it.  Only the part of the EEPROM
 * structure that is common for all chips is looked at, and only very
 * shallow decoding is performed, without differentiating by FTDI chip
 * type.  Compared to simply studying EEPROM images in raw hex, the main
 * utility of this program is decoding and displaying the three textual
 * ID strings.
 */

#include <sys/types.h>
#include <string.h>
#include <strings.h>
#include <stdio.h>
#include <stdlib.h>

extern unsigned eeprom_size;
extern u_short eeprom[256];

static unsigned useful_size;

static int
verify_eeprom_chksum()
{
	u_short chksum = 0xAAAA;
	unsigned n;

	for (n = 0; n < useful_size; n++) {
		chksum ^= eeprom[n];
		chksum = (chksum << 1) | (chksum >> 15);
	}
	return (chksum == 0);
}

static void
show_string_desc(headline, ptr_word)
	char *headline;
	unsigned ptr_word;
{
	unsigned start_byte, desc_len;
	unsigned start_word, total_words;
	unsigned head_word, nchars;
	u_short *sp;
	unsigned n, uni;

	if (!ptr_word) {
		printf("%s NULL\n", headline);
		return;
	}
	if (ptr_word & 0x0101) {
inv:		printf("%s INVALID\n", headline);
		return;
	}
	start_byte = ptr_word & 0xFF;
	desc_len = ptr_word >> 8;
	if (useful_size == 64)
		start_byte &= 0x7F;
	start_word = start_byte >> 1;
	total_words = desc_len >> 1;
	if (start_word < 10)
		goto inv;
	if (total_words < 1)
		goto inv;
	if (start_word + total_words >= useful_size)
		goto inv;
	head_word = eeprom[start_word];
	if ((head_word & 0xFF) != desc_len)
		goto inv;
	if ((head_word >> 8) != 0x03)
		goto inv;
	nchars = total_words - 1;
	printf("%s \"", headline);
	sp = eeprom + start_word + 1;
	for (n = 0; n < nchars; n++) {
		uni = *sp++;
		if (uni < 0x20 || uni > 0x7E) {
			printf("\\u%04X", uni);
			continue;
		}
		if (uni == '"' || uni == '\\')
			putchar('\\');
		putchar(uni);
	}
	putchar('"');
	putchar('\n');
}

main(argc, argv)
	char **argv;
{
	if (argc != 2) {
		fprintf(stderr, "usage: %s eeprom-image-file\n", argv[0]);
		exit(1);
	}
	if (strcmp(argv[1], "-"))
		read_eeprom_from_file(argv[1]);
	else
		read_eeprom_from_stdin();
	switch (eeprom_size) {
	case 64:
		printf("EEPROM size: 128 bytes (93C46 or FT232R)\n");
		useful_size = 64;
		break;
	case 128:
		printf("EEPROM size: 256 bytes (93C56)\n");
		useful_size = 128;
		break;
	case 256:
		printf("EEPROM size: 512 bytes (93C66)\n");
		useful_size = 128;
		break;
	default:
		fprintf(stderr,
			"BUG: invalid EEPROM size not caught earlier\n");
		exit(1);
	}
	printf("EEPROM checksum is %s\n",
		verify_eeprom_chksum() ? "good" : "BAD!");
	printf("FTDI byte 00: 0x%02X\n", eeprom[0] & 0xFF);
	printf("FTDI byte 01: 0x%02X\n", eeprom[0] >> 8);
	printf("idVendor:     0x%04X\n", eeprom[1]);
	printf("idProduct:    0x%04X\n", eeprom[2]);
	printf("bcdDevice:    0x%04X\n", eeprom[3]);
	printf("bmAttributes: 0x%02X\n", eeprom[4] & 0xFF);
	printf("bMaxPower:    %u mA\n", (eeprom[4] >> 8) * 2);
	printf("FTDI byte 0A: 0x%02X\n", eeprom[5] & 0xFF);
	printf("FTDI byte 0B: 0x%02X\n", eeprom[5] >> 8);
	printf("bcdUSB word:  0x%04X\n", eeprom[6]);
	show_string_desc("Manuf string:  ", eeprom[7]);
	show_string_desc("Product string:", eeprom[8]);
	show_string_desc("Serial# string:", eeprom[9]);
	exit(0);
}