view fteeprom/ftee-gen232r.c @ 104:866eae65dbea

LICENSE: same as other FreeCalypso tools
author Mychaela Falconia <falcon@freecalypso.org>
date Fri, 29 Sep 2023 18:20:04 +0000
parents 66cbbd7d85cf
children
line wrap: on
line source

/*
 * This program constructs a configuration EEPROM image for an FT232R chip
 * based on a configuration source file giving various settings.
 */

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

extern FILE *open_eeprom_config_file();

u_short vid = 0x0403, pid = 0x6001;
char *manuf, *product;
u_char byte00 = 0x00, byte01 = 0x40;
u_char byte08 = 0x80, byte0A = 0x00, byte0B = 0x00;
unsigned maxpower = 90;
u_short usb_version = 0x0200;
u_char cbusconf[5] = {3, 2, 0, 1, 5};

u_short eeprom[64];
unsigned eeprom_string_ptr = 0x0C;

static void
take_one_arg(arg)
	char *arg;
{
	char *cp;

	for (cp = arg; *cp && !isspace(*cp); cp++)
		;
	if (*cp)
		*cp = '\0';
}

static void
ftdi_chip_setting(arg, filename_for_errs, lineno)
	char *arg, *filename_for_errs;
{
	take_one_arg(arg);
	if (!strcasecmp(arg, "FT232R"))
		return;
	fprintf(stderr, "%s line %d: config is for wrong FTDI chip\n",
		filename_for_errs, lineno);
	exit(1);
}

static void
read_config_file(filename)
	char *filename;
{
	FILE *inf;
	char linebuf[1024];
	int lineno;
	char *cp, *np;

	inf = open_eeprom_config_file(filename);
	if (!inf) {
		perror(filename);
		exit(1);
	}
	for (lineno = 1; fgets(linebuf, sizeof linebuf, inf); lineno++) {
		cp = index(linebuf, '\n');
		if (!cp) {
			fprintf(stderr,
				"%s line %d: too long or unterminated\n",
				filename, lineno);
			exit(1);
		}
		*cp = '\0';
		for (cp = linebuf; isspace(*cp); cp++)
			;
		if (*cp == '\0' || *cp == '#')
			continue;
		for (np = cp; *cp && !isspace(*cp); cp++)
			;
		if (*cp)
			*cp++ = '\0';
		while (isspace(*cp))
			cp++;
		if (*cp == '\0' || *cp == '#') {
			fprintf(stderr,
				"%s line %d: \"%s\" setting without argument\n",
				filename, lineno, np);
			exit(1);
		}
		if (!strcmp(np, "vid"))
			vid = strtoul(cp, 0, 16);
		else if (!strcmp(np, "pid"))
			pid = strtoul(cp, 0, 16);
		else if (!strcmp(np, "manuf"))
			manuf = strdup(cp);
		else if (!strcmp(np, "product"))
			product = strdup(cp);
		else if (!strcmp(np, "byte00"))
			byte00 = strtoul(cp, 0, 16);
		else if (!strcmp(np, "byte01"))
			byte01 = strtoul(cp, 0, 16);
		else if (!strcmp(np, "byte08"))
			byte08 = strtoul(cp, 0, 16);
		else if (!strcmp(np, "byte0A"))
			byte0A = strtoul(cp, 0, 16);
		else if (!strcmp(np, "byte0B"))
			byte0B = strtoul(cp, 0, 16);
		else if (!strcmp(np, "maxpower"))
			maxpower = strtoul(cp, 0, 10);
		else if (!strcmp(np, "usbver"))
			usb_version = strtoul(cp, 0, 16);
		else if (!strcmp(np, "cbus0"))
			cbusconf[0] = strtoul(cp, 0, 16);
		else if (!strcmp(np, "cbus1"))
			cbusconf[1] = strtoul(cp, 0, 16);
		else if (!strcmp(np, "cbus2"))
			cbusconf[2] = strtoul(cp, 0, 16);
		else if (!strcmp(np, "cbus3"))
			cbusconf[3] = strtoul(cp, 0, 16);
		else if (!strcmp(np, "cbus4"))
			cbusconf[4] = strtoul(cp, 0, 16);
		else if (!strcmp(np, "ftdi-chip"))
			ftdi_chip_setting(cp, filename, lineno);
		else {
			fprintf(stderr, "%s line %d: unknown \"%s\" setting\n",
				filename, lineno, np);
			exit(1);
		}
	}
	fclose(inf);
	if (!manuf) {
		fprintf(stderr, "error: manuf not set in %s\n", filename);
		exit(1);
	}
	if (!product) {
		fprintf(stderr, "error: product not set in %s\n", filename);
		exit(1);
	}
}

static int
write_string(str)
	char *str;
{
	unsigned longlen, startptr;

	if (63 - eeprom_string_ptr < strlen(str) + 1) {
		fprintf(stderr, "error: strings are too long\n");
		exit(1);
	}
	longlen = strlen(str) * 2 + 2;
	startptr = eeprom_string_ptr;
	eeprom[eeprom_string_ptr++] = 0x0300 | longlen;
	while (*str)
		eeprom[eeprom_string_ptr++] = *str++;
	return (longlen << 8) | 0x80 | (startptr << 1);
}

static void
fill_eeprom(serial)
	char *serial;
{
	u_char byte09;

	if (serial)
		byte0A |= 0x08;
	else
		byte0A &= 0xF7;
	byte09 = maxpower / 2;
	eeprom[0] = (byte01 << 8) | byte00;
	eeprom[1] = vid;
	eeprom[2] = pid;
	eeprom[3] = 0x0600;
	eeprom[4] = (byte09 << 8) | byte08;
	eeprom[5] = (byte0B << 8) | byte0A;
	eeprom[6] = usb_version;
	eeprom[7] = write_string(manuf);
	eeprom[8] = write_string(product);
	if (serial)
		eeprom[9] = write_string(serial);
	else
		eeprom[9] = 0;
	eeprom[10] = (cbusconf[3] << 12) | (cbusconf[2] << 8) |
			(cbusconf[1] << 4) | cbusconf[0];
	eeprom[11] = cbusconf[4];
}

static void
do_checksum()
{
	u_short chksum = 0xAAAA;
	unsigned n;

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

static void
emit_output()
{
	unsigned n, col;

	for (n = 0; n < 64; n++) {
		col = n & 7;
		if (col == 0)
			printf("%02X:", n * 2);
		printf(" %04X", eeprom[n]);
		if (col == 7)
			putchar('\n');
	}
}

main(argc, argv)
	char **argv;
{
	if (argc < 2 || argc > 3) {
		fprintf(stderr, "usage: %s config-file [serial-num]\n",
			argv[0]);
		exit(1);
	}
	read_config_file(argv[1]);
	fill_eeprom(argv[2]);
	do_checksum();
	emit_output();
	exit(0);
}