From f505134f82e9f8f34009cfe76a2ea436d92e220a Mon Sep 17 00:00:00 2001 From: Hermann Kraus Date: Wed, 18 Aug 2010 09:50:55 +0200 Subject: [PATCH] Support for FT232R eeprom features From the mailinglist: Hello! I added support for creating FT232R-EEPROM images. They differ from FT232BM images making communication unreliable if you don't get them right: - Addr 0x00: Bit 6 selects between normal and high-current output mode - Addr 0x01: IN endpoint size. !!! It is essential to set this to 0x40 to get reliable communication! !!! - Addr 0x07: (Device version) Was changed from 0x04 to 0x06 - Addr 0x0B: Invert outputs. Bit numbers: 0 TXD 1 RXD 2 RTS# 3 CTS# 4 DTR# 5 DSR# 6 DCD# 7 RI# - Addr 0x14-0x16: Change function of CBUS pins. Low nibble of 0x14 is CBUS0, high nibble CBUS1 and so on. Values (hex): TXDEN = 0 PWREN# = 1 RXLED# = 2 TXLED# = 3 TX_RX_LED# = 4 SLEEP# = 5 CLK48 = 6 CLK24 = 7 CLK12 = 8 CLK6 = 9 IO_MODE = A BIT_WR = B BIT_RD = C RXF/TXE/RD/WR = D It should be noted that 0x14-0x16 are used by the current library to strings and therefore change behavior depending on the string descriptor. In images created by FT_Prog 0x17 is 0 so I threat this as reserved. FT_Prog has problems parsing string descriptor from devices written by ftdi-eeprom without this patch. I also have investigated FT2232L-EEPROM (=FT2232C) but have no final conclusion yet, because I don't want to change the information in this device. Just some obvious differences. - Addr 0x00/0x01: value 0x11 0x08 - Addr 0x07: (Device version) 0x05 - Addr 0x14/0x15: value 0x46 0x00 String descriptors start at 0x16. --- src/ftdi.c | 109 ++++++++++++++++++++++++++++++++++++++++++++++++++---------- src/ftdi.h | 58 +++++++++++++++++++++++++++++++- 2 files changed, 148 insertions(+), 19 deletions(-) diff --git a/src/ftdi.c b/src/ftdi.c index b42ba14..525f9d1 100644 --- a/src/ftdi.c +++ b/src/ftdi.c @@ -2176,6 +2176,8 @@ void ftdi_eeprom_setsize(struct ftdi_context *ftdi, struct ftdi_eeprom *eeprom, */ void ftdi_eeprom_initdefaults(struct ftdi_eeprom *eeprom) { + int i; + if (eeprom == NULL) return; @@ -2184,7 +2186,7 @@ void ftdi_eeprom_initdefaults(struct ftdi_eeprom *eeprom) eeprom->self_powered = 1; eeprom->remote_wakeup = 1; - eeprom->BM_type_chip = 1; + eeprom->chip_type = TYPE_BM; eeprom->in_is_isochronous = 0; eeprom->out_is_isochronous = 0; @@ -2198,6 +2200,12 @@ void ftdi_eeprom_initdefaults(struct ftdi_eeprom *eeprom) eeprom->manufacturer = NULL; eeprom->product = NULL; eeprom->serial = NULL; + for (i=0; i < 5; i++) + { + eeprom->cbus_function[i] = 0; + } + eeprom->high_current = 0; + eeprom->invert = 0; eeprom->size = FTDI_DEFAULT_EEPROM_SIZE; } @@ -2227,12 +2235,16 @@ void ftdi_eeprom_free(struct ftdi_eeprom *eeprom) Build binary output from ftdi_eeprom structure. Output is suitable for ftdi_write_eeprom(). + \note This function doesn't handle FT2232x devices. Only FT232x. \param eeprom Pointer to ftdi_eeprom \param output Buffer of 128 bytes to store eeprom image to - \retval >0: used eeprom size + \retval >0: free eeprom size \retval -1: eeprom size (128 bytes) exceeded by custom strings \retval -2: Invalid eeprom pointer + \retval -3: Invalid cbus function setting + \retval -4: Chip doesn't support invert + \retval -5: Chip doesn't support high current drive */ int ftdi_eeprom_build(struct ftdi_eeprom *eeprom, unsigned char *output) { @@ -2240,6 +2252,7 @@ int ftdi_eeprom_build(struct ftdi_eeprom *eeprom, unsigned char *output) unsigned short checksum, value; unsigned char manufacturer_size = 0, product_size = 0, serial_size = 0; int size_check; + const int cbus_max[5] = {13, 13, 13, 13, 9}; if (eeprom == NULL) return -2; @@ -2251,6 +2264,18 @@ int ftdi_eeprom_build(struct ftdi_eeprom *eeprom, unsigned char *output) if (eeprom->serial != NULL) serial_size = strlen(eeprom->serial); + // highest allowed cbus value + for (i = 0; i < 5; i++) + { + if ((eeprom->cbus_function[i] > cbus_max[i]) || + (eeprom->cbus_function[i] && eeprom->chip_type != TYPE_R)) return -3; + } + if (eeprom->chip_type != TYPE_R) + { + if (eeprom->invert) return -4; + if (eeprom->high_current) return -5; + } + size_check = eeprom->size; size_check -= 28; // 28 are always in use (fixed) @@ -2258,7 +2283,7 @@ int ftdi_eeprom_build(struct ftdi_eeprom *eeprom, unsigned char *output) // it seems that the FTDI chip will not read these strings from the lower half // Each string starts with two bytes; offset and type (0x03 for string) // the checksum needs two bytes, so without the string data that 8 bytes from the top half - if (eeprom->size>=256)size_check = 120; + if (eeprom->size>=256) size_check = 120; size_check -= manufacturer_size*2; size_check -= product_size*2; size_check -= serial_size*2; @@ -2270,7 +2295,12 @@ int ftdi_eeprom_build(struct ftdi_eeprom *eeprom, unsigned char *output) // empty eeprom memset (output, 0, eeprom->size); - // Addr 00: Stay 00 00 + // Addr 00: High current IO + output[0x00] = eeprom->high_current ? HIGH_CURRENT_DRIVE : 0; + // Addr 01: IN endpoint size (for R type devices, different for FT2232) + if (eeprom->chip_type == TYPE_R) { + output[0x01] = 0x40; + } // Addr 02: Vendor ID output[0x02] = eeprom->vendor_id; output[0x03] = eeprom->vendor_id >> 8; @@ -2281,11 +2311,22 @@ int ftdi_eeprom_build(struct ftdi_eeprom *eeprom, unsigned char *output) // Addr 06: Device release number (0400h for BM features) output[0x06] = 0x00; - - if (eeprom->BM_type_chip == 1) - output[0x07] = 0x04; - else - output[0x07] = 0x02; + switch (eeprom->chip_type) { + case TYPE_AM: + output[0x07] = 0x02; + break; + case TYPE_BM: + output[0x07] = 0x04; + break; + case TYPE_2232C: + output[0x07] = 0x05; + break; + case TYPE_R: + output[0x07] = 0x06; + break; + default: + output[0x07] = 0x00; + } // Addr 08: Config descriptor // Bit 7: always 1 @@ -2325,8 +2366,8 @@ int ftdi_eeprom_build(struct ftdi_eeprom *eeprom, unsigned char *output) j = j | 16; output[0x0A] = j; - // Addr 0B: reserved - output[0x0B] = 0x00; + // Addr 0B: Invert data lines + output[0x0B] = eeprom->invert & 0xff; // Addr 0C: USB version low byte when 0x0A bit 4 is set // Addr 0D: USB version high byte when 0x0A bit 4 is set @@ -2349,9 +2390,23 @@ int ftdi_eeprom_build(struct ftdi_eeprom *eeprom, unsigned char *output) // Addr 13: Length of serial string output[0x13] = serial_size*2 + 2; + // Addr 14: CBUS function: CBUS0, CBUS1 + // Addr 15: CBUS function: CBUS2, CBUS3 + // Addr 16: CBUS function: CBUS5 + output[0x14] = eeprom->cbus_function[0] | (eeprom->cbus_function[1] << 4); + output[0x15] = eeprom->cbus_function[2] | (eeprom->cbus_function[3] << 4); + output[0x16] = eeprom->cbus_function[4]; + // Addr 17: Unknown + // Dynamic content - i=0x14; - if (eeprom->size>=256) i = 0x80; + // In images produced by FTDI's FT_Prog for FT232R strings start at 0x18 + // Space till 0x18 should be considered as reserved. + if (eeprom->chip_type >= TYPE_R) { + i = 0x18; + } else { + i = 0x14; + } + if (eeprom->size >= 256) i = 0x80; // Output manufacturer @@ -2445,7 +2500,8 @@ int ftdi_eeprom_decode(struct ftdi_eeprom *eeprom, unsigned char *buf, int size) // empty eeprom struct memset(eeprom, 0, sizeof(struct ftdi_eeprom)); - // Addr 00: Stay 00 00 + // Addr 00: High current IO + eeprom->high_current = (buf[0x02] & HIGH_CURRENT_DRIVE); // Addr 02: Vendor ID eeprom->vendor_id = buf[0x02] + (buf[0x03] << 8); @@ -2456,14 +2512,17 @@ int ftdi_eeprom_decode(struct ftdi_eeprom *eeprom, unsigned char *buf, int size) value = buf[0x06] + (buf[0x07]<<8); switch (value) { + case 0x0600: + eeprom->chip_type = TYPE_R; + break; case 0x0400: - eeprom->BM_type_chip = 1; + eeprom->chip_type = TYPE_BM; break; case 0x0200: - eeprom->BM_type_chip = 0; + eeprom->chip_type = TYPE_AM; break; default: // Unknown device - eeprom->BM_type_chip = 0; + eeprom->chip_type = 0; break; } @@ -2496,7 +2555,8 @@ int ftdi_eeprom_decode(struct ftdi_eeprom *eeprom, unsigned char *buf, int size) if (j&0x08) eeprom->use_serial = 1; if (j&0x10) eeprom->change_usb_version = 1; - // Addr 0B: reserved + // Addr 0B: Invert data lines + eeprom->invert = buf[0x0B]; // Addr 0C: USB version low byte when 0x0A bit 4 is set // Addr 0D: USB version high byte when 0x0A bit 4 is set @@ -2523,6 +2583,19 @@ int ftdi_eeprom_decode(struct ftdi_eeprom *eeprom, unsigned char *buf, int size) if (serial_size > 0) eeprom->serial = malloc(serial_size); else eeprom->serial = NULL; + // Addr 14: CBUS function: CBUS0, CBUS1 + // Addr 15: CBUS function: CBUS2, CBUS3 + // Addr 16: CBUS function: CBUS5 + if (eeprom->chip_type == TYPE_R) { + eeprom->cbus_function[0] = buf[0x14] & 0x0f; + eeprom->cbus_function[1] = (buf[0x14] >> 4) & 0x0f; + eeprom->cbus_function[2] = buf[0x15] & 0x0f; + eeprom->cbus_function[3] = (buf[0x15] >> 4) & 0x0f; + eeprom->cbus_function[4] = buf[0x16] & 0x0f; + } else { + for (j=0; j<5; j++) eeprom->cbus_function[j] = 0; + } + // Decode manufacturer i = buf[0x0E] & 0x7f; // offset for (j=0;j