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 uvchost by
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 #include "UsbHostMgr.h" 00024 #include "usb_mem.h" 00025 #include "string.h" //For memcpy, memmove, memset 00026 //#define __DEBUG 00027 //#define __DEBUG3 00028 //#include "dbg/dbg.h" 00029 #include "mydbg.h" 00030 00031 // bits of the USB/OTG clock control register 00032 #define HOST_CLK_EN (1<<0) 00033 #define DEV_CLK_EN (1<<1) 00034 #define PORTSEL_CLK_EN (1<<3) 00035 #define AHB_CLK_EN (1<<4) 00036 00037 // bits of the USB/OTG clock status register 00038 #define HOST_CLK_ON (1<<0) 00039 #define DEV_CLK_ON (1<<1) 00040 #define PORTSEL_CLK_ON (1<<3) 00041 #define AHB_CLK_ON (1<<4) 00042 00043 // we need host clock, OTG/portsel clock and AHB clock 00044 #define CLOCK_MASK (HOST_CLK_EN | PORTSEL_CLK_EN | AHB_CLK_EN) 00045 00046 static UsbHostMgr* pMgr = NULL; 00047 00048 extern "C" void sUsbIrqhandler(void) __irq 00049 { 00050 DBG("\n+Int\n"); 00051 if(pMgr) 00052 pMgr->UsbIrqhandler(); 00053 DBG("\n-Int\n"); 00054 return; 00055 } 00056 00057 UsbHostMgr::UsbHostMgr() : m_lpDevices() 00058 { 00059 /*if(!pMgr)*/ //Assume singleton 00060 pMgr = this; 00061 usb_mem_init(); 00062 for(int i = 0; i < USB_HOSTMGR_MAX_DEVS; i++) { 00063 m_lpDevices[i] = NULL; 00064 } 00065 m_pHcca = (HCCA*) usb_get_hcca(); 00066 memset((void*)m_pHcca, 0, 0x100); 00067 m_hardware_init = false; 00068 DBG("Host manager at %p\n", this); 00069 } 00070 00071 UsbHostMgr::~UsbHostMgr() 00072 { 00073 if(pMgr == this) 00074 pMgr = NULL; 00075 } 00076 00077 UsbErr UsbHostMgr::init() //Initialize host 00078 { 00079 DBG("m_hardware_init=%d\n", m_hardware_init); 00080 if(m_hardware_init) { 00081 return USBERR_OK; 00082 } 00083 00084 NVIC_DisableIRQ(USB_IRQn); /* Disable the USB interrupt source */ 00085 00086 LPC_SC->PCONP &= ~(1UL<<31); //Cut power 00087 wait(1); 00088 00089 00090 // turn on power for USB 00091 LPC_SC->PCONP |= (1UL<<31); 00092 // Enable USB host clock, port selection and AHB clock 00093 LPC_USB->USBClkCtrl |= CLOCK_MASK; 00094 // Wait for clocks to become available 00095 while ((LPC_USB->USBClkSt & CLOCK_MASK) != CLOCK_MASK) 00096 ; 00097 00098 // it seems the bits[0:1] mean the following 00099 // 0: U1=device, U2=host 00100 // 1: U1=host, U2=host 00101 // 2: reserved 00102 // 3: U1=host, U2=device 00103 // NB: this register is only available if OTG clock (aka "port select") is enabled!! 00104 // since we don't care about port 2, set just bit 0 to 1 (U1=host) 00105 LPC_USB->OTGStCtrl |= 1; 00106 00107 // now that we've configured the ports, we can turn off the portsel clock 00108 LPC_USB->USBClkCtrl &= ~PORTSEL_CLK_EN; 00109 00110 // power pins are not connected on mbed, so we can skip them 00111 /* P1[18] = USB_UP_LED, 01 */ 00112 /* P1[19] = /USB_PPWR, 10 */ 00113 /* P1[22] = USB_PWRD, 10 */ 00114 /* P1[27] = /USB_OVRCR, 10 */ 00115 /*LPC_PINCON->PINSEL3 &= ~((3<<4) | (3<<6) | (3<<12) | (3<<22)); 00116 LPC_PINCON->PINSEL3 |= ((1<<4)|(2<<6) | (2<<12) | (2<<22)); // 0x00802080 00117 */ 00118 00119 // configure USB D+/D- pins 00120 /* P0[29] = USB_D+, 01 */ 00121 /* P0[30] = USB_D-, 01 */ 00122 LPC_PINCON->PINSEL1 &= ~((3<<26) | (3<<28)); 00123 LPC_PINCON->PINSEL1 |= ((1<<26)|(1<<28)); // 0x14000000 00124 00125 DBG("Initializing Host Stack\n"); 00126 00127 wait_ms(100); /* Wait 50 ms before apply reset */ 00128 LPC_USB->HcControl = 0; /* HARDWARE RESET */ 00129 LPC_USB->HcControlHeadED = 0; /* Initialize Control list head to Zero */ 00130 LPC_USB->HcBulkHeadED = 0; /* Initialize Bulk list head to Zero */ 00131 00132 /* SOFTWARE RESET */ 00133 LPC_USB->HcCommandStatus = OR_CMD_STATUS_HCR; 00134 LPC_USB->HcFmInterval = DEFAULT_FMINTERVAL; /* Write Fm Interval and Largest Data Packet Counter */ 00135 LPC_USB->HcPeriodicStart = FI*90/100; 00136 00137 /* Put HC in operational state */ 00138 LPC_USB->HcControl = (LPC_USB->HcControl & (~OR_CONTROL_HCFS)) | OR_CONTROL_HC_OPER; 00139 LPC_USB->HcRhStatus = OR_RH_STATUS_LPSC; /* Set Global Power */ 00140 00141 LPC_USB->HcHCCA = (uint32_t)(m_pHcca); 00142 LPC_USB->HcInterruptStatus |= LPC_USB->HcInterruptStatus; /* Clear Interrrupt Status */ 00143 00144 00145 LPC_USB->HcInterruptEnable = OR_INTR_ENABLE_MIE | 00146 OR_INTR_ENABLE_WDH | 00147 OR_INTR_ENABLE_RHSC; 00148 00149 NVIC_SetPriority(USB_IRQn, 0); /* highest priority */ 00150 /* Enable the USB Interrupt */ 00151 NVIC_SetVector(USB_IRQn, (uint32_t)(sUsbIrqhandler)); 00152 LPC_USB->HcRhPortStatus1 = OR_RH_PORT_CSC; 00153 LPC_USB->HcRhPortStatus1 = OR_RH_PORT_PRSC; 00154 00155 00156 /* Check for any connected devices */ 00157 //if (LPC_USB->HcRhPortStatus1 & OR_RH_PORT_CCS) //Root device connected 00158 //{ 00159 // //Device connected 00160 // wait(1); 00161 // DBG("Device connected (%08x)\n", LPC_USB->HcRhPortStatus1); 00162 // onUsbDeviceConnected(0, 1); //Hub 0 (root hub), Port 1 (count starts at 1) 00163 //} 00164 00165 DBG("Enabling IRQ\n"); 00166 NVIC_EnableIRQ(USB_IRQn); 00167 DBG("End of host stack initialization\n"); 00168 m_hardware_init = true; 00169 return USBERR_OK; 00170 } 00171 00172 UsbErr UsbHostMgr::poll() //Enumerate connected devices, etc 00173 { 00174 /* Check for any connected devices */ 00175 if (LPC_USB->HcRhPortStatus1 & OR_RH_PORT_CCS) //Root device connected 00176 { 00177 //Device connected 00178 wait(1); 00179 DBG("Device connected (%08x)\n", LPC_USB->HcRhPortStatus1); 00180 bool lowspeed = false; 00181 if (LPC_USB->HcRhPortStatus1 & 0x0200) { // lowspeed? 00182 lowspeed = true; 00183 } 00184 onUsbDeviceConnected(0, 1, lowspeed); //Hub 0 (root hub), Port 1 (count starts at 1) 00185 } 00186 00187 for(int i = 0; i < USB_HOSTMGR_MAX_DEVS; i++) 00188 { 00189 UsbDevice* dev = m_lpDevices[i]; 00190 if (dev == NULL) { 00191 continue; 00192 } 00193 DBG3("%d dev=%p %d %d addr=%d\n", i, dev, dev->m_connected, dev->m_enumerated, dev->m_addr); 00194 if(dev->m_connected) { 00195 if (!dev->m_enumerated) { 00196 dev->enumerate(); 00197 return USBERR_PROCESSING; 00198 } 00199 } 00200 } 00201 for(int i = 0; i < USB_HOSTMGR_MAX_DEVS; i++) { 00202 UsbDevice* dev = m_lpDevices[i]; 00203 if (dev == NULL) { 00204 continue; 00205 } 00206 if (dev->m_connected && dev->m_enumerated) { 00207 if (dev->m_DeviceClass == 0x09) { // HUB 00208 UsbErr rc = dev->hub_poll(); 00209 if (rc == USBERR_PROCESSING) { 00210 return USBERR_PROCESSING; 00211 } 00212 } 00213 } 00214 } 00215 return USBERR_OK; 00216 } 00217 00218 int UsbHostMgr::devicesCount() 00219 { 00220 int i; 00221 for(i = 0; i < USB_HOSTMGR_MAX_DEVS; i++) 00222 { 00223 if (m_lpDevices[i] == NULL) { 00224 return i; 00225 } 00226 } 00227 return i; 00228 } 00229 00230 UsbDevice* UsbHostMgr::getDevice(int item) 00231 { 00232 UsbDevice* pDev = m_lpDevices[item]; 00233 if(!pDev) 00234 return NULL; 00235 00236 pDev->m_refs++; 00237 return pDev; 00238 } 00239 00240 void UsbHostMgr::releaseDevice(UsbDevice* pDev) 00241 { 00242 pDev->m_refs--; 00243 if(pDev->m_refs > 0) 00244 return; 00245 //If refs count = 0, delete 00246 //Find & remove from list 00247 int i; 00248 for(i = 0; i < USB_HOSTMGR_MAX_DEVS; i++) 00249 { 00250 if (m_lpDevices[i] == pDev) 00251 break; 00252 } 00253 if(i!=USB_HOSTMGR_MAX_DEVS) 00254 memmove(&m_lpDevices[i], &m_lpDevices[i+1], sizeof(UsbDevice*) * (USB_HOSTMGR_MAX_DEVS - (i + 1))); //Safer than memcpy because of overlapping mem 00255 m_lpDevices[USB_HOSTMGR_MAX_DEVS - 1] = NULL; 00256 delete pDev; 00257 } 00258 00259 void UsbHostMgr::UsbIrqhandler() 00260 { 00261 uint32_t int_status; 00262 uint32_t ie_status; 00263 00264 int_status = LPC_USB->HcInterruptStatus; /* Read Interrupt Status */ 00265 ie_status = LPC_USB->HcInterruptEnable; /* Read Interrupt enable status */ 00266 00267 if (!(int_status & ie_status)) 00268 { 00269 return; 00270 } 00271 else 00272 { 00273 int_status = int_status & ie_status; 00274 if (int_status & OR_INTR_STATUS_RHSC) /* Root hub status change interrupt */ 00275 { 00276 DBG("LPC_USB->HcRhPortStatus1 = %08x\n", LPC_USB->HcRhPortStatus1); 00277 if (LPC_USB->HcRhPortStatus1 & OR_RH_PORT_CSC) 00278 { 00279 if (LPC_USB->HcRhStatus & OR_RH_STATUS_DRWE) 00280 { 00281 /* 00282 * When DRWE is on, Connect Status Change 00283 * means a remote wakeup event. 00284 */ 00285 //HOST_RhscIntr = 1;// JUST SOMETHING FOR A BREAKPOINT 00286 } 00287 else 00288 { 00289 /* 00290 * When DRWE is off, Connect Status Change 00291 * is NOT a remote wakeup event 00292 */ 00293 if (LPC_USB->HcRhPortStatus1 & OR_RH_PORT_CCS) //Root device connected 00294 { 00295 //Device connected 00296 DBG("Device connected (%08x)\n", LPC_USB->HcRhPortStatus1); 00297 onUsbDeviceConnected(0, 1); //Hub 0 (root hub), Port 1 (count starts at 1) 00298 } 00299 else //Root device disconnected 00300 { 00301 //Device disconnected 00302 DBG("Device disconnected\n"); 00303 onUsbDeviceDisconnected(0, 1); 00304 } 00305 //TODO: HUBS 00306 } 00307 LPC_USB->HcRhPortStatus1 = OR_RH_PORT_CSC; 00308 } 00309 if (LPC_USB->HcRhPortStatus1 & OR_RH_PORT_PRSC) 00310 { 00311 LPC_USB->HcRhPortStatus1 = OR_RH_PORT_PRSC; 00312 } 00313 } 00314 if (int_status & OR_INTR_STATUS_WDH) /* Writeback Done Head interrupt */ 00315 { 00316 //UsbEndpoint::sOnCompletion((LPC_USB->HccaDoneHead) & 0xFE); 00317 if(m_pHcca->DoneHead) 00318 { 00319 UsbEndpoint::sOnCompletion(m_pHcca->DoneHead); 00320 m_pHcca->DoneHead = 0; 00321 LPC_USB->HcInterruptStatus = OR_INTR_STATUS_WDH; 00322 if(m_pHcca->DoneHead) 00323 DBG("??????????????????????????????\n\n\n"); 00324 } 00325 else 00326 { 00327 //Probably an error 00328 int_status = LPC_USB->HcInterruptStatus; 00329 DBG("HcInterruptStatus = %08x\n", int_status); 00330 if (int_status & OR_INTR_STATUS_UE) //Unrecoverable error, disconnect devices and resume 00331 { 00332 onUsbDeviceDisconnected(0, 1); 00333 LPC_USB->HcInterruptStatus = OR_INTR_STATUS_UE; 00334 LPC_USB->HcCommandStatus = 0x01; //Host Controller Reset 00335 } 00336 } 00337 } 00338 LPC_USB->HcInterruptStatus = int_status; /* Clear interrupt status register */ 00339 } 00340 return; 00341 } 00342 00343 void UsbHostMgr::onUsbDeviceDisconnected(int hub, int port) 00344 { 00345 for(int i = 0; i < devicesCount(); i++) 00346 { 00347 if( (m_lpDevices[i]->m_hub == hub) 00348 && (m_lpDevices[i]->m_port == port) ) 00349 { 00350 m_lpDevices[i]->m_connected = false; 00351 if(!m_lpDevices[i]->m_enumerated) 00352 { 00353 delete m_lpDevices[i]; 00354 m_lpDevices[i] = NULL; 00355 } 00356 return; 00357 } 00358 } 00359 } 00360 00361 void UsbHostMgr::resetPort(int hub, int port) 00362 { 00363 DBG3("hub=%d port=%d\n", hub, port); 00364 if(hub == 0) //Root hub 00365 { 00366 wait_ms(100); /* USB 2.0 spec says at least 50ms delay before port reset */ 00367 LPC_USB->HcRhPortStatus1 = OR_RH_PORT_PRS; // Initiate port reset 00368 DBG("Before loop\n"); 00369 while (LPC_USB->HcRhPortStatus1 & OR_RH_PORT_PRS) 00370 ; 00371 LPC_USB->HcRhPortStatus1 = OR_RH_PORT_PRSC; // ...and clear port reset signal 00372 DBG("After loop\n"); 00373 wait_ms(200); /* Wait for 100 MS after port reset */ 00374 } 00375 else 00376 { 00377 for(int i = 0; i < USB_HOSTMGR_MAX_DEVS; i++) { 00378 UsbDevice* dev = m_lpDevices[i]; 00379 if (dev == NULL) { 00380 continue; 00381 } 00382 if (dev->m_addr == hub) { 00383 DBG("%d dev=%p\n", i, dev); 00384 dev->hub_PortReset(port); 00385 return; 00386 } 00387 } 00388 DBG_ASSERT(0); 00389 } 00390 }
Generated on Wed Jul 13 2022 01:34:55 by
1.7.2
