summaryrefslogtreecommitdiff
path: root/at91lib/usb/device/core/USBD_OTGHS.c
diff options
context:
space:
mode:
Diffstat (limited to 'at91lib/usb/device/core/USBD_OTGHS.c')
-rw-r--r--at91lib/usb/device/core/USBD_OTGHS.c1677
1 files changed, 1677 insertions, 0 deletions
diff --git a/at91lib/usb/device/core/USBD_OTGHS.c b/at91lib/usb/device/core/USBD_OTGHS.c
new file mode 100644
index 0000000..0f87143
--- /dev/null
+++ b/at91lib/usb/device/core/USBD_OTGHS.c
@@ -0,0 +1,1677 @@
+/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+/*!
+ Functions for OTGHS peripheral usage.
+*/
+
+//------------------------------------------------------------------------------
+// Headers
+//------------------------------------------------------------------------------
+
+#include <board.h>
+
+#ifdef CHIP_OTGHS
+
+#include "common.h"
+#include "trace.h"
+#include "usb.h"
+
+//------------------------------------------------------------------------------
+// Definitions
+//------------------------------------------------------------------------------
+
+#define NUM_IT_MAX (AT91C_BASE_OTGHS->OTGHS_IPFEATURES & AT91C_OTGHS_EPT_NBR_MAX)
+#define NUM_IT_MAX_DMA ((AT91C_BASE_OTGHS->OTGHS_IPFEATURES & AT91C_OTGHS_DMA_CHANNEL_NBR)>>4)
+
+#define SHIFT_DMA 24
+#define SHIFT_INTERUPT 12
+
+#define DMA
+
+//------------------------------------------------------------------------------
+// Structures
+//------------------------------------------------------------------------------
+
+// \brief Endpoint states
+typedef enum {
+
+ endpointStateDisabled,
+ endpointStateIdle,
+ endpointStateWrite,
+ endpointStateRead,
+ endpointStateHalted
+
+} EndpointState_t;
+
+//------------------------------------------------------------------------------
+// Macros
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+// Internal Functions
+//------------------------------------------------------------------------------
+//------------------------------------------------------------------------------
+// \brief Returns a pointer to the OTGHS controller interface used by an USB
+// driver
+//
+// The pointer is cast to the correct type (AT91PS_OTGHS).
+// \param pUsb Pointer to a S_usb instance
+// \return Pointer to the USB controller interface
+// \see S_usb
+//------------------------------------------------------------------------------
+static AT91PS_OTGHS OTGHS_GetDriverInterface(const S_usb *pUsb)
+{
+ return (AT91PS_OTGHS) pUsb->pDriver->pInterface;
+}
+
+//------------------------------------------------------------------------------
+// \fn OTGHS_GetInterfaceEPT
+// \brief Returns OTGHS endpoint FIFO interface from S_usb structure
+//------------------------------------------------------------------------------
+static AT91PS_OTGHS_EPTFIFO OTGHS_GetInterfaceEPT(const S_usb *pUsb)
+{
+ return (AT91PS_OTGHS_EPTFIFO) pUsb->pDriver->pEndpointFIFO;
+}
+
+
+//------------------------------------------------------------------------------
+// \brief Enables the peripheral clock of the USB controller associated with
+// the specified USB driver
+// \param pUsb Pointer to a S_usb instance
+// \see S_usb
+//------------------------------------------------------------------------------
+static void OTGHS_EnableMCK(const S_usb *pUsb)
+{
+
+}
+
+//------------------------------------------------------------------------------
+// \brief Disables the peripheral clock of the USB controller associated with
+// the specified USB driver
+// \param pUsb Pointer to a S_usb instance
+// \see S_usb
+//------------------------------------------------------------------------------
+static void OTGHS_DisableMCK(const S_usb *pUsb)
+{
+
+}
+
+//------------------------------------------------------------------------------
+// \brief Enables the 48MHz clock of the USB controller associated with
+// the specified USB driver
+// \param pUsb Pointer to a S_usb instance
+// \see S_usb
+//------------------------------------------------------------------------------
+static void OTGHS_EnableOTGHSCK(const S_usb *pUsb)
+{
+
+}
+
+//------------------------------------------------------------------------------
+// \brief Disables the 48MHz clock of the USB controller associated with
+// the specified USB driver
+// \param pUsb Pointer to a S_usb instance
+// \see S_usb
+//------------------------------------------------------------------------------
+static void OTGHS_DisableOTGHSCK(const S_usb *pUsb)
+{
+
+}
+
+//------------------------------------------------------------------------------
+// \brief Enables the transceiver of the USB controller associated with
+// the specified USB driver
+// \param pUsb Pointer to a S_usb instance
+// \see S_usb
+//------------------------------------------------------------------------------
+static void OTGHS_EnableTransceiver(const S_usb *pUsb)
+{
+ SET(OTGHS_GetDriverInterface(pUsb)->OTGHS_CTRL, AT91C_OTGHS_OTGPADE);
+}
+
+//------------------------------------------------------------------------------
+// \brief Disables the transceiver of the USB controller associated with
+// the specified USB driver
+// \param pUsb Pointer to a S_usb instance
+// \see S_usb
+//------------------------------------------------------------------------------
+static void OTGHS_DisableTransceiver(const S_usb *pUsb)
+{
+ CLEAR(OTGHS_GetDriverInterface(pUsb)->OTGHS_CTRL, AT91C_OTGHS_OTGPADE);
+}
+
+//------------------------------------------------------------------------------
+// \brief Invokes the callback associated with a finished transfer on an
+// endpoint
+// \param pEndpoint Pointer to a S_usb_endpoint instance
+// \param bStatus Status code returned by the transfer operation
+// \see Status codes
+// \see S_usb_endpoint
+//------------------------------------------------------------------------------
+static void OTGHS_EndOfTransfer(S_usb_endpoint *pEndpoint,
+ char bStatus)
+{
+ if ((pEndpoint->dState == endpointStateWrite)
+ || (pEndpoint->dState == endpointStateRead)) {
+
+ TRACE_DEBUG_WP("E");
+
+ // Endpoint returns in Idle state
+ pEndpoint->dState = endpointStateIdle;
+
+ // Invoke callback is present
+ if (pEndpoint->fCallback != 0) {
+
+ pEndpoint->fCallback((unsigned int) pEndpoint->pArgument,
+ (unsigned int) bStatus,
+ pEndpoint->dBytesTransferred,
+ pEndpoint->dBytesRemaining
+ + pEndpoint->dBytesBuffered);
+ }
+ }
+}
+
+//------------------------------------------------------------------------------
+// \brief Transfers a data payload from the current tranfer buffer to the
+// endpoint FIFO.
+// \param pUsb Pointer to a S_usb instance
+// \param bEndpoint Index of endpoint
+// \return Number of bytes transferred
+// \see S_usb
+//------------------------------------------------------------------------------
+static unsigned int OTGHS_WritePayload(const S_usb *pUsb,
+ unsigned char bEndpoint)
+{
+ AT91PS_OTGHS_EPTFIFO pInterfaceEPT = OTGHS_GetInterfaceEPT(pUsb);
+ S_usb_endpoint *pEndpoint = USB_GetEndpoint(pUsb, bEndpoint);
+ char *pfifo;
+ unsigned int dBytes;
+ unsigned int dCtr;
+
+ pfifo = (char*)&(pInterfaceEPT->OTGHS_READEPT0[bEndpoint*16384]);
+
+ // Get the number of bytes to send
+ dBytes = min(pEndpoint->wMaxPacketSize, pEndpoint->dBytesRemaining);
+
+ // Transfer one packet in the FIFO buffer
+ for (dCtr = 0; dCtr < dBytes; dCtr++) {
+
+ pfifo[dCtr] = *(pEndpoint->pData);
+ pEndpoint->pData++;
+ }
+
+ pEndpoint->dBytesBuffered += dBytes;
+ pEndpoint->dBytesRemaining -= dBytes;
+
+ return dBytes;
+}
+
+//----------------------------------------------------------------------------
+// \brief Transfers a data payload from an endpoint FIFO to the current
+// transfer buffer.
+// \param pUsb Pointer to a S_usb instance
+// \param bEndpoint Index of endpoint
+// \param wPacketSize Size of received data packet
+// \return Number of bytes transferred
+// \see S_usb
+//------------------------------------------------------------------------------
+static unsigned int OTGHS_GetPayload(const S_usb *pUsb,
+ unsigned char bEndpoint,
+ unsigned short wPacketSize)
+{
+ AT91PS_OTGHS_EPTFIFO pInterfaceEPT = OTGHS_GetInterfaceEPT(pUsb);
+ S_usb_endpoint *pEndpoint = USB_GetEndpoint(pUsb, bEndpoint);
+ char *pfifo;
+ unsigned int dBytes;
+ unsigned int dCtr;
+
+ pfifo = (char*)&(pInterfaceEPT->OTGHS_READEPT0[bEndpoint*16384]);
+
+ // Get number of bytes to retrieve
+ dBytes = min(pEndpoint->dBytesRemaining, wPacketSize);
+
+ // Retrieve packet
+ for (dCtr = 0; dCtr < dBytes; dCtr++) {
+
+ *(pEndpoint->pData) = pfifo[dCtr];
+ pEndpoint->pData++;
+ }
+
+ pEndpoint->dBytesRemaining -= dBytes;
+ pEndpoint->dBytesTransferred += dBytes;
+ pEndpoint->dBytesBuffered += wPacketSize - dBytes;
+
+ return dBytes;
+}
+
+//------------------------------------------------------------------------------
+// \brief Transfers a received SETUP packet from endpoint 0 FIFO to the
+// S_usb_request structure of an USB driver
+// \param pUsb Pointer to a S_usb instance
+// \see S_usb
+//------------------------------------------------------------------------------
+static void OTGHS_GetSetup(const S_usb *pUsb)
+{
+ unsigned int *pData = (unsigned int *) USB_GetSetup(pUsb);
+ AT91PS_OTGHS_EPTFIFO pInterfaceEPT = OTGHS_GetInterfaceEPT(pUsb);
+
+ pData[0] = pInterfaceEPT->OTGHS_READEPT0[0];
+ pData[1] = pInterfaceEPT->OTGHS_READEPT0[0];
+}
+
+//------------------------------------------------------------------------------
+// \brief This function reset all endpoint transfer descriptors
+// \param pUsb Pointer to a S_usb instance
+// \see S_usb
+//------------------------------------------------------------------------------
+static void OTGHS_ResetEndpoints(const S_usb *pUsb)
+{
+ S_usb_endpoint *pEndpoint;
+ unsigned char bEndpoint;
+
+ // Reset the transfer descriptor of every endpoint
+ for (bEndpoint = 0; bEndpoint < pUsb->dNumEndpoints; bEndpoint++) {
+
+ pEndpoint = USB_GetEndpoint(pUsb, bEndpoint);
+
+ // Reset endpoint transfer descriptor
+ pEndpoint->pData = 0;
+ pEndpoint->dBytesRemaining = 0;
+ pEndpoint->dBytesTransferred = 0;
+ pEndpoint->dBytesBuffered = 0;
+ pEndpoint->fCallback = 0;
+ pEndpoint->pArgument = 0;
+
+ // Configure endpoint characteristics
+ pEndpoint->dState = endpointStateDisabled;
+ }
+}
+
+//------------------------------------------------------------------------------
+// \brief Disable all endpoints (except control endpoint 0), aborting current
+// transfers if necessary.
+// \param pUsb Pointer to a S_usb instance
+//------------------------------------------------------------------------------
+static void OTGHS_DisableEndpoints(const S_usb *pUsb)
+{
+ S_usb_endpoint *pEndpoint;
+ unsigned char bEndpoint;
+
+ // Foreach endpoint, if it is enabled, disable it and invoke the callback
+ // Control endpoint 0 is not disabled
+ for (bEndpoint = 1; bEndpoint < pUsb->dNumEndpoints; bEndpoint++) {
+
+ pEndpoint = USB_GetEndpoint(pUsb, bEndpoint);
+ OTGHS_EndOfTransfer(pEndpoint, USB_STATUS_RESET);
+
+ pEndpoint->dState = endpointStateDisabled;
+ }
+}
+
+//------------------------------------------------------------------------------
+// \brief Endpoint interrupt handler.
+//
+// Handle IN/OUT transfers, received SETUP packets and STALLing
+// \param pUsb Pointer to a S_usb instance
+// \param bEndpoint Index of endpoint
+// \see S_usb
+//------------------------------------------------------------------------------
+static void OTGHS_EndpointHandler(const S_usb *pUsb, unsigned char bEndpoint)
+{
+ S_usb_endpoint *pEndpoint = USB_GetEndpoint(pUsb, bEndpoint);
+ AT91PS_OTGHS pInterface = OTGHS_GetDriverInterface(pUsb);
+ unsigned int dStatus = pInterface->OTGHS_DEVEPTCSR[bEndpoint];
+ unsigned short wPacketSize;
+
+ TRACE_DEBUG_WP("Ept%d, 0x%X ", bEndpoint, dStatus);
+
+ // Handle interrupts
+ // IN packet sent
+ if((ISSET(pInterface->OTGHS_DEVEPTCMR[bEndpoint], AT91C_OTGHS_TXINI))
+ && (ISSET(dStatus, AT91C_OTGHS_TXINI ))) {
+
+ TRACE_DEBUG_WP("Wr ");
+
+ if (pEndpoint->dBytesBuffered > 0) {
+
+ TRACE_DEBUG_WP("%d ", pEndpoint->dBytesBuffered);
+
+ pEndpoint->dBytesTransferred += pEndpoint->dBytesBuffered;
+ pEndpoint->dBytesBuffered = 0;
+ }
+
+ if ((!pEndpoint->isDataSent) || (pEndpoint->dBytesRemaining > 0)) {
+
+ OTGHS_WritePayload(pUsb, bEndpoint);
+ pEndpoint->isDataSent = true;
+
+ pInterface->OTGHS_DEVEPTCCR[bEndpoint] = AT91C_OTGHS_TXINI;
+ // For a non-control endpoint, the FIFOCON bit must be cleared
+ // to start the transfer
+ if ((AT91C_OTGHS_EPT_TYPE & pInterface->OTGHS_DEVEPTCFG[bEndpoint])
+ != AT91C_OTGHS_EPT_TYPE_CTL_EPT) {
+
+ pInterface->OTGHS_DEVEPTCDR[bEndpoint] = AT91C_OTGHS_FIFOCON;
+ }
+ }
+ else {
+
+ pInterface->OTGHS_DEVEPTCDR[bEndpoint] = AT91C_OTGHS_TXINI;
+
+ // Disable interrupt if this is not a control endpoint
+ if ((AT91C_OTGHS_EPT_TYPE & pInterface->OTGHS_DEVEPTCFG[bEndpoint])
+ != AT91C_OTGHS_EPT_TYPE_CTL_EPT) {
+
+ pInterface->OTGHS_DEVIDR = 1<<SHIFT_INTERUPT<<bEndpoint;
+
+ }
+ OTGHS_EndOfTransfer(pEndpoint, USB_STATUS_SUCCESS);
+ }
+ }
+
+ // OUT packet received
+ if(ISSET(dStatus, AT91C_OTGHS_RXOUT)) {
+
+ TRACE_DEBUG_WP("Rd ");
+
+ // Check that the endpoint is in Read state
+ if (pEndpoint->dState != endpointStateRead) {
+
+ // Endpoint is NOT in Read state
+ if (ISCLEARED(pInterface->OTGHS_DEVEPTCFG[bEndpoint], AT91C_OTGHS_EPT_TYPE)
+ && ISCLEARED(dStatus, (0x7FF<<20))) { // byte count
+
+ // Control endpoint, 0 bytes received
+ // Acknowledge the data and finish the current transfer
+ TRACE_DEBUG_WP("Ack ");
+ pInterface->OTGHS_DEVEPTCCR[bEndpoint] = AT91C_OTGHS_RXOUT;
+
+ OTGHS_EndOfTransfer(pEndpoint, USB_STATUS_SUCCESS);
+ }
+ else if (ISSET(dStatus, AT91C_OTGHS_STALL)) {
+
+ // Non-control endpoint
+ // Discard stalled data
+ TRACE_DEBUG_WP("Disc ");
+ pInterface->OTGHS_DEVEPTCCR[bEndpoint] = AT91C_OTGHS_RXOUT;
+ }
+ else {
+
+ // Non-control endpoint
+ // Nak data
+ TRACE_DEBUG_WP("Nak ");
+ pInterface->OTGHS_DEVIDR = 1<<SHIFT_INTERUPT<<bEndpoint;
+ }
+ }
+ else {
+
+ // Endpoint is in Read state
+ // Retrieve data and store it into the current transfer buffer
+ wPacketSize = (unsigned short) ((dStatus >> 20) & 0x7FF);
+
+ TRACE_DEBUG_WP("%d ", wPacketSize);
+
+ OTGHS_GetPayload(pUsb, bEndpoint, wPacketSize);
+
+ pInterface->OTGHS_DEVEPTCCR[bEndpoint] = AT91C_OTGHS_RXOUT;
+ pInterface->OTGHS_DEVEPTCDR[bEndpoint] = AT91C_OTGHS_FIFOCON;
+
+ if ((pEndpoint->dBytesRemaining == 0)
+ || (wPacketSize < pEndpoint->wMaxPacketSize)) {
+
+ pInterface->OTGHS_DEVEPTCDR[bEndpoint] = AT91C_OTGHS_RXOUT;
+
+ // Disable interrupt if this is not a control endpoint
+ if ((AT91C_OTGHS_EPT_TYPE & pInterface->OTGHS_DEVEPTCFG[bEndpoint])
+ != AT91C_OTGHS_EPT_TYPE_CTL_EPT) {
+
+ pInterface->OTGHS_DEVIDR = 1<<SHIFT_INTERUPT<<bEndpoint;
+ }
+
+ OTGHS_EndOfTransfer(pEndpoint, USB_STATUS_SUCCESS);
+ }
+ }
+ }
+
+ // SETUP packet received
+ if(ISSET(dStatus, AT91C_OTGHS_RXSTP)) {
+
+ TRACE_DEBUG_WP("Stp ");
+
+ // If a transfer was pending, complete it
+ // Handle 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->dState == endpointStateWrite)
+ || (pEndpoint->dState == endpointStateRead)) {
+
+ OTGHS_EndOfTransfer(pEndpoint, USB_STATUS_SUCCESS);
+ }
+
+ // Copy the setup packet in S_usb
+ OTGHS_GetSetup(pUsb);
+
+ // Acknowledge setup packet
+ pInterface->OTGHS_DEVEPTCCR[bEndpoint] = AT91C_OTGHS_RXSTP;
+
+ // Forward the request to the upper layer
+ USB_NewRequestCallback(pUsb);
+ }
+
+ // STALL sent
+ if (ISSET(dStatus, AT91C_OTGHS_STALL)) {
+
+ TRACE_WARNING("Sta 0x%X [%d] ", dStatus, bEndpoint);
+
+ // Acknowledge STALL interrupt and disable it
+ pInterface->OTGHS_DEVEPTCCR[bEndpoint] = AT91C_OTGHS_STALL;
+ //pInterface->OTGHS_DEVEPTCDR[bEndpoint] = AT91C_OTGHS_STALL;
+
+ // If the endpoint is not halted, clear the stall condition
+ if (pEndpoint->dState != endpointStateHalted) {
+
+ TRACE_WARNING("_ " );
+ // Acknowledge the stall RQ flag
+ pInterface->OTGHS_DEVEPTCDR[bEndpoint] = AT91C_OTGHS_STALLRQ;
+ }
+
+ }
+
+}
+
+
+//------------------------------------------------------------------------------
+// Exported functions
+//------------------------------------------------------------------------------
+//------------------------------------------------------------------------------
+// \brief Configure an endpoint with the provided endpoint descriptor
+// \param pUsb Pointer to a S_usb instance
+// \param pEpDesc Pointer to the endpoint descriptor
+// \return true if the endpoint is now configured, false otherwise
+// \see S_usb_endpoint_descriptor
+// \see S_usb
+//------------------------------------------------------------------------------
+static bool OTGHS_ConfigureEndpoint(const S_usb *pUsb,
+ const S_usb_endpoint_descriptor *pEpDesc)
+{
+ AT91PS_OTGHS pInterface = OTGHS_GetDriverInterface(pUsb);
+ S_usb_endpoint *pEndpoint;
+ unsigned char bEndpoint;
+ unsigned char bType;
+ unsigned char endpointDir;
+ unsigned short sizeEpt = 0;
+
+ // Maximum packet size configuration value
+ if( pEpDesc->wMaxPacketSize == 8 ) {
+ sizeEpt = AT91C_OTGHS_EPT_SIZE_8;
+ } else if ( pEpDesc->wMaxPacketSize == 16 ) {
+ sizeEpt = AT91C_OTGHS_EPT_SIZE_16;
+ } else if ( pEpDesc->wMaxPacketSize == 32 ) {
+ sizeEpt = AT91C_OTGHS_EPT_SIZE_32;
+ } else if ( pEpDesc->wMaxPacketSize == 64 ) {
+ sizeEpt = AT91C_OTGHS_EPT_SIZE_64;
+ } else if ( pEpDesc->wMaxPacketSize == 128 ) {
+ sizeEpt = AT91C_OTGHS_EPT_SIZE_128;
+ } else if ( pEpDesc->wMaxPacketSize == 256 ) {
+ sizeEpt = AT91C_OTGHS_EPT_SIZE_256;
+ } else if ( pEpDesc->wMaxPacketSize == 512 ) {
+ sizeEpt = AT91C_OTGHS_EPT_SIZE_512;
+ } else if ( pEpDesc->wMaxPacketSize == 1024 ) {
+ sizeEpt = AT91C_OTGHS_EPT_SIZE_1024;
+ } //else {
+ // sizeEpt = 0; // control endpoint
+ //}
+
+ // if pEpDesc == 0 then initialize the control endpoint
+ if (pEpDesc == (S_usb_endpoint_descriptor const *) 0) {
+
+ bEndpoint = 0;
+ bType = 0; // Control endpoint
+ }
+ else {
+ // The endpoint number
+ bEndpoint = (unsigned char) (pEpDesc->bEndpointAddress & 0x7);
+ // Transfer type: Control, Isochronous, Bulk, Interrupt
+ bType = (unsigned char) (pEpDesc->bmAttributes & 0x3);
+ // Direction, ignored for control endpoints
+ endpointDir = (unsigned char) (pEpDesc->bEndpointAddress & (1<<7));
+ }
+
+ // Get pointer on endpoint
+ pEndpoint = USB_GetEndpoint(pUsb, bEndpoint);
+ if (pEndpoint == 0) {
+
+ return false;
+ }
+
+ // Configure wMaxPacketSize
+ if (pEpDesc != 0) {
+
+ pEndpoint->wMaxPacketSize = pEpDesc->wMaxPacketSize;
+ }
+ else {
+
+ pEndpoint->wMaxPacketSize = USB_ENDPOINT0_MAXPACKETSIZE;
+ }
+
+ // Abort the current transfer is the endpoint was configured and in
+ // Write or Read state
+ if ((pEndpoint->dState == endpointStateRead)
+ || (pEndpoint->dState == endpointStateWrite)) {
+
+ OTGHS_EndOfTransfer(pEndpoint, USB_STATUS_RESET);
+ }
+
+ // Enter in IDLE state
+ pEndpoint->dState = endpointStateIdle;
+
+ // Reset Endpoint Fifos
+ pInterface->OTGHS_DEVEPT |= (1<<bEndpoint<<16);
+ pInterface->OTGHS_DEVEPT &= ~(1<<bEndpoint<<16);
+
+ // Enable endpoint
+ pInterface->OTGHS_DEVEPT |= (1<<bEndpoint);
+
+ // Configure endpoint
+ switch (bType) {
+
+ //-------------------------
+ case ENDPOINT_TYPE_CONTROL:
+ //-------------------------
+ TRACE_INFO("Control[%d]\n\r",bEndpoint);
+
+ //! Configure endpoint
+ pInterface->OTGHS_DEVEPTCFG[bEndpoint] = AT91C_OTGHS_ALLOC |
+ AT91C_OTGHS_EPT_SIZE_64 | AT91C_OTGHS_EPT_DIR_OUT | AT91C_OTGHS_EPT_TYPE_CTL_EPT | AT91C_OTGHS_BK_NUMBER_1;
+
+ // Enable RXSTP interrupt
+ pInterface->OTGHS_DEVEPTCER[bEndpoint] = AT91C_OTGHS_RXSTP;
+
+ // Enable endpoint IT
+ pInterface->OTGHS_DEVIER = 1<<SHIFT_INTERUPT<<bEndpoint;
+
+ break;
+
+ //-----------------------------
+ case ENDPOINT_TYPE_ISOCHRONOUS:
+ //-----------------------------
+ if (endpointDir) {
+ TRACE_INFO("Iso In[%d]\n\r",bEndpoint);
+
+ //! Configure endpoint
+#ifndef DMA
+ pInterface->OTGHS_DEVEPTCFG[bEndpoint] = AT91C_OTGHS_ALLOC |
+ sizeEpt | AT91C_OTGHS_EPT_DIR_IN | AT91C_OTGHS_EPT_TYPE_ISO_EPT | AT91C_OTGHS_BK_NUMBER_2;
+#else
+ pInterface->OTGHS_DEVEPTCFG[bEndpoint] = AT91C_OTGHS_ALLOC | AT91C_OTGHS_AUTOSW |
+ sizeEpt | AT91C_OTGHS_EPT_DIR_IN | AT91C_OTGHS_EPT_TYPE_ISO_EPT | AT91C_OTGHS_BK_NUMBER_2;
+#endif
+
+ }
+ else {
+ TRACE_INFO("Iso Out[%d]\n\r",bEndpoint);
+
+ //! Configure endpoint
+#ifndef DMA
+ pInterface->OTGHS_DEVEPTCFG[bEndpoint] = AT91C_OTGHS_ALLOC |
+ sizeEpt | AT91C_OTGHS_EPT_DIR_OUT | AT91C_OTGHS_EPT_TYPE_ISO_EPT | AT91C_OTGHS_BK_NUMBER_2;
+#else
+ pInterface->OTGHS_DEVEPTCFG[bEndpoint] = AT91C_OTGHS_ALLOC | AT91C_OTGHS_AUTOSW |
+ sizeEpt | AT91C_OTGHS_EPT_DIR_OUT | AT91C_OTGHS_EPT_TYPE_ISO_EPT | AT91C_OTGHS_BK_NUMBER_2;
+#endif
+
+ }
+ break;
+
+ //----------------------
+ case ENDPOINT_TYPE_BULK:
+ //----------------------
+ if (endpointDir) {
+ TRACE_INFO("Bulk In(%d)[%d] ",bEndpoint, pEpDesc->wMaxPacketSize);
+ //! Configure endpoint
+#ifndef DMA
+ pInterface->OTGHS_DEVEPTCFG[bEndpoint] = AT91C_OTGHS_ALLOC |
+ sizeEpt | AT91C_OTGHS_EPT_DIR_IN | AT91C_OTGHS_EPT_TYPE_BUL_EPT | AT91C_OTGHS_BK_NUMBER_2;
+#else
+ pInterface->OTGHS_DEVEPTCFG[bEndpoint] = AT91C_OTGHS_ALLOC | AT91C_OTGHS_AUTOSW |
+ sizeEpt | AT91C_OTGHS_EPT_DIR_IN | AT91C_OTGHS_EPT_TYPE_BUL_EPT | AT91C_OTGHS_BK_NUMBER_2;
+#endif
+
+ }
+ else {
+ TRACE_INFO("Bulk Out(%d)[%d]\n\r",bEndpoint, pEpDesc->wMaxPacketSize);
+ //! Configure endpoint
+#ifndef DMA
+ pInterface->OTGHS_DEVEPTCFG[bEndpoint] = AT91C_OTGHS_ALLOC |
+ sizeEpt | AT91C_OTGHS_EPT_DIR_OUT | AT91C_OTGHS_EPT_TYPE_BUL_EPT | AT91C_OTGHS_BK_NUMBER_2;
+#else
+ pInterface->OTGHS_DEVEPTCFG[bEndpoint] = AT91C_OTGHS_ALLOC | AT91C_OTGHS_AUTOSW |
+ sizeEpt | AT91C_OTGHS_EPT_DIR_OUT | AT91C_OTGHS_EPT_TYPE_BUL_EPT | AT91C_OTGHS_BK_NUMBER_2;
+#endif
+ }
+ break;
+
+ //---------------------------
+ case ENDPOINT_TYPE_INTERRUPT:
+ //---------------------------
+ if (endpointDir) {
+ TRACE_INFO("Interrupt In[%d]\n\r",bEndpoint);
+ //! Configure endpoint
+#ifndef DMA
+ pInterface->OTGHS_DEVEPTCFG[bEndpoint] = AT91C_OTGHS_ALLOC |
+ sizeEpt | AT91C_OTGHS_EPT_DIR_IN | AT91C_OTGHS_EPT_TYPE_INT_EPT | AT91C_OTGHS_BK_NUMBER_2;
+#else
+ pInterface->OTGHS_DEVEPTCFG[bEndpoint] = AT91C_OTGHS_ALLOC | AT91C_OTGHS_AUTOSW |
+ sizeEpt | AT91C_OTGHS_EPT_DIR_IN | AT91C_OTGHS_EPT_TYPE_INT_EPT | AT91C_OTGHS_BK_NUMBER_2;
+#endif
+
+ }
+ else {
+ TRACE_INFO("Interrupt Out[%d]\n\r",bEndpoint);
+ //! Configure endpoint
+#ifndef DMA
+ pInterface->OTGHS_DEVEPTCFG[bEndpoint] = AT91C_OTGHS_ALLOC |
+ sizeEpt | AT91C_OTGHS_EPT_DIR_OUT | AT91C_OTGHS_EPT_TYPE_INT_EPT | AT91C_OTGHS_BK_NUMBER_2;
+#else
+ pInterface->OTGHS_DEVEPTCFG[bEndpoint] = AT91C_OTGHS_ALLOC | AT91C_OTGHS_AUTOSW |
+ sizeEpt | AT91C_OTGHS_EPT_DIR_OUT | AT91C_OTGHS_EPT_TYPE_INT_EPT | AT91C_OTGHS_BK_NUMBER_2;
+#endif
+
+ }
+ break;
+
+ //------
+ default:
+ //------
+ TRACE_ERROR(" unknown endpoint type\n\r");
+ return false;
+ }
+
+ // Check if the configuration is ok
+ if (ISCLEARED(pInterface->OTGHS_DEVEPTCSR[bEndpoint], AT91C_OTGHS_CFGOK)) {
+
+ TRACE_FATAL("OTGHS_ConfigureEndpoint: Cannot configure endpoint\n\r");
+ return false;
+ }
+
+ return true;
+}
+
+
+//------------------------------------------------------------------------------
+// Interrupt service routine
+//------------------------------------------------------------------------------
+#ifdef DMA
+//----------------------------------------------------------------------------
+//! \fn OTGHS_DmaHandler
+//! \brief This function (ISR) handles DMA interrupts
+//----------------------------------------------------------------------------
+static void OTGHS_DmaHandler(const S_usb *pUsb, unsigned char endpoint)
+{
+ AT91PS_OTGHS pInterface = OTGHS_GetDriverInterface(pUsb);
+ S_usb_endpoint *pEndpoint = USB_GetEndpoint(pUsb, endpoint);
+ unsigned int csr;
+
+ csr = pInterface->OTGHS_DEVDMA[endpoint].OTGHS_DEVDMASTATUS;
+ pInterface->OTGHS_DEVIDR = (1<<SHIFT_DMA<<endpoint);
+
+ if((csr & AT91C_OTGHS_END_BF_ST) || (csr & AT91C_OTGHS_END_TR_ST)) {
+ // READ
+ TRACE_DEBUG_M("END_BF_ST\n\r");
+ pEndpoint->dBytesTransferred = pEndpoint->dBytesBuffered;
+ pEndpoint->dBytesBuffered = 0;
+
+ TRACE_DEBUG_M("dBytesBuffered: 0x%x\n\r",pEndpoint->dBytesBuffered);
+ TRACE_DEBUG_M("dBytesRemaining: 0x%x\n\r",pEndpoint->dBytesRemaining);
+ TRACE_DEBUG_M("dBytesTransferred: 0x%x\n\r",pEndpoint->dBytesTransferred);
+
+ OTGHS_EndOfTransfer(pEndpoint, USB_STATUS_SUCCESS);
+ pEndpoint->dState = endpointStateIdle;
+ }
+ else {
+ TRACE_FATAL("Probleme IT DMA\n\r");
+ }
+}
+#endif
+
+
+//------------------------------------------------------------------------------
+// \brief OTGHS interrupt handler
+//
+// Manages device resume, suspend, end of bus reset. Forwards endpoint
+// interrupts to the appropriate handler.
+// \param pUsb Pointer to a S_usb instance
+//------------------------------------------------------------------------------
+static void OTGHS_Handler(const S_usb *pUsb)
+{
+ AT91PS_OTGHS pInterface = OTGHS_GetDriverInterface(pUsb);
+ unsigned int dStatus;
+ unsigned char numIT;
+
+ if ( (!ISSET(USB_GetState(pUsb), USB_STATE_SUSPENDED))
+ && (ISSET(USB_GetState(pUsb), USB_STATE_POWERED))){
+
+ LED_TOGGLE(LED_USB);
+ }
+
+ TRACE_DEBUG_H("Hlr ");
+
+ // Get General interrupts status
+ dStatus = pInterface->OTGHS_SR & pInterface->OTGHS_CTRL & 0xFF;
+ while (dStatus != 0) {
+
+ if(ISSET(dStatus, AT91C_OTGHS_VBUSTI))
+ {
+ TRACE_DEBUG_M("__VBus\n\r");
+
+ USB_Attach(pUsb);
+
+ // Acknowledge the interrupt
+ pInterface->OTGHS_SCR = AT91C_OTGHS_VBUSTI;
+ }
+
+ // Don't treat others interrupt for this time
+ pInterface->OTGHS_SCR = AT91C_OTGHS_IDT | AT91C_OTGHS_SRP
+ | AT91C_OTGHS_VBERR | AT91C_OTGHS_BCERR
+ | AT91C_OTGHS_ROLEEX | AT91C_OTGHS_HNPERR
+ | AT91C_OTGHS_STO;
+
+ dStatus = pInterface->OTGHS_SR & pInterface->OTGHS_CTRL & 0xFF;
+ }
+
+
+ // Get OTG Device interrupts status
+ dStatus = pInterface->OTGHS_DEVISR & pInterface->OTGHS_DEVIMR;
+ TRACE_DEBUG_H("OTGHS_DEVISR:0x%X\n\r", pInterface->OTGHS_DEVISR);
+ while (dStatus != 0) {
+
+ // Start Of Frame (SOF)
+ if (ISSET(dStatus, AT91C_OTGHS_SOF)) {
+ TRACE_DEBUG_WP("SOF ");
+
+ // Invoke the SOF callback
+ USB_StartOfFrameCallback(pUsb);
+
+ // Acknowledge interrupt
+ SET(pInterface->OTGHS_DEVICR, AT91C_OTGHS_SOF);
+ CLEAR(dStatus, AT91C_OTGHS_SOF);
+ }
+
+ // Suspend
+ else if (dStatus & AT91C_OTGHS_SUSP) {
+
+ TRACE_DEBUG_M("S ");
+
+ if (!ISSET(USB_GetState(pUsb), USB_STATE_SUSPENDED)) {
+
+ // The device enters the Suspended state
+ // MCK + UDPCK must be off
+ // Pull-Up must be connected
+ // Transceiver must be disabled
+
+ // Enable wakeup
+ SET(pInterface->OTGHS_DEVIER, AT91C_OTGHS_EORST | AT91C_OTGHS_WAKEUP | AT91C_OTGHS_EORSM);
+
+ // Acknowledge interrupt
+ pInterface->OTGHS_DEVICR = AT91C_OTGHS_SUSP;
+ SET(*(pUsb->pState), USB_STATE_SUSPENDED);
+ OTGHS_DisableTransceiver(pUsb);
+ OTGHS_DisableMCK(pUsb);
+ OTGHS_DisableOTGHSCK(pUsb);
+
+ // Invoke the Suspend callback
+
+ USB_SuspendCallback(pUsb);
+ }
+ }
+
+ // Resume
+ else if (ISSET(dStatus, AT91C_OTGHS_WAKEUP)
+ || ISSET(dStatus, AT91C_OTGHS_EORSM)) {
+
+ // Invoke the Resume callback
+ USB_ResumeCallback(pUsb);
+
+ TRACE_DEBUG_M("R ");
+
+ // The device enters Configured state
+ // MCK + UDPCK must be on
+ // Pull-Up must be connected
+ // Transceiver must be enabled
+
+ if (ISSET(USB_GetState(pUsb), USB_STATE_SUSPENDED)) {
+
+ // Powered state
+ OTGHS_EnableMCK(pUsb);
+ OTGHS_EnableOTGHSCK(pUsb);
+
+ // Default state
+ if (ISSET(USB_GetState(pUsb), USB_STATE_DEFAULT)) {
+
+ OTGHS_EnableTransceiver(pUsb);
+ }
+
+ CLEAR(*(pUsb->pState), USB_STATE_SUSPENDED);
+ }
+ pInterface->OTGHS_DEVICR =
+ (AT91C_OTGHS_WAKEUP | AT91C_OTGHS_EORSM | AT91C_OTGHS_SUSP);
+
+ pInterface->OTGHS_DEVIER = (AT91C_OTGHS_EORST | AT91C_OTGHS_SUSP);
+ pInterface->OTGHS_DEVICR = (AT91C_OTGHS_WAKEUP | AT91C_OTGHS_EORSM);
+ pInterface->OTGHS_DEVIDR = AT91C_OTGHS_WAKEUP;
+
+ }
+
+ // End of bus reset
+ else if (dStatus & AT91C_OTGHS_EORST) {
+
+ TRACE_DEBUG_M("EoB ");
+ // The device enters the Default state
+ // MCK + UDPCK are already enabled
+ // Pull-Up is already connected
+ // Transceiver must be enabled
+ // Endpoint 0 must be enabled
+ SET(*(pUsb->pState), USB_STATE_DEFAULT);
+
+ OTGHS_EnableTransceiver(pUsb);
+
+ // The device leaves the Address & Configured states
+ CLEAR(*(pUsb->pState), USB_STATE_ADDRESS | USB_STATE_CONFIGURED);
+ OTGHS_ResetEndpoints(pUsb);
+ OTGHS_DisableEndpoints(pUsb);
+ OTGHS_ConfigureEndpoint(pUsb, 0);
+
+ // Flush and enable the Suspend interrupt
+ SET(pInterface->OTGHS_DEVICR, AT91C_OTGHS_WAKEUP | AT91C_OTGHS_SUSP);
+
+ // Enable the Start Of Frame (SOF) interrupt if needed
+ if (pUsb->pCallbacks->startOfFrame != 0) {
+
+ SET(pInterface->OTGHS_DEVIER, AT91C_OTGHS_SOF);
+ }
+
+ // Invoke the Reset callback
+ USB_ResetCallback(pUsb);
+
+ // Acknowledge end of bus reset interrupt
+ pInterface->OTGHS_DEVICR = AT91C_OTGHS_EORST;
+ }
+
+ // Handle upstream resume interrupt
+ else if (dStatus & AT91C_OTGHS_UPRSM) {
+
+ TRACE_DEBUG_WP(" External resume interrupt\n\r");
+
+ // - Acknowledge the IT
+ pInterface->OTGHS_DEVICR = AT91C_OTGHS_UPRSM;
+ }
+
+ // Endpoint interrupts
+ else {
+#ifndef DMA
+ // Handle endpoint interrupts
+ for (numIT = 0; numIT < NUM_IT_MAX; numIT++) {
+ if( dStatus & (1<<SHIFT_INTERUPT<<numIT) ) {
+ OTGHS_EndpointHandler(pUsb, numIT);
+ }
+ }
+#else
+ // Handle endpoint control interrupt
+ if( dStatus & (1<<SHIFT_INTERUPT<<0) ) {
+ OTGHS_EndpointHandler(pUsb, 0);
+ }
+ // Handle DMA interrupts
+ for(numIT = 1; numIT <= NUM_IT_MAX_DMA; numIT++) {
+ if( dStatus & (1<<SHIFT_DMA<<numIT) ) {
+ OTGHS_DmaHandler(pUsb, numIT);
+ }
+ }
+#endif
+ }
+
+ // Retrieve new interrupt status
+ dStatus = (pInterface->OTGHS_DEVISR) & (pInterface->OTGHS_DEVIMR);
+
+ // Mask unneeded interrupts
+ if (!ISSET(USB_GetState(pUsb), USB_STATE_DEFAULT)) {
+
+ dStatus &= AT91C_OTGHS_EORST | AT91C_OTGHS_SOF;
+ }
+
+ TRACE_DEBUG_H("\n\r");
+
+ if (dStatus != 0) {
+
+ TRACE_DEBUG_WP(" - ");
+ }
+ }
+
+ if ( (!ISSET(USB_GetState(pUsb), USB_STATE_SUSPENDED))
+ && (ISSET(USB_GetState(pUsb), USB_STATE_POWERED))){
+
+ LED_TOGGLE(LED_USB);
+ }
+}
+
+//------------------------------------------------------------------------------
+// \brief Sends data through an USB endpoint
+//
+// Sets up the transfer descriptor, write one or two data payloads
+// (depending on the number of FIFO banks for the endpoint) and then
+// starts the actual transfer. The operation is complete when all
+// the data has been sent.
+// \param pUsb Pointer to a S_usb instance
+// \param bEndpoint Index of endpoint
+// \param pData Pointer to a buffer containing the data to send
+// \param dLength Length of the data buffer
+// \param fCallback Optional function to invoke when the transfer finishes
+// \param pArgument Optional argument for the callback function
+// \return Operation result code
+// \see Operation result codes
+// \see Callback_f
+// \see S_usb
+//------------------------------------------------------------------------------
+static char OTGHS_Write(const S_usb *pUsb,
+ unsigned char bEndpoint,
+ const void *pData,
+ unsigned int dLength,
+ Callback_f fCallback,
+ void *pArgument)
+{
+ S_usb_endpoint *pEndpoint = USB_GetEndpoint(pUsb, bEndpoint);
+ AT91PS_OTGHS pInterface = OTGHS_GetDriverInterface(pUsb);
+
+ // Check that the endpoint is in Idle state
+ if (pEndpoint->dState != endpointStateIdle) {
+
+ return USB_STATUS_LOCKED;
+ }
+
+ TRACE_DEBUG_WP("Write%d(%d) ", bEndpoint, dLength);
+
+ // Setup the transfer descriptor
+ pEndpoint->pData = (char *) pData;
+ pEndpoint->dBytesRemaining = dLength;
+ pEndpoint->dBytesBuffered = 0;
+ pEndpoint->dBytesTransferred = 0;
+ pEndpoint->fCallback = fCallback;
+ pEndpoint->pArgument = pArgument;
+ pEndpoint->isDataSent = false;
+
+ // Send one packet
+ pEndpoint->dState = endpointStateWrite;
+
+#ifdef DMA
+ // Test if endpoint type control
+ if (AT91C_OTGHS_EPT_TYPE_CTL_EPT == (AT91C_OTGHS_EPT_TYPE & pInterface->OTGHS_DEVEPTCFG[bEndpoint])) {
+#endif
+ // Enable endpoint IT
+ pInterface->OTGHS_DEVIER = (1<<SHIFT_INTERUPT<<bEndpoint);
+ pInterface->OTGHS_DEVEPTCER[bEndpoint] = AT91C_OTGHS_TXINI;
+
+#ifdef DMA
+ }
+ else {
+
+ // others endoint (not control)
+ pEndpoint->dBytesBuffered = pEndpoint->dBytesRemaining;
+ pEndpoint->dBytesRemaining = 0;
+
+ pInterface->OTGHS_DEVDMA[bEndpoint].OTGHS_DEVDMAADDRESS = (unsigned int) pEndpoint->pData;
+
+ // Enable IT DMA
+ pInterface->OTGHS_DEVIER = (1<<SHIFT_DMA<<bEndpoint);
+
+ pInterface->OTGHS_DEVDMA[bEndpoint].OTGHS_DEVDMACONTROL =
+ (((pEndpoint->dBytesBuffered<<16)&AT91C_OTGHS_BUFF_LENGTH)
+ | AT91C_OTGHS_END_B_EN
+ | AT91C_OTGHS_END_BUFFIT
+ | AT91C_OTGHS_CHANN_ENB);
+
+ }
+#endif
+
+ return USB_STATUS_SUCCESS;
+}
+
+//------------------------------------------------------------------------------
+// \brief 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
+// packet size) is received.
+// \param pUsb Pointer to a S_usb instance
+// \param bEndpoint Index of endpoint
+// \param pData Pointer to a buffer to store the received data
+// \param dLength Length of the receive buffer
+// \param fCallback Optional callback function
+// \param pArgument Optional callback argument
+// \return Operation result code
+// \see Callback_f
+// \see S_usb
+//------------------------------------------------------------------------------
+static char OTGHS_Read(const S_usb *pUsb,
+ unsigned char bEndpoint,
+ void *pData,
+ unsigned int dLength,
+ Callback_f fCallback,
+ void *pArgument)
+{
+ AT91PS_OTGHS pInterface = OTGHS_GetDriverInterface(pUsb);
+ S_usb_endpoint *pEndpoint = USB_GetEndpoint(pUsb, bEndpoint);
+
+ //! Return if the endpoint is not in IDLE state
+ if (pEndpoint->dState != endpointStateIdle) {
+
+ return USB_STATUS_LOCKED;
+ }
+
+ TRACE_DEBUG_M("Read%d(%d) ", bEndpoint, dLength);
+
+ // Endpoint enters Read state
+ pEndpoint->dState = endpointStateRead;
+
+ //! Set the transfer descriptor
+ pEndpoint->pData = (char *) pData;
+ pEndpoint->dBytesRemaining = dLength;
+ pEndpoint->dBytesBuffered = 0;
+ pEndpoint->dBytesTransferred = 0;
+ pEndpoint->fCallback = fCallback;
+ pEndpoint->pArgument = pArgument;
+
+#ifdef DMA
+ // Test if endpoint type control
+ if (AT91C_OTGHS_EPT_TYPE_CTL_EPT == (AT91C_OTGHS_EPT_TYPE & pInterface->OTGHS_DEVEPTCFG[bEndpoint])) {
+#endif
+ // Control endpoint
+ // Enable endpoint IT
+ pInterface->OTGHS_DEVIER = (1<<SHIFT_INTERUPT<<bEndpoint);
+ pInterface->OTGHS_DEVEPTCER[bEndpoint] = AT91C_OTGHS_RXOUT;
+#ifdef DMA
+ }
+ else {
+
+ // others endoint (not control)
+ pEndpoint->dBytesBuffered = pEndpoint->dBytesRemaining;
+ pEndpoint->dBytesRemaining = 0;
+
+ // Enable IT DMA
+ pInterface->OTGHS_DEVIER = (1<<SHIFT_DMA<<bEndpoint);
+
+ pInterface->OTGHS_DEVDMA[bEndpoint].OTGHS_DEVDMAADDRESS = (unsigned int) pEndpoint->pData;
+
+ pInterface->OTGHS_DEVDMA[bEndpoint].OTGHS_DEVDMACONTROL = \
+ ( (pEndpoint->dBytesBuffered<<16)
+ | AT91C_OTGHS_END_TR_EN
+ | AT91C_OTGHS_END_TR_IT
+ | AT91C_OTGHS_END_B_EN
+ | AT91C_OTGHS_END_BUFFIT
+ | AT91C_OTGHS_CHANN_ENB);
+ }
+#endif
+
+ return USB_STATUS_SUCCESS;
+}
+
+//------------------------------------------------------------------------------
+// \brief Clears, sets or returns the Halt state on specified endpoint
+//
+// When in Halt state, an endpoint acknowledges every received packet
+// with a STALL handshake. This continues until the endpoint is
+// manually put out of the Halt state by calling this function.
+// \param pUsb Pointer to a S_usb instance
+// \param bEndpoint Index of endpoint
+// \param bRequest Request to perform
+// -> USB_SET_FEATURE, USB_CLEAR_FEATURE, USB_GET_STATUS
+// \return true if the endpoint is currently Halted, false otherwise
+// \see S_usb
+//------------------------------------------------------------------------------
+static bool OTGHS_Halt(const S_usb *pUsb,
+ unsigned char bEndpoint,
+ unsigned char bRequest)
+{
+ AT91PS_OTGHS pInterface = OTGHS_GetDriverInterface(pUsb);
+ S_usb_endpoint *pEndpoint = USB_GetEndpoint(pUsb, bEndpoint);
+
+ // Clear the Halt feature of the endpoint if it is enabled
+ if (bRequest == USB_CLEAR_FEATURE) {
+
+ TRACE_DEBUG_WP("Unhalt%d ", bEndpoint);
+
+ // Return endpoint to Idle state
+ pEndpoint->dState = endpointStateIdle;
+
+ // Clear FORCESTALL flag
+
+ // Disable stall on endpoint
+ pInterface->OTGHS_DEVEPTCDR[bEndpoint] = AT91C_OTGHS_STALLRQ;
+ pEndpoint->dState = endpointStateIdle;
+
+ // Reset data-toggle
+ pInterface->OTGHS_DEVEPTCER[bEndpoint] = AT91C_OTGHS_RSTDT;
+ }
+ // Set the Halt feature on the endpoint if it is not already enabled
+ // and the endpoint is not disabled
+ else if ((bRequest == USB_SET_FEATURE)
+ && (pEndpoint->dState != endpointStateHalted)
+ && (pEndpoint->dState != endpointStateDisabled)) {
+
+ TRACE_DEBUG_WP("Halt%d ", bEndpoint);
+
+ // Abort the current transfer if necessary
+ OTGHS_EndOfTransfer(pEndpoint, USB_STATUS_ABORTED);
+
+ // Put endpoint into Halt state
+ pInterface->OTGHS_DEVEPTCER[bEndpoint] = AT91C_OTGHS_STALLRQ;
+ pEndpoint->dState = endpointStateHalted;
+
+ // Enable the endpoint interrupt
+ pInterface->OTGHS_DEVIER = (1<<SHIFT_INTERUPT<<bEndpoint);
+ }
+
+ // Return the endpoint halt status
+ if (pEndpoint->dState == endpointStateHalted) {
+
+ return true;
+ }
+ else {
+
+ return false;
+ }
+}
+
+//------------------------------------------------------------------------------
+// \brief Causes the endpoint to acknowledge the next received packet with
+// a STALL handshake.
+//
+// Further packets are then handled normally.
+// \param pUsb Pointer to a S_usb instance
+// \param bEndpoint Index of endpoint
+// \return Operation result code
+// \see S_usb
+//------------------------------------------------------------------------------
+static char OTGHS_Stall(const S_usb *pUsb,
+ unsigned char bEndpoint)
+{
+ AT91PS_OTGHS pInterface = OTGHS_GetDriverInterface(pUsb);
+ S_usb_endpoint *pEndpoint = USB_GetEndpoint(pUsb, bEndpoint);
+
+ // Check that endpoint is in Idle state
+ if (pEndpoint->dState != endpointStateIdle) {
+
+ TRACE_WARNING("UDP_Stall: Endpoint%d locked\n\r", bEndpoint);
+ return USB_STATUS_LOCKED;
+ }
+
+ TRACE_DEBUG_WP("Stall%d ", bEndpoint);
+
+ pInterface->OTGHS_DEVEPTCER[bEndpoint] = AT91C_OTGHS_STALL;
+ pInterface->OTGHS_DEVEPTCER[bEndpoint] = AT91C_OTGHS_STALLRQ;
+
+ return USB_STATUS_SUCCESS;
+}
+
+//------------------------------------------------------------------------------
+// \brief Activates a remote wakeup procedure
+// \param pUsb Pointer to a S_usb instance
+// \see S_usb
+//------------------------------------------------------------------------------
+static void OTGHS_RemoteWakeUp(const S_usb *pUsb)
+{
+ AT91PS_OTGHS pInterface = OTGHS_GetDriverInterface(pUsb);
+
+ OTGHS_EnableMCK(pUsb);
+ OTGHS_EnableOTGHSCK(pUsb);
+ OTGHS_EnableTransceiver(pUsb);
+
+ TRACE_DEBUG_WP("Remote WakeUp ");
+
+ //! Enable wakeup interrupt
+ //pInterface->OTGHS_DEVIER = AT91C_OTGHS_UPRSM;
+
+ // Activates a remote wakeup
+ pInterface->OTGHS_DEVCTRL |= AT91C_OTGHS_RMWKUP;
+}
+
+//------------------------------------------------------------------------------
+// \brief Handles attachment or detachment from the USB when the VBus power
+// line status changes.
+// \param pUsb Pointer to a S_usb instance
+// \return true if VBus is present, false otherwise
+// \see S_usb
+//------------------------------------------------------------------------------
+static bool OTGHS_Attach(const S_usb *pUsb)
+{
+ AT91PS_OTGHS pInterface = OTGHS_GetDriverInterface(pUsb);
+
+ TRACE_DEBUG_WP("Attach(");
+
+ // Check if VBus is present
+ if (!ISSET(USB_GetState(pUsb), USB_STATE_POWERED)
+ && BRD_IsVBusConnected(pInterface)) {
+
+ // Powered state:
+ // MCK + UDPCK must be on
+ // Pull-Up must be connected
+ // Transceiver must be disabled
+
+ // Invoke the Resume callback
+ USB_ResumeCallback(pUsb);
+
+ OTGHS_EnableMCK(pUsb);
+ OTGHS_EnableOTGHSCK(pUsb);
+
+ // Enable the transceiver
+ OTGHS_EnableTransceiver(pUsb);
+
+ // Reconnect the pull-up if needed
+ if (ISSET(*(pUsb->pState), USB_STATE_SHOULD_RECONNECT)) {
+
+ USB_Connect(pUsb);
+ CLEAR(*(pUsb->pState), USB_STATE_SHOULD_RECONNECT);
+ }
+
+ // Clear the Suspend and Resume interrupts
+ pInterface->OTGHS_DEVICR = \
+ AT91C_OTGHS_WAKEUP | AT91C_OTGHS_EORSM | AT91C_OTGHS_SUSP;
+
+ // Enable interrupt
+ pInterface->OTGHS_DEVIER = AT91C_OTGHS_EORST | AT91C_OTGHS_WAKEUP | AT91C_OTGHS_EORSM;
+
+ // The device is in Powered state
+ SET(*(pUsb->pState), USB_STATE_POWERED);
+
+ }
+ else if (ISSET(USB_GetState(pUsb), USB_STATE_POWERED)
+ && !BRD_IsVBusConnected(pInterface)) {
+
+ // Attached state:
+ // MCK + UDPCK off
+ // Pull-Up must be disconnected
+ // Transceiver must be disabled
+
+ // Warning: MCK must be enabled to be able to write in UDP registers
+ // It may have been disabled by the Suspend interrupt, so re-enable it
+ OTGHS_EnableMCK(pUsb);
+
+ // Disable interrupts
+ pInterface->OTGHS_DEVIDR &= ~(AT91C_OTGHS_WAKEUP | AT91C_OTGHS_EORSM
+ | AT91C_OTGHS_SUSP | AT91C_OTGHS_SOF);
+
+ OTGHS_DisableEndpoints(pUsb);
+
+ // Disconnect the pull-up if needed
+ if (ISSET(USB_GetState(pUsb), USB_STATE_DEFAULT)) {
+
+ USB_Disconnect(pUsb);
+ SET(*(pUsb->pState), USB_STATE_SHOULD_RECONNECT);
+ }
+
+ OTGHS_DisableTransceiver(pUsb);
+ OTGHS_DisableMCK(pUsb);
+ OTGHS_DisableOTGHSCK(pUsb);
+
+ // The device leaves the all states except Attached
+ CLEAR(*(pUsb->pState), USB_STATE_POWERED | USB_STATE_DEFAULT
+ | USB_STATE_ADDRESS | USB_STATE_CONFIGURED | USB_STATE_SUSPENDED);
+
+ // Invoke the Suspend callback
+ USB_SuspendCallback(pUsb);
+
+ }
+
+ TRACE_DEBUG_WP("%d) ", ISSET(USB_GetState(pUsb), USB_STATE_POWERED));
+
+ return ISSET(USB_GetState(pUsb), USB_STATE_POWERED);
+}
+
+//------------------------------------------------------------------------------
+// \brief Sets the device address
+//
+// This function directly accesses the S_usb_request instance located
+// in the S_usb structure to extract its new address.
+// \param pUsb Pointer to a S_usb instance
+// \see S_usb
+//------------------------------------------------------------------------------
+static void OTGHS_SetAddress(S_usb const *pUsb)
+{
+ unsigned short wAddress = USB_GetSetup(pUsb)->wValue;
+ AT91PS_OTGHS pInterface = OTGHS_GetDriverInterface(pUsb);
+
+ TRACE_DEBUG_WP("SetAddr(%d) ", wAddress);
+
+ // Set address
+ pInterface->OTGHS_DEVCTRL = wAddress & AT91C_OTGHS_UADD;
+ pInterface->OTGHS_DEVCTRL |= AT91C_OTGHS_ADDEN;
+
+}
+
+//------------------------------------------------------------------------------
+// \brief Changes the device state from Address to Configured, or from
+// Configured to Address.
+//
+// This method directly access the last received SETUP packet to
+// decide on what to do.
+// \see S_usb
+//------------------------------------------------------------------------------
+static void OTGHS_SetConfiguration(S_usb const *pUsb)
+{
+ unsigned short wValue = USB_GetSetup(pUsb)->wValue;
+
+ TRACE_DEBUG_WP("SetCfg() ");
+
+ // Check the request
+ if (wValue != 0) {
+ // Enter Configured state
+ SET(*(pUsb->pState), USB_STATE_CONFIGURED);
+
+ }
+ else {
+
+ // Go back to Address state
+ CLEAR(*(pUsb->pState), USB_STATE_CONFIGURED);
+
+ // Abort all transfers
+ OTGHS_DisableEndpoints(pUsb);
+ }
+}
+
+//------------------------------------------------------------------------------
+// \brief Enables the pull-up on the D+ line to connect the device to the USB.
+// \param pUsb Pointer to a S_usb instance
+// \see S_usb
+//------------------------------------------------------------------------------
+static void OTGHS_Connect(const S_usb *pUsb)
+{
+#if defined(INTERNAL_PULLUP)
+ CLEAR(OTGHS_GetDriverInterface(pUsb)->OTGHS_DEVCTRL, AT91C_OTGHS_DETACH);
+
+#elif defined(INTERNAL_PULLUP_MATRIX)
+ TRACE_DEBUG_WP("PUON 1\n\r");
+ AT91C_BASE_MATRIX->MATRIX_USBPCR |= AT91C_MATRIX_USBPCR_PUON;
+
+#else
+ BRD_ConnectPullUp(UDP_GetDriverInterface(pUsb));
+
+#endif
+}
+
+//------------------------------------------------------------------------------
+// \brief Disables the pull-up on the D+ line to disconnect the device from
+// the bus.
+// \param pUsb Pointer to a S_usb instance
+// \see S_usb
+//------------------------------------------------------------------------------
+static void OTGHS_Disconnect(const S_usb *pUsb)
+{
+#if defined(INTERNAL_PULLUP)
+ SET(OTGHS_GetDriverInterface(pUsb)->OTGHS_DEVCTRL, AT91C_OTGHS_DETACH);
+
+#elif defined(INTERNAL_PULLUP_MATRIX)
+ TRACE_DEBUG_WP("PUON 0\n\r");
+ AT91C_BASE_MATRIX->MATRIX_USBPCR &= ~AT91C_MATRIX_USBPCR_PUON;
+
+#else
+ BRD_DisconnectPullUp(UDP_GetDriverInterface(pUsb));
+
+#endif
+ // Device leaves the Default state
+ CLEAR(*(pUsb->pState), USB_STATE_DEFAULT);
+}
+
+//------------------------------------------------------------------------------
+// \brief Certification test for High Speed device.
+// \param pUsb Pointer to a S_usb instance
+// \param bIndex char for the test choice
+// \see S_usb
+//------------------------------------------------------------------------------
+static void OTGHS_Test(const S_usb *pUsb, unsigned char bIndex)
+{
+ AT91PS_OTGHS pInterface = OTGHS_GetDriverInterface(pUsb);
+
+ pInterface->OTGHS_DEVIDR &= ~AT91C_OTGHS_SUSP;
+ pInterface->OTGHS_DEVCTRL |= AT91C_OTGHS_SPDCONF_HS; // remove suspend ?
+
+ switch( bIndex ) {
+ case TEST_PACKET:
+ TRACE_DEBUG_M("TEST_PACKET ");
+ pInterface->OTGHS_DEVCTRL |= AT91C_OTGHS_TSTPCKT;
+ break;
+
+ case TEST_J:
+ TRACE_DEBUG_M("TEST_J ");
+ pInterface->OTGHS_DEVCTRL |= AT91C_OTGHS_TSTJ;
+ break;
+
+ case TEST_K:
+ TRACE_DEBUG_M("TEST_K ");
+ pInterface->OTGHS_DEVCTRL |= AT91C_OTGHS_TSTK;
+ break;
+
+ case TEST_SEO_NAK:
+ TRACE_DEBUG_M("TEST_SEO_NAK ");
+ pInterface->OTGHS_DEVIDR = 0xFFFFFFFF;
+ break;
+
+ case TEST_SEND_ZLP:
+ pInterface->OTGHS_DEVEPTCCR[0] = AT91C_OTGHS_TXINI;
+ TRACE_DEBUG_M("SEND_ZLP ");
+ break;
+
+ TRACE_DEBUG_M("\n\r");
+ }
+}
+
+//------------------------------------------------------------------------------
+// \brief Certification test for High Speed device.
+// \param pUsb Pointer to a S_usb instance
+// \see S_usb
+//------------------------------------------------------------------------------
+static bool OTGHS_IsHighSpeed(const S_usb *pUsb)
+{
+ AT91PS_OTGHS pInterface = OTGHS_GetDriverInterface(pUsb);
+ bool status = false;
+
+ if(AT91C_OTGHS_SPEED_SR_HS == (pInterface->OTGHS_SR & (0x03<<12))) {
+ // High Speed
+ status = true;
+ }
+
+ return status;
+}
+
+//------------------------------------------------------------------------------
+// \brief Initializes the specified USB driver
+//
+// This function initializes the current FIFO bank of endpoints,
+// configures the pull-up and VBus lines, disconnects the pull-up and
+// then trigger the Init callback.
+// \param pUsb Pointer to a S_usb instance
+// \see S_usb
+//------------------------------------------------------------------------------
+static void OTGHS_Init(const S_usb *pUsb)
+{
+ AT91PS_OTGHS pInterface = OTGHS_GetDriverInterface(pUsb);
+ unsigned char i;
+
+ TRACE_DEBUG_WP("Init()\n\r");
+
+ // Enable USB macro
+ SET(OTGHS_GetDriverInterface(pUsb)->OTGHS_CTRL, AT91C_OTGHS_USBECTRL);
+
+ pInterface->OTGHS_DEVCTRL &=~ AT91C_OTGHS_DETACH; // detach
+
+ //// Force FS (for debug or test)
+// pDriver->OTGHS_DEVCTRL |= AT91C_OTGHS_SPDCONF_FS;
+ pInterface->OTGHS_DEVCTRL &= ~AT91C_OTGHS_SPDCONF_FS; // Normal mode
+ pInterface->OTGHS_DEVCTRL &= ~( AT91C_OTGHS_LS | AT91C_OTGHS_TSTJ
+ | AT91C_OTGHS_TSTK | AT91C_OTGHS_TSTPCKT
+ | AT91C_OTGHS_OPMODE2 ); // Normal mode
+
+
+ // With OR without DMA !!!
+ // Initialization of DMA
+ for( i=1; i<=((AT91C_BASE_OTGHS->OTGHS_IPFEATURES & AT91C_OTGHS_DMA_CHANNEL_NBR)>>4); i++ ) {
+
+ // RESET endpoint canal DMA:
+ // DMA stop channel command
+ AT91C_BASE_OTGHS->OTGHS_DEVDMA[i].OTGHS_DEVDMACONTROL = 0; // STOP command
+
+ // Disable endpoint
+ AT91C_BASE_OTGHS->OTGHS_DEVEPTCDR[i] = 0XFFFFFFFF;
+
+ // Reset endpoint config
+ AT91C_BASE_OTGHS->OTGHS_DEVEPTCFG[i] = 0;
+
+ // Reset DMA channel (Buff count and Control field)
+ AT91C_BASE_OTGHS->OTGHS_DEVDMA[i].OTGHS_DEVDMACONTROL = 0x02; // NON STOP command
+
+ // Reset DMA channel 0 (STOP)
+ AT91C_BASE_OTGHS->OTGHS_DEVDMA[i].OTGHS_DEVDMACONTROL = 0; // STOP command
+
+ // Clear DMA channel status (read the register for clear it)
+ AT91C_BASE_OTGHS->OTGHS_DEVDMA[i].OTGHS_DEVDMASTATUS = AT91C_BASE_OTGHS->OTGHS_DEVDMA[i].OTGHS_DEVDMASTATUS;
+
+ }
+
+ // Enable clock OTG pad
+ pInterface->OTGHS_CTRL &= ~AT91C_OTGHS_FRZCLKCTRL;
+
+ // Clear General IT
+ pInterface->OTGHS_SCR = 0x01FF;
+
+ // Clear OTG Device IT
+ pInterface->OTGHS_DEVICR = 0xFF;
+
+ // Clear OTG Host IT
+ pInterface->OTGHS_HSTICR = 0x7F;
+
+ // Reset all Endpoints Fifos
+ pInterface->OTGHS_DEVEPT |= (0x7F<<16);
+ pInterface->OTGHS_DEVEPT &= ~(0x7F<<16);
+
+ // Disable all endpoints
+ pInterface->OTGHS_DEVEPT &= ~0x7F;
+
+ // Bypass UTMI problems // jcb to be removed with new version of UTMI
+ // pInterface->OTGHS_TSTA2 = (1<<6)|(1<<7)|(1<<8);
+ // pInterface->OTGHS_TSTA2 = (1<<8);
+ pInterface->OTGHS_TSTA2 = 0;
+
+ // External pull-up on D+
+ // Configure
+ BRD_ConfigurePullUp(pInterface);
+
+ // Detach
+ OTGHS_Disconnect(pUsb);
+
+ // Device is in the Attached state
+ *(pUsb->pState) = USB_STATE_ATTACHED;
+
+ // Disable the UDP transceiver and interrupts
+ OTGHS_EnableMCK(pUsb);
+ SET(pInterface->OTGHS_DEVIER, AT91C_OTGHS_EORSM);
+
+ OTGHS_DisableMCK(pUsb);
+ OTGHS_Disconnect(pUsb);
+
+ // Test ID
+ if( 0 != (pInterface->OTGHS_SR & AT91C_OTGHS_ID) ) {
+ TRACE_INFO("ID=1: PERIPHERAL\n\r");
+ }
+ else {
+ TRACE_INFO("ID=0: HOST\n\r");
+ }
+
+ // Test VBUS
+ if( 0 != (pInterface->OTGHS_SR & AT91C_OTGHS_VBUSSR) ) {
+ TRACE_INFO("VBUS = 1\n\r");
+ }
+ else {
+ TRACE_INFO("VBUS = 0\n\r");
+ }
+
+ // Test SPEED
+ if(AT91C_OTGHS_SPEED_SR_HS == (pInterface->OTGHS_SR & (0x03<<12))) {
+ TRACE_INFO("HIGH SPEED\n\r");
+ }
+ else if(AT91C_OTGHS_SPEED_SR_LS == (pInterface->OTGHS_SR & (0x03<<12))) {
+ TRACE_INFO("LOW SPEED\n\r");
+ }
+ else {
+ TRACE_INFO("FULL SPEED\n\r");
+ }
+
+ // Configure interrupts
+ USB_InitCallback(pUsb);
+
+ pInterface->OTGHS_CTRL |= AT91C_OTGHS_VBUSTI;
+}
+
+//------------------------------------------------------------------------------
+// Global variables
+//------------------------------------------------------------------------------
+
+// \brief Low-level driver methods to use with the OTGHS USB controller
+// \see S_driver_methods
+const S_driver_methods sOTGHSMethods = {
+
+ OTGHS_Init,
+ OTGHS_Write,
+ OTGHS_Read,
+ OTGHS_Stall,
+ OTGHS_Halt,
+ OTGHS_RemoteWakeUp,
+ OTGHS_ConfigureEndpoint,
+ OTGHS_Attach,
+ OTGHS_SetAddress,
+ OTGHS_SetConfiguration,
+ OTGHS_Handler,
+ OTGHS_Connect,
+ OTGHS_Disconnect,
+ OTGHS_Test,
+ OTGHS_IsHighSpeed
+};
+
+// \brief Default driver when an UDP controller is present on a chip
+const S_usb_driver sDefaultDriver = {
+
+ AT91C_BASE_OTGHS,
+ AT91C_BASE_OTGHS_EPTFIFO,
+ 0,
+ AT91C_ID_OTGHS,
+ AT91C_PMC_OTG,
+ &sOTGHSMethods
+};
+
+#endif //#ifdef CHIP_OTGHS
+
personal git repositories of Harald Welte. Your mileage may vary