max4146x_comp

Dependencies:   MAX14690

Committer:
sdivarci
Date:
Sun Oct 25 20:10:02 2020 +0000
Revision:
0:0061165683ee
sdivarci

Who changed what in which revision?

UserRevisionLine numberNew contents of line
sdivarci 0:0061165683ee 1 /**************************************************************************//**
sdivarci 0:0061165683ee 2 * @file em_usbd.c
sdivarci 0:0061165683ee 3 * @brief USB protocol stack library, device API.
sdivarci 0:0061165683ee 4 * @version 3.20.14
sdivarci 0:0061165683ee 5 ******************************************************************************
sdivarci 0:0061165683ee 6 * @section License
sdivarci 0:0061165683ee 7 * <b>(C) Copyright 2014 Silicon Labs, http://www.silabs.com</b>
sdivarci 0:0061165683ee 8 *******************************************************************************
sdivarci 0:0061165683ee 9 *
sdivarci 0:0061165683ee 10 * Licensed under the Apache License, Version 2.0 (the "License");
sdivarci 0:0061165683ee 11 * you may not use this file except in compliance with the License.
sdivarci 0:0061165683ee 12 * You may obtain a copy of the License at
sdivarci 0:0061165683ee 13 *
sdivarci 0:0061165683ee 14 * http://www.apache.org/licenses/LICENSE-2.0
sdivarci 0:0061165683ee 15 *
sdivarci 0:0061165683ee 16 * Unless required by applicable law or agreed to in writing, software
sdivarci 0:0061165683ee 17 * distributed under the License is distributed on an "AS IS" BASIS,
sdivarci 0:0061165683ee 18 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
sdivarci 0:0061165683ee 19 * See the License for the specific language governing permissions and
sdivarci 0:0061165683ee 20 * limitations under the License.
sdivarci 0:0061165683ee 21 *
sdivarci 0:0061165683ee 22 ******************************************************************************/
sdivarci 0:0061165683ee 23
sdivarci 0:0061165683ee 24 #include "em_device.h"
sdivarci 0:0061165683ee 25 #if defined( USB_PRESENT ) && ( USB_COUNT == 1 )
sdivarci 0:0061165683ee 26 #include "em_usb.h"
sdivarci 0:0061165683ee 27 #if defined( USB_DEVICE )
sdivarci 0:0061165683ee 28
sdivarci 0:0061165683ee 29 #include "em_cmu.h"
sdivarci 0:0061165683ee 30 #include "em_usbtypes.h"
sdivarci 0:0061165683ee 31 #include "em_usbhal.h"
sdivarci 0:0061165683ee 32 #include "em_usbd.h"
sdivarci 0:0061165683ee 33
sdivarci 0:0061165683ee 34 /** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
sdivarci 0:0061165683ee 35
sdivarci 0:0061165683ee 36 static USBD_Device_TypeDef device;
sdivarci 0:0061165683ee 37 USBD_Device_TypeDef *dev = &device;
sdivarci 0:0061165683ee 38
sdivarci 0:0061165683ee 39 static uint32_t totalRxFifoSize = 0, totalTxFifoSize = 0;
sdivarci 0:0061165683ee 40 static int numEps = 0;
sdivarci 0:0061165683ee 41 static int txFifoNum = 1;
sdivarci 0:0061165683ee 42
sdivarci 0:0061165683ee 43 static void USBD_ResetEndpoints(void);
sdivarci 0:0061165683ee 44 extern USB_Status_TypeDef USBDHAL_ReconfigureFifos( uint32_t totalRxFifoSize,
sdivarci 0:0061165683ee 45 uint32_t totalTxFifoSize );
sdivarci 0:0061165683ee 46 #ifndef __MBED__
sdivarci 0:0061165683ee 47 static const char *stateNames[] =
sdivarci 0:0061165683ee 48 {
sdivarci 0:0061165683ee 49 [ USBD_STATE_NONE ] = "NONE ",
sdivarci 0:0061165683ee 50 [ USBD_STATE_ATTACHED ] = "ATTACHED ",
sdivarci 0:0061165683ee 51 [ USBD_STATE_POWERED ] = "POWERED ",
sdivarci 0:0061165683ee 52 [ USBD_STATE_DEFAULT ] = "DEFAULT ",
sdivarci 0:0061165683ee 53 [ USBD_STATE_ADDRESSED ] = "ADDRESSED ",
sdivarci 0:0061165683ee 54 [ USBD_STATE_CONFIGURED ] = "CONFIGURED",
sdivarci 0:0061165683ee 55 [ USBD_STATE_SUSPENDED ] = "SUSPENDED ",
sdivarci 0:0061165683ee 56 [ USBD_STATE_LASTMARKER ] = "UNDEFINED "
sdivarci 0:0061165683ee 57 };
sdivarci 0:0061165683ee 58 #endif
sdivarci 0:0061165683ee 59
sdivarci 0:0061165683ee 60 /** @endcond */
sdivarci 0:0061165683ee 61
sdivarci 0:0061165683ee 62 /***************************************************************************//**
sdivarci 0:0061165683ee 63 * @brief
sdivarci 0:0061165683ee 64 * Abort all pending transfers.
sdivarci 0:0061165683ee 65 *
sdivarci 0:0061165683ee 66 * @details
sdivarci 0:0061165683ee 67 * Aborts transfers for all endpoints currently in use. Pending
sdivarci 0:0061165683ee 68 * transfers on the default endpoint (EP0) are not aborted.
sdivarci 0:0061165683ee 69 ******************************************************************************/
sdivarci 0:0061165683ee 70 void USBD_AbortAllTransfers( void )
sdivarci 0:0061165683ee 71 {
sdivarci 0:0061165683ee 72 INT_Disable();
sdivarci 0:0061165683ee 73 USBDHAL_AbortAllTransfers( USB_STATUS_EP_ABORTED );
sdivarci 0:0061165683ee 74 INT_Enable();
sdivarci 0:0061165683ee 75 }
sdivarci 0:0061165683ee 76
sdivarci 0:0061165683ee 77 /***************************************************************************//**
sdivarci 0:0061165683ee 78 * @brief
sdivarci 0:0061165683ee 79 * Abort a pending transfer on a specific endpoint.
sdivarci 0:0061165683ee 80 *
sdivarci 0:0061165683ee 81 * @param[in] epAddr
sdivarci 0:0061165683ee 82 * The address of the endpoint to abort.
sdivarci 0:0061165683ee 83 ******************************************************************************/
sdivarci 0:0061165683ee 84 int USBD_AbortTransfer( int epAddr )
sdivarci 0:0061165683ee 85 {
sdivarci 0:0061165683ee 86 USB_XferCompleteCb_TypeDef callback;
sdivarci 0:0061165683ee 87 USBD_Ep_TypeDef *ep = USBD_GetEpFromAddr( epAddr );
sdivarci 0:0061165683ee 88
sdivarci 0:0061165683ee 89 if ( ep == NULL )
sdivarci 0:0061165683ee 90 {
sdivarci 0:0061165683ee 91 DEBUG_USB_API_PUTS( "\nUSBD_AbortTransfer(), Illegal endpoint" );
sdivarci 0:0061165683ee 92 EFM_ASSERT( false );
sdivarci 0:0061165683ee 93 return USB_STATUS_ILLEGAL;
sdivarci 0:0061165683ee 94 }
sdivarci 0:0061165683ee 95
sdivarci 0:0061165683ee 96 if ( ep->num == 0 )
sdivarci 0:0061165683ee 97 {
sdivarci 0:0061165683ee 98 DEBUG_USB_API_PUTS( "\nUSBD_AbortTransfer(), Illegal endpoint" );
sdivarci 0:0061165683ee 99 EFM_ASSERT( false );
sdivarci 0:0061165683ee 100 return USB_STATUS_ILLEGAL;
sdivarci 0:0061165683ee 101 }
sdivarci 0:0061165683ee 102
sdivarci 0:0061165683ee 103 INT_Disable();
sdivarci 0:0061165683ee 104 if ( ep->state == D_EP_IDLE )
sdivarci 0:0061165683ee 105 {
sdivarci 0:0061165683ee 106 INT_Enable();
sdivarci 0:0061165683ee 107 return USB_STATUS_OK;
sdivarci 0:0061165683ee 108 }
sdivarci 0:0061165683ee 109
sdivarci 0:0061165683ee 110 USBD_AbortEp( ep );
sdivarci 0:0061165683ee 111
sdivarci 0:0061165683ee 112 ep->state = D_EP_IDLE;
sdivarci 0:0061165683ee 113 if ( ep->xferCompleteCb )
sdivarci 0:0061165683ee 114 {
sdivarci 0:0061165683ee 115 callback = ep->xferCompleteCb;
sdivarci 0:0061165683ee 116 ep->xferCompleteCb = NULL;
sdivarci 0:0061165683ee 117
sdivarci 0:0061165683ee 118 if ( ( dev->lastState == USBD_STATE_CONFIGURED ) &&
sdivarci 0:0061165683ee 119 ( dev->state == USBD_STATE_ADDRESSED ) )
sdivarci 0:0061165683ee 120 {
sdivarci 0:0061165683ee 121 USBDHAL_DeactivateEp( ep );
sdivarci 0:0061165683ee 122 }
sdivarci 0:0061165683ee 123
sdivarci 0:0061165683ee 124 DEBUG_TRACE_ABORT( USB_STATUS_EP_ABORTED );
sdivarci 0:0061165683ee 125 callback( USB_STATUS_EP_ABORTED, ep->xferred, ep->remaining );
sdivarci 0:0061165683ee 126 }
sdivarci 0:0061165683ee 127
sdivarci 0:0061165683ee 128 INT_Enable();
sdivarci 0:0061165683ee 129 return USB_STATUS_OK;
sdivarci 0:0061165683ee 130 }
sdivarci 0:0061165683ee 131
sdivarci 0:0061165683ee 132 /***************************************************************************//**
sdivarci 0:0061165683ee 133 * @brief
sdivarci 0:0061165683ee 134 * Start USB device operation.
sdivarci 0:0061165683ee 135 *
sdivarci 0:0061165683ee 136 * @details
sdivarci 0:0061165683ee 137 * Device operation is started by connecting a pullup resistor on the
sdivarci 0:0061165683ee 138 * appropriate USB data line.
sdivarci 0:0061165683ee 139 ******************************************************************************/
sdivarci 0:0061165683ee 140 void USBD_Connect( void )
sdivarci 0:0061165683ee 141 {
sdivarci 0:0061165683ee 142 INT_Disable();
sdivarci 0:0061165683ee 143 USBDHAL_Connect();
sdivarci 0:0061165683ee 144 INT_Enable();
sdivarci 0:0061165683ee 145 }
sdivarci 0:0061165683ee 146
sdivarci 0:0061165683ee 147 /***************************************************************************//**
sdivarci 0:0061165683ee 148 * @brief
sdivarci 0:0061165683ee 149 * Stop USB device operation.
sdivarci 0:0061165683ee 150 *
sdivarci 0:0061165683ee 151 * @details
sdivarci 0:0061165683ee 152 * Device operation is stopped by disconnecting the pullup resistor from the
sdivarci 0:0061165683ee 153 * appropriate USB data line. Often referred to as a "soft" disconnect.
sdivarci 0:0061165683ee 154 ******************************************************************************/
sdivarci 0:0061165683ee 155 void USBD_Disconnect( void )
sdivarci 0:0061165683ee 156 {
sdivarci 0:0061165683ee 157 INT_Disable();
sdivarci 0:0061165683ee 158 USBDHAL_Disconnect();
sdivarci 0:0061165683ee 159 INT_Enable();
sdivarci 0:0061165683ee 160 }
sdivarci 0:0061165683ee 161
sdivarci 0:0061165683ee 162 /***************************************************************************//**
sdivarci 0:0061165683ee 163 * @brief
sdivarci 0:0061165683ee 164 * Check if an endpoint is busy doing a transfer.
sdivarci 0:0061165683ee 165 *
sdivarci 0:0061165683ee 166 * @param[in] epAddr
sdivarci 0:0061165683ee 167 * The address of the endpoint to check.
sdivarci 0:0061165683ee 168 *
sdivarci 0:0061165683ee 169 * @return
sdivarci 0:0061165683ee 170 * True if endpoint is busy, false otherwise.
sdivarci 0:0061165683ee 171 ******************************************************************************/
sdivarci 0:0061165683ee 172 bool USBD_EpIsBusy( int epAddr )
sdivarci 0:0061165683ee 173 {
sdivarci 0:0061165683ee 174 USBD_Ep_TypeDef *ep = USBD_GetEpFromAddr( epAddr );
sdivarci 0:0061165683ee 175
sdivarci 0:0061165683ee 176 if ( ep == NULL )
sdivarci 0:0061165683ee 177 {
sdivarci 0:0061165683ee 178 DEBUG_USB_API_PUTS( "\nUSBD_EpIsBusy(), Illegal endpoint" );
sdivarci 0:0061165683ee 179 EFM_ASSERT( false );
sdivarci 0:0061165683ee 180 return USB_STATUS_ILLEGAL;
sdivarci 0:0061165683ee 181 }
sdivarci 0:0061165683ee 182
sdivarci 0:0061165683ee 183 if ( ep->state == D_EP_IDLE )
sdivarci 0:0061165683ee 184 return false;
sdivarci 0:0061165683ee 185
sdivarci 0:0061165683ee 186 return true;
sdivarci 0:0061165683ee 187 }
sdivarci 0:0061165683ee 188
sdivarci 0:0061165683ee 189 /***************************************************************************//**
sdivarci 0:0061165683ee 190 * @brief
sdivarci 0:0061165683ee 191 * Get current USB device state.
sdivarci 0:0061165683ee 192 *
sdivarci 0:0061165683ee 193 * @return
sdivarci 0:0061165683ee 194 * Device USB state. See @ref USBD_State_TypeDef.
sdivarci 0:0061165683ee 195 ******************************************************************************/
sdivarci 0:0061165683ee 196 USBD_State_TypeDef USBD_GetUsbState( void )
sdivarci 0:0061165683ee 197 {
sdivarci 0:0061165683ee 198 return dev->state;
sdivarci 0:0061165683ee 199 }
sdivarci 0:0061165683ee 200
sdivarci 0:0061165683ee 201 /***************************************************************************//**
sdivarci 0:0061165683ee 202 * @brief
sdivarci 0:0061165683ee 203 * Get a string naming a device USB state.
sdivarci 0:0061165683ee 204 *
sdivarci 0:0061165683ee 205 * @param[in] state
sdivarci 0:0061165683ee 206 * Device USB state. See @ref USBD_State_TypeDef.
sdivarci 0:0061165683ee 207 *
sdivarci 0:0061165683ee 208 * @return
sdivarci 0:0061165683ee 209 * State name string pointer.
sdivarci 0:0061165683ee 210 ******************************************************************************/
sdivarci 0:0061165683ee 211 const char *USBD_GetUsbStateName( USBD_State_TypeDef state )
sdivarci 0:0061165683ee 212 {
sdivarci 0:0061165683ee 213 if ( state > USBD_STATE_LASTMARKER )
sdivarci 0:0061165683ee 214 state = USBD_STATE_LASTMARKER;
sdivarci 0:0061165683ee 215
sdivarci 0:0061165683ee 216 #ifndef __MBED__
sdivarci 0:0061165683ee 217 return stateNames[ state ];
sdivarci 0:0061165683ee 218 #else
sdivarci 0:0061165683ee 219 return NULL;
sdivarci 0:0061165683ee 220 #endif
sdivarci 0:0061165683ee 221 }
sdivarci 0:0061165683ee 222
sdivarci 0:0061165683ee 223 /***************************************************************************//**
sdivarci 0:0061165683ee 224 * @brief
sdivarci 0:0061165683ee 225 * Initializes USB device hardware and internal protocol stack data structures,
sdivarci 0:0061165683ee 226 * then connects the data-line (D+ or D-) pullup resistor to signal host that
sdivarci 0:0061165683ee 227 * enumeration can begin.
sdivarci 0:0061165683ee 228 *
sdivarci 0:0061165683ee 229 * @note
sdivarci 0:0061165683ee 230 * You may later use @ref USBD_Disconnect() and @ref USBD_Connect() to force
sdivarci 0:0061165683ee 231 * reenumeration.
sdivarci 0:0061165683ee 232 *
sdivarci 0:0061165683ee 233 * @param[in] p
sdivarci 0:0061165683ee 234 * Pointer to device initialization struct. See @ref USBD_Init_TypeDef.
sdivarci 0:0061165683ee 235 *
sdivarci 0:0061165683ee 236 * @return
sdivarci 0:0061165683ee 237 * @ref USB_STATUS_OK on success, else an appropriate error code.
sdivarci 0:0061165683ee 238 ******************************************************************************/
sdivarci 0:0061165683ee 239 int USBD_Init( const USBD_Init_TypeDef *p )
sdivarci 0:0061165683ee 240 {
sdivarci 0:0061165683ee 241 USBD_Ep_TypeDef *ep;
sdivarci 0:0061165683ee 242
sdivarci 0:0061165683ee 243 #if !defined( USB_CORECLK_HFRCO ) || !defined( CMU_OSCENCMD_USHFRCOEN )
sdivarci 0:0061165683ee 244 /* Devices supporting crystal-less USB can use HFRCO or HFXO as core clock. */
sdivarci 0:0061165683ee 245 /* All other devices must use HFXO as core clock. */
sdivarci 0:0061165683ee 246 if ( CMU_ClockSelectGet( cmuClock_HF ) != cmuSelect_HFXO )
sdivarci 0:0061165683ee 247 {
sdivarci 0:0061165683ee 248 CMU_ClockSelectSet( cmuClock_HF, cmuSelect_HFXO );
sdivarci 0:0061165683ee 249 }
sdivarci 0:0061165683ee 250 #endif
sdivarci 0:0061165683ee 251
sdivarci 0:0061165683ee 252 #if !defined( CMU_OSCENCMD_USHFRCOEN )
sdivarci 0:0061165683ee 253 #if ( USB_USBC_32kHz_CLK == USB_USBC_32kHz_CLK_LFXO )
sdivarci 0:0061165683ee 254 CMU_OscillatorEnable(cmuOsc_LFXO, true, false);
sdivarci 0:0061165683ee 255 #else
sdivarci 0:0061165683ee 256 CMU_OscillatorEnable(cmuOsc_LFRCO, true, false);
sdivarci 0:0061165683ee 257 #endif
sdivarci 0:0061165683ee 258
sdivarci 0:0061165683ee 259 #else
sdivarci 0:0061165683ee 260 CMU_ClockEnable(cmuClock_CORELE, true);
sdivarci 0:0061165683ee 261 /* LFC clock is needed to detect USB suspend when LEMIDLE is activated. */
sdivarci 0:0061165683ee 262 #if ( USB_USBC_32kHz_CLK == USB_USBC_32kHz_CLK_LFXO )
sdivarci 0:0061165683ee 263 CMU_ClockSelectSet(cmuClock_LFC, cmuSelect_LFXO);
sdivarci 0:0061165683ee 264 #else
sdivarci 0:0061165683ee 265 CMU_ClockSelectSet(cmuClock_LFC, cmuSelect_LFRCO);
sdivarci 0:0061165683ee 266 #endif
sdivarci 0:0061165683ee 267 CMU_ClockEnable(cmuClock_USBLE, true);
sdivarci 0:0061165683ee 268 #endif
sdivarci 0:0061165683ee 269
sdivarci 0:0061165683ee 270 USBTIMER_Init();
sdivarci 0:0061165683ee 271
sdivarci 0:0061165683ee 272 memset( dev, 0, sizeof( USBD_Device_TypeDef ) );
sdivarci 0:0061165683ee 273
sdivarci 0:0061165683ee 274 dev->setup = dev->setupPkt;
sdivarci 0:0061165683ee 275 dev->state = USBD_STATE_LASTMARKER;
sdivarci 0:0061165683ee 276 dev->savedState = USBD_STATE_NONE;
sdivarci 0:0061165683ee 277 dev->lastState = USBD_STATE_NONE;
sdivarci 0:0061165683ee 278 dev->callbacks = p->callbacks;
sdivarci 0:0061165683ee 279 dev->remoteWakeupEnabled = false;
sdivarci 0:0061165683ee 280
sdivarci 0:0061165683ee 281 /* Initialize EP0 */
sdivarci 0:0061165683ee 282
sdivarci 0:0061165683ee 283 ep = &dev->ep[ 0 ];
sdivarci 0:0061165683ee 284 ep->in = false;
sdivarci 0:0061165683ee 285 ep->buf = NULL;
sdivarci 0:0061165683ee 286 ep->num = 0;
sdivarci 0:0061165683ee 287 ep->mask = 1;
sdivarci 0:0061165683ee 288 ep->addr = 0;
sdivarci 0:0061165683ee 289 ep->type = USB_EPTYPE_CTRL;
sdivarci 0:0061165683ee 290 ep->txFifoNum = 0;
sdivarci 0:0061165683ee 291
sdivarci 0:0061165683ee 292 /* FIXME! */
sdivarci 0:0061165683ee 293 ep->packetSize = 64;
sdivarci 0:0061165683ee 294 dev->ep0MpsCode = _USB_DOEP0CTL_MPS_64B;
sdivarci 0:0061165683ee 295
sdivarci 0:0061165683ee 296 ep->remaining = 0;
sdivarci 0:0061165683ee 297 ep->xferred = 0;
sdivarci 0:0061165683ee 298 ep->state = D_EP_IDLE;
sdivarci 0:0061165683ee 299 ep->xferCompleteCb = NULL;
sdivarci 0:0061165683ee 300 ep->fifoSize = ep->packetSize / 4;
sdivarci 0:0061165683ee 301
sdivarci 0:0061165683ee 302 totalTxFifoSize = ep->fifoSize * p->bufferingMultiplier[ 0 ];
sdivarci 0:0061165683ee 303 totalRxFifoSize = (ep->fifoSize + 1) * p->bufferingMultiplier[ 0 ];
sdivarci 0:0061165683ee 304
sdivarci 0:0061165683ee 305 /* Rx-FIFO size: SETUP packets : 4*n + 6 n=#CTRL EP's
sdivarci 0:0061165683ee 306 * GOTNAK : 1
sdivarci 0:0061165683ee 307 * Status info : 2*n n=#OUT EP's (EP0 included) in HW
sdivarci 0:0061165683ee 308 */
sdivarci 0:0061165683ee 309 totalRxFifoSize += 10 + 1 + ( 2 * (MAX_NUM_OUT_EPS + 1) );
sdivarci 0:0061165683ee 310
sdivarci 0:0061165683ee 311 INT_Disable();
sdivarci 0:0061165683ee 312
sdivarci 0:0061165683ee 313 /* Enable USB clock */
sdivarci 0:0061165683ee 314 CMU->HFCORECLKEN0 |= CMU_HFCORECLKEN0_USB | CMU_HFCORECLKEN0_USBC;
sdivarci 0:0061165683ee 315
sdivarci 0:0061165683ee 316 #if defined( CMU_OSCENCMD_USHFRCOEN )
sdivarci 0:0061165683ee 317 CMU->USHFRCOCONF = CMU_USHFRCOCONF_BAND_48MHZ;
sdivarci 0:0061165683ee 318 CMU_ClockSelectSet( cmuClock_USBC, cmuSelect_USHFRCO );
sdivarci 0:0061165683ee 319
sdivarci 0:0061165683ee 320 /* Enable USHFRCO Clock Recovery mode. */
sdivarci 0:0061165683ee 321 CMU->USBCRCTRL |= CMU_USBCRCTRL_EN;
sdivarci 0:0061165683ee 322
sdivarci 0:0061165683ee 323 /* Turn on Low Energy Mode (LEM) features. */
sdivarci 0:0061165683ee 324 USB->CTRL = USB_CTRL_LEMOSCCTRL_GATE
sdivarci 0:0061165683ee 325 | USB_CTRL_LEMIDLEEN
sdivarci 0:0061165683ee 326 | USB_CTRL_LEMPHYCTRL;
sdivarci 0:0061165683ee 327 #else
sdivarci 0:0061165683ee 328 CMU_ClockSelectSet( cmuClock_USBC, cmuSelect_HFCLK );
sdivarci 0:0061165683ee 329 #endif
sdivarci 0:0061165683ee 330
sdivarci 0:0061165683ee 331 USBHAL_DisableGlobalInt();
sdivarci 0:0061165683ee 332
sdivarci 0:0061165683ee 333 if ( USBDHAL_CoreInit( totalRxFifoSize, totalTxFifoSize ) == USB_STATUS_OK )
sdivarci 0:0061165683ee 334 {
sdivarci 0:0061165683ee 335 USBDHAL_EnableUsbResetAndSuspendInt();
sdivarci 0:0061165683ee 336 USBHAL_EnableGlobalInt();
sdivarci 0:0061165683ee 337 NVIC_ClearPendingIRQ( USB_IRQn );
sdivarci 0:0061165683ee 338 NVIC_EnableIRQ( USB_IRQn );
sdivarci 0:0061165683ee 339 }
sdivarci 0:0061165683ee 340 else
sdivarci 0:0061165683ee 341 {
sdivarci 0:0061165683ee 342 INT_Enable();
sdivarci 0:0061165683ee 343 DEBUG_USB_API_PUTS( "\nUSBD_Init(), FIFO setup error" );
sdivarci 0:0061165683ee 344 EFM_ASSERT( false );
sdivarci 0:0061165683ee 345 return USB_STATUS_ILLEGAL;
sdivarci 0:0061165683ee 346 }
sdivarci 0:0061165683ee 347
sdivarci 0:0061165683ee 348 #if ( USB_PWRSAVE_MODE & USB_PWRSAVE_MODE_ONVBUSOFF )
sdivarci 0:0061165683ee 349 if ( USBHAL_VbusIsOn() )
sdivarci 0:0061165683ee 350 {
sdivarci 0:0061165683ee 351 USBD_SetUsbState( USBD_STATE_POWERED );
sdivarci 0:0061165683ee 352 }
sdivarci 0:0061165683ee 353 else
sdivarci 0:0061165683ee 354 #endif
sdivarci 0:0061165683ee 355 {
sdivarci 0:0061165683ee 356 USBD_SetUsbState( USBD_STATE_NONE );
sdivarci 0:0061165683ee 357 }
sdivarci 0:0061165683ee 358
sdivarci 0:0061165683ee 359 INT_Enable();
sdivarci 0:0061165683ee 360 return USB_STATUS_OK;
sdivarci 0:0061165683ee 361 }
sdivarci 0:0061165683ee 362
sdivarci 0:0061165683ee 363 /***************************************************************************//**
sdivarci 0:0061165683ee 364 * @brief
sdivarci 0:0061165683ee 365 * Start a read (OUT) transfer on an endpoint.
sdivarci 0:0061165683ee 366 *
sdivarci 0:0061165683ee 367 * @note
sdivarci 0:0061165683ee 368 * The transfer buffer length must be a multiple of 4 bytes in length and
sdivarci 0:0061165683ee 369 * WORD (4 byte) aligned. When allocating the buffer, round buffer length up.
sdivarci 0:0061165683ee 370 * If it is possible that the host will send more data than your device
sdivarci 0:0061165683ee 371 * expects, round buffer size up to the next multiple of maxpacket size.
sdivarci 0:0061165683ee 372 *
sdivarci 0:0061165683ee 373 * @param[in] epAddr
sdivarci 0:0061165683ee 374 * Endpoint address.
sdivarci 0:0061165683ee 375 *
sdivarci 0:0061165683ee 376 * @param[in] data
sdivarci 0:0061165683ee 377 * Pointer to transfer data buffer.
sdivarci 0:0061165683ee 378 *
sdivarci 0:0061165683ee 379 * @param[in] byteCount
sdivarci 0:0061165683ee 380 * Transfer length.
sdivarci 0:0061165683ee 381 *
sdivarci 0:0061165683ee 382 * @param[in] callback
sdivarci 0:0061165683ee 383 * Function to be called on transfer completion. Supply NULL if no callback
sdivarci 0:0061165683ee 384 * is needed. See @ref USB_XferCompleteCb_TypeDef.
sdivarci 0:0061165683ee 385 *
sdivarci 0:0061165683ee 386 * @return
sdivarci 0:0061165683ee 387 * @ref USB_STATUS_OK on success, else an appropriate error code.
sdivarci 0:0061165683ee 388 ******************************************************************************/
sdivarci 0:0061165683ee 389 int USBD_Read( int epAddr, void *data, int byteCount,
sdivarci 0:0061165683ee 390 USB_XferCompleteCb_TypeDef callback )
sdivarci 0:0061165683ee 391 {
sdivarci 0:0061165683ee 392 USBD_Ep_TypeDef *ep = USBD_GetEpFromAddr( epAddr );
sdivarci 0:0061165683ee 393
sdivarci 0:0061165683ee 394 USB_PRINTF("USBD: Read addr %x, data %p, size %d, cb 0x%lx\n",
sdivarci 0:0061165683ee 395 epAddr, data, byteCount, (uint32_t)callback);
sdivarci 0:0061165683ee 396
sdivarci 0:0061165683ee 397 if ( ep == NULL )
sdivarci 0:0061165683ee 398 {
sdivarci 0:0061165683ee 399 DEBUG_USB_API_PUTS( "\nUSBD_Read(), Illegal endpoint" );
sdivarci 0:0061165683ee 400 EFM_ASSERT( false );
sdivarci 0:0061165683ee 401 return USB_STATUS_ILLEGAL;
sdivarci 0:0061165683ee 402 }
sdivarci 0:0061165683ee 403
sdivarci 0:0061165683ee 404 if ( ( byteCount > MAX_XFER_LEN ) ||
sdivarci 0:0061165683ee 405 ( ( byteCount / ep->packetSize ) > MAX_PACKETS_PR_XFER ) )
sdivarci 0:0061165683ee 406 {
sdivarci 0:0061165683ee 407 DEBUG_USB_API_PUTS( "\nUSBD_Read(), Illegal transfer size" );
sdivarci 0:0061165683ee 408 EFM_ASSERT( false );
sdivarci 0:0061165683ee 409 return USB_STATUS_ILLEGAL;
sdivarci 0:0061165683ee 410 }
sdivarci 0:0061165683ee 411
sdivarci 0:0061165683ee 412 if ( (uint32_t)data & 3 )
sdivarci 0:0061165683ee 413 {
sdivarci 0:0061165683ee 414 DEBUG_USB_API_PUTS( "\nUSBD_Read(), Misaligned data buffer" );
sdivarci 0:0061165683ee 415 EFM_ASSERT( false );
sdivarci 0:0061165683ee 416 return USB_STATUS_ILLEGAL;
sdivarci 0:0061165683ee 417 }
sdivarci 0:0061165683ee 418
sdivarci 0:0061165683ee 419 INT_Disable();
sdivarci 0:0061165683ee 420 if ( USBDHAL_EpIsStalled( ep ) )
sdivarci 0:0061165683ee 421 {
sdivarci 0:0061165683ee 422 INT_Enable();
sdivarci 0:0061165683ee 423 DEBUG_USB_API_PUTS( "\nUSBD_Read(), Endpoint is halted" );
sdivarci 0:0061165683ee 424 return USB_STATUS_EP_STALLED;
sdivarci 0:0061165683ee 425 }
sdivarci 0:0061165683ee 426
sdivarci 0:0061165683ee 427 if ( ep->state != D_EP_IDLE )
sdivarci 0:0061165683ee 428 {
sdivarci 0:0061165683ee 429 INT_Enable();
sdivarci 0:0061165683ee 430 DEBUG_USB_API_PUTS( "\nUSBD_Read(), Endpoint is busy" );
sdivarci 0:0061165683ee 431 return USB_STATUS_EP_BUSY;
sdivarci 0:0061165683ee 432 }
sdivarci 0:0061165683ee 433
sdivarci 0:0061165683ee 434 if ( ( ep->num > 0 ) && ( USBD_GetUsbState() != USBD_STATE_CONFIGURED ) )
sdivarci 0:0061165683ee 435 {
sdivarci 0:0061165683ee 436 INT_Enable();
sdivarci 0:0061165683ee 437 DEBUG_USB_API_PUTS( "\nUSBD_Read(), Device not configured" );
sdivarci 0:0061165683ee 438 return USB_STATUS_DEVICE_UNCONFIGURED;
sdivarci 0:0061165683ee 439 }
sdivarci 0:0061165683ee 440
sdivarci 0:0061165683ee 441 ep->buf = (uint8_t*)data;
sdivarci 0:0061165683ee 442 ep->remaining = byteCount;
sdivarci 0:0061165683ee 443 ep->xferred = 0;
sdivarci 0:0061165683ee 444
sdivarci 0:0061165683ee 445 if ( ep->num == 0 )
sdivarci 0:0061165683ee 446 {
sdivarci 0:0061165683ee 447 ep->in = false;
sdivarci 0:0061165683ee 448 }
sdivarci 0:0061165683ee 449 else if ( ep->in != false )
sdivarci 0:0061165683ee 450 {
sdivarci 0:0061165683ee 451 INT_Enable();
sdivarci 0:0061165683ee 452 DEBUG_USB_API_PUTS( "\nUSBD_Read(), Illegal EP direction" );
sdivarci 0:0061165683ee 453 EFM_ASSERT( false );
sdivarci 0:0061165683ee 454 return USB_STATUS_ILLEGAL;
sdivarci 0:0061165683ee 455 }
sdivarci 0:0061165683ee 456
sdivarci 0:0061165683ee 457 ep->state = D_EP_RECEIVING;
sdivarci 0:0061165683ee 458 ep->xferCompleteCb = callback;
sdivarci 0:0061165683ee 459
sdivarci 0:0061165683ee 460 USBD_ArmEp( ep );
sdivarci 0:0061165683ee 461 INT_Enable();
sdivarci 0:0061165683ee 462 return USB_STATUS_OK;
sdivarci 0:0061165683ee 463 }
sdivarci 0:0061165683ee 464
sdivarci 0:0061165683ee 465 /***************************************************************************//**
sdivarci 0:0061165683ee 466 * @brief
sdivarci 0:0061165683ee 467 * Perform a remote wakeup signalling sequence.
sdivarci 0:0061165683ee 468 *
sdivarci 0:0061165683ee 469 * @note
sdivarci 0:0061165683ee 470 * It is the responsibility of the application to ensure that remote wakeup
sdivarci 0:0061165683ee 471 * is not attempted before the device has been suspended for at least 5
sdivarci 0:0061165683ee 472 * miliseconds. This function should not be called from within an interrupt
sdivarci 0:0061165683ee 473 * handler.
sdivarci 0:0061165683ee 474 *
sdivarci 0:0061165683ee 475 * @return
sdivarci 0:0061165683ee 476 * @ref USB_STATUS_OK on success, else an appropriate error code.
sdivarci 0:0061165683ee 477 ******************************************************************************/
sdivarci 0:0061165683ee 478 int USBD_RemoteWakeup( void )
sdivarci 0:0061165683ee 479 {
sdivarci 0:0061165683ee 480 INT_Disable();
sdivarci 0:0061165683ee 481
sdivarci 0:0061165683ee 482 if ( ( dev->state != USBD_STATE_SUSPENDED ) ||
sdivarci 0:0061165683ee 483 ( dev->remoteWakeupEnabled == false ) )
sdivarci 0:0061165683ee 484 {
sdivarci 0:0061165683ee 485 INT_Enable();
sdivarci 0:0061165683ee 486 DEBUG_USB_API_PUTS( "\nUSBD_RemoteWakeup(), Illegal remote wakeup" );
sdivarci 0:0061165683ee 487 return USB_STATUS_ILLEGAL;
sdivarci 0:0061165683ee 488 }
sdivarci 0:0061165683ee 489
sdivarci 0:0061165683ee 490 USBDHAL_SetRemoteWakeup();
sdivarci 0:0061165683ee 491 INT_Enable();
sdivarci 0:0061165683ee 492 USBTIMER_DelayMs( 10 );
sdivarci 0:0061165683ee 493 INT_Disable();
sdivarci 0:0061165683ee 494 USBDHAL_ClearRemoteWakeup();
sdivarci 0:0061165683ee 495 INT_Enable();
sdivarci 0:0061165683ee 496 return USB_STATUS_OK;
sdivarci 0:0061165683ee 497 }
sdivarci 0:0061165683ee 498
sdivarci 0:0061165683ee 499 /***************************************************************************//**
sdivarci 0:0061165683ee 500 * @brief
sdivarci 0:0061165683ee 501 * Check if it is ok to enter energy mode EM2.
sdivarci 0:0061165683ee 502 *
sdivarci 0:0061165683ee 503 * @note
sdivarci 0:0061165683ee 504 * Before entering EM2 both the USB hardware and the USB stack must be in a
sdivarci 0:0061165683ee 505 * certain state, this function checks if all conditions for entering EM2
sdivarci 0:0061165683ee 506 * is met.
sdivarci 0:0061165683ee 507 * Refer to the @ref usb_device_powersave section for more information.
sdivarci 0:0061165683ee 508 *
sdivarci 0:0061165683ee 509 * @return
sdivarci 0:0061165683ee 510 * True if ok to enter EM2, false otherwise.
sdivarci 0:0061165683ee 511 ******************************************************************************/
sdivarci 0:0061165683ee 512 bool USBD_SafeToEnterEM2( void )
sdivarci 0:0061165683ee 513 {
sdivarci 0:0061165683ee 514 #if ( USB_PWRSAVE_MODE )
sdivarci 0:0061165683ee 515 return USBD_poweredDown ? true : false;
sdivarci 0:0061165683ee 516 #else
sdivarci 0:0061165683ee 517 return false;
sdivarci 0:0061165683ee 518 #endif
sdivarci 0:0061165683ee 519 }
sdivarci 0:0061165683ee 520
sdivarci 0:0061165683ee 521 /** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
sdivarci 0:0061165683ee 522
sdivarci 0:0061165683ee 523 void USBD_SetUsbState( USBD_State_TypeDef newState )
sdivarci 0:0061165683ee 524 {
sdivarci 0:0061165683ee 525 USBD_State_TypeDef currentState;
sdivarci 0:0061165683ee 526
sdivarci 0:0061165683ee 527 currentState = dev->state;
sdivarci 0:0061165683ee 528 if ( newState == USBD_STATE_SUSPENDED )
sdivarci 0:0061165683ee 529 {
sdivarci 0:0061165683ee 530 dev->savedState = currentState;
sdivarci 0:0061165683ee 531 }
sdivarci 0:0061165683ee 532
sdivarci 0:0061165683ee 533 dev->lastState = dev->state;
sdivarci 0:0061165683ee 534 dev->state = newState;
sdivarci 0:0061165683ee 535
sdivarci 0:0061165683ee 536 if ( ( dev->callbacks->usbStateChange ) &&
sdivarci 0:0061165683ee 537 ( currentState != newState ) )
sdivarci 0:0061165683ee 538 {
sdivarci 0:0061165683ee 539 /* When we transition to a state "lower" than CONFIGURED
sdivarci 0:0061165683ee 540 * we must reset the endpoint data
sdivarci 0:0061165683ee 541 */
sdivarci 0:0061165683ee 542 if ( (dev->lastState == USBD_STATE_CONFIGURED ||
sdivarci 0:0061165683ee 543 dev->lastState == USBD_STATE_SUSPENDED ) &&
sdivarci 0:0061165683ee 544 dev->state < USBD_STATE_CONFIGURED )
sdivarci 0:0061165683ee 545 {
sdivarci 0:0061165683ee 546 USBD_ResetEndpoints();
sdivarci 0:0061165683ee 547 }
sdivarci 0:0061165683ee 548
sdivarci 0:0061165683ee 549 dev->callbacks->usbStateChange( currentState, newState );
sdivarci 0:0061165683ee 550 }
sdivarci 0:0061165683ee 551 }
sdivarci 0:0061165683ee 552
sdivarci 0:0061165683ee 553 /** @endcond */
sdivarci 0:0061165683ee 554
sdivarci 0:0061165683ee 555 /***************************************************************************//**
sdivarci 0:0061165683ee 556 * @brief
sdivarci 0:0061165683ee 557 * Set an endpoint in the stalled (halted) state.
sdivarci 0:0061165683ee 558 *
sdivarci 0:0061165683ee 559 * @param[in] epAddr
sdivarci 0:0061165683ee 560 * The address of the endpoint to stall.
sdivarci 0:0061165683ee 561 *
sdivarci 0:0061165683ee 562 * @return
sdivarci 0:0061165683ee 563 * @ref USB_STATUS_OK on success, else an appropriate error code.
sdivarci 0:0061165683ee 564 ******************************************************************************/
sdivarci 0:0061165683ee 565 int USBD_StallEp( int epAddr )
sdivarci 0:0061165683ee 566 {
sdivarci 0:0061165683ee 567 USB_Status_TypeDef retVal;
sdivarci 0:0061165683ee 568 USBD_Ep_TypeDef *ep = USBD_GetEpFromAddr( epAddr );
sdivarci 0:0061165683ee 569
sdivarci 0:0061165683ee 570 if ( ep == NULL )
sdivarci 0:0061165683ee 571 {
sdivarci 0:0061165683ee 572 DEBUG_USB_API_PUTS( "\nUSBD_StallEp(), Illegal request" );
sdivarci 0:0061165683ee 573 EFM_ASSERT( false );
sdivarci 0:0061165683ee 574 return USB_STATUS_ILLEGAL;
sdivarci 0:0061165683ee 575 }
sdivarci 0:0061165683ee 576
sdivarci 0:0061165683ee 577 if ( ep->num == 0 )
sdivarci 0:0061165683ee 578 {
sdivarci 0:0061165683ee 579 DEBUG_USB_API_PUTS( "\nUSBD_StallEp(), Illegal endpoint" );
sdivarci 0:0061165683ee 580 EFM_ASSERT( false );
sdivarci 0:0061165683ee 581 return USB_STATUS_ILLEGAL;
sdivarci 0:0061165683ee 582 }
sdivarci 0:0061165683ee 583
sdivarci 0:0061165683ee 584 INT_Disable();
sdivarci 0:0061165683ee 585 retVal = USBDHAL_StallEp( ep );
sdivarci 0:0061165683ee 586 INT_Enable();
sdivarci 0:0061165683ee 587
sdivarci 0:0061165683ee 588 if ( retVal != USB_STATUS_OK )
sdivarci 0:0061165683ee 589 {
sdivarci 0:0061165683ee 590 retVal = USB_STATUS_ILLEGAL;
sdivarci 0:0061165683ee 591 }
sdivarci 0:0061165683ee 592
sdivarci 0:0061165683ee 593 return retVal;
sdivarci 0:0061165683ee 594 }
sdivarci 0:0061165683ee 595
sdivarci 0:0061165683ee 596 /***************************************************************************//**
sdivarci 0:0061165683ee 597 * @brief
sdivarci 0:0061165683ee 598 * Stop USB device stack operation.
sdivarci 0:0061165683ee 599 *
sdivarci 0:0061165683ee 600 * @details
sdivarci 0:0061165683ee 601 * The data-line pullup resistor is turned off, USB interrupts are disabled,
sdivarci 0:0061165683ee 602 * and finally the USB pins are disabled.
sdivarci 0:0061165683ee 603 ******************************************************************************/
sdivarci 0:0061165683ee 604 void USBD_Stop( void )
sdivarci 0:0061165683ee 605 {
sdivarci 0:0061165683ee 606 USBD_Disconnect();
sdivarci 0:0061165683ee 607 NVIC_DisableIRQ( USB_IRQn );
sdivarci 0:0061165683ee 608 USBHAL_DisableGlobalInt();
sdivarci 0:0061165683ee 609 USBHAL_DisableUsbInt();
sdivarci 0:0061165683ee 610 USBHAL_DisablePhyPins();
sdivarci 0:0061165683ee 611 USBD_SetUsbState( USBD_STATE_NONE );
sdivarci 0:0061165683ee 612 /* Turn off USB clocks. */
sdivarci 0:0061165683ee 613 CMU->HFCORECLKEN0 &= ~(CMU_HFCORECLKEN0_USB | CMU_HFCORECLKEN0_USBC);
sdivarci 0:0061165683ee 614 }
sdivarci 0:0061165683ee 615
sdivarci 0:0061165683ee 616 /***************************************************************************//**
sdivarci 0:0061165683ee 617 * @brief
sdivarci 0:0061165683ee 618 * Reset stall state on a stalled (halted) endpoint.
sdivarci 0:0061165683ee 619 *
sdivarci 0:0061165683ee 620 * @param[in] epAddr
sdivarci 0:0061165683ee 621 * The address of the endpoint to un-stall.
sdivarci 0:0061165683ee 622 *
sdivarci 0:0061165683ee 623 * @return
sdivarci 0:0061165683ee 624 * @ref USB_STATUS_OK on success, else an appropriate error code.
sdivarci 0:0061165683ee 625 ******************************************************************************/
sdivarci 0:0061165683ee 626 int USBD_UnStallEp( int epAddr )
sdivarci 0:0061165683ee 627 {
sdivarci 0:0061165683ee 628 USB_Status_TypeDef retVal;
sdivarci 0:0061165683ee 629 USBD_Ep_TypeDef *ep = USBD_GetEpFromAddr( epAddr );
sdivarci 0:0061165683ee 630
sdivarci 0:0061165683ee 631 if ( ep == NULL )
sdivarci 0:0061165683ee 632 {
sdivarci 0:0061165683ee 633 DEBUG_USB_API_PUTS( "\nUSBD_UnStallEp(), Illegal request" );
sdivarci 0:0061165683ee 634 EFM_ASSERT( false );
sdivarci 0:0061165683ee 635 return USB_STATUS_ILLEGAL;
sdivarci 0:0061165683ee 636 }
sdivarci 0:0061165683ee 637
sdivarci 0:0061165683ee 638 if ( ep->num == 0 )
sdivarci 0:0061165683ee 639 {
sdivarci 0:0061165683ee 640 DEBUG_USB_API_PUTS( "\nUSBD_UnStallEp(), Illegal endpoint" );
sdivarci 0:0061165683ee 641 EFM_ASSERT( false );
sdivarci 0:0061165683ee 642 return USB_STATUS_ILLEGAL;
sdivarci 0:0061165683ee 643 }
sdivarci 0:0061165683ee 644
sdivarci 0:0061165683ee 645 INT_Disable();
sdivarci 0:0061165683ee 646 retVal = USBDHAL_UnStallEp( ep );
sdivarci 0:0061165683ee 647 INT_Enable();
sdivarci 0:0061165683ee 648
sdivarci 0:0061165683ee 649 if ( retVal != USB_STATUS_OK )
sdivarci 0:0061165683ee 650 {
sdivarci 0:0061165683ee 651 retVal = USB_STATUS_ILLEGAL;
sdivarci 0:0061165683ee 652 }
sdivarci 0:0061165683ee 653
sdivarci 0:0061165683ee 654 return retVal;
sdivarci 0:0061165683ee 655 }
sdivarci 0:0061165683ee 656
sdivarci 0:0061165683ee 657 /***************************************************************************//**
sdivarci 0:0061165683ee 658 * @brief
sdivarci 0:0061165683ee 659 * Start a write (IN) transfer on an endpoint.
sdivarci 0:0061165683ee 660 *
sdivarci 0:0061165683ee 661 * @param[in] epAddr
sdivarci 0:0061165683ee 662 * Endpoint address.
sdivarci 0:0061165683ee 663 *
sdivarci 0:0061165683ee 664 * @param[in] data
sdivarci 0:0061165683ee 665 * Pointer to transfer data buffer. This buffer must be WORD (4 byte) aligned.
sdivarci 0:0061165683ee 666 *
sdivarci 0:0061165683ee 667 * @param[in] byteCount
sdivarci 0:0061165683ee 668 * Transfer length.
sdivarci 0:0061165683ee 669 *
sdivarci 0:0061165683ee 670 * @param[in] callback
sdivarci 0:0061165683ee 671 * Function to be called on transfer completion. Supply NULL if no callback
sdivarci 0:0061165683ee 672 * is needed. See @ref USB_XferCompleteCb_TypeDef.
sdivarci 0:0061165683ee 673 *
sdivarci 0:0061165683ee 674 * @return
sdivarci 0:0061165683ee 675 * @ref USB_STATUS_OK on success, else an appropriate error code.
sdivarci 0:0061165683ee 676 ******************************************************************************/
sdivarci 0:0061165683ee 677 int USBD_Write( int epAddr, void *data, int byteCount,
sdivarci 0:0061165683ee 678 USB_XferCompleteCb_TypeDef callback )
sdivarci 0:0061165683ee 679 {
sdivarci 0:0061165683ee 680 USBD_Ep_TypeDef *ep = USBD_GetEpFromAddr( epAddr );
sdivarci 0:0061165683ee 681
sdivarci 0:0061165683ee 682 USB_PRINTF("USBD: Write addr %x, data %p, size %d, cb 0x%lx\n",
sdivarci 0:0061165683ee 683 epAddr, data, byteCount, (uint32_t)callback);
sdivarci 0:0061165683ee 684
sdivarci 0:0061165683ee 685 if ( ep == NULL )
sdivarci 0:0061165683ee 686 {
sdivarci 0:0061165683ee 687 DEBUG_USB_API_PUTS( "\nUSBD_Write(), Illegal endpoint" );
sdivarci 0:0061165683ee 688 EFM_ASSERT( false );
sdivarci 0:0061165683ee 689 return USB_STATUS_ILLEGAL;
sdivarci 0:0061165683ee 690 }
sdivarci 0:0061165683ee 691
sdivarci 0:0061165683ee 692 if ( ( byteCount > MAX_XFER_LEN ) ||
sdivarci 0:0061165683ee 693 ( ( byteCount / ep->packetSize ) > MAX_PACKETS_PR_XFER ) )
sdivarci 0:0061165683ee 694 {
sdivarci 0:0061165683ee 695 DEBUG_USB_API_PUTS( "\nUSBD_Write(), Illegal transfer size" );
sdivarci 0:0061165683ee 696 EFM_ASSERT( false );
sdivarci 0:0061165683ee 697 return USB_STATUS_ILLEGAL;
sdivarci 0:0061165683ee 698 }
sdivarci 0:0061165683ee 699
sdivarci 0:0061165683ee 700 if ( (uint32_t)data & 3 )
sdivarci 0:0061165683ee 701 {
sdivarci 0:0061165683ee 702 DEBUG_USB_API_PUTS( "\nUSBD_Write(), Misaligned data buffer" );
sdivarci 0:0061165683ee 703 EFM_ASSERT( false );
sdivarci 0:0061165683ee 704 return USB_STATUS_ILLEGAL;
sdivarci 0:0061165683ee 705 }
sdivarci 0:0061165683ee 706
sdivarci 0:0061165683ee 707 INT_Disable();
sdivarci 0:0061165683ee 708 if ( USBDHAL_EpIsStalled( ep ) )
sdivarci 0:0061165683ee 709 {
sdivarci 0:0061165683ee 710 INT_Enable();
sdivarci 0:0061165683ee 711 DEBUG_USB_API_PUTS( "\nUSBD_Write(), Endpoint is halted" );
sdivarci 0:0061165683ee 712 return USB_STATUS_EP_STALLED;
sdivarci 0:0061165683ee 713 }
sdivarci 0:0061165683ee 714
sdivarci 0:0061165683ee 715 if ( ep->state != D_EP_IDLE )
sdivarci 0:0061165683ee 716 {
sdivarci 0:0061165683ee 717 INT_Enable();
sdivarci 0:0061165683ee 718 DEBUG_USB_API_PUTS( "\nUSBD_Write(), Endpoint is busy" );
sdivarci 0:0061165683ee 719 return USB_STATUS_EP_BUSY;
sdivarci 0:0061165683ee 720 }
sdivarci 0:0061165683ee 721
sdivarci 0:0061165683ee 722 if ( ( ep->num > 0 ) && ( USBD_GetUsbState() != USBD_STATE_CONFIGURED ) )
sdivarci 0:0061165683ee 723 {
sdivarci 0:0061165683ee 724 INT_Enable();
sdivarci 0:0061165683ee 725 DEBUG_USB_API_PUTS( "\nUSBD_Write(), Device not configured" );
sdivarci 0:0061165683ee 726 return USB_STATUS_DEVICE_UNCONFIGURED;
sdivarci 0:0061165683ee 727 }
sdivarci 0:0061165683ee 728
sdivarci 0:0061165683ee 729 ep->buf = (uint8_t*)data;
sdivarci 0:0061165683ee 730 ep->remaining = byteCount;
sdivarci 0:0061165683ee 731 ep->xferred = 0;
sdivarci 0:0061165683ee 732
sdivarci 0:0061165683ee 733 if ( ep->num == 0 )
sdivarci 0:0061165683ee 734 {
sdivarci 0:0061165683ee 735 ep->in = true;
sdivarci 0:0061165683ee 736 }
sdivarci 0:0061165683ee 737 else if ( ep->in != true )
sdivarci 0:0061165683ee 738 {
sdivarci 0:0061165683ee 739 INT_Enable();
sdivarci 0:0061165683ee 740 DEBUG_USB_API_PUTS( "\nUSBD_Write(), Illegal EP direction" );
sdivarci 0:0061165683ee 741 EFM_ASSERT( false );
sdivarci 0:0061165683ee 742 return USB_STATUS_ILLEGAL;
sdivarci 0:0061165683ee 743 }
sdivarci 0:0061165683ee 744
sdivarci 0:0061165683ee 745 ep->state = D_EP_TRANSMITTING;
sdivarci 0:0061165683ee 746 ep->xferCompleteCb = callback;
sdivarci 0:0061165683ee 747
sdivarci 0:0061165683ee 748 USBD_ArmEp( ep );
sdivarci 0:0061165683ee 749 INT_Enable();
sdivarci 0:0061165683ee 750 return USB_STATUS_OK;
sdivarci 0:0061165683ee 751 }
sdivarci 0:0061165683ee 752
sdivarci 0:0061165683ee 753 int USBD_SetAddress(uint8_t addr)
sdivarci 0:0061165683ee 754 {
sdivarci 0:0061165683ee 755 int retVal = USB_STATUS_REQ_ERR;
sdivarci 0:0061165683ee 756
sdivarci 0:0061165683ee 757 if ( dev->state == USBD_STATE_DEFAULT )
sdivarci 0:0061165683ee 758 {
sdivarci 0:0061165683ee 759 if ( addr != 0 )
sdivarci 0:0061165683ee 760 {
sdivarci 0:0061165683ee 761 USBD_SetUsbState( USBD_STATE_ADDRESSED );
sdivarci 0:0061165683ee 762 }
sdivarci 0:0061165683ee 763 USBDHAL_SetAddr( addr );
sdivarci 0:0061165683ee 764 retVal = USB_STATUS_OK;
sdivarci 0:0061165683ee 765 }
sdivarci 0:0061165683ee 766 else if ( dev->state == USBD_STATE_ADDRESSED )
sdivarci 0:0061165683ee 767 {
sdivarci 0:0061165683ee 768 if ( addr == 0 )
sdivarci 0:0061165683ee 769 {
sdivarci 0:0061165683ee 770 USBD_SetUsbState( USBD_STATE_DEFAULT );
sdivarci 0:0061165683ee 771 }
sdivarci 0:0061165683ee 772 USBDHAL_SetAddr( addr );
sdivarci 0:0061165683ee 773 retVal = USB_STATUS_OK;
sdivarci 0:0061165683ee 774 }
sdivarci 0:0061165683ee 775
sdivarci 0:0061165683ee 776 return retVal;
sdivarci 0:0061165683ee 777 }
sdivarci 0:0061165683ee 778
sdivarci 0:0061165683ee 779 /***************************************************************************//**
sdivarci 0:0061165683ee 780 * @brief
sdivarci 0:0061165683ee 781 * Query the stall state of an endpoint
sdivarci 0:0061165683ee 782 *
sdivarci 0:0061165683ee 783 * @param[in] epAddr
sdivarci 0:0061165683ee 784 * The address of the endpoint to query.
sdivarci 0:0061165683ee 785 *
sdivarci 0:0061165683ee 786 * @return
sdivarci 0:0061165683ee 787 * True if endpoint is stalled, false otherwise
sdivarci 0:0061165683ee 788 ******************************************************************************/
sdivarci 0:0061165683ee 789 int USBD_EpIsStalled(int epAddr)
sdivarci 0:0061165683ee 790 {
sdivarci 0:0061165683ee 791 USBD_Ep_TypeDef *ep = USBD_GetEpFromAddr( epAddr );
sdivarci 0:0061165683ee 792
sdivarci 0:0061165683ee 793 if( !ep )
sdivarci 0:0061165683ee 794 {
sdivarci 0:0061165683ee 795 return false;
sdivarci 0:0061165683ee 796 }
sdivarci 0:0061165683ee 797
sdivarci 0:0061165683ee 798 return USBDHAL_EpIsStalled(ep);
sdivarci 0:0061165683ee 799 }
sdivarci 0:0061165683ee 800
sdivarci 0:0061165683ee 801 /***************************************************************************//**
sdivarci 0:0061165683ee 802 * @brief
sdivarci 0:0061165683ee 803 * Reset (remove) all client endpoints
sdivarci 0:0061165683ee 804 *
sdivarci 0:0061165683ee 805 * @details
sdivarci 0:0061165683ee 806 * Removes client endpoints, and resets the RX/TX fifos. No endpoints
sdivarci 0:0061165683ee 807 * other than EP0 can be used until added with @ref USBD_AddEndpoint.
sdivarci 0:0061165683ee 808 ******************************************************************************/
sdivarci 0:0061165683ee 809 static void USBD_ResetEndpoints(void)
sdivarci 0:0061165683ee 810 {
sdivarci 0:0061165683ee 811 USBD_Ep_TypeDef *ep = &dev->ep[0];
sdivarci 0:0061165683ee 812
sdivarci 0:0061165683ee 813 numEps = 0;
sdivarci 0:0061165683ee 814 txFifoNum = 1;
sdivarci 0:0061165683ee 815
sdivarci 0:0061165683ee 816 totalTxFifoSize = ep->fifoSize * 1;
sdivarci 0:0061165683ee 817 totalRxFifoSize = (ep->fifoSize + 1) * 1;
sdivarci 0:0061165683ee 818 totalRxFifoSize += 10 + 1 + ( 2 * (MAX_NUM_OUT_EPS + 1) );
sdivarci 0:0061165683ee 819 }
sdivarci 0:0061165683ee 820
sdivarci 0:0061165683ee 821 /***************************************************************************//**
sdivarci 0:0061165683ee 822 * @brief
sdivarci 0:0061165683ee 823 * Add a new endpoint
sdivarci 0:0061165683ee 824 *
sdivarci 0:0061165683ee 825 * @param[in] epAddr
sdivarci 0:0061165683ee 826 * Endpoint address
sdivarci 0:0061165683ee 827 *
sdivarci 0:0061165683ee 828 * @param[in] transferType
sdivarci 0:0061165683ee 829 * Endpoint type, one of @ref USB_EPTYPE_BULK, @ref USB_EPTYPE_INTR or
sdivarci 0:0061165683ee 830 * @ref USB_EPTYPE_ISOC.
sdivarci 0:0061165683ee 831 *
sdivarci 0:0061165683ee 832 * @param[in] maxPacketSize
sdivarci 0:0061165683ee 833 * Maximum packet size of the new endpoint, in bytes
sdivarci 0:0061165683ee 834 *
sdivarci 0:0061165683ee 835 * @param[in] bufferMult
sdivarci 0:0061165683ee 836 * FIFO buffer size multiplier
sdivarci 0:0061165683ee 837 *
sdivarci 0:0061165683ee 838 * @return
sdivarci 0:0061165683ee 839 * @ref USB_STATUS_OK on success, else an appropriate error code.
sdivarci 0:0061165683ee 840 ******************************************************************************/
sdivarci 0:0061165683ee 841 int USBD_AddEndpoint(int epAddr, int transferType,
sdivarci 0:0061165683ee 842 int maxPacketSize, int bufferMult)
sdivarci 0:0061165683ee 843 {
sdivarci 0:0061165683ee 844 USBD_Ep_TypeDef *ep;
sdivarci 0:0061165683ee 845
sdivarci 0:0061165683ee 846 numEps++;
sdivarci 0:0061165683ee 847
sdivarci 0:0061165683ee 848 ep = &dev->ep[ numEps ];
sdivarci 0:0061165683ee 849 ep->in = ( epAddr & USB_SETUP_DIR_MASK ) != 0;
sdivarci 0:0061165683ee 850 ep->buf = NULL;
sdivarci 0:0061165683ee 851 ep->addr = epAddr;
sdivarci 0:0061165683ee 852 ep->num = ep->addr & USB_EPNUM_MASK;
sdivarci 0:0061165683ee 853 ep->mask = 1 << ep->num;
sdivarci 0:0061165683ee 854 ep->type = transferType;
sdivarci 0:0061165683ee 855 ep->packetSize = maxPacketSize;
sdivarci 0:0061165683ee 856 ep->remaining = 0;
sdivarci 0:0061165683ee 857 ep->xferred = 0;
sdivarci 0:0061165683ee 858 ep->state = D_EP_IDLE;
sdivarci 0:0061165683ee 859 ep->xferCompleteCb = NULL;
sdivarci 0:0061165683ee 860
sdivarci 0:0061165683ee 861 if ( ep->in )
sdivarci 0:0061165683ee 862 {
sdivarci 0:0061165683ee 863 ep->txFifoNum = txFifoNum++;
sdivarci 0:0061165683ee 864 ep->fifoSize = ( ( ep->packetSize + 3 ) / 4 ) * bufferMult;
sdivarci 0:0061165683ee 865 dev->inEpAddr2EpIndex[ ep->num ] = numEps;
sdivarci 0:0061165683ee 866 totalTxFifoSize += ep->fifoSize;
sdivarci 0:0061165683ee 867
sdivarci 0:0061165683ee 868 if ( ep->num > MAX_NUM_IN_EPS )
sdivarci 0:0061165683ee 869 {
sdivarci 0:0061165683ee 870 DEBUG_USB_API_PUTS( "\nUSBD_AddEndpoint(), Illegal IN EP address" );
sdivarci 0:0061165683ee 871 EFM_ASSERT( false );
sdivarci 0:0061165683ee 872 return USB_STATUS_ILLEGAL;
sdivarci 0:0061165683ee 873 }
sdivarci 0:0061165683ee 874 }
sdivarci 0:0061165683ee 875 else
sdivarci 0:0061165683ee 876 {
sdivarci 0:0061165683ee 877 ep->fifoSize = ( ( ( ep->packetSize + 3 ) / 4 ) + 1 ) * bufferMult;
sdivarci 0:0061165683ee 878 dev->outEpAddr2EpIndex[ ep->num ] = numEps;
sdivarci 0:0061165683ee 879 totalRxFifoSize += ep->fifoSize;
sdivarci 0:0061165683ee 880
sdivarci 0:0061165683ee 881 if ( ep->num > MAX_NUM_OUT_EPS )
sdivarci 0:0061165683ee 882 {
sdivarci 0:0061165683ee 883 DEBUG_USB_API_PUTS( "\nUSBD_AddEndpoint(), Illegal OUT EP address" );
sdivarci 0:0061165683ee 884 EFM_ASSERT( false );
sdivarci 0:0061165683ee 885 return USB_STATUS_ILLEGAL;
sdivarci 0:0061165683ee 886 }
sdivarci 0:0061165683ee 887 }
sdivarci 0:0061165683ee 888
sdivarci 0:0061165683ee 889 USB_PRINTF("USBD: Added endpoint %d to slot %d, in %d, addr 0x%x, type %d, ps %d, fifo %ld (total tx %ld, rx %ld)\n",
sdivarci 0:0061165683ee 890 ep->num, numEps, ep->in, ep->addr, ep->type, ep->packetSize, ep->fifoSize,
sdivarci 0:0061165683ee 891 totalTxFifoSize, totalRxFifoSize);
sdivarci 0:0061165683ee 892
sdivarci 0:0061165683ee 893 INT_Disable();
sdivarci 0:0061165683ee 894 #if defined( CMU_OSCENCMD_USHFRCOEN )
sdivarci 0:0061165683ee 895 /* Happy Gecko workaround: disable LEM GATE mode if using ISOC endpoints. */
sdivarci 0:0061165683ee 896 if ( transferType == USB_EPTYPE_ISOC )
sdivarci 0:0061165683ee 897 {
sdivarci 0:0061165683ee 898 USB->CTRL = (USB->CTRL & ~_USB_CTRL_LEMOSCCTRL_MASK) | USB_CTRL_LEMOSCCTRL_NONE;
sdivarci 0:0061165683ee 899 }
sdivarci 0:0061165683ee 900 #endif
sdivarci 0:0061165683ee 901
sdivarci 0:0061165683ee 902 int ret = USBDHAL_ReconfigureFifos(totalRxFifoSize, totalTxFifoSize);
sdivarci 0:0061165683ee 903 INT_Enable();
sdivarci 0:0061165683ee 904
sdivarci 0:0061165683ee 905 if( ret != USB_STATUS_OK ) {
sdivarci 0:0061165683ee 906 return ret;
sdivarci 0:0061165683ee 907 }
sdivarci 0:0061165683ee 908
sdivarci 0:0061165683ee 909 USBDHAL_ActivateEp(ep, false);
sdivarci 0:0061165683ee 910
sdivarci 0:0061165683ee 911 return USB_STATUS_OK;
sdivarci 0:0061165683ee 912 }
sdivarci 0:0061165683ee 913
sdivarci 0:0061165683ee 914
sdivarci 0:0061165683ee 915 /***************************************************************************//**
sdivarci 0:0061165683ee 916 * @brief
sdivarci 0:0061165683ee 917 * Set an endpoint0 in the stalled (halted) state.
sdivarci 0:0061165683ee 918 *
sdivarci 0:0061165683ee 919 * @details
sdivarci 0:0061165683ee 920 * Temporarily stalls endpoint 0. Used to signal a failure to respond to
sdivarci 0:0061165683ee 921 * the host's setup packet.
sdivarci 0:0061165683ee 922 ******************************************************************************/
sdivarci 0:0061165683ee 923 void USBD_StallEp0()
sdivarci 0:0061165683ee 924 {
sdivarci 0:0061165683ee 925 int const epAddr = 0;
sdivarci 0:0061165683ee 926 USBD_Ep_TypeDef *ep = USBD_GetEpFromAddr( epAddr );
sdivarci 0:0061165683ee 927 ep->in = true;
sdivarci 0:0061165683ee 928 USBDHAL_StallEp( ep ); /* Stall Ep0 IN */
sdivarci 0:0061165683ee 929 ep->in = false; /* OUT for next SETUP */
sdivarci 0:0061165683ee 930 USBDHAL_StallEp( ep ); /* Stall Ep0 OUT */
sdivarci 0:0061165683ee 931 #if !defined( USB_DOEP0INT_STUPPKTRCVD )
sdivarci 0:0061165683ee 932 USBDHAL_ReenableEp0Setup( dev ); /* Prepare for next SETUP pkt. */
sdivarci 0:0061165683ee 933 #else
sdivarci 0:0061165683ee 934 USBDHAL_StartEp0Setup( dev );
sdivarci 0:0061165683ee 935 #endif
sdivarci 0:0061165683ee 936 ep->state = D_EP_IDLE;
sdivarci 0:0061165683ee 937 }
sdivarci 0:0061165683ee 938
sdivarci 0:0061165683ee 939 /******** THE REST OF THE FILE IS DOCUMENTATION ONLY !**********************//**
sdivarci 0:0061165683ee 940 * @{
sdivarci 0:0061165683ee 941
sdivarci 0:0061165683ee 942 @page usb_device USB device stack library
sdivarci 0:0061165683ee 943
sdivarci 0:0061165683ee 944 The source files for the USB device stack resides in the usb directory
sdivarci 0:0061165683ee 945 and follows the naming convention: em_usbd<em>nnn</em>.c/h.
sdivarci 0:0061165683ee 946
sdivarci 0:0061165683ee 947 @li @ref usb_device_intro
sdivarci 0:0061165683ee 948 @li @ref usb_device_api
sdivarci 0:0061165683ee 949 @li @ref usb_device_conf
sdivarci 0:0061165683ee 950 @li @ref usb_device_powersave
sdivarci 0:0061165683ee 951 @li @ref usb_device_example1
sdivarci 0:0061165683ee 952
sdivarci 0:0061165683ee 953
sdivarci 0:0061165683ee 954 @n @section usb_device_intro Introduction
sdivarci 0:0061165683ee 955
sdivarci 0:0061165683ee 956 The USB device protocol stack provides an API which makes it possible to
sdivarci 0:0061165683ee 957 create USB devices with a minimum of effort. The device stack supports control,
sdivarci 0:0061165683ee 958 bulk and interrupt transfers.
sdivarci 0:0061165683ee 959
sdivarci 0:0061165683ee 960 The stack is highly configurable to suit various needs, it does also contain
sdivarci 0:0061165683ee 961 useful debugging features together with several demonstration projects to
sdivarci 0:0061165683ee 962 get you started fast.
sdivarci 0:0061165683ee 963
sdivarci 0:0061165683ee 964 We recommend that you read through this documentation, then proceed to build
sdivarci 0:0061165683ee 965 and test a few example projects before you start designing your own device.
sdivarci 0:0061165683ee 966
sdivarci 0:0061165683ee 967 @n @section usb_device_api The device stack API
sdivarci 0:0061165683ee 968
sdivarci 0:0061165683ee 969 This section contains brief descriptions of the functions in the API. You will
sdivarci 0:0061165683ee 970 find detailed information on input and output parameters and return values by
sdivarci 0:0061165683ee 971 clicking on the hyperlinked function names. It is also a good idea to study
sdivarci 0:0061165683ee 972 the code in the USB demonstration projects.
sdivarci 0:0061165683ee 973
sdivarci 0:0061165683ee 974 Your application code must include one header file: @em em_usb.h.
sdivarci 0:0061165683ee 975
sdivarci 0:0061165683ee 976 All functions defined in the API can be called from within interrupt handlers.
sdivarci 0:0061165683ee 977
sdivarci 0:0061165683ee 978 The USB stack use a hardware timer to keep track of time. TIMER0 is the
sdivarci 0:0061165683ee 979 default choice, refer to @ref usb_device_conf for other possibilities.
sdivarci 0:0061165683ee 980 Your application must not use the selected timer.
sdivarci 0:0061165683ee 981
sdivarci 0:0061165683ee 982 <b>Pitfalls:</b>@n
sdivarci 0:0061165683ee 983 The USB peripheral will fill your receive buffers in quantities of WORD's
sdivarci 0:0061165683ee 984 (4 bytes). Transmit and receive buffers must be WORD aligned, in
sdivarci 0:0061165683ee 985 addition when allocating storage for receive buffers, round size up to
sdivarci 0:0061165683ee 986 next WORD boundary. If it is possible that the host will send more data
sdivarci 0:0061165683ee 987 than your device expects, round buffer size up to the next multiple of
sdivarci 0:0061165683ee 988 maxpacket size for the relevant endpoint to avoid data corruption.
sdivarci 0:0061165683ee 989
sdivarci 0:0061165683ee 990 Transmit buffers passed to @htmlonly USBD_Write() @endhtmlonly must be
sdivarci 0:0061165683ee 991 statically allocated because @htmlonly USBD_Write() @endhtmlonly only
sdivarci 0:0061165683ee 992 initiates the transfer. When the host decide to actually perform the
sdivarci 0:0061165683ee 993 transfer, your data must be available.
sdivarci 0:0061165683ee 994
sdivarci 0:0061165683ee 995 @n @ref USBD_Init() @n
sdivarci 0:0061165683ee 996 This function is called to register your device and all its properties with
sdivarci 0:0061165683ee 997 the device stack. The application must fill in a @ref USBD_Init_TypeDef
sdivarci 0:0061165683ee 998 structure prior to calling. Refer to @ref DeviceInitCallbacks for the
sdivarci 0:0061165683ee 999 optional callback functions defined within this structure. When this
sdivarci 0:0061165683ee 1000 function has been called your device is ready to be enumerated by the USB
sdivarci 0:0061165683ee 1001 host.
sdivarci 0:0061165683ee 1002
sdivarci 0:0061165683ee 1003 @ref USBD_Read(), @ref USBD_Write() @n
sdivarci 0:0061165683ee 1004 These functions initiate data transfers.
sdivarci 0:0061165683ee 1005 @n @htmlonly USBD_Read() @endhtmlonly initiate a transfer of data @em
sdivarci 0:0061165683ee 1006 from host @em to device (an @em OUT transfer in USB terminology).
sdivarci 0:0061165683ee 1007 @n @htmlonly USBD_Write() @endhtmlonly initiate a transfer of data @em from
sdivarci 0:0061165683ee 1008 device @em to host (an @em IN transfer).
sdivarci 0:0061165683ee 1009
sdivarci 0:0061165683ee 1010 When the USB host actually performs the transfer, your application will be
sdivarci 0:0061165683ee 1011 notified by means of a callback function which you provide (optionally).
sdivarci 0:0061165683ee 1012 Refer to @ref TransferCallback for details of the callback functionality.
sdivarci 0:0061165683ee 1013
sdivarci 0:0061165683ee 1014 @ref USBD_AbortTransfer(), @ref USBD_AbortAllTransfers() @n
sdivarci 0:0061165683ee 1015 These functions terminate transfers that are initiated, but has not yet
sdivarci 0:0061165683ee 1016 taken place. If a transfer is initiated with @htmlonly USBD_Read()
sdivarci 0:0061165683ee 1017 or USBD_Write(), @endhtmlonly but the USB host never actually peform
sdivarci 0:0061165683ee 1018 the transfers, these functions will deactivate the transfer setup to make
sdivarci 0:0061165683ee 1019 the USB device endpoint hardware ready for new (and potentially) different
sdivarci 0:0061165683ee 1020 transfers.
sdivarci 0:0061165683ee 1021
sdivarci 0:0061165683ee 1022 @ref USBD_Connect(), @ref USBD_Disconnect() @n
sdivarci 0:0061165683ee 1023 These functions turns the data-line (D+ or D-) pullup on or off. They can be
sdivarci 0:0061165683ee 1024 used to force reenumeration. It's good practice to delay at least one second
sdivarci 0:0061165683ee 1025 between @htmlonly USBD_Disconnect() and USBD_Connect() @endhtmlonly
sdivarci 0:0061165683ee 1026 to allow the USB host to unload the currently active device driver.
sdivarci 0:0061165683ee 1027
sdivarci 0:0061165683ee 1028 @ref USBD_EpIsBusy() @n
sdivarci 0:0061165683ee 1029 Check if an endpoint is busy.
sdivarci 0:0061165683ee 1030
sdivarci 0:0061165683ee 1031 @ref USBD_StallEp(), @ref USBD_UnStallEp() @n
sdivarci 0:0061165683ee 1032 These functions stalls or un-stalls an endpoint. This functionality may not
sdivarci 0:0061165683ee 1033 be needed by your application, but the USB device stack use them in response
sdivarci 0:0061165683ee 1034 to standard setup commands SET_FEATURE and CLEAR_FEATURE. They may be useful
sdivarci 0:0061165683ee 1035 when implementing some USB classes, e.g. a mass storage device use them
sdivarci 0:0061165683ee 1036 extensively.
sdivarci 0:0061165683ee 1037
sdivarci 0:0061165683ee 1038 @ref USBD_RemoteWakeup() @n
sdivarci 0:0061165683ee 1039 Used in SUSPENDED state (see @ref USB_Status_TypeDef) to signal resume to
sdivarci 0:0061165683ee 1040 host. It's the applications responsibility to adhere to the USB standard
sdivarci 0:0061165683ee 1041 which states that a device can not signal resume before it has been
sdivarci 0:0061165683ee 1042 SUSPENDED for at least 5 ms. The function will also check the configuration
sdivarci 0:0061165683ee 1043 descriptor defined by the application to see if it is legal for the device
sdivarci 0:0061165683ee 1044 to signal resume.
sdivarci 0:0061165683ee 1045
sdivarci 0:0061165683ee 1046 @ref USBD_GetUsbState() @n
sdivarci 0:0061165683ee 1047 Returns the device USB state (see @ref USBD_State_TypeDef). Refer to
sdivarci 0:0061165683ee 1048 Figure 9-1. "Device State Diagram" in the USB revision 2.0 specification.
sdivarci 0:0061165683ee 1049
sdivarci 0:0061165683ee 1050 @ref USBD_GetUsbStateName() @n
sdivarci 0:0061165683ee 1051 Returns a text string naming a given USB device state.
sdivarci 0:0061165683ee 1052
sdivarci 0:0061165683ee 1053 @ref USBD_SafeToEnterEM2() @n
sdivarci 0:0061165683ee 1054 Check if it is ok to enter energy mode EM2. Refer to the
sdivarci 0:0061165683ee 1055 @ref usb_device_powersave section for more information.
sdivarci 0:0061165683ee 1056
sdivarci 0:0061165683ee 1057 @n @anchor TransferCallback <b>The transfer complete callback function:</b> @n
sdivarci 0:0061165683ee 1058 @n USB_XferCompleteCb_TypeDef() is called when a transfer completes. It is
sdivarci 0:0061165683ee 1059 called with three parameters, the status of the transfer, the number of
sdivarci 0:0061165683ee 1060 bytes transferred and the number of bytes remaining. It may not always be
sdivarci 0:0061165683ee 1061 needed to have a callback on transfer completion, but you should keep in
sdivarci 0:0061165683ee 1062 mind that a transfer may be aborted when you least expect it. A transfer
sdivarci 0:0061165683ee 1063 will be aborted if host stalls the endpoint, if host resets your device, if
sdivarci 0:0061165683ee 1064 host unconfigures your device or if you unplug your device cable and the
sdivarci 0:0061165683ee 1065 device is selfpowered.
sdivarci 0:0061165683ee 1066 @htmlonly USB_XferCompleteCb_TypeDef() @endhtmlonly is also called if your
sdivarci 0:0061165683ee 1067 application use @htmlonly USBD_AbortTransfer() or USBD_AbortAllTransfers()
sdivarci 0:0061165683ee 1068 @endhtmlonly calls.
sdivarci 0:0061165683ee 1069 @note This callback is called from within an interrupt handler with
sdivarci 0:0061165683ee 1070 interrupts disabled.
sdivarci 0:0061165683ee 1071
sdivarci 0:0061165683ee 1072 @n @anchor DeviceInitCallbacks <b>Optional callbacks passed to the stack via
sdivarci 0:0061165683ee 1073 the @ref USBD_Init() function:</b> @n
sdivarci 0:0061165683ee 1074 @n These callbacks are all optional, and it is up to the application
sdivarci 0:0061165683ee 1075 programmer to decide if the application needs the functionality they
sdivarci 0:0061165683ee 1076 provide.
sdivarci 0:0061165683ee 1077 @note These callbacks are all called from within an interrupt handler
sdivarci 0:0061165683ee 1078 with interrupts disabled.
sdivarci 0:0061165683ee 1079
sdivarci 0:0061165683ee 1080 USBD_UsbResetCb_TypeDef() is called each time reset signalling is sensed on
sdivarci 0:0061165683ee 1081 the USB wire.
sdivarci 0:0061165683ee 1082
sdivarci 0:0061165683ee 1083 @n USBD_SofIntCb_TypeDef() is called with framenumber as a parameter on
sdivarci 0:0061165683ee 1084 each SOF interrupt.
sdivarci 0:0061165683ee 1085
sdivarci 0:0061165683ee 1086 @n USBD_DeviceStateChangeCb_TypeDef() is called whenever the device state
sdivarci 0:0061165683ee 1087 change. Useful for detecting e.g. SUSPENDED state change in order to reduce
sdivarci 0:0061165683ee 1088 current consumption of buspowered devices. The USB HID keyboard example
sdivarci 0:0061165683ee 1089 project has a good example on how to use this callback.
sdivarci 0:0061165683ee 1090
sdivarci 0:0061165683ee 1091 @n USBD_IsSelfPoweredCb_TypeDef() is called by the device stack when host
sdivarci 0:0061165683ee 1092 queries the device with a standard setup GET_STATUS command to check if the
sdivarci 0:0061165683ee 1093 device is currently selfpowered or buspowered. This feature is only
sdivarci 0:0061165683ee 1094 applicable on selfpowered devices which also works when only buspower is
sdivarci 0:0061165683ee 1095 available.
sdivarci 0:0061165683ee 1096
sdivarci 0:0061165683ee 1097 @n USBD_SetupCmdCb_TypeDef() is called each time a setup command is
sdivarci 0:0061165683ee 1098 received from host. Use this callback to override or extend the default
sdivarci 0:0061165683ee 1099 handling of standard setup commands, and to implement class or vendor
sdivarci 0:0061165683ee 1100 specific setup commands. The USB HID keyboard example project has a good
sdivarci 0:0061165683ee 1101 example on how to use this callback.
sdivarci 0:0061165683ee 1102
sdivarci 0:0061165683ee 1103 @n <b>Utility functions:</b> @n
sdivarci 0:0061165683ee 1104 @n USB_PUTCHAR() Transmit a single char on the debug serial port.
sdivarci 0:0061165683ee 1105 @n @n USB_PUTS() Transmit a zero terminated string on the debug serial port.
sdivarci 0:0061165683ee 1106 @n @n USB_PRINTF() Transmit "printf" formated data on the debug serial port.
sdivarci 0:0061165683ee 1107 @n @n USB_GetErrorMsgString() Return an error message string for a given
sdivarci 0:0061165683ee 1108 error code.
sdivarci 0:0061165683ee 1109 @n @n USB_PrintErrorMsgString() Format and print a text string given an
sdivarci 0:0061165683ee 1110 error code, prepends an optional user supplied leader string.
sdivarci 0:0061165683ee 1111 @n @n USBTIMER_DelayMs() Active wait millisecond delay function. Can also be
sdivarci 0:0061165683ee 1112 used inside interrupt handlers.
sdivarci 0:0061165683ee 1113 @n @n USBTIMER_DelayUs() Active wait microsecond delay function. Can also be
sdivarci 0:0061165683ee 1114 used inside interrupt handlers.
sdivarci 0:0061165683ee 1115 @n @n USBTIMER_Init() Initialize the timer system. Called by @htmlonly
sdivarci 0:0061165683ee 1116 USBD_Init(), @endhtmlonly but your application must call it again to
sdivarci 0:0061165683ee 1117 reinitialize whenever you change the HFPERCLK frequency.
sdivarci 0:0061165683ee 1118 @n @n USBTIMER_Start() Start a timer. You can configure the USB device stack
sdivarci 0:0061165683ee 1119 to provide any number of timers. The timers have 1 ms resolution, your
sdivarci 0:0061165683ee 1120 application is notified of timeout by means of a callback.
sdivarci 0:0061165683ee 1121 @n @n USBTIMER_Stop() Stop a timer.
sdivarci 0:0061165683ee 1122
sdivarci 0:0061165683ee 1123 @n @section usb_device_conf Configuring the device stack
sdivarci 0:0061165683ee 1124
sdivarci 0:0061165683ee 1125 Your application must provide a header file named @em usbconfig.h. This file
sdivarci 0:0061165683ee 1126 must contain the following \#define's:@n @n
sdivarci 0:0061165683ee 1127 @verbatim
sdivarci 0:0061165683ee 1128 #define USB_DEVICE // Compile the stack for device mode.
sdivarci 0:0061165683ee 1129 #define NUM_EP_USED n // Your application use 'n' endpoints in
sdivarci 0:0061165683ee 1130 // addition to endpoint 0. @endverbatim
sdivarci 0:0061165683ee 1131
sdivarci 0:0061165683ee 1132 @n @em usbconfig.h may define the following items: @n @n
sdivarci 0:0061165683ee 1133 @verbatim
sdivarci 0:0061165683ee 1134 #define NUM_APP_TIMERS n // Your application needs 'n' timers
sdivarci 0:0061165683ee 1135
sdivarci 0:0061165683ee 1136 #define DEBUG_USB_API // Turn on API debug diagnostics.
sdivarci 0:0061165683ee 1137
sdivarci 0:0061165683ee 1138 // Some utility functions in the API needs printf. These
sdivarci 0:0061165683ee 1139 // functions have "print" in their name. This macro enables
sdivarci 0:0061165683ee 1140 // these functions.
sdivarci 0:0061165683ee 1141 #define USB_USE_PRINTF // Enable utility print functions.
sdivarci 0:0061165683ee 1142
sdivarci 0:0061165683ee 1143 // Define a function for transmitting a single char on the serial port.
sdivarci 0:0061165683ee 1144 extern int RETARGET_WriteChar(char c);
sdivarci 0:0061165683ee 1145 #define USER_PUTCHAR RETARGET_WriteChar
sdivarci 0:0061165683ee 1146
sdivarci 0:0061165683ee 1147 #define USB_TIMER USB_TIMERn // Select which hardware timer the USB stack
sdivarci 0:0061165683ee 1148 // is allowed to use. Valid values are n=0,1,2...
sdivarci 0:0061165683ee 1149 // corresponding to TIMER0, TIMER1, ...
sdivarci 0:0061165683ee 1150 // If not specified, TIMER0 is used
sdivarci 0:0061165683ee 1151
sdivarci 0:0061165683ee 1152 #define USB_VBUS_SWITCH_NOT_PRESENT // Hardware does not have a VBUS switch
sdivarci 0:0061165683ee 1153
sdivarci 0:0061165683ee 1154 #define USB_CORECLK_HFRCO // Devices supporting crystal-less USB can use
sdivarci 0:0061165683ee 1155 // HFRCO as core clock, default is HFXO
sdivarci 0:0061165683ee 1156 @endverbatim
sdivarci 0:0061165683ee 1157
sdivarci 0:0061165683ee 1158 @n You are strongly encouraged to start application development with DEBUG_USB_API
sdivarci 0:0061165683ee 1159 turned on. When DEBUG_USB_API is turned on and USER_PUTCHAR is defined, useful
sdivarci 0:0061165683ee 1160 debugging information will be output on the development kit serial port.
sdivarci 0:0061165683ee 1161 Compiling with the DEBUG_EFM_USER flag will also enable all asserts
sdivarci 0:0061165683ee 1162 in both @em emlib and in the USB stack. If asserts are enabled and
sdivarci 0:0061165683ee 1163 USER_PUTCHAR defined, assert texts will be output on the serial port.
sdivarci 0:0061165683ee 1164
sdivarci 0:0061165683ee 1165 You application must include @em retargetserial.c if DEBUG_USB_API is defined
sdivarci 0:0061165683ee 1166 and @em retargetio.c if USB_USE_PRINTF is defined.
sdivarci 0:0061165683ee 1167 These files reside in the @em drivers
sdivarci 0:0061165683ee 1168 directory in the software package for your development board. Refer to
sdivarci 0:0061165683ee 1169 @ref usb_device_powersave for energy-saving mode configurations.
sdivarci 0:0061165683ee 1170
sdivarci 0:0061165683ee 1171 @n @section usb_device_powersave Energy-saving modes
sdivarci 0:0061165683ee 1172
sdivarci 0:0061165683ee 1173 The device stack provides two energy saving levels. The first level is to
sdivarci 0:0061165683ee 1174 set the USB peripheral in energy saving mode, the next level is to enter
sdivarci 0:0061165683ee 1175 Energy Mode 2 (EM2). These energy saving modes can be applied when the device
sdivarci 0:0061165683ee 1176 is suspended by the USB host, or when when the device is not connected to a
sdivarci 0:0061165683ee 1177 USB host.
sdivarci 0:0061165683ee 1178 In addition to this an application can use energy modes EM1 and EM2. There
sdivarci 0:0061165683ee 1179 are no restrictions on when EM1 can be entered, EM2 can only be entered
sdivarci 0:0061165683ee 1180 when the USB device is suspended or detached from host.
sdivarci 0:0061165683ee 1181
sdivarci 0:0061165683ee 1182 Energy-saving modes are selected with a \#define in @em usbconfig.h, default
sdivarci 0:0061165683ee 1183 selection is to not use any energy saving modes.@n @n
sdivarci 0:0061165683ee 1184 @verbatim
sdivarci 0:0061165683ee 1185 #define USB_PWRSAVE_MODE (USB_PWRSAVE_MODE_ONSUSPEND | USB_PWRSAVE_MODE_ENTEREM2)@endverbatim
sdivarci 0:0061165683ee 1186
sdivarci 0:0061165683ee 1187 There are three flags available, the flags can be or'ed together as shown above.
sdivarci 0:0061165683ee 1188
sdivarci 0:0061165683ee 1189 <b>\#define USB_PWRSAVE_MODE_ONSUSPEND</b>@n Set USB peripheral in low power
sdivarci 0:0061165683ee 1190 mode on suspend.
sdivarci 0:0061165683ee 1191
sdivarci 0:0061165683ee 1192 <b>\#define USB_PWRSAVE_MODE_ONVBUSOFF</b>@n Set USB peripheral in low power
sdivarci 0:0061165683ee 1193 mode when not attached to a host. This mode assumes that the internal voltage
sdivarci 0:0061165683ee 1194 regulator is used and that the VREGI pin of the chip is connected to VBUS.
sdivarci 0:0061165683ee 1195 This option can not be used with bus-powered devices.
sdivarci 0:0061165683ee 1196
sdivarci 0:0061165683ee 1197 <b>\#define USB_PWRSAVE_MODE_ENTEREM2</b>@n Enter EM2 when USB peripheral is
sdivarci 0:0061165683ee 1198 in low power mode.
sdivarci 0:0061165683ee 1199
sdivarci 0:0061165683ee 1200 When the USB peripheral is set in low power mode, it must be clocked by a 32kHz
sdivarci 0:0061165683ee 1201 clock. Both LFXO and LFRCO can be used, but only LFXO guarantee USB specification
sdivarci 0:0061165683ee 1202 compliance. Selection is done with a \#define in @em usbconfig.h.@n @n
sdivarci 0:0061165683ee 1203 @verbatim
sdivarci 0:0061165683ee 1204 #define USB_USBC_32kHz_CLK USB_USBC_32kHz_CLK_LFXO @endverbatim
sdivarci 0:0061165683ee 1205 Two flags are available, <b>USB_USBC_32kHz_CLK_LFXO</b> and
sdivarci 0:0061165683ee 1206 <b>USB_USBC_32kHz_CLK_LFRCO</b>. <b>USB_USBC_32kHz_CLK_LFXO</b> is selected
sdivarci 0:0061165683ee 1207 by default.
sdivarci 0:0061165683ee 1208
sdivarci 0:0061165683ee 1209 The USB HID keyboard and Mass Storage device example projects demonstrate
sdivarci 0:0061165683ee 1210 different energy-saving modes.
sdivarci 0:0061165683ee 1211
sdivarci 0:0061165683ee 1212 <b>Example 1:</b>
sdivarci 0:0061165683ee 1213 Leave all energy saving to the stack, the device enters EM2 on suspend and
sdivarci 0:0061165683ee 1214 when detached from host. @n
sdivarci 0:0061165683ee 1215 @verbatim
sdivarci 0:0061165683ee 1216 In usbconfig.h:
sdivarci 0:0061165683ee 1217
sdivarci 0:0061165683ee 1218 #define USB_PWRSAVE_MODE (USB_PWRSAVE_MODE_ONSUSPEND | USB_PWRSAVE_MODE_ONVBUSOFF | USB_PWRSAVE_MODE_ENTEREM2)
sdivarci 0:0061165683ee 1219 @endverbatim
sdivarci 0:0061165683ee 1220
sdivarci 0:0061165683ee 1221 @n <b>Example 2:</b>
sdivarci 0:0061165683ee 1222 Let the stack control energy saving in the USB periheral but let your
sdivarci 0:0061165683ee 1223 application control energy modes EM1 and EM2. @n
sdivarci 0:0061165683ee 1224 @verbatim
sdivarci 0:0061165683ee 1225 In usbconfig.h:
sdivarci 0:0061165683ee 1226
sdivarci 0:0061165683ee 1227 #define USB_PWRSAVE_MODE (USB_PWRSAVE_MODE_ONSUSPEND | USB_PWRSAVE_MODE_ONVBUSOFF)
sdivarci 0:0061165683ee 1228
sdivarci 0:0061165683ee 1229 In application code:
sdivarci 0:0061165683ee 1230
sdivarci 0:0061165683ee 1231 if ( USBD_SafeToEnterEM2() )
sdivarci 0:0061165683ee 1232 EMU_EnterEM2(true);
sdivarci 0:0061165683ee 1233 else
sdivarci 0:0061165683ee 1234 EMU_EnterEM1(); @endverbatim
sdivarci 0:0061165683ee 1235
sdivarci 0:0061165683ee 1236 @n @section usb_device_example1 Vendor unique device example application
sdivarci 0:0061165683ee 1237
sdivarci 0:0061165683ee 1238 This example represents the most simple USB device imaginable. It's purpose
sdivarci 0:0061165683ee 1239 is to turn user LED's on or off under control of vendor unique setup commands.
sdivarci 0:0061165683ee 1240 The device will rely on @em libusb device driver on the host, a host
sdivarci 0:0061165683ee 1241 application @em EFM32-LedApp.exe is bundled with the example.
sdivarci 0:0061165683ee 1242
sdivarci 0:0061165683ee 1243 The main() is really simple ! @n @n
sdivarci 0:0061165683ee 1244 @verbatim
sdivarci 0:0061165683ee 1245 #include "em_usb.h"
sdivarci 0:0061165683ee 1246
sdivarci 0:0061165683ee 1247 #include "descriptors.h"
sdivarci 0:0061165683ee 1248
sdivarci 0:0061165683ee 1249 int main( void )
sdivarci 0:0061165683ee 1250 {
sdivarci 0:0061165683ee 1251 BSP_Init(BSP_INIT_DEFAULT); // Initialize DK board register access
sdivarci 0:0061165683ee 1252 CMU_ClockSelectSet( cmuClock_HF, cmuSelect_HFXO );
sdivarci 0:0061165683ee 1253 BSP_LedsSet(0); // Turn off all LED's
sdivarci 0:0061165683ee 1254
sdivarci 0:0061165683ee 1255 ConsoleDebugInit(); // Initialize UART for debug diagnostics
sdivarci 0:0061165683ee 1256
sdivarci 0:0061165683ee 1257 USB_PUTS( "\nEFM32 USB LED Vendor Unique Device example\n" );
sdivarci 0:0061165683ee 1258
sdivarci 0:0061165683ee 1259 USBD_Init( &initstruct ); // GO !
sdivarci 0:0061165683ee 1260
sdivarci 0:0061165683ee 1261 //When using a debugger it is pratical to uncomment the following three
sdivarci 0:0061165683ee 1262 //lines to force host to re-enumerate the device.
sdivarci 0:0061165683ee 1263
sdivarci 0:0061165683ee 1264 //USBD_Disconnect();
sdivarci 0:0061165683ee 1265 //USBTIMER_DelayMs( 1000 );
sdivarci 0:0061165683ee 1266 //USBD_Connect();
sdivarci 0:0061165683ee 1267
sdivarci 0:0061165683ee 1268 for (;;) {}
sdivarci 0:0061165683ee 1269 } @endverbatim
sdivarci 0:0061165683ee 1270
sdivarci 0:0061165683ee 1271 @n Configure the device stack in <em>usbconfig.h</em>: @n @n
sdivarci 0:0061165683ee 1272 @verbatim
sdivarci 0:0061165683ee 1273 #define USB_DEVICE // Compile stack for device mode.
sdivarci 0:0061165683ee 1274
sdivarci 0:0061165683ee 1275 // **************************************************************************
sdivarci 0:0061165683ee 1276 ** **
sdivarci 0:0061165683ee 1277 ** Specify number of endpoints used (in addition to EP0). **
sdivarci 0:0061165683ee 1278 ** **
sdivarci 0:0061165683ee 1279 *****************************************************************************
sdivarci 0:0061165683ee 1280 #define NUM_EP_USED 0 // EP0 is the only endpoint used.
sdivarci 0:0061165683ee 1281
sdivarci 0:0061165683ee 1282 // **************************************************************************
sdivarci 0:0061165683ee 1283 ** **
sdivarci 0:0061165683ee 1284 ** Configure serial port debug output. **
sdivarci 0:0061165683ee 1285 ** **
sdivarci 0:0061165683ee 1286 *****************************************************************************
sdivarci 0:0061165683ee 1287 // Prototype a function for transmitting a single char on the serial port.
sdivarci 0:0061165683ee 1288 extern int RETARGET_WriteChar(char c);
sdivarci 0:0061165683ee 1289 #define USER_PUTCHAR RETARGET_WriteChar
sdivarci 0:0061165683ee 1290
sdivarci 0:0061165683ee 1291 // Enable debug diagnostics from API functions (illegal input params etc.)
sdivarci 0:0061165683ee 1292 #define DEBUG_USB_API @endverbatim
sdivarci 0:0061165683ee 1293
sdivarci 0:0061165683ee 1294 @n Define device properties and fill in USB initstruct in
sdivarci 0:0061165683ee 1295 <em>descriptors.h</em>: @n @n
sdivarci 0:0061165683ee 1296 @verbatim
sdivarci 0:0061165683ee 1297 EFM32_ALIGN(4)
sdivarci 0:0061165683ee 1298 static const USB_DeviceDescriptor_TypeDef deviceDesc __attribute__ ((aligned(4))) =
sdivarci 0:0061165683ee 1299 {
sdivarci 0:0061165683ee 1300 .bLength = USB_DEVICE_DESCSIZE,
sdivarci 0:0061165683ee 1301 .bDescriptorType = USB_DEVICE_DESCRIPTOR,
sdivarci 0:0061165683ee 1302 .bcdUSB = 0x0200,
sdivarci 0:0061165683ee 1303 .bDeviceClass = 0xFF,
sdivarci 0:0061165683ee 1304 .bDeviceSubClass = 0,
sdivarci 0:0061165683ee 1305 .bDeviceProtocol = 0,
sdivarci 0:0061165683ee 1306 .bMaxPacketSize0 = USB_FS_CTRL_EP_MAXSIZE,
sdivarci 0:0061165683ee 1307 .idVendor = 0x10C4,
sdivarci 0:0061165683ee 1308 .idProduct = 0x0001,
sdivarci 0:0061165683ee 1309 .bcdDevice = 0x0000,
sdivarci 0:0061165683ee 1310 .iManufacturer = 1,
sdivarci 0:0061165683ee 1311 .iProduct = 2,
sdivarci 0:0061165683ee 1312 .iSerialNumber = 3,
sdivarci 0:0061165683ee 1313 .bNumConfigurations = 1
sdivarci 0:0061165683ee 1314 };
sdivarci 0:0061165683ee 1315
sdivarci 0:0061165683ee 1316 EFM32_ALIGN(4)
sdivarci 0:0061165683ee 1317 static const uint8_t configDesc[] __attribute__ ((aligned(4)))=
sdivarci 0:0061165683ee 1318 {
sdivarci 0:0061165683ee 1319 // *** Configuration descriptor ***
sdivarci 0:0061165683ee 1320 USB_CONFIG_DESCSIZE, // bLength
sdivarci 0:0061165683ee 1321 USB_CONFIG_DESCRIPTOR, // bDescriptorType
sdivarci 0:0061165683ee 1322 USB_CONFIG_DESCSIZE + // wTotalLength (LSB)
sdivarci 0:0061165683ee 1323 USB_INTERFACE_DESCSIZE,
sdivarci 0:0061165683ee 1324 (USB_CONFIG_DESCSIZE + // wTotalLength (MSB)
sdivarci 0:0061165683ee 1325 USB_INTERFACE_DESCSIZE)>>8,
sdivarci 0:0061165683ee 1326 1, // bNumInterfaces
sdivarci 0:0061165683ee 1327 1, // bConfigurationValue
sdivarci 0:0061165683ee 1328 0, // iConfiguration
sdivarci 0:0061165683ee 1329 CONFIG_DESC_BM_RESERVED_D7 | // bmAttrib: Self powered
sdivarci 0:0061165683ee 1330 CONFIG_DESC_BM_SELFPOWERED,
sdivarci 0:0061165683ee 1331 CONFIG_DESC_MAXPOWER_mA( 100 ), // bMaxPower: 100 mA
sdivarci 0:0061165683ee 1332
sdivarci 0:0061165683ee 1333 // *** Interface descriptor ***
sdivarci 0:0061165683ee 1334 USB_INTERFACE_DESCSIZE, // bLength
sdivarci 0:0061165683ee 1335 USB_INTERFACE_DESCRIPTOR, // bDescriptorType
sdivarci 0:0061165683ee 1336 0, // bInterfaceNumber
sdivarci 0:0061165683ee 1337 0, // bAlternateSetting
sdivarci 0:0061165683ee 1338 NUM_EP_USED, // bNumEndpoints
sdivarci 0:0061165683ee 1339 0xFF, // bInterfaceClass
sdivarci 0:0061165683ee 1340 0, // bInterfaceSubClass
sdivarci 0:0061165683ee 1341 0, // bInterfaceProtocol
sdivarci 0:0061165683ee 1342 0, // iInterface
sdivarci 0:0061165683ee 1343 };
sdivarci 0:0061165683ee 1344
sdivarci 0:0061165683ee 1345 STATIC_CONST_STRING_DESC_LANGID( langID, 0x04, 0x09 );
sdivarci 0:0061165683ee 1346 STATIC_CONST_STRING_DESC( iManufacturer, 'E','n','e','r','g','y',' ', \
sdivarci 0:0061165683ee 1347 'M','i','c','r','o',' ','A','S' );
sdivarci 0:0061165683ee 1348 STATIC_CONST_STRING_DESC( iProduct , 'V','e','n','d','o','r',' ', \
sdivarci 0:0061165683ee 1349 'U','n','i','q','u','e',' ', \
sdivarci 0:0061165683ee 1350 'L','E','D',' ', \
sdivarci 0:0061165683ee 1351 'D','e','v','i','c','e' );
sdivarci 0:0061165683ee 1352 STATIC_CONST_STRING_DESC( iSerialNumber, '0','0','0','0','0','0', \
sdivarci 0:0061165683ee 1353 '0','0','1','2','3','4' );
sdivarci 0:0061165683ee 1354
sdivarci 0:0061165683ee 1355 static const void * const strings[] =
sdivarci 0:0061165683ee 1356 {
sdivarci 0:0061165683ee 1357 &langID,
sdivarci 0:0061165683ee 1358 &iManufacturer,
sdivarci 0:0061165683ee 1359 &iProduct,
sdivarci 0:0061165683ee 1360 &iSerialNumber
sdivarci 0:0061165683ee 1361 };
sdivarci 0:0061165683ee 1362
sdivarci 0:0061165683ee 1363 // Endpoint buffer sizes
sdivarci 0:0061165683ee 1364 // 1 = single buffer, 2 = double buffering, 3 = tripple buffering ...
sdivarci 0:0061165683ee 1365 static const uint8_t bufferingMultiplier[ NUM_EP_USED + 1 ] = { 1 };
sdivarci 0:0061165683ee 1366
sdivarci 0:0061165683ee 1367 static const USBD_Callbacks_TypeDef callbacks =
sdivarci 0:0061165683ee 1368 {
sdivarci 0:0061165683ee 1369 .usbReset = NULL,
sdivarci 0:0061165683ee 1370 .usbStateChange = NULL,
sdivarci 0:0061165683ee 1371 .setupCmd = SetupCmd,
sdivarci 0:0061165683ee 1372 .isSelfPowered = NULL,
sdivarci 0:0061165683ee 1373 .sofInt = NULL
sdivarci 0:0061165683ee 1374 };
sdivarci 0:0061165683ee 1375
sdivarci 0:0061165683ee 1376 static const USBD_Init_TypeDef initstruct =
sdivarci 0:0061165683ee 1377 {
sdivarci 0:0061165683ee 1378 .deviceDescriptor = &deviceDesc,
sdivarci 0:0061165683ee 1379 .configDescriptor = configDesc,
sdivarci 0:0061165683ee 1380 .stringDescriptors = strings,
sdivarci 0:0061165683ee 1381 .numberOfStrings = sizeof(strings)/sizeof(void*),
sdivarci 0:0061165683ee 1382 .callbacks = &callbacks,
sdivarci 0:0061165683ee 1383 .bufferingMultiplier = bufferingMultiplier
sdivarci 0:0061165683ee 1384 }; @endverbatim
sdivarci 0:0061165683ee 1385
sdivarci 0:0061165683ee 1386 @n Now we have to implement vendor unique USB setup commands to control the
sdivarci 0:0061165683ee 1387 LED's (see callbacks variable above). Notice that the buffer variable below is
sdivarci 0:0061165683ee 1388 statically allocated because @htmlonly USBD_Write() @endhtmlonly only
sdivarci 0:0061165683ee 1389 initiates the transfer. When the host actually performs the transfer, the
sdivarci 0:0061165683ee 1390 SetupCmd() function will have returned ! @n @n
sdivarci 0:0061165683ee 1391
sdivarci 0:0061165683ee 1392 @verbatim
sdivarci 0:0061165683ee 1393 #define VND_GET_LEDS 0x10
sdivarci 0:0061165683ee 1394 #define VND_SET_LED 0x11
sdivarci 0:0061165683ee 1395
sdivarci 0:0061165683ee 1396 static int SetupCmd( const USB_Setup_TypeDef *setup )
sdivarci 0:0061165683ee 1397 {
sdivarci 0:0061165683ee 1398 int retVal;
sdivarci 0:0061165683ee 1399 uint16_t leds;
sdivarci 0:0061165683ee 1400 static uint32_t buffer;
sdivarci 0:0061165683ee 1401 uint8_t *pBuffer = (uint8_t*)&buffer;
sdivarci 0:0061165683ee 1402
sdivarci 0:0061165683ee 1403 retVal = USB_STATUS_REQ_UNHANDLED;
sdivarci 0:0061165683ee 1404
sdivarci 0:0061165683ee 1405 if ( setup->Type == USB_SETUP_TYPE_VENDOR )
sdivarci 0:0061165683ee 1406 {
sdivarci 0:0061165683ee 1407 switch ( setup->bRequest )
sdivarci 0:0061165683ee 1408 {
sdivarci 0:0061165683ee 1409 case VND_GET_LEDS:
sdivarci 0:0061165683ee 1410 // ********************
sdivarci 0:0061165683ee 1411 *pBuffer = BSP_LedsGet() & 0x1F;
sdivarci 0:0061165683ee 1412 retVal = USBD_Write( 0, pBuffer, setup->wLength, NULL );
sdivarci 0:0061165683ee 1413 break;
sdivarci 0:0061165683ee 1414
sdivarci 0:0061165683ee 1415 case VND_SET_LED:
sdivarci 0:0061165683ee 1416 // ********************
sdivarci 0:0061165683ee 1417 leds = DVK_getLEDs() & 0x1F;
sdivarci 0:0061165683ee 1418 if ( setup->wValue )
sdivarci 0:0061165683ee 1419 {
sdivarci 0:0061165683ee 1420 leds |= LED0 << setup->wIndex;
sdivarci 0:0061165683ee 1421 }
sdivarci 0:0061165683ee 1422 else
sdivarci 0:0061165683ee 1423 {
sdivarci 0:0061165683ee 1424 leds &= ~( LED0 << setup->wIndex );
sdivarci 0:0061165683ee 1425 }
sdivarci 0:0061165683ee 1426 BSP_LedsSet( leds );
sdivarci 0:0061165683ee 1427 retVal = USB_STATUS_OK;
sdivarci 0:0061165683ee 1428 break;
sdivarci 0:0061165683ee 1429 }
sdivarci 0:0061165683ee 1430 }
sdivarci 0:0061165683ee 1431
sdivarci 0:0061165683ee 1432 return retVal;
sdivarci 0:0061165683ee 1433 }@endverbatim
sdivarci 0:0061165683ee 1434
sdivarci 0:0061165683ee 1435 * @}**************************************************************************/
sdivarci 0:0061165683ee 1436
sdivarci 0:0061165683ee 1437 #endif /* defined( USB_DEVICE ) */
sdivarci 0:0061165683ee 1438 #endif /* defined( USB_PRESENT ) && ( USB_COUNT == 1 ) */