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 3:a3872f7593e2, committed 2014-01-25
- Comitter:
- va009039
- Date:
- Sat Jan 25 12:51:44 2014 +0000
- Parent:
- 2:0cdac6bcc534
- Child:
- 4:21d651ad6987
- Commit message:
- fix max packet size
Changed in this revision
--- a/FATFileSystem.lib Thu Jan 23 08:32:54 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -http://mbed.org/users/mbed_official/code/FATFileSystem/#b6669c987c8e
--- a/USBHALHost.cpp Thu Jan 23 08:32:54 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,285 +0,0 @@ -// Simple USBHost for FRDM-KL46Z -#include "USBHALHost.h" -#include <algorithm> - -template <bool>struct CtAssert; -template <>struct CtAssert<true> {}; -#define CTASSERT(A) CtAssert<A>(); - - -#ifdef _USB_DBG -#define USB_DBG(...) do{fprintf(stderr,"[%s@%d] ",__PRETTY_FUNCTION__,__LINE__);fprintf(stderr,__VA_ARGS__);fprintf(stderr,"\n");} while(0); -#define USB_DBG_HEX(A,B) debug_hex(A,B) -void debug_hex(uint8_t* buf, int size); -#else -#define USB_DBG(...) while(0) -#define USB_DBG_HEX(A,B) while(0) -#endif - -#define USB_TEST_ASSERT(A) while(!(A)){fprintf(stderr,"\n\n%s@%d %s ASSERT!\n\n",__PRETTY_FUNCTION__,__LINE__,#A);exit(1);}; -#define USB_TEST_ASSERT_FALSE(A) USB_TEST_ASSERT(!(A)) - -#define BD_OWN_MASK (1<<7) -#define BD_DATA01_MASK (1<<6) -#define BD_KEEP_MASK (1<<5) -#define BD_NINC_MASK (1<<4) -#define BD_DTS_MASK (1<<3) -#define BD_STALL_MASK (1<<2) - -#define TX 1 -#define RX 0 - -#define EP0_BDT_IDX(dir, odd) (((2 * dir) + (1 * odd))) - -#define SETUP_TOKEN 0x0D -#define IN_TOKEN 0x09 -#define OUT_TOKEN 0x01 - -// for each endpt: 8 bytes -struct BDT { - uint8_t info; // BD[0:7] - uint8_t dummy; // RSVD: BD[8:15] - uint16_t byte_count; // BD[16:32] - uint32_t address; // Addr - void setBuffer(uint8_t* buf, int size) { - address = (uint32_t)buf; - byte_count = size; - } - uint8_t getStatus() { - return (info>>2)&0x0f; - } -}; - -__attribute__((__aligned__(512))) BDT bdt[64]; - -USBHALHost* USBHALHost::instHost; - -USBHALHost::USBHALHost() { - instHost = this; - memset(rx_data01, DATA1, sizeof(rx_data01)); - memset(tx_data01, DATA1, sizeof(tx_data01)); -} - -void USBHALHost::init() { - // Disable IRQ - NVIC_DisableIRQ(USB0_IRQn); - - // choose usb src as PLL - SIM->SOPT2 |= (SIM_SOPT2_USBSRC_MASK | SIM_SOPT2_PLLFLLSEL_MASK); - - // enable OTG clock - SIM->SCGC4 |= SIM_SCGC4_USBOTG_MASK; - - // USB Module Configuration - // Reset USB Module - USB0->USBTRC0 |= USB_USBTRC0_USBRESET_MASK; - while(USB0->USBTRC0 & USB_USBTRC0_USBRESET_MASK); - - // Clear interrupt flag - USB0->ISTAT = 0xff; - - // Set BDT Base Register - USB0->BDTPAGE1=(uint8_t)((uint32_t)bdt>>8); - USB0->BDTPAGE2=(uint8_t)((uint32_t)bdt>>16); - USB0->BDTPAGE3=(uint8_t)((uint32_t)bdt>>24); - - // Set SOF threshold - USB0->SOFTHLD = USB_SOFTHLD_CNT(1); - - // 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 - USB0->CTL &= ~USB_CTL_USBENSOFEN_MASK; - - NVIC_SetVector(USB0_IRQn, (uint32_t)_usbisr); - NVIC_EnableIRQ(USB0_IRQn); - - wait_attach(); - - 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); - - // token transfer initialize - tx_ptr = ODD; - rx_ptr = ODD; - USB0->INTEN |= USB_INTEN_TOKDNEEN_MASK; - - if (enumeration()) { - break; - } - USB_DBG("retry=%d", retry); - USB_TEST_ASSERT(retry > 1); - } -} - -void USBHALHost::wait_attach() { - attach_done = false; - USB0->INTEN = USB_INTEN_ATTACHEN_MASK; - while(!attach_done); - wait_ms(100); - USB_TEST_ASSERT_FALSE(USB0->CTL & USB_CTL_SE0_MASK); - lowSpeed = (USB0->CTL & USB_CTL_JSTATE_MASK) ? false : true; - if (lowSpeed) { // low speed - USB0->ENDPOINT[0].ENDPT |= USB_ENDPT_HOSTWOHUB_MASK; - } - USB_DBG("lowSpeed=%d", lowSpeed); -} - -void USBHALHost::setAddr(int _addr) { - USB0->ADDR = (lowSpeed ? USB_ADDR_LSEN_MASK : 0x00) | USB_ADDR_ADDR(_addr); -} - -void USBHALHost::setEndpoint(bool use_retry) { - USB0->ENDPOINT[0].ENDPT = (lowSpeed ? USB_ENDPT_HOSTWOHUB_MASK : 0x00)| - USB_ENDPT_EPCTLDIS_MASK| - (use_retry ? 0x00 : USB_ENDPT_RETRYDIS_MASK)| - USB_ENDPT_EPRXEN_MASK| - USB_ENDPT_EPTXEN_MASK| - USB_ENDPT_EPHSHK_MASK; -} - -int USBHALHost::token_setup(SETUP_PACKET* setup, uint16_t wLength) { - int retry = 0; - do { - token_ready(); - USB0->ENDPOINT[0].ENDPT = (lowSpeed ? USB_ENDPT_HOSTWOHUB_MASK : 0x00) | - USB_ENDPT_RETRYDIS_MASK| - USB_ENDPT_EPRXEN_MASK| - USB_ENDPT_EPTXEN_MASK| - USB_ENDPT_EPHSHK_MASK; - CTASSERT(sizeof(SETUP_PACKET) == 8); - setup->wLength = wLength; - int idx = EP0_BDT_IDX(TX, tx_ptr); - bdt[idx].setBuffer((uint8_t*)setup, sizeof(SETUP_PACKET)); - bdt[idx].info = BD_OWN_MASK | - BD_DTS_MASK; // always data0 - token_done = false; - USB0->TOKEN = USB_TOKEN_TOKENPID(SETUP_TOKEN)|USB_TOKEN_TOKENENDPT(0); - while(!token_done); - LastStatus = bdt[idx].getStatus(); - if (LastStatus == ACK) { - if (retry > 0) { - USB_DBG("retry=%d %02x", retry, prev_LastStatus); - } - return ACK; - } - wait_ms(1); - prev_LastStatus = LastStatus; - //USB_DBG("retry=%d %02x", retry, prev_LastStatus); - }while(retry++ < 10); - return LastStatus; -} - -int USBHALHost::token_in(uint8_t ep, uint8_t* data, int size, int retryLimit) { - USB_TEST_ASSERT(ep < sizeof(rx_data01)); - for(int retry = 0;; retry++) { - token_ready(); - int idx = EP0_BDT_IDX(RX, rx_ptr); - bdt[idx].setBuffer(data, size); - bdt[idx].info = BD_OWN_MASK| - BD_DTS_MASK| - ((rx_data01[ep] == DATA1) ? BD_DATA01_MASK : 0); - token_done = false; - USB0->TOKEN = USB_TOKEN_TOKENPID(IN_TOKEN)|USB_TOKEN_TOKENENDPT(ep); - while(!token_done); - LastStatus = bdt[idx].getStatus(); - int len = bdt[idx].byte_count; - if (LastStatus == DATA0 || LastStatus == DATA1) { - rx_data01[ep] = LastStatus == DATA0 ? DATA1 : DATA0; - if (retry > 0) { - USB_DBG("len=%d retry=%d %02x", len, retry, prev_LastStatus); - } - return len; - } - if (++retry >= retryLimit) { - return -1; - } - wait_ms(100); - prev_LastStatus = LastStatus; - } -} - -int USBHALHost::token_out(uint8_t ep, const uint8_t* data, int size) { - USB_TEST_ASSERT(ep < sizeof(tx_data01)); - int retry = 0; - do { - token_ready(); - int idx = EP0_BDT_IDX(TX, tx_ptr); - 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); - LastStatus = bdt[idx].getStatus(); - if (LastStatus == ACK) { - tx_data01[ep] = (tx_data01[ep] == DATA0) ? DATA1 : DATA0; - if (retry > 0) { - USB_DBG("retry=%d %02x", retry, prev_LastStatus); - } - return bdt[idx].byte_count; - } - wait_ms(10); - prev_LastStatus = LastStatus; - } while(retry++ < 10); - return -1; -} - -void USBHALHost::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 USBHALHost::_usbisr(void) { - if (instHost) { - instHost->UsbIrqhandler(); - } -} - -void USBHALHost::UsbIrqhandler() { - 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 = next_ptr; - } else { - rx_ptr = next_ptr; - } - token_done = true; - } - if (istat & USB_ISTAT_ATTACH_MASK) { - USB0->INTEN &= ~USB_INTEN_ATTACHEN_MASK; - attach_done = true; - } - USB0->ISTAT = istat; // clear -} - -void debug_hex(uint8_t* buf, int size) { - for(int i = 0; i < size; i++) { - fprintf(stderr, "%02x ", buf[i]); - if (i%16 == 15) { - fprintf(stderr, "\r\n"); - } - } - fprintf(stderr, "\r\n"); -} -
--- a/USBHALHost.h Thu Jan 23 08:32:54 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,66 +0,0 @@ -// Simple USBHost for FRDM-KL46Z -#pragma once -#include "mbed.h" - -struct SETUP_PACKET { - uint8_t bmRequestType; - uint8_t bRequest; - uint16_t wValue; - uint16_t wIndex; - uint16_t wLength; -}; - -#define SET_ADDRESS 5 -#define GET_DESCRIPTOR 6 -#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, -}; - -class USBHALHost { -public: - uint8_t LastStatus; - uint8_t prev_LastStatus; - -protected: - USBHALHost(); - void init(); - virtual bool enumeration() = 0; - bool lowSpeed; - - uint8_t ep_int_in; - uint8_t ep_bulk_in; - uint8_t ep_bulk_out; - int MaxPacketSize0; - void setAddr(int addr); - void setEndpoint(bool use_retry = false); - int token_setup(SETUP_PACKET* setup, uint16_t wLength = 0); - int token_in(uint8_t ep, uint8_t* data = NULL, int size = 0, int retryLimit = 10); - int token_out(uint8_t ep, const uint8_t* data = NULL, int size = 0); - void token_ready(); - uint8_t tx_data01[16]; - uint8_t rx_data01[16]; - -private: - static void _usbisr(void); - void UsbIrqhandler(); - - __IO bool attach_done; - __IO bool token_done; - void wait_attach(); - ODD_EVEN tx_ptr; - ODD_EVEN rx_ptr; - static USBHALHost * instHost; -};
--- a/USBHost.cpp Thu Jan 23 08:32:54 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,226 +0,0 @@ -// Simple USBHost for FRDM-KL46Z -#include "USBHost.h" -#include <algorithm> - -template <bool>struct CtAssert; -template <>struct CtAssert<true> {}; -#define CTASSERT(A) CtAssert<A>(); - - -#ifdef _USB_DBG -#define USB_DBG(...) do{fprintf(stderr,"[%s@%d] ",__PRETTY_FUNCTION__,__LINE__);fprintf(stderr,__VA_ARGS__);fprintf(stderr,"\n");} while(0); -#define USB_DBG_HEX(A,B) debug_hex(A,B) -void debug_hex(uint8_t* buf, int size); -#else -#define USB_DBG(...) while(0) -#define USB_DBG_HEX(A,B) while(0) -#endif - -#define USB_TEST_ASSERT(A) while(!(A)){fprintf(stderr,"\n\n%s@%d %s ASSERT!\n\n",__PRETTY_FUNCTION__,__LINE__,#A);exit(1);}; -#define USB_TEST_ASSERT_FALSE(A) USB_TEST_ASSERT(!(A)) - -USBHost* USBHost::inst = NULL; - -USBHost* USBHost::getHostInst() -{ - if (inst == NULL) { - inst = new USBHost(); - inst->init(); - } - return inst; -} - -USBHost::USBHost() { -} - -/* virtual */ 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); - if (result < 8) { - USB_DBG("result=%d %02x", result, LastStatus); - return false; - } - USB_DBG_HEX(desc, result); - MaxPacketSize0 = desc[7]; - - 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; - } - wait_ms(100); - dev_addr = 1; - - result = ControlRead(&setup_get_descriptor, 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); - 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); - 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; ) { - int Length = buf[i]; - uint8_t DescriptorType = buf[i+1]; - if (DescriptorType == 0x05) { // endpoint - uint8_t EndpointAddress = buf[i+2]; - uint8_t Attributes = buf[i+3]; - if (Attributes == 0x03) { // interrupt - if (EndpointAddress & 0x80) { - ep_int_in = EndpointAddress; - } - } else if (Attributes == 0x02) { // bulk - if (EndpointAddress & 0x80) { - ep_bulk_in = EndpointAddress; - } else { - ep_bulk_out = EndpointAddress; - } - } - } - USB_DBG_HEX(buf+i, Length); - i += Length; - } - delete[] buf; - - // 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) { - setAddr(dev_addr); - token_setup(setup, size); // setup stage - if (LastStatus != ACK) { - USB_DBG("setup %02x", LastStatus); - 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) { - USB_DBG("token_in %d/%d %02x", read_len, size, LastStatus); - return result; - } - read_len += result; - if (result < MaxPacketSize0) { - break; - } - } - 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) { - setAddr(dev_addr); - token_setup(setup, size); // setup stage - if (LastStatus != ACK) { - USB_DBG("setup %02x", LastStatus); - return -1; - } - - tx_data01[0] = DATA1; - int write_len = 0; - if (data != NULL) { - write_len = token_out(0, data, size); - if (write_len < 0) { - return -1; - } - } - 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) { - setAddr(dev_addr); - setEndpoint(); - const int retryLimit = 0; - return token_in(ep_int_in & 0x7f, data, size, retryLimit); -} - -int USBHost::BulkRead(uint8_t* data, int size) { - setAddr(dev_addr); - setEndpoint(); - 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) { - setAddr(dev_addr); - setEndpoint(); - 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; -} -
--- a/USBHost.h Thu Jan 23 08:32:54 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,21 +0,0 @@ -// Simple USBHost for FRDM-KL46Z -#pragma once -#include "mbed.h" -#include "USBHALHost.h" - -class USBHost : public USBHALHost { -public: - static USBHost* getHostInst(); - int InterruptRead(uint8_t* data, int size); - int ControlRead(SETUP_PACKET* setup, uint8_t* data, int size); - 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); - -private: - USBHost(); - static USBHost* inst; - virtual bool enumeration(); - int dev_addr; -}; -
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHost/USBEndpoint.h Sat Jan 25 12:51:44 2014 +0000 @@ -0,0 +1,15 @@ +#pragma once +#include "USBHostTypes.h" + +class USBEndpoint { +public: + void setState(uint8_t st){}; // dummy + void setSize(uint32_t size) { MaxPacketSize = size; } + void setAddress(uint8_t addr) { address = addr; } + uint8_t getAddress(){ return address; }; + uint32_t getSize() { return MaxPacketSize; } + +private: + uint8_t address; + int MaxPacketSize; +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHost/USBHALHost.cpp Sat Jan 25 12:51:44 2014 +0000 @@ -0,0 +1,375 @@ +// Simple USBHost for FRDM-KL46Z +#include "USBHALHost.h" +#include <algorithm> + +template <bool>struct CtAssert; +template <>struct CtAssert<true> {}; +#define CTASSERT(A) CtAssert<A>(); + + +#ifdef _USB_DBG +#define USB_DBG(...) do{fprintf(stderr,"[%s@%d] ",__PRETTY_FUNCTION__,__LINE__);fprintf(stderr,__VA_ARGS__);fprintf(stderr,"\n");} while(0); +#define USB_DBG_HEX(A,B) debug_hex(A,B) +void debug_hex(uint8_t* buf, int size); +#else +#define USB_DBG(...) while(0) +#define USB_DBG_HEX(A,B) while(0) +#endif + +#define USB_TEST_ASSERT(A) while(!(A)){fprintf(stderr,"\n\n%s@%d %s ASSERT!\n\n",__PRETTY_FUNCTION__,__LINE__,#A);exit(1);}; +#define USB_TEST_ASSERT_FALSE(A) USB_TEST_ASSERT(!(A)) + +#define BD_OWN_MASK (1<<7) +#define BD_DATA01_MASK (1<<6) +#define BD_KEEP_MASK (1<<5) +#define BD_NINC_MASK (1<<4) +#define BD_DTS_MASK (1<<3) +#define BD_STALL_MASK (1<<2) + +#define TX 1 +#define RX 0 + +#define EP0_BDT_IDX(dir, odd) (((2 * dir) + (1 * odd))) + +#define SETUP_TOKEN 0x0D +#define IN_TOKEN 0x09 +#define OUT_TOKEN 0x01 + +// for each endpt: 8 bytes +struct BDT { + uint8_t info; // BD[0:7] + uint8_t dummy; // RSVD: BD[8:15] + uint16_t byte_count; // BD[16:32] + uint32_t address; // Addr + void setBuffer(uint8_t* buf, int size) { + address = (uint32_t)buf; + byte_count = size; + } + uint8_t getStatus() { + return (info>>2)&0x0f; + } +}; + +__attribute__((__aligned__(512))) BDT bdt[64]; + +USBHALHost* USBHALHost::instHost; + +USBHALHost::USBHALHost() { + instHost = this; + report.clear(); +} + +void USBHALHost::init() { + // Disable IRQ + NVIC_DisableIRQ(USB0_IRQn); + + // choose usb src as PLL + SIM->SOPT2 |= (SIM_SOPT2_USBSRC_MASK | SIM_SOPT2_PLLFLLSEL_MASK); + + // enable OTG clock + SIM->SCGC4 |= SIM_SCGC4_USBOTG_MASK; + + // USB Module Configuration + // Reset USB Module + USB0->USBTRC0 |= USB_USBTRC0_USBRESET_MASK; + while(USB0->USBTRC0 & USB_USBTRC0_USBRESET_MASK); + + // Clear interrupt flag + USB0->ISTAT = 0xff; + + // Set BDT Base Register + USB0->BDTPAGE1=(uint8_t)((uint32_t)bdt>>8); + USB0->BDTPAGE2=(uint8_t)((uint32_t)bdt>>16); + USB0->BDTPAGE3=(uint8_t)((uint32_t)bdt>>24); + + // Set SOF threshold + USB0->SOFTHLD = USB_SOFTHLD_CNT(1); + + // 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 + USB0->CTL &= ~USB_CTL_USBENSOFEN_MASK; + + NVIC_SetVector(USB0_IRQn, (uint32_t)_usbisr); + NVIC_EnableIRQ(USB0_IRQn); + + wait_attach(); + + 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); + + // token transfer initialize + token_transfer_init(); + + USB0->INTEN |= USB_INTEN_TOKDNEEN_MASK| + USB_INTEN_ERROREN_MASK; + USB0->ERREN |= USB_ERREN_PIDERREN_MASK| + USB_ERREN_CRC5EOFEN_MASK| + USB_ERREN_CRC16EN_MASK| + USB_ERREN_DFN8EN_MASK| + USB_ERREN_BTOERREN_MASK| + USB_ERREN_DMAERREN_MASK| + USB_ERREN_BTSERREN_MASK; + + if (enumeration()) { + break; + } + USB_DBG("retry=%d", retry); + USB_TEST_ASSERT(retry > 1); + } +} + +void USBHALHost::wait_attach() { + attach_done = false; + USB0->INTEN = USB_INTEN_ATTACHEN_MASK; + while(!attach_done); + wait_ms(100); + USB_TEST_ASSERT_FALSE(USB0->CTL & USB_CTL_SE0_MASK); + lowSpeed = (USB0->CTL & USB_CTL_JSTATE_MASK) ? false : true; + if (lowSpeed) { // low speed + USB0->ENDPOINT[0].ENDPT |= USB_ENDPT_HOSTWOHUB_MASK; + } + USB_DBG("lowSpeed=%d", lowSpeed); +} + +void USBHALHost::setAddr(int _addr) { + USB0->ADDR = (lowSpeed ? USB_ADDR_LSEN_MASK : 0x00) | USB_ADDR_ADDR(_addr); +} + +void USBHALHost::setEndpoint(bool use_retry) { + USB0->ENDPOINT[0].ENDPT = (lowSpeed ? USB_ENDPT_HOSTWOHUB_MASK : 0x00)| + USB_ENDPT_EPCTLDIS_MASK| + (use_retry ? 0x00 : USB_ENDPT_RETRYDIS_MASK)| + USB_ENDPT_EPRXEN_MASK| + USB_ENDPT_EPTXEN_MASK| + USB_ENDPT_EPHSHK_MASK; +} + +void USBHALHost::token_transfer_init() { + tx_ptr = ODD; + rx_ptr = ODD; + data01.init(); +} + +int USBHALHost::token_setup(SETUP_PACKET* setup, uint16_t wLength) { + for(int retry = 0;; retry++) { + token_ready(); + USB0->ENDPOINT[0].ENDPT = (lowSpeed ? USB_ENDPT_HOSTWOHUB_MASK : 0x00) | + USB_ENDPT_RETRYDIS_MASK| + USB_ENDPT_EPRXEN_MASK| + USB_ENDPT_EPTXEN_MASK| + USB_ENDPT_EPHSHK_MASK; + CTASSERT(sizeof(SETUP_PACKET) == 8); + setup->wLength = wLength; + int idx = EP0_BDT_IDX(TX, tx_ptr); + bdt[idx].setBuffer((uint8_t*)setup, sizeof(SETUP_PACKET)); + bdt[idx].info = BD_OWN_MASK | + BD_DTS_MASK; // always data0 + token_done = false; + USB0->TOKEN = USB_TOKEN_TOKENPID(SETUP_TOKEN)|USB_TOKEN_TOKENENDPT(0); + while(!token_done); + LastStatus = bdt[idx].getStatus(); + if (LastStatus == ACK) { + if (retry > 0) { + USB_DBG("retry=%d %02x", retry, prev_LastStatus); + } + break; + } + if (retry > 10) { + break; + } + prev_LastStatus = LastStatus; + wait_ms(1); + } + data01.set(TX, 0, DATA1); + data01.set(RX, 0, DATA1); + return LastStatus; +} + +int USBHALHost::token_in(uint8_t ep, uint8_t* data, int size, int retryLimit) { + for(int retry = 0;; retry++) { + token_ready(); + int idx = EP0_BDT_IDX(RX, rx_ptr); + bdt[idx].setBuffer(data, size); + bdt[idx].info = BD_OWN_MASK| + BD_DTS_MASK| + (data01.get(RX, ep) == DATA1 ? BD_DATA01_MASK : 0); + token_done = false; + USB0->TOKEN = USB_TOKEN_TOKENPID(IN_TOKEN)|USB_TOKEN_TOKENENDPT(ep); + while(!token_done); + LastStatus = bdt[idx].getStatus(); + int len = bdt[idx].byte_count; + if (LastStatus == DATA0 || LastStatus == DATA1) { + data01.set(RX, ep, LastStatus == DATA0 ? DATA1 : DATA0); + if (retry > 0) { + USB_DBG("len=%d retry=%d %02x", len, retry, prev_LastStatus); + } + return len; + } else if (LastStatus == NAK) { + report.nak++; + } + if (retry >= retryLimit) { + return -1; + } + wait_ms(100); + prev_LastStatus = LastStatus; + } +} + +int USBHALHost::token_out(uint8_t ep, const uint8_t* data, int size) { + for(int retry = 0;; retry++) { + token_ready(); + int idx = EP0_BDT_IDX(TX, tx_ptr); + bdt[idx].setBuffer((uint8_t*)data, size); + bdt[idx].info = BD_OWN_MASK| + BD_DTS_MASK| + (data01.get(TX, ep) == DATA1 ? BD_DATA01_MASK : 0); + token_done = false; + USB0->TOKEN = USB_TOKEN_TOKENPID(OUT_TOKEN)|USB_TOKEN_TOKENENDPT(ep); + while(!token_done); + LastStatus = bdt[idx].getStatus(); + int len = bdt[idx].byte_count; + //USB_DBG("len=%d %02x", len, LastStatus); + if (LastStatus == ACK) { + data01.toggle(TX, ep); + if (retry > 0) { + USB_DBG("len=%d retry=%d %02x", len, retry, prev_LastStatus); + } + return len; + } else if (LastStatus == NAK) { + report.nak++; + } + if (retry > 10) { + return -1; + } + wait_ms(100); + prev_LastStatus = LastStatus; + } +} + +void USBHALHost::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 USBHALHost::_usbisr(void) { + if (instHost) { + instHost->UsbIrqhandler(); + } +} + +void USBHALHost::UsbIrqhandler() { + 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 = next_ptr; + } else { + rx_ptr = next_ptr; + } + token_done = true; + } + if (istat & USB_ISTAT_ATTACH_MASK) { + USB0->INTEN &= ~USB_INTEN_ATTACHEN_MASK; + attach_done = true; + } + if (istat & USB_ISTAT_ERROR_MASK) { + uint8_t errstat = USB0->ERRSTAT; + if (errstat & USB_ERRSTAT_PIDERR_MASK) { + report.errstat_piderr++; + } + if (errstat & USB_ERRSTAT_CRC5EOF_MASK) { + report.errstat_crc5eof++; + } + if (errstat & USB_ERRSTAT_CRC16_MASK) { + report.errstat_crc16++; + } + if (errstat & USB_ERRSTAT_DFN8_MASK) { + report.errstat_dfn8++; + } + if (errstat & USB_ERRSTAT_BTOERR_MASK) { + report.errstat_btoerr++; + } + if (errstat & USB_ERRSTAT_DMAERR_MASK) { + report.errstat_dmaerr++; + } + if (errstat & USB_ERRSTAT_BTSERR_MASK) { + report.errstat_btoerr++; + } + USB0->ERRSTAT = errstat; + } + USB0->ISTAT = istat; // clear +} + +void Report::clear() { + errstat_piderr = 0; + errstat_crc5eof = 0; + errstat_crc16 = 0; + errstat_dfn8 = 0; + errstat_btoerr = 0; + errstat_dmaerr = 0; + errstat_bsterr = 0; + // + nak = 0; +} + +void Report::print_errstat() { + printf("ERRSTAT PID: %d, CRC5EOF: %d, CRC16: %d, DFN8: %d, BTO: %d, DMA: %d, BST: %d\n", + errstat_piderr, errstat_crc5eof, + errstat_crc16, errstat_dfn8, + errstat_btoerr, errstat_dmaerr, errstat_bsterr); +} + +void Data01::init() { + memset(txrx_data01, DATA0, sizeof(txrx_data01)); +} + +void Data01::set(int txrx, int ep, uint8_t _data01) { + if (ep == 0) { + txrx = 0; + } + txrx_data01[txrx][ep] = _data01; +} + +void Data01::toggle(int txrx, int ep) { + if (ep == 0) { + txrx = 0; + } + txrx_data01[txrx][ep] = txrx_data01[txrx][ep] == DATA0 ? DATA1 : DATA0; +} + +uint8_t Data01::get(int txrx, int ep) { + if (ep == 0) { + txrx = 0; + } + return txrx_data01[txrx][ep]; +} + +void debug_hex(uint8_t* buf, int size) { + for(int i = 0; i < size; i++) { + fprintf(stderr, "%02x ", buf[i]); + if (i%16 == 15) { + fprintf(stderr, "\r\n"); + } + } + fprintf(stderr, "\r\n"); +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHost/USBHALHost.h Sat Jan 25 12:51:44 2014 +0000 @@ -0,0 +1,86 @@ +// Simple USBHost for FRDM-KL46Z +#pragma once +#include "mbed.h" +#include "USBHostTypes.h" +#include "USBEndpoint.h" + +struct SETUP_PACKET { + uint8_t bmRequestType; + uint8_t bRequest; + uint16_t wValue; + uint16_t wIndex; + uint16_t wLength; +}; + +#define GET_CONFIGURATION 8 + +// 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, +}; + +class Report { +public: + void clear(); + void print_errstat(); + // error count + uint32_t errstat_piderr; // USBx_ERRSTAT[PIDERR] + uint32_t errstat_crc5eof;// USBx_ERRSTAT[CRC5EOF] + uint32_t errstat_crc16; // USBx_ERRSTAT[CRC16] + uint32_t errstat_dfn8; // USBx_ERRSTAT[DFN8] + uint32_t errstat_btoerr; // USBx_ERRSTAT[BTOERR] + uint32_t errstat_dmaerr; // USBx_ERRSTAT[DMAERR] + uint32_t errstat_bsterr; // USBx_ERRSTAT[BTSERR] + // + uint32_t nak; +}; + +class Data01 { +public: + void init(); + void set(int txrx, int ep, uint8_t _data01); + void toggle(int txrx, int ep); + uint8_t get(int txrx, int ep); +private: + uint8_t txrx_data01[2][16]; +}; + +class USBHALHost { +public: + uint8_t LastStatus; + uint8_t prev_LastStatus; + Report report; + +protected: + USBHALHost(); + void init(); + virtual bool enumeration() = 0; + bool lowSpeed; + int MaxPacketSize0; + void setAddr(int addr); + void setEndpoint(bool use_retry = false); + void token_transfer_init(); + int token_setup(SETUP_PACKET* setup, uint16_t wLength = 0); + int token_in(uint8_t ep, uint8_t* data = NULL, int size = 0, int retryLimit = 10); + int token_out(uint8_t ep, const uint8_t* data = NULL, int size = 0); + void token_ready(); +private: + static void _usbisr(void); + void UsbIrqhandler(); + __IO bool attach_done; + __IO bool token_done; + void wait_attach(); + Data01 data01; + ODD_EVEN tx_ptr; + ODD_EVEN rx_ptr; + static USBHALHost * instHost; +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHost/USBHost.cpp Sat Jan 25 12:51:44 2014 +0000 @@ -0,0 +1,331 @@ +// Simple USBHost for FRDM-KL46Z +#include "USBHost.h" +#include <algorithm> + +template <bool>struct CtAssert; +template <>struct CtAssert<true> {}; +#define CTASSERT(A) CtAssert<A>(); + + +#ifdef _USB_DBG +#define USB_DBG(...) do{fprintf(stderr,"[%s@%d] ",__PRETTY_FUNCTION__,__LINE__);fprintf(stderr,__VA_ARGS__);fprintf(stderr,"\n");} while(0); +#define USB_DBG2(...) do{fprintf(stderr,"[%s@%d] ",__PRETTY_FUNCTION__,__LINE__);fprintf(stderr,__VA_ARGS__);fprintf(stderr,"\n");} while(0); +#define USB_DBG_HEX(A,B) debug_hex(A,B) +#define USB_DBG_ERRSTAT() report.print_errstat(); +void debug_hex(uint8_t* buf, int size); +#else +#define USB_DBG(...) while(0) +#define USB_DBG2(...) while(0) +#define USB_DBG_HEX(A,B) while(0) +#define USB_DBG_ERRSTAT() while(0) +#endif + +#define USB_TEST_ASSERT(A) while(!(A)){fprintf(stderr,"\n\n%s@%d %s ASSERT!\n\n",__PRETTY_FUNCTION__,__LINE__,#A);exit(1);}; +#define USB_TEST_ASSERT_FALSE(A) USB_TEST_ASSERT(!(A)) + +#define USB_INFO(...) do{fprintf(stderr,__VA_ARGS__);}while(0); + +USBHost* USBHost::inst = NULL; + +USBHost* USBHost::getHostInst() +{ + if (inst == NULL) { + inst = new USBHost(); + inst->init(); + } + return inst; +} + +USBHost::USBHost() { +} + +/* virtual */ 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); + if (result < 8) { + USB_DBG("result=%d %02x", result, LastStatus); + USB_DBG_ERRSTAT(); + return false; + } + USB_DBG_HEX(desc, result); + USB_DBG_ERRSTAT(); + DeviceDescriptor* dev_desc = reinterpret_cast<DeviceDescriptor*>(desc); + MaxPacketSize0 = dev_desc->bMaxPacketSize; + + 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); + USB_DBG_ERRSTAT(); + return false; + } + wait_ms(100); + dev_addr = 1; + + result = ControlRead(&setup_get_descriptor, desc, sizeof(desc)); + if (result < 8) { + USB_DBG("result=%d", result); + USB_DBG_ERRSTAT(); + return false; + } + USB_DBG_HEX(desc, result); + USB_DBG_ERRSTAT(); + + USB_INFO("VID: %04x, PID: %04x\n", dev_desc->idVendor, dev_desc->idProduct); + if (dev_desc->bDeviceClass == HUB_CLASS) { + USB_INFO("USB hub not supported.\n\n"); + exit(1); + } + + setup_get_descriptor.wValue = 2<<8; // config descriptor + result = ControlRead(&setup_get_descriptor, desc, 4); + if (result != 4) { + USB_DBG("result=%d", result); + USB_DBG_ERRSTAT(); + return false; + } + USB_DBG_HEX(desc, 4); + USB_DBG_ERRSTAT(); + + int TotalLength = desc[2]|desc[3]<<8; + uint8_t* buf = new uint8_t[TotalLength]; + result = ControlRead(&setup_get_descriptor, buf, TotalLength); + if (result != TotalLength) { + USB_DBG("result=%d TotalLength=%d %02x", result, TotalLength, LastStatus); + USB_DBG_ERRSTAT(); + return false; + } + USB_DBG_HEX(buf, TotalLength); + USB_DBG_ERRSTAT(); + + for(int i = 0; i < TotalLength; ) { + int Length = buf[i]; + uint8_t DescriptorType = buf[i+1]; + if (DescriptorType == 0x05) { // endpoint + EndpointDescriptor* desc = reinterpret_cast<EndpointDescriptor*>(buf+i); + USBEndpoint* ep = NULL; + if (desc->bmAttributes == 0x03) { // interrupt + if (desc->bEndpointAddress & 0x80) { + ep = &ep_int_in; + } + } else if (desc->bmAttributes == 0x02) { // bulk + ep = (desc->bEndpointAddress & 0x80) ? &ep_bulk_in : &ep_bulk_out; + } + if (ep) { + ep->setAddress(desc->bEndpointAddress); + ep->setSize(desc->wMaxPacketSize); + } + } + USB_DBG_HEX(buf+i, Length); + i += Length; + } + delete[] buf; + + // 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); + USB_DBG_ERRSTAT(); + if (lowSpeed && LastStatus == STALL) { // TODO: + wait_ms(100); + return true; + } + return false; + } + wait_ms(100); + return true; +} + +USB_TYPE USBHost::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 = ControlRead(&setup, buf, len); + USB_DBG2("result=%d %02x", result, LastStatus); + return (result >= 0) ? USB_TYPE_OK : USB_TYPE_ERROR; +} + +USB_TYPE USBHost::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 = ControlWrite(&setup, buf, len); + if (result >= 0) { + return USB_TYPE_OK; + } + USB_DBG("result=%d %02x", result, LastStatus); + USB_DBG_ERRSTAT(); + USB_DBG_HEX(buf, len); + return USB_TYPE_ERROR; +} + +USB_TYPE USBHost::bulkRead(USBDeviceConnected * dev, USBEndpoint * ep, uint8_t * buf, uint32_t len, bool blocking) { + USB_TEST_ASSERT(blocking); + int result = BulkRead(buf, len); + if (result >= 0) { + return USB_TYPE_OK; + } + //USB_DBG2("result=%d %02x", result, host->LastStatus); + return USB_TYPE_ERROR; +} + +USB_TYPE USBHost::bulkWrite(USBDeviceConnected * dev, USBEndpoint * ep, uint8_t * buf, uint32_t len, bool blocking) { + USB_TEST_ASSERT(blocking); + int result = BulkWrite(buf, len); + if (result >= 0) { + return USB_TYPE_OK; + } + USB_DBG2("result=%d %02x", result, LastStatus); + return USB_TYPE_ERROR; +} + +USB_TYPE USBHost::interruptWrite(USBDeviceConnected * dev, USBEndpoint * ep, uint8_t * buf, uint32_t len, bool blocking) { + USB_TEST_ASSERT(blocking); + int result = InterruptRead(buf, len); + if (result >= 0) { + return USB_TYPE_OK; + } + return USB_TYPE_ERROR; +} + +int USBHost::ControlRead(SETUP_PACKET* setup, uint8_t* data, int size) { + setAddr(dev_addr); + token_setup(setup, size); // setup stage + if (LastStatus != ACK) { + USB_DBG("setup %02x", LastStatus); + return -1; + } + 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) { + USB_DBG("token_in %d/%d %02x", read_len, size, LastStatus); + return result; + } + read_len += result; + if (result < MaxPacketSize0) { + break; + } + } + 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) { + setAddr(dev_addr); + token_setup(setup, size); // setup stage + if (LastStatus != ACK) { + USB_DBG("setup %02x", LastStatus); + return -1; + } + int write_len = 0; + if (data != NULL) { + write_len = token_out(0, data, size); + if (write_len < 0) { + return -1; + } + } + int result = token_in(0); // status stage + if (result < 0) { + USB_DBG("result=%d %02x", result, LastStatus); + //return result; + } + return write_len; +} + +int USBHost::InterruptRead(uint8_t* data, int size) { + setAddr(dev_addr); + setEndpoint(); + const int retryLimit = 0; + int max_packet_size = ep_int_in.getSize(); + int read_len = 0; + for(int n = 0; read_len < size; n++) { + int size2 = std::min(size-read_len, max_packet_size); + int result = token_in(ep_int_in.getAddress() & 0x7f, data+read_len, size2, retryLimit); + if (result < 0) { + if (LastStatus == NAK) { + if (n == 0) { + return -1; + } + break; + } + USB_DBG("token_in result=%d %02x", result, LastStatus); + return result; + } + read_len += result; + if (result < max_packet_size) { + break; + } + } + return read_len; +} + +int USBHost::BulkRead(uint8_t* data, int size, int timeout_ms) { + setAddr(dev_addr); + setEndpoint(); + int max_packet_size = ep_bulk_in.getSize(); + int retryLimit = (timeout_ms == 0) ? 0 : 10; + int read_len = 0; + Timer t; + for(int n = 0; read_len < size; n++) { + int size2 = std::min(size-read_len, max_packet_size); + int result = token_in(ep_bulk_in.getAddress() & 0x7f, data+read_len, size2, retryLimit); + if (result < 0) { + if (LastStatus == NAK) { + if (n == 0) { + return -1; + } + break; + } + USB_DBG("token_in result=%d %02x", result, LastStatus); + return result; + } + read_len += result; + if (result < max_packet_size) { + break; + } + if (timeout_ms > 0 && t.read_ms() > timeout_ms) { + USB_DBG("timeout_ms: %d", timeout_ms); + break; + } + } + return read_len; +} + +int USBHost::BulkWrite(const uint8_t* data, int size) { + setAddr(dev_addr); + setEndpoint(); + int max_packet_size = ep_bulk_out.getSize(); + int write_len = 0; + for(int n = 0; write_len < size; n++) { + int size2 = std::min(size-write_len, max_packet_size); + int result = token_out(ep_bulk_out.getAddress(), data+write_len, size2); + if (result < 0) { + if (LastStatus == NAK) { + if (n == 0) { + return -1; + } + break; + } + //USB_DBG("token_in result=%d %02x", result, LastStatus); + return result; + } + write_len += result; + if (result < max_packet_size) { + break; + } + } + return write_len; +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHost/USBHost.h Sat Jan 25 12:51:44 2014 +0000 @@ -0,0 +1,113 @@ +// Simple USBHost for FRDM-KL46Z +#pragma once +#include "mbed.h" +#include "USBHALHost.h" +#include "USBEndpoint.h" + +class USBDeviceConnected {}; //dummy +class IUSBEnumerator {}; // dummy + +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 interrupt 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 interrupt 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); + + int ControlRead(SETUP_PACKET* setup, uint8_t* data, int size); + int ControlWrite(SETUP_PACKET* setup, uint8_t* data = NULL, int size = 0); + int BulkRead(uint8_t* data, int size, int timeout_ms = -1); + int BulkWrite(const uint8_t* data, int size); + int InterruptRead(uint8_t* data, int size); + +private: + USBHost(); + static USBHost* inst; + virtual bool enumeration(); + int dev_addr; + USBEndpoint ep_int_in; + USBEndpoint ep_bulk_in; + USBEndpoint ep_bulk_out; +}; +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHost/USBHostConf.h Sat Jan 25 12:51:44 2014 +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 Sat Jan 25 12:51:44 2014 +0000 @@ -0,0 +1,158 @@ +/* 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 + +#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 + +#pragma pack(push,1) +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; +#pragma pack(pop) + +#endif
--- a/USBHostGPS.h Thu Jan 23 08:32:54 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,21 +0,0 @@ -// Simple USBHost GPS Dongle for FRDM-KL46Z -#include "USBHost.h" - -#define PL2303_SET_LINE_CODING 0x20 - -class USBHostGPS { -public: - USBHostGPS(int baud = 38400) { - host = USBHost::getHostInst(); - // stop bit = 1, parity = none, 8bit - uint8_t data[] = {baud&0xff, baud>>8, baud>>16, baud>>24, 0x00, 0x00, 0x08}; - SETUP_PACKET setup = {0x21, PL2303_SET_LINE_CODING, 0, 0, 0}; - host->ControlWrite(&setup, data, sizeof(data)); - } - int readNMEA(char* data, int size) { - return host->BulkRead((uint8_t*)data, size); - } - -private: - USBHost * host; -};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHostGPS/USBHostGPS.h Sat Jan 25 12:51:44 2014 +0000 @@ -0,0 +1,21 @@ +// Simple USBHost GPS Dongle for FRDM-KL46Z +#include "USBHost.h" + +#define PL2303_SET_LINE_CODING 0x20 + +class USBHostGPS { +public: + USBHostGPS(int baud = 38400) { + host = USBHost::getHostInst(); + // stop bit = 1, parity = none, 8bit + uint8_t data[] = {baud&0xff, baud>>8, baud>>16, baud>>24, 0x00, 0x00, 0x08}; + SETUP_PACKET setup = {0x21, PL2303_SET_LINE_CODING, 0, 0, 0}; + host->ControlWrite(&setup, data, sizeof(data)); + } + int readNMEA(char* data, int size) { + return host->BulkRead((uint8_t*)data, size); + } + +private: + USBHost * host; +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHostHID/USBHostMouse.h Sat Jan 25 12:51:44 2014 +0000 @@ -0,0 +1,16 @@ +// Simple USBHost Mouse for FRDM-KL46Z +#include "USBHost.h" + +class USBHostMouse { +public: + USBHostMouse() { + host = USBHost::getHostInst(); + } + int readReport(uint8_t* data) { + return host->InterruptRead(data, 4); + } + +private: + USBHost * host; +}; +
--- a/USBHostMSD.cpp Thu Jan 23 08:32:54 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,290 +0,0 @@ -/* 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; -} -
--- a/USBHostMSD.h Thu Jan 23 08:32:54 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,185 +0,0 @@ -/* 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) { - int result = host->BulkRead(buf, len); - if (result >= 0) { - return USB_TYPE_OK; - } - //USB_DBG2("result=%d %02x", result, host->LastStatus); - 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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHostMSD/FATFileSystem.lib Sat Jan 25 12:51:44 2014 +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/USBHostMSD/USBHostMSD.cpp Sat Jan 25 12:51:44 2014 +0000 @@ -0,0 +1,291 @@ +/* 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(); + report = &host->report; +} + +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 blockCount: %lld, blockSize: %d, Capacity: %lld\r\n", blockCount, blockSize, blockCount*blockSize); + } + return status; +} + + +int USBHostMSD::SCSIRequestSense() { + USB_DBG("Request sense"); + uint8_t cmd[6] = {0x03,0,0,0,18,0}; + uint8_t result[18]; + int status = SCSITransfer(cmd, 6, DEVICE_TO_HOST, result, 18); + return status; +} + + +int USBHostMSD::inquiry(uint8_t lun, uint8_t page_code) { + USB_DBG("Inquiry"); + uint8_t evpd = (page_code == 0) ? 0 : 1; + uint8_t cmd[6] = {0x12, (lun << 5) | evpd, page_code, 0, 36, 0}; + uint8_t result[36]; + int status = SCSITransfer(cmd, 6, DEVICE_TO_HOST, result, 36); + if (status == 0) { + char vid_pid[17]; + memcpy(vid_pid, &result[8], 8); + vid_pid[8] = 0; + USB_INFO("MSD Vendor ID: %s", vid_pid); + + memcpy(vid_pid, &result[16], 16); + vid_pid[16] = 0; + USB_INFO("MSD Product ID: %s", vid_pid); + + memcpy(vid_pid, &result[32], 4); + vid_pid[4] = 0; + USB_INFO("MSD Product rev: %s", vid_pid); + } + return status; +} + +int USBHostMSD::checkResult(uint8_t res, USBEndpoint * ep) { + // if ep stalled: send clear feature + if (res == USB_TYPE_STALL_ERROR) { + res = host->controlWrite(dev, + USB_RECIPIENT_ENDPOINT | USB_HOST_TO_DEVICE | USB_REQUEST_TYPE_STANDARD, + CLEAR_FEATURE, + 0, ep->getAddress(), NULL, 0); + // set state to IDLE if clear feature successful + if (res == USB_TYPE_OK) { + ep->setState(USB_TYPE_IDLE); + } + } + + if (res != USB_TYPE_OK) + return -1; + + return 0; +} + + +int USBHostMSD::SCSITransfer(uint8_t * cmd, uint8_t cmd_len, int flags, uint8_t * data, uint32_t transfer_len) { + + int res = 0; + + cbw.Signature = CBW_SIGNATURE; + cbw.Tag = 0; + cbw.DataLength = transfer_len; + cbw.Flags = flags; + cbw.LUN = 0; + cbw.CBLength = cmd_len; + memset(cbw.CB,0,sizeof(cbw.CB)); + if (cmd) { + memcpy(cbw.CB,cmd,cmd_len); + } + + // send the cbw + USB_DBG("Send CBW"); + res = host->bulkWrite(dev, bulk_out,(uint8_t *)&cbw, 31); + if (checkResult(res, bulk_out)) + return -1; + + // data stage if needed + if (data) { + USB_DBG("data stage"); + if (flags == HOST_TO_DEVICE) { + + res = host->bulkWrite(dev, bulk_out, data, transfer_len); + if (checkResult(res, bulk_out)) + return -1; + + } else if (flags == DEVICE_TO_HOST) { + + res = host->bulkRead(dev, bulk_in, data, transfer_len); + if (checkResult(res, bulk_in)) + return -1; + } + } + + // status stage + csw.Signature = 0; + USB_DBG("Read CSW"); + res = host->bulkRead(dev, bulk_in,(uint8_t *)&csw, 13); + if (checkResult(res, bulk_in)) + return -1; + + if (csw.Signature != CSW_SIGNATURE) { + return -1; + } + + USB_DBG("recv csw: status: %d", csw.Status); + + // ModeSense? + if ((csw.Status == 1) && (cmd[0] != 0x03)) { + USB_DBG("request mode sense"); + return SCSIRequestSense(); + } + + // perform reset recovery + if ((csw.Status == 2) && (cmd[0] != 0x03)) { + + // send Bulk-Only Mass Storage Reset request + res = host->controlWrite( dev, + USB_RECIPIENT_INTERFACE | USB_HOST_TO_DEVICE | USB_REQUEST_TYPE_CLASS, + BO_MASS_STORAGE_RESET, + 0, msd_intf, NULL, 0); + + // unstall both endpoints + res = host->controlWrite( dev, + USB_RECIPIENT_ENDPOINT | USB_HOST_TO_DEVICE | USB_REQUEST_TYPE_STANDARD, + CLEAR_FEATURE, + 0, bulk_in->getAddress(), NULL, 0); + + res = host->controlWrite( dev, + USB_RECIPIENT_ENDPOINT | USB_HOST_TO_DEVICE | USB_REQUEST_TYPE_STANDARD, + CLEAR_FEATURE, + 0, bulk_out->getAddress(), NULL, 0); + + } + + return csw.Status; +} + + +int USBHostMSD::dataTransfer(uint8_t * buf, uint32_t block, uint8_t nbBlock, int direction) { + uint8_t cmd[10]; + memset(cmd,0,10); + cmd[0] = (direction == DEVICE_TO_HOST) ? 0x28 : 0x2A; + + cmd[2] = (block >> 24) & 0xff; + cmd[3] = (block >> 16) & 0xff; + cmd[4] = (block >> 8) & 0xff; + cmd[5] = block & 0xff; + + cmd[7] = (nbBlock >> 8) & 0xff; + cmd[8] = nbBlock & 0xff; + + return SCSITransfer(cmd, 10, direction, buf, blockSize*nbBlock); +} + +int USBHostMSD::getMaxLun() { + uint8_t buf[1], res; + res = host->controlRead( dev, USB_RECIPIENT_INTERFACE | USB_DEVICE_TO_HOST | USB_REQUEST_TYPE_CLASS, + 0xfe, 0, msd_intf, buf, 1); + USB_DBG("max lun: %d", buf[0]); + return res; +} + +int USBHostMSD::disk_initialize() { + USB_DBG("FILESYSTEM: init"); + int i, timeout = 10; + + //getMaxLun(); + + for (i = 0; i < timeout; i++) { + wait_ms(100); + if (!testUnitReady()) + break; + } + + if (i == timeout) { + disk_init = false; + return -1; + } + + inquiry(0, 0); + disk_init = 1; + return readCapacity(); +} + +int USBHostMSD::disk_write(const uint8_t *buffer, uint64_t block_number) { + USB_DBG("FILESYSTEM: write block: %lld", block_number); + if (!disk_init) { + disk_initialize(); + } + if (!disk_init) + return -1; + return dataTransfer((uint8_t *)buffer, block_number, 1, HOST_TO_DEVICE); +} + +int USBHostMSD::disk_read(uint8_t * buffer, uint64_t block_number) { + USB_DBG("FILESYSTEM: read block %lld", block_number); + if (!disk_init) { + disk_initialize(); + } + if (!disk_init) + return -1; + return dataTransfer((uint8_t *)buffer, block_number, 1, DEVICE_TO_HOST); +} + +uint64_t USBHostMSD::disk_sectors() { + USB_DBG("FILESYSTEM: sectors"); + if (!disk_init) { + disk_initialize(); + } + if (!disk_init) + return 0; + return blockCount; +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHostMSD/USBHostMSD.h Sat Jan 25 12:51:44 2014 +0000 @@ -0,0 +1,122 @@ +/* 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 + +#if 1 +#define USB_INFO(...) do{fprintf(stderr,__VA_ARGS__);fprintf(stderr,"\r\n");}while(0); +#else +#define USB_INFO(...) while(0); +#endif + +#include "USBHostConf.h" +#include "USBHost.h" +#include "FATFileSystem.h" + +/** + * A class to communicate a USB flash disk + */ +class USBHostMSD : public 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(); + + Report* report; +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(); +}; + +#endif
--- a/USBHostMouse.h Thu Jan 23 08:32:54 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,16 +0,0 @@ -// Simple USBHost Mouse for FRDM-KL46Z -#include "USBHost.h" - -class USBHostMouse { -public: - USBHostMouse() { - host = USBHost::getHostInst(); - } - int readReport(uint8_t* data) { - return host->InterruptRead(data, 4); - } - -private: - USBHost * host; -}; -