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

Dependencies:   FATFileSystem

Dependents:   F401RE-BTstack_example F401RE-USBHostMSD_HelloWorld

Fork of KL46Z-USBHost by Norimasa Okamoto

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

Platforms

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

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

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

Examples

Import programF446RE-USBHostMouse_HelloWorld

USBHostMouse Hello World for ST-Nucleo-F446RE

Import programF401RE-USBHostMSD_HelloWorld

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

Import programF401RE-USBHostC270_example

Simple USBHost WebCam test program

Import programK64F_USBHostC270_example

Simple USBHost C270 example

Import programF401RE-BTstack_example

BTstack for Nucleo F401RE/FRDM-KL46Z example program

Import programUSBHostRSSI_example

Bluetooth device discovery example program.

Import programKL46Z-USBHostGPS_HelloWorld

Simple USBHost GPS Dongle Receiver for FRDM-KL46Z test program

Files at this revision

API Documentation at this revision

Comitter:
va009039
Date:
Tue Jan 21 08:59:28 2014 +0000
Parent:
0:5160ee0c522d
Child:
2:0cdac6bcc534
Commit message:
add USBHostMSD

Changed in this revision

FATFileSystem.lib Show annotated file Show diff for this revision Revisions of this file
USBHost.cpp Show annotated file Show diff for this revision Revisions of this file
USBHost.h Show annotated file Show diff for this revision Revisions of this file
USBHostMSD.cpp Show annotated file Show diff for this revision Revisions of this file
USBHostMSD.h Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/FATFileSystem.lib	Tue Jan 21 08:59:28 2014 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/FATFileSystem/#b6669c987c8e
--- a/USBHost.cpp	Sat Jan 18 13:30:22 2014 +0000
+++ b/USBHost.cpp	Tue Jan 21 08:59:28 2014 +0000
@@ -6,9 +6,16 @@
 template <>struct CtAssert<true> {};
 #define CTASSERT(A) CtAssert<A>();
 
+
+#ifdef _USB_DBG
+#define USB_DBG(...) do{fprintf(stderr,"[%s@%d] ",__PRETTY_FUNCTION__,__LINE__);fprintf(stderr,__VA_ARGS__);fprintf(stderr,"\n");} while(0);
+#define USB_DBG_HEX(A,B) debug_hex(A,B)
 void debug_hex(uint8_t* buf, int size);
-#define USB_DBG(...) do{fprintf(stderr,"[%s@%d] ",__PRETTY_FUNCTION__,__LINE__);fprintf(stderr,__VA_ARGS__);} while(0);
-#define USB_DBG_HEX(A,B) debug_hex(A,B)
+#else
+#define USB_DBG(...) while(0)
+#define USB_DBG_HEX(A,B) while(0)
+#endif
+
 #define USB_TEST_ASSERT(A) while(!(A)){fprintf(stderr,"\n\n%s@%d %s ASSERT!\n\n",__PRETTY_FUNCTION__,__LINE__,#A);exit(1);};
 #define USB_TEST_ASSERT_FALSE(A) USB_TEST_ASSERT(!(A))
 
@@ -38,6 +45,9 @@
         address = (uint32_t)buf;
         byte_count = size;
     }
+    uint8_t getStatus() {
+        return (info>>2)&0x0f;
+    }    
 };
 
 __attribute__((__aligned__(512))) BDT bdt[64];
@@ -55,6 +65,8 @@
 
 USBHost::USBHost() {
     inst = this;
+    memset(rx_data01, DATA1, sizeof(rx_data01));
+    memset(tx_data01, DATA1, sizeof(tx_data01));
 }
 
 void USBHost::init() {
@@ -86,6 +98,8 @@
     // pulldown D+ and D-
     USB0->USBCTRL = USB_USBCTRL_PDE_MASK;
 
+    USB0->USBTRC0 |= 0x40;
+
     // Host mode
     USB0->CTL |= USB_CTL_HOSTMODEEN_MASK;
     // Desable SOF packet generation
@@ -96,22 +110,27 @@
 
     wait_attach();
 
-    // Enable RESET
-    USB0->CTL |= USB_CTL_RESET_MASK;
-    wait_ms(10);
-    USB0->CTL &= ~USB_CTL_RESET_MASK;
+    for(int retry = 2; retry > 0; retry--) {
+        // Enable RESET
+        USB0->CTL |= USB_CTL_RESET_MASK;
+        wait_ms(500);
+        USB0->CTL &= ~USB_CTL_RESET_MASK;
     
-    // Enable SOF
-    USB0->CTL |= USB_CTL_USBENSOFEN_MASK;
-    wait_ms(100);
+        // Enable SOF
+        USB0->CTL |= USB_CTL_USBENSOFEN_MASK;
+        wait_ms(100);
 
-    // token transfer initialize
-    tx_ptr = ODD;
-    rx_ptr = ODD;
-    USB0->INTEN |= USB_INTEN_TOKDNEEN_MASK;
+        // token transfer initialize
+        tx_ptr = ODD;
+        rx_ptr = ODD;
+        USB0->INTEN |= USB_INTEN_TOKDNEEN_MASK;
 
-    enumeration();
-
+        if (enumeration()) {
+            break;
+        }
+        USB_DBG("retry=%d", retry);
+        USB_TEST_ASSERT(retry > 1);
+    }
 }
 
 void USBHost::wait_attach() {
@@ -120,34 +139,60 @@
     while(!attach_done);
     wait_ms(100);
     USB_TEST_ASSERT_FALSE(USB0->CTL & USB_CTL_SE0_MASK);
-    if (!(USB0->CTL & USB_CTL_JSTATE_MASK)) { // low speed
-        USB0->ADDR |= USB_ADDR_LSEN_MASK;
+    lowSpeed = (USB0->CTL & USB_CTL_JSTATE_MASK) ? false : true;
+    if (lowSpeed) { // low speed
+        USB0->ENDPOINT[0].ENDPT |= USB_ENDPT_HOSTWOHUB_MASK;
     }
-    USB0->ENDPOINT[0].ENDPT |= USB_ENDPT_HOSTWOHUB_MASK;
+    USB_DBG("lowSpeed=%d", lowSpeed);
 }
 
-void USBHost::enumeration() {
-    uint8_t desc[18];
+bool USBHost::enumeration() {
+    uint8_t desc[64];
     MaxPacketSize0 = 8;
+    dev_addr = 0;
+    USB0->ADDR = (lowSpeed ? USB_ADDR_LSEN_MASK : 0x00) | USB_ADDR_ADDR(dev_addr);
+    wait_ms(100);
     SETUP_PACKET setup_get_descriptor = {0x80, GET_DESCRIPTOR, 1<<8, 0, 0};
     int result = ControlRead(&setup_get_descriptor, desc, 8);
-    USB_TEST_ASSERT(result == 8);
+    if (result < 8) {
+        USB_DBG("result=%d %02x", result, LastStatus);
+        return false;
+    }
     USB_DBG_HEX(desc, result);
     MaxPacketSize0 = desc[7];
 
+    dev_addr = 1;
+    SETUP_PACKET setup_set_address = {0x00, SET_ADDRESS, 1, 0, 0};
+    result = ControlWrite(&setup_set_address);
+    if (result < 0) {
+        USB_DBG("result=%d %02x", result, LastStatus);
+        return false;
+    }
+    USB0->ADDR = (lowSpeed ? USB_ADDR_LSEN_MASK : 0x00) | USB_ADDR_ADDR(dev_addr);
+    wait_ms(100);
+
     result = ControlRead(&setup_get_descriptor, desc, sizeof(desc));
-    USB_TEST_ASSERT(result == sizeof(desc));
-    USB_DBG_HEX(desc, sizeof(desc));
+    if (result < 8) {
+        USB_DBG("result=%d", result);
+        return false;
+    }
+    USB_DBG_HEX(desc, result);
 
     setup_get_descriptor.wValue = 2<<8; // config descriptor
     result = ControlRead(&setup_get_descriptor, desc, 4);
-    USB_TEST_ASSERT(result == 4);
+    if (result != 4) {
+        USB_DBG("result=%d", result);
+        return false;
+    }
     USB_DBG_HEX(desc, 4);
 
     int TotalLength = desc[2]|desc[3]<<8;
     uint8_t* buf = new uint8_t[TotalLength];
     result = ControlRead(&setup_get_descriptor, buf, TotalLength);
-    USB_TEST_ASSERT(result == TotalLength);
+    if (result != TotalLength) {
+        USB_DBG("result=%d TotalLength=%d %02x", result, TotalLength, LastStatus);
+        return false;
+    }
     USB_DBG_HEX(buf, TotalLength);
 
     for(int i = 0; i < TotalLength; ) {
@@ -173,97 +218,197 @@
     }
     delete[] buf;
 
-    SETUP_PACKET setup_set_config = {0x00, SET_CONFIGURATION, 1, 0, 0}; // config = 1
-    ControlWrite(&setup_set_config);
+    // config = 1
+    SETUP_PACKET setup_set_config = {0x00, SET_CONFIGURATION, 1, 0, 0};
+    result = ControlWrite(&setup_set_config);
+    if (result < 0) {
+        USB_DBG("set config: %02x", LastStatus);
+        if (lowSpeed && LastStatus == STALL) { // TODO:
+            wait_ms(100);
+            return true;
+        }
+        return false;
+    }
+    wait_ms(100);
+    return true;
 }
 
 int USBHost::ControlRead(SETUP_PACKET* setup, uint8_t* data, int size) {
     token_setup(setup, size); // setup stage
+    USB_DBG("setup %02x", LastStatus);
+    if (LastStatus != ACK && lowSpeed == false) {
+        return -1;
+    }
+    rx_data01[0] = DATA1;
     int read_len = 0;
     while(read_len < size) {
         int size2 = std::min(size-read_len, MaxPacketSize0);
         int result = token_in(0, data+read_len, size2);
+        USB_DBG("token_in result=%d %02x", result, LastStatus);
+        if (result < 0) {
+            if (LastStatus == NAK || LastStatus == Bus_Timeout) {
+                break;
+            }
+            return result;
+        }
         read_len += result;
         if (result < MaxPacketSize0) {
             break;
         }
     }    
-    token_out(0); // status stage
+    tx_data01[0] = rx_data01[0];
+    int result = token_out(0); // status stage
+    if (result < 0) {
+        USB_DBG("status token_out %02x", LastStatus);
+        if (LastStatus == STALL) {
+            return read_len;
+        }
+        return result;
+    }
     return read_len;
 }
 
 int USBHost::ControlWrite(SETUP_PACKET* setup, uint8_t* data, int size) {
-    token_setup(setup, size); // setup stage
-    int result = 0;
+    if (token_setup(setup, size) != ACK) { // setup stage
+        return -1;
+    }
+    tx_data01[0] = DATA1;
+    int write_len = 0;
     if (data != NULL) {
-        result = token_out(0, data, size);
+        write_len = token_out(0, data, size);
+        if (write_len < 0) {
+            return -1;
+        }
     }
-    token_in(0); // status stage
-    return result;
+    rx_data01[0] = tx_data01[0];
+    int result = token_in(0); // status stage
+    if (result < 0) {
+        return result;
+    }
+    return write_len;
 }
 
 int USBHost::InterruptRead(uint8_t* data, int size) {
     USB0->ISTAT = 0xff;
-    USB0->ENDPOINT[0].ENDPT |= USB_ENDPT_EPCTLDIS_MASK|
-                               USB_ENDPT_EPRXEN_MASK|
-                               USB_ENDPT_EPTXEN_MASK|
-                               USB_ENDPT_EPHSHK_MASK;
+    USB0->ENDPOINT[0].ENDPT = (lowSpeed ? USB_ENDPT_HOSTWOHUB_MASK : 0x00) |
+                              USB_ENDPT_EPCTLDIS_MASK|
+                              USB_ENDPT_EPRXEN_MASK|
+                              USB_ENDPT_EPHSHK_MASK;
     return token_in(ep_int_in & 0x7f, data, size);
 }
 
 int USBHost::BulkRead(uint8_t* data, int size) {
-    USB0->ISTAT = 0xff;
-    USB0->ENDPOINT[0].ENDPT |= USB_ENDPT_EPCTLDIS_MASK|
-                               USB_ENDPT_EPRXEN_MASK|
-                               USB_ENDPT_EPTXEN_MASK|
-                               USB_ENDPT_EPHSHK_MASK;
-    return token_in(ep_bulk_in & 0x7f, data, size);
+    token_ready();
+    USB0->ENDPOINT[0].ENDPT = USB_ENDPT_EPCTLDIS_MASK|
+                              USB_ENDPT_EPRXEN_MASK|
+                              USB_ENDPT_EPHSHK_MASK;
+    const int max_packet_size = 64;
+    int read_len = 0;
+    while(read_len < size) {
+        int size2 = std::min(size-read_len, max_packet_size);
+        int result = token_in(ep_bulk_in & 0x7f, data+read_len, size2);
+        if (result < 0) {
+            //USB_DBG("token_in result=%d %02x", result, LastStatus);
+            return result;
+        }
+        read_len += result;
+        if (result < max_packet_size) {
+            break;
+        }
+    }
+    return read_len;
 }
 
 int USBHost::BulkWrite(const uint8_t* data, int size) {
-    USB0->ISTAT = 0xff;
-    USB0->ENDPOINT[0].ENDPT |= USB_ENDPT_EPCTLDIS_MASK|
-                               USB_ENDPT_EPRXEN_MASK|
-                               USB_ENDPT_EPTXEN_MASK|
-                               USB_ENDPT_EPHSHK_MASK;
-    return token_out(ep_bulk_out & 0x7f, data, size);
+    token_ready();
+    USB0->ENDPOINT[0].ENDPT = USB_ENDPT_EPCTLDIS_MASK|
+                              USB_ENDPT_EPTXEN_MASK|
+                              USB_ENDPT_EPHSHK_MASK;
+    const int max_packet_size = 64;
+    int write_len = 0;
+    while(write_len < size) {
+        int size2 = std::min(size-write_len, max_packet_size);
+        int result = token_out(ep_bulk_out, data+write_len, size2);
+        if (result < 0) {
+            //USB_DBG("token_in result=%d %02x", result, LastStatus);
+            return result;
+        }
+        write_len += result;
+        if (result < max_packet_size) {
+            break;
+        }
+    }
+    return write_len;
 }
 
 int USBHost::token_setup(SETUP_PACKET* setup, uint16_t wLength) {
-    USB0->ISTAT = 0xff;
-    USB0->ERRSTAT = 0xff;
-    USB0->ENDPOINT[0].ENDPT |= USB_ENDPT_EPRXEN_MASK|
-                               USB_ENDPT_EPTXEN_MASK|
-                               USB_ENDPT_EPHSHK_MASK;
+    token_ready();
+    USB0->ENDPOINT[0].ENDPT = (lowSpeed ? USB_ENDPT_HOSTWOHUB_MASK : 0x00) |
+                              USB_ENDPT_EPRXEN_MASK|
+                              USB_ENDPT_EPTXEN_MASK|
+                              USB_ENDPT_EPHSHK_MASK;
     int idx = EP0_BDT_IDX(TX, tx_ptr);
-    bdt[idx].info = BD_OWN_MASK;
+    bdt[idx].info = BD_OWN_MASK |
+                    BD_DTS_MASK; // always data0
     setup->wLength = wLength;
     bdt[idx].setBuffer((uint8_t*)setup, sizeof(SETUP_PACKET));
     CTASSERT(sizeof(SETUP_PACKET) == 8);
     token_done = false;
     USB0->TOKEN = USB_TOKEN_TOKENPID(SETUP_TOKEN)|USB_TOKEN_TOKENENDPT(0);
     while(!token_done);
-    return (bdt[idx].info>>2)&0x0f;
+    LastStatus = bdt[idx].getStatus();
+    return LastStatus;
 }
 
 int USBHost::token_in(uint8_t ep, uint8_t* data, int size) {
+    USB_TEST_ASSERT(ep < sizeof(rx_data01));
+    token_ready();
     int idx = EP0_BDT_IDX(RX, rx_ptr);
-    bdt[idx].info = BD_OWN_MASK|BD_DATA01_MASK;
+    bdt[idx].info = BD_OWN_MASK|
+                    BD_DTS_MASK|
+                    ((rx_data01[ep] == DATA1) ? BD_DATA01_MASK : 0);
     bdt[idx].setBuffer(data, size);
     token_done = false;
     USB0->TOKEN = USB_TOKEN_TOKENPID(IN_TOKEN)|USB_TOKEN_TOKENENDPT(ep);
     while(!token_done);
+    LastStatus = bdt[idx].getStatus();
+    if (LastStatus == DATA0) {
+        rx_data01[ep] = DATA1;
+    } else if (LastStatus == DATA1) {
+        rx_data01[ep] = DATA0;
+    } else {
+        return -1;
+    }
     return bdt[idx].byte_count;
 }
 
 int USBHost::token_out(uint8_t ep, const uint8_t* data, int size) {
+    USB_TEST_ASSERT(ep < sizeof(tx_data01));
+    token_ready();
     int idx = EP0_BDT_IDX(TX, tx_ptr);
-    bdt[idx].info = BD_OWN_MASK|BD_DATA01_MASK;
+    bdt[idx].info = BD_OWN_MASK|
+                    BD_DTS_MASK|
+                   ((tx_data01[ep] == DATA1) ? BD_DATA01_MASK : 0);
     bdt[idx].setBuffer((uint8_t*)data, size);
     token_done = false;
     USB0->TOKEN = USB_TOKEN_TOKENPID(OUT_TOKEN)|USB_TOKEN_TOKENENDPT(ep);
     while(!token_done);
-    return bdt[idx].byte_count;
+    LastStatus = bdt[idx].getStatus();
+    if (LastStatus == ACK) {
+        tx_data01[ep] = (tx_data01[ep] == DATA0) ? DATA1 : DATA0;
+        return bdt[idx].byte_count;
+    }
+    return -1;
+}
+
+void USBHost::token_ready() {
+    while(USB0->CTL & USB_CTL_TXSUSPENDTOKENBUSY_MASK) { // TOKEN_BUSY ?
+        wait_ms(1);
+    }
+    USB0->ISTAT |= USB_ISTAT_SOFTOK_MASK; // Clear SOF
+    while (!(USB0->ISTAT & USB_ISTAT_SOFTOK_MASK));
+    USB0->SOFTHLD = 0; // this is needed as without this you can get errors
+    USB0->ISTAT |= USB_ISTAT_SOFTOK_MASK; // clear SOF
 }
 
 void USBHost::_usbisr(void) {
@@ -276,10 +421,11 @@
     uint8_t istat = USB0->ISTAT;
     if (istat & USB_ISTAT_TOKDNE_MASK) {
         uint8_t stat = USB0->STAT;
+        ODD_EVEN next_ptr = (stat & USB_STAT_ODD_MASK) ? ODD : EVEN;
         if (stat & USB_STAT_TX_MASK) {
-            tx_ptr = (stat & USB_STAT_ODD_MASK) ? ODD : EVEN;
+            tx_ptr = next_ptr;
         } else {
-            rx_ptr = (stat & USB_STAT_ODD_MASK) ? ODD : EVEN;
+            rx_ptr = next_ptr;
         }
         token_done = true;
     }
--- a/USBHost.h	Sat Jan 18 13:30:22 2014 +0000
+++ b/USBHost.h	Tue Jan 21 08:59:28 2014 +0000
@@ -15,6 +15,15 @@
 #define GET_CONFIGURATION 8
 #define SET_CONFIGURATION 9
 
+// TOK_PID[5:2]
+#define DATA0 0x03
+#define DATA1 0x0b
+#define ACK   0x02
+#define STALL 0x0e
+#define NAK   0x0a
+#define Bus_Timeout 0x00
+#define Data_Error 0x0f
+
 enum ODD_EVEN {
     ODD = 0,
     EVEN = 1,
@@ -28,27 +37,33 @@
     int ControlWrite(SETUP_PACKET* setup, uint8_t* data = NULL, int size = 0);
     int BulkRead(uint8_t* data, int size);
     int BulkWrite(const uint8_t* data, int size);
+    uint8_t LastStatus;
 
 protected:
     USBHost();
     void init();
     void wait_attach();
-    void enumeration();
+    bool enumeration();
     uint8_t ep_int_in;
     uint8_t ep_bulk_in;
     uint8_t ep_bulk_out;
     int MaxPacketSize0;
+    bool lowSpeed;
+    int dev_addr;
 
 private:
     static void _usbisr(void);
     int token_setup(SETUP_PACKET* setup, uint16_t wLength = 0);
     int token_in(uint8_t ep, uint8_t* data = NULL, int size = 0);
     int token_out(uint8_t ep, const uint8_t* data = NULL, int size = 0);
+    void token_ready();
     void UsbIrqhandler();
     __IO bool attach_done;
     __IO bool token_done;
     ODD_EVEN tx_ptr;
     ODD_EVEN rx_ptr;
+    uint8_t tx_data01[16];
+    uint8_t rx_data01[16];
     static USBHost* inst;
 };
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHostMSD.cpp	Tue Jan 21 08:59:28 2014 +0000
@@ -0,0 +1,290 @@
+/* mbed USBHost Library
+ * Copyright (c) 2006-2013 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "USBHostMSD.h"
+
+#define CBW_SIGNATURE   0x43425355
+#define CSW_SIGNATURE   0x53425355
+
+#define DEVICE_TO_HOST  0x80
+#define HOST_TO_DEVICE  0x00
+
+#define GET_MAX_LUN             (0xFE)
+#define BO_MASS_STORAGE_RESET   (0xFF)
+
+USBHostMSD::USBHostMSD(const char * rootdir) : FATFileSystem(rootdir)
+{
+    host = USBHost::getHostInst();
+    init();
+}
+
+void USBHostMSD::init() {
+    dev_connected = false;
+    dev = NULL;
+    bulk_in = NULL;
+    bulk_out = NULL;
+    dev_connected = false;
+    blockSize = 0;
+    blockCount = 0;
+    msd_intf = 1; //msd_intf = -1;
+    msd_device_found = false;
+    disk_init = false;
+    dev_connected = false;
+    nb_ep = 0;
+}
+
+
+bool USBHostMSD::connected()
+{
+    return true;
+}
+
+bool USBHostMSD::connect()
+{
+    return true;
+}
+
+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, (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 = 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 = 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 = bulkWrite(dev, bulk_out, data, transfer_len);
+            if (checkResult(res, bulk_out))
+                return -1;
+
+        } else if (flags == DEVICE_TO_HOST) {
+
+            res = bulkRead(dev, bulk_in, data, transfer_len);
+            if (checkResult(res, bulk_in))
+                return -1;
+        }
+    }
+
+    // status stage
+    csw.Signature = 0;
+    USB_DBG("Read CSW");
+    res = 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 = 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 = controlWrite(   dev,
+                              USB_RECIPIENT_ENDPOINT | USB_HOST_TO_DEVICE | USB_REQUEST_TYPE_STANDARD,
+                              CLEAR_FEATURE,
+                              0, bulk_in->getAddress(), NULL, 0);
+        
+        res = 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 = controlRead(    dev, USB_RECIPIENT_INTERFACE | USB_DEVICE_TO_HOST | USB_REQUEST_TYPE_CLASS,
+                          0xfe, 0, msd_intf, buf, 1);
+    USB_DBG("max lun: %d", buf[0]);
+    return res;
+}
+
+int USBHostMSD::disk_initialize() {
+    USB_DBG("FILESYSTEM: init");
+    int i, timeout = 10;
+    
+    //getMaxLun();
+    
+    for (i = 0; i < timeout; i++) {
+        wait_ms(100);
+        if (!testUnitReady())
+            break;
+    }
+    
+    if (i == timeout) {
+        disk_init = false;
+        return -1;
+    }
+    
+    inquiry(0, 0);
+    disk_init = 1;
+    return readCapacity();
+}
+
+int USBHostMSD::disk_write(const uint8_t *buffer, uint64_t block_number) {
+    USB_DBG("FILESYSTEM: write block: %lld", block_number);
+    if (!disk_init) {
+        disk_initialize();
+    }
+    if (!disk_init)
+        return -1;
+    return dataTransfer((uint8_t *)buffer, block_number, 1, HOST_TO_DEVICE);
+}
+
+int USBHostMSD::disk_read(uint8_t * buffer, uint64_t block_number) {
+    USB_DBG("FILESYSTEM: read block %lld", block_number);
+    if (!disk_init) {
+        disk_initialize();
+    }
+    if (!disk_init)
+        return -1;
+    return dataTransfer((uint8_t *)buffer, block_number, 1, DEVICE_TO_HOST);
+}
+
+uint64_t USBHostMSD::disk_sectors() {
+    USB_DBG("FILESYSTEM: sectors");
+    if (!disk_init) {
+        disk_initialize();
+    }
+    if (!disk_init)
+        return 0;
+    return blockCount;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHostMSD.h	Tue Jan 21 08:59:28 2014 +0000
@@ -0,0 +1,191 @@
+/* mbed USBHost Library
+ * Copyright (c) 2006-2013 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef USBHOSTMSD_H
+#define USBHOSTMSD_H
+
+#if 0
+#define USB_DBG(...) do{fprintf(stderr,"[%s@%d] ",__PRETTY_FUNCTION__,__LINE__);fprintf(stderr,__VA_ARGS__);fprintf(stderr,"\r\n");} while(0);
+#else
+#define USB_DBG(...)  while(0);
+#endif
+
+#define USB_DBG2(...) do{fprintf(stderr,"[%s@%d] ",__PRETTY_FUNCTION__,__LINE__);fprintf(stderr,__VA_ARGS__);fprintf(stderr,"\r\n");} while(0);
+
+#if 1
+#define USB_INFO(...) do{fprintf(stderr,__VA_ARGS__);fprintf(stderr,"\r\n");}while(0);
+#else
+#define USB_INFO(...)  while(0);
+#endif
+
+//#include "USBHostConf.h"
+enum USB_TYPE {
+    USB_TYPE_OK = 0,
+    // completion code
+    USB_TYPE_STALL_ERROR = 4,
+    // general usb state
+    USB_TYPE_IDLE = 16,
+    USB_TYPE_ERROR = 18,
+};
+
+//  ----------- 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  CLEAR_FEATURE              0x01
+
+#include "USBHost.h"
+#include "FATFileSystem.h"
+
+class USBDeviceConnected { //dummy
+};
+
+struct USBEndpoint { // dummy
+    void setState(uint8_t st){};
+    uint8_t getAddress(){ return 0; };
+};
+
+/** 
+ * A class to communicate a USB flash disk
+ */
+class USBHostMSD : 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 FATFileSystem
+    virtual int disk_initialize();
+    virtual int disk_status() {return 0;};
+    virtual int disk_read(uint8_t * buffer, uint64_t sector);
+    virtual int disk_write(const uint8_t * buffer, uint64_t sector);
+    virtual int disk_sync() {return 0;};
+    virtual uint64_t disk_sectors();
+
+private:
+    USBHost * host;
+    USBDeviceConnected * dev;
+    bool dev_connected;
+    USBEndpoint * bulk_in;
+    USBEndpoint * bulk_out;
+    uint8_t nb_ep;
+
+    // Bulk-only CBW
+    typedef __packed struct {
+        uint32_t Signature;
+        uint32_t Tag;
+        uint32_t DataLength;
+        uint8_t  Flags;
+        uint8_t  LUN;
+        uint8_t  CBLength;
+        uint8_t  CB[16];
+    } CBW;
+
+    // Bulk-only CSW
+    typedef __packed struct {
+        uint32_t Signature;
+        uint32_t Tag;
+        uint32_t DataResidue;
+        uint8_t  Status;
+    } CSW;
+
+    CBW cbw;
+    CSW csw;
+
+    int SCSITransfer(uint8_t * cmd, uint8_t cmd_len, int flags, uint8_t * data, uint32_t transfer_len);
+    int testUnitReady();
+    int readCapacity();
+    int inquiry(uint8_t lun, uint8_t page_code);
+    int SCSIRequestSense();
+    int dataTransfer(uint8_t * buf, uint32_t block, uint8_t nbBlock, int direction);
+    int checkResult(uint8_t res, USBEndpoint * ep);
+    int getMaxLun();
+
+    int blockSize;
+    uint64_t blockCount;
+
+    int msd_intf;
+    bool msd_device_found;
+    bool disk_init;
+    
+    void init();
+
+    // KL46Z-USBHost interface
+    USB_TYPE controlRead(USBDeviceConnected* dev, uint8_t requestType, uint8_t request, uint32_t value, uint32_t index, uint8_t * buf, uint32_t len) {
+        SETUP_PACKET setup = {requestType, request, value, index};
+        int result = host->ControlRead(&setup, buf, len);
+        USB_DBG2("result=%d %02x", result, host->LastStatus);
+        return (result >= 0) ? USB_TYPE_OK : USB_TYPE_ERROR;
+    }
+
+    USB_TYPE controlWrite(USBDeviceConnected* dev, uint8_t requestType, uint8_t request, uint32_t value, uint32_t index, uint8_t * buf, uint32_t len) {
+        SETUP_PACKET setup = {requestType, request, value, index};
+        int result = host->ControlWrite(&setup, buf, len);
+        USB_DBG2("result=%d %02x", result, host->LastStatus);
+        return (result >= 0) ? USB_TYPE_OK : USB_TYPE_ERROR;
+    }
+    
+    USB_TYPE bulkRead(USBDeviceConnected * dev, USBEndpoint * ep, uint8_t * buf, uint32_t len, bool blocking = true) {
+        for(int retry = 2; retry > 0; retry--) {
+            int result = host->BulkRead(buf, len);
+            if (result >= 0) {
+                return USB_TYPE_OK;
+            }
+            USB_DBG2("result=%d %02x", result, host->LastStatus);
+            if (host->LastStatus != Bus_Timeout) {
+                break;
+            }
+            wait_ms(10);
+        }
+        return USB_TYPE_ERROR;
+    }
+    
+    USB_TYPE bulkWrite(USBDeviceConnected * dev, USBEndpoint * ep, uint8_t * buf, uint32_t len, bool blocking = true) {
+        int result = host->BulkWrite(buf, len);
+        if (result >= 0) {
+            return USB_TYPE_OK;
+        }
+        USB_DBG2("result=%d %02x", result, host->LastStatus);
+        return USB_TYPE_ERROR;
+    }
+};
+
+#endif