From a68a0d190fc3acdc85600d41ca94f133fcb5eb75 Mon Sep 17 00:00:00 2001
From: David Fries <David@Fries.net>
Date: Thu, 1 Jan 2015 19:06:55 -0600
Subject: [PATCH 1/4] fix NULL pointer crash entering direct spi mode

If setpin isn't defined entering direct spi mode will crash, check
before entering that mode.
---
 avrdude/term.c |    8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/avrdude/term.c b/avrdude/term.c
index 012f6f1..c8b1547 100644
--- a/avrdude/term.c
+++ b/avrdude/term.c
@@ -733,6 +733,11 @@ static int cmd_help(PROGRAMMER * pgm, struct avrpart * p,
 static int cmd_spi(PROGRAMMER * pgm, struct avrpart * p,
         int argc, char * argv[])
 {
+  if(!pgm->setpin) {
+    fprintf(stdout, "The %s programmer does not support direct SPI mode.\n",
+      pgm->type);
+    return -1;
+  }
   pgm->setpin(pgm, PIN_AVR_RESET, 1);
   spi_mode = 1;
   return 0;
@@ -741,6 +746,9 @@ static int cmd_spi(PROGRAMMER * pgm, struct avrpart * p,
 static int cmd_pgm(PROGRAMMER * pgm, struct avrpart * p,
         int argc, char * argv[])
 {
+  if(!pgm->setpin) {
+    return -1;
+  }
   pgm->setpin(pgm, PIN_AVR_RESET, 0);
   spi_mode = 0;
   pgm->initialize(pgm, p);
-- 
1.7.10.4


From 4815ad44ca2dec7275413cca02f759acbe0f120b Mon Sep 17 00:00:00 2001
From: David Fries <David@Fries.net>
Date: Thu, 1 Jan 2015 19:08:14 -0600
Subject: [PATCH 2/4] set back to pgm mode in quit

Otherwise it can't read the fuses and the safe fuse code complains.
---
 avrdude/term.c |    4 ++++
 1 file changed, 4 insertions(+)

diff --git a/avrdude/term.c b/avrdude/term.c
index c8b1547..2489ac3 100644
--- a/avrdude/term.c
+++ b/avrdude/term.c
@@ -543,6 +543,10 @@ static int cmd_sig(PROGRAMMER * pgm, struct avrpart * p,
 static int cmd_quit(PROGRAMMER * pgm, struct avrpart * p,
 		    int argc, char * argv[])
 {
+  /* FUSE bit verify will fail if left in SPI mode */
+  if(spi_mode == 1) {
+    cmd_pgm(pgm, p, 0, NULL);
+  }
   return 1;
 }
 
-- 
1.7.10.4


From c1aa8efd907d5e2d1930c278559129a3d2a5aed3 Mon Sep 17 00:00:00 2001
From: David Fries <David@Fries.net>
Date: Thu, 1 Jan 2015 19:16:47 -0600
Subject: [PATCH 3/4] add direct spi mode to USBtiny

It is limited to exactly sending (and receiving) 4 bytes, and unlike
programming mode where slave select isn't required, SS must be held
low for SPI to work.  The USBtiny programmer I have doesn't have a
wire for SS.
---
 avrdude/usbtiny.c |   36 ++++++++++++++++++++++++++++++++++++
 1 file changed, 36 insertions(+)

diff --git a/avrdude/usbtiny.c b/avrdude/usbtiny.c
index b6bc7cc..1e1ce33 100644
--- a/avrdude/usbtiny.c
+++ b/avrdude/usbtiny.c
@@ -370,6 +370,20 @@ static int usbtiny_initialize (PROGRAMMER *pgm, AVRPART *p )
   return 0;
 }
 
+static int usbtiny_setpin(struct programmer_t * pgm, int pinfunc, int value)
+{
+  /* USBtiny is not a bit bang device, but it can set RESET */
+  if(pinfunc == PIN_AVR_RESET) {
+    if (usb_control(pgm, USBTINY_POWERUP,
+                    PDATA(pgm)->sck_period, value ? RESET_HIGH : RESET_LOW) < 0) {
+      return -1;
+    }
+    usleep(50000);
+    return 0;
+  }
+  return -1;
+}
+
 /* Tell the USBtiny to release the output pins, etc */
 static void usbtiny_powerdown(PROGRAMMER * pgm)
 {
@@ -403,6 +417,26 @@ static int usbtiny_cmd(PROGRAMMER * pgm, const unsigned char *cmd, unsigned char
 	  res[2] == cmd[1]);              // AVR's do a delayed-echo thing
 }
 
+static int usbtiny_spi(struct programmer_t * pgm, const unsigned char *cmd, unsigned char *res, int count)
+{
+  int i;
+
+  // Make sure its empty so we don't read previous calls if it fails
+  memset(res, '\0', count);
+
+  if(count % 4) {
+    fprintf(stderr, "direct SPI write must be a multiple of 4 bytes for %s\n",
+      pgm->type);
+    return -1;
+  }
+  for(i=0; i<count; i+=4) {
+    if(usbtiny_cmd(pgm, cmd+i, res+i) < 0) {
+      return -1;
+    }
+  }
+  return 0;
+}
+
 /* Send the chip-erase command */
 static int usbtiny_chip_erase(PROGRAMMER * pgm, AVRPART * p)
 {
@@ -562,6 +596,8 @@ void usbtiny_initpgm ( PROGRAMMER* pgm )
   pgm->set_sck_period	= usbtiny_set_sck_period;
   pgm->setup            = usbtiny_setup;
   pgm->teardown         = usbtiny_teardown;
+  pgm->setpin		= usbtiny_setpin;
+  pgm->spi		= usbtiny_spi;
 }
 
 #else  /* !HAVE_LIBUSB */
-- 
1.7.10.4


From 39b557f2dffb62e235b5012575d1f9843aa9ca23 Mon Sep 17 00:00:00 2001
From: David Fries <David@Fries.net>
Date: Thu, 1 Jan 2015 19:58:23 -0600
Subject: [PATCH 4/4] man page updates for USBtiny and direct SPI

---
 avrdude/avrdude.1 |    5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/avrdude/avrdude.1 b/avrdude/avrdude.1
index a5e98ef..8028a41 100644
--- a/avrdude/avrdude.1
+++ b/avrdude/avrdude.1
@@ -739,7 +739,7 @@ Display the device signature bytes.
 Enter direct SPI mode.  The
 .Em pgmled
 pin acts as slave select.
-.Em Only supported on parallel bitbang programmers.
+.Em Only supported on parallel bitbang programmers, and partially by USBtiny.
 .It Ar part
 Display the current part settings and parameters.  Includes chip
 specific information including all memory types supported by the
@@ -1118,7 +1118,8 @@ This also applies to the STK500 and STK600 in parallel programming mode.
 .Pp
 The USBasp and USBtinyISP drivers do not offer any option to distinguish multiple
 devices connected simultaneously, so effectively only a single device
-is supported.
+is supported.  Slave Select must be externally held low for direct SPI when
+using USBtinyISP, and send must be a multiple of four bytes.
 .Pp
 The avrftdi driver allows one to select specific devices using any combination of vid,pid
 serial number (usbsn) vendor description (usbvendoror part description (usbproduct)
-- 
1.7.10.4

