diff -x .svn -Nur avrdude-r952/avrdude.1 avrdude/avrdude.1
--- avrdude-r952/avrdude.1	2011-02-25 17:30:08.000000000 -0700
+++ avrdude/avrdude.1	2011-02-28 14:40:34.000000000 -0700
@@ -148,11 +148,16 @@
 For ATxmega devices, the AVR Dragon is supported in PDI mode, provided it
 has a firmware version of at least 6.11 (decimal).
 .Pp
-The USBasp ISP and USBtinyISP adapters are also supported, provided
+The avrftdi, USBasp ISP and USBtinyISP adapters are also supported, provided
 .Nm avrdude
 has been compiled with libusb support.
-They both feature simple firmware-only USB implementations, running on
-an ATmega8 (or ATmega88), or ATtiny2313, respectively.
+USBasp ISP and USBtinyISP both feature simple firmware-only USB implementations, 
+running on an ATmega8 (or ATmega88), or ATtiny2313, respectively. If libftdi has 
+has been compiled in 
+.Nm avrdude
+The avrftdi device adds support for many programmers using FTDI's 2232C/D/H 
+and 4232H parts running in MPSSE mode, which hard-codes (in the chip) 
+SCK to bit 1, MOSI to bit 2, and MISO to bit 3. Reset is usually bit 4.
 .Pp
 Input files can be provided, and output files can be written in
 different file formats, such as raw binary files containing the data
@@ -1035,3 +1040,9 @@
 The USBasp and USBtinyISP drivers do not offer any option to distinguish multiple
 devices connected simultaneously, so effectively only a single device
 is supported.
+.Pp
+The avrftdi driver allows to select specific devices using any combination of vid,pid
+serial number (usbsn) vendor description (usbvendoror part description (usbproduct)
+as seen with lsusb or whatever tool used to view USB device information. Multiple 
+devices can be on the bus at the same time. For the H parts, which have multiple MPSSE
+interfaces, the interface can also be selected.  It defaults to interface 'A'.
diff -x .svn -Nur avrdude-r952/avrdude.conf.in avrdude/avrdude.conf.in
--- avrdude-r952/avrdude.conf.in	2011-02-25 17:30:08.000000000 -0700
+++ avrdude/avrdude.conf.in	2011-02-28 14:40:34.000000000 -0700
@@ -32,6 +32,14 @@
 #       rdyled   = <num> ;                          # pin number
 #       pgmled   = <num> ;                          # pin number
 #       vfyled   = <num> ;                          # pin number
+#  			usbvid   = <hexnum>;												# USB VID (Vendor ID)
+#       usbpid   = <hexnum>;												#	USB PID (Product ID)
+#       usbdev   = <interface>;											# USB interface or other device info 
+#       usbvendor = <vendorname>;										#	USB Vendor Name
+#       usbproduct = <productname>;									# USB Product Name
+#       usbsn    = <serialno>;                      # USB Serial Number
+#
+#        To invert a bit, use = ~ <num>, the spaces are important.
 #     ;
 #
 #   part
@@ -319,6 +327,73 @@
   desc  = "Arduino";
   type  = arduino;
 ;
+# this will interface with the chips on these programmers:
+#
+# http://real.kiev.ua/old/avreal/en/adapters
+# http://www.amontec.com/jtagkey.shtml, jtagkey-tiny.shtml
+# http://www.olimex.com/dev/arm-usb-ocd.html, arm-usb-tiny.html
+# http://www.ethernut.de/en/hardware/turtelizer/index.html
+# http://elk.informatik.fh-augsburg.de/hhweb/doc/openocd/usbjtag/usbjtag.html
+# http://dangerousprototypes.com/docs/FT2232_breakout_board
+# http://www.ftdichip.com/Products/Modules/DLPModules.htm,DLP-2232*,DLP-USB1232H
+# http://flashrom.org/FT2232SPI_Programmer
+# 
+# The drivers will look for a specific device and use the first one found.
+# If you have mulitple devices, then look for unique information (like SN)
+# And fill that in here.
+
+programmer
+  id	= "avrftdi";
+  desc	= "FT2232D based generic programmer";
+  type	= avrftdi;
+  usbvid     = 0x0403;
+  usbpid     = 0x6010;
+  usbvendor  = "";
+  usbproduct = "";
+  usbdev     = "A";
+  usbsn      = "";
+#ISP-signals - lower ACBUS-Nibble (default)
+  reset  = 4;
+  sck    = 1;
+  mosi   = 2;
+  miso   = 3;
+#LED SIGNALs - higher ACBUS-Nibble
+#  errled = 5;
+#  rdyled = 6;
+#  pgmled = 7;
+#  vfyled = 8;
+#Buffer Signal - ADBUS - Nibble
+#  buff   = 9;
+;
+# This is an implementation of the above with a buffer IC (74AC244) and
+# 4 LEDs directly attached, active low. The buff and reset pins are
+# understood (by avrdude) to be active low, so there's no
+# need to invert the bits.
+programmer
+  id	= "2232HIO";
+  desc	= "FT2232H based generic programmer";
+  type	= avrftdi;
+  usbvid     = 0x0403;
+# Note: This PID is reserved for generic H devices and 
+# should be programmed into the EEPROM
+#  usbpid     = 0x8A48;
+   usbpid    = 0x6010;
+  usbdev = "A";
+  usbvendor  = "";
+  usbproduct = "";
+  usbsn      = "";
+#ISP-signals 
+  reset  = 4;
+  sck    = 1;
+  mosi   = 2;
+  miso   = 3;
+  buff   = 5;
+#LED SIGNALs 
+  errled = ~ 12;
+  rdyled = ~ 15;
+  pgmled = ~ 14;
+  vfyled = ~ 13;
+;
 
 programmer
   id    = "avrisp";
diff -x .svn -Nur avrdude-r952/avrftdi.c avrdude/avrftdi.c
--- avrdude-r952/avrftdi.c	1969-12-31 17:00:00.000000000 -0700
+++ avrdude/avrftdi.c	2011-02-28 14:40:34.000000000 -0700
@@ -0,0 +1,992 @@
+/*
+ * avrftdi - extension for avrdude, Wolfgang Moser, Ville Voipio
+ * Copyright (C) 2011 Hannes Weisbach
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/* $Id$ */
+/*
+ * Interface to the MPSSE Engine of FTDI Chips using libftdi.
+ */
+#include "ac_cfg.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <stdint.h>
+
+#include "avrdude.h"
+#include "avr.h"
+#include "pgm.h"
+#include "avrftdi.h"
+
+#ifdef HAVE_LIBUSB
+#ifdef HAVE_LIBFTDI
+
+#include <ftdi.h>
+#include <usb.h>
+
+/* This is for running the code without having a FTDI-device.
+ * The generated code is useless! For debugging purposes only.
+ * This should never be defined, unless you know what you are
+ * doing.
+ * If you think you know what you are doing: YOU DONT!
+ */
+//#define DRYRUN
+
+static struct ftdi_context ftdic;
+static uint16_t pin_value, pin_direction, pin_inversion, led_mask;
+static int type; /**type is  bcdDevice. C/D is 0x500 H is 0x700 4H is 0x800*/
+static int ftype; /** is from FTDI. Use TYPE_2232C, TYPE_2232H, or TYPE_4232H*/
+
+static void buf_dump(unsigned char *buf, int len, char *desc, int offset, int width)
+{
+	int i;
+	fprintf(stderr, "%s begin:\n", desc);
+	for (i = 0; i < offset; i++)
+		fprintf(stderr, "%02x ", buf[i]);
+	fprintf(stderr, "\n");
+	for (i++; i <= len; i++) {
+		fprintf(stderr, "%02x ", buf[i-1]);
+		if((i-offset) != 0 && (i-offset)%width == 0) fprintf(stderr, "\n");
+	}
+	fprintf(stderr, "%s end\n", desc);
+}
+
+/* we use this to sync with the ftdi or flush the data path to the ftdi
+ * (USB stack, caches in USB hubs, instruction cache in the ftdi).
+ * This code is based on the assumption the ftdi_read call will return
+ * iff the instruction has been processed by the FTDI and therefore all
+ * other instructions before that. As sync/flush instruction we read the
+ * state of the lower GPIO pins and flush the data back immediately.
+ * This cannot be used, if there is outstanding data, because it will
+ * eat one byte.
+ * XXX: This is new and might very well be a buggy.
+ */
+static int avrftdi_flush(void)
+{
+	/* 0x81: read i/p low byte
+	 * 0x87: flush data back immediately
+	 */
+	unsigned char buf[] = { 0x81, 0x87 };
+
+#ifndef DRYRUN
+	E(ftdi_write_data(&ftdic, buf, sizeof(buf)) != sizeof(buf));
+	/* the read command we use for sync/flush gives us back one byte;
+	 * we need to read it.
+	 */
+	E(ftdi_read_data(&ftdic, buf, 1) != 1);
+#endif
+	return 0;
+}
+
+static int set_frequency(uint32_t freq)
+{
+	uint32_t divisor;
+	uint8_t buf[3];
+
+	/* divisor on 6000000 / freq - 1 */
+	divisor = (6000000 / freq) - 1;
+	if (divisor < 0) {
+		fprintf(stderr, "%s failure: Frequency too high (%u > 6 MHz)\n", progname, freq);
+		fprintf(stderr, "resetting Frequency to 6MHz\n");
+		divisor = 0;
+	}
+
+	if (divisor > 65535) {
+		fprintf(stderr, "%s failure: Frequency too low (%u < 91.553 Hz)\n", progname, freq);
+		fprintf(stderr, "resetting Frequency to 91.553Hz\n");
+		divisor = 65535;
+	}
+
+	if(verbose)
+		fprintf(stderr, "%s info: clock divisor: 0x%04x\n", progname, divisor);
+
+	buf[0] = 0x86;
+	buf[1] = (uint8_t)(divisor & 0xff);
+	buf[2] = (uint8_t)((divisor >> 8) & 0xff);
+
+#ifndef DRYRUN
+	E(ftdi_write_data(&ftdic, buf, 3) < 0);
+#endif
+
+	return 0;
+}
+
+/*   Add a single pin (by pin number) to the pin masks (or to pins), update pinmask[pinfunc]   */
+static int add_pin(PROGRAMMER *pgm, int pinfunc)
+{
+	int pin, inversion_mask, mlim;
+	
+	pin = pgm->pinno[pinfunc];
+	if (verbose)
+		fprintf(stderr, "add_pin: %d: bit 0x%04x inv=0x%04x\n", pinfunc,pin,(pin&PIN_INVERSE)?(1<<((pin&PIN_MASK)-1)):0);
+
+	/* non-existent definitions, go away */
+	if (pin == 0)
+		return 0;
+	
+	/* see if pin should be inverted */
+	if(pin & PIN_INVERSE) {
+		pin &= PIN_MASK;
+		inversion_mask = 1 << (pin - 1);
+	} else {
+		inversion_mask = 0;
+	}
+	if(TYPE_4232H == ftype)
+		mlim=7;
+	else if(TYPE_2232C==ftype)
+		mlim=11;
+	else if(TYPE_2232H == ftype)
+		mlim=15;
+	else{
+		printf("Unknown type %d (0x%x)\n",ftype,ftype);
+		mlim=15;
+	}
+	/* check that the pin number is in range */
+	if (pin > mlim) {
+		fprintf(stderr, "%s failure: invalid pin definition (pin no > %d) in config file\n", progname,mlim);
+		fprintf(stderr, "pin function no %d, pin no: 0x%x\n", pinfunc, pin);
+		return -1;
+	}
+
+	/* create the mask and check that the pin is available */
+	if (pin_direction & (1 << (pin -1)) ) {
+		fprintf(stderr, "%s failure: pin %d has two definitions in config file\n", progname, pin);
+		return -1;
+	} else {
+		pin_direction |= (1 << (pin - 1));
+		pin_inversion |= inversion_mask; 
+	}
+	if(PIN_LED_ERR==pinfunc||PIN_LED_VFY==pinfunc||PIN_LED_RDY==pinfunc||PIN_LED_PGM==pinfunc){
+		led_mask|=(1 << (pin - 1));
+	}
+		
+	return 0;
+}
+
+/*   Add pins by pin mask    */
+
+static int add_pins(PROGRAMMER *pgm, int pinfunc)
+{									
+	int i,pin,mlim;
+	uint32_t mask, inversion_mask=0;
+  pin = pgm->pinno[pinfunc];
+	
+	if(pin & PIN_INVERSE){
+		pin	&= PIN_MASK;
+		inversion_mask = pin >>1;
+	}
+	pin >>=1;
+	if (verbose)
+		fprintf(stderr, "add_pins: %d: 0x%04x, inv=0x%04x\n", pinfunc, pin,inversion_mask);
+	mask = pin;
+	if(TYPE_4232H == ftype)
+		mlim=8;
+	else if(TYPE_2232C==ftype)
+		mlim=12;
+	else if(TYPE_2232H == ftype)
+		mlim=16;
+	else{
+		printf("Unknown type %d (0x%x)\n",ftype,ftype);
+		mlim=16;
+	}
+	if (mask >= 1 << mlim) {
+		fprintf(stderr, "%s failure: pin list has pins out of range (%x>%x): ", progname,mask,1<<mlim);
+		mask &= ~(1 << mlim) - 1;
+	}
+	else if (mask & pin_direction) {
+		fprintf(stderr, "%s failure: conflicting pins in pin list: ", progname);
+		mask &= pin_direction;
+	}
+	else {
+		pin_direction |= (uint16_t)mask;
+		pin_inversion |= inversion_mask;
+		return 0;
+	}
+
+	/* print the list of pins, if needed */
+	i = 0;
+	while (mask > 1) {
+		if (mask & 1)
+			fprintf(stderr, "%d, ", i);
+		mask >>= 1;
+		i++;
+	}
+	if (mask > 0)
+		fprintf(stderr, "%d\n", i); 
+	return -1;
+}
+
+
+static int write_flush(  void )
+{
+	unsigned char buf[6];
+	if(verbose > 2)
+		fprintf(stderr, "%s info: direction: 0x%04x, value: 0x%04x, inversion: 0x%04x\n", progname, pin_direction, pin_value, pin_inversion);
+
+	buf[0] = 0x80;
+	buf[1] = pin_value & 0xff;
+	buf[2] = pin_direction & 0xff;
+	buf[3] = 0x82;
+	buf[4] = (pin_value >> 8) & 0xff;
+	buf[5] = (pin_direction >> 8) & 0xff;
+
+#ifndef DRYRUN
+	E(ftdi_write_data(&ftdic, buf, 6) != 6);
+
+#endif
+
+	if (verbose > 3)
+		printf("FTDI LOG: %02x %02x %02x %02x %02x %02x\n", buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]);
+
+	/* we need to flush here, because set_pin is used as reset.
+	 * if we want to sleep reset periods, we must be certain the
+	 * avr has got the reset signal when we start sleeping.
+	 * (it may be stuck in the USB stack or some USB hub)
+	 */
+	avrftdi_flush();
+
+	return 0;
+	
+}
+/* this function sets or clears a GPIO pin */
+static int set_pin(int pin, int value)
+{
+	int bit;
+	uint16_t tval;
+	if(0 == pin){
+		if(verbose>2)
+			fprintf(stderr,"%s info: Pin is zero val %d!\n",progname,value);
+		return 1;
+	}
+	--pin;
+	bit= 1 << (pin);
+	if(pin_inversion & bit) {
+		value = !value;
+	}
+	if(value)
+		value=bit;
+	
+	if(verbose>1)
+		fprintf(stderr, "%s info: pin %04x bit %04x value 0x%04x\n",progname,pin+1,bit,value );
+	/* set bits depending on value */
+	/*pin_value ^= (-value ^ pin_value) & (1 << (pin - 1));  */
+	tval=(pin_value&(~bit))|value;
+	if(tval != pin_value){
+		pin_value=tval;
+		return write_flush();
+	}else if(verbose>1) fprintf(stderr,"SameVal\n");
+	return 0;
+
+}
+/* this function sets or clears one or more GPIO pin these are bit-mapped */
+static int set_pins(int pin, int value)
+{
+	if(0 == pin){
+		if(verbose>2)
+			fprintf(stderr,"%s info: Pins is zero!\n",progname);
+		return 1;
+	}
+	pin >>=1;
+	if(pin_inversion & pin) {
+		value = !value;
+	}
+	if(value)
+		value=pin;
+	
+	if(verbose)
+		fprintf(stderr, "%s info: pin %04x value %d\n",progname,pin,value );
+	/* set bits depending on value */
+	/*pin_value ^= (-value ^ pin_value) & (1 << (pin - 1));  */
+	pin_value=(pin_value&(~pin))|value;
+	return write_flush();
+}
+/* these functions are callbacks, which go into the
+ * PROGRAMMER data structure ("optional functions")
+ */
+static int set_led_pgm(struct programmer_t * pgm, int value)
+{
+	return set_pin(pgm->pinno[PIN_LED_PGM], value);
+}
+
+static int set_led_rdy(struct programmer_t * pgm, int value)
+{
+	return set_pin(pgm->pinno[PIN_LED_RDY], value);
+}
+
+static int set_led_err(struct programmer_t * pgm, int value)
+{
+	return set_pin(pgm->pinno[PIN_LED_ERR], value);
+}
+
+static int set_led_vfy(struct programmer_t * pgm, int value)
+{
+	return set_pin(pgm->pinno[PIN_LED_VFY], value);
+}
+
+static int avrftdi_transmit(unsigned char mode, unsigned char *cmd, unsigned char *data, int buf_size)
+{
+	int k = 0;
+	int n;
+	unsigned char buf[4 + buf_size];
+
+	if (mode & TX) {
+		buf[0] = mode;
+		buf[1] = ((buf_size - 1) & 0xff);
+		buf[2] = (((buf_size - 1) >> 8) & 0xff);
+
+		memcpy(buf + 3, cmd, buf_size);
+		buf[buf_size + 3] = 0x87;
+
+#ifndef DRYRUN	
+		E(ftdi_write_data(&ftdic, buf, buf_size + 4) != buf_size + 4);
+#endif
+	}
+	
+	if (mode & RX) {
+		memset(buf, 0, sizeof(buf));
+		do {
+#ifndef DRYRUN
+			n = ftdi_read_data(&ftdic, buf + k, buf_size - k);
+			E(n < 0);
+#else
+			n = buf_size - k;
+#endif
+			k += n;
+		} while (k < buf_size);
+		
+		memcpy(data, buf, buf_size);
+	}
+
+	return k;
+}
+
+static int avrftdi_open(PROGRAMMER * pgm, char *port)
+{
+	int vid, pid, interface, snfound;
+	char serial[255], *foundsn;
+	struct ftdi_device_list* devlist;
+	struct ftdi_device_list* devlist_ptr;
+	struct usb_device *found_dev;
+	/* use vid/pid in following priority: config, defaults. cmd-line is currently not supported */
+	type=0;
+	snfound=0;
+	foundsn=NULL;
+	
+	if(pgm->usbvid)
+		vid = pgm->usbvid;
+	else
+		vid = 0x0403;
+
+	if(pgm->usbpid)
+		pid = pgm->usbpid;
+	else
+		pid = 0x6010;
+	
+	if(0 == pgm->usbsn[0])/**we don't care about SN. Use first avail.  */
+		snfound=1;
+	
+	if(!strcmp(pgm->usbdev,"A") || !strcmp(pgm->usbdev,"a"))
+		interface=INTERFACE_A;
+	else if(!strcmp(pgm->usbdev,"B") || !strcmp(pgm->usbdev,"b"))
+		interface=INTERFACE_B;
+	else {
+		fprintf(stderr,"%s: Invalid interface '%s'. Setting to Interface A\n",
+		progname,pgm->usbdev);
+		interface=INTERFACE_A;
+	}
+#ifndef DRYRUN
+	E(ftdi_init(&ftdic) < 0);
+	found_dev=NULL;
+	if(ftdi_usb_find_all(&ftdic, &devlist, vid, pid)) {
+		devlist_ptr = devlist;
+		do {
+			ftdi_usb_get_strings(&ftdic, devlist_ptr->dev, NULL, 0, NULL, 0, serial, 255);
+			
+			if(verbose)
+				fprintf(stderr, "%s: device: %s, serial number: %s type 0x%04x found\n", 
+			  progname,devlist_ptr->dev->filename, serial, devlist_ptr->dev->descriptor.bcdDevice);
+			  
+			if(!snfound){
+				if(!strcmp(pgm->usbsn, serial)){
+					foundsn=strdup(serial);
+					snfound=1;
+					found_dev=devlist_ptr->dev;
+					type=devlist_ptr->dev->descriptor.bcdDevice;
+				}
+			}else {
+				if(0 == type)	/**we assume it will attach to first found.  */
+					type=devlist_ptr->dev->descriptor.bcdDevice;
+				if(NULL == found_dev)
+					found_dev=devlist_ptr->dev;
+				if(NULL == foundsn)
+					foundsn=strdup(serial);
+			}
+			memset(serial, 0, 255);
+			devlist_ptr = devlist_ptr->next;
+		} while (devlist_ptr);
+	} else {
+		fprintf(stderr, "%s: No devices with Vendor-ID:Product-ID %04x:%04x found.\n", progname, vid, pid);
+		ftdi_list_free(&devlist);
+		return -1;
+	}
+	if(!snfound){
+		fprintf(stderr,"%s: No devices with VID:PID %04x:%04x and SN '%s' found.\n",
+			progname, vid, pid,pgm->usbsn);
+		ftdi_list_free(&devlist);
+		return -1;
+	}
+	if(verbose)
+		fprintf(stderr,"%s: Using device VID:PID %04x:%04x type 0x%04x and SN '%s'.\n",
+			progname, vid, pid,type, foundsn);
+	if(type == TYPE_C_D && INTERFACE_B==interface){
+		fprintf(stderr, "%s: Type C/D found. Setting interface to A\n", progname);
+		interface=INTERFACE_A;
+	}
+	/*must be A for mpsse if C/D, can be A/B for H */
+	if(verbose)
+		fprintf(stderr, "%s: Using USB Interface %c\n", progname,INTERFACE_A==interface?'A':'B');
+	free(foundsn);
+	E(ftdi_set_interface(&ftdic, interface) < 0);		
+	E(ftdi_usb_open_dev(&ftdic,found_dev) <0);
+/*	E(ftdi_usb_open_desc(&ftdic, vid,pid,NULL,0==pgm->usbsn[0]?NULL:pgm->usbsn) < 0);  */
+	ftype=ftdic.type;
+	E(ftdi_set_bitmode(&ftdic, pin_direction & 0xff, BITMODE_MPSSE) < 0);	/*set SPI */
+#endif
+	
+	
+	if (SCK != (1 << (pgm->pinno[PIN_AVR_SCK] - 1))
+		|| SDO != (1 << (pgm->pinno[PIN_AVR_MOSI] - 1))
+		|| SDI != (1 << (pgm->pinno[PIN_AVR_MISO] - 1))) {
+		fprintf(stderr, "%s failure: pinning for FTDI MPSSE must be:\n"
+			"\tSCK: 1, SDO: 2, SDI: 3(is: %d,%d,%d)\n",
+			progname,
+			pgm->pinno[PIN_AVR_SCK],
+			pgm->pinno[PIN_AVR_MOSI],
+			pgm->pinno[PIN_AVR_MISO]);
+		fprintf(stderr, "Setting pins accordingly ...\n");
+			pgm->pinno[PIN_AVR_SCK] = 1;
+			pgm->pinno[PIN_AVR_MOSI] = 2;
+			pgm->pinno[PIN_AVR_MISO] = 3;
+		
+	}
+	if(verbose)
+		fprintf(stderr, "%s info: reset pin value: %x\n", progname, pgm->pinno[PIN_AVR_RESET]-1);
+	if (pgm->pinno[PIN_AVR_RESET] < 4 || pgm->pinno[PIN_AVR_RESET] == 0) {
+		fprintf(stderr, "%s failure: RESET pin clashes with data pin or is not set.\n",
+			progname);
+		fprintf(stderr, "Setting to default-value 4\n");
+		pgm->pinno[PIN_AVR_RESET] = 4;
+	}
+	/**sync our internal state with the chip  */
+	pin_direction=0;
+	pin_value=0;
+	write_flush();
+	pin_direction = (0x3 | (1 << (pgm->pinno[PIN_AVR_RESET] - 1)));
+
+	/* gather the rest of the pins */
+	if (add_pins(pgm, PPI_AVR_VCC)) return -1;
+	if (add_pins(pgm, PPI_AVR_BUFF)) return -1;
+	if (add_pin(pgm, PIN_LED_ERR)) return -1;
+	if (add_pin(pgm, PIN_LED_RDY)) return -1;
+	if (add_pin(pgm, PIN_LED_PGM)) return -1;
+	if (add_pin(pgm, PIN_LED_VFY)) return -1;
+	
+	if (verbose > 1) {
+		fprintf(stderr, "pin direction mask: %04x\n", pin_direction);
+		fprintf(stderr, "pin value mask: %04x\n", pin_value);
+	}
+
+	if(pgm->baudrate) {
+		set_frequency(pgm->baudrate);
+	} else if(pgm->bitclock) {
+		set_frequency((uint32_t)(1.0f/pgm->bitclock));
+	} else {
+		set_frequency(pgm->baudrate ? pgm->baudrate : 150000);
+	}
+	/**set the ready LED, if we have one .. and set our direction up */
+  set_led_rdy(pgm,0);
+	set_led_rdy(pgm,1);
+	return 0;
+}
+
+static void avrftdi_close(PROGRAMMER * pgm)
+{
+	if(ftdic.usb_dev) {
+		set_pins(pgm->pinno[PPI_AVR_BUFF], ON);
+		set_pin(pgm->pinno[PIN_AVR_RESET], ON);
+		/**Stop driving the pins - except for the LEDs */
+		if (verbose > 1)
+			fprintf(stderr,"LED Mask=0x%04x value =0x%04x &=0x%04x\n",led_mask,pin_value,led_mask&pin_value);
+		pin_direction=led_mask;
+		pin_value&=led_mask;
+		write_flush();
+#ifndef DRYRUN
+		E_VOID(ftdi_usb_close(&ftdic));
+#endif
+	}
+	
+#ifndef DRYRUN
+	ftdi_deinit(&ftdic);
+#endif
+
+	return;
+}
+
+
+static int avrftdi_initialize(PROGRAMMER * pgm, AVRPART * p)
+{
+	set_pin(pgm->pinno[PIN_AVR_RESET], OFF);
+	set_pins(pgm->pinno[PPI_AVR_BUFF], OFF);
+	set_pin(pgm->pinno[PIN_AVR_SCK], OFF);
+	/*use speed optimization with CAUTION*/
+	usleep(20 * 1000);
+
+	/*giving rst-pulse of at least 2 avr-clock-cycles, for security (2us @ 1MHz) */
+	set_pin(pgm->pinno[PIN_AVR_RESET], ON);
+	usleep(20 * 1000);
+
+	/*setting rst back to 0 */
+	set_pin(pgm->pinno[PIN_AVR_RESET], OFF);
+	/*wait at least 20ms bevor issuing spi commands to avr */
+	usleep(20 * 1000);
+
+	return pgm->program_enable(pgm, p);
+}
+
+static void avrftdi_disable(PROGRAMMER * pgm)
+{
+	return;
+}
+
+static void avrftdi_enable(PROGRAMMER * pgm)
+{
+	return;
+}
+
+static void avrftdi_display(PROGRAMMER * pgm, const char *p)
+{
+	return;
+}
+
+
+static int avrftdi_cmd(PROGRAMMER * pgm, unsigned char cmd[4], unsigned char res[4])
+{
+	return avrftdi_transmit(TRX, cmd, res, sizeof(cmd));
+}
+
+
+static int avrftdi_program_enable(PROGRAMMER * pgm, AVRPART * p)
+{
+	int i;
+	unsigned char buf[4];
+
+	memset(buf, 0, sizeof(buf));
+
+	if (p->op[AVR_OP_PGM_ENABLE] == NULL) {
+		fprintf(stderr, "%s failure: Program Enable (PGM_ENABLE) command not defined for %s\n", progname, p->desc);
+		return -1;
+	}
+	
+	avr_set_bits(p->op[AVR_OP_PGM_ENABLE], buf);
+
+	for(i = 0; i < 4; i++) {
+		pgm->cmd(pgm, buf, buf);
+		if(buf[p->pollindex-1] != p->pollvalue) {
+			//try resetting
+			set_pin(pgm->pinno[PIN_AVR_RESET], ON);
+			usleep(20);
+			set_pin(pgm->pinno[PIN_AVR_RESET], OFF);
+			avr_set_bits(p->op[AVR_OP_PGM_ENABLE], buf);
+		} else
+			return 0;
+	}
+#ifndef DRYRUN	
+	return -1;
+#else
+	return 0;
+#endif
+}
+
+
+static int avrftdi_chip_erase(PROGRAMMER * pgm, AVRPART * p)
+{
+	unsigned char cmd[4];
+	unsigned char res[4];
+
+	if (p->op[AVR_OP_CHIP_ERASE] == NULL) {
+		fprintf(stderr, "%s failure Chip Erase (CHIP_ERASE) command not defined for %s\n", progname, p->desc);
+		return -1;
+	}
+
+	memset(cmd, 0, sizeof(cmd));
+
+	avr_set_bits(p->op[AVR_OP_CHIP_ERASE], cmd);
+	pgm->cmd(pgm, cmd, res);
+	usleep(p->chip_erase_delay);
+	pgm->initialize(pgm, p);
+
+	return 0;
+}
+
+
+/* Load extended address byte command */
+static int avrftdi_lext(PROGRAMMER *pgm, AVRPART *p, AVRMEM *m, int address)
+{
+	unsigned char buf[] = {0x11, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+	avr_set_bits(m->op[AVR_OP_LOAD_EXT_ADDR], &buf[3]);
+	avr_set_addr(m->op[AVR_OP_LOAD_EXT_ADDR], &buf[3], address);
+
+	if(verbose > 1) 
+		buf_dump(buf, sizeof(buf), "load extended address command", 0, 16*3);
+
+#ifndef DRYRUN
+	E(ftdi_write_data(&ftdic, buf, sizeof(buf)) != sizeof(buf));
+#endif
+	return 0;
+}
+
+static int avrftdi_eeprom_write(PROGRAMMER *pgm, AVRPART *p, AVRMEM *m, int page_size, int len)
+{
+	unsigned char cmd[4];
+	unsigned char *data = m->buf;
+	int add;
+	
+	avr_set_bits(m->op[AVR_OP_WRITE], cmd);
+	
+	for(add = 0; add < len; add++)
+	{
+		avr_set_addr(m->op[AVR_OP_WRITE], cmd, add);
+		avr_set_input(m->op[AVR_OP_WRITE], cmd, *data++);
+		
+		E(avrftdi_transmit(TX, cmd, cmd, 4) < 0);
+		
+		usleep((m->max_write_delay));
+		if(verbose < 3)
+			report_progress(add, len, NULL);
+	}
+	return len;
+}
+
+static int avrftdi_eeprom_read(PROGRAMMER *pgm, AVRPART *p, AVRMEM *m, int page_size, int len)
+{
+	unsigned char cmd[4];
+	unsigned char buffer[len], *bufptr = buffer;
+
+	int add;
+	
+	memset(buffer, 0, sizeof(buffer));
+	
+	for(add = 0; add < len; add++)
+	{
+		avr_set_bits(m->op[AVR_OP_READ], cmd);
+		avr_set_addr(m->op[AVR_OP_READ], cmd, add);
+
+		E(avrftdi_transmit(TRX, cmd, cmd, 4) < 0);
+		
+		avr_get_output(m->op[AVR_OP_READ], cmd, bufptr++);
+		if(verbose < 3)
+			report_progress(add, len, NULL);
+	}
+
+	memcpy(m->buf, buffer, len);
+	return len;
+}
+
+static int avrftdi_flash_write(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m, int page_size, int len)
+{
+	int i;
+	int address = 0, buf_size;
+	int bytes = len;
+	int blocksize;
+	int use_lext_address = m->op[AVR_OP_LOAD_EXT_ADDR] != NULL;
+	unsigned char *buf, *bufptr;
+	unsigned char *buffer = m->buf;
+	unsigned char byte;
+
+
+	buf = (unsigned char*) malloc(4 * len + 4);
+	if(buf == NULL) {
+		fprintf(stderr, "%s (%s): error %d allocating memory: %s\n", p->desc, __FUNCTION__, errno, strerror(errno));
+		exit(-1);
+	}
+
+	bufptr = buf;
+
+	/* pre-check opcodes */
+	if (m->op[AVR_OP_LOADPAGE_LO] == NULL) {
+		fprintf(stderr, "%s failure: %s command not defined for %s\n", progname, "AVR_OP_LOADPAGE_LO", p->desc);
+		return -1;
+	}
+	if (m->op[AVR_OP_LOADPAGE_HI] == NULL) {
+		fprintf(stderr, "%s failure: %s command not defined for %s\n", progname, "AVR_OP_LOADPAGE_HI", p->desc);
+		return -1;
+	}
+
+	//page_size = (page_size > m->page_size) ? m->page_size : page_size - 8;
+	page_size = m->page_size;
+
+	while (bytes) {
+		if (bytes > page_size) {
+			blocksize = (page_size)/2;
+			bytes -= (page_size);
+		} else {
+			blocksize = bytes/2;
+			bytes = 0;
+		}
+
+		if(verbose > 2)
+			fprintf(stderr, "-< bytes = %d of %d, blocksize = %d of %d\n", len - bytes, len, blocksize, m->page_size/2);
+
+		/* if we do cross a 64k word boundary (or write the first page), we need to issue
+		 * a 'load extended address byte' command, which is defined as
+		 * 0x4d 0x00 <address byte> 0x00.
+		 * As far as i know, this is only available on 256k parts.
+		 * 64k word is 128k bytes.
+		 */
+		if(use_lext_address && !(bytes & 0x1ffff)) {
+			avrftdi_lext(pgm, p, m, address);
+		}
+
+		for (i = 0; i < blocksize; i++) {
+			/*setting word*/
+			avr_set_bits(m->op[AVR_OP_LOADPAGE_LO], bufptr);
+			avr_set_addr(m->op[AVR_OP_LOADPAGE_LO], bufptr, address);
+			avr_set_input(m->op[AVR_OP_LOADPAGE_LO], bufptr, *buffer++);
+			bufptr += 4;		
+			avr_set_bits(m->op[AVR_OP_LOADPAGE_HI], bufptr);
+			avr_set_addr(m->op[AVR_OP_LOADPAGE_HI], bufptr, address);
+			avr_set_input(m->op[AVR_OP_LOADPAGE_HI], bufptr, *buffer++);
+			bufptr += 4;
+			address++;
+		}
+
+		if(verbose > 2)
+			fprintf(stderr, "address = %d, page_size = %d\n", address, m->page_size);
+	
+		if((!((address * 2) % m->page_size) || !bytes)) {
+			if(m->op[AVR_OP_WRITEPAGE] == NULL) {
+				fprintf(stderr, "%s failure: Write Page (WRITEPAGE) command not defined for %s\n", progname, p->desc);
+				exit(1);
+			} else {
+				avr_set_bits(m->op[AVR_OP_WRITEPAGE], bufptr);
+			}
+			/*setting page address highbyte*/
+			avr_set_addr(m->op[AVR_OP_WRITEPAGE], bufptr, address - 1);
+			bufptr += 4;
+		}
+			
+		buf_size = bufptr - buf;
+			
+		if(verbose > 3)
+			buf_dump(buf, buf_size, "command buffer", 0, 16*3);
+		if(verbose > 2)	
+			fprintf(stderr, "%s info: buffer size: %d\n", progname, buf_size);
+
+		E(avrftdi_transmit(TX, buf, buf, buf_size) < 0);
+			
+		bufptr = buf;
+		if ((!((address * 2) % m->page_size) || !bytes)) {
+			do {
+				pgm->read_byte(pgm, p, m, (address * 2) -1, &byte);
+			} while(m->buf[(address*2) - 1] != byte);
+		}
+			
+		if(verbose < 3)
+			report_progress(2*address, len, NULL);
+	}
+	return len;
+}
+
+static int avrftdi_flash_read(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m, int page_size, int len)
+{
+	/*
+	 *Reading from flash
+	 */
+	int use_lext_address = m->op[AVR_OP_LOAD_EXT_ADDR] != NULL;
+	int i, buf_index, buf_size = 0, psize = m->page_size;
+	unsigned char o_buf[4*len+4], *o_ptr = o_buf;
+	unsigned char i_buf[4*len+4];
+	int address = 0;
+	int bytes = len;
+	int blocksize;
+	unsigned char buffer[m->size], *bufptr = buffer;
+	
+	memset(o_buf, 0, sizeof(o_buf));
+	memset(i_buf, 0, sizeof(i_buf));
+	memset(buffer, 0, sizeof(buffer));
+	
+	/* pre-check opcodes */
+	if (m->op[AVR_OP_READ_LO] == NULL) {
+		fprintf(stderr, "%s failure: %s command not defined for %s\n", progname, "AVR_OP_READ_LO", p->desc);
+		return -1;
+	}
+	if (m->op[AVR_OP_READ_HI] == NULL) {
+		fprintf(stderr, "%s failure: %s command not defined for %s\n", progname, "AVR_OP_READ_HI", p->desc);
+		return -1;
+	}
+
+	while (bytes) {
+		if (bytes > psize) {
+			blocksize = psize/2;
+			bytes -= psize;
+		} else {
+			blocksize = bytes/2;
+			bytes = 0;
+		}
+	
+		if(use_lext_address && !(bytes & 0x1ffff)) {
+			avrftdi_lext(pgm, p, m, address);
+		}
+
+		for(i = 0; i < blocksize; i++) {
+			if(verbose > 3)
+				fprintf(stderr, "bufsize: %d, i: %d, add: %d\n", buf_size, i, address);
+			avr_set_bits(m->op[AVR_OP_READ_LO], o_ptr);
+			avr_set_addr(m->op[AVR_OP_READ_LO], o_ptr, address);
+			o_ptr += 4;
+			avr_set_bits(m->op[AVR_OP_READ_HI], o_ptr);
+			avr_set_addr(m->op[AVR_OP_READ_HI], o_ptr, address);
+			o_ptr += 4;
+			
+			address++;
+
+			//FIXME: why not program on per-page basis?
+			//maybe this covered a timing error in an earlier version?
+			buf_size = o_ptr - o_buf;
+			
+			if((buf_size >= (page_size - 8)) || ( i == blocksize-1)) {
+				E(avrftdi_transmit(TRX, o_buf, i_buf, buf_size) < 0);
+
+				for(buf_index = 0; buf_index < buf_size; buf_index+=8) {
+					avr_get_output(m->op[AVR_OP_READ_LO], i_buf+buf_index, bufptr++);
+					avr_get_output(m->op[AVR_OP_READ_HI], i_buf+buf_index+4, bufptr++);
+				}
+
+				if(verbose > 3) {
+					buf_dump(i_buf, buf_size, "i_buf", 0, 16);
+					//buf_dump(m->buf, 640, "vfy buf", 0, 16);
+				}
+				o_ptr = o_buf;
+			}
+		}
+		if(verbose < 3)
+			report_progress(2*address, len, NULL);
+	}
+	memcpy(m->buf, buffer, sizeof(buffer));
+	
+	return len;
+}
+
+static int avrftdi_paged_write(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m, int page_size, int n_bytes)
+{
+	if(strcmp(m->desc, "flash") == 0)
+		return avrftdi_flash_write(pgm, p, m, page_size, n_bytes);
+	else if (strcmp(m->desc, "eeprom") == 0)
+		return avrftdi_eeprom_write(pgm, p, m, page_size, n_bytes);
+	else
+		return -2;
+}
+
+static int avrftdi_paged_load(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m, int page_size, int n_bytes)
+{
+	if(strcmp(m->desc, "flash") == 0) 
+		return avrftdi_flash_read(pgm, p, m, page_size, n_bytes);
+	else if(strcmp(m->desc, "eeprom") == 0)
+		return avrftdi_eeprom_read(pgm, p, m, page_size, n_bytes);
+	else
+		return -2;
+}
+
+void avrftdi_initpgm(PROGRAMMER * pgm)
+{
+	strcpy(pgm->type, "avrftdi");
+
+	pin_value=pin_direction=pin_inversion=led_mask=0;
+	/*
+	 * mandatory functions
+	 */
+
+	pgm->initialize = avrftdi_initialize;
+	pgm->display = avrftdi_display;
+	pgm->enable = avrftdi_enable;
+	pgm->disable = avrftdi_disable;
+	pgm->program_enable = avrftdi_program_enable;
+	pgm->chip_erase = avrftdi_chip_erase;
+	pgm->cmd = avrftdi_cmd;
+	pgm->open = avrftdi_open;
+	pgm->close = avrftdi_close;
+	pgm->read_byte = avr_read_byte_default;
+	pgm->write_byte = avr_write_byte_default;
+
+	/*
+	 * optional functions
+	 */
+
+	pgm->paged_write = avrftdi_paged_write;
+	pgm->paged_load = avrftdi_paged_load;
+	
+	pgm->rdy_led = set_led_rdy;
+	pgm->err_led = set_led_err;
+	pgm->pgm_led = set_led_pgm;
+	pgm->vfy_led = set_led_vfy;
+
+	
+}
+
+#else /*HAVE_LIBFTDI*/
+
+static int avrftdi_noftdi_open (struct programmer_t *pgm, char * name)
+{
+	fprintf(stderr, "%s: error: no libftdi support. please compile again with libftdi installed.\n",
+	  progname);
+
+	exit(1);
+}
+
+void avrftdi_initpgm(PROGRAMMER * pgm)
+{
+	strcpy(pgm->type, "avrftdi");
+	pgm->open = avrftdi_noftdi_open;
+}
+
+#endif  /* HAVE_LIBFTDI */
+
+#else /*HAVE_LIBUSB*/
+
+static int avrftdi_nousb_open (struct programmer_t *pgm, char * name)
+{
+	fprintf(stderr, "%s: error: no usb support. please compile again with libsusb installed.\n",
+	  progname);
+	
+	exit(1);
+}
+
+void avrftdi_initpgm(PROGRAMMER * pgm)
+{
+	strcpy(pgm->type, "avrftdi");
+	pgm->open = avrftdi_nousb_open;
+}
+
+#endif /*HAVE_LIBUSB*/
+
diff -x .svn -Nur avrdude-r952/avrftdi.h avrdude/avrftdi.h
--- avrdude-r952/avrftdi.h	1969-12-31 17:00:00.000000000 -0700
+++ avrdude/avrftdi.h	2011-02-25 16:20:45.000000000 -0700
@@ -0,0 +1,35 @@
+#ifndef avrftdi_h
+#define avrfdti_h
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define SCK 0x01
+#define SDO 0x02
+#define SDI 0x04
+
+#define RX 0x20
+#define TX 0x11
+
+#define TRX (RX | TX)
+
+#define TYPE_C_D 0x500
+#define TYPE_H   0x700
+#define TYPE_4H  0x800						
+						
+#define E(x) if ((x)) { fprintf(stdout, "%s:%d %s() %s: %s (%d)\n\t%s\n", __FILE__, __LINE__, __FUNCTION__, \
+	#x, strerror(errno), errno, ftdi_get_error_string(&ftdic)); return -1; }
+
+#define E_VOID(x) if ((x)) { fprintf(stdout, "%s:%d %s() %s: %s (%d)\n\t%s\n", __FILE__, __LINE__, __FUNCTION__, \
+	#x, strerror(errno), errno, ftdi_get_error_string(&ftdic)); }
+
+void avrftdi_initpgm        (PROGRAMMER * pgm);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+
diff -x .svn -Nur avrdude-r952/config_gram.y avrdude/config_gram.y
--- avrdude-r952/config_gram.y	2011-02-25 17:30:08.000000000 -0700
+++ avrdude/config_gram.y	2011-02-28 14:40:34.000000000 -0700
@@ -48,6 +48,7 @@
 #include "avr.h"
 #include "jtagmkI.h"
 #include "jtagmkII.h"
+#include "avrftdi.h"
 
 #if defined(WIN32NATIVE)
 #define strtok_r( _s, _sep, _lasts ) \
@@ -82,6 +83,7 @@
 %token K_PAGED
 
 %token K_ARDUINO
+%token K_AVRFTDI
 %token K_BAUDRATE
 %token K_BS2
 %token K_BUFF
@@ -149,7 +151,13 @@
 %token K_STK600PP
 %token K_AVR910
 %token K_USBASP
+%token K_USBDEV
+%token K_USBSN
 %token K_USBTINY
+%token K_USBPID
+%token K_USBPRODUCT
+%token K_USBVENDOR
+%token K_USBVID
 %token K_BUTTERFLY
 %token K_TYPE
 %token K_VCC
@@ -432,6 +440,12 @@
     }
   } |
 
+  K_TYPE TKN_EQUAL K_AVRFTDI {
+    {
+      avrftdi_initpgm(current_prog);
+    }
+  } |
+
   K_TYPE TKN_EQUAL K_BUSPIRATE {
     {
       buspirate_initpgm(current_prog);
@@ -590,7 +604,49 @@
       }
     }
   } |
+  K_USBDEV TKN_EQUAL TKN_STRING {
+    {
+      strncpy(current_prog->usbdev, $3->value.string, PGM_USBSTRINGLEN);
+      current_prog->usbdev[PGM_USBSTRINGLEN-1] = 0;
+      free_token($3);
+    }
+  } |
+  K_USBVID TKN_EQUAL TKN_NUMBER {
+    {
+      current_prog->usbvid = $3->value.number;
+    }
+  } |
+
+  K_USBPID TKN_EQUAL TKN_NUMBER {
+    {
+      current_prog->usbpid = $3->value.number;
+    }
+  } |
+
+  K_USBSN TKN_EQUAL TKN_STRING {
+    {
+      strncpy(current_prog->usbsn, $3->value.string, PGM_USBSTRINGLEN);
+      current_prog->usbsn[PGM_USBSTRINGLEN-1] = 0;
+      free_token($3);
+    }
+  } |
+  
+  K_USBVENDOR TKN_EQUAL TKN_STRING {
+    {
+      strncpy(current_prog->usbvendor, $3->value.string, PGM_USBSTRINGLEN);
+      current_prog->usbvendor[PGM_USBSTRINGLEN-1] = 0;
+      free_token($3);
+    }
+  } |
 
+  K_USBPRODUCT TKN_EQUAL TKN_STRING {
+    {
+      strncpy(current_prog->usbproduct, $3->value.string, PGM_USBSTRINGLEN);
+      current_prog->usbproduct[PGM_USBSTRINGLEN-1] = 0;
+      free_token($3);
+    }
+  } |
+  
   K_BAUDRATE TKN_EQUAL TKN_NUMBER {
     {
       current_prog->baudrate = $3->value.number;
diff -x .svn -Nur avrdude-r952/configure.ac avrdude/configure.ac
--- avrdude-r952/configure.ac	2011-02-25 17:30:08.000000000 -0700
+++ avrdude/configure.ac	2011-02-13 20:16:11.000000000 -0700
@@ -83,7 +83,14 @@
    AC_CHECK_HEADERS([libusb.h])
 fi
 AC_SUBST(LIBUSB_1_0, $LIBUSB_1_0)
-
+AH_TEMPLATE([HAVE_LIBFTDI],
+            [Define if FTDI support is enabled via libftdi])
+AC_CHECK_LIB([ftdi], [ftdi_init], [have_libftdi=yes])
+if test x$have_libftdi = xyes; then
+   LIBFTDI="-lftdi"
+   AC_DEFINE([HAVE_LIBFTDI])
+fi
+AC_SUBST(LIBFTDI, $LIBFTDI)
 # Checks for header files.
 AC_CHECK_HEADERS([limits.h stdlib.h string.h])
 AC_CHECK_HEADERS([fcntl.h sys/ioctl.h sys/time.h termios.h unistd.h])
diff -x .svn -Nur avrdude-r952/lexer.l avrdude/lexer.l
--- avrdude-r952/lexer.l	2011-02-25 17:30:08.000000000 -0700
+++ avrdude/lexer.l	2011-02-28 14:40:34.000000000 -0700
@@ -120,6 +120,7 @@
 arduino          { yylval=NULL; return K_ARDUINO; }
 avr910           { yylval=NULL; return K_AVR910; }
 avr910_devcode   { yylval=NULL; return K_AVR910_DEVCODE; }
+avrftdi          { yylval=NULL; return K_AVRFTDI; }
 usbasp           { yylval=NULL; return K_USBASP; }
 usbtiny          { yylval=NULL; return K_USBTINY; }
 bank_size        { yylval=NULL; return K_PAGE_SIZE; }
@@ -197,6 +198,12 @@
 stk600hvsp       { yylval=NULL; return K_STK600HVSP; }
 stk600pp         { yylval=NULL; return K_STK600PP; }
 type             { yylval=NULL; return K_TYPE; }
+usbdev           { yylval=NULL; return K_USBDEV; }
+usbpid           { yylval=NULL; return K_USBPID; }
+usbproduct       { yylval=NULL; return K_USBPRODUCT; }
+usbsn            { yylval=NULL; return K_USBSN; }
+usbvendor        { yylval=NULL; return K_USBVENDOR; }
+usbvid           { yylval=NULL; return K_USBVID; }
 vcc              { yylval=NULL; return K_VCC; }
 vfyled           { yylval=NULL; return K_VFYLED; }
 
diff -x .svn -Nur avrdude-r952/Makefile.am avrdude/Makefile.am
--- avrdude-r952/Makefile.am	2011-02-25 17:30:08.000000000 -0700
+++ avrdude/Makefile.am	2011-02-24 16:05:40.000000000 -0700
@@ -56,7 +56,7 @@
 
 libavrdude_a_CFLAGS   = @ENABLE_WARNINGS@
 
-avrdude_LDADD  = $(top_builddir)/$(noinst_LIBRARIES) @LIBUSB@ @LIBUSB_1_0@ @LIBHID@ -lm
+avrdude_LDADD  = $(top_builddir)/$(noinst_LIBRARIES) @LIBUSB@ @LIBUSB_1_0@ @LIBFTDI@ @LIBHID@ -lm
 
 bin_PROGRAMS = avrdude
 
@@ -87,6 +87,8 @@
 	avr910.c \
 	avr910.h \
 	avrdude.h \
+	avrftdi.c \
+	avrftdi.h \
 	avrpart.c \
 	avrpart.h \
 	bitbang.c \
diff -x .svn -Nur avrdude-r952/pgm.h avrdude/pgm.h
--- avrdude-r952/pgm.h	2011-02-25 17:30:08.000000000 -0700
+++ avrdude/pgm.h	2011-02-28 14:40:34.000000000 -0700
@@ -36,6 +36,7 @@
 #define PGM_DESCLEN 80
 #define PGM_PORTLEN PATH_MAX
 #define PGM_TYPELEN 32
+#define PGM_USBSTRINGLEN 256
 
 typedef enum {
   EXIT_VCC_UNSPEC,
@@ -60,6 +61,9 @@
   int ppidata;
   int ppictrl;
   int baudrate;
+  int usbvid, usbpid;
+  char usbdev[PGM_USBSTRINGLEN], usbsn[PGM_USBSTRINGLEN];
+  char usbvendor[PGM_USBSTRINGLEN], usbproduct[PGM_USBSTRINGLEN];
   double bitclock;    /* JTAG ICE clock period in microseconds */
   int ispdelay;    /* ISP clock delay */
   union filedescriptor fd;
