Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of USBHostWANDongle by
USBHALHost.cpp
00001 /* Copyright (c) 2010-2012 mbed.org, MIT License 00002 * 00003 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 00004 * and associated documentation files (the "Software"), to deal in the Software without 00005 * restriction, including without limitation the rights to use, copy, modify, merge, publish, 00006 * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the 00007 * Software is furnished to do so, subject to the following conditions: 00008 * 00009 * The above copyright notice and this permission notice shall be included in all copies or 00010 * substantial portions of the Software. 00011 * 00012 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 00013 * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 00014 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 00015 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 00016 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 00017 */ 00018 00019 #define __DEBUG__ 0 //WARN: ENABLING DEBUGGING HERE WILL PRINTF IN IRQS!! UNEXPECTED BEHAVIOUR MAY RESULT... 00020 #ifndef __MODULE__ 00021 #define __MODULE__ "USBHALHost.cpp" 00022 #endif 00023 00024 #include "core/dbg.h" 00025 #include <cstdint> 00026 00027 #include "mbed.h" 00028 #include "USBHALHost.h" 00029 00030 // bits of the USB/OTG clock control register 00031 #define HOST_CLK_EN (1<<0) 00032 #define DEV_CLK_EN (1<<1) 00033 #define PORTSEL_CLK_EN (1<<3) 00034 #define AHB_CLK_EN (1<<4) 00035 00036 // bits of the USB/OTG clock status register 00037 #define HOST_CLK_ON (1<<0) 00038 #define DEV_CLK_ON (1<<1) 00039 #define PORTSEL_CLK_ON (1<<3) 00040 #define AHB_CLK_ON (1<<4) 00041 00042 // we need host clock, OTG/portsel clock and AHB clock 00043 #define CLOCK_MASK (HOST_CLK_EN | PORTSEL_CLK_EN | AHB_CLK_EN) 00044 00045 00046 00047 #define HCCA_SIZE 0x100 00048 #define ED_SIZE 0x10 00049 #define TD_SIZE 0x10 00050 00051 #define TOTAL_SIZE (HCCA_SIZE + (MAX_ENDPOINT*ED_SIZE) + (MAX_TD*TD_SIZE)) 00052 00053 static volatile uint8_t usb_buf[TOTAL_SIZE] __attribute((section("AHBSRAM1"),aligned(256))); //256 bytes aligned! 00054 00055 USBHALHost * USBHALHost::instHost; 00056 00057 USBHALHost::USBHALHost() : thread(USBHALHost::staticCb, (void*)this, osPriorityNormal, 4*128) { 00058 instHost = this; 00059 memInit(); 00060 memset((void*)usb_hcca, 0, HCCA_SIZE); 00061 for (int i = 0; i < MAX_ENDPOINT; i++) { 00062 edBufAlloc[i] = false; 00063 } 00064 for (int i = 0; i < MAX_TD; i++) { 00065 tdBufAlloc[i] = false; 00066 } 00067 } 00068 00069 00070 void USBHALHost::init() { 00071 thread.signal_set(USBHALHOST_SIG_INIT); 00072 } 00073 00074 00075 uint32_t USBHALHost::controlHeadED() { 00076 return LPC_USB->HcControlHeadED; 00077 } 00078 00079 uint32_t USBHALHost::bulkHeadED() { 00080 return LPC_USB->HcBulkHeadED; 00081 } 00082 00083 uint32_t USBHALHost::interruptHeadED() { 00084 return usb_hcca->IntTable[0]; 00085 } 00086 00087 void USBHALHost::updateBulkHeadED(uint32_t addr) { 00088 LPC_USB->HcBulkHeadED = addr; 00089 } 00090 00091 00092 void USBHALHost::updateControlHeadED(uint32_t addr) { 00093 LPC_USB->HcControlHeadED = addr; 00094 } 00095 00096 void USBHALHost::updateInterruptHeadED(uint32_t addr) { 00097 usb_hcca->IntTable[0] = addr; 00098 } 00099 00100 00101 void USBHALHost::enableControlList() { 00102 LPC_USB->HcCommandStatus = OR_CMD_STATUS_CLF; 00103 LPC_USB->HcControl |= OR_CONTROL_CLE; //Enable control list 00104 } 00105 00106 void USBHALHost::enableBulkList() { 00107 LPC_USB->HcCommandStatus = OR_CMD_STATUS_BLF; 00108 LPC_USB->HcControl |= OR_CONTROL_BLE; //Enable bulk list 00109 } 00110 00111 void USBHALHost::enableInterruptList() { 00112 LPC_USB->HcControl |= OR_CONTROL_PLE; 00113 } 00114 00115 bool USBHALHost::disableControlList() { 00116 if(LPC_USB->HcControl & OR_CONTROL_CLE) 00117 { 00118 LPC_USB->HcControl &= ~OR_CONTROL_CLE; //Disable control list 00119 return true; 00120 } 00121 else 00122 { 00123 return false; 00124 } 00125 } 00126 00127 bool USBHALHost::disableBulkList() { 00128 if(LPC_USB->HcControl & OR_CONTROL_BLE) 00129 { 00130 LPC_USB->HcControl &= ~OR_CONTROL_BLE; //Disable bulk list 00131 return true; 00132 } 00133 else 00134 { 00135 return false; 00136 } 00137 } 00138 00139 bool USBHALHost::disableInterruptList() { 00140 if(LPC_USB->HcControl & OR_CONTROL_PLE) 00141 { 00142 LPC_USB->HcControl &= ~OR_CONTROL_PLE; //Disable interrupt list 00143 return true; 00144 } 00145 else 00146 { 00147 return false; 00148 } 00149 } 00150 00151 //Lock processing 00152 void USBHALHost::lock() 00153 { 00154 mtx.lock(); 00155 } 00156 00157 void USBHALHost::unlock() 00158 { 00159 mtx.unlock(); 00160 } 00161 00162 void USBHALHost::memInit() { 00163 usb_hcca = (volatile HCCA *)usb_buf; 00164 usb_edBuf = usb_buf + HCCA_SIZE; 00165 usb_tdBuf = usb_buf + HCCA_SIZE + (MAX_ENDPOINT*ED_SIZE); 00166 } 00167 00168 volatile uint8_t * USBHALHost::getED() { 00169 for (int i = 0; i < MAX_ENDPOINT; i++) { 00170 if ( !edBufAlloc[i] ) { 00171 edBufAlloc[i] = true; 00172 return (volatile uint8_t *)(usb_edBuf + i*ED_SIZE); 00173 } 00174 } 00175 perror("Could not allocate ED\r\n"); 00176 return NULL; //Could not alloc ED 00177 } 00178 00179 volatile uint8_t * USBHALHost::getTD() { 00180 int i; 00181 for (i = 0; i < MAX_TD; i++) { 00182 if ( !tdBufAlloc[i] ) { 00183 tdBufAlloc[i] = true; 00184 return (volatile uint8_t *)(usb_tdBuf + i*TD_SIZE); 00185 } 00186 } 00187 perror("Could not allocate TD\r\n"); 00188 return NULL; //Could not alloc TD 00189 } 00190 00191 00192 void USBHALHost::freeED(volatile uint8_t * ed) { 00193 int i; 00194 i = (ed - usb_edBuf) / ED_SIZE; 00195 edBufAlloc[i] = false; 00196 } 00197 00198 void USBHALHost::freeTD(volatile uint8_t * td) { 00199 int i; 00200 i = (td - usb_tdBuf) / TD_SIZE; 00201 tdBufAlloc[i] = false; 00202 } 00203 00204 00205 void USBHALHost::resetPort(int hub, int port) { 00206 DBG("Resetting hub %d, port %d\n", hub, port); 00207 if (hub == 0) { //Root hub 00208 // USB 2.0 spec says at least 50ms delay before port reset 00209 Thread::wait(200); 00210 LPC_USB->HcRhPortStatus1 = OR_RH_PORT_PRS; // Initiate port reset 00211 while (LPC_USB->HcRhPortStatus1 & OR_RH_PORT_PRS); 00212 LPC_USB->HcRhPortStatus1 = OR_RH_PORT_PRSC; // ...and clear port reset signal 00213 // Wait for 100 MS after port reset 00214 Thread::wait(200); 00215 } else { 00216 //TODO: Hubs 00217 } 00218 } 00219 00220 00221 void USBHALHost::_usbisr(void) { 00222 if (instHost) { 00223 instHost->UsbIrqhandler(); 00224 } 00225 } 00226 00227 void USBHALHost::UsbIrqhandler() { 00228 if( LPC_USB->HcInterruptStatus & LPC_USB->HcInterruptEnable ) //Is there something to actually process? 00229 { 00230 NVIC_DisableIRQ(USB_IRQn); 00231 NVIC_ClearPendingIRQ(USB_IRQn); 00232 thread.signal_set(USBHALHOST_SIG_IRQ); //Signal processing thread 00233 } 00234 00235 } 00236 00237 void USBHALHost::process() 00238 { 00239 DBG("USB Process started"); 00240 00241 lock(); 00242 Thread::signal_wait(USBHALHOST_SIG_INIT); 00243 00244 NVIC_DisableIRQ(USB_IRQn); // Disable the USB interrupt source 00245 00246 LPC_SC->PCONP &= ~(1UL<<31); //Cut power 00247 Thread::wait(200); 00248 00249 // turn on power for USB 00250 LPC_SC->PCONP |= (1UL<<31); 00251 00252 // Enable USB host clock, port selection and AHB clock 00253 LPC_USB->USBClkCtrl |= CLOCK_MASK; 00254 00255 // Wait for clocks to become available 00256 while ((LPC_USB->USBClkSt & CLOCK_MASK) != CLOCK_MASK); 00257 00258 // it seems the bits[0:1] mean the following 00259 // 0: U1=device, U2=host 00260 // 1: U1=host, U2=host 00261 // 2: reserved 00262 // 3: U1=host, U2=device 00263 // NB: this register is only available if OTG clock (aka "port select") is enabled!! 00264 // since we don't care about port 2, set just bit 0 to 1 (U1=host) 00265 LPC_USB->OTGStCtrl |= 1; 00266 00267 // now that we've configured the ports, we can turn off the portsel clock 00268 LPC_USB->USBClkCtrl &= ~PORTSEL_CLK_EN; 00269 00270 // configure USB D+/D- pins 00271 // P0[29] = USB_D+, 01 00272 // P0[30] = USB_D-, 01 00273 LPC_PINCON->PINSEL1 &= ~((3<<26) | (3<<28)); 00274 LPC_PINCON->PINSEL1 |= ((1<<26)|(1<<28)); // 0x14000000 00275 00276 LPC_USB->HcControl = 0; // HARDWARE RESET 00277 LPC_USB->HcControlHeadED = 0; // Initialize Control list head to Zero 00278 LPC_USB->HcBulkHeadED = 0; // Initialize Bulk list head to Zero 00279 00280 //wait_ms(100); // Wait 50 ms before apply reset 00281 Thread::wait(100); 00282 00283 // SOFTWARE RESET 00284 LPC_USB->HcCommandStatus = OR_CMD_STATUS_HCR; 00285 LPC_USB->HcFmInterval = DEFAULT_FMINTERVAL; // Write Fm Interval and Largest Data Packet Counter 00286 LPC_USB->HcPeriodicStart = FI * 90 / 100; 00287 00288 // Put HC in operational state 00289 LPC_USB->HcControl = (LPC_USB->HcControl & (~OR_CONTROL_HCFS)) | OR_CONTROL_HC_OPER; 00290 LPC_USB->HcRhStatus = OR_RH_STATUS_LPSC; // Set Global Power 00291 00292 LPC_USB->HcHCCA = (uint32_t)(usb_hcca); 00293 LPC_USB->HcInterruptStatus |= LPC_USB->HcInterruptStatus; // Clear Interrrupt Status 00294 00295 LPC_USB->HcInterruptEnable = OR_INTR_ENABLE_MIE | OR_INTR_ENABLE_WDH | OR_INTR_ENABLE_RHSC; 00296 00297 //DG: Do not set prio 00298 //NVIC_SetPriority(USB_IRQn, 0); // highest priority 00299 // Enable the USB Interrupt 00300 NVIC_SetVector(USB_IRQn, (uint32_t)(_usbisr)); 00301 LPC_USB->HcRhPortStatus1 = OR_RH_PORT_CSC; 00302 LPC_USB->HcRhPortStatus1 = OR_RH_PORT_PRSC; 00303 00304 NVIC_EnableIRQ(USB_IRQn); 00305 00306 00307 // Check for any connected devices 00308 if (LPC_USB->HcRhPortStatus1 & OR_RH_PORT_CCS) { //Root device connected 00309 //Device connected 00310 Thread::wait(500); 00311 DBG("Device connected (%08x)\n\r", LPC_USB->HcRhPortStatus1); 00312 deviceConnected(0, 1, LPC_USB->HcRhPortStatus1 & OR_RH_PORT_LSDA); //Hub 0 (root hub), Port 1 (count starts at 1), Low or High speed 00313 } 00314 00315 unlock(); 00316 00317 00318 for(;;) 00319 { 00320 Thread::signal_wait(USBHALHOST_SIG_IRQ); //Wait for IRQ to process 00321 00322 lock(); 00323 DBG("Locked"); 00324 00325 WARN("isr %08x [EN %08x]", LPC_USB->HcInterruptStatus, LPC_USB->HcInterruptEnable); 00326 00327 //Now process IRQ 00328 uint32_t int_status = LPC_USB->HcInterruptStatus & LPC_USB->HcInterruptEnable; 00329 00330 if (int_status & OR_INTR_STATUS_RHSC) 00331 { // Root hub status change interrupt 00332 WARN("Port status %08x", LPC_USB->HcRhPortStatus1); 00333 if (LPC_USB->HcRhPortStatus1 & OR_RH_PORT_CSC) 00334 { 00335 if (LPC_USB->HcRhStatus & OR_RH_STATUS_DRWE) 00336 { 00337 00338 // When DRWE is on, Connect Status Change 00339 // means a remote wakeup event. 00340 00341 } 00342 else 00343 { 00344 00345 // When DRWE is off, Connect Status Change 00346 // is NOT a remote wakeup event 00347 00348 if (LPC_USB->HcRhPortStatus1 & OR_RH_PORT_CCS) 00349 { //Root device connected 00350 //Device connected 00351 WARN("Device connected!!"); 00352 // Thread::wait(500); 00353 deviceConnected(0, 1, LPC_USB->HcRhPortStatus1 & OR_RH_PORT_LSDA); //Hub 0 (root hub), Port 1 (count starts at 1), Low or High speed 00354 } 00355 else 00356 { //Root device disconnected 00357 //Device disconnected 00358 WARN("Device disconnected!!"); 00359 Thread::wait(500); 00360 if (!(int_status & OR_INTR_STATUS_WDH)) 00361 { 00362 usb_hcca->DoneHead = 0; 00363 } 00364 deviceDisconnected(0, 1, usb_hcca->DoneHead & 0xFFFFFFFE); 00365 if (int_status & OR_INTR_STATUS_WDH) 00366 { 00367 usb_hcca->DoneHead = 0; 00368 LPC_USB->HcInterruptStatus = OR_INTR_STATUS_WDH; 00369 } 00370 00371 } 00372 //TODO: HUBS 00373 } 00374 LPC_USB->HcRhPortStatus1 = OR_RH_PORT_CSC; 00375 } 00376 if (LPC_USB->HcRhPortStatus1 & OR_RH_PORT_PRSC) 00377 { 00378 LPC_USB->HcRhPortStatus1 = OR_RH_PORT_PRSC; 00379 //int_status &= ~OR_RH_PORT_PRSC; 00380 } 00381 LPC_USB->HcInterruptStatus = OR_INTR_STATUS_RHSC; 00382 } 00383 00384 if (int_status & OR_INTR_STATUS_WDH) 00385 { // Writeback Done Head interrupt 00386 transferCompleted(usb_hcca->DoneHead & 0xFFFFFFFE); 00387 LPC_USB->HcInterruptStatus = OR_INTR_STATUS_WDH; 00388 } 00389 00390 //IRQ Processed 00391 00392 DBG("Unlocked"); 00393 00394 NVIC_EnableIRQ(USB_IRQn); 00395 00396 unlock(); 00397 00398 } 00399 } 00400 00401 /*static*/ void USBHALHost::staticCb(void const* p) 00402 { 00403 ((USBHALHost*)p)->process(); 00404 }
Generated on Thu Jul 14 2022 09:11:27 by
1.7.2
