2  * Project: USBaspLoader 
   3  * Author: Christian Starkjohann 
   4  * Author: Stephan Baerwolf 
   5  * Creation Date: 2007-12-08 
   6  * Modification Date: 2012-11-10 
   8  * Copyright: (c) 2007 by OBJECTIVE DEVELOPMENT Software GmbH 
   9  * License: GNU GPL v2 (see License.txt) 
  10  * This Revision: $Id: main.c 786 2010-05-30 20:41:40Z cs $ 
  13 #include "spminterface.h"  /* must be included as first! */ 
  16 #include <avr/interrupt.h> 
  17 #include <avr/pgmspace.h> 
  20 #include <avr/eeprom.h> 
  21 #include <util/delay.h> 
  26  * 29.09.2012 /  30.09.2012 
  28  * Since cpufunc.h is not needed in this context and 
  29  * since it is not available in all toolchains, this include 
  30  * becomes deactivated by github issue-report. 
  31  * (In case of trouble it remains in sourcecode for reactivation.) 
  33  * The autor would like to thank Lena-M for reporting this 
  34  * issue (https://github.com/baerwolf/USBaspLoader/issues/1). 
  36 #include <avr/cpufunc.h> 
  45 #include "bootloaderconfig.h" 
  46 #include "usbdrv/usbdrv.c" 
  48 #ifndef BOOTLOADER_ADDRESS 
  49   #error need to know the bootloaders flash address! 
  51 #define BOOTLOADER_PAGEADDR     (BOOTLOADER_ADDRESS - (BOOTLOADER_ADDRESS % SPM_PAGESIZE)) 
  53 /* ------------------------------------------------------------------------ */ 
  55 /* Request constants used by USBasp */ 
  56 #define USBASP_FUNC_CONNECT         1 
  57 #define USBASP_FUNC_DISCONNECT      2 
  58 #define USBASP_FUNC_TRANSMIT        3 
  59 #define USBASP_FUNC_READFLASH       4 
  60 #define USBASP_FUNC_ENABLEPROG      5 
  61 #define USBASP_FUNC_WRITEFLASH      6 
  62 #define USBASP_FUNC_READEEPROM      7 
  63 #define USBASP_FUNC_WRITEEEPROM     8 
  64 #define USBASP_FUNC_SETLONGADDRESS  9 
  66 // additional USBasp Commands 
  67 #define USBASP_FUNC_SETISPSCK        10 
  68 #define USBASP_FUNC_TPI_CONNECT      11 
  69 #define USBASP_FUNC_TPI_DISCONNECT   12 
  70 #define USBASP_FUNC_TPI_RAWREAD      13 
  71 #define USBASP_FUNC_TPI_RAWWRITE     14 
  72 #define USBASP_FUNC_TPI_READBLOCK    15 
  73 #define USBASP_FUNC_TPI_WRITEBLOCK   16 
  74 #define USBASP_FUNC_GETCAPABILITIES 127 
  75 /* ------------------------------------------------------------------------ */ 
  78 #   define ulong    unsigned long 
  81 #   define uint     unsigned int 
  85 /* allow compatibility with avrusbboot's bootloaderconfig.h: */ 
  86 #ifdef BOOTLOADER_INIT 
  87 #   define bootLoaderInit()         BOOTLOADER_INIT 
  88 #   define bootLoaderExit() 
  90 #ifdef BOOTLOADER_CONDITION 
  91 #   define bootLoaderCondition()    BOOTLOADER_CONDITION 
  94 /* device compatibility: */ 
  95 #ifndef GICR    /* ATMega*8 don't have GICR, use MCUCR instead */ 
  99 /* ------------------------------------------------------------------------ */ 
 101 #if (FLASHEND) > 0xffff /* we need long addressing */ 
 102 #   define CURRENT_ADDRESS  currentAddress.l 
 103 #   define addr_t           ulong 
 105 #   define CURRENT_ADDRESS  currentAddress.w[0] 
 109 typedef union longConverter
{ 
 111     uint    w
[sizeof(addr_t
)/2]; 
 112     uchar   b
[sizeof(addr_t
)]; 
 116 #if BOOTLOADER_CAN_EXIT 
 117 static volatile unsigned char   stayinloader 
= 0xfe; 
 120 static longConverter_t          currentAddress
; /* in bytes */ 
 121 static uchar                    bytesRemaining
; 
 122 static uchar                    isLastPage
; 
 123 #if HAVE_EEPROM_PAGED_ACCESS 
 124 static uchar                    currentRequest
; 
 126 static const uchar              currentRequest 
= 0; 
 129 static const uchar  signatureBytes
[4] = { 
 130 #ifdef SIGNATURE_BYTES 
 132 #elif defined (__AVR_ATmega8__) || defined (__AVR_ATmega8A__) || defined (__AVR_ATmega8HVA__) 
 134 #elif defined (__AVR_ATmega32__) 
 136 #elif defined (__AVR_ATmega48__) || defined (__AVR_ATmega48A__) || defined (__AVR_ATmega48P__) 
 137     #error ATmega48 does not support bootloaders! 
 139 #elif defined (__AVR_ATmega48PA__) 
 140     #error ATmega48 does not support bootloaders! 
 142 #elif defined (__AVR_ATmega88__) || defined (__AVR_ATmega88A__) || defined (__AVR_ATmega88P__) 
 144 #elif defined (__AVR_ATmega88PA__) 
 146 #elif defined (__AVR_ATmega164A__) 
 148 #elif defined (__AVR_ATmega164P__) || defined (__AVR_ATmega164PA__) 
 150 #elif defined (__AVR_ATmega168__) || defined (__AVR_ATmega168A__) || defined (__AVR_ATmega168P__) 
 152 #elif defined (__AVR_ATmega168PA__) 
 154 #elif defined (__AVR_ATmega324A__) 
 156 #elif defined (__AVR_ATmega324P__) 
 158 #elif defined (__AVR_ATmega324PA__) 
 160 #elif defined (__AVR_ATmega328__) 
 162 #elif defined (__AVR_ATmega328P__) 
 164 #elif defined (__AVR_ATmega644__) || defined (__AVR_ATmega644A__) 
 166 #elif defined (__AVR_ATmega644P__) || defined (__AVR_ATmega644PA__) 
 168 #elif defined (__AVR_ATmega128__) 
 170 #elif defined (__AVR_ATmega1284__) 
 172 #elif defined (__AVR_ATmega1284P__) 
 175 #   error "Device signature is not known, please edit main.c!" 
 179 /* ------------------------------------------------------------------------ */ 
 181 #if (USE_BOOTUP_CLEARRAM) 
 183 * Under normal circumstances, RESET will not clear contents of RAM. 
 184 * As always, if you want it done - do it yourself... 
 186 void __attribute__ ((naked
)) __attribute__ ((section (".init3"))) __clearram(void); 
 187 void __clearram(void) { 
 188   extern size_t __bss_end
; 
 191     "ldi r29, %[ramendhi]\n\t" 
 192     "ldi r28, %[ramendlo]\n\t" 
 193     "__clearramloop%=:\n\t" 
 194     "st -Y , __zero_reg__\n\t" 
 195     "cp r28, %A[bssend]\n\t" 
 196     "cpc r29, %B[bssend]\n\t" 
 197     "brne __clearramloop%=\n\t" 
 199     : [ramendhi
] "M" (((RAMEND
+1)>>8) & 0xff), 
 200       [ramendlo
] "M" (((RAMEND
+1)>>0) & 0xff), 
 201       [bssend
] "r" (&__bss_end
) 
 207 #if (!USE_EXCESSIVE_ASSEMBLER) || (!(defined (__AVR_ATmega8__) || defined (__AVR_ATmega8A__) || defined (__AVR_ATmega8HVA__))) 
 208 static void (*nullVector
)(void) __attribute__((__noreturn__
)); 
 211 static void __attribute__((__noreturn__
)) leaveBootloader() 
 213 #if (USE_EXCESSIVE_ASSEMBLER) && (defined (__AVR_ATmega8__) || defined (__AVR_ATmega8A__) || defined (__AVR_ATmega8HVA__)) 
 217   "sbi          %[usbddr],      %[usbminus]\n\t"   
 218   "cbi          %[port],        %[bit]\n\t" 
 219   "out          %[usbintrenab], r30\n\t" 
 220   "out          %[usbintrcfg],  r30\n\t" 
 221   "ldi          r31,            %[ivce]\n\t" 
 222   "out          %[mygicr],      r31\n\t" 
 223   "out          %[mygicr],      r30\n\t"   
 227   : [port
]        "I" (_SFR_IO_ADDR(PIN_PORT(JUMPER_PORT
))), 
 228     [bit
]         "I" (PIN(JUMPER_PORT
, JUMPER_BIT
)), 
 229     [usbintrenab
] "I" (_SFR_IO_ADDR(USB_INTR_ENABLE
)), 
 230     [usbintrcfg
]  "I" (_SFR_IO_ADDR(USB_INTR_CFG
)), 
 231     [usbddr
]      "I" (_SFR_IO_ADDR(USBDDR
)), 
 232     [usbminus
]    "I" (USBMINUS
), 
 233     [mygicr
]      "I" (_SFR_IO_ADDR(GICR
)),            
 236 /* TODO: compiler will put an unnecessary "ret" at this end ! */ 
 240     usbDeviceDisconnect(); 
 243     USB_INTR_CFG 
= 0;       /* also reset config bits */ 
 244     GICR 
= (1 << IVCE
);     /* enable change of interrupt vectors */ 
 245     GICR 
= (0 << IVSEL
);    /* move interrupts to application flash section */ 
 247 /* We must go through a global function pointer variable instead of writing 
 248  *  ((void (*)(void))0)(); 
 249  * because the compiler optimizes a constant 0 to "rcall 0" which is not 
 250  * handled correctly by the assembler. 
 256 /* ------------------------------------------------------------------------ */ 
 259 uchar 
usbFunctionSetup_USBASP_FUNC_TRANSMIT(usbRequest_t 
*rq
) { 
 262   address
.bytes
[1] = rq
->wValue
.bytes
[1]; 
 263   address
.bytes
[0] = rq
->wIndex
.bytes
[0]; 
 265   if(rq
->wValue
.bytes
[0] == 0x30){        /* read signature */ 
 266     rval 
= rq
->wIndex
.bytes
[0] & 3; 
 267     rval 
= signatureBytes
[rval
]; 
 268 #if HAVE_READ_LOCK_FUSE 
 269 #if defined (__AVR_ATmega8__) || defined (__AVR_ATmega8A__) || defined (__AVR_ATmega32__) 
 270   }else if(rq
->wValue
.bytes
[0] == 0x58 && rq
->wValue
.bytes
[1] == 0x00){  /* read lock bits */ 
 271       rval 
= boot_lock_fuse_bits_get(GET_LOCK_BITS
); 
 272   }else if(rq
->wValue
.bytes
[0] == 0x50 && rq
->wValue
.bytes
[1] == 0x00){  /* read lfuse bits */ 
 273       rval 
= boot_lock_fuse_bits_get(GET_LOW_FUSE_BITS
); 
 274   }else if(rq
->wValue
.bytes
[0] == 0x58 && rq
->wValue
.bytes
[1] == 0x08){  /* read hfuse bits */ 
 275       rval 
= boot_lock_fuse_bits_get(GET_HIGH_FUSE_BITS
); 
 277 #elif defined (__AVR_ATmega48__)   || defined (__AVR_ATmega48A__)   || defined (__AVR_ATmega48P__)   || defined (__AVR_ATmega48PA__)  ||  \ 
 278 defined (__AVR_ATmega88__)   || defined (__AVR_ATmega88A__)   || defined (__AVR_ATmega88P__)   || defined (__AVR_ATmega88PA__)  ||  \ 
 279 defined (__AVR_ATmega164A__) || defined (__AVR_ATmega164P__)  ||                                                                      \ 
 280 defined (__AVR_ATmega168__)  || defined (__AVR_ATmega168A__)  || defined (__AVR_ATmega168P__)  || defined (__AVR_ATmega168PA__) ||  \ 
 281 defined (__AVR_ATmega324A__) || defined (__AVR_ATmega324P__)  ||                                                                      \ 
 282 defined (__AVR_ATmega328__)  || defined (__AVR_ATmega328P__)  ||                                                                      \ 
 283 defined (__AVR_ATmega644__)  || defined (__AVR_ATmega644A__)  || defined (__AVR_ATmega644P__) || defined (__AVR_ATmega644PA__)  ||  \ 
 284 defined (__AVR_ATmega128__)  ||                                                                                                       \ 
 285 defined (__AVR_ATmega1284__) || defined (__AVR_ATmega1284P__) 
 286   }else if(rq
->wValue
.bytes
[0] == 0x58 && rq
->wValue
.bytes
[1] == 0x00){  /* read lock bits */ 
 287       rval 
= boot_lock_fuse_bits_get(GET_LOCK_BITS
); 
 288   }else if(rq
->wValue
.bytes
[0] == 0x50 && rq
->wValue
.bytes
[1] == 0x00){  /* read lfuse bits */ 
 289       rval 
= boot_lock_fuse_bits_get(GET_LOW_FUSE_BITS
); 
 290   }else if(rq
->wValue
.bytes
[0] == 0x58 && rq
->wValue
.bytes
[1] == 0x08){  /* read hfuse bits */ 
 291       rval 
= boot_lock_fuse_bits_get(GET_HIGH_FUSE_BITS
); 
 292   }else if(rq
->wValue
.bytes
[0] == 0x50 && rq
->wValue
.bytes
[1] == 0x08){  /* read efuse bits */ 
 293       rval 
= boot_lock_fuse_bits_get(GET_EXTENDED_FUSE_BITS 
); 
 295   #warning "HAVE_READ_LOCK_FUSE is activated but MCU unknown -> will not support this feature" 
 298 #if HAVE_FLASH_BYTE_READACCESS 
 299   }else if(rq
->wValue
.bytes
[0] == 0x20){  /* read FLASH low  byte */ 
 300 #if ((FLASHEND) > 65535) 
 301       rval 
= pgm_read_byte_far((((addr_t
)address
.word
)<<1)+0); 
 303       rval 
= pgm_read_byte((((addr_t
)address
.word
)<<1)+0); 
 305   }else if(rq
->wValue
.bytes
[0] == 0x28){  /* read FLASH high byte */ 
 306 #if ((FLASHEND) > 65535) 
 307       rval 
= pgm_read_byte_far((((addr_t
)address
.word
)<<1)+1); 
 309       rval 
= pgm_read_byte((((addr_t
)address
.word
)<<1)+1); 
 312 #if HAVE_EEPROM_BYTE_ACCESS 
 313   }else if(rq
->wValue
.bytes
[0] == 0xa0){  /* read EEPROM byte */ 
 314       rval 
= eeprom_read_byte((void *)address
.word
); 
 315   }else if(rq
->wValue
.bytes
[0] == 0xc0){  /* write EEPROM byte */ 
 316       eeprom_write_byte((void *)address
.word
, rq
->wIndex
.bytes
[1]); 
 319   }else if(rq
->wValue
.bytes
[0] == 0xac && rq
->wValue
.bytes
[1] == 0x80){  /* chip erase */ 
 321 #if HAVE_BLB11_SOFTW_LOCKBIT 
 322       for(addr 
= 0; addr 
< (addr_t
)(BOOTLOADER_PAGEADDR
) ; addr 
+= SPM_PAGESIZE
) { 
 324       for(addr 
= 0; addr 
<= (addr_t
)(FLASHEND
) ; addr 
+= SPM_PAGESIZE
) { 
 326           /* wait and erase page */ 
 328 #   ifndef NO_FLASH_WRITE 
 329           boot_spm_busy_wait(); 
 331           boot_page_erase(addr
); 
 337       /* ignore all others, return default value == 0 */ 
 344 uchar   
usbFunctionSetup(uchar data
[8]) 
 346 usbRequest_t    
*rq 
= (void *)data
; 
 348 static uchar    replyBuffer
[4]; 
 350     usbMsgPtr 
= replyBuffer
; 
 351     if(rq
->bRequest 
== USBASP_FUNC_TRANSMIT
){   /* emulate parts of ISP protocol */ 
 352         replyBuffer
[3] = usbFunctionSetup_USBASP_FUNC_TRANSMIT(rq
); 
 354     }else if((rq
->bRequest 
== USBASP_FUNC_ENABLEPROG
) || (rq
->bRequest 
== USBASP_FUNC_SETISPSCK
)){ 
 355         /* replyBuffer[0] = 0; is never touched and thus always 0 which means success */ 
 357     }else if(rq
->bRequest 
>= USBASP_FUNC_READFLASH 
&& rq
->bRequest 
<= USBASP_FUNC_SETLONGADDRESS
){ 
 358         currentAddress
.w
[0] = rq
->wValue
.word
; 
 359         if(rq
->bRequest 
== USBASP_FUNC_SETLONGADDRESS
){ 
 360 #if (FLASHEND) > 0xffff 
 361             currentAddress
.w
[1] = rq
->wIndex
.word
; 
 364             bytesRemaining 
= rq
->wLength
.bytes
[0]; 
 365             /* if(rq->bRequest == USBASP_FUNC_WRITEFLASH) only evaluated during writeFlash anyway */ 
 366             isLastPage 
= rq
->wIndex
.bytes
[1] & 0x02; 
 367 #if HAVE_EEPROM_PAGED_ACCESS 
 368             currentRequest 
= rq
->bRequest
; 
 370             len 
= 0xff; /* hand over to usbFunctionRead() / usbFunctionWrite() */ 
 373     }else if(rq
->bRequest 
== USBASP_FUNC_DISCONNECT
){ 
 375 #if BOOTLOADER_CAN_EXIT 
 376       stayinloader         
&= (0xfe); 
 379         /* ignore: others, but could be USBASP_FUNC_CONNECT */ 
 380 #if BOOTLOADER_CAN_EXIT 
 381         stayinloader       
|= (0x01); 
 387 #if (USE_EXCESSIVE_ASSEMBLER) && ((!HAVE_CHIP_ERASE) || (HAVE_ONDEMAND_PAGEERASE)) && (SPM_PAGESIZE <= 256) && (((BOOTLOADER_PAGEADDR>>0)&0xff) == 0) 
 388 uchar 
usbFunctionWrite(uchar 
*data
, uchar len
) 
 392     DBG1(0x31, (void *)¤tAddress
.l
, 4); 
 393     if(len 
> bytesRemaining
) 
 394         len 
= bytesRemaining
; 
 395     bytesRemaining 
-= len
; 
 396     isLast 
= bytesRemaining 
== 0; 
 397     if(currentRequest 
>= USBASP_FUNC_READEEPROM
){ 
 399         for(i 
= 0; i 
< len
; i
++){ 
 400             eeprom_write_byte((void *)(currentAddress
.w
[0]++), *data
++); 
 406 "usbFunctionWrite_flashloop:\n\t" 
 408           "brlo         usbFunctionWrite_finished\n\t" 
 410 #if HAVE_BLB11_SOFTW_LOCKBIT 
 411           "cpi          r31, %[blsaddrhi]\n\t"                  /* accelerated BLB11_SOFTW_LOCKBIT check */ 
 412           "brsh         usbFunctionWrite_finished\n\t" 
 413 //        "brlo         usbFunctionWrite_addrunlock_ok\n\t" 
 414 //        "brne         usbFunctionWrite_finished\n\t" 
 415 //        "cpi          r30, %[blsaddrlo]\n\t" 
 416 //        "brlo         usbFunctionWrite_addrunlock_ok\n\t" 
 417 //        "rjmp         usbFunctionWrite_finished\n\t" 
 418 // "usbFunctionWrite_addrunlock_ok:\n\t" 
 420           "rcall        usbFunctionWrite_waitA\n\t" 
 421           "cli\n\t"                                             /* r0 or r1 may be __zero_reg__ and may become dangerous nonzero within interrupts */ 
 425           "ldi          r18,            %[pagfillval]\n\t" 
 426           "rcall        usbFunctionWrite_saveflash\n\t" /* page fill */ 
 429           "subi         r18,            0xfe\n\t"               /* add with 2 */ 
 430           "andi         r18,            %[pagemask]\n\t" 
 431           "breq         usbFunctionWrite_pageisfull\n\t" 
 433           "breq         usbFunctionWrite_skippageisfull\n\t" 
 434           "tst          %[isLastPage]\n\t" 
 435           "breq         usbFunctionWrite_skippageisfull\n\t" 
 437           "brne         usbFunctionWrite_skippageisfull\n\t" 
 439 "usbFunctionWrite_pageisfull:\n\t"                              /* start writing the page */ 
 440           "ldi          r18,            %[pageraseval]\n\t" 
 441           "rcall        usbFunctionWrite_saveflash\n\t" /* page erase */ 
 442           "rcall        usbFunctionWrite_waitA\n\t" 
 444           "ldi          r18,            %[pagwriteval]\n\t" 
 445           "rcall        usbFunctionWrite_saveflash\n\t" /* page write */ 
 446           "rcall        usbFunctionWrite_waitA\n\t" 
 448           "in           __tmp_reg__,    %[spmcr]\n\t" 
 449           "sbrs         __tmp_reg__,    %[rwwsbbit]\n\t" 
 450           "rjmp         usbFunctionWrite_skippageisfull\n\t" 
 451           "ldi          r18,            %[rwwenrval]\n\t" 
 452           "rcall        usbFunctionWrite_saveflash\n\t" /* reenable rww*/ 
 453 //        "rcall        usbFunctionWrite_waitA\n\t" 
 456 "usbFunctionWrite_skippageisfull:\n\t"     
 458           "rjmp         usbFunctionWrite_flashloop\n\t" 
 460 "usbFunctionWrite_saveflash:\n\t" 
 462           "out          %[spmcr],       r18\n\t" 
 464           "clr          __zero_reg__\n\t"                       /* if r0 or r1 is __zero_reg__ it may have become inconsisten while page-fill */ 
 468 "usbFunctionWrite_waitA:\n\t" 
 469           "in           __tmp_reg__,    %[spmcr]\n\t" 
 470           "sbrc         __tmp_reg__,    %[spmenbit]\n\t" 
 471           "rjmp         usbFunctionWrite_waitA\n\t" 
 474 "usbFunctionWrite_finished:\n\t" 
 475           : [addr
]         "+z" (currentAddress
.l
) 
 477           : [spmenbit
]    "I" (SPMEN
), 
 478             [rwwsbbit
]    "I" (RWWSB
), 
 479             [spmcr
]       "I" (_SFR_IO_ADDR(__SPM_REG
)), 
 480             [pagfillval
]  "M" ((1<<SPMEN
)), 
 481             [pageraseval
] "M" ((1<<PGERS
) | (1<<SPMEN
)), 
 482             [pagwriteval
] "M" ((1<<PGWRT
) | (1<<SPMEN
)), 
 483             [rwwenrval
]   "M" ((1<<RWWSRE
) | (1<<SPMEN
)), 
 484             [pagemask
]    "M" (SPM_PAGESIZE
-1), 
 485 #if HAVE_BLB11_SOFTW_LOCKBIT 
 486             [blsaddrhi
]    "M" ((uint8_t)((BOOTLOADER_PAGEADDR
>>8)&0xff)), 
 487 //          [blsaddrlo]    "M" ((uint8_t)((BOOTLOADER_PAGEADDR>>0)&0xff)), 
 489             [islast
]      "r"  (isLast
), 
 490             [isLastPage
]  "r"  (isLastPage
), 
 500 uchar 
usbFunctionWrite(uchar 
*data
, uchar len
) 
 504     DBG1(0x31, (void *)¤tAddress
.l
, 4); 
 505     if(len 
> bytesRemaining
) 
 506         len 
= bytesRemaining
; 
 507     bytesRemaining 
-= len
; 
 508     isLast 
= bytesRemaining 
== 0; 
 509     for(i 
= 0; i 
< len
;) { 
 510       if(currentRequest 
>= USBASP_FUNC_READEEPROM
){ 
 511         eeprom_write_byte((void *)(currentAddress
.w
[0]++), *data
++); 
 514 #if HAVE_BLB11_SOFTW_LOCKBIT 
 515         if (CURRENT_ADDRESS 
>= (addr_t
)(BOOTLOADER_PAGEADDR
)) { 
 522         boot_page_fill(CURRENT_ADDRESS
, *(short *)data
); 
 524         CURRENT_ADDRESS 
+= 2; 
 526         /* write page when we cross page boundary or we have the last partial page */ 
 527         if((currentAddress
.w
[0] & (SPM_PAGESIZE 
- 1)) == 0 || (isLast 
&& i 
>= len 
&& isLastPage
)){ 
 528 #if (!HAVE_CHIP_ERASE) || (HAVE_ONDEMAND_PAGEERASE) 
 530 #   ifndef NO_FLASH_WRITE 
 532             boot_page_erase(CURRENT_ADDRESS 
- 2);   /* erase page */ 
 534             boot_spm_busy_wait();                   /* wait until page is erased */ 
 538 #ifndef NO_FLASH_WRITE 
 540             boot_page_write(CURRENT_ADDRESS 
- 2); 
 542             boot_spm_busy_wait(); 
 549         DBG1(0x35, (void *)¤tAddress
.l
, 4); 
 555 uchar 
usbFunctionRead(uchar 
*data
, uchar len
) 
 559     if(len 
> bytesRemaining
) 
 560         len 
= bytesRemaining
; 
 561     bytesRemaining 
-= len
; 
 562     for(i 
= 0; i 
< len
; i
++){ 
 563         if(currentRequest 
>= USBASP_FUNC_READEEPROM
){ 
 564             *data 
= eeprom_read_byte((void *)currentAddress
.w
[0]); 
 566 #if ((FLASHEND) > 65535) 
 567             *data 
= pgm_read_byte_far(CURRENT_ADDRESS
); 
 569             *data 
= pgm_read_byte(CURRENT_ADDRESS
); 
 578 /* ------------------------------------------------------------------------ */ 
 580 static void initForUsbConnectivity(void) 
 582 #if HAVE_UNPRECISEWAIT 
 583     /* (0.25s*F_CPU)/(4 cycles per loop) ~ (65536*waitloopcnt) 
 584      * F_CPU/(16*65536) ~ waitloopcnt 
 585      * F_CPU / 1048576 ~ waitloopcnt 
 587     uint8_t waitloopcnt 
= 1 + (F_CPU
/1048576); 
 590     /* enforce USB re-enumerate: */ 
 591     usbDeviceDisconnect();  /* do this while interrupts are disabled */ 
 592 #if HAVE_UNPRECISEWAIT 
 594       /*we really don't care what value Z has... 
 595        * ...if we loop 65536/F_CPU more or less... 
 596        * ...unimportant - just save some opcodes 
 598 "initForUsbConnectivity_sleeploop:                      \n\t" 
 601       "brne     initForUsbConnectivity_sleeploop        \n\t" 
 607     _delay_ms(260);         /* fake USB disconnect for > 250 ms */ 
 613 int __attribute__((__noreturn__
)) main(void) 
 619 #ifndef NO_FLASH_WRITE 
 620     GICR 
= (1 << IVCE
);  /* enable change of interrupt vectors */ 
 621     GICR 
= (1 << IVSEL
); /* move interrupts to boot flash section */ 
 623     if(bootLoaderCondition()){ 
 625         wdt_disable();    /* main app may have enabled watchdog */ 
 627         initForUsbConnectivity(); 
 630 #if BOOTLOADER_CAN_EXIT 
 631 #if USE_EXCESSIVE_ASSEMBLER 
 633   "cpi          %[sil],         0x10\n\t" 
 634   "brlo         main_stayinloader_smaller\n\t" 
 635   "sbic         %[pin],         %[bit]\n\t" 
 636   "subi         %[sil],         0x10\n\t" 
 637   "rjmp         main_stayinloader_finished\n\t" 
 639   "main_stayinloader_smaller:\n\t" 
 640   "cpi          %[sil],         0x2\n\t" 
 641   "brlo         main_stayinloader_finished\n\t" 
 642   "sbis         %[pin],         %[bit]\n\t" 
 643   "subi         %[sil],         0x2\n\t" 
 645   "main_stayinloader_finished:\n\t" 
 646   : [sil
]        "+d" (stayinloader
) 
 647   : [pin
]         "I" (_SFR_IO_ADDR(PIN_PIN(JUMPER_PORT
))), 
 648     [bit
]         "I" (PIN(JUMPER_PORT
, JUMPER_BIT
)) 
 651         if (stayinloader 
>= 0x10) { 
 652           if (!bootLoaderCondition()) { 
 656           if (bootLoaderCondition()) { 
 657             if (stayinloader 
> 1) stayinloader
-=2; 
 663 #if BOOTLOADER_CAN_EXIT 
 664         }while (stayinloader
);  /* main event loop, if BOOTLOADER_CAN_EXIT*/ 
 666         }while (1);             /* main event loop */ 
 672 /* ------------------------------------------------------------------------ */