USB Host Driver with Socket Modem support. Works with revision 323 of mbed-src but broken with any later version.

Dependencies:   FATFileSystem

Fork of F401RE-USBHost by Norimasa Okamoto

Committer:
fritz291
Date:
Fri Jun 26 19:30:55 2015 +0000
Revision:
26:53970cabf56d
Parent:
18:61554f238584
Fixed small error in testAT function

Who changed what in which revision?

UserRevisionLine numberNew contents of line
va009039 18:61554f238584 1 /* mbed USBHost Library
va009039 18:61554f238584 2 * Copyright (c) 2006-2013 ARM Limited
va009039 18:61554f238584 3 *
va009039 18:61554f238584 4 * Licensed under the Apache License, Version 2.0 (the "License");
va009039 18:61554f238584 5 * you may not use this file except in compliance with the License.
va009039 18:61554f238584 6 * You may obtain a copy of the License at
va009039 18:61554f238584 7 *
va009039 18:61554f238584 8 * http://www.apache.org/licenses/LICENSE-2.0
va009039 18:61554f238584 9 *
va009039 18:61554f238584 10 * Unless required by applicable law or agreed to in writing, software
va009039 18:61554f238584 11 * distributed under the License is distributed on an "AS IS" BASIS,
va009039 18:61554f238584 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
va009039 18:61554f238584 13 * See the License for the specific language governing permissions and
va009039 18:61554f238584 14 * limitations under the License.
va009039 18:61554f238584 15 */
va009039 18:61554f238584 16
va009039 18:61554f238584 17 #if defined(TARGET_LPC4088)||defined(TARGET_LPC1768)
va009039 18:61554f238584 18 #include "USBHALHost.h"
va009039 18:61554f238584 19
va009039 18:61554f238584 20 #ifndef CTASSERT
va009039 18:61554f238584 21 template <bool>struct CtAssert;
va009039 18:61554f238584 22 template <>struct CtAssert<true> {};
va009039 18:61554f238584 23 #define CTASSERT(A) CtAssert<A>();
va009039 18:61554f238584 24 #endif
va009039 18:61554f238584 25
va009039 18:61554f238584 26 #ifdef _USB_DBG
va009039 18:61554f238584 27 #define USB_DBG(...) do{fprintf(stderr,"[%s@%d] ",__PRETTY_FUNCTION__,__LINE__);fprintf(stderr,__VA_ARGS__);fprintf(stderr,"\n");} while(0);
va009039 18:61554f238584 28 #define USB_DBG_HEX(A,B) debug_hex(A,B)
va009039 18:61554f238584 29 #define USB_DBG_ED(A) while(0)
va009039 18:61554f238584 30 #define USB_DBG_TD(A) while(0)
va009039 18:61554f238584 31 #define USB_DBG_ED_IF(A,B) while(0)
va009039 18:61554f238584 32 void debug_hex(uint8_t* buf, int size);
va009039 18:61554f238584 33 #else
va009039 18:61554f238584 34 #define USB_DBG(...) while(0)
va009039 18:61554f238584 35 #define USB_DBG_ED(A) while(0)
va009039 18:61554f238584 36 #define USB_DBG_TD(A) while(0)
va009039 18:61554f238584 37 #define USB_DBG_ED_IF(A,B) while(0)
va009039 18:61554f238584 38 #define USB_DBG_HEX(A,B) while(0)
va009039 18:61554f238584 39 #endif
va009039 18:61554f238584 40
va009039 18:61554f238584 41 #define USB_TRACE1(A) while(0)
va009039 18:61554f238584 42
va009039 18:61554f238584 43 #ifdef _USB_TEST
va009039 18:61554f238584 44 #undef USB_TEST_ASSERT
va009039 18:61554f238584 45 void usb_test_assert_internal(const char *expr, const char *file, int line);
va009039 18:61554f238584 46 #define USB_TEST_ASSERT(EXPR) while(!(EXPR)){usb_test_assert_internal(#EXPR,__FILE__,__LINE__);}
va009039 18:61554f238584 47 #else
va009039 18:61554f238584 48 #define USB_TEST_ASSERT(EXPR) while(0)
va009039 18:61554f238584 49 #endif
va009039 18:61554f238584 50
va009039 18:61554f238584 51 #define USB_INFO(...) do{fprintf(stderr,__VA_ARGS__);fprintf(stderr,"\n");}while(0);
va009039 18:61554f238584 52
va009039 18:61554f238584 53 // bits of the USB/OTG clock control register
va009039 18:61554f238584 54 #define HOST_CLK_EN (1<<0)
va009039 18:61554f238584 55 #define DEV_CLK_EN (1<<1)
va009039 18:61554f238584 56 #define PORTSEL_CLK_EN (1<<3)
va009039 18:61554f238584 57 #define AHB_CLK_EN (1<<4)
va009039 18:61554f238584 58
va009039 18:61554f238584 59 // bits of the USB/OTG clock status register
va009039 18:61554f238584 60 #define HOST_CLK_ON (1<<0)
va009039 18:61554f238584 61 #define DEV_CLK_ON (1<<1)
va009039 18:61554f238584 62 #define PORTSEL_CLK_ON (1<<3)
va009039 18:61554f238584 63 #define AHB_CLK_ON (1<<4)
va009039 18:61554f238584 64
va009039 18:61554f238584 65 // we need host clock, OTG/portsel clock and AHB clock
va009039 18:61554f238584 66 #define CLOCK_MASK (HOST_CLK_EN | PORTSEL_CLK_EN | AHB_CLK_EN)
va009039 18:61554f238584 67 #define FI 0x2EDF /* 12000 bits per frame (-1) */
va009039 18:61554f238584 68 #define DEFAULT_FMINTERVAL ((((6 * (FI - 210)) / 7) << 16) | FI)
va009039 18:61554f238584 69
va009039 18:61554f238584 70 USBHALHost* USBHALHost::instHost;
va009039 18:61554f238584 71
va009039 18:61554f238584 72 USBHALHost::USBHALHost() {
va009039 18:61554f238584 73 instHost = this;
va009039 18:61554f238584 74 }
va009039 18:61554f238584 75
va009039 18:61554f238584 76 void USBHALHost::init() {
va009039 18:61554f238584 77 NVIC_DisableIRQ(USB_IRQn);
va009039 18:61554f238584 78 m_pHcca = new HCCA();
va009039 18:61554f238584 79 init_hw_ohci(m_pHcca);
va009039 18:61554f238584 80 ResetRootHub();
va009039 18:61554f238584 81 NVIC_SetVector(USB_IRQn, (uint32_t)_usbisr);
va009039 18:61554f238584 82 NVIC_SetPriority(USB_IRQn, 0);
va009039 18:61554f238584 83 NVIC_EnableIRQ(USB_IRQn);
va009039 18:61554f238584 84
va009039 18:61554f238584 85 USB_INFO("Simple USBHost Library for LPC4088/LPC1768");
va009039 18:61554f238584 86 bool lowSpeed = wait_attach();
va009039 18:61554f238584 87 addDevice(NULL, 0, lowSpeed);
va009039 18:61554f238584 88 }
va009039 18:61554f238584 89
va009039 18:61554f238584 90 void USBHALHost::init_hw_ohci(HCCA* pHcca) {
va009039 18:61554f238584 91 LPC_SC->PCONP &= ~(1UL<<31); //Cut power
va009039 18:61554f238584 92 wait_ms(1000);
va009039 18:61554f238584 93 LPC_SC->PCONP |= (1UL<<31); // turn on power for USB
va009039 18:61554f238584 94 LPC_USB->USBClkCtrl |= CLOCK_MASK; // Enable USB host clock, port selection and AHB clock
va009039 18:61554f238584 95 // Wait for clocks to become available
va009039 18:61554f238584 96 while ((LPC_USB->USBClkSt & CLOCK_MASK) != CLOCK_MASK)
va009039 18:61554f238584 97 ;
va009039 18:61554f238584 98 LPC_USB->OTGStCtrl |= 1;
va009039 18:61554f238584 99 LPC_USB->USBClkCtrl &= ~PORTSEL_CLK_EN;
va009039 18:61554f238584 100
va009039 18:61554f238584 101 #if defined(TARGET_LPC1768)
va009039 18:61554f238584 102 LPC_PINCON->PINSEL1 &= ~((3<<26) | (3<<28));
va009039 18:61554f238584 103 LPC_PINCON->PINSEL1 |= ((1<<26)|(1<<28)); // 0x14000000
va009039 18:61554f238584 104 #elif defined(TARGET_LPC4088)
va009039 18:61554f238584 105 LPC_IOCON->P0_29 = 0x01; // USB_D+1
va009039 18:61554f238584 106 LPC_IOCON->P0_30 = 0x01; // USB_D-1
va009039 18:61554f238584 107 // DO NOT CHANGE P1_19.
va009039 18:61554f238584 108 #else
va009039 18:61554f238584 109 #error "target error"
va009039 18:61554f238584 110 #endif
va009039 18:61554f238584 111 USB_DBG("initialize OHCI\n");
va009039 18:61554f238584 112 wait_ms(100); /* Wait 50 ms before apply reset */
va009039 18:61554f238584 113 USB_TEST_ASSERT((LPC_USB->HcRevision&0xff) == 0x10); // check revision
va009039 18:61554f238584 114 LPC_USB->HcControl = 0; /* HARDWARE RESET */
va009039 18:61554f238584 115 LPC_USB->HcControlHeadED = 0; /* Initialize Control list head to Zero */
va009039 18:61554f238584 116 LPC_USB->HcBulkHeadED = 0; /* Initialize Bulk list head to Zero */
va009039 18:61554f238584 117 /* SOFTWARE RESET */
va009039 18:61554f238584 118 LPC_USB->HcCommandStatus = OR_CMD_STATUS_HCR;
va009039 18:61554f238584 119 LPC_USB->HcFmInterval = DEFAULT_FMINTERVAL; /* Write Fm Interval and Largest Data Packet Counter */
va009039 18:61554f238584 120 LPC_USB->HcPeriodicStart = FI*90/100;
va009039 18:61554f238584 121 /* Put HC in operational state */
va009039 18:61554f238584 122 LPC_USB->HcControl = (LPC_USB->HcControl & (~OR_CONTROL_HCFS)) | OR_CONTROL_HC_OPER;
va009039 18:61554f238584 123 LPC_USB->HcRhStatus = OR_RH_STATUS_LPSC; /* Set Global Power */
va009039 18:61554f238584 124 USB_TEST_ASSERT(pHcca);
va009039 18:61554f238584 125 for (int i = 0; i < 32; i++) {
va009039 18:61554f238584 126 pHcca->InterruptTable[i] = NULL;
va009039 18:61554f238584 127 }
va009039 18:61554f238584 128 LPC_USB->HcHCCA = reinterpret_cast<uint32_t>(pHcca);
va009039 18:61554f238584 129 LPC_USB->HcInterruptStatus |= LPC_USB->HcInterruptStatus; /* Clear Interrrupt Status */
va009039 18:61554f238584 130 LPC_USB->HcInterruptEnable = OR_INTR_ENABLE_MIE|OR_INTR_ENABLE_WDH|OR_INTR_ENABLE_FNO;
va009039 18:61554f238584 131
va009039 18:61554f238584 132 LPC_USB->HcRhPortStatus1 = OR_RH_PORT_CSC;
va009039 18:61554f238584 133 LPC_USB->HcRhPortStatus1 = OR_RH_PORT_PRSC;
va009039 18:61554f238584 134 }
va009039 18:61554f238584 135
va009039 18:61554f238584 136 void USBHALHost::ResetRootHub() {
va009039 18:61554f238584 137 wait_ms(100); /* USB 2.0 spec says at least 50ms delay before port reset */
va009039 18:61554f238584 138 LPC_USB->HcRhPortStatus1 = OR_RH_PORT_PRS; // Initiate port reset
va009039 18:61554f238584 139 USB_DBG("Before loop\n");
va009039 18:61554f238584 140 while (LPC_USB->HcRhPortStatus1 & OR_RH_PORT_PRS)
va009039 18:61554f238584 141 ;
va009039 18:61554f238584 142 LPC_USB->HcRhPortStatus1 = OR_RH_PORT_PRSC; // ...and clear port reset signal
va009039 18:61554f238584 143 USB_DBG("After loop\n");
va009039 18:61554f238584 144 wait_ms(200); /* Wait for 100 MS after port reset */
va009039 18:61554f238584 145 }
va009039 18:61554f238584 146
va009039 18:61554f238584 147 bool USBHALHost::wait_attach() {
va009039 18:61554f238584 148 bool lowSpeed = false;
va009039 18:61554f238584 149 uint32_t status = LPC_USB->HcRhPortStatus1;
va009039 18:61554f238584 150 if (status & OR_RH_PORT_LSDA) { // lowSpeedDeviceAttached
va009039 18:61554f238584 151 lowSpeed = true;
va009039 18:61554f238584 152 }
va009039 18:61554f238584 153 return lowSpeed;
va009039 18:61554f238584 154 }
va009039 18:61554f238584 155
va009039 18:61554f238584 156 void enable(ENDPOINT_TYPE type) {
va009039 18:61554f238584 157 switch(type) {
va009039 18:61554f238584 158 case CONTROL_ENDPOINT:
va009039 18:61554f238584 159 LPC_USB->HcCommandStatus |= OR_CMD_STATUS_CLF;
va009039 18:61554f238584 160 LPC_USB->HcControl |= OR_CONTROL_CLE;
va009039 18:61554f238584 161 break;
va009039 18:61554f238584 162 case ISOCHRONOUS_ENDPOINT:
va009039 18:61554f238584 163 LPC_USB->HcControl |= OR_CONTROL_PLE;
va009039 18:61554f238584 164 break;
va009039 18:61554f238584 165 case BULK_ENDPOINT:
va009039 18:61554f238584 166 LPC_USB->HcCommandStatus |= OR_CMD_STATUS_BLF;
va009039 18:61554f238584 167 LPC_USB->HcControl |= OR_CONTROL_BLE;
va009039 18:61554f238584 168 break;
va009039 18:61554f238584 169 case INTERRUPT_ENDPOINT:
va009039 18:61554f238584 170 LPC_USB->HcControl |= OR_CONTROL_PLE;
va009039 18:61554f238584 171 break;
va009039 18:61554f238584 172 }
va009039 18:61554f238584 173 }
va009039 18:61554f238584 174
va009039 18:61554f238584 175 void USBHALHost::token_init(USBEndpoint* ep) {
va009039 18:61554f238584 176 HCED* ed = ep->getHALData<HCED*>();
va009039 18:61554f238584 177 if (ed == NULL) {
va009039 18:61554f238584 178 ed = new HCED(ep);
va009039 18:61554f238584 179 ep->setHALData<HCED*>(ed);
va009039 18:61554f238584 180 }
va009039 18:61554f238584 181 USBDeviceConnected* dev = ep->getDevice();
va009039 18:61554f238584 182 USB_TEST_ASSERT(dev);
va009039 18:61554f238584 183 if (dev) {
va009039 18:61554f238584 184 uint8_t devAddr = dev->getAddress();
va009039 18:61554f238584 185 USB_DBG("devAddr=%02x", devAddr);
va009039 18:61554f238584 186 ed->setFunctionAddress(devAddr);
va009039 18:61554f238584 187 }
va009039 18:61554f238584 188 uint16_t size = ep->getSize();
va009039 18:61554f238584 189 USB_DBG("MaxPacketSize=%d", size);
va009039 18:61554f238584 190 ed->setMaxPacketSize(size);
va009039 18:61554f238584 191 if (ed->HeadTd == NULL) {
va009039 18:61554f238584 192 HCTD* td = new HCTD(ed);
va009039 18:61554f238584 193 ed->TailTd = td;
va009039 18:61554f238584 194 ed->HeadTd = td;
va009039 18:61554f238584 195 switch(ep->getType()) {
va009039 18:61554f238584 196 case CONTROL_ENDPOINT:
va009039 18:61554f238584 197 ed->Next = reinterpret_cast<HCED*>(LPC_USB->HcControlHeadED);
va009039 18:61554f238584 198 LPC_USB->HcControlHeadED = reinterpret_cast<uint32_t>(ed);
va009039 18:61554f238584 199 break;
va009039 18:61554f238584 200 case BULK_ENDPOINT:
va009039 18:61554f238584 201 ed->Next = reinterpret_cast<HCED*>(LPC_USB->HcBulkHeadED);
va009039 18:61554f238584 202 LPC_USB->HcBulkHeadED = reinterpret_cast<uint32_t>(ed);
va009039 18:61554f238584 203 break;
va009039 18:61554f238584 204 case INTERRUPT_ENDPOINT:
va009039 18:61554f238584 205 HCCA* pHcca = reinterpret_cast<HCCA*>(LPC_USB->HcHCCA);
va009039 18:61554f238584 206 ed->Next = pHcca->InterruptTable[0];
va009039 18:61554f238584 207 pHcca->InterruptTable[0] = ed;
va009039 18:61554f238584 208 break;
va009039 18:61554f238584 209 }
va009039 18:61554f238584 210 }
va009039 18:61554f238584 211 }
va009039 18:61554f238584 212
va009039 18:61554f238584 213 int USBHALHost::token_setup(USBEndpoint* ep, SETUP_PACKET* setup, uint16_t wLength) {
va009039 18:61554f238584 214 token_init(ep);
va009039 18:61554f238584 215 HCED* ed = ep->getHALData<HCED*>();
va009039 18:61554f238584 216 HCTD* td = ed->TailTd;
va009039 18:61554f238584 217 setup->wLength = wLength;
va009039 18:61554f238584 218 TBUF* tbuf = new(sizeof(SETUP_PACKET))TBUF(setup, sizeof(SETUP_PACKET));
va009039 18:61554f238584 219 td->transfer(tbuf, sizeof(SETUP_PACKET));
va009039 18:61554f238584 220 td->Control |= TD_TOGGLE_0|TD_SETUP; // DATA0
va009039 18:61554f238584 221 HCTD* blank = new HCTD(ed);
va009039 18:61554f238584 222 ed->enqueue(blank);
va009039 18:61554f238584 223 //DBG_ED(ed);
va009039 18:61554f238584 224 enable(ep->getType());
va009039 18:61554f238584 225
va009039 18:61554f238584 226 td = ed->get_queue_HCTD();
va009039 18:61554f238584 227 USB_TEST_ASSERT(td);
va009039 18:61554f238584 228 int result = td->getLengthTransferred();
va009039 18:61554f238584 229 USB_DBG_TD(td);
va009039 18:61554f238584 230 delete tbuf;
va009039 18:61554f238584 231 delete td;
va009039 18:61554f238584 232 return result;
va009039 18:61554f238584 233 }
va009039 18:61554f238584 234
va009039 18:61554f238584 235 static HCED* getHCED_iso(USBEndpoint* ep) {
va009039 18:61554f238584 236 HCED* ed = ep->getHALData<HCED*>();
va009039 18:61554f238584 237 if (ed != NULL) {
va009039 18:61554f238584 238 return ed;
va009039 18:61554f238584 239 }
va009039 18:61554f238584 240 ed = new HCED(ep);
va009039 18:61554f238584 241 ep->setHALData<HCED*>(ed);
va009039 18:61554f238584 242 ed->setFormat(); // F Format ITD
va009039 18:61554f238584 243 ed->iso.FrameCount = ep->ohci.frameCount;
va009039 18:61554f238584 244 ed->iso.queue_limit = ep->ohci.queueLimit;
va009039 18:61554f238584 245 ed->iso.queue_count = 0;
va009039 18:61554f238584 246 ed->iso.Current_FrameCount = 0;
va009039 18:61554f238584 247 ed->iso.Current_itd = NULL;
va009039 18:61554f238584 248 ed->iso.FrameNumber = LPC_USB->HcFmNumber + 10; // after 10msec
va009039 18:61554f238584 249 HCITD* itd = ed->new_HCITD();
va009039 18:61554f238584 250 ed->init_queue(reinterpret_cast<HCTD*>(itd));
va009039 18:61554f238584 251 HCCA* hcca = reinterpret_cast<HCCA*>(LPC_USB->HcHCCA);
va009039 18:61554f238584 252 hcca->enqueue(ed);
va009039 18:61554f238584 253 LPC_USB->HcControl |= OR_CONTROL_PLE; // PeriodicListEnable
va009039 18:61554f238584 254 LPC_USB->HcControl |= OR_CONTROL_IE; // IsochronousEnable
va009039 18:61554f238584 255 return ed;
va009039 18:61554f238584 256 }
va009039 18:61554f238584 257
va009039 18:61554f238584 258 static void enablePeriodic() {
va009039 18:61554f238584 259 LPC_USB->HcControl |= OR_CONTROL_PLE;
va009039 18:61554f238584 260 }
va009039 18:61554f238584 261
va009039 18:61554f238584 262 HCITD* isochronousReceive(USBEndpoint* ep) {
va009039 18:61554f238584 263 HCED* ed = getHCED_iso(ep);
va009039 18:61554f238584 264 USB_TEST_ASSERT(ed);
va009039 18:61554f238584 265 while(ed->iso.queue_count < ed->iso.queue_limit) {
va009039 18:61554f238584 266 HCITD* blank_itd = ed->new_HCITD();
va009039 18:61554f238584 267 if (ed->enqueue(reinterpret_cast<HCTD*>(blank_itd))) {
va009039 18:61554f238584 268 ed->iso.queue_count++;
va009039 18:61554f238584 269 }
va009039 18:61554f238584 270 enablePeriodic();
va009039 18:61554f238584 271 }
va009039 18:61554f238584 272
va009039 18:61554f238584 273 HCITD* itd = ed->get_queue_HCITD();
va009039 18:61554f238584 274 if (itd) {
va009039 18:61554f238584 275 ed->iso.queue_count--;
va009039 18:61554f238584 276 }
va009039 18:61554f238584 277 return itd;
va009039 18:61554f238584 278 }
va009039 18:61554f238584 279
va009039 18:61554f238584 280 int USBHALHost::token_iso_in(USBEndpoint* ep, uint8_t* data, int size) {
va009039 18:61554f238584 281 HCED* ed = getHCED_iso(ep);
va009039 18:61554f238584 282 if (ed->iso.Current_FrameCount == 0) {
va009039 18:61554f238584 283 HCITD* itd = isochronousReceive(ep);
va009039 18:61554f238584 284 if (itd == NULL) {
va009039 18:61554f238584 285 return -1;
va009039 18:61554f238584 286 }
va009039 18:61554f238584 287 if (itd->ConditionCode() != 0) {
va009039 18:61554f238584 288 delete itd;
va009039 18:61554f238584 289 return -1;
va009039 18:61554f238584 290 }
va009039 18:61554f238584 291 ed->iso.Current_itd = itd;
va009039 18:61554f238584 292 }
va009039 18:61554f238584 293
va009039 18:61554f238584 294 HCITD* itd = ed->iso.Current_itd;
va009039 18:61554f238584 295 int fc = ed->iso.Current_FrameCount;
va009039 18:61554f238584 296 int result = -1;
va009039 18:61554f238584 297 uint8_t cc = itd->ConditionCode(fc);
va009039 18:61554f238584 298 if (cc == 0 || cc == 9) {
va009039 18:61554f238584 299 result = itd->Length(fc);
va009039 18:61554f238584 300 memcpy(data, itd->Buffer(fc), result);
va009039 18:61554f238584 301 }
va009039 18:61554f238584 302
va009039 18:61554f238584 303 if (++ed->iso.Current_FrameCount >= itd->FrameCount()) {
va009039 18:61554f238584 304 ed->iso.Current_FrameCount = 0;
va009039 18:61554f238584 305 delete ed->iso.Current_itd;
va009039 18:61554f238584 306 }
va009039 18:61554f238584 307 return result;
va009039 18:61554f238584 308 }
va009039 18:61554f238584 309
va009039 18:61554f238584 310 int USBHALHost::multi_token_in(USBEndpoint* ep, uint8_t* data, int size) {
va009039 18:61554f238584 311 token_init(ep);
va009039 18:61554f238584 312 HCED* ed = ep->getHALData<HCED*>();
va009039 18:61554f238584 313 HCTD* td = ed->TailTd;
va009039 18:61554f238584 314 TBUF* tbuf = NULL;
va009039 18:61554f238584 315 if (data != NULL) {
va009039 18:61554f238584 316 tbuf = new(size)TBUF();
va009039 18:61554f238584 317 td->transfer(tbuf, size);
va009039 18:61554f238584 318 }
va009039 18:61554f238584 319 td->Control |= TD_IN;
va009039 18:61554f238584 320 HCTD* blank = new HCTD(ed);
va009039 18:61554f238584 321 ed->enqueue(blank);
va009039 18:61554f238584 322 USB_DBG_ED_IF(ed->EndpointNumber()==0, ed); // control transfer
va009039 18:61554f238584 323 enable(ep->getType());
va009039 18:61554f238584 324
va009039 18:61554f238584 325 td = ed->get_queue_HCTD();
va009039 18:61554f238584 326 USB_TEST_ASSERT(td);
va009039 18:61554f238584 327 if (data != NULL) {
va009039 18:61554f238584 328 memcpy(data, tbuf->buf, size);
va009039 18:61554f238584 329 delete tbuf;
va009039 18:61554f238584 330 }
va009039 18:61554f238584 331 int result = td->getLengthTransferred();
va009039 18:61554f238584 332 delete td;
va009039 18:61554f238584 333 return result;
va009039 18:61554f238584 334 }
va009039 18:61554f238584 335
va009039 18:61554f238584 336 int USBHALHost::multi_token_out(USBEndpoint* ep, const uint8_t* data, int size) {
va009039 18:61554f238584 337 token_init(ep);
va009039 18:61554f238584 338 HCED* ed = ep->getHALData<HCED*>();
va009039 18:61554f238584 339 HCTD* td = ed->TailTd;
va009039 18:61554f238584 340 TBUF* tbuf = NULL;
va009039 18:61554f238584 341 if (data != NULL) {
va009039 18:61554f238584 342 tbuf = new(size)TBUF(data, size);
va009039 18:61554f238584 343 td->transfer(tbuf, size);
va009039 18:61554f238584 344 }
va009039 18:61554f238584 345 td->Control |= TD_OUT;
va009039 18:61554f238584 346 HCTD* blank = new HCTD(ed);
va009039 18:61554f238584 347 ed->enqueue(blank);
va009039 18:61554f238584 348 USB_DBG_ED(ed);
va009039 18:61554f238584 349 enable(ep->getType());
va009039 18:61554f238584 350
va009039 18:61554f238584 351 td = ed->get_queue_HCTD();
va009039 18:61554f238584 352 USB_TEST_ASSERT(td);
va009039 18:61554f238584 353 if (data != NULL) {
va009039 18:61554f238584 354 delete tbuf;
va009039 18:61554f238584 355 }
va009039 18:61554f238584 356 int result = td->getLengthTransferred();
va009039 18:61554f238584 357 delete td;
va009039 18:61554f238584 358 return result;
va009039 18:61554f238584 359 }
va009039 18:61554f238584 360
va009039 18:61554f238584 361 void USBHALHost::multi_token_inNB(USBEndpoint* ep, uint8_t* data, int size) {
va009039 18:61554f238584 362 token_init(ep);
va009039 18:61554f238584 363 HCED* ed = ep->getHALData<HCED*>();
va009039 18:61554f238584 364 HCTD* td = ed->TailTd;
va009039 18:61554f238584 365 TBUF* tbuf = new(size)TBUF();
va009039 18:61554f238584 366 td->transfer(tbuf, size);
va009039 18:61554f238584 367 td->Control |= TD_IN;
va009039 18:61554f238584 368 HCTD* blank = new HCTD(ed);
va009039 18:61554f238584 369 ed->enqueue(blank);
va009039 18:61554f238584 370 enable(ep->getType());
va009039 18:61554f238584 371 }
va009039 18:61554f238584 372
va009039 18:61554f238584 373 USB_TYPE USBHALHost::multi_token_inNB_result(USBEndpoint* ep) {
va009039 18:61554f238584 374 HCED* ed = ep->getHALData<HCED*>();
va009039 18:61554f238584 375 if (ed == NULL) {
va009039 18:61554f238584 376 return USB_TYPE_ERROR;
va009039 18:61554f238584 377 }
va009039 18:61554f238584 378 HCTD* td = ed->get_queue_HCTD(0);
va009039 18:61554f238584 379 if (td) {
va009039 18:61554f238584 380 int len = td->getLengthTransferred();
va009039 18:61554f238584 381 TBUF* tbuf = (TBUF*)td->buf_top;
va009039 18:61554f238584 382 memcpy(ep->getBufStart(), tbuf->buf, len);
va009039 18:61554f238584 383 ep->setLengthTransferred(len);
va009039 18:61554f238584 384 ep->setState((USB_TYPE)td->ConditionCode());
va009039 18:61554f238584 385 delete td;
va009039 18:61554f238584 386 delete tbuf;
va009039 18:61554f238584 387 return USB_TYPE_OK;
va009039 18:61554f238584 388 }
va009039 18:61554f238584 389 return USB_TYPE_PROCESSING;
va009039 18:61554f238584 390 }
va009039 18:61554f238584 391
va009039 18:61554f238584 392 void USBHALHost::setToggle(USBEndpoint* ep, uint8_t toggle) {
va009039 18:61554f238584 393 USB_TEST_ASSERT(toggle == 1);
va009039 18:61554f238584 394 HCED* ed = ep->getHALData<HCED*>();
va009039 18:61554f238584 395 ed->setToggle(toggle);
va009039 18:61554f238584 396 }
va009039 18:61554f238584 397
va009039 18:61554f238584 398 void USBHALHost::_usbisr(void) {
va009039 18:61554f238584 399 if (instHost) {
va009039 18:61554f238584 400 instHost->UsbIrqhandler();
va009039 18:61554f238584 401 }
va009039 18:61554f238584 402 }
va009039 18:61554f238584 403
va009039 18:61554f238584 404 HCTD* td_reverse(HCTD* td)
va009039 18:61554f238584 405 {
va009039 18:61554f238584 406 HCTD* result = NULL;
va009039 18:61554f238584 407 HCTD* next;
va009039 18:61554f238584 408 while(td) {
va009039 18:61554f238584 409 next = const_cast<HCTD*>(td->Next);
va009039 18:61554f238584 410 td->Next = result;
va009039 18:61554f238584 411 result = td;
va009039 18:61554f238584 412 td = next;
va009039 18:61554f238584 413 }
va009039 18:61554f238584 414 return result;
va009039 18:61554f238584 415 }
va009039 18:61554f238584 416
va009039 18:61554f238584 417 void USBHALHost::UsbIrqhandler() {
va009039 18:61554f238584 418 if (!(LPC_USB->HcInterruptStatus & LPC_USB->HcInterruptEnable)) {
va009039 18:61554f238584 419 return;
va009039 18:61554f238584 420 }
va009039 18:61554f238584 421 m_report_irq++;
va009039 18:61554f238584 422 uint32_t status = LPC_USB->HcInterruptStatus;
va009039 18:61554f238584 423 if (status & OR_INTR_STATUS_FNO) {
va009039 18:61554f238584 424 m_report_FNO++;
va009039 18:61554f238584 425 }
va009039 18:61554f238584 426 if (status & OR_INTR_STATUS_WDH) {
va009039 18:61554f238584 427 union {
va009039 18:61554f238584 428 HCTD* done_td;
va009039 18:61554f238584 429 uint32_t lsb;
va009039 18:61554f238584 430 };
va009039 18:61554f238584 431 done_td = const_cast<HCTD*>(m_pHcca->DoneHead);
va009039 18:61554f238584 432 USB_TEST_ASSERT(done_td);
va009039 18:61554f238584 433 m_pHcca->DoneHead = NULL; // reset
va009039 18:61554f238584 434 if (lsb & 1) { // error ?
va009039 18:61554f238584 435 lsb &= ~1;
va009039 18:61554f238584 436 }
va009039 18:61554f238584 437 HCTD* td = td_reverse(done_td);
va009039 18:61554f238584 438 while(td) {
va009039 18:61554f238584 439 HCED* ed = td->parent;
va009039 18:61554f238584 440 USB_TEST_ASSERT(ed);
va009039 18:61554f238584 441 if (ed) {
va009039 18:61554f238584 442 ed->irqWdhHandler(td);
va009039 18:61554f238584 443 }
va009039 18:61554f238584 444 td = td->Next;
va009039 18:61554f238584 445 }
va009039 18:61554f238584 446 m_report_WDH++;
va009039 18:61554f238584 447 }
va009039 18:61554f238584 448 LPC_USB->HcInterruptStatus = status; // Clear Interrrupt Status
va009039 18:61554f238584 449 }
va009039 18:61554f238584 450
va009039 18:61554f238584 451 TBUF::TBUF(const void* data, int size) {
va009039 18:61554f238584 452 if (size > 0) {
va009039 18:61554f238584 453 memcpy(buf, data, size);
va009039 18:61554f238584 454 }
va009039 18:61554f238584 455 }
va009039 18:61554f238584 456
va009039 18:61554f238584 457 HCTD::HCTD(HCED* obj) {
va009039 18:61554f238584 458 CTASSERT(sizeof(HCTD) == 36);
va009039 18:61554f238584 459 USB_TEST_ASSERT(obj);
va009039 18:61554f238584 460 Control = TD_CC|TD_ROUNDING;
va009039 18:61554f238584 461 CurrBufPtr = NULL;
va009039 18:61554f238584 462 Next = NULL;
va009039 18:61554f238584 463 BufEnd = NULL;
va009039 18:61554f238584 464 buf_top = NULL;
va009039 18:61554f238584 465 buf_size = 0;
va009039 18:61554f238584 466 parent = obj;
va009039 18:61554f238584 467 }
va009039 18:61554f238584 468
va009039 18:61554f238584 469 HCITD::HCITD(HCED* obj, uint16_t FrameNumber, int FrameCount, uint16_t PacketSize) {
va009039 18:61554f238584 470 Control = 0xe0000000 | // CC ConditionCode NOT ACCESSED
va009039 18:61554f238584 471 ((FrameCount-1) << 24)| // FC FrameCount
va009039 18:61554f238584 472 TD_DELAY_INT(0) | // DI DelayInterrupt
va009039 18:61554f238584 473 FrameNumber; // SF StartingFrame
va009039 18:61554f238584 474 BufferPage0 = const_cast<uint8_t*>(buf);
va009039 18:61554f238584 475 BufferEnd = const_cast<uint8_t*>(buf) + PacketSize * FrameCount - 1;
va009039 18:61554f238584 476 Next = NULL;
va009039 18:61554f238584 477 parent = obj;
va009039 18:61554f238584 478 uint32_t addr = reinterpret_cast<uint32_t>(buf);
va009039 18:61554f238584 479 for(int i = 0; i < FrameCount; i++) {
va009039 18:61554f238584 480 uint16_t offset = addr & 0x0fff;
va009039 18:61554f238584 481 if ((addr&0xfffff000) == (reinterpret_cast<uint32_t>(BufferEnd)&0xfffff000)) {
va009039 18:61554f238584 482 offset |= 0x1000;
va009039 18:61554f238584 483 }
va009039 18:61554f238584 484 OffsetPSW[i] = 0xe000|offset;
va009039 18:61554f238584 485 addr += PacketSize;
va009039 18:61554f238584 486 }
va009039 18:61554f238584 487 }
va009039 18:61554f238584 488
va009039 18:61554f238584 489 uint8_t* HCITD::Buffer(int fc) {
va009039 18:61554f238584 490 int offset = fc * parent->getMaxPacketSize();
va009039 18:61554f238584 491 return const_cast<uint8_t*>(buf) + offset;
va009039 18:61554f238584 492 }
va009039 18:61554f238584 493
va009039 18:61554f238584 494 HCED::HCED(USBEndpoint* ep) {
va009039 18:61554f238584 495 CTASSERT(sizeof(HCED) <= (64*2));
va009039 18:61554f238584 496 USBDeviceConnected* dev = ep->getDevice();
va009039 18:61554f238584 497 int devAddr = 0;
va009039 18:61554f238584 498 bool lowSpeed = false;
va009039 18:61554f238584 499 if (dev) {
va009039 18:61554f238584 500 devAddr = dev->getAddress();
va009039 18:61554f238584 501 lowSpeed = dev->getSpeed();
va009039 18:61554f238584 502 }
va009039 18:61554f238584 503 int ep_number = ep->getAddress();
va009039 18:61554f238584 504 int MaxPacketSize = ep->getSize();
va009039 18:61554f238584 505 Control = devAddr | /* USB address */
va009039 18:61554f238584 506 ((ep_number & 0x7F) << 7) | /* Endpoint address */
va009039 18:61554f238584 507 (ep_number!=0?(((ep_number&0x80)?2:1) << 11):0)| /* direction : Out = 1, 2 = In */
va009039 18:61554f238584 508 ((lowSpeed?1:0) << 13) | /* speed full=0 low=1 */
va009039 18:61554f238584 509 (MaxPacketSize << 16); /* MaxPkt Size */
va009039 18:61554f238584 510 TailTd = NULL;
va009039 18:61554f238584 511 HeadTd = NULL;
va009039 18:61554f238584 512 Next = NULL;
va009039 18:61554f238584 513 }
va009039 18:61554f238584 514
va009039 18:61554f238584 515 bool HCED::enqueue(HCTD* td) {
va009039 18:61554f238584 516 if (td) {
va009039 18:61554f238584 517 HCTD* tail = reinterpret_cast<HCTD*>(TailTd);
va009039 18:61554f238584 518 if (tail) {
va009039 18:61554f238584 519 tail->Next = td;
va009039 18:61554f238584 520 TailTd = reinterpret_cast<HCTD*>(td);
va009039 18:61554f238584 521 return true;
va009039 18:61554f238584 522 }
va009039 18:61554f238584 523 }
va009039 18:61554f238584 524 return false;
va009039 18:61554f238584 525 }
va009039 18:61554f238584 526
va009039 18:61554f238584 527 void HCED::init_queue(HCTD* td) {
va009039 18:61554f238584 528 TailTd = reinterpret_cast<HCTD*>(td);
va009039 18:61554f238584 529 HeadTd = reinterpret_cast<HCTD*>(td);
va009039 18:61554f238584 530 }
va009039 18:61554f238584 531
va009039 18:61554f238584 532 void HCED::setToggle(uint8_t toggle) {
va009039 18:61554f238584 533 uint32_t c = reinterpret_cast<uint32_t>(HeadTd);
va009039 18:61554f238584 534 if (toggle == 0) { // DATA0
va009039 18:61554f238584 535 c &= ~0x02;
va009039 18:61554f238584 536 } else { // DATA1
va009039 18:61554f238584 537 c |= 0x02;
va009039 18:61554f238584 538 }
va009039 18:61554f238584 539 HeadTd = reinterpret_cast<HCTD*>(c);
va009039 18:61554f238584 540 }
va009039 18:61554f238584 541
va009039 18:61554f238584 542 uint8_t HCED::getToggle() {
va009039 18:61554f238584 543 uint32_t c = reinterpret_cast<uint32_t>(HeadTd);
va009039 18:61554f238584 544 return (c&0x02) ? 1 : 0;
va009039 18:61554f238584 545 }
va009039 18:61554f238584 546
va009039 18:61554f238584 547 HCTD* HCED::get_queue_HCTD(uint32_t millisec)
va009039 18:61554f238584 548 {
va009039 18:61554f238584 549 for(int i = 0; i < 16; i++) {
va009039 18:61554f238584 550 osEvent evt = done_queue_get(millisec);
va009039 18:61554f238584 551 if (evt.status == osEventMessage) {
va009039 18:61554f238584 552 HCTD* td = reinterpret_cast<HCTD*>(evt.value.p);
va009039 18:61554f238584 553 USB_TEST_ASSERT(td);
va009039 18:61554f238584 554 uint8_t cc = td->ConditionCode();
va009039 18:61554f238584 555 if (cc != 0) {
va009039 18:61554f238584 556 m_ConditionCode = cc;
va009039 18:61554f238584 557 USB_DBG_TD(td);
va009039 18:61554f238584 558 }
va009039 18:61554f238584 559 return td;
va009039 18:61554f238584 560 } else if (evt.status == osOK) {
va009039 18:61554f238584 561 continue;
va009039 18:61554f238584 562 } else if (evt.status == osEventTimeout) {
va009039 18:61554f238584 563 return NULL;
va009039 18:61554f238584 564 } else {
va009039 18:61554f238584 565 USB_DBG("evt.status: %02x\n", evt.status);
va009039 18:61554f238584 566 USB_TEST_ASSERT(evt.status == osEventMessage);
va009039 18:61554f238584 567 }
va009039 18:61554f238584 568 }
va009039 18:61554f238584 569 return NULL;
va009039 18:61554f238584 570 }
va009039 18:61554f238584 571
va009039 18:61554f238584 572 HCITD* HCED::get_queue_HCITD() {
va009039 18:61554f238584 573 osEvent evt = done_queue_get(0);
va009039 18:61554f238584 574 if (evt.status == osEventMessage) {
va009039 18:61554f238584 575 HCITD* itd = reinterpret_cast<HCITD*>(evt.value.p);
va009039 18:61554f238584 576 USB_TEST_ASSERT(itd);
va009039 18:61554f238584 577 return itd;
va009039 18:61554f238584 578 }
va009039 18:61554f238584 579 return NULL;
va009039 18:61554f238584 580 }
va009039 18:61554f238584 581 HCITD* HCED::new_HCITD() {
va009039 18:61554f238584 582 uint16_t mps = getMaxPacketSize();
va009039 18:61554f238584 583 int total_size = mps * iso.FrameCount;
va009039 18:61554f238584 584 HCITD* itd = new(total_size)HCITD(this, iso.FrameNumber, iso.FrameCount, mps);
va009039 18:61554f238584 585 iso.FrameNumber += iso.FrameCount;
va009039 18:61554f238584 586 return itd;
va009039 18:61554f238584 587 }
va009039 18:61554f238584 588
va009039 18:61554f238584 589 void HCCA::enqueue(HCED* ed) {
va009039 18:61554f238584 590 for(int i = 0; i < 32; i++) {
va009039 18:61554f238584 591 if (InterruptTable[i] == NULL) {
va009039 18:61554f238584 592 InterruptTable[i] = ed;
va009039 18:61554f238584 593 } else {
va009039 18:61554f238584 594 HCED* nextEd = InterruptTable[i];
va009039 18:61554f238584 595 while(nextEd->Next && nextEd->Next != ed) {
va009039 18:61554f238584 596 nextEd = nextEd->Next;
va009039 18:61554f238584 597 }
va009039 18:61554f238584 598 nextEd->Next = ed;
va009039 18:61554f238584 599 }
va009039 18:61554f238584 600 }
va009039 18:61554f238584 601 }
va009039 18:61554f238584 602
va009039 18:61554f238584 603 #endif // defined(TARGET_LPC4088)||defined(TARGET_LPC1768)
va009039 18:61554f238584 604