📄 bvd_udc_hw.c
字号:
* ServiceEP0
*
* Services End Point 0. This has been changed to a state machine in order
* to make the handling of the PXA250 UDC easier. The UDC has an internal
* state machine and can get out of sync with the driver. By implementing
* a state machine, this makes the process of keeping in sync with the UDC
* much easier.
*
* This routine gets invoked as a result of a line interrupt being report
* by the SA_USB_GetInterruptType routine.
*-----------------------------------------------------------------------------*/
int nResets = 0; // limits tracebuffer to cover no more than three resets.
void ServiceEP0( PSER_INFO pHWHead, PDWORD pModemStatus )
{
int nLoopCount = 0;
DWORD udc_cr; //udc_csrA, udc_csrB;
UDCTrace( pHWHead, UDCT_EP0, UDC_STATE( pHWHead ));
UDCTrace( pHWHead, UDCT_UDCCS0_STATE, UDC_CSR0( pHWHead ));
// Service EP0 Packet Complete intr
// This clears the IR0_0 interrupt due to IPR.
// This does not clear the IR0_0 interrupt due to OPR.
if (UDC_ISR0(pHWHead) & XLLP_UDC_UDCISR0_IR0_0)
{
UDCTrace( pHWHead, 0xbc04, UDC_ISR0(pHWHead) );
UDCTrace( pHWHead, 0xbc04, UDC_CSR0(pHWHead) );
UDC_ISR0_CLEAR_ENDPOINT_INTR( UDC_ISR0(pHWHead), XLLP_UDC_UDCISR0_IR0_0);
}
// Deal with EP0 FIFO error intr
if (UDC_ISR0(pHWHead) & XLLP_UDC_UDCISR0_IR0_1)
{
//NKDbgPrintfW(TEXT("!!! EP0 FIFO error\r\n"));
UDCTrace( pHWHead, 0xbc05, UDC_ISR0(pHWHead) );
UDCTrace( pHWHead, 0xbc05, UDC_CSR0(pHWHead) );
UDC_ISR0_CLEAR_ENDPOINT_INTR( UDC_ISR0(pHWHead), XLLP_UDC_UDCISR0_IR0_1);
}
if (UDC_ISR1(pHWHead) & XLLP_UDC_UDCISR1_IRCC)
{
/*
// bpc stuff: special code to reset the trace buffer after every three resets:
++nResets;
if( nResets >= 4 )
{
nResets = 0;
g_pTraceBuffer[0] = 4; // this resets the trace buffer.
// now add the trace entries back in that we just lost.
UDCTrace( pHWHead, 0xbca6, UDC_ISR1(pHWHead) );
}
else
{
UDCTrace( pHWHead, 0xbc06, UDC_ISR1(pHWHead) );
}
*/
CLEAR_CONFIG_CHANGE_INTR(UDC_ISR1(pHWHead));
UDC_STATE( pHWHead ) = WAIT_FOR_IN_STATUS;
// Save the configuration index into our state structure.
udc_cr = UDC_CR(pHWHead);
pHWHead->dConfIdx = (BYTE) ((udc_cr & 0x1800)>>11);
//RETAILMSG( 1, (TEXT("***Set Config: UDC_CR: %X\r\n"), udc_cr ));
//RETAILMSG( 1, (TEXT("***Setting SMAC\r\n")));
//Set SMAC
UDCCR_SMAC_SET( UDC_CR(pHWHead) );
//udc_csrA = UDC_CSR_A(pHWHead);
//udc_csrB = UDC_CSR_B(pHWHead);
//RETAILMSG( 1, (TEXT("UDC_CSR_A: %X\r\n"), udc_csrA));
//RETAILMSG( 1, (TEXT("UDC_CSR_B: %X\r\n"), udc_csrB));
UDC_STATE(pHWHead) = WAIT_FOR_SETUP;
goto SEP0_10; // if fall through, will process previous setup command.
}
DEBUGMSG( ZONE_USB,(TEXT("ServiceEP0: State=%d\r\n"), UDC_STATE( pHWHead )));
// Check for missing status interrupt
if( UDC_CSR0( pHWHead ) & XLLP_UDC_UDCCSR0_SA )
UDC_STATE(pHWHead) = WAIT_FOR_SETUP;
if( UDC_CSR0( pHWHead ) == 0x81 )
{
UDCTrace( pHWHead, 0xbc07, UDC_CSR0(pHWHead) );
DEBUGMSG( ZONE_ERROR,(TEXT("!!! STATUS = 81\r\n")));
//NKDbgPrintfW(TEXT("!!! STATUS = 81\r\n"));
}
else if ( UDC_CSR0( pHWHead ) == 0x2 )
{
UDCTrace( pHWHead, 0xbc18, UDC_CSR0(pHWHead) ); // out of order bcxx number 'cause of typo
//RETAILMSG( 1 ,(TEXT("!!! UDC_CSR0 == 2\r\n")));
//NKDbgPrintfW(TEXT("!!! !!! UDC_CSR0 == 2\r\n"));
}
switch( UDC_STATE(pHWHead)) {
case WAIT_FOR_SETUP:
// This indicates we should be processing a setup packet.
UDCTrace( pHWHead, 0xbc08, UDC_CSR0(pHWHead) );
ProcessEP0Setup( pHWHead, pModemStatus );
UDCTrace( pHWHead, 0xbc88, UDC_CSR0(pHWHead) );
break;
case DATA_STATE_XMIT:
// Transmit the next data packet for EP0
//RETAILMSG( 1 ,(TEXT("!!! Data State xmit!!!")));
UDCTrace( pHWHead, 0xbc09, UDC_CSR0(pHWHead) );
XmitEP0Data( pHWHead );
UDCTrace( pHWHead, 0xbc89, UDC_CSR0(pHWHead) );
break;
case DATA_STATE_RCVR:
// Receive the next data packet
UDCTrace( pHWHead, 0xbc0a, UDC_CSR0(pHWHead) );
ASSERT(0);
UDCTrace( pHWHead, 0xbc8a, UDC_CSR0(pHWHead) );
break;
case WAIT_FOR_OUT_STATUS:
// Process the OUT status state
UDCTrace( pHWHead, 0xbc0b, UDC_CSR0(pHWHead) );
ProcessEP0OutStatus( pHWHead );
UDCTrace( pHWHead, 0xbc8b, UDC_CSR0(pHWHead) );
break;
case WAIT_FOR_IN_STATUS:
// Process in IN status state
UDCTrace( pHWHead, 0xbc0c, UDC_CSR0(pHWHead) );
ProcessEP0InStatus( pHWHead );
UDCTrace( pHWHead, 0xbc8c, UDC_CSR0(pHWHead) );
//ASSERT(0);
break;
default:
UDCTrace( pHWHead, 0xbc0d, UDC_CSR0(pHWHead) );
ASSERT(0);
UDCTrace( pHWHead, 0xbc8d, UDC_CSR0(pHWHead) );
break;
}
// No need to clear the IR0 interrupt.
// UDC_ISR0_CLEAR_ENDPOINT_INTR( UDC_ISR0(pHWHead), XLLP_UDC_UDCISR0_IR0_0);
SEP0_10:
UDCTrace( pHWHead, 0xbc0f, UDC_CSR0(pHWHead) );
UDCTrace( pHWHead, UDCT_INTR, UDC_ISR0(pHWHead));
}
/*----------------------------------------------------------------------
* SA_USB_GetInterruptType
*
* Determine the source of an interrupt and return flags to control which
* function gets called to handle it. EP0 is handled as modem interrupt, EP1
* as TX, EP2 as RX and reset is handled as line interrupt.
*/
INTERRUPT_TYPE SA_USB_GetInterruptType( PSER_INFO pHWHead)
{
unsigned long udc_isr0_copy, udc_isr1_copy;
INTERRUPT_TYPE interruptFlags = 0;
udcStats.usbIntCount++;
udc_isr0_copy = UDC_ISR0( pHWHead ) ;
udc_isr1_copy = UDC_ISR1( pHWHead ) ;
DEBUGMSG( ZONE_INT,
(TEXT("+SA_USB_GetInterruptType: udc_isr0=%X udc_isr1=%X\r\n"), udc_isr0_copy, udc_isr1_copy));
UDCTrace( pHWHead, UDCT_INTR, udc_isr0_copy );
UDCTrace( pHWHead, UDCT_INTR, ( udc_isr1_copy & 0xffff0000 ) | ( pHWHead->pINTCRegs->ichp & 0x0000ffff ) );
/*
* If Reset received...
*/
if (udc_isr1_copy & XLLP_UDC_UDCISR1_IRRS)
interruptFlags |= INTR_LINE; /* We use INTR_LINE to handle USB Reset */
/*
* If Reset received...
*/
if (udc_isr1_copy & XLLP_UDC_UDCISR1_IRCC)
{
interruptFlags |= INTR_MODEM; /* We use INTR_MODEM for Config change intr */
//RETAILMSG( 1 ,(TEXT("!!! Config Change Intr\r\n")));
}
/*
* Setup command received. Model as modem interrupt.
*/
if ((udc_isr0_copy & XLLP_UDC_UDCISR0_IR0_0) || (udc_isr0_copy & XLLP_UDC_UDCISR0_IR0_1))
interruptFlags |= INTR_MODEM; /* Use INTR_MODEM for EP0 interrupts */
/*
* If Bulk In (transmit) interrupt ...
*/
if ((udc_isr0_copy & XLLP_UDC_UDCISR0_IRA_0) || (udc_isr0_copy & XLLP_UDC_UDCISR0_IRA_1))
{ interruptFlags |= INTR_TX;
}
/*
* If Bulk Out (receive) interrupt ...
*/
if ((udc_isr0_copy & XLLP_UDC_UDCISR0_IRB_0) || (udc_isr0_copy & XLLP_UDC_UDCISR0_IRB_1))
{ interruptFlags |= INTR_RX;
}
return (interruptFlags);
}
/*
* SA_USB_LineIntHandler
*
* This handler is called for reset interrupts
*/
void SA_USB_LineIntHandler(PSER_INFO pHWHead)
{
//NKDbgPrintfW(TEXT("SA_USB_LineIntHandler\r\n"));
if (1 == (pHWHead->UDC_Reset))
{
pHWHead->UDC_Reset = 0;
//Disable UDC Soft Connect
//pHWHead->pBCRReg->MISCWR2 |= XLLP_BCR_MISCWR2_NUSBC_SC;
pHWHead->ModemStatus &= ~MS_RLSD_ON;
EvaluateEventFlag(pHWHead->pMddHead, EV_RLSD);
//Timeout
WaitForSingleObject(pHWHead->hSerialEvent, pHWHead->UDC_ResetTimeOut);
//Enable UDC Soft Connect
//pHWHead->pBCRReg->MISCWR2 &= ~XLLP_BCR_MISCWR2_NUSBC_SC;
}
//Clear the interrupt request bit
CLEAR_RESET_INTR( UDC_ISR1(pHWHead) );
}
/*
* SA_USB_RxIntHandler
*
* Read characters up to the max packet length from the IN FIFO. Return the
* number of characters read in the supplied argument. The function returns
* a boolean indicating whether event characters are present.
*/
BOOL SA_USB_RxIntHandler(PSER_INFO pHWHead,
PUCHAR pRxBuffer,
ULONG *pBufflen)
{
BOOL fRXFlag = FALSE;
UCHAR cEvtChar = pHWHead->dcb.EvtChar;
//UCHAR cRxChar;
//UCHAR *pRxByte;
ULONG *pRxWord = (unsigned long*) pRxBuffer;
volatile ULONG buflen = *pBufflen;
volatile unsigned int bytes_to_read =0, word_count, byte_count; // temp_byte_count;
volatile DWORD dw_udc_csr_b; // dw_udc_cr_b;
PBYTE pData;
//int nIndex;
unsigned long rx_word1;
volatile BYTE *pEP_B_FIFO;
static UCHAR RxPacket[EP1Len];
static unsigned int RxPacketLen=0, RxPacketIndex=0;
//ULONG LineEvents = 0;
DEBUGMSG(ZONE_READ, (TEXT("RX Buff Len = %d \r\n"), buflen));
//RETAILMSG(1, (TEXT("RX: %X\r\n"), buflen));
//g_pBLReg->hex_led = 0xFFFFA001;
*pBufflen = 0;
pEP_B_FIFO = (volatile BYTE *) &(UDC_DR_B( pHWHead ));
UDCTrace( pHWHead, UDCT_UDC_ISR0, UDC_ISR0(pHWHead) );
// To do: Deal with EPB FIFO error intr
// Deal with EPB FIFO error intr
if (UDC_ISR0(pHWHead) & XLLP_UDC_UDCISR0_IRB_1)
{
//NKDbgPrintfW(TEXT("****!!! EPB FIFO error\r\n"));
UDC_ISR0_CLEAR_ENDPOINT_INTR( UDC_ISR0(pHWHead), XLLP_UDC_UDCISR0_IRB_1);
}
// Clear Interrupt
UDC_ISR0_CLEAR_ENDPOINT_INTR( UDC_ISR0(pHWHead), XLLP_UDC_UDCISR0_IRB_0);
UDCTrace( pHWHead, UDCT_UDC_ISR0, UDC_ISR0(pHWHead) );
// Is RPC set.
dw_udc_csr_b = UDC_CSR_B( pHWHead );
UDCTrace( pHWHead, UDCT_RX_INT, dw_udc_csr_b );
//pData = pRxBuffer; //pTxBuffer; //lastPacket
//nIndex=0;
if (RxPacketLen)
{
//NKDbgPrintfW(TEXT("***RX: Copy %X\r\n"), RxPacketLen);
if(buflen >= RxPacketLen)
{
memcpy(pRxBuffer, RxPacket + RxPacketIndex, RxPacketLen);
pRxBuffer += RxPacketLen;
(*pBufflen) += RxPacketLen;
buflen-= RxPacketLen;
RxPacketIndex=0;
RxPacketLen -= RxPacketLen;
//RETAILMSG(1, (TEXT("***RX: Copied %X\r\n"), buflen));
}
else
{
//NKDbgPrintfW(TEXT("***RX: Not copied%d\r\n"), buflen);
}
}
if((dw_udc_csr_b & XLLP_UDC_UDCCSR_PC) == 0 )
{
UDCTrace( pHWHead, UDCT_NO_RPC, dw_udc_csr_b );
udcStats.noRPC++;
//RETAILMSG( 1, (TEXT("***Rx: PC=0 UDC_CSR_B: %X\r\n"), dw_udc_csr_b));
// Clear Interrupt
//UDC_ISR0_CLEAR_ENDPOINT_INTR( UDC_ISR0(pHWHead), XLLP_UDC_UDCISR0_IRB_0);
//UDCTrace( pHWHead, UDCT_RX_INTR_DONE, UDC_CSR_B( pHWHead ));
//UDCTrace( pHWHead, UDCT_RX_DATA, *pBufflen );
//return fRXFlag;
}
else if ((dw_udc_csr_b & XLLP_UDC_UDCCSR_SP) && ((dw_udc_csr_b & XLLP_UDC_UDCCSR_BNE_BNF) == 0))
{
// Clear the PC bit
UDCCSR_MWRITE(UDC_CSR_B( pHWHead), XLLP_UDC_UDCCSR_PC);
// Clear Interrupt
UDC_ISR0_CLEAR_ENDPOINT_INTR( UDC_ISR0(pHWHead), XLLP_UDC_UDCISR0_IRB_0);
//RETAILMSG( 1, (TEXT("********Rx: ZLP received UDC_CSR_B: %X\r\n"), dw_udc_csr_b));
UDCTrace( pHWHead, UDCT_INTR, UDC_ISR0(pHWHead) );
UDCTrace( pHWHead, UDCT_RX_INTR_DONE, UDC_CSR_B( pHWHead ));
UDCTrace( pHWHead, UDCT_RX_DATA, *pBufflen );
return fRXFlag;
}
else
{
//
// Read the bytes from the FIFO and return the actual number read.
//
//pData = pRxBuffer;
pData = RxPacket;
RxPacketLen=0;
RxPacketIndex =0;
do
{
bytes_to_read = UDC_BCR_B(pHWHead);
word_count = bytes_to_read/4;
byte_count = bytes_to_read%4;
if (buflen >= bytes_to_read)
{
pData = pRxBuffer;
}
else
{
pData = (RxPacket + RxPacketIndex + RxPacketLen); //pData = RxPacket;
}
if (UDC_CSR_B( pHWHead ) & XLLP_UDC_UDCCSR_BNE_BNF )
{
if (word_count)
{
while (word_count)
{
rx_word1 = UDC_DR_B( pHWHead );
//pRxWord[0] = rx_word1;
//pRxWord++;
pData[0] = (BYTE) (rx_word1 & 0xFF);
pData[1] = (BYTE) ((rx_word1>>8) & 0xFF);
pData[2] = (BYTE) ((rx_word1>>16) & 0xFF);
pData[3] = (BYTE) ((rx_word1>>24) & 0xFF);
//RETAILMSG( 1, (TEXT("Rx: %x %x %x %x\r\n"), pData[0], pData[1], pData[2], pData[3]));
// if((pData[0] == cEvtChar) || (pData[1] == cEvtChar) || (pData[2] == cEvtChar) || (pData[3] == cEvtChar))
// fRXFlag = TRUE;
pData +=4;
RxPacketLen +=4;
word_count--;
}
}
if (byte_count)
{
//temp_byte_count = byte_count;
rx_word1 = UDC_DR_B( pHWHead );
//while (temp_byte_count)
//{
// pData[0] = (BYTE) (rx_word1 & 0xFF);
//ch1 = (BYTE) (rx_word1 & 0xFF);
//pData[0] = ch1;
// if (pData[0] == cEvtChar)
// fRXFlag = TRUE ;
// pData++;
// rx_word1 = (rx_word1>>8);
// temp_byte_count--;
//}
if (byte_count == 1)
{
pData[0] = (BYTE) (rx_word1 & 0xFF);
// if (pData[0] == cEvtChar)
// fRXFlag = TRUE ;
}
else if (byte_count == 2)
{
pData[0] = (BYTE) (rx_word1 & 0xFF);
pData[1] = (BYTE) ((rx_word1>>8) & 0xFF);
// if ((pData[0] == cEvtChar) || (pData[1] == cEvtChar))
// fRXFlag = TRUE ;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -