From be4bae37b3f851d7e06610fe474d84a3b2371efb Mon Sep 17 00:00:00 2001 From: Anders Larsen Date: Mon, 9 Apr 2012 17:29:22 +0200 Subject: [PATCH] Completed the support for the FT4232H chip Added missing fields to the ftdi_eeprom structure and the encoding and decoding functions. The ftdi_eeprom utility forces DRIVER_VCP on and RS485 off for all channels, but this could easily be made configurable, should the need arise. Signed-off-by: Anders Larsen --- doc/EEPROM-structure | 40 ++++++++------- ftdi_eeprom/main.c | 9 +++ src/ftdi.c | 134 +++++++++++++++++++++++++++++++++++++++++++++++--- src/ftdi.h | 10 +++- src/ftdi_i.h | 9 +++- 5 files changed, 175 insertions(+), 27 deletions(-) diff --git a/doc/EEPROM-structure b/doc/EEPROM-structure index c83337e..a1e9b02 100644 --- a/doc/EEPROM-structure +++ b/doc/EEPROM-structure @@ -9,27 +9,27 @@ Type | Use extra EEPROM space FT2XXB | No Byte.BIT| TYPE_AM TYPE_BM TYPE_2232C TYPE_R TYPE_2232H TYPE_4232H -00.0 | 0 0 channel_a_type channel_a_type channel_a_type -00.1 | 0 0 channel_a_type channel_a_type channel_a_type -00.2 | 0 0 channel_a_type high_current channel_a_type channel_a_type +00.0 | 0 0 channel_a_type channel_a_type 0 +00.1 | 0 0 channel_a_type channel_a_type 0 +00.2 | 0 0 channel_a_type high_current channel_a_type 0 00.3 | 0 0 channel_a_driver channel_a_driver channel_a_driver channel_a_driver 00.4 | 0 0 high_current_a 0 0 0 00.5 | 0 0 0 0 0 0 00.6 | 0 0 0 0 0 0 -00.7 | 0 0 0 0 SUSPEND_DBUS7 0 +00.7 | 0 0 0 0 SUSPEND_DBUS7 channel_c_driver On TYPE_R 00.3 set mean D2XX, on other devices VCP -01.0 | 0 0 channel_b_type channel_b_type channel_b_type -01.1 | 0 0 channel_b_type channel_b_type channel_b_type -01.2 | 0 0 channel_b_type 0 channel_b_type channel_b_type +01.0 | 0 0 channel_b_type channel_b_type 0 +01.1 | 0 0 channel_b_type channel_b_type 0 +01.2 | 0 0 channel_b_type 0 channel_b_type 0 01.3 | 0 0 channel_b_driver 0 channel_b_driver channel_b_driver 01.4 | 0 0 high_current_b 0 0 0 01.5 | 0 0 0 0 0 0 01.6 | 0 0 0 0 0 -01.7 | 0 0 0 0 0 0 +01.7 | 0 0 0 0 0 channel_d_driver -Fixme: Missing 4232H validation and channel_c_driver, channel_d_driver, channel_a|b|c|d_rs484enable +Fixme: Missing 4232H validation 02 | Vendor ID (VID) LSB (all) 03 | Vendor ID (VID) MSB (all) @@ -45,18 +45,22 @@ Fixme: Missing 4232H validation and channel_c_driver, channel_d_driver, channel_ | 09 | Max power (mA/2) | -Byte.BIT| TYPE_AM TYPE_BM TYPE_2232C TYPE_R TYPE_2232H TYPE_4232H -0a.0 | 0 IsoIn IsoIn part A 0 0 0 -0a.1 | 0 IsoOut IsoOut part A 0 0 0 -0a.2 | 0 suspend_pull_down suspend_pull_down suspend_pull_down -0a.3 | 0 use_serial use_serial +Byte.BIT| TYPE_AM TYPE_BM TYPE_2232C TYPE_R TYPE_2232H TYPE_4232H +0a.0 | 0 IsoIn IsoIn part A 0 0 0 +0a.1 | 0 IsoOut IsoOut part A 0 0 0 +0a.2 | 0 suspend_pull_down suspend_pull_down suspend_pull_down suspend_pull_down +0a.3 | 0 use_serial use_serial use_serial 0a.4 | 0 change_usb_version change_usb_version -0a.5 | 0 0 IsoIn part B 0 0 0 -0a.6 | 0 0 IsoOut part B 0 0 0 +0a.5 | 0 0 IsoIn part B 0 0 0 +0a.6 | 0 0 IsoOut part B 0 0 0 0a.7 | 0 - reserved - | -0b | TYPE_R Bitmask Invert, 0 else +0b | TYPE_R Bitmask Invert, 0 else +Byte.BIT| TYPE_4232H +0b.4 | channel_a_rs485enable +0b.5 | channel_b_rs485enable +0b.6 | channel_c_rs485enable +0b.7 | channel_d_rs485enable Byte | TYPE_AM TYPE_BM TYPE_2232C TYPE_R TYPE_2232H TYPE_4232H 0c | 0 USB-VER-LSB USB-VER-LSB 0 ? ? diff --git a/ftdi_eeprom/main.c b/ftdi_eeprom/main.c index 94cd7ec..ad7de93 100644 --- a/ftdi_eeprom/main.c +++ b/ftdi_eeprom/main.c @@ -297,6 +297,15 @@ int main(int argc, char *argv[]) if (cfg_getbool(cfg, "invert_ri")) invert |= INVERT_RI; eeprom_set_value(ftdi, INVERT, invert); + eeprom_set_value(ftdi, CHANNEL_A_DRIVER, DRIVER_VCP); + eeprom_set_value(ftdi, CHANNEL_B_DRIVER, DRIVER_VCP); + eeprom_set_value(ftdi, CHANNEL_C_DRIVER, DRIVER_VCP); + eeprom_set_value(ftdi, CHANNEL_D_DRIVER, DRIVER_VCP); + eeprom_set_value(ftdi, CHANNEL_A_RS485, 0); + eeprom_set_value(ftdi, CHANNEL_B_RS485, 0); + eeprom_set_value(ftdi, CHANNEL_C_RS485, 0); + eeprom_set_value(ftdi, CHANNEL_D_RS485, 0); + if (_erase > 0) { printf("FTDI erase eeprom: %d\n", ftdi_erase_eeprom(ftdi)); diff --git a/src/ftdi.c b/src/ftdi.c index 59a9eea..8650be2 100644 --- a/src/ftdi.c +++ b/src/ftdi.c @@ -2369,7 +2369,6 @@ int ftdi_eeprom_initdefaults(struct ftdi_context *ftdi, char * manufacturer, strcpy(eeprom->serial, serial); } - if (ftdi->type == TYPE_R) { eeprom->max_power = 90; @@ -2840,8 +2839,83 @@ int ftdi_eeprom_build(struct ftdi_context *ftdi) break; case TYPE_4232H: + if (eeprom->channel_a_driver == DRIVER_VCP) + output[0x00] |= DRIVER_VCP; + else + output[0x00] &= ~DRIVER_VCP; + if (eeprom->channel_b_driver == DRIVER_VCP) + output[0x01] |= DRIVER_VCP; + else + output[0x01] &= ~DRIVER_VCP; + if (eeprom->channel_c_driver == DRIVER_VCP) + output[0x00] |= (DRIVER_VCP << 4); + else + output[0x00] &= ~(DRIVER_VCP << 4); + if (eeprom->channel_d_driver == DRIVER_VCP) + output[0x01] |= (DRIVER_VCP << 4); + else + output[0x01] &= ~(DRIVER_VCP << 4); + + if (eeprom->suspend_pull_downs == 1) + output[0x0a] |= 0x4; + else + output[0x0a] &= ~0x4; + + if (eeprom->channel_a_rs485enable) + output[0x0b] |= CHANNEL_IS_RS485 << 0; + else + output[0x0b] &= ~(CHANNEL_IS_RS485 << 0); + if (eeprom->channel_b_rs485enable) + output[0x0b] |= CHANNEL_IS_RS485 << 1; + else + output[0x0b] &= ~(CHANNEL_IS_RS485 << 1); + if (eeprom->channel_c_rs485enable) + output[0x0b] |= CHANNEL_IS_RS485 << 2; + else + output[0x0b] &= ~(CHANNEL_IS_RS485 << 2); + if (eeprom->channel_d_rs485enable) + output[0x0b] |= CHANNEL_IS_RS485 << 3; + else + output[0x0b] &= ~(CHANNEL_IS_RS485 << 3); + + if (eeprom->group0_drive > DRIVE_16MA) + output[0x0c] |= DRIVE_16MA; + else + output[0x0c] |= eeprom->group0_drive; + if (eeprom->group0_schmitt == IS_SCHMITT) + output[0x0c] |= IS_SCHMITT; + if (eeprom->group0_slew == SLOW_SLEW) + output[0x0c] |= SLOW_SLEW; + + if (eeprom->group1_drive > DRIVE_16MA) + output[0x0c] |= DRIVE_16MA<<4; + else + output[0x0c] |= eeprom->group1_drive<<4; + if (eeprom->group1_schmitt == IS_SCHMITT) + output[0x0c] |= IS_SCHMITT<<4; + if (eeprom->group1_slew == SLOW_SLEW) + output[0x0c] |= SLOW_SLEW<<4; + + if (eeprom->group2_drive > DRIVE_16MA) + output[0x0d] |= DRIVE_16MA; + else + output[0x0d] |= eeprom->group2_drive; + if (eeprom->group2_schmitt == IS_SCHMITT) + output[0x0d] |= IS_SCHMITT; + if (eeprom->group2_slew == SLOW_SLEW) + output[0x0d] |= SLOW_SLEW; + + if (eeprom->group3_drive > DRIVE_16MA) + output[0x0d] |= DRIVE_16MA<<4; + else + output[0x0d] |= eeprom->group3_drive<<4; + if (eeprom->group3_schmitt == IS_SCHMITT) + output[0x0d] |= IS_SCHMITT<<4; + if (eeprom->group3_slew == SLOW_SLEW) + output[0x0d] |= SLOW_SLEW<<4; + output[0x18] = eeprom->chip; - fprintf(stderr,"FIXME: Build FT4232H specific EEPROM settings\n"); + break; case TYPE_232H: output[0x00] = type2bit(eeprom->channel_a_type, TYPE_232H); @@ -3097,7 +3171,7 @@ int ftdi_eeprom_decode(struct ftdi_context *ftdi, int verbose) else if (ftdi->type == TYPE_R) { /* TYPE_R flags D2XX, not VCP as all others*/ - eeprom->channel_a_driver = (~buf[0x00]) & DRIVER_VCP; + eeprom->channel_a_driver = ~buf[0x00] & DRIVER_VCP; eeprom->high_current = buf[0x00] & HIGH_CURRENT_DRIVE_R; if ( (buf[0x01]&0x40) != 0x40) fprintf(stderr, @@ -3119,15 +3193,26 @@ int ftdi_eeprom_decode(struct ftdi_context *ftdi, int verbose) eeprom->cbus_function[3] = (buf[0x15] >> 4) & 0x0f; eeprom->cbus_function[4] = buf[0x16] & 0x0f; } - else if ((ftdi->type == TYPE_2232H) ||(ftdi->type == TYPE_4232H)) + else if ((ftdi->type == TYPE_2232H) || (ftdi->type == TYPE_4232H)) { - eeprom->channel_a_type = bit2type(buf[0x00] & 0x7); eeprom->channel_a_driver = buf[0x00] & DRIVER_VCP; - eeprom->channel_b_type = bit2type(buf[0x01] & 0x7); eeprom->channel_b_driver = buf[0x01] & DRIVER_VCP; if (ftdi->type == TYPE_2232H) + { + eeprom->channel_a_type = bit2type(buf[0x00] & 0x7); + eeprom->channel_b_type = bit2type(buf[0x01] & 0x7); eeprom->suspend_dbus7 = buf[0x01] & SUSPEND_DBUS7_BIT; + } + else + { + eeprom->channel_c_driver = (buf[0x00] >> 4) & DRIVER_VCP; + eeprom->channel_d_driver = (buf[0x01] >> 4) & DRIVER_VCP; + eeprom->channel_a_rs485enable = buf[0x0b] & (CHANNEL_IS_RS485 << 0); + eeprom->channel_b_rs485enable = buf[0x0b] & (CHANNEL_IS_RS485 << 1); + eeprom->channel_c_rs485enable = buf[0x0b] & (CHANNEL_IS_RS485 << 2); + eeprom->channel_d_rs485enable = buf[0x0b] & (CHANNEL_IS_RS485 << 3); + } eeprom->chip = buf[0x18]; eeprom->group0_drive = buf[0x0c] & DRIVE_16MA; @@ -3269,7 +3354,6 @@ int ftdi_eeprom_decode(struct ftdi_context *ftdi, int verbose) fprintf(stdout,"C%d Function: %s\n", i, cbush_mux[eeprom->cbus_function[i]]); } - } if (ftdi->type == TYPE_R) @@ -3375,6 +3459,24 @@ int ftdi_get_eeprom_value(struct ftdi_context *ftdi, enum ftdi_eeprom_value valu case CHANNEL_B_DRIVER: *value = ftdi->eeprom->channel_b_driver; break; + case CHANNEL_C_DRIVER: + *value = ftdi->eeprom->channel_c_driver; + break; + case CHANNEL_D_DRIVER: + *value = ftdi->eeprom->channel_d_driver; + break; + case CHANNEL_A_RS485: + *value = ftdi->eeprom->channel_a_rs485enable; + break; + case CHANNEL_B_RS485: + *value = ftdi->eeprom->channel_b_rs485enable; + break; + case CHANNEL_C_RS485: + *value = ftdi->eeprom->channel_c_rs485enable; + break; + case CHANNEL_D_RS485: + *value = ftdi->eeprom->channel_d_rs485enable; + break; case CBUS_FUNCTION_0: *value = ftdi->eeprom->cbus_function[0]; break; @@ -3544,6 +3646,24 @@ int ftdi_set_eeprom_value(struct ftdi_context *ftdi, enum ftdi_eeprom_value valu case CHANNEL_B_DRIVER: ftdi->eeprom->channel_b_driver = value; break; + case CHANNEL_C_DRIVER: + ftdi->eeprom->channel_c_driver = value; + break; + case CHANNEL_D_DRIVER: + ftdi->eeprom->channel_d_driver = value; + break; + case CHANNEL_A_RS485: + ftdi->eeprom->channel_a_rs485enable = value; + break; + case CHANNEL_B_RS485: + ftdi->eeprom->channel_b_rs485enable = value; + break; + case CHANNEL_C_RS485: + ftdi->eeprom->channel_c_rs485enable = value; + break; + case CHANNEL_D_RS485: + ftdi->eeprom->channel_d_rs485enable = value; + break; case CBUS_FUNCTION_0: ftdi->eeprom->cbus_function[0] = value; break; diff --git a/src/ftdi.h b/src/ftdi.h index 7bf5b6e..38b0668 100644 --- a/src/ftdi.h +++ b/src/ftdi.h @@ -301,7 +301,13 @@ enum ftdi_eeprom_value POWER_SAVE = 45, CLOCK_POLARITY = 46, DATA_ORDER = 47, - FLOW_CONTROL = 48 + FLOW_CONTROL = 48, + CHANNEL_C_DRIVER = 49, + CHANNEL_D_DRIVER = 50, + CHANNEL_A_RS485 = 51, + CHANNEL_B_RS485 = 52, + CHANNEL_C_RS485 = 53, + CHANNEL_D_RS485 = 54, }; /** @@ -354,6 +360,8 @@ enum ftdi_cbush_func {/* FIXME: Recheck value, especially the last */ #define CHANNEL_IS_CPU 0x4 #define CHANNEL_IS_FT1284 0x8 +#define CHANNEL_IS_RS485 0x10 + #define DRIVE_4MA 0 #define DRIVE_8MA 1 #define DRIVE_12MA 2 diff --git a/src/ftdi_i.h b/src/ftdi_i.h index dd2d29b..8d8c77e 100644 --- a/src/ftdi_i.h +++ b/src/ftdi_i.h @@ -68,7 +68,7 @@ struct ftdi_eeprom /** serial number */ char *serial; - /* 2232D/H(/FT4432H?) specific */ + /* 2232D/H specific */ /* Hardware type, 0 = RS232 Uart, 1 = 245 FIFO, 2 = CPU FIFO, 4 = OPTO Isolate */ int channel_a_type; @@ -76,6 +76,13 @@ struct ftdi_eeprom /* Driver Type, 1 = VCP */ int channel_a_driver; int channel_b_driver; + int channel_c_driver; + int channel_d_driver; + /* 4232H specific */ + int channel_a_rs485enable; + int channel_b_rs485enable; + int channel_c_rs485enable; + int channel_d_rs485enable; /* Special function of FT232R/FT232H devices (and possibly others as well) */ /** CBUS pin function. See CBUS_xxx defines. */ -- 1.7.1