SAMV71 Xplained Ultra Software Package 1.3

USBD.c

Go to the documentation of this file.
00001 /* ----------------------------------------------------------------------------
00002  *         ATMEL Microcontroller Software Support
00003  * ----------------------------------------------------------------------------
00004  * Copyright (c) 2008, Atmel Corporation
00005  *
00006  * All rights reserved.
00007  *
00008  * Redistribution and use in source and binary forms, with or without
00009  * modification, are permitted provided that the following conditions are met:
00010  *
00011  * - Redistributions of source code must retain the above copyright notice,
00012  * this list of conditions and the disclaimer below.
00013  *
00014  * Atmel's name may not be used to endorse or promote products derived from
00015  * this software without specific prior written permission.
00016  *
00017  * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
00018  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
00019  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
00020  * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
00021  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
00022  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
00023  * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
00024  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
00025  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
00026  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00027  * ----------------------------------------------------------------------------
00028  */
00029 
00030 /** \file
00031  *
00032  *  \section Purpose
00033  *
00034  *  Implementation of USB device functions on a UDP controller.
00035  *
00036  *  See \ref usbd_api "USBD API Methods".
00037  */
00038 
00039 /** \addtogroup usbd_interface
00040  *@{
00041  */
00042 
00043 /*---------------------------------------------------------------------------
00044  *      Headers
00045  *---------------------------------------------------------------------------*/
00046 
00047 #include "USBD.h"
00048 #include "USBD_HAL.h"
00049 
00050 #include <USBLib_Trace.h>
00051 
00052 /*---------------------------------------------------------------------------
00053  *      Definitions
00054  *---------------------------------------------------------------------------*/
00055 
00056 /*---------------------------------------------------------------------------
00057  *      Internal variables
00058  *---------------------------------------------------------------------------*/
00059 
00060 /** Device current state. */
00061 static uint8_t deviceState;
00062 /** Indicates the previous device state */
00063 static uint8_t previousDeviceState;
00064 
00065 uint8_t ForceFS = 0;
00066 
00067 /*---------------------------------------------------------------------------
00068  *      Internal Functions
00069  *---------------------------------------------------------------------------*/
00070 
00071 /*---------------------------------------------------------------------------
00072  *      Exported functions
00073  *---------------------------------------------------------------------------*/
00074 
00075 /*---------------------------------------------------------------------------
00076  *      USBD: Event handlers
00077  *---------------------------------------------------------------------------*/
00078 
00079 /**
00080  *  Handle the USB suspend event, should be invoked whenever
00081  *  HW reports a suspend signal.
00082  */
00083 void USBD_SuspendHandler(void)
00084 {
00085     /* Don't do anything if the device is already suspended */
00086     if (deviceState != USBD_STATE_SUSPENDED) {
00087 
00088         /* Switch to the Suspended state */
00089         previousDeviceState = deviceState;
00090         deviceState = USBD_STATE_SUSPENDED;
00091 
00092         /* Suspend HW interface */
00093         USBD_HAL_Suspend();
00094 
00095         /* Invoke the User Suspended callback (Suspend System?) */
00096         if (NULL != USBDCallbacks_Suspended)
00097             USBDCallbacks_Suspended();
00098     }
00099 }
00100 
00101 /**
00102  *  Handle the USB resume event, should be invoked whenever
00103  *  HW reports a resume signal.
00104  */
00105 void USBD_ResumeHandler(void)
00106 {
00107     /* Don't do anything if the device was not suspended */
00108     if (deviceState == USBD_STATE_SUSPENDED) {
00109         /* Active the device */
00110         USBD_HAL_Activate();
00111         deviceState = previousDeviceState;
00112         if (deviceState >= USBD_STATE_DEFAULT) {
00113             /* Invoke the Resume callback */
00114             if (NULL != USBDCallbacks_Resumed)
00115                 USBDCallbacks_Resumed();
00116         }
00117     }
00118 }
00119 
00120 /**
00121  *  Handle the USB reset event, should be invoked whenever
00122  *  HW found USB reset signal on bus, which usually is called
00123  *  "end of bus reset" status.
00124  */
00125 void USBD_ResetHandler()
00126 {
00127     /* The device enters the Default state */
00128     deviceState = USBD_STATE_DEFAULT;
00129     /* Active the USB HW */
00130     USBD_HAL_Activate();
00131     /* Only EP0 enabled */
00132     USBD_HAL_ResetEPs(0xFFFFFFFF, USBD_STATUS_RESET, 0);
00133     USBD_ConfigureEndpoint(0);
00134     /* Invoke the Reset callback */
00135     if (NULL != USBDCallbacks_Reset)
00136         USBDCallbacks_Reset();
00137 }
00138 
00139 /**
00140  *  Handle the USB setup package received, should be invoked
00141  *  when an endpoint got a setup package as request.
00142  *  \param bEndpoint Endpoint number.
00143  *  \param pRequest  Pointer to content of request.
00144  */
00145 void USBD_RequestHandler(uint8_t bEndpoint,
00146                          const USBGenericRequest* pRequest)
00147 {
00148     if (bEndpoint != 0) {
00149         TRACE_WARNING("EP%d request not supported, default EP only",
00150                       bEndpoint);
00151     }
00152     else if (NULL != USBDCallbacks_RequestReceived) {
00153         USBDCallbacks_RequestReceived(pRequest);
00154     }
00155 }
00156 
00157 /*---------------------------------------------------------------------------
00158  *      USBD: Library interface
00159  *---------------------------------------------------------------------------*/
00160 
00161 /**
00162  * Configures an endpoint according to its Endpoint Descriptor.
00163  * \param pDescriptor Pointer to an Endpoint descriptor.
00164  */
00165 void USBD_ConfigureEndpoint(const USBEndpointDescriptor *pDescriptor)
00166 {
00167     USBD_HAL_ConfigureEP(pDescriptor);
00168 }
00169 
00170 /**
00171  * Sends data through a USB endpoint. Sets up the transfer descriptor,
00172  * writes one or two data payloads (depending on the number of FIFO bank
00173  * for the endpoint) and then starts the actual transfer. The operation is
00174  * complete when all the data has been sent.
00175  *
00176  * *If the size of the buffer is greater than the size of the endpoint
00177  *  (or twice the size if the endpoint has two FIFO banks), then the buffer
00178  *  must be kept allocated until the transfer is finished*. This means that
00179  *  it is not possible to declare it on the stack (i.e. as a local variable
00180  *  of a function which returns after starting a transfer).
00181  *
00182  * \param bEndpoint Endpoint number.
00183  * \param pData Pointer to a buffer with the data to send.
00184  * \param dLength Size of the data buffer.
00185  * \param fCallback Optional callback function to invoke when the transfer is
00186  *        complete.
00187  * \param pArgument Optional argument to the callback function.
00188  * \return USBD_STATUS_SUCCESS if the transfer has been started;
00189  *         otherwise, the corresponding error status code.
00190  */
00191 uint8_t USBD_Write( uint8_t          bEndpoint,
00192                     const void       *pData,
00193                     uint32_t         dLength,
00194                     TransferCallback fCallback,
00195                     void             *pArgument )
00196 {
00197     USBD_HAL_SetTransferCallback(bEndpoint, fCallback, pArgument);
00198     return USBD_HAL_Write(bEndpoint, pData, dLength);
00199 }
00200 #if 0
00201 /**
00202  * Sends data frames through a USB endpoint. Sets up the transfer descriptor
00203  * list, writes one or two data payloads (depending on the number of FIFO bank
00204  * for the endpoint) and then starts the actual transfer. The operation is
00205  * complete when all the data has been sent.
00206  *
00207  * *If the size of the frame is greater than the size of the endpoint
00208  *  (or twice the size if the endpoint has two FIFO banks), then the buffer
00209  *  must be kept allocated until the frame is finished*. This means that
00210  *  it is not possible to declare it on the stack (i.e. as a local variable
00211  *  of a function which returns after starting a transfer).
00212  *
00213  * \param bEndpoint Endpoint number.
00214  * \param pMbl Pointer to a frame (USBDTransferBuffer) list that describes
00215  *             the buffer list to send.
00216  * \param wListSize Size of the frame list.
00217  * \param bCircList Circle the list.
00218  * \param wStartNdx For circled list only, the first buffer index to transfer.
00219  * \param fCallback Optional callback function to invoke when the transfer is
00220  *        complete.
00221  * \param pArgument Optional argument to the callback function.
00222  * \return USBD_STATUS_SUCCESS if the transfer has been started;
00223  *         otherwise, the corresponding error status code.
00224  * \see USBDTransferBuffer, MblTransferCallback, USBD_MblReuse
00225  */
00226 uint8_t USBD_MblWrite( uint8_t       bEndpoint,
00227                     void                *pMbl,
00228                     uint16_t      wListSize,
00229                     uint8_t       bCircList,
00230                     uint16_t      wStartNdx,
00231                     MblTransferCallback fCallback,
00232                     void                *pArgument )
00233 {
00234     Endpoint    *pEndpoint = &(endpoints[bEndpoint]);
00235     MblTransfer *pTransfer = (MblTransfer*)&(pEndpoint->transfer);
00236     uint16_t i;
00237 
00238     /* EP0 is not suitable for Mbl */
00239 
00240     if (bEndpoint == 0) {
00241 
00242         return USBD_STATUS_INVALID_PARAMETER;
00243     }
00244 
00245     /* Check that the endpoint is in Idle state */
00246 
00247     if (pEndpoint->state != UDP_ENDPOINT_IDLE) {
00248 
00249         return USBD_STATUS_LOCKED;
00250     }
00251     pEndpoint->state = UDP_ENDPOINT_SENDINGM;
00252 
00253     TRACE_DEBUG_WP("WriteM%d(0x%x,%d) ", bEndpoint, pMbl, wListSize);
00254 
00255     /* Start from first if not circled list */
00256 
00257     if (!bCircList) wStartNdx = 0;
00258 
00259     /* Setup the transfer descriptor */
00260 
00261     pTransfer->pMbl        = (USBDTransferBuffer*)pMbl;
00262     pTransfer->listSize    = wListSize;
00263     pTransfer->fCallback   = fCallback;
00264     pTransfer->pArgument   = pArgument;
00265     pTransfer->currBuffer  = wStartNdx;
00266     pTransfer->freedBuffer = 0;
00267     pTransfer->pLastLoaded = &(((USBDTransferBuffer*)pMbl)[wStartNdx]);
00268     pTransfer->circList    = bCircList;
00269     pTransfer->allUsed     = 0;
00270 
00271     /* Clear all buffer */
00272 
00273     for (i = 0; i < wListSize; i ++) {
00274 
00275         pTransfer->pMbl[i].transferred = 0;
00276         pTransfer->pMbl[i].buffered   = 0;
00277         pTransfer->pMbl[i].remaining   = pTransfer->pMbl[i].size;
00278     }
00279 
00280     /* Send the first packet */
00281 
00282     while((UDP->UDP_CSR[bEndpoint]&UDP_CSR_TXPKTRDY)==UDP_CSR_TXPKTRDY);
00283     UDP_MblWriteFifo(bEndpoint);
00284     SET_CSR(bEndpoint, UDP_CSR_TXPKTRDY);
00285 
00286     /* If double buffering is enabled and there is data remaining, */
00287 
00288     /* prepare another packet */
00289 
00290     if ((CHIP_USB_ENDPOINTS_BANKS(bEndpoint) > 1)
00291         && (pTransfer->pMbl[pTransfer->currBuffer].remaining > 0)) {
00292 
00293         UDP_MblWriteFifo(bEndpoint);
00294     }
00295 
00296     /* Enable interrupt on endpoint */
00297 
00298     UDP->UDP_IER = 1 << bEndpoint;
00299 
00300     return USBD_STATUS_SUCCESS;
00301 }
00302 #endif
00303 /**
00304  * Reads incoming data on an USB endpoint This methods sets the transfer
00305  * descriptor and activate the endpoint interrupt. The actual transfer is
00306  * then carried out by the endpoint interrupt handler. The Read operation
00307  * finishes either when the buffer is full, or a short packet (inferior to
00308  * endpoint maximum  size) is received.
00309  *
00310  * *The buffer must be kept allocated until the transfer is finished*.
00311  * \param bEndpoint Endpoint number.
00312  * \param pData Pointer to a data buffer.
00313  * \param dLength Size of the data buffer in bytes.
00314  * \param fCallback Optional end-of-transfer callback function.
00315  * \param pArgument Optional argument to the callback function.
00316  * \return USBD_STATUS_SUCCESS if the read operation has been started;
00317  *         otherwise, the corresponding error code.
00318  */
00319 uint8_t USBD_Read(uint8_t          bEndpoint,
00320                   void             *pData,
00321                   uint32_t         dLength,
00322                   TransferCallback fCallback,
00323                   void             *pArgument)
00324 {
00325     USBD_HAL_SetTransferCallback(bEndpoint, fCallback, pArgument);
00326     return USBD_HAL_Read(bEndpoint, pData, dLength);
00327 }
00328 #if 0
00329 /**
00330  * Reuse first used/released buffer with new buffer address and size to be used
00331  * in transfer again. Only valid when frame list is ringed. Can be used for
00332  * both read & write.
00333  * \param bEndpoint  Endpoint number.
00334  * \param pNewBuffer Pointer to new buffer with data to send (0 to keep last).
00335  * \param wNewSize   Size of the data buffer
00336  */
00337 uint8_t USBD_MblReuse( uint8_t  bEndpoint,
00338                     uint8_t  *pNewBuffer,
00339                     uint16_t wNewSize )
00340 {
00341     Endpoint *pEndpoint = &(endpoints[bEndpoint]);
00342     MblTransfer *pTransfer = (MblTransfer*)&(pEndpoint->transfer);
00343     USBDTransferBuffer *pBi = &(pTransfer->pMbl[pTransfer->freedBuffer]);
00344 
00345     TRACE_DEBUG_WP("MblReuse(%d), st%x, circ%d\n\r",
00346         bEndpoint, pEndpoint->state, pTransfer->circList);
00347 
00348     /* Only for Multi-buffer-circle list */
00349 
00350     if (bEndpoint != 0
00351         && (pEndpoint->state == UDP_ENDPOINT_RECEIVINGM
00352             || pEndpoint->state == UDP_ENDPOINT_SENDINGM)
00353         && pTransfer->circList) {
00354     }
00355     else {
00356 
00357         return USBD_STATUS_WRONG_STATE;
00358     }
00359 
00360     /* Check if there is freed buffer */
00361 
00362     if (pTransfer->freedBuffer == pTransfer->currBuffer
00363         && !pTransfer->allUsed) {
00364 
00365         return USBD_STATUS_LOCKED;
00366    }
00367 
00368     /* Update transfer information */
00369 
00370     if ((++ pTransfer->freedBuffer) == pTransfer->listSize)
00371         pTransfer->freedBuffer = 0;
00372     if (pNewBuffer) {
00373         pBi->pBuffer = pNewBuffer;
00374         pBi->size    = wNewSize;
00375     }
00376     pBi->buffered    = 0;
00377     pBi->transferred = 0;
00378     pBi->remaining   = pBi->size;
00379 
00380     /* At least one buffer is not processed */
00381 
00382     pTransfer->allUsed = 0;
00383     return USBD_STATUS_SUCCESS;
00384 }
00385 #endif
00386 /**
00387  * Sets the HALT feature on the given endpoint (if not already in this state).
00388  * \param bEndpoint Endpoint number.
00389  */
00390 void USBD_Halt(uint8_t bEndpoint)
00391 {
00392     USBD_HAL_Halt(bEndpoint, 1);
00393 }
00394 
00395 /**
00396  * Clears the Halt feature on the given endpoint.
00397  * \param bEndpoint Index of endpoint
00398  */
00399 void USBD_Unhalt(uint8_t bEndpoint)
00400 {
00401     USBD_HAL_Halt(bEndpoint, 0);
00402 }
00403 
00404 /**
00405  * Returns the current Halt status of an endpoint.
00406  * \param bEndpoint Index of endpoint
00407  * \return 1 if the endpoint is currently halted; otherwise 0
00408  */
00409 uint8_t USBD_IsHalted(uint8_t bEndpoint)
00410 {
00411     return USBD_HAL_Halt(bEndpoint, 0xFF);
00412 }
00413 
00414 /**
00415  * Indicates if the device is running in high or full-speed. Always returns 0
00416  * since UDP does not support high-speed mode.
00417  */
00418 uint8_t USBD_IsHighSpeed(void)
00419 {
00420     return USBD_HAL_IsHighSpeed();
00421 }
00422 
00423 /**
00424  * Causes the given endpoint to acknowledge the next packet it receives
00425  * with a STALL handshake.
00426  * \param bEndpoint Endpoint number.
00427  * \return USBD_STATUS_SUCCESS or USBD_STATUS_LOCKED.
00428  */
00429 uint8_t USBD_Stall(uint8_t bEndpoint)
00430 
00431 {
00432     return USBD_HAL_Stall(bEndpoint);
00433 }
00434 
00435 /**
00436  * Sets the device address to the given value.
00437  * \param address New device address.
00438  */
00439 void USBD_SetAddress(uint8_t address)
00440 {
00441     TRACE_INFO_WP("SetAddr(%d) ", address);
00442 
00443     USBD_HAL_SetAddress(address);
00444     if (address == 0) deviceState = USBD_STATE_DEFAULT;
00445     else              deviceState = USBD_STATE_ADDRESS;
00446 }
00447 
00448 /**
00449  * Sets the current device configuration.
00450  * \param cfgnum - Configuration number to set.
00451  */
00452 void USBD_SetConfiguration(uint8_t cfgnum)
00453 {
00454     TRACE_INFO_WP("SetCfg(%d) ", cfgnum);
00455 
00456     USBD_HAL_SetConfiguration(cfgnum);
00457 
00458     if (cfgnum != 0) {
00459         deviceState = USBD_STATE_CONFIGURED;
00460     }
00461     else {
00462         deviceState = USBD_STATE_ADDRESS;
00463         /* Reset all endpoints but Control 0 */
00464         USBD_HAL_ResetEPs(0xFFFFFFFE, USBD_STATUS_RESET, 0);
00465     }
00466 }
00467 
00468 /*---------------------------------------------------------------------------
00469  *      USBD: Library API
00470  *---------------------------------------------------------------------------*/
00471 
00472 /**
00473  * Starts a remote wake-up procedure.
00474  */
00475 void USBD_RemoteWakeUp(void)
00476 {
00477     /* Device is NOT suspended */
00478     if (deviceState != USBD_STATE_SUSPENDED) {
00479 
00480         TRACE_INFO("USBD_RemoteWakeUp: Device is not suspended\n\r");
00481         return;
00482     }
00483     USBD_HAL_Activate();
00484     USBD_HAL_RemoteWakeUp();
00485 }
00486 
00487 /**
00488  * Connects the pull-up on the D+ line of the USB.
00489  */
00490 void USBD_Connect(void)
00491 {
00492     TRACE_INFO(" Connect -");
00493     USBD_HAL_Connect();
00494 }
00495 
00496 /**
00497  * Disconnects the pull-up from the D+ line of the USB.
00498  */
00499 void USBD_Disconnect(void)
00500 {
00501   TRACE_INFO(" DisConnect -");
00502     USBD_HAL_Disconnect();
00503 
00504     /* Device returns to the Powered state */
00505 
00506     if (deviceState > USBD_STATE_POWERED) {
00507 
00508         deviceState = USBD_STATE_POWERED;
00509     }
00510 
00511     if (previousDeviceState > USBD_STATE_POWERED) {
00512 
00513         previousDeviceState = USBD_STATE_POWERED;
00514     }
00515 }
00516 
00517 /**
00518  * Initializes the USB driver.
00519  */
00520 void USBD_Init(void)
00521 {
00522     TRACE_INFO_WP("USBD_Init\n\r");
00523 
00524     /* HW Layer Initialize */
00525     USBD_HAL_Init();
00526 
00527     /* Device is in the Attached state */
00528     deviceState = USBD_STATE_SUSPENDED;
00529     previousDeviceState = USBD_STATE_POWERED;
00530 
00531     /* Upper Layer Initialize */
00532     if (NULL != USBDCallbacks_Initialized)
00533         USBDCallbacks_Initialized();
00534 }
00535 
00536 /**
00537  * Returns the current state of the USB device.
00538  * \return Device current state.
00539  */
00540 uint8_t USBD_GetState(void)
00541 {
00542     return deviceState;
00543 }
00544 
00545 /**
00546  * Certification test for High Speed device.
00547  * \param bIndex Test to be done
00548  */
00549 void USBD_Test(uint8_t bIndex)
00550 {
00551     USBD_HAL_Test(bIndex);
00552 }
00553 
00554 
00555 void USBD_ForceFullSpeed(void)
00556 {
00557   ForceFS = 1;
00558 }
00559 
00560 /**@}*/
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines