Be doubly-certain that the incomming CDC class driver's endpoint/pipe is flushed...
[pub/USBasp.git] / Bootloaders / DFU / BootloaderDFU.c
index 289b4eb..157b78f 100644 (file)
@@ -1,21 +1,21 @@
 /*\r
              LUFA Library\r
-     Copyright (C) Dean Camera, 2009.\r
+     Copyright (C) Dean Camera, 2010.\r
               \r
   dean [at] fourwalledcubicle [dot] com\r
       www.fourwalledcubicle.com\r
 */\r
 \r
 /*\r
-  Copyright 2009  Dean Camera (dean [at] fourwalledcubicle [dot] com)\r
-\r
-  Permission to use, copy, modify, and distribute this software\r
-  and its documentation for any purpose and without fee is hereby\r
-  granted, provided that the above copyright notice appear in all\r
-  copies and that both that the copyright notice and this\r
-  permission notice and warranty disclaimer appear in supporting\r
-  documentation, and that the name of the author not be used in\r
-  advertising or publicity pertaining to distribution of the\r
+  Copyright 2010  Dean Camera (dean [at] fourwalledcubicle [dot] com)\r
+\r
+  Permission to use, copy, modify, distribute, and sell this \r
+  software and its documentation for any purpose is hereby granted\r
+  without fee, provided that the above copyright notice appear in \r
+  all copies and that both that the copyright notice and this\r
+  permission notice and warranty disclaimer appear in supporting \r
+  documentation, and that the name of the author not be used in \r
+  advertising or publicity pertaining to distribution of the \r
   software without specific, written prior permission.\r
 \r
   The author disclaim all warranties with regard to this\r
@@ -92,11 +92,29 @@ uint16_t StartAddr = 0x0000;
  */\r
 uint16_t EndAddr = 0x0000;\r
 \r
+\r
 /** Main program entry point. This routine configures the hardware required by the bootloader, then continuously \r
  *  runs the bootloader processing routine until instructed to soft-exit, or hard-reset via the watchdog to start\r
  *  the loaded application code.\r
  */\r
-int main (void)\r
+int main(void)\r
+{\r
+       /* Configure hardware required by the bootloader */\r
+       SetupHardware();\r
+\r
+       /* Run the USB management task while the bootloader is supposed to be running */\r
+       while (RunBootloader || WaitForExit)\r
+         USB_USBTask();\r
+       \r
+       /* Reset configured hardware back to their original states for the user application */\r
+       ResetHardware();\r
+       \r
+       /* Start the user application */\r
+       AppStartPtr();\r
+}\r
+\r
+/** Configures all hardware required for the bootloader. */\r
+void SetupHardware(void)\r
 {\r
        /* Disable watchdog if enabled by bootloader/fuses */\r
        MCUSR &= ~(1 << WDRF);\r
@@ -111,56 +129,29 @@ int main (void)
 \r
        /* Initialize the USB subsystem */\r
        USB_Init();\r
+}\r
 \r
-       /* Run the USB management task while the bootloader is supposed to be running */\r
-       while (RunBootloader || WaitForExit)\r
-         USB_USBTask();\r
-       \r
+/** Resets all configured hardware required for the bootloader back to their original states. */\r
+void ResetHardware(void)\r
+{\r
        /* Shut down the USB subsystem */\r
        USB_ShutDown();\r
        \r
        /* Relocate the interrupt vector table back to the application section */\r
        MCUCR = (1 << IVCE);\r
        MCUCR = 0;\r
-\r
-       /* Reset any used hardware ports back to their defaults */\r
-       PORTD = 0;\r
-       DDRD  = 0;\r
-       \r
-       #if defined(PORTE)\r
-       PORTE = 0;\r
-       DDRE  = 0;\r
-       #endif\r
-       \r
-       /* Start the user application */\r
-       AppStartPtr();\r
 }\r
 \r
-/** Event handler for the USB_Disconnect event. This indicates that the bootloader should exit and the user\r
- *  application started.\r
- */\r
-EVENT_HANDLER(USB_Disconnect)\r
-{\r
-       /* Upon disconnection, run user application */\r
-       RunBootloader = false;\r
-}\r
-\r
-/** Event handler for the USB_UnhandledControlPacket event. This is used to catch standard and class specific\r
+/** Event handler for the USB_UnhandledControlRequest event. This is used to catch standard and class specific\r
  *  control requests that are not handled internally by the USB library (including the DFU commands, which are\r
  *  all issued via the control endpoint), so that they can be handled appropriately for the application.\r
  */\r
-EVENT_HANDLER(USB_UnhandledControlPacket)\r
+void EVENT_USB_Device_UnhandledControlRequest(void)\r
 {\r
-       /* Discard unused wIndex value */\r
-       Endpoint_Discard_Word();\r
-       \r
-       /* Discard unused wValue value */\r
-       Endpoint_Discard_Word();\r
-\r
        /* Get the size of the command and data from the wLength value */\r
-       SentCommand.DataSize = Endpoint_Read_Word_LE();\r
+       SentCommand.DataSize = USB_ControlRequest.wLength;\r
 \r
-       switch (bRequest)\r
+       switch (USB_ControlRequest.bRequest)\r
        {\r
                case DFU_DNLOAD:\r
                        Endpoint_ClearSETUP();\r
@@ -178,7 +169,11 @@ EVENT_HANDLER(USB_UnhandledControlPacket)
                        /* If the request has a data stage, load it into the command struct */\r
                        if (SentCommand.DataSize)\r
                        {\r
-                               while (!(Endpoint_IsOUTReceived()));\r
+                               while (!(Endpoint_IsOUTReceived()))\r
+                               {                               \r
+                                       if (USB_DeviceState == DEVICE_STATE_Unattached)\r
+                                         return;\r
+                               }\r
 \r
                                /* First byte of the data stage is the DNLOAD request's command */\r
                                SentCommand.Command = Endpoint_Read_Byte();\r
@@ -210,8 +205,8 @@ EVENT_HANDLER(USB_UnhandledControlPacket)
                                        /* Throw away the filler bytes before the start of the firmware */\r
                                        DiscardFillerBytes(DFU_FILLER_BYTES_SIZE);\r
 \r
-                                       /* Throw away the page alignment filler bytes before the start of the firmware */\r
-                                       DiscardFillerBytes(StartAddr % SPM_PAGESIZE);\r
+                                       /* Throw away the packet alignment filler bytes before the start of the firmware */\r
+                                       DiscardFillerBytes(StartAddr % FIXED_CONTROL_ENDPOINT_SIZE);\r
                                        \r
                                        /* Calculate the number of bytes remaining to be written */\r
                                        uint16_t BytesRemaining = ((EndAddr - StartAddr) + 1);\r
@@ -236,7 +231,12 @@ EVENT_HANDLER(USB_UnhandledControlPacket)
                                                        if (!(Endpoint_BytesInEndpoint()))\r
                                                        {\r
                                                                Endpoint_ClearOUT();\r
-                                                               while (!(Endpoint_IsOUTReceived()));\r
+\r
+                                                               while (!(Endpoint_IsOUTReceived()))\r
+                                                               {                               \r
+                                                                       if (USB_DeviceState == DEVICE_STATE_Unattached)\r
+                                                                         return;\r
+                                                               }\r
                                                        }\r
 \r
                                                        /* Write the next word into the current flash page */\r
@@ -280,7 +280,12 @@ EVENT_HANDLER(USB_UnhandledControlPacket)
                                                        if (!(Endpoint_BytesInEndpoint()))\r
                                                        {\r
                                                                Endpoint_ClearOUT();\r
-                                                               while (!(Endpoint_IsOUTReceived()));\r
+\r
+                                                               while (!(Endpoint_IsOUTReceived()))\r
+                                                               {                               \r
+                                                                       if (USB_DeviceState == DEVICE_STATE_Unattached)\r
+                                                                         return;\r
+                                                               }\r
                                                        }\r
 \r
                                                        /* Read the byte from the USB interface and write to to the EEPROM */\r
@@ -298,16 +303,18 @@ EVENT_HANDLER(USB_UnhandledControlPacket)
 \r
                        Endpoint_ClearOUT();\r
 \r
-                       /* Acknowledge status stage */\r
-                       while (!(Endpoint_IsINReady()));\r
-                       Endpoint_ClearIN();\r
-                               \r
+                       Endpoint_ClearStatusStage();\r
+\r
                        break;\r
                case DFU_UPLOAD:\r
                        Endpoint_ClearSETUP();\r
 \r
-                       while (!(Endpoint_IsINReady()));\r
-\r
+                       while (!(Endpoint_IsINReady()))\r
+                       {                               \r
+                               if (USB_DeviceState == DEVICE_STATE_Unattached)\r
+                                 return;\r
+                       }\r
+                                                       \r
                        if (DFU_State != dfuUPLOAD_IDLE)\r
                        {\r
                                if ((DFU_State == dfuERROR) && IS_ONEBYTE_COMMAND(SentCommand.Data, 0x01))       // Blank Check\r
@@ -344,11 +351,16 @@ EVENT_HANDLER(USB_UnhandledControlPacket)
                                                if (Endpoint_BytesInEndpoint() == FIXED_CONTROL_ENDPOINT_SIZE)\r
                                                {\r
                                                        Endpoint_ClearIN();\r
-                                                       while (!(Endpoint_IsINReady()));\r
+\r
+                                                       while (!(Endpoint_IsINReady()))\r
+                                                       {                               \r
+                                                               if (USB_DeviceState == DEVICE_STATE_Unattached)\r
+                                                                 return;\r
+                                                       }\r
                                                }\r
 \r
                                                /* Read the flash word and send it via USB to the host */\r
-                                               #if defined(RAMPZ)\r
+                                               #if (FLASHEND > 0xFFFF)\r
                                                        Endpoint_Write_Word_LE(pgm_read_word_far(CurrFlashAddress.Long));\r
                                                #else\r
                                                        Endpoint_Write_Word_LE(pgm_read_word(CurrFlashAddress.Long));                                                   \r
@@ -369,7 +381,12 @@ EVENT_HANDLER(USB_UnhandledControlPacket)
                                                if (Endpoint_BytesInEndpoint() == FIXED_CONTROL_ENDPOINT_SIZE)\r
                                                {\r
                                                        Endpoint_ClearIN();\r
-                                                       while (!(Endpoint_IsINReady()));\r
+                                                       \r
+                                                       while (!(Endpoint_IsINReady()))\r
+                                                       {                               \r
+                                                               if (USB_DeviceState == DEVICE_STATE_Unattached)\r
+                                                                 return;\r
+                                                       }\r
                                                }\r
 \r
                                                /* Read the EEPROM byte and send it via USB to the host */\r
@@ -386,10 +403,7 @@ EVENT_HANDLER(USB_UnhandledControlPacket)
 \r
                        Endpoint_ClearIN();\r
 \r
-                       /* Acknowledge status stage */\r
-                       while (!(Endpoint_IsOUTReceived()));\r
-                       Endpoint_ClearOUT();\r
-\r
+                       Endpoint_ClearStatusStage();\r
                        break;\r
                case DFU_GETSTATUS:\r
                        Endpoint_ClearSETUP();\r
@@ -409,10 +423,7 @@ EVENT_HANDLER(USB_UnhandledControlPacket)
 \r
                        Endpoint_ClearIN();\r
                        \r
-                       /* Acknowledge status stage */\r
-                       while (!(Endpoint_IsOUTReceived()));\r
-                       Endpoint_ClearOUT();\r
-       \r
+                       Endpoint_ClearStatusStage();\r
                        break;          \r
                case DFU_CLRSTATUS:\r
                        Endpoint_ClearSETUP();\r
@@ -420,10 +431,7 @@ EVENT_HANDLER(USB_UnhandledControlPacket)
                        /* Reset the status value variable to the default OK status */\r
                        DFU_Status = OK;\r
 \r
-                       /* Acknowledge status stage */\r
-                       while (!(Endpoint_IsINReady()));\r
-                       Endpoint_ClearIN();\r
-                       \r
+                       Endpoint_ClearStatusStage();\r
                        break;\r
                case DFU_GETSTATE:\r
                        Endpoint_ClearSETUP();\r
@@ -433,21 +441,15 @@ EVENT_HANDLER(USB_UnhandledControlPacket)
                \r
                        Endpoint_ClearIN();\r
                        \r
-                       /* Acknowledge status stage */\r
-                       while (!(Endpoint_IsOUTReceived()));\r
-                       Endpoint_ClearOUT();\r
-\r
+                       Endpoint_ClearStatusStage();\r
                        break;\r
                case DFU_ABORT:\r
                        Endpoint_ClearSETUP();\r
                        \r
                        /* Reset the current state variable to the default idle state */\r
                        DFU_State = dfuIDLE;\r
-                       \r
-                       /* Acknowledge status stage */\r
-                       while (!(Endpoint_IsINReady()));\r
-                       Endpoint_ClearIN();\r
 \r
+                       Endpoint_ClearStatusStage();\r
                        break;\r
        }\r
 }\r
@@ -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\r
  *  discard unused bytes in the stream from the host, including the memory program block suffix.\r
  *\r
- *  \param NumberOfBytes  Number of bytes to discard from the host from the control endpoint\r
+ *  \param[in] NumberOfBytes  Number of bytes to discard from the host from the control endpoint\r
  */\r
 static void DiscardFillerBytes(uint8_t NumberOfBytes)\r
 {\r
@@ -466,10 +468,16 @@ static void DiscardFillerBytes(uint8_t NumberOfBytes)
                        Endpoint_ClearOUT();\r
 \r
                        /* Wait until next data packet received */\r
-                       while (!(Endpoint_IsOUTReceived()));\r
+                       while (!(Endpoint_IsOUTReceived()))\r
+                       {                               \r
+                               if (USB_DeviceState == DEVICE_STATE_Unattached)\r
+                                 return;\r
+                       }\r
+               }\r
+               else\r
+               {\r
+                       Endpoint_Discard_Byte();\r
                }\r
-\r
-               Endpoint_Discard_Byte();                                                \r
        }\r
 }\r
 \r
@@ -591,7 +599,7 @@ static void ProcessMemReadCommand(void)
                while (CurrFlashAddress < BOOT_START_ADDR)\r
                {\r
                        /* Check if the current byte is not blank */\r
-                       #if defined(RAMPZ)\r
+                       #if (FLASHEND > 0xFFFF)\r
                        if (pgm_read_byte_far(CurrFlashAddress) != 0xFF)\r
                        #else\r
                        if (pgm_read_byte(CurrFlashAddress) != 0xFF)\r
@@ -677,16 +685,12 @@ static void ProcessWriteCommand(void)
 static void ProcessReadCommand(void)\r
 {\r
        const uint8_t BootloaderInfo[3] = {BOOTLOADER_VERSION, BOOTLOADER_ID_BYTE1, BOOTLOADER_ID_BYTE2};\r
-       const uint8_t SignatureInfo[3]  = {SIGNATURE_0, SIGNATURE_1, SIGNATURE_2};\r
+       const uint8_t SignatureInfo[3]  = {AVR_SIGNATURE_1,    AVR_SIGNATURE_2,     AVR_SIGNATURE_3};\r
 \r
        uint8_t DataIndexToRead = SentCommand.Data[1];\r
 \r
        if (IS_ONEBYTE_COMMAND(SentCommand.Data, 0x00))                         // Read bootloader info\r
-       {\r
-               ResponseByte = BootloaderInfo[DataIndexToRead];\r
-       }\r
+         ResponseByte = BootloaderInfo[DataIndexToRead];\r
        else if (IS_ONEBYTE_COMMAND(SentCommand.Data, 0x01))                    // Read signature byte\r
-       {\r
-               ResponseByte = SignatureInfo[DataIndexToRead - 0x30];\r
-       }\r
+         ResponseByte = SignatureInfo[DataIndexToRead - 0x30];\r
 }\r