Simple USBHost library for LPC4088. Backward compatibility of official-USBHost.
Dependencies: FATFileSystem mbed-rtos
EA LPC4088 QSB専用の簡易USBホストライブラリです。
official-USBHostの下位互換で対応プログラムを僅かな修正で動かすことが出来ます。
examples:
Import programLPC4088-USBHostMSD_HelloWorld
Simple USBHost MSD(USB flash drive) for EA LPC4088 QSB test program
Import programLPC4088-BTstack_example
BTstack for EA LPC4088 QSB example program
Import programLPC4088-USBHostC270_example
Simple USBHost WebCam for EA LPC4088 QSB/LPC1768 test program
Revision 0:148fca6fd246, committed 2014-04-25
- Comitter:
- va009039
- Date:
- Fri Apr 25 05:18:55 2014 +0000
- Commit message:
- first commit
Changed in this revision
diff -r 000000000000 -r 148fca6fd246 FATFileSystem.lib --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/FATFileSystem.lib Fri Apr 25 05:18:55 2014 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/mbed_official/code/FATFileSystem/#e960e2b81a3c
diff -r 000000000000 -r 148fca6fd246 USBHost/BaseUsbHostDebug.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHost/BaseUsbHostDebug.cpp Fri Apr 25 05:18:55 2014 +0000 @@ -0,0 +1,98 @@ +// BaseUseHostDebug.cpp 2014/4/21 +#include "USBHost.h" +#include "BaseUsbHostDebug.h" + +void print_td(FILE* stream, HCTD* td) +{ + if (td == NULL) { + fprintf(stream, "TD %p:\n", td); + return; + } + uint32_t* p = reinterpret_cast<uint32_t*>(td); + fprintf(stream, "TD %p: %08X %08X %08X %08X", p, p[0], p[1], p[2], p[3]); + fprintf(stream, " ep=%p\n", td->ep); + uint8_t* bp = reinterpret_cast<uint8_t*>(p[1]); + uint8_t* be = reinterpret_cast<uint8_t*>(p[3]); + if (bp) { + fprintf(stream, "BF %p:", bp); + while(bp <= be) { + fprintf(stream, " %02X", *bp); + bp++; + } + fprintf(stream, "\n"); + } +} + +void print_ed(FILE* stream, HCED* ed) +{ + uint32_t* p = reinterpret_cast<uint32_t*>(ed); + while(p) { + fprintf(stream, "ED %p: %08X %08X %08X %08X\n", p, p[0], p[1], p[2], p[3]); + HCTD* td = reinterpret_cast<HCTD*>(p[2] & ~3); + HCTD* tdtail = reinterpret_cast<HCTD*>(p[1]); + while(td != NULL && td != tdtail) { + print_td(stream, td); + td = td->Next; + } + p = reinterpret_cast<uint32_t*>(p[3]); + } +} + +void print_itd(FILE* stream, HCITD* itd) +{ + if (itd == NULL) { + fprintf(stream, "ITD %p:\n", itd); + return; + } + uint32_t* p = reinterpret_cast<uint32_t*>(itd); + fprintf(stream, "ITD %p: %08X %08X %08X %08X", p, p[0], p[1], p[2], p[3]); + fprintf(stream, " ep=%p\n", itd->ep); + uint16_t* offset = reinterpret_cast<uint16_t*>(p+4); + fprintf(stream, "ITD %p: %04X %04X %04X %04X %04X %04X %04X %04X\n", offset, + offset[0], offset[1], offset[2], offset[3], offset[4], offset[5], offset[6], offset[7]); +} + +void print_ied(FILE* stream, HCED* ed) +{ + uint32_t* p = reinterpret_cast<uint32_t*>(ed); + while(p) { + fprintf(stream, "ED %p: %08X %08X %08X %08X\n", p, p[0], p[1], p[2], p[3]); + HCITD* itd = reinterpret_cast<HCITD*>(p[2] & ~3); + HCITD* itdtail = reinterpret_cast<HCITD*>(p[1]); + while(itd != NULL && itd != itdtail) { + print_itd(stream, itd); + itd = itd->Next; + } + p = reinterpret_cast<uint32_t*>(p[3]); + } +} + +void print_bytes(FILE* stream, char* s, uint8_t* buf, int len) +{ + fprintf(stream, "%s %d:", s, len); + for(int i = 0; i < len; i++) { + fprintf(stream, " %02X", buf[i]); + } + fprintf(stream, "\n"); +} + +void print_hex(FILE* stream, uint8_t* p, int len) +{ + for(int i = 0; i < len; i++) { + if (i%16 == 0) { + fprintf(stream, "%p:", p); + } + fprintf(stream, " %02X", *p); + p++; + if (i%16 == 15) { + fprintf(stream, "\n"); + } + } + fprintf(stream, "\n"); +} + +void assert_print(const char* pf, int line, const char* msg) { + fprintf(stderr, "\n\n%s@%d %s ASSERT!\n\n", pf, line, msg); + exit(1); +} +
diff -r 000000000000 -r 148fca6fd246 USBHost/BaseUsbHostDebug.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHost/BaseUsbHostDebug.h Fri Apr 25 05:18:55 2014 +0000 @@ -0,0 +1,45 @@ +// BaseUsbHostDebug.h 2014/4/22 +#pragma once + +#ifdef USB_DEBUG +//#define USB_DBG(...) do{fprintf(stderr,"[%s@%d] ",__PRETTY_FUNCTION__,__LINE__);fprintf(stderr,__VA_ARGS__);} while(0); +#define USB_DBG_IF(C, ...) if(C){fprintf(stderr,"[%s@%d] ",__PRETTY_FUNCTION__,__LINE__);fprintf(stderr,__VA_ARGS__);}else{} +#define USB_DBG_ED_IF(C,A) if(C){fprintf(stderr,"[%s@%d]\n",__PRETTY_FUNCTION__,__LINE__);print_ed(stderr,A);}else{} +#define USB_DBG_ED(A) fprintf(stderr,"[%s@%d]\n",__PRETTY_FUNCTION__,__LINE__);print_ed(stderr,A); +#else +//#define USB_DBG(...) while(0); +#define USB_DBG_IF(...) while(0); +#define USB_DBG_ED_IF(C,A) while(0) +#define USB_DBG_ED(A) while(0) +#endif + +#ifdef DEBUG +#define DBG(...) do{fprintf(stderr,"[%s@%d] ",__PRETTY_FUNCTION__,__LINE__);fprintf(stderr,__VA_ARGS__);} while(0); +#define DBG_PRINTF(...) do{fprintf(stderr,__VA_ARGS__);}while(0); +#define DBG_TD(A) do{fprintf(stderr,"[%s@%d]\n",__PRETTY_FUNCTION__,__LINE__);print_td(stderr,A);}while(0); +#define DBG_ED(A) do{fprintf(stderr,"[%s@%d]\n",__PRETTY_FUNCTION__,__LINE__);print_ed(stderr,A);}while(0); +#define DBG_ITD(A) do{fprintf(stderr,"[%s@%d]\n",__PRETTY_FUNCTION__,__LINE__);print_itd(stderr,A);}while(0); +#define DBG_IED(A) do{fprintf(stderr,"[%s@%d]\n",__PRETTY_FUNCTION__,__LINE__);print_ied(stderr,A);}while(0); +#define DBG_BYTES(A,B,C) do{fprintf(stderr,"[%s@%d] ",__PRETTY_FUNCTION__,__LINE__);print_bytes(stderr,A,B,C);}while(0); +#define DBG_HEX(A,B) do{fprintf(stderr,"[%s@%d]\n",__PRETTY_FUNCTION__,__LINE__);print_hex(stderr,A,B);}while(0); +#define DBG_OHCI(A) do{fprintf(stderr,"[%s@%d] %s: %08X\n",__PRETTY_FUNCTION__,__LINE__,#A,A);}while(0); +#else //DEBUG +#define DBG(...) while(0); +#define DBG_PRINTF(...) while(0); +#define DBG_TD(A) while(0); +#define DBG_ED(A) while(0); +#define DBG_ITD(A) while(0); +#define DBG_IED(A) while(0); +#define DBG_BYTES(A,B,C) while(0); +#define DBG_HEX(A,B) while(0); +#define DBG_OHCI(A) while(0); +#endif //DEBUG + +void print_td(FILE* stream, HCTD* td); +void print_ed(FILE* stream, HCED* ed); +void print_itd(FILE* stream, HCITD* itd); +void print_ied(FILE* stream, HCED* ed); +void print_bytes(FILE* stream, char* s, uint8_t* buf, int len); +void print_hex(FILE* stream, uint8_t* p, int len); + +
diff -r 000000000000 -r 148fca6fd246 USBHost/BaseUsbHostLib.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHost/BaseUsbHostLib.cpp Fri Apr 25 05:18:55 2014 +0000 @@ -0,0 +1,107 @@ +// BaseUsbHostLib.cpp 2014/4/22 +#include "USBHost.h" +//#define DEBUG +#include "BaseUsbHostDebug.h" +#define TEST +#include "BaseUsbHostTest.h" + +//#define DBG_USE_POSIX_MEMALIGN + +#ifdef DBG_USE_POSIX_MEMALIGN +void* usb_ram_malloc(size_t size, int aligment) +{ + TEST_ASSERT(aligment >= 4); + TEST_ASSERT(!(aligment & 3)); + void* p; + if (posix_memalign(&p, aligment, size) == 0) { + return p; + } + return NULL; +} + +void usb_ram_free(void* p) +{ + free(p); +} +#else + +#define CHUNK_SIZE 64 + +#if defined(TARGET_LPC1768) +#define USB_RAM_BASE 0x2007C000 +#define USB_RAM_SIZE 0x4000 +#define BLOCK_COUNT (USB_RAM_SIZE/CHUNK_SIZE) +#elif defined(TARGET_LPC4088) +#define USB_RAM_BASE 0x20000000 +#define USB_RAM_SIZE 0x4000 +#define BLOCK_COUNT (USB_RAM_SIZE/CHUNK_SIZE) +#else +#error "target error" +#endif + +static uint8_t* ram = NULL; +static uint8_t* map; + +static void usb_ram_init() +{ + USB_INFO("USB_RAM: 0x%p(%d)", USB_RAM_BASE, USB_RAM_SIZE); + ram = (uint8_t*)USB_RAM_BASE; + TEST_ASSERT((int)ram%256 == 0); + map = (uint8_t*)malloc(BLOCK_COUNT); + TEST_ASSERT(map); + memset(map, 0, BLOCK_COUNT); +} + +// first fit malloc +void* usb_ram_malloc(size_t size, int aligment) +{ + TEST_ASSERT(aligment >= 4); + TEST_ASSERT(!(aligment & 3)); + if (ram == NULL) { + usb_ram_init(); + } + int needs = (size+CHUNK_SIZE-1)/CHUNK_SIZE; + void* p = NULL; + for(int idx = 0; idx < BLOCK_COUNT;) { + bool found = true; + for(int i = 0; i < needs; i++) { + int block = map[idx + i]; + if (block != 0) { + idx += block; + found = false; + break; + } + } + if (!found) { + continue; + } + p = ram+idx*CHUNK_SIZE; + if ((int)p % aligment) { + idx++; + continue; + } + TEST_ASSERT((idx + needs) <= BLOCK_COUNT); + for(int i = 0; i < needs; i++) { + map[idx + i] = needs - i; + } + break; + } + TEST_ASSERT(p); + return p; +} + +void usb_ram_free(void* p) +{ + TEST_ASSERT(p >= ram); + TEST_ASSERT(p < (ram+CHUNK_SIZE*BLOCK_COUNT)); + int idx = ((int)p-(int)ram)/CHUNK_SIZE; + int block = map[idx]; + TEST_ASSERT(block >= 1); + for(int i =0; i < block; i++) { + map[idx + i] = 0; + } +} + +#endif // DBG_USE_POSIX_MEMALIGN + +
diff -r 000000000000 -r 148fca6fd246 USBHost/BaseUsbHostTest.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHost/BaseUsbHostTest.h Fri Apr 25 05:18:55 2014 +0000 @@ -0,0 +1,22 @@ +// BaseUsbHostTest.h 2014/4/22 +#pragma once + +#ifndef CTASSERT +template <bool>struct CtAssert; +template <>struct CtAssert<true> {}; +#define CTASSERT(A) CtAssert<A>(); +#endif //CTASSERT + +#ifdef TEST +//#define USB_TEST_ASSERT(A) if(A){}else{assert_print(__PRETTY_FUNCTION__, __LINE__, #A);} +#define TEST_ASSERT(A) if(A){}else{assert_print(__PRETTY_FUNCTION__, __LINE__,#A);} +#define TEST_ASSERT_TRUE(A) if(A){}else{assert_print(__PRETTY_FUNCTION__, __LINE__, #A);} +#define TEST_ASSERT_FALSE(A) if(A){assert_print(__PRETTY_FUNCTION__, __LINE__, #A);}else{} +#define TEST_ASSERT_EQUAL(A,B) if (A == B){}else{assert_print(__PRETTY_FUNCTION__, __LINE__, #A);} +void assert_print(const char* pf, int line, const char* msg); +#else +#define TEST_ASSERT(A) +#define TEST_ASSERT_TRUE(A) while(0); +#define TEST_ASSERT_FALSE(A) while(0); +#define TEST_ASSERT_EQUAL(A,B) while(0); +#endif
diff -r 000000000000 -r 148fca6fd246 USBHost/IUSBEnumerator.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHost/IUSBEnumerator.h Fri Apr 25 05:18:55 2014 +0000 @@ -0,0 +1,36 @@ +/* mbed USBHost Library + * Copyright (c) 2006-2013 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef IUSBENUMERATOR_H_ +#define IUSBENUMERATOR_H_ + +#include "stdint.h" +#include "USBEndpoint.h" + +/* +Generic interface to implement for "smart" USB enumeration +*/ + +class IUSBEnumerator +{ +public: + virtual void setVidPid(uint16_t vid, uint16_t pid) = 0; + virtual bool parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol) = 0; //Must return true if the interface should be parsed + virtual bool useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir) = 0; //Must return true if the endpoint will be used +}; + +#endif /*IUSBENUMERATOR_H_*/ +
diff -r 000000000000 -r 148fca6fd246 USBHost/USBDeviceConnected.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHost/USBDeviceConnected.cpp Fri Apr 25 05:18:55 2014 +0000 @@ -0,0 +1,89 @@ +/* mbed USBHost Library + * Copyright (c) 2006-2013 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "USBDeviceConnected.h" +#include "dbg.h" + +USBDeviceConnected::USBDeviceConnected() { + init(); +} + +void USBDeviceConnected::init() { + port = 0; + vid = 0; + pid = 0; + nb_interf = 0; + enumerated = false; + device_class = 0; + device_subclass = 0; + proto = 0; + lowSpeed = false; + hub_parent = NULL; +} + +bool USBDeviceConnected::addInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol) { + USB_DBG("intf_nb=%d", intf_nb); + if (intf.count(intf_nb) > 0) { + return false; + } + intf[intf_nb] = new INTERFACE(intf_class, intf_subclass, intf_protocol); + return true; +} + +bool USBDeviceConnected::addEndpoint(uint8_t intf_nb, USBEndpoint * ept) { + if (intf.count(intf_nb) > 0) { + intf[intf_nb]->ep.push_back(ept); + return true; + } + return false; +} + +void USBDeviceConnected::init(USBDeviceConnected* parent, uint8_t port_, bool lowSpeed_) { + USB_DBG("init dev: %p", this); + init(); + hub_parent = parent; + port = port_; + lowSpeed = lowSpeed_; +} + +void USBDeviceConnected::disconnect() { + //for(int i = 0; i < MAX_INTF; i++) { + // intf[i].detach.call(); + //} + //init(); +} + + +USBEndpoint * USBDeviceConnected::getEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir, uint8_t index) { + USB_DBG("intf_nb=%d", intf_nb); + USB_TEST_ASSERT(intf.count(intf_nb) > 0); + INTERFACE* inter = intf[intf_nb]; + for (int i = 0; i < inter->ep.size(); i++) { + if ((inter->ep[i]->getType() == type) && (inter->ep[i]->getDir() == dir)) { + if(index) { + index--; + } else { + return inter->ep[i]; + } + } + } + return NULL; +} + +USBEndpoint * USBDeviceConnected::getEndpoint(uint8_t intf_nb, uint8_t index) { + USB_TEST_ASSERT(intf.count(intf_nb) > 0); + return intf[intf_nb]->ep[index]; +}
diff -r 000000000000 -r 148fca6fd246 USBHost/USBDeviceConnected.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHost/USBDeviceConnected.h Fri Apr 25 05:18:55 2014 +0000 @@ -0,0 +1,133 @@ +/* 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. + */ +#pragma once + +#include "USBEndpoint.h" +#include "USBHostConf.h" +#include "myvector.h" +#include "mymap.h" + +class USBEndpoint; + +struct INTERFACE { + INTERFACE(uint8_t _class, uint8_t _subclass, uint8_t _protocol) { + intf_class = _class; + intf_subclass = _subclass; + intf_protocol = _protocol; + } + uint8_t intf_class; + uint8_t intf_subclass; + uint8_t intf_protocol; + myvector<USBEndpoint*>ep; +}; + +/** +* USBDeviceConnected class +*/ +class USBDeviceConnected { +public: + + /** + * Constructor + */ + USBDeviceConnected(); + + /** + * Attach an USBEndpoint to this device + * + * @param intf_nb interface number + * @param ep pointeur on the USBEndpoint which will be attached + * @returns true if successful, false otherwise + */ + bool addEndpoint(uint8_t intf_nb, USBEndpoint * ep); + + /** + * Retrieve an USBEndpoint by its TYPE and DIRECTION + * + * @param intf_nb the interface on which to lookup the USBEndpoint + * @param type type of the USBEndpoint looked for + * @param dir direction of the USBEndpoint looked for + * @param index the index of the USBEndpoint whitin the interface + * @returns pointer on the USBEndpoint if found, NULL otherwise + */ + USBEndpoint * getEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir, uint8_t index = 0); + + /** + * Retrieve an USBEndpoint by its index + * + * @param intf_nb interface number + * @param index index of the USBEndpoint + * @returns pointer on the USBEndpoint if found, NULL otherwise + */ + USBEndpoint * getEndpoint(uint8_t intf_nb, uint8_t index); + + /** + * Add a new interface to this device + * + * @param intf_nb interface number + * @param intf_class interface class + * @param intf_subclass interface subclass + * @param intf_protocol interface protocol + * @returns true if successful, false otherwise + */ + bool addInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol); + + /** + * Disconnect the device by calling a callback function registered by a driver + */ + void disconnect(); + + void init(USBDeviceConnected* parent, uint8_t _port, bool _lowSpeed); + void setAddress(uint8_t addr_) { addr = addr_; }; + void setVid(uint16_t vid_) { vid = vid_; }; + void setPid(uint16_t pid_) { pid = pid_; }; + void setClass(uint8_t device_class_) { device_class = device_class_; } + void setSubClass(uint8_t device_subclass_) { device_subclass = device_subclass_; }; + void setProtocol(uint8_t pr) { proto = pr; }; + void setEnumerated() { enumerated = true; }; + void setNbIntf(uint8_t nb_intf) {nb_interf = nb_intf; }; + void setSpeed(bool _lowSpeed) { lowSpeed = _lowSpeed; } + void setName(const char * name_, uint8_t intf_nb) { return; }; + void setEpCtl(USBEndpoint* ep) { ep_ctl = ep; } + + static int getNewAddress() { + static int addr = 1; + return addr++; + } + uint8_t getAddress() { return addr; }; + uint16_t getVid() { return vid; }; + uint16_t getPid() { return pid; }; + uint8_t getClass() { return device_class; }; + bool getSpeed() { return lowSpeed; } + bool isEnumerated() { return enumerated; }; + USBEndpoint* getEpCtl() { return ep_ctl; } + +private: + USBDeviceConnected* hub_parent; + mymap<int,INTERFACE*>intf; + uint8_t port; + uint16_t vid; + uint16_t pid; + uint8_t addr; + uint8_t device_class; + uint8_t device_subclass; + uint8_t proto; + bool lowSpeed; + bool enumerated; + uint8_t nb_interf; + USBEndpoint* ep_ctl; + void init(); +};
diff -r 000000000000 -r 148fca6fd246 USBHost/USBEndpoint.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHost/USBEndpoint.cpp Fri Apr 25 05:18:55 2014 +0000 @@ -0,0 +1,47 @@ +/* mbed USBHost Library + * Copyright (c) 2006-2013 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "USBHost.h" +#include "BaseUsbHostDebug.h" +#include "USBEndpoint.h" +#include "BaseUsbHostTest.h" + +HCTD* USBEndpoint::get_queue_HCTD(uint32_t millisec) +{ + for(int i = 0; i < 16; i++) { + osEvent evt = m_queue.get(millisec); + if (evt.status == osEventMessage) { + HCTD* td = reinterpret_cast<HCTD*>(evt.value.p); + TEST_ASSERT(td); + uint8_t cc = td->ConditionCode(); + if (cc != 0) { + m_ConditionCode = cc; + DBG_TD(td); + } + return td; + } else if (evt.status == osOK) { + continue; + } else if (evt.status == osEventTimeout) { + return NULL; + } else { + DBG("evt.status: %02x\n", evt.status); + TEST_ASSERT(evt.status == osEventMessage); + } + } + return NULL; +} + +
diff -r 000000000000 -r 148fca6fd246 USBHost/USBEndpoint.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHost/USBEndpoint.h Fri Apr 25 05:18:55 2014 +0000 @@ -0,0 +1,163 @@ +/* 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. + */ + +#pragma once +#include "rtos.h" +#include "FunctionPointer.h" +#include "USBHostTypes.h" +#include "USBDeviceConnected.h" + +class USBDeviceConnected; + +#define HCTD_QUEUE_SIZE 3 + +struct HCTD; +struct HCED; +struct HCITD; +class USBHost; + +/** +* USBEndpoint class +*/ +class USBEndpoint { +public: + /** + * Constructor + */ + USBEndpoint(USBDeviceConnected* _dev) { + init(CONTROL_ENDPOINT, IN, 8, 0); + dev = _dev; + } + + /** + * Initialize an endpoint + * + * @param type endpoint type + * @param dir endpoint direction + * @param size endpoint size + * @param ep_number endpoint number + */ + void init(ENDPOINT_TYPE _type, ENDPOINT_DIRECTION _dir, uint32_t size, uint8_t ep_number) { + setState(USB_TYPE_FREE); + setType(_type); + dir = _dir; + MaxPacketSize = size; + address = ep_number; + m_pED = NULL; + //data01_toggle = DATA0; // for KL46Z + } + + /** + * Attach a member function to call when a transfer is finished + * + * @param tptr pointer to the object to call the member function on + * @param mptr pointer to the member function to be called + */ + template<typename T> + void attach(T* tptr, void (T::*mptr)(void)) { + if((mptr != NULL) && (tptr != NULL)) { + rx.attach(tptr, mptr); + } + } + + /** + * Attach a callback called when a transfer is finished + * + * @param fptr function pointer + */ + void attach(void (*fptr)(void)) { + if(fptr != NULL) { + rx.attach(fptr); + } + } + + /** + * Call the handler associted to the end of a transfer + */ + void call() { + rx.call(); + }; + + void irqWdhHandler(HCTD* td) {m_queue.put(td);} // WDH + HCTD* get_queue_HCTD(uint32_t millisec=osWaitForever); + HCED* m_pED; + // report + uint8_t m_ConditionCode; + int m_report_queue_error; + + void setType(ENDPOINT_TYPE _type) { type = _type; }; + void setState(USB_TYPE st){ state = st; }; + void setLengthTransferred(int len) { transferred = len; }; + void setBuffer(uint8_t* buf, int size) { buf_start = buf, buf_size = size; } + void setSize(int size) { MaxPacketSize = size; } + void setNextEndpoint(USBEndpoint* ep) { nextEp = ep; }; + + USBDeviceConnected* getDevice() { return dev; } + ENDPOINT_TYPE getType() { return type; }; + USB_TYPE getState() { return state; } + int getLengthTransferred() { return transferred; } + uint8_t *getBufStart() { return buf_start; } + int getBufSize() { return buf_size; } + uint8_t getAddress(){ return address; }; + int getSize() { return MaxPacketSize; } + ENDPOINT_DIRECTION getDir() { return dir; } + USBEndpoint* nextEndpoint() { return nextEp; }; + +private: + ENDPOINT_TYPE type; + USB_TYPE state; + ENDPOINT_DIRECTION dir; + USBDeviceConnected* dev; + uint8_t address; + int transferred; + uint8_t * buf_start; + int buf_size; + FunctionPointer rx; + int MaxPacketSize; + USBEndpoint* nextEp; + +protected: + Queue<HCTD, HCTD_QUEUE_SIZE> m_queue; // TD done queue + int m_td_queue_count; +}; + +class EndpointQueue { +public: + EndpointQueue():head(NULL),tail(NULL) {} + void push(USBEndpoint* ep) { + if (head) { + tail->setNextEndpoint(ep); + } else { + head = ep; + } + tail = ep; + ep->setNextEndpoint(NULL); + } + USBEndpoint* pop() { + USBEndpoint* ep = head; + if (ep) { + head = ep->nextEndpoint(); + } + return ep; + } + bool empty() { return head == NULL; } + +private: + USBEndpoint* head; + USBEndpoint* tail; +}; + +
diff -r 000000000000 -r 148fca6fd246 USBHost/USBHALHost.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHost/USBHALHost.cpp Fri Apr 25 05:18:55 2014 +0000 @@ -0,0 +1,452 @@ +/* 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 "USBHALHost.h" +//#define _USB_DBG +#include "BaseUsbHostDebug.h" +#include "BaseUsbHostTest.h" + +#ifndef CTASSERT +template <bool>struct CtAssert; +template <>struct CtAssert<true> {}; +#define CTASSERT(A) CtAssert<A>(); +#endif + +#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 + +#ifdef _USB_TEST +#define USB_TEST_ASSERT(A) while(!(A)){fprintf(stderr,"\n\n%s@%d %s ASSERT!\n\n",__PRETTY_FUNCTION__,__LINE__,#A);exit(1);}; +#define USB_TEST_ASSERT_FALSE(A) USB_TEST_ASSERT(!(A)) +#else +#define USB_TEST_ASSERT(A) while(0) +#define USB_TEST_ASSERT_FALSE(A) while(0) +#endif + +#define USB_INFO(...) do{fprintf(stderr,__VA_ARGS__);fprintf(stderr,"\n");}while(0); + +// bits of the USB/OTG clock control register +#define HOST_CLK_EN (1<<0) +#define DEV_CLK_EN (1<<1) +#define PORTSEL_CLK_EN (1<<3) +#define AHB_CLK_EN (1<<4) + +// bits of the USB/OTG clock status register +#define HOST_CLK_ON (1<<0) +#define DEV_CLK_ON (1<<1) +#define PORTSEL_CLK_ON (1<<3) +#define AHB_CLK_ON (1<<4) + +// we need host clock, OTG/portsel clock and AHB clock +#define CLOCK_MASK (HOST_CLK_EN | PORTSEL_CLK_EN | AHB_CLK_EN) +#define FI 0x2EDF /* 12000 bits per frame (-1) */ +#define DEFAULT_FMINTERVAL ((((6 * (FI - 210)) / 7) << 16) | FI) + +USBHALHost* USBHALHost::instHost; + +USBHALHost::USBHALHost() { + instHost = this; +} + +void USBHALHost::init() { + NVIC_DisableIRQ(USB_IRQn); + m_pHcca = new HCCA(); + init_hw_ohci(m_pHcca); + ResetRootHub(); + NVIC_SetVector(USB_IRQn, (uint32_t)_usbisr); + NVIC_SetPriority(USB_IRQn, 0); + NVIC_EnableIRQ(USB_IRQn); + +#ifndef BASE_USBHOST + USB_INFO("Simple USBHost Library for EA LPC4088 QSB"); + bool lowSpeed = wait_attach(); + addDevice(NULL, 0, lowSpeed); +#endif // BASE_USBHOST +} + +void USBHALHost::init_hw_ohci(HCCA* pHcca) { + LPC_SC->PCONP &= ~(1UL<<31); //Cut power + wait_ms(1000); + LPC_SC->PCONP |= (1UL<<31); // turn on power for USB + LPC_USB->USBClkCtrl |= CLOCK_MASK; // Enable USB host clock, port selection and AHB clock + // Wait for clocks to become available + while ((LPC_USB->USBClkSt & CLOCK_MASK) != CLOCK_MASK) + ; + LPC_USB->OTGStCtrl |= 1; + LPC_USB->USBClkCtrl &= ~PORTSEL_CLK_EN; + +#if defined(TARGET_LPC1768) + LPC_PINCON->PINSEL1 &= ~((3<<26) | (3<<28)); + LPC_PINCON->PINSEL1 |= ((1<<26)|(1<<28)); // 0x14000000 +#elif defined(TARGET_LPC4088) + LPC_IOCON->P0_29 = 0x01; // USB_D+1 + LPC_IOCON->P0_30 = 0x01; // USB_D-1 + // DO NOT CHANGE P1_19. +#else +#error "target error" +#endif + USB_DBG("initialize OHCI\n"); + wait_ms(100); /* Wait 50 ms before apply reset */ + TEST_ASSERT((LPC_USB->HcRevision&0xff) == 0x10); // check revision + LPC_USB->HcControl = 0; /* HARDWARE RESET */ + LPC_USB->HcControlHeadED = 0; /* Initialize Control list head to Zero */ + LPC_USB->HcBulkHeadED = 0; /* Initialize Bulk list head to Zero */ + /* SOFTWARE RESET */ + LPC_USB->HcCommandStatus = OR_CMD_STATUS_HCR; + LPC_USB->HcFmInterval = DEFAULT_FMINTERVAL; /* Write Fm Interval and Largest Data Packet Counter */ + LPC_USB->HcPeriodicStart = FI*90/100; + /* Put HC in operational state */ + LPC_USB->HcControl = (LPC_USB->HcControl & (~OR_CONTROL_HCFS)) | OR_CONTROL_HC_OPER; + LPC_USB->HcRhStatus = OR_RH_STATUS_LPSC; /* Set Global Power */ + TEST_ASSERT(pHcca); + for (int i = 0; i < 32; i++) { + pHcca->InterruptTable[i] = NULL; + } + LPC_USB->HcHCCA = reinterpret_cast<uint32_t>(pHcca); + LPC_USB->HcInterruptStatus |= LPC_USB->HcInterruptStatus; /* Clear Interrrupt Status */ + LPC_USB->HcInterruptEnable = OR_INTR_ENABLE_MIE|OR_INTR_ENABLE_WDH|OR_INTR_ENABLE_FNO; + + LPC_USB->HcRhPortStatus1 = OR_RH_PORT_CSC; + LPC_USB->HcRhPortStatus1 = OR_RH_PORT_PRSC; +} + +void USBHALHost::ResetRootHub() { + wait_ms(100); /* USB 2.0 spec says at least 50ms delay before port reset */ + LPC_USB->HcRhPortStatus1 = OR_RH_PORT_PRS; // Initiate port reset + USB_DBG("Before loop\n"); + while (LPC_USB->HcRhPortStatus1 & OR_RH_PORT_PRS) + ; + LPC_USB->HcRhPortStatus1 = OR_RH_PORT_PRSC; // ...and clear port reset signal + USB_DBG("After loop\n"); + wait_ms(200); /* Wait for 100 MS after port reset */ +} + +bool USBHALHost::wait_attach() { + bool lowSpeed = false; + uint32_t status = LPC_USB->HcRhPortStatus1; + if (status & OR_RH_PORT_LSDA) { // lowSpeedDeviceAttached + lowSpeed = true; + } + return lowSpeed; +} + +void USBHALHost::enable(ENDPOINT_TYPE type) { + switch(type) { + case CONTROL_ENDPOINT: + LPC_USB->HcCommandStatus |= OR_CMD_STATUS_CLF; + LPC_USB->HcControl |= OR_CONTROL_CLE; + break; + case ISOCHRONOUS_ENDPOINT: + LPC_USB->HcControl |= OR_CONTROL_PLE; + break; + case BULK_ENDPOINT: + LPC_USB->HcCommandStatus |= OR_CMD_STATUS_BLF; + LPC_USB->HcControl |= OR_CONTROL_BLE; + break; + case INTERRUPT_ENDPOINT: + LPC_USB->HcControl |= OR_CONTROL_PLE; + break; + } +} + +void USBHALHost::token_init(USBEndpoint* ep) { + if (ep->m_pED == NULL) { + ep->m_pED = new HCED(ep); + USB_DBG_ED(ep->m_pED); + } + HCED* ed = ep->m_pED; + USBDeviceConnected* dev = ep->getDevice(); + USB_TEST_ASSERT(dev); + if (dev) { + uint8_t devAddr = dev->getAddress(); + USB_DBG("devAddr=%02x", devAddr); + ed->setFunctionAddress(devAddr); + } + uint16_t size = ep->getSize(); + USB_DBG("MaxPacketSize=%d", size); + ed->setMaxPacketSize(size); + if (ed->HeadTd == NULL) { + HCTD* td = new HCTD(ep); + ed->TailTd = td; + ed->HeadTd = td; + switch(ep->getType()) { + case CONTROL_ENDPOINT: + ed->Next = reinterpret_cast<HCED*>(LPC_USB->HcControlHeadED); + LPC_USB->HcControlHeadED = reinterpret_cast<uint32_t>(ed); + break; + case BULK_ENDPOINT: + ed->Next = reinterpret_cast<HCED*>(LPC_USB->HcBulkHeadED); + LPC_USB->HcBulkHeadED = reinterpret_cast<uint32_t>(ed); + break; + case INTERRUPT_ENDPOINT: + HCCA* pHcca = reinterpret_cast<HCCA*>(LPC_USB->HcHCCA); + ed->Next = pHcca->InterruptTable[0]; + pHcca->InterruptTable[0] = ed; + break; + } + USB_DBG_ED(ed); + } +} + +int USBHALHost::token_setup(USBEndpoint* ep, SETUP_PACKET* setup, uint16_t wLength) { + token_init(ep); + HCED* ed = ep->m_pED; + HCTD* td = ed->TailTd; + setup->wLength = wLength; + TBUF* tbuf = new(sizeof(SETUP_PACKET))TBUF(setup, sizeof(SETUP_PACKET)); + td->transfer(tbuf, sizeof(SETUP_PACKET)); + td->Control |= TD_TOGGLE_0|TD_SETUP; + HCTD* blank = new HCTD(ep); + ed->enqueue(blank); + //DBG_ED(ed); + enable(ep->getType()); + + td = ep->get_queue_HCTD(); + TEST_ASSERT(td); + int result = td->getLengthTransferred(); + DBG_TD(td); + delete tbuf; + delete td; + return result; +} + +int USBHALHost::token_in(USBEndpoint* ep, uint8_t* data, int size, int retryLimit) { + token_init(ep); + HCED* ed = ep->m_pED; + HCTD* td = ed->TailTd; + TBUF* tbuf = NULL; + if (data != NULL) { + tbuf = new(size)TBUF(); + td->transfer(tbuf, size); + } + td->Control |= TD_IN; + HCTD* blank = new HCTD(ep); + ed->enqueue(blank); + USB_DBG_ED_IF(ed->EndpointNumber()==0, ed); // control transfer + enable(ep->getType()); + + td = ep->get_queue_HCTD(); + TEST_ASSERT(td); + if (data != NULL) { + memcpy(data, tbuf->buf, size); + delete tbuf; + } + int result = td->getLengthTransferred(); + delete td; + return result; +} + +int USBHALHost::token_out(USBEndpoint* ep, const uint8_t* data, int size, int retryLimit) { + token_init(ep); + HCED* ed = ep->m_pED; + HCTD* td = ed->TailTd; + TBUF* tbuf = NULL; + if (data != NULL) { + tbuf = new(size)TBUF(data, size); + td->transfer(tbuf, size); + } + td->Control |= TD_OUT; + HCTD* blank = new HCTD(ep); + ed->enqueue(blank); + DBG_ED(ed); + enable(ep->getType()); + + td = ep->get_queue_HCTD(); + TEST_ASSERT(td); + if (data != NULL) { + delete tbuf; + } + int result = td->getLengthTransferred(); + delete td; + return result; +} + +void USBHALHost::token_inNB(USBEndpoint* ep, uint8_t* data, int size) { + token_init(ep); + HCED* ed = ep->m_pED; + HCTD* td = ed->TailTd; + TBUF* tbuf = new(size)TBUF(); + td->transfer(tbuf, size); + td->Control |= TD_IN; + HCTD* blank = new HCTD(ep); + ed->enqueue(blank); + enable(ep->getType()); +} + +USB_TYPE USBHALHost::token_inNB_result(USBEndpoint* ep) { + HCTD* td = ep->get_queue_HCTD(0); + if (td) { + int len = td->getLengthTransferred(); + TBUF* tbuf = (TBUF*)td->buf_top; + memcpy(ep->getBufStart(), tbuf->buf, len); + ep->setLengthTransferred(len); + ep->setState((USB_TYPE)td->ConditionCode()); + delete td; + delete tbuf; + return USB_TYPE_OK; + } + return USB_TYPE_PROCESSING; +} + +void USBHALHost::_usbisr(void) { + if (instHost) { + instHost->UsbIrqhandler(); + } +} + +HCTD* td_reverse(HCTD* td) +{ + HCTD* result = NULL; + HCTD* next; + while(td) { + next = const_cast<HCTD*>(td->Next); + td->Next = result; + result = td; + td = next; + } + return result; +} + +void USBHALHost::UsbIrqhandler() { + if (!(LPC_USB->HcInterruptStatus & LPC_USB->HcInterruptEnable)) { + return; + } + m_report_irq++; + uint32_t status = LPC_USB->HcInterruptStatus; + if (status & OR_INTR_STATUS_FNO) { + m_report_FNO++; + } + if (status & OR_INTR_STATUS_WDH) { + union { + HCTD* done_td; + uint32_t lsb; + }; + done_td = const_cast<HCTD*>(m_pHcca->DoneHead); + TEST_ASSERT(done_td); + m_pHcca->DoneHead = NULL; // reset + if (lsb & 1) { // error ? + lsb &= ~1; + } + HCTD* td = td_reverse(done_td); + while(td) { + USBEndpoint* ep = td->ep; + TEST_ASSERT(ep); + if (ep) { + ep->irqWdhHandler(td); + } + td = td->Next; + } + m_report_WDH++; + } + LPC_USB->HcInterruptStatus = status; // Clear Interrrupt Status +} + +TBUF::TBUF(const void* data, int size) { + if (size > 0) { + memcpy(buf, data, size); + } +} + +HCTD::HCTD(USBEndpoint* obj) { + CTASSERT(sizeof(HCTD) == 36); + TEST_ASSERT(obj); + Control = TD_CC|TD_ROUNDING; + CurrBufPtr = NULL; + Next = NULL; + BufEnd = NULL; + buf_top = NULL; + buf_size = 0; + ep = obj; +} + +HCITD::HCITD(USBEndpoint* obj, uint16_t FrameNumber, int FrameCount, uint16_t PacketSize) { + Control = 0xe0000000 | // CC ConditionCode NOT ACCESSED + ((FrameCount-1) << 24)| // FC FrameCount + TD_DELAY_INT(0) | // DI DelayInterrupt + FrameNumber; // SF StartingFrame + BufferPage0 = const_cast<uint8_t*>(buf); + BufferEnd = const_cast<uint8_t*>(buf) + PacketSize * FrameCount - 1; + Next = NULL; + ep = obj; + uint32_t addr = reinterpret_cast<uint32_t>(buf); + for(int i = 0; i < FrameCount; i++) { + uint16_t offset = addr & 0x0fff; + if ((addr&0xfffff000) == (reinterpret_cast<uint32_t>(BufferEnd)&0xfffff000)) { + offset |= 0x1000; + } + OffsetPSW[i] = 0xe000|offset; + addr += PacketSize; + } +} + +HCED::HCED(USBEndpoint* ep) { + USBDeviceConnected* dev = ep->getDevice(); + int devAddr = 0; + bool lowSpeed = false; + if (dev) { + devAddr = dev->getAddress(); + lowSpeed = dev->getSpeed(); + } + int ep_number = ep->getAddress(); + int MaxPacketSize = ep->getSize(); + Control = devAddr | /* USB address */ + ((ep_number & 0x7F) << 7) | /* Endpoint address */ + (ep_number!=0?(((ep_number&0x80)?2:1) << 11):0)| /* direction : Out = 1, 2 = In */ + ((lowSpeed?1:0) << 13) | /* speed full=0 low=1 */ + (MaxPacketSize << 16); /* MaxPkt Size */ + TailTd = NULL; + HeadTd = NULL; + Next = NULL; +} + +bool HCED::enqueue(HCTD* td) { + if (td) { + HCTD* tail = reinterpret_cast<HCTD*>(TailTd); + if (tail) { + tail->Next = td; + TailTd = reinterpret_cast<HCTD*>(td); + return true; + } + } + return false; +} + +void HCED::init_queue(HCTD* td) { + TailTd = reinterpret_cast<HCTD*>(td); + HeadTd = reinterpret_cast<HCTD*>(td); +} + +void HCCA::enqueue(HCED* ed) { + for(int i = 0; i < 32; i++) { + if (InterruptTable[i] == NULL) { + InterruptTable[i] = ed; + } else { + HCED* nextEd = InterruptTable[i]; + while(nextEd->Next && nextEd->Next != ed) { + nextEd = nextEd->Next; + } + nextEd->Next = ed; + } + } +} + +
diff -r 000000000000 -r 148fca6fd246 USBHost/USBHALHost.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHost/USBHALHost.h Fri Apr 25 05:18:55 2014 +0000 @@ -0,0 +1,275 @@ +/* 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. + */ + +#pragma once +#include "mbed.h" +#include "USBHostTypes.h" +#include "USBEndpoint.h" + +#if defined(TARGET_LPC4088) +#define HcRevision Revision +#define HcControl Control +#define HcCommandStatus CommandStatus +#define HcInterruptStatus InterruptStatus +#define HcInterruptEnable InterruptEnable +#define HcHCCA HCCA +#define HcControlHeadED ControlHeadED +#define HcBulkHeadED BulkHeadED +#define HcFmInterval FmInterval +#define HcFmNumber FmNumber +#define HcPeriodicStart PeriodicStart +#define HcRhStatus RhStatus +#define HcRhPortStatus1 RhPortStatus1 +#define OTGStCtrl StCtrl +#endif +// ------------------ HcControl Register --------------------- +#define OR_CONTROL_PLE 0x00000004 +#define OR_CONTROL_IE 0x00000008 +#define OR_CONTROL_CLE 0x00000010 +#define OR_CONTROL_BLE 0x00000020 +#define OR_CONTROL_HCFS 0x000000C0 +#define OR_CONTROL_HC_OPER 0x00000080 +// ----------------- HcCommandStatus Register ----------------- +#define OR_CMD_STATUS_HCR 0x00000001 +#define OR_CMD_STATUS_CLF 0x00000002 +#define OR_CMD_STATUS_BLF 0x00000004 +// --------------- HcInterruptStatus Register ----------------- +#define OR_INTR_STATUS_WDH 0x00000002 +#define OR_INTR_STATUS_UE 0x00000010 +#define OR_INTR_STATUS_FNO 0x00000020 +#define OR_INTR_STATUS_RHSC 0x00000040 +// --------------- HcInterruptEnable Register ----------------- +#define OR_INTR_ENABLE_WDH 0x00000002 +#define OR_INTR_ENABLE_FNO 0x00000020 +#define OR_INTR_ENABLE_RHSC 0x00000040 +#define OR_INTR_ENABLE_MIE 0x80000000 +// ---------------- HcRhDescriptorA Register ------------------ +#define OR_RH_STATUS_LPSC 0x00010000 +#define OR_RH_STATUS_DRWE 0x00008000 +// -------------- HcRhPortStatus[1:NDP] Register -------------- +#define OR_RH_PORT_CCS 0x00000001 +#define OR_RH_PORT_PRS 0x00000010 +#define OR_RH_PORT_LSDA 0x00000200 +#define OR_RH_PORT_CSC 0x00010000 +#define OR_RH_PORT_PRSC 0x00100000 + +// TRANSFER DESCRIPTOR CONTROL FIELDS +#define TD_ROUNDING (uint32_t)(0x00040000) /* Buffer Rounding */ +#define TD_SETUP (uint32_t)(0x00000000) /* Direction of Setup Packet */ +#define TD_IN (uint32_t)(0x00100000) /* Direction In */ +#define TD_OUT (uint32_t)(0x00080000) /* Direction Out */ +#define TD_DELAY_INT(x) (uint32_t)((x) << 21) /* Delay Interrupt */ +#define TD_DI (uint32_t)(7<<21) /* desable interrupt */ +#define TD_TOGGLE_0 (uint32_t)(0x02000000) /* Toggle 0 */ +#define TD_TOGGLE_1 (uint32_t)(0x03000000) /* Toggle 1 */ +#define TD_CC (uint32_t)(0xF0000000) /* Completion Code */ + +struct SETUP_PACKET { + uint8_t bmRequestType; + uint8_t bRequest; + uint16_t wValue; + uint16_t wIndex; + uint16_t wLength; + SETUP_PACKET(uint8_t RequestType, uint8_t Request, uint16_t Value, uint16_t Index, uint16_t Length) { + bmRequestType = RequestType; + bRequest = Request; + wValue = Value; + wIndex = Index; + wLength = Length; + } +}; + +void* usb_ram_malloc(size_t size, int aligment); // BaseUsbHostLib.cpp +void usb_ram_free(void* p); + +struct TBUF { + uint8_t buf[0]; + TBUF(const void* data = NULL, int size = 0); + void* operator new(size_t size, int buf_size) { return usb_ram_malloc(size+buf_size, 4); } + void operator delete(void* p) { usb_ram_free(p); } +}; + +struct HCTD { // HostController Transfer Descriptor + __IO uint32_t Control; // +0 Transfer descriptor control + __IO uint8_t* CurrBufPtr; // +4 Physical address of current buffer pointer + HCTD* Next; // +8 Physical pointer to next Transfer Descriptor + uint8_t* BufEnd; // +12 Physical address of end of buffer + uint8_t* buf_top; // +16 Buffer start address + uint16_t buf_size; // +20 buffer size size + uint8_t _dummy[10]; // +22 dummy + USBEndpoint* ep; // +32 endpoint object + // +36 + HCTD(USBEndpoint* obj); + void* operator new(size_t size) { return usb_ram_malloc(size, 16); } + void operator delete(void* p) { usb_ram_free(p); } + + void transfer(TBUF* tbuf, int len) { + CurrBufPtr = tbuf->buf; + buf_top = tbuf->buf; + buf_size = len; + BufEnd = const_cast<uint8_t*>(tbuf->buf)+len-1; + } + int getLengthTransferred() { + if (CurrBufPtr) { + return CurrBufPtr - buf_top; + } + return buf_size; + } + int status() { + if (CurrBufPtr) { + return CurrBufPtr - buf_top; + } + return buf_size; + } + + uint8_t ConditionCode() { + return Control>>28; + } +}; + +struct HCITD { // HostController Isochronous Transfer Descriptor + __IO uint32_t Control; // +0 Transfer descriptor control + uint8_t* BufferPage0; // +4 Buffer Page 0 + HCITD* Next; // +8 Physical pointer to next Isochronous Transfer Descriptor + uint8_t* BufferEnd; // +12 buffer End + __IO uint16_t OffsetPSW[8]; // +16 Offset/PSW + USBEndpoint* ep; // +32 endpoint object + __IO uint8_t buf[0]; // +36 buffer + // +36 + HCITD(USBEndpoint* obj, uint16_t FrameNumber, int FrameCount, uint16_t PacketSize); + void* operator new(size_t size, int buf_size) { return usb_ram_malloc(size+buf_size, 32); } + void operator delete(void* p) { usb_ram_free(p); } + + uint16_t StartingFrame() { + return Control & 0xffff; + } + + uint8_t FrameCount() { + return ((Control>>24)&7)+1; + } + + uint8_t ConditionCode() { + return Control>>28; + } +}; + +struct HCED { // HostController EndPoint Descriptor + __IO uint32_t Control; // +0 Endpoint descriptor control + HCTD* TailTd; // +4 Physical address of tail in Transfer descriptor list + __IO HCTD* HeadTd; // +8 Physcial address of head in Transfer descriptor list + HCED* Next; // +12 Physical address of next Endpoint descriptor + // +16 + HCED(USBEndpoint* ep); + void* operator new(size_t size) { return usb_ram_malloc(size, 16); } + void operator delete(void* p) { usb_ram_free(p); } + + uint8_t FunctionAddress() { + return Control & 0x7f; + } + + uint8_t EndpointNumber() { + return (Control>>7) & 0x7f; + } + + int Speed() { + return (Control>>13)&1; + } + + void setFunctionAddress(int addr) { + Control &= ~0x7f; + Control |= addr; + } + + void setMaxPacketSize(uint16_t size) { + Control &= ~0xffff0000; + Control |= size<<16; + } + + void setToggleDATA1() { + uint32_t c = reinterpret_cast<uint32_t>(HeadTd); + c |= 0x02; + HeadTd = reinterpret_cast<HCTD*>(c); + } + + int Skip() { + return (Control>>14) & 1; + } + + void setSkip() { + Control |= (1<<14); + } + + void setFormat() { + Control |= (1<<15); + } + + bool enqueue(HCTD* td); + void init_queue(HCTD* td); +}; + +struct HCCA { // Host Controller Communication Area + HCED* InterruptTable[32]; // +0 Interrupt Table + __IO uint16_t FrameNumber;// +128 Frame Number + __IO uint16_t Pad1; // +130 + __IO HCTD* DoneHead; // +132 Done Head + uint8_t Reserved[116]; // +136 Reserved for future use + uint8_t Unknown[4]; // +252 Unused + // +256 + void* operator new(size_t size) { return usb_ram_malloc(size, 256); } + void operator delete(void* p) { usb_ram_free(p); } + void enqueue(HCED* ed); +}; + +class USBHALHost { +public: + uint8_t LastStatus; + uint8_t prev_LastStatus; + static void enable(ENDPOINT_TYPE type); + +protected: + USBHALHost(); + void init(); + void init_hw_ohci(HCCA* pHcca); + void ResetRootHub(); + virtual bool addDevice(USBDeviceConnected* parent, int port, bool lowSpeed) = 0; + //void setAddr(int addr, bool lowSpeed = false); + //void setEndpoint(); + //void token_transfer_init(); + void token_init(USBEndpoint* ep); + int token_setup(USBEndpoint* ep, SETUP_PACKET* setup, uint16_t wLength = 0); + int token_in(USBEndpoint* ep, uint8_t* data = NULL, int size = 0, int retryLimit = 0); + int token_out(USBEndpoint* ep, const uint8_t* data = NULL, int size = 0, int retryLimit = 0); + void token_inNB(USBEndpoint* ep, uint8_t* data, int size); + USB_TYPE token_inNB_result(USBEndpoint* ep); + //void token_ready(); + // report + uint32_t m_report_irq; + uint32_t m_report_RHSC; + uint32_t m_report_FNO; + uint32_t m_report_WDH; + uint32_t m_report_sp; + +private: + static void _usbisr(void); + void UsbIrqhandler(); + HCCA* m_pHcca; + //__IO bool attach_done; + //__IO bool token_done; + bool wait_attach(); + bool root_lowSpeed; + static USBHALHost * instHost; +}; +
diff -r 000000000000 -r 148fca6fd246 USBHost/USBHost.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHost/USBHost.cpp Fri Apr 25 05:18:55 2014 +0000 @@ -0,0 +1,317 @@ +/* mbed USBHost Library + * Copyright (c) 2006-2013 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "USBHost.h" +#define USB_DEBUG +#include "BaseUsbHostDebug.h" +#define TEST +#include "BaseUsbHostTest.h" + +USBHost* USBHost::inst = NULL; + +USBHost* USBHost::getHostInst() { + if (inst == NULL) { + inst = new USBHost(); + inst->init(); + } + return inst; +} + +void USBHost::poll() +{ + if (inst) { + inst->task(); + } +} + +USBHost::USBHost() { +} + +/* virtual */ bool USBHost::addDevice(USBDeviceConnected* parent, int port, bool lowSpeed) { + USBDeviceConnected* dev = new USBDeviceConnected; + USBEndpoint* ep = new USBEndpoint(dev); + dev->init(0, port, lowSpeed); + dev->setAddress(0); + dev->setEpCtl(ep); + uint8_t desc[18]; + wait_ms(100); + + int rc = controlRead(dev, 0x80, GET_DESCRIPTOR, 1<<8, 0, desc, 8); + USB_TEST_ASSERT(rc == USB_TYPE_OK); + if (rc != USB_TYPE_OK) { + USB_ERR("ADD DEVICE FAILD"); + } + USB_DBG_HEX(desc, 8); + DeviceDescriptor* dev_desc = reinterpret_cast<DeviceDescriptor*>(desc); + ep->setSize(dev_desc->bMaxPacketSize); + + int new_addr = USBDeviceConnected::getNewAddress(); + rc = controlWrite(dev, 0x00, SET_ADDRESS, new_addr, 0, NULL, 0); + USB_TEST_ASSERT(rc == USB_TYPE_OK); + dev->setAddress(new_addr); + wait_ms(100); + + rc = controlRead(dev, 0x80, GET_DESCRIPTOR, 1<<8, 0, desc, sizeof(desc)); + USB_TEST_ASSERT(rc == USB_TYPE_OK); + USB_DBG_HEX(desc, sizeof(desc)); + + dev->setVid(dev_desc->idVendor); + dev->setPid(dev_desc->idProduct); + dev->setClass(dev_desc->bDeviceClass); + USB_INFO("parent:%p port:%d speed:%s VID:%04x PID:%04x class:%02x addr:%d", + parent, port, (lowSpeed ? "low " : "full"), dev->getVid(), dev->getPid(), dev->getClass(), + dev->getAddress()); + + DeviceLists.push_back(dev); + + if (dev->getClass() == HUB_CLASS) { + const int config = 1; + int rc = controlWrite(dev, 0x00, SET_CONFIGURATION, config, 0, NULL, 0); + USB_TEST_ASSERT(rc == USB_TYPE_OK); + wait_ms(100); + Hub(dev); + } + return true; +} + +// enumerate a device with the control USBEndpoint +USB_TYPE USBHost::enumerate(USBDeviceConnected * dev, IUSBEnumerator* pEnumerator) +{ + if (dev->getClass() == HUB_CLASS) { // skip hub class + return USB_TYPE_OK; + } + uint8_t desc[18]; + USB_TYPE rc = controlRead(dev, 0x80, GET_DESCRIPTOR, 1<<8, 0, desc, sizeof(desc)); + USB_TEST_ASSERT(rc == USB_TYPE_OK); + USB_DBG_HEX(desc, sizeof(desc)); + if (rc != USB_TYPE_OK) { + return rc; + } + DeviceDescriptor* dev_desc = reinterpret_cast<DeviceDescriptor*>(desc); + dev->setClass(dev_desc->bDeviceClass); + pEnumerator->setVidPid(dev->getVid(), dev->getPid()); + + rc = controlRead(dev, 0x80, GET_DESCRIPTOR, 2<<8, 0, desc, 4); + USB_TEST_ASSERT(rc == USB_TYPE_OK); + USB_DBG_HEX(desc, 4); + + int TotalLength = desc[2]|desc[3]<<8; + uint8_t* buf = new uint8_t[TotalLength]; + rc = controlRead(dev, 0x80, GET_DESCRIPTOR, 2<<8, 0, buf, TotalLength); + USB_TEST_ASSERT(rc == USB_TYPE_OK); + //USB_DBG_HEX(buf, TotalLength); + + // Parse the configuration descriptor + parseConfDescr(dev, buf, TotalLength, pEnumerator); + delete[] buf; + // only set configuration if not enumerated before + if (!dev->isEnumerated()) { + USB_DBG("Set configuration 1 on dev: %p", dev); + // sixth step: set configuration (only 1 supported) + int config = 1; + USB_TYPE res = controlWrite(dev, 0x00, SET_CONFIGURATION, config, 0, NULL, 0); + if (res != USB_TYPE_OK) { + USB_ERR("SET CONF FAILED"); + return res; + } + // Some devices may require this delay + wait_ms(100); + dev->setEnumerated(); + // Now the device is enumerated! + USB_DBG("dev %p is enumerated", dev); + } + return USB_TYPE_OK; +} + +// this method fills the USBDeviceConnected object: class,.... . It also add endpoints found in the descriptor. +void USBHost::parseConfDescr(USBDeviceConnected * dev, uint8_t * conf_descr, uint32_t len, IUSBEnumerator* pEnumerator) +{ + uint32_t index = 0; + uint32_t len_desc = 0; + uint8_t id = 0; + USBEndpoint * ep = NULL; + uint8_t intf_nb = 0; + bool parsing_intf = false; + uint8_t current_intf = 0; + EndpointDescriptor* ep_desc; + + while (index < len) { + len_desc = conf_descr[index]; + id = conf_descr[index+1]; + USB_DBG_HEX(conf_descr+index, len_desc); + switch (id) { + case CONFIGURATION_DESCRIPTOR: + USB_DBG("dev: %p has %d intf", dev, conf_descr[4]); + dev->setNbIntf(conf_descr[4]); + break; + case INTERFACE_DESCRIPTOR: + if(pEnumerator->parseInterface(conf_descr[index + 2], conf_descr[index + 5], conf_descr[index + 6], conf_descr[index + 7])) { + intf_nb++; + current_intf = conf_descr[index + 2]; + dev->addInterface(current_intf, conf_descr[index + 5], conf_descr[index + 6], conf_descr[index + 7]); + USB_DBG("ADD INTF %d on device %p: class: %d, subclass: %d, proto: %d", current_intf, dev, conf_descr[index + 5],conf_descr[index + 6],conf_descr[index + 7]); + parsing_intf = true; + } else { + parsing_intf = false; + } + break; + case ENDPOINT_DESCRIPTOR: + ep_desc = reinterpret_cast<EndpointDescriptor*>(conf_descr+index); + if (parsing_intf && (intf_nb <= MAX_INTF) ) { + ENDPOINT_TYPE type = (ENDPOINT_TYPE)(ep_desc->bmAttributes & 0x03); + ENDPOINT_DIRECTION dir = (ep_desc->bEndpointAddress & 0x80) ? IN : OUT; + if(pEnumerator->useEndpoint(current_intf, type, dir)) { + ep = new USBEndpoint(dev); + ep->init(type, dir, ep_desc->wMaxPacketSize, ep_desc->bEndpointAddress); + USB_DBG("ADD USBEndpoint %p, on interf %d on device %p", ep, current_intf, dev); + dev->addEndpoint(current_intf, ep); + } + } + break; + case HID_DESCRIPTOR: + //lenReportDescr = conf_descr[index + 7] | (conf_descr[index + 8] << 8); + break; + default: + break; + } + index += len_desc; + } +} + +USB_TYPE USBHost::controlRead(USBDeviceConnected* dev, uint8_t requestType, uint8_t request, uint32_t value, uint32_t index, uint8_t * buf, uint32_t len) { + USBEndpoint* ep = dev->getEpCtl(); + return controlRead(ep, requestType, request, value, index, buf, len); +} + +USB_TYPE USBHost::controlWrite(USBDeviceConnected* dev, uint8_t requestType, uint8_t request, uint32_t value, uint32_t index, uint8_t * buf, uint32_t len) { + USBEndpoint* ep = dev->getEpCtl(); + return controlWrite(ep, requestType, request, value, index, buf, len); +} + +USB_TYPE USBHost::controlRead(USBEndpoint* ep, 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, len); + int result = token_setup(ep, &setup, len); // setup stage + if (result < 0) { + return USB_TYPE_ERROR; + } + + result = token_in(ep, buf, len); // data stage + if (result < 0) { + return USB_TYPE_ERROR; + } + int read_len = result; + + ep->m_pED->setToggleDATA1(); + result = token_out(ep); // status stage + if (result < 0) { + return USB_TYPE_ERROR; + } + ep->setLengthTransferred(read_len); + return USB_TYPE_OK; +} + +USB_TYPE USBHost::controlWrite(USBEndpoint* ep, 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, len); + int result = token_setup(ep, &setup, len); // setup stage + if (result < 0) { + return USB_TYPE_ERROR; + } + int write_len = 0; + if (buf != NULL) { + result = token_out(ep, buf, len); // data stage + if (result < 0) { + return USB_TYPE_ERROR; + } + write_len = result; + } + ep->m_pED->setToggleDATA1(); + result = token_in(ep); // status stage + if (result < 0) { + return USB_TYPE_ERROR; + } + ep->setLengthTransferred(write_len); + return USB_TYPE_OK; +} + +USB_TYPE USBHost::bulkRead(USBDeviceConnected* dev, USBEndpoint* ep, uint8_t* buf, uint32_t len, bool blocking) { + if (!blocking) { + ep->setBuffer(buf, len); + ep_queue.push(ep); + token_inNB(ep, buf, len); + return USB_TYPE_PROCESSING; + } + int result = token_in(ep, buf, len); + if (result >= 0) { + ep->setLengthTransferred(result); + return USB_TYPE_OK; + } + return USB_TYPE_ERROR; +} + +USB_TYPE USBHost::bulkWrite(USBDeviceConnected * dev, USBEndpoint* ep, uint8_t * buf, uint32_t len, bool blocking) +{ + int result = token_out(ep, buf, len); + if (result >= 0) { + ep->setLengthTransferred(result); + return USB_TYPE_OK; + } + return USB_TYPE_ERROR; +} + +USB_TYPE USBHost::interruptRead(USBDeviceConnected * dev, USBEndpoint* ep, uint8_t* buf, uint32_t len, bool blocking) { + if (!blocking) { + ep->setBuffer(buf, len); + ep_queue.push(ep); + token_inNB(ep, buf, len); + return USB_TYPE_PROCESSING; + } + int result = token_in(ep, buf, len); + if (result >= 0) { + ep->setLengthTransferred(result); + return USB_TYPE_OK; + } + return USB_TYPE_ERROR; +} + +int USBHost::interruptReadNB(USBEndpoint* ep, uint8_t* data, int size) { + if (ep->getState() != USB_TYPE_PROCESSING) { + ep->setState(USB_TYPE_PROCESSING); + ep->setBuffer(data, size); + token_inNB(ep, data, size); + } + if (token_inNB_result(ep) != USB_TYPE_PROCESSING) { + return ep->getLengthTransferred(); + } + return -1; +} + +int USBHost::bulkReadNB(USBEndpoint*ep, uint8_t* data, int size) { + return interruptReadNB(ep, data, size); +} + +void USBHost::task() { + USBEndpoint* ep = ep_queue.pop(); + if (ep) { + if (token_inNB_result(ep) == USB_TYPE_OK) { + ep->call(); + } else { + ep_queue.push(ep); + } + } +} +
diff -r 000000000000 -r 148fca6fd246 USBHost/USBHost.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHost/USBHost.h Fri Apr 25 05:18:55 2014 +0000 @@ -0,0 +1,194 @@ +/* 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. + */ + +#pragma once +#include "mbed.h" +#include "USBHALHost.h" +#include "USBDeviceConnected.h" +#include "IUSBEnumerator.h" +#include "USBHostConf.h" +#include "dbg.h" +#include "myvector.h" + +// USB STANDARD REQUEST DEFINITIONS +#define USB_DESCRIPTOR_TYPE_STRING 3 +#define USB_DESCRIPTOR_TYPE_HUB 0x29 + +#pragma pack(push,1) +struct StringDescriptor {// offset + uint8_t bLength; // +0 + uint8_t bDescriptorType; // +1 + char bString[0]; // +2 +}; +#pragma pack(pop) + +/** +* USBHost class +* This class is a singleton. All drivers have a reference on the static USBHost instance +*/ +class USBHost : public USBHALHost { +public: + /** + * Static method to create or retrieve the single USBHost instance + */ + static USBHost* getHostInst(); + + /** + * Control read: setup stage, data stage and status stage + * + * @param dev the control read will be done for this device + * @param requestType request type + * @param request request + * @param value value + * @param index index + * @param buf pointer on a buffer where will be store the data received + * @param len length of the transfer + * + * @returns status of the control read + */ + USB_TYPE controlRead(USBDeviceConnected * dev, uint8_t requestType, uint8_t request, uint32_t value, uint32_t index, uint8_t * buf, uint32_t len); + + /** + * Control write: setup stage, data stage and status stage + * + * @param dev the control write will be done for this device + * @param requestType request type + * @param request request + * @param value value + * @param index index + * @param buf pointer on a buffer which will be written + * @param len length of the transfer + * + * @returns status of the control write + */ + USB_TYPE controlWrite(USBDeviceConnected * dev, uint8_t requestType, uint8_t request, uint32_t value, uint32_t index, uint8_t * buf, uint32_t len); + + /** + * Bulk read + * + * @param dev the bulk transfer will be done for this device + * @param ep USBEndpoint which will be used to read a packet + * @param buf pointer on a buffer where will be store the data received + * @param len length of the transfer + * @param blocking if true, the read is blocking (wait for completion) + * + * @returns status of the bulk read + */ + USB_TYPE bulkRead(USBDeviceConnected * dev, USBEndpoint * ep, uint8_t * buf, uint32_t len, bool blocking = true); + + /** + * Bulk write + * + * @param dev the bulk transfer will be done for this device + * @param ep USBEndpoint which will be used to write a packet + * @param buf pointer on a buffer which will be written + * @param len length of the transfer + * @param blocking if true, the write is blocking (wait for completion) + * + * @returns status of the bulk write + */ + USB_TYPE bulkWrite(USBDeviceConnected * dev, USBEndpoint * ep, uint8_t * buf, uint32_t len, bool blocking = true); + + /** + * Interrupt read + * + * @param dev the 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); + + /** + * Enumerate a device. + * + * @param dev device which will be enumerated + * + * @returns status of the enumeration + */ + USB_TYPE enumerate(USBDeviceConnected * dev, IUSBEnumerator* pEnumerator); + + /** + * Get a device + * + * @param index index of the device which will be returned + * + * @returns pointer on the "index" device + */ + USBDeviceConnected * getDevice(uint8_t index) { + return index < DeviceLists.size() ? DeviceLists[index] : NULL; + } + + /** + * register a driver into the host associated with a callback function called when the device is disconnected + * + * @param dev device + * @param intf interface number + * @param tptr pointer to the object to call the member function on + * @param mptr pointer to the member function to be called + */ + template<typename T> + void registerDriver(USBDeviceConnected * dev, uint8_t intf, T* tptr, void (T::*mptr)(void)) { + } + + // LPC4088-USBHost extensions + USB_TYPE controlRead(USBEndpoint* ep, uint8_t requestType, uint8_t request, uint32_t value, uint32_t index, uint8_t* buf, uint32_t len); + USB_TYPE controlWrite(USBEndpoint* ep, uint8_t requestType, uint8_t request, uint32_t value, uint32_t index, uint8_t* buf, uint32_t len); + int interruptReadNB(USBEndpoint* ep, uint8_t* data, int size); + int bulkReadNB(USBEndpoint*ep, uint8_t* data, int size); + /** + * + */ + static void poll(); + +private: + USBHost(); + static USBHost* inst; + virtual bool addDevice(USBDeviceConnected* parent, int port, bool lowSpeed); + void root_enumeration(USBDeviceConnected* dev); + void parseConfDescr(USBDeviceConnected* dev, uint8_t* conf_descr, uint32_t len, IUSBEnumerator* pEnumerator); + myvector<USBDeviceConnected*>DeviceLists; + + void task(); + EndpointQueue ep_queue; + + // USB HUB + bool Hub(USBDeviceConnected* dev); + int SetPortPower(USBDeviceConnected* dev, int port); + int ClearPortPower(USBDeviceConnected* dev, int port); + int PortReset(USBDeviceConnected* dev, int port); + int SetPortFeature(USBDeviceConnected* dev, int feature, int index); + int ClearPortFeature(USBDeviceConnected* dev, int feature, int index); + int SetPortReset(USBDeviceConnected* dev, int port); + int GetPortStatus(USBDeviceConnected* dev, int port, uint32_t* status); +}; +
diff -r 000000000000 -r 148fca6fd246 USBHost/USBHostConf.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHost/USBHostConf.h Fri Apr 25 05:18:55 2014 +0000 @@ -0,0 +1,71 @@ +/* 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 + +/* +* usb_thread stack size +*/ +#define USB_THREAD_STACK (256*4 + MAX_HUB_NB*256*4) + +#endif
diff -r 000000000000 -r 148fca6fd246 USBHost/USBHostHub.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHost/USBHostHub.cpp Fri Apr 25 05:18:55 2014 +0000 @@ -0,0 +1,112 @@ +#include "USBHost.h" + +#define PORT_CONNECTION 0 +#define PORT_ENABLE 1 +#define PORT_SUSPEND 2 +#define PORT_OVER_CURRENT 3 +#define PORT_RESET 4 +#define PORT_POWER 8 +#define PORT_LOW_SPEED 9 + +#define C_PORT_CONNECTION 16 +#define C_PORT_ENABLE 17 +#define C_PORT_SUSPEND 18 +#define C_PORT_OVER_CURRENT 19 +#define C_PORT_RESET 20 + +bool USBHost::Hub(USBDeviceConnected* dev) { + USB_INFO("New HUB: VID:%04x PID:%04x [dev: %p]", dev->getVid(), dev->getPid(), dev); + HubDescriptor hubdesc; + // get HUB descriptor + int rc = controlRead(dev, + USB_DEVICE_TO_HOST | USB_REQUEST_TYPE_CLASS, + GET_DESCRIPTOR, + 0x29 << 8, 0, reinterpret_cast<uint8_t*>(&hubdesc), + sizeof(HubDescriptor)); + USB_TEST_ASSERT(rc == USB_TYPE_OK); + if (rc != USB_TYPE_OK) { + return false; + } + USB_DBG_HEX((uint8_t*)&hubdesc, sizeof(hubdesc)); + + uint32_t status; + rc = controlRead( dev, + 0xa0, 0, 0, 0, reinterpret_cast<uint8_t*>(&status), 4); + USB_TEST_ASSERT(rc == USB_TYPE_OK); + if (rc != USB_TYPE_OK) { + return false; + } + USB_DBG("HUB STATUS: %08X\n", status); + + for(int i = 1; i <= hubdesc.bNbrPorts; i++) { + SetPortPower(dev, i); // power on + wait_ms(hubdesc.bPwrOn2PwrGood*2); + uint32_t status; + GetPortStatus(dev, i, &status); + USB_DBG("port: %d status: %08X\n", i, status); + if (status & 0x010000) { // Connect Status Change, has changed + USB_TEST_ASSERT(status & 0x000001); + ClearPortFeature(dev, C_PORT_CONNECTION, i); + int lowSpeed = 0; + if (status & 0x0200) { + lowSpeed = 1; + } + PortReset(dev, i); + if (!addDevice(dev, i, lowSpeed)) { + ClearPortPower(dev, i); // power off + } + } else { + ClearPortPower(dev, i); // power off + } + } + return false; +} + + +int USBHost::SetPortPower(USBDeviceConnected* dev, int port) +{ + return SetPortFeature(dev, PORT_POWER, port); +} + +int USBHost::ClearPortPower(USBDeviceConnected* dev, int port) +{ + return ClearPortFeature(dev, PORT_POWER, port); +} + +int USBHost::SetPortFeature(USBDeviceConnected* dev, int feature, int index) +{ + return controlWrite(dev, 0x23, SET_FEATURE,feature,index,0,0); +} + +int USBHost::ClearPortFeature(USBDeviceConnected* dev, int feature, int index) +{ + return controlWrite(dev, 0x23, CLEAR_FEATURE,feature,index,0,0); +} + +int USBHost::SetPortReset(USBDeviceConnected* dev, int port) +{ + return SetPortFeature(dev, PORT_RESET, port); +} + +int USBHost::GetPortStatus(USBDeviceConnected* dev, int port, uint32_t* status) +{ + return controlRead(dev, 0xa3, GET_STATUS, 0, port, (uint8_t*)status, 4); +} + +int USBHost::PortReset(USBDeviceConnected* dev, int port) +{ + USB_DBG("%p port=%d\n", this, port); + USB_TEST_ASSERT(port >= 1); + SetPortReset(dev, port); + // wait reset + for(int i = 0; i < 100; i++) { + uint32_t status; + GetPortStatus(dev, port, &status); + USB_DBG("RESET port: %d status: %08X\n", port, status); + if (status & 0x100000) { // Reset change , Reset complete + return USB_TYPE_OK; + } + wait_ms(5); + } + return USB_TYPE_ERROR; +}
diff -r 000000000000 -r 148fca6fd246 USBHost/USBHostTypes.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHost/USBHostTypes.h Fri Apr 25 05:18:55 2014 +0000 @@ -0,0 +1,167 @@ +/* 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 GET_STATUS 0x00 +#define SET_FEATURE 0x03 +#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 + +// PID +#define DATA0 0x03 +#define DATA1 0x0b +#define ACK 0x02 +#define STALL 0x0e +#define NAK 0x0a + +#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
diff -r 000000000000 -r 148fca6fd246 USBHost/dbg.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHost/dbg.h Fri Apr 25 05:18:55 2014 +0000 @@ -0,0 +1,93 @@ +/* mbed USBHost Library + * Copyright (c) 2006-2013 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef USB_DEBUG_H +#define USB_DEBUG_H + +//Debug is disabled by default +#ifndef DEBUG +#define DEBUG 3 /*INFO,ERR,WARN*/ +#endif +#ifndef DEBUG2 +#define DEBUG2 0 +#endif +#define DEBUG_TRANSFER 0 +#define DEBUG_EP_STATE 0 +#define DEBUG_EVENT 0 + +#if (DEBUG > 3) +#define USB_DBG(...) do{fprintf(stderr,"[%s@%d] ",__PRETTY_FUNCTION__,__LINE__);fprintf(stderr,__VA_ARGS__);fprintf(stderr,"\r\n");} while(0); +//#define USB_DBG(x, ...) std::printf("[USB_DBG: %s:%d]" x "\r\n", __FILE__, __LINE__, ##__VA_ARGS__); +#define USB_DBG_HEX(A,B) debug_hex(A,B) +extern void debug_hex(uint8_t* buf, int size); +#define USB_DBG_ERRSTAT() report.print_errstat(); +#else +#define USB_DBG(x, ...) +#define USB_DBG_HEX(A,B) while(0) +#define USB_DBG_ERRSTAT() while(0) +#endif + +#if (DEBUG2 > 3) +#define USB_DBG2(...) do{fprintf(stderr,"[%s@%d] ",__PRETTY_FUNCTION__,__LINE__);fprintf(stderr,__VA_ARGS__);fprintf(stderr,"\r\n");} while(0); +#else +#define USB_DBG2(...) while(0); +#endif + +#if (DEBUG > 2) +#define USB_INFO(...) do{fprintf(stderr,__VA_ARGS__);fprintf(stderr,"\r\n");}while(0); +//#define USB_INFO(x, ...) std::printf("[USB_INFO: %s:%d]" x "\r\n", __FILE__, __LINE__, ##__VA_ARGS__); +#else +#define USB_INFO(x, ...) +#endif + +#if (DEBUG > 1) +#define USB_WARN(x, ...) std::printf("[USB_WARNING: %s:%d]" x "\r\n", __FILE__, __LINE__, ##__VA_ARGS__); +#else +#define USB_WARN(x, ...) +#endif + +#if (DEBUG > 0) +#define USB_ERR(x, ...) std::printf("[USB_ERR: %s:%d]" x "\r\n", __FILE__, __LINE__, ##__VA_ARGS__); +#else +#define USB_ERR(x, ...) +#endif + +#if (DEBUG_TRANSFER) +#define USB_DBG_TRANSFER(x, ...) std::printf("[USB_TRANSFER: %s:%d]" x "\r\n", __FILE__, __LINE__, ##__VA_ARGS__); +#else +#define USB_DBG_TRANSFER(x, ...) +#endif + +#if (DEBUG_EVENT) +#define USB_DBG_EVENT(x, ...) std::printf("[USB_EVENT: %s:%d]" x "\r\n", __FILE__, __LINE__, ##__VA_ARGS__); +#else +#define USB_DBG_EVENT(x, ...) +#endif + +template <bool>struct CtAssert; +template <>struct CtAssert<true> {}; +#define CTASSERT(A) CtAssert<A>(); + +#ifdef _USB_TEST +#define USB_TEST_ASSERT(A) while(!(A)){fprintf(stderr,"\n\n%s@%d %s ASSERT!\n\n",__PRETTY_FUNCTION__,__LINE__,#A);exit(1);}; +#define USB_TEST_ASSERT_FALSE(A) USB_TEST_ASSERT(!(A)) +#else +#define USB_TEST_ASSERT(A) while(0) +#define USB_TEST_ASSERT_FALSE(A) while(0) +#endif + +#endif +
diff -r 000000000000 -r 148fca6fd246 USBHost/mymap.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHost/mymap.h Fri Apr 25 05:18:55 2014 +0000 @@ -0,0 +1,65 @@ +#pragma once + +template<class K,class T> +class mymap { + struct mypair { + K first; + T second; + }; +public: + mymap() { + m_size = 0; + } + T& operator[](const K& key) { + int it; + if (count(key) == 0) { + it = insert(key, 0); + } else { + it = find(key); + } + return m_buf[it].second; + } + bool empty() { return m_size == 0 ? true : false; } + int size() { return m_size; } + void clear() { m_size = 0; } + int count(K key) { + for(int i = 0; i < m_size; i++) { + if (m_buf[i].first == key) { + return 1; + } + } + return 0; + } + +private: + int find(K key) { + for(int i = 0; i < m_size; i++) { + if (m_buf[i].first == key) { + return i; + } + } + return -1; + } + int insert(K key, T value) { + int it = find(key); + if (it != -1) { + m_buf[it].second = value; + return it; + } + mypair* new_buf = new mypair[m_size+1]; + if (m_size > 0) { + for(int i = 0; i < m_size; i++) { + new_buf[i] = m_buf[i]; + } + delete[] m_buf; + } + m_buf = new_buf; + it = m_size++; + m_buf[it].first = key; + m_buf[it].second = value; + return it; + } + + int m_size; + mypair *m_buf; +};
diff -r 000000000000 -r 148fca6fd246 USBHost/myvector.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHost/myvector.h Fri Apr 25 05:18:55 2014 +0000 @@ -0,0 +1,34 @@ +#pragma once + +template<class T> +class myvector { +public: + myvector() { + m_size = 0; + m_buf = NULL; + } + ~myvector() { + if (m_buf) { + delete[] m_buf; + } + } + void push_back(T v) { + T* new_buf = new T[m_size+1]; + if (m_size > 0) { + for(int i = 0; i < m_size; i++) { + new_buf[i] = m_buf[i]; + } + delete[] m_buf; + } + m_buf = new_buf; + m_buf[m_size++] = v; + } + T& operator[](const int index) { + return m_buf[index]; + } + int size() { return m_size; } + +private: + int m_size; + T *m_buf; +};
diff -r 000000000000 -r 148fca6fd246 USBHostHID/USBHostKeyboard.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHostHID/USBHostKeyboard.cpp Fri Apr 25 05:18:55 2014 +0000 @@ -0,0 +1,184 @@ +/* mbed USBHost Library + * Copyright (c) 2006-2013 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "USBHostKeyboard.h" + +#if USBHOST_KEYBOARD + +static uint8_t keymap[4][0x39] = { + { 0, 0, 0, 0, 'a', 'b' /*0x05*/, + 'c', 'd', 'e', 'f', 'g' /*0x0a*/, + 'h', 'i', 'j', 'k', 'l'/*0x0f*/, + 'm', 'n', 'o', 'p', 'q'/*0x14*/, + 'r', 's', 't', 'u', 'v'/*0x19*/, + 'w', 'x', 'y', 'z', '1'/*0x1E*/, + '2', '3', '4', '5', '6'/*0x23*/, + '7', '8', '9', '0', 0x0A /*enter*/, /*0x28*/ + 0x1B /*escape*/, 0x08 /*backspace*/, 0x09/*tab*/, 0x20/*space*/, '-', /*0x2d*/ + '=', '[', ']', '\\', '#', /*0x32*/ + ';', '\'', 0, ',', '.', /*0x37*/ + '/'}, + + /* CTRL MODIFIER */ + { 0, 0, 0, 0, 0, 0 /*0x05*/, + 0, 0, 0, 0, 0 /*0x0a*/, + 0, 0, 0, 0, 0/*0x0f*/, + 0, 0, 0, 0, 0/*0x14*/, + 0, 0, 0, 0, 0/*0x19*/, + 0, 0, 0, 0, 0/*0x1E*/, + 0, 0, 0, 0, 0/*0x23*/, + 0, 0, 0, 0, 0 /*enter*/, /*0x28*/ + 0, 0, 0, 0, 0, /*0x2d*/ + 0, 0, 0, 0, 0, /*0x32*/ + 0, 0, 0, 0, 0, /*0x37*/ + 0}, + + /* SHIFT MODIFIER */ + { 0, 0, 0, 0, 'A', 'B' /*0x05*/, + 'C', 'D', 'E', 'F', 'G' /*0x0a*/, + 'H', 'I', 'J', 'K', 'L'/*0x0f*/, + 'M', 'N', 'O', 'P', 'Q'/*0x14*/, + 'R', 'S', 'T', 'U', 'V'/*0x19*/, + 'W', 'X', 'Y', 'Z', '!'/*0x1E*/, + '@', '#', '$', '%', '^'/*0x23*/, + '&', '*', '(', ')', 0, /*0x28*/ + 0, 0, 0, 0, 0, /*0x2d*/ + '+', '{', '}', '|', '~', /*0x32*/ + ':', '"', 0, '<', '>', /*0x37*/ + '?'}, + + /* ALT MODIFIER */ + { 0, 0, 0, 0, 0, 0 /*0x05*/, + 0, 0, 0, 0, 0 /*0x0a*/, + 0, 0, 0, 0, 0/*0x0f*/, + 0, 0, 0, 0, 0/*0x14*/, + 0, 0, 0, 0, 0/*0x19*/, + 0, 0, 0, 0, 0/*0x1E*/, + 0, 0, 0, 0, 0/*0x23*/, + 0, 0, 0, 0, 0 /*enter*/, /*0x28*/ + 0, 0, 0, 0, 0, /*0x2d*/ + 0, 0, 0, 0, 0, /*0x32*/ + 0, 0, 0, 0, 0, /*0x37*/ + 0} + +}; + + +USBHostKeyboard::USBHostKeyboard() { + host = USBHost::getHostInst(); + init(); +} + + +void USBHostKeyboard::init() { + dev = NULL; + int_in = NULL; + report_id = 0; + onKey = NULL; + onKeyCode = NULL; + dev_connected = false; + keyboard_intf = -1; + keyboard_device_found = false; +} + +bool USBHostKeyboard::connected() { + return dev_connected; +} + + +bool USBHostKeyboard::connect() { + + if (dev_connected) { + return true; + } + + for (uint8_t i = 0; i < MAX_DEVICE_CONNECTED; i++) { + if ((dev = host->getDevice(i)) != NULL) { + + if (host->enumerate(dev, this)) + break; + + if (keyboard_device_found) { + int_in = dev->getEndpoint(keyboard_intf, INTERRUPT_ENDPOINT, IN); + + if (!int_in) + break; + + USB_INFO("New Keyboard device: VID:%04x PID:%04x [dev: %p - intf: %d]", dev->getVid(), dev->getPid(), dev, keyboard_intf); + dev->setName("Keyboard", keyboard_intf); + host->registerDriver(dev, keyboard_intf, this, &USBHostKeyboard::init); + + int_in->attach(this, &USBHostKeyboard::rxHandler); + host->interruptRead(dev, int_in, report, int_in->getSize(), false); + + dev_connected = true; + return true; + } + } + } + init(); + return false; +} + +void USBHostKeyboard::rxHandler() { + int len = int_in->getLengthTransferred(); + int index = (len == 9) ? 1 : 0; + int len_listen = int_in->getSize(); + uint8_t key = 0; + if (len == 8 || len == 9) { + uint8_t modifier = (report[index] == 4) ? 3 : report[index]; + len_listen = len; + key = keymap[modifier][report[index + 2]]; + if (key && onKey) { + (*onKey)(key); + } + if ((report[index + 2] || modifier) && onKeyCode) { + (*onKeyCode)(report[index + 2], modifier); + } + } + if (dev && int_in) + host->interruptRead(dev, int_in, report, len_listen, false); +} + +/*virtual*/ void USBHostKeyboard::setVidPid(uint16_t vid, uint16_t pid) +{ + // we don't check VID/PID for keyboard driver +} + +/*virtual*/ bool USBHostKeyboard::parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol) //Must return true if the interface should be parsed +{ + if ((keyboard_intf == -1) && + (intf_class == HID_CLASS) && + (intf_subclass == 0x01) && + (intf_protocol == 0x01)) { + keyboard_intf = intf_nb; + return true; + } + return false; +} + +/*virtual*/ bool USBHostKeyboard::useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir) //Must return true if the endpoint will be used +{ + if (intf_nb == keyboard_intf) { + if (type == INTERRUPT_ENDPOINT && dir == IN) { + keyboard_device_found = true; + return true; + } + } + return false; +} + +#endif
diff -r 000000000000 -r 148fca6fd246 USBHostHID/USBHostKeyboard.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHostHID/USBHostKeyboard.h Fri Apr 25 05:18:55 2014 +0000 @@ -0,0 +1,102 @@ +/* mbed USBHost Library + * Copyright (c) 2006-2013 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef USBHOSTKEYBOARD_H +#define USBHOSTKEYBOARD_H + +#include "USBHostConf.h" + +#if USBHOST_KEYBOARD + +#include "USBHost.h" + +/** + * A class to communicate a USB keyboard + */ +class USBHostKeyboard : public IUSBEnumerator { +public: + + /** + * Constructor + */ + USBHostKeyboard(); + + /** + * Try to connect a keyboard device + * + * @return true if connection was successful + */ + bool connect(); + + /** + * Check if a keyboard is connected + * + * @returns true if a keyboard is connected + */ + bool connected(); + + /** + * Attach a callback called when a keyboard event is received + * + * @param ptr function pointer + */ + inline void attach(void (*ptr)(uint8_t key)) { + if (ptr != NULL) { + onKey = ptr; + } + } + + /** + * Attach a callback called when a keyboard event is received + * + * @param ptr function pointer + */ + inline void attach(void (*ptr)(uint8_t keyCode, uint8_t modifier)) { + if (ptr != NULL) { + onKeyCode = ptr; + } + } + +protected: + //From IUSBEnumerator + virtual void setVidPid(uint16_t vid, uint16_t pid); + virtual bool parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol); //Must return true if the interface should be parsed + virtual bool useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir); //Must return true if the endpoint will be used + +private: + USBHost * host; + USBDeviceConnected * dev; + USBEndpoint * int_in; + uint8_t report[9]; + int keyboard_intf; + bool keyboard_device_found; + + bool dev_connected; + + void rxHandler(); + + void (*onKey)(uint8_t key); + void (*onKeyCode)(uint8_t key, uint8_t modifier); + + int report_id; + + void init(); + +}; + +#endif + +#endif
diff -r 000000000000 -r 148fca6fd246 USBHostHID/USBHostMouse.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHostHID/USBHostMouse.cpp Fri Apr 25 05:18:55 2014 +0000 @@ -0,0 +1,144 @@ +/* mbed USBHost Library + * Copyright (c) 2006-2013 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "USBHostMouse.h" + +#if USBHOST_MOUSE + +USBHostMouse::USBHostMouse() { + host = USBHost::getHostInst(); + init(); +} + +void USBHostMouse::init() { + dev = NULL; + int_in = NULL; + onUpdate = NULL; + onButtonUpdate = NULL; + onXUpdate = NULL; + onYUpdate = NULL; + onZUpdate = NULL; + report_id = 0; + dev_connected = false; + mouse_device_found = false; + mouse_intf = -1; + + buttons = 0; + x = 0; + y = 0; + z = 0; +} + +bool USBHostMouse::connected() { + return dev_connected; +} + +bool USBHostMouse::connect() { + + if (dev_connected) { + return true; + } + + for (uint8_t i = 0; i < MAX_DEVICE_CONNECTED; i++) { + if ((dev = host->getDevice(i)) != NULL) { + + if(host->enumerate(dev, this)) + break; + + if (mouse_device_found) { + + int_in = dev->getEndpoint(mouse_intf, INTERRUPT_ENDPOINT, IN); + if (!int_in) + break; + + USB_INFO("New Mouse device: VID:%04x PID:%04x [dev: %p - intf: %d]", dev->getVid(), dev->getPid(), dev, mouse_intf); + dev->setName("Mouse", mouse_intf); + host->registerDriver(dev, mouse_intf, this, &USBHostMouse::init); + + int_in->attach(this, &USBHostMouse::rxHandler); + host->interruptRead(dev, int_in, report, int_in->getSize(), false); + + dev_connected = true; + return true; + } + } + } + init(); + return false; +} + +void USBHostMouse::rxHandler() { + int len_listen = int_in->getSize(); + + if (onUpdate) { + (*onUpdate)(report[0] & 0x07, report[1], report[2], report[3]); + } + + if (onButtonUpdate && (buttons != (report[0] & 0x07))) { + (*onButtonUpdate)(report[0] & 0x07); + } + + if (onXUpdate && (x != report[1])) { + (*onXUpdate)(report[1]); + } + + if (onYUpdate && (y != report[2])) { + (*onYUpdate)(report[2]); + } + + if (onZUpdate && (z != report[3])) { + (*onZUpdate)(report[3]); + } + + // update mouse state + buttons = report[0] & 0x07; + x = report[1]; + y = report[2]; + z = report[3]; + + if (dev) + host->interruptRead(dev, int_in, report, len_listen, false); +} + +/*virtual*/ void USBHostMouse::setVidPid(uint16_t vid, uint16_t pid) +{ + // we don't check VID/PID for mouse driver +} + +/*virtual*/ bool USBHostMouse::parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol) //Must return true if the interface should be parsed +{ + if ((mouse_intf == -1) && + (intf_class == HID_CLASS) && + (intf_subclass == 0x01) && + (intf_protocol == 0x02)) { + mouse_intf = intf_nb; + return true; + } + return false; +} + +/*virtual*/ bool USBHostMouse::useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir) //Must return true if the endpoint will be used +{ + if (intf_nb == mouse_intf) { + if (type == INTERRUPT_ENDPOINT && dir == IN) { + mouse_device_found = true; + return true; + } + } + return false; +} + +#endif
diff -r 000000000000 -r 148fca6fd246 USBHostHID/USBHostMouse.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHostHID/USBHostMouse.h Fri Apr 25 05:18:55 2014 +0000 @@ -0,0 +1,139 @@ +/* mbed USBHost Library + * Copyright (c) 2006-2013 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef USBHOSTMOUSE_H +#define USBHOSTMOUSE_H + +#include "USBHostConf.h" + +#if USBHOST_MOUSE + +#include "USBHost.h" + +/** + * A class to communicate a USB mouse + */ +class USBHostMouse : public IUSBEnumerator { +public: + + /** + * Constructor + */ + USBHostMouse(); + + /** + * Try to connect a mouse device + * + * @return true if connection was successful + */ + bool connect(); + + /** + * Check if a mouse is connected + * + * @returns true if a mouse is connected + */ + bool connected(); + + /** + * Attach a callback called when a mouse event is received + * + * @param ptr function pointer + */ + inline void attachEvent(void (*ptr)(uint8_t buttons, int8_t x, int8_t y, int8_t z)) { + if (ptr != NULL) { + onUpdate = ptr; + } + } + + /** + * Attach a callback called when the button state changes + * + * @param ptr function pointer + */ + inline void attachButtonEvent(void (*ptr)(uint8_t buttons)) { + if (ptr != NULL) { + onButtonUpdate = ptr; + } + } + + /** + * Attach a callback called when the X axis value changes + * + * @param ptr function pointer + */ + inline void attachXEvent(void (*ptr)(int8_t x)) { + if (ptr != NULL) { + onXUpdate = ptr; + } + } + + /** + * Attach a callback called when the Y axis value changes + * + * @param ptr function pointer + */ + inline void attachYEvent(void (*ptr)(int8_t y)) { + if (ptr != NULL) { + onYUpdate = ptr; + } + } + + /** + * Attach a callback called when the Z axis value changes (scrolling) + * + * @param ptr function pointer + */ + inline void attachZEvent(void (*ptr)(int8_t z)) { + if (ptr != NULL) { + onZUpdate = ptr; + } + } + +protected: + //From IUSBEnumerator + virtual void setVidPid(uint16_t vid, uint16_t pid); + virtual bool parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol); //Must return true if the interface should be parsed + virtual bool useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir); //Must return true if the endpoint will be used + +private: + USBHost * host; + USBDeviceConnected * dev; + USBEndpoint * int_in; + uint8_t report[4]; + + bool dev_connected; + bool mouse_device_found; + int mouse_intf; + + uint8_t buttons; + int8_t x; + int8_t y; + int8_t z; + + void rxHandler(); + void (*onUpdate)(uint8_t buttons, int8_t x, int8_t y, int8_t z); + void (*onButtonUpdate)(uint8_t buttons); + void (*onXUpdate)(int8_t x); + void (*onYUpdate)(int8_t y); + void (*onZUpdate)(int8_t z); + int report_id; + void init(); +}; + +#endif + +#endif
diff -r 000000000000 -r 148fca6fd246 USBHostMSD/USBHostMSD.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHostMSD/USBHostMSD.cpp Fri Apr 25 05:18:55 2014 +0000 @@ -0,0 +1,356 @@ +/* mbed USBHost Library + * Copyright (c) 2006-2013 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "USBHostMSD.h" + +#if USBHOST_MSD + +#include "dbg.h" + +#define CBW_SIGNATURE 0x43425355 +#define CSW_SIGNATURE 0x53425355 + +#define DEVICE_TO_HOST 0x80 +#define HOST_TO_DEVICE 0x00 + +#define GET_MAX_LUN (0xFE) +#define BO_MASS_STORAGE_RESET (0xFF) + +USBHostMSD::USBHostMSD(const char * rootdir) : FATFileSystem(rootdir) +{ + host = USBHost::getHostInst(); + init(); +} + +void USBHostMSD::init() { + dev_connected = false; + dev = NULL; + bulk_in = NULL; + bulk_out = NULL; + dev_connected = false; + blockSize = 0; + blockCount = 0; + msd_intf = -1; + msd_device_found = false; + disk_init = false; + dev_connected = false; + nb_ep = 0; +} + + +bool USBHostMSD::connected() +{ + return dev_connected; +} + +bool USBHostMSD::connect() +{ + + if (dev_connected) { + return true; + } + + for (uint8_t i = 0; i < MAX_DEVICE_CONNECTED; i++) { + if ((dev = host->getDevice(i)) != NULL) { + + USB_DBG("Trying to connect MSD device\r\n"); + + if(host->enumerate(dev, this)) + break; + + if (msd_device_found) { + bulk_in = dev->getEndpoint(msd_intf, BULK_ENDPOINT, IN); + bulk_out = dev->getEndpoint(msd_intf, BULK_ENDPOINT, OUT); + + if (!bulk_in || !bulk_out) + continue; + + USB_INFO("New MSD device: VID:%04x PID:%04x [dev: %p - intf: %d]", dev->getVid(), dev->getPid(), dev, msd_intf); + dev->setName("MSD", msd_intf); + host->registerDriver(dev, msd_intf, this, &USBHostMSD::init); + + dev_connected = true; + return true; + } + } //if() + } //for() + init(); + return false; +} + +/*virtual*/ void USBHostMSD::setVidPid(uint16_t vid, uint16_t pid) +{ + // we don't check VID/PID for MSD driver +} + +/*virtual*/ bool USBHostMSD::parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol) //Must return true if the interface should be parsed +{ + if ((msd_intf == -1) && + (intf_class == MSD_CLASS) && + (intf_subclass == 0x06) && + (intf_protocol == 0x50)) { + msd_intf = intf_nb; + return true; + } + return false; +} + +/*virtual*/ bool USBHostMSD::useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir) //Must return true if the endpoint will be used +{ + if (intf_nb == msd_intf) { + if (type == BULK_ENDPOINT) { + nb_ep++; + if (nb_ep == 2) + msd_device_found = true; + return true; + } + } + return false; +} + + +int USBHostMSD::testUnitReady() { + USB_DBG("Test unit ready"); + return SCSITransfer(NULL, 6, DEVICE_TO_HOST, 0, 0); +} + + +int USBHostMSD::readCapacity() { + USB_DBG("Read capacity"); + uint8_t cmd[10] = {0x25,0,0,0,0,0,0,0,0,0}; + uint8_t result[8]; + int status = SCSITransfer(cmd, 10, DEVICE_TO_HOST, result, 8); + if (status == 0) { + blockCount = (result[0] << 24) | (result[1] << 16) | (result[2] << 8) | result[3]; + blockSize = (result[4] << 24) | (result[5] << 16) | (result[6] << 8) | result[7]; + USB_INFO("MSD [dev: %p] - blockCount: %lld, blockSize: %d, Capacity: %lld\r\n", dev, blockCount, blockSize, blockCount*blockSize); + } + return status; +} + + +int USBHostMSD::SCSIRequestSense() { + USB_DBG("Request sense"); + uint8_t cmd[6] = {0x03,0,0,0,18,0}; + uint8_t result[18]; + int status = SCSITransfer(cmd, 6, DEVICE_TO_HOST, result, 18); + return status; +} + + +int USBHostMSD::inquiry(uint8_t lun, uint8_t page_code) { + USB_DBG("Inquiry"); + uint8_t evpd = (page_code == 0) ? 0 : 1; + uint8_t cmd[6] = {0x12, uint8_t((lun << 5) | evpd), page_code, 0, 36, 0}; + uint8_t result[36]; + int status = SCSITransfer(cmd, 6, DEVICE_TO_HOST, result, 36); + if (status == 0) { + char vid_pid[17]; + memcpy(vid_pid, &result[8], 8); + vid_pid[8] = 0; + USB_INFO("MSD [dev: %p] - Vendor ID: %s", dev, vid_pid); + + memcpy(vid_pid, &result[16], 16); + vid_pid[16] = 0; + USB_INFO("MSD [dev: %p] - Product ID: %s", dev, vid_pid); + + memcpy(vid_pid, &result[32], 4); + vid_pid[4] = 0; + USB_INFO("MSD [dev: %p] - Product rev: %s", dev, vid_pid); + } + return status; +} + +int USBHostMSD::checkResult(uint8_t res, USBEndpoint * ep) { + // if ep stalled: send clear feature + if (res == USB_TYPE_STALL_ERROR) { + res = host->controlWrite( dev, + USB_RECIPIENT_ENDPOINT | USB_HOST_TO_DEVICE | USB_REQUEST_TYPE_STANDARD, + CLEAR_FEATURE, + 0, ep->getAddress(), NULL, 0); + // set state to IDLE if clear feature successful + if (res == USB_TYPE_OK) { + ep->setState(USB_TYPE_IDLE); + } + } + + if (res != USB_TYPE_OK) + return -1; + + return 0; +} + + +int USBHostMSD::SCSITransfer(uint8_t * cmd, uint8_t cmd_len, int flags, uint8_t * data, uint32_t transfer_len) { + + int res = 0; + + cbw.Signature = CBW_SIGNATURE; + cbw.Tag = 0; + cbw.DataLength = transfer_len; + cbw.Flags = flags; + cbw.LUN = 0; + cbw.CBLength = cmd_len; + memset(cbw.CB,0,sizeof(cbw.CB)); + if (cmd) { + memcpy(cbw.CB,cmd,cmd_len); + } + + // send the cbw + USB_DBG("Send CBW"); + res = host->bulkWrite(dev, bulk_out,(uint8_t *)&cbw, 31); + if (checkResult(res, bulk_out)) + return -1; + + // data stage if needed + if (data) { + USB_DBG("data stage"); + if (flags == HOST_TO_DEVICE) { + + res = host->bulkWrite(dev, bulk_out, data, transfer_len); + if (checkResult(res, bulk_out)) + return -1; + + } else if (flags == DEVICE_TO_HOST) { + + res = host->bulkRead(dev, bulk_in, data, transfer_len); + if (checkResult(res, bulk_in)) + return -1; + } + } + + // status stage + csw.Signature = 0; + USB_DBG("Read CSW"); + res = host->bulkRead(dev, bulk_in,(uint8_t *)&csw, 13); + if (checkResult(res, bulk_in)) + return -1; + + if (csw.Signature != CSW_SIGNATURE) { + return -1; + } + + USB_DBG("recv csw: status: %d", csw.Status); + + // ModeSense? + if ((csw.Status == 1) && (cmd[0] != 0x03)) { + USB_DBG("request mode sense"); + return SCSIRequestSense(); + } + + // perform reset recovery + if ((csw.Status == 2) && (cmd[0] != 0x03)) { + + // send Bulk-Only Mass Storage Reset request + res = host->controlWrite( dev, + USB_RECIPIENT_INTERFACE | USB_HOST_TO_DEVICE | USB_REQUEST_TYPE_CLASS, + BO_MASS_STORAGE_RESET, + 0, msd_intf, NULL, 0); + + // unstall both endpoints + res = host->controlWrite( dev, + USB_RECIPIENT_ENDPOINT | USB_HOST_TO_DEVICE | USB_REQUEST_TYPE_STANDARD, + CLEAR_FEATURE, + 0, bulk_in->getAddress(), NULL, 0); + + res = host->controlWrite( dev, + USB_RECIPIENT_ENDPOINT | USB_HOST_TO_DEVICE | USB_REQUEST_TYPE_STANDARD, + CLEAR_FEATURE, + 0, bulk_out->getAddress(), NULL, 0); + + } + + return csw.Status; +} + + +int USBHostMSD::dataTransfer(uint8_t * buf, uint32_t block, uint8_t nbBlock, int direction) { + uint8_t cmd[10]; + memset(cmd,0,10); + cmd[0] = (direction == DEVICE_TO_HOST) ? 0x28 : 0x2A; + + cmd[2] = (block >> 24) & 0xff; + cmd[3] = (block >> 16) & 0xff; + cmd[4] = (block >> 8) & 0xff; + cmd[5] = block & 0xff; + + cmd[7] = (nbBlock >> 8) & 0xff; + cmd[8] = nbBlock & 0xff; + + return SCSITransfer(cmd, 10, direction, buf, blockSize*nbBlock); +} + +int USBHostMSD::getMaxLun() { + uint8_t buf[1], res; + res = host->controlRead( dev, USB_RECIPIENT_INTERFACE | USB_DEVICE_TO_HOST | USB_REQUEST_TYPE_CLASS, + 0xfe, 0, msd_intf, buf, 1); + USB_DBG("max lun: %d", buf[0]); + return res; +} + +int USBHostMSD::disk_initialize() { + USB_DBG("FILESYSTEM: init"); + /* U16 */int i, timeout = 10; + + getMaxLun(); + + for (i = 0; i < timeout; i++) { + wait_ms(100); //Thread::wait(100); + if (!testUnitReady()) + break; + } + + if (i == timeout) { + disk_init = false; + return -1; + } + + inquiry(0, 0); + disk_init = 1; + return readCapacity(); +} + +int USBHostMSD::disk_write(const uint8_t *buffer, uint64_t block_number) { + USB_DBG("FILESYSTEM: write block: %lld", block_number); + if (!disk_init) { + disk_initialize(); + } + if (!disk_init) + return -1; + return dataTransfer((uint8_t *)buffer, block_number, 1, HOST_TO_DEVICE); +} + +int USBHostMSD::disk_read(uint8_t * buffer, uint64_t block_number) { + USB_DBG("FILESYSTEM: read block %lld", block_number); + if (!disk_init) { + disk_initialize(); + } + if (!disk_init) + return -1; + return dataTransfer((uint8_t *)buffer, block_number, 1, DEVICE_TO_HOST); +} + +uint64_t USBHostMSD::disk_sectors() { + USB_DBG("FILESYSTEM: sectors"); + if (!disk_init) { + disk_initialize(); + } + if (!disk_init) + return 0; + return blockCount; +} + +#endif
diff -r 000000000000 -r 148fca6fd246 USBHostMSD/USBHostMSD.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHostMSD/USBHostMSD.h Fri Apr 25 05:18:55 2014 +0000 @@ -0,0 +1,119 @@ +/* mbed USBHost Library + * Copyright (c) 2006-2013 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef USBHOSTMSD_H +#define USBHOSTMSD_H + +#include "USBHostConf.h" + +#if USBHOST_MSD + +#include "USBHost.h" +#include "FATFileSystem.h" + +/** + * A class to communicate a USB flash disk + */ +class USBHostMSD : public IUSBEnumerator, public FATFileSystem { +public: + /** + * Constructor + * + * @param rootdir mount name + */ + USBHostMSD(const char * rootdir); + + /** + * Check if a MSD device is connected + * + * @return true if a MSD device is connected + */ + bool connected(); + + /** + * Try to connect to a MSD device + * + * @return true if connection was successful + */ + bool connect(); + +protected: + //From IUSBEnumerator + virtual void setVidPid(uint16_t vid, uint16_t pid); + virtual bool parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol); //Must return true if the interface should be parsed + virtual bool useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir); //Must return true if the endpoint will be used + + // From FATFileSystem + virtual int disk_initialize(); + virtual int disk_status() {return 0;}; + virtual int disk_read(uint8_t * buffer, uint64_t sector); + virtual int disk_write(const uint8_t * buffer, uint64_t sector); + virtual int disk_sync() {return 0;}; + virtual uint64_t disk_sectors(); + +private: + USBHost * host; + USBDeviceConnected * dev; + bool dev_connected; + USBEndpoint * bulk_in; + USBEndpoint * bulk_out; + uint8_t nb_ep; + + // Bulk-only CBW + typedef struct { + uint32_t Signature; + uint32_t Tag; + uint32_t DataLength; + uint8_t Flags; + uint8_t LUN; + uint8_t CBLength; + uint8_t CB[16]; + } PACKED CBW; + + // Bulk-only CSW + typedef struct { + uint32_t Signature; + uint32_t Tag; + uint32_t DataResidue; + uint8_t Status; + } PACKED CSW; + + CBW cbw; + CSW csw; + + int SCSITransfer(uint8_t * cmd, uint8_t cmd_len, int flags, uint8_t * data, uint32_t transfer_len); + int testUnitReady(); + int readCapacity(); + int inquiry(uint8_t lun, uint8_t page_code); + int SCSIRequestSense(); + int dataTransfer(uint8_t * buf, uint32_t block, uint8_t nbBlock, int direction); + int checkResult(uint8_t res, USBEndpoint * ep); + int getMaxLun(); + + int blockSize; + uint64_t blockCount; + + int msd_intf; + bool msd_device_found; + bool disk_init; + + void init(); + +}; + +#endif + +#endif
diff -r 000000000000 -r 148fca6fd246 mbed-rtos.lib --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mbed-rtos.lib Fri Apr 25 05:18:55 2014 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/mbed_official/code/mbed-rtos/#be2573f85b81