Simple USBHost library for Nucleo F446RE/F411RE/F401RE FRDM-KL46Z/KL25Z/F64F LPC4088/LPC1768
Dependents: F401RE-BTstack_example F401RE-USBHostMSD_HelloWorld
Fork of KL46Z-USBHost by
簡易USBホストライブラリです。
official-USBHostの下位互換で対応プログラムを僅かな修正で動かすことが出来ます。
Platforms
- Nucleo F446RE
- Nucleo F411RE
- Nucleo F401RE
- FRDM-K64F
- FRDM-KL46Z
- FRDM-KL25Z
- LPC4088
- LPC1768
Nucleo F446RE/F411RE/F401REのUSB接続方法
ST morpho | USB |
---|---|
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
Revision 1:c072d9e580b0, committed 2014-01-21
- 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
--- /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