Simple USBHost library for LPC4088. Backward compatibility of official-USBHost.
Dependencies: FATFileSystem mbed-rtos
USBHALHost.cpp
00001 /* mbed USBHost Library 00002 * Copyright (c) 2006-2013 ARM Limited 00003 * 00004 * Licensed under the Apache License, Version 2.0 (the "License"); 00005 * you may not use this file except in compliance with the License. 00006 * You may obtain a copy of the License at 00007 * 00008 * http://www.apache.org/licenses/LICENSE-2.0 00009 * 00010 * Unless required by applicable law or agreed to in writing, software 00011 * distributed under the License is distributed on an "AS IS" BASIS, 00012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00013 * See the License for the specific language governing permissions and 00014 * limitations under the License. 00015 */ 00016 00017 #include "USBHALHost.h" 00018 //#define _USB_DBG 00019 #include "BaseUsbHostDebug.h" 00020 #include "BaseUsbHostTest.h" 00021 00022 #ifndef CTASSERT 00023 template <bool>struct CtAssert; 00024 template <>struct CtAssert<true> {}; 00025 #define CTASSERT(A) CtAssert<A>(); 00026 #endif 00027 00028 #ifdef _USB_DBG 00029 #define USB_DBG(...) do{fprintf(stderr,"[%s@%d] ",__PRETTY_FUNCTION__,__LINE__);fprintf(stderr,__VA_ARGS__);fprintf(stderr,"\n");} while(0); 00030 #define USB_DBG_HEX(A,B) debug_hex(A,B) 00031 void debug_hex(uint8_t* buf, int size); 00032 #else 00033 #define USB_DBG(...) while(0) 00034 #define USB_DBG_HEX(A,B) while(0) 00035 #endif 00036 00037 #ifdef _USB_TEST 00038 #define USB_TEST_ASSERT(A) while(!(A)){fprintf(stderr,"\n\n%s@%d %s ASSERT!\n\n",__PRETTY_FUNCTION__,__LINE__,#A);exit(1);}; 00039 #define USB_TEST_ASSERT_FALSE(A) USB_TEST_ASSERT(!(A)) 00040 #else 00041 #define USB_TEST_ASSERT(A) while(0) 00042 #define USB_TEST_ASSERT_FALSE(A) while(0) 00043 #endif 00044 00045 #define USB_INFO(...) do{fprintf(stderr,__VA_ARGS__);fprintf(stderr,"\n");}while(0); 00046 00047 // bits of the USB/OTG clock control register 00048 #define HOST_CLK_EN (1<<0) 00049 #define DEV_CLK_EN (1<<1) 00050 #define PORTSEL_CLK_EN (1<<3) 00051 #define AHB_CLK_EN (1<<4) 00052 00053 // bits of the USB/OTG clock status register 00054 #define HOST_CLK_ON (1<<0) 00055 #define DEV_CLK_ON (1<<1) 00056 #define PORTSEL_CLK_ON (1<<3) 00057 #define AHB_CLK_ON (1<<4) 00058 00059 // we need host clock, OTG/portsel clock and AHB clock 00060 #define CLOCK_MASK (HOST_CLK_EN | PORTSEL_CLK_EN | AHB_CLK_EN) 00061 #define FI 0x2EDF /* 12000 bits per frame (-1) */ 00062 #define DEFAULT_FMINTERVAL ((((6 * (FI - 210)) / 7) << 16) | FI) 00063 00064 USBHALHost* USBHALHost::instHost; 00065 00066 USBHALHost::USBHALHost() { 00067 instHost = this; 00068 } 00069 00070 void USBHALHost::init() { 00071 NVIC_DisableIRQ(USB_IRQn); 00072 m_pHcca = new HCCA(); 00073 init_hw_ohci(m_pHcca); 00074 ResetRootHub(); 00075 NVIC_SetVector(USB_IRQn, (uint32_t)_usbisr); 00076 NVIC_SetPriority(USB_IRQn, 0); 00077 NVIC_EnableIRQ(USB_IRQn); 00078 00079 #ifndef BASE_USBHOST 00080 USB_INFO("Simple USBHost Library for EA LPC4088 QSB"); 00081 bool lowSpeed = wait_attach(); 00082 addDevice(NULL, 0, lowSpeed); 00083 #endif // BASE_USBHOST 00084 } 00085 00086 void USBHALHost::init_hw_ohci(HCCA* pHcca) { 00087 LPC_SC->PCONP &= ~(1UL<<31); //Cut power 00088 wait_ms(1000); 00089 LPC_SC->PCONP |= (1UL<<31); // turn on power for USB 00090 LPC_USB->USBClkCtrl |= CLOCK_MASK; // Enable USB host clock, port selection and AHB clock 00091 // Wait for clocks to become available 00092 while ((LPC_USB->USBClkSt & CLOCK_MASK) != CLOCK_MASK) 00093 ; 00094 LPC_USB->OTGStCtrl |= 1; 00095 LPC_USB->USBClkCtrl &= ~PORTSEL_CLK_EN; 00096 00097 #if defined(TARGET_LPC1768) 00098 LPC_PINCON->PINSEL1 &= ~((3<<26) | (3<<28)); 00099 LPC_PINCON->PINSEL1 |= ((1<<26)|(1<<28)); // 0x14000000 00100 #elif defined(TARGET_LPC4088) 00101 LPC_IOCON->P0_29 = 0x01; // USB_D+1 00102 LPC_IOCON->P0_30 = 0x01; // USB_D-1 00103 // DO NOT CHANGE P1_19. 00104 #else 00105 #error "target error" 00106 #endif 00107 USB_DBG("initialize OHCI\n"); 00108 wait_ms(100); /* Wait 50 ms before apply reset */ 00109 TEST_ASSERT((LPC_USB->HcRevision&0xff) == 0x10); // check revision 00110 LPC_USB->HcControl = 0; /* HARDWARE RESET */ 00111 LPC_USB->HcControlHeadED = 0; /* Initialize Control list head to Zero */ 00112 LPC_USB->HcBulkHeadED = 0; /* Initialize Bulk list head to Zero */ 00113 /* SOFTWARE RESET */ 00114 LPC_USB->HcCommandStatus = OR_CMD_STATUS_HCR; 00115 LPC_USB->HcFmInterval = DEFAULT_FMINTERVAL; /* Write Fm Interval and Largest Data Packet Counter */ 00116 LPC_USB->HcPeriodicStart = FI*90/100; 00117 /* Put HC in operational state */ 00118 LPC_USB->HcControl = (LPC_USB->HcControl & (~OR_CONTROL_HCFS)) | OR_CONTROL_HC_OPER; 00119 LPC_USB->HcRhStatus = OR_RH_STATUS_LPSC; /* Set Global Power */ 00120 TEST_ASSERT(pHcca); 00121 for (int i = 0; i < 32; i++) { 00122 pHcca->InterruptTable[i] = NULL; 00123 } 00124 LPC_USB->HcHCCA = reinterpret_cast<uint32_t>(pHcca); 00125 LPC_USB->HcInterruptStatus |= LPC_USB->HcInterruptStatus; /* Clear Interrrupt Status */ 00126 LPC_USB->HcInterruptEnable = OR_INTR_ENABLE_MIE|OR_INTR_ENABLE_WDH|OR_INTR_ENABLE_FNO; 00127 00128 LPC_USB->HcRhPortStatus1 = OR_RH_PORT_CSC; 00129 LPC_USB->HcRhPortStatus1 = OR_RH_PORT_PRSC; 00130 } 00131 00132 void USBHALHost::ResetRootHub() { 00133 wait_ms(100); /* USB 2.0 spec says at least 50ms delay before port reset */ 00134 LPC_USB->HcRhPortStatus1 = OR_RH_PORT_PRS; // Initiate port reset 00135 USB_DBG("Before loop\n"); 00136 while (LPC_USB->HcRhPortStatus1 & OR_RH_PORT_PRS) 00137 ; 00138 LPC_USB->HcRhPortStatus1 = OR_RH_PORT_PRSC; // ...and clear port reset signal 00139 USB_DBG("After loop\n"); 00140 wait_ms(200); /* Wait for 100 MS after port reset */ 00141 } 00142 00143 bool USBHALHost::wait_attach() { 00144 bool lowSpeed = false; 00145 uint32_t status = LPC_USB->HcRhPortStatus1; 00146 if (status & OR_RH_PORT_LSDA) { // lowSpeedDeviceAttached 00147 lowSpeed = true; 00148 } 00149 return lowSpeed; 00150 } 00151 00152 void USBHALHost::enable(ENDPOINT_TYPE type) { 00153 switch(type) { 00154 case CONTROL_ENDPOINT: 00155 LPC_USB->HcCommandStatus |= OR_CMD_STATUS_CLF; 00156 LPC_USB->HcControl |= OR_CONTROL_CLE; 00157 break; 00158 case ISOCHRONOUS_ENDPOINT: 00159 LPC_USB->HcControl |= OR_CONTROL_PLE; 00160 break; 00161 case BULK_ENDPOINT: 00162 LPC_USB->HcCommandStatus |= OR_CMD_STATUS_BLF; 00163 LPC_USB->HcControl |= OR_CONTROL_BLE; 00164 break; 00165 case INTERRUPT_ENDPOINT: 00166 LPC_USB->HcControl |= OR_CONTROL_PLE; 00167 break; 00168 } 00169 } 00170 00171 void USBHALHost::token_init(USBEndpoint* ep) { 00172 if (ep->m_pED == NULL) { 00173 ep->m_pED = new HCED(ep); 00174 USB_DBG_ED(ep->m_pED); 00175 } 00176 HCED* ed = ep->m_pED; 00177 USBDeviceConnected* dev = ep->getDevice(); 00178 USB_TEST_ASSERT(dev); 00179 if (dev) { 00180 uint8_t devAddr = dev->getAddress(); 00181 USB_DBG("devAddr=%02x", devAddr); 00182 ed->setFunctionAddress(devAddr); 00183 } 00184 uint16_t size = ep->getSize(); 00185 USB_DBG("MaxPacketSize=%d", size); 00186 ed->setMaxPacketSize(size); 00187 if (ed->HeadTd == NULL) { 00188 HCTD* td = new HCTD(ep); 00189 ed->TailTd = td; 00190 ed->HeadTd = td; 00191 switch(ep->getType()) { 00192 case CONTROL_ENDPOINT: 00193 ed->Next = reinterpret_cast<HCED*>(LPC_USB->HcControlHeadED); 00194 LPC_USB->HcControlHeadED = reinterpret_cast<uint32_t>(ed); 00195 break; 00196 case BULK_ENDPOINT: 00197 ed->Next = reinterpret_cast<HCED*>(LPC_USB->HcBulkHeadED); 00198 LPC_USB->HcBulkHeadED = reinterpret_cast<uint32_t>(ed); 00199 break; 00200 case INTERRUPT_ENDPOINT: 00201 HCCA* pHcca = reinterpret_cast<HCCA*>(LPC_USB->HcHCCA); 00202 ed->Next = pHcca->InterruptTable[0]; 00203 pHcca->InterruptTable[0] = ed; 00204 break; 00205 } 00206 USB_DBG_ED(ed); 00207 } 00208 } 00209 00210 int USBHALHost::token_setup(USBEndpoint* ep, SETUP_PACKET* setup, uint16_t wLength) { 00211 token_init(ep); 00212 HCED* ed = ep->m_pED; 00213 HCTD* td = ed->TailTd; 00214 setup->wLength = wLength; 00215 TBUF* tbuf = new(sizeof(SETUP_PACKET))TBUF(setup, sizeof(SETUP_PACKET)); 00216 td->transfer(tbuf, sizeof(SETUP_PACKET)); 00217 td->Control |= TD_TOGGLE_0|TD_SETUP; 00218 HCTD* blank = new HCTD(ep); 00219 ed->enqueue(blank); 00220 //DBG_ED(ed); 00221 enable(ep->getType()); 00222 00223 td = ep->get_queue_HCTD(); 00224 TEST_ASSERT(td); 00225 int result = td->getLengthTransferred(); 00226 DBG_TD(td); 00227 delete tbuf; 00228 delete td; 00229 return result; 00230 } 00231 00232 int USBHALHost::token_in(USBEndpoint* ep, uint8_t* data, int size, int retryLimit) { 00233 token_init(ep); 00234 HCED* ed = ep->m_pED; 00235 HCTD* td = ed->TailTd; 00236 TBUF* tbuf = NULL; 00237 if (data != NULL) { 00238 tbuf = new(size)TBUF(); 00239 td->transfer(tbuf, size); 00240 } 00241 td->Control |= TD_IN; 00242 HCTD* blank = new HCTD(ep); 00243 ed->enqueue(blank); 00244 USB_DBG_ED_IF(ed->EndpointNumber()==0, ed); // control transfer 00245 enable(ep->getType()); 00246 00247 td = ep->get_queue_HCTD(); 00248 TEST_ASSERT(td); 00249 if (data != NULL) { 00250 memcpy(data, tbuf->buf, size); 00251 delete tbuf; 00252 } 00253 int result = td->getLengthTransferred(); 00254 delete td; 00255 return result; 00256 } 00257 00258 int USBHALHost::token_out(USBEndpoint* ep, const uint8_t* data, int size, int retryLimit) { 00259 token_init(ep); 00260 HCED* ed = ep->m_pED; 00261 HCTD* td = ed->TailTd; 00262 TBUF* tbuf = NULL; 00263 if (data != NULL) { 00264 tbuf = new(size)TBUF(data, size); 00265 td->transfer(tbuf, size); 00266 } 00267 td->Control |= TD_OUT; 00268 HCTD* blank = new HCTD(ep); 00269 ed->enqueue(blank); 00270 DBG_ED(ed); 00271 enable(ep->getType()); 00272 00273 td = ep->get_queue_HCTD(); 00274 TEST_ASSERT(td); 00275 if (data != NULL) { 00276 delete tbuf; 00277 } 00278 int result = td->getLengthTransferred(); 00279 delete td; 00280 return result; 00281 } 00282 00283 void USBHALHost::token_inNB(USBEndpoint* ep, uint8_t* data, int size) { 00284 token_init(ep); 00285 HCED* ed = ep->m_pED; 00286 HCTD* td = ed->TailTd; 00287 TBUF* tbuf = new(size)TBUF(); 00288 td->transfer(tbuf, size); 00289 td->Control |= TD_IN; 00290 HCTD* blank = new HCTD(ep); 00291 ed->enqueue(blank); 00292 enable(ep->getType()); 00293 } 00294 00295 USB_TYPE USBHALHost::token_inNB_result(USBEndpoint* ep) { 00296 HCTD* td = ep->get_queue_HCTD(0); 00297 if (td) { 00298 int len = td->getLengthTransferred(); 00299 TBUF* tbuf = (TBUF*)td->buf_top; 00300 memcpy(ep->getBufStart(), tbuf->buf, len); 00301 ep->setLengthTransferred(len); 00302 ep->setState((USB_TYPE)td->ConditionCode()); 00303 delete td; 00304 delete tbuf; 00305 return USB_TYPE_OK; 00306 } 00307 return USB_TYPE_PROCESSING; 00308 } 00309 00310 void USBHALHost::_usbisr(void) { 00311 if (instHost) { 00312 instHost->UsbIrqhandler(); 00313 } 00314 } 00315 00316 HCTD* td_reverse(HCTD* td) 00317 { 00318 HCTD* result = NULL; 00319 HCTD* next; 00320 while(td) { 00321 next = const_cast<HCTD*>(td->Next); 00322 td->Next = result; 00323 result = td; 00324 td = next; 00325 } 00326 return result; 00327 } 00328 00329 void USBHALHost::UsbIrqhandler() { 00330 if (!(LPC_USB->HcInterruptStatus & LPC_USB->HcInterruptEnable)) { 00331 return; 00332 } 00333 m_report_irq++; 00334 uint32_t status = LPC_USB->HcInterruptStatus; 00335 if (status & OR_INTR_STATUS_FNO) { 00336 m_report_FNO++; 00337 } 00338 if (status & OR_INTR_STATUS_WDH) { 00339 union { 00340 HCTD* done_td; 00341 uint32_t lsb; 00342 }; 00343 done_td = const_cast<HCTD*>(m_pHcca->DoneHead); 00344 TEST_ASSERT(done_td); 00345 m_pHcca->DoneHead = NULL; // reset 00346 if (lsb & 1) { // error ? 00347 lsb &= ~1; 00348 } 00349 HCTD* td = td_reverse(done_td); 00350 while(td) { 00351 USBEndpoint* ep = td->ep; 00352 TEST_ASSERT(ep); 00353 if (ep) { 00354 ep->irqWdhHandler(td); 00355 } 00356 td = td->Next; 00357 } 00358 m_report_WDH++; 00359 } 00360 LPC_USB->HcInterruptStatus = status; // Clear Interrrupt Status 00361 } 00362 00363 TBUF::TBUF(const void* data, int size) { 00364 if (size > 0) { 00365 memcpy(buf, data, size); 00366 } 00367 } 00368 00369 HCTD::HCTD(USBEndpoint* obj) { 00370 CTASSERT(sizeof(HCTD) == 36); 00371 TEST_ASSERT(obj); 00372 Control = TD_CC|TD_ROUNDING; 00373 CurrBufPtr = NULL; 00374 Next = NULL; 00375 BufEnd = NULL; 00376 buf_top = NULL; 00377 buf_size = 0; 00378 ep = obj; 00379 } 00380 00381 HCITD::HCITD(USBEndpoint* obj, uint16_t FrameNumber, int FrameCount, uint16_t PacketSize) { 00382 Control = 0xe0000000 | // CC ConditionCode NOT ACCESSED 00383 ((FrameCount-1) << 24)| // FC FrameCount 00384 TD_DELAY_INT(0) | // DI DelayInterrupt 00385 FrameNumber; // SF StartingFrame 00386 BufferPage0 = const_cast<uint8_t*>(buf); 00387 BufferEnd = const_cast<uint8_t*>(buf) + PacketSize * FrameCount - 1; 00388 Next = NULL; 00389 ep = obj; 00390 uint32_t addr = reinterpret_cast<uint32_t>(buf); 00391 for(int i = 0; i < FrameCount; i++) { 00392 uint16_t offset = addr & 0x0fff; 00393 if ((addr&0xfffff000) == (reinterpret_cast<uint32_t>(BufferEnd)&0xfffff000)) { 00394 offset |= 0x1000; 00395 } 00396 OffsetPSW[i] = 0xe000|offset; 00397 addr += PacketSize; 00398 } 00399 } 00400 00401 HCED::HCED(USBEndpoint* ep) { 00402 USBDeviceConnected* dev = ep->getDevice(); 00403 int devAddr = 0; 00404 bool lowSpeed = false; 00405 if (dev) { 00406 devAddr = dev->getAddress(); 00407 lowSpeed = dev->getSpeed(); 00408 } 00409 int ep_number = ep->getAddress(); 00410 int MaxPacketSize = ep->getSize(); 00411 Control = devAddr | /* USB address */ 00412 ((ep_number & 0x7F) << 7) | /* Endpoint address */ 00413 (ep_number!=0?(((ep_number&0x80)?2:1) << 11):0)| /* direction : Out = 1, 2 = In */ 00414 ((lowSpeed?1:0) << 13) | /* speed full=0 low=1 */ 00415 (MaxPacketSize << 16); /* MaxPkt Size */ 00416 TailTd = NULL; 00417 HeadTd = NULL; 00418 Next = NULL; 00419 } 00420 00421 bool HCED::enqueue(HCTD* td) { 00422 if (td) { 00423 HCTD* tail = reinterpret_cast<HCTD*>(TailTd); 00424 if (tail) { 00425 tail->Next = td; 00426 TailTd = reinterpret_cast<HCTD*>(td); 00427 return true; 00428 } 00429 } 00430 return false; 00431 } 00432 00433 void HCED::init_queue(HCTD* td) { 00434 TailTd = reinterpret_cast<HCTD*>(td); 00435 HeadTd = reinterpret_cast<HCTD*>(td); 00436 } 00437 00438 void HCCA::enqueue(HCED* ed) { 00439 for(int i = 0; i < 32; i++) { 00440 if (InterruptTable[i] == NULL) { 00441 InterruptTable[i] = ed; 00442 } else { 00443 HCED* nextEd = InterruptTable[i]; 00444 while(nextEd->Next && nextEd->Next != ed) { 00445 nextEd = nextEd->Next; 00446 } 00447 nextEd->Next = ed; 00448 } 00449 } 00450 } 00451 00452
Generated on Tue Jul 12 2022 22:44:17 by 1.7.2