📄 bvd_udc_hw.c
字号:
UDCTrace( pHWHead, 0xbcc5, UDC_CSR0(pHWHead) );
UDCTrace( pHWHead, 0xbcc5, UDC_ISR0(pHWHead) );
UDCTrace( pHWHead, 0xbcc5, UDC_ISR1(pHWHead) );
UDC_STATE( pHWHead ) = WAIT_FOR_OUT_STATUS;
}
else
if( !nXferCount )
{
UDCTrace( pHWHead, 0xbcc6, UDC_CSR0(pHWHead) );
UDCTrace( pHWHead, 0xbcc6, UDC_ISR0(pHWHead) );
UDCTrace( pHWHead, 0xbcc6, UDC_ISR1(pHWHead) );
UDC_STATE( pHWHead ) = WAIT_FOR_OUT_STATUS;
}
}
/*----------------------------------------------------------------------------
* ParseSetup
*
* Parse through the setup command and perform actions based upon the
* requests. The caller has already read the data from the FIFO and placed
* into the serial info structure.
*----------------------------------------------------------------------------*/
BOOL ParseSetup( PSER_INFO pHWHead, PDWORD pModemStatus )
{
BOOL bErr = FALSE;
PUCHAR p;
WORD wLen, wTotLen = 0;
static int count = 0;
//DWORD udc_cr, udc_csrA, udc_csrB;
DEBUGMSG( ZONE_USB,
(TEXT("bmRequest: %02x bRequest: %02x wValue: %04x wIndex: %04x wLength: %04x\n"),
pHWHead->dReq.bmRequest,
pHWHead->dReq.bRequest,
pHWHead->dReq.wValue,
pHWHead->dReq.wIndex,
pHWHead->dReq.wLength));
UDCTrace( pHWHead, UDCT_PARSE_SETUP, (pHWHead->dReq.bmRequest |((DWORD) pHWHead->dReq.bRequest) << 8 | ((DWORD) pHWHead->dReq.wValue) << 16 ));
/*
* Decode and execute the command. We support two sets of commands, vendor
* specific (modem control) and chapter 9 standard commands.
*/
if (pHWHead->dReq.bmRequest & 0x60)
{
// vendor or class command
DEBUGMSG( ZONE_USB, (TEXT("Vendor/Class Command !!\n")));
if ( SET_CONTROL_LINE_STATE == pHWHead->dReq.bRequest )
{
/*
* Modem Control command
*
* Host is notifying us of control line state.
* wValue contains bitmask
* 0 - DTR
* 1 - RTS
*/
DEBUGMSG( ZONE_USB, (TEXT("SET_CONTROL_LINE_STATE %4.4X\r\n"),
pHWHead->dReq.wValue));
if (pHWHead->dReq.wValue & 0x01)
*pModemStatus |= (MS_DSR_ON|MS_RLSD_ON); // DTR active, set DSR/RLSD
else
*pModemStatus &= ~(MS_DSR_ON|MS_RLSD_ON); // DTR clear, clr DSR/RLSD
if (pHWHead->dReq.wValue & 0x02)
*pModemStatus |= MS_CTS_ON; // RTS active, set CTS
else
*pModemStatus &= ~MS_CTS_ON; // RTS clear, clear CTS
UDCTrace( pHWHead, UDCT_VENDOR_MODEM_CMD, pHWHead->dReq.bRequest);
// Set IPR bit for a EP0 No Data Vendor command.
// This tells UDC to send ZLP on IN Status.
// Software does not see the IN Status.
UDC_CSR0_MWRITE( UDC_CSR0(pHWHead), XLLP_UDC_UDCCSR0_IPR );
UDC_STATE( pHWHead ) = WAIT_FOR_IN_STATUS;
}
else
{
/*
* Unknown vendor/class request
*/
DEBUGMSG( ZONE_ERROR|ZONE_USB,
(TEXT("Unknown vendor/class request %2.2X\r\n"),
pHWHead->dReq.bRequest));
}
/*
* Vendor or Class command is complete
*/
return FALSE;
}
/*
* Standard chapter 9 commands
*/
switch (pHWHead->dReq.bRequest) {
case GET_DESCRIPTOR:
switch ((BYTE)(pHWHead->dReq.wValue>>8))
{
case DEVICE:
DEBUGMSG( ZONE_INIT|ZONE_USB,
(TEXT("GET_DESCRIPTOR:DEVICE 0x%X, 0x%X\r\n"),
uStd[0],
pHWHead->dReq.wLength));
p = (PUCHAR)uStd;
wLen = (BYTE)min(uStd[0],pHWHead->dReq.wLength);
wTotLen = uStd[0];
break;
case CONFIGURATION:
DEBUGMSG( ZONE_INIT|ZONE_USB,
(TEXT("GET_DESCRIPTOR:CONFIGURATION\r\n")));
p = (PUCHAR)&uStd[iCONF];
wLen = (BYTE)min(CFGLEN,pHWHead->dReq.wLength);
wTotLen = CFGLEN;
break;
case STRING:
DEBUGMSG( ZONE_INIT|ZONE_USB,
(TEXT("GET_DESCRIPTOR:STRING\r\n")));
UsbRequestGetStringDescriptor((XLLP_UINT16_T)pHWHead->dReq.wValue,
(P_XLLP_UINT8_T*)&p,
(P_XLLP_UINT8_T) &wTotLen);
wLen = (BYTE)min(wTotLen,pHWHead->dReq.wLength);
break;
default:
DEBUGMSG( ZONE_INIT|ZONE_USB|ZONE_ERROR,
(TEXT("GET_DESCRIPTOR:Unknown %d\r\n"),
(pHWHead->dReq.wValue>>8) ));
p = NULL;
wLen = 0;
wTotLen = 0;
break;
}
// Is there data to send?
if( wLen )
{
// Setup the pointers in the HW structure and then
// call to have the data transfer initiated.
pHWHead->pXmitData = p;
pHWHead->nXmitIndex = 0;
pHWHead->nXmitLength = (int) wLen;
pHWHead->nXmitReq = (int) pHWHead->dReq.wLength;
count = (int) pHWHead->dReq.wLength;
// Send IN Data
XmitEP0Data( pHWHead );
}
break;
case SET_CONFIG:
DEBUGMSG( ZONE_INIT | ZONE_USB,
(TEXT("Set Configuration: Configuration = %d\r\n"), pHWHead->dReq.wValue ));
// Save the configuration index into our state structure.
pHWHead->dConfIdx = (BYTE)pHWHead->dReq.wValue;
UDC_STATE( pHWHead ) = WAIT_FOR_IN_STATUS;
//Set SMAC
UDCCR_SMAC_SET( UDC_CR(pHWHead) );
break;
case SET_ADDRESS:
//Not passed to software
DEBUGMSG( ZONE_INIT | ZONE_USB,
(TEXT("Set Address: Address = %d\r\n"), pHWHead->dReq.wValue ));
//RETAILMSG( 1,
// (TEXT("Set Address: Address = %d\r\n"), pHWHead->dReq.wValue ));
pHWHead->dAddress = (BYTE) pHWHead->dReq.wValue;
break;
case GET_STATUS:
//Not passed to software
DEBUGMSG( ZONE_INIT|ZONE_USB, (TEXT("GET_STATUS\r\n")));
//NKDbgPrintfW(TEXT("GET_STATUS\r\n"));
break;
case SET_DESCRIPTOR:
DEBUGMSG( ZONE_ERROR|ZONE_USB, (TEXT("SET_DESCRIPTOR\r\n")));
//NKDbgPrintfW(TEXT("SET_DESCRIPTOR\r\n"));
break;
case GET_INTERFACE:
//Not passed to software
DEBUGMSG( ZONE_ERROR|ZONE_USB, (TEXT("GET_INTERFACE\r\n")));
//NKDbgPrintfW(TEXT("GET_INTERFACE\r\n"));
break;
case GET_CONFIG:
//Not passed to software
DEBUGMSG( ZONE_ERROR|ZONE_USB, (TEXT("GET_CONFIGURATION\r\n")));
//NKDbgPrintfW(TEXT("GET_CONFIGURATION\r\n"));
break;
case SET_INTERFACE:
DEBUGMSG( ZONE_INIT|ZONE_USB, (TEXT("SET_INTERFACE : %d,%d\r\n"),
pHWHead->dReq.wIndex, pHWHead->dReq.wValue));
//NKDbgPrintfW(TEXT("SET_INTERFACE : %d,%d\r\n"),
// pHWHead->dReq.wIndex, pHWHead->dReq.wValue);
//Cotulla UDC stalls on a non-zero alternate setting!
pHWHead->dInterface = (BYTE) pHWHead->dReq.wIndex;
pHWHead->dSetting = (BYTE) pHWHead->dReq.wValue;
UDC_STATE( pHWHead ) = WAIT_FOR_IN_STATUS;
break;
case CLEAR_FEATURE:
//Not passed to software
DEBUGMSG( ZONE_INIT|ZONE_USB, (TEXT("CLEAR_FEATURE\r\n")));
//NKDbgPrintfW(TEXT("CLEAR_FEATURE\r\n"));
/*
* Request to the endpoint (Clear Halt)
*/
if (pHWHead->dReq.bmRequest == 0x02)
{
/*
* Switch on endpoint number (wIndex)
*/
switch (pHWHead->dReq.wIndex & 0xF)
{
case 0:
/*
* Control endpoint. Not suggested.
*/
break;
case 1:
/*
* IN endpoint. Clear SST and FST to reset DATA0/DATA1.
*/
//UDCCS1_FST_CLR (pHWHead->pUDCRegs->udccs1);
//UDCCS1_MWRITE (pHWHead->pUDCRegs->udccs1, USB_UDCCS1_SST);
break;
case 2:
/*
* OUT endpoint. Clear SST and FST to reset DATA0/DATA1.
*/
//UDCCS2_FST_CLR (pHWHead->pUDCRegs->udccs2);
//UDCCS2_MWRITE (pHWHead->pUDCRegs->udccs2, USB_UDCCS2_SST);
break;
}
}
break;
case SET_FEATURE:
//Not passed to software
//NKDbgPrintfW(TEXT("SET_FEATURE\r\n"));
DEBUGMSG( ZONE_INIT|ZONE_USB,
(TEXT("SET_FEATURE %d\r\n"),
pHWHead->dReq.bmRequest));
if (pHWHead->dReq.bmRequest == 0x02)
{
switch (pHWHead->dReq.wIndex & 15)
{
case 0:
/*
* Control endpoint. Not suggested.
*/
break;
case 1:
/*
* IN endpoint. Set FST to force stall condition
*/
//UDCCS1_MWRITE(pHWHead->pUDCRegs->udccs1, USB_UDCCS1_FST);
break;
case 2:
/*
* OUT endpoint. Set FST to force stall condition
*/
//UDCCS2_MWRITE(pHWHead->pUDCRegs->udccs2, USB_UDCCS2_FST);
break;
}
}
break;
default:
DEBUGMSG( ZONE_ERROR|ZONE_USB,
(TEXT("Unhandled Command : %d\r\n"),
pHWHead->dReq.bRequest));
//NKDbgPrintfW(TEXT("Unhandled Command : %d\r\n"), pHWHead->dReq.bRequest);
// Unknown command received.
bErr = TRUE;
break;
}
return bErr;
}
/*----------------------------------------------------------------------------
* ProcessEP0Setup
*
* Process a setup packet for Endpoint 0.
*----------------------------------------------------------------------------*/
void ProcessEP0Setup( PSER_INFO pHWHead, PDWORD pdwModemStatus )
{
// Make sure that everything is correct to read the setup packet from
// the FIFO's
DEBUGMSG( ZONE_USB,(TEXT("ProcessEP0Setup: UDCCS0=%X\r\n"), UDC_CSR0( pHWHead )));
if((UDC_CSR0( pHWHead ) & (XLLP_UDC_UDCCSR0_SA | XLLP_UDC_UDCCSR0_OPR | XLLP_UDC_UDCCSR0_RNE)) ==
(XLLP_UDC_UDCCSR0_SA | XLLP_UDC_UDCCSR0_OPR | XLLP_UDC_UDCCSR0_RNE)) {
UDCTrace( pHWHead, UDCT_SETUP, UDC_CSR0( pHWHead ));
// Setup packet is available. Read it from the FIFO's
if (getCommand(pHWHead, (void*)&pHWHead->dReq) != 0) {
// Failed to properly get the data from the FIFO's.
// Force a STALL condition.
UDC_CSR0_MWRITE( UDC_CSR0(pHWHead), XLLP_UDC_UDCCSR0_FST );
// UDC_CSR0_FST_SET (pHWHead->pUDCRegs->UDC_CSR0);
ASSERT(0);
}
}
//Workaround for 0x81 condition
else if ((UDC_CSR0( pHWHead ) & (XLLP_UDC_UDCCSR0_SA | XLLP_UDC_UDCCSR0_OPR | XLLP_UDC_UDCCSR0_RNE)) ==
(XLLP_UDC_UDCCSR0_SA | XLLP_UDC_UDCCSR0_OPR)) {
UDCTrace( pHWHead, UDCT_SETUP, UDC_CSR0( pHWHead ));
//NKDbgPrintfW(TEXT("!!! STATUS = 81 handled\r\n"));
// Setup packet is available. Read it from the FIFO.
if (getCommandEightBytes(pHWHead, (void*)&pHWHead->dReq) != 0)
{
// Failed to properly get the data from the FIFO's.
// Force a STALL condition.
UDC_CSR0_MWRITE( UDC_CSR0(pHWHead), XLLP_UDC_UDCCSR0_FST );
ASSERT(0);
}
}
//Log clearing the OPR and SA bits.
UDCTrace( pHWHead, UDCT_UDCCS0, (XLLP_UDC_UDCCSR0_OPR | XLLP_UDC_UDCCSR0_SA));
// The next two steps should be done atomically to guarantee
// that IR0 bit reflects correct status of another OUT/IN pkt!
// Clear the OPR and SA bits.
UDC_CSR0_MWRITE( UDC_CSR0(pHWHead), (XLLP_UDC_UDCCSR0_OPR | XLLP_UDC_UDCCSR0_SA));
// This clears the IR0_0 interrupt due to OPR.
// bpc stuff: this was already done at entry to ServiceEP0: UDC_ISR0_CLEAR_ENDPOINT_INTR( UDC_ISR0(pHWHead), XLLP_UDC_UDCISR0_IR0_0);
// UDC_ISR0_CLEAR_ENDPOINT_INTR( UDC_ISR0(pHWHead), XLLP_UDC_UDCISR0_IR0_0);
// Process the setup command. This routine will parse
// the setup command and possibly call the xmit EP0 routine
// to start the transfer of the descriptor back to the host.
// The state will be updated by the routine.
if( ParseSetup( pHWHead, pdwModemStatus )) {
// Parsing of the setup failed. Force a STALL and
// then go back to IDLE state.
UDC_CSR0_MWRITE( UDC_CSR0(pHWHead), XLLP_UDC_UDCCSR0_FST );
ASSERT(0);
}
}
/*----------------------------------------------------------------------------
* ProcessEP0OutStatus
*
* Called to handle the condition where the state machine was waiting for
* a OUT status.
*----------------------------------------------------------------------------*/
void ProcessEP0OutStatus( PSER_INFO pHWHead )
{
// Make sure the OPR bit is set and SA and RNE are not set.
if((UDC_CSR0( pHWHead ) & (XLLP_UDC_UDCCSR0_OPR | XLLP_UDC_UDCCSR0_SA)) == XLLP_UDC_UDCCSR0_OPR ) {
// Out status was received. Turn off OPR and move to wait for setup
UDCTrace( pHWHead, UDCT_STATUS_OUT, UDC_CSR0( pHWHead ));
// The next two steps should be done atomically to guarantee
// that IR0 bit reflects correct status of another OUT/IN pkt!
// Clear the OPR bit.
UDC_CSR0_MWRITE( UDC_CSR0(pHWHead), XLLP_UDC_UDCCSR0_OPR );
// Clear the IR0_0 interrupt due to OPR.
UDC_ISR0_CLEAR_ENDPOINT_INTR( UDC_ISR0(pHWHead), XLLP_UDC_UDCISR0_IR0_0);
UDC_STATE( pHWHead ) = WAIT_FOR_SETUP;
}
else if (0 == UDC_CSR0( pHWHead ))
{
// IN Data has been sent out.
// STATUS Stage has not been received yet.
UDCTrace( pHWHead, UDCT_STATUS_OUT_MISSED, UDC_CSR0( pHWHead ));
// NKDbgPrintfW(TEXT("IN Data sent out : %X\r\n"), UDC_CSR0( pHWHead ));
}
else
{
//RETAILMSG( 1, (TEXT("????EP0 Out Status: UDC_CSR0= %x\r\n"), UDC_CSR0( pHWHead ) ));
//We should not be here.
//ASSERT(0);
UDC_STATE( pHWHead ) = WAIT_FOR_SETUP;
}
}
/*----------------------------------------------------------------------------
* ProcessEP0InStatus
*
* Called to handle condition where the state machine is waiting for an
* in status.
*----------------------------------------------------------------------------*/
void ProcessEP0InStatus( PSER_INFO pHWHead )
{
//ASSERT( 0 );
//For Standard Chapter 9 EP0 No data commands,
//we should not be here as UDC handles them automatically.
UDC_CSR0_MWRITE( UDC_CSR0(pHWHead), XLLP_UDC_UDCCSR0_IPR );
UDC_STATE( pHWHead ) = WAIT_FOR_SETUP;
UDCTrace( pHWHead, UDCT_UDCCS0, XLLP_UDC_UDCCSR0_IPR );
}
/*----------------------------------------------------------------------------
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -