USBasp 2007.10.23.
[pub/USBasp.git] / firmware / main.c
index 9d79354..af740fc 100644 (file)
@@ -3,21 +3,16 @@
 
   Thomas Fischl <tfischl@gmx.de>
 
-  License:
-  The project is built with AVR USB driver by Objective Development, which is
-  published under an own licence based on the GNU General Public License (GPL).
-  USBasp is also distributed under this enhanced licence. See Documentation.
-
+  License........: GNU GPL v2 (see Readme.txt)
   Target.........: ATMega8 at 12 MHz
   Creation Date..: 2005-02-20
-  Last change....: 2005-04-20
+  Last change....: 2007-07-23
 
   PC2 SCK speed option. GND  -> slow (8khz SCK),
                         open -> fast (375kHz SCK)
 */
 
 #include <avr/io.h>
-#include <avr/signal.h>
 #include <avr/interrupt.h>
 #include <avr/pgmspace.h>
 #include <avr/wdt.h>
@@ -34,6 +29,7 @@
 #define USBASP_FUNC_WRITEFLASH  6
 #define USBASP_FUNC_READEEPROM  7
 #define USBASP_FUNC_WRITEEEPROM 8
+#define USBASP_FUNC_SETLONGADDRESS 9
 
 #define PROG_STATE_IDLE         0
 #define PROG_STATE_WRITEFLASH   1
@@ -53,9 +49,10 @@ static uchar replyBuffer[8];
 
 static uchar prog_state = PROG_STATE_IDLE;
 
-static unsigned int prog_address;
+static uchar prog_address_newmode = 0;
+static unsigned long prog_address;
 static unsigned int prog_nbytes = 0;
-static uchar prog_pagesize;
+static unsigned int prog_pagesize;
 static uchar prog_blockflags;
 static uchar prog_pagecounter;
 
@@ -73,8 +70,11 @@ uchar usbFunctionSetup(uchar data[8]) {
       ispSetSCKOption(ISP_SCK_FAST);
     }
 
-    ispConnect();
+    /* set compatibility mode of address delivering */
+    prog_address_newmode = 0;
+
     ledRedOn();
+    ispConnect();
 
   } else if (data[1] == USBASP_FUNC_DISCONNECT) {
     ispDisconnect();
@@ -88,13 +88,19 @@ uchar usbFunctionSetup(uchar data[8]) {
     len = 4;
 
   } else if (data[1] == USBASP_FUNC_READFLASH) {
-    prog_address = (data[3] << 8) | data[2];
+
+    if (!prog_address_newmode)
+      prog_address = (data[3] << 8) | data[2];
+
     prog_nbytes = (data[7] << 8) | data[6];
     prog_state = PROG_STATE_READFLASH;
     len = 0xff; /* multiple in */
 
   } else if (data[1] == USBASP_FUNC_READEEPROM) {
-    prog_address = (data[3] << 8) | data[2];
+
+    if (!prog_address_newmode)
+       prog_address = (data[3] << 8) | data[2];
+
     prog_nbytes = (data[7] << 8) | data[6];
     prog_state = PROG_STATE_READEEPROM;
     len = 0xff; /* multiple in */
@@ -104,9 +110,13 @@ uchar usbFunctionSetup(uchar data[8]) {
     len = 1;
 
   } else if (data[1] == USBASP_FUNC_WRITEFLASH) {
-    prog_address = (data[3] << 8) | data[2];
+
+    if (!prog_address_newmode)
+      prog_address = (data[3] << 8) | data[2];
+
     prog_pagesize = data[4];
-    prog_blockflags = data[5];
+    prog_blockflags = data[5] & 0x0F;
+    prog_pagesize += (((unsigned int)data[5] & 0xF0)<<4);
     if (prog_blockflags & PROG_BLOCKFLAG_FIRST) {
       prog_pagecounter = prog_pagesize;
     }
@@ -115,12 +125,22 @@ uchar usbFunctionSetup(uchar data[8]) {
     len = 0xff; /* multiple out */
 
   } else if (data[1] == USBASP_FUNC_WRITEEEPROM) {
-    prog_address = (data[3] << 8) | data[2];
+
+    if (!prog_address_newmode)
+      prog_address = (data[3] << 8) | data[2];
+
     prog_pagesize = 0;
     prog_blockflags = 0;
     prog_nbytes = (data[7] << 8) | data[6];
     prog_state = PROG_STATE_WRITEEEPROM;
     len = 0xff; /* multiple out */
+
+  } else if(data[1] == USBASP_FUNC_SETLONGADDRESS) {
+
+    /* set new mode of address delivering (ignore address delivered in commands) */
+    prog_address_newmode = 1;
+    /* set new address */
+    prog_address = *((unsigned long*)&data[2]);
   }
 
   usbMsgPtr = replyBuffer;
@@ -160,6 +180,7 @@ uchar usbFunctionRead(uchar *data, uchar len) {
 
 uchar usbFunctionWrite(uchar *data, uchar len) {
 
+  uchar retVal = 0;
   uchar i;
 
   /* check if programmer is in correct write state */
@@ -202,20 +223,31 @@ uchar usbFunctionWrite(uchar *data, uchar len) {
        /* last block and page flush pending, so flush it now */
        ispFlushPage(prog_address, data[i]);
       }
+
+         retVal = 1; // Need to return 1 when no more data is to be received
     }
 
     prog_address ++;
   }
 
-  return 0;
+  return retVal;
 }
 
 
 int main(void)
 {
+  uchar   i, j;
+
   PORTD = 0;
   PORTB = 0;           /* no pullups on USB and ISP pins */
   DDRD = ~(1 << 2);    /* all outputs except PD2 = INT0 */
+
+  DDRB = ~0;            /* output SE0 for USB reset */
+  j = 0;
+  while(--j){           /* USB Reset by device only required on Watchdog Reset */
+      i = 0;
+      while(--i);       /* delay >10ms for USB reset */
+  }
   DDRB = 0;             /* all USB and ISP pins inputs */
 
   DDRC = 0x03;          /* all inputs except PC0, PC1 */