ftdi.c - description
-------------------
begin : Fri Apr 4 2003
- copyright : (C) 2003-2010 by Intra2net AG
+ copyright : (C) 2003-2011 by Intra2net AG and the libftdi developers
email : opensource@intra2net.com
***************************************************************************/
\retval 0: all fine
\retval -1: couldn't allocate read buffer
\retval -2: couldn't allocate struct buffer
+ \retval -3: libusb_init() failed
\remark This should be called before all functions
*/
ftdi->readbuffer_remaining = 0;
ftdi->writebuffer_chunksize = 4096;
ftdi->max_packet_size = 0;
+ ftdi->error_str = NULL;
+ ftdi->module_detach_mode = AUTO_DETACH_SIO_MODULE;
+
+ if (libusb_init(&ftdi->usb_ctx) < 0)
+ 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->error_str = NULL;
-
if (eeprom == 0)
ftdi_error_return(-2, "Can't malloc struct ftdi_eeprom");
memset(eeprom, 0, sizeof(struct ftdi_eeprom));
free(ftdi->eeprom);
ftdi->eeprom = NULL;
}
- libusb_exit(ftdi->usb_ctx);
+
+ if (ftdi->usb_ctx)
+ {
+ libusb_exit(ftdi->usb_ctx);
+ ftdi->usb_ctx = NULL;
+ }
}
/**
\retval >0: number of devices found
\retval -3: out of memory
- \retval -4: libusb_init() failed
\retval -5: libusb_get_device_list() failed
\retval -6: libusb_get_device_descriptor() failed
*/
int count = 0;
int i = 0;
- if (libusb_init(&ftdi->usb_ctx) < 0)
- ftdi_error_return(-4, "libusb_init() failed");
-
if (libusb_get_device_list(ftdi->usb_ctx, &devs) < 0)
ftdi_error_return(-5, "libusb_get_device_list() failed");
struct libusb_device_descriptor desc;
if (libusb_get_device_descriptor(dev, &desc) < 0)
- ftdi_error_return(-6, "libusb_get_device_descriptor() failed");
+ ftdi_error_return_free_device_list(-6, "libusb_get_device_descriptor() failed", devs);
if (desc.idVendor == vendor && desc.idProduct == product)
{
*curdev = (struct ftdi_device_list*)malloc(sizeof(struct ftdi_device_list));
if (!*curdev)
- ftdi_error_return(-3, "out of memory");
+ ftdi_error_return_free_device_list(-3, "out of memory", devs);
(*curdev)->next = NULL;
(*curdev)->dev = dev;
count++;
}
}
-
+ libusb_free_device_list(devs,1);
return count;
}
// 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)
+ if (ftdi->type == TYPE_2232H || ftdi->type == TYPE_4232H || ftdi->type == TYPE_232H )
packet_size = 512;
else
packet_size = 64;
\retval -8: ftdi context invalid
\retval -9: libusb_get_device_descriptor() failed
\retval -10: libusb_get_config_descriptor() failed
- \retval -11: libusb_etach_kernel_driver() failed
+ \retval -11: libusb_detach_kernel_driver() failed
\retval -12: libusb_get_configuration() failed
*/
int ftdi_usb_open_dev(struct ftdi_context *ftdi, libusb_device *dev)
// if usb_set_configuration() or usb_claim_interface() fails as the
// detach operation might be denied and everything still works fine.
// Likely scenario is a static ftdi_sio kernel module.
- if (libusb_detach_kernel_driver(ftdi->usb_dev, ftdi->interface) !=0)
- detach_errno = errno;
+ if (ftdi->module_detach_mode == AUTO_DETACH_SIO_MODULE)
+ {
+ if (libusb_detach_kernel_driver(ftdi->usb_dev, ftdi->interface) !=0)
+ detach_errno = errno;
+ }
if (libusb_get_configuration (ftdi->usb_dev, &cfg) < 0)
ftdi_error_return(-12, "libusb_get_configuration () failed");
ftdi->type = TYPE_2232H;
else if (desc.bcdDevice == 0x800)
ftdi->type = TYPE_4232H;
+ else if (desc.bcdDevice == 0x900)
+ ftdi->type = TYPE_232H;
// Determine maximum packet size
ftdi->max_packet_size = _ftdi_determine_max_packet_size(ftdi, dev);
char string[256];
int i = 0;
- if (libusb_init(&ftdi->usb_ctx) < 0)
- ftdi_error_return(-11, "libusb_init() failed");
-
if (ftdi == NULL)
ftdi_error_return(-11, "ftdi context invalid");
+ if (libusb_init(&ftdi->usb_ctx) < 0)
+ ftdi_error_return(-11, "libusb_init() failed");
+
if (libusb_get_device_list(ftdi->usb_ctx, &devs) < 0)
ftdi_error_return(-12, "libusb_get_device_list() failed");
{
if (libusb_get_string_descriptor_ascii(ftdi->usb_dev, desc.iProduct, (unsigned char *)string, sizeof(string)) < 0)
{
- libusb_close (ftdi->usb_dev);
+ ftdi_usb_close_internal (ftdi);
ftdi_error_return_free_device_list(-8, "unable to fetch product description", devs);
}
if (strncmp(string, description, sizeof(string)) != 0)
{
- libusb_close (ftdi->usb_dev);
+ ftdi_usb_close_internal (ftdi);
continue;
}
}
struct ftdi_transfer_control *ftdi_write_data_submit(struct ftdi_context *ftdi, unsigned char *buf, int size)
{
struct ftdi_transfer_control *tc;
- struct libusb_transfer *transfer = libusb_alloc_transfer(0);
+ struct libusb_transfer *transfer;
int write_size, ret;
if (ftdi == NULL || ftdi->usb_dev == NULL)
- {
- libusb_free_transfer(transfer);
return NULL;
- }
tc = (struct ftdi_transfer_control *) malloc (sizeof (*tc));
+ if (!tc)
+ return NULL;
- if (!tc || !transfer)
+ transfer = libusb_alloc_transfer(0);
+ if (!transfer)
+ {
+ free(tc);
return NULL;
+ }
tc->ftdi = ftdi;
tc->completed = 0;
if (ret < 0)
{
libusb_free_transfer(transfer);
- tc->completed = 1;
- tc->transfer = NULL;
+ free(tc);
return NULL;
}
tc->transfer = transfer;
if (libusb_control_transfer(ftdi->usb_dev, FTDI_DEVICE_IN_REQTYPE, SIO_POLL_MODEM_STATUS_REQUEST, 0, ftdi->index, (unsigned char *)usb_val, 2, ftdi->usb_read_timeout) != 2)
ftdi_error_return(-1, "getting modem status failed");
- *status = (usb_val[1] << 8) | usb_val[0];
+ *status = (usb_val[1] << 8) | (usb_val[0] & 0xFF);
return 0;
}
if ((ftdi->type == TYPE_AM) || (ftdi->type == TYPE_BM) ||
(ftdi->type == TYPE_R))
eeprom->product_id = 0x6001;
+ else if (ftdi->type == TYPE_4232H)
+ eeprom->product_id = 0x6011;
+ else if (ftdi->type == TYPE_232H)
+ eeprom->product_id = 0x6014;
else
eeprom->product_id = 0x6010;
if (ftdi->type == TYPE_AM)
if (eeprom->product)
free (eeprom->product);
eeprom->product = NULL;
+ if(product)
{
eeprom->product = malloc(strlen(product)+1);
if (eeprom->product)
case TYPE_4232H:
output[0x07] = 0x08;
break;
+ case TYPE_232H:
+ output[0x07] = 0x09;
+ break;
default:
output[0x07] = 0x00;
}
// Dynamic content
// Strings start at 0x94 (TYPE_AM, TYPE_BM)
// 0x96 (TYPE_2232C), 0x98 (TYPE_R) and 0x9a (TYPE_x232H)
+ // 0xa0 (TYPE_232H)
i = 0;
switch (ftdi->type)
{
+ case TYPE_232H:
+ i += 2;
case TYPE_2232H:
case TYPE_4232H:
i += 2;
break;
case TYPE_4232H:
+ output[0x18] = eeprom->chip;
fprintf(stderr,"FIXME: Build FT4232H specific EEPROM settings\n");
+ break;
+ case TYPE_232H:
+ output[0x00] = (eeprom->channel_a_type);
+ if ( eeprom->channel_a_driver == DRIVER_VCP)
+ output[0x00] |= DRIVER_VCPH;
+ else
+ output[0x00] &= ~DRIVER_VCPH;
+
+ 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[0x0d] |= DRIVE_16MA;
+ else
+ output[0x0d] |= eeprom->group1_drive;
+ if (eeprom->group1_schmitt == IS_SCHMITT)
+ output[0x0d] |= IS_SCHMITT;
+ if (eeprom->group1_slew == SLOW_SLEW)
+ output[0x0d] |= SLOW_SLEW;
+
+ output[0x1e] = eeprom->chip;
+ fprintf(stderr,"FIXME: Build FT232H specific EEPROM settings\n");
+ break;
+
}
// calculate checksum
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->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->chip = buf[0x1e];
+ /*FIXME: Decipher more values*/
+ }
if (verbose)
{
- char *channel_mode[] = {"UART","245","CPU", "unknown", "OPTO"};
+ char *channel_mode[] = {"UART","245","CPU", "unknown", "OPTO", "unknown1","unknown2","unknown3","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);
channel_mode[eeprom->channel_a_type],
(eeprom->channel_a_driver)?" VCP":"",
(eeprom->high_current_a)?" High Current IO":"");
- if ((ftdi->type >= TYPE_2232C) && (ftdi->type != TYPE_R))
+ if ((ftdi->type >= TYPE_2232C) && (ftdi->type != TYPE_R) && (ftdi->type != TYPE_232H))
fprintf(stdout,"Channel B has Mode %s%s%s\n",
channel_mode[eeprom->channel_b_type],
(eeprom->channel_b_driver)?" VCP":"",
(eeprom->group3_schmitt)?" Schmitt Input":"",
(eeprom->group3_slew)?" Slow Slew":"");
}
+ else if (ftdi->type == TYPE_232H)
+ {
+ fprintf(stdout,"ACBUS has %d mA drive%s%s\n",
+ (eeprom->group0_drive+1) *4,
+ (eeprom->group0_schmitt)?" Schmitt Input":"",
+ (eeprom->group0_slew)?" Slow Slew":"");
+ fprintf(stdout,"ADBUS has %d mA drive%s%s\n",
+ (eeprom->group1_drive+1) *4,
+ (eeprom->group1_schmitt)?" Schmitt Input":"",
+ (eeprom->group1_slew)?" Slow Slew":"");
+ }
+
if (ftdi->type == TYPE_R)
{
char *cbus_mux[] = {"TXDEN","PWREN","RXLED", "TXLED","TX+RXLED",
"IOMODE","BB_WR","BB_RD"
};
char *cbus_BB[] = {"RXF","TXE","RD", "WR"};
- int i;
if (eeprom->invert)
{
cbus_mux[eeprom->cbus_function[i]]);
else
{
- /* FIXME for Uwe: This results in an access above array bounds.
- Also I couldn't find documentation about this mode.
- fprintf(stdout,"C%d BB Function: %s\n", i,
- cbus_BB[i]);
- */
- fprintf(stdout, "Unknown CBUS mode. Might be special mode?\n");
- (void)cbus_BB;
+ if (i < 4)
+ /* Running MPROG show that C0..3 have fixed function Synchronous
+ Bit Bang mode */
+ fprintf(stdout,"C%d BB Function: %s\n", i,
+ cbus_BB[i]);
+ else
+ fprintf(stdout, "Unknown CBUS mode. Might be special mode?\n");
}
}
}
No parameter checking is performed
\param ftdi pointer to ftdi_context
- \param value_name Enum of the value to query
+ \param value_name Enum of the value to set
\param value to set
\retval 0: all fine
\retval 0: All fine
\retval -1: struct ftdi_contxt or ftdi_eeprom missing
+ \retval -2: Not enough room to store eeprom
*/
int ftdi_get_eeprom_buf(struct ftdi_context *ftdi, unsigned char * buf, int size)
{
if (!ftdi || !(ftdi->eeprom))
ftdi_error_return(-1, "No appropriate structure");
+
+ if (!buf || size < ftdi->eeprom->size)
+ ftdi_error_return(-1, "Not enough room to store eeprom");
+
+ // Only copy up to FTDI_MAX_EEPROM_SIZE bytes
+ if (size > FTDI_MAX_EEPROM_SIZE)
+ size = FTDI_MAX_EEPROM_SIZE;
+
memcpy(buf, ftdi->eeprom->buf, size);
+
return 0;
}
case TYPE_4232H:
chip_type_location = 0x18;
break;
+ case TYPE_232H:
+ chip_type_location = 0x1e;
+ break;
default:
ftdi_error_return(-4, "Device can't access unprotected area");
}