Fixed possible lost data in the XPLAINBridge, USBtoSerial and Benito projects when...
[pub/USBasp.git] / Bootloaders / DFU / BootloaderDFU.c
index 6f8acc8..f2247eb 100644 (file)
@@ -1,21 +1,21 @@
 /*
              LUFA Library
      Copyright (C) Dean Camera, 2010.
-              
+
   dean [at] fourwalledcubicle [dot] com
-      www.fourwalledcubicle.com
+           www.lufa-lib.org
 */
 
 /*
   Copyright 2010  Dean Camera (dean [at] fourwalledcubicle [dot] com)
 
-  Permission to use, copy, modify, distribute, and sell this 
+  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 
+  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 
+  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
@@ -93,7 +93,7 @@ uint16_t StartAddr = 0x0000;
 uint16_t EndAddr = 0x0000;
 
 
-/** Main program entry point. This routine configures the hardware required by the bootloader, then continuously 
+/** 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.
  */
@@ -101,17 +101,34 @@ int main(void)
 {
        /* Configure hardware required by the bootloader */
        SetupHardware();
+
+       #if ((BOARD == BOARD_XPLAIN) || (BOARD == BOARD_XPLAIN_REV1))
+       /* Disable JTAG debugging */
+       MCUCR |= (1 << JTD);
+       MCUCR |= (1 << JTD);
+
+       /* 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 */
+       RunBootloader = (!(PINF & (1 << 4)));
        
+       /* Re-enable JTAG debugging */
+       MCUCR &= ~(1 << JTD);
+       MCUCR &= ~(1 << JTD);   
+       #endif
+
        /* Enable global interrupts so that the USB stack can function */
        sei();
 
        /* 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();
 }
@@ -125,7 +142,7 @@ void SetupHardware(void)
 
        /* Disable clock division */
        clock_prescale_set(clock_div_1);
-       
+
        /* Relocate the interrupt vector table to the bootloader section */
        MCUCR = (1 << IVCE);
        MCUCR = (1 << IVSEL);
@@ -139,51 +156,58 @@ 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;
 }
 
-/** 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 for the USB_ControlRequest event. This is used to catch and process control requests sent to
+ *  the device from the USB host before passing along unhandled control requests to the library for processing
+ *  internally.
  */
-void EVENT_USB_Device_UnhandledControlRequest(void)
+void EVENT_USB_Device_ControlRequest(void)
 {
        /* Get the size of the command and data from the wLength value */
        SentCommand.DataSize = USB_ControlRequest.wLength;
+       
+       /* Ignore any requests that aren't directed to the DFU interface */
+       if ((USB_ControlRequest.bmRequestType & (CONTROL_REQTYPE_TYPE | CONTROL_REQTYPE_RECIPIENT)) !=
+           (REQTYPE_CLASS | REQREC_INTERFACE))
+       {
+               return;
+       }
 
        switch (USB_ControlRequest.bRequest)
        {
                case REQ_DFU_DNLOAD:
                        Endpoint_ClearSETUP();
-                       
+
                        /* Check if bootloader is waiting to terminate */
                        if (WaitForExit)
                        {
                                /* Bootloader is terminating - process last received command */
                                ProcessBootloaderCommand();
-                               
+
                                /* Indicate that the last command has now been processed - free to exit bootloader */
                                WaitForExit = false;
                        }
-                         
+
                        /* If the request has a data stage, load it into the command struct */
                        if (SentCommand.DataSize)
                        {
                                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();
-                                       
+
                                /* One byte of the data stage is the command, so subtract it from the total data bytes */
                                SentCommand.DataSize--;
-                               
+
                                /* Load in the rest of the data stage as command parameters */
                                for (uint8_t DataByte = 0; (DataByte < sizeof(SentCommand.Data)) &&
                                     Endpoint_BytesInEndpoint(); DataByte++)
@@ -191,14 +215,14 @@ void EVENT_USB_Device_UnhandledControlRequest(void)
                                        SentCommand.Data[DataByte] = Endpoint_Read_Byte();
                                        SentCommand.DataSize--;
                                }
-                               
+
                                /* Process the command */
                                ProcessBootloaderCommand();
                        }
-                       
+
                        /* Check if currently downloading firmware */
                        if (DFU_State == dfuDNLOAD_IDLE)
-                       {                                                                       
+                       {
                                if (!(SentCommand.DataSize))
                                {
                                        DFU_State = dfuIDLE;
@@ -210,21 +234,21 @@ void EVENT_USB_Device_UnhandledControlRequest(void)
 
                                        /* 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);
-                                       
+
                                        if (IS_ONEBYTE_COMMAND(SentCommand.Data, 0x00))        // Write flash
                                        {
                                                /* Calculate the number of words to be written from the number of bytes to be written */
                                                uint16_t WordsRemaining = (BytesRemaining >> 1);
-                                       
+
                                                union
                                                {
                                                        uint16_t Words[2];
                                                        uint32_t Long;
                                                } CurrFlashAddress                 = {.Words = {StartAddr, Flash64KBPage}};
-                                               
+
                                                uint32_t CurrFlashPageStartAddress = CurrFlashAddress.Long;
                                                uint8_t  WordsInFlashPage          = 0;
 
@@ -236,7 +260,7 @@ void EVENT_USB_Device_UnhandledControlRequest(void)
                                                                Endpoint_ClearOUT();
 
                                                                while (!(Endpoint_IsOUTReceived()))
-                                                               {                               
+                                                               {
                                                                        if (USB_DeviceState == DEVICE_STATE_Unattached)
                                                                          return;
                                                                }
@@ -255,7 +279,7 @@ void EVENT_USB_Device_UnhandledControlRequest(void)
                                                                /* Commit the flash page to memory */
                                                                boot_page_write(CurrFlashPageStartAddress);
                                                                boot_spm_busy_wait();
-                                                               
+
                                                                /* Check if programming incomplete */
                                                                if (WordsRemaining)
                                                                {
@@ -268,10 +292,10 @@ void EVENT_USB_Device_UnhandledControlRequest(void)
                                                                }
                                                        }
                                                }
-                                       
+
                                                /* Once programming complete, start address equals the end address */
                                                StartAddr = EndAddr;
-                                       
+
                                                /* Re-enable the RWW section of flash */
                                                boot_rww_enable();
                                        }
@@ -285,7 +309,7 @@ void EVENT_USB_Device_UnhandledControlRequest(void)
                                                                Endpoint_ClearOUT();
 
                                                                while (!(Endpoint_IsOUTReceived()))
-                                                               {                               
+                                                               {
                                                                        if (USB_DeviceState == DEVICE_STATE_Unattached)
                                                                          return;
                                                                }
@@ -293,12 +317,12 @@ void EVENT_USB_Device_UnhandledControlRequest(void)
 
                                                        /* Read the byte from the USB interface and write to to the EEPROM */
                                                        eeprom_write_byte((uint8_t*)StartAddr, Endpoint_Read_Byte());
-                                                       
+
                                                        /* Adjust counters */
                                                        StartAddr++;
                                                }
                                        }
-                                       
+
                                        /* Throw away the currently unused DFU file suffix */
                                        DiscardFillerBytes(DFU_FILE_SUFFIX_SIZE);
                                }
@@ -313,11 +337,11 @@ void EVENT_USB_Device_UnhandledControlRequest(void)
                        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
@@ -356,7 +380,7 @@ void EVENT_USB_Device_UnhandledControlRequest(void)
                                                        Endpoint_ClearIN();
 
                                                        while (!(Endpoint_IsINReady()))
-                                                       {                               
+                                                       {
                                                                if (USB_DeviceState == DEVICE_STATE_Unattached)
                                                                  return;
                                                        }
@@ -366,13 +390,13 @@ void EVENT_USB_Device_UnhandledControlRequest(void)
                                                #if (FLASHEND > 0xFFFF)
                                                        Endpoint_Write_Word_LE(pgm_read_word_far(CurrFlashAddress.Long));
                                                #else
-                                                       Endpoint_Write_Word_LE(pgm_read_word(CurrFlashAddress.Long));                                                   
+                                                       Endpoint_Write_Word_LE(pgm_read_word(CurrFlashAddress.Long));
                                                #endif
 
                                                /* Adjust counters */
                                                CurrFlashAddress.Long += 2;
                                        }
-                                       
+
                                        /* Once reading is complete, start address equals the end address */
                                        StartAddr = EndAddr;
                                }
@@ -384,9 +408,9 @@ void EVENT_USB_Device_UnhandledControlRequest(void)
                                                if (Endpoint_BytesInEndpoint() == FIXED_CONTROL_ENDPOINT_SIZE)
                                                {
                                                        Endpoint_ClearIN();
-                                                       
+
                                                        while (!(Endpoint_IsINReady()))
-                                                       {                               
+                                                       {
                                                                if (USB_DeviceState == DEVICE_STATE_Unattached)
                                                                  return;
                                                        }
@@ -410,14 +434,14 @@ void EVENT_USB_Device_UnhandledControlRequest(void)
                        break;
                case REQ_DFU_GETSTATUS:
                        Endpoint_ClearSETUP();
-                       
+
                        /* Write 8-bit status value */
                        Endpoint_Write_Byte(DFU_Status);
-                       
+
                        /* Write 24-bit poll timeout value */
                        Endpoint_Write_Byte(0);
                        Endpoint_Write_Word_LE(0);
-                       
+
                        /* Write 8-bit state value */
                        Endpoint_Write_Byte(DFU_State);
 
@@ -425,12 +449,12 @@ void EVENT_USB_Device_UnhandledControlRequest(void)
                        Endpoint_Write_Byte(0);
 
                        Endpoint_ClearIN();
-                       
+
                        Endpoint_ClearStatusStage();
-                       break;          
+                       break;
                case REQ_DFU_CLRSTATUS:
                        Endpoint_ClearSETUP();
-                       
+
                        /* Reset the status value variable to the default OK status */
                        DFU_Status = OK;
 
@@ -438,17 +462,17 @@ void EVENT_USB_Device_UnhandledControlRequest(void)
                        break;
                case REQ_DFU_GETSTATE:
                        Endpoint_ClearSETUP();
-                       
+
                        /* Write the current device state to the endpoint */
                        Endpoint_Write_Byte(DFU_State);
-               
+
                        Endpoint_ClearIN();
-                       
+
                        Endpoint_ClearStatusStage();
                        break;
                case REQ_DFU_ABORT:
                        Endpoint_ClearSETUP();
-                       
+
                        /* Reset the current state variable to the default idle state */
                        DFU_State = dfuIDLE;
 
@@ -472,7 +496,7 @@ static void DiscardFillerBytes(uint8_t NumberOfBytes)
 
                        /* Wait until next data packet received */
                        while (!(Endpoint_IsOUTReceived()))
-                       {                               
+                       {
                                if (USB_DeviceState == DEVICE_STATE_Unattached)
                                  return;
                        }
@@ -501,10 +525,10 @@ static void ProcessBootloaderCommand(void)
                        /* Set the state and status variables to indicate the error */
                        DFU_State  = dfuERROR;
                        DFU_Status = errWRITE;
-                       
+
                        /* Stall command */
                        Endpoint_StallTransaction();
-                       
+
                        /* Don't process the command */
                        return;
                }
@@ -544,7 +568,7 @@ static void LoadStartEndAddresses(void)
                uint16_t Word;
        } 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;
@@ -560,7 +584,7 @@ static void ProcessMemProgCommand(void)
        {
                /* Load in the start and ending read addresses */
                LoadStartEndAddresses();
-               
+
                /* If FLASH is being written to, we need to pre-erase the first page to write to */
                if (IS_ONEBYTE_COMMAND(SentCommand.Data, 0x00))
                {
@@ -569,12 +593,12 @@ static void ProcessMemProgCommand(void)
                                uint16_t Words[2];
                                uint32_t Long;
                        } CurrFlashAddress = {.Words = {StartAddr, Flash64KBPage}};
-                       
+
                        /* Erase the current page's temp buffer */
                        boot_page_erase(CurrFlashAddress.Long);
                        boot_spm_busy_wait();
                }
-               
+
                /* Set the state so that the next DNLOAD requests reads in the firmware */
                DFU_State = dfuDNLOAD_IDLE;
        }
@@ -611,7 +635,7 @@ static void ProcessMemReadCommand(void)
                                /* Save the location of the first non-blank byte for response back to the host */
                                Flash64KBPage = (CurrFlashAddress >> 16);
                                StartAddr     = CurrFlashAddress;
-                       
+
                                /* Set state and status variables to the appropriate error values */
                                DFU_State  = dfuERROR;
                                DFU_Status = errCHECK_ERASED;
@@ -680,7 +704,7 @@ static void ProcessWriteCommand(void)
 
                /* Re-enable the RWW section of flash as writing to the flash locks it out */
                boot_rww_enable();
-                                       
+
                /* Memory has been erased, reset the security bit so that programming/reading is allowed */
                IsSecure = false;
        }
@@ -701,3 +725,4 @@ static void ProcessReadCommand(void)
        else if (IS_ONEBYTE_COMMAND(SentCommand.Data, 0x01))                    // Read signature byte
          ResponseByte = SignatureInfo[DataIndexToRead - 0x30];
 }
+