ST/USBHOST forked to add another HID handler for raw keyboard data to get more detail not available with current handlers (all pressed keys, all releases, and periodic updates)
Dependents: C64-stm429_discovery
USBHALHost_M451.cpp
00001 /* mbed Microcontroller Library 00002 * Copyright (c) 2015-2016 Nuvoton 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 #if defined(TARGET_M451) 00018 00019 #include "mbed.h" 00020 #include "USBHALHost.h" 00021 #include "dbg.h" 00022 #include "pinmap.h" 00023 00024 #define HCCA_SIZE sizeof(HCCA) 00025 #define ED_SIZE sizeof(HCED) 00026 #define TD_SIZE sizeof(HCTD) 00027 00028 #define TOTAL_SIZE (HCCA_SIZE + (MAX_ENDPOINT*ED_SIZE) + (MAX_TD*TD_SIZE)) 00029 00030 #ifndef USBH_HcRhDescriptorA_POTPGT_Pos 00031 #define USBH_HcRhDescriptorA_POTPGT_Pos (24) 00032 #endif 00033 #ifndef USBH_HcRhDescriptorA_POTPGT_Msk 00034 #define USBH_HcRhDescriptorA_POTPGT_Msk (0xfful << USBH_HcRhDescriptorA_POTPGT_Pos) 00035 #endif 00036 00037 static volatile MBED_ALIGN(256) uint8_t usb_buf[TOTAL_SIZE]; // 256 bytes aligned! 00038 00039 USBHALHost * USBHALHost::instHost; 00040 00041 USBHALHost::USBHALHost() 00042 { 00043 instHost = this; 00044 memInit(); 00045 memset((void*)usb_hcca, 0, HCCA_SIZE); 00046 for (int i = 0; i < MAX_ENDPOINT; i++) { 00047 edBufAlloc[i] = false; 00048 } 00049 for (int i = 0; i < MAX_TD; i++) { 00050 tdBufAlloc[i] = false; 00051 } 00052 } 00053 00054 void USBHALHost::init() 00055 { 00056 // Unlock protected registers 00057 SYS_UnlockReg(); 00058 00059 // Enable USBH clock 00060 CLK_EnableModuleClock(USBH_MODULE); 00061 // Set USBH clock source/divider 00062 CLK_SetModuleClock(USBH_MODULE, 0, CLK_CLKDIV0_USB(3)); 00063 00064 // Configure OTG function as Host-Only 00065 SYS->USBPHY = SYS_USBPHY_LDO33EN_Msk | SYS_USBPHY_USBROLE_STD_USBH; 00066 00067 /* Below settings is use power switch IC to enable/disable USB Host power. 00068 Set PA.2 is VBUS_EN function pin and PA.3 VBUS_ST function pin */ 00069 pin_function(PA_3, SYS_GPA_MFPL_PA3MFP_USB_VBUS_ST); 00070 pin_function(PA_2, SYS_GPA_MFPL_PA2MFP_USB_VBUS_EN); 00071 00072 // Enable OTG clock 00073 CLK_EnableModuleClock(OTG_MODULE); 00074 00075 // Lock protected registers 00076 SYS_LockReg(); 00077 00078 // Overcurrent flag is low active 00079 USBH->HcMiscControl |= USBH_HcMiscControl_OCAL_Msk; 00080 00081 // Disable HC interrupts 00082 USBH->HcInterruptDisable = OR_INTR_ENABLE_MIE; 00083 00084 // Needed by some controllers 00085 USBH->HcControl = 0; 00086 00087 // Software reset 00088 USBH->HcCommandStatus = OR_CMD_STATUS_HCR; 00089 while (USBH->HcCommandStatus & OR_CMD_STATUS_HCR); 00090 00091 // Put HC in reset state 00092 USBH->HcControl = (USBH->HcControl & ~OR_CONTROL_HCFS) | OR_CONTROL_HC_RSET; 00093 // HCD must wait 10ms for HC reset complete 00094 wait_ms(100); 00095 00096 USBH->HcControlHeadED = 0; // Initialize Control ED list head to 0 00097 USBH->HcBulkHeadED = 0; // Initialize Bulk ED list head to 0 00098 USBH->HcHCCA = (uint32_t) usb_hcca; 00099 00100 USBH->HcFmInterval = DEFAULT_FMINTERVAL; // Frame interval = 12000 - 1 00101 // MPS = 10,104 00102 USBH->HcPeriodicStart = FI * 90 / 100; // 90% of frame interval 00103 USBH->HcLSThreshold = 0x628; // Low speed threshold 00104 00105 // Put HC in operational state 00106 USBH->HcControl = (USBH->HcControl & (~OR_CONTROL_HCFS)) | OR_CONTROL_HC_OPER; 00107 00108 // FIXME 00109 USBH->HcRhDescriptorA = USBH->HcRhDescriptorA & ~(USBH_HcRhDescriptorA_NOCP_Msk | USBH_HcRhDescriptorA_OCPM_Msk | USBH_HcRhDescriptorA_PSM_Msk); 00110 // Issue SetGlobalPower command 00111 USBH->HcRhStatus = USBH_HcRhStatus_LPSC_Msk; 00112 // Power On To Power Good Time, in 2 ms units 00113 wait_ms(((USBH->HcRhDescriptorA & USBH_HcRhDescriptorA_POTPGT_Msk) >> USBH_HcRhDescriptorA_POTPGT_Pos) * 2); 00114 00115 // Clear Interrrupt Status 00116 USBH->HcInterruptStatus |= USBH->HcInterruptStatus; 00117 // Enable interrupts we care about 00118 USBH->HcInterruptEnable = OR_INTR_ENABLE_MIE | OR_INTR_ENABLE_WDH | OR_INTR_ENABLE_RHSC; 00119 00120 NVIC_SetVector(USBH_IRQn, (uint32_t)(_usbisr)); 00121 NVIC_EnableIRQ(USBH_IRQn); 00122 00123 // Check for any connected devices 00124 if (USBH->HcRhPortStatus[0] & OR_RH_PORT_CCS) { 00125 // Device connected 00126 wait_ms(150); 00127 deviceConnected(0, 1, USBH->HcRhPortStatus[0] & OR_RH_PORT_LSDA); 00128 } 00129 } 00130 00131 uint32_t USBHALHost::controlHeadED() 00132 { 00133 return USBH->HcControlHeadED; 00134 } 00135 00136 uint32_t USBHALHost::bulkHeadED() 00137 { 00138 return USBH->HcBulkHeadED; 00139 } 00140 00141 uint32_t USBHALHost::interruptHeadED() 00142 { 00143 // FIXME: Only support one INT ED? 00144 return usb_hcca->IntTable[0]; 00145 } 00146 00147 void USBHALHost::updateBulkHeadED(uint32_t addr) 00148 { 00149 USBH->HcBulkHeadED = addr; 00150 } 00151 00152 00153 void USBHALHost::updateControlHeadED(uint32_t addr) 00154 { 00155 USBH->HcControlHeadED = addr; 00156 } 00157 00158 void USBHALHost::updateInterruptHeadED(uint32_t addr) 00159 { 00160 // FIXME: Only support one INT ED? 00161 usb_hcca->IntTable[0] = addr; 00162 } 00163 00164 00165 void USBHALHost::enableList(ENDPOINT_TYPE type) 00166 { 00167 switch(type) { 00168 case CONTROL_ENDPOINT: 00169 USBH->HcCommandStatus = OR_CMD_STATUS_CLF; 00170 USBH->HcControl |= OR_CONTROL_CLE; 00171 break; 00172 case ISOCHRONOUS_ENDPOINT: 00173 // FIXME 00174 break; 00175 case BULK_ENDPOINT: 00176 USBH->HcCommandStatus = OR_CMD_STATUS_BLF; 00177 USBH->HcControl |= OR_CONTROL_BLE; 00178 break; 00179 case INTERRUPT_ENDPOINT: 00180 USBH->HcControl |= OR_CONTROL_PLE; 00181 break; 00182 } 00183 } 00184 00185 00186 bool USBHALHost::disableList(ENDPOINT_TYPE type) 00187 { 00188 switch(type) { 00189 case CONTROL_ENDPOINT: 00190 if(USBH->HcControl & OR_CONTROL_CLE) { 00191 USBH->HcControl &= ~OR_CONTROL_CLE; 00192 return true; 00193 } 00194 return false; 00195 case ISOCHRONOUS_ENDPOINT: 00196 // FIXME 00197 return false; 00198 case BULK_ENDPOINT: 00199 if(USBH->HcControl & OR_CONTROL_BLE){ 00200 USBH->HcControl &= ~OR_CONTROL_BLE; 00201 return true; 00202 } 00203 return false; 00204 case INTERRUPT_ENDPOINT: 00205 if(USBH->HcControl & OR_CONTROL_PLE) { 00206 USBH->HcControl &= ~OR_CONTROL_PLE; 00207 return true; 00208 } 00209 return false; 00210 } 00211 return false; 00212 } 00213 00214 00215 void USBHALHost::memInit() 00216 { 00217 usb_hcca = (volatile HCCA *)usb_buf; 00218 usb_edBuf = usb_buf + HCCA_SIZE; 00219 usb_tdBuf = usb_buf + HCCA_SIZE + (MAX_ENDPOINT*ED_SIZE); 00220 } 00221 00222 volatile uint8_t * USBHALHost::getED() 00223 { 00224 for (int i = 0; i < MAX_ENDPOINT; i++) { 00225 if ( !edBufAlloc[i] ) { 00226 edBufAlloc[i] = true; 00227 return (volatile uint8_t *)(usb_edBuf + i*ED_SIZE); 00228 } 00229 } 00230 perror("Could not allocate ED\r\n"); 00231 return NULL; //Could not alloc ED 00232 } 00233 00234 volatile uint8_t * USBHALHost::getTD() 00235 { 00236 int i; 00237 for (i = 0; i < MAX_TD; i++) { 00238 if ( !tdBufAlloc[i] ) { 00239 tdBufAlloc[i] = true; 00240 return (volatile uint8_t *)(usb_tdBuf + i*TD_SIZE); 00241 } 00242 } 00243 perror("Could not allocate TD\r\n"); 00244 return NULL; //Could not alloc TD 00245 } 00246 00247 00248 void USBHALHost::freeED(volatile uint8_t * ed) 00249 { 00250 int i; 00251 i = (ed - usb_edBuf) / ED_SIZE; 00252 edBufAlloc[i] = false; 00253 } 00254 00255 void USBHALHost::freeTD(volatile uint8_t * td) 00256 { 00257 int i; 00258 i = (td - usb_tdBuf) / TD_SIZE; 00259 tdBufAlloc[i] = false; 00260 } 00261 00262 00263 void USBHALHost::resetRootHub() 00264 { 00265 // Reset port1 00266 USBH->HcRhPortStatus[0] = OR_RH_PORT_PRS; 00267 while (USBH->HcRhPortStatus[0] & OR_RH_PORT_PRS); 00268 USBH->HcRhPortStatus[0] = OR_RH_PORT_PRSC; 00269 } 00270 00271 00272 void USBHALHost::_usbisr(void) 00273 { 00274 if (instHost) { 00275 instHost->UsbIrqhandler(); 00276 } 00277 } 00278 00279 void USBHALHost::UsbIrqhandler() 00280 { 00281 uint32_t ints = USBH->HcInterruptStatus; 00282 00283 // Root hub status change interrupt 00284 if (ints & OR_INTR_STATUS_RHSC) { 00285 uint32_t ints_roothub = USBH->HcRhStatus; 00286 uint32_t ints_port1 = USBH->HcRhPortStatus[0]; 00287 uint32_t ints_port2 = USBH->HcRhPortStatus[1]; 00288 00289 // Port1: ConnectStatusChange 00290 if (ints_port1 & OR_RH_PORT_CSC) { 00291 if (ints_roothub & OR_RH_STATUS_DRWE) { 00292 // When DRWE is on, Connect Status Change means a remote wakeup event. 00293 } else { 00294 if (ints_port1 & OR_RH_PORT_CCS) { 00295 // Root device connected 00296 00297 // wait 150ms to avoid bounce 00298 wait_ms(150); 00299 00300 //Hub 0 (root hub), Port 1 (count starts at 1), Low or High speed 00301 deviceConnected(0, 1, ints_port1 & OR_RH_PORT_LSDA); 00302 } else { 00303 // Root device disconnected 00304 00305 if (!(ints & OR_INTR_STATUS_WDH)) { 00306 usb_hcca->DoneHead = 0; 00307 } 00308 00309 // wait 200ms to avoid bounce 00310 wait_ms(200); 00311 00312 deviceDisconnected(0, 1, NULL, usb_hcca->DoneHead & 0xFFFFFFFE); 00313 00314 if (ints & OR_INTR_STATUS_WDH) { 00315 usb_hcca->DoneHead = 0; 00316 USBH->HcInterruptStatus = OR_INTR_STATUS_WDH; 00317 } 00318 } 00319 } 00320 USBH->HcRhPortStatus[0] = OR_RH_PORT_CSC; 00321 } 00322 // Port1: Reset completed 00323 if (ints_port1 & OR_RH_PORT_PRSC) { 00324 USBH->HcRhPortStatus[0] = OR_RH_PORT_PRSC; 00325 } 00326 // Port1: PortEnableStatusChange 00327 if (ints_port1 & OR_RH_PORT_PESC) { 00328 USBH->HcRhPortStatus[0] = OR_RH_PORT_PESC; 00329 } 00330 00331 // Port2: PortOverCurrentIndicatorChange 00332 if (ints_port2 & OR_RH_PORT_OCIC) { 00333 USBH->HcRhPortStatus[1] = OR_RH_PORT_OCIC; 00334 } 00335 00336 USBH->HcInterruptStatus = OR_INTR_STATUS_RHSC; 00337 } 00338 00339 // Writeback Done Head interrupt 00340 if (ints & OR_INTR_STATUS_WDH) { 00341 transferCompleted(usb_hcca->DoneHead & 0xFFFFFFFE); 00342 USBH->HcInterruptStatus = OR_INTR_STATUS_WDH; 00343 } 00344 00345 00346 } 00347 #endif
Generated on Sat Jul 16 2022 02:45:31 by 1.7.2