X-Git-Url: http://git.linex4red.de/pub/USBasp.git/blobdiff_plain/82fa9149d705b70fc6d0e53e3d164fe138ce9a8b..0da99447d3e88e83f9977501bee56af5c7aa56c0:/Bootloaders/DFU/BootloaderDFU.c diff --git a/Bootloaders/DFU/BootloaderDFU.c b/Bootloaders/DFU/BootloaderDFU.c index f2247eb8b..fcacf76cb 100644 --- a/Bootloaders/DFU/BootloaderDFU.c +++ b/Bootloaders/DFU/BootloaderDFU.c @@ -1,13 +1,13 @@ /* LUFA Library - Copyright (C) Dean Camera, 2010. + Copyright (C) Dean Camera, 2012. dean [at] fourwalledcubicle [dot] com www.lufa-lib.org */ /* - Copyright 2010 Dean Camera (dean [at] fourwalledcubicle [dot] com) + Copyright 2012 Dean Camera (dean [at] fourwalledcubicle [dot] com) Permission to use, copy, modify, distribute, and sell this software and its documentation for any purpose is hereby granted @@ -38,60 +38,109 @@ /** Flag to indicate if the bootloader is currently running in secure mode, disallowing memory operations * other than erase. This is initially set to the value set by SECURE_MODE, and cleared by the bootloader - * once a memory erase has completed. + * once a memory erase has completed in a bootloader session. */ -bool IsSecure = SECURE_MODE; +static bool IsSecure = SECURE_MODE; /** Flag to indicate if the bootloader should be running, or should exit and allow the application code to run * via a soft reset. When cleared, the bootloader will abort, the USB interface will shut down and the application * jumped to via an indirect jump to location 0x0000 (or other location specified by the host). */ -bool RunBootloader = true; +static bool RunBootloader = true; /** Flag to indicate if the bootloader is waiting to exit. When the host requests the bootloader to exit and * jump to the application address it specifies, it sends two sequential commands which must be properly * acknowledged. Upon reception of the first the RunBootloader flag is cleared and the WaitForExit flag is set, * causing the bootloader to wait for the final exit command before shutting down. */ -bool WaitForExit = false; +static bool WaitForExit = false; /** Current DFU state machine state, one of the values in the DFU_State_t enum. */ -uint8_t DFU_State = dfuIDLE; +static uint8_t DFU_State = dfuIDLE; /** Status code of the last executed DFU command. This is set to one of the values in the DFU_Status_t enum after * each operation, and returned to the host when a Get Status DFU request is issued. */ -uint8_t DFU_Status = OK; +static uint8_t DFU_Status = OK; /** Data containing the DFU command sent from the host. */ -DFU_Command_t SentCommand; +static DFU_Command_t SentCommand; /** Response to the last issued Read Data DFU command. Unlike other DFU commands, the read command * requires a single byte response from the bootloader containing the read data when the next DFU_UPLOAD command * is issued by the host. */ -uint8_t ResponseByte; +static uint8_t ResponseByte; /** Pointer to the start of the user application. By default this is 0x0000 (the reset vector), however the host * may specify an alternate address when issuing the application soft-start command. */ -AppPtr_t AppStartPtr = (AppPtr_t)0x0000; +static AppPtr_t AppStartPtr = (AppPtr_t)0x0000; /** 64-bit flash page number. This is concatenated with the current 16-bit address on USB AVRs containing more than * 64KB of flash memory. */ -uint8_t Flash64KBPage = 0; +static uint8_t Flash64KBPage = 0; /** Memory start address, indicating the current address in the memory being addressed (either FLASH or EEPROM * depending on the issued command from the host). */ -uint16_t StartAddr = 0x0000; +static uint16_t StartAddr = 0x0000; -/** Memory end address, indicating the end address to read to/write from in the memory being addressed (either FLASH +/** Memory end address, indicating the end address to read from/write to in the memory being addressed (either FLASH * of EEPROM depending on the issued command from the host). */ -uint16_t EndAddr = 0x0000; +static uint16_t EndAddr = 0x0000; +/** Magic lock for forced application start. If the HWBE fuse is programmed and BOOTRST is unprogrammed, the bootloader + * will start if the /HWB line of the AVR is held low and the system is reset. However, if the /HWB line is still held + * low when the application attempts to start via a watchdog reset, the bootloader will re-start. If set to the value + * \ref MAGIC_BOOT_KEY the special init function \ref Application_Jump_Check() will force the application to start. + */ +uint16_t MagicBootKey ATTR_NO_INIT; + + +/** Special startup routine to check if the bootloader was started via a watchdog reset, and if the magic application + * start key has been loaded into \ref MagicBootKey. If the bootloader started via the watchdog and the key is valid, + * this will force the user application to start via a software jump. + */ +void Application_Jump_Check(void) +{ + bool JumpToApplication = false; + + #if ((BOARD == BOARD_XPLAIN) || (BOARD == BOARD_XPLAIN_REV1)) + /* Disable JTAG debugging */ + JTAG_DISABLE(); + + /* Enable pull-up on the JTAG TCK pin so we can use it to select the mode */ + PORTF |= (1 << 4); + Delay_MS(10); + + /* If the TCK pin is not jumpered to ground, start the user application instead */ + JumpToApplication |= ((PINF & (1 << 4)) != 0); + + /* Re-enable JTAG debugging */ + JTAG_ENABLE(); + #endif + + /* If the reset source was the bootloader and the key is correct, clear it and jump to the application */ + if ((MCUSR & (1 << WDRF)) && (MagicBootKey == MAGIC_BOOT_KEY)) + JumpToApplication |= true; + + /* If a request has been made to jump to the user application, honor it */ + if (JumpToApplication) + { + /* Turn off the watchdog */ + MCUSR &= ~(1< 0xFFFF) - Endpoint_Write_Word_LE(pgm_read_word_far(CurrFlashAddress.Long)); + Endpoint_Write_16_LE(pgm_read_word_far(CurrFlashAddress.Long)); #else - Endpoint_Write_Word_LE(pgm_read_word(CurrFlashAddress.Long)); + Endpoint_Write_16_LE(pgm_read_word(CurrFlashAddress.Long)); #endif /* Adjust counters */ @@ -417,7 +471,7 @@ void EVENT_USB_Device_ControlRequest(void) } /* Read the EEPROM byte and send it via USB to the host */ - Endpoint_Write_Byte(eeprom_read_byte((uint8_t*)StartAddr)); + Endpoint_Write_8(eeprom_read_byte((uint8_t*)StartAddr)); /* Adjust counters */ StartAddr++; @@ -432,27 +486,27 @@ void EVENT_USB_Device_ControlRequest(void) Endpoint_ClearStatusStage(); break; - case REQ_DFU_GETSTATUS: + case DFU_REQ_GETSTATUS: Endpoint_ClearSETUP(); /* Write 8-bit status value */ - Endpoint_Write_Byte(DFU_Status); + Endpoint_Write_8(DFU_Status); /* Write 24-bit poll timeout value */ - Endpoint_Write_Byte(0); - Endpoint_Write_Word_LE(0); + Endpoint_Write_8(0); + Endpoint_Write_16_LE(0); /* Write 8-bit state value */ - Endpoint_Write_Byte(DFU_State); + Endpoint_Write_8(DFU_State); /* Write 8-bit state string ID number */ - Endpoint_Write_Byte(0); + Endpoint_Write_8(0); Endpoint_ClearIN(); Endpoint_ClearStatusStage(); break; - case REQ_DFU_CLRSTATUS: + case DFU_REQ_CLRSTATUS: Endpoint_ClearSETUP(); /* Reset the status value variable to the default OK status */ @@ -460,17 +514,17 @@ void EVENT_USB_Device_ControlRequest(void) Endpoint_ClearStatusStage(); break; - case REQ_DFU_GETSTATE: + case DFU_REQ_GETSTATE: Endpoint_ClearSETUP(); /* Write the current device state to the endpoint */ - Endpoint_Write_Byte(DFU_State); + Endpoint_Write_8(DFU_State); Endpoint_ClearIN(); Endpoint_ClearStatusStage(); break; - case REQ_DFU_ABORT: + case DFU_REQ_ABORT: Endpoint_ClearSETUP(); /* Reset the current state variable to the default idle state */ @@ -503,7 +557,7 @@ static void DiscardFillerBytes(uint8_t NumberOfBytes) } else { - Endpoint_Discard_Byte(); + Endpoint_Discard_8(); } } } @@ -623,7 +677,7 @@ static void ProcessMemReadCommand(void) { uint32_t CurrFlashAddress = 0; - while (CurrFlashAddress < BOOT_START_ADDR) + while (CurrFlashAddress < (uint32_t)BOOT_START_ADDR) { /* Check if the current byte is not blank */ #if (FLASHEND > 0xFFFF) @@ -677,6 +731,9 @@ static void ProcessWriteCommand(void) { if (SentCommand.Data[1] == 0x00) // Start via watchdog { + /* Unlock the forced application start mode of the bootloader if it is restarted */ + MagicBootKey = MAGIC_BOOT_KEY; + /* Start the watchdog to reset the AVR once the communications are finalized */ wdt_enable(WDTO_250MS); } @@ -692,7 +749,7 @@ static void ProcessWriteCommand(void) uint32_t CurrFlashAddress = 0; /* Clear the application section of flash */ - while (CurrFlashAddress < BOOT_START_ADDR) + while (CurrFlashAddress < (uint32_t)BOOT_START_ADDR) { boot_page_erase(CurrFlashAddress); boot_spm_busy_wait();