diff --git a/avrdude/ChangeLog b/avrdude/ChangeLog
index 83dc43b8..6b3747fc 100644
--- a/avrdude/ChangeLog
+++ b/avrdude/ChangeLog
@@ -1,3 +1,23 @@
+2005-09-18  Joerg Wunsch <j@uriah.heep.sax.de>
+
+	Add the serial bit-bang driver, contributed by Michael Holzt.
+	* bitbang.h: New file.
+	* bitbang.c: New file.
+	* serbb.h: New file.
+	* serbb_posix.c: New file.
+	* serbb_win32.c: New file.
+	* Makefile.am: Include new files.
+	* config_gram.y: Add serbb to configuration language.
+	* lexer.l: (Ditto.)
+	* par.c: Centralize bit-bang code in bitbang.c.
+	* par.h: Declare newly published functions.
+	* pgm.h (struct programmer_t): Add a flag field for private use
+	  by the programmer.
+	* pindefs.h: Add definitions for negated serbb pins.
+	* avrdude.conf.in: Add serbb programmers ponyser, dasa, and dasa3.
+	* avrdude.1: Document serbb code.
+	* doc/avrdude.texi: (Ditto.)
+
 2005/09/18  Brian S. Dean  <bsd@bsdhome.com>
 
 	* avrdude.conf.in: Patch #4078: add VCC pin definition for DAPA
diff --git a/avrdude/Makefile.am b/avrdude/Makefile.am
index 9ca2895e..24741979 100644
--- a/avrdude/Makefile.am
+++ b/avrdude/Makefile.am
@@ -57,6 +57,8 @@ avrdude_SOURCES = \
 	avr910.h \
 	avrpart.c \
 	avrpart.h \
+	bitbang.c \
+	bitbang.h \
 	butterfly.c \
 	butterfly.h \
 	config.c \
@@ -85,6 +87,9 @@ avrdude_SOURCES = \
 	safemode.c \
 	safemode.h \
 	serial.h \
+	serbb.h \
+	serbb_posix.c \
+	serbb_win32.c \
 	ser_posix.c \
 	ser_win32.c \
 	stk500.c \
diff --git a/avrdude/NEWS b/avrdude/NEWS
index 2e15502f..1fa783bf 100644
--- a/avrdude/NEWS
+++ b/avrdude/NEWS
@@ -21,6 +21,9 @@ Current:
       - ATmega329x/649x
       - ATtiny25/45/85
 
+  * Support for serial bit-bang adapters: Ponyprog serial, UISP DASA,
+    UISP DASA3.
+
   * DAPA programmer pinout supported
 
   * New "safemode" feature where fuse bits are verified before exit
diff --git a/avrdude/avrdude.1 b/avrdude/avrdude.1
index 004540b1..81051e95 100644
--- a/avrdude/avrdude.1
+++ b/avrdude/avrdude.1
@@ -19,7 +19,7 @@
 .\"
 .\" $Id$
 .\"
-.Dd DATE August 28, 2005
+.Dd DATE September 18, 2005
 .Os
 .Dt AVRDUDE 1
 .Sh NAME
@@ -61,7 +61,8 @@ programmer connected directly to a
 .Xr ppi 4
 or
 .Xr parport 4
-parallel port.  In the simplest case, the hardware consists just of a
+parallel port, or to a standard serial port.
+In the simplest case, the hardware consists just of a
 cable connecting the respective AVR signal lines to the parallel port.
 .Pp
 The MCU is programmed in
@@ -83,6 +84,15 @@ signal is available to control a buffer/driver IC 74LS367 (or
 74HCT367).  The latter can be useful to decouple the parallel port
 from the MCU when in-system programming is used.
 .Pp
+A number of equally simple bit-bang programming adapters that connect
+to a serial port are supported as well, among them the popular
+Ponyprog serial adapter, and the DASA and DASA3 adapters that used to
+be supported by uisp(1).
+Note that these adapters are meant to be attached to a physical serial
+port.
+Connecting to a serial port emulated on top of USB is likely to not
+work at all, or to work abysmally slow.
+.Pp
 Atmel's STK500 programmer is also supported and connects to a serial
 port.
 Both, firmware versions 1.x and 2.x can be handled, but require a
diff --git a/avrdude/bitbang.c b/avrdude/bitbang.c
new file mode 100644
index 00000000..dee3cbc7
--- /dev/null
+++ b/avrdude/bitbang.c
@@ -0,0 +1,280 @@
+/*
+ * avrdude - A Downloader/Uploader for AVR device programmers
+ * Copyright (C) 2000, 2001, 2002, 2003  Brian S. Dean <bsd@bsdhome.com>
+ * Copyright (C) 2005 Michael Holzt <kju-avr@fqdn.org>
+ *
+ * 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$ */
+
+#include "ac_cfg.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include "avr.h"
+#include "pindefs.h"
+#include "pgm.h"
+#include "par.h"
+#include "serbb.h"
+
+#define SLOW_TOGGLE 0
+
+extern char * progname;
+extern int do_cycles;
+extern int verbose;
+
+static int bitbang_setpin(PROGRAMMER * pgm, int pin, int value)
+{
+  if ( pgm->flag )
+    serbb_setpin(pgm->fd,pin,value);
+  else
+    par_setpin(pgm->fd,pin,value);
+
+  return 0;
+}
+
+
+static int bitbang_getpin(PROGRAMMER * pgm, int pin)
+{
+  if ( pgm->flag )
+    return serbb_getpin(pgm->fd,pin);
+  else
+    return par_getpin(pgm->fd,pin);
+}
+
+
+static int bitbang_highpulsepin(PROGRAMMER * pgm, int pin)
+{
+  if ( pgm->flag )
+    return serbb_highpulsepin(pgm->fd,pin);
+  else
+    return par_highpulsepin(pgm->fd,pin);
+}
+
+
+/*
+ * transmit and receive a byte of data to/from the AVR device
+ */
+static unsigned char bitbang_txrx(PROGRAMMER * pgm, unsigned char byte)
+{
+  int i;
+  unsigned char r, b, rbyte;
+
+  rbyte = 0;
+  for (i=7; i>=0; i--) {
+    /*
+     * Write and read one bit on SPI.
+     * Some notes on timing: Let T be the time it takes to do
+     * one bitbang_setpin()-call resp. par clrpin()-call, then
+     * - SCK is high for 2T
+     * - SCK is low for 2T
+     * - MOSI setuptime is 1T
+     * - MOSI holdtime is 3T
+     * - SCK low to MISO read is 2T to 3T
+     * So we are within programming specs (expect for AT90S1200),
+     * if and only if T>t_CLCL (t_CLCL=clock period of target system).
+     *
+     * Due to the delay introduced by "IN" and "OUT"-commands,
+     * T is greater than 1us (more like 2us) on x86-architectures.
+     * So programming works safely down to 1MHz target clock.
+    */
+
+    b = (byte >> i) & 0x01;
+
+    /* set the data input line as desired */
+    bitbang_setpin(pgm, pgm->pinno[PIN_AVR_MOSI], b);
+
+    bitbang_setpin(pgm, pgm->pinno[PIN_AVR_SCK], 1);
+
+    /*
+     * read the result bit (it is either valid from a previous falling
+     * edge or it is ignored in the current context)
+     */
+    r = bitbang_getpin(pgm, pgm->pinno[PIN_AVR_MISO]);
+
+    bitbang_setpin(pgm, pgm->pinno[PIN_AVR_SCK], 0);
+
+    rbyte |= r << i;
+  }
+
+  return rbyte;
+}
+
+
+int bitbang_rdy_led(PROGRAMMER * pgm, int value)
+{
+  bitbang_setpin(pgm, pgm->pinno[PIN_LED_RDY], !value);
+  return 0;
+}
+
+int bitbang_err_led(PROGRAMMER * pgm, int value)
+{
+  bitbang_setpin(pgm, pgm->pinno[PIN_LED_ERR], !value);
+  return 0;
+}
+
+int bitbang_pgm_led(PROGRAMMER * pgm, int value)
+{
+  bitbang_setpin(pgm, pgm->pinno[PIN_LED_PGM], !value);
+  return 0;
+}
+
+int bitbang_vfy_led(PROGRAMMER * pgm, int value)
+{
+  bitbang_setpin(pgm, pgm->pinno[PIN_LED_VFY], !value);
+  return 0;
+}
+
+
+/*
+ * transmit an AVR device command and return the results; 'cmd' and
+ * 'res' must point to at least a 4 byte data buffer
+ */
+int bitbang_cmd(PROGRAMMER * pgm, unsigned char cmd[4],
+                   unsigned char res[4])
+{
+  int i;
+
+  for (i=0; i<4; i++) {
+    res[i] = bitbang_txrx(pgm, cmd[i]);
+  }
+
+    if(verbose >= 2)
+	{
+        fprintf(stderr, "bitbang_cmd(): [ ");
+        for(i = 0; i < 4; i++)
+            fprintf(stderr, "%02X ", cmd[i]);
+        fprintf(stderr, "] [ ");
+        for(i = 0; i < 4; i++)
+		{
+            fprintf(stderr, "%02X ", res[i]);
+		}
+        fprintf(stderr, "]\n");
+	}
+
+  return 0;
+}
+
+
+/*
+ * issue the 'chip erase' command to the AVR device
+ */
+int bitbang_chip_erase(PROGRAMMER * pgm, AVRPART * p)
+{
+  unsigned char cmd[4];
+  unsigned char res[4];
+
+  if (p->op[AVR_OP_CHIP_ERASE] == NULL) {
+    fprintf(stderr, "chip erase instruction not defined for part \"%s\"\n",
+            p->desc);
+    return -1;
+  }
+
+  pgm->pgm_led(pgm, ON);
+
+  memset(cmd, 0, sizeof(cmd));
+
+  avr_set_bits(p->op[AVR_OP_CHIP_ERASE], cmd);
+  pgm->cmd(pgm, cmd, res);
+  usleep(p->chip_erase_delay);
+  pgm->initialize(pgm, p);
+
+  pgm->pgm_led(pgm, OFF);
+
+  return 0;
+}
+
+/*
+ * issue the 'program enable' command to the AVR device
+ */
+int bitbang_program_enable(PROGRAMMER * pgm, AVRPART * p)
+{
+  unsigned char cmd[4];
+  unsigned char res[4];
+
+  if (p->op[AVR_OP_PGM_ENABLE] == NULL) {
+    fprintf(stderr, "program enable instruction not defined for part \"%s\"\n",
+            p->desc);
+    return -1;
+  }
+
+  memset(cmd, 0, sizeof(cmd));
+  avr_set_bits(p->op[AVR_OP_PGM_ENABLE], cmd);
+  pgm->cmd(pgm, cmd, res);
+
+  if (res[2] != cmd[1])
+    return -2;
+
+  return 0;
+}
+
+/*
+ * initialize the AVR device and prepare it to accept commands
+ */
+int bitbang_initialize(PROGRAMMER * pgm, AVRPART * p)
+{
+  int rc;
+  int tries;
+
+  pgm->powerup(pgm);
+  usleep(20000);
+
+  bitbang_setpin(pgm, pgm->pinno[PIN_AVR_SCK], 0);
+  bitbang_setpin(pgm, pgm->pinno[PIN_AVR_RESET], 0);
+  usleep(20000);
+
+  bitbang_highpulsepin(pgm, pgm->pinno[PIN_AVR_RESET]);
+
+  usleep(20000); /* 20 ms XXX should be a per-chip parameter */
+
+  /*
+   * Enable programming mode.  If we are programming an AT90S1200, we
+   * can only issue the command and hope it worked.  If we are using
+   * one of the other chips, the chip will echo 0x53 when issuing the
+   * third byte of the command.  In this case, try up to 32 times in
+   * order to possibly get back into sync with the chip if we are out
+   * of sync.
+   */
+  if (strcmp(p->desc, "AT90S1200")==0) {
+    pgm->program_enable(pgm, p);
+  }
+  else {
+    tries = 0;
+    do {
+      rc = pgm->program_enable(pgm, p);
+      if ((rc == 0)||(rc == -1))
+        break;
+      bitbang_highpulsepin(pgm, pgm->pinno[p->retry_pulse/*PIN_AVR_SCK*/]);
+      tries++;
+    } while (tries < 65);
+
+    /*
+     * can't sync with the device, maybe it's not attached?
+     */
+    if (rc) {
+      fprintf(stderr, "%s: AVR device not responding\n", progname);
+      return -1;
+    }
+  }
+
+  return 0;
+}
+
+
diff --git a/avrdude/bitbang.h b/avrdude/bitbang.h
new file mode 100644
index 00000000..b428e604
--- /dev/null
+++ b/avrdude/bitbang.h
@@ -0,0 +1,43 @@
+/*
+ * avrdude - A Downloader/Uploader for AVR device programmers
+ * Copyright (C) 2000, 2001, 2002, 2003  Brian S. Dean <bsd@bsdhome.com>
+ * Copyright (C) 2005 Michael Holzt <kju-avr@fqdn.org>
+ *
+ * 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 bitbang_h
+#define bitbang_h
+
+int bitbang_setpin(int fd, int pin, int value);
+int bitbang_getpin(int fd, int pin);
+int bitbang_highpulsepin(int fd, int pin);
+
+int  bitbang_rdy_led        (PROGRAMMER * pgm, int value);
+int  bitbang_err_led        (PROGRAMMER * pgm, int value);
+int  bitbang_pgm_led        (PROGRAMMER * pgm, int value);
+int  bitbang_vfy_led        (PROGRAMMER * pgm, int value);
+int  bitbang_cmd            (PROGRAMMER * pgm, unsigned char cmd[4],
+                                unsigned char res[4]);
+int  bitbang_chip_erase     (PROGRAMMER * pgm, AVRPART * p);
+int  bitbang_program_enable (PROGRAMMER * pgm, AVRPART * p);
+void bitbang_powerup        (PROGRAMMER * pgm);
+void bitbang_powerdown      (PROGRAMMER * pgm);
+int  bitbang_initialize     (PROGRAMMER * pgm, AVRPART * p);
+void bitbang_disable        (PROGRAMMER * pgm);
+void bitbang_enable         (PROGRAMMER * pgm);
+
+#endif
diff --git a/avrdude/config_gram.y b/avrdude/config_gram.y
index 88c65148..21c842c9 100644
--- a/avrdude/config_gram.y
+++ b/avrdude/config_gram.y
@@ -29,6 +29,7 @@
 #include "config.h"
 #include "lists.h"
 #include "par.h"
+#include "serbb.h"
 #include "pindefs.h"
 #include "ppi.h"
 #include "pgm.h"
@@ -49,7 +50,7 @@ extern char * progname;
 int yylex(void);
 int yyerror(char * errmsg);
 
-static int assign_pin(int pinno, TOKEN * v);
+static int assign_pin(int pinno, TOKEN * v, int invert);
 static int which_opcode(TOKEN * opcode);
 static int parse_cmdbits(OPCODE * op);
  
@@ -110,6 +111,7 @@ static int parse_cmdbits(OPCODE * op);
 %token K_READMEM
 %token K_RESET
 %token K_RETRY_PULSE
+%token K_SERBB
 %token K_SERIAL
 %token K_SCK
 %token K_SIZE
@@ -159,6 +161,7 @@ static int parse_cmdbits(OPCODE * op);
 %token TKN_COMMA
 %token TKN_EQUAL
 %token TKN_SEMI
+%token TKN_TILDE
 %token TKN_NUMBER
 %token TKN_STRING
 %token TKN_ID
@@ -325,6 +328,12 @@ prog_parm :
     }
   } |
 
+  K_TYPE TKN_EQUAL K_SERBB {
+    {
+      serbb_initpgm(current_prog);
+    }
+  } |
+
   K_TYPE TKN_EQUAL K_STK500 {
     { 
       stk500_initpgm(current_prog);
@@ -418,15 +427,26 @@ prog_parm :
   } |
 
   K_RESET  TKN_EQUAL TKN_NUMBER { free_token($1); 
-                                  assign_pin(PIN_AVR_RESET, $3); } |
+                                  assign_pin(PIN_AVR_RESET, $3, 0); } |
   K_SCK    TKN_EQUAL TKN_NUMBER { free_token($1); 
-                                  assign_pin(PIN_AVR_SCK, $3); } |
-  K_MOSI   TKN_EQUAL TKN_NUMBER { assign_pin(PIN_AVR_MOSI, $3); } |
-  K_MISO   TKN_EQUAL TKN_NUMBER { assign_pin(PIN_AVR_MISO, $3); } |
-  K_ERRLED TKN_EQUAL TKN_NUMBER { assign_pin(PIN_LED_ERR, $3); } |
-  K_RDYLED TKN_EQUAL TKN_NUMBER { assign_pin(PIN_LED_RDY, $3); } |
-  K_PGMLED TKN_EQUAL TKN_NUMBER { assign_pin(PIN_LED_PGM, $3); } |
-  K_VFYLED TKN_EQUAL TKN_NUMBER { assign_pin(PIN_LED_VFY, $3); }
+                                  assign_pin(PIN_AVR_SCK, $3, 0); } |
+  K_MOSI   TKN_EQUAL TKN_NUMBER { assign_pin(PIN_AVR_MOSI, $3, 0); } |
+  K_MISO   TKN_EQUAL TKN_NUMBER { assign_pin(PIN_AVR_MISO, $3, 0); } |
+  K_ERRLED TKN_EQUAL TKN_NUMBER { assign_pin(PIN_LED_ERR, $3, 0); } |
+  K_RDYLED TKN_EQUAL TKN_NUMBER { assign_pin(PIN_LED_RDY, $3, 0); } |
+  K_PGMLED TKN_EQUAL TKN_NUMBER { assign_pin(PIN_LED_PGM, $3, 0); } |
+  K_VFYLED TKN_EQUAL TKN_NUMBER { assign_pin(PIN_LED_VFY, $3, 0); } |
+
+  K_RESET  TKN_EQUAL TKN_TILDE TKN_NUMBER { free_token($1); 
+                                  assign_pin(PIN_AVR_RESET, $4, 1); } |
+  K_SCK    TKN_EQUAL TKN_TILDE TKN_NUMBER { free_token($1); 
+                                  assign_pin(PIN_AVR_SCK, $4, 1); } |
+  K_MOSI   TKN_EQUAL TKN_TILDE TKN_NUMBER { assign_pin(PIN_AVR_MOSI, $4, 1); } |
+  K_MISO   TKN_EQUAL TKN_TILDE TKN_NUMBER { assign_pin(PIN_AVR_MISO, $4, 1); } |
+  K_ERRLED TKN_EQUAL TKN_TILDE TKN_NUMBER { assign_pin(PIN_LED_ERR, $4, 1); } |
+  K_RDYLED TKN_EQUAL TKN_TILDE TKN_NUMBER { assign_pin(PIN_LED_RDY, $4, 1); } |
+  K_PGMLED TKN_EQUAL TKN_TILDE TKN_NUMBER { assign_pin(PIN_LED_PGM, $4, 1); } |
+  K_VFYLED TKN_EQUAL TKN_TILDE TKN_NUMBER { assign_pin(PIN_LED_VFY, $4, 1); }
 ;
 
 
@@ -854,7 +874,7 @@ static char * vtypestr(int type)
 #endif
 
 
-static int assign_pin(int pinno, TOKEN * v)
+static int assign_pin(int pinno, TOKEN * v, int invert)
 {
   int value;
 
@@ -867,6 +887,8 @@ static int assign_pin(int pinno, TOKEN * v)
             progname, lineno, infile);
     exit(1);
   }
+  if (invert)
+    value |= PIN_INVERSE;
 
   current_prog->pinno[pinno] = value;
 
diff --git a/avrdude/doc/avrdude.texi b/avrdude/doc/avrdude.texi
index 2f91262d..69cbd4b7 100644
--- a/avrdude/doc/avrdude.texi
+++ b/avrdude/doc/avrdude.texi
@@ -129,9 +129,10 @@ from the contents of a file, while interactive mode is useful for
 exploring memory contents, modifing individual bytes of eeprom,
 programming fuse/lock bits, etc.
 
-AVRDUDE supports five basic programmer types: Atmel's STK500,
+AVRDUDE supports six basic programmer types: Atmel's STK500,
 Atmel's JTAG ICE mkII, appnote
 avr910, appnote avr109 (including the AVR Butterfly),
+serial bit-bang adapters,
 and the PPI (parallel port interface). PPI represents a class
 of simple programmers where the programming lines are directly
 connected to the PC parallel port. Several pin configurations exist
@@ -139,7 +140,15 @@ for several variations of the PPI programmers, and AVRDUDE can be be
 configured to work with them by either specifying the appropriate
 programmer on the command line or by creating a new entry in its
 configuration file. All that's usually required for a new entry is to
-tell AVRDUDE which pins to use for each programming function. 
+tell AVRDUDE which pins to use for each programming function.
+
+A number of equally simple bit-bang programming adapters that connect
+to a serial port are supported as well, among them the popular
+Ponyprog serial adapter, and the DASA and DASA3 adapters that used to
+be supported by uisp(1).  Note that these adapters are meant to be
+attached to a physical serial port.  Connecting to a serial port
+emulated on top of USB is likely to not work at all, or to work
+abysmally slow.
 
 The STK500, JTAG ICE, avr910, and avr109/butterfly use the serial port to communicate with the PC.
 The STK500, JTAG ICE, and avr910 contain on-board logic to control the programming of the target
diff --git a/avrdude/lexer.l b/avrdude/lexer.l
index a8386fc1..c834624e 100644
--- a/avrdude/lexer.l
+++ b/avrdude/lexer.l
@@ -160,6 +160,7 @@ 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; }
 size             { yylval=NULL; return K_SIZE; }
 spmcr            { yylval=NULL; return K_SPMCR; }
@@ -212,6 +213,7 @@ yes              { yylval=new_token(K_YES); return K_YES; }
 ","       { yylval = NULL; pyytext(); return TKN_COMMA; }
 "="       { yylval = NULL; pyytext(); return TKN_EQUAL; }
 ";"       { yylval = NULL; pyytext(); return TKN_SEMI; }
+"~"       { yylval = NULL; pyytext(); return TKN_TILDE; }
 
 "\n"      { lineno++; }
 [ \r\t]+  /* ignore whitespace */
diff --git a/avrdude/par.c b/avrdude/par.c
index 33c07be1..fd257b38 100644
--- a/avrdude/par.c
+++ b/avrdude/par.c
@@ -37,8 +37,8 @@
 #include "avr.h"
 #include "pindefs.h"
 #include "pgm.h"
-#include "par.h"
 #include "ppi.h"
+#include "bitbang.h"
 
 #define SLOW_TOGGLE 0
 
@@ -49,7 +49,7 @@ struct ppipins_t {
   int inverted;
 };
 
-static struct ppipins_t pins[] = {
+struct ppipins_t ppipins[] = {
   {  1, PPICTRL,   0x01, 1 },
   {  2, PPIDATA,   0x01, 0 },
   {  3, PPIDATA,   0x02, 0 },
@@ -69,66 +69,30 @@ static struct ppipins_t pins[] = {
   { 17, PPICTRL,   0x08, 1 }
 };
 
-#define NPINS (sizeof(pins)/sizeof(struct ppipins_t))
+#define NPINS (sizeof(ppipins)/sizeof(struct ppipins_t))
 
 
 extern char * progname;
 extern int do_cycles;
 extern int verbose;
 
-
-static int par_setpin          (int fd, int pin, int value);
-
-static int par_getpin          (int fd, int pin);
-
-static int par_pulsepin        (int fd, int pin);
-
-
-static int  par_rdy_led        (PROGRAMMER * pgm, int value);
-
-static int  par_err_led        (PROGRAMMER * pgm, int value);
-
-static int  par_pgm_led        (PROGRAMMER * pgm, int value);
-
-static int  par_vfy_led        (PROGRAMMER * pgm, int value);
-
-static int  par_cmd            (PROGRAMMER * pgm, unsigned char cmd[4], 
-                                unsigned char res[4]);
-
-static int  par_chip_erase     (PROGRAMMER * pgm, AVRPART * p);
-
-static int  par_program_enable (PROGRAMMER * pgm, AVRPART * p);
-
-static void par_powerup        (PROGRAMMER * pgm);
-
-static void par_powerdown      (PROGRAMMER * pgm);
-
-static int  par_initialize     (PROGRAMMER * pgm, AVRPART * p);
-
-static void par_disable        (PROGRAMMER * pgm);
-
-static void par_enable         (PROGRAMMER * pgm);
-
-static int  par_open           (PROGRAMMER * pgm, char * port);
-
-static void par_close          (PROGRAMMER * pgm);
-
-
-static int par_setpin(int fd, int pin, int value)
+int par_setpin(int fd, int pin, int value)
 {
 
+  pin &= PIN_MASK;
+
   if (pin < 1 || pin > 17)
     return -1;
 
   pin--;
 
-  if (pins[pin].inverted)
+  if (ppipins[pin].inverted)
     value = !value;
 
   if (value)
-    ppi_set(fd, pins[pin].reg, pins[pin].bit);
+    ppi_set(fd, ppipins[pin].reg, ppipins[pin].bit);
   else
-    ppi_clr(fd, pins[pin].reg, pins[pin].bit);
+    ppi_clr(fd, ppipins[pin].reg, ppipins[pin].bit);
 
 #if SLOW_TOGGLE
   usleep(1000);
@@ -138,28 +102,30 @@ static int par_setpin(int fd, int pin, int value)
 }
 
 
-static int par_getpin(int fd, int pin)
+int par_getpin(int fd, int pin)
 {
   int value;
 
+  pin &= PIN_MASK;
+
   if (pin < 1 || pin > 17)
     return -1;
 
   pin--;
 
-  value = ppi_get(fd, pins[pin].reg, pins[pin].bit);
+  value = ppi_get(fd, ppipins[pin].reg, ppipins[pin].bit);
 
   if (value)
     value = 1;
     
-  if (pins[pin].inverted)
+  if (ppipins[pin].inverted)
     value = !value;
 
   return value;
 }
 
 
-static int par_pulsepin(int fd, int pin)
+int par_highpulsepin(int fd, int pin)
 {
 
   if (pin < 1 || pin > 17)
@@ -167,13 +133,11 @@ static int par_pulsepin(int fd, int pin)
 
   pin--;
 
-  ppi_toggle(fd, pins[pin].reg, pins[pin].bit);
-
+  ppi_set(fd, ppipins[pin].reg, ppipins[pin].bit);
 #if SLOW_TOGGLE
   usleep(1000);
 #endif
-
-  ppi_toggle(fd, pins[pin].reg, pins[pin].bit);
+  ppi_clr(fd, ppipins[pin].reg, ppipins[pin].bit);
 
 #if SLOW_TOGGLE
   usleep(1000);
@@ -184,15 +148,17 @@ static int par_pulsepin(int fd, int pin)
 
 int par_getpinmask(int pin)
 {
+  pin &= PIN_MASK;
+
   if (pin < 1 || pin > 17)
     return -1;
 
-  return pins[pin-1].bit;
+  return ppipins[pin-1].bit;
 }
 
 
-static char vccpins_buf[64];
-static char * vccpins_str(unsigned int pmask)
+char vccpins_buf[64];
+char * vccpins_str(unsigned int pmask)
 {
   unsigned int mask;
   int pin;
@@ -214,169 +180,10 @@ static char * vccpins_str(unsigned int pmask)
   return b;
 }
 
-
-
-/*
- * transmit and receive a byte of data to/from the AVR device
- */
-static unsigned char par_txrx(PROGRAMMER * pgm, unsigned char byte)
-{
-  int i;
-  unsigned char r, b, rbyte;
-
-  rbyte = 0;
-  for (i=7; i>=0; i--) {
-    /*
-     * Write and read one bit on SPI.
-     * Some notes on timing: Let T be the time it takes to do
-     * one par_setpin()-call resp. par clrpin()-call, then
-     * - SCK is high for 2T
-     * - SCK is low for 2T
-     * - MOSI setuptime is 1T
-     * - MOSI holdtime is 3T
-     * - SCK low to MISO read is 2T to 3T
-     * So we are within programming specs (expect for AT90S1200),
-     * if and only if T>t_CLCL (t_CLCL=clock period of target system).
-     *
-     * Due to the delay introduced by "IN" and "OUT"-commands,
-     * T is greater than 1us (more like 2us) on x86-architectures.
-     * So programming works safely down to 1MHz target clock.
-    */
-
-    b = (byte >> i) & 0x01;
-
-    /* set the data input line as desired */
-    par_setpin(pgm->fd, pgm->pinno[PIN_AVR_MOSI], b);
-
-    par_setpin(pgm->fd, pgm->pinno[PIN_AVR_SCK], 1);
-
-    /*
-     * read the result bit (it is either valid from a previous falling
-     * edge or it is ignored in the current context)
-     */
-    r = par_getpin(pgm->fd, pgm->pinno[PIN_AVR_MISO]);
-
-    par_setpin(pgm->fd, pgm->pinno[PIN_AVR_SCK], 0);
-
-    rbyte |= r << i;
-  }
-
-  return rbyte;
-}
-
-
-static int par_rdy_led(PROGRAMMER * pgm, int value)
-{
-  par_setpin(pgm->fd, pgm->pinno[PIN_LED_RDY], !value);
-  return 0;
-}
-
-static int par_err_led(PROGRAMMER * pgm, int value)
-{
-  par_setpin(pgm->fd, pgm->pinno[PIN_LED_ERR], !value);
-  return 0;
-}
-
-static int par_pgm_led(PROGRAMMER * pgm, int value)
-{
-  par_setpin(pgm->fd, pgm->pinno[PIN_LED_PGM], !value);
-  return 0;
-}
-
-static int par_vfy_led(PROGRAMMER * pgm, int value)
-{
-  par_setpin(pgm->fd, pgm->pinno[PIN_LED_VFY], !value);
-  return 0;
-}
-
-
-/*
- * transmit an AVR device command and return the results; 'cmd' and
- * 'res' must point to at least a 4 byte data buffer
- */
-static int par_cmd(PROGRAMMER * pgm, unsigned char cmd[4], 
-                   unsigned char res[4])
-{
-  int i;
-
-  for (i=0; i<4; i++) {
-    res[i] = par_txrx(pgm, cmd[i]);
-  }
-
-    if(verbose >= 2)
-	{
-        fprintf(stderr, "par_cmd(): [ ");
-        for(i = 0; i < 4; i++)
-            fprintf(stderr, "%02X ", cmd[i]);
-        fprintf(stderr, "] [ ");
-        for(i = 0; i < 4; i++)
-		{
-            fprintf(stderr, "%02X ", res[i]);
-		}
-        fprintf(stderr, "]\n");
-	}
-
-  return 0;
-}
-
-
-/*
- * issue the 'chip erase' command to the AVR device
- */
-static int par_chip_erase(PROGRAMMER * pgm, AVRPART * p)
-{
-  unsigned char cmd[4];
-  unsigned char res[4];
-
-  if (p->op[AVR_OP_CHIP_ERASE] == NULL) {
-    fprintf(stderr, "chip erase instruction not defined for part \"%s\"\n",
-            p->desc);
-    return -1;
-  }
-
-  pgm->pgm_led(pgm, ON);
-
-  memset(cmd, 0, sizeof(cmd));
-
-  avr_set_bits(p->op[AVR_OP_CHIP_ERASE], cmd);
-  pgm->cmd(pgm, cmd, res);
-  usleep(p->chip_erase_delay);
-  pgm->initialize(pgm, p);
-
-  pgm->pgm_led(pgm, OFF);
-
-  return 0;
-}
-
-/*
- * issue the 'program enable' command to the AVR device
- */
-static int par_program_enable(PROGRAMMER * pgm, AVRPART * p)
-{
-  unsigned char cmd[4];
-  unsigned char res[4];
-
-  if (p->op[AVR_OP_PGM_ENABLE] == NULL) {
-    fprintf(stderr, "program enable instruction not defined for part \"%s\"\n",
-            p->desc);
-    return -1;
-  }
-
-  memset(cmd, 0, sizeof(cmd));
-  avr_set_bits(p->op[AVR_OP_PGM_ENABLE], cmd);
-  pgm->cmd(pgm, cmd, res);
-
-  if (res[2] != cmd[1])
-    return -2;
-
-  return 0;
-}
-
-
 /*
  * apply power to the AVR processor
  */
-static void par_powerup(PROGRAMMER * pgm)
+void par_powerup(PROGRAMMER * pgm)
 {
   ppi_set(pgm->fd, PPIDATA, pgm->pinno[PPI_AVR_VCC]);    /* power up */
   usleep(100000);
@@ -386,71 +193,17 @@ static void par_powerup(PROGRAMMER * pgm)
 /*
  * remove power from the AVR processor
  */
-static void par_powerdown(PROGRAMMER * pgm)
+void par_powerdown(PROGRAMMER * pgm)
 {
   ppi_clr(pgm->fd, PPIDATA, pgm->pinno[PPI_AVR_VCC]);    /* power down */
 }
 
-
-/*
- * initialize the AVR device and prepare it to accept commands
- */
-static int par_initialize(PROGRAMMER * pgm, AVRPART * p)
-{
-  int rc;
-  int tries;
-
-  pgm->powerup(pgm);
-  usleep(20000);
-
-  par_setpin(pgm->fd, pgm->pinno[PIN_AVR_SCK], 0);
-  par_setpin(pgm->fd, pgm->pinno[PIN_AVR_RESET], 0);
-  usleep(20000);
-
-  par_pulsepin(pgm->fd, pgm->pinno[PIN_AVR_RESET]);
-
-  usleep(20000); /* 20 ms XXX should be a per-chip parameter */
-
-  /*
-   * Enable programming mode.  If we are programming an AT90S1200, we
-   * can only issue the command and hope it worked.  If we are using
-   * one of the other chips, the chip will echo 0x53 when issuing the
-   * third byte of the command.  In this case, try up to 32 times in
-   * order to possibly get back into sync with the chip if we are out
-   * of sync.
-   */
-  if (strcmp(p->desc, "AT90S1200")==0) {
-    pgm->program_enable(pgm, p);
-  }
-  else {
-    tries = 0;
-    do {
-      rc = pgm->program_enable(pgm, p);
-      if ((rc == 0)||(rc == -1))
-        break;
-      par_pulsepin(pgm->fd, pgm->pinno[p->retry_pulse/*PIN_AVR_SCK*/]);
-      tries++;
-    } while (tries < 65);
-
-    /*
-     * can't sync with the device, maybe it's not attached?
-     */
-    if (rc) {
-      fprintf(stderr, "%s: AVR device not responding\n", progname);
-      return -1;
-    }
-  }
-
-  return 0;
-}
-
-
-static void par_disable(PROGRAMMER * pgm)
+void par_disable(PROGRAMMER * pgm)
 {
   ppi_set(pgm->fd, PPIDATA, pgm->pinno[PPI_AVR_BUFF]);
 }
 
-static void par_enable(PROGRAMMER * pgm)
+void par_enable(PROGRAMMER * pgm)
 {
   /*
    * Prepare to start talking to the connected device - pull reset low
@@ -472,8 +225,7 @@ static void par_enable(PROGRAMMER * pgm)
   ppi_clr(pgm->fd, PPIDATA, pgm->pinno[PPI_AVR_BUFF]);
 }
 
-
-static int par_open(PROGRAMMER * pgm, char * port)
+int par_open(PROGRAMMER * pgm, char * port)
 {
   int rc;
 
@@ -507,7 +259,7 @@ static int par_open(PROGRAMMER * pgm, char * port)
 }
 
 
-static void par_close(PROGRAMMER * pgm)
+void par_close(PROGRAMMER * pgm)
 {
   /*
    * Restore pin values before closing,
@@ -523,8 +275,7 @@ static void par_close(PROGRAMMER * pgm)
   pgm->fd = -1;
 }
 
-
-static void par_display(PROGRAMMER * pgm, char * p)
+void par_display(PROGRAMMER * pgm, char * p)
 {
   char vccpins[64];
   char buffpins[64];
@@ -574,21 +325,22 @@ void par_initpgm(PROGRAMMER * pgm)
 {
   strcpy(pgm->type, "PPI");
 
-  pgm->rdy_led        = par_rdy_led;
-  pgm->err_led        = par_err_led;
-  pgm->pgm_led        = par_pgm_led;
-  pgm->vfy_led        = par_vfy_led;
-  pgm->initialize     = par_initialize;
+  pgm->rdy_led        = bitbang_rdy_led;
+  pgm->err_led        = bitbang_err_led;
+  pgm->pgm_led        = bitbang_pgm_led;
+  pgm->vfy_led        = bitbang_vfy_led;
+  pgm->initialize     = bitbang_initialize;
   pgm->display        = par_display;
   pgm->enable         = par_enable;
   pgm->disable        = par_disable;
   pgm->powerup        = par_powerup;
   pgm->powerdown      = par_powerdown;
-  pgm->program_enable = par_program_enable;
-  pgm->chip_erase     = par_chip_erase;
-  pgm->cmd            = par_cmd;
+  pgm->program_enable = bitbang_program_enable;
+  pgm->chip_erase     = bitbang_chip_erase;
+  pgm->cmd            = bitbang_cmd;
   pgm->open           = par_open;
   pgm->close          = par_close;
+  
+  /* this is a parallel port bitbang device */
+  pgm->flag	      = 0;
 }
-
-
diff --git a/avrdude/par.h b/avrdude/par.h
index 0aa24fa1..cb1d00a9 100644
--- a/avrdude/par.h
+++ b/avrdude/par.h
@@ -25,6 +25,9 @@
 void par_initpgm        (PROGRAMMER * pgm);
 
 int par_getpinmask(int pin);
+int par_setpin(int fd, int pin, int value);
+int par_getpin(int fd, int pin);
+int par_highpulsepin(int fd, int pin);
 
 #endif
 
diff --git a/avrdude/pgm.h b/avrdude/pgm.h
index 75f6cf0d..4482c580 100644
--- a/avrdude/pgm.h
+++ b/avrdude/pgm.h
@@ -83,6 +83,7 @@ typedef struct programmer_t {
   int  (*set_sck_period) (struct programmer_t * pgm, double v);
   char config_file[PATH_MAX]; /* config file where defined */
   int  lineno;                /* config file line number */
+  char flag;		      /* for private use of the programmer */
 } PROGRAMMER;
 
 
diff --git a/avrdude/pindefs.h b/avrdude/pindefs.h
index 25dc20f9..9c16ed1c 100644
--- a/avrdude/pindefs.h
+++ b/avrdude/pindefs.h
@@ -35,6 +35,8 @@ enum {
   PIN_LED_VFY,
   N_PINS
 };
+#define PIN_INVERSE 0x80	/* flag for inverted pin in serbb */
+#define PIN_MASK    0x7f
 
 #define LED_ON(fd,pin)  ppi_setpin(fd,pin,0)
 #define LED_OFF(fd,pin) ppi_setpin(fd,pin,1)
diff --git a/avrdude/serbb.h b/avrdude/serbb.h
new file mode 100644
index 00000000..0760f6e0
--- /dev/null
+++ b/avrdude/serbb.h
@@ -0,0 +1,33 @@
+/*
+ * avrdude - A Downloader/Uploader for AVR device programmers
+ * Copyright (C) 2000, 2001, 2002, 2003  Brian S. Dean <bsd@bsdhome.com>
+ * Copyright (C) 2005 Michael Holzt <kju-avr@fqdn.org>
+ *
+ * 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 serbb_h
+#define serbb_h
+
+void serbb_initpgm        (PROGRAMMER * pgm);
+
+int serbb_setpin(int fd, int pin, int value);
+int serbb_getpin(int fd, int pin);
+int serbb_highpulsepin(int fd, int pin);
+
+#endif
+
+
diff --git a/avrdude/serbb_posix.c b/avrdude/serbb_posix.c
new file mode 100644
index 00000000..04f261bf
--- /dev/null
+++ b/avrdude/serbb_posix.c
@@ -0,0 +1,271 @@
+/*
+ * avrdude - A Downloader/Uploader for AVR device programmers
+ * Copyright (C) 2000, 2001, 2002, 2003  Brian S. Dean <bsd@bsdhome.com>
+ * Copyright (C) 2005 Michael Holzt <kju-avr@fqdn.org>
+ *
+ * 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$ */
+
+/*
+ * Posix serial bitbanging interface for avrdude.
+ */
+
+#if !defined(WIN32NATIVE)
+
+#include "ac_cfg.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/ioctl.h>
+#include <termios.h>
+
+#include "avr.h"
+#include "pindefs.h"
+#include "pgm.h"
+#include "bitbang.h"
+
+#undef DEBUG
+
+extern char *progname;
+struct termios oldmode;
+
+/*
+  serial port/pin mapping
+
+  1	cd	<-
+  2	rxd	<-
+  3	txd	->
+  4	dtr	->
+  5	dsr	<-
+  6	rts	->
+  7	cts	<-
+*/
+
+int serregbits[] =
+{ TIOCM_CD, 0, 0, TIOCM_DTR, TIOCM_DSR, TIOCM_RTS, TIOCM_CTS };
+
+#ifdef DEBUG
+char *serpins[7] =
+  { "CD", "RXD", "TXD ~RESET", "DTR MOSI", "DSR", "RTS SCK", "CTS MISO" };
+#endif
+
+void serbb_setpin(int fd, int pin, int value)
+{
+  unsigned int	ctl;
+
+  if (pin & PIN_INVERSE)
+  {
+    value  = !value;
+    pin   &= PIN_MASK;
+  }
+
+  if ( pin < 1 || pin > 7 )
+    return;
+
+  pin--;
+
+#ifdef DEBUG
+  printf("%s to %d\n",serpins[pin],value);
+#endif
+
+  switch ( pin )
+  {
+    case 2:  /* txd */
+             ioctl(fd, value ? TIOCSBRK : TIOCCBRK, 0);
+             return;
+
+    case 3:  /* dtr, rts */
+    case 5:  ioctl(fd, TIOCMGET, &ctl);
+             if ( value )
+               ctl |= serregbits[pin];
+             else
+               ctl &= ~(serregbits[pin]);
+             ioctl(fd, TIOCMSET, &ctl);
+             return;
+
+    default: /* impossible */
+             return;
+  }
+}
+
+int serbb_getpin(int fd, int pin)
+{
+  unsigned int	ctl;
+  unsigned char invert;
+
+  if (pin & PIN_INVERSE)
+  {
+    invert = 1;
+    pin   &= PIN_MASK;
+  } else
+    invert = 0;
+
+  if ( pin < 1 || pin > 7 )
+    return(-1);
+
+  pin --;
+
+  switch ( pin )
+  {
+    case 1:  /* rxd, currently not implemented, FIXME */
+             return(-1);
+
+    case 0:  /* cd, dsr, dtr, rts, cts */
+    case 3:
+    case 4:
+    case 5:
+    case 6:  ioctl(fd, TIOCMGET, &ctl);
+             if ( !invert )
+             {
+#ifdef DEBUG
+               printf("%s is %d\n",serpins[pin],(ctl & serregbits[pin]) ? 1 : 0 );
+#endif
+               return ( (ctl & serregbits[pin]) ? 1 : 0 );
+             }
+             else
+             {
+#ifdef DEBUG
+               printf("%s is %d (~)\n",serpins[pin],(ctl & serregbits[pin]) ? 0 : 1 );
+#endif
+               return (( ctl & serregbits[pin]) ? 0 : 1 );
+             }
+
+    default: /* impossible */
+             return(-1);
+  }
+}
+
+int serbb_highpulsepin(int fd, int pin)
+{
+  if (pin < 1 || pin > 7)
+    return -1;
+
+  serbb_setpin(fd, pin, 1);
+  #if SLOW_TOGGLE
+  usleep(1000);
+  #endif
+  serbb_setpin(fd, pin, 0);
+
+  #if SLOW_TOGGLE
+  usleep(1000);
+  #endif
+
+  return 0;
+}
+
+
+
+void serbb_display(PROGRAMMER *pgm, char *p)
+{
+  /* MAYBE */
+}
+
+void serbb_enable(PROGRAMMER *pgm)
+{
+  /* nothing */
+}
+
+void serbb_disable(PROGRAMMER *pgm)
+{
+  /* nothing */
+}
+
+void serbb_powerup(PROGRAMMER *pgm)
+{
+  /* nothing */
+}
+
+void serbb_powerdown(PROGRAMMER *pgm)
+{
+  /* nothing */
+}
+
+int serbb_open(PROGRAMMER *pgm, char *port)
+{
+  struct termios mode;
+  int flags;
+
+  /* adapted from uisp code */
+
+  pgm->fd = open(port, O_RDWR | O_NOCTTY | O_NONBLOCK);
+
+  if ( pgm->fd > 0 )
+  {
+    tcgetattr(pgm->fd, &mode);
+    oldmode = mode;
+
+    cfmakeraw(&mode);
+    mode.c_iflag &= ~(INPCK | IXOFF | IXON);
+    mode.c_cflag &= ~(HUPCL | CSTOPB | CRTSCTS);
+    mode.c_cflag |= (CLOCAL | CREAD);
+    mode.c_cc [VMIN] = 1;
+    mode.c_cc [VTIME] = 0;
+
+    tcsetattr(pgm->fd, TCSANOW, &mode);
+
+    /* Clear O_NONBLOCK flag.  */
+    flags = fcntl(pgm->fd, F_GETFL, 0);
+    if (flags == -1)
+    {
+      fprintf(stderr, "%s: Can not get flags\n", progname);
+      return(-1);
+    }
+    flags &= ~O_NONBLOCK;
+    if (fcntl(pgm->fd, F_SETFL, flags) == -1)
+    {
+      fprintf(stderr, "%s: Can not clear nonblock flag\n", progname);
+      return(-1);
+    }
+  }
+
+  return(0);
+}
+
+void serbb_close(PROGRAMMER *pgm)
+{
+  tcsetattr(pgm->fd, TCSADRAIN, &oldmode);
+  return;
+}
+
+void serbb_initpgm(PROGRAMMER *pgm)
+{
+  strcpy(pgm->type, "SERBB");
+
+  pgm->rdy_led        = bitbang_rdy_led;
+  pgm->err_led        = bitbang_err_led;
+  pgm->pgm_led        = bitbang_pgm_led;
+  pgm->vfy_led        = bitbang_vfy_led;
+  pgm->initialize     = bitbang_initialize;
+  pgm->display        = serbb_display;
+  pgm->enable         = serbb_enable;
+  pgm->disable        = serbb_disable;
+  pgm->powerup        = serbb_powerup;
+  pgm->powerdown      = serbb_powerdown;
+  pgm->program_enable = bitbang_program_enable;
+  pgm->chip_erase     = bitbang_chip_erase;
+  pgm->cmd            = bitbang_cmd;
+  pgm->open           = serbb_open;
+  pgm->close          = serbb_close;
+
+  /* this is a serial port bitbang device */
+  pgm->flag           = 1;
+}
+
+#endif  /* WIN32NATIVE */
diff --git a/avrdude/serbb_win32.c b/avrdude/serbb_win32.c
new file mode 100644
index 00000000..79fc9834
--- /dev/null
+++ b/avrdude/serbb_win32.c
@@ -0,0 +1,372 @@
+/*
+ * avrdude - A Downloader/Uploader for AVR device programmers
+ * Copyright (C) 2003, 2004  Martin J. Thomas  <mthomas@rhrk.uni-kl.de>
+ * Copyright (C) 2005 Michael Holzt <kju-avr@fqdn.org>
+ * Copyright (C) 2005 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$ */
+
+/*
+ * Win32 serial bitbanging interface for avrdude.
+ */
+
+#if defined(WIN32NATIVE)
+
+
+#include "ac_cfg.h"
+
+#include <windows.h>
+#include <stdio.h>
+
+#include "avr.h"
+#include "pindefs.h"
+#include "pgm.h"
+#include "bitbang.h"
+
+extern char *progname;
+extern int verbose;
+
+/* cached status lines */
+static int dtr, rts, txd;
+
+#define W32SERBUFSIZE 1024
+
+/*
+  serial port/pin mapping
+
+  1	cd	<-
+  2	rxd	<-
+  3	txd	->
+  4	dtr	->
+  5	dsr	<-
+  6	rts	->
+  7	cts	<-
+
+  Negative pin # means negated value.
+*/
+
+void serbb_setpin(int fd, int pin, int value)
+{
+	HANDLE hComPort = (HANDLE)fd;
+        LPVOID lpMsgBuf;
+        DWORD dwFunc;
+        const char *name;
+
+        if (pin & PIN_INVERSE)
+        {
+                value = !value;
+                pin &= PIN_MASK;
+        }
+
+        if (pin < 1 || pin > 7)
+                return;
+
+        pin--;
+
+        switch (pin)
+        {
+        case 2:  /* txd */
+                dwFunc = value? SETBREAK: CLRBREAK;
+                name = value? "SETBREAK": "CLRBREAK";
+                txd = value;
+                break;
+
+        case 3:  /* dtr */
+                dwFunc = value? SETDTR: CLRDTR;
+                name = value? "SETDTR": "CLRDTR";
+                dtr = value;
+                break;
+
+        case 5:  /* rts */
+                dwFunc = value? SETRTS: CLRRTS;
+                name = value? "SETRTS": "CLRRTS";
+                break;
+
+        default:
+                if (verbose)
+                        fprintf(stderr,
+                                "%s: serbb_setpin(): unknown pin %d\n",
+                                progname, pin + 1);
+                return;
+        }
+        if (verbose > 4)
+                fprintf(stderr,
+                        "%s: serbb_setpin(): EscapeCommFunction(%s)\n",
+                        progname, name);
+        if (!EscapeCommFunction(hComPort, dwFunc))
+        {
+                FormatMessage(
+                        FORMAT_MESSAGE_ALLOCATE_BUFFER |
+                        FORMAT_MESSAGE_FROM_SYSTEM |
+                        FORMAT_MESSAGE_IGNORE_INSERTS,
+                        NULL,
+                        GetLastError(),
+                        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
+                        (LPTSTR) &lpMsgBuf,
+                        0,
+                        NULL);
+                fprintf(stderr,
+                        "%s: serbb_setpin(): SetCommState() failed: %s\n",
+                        progname, (char *)lpMsgBuf);
+                CloseHandle(hComPort);
+                LocalFree(lpMsgBuf);
+                exit(1);
+        }
+        return;
+}
+
+int serbb_getpin(int fd, int pin)
+{
+	HANDLE hComPort = (HANDLE)fd;
+        LPVOID lpMsgBuf;
+        int invert, rv;
+        const char *name;
+        DWORD modemstate;
+
+        if (pin & PIN_INVERSE)
+        {
+                invert = 1;
+                pin &= PIN_MASK;
+        } else
+                invert = 0;
+
+        if (pin < 1 || pin > 7)
+                return -1;
+
+        pin --;
+
+        if (pin == 0 /* cd */ || pin == 4 /* dsr */ || pin == 6 /* cts */)
+        {
+                if (!GetCommModemStatus(hComPort, &modemstate))
+                {
+                        FormatMessage(
+                                FORMAT_MESSAGE_ALLOCATE_BUFFER |
+                                FORMAT_MESSAGE_FROM_SYSTEM |
+                                FORMAT_MESSAGE_IGNORE_INSERTS,
+                                NULL,
+                                GetLastError(),
+                                MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
+                                (LPTSTR) &lpMsgBuf,
+                                0,
+                                NULL);
+                        fprintf(stderr,
+                                "%s: serbb_setpin(): GetCommModemStatus() failed: %s\n",
+                                progname, (char *)lpMsgBuf);
+                        CloseHandle(hComPort);
+                        LocalFree(lpMsgBuf);
+                        exit(1);
+                }
+                if (verbose > 4)
+                        fprintf(stderr,
+                                "%s: serbb_getpin(): GetCommState() => 0x%lx\n",
+                                progname, modemstate);
+                switch (pin)
+                {
+                case 0:
+                        modemstate &= MS_RLSD_ON;
+                        break;
+                case 4:
+                        modemstate &= MS_DSR_ON;
+                        break;
+                case 6:
+                        modemstate &= MS_CTS_ON;
+                        break;
+                }
+                rv = modemstate != 0;
+                if (invert)
+                        rv = !rv;
+
+                return rv;
+        }
+
+        switch (pin)
+        {
+        case 2: /* txd */
+                rv = txd;
+                name = "TXD";
+                break;
+        case 3: /* dtr */
+                rv = dtr;
+                name = "DTR";
+                break;
+        case 5: /* rts */
+                rv = rts;
+                name = "RTS";
+                break;
+        default:
+                if (verbose)
+                        fprintf(stderr,
+                                "%s: serbb_getpin(): unknown pin %d\n",
+                                progname, pin + 1);
+                return -1;
+        }
+        if (verbose > 4)
+                fprintf(stderr,
+                        "%s: serbb_getpin(): return cached state for %s\n",
+                        progname, name);
+        if (invert)
+                rv = !rv;
+
+        return rv;
+}
+
+int serbb_highpulsepin(int fd, int pin)
+{
+        if (pin < 1 || pin > 7)
+                return -1;
+
+        serbb_setpin(fd, pin, 1);
+#if SLOW_TOGGLE
+        usleep(1000);
+#endif
+        serbb_setpin(fd, pin, 0);
+
+#if SLOW_TOGGLE
+        usleep(1000);
+#endif
+
+        return 0;
+}
+
+
+void serbb_display(PROGRAMMER *pgm, char *p)
+{
+  /* MAYBE */
+}
+
+void serbb_enable(PROGRAMMER *pgm)
+{
+  /* nothing */
+}
+
+void serbb_disable(PROGRAMMER *pgm)
+{
+  /* nothing */
+}
+
+void serbb_powerup(PROGRAMMER *pgm)
+{
+  /* nothing */
+}
+
+void serbb_powerdown(PROGRAMMER *pgm)
+{
+  /* nothing */
+}
+
+int serbb_open(PROGRAMMER *pgm, char *port)
+{
+        DCB dcb;
+	LPVOID lpMsgBuf;
+	HANDLE hComPort = INVALID_HANDLE_VALUE;
+
+	hComPort = CreateFile(port, GENERIC_READ | GENERIC_WRITE, 0, NULL,
+                              OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+
+	if (hComPort == INVALID_HANDLE_VALUE) {
+		FormatMessage(
+			FORMAT_MESSAGE_ALLOCATE_BUFFER |
+			FORMAT_MESSAGE_FROM_SYSTEM |
+			FORMAT_MESSAGE_IGNORE_INSERTS,
+			NULL,
+			GetLastError(),
+			MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
+			(LPTSTR) &lpMsgBuf,
+			0,
+			NULL);
+		fprintf(stderr, "%s: ser_open(): can't open device \"%s\": %s\n",
+                        progname, port, (char*)lpMsgBuf);
+		LocalFree(lpMsgBuf);
+                return -1;
+	}
+
+	if (!SetupComm(hComPort, W32SERBUFSIZE, W32SERBUFSIZE))
+	{
+		CloseHandle(hComPort);
+		fprintf(stderr, "%s: ser_open(): can't set buffers for \"%s\"\n",
+                        progname, port);
+                return -1;
+	}
+
+
+	ZeroMemory(&dcb, sizeof(DCB));
+	dcb.DCBlength = sizeof(DCB);
+	dcb.BaudRate = CBR_9600;
+	dcb.fBinary = 1;
+	dcb.fDtrControl = DTR_CONTROL_DISABLE;
+	dcb.fRtsControl = RTS_CONTROL_DISABLE;
+	dcb.ByteSize = 8;
+	dcb.Parity = NOPARITY;
+	dcb.StopBits = ONESTOPBIT;
+
+	if (!SetCommState(hComPort, &dcb))
+	{
+		CloseHandle(hComPort);
+		fprintf(stderr, "%s: ser_open(): can't set com-state for \"%s\"\n",
+                        progname, port);
+                return -1;
+	}
+        if (verbose > 2)
+                fprintf(stderr,
+                        "%s: ser_open(): opened comm port \"%s\", handle 0x%x\n",
+                        progname, port, (int)hComPort);
+
+        pgm->fd = (int)hComPort;
+
+        dtr = rts = txd = 0;
+
+        return 0;
+}
+
+void serbb_close(PROGRAMMER *pgm)
+{
+	HANDLE hComPort=(HANDLE)pgm->fd;
+	if (hComPort != INVALID_HANDLE_VALUE)
+		CloseHandle (hComPort);
+        if (verbose > 2)
+                fprintf(stderr,
+                        "%s: ser_close(): closed comm port handle 0x%x\n",
+                        progname, (int)hComPort);
+
+	hComPort = INVALID_HANDLE_VALUE;
+}
+
+void serbb_initpgm(PROGRAMMER *pgm)
+{
+  strcpy(pgm->type, "SERBB");
+
+  pgm->rdy_led        = bitbang_rdy_led;
+  pgm->err_led        = bitbang_err_led;
+  pgm->pgm_led        = bitbang_pgm_led;
+  pgm->vfy_led        = bitbang_vfy_led;
+  pgm->initialize     = bitbang_initialize;
+  pgm->display        = serbb_display;
+  pgm->enable         = serbb_enable;
+  pgm->disable        = serbb_disable;
+  pgm->powerup        = serbb_powerup;
+  pgm->powerdown      = serbb_powerdown;
+  pgm->program_enable = bitbang_program_enable;
+  pgm->chip_erase     = bitbang_chip_erase;
+  pgm->cmd            = bitbang_cmd;
+  pgm->open           = serbb_open;
+  pgm->close          = serbb_close;
+
+  /* this is a serial port bitbang device */
+  pgm->flag           = 1;
+}
+
+#endif  /* WIN32NATIVE */