From ca81aeb1390e3514d9614e15b2751d6dcf2e8d26 Mon Sep 17 00:00:00 2001
From: Hannes Weisbach <hannes_weisbach@gmx.net>
Date: Mon, 6 May 2013 11:48:15 +0000
Subject: [PATCH] avrftdi: Change to new 0-based pin definitions

avrdude.conf.in: Change all programmers' pin definitions to 0-based
avrftdi.c: incorporate new 0-based pindef infrastructure
avrftdi_private.h: Add pin_checklist_t to avrftdi_t for runtime pin
checking in pgm->setpin.

git-svn-id: svn://svn.savannah.nongnu.org/avrdude/trunk@1164 81a1dc3b-b13d-400b-aceb-764788c761c2
---
 avrdude/ChangeLog         |   6 +-
 avrdude/avrdude.conf.in   |  64 +++---
 avrdude/avrftdi.c         | 436 +++++++++++---------------------------
 avrdude/avrftdi_private.h |   3 +
 4 files changed, 169 insertions(+), 340 deletions(-)

diff --git a/avrdude/ChangeLog b/avrdude/ChangeLog
index 3aea788a..089a3ba8 100644
--- a/avrdude/ChangeLog
+++ b/avrdude/ChangeLog
@@ -2,8 +2,12 @@
 
 	* avrftdi_tpi.c: instead of private set_pin() function pointer use the one
 	declared in struct PROGRAMMER.
-	* avrftdi_private.h: remove set_pin function pointer
+	* avrftdi_private.h: remove set_pin function pointer. Add pin_checklist_t
+	member to check pgm->setpin calls during runtime.
 	* avrftdi.c: remove set_pin function pointer init, add pgm->setpin init.
+	Convert avrftdi to new 0-based pindefs infrastructure.
+	* avrdude.conf.in: Change all avrftdi-based programmers' pin definitions to
+	0-based.
 
 2013-05-06  Joerg Wunsch <j.gnu@uriah.heep.sax.de>
 
diff --git a/avrdude/avrdude.conf.in b/avrdude/avrdude.conf.in
index f29d9e2c..aae97dbe 100644
--- a/avrdude/avrdude.conf.in
+++ b/avrdude/avrdude.conf.in
@@ -384,17 +384,17 @@ programmer
   usbdev     = "A";
   usbsn      = "";
 #ISP-signals - lower ADBUS-Nibble (default)
-  reset  = 4;
-  sck    = 1;
-  mosi   = 2;
-  miso   = 3;
+  reset  = 3;
+  sck    = 0;
+  mosi   = 1;
+  miso   = 2;
 #LED SIGNALs - higher ADBUS-Nibble
-#  errled = 5;
-#  rdyled = 6;
-#  pgmled = 7;
-#  vfyled = 8;
+#  errled = 4;
+#  rdyled = 5;
+#  pgmled = 6;
+#  vfyled = 7;
 #Buffer Signal - ACBUS - Nibble
-#  buff   = 9;
+#  buff   = 8;
 ;
 # 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
@@ -415,16 +415,16 @@ programmer
   usbproduct = "";
   usbsn      = "";
 #ISP-signals 
-  reset  = 4;
-  sck    = 1;
-  mosi   = 2;
-  miso   = 3;
-  buff   = 5;
+  reset  = 3;
+  sck    = 0;
+  mosi   = 1;
+  miso   = 2;
+  buff   = 4;
 #LED SIGNALs 
-  errled = ~ 12;
-  rdyled = ~ 15;
-  pgmled = ~ 14;
-  vfyled = ~ 13;
+  errled = ~ 11;
+  rdyled = ~ 14;
+  pgmled = ~ 13;
+  vfyled = ~ 12;
 ;
 
 #The FT4232H can be treated as FT2232H, but it has a different USB
@@ -448,11 +448,11 @@ programmer
   usbproduct = "";
   usbsn      = "";
 #ISP-signals => 20 - Pin connector on JTAGKey
-  reset  = 4; # TMS 7 violet
-  sck    = 1; # TCK 9 white
-  mosi   = 2; # TDI 5 green
-  miso   = 3; # TDO 13 orange
-  buff   = 5;
+  reset  = 3; # TMS 7 violet
+  sck    = 0; # TCK 9 white
+  mosi   = 1; # TDI 5 green
+  miso   = 2; # TDO 13 orange
+  buff   = 4;
 # VTG           VREF 1 brown with red tip
 # GND           GND 20 black
 # The colors are on the 20 pin breakout cable
@@ -492,10 +492,10 @@ programmer
   usbvendor  = "";
   usbproduct = "";
   usbsn      = "";
-  reset  = 4; # TMS 7
-  sck    = 1; # TCK 9
-  mosi   = 2; # TDI 5
-  miso   = 3; # TDO 13
+  reset  = 3; # TMS 7
+  sck    = 0; # TCK 9
+  mosi   = 1; # TDI 5
+  miso   = 2; # TDO 13
 ;
 
 # Only Rev. A boards.
@@ -512,12 +512,12 @@ programmer
   usbdev     = "A";
   usbsn      = "";
 #ISP-signals - lower ACBUS-Nibble (default)
-  reset  = 4;
-  sck    = 1;
-  mosi   = 2;
-  miso   = 3;
+  reset  = 3;
+  sck    = 0;
+  mosi   = 1;
+  miso   = 2;
 # Enable correct buffers
-  buff   = ~8;
+  buff   = ~7;
 ;
 
 programmer
diff --git a/avrdude/avrftdi.c b/avrdude/avrftdi.c
index ff107042..7e2ca68a 100644
--- a/avrdude/avrftdi.c
+++ b/avrdude/avrftdi.c
@@ -36,6 +36,7 @@
 #include "avrdude.h"
 #include "avr.h"
 #include "pgm.h"
+#include "pindefs.h"
 #include "avrftdi.h"
 #include "avrpart.h"
 #include "avrftdi_tpi.h"
@@ -47,9 +48,7 @@
 #include <libusb-1.0/libusb.h>
 #include <libftdi1/ftdi.h>
 
-enum { FTDI_SCK = 1, FTDI_MOSI, FTDI_MISO, FTDI_RESET };
-
-#define FTDI_DEFAULT_MASK ( (1 << (FTDI_SCK - 1)) | (1 << (FTDI_MOSI - 1)) )
+enum { FTDI_SCK = 0, FTDI_MOSI, FTDI_MISO, FTDI_RESET };
 
 /* This is for running the code without having a FTDI-device.
  * The generated code is useless! For debugging purposes only.
@@ -66,12 +65,11 @@ static int write_flush(avrftdi_t *);
  * the pin names used in FTDI datasheets.
  */
 static char*
-ftdi_pin_name(avrftdi_t* pdata, int pin)
+ftdi_pin_name(avrftdi_t* pdata, struct pindef_t pin)
 {
-	static char pin_name[16];
+	static char str[128];
 
 	char interface = '@';
-	char port;
 
 	/* INTERFACE_ANY is zero, so @ is used
 	 * INTERFACE_A is one, so '@' + 1 = 'A'
@@ -81,17 +79,39 @@ ftdi_pin_name(avrftdi_t* pdata, int pin)
 	 */
 	interface += pdata->ftdic->index;
 
-	/* This is FTDI's naming scheme.
-	 * probably 'D' is for data and 'C' for control
-	 */
-	if(pin <= 8)
-		port = 'D';
-	else
-		port = 'C';
+	int pinno;
+	int n = 0;
+	int mask = pin.mask[0];
 
-	snprintf(pin_name, sizeof(pin_name), "%c%cBUS%d", interface, port, pin-1);
+	const char * fmt;
 
-	return pin_name;
+	str[0] = 0;
+
+	for(pinno = 0; mask; mask >>= 1, pinno++) {
+		if(!(mask & 1))
+			continue;
+
+		int chars = 0;
+
+		char port;
+		/* This is FTDI's naming scheme.
+		 * probably 'D' is for data and 'C' for control
+		 */
+		if(pinno < 8)
+			port = 'D';
+		else
+			port = 'C';
+
+		if(str[0] == 0)
+			fmt = "%c%cBUS%d%n";
+		else
+			fmt = ", %c%cBUS%d%n";
+
+		snprintf(&str[n], sizeof(str) - n, fmt, interface, port, pinno, &chars);
+		n += chars;
+	}
+
+	return str;
 }
 
 /*
@@ -191,167 +211,6 @@ static int set_frequency(avrftdi_t* ftdi, uint32_t freq)
 	return 0;
 }
 
-/*
- * Adds a single pin to the direction mask and sets the pin state inactive in
- * the value mask. the value of 'inactive' is chosen according to the pin
- * configuration (high or low active).
- */
-static int add_pin(PROGRAMMER *pgm, int pinfunc)
-{
-	int pin, pin_mask, inverted, fail;
-	avrftdi_t* pdata = to_pdata(pgm);
-	
-	fail = 0;
-	pin = pgm->pinno[pinfunc] & PIN_MASK;
-	inverted = pgm->pinno[pinfunc] & PIN_INVERSE;
-	pin_mask = (1 << (pin - 1));
-
-	/* not configured */
-	if(!pin)
-	{
-		log_warn("Pin %s not configured\n", avr_pin_name(pinfunc));
-		return 0;
-	}
-
-	/* check that the pin number is in range */
-	if (pin > pdata->pin_limit)
-	{
-		log_warn("Invalid pin definition for pin %s.\n", avr_pin_name(pinfunc));
-		log_warn("Configured as pin %d, but highest pin is %d.\n",
-		         pin, pdata->pin_limit);
-		fail = 1;
-	}
-
-	/* check if the pin is still available */
-	if (pdata->pin_direction & pin_mask)
-	{
-		log_warn("Pin %d (%s) is used twice. The second use is %s.\n",
-		         pin, ftdi_pin_name(pdata, pin), avr_pin_name(pinfunc));
-		fail = 1;
-	}
-
-	/* 
-	 * No need to fail for a wrongly configured led.
-	 * MISO, MOSI and SCK are fixed and correctly set during setup.
-	 * Maybe we should fail for wrongly configured VCC or BUFF pins?
-	 */
-	if(fail)
-	{
-		if(pinfunc == PIN_AVR_RESET)
-		{
-			log_err("Aborting, since the reset pin is wrongly configured\n");
-			return -1;
-		}
-		else
-		{
-			log_warn("Ignoring wrongly configured pin.\n");
-			return 0;
-		}
-	}
-
-	/* all checks passed - do actual work */
-	log_info("Configure pin %d (%s) as %s (%s active)\n",	pin,
-	         ftdi_pin_name(pdata, pin), avr_pin_name(pinfunc),
-					 (inverted) ? "low": "high");
-
-	{
-		/* create mask */
-		pdata->pin_direction |= pin_mask;
-		/* and set default value */
-		if(inverted)
-			pdata->pin_value |= pin_mask;
-		else
-			pdata->pin_value &= ~(pin_mask);
-	}
-
-	if(PIN_LED_ERR == pinfunc ||
-		 PIN_LED_VFY == pinfunc ||
-		 PIN_LED_RDY == pinfunc ||
-		 PIN_LED_PGM == pinfunc) {
-		pdata->led_mask |= pin_mask;
-	}
-	
-	return 0;
-}
-
-/*
- * Add pins by pin mask
- * Check an entire mask for correctness and plausibility. Performed checks are
- * the pin number is lower that the total number of pins and the pin is not
- * configured yet.
- * If at least one test fails, the entire mask is discarded.
- * These basic tests could possibly moved to avrdude core, since it does not
- * contain any tests (as far as I can tell).
- */
-static int add_pins(PROGRAMMER *pgm, int pinfunc)
-{
-	int pin, inverted;
-	uint32_t pin_mask, pin_bit;
-	avrftdi_t* pdata = to_pdata(pgm);
-
-	pin_mask = (pgm->pinno[pinfunc] & PIN_MASK) >> 1;
-	/* FIXME: I think you cannot inverse these multi-pin options */
-	inverted = pgm->pinno[pinfunc] & PIN_INVERSE;
-
-	if(!pin_mask)
-	{
-		log_warn("Pins for %s not configured.\n", avr_pin_name(pinfunc));
-		return 0;
-	}
-
-	/* check every configured pin */
-	for(pin = 0; (1 << pin) & (PIN_MASK); pin++)
-	{
-		pin_bit = 1 << pin;
-		
-		/* skip, if this pin is not in the mask to be configured */
-		if(!(pin_bit & pin_mask))
-			continue;
-		
-
-		/* 0 is not a valid pin, see above, we use 1 << (pin - 1) to create pin_bit */
-		if(pin + 1 > pdata->pin_limit)
-		{
-			log_warn("Invalid pin definition for pin %s.\n", avr_pin_name(pinfunc));
-			log_warn("Configured as pin %d, but highest pin is %d.\n", pin + 1,
-			         pdata->pin_limit);
-			log_warn("Ignoring wrongly configured pins.\n");
-		}
-
-		if(pin_bit & pdata->pin_direction)
-		{
-			log_warn("Failure: pin %d (%s) is used twice. The second use is %s.\n",
-			         pin, ftdi_pin_name(pdata, pin), avr_pin_name(pinfunc));
-			log_warn("Ignoring wrongly configured pins.\n");
-		}
-
-	}
-
-	/* conditional output */
-	for(pin = 0; (1 << pin) & (PIN_MASK); pin++)
-	{
-		pin_bit = 1 << pin;
-
-		/* skip if pin is not set */
-		if(!(pin_bit & pin_mask))
-			continue;
-
-		/* remember, we count from 1, not 0 */
-		log_info("Configured pin %d (%s) as %s (%s active)\n", pin + 1,
-		         ftdi_pin_name(pdata, pin+1), avr_pin_name(pinfunc),
-						 (inverted) ? "low": "high");
-	}
-
-	/* do the work */
-	pdata->pin_direction |= (uint16_t)pin_mask;
-	if(inverted)
-		pdata->pin_value |= pin_mask;
-	else
-		pdata->pin_value &= ~pin_mask;
-
-	return 0;
-}
-
 /*
  * This function sets or clears any pin, except SCK, MISO and MOSI. Depending
  * on the pin configuration, a non-zero value sets the pin in the 'active'
@@ -362,92 +221,26 @@ static int add_pins(PROGRAMMER *pgm, int pinfunc)
  */
 static int set_pin(PROGRAMMER * pgm, int pinfunc, int value)
 {
-	
-	int pin, pin_mask;
-	int inverted;
-	
 	avrftdi_t* pdata = to_pdata(pgm);
-
-	pin = pgm->pinno[pinfunc] & PIN_MASK;
-	inverted = pgm->pinno[pinfunc] & PIN_INVERSE;
+	struct pindef_t pin = pgm->pin[pinfunc];
 	
-	pin_mask = 1 << (pin - 1);
-	
-	/* make value 0 or 1 and invert, if necessary */
-	value = (inverted) ? !value : !!value;
-	
-	if (!pin) {
+	if (pins_check(pgm, pdata->pin_checklist, N_PINS - 1)) {
 		/* this error message is really annoying, maybe use a ratelimit? */
 	/*
 		avrftdi_print(2, "%s info: Pin is zero, value: %d!\n",
 				progname, value);
 	*/
 		return 1;
+	
 	}
 
-	if (value)
-		value = pin_mask;
+	log_debug("Setting pin %s (%s) as %s: %s (%s active)\n",
+	          pinmask_to_str(pin.mask), ftdi_pin_name(pdata, pin),
+						avr_pin_name(pinfunc),
+	          (value) ? "high" : "low", (pin.inverse[0]) ? "low" : "high");
 
-	log_debug("Setting pin %d (%s) as %s: %s (%s active)\n", pin,
-	          ftdi_pin_name(pdata, pin), avr_pin_name(pinfunc),
-	          (value) ? "high" : "low", (inverted) ? "low" : "high");
+	pdata->pin_value = SET_BITS_0(pdata->pin_value, pgm, pinfunc, value);
 
-	/* set bits depending on value */
-	//tval = (pdata->pin_value & (~pin_mask)) | pin_mask;
-	pdata->pin_value ^= (-value ^ pdata->pin_value) & pin_mask;
-	//fprintf(stderr, "%x %x\n", tval, pdata->pin_value);
-	
-	return write_flush(pdata);
-}
-
-/*
- * This function sets or clears a group of pins - VCC or BUFF.
- * the semantics are the same as for single pins, described above.
- */
-static int set_pins(PROGRAMMER * pgm, int pinfunc, int value)
-{
-	int pin, pin_mask;
-	int inverted;
-	int pin_bit;
-	
-	avrftdi_t* pdata = to_pdata(pgm);
-
-	pin = pgm->pinno[pinfunc] & PIN_MASK;
-	inverted = pgm->pinno[pinfunc] & PIN_INVERSE;
-
-	pin_mask = pin >> 1;
-	
-	value = (inverted) ? !value : !!value;
-
-	if (!pin) {
-		/* dito above */
-		return 1;
-	}
-
-	if(value)
-		value = pin_mask;
-
-	/* conditional output */
-	for(pin = 0; (1 << pin) & (PIN_MASK); pin++)
-	{
-		pin_bit = 1 << pin;
-
-		/* skip if pin is not set */
-		if(!(pin_bit & pin_mask))
-			continue;
-
-		/* remember, we count from 1, not 0 */
-		log_debug("Setting pin %d (%s) as %s: %s (%s active)\n", pin + 1,
-		          ftdi_pin_name(pdata, pin+1), avr_pin_name(pinfunc),
-			        (value) ? "high" : "low", (inverted) ? "low": "high");
-	}
-
-	/* set bits depending on value */
-	/*pin_value ^= (-value ^ pin_value) & (1 << (pin - 1));  */
-	pdata->pin_value ^= (-value ^ pdata->pin_value) & pin_mask;
-
-	/*pdata->pin_value = (pdata->pin_value & (~pin_mask)) | value;*/
-	
 	return write_flush(pdata);
 }
 
@@ -656,6 +449,83 @@ static int write_flush(avrftdi_t* pdata)
 
 }
 
+static int avrftdi_pin_setup(PROGRAMMER * pgm)
+{
+	/*************
+	 * pin setup *
+	 *************/
+
+	int pin;
+
+	avrftdi_t* pdata = to_pdata(pgm);
+
+	/* SCK/MOSI/MISO are fixed and not invertable?*/
+	/* TODO: inverted SCK/MISO/MOSI */
+	static const struct pindef_t valid_pins_SCK  = {{0x01},{0x00}} ;
+	static const struct pindef_t valid_pins_MOSI = {{0x02},{0x00}} ;
+	static const struct pindef_t valid_pins_MISO = {{0x04},{0x00}} ;
+
+	/* value for 8/12/16 bit wide interface for other pins */
+	int valid_mask = ((1 << pdata->pin_limit) - 1);
+	/* mask out SCK/MISO/MOSI */
+	valid_mask &= ~((1 << FTDI_SCK) | (1 << FTDI_MOSI) | (1 << FTDI_MISO));
+
+	log_debug("Using valid mask: 0x%08x\n", valid_mask);
+	static struct pindef_t valid_pins_others;
+	valid_pins_others.mask[0] = valid_mask;
+	valid_pins_others.inverse[0] = valid_mask ;
+
+	/* build pin checklist */
+	for(pin = PPI_AVR_VCC; pin < N_PINS; ++pin) {
+		/* unfortunately, the pin name enum is one-based */
+		pdata->pin_checklist[pin - 1].pinname = pin;
+		pdata->pin_checklist[pin - 1].mandatory = 0;
+		pdata->pin_checklist[pin - 1].valid_pins = &valid_pins_others;
+	}
+	pdata->pin_checklist[PIN_AVR_SCK - 1].mandatory = 1;
+	pdata->pin_checklist[PIN_AVR_SCK - 1].valid_pins = &valid_pins_SCK;
+	pdata->pin_checklist[PIN_AVR_MOSI - 1].mandatory = 1;
+	pdata->pin_checklist[PIN_AVR_MOSI - 1].valid_pins = &valid_pins_MOSI;
+	pdata->pin_checklist[PIN_AVR_MISO - 1].mandatory = 1;
+	pdata->pin_checklist[PIN_AVR_MISO - 1].valid_pins = &valid_pins_MISO;
+
+
+	/* everything is an output, except MISO */
+	for(pin = PPI_AVR_VCC; pin < N_PINS; ++pin) {
+		pdata->pin_direction |= pgm->pin[pin].mask[0];
+		pdata->pin_value = SET_BITS_0(pdata->pin_value, pgm, pin, OFF);
+	}
+	pdata->pin_direction &= ~pgm->pin[PIN_AVR_MISO].mask[0];
+
+	for(pin = PIN_LED_ERR; pin < N_PINS; ++pin) {
+		pdata->led_mask |= pgm->pin[pin].mask[0];
+	}
+
+	/* assumes all checklists above have same number of entries */
+	if (pins_check(pgm, pdata->pin_checklist,N_PINS - 1)) {
+		log_err("Pin configuration for FTDI MPSSE must be:\n");
+		log_err("%s: 0, %s: 1, %s: 2 (is: %s, %s, %s)\n", avr_pin_name(PIN_AVR_SCK),
+		         avr_pin_name(PIN_AVR_MOSI), avr_pin_name(PIN_AVR_MISO),
+						 pins_to_str(&pgm->pin[PIN_AVR_SCK]),
+						 pins_to_str(&pgm->pin[PIN_AVR_MOSI]),
+						 pins_to_str(&pgm->pin[PIN_AVR_MISO]));
+		log_err("Please correct your cabling and/or configuration.\n");
+		log_err("If your hardware is fixed, consider using a bitbang programmer.\n");
+
+		return -1;
+	}
+
+	/*
+	 * TODO: No need to fail for a wrongly configured led or something.
+	 * Maybe we should only fail for SCK; MISO, MOSI, RST (and probably
+	 * VCC and BUFF).
+	 */
+
+	log_info("Pin direction mask: %04x\n", pdata->pin_direction);
+	log_info("Pin value mask: %04x\n", pdata->pin_value);
+
+	return 0;
+}
 
 static int avrftdi_open(PROGRAMMER * pgm, char *port)
 {
@@ -743,38 +613,6 @@ static int avrftdi_open(PROGRAMMER * pgm, char *port)
 		set_frequency(pdata, pgm->baudrate ? pgm->baudrate : 150000);
 	}
 
-	/*************
-	 * pin setup *
-	 *************/
-
-	if ( FTDI_SCK != pgm->pinno[PIN_AVR_SCK]
-		|| FTDI_MOSI != pgm->pinno[PIN_AVR_MOSI]
-		|| FTDI_MISO != pgm->pinno[PIN_AVR_MISO])
-	{
-		log_warn("Pin configuration for FTDI MPSSE must be:\n");
-		log_warn("%s: 1, %s: 2, %s: 3(is: %d,%d,%d)\n", avr_pin_name(PIN_AVR_SCK),
-		         avr_pin_name(PIN_AVR_MOSI), avr_pin_name(PIN_AVR_MISO),
-						 pgm->pinno[PIN_AVR_SCK],	pgm->pinno[PIN_AVR_MOSI],
-						 pgm->pinno[PIN_AVR_MISO]);
-
-		log_warn("Setting pins accordingly ...\n");
-			pgm->pinno[PIN_AVR_SCK] = FTDI_SCK;
-			pgm->pinno[PIN_AVR_MOSI] = FTDI_MOSI;
-			pgm->pinno[PIN_AVR_MISO] = FTDI_MISO;
-	}
-	
-	log_info("RESET pin value: %x\n", pgm->pinno[PIN_AVR_RESET]-1);
-
-	if ( pgm->pinno[PIN_AVR_RESET] < FTDI_RESET
-		|| pgm->pinno[PIN_AVR_RESET] == 0)
-	{
-		log_warn("RESET pin clashes with data pin or is not set.\n");
-		log_warn("Setting to default-value 4\n");
-		pgm->pinno[PIN_AVR_RESET] = FTDI_RESET;
-	}
-	
-	//pdata->pin_direction = (0x3 | (1 << (pgm->pinno[PIN_AVR_RESET] - 1)));
-
 	/* set pin limit depending on chip type */
 	switch(pdata->ftdic->type) {
 		case TYPE_AM:
@@ -784,44 +622,30 @@ static int avrftdi_open(PROGRAMMER * pgm, char *port)
 			log_err("cannot work with your chip. Try the 'synbb' programmer.\n");
 			return -1;
 		case TYPE_2232C:
-			pdata->pin_limit = 11;
+			pdata->pin_limit = 12;
 			pdata->rx_buffer_size = 384;
 			break;
 		case TYPE_2232H:
-			pdata->pin_limit = 15;
+			pdata->pin_limit = 16;
 			pdata->rx_buffer_size = 4096;
 			break;
 		case TYPE_232H:
-			pdata->pin_limit = 15;
+			pdata->pin_limit = 16;
 			pdata->rx_buffer_size = 1024;
 			break;
 		case TYPE_4232H:
-			pdata->pin_limit = 7;
+			pdata->pin_limit = 8;
 			pdata->rx_buffer_size = 2048;
 			break;
 		default:
 			log_warn("Found unkown device %x. I will do my ", pdata->ftdic->type);
 			log_warn("best to work with it, but no guarantees ...\n");
-			pdata->pin_limit = 7;
+			pdata->pin_limit = 8;
 			pdata->rx_buffer_size = pdata->ftdic->max_packet_size;
 			break;
 	}
 	
-	/* add SCK, MOSI and RESET as output pins - MISO needs no configuration */
-	if (add_pin(pgm, PIN_AVR_SCK)) return -1;
-	if (add_pin(pgm, PIN_AVR_MOSI)) return -1;
-	if (add_pin(pgm, PIN_AVR_RESET)) return -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;
-
-	log_info("Pin direction mask: %04x\n", pdata->pin_direction);
-	log_info("Pin value mask: %04x\n", pdata->pin_value);
+	avrftdi_pin_setup(pgm);
 
 	/**********************************************
 	 * set the ready LED and set our direction up *
@@ -838,13 +662,13 @@ static void avrftdi_close(PROGRAMMER * pgm)
 	avrftdi_t* pdata = to_pdata(pgm);
 
 	if(pdata->ftdic->usb_dev) {
-		set_pins(pgm, PPI_AVR_BUFF, ON);
+		set_pin(pgm, PPI_AVR_BUFF, ON);
 		set_pin(pgm, PIN_AVR_RESET, ON);
 
 		/* Stop driving the pins - except for the LEDs */
 		log_info("LED Mask=0x%04x value =0x%04x &=0x%04x\n",
 				pdata->led_mask, pdata->pin_value, pdata->led_mask & pdata->pin_value);
-		
+
 		pdata->pin_direction = pdata->led_mask;
 		pdata->pin_value &= pdata->led_mask;
 		write_flush(pdata);
@@ -868,7 +692,7 @@ static int avrftdi_initialize(PROGRAMMER * pgm, AVRPART * p)
 	else
 	{
 		set_pin(pgm, PIN_AVR_RESET, OFF);
-		set_pins(pgm, PPI_AVR_BUFF, OFF);
+		set_pin(pgm, PPI_AVR_BUFF, OFF);
 		set_pin(pgm, PIN_AVR_SCK, OFF);
 		/*use speed optimization with CAUTION*/
 		usleep(20 * 1000);
@@ -1298,8 +1122,6 @@ void avrftdi_initpgm(PROGRAMMER * pgm)
 
 	strcpy(pgm->type, "avrftdi");
 
-	pgm_fill_old_pins(pgm); // TODO to be removed if old pin data no longer needed
-
 	/*
 	 * mandatory functions
 	 */
diff --git a/avrdude/avrftdi_private.h b/avrdude/avrftdi_private.h
index 0087db22..21bf1f4f 100644
--- a/avrdude/avrftdi_private.h
+++ b/avrdude/avrftdi_private.h
@@ -10,6 +10,7 @@
 #include <libftdi1/ftdi.h>
 
 #include "pgm.h"
+#include "pindefs.h"
 
 enum { ERR, WARN, INFO, DEBUG, TRACE };
 
@@ -64,6 +65,8 @@ typedef struct avrftdi_s {
 	int pin_limit;
 	/* internal RX buffer of the device. needed for INOUT transfers */
 	int rx_buffer_size;
+	/* pin checklist. */
+ struct pin_checklist_t pin_checklist[N_PINS - 1];
 } avrftdi_t;
 
 void avrftdi_log(int level, const char * func, int line, const char * fmt, ...);