? ylwrap
Index: Makefile.am
===================================================================
RCS file: /sources/avrdude/avrdude/Makefile.am,v
retrieving revision 1.41
diff -u -r1.41 Makefile.am
--- Makefile.am	14 Mar 2008 13:00:05 -0000	1.41
+++ Makefile.am	2 May 2008 08:33:16 -0000
@@ -52,7 +52,7 @@
 
 libavrdude_a_CFLAGS   = @ENABLE_WARNINGS@
 
-avrdude_LDADD  = $(top_builddir)/$(noinst_LIBRARIES) @LIBUSB@ @LIBHID@ -lm
+avrdude_LDADD  = $(top_builddir)/$(noinst_LIBRARIES) @LIBFTDI@ @LIBUSB@ @LIBHID@ -lm
 
 bin_PROGRAMS = avrdude
 
@@ -81,6 +81,8 @@
 	avr910.c \
 	avr910.h \
 	avrdude.h \
+	avrftdi.c \
+	avrftdi.h \
 	avrpart.c \
 	avrpart.h \
 	bitbang.c \
Index: avrdude.conf.in
===================================================================
RCS file: /sources/avrdude/avrdude/avrdude.conf.in,v
retrieving revision 1.128
diff -u -r1.128 avrdude.conf.in
--- avrdude.conf.in	14 Mar 2008 13:00:05 -0000	1.128
+++ avrdude.conf.in	2 May 2008 08:33:23 -0000
@@ -311,6 +311,33 @@
 #
 
 programmer
+  id	= "armusbocd";
+  desc	= "Olimex ARM-USB-OCD";
+  type	= avrftdi;
+  vid = 0x15ba;
+  pid = 0x0003;
+  reset	= 3;
+  nbuff	= 4;
+  buff = 11;
+;
+
+programmer
+  id   = "jtagkey";
+  desc = "Amontec JTAG key";
+  type = avrftdi;
+  vid = 0x0403;
+  pid = 0xcff8;
+  reset = 3;
+  nbuff = 4, 11, 9;
+;
+
+programmer
+  id	= "avrftdi";
+  desc	= "FT2232D based generic programmer";
+  type	= avrftdi;
+;
+
+programmer
   id    = "avrisp";
   desc  = "Atmel AVR ISP";
   type  = stk500;
@@ -3073,7 +3100,7 @@
         size            = 2048;
         min_write_delay = 9000;
         max_write_delay = 9000;
-        readback_p1     = 0xff;
+        readback_p1     = 0xff;
         readback_p2     = 0xff;
 	read            = "  1   0   1   0      0   0   0   0",
                           "  0   0   0   x      x a10  a9  a8",
Index: avrftdi.c
===================================================================
RCS file: avrftdi.c
diff -N avrftdi.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ avrftdi.c	2 May 2008 08:33:23 -0000
@@ -0,0 +1,745 @@
+/*
+ * avrftdi - extension for avrdude
+ * Copyright (C) 2007 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
+ */
+
+/*
+ * 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 <ftdi.h>
+#include <usb.h>
+
+#include "avrdude.h"
+#include "avr.h"
+#include "pgm.h"
+#include "avrftdi.h"
+
+static struct ftdi_context ftdic;
+static uint16_t pinmask[N_PINS], pinstate, datadir;
+
+
+/*   Dump a buffer (possible header, with descriptions and given width)   */
+
+static void buf_dump(unsigned char *buf, int len, char *desc, int offset, int width)
+{
+	int i, n;
+
+	fprintf(stdout, "%s begin:\n", desc);
+
+	n = width;
+	for (i = 0; i < len; i++) {
+		fprintf(stdout, "%02x ", buf[i]);
+		n--;
+		if (n == 0 || i == offset-1) {
+			fprintf(stdout, "\n");
+			n = width;
+		}
+	}
+	fprintf(stdout, "%s end\n", desc);
+}
+
+
+
+/*   Write data to FTDI device, with possible debug   */
+
+static int ftdi_write_data_x(struct ftdi_context *ftdic, unsigned char *buf, int size)
+{
+	if(verbose > 1) 
+		buf_dump(buf, size, "o_buf", 0, 16);
+
+	return ftdi_write_data(ftdic, buf, size);
+}
+
+
+/*   Read data from FTDI device, with debug verbosity   */
+
+static int ftdi_read_data_x(struct ftdi_context *ftdic, unsigned char *buf, int size)
+{
+	int n;
+
+	n = ftdi_read_data(ftdic, buf, size);
+	if (verbose > 1)
+		buf_dump(buf, n, "i_buf", 0, 16);
+	
+	return n;
+}
+
+
+
+static int avrftdi_get_command(AVRPART *p, AVRMEM *m, unsigned char cmd, unsigned char *ret)
+{
+	if (m->op[cmd] == NULL) {
+		fprintf(stderr, "%s failure: %s command not defined for %s\n", progname, &cmd, p->desc);
+		exit(1);
+	} else
+		avr_set_bits(m->op[cmd], ret);
+	return 0;
+}
+
+
+
+/*   Set physical pin values and update the pin state   */
+
+static void set_pins(uint16_t mask)
+{
+	uint8_t buf[6];
+
+	buf[0] = 0x80;
+	buf[1] = (uint8_t)(mask & 0xff);
+	buf[2] = (uint8_t)(datadir & 0xff);
+	buf[3] = 0x82;
+	buf[4] = (uint8_t)(mask >> 8);
+	buf[5] = (uint8_t)(datadir >> 8);
+	E(ftdi_write_data_x(&ftdic, buf, 6) != 6);
+
+	pinstate = mask;
+}
+
+
+
+/*   Set pins and take pinstate into account   */
+/*     onmask: mask of pins to set   */
+/*     offmask: mask of pins to clear   */
+
+static void set_pinstate(uint16_t offmask, uint16_t onmask)
+{
+	uint16_t newstate;
+
+	if (verbose > 1)
+		fprintf(stderr, "set_pinstate: on: %04x, off: %04x\n", onmask, offmask);
+
+	newstate = (pinstate | onmask) & ~offmask;
+
+	if (newstate != pinstate)
+		set_pins(newstate);
+}
+
+
+static int set_led_pgm(struct programmer_t * pgm, int value)
+{
+	if (value == ON)
+		set_pinstate(0, pinmask[PIN_LED_PGM]);
+	else
+		set_pinstate(pinmask[PIN_LED_PGM], 0);
+	return 0;
+}
+
+
+static int set_led_rdy(struct programmer_t * pgm, int value)
+{
+	if (value == ON)
+		set_pinstate(0, pinmask[PIN_LED_RDY]);
+	else
+		set_pinstate(pinmask[PIN_LED_RDY], 0);
+	return 0;
+}
+
+
+static int set_led_err(struct programmer_t * pgm, int value)
+{
+	if (value == ON)
+		set_pinstate(0, pinmask[PIN_LED_ERR]);
+	else
+		set_pinstate(pinmask[PIN_LED_ERR], 0);
+	return 0;
+}
+
+
+static int set_led_vfy(struct programmer_t * pgm, int value)
+{
+	if (value == ON)
+		set_pinstate(0, pinmask[PIN_LED_VFY]);
+	else
+		set_pinstate(pinmask[PIN_LED_VFY], 0);
+	return 0;
+}
+
+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;
+
+		E(ftdi_write_data_x(&ftdic, buf, buf_size + 4) != buf_size + 4);
+	}
+	
+	if (mode & RX) {
+		memset(buf, 0, sizeof(buf));
+		do {
+			n = ftdi_read_data_x(&ftdic, buf + k, buf_size - k);
+			E(n < 0);
+			k += n;
+		} while (k < buf_size);
+		
+		memcpy(data, buf, buf_size);
+	}
+
+	return k;
+}
+
+
+/*   Set the baud rate   */
+
+static int set_frequency(uint32_t freq)
+{
+	uint32_t divisor;
+	uint8_t buf[3];
+
+	/* divisor on 6000000 / freq - 1 */
+	divisor = 6000000 / freq;
+	if (divisor == 0) {
+		fprintf(stderr, "%s failure: Frequency too high (%u > 6 MHz)\n", progname, freq);
+		return -1;
+	}
+	divisor--;
+
+	if (divisor > 65535) {
+		fprintf(stderr, "%s failure: Frequency too low (%u < 100 Hz)\n", progname, freq);
+		return -1;
+	}
+
+	buf[0] = 0x86;
+	buf[1] = (uint8_t)(divisor & 0xff);
+	buf[2] = (uint8_t)(divisor >> 8);
+
+	E(ftdi_write_data_x(&ftdic, buf, 3) < 0);
+
+	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, uint16_t *pins)
+{
+	int pin;
+	uint16_t mask;
+
+	pin = pgm->pinno[pinfunc];
+	if (verbose > 2)
+		fprintf(stdout, "add_pin: %d: %d\n", pinfunc, pgm->pinno[pinfunc]);
+
+	/* non-existent definitions, go away */
+	if (pin == 0)
+		return 0;
+
+	/* check that the pin number is in range */
+	if (pin >= 12) {
+		fprintf(stderr, "%s failure: invalid pin definition (pin nr > 11) in config file\n", progname);
+		return -1;
+	}
+
+	/* create the mask and check that the pin is available */
+	mask = 1 << pin;
+	if (*pins & mask) {
+		fprintf(stderr, "%s failure: pin %d has two definitions in config file\n", progname, pin);
+		return -1;
+	}
+
+	*pins |= mask;
+	pinmask[pinfunc] = mask;
+	return 0;
+}
+
+
+
+/*   Add a pins by pin mask    */
+
+static int add_pins(PROGRAMMER *pgm, int pinfunc, uint16_t *pins)
+{
+	uint32_t mask;
+	int i;
+
+	if (verbose > 2)
+		fprintf(stdout, "add_pins: %d: %04x\n", pinfunc, pgm->pinno[pinfunc]);
+
+	mask = pgm->pinno[pinfunc];
+	if (mask >= 1 << 12) {
+		fprintf(stderr, "%s failure: pin list has pins out of range: ", progname);
+		mask &= ~(1 << 12) - 1;
+	}
+	else if (mask & *pins) {
+		fprintf(stderr, "%s failure: conflicting pins in pin list: ", progname);
+		mask &= *pins;
+	}
+	else {
+		*pins |= (uint16_t)mask;
+		pinmask[pinfunc] = (uint16_t)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 avrftdi_open(PROGRAMMER * pgm, char *port)
+{
+	char  *dev, *ev, *ed;
+	unsigned int vid, pid;
+
+	/* set the VID/PID with the following priority: command line, configuration file, default */
+	if (strcmp(port, "default")) {
+		dev = strchr(port, ':');
+		if (dev == NULL) {		
+			fprintf(stderr, "%s failure: invalid port, 0xvendor:0xdevice USB ID expected (try lsusb)\n", progname);
+			return -1;
+		}
+		vid = strtoul(port, &ev, 16);
+		pid = strtoul(dev+1, &ed, 16);
+	}
+	else {
+		if (pgm->vid != 0)
+			vid = pgm->vid;
+		else
+			vid = 0x0403;
+
+		if (pgm->pid != 0)
+			pid = pgm->pid;
+		else
+			pid = 0x6010;
+	}
+
+	if (pid > 0xffff || vid > 0xffff) {
+		fprintf(stderr, "%s failure: USB Vendor and/or Device ID out of range\n",
+			progname);
+		return -1;
+	}
+
+	if (verbose > 0)
+		fprintf(stdout, "USB VID/PID: %04x:%04x\n", vid, pid);
+
+	/* fill in the default pins */
+	if (!pgm->pinno[PIN_AVR_SCK]) pgm->pinno[PIN_AVR_SCK] = SCKPIN;
+	if (!pgm->pinno[PIN_AVR_MOSI]) pgm->pinno[PIN_AVR_MOSI] = MOSIPIN;
+	if (!pgm->pinno[PIN_AVR_MISO]) pgm->pinno[PIN_AVR_MISO] = MISOPIN;
+	if (!pgm->pinno[PIN_AVR_RESET]) pgm->pinno[PIN_AVR_RESET] = RESETPIN;
+
+	/* check the MOSI/MISO/SCK mapping, it cannot be changed */
+	if (pgm->pinno[PIN_AVR_SCK] != SCKPIN  ||
+		pgm->pinno[PIN_AVR_MOSI] != MOSIPIN ||
+		pgm->pinno[PIN_AVR_MISO] != MISOPIN) {
+		fprintf(stderr, "%s failure: pinout for MPSSE/FTDI must be SCK=0, MOSI=1, MISO=2\n", progname);
+		return -1;
+	}
+
+	/* low three bits must be set as outputs for MPSSE */
+	datadir = (1 << SCKPIN) | (1 << MOSIPIN) | (1 << MISOPIN);
+
+	/* gather the rest of the pins */
+	if (add_pins(pgm, PPI_AVR_VCC, &datadir)) return -1;
+	if (add_pins(pgm, PPI_AVR_BUFF, &datadir)) return -1;
+	if (add_pins(pgm, PPI_AVR_NBUFF, &datadir)) return -1;
+	if (add_pin(pgm, PIN_AVR_RESET, &datadir)) return -1;
+	if (add_pin(pgm, PIN_LED_ERR, &datadir)) return -1;
+	if (add_pin(pgm, PIN_LED_RDY, &datadir)) return -1;
+	if (add_pin(pgm, PIN_LED_PGM, &datadir)) return -1;
+	if (add_pin(pgm, PIN_LED_VFY, &datadir)) return -1;
+
+	if (verbose > 1) {
+		fprintf(stdout, "PPI_AVR_VCC: mask %04x\n", pinmask[PPI_AVR_VCC]);
+		fprintf(stdout, "PPI_AVR_BUFF: mask %04x\n", pinmask[PPI_AVR_BUFF]);
+		fprintf(stdout, "PPI_AVR_NBUFF: mask %04x\n", pinmask[PPI_AVR_NBUFF]);
+		fprintf(stdout, "PIN_AVR_RESET: mask %04x\n", pinmask[PIN_AVR_RESET]);
+		fprintf(stdout, "PIN_LED_ERR: mask %04x\n", pinmask[PIN_LED_ERR]);
+		fprintf(stdout, "PIN_LED_RDY: mask %04x\n", pinmask[PIN_LED_RDY]);
+		fprintf(stdout, "PIN_LED_PGM: mask %04x\n", pinmask[PIN_LED_PGM]);
+		fprintf(stdout, "PIN_LED_VFY: mask %04x\n", pinmask[PIN_LED_VFY]);
+	}
+
+	E(ftdi_init(&ftdic) < 0);
+	E(ftdi_set_interface(&ftdic, INTERFACE_A) < 0);		/*must be A for mpsse */
+	E(ftdi_usb_open(&ftdic, vid, pid) < 0);
+	E(ftdi_set_bitmode(&ftdic, (uint8_t)(datadir & 0xff), BITMODE_MPSSE) < 0);	/*set SPI */
+
+	set_pins(pinmask[PPI_AVR_NBUFF]);
+	return set_frequency(pgm->baudrate ? pgm->baudrate : 150000);
+}
+
+
+
+static void avrftdi_close(PROGRAMMER * pgm)
+{
+	unsigned int i;
+	
+	//Check whether &ftdic was initialized, if not ftdi_deinit() crashes
+	E(ftdi_write_data_get_chunksize(&ftdic, &i) < 0);
+
+	if( i != 0 ) {
+		set_pinstate(pinmask[PIN_AVR_RESET], 0);
+		E(ftdi_usb_close(&ftdic));
+		ftdi_deinit(&ftdic);
+	}
+}
+
+
+static int avrftdi_initialize(PROGRAMMER * pgm, AVRPART * p)
+{
+	set_pinstate(pinmask[PIN_AVR_RESET], 0);
+	/*use speed optimization with CAUTION*/
+	usleep(10 * 1000);
+
+	/*giving rst-pulse of at least 2 avr-clock-cycles, for security (2us @ 1MHz) */
+	set_pinstate(0, pinmask[PIN_AVR_RESET]);
+	usleep(10 * 1000);
+
+	/*setting rst back to 0 */
+	set_pinstate(pinmask[PIN_AVR_RESET], 0);
+
+	/*wait at least 20ms bevor issuing spi commands to avr */
+	usleep(30 * 1000);
+
+	return pgm->program_enable(pgm, p);
+}
+
+static void avrftdi_disable(PROGRAMMER * pgm)
+{
+	set_pinstate(pinmask[PPI_AVR_BUFF], pinmask[PPI_AVR_NBUFF]);
+}
+
+static void avrftdi_enable(PROGRAMMER * pgm)
+{
+	set_pinstate(pinmask[PPI_AVR_NBUFF], pinmask[PPI_AVR_BUFF]);
+}
+
+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(INOUT, 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);
+		exit(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_pinstate(0, pinmask[PIN_AVR_RESET]);
+			usleep(20);
+			set_pinstate(pinmask[PIN_AVR_RESET], 0);
+			avr_set_bits(p->op[AVR_OP_PGM_ENABLE], buf);
+		} else
+			return 0;
+	}
+	
+	return -1;
+
+}
+
+
+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;
+}
+
+static int avrftdi_flash_read(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m, int page_size, int len)
+{
+	/*
+	 *Reading from flash
+	 */
+	int i, buf_index, buf_size = 0, psize = m->page_size;
+	unsigned char o_buf[4*len], *o_ptr = o_buf;
+	unsigned char i_buf[4*len];
+	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));
+
+	while (bytes) {
+		if (bytes > psize) {
+			blocksize = psize/2;
+			bytes -= psize;
+		} else {
+			blocksize = bytes/2;
+			bytes = 0;
+		}
+		
+		for(i = 0; i < blocksize; i++) {
+			if(verbose)
+				fprintf(stdout, "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++;
+			buf_size = o_ptr - o_buf;
+			
+			if((buf_size >= (page_size - 8)) || ( i == blocksize-1)) {
+				E(avrftdi_transmit(INOUT, o_buf, i_buf, buf_size) < 0);
+
+				for(buf_index = 0; buf_index < buf_size; buf_index+=8) {
+					//printf("\n%02x %02x", *(i_buf+buf_index+3), *(i_buf+buf_index+7));
+					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 >= 2) {
+					buf_dump(i_buf, buf_size, "i_buf", 0, 16);
+					buf_dump(m->buf, 640, "vfy buf", 0, 16);
+				}
+				o_ptr = o_buf;
+			}
+		}
+		report_progress(2*address, len, NULL);
+	}
+	memcpy(m->buf, buffer, sizeof(buffer));
+	
+	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(INOUT, cmd, cmd, 4) < 0);
+		
+		avr_get_output(m->op[AVR_OP_READ], cmd, bufptr++);
+		report_progress(add, len, NULL);
+	}
+
+	memcpy(m->buf, buffer, len);
+	return len;
+}
+
+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;
+}
+
+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));
+		report_progress(add, len, NULL);
+	}
+	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;
+	unsigned char buf[4*len + 4], *bufptr = buf;
+	unsigned char *buffer = m->buf;
+
+
+	//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)
+			fprintf(stderr, "-< bytes = %d of %d, blocksize = %d of %d\n", len - bytes, len, blocksize, m->page_size/2);
+
+	/*
+	 * cmd[3] = (blockflags & 0x0F) + ((page_size & 0xF00) >> 4); //TP: Mega128 fix
+	 */
+
+		for (i = 0; i < blocksize; i++) {
+			/*setting word*/
+			avrftdi_get_command(p, m, 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;		
+			avrftdi_get_command(p, m, 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)
+			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(stdout, "%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 >= 2)
+			buf_dump(buf, sizeof(buf), "command buffer", 0, 16*3);
+	
+		E(avrftdi_transmit(TX, buf, buf, buf_size) < 0);
+			
+		bufptr = buf;
+		if ((!((address * 2) % m->page_size) || !bytes)) {
+			usleep((m->min_write_delay)*10);
+		}
+			
+		report_progress(2*address, len, NULL);
+	}
+	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;
+}
+
+
+void avrftdi_initpgm(PROGRAMMER * pgm)
+{
+	strcpy(pgm->type, "avrftdi");
+
+	/*
+	 * 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;
+}
Index: avrftdi.h
===================================================================
RCS file: avrftdi.h
diff -N avrftdi.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ avrftdi.h	2 May 2008 08:33:23 -0000
@@ -0,0 +1,31 @@
+#ifndef avrftdi_h
+#define avrfdti_h
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Default MPSSE pin definitions */
+#define SCKPIN 0
+#define MOSIPIN 1
+#define MISOPIN 2
+#define RESETPIN 3
+
+/* MPSSE mode bits */
+#define RX 0x20
+#define TX 0x11
+
+#define INOUT (RX | TX)
+
+#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)); exit(1); }
+
+void avrftdi_initpgm        (PROGRAMMER * pgm);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+
Index: config_gram.y
===================================================================
RCS file: /sources/avrdude/avrdude/config_gram.y,v
retrieving revision 1.60
diff -u -r1.60 config_gram.y
--- config_gram.y	14 Mar 2008 13:00:06 -0000	1.60
+++ config_gram.y	2 May 2008 08:33:24 -0000
@@ -46,6 +46,7 @@
 #include "avr.h"
 #include "jtagmkI.h"
 #include "jtagmkII.h"
+#include "avrftdi.h"
 
 #if defined(WIN32NATIVE)
 #define strtok_r( _s, _sep, _lasts ) \
@@ -99,6 +100,7 @@
 %token K_EEPROM
 %token K_ERRLED
 %token K_FLASH
+%token K_AVRFTDI
 %token K_ID
 %token K_IO
 %token K_JTAG_MKI
@@ -110,12 +112,14 @@
 %token K_MIN_WRITE_DELAY
 %token K_MISO
 %token K_MOSI
+%token K_NBUFF
 %token K_NUM_PAGES
 %token K_PAGEL
 %token K_PAR
 %token K_PARALLEL
 %token K_PART
 %token K_PGMLED
+%token K_PID
 %token K_PROGRAMMER
 %token K_PSEUDO
 %token K_PWROFF_AFTER_WRITE
@@ -144,6 +148,7 @@
 %token K_BUTTERFLY
 %token K_TYPE
 %token K_VCC
+%token K_VID
 %token K_VFYLED
 
 %token K_NO
@@ -378,6 +383,12 @@
     }
   } |
 
+K_TYPE TKN_EQUAL K_AVRFTDI {
+    {
+      avrftdi_initpgm(current_prog);
+    }
+  } |
+
   K_TYPE TKN_EQUAL K_SERBB {
     {
       serbb_initpgm(current_prog);
@@ -550,12 +561,41 @@
     }
   } |
 
+  K_NBUFF TKN_EQUAL num_list {
+    { 
+      TOKEN * t;
+      int pin;
+
+      current_prog->pinno[PPI_AVR_NBUFF] = 0;
+
+      while (lsize(number_list)) {
+        t = lrmv_n(number_list, 1);
+        pin = t->value.number;
+        current_prog->pinno[PPI_AVR_NBUFF] |= (1 << pin);
+
+        free_token(t);
+      }
+    }
+  } |
+
   K_BAUDRATE TKN_EQUAL TKN_NUMBER {
     {
       current_prog->baudrate = $3->value.number;
     }
   } |
 
+  K_PID TKN_EQUAL TKN_NUMBER {
+    {
+      current_prog->pid = $3->value.number;
+    }
+  } |
+
+  K_VID TKN_EQUAL TKN_NUMBER {
+    {
+      current_prog->vid = $3->value.number;
+    }
+  } |
+
   K_RESET  TKN_EQUAL TKN_NUMBER { free_token($1); 
                                   assign_pin(PIN_AVR_RESET, $3, 0); } |
   K_SCK    TKN_EQUAL TKN_NUMBER { free_token($1); 
Index: configure.ac
===================================================================
RCS file: /sources/avrdude/avrdude/configure.ac,v
retrieving revision 1.53
diff -u -r1.53 configure.ac
--- configure.ac	29 Oct 2007 23:08:37 -0000	1.53
+++ configure.ac	2 May 2008 08:33:24 -0000
@@ -61,6 +61,15 @@
 fi
 AC_SUBST(LIBUSB, $LIBUSB)
 
+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_HEADER_STDC
 AC_CHECK_HEADERS([limits.h stdlib.h string.h])
Index: lexer.l
===================================================================
RCS file: /sources/avrdude/avrdude/lexer.l,v
retrieving revision 1.52
diff -u -r1.52 lexer.l
--- lexer.l	14 Mar 2008 13:00:06 -0000	1.52
+++ lexer.l	2 May 2008 08:33:24 -0000
@@ -142,6 +142,7 @@
 eeprom           { yylval=NULL; return K_EEPROM; }
 enablepageprogramming { yylval=NULL; return K_ENABLEPAGEPROGRAMMING; }
 errled           { yylval=NULL; return K_ERRLED; }
+avrftdi          { yylval=NULL; return K_AVRFTDI; }
 flash            { yylval=NULL; return K_FLASH; }
 has_jtag         { yylval=NULL; return K_HAS_JTAG; }
 has_debugwire    { yylval=NULL; return K_HAS_DW; }
@@ -156,6 +157,7 @@
 min_write_delay  { yylval=NULL; return K_MIN_WRITE_DELAY; }
 miso             { yylval=NULL; return K_MISO; }
 mosi             { yylval=NULL; return K_MOSI; }
+nbuff            { yylval=NULL; return K_NBUFF; }
 num_banks        { yylval=NULL; return K_NUM_PAGES; }
 num_pages        { yylval=NULL; return K_NUM_PAGES; }
 page_size        { yylval=NULL; return K_PAGE_SIZE; }
@@ -165,6 +167,7 @@
 parallel         { yylval=NULL; return K_PARALLEL; }
 part             { yylval=NULL; return K_PART; }
 pgmled           { yylval=NULL; return K_PGMLED; }
+pid              { yylval=NULL; return K_PID; }
 programmer       { yylval=NULL; return K_PROGRAMMER; }
 pwroff_after_write { yylval=NULL; return K_PWROFF_AFTER_WRITE; }
 rampz            { yylval=NULL; return K_RAMPZ; }
@@ -188,6 +191,7 @@
 stk600pp         { yylval=NULL; return K_STK600PP; }
 type             { yylval=NULL; return K_TYPE; }
 vcc              { yylval=NULL; return K_VCC; }
+vid              { yylval=NULL; return K_VID; }
 vfyled           { yylval=NULL; return K_VFYLED; }
 
 timeout          { yylval=NULL; return K_TIMEOUT; }
Index: main.c
===================================================================
RCS file: /sources/avrdude/avrdude/main.c,v
retrieving revision 1.131
diff -u -r1.131 main.c
--- main.c	8 Nov 2007 22:34:36 -0000	1.131
+++ main.c	2 May 2008 08:33:24 -0000
@@ -675,13 +675,14 @@
     }
   }
 
-  if ((strcmp(pgm->type, "STK500") == 0) ||
-      (strcmp(pgm->type, "avr910") == 0) ||
-      (strcmp(pgm->type, "STK500V2") == 0) ||
-      (strcmp(pgm->type, "JTAGMKII") == 0)) {
-    if (port == default_parallel) {
+  if (port == default_parallel) {
+    if ((strcmp(pgm->type, "STK500") == 0) ||
+        (strcmp(pgm->type, "avr910") == 0) ||
+        (strcmp(pgm->type, "STK500V2") == 0) ||
+        (strcmp(pgm->type, "JTAGMKII") == 0))
       port = default_serial;
-    }
+    else if (strcmp(pgm->type, "avrftdi") == 0)
+      port = "default";
   }
 
   if (partdesc == NULL) {
Index: pgm.c
===================================================================
RCS file: /sources/avrdude/avrdude/pgm.c,v
retrieving revision 1.26
diff -u -r1.26 pgm.c
--- pgm.c	7 Nov 2007 20:36:11 -0000	1.26
+++ pgm.c	2 May 2008 08:33:24 -0000
@@ -82,6 +82,8 @@
   pgm->config_file[0] = 0;
   pgm->lineno = 0;
   pgm->baudrate = 0;
+  pgm->vid = 0;
+  pgm->pid = 0;
 
   for (i=0; i<N_PINS; i++)
     pgm->pinno[i] = 0;
Index: pgm.h
===================================================================
RCS file: /sources/avrdude/avrdude/pgm.h,v
retrieving revision 1.37
diff -u -r1.37 pgm.h
--- pgm.h	14 Mar 2008 13:00:06 -0000	1.37
+++ pgm.h	2 May 2008 08:33:24 -0000
@@ -60,6 +60,8 @@
   int ppidata;
   int ppictrl;
   int baudrate;
+  unsigned int vid;
+  unsigned int pid;
   double bitclock;    /* JTAG ICE clock period in microseconds */
   int ispdelay;    /* ISP clock delay */
   union filedescriptor fd;
Index: pindefs.h
===================================================================
RCS file: /sources/avrdude/avrdude/pindefs.h,v
retrieving revision 1.12
diff -u -r1.12 pindefs.h
--- pindefs.h	18 Sep 2005 20:12:23 -0000	1.12
+++ pindefs.h	2 May 2008 08:33:24 -0000
@@ -25,6 +25,7 @@
 enum {
   PPI_AVR_VCC=1,
   PPI_AVR_BUFF,
+  PPI_AVR_NBUFF,
   PIN_AVR_RESET,
   PIN_AVR_SCK,
   PIN_AVR_MOSI,
