Index: buspirate.c
===================================================================
--- buspirate.c	(revision 1045)
+++ buspirate.c	(working copy)
@@ -775,6 +775,7 @@
 {
 	free(pgm->cookie);
 }
+const char buspirate_desc[] = "Using the Bus Pirate's SPI interface for programming";
 
 void buspirate_initpgm(struct programmer_t *pgm)
 {
Index: jtagmkII.c
===================================================================
--- jtagmkII.c	(revision 1045)
+++ jtagmkII.c	(working copy)
@@ -3577,6 +3577,8 @@
 #pragma mark -
 #endif
 
+const char jtagmkII_desc[] = "Atmel JTAG ICE mkII";
+
 void jtagmkII_initpgm(PROGRAMMER * pgm)
 {
   strcpy(pgm->type, "JTAGMKII");
@@ -3609,6 +3611,8 @@
   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 @@
   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 @@
   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 @@
   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 @@
   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 @@
   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");
Index: avrftdi.c
===================================================================
--- avrftdi.c	(revision 1045)
+++ avrftdi.c	(working copy)
@@ -1074,3 +1074,5 @@
 
 #endif /*HAVE_LIBUSB*/
 
+const char avrftdi_desc[] = "Interface to the MPSSE Engine of FTDI Chips using libftdi.";
+
Index: wiring.c
===================================================================
--- wiring.c	(revision 1045)
+++ wiring.c	(working copy)
@@ -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 @@
   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. */
Index: serbb.h
===================================================================
--- serbb.h	(revision 1045)
+++ serbb.h	(working copy)
@@ -26,6 +26,7 @@
 extern "C" {
 #endif
 
+extern const char serbb_desc[];
 void serbb_initpgm        (PROGRAMMER * pgm);
 
 #ifdef __cplusplus
Index: usbtiny.h
===================================================================
--- usbtiny.h	(revision 1045)
+++ usbtiny.h	(working copy)
@@ -67,6 +67,7 @@
 extern "C" {
 #endif
 
+extern const char usbtiny_desc[];
 void usbtiny_initpgm (PROGRAMMER * pgm);
 
 #ifdef __cplusplus
Index: buspirate.h
===================================================================
--- buspirate.h	(revision 1045)
+++ buspirate.h	(working copy)
@@ -25,6 +25,7 @@
 #ifndef buspirate_h
 #define buspirate_h
 
+extern const char buspirate_desc[];
 void buspirate_initpgm (struct programmer_t *pgm);
 
 #endif
Index: avrftdi.h
===================================================================
--- avrftdi.h	(revision 1045)
+++ avrftdi.h	(working copy)
@@ -45,6 +45,7 @@
 #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
Index: wiring.h
===================================================================
--- wiring.h	(revision 1045)
+++ wiring.h	(working copy)
@@ -22,6 +22,7 @@
 #ifndef wiring_h__
 #define wiring_h__
 
+extern const char wiring_desc[];
 void wiring_initpgm(PROGRAMMER * pgm);
 
 #endif
Index: jtagmkII.h
===================================================================
--- jtagmkII.h	(revision 1045)
+++ jtagmkII.h	(working copy)
@@ -33,6 +33,13 @@
 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);
Index: config.c
===================================================================
--- config.c	(revision 1045)
+++ config.c	(working copy)
@@ -57,10 +57,10 @@
 
 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 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 @@
   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;
Index: butterfly.c
===================================================================
--- butterfly.c	(revision 1045)
+++ butterfly.c	(working copy)
@@ -696,6 +696,7 @@
   return 3;
 }
 
+const char butterfly_desc[] = "Atmel Butterfly evaluation board; Atmel AppNotes AVR109, AVR911";
 
 void butterfly_initpgm(PROGRAMMER * pgm)
 {
@@ -735,6 +736,8 @@
   pgm->flag = 0;
 }
 
+const char butterfly_mk_desc[] = "Mikrokopter.de Butterfly";
+
 void butterfly_mk_initpgm(PROGRAMMER * pgm)
 {
   butterfly_initpgm(pgm);
Index: doc/avrdude.texi
===================================================================
--- doc/avrdude.texi	(revision 1045)
+++ doc/avrdude.texi	(working copy)
@@ -1435,7 +1435,7 @@
     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 @@
 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
Index: doc/Makefile.am
===================================================================
--- doc/Makefile.am	(revision 1045)
+++ doc/Makefile.am	(working copy)
@@ -23,6 +23,7 @@
 
 CLEANFILES = \
 	parts.texi \
+	programmer_types.texi \
 	version.texi \
 	stamp-vti
 
@@ -32,7 +33,7 @@
 
 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 @@
 	 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)}' \
Index: doc/.cvsignore
===================================================================
--- doc/.cvsignore	(revision 1045)
+++ doc/.cvsignore	(working copy)
@@ -20,4 +20,5 @@
 stamp-vti
 texinfo.tex
 version.texi
+programmer_types.texi
 parts.texi
Index: pgm_type.c
===================================================================
--- pgm_type.c	(revision 0)
+++ pgm_type.c	(revision 0)
@@ -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);
+  }
+}
+
+
Index: butterfly.h
===================================================================
--- butterfly.h	(revision 1045)
+++ butterfly.h	(working copy)
@@ -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);
 
Index: jtagmkI.c
===================================================================
--- jtagmkI.c	(revision 1045)
+++ jtagmkI.c	(working copy)
@@ -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 @@
   jtagmkI_print_parms1(pgm, "");
 }
 
+const char jtagmkI_desc[] = "Atmel JTAG ICE mkI";
 
 void jtagmkI_initpgm(PROGRAMMER * pgm)
 {
Index: pgm_type.h
===================================================================
--- pgm_type.h	(revision 0)
+++ pgm_type.h	(revision 0)
@@ -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
Index: jtagmkI.h
===================================================================
--- jtagmkI.h	(revision 1045)
+++ jtagmkI.h	(working copy)
@@ -26,6 +26,7 @@
 extern "C" {
 #endif
 
+extern const char jtagmkI_desc[];
 void jtagmkI_initpgm (PROGRAMMER * pgm);
 
 #ifdef __cplusplus
Index: config_gram.y
===================================================================
--- config_gram.y	(revision 1045)
+++ config_gram.y	(working copy)
@@ -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 @@
 %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_DEDICATED
 %token K_DEFAULT_PARALLEL
@@ -98,12 +83,6 @@
 %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
@@ -111,12 +90,6 @@
 %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
@@ -126,7 +99,6 @@
 %token K_NVM_BASE
 %token K_OFFSET
 %token K_PAGEL
-%token K_PAR
 %token K_PARALLEL
 %token K_PARENT
 %token K_PART
@@ -140,34 +112,19 @@
 %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_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
@@ -484,37 +441,24 @@
 ;
 
 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_usb:
Index: arduino.c
===================================================================
--- arduino.c	(revision 1045)
+++ arduino.c	(working copy)
@@ -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 @@
   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 */
Index: arduino.h
===================================================================
--- arduino.h	(revision 1045)
+++ arduino.h	(working copy)
@@ -22,6 +22,7 @@
 #ifndef arduino_h__
 #define arduino_h__
 
+extern const char arduino_desc[];
 void arduino_initpgm (PROGRAMMER * pgm);
 
 #endif
Index: serbb_win32.c
===================================================================
--- serbb_win32.c	(revision 1045)
+++ serbb_win32.c	(working copy)
@@ -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 @@
 	hComPort = INVALID_HANDLE_VALUE;
 }
 
+const char serbb_desc[] = "Serial port bitbanging";
+
 void serbb_initpgm(PROGRAMMER *pgm)
 {
   strcpy(pgm->type, "SERBB");
Index: avr910.c
===================================================================
--- avr910.c	(revision 1045)
+++ avr910.c	(working copy)
@@ -744,6 +744,7 @@
   return 3;
 }
 
+const char avr910_desc[] = "Serial programmers using protocol described in application note AVR910";
 
 void avr910_initpgm(PROGRAMMER * pgm)
 {
Index: stk500.c
===================================================================
--- stk500.c	(revision 1045)
+++ stk500.c	(working copy)
@@ -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 @@
   stk500_print_parms1(pgm, "");
 }
 
+const char stk500_desc[] = "Atmel STK500 Version 1.x firmware";
 
 void stk500_initpgm(PROGRAMMER * pgm)
 {
Index: avr910.h
===================================================================
--- avr910.h	(revision 1045)
+++ avr910.h	(working copy)
@@ -28,6 +28,7 @@
 extern "C" {
 #endif
 
+extern const char avr910_desc[];
 void avr910_initpgm (PROGRAMMER * pgm);
 
 #ifdef __cplusplus
Index: stk500.h
===================================================================
--- stk500.h	(revision 1045)
+++ stk500.h	(working copy)
@@ -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 */
Index: avrdude.conf.in
===================================================================
--- avrdude.conf.in	(revision 1045)
+++ avrdude.conf.in	(working copy)
@@ -343,13 +343,13 @@
 programmer
   id    = "wiring";
   desc  = "Wiring";
-  type  = wiring;
+  type  = "wiring";
 ;
 
 programmer
   id    = "arduino";
   desc  = "Arduino";
-  type  = arduino;
+  type  = "arduino";
 ;
 # this will interface with the chips on these programmers:
 #
@@ -369,7 +369,7 @@
 programmer
   id         = "avrftdi";
   desc       = "FT2232D based generic programmer";
-  type       = avrftdi;
+  type       = "avrftdi";
   usbvid     = 0x0403;
   usbpid     = 0x6010;
   usbvendor  = "";
@@ -396,7 +396,7 @@
 programmer
   id         = "2232HIO";
   desc       = "FT2232H based generic programmer";
-  type       = avrftdi;
+  type       = "avrftdi";
   usbvid     = 0x0403;
 # Note: This PID is reserved for generic H devices and 
 # should be programmed into the EEPROM
@@ -422,7 +422,7 @@
 programmer
   id         = "jtagkey";
   desc       = "Amontec JTAGKey, JTAGKey-Tiny and JTAGKey2";
-  type       = avrftdi;
+  type       = "avrftdi";
   usbvid     = 0x0403;
 # Note: This PID is used in all JTAGKey variants
   usbpid     = 0xCFF8;
@@ -467,19 +467,19 @@
 programmer
   id    = "avrisp";
   desc  = "Atmel AVR ISP";
-  type  = stk500;
+  type  = "stk500";
 ;
 
 programmer
   id    = "avrispv2";
   desc  = "Atmel AVR ISP V2";
-  type  =  stk500v2;
+  type  =  "stk500v2";
 ;
 
 programmer
   id    = "avrispmkII";
   desc  = "Atmel AVR ISP mkII";
-  type  =  stk500v2;
+  type  =  "stk500v2";
 ;
 
 programmer parent "avrispmkII"
@@ -489,7 +489,7 @@
 programmer
   id    = "buspirate";
   desc  = "The Bus Pirate";
-  type  = buspirate;
+  type  = "buspirate";
 ;
 
 # This is supposed to be the "default" STK500 entry.
@@ -499,67 +499,67 @@
 programmer
   id    = "stk500";
   desc  = "Atmel STK500";
-  type  = stk500generic;
+  type  = "stk500generic";
 ;
 
 programmer
   id    = "stk500v1";
   desc  = "Atmel STK500 Version 1.x firmware";
-  type  = stk500;
+  type  = "stk500";
 ;
 
 programmer
   id    = "mib510";
   desc  = "Crossbow MIB510 programming board";
-  type  = stk500;
+  type  = "stk500";
 ;
 
 programmer
   id    = "stk500v2";
   desc  = "Atmel STK500 Version 2.x firmware";
-  type  = stk500v2;
+  type  = "stk500v2";
 ;
 
 programmer
   id    = "stk500pp";
   desc  = "Atmel STK500 V2 in parallel programming mode";
-  type  = stk500pp;
+  type  = "stk500pp";
 ;
 
 programmer
   id    = "stk500hvsp";
   desc  = "Atmel STK500 V2 in high-voltage serial programming mode";
-  type  = stk500hvsp;
+  type  = "stk500hvsp";
 ;
 
 programmer
   id    = "stk600";
   desc  = "Atmel STK600";
-  type  = stk600;
+  type  = "stk600";
 ;
 
 programmer
   id    = "stk600pp";
   desc  = "Atmel STK600 in parallel programming mode";
-  type  = stk600pp;
+  type  = "stk600pp";
 ;
 
 programmer
   id    = "stk600hvsp";
   desc  = "Atmel STK600 in high-voltage serial programming mode";
-  type  = stk600hvsp;
+  type  = "stk600hvsp";
 ;
 
 programmer
   id    = "avr910";
   desc  = "Atmel Low Cost Serial Programmer";
-  type  = avr910;
+  type  = "avr910";
 ;
 
 programmer
   id    = "usbasp";
   desc  = "USBasp, http://www.fischl.de/usbasp/";
-  type  = usbasp;
+  type  = "usbasp";
   usbvid     = 0x16C0; # VOTI
   usbpid     = 0x05DC; # Obdev's free shared PID
   usbvendor  = "www.fischl.de";
@@ -583,7 +583,7 @@
 programmer
   id    = "nibobee";
   desc  = "NIBObee";
-  type  = usbasp;
+  type  = "usbasp";
   usbvid     = 0x16C0; # VOTI
   usbpid     = 0x092F; # NIBObee PID
   usbvendor  = "www.nicai-systems.com";
@@ -593,7 +593,7 @@
 programmer
   id    = "usbasp-clone";
   desc  = "Any usbasp clone with correct VID/PID";
-  type  = usbasp;
+  type  = "usbasp";
   usbvid    = 0x16C0; # VOTI
   usbpid    = 0x05DC; # Obdev's free shared PID
   #usbvendor  = "";
@@ -603,32 +603,32 @@
 programmer
   id    = "usbtiny";
   desc  = "USBtiny simple USB programmer, http://www.ladyada.net/make/usbtinyisp/";
-  type  = usbtiny;
+  type  = "usbtiny";
 ;
 
 programmer
   id    = "butterfly";
   desc  = "Atmel Butterfly Development Board";
-  type  = butterfly;
+  type  = "butterfly";
 ;
 
 programmer
   id    = "avr109";
   desc  = "Atmel AppNote AVR109 Boot Loader";
-  type  = butterfly;
+  type  = "butterfly";
 ;
 
 programmer
   id    = "avr911";
   desc  = "Atmel AppNote AVR911 AVROSP";
-  type  = butterfly;
+  type  = "butterfly";
 ;
  
 # suggested in http://forum.mikrokopter.de/topic-post48317.html
 programmer
   id    = "mkbutterfly";
   desc  = "Mikrokopter.de Butterfly";
-  type  = butterfly_mk;
+  type  = "butterfly_mk";
 ;
 
 programmer parent "mkbutterfly"
@@ -639,7 +639,7 @@
   id    = "jtagmkI";
   desc  = "Atmel JTAG ICE (mkI)";
   baudrate = 115200;    # default is 115200
-  type  = jtagmki;
+  type  = "jtagmki";
 ;
 
 # easier to type
@@ -657,7 +657,7 @@
   id    = "jtagmkII";
   desc  = "Atmel JTAG ICE mkII";
   baudrate = 19200;    # default is 19200
-  type  = jtagmkii;
+  type  = "jtagmkii";
 ;
 
 # easier to type
@@ -681,7 +681,7 @@
   id    = "jtag2isp";
   desc  = "Atmel JTAG ICE mkII in ISP mode";
   baudrate = 115200;
-  type  = jtagmkii_isp;
+  type  = "jtagmkii_isp";
 ;
 
 # JTAG ICE mkII in debugWire mode
@@ -689,7 +689,7 @@
   id    = "jtag2dw";
   desc  = "Atmel JTAG ICE mkII in debugWire mode";
   baudrate = 115200;
-  type  = jtagmkii_dw;
+  type  = "jtagmkii_dw";
 ;
 
 # JTAG ICE mkII in AVR32 mode
@@ -697,7 +697,7 @@
   id    = "jtagmkII_avr32";
   desc  = "Atmel JTAG ICE mkII im AVR32 mode";
   baudrate = 115200;
-  type  = jtagmkii_avr32;
+  type  = "jtagmkii_avr32";
 ;
 
 # JTAG ICE mkII in AVR32 mode
@@ -705,7 +705,7 @@
   id    = "jtag2avr32";
   desc  = "Atmel JTAG ICE mkII im AVR32 mode";
   baudrate = 115200;
-  type  = jtagmkii_avr32;
+  type  = "jtagmkii_avr32";
 ;
 
 # JTAG ICE mkII in PDI mode
@@ -713,7 +713,7 @@
   id    = "jtag2pdi";
   desc  = "Atmel JTAG ICE mkII PDI mode";
   baudrate = 115200;
-  type  = jtagmkii_pdi;
+  type  = "jtagmkii_pdi";
 ;
 
 # AVR Dragon in JTAG mode
@@ -721,7 +721,7 @@
   id    = "dragon_jtag";
   desc  = "Atmel AVR Dragon in JTAG mode";
   baudrate = 115200;
-  type  = dragon_jtag;
+  type  = "dragon_jtag";
 ;
 
 # AVR Dragon in ISP mode
@@ -729,7 +729,7 @@
   id    = "dragon_isp";
   desc  = "Atmel AVR Dragon in ISP mode";
   baudrate = 115200;
-  type  = dragon_isp;
+  type  = "dragon_isp";
 ;
 
 # AVR Dragon in PP mode
@@ -737,7 +737,7 @@
   id    = "dragon_pp";
   desc  = "Atmel AVR Dragon in PP mode";
   baudrate = 115200;
-  type  = dragon_pp;
+  type  = "dragon_pp";
 ;
 
 # AVR Dragon in HVSP mode
@@ -745,7 +745,7 @@
   id    = "dragon_hvsp";
   desc  = "Atmel AVR Dragon in HVSP mode";
   baudrate = 115200;
-  type  = dragon_hvsp;
+  type  = "dragon_hvsp";
 ;
 
 # AVR Dragon in debugWire mode
@@ -753,7 +753,7 @@
   id    = "dragon_dw";
   desc  = "Atmel AVR Dragon in debugWire mode";
   baudrate = 115200;
-  type  = dragon_dw;
+  type  = "dragon_dw";
 ;
 
 # AVR Dragon in PDI mode
@@ -761,13 +761,13 @@
   id    = "dragon_pdi";
   desc  = "Atmel AVR Dragon in PDI mode";
   baudrate = 115200;
-  type  = dragon_pdi;
+  type  = "dragon_pdi";
 ;
 
 programmer
   id    = "pavr";
   desc  = "Jason Kyle's pAVR Serial Programmer";
-  type  = avr910;
+  type  = "avr910";
 ;
 
 @HAVE_PARPORT_BEGIN@  Inclusion of the following depends on --enable-parport
@@ -776,7 +776,7 @@
 programmer
   id    = "bsd";
   desc  = "Brian Dean's Programmer, http://www.bsdhome.com/avrdude/";
-  type  = par;
+  type  = "par";
   vcc   = 2, 3, 4, 5;
   reset = 7;
   sck   = 8;
@@ -787,7 +787,7 @@
 programmer
   id    = "stk200";
   desc  = "STK200";
-  type  = par;
+  type  = "par";
   buff  = 4, 5;
   sck   = 6;
   mosi  = 7;
@@ -809,7 +809,7 @@
 programmer
   id    = "dt006";
   desc  = "Dontronics DT006";
-  type  = par;
+  type  = "par";
   reset = 4;
   sck   = 5;
   mosi  = 2;
@@ -824,7 +824,7 @@
 programmer
   id     = "alf";
   desc   = "Nightshade ALF-PgmAVR, http://nightshade.homeip.net/";
-  type   = par;
+  type   = "par";
   vcc    = 2, 3, 4, 5;
   buff   = 6;
   reset  = 7;
@@ -840,7 +840,7 @@
 programmer
   id    = "sp12";
   desc  = "Steve Bolt's Programmer";
-  type  = par;
+  type  = "par";
   vcc   = 4,5,6,7,8;
   reset = 3;
   sck   = 2;
@@ -851,7 +851,7 @@
 programmer
   id     = "picoweb";
   desc   = "Picoweb Programming Cable, http://www.picoweb.net/";
-  type   = par;
+  type   = "par";
   reset  = 2;
   sck    = 3;
   mosi   = 4;
@@ -861,7 +861,7 @@
 programmer
   id    = "abcmini";
   desc  = "ABCmini Board, aka Dick Smith HOTCHIP";
-  type  = par;
+  type  = "par";
   reset = 4;
   sck   = 3;
   mosi  = 2;
@@ -871,7 +871,7 @@
 programmer
   id    = "futurlec";
   desc  = "Futurlec.com programming cable.";
-  type  = par;
+  type  = "par";
   reset = 3;
   sck   = 2;
   mosi  = 1;
@@ -889,7 +889,7 @@
 programmer
   id    = "xil";
   desc  = "Xilinx JTAG cable";
-  type  = par;
+  type  = "par";
   mosi  = 2;
   sck   = 3;
   reset = 4;
@@ -902,7 +902,7 @@
 programmer
   id = "dapa";
   desc = "Direct AVR Parallel Access cable";
-  type = par;
+  type = "par";
   vcc   = 3;
   reset = 16;
   sck = 1;
@@ -913,7 +913,7 @@
 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";
   reset = ~6;
   sck   = ~8;
   mosi  = ~7;
@@ -923,7 +923,7 @@
 programmer
   id    = "ere-isp-avr";
   desc  = "ERE ISP-AVR <http://www.ere.co.th/download/sch050713.pdf>";
-  type  = par;
+  type  = "par";
   reset = ~4;
   sck   = 3;
   mosi  = 2;
@@ -933,7 +933,7 @@
 programmer
   id    = "blaster";
   desc  = "Altera ByteBlaster";
-  type  = par;
+  type  = "par";
   sck   = 2;
   miso  = 11;
   reset = 3;
@@ -955,7 +955,7 @@
 programmer
 id = "89isp";
 desc = "Atmel at89isp cable";
-type = par;
+type = "par";
 reset = 17;
 sck = 1;
 mosi = 2;
@@ -989,7 +989,7 @@
 programmer
   id    = "ponyser";
   desc  = "design ponyprog serial, reset=!txd sck=rts mosi=dtr miso=cts";
-  type  = serbb;
+  type  = "serbb";
   reset = ~3;
   sck   = 7;
   mosi  = 4;
@@ -1010,7 +1010,7 @@
 programmer
   id    = "dasa";
   desc  = "serial port banging, reset=rts sck=dtr mosi=txd miso=cts";
-  type  = serbb;
+  type  = "serbb";
   reset = 7;
   sck   = 4;
   mosi  = 3;
@@ -1023,7 +1023,7 @@
 programmer
   id    = "dasa3";
   desc  = "serial port banging, reset=!dtr sck=rts mosi=txd miso=cts";
-  type  = serbb;
+  type  = "serbb";
   reset = ~4;
   sck   = 7;
   mosi  = 3;
@@ -1036,7 +1036,7 @@
 programmer
   id    = "c2n232i";
   desc  = "serial port banging, reset=dtr sck=!rts mosi=!txd miso=!cts";
-  type  = serbb;
+  type  = "serbb";
   reset = 4;
   sck   = ~7;
   mosi  = ~3;
Index: stk500generic.c
===================================================================
--- stk500generic.c	(revision 1045)
+++ stk500generic.c	(working copy)
@@ -34,6 +34,7 @@
 
 #include "avrdude.h"
 #include "pgm.h"
+#include "stk500generic.h"
 #include "stk500.h"
 #include "stk500v2.h"
 
@@ -80,6 +81,7 @@
   pgm->teardown(pgm);
 }
 
+const char stk500generic_desc[] = "Atmel STK500, autodetect firmware version";
 
 void stk500generic_initpgm(PROGRAMMER * pgm)
 {
Index: stk500generic.h
===================================================================
--- stk500generic.h	(revision 1045)
+++ stk500generic.h	(working copy)
@@ -22,6 +22,7 @@
 #ifndef stk500generic_h__
 #define stk500generic_h__
 
+extern const char stk500generic_desc[];
 void stk500generic_initpgm (PROGRAMMER * pgm);
 
 #endif
Index: usbasp.c
===================================================================
--- usbasp.c	(revision 1045)
+++ usbasp.c	(working copy)
@@ -1161,3 +1161,6 @@
 }
 
 #endif  /* HAVE_LIBUSB */
+
+const char usbasp_desc[] = "USBasp programmer, see http://www.fischl.de/usbasp/";
+
Index: lists.c
===================================================================
--- lists.c	(revision 1045)
+++ lists.c	(working copy)
@@ -478,7 +478,7 @@
 |  at the same time.
  --------------------------------------------------*/
 void 
-ldestroy_cb ( LISTID lid, void (*ucleanup)() )
+ldestroy_cb ( LISTID lid, void (*ucleanup)(void * data_ptr) )
 {
   LIST * l;
   LISTNODE * ln;
Index: stk500v2.c
===================================================================
--- stk500v2.c	(revision 1045)
+++ stk500v2.c	(working copy)
@@ -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 @@
     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 @@
   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 @@
   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 @@
   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 @@
   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 @@
   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 @@
   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 @@
   pgm->page_size      = 256;
 }
 
+const char stk600_desc[] = "Atmel STK600";
+
 void stk600_initpgm(PROGRAMMER * pgm)
 {
   strcpy(pgm->type, "STK600");
@@ -3877,6 +3893,8 @@
   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 @@
   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");
Index: usbasp.h
===================================================================
--- usbasp.h	(revision 1045)
+++ usbasp.h	(working copy)
@@ -140,6 +140,7 @@
 extern "C" {
 #endif
 
+extern const char usbasp_desc[];
 void usbasp_initpgm (PROGRAMMER * pgm);
 
 #ifdef __cplusplus
Index: lists.h
===================================================================
--- lists.h	(revision 1045)
+++ lists.h	(working copy)
@@ -75,7 +75,7 @@
 
 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 */
Index: stk500v2.h
===================================================================
--- stk500v2.h	(revision 1045)
+++ stk500v2.h	(working copy)
@@ -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);
Index: serbb_posix.c
===================================================================
--- serbb_posix.c	(revision 1045)
+++ serbb_posix.c	(working copy)
@@ -42,6 +42,7 @@
 #include "pindefs.h"
 #include "pgm.h"
 #include "bitbang.h"
+#include "serbb.h"
 
 #undef DEBUG
 
@@ -283,6 +284,8 @@
   return;
 }
 
+const char serbb_desc[] = "Serial port bitbanging";
+
 void serbb_initpgm(PROGRAMMER *pgm)
 {
   strcpy(pgm->type, "SERBB");
Index: par.c
===================================================================
--- par.c	(revision 1045)
+++ par.c	(working copy)
@@ -42,6 +42,7 @@
 #include "pgm.h"
 #include "ppi.h"
 #include "bitbang.h"
+#include "par.h"
 
 #if HAVE_PARPORT
 
@@ -417,6 +418,8 @@
   return 0;
 }
 
+const char par_desc[] = "Parallel port bitbanging";
+
 void par_initpgm(PROGRAMMER * pgm)
 {
   strcpy(pgm->type, "PPI");
Index: main.c
===================================================================
--- main.c	(revision 1045)
+++ main.c	(working copy)
@@ -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 @@
     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)
@@ -257,7 +276,7 @@
 static void cleanup_main(void)
 {
     if (updates) {
-        ldestroy_cb(updates,free_update);
+        ldestroy_cb(updates, (void(*)(void*))free_update);
         updates = NULL;
     }
     if (extended_params) {
@@ -701,6 +720,13 @@
       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);
+    }
   }
 
 
Index: par.h
===================================================================
--- par.h	(revision 1045)
+++ par.h	(working copy)
@@ -26,6 +26,7 @@
 extern "C" {
 #endif
 
+extern const char par_desc[];
 void par_initpgm        (PROGRAMMER * pgm);
 
 #ifdef __cplusplus
Index: lexer.l
===================================================================
--- lexer.l	(revision 1045)
+++ lexer.l	(working copy)
@@ -37,6 +37,10 @@
 
 #define YY_NO_UNPUT
 
+#ifndef YYERRCODE
+#define YYERRCODE 256
+#endif
+
 %}
 
 DIGIT    [0-9]
@@ -117,20 +121,12 @@
             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; }
 desc             { yylval=NULL; return K_DESC; }
 default_parallel { yylval=NULL; return K_DEFAULT_PARALLEL; }
@@ -138,12 +134,6 @@
 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 @@
 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 @@
 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 @@
 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; }
 usbdev           { yylval=NULL; return K_USBDEV; }
 usbpid           { yylval=NULL; return K_USBPID; }
@@ -210,7 +184,6 @@
 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; }
@@ -284,10 +257,9 @@
              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; }
 
 %%
 
Index: Makefile.am
===================================================================
--- Makefile.am	(revision 1045)
+++ Makefile.am	(working copy)
@@ -125,6 +125,8 @@
 	par.h \
 	pgm.c \
 	pgm.h \
+	pgm_type.c \
+	pgm_type.h \
 	pindefs.h \
 	ppi.c \
 	ppi.h \
Index: usbtiny.c
===================================================================
--- usbtiny.c	(revision 1045)
+++ usbtiny.c	(working copy)
@@ -538,7 +538,7 @@
   return n_bytes;
 }
 
-extern void usbtiny_initpgm ( PROGRAMMER* pgm )
+void usbtiny_initpgm ( PROGRAMMER* pgm )
 {
   strcpy(pgm->type, "USBtiny");
 
@@ -584,3 +584,6 @@
 }
 
 #endif /* HAVE_LIBUSB */
+
+const char usbtiny_desc[] = "Driver for \"usbtiny\"-type programmers";
+
