USB device stack
Dependents: blinky_max32630fthr FTHR_USB_serial FTHR_OLED HSP_RPC_GUI_3_0_1 ... more
Fork of USBDevice by
USBHAL_Maxim.cpp
00001 /******************************************************************************* 00002 * Copyright (C) 2016 Maxim Integrated Products, Inc., All Rights Reserved. 00003 * 00004 * Permission is hereby granted, free of charge, to any person obtaining a 00005 * copy of this software and associated documentation files (the "Software"), 00006 * to deal in the Software without restriction, including without limitation 00007 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 00008 * and/or sell copies of the Software, and to permit persons to whom the 00009 * Software is furnished to do so, subject to the following conditions: 00010 * 00011 * The above copyright notice and this permission notice shall be included 00012 * in all copies or substantial portions of the Software. 00013 * 00014 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 00015 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 00016 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 00017 * IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES 00018 * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 00019 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 00020 * OTHER DEALINGS IN THE SOFTWARE. 00021 * 00022 * Except as contained in this notice, the name of Maxim Integrated 00023 * Products, Inc. shall not be used except as stated in the Maxim Integrated 00024 * Products, Inc. Branding Policy. 00025 * 00026 * The mere transfer of this software does not imply any licenses 00027 * of trade secrets, proprietary technology, copyrights, patents, 00028 * trademarks, maskwork rights, or any other form of intellectual 00029 * property whatsoever. Maxim Integrated Products, Inc. retains all 00030 * ownership rights. 00031 ******************************************************************************* 00032 */ 00033 00034 #if defined(TARGET_Maxim) 00035 00036 #include "USBHAL.h" 00037 #include "usb_regs.h" 00038 #include "clkman_regs.h" 00039 00040 #if defined(TARGET_MAX32625) || defined(TARGET_MAX32630) 00041 #include "pwrman_regs.h" 00042 #endif 00043 00044 #define CONNECT_INTS (MXC_F_USB_DEV_INTEN_BRST | MXC_F_USB_DEV_INTEN_SETUP | MXC_F_USB_DEV_INTEN_EP_IN | MXC_F_USB_DEV_INTEN_EP_OUT | MXC_F_USB_DEV_INTEN_DMA_ERR) 00045 00046 USBHAL *USBHAL::instance; 00047 00048 typedef struct { 00049 volatile uint32_t buf0_desc; 00050 volatile uint32_t buf0_address; 00051 volatile uint32_t buf1_desc; 00052 volatile uint32_t buf1_address; 00053 } ep_buffer_t; 00054 00055 typedef struct { 00056 ep_buffer_t out_buffer; 00057 ep_buffer_t in_buffer; 00058 } ep0_buffer_t; 00059 00060 typedef struct { 00061 ep0_buffer_t ep0; 00062 ep_buffer_t ep[MXC_USB_NUM_EP - 1]; 00063 } ep_buffer_descriptor_t; 00064 00065 // Static storage for endpoint buffer descriptor table. Must be 512 byte aligned for DMA. 00066 #ifdef __IAR_SYSTEMS_ICC__ 00067 #pragma data_alignment = 512 00068 #else 00069 __attribute__ ((aligned (512))) 00070 #endif 00071 ep_buffer_descriptor_t ep_buffer_descriptor; 00072 00073 // static storage for temporary data buffers. Must be 32 byte aligned. 00074 #ifdef __IAR_SYSTEMS_ICC__ 00075 #pragma data_alignment = 4 00076 #else 00077 __attribute__ ((aligned (4))) 00078 #endif 00079 static uint8_t aligned_buffer[NUMBER_OF_LOGICAL_ENDPOINTS][MXC_USB_MAX_PACKET]; 00080 00081 // control packet state 00082 static enum { 00083 CTRL_NONE = 0, 00084 CTRL_SETUP, 00085 CTRL_OUT, 00086 CTRL_IN, 00087 } control_state; 00088 00089 USBHAL::USBHAL(void) 00090 { 00091 NVIC_DisableIRQ(USB_IRQn); 00092 00093 #if defined(TARGET_MAX32600) 00094 // The PLL must be enabled for USB 00095 MBED_ASSERT(MXC_CLKMAN->clk_config & MXC_F_CLKMAN_CLK_CONFIG_PLL_ENABLE); 00096 00097 // Enable the USB clock 00098 MXC_CLKMAN->clk_ctrl |= MXC_F_CLKMAN_CLK_CTRL_USB_GATE_N; 00099 #elif defined(TARGET_MAX32620) 00100 // Enable the USB clock 00101 MXC_CLKMAN->clk_ctrl |= MXC_F_CLKMAN_CLK_CTRL_USB_CLOCK_ENABLE; 00102 #elif defined(TARGET_MAX32625) || defined(TARGET_MAX32630) 00103 MXC_PWRMAN->pwr_rst_ctrl |= MXC_F_PWRMAN_PWR_RST_CTRL_USB_POWERED; 00104 MXC_CLKMAN->clk_ctrl |= MXC_F_CLKMAN_CLK_CTRL_USB_CLOCK_ENABLE; 00105 #endif 00106 00107 // reset the device 00108 MXC_USB->cn = 0; 00109 MXC_USB->cn = MXC_F_USB_CN_USB_EN; 00110 MXC_USB->dev_inten = 0; 00111 MXC_USB->dev_cn = 0; 00112 MXC_USB->dev_cn = MXC_F_USB_DEV_CN_URST; 00113 MXC_USB->dev_cn = 0; 00114 00115 // fill in callback arrays 00116 epCallback[EP0OUT] = NULL; 00117 epCallback[EP0IN] = NULL; 00118 epCallback[EP1OUT] = &USBHAL::EP1_OUT_callback; 00119 epCallback[EP1IN ] = &USBHAL::EP1_IN_callback; 00120 epCallback[EP2OUT] = &USBHAL::EP2_OUT_callback; 00121 epCallback[EP2IN ] = &USBHAL::EP2_IN_callback; 00122 epCallback[EP3OUT] = &USBHAL::EP3_OUT_callback; 00123 epCallback[EP3IN ] = &USBHAL::EP3_IN_callback; 00124 epCallback[EP4OUT] = &USBHAL::EP4_OUT_callback; 00125 epCallback[EP4IN ] = &USBHAL::EP4_IN_callback; 00126 epCallback[EP5OUT] = &USBHAL::EP5_OUT_callback; 00127 epCallback[EP5IN ] = &USBHAL::EP5_IN_callback; 00128 epCallback[EP6OUT] = &USBHAL::EP6_OUT_callback; 00129 epCallback[EP6IN ] = &USBHAL::EP6_IN_callback; 00130 epCallback[EP7OUT] = &USBHAL::EP7_OUT_callback; 00131 epCallback[EP7IN ] = &USBHAL::EP7_IN_callback; 00132 00133 // clear driver state 00134 control_state = CTRL_NONE; 00135 00136 // set the descriptor location 00137 MXC_USB->ep_base = (uint32_t)&ep_buffer_descriptor; 00138 00139 // enable VBUS interrupts 00140 MXC_USB->dev_inten = MXC_F_USB_DEV_INTEN_NO_VBUS | MXC_F_USB_DEV_INTEN_VBUS; 00141 00142 // attach IRQ handler and enable interrupts 00143 instance = this; 00144 NVIC_SetVector(USB_IRQn, (uint32_t)&_usbisr); 00145 NVIC_EnableIRQ(USB_IRQn); 00146 } 00147 00148 USBHAL::~USBHAL(void) 00149 { 00150 MXC_USB->dev_cn = MXC_F_USB_DEV_CN_URST; 00151 MXC_USB->dev_cn = 0; 00152 MXC_USB->cn = 0; 00153 } 00154 00155 void USBHAL::connect(void) 00156 { 00157 // enable interrupts 00158 MXC_USB->dev_inten |= CONNECT_INTS; 00159 00160 // allow interrupts on ep0 00161 MXC_USB->ep[0] |= MXC_F_USB_EP_INT_EN; 00162 00163 // pullup enable 00164 MXC_USB->dev_cn |= (MXC_F_USB_DEV_CN_CONNECT | MXC_F_USB_DEV_CN_FIFO_MODE); 00165 } 00166 00167 void USBHAL::disconnect(void) 00168 { 00169 // disable interrupts 00170 MXC_USB->dev_inten &= ~CONNECT_INTS; 00171 00172 // disable pullup 00173 MXC_USB->dev_cn &= ~MXC_F_USB_DEV_CN_CONNECT; 00174 } 00175 00176 void USBHAL::configureDevice(void) 00177 { 00178 // do nothing 00179 } 00180 00181 void USBHAL::unconfigureDevice(void) 00182 { 00183 // reset endpoints 00184 for (int i = 0; i < MXC_USB_NUM_EP; i++) { 00185 // Disable endpoint and clear the data toggle 00186 MXC_USB->ep[i] &= ~MXC_F_USB_EP_DIR; 00187 MXC_USB->ep[i] |= MXC_F_USB_EP_DT; 00188 } 00189 } 00190 00191 void USBHAL::setAddress(uint8_t address) 00192 { 00193 // do nothing 00194 } 00195 00196 void USBHAL::remoteWakeup(void) 00197 { 00198 // do nothing 00199 } 00200 00201 static ep_buffer_t *get_desc(uint8_t endpoint) 00202 { 00203 uint8_t epnum = EP_NUM(endpoint); 00204 ep_buffer_t *desc; 00205 00206 if (epnum == 0) { 00207 if (IN_EP(endpoint)) { 00208 desc = &ep_buffer_descriptor.ep0.in_buffer; 00209 } else { 00210 desc = &ep_buffer_descriptor.ep0.out_buffer; 00211 } 00212 } else { 00213 desc = &ep_buffer_descriptor.ep[epnum - 1]; 00214 } 00215 00216 return desc; 00217 } 00218 00219 void USBHAL::EP0setup(uint8_t *buffer) 00220 { 00221 // Setup packet is fixed at 8 bytes 00222 // Setup registers cannot be read in byte mode 00223 uint32_t *ptr32 = (uint32_t*)buffer; 00224 ptr32[0] = (uint32_t)MXC_USB->setup0; 00225 ptr32[1] = (uint32_t)MXC_USB->setup1; 00226 } 00227 00228 void USBHAL::EP0read(void) 00229 { 00230 if (control_state == CTRL_IN) { 00231 // This is the status stage. ACK. 00232 MXC_USB->ep[0] |= MXC_F_USB_EP_ST_ACK; 00233 control_state = CTRL_NONE; 00234 return; 00235 } 00236 00237 control_state = CTRL_OUT; 00238 00239 endpointRead(EP0OUT, MAX_PACKET_SIZE_EP0); 00240 } 00241 00242 void USBHAL::EP0readStage(void) 00243 { 00244 // do nothing 00245 } 00246 00247 uint32_t USBHAL::EP0getReadResult(uint8_t *buffer) 00248 { 00249 uint32_t size; 00250 00251 if (MXC_USB->out_owner & 1) { 00252 return 0; 00253 } 00254 00255 // get the packet length and contents 00256 ep_buffer_t *desc = get_desc(EP0OUT); 00257 size = desc->buf0_desc; 00258 memcpy(buffer, aligned_buffer[0], size); 00259 00260 return size; 00261 } 00262 00263 void USBHAL::EP0write(uint8_t *buffer, uint32_t size) 00264 { 00265 if ((size == 0) && (control_state != CTRL_IN)) { 00266 // This is a status stage ACK. Handle in hardware. 00267 MXC_USB->ep[0] |= MXC_F_USB_EP_ST_ACK; 00268 control_state = CTRL_NONE; 00269 return; 00270 } 00271 00272 control_state = CTRL_IN; 00273 00274 endpointWrite(EP0IN, buffer, size); 00275 } 00276 00277 void USBHAL::EP0stall(void) 00278 { 00279 stallEndpoint(0); 00280 } 00281 00282 EP_STATUS USBHAL::endpointRead(uint8_t endpoint, uint32_t maximumSize) 00283 { 00284 uint8_t epnum = EP_NUM(endpoint); 00285 00286 if ((endpoint >= NUMBER_OF_PHYSICAL_ENDPOINTS) || IN_EP(endpoint)) { 00287 return EP_INVALID; 00288 } 00289 00290 if (maximumSize > MXC_USB_MAX_PACKET) { 00291 return EP_INVALID; 00292 } 00293 00294 uint32_t mask = (1 << epnum); 00295 if (MXC_USB->out_owner & mask) { 00296 return EP_INVALID; 00297 } 00298 00299 ep_buffer_t *desc = get_desc(endpoint); 00300 desc->buf0_desc = maximumSize; 00301 desc->buf0_address = (uint32_t)aligned_buffer[epnum]; 00302 00303 MXC_USB->out_owner = mask; 00304 00305 return EP_PENDING; 00306 } 00307 00308 EP_STATUS USBHAL::endpointReadResult(uint8_t endpoint, uint8_t *data, uint32_t *bytesRead) 00309 { 00310 if ((endpoint >= NUMBER_OF_PHYSICAL_ENDPOINTS) || IN_EP(endpoint)) { 00311 return EP_INVALID; 00312 } 00313 00314 uint32_t mask = (1 << EP_NUM(endpoint)); 00315 if (MXC_USB->out_owner & mask) { 00316 return EP_PENDING; 00317 } 00318 00319 // get the packet length and contents 00320 ep_buffer_t *desc = get_desc(endpoint); 00321 *bytesRead = desc->buf0_desc; 00322 memcpy(data, aligned_buffer[EP_NUM(endpoint)], *bytesRead); 00323 00324 return EP_COMPLETED; 00325 } 00326 00327 EP_STATUS USBHAL::endpointWrite(uint8_t endpoint, uint8_t *data, uint32_t size) 00328 { 00329 uint8_t epnum = EP_NUM(endpoint); 00330 00331 if ((endpoint >= NUMBER_OF_PHYSICAL_ENDPOINTS) || OUT_EP(endpoint)) { 00332 return EP_INVALID; 00333 } 00334 00335 if (size > MXC_USB_MAX_PACKET) { 00336 return EP_INVALID; 00337 } 00338 00339 uint32_t mask = (1 << epnum); 00340 if (MXC_USB->in_owner & mask) { 00341 return EP_INVALID; 00342 } 00343 00344 memcpy(aligned_buffer[epnum], data, size); 00345 00346 ep_buffer_t *desc = get_desc(endpoint); 00347 desc->buf0_desc = size; 00348 desc->buf0_address = (uint32_t)aligned_buffer[epnum]; 00349 00350 // start the DMA 00351 MXC_USB->in_owner = mask; 00352 00353 return EP_PENDING; 00354 } 00355 00356 EP_STATUS USBHAL::endpointWriteResult(uint8_t endpoint) 00357 { 00358 uint32_t mask = (1 << EP_NUM(endpoint)); 00359 if (MXC_USB->in_owner & mask) { 00360 return EP_PENDING; 00361 } 00362 00363 return EP_COMPLETED; 00364 } 00365 00366 void USBHAL::stallEndpoint(uint8_t endpoint) 00367 { 00368 uint8_t epnum = EP_NUM(endpoint); 00369 00370 if (epnum == 0) { 00371 MXC_USB->ep[epnum] |= MXC_F_USB_EP_ST_STALL; 00372 } 00373 00374 MXC_USB->ep[epnum] |= MXC_F_USB_EP_STALL; 00375 } 00376 00377 void USBHAL::unstallEndpoint(uint8_t endpoint) 00378 { 00379 MXC_USB->ep[EP_NUM(endpoint)] &= ~MXC_F_USB_EP_STALL; 00380 } 00381 00382 bool USBHAL::realiseEndpoint(uint8_t endpoint, uint32_t maxPacket, uint32_t options) 00383 { 00384 uint8_t epnum = EP_NUM(endpoint); 00385 uint32_t ep_ctrl; 00386 00387 if (epnum >= NUMBER_OF_PHYSICAL_ENDPOINTS) { 00388 return false; 00389 } 00390 00391 if (IN_EP(endpoint)) { 00392 ep_ctrl = (MXC_V_USB_EP_DIR_IN << MXC_F_USB_EP_DIR_POS); 00393 } else { 00394 ep_ctrl = (MXC_S_USB_EP_DIR_OUT << MXC_F_USB_EP_DIR_POS); 00395 } 00396 00397 ep_ctrl |= (MXC_F_USB_EP_DT | MXC_F_USB_EP_INT_EN); 00398 00399 MXC_USB->ep[epnum] = ep_ctrl; 00400 00401 return true; 00402 } 00403 00404 bool USBHAL::getEndpointStallState(unsigned char endpoint) 00405 { 00406 return !!(MXC_USB->ep[endpoint] & MXC_F_USB_EP_STALL); 00407 } 00408 00409 void USBHAL::_usbisr(void) 00410 { 00411 instance->usbisr(); 00412 } 00413 00414 void USBHAL::usbisr(void) 00415 { 00416 // get and clear irqs 00417 uint32_t irq_flags = MXC_USB->dev_intfl; 00418 MXC_USB->dev_intfl = irq_flags; 00419 00420 // process only enabled interrupts 00421 irq_flags &= MXC_USB->dev_inten; 00422 00423 // suspend 00424 if (irq_flags & MXC_F_USB_DEV_INTFL_SUSP) { 00425 suspendStateChanged(1); 00426 } 00427 00428 // bus reset 00429 if (irq_flags & MXC_F_USB_DEV_INTFL_BRST) { 00430 00431 // reset endpoints 00432 for (int i = 0; i < MXC_USB_NUM_EP; i++) { 00433 // Disable endpoint and clear the data toggle 00434 MXC_USB->ep[i] &= ~MXC_F_USB_EP_DIR; 00435 MXC_USB->ep[i] |= MXC_F_USB_EP_DT; 00436 } 00437 00438 // clear driver state 00439 control_state = CTRL_NONE; 00440 00441 busReset(); 00442 00443 // no need to process events after reset 00444 return; 00445 } 00446 00447 // Setup packet 00448 if (irq_flags & MXC_F_USB_DEV_INTFL_SETUP) { 00449 control_state = CTRL_SETUP; 00450 EP0setupCallback(); 00451 } 00452 00453 // IN packets 00454 if (irq_flags & MXC_F_USB_DEV_INTFL_EP_IN) { 00455 // get and clear IN irqs 00456 uint32_t in_irqs = MXC_USB->in_int; 00457 MXC_USB->in_int = in_irqs; 00458 00459 if (in_irqs & 1) { 00460 EP0in(); 00461 } 00462 00463 for (uint8_t epnum = 1; epnum < NUMBER_OF_LOGICAL_ENDPOINTS; epnum++) { 00464 uint32_t irq_mask = (1 << epnum); 00465 if (in_irqs & irq_mask) { 00466 uint8_t endpoint = (epnum << 1) | DIR_IN; 00467 (instance->*(epCallback[endpoint]))(); 00468 } 00469 } 00470 } 00471 00472 // OUT packets 00473 if (irq_flags & MXC_F_USB_DEV_INTFL_EP_OUT) { 00474 // get and clear OUT irqs 00475 uint32_t out_irqs = MXC_USB->out_int; 00476 MXC_USB->out_int = out_irqs; 00477 00478 if (out_irqs & 1) { 00479 EP0out(); 00480 } 00481 00482 for (uint8_t epnum = 1; epnum < NUMBER_OF_LOGICAL_ENDPOINTS; epnum++) { 00483 uint32_t irq_mask = (1 << epnum); 00484 if (out_irqs & irq_mask) { 00485 uint8_t endpoint = (epnum << 1) | DIR_OUT; 00486 (instance->*(epCallback[endpoint]))(); 00487 } 00488 } 00489 } 00490 } 00491 00492 #endif
Generated on Wed Jul 13 2022 12:44:03 by 1.7.2