ftdi.c - description
-------------------
begin : Fri Apr 4 2003
- copyright : (C) 2003-2017 by Intra2net AG and the libftdi developers
+ copyright : (C) 2003-2020 by Intra2net AG and the libftdi developers
email : opensource@intra2net.com
+ SPDX-License-Identifier: LGPL-2.1-only
***************************************************************************/
/***************************************************************************
\retval 0: all fine
\retval -1: couldn't allocate read buffer
- \retval -2: couldn't allocate struct buffer
+ \retval -2: couldn't allocate struct buffer
\retval -3: libusb_init() failed
\remark This should be called before all functions
ftdi_error_return(-3, "libusb_init() failed");
ftdi_set_interface(ftdi, INTERFACE_ANY);
- ftdi->bitbang_mode = 1; /* when bitbang is enabled this holds the number of the mode */
+ ftdi->bitbang_mode = 1; /* when bitbang is enabled this holds the number of the mode */
eeprom = (struct ftdi_eeprom *)malloc(sizeof(struct ftdi_eeprom));
if (eeprom == 0)
/**
Finds all ftdi devices with given VID:PID on the usb bus. Creates a new
ftdi_device_list which needs to be deallocated by ftdi_list_free() after
- use. With VID:PID 0:0, search for the default devices
+ use. With VID:PID 0:0, search for the default devices
(0x403:0x6001, 0x403:0x6010, 0x403:0x6011, 0x403:0x6014, 0x403:0x6015)
\param ftdi pointer to ftdi_context
if (libusb_get_device_descriptor(dev, &desc) < 0)
ftdi_error_return(-11, "libusb_get_device_descriptor() failed");
- if (manufacturer != NULL)
+ if (manufacturer != NULL && mnf_len > 0)
{
- if (libusb_get_string_descriptor_ascii(ftdi->usb_dev, desc.iManufacturer, (unsigned char *)manufacturer, mnf_len) < 0)
+ if (desc.iManufacturer == 0)
+ {
+ manufacturer[0] = '\0';
+ }
+ else if (libusb_get_string_descriptor_ascii(ftdi->usb_dev, desc.iManufacturer, (unsigned char *)manufacturer, mnf_len) < 0)
{
ftdi_usb_close_internal (ftdi);
ftdi_error_return(-7, "libusb_get_string_descriptor_ascii() failed");
}
}
- if (description != NULL)
+ if (description != NULL && desc_len > 0)
{
- if (libusb_get_string_descriptor_ascii(ftdi->usb_dev, desc.iProduct, (unsigned char *)description, desc_len) < 0)
+ if (desc.iProduct == 0)
+ {
+ description[0] = '\0';
+ }
+ else if (libusb_get_string_descriptor_ascii(ftdi->usb_dev, desc.iProduct, (unsigned char *)description, desc_len) < 0)
{
ftdi_usb_close_internal (ftdi);
ftdi_error_return(-8, "libusb_get_string_descriptor_ascii() failed");
}
}
- if (serial != NULL)
+ if (serial != NULL && serial_len > 0)
{
- if (libusb_get_string_descriptor_ascii(ftdi->usb_dev, desc.iSerialNumber, (unsigned char *)serial, serial_len) < 0)
+ if (desc.iSerialNumber == 0)
+ {
+ serial[0] = '\0';
+ }
+ else if (libusb_get_string_descriptor_ascii(ftdi->usb_dev, desc.iSerialNumber, (unsigned char *)serial, serial_len) < 0)
{
ftdi_usb_close_internal (ftdi);
ftdi_error_return(-9, "libusb_get_string_descriptor_ascii() failed");
ftdi_error_return(-12, "libusb_get_configuration () failed");
// set configuration (needed especially for windows)
// tolerate EBUSY: one device with one configuration, but two interfaces
- // and libftdi sessions to both interfaces (e.g. FT2232)
+ // and libftdi sessions to both interfaces (e.g. FT2232)
if (desc.bNumConfigurations > 0 && cfg != cfg0)
{
if (libusb_set_configuration(ftdi->usb_dev, cfg0) < 0)
return best_baud;
}
-/* ftdi_to_clkbits Convert a requested baudrate for a given system clock and predivisor
+/* ftdi_to_clkbits Convert a requested baudrate for a given system clock and predivisor
to encoded divisor and the achievable baudrate
Function is only used internally
\internal
AM Type chips have only four fractional subdivisors at value[15:14]
for subdivisors 0, 0.5, 0.25, 0.125
*/
-static int ftdi_to_clkbits(int baudrate, unsigned int clk, int clk_div, unsigned long *encoded_divisor)
+static int ftdi_to_clkbits(int baudrate, int clk, int clk_div, unsigned long *encoded_divisor)
{
static const char frac_code[8] = {0, 3, 2, 4, 1, 5, 6, 7};
int best_baud = 0;
/**
Reads data in chunks (see ftdi_read_data_set_chunksize()) from the chip.
- Automatically strips the two modem status bytes transfered during every read.
+ Automatically strips the two modem status bytes transferred during every read.
\param ftdi pointer to ftdi_context
\param buf Buffer to store data in
}
/**
+ Set module detach mode.
+
+ \param ftdi pointer to ftdi_context
+ \param mode detach mode to use.
+
+ \retval 0: all fine
+ \retval -1: can't enable bitbang mode
+*/
+int ftdi_set_module_detach_mode(struct ftdi_context *ftdi, enum ftdi_module_detach_mode mode)
+{
+ if (ftdi == NULL)
+ ftdi_error_return(-1, "FTDI context invalid");
+
+ ftdi->module_detach_mode = mode;
+ return 0;
+}
+
+/**
Disable bitbang mode.
\param ftdi pointer to ftdi_context
\retval -2: No struct ftdi_eeprom
\retval -3: No connected device or device not yet opened
*/
-int ftdi_eeprom_initdefaults(struct ftdi_context *ftdi, char * manufacturer,
- char * product, char * serial)
+int ftdi_eeprom_initdefaults(struct ftdi_context *ftdi, const char * manufacturer,
+ const char * product, const char * serial)
{
struct ftdi_eeprom *eeprom;
ftdi_error_return(-3, "No connected device or device not yet opened");
eeprom->vendor_id = 0x0403;
- eeprom->use_serial = 1;
+ eeprom->use_serial = (serial != NULL);
if ((ftdi->type == TYPE_AM) || (ftdi->type == TYPE_BM) ||
(ftdi->type == TYPE_R))
eeprom->product_id = 0x6001;
return 0;
}
-int ftdi_eeprom_set_strings(struct ftdi_context *ftdi, char * manufacturer,
- char * product, char * serial)
+int ftdi_eeprom_set_strings(struct ftdi_context *ftdi, const char * manufacturer,
+ const char * product, const char * serial)
{
struct ftdi_eeprom *eeprom;
// Dynamic content
// Strings start at 0x94 (TYPE_AM, TYPE_BM)
// 0x96 (TYPE_2232C), 0x98 (TYPE_R) and 0x9a (TYPE_x232H)
- // 0xa0 (TYPE_232H)
+ // 0xa0 (TYPE_232H, TYPE_230X)
i = 0;
switch (ftdi->type)
{
case TYPE_2232H:
case TYPE_4232H:
i += 2;
+ /* Fall through*/
case TYPE_R:
i += 2;
+ /* Fall through*/
case TYPE_2232C:
i += 2;
+ /* Fall through*/
case TYPE_AM:
case TYPE_BM:
i += 0x94;
i = 0xa0;
break;
}
- /* Wrap around 0x80 for 128 byte EEPROMS (Internale and 93x46) */
+ /* Wrap around 0x80 for 128 byte EEPROMS (Internal and 93x46) */
eeprom_size_mask = eeprom->size -1;
free_end = i & eeprom_size_mask;
}
output[0x11] = product_size*2 + 2;
- // Addr 12: Offset of the serial string + 0x80, calculated later
- // Addr 13: Length of serial string
- output[0x12] = i | 0x80; // calculate offset
- output[i & eeprom_size_mask] = serial_size*2 + 2, i++;
- output[i & eeprom_size_mask] = 0x03, i++;
- for (j = 0; j < serial_size; j++)
- {
- output[i & eeprom_size_mask] = eeprom->serial[j], i++;
- output[i & eeprom_size_mask] = 0x00, i++;
+ if (eeprom->use_serial) {
+ // Addr 12: Offset of the serial string + 0x80, calculated later
+ // Addr 13: Length of serial string
+ output[0x12] = i | 0x80; // calculate offset
+ output[i & eeprom_size_mask] = serial_size*2 + 2, i++;
+ output[i & eeprom_size_mask] = 0x03, i++;
+ for (j = 0; j < serial_size; j++)
+ {
+ output[i & eeprom_size_mask] = eeprom->serial[j], i++;
+ output[i & eeprom_size_mask] = 0x00, i++;
+ }
+ output[0x13] = serial_size*2 + 2;
}
// Legacy port name and PnP fields for FT2232 and newer chips
- if (ftdi->type > TYPE_BM)
+ // It doesn't appear when written with FT_Prog for FT4232H chip.
+ if (ftdi->type > TYPE_BM && ftdi->type != TYPE_4232H)
{
output[i & eeprom_size_mask] = 0x02; /* as seen when written with FTD2XX */
i++;
i++;
output[i & eeprom_size_mask] = eeprom->is_not_pnp; /* as seen when written with FTD2XX */
i++;
+ output[i & eeprom_size_mask] = 0x00;
+ i++;
}
- output[0x13] = serial_size*2 + 2;
-
if (ftdi->type > TYPE_AM) /* use_serial not used in AM devices */
{
if (eeprom->use_serial)
}
/* Bytes and Bits specific to (some) types
- Write linear, as this allows easier fixing*/
+ Write linear, as this allows easier fixing */
switch (ftdi->type)
{
case TYPE_AM:
case TYPE_2232C:
output[0x00] = type2bit(eeprom->channel_a_type, TYPE_2232C);
- if ( eeprom->channel_a_driver == DRIVER_VCP)
+ if (eeprom->channel_a_driver)
output[0x00] |= DRIVER_VCP;
else
output[0x00] &= ~DRIVER_VCP;
- if ( eeprom->high_current_a == HIGH_CURRENT_DRIVE)
+ if (eeprom->high_current_a)
output[0x00] |= HIGH_CURRENT_DRIVE;
else
output[0x00] &= ~HIGH_CURRENT_DRIVE;
output[0x01] = type2bit(eeprom->channel_b_type, TYPE_2232C);
- if ( eeprom->channel_b_driver == DRIVER_VCP)
+ if (eeprom->channel_b_driver)
output[0x01] |= DRIVER_VCP;
else
output[0x01] &= ~DRIVER_VCP;
- if ( eeprom->high_current_b == HIGH_CURRENT_DRIVE)
+ if (eeprom->high_current_b)
output[0x01] |= HIGH_CURRENT_DRIVE;
else
output[0x01] &= ~HIGH_CURRENT_DRIVE;
break;
case TYPE_R:
output[0x00] = type2bit(eeprom->channel_a_type, TYPE_R);
- if (eeprom->high_current == HIGH_CURRENT_DRIVE_R)
+ if (eeprom->high_current)
output[0x00] |= HIGH_CURRENT_DRIVE_R;
+
+ /* Field is inverted for TYPE_R: Bit 00.3 set to 1 is D2XX, VCP is 0 */
+ if (eeprom->channel_a_driver)
+ output[0x00] &= ~DRIVER_VCP;
+ else
+ output[0x00] |= DRIVER_VCP;
+
if (eeprom->external_oscillator)
output[0x00] |= 0x02;
- output[0x01] = 0x40; /* Hard coded Endpoint Size*/
+ output[0x01] = 0x40; /* Hard coded Endpoint Size */
if (eeprom->suspend_pull_downs)
output[0x0A] |= 0x4;
break;
case TYPE_2232H:
output[0x00] = type2bit(eeprom->channel_a_type, TYPE_2232H);
- if ( eeprom->channel_a_driver == DRIVER_VCP)
+ if (eeprom->channel_a_driver)
output[0x00] |= DRIVER_VCP;
else
output[0x00] &= ~DRIVER_VCP;
output[0x01] = type2bit(eeprom->channel_b_type, TYPE_2232H);
- if ( eeprom->channel_b_driver == DRIVER_VCP)
+ if (eeprom->channel_b_driver)
output[0x01] |= DRIVER_VCP;
else
output[0x01] &= ~DRIVER_VCP;
- if (eeprom->suspend_dbus7 == SUSPEND_DBUS7_BIT)
+
+ if (eeprom->suspend_dbus7)
output[0x01] |= SUSPEND_DBUS7_BIT;
else
output[0x01] &= ~SUSPEND_DBUS7_BIT;
output[0x0c] |= DRIVE_16MA;
else
output[0x0c] |= eeprom->group0_drive;
- if (eeprom->group0_schmitt == IS_SCHMITT)
+ if (eeprom->group0_schmitt)
output[0x0c] |= IS_SCHMITT;
- if (eeprom->group0_slew == SLOW_SLEW)
+ if (eeprom->group0_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)
+ if (eeprom->group1_schmitt)
output[0x0c] |= IS_SCHMITT<<4;
- if (eeprom->group1_slew == SLOW_SLEW)
+ if (eeprom->group1_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)
+ if (eeprom->group2_schmitt)
output[0x0d] |= IS_SCHMITT;
- if (eeprom->group2_slew == SLOW_SLEW)
+ if (eeprom->group2_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)
+ if (eeprom->group3_schmitt)
output[0x0d] |= IS_SCHMITT<<4;
- if (eeprom->group3_slew == SLOW_SLEW)
+ if (eeprom->group3_slew)
output[0x0d] |= SLOW_SLEW<<4;
output[0x18] = eeprom->chip;
break;
case TYPE_4232H:
- if (eeprom->channel_a_driver == DRIVER_VCP)
+ if (eeprom->channel_a_driver)
output[0x00] |= DRIVER_VCP;
else
output[0x00] &= ~DRIVER_VCP;
- if (eeprom->channel_b_driver == DRIVER_VCP)
+ if (eeprom->channel_b_driver)
output[0x01] |= DRIVER_VCP;
else
output[0x01] &= ~DRIVER_VCP;
- if (eeprom->channel_c_driver == DRIVER_VCP)
+ if (eeprom->channel_c_driver)
output[0x00] |= (DRIVER_VCP << 4);
else
output[0x00] &= ~(DRIVER_VCP << 4);
- if (eeprom->channel_d_driver == DRIVER_VCP)
+ if (eeprom->channel_d_driver)
output[0x01] |= (DRIVER_VCP << 4);
else
output[0x01] &= ~(DRIVER_VCP << 4);
output[0x0c] |= DRIVE_16MA;
else
output[0x0c] |= eeprom->group0_drive;
- if (eeprom->group0_schmitt == IS_SCHMITT)
+ if (eeprom->group0_schmitt)
output[0x0c] |= IS_SCHMITT;
- if (eeprom->group0_slew == SLOW_SLEW)
+ if (eeprom->group0_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)
+ if (eeprom->group1_schmitt)
output[0x0c] |= IS_SCHMITT<<4;
- if (eeprom->group1_slew == SLOW_SLEW)
+ if (eeprom->group1_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)
+ if (eeprom->group2_schmitt)
output[0x0d] |= IS_SCHMITT;
- if (eeprom->group2_slew == SLOW_SLEW)
+ if (eeprom->group2_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)
+ if (eeprom->group3_schmitt)
output[0x0d] |= IS_SCHMITT<<4;
- if (eeprom->group3_slew == SLOW_SLEW)
+ if (eeprom->group3_slew)
output[0x0d] |= SLOW_SLEW<<4;
output[0x18] = eeprom->chip;
break;
case TYPE_232H:
output[0x00] = type2bit(eeprom->channel_a_type, TYPE_232H);
- if ( eeprom->channel_a_driver == DRIVER_VCP)
+ if (eeprom->channel_a_driver)
output[0x00] |= DRIVER_VCPH;
else
output[0x00] &= ~DRIVER_VCPH;
+
if (eeprom->powersave)
output[0x01] |= POWER_SAVE_DISABLE_H;
else
output[0x01] |= FT1284_FLOW_CONTROL;
else
output[0x01] &= ~FT1284_FLOW_CONTROL;
+
if (eeprom->group0_drive > DRIVE_16MA)
output[0x0c] |= DRIVE_16MA;
else
output[0x0c] |= eeprom->group0_drive;
- if (eeprom->group0_schmitt == IS_SCHMITT)
+ if (eeprom->group0_schmitt)
output[0x0c] |= IS_SCHMITT;
- if (eeprom->group0_slew == SLOW_SLEW)
+ if (eeprom->group0_slew)
output[0x0c] |= SLOW_SLEW;
if (eeprom->group1_drive > DRIVE_16MA)
output[0x0d] |= DRIVE_16MA;
else
output[0x0d] |= eeprom->group1_drive;
- if (eeprom->group1_schmitt == IS_SCHMITT)
+ if (eeprom->group1_schmitt)
output[0x0d] |= IS_SCHMITT;
- if (eeprom->group1_slew == SLOW_SLEW)
+ if (eeprom->group1_slew)
output[0x0d] |= SLOW_SLEW;
set_ft232h_cbus(eeprom, output);
output[0x1e] = eeprom->chip;
- fprintf(stderr,"FIXME: Build FT232H specific EEPROM settings\n");
+ /* FIXME: Build FT232H specific EEPROM settings */
break;
case TYPE_230X:
output[0x00] = 0x80; /* Actually, leave the default value */
/*FIXME: Make DBUS & CBUS Control configurable*/
- output[0x0c] = 0; /* DBUS drive 4mA, CBUS drive 4 mA like factory default */
+ output[0x0c] = 0; /* DBUS drive 4mA, CBUS drive 4mA like factory default */
for (j = 0; j <= 6; j++)
{
output[0x1a + j] = eeprom->cbus_function[j];
{
case TYPE_230X:
free_start += 2;
+ /* Fall through*/
case TYPE_232H:
free_start += 6;
+ /* Fall through*/
case TYPE_2232H:
case TYPE_4232H:
free_start += 2;
+ /* Fall through*/
case TYPE_R:
free_start += 2;
+ /* Fall through*/
case TYPE_2232C:
free_start++;
+ /* Fall through*/
case TYPE_AM:
case TYPE_BM:
free_start += 0x14;
i = 0x50;
}
value = data;
+ output[i * 2] = data;
+ output[(i * 2) + 1] = data >> 8;
}
else {
value = output[i*2];
// Bit 7: always 1
// Bit 6: 1 if this device is self powered, 0 if bus powered
// Bit 5: 1 if this device uses remote wakeup
- eeprom->self_powered = buf[0x08] & 0x40;
- eeprom->remote_wakeup = buf[0x08] & 0x20;
+ eeprom->self_powered = !!(buf[0x08] & 0x40);
+ eeprom->remote_wakeup = !!(buf[0x08] & 0x20);
// Addr 09: Max power consumption: max power = value * 2 mA
eeprom->max_power = MAX_POWER_MILLIAMP_PER_UNIT * buf[0x09];
// Bit 1: 1 - Out EndPoint is Isochronous
// Bit 0: 1 - In EndPoint is Isochronous
//
- eeprom->in_is_isochronous = buf[0x0A]&0x01;
- eeprom->out_is_isochronous = buf[0x0A]&0x02;
- eeprom->suspend_pull_downs = buf[0x0A]&0x04;
+ eeprom->in_is_isochronous = !!(buf[0x0A]&0x01);
+ eeprom->out_is_isochronous = !!(buf[0x0A]&0x02);
+ eeprom->suspend_pull_downs = !!(buf[0x0A]&0x04);
eeprom->use_serial = !!(buf[0x0A] & USE_SERIAL_NUM);
eeprom->use_usb_version = !!(buf[0x0A] & USE_USB_VERSION_BIT);
else if (ftdi->type == TYPE_2232C)
{
eeprom->channel_a_type = bit2type(buf[0x00] & 0x7);
- eeprom->channel_a_driver = buf[0x00] & DRIVER_VCP;
- eeprom->high_current_a = buf[0x00] & HIGH_CURRENT_DRIVE;
+ eeprom->channel_a_driver = !!(buf[0x00] & DRIVER_VCP);
+ eeprom->high_current_a = !!(buf[0x00] & HIGH_CURRENT_DRIVE);
eeprom->channel_b_type = buf[0x01] & 0x7;
- eeprom->channel_b_driver = buf[0x01] & DRIVER_VCP;
- eeprom->high_current_b = buf[0x01] & HIGH_CURRENT_DRIVE;
+ eeprom->channel_b_driver = !!(buf[0x01] & DRIVER_VCP);
+ eeprom->high_current_b = !!(buf[0x01] & HIGH_CURRENT_DRIVE);
eeprom->chip = buf[0x14];
}
else if (ftdi->type == TYPE_R)
{
- /* TYPE_R flags D2XX, not VCP as all others*/
- eeprom->channel_a_driver = ~buf[0x00] & DRIVER_VCP;
- eeprom->high_current = buf[0x00] & HIGH_CURRENT_DRIVE_R;
- eeprom->external_oscillator = buf[0x00] & 0x02;
+ /* TYPE_R flags D2XX, not VCP as all others */
+ eeprom->channel_a_driver = !(buf[0x00] & DRIVER_VCP); /* note: inverted flag, use a single NOT */
+ eeprom->high_current = !!(buf[0x00] & HIGH_CURRENT_DRIVE_R);
+ eeprom->external_oscillator = !!(buf[0x00] & 0x02);
if ( (buf[0x01]&0x40) != 0x40)
fprintf(stderr,
"TYPE_R EEPROM byte[0x01] Bit 6 unexpected Endpoint size."
eeprom->chip = buf[0x16];
// Addr 0B: Invert data lines
// Works only on FT232R, not FT245R, but no way to distinguish
- eeprom->invert = buf[0x0B];
+ eeprom->invert = buf[0x0B]; /* note: not a bitflag */
// Addr 14: CBUS function: CBUS0, CBUS1
// Addr 15: CBUS function: CBUS2, CBUS3
// Addr 16: CBUS function: CBUS5
}
else if ((ftdi->type == TYPE_2232H) || (ftdi->type == TYPE_4232H))
{
- eeprom->channel_a_driver = buf[0x00] & DRIVER_VCP;
- eeprom->channel_b_driver = buf[0x01] & DRIVER_VCP;
+ eeprom->channel_a_driver = !!(buf[0x00] & DRIVER_VCP);
+ 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;
+ 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->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;
- eeprom->group0_schmitt = buf[0x0c] & IS_SCHMITT;
- eeprom->group0_slew = buf[0x0c] & SLOW_SLEW;
- eeprom->group1_drive = (buf[0x0c] >> 4) & 0x3;
- eeprom->group1_schmitt = (buf[0x0c] >> 4) & IS_SCHMITT;
- eeprom->group1_slew = (buf[0x0c] >> 4) & SLOW_SLEW;
- eeprom->group2_drive = buf[0x0d] & DRIVE_16MA;
- eeprom->group2_schmitt = buf[0x0d] & IS_SCHMITT;
- eeprom->group2_slew = buf[0x0d] & SLOW_SLEW;
- eeprom->group3_drive = (buf[0x0d] >> 4) & DRIVE_16MA;
- eeprom->group3_schmitt = (buf[0x0d] >> 4) & IS_SCHMITT;
- eeprom->group3_slew = (buf[0x0d] >> 4) & SLOW_SLEW;
+ eeprom->group0_drive = buf[0x0c] & DRIVE_16MA; /* not a bitflag */
+ eeprom->group0_schmitt = !!(buf[0x0c] & IS_SCHMITT);
+ eeprom->group0_slew = !!(buf[0x0c] & SLOW_SLEW);
+ eeprom->group1_drive = (buf[0x0c] >> 4) & DRIVE_16MA; /* not a bitflag */
+ eeprom->group1_schmitt = !!((buf[0x0c] >> 4) & IS_SCHMITT);
+ eeprom->group1_slew = !!((buf[0x0c] >> 4) & SLOW_SLEW);
+ eeprom->group2_drive = buf[0x0d] & DRIVE_16MA; /* not a bitflag */
+ eeprom->group2_schmitt = !!(buf[0x0d] & IS_SCHMITT);
+ eeprom->group2_slew = !!(buf[0x0d] & SLOW_SLEW);
+ eeprom->group3_drive = (buf[0x0d] >> 4) & DRIVE_16MA; /* not a bitflag */
+ eeprom->group3_schmitt = !!((buf[0x0d] >> 4) & IS_SCHMITT);
+ eeprom->group3_slew = !!((buf[0x0d] >> 4) & SLOW_SLEW);
}
else if (ftdi->type == TYPE_232H)
{
eeprom->channel_a_type = buf[0x00] & 0xf;
- eeprom->channel_a_driver = (buf[0x00] & DRIVER_VCPH)?DRIVER_VCP:0;
- eeprom->clock_polarity = buf[0x01] & FT1284_CLK_IDLE_STATE;
- eeprom->data_order = buf[0x01] & FT1284_DATA_LSB;
- eeprom->flow_control = buf[0x01] & FT1284_FLOW_CONTROL;
- eeprom->powersave = buf[0x01] & POWER_SAVE_DISABLE_H;
- eeprom->group0_drive = buf[0x0c] & DRIVE_16MA;
- eeprom->group0_schmitt = buf[0x0c] & IS_SCHMITT;
- eeprom->group0_slew = buf[0x0c] & SLOW_SLEW;
- eeprom->group1_drive = buf[0x0d] & DRIVE_16MA;
- eeprom->group1_schmitt = buf[0x0d] & IS_SCHMITT;
- eeprom->group1_slew = buf[0x0d] & SLOW_SLEW;
+ eeprom->channel_a_driver = !!(buf[0x00] & DRIVER_VCPH);
+ eeprom->clock_polarity = !!(buf[0x01] & FT1284_CLK_IDLE_STATE);
+ eeprom->data_order = !!(buf[0x01] & FT1284_DATA_LSB);
+ eeprom->flow_control = !!(buf[0x01] & FT1284_FLOW_CONTROL);
+ eeprom->powersave = !!(buf[0x01] & POWER_SAVE_DISABLE_H);
+ eeprom->group0_drive = buf[0x0c] & DRIVE_16MA; /* not a bitflag */
+ eeprom->group0_schmitt = !!(buf[0x0c] & IS_SCHMITT);
+ eeprom->group0_slew = !!(buf[0x0c] & SLOW_SLEW);
+ eeprom->group1_drive = buf[0x0d] & DRIVE_16MA; /* not a bitflag */
+ eeprom->group1_schmitt = !!(buf[0x0d] & IS_SCHMITT);
+ eeprom->group1_slew = !!(buf[0x0d] & SLOW_SLEW);
for(i=0; i<5; i++)
{
{
eeprom->cbus_function[i] = buf[0x1a + i] & 0xFF;
}
- eeprom->group0_drive = buf[0x0c] & 0x03;
- eeprom->group0_schmitt = buf[0x0c] & IS_SCHMITT;
- eeprom->group0_slew = buf[0x0c] & SLOW_SLEW;
- eeprom->group1_drive = (buf[0x0c] >> 4) & 0x03;
- eeprom->group1_schmitt = (buf[0x0c] >> 4) & IS_SCHMITT;
- eeprom->group1_slew = (buf[0x0c] >> 4) & SLOW_SLEW;
-
- eeprom->invert = buf[0xb];
+ eeprom->group0_drive = buf[0x0c] & DRIVE_16MA; /* not a bitflag */
+ eeprom->group0_schmitt = !!(buf[0x0c] & IS_SCHMITT);
+ eeprom->group0_slew = !!(buf[0x0c] & SLOW_SLEW);
+ eeprom->group1_drive = (buf[0x0c] >> 4) & DRIVE_16MA; /* not a bitflag */
+ eeprom->group1_schmitt = !!((buf[0x0c] >> 4) & IS_SCHMITT);
+ eeprom->group1_slew = !!((buf[0x0c] >> 4) & SLOW_SLEW);
+
+ eeprom->invert = buf[0xb]; /* not a bitflag */
}
if (verbose)
(eeprom->data_order)?"LSB":"MSB",
(eeprom->flow_control)?"":"No ");
}
- if ((ftdi->type == TYPE_2232H) || (ftdi->type == TYPE_4232H))
+ if ((ftdi->type == TYPE_2232H) || (ftdi->type == TYPE_4232H) || (ftdi->type == TYPE_2232C))
fprintf(stdout,"Channel B has Mode %s%s%s\n",
channel_mode[eeprom->channel_b_type],
(eeprom->channel_b_driver)?" VCP":"",
(eeprom->high_current_b)?" High Current IO":"");
+ if (ftdi->type == TYPE_4232H)
+ {
+ fprintf(stdout,"Channel C has Mode UART%s\n",
+ (eeprom->channel_c_driver)?" VCP":"");
+ fprintf(stdout,"Channel D has Mode UART%s\n",
+ (eeprom->channel_d_driver)?" VCP":"");
+ }
if (((ftdi->type == TYPE_BM) || (ftdi->type == TYPE_2232C)) &&
eeprom->use_usb_version)
fprintf(stdout,"Use explicit USB Version %04x\n",eeprom->usb_version);
case EXTERNAL_OSCILLATOR:
*value = ftdi->eeprom->external_oscillator;
break;
+ case USER_DATA_ADDR:
+ *value = ftdi->eeprom->user_data_addr;
+ break;
default:
ftdi_error_return(-1, "Request for unknown EEPROM value");
}