📄 sc2413pdd.cpp-ori
字号:
)
{
SETFNAME();
FUNCTION_ENTER_MSG();
ValidateContext(pContext);
DEBUGCHK(pContext->fRunning);
BOOL fNotify = FALSE;
DWORD dwPendingEvents=0;
EP_STATUS *peps = GetEpStatus(pContext, dwEndpoint);
PREFAST_DEBUGCHK(peps);
LOCK_ENDPOINT(peps);
DWORD dwEndPoint = peps->dwEndPointNumber;
if (dwEndpoint == 0){
BYTE bEP0IrqStatus = ReadIndexedReg(pContext, 0, EP0_CSR_REG_OFFSET);
// The Setup Token is handled in HandleUSBEvents()
// Handle End Of Status Packet (Zero Length Data
// Packet
// Note that the SETUP TOKEN is decoded in Ufn_Read to
// determine if a GET_ or SET_ command is coming. That decoding
// sets the initial State Machine State to
// EP0_STATE_OUT_DATA_PHASE or EP0_STATE_IN_DATA_PHASE
DWORD bWordCount = ReadIndexedReg(pContext, dwEndpoint, OUT_FIFO_CNT1_REG_OFFSET);
switch(peps->dwEpState) {
case EP0_STATE_OUT_DATA_PHASE:
// Check For out packet read && receive fifo not empty -> out token event
if ( (bEP0IrqStatus & EP0_OUT_PACKET_RDY) && (bWordCount) ){
DEBUGMSG(ZONE_RECEIVE, (_T("%s out token packet on endpoint 0 \r\n"), pszFname));
dwPendingEvents |= OUT_TRANSFER;
}
// status stage of control transfer; zero-length packet received
else if ( (bEP0IrqStatus & EP0_OUT_PACKET_RDY) && ( bWordCount == 0) ){
DEBUGMSG(ZONE_RECEIVE, (_T("%s status stage of control transfer on endpoint 0; UDCCS0 = 0x%x \r\n"), pszFname, bEP0IrqStatus));
// clear OPR by writing a 1 to SO bit
peps->dwEpState = EP_STATE_IDLE;
SetClearIndexedReg(pContext,0,EP0_CSR_REG_OFFSET, DATA_END | SERVICED_OUT_PKY_RDY,SET); // 050827
// SetClearIndexedReg(pContext,0,EP0_CSR_REG_OFFSET, SERVICED_OUT_PKY_RDY,SET);
}
break;
// IN Data Phase and IPR is cleared
case EP0_STATE_IN_DATA_PHASE:
// Check For status stage - End control transfer; zero-length packet received
if ( (bEP0IrqStatus & EP0_OUT_PACKET_RDY) && ( bWordCount == 0) ) {
dwPendingEvents = IN_TRANSFER;
DEBUGMSG(ZONE_SEND, (_T("%s In - end xfer; UDCCS0 = 0x%x \r\n"), pszFname, bEP0IrqStatus));
}
else if ((bEP0IrqStatus & EP0_IN_PACKET_RDY) == 0) {
dwPendingEvents = IN_TRANSFER;
}
DEBUGMSG(ZONE_SEND, (_T("%s Data Phase In Token\r\n"), pszFname));
break;
default: // EP_STATE_IDLE
// During Normal ACK/NAK This State should never happen but it will
// Force the State Machine into a known State if it does
// RETAILMSG(1, (TEXT("<EP_STATE_IDLE(0x%x)>"), peps->dwEpState));
peps->dwEpState = EP_STATE_IDLE;
DEBUGMSG(ZONE_FUNCTION, (_T("%s EP0 Status = %x \r\n"),
pszFname, bEP0IrqStatus ));
break;
}
DEBUGMSG(ZONE_FUNCTION, (_T("%s EP State = %u \r\n"), pszFname, peps->dwEpState ));
DEBUGMSG(ZONE_FUNCTION, (_T("%s HE EP0 Status = %x,%u \r\n"), pszFname, bEP0IrqStatus, peps->dwEpState ));
}
else { // Any endpoint other than 0
BYTE bEpIrqStat;
if (peps->dwDirectionAssigned == USB_IN_TRANSFER){
bEpIrqStat = ReadIndexedReg(pContext, dwEndPoint,IN_CSR1_REG_OFFSET);
DEBUGMSG(ZONE_FUNCTION, (_T("%s HE EPIN Status = %x\r\n"), pszFname, bEpIrqStat));
// Stall "acknowledged" from Host
if (bEpIrqStat & IN_SENT_STALL)
{
RETAILMSG(1, (TEXT("[ISS]")));
USB_DEVICE_REQUEST udr;
udr.bmRequestType = USB_REQUEST_FOR_ENDPOINT;
udr.bRequest =USB_REQUEST_CLEAR_FEATURE;
udr.wValue = USB_FEATURE_ENDPOINT_STALL;
udr.wIndex = USB_ENDPOINT_DIRECTION_MASK | (BYTE) dwEndpoint;
udr.wLength =0;
DisableEndpointInterrupt(pContext, dwEndpoint);
DEBUGMSG(ZONE_PIPE, (_T("%s Got SST EP%u \r\n"),
pszFname, dwEndpoint));
pContext->pfnNotify(pContext->pvMddContext, UFN_MSG_SETUP_PACKET, (DWORD) &udr);
// Must Clear both Send and Sent Stall
SetClearIndexedReg(pContext, dwEndpoint, IN_CSR1_REG_OFFSET, (IN_SEND_STALL), SET);
// SetClearIndexedReg(pContext, dwEndpoint, IN_CSR1_REG_OFFSET, (IN_SEND_STALL | IN_SENT_STALL), CLEAR);
}
if (!(bEpIrqStat & IN_PACKET_READY)) {// If Transmit Complete
// send another
DEBUGMSG(ZONE_SEND, (_T("%s transmit packet complete on endpoint %u \r\n"),
pszFname, dwEndpoint));
dwPendingEvents = IN_TRANSFER;
}
DEBUGMSG(ZONE_FUNCTION, (_T("%s End EPIn Status = %x \r\n"),
pszFname, bEpIrqStat));
}
else {
bEpIrqStat = ReadIndexedReg(pContext, dwEndPoint, OUT_CSR1_REG_OFFSET);
// Stall "acknowledged" from Host
if (bEpIrqStat & OUT_SENT_STALL) {
RETAILMSG(1, (TEXT("[OSS]")));
USB_DEVICE_REQUEST udr;
udr.bmRequestType = USB_REQUEST_FOR_ENDPOINT;
udr.bRequest =USB_REQUEST_CLEAR_FEATURE;
udr.wValue = USB_FEATURE_ENDPOINT_STALL;
udr.wIndex = (BYTE) dwEndpoint;
udr.wLength =0;
DisableEndpointInterrupt(pContext, dwEndpoint);
DEBUGMSG(ZONE_FUNCTION, (_T("%s Got SST EP%u \r\n"), pszFname, dwEndpoint));
pContext->pfnNotify(pContext->pvMddContext, UFN_MSG_SETUP_PACKET, (DWORD) &udr);
SetClearIndexedReg(pContext, dwEndpoint, OUT_CSR1_REG_OFFSET, (OUT_SEND_STALL | OUT_SENT_STALL), CLEAR);
}
// receive packet complete && receive fifo not empty -> out token + data rx event
if (bEpIrqStat & OUT_PACKET_READY) {
DEBUGMSG(ZONE_RECEIVE, (_T("%s received packet complete on endpoint %u \r\n"),
pszFname, dwEndpoint ));
// the UDC combines the OUT token event with the Data RX event
dwPendingEvents = OUT_TRANSFER;
}
DEBUGMSG(ZONE_FUNCTION, (_T("%s End EPOut Status = %x \r\n"),
pszFname, bEpIrqStat ));
}
}
if (dwPendingEvents & IN_TRANSFER) {
// RETAILMSG(1,(TEXT("PI "))); // 050828
HandleTx(pContext, peps, 0);
}
else if (dwPendingEvents & OUT_TRANSFER) {
// RETAILMSG(1,(TEXT("PO "))); // 050828
HandleRx(pContext, peps);
}
FUNCTION_LEAVE_MSG();
UNLOCK_ENDPOINT(peps);
}
// Process a SC2413 interrupt.
static
VOID
HandleUSBEvent(
PCTRLR_PDD_CONTEXT pContext
)
{
SETFNAME();
FUNCTION_ENTER_MSG();
ValidateContext(pContext);
EP_STATUS *peps = GetEpStatus(pContext, 0);
BYTE bEpIrqStat = ReadReg(pContext, EP_INT_REG_OFFSET);
BYTE bUSBBusIrqStat = ReadReg(pContext, USB_INT_REG_OFFSET);
#if RNDIS==1
// static BYTE EP0_OUT_MORE_DATA = FALSE;
static USHORT EP0_TOTAL_OUT_LEN = 0;
#endif
// RETAILMSG(1,(TEXT("%x "),bEpIrqStat)); // 050828
#if 0
RETAILMSG(1, (TEXT("%x,%x\n"),ReadReg(pContext, USB_INT_REG_OFFSET),ReadReg(pContext, USB_INT_EN_REG_OFFSET)));
RETAILMSG(1, (TEXT("%x,%x\n"),ReadReg(pContext, IDXADDR_REG_OFFSET),ReadReg(pContext, EP0_CSR_REG_OFFSET)));
RETAILMSG(1, (TEXT("%x,%x\n"),ReadReg(pContext, IN_CSR1_REG_OFFSET),ReadReg(pContext, IN_CSR2_REG_OFFSET)));
RETAILMSG(1, (TEXT("%x,%x\n"),ReadReg(pContext, OUT_CSR1_REG_OFFSET),ReadReg(pContext, OUT_CSR2_REG_OFFSET)));
RETAILMSG(1, (TEXT("%x,%x\n\n"),ReadReg(pContext, OUT_FIFO_CNT1_REG_OFFSET),ReadReg(pContext,OUT_FIFO_CNT2_REG_OFFSET)));
#endif
if (bUSBBusIrqStat & USB_SUSPEND_INTR) {
//RETAILMSG(1, (TEXT("USB_SUSPEND_INTR \r\n")));
WriteReg(pContext, USB_INT_REG_OFFSET, USB_SUSPEND_INTR);
SetClearReg(pContext, PWR_REG_OFFSET, SUSPEND_MODE_ENABLE_CTRL, CLEAR);
// Disable the interrupt
SetClearReg(pContext, USB_INT_EN_REG_OFFSET, USB_SUSPEND_INTR, CLEAR);
// Enable resume interrupt
// SetClearReg(pContext, USB_INT_EN_REG_OFFSET, USB_RESET_INTR, CLEAR); // 050827
if (pContext->attachedState == UFN_ATTACH) {
RETAILMSG(1, (_T("Suspend\r\n")));
pContext->pfnNotify(pContext->pvMddContext, UFN_MSG_BUS_EVENTS, UFN_SUSPEND);
g_wCurrentState = UFN_SUSPEND;
}
}
else if ( (g_wCurrentState == UFN_SUSPEND && bUSBBusIrqStat & USB_RESET_INTR) || (bUSBBusIrqStat & USB_RESUME_INTR) ) {
RETAILMSG(1, (TEXT("USB_RESUME_INTR:0x%x,0x%x \r\n"),bUSBBusIrqStat,g_wCurrentState)); // 050827
if ( bUSBBusIrqStat & USB_RESUME_INTR )
WriteReg(pContext, USB_INT_REG_OFFSET, USB_RESUME_INTR);
// if ( bUSBBusIrqStat & USB_RESET_INTR )
// WriteReg(pContext, USB_INT_REG_OFFSET, USB_RESET_INTR);
// Disable the interrupt
// SetClearReg(pContext, USB_INT_EN_REG_OFFSET, USB_RESUME_INTR, CLEAR);
// Enable suspend interrupt
SetClearReg(pContext, USB_INT_EN_REG_OFFSET, USB_SUSPEND_INTR, SET);
if (pContext->attachedState == UFN_ATTACH) {
RETAILMSG(1, (_T("Resume\r\n")));
pContext->pfnNotify(pContext->pvMddContext, UFN_MSG_BUS_EVENTS, UFN_RESUME);
g_wCurrentState = UFN_RESUME; // 050827
}
}
else if (bUSBBusIrqStat & USB_RESET_INTR) {
RETAILMSG(1, (TEXT("USB_RESET_INTR \r\n")));
#if RNDIS==1
EP0_TOTAL_OUT_LEN = 0;
#endif
// peps->dwEpState = EP_STATE_IDLE;
// pContext->pfnNotify(pContext->pvMddContext, UFN_MSG_BUS_EVENTS, UFN_RESET);
pContext->fSpeedReported = FALSE;
WriteReg(pContext, USB_INT_REG_OFFSET, USB_RESET_INTR);
// If the cable was connected to a host at boot, the attach interrupt
// will be missed. Generate it here.
if (pContext->attachedState == UFN_ATTACH) {
pContext->pfnNotify(pContext->pvMddContext,
UFN_MSG_BUS_EVENTS, UFN_DETACH);
pContext->attachedState = UFN_DETACH;
g_wCurrentState = UFN_DETACH;
}
if (pContext->attachedState == UFN_DETACH){
pContext->pfnNotify(pContext->pvMddContext,
UFN_MSG_BUS_EVENTS, UFN_ATTACH);
pContext->attachedState = UFN_ATTACH;
g_wCurrentState = UFN_ATTACH;
}
peps->dwEpState = EP_STATE_IDLE;
pContext->pfnNotify(pContext->pvMddContext, UFN_MSG_BUS_EVENTS, UFN_RESET);
// Enable the Suspend interrupt...
SetClearReg(pContext, USB_INT_EN_REG_OFFSET, USB_SUSPEND_INTR, SET);
SetClearReg(pContext, PWR_REG_OFFSET, SUSPEND_MODE_ENABLE_CTRL, SET);
DEBUGMSG(ZONE_USB_EVENTS, (_T("%s Reset\r\n"), pszFname));
}
// Setup Token Processing
if (bEpIrqStat & EP0_INT_INTR) {
// RETAILMSG(1, (TEXT("[EP0]")));
//Read the Ep0 Interrupt Status Register
BYTE bEP0IrqStatus = ReadIndexedReg(pContext, 0, EP0_CSR_REG_OFFSET);
DEBUGMSG(ZONE_USB_EVENTS, (_T("%s Status, %x\r\n"), pszFname, bEP0IrqStatus));
if (bEP0IrqStatus & SETUP_END) {
// RETAILMSG(1, (TEXT("[SE]")));
SetClearIndexedReg(pContext, 0, EP0_CSR_REG_OFFSET, SERVICED_SETUP_END, SET);
peps->dwEpState = EP_STATE_IDLE;
PSTransfer pTransfer = peps->pTransfer;
// Make MDD think everything is ok. Host will retry last packet
if(pTransfer) {
CompleteTransfer(pContext, peps, UFN_NO_ERROR);
}
// The HW does not seem to work correctly. It takes some time to
// clear the setup end before the Setup Toke is correctly acked and
// The Word Count register is loaded (note that opr is normally set here
// during the same ISR pass as well. The HW manual says
// to unload the packet if opr is set as well. This time was
// determined experimentally
StallExecution(100); // Wait for HW To clear SE
DEBUGMSG(ZONE_USB_EVENTS, (_T("%s Setup End, %x\r\n"),
pszFname, bEP0IrqStatus));
bEP0IrqStatus &= ~SETUP_END;
}
// Set By USB if protocoll violation detected
if (bEP0IrqStatus & EP0_SENT_STALL) {
RETAILMSG(1, (TEXT("[SS]")));
USB_DEVICE_REQUEST udr;
udr.bmRequestType = USB_REQUEST_FOR_ENDPOINT;
udr.bRequest =USB_REQUEST_CLEAR_FEATURE;
udr.wValue = USB_FEATURE_ENDPOINT_STALL;
udr.wIndex = 0; // Ep 0
udr.wLength =0;
pContext->pfnNotify(pContext->pvMddContext, UFN_MSG_SETUP_PACKET, (DWORD) &udr);
// Must Clear both Send and Sent Stall
SetClearIndexedReg(pContext,0, EP0_CSR_REG_OFFSET, (EP0_SEND_STALL | EP0_SENT_STALL), CLEAR);
peps->dwEpState = EP_STATE_IDLE;
bEP0IrqStatus &= ~EP0_SENT_STALL;
}
const DWORD dwSetupPacketSize = ReadIndexedReg(pContext, 0, OUT_FIFO_CNT1_REG_OFFSET);
// If a new Command receieved
#if RNDIS==1
if ((bEP0IrqStatus & EP0_OUT_PACKET_RDY) && (EP0_TOTAL_OUT_LEN == 0)) {
#else
if (bEP0IrqStatus & EP0_OUT_PACKET_RDY) {
#endif
BOOL fUdrValid = TRUE; // Indicate whether or not UDR was correctly
// decoded
USB_DEVICE_REQUEST udr;
udr.wLength = 0;
DWORD dwBytesRead;
PBYTE pbUdr = (PBYTE) &udr;
volatile ULONG *pulFifoReg = _GetDataRegister(0);
for (dwBytesRead = 0; dwBytesRead < dwSetupPacketSize; dwBytesRead++) {
pbUdr[dwBytesRead] = (UCHAR) *pulFifoReg;
}
// Parse the Setup Command this is necessary to Configure the
// SW State Machine and to set bits to enable the HW to
// ACK/NAK correctly.
if (fUdrValid) {
// Determine if this is a NO Data Packet
if (udr.wLength > 0) {
// Determine transfer Direction
if (udr.bmRequestType & USB_ENDPOINT_DIRECTION_MASK) {
// Start the SW OUT State Machine
peps->dwEpState = EP0_STATE_IN_DATA_PHASE;
}
else {
// Start the SW OUT State Machine
peps->dwEpState = EP0_STATE_OUT_DATA_PHASE;
}
}
else if ( (udr.bmRequestType != USB_REQUEST_STANDARD) &&
(udr.bmRequestType != USB_REQUEST_FOR_ENDPOINT) ) {
// Is it a Standard, Class, Vendor or Reserved Command
// The UDC HW needs the IPR bit set accordingly
// If it is No Data - Vendor, Class or Reserved Command
// ClientDriver will issue a SendControlStatusHandshake to
// complete the transaction.
// Nothing left to do... transition to IDLE.
peps->dwEpState = EP_STATE_IDLE;
}
else { // Make sure the IPR Bit is Clear
// Must be
// (udr->wLength == 0) &&
// (udr->bmRequestType == USB_REQUEST_STANDARD)
SetClearIndexedReg(pContext, 0, EP0_CSR_REG_OFFSET, EP0_IN_PACKET_RDY, CLEAR);
}
}
else {
RETAILMSG(1, (_T("%s Udr Invalid\r\n"),
pszFname));
// Udr read from the FIFO was invalid
// Ideally this should not hapen. This is a recovery mechanism if
// we get out of sync somehow.
// Client won't care and will see a reset to clean things up
SetClearIndexedReg(pContext, 0, OUT_CSR1_REG_OFFSET,
DATA_END | SERVICED_OUT_PKY_RDY, SET);
DEBUGCHK(FALSE);
fUdrValid = FALSE;
}
#if RNDIS==1
if(peps->dwEpState == EP0_STATE_OUT_DATA_PHASE)
{
if (udr.wLength != 0)
EP0_TOTAL_OUT_LEN = udr.wLength;
else
EP0_TOTAL_OUT_LEN = 0;
}
#endif
if (fUdrValid) {
// Only clear OPR if sending data back - else it will be done in
// ControlStatusHandshake
// RETAILMSG(1, (TEXT("[0x%x]"), udr.wLength));
if(udr.wLength == 0){
pContext->sendDataEnd = TRUE;
}
else {
// Clear Out Packet Ready - receive FIFO should be empty
SetClearIndexedReg(pContext, 0, EP0_CSR_REG_OFFSET, SERVICED_OUT_PKY_RDY, SET);
pContext->sendDataEnd = FALSE;
}
if (pContext->fSpeedReported == FALSE) {
// After Every Reset Notify MDD of Speed setting.
// This device can only support FULL Speed.
pContext->pfnNotify(pContext->pvMddContext, UFN_MSG_BUS_SPEED, BS_FULL_SPEED);
pContext->fSpeedReported = TRUE;
}
pContext->pfnNotify(pContext->pvMddContext, UFN_MSG_SETUP_PACKET, (DWORD) &udr);
}
bEP0IrqStatus &= ~EP0_OUT_PACKET_RDY;
}
#if RNDIS==1
else if ((bEP0IrqStatus & EP0_OUT_PACKET_RDY) && (EP0_TOTAL_OUT_LEN != 0) ) // 050827
{
HandleEndpointEvent(pContext, 0, bEP0IrqStatus);
EP0_TOTAL_OUT_LEN -= (USHORT)dwSetupPacketSize;
}
#endif
// If Out Packet ready and No Data then must be an End Transfer
else if ( (bEP0IrqStatus & EP0_OUT_PACKET_RDY) && (dwSetupPacketSize == 0) ) {
// Update the register - Clear OPR, Set DE
SetClearIndexedReg(pContext, 0, EP0_CSR_REG_OFFSET, DATA_END | SERVICED_OUT_PKY_RDY, SET);
peps->dwEpState = EP_STATE_IDLE;
DEBUGMSG(ZONE_RECEIVE, (_T("%s End Xfer \r\n"), pszFname));
}
else {
HandleEndpointEvent(pContext, 0, bEP0IrqStatus);
}
#if 1
bEP0IrqStatus = ReadIndexedReg(pContext, 0, EP0_CSR_REG_OFFSET);
if ( ((peps->dwDirectionAssigned == USB_OUT_TRANSFER)) && (bEP0IrqStatus & EP0_OUT_PACKET_RDY) ) // 050828
{
}
else
{
// Clear End Point 0 Interrupt
ClearEndpointInterrupt(pContext, 0);
}
#else
ClearEndpointInterrupt(pContext, 0);
#endif
}
// Process All Other (besides EP0) Endpoints
BYTE bEpMaskBits = ReadReg(pContext, EP_INT_EN_REG_OFFSET);
DEBUGMSG(ZONE_FUNCTION, (_T("%s HUSB Status, %x\r\n"), pszFname, bEpIrqStat));
BYTE bStatusBit = 0;
for (DWORD dwEndpoint = 1; dwEndpoint < ENDPOINT_COUNT; ++dwEndpoint) {
// Check the Interrupt Mask
// Check the Interrupt Status
bStatusBit = EpToIrqStatBit(dwEndpoint);
if ( (bEpMaskBits & bStatusBit) &&
(bEpIrqStat & bStatusBit) ) {
// RETAILMSG(1, (TEXT("E%d\n"),dwEndpoint)); // 050828
#if 1
HandleEndpointEvent(pContext, dwEndpoint, bEpIrqStat);
BYTE ocsr1 = ReadIndexedReg(pContext, dwEndpoint, OUT_CSR1_REG_OFFSET);
// receive packet complete && receive fifo not empty -> out token + data rx event
if ((peps->dwDirectionAssigned == USB_OUT_TRANSFER) && (ocsr1 & OUT_PACKET_READY) ) // 050828
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -