--- /dev/null
+/* ----------------------------------------------------------------------------\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