USB host library, support isochronous,bulk,interrupt and control.

Dependents:   BaseUsbHost_example BaseJpegDecode_example SimpleJpegDecode_example

Import programBaseUsbHost_example

BaseUsbHost example program

Files at this revision

API Documentation at this revision

Comitter:
va009039
Date:
Tue Dec 04 13:29:41 2012 +0000
Child:
1:3b7bc4f87a61
Commit message:
first commit

Changed in this revision

BaseUsbHost.cpp Show annotated file Show diff for this revision Revisions of this file
BaseUsbHost.h Show annotated file Show diff for this revision Revisions of this file
BaseUsbHostBlkEp.cpp Show annotated file Show diff for this revision Revisions of this file
BaseUsbHostCtlEp.cpp Show annotated file Show diff for this revision Revisions of this file
BaseUsbHostDebug.cpp Show annotated file Show diff for this revision Revisions of this file
BaseUsbHostDebug.h Show annotated file Show diff for this revision Revisions of this file
BaseUsbHostHub.cpp Show annotated file Show diff for this revision Revisions of this file
BaseUsbHostIntEp.cpp Show annotated file Show diff for this revision Revisions of this file
BaseUsbHostIsoEp.cpp Show annotated file Show diff for this revision Revisions of this file
BaseUsbHostTest.h Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BaseUsbHost.cpp	Tue Dec 04 13:29:41 2012 +0000
@@ -0,0 +1,283 @@
+// BaseUsbHost.cpp 2012/12/4
+#include "mbed.h"
+#include "rtos.h"
+#include "BaseUsbHost.h"
+#define DEBUG
+#include "BaseUsbHostDebug.h"
+#define TEST
+#include "BaseUsbHostTest.h"
+
+// bits of the USB/OTG clock control register
+#define HOST_CLK_EN     (1<<0)
+#define DEV_CLK_EN      (1<<1)
+#define PORTSEL_CLK_EN  (1<<3)
+#define AHB_CLK_EN      (1<<4)
+
+// bits of the USB/OTG clock status register
+#define HOST_CLK_ON     (1<<0)
+#define DEV_CLK_ON      (1<<1)
+#define PORTSEL_CLK_ON  (1<<3)
+#define AHB_CLK_ON      (1<<4)
+
+// we need host clock, OTG/portsel clock and AHB clock
+#define CLOCK_MASK (HOST_CLK_EN | PORTSEL_CLK_EN | AHB_CLK_EN)
+
+#define  FI                     0x2EDF           /* 12000 bits per frame (-1) */
+#define  DEFAULT_FMINTERVAL     ((((6 * (FI - 210)) / 7) << 16) | FI)
+
+static BaseUsbHost* pHost = NULL;
+
+extern "C" void USB_IRQHandler(void) __irq;
+void USB_IRQHandler(void) __irq
+{
+    if (pHost) {
+        pHost->irqHandler();
+    }
+}
+
+inline static void* malloc_align(size_t size, size_t alignment)
+{
+    void* p;
+    int r = posix_memalign(&p, alignment, size);
+    if (r == 0) {
+        return p;
+    }
+    return NULL;
+}
+
+BaseUsbHost::BaseUsbHost()
+{
+    if (pHost) {
+        TEST_ASSERT(pHost == NULL);
+        return;
+    }
+    pHost = this;
+    NVIC_DisableIRQ(USB_IRQn);
+    m_pHcca = reinterpret_cast<HCCA*>(malloc_align(sizeof(HCCA), 256));
+    TEST_ASSERT(m_pHcca);
+    init_hw_ohci(m_pHcca);
+    ResetRootHub();
+    NVIC_SetPriority(USB_IRQn, 0);
+    NVIC_EnableIRQ(USB_IRQn);
+}
+
+void BaseUsbHost::init_hw_ohci(HCCA* pHcca)
+{
+    LPC_SC->PCONP &= ~(1UL<<31);    //Cut power
+    wait(1);
+    LPC_SC->PCONP |= (1UL<<31);     // turn on power for USB
+    LPC_USB->USBClkCtrl |= CLOCK_MASK; // Enable USB host clock, port selection and AHB clock
+    // Wait for clocks to become available
+    while ((LPC_USB->USBClkSt & CLOCK_MASK) != CLOCK_MASK)
+        ;
+    LPC_USB->OTGStCtrl |= 1;
+    LPC_USB->USBClkCtrl &= ~PORTSEL_CLK_EN;
+    
+    LPC_PINCON->PINSEL1 &= ~((3<<26) | (3<<28));  
+    LPC_PINCON->PINSEL1 |=  ((1<<26)|(1<<28));     // 0x14000000
+      
+    DBG("initialize OHCI\n");
+    wait_ms(100);                                   /* Wait 50 ms before apply reset              */
+    TEST_ASSERT((LPC_USB->HcRevision&0xff) == 0x10); // check revision
+    LPC_USB->HcControl       = 0;                       /* HARDWARE RESET                             */
+    LPC_USB->HcControlHeadED = 0;                       /* Initialize Control list head to Zero       */
+    LPC_USB->HcBulkHeadED    = 0;                       /* Initialize Bulk list head to Zero          */
+                                                        /* SOFTWARE RESET                             */
+    LPC_USB->HcCommandStatus = OR_CMD_STATUS_HCR;
+    LPC_USB->HcFmInterval    = DEFAULT_FMINTERVAL;      /* Write Fm Interval and Largest Data Packet Counter */
+    LPC_USB->HcPeriodicStart = FI*90/100;
+                                                      /* Put HC in operational state                */
+    LPC_USB->HcControl  = (LPC_USB->HcControl & (~OR_CONTROL_HCFS)) | OR_CONTROL_HC_OPER;
+    LPC_USB->HcRhStatus = OR_RH_STATUS_LPSC;            /* Set Global Power */
+    TEST_ASSERT(pHcca);
+    for (int i = 0; i < 32; i++) {
+        pHcca->InterruptTable[i] = NULL;
+    }
+    LPC_USB->HcHCCA = (uint32_t)pHcca;
+    LPC_USB->HcInterruptStatus |= LPC_USB->HcInterruptStatus; /* Clear Interrrupt Status */
+
+    //LPC_USB->HcInterruptEnable  = MIE|WDH|RHSC|FNO;
+    LPC_USB->HcInterruptEnable  = OR_INTR_ENABLE_MIE|OR_INTR_ENABLE_WDH|OR_INTR_ENABLE_FNO;
+
+    LPC_USB->HcRhPortStatus1 = OR_RH_PORT_CSC;
+    LPC_USB->HcRhPortStatus1 = OR_RH_PORT_PRSC;
+}
+
+void BaseUsbHost::ResetRootHub()
+{
+    wait_ms(100); /* USB 2.0 spec says at least 50ms delay before port reset */
+    LPC_USB->HcRhPortStatus1 = OR_RH_PORT_PRS; // Initiate port reset
+    DBG("Before loop\n");
+    while (LPC_USB->HcRhPortStatus1 & OR_RH_PORT_PRS)
+      ;
+    LPC_USB->HcRhPortStatus1 = OR_RH_PORT_PRSC; // ...and clear port reset signal
+    DBG("After loop\n");
+    wait_ms(200); /* Wait for 100 MS after port reset  */
+}
+
+HCTD* td_reverse(HCTD* td)
+{
+    HCTD* result = NULL;
+    HCTD* next;
+    while(td) {
+        next = reinterpret_cast<HCTD*>(td->Next);
+        td->Next = reinterpret_cast<uint32_t>(result);
+        result = td;
+        td = next;
+    }
+    return result;
+}
+
+void BaseUsbHost::irqHandler()
+{
+    if (!(LPC_USB->HcInterruptStatus & LPC_USB->HcInterruptEnable)) {
+        return;
+    }
+    m_report_irq++;
+    uint32_t status = LPC_USB->HcInterruptStatus;
+    if (status & OR_INTR_STATUS_FNO) {
+        m_report_FNO++;
+    }
+    if (status & OR_INTR_STATUS_WDH) {
+        uint32_t done_td = m_pHcca->DoneHead;
+        TEST_ASSERT(done_td);
+        m_pHcca->DoneHead = NULL; // reset
+        if (done_td & 1) { // error ?
+            done_td &= ~1;
+        }
+        HCTD* td = td_reverse(reinterpret_cast<HCTD*>(done_td));
+        while(td) {
+            BaseEp* ep = reinterpret_cast<BaseEp*>(td->ep);
+            TEST_ASSERT(ep);
+            ep->irqWdhHandler(td);
+            td = reinterpret_cast<HCTD*>(td->Next);
+        }
+        m_report_WDH++;
+    }
+    LPC_USB->HcInterruptStatus = status; // Clear Interrrupt Status
+}
+
+BaseEp::BaseEp(int addr, uint8_t ep, uint16_t size, int lowSpeed):m_td_queue_count(0)
+{
+    DBG("%p FA=%d EN=%02x MPS=%d S=%d\n", this, addr, ep, size, lowSpeed);
+    m_pED  = reinterpret_cast<HCED*>(malloc_align(sizeof(HCED), 16));
+    TEST_ASSERT(m_pED);
+    TEST_ASSERT(size >= 8 && size <= 1023);    
+    TEST_ASSERT(lowSpeed == 0 || lowSpeed == 1);
+    m_pED->Control =  addr         | /* USB address */
+        ((ep & 0x7F) << 7)         | /* Endpoint address */
+        (ep!=0?(((ep&0x80)?2:1) << 11):0)| /* direction : Out = 1, 2 = In */
+        ((lowSpeed?1:0) << 13)     | /* speed full=0 low=1 */
+        (size << 16);                /* MaxPkt Size */
+    m_pED->Next = NULL;
+}
+
+int BaseEp::GetAddr()
+{
+    HCED* ed = m_pED;
+    TEST_ASSERT(ed);
+    if (ed) {
+        return ed->Control & 0x7f;
+    }
+    return 0;
+}
+
+int BaseEp::GetLowSpeed()
+{
+    HCED* ed = m_pED;
+    TEST_ASSERT(ed);
+    if (ed) {
+        if (ed->Control & (1<<13)) {
+            return 1;
+        }
+    }
+    return 0;
+}
+
+void BaseEp::update_FunctionAddress(int addr)
+{
+    TEST_ASSERT(addr >= 0 && addr <= 127);
+    HCED* ed = m_pED;
+    TEST_ASSERT(ed);
+    ed->Control &= ~0x7f;
+    ed->Control |= addr;
+}
+
+void BaseEp::update_MaxPacketSize(uint16_t size)
+{
+    TEST_ASSERT(size >= 8 && size <= 1023);
+    HCED* ed = m_pED;
+    TEST_ASSERT(ed);
+    ed->Control &= ~0xffff0000;
+    ed->Control |= size<<16;
+}
+
+HCTD* BaseEp::new_HCTD(int buf_size)
+{
+    HCTD* td;
+    int r = posix_memalign(reinterpret_cast<void**>(&td), 16, sizeof(HCTD) + buf_size);
+    if (r == 0) {
+        td->Control = TD_CC|TD_ROUNDING;
+        td->Next = NULL;
+        td->ep = this;
+        td->buf_top = NULL;
+        td->buf_size = buf_size;
+        if (buf_size == 0) {
+            td->CurrBufPtr = NULL;
+            td->BufEnd = NULL;
+        } else {
+            td->CurrBufPtr = td->buf;
+            td->BufEnd = const_cast<uint8_t*>(td->buf)+buf_size-1;
+        }
+        return td;
+    }
+    return NULL;
+}
+
+void BaseEp::delete_HCTD(HCTD* p)
+{
+    free(p);
+}
+
+HCTD* BaseEp::get_queue_HCTD(uint32_t millisec)
+{
+    for(int i = 0; i < 16; i++) {
+        osEvent evt = m_queue.get(millisec);
+        if (evt.status == osEventMessage) {
+            HCTD* td = reinterpret_cast<HCTD*>(evt.value.p);
+            TEST_ASSERT(td);
+            if (td->Control & TD_CC) {
+                m_ConditionCode = td->Control>>28;
+                DBG_TD(td);
+            }
+            return td;
+        } else if (evt.status == osOK) {
+            continue;
+        } else if (evt.status == osEventTimeout) {
+            return NULL;
+        } else {
+            DBG("evt.status: %02x\n", evt.status);
+            TEST_ASSERT(evt.status == osEventMessage);
+        }
+    }
+    return NULL;
+}
+
+int BaseEp::wait_queue_HCTD(HCTD* wait_td, uint32_t millisec)
+{
+    for(int i = 0; i < 16; i++) {
+        HCTD* td = get_queue_HCTD(millisec);
+        if (td) {
+            if (td->Control & TD_CC) {
+                DBG_TD(td);
+                delete_HCTD(td);
+                return USB_ERROR;
+            }
+            delete_HCTD(td);
+            if (td == wait_td) {
+                return USB_OK;
+            }
+        }
+    }
+    return USB_ERROR;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BaseUsbHost.h	Tue Dec 04 13:29:41 2012 +0000
@@ -0,0 +1,222 @@
+// BaseUsbHost.h 2012/12/4
+#ifndef BASE_USB_HOST_H
+#define BASE_USB_HOST_H
+
+#define USB_OK       0
+#define USB_ERROR   -1
+#define USB_TIMEOUT -2
+#define USB_ERROR2  -3
+
+// USB STANDARD REQUEST DEFINITIONS
+#define  USB_DESCRIPTOR_TYPE_DEVICE         1
+#define  USB_DESCRIPTOR_TYPE_CONFIGURATION  2
+#define  USB_DESCRIPTOR_TYPE_STRING         3
+#define  USB_DESCRIPTOR_TYPE_INTERFACE      4
+#define  USB_DESCRIPTOR_TYPE_ENDPOINT       5
+#define  USB_DESCRIPTOR_TYPE_HUB         0x29
+// ----------- Control RequestType Fields  -----------
+#define  USB_DEVICE_TO_HOST      0x80
+#define  USB_HOST_TO_DEVICE      0x00
+#define  USB_REQUEST_TYPE_CLASS  0x20
+#define  USB_RECIPIENT_DEVICE    0x00
+#define  USB_RECIPIENT_INTERFACE 0x01
+#define  USB_RECIPIENT_OTHER     0x03
+// -------------- USB Standard Requests  --------------
+#define  GET_STATUS              0
+#define  CLEAR_FEATURE           1
+#define  SET_FEATURE             3
+#define  SET_ADDRESS             5
+#define  GET_DESCRIPTOR          6
+#define  SET_CONFIGURATION       9
+#define  SET_INTERFACE           11
+// ------------------ HcControl Register ---------------------
+#define  OR_CONTROL_PLE                 0x00000004
+#define  OR_CONTROL_IE                  0x00000008
+#define  OR_CONTROL_CLE                 0x00000010
+#define  OR_CONTROL_BLE                 0x00000020
+#define  OR_CONTROL_HCFS                0x000000C0
+#define  OR_CONTROL_HC_OPER             0x00000080
+// ----------------- HcCommandStatus Register -----------------
+#define  OR_CMD_STATUS_HCR              0x00000001
+#define  OR_CMD_STATUS_CLF              0x00000002
+#define  OR_CMD_STATUS_BLF              0x00000004
+// --------------- HcInterruptStatus Register -----------------
+#define  OR_INTR_STATUS_WDH             0x00000002
+#define  OR_INTR_STATUS_UE              0x00000010
+#define  OR_INTR_STATUS_FNO             0x00000020
+#define  OR_INTR_STATUS_RHSC            0x00000040
+// --------------- HcInterruptEnable Register -----------------
+#define  OR_INTR_ENABLE_WDH             0x00000002
+#define  OR_INTR_ENABLE_FNO             0x00000020
+#define  OR_INTR_ENABLE_RHSC            0x00000040
+#define  OR_INTR_ENABLE_MIE             0x80000000
+// ---------------- HcRhDescriptorA Register ------------------
+#define  OR_RH_STATUS_LPSC              0x00010000
+#define  OR_RH_STATUS_DRWE              0x00008000
+// -------------- HcRhPortStatus[1:NDP] Register --------------
+#define  OR_RH_PORT_CCS                 0x00000001
+#define  OR_RH_PORT_PRS                 0x00000010
+#define  OR_RH_PORT_CSC                 0x00010000
+#define  OR_RH_PORT_PRSC                0x00100000
+
+// TRANSFER DESCRIPTOR CONTROL FIELDS
+#define  TD_ROUNDING     (uint32_t)(0x00040000) /* Buffer Rounding */
+#define  TD_SETUP        (uint32_t)(0x00000000) /* Direction of Setup Packet */
+#define  TD_IN           (uint32_t)(0x00100000) /* Direction In */
+#define  TD_OUT          (uint32_t)(0x00080000) /* Direction Out */
+#define  TD_DELAY_INT(x) (uint32_t)((x) << 21)  /* Delay Interrupt */
+#define  TD_DI           (uint32_t)(7<<21)      /* desable interrupt */
+#define  TD_TOGGLE_0     (uint32_t)(0x02000000) /* Toggle 0 */
+#define  TD_TOGGLE_1     (uint32_t)(0x03000000) /* Toggle 1 */
+#define  TD_CC           (uint32_t)(0xF0000000) /* Completion Code */
+
+typedef struct {    // Host Controller Communication Area
+    uint32_t InterruptTable[32]; // Interrupt Table
+    __IO uint16_t FrameNumber;   // Frame Number
+    __IO uint16_t Pad1;
+    __IO uint32_t DoneHead;      // Done Head
+    uint8_t Reserved[116];       // Reserved for future use
+    uint8_t Unknown[4];          // Unused
+} HCCA;
+
+typedef struct {    // HostController Transfer Descriptor
+    __IO uint32_t  Control;    // +0 Transfer descriptor control
+    __IO uint8_t*  CurrBufPtr; // +4 Physical address of current buffer pointer
+    __IO uint32_t  Next;       // +8 Physical pointer to next Transfer Descriptor
+    uint8_t*  BufEnd;          // +12 Physical address of end of buffer
+    uint8_t* buf_top;          // +16 Buffer start address
+    uint16_t buf_size;         // +20 buffer size size
+    uint8_t setup[8];          // +22 setup cmd area
+    uint8_t _dummy[2];         // +30 dummy
+    void *ep;                  // +32 endpoint object
+    __IO uint8_t buf[0];       // +36 buffer
+} HCTD;                        // +36 
+
+typedef struct {    // HostController Isochronous Transfer Descriptor
+    __IO uint32_t Control;      // +0 Transfer descriptor control
+    uint8_t*  BufferPage0;      // +4 Buffer Page 0
+    __IO uint32_t  Next;        // +8 Physical pointer to next Transfer Descriptor
+    uint8_t*  BufferEnd;        // +12 buffer End
+    __IO uint16_t OffsetPSW[8]; // +16 Offset/PSW
+    void *ep;                   // +32 endpoint object
+    __IO uint8_t buf[0];        // +36 buffer
+} HCITD;                        // +36
+
+typedef struct {    // HostController EndPoint Descriptor
+    __IO uint32_t Control; // +0 Endpoint descriptor control
+    HCTD* TailTd;          // +4 Physical address of tail in Transfer descriptor list
+    __IO HCTD* HeadTd;     // +8 Physcial address of head in Transfer descriptor list
+    uint32_t Next;         // +12 Physical address of next Endpoint descriptor
+} HCED;
+
+#define DELETE_TD(A) free(A)
+#define DELETE_ITD(A) free(A)
+
+class BaseUsbHost {
+public:
+    BaseUsbHost();
+    void init_hw_ohci(HCCA* pHcca);
+    void ResetRootHub();
+    void irqHandler();
+    HCCA* m_pHcca;
+    // report
+    uint32_t m_report_irq; 
+    uint32_t m_report_RHSC;
+    uint32_t m_report_FNO; 
+    uint32_t m_report_WDH;  
+    uint32_t m_report_sp;
+};
+
+#define HCTD_QUEUE_SIZE 3
+
+class BaseEp { // endpoint
+public:
+    BaseEp(int addr, uint8_t ep = 0, uint16_t size = 8, int lowSpeed = 0);
+    int GetAddr();
+    int GetLowSpeed();
+    void update_FunctionAddress(int addr);
+    void update_MaxPacketSize(uint16_t size);
+    //
+    HCTD* new_HCTD(int buf_size=0);
+    void delete_HCTD(HCTD* p);
+    HCED* m_pED;
+    // TD done queue
+    virtual void irqWdhHandler(HCTD* td) = 0; // WDH
+    HCTD* get_queue_HCTD(uint32_t millisec=osWaitForever);
+    int wait_queue_HCTD(HCTD* wait_td, uint32_t millisec=osWaitForever);
+    Queue<HCTD, HCTD_QUEUE_SIZE> m_queue;
+    int m_td_queue_count;
+    // report
+    uint8_t m_ConditionCode;
+    int m_report_queue_error;
+};
+
+class ControlEp : public BaseEp {
+public:
+    ControlEp(int lowSpeed = 0);
+    virtual void irqWdhHandler(HCTD* td) {m_queue.put(td);}
+    int GetDescriptor(int descType, int descIndex, uint8_t* data, int length);
+    int SetAddress(int addr); // device address 
+    int SetConfiguration(int config);
+    int GetConfiguration(int *config);
+    int SetInterfaceAlternate(int interface, int alternate);
+    int GetInterface(int interface, int *alternate);
+    int controlSend(uint8_t bmRequestType, uint8_t bRequest, uint16_t wValue, uint16_t wIndex=0, const uint8_t* data=NULL, int length=0);
+    int controlReceive(uint8_t bmRequestType, uint8_t bRequest, uint16_t wValue, uint16_t wIndex, uint8_t* data, int length);
+    //
+    uint8_t DeviceClass;
+    uint8_t DeviceSubClass;
+    uint8_t DeviceProtocol;
+    //
+    int open(int addr);
+    void setup(HCTD* td, uint8_t bmRequestType, uint8_t bRequest, uint16_t wValue, uint16_t wIndex=0, uint16_t wLength=0);
+};
+
+class BulkEp : public BaseEp {
+public:
+    BulkEp(int addr, uint8_t ep, uint16_t size);
+    virtual void irqWdhHandler(HCTD* td) {m_queue.put(td);}
+    int read(uint8_t* buf, int len, int millisec=osWaitForever);
+    int write(const uint8_t* buf, int len, int millisec=osWaitForever);
+};
+
+class InterruptEp : public BaseEp {
+public:
+    InterruptEp(int addr, uint8_t ep, uint16_t size, int lowSpeed=0);
+    virtual void irqWdhHandler(HCTD* td) {m_queue.put(td);}
+    int read(uint8_t* buf, int len, int millisec=osWaitForever);
+};
+
+class IsochronousEp : public BaseEp {
+public:
+    IsochronousEp(int addr, uint8_t ep, uint16_t size);
+    virtual void irqWdhHandler(HCTD* td);
+    void reset();
+    HCITD* read();
+    HCITD* new_HCITD();
+    HCITD* get_queue_HCITD(uint32_t millisec);
+    int m_itd_queue_count;
+    uint16_t m_FrameNumber;
+    int m_PacketSize; // 128,192
+    int m_FrameCount; // 1-8
+};
+
+#define MAX_HUB_PORT 4
+
+class UsbHub {
+public:
+    UsbHub(ControlEp* ctlEp = NULL);
+    void DeviceConnected(int port, int low_speed);
+    int PortReset(int port);
+    //
+    int SetPortFeature(int feature, int index);
+    int ClearPortFeature(int feature, int index);
+    int SetPortPower(int port);
+    int SetPortReset(int port);
+    int GetPortStatus(int port, uint32_t* status);
+    ControlEp* m_ctlEp;
+    ControlEp* PortEp[MAX_HUB_PORT]; // port endpoint(control) 
+};
+
+
+#endif //BASE_USB_HOST_H
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BaseUsbHostBlkEp.cpp	Tue Dec 04 13:29:41 2012 +0000
@@ -0,0 +1,88 @@
+// BaseUsbHostBlkEp.cpp 2012/12/3
+#include "mbed.h"
+#include "rtos.h"
+#include "BaseUsbHost.h"
+//#define DEBUG
+#include "BaseUsbHostDebug.h"
+#define TEST
+#include "BaseUsbHostTest.h"
+
+BulkEp::BulkEp(int addr, uint8_t ep, uint16_t size): BaseEp(addr, ep, size)
+{
+    HCTD* td = new_HCTD();
+    TEST_ASSERT(td);
+    m_pED->TailTd = td;
+    m_pED->HeadTd = td; 
+
+    m_pED->Next = LPC_USB->HcBulkHeadED;
+    LPC_USB->HcBulkHeadED = reinterpret_cast<uint32_t>(m_pED);
+    
+    DBG_OHCI(LPC_USB->HcBulkHeadED);
+    DBG_ED(m_pED);
+
+    LPC_USB->HcCommandStatus |= OR_CMD_STATUS_BLF;
+    LPC_USB->HcControl |= OR_CONTROL_BLE;
+}
+
+int BulkEp::read(uint8_t* buf, int len, int millisec)
+{
+    HCTD* data_td = m_pED->TailTd;
+    TEST_ASSERT(data_td);
+    data_td->Control |= TD_IN;
+    data_td->CurrBufPtr = buf;
+    data_td->BufEnd = const_cast<uint8_t*>(buf)+len-1;
+    HCTD* blank_td = new_HCTD();
+    TEST_ASSERT(blank_td);
+    data_td->Next = reinterpret_cast<uint32_t>(blank_td);
+    m_pED->TailTd = blank_td;
+    m_td_queue_count++;
+    DBG_ED(m_pED);
+
+    LPC_USB->HcCommandStatus |= OR_CMD_STATUS_BLF;
+    LPC_USB->HcControl |= OR_CONTROL_BLE;
+ 
+    HCTD* td = get_queue_HCTD(millisec);
+    if (td) {
+        DBG_TD(td);
+        int ret = len;
+        if (td->CurrBufPtr) {
+            ret = td->CurrBufPtr - buf;
+        }
+        delete_HCTD(td); 
+        m_td_queue_count--;
+        return ret;
+    }
+    return USB_ERROR;
+}
+
+int BulkEp::write(const uint8_t* buf, int len, int millisec)
+{
+    HCTD* data_td = m_pED->TailTd;
+    TEST_ASSERT(data_td);
+    data_td->Control |= TD_OUT;
+    data_td->CurrBufPtr = const_cast<uint8_t*>(buf);
+    data_td->BufEnd = const_cast<uint8_t*>(buf)+len-1;
+    HCTD* blank_td = new_HCTD();
+    TEST_ASSERT(blank_td);
+    data_td->Next = reinterpret_cast<uint32_t>(blank_td);
+    m_pED->TailTd = blank_td;
+    m_td_queue_count++;
+    DBG_ED(m_pED);
+    
+    LPC_USB->HcCommandStatus |= OR_CMD_STATUS_BLF;
+    LPC_USB->HcControl |= OR_CONTROL_BLE;
+ 
+    HCTD* td = get_queue_HCTD(millisec);
+    if (td) {
+        DBG_TD(td);
+        int ret = len;
+        if (td->CurrBufPtr) {
+            ret = td->CurrBufPtr - buf;
+        }
+        delete_HCTD(td); 
+        m_td_queue_count--;
+        return ret;
+    }
+    return USB_ERROR;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BaseUsbHostCtlEp.cpp	Tue Dec 04 13:29:41 2012 +0000
@@ -0,0 +1,189 @@
+// BaseUsbHostCtlEp.cpp 2012/12/4
+#include "mbed.h"
+#include "rtos.h"
+#include "BaseUsbHost.h"
+#define DEBUG
+#include "BaseUsbHostDebug.h"
+#define TEST
+#include "BaseUsbHostTest.h"
+
+static uint8_t device_addr = 1;
+ControlEp::ControlEp(int lowSpeed):BaseEp(0, 0, 8, lowSpeed)
+{
+    TEST_ASSERT(HCTD_QUEUE_SIZE >= 3);
+    HCTD* td = new_HCTD();
+    TEST_ASSERT(td);
+    m_pED->TailTd = td;
+    m_pED->HeadTd = td; 
+    
+    m_pED->Next = LPC_USB->HcControlHeadED;
+    LPC_USB->HcControlHeadED = reinterpret_cast<uint32_t>(m_pED);
+
+    DBG_OHCI(LPC_USB->HcControlHeadED);
+    DBG_ED(m_pED);
+
+    int r = open(device_addr);
+    if (r == USB_OK) {
+        device_addr++;
+    }
+}
+
+int ControlEp::SetAddress(int addr)
+{
+    return controlSend(0x00, 5, addr);
+}
+
+int ControlEp::GetDescriptor(int descType, int descIndex, uint8_t* data, int length)
+{
+    return controlReceive(0x80, 6, (descType<<8)|descIndex, 0, data, length);
+}
+
+int ControlEp::SetConfiguration(int config)
+{
+    return controlSend(0x00, 9, config);
+}
+
+int ControlEp::GetConfiguration(int *config)
+{
+    uint8_t buf[1];
+    int rc = controlReceive(0x80, 8, 0, 0, buf, 1);
+    *config = buf[0];
+    return rc;
+}
+
+int ControlEp::SetInterfaceAlternate(int interface, int alternate)
+{
+    int rc = controlSend(USB_HOST_TO_DEVICE | USB_RECIPIENT_INTERFACE, 
+                     SET_INTERFACE, alternate, interface, NULL, 0);
+    return rc;
+}
+
+int ControlEp::GetInterface(int interface, int *alternate)
+{
+    uint8_t buf[1];
+    int rc = controlReceive(0x81, 10, 0, interface, buf, 1);
+    *alternate = buf[0];
+    return rc;
+}
+
+int ControlEp::open(int addr)
+{
+    TEST_ASSERT(addr >= 1 && addr <= 127);
+    uint8_t buf[8];
+    int r = GetDescriptor(1, 0, buf, 8);
+    TEST_ASSERT(r == USB_OK);
+    if (r != USB_OK) {
+        return r;
+    }
+    TEST_ASSERT(buf[0] == 0x12);
+    TEST_ASSERT(buf[1] == 0x01);
+    TEST_ASSERT(buf[7] >= 8);
+    DeviceClass = buf[3];
+    DeviceSubClass = buf[4];
+    DeviceProtocol = buf[5];
+    DBG("DeviceClass: %02X\n", DeviceClass);
+    DBG("DeviceSubClass: %02X\n", DeviceSubClass);
+    DBG("DeviceProtocol: %02X\n", DeviceProtocol);
+    update_MaxPacketSize(buf[7]);
+    r = SetAddress(addr);    
+    TEST_ASSERT(r == USB_OK);
+    if (r != USB_OK) {
+        return r;
+    }
+    wait_ms(2);
+    update_FunctionAddress(addr);
+    return USB_OK;
+}
+
+int ControlEp::controlReceive(uint8_t bmRequestType, uint8_t bRequest, uint16_t wValue, uint16_t wIndex,
+                     uint8_t* data, int length) {
+    DBG("Type: %02X Request: %02X Value: %04X Index: %04X %p %d\n", bmRequestType, bRequest, wValue, wIndex, data, length);
+    HCTD* setup_td = m_pED->TailTd;
+    setup(setup_td, bmRequestType, bRequest, wValue, wIndex, length);
+    setup_td->Control |= TD_DI;
+
+    HCTD* data_td = new_HCTD(length);
+    TEST_ASSERT(data_td);
+    data_td->Control |= TD_TOGGLE_1|TD_IN|TD_DI; 
+    //data_td->Control |= TD_IN|TD_DI; 
+    setup_td->Next = reinterpret_cast<uint32_t>(data_td);
+
+    HCTD* status_td = new_HCTD();
+    TEST_ASSERT(status_td);
+    status_td->Control |= TD_TOGGLE_1|TD_OUT; // OUT(DATA1)
+    data_td->Next = reinterpret_cast<uint32_t>(status_td);
+
+    HCTD* blank_td = new_HCTD();
+    TEST_ASSERT(blank_td);
+    status_td->Next = reinterpret_cast<uint32_t>(blank_td);
+    m_pED->TailTd = blank_td;
+
+    LPC_USB->HcCommandStatus |= OR_CMD_STATUS_CLF;
+    LPC_USB->HcControl |= OR_CONTROL_CLE;
+
+    int r = wait_queue_HCTD(setup_td, 100); // wait setup stage
+    TEST_ASSERT(r == USB_OK);
+    HCTD* td = get_queue_HCTD(100);
+    if (td == data_td) {
+        memcpy(data, const_cast<uint8_t*>(td->buf), length);
+        delete_HCTD(td);
+    } else {
+        DBG_TD(td);
+        TEST_ASSERT(td == data_td);
+        return USB_ERROR;
+    }
+    r = wait_queue_HCTD(status_td, 100); // wait status stage
+    TEST_ASSERT(r == USB_OK);
+    return r;
+}
+
+int ControlEp::controlSend(uint8_t bmRequestType, uint8_t bRequest, uint16_t wValue, uint16_t wIndex,
+                     const uint8_t* data, int length) {
+    DBG("Type: %02X Request: %02X Value: %04X Index: %04X %p %d\n", bmRequestType, bRequest, wValue, wIndex, data, length);
+    HCTD* setup_td = m_pED->TailTd;
+    setup(setup_td, bmRequestType, bRequest, wValue, wIndex, length);
+
+    HCTD* status_td = new_HCTD();
+    TEST_ASSERT(status_td);
+    HCTD* blank_td = new_HCTD();
+    TEST_ASSERT(blank_td);
+    setup_td->Control |= TD_DI;
+    status_td->Control |= TD_TOGGLE_1|TD_IN; // IN(DATA1)
+    setup_td->Next = reinterpret_cast<uint32_t>(status_td);
+    status_td->Next = reinterpret_cast<uint32_t>(blank_td);
+
+    if (length != 0) {
+        HCTD* data_td = new_HCTD(length);
+        TEST_ASSERT(data_td);
+        data_td->Control |= TD_TOGGLE_1|TD_OUT|TD_DI; 
+        memcpy(const_cast<uint8_t*>(data_td->buf), data, length);
+        setup_td->Next = reinterpret_cast<uint32_t>(data_td);
+        data_td->Next = reinterpret_cast<uint32_t>(status_td);
+    }
+    m_pED->TailTd = blank_td;
+    DBG_ED(m_pED);
+
+    LPC_USB->HcCommandStatus |= OR_CMD_STATUS_CLF;
+    LPC_USB->HcControl |= OR_CONTROL_CLE;
+    
+    int r = wait_queue_HCTD(status_td, 200); // wait status stage
+    TEST_ASSERT(r == USB_OK);
+    return r;
+}
+
+void ControlEp::setup(HCTD* td, uint8_t bmRequestType, uint8_t bRequest, uint16_t wValue, 
+                      uint16_t wIndex, uint16_t wLength)
+{
+    td->setup[0] = bmRequestType;
+    td->setup[1] = bRequest;
+    td->setup[2] = wValue;
+    td->setup[3] = wValue>>8;
+    td->setup[4] = wIndex;
+    td->setup[5] = wIndex>>8;
+    td->setup[6] = wLength;
+    td->setup[7] = wLength>>8;
+    td->Control |= TD_TOGGLE_0|TD_SETUP; 
+    td->CurrBufPtr = td->setup;
+    td->BufEnd = td->setup+8-1;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BaseUsbHostDebug.cpp	Tue Dec 04 13:29:41 2012 +0000
@@ -0,0 +1,104 @@
+// BaseUseHostDebug.cpp 2012/12/4
+#include "mbed.h"
+#include "rtos.h"
+#include "BaseUsbHost.h"
+#include "BaseUsbHostDebug.h"
+
+#define OHCI_REG_READ(REG)     (LPC_USB->##REG)
+#define OHCI_REG_WRITE(REG,B) LPC_USB->##REG = (B)
+#define OHCI_REG_OR(REG,B)    LPC_USB->##REG |= (B)
+#define OHCI_REG_AND(REG,B)   LPC_USB->##REG &= (B)
+
+void print_td(FILE* stream, HCTD* td)
+{
+    if (td == NULL) {
+        fprintf(stream, "TD %p:\n", td);
+        return;
+    }
+    uint32_t* p = reinterpret_cast<uint32_t*>(td);
+    fprintf(stream, "TD %p: %08X %08X %08X %08X", p, p[0], p[1], p[2], p[3]);
+    fprintf(stream, " ep=%p", td->ep);
+    for(int i = 0; i < 8; i++) {
+        fprintf(stream, " %02X", td->buf[i]);
+    }
+    fprintf(stream, "\n");
+    uint8_t* bp = reinterpret_cast<uint8_t*>(p[1]);
+    uint8_t* be = reinterpret_cast<uint8_t*>(p[3]);
+    if (bp) {
+        fprintf(stream, "BF %p:", bp);
+        while(bp <= be) {
+            fprintf(stream, " %02X", *bp);
+            bp++;
+        }
+        fprintf(stream, "\n");
+    } 
+}
+
+void print_ed(FILE* stream, HCED* ed)
+{
+    uint32_t* p = reinterpret_cast<uint32_t*>(ed);
+    while(p) {
+        fprintf(stream, "ED %p: %08X %08X %08X %08X\n", p, p[0], p[1], p[2], p[3]);
+        HCTD* td = reinterpret_cast<HCTD*>(p[2] & ~3);
+        HCTD* tdtail = reinterpret_cast<HCTD*>(p[1]);
+        while(td != NULL && td != tdtail) {
+            print_td(stream, td);
+            td = reinterpret_cast<HCTD*>(td->Next);
+        }
+        p = reinterpret_cast<uint32_t*>(p[3]);
+    }
+}
+
+void print_itd(FILE* stream, HCITD* itd)
+{
+    if (itd == NULL) {
+        fprintf(stream, "ITD %p:\n", itd);
+        return;
+    }
+    uint32_t* p = reinterpret_cast<uint32_t*>(itd);
+    fprintf(stream, "ITD %p: %08X %08X %08X %08X", p, p[0], p[1], p[2], p[3]);
+    fprintf(stream, " ep=%p\n", itd->ep);
+    uint16_t* offset = reinterpret_cast<uint16_t*>(p+4);
+    fprintf(stream, "ITD %p: %04X %04X %04X %04X %04X %04X %04X %04X\n", offset, 
+        offset[0], offset[1], offset[2], offset[3], offset[4], offset[5], offset[6], offset[7]);
+}
+
+void print_ied(FILE* stream, HCED* ed)
+{
+    uint32_t* p = reinterpret_cast<uint32_t*>(ed);
+    while(p) {
+        fprintf(stream, "ED %p: %08X %08X %08X %08X\n", p, p[0], p[1], p[2], p[3]);
+        HCITD* itd = reinterpret_cast<HCITD*>(p[2] & ~3);
+        HCITD* itdtail = reinterpret_cast<HCITD*>(p[1]);
+        while(itd != NULL && itd != itdtail) {
+            print_itd(stream, itd);
+            itd = reinterpret_cast<HCITD*>(itd->Next);
+        }
+        p = reinterpret_cast<uint32_t*>(p[3]);
+    }
+}
+
+void print_bytes(FILE* stream, char* s, uint8_t* buf, int len)
+{
+    fprintf(stream, "%s %d:", s, len);
+    for(int i = 0; i < len; i++) {
+        fprintf(stream, " %02X", buf[i]);
+    }
+    fprintf(stream, "\n");
+}
+
+void print_hex(FILE* stream, uint8_t* p, int len)
+{
+    for(int i = 0; i < len; i++) {
+        if (i%16 == 0) {
+            fprintf(stream, "%p:", p);
+        }
+        fprintf(stream, " %02X", *p);
+        p++;
+        if (i%16 == 15) {
+            fprintf(stream, "\n");
+        }
+    }
+    fprintf(stream, "\n");
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BaseUsbHostDebug.h	Tue Dec 04 13:29:41 2012 +0000
@@ -0,0 +1,33 @@
+// BaseUsbHostDebug.h 2012/12/2
+#ifndef BASE_USB_HOST_DEBUG_H
+#define BASE_USB_HOST_DEBUG_H
+#ifdef DEBUG
+#define DBG(...) do{fprintf(stderr,"[%s@%d] ",__PRETTY_FUNCTION__,__LINE__);fprintf(stderr,__VA_ARGS__);} while(0);
+#define DBG_PRINTF(...) do{fprintf(stderr,__VA_ARGS__);}while(0);
+#define DBG_TD(A) do{fprintf(stderr,"[%s@%d]\n",__PRETTY_FUNCTION__,__LINE__);print_td(stderr,A);}while(0);
+#define DBG_ED(A) do{fprintf(stderr,"[%s@%d]\n",__PRETTY_FUNCTION__,__LINE__);print_ed(stderr,A);}while(0);
+#define DBG_ITD(A) do{fprintf(stderr,"[%s@%d]\n",__PRETTY_FUNCTION__,__LINE__);print_itd(stderr,A);}while(0);
+#define DBG_IED(A) do{fprintf(stderr,"[%s@%d]\n",__PRETTY_FUNCTION__,__LINE__);print_ied(stderr,A);}while(0);
+#define DBG_BYTES(A,B,C) do{fprintf(stderr,"[%s@%d] ",__PRETTY_FUNCTION__,__LINE__);print_bytes(stderr,A,B,C);}while(0);
+#define DBG_HEX(A,B) do{fprintf(stderr,"[%s@%d]\n",__PRETTY_FUNCTION__,__LINE__);print_hex(stderr,A,B);}while(0);
+#define DBG_OHCI(A) do{fprintf(stderr,"[%s@%d] %s: %08X\n",__PRETTY_FUNCTION__,__LINE__,#A,A);}while(0);
+#else //DEBUG
+#define DBG(...)  while(0);
+#define DBG_PRINTF(...) while(0);
+#define DBG_TD(A) while(0);
+#define DBG_ED(A) while(0);
+#define DBG_ITD(A) while(0);
+#define DBG_IED(A) while(0);
+#define DBG_BYTES(A,B,C) while(0);
+#define DBG_HEX(A,B) while(0);
+#define DBG_OHCI(A) while(0);
+#endif //DEBUG
+
+void print_td(FILE* stream, HCTD* td);
+void print_ed(FILE* stream, HCED* ed);
+void print_itd(FILE* stream, HCITD* itd);
+void print_ied(FILE* stream, HCED* ed);
+void print_bytes(FILE* stream, char* s, uint8_t* buf, int len);
+void print_hex(FILE* stream, uint8_t* p, int len);
+
+#endif //BASE_USB_HOST_DEBUG_H
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BaseUsbHostHub.cpp	Tue Dec 04 13:29:41 2012 +0000
@@ -0,0 +1,135 @@
+// BaseUsbHostHub.cpp 2012/12/4
+#include "mbed.h"
+#include "rtos.h"
+#include "BaseUsbHost.h"
+#define DEBUG
+#include "BaseUsbHostDebug.h"
+#define TEST
+#include "BaseUsbHostTest.h"
+
+#define PORT_CONNECTION 0
+#define PORT_ENABLE  1
+#define PORT_SUSPEND  2
+#define PORT_OVER_CURRENT 3
+#define PORT_RESET 4
+#define PORT_POWER 8
+#define PORT_LOW_SPEED 9
+
+#define C_PORT_CONNECTION 16
+#define C_PORT_ENABLE 17
+#define C_PORT_SUSPEND 18
+#define C_PORT_OVER_CURRENT 19
+#define C_PORT_RESET 20
+
+int UsbHub::SetPortFeature(int feature, int index)
+{
+    return m_ctlEp->controlSend(0x23, SET_FEATURE,feature,index,0,0);
+}
+
+int UsbHub::ClearPortFeature(int feature, int index)
+{
+    return m_ctlEp->controlSend(0x23, CLEAR_FEATURE,feature,index,0,0);
+}
+
+int UsbHub::SetPortPower(int port)
+{
+    return SetPortFeature(PORT_POWER, port);
+}
+
+int UsbHub::SetPortReset(int port)
+{
+    return SetPortFeature(PORT_RESET, port);
+}
+
+int UsbHub::GetPortStatus(int port, uint32_t* status)
+{
+    return m_ctlEp->controlReceive(0xa3, GET_STATUS, 0, port, (uint8_t*)status, 4);
+}
+
+UsbHub::UsbHub(ControlEp* ctlEp)
+{
+    for(int i = 0; i < MAX_HUB_PORT; i++) {
+        PortEp[i] = NULL;
+    }
+    
+    if (ctlEp == NULL) {
+        DBG_OHCI(LPC_USB->HcRhPortStatus1);
+        int lowSpeed = 0;
+        if (LPC_USB->HcRhPortStatus1 & 0x200) {
+            lowSpeed = 1;
+        }
+        m_ctlEp = new ControlEp(lowSpeed);
+        TEST_ASSERT_TRUE(m_ctlEp);
+    } else {
+        m_ctlEp = ctlEp;
+    }
+    uint8_t desc[9];
+    m_ctlEp->GetDescriptor(1, 0, desc, sizeof(desc));
+    DBG_HEX(desc, sizeof(desc));
+    TEST_ASSERT_TRUE(desc[0] == 0x12);
+    TEST_ASSERT_TRUE(desc[1] == 0x01);
+    TEST_ASSERT_TRUE(desc[4] == 0x09); // hub
+    if (desc[4] != 0x09) { // hub ?
+        return;
+    }
+
+    m_ctlEp->controlReceive(0xa0, 6, 0x29<<8, 0, desc, sizeof(desc));
+    DBG_HEX(desc, sizeof(desc));
+    TEST_ASSERT_TRUE(desc[0] == 9); // length
+    TEST_ASSERT_TRUE(desc[1] == 0x29); // hub
+    int bNbrPorts = desc[2];
+    TEST_ASSERT_TRUE(bNbrPorts <= MAX_HUB_PORT);
+    m_ctlEp->SetConfiguration(1);
+
+    uint32_t status;
+    m_ctlEp->controlReceive(0xa0, 0, 0, 0, (uint8_t*)&status, 4);
+    DBG("HUB STATUS: %08X\n", status);
+
+    for(int i = 1; i <= bNbrPorts; i++) {
+        SetPortFeature(PORT_POWER, i); // power on
+    }
+
+    for(int i = 1; i <= bNbrPorts; i++) {
+        uint32_t status;
+        GetPortStatus(i, &status);
+        DBG("port: %d status: %08X\n", i, status);
+        if (status & 0x010000) { // Connect Status Change, has changed
+            TEST_ASSERT(status & 0x000001);
+            ClearPortFeature(C_PORT_CONNECTION, i);
+            bool low_speed = false;
+            if (status & 0x0200) {
+                low_speed = true;
+            }
+            DeviceConnected(i, low_speed);
+        }
+    }
+}
+
+void UsbHub::DeviceConnected(int port, int low_speed)
+{
+    DBG("port=%d low_speed=%d\n", port, low_speed);
+    PortReset(port);
+    ControlEp* ctlEp = new ControlEp(low_speed);
+    TEST_ASSERT_TRUE(ctlEp);
+ 
+    PortEp[port-1] = ctlEp;
+    DBG("PortEp[%d]: %p\n", port-1, PortEp[port-1]);
+}
+
+int UsbHub::PortReset(int port)
+{
+    DBG("%p port=%d\n", this, port);
+    TEST_ASSERT(port >= 1);
+    SetPortReset(port);
+    // wait reset
+    for(int i = 0; i < 100; i++) {
+        uint32_t status;    
+        GetPortStatus(port, &status);
+        DBG("RESET port: %d status: %08X\n", port, status);
+        if (status & 0x100000) { // Reset change , Reset complete
+            return USB_OK;
+        }
+        wait_ms(5);
+     }
+     return USB_ERROR;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BaseUsbHostIntEp.cpp	Tue Dec 04 13:29:41 2012 +0000
@@ -0,0 +1,55 @@
+// BaseUsbHostIntEp.cpp 2012/12/4
+#include "mbed.h"
+#include "rtos.h"
+#include "BaseUsbHost.h"
+#define DEBUG
+#include "BaseUsbHostDebug.h"
+#define TEST
+#include "BaseUsbHostTest.h"
+
+InterruptEp::InterruptEp(int addr, uint8_t ep, uint16_t size, int lowSpeed)
+    :BaseEp(addr, ep, size, lowSpeed)
+{
+    HCTD* td = new_HCTD();
+    TEST_ASSERT(td);
+    m_pED->TailTd = td;
+    m_pED->HeadTd = td; 
+
+    HCCA* pHcca = reinterpret_cast<HCCA*>(LPC_USB->HcHCCA);
+    TEST_ASSERT(pHcca);
+    int n = 0;
+    m_pED->Next = pHcca->InterruptTable[n];
+    pHcca->InterruptTable[n] = reinterpret_cast<uint32_t>(m_pED);
+    LPC_USB->HcControl |= OR_CONTROL_PLE;
+}
+    
+int InterruptEp::read(uint8_t* buf, int len, int millisec)
+{
+    if (m_td_queue_count == 0) {
+        HCTD* data_td = m_pED->TailTd;
+        TEST_ASSERT(data_td);
+        data_td->Control |= TD_IN;
+        data_td->CurrBufPtr = buf;
+        data_td->BufEnd = const_cast<uint8_t*>(buf)+len-1;
+        HCTD* blank_td = new_HCTD();
+        TEST_ASSERT(blank_td);
+        data_td->Next = reinterpret_cast<uint32_t>(blank_td);
+        m_pED->TailTd = blank_td;
+        m_td_queue_count++;
+        DBG_ED(m_pED);
+        LPC_USB->HcControl |= OR_CONTROL_PLE; // Enable Periodic
+    }
+        
+    HCTD* td = get_queue_HCTD(millisec);
+    if (td) {
+        DBG_TD(td);
+        int ret = len;
+        if (td->CurrBufPtr) {
+            ret = td->CurrBufPtr - buf;
+        }
+        delete_HCTD(td); 
+        m_td_queue_count--;
+        return ret;
+    }
+    return USB_TIMEOUT;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BaseUsbHostIsoEp.cpp	Tue Dec 04 13:29:41 2012 +0000
@@ -0,0 +1,134 @@
+// BaseUsbHostIsoEp.cpp 2012/12/4
+#include "mbed.h"
+#include "rtos.h"
+#include "BaseUsbHost.h"
+#define DEBUG
+#include "BaseUsbHostDebug.h"
+#define TEST
+#include "BaseUsbHostTest.h"
+
+IsochronousEp::IsochronousEp(int addr, uint8_t ep, uint16_t size):BaseEp(addr, ep, size)
+{
+    DBG("%p FA:%d EP:%02X MPS:%d\n", this, addr, ep, size);
+    TEST_ASSERT(m_pED);
+    
+    m_pED->Control |= (1 << 15); // F Format ITD
+
+    TEST_ASSERT(size >= 128 && size <= 1023);
+    m_PacketSize = size;
+    m_FrameCount = 8;
+    m_itd_queue_count = 0;
+    reset();
+    HCITD* itd = new_HCITD();
+    TEST_ASSERT(itd);
+    m_pED->TailTd = reinterpret_cast<HCTD*>(itd);
+    m_pED->HeadTd = reinterpret_cast<HCTD*>(itd); 
+
+    HCCA* hcca = reinterpret_cast<HCCA*>(LPC_USB->HcHCCA);
+    TEST_ASSERT(hcca);
+    for(int i = 0; i < 32; i++) {
+        if (hcca->InterruptTable[i] == 0) {
+            hcca->InterruptTable[i] = reinterpret_cast<uint32_t>(m_pED);
+        } else {
+            HCED* nextEd = reinterpret_cast<HCED*>(hcca->InterruptTable[i]);
+            while(nextEd->Next && nextEd->Next != reinterpret_cast<uint32_t>(m_pED)) {
+                nextEd = reinterpret_cast<HCED*>(nextEd->Next);
+            }
+            nextEd->Next = reinterpret_cast<uint32_t>(m_pED);
+        }
+    }
+    DBG_ED(m_pED);
+}
+
+void IsochronousEp::reset()
+{
+    m_FrameNumber = LPC_USB->HcFmNumber + 100; // 100msec
+}
+
+void IsochronousEp::irqWdhHandler(HCTD* td)
+{
+    osStatus st = m_queue.put(td);
+    if (st != osOK) {
+        //led4_error = 1;
+    }
+    //led2 = !led2;
+}
+
+HCITD* IsochronousEp::new_HCITD()
+{
+    HCITD* itd;
+    int r = posix_memalign(reinterpret_cast<void**>(&itd), 32, sizeof(HCITD)+m_PacketSize*m_FrameCount);
+    if (r != 0) {
+        return NULL;
+    } 
+    int di = 0; //DelayInterrupt
+    itd->Control = 0xe0000000            | // CC ConditionCode NOT ACCESSED
+                 ((m_FrameCount-1) << 24)| // FC FrameCount
+                       TD_DELAY_INT(di)  | // DI DelayInterrupt
+                     m_FrameNumber;        // SF StartingFrame
+    itd->BufferPage0 = const_cast<uint8_t*>(itd->buf);
+    itd->BufferEnd = const_cast<uint8_t*>(itd->buf) + m_PacketSize * m_FrameCount - 1;
+    itd->Next = NULL; 
+    itd->ep = this;
+    uint32_t addr = reinterpret_cast<uint32_t>(itd->buf);
+    for(int i = 0; i < m_FrameCount; i++) {
+        uint16_t offset = addr & 0x0fff;
+        if ((addr&0xfffff000) == (reinterpret_cast<uint32_t>(itd->BufferEnd)&0xfffff000)) {
+            offset |= 0x1000;
+        }
+        itd->OffsetPSW[i] = 0xe000|offset;
+        addr += m_PacketSize;
+    }
+    m_FrameNumber += m_FrameCount;
+    return itd;
+}
+
+
+HCITD* IsochronousEp::read()
+{
+    TEST_ASSERT(m_itd_queue_count >= 0);
+    while(m_itd_queue_count < HCTD_QUEUE_SIZE) {
+        HCITD* itd = reinterpret_cast<HCITD*>(m_pED->TailTd);
+        TEST_ASSERT(itd);
+        //DBG_ITD(itd);
+        HCITD* blank_itd = new_HCITD();
+        TEST_ASSERT(blank_itd);
+        itd->Next = reinterpret_cast<uint32_t>(blank_itd);
+        m_pED->TailTd = reinterpret_cast<HCTD*>(blank_itd);
+        m_itd_queue_count++;
+        //DBG_IED(m_pED);
+        LPC_USB->HcControl |= OR_CONTROL_PLE; // Enable Periodic
+    }
+    
+    HCITD* itd = get_queue_HCITD(1);
+    if (itd) {
+        m_itd_queue_count--;
+    }
+    return itd;
+}
+
+HCITD* IsochronousEp::get_queue_HCITD(uint32_t millisec)
+{
+    for(int i = 0; i < 16; i++) {
+        osEvent evt = m_queue.get(millisec);
+        if (evt.status == osEventMessage) {
+            HCITD* itd = reinterpret_cast<HCITD*>(evt.value.p);
+            TEST_ASSERT(itd);
+            //led3 = !led3;
+            uint8_t cc = itd->Control>>28;
+            if (cc != 0) {
+                m_ConditionCode = cc;
+            }
+            return itd;
+        } else if (evt.status == osOK) {
+            continue;
+        } else if (evt.status == osEventTimeout) {
+            return NULL;
+        } else {
+            DBG("evt.status: %02x\n", evt.status);
+            TEST_ASSERT(evt.status == osEventMessage);
+        }
+    }
+    return NULL;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BaseUsbHostTest.h	Tue Dec 04 13:29:41 2012 +0000
@@ -0,0 +1,15 @@
+// BaseUsbHostTest.h 2012/12/2
+#ifndef BASE_USB_HOST_TEST_H
+#define BASE_USB_HOST_TEST_H
+#ifdef TEST
+#define TEST_ASSERT(A) while(!(A)){fprintf(stderr,"\n\n%s@%d %s ASSERT!\n\n",__PRETTY_FUNCTION__,__LINE__,#A);exit(1);};
+#define TEST_ASSERT_TRUE(A) while(!(A)){fprintf(stderr,"\n\n%s@%d %s ASSERT!\n\n",__PRETTY_FUNCTION__,__LINE__,#A);exit(1);};
+#define TEST_ASSERT_FALSE(A) while((A)){fprintf(stderr,"\n\n%s@%d %s ASSERT!\n\n",__PRETTY_FUNCTION__,__LINE__,#A);exit(1);};
+#define TEST_ASSERT_EQUAL(A,B) while(!(A == B)){fprintf(stderr,"\n\n%s@%d %s ASSERT!\n\n",__PRETTY_FUNCTION__,__LINE__,#A);exit(1);};
+#else
+#define TEST_ASSERT(A)
+#define TEST_ASSERT_TRUE(A) while(0);
+#define TEST_ASSERT_FALSE(A) while(0);
+#define TEST_ASSERT_EQUAL(A,B) while(0);
+#endif
+#endif // BASE_USB_HOST_TEST_H