commit 96f6abd7beca1c4069fb8385bdfee322ae3e5d68
Author: David Mosberger-Tang <davidm@egauge.net>
Date:   Thu May 4 16:10:45 2017 -0600

    Add D2XX driver compatiblity.  There is nothing really wrong with
    libftdi1 on Windows, but the D2XX driver seems more easy to install.
    
    Performance is reasonable (measured on a relatively slow laptop):
    
    ---
    $ avrdude.exe -ctc2030 -pt9 -Uflash:w:out.hex -b750000
    
    avrdude.exe: AVR device initialized and ready to accept instructions
    
    Reading | ################################################## | 100% 0.03s
    
    avrdude.exe: Device signature = 0x1e9008 (probably t9)
    avrdude.exe: NOTE: "flash" memory has been specified, an erase cycle will be pe
    formed
                 To disable this feature, specify the -D option.
    	     avrdude.exe: erasing chip
    	     avrdude.exe: reading input file "out.hex"
    	     avrdude.exe: input file out.hex auto detected as Intel Hex
    	     avrdude.exe: writing flash (998 bytes):
    
    Writing | ################################################## | 100% 3.17s
    
    avrdude.exe: 998 bytes of flash written
    avrdude.exe: verifying flash memory against out.hex:
    avrdude.exe: load data flash data from input file out.hex:
    avrdude.exe: input file out.hex auto detected as Intel Hex
    avrdude.exe: input file out.hex contains 998 bytes
    avrdude.exe: reading on-chip flash data:
    
    Reading | ################################################## | 100% 2.00s
    
    avrdude.exe: verifying ...
    avrdude.exe: 998 bytes of flash verified
    
    avrdude.exe done.  Thank you.
    ---

diff --git a/configure.ac b/configure.ac
index a23a959..ba96bc8 100644
--- a/configure.ac
+++ b/configure.ac
@@ -17,7 +17,7 @@
 #
 
 #
-# $Id$
+# $Id: configure.ac 1390 2016-04-20 20:40:58Z joerg_wunsch $
 #
 
 # Process this file with autoconf to produce a configure script.
@@ -169,6 +169,8 @@ fi
 AC_SUBST(LIBHIDAPI, $LIBHIDAPI)
 
 
+AH_TEMPLATE([HAVE_LIBFTD2XX],
+	    [Define if FTDI support is enabled via FTDI D2XX driver])
 AH_TEMPLATE([HAVE_LIBFTDI1],
             [Define if FTDI support is enabled via libftdi1])
 AH_TEMPLATE([HAVE_LIBFTDI],
@@ -177,6 +179,7 @@ AH_TEMPLATE([HAVE_LIBFTDI_TYPE_232H],
             [Define if libftdi supports FT232H, libftdi version >= 0.20])
 AC_CHECK_LIB([ftdi1], [ftdi_new], [have_libftdi1=yes], [], [$LIBUSB_1_0])
 AC_CHECK_LIB([ftdi], [ftdi_usb_get_strings], [have_libftdi=yes], [], [-lusb])
+AC_CHECK_LIB([ftd2xx], [FT_Open], [have_libftd2xx=yes], [], [])
 if test x$have_libftdi1 = xyes; then
    LIBFTDI1="-lftdi1"
    AC_DEFINE([HAVE_LIBFTDI1])
@@ -190,6 +193,10 @@ else
       if test x$have_libftdi_FT232H = xyes; then
          AC_DEFINE([HAVE_LIBFTDI_TYPE_232H])
       fi
+   else
+      LIBFTD2XX="-lftd2xx"
+      AC_DEFINE([HAVE_LIBFTD2XX])
+      AC_SUBST(LIBFTD2XX, $LIBFTD2XX)
    fi
 fi
 AC_CHECK_HEADERS([pthread.h])
@@ -534,6 +541,16 @@ else
    echo "DON'T HAVE libftdi"
 fi
 
+if test x$have_libftd2xx = xyes; then
+   if test x$have_libftdi1 = xyes -o x$have_libftdi = xyes; then
+       echo "DO HAVE    libftd2xx (but prefer to use libftdi/libftdi1)"
+   else
+       echo "DO HAVE    libftd2xx"
+   fi
+else
+   echo "DON'T HAVE libftd2xx"
+fi
+
 if test x$have_libhid = xyes; then
    echo "DO HAVE    libhid"
 else
diff --git a/ft245r.c b/ft245r.c
index a6106ab..6cfc3c7 100644
--- a/ft245r.c
+++ b/ft245r.c
@@ -87,7 +87,9 @@
 #elif defined(HAVE_LIBFTDI) && defined(HAVE_USB_H)
 /* ftdi.h includes usb.h */
 #include <ftdi.h>
-#else 
+#elif defined(HAVE_LIBFTD2XX)
+# include <ftd2xx.h>
+#else
 #warning No libftdi or libusb support. Install libftdi1/libusb-1.0 or libftdi/libusb and run configure/make again.
 #define DO_NOT_BUILD_FT245R
 #endif
@@ -108,6 +110,156 @@ void ft245r_initpgm(PROGRAMMER * pgm) {
 
 #else
 
+#ifdef HAVE_LIBFTD2XX
+
+/* Emulate libftdi interface using FTD2XX API.  */
+
+struct ftdi_context {
+  FT_HANDLE handle;
+  FT_STATUS last_error;
+};
+
+#define BITMODE_RESET	FT_BITMODE_RESET
+#define BITMODE_BITBANG	FT_BITMODE_ASYNC_BITBANG
+#define BITMODE_SYNCBB	FT_BITMODE_SYNC_BITBANG
+
+static int
+ftdi_read_data(struct ftdi_context *ftdi, const unsigned char *buf, int size)
+{
+  FT_STATUS status;
+  DWORD nread;
+
+  status = FT_Read(ftdi->handle, (void *) buf, size, &nread);
+  if (status != FT_OK) {
+    ftdi->last_error = status;
+    return -1;
+  }
+  return nread;
+}
+
+static int
+ftdi_write_data(struct ftdi_context *ftdi, const unsigned char *buf, int size)
+{
+  FT_STATUS status;
+  DWORD nwritten;
+
+  status = FT_Write(ftdi->handle, (void *) buf, size, &nwritten);
+  if (status != FT_OK) {
+    ftdi->last_error = status;
+    return -1;
+  }
+  if (nwritten != size) {
+    ftdi->last_error = FT_IO_ERROR;
+    return -1;
+  }
+  return nwritten;
+}
+
+static int
+ftdi_read_pins(struct ftdi_context *ftdi, unsigned char *pins)
+{
+  FT_STATUS status;
+
+  status = FT_GetBitMode(ftdi->handle, pins);
+  if (status != FT_OK) {
+    ftdi->last_error = status;
+    return -1;
+  }
+  return 0;
+}
+
+static int
+ftdi_set_baudrate(struct ftdi_context *ftdi, int baudrate)
+{
+  FT_STATUS status;
+
+  status = FT_SetBaudRate(ftdi->handle, 4*baudrate);
+  if (status != FT_OK) {
+    ftdi->last_error = status;
+    return -1;
+  }
+  return 0;
+}
+
+static int
+ftdi_set_bitmode(struct ftdi_context *ftdi, unsigned char bitmask,
+		 unsigned char mode)
+{
+  FT_STATUS status;
+
+  status = FT_SetBitMode(ftdi->handle, bitmask, mode);
+  if (status != FT_OK) {
+    ftdi->last_error = status;
+    return -1;
+  }
+  return 0;
+}
+
+static int
+ftdi_usb_close(struct ftdi_context *ftdi)
+{
+  FT_STATUS status;
+
+  status = FT_Close(ftdi->handle);
+  if (status != FT_OK) {
+    ftdi->last_error = status;
+    return -1;
+  }
+  return 0;
+}
+
+static void
+ftdi_deinit(struct ftdi_context *ftdi)
+{
+  return;
+}
+
+static const char *
+ftdi_get_error_string(struct ftdi_context *ftdi)
+{
+  switch (ftdi->last_error)
+    {
+    case FT_OK:			return "OK";
+    case FT_INVALID_HANDLE:	return "invalid handle";
+    case FT_DEVICE_NOT_FOUND:	return "device not found";
+    case FT_DEVICE_NOT_OPENED:	return "device not opened";
+    case FT_IO_ERROR:		return "I/O error";
+    case FT_INSUFFICIENT_RESOURCES: return "insufficient resources";
+    case FT_INVALID_PARAMETER:	return "invalid parameter";
+    case FT_INVALID_BAUD_RATE:	return "invalid baudrate";
+    case FT_DEVICE_NOT_OPENED_FOR_ERASE: return "device not opened for erase";
+    case FT_DEVICE_NOT_OPENED_FOR_WRITE: return "device not opened for write";
+    case FT_FAILED_TO_WRITE_DEVICE: return "failed to write device";
+    case FT_EEPROM_READ_FAILED:	return "EEPROM read failed";
+    case FT_EEPROM_WRITE_FAILED:return "EEPROM write failed";
+    case FT_EEPROM_ERASE_FAILED:return "EEPROM erase failed";
+    case FT_EEPROM_NOT_PRESENT:	return "EEPROM not present";
+    case FT_EEPROM_NOT_PROGRAMMED: return "EEPROM not programmed";
+    case FT_INVALID_ARGS:	return "invalid arguments";
+    case FT_NOT_SUPPORTED:	return "not supported";
+    case FT_OTHER_ERROR:	return "other error";
+    case FT_DEVICE_LIST_NOT_READY:
+      return "device list not ready";
+    default:
+      return "unknown error";
+    }
+}
+
+static int
+ftdi_set_latency_timer(struct ftdi_context *ftdi, unsigned char timeout)
+{
+    FT_STATUS status;
+
+    status = FT_SetLatencyTimer(ftdi->handle, timeout);
+    if (status != FT_OK) {
+	ftdi->last_error = status;
+	return -1;
+    }
+    return 0;
+}
+
+#endif /* !HAVE_LIBFTD2XX */
+
 #define FT245R_CYCLES	2
 #define FT245R_FRAGMENT_SIZE  512
 #define REQ_OUTSTANDINGS	10
@@ -824,6 +976,14 @@ static int ft245r_open(PROGRAMMER * pgm, char * port) {
     }
 
     handle = malloc (sizeof (struct ftdi_context));
+#ifdef HAVE_LIBFTD2XX
+    memset(handle, 0, sizeof(*handle));
+    if (FT_Open(devnum, &handle->handle) != FT_OK) {
+	avrdude_message(MSG_INFO, "%s: can't open FTDI device %d\n",
+			progname, devnum);
+	goto cleanup_no_usb;
+    }
+#else /* !HAVE_LIBFTD2XX */
     ftdi_init(handle);
     LNODEID usbpid = lfirst(pgm->usbpid);
     int pid;
@@ -845,6 +1005,7 @@ static int ft245r_open(PROGRAMMER * pgm, char * port) {
         avrdude_message(MSG_INFO, "can't open ftdi device %d. (%s)\n", devnum, ftdi_get_error_string(handle));
         goto cleanup_no_usb;
     }
+#endif /* !HAVE_LIBFTD2XX */
 
     ft245r_ddr = 
          pgm->pin[PIN_AVR_SCK].mask[0]
