USB Host WAN Dongle library
Fork of USBHostWANDongle_bleedingedge 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 Tue Jul 12 2022 20:45:23 by 1.7.2