Simple USBHost library for Nucleo F446RE/F411RE/F401RE FRDM-KL46Z/KL25Z/F64F LPC4088/LPC1768

Dependencies:   FATFileSystem

Dependents:   F401RE-BTstack_example F401RE-USBHostMSD_HelloWorld

Fork of KL46Z-USBHost by Norimasa Okamoto

簡易USBホストライブラリです。
official-USBHostの下位互換で対応プログラムを僅かな修正で動かすことが出来ます。

Platforms

  • Nucleo F446RE
  • Nucleo F411RE
  • Nucleo F401RE
  • FRDM-K64F
  • FRDM-KL46Z
  • FRDM-KL25Z
  • LPC4088
  • LPC1768

Nucleo F446RE/F411RE/F401REのUSB接続方法

ST morphoUSB
U5V (CN10-8)VBUS (1 RED)
PA11 (CN10-14)DM  (2 WHITE)
PA12 (CN10-12)DP  (3 GREEN)
GND (CN10-20)GND (4 BLACK)

Examples

Import programF446RE-USBHostMouse_HelloWorld

USBHostMouse Hello World for ST-Nucleo-F446RE

Import programF401RE-USBHostMSD_HelloWorld

Simple USBHost MSD(USB flash drive) for Nucleo F401RE/FRDM-KL46Z test program

Import programF401RE-USBHostC270_example

Simple USBHost WebCam test program

Import programK64F_USBHostC270_example

Simple USBHost C270 example

Import programF401RE-BTstack_example

BTstack for Nucleo F401RE/FRDM-KL46Z example program

Import programUSBHostRSSI_example

Bluetooth device discovery example program.

Import programKL46Z-USBHostGPS_HelloWorld

Simple USBHost GPS Dongle Receiver for FRDM-KL46Z test program

Files at this revision

API Documentation at this revision

Comitter:
va009039
Date:
Mon Feb 03 13:00:16 2014 +0000
Parent:
8:6463cd1964c0
Child:
10:40c7f6788902
Commit message:
add interrupt write transfer.

Changed in this revision

FATFileSystem.lib Show annotated file Show diff for this revision Revisions of this file
USBHost/USBDeviceConnected.cpp Show annotated file Show diff for this revision Revisions of this file
USBHost/USBDeviceConnected.h Show annotated file Show diff for this revision Revisions of this file
USBHost/USBEndpoint.h Show annotated file Show diff for this revision Revisions of this file
USBHost/USBHALHost.cpp Show annotated file Show diff for this revision Revisions of this file
USBHost/USBHost.cpp Show annotated file Show diff for this revision Revisions of this file
USBHost/USBHost.h Show annotated file Show diff for this revision Revisions of this file
USBHost/USBHostConf.h Show annotated file Show diff for this revision Revisions of this file
USBHost/USBHostHub.cpp Show annotated file Show diff for this revision Revisions of this file
USBHost/dbg.h Show annotated file Show diff for this revision Revisions of this file
USBHost/mymap.h Show annotated file Show diff for this revision Revisions of this file
USBHost/myqueue.h Show annotated file Show diff for this revision Revisions of this file
USBHostGPS/USBHostGPS.cpp Show diff for this revision Revisions of this file
USBHostGPS/USBHostGPS.h Show diff for this revision Revisions of this file
USBHostHID/USBHostKeyboard.cpp Show annotated file Show diff for this revision Revisions of this file
USBHostHID/USBHostKeyboard.h Show annotated file Show diff for this revision Revisions of this file
USBHostHID/USBHostMouse.cpp Show annotated file Show diff for this revision Revisions of this file
USBHostHID/USBHostMouse.h Show annotated file Show diff for this revision Revisions of this file
USBHostMSD/FATFileSystem.lib Show diff for this revision Revisions of this file
USBHostMSD/USBHostMSD.cpp Show annotated file Show diff for this revision Revisions of this file
USBHostMSD/USBHostMSD.h Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/FATFileSystem.lib	Mon Feb 03 13:00:16 2014 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/FATFileSystem/#b6669c987c8e
--- a/USBHost/USBDeviceConnected.cpp	Fri Jan 31 13:45:07 2014 +0000
+++ b/USBHost/USBDeviceConnected.cpp	Mon Feb 03 13:00:16 2014 +0000
@@ -15,8 +15,7 @@
  */
 
 #include "USBDeviceConnected.h"
-//#include "dbg.h"
-#define USB_DBG(...) while(0)
+#include "dbg.h"
 
 USBDeviceConnected::USBDeviceConnected() {
     init();
@@ -35,54 +34,33 @@
     device_subclass = 0;
     proto = 0;
     lowSpeed = false;
-    for (int i = 0; i < MAX_INTF; i++) {
-        memset((void *)&intf[i], 0, sizeof(INTERFACE));
-        intf[i].in_use = false;
-        for (int j = 0; j < MAX_ENDPOINT_PER_INTERFACE; j++) {
-            intf[i].ep[j] = NULL;
-            //strcpy(intf[i].name, "Unknown");
-        }
-    }
+    intf.clear();
     //hub_parent = NULL;
     //hub = NULL;
-    nb_interf = 0;
-}
-
-INTERFACE * USBDeviceConnected::getInterface(uint8_t index) {
-    if (index >= MAX_INTF)
-        return NULL;
-    
-    if (intf[index].in_use)
-        return &intf[index];
-    
-    return NULL;
 }
 
 bool USBDeviceConnected::addInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol) {
-    if ((intf_nb >= MAX_INTF) || (intf[intf_nb].in_use)) {
+    USB_DBG("intf_nb=%d", intf_nb);
+    INTERFACE* inter = intf.get(intf_nb);
+    if (inter) {
         return false;
-    }
-    intf[intf_nb].in_use = true;
-    intf[intf_nb].intf_class = intf_class;
-    intf[intf_nb].intf_subclass = intf_subclass;
-    intf[intf_nb].intf_protocol = intf_protocol;
-    intf[intf_nb].nb_endpoint = 0;
+    }
+    inter = new INTERFACE;
+    inter->in_use = true;
+    inter->intf_class = intf_class;
+    inter->intf_subclass = intf_subclass;
+    inter->intf_protocol = intf_protocol;
+    intf.put(intf_nb, inter);
     return true;
 }
 
 bool USBDeviceConnected::addEndpoint(uint8_t intf_nb, USBEndpoint * ept) {
-    if ((intf_nb >= MAX_INTF) || (intf[intf_nb].in_use == false) || (intf[intf_nb].nb_endpoint >= MAX_ENDPOINT_PER_INTERFACE)) {
+    INTERFACE* inter = intf.get(intf_nb);
+    if (inter == NULL) {
         return false;
     }
-    intf[intf_nb].nb_endpoint++;
-
-    for (int i = 0; i < MAX_ENDPOINT_PER_INTERFACE; i++) {
-        if (intf[intf_nb].ep[i] == NULL) {
-            intf[intf_nb].ep[i] = ept;
-            return true;
-        }
-    }
-    return false;
+    inter->ep.push(ept);
+    return true;
 }
 
 void USBDeviceConnected::init(uint8_t hub_, uint8_t port_, bool lowSpeed_) {
@@ -102,15 +80,15 @@
 
 
 USBEndpoint * USBDeviceConnected::getEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir, uint8_t index) {
-    if (intf_nb >= MAX_INTF) {
-        return NULL;
-    }
-    for (int i = 0; i < MAX_ENDPOINT_PER_INTERFACE; i++) {
-        if ((intf[intf_nb].ep[i]->getType() == type) && (intf[intf_nb].ep[i]->getDir() == dir)) {
+    USB_DBG("intf_nb=%d", intf_nb);
+    INTERFACE* inter = intf.get(intf_nb);
+    USB_TEST_ASSERT(inter);
+    for (int i = 0; i < inter->ep.size(); i++) {
+        if ((inter->ep.at(i)->getType() == type) && (inter->ep.at(i)->getDir() == dir)) {
             if(index) {
                 index--;
             } else {
-                return intf[intf_nb].ep[i];
+                return inter->ep.at(i);
             }
         }
     }
@@ -118,8 +96,7 @@
 }
 
 USBEndpoint * USBDeviceConnected::getEndpoint(uint8_t intf_nb, uint8_t index) {
-    if ((intf_nb >= MAX_INTF) || (index >= MAX_ENDPOINT_PER_INTERFACE)) {
-        return NULL;
-    }
-    return intf[intf_nb].ep[index];
+    INTERFACE* inter = intf.get(intf_nb);
+    USB_TEST_ASSERT(inter);
+    return inter->ep.at(index);
 }
--- a/USBHost/USBDeviceConnected.h	Fri Jan 31 13:45:07 2014 +0000
+++ b/USBHost/USBDeviceConnected.h	Mon Feb 03 13:00:16 2014 +0000
@@ -17,19 +17,25 @@
 
 #include "USBEndpoint.h"
 #include "USBHostConf.h"
+#include "myqueue.h"
+#include "mymap.h"
 
 class USBEndpoint;
 
-typedef struct {
+struct INTERFACE {
+    INTERFACE() {
+        in_use = false;
+        intf_class = 0;
+        intf_subclass = 0;
+        intf_protocol = 0;
+        ep.clear();
+    }
     bool in_use;
-    uint8_t nb_endpoint;
     uint8_t intf_class;
     uint8_t intf_subclass;
     uint8_t intf_protocol;
-    USBEndpoint * ep[MAX_ENDPOINT_PER_INTERFACE];
-    //FunctionPointer detach;
-    //char name[10];
-} INTERFACE; 
+    myqueue<USBEndpoint*>ep; 
+}; 
 
 /**
 * USBDeviceConnected class
@@ -83,14 +89,6 @@
     bool addInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol);
 
     /**
-    * Get a specific interface
-    *
-    * @param index index of the interface to be fetched
-    * @returns interface
-    */
-    INTERFACE * getInterface(uint8_t index);
-
-    /**
     * Disconnect the device by calling a callback function registered by a driver
     */
     void disconnect();
@@ -122,7 +120,7 @@
     USBEndpoint* getEpCtl() { return ep_ctl; }
 
 private:
-    INTERFACE intf[MAX_INTF];
+    mymap<int,INTERFACE*>intf;
     uint8_t hub_nb;
     uint8_t port;
     uint16_t vid;
--- a/USBHost/USBEndpoint.h	Fri Jan 31 13:45:07 2014 +0000
+++ b/USBHost/USBEndpoint.h	Mon Feb 03 13:00:16 2014 +0000
@@ -15,17 +15,58 @@
  */
  
 #pragma once
+#include "FunctionPointer.h"
 #include "USBHostTypes.h"
 #include "USBDeviceConnected.h"
+
 class USBDeviceConnected;
 
+/**
+* USBEndpoint class
+*/
 class USBEndpoint {
 public:
+    /**
+    * Constructor
+    */
     USBEndpoint() : data01_toggle(DATA0),address(0),MaxPacketSize(8) {
         dev = NULL;
     }
+
+    /**
+     *  Attach a member function to call when a transfer is finished
+     *
+     *  @param tptr pointer to the object to call the member function on
+     *  @param mptr pointer to the member function to be called
+     */
+    template<typename T>
+    inline void attach(T* tptr, void (T::*mptr)(void)) {
+        if((mptr != NULL) && (tptr != NULL)) {
+            rx.attach(tptr, mptr);
+        }
+    }
+
+    /**
+     * Attach a callback called when a transfer is finished
+     *
+     * @param fptr function pointer
+     */
+    inline void attach(void (*fptr)(void)) {
+        if(fptr != NULL) {
+            rx.attach(fptr);
+        }
+    }
+
+    /**
+    * Call the handler associted to the end of a transfer
+    */
+    inline void call() {
+        rx.call();
+    };
+
     void setDevice(USBDeviceConnected* _dev) { dev = _dev; }
     void setState(uint8_t st){}; // dummy
+    void setBuffer(uint8_t* buf, int size) { buf_start = buf, buf_size = size; }
     void setLengthTransferred(int len) { transferred = len; };
     void setSize(int size) { MaxPacketSize = size; }
     void setType(ENDPOINT_TYPE _type) { type = _type; };
@@ -35,6 +76,8 @@
     USBDeviceConnected* getDevice() { return dev; }
     ENDPOINT_TYPE getType() { return type; };
     int getLengthTransferred() { return transferred; }
+    uint8_t *getBufStart() { return buf_start; }
+    int getBufSize() { return buf_size; }
     uint8_t getAddress(){ return address; };
     int getSize() { return MaxPacketSize; }
     ENDPOINT_DIRECTION getDir() { return (address & 0x80) ? IN : OUT; }
@@ -49,6 +92,12 @@
     USBDeviceConnected* dev;
     uint8_t data01_toggle; // DATA0,DATA1
     uint8_t address;
+
     int transferred;
+    uint8_t * buf_start;
+    int buf_size;
+
+    FunctionPointer rx;
+
     int MaxPacketSize;
 };
--- a/USBHost/USBHALHost.cpp	Fri Jan 31 13:45:07 2014 +0000
+++ b/USBHost/USBHALHost.cpp	Mon Feb 03 13:00:16 2014 +0000
@@ -23,6 +23,8 @@
 #define USB_TEST_ASSERT_FALSE(A) while(0)
 #endif
 
+#define USB_INFO(...) do{fprintf(stderr,__VA_ARGS__);fprintf(stderr,"\n");}while(0);
+
 #define BD_OWN_MASK        (1<<7)
 #define BD_DATA01_MASK     (1<<6)
 #define BD_KEEP_MASK       (1<<5)
@@ -138,7 +140,15 @@
 bool USBHALHost::wait_attach() {
     attach_done = false;
     USB0->INTEN = USB_INTEN_ATTACHEN_MASK;
-    while(!attach_done);
+    Timer t;
+    t.reset();
+    t.start();
+    while(!attach_done) {
+        if (t.read_ms() > 5*1000) {
+            t.reset();
+            USB_INFO("Please attach USB device.");
+        }
+    }
     wait_ms(100);
     USB_TEST_ASSERT_FALSE(USB0->CTL & USB_CTL_SE0_MASK);
     root_lowSpeed = (USB0->CTL & USB_CTL_JSTATE_MASK) ? false : true;
--- a/USBHost/USBHost.cpp	Fri Jan 31 13:45:07 2014 +0000
+++ b/USBHost/USBHost.cpp	Mon Feb 03 13:00:16 2014 +0000
@@ -2,34 +2,6 @@
 #include "USBHost.h"
 #include <algorithm>
 
-template <bool>struct CtAssert;
-template <>struct CtAssert<true> {};
-#define CTASSERT(A) CtAssert<A>();
-
-
-#ifdef _USB_DBG
-#define USB_DBG(...) do{fprintf(stderr,"[%s@%d] ",__PRETTY_FUNCTION__,__LINE__);fprintf(stderr,__VA_ARGS__);fprintf(stderr,"\n");} while(0);
-#define USB_DBG2(...) do{fprintf(stderr,"[%s@%d] ",__PRETTY_FUNCTION__,__LINE__);fprintf(stderr,__VA_ARGS__);fprintf(stderr,"\n");} while(0);
-#define USB_DBG_HEX(A,B) debug_hex(A,B)
-#define USB_DBG_ERRSTAT() report.print_errstat();
-void debug_hex(uint8_t* buf, int size);
-#else
-#define USB_DBG(...) while(0)
-#define USB_DBG2(...) while(0)
-#define USB_DBG_HEX(A,B) while(0)
-#define USB_DBG_ERRSTAT() while(0)
-#endif
-
-#ifdef _USB_TEST
-#define USB_TEST_ASSERT(A) while(!(A)){fprintf(stderr,"\n\n%s@%d %s ASSERT!\n\n",__PRETTY_FUNCTION__,__LINE__,#A);exit(1);};
-#define USB_TEST_ASSERT_FALSE(A) USB_TEST_ASSERT(!(A))
-#else
-#define USB_TEST_ASSERT(A) while(0)
-#define USB_TEST_ASSERT_FALSE(A) while(0)
-#endif
-
-#define USB_INFO(...) do{fprintf(stderr,__VA_ARGS__);}while(0);
-
 USBHost* USBHost::inst = NULL;
 
 USBHost* USBHost::getHostInst()
@@ -41,8 +13,14 @@
     return inst;
 }
 
+void USBHost::poll()
+{
+    if (inst) {
+        inst->task();
+    }
+}
+
 USBHost::USBHost() {
-    DeviceLists_count = 0;
 }
 
 /* virtual */ bool USBHost::addDevice(int hub, int port, bool lowSpeed) {
@@ -74,12 +52,11 @@
     dev->setVid(dev_desc->idVendor);
     dev->setPid(dev_desc->idProduct);
     dev->setClass(dev_desc->bDeviceClass);
-    USB_INFO("hub: %d port: %d speed: %s vid: %04x pid: %04x class: %02x addr: %d\n",
+    USB_INFO("hub: %d port: %d speed: %s vid: %04x pid: %04x class: %02x addr: %d",
         hub, port, (lowSpeed ? "low " : "full"), dev->getVid(), dev->getPid(), dev->getClass(),
         dev->getAddress());
 
-    USB_TEST_ASSERT(DeviceLists_count < MAX_DEVICE_CONNECTED);
-    DeviceLists[DeviceLists_count++] = dev;
+    DeviceLists.push(dev);
 
     if (dev->getClass() == HUB_CLASS) {
         const int config = 1;
@@ -146,7 +123,6 @@
     uint32_t index = 0;
     uint32_t len_desc = 0;
     uint8_t id = 0;
-    int nb_endpoints_used = 0;
     USBEndpoint * ep = NULL;
     uint8_t intf_nb = 0;
     bool parsing_intf = false;
@@ -156,6 +132,7 @@
     while (index < len) {
         len_desc = conf_descr[index];
         id = conf_descr[index+1];
+        USB_DBG_HEX(conf_descr+index, len_desc);
         switch (id) {
             case CONFIGURATION_DESCRIPTOR:
                 USB_DBG("dev: %p has %d intf", dev, conf_descr[4]);
@@ -163,14 +140,10 @@
                 break;
             case INTERFACE_DESCRIPTOR:
                 if(pEnumerator->parseInterface(conf_descr[index + 2], conf_descr[index + 5], conf_descr[index + 6], conf_descr[index + 7])) {
-                    if (intf_nb++ <= MAX_INTF) {
-                        current_intf = conf_descr[index + 2];
-                        dev->addInterface(current_intf, conf_descr[index + 5], conf_descr[index + 6], conf_descr[index + 7]);
-                        nb_endpoints_used = 0;
-                        USB_DBG("ADD INTF %d on device %p: class: %d, subclass: %d, proto: %d", current_intf, dev, conf_descr[index + 5],conf_descr[index + 6],conf_descr[index + 7]);
-                    } else {
-                        USB_DBG("Drop intf...");
-                    }
+                    intf_nb++;
+                    current_intf = conf_descr[index + 2];
+                    dev->addInterface(current_intf, conf_descr[index + 5], conf_descr[index + 6], conf_descr[index + 7]);
+                    USB_DBG("ADD INTF %d on device %p: class: %d, subclass: %d, proto: %d", current_intf, dev, conf_descr[index + 5],conf_descr[index + 6],conf_descr[index + 7]);
                     parsing_intf = true;
                 } else {
                     parsing_intf = false;
@@ -179,19 +152,16 @@
             case ENDPOINT_DESCRIPTOR:
                 ep_desc = reinterpret_cast<EndpointDescriptor*>(conf_descr+index);
                 if (parsing_intf && (intf_nb <= MAX_INTF) ) {
-                    if (nb_endpoints_used < MAX_ENDPOINT_PER_INTERFACE) {
-                        ENDPOINT_TYPE type = (ENDPOINT_TYPE)(ep_desc->bmAttributes & 0x03);
-                        ENDPOINT_DIRECTION dir = (ep_desc->bEndpointAddress & 0x80) ? IN : OUT;
-                        if(pEnumerator->useEndpoint(current_intf, type, dir)) {
-                            ep = new USBEndpoint;
-                            ep->setDevice(dev);
-                            ep->setType(type);
-                            ep->setAddress(ep_desc->bEndpointAddress);
-                            ep->setSize(ep_desc->wMaxPacketSize);
-                            USB_DBG("ADD USBEndpoint %p, on interf %d on device %p", ep, current_intf, dev);
-                            dev->addEndpoint(current_intf, ep);
-                            nb_endpoints_used++;
-                        }
+                    ENDPOINT_TYPE type = (ENDPOINT_TYPE)(ep_desc->bmAttributes & 0x03);
+                    ENDPOINT_DIRECTION dir = (ep_desc->bEndpointAddress & 0x80) ? IN : OUT;
+                    if(pEnumerator->useEndpoint(current_intf, type, dir)) {
+                        ep = new USBEndpoint;
+                        ep->setDevice(dev);
+                        ep->setType(type);
+                        ep->setAddress(ep_desc->bEndpointAddress);
+                        ep->setSize(ep_desc->wMaxPacketSize);
+                        USB_DBG("ADD USBEndpoint %p, on interf %d on device %p", ep, current_intf, dev);
+                        dev->addEndpoint(current_intf, ep);
                     }
                 }
                 break;
@@ -223,9 +193,14 @@
     return USB_TYPE_ERROR;
 }
 
-USB_TYPE USBHost::bulkRead(USBDeviceConnected * dev, USBEndpoint * ep, uint8_t * buf, uint32_t len, bool blocking) {
-    USB_TEST_ASSERT(blocking);
-    int result = BulkRead(ep, buf, len);
+USB_TYPE USBHost::bulkRead(USBDeviceConnected* dev, USBEndpoint* ep, uint8_t* buf, uint32_t len, bool blocking) {
+    if (blocking == false) {
+        ep->setType(BULK_ENDPOINT);
+        ep->setBuffer(buf, len);
+        ep_queue.push(ep);
+        return USB_TYPE_PROCESSING;
+    }
+    int result = bulkReadBLOCK(ep, buf, len, -1);
     if (result >= 0) {
         return USB_TYPE_OK;
     }
@@ -233,9 +208,9 @@
     return USB_TYPE_ERROR;
 }
 
-USB_TYPE USBHost::bulkWrite(USBDeviceConnected * dev, USBEndpoint * ep, uint8_t * buf, uint32_t len, bool blocking) {
+USB_TYPE USBHost::bulkWrite(USBDeviceConnected* dev, USBEndpoint* ep, uint8_t* buf, uint32_t len, bool blocking) {
     USB_TEST_ASSERT(blocking);
-    int result = BulkWrite(ep, buf, len);
+    int result = bulkWriteNB(ep, buf, len);
     if (result >= 0) {
         return USB_TYPE_OK;
     }
@@ -243,12 +218,32 @@
     return USB_TYPE_ERROR;
 }
 
-USB_TYPE USBHost::interruptRead(USBDeviceConnected * dev, USBEndpoint * ep, uint8_t * buf, uint32_t len, bool blocking) {
-    int result = InterruptRead(ep, buf, len);
-    if (result >= 0) {
-        return USB_TYPE_OK;
+USB_TYPE USBHost::interruptRead(USBDeviceConnected* dev, USBEndpoint* ep, uint8_t* buf, uint32_t len, bool blocking) {
+    if (blocking == false) {
+        ep->setType(INTERRUPT_ENDPOINT);
+        ep->setBuffer(buf, len);
+        ep_queue.push(ep);
+        return USB_TYPE_PROCESSING;
     }
-    return USB_TYPE_ERROR;
+    interruptReadNB(ep, buf, len);
+    return USB_TYPE_OK;
+}
+
+USB_TYPE USBHost::interruptWrite(USBDeviceConnected* dev, USBEndpoint* ep, uint8_t* buf, uint32_t len, bool blocking) {
+    USB_TEST_ASSERT(blocking);
+    interruptWriteNB(ep, buf, len);
+    return USB_TYPE_OK;
+}
+
+USB_TYPE USBHost::isochronousRead(USBDeviceConnected* dev, USBEndpoint* ep, uint8_t* buf, uint32_t len, bool blocking) {
+    if (blocking == false) {
+        ep->setType(ISOCHRONOUS_ENDPOINT);
+        ep->setBuffer(buf, len);
+        ep_queue.push(ep);
+        return USB_TYPE_PROCESSING;
+    }
+    isochronousReadNB(ep, buf, len);
+    return USB_TYPE_OK;
 }
 
 int USBHost::ControlRead(USBDeviceConnected* dev, SETUP_PACKET* setup, uint8_t* data, int size) {
@@ -316,7 +311,8 @@
     return write_len;
 }
 
-int USBHost::InterruptRead(USBEndpoint* ep, uint8_t* data, int size) {
+int USBHost::interruptReadNB(USBEndpoint* ep, uint8_t* data, int size)
+{
     USB_TEST_ASSERT(ep);
     USBDeviceConnected* dev = ep->getDevice();
     USB_TEST_ASSERT(dev);
@@ -346,7 +342,43 @@
     return read_len;
 }
 
-int USBHost::BulkRead(USBEndpoint* ep, uint8_t* data, int size, int timeout_ms) {
+int USBHost::interruptWriteNB(USBEndpoint* ep, const uint8_t* data, int size)
+{
+    USB_TEST_ASSERT(ep);
+    USBDeviceConnected* dev = ep->getDevice();
+    USB_TEST_ASSERT(dev);
+    setAddr(dev->getAddress(), dev->getSpeed());
+    setEndpoint();
+    const int retryLimit = 0;
+    int transferred_len = 0;
+    for(int n = 0; transferred_len < size; n++) {
+        int size2 = std::min(size-transferred_len, ep->getSize());
+        int result = token_out(ep, data+transferred_len, size2, retryLimit);
+        if (result < 0) {
+            if (LastStatus == NAK) {
+                if (n == 0) {
+                    return -1;
+                }
+                break;
+            }
+            //USB_DBG("token_in result=%d %02x", result, LastStatus);
+            return result;
+        }
+        transferred_len += result;
+        if (result < ep->getSize()) {
+            break;
+        }
+    }
+    ep->setLengthTransferred(transferred_len);
+    return transferred_len;
+}
+
+int USBHost::bulkReadNB(USBEndpoint* ep, uint8_t* data, int size)
+{
+    return bulkReadBLOCK(ep, data, size, 0);
+}
+
+int USBHost::bulkReadBLOCK(USBEndpoint* ep, uint8_t* data, int size, int timeout_ms) {
     USB_TEST_ASSERT(ep);
     USBDeviceConnected* dev = ep->getDevice();
     USB_TEST_ASSERT(dev);
@@ -381,7 +413,7 @@
     return read_len;
 }
 
-int USBHost::BulkWrite(USBEndpoint* ep, const uint8_t* data, int size) {
+int USBHost::bulkWriteNB(USBEndpoint* ep, const uint8_t* data, int size) {
     USB_TEST_ASSERT(ep);
     USBDeviceConnected* dev = ep->getDevice();
     USB_TEST_ASSERT(dev);
@@ -410,7 +442,7 @@
     return write_len;
 }
 
-int USBHost::IsochronousRead(USBEndpoint* ep, uint8_t* data, int size) {
+int USBHost::isochronousReadNB(USBEndpoint* ep, uint8_t* data, int size) {
     USBDeviceConnected* dev = ep->getDevice();
     USB_TEST_ASSERT(dev);
     setAddr(dev->getAddress());
@@ -421,3 +453,30 @@
     return result;
 }
 
+void USBHost::task()
+{
+    if (ep_queue.empty()) {
+        return;
+    }
+    USBEndpoint* ep = ep_queue.pop();
+    USB_TEST_ASSERT(ep);
+    ep->setLengthTransferred(0);
+    switch(ep->getType()) {
+        case INTERRUPT_ENDPOINT:
+            if (ep->getDir() == IN) {
+                interruptReadNB(ep, ep->getBufStart(), ep->getBufSize());
+            }
+            break;
+        case BULK_ENDPOINT:
+            if (ep->getDir() == IN) {
+                bulkReadNB(ep, ep->getBufStart(), ep->getBufSize());
+            }
+            break;
+        case ISOCHRONOUS_ENDPOINT:
+            if (ep->getDir() == IN) {
+                isochronousReadNB(ep, ep->getBufStart(), ep->getBufSize());
+            }
+            break;
+    }
+    ep->call();
+}
--- a/USBHost/USBHost.h	Fri Jan 31 13:45:07 2014 +0000
+++ b/USBHost/USBHost.h	Mon Feb 03 13:00:16 2014 +0000
@@ -5,7 +5,8 @@
 #include "USBDeviceConnected.h"
 #include "IUSBEnumerator.h"
 #include "USBHostConf.h"
-#include "USBEndpoint.h"
+#include "dbg.h"
+#include "myqueue.h"
 
 class USBHost : public USBHALHost {
 public:
@@ -43,6 +44,7 @@
     * @returns status of the control write
     */
     USB_TYPE controlWrite(USBDeviceConnected * dev, uint8_t requestType, uint8_t request, uint32_t value, uint32_t index, uint8_t * buf, uint32_t len);
+
     /**
     * Bulk read
     *
@@ -96,6 +98,19 @@
     USB_TYPE interruptWrite(USBDeviceConnected * dev, USBEndpoint * ep, uint8_t * buf, uint32_t len, bool blocking = true);
 
     /**
+    * Isochronous read
+    *
+    * @param dev the isochronous transfer will be done for this device
+    * @param ep USBEndpoint which will be used to write a packet
+    * @param buf pointer on a buffer which will be written
+    * @param len length of the transfer
+    * @param blocking if true, the read is blocking (wait for completion)
+    *
+    * @returns status of the interrupt read
+    */
+    USB_TYPE isochronousRead(USBDeviceConnected* dev, USBEndpoint* ep, uint8_t* buf, uint32_t len, bool blocking = true);
+
+    /**
     * Enumerate a device.
     *
     * @param dev device which will be enumerated
@@ -112,7 +127,7 @@
     * @returns pointer on the "index" device
     */
     USBDeviceConnected * getDevice(uint8_t index) {
-        return (index < DeviceLists_count) ? DeviceLists[index] : NULL;
+        return DeviceLists.empty() ? NULL : DeviceLists.at(index);
     }
 
     /**
@@ -127,8 +142,13 @@
     void registerDriver(USBDeviceConnected * dev, uint8_t intf, T* tptr, void (T::*mptr)(void)) {
     }
 
-    int BulkRead(USBEndpoint*ep, uint8_t* data, int size, int timeout_ms = -1);
-    int IsochronousRead(USBEndpoint*ep, uint8_t* data, int size);
+    // KL46Z-USBHost extensions
+    int interruptReadNB(USBEndpoint* ep, uint8_t* data, int size);
+    int interruptWriteNB(USBEndpoint* ep, const uint8_t* data, int size);
+    int bulkReadNB(USBEndpoint*ep, uint8_t* data, int size);
+    int bulkWriteNB(USBEndpoint*ep, const uint8_t* data, int size);
+    int isochronousReadNB(USBEndpoint*ep, uint8_t* data, int size);
+    static void poll();
 
 private:
     USBHost();
@@ -136,13 +156,13 @@
     virtual bool addDevice(int hub, int port, bool lowSpeed);
     void root_enumeration(USBDeviceConnected* dev);
     void parseConfDescr(USBDeviceConnected* dev, uint8_t* conf_descr, uint32_t len, IUSBEnumerator* pEnumerator);
-    USBDeviceConnected* DeviceLists[MAX_DEVICE_CONNECTED];
-    int DeviceLists_count;
+    myqueue<USBDeviceConnected*>DeviceLists;
 
     int ControlRead(USBDeviceConnected* dev, SETUP_PACKET* setup, uint8_t* data, int size);
     int ControlWrite(USBDeviceConnected* dev, SETUP_PACKET* setup, uint8_t* data = NULL, int size = 0);
-    int BulkWrite(USBEndpoint*ep, const uint8_t* data, int size);
-    int InterruptRead(USBEndpoint*ep, uint8_t* data, int size);
+    int bulkReadBLOCK(USBEndpoint*ep, uint8_t* data, int size, int timeout_ms);
+    void task();
+    myqueue<USBEndpoint*>ep_queue;
 
     // USB HUB
     bool Hub(USBDeviceConnected* dev);
--- a/USBHost/USBHostConf.h	Fri Jan 31 13:45:07 2014 +0000
+++ b/USBHost/USBHostConf.h	Mon Feb 03 13:00:16 2014 +0000
@@ -64,21 +64,6 @@
 #define MAX_INTF                    4
 
 /*
-* Maximum number of endpoints on each interface
-*/
-#define MAX_ENDPOINT_PER_INTERFACE  3
-
-/*
-* Maximum number of endpoint descriptors that can be allocated
-*/
-#define MAX_ENDPOINT                (MAX_DEVICE_CONNECTED * MAX_INTF * MAX_ENDPOINT_PER_INTERFACE)
-
-/*
-* Maximum number of transfer descriptors that can be allocated
-*/
-#define MAX_TD                      (MAX_ENDPOINT*2)
-
-/*
 * usb_thread stack size
 */
 #define USB_THREAD_STACK            (256*4 + MAX_HUB_NB*256*4)
--- a/USBHost/USBHostHub.cpp	Fri Jan 31 13:45:07 2014 +0000
+++ b/USBHost/USBHostHub.cpp	Mon Feb 03 13:00:16 2014 +0000
@@ -1,22 +1,5 @@
 #include "USBHost.h"
 
-#ifdef _USB_DBG
-#define USB_DBG(...) do{fprintf(stderr,"[%s@%d] ",__PRETTY_FUNCTION__,__LINE__);fprintf(stderr,__VA_ARGS__);fprintf(stderr,"\n");} while(0);
-#define USB_DBG_HEX(A,B) debug_hex(A,B)
-extern void debug_hex(uint8_t* buf, int size);
-#else
-#define USB_DBG(...) while(0)
-#define USB_DBG_HEX(A,B) while(0)
-#endif
-
-#ifdef _USB_TEST
-#define USB_TEST_ASSERT(A) while(!(A)){fprintf(stderr,"\n\n%s@%d %s ASSERT!\n\n",__PRETTY_FUNCTION__,__LINE__,#A);exit(1);};
-#define USB_TEST_ASSERT_FALSE(A) USB_TEST_ASSERT(!(A))
-#else
-#define USB_TEST_ASSERT(A) while(0)
-#define USB_TEST_ASSERT_FALSE(A) while(0)
-#endif
-
 #define PORT_CONNECTION   0
 #define PORT_ENABLE       1
 #define PORT_SUSPEND      2
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/dbg.h	Mon Feb 03 13:00:16 2014 +0000
@@ -0,0 +1,93 @@
+/* mbed USBHost Library
+ * Copyright (c) 2006-2013 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef USB_DEBUG_H
+#define USB_DEBUG_H
+
+//Debug is disabled by default
+#ifndef DEBUG
+#define DEBUG 3 /*INFO,ERR,WARN*/
+#endif
+#ifndef DEBUG2
+#define DEBUG2 0
+#endif
+#define DEBUG_TRANSFER 0
+#define DEBUG_EP_STATE 0
+#define DEBUG_EVENT 0
+
+#if (DEBUG > 3)
+#define USB_DBG(...) do{fprintf(stderr,"[%s@%d] ",__PRETTY_FUNCTION__,__LINE__);fprintf(stderr,__VA_ARGS__);fprintf(stderr,"\r\n");} while(0);
+//#define USB_DBG(x, ...) std::printf("[USB_DBG: %s:%d]" x "\r\n", __FILE__, __LINE__, ##__VA_ARGS__);
+#define USB_DBG_HEX(A,B) debug_hex(A,B)
+extern void debug_hex(uint8_t* buf, int size);
+#define USB_DBG_ERRSTAT() report.print_errstat();
+#else
+#define USB_DBG(x, ...)
+#define USB_DBG_HEX(A,B) while(0)
+#define USB_DBG_ERRSTAT() while(0)
+#endif
+
+#if (DEBUG2 > 3)
+#define USB_DBG2(...) do{fprintf(stderr,"[%s@%d] ",__PRETTY_FUNCTION__,__LINE__);fprintf(stderr,__VA_ARGS__);fprintf(stderr,"\r\n");} while(0);
+#else
+#define USB_DBG2(...)  while(0);
+#endif
+
+#if (DEBUG > 2)
+#define USB_INFO(...) do{fprintf(stderr,__VA_ARGS__);fprintf(stderr,"\r\n");}while(0);
+//#define USB_INFO(x, ...) std::printf("[USB_INFO: %s:%d]" x "\r\n", __FILE__, __LINE__, ##__VA_ARGS__);
+#else
+#define USB_INFO(x, ...)
+#endif
+
+#if (DEBUG > 1)
+#define USB_WARN(x, ...) std::printf("[USB_WARNING: %s:%d]" x "\r\n", __FILE__, __LINE__, ##__VA_ARGS__);
+#else
+#define USB_WARN(x, ...)
+#endif
+
+#if (DEBUG > 0)
+#define USB_ERR(x, ...) std::printf("[USB_ERR: %s:%d]" x "\r\n", __FILE__, __LINE__, ##__VA_ARGS__);
+#else
+#define USB_ERR(x, ...)
+#endif
+
+#if (DEBUG_TRANSFER)
+#define USB_DBG_TRANSFER(x, ...) std::printf("[USB_TRANSFER: %s:%d]" x "\r\n", __FILE__, __LINE__, ##__VA_ARGS__);
+#else
+#define USB_DBG_TRANSFER(x, ...)
+#endif
+
+#if (DEBUG_EVENT)
+#define USB_DBG_EVENT(x, ...) std::printf("[USB_EVENT: %s:%d]" x "\r\n", __FILE__, __LINE__, ##__VA_ARGS__);
+#else
+#define USB_DBG_EVENT(x, ...)
+#endif
+
+template <bool>struct CtAssert;
+template <>struct CtAssert<true> {};
+#define CTASSERT(A) CtAssert<A>();
+
+#ifdef _USB_TEST
+#define USB_TEST_ASSERT(A) while(!(A)){fprintf(stderr,"\n\n%s@%d %s ASSERT!\n\n",__PRETTY_FUNCTION__,__LINE__,#A);exit(1);};
+#define USB_TEST_ASSERT_FALSE(A) USB_TEST_ASSERT(!(A))
+#else
+#define USB_TEST_ASSERT(A) while(0)
+#define USB_TEST_ASSERT_FALSE(A) while(0)
+#endif
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/mymap.h	Mon Feb 03 13:00:16 2014 +0000
@@ -0,0 +1,53 @@
+#pragma once
+
+template<class K,class T>
+class mymap {
+    struct mypair {
+        K key;
+        T value;
+    };
+public:
+    mymap() {
+        m_size = 0;
+        m_limit = 4;
+        m_buf = new mypair[m_limit];
+    }
+    void put(K key, T value) {
+        int i = find(key);
+        if (i == (-1)) {
+            if (m_size >= m_limit) {
+                int new_limit = m_limit + 4;
+                mypair* new_buf = new mypair[new_limit];
+                for(int i = 0; i < m_size; i++) {
+                    new_buf[i] = m_buf[i];
+                }
+                delete[] m_buf;
+                m_buf = new_buf;
+                m_limit = new_limit;
+            }
+            i = m_size++;
+            m_buf[i].key = key;
+        }
+        m_buf[i].value = value;
+    }
+    T get(K key) {
+        int i = find(key);
+        return (i == -1) ? NULL : m_buf[i].value;
+    }
+    bool empty() { return m_size == 0 ? true : false; }
+    int size() { return m_size; }
+    void clear() { m_size = 0; }
+
+private:
+    int find(K key) {
+        for(int i = 0; i < m_size; i++) {
+            if (m_buf[i].key == key) {
+                return i;
+            }
+        }
+        return -1;
+    }
+    int m_limit;
+    int m_size;
+    mypair *m_buf;
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/myqueue.h	Mon Feb 03 13:00:16 2014 +0000
@@ -0,0 +1,48 @@
+#pragma once
+
+template<class T>
+class myqueue {
+public:
+    myqueue() {
+        m_w = m_r = 0;
+        m_size = 0;
+        m_limit = 4;
+        m_buf = new T[m_limit];
+    }
+    void push(T v) {
+        if (m_size >= m_limit) {
+            int new_limit = m_limit + 4;
+            T* new_buf = new T[new_limit];
+            for(int i = 0; i < m_size; i++) {
+                new_buf[i] = m_buf[i];
+            }
+            delete[] m_buf;
+            m_buf = new_buf;
+            m_limit = new_limit;
+        }
+        m_buf[m_w++] = v;
+        if (m_w >= m_limit) {
+            m_w = 0;
+        }
+        m_size++;
+    }
+    T pop() {
+        T v = m_buf[m_r++];
+        if (m_r >= m_limit) {
+            m_r = 0;
+        }
+        m_size--;
+        return v;
+    }
+    bool empty() { return (m_w == m_r) ? true : false; }
+    int size() { return m_size; }
+    void clear() { m_size = 0; }
+    T at(int i) { return m_buf[i]; }
+
+private:
+    int m_limit;
+    int m_size;
+    int m_w;
+    int m_r;
+    T *m_buf;
+};
--- a/USBHostGPS/USBHostGPS.cpp	Fri Jan 31 13:45:07 2014 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,100 +0,0 @@
-#include "USBHostGPS.h"
-
-#ifdef _USB_DBG
-#define USB_DBG(...) do{fprintf(stderr,"[%s@%d] ",__PRETTY_FUNCTION__,__LINE__);fprintf(stderr,__VA_ARGS__);fprintf(stderr,"\n");} while(0);
-#define USB_DBG2(...) do{fprintf(stderr,"[%s@%d] ",__PRETTY_FUNCTION__,__LINE__);fprintf(stderr,__VA_ARGS__);fprintf(stderr,"\n");} while(0);
-#define USB_DBG_HEX(A,B) debug_hex(A,B)
-void debug_hex(uint8_t* buf, int size);
-#else
-#define USB_DBG(...) while(0)
-#define USB_DBG2(...) while(0)
-#define USB_DBG_HEX(A,B) while(0)
-#endif
-
-#define USB_TEST_ASSERT(A) while(!(A)){fprintf(stderr,"\n\n%s@%d %s ASSERT!\n\n",__PRETTY_FUNCTION__,__LINE__,#A);exit(1);};
-#define USB_TEST_ASSERT_FALSE(A) USB_TEST_ASSERT(!(A))
-
-#define USB_INFO(...) do{fprintf(stderr,__VA_ARGS__);}while(0);
-
-
-USBHostGPS::USBHostGPS(int baud_)
-{
-    host = USBHost::getHostInst();
-    init();
-    baud = baud_;
-}
-
-void USBHostGPS::init() {
-    dev = NULL;
-    bulk_in = NULL;
-    onUpdate = NULL;
-    dev_connected = false;
-    gps_device_found = false;
-    gps_intf = -1;
-}
-
-bool USBHostGPS::connected() {
-    return dev_connected;
-}
-
-bool USBHostGPS::connect() {
-
-    if (dev_connected) {
-        return true;
-    }
-    
-    for (uint8_t i = 0; i < MAX_DEVICE_CONNECTED; i++) {
-        if ((dev = host->getDevice(i)) != NULL) {
-            if(host->enumerate(dev, this)) {
-                break;
-            }
-            if (gps_device_found) {
-                bulk_in = dev->getEndpoint(gps_intf, BULK_ENDPOINT, IN);
-                USB_TEST_ASSERT(bulk_in);
-                // stop bit = 1, parity = none, 8bit
-                uint8_t data[] = {baud&0xff, baud>>8, baud>>16, baud>>24, 0x00, 0x00, 0x08};
-                USB_TYPE rc = host->controlWrite(dev, 0x21, PL2303_SET_LINE_CODING, 0, 0, data, sizeof(data));
-                USB_TEST_ASSERT(rc == USB_TYPE_OK);
-                USB_INFO("New GPS device: VID:%04x PID:%04x [dev: %p - intf: %d]\n", dev->getVid(), dev->getPid(), dev, gps_intf);
-                dev_connected = true;
-                return true;
-            }
-        }
-    }
-    init();
-    return false;
-}
-
-/*virtual*/ void USBHostGPS::setVidPid(uint16_t vid, uint16_t pid)
-{
-    USB_DBG("vid:%04x pid:%04x", vid, pid);
-    if (pid == 0x2303) {
-        gps_device_found = true;
-    }
-}
-
-/*virtual*/ bool USBHostGPS::parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol) //Must return true if the interface should be parsed
-{
-    USB_DBG("intf: %d class: %02x %02x %02x", intf_nb, intf_class, intf_subclass, intf_protocol);
-    if (gps_device_found) {
-        if (gps_intf == -1) {
-            gps_intf = intf_nb;
-            return true;
-        }
-    }    
-    return false;
-}
-
-/*virtual*/ bool USBHostGPS::useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir) //Must return true if the endpoint will be used
-{
-    USB_DBG("intf_nb=%d type=%d dir=%d", intf_nb, type, dir);
-    if (gps_device_found) {
-        if (intf_nb == gps_intf) {
-            if (type == BULK_ENDPOINT && dir == IN) {
-                return true;
-            }
-        }
-    }
-    return false;
-}
-
--- a/USBHostGPS/USBHostGPS.h	Fri Jan 31 13:45:07 2014 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,63 +0,0 @@
-// Simple USBHost GPS Dongle for FRDM-KL46Z
-#include "USBHost.h"
-
-#define PL2303_SET_LINE_CODING 0x20
-
-class USBHostGPS : public IUSBEnumerator {
-public:
-
-    /**
-    * Constructor
-    */
-    USBHostGPS(int baud = 38400);
-
-    /**
-     * Try to connect a USB GPS device
-     *
-     * @return true if connection was successful
-     */
-    bool connect();
-
-    /**
-    * Check if a USB GPS is connected
-    *
-    * @returns true if a mouse is connected
-    */
-    bool connected();
-
-    int readNMEA(char* data, int size, int timeout_ms) {
-        int result = host->BulkRead(bulk_in, (uint8_t*)data, size, timeout_ms);
-        return (result >= 0) ? bulk_in->getLengthTransferred() : 0;
-    }
-    void attachEvent(void (*ptr)(uint8_t* data, int size)) {
-        if (ptr != NULL) {
-            onUpdate = ptr;
-        }
-    }
-    void poll() {
-        int result = host->BulkRead(bulk_in, buf, sizeof(buf), 0);
-        if (result >= 0) {
-            if (onUpdate) {
-                (*onUpdate)(buf, bulk_in->getLengthTransferred());
-            }
-        }
-    }
-
-protected:
-    //From IUSBEnumerator
-    virtual void setVidPid(uint16_t vid, uint16_t pid);
-    virtual bool parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol); //Must return true if the interface should be parsed
-    virtual bool useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir); //Must return true if the endpoint will be used
-
-private:
-    USBHost * host;
-    USBDeviceConnected* dev;
-    USBEndpoint* bulk_in;
-    bool dev_connected;
-    bool gps_device_found;
-    int gps_intf;
-    void (*onUpdate)(uint8_t* data, int size);
-    uint8_t buf[64];
-    int baud;
-    void init();
-};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHostHID/USBHostKeyboard.cpp	Mon Feb 03 13:00:16 2014 +0000
@@ -0,0 +1,184 @@
+/* mbed USBHost Library
+ * Copyright (c) 2006-2013 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "USBHostKeyboard.h"
+
+#if USBHOST_KEYBOARD
+
+static uint8_t keymap[4][0x39] = { 
+    { 0, 0, 0, 0, 'a', 'b' /*0x05*/,
+      'c', 'd', 'e', 'f', 'g' /*0x0a*/,
+      'h', 'i', 'j', 'k', 'l'/*0x0f*/,
+      'm', 'n', 'o', 'p', 'q'/*0x14*/,
+      'r', 's', 't', 'u', 'v'/*0x19*/,
+      'w', 'x', 'y', 'z', '1'/*0x1E*/,
+      '2', '3', '4', '5', '6'/*0x23*/,
+      '7', '8', '9', '0', 0x0A /*enter*/, /*0x28*/
+      0x1B /*escape*/, 0x08 /*backspace*/, 0x09/*tab*/, 0x20/*space*/, '-', /*0x2d*/
+      '=', '[', ']', '\\', '#', /*0x32*/
+      ';', '\'', 0, ',', '.', /*0x37*/
+      '/'},
+
+    /* CTRL MODIFIER */
+    { 0, 0, 0, 0, 0, 0 /*0x05*/,
+      0, 0, 0, 0, 0 /*0x0a*/,
+      0, 0, 0, 0, 0/*0x0f*/,
+      0, 0, 0, 0, 0/*0x14*/,
+      0, 0, 0, 0, 0/*0x19*/,
+      0, 0, 0, 0, 0/*0x1E*/,
+      0, 0, 0, 0, 0/*0x23*/,
+      0, 0, 0, 0, 0 /*enter*/, /*0x28*/
+      0, 0, 0, 0, 0, /*0x2d*/
+      0, 0, 0, 0, 0, /*0x32*/
+      0, 0, 0, 0, 0, /*0x37*/
+      0},
+
+    /* SHIFT MODIFIER */
+    { 0, 0, 0, 0, 'A', 'B' /*0x05*/,
+      'C', 'D', 'E', 'F', 'G' /*0x0a*/,
+      'H', 'I', 'J', 'K', 'L'/*0x0f*/,
+      'M', 'N', 'O', 'P', 'Q'/*0x14*/,
+      'R', 'S', 'T', 'U', 'V'/*0x19*/,
+      'W', 'X', 'Y', 'Z', '!'/*0x1E*/,
+      '@', '#', '$', '%', '^'/*0x23*/,
+      '&', '*', '(', ')', 0, /*0x28*/
+      0, 0, 0, 0, 0, /*0x2d*/
+      '+', '{', '}', '|', '~', /*0x32*/
+      ':', '"', 0, '<', '>', /*0x37*/
+      '?'},
+
+    /* ALT MODIFIER */
+    { 0, 0, 0, 0, 0, 0 /*0x05*/,
+      0, 0, 0, 0, 0 /*0x0a*/,
+      0, 0, 0, 0, 0/*0x0f*/,
+      0, 0, 0, 0, 0/*0x14*/,
+      0, 0, 0, 0, 0/*0x19*/,
+      0, 0, 0, 0, 0/*0x1E*/,
+      0, 0, 0, 0, 0/*0x23*/,
+      0, 0, 0, 0, 0 /*enter*/, /*0x28*/
+      0, 0, 0, 0, 0, /*0x2d*/
+      0, 0, 0, 0, 0, /*0x32*/
+      0, 0, 0, 0, 0, /*0x37*/
+      0}
+
+};
+
+
+USBHostKeyboard::USBHostKeyboard() {
+    host = USBHost::getHostInst();
+    init();
+}
+
+
+void USBHostKeyboard::init() {
+    dev = NULL;
+    int_in = NULL;
+    report_id = 0;
+    onKey = NULL;
+    onKeyCode = NULL;
+    dev_connected = false;
+    keyboard_intf = -1;
+    keyboard_device_found = false;
+}
+
+bool USBHostKeyboard::connected() {
+    return dev_connected;
+}
+
+
+bool USBHostKeyboard::connect() {
+    
+    if (dev_connected) {
+        return true;
+    }
+    
+    for (uint8_t i = 0; i < MAX_DEVICE_CONNECTED; i++) {
+        if ((dev = host->getDevice(i)) != NULL) {
+
+            if (host->enumerate(dev, this))
+                break;
+            
+            if (keyboard_device_found) {
+                int_in = dev->getEndpoint(keyboard_intf, INTERRUPT_ENDPOINT, IN);
+                
+                if (!int_in)
+                    break;
+                
+                USB_INFO("New Keyboard device: VID:%04x PID:%04x [dev: %p - intf: %d]", dev->getVid(), dev->getPid(), dev, keyboard_intf);
+                dev->setName("Keyboard", keyboard_intf);
+                host->registerDriver(dev, keyboard_intf, this, &USBHostKeyboard::init);
+                
+                int_in->attach(this, &USBHostKeyboard::rxHandler);
+                host->interruptRead(dev, int_in, report, int_in->getSize(), false);
+                
+                dev_connected = true;
+                return true;
+            }
+        }
+    }
+    init();
+    return false;
+}
+
+void USBHostKeyboard::rxHandler() {
+    int len = int_in->getLengthTransferred();
+    int index = (len == 9) ? 1 : 0;
+    int len_listen = int_in->getSize();
+    uint8_t key = 0;
+    if (len == 8 || len == 9) {
+        uint8_t modifier = (report[index] == 4) ? 3 : report[index];
+        len_listen = len;
+        key = keymap[modifier][report[index + 2]];
+        if (key && onKey) {
+            (*onKey)(key);
+        }
+        if ((report[index + 2] || modifier) && onKeyCode) {
+            (*onKeyCode)(report[index + 2], modifier);
+        }
+    }
+    if (dev && int_in)
+        host->interruptRead(dev, int_in, report, len_listen, false);
+}
+
+/*virtual*/ void USBHostKeyboard::setVidPid(uint16_t vid, uint16_t pid)
+{
+    // we don't check VID/PID for keyboard driver
+}
+
+/*virtual*/ bool USBHostKeyboard::parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol) //Must return true if the interface should be parsed
+{
+    if ((keyboard_intf == -1) &&
+        (intf_class == HID_CLASS) &&
+        (intf_subclass == 0x01) &&
+        (intf_protocol == 0x01)) {
+        keyboard_intf = intf_nb;
+        return true;
+    }
+    return false;
+}
+
+/*virtual*/ bool USBHostKeyboard::useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir) //Must return true if the endpoint will be used
+{
+    if (intf_nb == keyboard_intf) {
+        if (type == INTERRUPT_ENDPOINT && dir == IN) {
+            keyboard_device_found = true;
+            return true;
+        }
+    }
+    return false;
+}
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHostHID/USBHostKeyboard.h	Mon Feb 03 13:00:16 2014 +0000
@@ -0,0 +1,102 @@
+/* mbed USBHost Library
+ * Copyright (c) 2006-2013 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef USBHOSTKEYBOARD_H
+#define USBHOSTKEYBOARD_H
+
+#include "USBHostConf.h"
+
+#if USBHOST_KEYBOARD
+
+#include "USBHost.h"
+
+/** 
+ * A class to communicate a USB keyboard
+ */
+class USBHostKeyboard : public IUSBEnumerator {
+public:
+    
+    /**
+    * Constructor
+    */
+    USBHostKeyboard();
+
+    /**
+     * Try to connect a keyboard device
+     *
+     * @return true if connection was successful
+     */
+    bool connect();
+
+    /**
+    * Check if a keyboard is connected
+    *
+    * @returns true if a keyboard is connected
+    */
+    bool connected();
+
+    /**
+     * Attach a callback called when a keyboard event is received
+     *
+     * @param ptr function pointer
+     */
+    inline void attach(void (*ptr)(uint8_t key)) {
+        if (ptr != NULL) {
+            onKey = ptr;
+        }
+    }
+
+    /**
+     * Attach a callback called when a keyboard event is received
+     *
+     * @param ptr function pointer
+     */
+    inline void attach(void (*ptr)(uint8_t keyCode, uint8_t modifier)) {
+        if (ptr != NULL) {
+            onKeyCode = ptr;
+        }
+    }
+
+protected:
+    //From IUSBEnumerator
+    virtual void setVidPid(uint16_t vid, uint16_t pid);
+    virtual bool parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol); //Must return true if the interface should be parsed
+    virtual bool useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir); //Must return true if the endpoint will be used
+
+private:
+    USBHost * host;
+    USBDeviceConnected * dev;
+    USBEndpoint * int_in;
+    uint8_t report[9];
+    int keyboard_intf;
+    bool keyboard_device_found;
+    
+    bool dev_connected;
+
+    void rxHandler();
+
+    void (*onKey)(uint8_t key);
+    void (*onKeyCode)(uint8_t key, uint8_t modifier);
+
+    int report_id;
+    
+    void init();
+
+};
+
+#endif
+
+#endif
--- a/USBHostHID/USBHostMouse.cpp	Fri Jan 31 13:45:07 2014 +0000
+++ b/USBHostHID/USBHostMouse.cpp	Mon Feb 03 13:00:16 2014 +0000
@@ -1,175 +1,144 @@
-#include "USBHostMouse.h"
-
-#ifdef _USB_DBG
-#define USB_DBG(...) do{fprintf(stderr,"[%s@%d] ",__PRETTY_FUNCTION__,__LINE__);fprintf(stderr,__VA_ARGS__);fprintf(stderr,"\n");} while(0);
-#define USB_DBG_HEX(A,B) debug_hex(A,B)
-void debug_hex(uint8_t* buf, int size);
-#else
-#define USB_DBG(...) while(0)
-#define USB_DBG_HEX(A,B) while(0)
-#endif
-
-#define USB_TEST_ASSERT(A) while(!(A)){fprintf(stderr,"\n\n%s@%d %s ASSERT!\n\n",__PRETTY_FUNCTION__,__LINE__,#A);exit(1);};
-#define USB_TEST_ASSERT_FALSE(A) USB_TEST_ASSERT(!(A))
-
-#define USB_INFO(...) do{fprintf(stderr,__VA_ARGS__);}while(0);
-
-USBHostMouse::USBHostMouse() {
-    host = USBHost::getHostInst();
-    init();
-}
-
-void USBHostMouse::init() {
-    dev = NULL;
-    int_in = NULL;
-    onUpdate = NULL;
-    onButtonUpdate = NULL;
-    onXUpdate = NULL;
-    onYUpdate = NULL;
-    onZUpdate = NULL;
-    report_id = 0;
-    dev_connected = false;
-    mouse_device_found = false;
-    mouse_intf = -1;
-    
-    buttons = 0;
-    x = 0;
-    y = 0;
-    z = 0;
-}
-
-bool USBHostMouse::connected() {
-    return dev_connected;
-}
-
-bool USBHostMouse::connect() {
-
-    if (dev_connected) {
-        return true;
-    }
-    
-    for (uint8_t i = 0; i < MAX_DEVICE_CONNECTED; i++) {
-        if ((dev = host->getDevice(i)) != NULL) {
-
-            if(host->enumerate(dev, this))
-                break;
-            
-            if (mouse_device_found) {
-                
-                int_in = dev->getEndpoint(mouse_intf, INTERRUPT_ENDPOINT, IN);
-                USB_DBG("int_in=%p", int_in);
-                if (!int_in)
-                    break;
-                
-                USB_INFO("New Mouse device: VID:%04x PID:%04x [dev: %p - intf: %d]\n", dev->getVid(), dev->getPid(), dev, mouse_intf);
-                dev->setName("Mouse", mouse_intf);
-                host->registerDriver(dev, mouse_intf, this, &USBHostMouse::init);
-                
-                //int_in->attach(this, &USBHostMouse::rxHandler);
-                host->interruptRead(dev, int_in, report, int_in->getSize(), false);
-                
-                dev_connected = true;
-                return true;
-            }
-        }
-    }
-    init();
-    return false;
-}
-
-/*virtual*/ void USBHostMouse::setVidPid(uint16_t vid, uint16_t pid)
-{
-    USB_DBG("vid:%04x pid:%04x", vid, pid);
-    // we don't check VID/PID for mouse driver
-}
-
-/*virtual*/ bool USBHostMouse::parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol) //Must return true if the interface should be parsed
-{
-    USB_DBG("intf: %d class: %02x %02x %02x", intf_nb, intf_class, intf_subclass, intf_protocol);
-    if ((mouse_intf == -1) &&
-        (intf_class == HID_CLASS) &&
-        (intf_subclass == 0x01) &&
-        (intf_protocol == 0x02)) {
-        mouse_intf = intf_nb;
-        return true;
-    }
-    return false;
-}
-
-/*virtual*/ bool USBHostMouse::useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir) //Must return true if the endpoint will be used
-{
-    USB_DBG("intf_nb=%d type=%d dir=%d", intf_nb, type, dir);
-
-    if (intf_nb == mouse_intf) {
-        if (type == INTERRUPT_ENDPOINT && dir == IN) {
-            mouse_device_found = true;
-            return true;
-        }
-    }
-    return false;
-}
-
-#if 0
-void USBHostMouse::setup() {
-    dev = host->getDevice(0);
-    if (dev->getClass() == HUB_CLASS) {
-        for(int i = 1; ; i++) {
-            dev = host->getDevice(i);
-            if (dev == NULL) {
-                break;
-            }
-            if (enumeration(dev)) {
-                break;
-            }
-        }
-        USB_TEST_ASSERT(ep_int_in);
-    } else {
-        ep_int_in = NULL;
-    }
-}
-
-bool USBHostMouse::enumeration(USBDeviceConnected* dev) {
-    // config descriptor
-    uint8_t desc[4];
-    int rc = host->controlRead(dev, 0x80, GET_DESCRIPTOR, 2<<8, 0, desc, 4);
-    USB_TEST_ASSERT(rc == USB_TYPE_OK);
-    USB_DBG_HEX(desc, 4);
-
-    int TotalLength = desc[2]|desc[3]<<8;
-    uint8_t* buf = new uint8_t[TotalLength];
-    rc = host->controlRead(dev, 0x80, GET_DESCRIPTOR, 2<<8, 0, buf, TotalLength);
-    USB_TEST_ASSERT(rc == USB_TYPE_OK);
-    //USB_DBG_HEX(buf, TotalLength);
-    bool found = false;
-    for(int i = 0; i < TotalLength; ) {
-        int Length = buf[i];
-        uint8_t DescriptorType = buf[i+1];
-        if (DescriptorType == 0x04) { // interface
-            InterfaceDescriptor* desc = reinterpret_cast<InterfaceDescriptor*>(buf+i);
-            if (desc->bInterfaceClass == 0x03) {
-                found = true;
-            }
-        } else if (DescriptorType == 0x05) { // endpoint
-            EndpointDescriptor* desc = reinterpret_cast<EndpointDescriptor*>(buf+i);
-            if (desc->bmAttributes == 0x03 &&
-                (desc->bEndpointAddress & 0x80)) { // interrupt in
-                ep_int_in = new USBEndpoint;
-                ep_int_in->setDevice(dev);
-                ep_int_in->setAddress(desc->bEndpointAddress);
-                ep_int_in->setSize(desc->wMaxPacketSize);
-            }
-        }
-        USB_DBG_HEX(buf+i, Length);
-        i += Length;
-    }
-    delete[] buf;
-    if (!found) {
-        return false;
-    }
-    int config = 1;
-    host->controlWrite(dev, 0x00, SET_CONFIGURATION, config, 0, NULL, 0);
-    wait_ms(100);
-    return true;
-}
-#endif
-
+/* mbed USBHost Library
+ * Copyright (c) 2006-2013 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "USBHostMouse.h"
+
+#if USBHOST_MOUSE
+
+USBHostMouse::USBHostMouse() {
+    host = USBHost::getHostInst();
+    init();
+}
+
+void USBHostMouse::init() {
+    dev = NULL;
+    int_in = NULL;
+    onUpdate = NULL;
+    onButtonUpdate = NULL;
+    onXUpdate = NULL;
+    onYUpdate = NULL;
+    onZUpdate = NULL;
+    report_id = 0;
+    dev_connected = false;
+    mouse_device_found = false;
+    mouse_intf = -1;
+    
+    buttons = 0;
+    x = 0;
+    y = 0;
+    z = 0;
+}
+
+bool USBHostMouse::connected() {
+    return dev_connected;
+}
+
+bool USBHostMouse::connect() {
+
+    if (dev_connected) {
+        return true;
+    }
+    
+    for (uint8_t i = 0; i < MAX_DEVICE_CONNECTED; i++) {
+        if ((dev = host->getDevice(i)) != NULL) {
+
+            if(host->enumerate(dev, this))
+                break;
+            
+            if (mouse_device_found) {
+                
+                int_in = dev->getEndpoint(mouse_intf, INTERRUPT_ENDPOINT, IN);
+                if (!int_in)
+                    break;
+                
+                USB_INFO("New Mouse device: VID:%04x PID:%04x [dev: %p - intf: %d]", dev->getVid(), dev->getPid(), dev, mouse_intf);
+                dev->setName("Mouse", mouse_intf);
+                host->registerDriver(dev, mouse_intf, this, &USBHostMouse::init);
+                
+                int_in->attach(this, &USBHostMouse::rxHandler);
+                host->interruptRead(dev, int_in, report, int_in->getSize(), false);
+                
+                dev_connected = true;
+                return true;
+            }
+        }
+    }
+    init();
+    return false;
+}
+
+void USBHostMouse::rxHandler() {
+    int len_listen = int_in->getSize();
+    
+    if (onUpdate) {
+        (*onUpdate)(report[0] & 0x07, report[1], report[2], report[3]);
+    }
+    
+    if (onButtonUpdate && (buttons != (report[0] & 0x07))) {
+        (*onButtonUpdate)(report[0] & 0x07);
+    }
+    
+    if (onXUpdate && (x != report[1])) {
+        (*onXUpdate)(report[1]);
+    }
+    
+    if (onYUpdate && (y != report[2])) {
+        (*onYUpdate)(report[2]);
+    }
+    
+    if (onZUpdate && (z != report[3])) {
+        (*onZUpdate)(report[3]);
+    }
+        
+    // update mouse state
+    buttons = report[0] & 0x07;
+    x = report[1];
+    y = report[2];
+    z = report[3];
+    
+    if (dev)
+        host->interruptRead(dev, int_in, report, len_listen, false);
+}
+
+/*virtual*/ void USBHostMouse::setVidPid(uint16_t vid, uint16_t pid)
+{
+    // we don't check VID/PID for mouse driver
+}
+
+/*virtual*/ bool USBHostMouse::parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol) //Must return true if the interface should be parsed
+{
+    if ((mouse_intf == -1) &&
+        (intf_class == HID_CLASS) &&
+        (intf_subclass == 0x01) &&
+        (intf_protocol == 0x02)) {
+        mouse_intf = intf_nb;
+        return true;
+    }
+    return false;
+}
+
+/*virtual*/ bool USBHostMouse::useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir) //Must return true if the endpoint will be used
+{
+    if (intf_nb == mouse_intf) {
+        if (type == INTERRUPT_ENDPOINT && dir == IN) {
+            mouse_device_found = true;
+            return true;
+        }
+    }
+    return false;
+}
+
+#endif
--- a/USBHostHID/USBHostMouse.h	Fri Jan 31 13:45:07 2014 +0000
+++ b/USBHostHID/USBHostMouse.h	Mon Feb 03 13:00:16 2014 +0000
@@ -1,88 +1,139 @@
-/* mbed USBHost Library
- * Copyright (c) 2006-2013 ARM Limited
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "USBHost.h"
-
-class USBHostMouse : public IUSBEnumerator {
-public:
-
-    /**
-    * Constructor
-    */
-    USBHostMouse();
-
-    /**
-     * Try to connect a mouse device
-     *
-     * @return true if connection was successful
-     */
-    bool connect();
-
-    /**
-    * Check if a mouse is connected
-    *
-    * @returns true if a mouse is connected
-    */
-    bool connected();
-
-    int readReport(uint8_t* data) {
-        int rc = host->interruptRead(dev, int_in, data, 4);
-        return rc == USB_TYPE_OK ? 4 : 0;
-    }
-    void attachEvent(void (*ptr)(uint8_t* data, int size)) {
-        if (ptr != NULL) {
-            onUpdate = ptr;
-        }
-    }
-    void poll() {
-        USB_TYPE rc = host->interruptRead(dev, int_in, report, sizeof(report));
-        if (rc == USB_TYPE_OK) {
-            if (onUpdate) {
-                (*onUpdate)(report, int_in->getLengthTransferred());
-            }
-        }
-    }
-
-protected:
-    //From IUSBEnumerator
-    virtual void setVidPid(uint16_t vid, uint16_t pid);
-    virtual bool parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol); //Must return true if the interface should be parsed
-    virtual bool useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir); //Must return true if the endpoint will be used
-
-private:
-    USBHost * host;
-    USBDeviceConnected * dev;
-    USBEndpoint * int_in;
-    uint8_t report[4];
-    
-    bool dev_connected;
-    bool mouse_device_found;
-    int mouse_intf;
-
-    uint8_t buttons;
-    int8_t x;
-    int8_t y;
-    int8_t z;
-
-    void (*onUpdate)(uint8_t* data, int size);
-    void (*onButtonUpdate)(uint8_t buttons);
-    void (*onXUpdate)(int8_t x);
-    void (*onYUpdate)(int8_t y);
-    void (*onZUpdate)(int8_t z);
-    int report_id;
-    void init();
-};
-
+/* mbed USBHost Library
+ * Copyright (c) 2006-2013 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef USBHOSTMOUSE_H
+#define USBHOSTMOUSE_H
+
+#include "USBHostConf.h"
+
+#if USBHOST_MOUSE
+
+#include "USBHost.h"
+
+/** 
+ * A class to communicate a USB mouse
+ */
+class USBHostMouse : public IUSBEnumerator {
+public:
+
+    /**
+    * Constructor
+    */
+    USBHostMouse();
+
+    /**
+     * Try to connect a mouse device
+     *
+     * @return true if connection was successful
+     */
+    bool connect();
+
+    /**
+    * Check if a mouse is connected
+    *
+    * @returns true if a mouse is connected
+    */
+    bool connected();
+
+    /**
+     * Attach a callback called when a mouse event is received
+     *
+     * @param ptr function pointer
+     */
+    inline void attachEvent(void (*ptr)(uint8_t buttons, int8_t x, int8_t y, int8_t z)) {
+        if (ptr != NULL) {
+            onUpdate = ptr;
+        }
+    }
+    
+    /**
+     * Attach a callback called when the button state changes
+     *
+     * @param ptr function pointer
+     */
+    inline void attachButtonEvent(void (*ptr)(uint8_t buttons)) {
+        if (ptr != NULL) {
+            onButtonUpdate = ptr;
+        }
+    }
+    
+    /**
+     * Attach a callback called when the X axis value changes
+     *
+     * @param ptr function pointer
+     */
+    inline void attachXEvent(void (*ptr)(int8_t x)) {
+        if (ptr != NULL) {
+            onXUpdate = ptr;
+        }
+    }
+    
+    /**
+     * Attach a callback called when the Y axis value changes
+     *
+     * @param ptr function pointer
+     */
+    inline void attachYEvent(void (*ptr)(int8_t y)) {
+        if (ptr != NULL) {
+            onYUpdate = ptr;
+        }
+    }
+    
+    /**
+     * Attach a callback called when the Z axis value changes (scrolling)
+     *
+     * @param ptr function pointer
+     */
+    inline void attachZEvent(void (*ptr)(int8_t z)) {
+        if (ptr != NULL) {
+            onZUpdate = ptr;
+        }
+    }
+
+protected:
+    //From IUSBEnumerator
+    virtual void setVidPid(uint16_t vid, uint16_t pid);
+    virtual bool parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol); //Must return true if the interface should be parsed
+    virtual bool useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir); //Must return true if the endpoint will be used
+
+private:
+    USBHost * host;
+    USBDeviceConnected * dev;
+    USBEndpoint * int_in;
+    uint8_t report[4];
+    
+    bool dev_connected;
+    bool mouse_device_found;
+    int mouse_intf;
+
+    uint8_t buttons;
+    int8_t x;
+    int8_t y;
+    int8_t z;
+
+    void rxHandler();
+    void (*onUpdate)(uint8_t buttons, int8_t x, int8_t y, int8_t z);
+    void (*onButtonUpdate)(uint8_t buttons);
+    void (*onXUpdate)(int8_t x);
+    void (*onYUpdate)(int8_t y);
+    void (*onZUpdate)(int8_t z);
+    int report_id;
+    void init();
+};
+
+#endif
+
+#endif
--- a/USBHostMSD/FATFileSystem.lib	Fri Jan 31 13:45:07 2014 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-http://mbed.org/users/mbed_official/code/FATFileSystem/#b6669c987c8e
--- a/USBHostMSD/USBHostMSD.cpp	Fri Jan 31 13:45:07 2014 +0000
+++ b/USBHostMSD/USBHostMSD.cpp	Mon Feb 03 13:00:16 2014 +0000
@@ -1,352 +1,356 @@
-/* mbed USBHost Library
- * Copyright (c) 2006-2013 ARM Limited
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "USBHostMSD.h"
-
-#define CBW_SIGNATURE   0x43425355
-#define CSW_SIGNATURE   0x53425355
-
-#define DEVICE_TO_HOST  0x80
-#define HOST_TO_DEVICE  0x00
-
-#define GET_MAX_LUN             (0xFE)
-#define BO_MASS_STORAGE_RESET   (0xFF)
-
-USBHostMSD::USBHostMSD(const char * rootdir) : FATFileSystem(rootdir)
-{
-    host = USBHost::getHostInst();
-    init();
-}
-
-void USBHostMSD::init() {
-    dev_connected = false;
-    dev = NULL;
-    bulk_in = NULL;
-    bulk_out = NULL;
-    dev_connected = false;
-    blockSize = 0;
-    blockCount = 0;
-    msd_intf = -1;
-    msd_device_found = false;
-    disk_init = false;
-    dev_connected = false;
-    nb_ep = 0;
-}
-
-bool USBHostMSD::connected()
-{
-    return dev_connected;
-}
-
-bool USBHostMSD::connect()
-{
-    if (dev_connected) {
-        return true;
-    }
-
-    for (uint8_t i = 0; i < MAX_DEVICE_CONNECTED; i++) {
-        if ((dev = host->getDevice(i)) != NULL) {
-            
-            //USB_DBG("Trying to connect MSD device dev=%p\n", dev);
-            
-            if(host->enumerate(dev, this))
-                break;
-
-            if (msd_device_found) {
-                bulk_in = dev->getEndpoint(msd_intf, BULK_ENDPOINT, IN);
-                bulk_out = dev->getEndpoint(msd_intf, BULK_ENDPOINT, OUT);
-                
-                if (!bulk_in || !bulk_out)
-                    continue;
-                
-                USB_INFO("New MSD device: VID:%04x PID:%04x [dev: %p - intf: %d]", dev->getVid(), dev->getPid(), dev, msd_intf);
-                dev->setName("MSD", msd_intf);
-                host->registerDriver(dev, msd_intf, this, &USBHostMSD::init);
-
-                dev_connected = true;
-                return true;
-            }
-        } //if()
-    } //for()
-    init();
-    return false;
-}
-
-/*virtual*/ void USBHostMSD::setVidPid(uint16_t vid, uint16_t pid)
-{
-    USB_DBG2("vid:%04x pid:%04x", vid, pid);
-    // we don't check VID/PID for MSD driver
-}
-
-/*virtual*/ bool USBHostMSD::parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol) //Must return true if the interface should be parsed
-{
-    USB_DBG2("intf: %d class: %02x %02x %02x", intf_nb, intf_class, intf_subclass, intf_protocol);
-
-    if ((msd_intf == -1) &&
-        (intf_class == MSD_CLASS) &&
-        (intf_subclass == 0x06) &&
-        (intf_protocol == 0x50)) {
-        msd_intf = intf_nb;
-        return true;
-    }
-    return false;
-}
-
-/*virtual*/ bool USBHostMSD::useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir) //Must return true if the endpoint will be used
-{
-    USB_DBG2("intf_nb=%d type=%d dir=%d", intf_nb, type, dir);
-    if (intf_nb == msd_intf) {
-        if (type == BULK_ENDPOINT) {
-            nb_ep++;
-            if (nb_ep == 2)
-                msd_device_found = true;
-            return true;
-        }
-    }
-    return false;
-}
-
-int USBHostMSD::testUnitReady() {
-    USB_DBG("Test unit ready");
-    return SCSITransfer(NULL, 6, DEVICE_TO_HOST, 0, 0);
-}
-
-
-int USBHostMSD::readCapacity() {
-    USB_DBG("Read capacity");
-    uint8_t cmd[10] = {0x25,0,0,0,0,0,0,0,0,0};
-    uint8_t result[8];
-    int status = SCSITransfer(cmd, 10, DEVICE_TO_HOST, result, 8);
-    if (status == 0) {
-        blockCount = (result[0] << 24) | (result[1] << 16) | (result[2] << 8) | result[3];
-        blockSize = (result[4] << 24) | (result[5] << 16) | (result[6] << 8) | result[7];
-        USB_INFO("MSD blockCount: %lld, blockSize: %d, Capacity: %lld\r\n", blockCount, blockSize, blockCount*blockSize);
-    }
-    return status;
-}
-
-
-int USBHostMSD::SCSIRequestSense() {
-    USB_DBG("Request sense");
-    uint8_t cmd[6] = {0x03,0,0,0,18,0};
-    uint8_t result[18];
-    int status = SCSITransfer(cmd, 6, DEVICE_TO_HOST, result, 18);
-    return status;
-}
-
-
-int USBHostMSD::inquiry(uint8_t lun, uint8_t page_code) {
-    USB_DBG("Inquiry");
-    uint8_t evpd = (page_code == 0) ? 0 : 1;
-    uint8_t cmd[6] = {0x12, (lun << 5) | evpd, page_code, 0, 36, 0};
-    uint8_t result[36];
-    int status = SCSITransfer(cmd, 6, DEVICE_TO_HOST, result, 36);
-    if (status == 0) {
-        char vid_pid[17];
-        memcpy(vid_pid, &result[8], 8);
-        vid_pid[8] = 0;
-        USB_INFO("MSD Vendor ID: %s", vid_pid);
-
-        memcpy(vid_pid, &result[16], 16);
-        vid_pid[16] = 0;
-        USB_INFO("MSD Product ID: %s", vid_pid);
-
-        memcpy(vid_pid, &result[32], 4);
-        vid_pid[4] = 0;
-        USB_INFO("MSD Product rev: %s", vid_pid);
-    }
-    return status;
-}
-
-int USBHostMSD::checkResult(uint8_t res, USBEndpoint * ep) {
-    // if ep stalled: send clear feature
-    if (res == USB_TYPE_STALL_ERROR) {
-        res = host->controlWrite(dev,
-                           USB_RECIPIENT_ENDPOINT | USB_HOST_TO_DEVICE | USB_REQUEST_TYPE_STANDARD,
-                           CLEAR_FEATURE,
-                           0, ep->getAddress(), NULL, 0);
-        // set state to IDLE if clear feature successful
-        if (res == USB_TYPE_OK) {
-            ep->setState(USB_TYPE_IDLE);
-        }
-    }
-
-    if (res != USB_TYPE_OK)
-        return -1;
-
-    return 0;
-}
-
-
-int USBHostMSD::SCSITransfer(uint8_t * cmd, uint8_t cmd_len, int flags, uint8_t * data, uint32_t transfer_len) {
-
-    int res = 0;
-
-    cbw.Signature = CBW_SIGNATURE;
-    cbw.Tag = 0;
-    cbw.DataLength = transfer_len;
-    cbw.Flags = flags;
-    cbw.LUN = 0;
-    cbw.CBLength = cmd_len;
-    memset(cbw.CB,0,sizeof(cbw.CB));
-    if (cmd) {
-        memcpy(cbw.CB,cmd,cmd_len);
-    }
-
-    // send the cbw
-    USB_DBG("Send CBW");
-    res = host->bulkWrite(dev, bulk_out,(uint8_t *)&cbw, 31);
-    if (checkResult(res, bulk_out))
-        return -1;
-
-    // data stage if needed
-    if (data) {
-        USB_DBG("data stage");
-        if (flags == HOST_TO_DEVICE) {
-            
-            res = host->bulkWrite(dev, bulk_out, data, transfer_len);
-            if (checkResult(res, bulk_out))
-                return -1;
-
-        } else if (flags == DEVICE_TO_HOST) {
-
-            res = host->bulkRead(dev, bulk_in, data, transfer_len);
-            if (checkResult(res, bulk_in))
-                return -1;
-        }
-    }
-
-    // status stage
-    csw.Signature = 0;
-    USB_DBG("Read CSW");
-    res = host->bulkRead(dev, bulk_in,(uint8_t *)&csw, 13);
-    if (checkResult(res, bulk_in))
-        return -1;
-
-    if (csw.Signature != CSW_SIGNATURE) {
-        return -1;
-    }
-    
-    USB_DBG("recv csw: status: %d", csw.Status);
-
-    // ModeSense?
-    if ((csw.Status == 1) && (cmd[0] != 0x03)) {
-        USB_DBG("request mode sense");
-        return SCSIRequestSense();
-    }
-    
-    // perform reset recovery
-    if ((csw.Status == 2) && (cmd[0] != 0x03)) {
-        
-        // send Bulk-Only Mass Storage Reset request
-        res = host->controlWrite(   dev,
-                              USB_RECIPIENT_INTERFACE | USB_HOST_TO_DEVICE | USB_REQUEST_TYPE_CLASS,
-                              BO_MASS_STORAGE_RESET,
-                              0, msd_intf, NULL, 0);
-        
-        // unstall both endpoints
-        res = host->controlWrite(   dev,
-                              USB_RECIPIENT_ENDPOINT | USB_HOST_TO_DEVICE | USB_REQUEST_TYPE_STANDARD,
-                              CLEAR_FEATURE,
-                              0, bulk_in->getAddress(), NULL, 0);
-        
-        res = host->controlWrite(   dev,
-                              USB_RECIPIENT_ENDPOINT | USB_HOST_TO_DEVICE | USB_REQUEST_TYPE_STANDARD,
-                              CLEAR_FEATURE,
-                              0, bulk_out->getAddress(), NULL, 0);
-        
-    }
-
-    return csw.Status;
-}
-
-
-int USBHostMSD::dataTransfer(uint8_t * buf, uint32_t block, uint8_t nbBlock, int direction) {
-    uint8_t cmd[10];
-    memset(cmd,0,10);
-    cmd[0] = (direction == DEVICE_TO_HOST) ? 0x28 : 0x2A;
-
-    cmd[2] = (block >> 24) & 0xff;
-    cmd[3] = (block >> 16) & 0xff;
-    cmd[4] = (block >> 8) & 0xff;
-    cmd[5] =  block & 0xff;
-
-    cmd[7] = (nbBlock >> 8) & 0xff;
-    cmd[8] = nbBlock & 0xff;
-
-    return SCSITransfer(cmd, 10, direction, buf, blockSize*nbBlock);
-}
-
-int USBHostMSD::getMaxLun() {
-    uint8_t buf[1], res;
-    res = host->controlRead(    dev, USB_RECIPIENT_INTERFACE | USB_DEVICE_TO_HOST | USB_REQUEST_TYPE_CLASS,
-                          0xfe, 0, msd_intf, buf, 1);
-    USB_DBG("max lun: %d", buf[0]);
-    return res;
-}
-
-int USBHostMSD::disk_initialize() {
-    USB_DBG("FILESYSTEM: init");
-    int i, timeout = 10;
-    
-    //getMaxLun();
-    
-    for (i = 0; i < timeout; i++) {
-        wait_ms(100);
-        if (!testUnitReady())
-            break;
-    }
-    
-    if (i == timeout) {
-        disk_init = false;
-        return -1;
-    }
-    
-    inquiry(0, 0);
-    disk_init = 1;
-    return readCapacity();
-}
-
-int USBHostMSD::disk_write(const uint8_t *buffer, uint64_t block_number) {
-    USB_DBG("FILESYSTEM: write block: %lld", block_number);
-    if (!disk_init) {
-        disk_initialize();
-    }
-    if (!disk_init)
-        return -1;
-    return dataTransfer((uint8_t *)buffer, block_number, 1, HOST_TO_DEVICE);
-}
-
-int USBHostMSD::disk_read(uint8_t * buffer, uint64_t block_number) {
-    USB_DBG("FILESYSTEM: read block %lld", block_number);
-    if (!disk_init) {
-        disk_initialize();
-    }
-    if (!disk_init)
-        return -1;
-    return dataTransfer((uint8_t *)buffer, block_number, 1, DEVICE_TO_HOST);
-}
-
-uint64_t USBHostMSD::disk_sectors() {
-    USB_DBG("FILESYSTEM: sectors");
-    if (!disk_init) {
-        disk_initialize();
-    }
-    if (!disk_init)
-        return 0;
-    return blockCount;
-}
-
+/* mbed USBHost Library
+ * Copyright (c) 2006-2013 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "USBHostMSD.h"
+
+#if USBHOST_MSD
+
+#include "dbg.h"
+
+#define CBW_SIGNATURE   0x43425355
+#define CSW_SIGNATURE   0x53425355
+
+#define DEVICE_TO_HOST  0x80
+#define HOST_TO_DEVICE  0x00
+
+#define GET_MAX_LUN             (0xFE)
+#define BO_MASS_STORAGE_RESET   (0xFF)
+
+USBHostMSD::USBHostMSD(const char * rootdir) : FATFileSystem(rootdir)
+{
+    host = USBHost::getHostInst();
+    init();
+}
+
+void USBHostMSD::init() {
+    dev_connected = false;
+    dev = NULL;
+    bulk_in = NULL;
+    bulk_out = NULL;
+    dev_connected = false;
+    blockSize = 0;
+    blockCount = 0;
+    msd_intf = -1;
+    msd_device_found = false;
+    disk_init = false;
+    dev_connected = false;
+    nb_ep = 0;
+}
+
+
+bool USBHostMSD::connected()
+{
+    return dev_connected;
+}
+
+bool USBHostMSD::connect()
+{
+
+    if (dev_connected) {
+        return true;
+    }
+
+    for (uint8_t i = 0; i < MAX_DEVICE_CONNECTED; i++) {
+        if ((dev = host->getDevice(i)) != NULL) {
+            
+            USB_DBG("Trying to connect MSD device\r\n");
+            
+            if(host->enumerate(dev, this))
+                break;
+
+            if (msd_device_found) {
+                bulk_in = dev->getEndpoint(msd_intf, BULK_ENDPOINT, IN);
+                bulk_out = dev->getEndpoint(msd_intf, BULK_ENDPOINT, OUT);
+                
+                if (!bulk_in || !bulk_out)
+                    continue;
+                
+                USB_INFO("New MSD device: VID:%04x PID:%04x [dev: %p - intf: %d]", dev->getVid(), dev->getPid(), dev, msd_intf);
+                dev->setName("MSD", msd_intf);
+                host->registerDriver(dev, msd_intf, this, &USBHostMSD::init);
+
+                dev_connected = true;
+                return true;
+            }
+        } //if()
+    } //for()
+    init();
+    return false;
+}
+
+/*virtual*/ void USBHostMSD::setVidPid(uint16_t vid, uint16_t pid)
+{
+    // we don't check VID/PID for MSD driver
+}
+
+/*virtual*/ bool USBHostMSD::parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol) //Must return true if the interface should be parsed
+{
+    if ((msd_intf == -1) &&
+        (intf_class == MSD_CLASS) &&
+        (intf_subclass == 0x06) &&
+        (intf_protocol == 0x50)) {
+        msd_intf = intf_nb;
+        return true;
+    }
+    return false;
+}
+
+/*virtual*/ bool USBHostMSD::useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir) //Must return true if the endpoint will be used
+{
+    if (intf_nb == msd_intf) {
+        if (type == BULK_ENDPOINT) {
+            nb_ep++;
+            if (nb_ep == 2)
+                msd_device_found = true;
+            return true;
+        }
+    }
+    return false;
+}
+
+
+int USBHostMSD::testUnitReady() {
+    USB_DBG("Test unit ready");
+    return SCSITransfer(NULL, 6, DEVICE_TO_HOST, 0, 0);
+}
+
+
+int USBHostMSD::readCapacity() {
+    USB_DBG("Read capacity");
+    uint8_t cmd[10] = {0x25,0,0,0,0,0,0,0,0,0};
+    uint8_t result[8];
+    int status = SCSITransfer(cmd, 10, DEVICE_TO_HOST, result, 8);
+    if (status == 0) {
+        blockCount = (result[0] << 24) | (result[1] << 16) | (result[2] << 8) | result[3];
+        blockSize = (result[4] << 24) | (result[5] << 16) | (result[6] << 8) | result[7];
+        USB_INFO("MSD [dev: %p] - blockCount: %lld, blockSize: %d, Capacity: %lld\r\n", dev, blockCount, blockSize, blockCount*blockSize);
+    }
+    return status;
+}
+
+
+int USBHostMSD::SCSIRequestSense() {
+    USB_DBG("Request sense");
+    uint8_t cmd[6] = {0x03,0,0,0,18,0};
+    uint8_t result[18];
+    int status = SCSITransfer(cmd, 6, DEVICE_TO_HOST, result, 18);
+    return status;
+}
+
+
+int USBHostMSD::inquiry(uint8_t lun, uint8_t page_code) {
+    USB_DBG("Inquiry");
+    uint8_t evpd = (page_code == 0) ? 0 : 1;
+    uint8_t cmd[6] = {0x12, uint8_t((lun << 5) | evpd), page_code, 0, 36, 0};
+    uint8_t result[36];
+    int status = SCSITransfer(cmd, 6, DEVICE_TO_HOST, result, 36);
+    if (status == 0) {
+        char vid_pid[17];
+        memcpy(vid_pid, &result[8], 8);
+        vid_pid[8] = 0;
+        USB_INFO("MSD [dev: %p] - Vendor ID: %s", dev, vid_pid);
+
+        memcpy(vid_pid, &result[16], 16);
+        vid_pid[16] = 0;
+        USB_INFO("MSD [dev: %p] - Product ID: %s", dev, vid_pid);
+
+        memcpy(vid_pid, &result[32], 4);
+        vid_pid[4] = 0;
+        USB_INFO("MSD [dev: %p] - Product rev: %s", dev, vid_pid);
+    }
+    return status;
+}
+
+int USBHostMSD::checkResult(uint8_t res, USBEndpoint * ep) {
+    // if ep stalled: send clear feature
+    if (res == USB_TYPE_STALL_ERROR) {
+        res = host->controlWrite(   dev,
+                                    USB_RECIPIENT_ENDPOINT | USB_HOST_TO_DEVICE | USB_REQUEST_TYPE_STANDARD,
+                                    CLEAR_FEATURE,
+                                    0, ep->getAddress(), NULL, 0);
+        // set state to IDLE if clear feature successful
+        if (res == USB_TYPE_OK) {
+            ep->setState(USB_TYPE_IDLE);
+        }
+    }
+
+    if (res != USB_TYPE_OK)
+        return -1;
+
+    return 0;
+}
+
+
+int USBHostMSD::SCSITransfer(uint8_t * cmd, uint8_t cmd_len, int flags, uint8_t * data, uint32_t transfer_len) {
+
+    int res = 0;
+
+    cbw.Signature = CBW_SIGNATURE;
+    cbw.Tag = 0;
+    cbw.DataLength = transfer_len;
+    cbw.Flags = flags;
+    cbw.LUN = 0;
+    cbw.CBLength = cmd_len;
+    memset(cbw.CB,0,sizeof(cbw.CB));
+    if (cmd) {
+        memcpy(cbw.CB,cmd,cmd_len);
+    }
+
+    // send the cbw
+    USB_DBG("Send CBW");
+    res = host->bulkWrite(dev, bulk_out,(uint8_t *)&cbw, 31);
+    if (checkResult(res, bulk_out))
+        return -1;
+
+    // data stage if needed
+    if (data) {
+        USB_DBG("data stage");
+        if (flags == HOST_TO_DEVICE) {
+            
+            res = host->bulkWrite(dev, bulk_out, data, transfer_len);
+            if (checkResult(res, bulk_out))
+                return -1;
+
+        } else if (flags == DEVICE_TO_HOST) {
+
+            res = host->bulkRead(dev, bulk_in, data, transfer_len);
+            if (checkResult(res, bulk_in))
+                return -1;
+        }
+    }
+
+    // status stage
+    csw.Signature = 0;
+    USB_DBG("Read CSW");
+    res = host->bulkRead(dev, bulk_in,(uint8_t *)&csw, 13);
+    if (checkResult(res, bulk_in))
+        return -1;
+
+    if (csw.Signature != CSW_SIGNATURE) {
+        return -1;
+    }
+    
+    USB_DBG("recv csw: status: %d", csw.Status);
+
+    // ModeSense?
+    if ((csw.Status == 1) && (cmd[0] != 0x03)) {
+        USB_DBG("request mode sense");
+        return SCSIRequestSense();
+    }
+    
+    // perform reset recovery
+    if ((csw.Status == 2) && (cmd[0] != 0x03)) {
+        
+        // send Bulk-Only Mass Storage Reset request
+        res = host->controlWrite(   dev,
+                                    USB_RECIPIENT_INTERFACE | USB_HOST_TO_DEVICE | USB_REQUEST_TYPE_CLASS,
+                                    BO_MASS_STORAGE_RESET,
+                                    0, msd_intf, NULL, 0);
+        
+        // unstall both endpoints
+        res = host->controlWrite(   dev,
+                                    USB_RECIPIENT_ENDPOINT | USB_HOST_TO_DEVICE | USB_REQUEST_TYPE_STANDARD,
+                                    CLEAR_FEATURE,
+                                    0, bulk_in->getAddress(), NULL, 0);
+        
+        res = host->controlWrite(   dev,
+                                    USB_RECIPIENT_ENDPOINT | USB_HOST_TO_DEVICE | USB_REQUEST_TYPE_STANDARD,
+                                    CLEAR_FEATURE,
+                                    0, bulk_out->getAddress(), NULL, 0);
+        
+    }
+
+    return csw.Status;
+}
+
+
+int USBHostMSD::dataTransfer(uint8_t * buf, uint32_t block, uint8_t nbBlock, int direction) {
+    uint8_t cmd[10];
+    memset(cmd,0,10);
+    cmd[0] = (direction == DEVICE_TO_HOST) ? 0x28 : 0x2A;
+
+    cmd[2] = (block >> 24) & 0xff;
+    cmd[3] = (block >> 16) & 0xff;
+    cmd[4] = (block >> 8) & 0xff;
+    cmd[5] =  block & 0xff;
+
+    cmd[7] = (nbBlock >> 8) & 0xff;
+    cmd[8] = nbBlock & 0xff;
+
+    return SCSITransfer(cmd, 10, direction, buf, blockSize*nbBlock);
+}
+
+int USBHostMSD::getMaxLun() {
+    uint8_t buf[1], res;
+    res = host->controlRead(    dev, USB_RECIPIENT_INTERFACE | USB_DEVICE_TO_HOST | USB_REQUEST_TYPE_CLASS,
+                                0xfe, 0, msd_intf, buf, 1);
+    USB_DBG("max lun: %d", buf[0]);
+    return res;
+}
+
+int USBHostMSD::disk_initialize() {
+    USB_DBG("FILESYSTEM: init");
+    /* U16 */int i, timeout = 10;
+    
+    getMaxLun();
+    
+    for (i = 0; i < timeout; i++) {
+        wait_ms(100); //Thread::wait(100);
+        if (!testUnitReady())
+            break;
+    }
+    
+    if (i == timeout) {
+        disk_init = false;
+        return -1;
+    }
+    
+    inquiry(0, 0);
+    disk_init = 1;
+    return readCapacity();
+}
+
+int USBHostMSD::disk_write(const uint8_t *buffer, uint64_t block_number) {
+    USB_DBG("FILESYSTEM: write block: %lld", block_number);
+    if (!disk_init) {
+        disk_initialize();
+    }
+    if (!disk_init)
+        return -1;
+    return dataTransfer((uint8_t *)buffer, block_number, 1, HOST_TO_DEVICE);
+}
+
+int USBHostMSD::disk_read(uint8_t * buffer, uint64_t block_number) {
+    USB_DBG("FILESYSTEM: read block %lld", block_number);
+    if (!disk_init) {
+        disk_initialize();
+    }
+    if (!disk_init)
+        return -1;
+    return dataTransfer((uint8_t *)buffer, block_number, 1, DEVICE_TO_HOST);
+}
+
+uint64_t USBHostMSD::disk_sectors() {
+    USB_DBG("FILESYSTEM: sectors");
+    if (!disk_init) {
+        disk_initialize();
+    }
+    if (!disk_init)
+        return 0;
+    return blockCount;
+}
+
+#endif
--- a/USBHostMSD/USBHostMSD.h	Fri Jan 31 13:45:07 2014 +0000
+++ b/USBHostMSD/USBHostMSD.h	Mon Feb 03 13:00:16 2014 +0000
@@ -1,131 +1,119 @@
-/* mbed USBHost Library
- * Copyright (c) 2006-2013 ARM Limited
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef USBHOSTMSD_H
-#define USBHOSTMSD_H
-
-#if _USB_DBG
-#define USB_DBG(...) do{fprintf(stderr,"[%s@%d] ",__PRETTY_FUNCTION__,__LINE__);fprintf(stderr,__VA_ARGS__);fprintf(stderr,"\r\n");} while(0);
-#else
-#define USB_DBG(...)  while(0);
-#endif
-
-#if 0
-#define USB_DBG2(...) do{fprintf(stderr,"[%s@%d] ",__PRETTY_FUNCTION__,__LINE__);fprintf(stderr,__VA_ARGS__);fprintf(stderr,"\r\n");} while(0);
-#else
-#define USB_DBG2(...)  while(0);
-#endif
-
-#if 1
-#define USB_INFO(...) do{fprintf(stderr,__VA_ARGS__);fprintf(stderr,"\r\n");}while(0);
-#else
-#define USB_INFO(...)  while(0);
-#endif
-
-#include "USBHostConf.h"
-#include "USBHost.h"
-#include "FATFileSystem.h"
-
-/** 
- * A class to communicate a USB flash disk
- */
-class USBHostMSD : public IUSBEnumerator, public FATFileSystem {
-public:
-    /**
-    * Constructor
-    *
-    * @param rootdir mount name
-    */
-    USBHostMSD(const char * rootdir);
-
-    /**
-    * Check if a MSD device is connected
-    *
-    * @return true if a MSD device is connected
-    */
-    bool connected();
-
-    /**
-     * Try to connect to a MSD device
-     *
-     * @return true if connection was successful
-     */
-    bool connect();
-
-protected:
-    //From IUSBEnumerator
-    virtual void setVidPid(uint16_t vid, uint16_t pid);
-    virtual bool parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol); //Must return true if the interface should be parsed
-    virtual bool useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir); //Must return true if the endpoint will be used
-
-    // From FATFileSystem
-    virtual int disk_initialize();
-    virtual int disk_status() {return 0;};
-    virtual int disk_read(uint8_t * buffer, uint64_t sector);
-    virtual int disk_write(const uint8_t * buffer, uint64_t sector);
-    virtual int disk_sync() {return 0;};
-    virtual uint64_t disk_sectors();
-
-private:
-    USBHost * host;
-    USBDeviceConnected * dev;
-    bool dev_connected;
-    USBEndpoint * bulk_in;
-    USBEndpoint * bulk_out;
-    uint8_t nb_ep;
-
-    // Bulk-only CBW
-    typedef __packed struct {
-        uint32_t Signature;
-        uint32_t Tag;
-        uint32_t DataLength;
-        uint8_t  Flags;
-        uint8_t  LUN;
-        uint8_t  CBLength;
-        uint8_t  CB[16];
-    } CBW;
-
-    // Bulk-only CSW
-    typedef __packed struct {
-        uint32_t Signature;
-        uint32_t Tag;
-        uint32_t DataResidue;
-        uint8_t  Status;
-    } CSW;
-
-    CBW cbw;
-    CSW csw;
-
-    int SCSITransfer(uint8_t * cmd, uint8_t cmd_len, int flags, uint8_t * data, uint32_t transfer_len);
-    int testUnitReady();
-    int readCapacity();
-    int inquiry(uint8_t lun, uint8_t page_code);
-    int SCSIRequestSense();
-    int dataTransfer(uint8_t * buf, uint32_t block, uint8_t nbBlock, int direction);
-    int checkResult(uint8_t res, USBEndpoint * ep);
-    int getMaxLun();
-
-    int blockSize;
-    uint64_t blockCount;
-
-    int msd_intf;
-    bool msd_device_found;
-    bool disk_init;
-    
-    void init();
-};
-
-#endif
+/* mbed USBHost Library
+ * Copyright (c) 2006-2013 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef USBHOSTMSD_H
+#define USBHOSTMSD_H
+
+#include "USBHostConf.h"
+
+#if USBHOST_MSD
+
+#include "USBHost.h"
+#include "FATFileSystem.h"
+
+/** 
+ * A class to communicate a USB flash disk
+ */
+class USBHostMSD : public IUSBEnumerator, public FATFileSystem {
+public:
+    /**
+    * Constructor
+    *
+    * @param rootdir mount name
+    */
+    USBHostMSD(const char * rootdir);
+
+    /**
+    * Check if a MSD device is connected
+    *
+    * @return true if a MSD device is connected
+    */
+    bool connected();
+
+    /**
+     * Try to connect to a MSD device
+     *
+     * @return true if connection was successful
+     */
+    bool connect();
+
+protected:
+    //From IUSBEnumerator
+    virtual void setVidPid(uint16_t vid, uint16_t pid);
+    virtual bool parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol); //Must return true if the interface should be parsed
+    virtual bool useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir); //Must return true if the endpoint will be used
+
+    // From FATFileSystem
+    virtual int disk_initialize();
+    virtual int disk_status() {return 0;};
+    virtual int disk_read(uint8_t * buffer, uint64_t sector);
+    virtual int disk_write(const uint8_t * buffer, uint64_t sector);
+    virtual int disk_sync() {return 0;};
+    virtual uint64_t disk_sectors();
+
+private:
+    USBHost * host;
+    USBDeviceConnected * dev;
+    bool dev_connected;
+    USBEndpoint * bulk_in;
+    USBEndpoint * bulk_out;
+    uint8_t nb_ep;
+
+    // Bulk-only CBW
+    typedef struct {
+        uint32_t Signature;
+        uint32_t Tag;
+        uint32_t DataLength;
+        uint8_t  Flags;
+        uint8_t  LUN;
+        uint8_t  CBLength;
+        uint8_t  CB[16];
+    } PACKED CBW;
+
+    // Bulk-only CSW
+    typedef struct {
+        uint32_t Signature;
+        uint32_t Tag;
+        uint32_t DataResidue;
+        uint8_t  Status;
+    } PACKED CSW;
+
+    CBW cbw;
+    CSW csw;
+
+    int SCSITransfer(uint8_t * cmd, uint8_t cmd_len, int flags, uint8_t * data, uint32_t transfer_len);
+    int testUnitReady();
+    int readCapacity();
+    int inquiry(uint8_t lun, uint8_t page_code);
+    int SCSIRequestSense();
+    int dataTransfer(uint8_t * buf, uint32_t block, uint8_t nbBlock, int direction);
+    int checkResult(uint8_t res, USBEndpoint * ep);
+    int getMaxLun();
+
+    int blockSize;
+    uint64_t blockCount;
+
+    int msd_intf;
+    bool msd_device_found;
+    bool disk_init;
+    
+    void init();
+
+};
+
+#endif
+
+#endif