diff -pu avrdude-5.1/Makefile.am.orig avrdude-5.1/Makefile.am
--- avrdude-5.1/Makefile.am.orig	2006-01-13 00:13:50.000000000 +0100
+++ avrdude-5.1/Makefile.am	2006-02-11 22:09:53.000000000 +0100
@@ -62,6 +62,8 @@ avrdude_SOURCES = \
 	bitbang.h \
 	butterfly.c \
 	butterfly.h \
+	usbtiny.c \
+	usbtiny.h \
 	config.c \
 	config.h \
 	confwin.c \
diff -pu avrdude-5.1/Makefile.in.orig avrdude-5.1/Makefile.in
--- avrdude-5.1/Makefile.in.orig	2006-01-23 22:45:25.000000000 +0100
+++ avrdude-5.1/Makefile.in	2006-03-25 23:05:12.000000000 +0100
@@ -88,17 +88,17 @@ am_avrdude_OBJECTS = avrdude-config_gram
 	avrdude-lexer.$(OBJEXT) avrdude-avr.$(OBJEXT) \
 	avrdude-avr910.$(OBJEXT) avrdude-avrpart.$(OBJEXT) \
 	avrdude-bitbang.$(OBJEXT) avrdude-butterfly.$(OBJEXT) \
-	avrdude-config.$(OBJEXT) avrdude-confwin.$(OBJEXT) \
-	avrdude-crc16.$(OBJEXT) avrdude-fileio.$(OBJEXT) \
-	avrdude-jtagmkI.$(OBJEXT) avrdude-jtagmkII.$(OBJEXT) \
-	avrdude-lists.$(OBJEXT) avrdude-main.$(OBJEXT) \
-	avrdude-par.$(OBJEXT) avrdude-pgm.$(OBJEXT) \
-	avrdude-ppi.$(OBJEXT) avrdude-ppiwin.$(OBJEXT) \
-	avrdude-safemode.$(OBJEXT) avrdude-serbb_posix.$(OBJEXT) \
-	avrdude-serbb_win32.$(OBJEXT) avrdude-ser_posix.$(OBJEXT) \
-	avrdude-ser_win32.$(OBJEXT) avrdude-stk500.$(OBJEXT) \
-	avrdude-stk500v2.$(OBJEXT) avrdude-term.$(OBJEXT) \
-	avrdude-usb_libusb.$(OBJEXT)
+	avrdude-usbtiny.$(OBJEXT) avrdude-config.$(OBJEXT) \
+	avrdude-confwin.$(OBJEXT) avrdude-crc16.$(OBJEXT) \
+	avrdude-fileio.$(OBJEXT) avrdude-jtagmkI.$(OBJEXT) \
+	avrdude-jtagmkII.$(OBJEXT) avrdude-lists.$(OBJEXT) \
+	avrdude-main.$(OBJEXT) avrdude-par.$(OBJEXT) \
+	avrdude-pgm.$(OBJEXT) avrdude-ppi.$(OBJEXT) \
+	avrdude-ppiwin.$(OBJEXT) avrdude-safemode.$(OBJEXT) \
+	avrdude-serbb_posix.$(OBJEXT) avrdude-serbb_win32.$(OBJEXT) \
+	avrdude-ser_posix.$(OBJEXT) avrdude-ser_win32.$(OBJEXT) \
+	avrdude-stk500.$(OBJEXT) avrdude-stk500v2.$(OBJEXT) \
+	avrdude-term.$(OBJEXT) avrdude-usb_libusb.$(OBJEXT)
 avrdude_OBJECTS = $(am_avrdude_OBJECTS)
 avrdude_LDADD = $(LDADD)
 DEFAULT_INCLUDES = -I. -I$(srcdir) -I.
@@ -271,6 +271,8 @@ avrdude_SOURCES = \
 	bitbang.h \
 	butterfly.c \
 	butterfly.h \
+	usbtiny.c \
+	usbtiny.h \
 	config.c \
 	config.h \
 	confwin.c \
@@ -445,6 +447,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/avrdude-stk500v2.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/avrdude-term.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/avrdude-usb_libusb.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/avrdude-usbtiny.Po@am__quote@
 
 .c.o:
 @am__fastdepCC_TRUE@	if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
@@ -558,6 +561,20 @@ avrdude-butterfly.obj: butterfly.c
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(avrdude_CPPFLAGS) $(CPPFLAGS) $(avrdude_CFLAGS) $(CFLAGS) -c -o avrdude-butterfly.obj `if test -f 'butterfly.c'; then $(CYGPATH_W) 'butterfly.c'; else $(CYGPATH_W) '$(srcdir)/butterfly.c'; fi`
 
+avrdude-usbtiny.o: usbtiny.c
+@am__fastdepCC_TRUE@	if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(avrdude_CPPFLAGS) $(CPPFLAGS) $(avrdude_CFLAGS) $(CFLAGS) -MT avrdude-usbtiny.o -MD -MP -MF "$(DEPDIR)/avrdude-usbtiny.Tpo" -c -o avrdude-usbtiny.o `test -f 'usbtiny.c' || echo '$(srcdir)/'`usbtiny.c; \
+@am__fastdepCC_TRUE@	then mv -f "$(DEPDIR)/avrdude-usbtiny.Tpo" "$(DEPDIR)/avrdude-usbtiny.Po"; else rm -f "$(DEPDIR)/avrdude-usbtiny.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='usbtiny.c' object='avrdude-usbtiny.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(avrdude_CPPFLAGS) $(CPPFLAGS) $(avrdude_CFLAGS) $(CFLAGS) -c -o avrdude-usbtiny.o `test -f 'usbtiny.c' || echo '$(srcdir)/'`usbtiny.c
+
+avrdude-usbtiny.obj: usbtiny.c
+@am__fastdepCC_TRUE@	if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(avrdude_CPPFLAGS) $(CPPFLAGS) $(avrdude_CFLAGS) $(CFLAGS) -MT avrdude-usbtiny.obj -MD -MP -MF "$(DEPDIR)/avrdude-usbtiny.Tpo" -c -o avrdude-usbtiny.obj `if test -f 'usbtiny.c'; then $(CYGPATH_W) 'usbtiny.c'; else $(CYGPATH_W) '$(srcdir)/usbtiny.c'; fi`; \
+@am__fastdepCC_TRUE@	then mv -f "$(DEPDIR)/avrdude-usbtiny.Tpo" "$(DEPDIR)/avrdude-usbtiny.Po"; else rm -f "$(DEPDIR)/avrdude-usbtiny.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='usbtiny.c' object='avrdude-usbtiny.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(avrdude_CPPFLAGS) $(CPPFLAGS) $(avrdude_CFLAGS) $(CFLAGS) -c -o avrdude-usbtiny.obj `if test -f 'usbtiny.c'; then $(CYGPATH_W) 'usbtiny.c'; else $(CYGPATH_W) '$(srcdir)/usbtiny.c'; fi`
+
 avrdude-config.o: config.c
 @am__fastdepCC_TRUE@	if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(avrdude_CPPFLAGS) $(CPPFLAGS) $(avrdude_CFLAGS) $(CFLAGS) -MT avrdude-config.o -MD -MP -MF "$(DEPDIR)/avrdude-config.Tpo" -c -o avrdude-config.o `test -f 'config.c' || echo '$(srcdir)/'`config.c; \
 @am__fastdepCC_TRUE@	then mv -f "$(DEPDIR)/avrdude-config.Tpo" "$(DEPDIR)/avrdude-config.Po"; else rm -f "$(DEPDIR)/avrdude-config.Tpo"; exit 1; fi
diff -pu avrdude-5.1/avrdude.conf.in.orig avrdude-5.1/avrdude.conf.in
--- avrdude-5.1/avrdude.conf.in.orig	2006-01-17 22:01:25.000000000 +0100
+++ avrdude-5.1/avrdude.conf.in	2006-02-11 22:09:53.000000000 +0100
@@ -537,6 +537,12 @@ programmer
   miso  = 7;
 ;
 
+programmer
+  id	= "usbtiny";
+  desc	= "USB programmer built with ATtiny2313";
+  type	= usbtiny;
+;
+
 #
 # PART DEFINITIONS
 #
diff -pu avrdude-5.1/config_gram.y.orig avrdude-5.1/config_gram.y
--- avrdude-5.1/config_gram.y.orig	2005-11-25 07:14:06.000000000 +0100
+++ avrdude-5.1/config_gram.y	2006-02-11 22:09:53.000000000 +0100
@@ -40,6 +40,7 @@
 #include "avr.h"
 #include "jtagmkI.h"
 #include "jtagmkII.h"
+#include "usbtiny.h"
 
 #if defined(WIN32NATIVE)
 #define strtok_r( _s, _sep, _lasts ) \
@@ -125,6 +126,7 @@ static int parse_cmdbits(OPCODE * op);
 %token K_VCC
 %token K_VFYLED
 %token K_WRITEPAGE
+%token K_USBTINY
 
 %token K_NO
 %token K_YES
@@ -372,6 +374,12 @@ prog_parm :
     }
   } |
 
+  K_TYPE TKN_EQUAL K_USBTINY {
+    {
+      usbtiny_initpgm(current_prog);
+    }
+  } |
+
   K_DESC TKN_EQUAL TKN_STRING {
     strncpy(current_prog->desc, $3->value.string, PGM_DESCLEN);
     current_prog->desc[PGM_DESCLEN-1] = 0;
diff -pu avrdude-5.1/lexer.l.orig avrdude-5.1/lexer.l
--- avrdude-5.1/lexer.l.orig	2005-11-25 07:14:06.000000000 +0100
+++ avrdude-5.1/lexer.l	2006-02-11 22:09:53.000000000 +0100
@@ -172,6 +172,7 @@ stk500           { yylval=NULL; return K
 stk500v2         { yylval=NULL; return K_STK500V2; }
 stk500_devcode   { yylval=NULL; return K_STK500_DEVCODE; }
 type             { yylval=NULL; return K_TYPE; }
+usbtiny          { yylval=NULL; return K_USBTINY; }
 vcc              { yylval=NULL; return K_VCC; }
 vfyled           { yylval=NULL; return K_VFYLED; }
 
diff -pu /dev/null avrdude-5.1/usbtiny.c
--- /dev/null	2006-01-16 00:01:55.000000000 +0100
+++ avrdude-5.1/usbtiny.c	2006-02-25 20:51:32.000000000 +0100
@@ -0,0 +1,414 @@
+// ----------------------------------------------------------------------
+// Driver for the "usbtiny" programmer.
+//
+// Copyright (C) 2006 Dick Streefland
+//
+// This is free software, licensed under the terms of the GNU General
+// Public License as published by the Free Software Foundation.
+// ----------------------------------------------------------------------
+
+#include <string.h>
+#include <usb.h>
+#include "pgm.h"
+#include "avr.h"
+
+#define	USBDEV_VENDOR	0x1964
+#define	USBDEV_PRODUCT	0x0001
+
+enum
+{
+	// Generic requests
+	USBTINY_ECHO,		// echo test
+	USBTINY_READ,		// read byte (wIndex:address)
+	USBTINY_WRITE,		// write byte (wIndex:address, wValue:value)
+	USBTINY_CLR,		// clear bit (wIndex:address, wValue:bitno)
+	USBTINY_SET,		// set bit (wIndex:address, wValue:bitno)
+	// Programming requests
+	USBTINY_POWERUP,	// apply power (wValue:SCK-period, wIndex:RESET)
+	USBTINY_POWERDOWN,	// remove power from chip
+	USBTINY_SPI,		// issue SPI command (wValue:c1c0, wIndex:c3c2)
+	USBTINY_POLL_BYTES,	// set poll bytes for write (wValue:p1p2)
+	USBTINY_FLASH_READ,	// read flash (wIndex:address)
+	USBTINY_FLASH_WRITE,	// write flash (wIndex:address, wValue:timeout)
+	USBTINY_EEPROM_READ,	// read eeprom (wIndex:address)
+	USBTINY_EEPROM_WRITE,	// write eeprom (wIndex:address, wValue:timeout)
+};
+
+enum
+{
+	RESET_LOW	= 0,
+	RESET_HIGH	= 1,
+	SCK_MIN		= 1,	// usec (target clock >= 4 MHz)
+	SCK_MAX		= 250,	// usec (target clock >= 16 KHz)
+	SCK_DEFAULT	= 10,	// usec (target clock >= 0.4 MHz)
+	CHUNK_SIZE	= 128,	// must be power of 2 less than 256
+	USB_TIMEOUT	= 500,	// msec
+};
+
+typedef	unsigned char	byte_t;
+typedef	unsigned int	uint_t;
+typedef	unsigned long	ulong_t;
+
+extern	int		avr_write_byte_default ( PROGRAMMER* pgm, AVRPART* p,
+			                         AVRMEM* mem, ulong_t addr,
+						 byte_t data );
+extern	int		verbose;
+extern	char*		progname;
+
+static	usb_dev_handle*	usb_handle;
+static	int		sck_period;
+static	int		chunk_size;
+static	AVRMEM*		cache_mem;
+static	ulong_t		cache_base;
+static	byte_t		cache_buf[CHUNK_SIZE];
+static	int		cache_disable;
+
+// ----------------------------------------------------------------------
+
+static	void	usb_control ( int req, int val, int index )
+{
+	usb_control_msg( usb_handle,
+			 USB_ENDPOINT_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			 req, val, index, NULL, 0, USB_TIMEOUT );
+}
+
+static	int	usb_in ( int req, int val, int index, byte_t* buf, int buflen, int umax )
+{
+	int	n;
+	int	timeout;
+
+	timeout = USB_TIMEOUT + (buflen * umax) / 1000;
+	n = usb_control_msg( usb_handle,
+			USB_ENDPOINT_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			req, val, index, (char*) buf, buflen, timeout );
+	if	( n != buflen )
+	{
+		fprintf( stderr, "USB read error: expected %d, got %d\n", buflen, n );
+		return -1;
+	}
+	return 0;
+}
+
+static	int	usb_out ( int req, int val, int index, byte_t* buf, int buflen, int umax )
+{
+	int	n;
+	int	timeout;
+
+	timeout = USB_TIMEOUT + (buflen * umax) / 1000;
+	n = usb_control_msg( usb_handle,
+			USB_ENDPOINT_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			req, val, index, (char*) buf, buflen, timeout );
+	if	( n != buflen )
+	{
+		fprintf( stderr, "USB write error: expected %d, got %d\n", buflen, n );
+		return -1;
+	}
+	return 0;
+}
+
+static	int	usbtiny_avr_op ( PROGRAMMER* pgm, AVRPART* p, int op, byte_t res[4] )
+{
+	byte_t	cmd[4];
+
+	if	( ! p->op[op] )
+	{
+		fprintf( stderr, "Operation %d not defined\n", op );
+		return -1;
+	}
+	memset( cmd, 0, sizeof(cmd) );
+	avr_set_bits( p->op[op], cmd );
+	return pgm->cmd( pgm, cmd, res );
+}
+
+// ----------------------------------------------------------------------
+
+static	int	usbtiny_open ( PROGRAMMER* pgm, char* name )
+{
+	struct	usb_bus*	bus;
+	struct	usb_device*	dev = 0;
+
+	usb_init();
+	usb_find_busses();
+	usb_find_devices();
+	for	( bus = usb_busses; bus; bus = bus->next )
+	{
+		for	( dev = bus->devices; dev; dev = dev->next )
+		{
+			if	(  dev->descriptor.idVendor == USBDEV_VENDOR
+				&& dev->descriptor.idProduct == USBDEV_PRODUCT
+				)
+			{
+				usb_handle = usb_open( dev );
+				if	( ! usb_handle )
+				{
+					fprintf( stderr,
+						"Cannot open USB device: %s\n",
+						usb_strerror() );
+					return -1;
+				}
+				return 0;
+			}
+		}
+	}
+	fprintf( stderr, "Could not find USB device 0x%x/0x%x\n",
+		USBDEV_VENDOR, USBDEV_PRODUCT );
+	return -1;
+}
+
+static	void	usbtiny_close ( PROGRAMMER* pgm )
+{
+	if	( ! usb_handle )
+	{
+		return;
+	}
+	usb_close( usb_handle );
+	usb_handle = NULL;
+}
+
+static	void	usbtiny_set_chunk_size ( int period )
+{
+	chunk_size = CHUNK_SIZE;
+	while	( chunk_size > 8 && period > 16 )
+	{	// Reduce the chunk size for a slow SCK to reduce
+		// the maximum time of a single USB transfer.
+		chunk_size >>= 1;
+		period >>= 1;
+	}
+}
+
+static	int	usbtiny_set_sck_period ( PROGRAMMER* pgm, double v )
+{
+	sck_period = (int) (v * 1e6 + 0.5);
+	if	( sck_period < SCK_MIN )
+	{
+		sck_period = SCK_MIN;
+	}
+	if	( sck_period > SCK_MAX )
+	{
+		sck_period = SCK_MAX;
+	}
+	printf( "%s: Setting SCK period to %d usec\n", progname, sck_period );
+	usb_control( USBTINY_POWERUP, sck_period, RESET_LOW );
+	usbtiny_set_chunk_size( sck_period );
+	return 0;
+}
+
+static	int	usbtiny_initialize ( PROGRAMMER* pgm, AVRPART* p )
+{
+	byte_t	res[4];
+
+	if	( pgm->bitclock > 0.0 )
+	{	// -B option specified: convert to valid range for sck_period
+		usbtiny_set_sck_period( pgm, pgm->bitclock );
+	}
+	else
+	{	// -B option not specified: use default
+		sck_period = SCK_DEFAULT;
+		if	( verbose )
+		{
+			printf( "%s: Using SCK period of %d usec\n",
+				progname, sck_period );
+		}
+		usb_control( USBTINY_POWERUP, sck_period, RESET_LOW );
+		usbtiny_set_chunk_size( sck_period );
+	}
+	usleep( 50000 );
+	if	( ! usbtiny_avr_op( pgm, p, AVR_OP_PGM_ENABLE, res ) )
+	{	// no response, RESET and try again
+		usb_control( USBTINY_POWERUP, sck_period, RESET_HIGH );
+		usb_control( USBTINY_POWERUP, sck_period, RESET_LOW );
+		usleep( 20000 );
+		if	( ! usbtiny_avr_op( pgm, p, AVR_OP_PGM_ENABLE, res ) )
+		{	// give up
+			return -1;
+		}
+	}
+	return 0;
+}
+
+static	void	usbtiny_powerdown ( PROGRAMMER* pgm )
+{
+	if	( ! usb_handle )
+	{
+		return;
+	}
+	usb_control( USBTINY_POWERDOWN, 0, 0 );
+}
+
+static	int	usbtiny_cmd ( PROGRAMMER* pgm, byte_t cmd[4], byte_t res[4] )
+{
+	int	r;
+
+	cache_mem = NULL;
+	memset( res, '\0', sizeof(res) );
+	r = usb_in( USBTINY_SPI, (cmd[1] << 8) | cmd[0], (cmd[3] << 8) | cmd[2],
+	            (char*) res, sizeof(res), 8 * sck_period );
+	if	( verbose > 1 )
+	{
+		printf( "CMD: [%02x %02x %02x %02x] [%02x %02x %02x %02x]\n",
+		        cmd[0], cmd[1], cmd[2], cmd[3],
+			res[0], res[1], res[2], res[3] );
+	}
+	return (r == 0 && res[2] == cmd[1]);
+}
+
+static	int	usbtiny_chip_erase ( PROGRAMMER* pgm, AVRPART* p )
+{
+	byte_t	res[4];
+	int	r;
+
+	r = usbtiny_avr_op( pgm, p, AVR_OP_CHIP_ERASE, res );
+	usleep( p->chip_erase_delay );
+	usb_control( USBTINY_POWERUP, sck_period, RESET_HIGH );
+	pgm->initialize( pgm, p );
+	return r;
+}
+
+static	void	usbtiny_display ( PROGRAMMER* pgm, char* p )
+{
+}
+
+static	void	usbtiny_enable ( PROGRAMMER* pgm )
+{
+}
+
+static	void	usbtiny_disable ( PROGRAMMER* pgm )
+{
+}
+
+static	int	usbtiny_paged_load ( PROGRAMMER* pgm, AVRPART* p, AVRMEM* m,
+		                     int page_size, int n_bytes )
+{
+	int	i;
+	int	chunk;
+	int	req;
+
+	req = ( strcmp( m->desc, "flash" ) == 0
+	      ? USBTINY_FLASH_READ
+	      : USBTINY_EEPROM_READ
+	      );
+	for	( i = 0; i < n_bytes; i += chunk )
+	{
+		chunk = chunk_size;
+		if	( chunk > n_bytes - i )
+		{
+			chunk = n_bytes - i;
+		}
+		usb_in( req, 0, i, m->buf + i, chunk, 32 * sck_period );
+		report_progress( i + chunk, n_bytes, NULL );
+	}
+	return n_bytes;
+}
+
+static	int	usbtiny_paged_write ( PROGRAMMER* pgm, AVRPART* p, AVRMEM* m,
+		                      int page_size, int n_bytes )
+{
+	int	i;
+	int	chunk;
+	int	next;
+	int	req;
+	int	delay;
+
+	req = ( strcmp( m->desc, "flash" ) == 0
+	      ? USBTINY_FLASH_WRITE
+	      : USBTINY_EEPROM_WRITE
+	      );
+	delay = 0;
+	if	( ! m->paged )
+	{
+		i = (m->readback[1] << 8) | m->readback[0];
+		usb_control( USBTINY_POLL_BYTES, i, 0 );
+		delay = m->max_write_delay;
+	}
+	for	( i = 0; i < n_bytes; i = next )
+	{
+		chunk = chunk_size;
+		if	( m->paged && chunk > page_size )
+		{
+			chunk = page_size;
+		}
+		if	( chunk > n_bytes - i )
+		{
+			chunk = n_bytes - i;
+		}
+		usb_out( req, delay, i, m->buf + i, chunk, 32 * sck_period + delay );
+		next = i + chunk;
+		if	(  m->paged
+			&& ((next % page_size) == 0 || next == n_bytes)
+			)
+		{
+			avr_write_page( pgm, p, m, (unsigned long) i );
+		}
+		report_progress( next, n_bytes, NULL );
+	}
+	return n_bytes;
+}
+
+static	int	usbtiny_read_byte ( PROGRAMMER* pgm, AVRPART* p, AVRMEM* m,
+		                    ulong_t addr, byte_t* value )
+{
+	ulong_t	base;
+	int	req;
+	int	size;
+
+	if	( cache_disable > 0 )
+	{
+		return -1;	// fall back to avr_read_byte_default()
+	}
+	if	(  strcmp( m->desc, "flash" ) != 0
+		&& strcmp( m->desc, "eeprom" ) != 0
+		)
+	{
+		return -1;	// fall back to avr_read_byte_default()
+	}
+	base = addr & ~ (chunk_size - 1);
+	if	( cache_mem != m || cache_base != base )
+	{
+		req = ( strcmp( m->desc, "flash" ) == 0
+		      ? USBTINY_FLASH_READ
+		      : USBTINY_EEPROM_READ
+		      );
+		size = (m->size < chunk_size ? m->size : chunk_size);
+		if	( usb_in( req, 0, (int) base, cache_buf, size, 32 * sck_period ) != 0 )
+		{
+			cache_mem = NULL;
+			return -1;
+		}
+		cache_mem = m;
+		cache_base = base;
+	}
+	*value = cache_buf[addr - base];
+	return 0;
+}
+
+static	int	usbtiny_write_byte ( PROGRAMMER* pgm, AVRPART* p, AVRMEM* m,
+		                     ulong_t addr, byte_t value )
+{
+	int	r;
+
+	cache_disable++;
+	r = avr_write_byte_default( pgm, p, m, addr, value );
+	cache_disable--;
+	return r;
+}
+
+extern	void	usbtiny_initpgm ( PROGRAMMER* pgm )
+{
+	strcpy( pgm->type, "USBTINY" );
+	pgm->initialize		= usbtiny_initialize;
+	pgm->display		= usbtiny_display;
+	pgm->enable		= usbtiny_enable;
+	pgm->disable		= usbtiny_disable;
+	pgm->powerup		= NULL;
+	pgm->powerdown		= usbtiny_powerdown;
+	pgm->program_enable	= NULL;
+	pgm->chip_erase		= usbtiny_chip_erase;
+	pgm->cmd		= usbtiny_cmd;
+	pgm->open		= usbtiny_open;
+	pgm->close		= usbtiny_close;
+	pgm->paged_load		= usbtiny_paged_load;
+	pgm->paged_write	= usbtiny_paged_write;
+	pgm->read_byte		= usbtiny_read_byte;
+	pgm->write_byte		= usbtiny_write_byte;
+	pgm->set_sck_period	= usbtiny_set_sck_period;
+}
diff -pu /dev/null avrdude-5.1/usbtiny.h
--- /dev/null	2006-01-16 00:01:55.000000000 +0100
+++ avrdude-5.1/usbtiny.h	2006-02-11 22:09:53.000000000 +0100
@@ -0,0 +1 @@
+extern	void	usbtiny_initpgm ( PROGRAMMER* pgm );
