NetServices Stack source
Dependents: HelloWorld ServoInterfaceBoardExample1 4180_Lab4
UsbHostMgr.cpp
00001 00002 /* 00003 Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com) 00004 00005 Permission is hereby granted, free of charge, to any person obtaining a copy 00006 of this software and associated documentation files (the "Software"), to deal 00007 in the Software without restriction, including without limitation the rights 00008 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 00009 copies of the Software, and to permit persons to whom the Software is 00010 furnished to do so, subject to the following conditions: 00011 00012 The above copyright notice and this permission notice shall be included in 00013 all copies or substantial portions of the Software. 00014 00015 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 00016 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 00017 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 00018 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 00019 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 00020 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 00021 THE SOFTWARE. 00022 */ 00023 00024 #include "UsbHostMgr.h" 00025 00026 #include "usb_mem.h" 00027 00028 #include "string.h" //For memcpy, memmove, memset 00029 00030 #include "netCfg.h" 00031 #if NET_USB 00032 00033 //#define __DEBUG 00034 #include "dbg/dbg.h" 00035 00036 // bits of the USB/OTG clock control register 00037 #define HOST_CLK_EN (1<<0) 00038 #define DEV_CLK_EN (1<<1) 00039 #define PORTSEL_CLK_EN (1<<3) 00040 #define AHB_CLK_EN (1<<4) 00041 00042 // bits of the USB/OTG clock status register 00043 #define HOST_CLK_ON (1<<0) 00044 #define DEV_CLK_ON (1<<1) 00045 #define PORTSEL_CLK_ON (1<<3) 00046 #define AHB_CLK_ON (1<<4) 00047 00048 // we need host clock, OTG/portsel clock and AHB clock 00049 #define CLOCK_MASK (HOST_CLK_EN | PORTSEL_CLK_EN | AHB_CLK_EN) 00050 00051 static UsbHostMgr* pMgr = NULL; 00052 00053 extern "C" void sUsbIrqhandler(void) __irq 00054 { 00055 DBG("\n+Int\n"); 00056 if(pMgr) 00057 pMgr->UsbIrqhandler(); 00058 DBG("\n-Int\n"); 00059 return; 00060 } 00061 00062 UsbHostMgr::UsbHostMgr() : m_lpDevices() 00063 { 00064 /*if(!pMgr)*/ //Assume singleton 00065 pMgr = this; 00066 usb_mem_init(); 00067 memset(m_lpDevices, NULL, sizeof(UsbDevice*) * USB_HOSTMGR_MAX_DEVS); 00068 m_pHcca = (HCCA*) usb_get_hcca(); 00069 memset((void*)m_pHcca, 0, 0x100); 00070 DBG("Host manager at %p\n", this); 00071 } 00072 00073 UsbHostMgr::~UsbHostMgr() 00074 { 00075 if(pMgr == this) 00076 pMgr = NULL; 00077 } 00078 00079 UsbErr UsbHostMgr::init() //Initialize host 00080 { 00081 NVIC_DisableIRQ(USB_IRQn); /* Disable the USB interrupt source */ 00082 00083 LPC_SC->PCONP &= ~(1UL<<31); //Cut power 00084 wait(1); 00085 00086 00087 // turn on power for USB 00088 LPC_SC->PCONP |= (1UL<<31); 00089 // Enable USB host clock, port selection and AHB clock 00090 LPC_USB->USBClkCtrl |= CLOCK_MASK; 00091 // Wait for clocks to become available 00092 while ((LPC_USB->USBClkSt & CLOCK_MASK) != CLOCK_MASK) 00093 ; 00094 00095 // it seems the bits[0:1] mean the following 00096 // 0: U1=device, U2=host 00097 // 1: U1=host, U2=host 00098 // 2: reserved 00099 // 3: U1=host, U2=device 00100 // NB: this register is only available if OTG clock (aka "port select") is enabled!! 00101 // since we don't care about port 2, set just bit 0 to 1 (U1=host) 00102 LPC_USB->OTGStCtrl |= 1; 00103 00104 // now that we've configured the ports, we can turn off the portsel clock 00105 LPC_USB->USBClkCtrl &= ~PORTSEL_CLK_EN; 00106 00107 // power pins are not connected on mbed, so we can skip them 00108 /* P1[18] = USB_UP_LED, 01 */ 00109 /* P1[19] = /USB_PPWR, 10 */ 00110 /* P1[22] = USB_PWRD, 10 */ 00111 /* P1[27] = /USB_OVRCR, 10 */ 00112 /*LPC_PINCON->PINSEL3 &= ~((3<<4) | (3<<6) | (3<<12) | (3<<22)); 00113 LPC_PINCON->PINSEL3 |= ((1<<4)|(2<<6) | (2<<12) | (2<<22)); // 0x00802080 00114 */ 00115 00116 // configure USB D+/D- pins 00117 /* P0[29] = USB_D+, 01 */ 00118 /* P0[30] = USB_D-, 01 */ 00119 LPC_PINCON->PINSEL1 &= ~((3<<26) | (3<<28)); 00120 LPC_PINCON->PINSEL1 |= ((1<<26)|(1<<28)); // 0x14000000 00121 00122 DBG("Initializing Host Stack\n"); 00123 00124 wait_ms(100); /* Wait 50 ms before apply reset */ 00125 LPC_USB->HcControl = 0; /* HARDWARE RESET */ 00126 LPC_USB->HcControlHeadED = 0; /* Initialize Control list head to Zero */ 00127 LPC_USB->HcBulkHeadED = 0; /* Initialize Bulk list head to Zero */ 00128 00129 /* SOFTWARE RESET */ 00130 LPC_USB->HcCommandStatus = OR_CMD_STATUS_HCR; 00131 LPC_USB->HcFmInterval = DEFAULT_FMINTERVAL; /* Write Fm Interval and Largest Data Packet Counter */ 00132 00133 /* Put HC in operational state */ 00134 LPC_USB->HcControl = (LPC_USB->HcControl & (~OR_CONTROL_HCFS)) | OR_CONTROL_HC_OPER; 00135 LPC_USB->HcRhStatus = OR_RH_STATUS_LPSC; /* Set Global Power */ 00136 00137 LPC_USB->HcHCCA = (uint32_t)(m_pHcca); 00138 LPC_USB->HcInterruptStatus |= LPC_USB->HcInterruptStatus; /* Clear Interrrupt Status */ 00139 00140 00141 LPC_USB->HcInterruptEnable = OR_INTR_ENABLE_MIE | 00142 OR_INTR_ENABLE_WDH | 00143 OR_INTR_ENABLE_RHSC; 00144 00145 NVIC_SetPriority(USB_IRQn, 0); /* highest priority */ 00146 /* Enable the USB Interrupt */ 00147 NVIC_SetVector(USB_IRQn, (uint32_t)(sUsbIrqhandler)); 00148 LPC_USB->HcRhPortStatus1 = OR_RH_PORT_CSC; 00149 LPC_USB->HcRhPortStatus1 = OR_RH_PORT_PRSC; 00150 00151 /* Check for any connected devices */ 00152 if (LPC_USB->HcRhPortStatus1 & OR_RH_PORT_CCS) //Root device connected 00153 { 00154 //Device connected 00155 wait(1); 00156 DBG("Device connected (%08x)\n", LPC_USB->HcRhPortStatus1); 00157 onUsbDeviceConnected(0, 1); //Hub 0 (root hub), Port 1 (count starts at 1) 00158 } 00159 00160 DBG("Enabling IRQ\n"); 00161 NVIC_EnableIRQ(USB_IRQn); 00162 DBG("End of host stack initialization\n"); 00163 return USBERR_OK; 00164 } 00165 00166 void UsbHostMgr::poll() //Enumerate connected devices, etc 00167 { 00168 /* Check for any connected devices */ 00169 if (LPC_USB->HcRhPortStatus1 & OR_RH_PORT_CCS) //Root device connected 00170 { 00171 //Device connected 00172 wait(1); 00173 DBG("Device connected (%08x)\n", LPC_USB->HcRhPortStatus1); 00174 onUsbDeviceConnected(0, 1); //Hub 0 (root hub), Port 1 (count starts at 1) 00175 } 00176 00177 for(int i = 0; i < devicesCount(); i++) 00178 { 00179 if( (m_lpDevices[i]->m_connected) 00180 && !(m_lpDevices[i]->m_enumerated) ) 00181 { 00182 m_lpDevices[i]->enumerate(); 00183 return; 00184 } 00185 } 00186 } 00187 00188 int UsbHostMgr::devicesCount() 00189 { 00190 int i; 00191 for(i = 0; i < USB_HOSTMGR_MAX_DEVS; i++) 00192 { 00193 if (m_lpDevices[i] == NULL) 00194 break; 00195 } 00196 return i; 00197 } 00198 00199 UsbDevice* UsbHostMgr::getDevice(int item) 00200 { 00201 UsbDevice* pDev = m_lpDevices[item]; 00202 if(!pDev) 00203 return NULL; 00204 00205 pDev->m_refs++; 00206 return pDev; 00207 } 00208 00209 void UsbHostMgr::releaseDevice(UsbDevice* pDev) 00210 { 00211 pDev->m_refs--; 00212 if(pDev->m_refs > 0) 00213 return; 00214 //If refs count = 0, delete 00215 //Find & remove from list 00216 int i; 00217 for(i = 0; i < USB_HOSTMGR_MAX_DEVS; i++) 00218 { 00219 if (m_lpDevices[i] == pDev) 00220 break; 00221 } 00222 if(i!=USB_HOSTMGR_MAX_DEVS) 00223 memmove(&m_lpDevices[i], &m_lpDevices[i+1], sizeof(UsbDevice*) * (USB_HOSTMGR_MAX_DEVS - (i + 1))); //Safer than memcpy because of overlapping mem 00224 m_lpDevices[USB_HOSTMGR_MAX_DEVS - 1] = NULL; 00225 delete pDev; 00226 } 00227 00228 void UsbHostMgr::UsbIrqhandler() 00229 { 00230 uint32_t int_status; 00231 uint32_t ie_status; 00232 00233 int_status = LPC_USB->HcInterruptStatus; /* Read Interrupt Status */ 00234 ie_status = LPC_USB->HcInterruptEnable; /* Read Interrupt enable status */ 00235 00236 if (!(int_status & ie_status)) 00237 { 00238 return; 00239 } 00240 else 00241 { 00242 int_status = int_status & ie_status; 00243 if (int_status & OR_INTR_STATUS_RHSC) /* Root hub status change interrupt */ 00244 { 00245 DBG("LPC_USB->HcRhPortStatus1 = %08x\n", LPC_USB->HcRhPortStatus1); 00246 if (LPC_USB->HcRhPortStatus1 & OR_RH_PORT_CSC) 00247 { 00248 if (LPC_USB->HcRhStatus & OR_RH_STATUS_DRWE) 00249 { 00250 /* 00251 * When DRWE is on, Connect Status Change 00252 * means a remote wakeup event. 00253 */ 00254 //HOST_RhscIntr = 1;// JUST SOMETHING FOR A BREAKPOINT 00255 } 00256 else 00257 { 00258 /* 00259 * When DRWE is off, Connect Status Change 00260 * is NOT a remote wakeup event 00261 */ 00262 if (LPC_USB->HcRhPortStatus1 & OR_RH_PORT_CCS) //Root device connected 00263 { 00264 //Device connected 00265 DBG("Device connected (%08x)\n", LPC_USB->HcRhPortStatus1); 00266 onUsbDeviceConnected(0, 1); //Hub 0 (root hub), Port 1 (count starts at 1) 00267 } 00268 else //Root device disconnected 00269 { 00270 //Device disconnected 00271 DBG("Device disconnected\n"); 00272 onUsbDeviceDisconnected(0, 1); 00273 } 00274 //TODO: HUBS 00275 } 00276 LPC_USB->HcRhPortStatus1 = OR_RH_PORT_CSC; 00277 } 00278 if (LPC_USB->HcRhPortStatus1 & OR_RH_PORT_PRSC) 00279 { 00280 LPC_USB->HcRhPortStatus1 = OR_RH_PORT_PRSC; 00281 } 00282 } 00283 if (int_status & OR_INTR_STATUS_WDH) /* Writeback Done Head interrupt */ 00284 { 00285 //UsbEndpoint::sOnCompletion((LPC_USB->HccaDoneHead) & 0xFE); 00286 if(m_pHcca->DoneHead) 00287 { 00288 UsbEndpoint::sOnCompletion(m_pHcca->DoneHead); 00289 m_pHcca->DoneHead = 0; 00290 LPC_USB->HcInterruptStatus = OR_INTR_STATUS_WDH; 00291 if(m_pHcca->DoneHead) 00292 DBG("??????????????????????????????\n\n\n"); 00293 } 00294 else 00295 { 00296 //Probably an error 00297 int_status = LPC_USB->HcInterruptStatus; 00298 DBG("HcInterruptStatus = %08x\n", int_status); 00299 if (int_status & OR_INTR_STATUS_UE) //Unrecoverable error, disconnect devices and resume 00300 { 00301 onUsbDeviceDisconnected(0, 1); 00302 LPC_USB->HcInterruptStatus = OR_INTR_STATUS_UE; 00303 LPC_USB->HcCommandStatus = 0x01; //Host Controller Reset 00304 } 00305 } 00306 } 00307 LPC_USB->HcInterruptStatus = int_status; /* Clear interrupt status register */ 00308 } 00309 return; 00310 } 00311 00312 void UsbHostMgr::onUsbDeviceConnected(int hub, int port) 00313 { 00314 int item = devicesCount(); 00315 if( item == USB_HOSTMGR_MAX_DEVS ) 00316 return; //List full... 00317 //Find a free address (not optimized, but not really important) 00318 int i; 00319 int addr = 1; 00320 for(i = 0; i < item; i++) 00321 { 00322 addr = MAX( addr, m_lpDevices[i]->m_addr + 1 ); 00323 } 00324 m_lpDevices[item] = new UsbDevice( this, hub, port, addr ); 00325 m_lpDevices[item]->m_connected = true; 00326 } 00327 00328 void UsbHostMgr::onUsbDeviceDisconnected(int hub, int port) 00329 { 00330 for(int i = 0; i < devicesCount(); i++) 00331 { 00332 if( (m_lpDevices[i]->m_hub == hub) 00333 && (m_lpDevices[i]->m_port == port) ) 00334 { 00335 m_lpDevices[i]->m_connected = false; 00336 if(!m_lpDevices[i]->m_enumerated) 00337 { 00338 delete m_lpDevices[i]; 00339 m_lpDevices[i] = NULL; 00340 } 00341 return; 00342 } 00343 } 00344 } 00345 00346 void UsbHostMgr::resetPort(int hub, int port) 00347 { 00348 DBG("Resetting hub %d, port %d\n", hub, port); 00349 if(hub == 0) //Root hub 00350 { 00351 wait_ms(100); /* USB 2.0 spec says at least 50ms delay before port reset */ 00352 LPC_USB->HcRhPortStatus1 = OR_RH_PORT_PRS; // Initiate port reset 00353 DBG("Before loop\n"); 00354 while (LPC_USB->HcRhPortStatus1 & OR_RH_PORT_PRS) 00355 ; 00356 LPC_USB->HcRhPortStatus1 = OR_RH_PORT_PRSC; // ...and clear port reset signal 00357 DBG("After loop\n"); 00358 wait_ms(200); /* Wait for 100 MS after port reset */ 00359 } 00360 else 00361 { 00362 //TODO: Hubs 00363 } 00364 DBG("Port reset OK\n"); 00365 } 00366 00367 #endif
Generated on Tue Jul 12 2022 11:52:59 by
![doxygen](doxygen.png)