USB device stack

Dependents:   blinky_max32630fthr FTHR_USB_serial FTHR_OLED HSP_RPC_GUI_3_0_1 ... more

Fork of USBDevice by mbed official

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers USBHAL_EFM32.cpp Source File

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