X-Git-Url: http://git.linex4red.de/pub/USBasp.git/blobdiff_plain/c1a1b6eeecb375259968ef6d989833312047f2d8..d26a9ed5fd6fc60a0dfa61d04f5ae2bd7163a85d:/Bootloaders/DFU/BootloaderDFU.c diff --git a/Bootloaders/DFU/BootloaderDFU.c b/Bootloaders/DFU/BootloaderDFU.c index a997b207c..157b78ffb 100644 --- a/Bootloaders/DFU/BootloaderDFU.c +++ b/Bootloaders/DFU/BootloaderDFU.c @@ -1,21 +1,21 @@ /* LUFA Library - Copyright (C) Dean Camera, 2009. + Copyright (C) Dean Camera, 2010. dean [at] fourwalledcubicle [dot] com www.fourwalledcubicle.com */ /* - Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com) - - Permission to use, copy, modify, and distribute this software - and its documentation for any purpose and without fee is hereby - granted, provided that the above copyright notice appear in all - copies and that both that the copyright notice and this - permission notice and warranty disclaimer appear in supporting - documentation, and that the name of the author not be used in - advertising or publicity pertaining to distribution of the + Copyright 2010 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 + without fee, provided that the above copyright notice appear in + all copies and that both that the copyright notice and this + permission notice and warranty disclaimer appear in supporting + documentation, and that the name of the author not be used in + advertising or publicity pertaining to distribution of the software without specific, written prior permission. The author disclaim all warranties with regard to this @@ -32,13 +32,6 @@ * * Main source file for the DFU class bootloader. This file contains the complete bootloader logic. */ - -/** Configuration define. Define this token to true to case the bootloader to reject all memory commands - * until a memory erase has been performed. When used in conjunction with the lockbits of the AVR, this - * can protect the AVR's firmware from being dumped from a secured AVR. When false, memory operations are - * allowed at any time. - */ -#define SECURE_MODE false #define INCLUDE_FROM_BOOTLOADER_C #include "BootloaderDFU.h" @@ -57,7 +50,7 @@ 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 - * acknowedged. Upon reception of the first the RunBootloader flag is cleared and the WaitForExit flag is set, + * 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; @@ -99,18 +92,36 @@ uint16_t StartAddr = 0x0000; */ uint16_t EndAddr = 0x0000; + /** Main program entry point. This routine configures the hardware required by the bootloader, then continuously * runs the bootloader processing routine until instructed to soft-exit, or hard-reset via the watchdog to start * the loaded application code. */ -int main (void) +int main(void) +{ + /* Configure hardware required by the bootloader */ + SetupHardware(); + + /* Run the USB management task while the bootloader is supposed to be running */ + while (RunBootloader || WaitForExit) + USB_USBTask(); + + /* Reset configured hardware back to their original states for the user application */ + ResetHardware(); + + /* Start the user application */ + AppStartPtr(); +} + +/** Configures all hardware required for the bootloader. */ +void SetupHardware(void) { /* Disable watchdog if enabled by bootloader/fuses */ MCUSR &= ~(1 << WDRF); wdt_disable(); - /* Disable Clock Division */ - SetSystemClockPrescaler(0); + /* Disable clock division */ + clock_prescale_set(clock_div_1); /* Relocate the interrupt vector table to the bootloader section */ MCUCR = (1 << IVCE); @@ -118,59 +129,32 @@ int main (void) /* Initialize the USB subsystem */ USB_Init(); +} - /* Run the USB management task while the bootloader is supposed to be running */ - while (RunBootloader || WaitForExit) - USB_USBTask(); - +/** Resets all configured hardware required for the bootloader back to their original states. */ +void ResetHardware(void) +{ /* Shut down the USB subsystem */ USB_ShutDown(); /* Relocate the interrupt vector table back to the application section */ MCUCR = (1 << IVCE); MCUCR = 0; - - /* Reset any used hardware ports back to their defaults */ - PORTD = 0; - DDRD = 0; - - #if defined(PORTE) - PORTE = 0; - DDRE = 0; - #endif - - /* Start the user application */ - AppStartPtr(); } -/** Event handler for the USB_Disconnect event. This indicates that the bootloader should exit and the user - * application started. - */ -EVENT_HANDLER(USB_Disconnect) -{ - /* Upon disconnection, run user application */ - RunBootloader = false; -} - -/** Event handler for the USB_UnhandledControlPacket event. This is used to catch standard and class specific +/** Event handler for the USB_UnhandledControlRequest event. This is used to catch standard and class specific * control requests that are not handled internally by the USB library (including the DFU commands, which are * all issued via the control endpoint), so that they can be handled appropriately for the application. */ -EVENT_HANDLER(USB_UnhandledControlPacket) +void EVENT_USB_Device_UnhandledControlRequest(void) { - /* Discard unused wIndex value */ - Endpoint_Discard_Word(); - - /* Discard unused wValue value */ - Endpoint_Discard_Word(); - /* Get the size of the command and data from the wLength value */ - SentCommand.DataSize = Endpoint_Read_Word_LE(); + SentCommand.DataSize = USB_ControlRequest.wLength; - switch (bRequest) + switch (USB_ControlRequest.bRequest) { case DFU_DNLOAD: - Endpoint_ClearSetupReceived(); + Endpoint_ClearSETUP(); /* Check if bootloader is waiting to terminate */ if (WaitForExit) @@ -185,7 +169,11 @@ EVENT_HANDLER(USB_UnhandledControlPacket) /* If the request has a data stage, load it into the command struct */ if (SentCommand.DataSize) { - while (!(Endpoint_IsSetupOUTReceived())); + while (!(Endpoint_IsOUTReceived())) + { + if (USB_DeviceState == DEVICE_STATE_Unattached) + return; + } /* First byte of the data stage is the DNLOAD request's command */ SentCommand.Command = Endpoint_Read_Byte(); @@ -217,8 +205,8 @@ EVENT_HANDLER(USB_UnhandledControlPacket) /* Throw away the filler bytes before the start of the firmware */ DiscardFillerBytes(DFU_FILLER_BYTES_SIZE); - /* Throw away the page alignment filler bytes before the start of the firmware */ - DiscardFillerBytes(StartAddr % SPM_PAGESIZE); + /* Throw away the packet alignment filler bytes before the start of the firmware */ + DiscardFillerBytes(StartAddr % FIXED_CONTROL_ENDPOINT_SIZE); /* Calculate the number of bytes remaining to be written */ uint16_t BytesRemaining = ((EndAddr - StartAddr) + 1); @@ -232,7 +220,7 @@ EVENT_HANDLER(USB_UnhandledControlPacket) { uint16_t Words[2]; uint32_t Long; - } CurrFlashAddress = {Words: {StartAddr, Flash64KBPage}}; + } CurrFlashAddress = {.Words = {StartAddr, Flash64KBPage}}; uint32_t CurrFlashPageStartAddress = CurrFlashAddress.Long; uint8_t WordsInFlashPage = 0; @@ -242,8 +230,13 @@ EVENT_HANDLER(USB_UnhandledControlPacket) /* Check if endpoint is empty - if so clear it and wait until ready for next packet */ if (!(Endpoint_BytesInEndpoint())) { - Endpoint_ClearSetupOUT(); - while (!(Endpoint_IsSetupOUTReceived())); + Endpoint_ClearOUT(); + + while (!(Endpoint_IsOUTReceived())) + { + if (USB_DeviceState == DEVICE_STATE_Unattached) + return; + } } /* Write the next word into the current flash page */ @@ -286,8 +279,13 @@ EVENT_HANDLER(USB_UnhandledControlPacket) /* Check if endpoint is empty - if so clear it and wait until ready for next packet */ if (!(Endpoint_BytesInEndpoint())) { - Endpoint_ClearSetupOUT(); - while (!(Endpoint_IsSetupOUTReceived())); + Endpoint_ClearOUT(); + + while (!(Endpoint_IsOUTReceived())) + { + if (USB_DeviceState == DEVICE_STATE_Unattached) + return; + } } /* Read the byte from the USB interface and write to to the EEPROM */ @@ -303,17 +301,20 @@ EVENT_HANDLER(USB_UnhandledControlPacket) } } - Endpoint_ClearSetupOUT(); + Endpoint_ClearOUT(); + + Endpoint_ClearStatusStage(); - /* Send ZLP to the host to acknowedge the request */ - Endpoint_ClearSetupIN(); - break; case DFU_UPLOAD: - Endpoint_ClearSetupReceived(); - - while (!(Endpoint_IsSetupINReady())); + Endpoint_ClearSETUP(); + while (!(Endpoint_IsINReady())) + { + if (USB_DeviceState == DEVICE_STATE_Unattached) + return; + } + if (DFU_State != dfuUPLOAD_IDLE) { if ((DFU_State == dfuERROR) && IS_ONEBYTE_COMMAND(SentCommand.Data, 0x01)) // Blank Check @@ -342,19 +343,24 @@ EVENT_HANDLER(USB_UnhandledControlPacket) { uint16_t Words[2]; uint32_t Long; - } CurrFlashAddress = {Words: {StartAddr, Flash64KBPage}}; + } CurrFlashAddress = {.Words = {StartAddr, Flash64KBPage}}; while (WordsRemaining--) { /* Check if endpoint is full - if so clear it and wait until ready for next packet */ if (Endpoint_BytesInEndpoint() == FIXED_CONTROL_ENDPOINT_SIZE) { - Endpoint_ClearSetupIN(); - while (!(Endpoint_IsSetupINReady())); + Endpoint_ClearIN(); + + while (!(Endpoint_IsINReady())) + { + if (USB_DeviceState == DEVICE_STATE_Unattached) + return; + } } /* Read the flash word and send it via USB to the host */ - #if defined(RAMPZ) + #if (FLASHEND > 0xFFFF) Endpoint_Write_Word_LE(pgm_read_word_far(CurrFlashAddress.Long)); #else Endpoint_Write_Word_LE(pgm_read_word(CurrFlashAddress.Long)); @@ -374,8 +380,13 @@ EVENT_HANDLER(USB_UnhandledControlPacket) /* Check if endpoint is full - if so clear it and wait until ready for next packet */ if (Endpoint_BytesInEndpoint() == FIXED_CONTROL_ENDPOINT_SIZE) { - Endpoint_ClearSetupIN(); - while (!(Endpoint_IsSetupINReady())); + Endpoint_ClearIN(); + + while (!(Endpoint_IsINReady())) + { + if (USB_DeviceState == DEVICE_STATE_Unattached) + return; + } } /* Read the EEPROM byte and send it via USB to the host */ @@ -390,15 +401,12 @@ EVENT_HANDLER(USB_UnhandledControlPacket) DFU_State = dfuIDLE; } - Endpoint_ClearSetupIN(); - - /* Send ZLP to the host to acknowedge the request */ - while (!(Endpoint_IsSetupOUTReceived())); - Endpoint_ClearSetupOUT(); + Endpoint_ClearIN(); + Endpoint_ClearStatusStage(); break; case DFU_GETSTATUS: - Endpoint_ClearSetupReceived(); + Endpoint_ClearSETUP(); /* Write 8-bit status value */ Endpoint_Write_Byte(DFU_Status); @@ -413,41 +421,35 @@ EVENT_HANDLER(USB_UnhandledControlPacket) /* Write 8-bit state string ID number */ Endpoint_Write_Byte(0); - Endpoint_ClearSetupIN(); + Endpoint_ClearIN(); - while (!(Endpoint_IsSetupOUTReceived())); - Endpoint_ClearSetupOUT(); - + Endpoint_ClearStatusStage(); break; case DFU_CLRSTATUS: - Endpoint_ClearSetupReceived(); + Endpoint_ClearSETUP(); /* Reset the status value variable to the default OK status */ DFU_Status = OK; - - Endpoint_ClearSetupIN(); + Endpoint_ClearStatusStage(); break; case DFU_GETSTATE: - Endpoint_ClearSetupReceived(); + Endpoint_ClearSETUP(); /* Write the current device state to the endpoint */ Endpoint_Write_Byte(DFU_State); - Endpoint_ClearSetupIN(); + Endpoint_ClearIN(); - while (!(Endpoint_IsSetupOUTReceived())); - Endpoint_ClearSetupOUT(); - + Endpoint_ClearStatusStage(); break; case DFU_ABORT: - Endpoint_ClearSetupReceived(); + Endpoint_ClearSETUP(); /* Reset the current state variable to the default idle state */ DFU_State = dfuIDLE; - - Endpoint_ClearSetupIN(); + Endpoint_ClearStatusStage(); break; } } @@ -455,7 +457,7 @@ EVENT_HANDLER(USB_UnhandledControlPacket) /** Routine to discard the specified number of bytes from the control endpoint stream. This is used to * discard unused bytes in the stream from the host, including the memory program block suffix. * - * \param NumberOfBytes Number of bytes to discard from the host from the control endpoint + * \param[in] NumberOfBytes Number of bytes to discard from the host from the control endpoint */ static void DiscardFillerBytes(uint8_t NumberOfBytes) { @@ -463,13 +465,19 @@ static void DiscardFillerBytes(uint8_t NumberOfBytes) { if (!(Endpoint_BytesInEndpoint())) { - Endpoint_ClearSetupOUT(); + Endpoint_ClearOUT(); /* Wait until next data packet received */ - while (!(Endpoint_IsSetupOUTReceived())); + while (!(Endpoint_IsOUTReceived())) + { + if (USB_DeviceState == DEVICE_STATE_Unattached) + return; + } + } + else + { + Endpoint_Discard_Byte(); } - - Endpoint_Discard_Byte(); } } @@ -531,15 +539,15 @@ static void LoadStartEndAddresses(void) { uint8_t Bytes[2]; uint16_t Word; - } Address[2] = {{Bytes: {SentCommand.Data[2], SentCommand.Data[1]}}, - {Bytes: {SentCommand.Data[4], SentCommand.Data[3]}}}; + } Address[2] = {{.Bytes = {SentCommand.Data[2], SentCommand.Data[1]}}, + {.Bytes = {SentCommand.Data[4], SentCommand.Data[3]}}}; /* Load in the start and ending read addresses from the sent data packet */ StartAddr = Address[0].Word; EndAddr = Address[1].Word; } -/** Handler for a Memory Program command issued by the host. This routine handles the preperations needed +/** Handler for a Memory Program command issued by the host. This routine handles the preparations needed * to write subsequent data from the host into the specified memory. */ static void ProcessMemProgCommand(void) @@ -557,7 +565,7 @@ static void ProcessMemProgCommand(void) { uint16_t Words[2]; uint32_t Long; - } CurrFlashAddress = {Words: {StartAddr, Flash64KBPage}}; + } CurrFlashAddress = {.Words = {StartAddr, Flash64KBPage}}; /* Erase the current page's temp buffer */ boot_page_erase(CurrFlashAddress.Long); @@ -569,7 +577,7 @@ static void ProcessMemProgCommand(void) } } -/** Handler for a Memory Read command issued by the host. This routine handles the preperations needed +/** Handler for a Memory Read command issued by the host. This routine handles the preparations needed * to read subsequent data from the specified memory out to the host, as well as implementing the memory * blank check command. */ @@ -591,7 +599,7 @@ static void ProcessMemReadCommand(void) while (CurrFlashAddress < BOOT_START_ADDR) { /* Check if the current byte is not blank */ - #if defined(RAMPZ) + #if (FLASHEND > 0xFFFF) if (pgm_read_byte_far(CurrFlashAddress) != 0xFF) #else if (pgm_read_byte(CurrFlashAddress) != 0xFF) @@ -639,7 +647,7 @@ static void ProcessWriteCommand(void) { uint8_t Bytes[2]; AppPtr_t FuncPtr; - } Address = {Bytes: {SentCommand.Data[4], SentCommand.Data[3]}}; + } Address = {.Bytes = {SentCommand.Data[4], SentCommand.Data[3]}}; AppStartPtr = Address.FuncPtr; @@ -677,16 +685,12 @@ static void ProcessWriteCommand(void) static void ProcessReadCommand(void) { const uint8_t BootloaderInfo[3] = {BOOTLOADER_VERSION, BOOTLOADER_ID_BYTE1, BOOTLOADER_ID_BYTE2}; - const uint8_t SignatureInfo[3] = {SIGNATURE_BYTE_1, SIGNATURE_BYTE_2, SIGNATURE_BYTE_3}; + const uint8_t SignatureInfo[3] = {AVR_SIGNATURE_1, AVR_SIGNATURE_2, AVR_SIGNATURE_3}; uint8_t DataIndexToRead = SentCommand.Data[1]; if (IS_ONEBYTE_COMMAND(SentCommand.Data, 0x00)) // Read bootloader info - { - ResponseByte = BootloaderInfo[DataIndexToRead]; - } + ResponseByte = BootloaderInfo[DataIndexToRead]; else if (IS_ONEBYTE_COMMAND(SentCommand.Data, 0x01)) // Read signature byte - { - ResponseByte = SignatureInfo[DataIndexToRead - 0x30]; - } + ResponseByte = SignatureInfo[DataIndexToRead - 0x30]; }