blob: b40f768ed0340432ccdc0692bb93c2980e6c4f43 [file] [log] [blame]
/* ----------------------------------------------------------------------------
* SAM Software Package License
* ----------------------------------------------------------------------------
* Copyright (c) 2014, Atmel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ----------------------------------------------------------------------------
*/
/**
\file
Implementation of USB device functions on a UDP controller.
See \ref usbd_api_method USBD API Methods.
*/
/** \addtogroup usbd_hal
*@{*/
/*---------------------------------------------------------------------------
* Headers
*---------------------------------------------------------------------------*/
#include "chip.h"
#include "USBD_HAL.h"
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
/*---------------------------------------------------------------------------
* Definitions
*---------------------------------------------------------------------------*/
#define DMA
/** Maximum number of endpoints interrupts. */
#define NUM_IT_MAX 11
/** Maximum number of endpoint DMA interrupts */
#define NUM_IT_MAX_DMA \
((USBHS->UDPHS_IPFEATURES \
& UDPHS_IPFEATURES_DMA_CHANNEL_NBR_Msk) \
>>UDPHS_IPFEATURES_DMA_CHANNEL_NBR_Pos)
/** Bits that should be shifted to access interrupt bits. */
#define SHIFT_INTERUPT 12
/** Max size of the FMA FIFO */
#define DMA_MAX_FIFO_SIZE (65536/1)
/** fifo space size in DW */
#define EPT_VIRTUAL_SIZE 16384
/**
* \section endpoint_states_sec "UDP Endpoint states"
*
* This page lists the endpoint states.
*
* \subsection States
* - UDPHS_ENDPOINT_DISABLED
* - UDPHS_ENDPOINT_HALTED
* - UDPHS_ENDPOINT_IDLE
* - UDPHS_ENDPOINT_SENDING
* - UDPHS_ENDPOINT_RECEIVING
* - UDPHS_ENDPOINT_SENDINGM
* - UDPHS_ENDPOINT_RECEIVINGM
*/
/** Endpoint states: Endpoint is disabled */
#define UDPHS_ENDPOINT_DISABLED 0
/** Endpoint states: Endpoint is halted (i.e. STALLs every request) */
#define UDPHS_ENDPOINT_HALTED 1
/** Endpoint states: Endpoint is idle (i.e. ready for transmission) */
#define UDPHS_ENDPOINT_IDLE 2
/** Endpoint states: Endpoint is sending data */
#define UDPHS_ENDPOINT_SENDING 3
/** Endpoint states: Endpoint is receiving data */
#define UDPHS_ENDPOINT_RECEIVING 4
/** Endpoint states: Endpoint is sending MBL */
#define UDPHS_ENDPOINT_SENDINGM 5
/** Endpoint states: Endpoint is receiving MBL */
#define UDPHS_ENDPOINT_RECEIVINGM 6
/** Get Number of buffer in Multi-Buffer-List
* \param i input index
* \param o output index
* \param size list size
*/
#define MBL_NbBuffer(i, o, size) (((i)>(o))?((i)-(o)):((i)+(size)-(o)))
/** Buffer list is full */
#define MBL_FULL 1
/** Buffer list is null */
#define MBL_NULL 2
/*---------------------------------------------------------------------------
* Types
*---------------------------------------------------------------------------*/
/** Describes header for UDP endpoint transfer. */
typedef struct {
/** Optional callback to invoke when the transfer completes. */
void* fCallback;
/** Optional argument to the callback function. */
void* pArgument;
/** Transfer type */
uint8_t transType;
/* Reserved to 32-b aligned */
uint8_t reserved[3];
} TransferHeader;
/** Describes a transfer on a UDP endpoint. */
typedef struct {
/** Optional callback to invoke when the transfer completes. */
TransferCallback fCallback;
/** Optional argument to the callback function. */
void *pArgument;
/** Transfer type */
uint8_t transType;
uint8_t reserved[3];
/** Number of bytes which have been written into the UDP internal FIFO
* buffers. */
int32_t buffered;
/** Pointer to a data buffer used for emission/reception. */
uint8_t *pData;
/** Number of bytes which have been sent/received. */
int32_t transferred;
/** Number of bytes which have not been buffered/transferred yet. */
int32_t remaining;
} Transfer;
/** Describes Multi Buffer List transfer on a UDP endpoint. */
typedef struct {
/** Optional callback to invoke when the transfer completes. */
MblTransferCallback fCallback;
/** Optional argument to the callback function. */
void *pArgument;
/** Transfer type */
uint8_t transType;
/** List state (OK, FULL, NULL) (run time) */
uint8_t listState;
/** Multi-Buffer List size */
uint16_t listSize;
/** Pointer to multi-buffer list */
USBDTransferBuffer *pMbl;
/** Offset number of buffers to start transfer */
uint16_t offsetSize;
/** Current processing buffer index (run time) */
uint16_t outCurr;
/** Loaded buffer index (run time) */
uint16_t outLast;
/** Current buffer for input (run time) */
uint16_t inCurr;
} MblTransfer;
/**
* Describes the state of an endpoint of the UDP controller.
*/
typedef struct {
/* CSR */
/** Current endpoint state. */
volatile uint8_t state;
/** Current reception bank (0 or 1). */
volatile uint8_t bank;
/** Maximum packet size for the endpoint. */
volatile uint16_t size;
/** Describes an ongoing transfer (if current state is either
* UDPHS_ENDPOINT_SENDING or UDPHS_ENDPOINT_RECEIVING) */
union {
TransferHeader transHdr;
Transfer singleTransfer;
MblTransfer mblTransfer;
} transfer;
/** Special case for send a ZLP */
uint32_t sendZLP;
} Endpoint;
/**
* DMA Descriptor.
*/
typedef struct {
void *pNxtDesc;
void *pAddr;
uint32_t dwCtrl;
uint32_t dw;
} UdphsDmaDescriptor;
/*---------------------------------------------------------------------------
* Internal variables
*---------------------------------------------------------------------------*/
/** Holds the internal state for each endpoint of the UDP. */
static Endpoint endpoints[CHIP_USB_NUMENDPOINTS];
/** 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
};
/** DMA link list */
COMPILER_ALIGNED(16) static UdphsDmaDescriptor dmaLL[5];
COMPILER_ALIGNED(16) static UdphsDmaDescriptor *pDmaLL;
/*---------------------------------------------------------------------------
* Internal Functions
*---------------------------------------------------------------------------*/
/**
* 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(uint8_t bEndpoint, uint8_t bStatus)
{
Endpoint *pEp = &(endpoints[bEndpoint]);
/* Check that endpoint was sending or receiving data */
if ( (pEp->state == UDPHS_ENDPOINT_RECEIVING)
|| (pEp->state == UDPHS_ENDPOINT_SENDING) )
{
Transfer *pXfr = (Transfer*)&(pEp->transfer);
uint32_t transferred = pXfr->transferred;
uint32_t remaining = pXfr->remaining + pXfr->buffered;
TRACE_DEBUG_WP("EoT ");
if (pEp->state == UDPHS_ENDPOINT_SENDING)
pEp->sendZLP = 0;
pEp->state = UDPHS_ENDPOINT_IDLE;
pXfr->pData = 0;
pXfr->transferred = -1;
pXfr->buffered = -1;
pXfr->remaining = -1;
/* Invoke callback */
if (pXfr->fCallback)
{
pXfr->fCallback(pXfr->pArgument, bStatus, transferred, remaining);
}
else
{
TRACE_DEBUG_WP("NoCB ");
}
}
else if ( (pEp->state == UDPHS_ENDPOINT_RECEIVINGM)
|| (pEp->state == UDPHS_ENDPOINT_SENDINGM) )
{
MblTransfer *pXfr = (MblTransfer*)&(pEp->transfer);
TRACE_DEBUG_WP("EoMT ");
pEp->state = UDPHS_ENDPOINT_IDLE;
pXfr->listState = 0;
pXfr->outCurr = pXfr->inCurr = pXfr->outLast = 0;
/* Invoke callback */
if (pXfr->fCallback)
{
pXfr->fCallback(pXfr->pArgument, bStatus);
}
else
{
TRACE_DEBUG_WP("NoCB ");
}
}
}
/**
* Update multi-buffer-transfer descriptors.
* \param pTransfer Pointer to instance MblTransfer.
* \param size Size of bytes that processed.
* \param forceEnd Force the buffer END.
* \return 1 if current buffer ended.
*/
static uint8_t UDPHS_MblUpdate(MblTransfer *pTransfer,
USBDTransferBuffer * pBi,
uint16_t size,
uint8_t forceEnd)
{
/* Update transfer descriptor */
pBi->remaining -= size;
/* Check if list NULL */
if (pTransfer->listState == MBL_NULL) {
return 1;
}
/* Check if current buffer ended */
if (pBi->remaining == 0 || forceEnd || size == 0) {
/* Process to next buffer */
if ((++ pTransfer->outCurr) == pTransfer->listSize)
pTransfer->outCurr = 0;
/* Check buffer NULL case */
if (pTransfer->outCurr == pTransfer->inCurr)
pTransfer->listState = MBL_NULL;
else {
pTransfer->listState = 0;
/* Continue transfer, prepare for next operation */
pBi = &pTransfer->pMbl[pTransfer->outCurr];
pBi->buffered = 0;
pBi->transferred = 0;
pBi->remaining = pBi->size;
}
return 1;
}
return 0;
}
/**
* Transfers a data payload from the current transfer buffer to the endpoint
* FIFO
* \param bEndpoint Number of the endpoint which is sending data.
*/
static uint8_t UDPHS_MblWriteFifo(uint8_t bEndpoint)
{
Endpoint *pEndpoint = &(endpoints[bEndpoint]);
MblTransfer *pTransfer = (MblTransfer*)&(pEndpoint->transfer);
USBDTransferBuffer *pBi = &(pTransfer->pMbl[pTransfer->outCurr]);
uint8_t *pFifo;
int32_t size;
volatile uint8_t * pBytes;
volatile uint8_t bufferEnd = 1;
/* Get the number of bytes to send */
size = pEndpoint->size;
if (size > pBi->remaining) size = pBi->remaining;
TRACE_DEBUG_WP("w%d.%d ", pTransfer->outCurr, size);
/* Record last accessed buffer */
pTransfer->outLast = pTransfer->outCurr;
pBytes = &(pBi->pBuffer[pBi->transferred + pBi->buffered]);
pBi->buffered += size;
bufferEnd = UDPHS_MblUpdate(pTransfer, pBi, size, 0);
/* Write packet in the FIFO buffer */
pFifo = (uint8_t*)((uint32_t*)USBHS_RAM_ADDR
+ (EPT_VIRTUAL_SIZE * bEndpoint));
memory_sync();
if (size) {
int32_t c8 = size >> 3;
int32_t c1 = size & 0x7;
for (; c8; c8 --) {
*(pFifo++) = *(pBytes ++);
*(pFifo++) = *(pBytes ++);
*(pFifo++) = *(pBytes ++);
*(pFifo++) = *(pBytes ++);
*(pFifo++) = *(pBytes ++);
*(pFifo++) = *(pBytes ++);
*(pFifo++) = *(pBytes ++);
*(pFifo++) = *(pBytes ++);
}
for (; c1; c1 --) {
*(pFifo++) = *(pBytes ++);
}
}
return bufferEnd;
}
#if 0
/**
* Transfers a data payload from an endpoint FIFO to the current transfer
* buffer, if NULL packet received, the current buffer is ENDed.
* \param bEndpoint Endpoint number.
* \param wPacketSize Size of received data packet */
* \return 1 if the buffer ENDed. */
*/
static uint8_t UDPHS_MblReadFifo(uint8_t bEndpoint, uint16_t wPacketSize)
{
return 0;
}
*/
#endif
/**
* Transfers a data payload from the current transfer buffer to the endpoint
* FIFO
* \param bEndpoint Number of the endpoint which is sending data.
*/
static void UDPHS_WritePayload(uint8_t bEndpoint, int32_t size)
{
Endpoint *pEndpoint = &(endpoints[bEndpoint]);
Transfer *pTransfer = (Transfer*)&(pEndpoint->transfer);
uint8_t *pFifo;
/* Get the number of bytes to send */
if (size > pTransfer->remaining)
{
size = pTransfer->remaining;
}
/* Update transfer descriptor information */
pTransfer->buffered += size;
pTransfer->remaining -= size;
/* Write packet in the FIFO buffer */
pFifo = (uint8_t*)((uint32_t*)USBHS_RAM_ADDR
+ (EPT_VIRTUAL_SIZE * bEndpoint));
memory_sync();
for (; size; size --)
{
*(pFifo ++) = *(pTransfer->pData ++);
}
memory_sync();
}
/**
* 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(uint8_t bEndpoint, int32_t wPacketSize)
{
Endpoint *pEndpoint = &(endpoints[bEndpoint]);
Transfer *pTransfer = (Transfer*)&(pEndpoint->transfer);
uint8_t *pFifo;
/* 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 */
pFifo = (uint8_t*)((uint32_t*)USBHS_RAM_ADDR
+ (EPT_VIRTUAL_SIZE * bEndpoint));
while (wPacketSize > 0)
{
*(pTransfer->pData ++) = *(pFifo ++);
memory_sync();
wPacketSize--;
}
}
/**
* Received SETUP packet from endpoint 0 FIFO
* \param pRequest Generic USB SETUP request sent over Control endpoints
*/
static void UDPHS_ReadRequest(USBGenericRequest *pRequest)
{
uint32_t *pData = (uint32_t *)(void*)pRequest;
volatile uint32_t *pFifo;
pFifo = (volatile uint32_t*)USBHS_RAM_ADDR;
*pData ++ = *pFifo;
memory_sync();
pFifo = (volatile uint32_t*)USBHS_RAM_ADDR;
*pData = *pFifo;
memory_sync();
}
/**
* Endpoint interrupt handler.
* Handle IN/OUT transfers, received SETUP packets and STALLing
* \param bEndpoint Index of endpoint
*/
static void UDPHS_EndpointHandler(uint8_t bEndpoint)
{
Usbhs *pUdp = USBHS;
//UdphsDma *pDma = &pUdp->USBHS_DEVDMA[bEndpoint];
Endpoint *pEp = &(endpoints[bEndpoint]);
Transfer *pXfr = (Transfer*)&(pEp->transfer);
//MblTransfer *pMblt = (MblTransfer*)&(pEp->transfer);
uint32_t status = USBHS_ReadEPStatus(pUdp, bEndpoint, 0xFFFFFFFF);
uint32_t type = USBHS_GetEpType(pUdp, bEndpoint);
uint32_t reqBuf[2];
USBGenericRequest *pReq = (USBGenericRequest *)reqBuf;
uint16_t wPktSize;
TRACE_DEBUG_WP("Ep%d ", bEndpoint);
/* IN packet sent */
if ( ( status & USBHS_DEVEPTISR_TXINI) && USBHS_IsEpIntEnable(pUdp, bEndpoint, USBHS_DEVEPTIMR_TXINE))
{
TRACE_DEBUG_WP("Wr ");
/* Multi-buffer-list transfer state */
if ( pEp->state == UDPHS_ENDPOINT_SENDINGM )
{
}
/* Sending state */
else if ( pEp->state == UDPHS_ENDPOINT_SENDING )
{
if (pXfr->buffered)
{
pXfr->transferred += pXfr->buffered;
pXfr->buffered = 0;
}
if((pXfr->transferred % pEp->size == 0) && ( pXfr->remaining == 0) && ( pXfr->transferred > 0)&&(pEp->sendZLP == 0))
{
pEp->sendZLP = 1; // Force ZLP transmission in total length is a multiple of endpoint size
}
if ( pXfr->buffered == 0
&& pXfr->transferred == 0
&& pXfr->remaining == 0
&& pEp->sendZLP == 0 )
{
pEp->sendZLP = 1;
}
/* End of Xfr ? */
if ( pXfr->remaining || pEp->sendZLP == 1)
{
if(pEp->sendZLP == 1)
{
// A null packet will be send, keep trace of it : Change this value only if ZLP will be send!!!
pEp->sendZLP = 2;
}
/* Transfer remaining */
TRACE_DEBUG_WP("%d ", pEp->size);
/* Send next packet */
UDPHS_WritePayload(bEndpoint, pEp->size);
USBHS_AckEpInterrupt(USBHS, 0, USBHS_DEVEPTICR_TXINIC);
}
else
{
TRACE_DEBUG_WP("l%d ", pXfr->transferred);
/* Disable interrupt on non-control EP */
if (type != USBHS_DEVEPTCFG_EPTYPE_CTRL)
{
USBHS_DisableIntEP(pUdp, bEndpoint);
}
USBHS_DisableEPIntType(pUdp, bEndpoint, USBHS_DEVEPTIDR_TXINEC);
UDPHS_EndOfTransfer(bEndpoint, USBD_STATUS_SUCCESS);
pEp->sendZLP = 0;
}
}
else
{
TRACE_DEBUG("Err Wr %d\n\r", pEp->sendZLP);
}
}
/* OUT packet received */
if ( USBHS_DEVEPTISR_RXOUTI & status )
{
TRACE_DEBUG_WP("Rd ");
/* NOT in receiving state */
if (pEp->state != UDPHS_ENDPOINT_RECEIVING)
{
/* Check if ACK received on a Control EP */
if ( (USBHS_DEVEPTCFG_EPTYPE_CTRL == type)
&& (0 == (status & USBHS_DEVEPTISR_BYCT_Msk)) )
{
TRACE_INFO_WP("Ack ");
USBHS_AckEpInterrupt(pUdp, bEndpoint, USBHS_DEVEPTICR_RXOUTIC);
UDPHS_EndOfTransfer(bEndpoint, USBD_STATUS_SUCCESS);
}
/* data has been STALLed */
else if (USBHS_DEVEPTISR_STALLEDI & status)
{
TRACE_INFO_WP("Discard ");
USBHS_AckEpInterrupt(pUdp, bEndpoint, USBHS_DEVEPTICR_RXOUTIC);
}
/* NAK the data */
else
{
TRACE_INFO_WP("Nak ");
USBHS_DisableIntEP(pUdp, bEndpoint);
}
}
/* In read state */
else
{
wPktSize = USBHS_ByteCount(pUdp, bEndpoint);
TRACE_DEBUG_WP("%d ", wPktSize);
UDPHS_ReadPayload(bEndpoint, wPktSize);
USBHS_AckEpInterrupt(pUdp, bEndpoint, USBHS_DEVEPTICR_RXOUTIC);
/* Check if transfer is finished */
if (pXfr->remaining == 0 || wPktSize < pEp->size)
{
USBHS_DisableEPIntType(pUdp, bEndpoint, USBHS_DEVEPTIDR_RXOUTEC);
/* Disable interrupt if not control EP */
if (USBHS_DEVEPTCFG_EPTYPE_CTRL != type)
{
USBHS_DisableIntEP(pUdp, bEndpoint);
}
UDPHS_EndOfTransfer(bEndpoint, USBD_STATUS_SUCCESS);
USBHS_AckEpInterrupt(pUdp, bEndpoint, USBHS_DEVEPTICR_NAKINIC);
USBHS_AckEpInterrupt(pUdp, bEndpoint, USBHS_DEVEPTICR_TXINIC);
}
}
}
/* STALL sent */
if ( USBHS_DEVEPTISR_STALLEDI & status )
{
/* Acknowledge */
USBHS_AckEpInterrupt(pUdp, bEndpoint, USBHS_DEVEPTICR_STALLEDIC);
/* ISO error */
if (type == USBHS_DEVEPTCFG_EPTYPE_ISO)
{
TRACE_WARNING("IsoE[%d]\n\r", bEndpoint);
UDPHS_EndOfTransfer(bEndpoint, USBD_STATUS_ABORTED);
}
/* If EP is not halted, clear STALL */
else
{
TRACE_WARNING("Stall[%d]\n\r", bEndpoint);
if (pEp->state != UDPHS_ENDPOINT_HALTED)
{
USBHS_DisableEPIntType(pUdp, bEndpoint, USBHS_DEVEPTIDR_STALLRQC);
}
}
}
/* SETUP packet received */
if ( USBHS_DEVEPTISR_RXSTPI & status )
{
/* 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 (pEp->state == UDPHS_ENDPOINT_RECEIVING
|| pEp->state == UDPHS_ENDPOINT_RECEIVINGM
|| pEp->state == UDPHS_ENDPOINT_SENDING
|| pEp->state == UDPHS_ENDPOINT_SENDINGM)
{
UDPHS_EndOfTransfer(bEndpoint, USBD_STATUS_SUCCESS);
}
/* ISO Err Flow */
if (type == USBHS_DEVEPTCFG_EPTYPE_ISO)
{
TRACE_WARNING("IsoFE[%d]\n\r", bEndpoint);
/* Acknowledge setup packet */
USBHS_AckEpInterrupt(pUdp, bEndpoint, USBHS_DEVEPTICR_RXSTPIC);
}
else
{
TRACE_DEBUG_WP("Stup ");
/* Copy setup */
UDPHS_ReadRequest(pReq);
/* Acknowledge setup packet */
USBHS_AckEpInterrupt(pUdp, bEndpoint, USBHS_DEVEPTICR_RXSTPIC);
/* Handler */
USBD_RequestHandler(bEndpoint, pReq);
}
}
}
#ifdef DMA
/**
* DMA Single transfer
* \param bEndpoint EP number.
* \pXfr Pointer to transfer instance.
* \dwCfg DMA Control configuration (excluding length).
*/
static inline void UDPHS_DmaSingle(uint8_t bEndpoint, Transfer *pXfr, uint32_t dwCfg)
{
Usbhs *pUdp = USBHS;
UsbhsDevdma *pUsbDma = &pUdp->USBHS_DEVDMA[bEndpoint];
/* Single transfer */
SCB_CleanInvalidateDCache();
USBHS_SetDmaBuffAdd(pUsbDma, (uint32_t)&pXfr->pData[pXfr->transferred]);
USBHS_GetDmaStatus(pUsbDma);
TRACE_DEBUG_WP("Dma[B%d:T%d] ", pXfr->buffered, pXfr->transferred);
/* DMA Configure */
USBHS_ConfigureDma(pUsbDma, 0);
USBHS_ConfigureDma(pUsbDma, (USBHS_DEVDMACONTROL_BUFF_LENGTH(pXfr->buffered) | dwCfg) );
/* Interrupt enable */
USBHS_EnableDMAIntEP(pUdp, bEndpoint);
}
/**
* Endpoint DMA interrupt handler.
* This function handles DMA interrupts.
* \param bEndpoint Index of endpoint
*/
static void UDPHS_DmaHandler(uint8_t bEndpoint)
{
Usbhs *pUdp = USBHS;
uint8_t bDmaEndpoint = bEndpoint -1;
Endpoint *pEp = &(endpoints[bEndpoint]);
Transfer *pXfr = (Transfer*)&(pEp->transfer);
uint32_t dwDmaSr;
int32_t iRemain, iXfred;
uint8_t bRc = USBD_STATUS_SUCCESS;
UsbhsDevdma *pUsbDma = &pUdp->USBHS_DEVDMA[bDmaEndpoint];
dwDmaSr = USBHS_GetDmaStatus(pUsbDma);
TRACE_DEBUG_WP("iDma%d,%x ", bDmaEndpoint, dwDmaSr);
/* Mbl transfer */
if (pEp->state == UDPHS_ENDPOINT_SENDINGM)
{
/* Not implemented */
return;
}
else if (pEp->state == UDPHS_ENDPOINT_RECEIVINGM)
{
/* Not implemented */
return;
}
/* Disable DMA interrupt to avoid receiving 2 (B_EN and TR_EN) */
pUdp->USBHS_DEVDMA[bDmaEndpoint].USBHS_DEVDMACONTROL &= ~(USBHS_DEVDMACONTROL_END_TR_EN
|USBHS_DEVDMACONTROL_END_B_EN);
SCB_CleanInvalidateDCache();
if (USBHS_DEVDMASTATUS_END_BF_ST & dwDmaSr)
{
TRACE_DEBUG_WP("EoDmaB ");
/* BUFF_COUNT holds the number of untransmitted bytes.
BUFF_COUNT is equal to zero in case of good transfer */
iRemain = (dwDmaSr & USBHS_DEVDMASTATUS_BUFF_COUNT_Msk)
>> USBHS_DEVDMASTATUS_BUFF_COUNT_Pos;
TRACE_DEBUG_WP("C%d ", iRemain);
iXfred = pXfr->buffered - iRemain;
pXfr->transferred += iXfred;
pXfr->buffered = iRemain;
pXfr->remaining -= iXfred;
TRACE_DEBUG_WP("[B%d:T%d:R%d] ", pXfr->buffered, pXfr->transferred, pXfr->remaining);
/* There is still data */
if (pXfr->remaining + pXfr->buffered > 0)
{
if (pXfr->remaining > DMA_MAX_FIFO_SIZE)
{
pXfr->buffered = DMA_MAX_FIFO_SIZE;
}
else
{
pXfr->buffered = pXfr->remaining;
}
/* Single transfer again */
UDPHS_DmaSingle(bDmaEndpoint, pXfr, USBHS_DEVDMACONTROL_END_TR_EN
| USBHS_DEVDMACONTROL_END_TR_IT
| USBHS_DEVDMACONTROL_END_B_EN
| USBHS_DEVDMACONTROL_END_BUFFIT
| USBHS_DEVDMACONTROL_CHANN_ENB);
}
}
else if (USBHS_DEVDMASTATUS_END_TR_ST & dwDmaSr)
{
TRACE_DEBUG_WP("EoDmaT ");
pXfr->transferred = pXfr->buffered -
((dwDmaSr & USBHS_DEVDMASTATUS_BUFF_COUNT_Msk)
>> USBHS_DEVDMASTATUS_BUFF_COUNT_Pos);
pXfr->remaining = 0;
TRACE_DEBUG_WP("[B%d:T%d] ", pXfr->buffered, pXfr->transferred);
}
else
{
TRACE_ERROR("UDPHS_DmaHandler: ST 0x%X\n\r", (unsigned int)dwDmaSr);
bRc = USBD_STATUS_ABORTED;
}
/* Callback */
if (pXfr->remaining == 0)
{
UDPHS_EndOfTransfer(bEndpoint, bRc);
}
}
#endif
/**
* Sends data through a USB endpoint. Sets up the transfer descriptor,
* writes one or two data payloads (depending on the number of FIFO bank
* for the endpoint) and then starts the actual transfer. The operation is
* complete when all the data has been sent.
*
* *If the size of the buffer is greater than the size of the endpoint
* (or twice the size if the endpoint has two FIFO banks), then the buffer
* must be kept allocated until the transfer is finished*. This means that
* it is not possible to declare it on the stack (i.e. as a local variable
* of a function which returns after starting a transfer).
*
* \param pEndpoint Pointer to Endpoint struct.
* \param pData Pointer to a buffer with the data to send.
* \param dLength Size of the data buffer.
* \return USBD_STATUS_SUCCESS if the transfer has been started;
* otherwise, the corresponding error status code.
*/
static inline uint8_t UDPHS_Write(uint8_t bEndpoint,
const void *pData,
uint32_t dLength)
{
Usbhs *pUdp = USBHS;
uint8_t bDmaEndpoint = bEndpoint -1;
Endpoint *pEp = &(endpoints[bEndpoint]);
Transfer *pXfr = (Transfer*)&(pEp->transfer);
/* Return if busy */
if (pEp->state != UDPHS_ENDPOINT_IDLE)
{
return USBD_STATUS_LOCKED;
}
/* Sending state */
pEp->state = UDPHS_ENDPOINT_SENDING;
TRACE_DEBUG_WP("Wr%d(%d) ", bEndpoint, dLength);
pEp->sendZLP = 0;
/* Setup transfer descriptor */
pXfr->pData = (void*) pData;
pXfr->remaining = dLength;
pXfr->buffered = 0;
pXfr->transferred = 0;
#ifdef DMA
SCB_CleanInvalidateDCache();
/* 1. DMA supported, 2. Not ZLP */
if (CHIP_USB_ENDPOINTS_DMA(bEndpoint)
&& pXfr->remaining > 0)
{
if (pXfr->remaining > DMA_MAX_FIFO_SIZE)
{
/* Transfer the max */
pXfr->buffered = DMA_MAX_FIFO_SIZE;
}
else
{
/* Good size */
pXfr->buffered = pXfr->remaining;
}
/* Single transfer */
UDPHS_DmaSingle(bDmaEndpoint, pXfr, USBHS_DEVDMACONTROL_END_B_EN
| USBHS_DEVDMACONTROL_END_BUFFIT
| USBHS_DEVDMACONTROL_CHANN_ENB);
return USBD_STATUS_SUCCESS;
}
#endif
/* Enable IT */
USBHS_EnableIntEP(pUdp, bEndpoint );
USBHS_EnableEPIntType(pUdp, bEndpoint, USBHS_DEVEPTIER_TXINES);
return USBD_STATUS_SUCCESS;
}
/**
* Sends data through a USB endpoint. Sets up the transfer descriptor list,
* writes one or two data payloads (depending on the number of FIFO bank
* for the endpoint) and then starts the actual transfer. The operation is
* complete when all the transfer buffer in the list has been sent.
*
* *If the size of the buffer is greater than the size of the endpoint
* (or twice the size if the endpoint has two FIFO banks), then the buffer
* must be kept allocated until the transfer is finished*. This means that
* it is not possible to declare it on the stack (i.e. as a local variable
* of a function which returns after starting a transfer).
*
* \param pEndpoint Pointer to Endpoint struct.
* \param pData Pointer to a buffer with the data to send.
* \param dLength Size of the data buffer.
* \return USBD_STATUS_SUCCESS if the transfer has been started;
* otherwise, the corresponding error status code.
*/
static inline uint8_t UDPHS_AddWr(uint8_t bEndpoint,
const void *pData,
uint32_t dLength)
{
Usbhs *pUdp = USBHS;
Endpoint *pEp = &(endpoints[bEndpoint]);
MblTransfer *pMbl = (MblTransfer*)&(pEp->transfer);
USBDTransferBuffer *pTx;
/* Check parameter */
if (dLength >= 0x10000)
{
return USBD_STATUS_INVALID_PARAMETER;
}
/* Data in process */
if (pEp->state > UDPHS_ENDPOINT_IDLE)
{ /* MBL transfer */
if (pMbl->transType)
{
if (pMbl->listState == MBL_FULL)
{
return USBD_STATUS_LOCKED;
}
}
else
{
return USBD_STATUS_LOCKED;
}
}
TRACE_DEBUG_WP("AddW%d(%d) ", bEndpoint, dLength);
/* Add buffer to buffer list and update index */
pTx = &(pMbl->pMbl[pMbl->inCurr]);
pTx->pBuffer = (uint8_t*)pData;
pTx->size = pTx->remaining = dLength;
pTx->transferred = pTx->buffered = 0;
/* Update input index */
if (pMbl->inCurr >= (pMbl->listSize-1)) pMbl->inCurr = 0;
else pMbl->inCurr ++;
if (pMbl->inCurr == pMbl->outCurr) pMbl->listState = MBL_FULL;
else pMbl->listState = 0;
/* Start sending when offset achieved */
if (MBL_NbBuffer(pMbl->inCurr, pMbl->outCurr, pMbl->listSize)
>= pMbl->offsetSize
&& pEp->state == UDPHS_ENDPOINT_IDLE)
{
uint8_t nbBanks = CHIP_USB_ENDPOINTS_BANKS(bEndpoint);
/* Change state */
pEp->state = UDPHS_ENDPOINT_SENDINGM;
TRACE_DEBUG_WP("StartM ");
/* Fill data into FIFO */
for (;
nbBanks && pMbl->pMbl[pMbl->inCurr].remaining;
nbBanks --)
{
UDPHS_MblWriteFifo(bEndpoint);
USBHS_RaiseEPInt(pUdp, bEndpoint, USBHS_DEVEPTIFR_TXINIS);
}
/* Enable interrupt */
USBHS_EnableIntEP(pUdp, bEndpoint);
USBHS_EnableEPIntType(pUdp, bEndpoint, USBHS_DEVEPTIER_TXINES);
}
return USBD_STATUS_SUCCESS;
}
/**
* Reads incoming data on an USB endpoint This methods sets the transfer
* descriptor and activate the endpoint interrupt. The actual transfer is
* then carried out by the endpoint interrupt handler. The Read operation
* finishes either when the buffer is full, or a short packet (inferior to
* endpoint maximum size) is received.
*
* *The buffer must be kept allocated until the transfer is finished*.
* \param bEndpoint Endpoint number.
* \param pData Pointer to a data buffer.
* \param dLength Size of the data buffer in bytes.
* \return USBD_STATUS_SUCCESS if the read operation has been started;
* otherwise, the corresponding error code.
*/
static inline uint8_t UDPHS_Read(uint8_t bEndpoint,
void *pData,
uint32_t dLength)
{
Usbhs *pUdp = USBHS;
uint8_t bDmaEndpoint = (bEndpoint-1);
Endpoint *pEp = &(endpoints[bEndpoint]);
Transfer *pXfr = (Transfer*)&(pEp->transfer);
/* Return if busy */
if (pEp->state != UDPHS_ENDPOINT_IDLE)
{
return USBD_STATUS_LOCKED;
}
/* Receiving state */
pEp->state = UDPHS_ENDPOINT_RECEIVING;
TRACE_DEBUG_WP("Rd%d(%d) ", bEndpoint, dLength);
/* Setup transfer descriptor */
pXfr->pData = (void*) pData;
pXfr->remaining = dLength;
pXfr->buffered = 0;
pXfr->transferred = 0;
#ifdef DMA
SCB_CleanInvalidateDCache();
/* If: 1. DMA supported, 2. Has data */
if (CHIP_USB_ENDPOINTS_DMA(bEndpoint)
&& pXfr->remaining > 0)
{
/* DMA XFR size adjust */
if (pXfr->remaining > DMA_MAX_FIFO_SIZE)
pXfr->buffered = DMA_MAX_FIFO_SIZE;
else
pXfr->buffered = pXfr->remaining;
/* Single transfer */
UDPHS_DmaSingle(bDmaEndpoint, pXfr, USBHS_DEVDMACONTROL_END_TR_EN
| USBHS_DEVDMACONTROL_END_TR_IT
| USBHS_DEVDMACONTROL_END_B_EN
| USBHS_DEVDMACONTROL_END_BUFFIT
| USBHS_DEVDMACONTROL_CHANN_ENB);
return USBD_STATUS_SUCCESS;
}
#endif
/* Enable IT */
USBHS_EnableIntEP(pUdp, bEndpoint);
USBHS_EnableEPIntType(pUdp, bEndpoint, USBHS_DEVEPTIER_RXOUTES);
return USBD_STATUS_SUCCESS;
}
#if 0
/**
* Reads incoming data on an USB endpoint This methods sets the transfer
* descriptor and activate the endpoint interrupt. The actual transfer is
* then carried out by the endpoint interrupt handler. The Read operation
* finishes either when the buffer is full, or a short packet (inferior to
* endpoint maximum size) is received.
*
* *The buffer must be kept allocated until the transfer is finished*.
* \param bEndpoint Endpoint number.
* \param pData Pointer to a data buffer.
* \param dLength Size of the data buffer in bytes.
* \return USBD_STATUS_SUCCESS if the read operation has been started;
* otherwise, the corresponding error code.
*/
static inline uint8_t UDPHS_AddRd(uint8_t bEndpoint,
void *pData,
uint32_t dLength)
{
return USBD_STATUS_SW_NOT_SUPPORTED;
}
#endif
/*---------------------------------------------------------------------------
* Exported functions
*---------------------------------------------------------------------------*/
/**
* USBD (UDP) interrupt handler
* Manages device resume, suspend, end of bus reset.
* Forwards endpoint events to the appropriate handler.
*/
void USBHS_Handler(void)
{
Usbhs *pUdp = USBHS;
uint32_t status, IntStatus;
uint8_t numIt;
status = USBHS_ReadIntStatus(pUdp, 0xFFFFFFFF);
IntStatus = status & USBHS_IsIntEnable(pUdp, 0xFFFFFFFF);
/* Handle all USBHS interrupts */
TRACE_DEBUG_WP("\n\r%c ", USBD_HAL_IsHighSpeed() ? 'H' : 'F');
//while( status )
{
/* SOF */
if (IntStatus & USBHS_DEVISR_SOF)
{
TRACE_DEBUG_WP("SOF ");
/* SOF handler */
/* Acknowledge interrupt */
USBHS_AckInt(pUdp, USBHS_DEVICR_SOFC);
status &= ~(uint32_t)USBHS_DEVISR_SOF;
}
/* MSOF*/
else if (IntStatus & USBHS_DEVISR_MSOF)
{
TRACE_DEBUG_WP("Mosf ");
/* Acknowledge interrupt */
USBHS_AckInt(pUdp, USBHS_DEVICR_MSOFC);
}
/* Suspend, treated last */
else if (IntStatus & USBHS_DEVISR_SUSP)
{
TRACE_WARNING_WP("Susp ");
USBHS_FreezeClock(pUdp, false);
USBHS_DisableInt(pUdp, USBHS_DEVIDR_SUSPEC);
/* Enable wakeup */
USBHS_EnableInt(pUdp, USBHS_DEVIER_WAKEUPES );
USBHS_FreezeClock(pUdp, true); // Mandatory to exit of sleep mode after a wakeup event
/* Acknowledge interrupt */
//USBHS_AckInt(pUdp, (USBHS_DEVICR_SUSPC | USBHS_DEVICR_WAKEUPC) );
USBD_SuspendHandler();
}
/* Wake up */
else if (IntStatus & USBHS_DEVISR_WAKEUP)
{
TRACE_INFO_WP("Rsm ");
USBHS_FreezeClock(pUdp, false);
while( !USBHS_ISUsableClock(pUdp) )
{
if(status & USBHS_DEVISR_SUSP)
{
break; // In case of USB state change in HS
}
}
/* Acknowledge interrupt */
/*USBHS_AckInt(pUdp, (USBHS_DEVICR_SUSPC |
USBHS_DEVICR_WAKEUPC |
USBHS_DEVICR_EORSMC) );*/
USBHS_DisableInt(pUdp, USBHS_DEVIDR_WAKEUPEC);
USBHS_EnableInt(pUdp, USBHS_DEVIER_SUSPES );
//USBHS_AckInt(pUdp, (USBHS_DEVIER_EORSMES | USBHS_DEVICR_WAKEUPC) );
}
/* Bus reset */
else if (IntStatus & USBHS_DEVISR_EORST)
{
TRACE_DEBUG_WP("EoB ");
/* Acknowledge interrupt */
USBHS_AckInt(pUdp, USBHS_DEVICR_EORSTC);
/* Flush and enable the suspend interrupt */
USBHS_AckInt(pUdp, (USBHS_DEVICR_SUSPC | USBHS_DEVICR_WAKEUPC) );
USBHS_EnableInt(pUdp, USBHS_DEVIER_SUSPES );
/* Reset handler */
USBD_ResetHandler();
}
/* Upstream resume */
else if (IntStatus & USBHS_DEVISR_UPRSM)
{
TRACE_DEBUG_WP("ExtRes ");
/* Acknowledge interrupt */
USBHS_AckInt(pUdp, USBHS_DEVICR_UPRSMC);
}
/* Endpoints */
else
{
#ifdef DMA
for (numIt = 0; numIt < NUM_IT_MAX; numIt ++)
{
if (CHIP_USB_ENDPOINTS_DMA(numIt))
{
if (IntStatus & (USBHS_DEVIMR_DMA_1 << (numIt - 1) ))
{
UDPHS_DmaHandler(numIt);
}
}
else if (IntStatus & (USBHS_DEVISR_PEP_0 << numIt))
{
UDPHS_EndpointHandler(numIt);
}
memory_sync();
}
#else
for (numIt = 0; numIt < NUM_IT_MAX; numIt ++)
{
if (IntStatus & (USBHS_DEVISR_PEP_0 << numIt))
{
UDPHS_EndpointHandler(numIt);
}
memory_sync();
}
#endif
}
/* Update interrupt status */
//status = USBHS_ReadIntStatus(pUdp, 0xFFFFFFFF);
//status &= USBHS_IsIntEnable(pUdp, 0xFFFFFFFF);
TRACE_DEBUG_WP("\n\r");
if (status)
{
TRACE_DEBUG_WP(" - ");
}
}
//NVIC_ClearPendingIRQ(USBHS_IRQn); // clear l'IRQ
memory_sync();
}
/**
* \brief Reset endpoints and disable them.
* -# Terminate transfer if there is any, with given status;
* -# Reset the endpoint & disable it.
* \param bmEPs Bitmap for endpoints to reset.
* \param bStatus Status passed to terminate transfer on endpoint.
* \param bKeepCfg 1 to keep old endpoint configuration.
* \note Use USBD_HAL_ConfigureEP() to configure and enable endpoint
if not keeping old configuration.
* \sa USBD_HAL_ConfigureEP().
*/
void USBD_HAL_ResetEPs(uint32_t bmEPs, uint8_t bStatus, uint8_t bKeepCfg)
{
Usbhs *pUdp = USBHS;
Endpoint *pEndpoint;
uint32_t tmp = bmEPs & ((1<<CHIP_USB_NUMENDPOINTS)-1);
uint8_t ep;
uint32_t epBit, epCfg;
for (ep = 0, epBit = 1; ep < CHIP_USB_NUMENDPOINTS; ep ++)
{
if (tmp & epBit)
{
/* Disable ISR */
pUdp->USBHS_DEVIDR |= (epBit << SHIFT_INTERUPT);
/* Kill pending Banks ?? */
#if 0
while(USBHS_IsBankFree(pUdp, ep) > 0)
{
USBHS_KillBank(pUdp, ep);
while(USBHS_IsBankKilled(pUdp, ep));
}
#endif
/* Reset transfer information */
pEndpoint = &(endpoints[ep]);
/* Reset endpoint state */
pEndpoint->bank = 0;
/* Endpoint configure */
epCfg = pUdp->USBHS_DEVEPTCFG[ep];
/* Reset endpoint */
// USBHS_ResetEP(pUdp, epBit);
/* Restore configure */
if (bKeepCfg)
{
pUdp->USBHS_DEVEPTCFG[ep] = epCfg;
}
else
{
pEndpoint->state = UDPHS_ENDPOINT_DISABLED;
}
/* Terminate transfer on this EP */
UDPHS_EndOfTransfer(ep, bStatus);
}
epBit <<= 1;
}
}
/**
* Cancel pending READ/WRITE
* \param bmEPs Bitmap for endpoints to reset.
* \note EP callback is invoked with USBD_STATUS_CANCELED.
*/
void USBD_HAL_CancelIo(uint32_t bmEPs)
{
Usbhs *pUdp = USBHS;
//UdphsEpt *pHwEp = NULL;
uint32_t tmp = bmEPs & ((1<<CHIP_USB_NUMENDPOINTS)-1);
uint8_t ep;
uint32_t epBit;
for (ep = 0, epBit = 1; ep < CHIP_USB_NUMENDPOINTS; ep ++)
{
if (tmp & epBit)
{
//pHwEp = &pUdp->UDPHS_EPT[ep];
/* Disable ISR */
pUdp->USBHS_DEVIDR |= (epBit << SHIFT_INTERUPT);
/* Kill pending Banks ?? */
#if 0
pHwEp->UDPHS_EPTSETSTA = UDPHS_EPTSETSTA_KILL_BANK;
pHwEp->UDPHS_EPTSETSTA = UDPHS_EPTSETSTA_KILL_BANK;
pHwEp->UDPHS_EPTSETSTA = UDPHS_EPTSETSTA_KILL_BANK;
#endif
/* Terminate transfer on this EP */
UDPHS_EndOfTransfer(ep, USBD_STATUS_CANCELED);
}
epBit <<= 1;
}
}
/**
* Configures an endpoint according to its endpoint Descriptor.
* \param pDescriptor Pointer to an endpoint descriptor.
* \return The endpoint address.
*/
uint8_t USBD_HAL_ConfigureEP(const USBEndpointDescriptor *pDescriptor)
{
Usbhs *pUdp = USBHS;
Endpoint *pEndpoint;
uint8_t bEndpoint;
uint8_t bType;
uint8_t bEndpointDir;
uint8_t bNbTrans = 1;
uint8_t bSizeEpt = 0;
uint8_t bHs = ((USBHS_GetUsbSpeed(pUdp) == USBHS_SR_SPEED_HIGH_SPEED)? true: false );
/* NULL descriptor -> Control endpoint 0 */
if (pDescriptor == 0)
{
bEndpoint = 0;
pEndpoint = &(endpoints[bEndpoint]);
bType = USBEndpointDescriptor_CONTROL;
bEndpointDir = 0;
pEndpoint->size = CHIP_USB_ENDPOINTS_MAXPACKETSIZE(0);
pEndpoint->bank = CHIP_USB_ENDPOINTS_BANKS(0);
}
/* Device descriptor -> Control endpoint 0 */
else if (pDescriptor->bDescriptorType == USBGenericDescriptor_DEVICE)
{
USBDeviceDescriptor *pDevDesc = (USBDeviceDescriptor*)pDescriptor;
bEndpoint = 0;
pEndpoint = &(endpoints[bEndpoint]);
bType = USBEndpointDescriptor_CONTROL;
bEndpointDir = 0;
pEndpoint->size =pDevDesc->bMaxPacketSize0;
pEndpoint->bank = CHIP_USB_ENDPOINTS_BANKS(0);
}
/* Endpoint descriptor */
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 = CHIP_USB_ENDPOINTS_BANKS(bEndpoint);
/* Convert descriptor value to EP configuration */
if (bHs) { /* HS Interval, *125us */
/* MPS: Bit12,11 specify NB_TRANS, as USB 2.0 Spec. */
bNbTrans = ((pEndpoint->size >> 11) & 0x3);
if(CHIP_USB_ENDPOINTS_HBW(bEndpoint))
{
if (bNbTrans == 3)
bNbTrans = 1;
else
bNbTrans ++;
}
else
{
bNbTrans = 0;
}
/* Mask, bit 10..0 is the size */
pEndpoint->size &= 0x7FF;
}
}
TRACE_DEBUG_WP("CfgE%d ", bEndpoint);
/* Abort the current transfer is the endpoint was configured and in
Write or Read state */
if( (pEndpoint->state == UDPHS_ENDPOINT_RECEIVING)
|| (pEndpoint->state == UDPHS_ENDPOINT_SENDING)
|| (pEndpoint->state == UDPHS_ENDPOINT_RECEIVINGM)
|| (pEndpoint->state == UDPHS_ENDPOINT_SENDINGM) ) {
UDPHS_EndOfTransfer(bEndpoint, USBD_STATUS_RESET);
}
pEndpoint->state = UDPHS_ENDPOINT_IDLE;
/* Configure endpoint size */
if( pEndpoint->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;
/* Configure endpoint */
if (bType == USBEndpointDescriptor_CONTROL)
{
USBHS_EnableIntEP(pUdp, bEndpoint);
}
USBHS_ConfigureEPs(pUdp, bEndpoint, bType, bEndpointDir, bSizeEpt, ((pEndpoint->bank) - 1));
USBHS_AllocateMemory(pUdp, bEndpoint);
while( (USBHS_DEVEPTISR_CFGOK & pUdp->USBHS_DEVEPTISR[bEndpoint]) == 0 ) {
/* 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", (unsigned int)pUdp->USBHS_DEVEPTCFG[bEndpoint]);
for(;;);
}
if (bType == USBEndpointDescriptor_CONTROL)
{
// enable Endpoint
USBHS_EnableEP(pUdp, bEndpoint, true);
// Enable Ep interrupt type
USBHS_EnableEPIntType(pUdp, bEndpoint, USBHS_DEVEPTIER_RXOUTES | USBHS_DEVEPTIER_RXSTPES );
// enable endpoint interrupt
USBHS_EnableIntEP(pUdp, bEndpoint);
}
else
{
#ifndef DMA
USBHS_EnableEP(pUdp, bEndpoint, true);
#else
USBHS_EnableEP(pUdp, bEndpoint, true);
if (bType == USBEndpointDescriptor_ISOCHRONOUS)
{
USBHS_SetIsoTrans(pUdp, bEndpoint, bNbTrans);
}
USBHS_AutoSwitchBankEnable(pUdp, bEndpoint, true);
#endif
}
//TRACE_DEBUG_WP("<%x,%x,%x> ", pEpt->UDPHS_EPTCFG, pEpt->UDPHS_EPTCTL, pEpt->UDPHS_EPTSTA);
return bEndpoint;
}
/**
* Set callback for a USB endpoint for transfer (read/write).
*
* \param bEP Endpoint number.
* \param fCallback Optional callback function to invoke when the transfer is
* complete.
* \param pCbData Optional pointer to data to the callback function.
* \return USBD_STATUS_SUCCESS or USBD_STATUS_LOCKED if endpoint is busy.
*/
uint8_t USBD_HAL_SetTransferCallback(uint8_t bEP,
TransferCallback fCallback,
void *pCbData)
{
Endpoint *pEndpoint = &(endpoints[bEP]);
TransferHeader *pTransfer = (TransferHeader*)&(pEndpoint->transfer);
/* Check that the endpoint is not transferring */
if (pEndpoint->state > UDPHS_ENDPOINT_IDLE) {
return USBD_STATUS_LOCKED;
}
TRACE_DEBUG_WP("sXfrCb ");
/* Setup the transfer callback and extension data */
pTransfer->fCallback = (void*)fCallback;
pTransfer->pArgument = pCbData;
return USBD_STATUS_SUCCESS;
}
/**
* Configure an endpoint to use multi-buffer-list transfer mode.
* The buffers can be added by _Read/_Write function.
* \param pMbList Pointer to a multi-buffer list used, NULL to disable MBL.
* \param mblSize Multi-buffer list size (number of buffers can be queued)
* \param startOffset When number of buffer achieve this offset transfer start
*/
uint8_t USBD_HAL_SetupMblTransfer( uint8_t bEndpoint,
USBDTransferBuffer* pMbList,
uint16_t mblSize,
uint16_t startOffset)
{
Endpoint *pEndpoint = &(endpoints[bEndpoint]);
MblTransfer *pXfr = (MblTransfer*)&(pEndpoint->transfer);
uint16_t i;
/* Check that the endpoint is not transferring */
if (pEndpoint->state > UDPHS_ENDPOINT_IDLE) {
return USBD_STATUS_LOCKED;
}
TRACE_DEBUG_WP("sMblXfr ");
/* Enable Multi-Buffer Transfer List */
if (pMbList) {
/* Reset list items */
for (i = 0; i < mblSize; i --) {
pMbList[i].pBuffer = NULL;
pMbList[i].size = 0;
pMbList[i].transferred = 0;
pMbList[i].buffered = 0;
pMbList[i].remaining = 0;
}
/* Setup transfer */
pXfr->transType = 1;
pXfr->listState = 0; /* OK */
pXfr->listSize = mblSize;
pXfr->pMbl = pMbList;
pXfr->outCurr = pXfr->outLast = 0;
pXfr->inCurr = 0;
pXfr->offsetSize = startOffset;
}
/* Disable Multi-Buffer Transfer */
else {
pXfr->transType = 0;
pXfr->pMbl = NULL;
pXfr->listSize = 0;
pXfr->offsetSize = 1;
}
return USBD_STATUS_SUCCESS;
}
/**
* Sends data through a USB endpoint. Sets up the transfer descriptor,
* writes one or two data payloads (depending on the number of FIFO bank
* for the endpoint) and then starts the actual transfer. The operation is
* complete when all the data has been sent.
*
* *If the size of the buffer is greater than the size of the endpoint
* (or twice the size if the endpoint has two FIFO banks), then the buffer
* must be kept allocated until the transfer is finished*. This means that
* it is not possible to declare it on the stack (i.e. as a local variable
* of a function which returns after starting a transfer).
*
* \param bEndpoint Endpoint number.
* \param pData Pointer to a buffer with the data to send.
* \param dLength Size of the data buffer.
* \return USBD_STATUS_SUCCESS if the transfer has been started;
* otherwise, the corresponding error status code.
*/
uint8_t USBD_HAL_Write( uint8_t bEndpoint,
const void *pData,
uint32_t dLength)
{
if (endpoints[bEndpoint].transfer.transHdr.transType)
return UDPHS_AddWr(bEndpoint, pData, dLength);
else
return UDPHS_Write(bEndpoint, pData, dLength);
}
/**
* Special write function.
* Sends data through a USB endpoint. Sets up the transfer descriptor,
* writes header and one or two data payloads (depending on the number of
* FIFO bank for the endpoint) and then starts the actual transfer. The
* operation is complete when all the data has been sent.
*
* *If the size of the buffer is greater than the size of the endpoint
* (or twice the size if the endpoint has two FIFO banks), then the buffer
* must be kept allocated until the transfer is finished*. This means that
* it is not possible to declare it on the stack (i.e. as a local variable
* of a function which returns after starting a transfer).
*
* \param bEndpoint Endpoint number.
* \param pData Pointer to a buffer with the data to send.
* \param dLength Size of the data buffer.
* \return USBD_STATUS_SUCCESS if the transfer has been started;
* otherwise, the corresponding error status code.
*/
uint8_t USBD_HAL_WrWithHdr(uint8_t bEndpoint,
const void * pHdr, uint8_t bHdrLen,
const void * pData,uint32_t dLength)
{
Usbhs *pUdp = USBHS;
Endpoint *pEp = &(endpoints[bEndpoint]);
uint8_t bDmaEndpoint = (bEndpoint-1);
Transfer *pXfr = (Transfer*)&(pEp->transfer);
/* Return if DMA is not supported */
if (!CHIP_USB_ENDPOINTS_DMA(bEndpoint))
{
return USBD_STATUS_HW_NOT_SUPPORTED;
}
#ifdef DMA
/* Return if busy */
if (pEp->state != UDPHS_ENDPOINT_IDLE)
{
return USBD_STATUS_LOCKED;
}
/* Sending state */
pEp->state = UDPHS_ENDPOINT_SENDING;
TRACE_DEBUG_WP("Wr%d(%d+%d) ", bEndpoint, bHdrLen, dLength);
pEp->sendZLP = 0;
/* Setup transfer descriptor */
pXfr->pData = (void*) pData;
pXfr->remaining = bHdrLen + dLength;
pXfr->buffered = 0;
pXfr->transferred = 0;
SCB_CleanInvalidateDCache();
/* 1. DMA supported always, 2. Not ZLP */
if (bHdrLen + dLength > 0)
{
uint8_t bNbTrans = (USBHS_GetConfigureEPs(pUdp, bEndpoint, USBHS_DEVEPTCFG_NBTRANS_Msk)
>> USBHS_DEVEPTCFG_NBTRANS_Pos);
if (pXfr->remaining > DMA_MAX_FIFO_SIZE)
{
/* Transfer the max */
pXfr->buffered = DMA_MAX_FIFO_SIZE;
}
else
{
/* Good size, total size */
pXfr->buffered = pXfr->remaining;
}
/* LD1: header - load to fifo without interrupt */
/* Header discarded if exceed the DMA FIFO length */
//if (bHdrLen > DMA_MAX_FIFO_SIZE) bHdrLen = DMA_MAX_FIFO_SIZE;
pDmaLL[0].pNxtDesc = (void*)&pDmaLL[1];
pDmaLL[0].pAddr = (void*)pHdr;
pDmaLL[0].dwCtrl = USBHS_DEVDMACONTROL_CHANN_ENB
| USBHS_DEVDMACONTROL_BUFF_LENGTH(bHdrLen)
| USBHS_DEVDMACONTROL_LDNXT_DSC;
/* High bandwidth ISO EP, max size n*ep_size */
if (bNbTrans > 1) {
uint8_t* pU8 = (uint8_t*)pData;
uint32_t maxSize = bNbTrans * pEp->size;
dLength = pXfr->buffered - bHdrLen;
if (dLength > maxSize) dLength = maxSize;
#if 0 /* Prepare banks by 1 DMA descriptor -- NK if not standard EP size, works! */
/* LD2: data - load to fifo with interrupt */
pDmaLL[1].pNxtDesc = (void*)NULL;
pDmaLL[1].pAddr = (void*)pU8;
pDmaLL[1].dwCtrl = USBHS_DEVDMACONTROL_CHANN_ENB
| USBHS_DEVDMACONTROL_BUFF_LENGTH(dLength)
| USBHS_DEVDMACONTROL_END_B_EN
| USBHS_DEVDMACONTROL_END_BUFFIT;
#else
uint32_t pktLen, ndxData = 0;
/* LD2: data - bank 0 */
pktLen = pEp->size - bHdrLen;
if (pktLen >= dLength) { /* It's the last DMA LLI */
pDmaLL[1].pNxtDesc = (void*)NULL;
pDmaLL[1].pAddr = (void*)pU8;
pDmaLL[1].dwCtrl = USBHS_DEVDMACONTROL_CHANN_ENB
| USBHS_DEVDMACONTROL_BUFF_LENGTH(dLength)
| USBHS_DEVDMACONTROL_END_B_EN
| USBHS_DEVDMACONTROL_END_BUFFIT;
}
else {
pDmaLL[1].pNxtDesc = (void*)&pDmaLL[2];
pDmaLL[1].pAddr = (void*)pU8;
pDmaLL[1].dwCtrl = USBHS_DEVDMACONTROL_CHANN_ENB
| USBHS_DEVDMACONTROL_BUFF_LENGTH(pktLen)
| USBHS_DEVDMACONTROL_END_B_EN
| USBHS_DEVDMACONTROL_LDNXT_DSC;
dLength -= pktLen; ndxData += pktLen;
/* LD3: data - bank 1 */
pktLen = pEp->size;
if (pktLen >= dLength) { /* It's the last */
pDmaLL[1].pNxtDesc = (void*) NULL;
pDmaLL[1].pAddr = (void*)&pU8[ndxData];
pDmaLL[1].dwCtrl = USBHS_DEVDMACONTROL_CHANN_ENB
| USBHS_DEVDMACONTROL_BUFF_LENGTH(dLength)
| USBHS_DEVDMACONTROL_END_B_EN
| USBHS_DEVDMACONTROL_END_BUFFIT;
}
else {
pDmaLL[2].pNxtDesc = (void*)&pDmaLL[3];
pDmaLL[2].pAddr = (void*)&pU8[ndxData];
pDmaLL[2].dwCtrl = USBHS_DEVDMACONTROL_CHANN_ENB
| USBHS_DEVDMACONTROL_BUFF_LENGTH(pktLen)
| USBHS_DEVDMACONTROL_END_B_EN
| USBHS_DEVDMACONTROL_LDNXT_DSC;
dLength -= pktLen; ndxData += pktLen;
/* LD4: data - bank 2 */
pDmaLL[3].pNxtDesc = (void*) NULL;
pDmaLL[3].pAddr = (void*)&pU8[ndxData];
pDmaLL[3].dwCtrl = USBHS_DEVDMACONTROL_CHANN_ENB
| USBHS_DEVDMACONTROL_BUFF_LENGTH(dLength)
| USBHS_DEVDMACONTROL_END_B_EN
| USBHS_DEVDMACONTROL_END_BUFFIT;
}
}
#endif
}
else { /* Normal, fill all data */
/* LD2: data - load to fifo with interrupt */
dLength = pXfr->buffered - bHdrLen;
pDmaLL[1].pNxtDesc = (void*)NULL;
pDmaLL[1].pAddr = (void*)pData;
pDmaLL[1].dwCtrl = USBHS_DEVDMACONTROL_CHANN_ENB
| USBHS_DEVDMACONTROL_BUFF_LENGTH(dLength)
| USBHS_DEVDMACONTROL_END_B_EN
| USBHS_DEVDMACONTROL_END_BUFFIT;
}
/* Interrupt enable */
pUdp->USBHS_DEVIER |= (USBHS_DEVIMR_DMA_1 << bDmaEndpoint);
/* Start transfer with LLI */
pUdp->USBHS_DEVDMA[bDmaEndpoint].USBHS_DEVDMANXTDSC = (uint32_t)pDmaLL;
pUdp->USBHS_DEVDMA[bDmaEndpoint].USBHS_DEVDMACONTROL = 0;
pUdp->USBHS_DEVDMA[bDmaEndpoint].USBHS_DEVDMACONTROL = USBHS_DEVDMACONTROL_LDNXT_DSC;
return USBD_STATUS_SUCCESS;
}
#endif
/* Enable IT */
USBHS_EnableIntEP( pUdp, bEndpoint );
USBHS_EnableEPIntType(pUdp, bEndpoint, USBHS_DEVEPTIER_TXINES);
return USBD_STATUS_SUCCESS;
}
/**
* Reads incoming data on an USB endpoint This methods sets the transfer
* descriptor and activate the endpoint interrupt. The actual transfer is
* then carried out by the endpoint interrupt handler. The Read operation
* finishes either when the buffer is full, or a short packet (inferior to
* endpoint maximum size) is received.
*
* *The buffer must be kept allocated until the transfer is finished*.
* \param bEndpoint Endpoint number.
* \param pData Pointer to a data buffer.
* \param dLength Size of the data buffer in bytes.
* \return USBD_STATUS_SUCCESS if the read operation has been started;
* otherwise, the corresponding error code.
*/
uint8_t USBD_HAL_Read(uint8_t bEndpoint,
void *pData,
uint32_t dLength)
{
if (endpoints[bEndpoint].transfer.transHdr.transType)
return USBD_STATUS_SW_NOT_SUPPORTED;
else
return UDPHS_Read(bEndpoint, pData, dLength);
}
/**
* \brief Enable Pull-up, connect.
*
* -# Enable HW access if needed
* -# Enable Pull-Up
* -# Disable HW access if needed
*/
void USBD_HAL_Connect(void)
{
// At startup the USB bus state is unknown,
// therefore the state is considered IDLE to not miss any USB event
USBHS_FreezeClock(USBHS, false);
// Authorize attach
USBHS_DetachUsb(USBHS, false);
// (RESET_AND_WAKEUP)
// After the attach and the first USB suspend, the following USB Reset time can be inferior to CPU restart clock time.
// Thus, the USB Reset state is not detected and endpoint control is not allocated
// In this case, a Reset is do automatically after attach.
USBD_HAL_ConfigureEP(0);
// Enable USB line events
USBHS_EnableInt(USBHS, (USBHS_DEVIER_EORSTES | USBHS_DEVIER_WAKEUPES | USBHS_DEVIER_SUSPES | USBHS_DEVIER_SOFES) );
#ifdef USB_DEVICE_HS_SUPPORT
USBHS_EnableInt(USBHS, USBHS_DEVIER_MSOFES);
#endif
// Reset following interrupts flag
USBHS_AckInt(USBHS, ( USBHS_DEVICR_EORSTC | USBHS_DEVICR_SOFC | USBHS_DEVICR_MSOFC ) );
// The first suspend interrupt is not detected else raise it
USBHS_RaiseInt(USBHS, USBHS_DEVIFR_SUSPS);
USBHS_AckInt(USBHS, USBHS_DEVICR_WAKEUPC);
USBHS_FreezeClock(USBHS, true);
}
/**
* \brief Disable Pull-up, disconnect.
*
* -# Enable HW access if needed
* -# Disable PULL-Up
* -# Disable HW access if needed
*/
void USBD_HAL_Disconnect(void)
{
USBHS_FreezeClock(USBHS, ENABLE);
// Detach device from the bus
USBHS_DetachUsb(USBHS, true);
}
/**
* Starts a remote wake-up procedure.
*/
void USBD_HAL_RemoteWakeUp(void)
{
Usbhs *pUdp = USBHS;
TRACE_INFO_WP("RWUp ");
/* Activates a remote wakeup (edge on ESR), then clear ESR */
USBHS_SetRemoteWakeUp(pUdp);
while(pUdp->USBHS_DEVCTRL & USBHS_DEVCTRL_RMWKUP);
{
TRACE_DEBUG_WP("w");
}
}
/**
* Sets the device address to the given value.
* \param address New device address.
*/
void USBD_HAL_SetAddress(uint8_t address)
{
Usbhs *pUdp = USBHS;
if (address)
{
USBHS_SetAddress(pUdp, address);
}
else
{
USBHS_EnableAddress(pUdp, false);
}
}
/**
* Sets the current device configuration.
* \param cfgnum - Configuration number to set.
*/
void USBD_HAL_SetConfiguration(uint8_t cfgnum)
{
/* Nothing to do now */
cfgnum = cfgnum;
}
/**
* Initializes the USB HW Access driver.
*/
void USBD_HAL_Init(void)
{
#ifdef DMA
/* DMA Link list should be 16-bytes aligned */
if ((uint32_t)dmaLL & 0xFFFFFFF0)
pDmaLL = (UdphsDmaDescriptor*)((uint32_t)&dmaLL[1] & 0xFFFFFFF0);
else
pDmaLL = (UdphsDmaDescriptor*)((uint32_t)&dmaLL[0]);
#endif
/** Disable USB hardware */
USBHS_UsbEnable(USBHS, false);
USBHS_UsbMode(USBHS, DEVICE_MODE);
/** Enable USB hardware*/
USBHS_UsbEnable(USBHS, true);
USBHS_FreezeClock(USBHS, false);
if(ForceFS)
{
USBHS_EnableHighSpeed(USBHS, false);
}
else
{
USBHS_EnableHighSpeed(USBHS, true);
}
/* Check USB clock */
while( !USBHS_ISUsableClock(USBHS) );
USBHS_FreezeClock(USBHS, true);
/* Clear IRQ */
NVIC_ClearPendingIRQ(USBHS_IRQn);
/* IRQ */
NVIC_EnableIRQ(USBHS_IRQn) ;
}
/**
* Causes the given endpoint to acknowledge the next packet it receives
* with a STALL handshake except setup request.
* \param bEP Endpoint number.
* \return USBD_STATUS_SUCCESS or USBD_STATUS_LOCKED.
*/
uint8_t USBD_HAL_Stall(uint8_t bEP)
{
Usbhs *pUdp = USBHS;
Endpoint *pEndpoint = &(endpoints[bEP]);
/* Check that endpoint is in Idle state */
if (pEndpoint->state != UDPHS_ENDPOINT_IDLE)
{
TRACE_WARNING("UDP_Stall: EP%d locked\n\r", bEP);
return USBD_STATUS_LOCKED;
}
/* STALL endpoint */
USBHS_EnableEPIntType(pUdp, bEP, USBHS_DEVEPTIER_STALLRQS);
TRACE_INFO_WP("Stall%d ", bEP);
return USBD_STATUS_SUCCESS;
}
/**
* Sets/Clear/Get the HALT state on the endpoint.
* In HALT state, the endpoint should keep stalling any packet.
* \param bEndpoint Endpoint number.
* \param ctl Control code CLR/HALT/READ.
* 0: Clear HALT state;
* 1: Set HALT state;
* .: Return HALT status.
* \return USBD_STATUS_INVALID_PARAMETER if endpoint not exist,
* otherwise endpoint halt status.
*/
uint8_t USBD_HAL_Halt(uint8_t bEndpoint, uint8_t ctl)
{
Usbhs *pUdp = USBHS;
Endpoint *pEndpoint = &(endpoints[bEndpoint]);
uint8_t bDmaEndpoint = (bEndpoint-1);
uint8_t status = 0;
/* SET Halt */
if (ctl == 1)
{
/* Check that endpoint is enabled and not already in Halt state */
if ((pEndpoint->state != UDPHS_ENDPOINT_DISABLED)
&& (pEndpoint->state != UDPHS_ENDPOINT_HALTED))
{
TRACE_INFO_WP("Halt%d ", bEndpoint);
/* Abort the current transfer if necessary */
UDPHS_EndOfTransfer(bEndpoint, USBD_STATUS_ABORTED);
/* Put endpoint into Halt state */
pEndpoint->state = UDPHS_ENDPOINT_HALTED;
memory_sync();
//SCB_CleanInvalidateDCache();
while(!USBHS_IsBankFree(pUdp, bEndpoint))
{
USBHS_KillBank(pUdp, bEndpoint);
while(USBHS_IsBankKilled(pUdp, bEndpoint));
}
if(USBHS_IsBankFree(pUdp, bEndpoint))
{
USBHS_AutoSwitchBankEnable(pUdp, bEndpoint, false);
USBHS_EnableEPIntType(pUdp, bEndpoint, (USBHS_DEVEPTIER_STALLRQS | USBHS_DEVEPTIER_RSTDTS) );
}
else
{
USBHS_EnableEPIntType(pUdp, bEndpoint, USBHS_DEVEPTIER_NBUSYBKES );
#ifdef DMA
if (CHIP_USB_ENDPOINTS_DMA(bDmaEndpoint))
{
/* Enable the endpoint DMA interrupt */
USBHS_EnableDMAIntEP(pUdp, bDmaEndpoint);
}
else
{
/* Enable the endpoint interrupt */
USBHS_EnableIntEP( pUdp, bEndpoint );
}
#else
/* Enable the endpoint interrupt */
USBHS_EnableIntEP( pUdp, bEndpoint );
#endif
}
}
}
/* CLEAR Halt */
else if (ctl == 0)
{
/* Check if the endpoint is halted */
if ((pEndpoint->state == UDPHS_ENDPOINT_HALTED) || (USBHS_IsEpIntEnable(pUdp, bEndpoint, USBHS_DEVEPTIMR_STALLRQ)) )
{
TRACE_INFO_WP("Unhalt%d ", bEndpoint);
/* Return endpoint to Idle state */
pEndpoint->state = UDPHS_ENDPOINT_IDLE;
/* Clear FORCESTALL flag */
USBHS_DisableEPIntType(pUdp, bEndpoint, USBHS_DEVEPTIDR_STALLRQC);
USBHS_AutoSwitchBankEnable(pUdp, bEndpoint, true);
}
}
/* Return Halt status */
if (pEndpoint->state == UDPHS_ENDPOINT_HALTED)
{
status = 1;
}
return( status );
}
/**
* Indicates if the device is running in high or full-speed. Always returns 0
* since UDP does not support high-speed mode.
*/
uint8_t USBD_HAL_IsHighSpeed(void)
{
Usbhs *pUdp = USBHS;
uint32_t tmp = USBHS_GetUsbSpeed(pUdp);
return ((tmp & USBHS_SR_SPEED_HIGH_SPEED) >> USBHS_SR_SPEED_Pos) ;
}
/**
* Suspend USB Device HW Interface
*
* -# Disable transceiver
* -# Disable USB Clock
* -# Disable USB Peripheral
*/
void USBD_HAL_Suspend(void)
{
/* The device enters the Suspended state */
USBHS_FreezeClock(USBHS, ENABLE);
}
/**
* Activate USB Device HW Interface
* -# Enable USB Peripheral
* -# Enable USB Clock
* -# Enable transceiver
*/
void USBD_HAL_Activate(void)
{
USBHS_FreezeClock(USBHS, DISABLE);
}
void USBD_HAL_Disable(void)
{
//** Disable USB hardware
USBHS_UsbEnable(USBHS, false);
/* Clear IRQ */
NVIC_ClearPendingIRQ(USBHS_IRQn);
/* IRQ */
NVIC_DisableIRQ(USBHS_IRQn) ;
}
/**
* Certification test for High Speed device.
* \param bIndex Test to be done
*/
void USBD_HAL_Test( uint8_t bIndex )
{
Usbhs *pUdp = USBHS;
uint8_t *pFifo;
uint32_t i;
/* remove suspend for TEST */
USBHS_DisableInt(pUdp, USBHS_DEVIDR_SUSPEC);
/* force High Speed (remove suspend) */
pUdp->USBHS_DEVCTRL |= USBHS_DEVCTRL_SPDCONF_HIGH_SPEED;
USBHS_EnableTestMode(pUdp, USBHS_DEVCTRL_OPMODE2);
switch( bIndex ) {
case USBFeatureRequest_TESTPACKET:
TRACE_DEBUG_WP("TEST_PACKET ");
pUdp->USBHS_DEVDMA[1].USBHS_DEVDMACONTROL = 0;
pUdp->USBHS_DEVDMA[2].USBHS_DEVDMACONTROL = 0;
/* Configure endpoint 2, 64 bytes, direction IN, type BULK, 1 bank */
pUdp->USBHS_DEVEPTCFG[2]= USBHS_DEVEPTCFG_EPSIZE_64_BYTE
| USBHS_DEVEPTCFG_EPDIR
| USBHS_DEVEPTCFG_EPTYPE_BLK
| USBHS_DEVEPTCFG_EPBK_1_BANK;
USBHS_AllocateMemory(pUdp, 2);
while( (USBHS_DEVEPTISR_CFGOK & pUdp->USBHS_DEVEPTISR[2]) != USBHS_DEVEPTISR_CFGOK);
USBHS_EnableEP(pUdp, 2, true);
/* Write FIFO */
pFifo = (uint8_t*)((uint32_t *)(USBHS_RAM_ADDR) + (EPT_VIRTUAL_SIZE * 2));
for( i=0; i<sizeof(test_packet_buffer); i++) {
pFifo[i] = test_packet_buffer[i];
}
/* Tst PACKET */
USBHS_EnableTestMode(pUdp, USBHS_DEVCTRL_TSTPCKT);
/* Send packet */
USBHS_RaiseEPInt(pUdp, 2, USBHS_DEVEPTIFR_TXINIS);
break;
case USBFeatureRequest_TESTJ:
TRACE_DEBUG_WP("TEST_J ");
USBHS_EnableTestMode(pUdp, USBHS_DEVCTRL_TSTJ);
break;
case USBFeatureRequest_TESTK:
TRACE_DEBUG_WP("TEST_K ");
USBHS_EnableTestMode(pUdp, USBHS_DEVCTRL_TSTK);
break;
case USBFeatureRequest_TESTSE0NAK:
TRACE_DEBUG_WP("TEST_SEO_NAK ");
USBHS_DisableInt(pUdp, 0xFFFFFFFF); // for test
break;
case USBFeatureRequest_TESTSENDZLP:
USBHS_RaiseEPInt(pUdp, 0, USBHS_DEVEPTIFR_TXINIS);
TRACE_DEBUG_WP("SEND_ZLP ");
break;
}
TRACE_DEBUG_WP("\n\r");
}
/**@}*/