From e6503fd0d61bbcc1ff529cb2c57c2ca46ddd766c Mon Sep 17 00:00:00 2001
From: Micah Elizabeth Scott <micah@scanlime.org>
Date: Mon, 7 Oct 2013 17:46:51 -0700
Subject: [PATCH] Additional DFU cleanup, usb reset callback

---
 bootloader/dfu.c      |   7 ++-
 bootloader/dfu.h      |   1 +
 bootloader/usb_desc.c |   2 +-
 bootloader/usb_dev.c  | 104 ++++++++++++++++++++++--------------------
 4 files changed, 61 insertions(+), 53 deletions(-)

diff --git a/bootloader/dfu.c b/bootloader/dfu.c
index 766a9b2..90695fd 100644
--- a/bootloader/dfu.c
+++ b/bootloader/dfu.c
@@ -101,8 +101,6 @@ bool dfu_download(unsigned blockNum, unsigned blockLength,
 	// Store more data...
 	memcpy(dfu_buffer + packetOffset, data, packetLength);
 
-debug++;
-
 	if (packetOffset + packetLength != blockLength) {
 		// Still waiting for more data.
 		return true;
@@ -192,3 +190,8 @@ bool dfu_abort()
 	dfu_status = OK;
 	return true;
 }
+
+void dfu_usb_reset()
+{
+	debug++;
+}
diff --git a/bootloader/dfu.h b/bootloader/dfu.h
index 105f67f..bd2bf3b 100644
--- a/bootloader/dfu.h
+++ b/bootloader/dfu.h
@@ -68,6 +68,7 @@ void dfu_init();
 
 // USB entry points. Always successful.
 uint8_t dfu_getstate();
+void dfu_usb_reset();
 
 // USB entry points. True on success, false for stall.
 bool dfu_getstatus(uint8_t *status);
diff --git a/bootloader/usb_desc.c b/bootloader/usb_desc.c
index d968777..b28943c 100644
--- a/bootloader/usb_desc.c
+++ b/bootloader/usb_desc.c
@@ -113,7 +113,7 @@ static uint8_t config_descriptor[CONFIG_DESC_SIZE] = {
         // DFU Functional Descriptor (DFU spec TAble 4.2)
         9,                                      // bLength
         0x21,                                   // bDescriptorType
-        0x01,                                   // bmAttributes: Download only, must be reset
+        0x0D,                                   // bmAttributes
         LSB(DFU_DETACH_TIMEOUT),                // wDetachTimeOut
         MSB(DFU_DETACH_TIMEOUT),
         LSB(DFU_TRANSFER_SIZE),                 // wTransferSize
diff --git a/bootloader/usb_dev.c b/bootloader/usb_dev.c
index 7b17e1f..8aff8f8 100644
--- a/bootloader/usb_dev.c
+++ b/bootloader/usb_dev.c
@@ -38,14 +38,13 @@
 #include "dfu.h"
 
 // buffer descriptor table
-
 typedef struct {
     uint32_t desc;
     void * addr;
 } bdt_t;
 
 __attribute__ ((section(".usbdescriptortable"), used))
-static bdt_t table[4];  // EP0 only
+static bdt_t table[64];  // BDT page (512 bytes)
 
 #define BDT_OWN     0x80
 #define BDT_DATA1   0x40
@@ -74,36 +73,36 @@ static bdt_t table[4];  // EP0 only
 
 
 static union {
- struct {
-  union {
-   struct {
-    uint8_t bmRequestType;
-    uint8_t bRequest;
-   };
-    uint16_t wRequestAndType;
-  };
-    uint16_t wValue;
-    uint16_t wIndex;
-    uint16_t wLength;
- };
- struct {
-    uint32_t word1;
-    uint32_t word2;
- };
+    struct {
+        union {
+            struct {
+                uint8_t bmRequestType;
+                uint8_t bRequest;
+            };
+            uint16_t wRequestAndType;
+        };
+        uint16_t wValue;
+        uint16_t wIndex;
+        uint16_t wLength;
+    };
+    struct {
+        uint32_t word1;
+        uint32_t word2;
+    };
 } setup;
 
 
-#define GET_STATUS      0
+#define GET_STATUS          0
 #define CLEAR_FEATURE       1
-#define SET_FEATURE     3
-#define SET_ADDRESS     5
+#define SET_FEATURE         3
+#define SET_ADDRESS         5
 #define GET_DESCRIPTOR      6
 #define SET_DESCRIPTOR      7
 #define GET_CONFIGURATION   8
 #define SET_CONFIGURATION   9
 #define GET_INTERFACE       10
 #define SET_INTERFACE       11
-#define SYNCH_FRAME     12
+#define SYNCH_FRAME         12
 
 // SETUP always uses a DATA0 PID for the data field of the SETUP transaction.
 // transactions in the data phase start with DATA1 and toggle (figure 8-12, USB1.1)
@@ -135,6 +134,7 @@ static void endpoint0_transmit(const void *data, uint32_t len)
     ep0_tx_bdt_bank ^= 1;
 }
 
+
 static void usb_setup(void)
 {
     const uint8_t *data = NULL;
@@ -218,7 +218,12 @@ static void usb_setup(void)
             endpoint0_stall();
             return;
         }
-        // Data comes in the OUT phase.
+        // Data comes in the OUT phase. But if it's a zero-length request, handle it now.
+        if (setup.wLength == 0) {
+            if (!dfu_download(setup.wValue, 0, 0, 0, NULL)) {
+                endpoint0_stall();
+            }
+        }
         break;
 
       case 0x03a1: // DFU_GETSTATUS
@@ -329,36 +334,35 @@ static void usb_control(uint32_t stat)
         break;
 
     case 0x01:  // OUT transaction received from host
-        // The only control OUT request we have now, DFU_DNLOAD
-        if (setup.wRequestAndType == 0x0121 && setup.wIndex == 0 &&
-            ep0_rx_offset <= setup.wLength) {
-            bool success;
 
-            size = setup.wLength - ep0_rx_offset;
-            if (size > EP0_SIZE) size = EP0_SIZE;
-
-            success = dfu_download(setup.wValue,   // blockNum
-                                   setup.wLength,  // blockLength
-                                   ep0_rx_offset,  // packetOffset
-                                   size,           // packetLength
-                                   buf);           // data
-
-            // Give the buffer back
-            b->desc = BDT_DESC_RX(EP0_SIZE);
+        // The only control OUT request we have now, DFU_DNLOAD
+        if (setup.wRequestAndType == 0x0121) {
 
-            if (success) {
-                ep0_rx_offset += size;
-                if (ep0_rx_offset >= setup.wLength) {
-                    // End of transaction, acknowledge with a zero-length IN                
-                   endpoint0_transmit(reply_buffer, 0);
-                }
-            } else {
+            if (setup.wIndex != 0 && ep0_rx_offset > setup.wLength) {
                 endpoint0_stall();
+            } else {
+                size = setup.wLength - ep0_rx_offset;
+                if (size > EP0_SIZE) size = EP0_SIZE;
+
+                if (dfu_download(setup.wValue,   // blockNum
+                                 setup.wLength,  // blockLength
+                                 ep0_rx_offset,  // packetOffset
+                                 size,           // packetLength
+                                 buf)) {         // data
+
+                    ep0_rx_offset += size;
+                    if (ep0_rx_offset >= setup.wLength) {
+                        // End of transaction, acknowledge with a zero-length IN                
+                       endpoint0_transmit(reply_buffer, 0);
+                    }
+                } else {
+                    endpoint0_stall();
+                }
             }
-        } else {
-            // Give the buffer back
-            b->desc = BDT_DESC_RX(EP0_SIZE);
         }
+
+        // Give the buffer back
+        b->desc = BDT_DESC_RX(EP0_SIZE);
         break;
 
     case 0x09: // IN transaction completed to host
@@ -383,7 +387,6 @@ static void usb_control(uint32_t stat)
 }
 
 
-
 void usb_isr(void)
 {
     uint8_t status, stat;
@@ -442,6 +445,8 @@ restart:
 
         // is this necessary?
         USB0_CTL = USB_CTL_USBENSOFEN;
+
+        dfu_usb_reset();
         return;
     }
 
@@ -462,7 +467,6 @@ restart:
 }
 
 
-
 void usb_init(void)
 {
     // this basically follows the flowchart in the Kinetis
-- 
GitLab