+ if (require_send > 0)
+ if (ft2232_send_and_recv(first_unsent, cmd) != ERROR_OK)
+ retval = ERROR_JTAG_QUEUE_FAILED;
+
+ return retval;
+}
+
+
+#if BUILD_FT2232_FTD2XX == 1
+static int ft2232_init_ftd2xx(u16 vid, u16 pid, int more, int* try_more)
+{
+ FT_STATUS status;
+ DWORD openex_flags = 0;
+ char* openex_string = NULL;
+ u8 latency_timer;
+
+ LOG_DEBUG("'ft2232' interface using FTD2XX with '%s' layout (%4.4x:%4.4x)", ft2232_layout, vid, pid);
+
+#if IS_WIN32 == 0
+ /* Add non-standard Vid/Pid to the linux driver */
+ if ( ( status = FT_SetVIDPID(vid, pid) ) != FT_OK )
+ {
+ LOG_WARNING("couldn't add %4.4x:%4.4x", vid, pid);
+ }
+#endif
+
+ if (ft2232_device_desc && ft2232_serial)
+ {
+ LOG_WARNING("can't open by device description and serial number, giving precedence to serial");
+ ft2232_device_desc = NULL;
+ }
+
+ if (ft2232_device_desc)
+ {
+ openex_string = ft2232_device_desc;
+ openex_flags = FT_OPEN_BY_DESCRIPTION;
+ }
+ else if (ft2232_serial)
+ {
+ openex_string = ft2232_serial;
+ openex_flags = FT_OPEN_BY_SERIAL_NUMBER;
+ }
+ else
+ {
+ LOG_ERROR("neither device description nor serial number specified");
+ LOG_ERROR("please add \"ft2232_device_desc <string>\" or \"ft2232_serial <string>\" to your .cfg file");
+
+ return ERROR_JTAG_INIT_FAILED;
+ }
+
+ status = FT_OpenEx(openex_string, openex_flags, &ftdih);
+ if( status != FT_OK ){
+ // under Win32, the FTD2XX driver appends an "A" to the end
+ // of the description, if we tried by the desc, then
+ // try by the alternate "A" description.
+ if( openex_string == ft2232_device_desc ){
+ // Try the alternate method.
+ openex_string = ft2232_device_desc_A;
+ status = FT_OpenEx(openex_string, openex_flags, &ftdih);
+ if( status == FT_OK ){
+ // yea, the "alternate" method worked!
+ } else {
+ // drat, give the user a meaningfull message.
+ // telling the use we tried *BOTH* methods.
+ LOG_WARNING("Unable to open FTDI Device tried: '%s' and '%s'\n",
+ ft2232_device_desc,
+ ft2232_device_desc_A );
+ }
+ }
+ }
+
+ if ( status != FT_OK )
+ {
+ DWORD num_devices;
+
+ if (more)
+ {
+ LOG_WARNING("unable to open ftdi device (trying more): %lu", status);
+ *try_more = 1;
+ return ERROR_JTAG_INIT_FAILED;
+ }
+ LOG_ERROR("unable to open ftdi device: %lu", status);
+ status = FT_ListDevices(&num_devices, NULL, FT_LIST_NUMBER_ONLY);
+ if (status == FT_OK)
+ {
+ char** desc_array = malloc( sizeof(char*) * (num_devices + 1) );
+ u32 i;
+
+ for (i = 0; i < num_devices; i++)
+ desc_array[i] = malloc(64);
+
+ desc_array[num_devices] = NULL;
+
+ status = FT_ListDevices(desc_array, &num_devices, FT_LIST_ALL | openex_flags);
+
+ if (status == FT_OK)
+ {
+ LOG_ERROR("ListDevices: %lu\n", num_devices);
+ for (i = 0; i < num_devices; i++)
+ LOG_ERROR("%i: \"%s\"", i, desc_array[i]);
+ }
+
+ for (i = 0; i < num_devices; i++)
+ free(desc_array[i]);
+
+ free(desc_array);
+ }
+ else
+ {
+ LOG_ERROR("ListDevices: NONE\n");
+ }
+ return ERROR_JTAG_INIT_FAILED;
+ }
+
+ if ( ( status = FT_SetLatencyTimer(ftdih, ft2232_latency) ) != FT_OK )
+ {
+ LOG_ERROR("unable to set latency timer: %lu", status);
+ return ERROR_JTAG_INIT_FAILED;
+ }
+
+ if ( ( status = FT_GetLatencyTimer(ftdih, &latency_timer) ) != FT_OK )
+ {
+ LOG_ERROR("unable to get latency timer: %lu", status);
+ return ERROR_JTAG_INIT_FAILED;
+ }
+ else
+ {
+ LOG_DEBUG("current latency timer: %i", latency_timer);
+ }
+
+ if ( ( status = FT_SetTimeouts(ftdih, 5000, 5000) ) != FT_OK )
+ {
+ LOG_ERROR("unable to set timeouts: %lu", status);
+ return ERROR_JTAG_INIT_FAILED;
+ }
+
+ if ( ( status = FT_SetBitMode(ftdih, 0x0b, 2) ) != FT_OK )
+ {
+ LOG_ERROR("unable to enable bit i/o mode: %lu", status);
+ return ERROR_JTAG_INIT_FAILED;
+ }
+
+ return ERROR_OK;
+}
+
+
+static int ft2232_purge_ftd2xx(void)
+{
+ FT_STATUS status;
+
+ if ( ( status = FT_Purge(ftdih, FT_PURGE_RX | FT_PURGE_TX) ) != FT_OK )
+ {
+ LOG_ERROR("error purging ftd2xx device: %lu", status);
+ return ERROR_JTAG_INIT_FAILED;
+ }
+
+ return ERROR_OK;
+}
+
+
+#endif /* BUILD_FT2232_FTD2XX == 1 */
+
+#if BUILD_FT2232_LIBFTDI == 1
+static int ft2232_init_libftdi(u16 vid, u16 pid, int more, int* try_more)
+{
+ u8 latency_timer;
+
+ LOG_DEBUG("'ft2232' interface using libftdi with '%s' layout (%4.4x:%4.4x)",
+ ft2232_layout, vid, pid);
+
+ if (ftdi_init(&ftdic) < 0)
+ return ERROR_JTAG_INIT_FAILED;
+
+ /* context, vendor id, product id */
+ if (ftdi_usb_open_desc(&ftdic, vid, pid, ft2232_device_desc,
+ ft2232_serial) < 0)
+ {
+ if (more)
+ LOG_WARNING("unable to open ftdi device (trying more): %s",
+ ftdic.error_str);
+ else
+ LOG_ERROR("unable to open ftdi device: %s", ftdic.error_str);
+ *try_more = 1;
+ return ERROR_JTAG_INIT_FAILED;
+ }
+
+ if (ftdi_set_interface(&ftdic, INTERFACE_A) < 0)
+ {
+ LOG_ERROR("unable to select FT2232 channel A: %s", ftdic.error_str);
+ return ERROR_JTAG_INIT_FAILED;
+ }
+
+ if (ftdi_usb_reset(&ftdic) < 0)
+ {
+ LOG_ERROR("unable to reset ftdi device");
+ return ERROR_JTAG_INIT_FAILED;
+ }
+
+ if (ftdi_set_latency_timer(&ftdic, ft2232_latency) < 0)
+ {
+ LOG_ERROR("unable to set latency timer");
+ return ERROR_JTAG_INIT_FAILED;
+ }
+
+ if (ftdi_get_latency_timer(&ftdic, &latency_timer) < 0)
+ {
+ LOG_ERROR("unable to get latency timer");
+ return ERROR_JTAG_INIT_FAILED;
+ }
+ else
+ {
+ LOG_DEBUG("current latency timer: %i", latency_timer);
+ }
+
+ ftdi_set_bitmode(&ftdic, 0x0b, 2); /* ctx, JTAG I/O mask */