From 98f9d442b44dbe2e3e4b3c8296be7e78d5d05450 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 24 Jul 2011 09:39:28 +0200 Subject: initial import of the usb ccid example for the sam7s --- at91lib/usb/device/core/USBD_UDPHS.c | 1680 ++++++++++++++++++++++++++++++++++ 1 file changed, 1680 insertions(+) create mode 100644 at91lib/usb/device/core/USBD_UDPHS.c (limited to 'at91lib/usb/device/core/USBD_UDPHS.c') diff --git a/at91lib/usb/device/core/USBD_UDPHS.c b/at91lib/usb/device/core/USBD_UDPHS.c new file mode 100644 index 0000000..f7c0684 --- /dev/null +++ b/at91lib/usb/device/core/USBD_UDPHS.c @@ -0,0 +1,1680 @@ +/* ---------------------------------------------------------------------------- + * 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. + * ---------------------------------------------------------------------------- + */ + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ + +#include "USBD.h" +#include "USBDCallbacks.h" +#include "USBDDriver.h" +#include +#include +#include +#include +#include +#include +#include + +#include + +#ifdef BOARD_USB_UDPHS + +//------------------------------------------------------------------------------ +// Definitions +//------------------------------------------------------------------------------ + +/// Maximum number of endpoints interrupts. +#define NUM_IT_MAX \ + (AT91C_BASE_UDPHS->UDPHS_IPFEATURES & AT91C_UDPHS_EPT_NBR_MAX) +/// Maximum number of endpoint DMA interrupts +#define NUM_IT_MAX_DMA \ + ((AT91C_BASE_UDPHS->UDPHS_IPFEATURES & AT91C_UDPHS_DMA_CHANNEL_NBR)>>4) +/// Bits that should be shifted to access DMA control bits. +#define SHIFT_DMA 24 +/// Bits that should be shifted to access interrupt bits. +#define SHIFT_INTERUPT 8 + +/// Compile option, use DMA. Remove this define for not use DMA. +#define DMA + +/// Max size of the FMA FIFO +#define DMA_MAX_FIFO_SIZE 65536 + +//------------------------------------------------------------------------------ +/// \page "Endpoint states" +/// This page lists the endpoint states. +/// !States +// - UDP_ENDPOINT_DISABLED +// - UDP_ENDPOINT_HALTED +// - UDP_ENDPOINT_IDLE +// - UDP_ENDPOINT_SENDING +// - UDP_ENDPOINT_RECEIVING + +/// 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 +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +// Structures +//------------------------------------------------------------------------------ + +/// Describes an ongoing transfer on a UDP endpoint. +typedef struct +{ + /// Pointer to a data buffer used for emission/reception. + char *pData; + /// Number of bytes which have been written into the UDP internal FIFO + /// buffers. + volatile int buffered; + /// Number of bytes which have been sent/received. + volatile int transferred; + /// Number of bytes which have not been buffered/transferred yet. + volatile int remaining; + /// Optional callback to invoke when the transfer completes. + volatile TransferCallback fCallback; + /// Optional argument to the callback function. + void *pArgument; +} Transfer; + +//------------------------------------------------------------------------------ +/// Describes the state of an endpoint of the UDP controller. +//------------------------------------------------------------------------------ +typedef struct +{ + /// Current endpoint state. + volatile unsigned char state; + /// Current reception bank (0 or 1). + unsigned char bank; + /// Maximum packet size for the endpoint. + unsigned short size; + /// Describes an ongoing transfer (if current state is either + /// or ) + Transfer transfer; +} Endpoint; + +//------------------------------------------------------------------------------ +// Internal variables +//------------------------------------------------------------------------------ + +/// Holds the internal state for each endpoint of the UDP. +static Endpoint endpoints[BOARD_USB_NUMENDPOINTS]; +/// Device current state. +static unsigned char deviceState; +/// Indicates the previous device state +static unsigned char previousDeviceState; +/// Special case for send a ZLP +static unsigned char sendZLP = 0; + +/// 7.1.20 Test Mode Support +/// Test codes for the USB HS test mode. +static const char test_packet_buffer[] = { + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // JKJKJKJK * 9 + 0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA, // JJKKJJKK * 8 + 0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE, // JJJJKKKK * 8 + 0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, // JJJJJJJKKKKKKK * 8 + 0x7F,0xBF,0xDF,0xEF,0xF7,0xFB,0xFD, // JJJJJJJK * 8 + 0xFC,0x7E,0xBF,0xDF,0xEF,0xF7,0xFB,0xFD,0x7E // {JKKKKKKK * 10}, JK +}; + +//------------------------------------------------------------------------------ +// Internal Functions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// Disables the BIAS of the USB controller +//------------------------------------------------------------------------------ +static inline void UDPHS_DisableBIAS( void ) +{ + // For CAP9, SAM9RL, HS +#if !defined (BOARD_USB_NO_BIAS_COMMAND) + AT91C_BASE_PMC->PMC_UCKR &= ~AT91C_CKGR_BIASEN_ENABLED; +#endif +} + +//------------------------------------------------------------------------------ +/// Enables the BIAS of the USB controller +//------------------------------------------------------------------------------ +static inline void UDPHS_EnableBIAS( void ) +{ + // For CAP9, SAM9RL, HS +#if !defined (BOARD_USB_NO_BIAS_COMMAND) + UDPHS_DisableBIAS(); + AT91C_BASE_PMC->PMC_UCKR |= AT91C_CKGR_BIASEN_ENABLED; +#endif +} + +//------------------------------------------------------------------------------ +/// Enable UDPHS clock +//------------------------------------------------------------------------------ +static inline void UDPHS_EnableUsbClock( void ) +{ +#if !defined (PMC_BY_HARD) + AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_UDPHS); + // Enable 480MHZ + AT91C_BASE_CKGR->CKGR_UCKR |= (AT91C_CKGR_PLLCOUNT & (3 << 20)) | AT91C_CKGR_UPLLEN; + // Wait until UTMI PLL is locked + while ((AT91C_BASE_PMC->PMC_SR & AT91C_PMC_LOCKU) == 0); +#endif +} + +//------------------------------------------------------------------------------ +/// Disable UDPHS clock +//------------------------------------------------------------------------------ +static inline void UDPHS_DisableUsbClock( void ) +{ +#if !defined (PMC_BY_HARD) + AT91C_BASE_PMC->PMC_PCDR = (1 << AT91C_ID_UDPHS); + // 480MHZ + AT91C_BASE_CKGR->CKGR_UCKR &= ~AT91C_CKGR_UPLLEN; +#endif +} + +//------------------------------------------------------------------------------ +/// 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 UDPHS_EndOfTransfer( unsigned char bEndpoint, char bStatus ) +{ + Endpoint *pEndpoint = &(endpoints[bEndpoint]); + Transfer *pTransfer = &(pEndpoint->transfer); + + // Check that endpoint was sending or receiving data + if( (pEndpoint->state == UDP_ENDPOINT_RECEIVING) + || (pEndpoint->state == UDP_ENDPOINT_SENDING) ) { + + TRACE_DEBUG_WP("Eo"); + + // Endpoint returns in Idle state + pEndpoint->state = UDP_ENDPOINT_IDLE; + + // Invoke callback is present + if (pTransfer->fCallback != 0) { + + ((TransferCallback) pTransfer->fCallback) + (pTransfer->pArgument, + bStatus, + pTransfer->transferred, + pTransfer->remaining + pTransfer->buffered); + } + else { + TRACE_DEBUG_WP("No callBack\n\r"); + } + } +} + +//------------------------------------------------------------------------------ +/// Clears the correct RX flag in endpoint status register +/// \param bEndpoint Index of endpoint +//------------------------------------------------------------------------------ +static void UDPHS_ClearRxFlag( unsigned char bEndpoint ) +{ + AT91C_BASE_UDPHS->UDPHS_EPT[bEndpoint].UDPHS_EPTCLRSTA = AT91C_UDPHS_RX_BK_RDY; +} + +//------------------------------------------------------------------------------ +/// 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 UDPHS_WritePayload( unsigned char bEndpoint ) +{ + Endpoint *pEndpoint = &(endpoints[bEndpoint]); + Transfer *pTransfer = &(pEndpoint->transfer); + char *pFifo; + signed int size; + unsigned int dCtr; + + pFifo = (char*)((unsigned int *)AT91C_BASE_UDPHS_EPTFIFO + (16384 * bEndpoint)); + + // 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 + dCtr = 0; + while (size > 0) { + + pFifo[dCtr] = *(pTransfer->pData); + pTransfer->pData++; + size--; + dCtr++; + } +} + +//------------------------------------------------------------------------------ +/// 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 UDPHS_ReadPayload( unsigned char bEndpoint, int wPacketSize ) +{ + Endpoint *pEndpoint = &(endpoints[bEndpoint]); + Transfer *pTransfer = &(pEndpoint->transfer); + char *pFifo; + unsigned char dBytes=0; + + pFifo = (char*)((unsigned int *)AT91C_BASE_UDPHS_EPTFIFO + (16384 * bEndpoint)); + + // 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) = pFifo[dBytes]; + pTransfer->pData++; + wPacketSize--; + dBytes++; + } +} + + +//------------------------------------------------------------------------------ +/// Received SETUP packet from endpoint 0 FIFO +/// \param pRequest Generic USB SETUP request sent over Control endpoints +//------------------------------------------------------------------------------ +static void UDPHS_ReadRequest( USBGenericRequest *pRequest ) +{ + unsigned int *pData = (unsigned int *)pRequest; + unsigned int fifo; + + fifo = (AT91C_BASE_UDPHS_EPTFIFO->UDPHS_READEPT0[0]); + *pData = fifo; + fifo = (AT91C_BASE_UDPHS_EPTFIFO->UDPHS_READEPT0[0]); + pData++; + *pData = fifo; + //TRACE_ERROR("SETUP: 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n\r", pData[0],pData[1],pData[2],pData[3],pData[4],pData[5],pData[6],pData[7]); +} + +//------------------------------------------------------------------------------ +/// Reset all endpoint transfer descriptors +//------------------------------------------------------------------------------ +static void UDPHS_ResetEndpoints( void ) +{ + Endpoint *pEndpoint; + Transfer *pTransfer; + unsigned char bEndpoint; + + // Reset the transfer descriptor of every endpoint + for( bEndpoint = 0; bEndpoint < BOARD_USB_NUMENDPOINTS; bEndpoint++ ) { + + pEndpoint = &(endpoints[bEndpoint]); + pTransfer = &(pEndpoint->transfer); + + // Reset endpoint transfer descriptor + pTransfer->pData = 0; + pTransfer->transferred = -1; + pTransfer->buffered = -1; + pTransfer->remaining = -1; + pTransfer->fCallback = 0; + pTransfer->pArgument = 0; + + // Reset endpoint state + pEndpoint->bank = 0; + pEndpoint->state = UDP_ENDPOINT_DISABLED; + } +} + + +//------------------------------------------------------------------------------ +/// Disable all endpoints (except control endpoint 0), aborting current +/// transfers if necessary +//------------------------------------------------------------------------------ +static void UDPHS_DisableEndpoints( void ) +{ + unsigned char bEndpoint; + + // Disable each endpoint, terminating any pending transfer + // Control endpoint 0 is not disabled + for( bEndpoint = 1; bEndpoint < BOARD_USB_NUMENDPOINTS; bEndpoint++ ) { + + UDPHS_EndOfTransfer( bEndpoint, USBD_STATUS_ABORTED ); + endpoints[bEndpoint].state = UDP_ENDPOINT_DISABLED; + } +} + +//------------------------------------------------------------------------------ +/// Endpoint interrupt handler. +/// Handle IN/OUT transfers, received SETUP packets and STALLing +/// \param bEndpoint Index of endpoint +//------------------------------------------------------------------------------ +static void UDPHS_EndpointHandler( unsigned char bEndpoint ) +{ + Endpoint *pEndpoint = &(endpoints[bEndpoint]); + Transfer *pTransfer = &(pEndpoint->transfer); + unsigned int status = AT91C_BASE_UDPHS->UDPHS_EPT[bEndpoint].UDPHS_EPTSTA; + unsigned short wPacketSize; + USBGenericRequest request; + + TRACE_DEBUG_WP("E%d ", bEndpoint); + TRACE_DEBUG_WP("st:0x%X ", status); + + // Handle interrupts + // IN packet sent + if( (AT91C_UDPHS_TX_PK_RDY == (AT91C_BASE_UDPHS->UDPHS_EPT[bEndpoint].UDPHS_EPTCTL & AT91C_UDPHS_TX_PK_RDY)) + && (0 == (status & AT91C_UDPHS_TX_PK_RDY )) ) { + + TRACE_DEBUG_WP("Wr "); + + // Check that endpoint was in Sending state + if( pEndpoint->state == UDP_ENDPOINT_SENDING ) { + + if (pTransfer->buffered > 0) { + pTransfer->transferred += pTransfer->buffered; + pTransfer->buffered = 0; + } + + if( ((pTransfer->buffered)==0) + &&((pTransfer->transferred)==0) + &&((pTransfer->remaining)==0) + &&(sendZLP == 0)) { + sendZLP = 1; + } + + // End of transfer ? + if( (pTransfer->remaining > 0) + ||(sendZLP == 1)) { + TRACE_DEBUG_WP("\n\r1pTransfer->buffered %d \n\r", pTransfer->buffered); + TRACE_DEBUG_WP("1pTransfer->transferred %d \n\r", pTransfer->transferred); + TRACE_DEBUG_WP("1pTransfer->remaining %d \n\r", pTransfer->remaining); + + // Transfer remaining data + TRACE_DEBUG_WP(" %d ", pEndpoint->size); + + // Send next packet + UDPHS_WritePayload(bEndpoint); + AT91C_BASE_UDPHS->UDPHS_EPT[bEndpoint].UDPHS_EPTSETSTA = AT91C_UDPHS_TX_PK_RDY; + sendZLP = 2; + } + else { + TRACE_DEBUG_WP("\n\r0pTransfer->buffered %d \n\r", pTransfer->buffered); + TRACE_DEBUG_WP("0pTransfer->transferred %d \n\r", pTransfer->transferred); + TRACE_DEBUG_WP("0pTransfer->remaining %d \n\r", pTransfer->remaining); + + TRACE_DEBUG_WP(" %d ", pTransfer->transferred); + + // Disable interrupt if this is not a control endpoint + if( AT91C_UDPHS_EPT_TYPE_CTL_EPT != (AT91C_UDPHS_EPT_TYPE&(AT91C_BASE_UDPHS->UDPHS_EPT[bEndpoint].UDPHS_EPTCFG)) ) { + + AT91C_BASE_UDPHS->UDPHS_IEN &= ~(1<UDPHS_EPT[bEndpoint].UDPHS_EPTCTLDIS = AT91C_UDPHS_TX_PK_RDY; + + UDPHS_EndOfTransfer(bEndpoint, USBD_STATUS_SUCCESS); + sendZLP = 0; + } + } + else { + + TRACE_ERROR("Error Wr"); + } + } + + // OUT packet received + if( AT91C_UDPHS_RX_BK_RDY == (status & AT91C_UDPHS_RX_BK_RDY) ) { + + 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( (0 == (AT91C_BASE_UDPHS->UDPHS_EPT[bEndpoint].UDPHS_EPTCFG & AT91C_UDPHS_EPT_TYPE)) + && (0 == (status & AT91C_UDPHS_BYTE_COUNT)) ) { + + // Control endpoint, 0 bytes received + // Acknowledge the data and finish the current transfer + TRACE_DEBUG_WP("Ack "); + UDPHS_ClearRxFlag(bEndpoint); + UDPHS_EndOfTransfer(bEndpoint, USBD_STATUS_SUCCESS); + } + // Check if the data has been STALLed + else if( AT91C_UDPHS_FRCESTALL == (status & AT91C_UDPHS_FRCESTALL)) { + + // Discard STALLed data + TRACE_DEBUG_WP("Discard "); + UDPHS_ClearRxFlag(bEndpoint); + } + // NAK the data + else { + + TRACE_DEBUG_WP("Nak "); + AT91C_BASE_UDPHS->UDPHS_IEN &= ~(1<>20); + + TRACE_DEBUG_WP("%d ", wPacketSize); + UDPHS_ReadPayload(bEndpoint, wPacketSize); + UDPHS_ClearRxFlag(bEndpoint); + + // Check if the transfer is finished + if ((pTransfer->remaining == 0) || (wPacketSize < pEndpoint->size)) { + + AT91C_BASE_UDPHS->UDPHS_EPT[bEndpoint].UDPHS_EPTCTLDIS = AT91C_UDPHS_RX_BK_RDY; + + // Disable interrupt if this is not a control endpoint + if( AT91C_UDPHS_EPT_TYPE_CTL_EPT != (AT91C_UDPHS_EPT_TYPE & (AT91C_BASE_UDPHS->UDPHS_EPT[bEndpoint].UDPHS_EPTCFG)) ) { + + AT91C_BASE_UDPHS->UDPHS_IEN &= ~(1<UDPHS_EPT[bEndpoint].UDPHS_EPTCLRSTA = AT91C_UDPHS_STALL_SNT; + + // If the endpoint is not halted, clear the STALL condition + if (pEndpoint->state != UDP_ENDPOINT_HALTED) { + + TRACE_WARNING( "_ " ); + AT91C_BASE_UDPHS->UDPHS_EPT[bEndpoint].UDPHS_EPTCLRSTA = AT91C_UDPHS_FRCESTALL; + } + } + + // SETUP packet received + if( AT91C_UDPHS_RX_SETUP == (status & AT91C_UDPHS_RX_SETUP) ) { + + 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)) { + + UDPHS_EndOfTransfer(bEndpoint, USBD_STATUS_SUCCESS); + } + // Copy the setup packet + UDPHS_ReadRequest(&request); + + // Acknowledge setup packet + AT91C_BASE_UDPHS->UDPHS_EPT[bEndpoint].UDPHS_EPTCLRSTA = AT91C_UDPHS_RX_SETUP; + + // Forward the request to the upper layer + USBDCallbacks_RequestReceived(&request); + } + +} + +//------------------------------------------------------------------------------ +// Interrupt service routine +//------------------------------------------------------------------------------ +#ifdef DMA +//---------------------------------------------------------------------------- +/// Endpoint DMA interrupt handler. +/// This function (ISR) handles dma interrupts +/// \param bEndpoint Index of endpoint +//---------------------------------------------------------------------------- +static void UDPHS_DmaHandler( unsigned char bEndpoint ) +{ + Endpoint *pEndpoint = &(endpoints[bEndpoint]); + Transfer *pTransfer = &(pEndpoint->transfer); + int justTransferred; + unsigned int status; + unsigned char result = USBD_STATUS_SUCCESS; + + status = AT91C_BASE_UDPHS->UDPHS_DMA[bEndpoint].UDPHS_DMASTATUS; + TRACE_DEBUG_WP("Dma Ept%d ", bEndpoint); + + // Disable DMA interrupt to avoid receiving 2 interrupts (B_EN and TR_EN) + AT91C_BASE_UDPHS->UDPHS_DMA[bEndpoint].UDPHS_DMACONTROL &= + ~(AT91C_UDPHS_END_TR_EN | AT91C_UDPHS_END_B_EN); + + AT91C_BASE_UDPHS->UDPHS_IEN &= ~(1 << SHIFT_DMA << bEndpoint); + + if( AT91C_UDPHS_END_BF_ST == (status & AT91C_UDPHS_END_BF_ST) ) { + + TRACE_DEBUG_WP("EndBuffer "); + + // BUFF_COUNT holds the number of untransmitted bytes. + // BUFF_COUNT is equal to zero in case of good transfer + justTransferred = pTransfer->buffered + - ((status & AT91C_UDPHS_BUFF_COUNT) >> 16); + pTransfer->transferred += justTransferred; + + pTransfer->buffered = ((status & AT91C_UDPHS_BUFF_COUNT) >> 16); + + pTransfer->remaining -= justTransferred; + + TRACE_DEBUG_WP("\n\r1pTransfer->buffered %d \n\r", pTransfer->buffered); + TRACE_DEBUG_WP("1pTransfer->transferred %d \n\r", pTransfer->transferred); + TRACE_DEBUG_WP("1pTransfer->remaining %d \n\r", pTransfer->remaining); + + if( (pTransfer->remaining + pTransfer->buffered) > 0 ) { + + // Prepare an other transfer + if( pTransfer->remaining > DMA_MAX_FIFO_SIZE ) { + + pTransfer->buffered = DMA_MAX_FIFO_SIZE; + } + else { + pTransfer->buffered = pTransfer->remaining; + } + + AT91C_BASE_UDPHS->UDPHS_DMA[bEndpoint].UDPHS_DMAADDRESS = + (unsigned int)((pTransfer->pData) + (pTransfer->transferred)); + + // Clear unwanted interrupts + AT91C_BASE_UDPHS->UDPHS_DMA[bEndpoint].UDPHS_DMASTATUS; + + // Enable DMA endpoint interrupt + AT91C_BASE_UDPHS->UDPHS_IEN |= (1 << SHIFT_DMA << bEndpoint); + // DMA config for receive the good size of buffer, or an error buffer + + AT91C_BASE_UDPHS->UDPHS_DMA[bEndpoint].UDPHS_DMACONTROL = 0; // raz + AT91C_BASE_UDPHS->UDPHS_DMA[bEndpoint].UDPHS_DMACONTROL = + ( ((pTransfer->buffered << 16) & AT91C_UDPHS_BUFF_COUNT) + | AT91C_UDPHS_END_TR_EN + | AT91C_UDPHS_END_TR_IT + | AT91C_UDPHS_END_B_EN + | AT91C_UDPHS_END_BUFFIT + | AT91C_UDPHS_CHANN_ENB ); + } + } + else if( AT91C_UDPHS_END_TR_ST == (status & AT91C_UDPHS_END_TR_ST) ) { + + TRACE_DEBUG_WP("EndTransf "); + + pTransfer->transferred = pTransfer->buffered + - ((status & AT91C_UDPHS_BUFF_COUNT) >> 16); + pTransfer->remaining = 0; + TRACE_DEBUG_WP("\n\r0pTransfer->buffered %d \n\r", pTransfer->buffered); + TRACE_DEBUG_WP("0pTransfer->transferred %d \n\r", pTransfer->transferred); + TRACE_DEBUG_WP("0pTransfer->remaining %d \n\r", pTransfer->remaining); + } + else { + + TRACE_ERROR("UDPHS_DmaHandler: Error (0x%08X)\n\r", status); + result = USBD_STATUS_ABORTED; + } + + // Invoke callback + if( pTransfer->remaining == 0 ) { + + TRACE_DEBUG_WP("EOT "); + UDPHS_EndOfTransfer(bEndpoint, result); + } +} +#endif + + +//------------------------------------------------------------------------------ +// Exported functions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// USB interrupt handler +/// Manages device resume, suspend, end of bus reset. +/// Forwards endpoint interrupts to the appropriate handler. +//------------------------------------------------------------------------------ +void USBD_InterruptHandler(void) +{ + unsigned int status; + unsigned char numIT; + + if (deviceState >= USBD_STATE_POWERED) { + + LED_Set(USBD_LEDUSB); + } + + // Get interrupts status + status = AT91C_BASE_UDPHS->UDPHS_INTSTA & AT91C_BASE_UDPHS->UDPHS_IEN; + + // Handle all UDPHS interrupts + TRACE_DEBUG_WP("H"); + while (status != 0) { + + // Start Of Frame (SOF) + if ((status & AT91C_UDPHS_IEN_SOF) != 0) { + + TRACE_DEBUG_WP("SOF "); + + // Invoke the SOF callback + //USB_StartOfFrameCallback(pUsb); + + // Acknowledge interrupt + AT91C_BASE_UDPHS->UDPHS_CLRINT = AT91C_UDPHS_IEN_SOF; + status &= ~AT91C_UDPHS_IEN_SOF; + } + // Suspend + // This interrupt is always treated last (hence the '==') + else if (status == AT91C_UDPHS_DET_SUSPD) { + + TRACE_DEBUG_WP("S"); + + // The device enters the Suspended state + // MCK + UDPCK must be off + // Pull-Up must be connected + // Transceiver must be disabled + + LED_Clear(USBD_LEDUSB); + + UDPHS_DisableBIAS(); + + // Enable wakeup + AT91C_BASE_UDPHS->UDPHS_IEN |= AT91C_UDPHS_WAKE_UP | AT91C_UDPHS_ENDOFRSM; + AT91C_BASE_UDPHS->UDPHS_IEN &= ~AT91C_UDPHS_DET_SUSPD; + + // Acknowledge interrupt + AT91C_BASE_UDPHS->UDPHS_CLRINT = AT91C_UDPHS_DET_SUSPD | AT91C_UDPHS_WAKE_UP; + previousDeviceState = deviceState; + deviceState = USBD_STATE_SUSPENDED; + UDPHS_DisableUsbClock(); + + // Invoke the Suspend callback + USBDCallbacks_Suspended(); + } + // Resume + else if( ((status & AT91C_UDPHS_WAKE_UP) != 0) // line activity + || ((status & AT91C_UDPHS_ENDOFRSM) != 0)) { // pc wakeup + +//JCB +#ifdef NOT_DEFINED +#if !defined(PIN_USB_VBUS) + // Configure PIO + PIO_Configure(&pinVbus, 1); + + // Check current level on VBus + if (PIO_Get(&pinVbus) == 1) // Protection +#endif +#endif + { + // Invoke the Resume callback + USBDCallbacks_Resumed(); + + TRACE_DEBUG_WP("R"); + + UDPHS_EnableUsbClock(); + UDPHS_EnableBIAS(); + + // The device enters Configured state + // MCK + UDPCK must be on + // Pull-Up must be connected + // Transceiver must be enabled + + deviceState = previousDeviceState; + + AT91C_BASE_UDPHS->UDPHS_CLRINT = AT91C_UDPHS_WAKE_UP | AT91C_UDPHS_ENDOFRSM | AT91C_UDPHS_DET_SUSPD; + + AT91C_BASE_UDPHS->UDPHS_IEN |= AT91C_UDPHS_ENDOFRSM | AT91C_UDPHS_DET_SUSPD; + AT91C_BASE_UDPHS->UDPHS_CLRINT = AT91C_UDPHS_WAKE_UP | AT91C_UDPHS_ENDOFRSM; + AT91C_BASE_UDPHS->UDPHS_IEN &= ~AT91C_UDPHS_WAKE_UP; + } +// jcb !!! +#ifdef NOT_DEFINED +#if !defined(PIN_USB_VBUS) + else { + + // No VBUS + // Disconnect the pull-up + USBD_Disconnect(); + AT91C_BASE_UDPHS->UDPHS_CLRINT = AT91C_UDPHS_WAKE_UP; + } +#endif +#endif + } + // End of bus reset + else if ((status & AT91C_UDPHS_ENDRESET) == AT91C_UDPHS_ENDRESET) { + +// TRACE_DEBUG_WP("EoB "); + + // The device enters the Default state + deviceState = USBD_STATE_DEFAULT; + // MCK + UDPCK are already enabled + // Pull-Up is already connected + // Transceiver must be enabled + // Endpoint 0 must be enabled + + UDPHS_ResetEndpoints(); + UDPHS_DisableEndpoints(); + USBD_ConfigureEndpoint(0); + + // Flush and enable the Suspend interrupt + AT91C_BASE_UDPHS->UDPHS_CLRINT = AT91C_UDPHS_WAKE_UP | AT91C_UDPHS_DET_SUSPD; + + //// Enable the Start Of Frame (SOF) interrupt if needed + //if (pCallbacks->startOfFrame != 0) + //{ + // AT91C_BASE_UDPHS->UDPHS_IEN |= AT91C_UDPHS_IEN_SOF; + //} + + // Invoke the Reset callback + USBDCallbacks_Reset(); + + // Acknowledge end of bus reset interrupt + AT91C_BASE_UDPHS->UDPHS_CLRINT = AT91C_UDPHS_ENDRESET; + + AT91C_BASE_UDPHS->UDPHS_IEN |= AT91C_UDPHS_DET_SUSPD; + } + // Handle upstream resume interrupt + else if (status & AT91C_UDPHS_UPSTR_RES) { + + TRACE_DEBUG_WP("ExtRes "); + + // - Acknowledge the IT + AT91C_BASE_UDPHS->UDPHS_CLRINT = AT91C_UDPHS_UPSTR_RES; + } + // Endpoint interrupts + else { +#ifndef DMA + // Handle endpoint interrupts + for (numIT = 0; numIT < NUM_IT_MAX; numIT++) { + + if ((status & (1 << SHIFT_INTERUPT << numIT)) != 0) { + + UDPHS_EndpointHandler(numIT); + } + } +#else + // Handle endpoint control interrupt + if ((status & (1 << SHIFT_INTERUPT << 0)) != 0) { + + UDPHS_EndpointHandler( 0 ); + } + else { + + numIT = 1; + while((status&(0x7E<UDPHS_INTSTA & AT91C_BASE_UDPHS->UDPHS_IEN; + + TRACE_DEBUG_WP("\n\r"); + if (status != 0) { + + TRACE_DEBUG_WP(" - "); + } + } + + if (deviceState >= USBD_STATE_POWERED) { + + LED_Clear(USBD_LEDUSB); + } +} + +//------------------------------------------------------------------------------ +/// Configure an endpoint with the provided endpoint descriptor +/// \param pDdescriptor Pointer to the endpoint descriptor +//------------------------------------------------------------------------------ +void USBD_ConfigureEndpoint(const USBEndpointDescriptor *pDescriptor) +{ + Endpoint *pEndpoint; + unsigned char bEndpoint; + unsigned char bType; + unsigned char bEndpointDir; + unsigned char bSizeEpt = 0; + + // NULL descriptor -> Control endpoint 0 + if (pDescriptor == 0) { + + bEndpoint = 0; + pEndpoint = &(endpoints[bEndpoint]); + bType = USBEndpointDescriptor_CONTROL; + bEndpointDir = 0; + pEndpoint->size = BOARD_USB_ENDPOINTS_MAXPACKETSIZE(0); + pEndpoint->bank = BOARD_USB_ENDPOINTS_BANKS(0); + } + else { + + // The endpoint number + bEndpoint = USBEndpointDescriptor_GetNumber(pDescriptor); + pEndpoint = &(endpoints[bEndpoint]); + // Transfer type: Control, Isochronous, Bulk, Interrupt + bType = USBEndpointDescriptor_GetType(pDescriptor); + // Direction, ignored for control endpoints + bEndpointDir = USBEndpointDescriptor_GetDirection(pDescriptor); + pEndpoint->size = USBEndpointDescriptor_GetMaxPacketSize(pDescriptor); + pEndpoint->bank = BOARD_USB_ENDPOINTS_BANKS(bEndpoint); + } + + // 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) ) { + + UDPHS_EndOfTransfer(bEndpoint, USBD_STATUS_RESET); + } + pEndpoint->state = UDP_ENDPOINT_IDLE; + + // Disable endpoint + AT91C_BASE_UDPHS->UDPHS_EPT[bEndpoint].UDPHS_EPTCTLDIS = AT91C_UDPHS_SHRT_PCKT + | AT91C_UDPHS_BUSY_BANK + | AT91C_UDPHS_NAK_OUT + | AT91C_UDPHS_NAK_IN + | AT91C_UDPHS_STALL_SNT + | AT91C_UDPHS_RX_SETUP + | AT91C_UDPHS_TX_PK_RDY + | AT91C_UDPHS_TX_COMPLT + | AT91C_UDPHS_RX_BK_RDY + | AT91C_UDPHS_ERR_OVFLW + | AT91C_UDPHS_MDATA_RX + | AT91C_UDPHS_DATAX_RX + | AT91C_UDPHS_NYET_DIS + | AT91C_UDPHS_INTDIS_DMA + | AT91C_UDPHS_AUTO_VALID + | AT91C_UDPHS_EPT_DISABL; + + // Reset Endpoint Fifos + AT91C_BASE_UDPHS->UDPHS_EPT[bEndpoint].UDPHS_EPTCLRSTA = AT91C_UDPHS_TOGGLESQ | AT91C_UDPHS_FRCESTALL; + AT91C_BASE_UDPHS->UDPHS_EPTRST = 1<size <= 8 ) { + bSizeEpt = 0; + } + else if ( pEndpoint->size <= 16 ) { + bSizeEpt = 1; + } + else if ( pEndpoint->size <= 32 ) { + bSizeEpt = 2; + } + else if ( pEndpoint->size <= 64 ) { + bSizeEpt = 3; + } + else if ( pEndpoint->size <= 128 ) { + bSizeEpt = 4; + } + else if ( pEndpoint->size <= 256 ) { + bSizeEpt = 5; + } + else if ( pEndpoint->size <= 512 ) { + bSizeEpt = 6; + } + else if ( pEndpoint->size <= 1024 ) { + bSizeEpt = 7; + } //else { + // sizeEpt = 0; // control endpoint + //} + + // Configure endpoint + if (bType == USBEndpointDescriptor_CONTROL) { + + // Enable endpoint IT for control endpoint + AT91C_BASE_UDPHS->UDPHS_IEN |= (1<UDPHS_EPT[bEndpoint].UDPHS_EPTCFG = bSizeEpt + | (bEndpointDir << 3) + | (bType << 4) + | ((pEndpoint->bank) << 6); + + while( (signed int)AT91C_UDPHS_EPT_MAPD != (signed int)((AT91C_BASE_UDPHS->UDPHS_EPT[bEndpoint].UDPHS_EPTCFG) & AT91C_UDPHS_EPT_MAPD) ) { + + // resolved by clearing the reset IT in good place + TRACE_ERROR("PB bEndpoint: 0x%X\n\r", bEndpoint); + TRACE_ERROR("PB bSizeEpt: 0x%X\n\r", bSizeEpt); + TRACE_ERROR("PB bEndpointDir: 0x%X\n\r", bEndpointDir); + TRACE_ERROR("PB bType: 0x%X\n\r", bType); + TRACE_ERROR("PB pEndpoint->bank: 0x%X\n\r", pEndpoint->bank); + TRACE_ERROR("PB UDPHS_EPTCFG: 0x%X\n\r", AT91C_BASE_UDPHS->UDPHS_EPT[bEndpoint].UDPHS_EPTCFG); + for(;;); + } + + if (bType == USBEndpointDescriptor_CONTROL) { + + AT91C_BASE_UDPHS->UDPHS_EPT[bEndpoint].UDPHS_EPTCTLENB = AT91C_UDPHS_RX_BK_RDY + | AT91C_UDPHS_RX_SETUP + | AT91C_UDPHS_EPT_ENABL; + } + else { +#ifndef DMA + AT91C_BASE_UDPHS->UDPHS_EPT[bEndpoint].UDPHS_EPTCTLENB = AT91C_UDPHS_EPT_ENABL; +#else + AT91C_BASE_UDPHS->UDPHS_EPT[bEndpoint].UDPHS_EPTCTLENB = AT91C_UDPHS_AUTO_VALID + | AT91C_UDPHS_EPT_ENABL; +#endif + } + +} + +//------------------------------------------------------------------------------ +/// Sends data through an USB endpoint (IN) +/// 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 bEndpoint Index of endpoint +/// \param *pData Data to be written +/// \param dLength Data length to be send +/// \param fCallback Callback to be call after the success command +/// \param *pArgument Callback argument +/// \return USBD_STATUS_LOCKED or USBD_STATUS_SUCCESS +//------------------------------------------------------------------------------ +char USBD_Write( unsigned char bEndpoint, + const void *pData, + unsigned int dLength, + TransferCallback fCallback, + void *pArgument ) +{ + Endpoint *pEndpoint = &(endpoints[bEndpoint]); + Transfer *pTransfer = &(pEndpoint->transfer); + + // Return if the endpoint is not in IDLE state + if (pEndpoint->state != UDP_ENDPOINT_IDLE) { + + return USBD_STATUS_LOCKED; + } + + TRACE_DEBUG_WP("Write%d(%d) ", bEndpoint, dLength); + + // Setup the transfer descriptor + pTransfer->pData = (void *) pData; + pTransfer->remaining = dLength; + pTransfer->buffered = 0; + pTransfer->transferred = 0; + pTransfer->fCallback = fCallback; + pTransfer->pArgument = pArgument; + + // Send one packet + pEndpoint->state = UDP_ENDPOINT_SENDING; + +#ifdef DMA + // Test if endpoint type control + if(AT91C_UDPHS_EPT_TYPE_CTL_EPT == (AT91C_UDPHS_EPT_TYPE&(AT91C_BASE_UDPHS->UDPHS_EPT[bEndpoint].UDPHS_EPTCFG))) { +#endif + // Enable endpoint IT + AT91C_BASE_UDPHS->UDPHS_IEN |= (1 << SHIFT_INTERUPT << bEndpoint); + AT91C_BASE_UDPHS->UDPHS_EPT[bEndpoint].UDPHS_EPTCTLENB = AT91C_UDPHS_TX_PK_RDY; + +#ifdef DMA + } + else { + + if( pTransfer->remaining == 0 ) { + // DMA not handle ZLP + AT91C_BASE_UDPHS->UDPHS_EPT[bEndpoint].UDPHS_EPTSETSTA = AT91C_UDPHS_TX_PK_RDY; + // Enable endpoint IT + AT91C_BASE_UDPHS->UDPHS_IEN |= (1 << SHIFT_INTERUPT << bEndpoint); + AT91C_BASE_UDPHS->UDPHS_EPT[bEndpoint].UDPHS_EPTCTLENB = AT91C_UDPHS_TX_PK_RDY; + } + else { + // Others endpoints (not control) + if( pTransfer->remaining > DMA_MAX_FIFO_SIZE ) { + + // Transfer the max + pTransfer->buffered = DMA_MAX_FIFO_SIZE; + } + else { + // Transfer the good size + pTransfer->buffered = pTransfer->remaining; + } + + TRACE_DEBUG_WP("\n\r_WR:%d ", pTransfer->remaining ); + TRACE_DEBUG_WP("B:%d ", pTransfer->buffered ); + TRACE_DEBUG_WP("T:%d ", pTransfer->transferred ); + + AT91C_BASE_UDPHS->UDPHS_DMA[bEndpoint].UDPHS_DMAADDRESS = (unsigned int)(pTransfer->pData); + + // Clear unwanted interrupts + AT91C_BASE_UDPHS->UDPHS_DMA[bEndpoint].UDPHS_DMASTATUS; + // Enable DMA endpoint interrupt + AT91C_BASE_UDPHS->UDPHS_IEN |= (1 << SHIFT_DMA << bEndpoint); + // DMA config + AT91C_BASE_UDPHS->UDPHS_DMA[bEndpoint].UDPHS_DMACONTROL = 0; // raz + AT91C_BASE_UDPHS->UDPHS_DMA[bEndpoint].UDPHS_DMACONTROL = + ( ((pTransfer->buffered << 16) & AT91C_UDPHS_BUFF_COUNT) + | AT91C_UDPHS_END_B_EN + | AT91C_UDPHS_END_BUFFIT + | AT91C_UDPHS_CHANN_ENB ); + } + } +#endif + + return USBD_STATUS_SUCCESS; +} + +//------------------------------------------------------------------------------ +/// Reads incoming data on an USB endpoint (OUT) +/// \param bEndpoint Index of endpoint +/// \param *pData Data to be readen +/// \param dLength Data length to be receive +/// \param fCallback Callback to be call after the success command +/// \param *pArgument Callback argument +/// \return USBD_STATUS_LOCKED or USBD_STATUS_SUCCESS +//------------------------------------------------------------------------------ +char USBD_Read( unsigned char bEndpoint, + void *pData, + unsigned int dLength, + TransferCallback fCallback, + void *pArgument ) +{ + Endpoint *pEndpoint = &(endpoints[bEndpoint]); + Transfer *pTransfer = &(pEndpoint->transfer); + + // Return if the endpoint is not in IDLE state + if (pEndpoint->state != UDP_ENDPOINT_IDLE) { + + return USBD_STATUS_LOCKED; + } + + TRACE_DEBUG_WP("Read%d(%d) ", bEndpoint, dLength); + + // Endpoint enters Receiving state + pEndpoint->state = UDP_ENDPOINT_RECEIVING; + + // Set the transfer descriptor + pTransfer->pData = pData; + pTransfer->remaining = dLength; + pTransfer->buffered = 0; + pTransfer->transferred = 0; + pTransfer->fCallback = fCallback; + pTransfer->pArgument = pArgument; + +#ifdef DMA + // Test if endpoint type control + if(AT91C_UDPHS_EPT_TYPE_CTL_EPT == (AT91C_UDPHS_EPT_TYPE&(AT91C_BASE_UDPHS->UDPHS_EPT[bEndpoint].UDPHS_EPTCFG))) { +#endif + // Control endpoint + // Enable endpoint IT + AT91C_BASE_UDPHS->UDPHS_IEN |= (1 << SHIFT_INTERUPT << bEndpoint); + AT91C_BASE_UDPHS->UDPHS_EPT[bEndpoint].UDPHS_EPTCTLENB = AT91C_UDPHS_RX_BK_RDY; +#ifdef DMA + } + else { + + TRACE_DEBUG_WP("Read%d(%d) ", bEndpoint, dLength); + + // Others endpoints (not control) + if( pTransfer->remaining > DMA_MAX_FIFO_SIZE ) { + + // Transfer the max + pTransfer->buffered = DMA_MAX_FIFO_SIZE; + } + else { + // Transfer the good size + pTransfer->buffered = pTransfer->remaining; + } + + AT91C_BASE_UDPHS->UDPHS_DMA[bEndpoint].UDPHS_DMAADDRESS = (unsigned int)(pTransfer->pData); + + // Clear unwanted interrupts + AT91C_BASE_UDPHS->UDPHS_DMA[bEndpoint].UDPHS_DMASTATUS; + + // Enable DMA endpoint interrupt + AT91C_BASE_UDPHS->UDPHS_IEN |= (1 << SHIFT_DMA << bEndpoint); + + TRACE_DEBUG_WP("\n\r_RR:%d ", pTransfer->remaining ); + TRACE_DEBUG_WP("B:%d ", pTransfer->buffered ); + TRACE_DEBUG_WP("T:%d ", pTransfer->transferred ); + + // DMA config + AT91C_BASE_UDPHS->UDPHS_DMA[bEndpoint].UDPHS_DMACONTROL = 0; // raz + AT91C_BASE_UDPHS->UDPHS_DMA[bEndpoint].UDPHS_DMACONTROL = + ( ((pTransfer->buffered << 16) & AT91C_UDPHS_BUFF_COUNT) + | AT91C_UDPHS_END_TR_EN + | AT91C_UDPHS_END_TR_IT + | AT91C_UDPHS_END_B_EN + | AT91C_UDPHS_END_BUFFIT + | AT91C_UDPHS_CHANN_ENB ); + } +#endif + + return USBD_STATUS_SUCCESS; +} + +//------------------------------------------------------------------------------ +/// Put endpoint into Halt state +/// \param bEndpoint Index of endpoint +//------------------------------------------------------------------------------ +void USBD_Halt( unsigned char bEndpoint ) +{ + Endpoint *pEndpoint = &(endpoints[bEndpoint]); + + // 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 + UDPHS_EndOfTransfer(bEndpoint, USBD_STATUS_ABORTED); + + // Put endpoint into Halt state + AT91C_BASE_UDPHS->UDPHS_EPT[bEndpoint].UDPHS_EPTSETSTA = AT91C_UDPHS_FRCESTALL; + pEndpoint->state = UDP_ENDPOINT_HALTED; + +#ifdef DMA + // Test if endpoint type control + if(AT91C_UDPHS_EPT_TYPE_CTL_EPT == (AT91C_UDPHS_EPT_TYPE&(AT91C_BASE_UDPHS->UDPHS_EPT[bEndpoint].UDPHS_EPTCFG))) { +#endif + // Enable the endpoint interrupt + AT91C_BASE_UDPHS->UDPHS_IEN |= (1<UDPHS_IEN |= (1<state != UDP_ENDPOINT_DISABLED) { + + TRACE_DEBUG_WP("Unhalt%d ", bEndpoint); + + // Return endpoint to Idle state + pEndpoint->state = UDP_ENDPOINT_IDLE; + + // Clear FORCESTALL flag + AT91C_BASE_UDPHS->UDPHS_EPT[bEndpoint].UDPHS_EPTCLRSTA = AT91C_UDPHS_TOGGLESQ | AT91C_UDPHS_FRCESTALL; + + // Reset Endpoint Fifos + AT91C_BASE_UDPHS->UDPHS_EPTRST = (1<state == UDP_ENDPOINT_HALTED) { + status = 1; + } + return( status ); +} + +//------------------------------------------------------------------------------ +/// IS High Speed device working in High Speed ? +/// \return 1 if the device is in High Speed; otherwise 0 (Full Speed) +//------------------------------------------------------------------------------ +unsigned char USBD_IsHighSpeed( void ) +{ + unsigned char status = 0; + + if( AT91C_UDPHS_SPEED == (AT91C_BASE_UDPHS->UDPHS_INTSTA & AT91C_UDPHS_SPEED) ) + { + // High Speed + TRACE_DEBUG_WP("High Speed\n\r"); + status = 1; + } + else { + TRACE_DEBUG_WP("Full Speed\n\r"); + } + return( status ); +} + + +//------------------------------------------------------------------------------ +/// Causes the endpoint to acknowledge the next received packet with a STALL +/// handshake. +/// Further packets are then handled normally. +/// \param bEndpoint Index of endpoint +/// \return Operation result code: USBD_STATUS_LOCKED or USBD_STATUS_SUCCESS +//------------------------------------------------------------------------------ +unsigned char USBD_Stall( unsigned char bEndpoint ) +{ + Endpoint *pEndpoint = &(endpoints[bEndpoint]); + + // Check that endpoint is in Idle state + if (pEndpoint->state != UDP_ENDPOINT_IDLE) { + + TRACE_WARNING("UDP_Stall: Endpoint%d locked\n\r", bEndpoint); + return USBD_STATUS_LOCKED; + } + + TRACE_DEBUG_WP("Stall%d ", bEndpoint); + + AT91C_BASE_UDPHS->UDPHS_EPT[bEndpoint].UDPHS_EPTSETSTA = AT91C_UDPHS_FRCESTALL; + + return USBD_STATUS_SUCCESS; +} + +//------------------------------------------------------------------------------ +/// Activates a remote wakeup procedure +//------------------------------------------------------------------------------ +void USBD_RemoteWakeUp(void) +{ + TRACE_DEBUG_WP("Remote WakeUp\n\r"); + + // Device is currently suspended + if (deviceState == USBD_STATE_SUSPENDED) { + + TRACE_DEBUG_WP("RW\n\r"); + UDPHS_EnableUsbClock(); + + // Activates a remote wakeup + AT91C_BASE_UDPHS->UDPHS_CTRL |= AT91C_UDPHS_REWAKEUP; + + while ((AT91C_BASE_UDPHS->UDPHS_CTRL&AT91C_UDPHS_REWAKEUP) == AT91C_UDPHS_REWAKEUP) { + + TRACE_DEBUG_WP("W"); + } + UDPHS_EnableBIAS(); + } + // Device is NOT suspended + else { + + TRACE_WARNING("USBD_RemoteWakeUp: Device is not suspended\n\r"); + } +} + +//------------------------------------------------------------------------------ +/// Sets the device address +/// \param address Adress to be set +//------------------------------------------------------------------------------ +void USBD_SetAddress( unsigned char address ) +{ + TRACE_DEBUG_WP("SetAddr(%d) ", address); + + // Set address + AT91C_BASE_UDPHS->UDPHS_CTRL &= ~AT91C_UDPHS_DEV_ADDR; // RAZ Address + AT91C_BASE_UDPHS->UDPHS_CTRL |= address | AT91C_UDPHS_FADDR_EN; + + // If the address is 0, the device returns to the Default state + if (address == 0) { + deviceState = USBD_STATE_DEFAULT; + } + // If the address is non-zero, the device enters the Address state + else { + deviceState = USBD_STATE_ADDRESS; + } +} + +//------------------------------------------------------------------------------ +/// 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. +/// \param cfgnum configuration number +//------------------------------------------------------------------------------ +void USBD_SetConfiguration( unsigned char cfgnum ) +{ + TRACE_DEBUG_WP("SetCfg(%d) ", cfgnum); + + // Check the request + if( cfgnum != 0 ) { + + // Enter Configured state + deviceState = USBD_STATE_CONFIGURED; + } + // If the configuration number is zero, the device goes back to the Address + // state + else { + + // Go back to Address state + deviceState = USBD_STATE_ADDRESS; + + // Abort all transfers + UDPHS_DisableEndpoints(); + } +} + +//------------------------------------------------------------------------------ +/// Enables the pull-up on the D+ line to connect the device to the USB. +//------------------------------------------------------------------------------ +void USBD_Connect( void ) +{ + TRACE_DEBUG_WP("Conn "); +#if defined(BOARD_USB_PULLUP_INTERNAL) + AT91C_BASE_UDPHS->UDPHS_CTRL &= ~AT91C_UDPHS_DETACH; // Pull Up on DP + AT91C_BASE_UDPHS->UDPHS_CTRL |= AT91C_UDPHS_PULLD_DIS; // Disable Pull Down + +#elif defined(BOARD_USB_PULLUP_INTERNAL_BY_MATRIX) + TRACE_DEBUG_WP("PUON 1\n\r"); + AT91C_BASE_MATRIX->MATRIX_USBPCR |= AT91C_MATRIX_USBPCR_PUON; + +#elif defined(BOARD_USB_PULLUP_EXTERNAL) + +#ifdef PIN_USB_PULLUP + const Pin pinPullUp = PIN_USB_PULLUP; + if( pinPullUp.attribute == PIO_OUTPUT_0 ) { + + PIO_Set(&pinPullUp); + } + else { + + PIO_Clear(&pinPullUp); + } +#else + #error unsupported now +#endif + +#elif !defined(BOARD_USB_PULLUP_ALWAYSON) + #error Unsupported pull-up type. + +#endif +} + +//------------------------------------------------------------------------------ +/// Disables the pull-up on the D+ line to disconnect the device from the bus. +//------------------------------------------------------------------------------ +void USBD_Disconnect( void ) +{ + TRACE_DEBUG_WP("Disc "); + +#if defined(BOARD_USB_PULLUP_INTERNAL) + AT91C_BASE_UDPHS->UDPHS_CTRL |= AT91C_UDPHS_DETACH; // detach + AT91C_BASE_UDPHS->UDPHS_CTRL &= ~AT91C_UDPHS_PULLD_DIS; // Enable Pull Down + +#elif defined(BOARD_USB_PULLUP_INTERNAL_BY_MATRIX) + AT91C_BASE_MATRIX->MATRIX_USBPCR &= ~AT91C_MATRIX_USBPCR_PUON; + +#elif defined(BOARD_USB_PULLUP_EXTERNAL) + +#ifdef PIN_USB_PULLUP + const Pin pinPullUp = PIN_USB_PULLUP; + if (pinPullUp.attribute == PIO_OUTPUT_0) { + + PIO_Clear(&pinPullUp); + } + else { + + PIO_Set(&pinPullUp); + } +#else + #error unsupported now +#endif + +#elif !defined(BOARD_USB_PULLUP_ALWAYSON) + #error Unsupported pull-up type. + +#endif + + // Device returns to the Powered state + if (deviceState > USBD_STATE_POWERED) { + + deviceState = USBD_STATE_POWERED; + } +} + +//------------------------------------------------------------------------------ +/// Certification test for High Speed device. +/// \param bIndex Test to be done +//------------------------------------------------------------------------------ +void USBD_Test( unsigned char bIndex ) +{ + char *pFifo; + unsigned char i; + + AT91C_BASE_UDPHS->UDPHS_IEN &= ~AT91C_UDPHS_DET_SUSPD; // remove suspend for TEST + AT91C_BASE_UDPHS->UDPHS_TST |= AT91C_UDPHS_SPEED_CFG_HS; // force High Speed (remove suspend) + + switch( bIndex ) { + + case USBFeatureRequest_TESTPACKET: + TRACE_DEBUG_WP("TEST_PACKET "); + + AT91C_BASE_UDPHS->UDPHS_DMA[1].UDPHS_DMACONTROL = 0; + AT91C_BASE_UDPHS->UDPHS_DMA[2].UDPHS_DMACONTROL = 0; + + // Configure endpoint 2, 64 bytes, direction IN, type BULK, 1 bank + AT91C_BASE_UDPHS->UDPHS_EPT[2].UDPHS_EPTCFG = AT91C_UDPHS_EPT_SIZE_64 | AT91C_UDPHS_EPT_DIR_IN | AT91C_UDPHS_EPT_TYPE_BUL_EPT | AT91C_UDPHS_BK_NUMBER_1; + while( (signed int)(AT91C_BASE_UDPHS->UDPHS_EPT[2].UDPHS_EPTCFG & AT91C_UDPHS_EPT_MAPD) != (signed int)AT91C_UDPHS_EPT_MAPD ) {} + + AT91C_BASE_UDPHS->UDPHS_EPT[2].UDPHS_EPTCTLENB = AT91C_UDPHS_EPT_ENABL; + + // Write FIFO + pFifo = (char*)((unsigned int *)(AT91C_BASE_UDPHS_EPTFIFO->UDPHS_READEPT0) + (16384 * 2)); + for( i=0; iUDPHS_TST |= AT91C_UDPHS_TST_PKT; + // Send packet + AT91C_BASE_UDPHS->UDPHS_EPT[2].UDPHS_EPTSETSTA = AT91C_UDPHS_TX_PK_RDY; + break; + + case USBFeatureRequest_TESTJ: + TRACE_DEBUG_WP("TEST_J "); + AT91C_BASE_UDPHS->UDPHS_TST = AT91C_UDPHS_TST_J; + break; + + case USBFeatureRequest_TESTK: + TRACE_DEBUG_WP("TEST_K "); + AT91C_BASE_UDPHS->UDPHS_TST = AT91C_UDPHS_TST_K; + break; + + case USBFeatureRequest_TESTSE0NAK: + TRACE_DEBUG_WP("TEST_SEO_NAK "); + AT91C_BASE_UDPHS->UDPHS_IEN = 0; // for test + break; + + case USBFeatureRequest_TESTSENDZLP: + //while( 0 != (AT91C_BASE_UDPHS->UDPHS_EPT[0].UDPHS_EPTSTA & AT91C_UDPHS_TX_PK_RDY ) ) {} + AT91C_BASE_UDPHS->UDPHS_EPT[0].UDPHS_EPTSETSTA = AT91C_UDPHS_TX_PK_RDY; + //while( 0 != (AT91C_BASE_UDPHS->UDPHS_EPT[0].UDPHS_EPTSTA & AT91C_UDPHS_TX_PK_RDY ) ) {} + TRACE_DEBUG_WP("SEND_ZLP "); + break; + } + TRACE_DEBUG_WP("\n\r"); +} + + +//------------------------------------------------------------------------------ +/// 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. +//------------------------------------------------------------------------------ +void USBD_Init( void ) +{ + unsigned char i; + + TRACE_DEBUG_WP("USBD Init()\n\r"); + + // Reset endpoint structures + UDPHS_ResetEndpoints(); + + // Enables the USB Clock + UDPHS_EnableUsbClock(); + + // Configure the pull-up on D+ and disconnect it +#if defined(BOARD_USB_PULLUP_INTERNAL) + AT91C_BASE_UDPHS->UDPHS_CTRL |= AT91C_UDPHS_DETACH; // detach + AT91C_BASE_UDPHS->UDPHS_CTRL |= AT91C_UDPHS_PULLD_DIS; // Disable Pull Down + +#elif defined(BOARD_USB_PULLUP_INTERNAL_BY_MATRIX) + TRACE_DEBUG_WP("PUON 0\n\r"); + AT91C_BASE_MATRIX->MATRIX_USBPCR &= ~AT91C_MATRIX_USBPCR_PUON; + +#elif defined(BOARD_USB_PULLUP_EXTERNAL) +#ifdef PIN_USB_PULLUP + const Pin pinPullUp = PIN_USB_PULLUP; + PIO_Configure(&pinPullUp, 1); + if (pinPullUp.attribute == PIO_OUTPUT_0) { + + PIO_Clear(&pinPullUp); + } + else { + + PIO_Set(&pinPullUp); + } +#else + #error unsupported now +#endif +#elif !defined(BOARD_USB_PULLUP_ALWAYSON) + #error Unsupported pull-up type. + +#endif + + // Reset and enable IP UDPHS + AT91C_BASE_UDPHS->UDPHS_CTRL &= ~AT91C_UDPHS_EN_UDPHS; + AT91C_BASE_UDPHS->UDPHS_CTRL |= AT91C_UDPHS_EN_UDPHS; + // Enable and disable of the transceiver is automaticaly done by the IP. + + // With OR without DMA !!! + // Initialization of DMA + for( i=1; i<=((AT91C_BASE_UDPHS->UDPHS_IPFEATURES & AT91C_UDPHS_DMA_CHANNEL_NBR)>>4); i++ ) { + + // RESET endpoint canal DMA: + // DMA stop channel command + AT91C_BASE_UDPHS->UDPHS_DMA[i].UDPHS_DMACONTROL = 0; // STOP command + + // Disable endpoint + AT91C_BASE_UDPHS->UDPHS_EPT[i].UDPHS_EPTCTLDIS = AT91C_UDPHS_SHRT_PCKT + | AT91C_UDPHS_BUSY_BANK + | AT91C_UDPHS_NAK_OUT + | AT91C_UDPHS_NAK_IN + | AT91C_UDPHS_STALL_SNT + | AT91C_UDPHS_RX_SETUP + | AT91C_UDPHS_TX_PK_RDY + | AT91C_UDPHS_TX_COMPLT + | AT91C_UDPHS_RX_BK_RDY + | AT91C_UDPHS_ERR_OVFLW + | AT91C_UDPHS_MDATA_RX + | AT91C_UDPHS_DATAX_RX + | AT91C_UDPHS_NYET_DIS + | AT91C_UDPHS_INTDIS_DMA + | AT91C_UDPHS_AUTO_VALID + | AT91C_UDPHS_EPT_DISABL; + + // Clear status endpoint + AT91C_BASE_UDPHS->UDPHS_EPT[i].UDPHS_EPTCLRSTA = AT91C_UDPHS_TOGGLESQ + | AT91C_UDPHS_FRCESTALL + | AT91C_UDPHS_RX_BK_RDY + | AT91C_UDPHS_TX_COMPLT + | AT91C_UDPHS_RX_SETUP + | AT91C_UDPHS_STALL_SNT + | AT91C_UDPHS_NAK_IN + | AT91C_UDPHS_NAK_OUT; + + // Reset endpoint config + AT91C_BASE_UDPHS->UDPHS_EPT[i].UDPHS_EPTCTLENB = 0; + + // Reset DMA channel (Buff count and Control field) + AT91C_BASE_UDPHS->UDPHS_DMA[i].UDPHS_DMACONTROL = AT91C_UDPHS_LDNXT_DSC; // NON STOP command + + // Reset DMA channel 0 (STOP) + AT91C_BASE_UDPHS->UDPHS_DMA[i].UDPHS_DMACONTROL = 0; // STOP command + + // Clear DMA channel status (read the register for clear it) + AT91C_BASE_UDPHS->UDPHS_DMA[i].UDPHS_DMASTATUS = AT91C_BASE_UDPHS->UDPHS_DMA[i].UDPHS_DMASTATUS; + + } + + AT91C_BASE_UDPHS->UDPHS_TST = 0; + AT91C_BASE_UDPHS->UDPHS_IEN = 0; + AT91C_BASE_UDPHS->UDPHS_CLRINT = AT91C_UDPHS_UPSTR_RES + | AT91C_UDPHS_ENDOFRSM + | AT91C_UDPHS_WAKE_UP + | AT91C_UDPHS_ENDRESET + | AT91C_UDPHS_IEN_SOF + | AT91C_UDPHS_MICRO_SOF + | AT91C_UDPHS_DET_SUSPD; + + // Device is in the Attached state + deviceState = USBD_STATE_SUSPENDED; + previousDeviceState = USBD_STATE_POWERED; + + // Disable interrupts + AT91C_BASE_UDPHS->UDPHS_IEN = AT91C_UDPHS_ENDOFRSM + | AT91C_UDPHS_WAKE_UP + | AT91C_UDPHS_DET_SUSPD; + + // Disable USB clocks + UDPHS_DisableUsbClock(); + + // Configure interrupts + USBDCallbacks_Initialized(); +} + +//------------------------------------------------------------------------------ +/// Returns the current state of the USB device. +/// \return Device current state. +//------------------------------------------------------------------------------ +unsigned char USBD_GetState( void ) +{ + return deviceState; +} + +#endif // BOARD_USB_UDPHS + -- cgit v1.2.3