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 USBDevice by
USBHAL_EFM32.cpp
00001 /* Copyright 2015 Silicon Labs, http://www.silabs.com 00002 * 00003 * Licensed under the Apache License, Version 2.0 (the "License"); 00004 * you may not use this file except in compliance with the License. 00005 * You may obtain a copy of the License at 00006 * 00007 * http://www.apache.org/licenses/LICENSE-2.0 00008 * 00009 * Unless required by applicable law or agreed to in writing, software 00010 * distributed under the License is distributed on an "AS IS" BASIS, 00011 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00012 * See the License for the specific language governing permissions and 00013 * limitations under the License. 00014 */ 00015 00016 #if defined TARGET_EFM32GG_STK3700 || \ 00017 defined TARGET_EFM32LG_STK3600 || \ 00018 defined TARGET_EFM32WG_STK3800 || \ 00019 defined TARGET_EFM32HG_STK3400 00020 00021 #include "USBHAL.h" 00022 #include "em_usb.h" 00023 #include "em_usbtypes.h" 00024 #include "em_usbhal.h" 00025 #include "em_usbd.h" 00026 00027 #include "sleepmodes.h" 00028 00029 enum USBISRCommand { 00030 CMD_HANDLED = 0, 00031 CMD_EP0SETUP, 00032 CMD_EP0IN, 00033 CMD_EP0OUT, 00034 CMD_EP_XFER_COMPLETED, 00035 CMD_SOF, 00036 CMD_BUSRESET, 00037 CMD_SUSPEND_STATE_CHANGED, 00038 CMD_ENUM_END_MARKER 00039 }; 00040 00041 enum IEPStatus { 00042 NOT_CONFIGURED = 0, 00043 IDLE = 1, 00044 READ_PENDING = 2, 00045 WRITE_PENDING = 3, 00046 READ_COMPLETE = 4, 00047 WRITE_COMPLETE = 5, 00048 FAILED_INVALID = 6, 00049 FAILED_STALLED = 7 00050 }; 00051 00052 typedef struct { 00053 IEPStatus status; 00054 uint32_t byte_count; 00055 uint32_t max_packet; 00056 USB_XferCompleteCb_TypeDef intern_cb; 00057 uint8_t *data_buf; 00058 } ep_state_t; 00059 00060 USBHAL * USBHAL::instance; 00061 static uint8_t ep0setupdata[8]; 00062 static ep_state_t ep_state[NUMBER_OF_ENDPOINTS]; 00063 #ifdef USB_USE_DYNAMIC_MEMORY 00064 static uint8_t ep0in_data_buf[MAX_PACKET_SIZE_EP0] __attribute__ ((aligned (4))); 00065 static uint8_t ep0out_data_buf[MAX_PACKET_SIZE_EP0]; // FIXME: does this need to be this big? 00066 #else 00067 static uint8_t ep_data_buf[NUMBER_OF_ENDPOINTS][64] __attribute__ ((aligned (4))); 00068 #endif 00069 00070 static void run_cmd(USBISRCommand cmd, uint32_t param); 00071 static void (*isrptr)() = NULL; 00072 static USBISRCommand usb_isrcmd = CMD_HANDLED; 00073 static uint32_t usb_isrcmd_param = 0; 00074 00075 extern "C" void usbhal_allow_em2(bool allow_em2); 00076 00077 #ifdef DEBUG_USB_API 00078 #define TRACE(fmt,...) printf("USB: %s: " fmt "\n", __func__, __VA_ARGS__); 00079 #define TRACE_FUNC_IN printf("USB: > %s\n",__func__); 00080 #define TRACE_FUNC_IN_P(fmt, ...) printf("USB: > %s: " fmt "\n", __func__, __VA_ARGS__); 00081 #else 00082 #define TRACE(fmt,...) 00083 #define TRACE_FUNC_IN 00084 #define TRACE_FUNC_IN_P(fmt, ...) 00085 #endif 00086 00087 static EP_STATUS internEndpointRead(uint8_t ep, uint32_t maxSize); 00088 00089 static int usbhal_xfer_complete_cb(uint8_t epaddr, USB_Status_TypeDef status, 00090 uint32_t xferred, uint32_t remaining); 00091 static void usbhal_free_buffers(void); 00092 00093 /* Internal EP transfer complete callbacks */ 00094 #define EPCB(n) static int usbhal_xfer_complete_cb_##n(USB_Status_TypeDef status, \ 00095 uint32_t xferred, uint32_t remaining) { \ 00096 return usbhal_xfer_complete_cb(n, status, xferred, remaining); \ 00097 } 00098 /* ------^ */ 00099 EPCB(EP0OUT) 00100 EPCB(EP0IN) 00101 EPCB(EP1OUT) 00102 EPCB(EP1IN) 00103 EPCB(EP2OUT) 00104 EPCB(EP2IN) 00105 EPCB(EP3OUT) 00106 EPCB(EP3IN) 00107 #ifndef TARGET_EFM32HG_STK3400 00108 EPCB(EP4OUT) 00109 EPCB(EP4IN) 00110 EPCB(EP5OUT) 00111 EPCB(EP5IN) 00112 EPCB(EP6OUT) 00113 EPCB(EP6IN) 00114 #endif 00115 00116 static inline bool is_aligned(const void *pointer, size_t byte_count) 00117 { 00118 return ((uintptr_t)pointer % byte_count == 0); 00119 } 00120 00121 USBHAL::USBHAL(void) 00122 { 00123 TRACE_FUNC_IN; 00124 00125 isrptr = &USBHAL::_usbisr; 00126 00127 if (instance) { 00128 TRACE("Assert self failed! instance=%p", instance); 00129 abort(); 00130 } 00131 instance = this; 00132 00133 // When USB is active, we can't go below EM1. This block may 00134 // be dynamically removed/reinstated to allow deeper sleep. 00135 usbhal_allow_em2(false); 00136 00137 // When in suspend / Vbus off we can go to EM2, but never below 00138 // that as long as USB is being used. Despite the name the call here 00139 // blocks entering modes _below_ EM2, but allows EM2. 00140 blockSleepMode(EM2); 00141 00142 epCallback[EP0OUT] = NULL; 00143 epCallback[EP0IN ] = NULL; 00144 epCallback[EP1OUT] = &USBHAL::EP1_OUT_callback; 00145 epCallback[EP1IN ] = &USBHAL::EP1_IN_callback; 00146 epCallback[EP2OUT] = &USBHAL::EP2_OUT_callback; 00147 epCallback[EP2IN ] = &USBHAL::EP2_IN_callback; 00148 epCallback[EP3OUT] = &USBHAL::EP3_OUT_callback; 00149 epCallback[EP3IN ] = &USBHAL::EP3_IN_callback; 00150 #ifndef TARGET_EFM32HG_STK3400 00151 epCallback[EP4OUT] = &USBHAL::EP4_OUT_callback; 00152 epCallback[EP4IN ] = &USBHAL::EP4_IN_callback; 00153 epCallback[EP5OUT] = &USBHAL::EP5_OUT_callback; 00154 epCallback[EP5IN ] = &USBHAL::EP5_IN_callback; 00155 epCallback[EP6OUT] = &USBHAL::EP6_OUT_callback; 00156 epCallback[EP6IN ] = &USBHAL::EP6_IN_callback; 00157 #endif 00158 00159 memset(ep_state, 0, sizeof(ep_state)); 00160 00161 ep_state[EP0OUT].intern_cb = usbhal_xfer_complete_cb_EP0OUT; 00162 ep_state[EP0IN ].intern_cb = usbhal_xfer_complete_cb_EP0IN; 00163 ep_state[EP1OUT].intern_cb = usbhal_xfer_complete_cb_EP1OUT; 00164 ep_state[EP1IN ].intern_cb = usbhal_xfer_complete_cb_EP1IN; 00165 ep_state[EP2OUT].intern_cb = usbhal_xfer_complete_cb_EP2OUT; 00166 ep_state[EP2IN ].intern_cb = usbhal_xfer_complete_cb_EP2IN; 00167 ep_state[EP3OUT].intern_cb = usbhal_xfer_complete_cb_EP3OUT; 00168 ep_state[EP3IN ].intern_cb = usbhal_xfer_complete_cb_EP3IN; 00169 #ifndef TARGET_EFM32HG_STK3400 00170 ep_state[EP4OUT].intern_cb = usbhal_xfer_complete_cb_EP4OUT; 00171 ep_state[EP4IN ].intern_cb = usbhal_xfer_complete_cb_EP4IN; 00172 ep_state[EP5OUT].intern_cb = usbhal_xfer_complete_cb_EP5OUT; 00173 ep_state[EP5IN ].intern_cb = usbhal_xfer_complete_cb_EP5IN; 00174 ep_state[EP6OUT].intern_cb = usbhal_xfer_complete_cb_EP6OUT; 00175 ep_state[EP6IN ].intern_cb = usbhal_xfer_complete_cb_EP6IN; 00176 #endif 00177 00178 #ifdef USB_USE_DYNAMIC_MEMORY 00179 ep_state[EP0OUT].data_buf = ep0out_data_buf; 00180 ep_state[EP0IN].data_buf = ep0in_data_buf; 00181 #else 00182 for (int i=0 ; i<NUMBER_OF_ENDPOINTS ; i++) { 00183 ep_state[i].data_buf = ep_data_buf[i]; 00184 } 00185 #endif 00186 } 00187 00188 USBHAL::~USBHAL(void) 00189 { 00190 TRACE_FUNC_IN; 00191 USBD_AbortAllTransfers(); 00192 USBD_Disconnect(); 00193 usbhal_free_buffers(); 00194 00195 usbhal_allow_em2(true); 00196 unblockSleepMode(EM2); 00197 } 00198 00199 extern "C" void usbhal_allow_em2(bool allow_em2) 00200 { 00201 if (allow_em2) { 00202 // unblockSleepMode is safe to call even if we would unblock 00203 // an already unblocked mode, so no checks here. 00204 unblockSleepMode(EM1); 00205 } else { 00206 blockSleepMode(EM1); 00207 } 00208 } 00209 00210 static void usbhal_reset_cb(void) 00211 { 00212 TRACE_FUNC_IN; 00213 run_cmd(CMD_BUSRESET, 0); 00214 } 00215 00216 #ifdef DEBUG_USB_API 00217 static const char *usbstate[] = { "NONE", "ATTACHED", "POWERED", "DEFAULT", 00218 "ADDRESSED", "CONFIGURED", "SUSPENDED", "???" }; 00219 #endif 00220 00221 static void usbhal_state_change_cb(USBD_State_TypeDef oldState, 00222 USBD_State_TypeDef newState) 00223 { 00224 TRACE("state changed %s -> %s", usbstate[oldState], usbstate[newState]); 00225 00226 if (oldState == USBD_STATE_SUSPENDED) { 00227 run_cmd(CMD_SUSPEND_STATE_CHANGED, 0); 00228 } 00229 00230 if (newState == USBD_STATE_SUSPENDED) { 00231 run_cmd(CMD_SUSPEND_STATE_CHANGED, 1); 00232 } 00233 00234 // Should call connectStateChanged from here as well but there is 00235 // no documentation on when to actually do so. (And the implementation 00236 // in USBDevice.cpp is a stub) 00237 00238 // HACK! Since connectStateChanged is not used, indicate the loss 00239 // off connection by reporting a bus reset. This causes USBDevice 00240 // to realise that at least it's not in CONFIGURED anymore, and 00241 // stop trying to read/write in a busyloop. 00242 if (newState == USBD_STATE_NONE) { 00243 run_cmd(CMD_BUSRESET, 0); 00244 } 00245 } 00246 00247 static int usbhal_setupcmd_cb(const USB_Setup_TypeDef *setup) 00248 { 00249 TRACE_FUNC_IN; 00250 if (!setup) { 00251 EFM_ASSERT(false); 00252 return USB_STATUS_REQ_ERR; 00253 } 00254 00255 memcpy(ep0setupdata, setup, 8); 00256 run_cmd(CMD_EP0SETUP, 0); 00257 00258 return USB_STATUS_OK; 00259 } 00260 00261 static void usbhal_sof_cb(uint16_t frameNum) 00262 { 00263 run_cmd(CMD_SOF, frameNum); 00264 } 00265 00266 static void usbhal_free_buffers(void) 00267 { 00268 #ifdef USB_USE_DYNAMIC_MEMORY 00269 TRACE_FUNC_IN; 00270 00271 for (int i=EP1OUT ; i<NUMBER_OF_ENDPOINTS ; i++ ) { 00272 if (ep_state[i].data_buf) { 00273 free(ep_state[i].data_buf); 00274 ep_state[i].data_buf = NULL; 00275 } 00276 } 00277 #endif 00278 } 00279 00280 void USBHAL::connect(void) 00281 { 00282 TRACE_FUNC_IN; 00283 00284 // Init datastructures must be static - driver will use these even after the init function exits! 00285 00286 static const uint8_t buffer_multiplier[] = { 1 }; // Mult 1 for control EP 00287 static const USBD_Callbacks_TypeDef usbd_callbacks = { 00288 .usbReset = usbhal_reset_cb, 00289 .usbStateChange = usbhal_state_change_cb, 00290 .setupCmd = usbhal_setupcmd_cb, 00291 .isSelfPowered = NULL, 00292 .sofInt = usbhal_sof_cb 00293 }; 00294 00295 USBD_Init_TypeDef initdata = { 00296 .deviceDescriptor = NULL, 00297 .configDescriptor = NULL, 00298 .stringDescriptors = NULL, 00299 .numberOfStrings = 0, 00300 .bufferingMultiplier = buffer_multiplier, 00301 .callbacks = &usbd_callbacks, 00302 .reserved = 0 00303 }; 00304 00305 int ret = USBD_Init(&initdata); 00306 00307 TRACE("init = %d, devicedesc = %lx, configdesc = %lx", ret, 00308 (uint32_t) initdata.deviceDescriptor, 00309 (uint32_t) initdata.configDescriptor); 00310 00311 EFM_ASSERT(ret == USB_STATUS_OK); 00312 } 00313 00314 void USBHAL::disconnect(void) 00315 { 00316 TRACE_FUNC_IN; 00317 USBD_Disconnect(); 00318 } 00319 00320 void USBHAL::configureDevice(void) 00321 { 00322 TRACE_FUNC_IN; 00323 USBD_SetUsbState(USBD_STATE_CONFIGURED); 00324 } 00325 00326 void USBHAL::unconfigureDevice(void) 00327 { 00328 TRACE_FUNC_IN; 00329 USBD_SetUsbState(USBD_STATE_DEFAULT); 00330 usbhal_free_buffers(); 00331 } 00332 00333 void USBHAL::setAddress(uint8_t address) 00334 { 00335 TRACE_FUNC_IN_P("addr 0x%x", (unsigned)address); 00336 USBD_SetAddress(address); 00337 } 00338 00339 void USBHAL::remoteWakeup(void) 00340 { 00341 TRACE_FUNC_IN; 00342 USBD_RemoteWakeup(); 00343 } 00344 00345 void USBHAL::EP0setup(uint8_t *buffer) 00346 { 00347 TRACE_FUNC_IN; 00348 EFM_ASSERT(buffer); 00349 if (buffer) { 00350 memcpy(buffer, ep0setupdata, 8); 00351 } 00352 } 00353 00354 void USBHAL::EP0read(void) 00355 { 00356 TRACE_FUNC_IN; 00357 (void)internEndpointRead(0, MAX_PACKET_SIZE_EP0); 00358 } 00359 00360 void USBHAL::EP0readStage(void) 00361 { 00362 TRACE_FUNC_IN; 00363 // Not needed 00364 } 00365 00366 uint32_t USBHAL::EP0getReadResult(uint8_t *buffer) 00367 { 00368 TRACE_FUNC_IN; 00369 EFM_ASSERT(buffer); 00370 00371 uint32_t read = 0; 00372 endpointReadResult(0, buffer, &read); 00373 return read; 00374 } 00375 00376 static int usbhal_xfer_complete_cb(uint8_t ep, USB_Status_TypeDef status, 00377 uint32_t xferred, uint32_t remaining) 00378 { 00379 TRACE_FUNC_IN_P("ep 0x%x, status %u, xferred %lu, rem %lu", 00380 ep, status, xferred, remaining); 00381 00382 if (ep >= NUMBER_OF_ENDPOINTS) { 00383 EFM_ASSERT(false); 00384 return USB_STATUS_REQ_ERR; 00385 } 00386 00387 switch (ep) { 00388 case EP0OUT: 00389 if (ep_state[EP0OUT].status == READ_PENDING) { 00390 ep_state[EP0OUT].status = READ_COMPLETE; 00391 ep_state[EP0OUT].byte_count = xferred; 00392 // drop zlp 00393 if (xferred == 0) { 00394 break; 00395 } 00396 } 00397 run_cmd(CMD_EP0OUT, 0); 00398 break; 00399 00400 case EP0IN: 00401 run_cmd(CMD_EP0IN, 0); 00402 break; 00403 00404 default: 00405 bool write = ep & 1; 00406 00407 if (status == USB_STATUS_OK) { 00408 if (!write && ep_state[ep].status == READ_PENDING) { 00409 ep_state[ep].status = READ_COMPLETE; 00410 ep_state[ep].byte_count = xferred; 00411 } else if (write && ep_state[ep].status == WRITE_PENDING) { 00412 ep_state[ep].status = WRITE_COMPLETE; 00413 } else { 00414 ep_state[ep].status = FAILED_INVALID; 00415 } 00416 } else { 00417 ep_state[ep].status = FAILED_INVALID; 00418 } 00419 00420 if (ep_state[ep].status != FAILED_INVALID) { 00421 run_cmd(CMD_EP_XFER_COMPLETED, ep); 00422 } 00423 break; 00424 } 00425 00426 return USB_STATUS_OK; 00427 } 00428 00429 void USBHAL::EP0write(uint8_t *buffer, uint32_t size) 00430 { 00431 //TRACE_FUNC_IN_P("buffer %lx, size %lu", (uint32_t) buffer, size); 00432 00433 int ret; 00434 USB_XferCompleteCb_TypeDef cb = ep_state[EP0IN].intern_cb; 00435 00436 EFM_ASSERT((buffer != NULL) || (size == 0)); 00437 EFM_ASSERT(size <= MAX_PACKET_SIZE_EP0); 00438 00439 if (!buffer || size == 0) { 00440 // No callback after writing EP0 ZLP 00441 cb = NULL; 00442 } 00443 00444 if (buffer && !is_aligned(buffer,4)) { 00445 // Copy unaligned data to write-buffer before USBD_Write 00446 memcpy(ep_state[EP0IN].data_buf, buffer, size); 00447 ret = USBD_Write(0, ep_state[EP0IN].data_buf, size, cb); 00448 } else { 00449 ret = USBD_Write(0, buffer, size, cb); 00450 } 00451 00452 if (ret != USB_STATUS_OK) { 00453 TRACE("FAILED - ret %d", ret); 00454 } 00455 } 00456 00457 void USBHAL::EP0stall(void) 00458 { 00459 TRACE_FUNC_IN; 00460 USBD_StallEp0(); 00461 } 00462 00463 static EP_STATUS internEndpointRead(uint8_t ep, uint32_t maxSize) 00464 { 00465 //TRACE_FUNC_IN_P("endpoint 0x%x, size %ld, cb %d", (unsigned)ep, maxSize, useCallback); 00466 00467 if (ep >= NUMBER_OF_ENDPOINTS) { 00468 EFM_ASSERT(false); 00469 return EP_INVALID; 00470 } 00471 00472 ep_state[ep].status = READ_PENDING; 00473 00474 int ret = USBD_Read(USB_EP_TO_ADDR(ep), ep_state[ep].data_buf, maxSize, 00475 ep_state[ep].intern_cb); 00476 00477 if (ret == USB_STATUS_OK) { 00478 return EP_PENDING; 00479 } else { 00480 TRACE("FAILED - ret %d", ret); 00481 00482 if (ret == USB_STATUS_EP_STALLED) { 00483 return EP_STALLED; 00484 } else { 00485 return EP_INVALID; 00486 } 00487 } 00488 } 00489 00490 EP_STATUS USBHAL::endpointRead(uint8_t endpoint, uint32_t maximumSize) 00491 { 00492 return internEndpointRead(endpoint, maximumSize); 00493 } 00494 00495 EP_STATUS USBHAL::endpointReadResult(uint8_t endpoint, uint8_t *data, uint32_t *bytesRead) 00496 { 00497 TRACE_FUNC_IN; 00498 00499 if (endpoint >= NUMBER_OF_ENDPOINTS) { 00500 EFM_ASSERT(false); 00501 return EP_INVALID; 00502 } 00503 00504 EFM_ASSERT(data); 00505 EFM_ASSERT(bytesRead); 00506 if (!data || !bytesRead) { 00507 return EP_INVALID; 00508 } 00509 00510 switch (ep_state[endpoint].status) { 00511 case READ_PENDING: 00512 return EP_PENDING; 00513 00514 case READ_COMPLETE: 00515 memcpy(data, ep_state[endpoint].data_buf, ep_state[endpoint].byte_count); 00516 *bytesRead = ep_state[endpoint].byte_count; 00517 ep_state[endpoint].status = IDLE; 00518 return EP_COMPLETED; 00519 00520 case FAILED_STALLED: 00521 ep_state[endpoint].status = IDLE; 00522 return EP_STALLED; 00523 00524 default: 00525 ep_state[endpoint].status = IDLE; 00526 return EP_INVALID; 00527 } 00528 } 00529 00530 EP_STATUS USBHAL::endpointWrite(uint8_t endpoint, uint8_t *data, uint32_t size) 00531 { 00532 TRACE_FUNC_IN_P("endpoint 0x%x, data 0x%lx, size %lu", (unsigned )endpoint, (uint32_t)data, size); 00533 00534 EFM_ASSERT(endpoint < NUMBER_OF_ENDPOINTS); 00535 EFM_ASSERT(endpoint > EP0IN); 00536 EFM_ASSERT(size <= ep_state[endpoint].max_packet); 00537 EFM_ASSERT(data); 00538 00539 uint8_t ep = USB_EP_TO_INDEX(endpoint); 00540 00541 if (endpoint >= NUMBER_OF_ENDPOINTS || endpoint <= EP0IN) { 00542 return EP_INVALID; 00543 } 00544 00545 if (size > ep_state[endpoint].max_packet) { 00546 return EP_INVALID; 00547 } 00548 00549 if (!data) { 00550 return EP_INVALID; 00551 } 00552 00553 memcpy(ep_state[ep].data_buf, data, size); 00554 00555 ep_state[ep].status = WRITE_PENDING; 00556 int ret = USBD_Write(USB_EP_TO_ADDR(endpoint), ep_state[ep].data_buf, size, ep_state[ep].intern_cb); 00557 00558 if (ret == USB_STATUS_EP_STALLED) { 00559 ep_state[ep].status = IDLE; 00560 return EP_STALLED; 00561 } else if (ret != USB_STATUS_OK) { 00562 ep_state[ep].status = IDLE; 00563 return EP_INVALID; 00564 } 00565 00566 return EP_PENDING; 00567 } 00568 00569 EP_STATUS USBHAL::endpointWriteResult(uint8_t endpoint) 00570 { 00571 if (endpoint >= NUMBER_OF_ENDPOINTS) { 00572 EFM_ASSERT(false); 00573 return EP_INVALID; 00574 } 00575 00576 switch (ep_state[endpoint].status) { 00577 case WRITE_PENDING: 00578 return EP_PENDING; 00579 00580 case WRITE_COMPLETE: 00581 ep_state[endpoint].status = IDLE; 00582 return EP_COMPLETED; 00583 00584 case FAILED_STALLED: 00585 ep_state[endpoint].status = IDLE; 00586 return EP_STALLED; 00587 00588 default: 00589 ep_state[endpoint].status = IDLE; 00590 return EP_INVALID; 00591 } 00592 } 00593 00594 void USBHAL::stallEndpoint(uint8_t endpoint) 00595 { 00596 TRACE_FUNC_IN; 00597 00598 EFM_ASSERT(endpoint < NUMBER_OF_ENDPOINTS); 00599 EFM_ASSERT((endpoint != EP0OUT) && (endpoint != EP0IN)); 00600 00601 USBD_StallEp(USB_EP_TO_ADDR(endpoint)); 00602 } 00603 00604 void USBHAL::unstallEndpoint(uint8_t endpoint) 00605 { 00606 TRACE_FUNC_IN; 00607 00608 EFM_ASSERT(endpoint < NUMBER_OF_ENDPOINTS); 00609 EFM_ASSERT((endpoint != EP0OUT) && (endpoint != EP0IN)); 00610 00611 USBD_UnStallEp(USB_EP_TO_ADDR(endpoint)); 00612 } 00613 00614 bool USBHAL::realiseEndpoint(uint8_t endpoint, uint32_t maxPacket, uint32_t options) 00615 { 00616 TRACE_FUNC_IN_P("endpoint %d, packetsize %ld, options 0x%lx", endpoint, 00617 maxPacket, options); 00618 00619 int mult = 1; // RX/TX buffer size multiplier 00620 int type = USB_EPTYPE_INTR; 00621 00622 if (endpoint >= NUMBER_OF_ENDPOINTS) { 00623 EFM_ASSERT(false); 00624 return false; 00625 } 00626 00627 if (endpoint == EP0IN || endpoint == EP0OUT) { 00628 EFM_ASSERT(false); 00629 return false; 00630 } 00631 00632 ep_state[endpoint].max_packet = 0; 00633 00634 if (endpoint == EPISO_OUT || endpoint == EPISO_IN) { 00635 if (maxPacket > MAX_PACKET_SIZE_EPISO) { 00636 EFM_ASSERT(false); 00637 return false; 00638 } 00639 } else if ((maxPacket > MAX_PACKET_SIZE_EPBULK) || (maxPacket > MAX_PACKET_SIZE_EPINT)) { 00640 EFM_ASSERT(false); 00641 return false; 00642 } 00643 00644 // USBDevice performs a read right after creating the endpoints, 00645 // before calling configureDevice. The read will fail since 00646 // at that point the device state is still ADDRESSED. Workaround 00647 // is to force configured state here. 00648 // 00649 // This relies on USBDevice to not call realiseEndpoint unless 00650 // it is transitioning to the CONFIGURED state. 00651 USBD_SetUsbState(USBD_STATE_CONFIGURED); 00652 00653 // Why doesn't this function have a type param? This is silly... 00654 switch (endpoint) { 00655 case EPBULK_OUT: 00656 case EPBULK_IN: 00657 type = USB_EPTYPE_BULK; 00658 mult = 2; 00659 break; 00660 case EPINT_OUT: 00661 case EPINT_IN: 00662 type = USB_EPTYPE_INTR; 00663 mult = 1; 00664 break; 00665 case EPISO_OUT: 00666 case EPISO_IN: 00667 type = USB_EPTYPE_ISOC; 00668 mult = 2; // ? 00669 break; 00670 } 00671 00672 // Some options force the endpoint to a specific type 00673 if( options & ISOCHRONOUS ) { 00674 type = USB_EPTYPE_ISOC; 00675 mult = 2; // ? 00676 } else if ( options & RATE_FEEDBACK_MODE ) { 00677 // No support for whatever rate feedback is, but for interrupt only 00678 type = USB_EPTYPE_INTR; 00679 mult = 1; 00680 } 00681 00682 #ifdef USB_USE_DYNAMIC_MEMORY 00683 if (ep_state[endpoint].data_buf) { 00684 free(ep_state[endpoint].data_buf); 00685 } 00686 00687 ep_state[endpoint].data_buf = (uint8_t *)malloc(maxPacket); 00688 00689 if (!ep_state[endpoint].data_buf) { 00690 EFM_ASSERT(false); 00691 return false; 00692 } 00693 #endif 00694 00695 int ret = USBD_AddEndpoint(USB_EP_TO_ADDR(endpoint), type, maxPacket, mult); 00696 00697 if (ret == USB_STATUS_OK) { 00698 ep_state[endpoint].status = IDLE; 00699 ep_state[endpoint].max_packet = maxPacket; 00700 return true; 00701 } else { 00702 return false; 00703 } 00704 } 00705 00706 bool USBHAL::getEndpointStallState(unsigned char endpoint) 00707 { 00708 TRACE_FUNC_IN; 00709 if (endpoint >= NUMBER_OF_ENDPOINTS) { 00710 EFM_ASSERT(false); 00711 return false; 00712 } 00713 return USBD_EpIsStalled(USB_EP_TO_ADDR(endpoint)); 00714 } 00715 00716 static void run_cmd(USBISRCommand cmd, uint32_t param) 00717 { 00718 if (usb_isrcmd != CMD_HANDLED || cmd >= CMD_ENUM_END_MARKER) { 00719 EFM_ASSERT(false); 00720 abort(); 00721 } 00722 00723 usb_isrcmd = cmd; 00724 usb_isrcmd_param = param; 00725 isrptr(); 00726 } 00727 00728 void USBHAL::_usbisr(void) 00729 { 00730 EFM_ASSERT(instance); 00731 instance->usbisr(); 00732 } 00733 00734 void USBHAL::usbisr(void) 00735 { 00736 //TRACE_FUNC_IN; 00737 00738 // This "ISR" is used just to route callbacks from SiL USB driver 00739 // callback context (which can not call protected/private USBHAL 00740 // methods), to the actual USBHAL. 00741 00742 EFM_ASSERT(usb_isrcmd != CMD_HANDLED); 00743 switch (usb_isrcmd) { 00744 case CMD_EP0SETUP: 00745 this->EP0setupCallback(); 00746 break; 00747 case CMD_EP0IN: 00748 this->EP0in(); 00749 break; 00750 case CMD_EP0OUT: 00751 this->EP0out(); 00752 break; 00753 case CMD_BUSRESET: 00754 this->busReset(); 00755 break; 00756 case CMD_EP_XFER_COMPLETED: 00757 if (epCallback[usb_isrcmd_param] && instance) { 00758 (instance->*(epCallback[usb_isrcmd_param]))(); 00759 } 00760 break; 00761 case CMD_SOF: 00762 this->SOF(usb_isrcmd_param); 00763 break; 00764 case CMD_SUSPEND_STATE_CHANGED: 00765 this->suspendStateChanged(usb_isrcmd_param); 00766 break; 00767 default: 00768 EFM_ASSERT(false); 00769 break; 00770 } 00771 usb_isrcmd = CMD_HANDLED; 00772 } 00773 #endif 00774 00775 // End of file
Generated on Fri Jul 15 2022 22:45:14 by
1.7.2
