USB device stack with Nucleo F401RE support. NOTE: the default clock config needs to be changed to in order for USB to work.

Fork of USBDevice by Tomas Cerskus

Slightly modified original USBDevice library to support F401RE.

On F401RE the data pins of your USB connector should be attached to PA12 (D+) and PA11(D-). It is also required to connect the +5V USB line to PA9.

F401RE requires 48MHz clock for USB. Therefore in order for this to work you will need to change the default clock settings:

Clock settings for USB

#include "stm32f4xx_hal.h"

RCC_OscInitTypeDef RCC_OscInitStruct;
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.HSICalibrationValue = 16;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
RCC_OscInitStruct.PLL.PLLM = 16;
RCC_OscInitStruct.PLL.PLLN = 336;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV4;
RCC_OscInitStruct.PLL.PLLQ = 7;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) {
    error("RTC error: LSI clock initialization failed."); 
}

NOTE: Changing the clock frequency might affect the behavior of other libraries. I only tested the Serial library.

UPDATE: Clock settings should not to be changed anymore! Looks like the newer mbed library has the required clock enabled.

Files at this revision

API Documentation at this revision

Comitter:
samux
Date:
Fri Mar 01 13:10:29 2013 +0000
Parent:
7:f8f057664123
Child:
9:354942d2fa38
Commit message:
add FRDM-KL25Z support

Changed in this revision

USBDevice/USBDevice.cpp Show annotated file Show diff for this revision Revisions of this file
USBDevice/USBEndpoints.h Show annotated file Show diff for this revision Revisions of this file
USBDevice/USBEndpoints_KL25Z.h Show annotated file Show diff for this revision Revisions of this file
USBDevice/USBHAL.h Show annotated file Show diff for this revision Revisions of this file
USBDevice/USBHAL_KL25Z.cpp Show annotated file Show diff for this revision Revisions of this file
USBDevice/USBHAL_LPC11U.cpp Show annotated file Show diff for this revision Revisions of this file
USBDevice/USBHAL_LPC17.cpp Show annotated file Show diff for this revision Revisions of this file
USBMSD/USBMSD.cpp Show annotated file Show diff for this revision Revisions of this file
USBMSD/USBMSD.h Show annotated file Show diff for this revision Revisions of this file
USBSerial/USBCDC.cpp Show annotated file Show diff for this revision Revisions of this file
--- a/USBDevice/USBDevice.cpp	Mon Jan 21 10:41:28 2013 +0000
+++ b/USBDevice/USBDevice.cpp	Fri Mar 01 13:10:29 2013 +0000
@@ -250,6 +250,7 @@
         }
 
         EP0read();
+        EP0readStage();
 
         /* Completed */
         return true;
--- a/USBDevice/USBEndpoints.h	Mon Jan 21 10:41:28 2013 +0000
+++ b/USBDevice/USBEndpoints.h	Fri Mar 01 13:10:29 2013 +0000
@@ -41,6 +41,8 @@
 #include "USBEndpoints_LPC17_LPC23.h"
 #elif defined(TARGET_LPC11U24)
 #include "USBEndpoints_LPC11U.h"
+#elif defined(TARGET_KL25Z)
+#include "USBEndpoints_KL25Z.h"
 #else
 #error "Unknown target type"
 #endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBDevice/USBEndpoints_KL25Z.h	Fri Mar 01 13:10:29 2013 +0000
@@ -0,0 +1,93 @@
+/* Copyright (c) 2010-2011 mbed.org, MIT License
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+* and associated documentation files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use, copy, modify, merge, publish,
+* distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in all copies or
+* substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#define NUMBER_OF_LOGICAL_ENDPOINTS (16)
+#define NUMBER_OF_PHYSICAL_ENDPOINTS (NUMBER_OF_LOGICAL_ENDPOINTS * 2)
+
+/* Define physical endpoint numbers */
+
+/*      Endpoint    No.   */
+/*      ----------------  */
+#define EP0OUT      (0)  
+#define EP0IN       (1)  
+#define EP1OUT      (2)  
+#define EP1IN       (3)  
+#define EP2OUT      (4)  
+#define EP2IN       (5)  
+#define EP3OUT      (6)  
+#define EP3IN       (7)  
+#define EP4OUT      (8)  
+#define EP4IN       (9)  
+#define EP5OUT      (10) 
+#define EP5IN       (11) 
+#define EP6OUT      (12) 
+#define EP6IN       (13) 
+#define EP7OUT      (14) 
+#define EP7IN       (15) 
+#define EP8OUT      (16) 
+#define EP8IN       (17) 
+#define EP9OUT      (18) 
+#define EP9IN       (19) 
+#define EP10OUT     (20) 
+#define EP10IN      (21) 
+#define EP11OUT     (22) 
+#define EP11IN      (23) 
+#define EP12OUT     (24) 
+#define EP12IN      (25) 
+#define EP13OUT     (26) 
+#define EP13IN      (27) 
+#define EP14OUT     (28) 
+#define EP14IN      (29) 
+#define EP15OUT     (30) 
+#define EP15IN      (31) 
+
+/* Maximum Packet sizes */
+
+#define MAX_PACKET_SIZE_EP0  (64)
+#define MAX_PACKET_SIZE_EP1  (64)
+#define MAX_PACKET_SIZE_EP2  (64)
+#define MAX_PACKET_SIZE_EP3  (1023)
+#define MAX_PACKET_SIZE_EP4  (64)
+#define MAX_PACKET_SIZE_EP5  (64)
+#define MAX_PACKET_SIZE_EP6  (64)
+#define MAX_PACKET_SIZE_EP7  (64)
+#define MAX_PACKET_SIZE_EP8  (64)
+#define MAX_PACKET_SIZE_EP9  (64)
+#define MAX_PACKET_SIZE_EP10 (64)
+#define MAX_PACKET_SIZE_EP11 (64)
+#define MAX_PACKET_SIZE_EP12 (64)
+#define MAX_PACKET_SIZE_EP13 (64)
+#define MAX_PACKET_SIZE_EP14 (64)
+#define MAX_PACKET_SIZE_EP15 (64)
+
+/* Generic endpoints - intended to be portable accross devices */
+/* and be suitable for simple USB devices. */
+
+/* Bulk endpoints */
+#define EPBULK_OUT  (EP2OUT)
+#define EPBULK_IN   (EP2IN)
+/* Interrupt endpoints */
+#define EPINT_OUT   (EP1OUT)
+#define EPINT_IN    (EP1IN)
+/* Isochronous endpoints */
+#define EPISO_OUT   (EP3OUT)
+#define EPISO_IN    (EP3IN)
+
+#define MAX_PACKET_SIZE_EPBULK  (MAX_PACKET_SIZE_EP2)
+#define MAX_PACKET_SIZE_EPINT   (MAX_PACKET_SIZE_EP1)
+#define MAX_PACKET_SIZE_EPISO   (MAX_PACKET_SIZE_EP3)
--- a/USBDevice/USBHAL.h	Mon Jan 21 10:41:28 2013 +0000
+++ b/USBDevice/USBHAL.h	Fri Mar 01 13:10:29 2013 +0000
@@ -37,6 +37,7 @@
     /* Endpoint 0 */
     void EP0setup(uint8_t *buffer);
     void EP0read(void);
+    void EP0readStage(void);
     uint32_t EP0getReadResult(uint8_t *buffer);
     void EP0write(uint8_t *buffer, uint32_t size);
     void EP0getWriteResult(void);
@@ -61,17 +62,52 @@
     virtual void connectStateChanged(unsigned int connected){};
     virtual void suspendStateChanged(unsigned int suspended){};
     virtual void SOF(int frameNumber){};
+            
     virtual bool EP1_OUT_callback(){return false;};
     virtual bool EP1_IN_callback(){return false;};
     virtual bool EP2_OUT_callback(){return false;};
     virtual bool EP2_IN_callback(){return false;};
     virtual bool EP3_OUT_callback(){return false;};
     virtual bool EP3_IN_callback(){return false;};
+    virtual bool EP4_OUT_callback(){return false;};
+    virtual bool EP4_IN_callback(){return false;};
+    
+#if !defined(TARGET_LPC11U24)
+    virtual bool EP5_OUT_callback(){return false;};
+    virtual bool EP5_IN_callback(){return false;};
+    virtual bool EP6_OUT_callback(){return false;};
+    virtual bool EP6_IN_callback(){return false;};
+    virtual bool EP7_OUT_callback(){return false;};
+    virtual bool EP7_IN_callback(){return false;};
+    virtual bool EP8_OUT_callback(){return false;};
+    virtual bool EP8_IN_callback(){return false;};
+    virtual bool EP9_OUT_callback(){return false;};
+    virtual bool EP9_IN_callback(){return false;};
+    virtual bool EP10_OUT_callback(){return false;};
+    virtual bool EP10_IN_callback(){return false;};
+    virtual bool EP11_OUT_callback(){return false;};
+    virtual bool EP11_IN_callback(){return false;};
+    virtual bool EP12_OUT_callback(){return false;};
+    virtual bool EP12_IN_callback(){return false;};
+    virtual bool EP13_OUT_callback(){return false;};
+    virtual bool EP13_IN_callback(){return false;};
+    virtual bool EP14_OUT_callback(){return false;};
+    virtual bool EP14_IN_callback(){return false;};
+    virtual bool EP15_OUT_callback(){return false;};
+    virtual bool EP15_IN_callback(){return false;};
+#endif
     
 private:
     void usbisr(void);
     static void _usbisr(void);
     static USBHAL * instance;
+
+#if defined(TARGET_LPC11U24)
+        bool (USBHAL::*epCallback[10 - 2])(void);
+#else
+        bool (USBHAL::*epCallback[32 - 2])(void);
+#endif
+
+        
 };
 #endif
-
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBDevice/USBHAL_KL25Z.cpp	Fri Mar 01 13:10:29 2013 +0000
@@ -0,0 +1,514 @@
+/* Copyright (c) 2010-2011 mbed.org, MIT License
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+* and associated documentation files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use, copy, modify, merge, publish,
+* distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in all copies or
+* substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#if defined(TARGET_KL25Z)
+
+#include "USBHAL.h"
+
+USBHAL * USBHAL::instance;
+
+static volatile int epComplete = 0;
+
+// Convert physical endpoint number to register bit
+#define EP(endpoint) (1<<(endpoint))
+
+// Convert physical to logical
+#define PHY_TO_LOG(endpoint)    ((endpoint)>>1)
+
+// Get endpoint direction
+#define IN_EP(endpoint)     ((endpoint) & 1U ? true : false)
+#define OUT_EP(endpoint)    ((endpoint) & 1U ? false : true)
+
+#define BD_OWN_MASK        (1<<7)
+#define BD_DATA01_MASK     (1<<6)
+#define BD_KEEP_MASK       (1<<5)
+#define BD_NINC_MASK       (1<<4)
+#define BD_DTS_MASK        (1<<3)
+#define BD_STALL_MASK      (1<<2)
+
+#define TX    1
+#define RX    0
+#define ODD   0
+#define EVEN  1
+// this macro waits a physical endpoint number
+#define EP_BDT_IDX(ep, dir, odd) (((ep * 4) + (2 * dir) + (1 *  odd)))
+
+#define SETUP_TOKEN    0x0D
+#define IN_TOKEN       0x09
+#define OUT_TOKEN      0x01
+#define TOK_PID(idx)   ((bdt[idx].info >> 2) & 0x0F)
+
+// for each endpt: 8 bytes
+typedef struct BDT {
+    uint8_t   info;       // BD[0:7]
+    uint8_t   dummy;      // RSVD: BD[8:15]
+    uint16_t  byte_count; // BD[16:32]
+    uint32_t  address;    // Addr
+} BDT; 
+
+
+// there are:
+//    * 16 bidirectionnal endpt -> 32 physical endpt
+//    * as there are ODD and EVEN buffer -> 32*2 bdt
+__attribute__((__aligned__(512))) BDT bdt[NUMBER_OF_PHYSICAL_ENDPOINTS * 2];
+uint8_t endpoint_buffer[(NUMBER_OF_PHYSICAL_ENDPOINTS - 2) * 2][64];
+uint8_t endpoint_buffer_iso[2*2][1023];
+
+static uint8_t set_addr = 0;
+static uint8_t addr = 0;
+
+static uint32_t Data1  = 0x55555555;
+
+static uint32_t frameNumber() {
+    return((USB0->FRMNUML | (USB0->FRMNUMH << 8) & 0x07FF));
+}
+
+uint32_t USBHAL::endpointReadcore(uint8_t endpoint, uint8_t *buffer) {
+    return 0;
+}
+
+USBHAL::USBHAL(void) {    
+    // Disable IRQ
+    NVIC_DisableIRQ(USB0_IRQn);
+    
+    // fill in callback array
+    epCallback[0] = &USBHAL::EP1_OUT_callback;
+    epCallback[1] = &USBHAL::EP1_IN_callback;
+    epCallback[2] = &USBHAL::EP2_OUT_callback;
+    epCallback[3] = &USBHAL::EP2_IN_callback;
+    epCallback[4] = &USBHAL::EP3_OUT_callback;
+    epCallback[5] = &USBHAL::EP3_IN_callback;
+    epCallback[6] = &USBHAL::EP4_OUT_callback;
+    epCallback[7] = &USBHAL::EP4_IN_callback;
+    epCallback[8] = &USBHAL::EP5_OUT_callback;
+    epCallback[9] = &USBHAL::EP5_IN_callback;
+    epCallback[10] = &USBHAL::EP6_OUT_callback;
+    epCallback[11] = &USBHAL::EP6_IN_callback;
+    epCallback[12] = &USBHAL::EP7_OUT_callback;
+    epCallback[13] = &USBHAL::EP7_IN_callback;
+    epCallback[14] = &USBHAL::EP8_OUT_callback;
+    epCallback[15] = &USBHAL::EP8_IN_callback;
+    epCallback[16] = &USBHAL::EP9_OUT_callback;
+    epCallback[17] = &USBHAL::EP9_IN_callback;
+    epCallback[18] = &USBHAL::EP10_OUT_callback;
+    epCallback[19] = &USBHAL::EP10_IN_callback;
+    epCallback[20] = &USBHAL::EP11_OUT_callback;
+    epCallback[21] = &USBHAL::EP11_IN_callback;
+    epCallback[22] = &USBHAL::EP12_OUT_callback;
+    epCallback[23] = &USBHAL::EP12_IN_callback;
+    epCallback[24] = &USBHAL::EP13_OUT_callback;
+    epCallback[25] = &USBHAL::EP13_IN_callback;
+    epCallback[26] = &USBHAL::EP14_OUT_callback;
+    epCallback[27] = &USBHAL::EP14_IN_callback;
+    epCallback[28] = &USBHAL::EP15_OUT_callback;
+    epCallback[29] = &USBHAL::EP15_IN_callback;
+    
+    
+    // choose usb src as PLL
+    SIM->SOPT2 |= (SIM_SOPT2_USBSRC_MASK | SIM_SOPT2_PLLFLLSEL_MASK);
+    
+    // enable OTG clock
+    SIM->SCGC4 |= SIM_SCGC4_USBOTG_MASK;
+
+    // Attach IRQ
+    instance = this;
+    NVIC_SetVector(USB0_IRQn, (uint32_t)&_usbisr);
+    NVIC_EnableIRQ(USB0_IRQn);
+    
+    // USB Module Configuration
+    // Reset USB Module
+    USB0->USBTRC0 |= USB_USBTRC0_USBRESET_MASK;
+    while(USB0->USBTRC0 & USB_USBTRC0_USBRESET_MASK);
+    
+    // Set BDT Base Register
+    USB0->BDTPAGE1=(uint8_t)((uint32_t)bdt>>8);
+    USB0->BDTPAGE2=(uint8_t)((uint32_t)bdt>>16);
+    USB0->BDTPAGE3=(uint8_t)((uint32_t)bdt>>24);
+
+    // Clear interrupt flag
+    USB0->ISTAT = 0xff;
+
+    // USB Interrupt Enablers
+    USB0->INTEN |= USB_INTEN_TOKDNEEN_MASK | 
+                   USB_INTEN_SOFTOKEN_MASK | 
+                   USB_INTEN_ERROREN_MASK  |
+                   USB_INTEN_USBRSTEN_MASK;
+    
+    // Disable weak pull downs 
+    USB0->USBCTRL &= ~(USB_USBCTRL_PDE_MASK | USB_USBCTRL_SUSP_MASK);   
+    
+    USB0->USBTRC0 |= 0x40;
+}
+
+USBHAL::~USBHAL(void) { }
+
+void USBHAL::connect(void) {
+    // enable USB
+    USB0->CTL |= USB_CTL_USBENSOFEN_MASK;
+    // Pull up enable
+    USB0->CONTROL |= USB_CONTROL_DPPULLUPNONOTG_MASK;
+}
+
+void USBHAL::disconnect(void) {
+    // disable USB
+    USB0->CTL &= ~USB_CTL_USBENSOFEN_MASK;
+    // Pull up disable
+    USB0->CONTROL &= ~USB_CONTROL_DPPULLUPNONOTG_MASK;
+}
+
+void USBHAL::configureDevice(void) {
+    // not needed
+}
+
+void USBHAL::unconfigureDevice(void) {
+    // not needed
+}
+
+void USBHAL::setAddress(uint8_t address) {
+    // we don't set the address now otherwise the usb controller does not ack
+    // we set a flag instead
+    // see usbisr when an IN token is received
+    set_addr = 1;
+    addr = address;
+}
+
+bool USBHAL::realiseEndpoint(uint8_t endpoint, uint32_t maxPacket, uint32_t flags) {
+    uint32_t handshake_flag = 0;
+    uint8_t * buf;
+
+    if (endpoint > NUMBER_OF_PHYSICAL_ENDPOINTS - 1) {
+        return false;
+    }
+
+    uint32_t log_endpoint = PHY_TO_LOG(endpoint);
+
+    if ((flags & ISOCHRONOUS) == 0) {
+        handshake_flag = USB_ENDPT_EPHSHK_MASK;
+        if (IN_EP(endpoint))
+            buf = &endpoint_buffer[EP_BDT_IDX(log_endpoint, TX, ODD )][0];
+        else
+            buf = &endpoint_buffer[EP_BDT_IDX(log_endpoint, RX, ODD )][0];
+    } else {
+        if (IN_EP(endpoint))
+            buf = &endpoint_buffer_iso[2][0];
+        else
+            buf = &endpoint_buffer_iso[0][0];
+    }
+
+    // IN endpt -> device to host (TX)
+    if (IN_EP(endpoint)) {
+        USB0->ENDPOINT[log_endpoint].ENDPT |= handshake_flag |        // ep handshaking (not if iso endpoint)
+                                              USB_ENDPT_EPTXEN_MASK;  // en TX (IN) tran
+        bdt[EP_BDT_IDX(log_endpoint, TX, ODD )].address = (uint32_t) buf;
+        bdt[EP_BDT_IDX(log_endpoint, TX, EVEN)].address = 0;
+    }
+    // OUT endpt -> host to device (RX)
+    else {
+        USB0->ENDPOINT[log_endpoint].ENDPT |= handshake_flag |        // ep handshaking (not if iso endpoint)
+                                              USB_ENDPT_EPRXEN_MASK;  // en RX (OUT) tran.
+        bdt[EP_BDT_IDX(log_endpoint, RX, ODD )].byte_count = maxPacket;
+        bdt[EP_BDT_IDX(log_endpoint, RX, ODD )].address    = (uint32_t) buf;
+        bdt[EP_BDT_IDX(log_endpoint, RX, ODD )].info       = BD_OWN_MASK | BD_DTS_MASK;
+        bdt[EP_BDT_IDX(log_endpoint, RX, EVEN)].info       = 0;
+    }
+
+    Data1 |= (1 << endpoint);
+
+    return true;
+}
+
+// read setup packet
+void USBHAL::EP0setup(uint8_t *buffer) {
+    uint32_t sz;
+    endpointReadResult(EP0OUT, buffer, &sz);
+}
+
+void USBHAL::EP0readStage(void) {
+    Data1 &= ~1UL;  // set DATA0
+    bdt[0].info = (BD_DTS_MASK | BD_OWN_MASK);
+}
+
+void USBHAL::EP0read(void) {
+    uint32_t idx = EP_BDT_IDX(PHY_TO_LOG(EP0OUT), RX, 0);
+    bdt[idx].byte_count = MAX_PACKET_SIZE_EP0;
+}
+
+uint32_t USBHAL::EP0getReadResult(uint8_t *buffer) {
+    uint32_t sz;
+    endpointReadResult(EP0OUT, buffer, &sz);
+    return sz;
+}
+
+void USBHAL::EP0write(uint8_t *buffer, uint32_t size) {
+    endpointWrite(EP0IN, buffer, size);
+}
+
+void USBHAL::EP0getWriteResult(void) {
+}
+
+void USBHAL::EP0stall(void) {
+    stallEndpoint(EP0OUT);
+}
+
+EP_STATUS USBHAL::endpointRead(uint8_t endpoint, uint32_t maximumSize) {
+    endpoint = PHY_TO_LOG(endpoint);
+    uint32_t idx = EP_BDT_IDX(endpoint, RX, 0);
+    bdt[idx].byte_count = maximumSize;
+    return EP_PENDING;
+}
+
+EP_STATUS USBHAL::endpointReadResult(uint8_t endpoint, uint8_t * buffer, uint32_t *bytesRead) {
+    uint32_t n, sz, idx, setup = 0;
+    uint8_t not_iso;
+    uint8_t * ep_buf;
+    
+    uint32_t log_endpoint = PHY_TO_LOG(endpoint);
+    
+    if (endpoint > NUMBER_OF_PHYSICAL_ENDPOINTS - 1) {
+        return EP_INVALID;
+    }
+
+    // if read on a IN endpoint -> error
+    if (IN_EP(endpoint)) {
+        return EP_INVALID;
+    }
+
+    idx = EP_BDT_IDX(log_endpoint, RX, 0);
+    sz  = bdt[idx].byte_count;
+    not_iso = USB0->ENDPOINT[log_endpoint].ENDPT & USB_ENDPT_EPHSHK_MASK;
+
+    //for isochronous endpoint, we don't wait an interrupt
+    if ((log_endpoint != 0) && not_iso && !(epComplete & EP(endpoint))) {
+        return EP_PENDING;
+    }
+
+    if ((log_endpoint == 0) && (TOK_PID(idx) == SETUP_TOKEN)) {
+        setup = 1;
+    }
+
+    // non iso endpoint
+    if (not_iso) {
+        ep_buf = endpoint_buffer[idx];
+    } else {
+        ep_buf = endpoint_buffer_iso[0];
+    }
+
+    for (n = 0; n < sz; n++) {
+        buffer[n] = ep_buf[n];
+    }
+
+    if (((Data1 >> endpoint) & 1) == ((bdt[idx].info >> 6) & 1)) {
+        if (setup && (buffer[6] == 0))  // if no setup data stage,
+            Data1 &= ~1UL;              // set DATA0
+        else 
+            Data1 ^= (1 << endpoint);
+    }
+
+    if (((Data1 >> endpoint) & 1)) {
+        bdt[idx].info = BD_DTS_MASK | BD_DATA01_MASK | BD_OWN_MASK;
+    }
+    else {
+        bdt[idx].info = BD_DTS_MASK | BD_OWN_MASK;
+    }
+        
+    USB0->CTL &= ~USB_CTL_TXSUSPENDTOKENBUSY_MASK;
+    *bytesRead = sz;
+
+    epComplete &= ~EP(endpoint);
+    return EP_COMPLETED;
+}
+
+EP_STATUS USBHAL::endpointWrite(uint8_t endpoint, uint8_t *data, uint32_t size) {
+    uint32_t idx, n;
+    uint8_t * ep_buf;
+
+    if (endpoint > NUMBER_OF_PHYSICAL_ENDPOINTS - 1) {
+        return EP_INVALID;
+    }
+
+    // if write on a OUT endpoint -> error
+    if (OUT_EP(endpoint)) {
+        return EP_INVALID;
+    }
+
+    idx = EP_BDT_IDX(PHY_TO_LOG(endpoint), TX, 0);
+    bdt[idx].byte_count = size;
+    
+    
+    // non iso endpoint
+    if (USB0->ENDPOINT[PHY_TO_LOG(endpoint)].ENDPT & USB_ENDPT_EPHSHK_MASK) {
+        ep_buf = endpoint_buffer[idx];
+    } else {
+        ep_buf = endpoint_buffer_iso[2];
+    }
+    
+    for (n = 0; n < size; n++) {
+        ep_buf[n] = data[n];
+    }
+    
+    if ((Data1 >> endpoint) & 1) {
+        bdt[idx].info = BD_OWN_MASK | BD_DTS_MASK;
+    } else {
+        bdt[idx].info = BD_OWN_MASK | BD_DTS_MASK | BD_DATA01_MASK;
+    }
+    
+    Data1 ^= (1 << endpoint);
+    
+    return EP_PENDING;
+}
+
+EP_STATUS USBHAL::endpointWriteResult(uint8_t endpoint) {
+    if (epComplete & EP(endpoint)) {
+        epComplete &= ~EP(endpoint);
+        return EP_COMPLETED;
+    }
+
+    return EP_PENDING;
+}
+
+void USBHAL::stallEndpoint(uint8_t endpoint) {
+    USB0->ENDPOINT[PHY_TO_LOG(endpoint)].ENDPT |= USB_ENDPT_EPSTALL_MASK;
+}
+
+void USBHAL::unstallEndpoint(uint8_t endpoint) {
+    USB0->ENDPOINT[PHY_TO_LOG(endpoint)].ENDPT &= ~USB_ENDPT_EPSTALL_MASK;
+}
+
+bool USBHAL::getEndpointStallState(uint8_t endpoint) {
+    uint8_t stall = (USB0->ENDPOINT[PHY_TO_LOG(endpoint)].ENDPT & USB_ENDPT_EPSTALL_MASK);
+    return (stall) ? true : false;
+}
+
+void USBHAL::remoteWakeup(void) {
+    // [TODO]
+}
+
+
+void USBHAL::_usbisr(void) {
+    instance->usbisr();
+}
+
+
+void USBHAL::usbisr(void) {
+    uint8_t i;
+    uint8_t istat = USB0->ISTAT;
+
+    // reset interrupt
+    if (istat & USB_ISTAT_USBRST_MASK) {            
+        // disable all endpt
+        for(i = 0; i < 16; i++) {
+            USB0->ENDPOINT[i].ENDPT = 0x00;
+        }
+
+        // enable control endpoint
+        realiseEndpoint(EP0OUT, MAX_PACKET_SIZE_EP0, 0);
+        realiseEndpoint(EP0IN, MAX_PACKET_SIZE_EP0, 0);
+
+        Data1 = 0x55555555;
+        USB0->CTL |=  USB_CTL_ODDRST_MASK;
+
+        USB0->ISTAT   =  0xFF;  // clear all interrupt status flags
+        USB0->ERRSTAT =  0xFF;  // clear all error flags
+        USB0->ERREN   =  0xFF;  // enable error interrupt sources
+        USB0->ADDR    =  0x00;  // set default address
+
+        return;
+    }
+
+    // resume interrupt
+    if (istat & USB_ISTAT_RESUME_MASK) {
+        USB0->ISTAT = USB_ISTAT_RESUME_MASK;
+    }
+
+    // SOF interrupt
+    if (istat & USB_ISTAT_SOFTOK_MASK) {
+        USB0->ISTAT = USB_ISTAT_SOFTOK_MASK;  
+        // SOF event, read frame number
+        SOF(frameNumber());
+    }
+    
+    // stall interrupt
+    if (istat & 1<<7) {
+        if (USB0->ENDPOINT[0].ENDPT & USB_ENDPT_EPSTALL_MASK)
+            USB0->ENDPOINT[0].ENDPT &= ~USB_ENDPT_EPSTALL_MASK;
+        USB0->ISTAT |= USB_ISTAT_STALL_MASK;
+    }
+
+    // token interrupt
+    if (istat & 1<<3) {
+        uint32_t num  = (USB0->STAT >> 4) & 0x0F;
+        uint32_t dir  = (USB0->STAT >> 3) & 0x01;
+        uint32_t ev_odd = (USB0->STAT >> 2) & 0x01;
+
+        // setup packet
+        if ((num == 0) && (TOK_PID((EP_BDT_IDX(num, dir, ev_odd))) == SETUP_TOKEN)) {
+            Data1 &= ~0x02;
+            bdt[EP_BDT_IDX(0, TX, EVEN)].info &= ~BD_OWN_MASK;
+            bdt[EP_BDT_IDX(0, TX, ODD)].info  &= ~BD_OWN_MASK;
+
+            // EP0 SETUP event (SETUP data received)
+            EP0setupCallback();
+                    
+        } else {
+            // OUT packet
+            if (TOK_PID((EP_BDT_IDX(num, dir, ev_odd))) == OUT_TOKEN) {
+                if (num == 0)
+                    EP0out();
+                else {
+                    epComplete |= (1 << EP(num));
+                    if ((instance->*(epCallback[EP(num) - 2]))()) {
+                        epComplete &= ~(1 << EP(num));
+                    }
+                }
+            }
+
+            // IN packet
+            if (TOK_PID((EP_BDT_IDX(num, dir, ev_odd))) == IN_TOKEN) {
+                if (num == 0) {
+                    EP0in();
+                    if (set_addr == 1) {
+                        USB0->ADDR = addr & 0x7F;
+                        set_addr = 0;
+                    }
+                }
+                else {
+                    epComplete |= (1 << (EP(num) + 1));
+                    if ((instance->*(epCallback[EP(num) + 1 - 2]))()) {
+                        epComplete &= ~(1 << (EP(num) + 1));
+                    }
+                }
+            }
+        }
+
+        USB0->ISTAT = USB_ISTAT_TOKDNE_MASK;
+    }
+        
+    // sleep interrupt
+    if (istat & 1<<4) {
+        USB0->ISTAT |= USB_ISTAT_SLEEP_MASK;
+    }    
+
+    // error interrupt
+    if (istat & USB_ISTAT_ERROR_MASK) {
+        USB0->ERRSTAT = 0xFF;
+        USB0->ISTAT |= USB_ISTAT_ERROR_MASK;
+    }
+}
+
+
+#endif
--- a/USBDevice/USBHAL_LPC11U.cpp	Mon Jan 21 10:41:28 2013 +0000
+++ b/USBDevice/USBHAL_LPC11U.cpp	Fri Mar 01 13:10:29 2013 +0000
@@ -22,7 +22,6 @@
 
 USBHAL * USBHAL::instance;
 
-
 // Valid physical endpoint numbers are 0 to (NUMBER_OF_PHYSICAL_ENDPOINTS-1)
 #define LAST_PHYSICAL_ENDPOINT (NUMBER_OF_PHYSICAL_ENDPOINTS-1)
 
@@ -129,6 +128,16 @@
 
 USBHAL::USBHAL(void) {
     NVIC_DisableIRQ(USB_IRQn);
+    
+    // fill in callback array
+    epCallback[0] = &USBHAL::EP1_OUT_callback;
+    epCallback[1] = &USBHAL::EP1_IN_callback;
+    epCallback[2] = &USBHAL::EP2_OUT_callback;
+    epCallback[3] = &USBHAL::EP2_IN_callback;
+    epCallback[4] = &USBHAL::EP3_OUT_callback;
+    epCallback[5] = &USBHAL::EP3_IN_callback;
+    epCallback[6] = &USBHAL::EP4_OUT_callback;
+    epCallback[7] = &USBHAL::EP4_IN_callback;
 
     // nUSB_CONNECT output
     LPC_IOCON->PIO0_6 = 0x00000001;
@@ -181,7 +190,6 @@
 USBHAL::~USBHAL(void) {
     // Ensure device disconnected (DCON not set)
     LPC_USB->DEVCMDSTAT = 0;
-
     // Disable USB interrupts
     NVIC_DisableIRQ(USB_IRQn);
 }
@@ -199,9 +207,11 @@
 }
 
 void USBHAL::configureDevice(void) {
+    // Not required
 }
 
 void USBHAL::unconfigureDevice(void) {
+    // Not required
 }
 
 void USBHAL::EP0setup(uint8_t *buffer) {
@@ -232,6 +242,11 @@
     return bytesRead;
 }
 
+
+void USBHAL::EP0readStage(void) {
+    // Not required
+}
+
 void USBHAL::EP0write(uint8_t *buffer, uint32_t size) {
     // Start and endpoint 0 write
 
@@ -303,10 +318,7 @@
 }
 
 void USBHAL::EP0getWriteResult(void) {
-    // Complete an endpoint 0 write
-
-    // Nothing required for this target
-    return;
+    // Not required
 }
 
 void USBHAL::EP0stall(void) {
@@ -385,8 +397,8 @@
 
 EP_STATUS USBHAL::endpointWriteResult(uint8_t endpoint) {
     uint32_t bf;
+    
     // Validate parameters
-
     if (endpoint > LAST_PHYSICAL_ENDPOINT) {
         return EP_INVALID;
     }
@@ -422,8 +434,7 @@
 
 void USBHAL::stallEndpoint(uint8_t endpoint) {
 
-    // TODO: should this clear active bit?
-
+    // FIX: should this clear active bit?
     if (IN_EP(endpoint)) {
         ep[PHY_TO_LOG(endpoint)].in[0] |= CMDSTS_S;
         ep[PHY_TO_LOG(endpoint)].in[1] |= CMDSTS_S;
@@ -441,26 +452,26 @@
             ep[PHY_TO_LOG(endpoint)].in[1] = 0; // S = 0
 
             if (LPC_USB->EPINUSE & EP(endpoint)) {
-                ep[PHY_TO_LOG(endpoint)].in[1] = CMDSTS_TR; // S =0, TR=1, TV = 0
+                ep[PHY_TO_LOG(endpoint)].in[1] = CMDSTS_TR; // S = 0, TR = 1, TV = 0
             } else {
-                ep[PHY_TO_LOG(endpoint)].in[0] = CMDSTS_TR; // S =0, TR=1, TV = 0
+                ep[PHY_TO_LOG(endpoint)].in[0] = CMDSTS_TR; // S = 0, TR = 1, TV = 0
             }
         } else {
             ep[PHY_TO_LOG(endpoint)].out[0] = 0; // S = 0
             ep[PHY_TO_LOG(endpoint)].out[1] = 0; // S = 0
 
             if (LPC_USB->EPINUSE & EP(endpoint)) {
-                ep[PHY_TO_LOG(endpoint)].out[1] = CMDSTS_TR; // S =0, TR=1, TV = 0
+                ep[PHY_TO_LOG(endpoint)].out[1] = CMDSTS_TR; // S = 0, TR = 1, TV = 0
             } else {
-                ep[PHY_TO_LOG(endpoint)].out[0] = CMDSTS_TR; // S =0, TR=1, TV = 0
+                ep[PHY_TO_LOG(endpoint)].out[0] = CMDSTS_TR; // S = 0, TR = 1, TV = 0
             }
         }
     } else {
         // Single buffered
         if (IN_EP(endpoint)) {
-            ep[PHY_TO_LOG(endpoint)].in[0] = CMDSTS_TR; // S=0, TR=1, TV = 0
+            ep[PHY_TO_LOG(endpoint)].in[0] = CMDSTS_TR;     // S = 0, TR = 1, TV = 0
         } else {
-            ep[PHY_TO_LOG(endpoint)].out[0] = CMDSTS_TR; // S=0, TR=1, TV = 0
+            ep[PHY_TO_LOG(endpoint)].out[0] = CMDSTS_TR;    // S = 0, TR = 1, TV = 0
         }
     }
 }
@@ -658,55 +669,15 @@
         // EP0IN ACK event (IN data sent)
         EP0in();
     }
-
-    if (LPC_USB->INTSTAT & EP(EP1IN)) {
-        // Clear EP1IN interrupt
-        LPC_USB->INTSTAT = EP(EP1IN);
-        epComplete |= EP(EP1IN);
-        if (EP1_IN_callback())
-            epComplete &= ~EP(EP1IN);
-    }
-
-    if (LPC_USB->INTSTAT & EP(EP1OUT)) {
-        // Clear EP1OUT interrupt
-        LPC_USB->INTSTAT = EP(EP1OUT);
-        epComplete |= EP(EP1OUT);
-        if (EP1_OUT_callback())
-            epComplete &= ~EP(EP1OUT);
-    }
-
-    if (LPC_USB->INTSTAT & EP(EP2IN)) {
-        // Clear EPBULK_IN interrupt
-        LPC_USB->INTSTAT = EP(EP2IN);
-        epComplete |= EP(EP2IN);
-        if (EP2_IN_callback())
-            epComplete &= ~EP(EP2IN);
-    }
-
-    if (LPC_USB->INTSTAT & EP(EP2OUT)) {
-        // Clear EPBULK_OUT interrupt
-        LPC_USB->INTSTAT = EP(EP2OUT);
-        epComplete |= EP(EP2OUT);
-        //Call callback function. If true, clear epComplete
-        if (EP2_OUT_callback())
-            epComplete &= ~EP(EP2OUT);
-    }
-
-    if (LPC_USB->INTSTAT & EP(EP3IN)) {
-        // Clear EP3_IN interrupt
-        LPC_USB->INTSTAT = EP(EP3IN);
-        epComplete |= EP(EP3IN);
-        if (EP3_IN_callback())
-            epComplete &= ~EP(EP3IN);
-    }
-
-    if (LPC_USB->INTSTAT & EP(EP3OUT)) {
-        // Clear EP3_OUT interrupt
-        LPC_USB->INTSTAT = EP(EP3OUT);
-        epComplete |= EP(EP3OUT);
-        //Call callback function. If true, clear epComplete
-        if (EP3_OUT_callback())
-            epComplete &= ~EP(EP3OUT);
+    
+    for (uint8_t num = 2; num < 5*2; num++) {
+        if (LPC_USB->INTSTAT & EP(num)) {
+            LPC_USB->INTSTAT = EP(num);
+            epComplete |= EP(num);
+            if ((instance->*(epCallback[num - 2]))()) {
+                epComplete &= ~EP(num);
+            }
+        }
     }
 }
 
--- a/USBDevice/USBHAL_LPC17.cpp	Mon Jan 21 10:41:28 2013 +0000
+++ b/USBDevice/USBHAL_LPC17.cpp	Fri Mar 01 13:10:29 2013 +0000
@@ -16,7 +16,7 @@
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
 
-#ifdef TARGET_LPC1768
+#if defined(TARGET_LPC1768) || defined(TARGET_LPC2368)
 
 #include "USBHAL.h"
 
@@ -116,8 +116,8 @@
 
 USBHAL * USBHAL::instance;
 
-volatile int epComplete;
-uint32_t endpointStallState;
+static volatile int epComplete;
+static uint32_t endpointStallState;
 
 static void SIECommand(uint32_t command) {
     // The command phase of a SIE transaction
@@ -209,18 +209,14 @@
 
 static void SIEconnect(void) {
     // Connect USB device
-    uint8_t status;
-
-    status = SIEgetDeviceStatus();
+    uint8_t status = SIEgetDeviceStatus();
     SIEsetDeviceStatus(status | SIE_DS_CON);
 }
 
 
 static void SIEdisconnect(void) {
     // Disconnect USB device
-    uint8_t status;
-
-    status = SIEgetDeviceStatus();
+    uint8_t status = SIEgetDeviceStatus();
     SIEsetDeviceStatus(status & ~SIE_DS_CON);
 }
 
@@ -233,9 +229,6 @@
 }
 
 
-
-
-
 static void enableEndpointEvent(uint8_t endpoint) {
     // Enable an endpoint interrupt
     LPC_USB->USBEpIntEn |= EP(endpoint);
@@ -248,8 +241,6 @@
 }
 
 static volatile uint32_t __attribute__((used)) dummyRead;
-
-
 uint32_t USBHAL::endpointReadcore(uint8_t endpoint, uint8_t *buffer) {
     // Read from an OUT endpoint
     uint32_t size;
@@ -333,15 +324,41 @@
     SIEvalidateBuffer();
 }
 
-
-
-
-
-
-
 USBHAL::USBHAL(void) {
     // Disable IRQ
     NVIC_DisableIRQ(USB_IRQn);
+    
+    // fill in callback array
+    epCallback[0] = &USBHAL::EP1_OUT_callback;
+    epCallback[1] = &USBHAL::EP1_IN_callback;
+    epCallback[2] = &USBHAL::EP2_OUT_callback;
+    epCallback[3] = &USBHAL::EP2_IN_callback;
+    epCallback[4] = &USBHAL::EP3_OUT_callback;
+    epCallback[5] = &USBHAL::EP3_IN_callback;
+    epCallback[6] = &USBHAL::EP4_OUT_callback;
+    epCallback[7] = &USBHAL::EP4_IN_callback;
+    epCallback[8] = &USBHAL::EP5_OUT_callback;
+    epCallback[9] = &USBHAL::EP5_IN_callback;
+    epCallback[10] = &USBHAL::EP6_OUT_callback;
+    epCallback[11] = &USBHAL::EP6_IN_callback;
+    epCallback[12] = &USBHAL::EP7_OUT_callback;
+    epCallback[13] = &USBHAL::EP7_IN_callback;
+    epCallback[14] = &USBHAL::EP8_OUT_callback;
+    epCallback[15] = &USBHAL::EP8_IN_callback;
+    epCallback[16] = &USBHAL::EP9_OUT_callback;
+    epCallback[17] = &USBHAL::EP9_IN_callback;
+    epCallback[18] = &USBHAL::EP10_OUT_callback;
+    epCallback[19] = &USBHAL::EP10_IN_callback;
+    epCallback[20] = &USBHAL::EP11_OUT_callback;
+    epCallback[21] = &USBHAL::EP11_IN_callback;
+    epCallback[22] = &USBHAL::EP12_OUT_callback;
+    epCallback[23] = &USBHAL::EP12_IN_callback;
+    epCallback[24] = &USBHAL::EP13_OUT_callback;
+    epCallback[25] = &USBHAL::EP13_IN_callback;
+    epCallback[26] = &USBHAL::EP14_OUT_callback;
+    epCallback[27] = &USBHAL::EP14_IN_callback;
+    epCallback[28] = &USBHAL::EP15_OUT_callback;
+    epCallback[29] = &USBHAL::EP15_IN_callback;
 
     // Enable power to USB device controller
     LPC_SC->PCONP |= PCUSB;
@@ -381,7 +398,6 @@
 USBHAL::~USBHAL(void) {
     // Ensure device disconnected
     SIEdisconnect();
-
     // Disable USB interrupts
     NVIC_DisableIRQ(USB_IRQn);
 }
@@ -418,6 +434,10 @@
     // Not required
 }
 
+void USBHAL::EP0readStage(void) {
+    // Not required
+}
+
 uint32_t USBHAL::EP0getReadResult(uint8_t *buffer) {
     return endpointReadcore(EP0OUT, buffer);
 }
@@ -527,10 +547,6 @@
     SIEsetDeviceStatus(status & ~SIE_DS_SUS);
 }
 
-
-
-
-
 void USBHAL::_usbisr(void) {
     instance->usbisr();
 }
@@ -590,54 +606,16 @@
             LPC_USB->USBDevIntClr = EP_SLOW;
             EP0in();
         }
-
-        // TODO: This should cover all endpoints, not just EP1,2,3:
-        if (LPC_USB->USBEpIntSt & EP(EP1IN)) {
-            selectEndpointClearInterrupt(EP1IN);
-            epComplete |= EP(EP1IN);
-            LPC_USB->USBDevIntClr = EP_SLOW;
-            if (EP1_IN_callback())
-                epComplete &= ~EP(EP1IN);
-        }
-
-        if (LPC_USB->USBEpIntSt & EP(EP1OUT)) {
-            selectEndpointClearInterrupt(EP1OUT);
-            epComplete |= EP(EP1OUT);
-            LPC_USB->USBDevIntClr = EP_SLOW;
-            if (EP1_OUT_callback())
-                epComplete &= ~EP(EP1OUT);
-        }
-
-        if (LPC_USB->USBEpIntSt & EP(EP2IN)) {
-            selectEndpointClearInterrupt(EP2IN);
-            epComplete |= EP(EP2IN);
-            LPC_USB->USBDevIntClr = EP_SLOW;
-            if (EP2_IN_callback())
-                epComplete &= ~EP(EP2IN);
-        }
-
-        if (LPC_USB->USBEpIntSt & EP(EP2OUT)) {
-            selectEndpointClearInterrupt(EP2OUT);
-            epComplete |= EP(EP2OUT);
-            LPC_USB->USBDevIntClr = EP_SLOW;
-            if (EP2_OUT_callback())
-                epComplete &= ~EP(EP2OUT);
-        }
-
-        if (LPC_USB->USBEpIntSt & EP(EP3IN)) {
-            selectEndpointClearInterrupt(EP3IN);
-            epComplete |= EP(EP3IN);
-            LPC_USB->USBDevIntClr = EP_SLOW;
-            if (EP3_IN_callback())
-                epComplete &= ~EP(EP3IN);
-        }
-
-        if (LPC_USB->USBEpIntSt & EP(EP3OUT)) {
-            selectEndpointClearInterrupt(EP3OUT);
-            epComplete |= EP(EP3OUT);
-            LPC_USB->USBDevIntClr = EP_SLOW;
-            if (EP3_OUT_callback())
-                epComplete &= ~EP(EP3OUT);
+        
+        for (uint8_t num = 2; num < 16*2; num++) {
+            if (LPC_USB->USBEpIntSt & EP(num)) {
+                selectEndpointClearInterrupt(num);
+                epComplete |= EP(num);
+                LPC_USB->USBDevIntClr = EP_SLOW;
+                if ((instance->*(epCallback[num - 2]))()) {
+                    epComplete &= ~EP(num);
+                }
+            }
         }
     }
 }
--- a/USBMSD/USBMSD.cpp	Mon Jan 21 10:41:28 2013 +0000
+++ b/USBMSD/USBMSD.cpp	Fri Mar 01 13:10:29 2013 +0000
@@ -642,4 +642,4 @@
         0                           // bInterval
     };
     return configDescriptor;
-}
\ No newline at end of file
+}
--- a/USBMSD/USBMSD.h	Mon Jan 21 10:41:28 2013 +0000
+++ b/USBMSD/USBMSD.h	Fri Mar 01 13:10:29 2013 +0000
@@ -236,4 +236,4 @@
     void fail();
 };
 
-#endif
\ No newline at end of file
+#endif
--- a/USBSerial/USBCDC.cpp	Mon Jan 21 10:41:28 2013 +0000
+++ b/USBSerial/USBCDC.cpp	Fri Mar 01 13:10:29 2013 +0000
@@ -56,8 +56,7 @@
                 terminal_connected = true;
                 break;
             case CDC_SET_CONTROL_LINE_STATE:
-                if (terminal_connected)
-                    terminal_connected = false;
+                terminal_connected = false;
                 success = true;
                 break;
             default:
@@ -147,12 +146,13 @@
 }
 
 
-#define CONFIG1_DESC_SIZE (9+9+5+5+4+5+7+9+7+7)
+#define CONFIG1_DESC_SIZE (9+8+9+5+5+4+5+7+9+7+7)
 
 uint8_t * USBCDC::configurationDesc() {
     static uint8_t configDescriptor[] = {
-        9,                      // bLength;
-        2,                      // bDescriptorType;
+        // configuration descriptor
+        9,                      // bLength
+        2,                      // bDescriptorType
         LSB(CONFIG1_DESC_SIZE), // wTotalLength
         MSB(CONFIG1_DESC_SIZE),
         2,                      // bNumInterfaces
@@ -160,6 +160,16 @@
         0,                      // iConfiguration
         0x80,                   // bmAttributes
         50,                     // bMaxPower
+        
+        // IAD to associate the two CDC interfaces
+        0x08,                   // bLength
+        0x0b,                   // bDescriptorType
+        0x00,                   // bFirstInterface
+        0x02,                   // bInterfaceCount
+        0x02,                   // bFunctionClass
+        0x02,                   // bFunctionSubClass
+        0,                      // bFunctionProtocol
+        0,                      // iFunction
 
         // interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12
         9,                      // bLength
@@ -211,33 +221,33 @@
 
 
         // interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12
-        9,          // bLength
-        4,          // bDescriptorType
-        1,          // bInterfaceNumber
-        0,          // bAlternateSetting
-        2,          // bNumEndpoints
-        0x0A,       // bInterfaceClass
-        0x00,       // bInterfaceSubClass
-        0x00,       // bInterfaceProtocol
-        0,          // iInterface
+        9,                          // bLength
+        4,                          // bDescriptorType
+        1,                          // bInterfaceNumber
+        0,                          // bAlternateSetting
+        2,                          // bNumEndpoints
+        0x0A,                       // bInterfaceClass
+        0x00,                       // bInterfaceSubClass
+        0x00,                       // bInterfaceProtocol
+        0,                          // iInterface
 
         // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
-        7,                      // bLength
-        5,                      // bDescriptorType
-        PHY_TO_DESC(EPBULK_IN), // bEndpointAddress
-        0x02,                   // bmAttributes (0x02=bulk)
-        LSB(MAX_PACKET_SIZE_EPBULK),    // wMaxPacketSize (LSB)
-        MSB(MAX_PACKET_SIZE_EPBULK),    // wMaxPacketSize (MSB)
-        0,                      // bInterval
+        ENDPOINT_DESCRIPTOR_LENGTH, // bLength
+        ENDPOINT_DESCRIPTOR,        // bDescriptorType
+        PHY_TO_DESC(EPBULK_IN),     // bEndpointAddress
+        E_BULK,                     // bmAttributes (0x02=bulk)
+        LSB(MAX_PACKET_SIZE_EPBULK),// wMaxPacketSize (LSB)
+        MSB(MAX_PACKET_SIZE_EPBULK),// wMaxPacketSize (MSB)
+        0,                          // bInterval
 
         // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
-        7,                      // bLength
-        5,                      // bDescriptorType
-        PHY_TO_DESC(EPBULK_OUT),// bEndpointAddress
-        0x02,                   // bmAttributes (0x02=bulk)
-        LSB(MAX_PACKET_SIZE_EPBULK),    // wMaxPacketSize (LSB)
-        MSB(MAX_PACKET_SIZE_EPBULK),     // wMaxPacketSize (MSB)
-        0                       // bInterval
+        ENDPOINT_DESCRIPTOR_LENGTH, // bLength
+        ENDPOINT_DESCRIPTOR,        // bDescriptorType
+        PHY_TO_DESC(EPBULK_OUT),    // bEndpointAddress
+        E_BULK,                     // bmAttributes (0x02=bulk)
+        LSB(MAX_PACKET_SIZE_EPBULK),// wMaxPacketSize (LSB)
+        MSB(MAX_PACKET_SIZE_EPBULK),// wMaxPacketSize (MSB)
+        0                           // bInterval
     };
     return configDescriptor;
 }