aboutsummaryrefslogtreecommitdiffstats
path: root/firmware/atmel_softpack_libraries/libchip_sam3s/source/USBD_HAL.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/atmel_softpack_libraries/libchip_sam3s/source/USBD_HAL.c')
-rw-r--r--firmware/atmel_softpack_libraries/libchip_sam3s/source/USBD_HAL.c1702
1 files changed, 1702 insertions, 0 deletions
diff --git a/firmware/atmel_softpack_libraries/libchip_sam3s/source/USBD_HAL.c b/firmware/atmel_softpack_libraries/libchip_sam3s/source/USBD_HAL.c
new file mode 100644
index 0000000..7776004
--- /dev/null
+++ b/firmware/atmel_softpack_libraries/libchip_sam3s/source/USBD_HAL.c
@@ -0,0 +1,1702 @@
+/* ----------------------------------------------------------------------------
+ * ATMEL Microcontroller Software Support
+ * ----------------------------------------------------------------------------
+ * Copyright (c) 2008, Atmel Corporation
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the disclaimer below.
+ *
+ * Atmel's name may not be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
+ * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+ * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ----------------------------------------------------------------------------
+ */
+
+/**
+
+ \file
+
+ \section Purpose
+
+ Implementation of USB device functions on a UDP controller.
+
+ See \ref usbd_api_method USBD API Methods.
+*/
+
+/** \addtogroup usbd_hal
+ *@{*/
+
+/*---------------------------------------------------------------------------
+ * Headers
+ *---------------------------------------------------------------------------*/
+
+#ifdef TRACE_LEVEL
+#undef TRACE_LEVEL
+#endif
+#define TRACE_LEVEL TRACE_LEVEL_WARNING
+
+#include "chip.h"
+#include "USBD_HAL.h"
+#include <usb/device/dfu/dfu.h>
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+
+/*---------------------------------------------------------------------------
+ * Definitions
+ *---------------------------------------------------------------------------*/
+
+/** Indicates chip has an UDP Full Speed. */
+#define CHIP_USB_UDP
+
+/** Indicates chip has an internal pull-up. */
+#define CHIP_USB_PULLUP_INTERNAL
+
+/** Number of USB endpoints */
+#define CHIP_USB_NUMENDPOINTS 8
+
+/** Endpoints max paxcket size */
+#define CHIP_USB_ENDPOINTS_MAXPACKETSIZE(i) \
+ ((i == 0) ? 64 : \
+ ((i == 1) ? 64 : \
+ ((i == 2) ? 64 : \
+ ((i == 3) ? 64 : \
+ ((i == 4) ? 512 : \
+ ((i == 5) ? 512 : \
+ ((i == 6) ? 64 : \
+ ((i == 7) ? 64 : 0 ))))))))
+
+/** Endpoints Number of Bank */
+#define CHIP_USB_ENDPOINTS_BANKS(i) \
+ ((i == 0) ? 1 : \
+ ((i == 1) ? 2 : \
+ ((i == 2) ? 2 : \
+ ((i == 3) ? 1 : \
+ ((i == 4) ? 2 : \
+ ((i == 5) ? 2 : \
+ ((i == 6) ? 2 : \
+ ((i == 7) ? 2 : 0 ))))))))
+
+/**
+ * \section UDP_registers_sec "UDP Register field values"
+ *
+ * This section lists the initialize values of UDP registers.
+ *
+ * \subsection Values
+ * - UDP_RXDATA
+ */
+/** Bit mask for both banks of the UDP_CSR register. */
+#define UDP_CSR_RXDATA_BK (UDP_CSR_RX_DATA_BK0 | UDP_CSR_RX_DATA_BK1)
+
+/**
+ * \section endpoint_states_sec "UDP Endpoint states"
+ *
+ * This page lists the endpoint states.
+ *
+ * \subsection States
+ * - UDP_ENDPOINT_DISABLED
+ * - UDP_ENDPOINT_HALTED
+ * - UDP_ENDPOINT_IDLE
+ * - UDP_ENDPOINT_SENDING
+ * - UDP_ENDPOINT_RECEIVING
+ * - UDP_ENDPOINT_SENDINGM
+ * - UDP_ENDPOINT_RECEIVINGM
+ */
+
+/** Endpoint states: Endpoint is disabled */
+#define UDP_ENDPOINT_DISABLED 0
+/** Endpoint states: Endpoint is halted (i.e. STALLs every request) */
+#define UDP_ENDPOINT_HALTED 1
+/** Endpoint states: Endpoint is idle (i.e. ready for transmission) */
+#define UDP_ENDPOINT_IDLE 2
+/** Endpoint states: Endpoint is sending data */
+#define UDP_ENDPOINT_SENDING 3
+/** Endpoint states: Endpoint is receiving data */
+#define UDP_ENDPOINT_RECEIVING 4
+/** Endpoint states: Endpoint is sending MBL */
+#define UDP_ENDPOINT_SENDINGM 5
+/** Endpoint states: Endpoint is receiving MBL */
+#define UDP_ENDPOINT_RECEIVINGM 6
+
+/**
+ * \section udp_csr_register_access_sec "UDP CSR register access"
+ *
+ * This page lists the macros to access UDP CSR register.
+ *
+ * \comment
+ * In a preemptive environment, set or clear the flag and wait for a time of
+ * 1 UDPCK clock cycle and 1 peripheral clock cycle. However, RX_DATA_BK0,
+ * TXPKTRDY, RX_DATA_BK1 require wait times of 3 UDPCK clock cycles and
+ * 5 peripheral clock cycles before accessing DPR.
+ * See datasheet
+ *
+ * !Macros
+ * - CLEAR_CSR
+ * - SET_CSR
+ */
+
+#if defined ( __CC_ARM )
+ #define nop() {volatile int h; for(h=0;h<10;h++){}}
+#elif defined ( __ICCARM__ )
+ #include <intrinsics.h>
+ #define nop() (__no_operation())
+#elif defined ( __GNUC__ )
+ #define nop() __asm__ __volatile__ ( "nop" )
+#endif
+
+
+/** Bitmap for all status bits in CSR. */
+#define REG_NO_EFFECT_1_ALL UDP_CSR_RX_DATA_BK0 | UDP_CSR_RX_DATA_BK1 \
+ |UDP_CSR_STALLSENTISOERROR | UDP_CSR_RXSETUP \
+ |UDP_CSR_TXCOMP
+
+/**
+ * Sets the specified bit(s) in the UDP_CSR register.
+ *
+ * \param endpoint The endpoint number of the CSR to process.
+ * \param flags The bitmap to set to 1.
+ */
+#define SET_CSR(endpoint, flags) \
+ { \
+ volatile uint32_t reg; \
+ int32_t nop_count ; \
+ reg = UDP->UDP_CSR[endpoint] ; \
+ reg |= REG_NO_EFFECT_1_ALL; \
+ reg |= (flags); \
+ UDP->UDP_CSR[endpoint] = reg; \
+ for( nop_count=0; nop_count<15; nop_count++ ) {\
+ nop();\
+ }\
+ }
+
+/**
+ * Clears the specified bit(s) in the UDP_CSR register.
+ *
+ * \param endpoint The endpoint number of the CSR to process.
+ * \param flags The bitmap to clear to 0.
+ */
+#define CLEAR_CSR(endpoint, flags) \
+{ \
+ volatile uint32_t reg; \
+ int32_t nop_count ; \
+ reg = UDP->UDP_CSR[endpoint]; \
+ reg |= REG_NO_EFFECT_1_ALL; \
+ reg &= ~((uint32_t)(flags)); \
+ UDP->UDP_CSR[endpoint] = reg; \
+ for( nop_count=0; nop_count<15; nop_count++ ) {\
+ nop();\
+ }\
+}
+
+
+/** Get Number of buffer in Multi-Buffer-List
+ * \param i input index
+ * \param o output index
+ * \param size list size
+ */
+#define MBL_NbBuffer(i, o, size) (((i)>(o))?((i)-(o)):((i)+(size)-(o)))
+
+/** Buffer list is full */
+#define MBL_FULL 1
+/** Buffer list is null */
+#define MBL_NULL 2
+
+/*---------------------------------------------------------------------------
+ * Types
+ *---------------------------------------------------------------------------*/
+
+/** Describes header for UDP endpoint transfer. */
+typedef struct {
+ /** Optional callback to invoke when the transfer completes. */
+ void* fCallback;
+ /** Optional argument to the callback function. */
+ void* pArgument;
+ /** Transfer type */
+ uint8_t transType;
+} TransferHeader;
+
+/** Describes a transfer on a UDP endpoint. */
+typedef struct {
+
+ /** Optional callback to invoke when the transfer completes. */
+ TransferCallback fCallback;
+ /** Optional argument to the callback function. */
+ void *pArgument;
+ /** Transfer type */
+ uint16_t transType;
+ /** Number of bytes which have been written into the UDP internal FIFO
+ * buffers. */
+ int16_t buffered;
+ /** Pointer to a data buffer used for emission/reception. */
+ uint8_t *pData;
+ /** Number of bytes which have been sent/received. */
+ int32_t transferred;
+ /** Number of bytes which have not been buffered/transferred yet. */
+ int32_t remaining;
+} Transfer;
+
+/** Describes Multi Buffer List transfer on a UDP endpoint. */
+typedef struct {
+ /** Optional callback to invoke when the transfer completes. */
+ MblTransferCallback fCallback;
+ /** Optional argument to the callback function. */
+ void *pArgument;
+ /** Transfer type */
+ volatile uint8_t transType;
+ /** List state (OK, FULL, NULL) (run time) */
+ uint8_t listState;
+ /** Multi-Buffer List size */
+ uint16_t listSize;
+ /** Pointer to multi-buffer list */
+ USBDTransferBuffer *pMbl;
+ /** Offset number of buffers to start transfer */
+ uint16_t offsetSize;
+ /** Current processing buffer index (run time) */
+ uint16_t outCurr;
+ /** Loast loaded buffer index (run time) */
+ uint16_t outLast;
+ /** Current buffer for input (run time) */
+ uint16_t inCurr;
+} MblTransfer;
+
+/**
+ * Describes the state of an endpoint of the UDP controller.
+ */
+typedef struct {
+
+ /* CSR */
+ //uint32_t CSR;
+ /** Current endpoint state. */
+ volatile uint8_t state;
+ /** Current reception bank (0 or 1). */
+ volatile uint8_t bank;
+ /** Maximum packet size for the endpoint. */
+ volatile uint16_t size;
+ /** Describes an ongoing transfer (if current state is either
+ * UDP_ENDPOINT_SENDING or UDP_ENDPOINT_RECEIVING) */
+ union {
+ TransferHeader transHdr;
+ Transfer singleTransfer;
+ MblTransfer mblTransfer;
+ } transfer;
+} Endpoint;
+
+/*---------------------------------------------------------------------------
+ * Internal variables
+ *---------------------------------------------------------------------------*/
+
+/** Holds the internal state for each endpoint of the UDP. */
+static Endpoint endpoints[CHIP_USB_NUMENDPOINTS];
+
+/*---------------------------------------------------------------------------
+ * Internal Functions
+ *---------------------------------------------------------------------------*/
+
+/**
+ * Enables the clock of the UDP peripheral.
+ * \return 1 if peripheral status changed.
+ */
+static uint8_t UDP_EnablePeripheralClock(void)
+{
+ if (!PMC_IsPeriphEnabled(ID_UDP)) {
+ PMC_EnablePeripheral(ID_UDP);
+ return 1;
+ }
+ return 0;
+}
+
+/**
+ * Disables the UDP peripheral clock.
+ */
+static inline void UDP_DisablePeripheralClock(void)
+{
+ PMC_DisablePeripheral(ID_UDP);
+}
+
+/**
+ * Enables the 48MHz USB clock.
+ */
+static inline void UDP_EnableUsbClock(void)
+{
+ REG_PMC_SCER = PMC_SCER_UDP;
+}
+
+/**
+ * Disables the 48MHz USB clock.
+ */
+static inline void UDP_DisableUsbClock(void)
+{
+ REG_PMC_SCDR = PMC_SCER_UDP;
+}
+
+/**
+ * Enables the UDP transceiver.
+ */
+static inline void UDP_EnableTransceiver(void)
+{
+ UDP->UDP_TXVC &= ~(uint32_t)UDP_TXVC_TXVDIS;
+}
+
+/**
+ * Disables the UDP transceiver.
+ */
+static inline void UDP_DisableTransceiver(void)
+{
+ UDP->UDP_TXVC |= UDP_TXVC_TXVDIS;
+}
+
+/**
+ * Handles a completed transfer on the given endpoint, invoking the
+ * configured callback if any.
+ * \param bEndpoint Number of the endpoint for which the transfer has completed.
+ * \param bStatus Status code returned by the transfer operation
+ */
+static void UDP_EndOfTransfer(uint8_t bEndpoint, uint8_t bStatus)
+{
+ Endpoint *pEndpoint = &(endpoints[bEndpoint]);
+
+ // Check that endpoint was sending or receiving data
+ if( (pEndpoint->state == UDP_ENDPOINT_RECEIVING)
+ || (pEndpoint->state == UDP_ENDPOINT_SENDING)) {
+
+ Transfer *pTransfer = (Transfer *)&(pEndpoint->transfer);
+ uint32_t transferred = pTransfer->transferred;
+ uint32_t remaining = pTransfer->remaining + pTransfer->buffered;
+
+ TRACE_DEBUG_WP("EoT ");
+
+ /* Endpoint returns in Idle state */
+ pEndpoint->state = UDP_ENDPOINT_IDLE;
+ /* Reset descriptor values */
+ pTransfer->pData = 0;
+ pTransfer->transferred = -1;
+ pTransfer->buffered = -1;
+ pTransfer->remaining = -1;
+
+ // Invoke callback is present
+ if (pTransfer->fCallback != 0) {
+
+ ((TransferCallback) pTransfer->fCallback)
+ (pTransfer->pArgument,
+ bStatus,
+ transferred,
+ remaining);
+ }
+ else {
+ TRACE_DEBUG_WP("NoCB ");
+ }
+ }
+ else if ( (pEndpoint->state == UDP_ENDPOINT_RECEIVINGM)
+ || (pEndpoint->state == UDP_ENDPOINT_SENDINGM) ) {
+
+ MblTransfer *pTransfer = (MblTransfer*)&(pEndpoint->transfer);
+
+ TRACE_DEBUG_WP("EoMT ");
+
+ /* Endpoint returns in Idle state */
+ pEndpoint->state = UDP_ENDPOINT_IDLE;
+ /* Reset transfer descriptor */
+ if (pTransfer->transType) {
+ MblTransfer *pMblt = (MblTransfer*)&(pEndpoint->transfer);
+ pMblt->listState = 0;
+ pMblt->outCurr = pMblt->inCurr = pMblt->outLast = 0;
+ }
+ /* Invoke callback */
+ if (pTransfer->fCallback != 0) {
+
+ ((MblTransferCallback) pTransfer->fCallback)
+ (pTransfer->pArgument,
+ bStatus);
+ }
+ else {
+ TRACE_DEBUG_WP("NoCB ");
+ }
+ }
+}
+
+/**
+ * Clears the correct reception flag (bank 0 or bank 1) of an endpoint
+ * \param bEndpoint Index of endpoint
+ */
+static void UDP_ClearRxFlag(uint8_t bEndpoint)
+{
+ Endpoint *pEndpoint = &(endpoints[bEndpoint]);
+
+ // Clear flag and change banks
+ if (pEndpoint->bank == 0) {
+
+ CLEAR_CSR(bEndpoint, UDP_CSR_RX_DATA_BK0);
+ // Swap bank if in dual-fifo mode
+ if (CHIP_USB_ENDPOINTS_BANKS(bEndpoint) > 1) {
+
+ pEndpoint->bank = 1;
+ }
+ }
+ else {
+
+ CLEAR_CSR(bEndpoint, UDP_CSR_RX_DATA_BK1);
+ pEndpoint->bank = 0;
+ }
+}
+
+/**
+ * Update multi-buffer-transfer descriptors.
+ * \param pTransfer Pointer to instance MblTransfer.
+ * \param size Size of bytes that processed.
+ * \param forceEnd Force the buffer END.
+ * \return 1 if current buffer ended.
+ */
+static uint8_t UDP_MblUpdate(MblTransfer *pTransfer,
+ USBDTransferBuffer * pBi,
+ uint16_t size,
+ uint8_t forceEnd)
+{
+ /* Update transfer descriptor */
+ pBi->remaining -= size;
+ /* Check if list NULL */
+ if (pTransfer->listState == MBL_NULL) {
+ return 1;
+ }
+ /* Check if current buffer ended */
+ if (pBi->remaining == 0 || forceEnd || size == 0) {
+
+ /* Process to next buffer */
+ if ((++ pTransfer->outCurr) == pTransfer->listSize)
+ pTransfer->outCurr = 0;
+ /* Check buffer NULL case */
+ if (pTransfer->outCurr == pTransfer->inCurr)
+ pTransfer->listState = MBL_NULL;
+ else {
+ pTransfer->listState = 0;
+ /* Continue transfer, prepare for next operation */
+ pBi = &pTransfer->pMbl[pTransfer->outCurr];
+ pBi->buffered = 0;
+ pBi->transferred = 0;
+ pBi->remaining = pBi->size;
+ }
+ return 1;
+ }
+ return 0;
+}
+
+/**
+ * Transfers a data payload from the current tranfer buffer to the endpoint
+ * FIFO
+ * \param bEndpoint Number of the endpoint which is sending data.
+ */
+static uint8_t UDP_MblWriteFifo(uint8_t bEndpoint)
+{
+ Endpoint *pEndpoint = &(endpoints[bEndpoint]);
+ MblTransfer *pTransfer = (MblTransfer*)&(pEndpoint->transfer);
+ USBDTransferBuffer *pBi = &(pTransfer->pMbl[pTransfer->outCurr]);
+ int32_t size;
+
+ volatile uint8_t * pBytes;
+ volatile uint8_t bufferEnd = 1;
+
+ /* Get the number of bytes to send */
+ size = pEndpoint->size;
+ if (size > pBi->remaining) size = pBi->remaining;
+
+ TRACE_DEBUG_WP("w%d.%" PRId32 " ", pTransfer->outCurr, size);
+
+ /* Record last accessed buffer */
+ pTransfer->outLast = pTransfer->outCurr;
+
+ pBytes = &(pBi->pBuffer[pBi->transferred + pBi->buffered]);
+ pBi->buffered += size;
+ bufferEnd = UDP_MblUpdate(pTransfer, pBi, size, 0);
+
+ /* Write packet in the FIFO buffer */
+ if (size) {
+ int32_t c8 = size >> 3;
+ int32_t c1 = size & 0x7;
+ for (; c8; c8 --) {
+ UDP->UDP_FDR[bEndpoint] = *(pBytes ++);
+ UDP->UDP_FDR[bEndpoint] = *(pBytes ++);
+ UDP->UDP_FDR[bEndpoint] = *(pBytes ++);
+ UDP->UDP_FDR[bEndpoint] = *(pBytes ++);
+
+ UDP->UDP_FDR[bEndpoint] = *(pBytes ++);
+ UDP->UDP_FDR[bEndpoint] = *(pBytes ++);
+ UDP->UDP_FDR[bEndpoint] = *(pBytes ++);
+ UDP->UDP_FDR[bEndpoint] = *(pBytes ++);
+ }
+ for (; c1; c1 --) {
+ UDP->UDP_FDR[bEndpoint] = *(pBytes ++);
+ }
+ }
+ return bufferEnd;
+}
+
+/**
+ * Transfers a data payload from the current tranfer buffer to the endpoint
+ * FIFO
+ * \param bEndpoint Number of the endpoint which is sending data.
+ */
+static void UDP_WritePayload(uint8_t bEndpoint)
+{
+ Endpoint *pEndpoint = &(endpoints[bEndpoint]);
+ Transfer *pTransfer = (Transfer*)&(pEndpoint->transfer);
+ int32_t size;
+
+ // Get the number of bytes to send
+ size = pEndpoint->size;
+ if (size > pTransfer->remaining) {
+
+ size = pTransfer->remaining;
+ }
+
+ // Update transfer descriptor information
+ pTransfer->buffered += size;
+ pTransfer->remaining -= size;
+
+ // Write packet in the FIFO buffer
+ while (size > 0) {
+
+ UDP->UDP_FDR[bEndpoint] = *(pTransfer->pData);
+ pTransfer->pData++;
+ size--;
+ }
+}
+
+
+/**
+ * Transfers a data payload from an endpoint FIFO to the current transfer buffer
+ * \param bEndpoint Endpoint number.
+ * \param wPacketSize Size of received data packet
+ */
+static void UDP_ReadPayload(uint8_t bEndpoint, int32_t wPacketSize)
+{
+ Endpoint *pEndpoint = &(endpoints[bEndpoint]);
+ Transfer *pTransfer = (Transfer*)&(pEndpoint->transfer);
+
+ // Check that the requested size is not bigger than the remaining transfer
+ if (wPacketSize > pTransfer->remaining) {
+
+ pTransfer->buffered += wPacketSize - pTransfer->remaining;
+ wPacketSize = pTransfer->remaining;
+ }
+
+ // Update transfer descriptor information
+ pTransfer->remaining -= wPacketSize;
+ pTransfer->transferred += wPacketSize;
+
+ // Retrieve packet
+ while (wPacketSize > 0) {
+
+ *(pTransfer->pData) = (uint8_t) UDP->UDP_FDR[bEndpoint];
+ pTransfer->pData++;
+ wPacketSize--;
+ }
+}
+
+/**
+ * Received SETUP packet from endpoint 0 FIFO
+ * \param pRequest Generic USB SETUP request sent over Control endpoints
+ */
+static void UDP_ReadRequest(USBGenericRequest *pRequest)
+{
+ uint8_t *pData = (uint8_t *)pRequest;
+ uint32_t i;
+
+ // Copy packet
+ for (i = 0; i < 8; i++) {
+
+ *pData = (uint8_t) UDP->UDP_FDR[0];
+ pData++;
+ }
+}
+
+/**
+ * Checks if an ongoing transfer on an endpoint has been completed.
+ * \param bEndpoint Endpoint number.
+ * \return 1 if the current transfer on the given endpoint is complete;
+ * otherwise 0.
+ */
+static uint8_t UDP_IsTransferFinished(uint8_t bEndpoint)
+{
+ Endpoint *pEndpoint = &(endpoints[bEndpoint]);
+ Transfer *pTransfer = (Transfer*)&(pEndpoint->transfer);
+
+ // Check if it is a Control endpoint
+ // -> Control endpoint must always finish their transfer with a zero-length
+ // packet
+ if ((UDP->UDP_CSR[bEndpoint] & UDP_CSR_EPTYPE_Msk) == UDP_CSR_EPTYPE_CTRL) {
+
+ return (pTransfer->buffered < pEndpoint->size);
+ }
+ // Other endpoints only need to transfer all the data
+ else {
+
+ return (pTransfer->buffered <= pEndpoint->size)
+ && (pTransfer->remaining == 0);
+ }
+}
+
+/**
+ * Endpoint interrupt handler.
+ * Handle IN/OUT transfers, received SETUP packets and STALLing
+ * \param bEndpoint Index of endpoint
+ */
+static void UDP_EndpointHandler(uint8_t bEndpoint)
+{
+ Endpoint *pEndpoint = &(endpoints[bEndpoint]);
+ Transfer *pTransfer = (Transfer*)&(pEndpoint->transfer);
+ MblTransfer *pMblt = (MblTransfer*)&(pEndpoint->transfer);
+ uint32_t status = UDP->UDP_CSR[bEndpoint];
+ uint16_t wPacketSize;
+ USBGenericRequest request;
+
+ TRACE_DEBUG_WP("E%d ", bEndpoint);
+ TRACE_DEBUG_WP("st:0x%" PRIX32 " ", status);
+
+ // Handle interrupts
+ // IN packet sent
+ if ((status & UDP_CSR_TXCOMP) != 0) {
+
+ TRACE_DEBUG_WP("Wr ");
+
+ // Check that endpoint was in MBL Sending state
+ if (pEndpoint->state == UDP_ENDPOINT_SENDINGM) {
+
+ USBDTransferBuffer * pMbli = &(pMblt->pMbl[pMblt->outLast]);
+ uint8_t bufferEnd = 0;
+
+ TRACE_DEBUG_WP("TxM%d.%d ", pMblt->listState, pMbli->buffered);
+
+ // End of transfer ?
+ if (pMblt->listState == MBL_NULL && pMbli->buffered == 0) {
+
+ pMbli->transferred += pMbli->buffered;
+ pMbli->buffered = 0;
+
+ // Disable interrupt
+ UDP->UDP_IDR = 1 << bEndpoint;
+ UDP_EndOfTransfer(bEndpoint, USBD_STATUS_SUCCESS);
+ CLEAR_CSR(bEndpoint, UDP_CSR_TXCOMP);
+ }
+ else {
+
+ // Transfer remaining data
+ TRACE_DEBUG_WP("%d ", pEndpoint->size);
+
+ if (pMbli->buffered > pEndpoint->size) {
+ pMbli->transferred += pEndpoint->size;
+ pMbli->buffered -= pEndpoint->size;
+ }
+ else {
+ pMbli->transferred += pMbli->buffered;
+ pMbli->buffered = 0;
+ }
+
+ // Send next packet
+ if (CHIP_USB_ENDPOINTS_BANKS(bEndpoint) == 1) {
+
+ // No double buffering
+ bufferEnd = UDP_MblWriteFifo(bEndpoint);
+ SET_CSR(bEndpoint, UDP_CSR_TXPKTRDY);
+ CLEAR_CSR(bEndpoint, UDP_CSR_TXCOMP);
+ }
+ else {
+ // Double buffering
+ SET_CSR(bEndpoint, UDP_CSR_TXPKTRDY);
+ CLEAR_CSR(bEndpoint, UDP_CSR_TXCOMP);
+ bufferEnd = UDP_MblWriteFifo(bEndpoint);
+ }
+
+ if (bufferEnd && pMblt->fCallback) {
+ ((MblTransferCallback) pTransfer->fCallback)
+ (pTransfer->pArgument,
+ USBD_STATUS_PARTIAL_DONE);
+ }
+ }
+ }
+ // Check that endpoint was in Sending state
+ else if (pEndpoint->state == UDP_ENDPOINT_SENDING) {
+
+ // End of transfer ?
+ if (UDP_IsTransferFinished(bEndpoint)) {
+
+ pTransfer->transferred += pTransfer->buffered;
+ pTransfer->buffered = 0;
+
+ // Disable interrupt if this is not a control endpoint
+ if ((status & UDP_CSR_EPTYPE_Msk) != UDP_CSR_EPTYPE_CTRL) {
+
+ UDP->UDP_IDR = 1 << bEndpoint;
+ }
+
+ UDP_EndOfTransfer(bEndpoint, USBD_STATUS_SUCCESS);
+ CLEAR_CSR(bEndpoint, UDP_CSR_TXCOMP);
+ }
+ else {
+
+ // Transfer remaining data
+ TRACE_DEBUG_WP(" %d ", pEndpoint->size);
+
+ pTransfer->transferred += pEndpoint->size;
+ pTransfer->buffered -= pEndpoint->size;
+
+ // Send next packet
+ if (CHIP_USB_ENDPOINTS_BANKS(bEndpoint) == 1) {
+
+ // No double buffering
+ UDP_WritePayload(bEndpoint);
+ SET_CSR(bEndpoint, UDP_CSR_TXPKTRDY);
+ CLEAR_CSR(bEndpoint, UDP_CSR_TXCOMP);
+ }
+ else {
+ // Double buffering
+ SET_CSR(bEndpoint, UDP_CSR_TXPKTRDY);
+ CLEAR_CSR(bEndpoint, UDP_CSR_TXCOMP);
+ UDP_WritePayload(bEndpoint);
+ }
+ }
+ }
+ else {
+ // Acknowledge interrupt
+ TRACE_ERROR("Error Wr%d, %x\n\r", bEndpoint, pEndpoint->state);
+ CLEAR_CSR(bEndpoint, UDP_CSR_TXCOMP);
+ }
+ }
+
+ // OUT packet received
+ if ((status & UDP_CSR_RXDATA_BK) != 0) {
+
+ TRACE_DEBUG_WP("Rd ");
+
+ // Check that the endpoint is in Receiving state
+ if (pEndpoint->state != UDP_ENDPOINT_RECEIVING) {
+
+ // Check if an ACK has been received on a Control endpoint
+ if (((status & UDP_CSR_EPTYPE_Msk) == UDP_CSR_EPTYPE_CTRL)
+ && ((status & UDP_CSR_RXBYTECNT_Msk) == 0)) {
+
+ // Acknowledge the data and finish the current transfer
+ UDP_ClearRxFlag(bEndpoint);
+ UDP_EndOfTransfer(bEndpoint, USBD_STATUS_SUCCESS);
+ }
+ // Check if the data has been STALLed
+ else if ((status & UDP_CSR_FORCESTALL) != 0) {
+
+ // Discard STALLed data
+ TRACE_DEBUG_WP("Discard ");
+ UDP_ClearRxFlag(bEndpoint);
+ }
+ // NAK the data
+ else {
+
+ TRACE_DEBUG_WP("Nak ");
+ UDP->UDP_IDR = 1 << bEndpoint;
+ }
+ }
+ // Endpoint is in Read state
+ else {
+
+ // Retrieve data and store it into the current transfer buffer
+ wPacketSize = (uint16_t) (status >> 16);
+ TRACE_DEBUG_WP("%d ", wPacketSize);
+ UDP_ReadPayload(bEndpoint, wPacketSize);
+ UDP_ClearRxFlag(bEndpoint);
+
+ // Check if the transfer is finished
+ if ((pTransfer->remaining == 0) || (wPacketSize < pEndpoint->size)) {
+
+ // Disable interrupt if this is not a control endpoint
+ if ((status & UDP_CSR_EPTYPE_Msk) != UDP_CSR_EPTYPE_CTRL) {
+
+ UDP->UDP_IDR = 1 << bEndpoint;
+ }
+ UDP_EndOfTransfer(bEndpoint, USBD_STATUS_SUCCESS);
+ }
+ }
+ }
+
+ // STALL sent
+ if ((status & UDP_CSR_STALLSENTISOERROR) != 0) {
+
+ CLEAR_CSR(bEndpoint, UDP_CSR_STALLSENTISOERROR);
+
+ if ( (status & UDP_CSR_EPTYPE_Msk) == UDP_CSR_EPTYPE_ISO_IN
+ || (status & UDP_CSR_EPTYPE_Msk) == UDP_CSR_EPTYPE_ISO_OUT ) {
+
+ TRACE_WARNING("Isoe [%d] ", bEndpoint);
+ UDP_EndOfTransfer(bEndpoint, USBD_STATUS_ABORTED);
+ }
+ else {
+
+ TRACE_WARNING("Sta 0x%X [%d] ", (int)status, bEndpoint);
+
+ if (pEndpoint->state != UDP_ENDPOINT_HALTED) {
+
+ TRACE_WARNING( "_ " );
+ // If the endpoint is not halted, clear the STALL condition
+ CLEAR_CSR(bEndpoint, UDP_CSR_FORCESTALL);
+ }
+ }
+ }
+
+ // SETUP packet received
+ if ((status & UDP_CSR_RXSETUP) != 0) {
+
+ TRACE_DEBUG_WP("Stp ");
+
+ // If a transfer was pending, complete it
+ // Handles the case where during the status phase of a control write
+ // transfer, the host receives the device ZLP and ack it, but the ack
+ // is not received by the device
+ if ((pEndpoint->state == UDP_ENDPOINT_RECEIVING)
+ || (pEndpoint->state == UDP_ENDPOINT_SENDING)) {
+
+ UDP_EndOfTransfer(bEndpoint, USBD_STATUS_SUCCESS);
+ }
+ // Copy the setup packet
+ UDP_ReadRequest(&request);
+
+ // Set the DIR bit before clearing RXSETUP in Control IN sequence
+ if (USBGenericRequest_GetDirection(&request) == USBGenericRequest_IN) {
+
+ SET_CSR(bEndpoint, UDP_CSR_DIR);
+ }
+ // Acknowledge setup packet
+ CLEAR_CSR(bEndpoint, UDP_CSR_RXSETUP);
+
+ // Forward the request to the upper layer
+ USBD_RequestHandler(0, &request);
+ }
+
+}
+
+/**
+ * Sends data through a USB endpoint. Sets up the transfer descriptor,
+ * writes one or two data payloads (depending on the number of FIFO bank
+ * for the endpoint) and then starts the actual transfer. The operation is
+ * complete when all the data has been sent.
+ *
+ * *If the size of the buffer is greater than the size of the endpoint
+ * (or twice the size if the endpoint has two FIFO banks), then the buffer
+ * must be kept allocated until the transfer is finished*. This means that
+ * it is not possible to declare it on the stack (i.e. as a local variable
+ * of a function which returns after starting a transfer).
+ *
+ * \param pEndpoint Pointer to Endpoint struct.
+ * \param pData Pointer to a buffer with the data to send.
+ * \param dLength Size of the data buffer.
+ * \return USBD_STATUS_SUCCESS if the transfer has been started;
+ * otherwise, the corresponding error status code.
+ */
+static inline uint8_t UDP_Write(uint8_t bEndpoint,
+ const void *pData,
+ uint32_t dLength)
+{
+ Endpoint *pEndpoint = &(endpoints[bEndpoint]);
+ Transfer *pTransfer = (Transfer*)&(pEndpoint->transfer);
+
+ /* Check that the endpoint is in Idle state */
+ if (pEndpoint->state != UDP_ENDPOINT_IDLE) {
+
+ return USBD_STATUS_LOCKED;
+ }
+ TRACE_DEBUG_WP("Write%d(%" PRIu32 ") ", bEndpoint, dLength);
+
+/* int i;
+ for (i = 0; i < dLength; i++) {
+ if (!(i%16)) {
+ printf("\n\r");
+ }
+ printf("0x%x ", ((uint8_t*)pData)[i]);
+ }
+ printf("\n\r");
+*/
+
+ /* Setup the transfer descriptor */
+ pTransfer->pData = (void *) pData;
+ pTransfer->remaining = dLength;
+ pTransfer->buffered = 0;
+ pTransfer->transferred = 0;
+
+ /* Send the first packet */
+ pEndpoint->state = UDP_ENDPOINT_SENDING;
+ while((UDP->UDP_CSR[bEndpoint]&UDP_CSR_TXPKTRDY)==UDP_CSR_TXPKTRDY);
+ UDP_WritePayload(bEndpoint);
+ SET_CSR(bEndpoint, UDP_CSR_TXPKTRDY);
+
+ /* If double buffering is enabled and there is data remaining,
+ prepare another packet */
+ if ((CHIP_USB_ENDPOINTS_BANKS(bEndpoint) > 1) && (pTransfer->remaining > 0)) {
+
+ UDP_WritePayload(bEndpoint);
+ }
+
+ /* Enable interrupt on endpoint */
+ UDP->UDP_IER = 1 << bEndpoint;
+
+ return USBD_STATUS_SUCCESS;
+}
+
+/**
+ * Sends data through a USB endpoint. Sets up the transfer descriptor list,
+ * writes one or two data payloads (depending on the number of FIFO bank
+ * for the endpoint) and then starts the actual transfer. The operation is
+ * complete when all the transfer buffer in the list has been sent.
+ *
+ * *If the size of the buffer is greater than the size of the endpoint
+ * (or twice the size if the endpoint has two FIFO banks), then the buffer
+ * must be kept allocated until the transfer is finished*. This means that
+ * it is not possible to declare it on the stack (i.e. as a local variable
+ * of a function which returns after starting a transfer).
+ *
+ * \param pEndpoint Pointer to Endpoint struct.
+ * \param pData Pointer to a buffer with the data to send.
+ * \param dLength Size of the data buffer.
+ * \return USBD_STATUS_SUCCESS if the transfer has been started;
+ * otherwise, the corresponding error status code.
+ */
+static inline uint8_t UDP_AddWr(uint8_t bEndpoint,
+ const void *pData,
+ uint32_t dLength)
+{
+ Endpoint *pEndpoint = &(endpoints[bEndpoint]);
+ MblTransfer *pMbl = (MblTransfer*)&(pEndpoint->transfer);
+ USBDTransferBuffer *pTx;
+
+ /* Check parameter */
+ if (dLength >= 0x10000)
+ return USBD_STATUS_INVALID_PARAMETER;
+
+ /* Data in progressing */
+ if (pEndpoint->state > UDP_ENDPOINT_IDLE) {
+ /* If list full */
+ if (pMbl->listState == MBL_FULL) {
+ return USBD_STATUS_LOCKED;
+ }
+ }
+
+ TRACE_DEBUG_WP("AddW%d(%" PRIu32 ") ", bEndpoint, dLength);
+
+ /* Add buffer to buffer list and update index */
+ pTx = &(pMbl->pMbl[pMbl->inCurr]);
+ pTx->pBuffer = (uint8_t*)pData;
+ pTx->size = pTx->remaining = dLength;
+ pTx->transferred = pTx->buffered = 0;
+ /* Update input index */
+ if (pMbl->inCurr >= (pMbl->listSize-1)) pMbl->inCurr = 0;
+ else pMbl->inCurr ++;
+ if (pMbl->inCurr == pMbl->outCurr) pMbl->listState = MBL_FULL;
+ else pMbl->listState = 0;
+ /* Start sending when offset achieved */
+ if (MBL_NbBuffer(pMbl->inCurr, pMbl->outCurr, pMbl->listSize)
+ >= pMbl->offsetSize
+ && pEndpoint->state == UDP_ENDPOINT_IDLE) {
+ TRACE_DEBUG_WP("StartT ");
+ /* Change state */
+ pEndpoint->state = UDP_ENDPOINT_SENDINGM;
+ while((UDP->UDP_CSR[bEndpoint]&UDP_CSR_TXPKTRDY)==UDP_CSR_TXPKTRDY);
+ /* Send first packet */
+ UDP_MblWriteFifo(bEndpoint);
+ SET_CSR(bEndpoint, UDP_CSR_TXPKTRDY);
+ /* If double buffering is enabled and there is remaining, continue */
+ if ((CHIP_USB_ENDPOINTS_BANKS(bEndpoint) > 1)
+ && pMbl->pMbl[pMbl->outCurr].remaining) {
+ UDP_MblWriteFifo(bEndpoint);
+ }
+ /* Enable interrupt on endpoint */
+ UDP->UDP_IER = 1 << bEndpoint;
+ }
+
+ return USBD_STATUS_SUCCESS;
+}
+
+/**
+ * Reads incoming data on an USB endpoint This methods sets the transfer
+ * descriptor and activate the endpoint interrupt. The actual transfer is
+ * then carried out by the endpoint interrupt handler. The Read operation
+ * finishes either when the buffer is full, or a short packet (inferior to
+ * endpoint maximum size) is received.
+ *
+ * *The buffer must be kept allocated until the transfer is finished*.
+ * \param bEndpoint Endpoint number.
+ * \param pData Pointer to a data buffer.
+ * \param dLength Size of the data buffer in bytes.
+ * \return USBD_STATUS_SUCCESS if the read operation has been started;
+ * otherwise, the corresponding error code.
+ */
+static inline uint8_t UDP_Read(uint8_t bEndpoint,
+ void *pData,
+ uint32_t dLength)
+{
+ Endpoint *pEndpoint = &(endpoints[bEndpoint]);
+ Transfer *pTransfer = (Transfer*)&(pEndpoint->transfer);
+
+ /* Return if the endpoint is not in IDLE state */
+ if (pEndpoint->state != UDP_ENDPOINT_IDLE) {
+
+ return USBD_STATUS_LOCKED;
+ }
+
+ /* Endpoint enters Receiving state */
+ pEndpoint->state = UDP_ENDPOINT_RECEIVING;
+ TRACE_DEBUG_WP("Read%d(%" PRIu32 ") ", bEndpoint, dLength);
+
+/* int i;
+ for (i = 0; i < dLength; i++) {
+ if (!(i%16)) {
+ printf("\n\r");
+ }
+ printf("0x%x ", ((uint8_t*)pData)[i]);
+ }
+ printf("\n\r");
+*/
+
+ /* Set the transfer descriptor */
+ pTransfer->pData = pData;
+ pTransfer->remaining = dLength;
+ pTransfer->buffered = 0;
+ pTransfer->transferred = 0;
+
+ /* Enable interrupt on endpoint */
+ UDP->UDP_IER = 1 << bEndpoint;
+
+ return USBD_STATUS_SUCCESS;
+}
+
+
+/*---------------------------------------------------------------------------
+ * Exported functions
+ *---------------------------------------------------------------------------*/
+
+/**
+ * USBD (UDP) interrupt handler
+ * Manages device resume, suspend, end of bus reset.
+ * Forwards endpoint events to the appropriate handler.
+ */
+void USBD_IrqHandler(void)
+{
+ uint32_t status;
+ int32_t eptnum = 0;
+
+ /* Enable peripheral ? */
+ //UDP_EnablePeripheralClock();
+
+ /* Get interrupt status
+ Some interrupts may get masked depending on the device state */
+ status = UDP->UDP_ISR;
+ status &= UDP->UDP_IMR;
+
+ TRACE_DEBUG("status; 0x%" PRIx32 , status);
+
+ if (USBD_GetState() < USBD_STATE_POWERED) {
+
+ status &= UDP_ICR_WAKEUP | UDP_ICR_RXRSM;
+ UDP->UDP_ICR = ~status;
+ }
+
+ /* Return immediately if there is no interrupt to service */
+ if (status == 0) {
+
+ TRACE_DEBUG_WP(".\n\r");
+ return;
+ }
+
+ /* Toggle USB LED if the device is active */
+ if (USBD_GetState() >= USBD_STATE_POWERED) {
+
+ //LED_Set(USBD_LEDUSB);
+ }
+
+ /* Service interrupts */
+
+ /** / Start Of Frame (SOF) */
+ //if (ISSET(dStatus, UDP_ISR_SOFINT)) {
+ //
+ // TRACE_DEBUG("SOF");
+ //
+ // // Invoke the SOF callback
+ // USB_StartOfFrameCallback(pUsb);
+ //
+ // // Acknowledge interrupt
+ // UDP->UDP_ICR = UDP_ICR_SOFINT;
+ // dStatus &= ~UDP_ISR_SOFINT;
+ //}
+ /* Resume (Wakeup) */
+ if ((status & (UDP_ISR_WAKEUP | UDP_ISR_RXRSM)) != 0) {
+
+ TRACE_INFO_WP("Res ");
+ /* Clear and disable resume interrupts */
+ UDP->UDP_ICR = UDP_ICR_WAKEUP | UDP_ICR_RXRSM | UDP_ICR_RXSUSP;
+ UDP->UDP_IDR = UDP_IDR_WAKEUP | UDP_IDR_RXRSM;
+ /* Do resome operations */
+ USBD_ResumeHandler();
+ }
+
+ /* Suspend
+ This interrupt is always treated last (hence the '==') */
+ if (status == UDP_ISR_RXSUSP) {
+
+ TRACE_INFO_WP("Susp ");
+ /* Enable wakeup */
+ UDP->UDP_IER = UDP_IER_WAKEUP | UDP_IER_RXRSM;
+ /* Acknowledge interrupt */
+ UDP->UDP_ICR = UDP_ICR_RXSUSP;
+ /* Do suspend operations */
+ USBD_SuspendHandler();
+ }
+ /* End of bus reset */
+ else if ((status & UDP_ISR_ENDBUSRES) != 0) {
+
+ TRACE_INFO_WP("EoBRes ");
+
+#if defined(BOARD_USB_DFU) && defined(dfu)
+ if (g_dfu.past_manifest)
+ USBDFU_SwitchToApp();
+#endif
+
+ /* Flush and enable the Suspend interrupt */
+ UDP->UDP_ICR = UDP_ICR_WAKEUP | UDP_ICR_RXRSM | UDP_ICR_RXSUSP;
+ UDP->UDP_IER = UDP_IER_RXSUSP;
+
+ /* Do RESET operations */
+ USBD_ResetHandler();
+
+ /* Acknowledge end of bus reset interrupt */
+ UDP->UDP_ICR = UDP_ICR_ENDBUSRES;
+ }
+ /* Endpoint interrupts */
+ else {
+
+ status &= ((1 << CHIP_USB_NUMENDPOINTS) - 1);
+ while (status != 0) {
+
+ /* Check if endpoint has a pending interrupt */
+ if ((status & (1 << eptnum)) != 0) {
+
+ UDP_EndpointHandler(eptnum);
+ status &= ~(1 << eptnum);
+
+ if (status != 0) {
+
+ TRACE_INFO_WP("\n\r - ");
+ }
+ }
+ eptnum++;
+ }
+ }
+
+ /* Toggle LED back to its previous state */
+ TRACE_DEBUG_WP("!");
+ TRACE_INFO_WP("\n\r");
+ if (USBD_GetState() >= USBD_STATE_POWERED) {
+
+ //LED_Clear(USBD_LEDUSB);
+ }
+}
+
+/**
+ * \brief Reset endpoints and disable them.
+ * -# Terminate transfer if there is any, with given status;
+ * -# Reset the endpoint & disable it.
+ * \param bmEPs Bitmap for endpoints to reset.
+ * \param bStatus Status passed to terminate transfer on endpoint.
+ * \param bKeepCfg 1 to keep old endpoint configuration.
+ * \note Use USBD_HAL_ConfigureEP() to configure and enable endpoint
+ if not keeping old configuration.
+ * \sa USBD_HAL_ConfigureEP().
+ */
+void USBD_HAL_ResetEPs(uint32_t bmEPs, uint8_t bStatus, uint8_t bKeepCfg)
+{
+ Endpoint *pEndpoint;
+ uint32_t tmp = bmEPs & ((1<<CHIP_USB_NUMENDPOINTS)-1);
+ uint8_t ep;
+ uint32_t epBit, epCfg;
+ for (ep = 0, epBit = 1; ep < CHIP_USB_NUMENDPOINTS; ep ++) {
+ if (tmp & epBit) {
+
+ /* Disable ISR */
+ UDP->UDP_IDR = epBit;
+ /* Kill pending TXPKTREADY */
+ CLEAR_CSR(ep, UDP_CSR_TXPKTRDY);
+
+ /* Reset transfer information */
+ pEndpoint = &(endpoints[ep]);
+ /* Reset endpoint state */
+ pEndpoint->bank = 0;
+ /* Endpoint configure */
+ epCfg = UDP->UDP_CSR[ep];
+ /* Reset endpoint */
+ UDP->UDP_RST_EP |= epBit;
+ UDP->UDP_RST_EP &= ~epBit;
+ /* Restore configure */
+ if (bKeepCfg) {
+ //SET_CSR(ep, pEndpoint->CSR);
+ SET_CSR(ep, epCfg);
+ }
+ else {
+ //pEndpoint->CSR = 0;
+ pEndpoint->state = UDP_ENDPOINT_DISABLED;
+ }
+
+ /* Terminate transfer on this EP */
+ UDP_EndOfTransfer(ep, bStatus);
+ }
+ epBit <<= 1;
+ }
+ /* Reset EPs */
+ // UDP->UDP_RST_EP |= bmEPs;
+ // UDP->UDP_RST_EP &= ~bmEPs;
+}
+
+/**
+ * Cancel pending READ/WRITE
+ * \param bmEPs Bitmap for endpoints to reset.
+ * \note EP callback is invoked with USBD_STATUS_CANCELED.
+ */
+void USBD_HAL_CancelIo(uint32_t bmEPs)
+{
+ uint32_t tmp = bmEPs & ((1<<CHIP_USB_NUMENDPOINTS)-1);
+ uint8_t ep;
+ uint32_t epBit;
+ for (ep = 0, epBit = 1; ep < CHIP_USB_NUMENDPOINTS; ep ++) {
+ if (tmp & epBit) {
+
+ /* Disable ISR */
+ UDP->UDP_IDR = epBit;
+ /* Kill pending TXPKTREADY */
+ CLEAR_CSR(ep, UDP_CSR_TXPKTRDY);
+
+ /* Terminate transfer on this EP */
+ UDP_EndOfTransfer(ep, USBD_STATUS_CANCELED);
+ }
+ epBit <<= 1;
+ }
+}
+
+/**
+ * Configures an endpoint according to its endpoint Descriptor.
+ * \param pDescriptor Pointer to an endpoint descriptor.
+ */
+uint8_t USBD_HAL_ConfigureEP(const USBEndpointDescriptor *pDescriptor)
+{
+ Endpoint *pEndpoint;
+ uint8_t bEndpoint;
+ uint8_t bType;
+ uint8_t bEndpointDir;
+
+ /* NULL descriptor -> Control endpoint 0 in default */
+ if (pDescriptor == 0) {
+ bEndpoint = 0;
+ pEndpoint = &(endpoints[bEndpoint]);
+ bType= USBEndpointDescriptor_CONTROL;
+ bEndpointDir = 0;
+ pEndpoint->size = CHIP_USB_ENDPOINTS_MAXPACKETSIZE(0);
+ }
+ /* Device descriptor -> Specific Control EP */
+ else if (pDescriptor->bDescriptorType == USBGenericDescriptor_DEVICE) {
+ bEndpoint = 0;
+ pEndpoint = &(endpoints[bEndpoint]);
+ bType = USBEndpointDescriptor_CONTROL;
+ bEndpointDir = 0;
+ pEndpoint->size = ((USBDeviceDescriptor *)pDescriptor)->bMaxPacketSize0;
+ }
+ /* Not endpoint descriptor, ERROR! */
+ else if (pDescriptor->bDescriptorType != USBGenericDescriptor_ENDPOINT) {
+ return 0xFF;
+ }
+ else {
+ bEndpoint = USBEndpointDescriptor_GetNumber(pDescriptor);
+ pEndpoint = &(endpoints[bEndpoint]);
+ bType = USBEndpointDescriptor_GetType(pDescriptor);
+ bEndpointDir = USBEndpointDescriptor_GetDirection(pDescriptor);
+ pEndpoint->size = USBEndpointDescriptor_GetMaxPacketSize(pDescriptor);
+ }
+
+ /* Abort the current transfer is the endpoint was configured and in
+ Write or Read state */
+ if ((pEndpoint->state == UDP_ENDPOINT_RECEIVING)
+ || (pEndpoint->state == UDP_ENDPOINT_SENDING)
+ || (pEndpoint->state == UDP_ENDPOINT_RECEIVINGM)
+ || (pEndpoint->state == UDP_ENDPOINT_SENDINGM)) {
+ UDP_EndOfTransfer(bEndpoint, USBD_STATUS_RESET);
+ }
+ pEndpoint->state = UDP_ENDPOINT_IDLE;
+
+ /* Reset Endpoint Fifos */
+ UDP->UDP_RST_EP |= (1 << bEndpoint);
+ UDP->UDP_RST_EP &= ~(1 << bEndpoint);
+
+ /* Configure endpoint */
+ SET_CSR(bEndpoint, (uint32_t)UDP_CSR_EPEDS
+ | (bType << 8) | (bEndpointDir << 10));
+ if (bType != USBEndpointDescriptor_CONTROL) {
+
+ }
+ else {
+
+ UDP->UDP_IER = (1 << bEndpoint);
+ }
+
+ TRACE_INFO_WP("CfgEp%d ", bEndpoint);
+ return bEndpoint;
+}
+
+/**
+ * Set callback for a USB endpoint for transfer (read/write).
+ *
+ * \param bEP Endpoint number.
+ * \param fCallback Optional callback function to invoke when the transfer is
+ * complete.
+ * \param pCbData Optional pointer to data to the callback function.
+ * \return USBD_STATUS_SUCCESS or USBD_STATUS_LOCKED if endpoint is busy.
+ */
+uint8_t USBD_HAL_SetTransferCallback(uint8_t bEP,
+ TransferCallback fCallback,
+ void *pCbData)
+{
+ Endpoint *pEndpoint = &(endpoints[bEP]);
+ TransferHeader *pTransfer = (TransferHeader*)&(pEndpoint->transfer);
+ /* Check that the endpoint is not transferring */
+ if (pEndpoint->state > UDP_ENDPOINT_IDLE) {
+ return USBD_STATUS_LOCKED;
+ }
+ TRACE_DEBUG_WP("sXfrCb ");
+ /* Setup the transfer callback and extension data */
+ pTransfer->fCallback = (void*)fCallback;
+ pTransfer->pArgument = pCbData;
+ return USBD_STATUS_SUCCESS;
+}
+
+/**
+ * Configure an endpoint to use multi-buffer-list transfer mode.
+ * The buffers can be added by _Read/_Write function.
+ * \param pMbList Pointer to a multi-buffer list used, NULL to disable MBL.
+ * \param mblSize Multi-buffer list size (number of buffers can be queued)
+ * \param startOffset When number of buffer achieve this offset transfer start
+ */
+uint8_t USBD_HAL_SetupMblTransfer( uint8_t bEndpoint,
+ USBDTransferBuffer* pMbList,
+ uint16_t mblSize,
+ uint16_t startOffset)
+{
+ Endpoint *pEndpoint = &(endpoints[bEndpoint]);
+ MblTransfer *pXfr = (MblTransfer*)&(pEndpoint->transfer);
+ uint16_t i;
+ /* Check that the endpoint is not transferring */
+ if (pEndpoint->state > UDP_ENDPOINT_IDLE) {
+ return USBD_STATUS_LOCKED;
+ }
+ TRACE_DEBUG_WP("sMblXfr ");
+ /* Enable Multi-Buffer Transfer List */
+ if (pMbList) {
+ /* Reset list items */
+ for (i = 0; i < mblSize; i --) {
+ pMbList[i].pBuffer = NULL;
+ pMbList[i].size = 0;
+ pMbList[i].transferred = 0;
+ pMbList[i].buffered = 0;
+ pMbList[i].remaining = 0;
+ }
+ /* Setup transfer */
+ pXfr->transType = 1;
+ pXfr->listState = 0; /* OK */
+ pXfr->listSize = mblSize;
+ pXfr->pMbl = pMbList;
+ pXfr->outCurr = pXfr->outLast = 0;
+ pXfr->inCurr = 0;
+ pXfr->offsetSize = startOffset;
+ }
+ /* Disable Multi-Buffer Transfer */
+ else {
+ pXfr->transType = 0;
+ pXfr->pMbl = NULL;
+ pXfr->listSize = 0;
+ pXfr->offsetSize = 1;
+ }
+ return USBD_STATUS_SUCCESS;
+}
+
+/**
+ * Sends data through a USB endpoint. Sets up the transfer descriptor,
+ * writes one or two data payloads (depending on the number of FIFO bank
+ * for the endpoint) and then starts the actual transfer. The operation is
+ * complete when all the data has been sent.
+ *
+ * *If the size of the buffer is greater than the size of the endpoint
+ * (or twice the size if the endpoint has two FIFO banks), then the buffer
+ * must be kept allocated until the transfer is finished*. This means that
+ * it is not possible to declare it on the stack (i.e. as a local variable
+ * of a function which returns after starting a transfer).
+ *
+ * \param bEndpoint Endpoint number.
+ * \param pData Pointer to a buffer with the data to send.
+ * \param dLength Size of the data buffer.
+ * \return USBD_STATUS_SUCCESS if the transfer has been started;
+ * otherwise, the corresponding error status code.
+ */
+uint8_t USBD_HAL_Write( uint8_t bEndpoint,
+ const void *pData,
+ uint32_t dLength)
+{
+ if (endpoints[bEndpoint].transfer.transHdr.transType)
+ return UDP_AddWr(bEndpoint, pData, dLength);
+ else
+ return UDP_Write(bEndpoint, pData, dLength);
+}
+
+/**
+ * Reads incoming data on an USB endpoint This methods sets the transfer
+ * descriptor and activate the endpoint interrupt. The actual transfer is
+ * then carried out by the endpoint interrupt handler. The Read operation
+ * finishes either when the buffer is full, or a short packet (inferior to
+ * endpoint maximum size) is received.
+ *
+ * *The buffer must be kept allocated until the transfer is finished*.
+ * \param bEndpoint Endpoint number.
+ * \param pData Pointer to a data buffer.
+ * \param dLength Size of the data buffer in bytes.
+ * \return USBD_STATUS_SUCCESS if the read operation has been started;
+ * otherwise, the corresponding error code.
+ */
+uint8_t USBD_HAL_Read(uint8_t bEndpoint,
+ void *pData,
+ uint32_t dLength)
+{
+ if (endpoints[bEndpoint].transfer.transHdr.transType)
+ return USBD_STATUS_SW_NOT_SUPPORTED;
+ else
+ return UDP_Read(bEndpoint, pData, dLength);
+}
+
+/**
+ * \brief Enable Pull-up, connect.
+ *
+ * -# Enable HW access if needed
+ * -# Enable Pull-Up
+ * -# Disable HW access if needed
+ */
+void USBD_HAL_Connect(void)
+{
+ uint8_t dis = UDP_EnablePeripheralClock();
+ UDP->UDP_TXVC |= UDP_TXVC_PUON;
+ if (dis) UDP_DisablePeripheralClock();
+}
+
+/**
+ * \brief Disable Pull-up, disconnect.
+ *
+ * -# Enable HW access if needed
+ * -# Disable PULL-Up
+ * -# Disable HW access if needed
+ */
+void USBD_HAL_Disconnect(void)
+{
+ uint8_t dis = UDP_EnablePeripheralClock();
+ UDP->UDP_TXVC &= ~(uint32_t)UDP_TXVC_PUON;
+ if (dis) UDP_DisablePeripheralClock();
+}
+
+/**
+ * Starts a remote wake-up procedure.
+ */
+void USBD_HAL_RemoteWakeUp(void)
+{
+ UDP_EnablePeripheralClock();
+ UDP_EnableUsbClock();
+ UDP_EnableTransceiver();
+
+ TRACE_INFO_WP("RWUp ");
+
+ // Activates a remote wakeup (edge on ESR), then clear ESR
+ UDP->UDP_GLB_STAT |= UDP_GLB_STAT_ESR;
+ UDP->UDP_GLB_STAT &= ~(uint32_t)UDP_GLB_STAT_ESR;
+}
+
+/**
+ * Sets the device address to the given value.
+ * \param address New device address.
+ */
+void USBD_HAL_SetAddress(uint8_t address)
+{
+ /* Set address */
+ UDP->UDP_FADDR = UDP_FADDR_FEN | (address & UDP_FADDR_FADD_Msk);
+ /* If the address is 0, the device returns to the Default state */
+ if (address == 0) UDP->UDP_GLB_STAT = 0;
+ /* If the address is non-zero, the device enters the Address state */
+ else UDP->UDP_GLB_STAT = UDP_GLB_STAT_FADDEN;
+}
+
+/**
+ * Sets the current device configuration.
+ * \param cfgnum - Configuration number to set.
+ */
+void USBD_HAL_SetConfiguration(uint8_t cfgnum)
+{
+ /* If the configuration number if non-zero, the device enters the
+ Configured state */
+ if (cfgnum != 0) UDP->UDP_GLB_STAT |= UDP_GLB_STAT_CONFG;
+ /* If the configuration number is zero, the device goes back to the Address
+ state */
+ else {
+ UDP->UDP_GLB_STAT = UDP_FADDR_FEN;
+ }
+}
+
+/**
+ * Initializes the USB HW Access driver.
+ */
+void USBD_HAL_Init(void)
+{
+ TRACE_DEBUG("%s\n\r", "USBD_HAL_Init");
+
+ /* Must before USB & TXVC access! */
+ UDP_EnablePeripheralClock();
+
+ /* Reset & disable endpoints */
+ USBD_HAL_ResetEPs(0xFFFFFFFF, USBD_STATUS_RESET, 0);
+
+ /* Configure the pull-up on D+ and disconnect it */
+ UDP->UDP_TXVC &= ~(uint32_t)UDP_TXVC_PUON;
+
+ UDP_EnableUsbClock();
+
+ UDP->UDP_IDR = 0xFE;
+ UDP->UDP_IER = UDP_IER_WAKEUP;
+}
+
+/**
+ * Causes the given endpoint to acknowledge the next packet it receives
+ * with a STALL handshake except setup request.
+ * \param bEP Endpoint number.
+ * \return USBD_STATUS_SUCCESS or USBD_STATUS_LOCKED.
+ */
+uint8_t USBD_HAL_Stall(uint8_t bEP)
+{
+ Endpoint *pEndpoint = &(endpoints[bEP]);
+
+ /* Check that endpoint is in Idle state */
+ if (pEndpoint->state != UDP_ENDPOINT_IDLE) {
+ TRACE_WARNING("UDP_Stall: EP%d locked\n\r", bEP);
+ return USBD_STATUS_LOCKED;
+ }
+ /* STALL endpoint */
+ SET_CSR(bEP, UDP_CSR_FORCESTALL);
+ TRACE_DEBUG_WP("Stall%d ", bEP);
+ return USBD_STATUS_SUCCESS;
+}
+
+/**
+ * Sets/Clear/Get the HALT state on the endpoint.
+ * In HALT state, the endpoint should keep stalling any packet.
+ * \param bEndpoint Endpoint number.
+ * \param ctl Control code CLR/HALT/READ.
+ * 0: Clear HALT state;
+ * 1: Set HALT state;
+ * .: Return HALT status.
+ * \return USBD_STATUS_INVALID_PARAMETER if endpoint not exist,
+ * otherwise endpoint halt status.
+ */
+uint8_t USBD_HAL_Halt(uint8_t bEndpoint, uint8_t ctl)
+{
+ Endpoint *pEndpoint = &(endpoints[bEndpoint]);
+ uint8_t status = 0;
+
+ /* SET Halt */
+ if (ctl == 1) {
+ /* Check that endpoint is enabled and not already in Halt state */
+ if ((pEndpoint->state != UDP_ENDPOINT_DISABLED)
+ && (pEndpoint->state != UDP_ENDPOINT_HALTED)) {
+
+ TRACE_DEBUG_WP("Halt%d ", bEndpoint);
+
+ /* Abort the current transfer if necessary */
+ UDP_EndOfTransfer(bEndpoint, USBD_STATUS_ABORTED);
+
+ /* Put endpoint into Halt state */
+ SET_CSR(bEndpoint, UDP_CSR_FORCESTALL);
+ pEndpoint->state = UDP_ENDPOINT_HALTED;
+
+ /* Enable the endpoint interrupt */
+ UDP->UDP_IER = 1 << bEndpoint;
+ }
+ }
+ /* CLEAR Halt */
+ else if (ctl == 0) {
+ /* Check if the endpoint is halted */
+ //if (pEndpoint->state != UDP_ENDPOINT_DISABLED) {
+ if (pEndpoint->state == UDP_ENDPOINT_HALTED) {
+
+ TRACE_DEBUG_WP("Unhalt%d ", bEndpoint);
+
+ /* Return endpoint to Idle state */
+ pEndpoint->state = UDP_ENDPOINT_IDLE;
+
+ /* Clear FORCESTALL flag */
+ CLEAR_CSR(bEndpoint, UDP_CSR_FORCESTALL);
+
+ /* Reset Endpoint Fifos, beware this is a 2 steps operation */
+ UDP->UDP_RST_EP |= 1 << bEndpoint;
+ UDP->UDP_RST_EP &= ~(1 << bEndpoint);
+ }
+ }
+
+ /* Return Halt status */
+ if (pEndpoint->state == UDP_ENDPOINT_HALTED) {
+ status = 1;
+ }
+ return( status );
+}
+
+/**
+ * Indicates if the device is running in high or full-speed. Always returns 0
+ * since UDP does not support high-speed mode.
+ */
+uint8_t USBD_HAL_IsHighSpeed(void)
+{
+ return 0;
+}
+
+/**
+ * Suspend USB Device HW Interface
+ *
+ * -# Disable transceiver
+ * -# Disable USB Clock
+ * -# Disable USB Peripheral
+ */
+void USBD_HAL_Suspend(void)
+{
+ /* The device enters the Suspended state */
+ UDP_DisableTransceiver();
+ UDP_DisableUsbClock();
+ UDP_DisablePeripheralClock();
+}
+
+/**
+ * Activate USB Device HW Interface
+ * -# Enable USB Peripheral
+ * -# Enable USB Clock
+ * -# Enable transceiver
+ */
+void USBD_HAL_Activate(void)
+{
+ UDP_EnablePeripheralClock();
+ UDP_EnableUsbClock();
+ UDP_EnableTransceiver();
+}
+
+/**@}*/
+