diff --git a/ChangeLog b/ChangeLog
index b6d65577..dd721e80 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,23 @@
+2006-09-20 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	Add the "stk500generic" programmer that auto-probes for STK500
+	either firmware version 1 or 2.
+	* Makefile.am (avrdude_SOURCES): add the new files
+	stk500generic.c and stk500generic.h.
+	* avrdude.conf.in: Add the stk500generic programmer type, and
+	change the "stk500" entry to point to this programmer.
+	* config_gram.y: Add the stk500generic keyword.
+	* lexer.l: (Ditto.)
+	* stk500.c: Change the stk500v1 code to not call exit()
+	prematurely when failing to open the programmer, but instead
+	return an error status.
+	* stk500generic.c: (New file.) Stub programmer implementation.
+	Probe for either stk500v1 or stk500v2, and adjust the current pgm
+	appropriately.
+	* stk500generic.h: (New file.) Declare the public interface(s)
+	of stk500generic.c.
+	* doc/avrdude.texi: Document the changed behaviour of stk500.
+
 2006-09-18 Joerg Wunsch <j@uriah.heep.sax.de>
 
 	* avrdude.conf.in: Various fixes for ancient processors and their
diff --git a/Makefile.am b/Makefile.am
index b640e6ce..b2300a07 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -121,6 +121,8 @@ avrdude_SOURCES = \
 	stk500v2.c \
 	stk500v2.h \
 	stk500v2_private.h \
+	stk500generic.c \
+	stk500generic.h \
 	term.c \
 	term.h \
 	usbasp.c \
diff --git a/avrdude.conf.in b/avrdude.conf.in
index a0a51c27..6b1ff2c2 100644
--- a/avrdude.conf.in
+++ b/avrdude.conf.in
@@ -15,7 +15,7 @@
 #   programmer
 #       id       = <id1> [, <id2> [, <id3>] ...] ;  # <idN> are quoted strings
 #       desc     = <description> ;                  # quoted string
-#       type     = par | stk500 | stk500v2 | stk500pp | stk500hvsp |
+#       type     = par | stk500 | stk500v2 | stk500pp | stk500hvsp | stk500generic |
 #                  avr910 | butterfly | usbasp |
 #                  jtagmki | jtagmkii | jtagmkii_isp; # programmer type
 #       baudrate = <num> ;                          # baudrate for avr910-programmer
@@ -316,12 +316,13 @@ programmer
 ;
 
 # This is supposed to be the "default" STK500 entry.
-# Refers to V1 by now, might be changed to V2 in a
-# future release.
+# Attempts to select the correct firmware version
+# by probing for it.  Better use one of the entries
+# below instead.
 programmer
   id    = "stk500";
   desc  = "Atmel STK500";
-  type  = stk500;
+  type  = stk500generic;
 ;
 
 programmer
diff --git a/config_gram.y b/config_gram.y
index 785f2e27..10dc23f2 100644
--- a/config_gram.y
+++ b/config_gram.y
@@ -36,6 +36,7 @@
 #include "pgm.h"
 #include "stk500.h"
 #include "stk500v2.h"
+#include "stk500generic.h"
 #include "avr910.h"
 #include "butterfly.h"
 #include "usbasp.h"
@@ -126,6 +127,7 @@ static int parse_cmdbits(OPCODE * op);
 %token K_STK500HVSP
 %token K_STK500PP
 %token K_STK500V2
+%token K_STK500GENERIC
 %token K_AVR910
 %token K_USBASP
 %token K_BUTTERFLY
@@ -393,6 +395,12 @@ prog_parm :
     }
   } |
 
+  K_TYPE TKN_EQUAL K_STK500GENERIC {
+    {
+      stk500generic_initpgm(current_prog);
+    }
+  } |
+
   K_TYPE TKN_EQUAL K_AVR910 {
     { 
       avr910_initpgm(current_prog);
diff --git a/doc/avrdude.texi b/doc/avrdude.texi
index c3a05ab8..27265c1e 100644
--- a/doc/avrdude.texi
+++ b/doc/avrdude.texi
@@ -401,7 +401,9 @@ Steve Bolt's Programmer
 @item @code{stk200}      @tab
 STK200
 @item @code{stk500}      @tab
-Atmel STK500
+Atmel STK500, probing for either version 1.x or 2.x firmware
+@item @code{stk500v1}    @tab
+Atmel STK500, running a version 1.x firmware
 @item @code{stk500hvsp}  @tab
 Atmel STK500 in high-voltage serial programming mode(version 2.x firmware only)
 @item @code{stk500pp}    @tab
diff --git a/lexer.l b/lexer.l
index 867149a3..32ccc928 100644
--- a/lexer.l
+++ b/lexer.l
@@ -176,6 +176,7 @@ 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; }
 type             { yylval=NULL; return K_TYPE; }
 vcc              { yylval=NULL; return K_VCC; }
diff --git a/stk500.c b/stk500.c
index 170962dd..a17f301b 100644
--- a/stk500.c
+++ b/stk500.c
@@ -70,7 +70,7 @@ static int stk500_recv(PROGRAMMER * pgm, unsigned char * buf, size_t len)
     fprintf(stderr,
 	    "%s: stk500_recv(): programmer is not responding\n",
 	    progname);
-    exit(1);
+    return -1;
   }
   return 0;
 }
@@ -101,22 +101,24 @@ static int stk500_getsync(PROGRAMMER * pgm)
   stk500_drain(pgm, 0);
 
   stk500_send(pgm, buf, 2);
-  stk500_recv(pgm, resp, 1);
+  if (stk500_recv(pgm, resp, 1) < 0)
+    return -1;
   if (resp[0] != Resp_STK_INSYNC) {
     fprintf(stderr, 
             "%s: stk500_getsync(): not in sync: resp=0x%02x\n",
             progname, resp[0]);
     stk500_drain(pgm, 0);
-    exit(1);
+    return -1;
   }
 
-  stk500_recv(pgm, resp, 1);
+  if (stk500_recv(pgm, resp, 1) < 0)
+    return -1;
   if (resp[0] != Resp_STK_OK) {
     fprintf(stderr, 
             "%s: stk500_getsync(): can't communicate with device: "
             "resp=0x%02x\n",
             progname, resp[0]);
-    exit(1);
+    return -1;
   }
 
   return 0;
@@ -141,7 +143,8 @@ static int stk500_cmd(PROGRAMMER * pgm, unsigned char cmd[4],
 
   stk500_send(pgm, buf, 6);
 
-  stk500_recv(pgm, buf, 1);
+  if (stk500_recv(pgm, buf, 1) < 0)
+    exit(1);
   if (buf[0] != Resp_STK_INSYNC) {
     fprintf(stderr, "%s: stk500_cmd(): programmer is out of sync\n", progname);
     exit(1);
@@ -150,9 +153,11 @@ static int stk500_cmd(PROGRAMMER * pgm, unsigned char cmd[4],
   res[0] = cmd[1];
   res[1] = cmd[2];
   res[2] = cmd[3];
-  stk500_recv(pgm, &res[3], 1);
+  if (stk500_recv(pgm, &res[3], 1) < 0)
+    exit(1);
 
-  stk500_recv(pgm, buf, 1);
+  if (stk500_recv(pgm, buf, 1) < 0)
+    exit(1);
   if (buf[0] != Resp_STK_OK) {
     fprintf(stderr, "%s: stk500_cmd(): protocol error\n", progname);
     exit(1);
@@ -207,14 +212,16 @@ static int stk500_program_enable(PROGRAMMER * pgm, AVRPART * p)
   buf[1] = Sync_CRC_EOP;
 
   stk500_send(pgm, buf, 2);
-  stk500_recv(pgm, buf, 1);
+  if (stk500_recv(pgm, buf, 1) < 0)
+    exit(1);
   if (buf[0] == Resp_STK_NOSYNC) {
     if (tries > 33) {
       fprintf(stderr, "%s: stk500_program_enable(): can't get into sync\n",
               progname);
       return -1;
     }
-    stk500_getsync(pgm);
+    if (stk500_getsync(pgm) < 0)
+      return -1;
     goto retry;
   }
   else if (buf[0] != Resp_STK_INSYNC) {
@@ -225,7 +232,8 @@ static int stk500_program_enable(PROGRAMMER * pgm, AVRPART * p)
     return -1;
   }
 
-  stk500_recv(pgm, buf, 1);
+  if (stk500_recv(pgm, buf, 1) < 0)
+    exit(1);
   if (buf[0] == Resp_STK_OK) {
     return 0;
   }
@@ -271,14 +279,16 @@ static int stk500_set_extended_parms(PROGRAMMER * pgm, int n,
   buf[i] = Sync_CRC_EOP;
 
   stk500_send(pgm, buf, i+1);
-  stk500_recv(pgm, buf, 1);
+  if (stk500_recv(pgm, buf, 1) < 0)
+    exit(1);
   if (buf[0] == Resp_STK_NOSYNC) {
     if (tries > 33) {
       fprintf(stderr, "%s: stk500_set_extended_parms(): can't get into sync\n",
               progname);
       return -1;
     }
-    stk500_getsync(pgm);
+    if (stk500_getsync(pgm) < 0)
+      return -1;
     goto retry;
   }
   else if (buf[0] != Resp_STK_INSYNC) {
@@ -289,7 +299,8 @@ static int stk500_set_extended_parms(PROGRAMMER * pgm, int n,
     return -1;
   }
 
-  stk500_recv(pgm, buf, 1);
+  if (stk500_recv(pgm, buf, 1) < 0)
+    exit(1);
   if (buf[0] == Resp_STK_OK) {
     return 0;
   }
@@ -436,14 +447,16 @@ static int stk500_initialize(PROGRAMMER * pgm, AVRPART * p)
   buf[21] = Sync_CRC_EOP;
 
   stk500_send(pgm, buf, 22);
-  stk500_recv(pgm, buf, 1);
+  if (stk500_recv(pgm, buf, 1) < 0)
+    exit(1);
   if (buf[0] == Resp_STK_NOSYNC) {
     fprintf(stderr,
             "%s: stk500_initialize(): programmer not in sync, resp=0x%02x\n", 
             progname, buf[0]);
     if (tries > 33)
       return -1;
-    stk500_getsync(pgm);
+    if (stk500_getsync(pgm) < 0)
+      return -1;
     goto retry;
     return -1;
   }
@@ -455,7 +468,8 @@ static int stk500_initialize(PROGRAMMER * pgm, AVRPART * p)
     return -1;
   }
 
-  stk500_recv(pgm, buf, 1);
+  if (stk500_recv(pgm, buf, 1) < 0)
+    exit(1);
   if (buf[0] != Resp_STK_OK) {
     fprintf(stderr,
             "%s: stk500_initialize(): (b) protocol error, "
@@ -517,14 +531,16 @@ static void stk500_disable(PROGRAMMER * pgm)
   buf[1] = Sync_CRC_EOP;
 
   stk500_send(pgm, buf, 2);
-  stk500_recv(pgm, buf, 1);
+  if (stk500_recv(pgm, buf, 1) < 0)
+    exit(1);
   if (buf[0] == Resp_STK_NOSYNC) {
     if (tries > 33) {
       fprintf(stderr, "%s: stk500_disable(): can't get into sync\n",
               progname);
       return;
     }
-    stk500_getsync(pgm);
+    if (stk500_getsync(pgm) < 0)
+      return;
     goto retry;
   }
   else if (buf[0] != Resp_STK_INSYNC) {
@@ -535,7 +551,8 @@ static void stk500_disable(PROGRAMMER * pgm)
     return;
   }
 
-  stk500_recv(pgm, buf, 1);
+  if (stk500_recv(pgm, buf, 1) < 0)
+    exit(1);
   if (buf[0] == Resp_STK_OK) {
     return;
   }
@@ -570,7 +587,8 @@ static int stk500_open(PROGRAMMER * pgm, char * port)
    */
   stk500_drain(pgm, 0);
 
-  stk500_getsync(pgm);
+  if (stk500_getsync(pgm) < 0)
+    return -1;
 
   stk500_drain(pgm, 0);
 
@@ -600,14 +618,16 @@ static int stk500_loadaddr(PROGRAMMER * pgm, unsigned int addr)
 
   stk500_send(pgm, buf, 4);
 
-  stk500_recv(pgm, buf, 1);
+  if (stk500_recv(pgm, buf, 1) < 0)
+    exit(1);
   if (buf[0] == Resp_STK_NOSYNC) {
     if (tries > 33) {
       fprintf(stderr, "%s: stk500_loadaddr(): can't get into sync\n",
               progname);
       return -1;
     }
-    stk500_getsync(pgm);
+    if (stk500_getsync(pgm) < 0)
+      return -1;
     goto retry;
   }
   else if (buf[0] != Resp_STK_INSYNC) {
@@ -618,7 +638,8 @@ static int stk500_loadaddr(PROGRAMMER * pgm, unsigned int addr)
     return -1;
   }
 
-  stk500_recv(pgm, buf, 1);
+  if (stk500_recv(pgm, buf, 1) < 0)
+    exit(1);
   if (buf[0] == Resp_STK_OK) {
     return 0;
   }
@@ -718,14 +739,16 @@ static int stk500_paged_write(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
     buf[0] = Sync_CRC_EOP;
     stk500_send(pgm, buf, 1);
 
-    stk500_recv(pgm, buf, 1);
+    if (stk500_recv(pgm, buf, 1) < 0)
+      exit(1);
     if (buf[0] == Resp_STK_NOSYNC) {
       if (tries > 33) {
         fprintf(stderr, "\n%s: stk500_paged_write(): can't get into sync\n",
                 progname);
         return -3;
       }
-      stk500_getsync(pgm);
+      if (stk500_getsync(pgm) < 0)
+	return -1;
       goto retry;
     }
     else if (buf[0] != Resp_STK_INSYNC) {
@@ -736,7 +759,8 @@ static int stk500_paged_write(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
       return -4;
     }
     
-    stk500_recv(pgm, buf, 1);
+    if (stk500_recv(pgm, buf, 1) < 0)
+      exit(1);
     if (buf[0] != Resp_STK_OK) {
       fprintf(stderr,
               "\n%s: stk500_paged_write(): (a) protocol error, "
@@ -824,14 +848,16 @@ static int stk500_paged_load(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
     buf[4] = Sync_CRC_EOP;
     stk500_send(pgm, buf, 5);
 
-    stk500_recv(pgm, buf, 1);
+    if (stk500_recv(pgm, buf, 1) < 0)
+      exit(1);
     if (buf[0] == Resp_STK_NOSYNC) {
       if (tries > 33) {
         fprintf(stderr, "\n%s: stk500_paged_load(): can't get into sync\n",
                 progname);
         return -3;
       }
-      stk500_getsync(pgm);
+      if (stk500_getsync(pgm) < 0)
+	return -1;
       goto retry;
     }
     else if (buf[0] != Resp_STK_INSYNC) {
@@ -842,9 +868,11 @@ static int stk500_paged_load(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
       return -4;
     }
 
-    stk500_recv(pgm, &m->buf[addr], block_size);
+    if (stk500_recv(pgm, &m->buf[addr], block_size) < 0)
+      exit(1);
 
-    stk500_recv(pgm, buf, 1);
+    if (stk500_recv(pgm, buf, 1) < 0)
+      exit(1);
     if (buf[0] != Resp_STK_OK) {
       fprintf(stderr,
               "\n%s: stk500_paged_load(): (a) protocol error, "
@@ -1003,14 +1031,16 @@ static int stk500_getparm(PROGRAMMER * pgm, unsigned parm, unsigned * value)
 
   stk500_send(pgm, buf, 3);
 
-  stk500_recv(pgm, buf, 1);
+  if (stk500_recv(pgm, buf, 1) < 0)
+    exit(1);
   if (buf[0] == Resp_STK_NOSYNC) {
     if (tries > 33) {
       fprintf(stderr, "\n%s: stk500_getparm(): can't get into sync\n",
               progname);
       return -1;
     }
-    stk500_getsync(pgm);
+    if (stk500_getsync(pgm) < 0)
+      return -1;
     goto retry;
   }
   else if (buf[0] != Resp_STK_INSYNC) {
@@ -1021,10 +1051,12 @@ static int stk500_getparm(PROGRAMMER * pgm, unsigned parm, unsigned * value)
     return -2;
   }
 
-  stk500_recv(pgm, buf, 1);
+  if (stk500_recv(pgm, buf, 1) < 0)
+    exit(1);
   v = buf[0];
 
-  stk500_recv(pgm, buf, 1);
+  if (stk500_recv(pgm, buf, 1) < 0)
+    exit(1);
   if (buf[0] == Resp_STK_FAILED) {
     fprintf(stderr,
             "\n%s: stk500_getparm(): parameter 0x%02x failed\n",
@@ -1059,14 +1091,16 @@ static int stk500_setparm(PROGRAMMER * pgm, unsigned parm, unsigned value)
 
   stk500_send(pgm, buf, 4);
 
-  stk500_recv(pgm, buf, 1);
+  if (stk500_recv(pgm, buf, 1) < 0)
+    exit(1);
   if (buf[0] == Resp_STK_NOSYNC) {
     if (tries > 33) {
       fprintf(stderr, "\n%s: stk500_setparm(): can't get into sync\n",
               progname);
       return -1;
     }
-    stk500_getsync(pgm);
+    if (stk500_getsync(pgm) < 0)
+      return -1;
     goto retry;
   }
   else if (buf[0] != Resp_STK_INSYNC) {
@@ -1077,12 +1111,14 @@ static int stk500_setparm(PROGRAMMER * pgm, unsigned parm, unsigned value)
     return -2;
   }
 
-  stk500_recv(pgm, buf, 1);
+  if (stk500_recv(pgm, buf, 1) < 0)
+    exit(1);
   if (buf[0] == Resp_STK_OK)
     return 0;
 
   parm = buf[0];	/* if not STK_OK, we've been echoed parm here */
-  stk500_recv(pgm, buf, 1);
+  if (stk500_recv(pgm, buf, 1) < 0)
+    exit(1);
   if (buf[0] == Resp_STK_FAILED) {
     fprintf(stderr,
             "\n%s: stk500_setparm(): parameter 0x%02x failed\n",
diff --git a/stk500generic.c b/stk500generic.c
new file mode 100644
index 00000000..db334f23
--- /dev/null
+++ b/stk500generic.c
@@ -0,0 +1,72 @@
+/*
+ * avrdude - A Downloader/Uploader for AVR device programmers
+ * Copyright (C) 2006 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$ */
+
+/*
+ * avrdude interface for Atmel STK500 programmer
+ *
+ * This is a wrapper around the STK500[v1] and STK500v2 programmers.
+ * Try to select the programmer type that actually responds, and
+ * divert to the actual programmer implementation if successful.
+ */
+
+#include "ac_cfg.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#include "pgm.h"
+#include "stk500.h"
+#include "stk500v2.h"
+
+extern char *progname;
+
+static int stk500generic_open(PROGRAMMER * pgm, char * port)
+{
+  stk500_initpgm(pgm);
+  if (pgm->open(pgm, port) >= 0)
+    {
+      fprintf(stderr,
+	      "%s: successfully opened stk500v1 device -- please use -c stk500v1\n",
+	      progname);
+      return 0;
+    }
+
+  stk500v2_initpgm(pgm);
+  if (pgm->open(pgm, port) >= 0)
+    {
+      fprintf(stderr,
+	      "%s: successfully opened stk500v2 device -- please use -c stk500v2\n",
+	      progname);
+      return 0;
+    }
+
+  fprintf(stderr,
+	  "%s: cannot open either stk500v1 or stk500v2 programmer\n",
+	  progname);
+  return -1;
+}
+
+void stk500generic_initpgm(PROGRAMMER * pgm)
+{
+  strcpy(pgm->type, "STK500GENERIC");
+
+  pgm->open           = stk500generic_open;
+}
diff --git a/stk500generic.h b/stk500generic.h
new file mode 100644
index 00000000..89af83b1
--- /dev/null
+++ b/stk500generic.h
@@ -0,0 +1,29 @@
+/*
+ * avrdude - A Downloader/Uploader for AVR device programmers
+ * Copyright (C) 2006 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$ */
+
+#ifndef stk500generic_h__
+#define stk500generic_h__
+
+void stk500generic_initpgm (PROGRAMMER * pgm);
+
+#endif
+
+