ftdi.c - description
-------------------
begin : Fri Apr 4 2003
- copyright : (C) 2003-2011 by Intra2net AG and the libftdi developers
+ copyright : (C) 2003-2013 by Intra2net AG and the libftdi developers
email : opensource@intra2net.com
***************************************************************************/
// Determine maximum packet size. Init with default value.
// New hi-speed devices from FTDI use a packet size of 512 bytes
// but could be connected to a normal speed USB hub -> 64 bytes packet size.
- if (ftdi->type == TYPE_2232H || ftdi->type == TYPE_4232H || ftdi->type == TYPE_232H )
+ if (ftdi->type == TYPE_2232H || ftdi->type == TYPE_4232H || ftdi->type == TYPE_232H || ftdi->type == TYPE_230X)
packet_size = 512;
else
packet_size = 64;
ftdi->type = TYPE_4232H;
else if (desc.bcdDevice == 0x900)
ftdi->type = TYPE_232H;
+ else if (desc.bcdDevice == 0x1000)
+ ftdi->type = TYPE_230X;
// Determine maximum packet size
ftdi->max_packet_size = _ftdi_determine_max_packet_size(ftdi, dev);
#define H_CLK 120000000
#define C_CLK 48000000
- if ((ftdi->type == TYPE_2232H) || (ftdi->type == TYPE_4232H) || (ftdi->type == TYPE_232H ))
+ if ((ftdi->type == TYPE_2232H) || (ftdi->type == TYPE_4232H) || (ftdi->type == TYPE_232H) || (ftdi->type == TYPE_230X))
{
if(baudrate*10 > H_CLK /0x3fff)
{
}
// Split into "value" and "index" values
*value = (unsigned short)(encoded_divisor & 0xFFFF);
- if (ftdi->type == TYPE_2232H ||
- ftdi->type == TYPE_4232H || ftdi->type == TYPE_232H )
+ if (ftdi->type == TYPE_2232H || ftdi->type == TYPE_4232H || ftdi->type == TYPE_232H || ftdi->type == TYPE_230X)
{
*index = (unsigned short)(encoded_divisor >> 8);
*index &= 0xFF00;
tc->size = size;
tc->offset = 0;
- if (size < ftdi->writebuffer_chunksize)
+ if (size < (int)ftdi->writebuffer_chunksize)
write_size = size;
else
write_size = ftdi->writebuffer_chunksize;
tc->buf = buf;
tc->size = size;
- if (size <= ftdi->readbuffer_remaining)
+ if (size <= (int)ftdi->readbuffer_remaining)
{
memcpy (buf, ftdi->readbuffer+ftdi->readbuffer_offset, size);
ftdi_error_return(-1, "max_packet_size is bogus (zero)");
// everything we want is still in the readbuffer?
- if (size <= ftdi->readbuffer_remaining)
+ if (size <= (int)ftdi->readbuffer_remaining)
{
memcpy (buf, ftdi->readbuffer+ftdi->readbuffer_offset, size);
eeprom->product_id = 0x6011;
else if (ftdi->type == TYPE_232H)
eeprom->product_id = 0x6014;
+ else if (ftdi->type == TYPE_230X)
+ eeprom->product_id = 0x6015;
else
eeprom->product_id = 0x6010;
+
if (ftdi->type == TYPE_AM)
eeprom->usb_version = 0x0101;
else
case TYPE_2232H: default_product = "Dual RS232-HS"; break;
case TYPE_4232H: default_product = "FT4232H"; break;
case TYPE_232H: default_product = "Single-RS232-HS"; break;
+ case TYPE_230X: default_product = "FT230X Basic UART"; break;
default:
ftdi_error_return(-3, "Unknown chip type");
}
eeprom->cbus_function[3] = CBUS_PWREN;
eeprom->cbus_function[4] = CBUS_SLEEP;
}
+ else if (ftdi->type == TYPE_230X)
+ {
+ eeprom->max_power = 90;
+ eeprom->size = 0x100;
+ eeprom->cbus_function[0] = CBUSH_TXDEN;
+ eeprom->cbus_function[1] = CBUSH_RXLED;
+ eeprom->cbus_function[2] = CBUSH_TXLED;
+ eeprom->cbus_function[3] = CBUSH_SLEEP;
+ }
else
{
if(ftdi->type == TYPE_232H)
}
eeprom->size = -1;
}
- eeprom->initialized_for_connected_device = 1;
+ switch (ftdi->type)
+ {
+ case TYPE_AM:
+ eeprom->release_number = 0x0200;
+ break;
+ case TYPE_BM:
+ eeprom->release_number = 0x0400;
+ break;
+ case TYPE_2232C:
+ eeprom->release_number = 0x0500;
+ break;
+ case TYPE_R:
+ eeprom->release_number = 0x0600;
+ break;
+ case TYPE_2232H:
+ eeprom->release_number = 0x0700;
+ break;
+ case TYPE_4232H:
+ eeprom->release_number = 0x0800;
+ break;
+ case TYPE_232H:
+ eeprom->release_number = 0x0900;
+ break;
+ case TYPE_230X:
+ eeprom->release_number = 0x1000;
+ break;
+ default:
+ eeprom->release_number = 0x00;
+ }
+ return 0;
+}
+
+int ftdi_eeprom_set_strings(struct ftdi_context *ftdi, char * manufacturer,
+ char * product, char * serial)
+{
+ struct ftdi_eeprom *eeprom;
+
+ if (ftdi == NULL)
+ ftdi_error_return(-1, "No struct ftdi_context");
+
+ if (ftdi->eeprom == NULL)
+ ftdi_error_return(-2,"No struct ftdi_eeprom");
+
+ eeprom = ftdi->eeprom;
+
+ if (ftdi->usb_dev == NULL)
+ ftdi_error_return(-3, "No connected device or device not yet opened");
+
+ if (manufacturer) {
+ if (eeprom->manufacturer)
+ free (eeprom->manufacturer);
+ eeprom->manufacturer = malloc(strlen(manufacturer)+1);
+ if (eeprom->manufacturer)
+ strcpy(eeprom->manufacturer, manufacturer);
+ }
+
+ if(product) {
+ if (eeprom->product)
+ free (eeprom->product);
+ eeprom->product = malloc(strlen(product)+1);
+ if (eeprom->product)
+ strcpy(eeprom->product, product);
+ }
+
+ if (serial) {
+ if (eeprom->serial)
+ free (eeprom->serial);
+ eeprom->serial = malloc(strlen(serial)+1);
+ if (eeprom->serial) {
+ strcpy(eeprom->serial, serial);
+ eeprom->use_serial = 1;
+ }
+ }
return 0;
}
+
+
/*FTD2XX doesn't check for values not fitting in the ACBUS Signal oprtions*/
void set_ft232h_cbus(struct ftdi_eeprom *eeprom, unsigned char * output)
{
default: return 0;
}
}
+ case TYPE_230X: /* FT230X is only UART */
default: return 0;
}
return 0;
if (eeprom->chip == -1)
ftdi_error_return(-6,"No connected EEPROM or EEPROM type unknown");
- if ((eeprom->chip == 0x56) || (eeprom->chip == 0x66))
- eeprom->size = 0x100;
- else
- eeprom->size = 0x80;
+ if (eeprom->size == -1) {
+ if ((eeprom->chip == 0x56) || (eeprom->chip == 0x66))
+ eeprom->size = 0x100;
+ else
+ eeprom->size = 0x80;
+ }
if (eeprom->manufacturer != NULL)
manufacturer_size = strlen(eeprom->manufacturer);
user_area_size = 90; // two extra config bytes and 4 bytes PnP stuff
break;
case TYPE_R:
+ case TYPE_230X:
user_area_size = 88; // four extra config bytes + 4 bytes PnP stuff
break;
case TYPE_2232H: // six extra config bytes + 4 bytes PnP stuff
ftdi_error_return(-1,"eeprom size exceeded");
// empty eeprom
- memset (ftdi->eeprom->buf, 0, FTDI_MAX_EEPROM_SIZE);
+ if (ftdi->type == TYPE_230X) {
+ /* FT230X have a reserved section in the middle of the MTP,
+ which cannot be written to, but must be included in the checksum */
+ memset(ftdi->eeprom->buf, 0, 0x80);
+ memset((ftdi->eeprom->buf + 0xa0), 0, (FTDI_MAX_EEPROM_SIZE - 0xa0));
+ } else {
+ memset(ftdi->eeprom->buf, 0, FTDI_MAX_EEPROM_SIZE);
+ }
// Bytes and Bits set for all Types
output[0x05] = eeprom->product_id >> 8;
// Addr 06: Device release number (0400h for BM features)
- output[0x06] = 0x00;
- switch (ftdi->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;
- case TYPE_2232H:
- output[0x07] = 0x07;
- break;
- case TYPE_4232H:
- output[0x07] = 0x08;
- break;
- case TYPE_232H:
- output[0x07] = 0x09;
- break;
- default:
- output[0x07] = 0x00;
- }
+ output[0x06] = eeprom->release_number;
+ output[0x07] = eeprom->release_number >> 8;
// Addr 08: Config descriptor
// Bit 7: always 1
// Bit 5: 1 if this device uses remote wakeup
// Bit 4-0: reserved - 0
j = 0x80;
- if (eeprom->self_powered == 1)
+ if (eeprom->self_powered)
j |= 0x40;
- if (eeprom->remote_wakeup == 1)
+ if (eeprom->remote_wakeup)
j |= 0x20;
output[0x08] = j;
// Addr 09: Max power consumption: max power = value * 2 mA
output[0x09] = eeprom->max_power / MAX_POWER_MILLIAMP_PER_UNIT;
- if (ftdi->type != TYPE_AM)
+ if ((ftdi->type != TYPE_AM) && (ftdi->type != TYPE_230X))
{
// Addr 0A: Chip configuration
// Bit 7: 0 - reserved
// Bit 0: 1 - In EndPoint is Isochronous
//
j = 0;
- if (eeprom->in_is_isochronous == 1)
+ if (eeprom->in_is_isochronous)
j = j | 1;
- if (eeprom->out_is_isochronous == 1)
+ if (eeprom->out_is_isochronous)
j = j | 2;
output[0x0A] = j;
}
case TYPE_AM:
case TYPE_BM:
i += 0x94;
+ break;
+ case TYPE_230X:
+ i = 0xa0;
+ break;
}
/* Wrap around 0x80 for 128 byte EEPROMS (Internale and 93x46) */
eeprom_size_mask = eeprom->size -1;
else
output[0x01] &= ~HIGH_CURRENT_DRIVE;
- if (eeprom->in_is_isochronous == 1)
+ if (eeprom->in_is_isochronous)
output[0x0A] |= 0x1;
else
output[0x0A] &= ~0x1;
- if (eeprom->out_is_isochronous == 1)
+ if (eeprom->out_is_isochronous)
output[0x0A] |= 0x2;
else
output[0x0A] &= ~0x2;
- if (eeprom->suspend_pull_downs == 1)
+ if (eeprom->suspend_pull_downs)
output[0x0A] |= 0x4;
else
output[0x0A] &= ~0x4;
output[0x00] |= HIGH_CURRENT_DRIVE_R;
output[0x01] = 0x40; /* Hard coded Endpoint Size*/
- if (eeprom->suspend_pull_downs == 1)
+ if (eeprom->suspend_pull_downs)
output[0x0A] |= 0x4;
else
output[0x0A] &= ~0x4;
else
output[0x01] &= ~SUSPEND_DBUS7_BIT;
- if (eeprom->suspend_pull_downs == 1)
+ if (eeprom->suspend_pull_downs)
output[0x0A] |= 0x4;
else
output[0x0A] &= ~0x4;
else
output[0x01] &= ~(DRIVER_VCP << 4);
- if (eeprom->suspend_pull_downs == 1)
+ if (eeprom->suspend_pull_downs)
output[0x0a] |= 0x4;
else
output[0x0a] &= ~0x4;
output[0x1e] = eeprom->chip;
fprintf(stderr,"FIXME: Build FT232H specific EEPROM settings\n");
break;
-
+ case TYPE_230X:
+ output[0x00] = 0x80; /* Actually, leave the default value */
+ output[0x0a] = 0x08; /* Enable USB Serial Number */
+ output[0x0c] = (0x01) | (0x3 << 4); /* DBUS drive 4mA, CBUS drive 16mA */
+ for (j = 0; j <= 6; j++) {
+ output[0x1a + j] = eeprom->cbus_function[j];
+ }
+ break;
}
// calculate checksum
for (i = 0; i < eeprom->size/2-1; i++)
{
+ if ((ftdi->type == TYPE_230X) && (i == 0x12)) {
+ /* FT230X has a user section in the MTP which is not part of the checksum */
+ i = 0x40;
+ }
value = output[i*2];
value += output[(i*2)+1] << 8;
output[eeprom->size-2] = checksum;
output[eeprom->size-1] = checksum >> 8;
+ eeprom->initialized_for_connected_device = 1;
return user_area_size;
}
/* Decode the encoded EEPROM field for the FTDI Mode into a value for the abstracted
unsigned char manufacturer_size = 0, product_size = 0, serial_size = 0;
int eeprom_size;
struct ftdi_eeprom *eeprom;
- unsigned char *buf = ftdi->eeprom->buf;
- int release;
+ unsigned char *buf = NULL;
if (ftdi == NULL)
ftdi_error_return(-1,"No context");
eeprom = ftdi->eeprom;
eeprom_size = eeprom->size;
+ buf = ftdi->eeprom->buf;
// Addr 02: Vendor ID
eeprom->vendor_id = buf[0x02] + (buf[0x03] << 8);
// Addr 04: Product ID
eeprom->product_id = buf[0x04] + (buf[0x05] << 8);
- release = buf[0x06] + (buf[0x07]<<8);
+ // Addr 06: Device release number
+ eeprom->release_number = buf[0x06] + (buf[0x07]<<8);
// Addr 08: Config descriptor
// Bit 7: always 1
for (i = 0; i < eeprom_size/2-1; i++)
{
+ if ((ftdi->type == TYPE_230X) && (i == 0x12)) {
+ /* FT230X has a user section in the MTP which is not part of the checksum */
+ i = 0x40;
+ }
value = buf[i*2];
value += buf[(i*2)+1] << 8;
eeprom->chip = buf[0x1e];
/*FIXME: Decipher more values*/
}
+ else if (ftdi->type == TYPE_230X)
+ {
+ for(i=0; i<4; 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;
+ }
if (verbose)
{
char *channel_mode[] = {"UART", "FIFO", "CPU", "OPTO", "FT1284"};
fprintf(stdout, "VID: 0x%04x\n",eeprom->vendor_id);
fprintf(stdout, "PID: 0x%04x\n",eeprom->product_id);
- fprintf(stdout, "Release: 0x%04x\n",release);
+ fprintf(stdout, "Release: 0x%04x\n",eeprom->release_number);
if (eeprom->self_powered)
fprintf(stdout, "Self-Powered%s", (eeprom->remote_wakeup)?", USB Remote Wake Up\n":"\n");
cbush_mux[eeprom->cbus_function[i]]);
}
}
+ else if (ftdi->type == TYPE_230X)
+ {
+ int i;
+ char *cbush_mux[] = {"TRISTATE","RXLED","TXLED", "TXRXLED","PWREN",
+ "SLEEP","DRIVE_0","DRIVE_1","IOMODE","TXDEN",
+ "CLK24","CLK12","CLK6","BAT_DETECT","BAT_DETECT#",
+ "I2C_TXE#", "I2C_RXF#", "VBUS_SENSE", "BB_WR#",
+ "BBRD#", "TIME_STAMP", "AWAKE#",
+ };
+ fprintf(stdout,"IOBUS has %d mA drive%s%s\n",
+ (eeprom->group0_drive+1) *4,
+ (eeprom->group0_schmitt)?" Schmitt Input":"",
+ (eeprom->group0_slew)?" Slow Slew":"");
+ fprintf(stdout,"CBUS has %d mA drive%s%s\n",
+ (eeprom->group1_drive+1) *4,
+ (eeprom->group1_schmitt)?" Schmitt Input":"",
+ (eeprom->group1_slew)?" Slow Slew":"");
+ for (i=0; i<4; i++)
+ {
+ if (eeprom->cbus_function[i]<= CBUSH_AWAKE)
+ fprintf(stdout,"CBUS%d Function: %s\n", i, cbush_mux[eeprom->cbus_function[i]]);
+ }
+ }
if (ftdi->type == TYPE_R)
{
case PRODUCT_ID:
*value = ftdi->eeprom->product_id;
break;
+ case RELEASE_NUMBER:
+ *value = ftdi->eeprom->release_number;
+ break;
case SELF_POWERED:
*value = ftdi->eeprom->self_powered;
break;
case PRODUCT_ID:
ftdi->eeprom->product_id = value;
break;
+ case RELEASE_NUMBER:
+ ftdi->eeprom->release_number = value;
+ break;
case SELF_POWERED:
ftdi->eeprom->self_powered = value;
break;
default :
ftdi_error_return(-1, "Request to unknown EEPROM value");
}
+ ftdi->eeprom->initialized_for_connected_device = 0;
return 0;
}
for (i = 0; i < ftdi->eeprom->size/2; i++)
{
+ /* Do not try to write to reserved area */
+ if ((ftdi->type == TYPE_230X) && (i == 0x40)) {
+ i = 0x50;
+ }
usb_val = eeprom[i*2];
usb_val += eeprom[(i*2)+1] << 8;
if (libusb_control_transfer(ftdi->usb_dev, FTDI_DEVICE_OUT_REQTYPE,