📄 usbd_udphs.c
字号:
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;
}
}
//------------------------------------------------------------------------------
// Function: UDP_IsTransferFinished
// Checks if an ongoing transfer on an endpoint has been completed.
// Parameters:
// bEndpoint - Endpoint number.
// Returns:
// 1 if the current transfer on the given endpoint is complete; otherwise
// 0
//------------------------------------------------------------------------------
static unsigned char UDPHS_IsTransferFinished( unsigned char bEndpoint )
{
Endpoint *pEndpoint = &(endpoints[bEndpoint]);
Transfer *pTransfer = &(pEndpoint->transfer);
// Check if it is a Control endpoint
// -> Control endpoint must always finish their transfer with a zero-length
// packet
if( AT91C_UDPHS_EPT_TYPE_CTL_EPT ==
(AT91C_UDPHS_EPT_TYPE&(AT91C_BASE_UDPHS->UDPHS_EPT[bEndpoint].UDPHS_EPTCFG)) ) {
return (pTransfer->buffered < pEndpoint->size);
}
// Other endpoints only need to transfer all the data
else {
return( (pTransfer->buffered <= pEndpoint->size) && (pTransfer->remaining == 0) );
}
}
//------------------------------------------------------------------------------
// Endpoint interrupt handler.
// Handle IN/OUT transfers, received SETUP packets and STALLing
// 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_LOG(trace_DEBUG, "E%d ", bEndpoint);
// 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_LOG(trace_DEBUG, "Wr ");
// Check that endpoint was in Sending state
if( pEndpoint->state == UDP_ENDPOINT_SENDING ) {
// End of transfer ?
if( UDPHS_IsTransferFinished(bEndpoint) ) {
trace_LOG(trace_DEBUG, "%d ", pTransfer->transferred);
pTransfer->transferred += pTransfer->buffered;
pTransfer->buffered = 0;
// 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)) ) {
#ifndef DMA
AT91C_BASE_UDPHS->UDPHS_IEN &= ~(1<<SHIFT_INTERUPT<<bEndpoint);
#else
AT91C_BASE_UDPHS->UDPHS_IEN &= ~(1<<SHIFT_DMA<<bEndpoint);
#endif
}
AT91C_BASE_UDPHS->UDPHS_EPT[bEndpoint].UDPHS_EPTCTLDIS = AT91C_UDPHS_TX_PK_RDY;
UDPHS_EndOfTransfer(bEndpoint, USBD_STATUS_SUCCESS);
}
else {
// Transfer remaining data
trace_LOG(trace_DEBUG, "%d ", pEndpoint->size);
pTransfer->transferred += pEndpoint->size;
pTransfer->buffered -= pEndpoint->size;
// Send next packet
UDPHS_WritePayload(bEndpoint);
AT91C_BASE_UDPHS->UDPHS_EPT[bEndpoint].UDPHS_EPTSETSTA = AT91C_UDPHS_TX_PK_RDY;
}
}
else {
trace_LOG(trace_FATAL, "Error Wr");
}
}
// OUT packet received
if( AT91C_UDPHS_RX_BK_RDY == (status & AT91C_UDPHS_RX_BK_RDY) ) {
trace_LOG(trace_DEBUG, "Rd ");
// Check that the endpoint is in Receiving state
if (pEndpoint->state != UDP_ENDPOINT_RECEIVING) {
// Endpoint is NOT in Read state
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_LOG(trace_DEBUG, "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_LOG(trace_DEBUG, "Discard ");
UDPHS_ClearRxFlag(bEndpoint);
}
// NAK the data
else {
trace_LOG(trace_DEBUG, "Nak ");
#ifndef DMA
AT91C_BASE_UDPHS->UDPHS_IEN &= ~(1<<SHIFT_INTERUPT<<bEndpoint);
#else
AT91C_BASE_UDPHS->UDPHS_IEN &= ~(1<<SHIFT_DMA<<bEndpoint);
#endif
}
}
else {
// Endpoint is in Read state
// Retrieve data and store it into the current transfer buffer
wPacketSize = (unsigned short)((status & AT91C_UDPHS_BYTE_COUNT)>>20);
trace_LOG(trace_DEBUG, "%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)) ) {
#ifndef DMA
AT91C_BASE_UDPHS->UDPHS_IEN &= ~(1<<SHIFT_INTERUPT<<bEndpoint);
#else
AT91C_BASE_UDPHS->UDPHS_IEN &= ~(1<<SHIFT_DMA<<bEndpoint);
#endif
}
UDPHS_EndOfTransfer(bEndpoint, USBD_STATUS_SUCCESS);
}
}
}
// STALL sent
if( AT91C_UDPHS_STALL_SNT == (status & AT91C_UDPHS_STALL_SNT) ) {
trace_LOG(trace_WARNING, "Sta 0x%X [%d] ", status, bEndpoint);
// Acknowledge the stall flag
AT91C_BASE_UDPHS->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_LOG(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_LOG(trace_DEBUG, "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
//----------------------------------------------------------------------------
// \fn UDPHS_DmaHandler
// \brief This function (ISR) handles dma interrupts
//----------------------------------------------------------------------------
static void UDPHS_DmaHandler( unsigned char bEndpoint )
{
Endpoint *pEndpoint = &(endpoints[bEndpoint]);
Transfer *pTransfer = &(pEndpoint->transfer);
unsigned int status;
unsigned char result = USBD_STATUS_SUCCESS;
status = AT91C_BASE_UDPHS->UDPHS_DMA[bEndpoint].UDPHS_DMASTATUS;
trace_LOG(trace_DEBUG, "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_LOG(trace_DEBUG, "EndBuffer ");
// BUFF_COUNT holds the number of untransmitted bytes.
// BUFF_COUNT is equal to zero in case of good transfer
pTransfer->transferred = pTransfer->buffered
- ((status & AT91C_UDPHS_BUFF_COUNT) >> 16);
pTransfer->buffered = ((status & AT91C_UDPHS_BUFF_COUNT) >> 16);
pTransfer->remaining -= pTransfer->transferred;
trace_LOG(trace_DEBUG, "\n\rR:%d ", pTransfer->remaining );
trace_LOG(trace_DEBUG, "B:%d ", pTransfer->buffered );
trace_LOG(trace_DEBUG, "T:%d ", pTransfer->transferred );
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->buffered));
// 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_LOG(trace_DEBUG, "EndTransf ");
pTransfer->transferred = pTransfer->buffered
- ((status & AT91C_UDPHS_BUFF_COUNT) >> 16);
pTransfer->remaining = 0;
trace_LOG(trace_DEBUG, "\n\rR:%d ", pTransfer->remaining );
trace_LOG(trace_DEBUG, "B:%d ", pTransfer->buffered );
trace_LOG(trace_DEBUG, "T:%d ", pTransfer->transferred );
}
else {
trace_LOG(trace_ERROR, "UDPHS_DmaHandler: Error (0x%08X)\n\r", status);
result = USBD_STATUS_ABORTED;
}
// Invoke callback
if( pTransfer->remaining == 0 ) {
trace_LOG(trace_DEBUG, "EOT ");
UDPHS_EndOfTransfer(bEndpoint, result);
}
}
#endif
//------------------------------------------------------------------------------
// Exported functions
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
// UDP interrupt handler
// Manages device resume, suspend, end of bus reset. Forwards endpoint
// interrupts to the appropriate handler.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -