diff -Nupr avrdude-5.4/Makefile.am avrdude-5.4-usbtiny/Makefile.am
--- avrdude-5.4/Makefile.am	2007-01-25 12:51:11.000000000 -0800
+++ avrdude-5.4-usbtiny/Makefile.am	2007-08-08 16:54:16.000000000 -0700
@@ -137,6 +137,8 @@ libavrdude_a_SOURCES = \
 	usbasp.h \
 	usbdevs.h \
 	usb_libusb.c \
+	usbtiny.h \
+	usbtiny.c \
 	update.h \
 	update.c
 
diff -Nupr avrdude-5.4/avrdude.conf.in avrdude-5.4-usbtiny/avrdude.conf.in
--- avrdude-5.4/avrdude.conf.in	2007-05-16 14:29:36.000000000 -0700
+++ avrdude-5.4-usbtiny/avrdude.conf.in	2007-08-08 16:49:33.000000000 -0700
@@ -378,6 +378,12 @@ programmer
 ;
 
 programmer
+  id    = "usbtiny";
+  desc  = "USBtiny simple USB programmer";
+  type  = usbtiny;
+;
+
+programmer
   id    = "butterfly";
   desc  = "Atmel Butterfly Development Board";
   type  = butterfly;
diff -Nupr avrdude-5.4/config_gram.y avrdude-5.4-usbtiny/config_gram.y
--- avrdude-5.4/config_gram.y	2007-02-02 13:48:19.000000000 -0800
+++ avrdude-5.4-usbtiny/config_gram.y	2007-08-08 16:49:33.000000000 -0700
@@ -42,6 +42,7 @@
 #include "avr910.h"
 #include "butterfly.h"
 #include "usbasp.h"
+#include "usbtiny.h"
 #include "avr.h"
 #include "jtagmkI.h"
 #include "jtagmkII.h"
@@ -136,6 +137,7 @@ static int parse_cmdbits(OPCODE * op);
 %token K_STK500GENERIC
 %token K_AVR910
 %token K_USBASP
+%token K_USBTINY
 %token K_BUTTERFLY
 %token K_TYPE
 %token K_VCC
@@ -421,6 +423,12 @@ prog_parm :
     }
   } |
 
+  K_TYPE TKN_EQUAL K_USBTINY {
+    {
+      usbtiny_initpgm(current_prog);
+    }
+  } |
+
   K_TYPE TKN_EQUAL K_BUTTERFLY {
     { 
       butterfly_initpgm(current_prog);
diff -Nupr avrdude-5.4/lexer.l avrdude-5.4-usbtiny/lexer.l
--- avrdude-5.4/lexer.l	2007-01-24 14:43:46.000000000 -0800
+++ avrdude-5.4-usbtiny/lexer.l	2007-08-08 16:49:33.000000000 -0700
@@ -120,6 +120,7 @@ allowfullpagebitstream { yylval=NULL; re
 avr910           { yylval=NULL; return K_AVR910; }
 avr910_devcode   { yylval=NULL; return K_AVR910_DEVCODE; }
 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; }
diff -Nupr avrdude-5.4/usbspi.c avrdude-5.4-usbtiny/usbspi.c
--- avrdude-5.4/usbspi.c	1969-12-31 16:00:00.000000000 -0800
+++ avrdude-5.4-usbtiny/usbspi.c	2007-08-08 16:49:33.000000000 -0700
@@ -0,0 +1,338 @@
+/*
+ * avrdude - A Downloader/Uploader for AVR device programmers
+ * Copyright (C) 2000-2006  Brian S. Dean <bsd@bsdhome.com>
+ *
+ * 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
+ */
+
+// This stuff is all adapted from par.c & usb_libusb.c cause its the only code i know well 
+// and usbasp is based on code that is oddly licensed. :(
+
+#include "ac_cfg.h"
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/time.h>
+
+#include "avr.h"
+#include "pgm.h"
+#include "bitbang.h"
+#include "usbspi.h"
+
+extern char *progname;
+
+#if defined(HAVE_LIBUSB)      // we use LIBUSB to talk to the board
+
+#define USB_TIMEOUT 500 // ms
+
+#include <usb.h>
+
+#include "serial.h"
+#include "usbdevs.h"
+
+extern int verbose;
+static usb_dev_handle *usbhandle = 0;
+//static char usbbuf[USBDEV_MAX_XFER];
+//static int buflen = -1, bufptr;
+//static int usb_interface;
+
+static	int usb_out ( int req, int val, int index, char* buf, int buflen, int umax )
+{
+  int	n;
+  int	timeout;
+  
+  timeout = USB_TIMEOUT + (buflen * umax) / 1000;
+  n = usb_control_msg( usbhandle,
+		       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 usb_in ( int req, int val, int index, char *buf, int buflen, int umax )
+{
+  int	n;
+  int	timeout;
+  
+  timeout = USB_TIMEOUT + (buflen * umax) / 1000;
+  n = usb_control_msg( usbhandle,
+		       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 n;
+}
+
+static int usbspi_setpin(PROGRAMMER * pgm, int pin, int value) {
+  char buffer[8];
+  int ret;
+
+
+  if (value) {
+    ret = usb_out(USBSPI_SETPIN, pin, 2, buffer, 0, 50);
+    if (ret < 0) {
+      fprintf(stderr, "Unable to send vendor request, ret = %d...\n", ret);
+      return -1;
+    }
+  } else {
+    ret = usb_out(USBSPI_CLRPIN, pin, 2, buffer, 0, 50);
+    if (ret < 0) {
+      fprintf(stderr, "Unable to send vendor request, ret = %d...\n", ret);
+      return -1;
+    }
+  }
+  if (pgm->ispdelay > 1)
+    bitbang_delay(pgm->ispdelay);
+  
+  return 0;
+}
+
+
+static int usbspi_getpin(PROGRAMMER * pgm, int pin)
+{
+  char buffer[1];
+  int ret;
+
+  ret = usb_in(USBSPI_GETPIN, pin, 0, buffer, 1, 200);
+  if (ret < 0) {
+    fprintf(stderr, "Unable to send vendor request, ret = %d...\n", ret);
+    return -1;
+  }
+
+  if (buffer[0] & (1 << pin))
+    return 1;
+  else
+    return 0;
+}
+
+
+static int usbspi_highpulsepin(PROGRAMMER * pgm, int pin) {
+  char buffer[8];
+  int ret;
+
+  if (usbhandle) {
+    ret = usb_out(USBSPI_SETPIN, 4 /* reset */, 2, buffer, 0, 50);
+    if (ret < 0) {
+      fprintf(stderr, "Unable to send vendor request, ret = %d...\n", ret);
+      return -1;
+    }
+    if (pgm->ispdelay > 1)
+      bitbang_delay(pgm->ispdelay);
+
+    ret = usb_out(USBSPI_CLRPIN, 4 /* reset */, 2, buffer, 0, 50);
+    if (ret < 0) {
+      fprintf(stderr, "Unable to send vendor request, ret = %d...\n", ret);
+      return -1;
+    }
+    if (pgm->ispdelay > 1)
+      bitbang_delay(pgm->ispdelay);
+  }
+
+  return 0;
+}
+
+static void usbspi_powerup(PROGRAMMER * pgm)
+{
+  int ret, sck_period=10;
+  char buffer[8];
+
+  if (usbhandle) {
+    ret = usb_out(USBSPI_POWERUP, sck_period, 2, buffer, 0, 50);
+    if (ret < 0) {
+      fprintf(stderr, "Unable to send vendor request, ret = %d...\n", ret);
+    }
+  }
+  usleep(100000);
+}
+
+/*
+ * transmit an AVR device command and return the results; 'cmd' and
+ * 'res' must point to at least a 4 byte data buffer
+ */
+int usbspi_cmd(PROGRAMMER * pgm, unsigned char cmd[4],
+                   unsigned char res[4])
+{
+  int i, ret;
+  unsigned char buffer[4];
+ 
+  /* 
+     //one byte at a time
+   for (i=0; i<4; i++) {
+    ret = usb_in(USBSPI_SPI, cmd[i], 0, res+i, 1, 200);
+    if (ret < 0) {
+      fprintf(stderr, "Unable to send vendor request, ret = %d...\n", ret);
+      return -1;
+    }
+
+    if (ret != 1) {
+      fprintf(stderr, "Bad response\n");
+      return -1;
+    }
+  }
+  */
+
+  ret = usb_out(USBSPI_WRITESPI4, 0, 0, cmd, 4, 200);
+  if (ret < 0) {
+    fprintf(stderr, "Unable to send vendor request, ret = %d...\n", ret);
+    return -1;
+  }
+  ret = usb_in(USBSPI_READSPI4, 0, 0, res, 4, 200);
+  if (ret < 0) {
+    fprintf(stderr, "Unable to send vendor request, ret = %d...\n", ret);
+    return -1;
+  }
+
+  if(verbose >= 2)
+    {
+      fprintf(stderr, "usbspi_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;
+}
+
+static void usbspi_disable(PROGRAMMER * pgm)
+{
+  /* Do nothing */
+
+  return;
+}
+
+static void usbspi_enable(PROGRAMMER * pgm)
+{
+  /* Do nothing */
+
+  return;
+}
+
+static int usbspi_open(PROGRAMMER * pgm, char * port)
+{
+  struct usb_bus *bus;
+  struct usb_device *dev;
+  int dev_found;
+
+  usb_init();
+
+  usb_find_busses();
+  usb_find_devices();
+  
+  usbhandle = NULL;
+  dev_found = FALSE;
+  for (bus = usb_get_busses(); bus && !dev_found; bus = bus->next) {
+    for (dev = bus->devices; dev && !dev_found; dev = dev->next) {
+      if ((dev->descriptor.idVendor == USBSPI_VID) && 
+	  (dev->descriptor.idProduct == USBSPI_PID)) {
+	dev_found = TRUE;
+	usbhandle = usb_open(dev);
+	fprintf(stderr, "Found USB-SPI device with matching VID/PID!\n");
+      }
+    }
+  }
+   
+  if (!dev_found) {
+      /* Couldn't find the VID/PID pair */
+      fprintf(stderr,
+	      "%s: error: could not find USB device "
+	      "\"USBSPI\" with vid=0x%x pid=0x%x\n",
+  	      progname, USBSPI_VID, USBSPI_PID);
+      exit(1);
+  }
+
+  return 0;
+}
+
+
+static void usbspi_close(PROGRAMMER * pgm)
+{
+  int ret;
+  char buffer[8];
+
+  if (usbhandle) {
+    ret = usb_out(USBSPI_POWERDOWN, 0, 2, buffer, 0, 50);
+    if (ret < 0) {
+      fprintf(stderr, "Unable to send vendor request, ret = %d...\n", ret);
+    }
+    
+    usb_close(usbhandle);
+  }
+}
+
+static void usbspi_display(PROGRAMMER * pgm, char * p)
+{
+  // get version?
+
+  fprintf(stderr, "USBSPI programmer - www.adafruit.com/make/usbspi\n");
+}
+
+void usbspi_initpgm(PROGRAMMER * pgm)
+{
+  strcpy(pgm->type, "USBSPI");
+
+  //pgm->rdy_led        = usbspi_rdy_led;
+  //pgm->err_led        = usbspi_err_led;
+  //pgm->pgm_led        = usbspi_pgm_led;
+  //pgm->vfy_led        = usbspi_vfy_led;
+  pgm->initialize     = bitbang_initialize;
+  pgm->display        = usbspi_display;
+  pgm->enable         = usbspi_enable;
+  pgm->disable        = usbspi_disable;
+  pgm->powerup        = usbspi_powerup;
+  //  pgm->powerdown      = usbspi_powerdown;
+  pgm->program_enable = bitbang_program_enable;
+  pgm->chip_erase     = bitbang_chip_erase;
+  pgm->cmd            = usbspi_cmd;
+  pgm->open           = usbspi_open;
+  pgm->close          = usbspi_close;
+  pgm->setpin         = usbspi_setpin;
+  pgm->getpin         = usbspi_getpin;
+  pgm->read_byte      = avr_read_byte_default;
+  pgm->write_byte     = avr_write_byte_default;
+  pgm->highpulsepin   = usbspi_highpulsepin;
+
+  pgm->pinno[PIN_AVR_SCK] = 7;
+  pgm->pinno[PIN_AVR_MOSI] = 6;
+  pgm->pinno[PIN_AVR_MISO] = 5;
+  pgm->pinno[PIN_AVR_RESET] = 4;
+  pgm->pinno[PIN_LED_PGM] = 0;
+}
+
+#else  /* !HAVE_LIBUSB */
+
+void usbspi_initpgm(PROGRAMMER * pgm)
+{
+  fprintf(stderr,
+	  "%s: libusb access not available in this configuration\n",
+	  progname);
+}
+
+#endif /* HAVE_LIBUSB */
diff -Nupr avrdude-5.4/usbspi.h avrdude-5.4-usbtiny/usbspi.h
--- avrdude-5.4/usbspi.h	1969-12-31 16:00:00.000000000 -0800
+++ avrdude-5.4-usbtiny/usbspi.h	2007-08-08 16:49:33.000000000 -0700
@@ -0,0 +1,36 @@
+/*
+ * avrdude - A Downloader/Uploader for AVR device programmers
+ * Copyright (C) 2006  Thomas Fischl
+ *
+ * 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
+ */
+
+
+#ifndef usbspi_h
+#define usbspi_h
+
+#include "avrpart.h"
+
+void usbspi_initpgm (PROGRAMMER * pgm);
+
+
+// these are specifically assigned to Adafruit Industries,
+// if you need your own VID and PIDs you can get them for cheap from
+// www.mecanique.co.uk so please don't reuse these. Thanks!
+
+#define USBSPI_VID 0x1781
+#define USBSPI_PID 0x0C9F
+
+#endif /* usbspi_h */
diff -Nupr avrdude-5.4/usbtiny.c avrdude-5.4-usbtiny/usbtiny.c
--- avrdude-5.4/usbtiny.c	1969-12-31 16:00:00.000000000 -0800
+++ avrdude-5.4-usbtiny/usbtiny.c	2007-08-08 16:49:33.000000000 -0700
@@ -0,0 +1,440 @@
+// ----------------------------------------------------------------------
+// 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 "ac_cfg.h"
+
+#include <string.h>
+#include "pgm.h"
+#include "avr.h"
+
+extern	char*		progname;
+
+#if defined(HAVE_LIBUSB)      // we use LIBUSB to talk to the board
+
+#include <usb.h>
+
+
+// these are specifically assigned to USBtiny courtesy of Adafruit Industries,
+// if you need your own VID and PIDs you can get them for cheap from
+// www.mecanique.co.uk so please don't reuse these. Thanks!
+
+#define USBDEV_VENDOR 0x1781
+#define USBDEV_PRODUCT 0x0C9F
+
+
+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;
+
+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 avr_read_byte_default(pgm, p, m, addr, value);
+				       // fall back to avr_read_byte_default()
+	}
+	if	(  strcmp( m->desc, "flash" ) != 0
+		&& strcmp( m->desc, "eeprom" ) != 0
+		)
+	{
+	  return avr_read_byte_default(pgm, p, m, addr, value);
+				       // 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;
+}
+
+#else  /* !HAVE_LIBUSB */
+
+void usbtiny_initpgm(PROGRAMMER * pgm)
+{
+  fprintf(stderr,
+	  "%s: libusb access not available in this configuration\n",
+	  progname);
+}
+
+#endif /* HAVE_LIBUSB */
diff -Nupr avrdude-5.4/usbtiny.h avrdude-5.4-usbtiny/usbtiny.h
--- avrdude-5.4/usbtiny.h	1969-12-31 16:00:00.000000000 -0800
+++ avrdude-5.4-usbtiny/usbtiny.h	2007-08-08 16:49:33.000000000 -0700
@@ -0,0 +1,28 @@
+/*
+ * avrdude - A Downloader/Uploader for AVR device programmers
+ * Copyright (C) 2006  Thomas Fischl
+ *
+ * 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
+ */
+
+
+#ifndef usbspi_h
+#define usbspi_h
+
+#include "avrpart.h"
+
+void usbtiny_initpgm (PROGRAMMER * pgm);
+
+#endif /* usbspi_h */
