From 751b96182c41218b571cd499b1f34e3f9b900c7e Mon Sep 17 00:00:00 2001
From: rliebscher <rliebscher@81a1dc3b-b13d-400b-aceb-764788c761c2>
Date: Tue, 31 Jan 2012 17:03:43 +0000
Subject: [PATCH] Parser does not need to know all programmer types now, new
 programmers will update only the table in pgm_type.c.   * config_gram.y,
 lexer.l: removed programmer type keywords,     use now
 locate_programmer_type() function   * pgm_type.[ch]: added new files for
 table of programmer types   * main.c: allow list of programmer types by -c
 ?type   * avrdude.conf.in: changed all type keywords to quoted strings   *
 doc/avrdude.texi: changed description of type definition, list     of valid
 types is now included from generated file   * doc/Makefile.am: generate list
 of programmer types for doc   * all programmers [hc]: add xxx_desc string for
 description of programmer

git-svn-id: svn://svn.savannah.nongnu.org/avrdude/trunk/avrdude@1051 81a1dc3b-b13d-400b-aceb-764788c761c2
---
 ChangeLog        |  14 +++++
 Makefile.am      |   2 +
 arduino.c        |   5 +-
 arduino.h        |   1 +
 avr910.c         |   1 +
 avr910.h         |   1 +
 avrdude.conf.in  | 118 ++++++++++++++++++++--------------------
 avrftdi.c        |   2 +
 avrftdi.h        |   1 +
 buspirate.c      |   1 +
 buspirate.h      |   1 +
 butterfly.c      |   3 +
 butterfly.h      |   2 +
 config.c         |  15 +++--
 config_gram.y    |  94 +++++++-------------------------
 doc/.cvsignore   |   1 +
 doc/Makefile.am  |  16 ++++--
 doc/avrdude.texi |  34 +-----------
 jtagmkI.c        |   2 +
 jtagmkI.h        |   1 +
 jtagmkII.c       |  11 ++++
 jtagmkII.h       |   7 +++
 lexer.l          |  40 ++------------
 lists.c          |   2 +-
 lists.h          |   2 +-
 main.c           |  28 +++++++++-
 par.c            |   3 +
 par.h            |   1 +
 pgm_type.c       | 139 +++++++++++++++++++++++++++++++++++++++++++++++
 pgm_type.h       |  51 +++++++++++++++++
 serbb.h          |   1 +
 serbb_posix.c    |   3 +
 serbb_win32.c    |   3 +
 stk500.c         |   2 +
 stk500.h         |   1 +
 stk500generic.c  |   2 +
 stk500generic.h  |   1 +
 stk500v2.c       |  20 +++++++
 stk500v2.h       |  10 ++++
 usbasp.c         |   3 +
 usbasp.h         |   1 +
 usbtiny.c        |   5 +-
 usbtiny.h        |   1 +
 wiring.c         |   3 +
 wiring.h         |   1 +
 45 files changed, 442 insertions(+), 214 deletions(-)
 create mode 100644 pgm_type.c
 create mode 100644 pgm_type.h

diff --git a/ChangeLog b/ChangeLog
index 5446e698..22437fcd 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,17 @@
+2012-01-31  Rene Liebscher <R.Liebscher@gmx.de>
+
+	Parser does not need to know all programmer types now, new programmers
+	will update only the table in pgm_type.c.
+	* config_gram.y, lexer.l: removed programmer type keywords,
+	use now locate_programmer_type() function
+	* pgm_type.[ch]: added new files for table of programmer types
+	* main.c: allow list of programmer types by -c ?type
+	* avrdude.conf.in: changed all type keywords to quoted strings
+	* doc/avrdude.texi: changed description of type definition, list
+	of valid types is now included from generated file
+	* doc/Makefile.am: generate list of programmer types for doc
+	* all programmers [hc]: add xxx_desc string for description of programmer
+
 2012-01-30  Rene Liebscher <R.Liebscher@gmx.de>
 
 	* configure.ac: fixed detection of yylex_destroy availability
diff --git a/Makefile.am b/Makefile.am
index 343a56dc..f4ef4db3 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -125,6 +125,8 @@ libavrdude_a_SOURCES = \
 	par.h \
 	pgm.c \
 	pgm.h \
+	pgm_type.c \
+	pgm_type.h \
 	pindefs.h \
 	ppi.c \
 	ppi.h \
diff --git a/arduino.c b/arduino.c
index 6ab8a4b2..5e866da6 100644
--- a/arduino.c
+++ b/arduino.c
@@ -37,6 +37,7 @@
 #include "stk500_private.h"
 #include "stk500.h"
 #include "serial.h"
+#include "arduino.h"
 
 /* read signature bytes - arduino version */
 static int arduino_read_sig_bytes(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m)
@@ -116,9 +117,11 @@ static void arduino_close(PROGRAMMER * pgm)
   pgm->fd.ifd = -1;
 }
 
+const char arduino_desc[] = "Arduino programmer";
+
 void arduino_initpgm(PROGRAMMER * pgm)
 {
-	/* This is mostly a STK500; just the signature is read
+  /* This is mostly a STK500; just the signature is read
      differently than on real STK500v1 
      and the DTR signal is set when opening the serial port
      for the Auto-Reset feature */
diff --git a/arduino.h b/arduino.h
index a5819ee1..11c419e5 100644
--- a/arduino.h
+++ b/arduino.h
@@ -22,6 +22,7 @@
 #ifndef arduino_h__
 #define arduino_h__
 
+extern const char arduino_desc[];
 void arduino_initpgm (PROGRAMMER * pgm);
 
 #endif
diff --git a/avr910.c b/avr910.c
index 40f57d02..0642da16 100644
--- a/avr910.c
+++ b/avr910.c
@@ -744,6 +744,7 @@ static int avr910_read_sig_bytes(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m)
   return 3;
 }
 
+const char avr910_desc[] = "Serial programmers using protocol described in application note AVR910";
 
 void avr910_initpgm(PROGRAMMER * pgm)
 {
diff --git a/avr910.h b/avr910.h
index ed8b2c56..34ff0d53 100644
--- a/avr910.h
+++ b/avr910.h
@@ -28,6 +28,7 @@
 extern "C" {
 #endif
 
+extern const char avr910_desc[];
 void avr910_initpgm (PROGRAMMER * pgm);
 
 #ifdef __cplusplus
diff --git a/avrdude.conf.in b/avrdude.conf.in
index 66ed08ec..5f5c9532 100644
--- a/avrdude.conf.in
+++ b/avrdude.conf.in
@@ -344,14 +344,14 @@ default_serial     = "@DEFAULT_SER_PORT@";
 programmer
   id    = "wiring";
   desc  = "Wiring";
-  type  = wiring;
+  type  = "wiring";
   connection_type = serial;
 ;
 
 programmer
   id    = "arduino";
   desc  = "Arduino";
-  type  = arduino;
+  type  = "arduino";
   connection_type = serial;
 ;
 # this will interface with the chips on these programmers:
@@ -372,7 +372,7 @@ programmer
 programmer
   id         = "avrftdi";
   desc       = "FT2232D based generic programmer";
-  type       = avrftdi;
+  type       = "avrftdi";
   connection_type = usb;
   usbvid     = 0x0403;
   usbpid     = 0x6010;
@@ -400,7 +400,7 @@ programmer
 programmer
   id         = "2232HIO";
   desc       = "FT2232H based generic programmer";
-  type       = avrftdi;
+  type       = "avrftdi";
   connection_type = usb;
   usbvid     = 0x0403;
 # Note: This PID is reserved for generic H devices and 
@@ -427,7 +427,7 @@ programmer
 programmer
   id         = "jtagkey";
   desc       = "Amontec JTAGKey, JTAGKey-Tiny and JTAGKey2";
-  type       = avrftdi;
+  type       = "avrftdi";
   connection_type = usb;
   usbvid     = 0x0403;
 # Note: This PID is used in all JTAGKey variants
@@ -473,21 +473,21 @@ programmer parent "jtagkey"
 programmer
   id    = "avrisp";
   desc  = "Atmel AVR ISP";
-  type  = stk500;
+  type  = "stk500";
   connection_type = serial;
 ;
 
 programmer
   id    = "avrispv2";
   desc  = "Atmel AVR ISP V2";
-  type  =  stk500v2;
+  type  =  "stk500v2";
   connection_type = serial;
 ;
 
 programmer
   id    = "avrispmkII";
   desc  = "Atmel AVR ISP mkII";
-  type  =  stk500v2;
+  type  =  "stk500v2";
   connection_type = usb;
 ;
 
@@ -498,7 +498,7 @@ programmer parent "avrispmkII"
 programmer
   id    = "buspirate";
   desc  = "The Bus Pirate";
-  type  = buspirate;
+  type  = "buspirate";
   connection_type = serial;
 ;
 
@@ -509,77 +509,77 @@ programmer
 programmer
   id    = "stk500";
   desc  = "Atmel STK500";
-  type  = stk500generic;
+  type  = "stk500generic";
   connection_type = serial;
 ;
 
 programmer
   id    = "stk500v1";
   desc  = "Atmel STK500 Version 1.x firmware";
-  type  = stk500;
+  type  = "stk500";
   connection_type = serial;
 ;
 
 programmer
   id    = "mib510";
   desc  = "Crossbow MIB510 programming board";
-  type  = stk500;
+  type  = "stk500";
   connection_type = serial;
 ;
 
 programmer
   id    = "stk500v2";
   desc  = "Atmel STK500 Version 2.x firmware";
-  type  = stk500v2;
+  type  = "stk500v2";
   connection_type = serial;
 ;
 
 programmer
   id    = "stk500pp";
   desc  = "Atmel STK500 V2 in parallel programming mode";
-  type  = stk500pp;
+  type  = "stk500pp";
   connection_type = serial;
 ;
 
 programmer
   id    = "stk500hvsp";
   desc  = "Atmel STK500 V2 in high-voltage serial programming mode";
-  type  = stk500hvsp;
+  type  = "stk500hvsp";
   connection_type = serial;
 ;
 
 programmer
   id    = "stk600";
   desc  = "Atmel STK600";
-  type  = stk600;
+  type  = "stk600";
   connection_type = usb;
 ;
 
 programmer
   id    = "stk600pp";
   desc  = "Atmel STK600 in parallel programming mode";
-  type  = stk600pp;
+  type  = "stk600pp";
   connection_type = usb;
 ;
 
 programmer
   id    = "stk600hvsp";
   desc  = "Atmel STK600 in high-voltage serial programming mode";
-  type  = stk600hvsp;
+  type  = "stk600hvsp";
   connection_type = usb;
 ;
 
 programmer
   id    = "avr910";
   desc  = "Atmel Low Cost Serial Programmer";
-  type  = avr910;
+  type  = "avr910";
   connection_type = serial;
 ;
 
 programmer
   id    = "usbasp";
   desc  = "USBasp, http://www.fischl.de/usbasp/";
-  type  = usbasp;
+  type  = "usbasp";
   connection_type = usb;
   usbvid     = 0x16C0; # VOTI
   usbpid     = 0x05DC; # Obdev's free shared PID
@@ -604,7 +604,7 @@ programmer
 programmer
   id    = "nibobee";
   desc  = "NIBObee";
-  type  = usbasp;
+  type  = "usbasp";
   connection_type = usb;
   usbvid     = 0x16C0; # VOTI
   usbpid     = 0x092F; # NIBObee PID
@@ -615,7 +615,7 @@ programmer
 programmer
   id    = "usbasp-clone";
   desc  = "Any usbasp clone with correct VID/PID";
-  type  = usbasp;
+  type  = "usbasp";
   connection_type = usb;
   usbvid    = 0x16C0; # VOTI
   usbpid    = 0x05DC; # Obdev's free shared PID
@@ -626,28 +626,28 @@ programmer
 programmer
   id    = "usbtiny";
   desc  = "USBtiny simple USB programmer, http://www.ladyada.net/make/usbtinyisp/";
-  type  = usbtiny;
+  type  = "usbtiny";
   connection_type = usb;
 ;
 
 programmer
   id    = "butterfly";
   desc  = "Atmel Butterfly Development Board";
-  type  = butterfly;
+  type  = "butterfly";
   connection_type = serial;
 ;
 
 programmer
   id    = "avr109";
   desc  = "Atmel AppNote AVR109 Boot Loader";
-  type  = butterfly;
+  type  = "butterfly";
   connection_type = serial;
 ;
 
 programmer
   id    = "avr911";
   desc  = "Atmel AppNote AVR911 AVROSP";
-  type  = butterfly;
+  type  = "butterfly";
   connection_type = serial;
 ;
  
@@ -655,7 +655,7 @@ programmer
 programmer
   id    = "mkbutterfly";
   desc  = "Mikrokopter.de Butterfly";
-  type  = butterfly_mk;
+  type  = "butterfly_mk";
   connection_type = serial;
 ;
 
@@ -667,7 +667,7 @@ programmer
   id    = "jtagmkI";
   desc  = "Atmel JTAG ICE (mkI)";
   baudrate = 115200;    # default is 115200
-  type  = jtagmki;
+  type  = "jtagmki";
   connection_type = serial;
 ;
 
@@ -691,7 +691,7 @@ programmer
   id    = "jtagmkII";
   desc  = "Atmel JTAG ICE mkII";
   baudrate = 19200;    # default is 19200
-  type  = jtagmkii;
+  type  = "jtagmkii";
   connection_type = usb;
 ;
 
@@ -716,7 +716,7 @@ programmer
   id    = "jtag2isp";
   desc  = "Atmel JTAG ICE mkII in ISP mode";
   baudrate = 115200;
-  type  = jtagmkii_isp;
+  type  = "jtagmkii_isp";
   connection_type = usb;
 ;
 
@@ -725,7 +725,7 @@ programmer
   id    = "jtag2dw";
   desc  = "Atmel JTAG ICE mkII in debugWire mode";
   baudrate = 115200;
-  type  = jtagmkii_dw;
+  type  = "jtagmkii_dw";
   connection_type = usb;
 ;
 
@@ -734,7 +734,7 @@ programmer
   id    = "jtagmkII_avr32";
   desc  = "Atmel JTAG ICE mkII im AVR32 mode";
   baudrate = 115200;
-  type  = jtagmkii_avr32;
+  type  = "jtagmkii_avr32";
   connection_type = usb;
 ;
 
@@ -743,7 +743,7 @@ programmer
   id    = "jtag2avr32";
   desc  = "Atmel JTAG ICE mkII im AVR32 mode";
   baudrate = 115200;
-  type  = jtagmkii_avr32;
+  type  = "jtagmkii_avr32";
   connection_type = usb;
 ;
 
@@ -752,7 +752,7 @@ programmer
   id    = "jtag2pdi";
   desc  = "Atmel JTAG ICE mkII PDI mode";
   baudrate = 115200;
-  type  = jtagmkii_pdi;
+  type  = "jtagmkii_pdi";
   connection_type = usb;
 ;
 
@@ -761,7 +761,7 @@ programmer
   id    = "dragon_jtag";
   desc  = "Atmel AVR Dragon in JTAG mode";
   baudrate = 115200;
-  type  = dragon_jtag;
+  type  = "dragon_jtag";
   connection_type = usb;
 ;
 
@@ -770,7 +770,7 @@ programmer
   id    = "dragon_isp";
   desc  = "Atmel AVR Dragon in ISP mode";
   baudrate = 115200;
-  type  = dragon_isp;
+  type  = "dragon_isp";
   connection_type = usb;
 ;
 
@@ -779,7 +779,7 @@ programmer
   id    = "dragon_pp";
   desc  = "Atmel AVR Dragon in PP mode";
   baudrate = 115200;
-  type  = dragon_pp;
+  type  = "dragon_pp";
   connection_type = usb;
 ;
 
@@ -788,7 +788,7 @@ programmer
   id    = "dragon_hvsp";
   desc  = "Atmel AVR Dragon in HVSP mode";
   baudrate = 115200;
-  type  = dragon_hvsp;
+  type  = "dragon_hvsp";
   connection_type = usb;
 ;
 
@@ -797,7 +797,7 @@ programmer
   id    = "dragon_dw";
   desc  = "Atmel AVR Dragon in debugWire mode";
   baudrate = 115200;
-  type  = dragon_dw;
+  type  = "dragon_dw";
   connection_type = usb;
 ;
 
@@ -806,14 +806,14 @@ programmer
   id    = "dragon_pdi";
   desc  = "Atmel AVR Dragon in PDI mode";
   baudrate = 115200;
-  type  = dragon_pdi;
+  type  = "dragon_pdi";
   connection_type = usb;
 ;
 
 programmer
   id    = "pavr";
   desc  = "Jason Kyle's pAVR Serial Programmer";
-  type  = avr910;
+  type  = "avr910";
   connection_type = serial;
 ;
 
@@ -823,7 +823,7 @@ programmer
 programmer
   id    = "bsd";
   desc  = "Brian Dean's Programmer, http://www.bsdhome.com/avrdude/";
-  type  = par;
+  type  = "par";
   connection_type = parallel;
   vcc   = 2, 3, 4, 5;
   reset = 7;
@@ -835,7 +835,7 @@ programmer
 programmer
   id    = "stk200";
   desc  = "STK200";
-  type  = par;
+  type  = "par";
   connection_type = parallel;
   buff  = 4, 5;
   sck   = 6;
@@ -858,7 +858,7 @@ programmer parent "stk200"
 programmer
   id    = "dt006";
   desc  = "Dontronics DT006";
-  type  = par;
+  type  = "par";
   connection_type = parallel;
   reset = 4;
   sck   = 5;
@@ -874,7 +874,7 @@ programmer parent "dt006"
 programmer
   id     = "alf";
   desc   = "Nightshade ALF-PgmAVR, http://nightshade.homeip.net/";
-  type   = par;
+  type   = "par";
   connection_type = parallel;
   vcc    = 2, 3, 4, 5;
   buff   = 6;
@@ -891,7 +891,7 @@ programmer
 programmer
   id    = "sp12";
   desc  = "Steve Bolt's Programmer";
-  type  = par;
+  type  = "par";
   connection_type = parallel;
   vcc   = 4,5,6,7,8;
   reset = 3;
@@ -903,7 +903,7 @@ programmer
 programmer
   id     = "picoweb";
   desc   = "Picoweb Programming Cable, http://www.picoweb.net/";
-  type   = par;
+  type   = "par";
   connection_type = parallel;
   reset  = 2;
   sck    = 3;
@@ -914,7 +914,7 @@ programmer
 programmer
   id    = "abcmini";
   desc  = "ABCmini Board, aka Dick Smith HOTCHIP";
-  type  = par;
+  type  = "par";
   connection_type = parallel;
   reset = 4;
   sck   = 3;
@@ -925,7 +925,7 @@ programmer
 programmer
   id    = "futurlec";
   desc  = "Futurlec.com programming cable.";
-  type  = par;
+  type  = "par";
   connection_type = parallel;
   reset = 3;
   sck   = 2;
@@ -944,7 +944,7 @@ programmer
 programmer
   id    = "xil";
   desc  = "Xilinx JTAG cable";
-  type  = par;
+  type  = "par";
   connection_type = parallel;
   mosi  = 2;
   sck   = 3;
@@ -958,7 +958,7 @@ programmer
 programmer
   id = "dapa";
   desc = "Direct AVR Parallel Access cable";
-  type = par;
+  type = "par";
   connection_type = parallel;
   vcc   = 3;
   reset = 16;
@@ -970,7 +970,7 @@ programmer
 programmer
   id    = "atisp";
   desc  = "AT-ISP V1.1 programming cable for AVR-SDK1 from <http://micro-research.co.th/> micro-research.co.th";
-  type  = par;
+  type  = "par";
   connection_type = parallel;
   reset = ~6;
   sck   = ~8;
@@ -981,7 +981,7 @@ programmer
 programmer
   id    = "ere-isp-avr";
   desc  = "ERE ISP-AVR <http://www.ere.co.th/download/sch050713.pdf>";
-  type  = par;
+  type  = "par";
   connection_type = parallel;
   reset = ~4;
   sck   = 3;
@@ -992,7 +992,7 @@ programmer
 programmer
   id    = "blaster";
   desc  = "Altera ByteBlaster";
-  type  = par;
+  type  = "par";
   connection_type = parallel;
   sck   = 2;
   miso  = 11;
@@ -1015,7 +1015,7 @@ programmer parent "pony-stk200"
 programmer
   id = "89isp";
   desc = "Atmel at89isp cable";
-  type = par;
+  type = "par";
   connection_type = parallel;
   reset = 17;
   sck = 1;
@@ -1050,7 +1050,7 @@ programmer
 programmer
   id    = "ponyser";
   desc  = "design ponyprog serial, reset=!txd sck=rts mosi=dtr miso=cts";
-  type  = serbb;
+  type  = "serbb";
   connection_type = serial;
   reset = ~3;
   sck   = 7;
@@ -1072,7 +1072,7 @@ programmer parent "ponyser"
 programmer
   id    = "dasa";
   desc  = "serial port banging, reset=rts sck=dtr mosi=txd miso=cts";
-  type  = serbb;
+  type  = "serbb";
   connection_type = serial;
   reset = 7;
   sck   = 4;
@@ -1086,7 +1086,7 @@ programmer
 programmer
   id    = "dasa3";
   desc  = "serial port banging, reset=!dtr sck=rts mosi=txd miso=cts";
-  type  = serbb;
+  type  = "serbb";
   connection_type = serial;
   reset = ~4;
   sck   = 7;
@@ -1100,7 +1100,7 @@ programmer
 programmer
   id    = "c2n232i";
   desc  = "serial port banging, reset=dtr sck=!rts mosi=!txd miso=!cts";
-  type  = serbb;
+  type  = "serbb";
   connection_type = serial;
   reset = 4;
   sck   = ~7;
diff --git a/avrftdi.c b/avrftdi.c
index 558b7975..a6367c6a 100644
--- a/avrftdi.c
+++ b/avrftdi.c
@@ -1074,3 +1074,5 @@ void avrftdi_initpgm(PROGRAMMER * pgm)
 
 #endif /*HAVE_LIBUSB*/
 
+const char avrftdi_desc[] = "Interface to the MPSSE Engine of FTDI Chips using libftdi.";
+
diff --git a/avrftdi.h b/avrftdi.h
index b1ffc893..f31cf1b1 100644
--- a/avrftdi.h
+++ b/avrftdi.h
@@ -45,6 +45,7 @@ extern "C" {
 #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)); }
 
+extern const char avrftdi_desc[];
 void avrftdi_initpgm        (PROGRAMMER * pgm);
 
 #ifdef __cplusplus
diff --git a/buspirate.c b/buspirate.c
index 090b54c8..ecbeff2e 100644
--- a/buspirate.c
+++ b/buspirate.c
@@ -775,6 +775,7 @@ static void buspirate_teardown(struct programmer_t *pgm)
 {
 	free(pgm->cookie);
 }
+const char buspirate_desc[] = "Using the Bus Pirate's SPI interface for programming";
 
 void buspirate_initpgm(struct programmer_t *pgm)
 {
diff --git a/buspirate.h b/buspirate.h
index a0d6095f..7e9de78d 100644
--- a/buspirate.h
+++ b/buspirate.h
@@ -25,6 +25,7 @@
 #ifndef buspirate_h
 #define buspirate_h
 
+extern const char buspirate_desc[];
 void buspirate_initpgm (struct programmer_t *pgm);
 
 #endif
diff --git a/butterfly.c b/butterfly.c
index 014f3ff3..5b070dd1 100644
--- a/butterfly.c
+++ b/butterfly.c
@@ -696,6 +696,7 @@ static int butterfly_read_sig_bytes(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m)
   return 3;
 }
 
+const char butterfly_desc[] = "Atmel Butterfly evaluation board; Atmel AppNotes AVR109, AVR911";
 
 void butterfly_initpgm(PROGRAMMER * pgm)
 {
@@ -735,6 +736,8 @@ void butterfly_initpgm(PROGRAMMER * pgm)
   pgm->flag = 0;
 }
 
+const char butterfly_mk_desc[] = "Mikrokopter.de Butterfly";
+
 void butterfly_mk_initpgm(PROGRAMMER * pgm)
 {
   butterfly_initpgm(pgm);
diff --git a/butterfly.h b/butterfly.h
index aa4c58c7..d698f565 100644
--- a/butterfly.h
+++ b/butterfly.h
@@ -26,6 +26,8 @@
 extern "C" {
 #endif
 
+extern const char butterfly_desc[];
+extern const char butterfly_mk_desc[];
 void butterfly_initpgm (PROGRAMMER * pgm);
 void butterfly_mk_initpgm (PROGRAMMER * pgm);
 
diff --git a/config.c b/config.c
index 8a13befb..838a226e 100644
--- a/config.c
+++ b/config.c
@@ -57,10 +57,10 @@ extern char * yytext;
 
 void cleanup_config(void)
 {
-  ldestroy_cb(part_list,avr_free_part);
-  ldestroy_cb(programmers,pgm_free);
-  ldestroy_cb(string_list,free_token);
-  ldestroy_cb(number_list,free_token);
+  ldestroy_cb(part_list, (void(*)(void*))avr_free_part);
+  ldestroy_cb(programmers, (void(*)(void*))pgm_free);
+  ldestroy_cb(string_list, (void(*)(void*))free_token);
+  ldestroy_cb(number_list, (void(*)(void*))free_token);
 }
 
 int init_config(void)
@@ -89,7 +89,7 @@ int yywrap()
 
 int yyerror(char * errmsg)
 {
-  fprintf(stderr, "%s at %s:%d\n", errmsg, infile, lineno);
+  fprintf(stderr, "%s: %s at %s:%d\n", progname, errmsg, infile, lineno);
   exit(1);
 }
 
@@ -291,6 +291,11 @@ char * dup_string(const char * str)
   return s;
 }
 
+#ifdef HAVE_YYLEX_DESTROY
+/* reset lexer and free any allocated memory */
+extern int yylex_destroy(void);
+#endif
+
 int read_config(const char * file)
 {
   FILE * f;
diff --git a/config_gram.y b/config_gram.y
index 68e584bd..b20d545a 100644
--- a/config_gram.y
+++ b/config_gram.y
@@ -36,20 +36,8 @@
 #include "pindefs.h"
 #include "ppi.h"
 #include "pgm.h"
-#include "stk500.h"
-#include "arduino.h"
-#include "buspirate.h"
-#include "stk500v2.h"
-#include "wiring.h"
-#include "stk500generic.h"
-#include "avr910.h"
-#include "butterfly.h"
-#include "usbasp.h"
-#include "usbtiny.h"
+#include "pgm_type.h"
 #include "avr.h"
-#include "jtagmkI.h"
-#include "jtagmkII.h"
-#include "avrftdi.h"
 
 #if defined(WIN32NATIVE)
 #define strtok_r( _s, _sep, _lasts ) \
@@ -84,12 +72,9 @@ static int pin_name;
 %token K_PAGE_SIZE
 %token K_PAGED
 
-%token K_ARDUINO
-%token K_AVRFTDI
 %token K_BAUDRATE
 %token K_BS2
 %token K_BUFF
-%token K_BUSPIRATE
 %token K_CHIP_ERASE_DELAY
 %token K_CONNTYPE
 %token K_DEDICATED
@@ -99,12 +84,6 @@ static int pin_name;
 %token K_DEFAULT_BITCLOCK
 %token K_DESC
 %token K_DEVICECODE
-%token K_DRAGON_DW
-%token K_DRAGON_HVSP
-%token K_DRAGON_ISP
-%token K_DRAGON_JTAG
-%token K_DRAGON_PDI
-%token K_DRAGON_PP
 %token K_STK500_DEVCODE
 %token K_AVR910_DEVCODE
 %token K_EEPROM
@@ -112,12 +91,6 @@ static int pin_name;
 %token K_FLASH
 %token K_ID
 %token K_IO
-%token K_JTAG_MKI
-%token K_JTAG_MKII
-%token K_JTAG_MKII_AVR32
-%token K_JTAG_MKII_DW
-%token K_JTAG_MKII_ISP
-%token K_JTAG_MKII_PDI
 %token K_LOADPAGE
 %token K_MAX_WRITE_DELAY
 %token K_MIN_WRITE_DELAY
@@ -127,7 +100,6 @@ static int pin_name;
 %token K_NVM_BASE
 %token K_OFFSET
 %token K_PAGEL
-%token K_PAR
 %token K_PARALLEL
 %token K_PARENT
 %token K_PART
@@ -141,35 +113,20 @@ static int pin_name;
 %token K_READMEM
 %token K_RESET
 %token K_RETRY_PULSE
-%token K_SERBB
 %token K_SERIAL
 %token K_SCK
 %token K_SIGNATURE
 %token K_SIZE
-%token K_STK500
-%token K_STK500HVSP
-%token K_STK500PP
-%token K_STK500V2
-%token K_STK500GENERIC
-%token K_STK600
-%token K_STK600HVSP
-%token K_STK600PP
-%token K_AVR910
 %token K_USB
-%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_BUTTERFLY_MK
 %token K_TYPE
 %token K_VCC
 %token K_VFYLED
-%token K_WIRING
 
 %token K_NO
 %token K_YES
@@ -488,37 +445,24 @@ prog_parm_type:
 ;
 
 prog_parm_type_id:
-  K_PAR             { current_prog->initpgm = par_initpgm; } |
-  K_SERBB           { current_prog->initpgm = serbb_initpgm; } |
-  K_STK500          { current_prog->initpgm = stk500_initpgm; } |
-  K_STK500V2        { current_prog->initpgm = stk500v2_initpgm; } |
-  K_WIRING          { current_prog->initpgm = wiring_initpgm; } |
-  K_STK500HVSP      { current_prog->initpgm = stk500hvsp_initpgm; } |
-  K_STK500PP        { current_prog->initpgm = stk500pp_initpgm; } |
-  K_STK500GENERIC   { current_prog->initpgm = stk500generic_initpgm; } |
-  K_ARDUINO         { current_prog->initpgm = arduino_initpgm; } |
-  K_AVRFTDI         { current_prog->initpgm = avrftdi_initpgm; } |
-  K_BUSPIRATE       { current_prog->initpgm = buspirate_initpgm; } |
-  K_STK600          { current_prog->initpgm = stk600_initpgm; } |
-  K_STK600HVSP      { current_prog->initpgm = stk600hvsp_initpgm; } |
-  K_STK600PP        { current_prog->initpgm = stk600pp_initpgm; } |
-  K_AVR910          { current_prog->initpgm = avr910_initpgm; } |
-  K_USBASP          { current_prog->initpgm = usbasp_initpgm; } |
-  K_USBTINY         { current_prog->initpgm = usbtiny_initpgm; } |
-  K_BUTTERFLY       { current_prog->initpgm = butterfly_initpgm; } |
-  K_BUTTERFLY_MK    { current_prog->initpgm = butterfly_mk_initpgm; } |
-  K_JTAG_MKI        { current_prog->initpgm = jtagmkI_initpgm; } |
-  K_JTAG_MKII       { current_prog->initpgm = jtagmkII_initpgm; } |
-  K_JTAG_MKII_AVR32 { current_prog->initpgm = jtagmkII_avr32_initpgm; } |
-  K_JTAG_MKII_DW    { current_prog->initpgm = jtagmkII_dw_initpgm; } |
-  K_JTAG_MKII_ISP   { current_prog->initpgm = stk500v2_jtagmkII_initpgm; } |
-  K_JTAG_MKII_PDI   { current_prog->initpgm = jtagmkII_pdi_initpgm; } |
-  K_DRAGON_DW       { current_prog->initpgm = jtagmkII_dragon_dw_initpgm; } |
-  K_DRAGON_HVSP     { current_prog->initpgm = stk500v2_dragon_hvsp_initpgm; } |
-  K_DRAGON_ISP      { current_prog->initpgm = stk500v2_dragon_isp_initpgm; } |
-  K_DRAGON_JTAG     { current_prog->initpgm = jtagmkII_dragon_initpgm; } |
-  K_DRAGON_PDI      { current_prog->initpgm = jtagmkII_dragon_pdi_initpgm; } |
-  K_DRAGON_PP       { current_prog->initpgm = stk500v2_dragon_pp_initpgm; }
+  TKN_STRING        {
+  const struct programmer_type_t * pgm_type = locate_programmer_type($1->value.string);
+    if (pgm_type == NULL) {
+        fprintf(stderr,
+                "%s: error at %s:%d: programmer type %s not found\n",
+                progname, infile, lineno, $1->value.string);
+        exit(1);
+    }
+    current_prog->initpgm = pgm_type->initpgm;
+    free_token($1); 
+}
+  | error
+{
+        fprintf(stderr,
+                "%s: error at %s:%d: programmer type must be written as \"id_type\"\n",
+                progname, infile, lineno);
+        exit(1);
+}
 ;
 
 prog_parm_conntype:
diff --git a/doc/.cvsignore b/doc/.cvsignore
index 911e1eb0..99f4eabd 100644
--- a/doc/.cvsignore
+++ b/doc/.cvsignore
@@ -20,4 +20,5 @@ mdate-sh
 stamp-vti
 texinfo.tex
 version.texi
+programmer_types.texi
 parts.texi
diff --git a/doc/Makefile.am b/doc/Makefile.am
index 35b8f402..8481b213 100644
--- a/doc/Makefile.am
+++ b/doc/Makefile.am
@@ -23,6 +23,7 @@
 
 CLEANFILES = \
 	parts.texi \
+	programmer_types.texi \
 	version.texi \
 	stamp-vti
 
@@ -32,7 +33,7 @@ all-local: info html ps pdf
 
 html: avrdude-html/avrdude.html
 
-avrdude-html/avrdude.html: $(srcdir)/$(info_TEXINFOS) $(srcdir)/parts.texi
+avrdude-html/avrdude.html: $(srcdir)/$(info_TEXINFOS) $(srcdir)/parts.texi $(srcdir)/programmer_types.texi
 	texi2html -split_node $(srcdir)/$(info_TEXINFOS)
 	if [ -e ./avrdude.html -o -e ./avrdude_1.html ]; then \
 	 mkdir -p avrdude-html ; \
@@ -41,14 +42,21 @@ avrdude-html/avrdude.html: $(srcdir)/$(info_TEXINFOS) $(srcdir)/parts.texi
 	 mv -f avrdude avrdude-html; \
 	fi;
 
-avrdude.info: parts.texi
-avrdude.dvi: parts.texi
-avrdude.pdf: parts.texi
+avrdude.info: parts.texi programmer_types.texi
+avrdude.dvi: parts.texi programmer_types.texi
+avrdude.pdf: parts.texi programmer_types.texi
 
 # if it does not exist make this first
 ../avrdude$(EXEEXT):
 	$(MAKE) -C .. avrdude$(EXEEXT)
 
+programmer_types.texi: ../avrdude$(EXEEXT) ../avrdude.conf Makefile
+	../avrdude$(EXEEXT) -C ../avrdude.conf -c \?type 2>&1 \
+	| $(AWK) '$$2 ~ /^=$$/ {printf("@item @code{%s} @tab %s\n",$$1,gensub("[^=]+=[ \t]*","",1))}' \
+	| sed "s#<\?\(http://[^ \t,>]*\)>\?#@url{\1}#g" \
+	>programmer_types.texi
+
+
 parts.texi: ../avrdude$(EXEEXT) ../avrdude.conf parts_comments.txt Makefile
 	../avrdude$(EXEEXT) -C ../avrdude.conf -p \? 2>&1 \
 	| $(AWK) '$$2 ~ /^=$$/ {printf("@item @code{%s} @tab %s\n",$$1,$$3)}' \
diff --git a/doc/avrdude.texi b/doc/avrdude.texi
index 9135c91d..8c5538f4 100644
--- a/doc/avrdude.texi
+++ b/doc/avrdude.texi
@@ -1435,7 +1435,7 @@ programmer
     parent <id>                                 # <id> is a quoted string
     id       = <id1> [, <id2> [, <id3>] ...] ;  # <idN> are quoted strings
     desc     = <description> ;                  # quoted string
-    type     = par | stk500 | ... ;             # programmer type (see below for a list)
+    type     = "par" | "stk500" | ... ;         # programmer type (see below for a list)
     baudrate = <num> ;                          # baudrate for serial ports
     vcc      = <num1> [, <num2> ... ] ;         # pin number(s)
     buff     = <num1> [, <num2> ... ] ;         # pin number(s)
@@ -1467,37 +1467,7 @@ To invert a bit in the pin definitions, use @code{= ~ <num>}.
 Following programmer types are currently implemented:
 
 @multitable @columnfractions .25 .6
-@item @code{arduino}  @tab Arduino
-@item @code{avr910}  @tab avr910
-@item @code{avrftdi}  @tab avrftdi
-@item @code{buspirate}  @tab BusPirate
-@item @code{butterfly}  @tab butterfly
-@item @code{butterfly_mk}  @tab butterfly_mk
-@item @code{dragon_dw}  @tab DRAGON_DW
-@item @code{dragon_hvsp}  @tab DRAGON_HVSP
-@item @code{dragon_isp}  @tab DRAGON_ISP
-@item @code{dragon_jtag}  @tab DRAGON_JTAG
-@item @code{dragon_pdi}  @tab DRAGON_PDI
-@item @code{dragon_pp}  @tab DRAGON_PP
-@item @code{jtagmki}  @tab JTAGMKI
-@item @code{jtagmkii}  @tab JTAGMKII
-@item @code{jtagmkii_avr32}  @tab JTAGMKII_AVR32
-@item @code{jtagmkii_dw}  @tab JTAGMKII_DW
-@item @code{jtagmkii_isp}  @tab JTAGMKII_ISP
-@item @code{jtagmkii_pdi}  @tab JTAGMKII_PDI
-@item @code{par}  @tab PPI
-@item @code{serbb}  @tab SERBB
-@item @code{stk500}  @tab STK500
-@item @code{stk500generic}  @tab STK500GENERIC
-@item @code{stk500hvsp}  @tab STK500HVSP
-@item @code{stk500pp}  @tab STK500PP
-@item @code{stk500v2}  @tab STK500V2
-@item @code{stk600}  @tab STK600
-@item @code{stk600hvsp}  @tab STK600HVSP
-@item @code{stk600pp}  @tab STK600PP
-@item @code{usbasp}  @tab usbasp
-@item @code{usbtiny}  @tab USBtiny
-@item @code{wiring}  @tab Wiring
+@include programmer_types.texi
 @end multitable
 
 @c
diff --git a/jtagmkI.c b/jtagmkI.c
index c9521b52..62a48e51 100644
--- a/jtagmkI.c
+++ b/jtagmkI.c
@@ -37,6 +37,7 @@
 #include "avr.h"
 #include "crc16.h"
 #include "pgm.h"
+#include "jtagmkI.h"
 #include "jtagmkI_private.h"
 #include "serial.h"
 
@@ -1372,6 +1373,7 @@ static void jtagmkI_print_parms(PROGRAMMER * pgm)
   jtagmkI_print_parms1(pgm, "");
 }
 
+const char jtagmkI_desc[] = "Atmel JTAG ICE mkI";
 
 void jtagmkI_initpgm(PROGRAMMER * pgm)
 {
diff --git a/jtagmkI.h b/jtagmkI.h
index d6669b11..62fa4532 100644
--- a/jtagmkI.h
+++ b/jtagmkI.h
@@ -26,6 +26,7 @@
 extern "C" {
 #endif
 
+extern const char jtagmkI_desc[];
 void jtagmkI_initpgm (PROGRAMMER * pgm);
 
 #ifdef __cplusplus
diff --git a/jtagmkII.c b/jtagmkII.c
index bf2cb522..f3e54857 100644
--- a/jtagmkII.c
+++ b/jtagmkII.c
@@ -3577,6 +3577,8 @@ static int jtagmkII_flash_clear_pagebuffer32(PROGRAMMER * pgm)
 #pragma mark -
 #endif
 
+const char jtagmkII_desc[] = "Atmel JTAG ICE mkII";
+
 void jtagmkII_initpgm(PROGRAMMER * pgm)
 {
   strcpy(pgm->type, "JTAGMKII");
@@ -3609,6 +3611,8 @@ void jtagmkII_initpgm(PROGRAMMER * pgm)
   pgm->flag           = PGM_FL_IS_JTAG;
 }
 
+const char jtagmkII_dw_desc[] = "Atmel JTAG ICE mkII in debugWire mode";
+
 void jtagmkII_dw_initpgm(PROGRAMMER * pgm)
 {
   strcpy(pgm->type, "JTAGMKII_DW");
@@ -3639,6 +3643,7 @@ void jtagmkII_dw_initpgm(PROGRAMMER * pgm)
   pgm->flag           = PGM_FL_IS_DW;
 }
 
+const char jtagmkII_pdi_desc[] = "Atmel JTAG ICE mkII in PDI mode";
 
 void jtagmkII_pdi_initpgm(PROGRAMMER * pgm)
 {
@@ -3670,6 +3675,7 @@ void jtagmkII_pdi_initpgm(PROGRAMMER * pgm)
   pgm->flag           = PGM_FL_IS_PDI;
 }
 
+const char jtagmkII_dragon_desc[] = "Atmel AVR Dragon in JTAG mode";
 
 void jtagmkII_dragon_initpgm(PROGRAMMER * pgm)
 {
@@ -3703,6 +3709,7 @@ void jtagmkII_dragon_initpgm(PROGRAMMER * pgm)
   pgm->flag           = PGM_FL_IS_JTAG;
 }
 
+const char jtagmkII_dragon_dw_desc[] = "Atmel AVR Dragon in debugWire mode";
 
 void jtagmkII_dragon_dw_initpgm(PROGRAMMER * pgm)
 {
@@ -3734,6 +3741,8 @@ void jtagmkII_dragon_dw_initpgm(PROGRAMMER * pgm)
   pgm->flag           = PGM_FL_IS_DW;
 }
 
+const char jtagmkII_avr32_desc[] = "Atmel JTAG ICE mkII in AVR32 mode";
+
 void jtagmkII_avr32_initpgm(PROGRAMMER * pgm)
 {
   strcpy(pgm->type, "JTAGMKII_AVR32");
@@ -3766,6 +3775,8 @@ void jtagmkII_avr32_initpgm(PROGRAMMER * pgm)
   pgm->flag           = PGM_FL_IS_JTAG;
 }
 
+const char jtagmkII_dragon_pdi_desc[] = "Atmel AVR Dragon in PDI mode";
+
 void jtagmkII_dragon_pdi_initpgm(PROGRAMMER * pgm)
 {
   strcpy(pgm->type, "DRAGON_PDI");
diff --git a/jtagmkII.h b/jtagmkII.h
index 22a15f82..fa491159 100644
--- a/jtagmkII.h
+++ b/jtagmkII.h
@@ -33,6 +33,13 @@ int  jtagmkII_getsync(PROGRAMMER * pgm, int mode);
 int  jtagmkII_getparm(PROGRAMMER * pgm, unsigned char parm,
 		      unsigned char * value);
 
+extern const char jtagmkII_desc[];
+extern const char jtagmkII_avr32_desc[];
+extern const char jtagmkII_dw_desc[];
+extern const char jtagmkII_pdi_desc[];
+extern const char jtagmkII_dragon_desc[];
+extern const char jtagmkII_dragon_dw_desc[];
+extern const char jtagmkII_dragon_pdi_desc[];
 void jtagmkII_initpgm (PROGRAMMER * pgm);
 void jtagmkII_avr32_initpgm (PROGRAMMER * pgm);
 void jtagmkII_dw_initpgm (PROGRAMMER * pgm);
diff --git a/lexer.l b/lexer.l
index 103c0829..e684e69d 100644
--- a/lexer.l
+++ b/lexer.l
@@ -35,6 +35,10 @@
 #include "config_gram.h"
 #include "lists.h"
 
+#ifndef YYERRCODE
+#define YYERRCODE 256
+#endif
+
 %}
 
 DIGIT    [0-9]
@@ -116,20 +120,12 @@ SIGN     [+-]
             exit(1); }
 
 allowfullpagebitstream { yylval=NULL; return K_ALLOWFULLPAGEBITSTREAM; }
-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; }
 banked           { yylval=NULL; return K_PAGED; }
 baudrate         { yylval=NULL; return K_BAUDRATE; }
 bs2              { yylval=NULL; return K_BS2; }
 buff             { yylval=NULL; return K_BUFF; }
-buspirate        { yylval=NULL; return K_BUSPIRATE; }
-butterfly        { yylval=NULL; return K_BUTTERFLY; }
-butterfly_mk     { yylval=NULL; return K_BUTTERFLY_MK; }
 chip_erase_delay { yylval=NULL; return K_CHIP_ERASE_DELAY; }
 connection_type  { yylval=NULL; return K_CONNTYPE; }
 desc             { yylval=NULL; return K_DESC; }
@@ -138,12 +134,6 @@ default_programmer { yylval=NULL; return K_DEFAULT_PROGRAMMER; }
 default_serial   { yylval=NULL; return K_DEFAULT_SERIAL; }
 default_bitclock { yylval=NULL; return K_DEFAULT_BITCLOCK; }
 devicecode       { yylval=NULL; return K_DEVICECODE; }
-dragon_dw        { yylval=NULL; return K_DRAGON_DW; }
-dragon_hvsp      { yylval=NULL; return K_DRAGON_HVSP; }
-dragon_isp       { yylval=NULL; return K_DRAGON_ISP; }
-dragon_jtag      { yylval=NULL; return K_DRAGON_JTAG; }
-dragon_pdi       { yylval=NULL; return K_DRAGON_PDI; }
-dragon_pp        { yylval=NULL; return K_DRAGON_PP; }
 eecr             { yylval=NULL; return K_EECR; }
 eeprom           { yylval=NULL; return K_EEPROM; }
 enablepageprogramming { yylval=NULL; return K_ENABLEPAGEPROGRAMMING; }
@@ -157,12 +147,6 @@ id               { yylval=NULL; return K_ID; }
 idr              { yylval=NULL; return K_IDR; }
 is_at90s1200     { yylval=NULL; return K_IS_AT90S1200; }
 is_avr32         { yylval=NULL; return K_IS_AVR32; }
-jtagmki          { yylval=NULL; return K_JTAG_MKI; }
-jtagmkii         { yylval=NULL; return K_JTAG_MKII; }
-jtagmkii_avr32   { yylval=NULL; return K_JTAG_MKII_AVR32; }
-jtagmkii_dw      { yylval=NULL; return K_JTAG_MKII_DW; }
-jtagmkii_isp     { yylval=NULL; return K_JTAG_MKII_ISP; }
-jtagmkii_pdi     { yylval=NULL; return K_JTAG_MKII_PDI; }
 max_write_delay  { yylval=NULL; return K_MAX_WRITE_DELAY; }
 memory           { yylval=NULL; return K_MEMORY; }
 min_write_delay  { yylval=NULL; return K_MIN_WRITE_DELAY; }
@@ -175,7 +159,6 @@ offset           { yylval=NULL; return K_OFFSET; }
 page_size        { yylval=NULL; return K_PAGE_SIZE; }
 paged            { yylval=NULL; return K_PAGED; }
 pagel            { yylval=NULL; return K_PAGEL; }
-par              { yylval=NULL; return K_PAR; }
 parallel         { yylval=NULL; return K_PARALLEL; }
 parent           { yylval=NULL; return K_PARENT; }
 part             { yylval=NULL; return K_PART; }
@@ -187,20 +170,11 @@ rdyled           { yylval=NULL; return K_RDYLED; }
 readback_p1      { yylval=NULL; return K_READBACK_P1; }
 readback_p2      { yylval=NULL; return K_READBACK_P2; }
 retry_pulse      { yylval=NULL; return K_RETRY_PULSE; }
-serbb            { yylval=NULL; return K_SERBB; }
 serial           { yylval=NULL; return K_SERIAL; }
 signature        { yylval=NULL; return K_SIGNATURE; }
 size             { yylval=NULL; return K_SIZE; }
 spmcr            { yylval=NULL; return K_SPMCR; }
-stk500           { yylval=NULL; return K_STK500; }
-stk500hvsp       { yylval=NULL; return K_STK500HVSP; }
-stk500pp         { yylval=NULL; return K_STK500PP; }
-stk500v2         { yylval=NULL; return K_STK500V2; }
-stk500generic    { yylval=NULL; return K_STK500GENERIC; }
 stk500_devcode   { yylval=NULL; return K_STK500_DEVCODE; }
-stk600           { yylval=NULL; return K_STK600; }
-stk600hvsp       { yylval=NULL; return K_STK600HVSP; }
-stk600pp         { yylval=NULL; return K_STK600PP; }
 type             { yylval=NULL; return K_TYPE; }
 usb              { yylval=NULL; return K_USB; }
 usbdev           { yylval=NULL; return K_USBDEV; }
@@ -211,7 +185,6 @@ usbvendor        { yylval=NULL; return K_USBVENDOR; }
 usbvid           { yylval=NULL; return K_USBVID; }
 vcc              { yylval=NULL; return K_VCC; }
 vfyled           { yylval=NULL; return K_VFYLED; }
-wiring           { yylval=NULL; return K_WIRING; }
 
 timeout          { yylval=NULL; return K_TIMEOUT; }
 stabdelay        { yylval=NULL; return K_STABDELAY; }
@@ -285,10 +258,9 @@ c: { fprintf(stderr, "error at %s:%d: possible old-style config file entry\n",
              infile, lineno);
      fprintf(stderr, "  Update your config file (see %s%s for a sample)\n",
              CONFIG_DIR, "/avrdude.conf.sample");
-     exit(1); }
+     return YYERRCODE; }
 
-. { fprintf(stderr, "error at %s:%d unrecognized character: \"%s\"\n", 
-            infile, lineno, yytext); exit(1); }
+. { return YYERRCODE; }
 
 %%
 
diff --git a/lists.c b/lists.c
index 8ea39623..c4a7cf31 100644
--- a/lists.c
+++ b/lists.c
@@ -478,7 +478,7 @@ lcreat ( void * liststruct, int elements )
 |  at the same time.
  --------------------------------------------------*/
 void 
-ldestroy_cb ( LISTID lid, void (*ucleanup)() )
+ldestroy_cb ( LISTID lid, void (*ucleanup)(void * data_ptr) )
 {
   LIST * l;
   LISTNODE * ln;
diff --git a/lists.h b/lists.h
index d3544572..80798f31 100644
--- a/lists.h
+++ b/lists.h
@@ -75,7 +75,7 @@ extern "C" {
 
 LISTID     lcreat      ( void * liststruct, int poolsize );
 void       ldestroy    ( LISTID lid );
-void       ldestroy_cb ( LISTID lid, void (*ucleanup)() );
+void       ldestroy_cb ( LISTID lid, void (*ucleanup)(void * data_ptr) );
 
 LNODEID    lfirst ( LISTID  ); /* head of the list */
 LNODEID    llast  ( LISTID  ); /* tail of the list */
diff --git a/main.c b/main.c
index 6c24f74a..9bd05195 100644
--- a/main.c
+++ b/main.c
@@ -55,6 +55,7 @@
 #include "term.h"
 #include "safemode.h"
 #include "update.h"
+#include "pgm_type.h"
 
 
 /* Get VERSION from ac_cfg.h */
@@ -221,6 +222,24 @@ static void list_programmers(FILE * f, const char *prefix, LISTID programmers)
     walk_programmers(programmers, list_programmers_callback, &c);
 }
 
+static void list_programmer_types_callback(const char *name, const char *desc,
+                                      void *cookie)
+{
+    struct list_walk_cookie *c = (struct list_walk_cookie *)cookie;
+    fprintf(c->f, "%s%-16s = %-s\n",
+                c->prefix, name, desc);
+}
+
+static void list_programmer_types(FILE * f, const char *prefix)
+{
+    struct list_walk_cookie c;
+
+    c.f = f;
+    c.prefix = prefix;
+
+    walk_programmer_types(list_programmer_types_callback, &c);
+}
+
 static void list_avrparts_callback(const char *name, const char *desc,
                                    const char *cfgname, int cfglineno,
                                    void *cookie)
@@ -261,7 +280,7 @@ static void exithook(void)
 static void cleanup_main(void)
 {
     if (updates) {
-        ldestroy_cb(updates,free_update);
+        ldestroy_cb(updates, (void(*)(void*))free_update);
         updates = NULL;
     }
     if (extended_params) {
@@ -705,6 +724,13 @@ int main(int argc, char * argv [])
       fprintf(stderr,"\n");
       exit(1);
     }
+    if (strcmp(programmer, "?type") == 0) {
+      fprintf(stderr, "\n");
+      fprintf(stderr,"Valid programmer types are:\n");
+      list_programmer_types(stderr, "  ");
+      fprintf(stderr,"\n");
+      exit(1);
+    }
   }
 
 
diff --git a/par.c b/par.c
index 54a04cf3..37f640cc 100644
--- a/par.c
+++ b/par.c
@@ -42,6 +42,7 @@
 #include "pgm.h"
 #include "ppi.h"
 #include "bitbang.h"
+#include "par.h"
 
 #if HAVE_PARPORT
 
@@ -417,6 +418,8 @@ static int par_parseexitspecs(PROGRAMMER * pgm, char *s)
   return 0;
 }
 
+const char par_desc[] = "Parallel port bitbanging";
+
 void par_initpgm(PROGRAMMER * pgm)
 {
   strcpy(pgm->type, "PPI");
diff --git a/par.h b/par.h
index 7d9b2416..5240cc01 100644
--- a/par.h
+++ b/par.h
@@ -26,6 +26,7 @@
 extern "C" {
 #endif
 
+extern const char par_desc[];
 void par_initpgm        (PROGRAMMER * pgm);
 
 #ifdef __cplusplus
diff --git a/pgm_type.c b/pgm_type.c
new file mode 100644
index 00000000..47b386c5
--- /dev/null
+++ b/pgm_type.c
@@ -0,0 +1,139 @@
+/*
+ * avrdude - A Downloader/Uploader for AVR device programmers
+ * Copyright (C) 2002-2004  Brian S. Dean <bsd@bsdhome.com>
+ * Copyright 2007 Joerg Wunsch <j@uriah.heep.sax.de>
+ *
+ * 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: pgm.c 976 2011-08-23 21:03:36Z joerg_wunsch $ */
+
+#include "ac_cfg.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "avrdude.h"
+#include "pgm_type.h"
+
+#include "arduino.h"
+#include "avr.h"
+#include "avr910.h"
+#include "avrftdi.h"
+#include "buspirate.h"
+#include "butterfly.h"
+#include "jtagmkI.h"
+#include "jtagmkII.h"
+#include "par.h"
+#include "ppi.h"
+#include "serbb.h"
+#include "stk500.h"
+#include "stk500generic.h"
+#include "stk500v2.h"
+#include "usbasp.h"
+#include "usbtiny.h"
+#include "wiring.h"
+
+
+const PROGRAMMER_TYPE const programmers_types[] = {
+        {"arduino", arduino_initpgm, arduino_desc},
+        {"avr910", avr910_initpgm, avr910_desc},
+        {"avrftdi", avrftdi_initpgm, avrftdi_desc},
+        {"buspirate", buspirate_initpgm, buspirate_desc},
+        {"butterfly", butterfly_initpgm, butterfly_desc},
+        {"butterfly_mk", butterfly_mk_initpgm, butterfly_mk_desc},
+        {"dragon_dw", jtagmkII_dragon_dw_initpgm, jtagmkII_dragon_dw_desc},
+        {"dragon_hvsp", stk500v2_dragon_hvsp_initpgm, stk500v2_dragon_hvsp_desc},
+        {"dragon_isp", stk500v2_dragon_isp_initpgm, stk500v2_dragon_isp_desc},
+        {"dragon_jtag", jtagmkII_dragon_initpgm, jtagmkII_dragon_desc},
+        {"dragon_pdi", jtagmkII_dragon_pdi_initpgm, jtagmkII_dragon_pdi_desc},
+        {"dragon_pp", stk500v2_dragon_pp_initpgm, stk500v2_dragon_pp_desc},
+        {"jtagmki", jtagmkI_initpgm, jtagmkI_desc},
+        {"jtagmkii", jtagmkII_initpgm, jtagmkII_desc},
+        {"jtagmkii_avr32", jtagmkII_avr32_initpgm, jtagmkII_avr32_desc},
+        {"jtagmkii_dw", jtagmkII_dw_initpgm, jtagmkII_dw_desc},
+        {"jtagmkii_isp", stk500v2_jtagmkII_initpgm, stk500v2_jtagmkII_desc},
+        {"jtagmkii_pdi", jtagmkII_pdi_initpgm, jtagmkII_pdi_desc},
+        {"par", par_initpgm, par_desc},
+        {"serbb", serbb_initpgm, serbb_desc},
+        {"stk500", stk500_initpgm, stk500_desc},
+        {"stk500generic", stk500generic_initpgm, stk500generic_desc},
+        {"stk500v2", stk500v2_initpgm, stk500v2_desc},
+        {"stk500hvsp", stk500hvsp_initpgm, stk500hvsp_desc},
+        {"stk500pp", stk500pp_initpgm, stk500pp_desc},
+        {"stk600", stk600_initpgm, stk600_desc},
+        {"stk600hvsp", stk600hvsp_initpgm, stk600hvsp_desc},
+        {"stk600pp", stk600pp_initpgm, stk600pp_desc},
+        {"usbasp", usbasp_initpgm, usbasp_desc},
+        {"usbtiny", usbtiny_initpgm, usbtiny_desc},
+        {"wiring", wiring_initpgm, wiring_desc},
+};
+
+const PROGRAMMER_TYPE * locate_programmer_type(const char * id)
+{
+  const PROGRAMMER_TYPE * p = NULL;
+  int i;
+  int found;
+
+  found = 0;
+
+  for (i = 0; i < sizeof(programmers_types)/sizeof(programmers_types[0]) && !found; i++) {
+    p = &(programmers_types[i]);
+    if (strcasecmp(id, p->id) == 0)
+        found = 1;
+  }
+
+  if (found)
+    return p;
+
+  return NULL;
+}
+
+/*
+ * Iterate over the list of programmers given as "programmers", and
+ * call the callback function cb for each entry found.  cb is being
+ * passed the following arguments:
+ * . the name of the programmer (for -c)
+ * . the descriptive text given in the config file
+ * . the name of the config file this programmer has been defined in
+ * . the line number of the config file this programmer has been defined at
+ * . the "cookie" passed into walk_programmers() (opaque client data)
+ */
+ /*
+void walk_programmer_types(LISTID programmer_types, walk_programmer_types_cb cb, void *cookie)
+{
+  LNODEID ln1;
+  PROGRAMMER * p;
+
+  for (ln1 = lfirst(programmers); ln1; ln1 = lnext(ln1)) {
+    p = ldata(ln1);
+      cb(p->id, p->desc, cookie);
+    }
+  }
+}*/
+
+void walk_programmer_types(walk_programmer_types_cb cb, void *cookie)
+{
+  const PROGRAMMER_TYPE * p;
+  int i;
+
+  for (i = 0; i < sizeof(programmers_types)/sizeof(programmers_types[0]); i++) {
+    p = &(programmers_types[i]);
+    cb(p->id, p->desc, cookie);
+  }
+}
+
+
diff --git a/pgm_type.h b/pgm_type.h
new file mode 100644
index 00000000..aa68d56a
--- /dev/null
+++ b/pgm_type.h
@@ -0,0 +1,51 @@
+/*
+ * avrdude - A Downloader/Uploader for AVR device programmers
+ * Copyright (C) 2002-2004  Brian S. Dean <bsd@bsdhome.com>
+ * Copyright 2007 Joerg Wunsch <j@uriah.heep.sax.de>
+ *
+ * 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: pgm.h 1007 2011-09-14 21:49:42Z joerg_wunsch $ */
+
+#ifndef pgm_type_h
+#define pgm_type_h
+
+#include "lists.h"
+#include "pgm.h"
+
+/*LISTID programmer_types;*/
+
+typedef struct programmer_type_t {
+  const char * const id;
+  void (*initpgm)(struct programmer_t * pgm);
+  const char * const desc;
+} PROGRAMMER_TYPE;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+const PROGRAMMER_TYPE * locate_programmer_type(/*LISTID programmer_types, */const char * id);
+
+typedef void (*walk_programmer_types_cb)(const char *id, const char *desc,
+                                    void *cookie);
+void walk_programmer_types(/*LISTID programmer_types,*/ walk_programmer_types_cb cb, void *cookie);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/serbb.h b/serbb.h
index f466569c..736ea94d 100644
--- a/serbb.h
+++ b/serbb.h
@@ -26,6 +26,7 @@
 extern "C" {
 #endif
 
+extern const char serbb_desc[];
 void serbb_initpgm        (PROGRAMMER * pgm);
 
 #ifdef __cplusplus
diff --git a/serbb_posix.c b/serbb_posix.c
index 668a2079..400568f4 100644
--- a/serbb_posix.c
+++ b/serbb_posix.c
@@ -42,6 +42,7 @@
 #include "pindefs.h"
 #include "pgm.h"
 #include "bitbang.h"
+#include "serbb.h"
 
 #undef DEBUG
 
@@ -283,6 +284,8 @@ static void serbb_close(PROGRAMMER *pgm)
   return;
 }
 
+const char serbb_desc[] = "Serial port bitbanging";
+
 void serbb_initpgm(PROGRAMMER *pgm)
 {
   strcpy(pgm->type, "SERBB");
diff --git a/serbb_win32.c b/serbb_win32.c
index 2f5af8ad..ffc8f6d0 100644
--- a/serbb_win32.c
+++ b/serbb_win32.c
@@ -38,6 +38,7 @@
 #include "pindefs.h"
 #include "pgm.h"
 #include "bitbang.h"
+#include "serbb.h"
 
 /* cached status lines */
 static int dtr, rts, txd;
@@ -344,6 +345,8 @@ static void serbb_close(PROGRAMMER *pgm)
 	hComPort = INVALID_HANDLE_VALUE;
 }
 
+const char serbb_desc[] = "Serial port bitbanging";
+
 void serbb_initpgm(PROGRAMMER *pgm)
 {
   strcpy(pgm->type, "SERBB");
diff --git a/stk500.c b/stk500.c
index 32842ad4..8fb97edf 100644
--- a/stk500.c
+++ b/stk500.c
@@ -40,6 +40,7 @@
 #include "avrdude.h"
 #include "avr.h"
 #include "pgm.h"
+#include "stk500.h"
 #include "stk500_private.h"
 #include "serial.h"
 
@@ -1270,6 +1271,7 @@ static void stk500_print_parms(PROGRAMMER * pgm)
   stk500_print_parms1(pgm, "");
 }
 
+const char stk500_desc[] = "Atmel STK500 Version 1.x firmware";
 
 void stk500_initpgm(PROGRAMMER * pgm)
 {
diff --git a/stk500.h b/stk500.h
index 4b22ee05..e320abce 100644
--- a/stk500.h
+++ b/stk500.h
@@ -26,6 +26,7 @@
 extern "C" {
 #endif
 
+extern const char stk500_desc[];
 void stk500_initpgm (PROGRAMMER * pgm);
 
 /* used by arduino.c to avoid duplicate code */
diff --git a/stk500generic.c b/stk500generic.c
index 12125393..54cc5749 100644
--- a/stk500generic.c
+++ b/stk500generic.c
@@ -34,6 +34,7 @@
 
 #include "avrdude.h"
 #include "pgm.h"
+#include "stk500generic.h"
 #include "stk500.h"
 #include "stk500v2.h"
 
@@ -80,6 +81,7 @@ static void stk500generic_teardown(PROGRAMMER * pgm)
   pgm->teardown(pgm);
 }
 
+const char stk500generic_desc[] = "Atmel STK500, autodetect firmware version";
 
 void stk500generic_initpgm(PROGRAMMER * pgm)
 {
diff --git a/stk500generic.h b/stk500generic.h
index 89af83b1..0bac3560 100644
--- a/stk500generic.h
+++ b/stk500generic.h
@@ -22,6 +22,7 @@
 #ifndef stk500generic_h__
 #define stk500generic_h__
 
+extern const char stk500generic_desc[];
 void stk500generic_initpgm (PROGRAMMER * pgm);
 
 #endif
diff --git a/stk500v2.c b/stk500v2.c
index 59fef627..42ef1236 100644
--- a/stk500v2.c
+++ b/stk500v2.c
@@ -52,6 +52,7 @@
 #include "avr.h"
 #include "pgm.h"
 #include "stk500_private.h"	// temp until all code converted
+#include "stk500v2.h"
 #include "stk500v2_private.h"
 #include "serial.h"
 #include "usbdevs.h"
@@ -3611,6 +3612,7 @@ static void stk600_setup_isp(PROGRAMMER * pgm)
     pgm->chip_erase = stk500v2_chip_erase;
 }
 
+const char stk500v2_desc[] = "Atmel STK500 Version 2.x firmware";
 
 void stk500v2_initpgm(PROGRAMMER * pgm)
 {
@@ -3647,6 +3649,8 @@ void stk500v2_initpgm(PROGRAMMER * pgm)
   pgm->page_size      = 256;
 }
 
+const char stk500pp_desc[] = "Atmel STK500 V2 in parallel programming mode";
+
 void stk500pp_initpgm(PROGRAMMER * pgm)
 {
   strcpy(pgm->type, "STK500PP");
@@ -3680,6 +3684,8 @@ void stk500pp_initpgm(PROGRAMMER * pgm)
   pgm->page_size      = 256;
 }
 
+const char stk500hvsp_desc[] = "Atmel STK500 V2 in high-voltage serial programming mode";
+
 void stk500hvsp_initpgm(PROGRAMMER * pgm)
 {
   strcpy(pgm->type, "STK500HVSP");
@@ -3713,6 +3719,8 @@ void stk500hvsp_initpgm(PROGRAMMER * pgm)
   pgm->page_size      = 256;
 }
 
+const char stk500v2_jtagmkII_desc[] = "Atmel JTAG ICE mkII in ISP mode";
+
 void stk500v2_jtagmkII_initpgm(PROGRAMMER * pgm)
 {
   strcpy(pgm->type, "JTAGMKII_ISP");
@@ -3745,6 +3753,8 @@ void stk500v2_jtagmkII_initpgm(PROGRAMMER * pgm)
   pgm->page_size      = 256;
 }
 
+const char stk500v2_dragon_isp_desc[] = "Atmel AVR Dragon in ISP mode";
+
 void stk500v2_dragon_isp_initpgm(PROGRAMMER * pgm)
 {
   strcpy(pgm->type, "DRAGON_ISP");
@@ -3776,6 +3786,8 @@ void stk500v2_dragon_isp_initpgm(PROGRAMMER * pgm)
   pgm->page_size      = 256;
 }
 
+const char stk500v2_dragon_pp_desc[] = "Atmel AVR Dragon in PP mode";
+
 void stk500v2_dragon_pp_initpgm(PROGRAMMER * pgm)
 {
   strcpy(pgm->type, "DRAGON_PP");
@@ -3809,6 +3821,8 @@ void stk500v2_dragon_pp_initpgm(PROGRAMMER * pgm)
   pgm->page_size      = 256;
 }
 
+const char stk500v2_dragon_hvsp_desc[] = "Atmel AVR Dragon in HVSP mode";
+
 void stk500v2_dragon_hvsp_initpgm(PROGRAMMER * pgm)
 {
   strcpy(pgm->type, "DRAGON_HVSP");
@@ -3842,6 +3856,8 @@ void stk500v2_dragon_hvsp_initpgm(PROGRAMMER * pgm)
   pgm->page_size      = 256;
 }
 
+const char stk600_desc[] = "Atmel STK600";
+
 void stk600_initpgm(PROGRAMMER * pgm)
 {
   strcpy(pgm->type, "STK600");
@@ -3877,6 +3893,8 @@ void stk600_initpgm(PROGRAMMER * pgm)
   pgm->page_size      = 256;
 }
 
+const char stk600pp_desc[] = "Atmel STK600 in parallel programming mode";
+
 void stk600pp_initpgm(PROGRAMMER * pgm)
 {
   strcpy(pgm->type, "STK600PP");
@@ -3910,6 +3928,8 @@ void stk600pp_initpgm(PROGRAMMER * pgm)
   pgm->page_size      = 256;
 }
 
+const char stk600hvsp_desc[] = "Atmel STK600 in high-voltage serial programming mode";
+
 void stk600hvsp_initpgm(PROGRAMMER * pgm)
 {
   strcpy(pgm->type, "STK600HVSP");
diff --git a/stk500v2.h b/stk500v2.h
index 2278270d..88bf7a1b 100644
--- a/stk500v2.h
+++ b/stk500v2.h
@@ -27,6 +27,16 @@
 extern "C" {
 #endif
 
+extern const char stk500v2_desc[];
+extern const char stk500hvsp_desc[];
+extern const char stk500pp_desc[];
+extern const char stk500v2_jtagmkII_desc[];
+extern const char stk500v2_dragon_hvsp_desc[];
+extern const char stk500v2_dragon_isp_desc[];
+extern const char stk500v2_dragon_pp_desc[];
+extern const char stk600_desc[];
+extern const char stk600hvsp_desc[];
+extern const char stk600pp_desc[];
 void stk500v2_initpgm (PROGRAMMER * pgm);
 void stk500hvsp_initpgm (PROGRAMMER * pgm);
 void stk500pp_initpgm (PROGRAMMER * pgm);
diff --git a/usbasp.c b/usbasp.c
index 683cf72c..d59c624b 100644
--- a/usbasp.c
+++ b/usbasp.c
@@ -1161,3 +1161,6 @@ void usbasp_initpgm(PROGRAMMER * pgm)
 }
 
 #endif  /* HAVE_LIBUSB */
+
+const char usbasp_desc[] = "USBasp programmer, see http://www.fischl.de/usbasp/";
+
diff --git a/usbasp.h b/usbasp.h
index 91b6e8a8..96a95cd3 100644
--- a/usbasp.h
+++ b/usbasp.h
@@ -140,6 +140,7 @@ typedef struct sckoptions_t {
 extern "C" {
 #endif
 
+extern const char usbasp_desc[];
 void usbasp_initpgm (PROGRAMMER * pgm);
 
 #ifdef __cplusplus
diff --git a/usbtiny.c b/usbtiny.c
index d5d4b122..887e2c3e 100644
--- a/usbtiny.c
+++ b/usbtiny.c
@@ -538,7 +538,7 @@ static int usbtiny_paged_write(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
   return n_bytes;
 }
 
-extern void usbtiny_initpgm ( PROGRAMMER* pgm )
+void usbtiny_initpgm ( PROGRAMMER* pgm )
 {
   strcpy(pgm->type, "USBtiny");
 
@@ -584,3 +584,6 @@ void usbtiny_initpgm(PROGRAMMER * pgm)
 }
 
 #endif /* HAVE_LIBUSB */
+
+const char usbtiny_desc[] = "Driver for \"usbtiny\"-type programmers";
+
diff --git a/usbtiny.h b/usbtiny.h
index 77f9a42e..4333bfd2 100644
--- a/usbtiny.h
+++ b/usbtiny.h
@@ -67,6 +67,7 @@
 extern "C" {
 #endif
 
+extern const char usbtiny_desc[];
 void usbtiny_initpgm (PROGRAMMER * pgm);
 
 #ifdef __cplusplus
diff --git a/wiring.c b/wiring.c
index 1b7236e4..27dce82f 100644
--- a/wiring.c
+++ b/wiring.c
@@ -51,6 +51,7 @@
 #include "stk500v2_private.h"
 #include "stk500v2.h"
 #include "serial.h"
+#include "wiring.h"
 
 /*
  * Private data for this programmer.
@@ -219,6 +220,8 @@ static void wiring_close(PROGRAMMER * pgm)
   pgm->fd.ifd = -1;
 }
 
+const char wiring_desc[] = "http://wiring.org.co/, Basically STK500v2 protocol, with some glue to trigger the bootloader.";
+
 void wiring_initpgm(PROGRAMMER * pgm)
 {
   /* The Wiring bootloader uses a near-complete STK500v2 protocol. */
diff --git a/wiring.h b/wiring.h
index 57f70a75..3d4ab36d 100644
--- a/wiring.h
+++ b/wiring.h
@@ -22,6 +22,7 @@
 #ifndef wiring_h__
 #define wiring_h__
 
+extern const char wiring_desc[];
 void wiring_initpgm(PROGRAMMER * pgm);
 
 #endif