ftdi.c
Go to the documentation of this file.
/***************************************************************************
ftdi.c - description
-------------------
begin : Fri Apr 4 2003
copyright : (C) 2003-2020 by Intra2net AG and the libftdi developers
email : opensource@intra2net.com
SPDX-License-Identifier: LGPL-2.1-only
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License *
* version 2.1 as published by the Free Software Foundation; *
* *
***************************************************************************/
/* @{ */
#include <libusb.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include "ftdi_i.h"
/* Prevent deprecated messages when building library */
#define _FTDI_DISABLE_DEPRECATED
#include "ftdi.h"
#include "ftdi_version_i.h"
#define ftdi_error_return(code, str) do { \
if ( ftdi ) \
ftdi->error_str = str; \
else \
fprintf(stderr, str); \
return code; \
} while(0);
#define ftdi_error_return_free_device_list(code, str, devs) do { \
libusb_free_device_list(devs,1); \
ftdi->error_str = str; \
return code; \
} while(0);
static void ftdi_usb_close_internal (struct ftdi_context *ftdi)
{
if (ftdi && ftdi->usb_dev)
{
libusb_close (ftdi->usb_dev);
ftdi->usb_dev = NULL;
if(ftdi->eeprom)
ftdi->eeprom->initialized_for_connected_device = 0;
}
}
int ftdi_init(struct ftdi_context *ftdi)
{
struct ftdi_eeprom* eeprom;
ftdi->usb_ctx = NULL;
ftdi->usb_dev = NULL;
ftdi->usb_read_timeout = 5000;
ftdi->usb_write_timeout = 5000;
ftdi->type = TYPE_BM; /* chip type */
ftdi->baudrate = -1;
ftdi->bitbang_enabled = 0; /* 0: normal mode 1: any of the bitbang modes enabled */
ftdi->readbuffer = NULL;
ftdi->readbuffer_offset = 0;
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 */
eeprom = (struct ftdi_eeprom *)malloc(sizeof(struct ftdi_eeprom));
if (eeprom == 0)
ftdi_error_return(-2, "Can't malloc struct ftdi_eeprom");
memset(eeprom, 0, sizeof(struct ftdi_eeprom));
ftdi->eeprom = eeprom;
/* All fine. Now allocate the readbuffer */
return ftdi_read_data_set_chunksize(ftdi, 4096);
}
struct ftdi_context *ftdi_new(void)
{
struct ftdi_context * ftdi = (struct ftdi_context *)malloc(sizeof(struct ftdi_context));
if (ftdi == NULL)
{
return NULL;
}
if (ftdi_init(ftdi) != 0)
{
free(ftdi);
return NULL;
}
return ftdi;
}
int ftdi_set_interface(struct ftdi_context *ftdi, enum ftdi_interface interface)
{
if (ftdi == NULL)
ftdi_error_return(-2, "USB device unavailable");
if (ftdi->usb_dev != NULL)
{
int check_interface = interface;
if (check_interface == INTERFACE_ANY)
check_interface = INTERFACE_A;
if (ftdi->index != check_interface)
ftdi_error_return(-3, "Interface can not be changed on an already open device");
}
switch (interface)
{
case INTERFACE_ANY:
case INTERFACE_A:
ftdi->interface = 0;
ftdi->index = INTERFACE_A;
ftdi->in_ep = 0x02;
ftdi->out_ep = 0x81;
break;
case INTERFACE_B:
ftdi->interface = 1;
ftdi->index = INTERFACE_B;
ftdi->in_ep = 0x04;
ftdi->out_ep = 0x83;
break;
case INTERFACE_C:
ftdi->interface = 2;
ftdi->index = INTERFACE_C;
ftdi->in_ep = 0x06;
ftdi->out_ep = 0x85;
break;
case INTERFACE_D:
ftdi->interface = 3;
ftdi->index = INTERFACE_D;
ftdi->in_ep = 0x08;
ftdi->out_ep = 0x87;
break;
default:
ftdi_error_return(-1, "Unknown interface");
}
return 0;
}
void ftdi_deinit(struct ftdi_context *ftdi)
{
if (ftdi == NULL)
return;
ftdi_usb_close_internal (ftdi);
if (ftdi->readbuffer != NULL)
{
free(ftdi->readbuffer);
ftdi->readbuffer = NULL;
}
if (ftdi->eeprom != NULL)
{
if (ftdi->eeprom->manufacturer != 0)
{
free(ftdi->eeprom->manufacturer);
ftdi->eeprom->manufacturer = 0;
}
if (ftdi->eeprom->product != 0)
{
free(ftdi->eeprom->product);
ftdi->eeprom->product = 0;
}
if (ftdi->eeprom->serial != 0)
{
free(ftdi->eeprom->serial);
ftdi->eeprom->serial = 0;
}
free(ftdi->eeprom);
ftdi->eeprom = NULL;
}
if (ftdi->usb_ctx)
{
libusb_exit(ftdi->usb_ctx);
ftdi->usb_ctx = NULL;
}
}
void ftdi_free(struct ftdi_context *ftdi)
{
ftdi_deinit(ftdi);
free(ftdi);
}
void ftdi_set_usbdev (struct ftdi_context *ftdi, libusb_device_handle *usb)
{
if (ftdi == NULL)
return;
ftdi->usb_dev = usb;
}
struct ftdi_version_info ftdi_get_library_version(void)
{
struct ftdi_version_info ver;
ver.major = FTDI_MAJOR_VERSION;
ver.minor = FTDI_MINOR_VERSION;
ver.micro = FTDI_MICRO_VERSION;
ver.version_str = FTDI_VERSION_STRING;
ver.snapshot_str = FTDI_SNAPSHOT_VERSION;
return ver;
}
int ftdi_usb_find_all(struct ftdi_context *ftdi, struct ftdi_device_list **devlist, int vendor, int product)
{
struct ftdi_device_list **curdev;
libusb_device *dev;
libusb_device **devs;
int count = 0;
int i = 0;
if (libusb_get_device_list(ftdi->usb_ctx, &devs) < 0)
ftdi_error_return(-5, "libusb_get_device_list() failed");
curdev = devlist;
*curdev = NULL;
while ((dev = devs[i++]) != NULL)
{
struct libusb_device_descriptor desc;
if (libusb_get_device_descriptor(dev, &desc) < 0)
ftdi_error_return_free_device_list(-6, "libusb_get_device_descriptor() failed", devs);
if (((vendor || product) &&
desc.idVendor == vendor && desc.idProduct == product) ||
(!(vendor || product) &&
(desc.idVendor == 0x403) && (desc.idProduct == 0x6001 || desc.idProduct == 0x6010
|| desc.idProduct == 0x6011 || desc.idProduct == 0x6014
|| desc.idProduct == 0x6015)))
{
*curdev = (struct ftdi_device_list*)malloc(sizeof(struct ftdi_device_list));
if (!*curdev)
ftdi_error_return_free_device_list(-3, "out of memory", devs);
(*curdev)->next = NULL;
(*curdev)->dev = dev;
libusb_ref_device(dev);
curdev = &(*curdev)->next;
count++;
}
}
libusb_free_device_list(devs,1);
return count;
}
void ftdi_list_free(struct ftdi_device_list **devlist)
{
struct ftdi_device_list *curdev, *next;
for (curdev = *devlist; curdev != NULL;)
{
next = curdev->next;
libusb_unref_device(curdev->dev);
free(curdev);
curdev = next;
}
*devlist = NULL;
}
void ftdi_list_free2(struct ftdi_device_list *devlist)
{
ftdi_list_free(&devlist);
}
int ftdi_usb_get_strings(struct ftdi_context *ftdi,
struct libusb_device *dev,
char *manufacturer, int mnf_len,
char *description, int desc_len,
char *serial, int serial_len)
{
int ret;
if ((ftdi==NULL) || (dev==NULL))
return -1;
if (ftdi->usb_dev == NULL && libusb_open(dev, &ftdi->usb_dev) < 0)
ftdi_error_return(-4, "libusb_open() failed");
// ftdi->usb_dev will not be NULL when entering ftdi_usb_get_strings2(), so
// it won't be closed either. This allows us to close it whether we actually
// called libusb_open() up above or not. This matches the expected behavior
// (and note) for ftdi_usb_get_strings().
ret = ftdi_usb_get_strings2(ftdi, dev,
manufacturer, mnf_len,
description, desc_len,
serial, serial_len);
// only close it if it was successful, as all other return codes close
// before returning already.
if (ret == 0)
ftdi_usb_close_internal(ftdi);
return ret;
}
int ftdi_usb_get_strings2(struct ftdi_context *ftdi, struct libusb_device *dev,
char *manufacturer, int mnf_len,
char *description, int desc_len,
char *serial, int serial_len)
{
struct libusb_device_descriptor desc;
char need_open;
if ((ftdi==NULL) || (dev==NULL))
return -1;
need_open = (ftdi->usb_dev == NULL);
if (need_open && libusb_open(dev, &ftdi->usb_dev) < 0)
ftdi_error_return(-4, "libusb_open() failed");
if (libusb_get_device_descriptor(dev, &desc) < 0)
ftdi_error_return(-11, "libusb_get_device_descriptor() failed");
if (manufacturer != NULL)
{
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 (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 (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");
}
}
if (need_open)
ftdi_usb_close_internal (ftdi);
return 0;
}
static unsigned int _ftdi_determine_max_packet_size(struct ftdi_context *ftdi, libusb_device *dev)
{
struct libusb_device_descriptor desc;
struct libusb_config_descriptor *config0;
unsigned int packet_size;
// Sanity check
if (ftdi == NULL || dev == NULL)
return 64;
// 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)
packet_size = 512;
else
packet_size = 64;
if (libusb_get_device_descriptor(dev, &desc) < 0)
return packet_size;
if (libusb_get_config_descriptor(dev, 0, &config0) < 0)
return packet_size;
if (desc.bNumConfigurations > 0)
{
if (ftdi->interface < config0->bNumInterfaces)
{
struct libusb_interface interface = config0->interface[ftdi->interface];
if (interface.num_altsetting > 0)
{
struct libusb_interface_descriptor descriptor = interface.altsetting[0];
if (descriptor.bNumEndpoints > 0)
{
packet_size = descriptor.endpoint[0].wMaxPacketSize;
}
}
}
}
libusb_free_config_descriptor (config0);
return packet_size;
}
int ftdi_usb_open_dev(struct ftdi_context *ftdi, libusb_device *dev)
{
struct libusb_device_descriptor desc;
struct libusb_config_descriptor *config0;
int cfg, cfg0, detach_errno = 0;
if (ftdi == NULL)
ftdi_error_return(-8, "ftdi context invalid");
if (libusb_open(dev, &ftdi->usb_dev) < 0)
ftdi_error_return(-4, "libusb_open() failed");
if (libusb_get_device_descriptor(dev, &desc) < 0)
ftdi_error_return(-9, "libusb_get_device_descriptor() failed");
if (libusb_get_config_descriptor(dev, 0, &config0) < 0)
ftdi_error_return(-10, "libusb_get_config_descriptor() failed");
cfg0 = config0->bConfigurationValue;
libusb_free_config_descriptor (config0);
// Try to detach ftdi_sio kernel module.
//
// The return code is kept in a separate variable and only parsed
// 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 (ftdi->module_detach_mode == AUTO_DETACH_SIO_MODULE)
{
if (libusb_detach_kernel_driver(ftdi->usb_dev, ftdi->interface) !=0)
detach_errno = errno;
}
else if (ftdi->module_detach_mode == AUTO_DETACH_REATACH_SIO_MODULE)
{
if (libusb_set_auto_detach_kernel_driver(ftdi->usb_dev, 1) != LIBUSB_SUCCESS)
detach_errno = errno;
}
if (libusb_get_configuration (ftdi->usb_dev, &cfg) < 0)
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)
if (desc.bNumConfigurations > 0 && cfg != cfg0)
{
if (libusb_set_configuration(ftdi->usb_dev, cfg0) < 0)
{
ftdi_usb_close_internal (ftdi);
if (detach_errno == EPERM)
{
ftdi_error_return(-8, "inappropriate permissions on device!");
}
else
{
ftdi_error_return(-3, "unable to set usb configuration. Make sure the default FTDI driver is not in use");
}
}
}
if (libusb_claim_interface(ftdi->usb_dev, ftdi->interface) < 0)
{
ftdi_usb_close_internal (ftdi);
if (detach_errno == EPERM)
{
ftdi_error_return(-8, "inappropriate permissions on device!");
}
else
{
ftdi_error_return(-5, "unable to claim usb device. Make sure the default FTDI driver is not in use");
}
}
if (ftdi_usb_reset (ftdi) != 0)
{
ftdi_usb_close_internal (ftdi);
ftdi_error_return(-6, "ftdi_usb_reset failed");
}
// Try to guess chip type
// Bug in the BM type chips: bcdDevice is 0x200 for serial == 0
if (desc.bcdDevice == 0x400 || (desc.bcdDevice == 0x200
&& desc.iSerialNumber == 0))
ftdi->type = TYPE_BM;
else if (desc.bcdDevice == 0x200)
ftdi->type = TYPE_AM;
else if (desc.bcdDevice == 0x500)
ftdi->type = TYPE_2232C;
else if (desc.bcdDevice == 0x600)
ftdi->type = TYPE_R;
else if (desc.bcdDevice == 0x700)
ftdi->type = TYPE_2232H;
else if (desc.bcdDevice == 0x800)
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);
if (ftdi_set_baudrate (ftdi, 9600) != 0)
{
ftdi_usb_close_internal (ftdi);
ftdi_error_return(-7, "set baudrate failed");
}
ftdi_error_return(0, "all fine");
}
int ftdi_usb_open(struct ftdi_context *ftdi, int vendor, int product)
{
return ftdi_usb_open_desc(ftdi, vendor, product, NULL, NULL);
}
int ftdi_usb_open_desc(struct ftdi_context *ftdi, int vendor, int product,
const char* description, const char* serial)
{
return ftdi_usb_open_desc_index(ftdi,vendor,product,description,serial,0);
}
int ftdi_usb_open_desc_index(struct ftdi_context *ftdi, int vendor, int product,
const char* description, const char* serial, unsigned int index)
{
libusb_device *dev;
libusb_device **devs;
char string[256];
int i = 0;
if (ftdi == NULL)
ftdi_error_return(-11, "ftdi context invalid");
if (libusb_get_device_list(ftdi->usb_ctx, &devs) < 0)
ftdi_error_return(-12, "libusb_get_device_list() failed");
while ((dev = devs[i++]) != NULL)
{
struct libusb_device_descriptor desc;
int res;
if (libusb_get_device_descriptor(dev, &desc) < 0)
ftdi_error_return_free_device_list(-13, "libusb_get_device_descriptor() failed", devs);
if (desc.idVendor == vendor && desc.idProduct == product)
{
if (libusb_open(dev, &ftdi->usb_dev) < 0)
ftdi_error_return_free_device_list(-4, "usb_open() failed", devs);
if (description != NULL)
{
if (libusb_get_string_descriptor_ascii(ftdi->usb_dev, desc.iProduct, (unsigned char *)string, sizeof(string)) < 0)
{
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)
{
ftdi_usb_close_internal (ftdi);
continue;
}
}
if (serial != NULL)
{
if (libusb_get_string_descriptor_ascii(ftdi->usb_dev, desc.iSerialNumber, (unsigned char *)string, sizeof(string)) < 0)
{
ftdi_usb_close_internal (ftdi);
ftdi_error_return_free_device_list(-9, "unable to fetch serial number", devs);
}
if (strncmp(string, serial, sizeof(string)) != 0)
{
ftdi_usb_close_internal (ftdi);
continue;
}
}
ftdi_usb_close_internal (ftdi);
if (index > 0)
{
index--;
continue;
}
res = ftdi_usb_open_dev(ftdi, dev);
libusb_free_device_list(devs,1);
return res;
}
}
// device not found
ftdi_error_return_free_device_list(-3, "device not found", devs);
}
int ftdi_usb_open_bus_addr(struct ftdi_context *ftdi, uint8_t bus, uint8_t addr)
{
libusb_device *dev;
libusb_device **devs;
int i = 0;
if (ftdi == NULL)
ftdi_error_return(-11, "ftdi context invalid");
if (libusb_get_device_list(ftdi->usb_ctx, &devs) < 0)
ftdi_error_return(-12, "libusb_get_device_list() failed");
while ((dev = devs[i++]) != NULL)
{
if (libusb_get_bus_number(dev) == bus && libusb_get_device_address(dev) == addr)
{
int res;
res = ftdi_usb_open_dev(ftdi, dev);
libusb_free_device_list(devs,1);
return res;
}
}
// device not found
ftdi_error_return_free_device_list(-3, "device not found", devs);
}
int ftdi_usb_open_string(struct ftdi_context *ftdi, const char* description)
{
if (ftdi == NULL)
ftdi_error_return(-12, "ftdi context invalid");
if (description[0] == 0 || description[1] != ':')
ftdi_error_return(-11, "illegal description format");
if (description[0] == 'd')
{
libusb_device *dev;
libusb_device **devs;
unsigned int bus_number, device_address;
int i = 0;
if (libusb_get_device_list(ftdi->usb_ctx, &devs) < 0)
ftdi_error_return(-2, "libusb_get_device_list() failed");
/* XXX: This doesn't handle symlinks/odd paths/etc... */
if (sscanf (description + 2, "%u/%u", &bus_number, &device_address) != 2)
ftdi_error_return_free_device_list(-11, "illegal description format", devs);
while ((dev = devs[i++]) != NULL)
{
int ret;
if (bus_number == libusb_get_bus_number (dev)
&& device_address == libusb_get_device_address (dev))
{
ret = ftdi_usb_open_dev(ftdi, dev);
libusb_free_device_list(devs,1);
return ret;
}
}
// device not found
ftdi_error_return_free_device_list(-3, "device not found", devs);
}
else if (description[0] == 'i' || description[0] == 's')
{
unsigned int vendor;
unsigned int product;
unsigned int index=0;
const char *serial=NULL;
const char *startp, *endp;
errno=0;
startp=description+2;
vendor=strtoul((char*)startp,(char**)&endp,0);
if (*endp != ':' || endp == startp || errno != 0)
ftdi_error_return(-11, "illegal description format");
startp=endp+1;
product=strtoul((char*)startp,(char**)&endp,0);
if (endp == startp || errno != 0)
ftdi_error_return(-11, "illegal description format");
if (description[0] == 'i' && *endp != 0)
{
/* optional index field in i-mode */
if (*endp != ':')
ftdi_error_return(-11, "illegal description format");
startp=endp+1;
index=strtoul((char*)startp,(char**)&endp,0);
if (*endp != 0 || endp == startp || errno != 0)
ftdi_error_return(-11, "illegal description format");
}
if (description[0] == 's')
{
if (*endp != ':')
ftdi_error_return(-11, "illegal description format");
/* rest of the description is the serial */
serial=endp+1;
}
return ftdi_usb_open_desc_index(ftdi, vendor, product, NULL, serial, index);
}
else
{
ftdi_error_return(-11, "illegal description format");
}
}
int ftdi_usb_reset(struct ftdi_context *ftdi)
{
if (ftdi == NULL || ftdi->usb_dev == NULL)
ftdi_error_return(-2, "USB device unavailable");
if (libusb_control_transfer(ftdi->usb_dev, FTDI_DEVICE_OUT_REQTYPE,
SIO_RESET_REQUEST, SIO_RESET_SIO,
ftdi->index, NULL, 0, ftdi->usb_write_timeout) < 0)
ftdi_error_return(-1,"FTDI reset failed");
// Invalidate data in the readbuffer
ftdi->readbuffer_offset = 0;
ftdi->readbuffer_remaining = 0;
return 0;
}
int ftdi_tciflush(struct ftdi_context *ftdi)
{
if (ftdi == NULL || ftdi->usb_dev == NULL)
ftdi_error_return(-2, "USB device unavailable");
if (libusb_control_transfer(ftdi->usb_dev, FTDI_DEVICE_OUT_REQTYPE,
SIO_RESET_REQUEST, SIO_TCIFLUSH,
ftdi->index, NULL, 0, ftdi->usb_write_timeout) < 0)
ftdi_error_return(-1, "FTDI purge of RX buffer failed");
// Invalidate data in the readbuffer
ftdi->readbuffer_offset = 0;
ftdi->readbuffer_remaining = 0;
return 0;
}
int ftdi_usb_purge_rx_buffer(struct ftdi_context *ftdi)
{
if (ftdi == NULL || ftdi->usb_dev == NULL)
ftdi_error_return(-2, "USB device unavailable");
if (libusb_control_transfer(ftdi->usb_dev, FTDI_DEVICE_OUT_REQTYPE,
SIO_RESET_REQUEST, SIO_RESET_PURGE_RX,
ftdi->index, NULL, 0, ftdi->usb_write_timeout) < 0)
ftdi_error_return(-1, "FTDI purge of RX buffer failed");
// Invalidate data in the readbuffer
ftdi->readbuffer_offset = 0;
ftdi->readbuffer_remaining = 0;
return 0;
}
int ftdi_tcoflush(struct ftdi_context *ftdi)
{
if (ftdi == NULL || ftdi->usb_dev == NULL)
ftdi_error_return(-2, "USB device unavailable");
if (libusb_control_transfer(ftdi->usb_dev, FTDI_DEVICE_OUT_REQTYPE,
SIO_RESET_REQUEST, SIO_TCOFLUSH,
ftdi->index, NULL, 0, ftdi->usb_write_timeout) < 0)
ftdi_error_return(-1, "FTDI purge of TX buffer failed");
return 0;
}
int ftdi_usb_purge_tx_buffer(struct ftdi_context *ftdi)
{
if (ftdi == NULL || ftdi->usb_dev == NULL)
ftdi_error_return(-2, "USB device unavailable");
if (libusb_control_transfer(ftdi->usb_dev, FTDI_DEVICE_OUT_REQTYPE,
SIO_RESET_REQUEST, SIO_RESET_PURGE_TX,
ftdi->index, NULL, 0, ftdi->usb_write_timeout) < 0)
ftdi_error_return(-1, "FTDI purge of TX buffer failed");
return 0;
}
int ftdi_tcioflush(struct ftdi_context *ftdi)
{
int result;
if (ftdi == NULL || ftdi->usb_dev == NULL)
ftdi_error_return(-3, "USB device unavailable");
result = ftdi_tcoflush(ftdi);
if (result < 0)
return -1;
result = ftdi_tciflush(ftdi);
if (result < 0)
return -2;
return 0;
}
int ftdi_usb_purge_buffers(struct ftdi_context *ftdi)
{
int result;
if (ftdi == NULL || ftdi->usb_dev == NULL)
ftdi_error_return(-3, "USB device unavailable");
result = ftdi_usb_purge_rx_buffer(ftdi);
if (result < 0)
return -1;
result = ftdi_usb_purge_tx_buffer(ftdi);
if (result < 0)
return -2;
return 0;
}
int ftdi_usb_close(struct ftdi_context *ftdi)
{
int rtn = 0;
if (ftdi == NULL)
ftdi_error_return(-3, "ftdi context invalid");
if (ftdi->usb_dev != NULL)
if (libusb_release_interface(ftdi->usb_dev, ftdi->interface) < 0)
rtn = -1;
ftdi_usb_close_internal (ftdi);
return rtn;
}
/* ftdi_to_clkbits_AM For the AM device, convert a requested baudrate
to encoded divisor and the achievable baudrate
Function is only used internally
\internal
See AN120
clk/1 -> 0
clk/1.5 -> 1
clk/2 -> 2
From /2, 0.125/ 0.25 and 0.5 steps may be taken
The fractional part has frac_code encoding
*/
static int ftdi_to_clkbits_AM(int baudrate, unsigned long *encoded_divisor)
{
static const char frac_code[8] = {0, 3, 2, 4, 1, 5, 6, 7};
static const char am_adjust_up[8] = {0, 0, 0, 1, 0, 3, 2, 1};
static const char am_adjust_dn[8] = {0, 0, 0, 1, 0, 1, 2, 3};
int divisor, best_divisor, best_baud, best_baud_diff;
int i;
divisor = 24000000 / baudrate;
// Round down to supported fraction (AM only)
divisor -= am_adjust_dn[divisor & 7];
// Try this divisor and the one above it (because division rounds down)
best_divisor = 0;
best_baud = 0;
best_baud_diff = 0;
for (i = 0; i < 2; i++)
{
int try_divisor = divisor + i;
int baud_estimate;
int baud_diff;
// Round up to supported divisor value
if (try_divisor <= 8)
{
// Round up to minimum supported divisor
try_divisor = 8;
}
else if (divisor < 16)
{
// AM doesn't support divisors 9 through 15 inclusive
try_divisor = 16;
}
else
{
// Round up to supported fraction (AM only)
try_divisor += am_adjust_up[try_divisor & 7];
if (try_divisor > 0x1FFF8)
{
// Round down to maximum supported divisor value (for AM)
try_divisor = 0x1FFF8;
}
}
// Get estimated baud rate (to nearest integer)
baud_estimate = (24000000 + (try_divisor / 2)) / try_divisor;
// Get absolute difference from requested baud rate
if (baud_estimate < baudrate)
{
baud_diff = baudrate - baud_estimate;
}
else
{
baud_diff = baud_estimate - baudrate;
}
if (i == 0 || baud_diff < best_baud_diff)
{
// Closest to requested baud rate so far
best_divisor = try_divisor;
best_baud = baud_estimate;
best_baud_diff = baud_diff;
if (baud_diff == 0)
{
// Spot on! No point trying
break;
}
}
}
// Encode the best divisor value
*encoded_divisor = (best_divisor >> 3) | (frac_code[best_divisor & 7] << 14);
// Deal with special cases for encoded value
if (*encoded_divisor == 1)
{
*encoded_divisor = 0; // 3000000 baud
}
else if (*encoded_divisor == 0x4001)
{
*encoded_divisor = 1; // 2000000 baud (BM only)
}
return best_baud;
}
/* 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
See AN120
clk/1 -> 0
clk/1.5 -> 1
clk/2 -> 2
From /2, 0.125 steps may be taken.
The fractional part has frac_code encoding
value[13:0] of value is the divisor
index[9] mean 12 MHz Base(120 MHz/10) rate versus 3 MHz (48 MHz/16) else
H Type have all features above with
{index[8],value[15:14]} is the encoded subdivisor
FT232R, FT2232 and FT232BM have no option for 12 MHz and with
{index[0],value[15:14]} is the encoded subdivisor
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 const char frac_code[8] = {0, 3, 2, 4, 1, 5, 6, 7};
int best_baud = 0;
int divisor, best_divisor;
if (baudrate >= clk/clk_div)
{
*encoded_divisor = 0;
best_baud = clk/clk_div;
}
else if (baudrate >= clk/(clk_div + clk_div/2))
{
*encoded_divisor = 1;
best_baud = clk/(clk_div + clk_div/2);
}
else if (baudrate >= clk/(2*clk_div))
{
*encoded_divisor = 2;
best_baud = clk/(2*clk_div);
}
else
{
/* We divide by 16 to have 3 fractional bits and one bit for rounding */
divisor = clk*16/clk_div / baudrate;
if (divisor & 1) /* Decide if to round up or down*/
best_divisor = divisor /2 +1;
else
best_divisor = divisor/2;
if(best_divisor > 0x20000)
best_divisor = 0x1ffff;
best_baud = clk*16/clk_div/best_divisor;
if (best_baud & 1) /* Decide if to round up or down*/
best_baud = best_baud /2 +1;
else
best_baud = best_baud /2;
*encoded_divisor = (best_divisor >> 3) | (frac_code[best_divisor & 0x7] << 14);
}
return best_baud;
}
static int ftdi_convert_baudrate(int baudrate, struct ftdi_context *ftdi,
unsigned short *value, unsigned short *index)
{
int best_baud;
unsigned long encoded_divisor;
if (baudrate <= 0)
{
// Return error
return -1;
}
#define H_CLK 120000000
#define C_CLK 48000000
if ((ftdi->type == TYPE_2232H) || (ftdi->type == TYPE_4232H) || (ftdi->type == TYPE_232H))
{
if(baudrate*10 > H_CLK /0x3fff)
{
/* On H Devices, use 12 000 000 Baudrate when possible
We have a 14 bit divisor, a 1 bit divisor switch (10 or 16)
three fractional bits and a 120 MHz clock
Assume AN_120 "Sub-integer divisors between 0 and 2 are not allowed" holds for
DIV/10 CLK too, so /1, /1.5 and /2 can be handled the same*/
best_baud = ftdi_to_clkbits(baudrate, H_CLK, 10, &encoded_divisor);
encoded_divisor |= 0x20000; /* switch on CLK/10*/
}
else
best_baud = ftdi_to_clkbits(baudrate, C_CLK, 16, &encoded_divisor);
}
else if ((ftdi->type == TYPE_BM) || (ftdi->type == TYPE_2232C) || (ftdi->type == TYPE_R) || (ftdi->type == TYPE_230X))
{
best_baud = ftdi_to_clkbits(baudrate, C_CLK, 16, &encoded_divisor);
}
else
{
best_baud = ftdi_to_clkbits_AM(baudrate, &encoded_divisor);
}
// 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)
{
*index = (unsigned short)(encoded_divisor >> 8);
*index &= 0xFF00;
*index |= ftdi->index;
}
else
*index = (unsigned short)(encoded_divisor >> 16);
// Return the nearest baud rate
return best_baud;
}
int convert_baudrate_UT_export(int baudrate, struct ftdi_context *ftdi,
unsigned short *value, unsigned short *index)
{
return ftdi_convert_baudrate(baudrate, ftdi, value, index);
}
int ftdi_set_baudrate(struct ftdi_context *ftdi, int baudrate)
{
unsigned short value, index;
int actual_baudrate;
if (ftdi == NULL || ftdi->usb_dev == NULL)
ftdi_error_return(-3, "USB device unavailable");
if (ftdi->bitbang_enabled)
{
baudrate = baudrate*4;
}
actual_baudrate = ftdi_convert_baudrate(baudrate, ftdi, &value, &index);
if (actual_baudrate <= 0)
ftdi_error_return (-1, "Silly baudrate <= 0.");
// Check within tolerance (about 5%)
if ((actual_baudrate * 2 < baudrate /* Catch overflows */ )
|| ((actual_baudrate < baudrate)
? (actual_baudrate * 21 < baudrate * 20)
: (baudrate * 21 < actual_baudrate * 20)))
ftdi_error_return (-1, "Unsupported baudrate. Note: bitbang baudrates are automatically multiplied by 4");
if (libusb_control_transfer(ftdi->usb_dev, FTDI_DEVICE_OUT_REQTYPE,
SIO_SET_BAUDRATE_REQUEST, value,
index, NULL, 0, ftdi->usb_write_timeout) < 0)
ftdi_error_return (-2, "Setting new baudrate failed");
ftdi->baudrate = baudrate;
return 0;
}
int ftdi_set_line_property(struct ftdi_context *ftdi, enum ftdi_bits_type bits,
enum ftdi_stopbits_type sbit, enum ftdi_parity_type parity)
{
return ftdi_set_line_property2(ftdi, bits, sbit, parity, BREAK_OFF);
}
int ftdi_set_line_property2(struct ftdi_context *ftdi, enum ftdi_bits_type bits,
enum ftdi_stopbits_type sbit, enum ftdi_parity_type parity,
enum ftdi_break_type break_type)
{
unsigned short value = bits;
if (ftdi == NULL || ftdi->usb_dev == NULL)
ftdi_error_return(-2, "USB device unavailable");
switch (parity)
{
case NONE:
value |= (0x00 << 8);
break;
case ODD:
value |= (0x01 << 8);
break;
case EVEN:
value |= (0x02 << 8);
break;
case MARK:
value |= (0x03 << 8);
break;
case SPACE:
value |= (0x04 << 8);
break;
}
switch (sbit)
{
case STOP_BIT_1:
value |= (0x00 << 11);
break;
case STOP_BIT_15:
value |= (0x01 << 11);
break;
case STOP_BIT_2:
value |= (0x02 << 11);
break;
}
switch (break_type)
{
case BREAK_OFF:
value |= (0x00 << 14);
break;
case BREAK_ON:
value |= (0x01 << 14);
break;
}
if (libusb_control_transfer(ftdi->usb_dev, FTDI_DEVICE_OUT_REQTYPE,
SIO_SET_DATA_REQUEST, value,
ftdi->index, NULL, 0, ftdi->usb_write_timeout) < 0)
ftdi_error_return (-1, "Setting new line property failed");
return 0;
}
int ftdi_write_data(struct ftdi_context *ftdi, const unsigned char *buf, int size)
{
int offset = 0;
int actual_length;
if (ftdi == NULL || ftdi->usb_dev == NULL)
ftdi_error_return(-666, "USB device unavailable");
while (offset < size)
{
int write_size = ftdi->writebuffer_chunksize;
if (offset+write_size > size)
write_size = size-offset;
if (libusb_bulk_transfer(ftdi->usb_dev, ftdi->in_ep, (unsigned char *)buf+offset, write_size, &actual_length, ftdi->usb_write_timeout) < 0)
ftdi_error_return(-1, "usb bulk write failed");
offset += actual_length;
}
return offset;
}
static void LIBUSB_CALL ftdi_read_data_cb(struct libusb_transfer *transfer)
{
struct ftdi_transfer_control *tc = (struct ftdi_transfer_control *) transfer->user_data;
struct ftdi_context *ftdi = tc->ftdi;
int packet_size, actual_length, num_of_chunks, chunk_remains, i, ret;
packet_size = ftdi->max_packet_size;
actual_length = transfer->actual_length;
if (actual_length > 2)
{
// skip FTDI status bytes.
// Maybe stored in the future to enable modem use
num_of_chunks = actual_length / packet_size;
chunk_remains = actual_length % packet_size;
//printf("actual_length = %X, num_of_chunks = %X, chunk_remains = %X, readbuffer_offset = %X\n", actual_length, num_of_chunks, chunk_remains, ftdi->readbuffer_offset);
ftdi->readbuffer_offset += 2;
actual_length -= 2;
if (actual_length > packet_size - 2)
{
for (i = 1; i < num_of_chunks; i++)
memmove (ftdi->readbuffer+ftdi->readbuffer_offset+(packet_size - 2)*i,
ftdi->readbuffer+ftdi->readbuffer_offset+packet_size*i,
packet_size - 2);
if (chunk_remains > 2)
{
memmove (ftdi->readbuffer+ftdi->readbuffer_offset+(packet_size - 2)*i,
ftdi->readbuffer+ftdi->readbuffer_offset+packet_size*i,
chunk_remains-2);
actual_length -= 2*num_of_chunks;
}
else
actual_length -= 2*(num_of_chunks-1)+chunk_remains;
}
if (actual_length > 0)
{
// data still fits in buf?
if (tc->offset + actual_length <= tc->size)
{
memcpy (tc->buf + tc->offset, ftdi->readbuffer + ftdi->readbuffer_offset, actual_length);
//printf("buf[0] = %X, buf[1] = %X\n", buf[0], buf[1]);
tc->offset += actual_length;
ftdi->readbuffer_offset = 0;
ftdi->readbuffer_remaining = 0;
/* Did we read exactly the right amount of bytes? */
if (tc->offset == tc->size)
{
//printf("read_data exact rem %d offset %d\n",
//ftdi->readbuffer_remaining, offset);
tc->completed = 1;
return;
}
}
else
{
// only copy part of the data or size <= readbuffer_chunksize
int part_size = tc->size - tc->offset;
memcpy (tc->buf + tc->offset, ftdi->readbuffer + ftdi->readbuffer_offset, part_size);
tc->offset += part_size;
ftdi->readbuffer_offset += part_size;
ftdi->readbuffer_remaining = actual_length - part_size;
/* printf("Returning part: %d - size: %d - offset: %d - actual_length: %d - remaining: %d\n",
part_size, size, offset, actual_length, ftdi->readbuffer_remaining); */
tc->completed = 1;
return;
}
}
}
if (transfer->status == LIBUSB_TRANSFER_CANCELLED)
tc->completed = LIBUSB_TRANSFER_CANCELLED;
else
{
ret = libusb_submit_transfer (transfer);
if (ret < 0)
tc->completed = 1;
}
}
static void LIBUSB_CALL ftdi_write_data_cb(struct libusb_transfer *transfer)
{
struct ftdi_transfer_control *tc = (struct ftdi_transfer_control *) transfer->user_data;
struct ftdi_context *ftdi = tc->ftdi;
tc->offset += transfer->actual_length;
if (tc->offset == tc->size)
{
tc->completed = 1;
}
else
{
int write_size = ftdi->writebuffer_chunksize;
int ret;
if (tc->offset + write_size > tc->size)
write_size = tc->size - tc->offset;
transfer->length = write_size;
transfer->buffer = tc->buf + tc->offset;
if (transfer->status == LIBUSB_TRANSFER_CANCELLED)
tc->completed = LIBUSB_TRANSFER_CANCELLED;
else
{
ret = libusb_submit_transfer (transfer);
if (ret < 0)
tc->completed = 1;
}
}
}
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;
int write_size, ret;
if (ftdi == NULL || ftdi->usb_dev == NULL)
return NULL;
tc = (struct ftdi_transfer_control *) malloc (sizeof (*tc));
if (!tc)
return NULL;
transfer = libusb_alloc_transfer(0);
if (!transfer)
{
free(tc);
return NULL;
}
tc->ftdi = ftdi;
tc->completed = 0;
tc->buf = buf;
tc->size = size;
tc->offset = 0;
if (size < (int)ftdi->writebuffer_chunksize)
write_size = size;
else
write_size = ftdi->writebuffer_chunksize;
libusb_fill_bulk_transfer(transfer, ftdi->usb_dev, ftdi->in_ep, buf,
write_size, ftdi_write_data_cb, tc,
ftdi->usb_write_timeout);
transfer->type = LIBUSB_TRANSFER_TYPE_BULK;
ret = libusb_submit_transfer(transfer);
if (ret < 0)
{
libusb_free_transfer(transfer);
free(tc);
return NULL;
}
tc->transfer = transfer;
return tc;
}
struct ftdi_transfer_control *ftdi_read_data_submit(struct ftdi_context *ftdi, unsigned char *buf, int size)
{
struct ftdi_transfer_control *tc;
struct libusb_transfer *transfer;
int ret;
if (ftdi == NULL || ftdi->usb_dev == NULL)
return NULL;
tc = (struct ftdi_transfer_control *) malloc (sizeof (*tc));
if (!tc)
return NULL;
tc->ftdi = ftdi;
tc->buf = buf;
tc->size = size;
if (size <= (int)ftdi->readbuffer_remaining)
{
memcpy (buf, ftdi->readbuffer+ftdi->readbuffer_offset, size);
// Fix offsets
ftdi->readbuffer_remaining -= size;
ftdi->readbuffer_offset += size;
/* printf("Returning bytes from buffer: %d - remaining: %d\n", size, ftdi->readbuffer_remaining); */
tc->completed = 1;
tc->offset = size;
tc->transfer = NULL;
return tc;
}
tc->completed = 0;
if (ftdi->readbuffer_remaining != 0)
{
memcpy (buf, ftdi->readbuffer+ftdi->readbuffer_offset, ftdi->readbuffer_remaining);
tc->offset = ftdi->readbuffer_remaining;
}
else
tc->offset = 0;
transfer = libusb_alloc_transfer(0);
if (!transfer)
{
free (tc);
return NULL;
}
ftdi->readbuffer_remaining = 0;
ftdi->readbuffer_offset = 0;
libusb_fill_bulk_transfer(transfer, ftdi->usb_dev, ftdi->out_ep, ftdi->readbuffer, ftdi->readbuffer_chunksize, ftdi_read_data_cb, tc, ftdi->usb_read_timeout);
transfer->type = LIBUSB_TRANSFER_TYPE_BULK;
ret = libusb_submit_transfer(transfer);
if (ret < 0)
{
libusb_free_transfer(transfer);
free (tc);
return NULL;
}
tc->transfer = transfer;
return tc;
}
int ftdi_transfer_data_done(struct ftdi_transfer_control *tc)
{
int ret;
struct timeval to = { 0, 0 };
while (!tc->completed)
{
ret = libusb_handle_events_timeout_completed(tc->ftdi->usb_ctx,
&to, &tc->completed);
if (ret < 0)
{
if (ret == LIBUSB_ERROR_INTERRUPTED)
continue;
libusb_cancel_transfer(tc->transfer);
while (!tc->completed)
if (libusb_handle_events_timeout_completed(tc->ftdi->usb_ctx,
&to, &tc->completed) < 0)
break;
libusb_free_transfer(tc->transfer);
free (tc);
return ret;
}
}
ret = tc->offset;
if (tc->transfer)
{
if (tc->transfer->status != LIBUSB_TRANSFER_COMPLETED)
ret = -1;
libusb_free_transfer(tc->transfer);
}
free(tc);
return ret;
}
void ftdi_transfer_data_cancel(struct ftdi_transfer_control *tc,
struct timeval * to)
{
struct timeval tv = { 0, 0 };
if (!tc->completed && tc->transfer != NULL)
{
if (to == NULL)
to = &tv;
libusb_cancel_transfer(tc->transfer);
while (!tc->completed)
{
if (libusb_handle_events_timeout_completed(tc->ftdi->usb_ctx, to, &tc->completed) < 0)
break;
}
}
if (tc->transfer)
libusb_free_transfer(tc->transfer);
free (tc);
}
int ftdi_write_data_set_chunksize(struct ftdi_context *ftdi, unsigned int chunksize)
{
if (ftdi == NULL)
ftdi_error_return(-1, "ftdi context invalid");
ftdi->writebuffer_chunksize = chunksize;
return 0;
}
int ftdi_write_data_get_chunksize(struct ftdi_context *ftdi, unsigned int *chunksize)
{
if (ftdi == NULL)
ftdi_error_return(-1, "ftdi context invalid");
*chunksize = ftdi->writebuffer_chunksize;
return 0;
}
int ftdi_read_data(struct ftdi_context *ftdi, unsigned char *buf, int size)
{
int offset = 0, ret, i, num_of_chunks, chunk_remains;
int packet_size;
int actual_length = 1;
if (ftdi == NULL || ftdi->usb_dev == NULL)
ftdi_error_return(-666, "USB device unavailable");
// Packet size sanity check (avoid division by zero)
packet_size = ftdi->max_packet_size;
if (packet_size == 0)
ftdi_error_return(-1, "max_packet_size is bogus (zero)");
// everything we want is still in the readbuffer?
if (size <= (int)ftdi->readbuffer_remaining)
{
memcpy (buf, ftdi->readbuffer+ftdi->readbuffer_offset, size);
// Fix offsets
ftdi->readbuffer_remaining -= size;
ftdi->readbuffer_offset += size;
/* printf("Returning bytes from buffer: %d - remaining: %d\n", size, ftdi->readbuffer_remaining); */
return size;
}
// something still in the readbuffer, but not enough to satisfy 'size'?
if (ftdi->readbuffer_remaining != 0)
{
memcpy (buf, ftdi->readbuffer+ftdi->readbuffer_offset, ftdi->readbuffer_remaining);
// Fix offset
offset += ftdi->readbuffer_remaining;
}
// do the actual USB read
while (offset < size && actual_length > 0)
{
ftdi->readbuffer_remaining = 0;
ftdi->readbuffer_offset = 0;
/* returns how much received */
ret = libusb_bulk_transfer (ftdi->usb_dev, ftdi->out_ep, ftdi->readbuffer, ftdi->readbuffer_chunksize, &actual_length, ftdi->usb_read_timeout);
if (ret < 0)
ftdi_error_return(ret, "usb bulk read failed");
if (actual_length > 2)
{
// skip FTDI status bytes.
// Maybe stored in the future to enable modem use
num_of_chunks = actual_length / packet_size;
chunk_remains = actual_length % packet_size;
//printf("actual_length = %X, num_of_chunks = %X, chunk_remains = %X, readbuffer_offset = %X\n", actual_length, num_of_chunks, chunk_remains, ftdi->readbuffer_offset);
ftdi->readbuffer_offset += 2;
actual_length -= 2;
if (actual_length > packet_size - 2)
{
for (i = 1; i < num_of_chunks; i++)
memmove (ftdi->readbuffer+ftdi->readbuffer_offset+(packet_size - 2)*i,
ftdi->readbuffer+ftdi->readbuffer_offset+packet_size*i,
packet_size - 2);
if (chunk_remains > 2)
{
memmove (ftdi->readbuffer+ftdi->readbuffer_offset+(packet_size - 2)*i,
ftdi->readbuffer+ftdi->readbuffer_offset+packet_size*i,
chunk_remains-2);
actual_length -= 2*num_of_chunks;
}
else
actual_length -= 2*(num_of_chunks-1)+chunk_remains;
}
}
else if (actual_length <= 2)
{
// no more data to read?
return offset;
}
if (actual_length > 0)
{
// data still fits in buf?
if (offset+actual_length <= size)
{
memcpy (buf+offset, ftdi->readbuffer+ftdi->readbuffer_offset, actual_length);
//printf("buf[0] = %X, buf[1] = %X\n", buf[0], buf[1]);
offset += actual_length;
/* Did we read exactly the right amount of bytes? */
if (offset == size)
//printf("read_data exact rem %d offset %d\n",
//ftdi->readbuffer_remaining, offset);
return offset;
}
else
{
// only copy part of the data or size <= readbuffer_chunksize
int part_size = size-offset;
memcpy (buf+offset, ftdi->readbuffer+ftdi->readbuffer_offset, part_size);
ftdi->readbuffer_offset += part_size;
ftdi->readbuffer_remaining = actual_length-part_size;
offset += part_size;
/* printf("Returning part: %d - size: %d - offset: %d - actual_length: %d - remaining: %d\n",
part_size, size, offset, actual_length, ftdi->readbuffer_remaining); */
return offset;
}
}
}
// never reached
return -127;
}
int ftdi_read_data_set_chunksize(struct ftdi_context *ftdi, unsigned int chunksize)
{
unsigned char *new_buf;
if (ftdi == NULL)
ftdi_error_return(-1, "ftdi context invalid");
// Invalidate all remaining data
ftdi->readbuffer_offset = 0;
ftdi->readbuffer_remaining = 0;
#ifdef __linux__
/* We can't set readbuffer_chunksize larger than MAX_BULK_BUFFER_LENGTH,
which is defined in libusb-1.0. Otherwise, each USB read request will
be divided into multiple URBs. This will cause issues on Linux kernel
older than 2.6.32. */
if (chunksize > 16384)
chunksize = 16384;
#endif
if ((new_buf = (unsigned char *)realloc(ftdi->readbuffer, chunksize)) == NULL)
ftdi_error_return(-1, "out of memory for readbuffer");
ftdi->readbuffer = new_buf;
ftdi->readbuffer_chunksize = chunksize;
return 0;
}
int ftdi_read_data_get_chunksize(struct ftdi_context *ftdi, unsigned int *chunksize)
{
if (ftdi == NULL)
ftdi_error_return(-1, "FTDI context invalid");
*chunksize = ftdi->readbuffer_chunksize;
return 0;
}
int ftdi_set_bitmode(struct ftdi_context *ftdi, unsigned char bitmask, unsigned char mode)
{
unsigned short usb_val;
if (ftdi == NULL || ftdi->usb_dev == NULL)
ftdi_error_return(-2, "USB device unavailable");
usb_val = bitmask; // low byte: bitmask
usb_val |= (mode << 8);
if (libusb_control_transfer(ftdi->usb_dev, FTDI_DEVICE_OUT_REQTYPE, SIO_SET_BITMODE_REQUEST, usb_val, ftdi->index, NULL, 0, ftdi->usb_write_timeout) < 0)
ftdi_error_return(-1, "unable to configure bitbang mode. Perhaps not a BM/2232C type chip?");
ftdi->bitbang_mode = mode;
ftdi->bitbang_enabled = (mode == BITMODE_RESET) ? 0 : 1;
return 0;
}
int ftdi_disable_bitbang(struct ftdi_context *ftdi)
{
if (ftdi == NULL || ftdi->usb_dev == NULL)
ftdi_error_return(-2, "USB device unavailable");
if (libusb_control_transfer(ftdi->usb_dev, FTDI_DEVICE_OUT_REQTYPE, SIO_SET_BITMODE_REQUEST, 0, ftdi->index, NULL, 0, ftdi->usb_write_timeout) < 0)
ftdi_error_return(-1, "unable to leave bitbang mode. Perhaps not a BM type chip?");
ftdi->bitbang_enabled = 0;
return 0;
}
int ftdi_read_pins(struct ftdi_context *ftdi, unsigned char *pins)
{
if (ftdi == NULL || ftdi->usb_dev == NULL)
ftdi_error_return(-2, "USB device unavailable");
if (libusb_control_transfer(ftdi->usb_dev, FTDI_DEVICE_IN_REQTYPE, SIO_READ_PINS_REQUEST, 0, ftdi->index, (unsigned char *)pins, 1, ftdi->usb_read_timeout) != 1)
ftdi_error_return(-1, "read pins failed");
return 0;
}
int ftdi_set_latency_timer(struct ftdi_context *ftdi, unsigned char latency)
{
unsigned short usb_val;
if (latency < 1)
ftdi_error_return(-1, "latency out of range. Only valid for 1-255");
if (ftdi == NULL || ftdi->usb_dev == NULL)
ftdi_error_return(-3, "USB device unavailable");
usb_val = latency;
if (libusb_control_transfer(ftdi->usb_dev, FTDI_DEVICE_OUT_REQTYPE, SIO_SET_LATENCY_TIMER_REQUEST, usb_val, ftdi->index, NULL, 0, ftdi->usb_write_timeout) < 0)
ftdi_error_return(-2, "unable to set latency timer");
return 0;
}
int ftdi_get_latency_timer(struct ftdi_context *ftdi, unsigned char *latency)
{
unsigned short usb_val;
if (ftdi == NULL || ftdi->usb_dev == NULL)
ftdi_error_return(-2, "USB device unavailable");
if (libusb_control_transfer(ftdi->usb_dev, FTDI_DEVICE_IN_REQTYPE, SIO_GET_LATENCY_TIMER_REQUEST, 0, ftdi->index, (unsigned char *)&usb_val, 1, ftdi->usb_read_timeout) != 1)
ftdi_error_return(-1, "reading latency timer failed");
*latency = (unsigned char)usb_val;
return 0;
}
int ftdi_poll_modem_status(struct ftdi_context *ftdi, unsigned short *status)
{
char usb_val[2];
if (ftdi == NULL || ftdi->usb_dev == NULL)
ftdi_error_return(-2, "USB device unavailable");
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] & 0xFF);
return 0;
}
int ftdi_setflowctrl(struct ftdi_context *ftdi, int flowctrl)
{
if (ftdi == NULL || ftdi->usb_dev == NULL)
ftdi_error_return(-2, "USB device unavailable");
if (libusb_control_transfer(ftdi->usb_dev, FTDI_DEVICE_OUT_REQTYPE,
SIO_SET_FLOW_CTRL_REQUEST, 0, (flowctrl | ftdi->index),
NULL, 0, ftdi->usb_write_timeout) < 0)
ftdi_error_return(-1, "set flow control failed");
return 0;
}
int ftdi_setflowctrl_xonxoff(struct ftdi_context *ftdi, unsigned char xon, unsigned char xoff)
{
if (ftdi == NULL || ftdi->usb_dev == NULL)
ftdi_error_return(-2, "USB device unavailable");
uint16_t xonxoff = xon | (xoff << 8);
if (libusb_control_transfer(ftdi->usb_dev, FTDI_DEVICE_OUT_REQTYPE,
SIO_SET_FLOW_CTRL_REQUEST, xonxoff, (SIO_XON_XOFF_HS | ftdi->index),
NULL, 0, ftdi->usb_write_timeout) < 0)
ftdi_error_return(-1, "set flow control failed");
return 0;
}
int ftdi_setdtr(struct ftdi_context *ftdi, int state)
{
unsigned short usb_val;
if (ftdi == NULL || ftdi->usb_dev == NULL)
ftdi_error_return(-2, "USB device unavailable");
if (state)
usb_val = SIO_SET_DTR_HIGH;
else
usb_val = SIO_SET_DTR_LOW;
if (libusb_control_transfer(ftdi->usb_dev, FTDI_DEVICE_OUT_REQTYPE,
SIO_SET_MODEM_CTRL_REQUEST, usb_val, ftdi->index,
NULL, 0, ftdi->usb_write_timeout) < 0)
ftdi_error_return(-1, "set dtr failed");
return 0;
}
int ftdi_setrts(struct ftdi_context *ftdi, int state)
{
unsigned short usb_val;
if (ftdi == NULL || ftdi->usb_dev == NULL)
ftdi_error_return(-2, "USB device unavailable");
if (state)
usb_val = SIO_SET_RTS_HIGH;
else
usb_val = SIO_SET_RTS_LOW;
if (libusb_control_transfer(ftdi->usb_dev, FTDI_DEVICE_OUT_REQTYPE,
SIO_SET_MODEM_CTRL_REQUEST, usb_val, ftdi->index,
NULL, 0, ftdi->usb_write_timeout) < 0)
ftdi_error_return(-1, "set of rts failed");
return 0;
}
int ftdi_setdtr_rts(struct ftdi_context *ftdi, int dtr, int rts)
{
unsigned short usb_val;
if (ftdi == NULL || ftdi->usb_dev == NULL)
ftdi_error_return(-2, "USB device unavailable");
if (dtr)
usb_val = SIO_SET_DTR_HIGH;
else
usb_val = SIO_SET_DTR_LOW;
if (rts)
usb_val |= SIO_SET_RTS_HIGH;
else
usb_val |= SIO_SET_RTS_LOW;
if (libusb_control_transfer(ftdi->usb_dev, FTDI_DEVICE_OUT_REQTYPE,
SIO_SET_MODEM_CTRL_REQUEST, usb_val, ftdi->index,
NULL, 0, ftdi->usb_write_timeout) < 0)
ftdi_error_return(-1, "set of rts/dtr failed");
return 0;
}
int ftdi_set_event_char(struct ftdi_context *ftdi,
unsigned char eventch, unsigned char enable)
{
unsigned short usb_val;
if (ftdi == NULL || ftdi->usb_dev == NULL)
ftdi_error_return(-2, "USB device unavailable");
usb_val = eventch;
if (enable)
usb_val |= 1 << 8;
if (libusb_control_transfer(ftdi->usb_dev, FTDI_DEVICE_OUT_REQTYPE, SIO_SET_EVENT_CHAR_REQUEST, usb_val, ftdi->index, NULL, 0, ftdi->usb_write_timeout) < 0)
ftdi_error_return(-1, "setting event character failed");
return 0;
}
int ftdi_set_error_char(struct ftdi_context *ftdi,
unsigned char errorch, unsigned char enable)
{
unsigned short usb_val;
if (ftdi == NULL || ftdi->usb_dev == NULL)
ftdi_error_return(-2, "USB device unavailable");
usb_val = errorch;
if (enable)
usb_val |= 1 << 8;
if (libusb_control_transfer(ftdi->usb_dev, FTDI_DEVICE_OUT_REQTYPE, SIO_SET_ERROR_CHAR_REQUEST, usb_val, ftdi->index, NULL, 0, ftdi->usb_write_timeout) < 0)
ftdi_error_return(-1, "setting error character failed");
return 0;
}
int ftdi_eeprom_initdefaults(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;
memset(eeprom, 0, sizeof(struct ftdi_eeprom));
if (ftdi->usb_dev == NULL)
ftdi_error_return(-3, "No connected device or device not yet opened");
eeprom->vendor_id = 0x0403;
eeprom->use_serial = 1;
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 if (ftdi->type == TYPE_230X)
eeprom->product_id = 0x6015;
else
eeprom->product_id = 0x6010;
if (ftdi->type == TYPE_AM)
eeprom->usb_version = 0x0101;
else
eeprom->usb_version = 0x0200;
eeprom->max_power = 100;
if (eeprom->manufacturer)
free (eeprom->manufacturer);
eeprom->manufacturer = NULL;
if (manufacturer)
{
eeprom->manufacturer = (char *)malloc(strlen(manufacturer)+1);
if (eeprom->manufacturer)
strcpy(eeprom->manufacturer, manufacturer);
}
if (eeprom->product)
free (eeprom->product);
eeprom->product = NULL;
if(product)
{
eeprom->product = (char *)malloc(strlen(product)+1);
if (eeprom->product)
strcpy(eeprom->product, product);
}
else
{
const char* default_product;
switch(ftdi->type)
{
case TYPE_AM: default_product = "AM"; break;
case TYPE_BM: default_product = "BM"; break;
case TYPE_2232C: default_product = "Dual RS232"; break;
case TYPE_R: default_product = "FT232R USB UART"; break;
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->product = (char *)malloc(strlen(default_product) +1);
if (eeprom->product)
strcpy(eeprom->product, default_product);
}
if (eeprom->serial)
free (eeprom->serial);
eeprom->serial = NULL;
if (serial)
{
eeprom->serial = (char *)malloc(strlen(serial)+1);
if (eeprom->serial)
strcpy(eeprom->serial, serial);
}
if (ftdi->type == TYPE_R)
{
eeprom->max_power = 90;
eeprom->size = 0x80;
eeprom->cbus_function[0] = CBUS_TXLED;
eeprom->cbus_function[1] = CBUS_RXLED;
eeprom->cbus_function[2] = CBUS_TXDEN;
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] = CBUSX_TXDEN;
eeprom->cbus_function[1] = CBUSX_RXLED;
eeprom->cbus_function[2] = CBUSX_TXLED;
eeprom->cbus_function[3] = CBUSX_SLEEP;
}
else
{
if(ftdi->type == TYPE_232H)
{
int i;
for (i=0; i<10; i++)
eeprom->cbus_function[i] = CBUSH_TRISTATE;
}
eeprom->size = -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, const char * manufacturer,
const char * product, const 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 = (char *)malloc(strlen(manufacturer)+1);
if (eeprom->manufacturer)
strcpy(eeprom->manufacturer, manufacturer);
}
if(product)
{
if (eeprom->product)
free (eeprom->product);
eeprom->product = (char *)malloc(strlen(product)+1);
if (eeprom->product)
strcpy(eeprom->product, product);
}
if (serial)
{
if (eeprom->serial)
free (eeprom->serial);
eeprom->serial = (char *)malloc(strlen(serial)+1);
if (eeprom->serial)
{
strcpy(eeprom->serial, serial);
eeprom->use_serial = 1;
}
}
return 0;
}
int ftdi_eeprom_get_strings(struct ftdi_context *ftdi,
char *manufacturer, int mnf_len,
char *product, int prod_len,
char *serial, int serial_len)
{
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 (manufacturer)
{
strncpy(manufacturer, eeprom->manufacturer, mnf_len);
if (mnf_len > 0)
manufacturer[mnf_len - 1] = '\0';
}
if (product)
{
strncpy(product, eeprom->product, prod_len);
if (prod_len > 0)
product[prod_len - 1] = '\0';
}
if (serial)
{
strncpy(serial, eeprom->serial, serial_len);
if (serial_len > 0)
serial[serial_len - 1] = '\0';
}
return 0;
}
/*FTD2XX doesn't check for values not fitting in the ACBUS Signal options*/
void set_ft232h_cbus(struct ftdi_eeprom *eeprom, unsigned char * output)
{
int i;
for(i=0; i<5; i++)
{
int mode_low, mode_high;
if (eeprom->cbus_function[2*i]> CBUSH_CLK7_5)
mode_low = CBUSH_TRISTATE;
else
mode_low = eeprom->cbus_function[2*i];
if (eeprom->cbus_function[2*i+1]> CBUSH_CLK7_5)
mode_high = CBUSH_TRISTATE;
else
mode_high = eeprom->cbus_function[2*i+1];
output[0x18+i] = (mode_high <<4) | mode_low;
}
}
/* Return the bits for the encoded EEPROM Structure of a requested Mode
*
*/
static unsigned char type2bit(unsigned char type, enum ftdi_chip_type chip)
{
switch (chip)
{
case TYPE_2232H:
case TYPE_2232C:
{
switch (type)
{
case CHANNEL_IS_UART: return 0;
case CHANNEL_IS_FIFO: return 0x01;
case CHANNEL_IS_OPTO: return 0x02;
case CHANNEL_IS_CPU : return 0x04;
default: return 0;
}
}
case TYPE_232H:
{
switch (type)
{
case CHANNEL_IS_UART : return 0;
case CHANNEL_IS_FIFO : return 0x01;
case CHANNEL_IS_OPTO : return 0x02;
case CHANNEL_IS_CPU : return 0x04;
case CHANNEL_IS_FT1284 : return 0x08;
default: return 0;
}
}
case TYPE_R:
{
switch (type)
{
case CHANNEL_IS_UART : return 0;
case CHANNEL_IS_FIFO : return 0x01;
default: return 0;
}
}
case TYPE_230X: /* FT230X is only UART */
default: return 0;
}
return 0;
}
int ftdi_eeprom_build(struct ftdi_context *ftdi)
{
unsigned char i, j, eeprom_size_mask;
unsigned short checksum, value;
unsigned char manufacturer_size = 0, product_size = 0, serial_size = 0;
int user_area_size, free_start, free_end;
struct ftdi_eeprom *eeprom;
unsigned char * output;
if (ftdi == NULL)
ftdi_error_return(-2,"No context");
if (ftdi->eeprom == NULL)
ftdi_error_return(-2,"No eeprom structure");
eeprom= ftdi->eeprom;
output = eeprom->buf;
if (eeprom->chip == -1)
ftdi_error_return(-6,"No connected EEPROM or EEPROM type unknown");
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);
if (eeprom->product != NULL)
product_size = strlen(eeprom->product);
if (eeprom->serial != NULL)
serial_size = strlen(eeprom->serial);
// eeprom size check
switch (ftdi->type)
{
case TYPE_AM:
case TYPE_BM:
case TYPE_R:
user_area_size = 96; // base size for strings (total of 48 characters)
break;
case TYPE_2232C:
user_area_size = 90; // two extra config bytes and 4 bytes PnP stuff
break;
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
case TYPE_4232H:
user_area_size = 86;
break;
case TYPE_232H:
user_area_size = 80;
break;
default:
user_area_size = 0;
break;
}
user_area_size -= (manufacturer_size + product_size + serial_size) * 2;
if (user_area_size < 0)
ftdi_error_return(-1,"eeprom size exceeded");
// empty eeprom
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
// Addr 02: Vendor ID
output[0x02] = eeprom->vendor_id;
output[0x03] = eeprom->vendor_id >> 8;
// Addr 04: Product ID
output[0x04] = eeprom->product_id;
output[0x05] = eeprom->product_id >> 8;
// Addr 06: Device release number (0400h for BM features)
output[0x06] = eeprom->release_number;
output[0x07] = eeprom->release_number >> 8;
// Addr 08: Config descriptor
// 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
// Bit 4-0: reserved - 0
j = 0x80;
if (eeprom->self_powered)
j |= 0x40;
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) && (ftdi->type != TYPE_230X))
{
// Addr 0A: Chip configuration
// Bit 7: 0 - reserved
// Bit 6: 0 - reserved
// Bit 5: 0 - reserved
// Bit 4: 1 - Change USB version
// Bit 3: 1 - Use the serial number string
// Bit 2: 1 - Enable suspend pull downs for lower power
// Bit 1: 1 - Out EndPoint is Isochronous
// Bit 0: 1 - In EndPoint is Isochronous
//
j = 0;
if (eeprom->in_is_isochronous)
j = j | 1;
if (eeprom->out_is_isochronous)
j = j | 2;
output[0x0A] = j;
}
// 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_2232H:
case TYPE_4232H:
i += 2;
case TYPE_R:
i += 2;
case TYPE_2232C:
i += 2;
case TYPE_AM:
case TYPE_BM:
i += 0x94;
break;
case TYPE_232H:
case TYPE_230X:
i = 0xa0;
break;
}
/* Wrap around 0x80 for 128 byte EEPROMS (Internale and 93x46) */
eeprom_size_mask = eeprom->size -1;
free_end = i & eeprom_size_mask;
// Addr 0E: Offset of the manufacturer string + 0x80, calculated later
// Addr 0F: Length of manufacturer string
// Output manufacturer
output[0x0E] = i; // calculate offset
output[i & eeprom_size_mask] = manufacturer_size*2 + 2, i++;
output[i & eeprom_size_mask] = 0x03, i++; // type: string
for (j = 0; j < manufacturer_size; j++)
{
output[i & eeprom_size_mask] = eeprom->manufacturer[j], i++;
output[i & eeprom_size_mask] = 0x00, i++;
}
output[0x0F] = manufacturer_size*2 + 2;
// Addr 10: Offset of the product string + 0x80, calculated later
// Addr 11: Length of product string
output[0x10] = i | 0x80; // calculate offset
output[i & eeprom_size_mask] = product_size*2 + 2, i++;
output[i & eeprom_size_mask] = 0x03, i++;
for (j = 0; j < product_size; j++)
{
output[i & eeprom_size_mask] = eeprom->product[j], i++;
output[i & eeprom_size_mask] = 0x00, i++;
}
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++;
}
// Legacy port name and PnP fields for FT2232 and newer chips
if (ftdi->type > TYPE_BM)
{
output[i & eeprom_size_mask] = 0x02; /* as seen when written with FTD2XX */
i++;
output[i & eeprom_size_mask] = 0x03; /* as seen when written with FTD2XX */
i++;
output[i & eeprom_size_mask] = eeprom->is_not_pnp; /* as seen when written with FTD2XX */
i++;
}
output[0x13] = serial_size*2 + 2;
if (ftdi->type > TYPE_AM) /* use_serial not used in AM devices */
{
if (eeprom->use_serial)
output[0x0A] |= USE_SERIAL_NUM;
else
output[0x0A] &= ~USE_SERIAL_NUM;
}
/* Bytes and Bits specific to (some) types
Write linear, as this allows easier fixing*/
switch (ftdi->type)
{
case TYPE_AM:
break;
case TYPE_BM:
output[0x0C] = eeprom->usb_version & 0xff;
output[0x0D] = (eeprom->usb_version>>8) & 0xff;
if (eeprom->use_usb_version)
output[0x0A] |= USE_USB_VERSION_BIT;
else
output[0x0A] &= ~USE_USB_VERSION_BIT;
break;
case TYPE_2232C:
output[0x00] = type2bit(eeprom->channel_a_type, TYPE_2232C);
if (eeprom->channel_a_driver)
output[0x00] |= DRIVER_VCP;
else
output[0x00] &= ~DRIVER_VCP;
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)
output[0x01] |= DRIVER_VCP;
else
output[0x01] &= ~DRIVER_VCP;
if (eeprom->high_current_b)
output[0x01] |= HIGH_CURRENT_DRIVE;
else
output[0x01] &= ~HIGH_CURRENT_DRIVE;
if (eeprom->in_is_isochronous)
output[0x0A] |= 0x1;
else
output[0x0A] &= ~0x1;
if (eeprom->out_is_isochronous)
output[0x0A] |= 0x2;
else
output[0x0A] &= ~0x2;
if (eeprom->suspend_pull_downs)
output[0x0A] |= 0x4;
else
output[0x0A] &= ~0x4;
if (eeprom->use_usb_version)
output[0x0A] |= USE_USB_VERSION_BIT;
else
output[0x0A] &= ~USE_USB_VERSION_BIT;
output[0x0C] = eeprom->usb_version & 0xff;
output[0x0D] = (eeprom->usb_version>>8) & 0xff;
output[0x14] = eeprom->chip;
break;
case TYPE_R:
output[0x00] = type2bit(eeprom->channel_a_type, TYPE_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*/
if (eeprom->suspend_pull_downs)
output[0x0A] |= 0x4;
else
output[0x0A] &= ~0x4;
output[0x0B] = eeprom->invert;
output[0x0C] = eeprom->usb_version & 0xff;
output[0x0D] = (eeprom->usb_version>>8) & 0xff;
if (eeprom->cbus_function[0] > CBUS_BB_RD)
output[0x14] = CBUS_TXLED;
else
output[0x14] = eeprom->cbus_function[0];
if (eeprom->cbus_function[1] > CBUS_BB_RD)
output[0x14] |= CBUS_RXLED<<4;
else
output[0x14] |= eeprom->cbus_function[1]<<4;
if (eeprom->cbus_function[2] > CBUS_BB_RD)
output[0x15] = CBUS_TXDEN;
else
output[0x15] = eeprom->cbus_function[2];
if (eeprom->cbus_function[3] > CBUS_BB_RD)
output[0x15] |= CBUS_PWREN<<4;
else
output[0x15] |= eeprom->cbus_function[3]<<4;
if (eeprom->cbus_function[4] > CBUS_CLK6)
output[0x16] = CBUS_SLEEP;
else
output[0x16] = eeprom->cbus_function[4];
break;
case TYPE_2232H:
output[0x00] = type2bit(eeprom->channel_a_type, TYPE_2232H);
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)
output[0x01] |= DRIVER_VCP;
else
output[0x01] &= ~DRIVER_VCP;
if (eeprom->suspend_dbus7)
output[0x01] |= SUSPEND_DBUS7_BIT;
else
output[0x01] &= ~SUSPEND_DBUS7_BIT;
if (eeprom->suspend_pull_downs)
output[0x0A] |= 0x4;
else
output[0x0A] &= ~0x4;
if (eeprom->group0_drive > DRIVE_16MA)
output[0x0c] |= DRIVE_16MA;
else
output[0x0c] |= eeprom->group0_drive;
if (eeprom->group0_schmitt)
output[0x0c] |= IS_SCHMITT;
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)
output[0x0c] |= IS_SCHMITT<<4;
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)
output[0x0d] |= IS_SCHMITT;
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)
output[0x0d] |= IS_SCHMITT<<4;
if (eeprom->group3_slew)
output[0x0d] |= SLOW_SLEW<<4;
output[0x18] = eeprom->chip;
break;
case TYPE_4232H:
if (eeprom->channel_a_driver)
output[0x00] |= DRIVER_VCP;
else
output[0x00] &= ~DRIVER_VCP;
if (eeprom->channel_b_driver)
output[0x01] |= DRIVER_VCP;
else
output[0x01] &= ~DRIVER_VCP;
if (eeprom->channel_c_driver)
output[0x00] |= (DRIVER_VCP << 4);
else
output[0x00] &= ~(DRIVER_VCP << 4);
if (eeprom->channel_d_driver)
output[0x01] |= (DRIVER_VCP << 4);
else
output[0x01] &= ~(DRIVER_VCP << 4);
if (eeprom->suspend_pull_downs)
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)
output[0x0c] |= IS_SCHMITT;
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)
output[0x0c] |= IS_SCHMITT<<4;
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)
output[0x0d] |= IS_SCHMITT;
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)
output[0x0d] |= IS_SCHMITT<<4;
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)
output[0x00] |= DRIVER_VCPH;
else
output[0x00] &= ~DRIVER_VCPH;
if (eeprom->powersave)
output[0x01] |= POWER_SAVE_DISABLE_H;
else
output[0x01] &= ~POWER_SAVE_DISABLE_H;
if (eeprom->suspend_pull_downs)
output[0x0a] |= 0x4;
else
output[0x0a] &= ~0x4;
if (eeprom->clock_polarity)
output[0x01] |= FT1284_CLK_IDLE_STATE;
else
output[0x01] &= ~FT1284_CLK_IDLE_STATE;
if (eeprom->data_order)
output[0x01] |= FT1284_DATA_LSB;
else
output[0x01] &= ~FT1284_DATA_LSB;
if (eeprom->flow_control)
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)
output[0x0c] |= IS_SCHMITT;
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)
output[0x0d] |= IS_SCHMITT;
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");
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 */
for (j = 0; j <= 6; j++)
{
output[0x1a + j] = eeprom->cbus_function[j];
}
output[0x0b] = eeprom->invert;
break;
}
/* First address without use */
free_start = 0;
switch (ftdi->type)
{
case TYPE_230X:
free_start += 2;
case TYPE_232H:
free_start += 6;
case TYPE_2232H:
case TYPE_4232H:
free_start += 2;
case TYPE_R:
free_start += 2;
case TYPE_2232C:
free_start++;
case TYPE_AM:
case TYPE_BM:
free_start += 0x14;
}
/* Arbitrary user data */
if (eeprom->user_data && eeprom->user_data_size >= 0)
{
if (eeprom->user_data_addr < free_start)
fprintf(stderr,"Warning, user data starts inside the generated data!\n");
if (eeprom->user_data_addr + eeprom->user_data_size >= free_end)
fprintf(stderr,"Warning, user data overlaps the strings area!\n");
if (eeprom->user_data_addr + eeprom->user_data_size > eeprom->size)
ftdi_error_return(-1,"eeprom size exceeded");
memcpy(output + eeprom->user_data_addr, eeprom->user_data, eeprom->user_data_size);
}
// calculate checksum
checksum = 0xAAAA;
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;
}
if ((ftdi->type == TYPE_230X) && (i >= 0x40) && (i < 0x50)) {
uint16_t data;
if (ftdi_read_eeprom_location(ftdi, i, &data)) {
fprintf(stderr, "Reading Factory Configuration Data failed\n");
i = 0x50;
}
value = data;
}
else {
value = output[i*2];
value += output[(i*2)+1] << 8;
}
checksum = value^checksum;
checksum = (checksum << 1) | (checksum >> 15);
}
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
* EEPROM structure
*
* FTD2XX doesn't allow to set multiple bits in the interface mode bitfield, and so do we
*/
static unsigned char bit2type(unsigned char bits)
{
switch (bits)
{
case 0: return CHANNEL_IS_UART;
case 1: return CHANNEL_IS_FIFO;
case 2: return CHANNEL_IS_OPTO;
case 4: return CHANNEL_IS_CPU;
case 8: return CHANNEL_IS_FT1284;
default:
fprintf(stderr," Unexpected value %d for Hardware Interface type\n",
bits);
}
return 0;
}
/* Decode 230X / 232R type chips invert bits
* Prints directly to stdout.
*/
static void print_inverted_bits(int invert)
{
const char *r_bits[] = {"TXD","RXD","RTS","CTS","DTR","DSR","DCD","RI"};
int i;
fprintf(stdout,"Inverted bits:");
for (i=0; i<8; i++)
if ((invert & (1<<i)) == (1<<i))
fprintf(stdout," %s",r_bits[i]);
fprintf(stdout,"\n");
}
int ftdi_eeprom_decode(struct ftdi_context *ftdi, int verbose)
{
int i, j;
unsigned short checksum, eeprom_checksum, value;
unsigned char manufacturer_size = 0, product_size = 0, serial_size = 0;
int eeprom_size;
struct ftdi_eeprom *eeprom;
unsigned char *buf = NULL;
if (ftdi == NULL)
ftdi_error_return(-1,"No context");
if (ftdi->eeprom == NULL)
ftdi_error_return(-1,"No eeprom structure");
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);
// Addr 06: Device release number
eeprom->release_number = buf[0x06] + (buf[0x07]<<8);
// Addr 08: Config descriptor
// 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);
// Addr 09: Max power consumption: max power = value * 2 mA
eeprom->max_power = MAX_POWER_MILLIAMP_PER_UNIT * buf[0x09];
// Addr 0A: Chip configuration
// Bit 7: 0 - reserved
// Bit 6: 0 - reserved
// Bit 5: 0 - reserved
// Bit 4: 1 - Change USB version on BM and 2232C
// Bit 3: 1 - Use the serial number string
// Bit 2: 1 - Enable suspend pull downs for lower power
// 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->use_serial = !!(buf[0x0A] & USE_SERIAL_NUM);
eeprom->use_usb_version = !!(buf[0x0A] & USE_USB_VERSION_BIT);
// Addr 0C: USB version low byte when 0x0A
// Addr 0D: USB version high byte when 0x0A
eeprom->usb_version = buf[0x0C] + (buf[0x0D] << 8);
// Addr 0E: Offset of the manufacturer string + 0x80, calculated later
// Addr 0F: Length of manufacturer string
manufacturer_size = buf[0x0F]/2;
if (eeprom->manufacturer)
free(eeprom->manufacturer);
if (manufacturer_size > 0)
{
eeprom->manufacturer = (char *)malloc(manufacturer_size);
if (eeprom->manufacturer)
{
// Decode manufacturer
i = buf[0x0E] & (eeprom_size -1); // offset
for (j=0; j<manufacturer_size-1; j++)
{
eeprom->manufacturer[j] = buf[2*j+i+2];
}
eeprom->manufacturer[j] = '\0';
}
}
else eeprom->manufacturer = NULL;
// Addr 10: Offset of the product string + 0x80, calculated later
// Addr 11: Length of product string
if (eeprom->product)
free(eeprom->product);
product_size = buf[0x11]/2;
if (product_size > 0)
{
eeprom->product = (char *)malloc(product_size);
if (eeprom->product)
{
// Decode product name
i = buf[0x10] & (eeprom_size -1); // offset
for (j=0; j<product_size-1; j++)
{
eeprom->product[j] = buf[2*j+i+2];
}
eeprom->product[j] = '\0';
}
}
else eeprom->product = NULL;
// Addr 12: Offset of the serial string + 0x80, calculated later
// Addr 13: Length of serial string
if (eeprom->serial)
free(eeprom->serial);
serial_size = buf[0x13]/2;
if (serial_size > 0)
{
eeprom->serial = (char *)malloc(serial_size);
if (eeprom->serial)
{
// Decode serial
i = buf[0x12] & (eeprom_size -1); // offset
for (j=0; j<serial_size-1; j++)
{
eeprom->serial[j] = buf[2*j+i+2];
}
eeprom->serial[j] = '\0';
}
}
else eeprom->serial = NULL;
// verify checksum
checksum = 0xAAAA;
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;
checksum = value^checksum;
checksum = (checksum << 1) | (checksum >> 15);
}
eeprom_checksum = buf[eeprom_size-2] + (buf[eeprom_size-1] << 8);
if (eeprom_checksum != checksum)
{
fprintf(stderr, "Checksum Error: %04x %04x\n", checksum, eeprom_checksum);
ftdi_error_return(-1,"EEPROM checksum error");
}
eeprom->channel_a_type = 0;
if ((ftdi->type == TYPE_AM) || (ftdi->type == TYPE_BM))
{
eeprom->chip = -1;
}
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_b_type = buf[0x01] & 0x7;
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); /* 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."
" If this happened with the\n"
" EEPROM programmed by FTDI tools, please report "
"to libftdi@developer.intra2net.com\n");
eeprom->chip = buf[0x16];
// Addr 0B: Invert data lines
// Works only on FT232R, not FT245R, but no way to distinguish
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
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 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);
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; /* 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);
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[2*i ] = buf[0x18+i] & 0x0f;
eeprom->cbus_function[2*i+1] = (buf[0x18+i] >> 4) & 0x0f;
}
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] & 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)
{
const 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",eeprom->release_number);
if (eeprom->self_powered)
fprintf(stdout, "Self-Powered%s", (eeprom->remote_wakeup)?", USB Remote Wake Up\n":"\n");
else
fprintf(stdout, "Bus Powered: %3d mA%s", eeprom->max_power,
(eeprom->remote_wakeup)?" USB Remote Wake Up\n":"\n");
if (eeprom->manufacturer)
fprintf(stdout, "Manufacturer: %s\n",eeprom->manufacturer);
if (eeprom->product)
fprintf(stdout, "Product: %s\n",eeprom->product);
if (eeprom->serial)
fprintf(stdout, "Serial: %s\n",eeprom->serial);
fprintf(stdout, "Checksum : %04x\n", checksum);
if (ftdi->type == TYPE_R) {
fprintf(stdout, "Internal EEPROM\n");
fprintf(stdout,"Oscillator: %s\n", eeprom->external_oscillator?"External":"Internal");
}
else if (eeprom->chip >= 0x46)
fprintf(stdout, "Attached EEPROM: 93x%02x\n", eeprom->chip);
if (eeprom->suspend_dbus7)
fprintf(stdout, "Suspend on DBUS7\n");
if (eeprom->suspend_pull_downs)
fprintf(stdout, "Pull IO pins low during suspend\n");
if(eeprom->powersave)
{
if(ftdi->type >= TYPE_232H)
fprintf(stdout,"Enter low power state on ACBUS7\n");
}
if (eeprom->remote_wakeup)
fprintf(stdout, "Enable Remote Wake Up\n");
fprintf(stdout, "PNP: %d\n",(eeprom->is_not_pnp)?0:1);
if (ftdi->type >= TYPE_2232C)
fprintf(stdout,"Channel A has Mode %s%s%s\n",
channel_mode[eeprom->channel_a_type],
(eeprom->channel_a_driver)?" VCP":"",
(eeprom->high_current_a)?" High Current IO":"");
if (ftdi->type == TYPE_232H)
{
fprintf(stdout,"FT1284 Mode Clock is idle %s, %s first, %sFlow Control\n",
(eeprom->clock_polarity)?"HIGH":"LOW",
(eeprom->data_order)?"LSB":"MSB",
(eeprom->flow_control)?"":"No ");
}
if ((ftdi->type == TYPE_2232H) || (ftdi->type == TYPE_4232H))
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_BM) || (ftdi->type == TYPE_2232C)) &&
eeprom->use_usb_version)
fprintf(stdout,"Use explicit USB Version %04x\n",eeprom->usb_version);
if ((ftdi->type == TYPE_2232H) || (ftdi->type == TYPE_4232H))
{
fprintf(stdout,"%s has %d mA drive%s%s\n",
(ftdi->type == TYPE_2232H)?"AL":"A",
(eeprom->group0_drive+1) *4,
(eeprom->group0_schmitt)?" Schmitt Input":"",
(eeprom->group0_slew)?" Slow Slew":"");
fprintf(stdout,"%s has %d mA drive%s%s\n",
(ftdi->type == TYPE_2232H)?"AH":"B",
(eeprom->group1_drive+1) *4,
(eeprom->group1_schmitt)?" Schmitt Input":"",
(eeprom->group1_slew)?" Slow Slew":"");
fprintf(stdout,"%s has %d mA drive%s%s\n",
(ftdi->type == TYPE_2232H)?"BL":"C",
(eeprom->group2_drive+1) *4,
(eeprom->group2_schmitt)?" Schmitt Input":"",
(eeprom->group2_slew)?" Slow Slew":"");
fprintf(stdout,"%s has %d mA drive%s%s\n",
(ftdi->type == TYPE_2232H)?"BH":"D",
(eeprom->group3_drive+1) *4,
(eeprom->group3_schmitt)?" Schmitt Input":"",
(eeprom->group3_slew)?" Slow Slew":"");
}
else if (ftdi->type == TYPE_232H)
{
const char *cbush_mux[] = {"TRISTATE","TXLED","RXLED", "TXRXLED","PWREN",
"SLEEP","DRIVE_0","DRIVE_1","IOMODE","TXDEN",
"CLK30","CLK15","CLK7_5"
};
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":"");
for (i=0; i<10; i++)
{
if (eeprom->cbus_function[i]<= CBUSH_CLK7_5 )
fprintf(stdout,"C%d Function: %s\n", i,
cbush_mux[eeprom->cbus_function[i]]);
}
}
else if (ftdi->type == TYPE_230X)
{
const char *cbusx_mux[] = {"TRISTATE","TXLED","RXLED", "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,"DBUS 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]<= CBUSX_AWAKE)
fprintf(stdout,"CBUS%d Function: %s\n", i, cbusx_mux[eeprom->cbus_function[i]]);
}
if (eeprom->invert)
print_inverted_bits(eeprom->invert);
}
if (ftdi->type == TYPE_R)
{
const char *cbus_mux[] = {"TXDEN","PWREN","RXLED", "TXLED","TX+RXLED",
"SLEEP","CLK48","CLK24","CLK12","CLK6",
"IOMODE","BB_WR","BB_RD"
};
const char *cbus_BB[] = {"RXF","TXE","RD", "WR"};
if (eeprom->invert)
print_inverted_bits(eeprom->invert);
for (i=0; i<5; i++)
{
if (eeprom->cbus_function[i]<=CBUS_BB_RD)
fprintf(stdout,"C%d Function: %s\n", i,
cbus_mux[eeprom->cbus_function[i]]);
else
{
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");
}
}
}
}
return 0;
}
int ftdi_get_eeprom_value(struct ftdi_context *ftdi, enum ftdi_eeprom_value value_name, int* value)
{
switch (value_name)
{
case VENDOR_ID:
*value = ftdi->eeprom->vendor_id;
break;
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 REMOTE_WAKEUP:
*value = ftdi->eeprom->remote_wakeup;
break;
case IS_NOT_PNP:
*value = ftdi->eeprom->is_not_pnp;
break;
case SUSPEND_DBUS7:
*value = ftdi->eeprom->suspend_dbus7;
break;
case IN_IS_ISOCHRONOUS:
*value = ftdi->eeprom->in_is_isochronous;
break;
case OUT_IS_ISOCHRONOUS:
*value = ftdi->eeprom->out_is_isochronous;
break;
case SUSPEND_PULL_DOWNS:
*value = ftdi->eeprom->suspend_pull_downs;
break;
case USE_SERIAL:
*value = ftdi->eeprom->use_serial;
break;
case USB_VERSION:
*value = ftdi->eeprom->usb_version;
break;
case USE_USB_VERSION:
*value = ftdi->eeprom->use_usb_version;
break;
case MAX_POWER:
*value = ftdi->eeprom->max_power;
break;
case CHANNEL_A_TYPE:
*value = ftdi->eeprom->channel_a_type;
break;
case CHANNEL_B_TYPE:
*value = ftdi->eeprom->channel_b_type;
break;
case CHANNEL_A_DRIVER:
*value = ftdi->eeprom->channel_a_driver;
break;
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;
case CBUS_FUNCTION_1:
*value = ftdi->eeprom->cbus_function[1];
break;
case CBUS_FUNCTION_2:
*value = ftdi->eeprom->cbus_function[2];
break;
case CBUS_FUNCTION_3:
*value = ftdi->eeprom->cbus_function[3];
break;
case CBUS_FUNCTION_4:
*value = ftdi->eeprom->cbus_function[4];
break;
case CBUS_FUNCTION_5:
*value = ftdi->eeprom->cbus_function[5];
break;
case CBUS_FUNCTION_6:
*value = ftdi->eeprom->cbus_function[6];
break;
case CBUS_FUNCTION_7:
*value = ftdi->eeprom->cbus_function[7];
break;
case CBUS_FUNCTION_8:
*value = ftdi->eeprom->cbus_function[8];
break;
case CBUS_FUNCTION_9:
*value = ftdi->eeprom->cbus_function[9];
break;
case HIGH_CURRENT:
*value = ftdi->eeprom->high_current;
break;
case HIGH_CURRENT_A:
*value = ftdi->eeprom->high_current_a;
break;
case HIGH_CURRENT_B:
*value = ftdi->eeprom->high_current_b;
break;
case INVERT:
*value = ftdi->eeprom->invert;
break;
case GROUP0_DRIVE:
*value = ftdi->eeprom->group0_drive;
break;
case GROUP0_SCHMITT:
*value = ftdi->eeprom->group0_schmitt;
break;
case GROUP0_SLEW:
*value = ftdi->eeprom->group0_slew;
break;
case GROUP1_DRIVE:
*value = ftdi->eeprom->group1_drive;
break;
case GROUP1_SCHMITT:
*value = ftdi->eeprom->group1_schmitt;
break;
case GROUP1_SLEW:
*value = ftdi->eeprom->group1_slew;
break;
case GROUP2_DRIVE:
*value = ftdi->eeprom->group2_drive;
break;
case GROUP2_SCHMITT:
*value = ftdi->eeprom->group2_schmitt;
break;
case GROUP2_SLEW:
*value = ftdi->eeprom->group2_slew;
break;
case GROUP3_DRIVE:
*value = ftdi->eeprom->group3_drive;
break;
case GROUP3_SCHMITT:
*value = ftdi->eeprom->group3_schmitt;
break;
case GROUP3_SLEW:
*value = ftdi->eeprom->group3_slew;
break;
case POWER_SAVE:
*value = ftdi->eeprom->powersave;
break;
case CLOCK_POLARITY:
*value = ftdi->eeprom->clock_polarity;
break;
case DATA_ORDER:
*value = ftdi->eeprom->data_order;
break;
case FLOW_CONTROL:
*value = ftdi->eeprom->flow_control;
break;
case CHIP_TYPE:
*value = ftdi->eeprom->chip;
break;
case CHIP_SIZE:
*value = ftdi->eeprom->size;
break;
case EXTERNAL_OSCILLATOR:
*value = ftdi->eeprom->external_oscillator;
break;
default:
ftdi_error_return(-1, "Request for unknown EEPROM value");
}
return 0;
}
int ftdi_set_eeprom_value(struct ftdi_context *ftdi, enum ftdi_eeprom_value value_name, int value)
{
switch (value_name)
{
case VENDOR_ID:
ftdi->eeprom->vendor_id = value;
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;
case REMOTE_WAKEUP:
ftdi->eeprom->remote_wakeup = value;
break;
case IS_NOT_PNP:
ftdi->eeprom->is_not_pnp = value;
break;
case SUSPEND_DBUS7:
ftdi->eeprom->suspend_dbus7 = value;
break;
case IN_IS_ISOCHRONOUS:
ftdi->eeprom->in_is_isochronous = value;
break;
case OUT_IS_ISOCHRONOUS:
ftdi->eeprom->out_is_isochronous = value;
break;
case SUSPEND_PULL_DOWNS:
ftdi->eeprom->suspend_pull_downs = value;
break;
case USE_SERIAL:
ftdi->eeprom->use_serial = value;
break;
case USB_VERSION:
ftdi->eeprom->usb_version = value;
break;
case USE_USB_VERSION:
ftdi->eeprom->use_usb_version = value;
break;
case MAX_POWER:
ftdi->eeprom->max_power = value;
break;
case CHANNEL_A_TYPE:
ftdi->eeprom->channel_a_type = value;
break;
case CHANNEL_B_TYPE:
ftdi->eeprom->channel_b_type = value;
break;
case CHANNEL_A_DRIVER:
ftdi->eeprom->channel_a_driver = value;
break;
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;
case CBUS_FUNCTION_1:
ftdi->eeprom->cbus_function[1] = value;
break;
case CBUS_FUNCTION_2:
ftdi->eeprom->cbus_function[2] = value;
break;
case CBUS_FUNCTION_3:
ftdi->eeprom->cbus_function[3] = value;
break;
case CBUS_FUNCTION_4:
ftdi->eeprom->cbus_function[4] = value;
break;
case CBUS_FUNCTION_5:
ftdi->eeprom->cbus_function[5] = value;
break;
case CBUS_FUNCTION_6:
ftdi->eeprom->cbus_function[6] = value;
break;
case CBUS_FUNCTION_7:
ftdi->eeprom->cbus_function[7] = value;
break;
case CBUS_FUNCTION_8:
ftdi->eeprom->cbus_function[8] = value;
break;
case CBUS_FUNCTION_9:
ftdi->eeprom->cbus_function[9] = value;
break;
case HIGH_CURRENT:
ftdi->eeprom->high_current = value;
break;
case HIGH_CURRENT_A:
ftdi->eeprom->high_current_a = value;
break;
case HIGH_CURRENT_B:
ftdi->eeprom->high_current_b = value;
break;
case INVERT:
ftdi->eeprom->invert = value;
break;
case GROUP0_DRIVE:
ftdi->eeprom->group0_drive = value;
break;
case GROUP0_SCHMITT:
ftdi->eeprom->group0_schmitt = value;
break;
case GROUP0_SLEW:
ftdi->eeprom->group0_slew = value;
break;
case GROUP1_DRIVE:
ftdi->eeprom->group1_drive = value;
break;
case GROUP1_SCHMITT:
ftdi->eeprom->group1_schmitt = value;
break;
case GROUP1_SLEW:
ftdi->eeprom->group1_slew = value;
break;
case GROUP2_DRIVE:
ftdi->eeprom->group2_drive = value;
break;
case GROUP2_SCHMITT:
ftdi->eeprom->group2_schmitt = value;
break;
case GROUP2_SLEW:
ftdi->eeprom->group2_slew = value;
break;
case GROUP3_DRIVE:
ftdi->eeprom->group3_drive = value;
break;
case GROUP3_SCHMITT:
ftdi->eeprom->group3_schmitt = value;
break;
case GROUP3_SLEW:
ftdi->eeprom->group3_slew = value;
break;
case CHIP_TYPE:
ftdi->eeprom->chip = value;
break;
case POWER_SAVE:
ftdi->eeprom->powersave = value;
break;
case CLOCK_POLARITY:
ftdi->eeprom->clock_polarity = value;
break;
case DATA_ORDER:
ftdi->eeprom->data_order = value;
break;
case FLOW_CONTROL:
ftdi->eeprom->flow_control = value;
break;
case CHIP_SIZE:
ftdi_error_return(-2, "EEPROM Value can't be changed");
break;
case EXTERNAL_OSCILLATOR:
ftdi->eeprom->external_oscillator = value;
break;
case USER_DATA_ADDR:
ftdi->eeprom->user_data_addr = value;
break;
default :
ftdi_error_return(-1, "Request to unknown EEPROM value");
}
ftdi->eeprom->initialized_for_connected_device = 0;
return 0;
}
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;
}
int ftdi_set_eeprom_buf(struct ftdi_context *ftdi, const unsigned char * buf, int size)
{
if (!ftdi || !(ftdi->eeprom) || !buf)
ftdi_error_return(-1, "No appropriate structure");
// Only copy up to FTDI_MAX_EEPROM_SIZE bytes
if (size > FTDI_MAX_EEPROM_SIZE)
size = FTDI_MAX_EEPROM_SIZE;
memcpy(ftdi->eeprom->buf, buf, size);
return 0;
}
int ftdi_set_eeprom_user_data(struct ftdi_context *ftdi, const char * buf, int size)
{
if (!ftdi || !(ftdi->eeprom) || !buf)
ftdi_error_return(-1, "No appropriate structure");
ftdi->eeprom->user_data_size = size;
ftdi->eeprom->user_data = buf;
return 0;
}
int ftdi_read_eeprom_location (struct ftdi_context *ftdi, int eeprom_addr, unsigned short *eeprom_val)
{
unsigned char buf[2];
if (ftdi == NULL || ftdi->usb_dev == NULL)
ftdi_error_return(-2, "USB device unavailable");
if (libusb_control_transfer(ftdi->usb_dev, FTDI_DEVICE_IN_REQTYPE, SIO_READ_EEPROM_REQUEST, 0, eeprom_addr, buf, 2, ftdi->usb_read_timeout) != 2)
ftdi_error_return(-1, "reading eeprom failed");
*eeprom_val = (0xff & buf[0]) | (buf[1] << 8);
return 0;
}
int ftdi_read_eeprom(struct ftdi_context *ftdi)
{
int i;
unsigned char *buf;
if (ftdi == NULL || ftdi->usb_dev == NULL)
ftdi_error_return(-2, "USB device unavailable");
buf = ftdi->eeprom->buf;
for (i = 0; i < FTDI_MAX_EEPROM_SIZE/2; i++)
{
if (libusb_control_transfer(
ftdi->usb_dev, FTDI_DEVICE_IN_REQTYPE,SIO_READ_EEPROM_REQUEST, 0, i,
buf+(i*2), 2, ftdi->usb_read_timeout) != 2)
ftdi_error_return(-1, "reading eeprom failed");
}
if (ftdi->type == TYPE_R)
ftdi->eeprom->size = 0x80;
/* Guesses size of eeprom by comparing halves
- will not work with blank eeprom */
else if (strrchr((const char *)buf, 0xff) == ((const char *)buf +FTDI_MAX_EEPROM_SIZE -1))
ftdi->eeprom->size = -1;
else if (memcmp(buf,&buf[0x80],0x80) == 0)
ftdi->eeprom->size = 0x80;
else if (memcmp(buf,&buf[0x40],0x40) == 0)
ftdi->eeprom->size = 0x40;
else
ftdi->eeprom->size = 0x100;
return 0;
}
/*
ftdi_read_chipid_shift does the bitshift operation needed for the FTDIChip-ID
Function is only used internally
\internal
*/
static unsigned char ftdi_read_chipid_shift(unsigned char value)
{
return ((value & 1) << 1) |
((value & 2) << 5) |
((value & 4) >> 2) |
((value & 8) << 4) |
((value & 16) >> 1) |
((value & 32) >> 1) |
((value & 64) >> 4) |
((value & 128) >> 2);
}
int ftdi_read_chipid(struct ftdi_context *ftdi, unsigned int *chipid)
{
unsigned int a = 0, b = 0;
if (ftdi == NULL || ftdi->usb_dev == NULL)
ftdi_error_return(-2, "USB device unavailable");
if (libusb_control_transfer(ftdi->usb_dev, FTDI_DEVICE_IN_REQTYPE, SIO_READ_EEPROM_REQUEST, 0, 0x43, (unsigned char *)&a, 2, ftdi->usb_read_timeout) == 2)
{
a = a << 8 | a >> 8;
if (libusb_control_transfer(ftdi->usb_dev, FTDI_DEVICE_IN_REQTYPE, SIO_READ_EEPROM_REQUEST, 0, 0x44, (unsigned char *)&b, 2, ftdi->usb_read_timeout) == 2)
{
b = b << 8 | b >> 8;
a = (a << 16) | (b & 0xFFFF);
a = ftdi_read_chipid_shift(a) | ftdi_read_chipid_shift(a>>8)<<8
| ftdi_read_chipid_shift(a>>16)<<16 | ftdi_read_chipid_shift(a>>24)<<24;
*chipid = a ^ 0xa5f0f7d1;
return 0;
}
}
ftdi_error_return(-1, "read of FTDIChip-ID failed");
}
int ftdi_write_eeprom_location(struct ftdi_context *ftdi, int eeprom_addr,
unsigned short eeprom_val)
{
int chip_type_location;
unsigned short chip_type;
if (ftdi == NULL || ftdi->usb_dev == NULL)
ftdi_error_return(-2, "USB device unavailable");
if (eeprom_addr <0x80)
ftdi_error_return(-2, "Invalid access to checksum protected area below 0x80");
switch (ftdi->type)
{
case TYPE_BM:
case TYPE_2232C:
chip_type_location = 0x14;
break;
case TYPE_2232H:
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");
}
if (ftdi_read_eeprom_location( ftdi, chip_type_location>>1, &chip_type))
ftdi_error_return(-5, "Reading failed");
fprintf(stderr," loc 0x%04x val 0x%04x\n", chip_type_location,chip_type);
if ((chip_type & 0xff) != 0x66)
{
ftdi_error_return(-6, "EEPROM is not of 93x66");
}
if (libusb_control_transfer(ftdi->usb_dev, FTDI_DEVICE_OUT_REQTYPE,
SIO_WRITE_EEPROM_REQUEST, eeprom_val, eeprom_addr,
NULL, 0, ftdi->usb_write_timeout) != 0)
ftdi_error_return(-1, "unable to write eeprom");
return 0;
}
int ftdi_write_eeprom(struct ftdi_context *ftdi)
{
unsigned short usb_val, status;
int i, ret;
unsigned char *eeprom;
if (ftdi == NULL || ftdi->usb_dev == NULL)
ftdi_error_return(-2, "USB device unavailable");
if(ftdi->eeprom->initialized_for_connected_device == 0)
ftdi_error_return(-3, "EEPROM not initialized for the connected device");
eeprom = ftdi->eeprom->buf;
/* These commands were traced while running MProg */
if ((ret = ftdi_usb_reset(ftdi)) != 0)
return ret;
if ((ret = ftdi_poll_modem_status(ftdi, &status)) != 0)
return ret;
if ((ret = ftdi_set_latency_timer(ftdi, 0x77)) != 0)
return ret;
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,
SIO_WRITE_EEPROM_REQUEST, usb_val, i,
NULL, 0, ftdi->usb_write_timeout) < 0)
ftdi_error_return(-1, "unable to write eeprom");
}
return 0;
}
#define MAGIC 0x55aa
int ftdi_erase_eeprom(struct ftdi_context *ftdi)
{
unsigned short eeprom_value;
if (ftdi == NULL || ftdi->usb_dev == NULL)
ftdi_error_return(-2, "USB device unavailable");
if ((ftdi->type == TYPE_R) || (ftdi->type == TYPE_230X))
{
ftdi->eeprom->chip = 0;
return 0;
}
if (libusb_control_transfer(ftdi->usb_dev, FTDI_DEVICE_OUT_REQTYPE, SIO_ERASE_EEPROM_REQUEST,
0, 0, NULL, 0, ftdi->usb_write_timeout) < 0)
ftdi_error_return(-1, "unable to erase eeprom");
/* detect chip type by writing 0x55AA as magic at word position 0xc0
Chip is 93x46 if magic is read at word position 0x00, as wraparound happens around 0x40
Chip is 93x56 if magic is read at word position 0x40, as wraparound happens around 0x80
Chip is 93x66 if magic is only read at word position 0xc0*/
if (libusb_control_transfer(ftdi->usb_dev, FTDI_DEVICE_OUT_REQTYPE,
SIO_WRITE_EEPROM_REQUEST, MAGIC, 0xc0,
NULL, 0, ftdi->usb_write_timeout) != 0)
ftdi_error_return(-3, "Writing magic failed");
if (ftdi_read_eeprom_location( ftdi, 0x00, &eeprom_value))
ftdi_error_return(-4, "Reading failed");
if (eeprom_value == MAGIC)
{
ftdi->eeprom->chip = 0x46;
}
else
{
if (ftdi_read_eeprom_location( ftdi, 0x40, &eeprom_value))
ftdi_error_return(-4, "Reading failed");
if (eeprom_value == MAGIC)
ftdi->eeprom->chip = 0x56;
else
{
if (ftdi_read_eeprom_location( ftdi, 0xc0, &eeprom_value))
ftdi_error_return(-4, "Reading failed");
if (eeprom_value == MAGIC)
ftdi->eeprom->chip = 0x66;
else
{
ftdi->eeprom->chip = -1;
}
}
}
if (libusb_control_transfer(ftdi->usb_dev, FTDI_DEVICE_OUT_REQTYPE, SIO_ERASE_EEPROM_REQUEST,
0, 0, NULL, 0, ftdi->usb_write_timeout) < 0)
ftdi_error_return(-1, "unable to erase eeprom");
return 0;
}
const char *ftdi_get_error_string (struct ftdi_context *ftdi)
{
if (ftdi == NULL)
return "";
return ftdi->error_str;
}
/* @} end of doxygen libftdi group */
ftdi_write_data
int ftdi_write_data(struct ftdi_context *ftdi, const unsigned char *buf, int size)
Definition ftdi.c:1583
ftdi_set_line_property
int ftdi_set_line_property(struct ftdi_context *ftdi, enum ftdi_bits_type bits, enum ftdi_stopbits_type sbit, enum ftdi_parity_type parity)
Definition ftdi.c:1494
ftdi_usb_open_dev
int ftdi_usb_open_dev(struct ftdi_context *ftdi, libusb_device *dev)
Definition ftdi.c:589
ftdi_eeprom_initdefaults
int ftdi_eeprom_initdefaults(struct ftdi_context *ftdi, char *manufacturer, char *product, char *serial)
Definition ftdi.c:2579
ftdi_read_data_submit
struct ftdi_transfer_control * ftdi_read_data_submit(struct ftdi_context *ftdi, unsigned char *buf, int size)
Definition ftdi.c:1805
ftdi_usb_get_strings
int ftdi_usb_get_strings(struct ftdi_context *ftdi, struct libusb_device *dev, char *manufacturer, int mnf_len, char *description, int desc_len, char *serial, int serial_len)
Definition ftdi.c:413
ftdi_set_eeprom_user_data
int ftdi_set_eeprom_user_data(struct ftdi_context *ftdi, const char *buf, int size)
Definition ftdi.c:4416
ftdi_usb_purge_tx_buffer
int ftdi_usb_purge_tx_buffer(struct ftdi_context *ftdi)
Definition ftdi.c:1113
ftdi_set_usbdev
void ftdi_set_usbdev(struct ftdi_context *ftdi, libusb_device_handle *usb)
Definition ftdi.c:272
ftdi_init
int ftdi_init(struct ftdi_context *ftdi)
Definition ftdi.c:91
ftdi_usb_purge_rx_buffer
int ftdi_usb_purge_rx_buffer(struct ftdi_context *ftdi)
Definition ftdi.c:1060
ftdi_erase_eeprom
int ftdi_erase_eeprom(struct ftdi_context *ftdi)
Definition ftdi.c:4669
ftdi_usb_reset
int ftdi_usb_reset(struct ftdi_context *ftdi)
Definition ftdi.c:1003
ftdi_usb_find_all
int ftdi_usb_find_all(struct ftdi_context *ftdi, struct ftdi_device_list **devlist, int vendor, int product)
Definition ftdi.c:314
ftdi_usb_purge_buffers
int ftdi_usb_purge_buffers(struct ftdi_context *ftdi)
Definition ftdi.c:1168
ftdi_list_free
void ftdi_list_free(struct ftdi_device_list **devlist)
Definition ftdi.c:362
ftdi_tciflush
int ftdi_tciflush(struct ftdi_context *ftdi)
Definition ftdi.c:1030
ftdi_poll_modem_status
int ftdi_poll_modem_status(struct ftdi_context *ftdi, unsigned short *status)
Definition ftdi.c:2347
ftdi_usb_open_desc_index
int ftdi_usb_open_desc_index(struct ftdi_context *ftdi, int vendor, int product, const char *description, const char *serial, unsigned int index)
Definition ftdi.c:764
ftdi_free
void ftdi_free(struct ftdi_context *ftdi)
Definition ftdi.c:260
ftdi_set_latency_timer
int ftdi_set_latency_timer(struct ftdi_context *ftdi, unsigned char latency)
Definition ftdi.c:2266
ftdi_disable_bitbang
int ftdi_disable_bitbang(struct ftdi_context *ftdi)
Definition ftdi.c:2217
ftdi_setdtr
int ftdi_setdtr(struct ftdi_context *ftdi, int state)
Definition ftdi.c:2423
ftdi_set_line_property2
int ftdi_set_line_property2(struct ftdi_context *ftdi, enum ftdi_bits_type bits, enum ftdi_stopbits_type sbit, enum ftdi_parity_type parity, enum ftdi_break_type break_type)
Definition ftdi.c:1513
set_ft232h_cbus
void set_ft232h_cbus(struct ftdi_eeprom *eeprom, unsigned char *output)
Definition ftdi.c:2832
ftdi_error_return_free_device_list
#define ftdi_error_return_free_device_list(code, str, devs)
Definition ftdi.c:52
ftdi_setrts
int ftdi_setrts(struct ftdi_context *ftdi, int state)
Definition ftdi.c:2453
ftdi_write_data_get_chunksize
int ftdi_write_data_get_chunksize(struct ftdi_context *ftdi, unsigned int *chunksize)
Definition ftdi.c:1983
ftdi_setdtr_rts
int ftdi_setdtr_rts(struct ftdi_context *ftdi, int dtr, int rts)
Definition ftdi.c:2484
ftdi_write_eeprom_location
int ftdi_write_eeprom_location(struct ftdi_context *ftdi, int eeprom_addr, unsigned short eeprom_val)
Definition ftdi.c:4558
ftdi_get_eeprom_value
int ftdi_get_eeprom_value(struct ftdi_context *ftdi, enum ftdi_eeprom_value value_name, int *value)
Definition ftdi.c:3978
ftdi_eeprom_set_strings
int ftdi_eeprom_set_strings(struct ftdi_context *ftdi, const char *manufacturer, const char *product, const char *serial)
Definition ftdi.c:2727
ftdi_read_eeprom_location
int ftdi_read_eeprom_location(struct ftdi_context *ftdi, int eeprom_addr, unsigned short *eeprom_val)
Definition ftdi.c:4437
ftdi_read_data_set_chunksize
int ftdi_read_data_set_chunksize(struct ftdi_context *ftdi, unsigned int chunksize)
Definition ftdi.c:2133
ftdi_write_data_submit
struct ftdi_transfer_control * ftdi_write_data_submit(struct ftdi_context *ftdi, unsigned char *buf, int size)
Definition ftdi.c:1743
ftdi_set_interface
int ftdi_set_interface(struct ftdi_context *ftdi, enum ftdi_interface interface)
Definition ftdi.c:161
ftdi_set_event_char
int ftdi_set_event_char(struct ftdi_context *ftdi, unsigned char eventch, unsigned char enable)
Definition ftdi.c:2520
ftdi_deinit
void ftdi_deinit(struct ftdi_context *ftdi)
Definition ftdi.c:214
ftdi_read_data
int ftdi_read_data(struct ftdi_context *ftdi, unsigned char *buf, int size)
Definition ftdi.c:2007
ftdi_set_bitmode
int ftdi_set_bitmode(struct ftdi_context *ftdi, unsigned char bitmask, unsigned char mode)
Definition ftdi.c:2191
ftdi_get_error_string
const char * ftdi_get_error_string(struct ftdi_context *ftdi)
Definition ftdi.c:4731
ftdi_write_data_set_chunksize
int ftdi_write_data_set_chunksize(struct ftdi_context *ftdi, unsigned int chunksize)
Definition ftdi.c:1965
ftdi_error_return
#define ftdi_error_return(code, str)
Definition ftdi.c:44
ftdi_write_eeprom
int ftdi_write_eeprom(struct ftdi_context *ftdi)
Definition ftdi.c:4614
ftdi_set_eeprom_value
int ftdi_set_eeprom_value(struct ftdi_context *ftdi, enum ftdi_eeprom_value value_name, int value)
Definition ftdi.c:4171
H_CLK
#define H_CLK
convert_baudrate_UT_export
int convert_baudrate_UT_export(int baudrate, struct ftdi_context *ftdi, unsigned short *value, unsigned short *index)
Wrapper function to export ftdi_convert_baudrate() to the unit test Do not use, it's only for the uni...
Definition ftdi.c:1431
ftdi_get_eeprom_buf
int ftdi_get_eeprom_buf(struct ftdi_context *ftdi, unsigned char *buf, int size)
Definition ftdi.c:4367
ftdi_usb_open_desc
int ftdi_usb_open_desc(struct ftdi_context *ftdi, int vendor, int product, const char *description, const char *serial)
Definition ftdi.c:733
MAGIC
#define MAGIC
Definition ftdi.c:4668
ftdi_usb_close
int ftdi_usb_close(struct ftdi_context *ftdi)
Definition ftdi.c:1197
ftdi_usb_open
int ftdi_usb_open(struct ftdi_context *ftdi, int vendor, int product)
Definition ftdi.c:707
ftdi_list_free2
void ftdi_list_free2(struct ftdi_device_list *devlist)
Definition ftdi.c:382
ftdi_usb_open_bus_addr
int ftdi_usb_open_bus_addr(struct ftdi_context *ftdi, uint8_t bus, uint8_t addr)
Definition ftdi.c:857
ftdi_set_eeprom_buf
int ftdi_set_eeprom_buf(struct ftdi_context *ftdi, const unsigned char *buf, int size)
Definition ftdi.c:4393
ftdi_usb_open_string
int ftdi_usb_open_string(struct ftdi_context *ftdi, const char *description)
Definition ftdi.c:910
C_CLK
#define C_CLK
ftdi_read_data_get_chunksize
int ftdi_read_data_get_chunksize(struct ftdi_context *ftdi, unsigned int *chunksize)
Definition ftdi.c:2170
ftdi_new
struct ftdi_context * ftdi_new(void)
Definition ftdi.c:132
ftdi_tcoflush
int ftdi_tcoflush(struct ftdi_context *ftdi)
Definition ftdi.c:1087
ftdi_read_pins
int ftdi_read_pins(struct ftdi_context *ftdi, unsigned char *pins)
Definition ftdi.c:2240
ftdi_read_chipid
int ftdi_read_chipid(struct ftdi_context *ftdi, unsigned int *chipid)
Definition ftdi.c:4520
ftdi_read_eeprom
int ftdi_read_eeprom(struct ftdi_context *ftdi)
Definition ftdi.c:4461
ftdi_setflowctrl
int ftdi_setflowctrl(struct ftdi_context *ftdi, int flowctrl)
Definition ftdi.c:2375
ftdi_eeprom_decode
int ftdi_eeprom_decode(struct ftdi_context *ftdi, int verbose)
Definition ftdi.c:3548
ftdi_transfer_data_cancel
void ftdi_transfer_data_cancel(struct ftdi_transfer_control *tc, struct timeval *to)
Definition ftdi.c:1931
ftdi_eeprom_build
int ftdi_eeprom_build(struct ftdi_context *ftdi)
Definition ftdi.c:2910
ftdi_get_latency_timer
int ftdi_get_latency_timer(struct ftdi_context *ftdi, unsigned char *latency)
Definition ftdi.c:2293
ftdi_usb_get_strings2
int ftdi_usb_get_strings2(struct ftdi_context *ftdi, struct libusb_device *dev, char *manufacturer, int mnf_len, char *description, int desc_len, char *serial, int serial_len)
Definition ftdi.c:470
ftdi_setflowctrl_xonxoff
int ftdi_setflowctrl_xonxoff(struct ftdi_context *ftdi, unsigned char xon, unsigned char xoff)
Definition ftdi.c:2399
ftdi_set_baudrate
int ftdi_set_baudrate(struct ftdi_context *ftdi, int baudrate)
Definition ftdi.c:1448
ftdi_set_error_char
int ftdi_set_error_char(struct ftdi_context *ftdi, unsigned char errorch, unsigned char enable)
Definition ftdi.c:2549
ftdi_tcioflush
int ftdi_tcioflush(struct ftdi_context *ftdi)
Definition ftdi.c:1137
ftdi_eeprom_get_strings
int ftdi_eeprom_get_strings(struct ftdi_context *ftdi, char *manufacturer, int mnf_len, char *product, int prod_len, char *serial, int serial_len)
Definition ftdi.c:2793
ftdi_get_library_version
struct ftdi_version_info ftdi_get_library_version(void)
Get libftdi library version.
Definition ftdi.c:285
ftdi_transfer_data_done
int ftdi_transfer_data_done(struct ftdi_transfer_control *tc)
Definition ftdi.c:1884
ftdi.h
ftdi_chip_type
ftdi_chip_type
Definition ftdi.h:47
TYPE_2232H
@ TYPE_2232H
Definition ftdi.h:52
TYPE_BM
@ TYPE_BM
Definition ftdi.h:49
TYPE_R
@ TYPE_R
Definition ftdi.h:51
TYPE_2232C
@ TYPE_2232C
Definition ftdi.h:50
TYPE_230X
@ TYPE_230X
Definition ftdi.h:55
TYPE_4232H
@ TYPE_4232H
Definition ftdi.h:53
TYPE_AM
@ TYPE_AM
Definition ftdi.h:48
TYPE_232H
@ TYPE_232H
Definition ftdi.h:54
HIGH_CURRENT_DRIVE
#define HIGH_CURRENT_DRIVE
Definition ftdi.h:472
SIO_SET_DTR_LOW
#define SIO_SET_DTR_LOW
Definition ftdi.h:232
SLOW_SLEW
#define SLOW_SLEW
Definition ftdi.h:460
USE_SERIAL_NUM
#define USE_SERIAL_NUM
Definition ftdi.h:406
FT1284_CLK_IDLE_STATE
#define FT1284_CLK_IDLE_STATE
Definition ftdi.h:401
BITMODE_RESET
@ BITMODE_RESET
Definition ftdi.h:69
SIO_SET_DATA_REQUEST
#define SIO_SET_DATA_REQUEST
Definition ftdi.h:169
SIO_RESET_PURGE_TX
#define SIO_RESET_PURGE_TX
Definition ftdi.h:219
ftdi_stopbits_type
ftdi_stopbits_type
Definition ftdi.h:60
STOP_BIT_1
@ STOP_BIT_1
Definition ftdi.h:60
STOP_BIT_2
@ STOP_BIT_2
Definition ftdi.h:60
STOP_BIT_15
@ STOP_BIT_15
Definition ftdi.h:60
CHANNEL_IS_FT1284
#define CHANNEL_IS_FT1284
Definition ftdi.h:452
SIO_SET_EVENT_CHAR_REQUEST
#define SIO_SET_EVENT_CHAR_REQUEST
Definition ftdi.h:173
DRIVER_VCP
#define DRIVER_VCP
Definition ftdi.h:464
SIO_RESET_REQUEST
#define SIO_RESET_REQUEST
Definition ftdi.h:167
FT1284_DATA_LSB
#define FT1284_DATA_LSB
Definition ftdi.h:402
CBUSH_CLK7_5
@ CBUSH_CLK7_5
Definition ftdi.h:418
CBUSH_TRISTATE
@ CBUSH_TRISTATE
Definition ftdi.h:416
SIO_SET_ERROR_CHAR_REQUEST
#define SIO_SET_ERROR_CHAR_REQUEST
Definition ftdi.h:174
DRIVER_VCPH
#define DRIVER_VCPH
Definition ftdi.h:465
SIO_SET_MODEM_CTRL_REQUEST
#define SIO_SET_MODEM_CTRL_REQUEST
Definition ftdi.h:171
SIO_READ_PINS_REQUEST
#define SIO_READ_PINS_REQUEST
Definition ftdi.h:178
SIO_SET_LATENCY_TIMER_REQUEST
#define SIO_SET_LATENCY_TIMER_REQUEST
Definition ftdi.h:175
CHANNEL_IS_CPU
#define CHANNEL_IS_CPU
Definition ftdi.h:451
POWER_SAVE_DISABLE_H
#define POWER_SAVE_DISABLE_H
Definition ftdi.h:404
ftdi_bits_type
ftdi_bits_type
Definition ftdi.h:62
SIO_ERASE_EEPROM_REQUEST
#define SIO_ERASE_EEPROM_REQUEST
Definition ftdi.h:181
CHANNEL_IS_RS485
#define CHANNEL_IS_RS485
Definition ftdi.h:454
FT1284_FLOW_CONTROL
#define FT1284_FLOW_CONTROL
Definition ftdi.h:403
SIO_SET_BAUDRATE_REQUEST
#define SIO_SET_BAUDRATE_REQUEST
Definition ftdi.h:168
SIO_READ_EEPROM_REQUEST
#define SIO_READ_EEPROM_REQUEST
Definition ftdi.h:179
ftdi_interface
ftdi_interface
Definition ftdi.h:83
INTERFACE_C
@ INTERFACE_C
Definition ftdi.h:87
INTERFACE_D
@ INTERFACE_D
Definition ftdi.h:88
INTERFACE_B
@ INTERFACE_B
Definition ftdi.h:86
INTERFACE_ANY
@ INTERFACE_ANY
Definition ftdi.h:84
INTERFACE_A
@ INTERFACE_A
Definition ftdi.h:85
SIO_TCIFLUSH
#define SIO_TCIFLUSH
Definition ftdi.h:222
CHANNEL_IS_OPTO
#define CHANNEL_IS_OPTO
Definition ftdi.h:450
SIO_POLL_MODEM_STATUS_REQUEST
#define SIO_POLL_MODEM_STATUS_REQUEST
Definition ftdi.h:172
SIO_WRITE_EEPROM_REQUEST
#define SIO_WRITE_EEPROM_REQUEST
Definition ftdi.h:180
ftdi_parity_type
ftdi_parity_type
Definition ftdi.h:58
EVEN
@ EVEN
Definition ftdi.h:58
ODD
@ ODD
Definition ftdi.h:58
MARK
@ MARK
Definition ftdi.h:58
SPACE
@ SPACE
Definition ftdi.h:58
NONE
@ NONE
Definition ftdi.h:58
SIO_XON_XOFF_HS
#define SIO_XON_XOFF_HS
Definition ftdi.h:228
CBUSX_TXDEN
@ CBUSX_TXDEN
Definition ftdi.h:424
CBUSX_AWAKE
@ CBUSX_AWAKE
Definition ftdi.h:427
CBUSX_SLEEP
@ CBUSX_SLEEP
Definition ftdi.h:424
CBUSX_RXLED
@ CBUSX_RXLED
Definition ftdi.h:423
CBUSX_TXLED
@ CBUSX_TXLED
Definition ftdi.h:423
SIO_SET_DTR_HIGH
#define SIO_SET_DTR_HIGH
Definition ftdi.h:231
FTDI_DEVICE_IN_REQTYPE
#define FTDI_DEVICE_IN_REQTYPE
Definition ftdi.h:164
SIO_RESET_SIO
#define SIO_RESET_SIO
Definition ftdi.h:184
SIO_SET_FLOW_CTRL_REQUEST
#define SIO_SET_FLOW_CTRL_REQUEST
Definition ftdi.h:170
ftdi_eeprom_value
ftdi_eeprom_value
Definition ftdi.h:330
CHANNEL_B_RS485
@ CHANNEL_B_RS485
Definition ftdi.h:383
GROUP1_SCHMITT
@ GROUP1_SCHMITT
Definition ftdi.h:366
GROUP2_DRIVE
@ GROUP2_DRIVE
Definition ftdi.h:368
CBUS_FUNCTION_6
@ CBUS_FUNCTION_6
Definition ftdi.h:354
CBUS_FUNCTION_9
@ CBUS_FUNCTION_9
Definition ftdi.h:357
IN_IS_ISOCHRONOUS
@ IN_IS_ISOCHRONOUS
Definition ftdi.h:337
SUSPEND_DBUS7
@ SUSPEND_DBUS7
Definition ftdi.h:336
GROUP2_SCHMITT
@ GROUP2_SCHMITT
Definition ftdi.h:369
FLOW_CONTROL
@ FLOW_CONTROL
Definition ftdi.h:379
CBUS_FUNCTION_8
@ CBUS_FUNCTION_8
Definition ftdi.h:356
DATA_ORDER
@ DATA_ORDER
Definition ftdi.h:378
CHANNEL_D_DRIVER
@ CHANNEL_D_DRIVER
Definition ftdi.h:381
CHANNEL_B_DRIVER
@ CHANNEL_B_DRIVER
Definition ftdi.h:347
USE_USB_VERSION
@ USE_USB_VERSION
Definition ftdi.h:342
CHANNEL_C_RS485
@ CHANNEL_C_RS485
Definition ftdi.h:384
CBUS_FUNCTION_2
@ CBUS_FUNCTION_2
Definition ftdi.h:350
CHIP_SIZE
@ CHIP_SIZE
Definition ftdi.h:374
POWER_SAVE
@ POWER_SAVE
Definition ftdi.h:376
CHANNEL_C_DRIVER
@ CHANNEL_C_DRIVER
Definition ftdi.h:380
CLOCK_POLARITY
@ CLOCK_POLARITY
Definition ftdi.h:377
USB_VERSION
@ USB_VERSION
Definition ftdi.h:341
CBUS_FUNCTION_4
@ CBUS_FUNCTION_4
Definition ftdi.h:352
GROUP0_SLEW
@ GROUP0_SLEW
Definition ftdi.h:364
REMOTE_WAKEUP
@ REMOTE_WAKEUP
Definition ftdi.h:334
SUSPEND_PULL_DOWNS
@ SUSPEND_PULL_DOWNS
Definition ftdi.h:339
PRODUCT_ID
@ PRODUCT_ID
Definition ftdi.h:332
HIGH_CURRENT
@ HIGH_CURRENT
Definition ftdi.h:358
USE_SERIAL
@ USE_SERIAL
Definition ftdi.h:340
CHANNEL_D_RS485
@ CHANNEL_D_RS485
Definition ftdi.h:385
CHANNEL_B_TYPE
@ CHANNEL_B_TYPE
Definition ftdi.h:345
CBUS_FUNCTION_1
@ CBUS_FUNCTION_1
Definition ftdi.h:349
IS_NOT_PNP
@ IS_NOT_PNP
Definition ftdi.h:335
MAX_POWER
@ MAX_POWER
Definition ftdi.h:343
CHANNEL_A_TYPE
@ CHANNEL_A_TYPE
Definition ftdi.h:344
SELF_POWERED
@ SELF_POWERED
Definition ftdi.h:333
GROUP1_SLEW
@ GROUP1_SLEW
Definition ftdi.h:367
HIGH_CURRENT_A
@ HIGH_CURRENT_A
Definition ftdi.h:359
GROUP3_DRIVE
@ GROUP3_DRIVE
Definition ftdi.h:371
CHANNEL_A_DRIVER
@ CHANNEL_A_DRIVER
Definition ftdi.h:346
HIGH_CURRENT_B
@ HIGH_CURRENT_B
Definition ftdi.h:360
VENDOR_ID
@ VENDOR_ID
Definition ftdi.h:331
GROUP0_SCHMITT
@ GROUP0_SCHMITT
Definition ftdi.h:363
CHIP_TYPE
@ CHIP_TYPE
Definition ftdi.h:375
INVERT
@ INVERT
Definition ftdi.h:361
GROUP2_SLEW
@ GROUP2_SLEW
Definition ftdi.h:370
CBUS_FUNCTION_3
@ CBUS_FUNCTION_3
Definition ftdi.h:351
RELEASE_NUMBER
@ RELEASE_NUMBER
Definition ftdi.h:386
OUT_IS_ISOCHRONOUS
@ OUT_IS_ISOCHRONOUS
Definition ftdi.h:338
CBUS_FUNCTION_7
@ CBUS_FUNCTION_7
Definition ftdi.h:355
EXTERNAL_OSCILLATOR
@ EXTERNAL_OSCILLATOR
Definition ftdi.h:387
CBUS_FUNCTION_5
@ CBUS_FUNCTION_5
Definition ftdi.h:353
CBUS_FUNCTION_0
@ CBUS_FUNCTION_0
Definition ftdi.h:348
GROUP0_DRIVE
@ GROUP0_DRIVE
Definition ftdi.h:362
GROUP3_SLEW
@ GROUP3_SLEW
Definition ftdi.h:373
USER_DATA_ADDR
@ USER_DATA_ADDR
Definition ftdi.h:388
CHANNEL_A_RS485
@ CHANNEL_A_RS485
Definition ftdi.h:382
GROUP1_DRIVE
@ GROUP1_DRIVE
Definition ftdi.h:365
GROUP3_SCHMITT
@ GROUP3_SCHMITT
Definition ftdi.h:372
SIO_SET_RTS_LOW
#define SIO_SET_RTS_LOW
Definition ftdi.h:235
CBUS_TXLED
@ CBUS_TXLED
Definition ftdi.h:409
CBUS_PWREN
@ CBUS_PWREN
Definition ftdi.h:409
CBUS_SLEEP
@ CBUS_SLEEP
Definition ftdi.h:410
CBUS_RXLED
@ CBUS_RXLED
Definition ftdi.h:409
CBUS_TXDEN
@ CBUS_TXDEN
Definition ftdi.h:409
CBUS_BB_RD
@ CBUS_BB_RD
Definition ftdi.h:411
CBUS_CLK6
@ CBUS_CLK6
Definition ftdi.h:410
SIO_GET_LATENCY_TIMER_REQUEST
#define SIO_GET_LATENCY_TIMER_REQUEST
Definition ftdi.h:176
SUSPEND_DBUS7_BIT
#define SUSPEND_DBUS7_BIT
Definition ftdi.h:469
AUTO_DETACH_SIO_MODULE
@ AUTO_DETACH_SIO_MODULE
Definition ftdi.h:94
AUTO_DETACH_REATACH_SIO_MODULE
@ AUTO_DETACH_REATACH_SIO_MODULE
Definition ftdi.h:96
HIGH_CURRENT_DRIVE_R
#define HIGH_CURRENT_DRIVE_R
Definition ftdi.h:473
ftdi_break_type
ftdi_break_type
Definition ftdi.h:64
BREAK_OFF
@ BREAK_OFF
Definition ftdi.h:64
BREAK_ON
@ BREAK_ON
Definition ftdi.h:64
CHANNEL_IS_UART
#define CHANNEL_IS_UART
Definition ftdi.h:448
SIO_RESET_PURGE_RX
#define SIO_RESET_PURGE_RX
Definition ftdi.h:218
IS_SCHMITT
#define IS_SCHMITT
Definition ftdi.h:461
USE_USB_VERSION_BIT
#define USE_USB_VERSION_BIT
Definition ftdi.h:467
DRIVE_16MA
#define DRIVE_16MA
Definition ftdi.h:459
SIO_SET_RTS_HIGH
#define SIO_SET_RTS_HIGH
Definition ftdi.h:234
SIO_TCOFLUSH
#define SIO_TCOFLUSH
Definition ftdi.h:223
CHANNEL_IS_FIFO
#define CHANNEL_IS_FIFO
Definition ftdi.h:449
SIO_SET_BITMODE_REQUEST
#define SIO_SET_BITMODE_REQUEST
Definition ftdi.h:177
FTDI_DEVICE_OUT_REQTYPE
#define FTDI_DEVICE_OUT_REQTYPE
Definition ftdi.h:163
ftdi_i.h
FTDI_MAX_EEPROM_SIZE
#define FTDI_MAX_EEPROM_SIZE
Definition ftdi_i.h:23
MAX_POWER_MILLIAMP_PER_UNIT
#define MAX_POWER_MILLIAMP_PER_UNIT
Definition ftdi_i.h:26
ftdi_context
Main context structure for all libftdi functions.
Definition ftdi.h:272
ftdi_context::bitbang_mode
unsigned char bitbang_mode
Definition ftdi.h:314
ftdi_context::eeprom
struct ftdi_eeprom * eeprom
Definition ftdi.h:317
ftdi_context::usb_ctx
struct libusb_context * usb_ctx
Definition ftdi.h:275
ftdi_context::module_detach_mode
enum ftdi_module_detach_mode module_detach_mode
Definition ftdi.h:323
ftdi_context::out_ep
int out_ep
Definition ftdi.h:311
ftdi_context::writebuffer_chunksize
unsigned int writebuffer_chunksize
Definition ftdi.h:299
ftdi_context::bitbang_enabled
unsigned char bitbang_enabled
Definition ftdi.h:289
ftdi_context::usb_dev
struct libusb_device_handle * usb_dev
Definition ftdi.h:277
ftdi_context::type
enum ftdi_chip_type type
Definition ftdi.h:285
ftdi_context::max_packet_size
unsigned int max_packet_size
Definition ftdi.h:301
ftdi_context::readbuffer
unsigned char * readbuffer
Definition ftdi.h:291
ftdi_context::readbuffer_chunksize
unsigned int readbuffer_chunksize
Definition ftdi.h:297
ftdi_context::error_str
const char * error_str
Definition ftdi.h:320
ftdi_context::in_ep
int in_ep
Definition ftdi.h:310
ftdi_context::index
int index
Definition ftdi.h:307
ftdi_context::baudrate
int baudrate
Definition ftdi.h:287
ftdi_context::readbuffer_remaining
unsigned int readbuffer_remaining
Definition ftdi.h:295
ftdi_context::interface
int interface
Definition ftdi.h:305
ftdi_context::readbuffer_offset
unsigned int readbuffer_offset
Definition ftdi.h:293
ftdi_context::usb_write_timeout
int usb_write_timeout
Definition ftdi.h:281
ftdi_context::usb_read_timeout
int usb_read_timeout
Definition ftdi.h:279
ftdi_device_list
list of usb devices created by ftdi_usb_find_all()
Definition ftdi.h:395
ftdi_device_list::next
struct ftdi_device_list * next
Definition ftdi.h:397
ftdi_device_list::dev
struct libusb_device * dev
Definition ftdi.h:399
ftdi_eeprom
FTDI eeprom structure.
Definition ftdi_i.h:32
ftdi_eeprom::user_data_addr
int user_data_addr
Definition ftdi_i.h:130
ftdi_eeprom::self_powered
int self_powered
Definition ftdi_i.h:43
ftdi_eeprom::user_data_size
int user_data_size
Definition ftdi_i.h:131
ftdi_eeprom::buf
unsigned char buf[FTDI_MAX_EEPROM_SIZE]
Definition ftdi_i.h:139
ftdi_eeprom::channel_b_driver
int channel_b_driver
Definition ftdi_i.h:82
ftdi_eeprom::group3_slew
int group3_slew
Definition ftdi_i.h:121
ftdi_eeprom::external_oscillator
int external_oscillator
Definition ftdi_i.h:103
ftdi_eeprom::channel_c_rs485enable
int channel_c_rs485enable
Definition ftdi_i.h:88
ftdi_eeprom::channel_b_type
int channel_b_type
Definition ftdi_i.h:79
ftdi_eeprom::is_not_pnp
int is_not_pnp
Definition ftdi_i.h:47
ftdi_eeprom::group0_schmitt
int group0_schmitt
Definition ftdi_i.h:111
ftdi_eeprom::invert
int invert
Definition ftdi_i.h:101
ftdi_eeprom::high_current_a
int high_current_a
Definition ftdi_i.h:97
ftdi_eeprom::high_current_b
int high_current_b
Definition ftdi_i.h:99
ftdi_eeprom::in_is_isochronous
int in_is_isochronous
Definition ftdi_i.h:53
ftdi_eeprom::use_usb_version
int use_usb_version
Definition ftdi_i.h:64
ftdi_eeprom::clock_polarity
int clock_polarity
Definition ftdi_i.h:125
ftdi_eeprom::group2_drive
int group2_drive
Definition ftdi_i.h:116
ftdi_eeprom::group1_drive
int group1_drive
Definition ftdi_i.h:113
ftdi_eeprom::channel_a_driver
int channel_a_driver
Definition ftdi_i.h:81
ftdi_eeprom::user_data
const char * user_data
Definition ftdi_i.h:132
ftdi_eeprom::channel_d_rs485enable
int channel_d_rs485enable
Definition ftdi_i.h:89
ftdi_eeprom::size
int size
Definition ftdi_i.h:136
ftdi_eeprom::chip
int chip
Definition ftdi_i.h:138
ftdi_eeprom::suspend_pull_downs
int suspend_pull_downs
Definition ftdi_i.h:57
ftdi_eeprom::initialized_for_connected_device
int initialized_for_connected_device
Definition ftdi_i.h:40
ftdi_eeprom::group3_schmitt
int group3_schmitt
Definition ftdi_i.h:120
ftdi_eeprom::usb_version
int usb_version
Definition ftdi_i.h:62
ftdi_eeprom::flow_control
int flow_control
Definition ftdi_i.h:127
ftdi_eeprom::data_order
int data_order
Definition ftdi_i.h:126
ftdi_eeprom::max_power
int max_power
Definition ftdi_i.h:66
ftdi_eeprom::group1_slew
int group1_slew
Definition ftdi_i.h:115
ftdi_eeprom::remote_wakeup
int remote_wakeup
Definition ftdi_i.h:45
ftdi_eeprom::product
char * product
Definition ftdi_i.h:71
ftdi_eeprom::group2_schmitt
int group2_schmitt
Definition ftdi_i.h:117
ftdi_eeprom::serial
char * serial
Definition ftdi_i.h:73
ftdi_eeprom::release_number
int release_number
Definition ftdi_i.h:142
ftdi_eeprom::product_id
int product_id
Definition ftdi_i.h:36
ftdi_eeprom::cbus_function
int cbus_function[10]
Definition ftdi_i.h:93
ftdi_eeprom::group2_slew
int group2_slew
Definition ftdi_i.h:118
ftdi_eeprom::group0_slew
int group0_slew
Definition ftdi_i.h:112
ftdi_eeprom::out_is_isochronous
int out_is_isochronous
Definition ftdi_i.h:55
ftdi_eeprom::group0_drive
int group0_drive
Definition ftdi_i.h:110
ftdi_eeprom::use_serial
int use_serial
Definition ftdi_i.h:60
ftdi_eeprom::group1_schmitt
int group1_schmitt
Definition ftdi_i.h:114
ftdi_eeprom::channel_a_rs485enable
int channel_a_rs485enable
Definition ftdi_i.h:86
ftdi_eeprom::manufacturer
char * manufacturer
Definition ftdi_i.h:69
ftdi_eeprom::powersave
int powersave
Definition ftdi_i.h:123
ftdi_eeprom::high_current
int high_current
Definition ftdi_i.h:95
ftdi_eeprom::channel_c_driver
int channel_c_driver
Definition ftdi_i.h:83
ftdi_eeprom::channel_a_type
int channel_a_type
Definition ftdi_i.h:78
ftdi_eeprom::group3_drive
int group3_drive
Definition ftdi_i.h:119
ftdi_eeprom::channel_d_driver
int channel_d_driver
Definition ftdi_i.h:84
ftdi_eeprom::channel_b_rs485enable
int channel_b_rs485enable
Definition ftdi_i.h:87
ftdi_eeprom::vendor_id
int vendor_id
Definition ftdi_i.h:34
ftdi_eeprom::suspend_dbus7
int suspend_dbus7
Definition ftdi_i.h:50
ftdi_transfer_control
Definition ftdi.h:257
ftdi_transfer_control::size
int size
Definition ftdi.h:260
ftdi_transfer_control::transfer
struct libusb_transfer * transfer
Definition ftdi.h:263
ftdi_transfer_control::buf
unsigned char * buf
Definition ftdi.h:259
ftdi_transfer_control::offset
int offset
Definition ftdi.h:261
ftdi_transfer_control::ftdi
struct ftdi_context * ftdi
Definition ftdi.h:262
ftdi_transfer_control::completed
int completed
Definition ftdi.h:258
ftdi_version_info
Definition ftdi.h:506
ftdi_version_info::minor
int minor
Definition ftdi.h:508
ftdi_version_info::major
int major
Definition ftdi.h:507
ftdi_version_info::micro
int micro
Definition ftdi.h:509
ftdi_version_info::snapshot_str
const char * snapshot_str
Definition ftdi.h:511
ftdi_version_info::version_str
const char * version_str
Definition ftdi.h:510