]> git.sur5r.net Git - freertos/blobdiff - FreeRTOS/Demo/CORTEX_A5_SAMA5D3x_Xplained_IAR/AtmelFiles/usb/device/core/USBD.c
SAMA5D3 demo: Add CDC driver code and use CDC to create a simple command console.
[freertos] / FreeRTOS / Demo / CORTEX_A5_SAMA5D3x_Xplained_IAR / AtmelFiles / usb / device / core / USBD.c
diff --git a/FreeRTOS/Demo/CORTEX_A5_SAMA5D3x_Xplained_IAR/AtmelFiles/usb/device/core/USBD.c b/FreeRTOS/Demo/CORTEX_A5_SAMA5D3x_Xplained_IAR/AtmelFiles/usb/device/core/USBD.c
new file mode 100644 (file)
index 0000000..12dfa47
--- /dev/null
@@ -0,0 +1,550 @@
+/* ----------------------------------------------------------------------------\r
+ *         ATMEL Microcontroller Software Support\r
+ * ----------------------------------------------------------------------------\r
+ * Copyright (c) 2008, Atmel Corporation\r
+ *\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without\r
+ * modification, are permitted provided that the following conditions are met:\r
+ *\r
+ * - Redistributions of source code must retain the above copyright notice,\r
+ * this list of conditions and the disclaimer below.\r
+ *\r
+ * Atmel's name may not be used to endorse or promote products derived from\r
+ * this software without specific prior written permission.\r
+ *\r
+ * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR\r
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE\r
+ * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,\r
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\r
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,\r
+ * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\r
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\r
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\r
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+ * ----------------------------------------------------------------------------\r
+ */\r
+\r
+/** \file\r
+ *\r
+ *  \section Purpose\r
+ *\r
+ *  Implementation of USB device functions on a UDP controller.\r
+ *\r
+ *  See \ref usbd_api "USBD API Methods".\r
+ */\r
+\r
+/** \addtogroup usbd_interface\r
+ *@{\r
+ */\r
+\r
+/*---------------------------------------------------------------------------\r
+ *      Headers\r
+ *---------------------------------------------------------------------------*/\r
+\r
+#include "USBD.h"\r
+#include "USBD_HAL.h"\r
+\r
+#include <USBLib_Trace.h>\r
+\r
+/*---------------------------------------------------------------------------\r
+ *      Definitions\r
+ *---------------------------------------------------------------------------*/\r
+\r
+/*---------------------------------------------------------------------------\r
+ *      Internal variables\r
+ *---------------------------------------------------------------------------*/\r
+\r
+/** Device current state. */\r
+static uint8_t deviceState;\r
+/** Indicates the previous device state */\r
+static uint8_t previousDeviceState;\r
+\r
+/*---------------------------------------------------------------------------\r
+ *      Internal Functions\r
+ *---------------------------------------------------------------------------*/\r
+\r
+/*---------------------------------------------------------------------------\r
+ *      Exported functions\r
+ *---------------------------------------------------------------------------*/\r
+\r
+/*---------------------------------------------------------------------------\r
+ *      USBD: Event handlers\r
+ *---------------------------------------------------------------------------*/\r
+\r
+/**\r
+ *  Handle the USB suspend event, should be invoked whenever\r
+ *  HW reports a suspend signal.\r
+ */\r
+void USBD_SuspendHandler(void)\r
+{\r
+    /* Don't do anything if the device is already suspended */\r
+    if (deviceState != USBD_STATE_SUSPENDED) {\r
+\r
+        /* Switch to the Suspended state */\r
+        previousDeviceState = deviceState;\r
+        deviceState = USBD_STATE_SUSPENDED;\r
+\r
+        /* Suspend HW interface */\r
+        USBD_HAL_Suspend();\r
+\r
+        /* Invoke the User Suspended callback (Suspend System?) */\r
+        if (NULL != USBDCallbacks_Suspended)\r
+            USBDCallbacks_Suspended();\r
+    }\r
+}\r
+\r
+/**\r
+ *  Handle the USB resume event, should be invoked whenever\r
+ *  HW reports a resume signal.\r
+ */\r
+void USBD_ResumeHandler(void)\r
+{\r
+    /* Don't do anything if the device was not suspended */\r
+    if (deviceState == USBD_STATE_SUSPENDED) {\r
+        /* Active the device */\r
+        USBD_HAL_Activate();\r
+        deviceState = previousDeviceState;\r
+        if (deviceState >= USBD_STATE_DEFAULT) {\r
+            /* Invoke the Resume callback */\r
+            if (NULL != USBDCallbacks_Resumed)\r
+                USBDCallbacks_Resumed();\r
+        }\r
+    }\r
+}\r
+\r
+/**\r
+ *  Handle the USB reset event, should be invoked whenever\r
+ *  HW found USB reset signal on bus, which usually is called\r
+ *  "end of bus reset" status.\r
+ */\r
+void USBD_ResetHandler()\r
+{\r
+    /* The device enters the Default state */\r
+    deviceState = USBD_STATE_DEFAULT;\r
+    /* Active the USB HW */\r
+    USBD_HAL_Activate();\r
+    /* Only EP0 enabled */\r
+    USBD_HAL_ResetEPs(0xFFFFFFFF, USBD_STATUS_RESET, 0);\r
+    USBD_ConfigureEndpoint(0);\r
+    /* Invoke the Reset callback */\r
+    if (NULL != USBDCallbacks_Reset)\r
+        USBDCallbacks_Reset();\r
+}\r
+\r
+/**\r
+ *  Handle the USB setup package received, should be invoked\r
+ *  when an endpoint got a setup package as request.\r
+ *  \param bEndpoint Endpoint number.\r
+ *  \param pRequest  Pointer to content of request.\r
+ */\r
+void USBD_RequestHandler(uint8_t bEndpoint,\r
+                         const USBGenericRequest* pRequest)\r
+{\r
+    if (bEndpoint != 0) {\r
+        TRACE_WARNING("EP%d request not supported, default EP only",\r
+                      bEndpoint);\r
+    }\r
+    else if (NULL != USBDCallbacks_RequestReceived) {\r
+        USBDCallbacks_RequestReceived(pRequest);\r
+    }\r
+}\r
+\r
+/*---------------------------------------------------------------------------\r
+ *      USBD: Library interface\r
+ *---------------------------------------------------------------------------*/\r
+\r
+/**\r
+ * Configures an endpoint according to its Endpoint Descriptor.\r
+ * \param pDescriptor Pointer to an Endpoint descriptor.\r
+ */\r
+void USBD_ConfigureEndpoint(const USBEndpointDescriptor *pDescriptor)\r
+{\r
+    USBD_HAL_ConfigureEP(pDescriptor);\r
+}\r
+\r
+/**\r
+ * Sends data through a USB endpoint. Sets up the transfer descriptor,\r
+ * writes one or two data payloads (depending on the number of FIFO bank\r
+ * for the endpoint) and then starts the actual transfer. The operation is\r
+ * complete when all the data has been sent.\r
+ *\r
+ * *If the size of the buffer is greater than the size of the endpoint\r
+ *  (or twice the size if the endpoint has two FIFO banks), then the buffer\r
+ *  must be kept allocated until the transfer is finished*. This means that\r
+ *  it is not possible to declare it on the stack (i.e. as a local variable\r
+ *  of a function which returns after starting a transfer).\r
+ *\r
+ * \param bEndpoint Endpoint number.\r
+ * \param pData Pointer to a buffer with the data to send.\r
+ * \param dLength Size of the data buffer.\r
+ * \param fCallback Optional callback function to invoke when the transfer is\r
+ *        complete.\r
+ * \param pArgument Optional argument to the callback function.\r
+ * \return USBD_STATUS_SUCCESS if the transfer has been started;\r
+ *         otherwise, the corresponding error status code.\r
+ */\r
+uint8_t USBD_Write( uint8_t          bEndpoint,\r
+                    const void       *pData,\r
+                    uint32_t         dLength,\r
+                    TransferCallback fCallback,\r
+                    void             *pArgument )\r
+{\r
+    USBD_HAL_SetTransferCallback(bEndpoint, fCallback, pArgument);\r
+    return USBD_HAL_Write(bEndpoint, pData, dLength);\r
+}\r
+#if 0\r
+/**\r
+ * Sends data frames through a USB endpoint. Sets up the transfer descriptor\r
+ * list, writes one or two data payloads (depending on the number of FIFO bank\r
+ * for the endpoint) and then starts the actual transfer. The operation is\r
+ * complete when all the data has been sent.\r
+ *\r
+ * *If the size of the frame is greater than the size of the endpoint\r
+ *  (or twice the size if the endpoint has two FIFO banks), then the buffer\r
+ *  must be kept allocated until the frame is finished*. This means that\r
+ *  it is not possible to declare it on the stack (i.e. as a local variable\r
+ *  of a function which returns after starting a transfer).\r
+ *\r
+ * \param bEndpoint Endpoint number.\r
+ * \param pMbl Pointer to a frame (USBDTransferBuffer) list that describes\r
+ *             the buffer list to send.\r
+ * \param wListSize Size of the frame list.\r
+ * \param bCircList Circle the list.\r
+ * \param wStartNdx For circled list only, the first buffer index to transfer.\r
+ * \param fCallback Optional callback function to invoke when the transfer is\r
+ *        complete.\r
+ * \param pArgument Optional argument to the callback function.\r
+ * \return USBD_STATUS_SUCCESS if the transfer has been started;\r
+ *         otherwise, the corresponding error status code.\r
+ * \see USBDTransferBuffer, MblTransferCallback, USBD_MblReuse\r
+ */\r
+uint8_t USBD_MblWrite( uint8_t       bEndpoint,\r
+                    void                *pMbl,\r
+                    uint16_t      wListSize,\r
+                    uint8_t       bCircList,\r
+                    uint16_t      wStartNdx,\r
+                    MblTransferCallback fCallback,\r
+                    void                *pArgument )\r
+{\r
+    Endpoint    *pEndpoint = &(endpoints[bEndpoint]);\r
+    MblTransfer *pTransfer = (MblTransfer*)&(pEndpoint->transfer);\r
+    uint16_t i;\r
+\r
+    /* EP0 is not suitable for Mbl */\r
+\r
+    if (bEndpoint == 0) {\r
+\r
+        return USBD_STATUS_INVALID_PARAMETER;\r
+    }\r
+\r
+    /* Check that the endpoint is in Idle state */\r
+\r
+    if (pEndpoint->state != UDP_ENDPOINT_IDLE) {\r
+\r
+        return USBD_STATUS_LOCKED;\r
+    }\r
+    pEndpoint->state = UDP_ENDPOINT_SENDINGM;\r
+\r
+    TRACE_DEBUG_WP("WriteM%d(0x%x,%d) ", bEndpoint, pMbl, wListSize);\r
+\r
+    /* Start from first if not circled list */\r
+\r
+    if (!bCircList) wStartNdx = 0;\r
+\r
+    /* Setup the transfer descriptor */\r
+\r
+    pTransfer->pMbl        = (USBDTransferBuffer*)pMbl;\r
+    pTransfer->listSize    = wListSize;\r
+    pTransfer->fCallback   = fCallback;\r
+    pTransfer->pArgument   = pArgument;\r
+    pTransfer->currBuffer  = wStartNdx;\r
+    pTransfer->freedBuffer = 0;\r
+    pTransfer->pLastLoaded = &(((USBDTransferBuffer*)pMbl)[wStartNdx]);\r
+    pTransfer->circList    = bCircList;\r
+    pTransfer->allUsed     = 0;\r
+\r
+    /* Clear all buffer */\r
+\r
+    for (i = 0; i < wListSize; i ++) {\r
+\r
+        pTransfer->pMbl[i].transferred = 0;\r
+        pTransfer->pMbl[i].buffered   = 0;\r
+        pTransfer->pMbl[i].remaining   = pTransfer->pMbl[i].size;\r
+    }\r
+\r
+    /* Send the first packet */\r
+\r
+    while((UDP->UDP_CSR[bEndpoint]&UDP_CSR_TXPKTRDY)==UDP_CSR_TXPKTRDY);\r
+    UDP_MblWriteFifo(bEndpoint);\r
+    SET_CSR(bEndpoint, UDP_CSR_TXPKTRDY);\r
+\r
+    /* If double buffering is enabled and there is data remaining, */\r
+\r
+    /* prepare another packet */\r
+\r
+    if ((CHIP_USB_ENDPOINTS_BANKS(bEndpoint) > 1)\r
+        && (pTransfer->pMbl[pTransfer->currBuffer].remaining > 0)) {\r
+\r
+        UDP_MblWriteFifo(bEndpoint);\r
+    }\r
+\r
+    /* Enable interrupt on endpoint */\r
+\r
+    UDP->UDP_IER = 1 << bEndpoint;\r
+\r
+    return USBD_STATUS_SUCCESS;\r
+}\r
+#endif\r
+/**\r
+ * Reads incoming data on an USB endpoint This methods sets the transfer\r
+ * descriptor and activate the endpoint interrupt. The actual transfer is\r
+ * then carried out by the endpoint interrupt handler. The Read operation\r
+ * finishes either when the buffer is full, or a short packet (inferior to\r
+ * endpoint maximum  size) is received.\r
+ *\r
+ * *The buffer must be kept allocated until the transfer is finished*.\r
+ * \param bEndpoint Endpoint number.\r
+ * \param pData Pointer to a data buffer.\r
+ * \param dLength Size of the data buffer in bytes.\r
+ * \param fCallback Optional end-of-transfer callback function.\r
+ * \param pArgument Optional argument to the callback function.\r
+ * \return USBD_STATUS_SUCCESS if the read operation has been started;\r
+ *         otherwise, the corresponding error code.\r
+ */\r
+uint8_t USBD_Read(uint8_t          bEndpoint,\r
+                  void             *pData,\r
+                  uint32_t         dLength,\r
+                  TransferCallback fCallback,\r
+                  void             *pArgument)\r
+{\r
+    USBD_HAL_SetTransferCallback(bEndpoint, fCallback, pArgument);\r
+    return USBD_HAL_Read(bEndpoint, pData, dLength);\r
+}\r
+#if 0\r
+/**\r
+ * Reuse first used/released buffer with new buffer address and size to be used\r
+ * in transfer again. Only valid when frame list is ringed. Can be used for\r
+ * both read & write.\r
+ * \param bEndpoint  Endpoint number.\r
+ * \param pNewBuffer Pointer to new buffer with data to send (0 to keep last).\r
+ * \param wNewSize   Size of the data buffer\r
+ */\r
+uint8_t USBD_MblReuse( uint8_t  bEndpoint,\r
+                    uint8_t  *pNewBuffer,\r
+                    uint16_t wNewSize )\r
+{\r
+    Endpoint *pEndpoint = &(endpoints[bEndpoint]);\r
+    MblTransfer *pTransfer = (MblTransfer*)&(pEndpoint->transfer);\r
+    USBDTransferBuffer *pBi = &(pTransfer->pMbl[pTransfer->freedBuffer]);\r
+\r
+    TRACE_DEBUG_WP("MblReuse(%d), st%x, circ%d\n\r",\r
+        bEndpoint, pEndpoint->state, pTransfer->circList);\r
+\r
+    /* Only for Multi-buffer-circle list */\r
+\r
+    if (bEndpoint != 0\r
+        && (pEndpoint->state == UDP_ENDPOINT_RECEIVINGM\r
+            || pEndpoint->state == UDP_ENDPOINT_SENDINGM)\r
+        && pTransfer->circList) {\r
+    }\r
+    else {\r
+\r
+        return USBD_STATUS_WRONG_STATE;\r
+    }\r
+\r
+    /* Check if there is freed buffer */\r
+\r
+    if (pTransfer->freedBuffer == pTransfer->currBuffer\r
+        && !pTransfer->allUsed) {\r
+\r
+        return USBD_STATUS_LOCKED;\r
+   }\r
+\r
+    /* Update transfer information */\r
+\r
+    if ((++ pTransfer->freedBuffer) == pTransfer->listSize)\r
+        pTransfer->freedBuffer = 0;\r
+    if (pNewBuffer) {\r
+        pBi->pBuffer = pNewBuffer;\r
+        pBi->size    = wNewSize;\r
+    }\r
+    pBi->buffered    = 0;\r
+    pBi->transferred = 0;\r
+    pBi->remaining   = pBi->size;\r
+\r
+    /* At least one buffer is not processed */\r
+\r
+    pTransfer->allUsed = 0;\r
+    return USBD_STATUS_SUCCESS;\r
+}\r
+#endif\r
+/**\r
+ * Sets the HALT feature on the given endpoint (if not already in this state).\r
+ * \param bEndpoint Endpoint number.\r
+ */\r
+void USBD_Halt(uint8_t bEndpoint)\r
+{\r
+    USBD_HAL_Halt(bEndpoint, 1);\r
+}\r
+\r
+/**\r
+ * Clears the Halt feature on the given endpoint.\r
+ * \param bEndpoint Index of endpoint\r
+ */\r
+void USBD_Unhalt(uint8_t bEndpoint)\r
+{\r
+    USBD_HAL_Halt(bEndpoint, 0);\r
+}\r
+\r
+/**\r
+ * Returns the current Halt status of an endpoint.\r
+ * \param bEndpoint Index of endpoint\r
+ * \return 1 if the endpoint is currently halted; otherwise 0\r
+ */\r
+uint8_t USBD_IsHalted(uint8_t bEndpoint)\r
+{\r
+    return USBD_HAL_Halt(bEndpoint, 0xFF);\r
+}\r
+\r
+/**\r
+ * Indicates if the device is running in high or full-speed. Always returns 0\r
+ * since UDP does not support high-speed mode.\r
+ */\r
+uint8_t USBD_IsHighSpeed(void)\r
+{\r
+    return USBD_HAL_IsHighSpeed();\r
+}\r
+\r
+/**\r
+ * Causes the given endpoint to acknowledge the next packet it receives\r
+ * with a STALL handshake.\r
+ * \param bEndpoint Endpoint number.\r
+ * \return USBD_STATUS_SUCCESS or USBD_STATUS_LOCKED.\r
+ */\r
+uint8_t USBD_Stall(uint8_t bEndpoint)\r
+\r
+{\r
+    return USBD_HAL_Stall(bEndpoint);\r
+}\r
+\r
+/**\r
+ * Sets the device address to the given value.\r
+ * \param address New device address.\r
+ */\r
+void USBD_SetAddress(uint8_t address)\r
+{\r
+    TRACE_INFO_WP("SetAddr(%d) ", address);\r
+\r
+    USBD_HAL_SetAddress(address);\r
+    if (address == 0) deviceState = USBD_STATE_DEFAULT;\r
+    else              deviceState = USBD_STATE_ADDRESS;\r
+}\r
+\r
+/**\r
+ * Sets the current device configuration.\r
+ * \param cfgnum - Configuration number to set.\r
+ */\r
+void USBD_SetConfiguration(uint8_t cfgnum)\r
+{\r
+    TRACE_INFO_WP("SetCfg(%d) ", cfgnum);\r
+\r
+    USBD_HAL_SetConfiguration(cfgnum);\r
+\r
+    if (cfgnum != 0) {\r
+        deviceState = USBD_STATE_CONFIGURED;\r
+    }\r
+    else {\r
+        deviceState = USBD_STATE_ADDRESS;\r
+        /* Reset all endpoints but Control 0 */\r
+        USBD_HAL_ResetEPs(0xFFFFFFFE, USBD_STATUS_RESET, 0);\r
+    }\r
+}\r
+\r
+/*---------------------------------------------------------------------------\r
+ *      USBD: Library API\r
+ *---------------------------------------------------------------------------*/\r
+\r
+/**\r
+ * Starts a remote wake-up procedure.\r
+ */\r
+void USBD_RemoteWakeUp(void)\r
+{\r
+    /* Device is NOT suspended */\r
+    if (deviceState != USBD_STATE_SUSPENDED) {\r
+\r
+        TRACE_INFO("USBD_RemoteWakeUp: Device is not suspended\n\r");\r
+        return;\r
+    }\r
+    USBD_HAL_Activate();\r
+    USBD_HAL_RemoteWakeUp();\r
+}\r
+\r
+/**\r
+ * Connects the pull-up on the D+ line of the USB.\r
+ */\r
+void USBD_Connect(void)\r
+{\r
+    USBD_HAL_Connect();\r
+}\r
+\r
+/**\r
+ * Disconnects the pull-up from the D+ line of the USB.\r
+ */\r
+void USBD_Disconnect(void)\r
+{\r
+    USBD_HAL_Disconnect();\r
+\r
+    /* Device returns to the Powered state */\r
+\r
+    if (deviceState > USBD_STATE_POWERED) {\r
+\r
+        deviceState = USBD_STATE_POWERED;\r
+    }\r
+\r
+    if (previousDeviceState > USBD_STATE_POWERED) {\r
+\r
+        previousDeviceState = USBD_STATE_POWERED;\r
+    }\r
+}\r
+\r
+/**\r
+ * Initializes the USB driver.\r
+ */\r
+void USBD_Init(void)\r
+{\r
+    TRACE_INFO_WP("USBD_Init\n\r");\r
+\r
+    /* HW Layer Initialize */\r
+    USBD_HAL_Init();\r
+\r
+    /* Device is in the Attached state */\r
+    deviceState = USBD_STATE_SUSPENDED;\r
+    previousDeviceState = USBD_STATE_POWERED;\r
+\r
+    /* Upper Layer Initialize */\r
+    if (NULL != USBDCallbacks_Initialized)\r
+        USBDCallbacks_Initialized();\r
+}\r
+\r
+/**\r
+ * Returns the current state of the USB device.\r
+ * \return Device current state.\r
+ */\r
+uint8_t USBD_GetState(void)\r
+{\r
+    return deviceState;\r
+}\r
+\r
+/**\r
+ * Certification test for High Speed device.\r
+ * \param bIndex Test to be done\r
+ */\r
+void USBD_Test(uint8_t bIndex)\r
+{\r
+    USBD_HAL_Test(bIndex);\r
+}\r
+\r
+/**@}*/\r