USBHost library with fixes

Dependencies:   mbed-rtos FATFileSystem

Dependents:   mbedica

Files at this revision

API Documentation at this revision

Comitter:
zrussell3
Date:
Thu Dec 13 19:24:21 2018 +0000
Commit message:
Modified USBHost library to fix modifier input

Changed in this revision

FATFileSystem.lib Show annotated file Show diff for this revision Revisions of this file
USBHost/IUSBEnumerator.h 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.cpp 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/USBHALHost.h 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/USBHostTypes.h 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
USBHost3GModule/IUSBHostSerial.h Show annotated file Show diff for this revision Revisions of this file
USBHost3GModule/IUSBHostSerialListener.h Show annotated file Show diff for this revision Revisions of this file
USBHost3GModule/WANDongle.cpp Show annotated file Show diff for this revision Revisions of this file
USBHost3GModule/WANDongle.h Show annotated file Show diff for this revision Revisions of this file
USBHost3GModule/WANDongleInitializer.h Show annotated file Show diff for this revision Revisions of this file
USBHost3GModule/WANDongleSerialPort.cpp Show annotated file Show diff for this revision Revisions of this file
USBHost3GModule/WANDongleSerialPort.h Show annotated file 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
USBHostHub/USBHostHub.cpp Show annotated file Show diff for this revision Revisions of this file
USBHostHub/USBHostHub.h Show annotated file 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
USBHostSerial/MtxCircBuffer.h Show annotated file Show diff for this revision Revisions of this file
USBHostSerial/USBHostSerial.cpp Show annotated file Show diff for this revision Revisions of this file
USBHostSerial/USBHostSerial.h Show annotated file Show diff for this revision Revisions of this file
mbed-rtos.lib 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	Thu Dec 13 19:24:21 2018 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/FATFileSystem/#b6669c987c8e
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/IUSBEnumerator.h	Thu Dec 13 19:24:21 2018 +0000
@@ -0,0 +1,36 @@
+/* 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 IUSBENUMERATOR_H_
+#define IUSBENUMERATOR_H_
+
+#include "stdint.h"
+#include "USBEndpoint.h"
+
+/*
+Generic interface to implement for "smart" USB enumeration
+*/
+
+class IUSBEnumerator
+{
+public:
+    virtual void setVidPid(uint16_t vid, uint16_t pid) = 0;
+    virtual bool parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol) = 0; //Must return true if the interface should be parsed
+    virtual bool useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir) = 0; //Must return true if the endpoint will be used
+};
+
+#endif /*IUSBENUMERATOR_H_*/
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/USBDeviceConnected.cpp	Thu Dec 13 19:24:21 2018 +0000
@@ -0,0 +1,124 @@
+/* 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 "USBDeviceConnected.h"
+#include "dbg.h"
+
+USBDeviceConnected::USBDeviceConnected() {
+    init();
+}
+
+void USBDeviceConnected::init() {
+    hub_nb = 0;
+    port = 0;
+    vid = 0;
+    pid = 0;
+    nb_interf = 0;
+    enumerated = false;
+    activeAddr = false;
+    sizeControlEndpoint = 8;
+    device_class = 0;
+    device_subclass = 0;
+    proto = 0;
+    speed = 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");
+        }
+    }
+    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)) {
+        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;
+    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)) {
+        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;
+}
+
+void USBDeviceConnected::init(uint8_t hub_, uint8_t port_, bool lowSpeed_) {
+    USB_DBG("init dev: %p", this);
+    init();
+    hub_nb = hub_;
+    port = port_;
+    speed = lowSpeed_;
+}
+
+void USBDeviceConnected::disconnect() {
+    for(int i = 0; i < MAX_INTF; i++) {
+        intf[i].detach.call();
+    }
+    init();
+}
+
+
+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)) {
+            if(index) {
+                index--;
+            } else {
+                return intf[intf_nb].ep[i];
+            }
+        }
+    }
+    return NULL;
+}
+
+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];
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/USBDeviceConnected.h	Thu Dec 13 19:24:21 2018 +0000
@@ -0,0 +1,185 @@
+/* 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 USBDEVICECONNECTED_H
+#define USBDEVICECONNECTED_H
+
+#include "stdint.h"
+#include "USBEndpoint.h"
+#include "USBHostConf.h"
+#include "rtos.h"
+
+class USBHostHub;
+
+typedef struct {
+    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; 
+
+/**
+* USBDeviceConnected class
+*/
+class USBDeviceConnected
+{
+public:
+
+    /**
+    * Constructor
+    */
+    USBDeviceConnected();
+
+    /**
+    * Attach an USBEndpoint to this device
+    *
+    * @param intf_nb interface number
+    * @param ep pointeur on the USBEndpoint which will be attached
+    * @returns true if successful, false otherwise
+    */
+    bool addEndpoint(uint8_t intf_nb, USBEndpoint * ep);
+
+    /**
+    * Retrieve an USBEndpoint by its TYPE and DIRECTION
+    *
+    * @param intf_nb the interface on which to lookup the USBEndpoint
+    * @param type type of the USBEndpoint looked for
+    * @param dir direction of the USBEndpoint looked for
+    * @param index the index of the USBEndpoint whitin the interface
+    * @returns pointer on the USBEndpoint if found, NULL otherwise
+    */
+    USBEndpoint * getEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir, uint8_t index = 0);
+
+    /**
+    * Retrieve an USBEndpoint by its index
+    *
+    * @param intf_nb interface number
+    * @param index index of the USBEndpoint
+    * @returns pointer on the USBEndpoint if found, NULL otherwise
+    */
+    USBEndpoint * getEndpoint(uint8_t intf_nb, uint8_t index);
+
+    /**
+    * Add a new interface to this device
+    *
+    * @param intf_nb interface number
+    * @param intf_class interface class
+    * @param intf_subclass interface subclass
+    * @param intf_protocol interface protocol
+    * @returns true if successful, false otherwise
+    */
+    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);
+
+    /**
+     *  Attach a member function to call when a the device has been disconnected
+     *
+     *  @param intf_nb interface number
+     *  @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 onDisconnect(uint8_t intf_nb, T* tptr, void (T::*mptr)(void)) {
+        if ((mptr != NULL) && (tptr != NULL)) {
+            intf[intf_nb].detach.attach(tptr, mptr);
+        }
+    }
+
+    /**
+     * Attach a callback called when the device has been disconnected
+     *
+     *  @param intf_nb interface number
+     *  @param fn function pointer
+     */
+    inline void onDisconnect(uint8_t intf_nb, void (*fn)(void)) {
+        if (fn != NULL) {
+            intf[intf_nb].detach.attach(fn);
+        }
+    }
+
+    /**
+    * Disconnect the device by calling a callback function registered by a driver
+    */
+    void disconnect();
+
+    // setters
+    void init(uint8_t hub, uint8_t port, bool lowSpeed);
+    inline void setAddress(uint8_t addr_) { addr = addr_; };
+    inline void setVid(uint16_t vid_) { vid = vid_; };
+    inline void setPid(uint16_t pid_) { pid = pid_; };
+    inline void setClass(uint8_t device_class_) { device_class = device_class_; };
+    inline void setSubClass(uint8_t device_subclass_) { device_subclass = device_subclass_; };
+    inline void setProtocol(uint8_t pr) { proto = pr; };
+    inline void setSizeControlEndpoint(uint32_t size) { sizeControlEndpoint = size; };
+    inline void activeAddress(bool active) { activeAddr = active; };
+    inline void setEnumerated() { enumerated = true; };
+    inline void setNbIntf(uint8_t nb_intf) {nb_interf = nb_intf; };
+    inline void setHubParent(USBHostHub * hub) { hub_parent = hub; };
+    inline void setName(const char * name_, uint8_t intf_nb) { strcpy(intf[intf_nb].name, name_); };
+
+    //getters
+    inline uint8_t     getPort() { return port; };
+    inline uint8_t     getHub() { return hub_nb; };
+    inline uint8_t     getAddress() { return addr; };
+    inline uint16_t    getVid() { return vid; };
+    inline uint16_t    getPid() { return pid; };
+    inline uint8_t     getClass() { return device_class; };
+    inline uint8_t     getSubClass() { return device_subclass; };
+    inline uint8_t     getProtocol() { return proto; };
+    inline bool        getSpeed() { return speed; };
+    inline uint32_t    getSizeControlEndpoint() { return sizeControlEndpoint; };
+    inline bool        isActiveAddress() { return activeAddr; };
+    inline bool        isEnumerated() { return enumerated; };
+    inline USBHostHub * getHubParent() { return hub_parent; };
+    inline uint8_t      getNbIntf() { return nb_interf; };
+    inline const char * getName(uint8_t intf_nb) { return intf[intf_nb].name; };
+    
+    // in case this device is a hub
+    USBHostHub * hub;
+
+private:
+    USBHostHub * hub_parent;
+
+    INTERFACE intf[MAX_INTF];
+    uint32_t sizeControlEndpoint;
+    uint8_t hub_nb;
+    uint8_t port;
+    uint16_t vid;
+    uint16_t pid;
+    uint8_t addr;
+    uint8_t device_class;
+    uint8_t device_subclass;
+    uint8_t proto;
+    bool speed;
+    volatile bool activeAddr;
+    volatile bool enumerated;
+    uint8_t nb_interf;
+
+    void init();
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/USBEndpoint.cpp	Thu Dec 13 19:24:21 2018 +0000
@@ -0,0 +1,162 @@
+/* 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 "dbg.h"
+#include "USBEndpoint.h"
+
+void USBEndpoint::init(HCED * hced_, ENDPOINT_TYPE type_, ENDPOINT_DIRECTION dir_, uint32_t size, uint8_t ep_number, HCTD* td_list_[2])
+{
+    hced = hced_;
+    type = type_;
+    dir = dir_;
+    setup = (type == CONTROL_ENDPOINT) ? true : false;
+
+    //TDs have been allocated by the host
+    memcpy((HCTD**)td_list, td_list_, sizeof(HCTD*)*2); //TODO: Maybe should add a param for td_list size... at least a define
+    memset(td_list_[0], 0, sizeof(HCTD));
+    memset(td_list_[1], 0, sizeof(HCTD));
+    
+    td_list[0]->ep = this;
+    td_list[1]->ep = this;
+
+    hced->control = 0;
+    //Empty queue
+    hced->tailTD = td_list[0];
+    hced->headTD = td_list[0];
+    hced->nextED = 0;
+
+    address = (ep_number & 0x7F) | ((dir - 1) << 7);
+
+    hced->control = ((ep_number & 0x7F) << 7)                         // Endpoint address
+                    | (type != CONTROL_ENDPOINT ? ( dir << 11) : 0 )  // direction : Out = 1, 2 = In
+                    | ((size & 0x3ff) << 16);                         // MaxPkt Size
+
+    transfer_len = 0;
+    transferred = 0;
+    buf_start = 0;
+    nextEp = NULL;
+
+    td_current = td_list[0];
+    td_next = td_list[1];
+    
+    intf_nb = 0;
+
+    state = USB_TYPE_IDLE;
+}
+
+void USBEndpoint::setSize(uint32_t size)
+{
+    hced->control &= ~(0x3ff << 16);
+    hced->control |= (size << 16);
+}
+
+
+void USBEndpoint::setDeviceAddress(uint8_t addr)
+{
+    hced->control &= ~(0x7f);
+    hced->control |= (addr & 0x7F);
+}
+
+void USBEndpoint::setSpeed(uint8_t speed)
+{
+    hced->control &= ~(1 << 13);
+    hced->control |= (speed << 13);
+}
+
+//Only for control Eps
+void USBEndpoint::setNextToken(uint32_t token)
+{
+    switch (token) {
+        case TD_SETUP:
+            dir = OUT;
+            setup = true;
+            break;
+        case TD_IN:
+            dir = IN;
+            setup = false;
+            break;
+        case TD_OUT:
+            dir = OUT;
+            setup = false;
+            break;
+    }
+}
+
+struct {
+    USB_TYPE type;
+    const char * str;
+} static type_string[] = {
+/*0*/   {USB_TYPE_OK, "USB_TYPE_OK"},
+        {USB_TYPE_CRC_ERROR, "USB_TYPE_CRC_ERROR"},
+        {USB_TYPE_BIT_STUFFING_ERROR, "USB_TYPE_BIT_STUFFING_ERROR"},
+        {USB_TYPE_DATA_TOGGLE_MISMATCH_ERROR, "USB_TYPE_DATA_TOGGLE_MISMATCH_ERROR"},
+        {USB_TYPE_STALL_ERROR, "USB_TYPE_STALL_ERROR"},
+/*5*/   {USB_TYPE_DEVICE_NOT_RESPONDING_ERROR, "USB_TYPE_DEVICE_NOT_RESPONDING_ERROR"},
+        {USB_TYPE_PID_CHECK_FAILURE_ERROR, "USB_TYPE_PID_CHECK_FAILURE_ERROR"},
+        {USB_TYPE_UNEXPECTED_PID_ERROR, "USB_TYPE_UNEXPECTED_PID_ERROR"},
+        {USB_TYPE_DATA_OVERRUN_ERROR, "USB_TYPE_DATA_OVERRUN_ERROR"},
+        {USB_TYPE_DATA_UNDERRUN_ERROR, "USB_TYPE_DATA_UNDERRUN_ERROR"},
+/*10*/  {USB_TYPE_ERROR, "USB_TYPE_ERROR"},
+        {USB_TYPE_ERROR, "USB_TYPE_ERROR"},
+        {USB_TYPE_BUFFER_OVERRUN_ERROR, "USB_TYPE_BUFFER_OVERRUN_ERROR"},
+        {USB_TYPE_BUFFER_UNDERRUN_ERROR, "USB_TYPE_BUFFER_UNDERRUN_ERROR"},
+        {USB_TYPE_DISCONNECTED, "USB_TYPE_DISCONNECTED"},
+/*15*/  {USB_TYPE_FREE, "USB_TYPE_FREE"},
+        {USB_TYPE_IDLE, "USB_TYPE_IDLE"},
+        {USB_TYPE_PROCESSING, "USB_TYPE_PROCESSING"},
+        {USB_TYPE_ERROR, "USB_TYPE_ERROR"}
+};
+
+void USBEndpoint::setState(uint8_t st) {
+    if (st > 18)
+        return;
+    state = type_string[st].type;
+}
+
+
+const char * USBEndpoint::getStateString() {
+    return type_string[state].str;
+}
+
+void USBEndpoint::queueTransfer()
+{
+    transfer_len = (uint32_t)td_current->bufEnd - (uint32_t)td_current->currBufPtr + 1;
+    transferred = transfer_len;
+    buf_start = (uint8_t *)td_current->currBufPtr;
+
+    //Now add this free TD at this end of the queue
+    state = USB_TYPE_PROCESSING;
+    td_current->nextTD = td_next;
+    hced->tailTD = td_next;
+}
+
+void USBEndpoint::unqueueTransfer(volatile HCTD * td)
+{
+    td->control=0;
+    td->currBufPtr=0;
+    td->bufEnd=0;
+    td->nextTD=0;
+    hced->headTD = (HCTD *)((uint32_t)hced->tailTD | ((uint32_t)hced->headTD & 0x2)); //Carry bit
+    td_current = td_next;
+    td_next = td;
+}
+
+void USBEndpoint::queueEndpoint(USBEndpoint * ed)
+{
+    nextEp = ed;
+    hced->nextED = (ed == NULL) ? 0 : ed->getHCED();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/USBEndpoint.h	Thu Dec 13 19:24:21 2018 +0000
@@ -0,0 +1,171 @@
+/* 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 USBENDPOINT_H
+#define USBENDPOINT_H
+
+#include "FunctionPointer.h"
+#include "USBHostTypes.h"
+#include "rtos.h"
+
+class USBDeviceConnected;
+
+/**
+* USBEndpoint class
+*/
+class USBEndpoint
+{
+public:
+    /**
+    * Constructor
+    */
+    USBEndpoint() {
+        state = USB_TYPE_FREE;
+        nextEp = NULL;
+    };
+
+    /**
+    * Initialize an endpoint
+    *
+    * @param hced hced associated to the endpoint
+    * @param type endpoint type
+    * @param dir endpoint direction
+    * @param size endpoint size
+    * @param ep_number endpoint number
+    * @param td_list array of two allocated transfer descriptors
+    */
+    void init(HCED * hced, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir, uint32_t size, uint8_t ep_number, HCTD* td_list[2]);
+
+    /**
+    * Set next token. Warning: only useful for the control endpoint
+    *
+    * @param token IN, OUT or SETUP token
+    */
+    void setNextToken(uint32_t token);
+
+    /**
+    * Queue an endpoint
+    *
+    * @param endpoint endpoint which will be queued in the linked list
+    */
+    void queueEndpoint(USBEndpoint * endpoint);
+
+
+    /**
+    * Queue a transfer on the endpoint
+    */
+    void queueTransfer();
+
+    /**
+    * Unqueue a transfer from the endpoint
+    *
+    * @param td hctd which will be unqueued
+    */
+    void unqueueTransfer(volatile HCTD * td);
+
+    /**
+     *  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();
+    };
+
+
+    // setters
+    inline void setState(USB_TYPE st) { state = st; }
+    void setState(uint8_t st);
+    void setDeviceAddress(uint8_t addr);
+    inline void setLengthTransferred(int len) { transferred = len; };
+    void setSpeed(uint8_t speed);
+    void setSize(uint32_t size);
+    inline void setDir(ENDPOINT_DIRECTION d) { dir = d; }
+    inline void setIntfNb(uint8_t intf_nb_) { intf_nb = intf_nb_; };
+
+    // getters
+    const char *                getStateString();
+    inline USB_TYPE             getState() { return state; }
+    inline ENDPOINT_TYPE        getType() { return type; };
+    inline uint8_t              getDeviceAddress() { return hced->control & 0x7f; };
+    inline int                  getLengthTransferred() { return transferred; }
+    inline uint8_t *            getBufStart() { return buf_start; }
+    inline uint8_t              getAddress(){ return address; };
+    inline uint32_t             getSize() { return (hced->control >> 16) & 0x3ff; };
+    inline volatile HCTD *      getHeadTD() { return (volatile HCTD*) ((uint32_t)hced->headTD & ~0xF); };
+    inline volatile HCTD**      getTDList() { return td_list; };
+    inline volatile HCED *      getHCED() { return hced; };
+    inline ENDPOINT_DIRECTION   getDir() { return dir; }
+    inline volatile HCTD *      getProcessedTD() { return td_current; };
+    inline volatile HCTD*       getNextTD() { return td_current; };
+    inline bool                 isSetup() { return setup; }
+    inline USBEndpoint *        nextEndpoint() { return (USBEndpoint*)nextEp; };
+    inline uint8_t              getIntfNb() { return intf_nb; };
+    
+    USBDeviceConnected * dev;
+    
+    Queue<uint8_t, 1> ep_queue;
+
+private:
+    ENDPOINT_TYPE type;
+    volatile USB_TYPE state;
+    ENDPOINT_DIRECTION dir;
+    bool setup;
+
+    uint8_t address;
+
+    int transfer_len;
+    int transferred;
+    uint8_t * buf_start;
+
+    FunctionPointer rx;
+
+    USBEndpoint* nextEp;
+
+    // USBEndpoint descriptor
+    volatile HCED * hced;
+
+    volatile HCTD * td_list[2];
+    volatile HCTD * td_current;
+    volatile HCTD * td_next;
+    
+    uint8_t intf_nb;
+
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/USBHALHost.cpp	Thu Dec 13 19:24:21 2018 +0000
@@ -0,0 +1,322 @@
+/* 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 "mbed.h"
+#include "USBHALHost.h"
+#include "dbg.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 HCCA_SIZE sizeof(HCCA)
+#define ED_SIZE sizeof(HCED)
+#define TD_SIZE sizeof(HCTD)
+
+#define TOTAL_SIZE (HCCA_SIZE + (MAX_ENDPOINT*ED_SIZE) + (MAX_TD*TD_SIZE))
+
+static volatile uint8_t usb_buf[TOTAL_SIZE] __attribute((section("AHBSRAM1"),aligned(256)));  //256 bytes aligned!
+
+USBHALHost * USBHALHost::instHost;
+
+USBHALHost::USBHALHost() {
+    instHost = this;
+    memInit();
+    memset((void*)usb_hcca, 0, HCCA_SIZE);
+    for (int i = 0; i < MAX_ENDPOINT; i++) {
+        edBufAlloc[i] = false;
+    }
+    for (int i = 0; i < MAX_TD; i++) {
+        tdBufAlloc[i] = false;
+    }
+}
+
+void USBHALHost::init() {
+    NVIC_DisableIRQ(USB_IRQn);
+    
+    //Cut power
+    LPC_SC->PCONP &= ~(1UL<<31);
+    wait_ms(100);
+
+    // turn on power for USB
+    LPC_SC->PCONP       |= (1UL<<31);
+
+    // Enable USB host clock, port selection and AHB clock
+    LPC_USB->USBClkCtrl |= CLOCK_MASK;
+
+    // Wait for clocks to become available
+    while ((LPC_USB->USBClkSt & CLOCK_MASK) != CLOCK_MASK);
+
+    // it seems the bits[0:1] mean the following
+    // 0: U1=device, U2=host
+    // 1: U1=host, U2=host
+    // 2: reserved
+    // 3: U1=host, U2=device
+    // NB: this register is only available if OTG clock (aka "port select") is enabled!!
+    // since we don't care about port 2, set just bit 0 to 1 (U1=host)
+    LPC_USB->OTGStCtrl |= 1;
+
+    // now that we've configured the ports, we can turn off the portsel clock
+    LPC_USB->USBClkCtrl &= ~PORTSEL_CLK_EN;
+
+    // configure USB D+/D- pins
+    // P0[29] = USB_D+, 01
+    // P0[30] = USB_D-, 01
+    LPC_PINCON->PINSEL1 &= ~((3<<26) | (3<<28));
+    LPC_PINCON->PINSEL1 |=  ((1<<26) | (1<<28));
+
+    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
+
+    // Wait 100 ms before apply reset
+    wait_ms(100);
+
+    // software reset
+    LPC_USB->HcCommandStatus = OR_CMD_STATUS_HCR;
+    
+    // Write Fm Interval and Largest Data Packet Counter
+    LPC_USB->HcFmInterval    = DEFAULT_FMINTERVAL;
+    LPC_USB->HcPeriodicStart = FI * 90 / 100;
+
+    // Put HC in operational state
+    LPC_USB->HcControl  = (LPC_USB->HcControl & (~OR_CONTROL_HCFS)) | OR_CONTROL_HC_OPER;
+    // Set Global Power
+    LPC_USB->HcRhStatus = OR_RH_STATUS_LPSC;
+
+    LPC_USB->HcHCCA = (uint32_t)(usb_hcca);
+    
+    // Clear Interrrupt Status
+    LPC_USB->HcInterruptStatus |= LPC_USB->HcInterruptStatus;
+
+    LPC_USB->HcInterruptEnable  = OR_INTR_ENABLE_MIE | OR_INTR_ENABLE_WDH | OR_INTR_ENABLE_RHSC;
+
+    // Enable the USB Interrupt
+    NVIC_SetVector(USB_IRQn, (uint32_t)(_usbisr));
+    LPC_USB->HcRhPortStatus1 = OR_RH_PORT_CSC;
+    LPC_USB->HcRhPortStatus1 = OR_RH_PORT_PRSC;
+
+    NVIC_EnableIRQ(USB_IRQn);
+
+    // Check for any connected devices
+    if (LPC_USB->HcRhPortStatus1 & OR_RH_PORT_CCS) {
+        //Device connected
+        wait_ms(150);
+        USB_DBG("Device connected (%08x)\n\r", LPC_USB->HcRhPortStatus1);
+        deviceConnected(0, 1, LPC_USB->HcRhPortStatus1 & OR_RH_PORT_LSDA);
+    }
+}
+
+uint32_t USBHALHost::controlHeadED() {
+    return LPC_USB->HcControlHeadED;
+}
+
+uint32_t USBHALHost::bulkHeadED() {
+    return LPC_USB->HcBulkHeadED;
+}
+
+uint32_t USBHALHost::interruptHeadED() {
+    return usb_hcca->IntTable[0];
+}
+
+void USBHALHost::updateBulkHeadED(uint32_t addr) {
+    LPC_USB->HcBulkHeadED = addr;
+}
+
+
+void USBHALHost::updateControlHeadED(uint32_t addr) {
+    LPC_USB->HcControlHeadED = addr;
+}
+
+void USBHALHost::updateInterruptHeadED(uint32_t addr) {
+    usb_hcca->IntTable[0] = addr;
+}
+
+
+void USBHALHost::enableList(ENDPOINT_TYPE type) {
+    switch(type) {
+        case CONTROL_ENDPOINT:
+            LPC_USB->HcCommandStatus = OR_CMD_STATUS_CLF;
+            LPC_USB->HcControl |= OR_CONTROL_CLE;
+            break;
+        case ISOCHRONOUS_ENDPOINT:
+            break;
+        case BULK_ENDPOINT:
+            LPC_USB->HcCommandStatus = OR_CMD_STATUS_BLF;
+            LPC_USB->HcControl |= OR_CONTROL_BLE;
+            break;
+        case INTERRUPT_ENDPOINT:
+            LPC_USB->HcControl |= OR_CONTROL_PLE;
+            break;
+    }
+}
+
+
+bool USBHALHost::disableList(ENDPOINT_TYPE type) {
+    switch(type) {
+        case CONTROL_ENDPOINT:
+            if(LPC_USB->HcControl & OR_CONTROL_CLE) {
+                LPC_USB->HcControl &= ~OR_CONTROL_CLE;
+                return true;
+            }
+            return false;
+        case ISOCHRONOUS_ENDPOINT:
+            return false;
+        case BULK_ENDPOINT:
+            if(LPC_USB->HcControl & OR_CONTROL_BLE){
+                LPC_USB->HcControl &= ~OR_CONTROL_BLE;
+                return true;
+            }
+            return false;
+        case INTERRUPT_ENDPOINT:
+            if(LPC_USB->HcControl & OR_CONTROL_PLE) {
+                LPC_USB->HcControl &= ~OR_CONTROL_PLE;
+                return true;
+            }
+            return false;
+    }
+    return false;
+}
+
+
+void USBHALHost::memInit() {
+    usb_hcca = (volatile HCCA *)usb_buf;
+    usb_edBuf = usb_buf + HCCA_SIZE;
+    usb_tdBuf = usb_buf + HCCA_SIZE + (MAX_ENDPOINT*ED_SIZE);
+}
+
+volatile uint8_t * USBHALHost::getED() {
+    for (int i = 0; i < MAX_ENDPOINT; i++) {
+        if ( !edBufAlloc[i] ) {
+            edBufAlloc[i] = true;
+            return (volatile uint8_t *)(usb_edBuf + i*ED_SIZE);
+        }
+    }
+    perror("Could not allocate ED\r\n");
+    return NULL; //Could not alloc ED
+}
+
+volatile uint8_t * USBHALHost::getTD() {
+    int i;
+    for (i = 0; i < MAX_TD; i++) {
+        if ( !tdBufAlloc[i] ) {
+            tdBufAlloc[i] = true;
+            return (volatile uint8_t *)(usb_tdBuf + i*TD_SIZE);
+        }
+    }
+    perror("Could not allocate TD\r\n");
+    return NULL; //Could not alloc TD
+}
+
+
+void USBHALHost::freeED(volatile uint8_t * ed) {
+    int i;
+    i = (ed - usb_edBuf) / ED_SIZE;
+    edBufAlloc[i] = false;
+}
+
+void USBHALHost::freeTD(volatile uint8_t * td) {
+    int i;
+    i = (td - usb_tdBuf) / TD_SIZE;
+    tdBufAlloc[i] = false;
+}
+
+
+void USBHALHost::resetRootHub() {
+    // Initiate port reset
+    LPC_USB->HcRhPortStatus1 = OR_RH_PORT_PRS;
+    
+    while (LPC_USB->HcRhPortStatus1 & OR_RH_PORT_PRS);
+    
+    // ...and clear port reset signal
+    LPC_USB->HcRhPortStatus1 = OR_RH_PORT_PRSC;
+}
+
+
+void USBHALHost::_usbisr(void) {
+    if (instHost) {
+        instHost->UsbIrqhandler();
+    }
+}
+
+void USBHALHost::UsbIrqhandler() {
+    if( LPC_USB->HcInterruptStatus & LPC_USB->HcInterruptEnable ) //Is there something to actually process?
+    {
+        
+        uint32_t int_status = LPC_USB->HcInterruptStatus & LPC_USB->HcInterruptEnable;
+
+        // Root hub status change interrupt
+        if (int_status & OR_INTR_STATUS_RHSC) { 
+            if (LPC_USB->HcRhPortStatus1 & OR_RH_PORT_CSC) {
+                if (LPC_USB->HcRhStatus & OR_RH_STATUS_DRWE) {
+                    // When DRWE is on, Connect Status Change
+                    // means a remote wakeup event.
+                } else {
+
+                    //Root device connected
+                    if (LPC_USB->HcRhPortStatus1 & OR_RH_PORT_CCS) { 
+                        
+                        // wait 150ms to avoid bounce
+                        wait_ms(150);
+                        
+                        //Hub 0 (root hub), Port 1 (count starts at 1), Low or High speed
+                        deviceConnected(0, 1, LPC_USB->HcRhPortStatus1 & OR_RH_PORT_LSDA); 
+                    } 
+                    
+                    //Root device disconnected
+                    else { 
+                        
+                        if (!(int_status & OR_INTR_STATUS_WDH)) {
+                            usb_hcca->DoneHead = 0;
+                        }
+                        
+                        // wait 200ms to avoid bounce
+                        wait_ms(200);
+                        
+                        deviceDisconnected(0, 1, NULL, usb_hcca->DoneHead & 0xFFFFFFFE);
+                        
+                        if (int_status & OR_INTR_STATUS_WDH) {
+                            usb_hcca->DoneHead = 0;
+                            LPC_USB->HcInterruptStatus = OR_INTR_STATUS_WDH;
+                        }
+                    }
+                }
+                LPC_USB->HcRhPortStatus1 = OR_RH_PORT_CSC;
+            }
+            if (LPC_USB->HcRhPortStatus1 & OR_RH_PORT_PRSC) {
+                LPC_USB->HcRhPortStatus1 = OR_RH_PORT_PRSC;
+            }
+            LPC_USB->HcInterruptStatus = OR_INTR_STATUS_RHSC;
+        }
+
+        // Writeback Done Head interrupt
+        if (int_status & OR_INTR_STATUS_WDH) {
+            transferCompleted(usb_hcca->DoneHead & 0xFFFFFFFE);
+            LPC_USB->HcInterruptStatus = OR_INTR_STATUS_WDH;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/USBHALHost.h	Thu Dec 13 19:24:21 2018 +0000
@@ -0,0 +1,169 @@
+/* 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 USBHALHOST_H
+#define USBHALHOST_H
+
+#include "USBHostTypes.h"
+#include "USBHostConf.h"
+
+class USBHostHub;
+
+/**
+* USBHALHost class
+*/
+class USBHALHost {
+protected:
+
+    /**
+    * Constructor
+    * init variables and memory where will be stored HCCA, ED and TD
+    */
+    USBHALHost();
+    
+    /**
+    * Initialize host controller. Enable USB interrupts. This part is not in the constructor because, 
+    * this function calls a virtual method if a device is already connected
+    */
+    void init();
+    
+    /**
+    * reset the root hub
+    */
+    void resetRootHub();
+    
+    /**
+    * return the value contained in the control HEAD ED register
+    *
+    * @returns address of the control Head ED
+    */
+    uint32_t controlHeadED();
+    
+    /**
+    * return the value contained in the bulk HEAD ED register
+    *
+    * @returns address of the bulk head ED
+    */
+    uint32_t bulkHeadED();
+    
+    /**
+    * return the value of the head interrupt ED contained in the HCCA
+    *
+    * @returns address of the head interrupt ED contained in the HCCA
+    */
+    uint32_t interruptHeadED();
+    
+    /**
+    * Update the head ED for control transfers
+    */
+    void updateControlHeadED(uint32_t addr);
+    
+    /**
+    * Update the head ED for bulk transfers
+    */
+    void updateBulkHeadED(uint32_t addr);
+    
+    /**
+    * Update the head ED for interrupt transfers
+    */
+    void updateInterruptHeadED(uint32_t addr);
+    
+    /**
+    * Enable List for the specified endpoint type
+    *
+    * @param type enable the list of ENDPOINT_TYPE type
+    */
+    void enableList(ENDPOINT_TYPE type);
+    
+    /**
+    * Disable List for the specified endpoint type
+    *
+    * @param type disable the list of ENDPOINT_TYPE type
+    */
+    bool disableList(ENDPOINT_TYPE type);
+
+    /**
+    * Virtual method called when a device has been connected
+    *
+    * @param hub hub number of the device
+    * @param port port number of the device
+    * @param lowSpeed 1 if low speed, 0 otherwise
+    * @param hub_parent reference to the hub where the device is connected (NULL if the hub parent is the root hub)
+    */
+    virtual void deviceConnected(int hub, int port, bool lowSpeed, USBHostHub * hub_parent = NULL) = 0;
+    
+    /**
+    * Virtual method called when a device has been disconnected
+    *
+    * @param hub hub number of the device
+    * @param port port number of the device
+    * @param hub_parent reference to the hub where the device is connected (NULL if the hub parent is the root hub)
+    * @param addr list of the TDs which have been completed to dequeue freed TDs
+    */
+    virtual void deviceDisconnected(int hub, int port, USBHostHub * hub_parent, volatile uint32_t addr) = 0;
+    
+    /**
+    * Virtual method called when a transfer has been completed
+    *
+    * @param addr list of the TDs which have been completed
+    */
+    virtual void transferCompleted(volatile uint32_t addr) = 0;
+    
+    /**
+    * Find a memory section for a new ED
+    *
+    * @returns the address of the new ED
+    */
+    volatile uint8_t * getED();
+    
+    /**
+    * Find a memory section for a new TD
+    *
+    * @returns the address of the new TD
+    */
+    volatile uint8_t * getTD();
+    
+    /**
+    * Release a previous memory section reserved for an ED
+    *
+    * @param ed address of the ED
+    */
+    void freeED(volatile uint8_t * ed);
+    
+    /**
+    * Release a previous memory section reserved for an TD
+    *
+    * @param td address of the TD
+    */
+    void freeTD(volatile uint8_t * td);
+
+private:
+    static void _usbisr(void);
+    void UsbIrqhandler();
+
+    void memInit();
+
+    HCCA volatile * usb_hcca;           //256 bytes aligned
+    uint8_t volatile  * usb_edBuf;      //4 bytes aligned
+    uint8_t volatile  * usb_tdBuf;      //4 bytes aligned
+
+    static USBHALHost * instHost;
+    
+    bool volatile  edBufAlloc[MAX_ENDPOINT];
+    bool volatile tdBufAlloc[MAX_TD];
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/USBHost.cpp	Thu Dec 13 19:24:21 2018 +0000
@@ -0,0 +1,1161 @@
+/* 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"
+#include "USBHostHub.h"
+
+USBHost * USBHost::instHost = NULL;
+
+#define DEVICE_CONNECTED_EVENT      (1 << 0)
+#define DEVICE_DISCONNECTED_EVENT   (1 << 1)
+#define TD_PROCESSED_EVENT          (1 << 2)
+
+#define MAX_TRY_ENUMERATE_HUB       3
+
+#define MIN(a, b) ((a > b) ? b : a)
+
+/**
+* How interrupts are processed:
+*    - new device connected:
+*       - a message is queued in queue_usb_event with the id DEVICE_CONNECTED_EVENT
+*       - when the usb_thread receives the event, it:
+*           - resets the device
+*           - reads the device descriptor
+*           - sets the address of the device
+*           - if it is a hub, enumerates it
+*   - device disconnected:
+*       - a message is queued in queue_usb_event with the id DEVICE_DISCONNECTED_EVENT
+*       - when the usb_thread receives the event, it:
+*           - free the device and all its children (hub)
+*   - td processed
+*       - a message is queued in queue_usb_event with the id TD_PROCESSED_EVENT
+*       - when the usb_thread receives the event, it:
+*           - call the callback attached to the endpoint where the td is attached
+*/
+void USBHost::usb_process() {
+    
+    bool controlListState;
+    bool bulkListState;
+    bool interruptListState;
+    USBEndpoint * ep;
+    uint8_t i, j, res, timeout_set_addr = 10;
+    uint8_t buf[8];
+    bool too_many_hub;
+    int idx;
+
+#if DEBUG_TRANSFER
+    uint8_t * buf_transfer;
+#endif
+        
+#if MAX_HUB_NB
+    uint8_t k;
+#endif
+    
+    while(1) {
+        osEvent evt = mail_usb_event.get();
+        
+        if (evt.status == osEventMail) {
+            
+            message_t * usb_msg = (message_t*)evt.value.p;
+            
+            switch (usb_msg->event_id) {
+                
+                // a new device has been connected
+                case DEVICE_CONNECTED_EVENT:
+                    too_many_hub = false;
+                    buf[4] = 0;
+                
+                    usb_mutex.lock();
+                    
+                    for (i = 0; i < MAX_DEVICE_CONNECTED; i++) {
+                        if (!deviceInUse[i]) {
+                            USB_DBG_EVENT("new device connected: %p\r\n", &devices[i]);
+                            devices[i].init(usb_msg->hub, usb_msg->port, usb_msg->lowSpeed);
+                            deviceReset[i] = false;
+                            deviceInited[i] = true;
+                            break;
+                        }
+                    }
+                    
+                    if (i == MAX_DEVICE_CONNECTED) {
+                        USB_ERR("Too many device connected!!\r\n");
+                        usb_mutex.unlock();
+                        continue;
+                    }
+                    
+                    if (!controlEndpointAllocated) {
+                        control = newEndpoint(CONTROL_ENDPOINT, OUT, 0x08, 0x00);
+                        addEndpoint(NULL, 0, (USBEndpoint*)control);
+                        controlEndpointAllocated = true;
+                    }
+                    
+#if MAX_HUB_NB
+                    if (usb_msg->hub_parent)
+                        devices[i].setHubParent((USBHostHub *)(usb_msg->hub_parent));
+#endif
+                    
+                    for (j = 0; j < timeout_set_addr; j++) {
+                        
+                        resetDevice(&devices[i]);
+                        
+                        // set size of control endpoint
+                        devices[i].setSizeControlEndpoint(8);
+                        
+                        devices[i].activeAddress(false);
+                        
+                        // get first 8 bit of device descriptor
+                        // and check if we deal with a hub
+                        USB_DBG("usb_thread read device descriptor on dev: %p\r\n", &devices[i]);
+                        res = getDeviceDescriptor(&devices[i], buf, 8);
+                    
+                        if (res != USB_TYPE_OK) {
+                            USB_ERR("usb_thread could not read dev descr");
+                            continue;
+                        }
+                    
+                        // set size of control endpoint
+                        devices[i].setSizeControlEndpoint(buf[7]);
+                        
+                        // second step: set an address to the device
+                        res = setAddress(&devices[i], devices[i].getAddress());
+                    
+                        if (res != USB_TYPE_OK) {
+                            USB_ERR("SET ADDR FAILED");
+                            continue;
+                        }
+                        devices[i].activeAddress(true);
+                        USB_DBG("Address of %p: %d", &devices[i], devices[i].getAddress());
+                        
+                        // try to read again the device descriptor to check if the device
+                        // answers to its new address
+                        res = getDeviceDescriptor(&devices[i], buf, 8);
+                    
+                        if (res == USB_TYPE_OK) {
+                            break;
+                        }
+                        
+                        Thread::wait(100);
+                    }
+                    
+                    USB_INFO("New device connected: %p [hub: %d - port: %d]", &devices[i], usb_msg->hub, usb_msg->port);
+                    
+#if MAX_HUB_NB
+                    if (buf[4] == HUB_CLASS) {
+                        for (k = 0; k < MAX_HUB_NB; k++) {
+                            if (hub_in_use[k] == false) {
+                                for (uint8_t j = 0; j < MAX_TRY_ENUMERATE_HUB; j++) {
+                                    if (hubs[k].connect(&devices[i])) {
+                                        devices[i].hub = &hubs[k];
+                                        hub_in_use[k] = true;
+                                        break;
+                                    }
+                                }
+                                if (hub_in_use[k] == true)
+                                    break;
+                            }
+                        }
+                        
+                        if (k == MAX_HUB_NB) {
+                            USB_ERR("Too many hubs connected!!\r\n");
+                            too_many_hub = true;
+                        }
+                    }
+                    
+                    if (usb_msg->hub_parent)
+                        ((USBHostHub *)(usb_msg->hub_parent))->deviceConnected(&devices[i]);
+#endif
+                    
+                    if ((i < MAX_DEVICE_CONNECTED) && !too_many_hub) {
+                        deviceInUse[i] = true;
+                    }
+                    
+                    usb_mutex.unlock();
+                    
+                    break;
+                    
+                // a device has been disconnected
+                case DEVICE_DISCONNECTED_EVENT:
+                    
+                    usb_mutex.lock();
+                
+                    controlListState = disableList(CONTROL_ENDPOINT);
+                    bulkListState = disableList(BULK_ENDPOINT);
+                    interruptListState = disableList(INTERRUPT_ENDPOINT);
+                
+                    idx = findDevice(usb_msg->hub, usb_msg->port, (USBHostHub *)(usb_msg->hub_parent));
+                    if (idx != -1) {
+                        freeDevice((USBDeviceConnected*)&devices[idx]);
+                    }
+                    
+                    if (controlListState) enableList(CONTROL_ENDPOINT);
+                    if (bulkListState) enableList(BULK_ENDPOINT);
+                    if (interruptListState) enableList(INTERRUPT_ENDPOINT);
+                    
+                    usb_mutex.unlock();
+                    
+                    break;
+                    
+                // a td has been processed
+                // call callback on the ed associated to the td
+                // we are not in ISR -> users can use printf in their callback method
+                case TD_PROCESSED_EVENT:
+                    ep = (USBEndpoint *) ((HCTD *)usb_msg->td_addr)->ep;
+                    if (usb_msg->td_state == USB_TYPE_IDLE) {
+                        USB_DBG_EVENT("call callback on td %p [ep: %p state: %s - dev: %p - %s]", usb_msg->td_addr, ep, ep->getStateString(), ep->dev, ep->dev->getName(ep->getIntfNb()));
+
+#if DEBUG_TRANSFER
+                        if (ep->getDir() == IN) {
+                            buf_transfer = ep->getBufStart();
+                            printf("READ SUCCESS [%d bytes transferred - td: 0x%08X] on ep: [%p - addr: %02X]: ",  ep->getLengthTransferred(), usb_msg->td_addr, ep, ep->getAddress());
+                            for (int i = 0; i < ep->getLengthTransferred(); i++)
+                                printf("%02X ", buf_transfer[i]);
+                            printf("\r\n\r\n");
+                        }
+#endif
+                        ep->call();
+                    } else {
+                        idx = findDevice(ep->dev);
+                        if (idx != -1) {
+                            if (deviceInUse[idx]) {
+                                USB_WARN("td %p processed but not in idle state: %s [ep: %p - dev: %p - %s]", usb_msg->td_addr, ep->getStateString(), ep, ep->dev, ep->dev->getName(ep->getIntfNb()));
+                                ep->setState(USB_TYPE_IDLE);
+                            }
+                        }
+                    }
+                    break;
+            }
+            
+            mail_usb_event.free(usb_msg);
+        }
+    }
+}
+
+/* static */void USBHost::usb_process_static(void const * arg) {
+    ((USBHost *)arg)->usb_process();
+}
+
+USBHost::USBHost() : usbThread(USBHost::usb_process_static, (void *)this, osPriorityNormal, USB_THREAD_STACK)
+{
+    headControlEndpoint = NULL;
+    headBulkEndpoint = NULL;
+    headInterruptEndpoint = NULL;
+    tailControlEndpoint = NULL;
+    tailBulkEndpoint = NULL;
+    tailInterruptEndpoint = NULL;
+
+    lenReportDescr = 0;
+
+    controlEndpointAllocated = false;
+
+    for (uint8_t i = 0; i < MAX_DEVICE_CONNECTED; i++) {
+        deviceInUse[i] = false;
+        devices[i].setAddress(i + 1);
+        deviceReset[i] = false;
+        deviceInited[i] = false;
+        for (uint8_t j = 0; j < MAX_INTF; j++)
+            deviceAttachedDriver[i][j] = false;
+    }
+    
+#if MAX_HUB_NB
+    for (uint8_t i = 0; i < MAX_HUB_NB; i++) {
+        hubs[i].setHost(this);
+        hub_in_use[i] = false;
+    }
+#endif
+}
+
+
+void USBHost::transferCompleted(volatile uint32_t addr)
+{
+    uint8_t state;
+
+    if(addr == 0)
+        return;
+
+    volatile HCTD* tdList = NULL;
+
+    //First we must reverse the list order and dequeue each TD
+    do {
+        volatile HCTD* td = (volatile HCTD*)addr;
+        addr = (uint32_t)td->nextTD; //Dequeue from physical list
+        td->nextTD = tdList; //Enqueue into reversed list
+        tdList = td;
+    } while(addr);
+
+    while(tdList != NULL) {
+        volatile HCTD* td = tdList;
+        tdList = (volatile HCTD*)td->nextTD; //Dequeue element now as it could be modified below
+        if (td->ep != NULL) {
+            USBEndpoint * ep = (USBEndpoint *)(td->ep);
+            
+            if (((HCTD *)td)->control >> 28) {
+                state = ((HCTD *)td)->control >> 28;
+            } else {
+                if (td->currBufPtr)
+                    ep->setLengthTransferred((uint32_t)td->currBufPtr - (uint32_t)ep->getBufStart());
+                state = 16 /*USB_TYPE_IDLE*/;
+            }
+            
+            ep->unqueueTransfer(td);
+            
+            if (ep->getType() != CONTROL_ENDPOINT) {
+                // callback on the processed td will be called from the usb_thread (not in ISR)
+                message_t * usb_msg = mail_usb_event.alloc();
+                usb_msg->event_id = TD_PROCESSED_EVENT;
+                usb_msg->td_addr = (void *)td;
+                usb_msg->td_state = state;
+                mail_usb_event.put(usb_msg);
+            }
+            ep->setState(state);
+            ep->ep_queue.put((uint8_t*)1);
+        }
+    }
+}
+
+USBHost * USBHost::getHostInst()
+{
+    if (instHost == NULL) {
+        instHost = new USBHost();
+        instHost->init();
+    }
+    return instHost;
+}
+
+
+/*
+ * Called when a device has been connected
+ * Called in ISR!!!! (no printf)
+ */
+/* virtual */ void USBHost::deviceConnected(int hub, int port, bool lowSpeed, USBHostHub * hub_parent)
+{
+    // be sure that the new device connected is not already connected...
+    int idx = findDevice(hub, port, hub_parent);
+    if (idx != -1) {
+        if (deviceInited[idx])
+            return;
+    }
+    
+    message_t * usb_msg = mail_usb_event.alloc();
+    usb_msg->event_id = DEVICE_CONNECTED_EVENT;
+    usb_msg->hub = hub;
+    usb_msg->port = port;
+    usb_msg->lowSpeed = lowSpeed;
+    usb_msg->hub_parent = hub_parent;
+    mail_usb_event.put(usb_msg);
+}
+
+/*
+ * Called when a device has been disconnected
+ * Called in ISR!!!! (no printf)
+ */
+/* virtual */ void USBHost::deviceDisconnected(int hub, int port, USBHostHub * hub_parent, volatile uint32_t addr)
+{
+    // be sure that the device disconnected is connected...
+    int idx = findDevice(hub, port, hub_parent);
+    if (idx != -1) {
+        if (!deviceInUse[idx])
+            return;
+    } else {
+        return;
+    }
+    
+    message_t * usb_msg = mail_usb_event.alloc();
+    usb_msg->event_id = DEVICE_DISCONNECTED_EVENT;
+    usb_msg->hub = hub;
+    usb_msg->port = port;
+    usb_msg->hub_parent = hub_parent;
+    mail_usb_event.put(usb_msg);
+}
+
+void USBHost::freeDevice(USBDeviceConnected * dev)
+{
+    USBEndpoint * ep = NULL;
+    HCED * ed = NULL;
+    
+#if MAX_HUB_NB
+    if (dev->getClass() == HUB_CLASS) {
+        if (dev->hub == NULL) {
+            USB_ERR("HUB NULL!!!!!\r\n");
+        } else {
+            dev->hub->hubDisconnected();
+            for (uint8_t i = 0; i < MAX_HUB_NB; i++) {
+                if (dev->hub == &hubs[i]) {
+                    hub_in_use[i] = false;
+                    break;
+                }
+            }
+        }
+    }
+    
+    // notify hub parent that this device has been disconnected
+    if (dev->getHubParent())
+        dev->getHubParent()->deviceDisconnected(dev);
+    
+#endif
+    
+    int idx = findDevice(dev);
+    if (idx != -1) {
+        deviceInUse[idx] = false;
+        deviceReset[idx] = false;
+
+        for (uint8_t j = 0; j < MAX_INTF; j++) {
+            deviceAttachedDriver[idx][j] = false;
+            if (dev->getInterface(j) != NULL) {
+                USB_DBG("FREE INTF %d on dev: %p, %p, nb_endpot: %d, %s", j, (void *)dev->getInterface(j), dev, dev->getInterface(j)->nb_endpoint, dev->getName(j));
+                for (int i = 0; i < dev->getInterface(j)->nb_endpoint; i++) {
+                    if ((ep = dev->getEndpoint(j, i)) != NULL) {
+                        ed = (HCED *)ep->getHCED();
+                        ed->control |= (1 << 14); //sKip bit
+                        unqueueEndpoint(ep);
+
+                        freeTD((volatile uint8_t*)ep->getTDList()[0]);
+                        freeTD((volatile uint8_t*)ep->getTDList()[1]);
+
+                        freeED((uint8_t *)ep->getHCED());
+                    }
+                    printList(BULK_ENDPOINT);
+                    printList(INTERRUPT_ENDPOINT);
+                }
+                USB_INFO("Device disconnected [%p - %s - hub: %d - port: %d]", dev, dev->getName(j), dev->getHub(), dev->getPort());
+            }
+        }
+        dev->disconnect();
+    }
+}
+
+
+void USBHost::unqueueEndpoint(USBEndpoint * ep)
+{
+    USBEndpoint * prec = NULL;
+    USBEndpoint * current = NULL;
+
+    for (int i = 0; i < 2; i++) {
+        current = (i == 0) ? (USBEndpoint*)headBulkEndpoint : (USBEndpoint*)headInterruptEndpoint;
+        prec = current;
+        while (current != NULL) {
+            if (current == ep) {
+                if (current->nextEndpoint() != NULL) {
+                    prec->queueEndpoint(current->nextEndpoint());
+                    if (current == headBulkEndpoint) {
+                        updateBulkHeadED((uint32_t)current->nextEndpoint()->getHCED());
+                        headBulkEndpoint = current->nextEndpoint();
+                    } else if (current == headInterruptEndpoint) {
+                        updateInterruptHeadED((uint32_t)current->nextEndpoint()->getHCED());
+                        headInterruptEndpoint = current->nextEndpoint();
+                    }
+                }
+                // here we are dequeuing the queue of ed
+                // we need to update the tail pointer
+                else {
+                    prec->queueEndpoint(NULL);
+                    if (current == headBulkEndpoint) {
+                        updateBulkHeadED(0);
+                        headBulkEndpoint = current->nextEndpoint();
+                    } else if (current == headInterruptEndpoint) {
+                        updateInterruptHeadED(0);
+                        headInterruptEndpoint = current->nextEndpoint();
+                    }
+                    
+                    // modify tail
+                    switch (current->getType()) {
+                        case BULK_ENDPOINT:
+                            tailBulkEndpoint = prec;
+                            break;
+                        case INTERRUPT_ENDPOINT:
+                            tailInterruptEndpoint = prec;
+                            break;
+                        default:
+                            break;
+                    }
+                }
+                current->setState(USB_TYPE_FREE);
+                return;
+            }
+            prec = current;
+            current = current->nextEndpoint();
+        }
+    }
+}
+
+
+USBDeviceConnected * USBHost::getDevice(uint8_t index)
+{
+    if ((index >= MAX_DEVICE_CONNECTED) || (!deviceInUse[index])) {
+        return NULL;
+    }
+    return (USBDeviceConnected*)&devices[index];
+}
+
+// create an USBEndpoint descriptor. the USBEndpoint is not linked
+USBEndpoint * USBHost::newEndpoint(ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir, uint32_t size, uint8_t addr)
+{
+    int i = 0;
+    HCED * ed = (HCED *)getED();
+    HCTD* td_list[2] = { (HCTD*)getTD(), (HCTD*)getTD() };
+
+    memset((void *)td_list[0], 0x00, sizeof(HCTD));
+    memset((void *)td_list[1], 0x00, sizeof(HCTD));
+
+    // search a free USBEndpoint
+    for (i = 0; i < MAX_ENDPOINT; i++) {
+        if (endpoints[i].getState() == USB_TYPE_FREE) {
+            endpoints[i].init(ed, type, dir, size, addr, td_list);
+            USB_DBG("USBEndpoint created (%p): type: %d, dir: %d, size: %d, addr: %d, state: %s", &endpoints[i], type, dir, size, addr, endpoints[i].getStateString());
+            return &endpoints[i];
+        }
+    }
+    USB_ERR("could not allocate more endpoints!!!!");
+    return NULL;
+}
+
+
+USB_TYPE USBHost::resetDevice(USBDeviceConnected * dev)
+{
+    int index = findDevice(dev);
+    if (index != -1) {
+        USB_DBG("Resetting hub %d, port %d\n", dev->getHub(), dev->getPort());
+        Thread::wait(100);
+        if (dev->getHub() == 0) {
+            resetRootHub();
+        }
+#if MAX_HUB_NB
+        else {
+            dev->getHubParent()->portReset(dev->getPort());
+        }
+#endif
+        Thread::wait(100);
+        deviceReset[index] = true;
+        return USB_TYPE_OK;
+    }
+    
+    return USB_TYPE_ERROR;
+}
+
+// link the USBEndpoint to the linked list and attach an USBEndpoint to a device
+bool USBHost::addEndpoint(USBDeviceConnected * dev, uint8_t intf_nb, USBEndpoint * ep)
+{
+
+    if (ep == NULL) {
+        return false;
+    }
+
+    HCED * prevEd;
+
+    // set device address in the USBEndpoint descriptor
+    if (dev == NULL) {
+        ep->setDeviceAddress(0);
+    } else {
+        ep->setDeviceAddress(dev->getAddress());
+    }
+
+    if ((dev != NULL) && dev->getSpeed()) {
+        ep->setSpeed(dev->getSpeed());
+    }
+    
+    ep->setIntfNb(intf_nb);
+
+    // queue the new USBEndpoint on the ED list
+    switch (ep->getType()) {
+
+        case CONTROL_ENDPOINT:
+            prevEd = ( HCED*) controlHeadED();
+            if (!prevEd) {
+                updateControlHeadED((uint32_t) ep->getHCED());
+                USB_DBG_TRANSFER("First control USBEndpoint: %08X", (uint32_t) ep->getHCED());
+                headControlEndpoint = ep;
+                tailControlEndpoint = ep;
+                return true;
+            }
+            tailControlEndpoint->queueEndpoint(ep);
+            tailControlEndpoint = ep;
+            return true;
+
+        case BULK_ENDPOINT:
+            prevEd = ( HCED*) bulkHeadED();
+            if (!prevEd) {
+                updateBulkHeadED((uint32_t) ep->getHCED());
+                USB_DBG_TRANSFER("First bulk USBEndpoint: %08X\r\n", (uint32_t) ep->getHCED());
+                headBulkEndpoint = ep;
+                tailBulkEndpoint = ep;
+                break;
+            }
+            USB_DBG_TRANSFER("Queue BULK Ed %p after %p\r\n",ep->getHCED(), prevEd);
+            tailBulkEndpoint->queueEndpoint(ep);
+            tailBulkEndpoint = ep;
+            break;
+
+        case INTERRUPT_ENDPOINT:
+            prevEd = ( HCED*) interruptHeadED();
+            if (!prevEd) {
+                updateInterruptHeadED((uint32_t) ep->getHCED());
+                USB_DBG_TRANSFER("First interrupt USBEndpoint: %08X\r\n", (uint32_t) ep->getHCED());
+                headInterruptEndpoint = ep;
+                tailInterruptEndpoint = ep;
+                break;
+            }
+            USB_DBG_TRANSFER("Queue INTERRUPT Ed %p after %p\r\n",ep->getHCED(), prevEd);
+            tailInterruptEndpoint->queueEndpoint(ep);
+            tailInterruptEndpoint = ep;
+            break;
+        default:
+            return false;
+    }
+    
+    ep->dev = dev;
+    dev->addEndpoint(intf_nb, ep);
+
+    return true;
+}
+
+
+int USBHost::findDevice(USBDeviceConnected * dev)
+{
+    for (int i = 0; i < MAX_DEVICE_CONNECTED; i++) {
+        if (dev == &devices[i]) {
+            return i;
+        }
+    }
+    return -1;
+}
+
+int USBHost::findDevice(uint8_t hub, uint8_t port, USBHostHub * hub_parent)
+{
+    for (int i = 0; i < MAX_DEVICE_CONNECTED; i++) {
+        if (devices[i].getHub() == hub && devices[i].getPort() == port) {
+            if (hub_parent != NULL) {
+                if (hub_parent == devices[i].getHubParent())
+                    return i;
+            } else {
+                return i;
+            }
+        }
+    }
+    return -1;
+}
+
+void USBHost::printList(ENDPOINT_TYPE type)
+{
+#if DEBUG_EP_STATE
+    volatile HCED * hced;
+    switch(type) {
+        case CONTROL_ENDPOINT:
+            hced = (HCED *)controlHeadED();
+            break;
+        case BULK_ENDPOINT:
+            hced = (HCED *)bulkHeadED();
+            break;
+        case INTERRUPT_ENDPOINT:
+            hced = (HCED *)interruptHeadED();
+            break;
+    }
+    volatile HCTD * hctd = NULL;
+    const char * type_str = (type == BULK_ENDPOINT) ? "BULK" :
+                            ((type == INTERRUPT_ENDPOINT) ? "INTERRUPT" :
+                            ((type == CONTROL_ENDPOINT) ? "CONTROL" : "ISOCHRONOUS"));
+    printf("State of %s:\r\n", type_str);
+    while (hced != NULL) {
+        uint8_t dir = ((hced->control & (3 << 11)) >> 11);
+        printf("hced: %p [ADDR: %d, DIR: %s, EP_NB: 0x%X]\r\n", hced,
+                                                   hced->control & 0x7f,
+                                                   (dir == 1) ? "OUT" : ((dir == 0) ? "FROM_TD":"IN"),
+                                                    (hced->control & (0xf << 7)) >> 7);
+        hctd = (HCTD *)((uint32_t)(hced->headTD) & ~(0xf));
+        while (hctd != hced->tailTD) {
+            printf("\thctd: %p [DIR: %s]\r\n", hctd, ((hctd->control & (3 << 19)) >> 19) == 1 ? "OUT" : "IN");
+            hctd = hctd->nextTD;
+        }
+        printf("\thctd: %p\r\n", hctd);
+        hced = hced->nextED;
+    }
+    printf("\r\n\r\n");
+#endif
+}
+
+
+// add a transfer on the TD linked list
+USB_TYPE USBHost::addTransfer(USBEndpoint * ed, uint8_t * buf, uint32_t len)
+{
+    td_mutex.lock();
+
+    // allocate a TD which will be freed in TDcompletion
+    volatile HCTD * td = ed->getNextTD();
+    if (td == NULL) {
+        return USB_TYPE_ERROR;
+    }
+
+    uint32_t token = (ed->isSetup() ? TD_SETUP : ( (ed->getDir() == IN) ? TD_IN : TD_OUT ));
+
+    uint32_t td_toggle;
+
+    if (ed->getType() == CONTROL_ENDPOINT) {
+        if (ed->isSetup()) {
+            td_toggle = TD_TOGGLE_0;
+        } else {
+            td_toggle = TD_TOGGLE_1;
+        }
+    } else {
+        td_toggle = 0;
+    }
+
+    td->control      = (TD_ROUNDING | token | TD_DELAY_INT(0) | td_toggle | TD_CC);
+    td->currBufPtr   = buf;
+    td->bufEnd       = (buf + (len - 1));
+
+    ENDPOINT_TYPE type = ed->getType();
+
+    disableList(type);
+    ed->queueTransfer();
+    printList(type);
+    enableList(type);
+    
+    td_mutex.unlock();
+
+    return USB_TYPE_PROCESSING;
+}
+
+
+
+USB_TYPE USBHost::getDeviceDescriptor(USBDeviceConnected * dev, uint8_t * buf, uint16_t max_len_buf, uint16_t * len_dev_descr)
+{
+    USB_TYPE t = controlRead(  dev,
+                         USB_DEVICE_TO_HOST | USB_RECIPIENT_DEVICE,
+                         GET_DESCRIPTOR,
+                         (DEVICE_DESCRIPTOR << 8) | (0),
+                         0, buf, MIN(DEVICE_DESCRIPTOR_LENGTH, max_len_buf));
+    if (len_dev_descr)
+        *len_dev_descr = MIN(DEVICE_DESCRIPTOR_LENGTH, max_len_buf);
+    
+    return t;
+}
+
+USB_TYPE USBHost::getConfigurationDescriptor(USBDeviceConnected * dev, uint8_t * buf, uint16_t max_len_buf, uint16_t * len_conf_descr)
+{
+    USB_TYPE res;
+    uint16_t total_conf_descr_length = 0;
+
+    // fourth step: get the beginning of the configuration descriptor to have the total length of the conf descr
+    res = controlRead(  dev,
+                        USB_DEVICE_TO_HOST | USB_RECIPIENT_DEVICE,
+                        GET_DESCRIPTOR,
+                        (CONFIGURATION_DESCRIPTOR << 8) | (0),
+                        0, buf, CONFIGURATION_DESCRIPTOR_LENGTH);
+
+    if (res != USB_TYPE_OK) {
+        USB_ERR("GET CONF 1 DESCR FAILED");
+        return res;
+    }
+    total_conf_descr_length = buf[2] | (buf[3] << 8);
+    total_conf_descr_length = MIN(max_len_buf, total_conf_descr_length);
+    
+    if (len_conf_descr)
+        *len_conf_descr = total_conf_descr_length;
+    
+    USB_DBG("TOTAL_LENGTH: %d \t NUM_INTERF: %d", total_conf_descr_length, buf[4]);
+
+    return controlRead(  dev,
+                         USB_DEVICE_TO_HOST | USB_RECIPIENT_DEVICE,
+                         GET_DESCRIPTOR,
+                         (CONFIGURATION_DESCRIPTOR << 8) | (0),
+                         0, buf, total_conf_descr_length);
+}
+
+
+USB_TYPE USBHost::setAddress(USBDeviceConnected * dev, uint8_t address) {
+    return controlWrite(    dev,
+                            USB_HOST_TO_DEVICE | USB_RECIPIENT_DEVICE,
+                            SET_ADDRESS,
+                            address,
+                            0, NULL, 0);
+    
+}
+
+USB_TYPE USBHost::setConfiguration(USBDeviceConnected * dev, uint8_t conf)
+{
+    return controlWrite( dev,
+                         USB_HOST_TO_DEVICE | USB_RECIPIENT_DEVICE,
+                         SET_CONFIGURATION,
+                         conf,
+                         0, NULL, 0);
+}
+
+uint8_t USBHost::numberDriverAttached(USBDeviceConnected * dev) {
+    int index = findDevice(dev);
+    uint8_t cnt = 0;
+    if (index == -1)
+        return 0;
+    for (uint8_t i = 0; i < MAX_INTF; i++) {
+        if (deviceAttachedDriver[index][i])
+            cnt++;
+    }
+    return cnt;
+}
+
+// enumerate a device with the control USBEndpoint
+USB_TYPE USBHost::enumerate(USBDeviceConnected * dev, IUSBEnumerator* pEnumerator)
+{
+    uint16_t total_conf_descr_length = 0;
+    USB_TYPE res;
+    
+    usb_mutex.lock();
+    
+    // don't enumerate a device which all interfaces are registered to a specific driver
+    int index = findDevice(dev);
+    
+    if (index == -1) {
+        usb_mutex.unlock();
+        return USB_TYPE_ERROR;
+    }
+    
+    uint8_t nb_intf_attached = numberDriverAttached(dev);
+    USB_DBG("dev: %p nb_intf: %d", dev, dev->getNbIntf());
+    USB_DBG("dev: %p nb_intf_attached: %d", dev, nb_intf_attached);
+    if ((nb_intf_attached != 0) && (dev->getNbIntf() == nb_intf_attached)) {
+        USB_DBG("Don't enumerate dev: %p because all intf are registered with a driver", dev);
+        usb_mutex.unlock();
+        return USB_TYPE_OK;
+    }
+    
+    USB_DBG("Enumerate dev: %p", dev);
+    
+    // third step: get the whole device descriptor to see vid, pid
+    res = getDeviceDescriptor(dev, data, DEVICE_DESCRIPTOR_LENGTH);
+
+    if (res != USB_TYPE_OK) {
+        USB_DBG("GET DEV DESCR FAILED");
+        usb_mutex.unlock();
+        return res;
+    }
+    
+    dev->setClass(data[4]);
+    dev->setSubClass(data[5]);
+    dev->setProtocol(data[6]);
+    dev->setVid(data[8] | (data[9] << 8));
+    dev->setPid(data[10] | (data[11] << 8));
+    USB_DBG("CLASS: %02X \t VID: %04X \t PID: %04X", data[4], data[8] | (data[9] << 8), data[10] | (data[11] << 8));
+
+    pEnumerator->setVidPid( data[8] | (data[9] << 8), data[10] | (data[11] << 8) );
+
+    res = getConfigurationDescriptor(dev, data, sizeof(data), &total_conf_descr_length);
+    if (res != USB_TYPE_OK) {
+        usb_mutex.unlock();
+        return res;
+    }
+
+#if DEBUG
+    USB_DBG("CONFIGURATION DESCRIPTOR:\r\n");
+    for (int i = 0; i < total_conf_descr_length; i++)
+        printf("%02X ", data[i]);
+    printf("\r\n\r\n");
+#endif
+
+    // Parse the configuration descriptor
+    parseConfDescr(dev, data, total_conf_descr_length, pEnumerator);
+
+    // only set configuration if not enumerated before
+    if (!dev->isEnumerated()) {
+        
+        USB_DBG("Set configuration 1 on dev: %p", dev);
+        // sixth step: set configuration (only 1 supported)
+        res = setConfiguration(dev, 1);
+
+        if (res != USB_TYPE_OK) {
+            USB_DBG("SET CONF FAILED");
+            usb_mutex.unlock();
+            return res;
+        }
+    }
+    
+    dev->setEnumerated();
+
+    // Now the device is enumerated!
+    USB_DBG("dev %p is enumerated\r\n", dev);
+    usb_mutex.unlock();
+
+    // Some devices may require this delay
+    wait_ms(100);
+
+    return USB_TYPE_OK;
+}
+// this method fills the USBDeviceConnected object: class,.... . It also add endpoints found in the descriptor.
+void USBHost::parseConfDescr(USBDeviceConnected * dev, uint8_t * conf_descr, uint32_t len, IUSBEnumerator* pEnumerator)
+{
+    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;
+    uint8_t current_intf = 0;
+
+    while (index < len) {
+        len_desc = conf_descr[index];
+        id = conf_descr[index+1];
+        switch (id) {
+            case CONFIGURATION_DESCRIPTOR:
+                USB_DBG("dev: %p has %d intf", dev, conf_descr[4]);
+                dev->setNbIntf(conf_descr[4]);
+                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...");
+                    }
+                    parsing_intf = true;
+                } else {
+                    parsing_intf = false;
+                }
+                break;
+            case ENDPOINT_DESCRIPTOR:
+                if (parsing_intf && (intf_nb <= MAX_INTF) ) {
+                    if (nb_endpoints_used < MAX_ENDPOINT_PER_INTERFACE) {
+                        if( pEnumerator->useEndpoint(current_intf, (ENDPOINT_TYPE)(conf_descr[index + 3] & 0x03), (ENDPOINT_DIRECTION)((conf_descr[index + 2] >> 7) + 1)) ) {
+                            // if the USBEndpoint is isochronous -> skip it (TODO: fix this)
+                            if ((conf_descr[index + 3] & 0x03) != ISOCHRONOUS_ENDPOINT) {
+                                ep = newEndpoint((ENDPOINT_TYPE)(conf_descr[index+3] & 0x03),
+                                                 (ENDPOINT_DIRECTION)((conf_descr[index + 2] >> 7) + 1),
+                                                 conf_descr[index + 4] | (conf_descr[index + 5] << 8),
+                                                 conf_descr[index + 2] & 0x0f);
+                                USB_DBG("ADD USBEndpoint %p, on interf %d on device %p", ep, current_intf, dev);
+                                if (ep != NULL && dev != NULL) {
+                                    addEndpoint(dev, current_intf, ep);
+                                } else {
+                                    USB_DBG("EP NULL");
+                                }
+                                nb_endpoints_used++;
+                            } else {
+                                USB_DBG("ISO USBEndpoint NOT SUPPORTED");
+                            }
+                        }
+                    }
+                }
+                break;
+            case HID_DESCRIPTOR:
+                lenReportDescr = conf_descr[index + 7] | (conf_descr[index + 8] << 8);
+                break;
+            default:
+                break;
+        }
+        index += len_desc;
+    }
+}
+
+
+USB_TYPE USBHost::bulkWrite(USBDeviceConnected * dev, USBEndpoint * ep, uint8_t * buf, uint32_t len, bool blocking)
+{
+    return generalTransfer(dev, ep, buf, len, blocking, BULK_ENDPOINT, true);
+}
+
+USB_TYPE USBHost::bulkRead(USBDeviceConnected * dev, USBEndpoint * ep, uint8_t * buf, uint32_t len, bool blocking)
+{
+    return generalTransfer(dev, ep, buf, len, blocking, BULK_ENDPOINT, false);
+}
+
+USB_TYPE USBHost::interruptWrite(USBDeviceConnected * dev, USBEndpoint * ep, uint8_t * buf, uint32_t len, bool blocking)
+{
+    return generalTransfer(dev, ep, buf, len, blocking, INTERRUPT_ENDPOINT, true);
+}
+
+USB_TYPE USBHost::interruptRead(USBDeviceConnected * dev, USBEndpoint * ep, uint8_t * buf, uint32_t len, bool blocking)
+{
+    return generalTransfer(dev, ep, buf, len, blocking, INTERRUPT_ENDPOINT, false);
+}
+
+USB_TYPE USBHost::generalTransfer(USBDeviceConnected * dev, USBEndpoint * ep, uint8_t * buf, uint32_t len, bool blocking, ENDPOINT_TYPE type, bool write) {
+    
+#if DEBUG_TRANSFER
+    const char * type_str = (type == BULK_ENDPOINT) ? "BULK" : ((type == INTERRUPT_ENDPOINT) ? "INTERRUPT" : "ISOCHRONOUS");
+    USB_DBG_TRANSFER("----- %s %s [dev: %p - %s - hub: %d - port: %d - addr: %d - ep: %02X]------", type_str, (write) ? "WRITE" : "READ", dev, dev->getName(ep->getIntfNb()), dev->getHub(), dev->getPort(), dev->getAddress(), ep->getAddress());
+#endif
+    
+    usb_mutex.lock();
+    
+    USB_TYPE res;
+    ENDPOINT_DIRECTION dir = (write) ? OUT : IN;
+    
+    if (dev == NULL) {
+        USB_ERR("dev NULL");
+        usb_mutex.unlock();
+        return USB_TYPE_ERROR;
+    }
+
+    if (ep == NULL) {
+        USB_ERR("ep NULL");
+        usb_mutex.unlock();
+        return USB_TYPE_ERROR;
+    }
+
+    if (ep->getState() != USB_TYPE_IDLE) {
+        USB_WARN("[ep: %p - dev: %p - %s] NOT IDLE: %s", ep, ep->dev, ep->dev->getName(ep->getIntfNb()), ep->getStateString());
+        usb_mutex.unlock();
+        return ep->getState();
+    }
+
+    if ((ep->getDir() != dir) || (ep->getType() != type)) {
+        USB_ERR("[ep: %p - dev: %p] wrong dir or bad USBEndpoint type", ep, ep->dev);
+        usb_mutex.unlock();
+        return USB_TYPE_ERROR;
+    }
+
+    if (dev->getAddress() != ep->getDeviceAddress()) {
+        USB_ERR("[ep: %p - dev: %p] USBEndpoint addr and device addr don't match", ep, ep->dev);
+        usb_mutex.unlock();
+        return USB_TYPE_ERROR;
+    }
+    
+#if DEBUG_TRANSFER
+    if (write) {
+        USB_DBG_TRANSFER("%s WRITE buffer", type_str);
+        for (int i = 0; i < ep->getLengthTransferred(); i++)
+            printf("%02X ", buf[i]);
+        printf("\r\n\r\n");
+    }
+#endif
+    addTransfer(ep, buf, len);
+
+    if (blocking) {
+        
+        ep->ep_queue.get();
+        res = ep->getState();
+        
+        USB_DBG_TRANSFER("%s TRANSFER res: %s on ep: %p\r\n", type_str, ep->getStateString(), ep);
+        
+        if (res != USB_TYPE_IDLE) {
+            usb_mutex.unlock();
+            return res;
+        }
+        
+        usb_mutex.unlock();
+        return USB_TYPE_OK;
+    }
+    
+    usb_mutex.unlock();
+    return USB_TYPE_PROCESSING;
+
+}
+
+
+USB_TYPE USBHost::controlRead(USBDeviceConnected * dev, uint8_t requestType, uint8_t request, uint32_t value, uint32_t index, uint8_t * buf, uint32_t len) {
+    return controlTransfer(dev, requestType, request, value, index, buf, len, false);
+}
+
+USB_TYPE USBHost::controlWrite(USBDeviceConnected * dev, uint8_t requestType, uint8_t request, uint32_t value, uint32_t index, uint8_t * buf, uint32_t len) {
+    return controlTransfer(dev, requestType, request, value, index, buf, len, true);
+}
+
+USB_TYPE USBHost::controlTransfer(USBDeviceConnected * dev, uint8_t requestType, uint8_t request, uint32_t value, uint32_t index, uint8_t * buf, uint32_t len, bool write)
+{
+    usb_mutex.lock();
+    USB_DBG_TRANSFER("----- CONTROL %s [dev: %p - hub: %d - port: %d] ------", (write) ? "WRITE" : "READ", dev, dev->getHub(), dev->getPort());
+
+    int length_transfer = len;
+    USB_TYPE res;
+    uint32_t token;
+
+    control->setSpeed(dev->getSpeed());
+    control->setSize(dev->getSizeControlEndpoint());
+    if (dev->isActiveAddress()) {
+        control->setDeviceAddress(dev->getAddress());
+    } else {
+        control->setDeviceAddress(0);
+    }
+
+    USB_DBG_TRANSFER("Control transfer on device: %d\r\n", control->getDeviceAddress());
+    fillControlBuf(requestType, request, value, index, len);
+
+#if DEBUG_TRANSFER
+    USB_DBG_TRANSFER("SETUP PACKET: ");
+    for (int i = 0; i < 8; i++)
+        printf("%01X ", setupPacket[i]);
+    printf("\r\n");
+#endif
+
+    control->setNextToken(TD_SETUP);
+    addTransfer(control, (uint8_t*)setupPacket, 8);
+
+    control->ep_queue.get();
+    res = control->getState();
+
+    USB_DBG_TRANSFER("CONTROL setup stage %s", control->getStateString());
+
+    if (res != USB_TYPE_IDLE) {
+        usb_mutex.unlock();
+        return res;
+    }
+
+    if (length_transfer) {
+        token = (write) ? TD_OUT : TD_IN;
+        control->setNextToken(token);
+        addTransfer(control, (uint8_t *)buf, length_transfer);
+
+        control->ep_queue.get();
+        res = control->getState();
+
+#if DEBUG_TRANSFER
+        USB_DBG_TRANSFER("CONTROL %s stage %s", (write) ? "WRITE" : "READ", control->getStateString());
+        if (write) {
+            USB_DBG_TRANSFER("CONTROL WRITE buffer");
+            for (int i = 0; i < control->getLengthTransferred(); i++)
+                printf("%02X ", buf[i]);
+            printf("\r\n\r\n");
+        } else {
+            USB_DBG_TRANSFER("CONTROL READ SUCCESS [%d bytes transferred]", control->getLengthTransferred());
+            for (int i = 0; i < control->getLengthTransferred(); i++)
+                printf("%02X ", buf[i]);
+            printf("\r\n\r\n");
+        }
+#endif
+
+        if (res != USB_TYPE_IDLE) {
+            usb_mutex.unlock();
+            return res;
+        }
+    }
+
+    token = (write) ? TD_IN : TD_OUT;
+    control->setNextToken(token);
+    addTransfer(control, NULL, 0);
+
+    control->ep_queue.get();
+    res = control->getState();
+
+    USB_DBG_TRANSFER("CONTROL ack stage %s", control->getStateString());
+    usb_mutex.unlock();
+
+    if (res != USB_TYPE_IDLE)
+        return res;
+
+    return USB_TYPE_OK;
+}
+
+
+void USBHost::fillControlBuf(uint8_t requestType, uint8_t request, uint16_t value, uint16_t index, int len)
+{
+    setupPacket[0] = requestType;
+    setupPacket[1] = request;
+    setupPacket[2] = (uint8_t) value;
+    setupPacket[3] = (uint8_t) (value >> 8);
+    setupPacket[4] = (uint8_t) index;
+    setupPacket[5] = (uint8_t) (index >> 8);
+    setupPacket[6] = (uint8_t) len;
+    setupPacket[7] = (uint8_t) (len >> 8);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/USBHost.h	Thu Dec 13 19:24:21 2018 +0000
@@ -0,0 +1,383 @@
+/* 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 USBHOST_H
+#define USBHOST_H
+
+#include "USBHALHost.h"
+#include "USBDeviceConnected.h"
+#include "IUSBEnumerator.h"
+#include "USBHostConf.h"
+#include "rtos.h"
+#include "dbg.h"
+#include "USBHostHub.h"
+
+/**
+* USBHost class
+*   This class is a singleton. All drivers have a reference on the static USBHost instance
+*/
+class USBHost : public USBHALHost {
+public:
+    /**
+    * Static method to create or retrieve the single USBHost instance
+    */
+    static USBHost * getHostInst();
+    
+    /**
+    * Control read: setup stage, data stage and status stage
+    *
+    * @param dev the control read will be done for this device
+    * @param requestType request type
+    * @param request request
+    * @param value value
+    * @param index index
+    * @param buf pointer on a buffer where will be store the data received
+    * @param len length of the transfer
+    *
+    * @returns status of the control read
+    */
+    USB_TYPE controlRead(USBDeviceConnected * dev, uint8_t requestType, uint8_t request, uint32_t value, uint32_t index, uint8_t * buf, uint32_t len);
+
+    /**
+    * Control write: setup stage, data stage and status stage
+    *
+    * @param dev the control write will be done for this device
+    * @param requestType request type
+    * @param request request
+    * @param value value
+    * @param index index
+    * @param buf pointer on a buffer which will be written
+    * @param len length of the transfer
+    *
+    * @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
+    *
+    * @param dev the bulk transfer will be done for this device
+    * @param ep USBEndpoint which will be used to read a packet
+    * @param buf pointer on a buffer where will be store the data received
+    * @param len length of the transfer
+    * @param blocking if true, the read is blocking (wait for completion)
+    *
+    * @returns status of the bulk read
+    */
+    USB_TYPE bulkRead(USBDeviceConnected * dev, USBEndpoint * ep, uint8_t * buf, uint32_t len, bool blocking = true);
+
+    /**
+    * Bulk write
+    *
+    * @param dev the bulk 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 write is blocking (wait for completion)
+    *
+    * @returns status of the bulk write
+    */
+    USB_TYPE bulkWrite(USBDeviceConnected * dev, USBEndpoint * ep, uint8_t * buf, uint32_t len, bool blocking = true);
+
+    /**
+    * Interrupt read
+    *
+    * @param dev the bulk 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 interruptRead(USBDeviceConnected * dev, USBEndpoint * ep, uint8_t * buf, uint32_t len, bool blocking = true);
+
+    /**
+    * Interrupt write
+    *
+    * @param dev the bulk 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 write is blocking (wait for completion)
+    *
+    * @returns status of the interrupt write
+    */
+    USB_TYPE interruptWrite(USBDeviceConnected * dev, USBEndpoint * ep, uint8_t * buf, uint32_t len, bool blocking = true);
+
+    /**
+    * Enumerate a device.
+    *
+    * @param dev device which will be enumerated
+    *
+    * @returns status of the enumeration
+    */
+    USB_TYPE enumerate(USBDeviceConnected * dev, IUSBEnumerator* pEnumerator);
+
+    /**
+    * reset a specific device
+    *
+    * @param dev device which will be resetted
+    */
+    USB_TYPE resetDevice(USBDeviceConnected * dev);
+
+    /**
+    * Get a device
+    *
+    * @param index index of the device which will be returned
+    *
+    * @returns pointer on the "index" device
+    */
+    USBDeviceConnected * getDevice(uint8_t index);
+
+    /*
+    * If there is a HID device connected, the host stores the length of the report descriptor.
+    * This avoid to the driver to re-ask the configuration descriptor to request the report descriptor
+    *
+    * @returns length of the report descriptor
+    */
+    inline uint16_t getLengthReportDescr() {
+        return lenReportDescr;
+    };
+
+    /**
+     *  register a driver into the host associated with a callback function called when the device is disconnected
+     *
+     *  @param dev device
+     *  @param intf interface number
+     *  @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 registerDriver(USBDeviceConnected * dev, uint8_t intf, T* tptr, void (T::*mptr)(void)) {
+        int index = findDevice(dev);
+        if ((index != -1) && (mptr != NULL) && (tptr != NULL)) {
+            USB_DBG("register driver for dev: %p on intf: %d", dev, intf);
+            deviceAttachedDriver[index][intf] = true;
+            dev->onDisconnect(intf, tptr, mptr);
+        }
+    }
+
+    /**
+     * register a driver into the host associated with a callback function called when the device is disconnected
+     *
+     * @param dev device
+     * @param intf interface number
+     * @param fn callback called when the specified device has been disconnected
+     */
+    inline void registerDriver(USBDeviceConnected * dev, uint8_t intf, void (*fn)(void)) {
+        int index = findDevice(dev);
+        if ((index != -1) && (fn != NULL)) {
+            USB_DBG("register driver for dev: %p on intf: %d", dev, intf);
+            deviceAttachedDriver[index][intf] = true;
+            dev->onDisconnect(intf, fn);
+        }
+    }
+    
+    friend class USBHostHub;
+
+protected:
+
+    /**
+    * Virtual method called when a transfer has been completed
+    *
+    * @param addr list of the TDs which have been completed
+    */
+    virtual void transferCompleted(volatile uint32_t addr);
+
+    /**
+    * Virtual method called when a device has been connected
+    *
+    * @param hub hub number of the device
+    * @param port port number of the device
+    * @param lowSpeed 1 if low speed, 0 otherwise
+    * @param hub_parent reference on the parent hub
+    */
+    virtual void deviceConnected(int hub, int port, bool lowSpeed, USBHostHub * hub_parent = NULL);
+
+    /**
+    * Virtuel method called when a device has been disconnected
+    *
+    * @param hub hub number of the device
+    * @param port port number of the device
+    * @param addr list of the TDs which have been completed to dequeue freed TDs
+    */
+    virtual void deviceDisconnected(int hub, int port, USBHostHub * hub_parent, volatile uint32_t addr);
+
+
+private:
+    // singleton class -> constructor is private
+    USBHost();
+    static USBHost * instHost;
+    uint16_t  lenReportDescr;
+
+    // endpoints
+    void unqueueEndpoint(USBEndpoint * ep) ;
+    USBEndpoint  endpoints[MAX_ENDPOINT];
+    USBEndpoint* volatile  control;
+
+    USBEndpoint* volatile  headControlEndpoint;
+    USBEndpoint* volatile  headBulkEndpoint;
+    USBEndpoint* volatile  headInterruptEndpoint;
+
+    USBEndpoint* volatile  tailControlEndpoint;
+    USBEndpoint* volatile  tailBulkEndpoint;
+    USBEndpoint* volatile  tailInterruptEndpoint;
+
+    bool controlEndpointAllocated;
+
+    // devices connected
+    USBDeviceConnected devices[MAX_DEVICE_CONNECTED];
+    bool  deviceInUse[MAX_DEVICE_CONNECTED];
+    bool  deviceAttachedDriver[MAX_DEVICE_CONNECTED][MAX_INTF];
+    bool  deviceReset[MAX_DEVICE_CONNECTED];
+    bool  deviceInited[MAX_DEVICE_CONNECTED];
+    
+#if MAX_HUB_NB
+    USBHostHub hubs[MAX_HUB_NB];
+    bool hub_in_use[MAX_HUB_NB];
+#endif
+
+    // to store a setup packet
+    uint8_t  setupPacket[8];
+    
+    typedef struct {
+        uint8_t event_id;
+        void * td_addr;
+        uint8_t hub;
+        uint8_t port;
+        uint8_t lowSpeed;
+        uint8_t td_state;
+        void * hub_parent;
+    } message_t;
+    
+    Thread usbThread;
+    void usb_process();
+    static void usb_process_static(void const * arg);
+    Mail<message_t, 10> mail_usb_event;
+    Mutex usb_mutex;
+    Mutex td_mutex;
+    
+    // buffer for conf descriptor
+    uint8_t data[415];
+    
+    /**
+    * Add a transfer on the TD linked list associated to an ED
+    *
+    * @param ed the transfer is associated to this ed
+    * @param buf pointer on a buffer where will be read/write data to send or receive
+    * @param len transfer length
+    *
+    * @return status of the transfer
+    */
+    USB_TYPE addTransfer(USBEndpoint * ed, uint8_t * buf, uint32_t len) ;
+    
+    /**
+    * Link the USBEndpoint to the linked list and attach an USBEndpoint this USBEndpoint to a device
+    *
+    * @param dev pointer on a USBDeviceConnected object
+    * @param ep pointer on the USBEndpoint which will be added
+    *
+    * return true if successful
+    */
+    bool addEndpoint(USBDeviceConnected * dev, uint8_t intf_nb, USBEndpoint * ep) ;
+
+    /**
+    * Create an USBEndpoint descriptor. Warning: the USBEndpoint is not linked.
+    *
+    * @param type USBEndpoint type (CONTROL_ENDPOINT, BULK_ENDPOINT, INTERRUPT_ENDPOINT)
+    * @param dir USBEndpoint direction (no meaning for CONTROL_ENDPOINT)
+    * @param size USBEndpoint max packet size
+    * @param addr USBEndpoint address
+    *
+    * @returns pointer on the USBEndpoint created
+    */
+    USBEndpoint * newEndpoint(ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir, uint32_t size, uint8_t addr) ;
+    
+    /**
+    * Request the device descriptor
+    *
+    * @param dev request the device descriptor on this device
+    * @param buf buffer to store the device descriptor
+    * @param max_len_buf maximum size of buf
+    * @param len_dev_descr pointer to store the length of the packet transferred
+    */
+    USB_TYPE getDeviceDescriptor(USBDeviceConnected * dev, uint8_t * buf, uint16_t max_len_buf, uint16_t * len_dev_descr = NULL);
+
+    /**
+    * Request the configuration descriptor
+    *
+    * @param dev request the configuration descriptor on this device
+    * @param buf buffer to store the configuration descriptor
+    * @param max_len_buf maximum size of buf
+    * @param len_conf_descr pointer to store the length of the packet transferred
+    */
+    USB_TYPE getConfigurationDescriptor(USBDeviceConnected * dev, uint8_t * buf, uint16_t max_len_buf, uint16_t * len_conf_descr = NULL);
+    
+    /**
+    * Set the address of a specific device
+    *
+    * @param dev device to set the address
+    * @param address address
+    */
+    USB_TYPE setAddress(USBDeviceConnected * dev, uint8_t address);
+
+    /**
+    * Set the configuration of a device
+    *
+    * @param dev device on which the specified configuration will be activated
+    * @param conf configuration number to activate (usually 1)
+    */
+    USB_TYPE setConfiguration(USBDeviceConnected * dev, uint8_t conf);
+    
+    /**
+    * Free a specific device
+    *
+    * @param dev device to be freed
+    */
+    void freeDevice(USBDeviceConnected * dev);
+
+    USB_TYPE controlTransfer(   USBDeviceConnected * dev,
+                                uint8_t requestType,
+                                uint8_t request,
+                                uint32_t value,
+                                uint32_t index,
+                                uint8_t * buf,
+                                uint32_t len,
+                                bool write);
+
+    USB_TYPE generalTransfer(   USBDeviceConnected * dev,
+                                USBEndpoint * ep,
+                                uint8_t * buf,
+                                uint32_t len,
+                                bool blocking,
+                                ENDPOINT_TYPE type,
+                                bool write) ;
+                                
+    void fillControlBuf(uint8_t requestType, uint8_t request, uint16_t value, uint16_t index, int len) ;
+    void parseConfDescr(USBDeviceConnected * dev, uint8_t * conf_descr, uint32_t len, IUSBEnumerator* pEnumerator) ;
+    int findDevice(USBDeviceConnected * dev) ;
+    int findDevice(uint8_t hub, uint8_t port, USBHostHub * hub_parent = NULL) ;
+    uint8_t numberDriverAttached(USBDeviceConnected * dev);
+
+    /////////////////////////
+    /// FOR DEBUG
+    /////////////////////////
+    void printList(ENDPOINT_TYPE type);
+
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/USBHostConf.h	Thu Dec 13 19:24:21 2018 +0000
@@ -0,0 +1,86 @@
+/* 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 USBHOST_CONF_H
+#define USBHOST_CONF_H
+
+/*
+* Maximum number of devices that can be connected
+* to the usb host
+*/
+#define MAX_DEVICE_CONNECTED        5
+
+/*
+* Maximum of Hub connected to the usb host
+*/
+#define MAX_HUB_NB                  2
+
+/*
+* Maximum number of ports on a USB hub
+*/
+#define MAX_HUB_PORT                4
+
+/*
+* Enable USBHostMSD
+*/
+#define USBHOST_MSD                 1
+
+/*
+* Enable USBHostKeyboard
+*/
+#define USBHOST_KEYBOARD            1
+
+/*
+* Enable USBHostMouse
+*/
+#define USBHOST_MOUSE               1
+
+/*
+* Enable USBHostSerial or USBHostMultiSerial (if set > 1)
+*/
+#define USBHOST_SERIAL              1
+
+/*
+* Enable USB3Gmodule
+*/
+#define USBHOST_3GMODULE            1 
+
+/*
+* Maximum number of interfaces of a usb device
+*/
+#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)
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/USBHostTypes.h	Thu Dec 13 19:24:21 2018 +0000
@@ -0,0 +1,226 @@
+/* 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_INC_H
+#define USB_INC_H
+
+#include "mbed.h"
+#include "toolchain.h"
+
+enum USB_TYPE {
+    USB_TYPE_OK = 0,
+
+    // completion code
+    USB_TYPE_CRC_ERROR = 1,
+    USB_TYPE_BIT_STUFFING_ERROR = 2,
+    USB_TYPE_DATA_TOGGLE_MISMATCH_ERROR = 3,
+    USB_TYPE_STALL_ERROR = 4,
+    USB_TYPE_DEVICE_NOT_RESPONDING_ERROR = 5,
+    USB_TYPE_PID_CHECK_FAILURE_ERROR = 6,
+    USB_TYPE_UNEXPECTED_PID_ERROR = 7,
+    USB_TYPE_DATA_OVERRUN_ERROR = 8,
+    USB_TYPE_DATA_UNDERRUN_ERROR = 9,
+    USB_TYPE_RESERVED = 9,
+    USB_TYPE_RESERVED_ = 10,
+    USB_TYPE_BUFFER_OVERRUN_ERROR = 12,
+    USB_TYPE_BUFFER_UNDERRUN_ERROR = 13,
+
+    // general usb state
+    USB_TYPE_DISCONNECTED = 14,
+    USB_TYPE_FREE = 15,
+    USB_TYPE_IDLE = 16,
+    USB_TYPE_PROCESSING = 17,
+
+    USB_TYPE_ERROR = 18,
+};
+
+
+enum ENDPOINT_DIRECTION {
+    OUT = 1,
+    IN
+};
+
+enum ENDPOINT_TYPE {
+    CONTROL_ENDPOINT = 0,
+    ISOCHRONOUS_ENDPOINT,
+    BULK_ENDPOINT,
+    INTERRUPT_ENDPOINT
+};
+
+#define AUDIO_CLASS     0x01
+#define CDC_CLASS       0x02
+#define HID_CLASS       0x03
+#define MSD_CLASS       0x08
+#define HUB_CLASS       0x09
+#define SERIAL_CLASS    0x0A
+
+// ------------------ HcControl Register ---------------------  
+#define  OR_CONTROL_PLE                 0x00000004
+#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_RHSC            0x00000040
+#define  OR_INTR_STATUS_UE              0x00000010
+// --------------- HcInterruptEnable Register ----------------- 
+#define  OR_INTR_ENABLE_WDH             0x00000002
+#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
+#define  OR_RH_PORT_LSDA                0x00000200
+
+#define  FI                     0x2EDF           // 12000 bits per frame (-1)
+#define  DEFAULT_FMINTERVAL     ((((6 * (FI - 210)) / 7) << 16) | FI)
+
+#define  ED_SKIP            (uint32_t) (0x00001000)        // Skip this ep in queue
+
+#define  TD_ROUNDING        (uint32_t) (0x00040000)        // Buffer Rounding                             
+#define  TD_SETUP           (uint32_t)(0)                  // 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_TOGGLE_0        (uint32_t)(0x02000000)         // Toggle 0                                    
+#define  TD_TOGGLE_1        (uint32_t)(0x03000000)         // Toggle 1                                    
+#define  TD_CC              (uint32_t)(0xF0000000)         // Completion Code                             
+
+#define  DEVICE_DESCRIPTOR                     (1)
+#define  CONFIGURATION_DESCRIPTOR              (2)
+#define  INTERFACE_DESCRIPTOR                  (4)
+#define  ENDPOINT_DESCRIPTOR                   (5)
+#define  HID_DESCRIPTOR                        (33)
+
+//  ----------- Control RequestType Fields  ----------- 
+#define  USB_DEVICE_TO_HOST         0x80
+#define  USB_HOST_TO_DEVICE         0x00
+#define  USB_REQUEST_TYPE_CLASS     0x20
+#define  USB_REQUEST_TYPE_STANDARD  0x00
+#define  USB_RECIPIENT_DEVICE       0x00
+#define  USB_RECIPIENT_INTERFACE    0x01
+#define  USB_RECIPIENT_ENDPOINT     0x02
+
+// -------------- USB Standard Requests  -------------- 
+#define  SET_ADDRESS                0x05
+#define  GET_DESCRIPTOR             0x06
+#define  SET_CONFIGURATION          0x09
+#define  SET_INTERFACE              0x0b
+#define  CLEAR_FEATURE              0x01
+
+// -------------- USB Descriptor Length  -------------- 
+#define DEVICE_DESCRIPTOR_LENGTH            0x12
+#define CONFIGURATION_DESCRIPTOR_LENGTH     0x09
+
+// ------------ HostController Transfer Descriptor ------------
+typedef struct HCTD {
+    __IO  uint32_t   control;        // Transfer descriptor control
+    __IO  uint8_t *  currBufPtr;    // Physical address of current buffer pointer
+    __IO  HCTD *     nextTD;         // Physical pointer to next Transfer Descriptor
+    __IO  uint8_t *  bufEnd;        // Physical address of end of buffer
+    void * ep;                      // ep address where a td is linked in
+    uint32_t dummy[3];              // padding
+} PACKED HCTD;
+
+// ----------- HostController EndPoint Descriptor ------------- 
+typedef struct hcEd {
+    __IO  uint32_t  control;        // Endpoint descriptor control
+    __IO  HCTD *  tailTD;           // Physical address of tail in Transfer descriptor list
+    __IO  HCTD *  headTD;           // Physcial address of head in Transfer descriptor list
+    __IO  hcEd *  nextED;         // Physical address of next Endpoint descriptor
+} PACKED HCED;
+
+
+// ----------- Host Controller Communication Area ------------  
+typedef struct hcca {
+    __IO  uint32_t  IntTable[32];   // Interrupt Table
+    __IO  uint32_t  FrameNumber;    // Frame Number
+    __IO  uint32_t  DoneHead;       // Done Head
+    volatile  uint8_t   Reserved[116];  // Reserved for future use                                  
+    volatile  uint8_t   Unknown[4];     // Unused                                                   
+} PACKED HCCA;
+
+typedef struct {
+    uint8_t bLength;            
+    uint8_t bDescriptorType;    
+    uint16_t bcdUSB;            
+    uint8_t bDeviceClass;       
+    uint8_t bDeviceSubClass;    
+    uint8_t bDeviceProtocol;    
+    uint8_t bMaxPacketSize;     
+    uint16_t idVendor;          
+    uint16_t idProduct;         
+    uint16_t bcdDevice;         
+    uint8_t iManufacturer;      
+    uint8_t iProduct;           
+    uint8_t iSerialNumber;      
+    uint8_t bNumConfigurations; 
+} PACKED DeviceDescriptor;
+
+typedef struct {
+    uint8_t bLength;               
+    uint8_t bDescriptorType;       
+    uint16_t wTotalLength;         
+    uint8_t bNumInterfaces;        
+    uint8_t bConfigurationValue;   
+    uint8_t iConfiguration;        
+    uint8_t bmAttributes;          
+    uint8_t bMaxPower;             
+} PACKED ConfigurationDescriptor; 
+
+typedef struct {
+    uint8_t bLength;                 
+    uint8_t bDescriptorType;   
+    uint8_t bInterfaceNumber;  
+    uint8_t bAlternateSetting; 
+    uint8_t bNumEndpoints;     
+    uint8_t bInterfaceClass;   
+    uint8_t bInterfaceSubClass;
+    uint8_t bInterfaceProtocol;
+    uint8_t iInterface;        
+} InterfaceDescriptor; 
+
+typedef struct {
+    uint8_t bLength;          
+    uint8_t bDescriptorType;  
+    uint8_t bEndpointAddress; 
+    uint8_t bmAttributes;     
+    uint16_t wMaxPacketSize;  
+    uint8_t bInterval;        
+} EndpointDescriptor;
+
+typedef struct {
+    uint8_t bDescLength;      
+    uint8_t bDescriptorType;  
+    uint8_t bNbrPorts;        
+    uint16_t wHubCharacteristics;
+    uint8_t bPwrOn2PwrGood;   
+    uint8_t bHubContrCurrent; 
+    uint8_t DeviceRemovable;  
+    uint8_t PortPweCtrlMak;   
+} HubDescriptor;              
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/dbg.h	Thu Dec 13 19:24:21 2018 +0000
@@ -0,0 +1,66 @@
+/* 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
+#define DEBUG 3 /*INFO,ERR,WARN*/
+#define DEBUG_TRANSFER 0
+#define DEBUG_EP_STATE 0
+#define DEBUG_EVENT 0
+
+#if (DEBUG > 3)
+#define USB_DBG(x, ...) std::printf("[USB_DBG: %s:%d]" x "\r\n", __FILE__, __LINE__, ##__VA_ARGS__);
+#else
+#define USB_DBG(x, ...)
+#endif
+
+#if (DEBUG > 2)
+#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
+
+
+#endif
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost3GModule/IUSBHostSerial.h	Thu Dec 13 19:24:21 2018 +0000
@@ -0,0 +1,95 @@
+/* IUSBHostSerial.h */
+/* Copyright (c) 2010-2012 mbed.org, MIT License
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+* and associated documentation files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use, copy, modify, merge, publish,
+* distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in all copies or
+* substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#ifndef IUSBHOSTSERIAL_H_
+#define IUSBHOSTSERIAL_H_
+
+/**
+ * Generic interface to abstract 3G dongles' impl
+ */
+
+#include "USBHostConf.h"
+
+#ifdef USBHOST_3GMODULE
+
+#include "IUSBHostSerialListener.h"
+
+// This is needed by some versions of GCC
+#undef putc
+#undef getc
+
+class IUSBHostSerial {
+public:
+
+    enum IrqType {
+        RxIrq,
+        TxIrq
+    };
+
+    /*
+    * Get a char from the dongle's serial interface
+    */
+    virtual int getc() = 0;
+
+    /*
+    * Put a char to the dongle's serial interface
+    */
+    virtual int putc(int c) = 0;
+
+    /*
+     *  Read a packet from the dongle's serial interface, to be called after multiple getc() calls
+     */
+    virtual int readPacket() = 0;
+
+    /*
+     *  Write a packet to the dongle's serial interface, to be called after multiple putc() calls
+     */
+    virtual int writePacket() = 0;
+
+    /**
+    * Check the number of bytes available.
+    *
+    * @returns the number of bytes available
+    */
+    virtual int readable() = 0;
+
+    /**
+    * Check the free space in output.
+    *
+    * @returns the number of bytes available
+    */
+    virtual int writeable() = 0;
+
+    /**
+     *  Attach a handler to call when a packet is received / when a packet has been transmitted.
+     *
+     *  @param pListener instance of the listener deriving from the IUSBHostSerialListener
+     */
+    virtual void attach(IUSBHostSerialListener* pListener) = 0;
+
+    /**
+     * Enable or disable readable/writeable callbacks
+     */
+    virtual void setupIrq(bool en, IrqType irq = RxIrq) = 0;
+
+};
+
+#endif /* USBHOST_3GMODULE */
+
+#endif /* IUSBHOSTSERIAL_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost3GModule/IUSBHostSerialListener.h	Thu Dec 13 19:24:21 2018 +0000
@@ -0,0 +1,37 @@
+/* IUSBHostSerialListener.h */
+/* Copyright (c) 2010-2012 mbed.org, MIT License
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+* and associated documentation files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use, copy, modify, merge, publish,
+* distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in all copies or
+* substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+
+#ifndef IUSBHOSTSERIALLISTENER_H_
+#define IUSBHOSTSERIALLISTENER_H_
+
+#include "USBHostConf.h"
+
+#ifdef USBHOST_3GMODULE
+
+class IUSBHostSerialListener
+{
+public:
+  virtual void readable() = 0; //Called when new data is available
+  virtual void writeable() = 0; //Called when new space is available
+};
+
+#endif /* USBHOST_3GMODULE */
+
+#endif /* IUSBHOSTSERIALLISTENER_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost3GModule/WANDongle.cpp	Thu Dec 13 19:24:21 2018 +0000
@@ -0,0 +1,236 @@
+/* Copyright (c) 2010-2012 mbed.org, MIT License
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+* and associated documentation files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use, copy, modify, merge, publish,
+* distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in all copies or
+* substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#include "USBHostConf.h"
+
+#ifdef USBHOST_3GMODULE
+
+#define __DEBUG__ 0
+#ifndef __MODULE__
+#define __MODULE__ "WANDongle.cpp"
+#endif
+
+#include "dbg.h"
+#include <stdint.h>
+#include "rtos.h"
+
+#include "WANDongle.h"
+#include "WANDongleInitializer.h"
+
+WANDongle::WANDongle() : m_pInitializer(NULL), m_serialCount(0), m_totalInitializers(0)
+{
+    host = USBHost::getHostInst();
+    init();
+}
+
+
+bool WANDongle::connected() {
+  return dev_connected;
+}
+
+bool WANDongle::tryConnect()
+{
+  //FIXME should run on USB thread
+
+  USB_DBG("Trying to connect device");
+
+  if (dev_connected) {
+      return true;
+  }
+  
+  m_pInitializer = NULL;
+
+  for (int i = 0; i < MAX_DEVICE_CONNECTED; i++)
+  {
+      if ((dev = host->getDevice(i)) != NULL)
+      {
+          m_pInitializer = NULL; //Will be set in setVidPid callback
+      
+          USB_DBG("Enumerate");
+          int ret = host->enumerate(dev, this);
+          if(ret)
+          {
+            return false;
+          }
+          
+          USB_DBG("Device has VID:%04x PID:%04x", dev->getVid(), dev->getPid());
+                   
+          if(m_pInitializer) //If an initializer has been found
+          {
+            USB_DBG("m_pInitializer=%p", m_pInitializer);
+            USB_DBG("m_pInitializer->getSerialVid()=%04x", m_pInitializer->getSerialVid());
+            USB_DBG("m_pInitializer->getSerialPid()=%04x", m_pInitializer->getSerialPid());
+            if ((dev->getVid() == m_pInitializer->getSerialVid()) && (dev->getPid() == m_pInitializer->getSerialPid()))
+            {
+              USB_DBG("The dongle is in virtual serial mode");
+              host->registerDriver(dev, 0, this, &WANDongle::init);
+              m_serialCount = m_pInitializer->getSerialPortCount();
+              if( m_serialCount > WANDONGLE_MAX_SERIAL_PORTS )
+              {
+                m_serialCount = WANDONGLE_MAX_SERIAL_PORTS;
+              }
+              for(int j = 0; j < m_serialCount; j++)
+              {
+                USB_DBG("Connecting serial port #%d", j+1);
+                USB_DBG("Ep %p", m_pInitializer->getEp(dev, j, false));
+                USB_DBG("Ep %p", m_pInitializer->getEp(dev, j, true));
+                m_serial[j].connect( dev, m_pInitializer->getEp(dev, j, false), m_pInitializer->getEp(dev, j, true) );
+              }
+              
+              USB_DBG("Device connected");
+              
+              dev_connected = true;
+              
+              
+              return true;
+            }
+            else if ((dev->getVid() == m_pInitializer->getMSDVid()) && (dev->getPid() == m_pInitializer->getMSDPid()))
+            {
+              USB_DBG("Vodafone K3370 dongle detected in MSD mode");
+              //Try to switch   
+              if( m_pInitializer->switchMode(dev) )
+              {
+                USB_DBG("Switched OK");
+                return false; //Will be connected on a next iteration
+              }
+              else
+              {
+                USB_ERR("Could not switch mode");
+                return false;
+              }
+            }
+          } //if()
+      } //if()
+  } //for()
+  return false;
+}
+
+bool WANDongle::disconnect()
+{
+  dev_connected = false;
+  for(int i = 0; i < WANDONGLE_MAX_SERIAL_PORTS; i++)
+  {
+    m_serial[i].disconnect();
+  }
+  return true;
+}
+
+int WANDongle::getDongleType()
+{
+  if( m_pInitializer != NULL )
+  {
+    return m_pInitializer->getType();
+  }
+  else
+  {
+    return WAN_DONGLE_TYPE_UNKNOWN;
+  }
+}
+
+IUSBHostSerial& WANDongle::getSerial(int index)
+{
+  return m_serial[index];
+}
+
+int WANDongle::getSerialCount()
+{
+  return m_serialCount;
+}
+
+//Private methods
+void WANDongle::init()
+{
+  m_pInitializer = NULL;
+  dev_connected = false;
+  for(int i = 0; i < WANDONGLE_MAX_SERIAL_PORTS; i++)
+  {
+    m_serial[i].init(host);
+  }
+}
+
+
+/*virtual*/ void WANDongle::setVidPid(uint16_t vid, uint16_t pid)
+{
+  WANDongleInitializer* initializer;
+
+  for(int i = 0; i < m_totalInitializers; i++)
+  {
+    initializer = m_Initializers[i];
+    USB_DBG("initializer=%p", initializer);
+    USB_DBG("initializer->getSerialVid()=%04x", initializer->getSerialVid());
+    USB_DBG("initializer->getSerialPid()=%04x", initializer->getSerialPid());
+    if ((dev->getVid() == initializer->getSerialVid()) && (dev->getPid() == initializer->getSerialPid()))
+    {
+      USB_DBG("The dongle is in virtual serial mode");
+      m_pInitializer = initializer;
+      break;
+    }
+    else if ((dev->getVid() == initializer->getMSDVid()) && (dev->getPid() == initializer->getMSDPid()))
+    {
+      USB_DBG("Dongle detected in MSD mode");
+      m_pInitializer = initializer;
+      break;
+    }
+    initializer++;
+  } //for
+  if(m_pInitializer)
+  {
+    m_pInitializer->setVidPid(vid, pid);
+  }
+}
+
+/*virtual*/ bool WANDongle::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(m_pInitializer)
+  {
+    return m_pInitializer->parseInterface(intf_nb, intf_class, intf_subclass, intf_protocol);
+  }
+  else
+  {
+    return false;
+  }
+}
+
+/*virtual*/ bool WANDongle::useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir) //Must return true if the endpoint will be used
+{
+  if(m_pInitializer)
+  {
+    return m_pInitializer->useEndpoint(intf_nb, type, dir);
+  }
+  else
+  {
+    return false;
+  }
+}
+
+
+bool WANDongle::addInitializer(WANDongleInitializer* pInitializer)
+{
+  if (m_totalInitializers >= WANDONGLE_MAX_INITIALIZERS)
+    return false;
+  m_Initializers[m_totalInitializers++] = pInitializer;
+  return true;
+}
+
+WANDongle::~WANDongle()
+{
+  for(int i = 0; i < m_totalInitializers; i++)
+    delete m_Initializers[i];
+}
+
+#endif /* USBHOST_3GMODULE */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost3GModule/WANDongle.h	Thu Dec 13 19:24:21 2018 +0000
@@ -0,0 +1,108 @@
+/* Copyright (c) 2010-2012 mbed.org, MIT License
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+* and associated documentation files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use, copy, modify, merge, publish,
+* distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in all copies or
+* substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#ifndef WANDONGLE_H
+#define WANDONGLE_H
+
+#include "USBHostConf.h"
+
+#ifdef USBHOST_3GMODULE
+
+#include "USBHost.h"
+#include "IUSBHostSerial.h"
+
+#include "rtos.h"
+
+#include "WANDongleSerialPort.h"
+#include "WANDongleInitializer.h"
+#include "IUSBEnumerator.h"
+
+#define WANDONGLE_MAX_OUTEP_SIZE 64
+#define WANDONGLE_MAX_INEP_SIZE 64
+
+/** A class to use a WAN (3G/LTE) access dongle
+ *
+ */
+class WANDongle : public IUSBEnumerator {
+public:
+    /*
+    * Constructor
+    *
+    * @param rootdir mount name
+    */
+    WANDongle();
+
+    /*
+    * Destructor
+    */
+    virtual ~WANDongle();
+
+    /*
+    * Check if a serial port device is connected
+    *
+    * @return true if a serial device is connected
+    */
+    bool connected();
+    
+    /*
+     * Try to connect device
+     *
+     * * @return true if connection was successful
+     */
+    bool tryConnect();
+    
+    /*
+     * Disconnect device
+     *
+     * * @return true if disconnection was successful
+     */
+    bool disconnect();
+       
+    int getDongleType();
+    
+    IUSBHostSerial& getSerial(int index);
+    int getSerialCount();
+    bool addInitializer(WANDongleInitializer* pInitializer);
+
+    //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
+    
+protected:
+    USBHost * host;
+    USBDeviceConnected * dev;
+    bool dev_connected;
+    
+    WANDongleInitializer* m_pInitializer;
+
+    void init();
+    
+    WANDongleSerialPort m_serial[WANDONGLE_MAX_SERIAL_PORTS];
+    int m_serialCount;
+ 
+    int m_totalInitializers;
+    WANDongleInitializer* m_Initializers[WANDONGLE_MAX_INITIALIZERS];
+};
+
+#endif /* USBHOST_3GMODULE */
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost3GModule/WANDongleInitializer.h	Thu Dec 13 19:24:21 2018 +0000
@@ -0,0 +1,73 @@
+/* Copyright (c) 2010-2012 mbed.org, MIT License
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+* and associated documentation files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use, copy, modify, merge, publish,
+* distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in all copies or
+* substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#ifndef WANDONGLEINITIALIZER_H
+#define WANDONGLEINITIALIZER_H
+
+#include "USBHostConf.h"
+
+#ifdef USBHOST_3GMODULE
+
+#include <stdint.h>
+
+#include "USBHost.h"
+#include "IUSBEnumerator.h"
+
+// [TODO] move these declarations to a proper place
+#define WANDONGLE_MAX_SERIAL_PORTS 2
+#define WANDONGLE_MAX_INITIALIZERS 6
+
+#define WAN_DONGLE_TYPE_UNKNOWN    (-1)
+
+class WANDongleInitializer : public IUSBEnumerator
+{
+protected:
+    WANDongleInitializer(USBHost* pHost) { m_pHost = pHost; }
+    USBHost* m_pHost;
+    uint8_t m_serialIntfMap[WANDONGLE_MAX_SERIAL_PORTS];
+    
+public:
+    virtual ~WANDongleInitializer() {}
+    virtual uint16_t getMSDVid() = 0;
+    virtual uint16_t getMSDPid() = 0;
+    
+    virtual uint16_t getSerialVid() = 0;
+    virtual uint16_t getSerialPid() = 0;
+    
+    virtual bool switchMode(USBDeviceConnected* pDev) = 0;
+    
+    virtual USBEndpoint* getEp(USBDeviceConnected* pDev, int serialPortNumber, bool tx) {
+        return pDev->getEndpoint(m_serialIntfMap[serialPortNumber], BULK_ENDPOINT, tx ? OUT : IN, 0);
+    }
+    
+    virtual int getSerialPortCount() = 0;
+    
+    virtual void setVidPid(uint16_t vid, uint16_t pid) = 0;
+    
+    virtual bool parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol) = 0; //Must return true if the interface should be parsed
+    
+    virtual bool useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir) = 0; //Must return true if the endpoint will be used
+    
+    virtual int getType() = 0;
+
+    virtual uint8_t getSerialIntf(int index) { return m_serialIntfMap[index]; }
+};
+
+#endif /* USBHOST_3GMODULE */
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost3GModule/WANDongleSerialPort.cpp	Thu Dec 13 19:24:21 2018 +0000
@@ -0,0 +1,340 @@
+/* Copyright (c) 2010-2012 mbed.org, MIT License
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+* and associated documentation files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use, copy, modify, merge, publish,
+* distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in all copies or
+* substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#include "USBHostConf.h"
+
+#ifdef USBHOST_3GMODULE
+
+#define __DEBUG__ 0
+#ifndef __MODULE__
+#define __MODULE__ "WANDongleSerialPort.cpp"
+#endif
+
+#include "dbg.h"
+#include <stdint.h>
+#include "rtos.h"
+
+#include "WANDongleSerialPort.h"
+
+WANDongleSerialPort::WANDongleSerialPort() : cb_tx_en(false), cb_rx_en(false), listener(NULL)
+{
+  reset();
+}
+
+void WANDongleSerialPort::init(USBHost* pHost)
+{
+  host = pHost;
+}
+
+void WANDongleSerialPort::reset()
+{
+  tx_mtx.lock();
+  rx_mtx.lock();
+
+  bulk_in = NULL;
+  bulk_out = NULL;
+
+  buf_out_len = 0;
+  max_out_size = 0;
+  lock_tx = false;
+  cb_tx_pending = false;
+
+  buf_in_len = 0;
+  buf_in_read_pos = 0;
+  lock_rx = false;
+  cb_rx_pending = false;
+  
+  tx_mtx.unlock();
+  rx_mtx.unlock();
+}
+
+int WANDongleSerialPort::readPacket()
+{
+  USB_DBG("Read packet on %p", this);
+  rx_mtx.lock();
+  if(lock_rx)
+  {
+    USB_ERR("Fail");
+    rx_mtx.unlock();
+    return -1;
+  }
+  
+  if( bulk_in == NULL )
+  {
+    USB_WARN("Port is disconnected");
+    rx_mtx.unlock();
+    return -1;
+  }
+
+  lock_rx = true; //Receiving
+  rx_mtx.unlock();
+//  USB_DBG("readPacket");
+  //lock_rx.lock();
+  USB_TYPE res = host->bulkRead(dev, (USBEndpoint *)bulk_in, buf_in, ((USBEndpoint *)bulk_in)->getSize(), false); //Queue transfer
+  if(res != USB_TYPE_PROCESSING)
+  {
+    //lock_rx.unlock();
+    USB_ERR("host->bulkRead() returned %d", res);
+    Thread::wait(100);
+    return -1;
+  }
+  return 0;
+}
+
+int WANDongleSerialPort::writePacket()
+{
+  tx_mtx.lock();
+  if(lock_tx)
+  {
+    USB_ERR("Fail");
+    tx_mtx.unlock();
+    return -1;
+  }
+  
+  if( bulk_out == NULL )
+  {
+    USB_WARN("Port is disconnected");
+    tx_mtx.unlock();
+    return -1;
+  }
+
+  lock_tx = true; //Transmitting
+  tx_mtx.unlock();
+//  USB_DBG("writePacket");
+
+  //lock_tx.lock();
+  USB_TYPE res = host->bulkWrite(dev, (USBEndpoint *)bulk_out, buf_out, buf_out_len, false); //Queue transfer
+  if(res != USB_TYPE_PROCESSING)
+  {
+    //lock_tx.unlock();
+    USB_ERR("host->bulkWrite() returned %d", res);
+    Thread::wait(100);
+    return -1;
+  }
+  return 0;
+}
+
+int WANDongleSerialPort::putc(int c)
+{
+  tx_mtx.lock();
+  if(!lock_tx)
+  {
+    if(buf_out_len < max_out_size)
+    {
+      buf_out[buf_out_len] = (uint8_t)c;
+      buf_out_len++;
+    }
+  }
+  else
+  {
+    USB_ERR("CAN'T WRITE!");
+  }
+  tx_mtx.unlock();
+  return c;
+}
+
+int WANDongleSerialPort::getc()
+{
+  rx_mtx.lock();
+  int c = 0;
+  if(!lock_rx)
+  {
+    if(buf_in_read_pos < buf_in_len)
+    {
+      c = (int)buf_in[buf_in_read_pos];
+      buf_in_read_pos++;
+    }
+  }
+  else
+  {
+    USB_ERR("CAN'T READ!");
+  }
+  rx_mtx.unlock();
+  return c;
+}
+
+int WANDongleSerialPort::readable()
+{
+  rx_mtx.lock();
+  if (lock_rx)
+  {
+    rx_mtx.unlock();
+    return 0;
+  }
+
+ /* if( !lock_rx.trylock() )
+  {
+    return 0;
+  }*/
+  int res = buf_in_len - buf_in_read_pos;
+  //lock_rx.unlock();
+  rx_mtx.unlock();
+  return res;
+}
+
+int WANDongleSerialPort::writeable()
+{
+  tx_mtx.lock();
+  if (lock_tx)
+  {
+    tx_mtx.unlock();
+    return 0;
+  }
+
+  /*if( !lock_tx.trylock() )
+  {
+    return 0;
+  }*/
+  int res = max_out_size - buf_out_len;
+  tx_mtx.unlock();
+ //lock_tx.unlock();
+  return res;
+}
+
+void WANDongleSerialPort::attach(IUSBHostSerialListener* pListener)
+{
+  if(pListener == NULL)
+  {
+    setupIrq(false, RxIrq);
+    setupIrq(false, TxIrq);
+  }
+  listener = pListener;
+  if(pListener != NULL)
+  {
+    setupIrq(true, RxIrq);
+    setupIrq(true, TxIrq);
+  }
+}
+
+void WANDongleSerialPort::setupIrq(bool en, IrqType irq /*= RxIrq*/)
+{
+  switch(irq)
+  {
+  case RxIrq:
+    rx_mtx.lock();
+    cb_rx_en = en;
+    if(en && cb_rx_pending)
+    {
+      cb_rx_pending = false;
+      rx_mtx.unlock();
+      listener->readable(); //Process the interrupt that was raised
+    }
+    else
+    {
+      rx_mtx.unlock();
+    }
+    break;
+  case TxIrq:
+    tx_mtx.lock();
+    cb_tx_en = en;
+    if(en && cb_tx_pending)
+    {
+      cb_tx_pending = false;
+      tx_mtx.unlock();
+      listener->writeable(); //Process the interrupt that was raised
+    }
+    else
+    {
+      tx_mtx.unlock();
+    }
+    break;
+  }
+}
+
+
+void WANDongleSerialPort::connect( USBDeviceConnected* pDev, USBEndpoint* pInEp, USBEndpoint* pOutEp )
+{
+  dev = pDev;
+  bulk_in = pInEp;
+  bulk_out = pOutEp;
+  max_out_size = bulk_out->getSize();
+  if( max_out_size > WANDONGLE_MAX_OUTEP_SIZE )
+  {
+    max_out_size = WANDONGLE_MAX_OUTEP_SIZE;
+  }
+  bulk_in->attach(this, &WANDongleSerialPort::rxHandler);
+  bulk_out->attach(this, &WANDongleSerialPort::txHandler);
+  readPacket(); //Start receiving data
+}
+
+void WANDongleSerialPort::disconnect( )
+{
+    reset();
+}
+
+//Private methods
+
+
+void WANDongleSerialPort::rxHandler()
+{
+  if (((USBEndpoint *) bulk_in)->getState() == USB_TYPE_IDLE) //Success
+  {
+    buf_in_read_pos = 0;
+    buf_in_len = ((USBEndpoint *) bulk_in)->getLengthTransferred(); //Update length
+    //lock_rx.unlock();
+    rx_mtx.lock();
+    lock_rx = false; //Transmission complete
+    if(cb_rx_en)
+    {
+      rx_mtx.unlock();
+      listener->readable(); //Call handler from the IRQ context
+      //readPacket() should be called by the handler subsequently once the buffer has been emptied
+    }
+    else
+    {
+      cb_rx_pending = true; //Queue the callback
+      rx_mtx.unlock();
+    }
+
+  }
+  else //Error, try reading again
+  {
+    //lock_rx.unlock();
+    USB_DBG("Trying again");
+    readPacket();
+  }
+}
+
+void WANDongleSerialPort::txHandler()
+{
+  if (((USBEndpoint *) bulk_out)->getState() == USB_TYPE_IDLE) //Success
+  {
+    tx_mtx.lock();
+    buf_out_len = 0; //Reset length
+    lock_tx = false; //Transmission complete
+    //lock_tx.unlock();
+    if(cb_tx_en)
+    {
+      tx_mtx.unlock();
+      listener->writeable(); //Call handler from the IRQ context
+      //writePacket() should be called by the handler subsequently once the buffer has been filled
+    }
+    else
+    {
+      cb_tx_pending = true; //Queue the callback
+      tx_mtx.unlock();
+    }
+  }
+  else //Error, try reading again
+  {
+    //lock_tx.unlock();
+    writePacket();
+  }
+}
+
+#endif /* USBHOST_3GMODULE */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost3GModule/WANDongleSerialPort.h	Thu Dec 13 19:24:21 2018 +0000
@@ -0,0 +1,133 @@
+/* Copyright (c) 2010-2012 mbed.org, MIT License
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+* and associated documentation files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use, copy, modify, merge, publish,
+* distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in all copies or
+* substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#ifndef WANDONGLESERIALPORT_H
+#define WANDONGLESERIALPORT_H
+
+#include "USBHostConf.h"
+
+#ifdef USBHOST_3GMODULE
+
+#include "USBHost.h"
+#include "IUSBHostSerial.h"
+
+#include "rtos.h"
+
+
+#define WANDONGLE_MAX_OUTEP_SIZE 64
+#define WANDONGLE_MAX_INEP_SIZE 64
+
+/** A class to use a WAN (3G/LTE) access dongle
+ *
+ */
+class WANDongleSerialPort : public IUSBHostSerial {
+public:
+    /*
+    * Constructor
+    *
+    */
+    WANDongleSerialPort();
+    
+    void init( USBHost* pHost );
+    
+    void connect( USBDeviceConnected* pDev, USBEndpoint* pInEp, USBEndpoint* pOutEp );
+    
+    void disconnect( );
+
+    /*
+    * Get a char from the dongle's serial interface
+    */
+    virtual int getc();
+
+    /*
+    * Put a char to the dongle's serial interface
+    */
+    virtual int putc(int c);
+
+    /*
+     *  Read a packet from the dongle's serial interface, to be called after multiple getc() calls
+     */
+    virtual int readPacket();
+
+    /*
+     *  Write a packet to the dongle's serial interface, to be called after multiple putc() calls
+     */
+    virtual int writePacket();
+
+    /**
+    * Check the number of bytes available.
+    *
+    * @returns the number of bytes available
+    */
+    virtual int readable();
+
+    /**
+    * Check the free space in output.
+    *
+    * @returns the number of bytes available
+    */
+    virtual int writeable();
+
+    /**
+     *  Attach a handler to call when a packet is received / when a packet has been transmitted.
+     *
+     *  @param pListener instance of the listener deriving from the IUSBHostSerialListener
+     */
+    virtual void attach(IUSBHostSerialListener* pListener);
+    
+    /**
+     * Enable or disable readable/writeable callbacks
+     */
+    virtual void setupIrq(bool en, IrqType irq = RxIrq);
+
+    
+protected:
+    USBEndpoint * bulk_in;
+    USBEndpoint * bulk_out;
+    USBHost * host;
+    USBDeviceConnected * dev;
+
+    uint8_t buf_out[WANDONGLE_MAX_OUTEP_SIZE];
+    volatile uint32_t buf_out_len;
+    uint32_t max_out_size;
+    volatile bool lock_tx;
+    volatile bool cb_tx_en;
+    volatile bool cb_tx_pending;
+    Mutex tx_mtx;
+
+    uint8_t buf_in[WANDONGLE_MAX_INEP_SIZE];
+    volatile uint32_t buf_in_len;
+    volatile uint32_t buf_in_read_pos;
+    volatile bool lock_rx;
+    volatile bool cb_rx_en;
+    volatile bool cb_rx_pending;
+    Mutex rx_mtx;
+    
+    IUSBHostSerialListener* listener;
+    
+    void reset();
+    
+    void rxHandler();
+    void txHandler();
+
+};
+
+#endif /* USBHOST_3GMODULE */
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHostHID/USBHostKeyboard.cpp	Thu Dec 13 19:24:21 2018 +0000
@@ -0,0 +1,185 @@
+/* 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);
+            (*onKeyCode)(key, 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	Thu Dec 13 19:24:21 2018 +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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHostHID/USBHostMouse.cpp	Thu Dec 13 19:24:21 2018 +0000
@@ -0,0 +1,144 @@
+/* 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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHostHID/USBHostMouse.h	Thu Dec 13 19:24:21 2018 +0000
@@ -0,0 +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.
+ */
+
+#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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHostHub/USBHostHub.cpp	Thu Dec 13 19:24:21 2018 +0000
@@ -0,0 +1,271 @@
+/* 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 "USBHostHub.h"
+
+#if MAX_HUB_NB
+
+#include "USBHost.h"
+#include "dbg.h"
+
+#define GET_STATUS 0x00
+#define CLEAR_FEATURE 0x01
+#define GET_STATE 0x02
+#define SET_FEATURE 0x03
+#define GET_DESCRIPTOR 0x06
+
+#define PORT_CONNECTION_FEATURE     (0x00)
+#define PORT_ENABLE_FEATURE         (0x01)
+#define PORT_RESET_FEATURE          (0x04)
+#define PORT_POWER_FEATURE          (0x08)
+
+#define C_PORT_CONNECTION_FEATURE     (16)
+#define C_PORT_ENABLE_FEATURE         (17)
+#define C_PORT_RESET_FEATURE          (20)
+
+#define PORT_CONNECTION   (1 << 0)
+#define PORT_ENABLE       (1 << 1)
+#define PORT_SUSPEND      (1 << 2)
+#define PORT_OVER_CURRENT (1 << 3)
+#define PORT_RESET        (1 << 4)
+#define PORT_POWER        (1 << 8)
+#define PORT_LOW_SPEED    (1 << 9)
+
+#define C_PORT_CONNECTION   (1 << 16)
+#define C_PORT_ENABLE       (1 << 17)
+#define C_PORT_SUSPEND      (1 << 18)
+#define C_PORT_OVER_CURRENT (1 << 19)
+#define C_PORT_RESET        (1 << 20)
+
+USBHostHub::USBHostHub() {
+    host = NULL;
+    init();
+}
+
+void USBHostHub::init() {
+    dev_connected = false;
+    dev = NULL;
+    int_in = NULL;
+    dev_connected = false;
+    hub_intf = -1;
+    hub_device_found = false;
+    nb_port = 0;
+    hub_characteristics = 0;
+    
+    for (int i = 0; i < MAX_HUB_PORT; i++) {
+        device_children[i] = NULL;
+    }
+}
+
+void USBHostHub::setHost(USBHost * host_) {
+    host = host_;
+}
+
+bool USBHostHub::connected()
+{
+    return dev_connected;
+}
+
+bool USBHostHub::connect(USBDeviceConnected * dev)
+{   
+    if (dev_connected) {
+        return true;
+    }
+    
+    if(host->enumerate(dev, this)) {
+        init();
+        return false;
+    }
+    
+    if (hub_device_found) {
+        this->dev = dev;
+    
+        int_in = dev->getEndpoint(hub_intf, INTERRUPT_ENDPOINT, IN);
+        
+        if (!int_in) {
+            init();
+            return false;
+        }
+        
+        USB_INFO("New HUB: VID:%04x PID:%04x [dev: %p - intf: %d]", dev->getVid(), dev->getPid(), dev, hub_intf);
+        dev->setName("Hub", hub_intf);
+        host->registerDriver(dev, hub_intf, this, &USBHostHub::disconnect);
+        
+        int_in->attach(this, &USBHostHub::rxHandler);
+        
+        // get HUB descriptor
+        host->controlRead(  dev, 
+                            USB_DEVICE_TO_HOST | USB_REQUEST_TYPE_CLASS,
+                            GET_DESCRIPTOR,
+                            0x29 << 8, 0, buf, sizeof(HubDescriptor));
+        nb_port = buf[2];
+        hub_characteristics = buf[3];
+        
+        USB_DBG("Hub has %d port", nb_port);
+        
+        for (uint8_t j = 1; j <= nb_port; j++) {
+            setPortFeature(PORT_POWER_FEATURE, j);
+        }
+        wait_ms(buf[5]*2);
+        
+        host->interruptRead(dev, int_in, buf, 1, false);
+        dev_connected = true;
+        return true;
+    }
+    
+    return false;
+}
+
+void USBHostHub::disconnect() {
+    init();
+}
+
+/*virtual*/ void USBHostHub::setVidPid(uint16_t vid, uint16_t pid)
+{
+    // we don't check VID/PID for MSD driver
+}
+
+/*virtual*/ bool USBHostHub::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 ((hub_intf == -1) &&
+        (intf_class == HUB_CLASS) &&
+        (intf_subclass == 0) &&
+        (intf_protocol == 0)) {
+        hub_intf = intf_nb;
+        return true;
+    }
+    return false;
+}
+
+/*virtual*/ bool USBHostHub::useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir) //Must return true if the endpoint will be used
+{
+    if (intf_nb == hub_intf) {
+        if ((type == INTERRUPT_ENDPOINT) && (dir == IN)) {
+            hub_device_found = true;
+            return true;
+        }
+    }
+    return false;
+}
+
+void USBHostHub::deviceConnected(USBDeviceConnected * dev) {
+    device_children[dev->getPort() - 1] = dev;
+}
+
+void USBHostHub::deviceDisconnected(USBDeviceConnected * dev) {
+    device_children[dev->getPort() - 1] = NULL;
+}
+
+void USBHostHub::hubDisconnected() {
+    for (uint8_t i = 0; i < MAX_HUB_PORT; i++) {
+        if (device_children[i] != NULL) {
+            host->freeDevice(device_children[i]);
+        }
+    }
+}
+
+void USBHostHub::rxHandler() {
+    uint32_t status;
+    if (int_in) {
+        if (int_in->getState() == USB_TYPE_IDLE) {
+            for (int port = 1; port <= nb_port; port++) {
+                status = getPortStatus(port);
+                USB_DBG("[hub handler hub: %d] status port %d [hub: %p]: 0x%X", dev->getHub(), port, dev, status);
+                
+                // if connection status has changed
+                if (status & C_PORT_CONNECTION) {
+                    if (status & PORT_CONNECTION) {
+                        USB_DBG("[hub handler hub: %d - port: %d] new device connected", dev->getHub(), port);
+                        host->deviceConnected(dev->getHub() + 1, port, status & PORT_LOW_SPEED, this);
+                    } else {
+                        USB_DBG("[hub handler hub: %d - port: %d] device disconnected", dev->getHub(), port);
+                        host->deviceDisconnected(dev->getHub() + 1, port, this, 0);
+                    }
+                    
+                    clearPortFeature(C_PORT_CONNECTION_FEATURE, port);
+                }
+                
+                if (status & C_PORT_RESET) {
+                    clearPortFeature(C_PORT_RESET_FEATURE, port);
+                }
+                
+                if (status & C_PORT_ENABLE) {
+                    clearPortFeature(C_PORT_ENABLE_FEATURE, port);
+                }
+                
+                if ((status & PORT_OVER_CURRENT)) {
+                    USB_ERR("OVER CURRENT DETECTED\r\n");
+                    clearPortFeature(PORT_OVER_CURRENT, port);
+                    host->deviceDisconnected(dev->getHub() + 1, port, this, 0);
+                }
+            }
+        }
+        host->interruptRead(dev, int_in, buf, 1, false);
+    }
+}
+
+void USBHostHub::portReset(uint8_t port) {
+    // reset port
+    uint32_t status;
+    USB_DBG("reset port %d on hub: %p [this: %p]", port, dev, this)
+    setPortFeature(PORT_RESET_FEATURE, port);
+    while(1) {
+        status = getPortStatus(port);
+        if (status & (PORT_ENABLE | PORT_RESET))
+            break;
+        if (status & PORT_OVER_CURRENT) {
+            USB_ERR("OVER CURRENT DETECTED\r\n");
+            clearPortFeature(PORT_OVER_CURRENT, port);
+            host->deviceDisconnected(dev->getHub() + 1, port, this, 0);
+            break;
+        }
+        Thread::wait(10);
+    }
+}
+
+void USBHostHub::setPortFeature(uint32_t feature, uint8_t port) {
+    host->controlWrite( dev,
+                        USB_HOST_TO_DEVICE | USB_REQUEST_TYPE_CLASS | USB_RECIPIENT_INTERFACE | USB_RECIPIENT_ENDPOINT,
+                        SET_FEATURE,
+                        feature,
+                        port,
+                        NULL,
+                        0);
+}
+
+void USBHostHub::clearPortFeature(uint32_t feature, uint8_t port) {
+    host->controlWrite( dev,
+                        USB_HOST_TO_DEVICE | USB_REQUEST_TYPE_CLASS | USB_RECIPIENT_INTERFACE | USB_RECIPIENT_ENDPOINT,
+                        CLEAR_FEATURE,
+                        feature,
+                        port,
+                        NULL,
+                        0);
+}
+
+uint32_t USBHostHub::getPortStatus(uint8_t port) {
+    uint32_t st;
+    host->controlRead(  dev,
+                        USB_DEVICE_TO_HOST | USB_REQUEST_TYPE_CLASS | USB_RECIPIENT_INTERFACE | USB_RECIPIENT_ENDPOINT,
+                        GET_STATUS,
+                        0,
+                        port,
+                        (uint8_t *)&st,
+                        4);
+    return st;
+}
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHostHub/USBHostHub.h	Thu Dec 13 19:24:21 2018 +0000
@@ -0,0 +1,125 @@
+/* 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 USBHOSTHUB_H
+#define USBHOSTHUB_H
+
+#include "USBHostConf.h"
+
+#if MAX_HUB_NB
+
+#include "USBHostTypes.h"
+#include "IUSBEnumerator.h"
+
+class USBHost;
+class USBDeviceConnected;
+class USBEndpoint;
+
+/** 
+ * A class to use a USB Hub
+ */
+class USBHostHub : public IUSBEnumerator {
+public:
+    /**
+    * Constructor
+    */
+    USBHostHub();
+
+    /**
+    * Check if a USB Hub is connected
+    *
+    * @return true if a serial device is connected
+    */
+    bool connected();
+
+    /**
+     * Try to connect device
+     *
+     * @param dev device to connect
+     * @return true if connection was successful
+     */
+    bool connect(USBDeviceConnected * dev);
+    
+    /**
+    * Automatically called by USBHost when a device
+    * has been enumerated by usb_thread
+    *
+    * @param dev device connected
+    */
+    void deviceConnected(USBDeviceConnected * dev);
+    
+    /**
+    * Automatically called by USBHost when a device
+    * has been disconnected from this hub
+    *
+    * @param dev device disconnected
+    */
+    void deviceDisconnected(USBDeviceConnected * dev);
+    
+    /**
+    * Rest a specific port
+    *
+    * @param port port number
+    */
+    void portReset(uint8_t port);
+    
+    /*
+    * Called by USBHost to set the instance of USBHost
+    *
+    * @param host host instance
+    */
+    void setHost(USBHost * host);
+    
+    /**
+    * Called by USBhost when a hub has been disconnected
+    */
+    void hubDisconnected();
+
+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;
+    bool dev_connected;
+    USBEndpoint * int_in;
+    uint8_t nb_port;
+    uint8_t hub_characteristics;
+
+    void rxHandler();
+
+    uint8_t buf[sizeof(HubDescriptor)];
+
+    int hub_intf;
+    bool hub_device_found;
+
+    void setPortFeature(uint32_t feature, uint8_t port);
+    void clearPortFeature(uint32_t feature, uint8_t port);
+    uint32_t getPortStatus(uint8_t port);
+
+    USBDeviceConnected * device_children[MAX_HUB_PORT];
+    
+    void init();
+    void disconnect();
+
+};
+
+#endif
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHostMSD/USBHostMSD.cpp	Thu Dec 13 19:24:21 2018 +0000
@@ -0,0 +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"
+
+#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 i, timeout = 10;
+    
+    getMaxLun();
+    
+    for (i = 0; i < timeout; i++) {
+        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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHostMSD/USBHostMSD.h	Thu Dec 13 19:24:21 2018 +0000
@@ -0,0 +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
+
+#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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHostSerial/MtxCircBuffer.h	Thu Dec 13 19:24:21 2018 +0000
@@ -0,0 +1,89 @@
+/* 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 MTXCIRCBUFFER_H
+#define MTXCIRCBUFFER_H
+
+#include "stdint.h"
+#include "rtos.h"
+
+//Mutex protected circular buffer
+template<typename T, int size>
+class MtxCircBuffer {
+public:
+    
+    MtxCircBuffer() {
+        write = 0;
+        read = 0;
+    }
+
+    bool isFull() {
+        mtx.lock();
+        bool r = (((write + 1) % size) == read);
+        mtx.unlock();
+        return r;
+    }
+
+    bool isEmpty() {
+        mtx.lock();
+        bool r = (read == write);
+        mtx.unlock();
+        return r;
+    }
+    
+    void flush() {
+        write = 0;
+        read = 0;
+    }
+
+    void queue(T k) {
+        mtx.lock();
+        while (((write + 1) % size) == read) {
+            mtx.unlock();
+            Thread::wait(10);
+            mtx.lock();
+        }
+        buf[write++] = k;
+        write %= size;
+        mtx.unlock();
+    }
+
+    uint16_t available() {
+        mtx.lock();
+        uint16_t a = (write >= read) ? (write - read) : (size - read + write);
+        mtx.unlock();
+        return a;
+    }
+
+    bool dequeue(T * c) {
+        mtx.lock();
+        bool empty = (read == write);
+        if (!empty) {
+            *c = buf[read++];
+            read %= size;
+        }
+        mtx.unlock();
+        return (!empty);
+    }
+
+private:
+    volatile uint16_t write;
+    volatile uint16_t read;
+    volatile T buf[size];
+    Mutex mtx;
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHostSerial/USBHostSerial.cpp	Thu Dec 13 19:24:21 2018 +0000
@@ -0,0 +1,343 @@
+/* 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 "USBHostSerial.h"
+
+#if USBHOST_SERIAL
+
+#include "dbg.h"
+
+#define CHECK_INTERFACE(cls,subcls,proto) \
+        (((cls == 0xFF)         && (subcls == 0xFF) && (proto == 0xFF)) /* QUALCOM CDC */  || \
+         ((cls == SERIAL_CLASS) && (subcls == 0x00) && (proto == 0x00)) /* STANDARD CDC */ )
+
+#if (USBHOST_SERIAL <= 1)
+
+USBHostSerial::USBHostSerial() 
+{
+    host = USBHost::getHostInst();
+    ports_found = 0;
+    dev_connected = false;
+}
+
+bool USBHostSerial::connected()
+{
+    return dev_connected;
+}
+
+void USBHostSerial::disconnect(void)
+{
+    ports_found = 0;
+    dev = NULL;
+}
+
+bool USBHostSerial::connect() {
+
+    if (dev) 
+    {
+        for (uint8_t i = 0; i < MAX_DEVICE_CONNECTED; i++) 
+        {
+            USBDeviceConnected* d = host->getDevice(i);
+            if (dev == d)
+                return true;
+        }
+        disconnect();
+    }
+    for (uint8_t i = 0; i < MAX_DEVICE_CONNECTED; i++) 
+    {
+        USBDeviceConnected* d = host->getDevice(i);
+        if (d != NULL) {
+            
+            USB_DBG("Trying to connect serial device \r\n");
+            if(host->enumerate(d, this))
+                break;
+            
+            USBEndpoint* bulk_in  = d->getEndpoint(port_intf, BULK_ENDPOINT, IN);
+            USBEndpoint* bulk_out = d->getEndpoint(port_intf, BULK_ENDPOINT, OUT);
+            if (bulk_in && bulk_out)
+            {
+                USBHostSerialPort::connect(host,d,port_intf,bulk_in, bulk_out);
+                dev = d;
+            }
+        }
+    }
+    return dev != NULL;
+}
+
+/*virtual*/ void USBHostSerial::setVidPid(uint16_t vid, uint16_t pid)
+{
+    // we don't check VID/PID for MSD driver
+}
+
+/*virtual*/ bool USBHostSerial::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 (!ports_found && 
+        CHECK_INTERFACE(intf_class, intf_subclass, intf_protocol)) {
+        port_intf = intf_nb;
+        ports_found = true;
+        return true;
+    }
+    return false;
+}
+
+/*virtual*/ bool USBHostSerial::useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir) //Must return true if the endpoint will be used
+{
+    if (ports_found && (intf_nb == port_intf)) {
+        if (type == BULK_ENDPOINT) 
+            return true;
+    }
+    return false;
+}
+
+#else // (USBHOST_SERIAL > 1)
+
+//------------------------------------------------------------------------------
+
+USBHostMultiSerial::USBHostMultiSerial() 
+{
+    host = USBHost::getHostInst();
+    dev = NULL;
+    memset(ports, NULL, sizeof(ports));
+    ports_found = 0;
+    dev_connected = false;
+}
+
+USBHostMultiSerial::~USBHostMultiSerial()
+{
+    disconnect();
+}
+
+bool USBHostMultiSerial::connected()
+{
+    return dev_connected;
+}
+
+void USBHostMultiSerial::disconnect(void)
+{
+    for (int port = 0; port < USBHOST_SERIAL; port ++) 
+    {
+        if (ports[port])
+        {
+            delete ports[port];
+            ports[port] = NULL;
+        }
+    }
+    ports_found = 0;
+    dev = NULL;
+}
+
+bool USBHostMultiSerial::connect() {
+
+    if (dev) 
+    {
+        for (uint8_t i = 0; i < MAX_DEVICE_CONNECTED; i++) 
+        {
+            USBDeviceConnected* d = host->getDevice(i);
+            if (dev == d)
+                return true;
+        }
+        disconnect();
+    }
+    for (uint8_t i = 0; i < MAX_DEVICE_CONNECTED; i++) 
+    {
+        USBDeviceConnected* d = host->getDevice(i);
+        if (d != NULL) {
+            
+            USB_DBG("Trying to connect serial device \r\n");
+            if(host->enumerate(d, this))
+                break;
+            
+            for (int port = 0; port < ports_found; port ++) 
+            {
+                USBEndpoint* bulk_in  = d->getEndpoint(port_intf[port], BULK_ENDPOINT, IN);
+                USBEndpoint* bulk_out = d->getEndpoint(port_intf[port], BULK_ENDPOINT, OUT);
+                if (bulk_in && bulk_out)
+                {
+                    ports[port] = new USBHostSerialPort();
+                    if (ports[port])
+                    {
+                        ports[port]->connect(host,d,port_intf[port],bulk_in, bulk_out);
+                        dev = d;
+                    }
+                }
+            }
+        }
+    }
+    return dev != NULL;
+}
+
+/*virtual*/ void USBHostMultiSerial::setVidPid(uint16_t vid, uint16_t pid)
+{
+    // we don't check VID/PID for MSD driver
+}
+
+/*virtual*/ bool USBHostMultiSerial::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 ((ports_found < USBHOST_SERIAL) && 
+        CHECK_INTERFACE(intf_class, intf_subclass, intf_protocol)) {
+        port_intf[ports_found++] = intf_nb;
+        return true;
+    }
+    return false;
+}
+
+/*virtual*/ bool USBHostMultiSerial::useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir) //Must return true if the endpoint will be used
+{
+    if ((ports_found > 0) && (intf_nb == port_intf[ports_found-1])) {
+        if (type == BULK_ENDPOINT) 
+            return true;
+    }
+    return false;
+}
+
+#endif
+
+//------------------------------------------------------------------------------
+
+#define SET_LINE_CODING 0x20
+
+USBHostSerialPort::USBHostSerialPort(): circ_buf() 
+{
+    init();
+}
+
+void USBHostSerialPort::init(void)
+{
+    host = NULL;
+    dev = NULL;
+    serial_intf = NULL;
+    size_bulk_in = 0;
+    size_bulk_out = 0;
+    bulk_in = NULL;
+    bulk_out = NULL;
+    line_coding.baudrate = 9600;
+    line_coding.data_bits = 8;
+    line_coding.parity = None;
+    line_coding.stop_bits = 1;
+    circ_buf.flush();
+}
+
+void USBHostSerialPort::connect(USBHost* _host, USBDeviceConnected * _dev, 
+        uint8_t _serial_intf, USBEndpoint* _bulk_in, USBEndpoint* _bulk_out)
+{
+    host = _host;
+    dev = _dev;
+    serial_intf = _serial_intf;
+    bulk_in = _bulk_in;
+    bulk_out = _bulk_out;
+    
+    USB_INFO("New Serial device: VID:%04x PID:%04x [dev: %p - intf: %d]", dev->getVid(), dev->getPid(), dev, serial_intf);
+    dev->setName("Serial", serial_intf);
+    host->registerDriver(dev, serial_intf, this, &USBHostSerialPort::init);
+    //baud(9600);
+    size_bulk_in = bulk_in->getSize();
+    size_bulk_out = bulk_out->getSize();
+    bulk_in->attach(this, &USBHostSerialPort::rxHandler);
+    bulk_out->attach(this, &USBHostSerialPort::txHandler);
+    host->bulkRead(dev, bulk_in, buf, size_bulk_in, false);
+}
+
+void USBHostSerialPort::rxHandler() {
+    if (bulk_in) {
+        int len = bulk_in->getLengthTransferred();
+        if (bulk_in->getState() == USB_TYPE_IDLE) {
+            for (int i = 0; i < len; i++) {
+                circ_buf.queue(buf[i]);
+            }
+            rx.call();
+            host->bulkRead(dev, bulk_in, buf, size_bulk_in, false);
+        }
+    }
+}
+
+void USBHostSerialPort::txHandler() {
+    if (bulk_out) {
+        if (bulk_out->getState() == USB_TYPE_IDLE) {
+            tx.call();
+        }
+    }
+}
+
+int USBHostSerialPort::_putc(int c) {
+    if (bulk_out) {
+        if (host->bulkWrite(dev, bulk_out, (uint8_t *)&c, 1) == USB_TYPE_OK) {
+            return 1;
+        }
+    }
+    return -1;
+}
+
+void USBHostSerialPort::baud(int baudrate) {
+    line_coding.baudrate = baudrate;
+    format(line_coding.data_bits, (Parity)line_coding.parity, line_coding.stop_bits);
+}
+
+void USBHostSerialPort::format(int bits, Parity parity, int stop_bits) {
+    line_coding.data_bits = bits;
+    line_coding.parity = parity;
+    line_coding.stop_bits = (stop_bits == 1) ? 0 : 2;
+    
+    // set line coding
+    host->controlWrite( dev,
+                        USB_RECIPIENT_INTERFACE | USB_HOST_TO_DEVICE | USB_REQUEST_TYPE_CLASS,
+                        SET_LINE_CODING,
+                        0, serial_intf, (uint8_t *)&line_coding, 7);
+}
+
+int USBHostSerialPort::_getc() {
+    uint8_t c = 0;
+    if (bulk_in == NULL) {
+        init();
+        return -1;
+    }
+    while (circ_buf.isEmpty());
+    circ_buf.dequeue(&c);
+    return c;
+}
+
+int USBHostSerialPort::writeBuf(const char* b, int s)
+{
+    int c = 0;
+    if (bulk_out) 
+    {
+        while (c < s)
+        {
+            int i = (s < size_bulk_out) ? s : size_bulk_out;
+            if (host->bulkWrite(dev, bulk_out, (uint8_t *)(b+c), i) == USB_TYPE_OK) 
+                c += i;
+        }
+    }
+    return s;
+}
+
+int USBHostSerialPort::readBuf(char* b, int s)
+{
+    int i = 0;
+    if (bulk_in) 
+    {
+        for (i = 0; i < s; )
+            b[i++] = getc();
+    }
+    return i;
+}
+
+uint8_t USBHostSerialPort::available() {
+    return circ_buf.available();
+}
+
+
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHostSerial/USBHostSerial.h	Thu Dec 13 19:24:21 2018 +0000
@@ -0,0 +1,231 @@
+/* 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 USBHOSTSERIAL_H
+#define USBHOSTSERIAL_H
+
+#include "USBHostConf.h"
+
+#if USBHOST_SERIAL
+
+#include "USBHost.h"
+#include "Stream.h"
+#include "MtxCircBuffer.h"
+
+/** 
+ * A class to communicate a USB virtual serial port
+ */
+class USBHostSerialPort : public Stream {
+public:
+    /**
+    * Constructor
+    */
+    USBHostSerialPort();
+
+    enum IrqType {
+        RxIrq,
+        TxIrq
+    };
+    
+    enum Parity {
+        None = 0,
+        Odd,
+        Even,
+        Mark,
+        Space
+    };
+
+    void connect(USBHost* _host, USBDeviceConnected * _dev, 
+        uint8_t _serial_intf, USBEndpoint* _bulk_in, USBEndpoint* _bulk_out);
+
+    /**
+    * Check the number of bytes available.
+    *
+    * @returns the number of bytes available
+    */
+    uint8_t available(); 
+
+    /**
+     *  Attach a member function to call when a packet is received.
+     *
+     *  @param tptr pointer to the object to call the member function on
+     *  @param mptr pointer to the member function to be called
+     *  @param irq irq type
+     */
+    template<typename T>
+    inline void attach(T* tptr, void (T::*mptr)(void), IrqType irq = RxIrq) {
+        if ((mptr != NULL) && (tptr != NULL)) {
+            if (irq == RxIrq) {
+                rx.attach(tptr, mptr);
+            } else {
+                tx.attach(tptr, mptr);
+            }
+        }
+    }
+
+    /**
+     * Attach a callback called when a packet is received
+     *
+     * @param ptr function pointer
+     */
+    inline void attach(void (*fn)(void), IrqType irq = RxIrq) {
+        if (fn != NULL) {
+            if (irq == RxIrq) {
+                rx.attach(fn);
+            } else {
+                tx.attach(fn);
+            }
+        }
+    }
+    
+    /** Set the baud rate of the serial port
+     *
+     *  @param baudrate The baudrate of the serial port (default = 9600).
+     */
+    void baud(int baudrate = 9600);
+    
+    /** Set the transmission format used by the Serial port
+     *
+     *  @param bits The number of bits in a word (default = 8)
+     *  @param parity The parity used (USBHostSerialPort::None, USBHostSerialPort::Odd, USBHostSerialPort::Even, USBHostSerialPort::Mark, USBHostSerialPort::Space; default = USBHostSerialPort::None)
+     *  @param stop The number of stop bits (1 or 2; default = 1)
+     */
+    void format(int bits = 8, Parity parity = USBHostSerialPort::None, int stop_bits = 1);
+    virtual int writeBuf(const char* b, int s);
+    virtual int readBuf(char* b, int s);
+
+protected:
+    virtual int _getc();
+    virtual int _putc(int c);
+    
+private:
+    USBHost * host;
+    USBDeviceConnected * dev;
+
+    USBEndpoint * bulk_in;
+    USBEndpoint * bulk_out;
+    uint32_t size_bulk_in;
+    uint32_t size_bulk_out;
+
+    void init();
+
+    MtxCircBuffer<uint8_t, 128> circ_buf;
+
+    uint8_t buf[64];
+
+    typedef struct {
+        uint32_t baudrate;
+        uint8_t stop_bits;
+        uint8_t parity;
+        uint8_t data_bits;
+    } PACKED LINE_CODING;
+    
+    LINE_CODING line_coding;
+
+    void rxHandler();
+    void txHandler();
+    FunctionPointer rx;
+    FunctionPointer tx;
+
+    uint8_t serial_intf;
+};
+
+#if (USBHOST_SERIAL <= 1)
+
+class USBHostSerial : public IUSBEnumerator, public USBHostSerialPort 
+{
+public: 
+    USBHostSerial();
+    
+    /**
+     * Try to connect a serial device
+     *
+     * @return true if connection was successful
+     */
+    bool connect();
+    
+    void disconnect();
+
+    /**
+    * Check if a any serial port is connected
+    *
+    * @returns true if a serial device is connected
+    */
+    bool connected();
+  
+protected:
+    USBHost* host;
+    USBDeviceConnected* dev;
+    uint8_t port_intf;
+    int ports_found;
+
+    //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:
+    bool dev_connected;
+};
+
+#else // (USBHOST_SERIAL > 1)
+
+class USBHostMultiSerial : public IUSBEnumerator {
+public: 
+    USBHostMultiSerial();
+    virtual ~USBHostMultiSerial();
+    
+    USBHostSerialPort* getPort(int port) 
+    { 
+        return port < USBHOST_SERIAL ? ports[port] : NULL; 
+    }
+
+    /**
+     * Try to connect a serial device
+     *
+     * @return true if connection was successful
+     */
+    bool connect();
+    
+    void disconnect();
+
+    /**
+    * Check if a any serial port is connected
+    *
+    * @returns true if a serial device is connected
+    */
+    bool connected();
+  
+protected:
+    USBHost* host;
+    USBDeviceConnected* dev;
+    USBHostSerialPort* ports[USBHOST_SERIAL];
+    uint8_t port_intf[USBHOST_SERIAL];
+    int ports_found;
+
+    //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:
+    bool dev_connected;
+};
+#endif // (USBHOST_SERIAL <= 1)
+
+#endif
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-rtos.lib	Thu Dec 13 19:24:21 2018 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/mbed-rtos/#015df9e602b6