📄 s3c6400otgdevice.cpp
字号:
return bRet;
}
static
VOID
HandleEndpoint0Event(
PCTRLR_PDD_CONTEXT pContext
)
{
SETFNAME();
FUNCTION_ENTER_MSG();
ValidateContext(pContext);
DEBUGCHK(pContext->fRunning);
PEP_STATUS peps = GetEpStatus(pContext, 0);
LOCK_ENDPOINT(peps);
// Write 0 to SEND_STALL and SENT_STALL to clear them, so we need to
// leave them unchanged by default.
BYTE bEp0CsrToWrite = 0;
BOOL fSendUdr = FALSE;
BOOL fCompleted = FALSE;
DWORD dwStatus;
if (pContext->Ep0State == EP0_STATE_IDLE)
{
if (pContext->fSpeedReported == FALSE)
{
// After Every Reset Notify MDD of Speed setting.
// This device can only support FULL Speed.
// It will be process in HandleUSBBusIrq INT_SDE +chandolp
DWORD wDSTS = ReadReg(pContext, DSTS);
if (pContext->dwDetectedSpeed == USB_FULL)
{
pContext->pfnNotify(pContext->pvMddContext, UFN_MSG_BUS_SPEED, BS_FULL_SPEED);
}
else if(pContext->dwDetectedSpeed == USB_HIGH)
{
pContext->pfnNotify(pContext->pvMddContext, UFN_MSG_BUS_SPEED, BS_HIGH_SPEED);
}
else
{
RETAILMSG(1,(TEXT("SPEED Exeption LowSpeed \r\n")));
}
pContext->fSpeedReported = TRUE;
}
// New setup packet
DWORD cbOutFifo = pContext->CntValue;
pContext->CntValue = 0;
PDWORD pbUdr = (PDWORD) &pContext->udr;
volatile ULONG *pulFifoReg = _GetDataRegister(0);
DWORD cbBytesRemaining = cbOutFifo;
while (cbBytesRemaining>0)
{
*pbUdr++ = (DWORD) *pulFifoReg;
cbBytesRemaining -= 4;
}
if (cbOutFifo != sizeof(pContext->udr))
{
DEBUGMSG(ZONE_ERROR, (_T("%s Setup packet was only %x bytes!\r\n"), pszFname, cbOutFifo));
// Ideally this should not hapen. This is a recovery mechanism if
// we get out of sync somehow.
bEp0CsrToWrite |= (EP0_SEND_STALL | SERVICED_OUT_PKY_RDY | DATA_END);
}
else
{
// 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.
// Determine if this is a NO Data Packet
if (pContext->udr.wLength > 0)
{
// Determine transfer Direction
if (pContext->udr.bmRequestType & USB_ENDPOINT_DIRECTION_MASK)
{
// Start the SW OUT State Machine
pContext->Ep0State = EP0_STATE_IN_DATA_PHASE;
}
else
{
// Start the SW OUT State Machine
pContext->Ep0State = EP0_STATE_OUT_DATA_PHASE;
}
pContext->sendDataEnd = FALSE;
}
else
{ // udr.wLength == 0
// ClientDriver will issue a SendControlStatusHandshake to
// complete the transaction.
pContext->sendDataEnd = TRUE;
// Nothing left to do... stay in IDLE.
DEBUGCHK(pContext->Ep0State == EP0_STATE_IDLE);
}
fSendUdr = TRUE;
}
}
else if (pContext->Ep0State == EP0_STATE_OUT_DATA_PHASE)
{
// Check For out packet read && receive fifo not empty -> out token event
if (pContext->CntValue)
{
DEBUGMSG(ZONE_RECEIVE, (_T("%s out token packet on endpoint 0 \r\n"), pszFname));
HandleRx(pContext, peps, &fCompleted, &dwStatus);
pContext->sendDataEnd = TRUE;
}
// status stage of control transfer; zero-length packet received
else
{
DEBUGMSG(ZONE_RECEIVE, (_T("%s status stage of control transfer on endpoint 0\r\n"), pszFname));
pContext->Ep0State = EP0_STATE_IDLE;
}
}
else
{
HandleTx(pContext, peps, 1);
}
// Clear any interrupts
DEBUGMSG(ZONE_COMMENT, (_T("%s Writing 0x%02x to EP0_CSR\r\n"), pszFname, bEp0CsrToWrite));
if (fCompleted)
{
CompleteTransfer(pContext, peps, dwStatus);
}
if (fSendUdr)
{
pContext->pfnNotify(pContext->pvMddContext, UFN_MSG_SETUP_PACKET, (DWORD) &pContext->udr);
}
FUNCTION_LEAVE_MSG();
UNLOCK_ENDPOINT(peps);
}
// Process an endpoint interrupt. Call interrupt-specific handler.
static
VOID
HandleEndpointEvent(
PCTRLR_PDD_CONTEXT pContext,
DWORD dwEndpoint,
DWORD epIrqStat
)
{
SETFNAME();
FUNCTION_ENTER_MSG();
ValidateContext(pContext);
DEBUGCHK(pContext->fRunning);
DEBUGCHK(dwEndpoint != 0);
DWORD dwPendingEvents = 0;
EP_STATUS *peps = GetEpStatus(pContext, dwEndpoint);
PREFAST_DEBUGCHK(peps);
LOCK_ENDPOINT(peps);
if (peps->dwDirectionAssigned == USB_IN_TRANSFER)
{
dwPendingEvents = IN_TRANSFER;
}
else
{
dwPendingEvents = OUT_TRANSFER;
}
BOOL fCompleted = FALSE;
DWORD dwStatus;
if (dwPendingEvents == IN_TRANSFER)
{
HandleTx(pContext, peps, 0);
}
else if (dwPendingEvents == OUT_TRANSFER)
{
HandleRx(pContext, peps, &fCompleted, &dwStatus);
}
if (fCompleted)
{
// Disable transfer interrupts until another transfer is issued.
DisableEndpointInterrupt(pContext, peps->dwEndpointNumber, peps->dwDirectionAssigned);
}
if (fCompleted)
{
CompleteTransfer(pContext, peps, dwStatus);
}
FUNCTION_LEAVE_MSG();
UNLOCK_ENDPOINT(peps);
}
static
VOID
SetEndpoint(
PCTRLR_PDD_CONTEXT pContext
)
{
// Unmask DAINT source
WriteReg(pContext, DIEPINT0, 0xff);
WriteReg(pContext, DOEPINT0, 0xff);
WriteReg(pContext, DIEPINT1, 0xff);
WriteReg(pContext, DOEPINT2, 0xff);
// Init For Ep0
WriteReg(pContext, DIEPTSIZ0, 1<<19|pContext->dwEp0MaxPktSize<<0);
WriteReg(pContext, DOEPTSIZ0, 1<<29|1<<19|pContext->dwEp0MaxPktSize);
WriteReg(pContext, DOEPCTL0, 0<<31|1<<26); //ep0 enable, clear nak
}
static
VOID
SetMaxPktSizes(
PCTRLR_PDD_CONTEXT pContext,
USB_SPEED eSpeed
)
{
if (eSpeed == USB_HIGH)
{
pContext->eSpeed = USB_HIGH;
pContext->dwEp0MaxPktSize = 64;
}
else
{
pContext->eSpeed = USB_FULL;
pContext->dwEp0MaxPktSize = 8;
}
}
static
VOID
SetAllOutEpNak(
PCTRLR_PDD_CONTEXT pContext
)
{
volatile DWORD dwTemp;
DWORD dwEndpoint;
for(dwEndpoint=0; dwEndpoint<ENDPOINT_COUNT; dwEndpoint++)
{
dwTemp = ReadEPSpecificReg(pContext, dwEndpoint, DOEPCTL);
dwTemp |= DEPCTL_SNAK;
WriteEPSpecificReg(pContext, dwEndpoint, DOEPCTL, dwTemp);
}
}
static
VOID
ClearAllOutEpNak(
PCTRLR_PDD_CONTEXT pContext
)
{
volatile DWORD dwTemp;
DWORD dwEndpoint;
for(dwEndpoint=0; dwEndpoint<ENDPOINT_COUNT; dwEndpoint++)
{
dwTemp = ReadEPSpecificReg(pContext, dwEndpoint, DOEPCTL);
dwTemp |= DEPCTL_CNAK;
WriteEPSpecificReg(pContext, dwEndpoint, DOEPCTL, dwTemp);
}
}
// Process USB Bus interrupt
static
VOID
HandleUSBBusIrq(
PCTRLR_PDD_CONTEXT pContext,
DWORD bUSBBusIrqStat
)
{
SETFNAME();
FUNCTION_ENTER_MSG();
SetAllOutEpNak(pContext);
if (bUSBBusIrqStat & INT_RESET)
{
DWORD dwGOTGCTL = ReadReg(pContext, GOTGCTL);
if (pContext->attachedState == UFN_DETACH)
{
if(dwGOTGCTL & (B_SESSION_VALID|A_SESSION_VALID))
{
if(USBClassInfo == USB_MSF)
{
Sleep(1000); //for MSF Class. on booting, to generate SD Detect INT and to to mount before storage detectetcion on BOT
}
SoftResetCore(pContext);
RETAILMSG(1,(TEXT("[UFNPDD] OTG Cable Attached\r\n")));
InitDevice(pContext);
pContext->fSpeedReported = FALSE;
pContext->fSetUpPhaseDone = FALSE;
pContext->Ep0State = EP0_STATE_IDLE;
pContext->CntValue = 0;
pContext->pfnNotify(pContext->pvMddContext, UFN_MSG_BUS_EVENTS, UFN_ATTACH);
pContext->attachedState = UFN_ATTACH;
}
else
{
RETAILMSG(1,(TEXT("[UFNPDD] RESET Exeption \r\n")));
pContext->pfnNotify(pContext->pvMddContext, UFN_MSG_BUS_EVENTS, UFN_DETACH);
pContext->attachedState = UFN_DETACH;
}
}
else
{
if(!(dwGOTGCTL & (B_SESSION_VALID|A_SESSION_VALID)))
{
RETAILMSG(0,(TEXT("[UFNPDD] OTG Cable Detached\r\n")));
pContext->pfnNotify(pContext->pvMddContext, UFN_MSG_BUS_EVENTS, UFN_DETACH);
pContext->attachedState = UFN_DETACH;
}
else
{
if(USBClassInfo == USB_MSF)
{
SoftResetCore(pContext);
InitDevice(pContext);
pContext->fSpeedReported = FALSE;
pContext->fSetUpPhaseDone = FALSE;
pContext->Ep0State = EP0_STATE_IDLE;
pContext->CntValue = 0;
Sleep(100);
}
RETAILMSG(1,(TEXT("[UFNPDD] RESET Again \r\n")));
}
}
WriteReg(pContext, GINTSTS, INT_RESET);
DEBUGMSG(ZONE_USB_EVENTS, (_T("%s Reset\r\n"), pszFname));
pContext->pfnNotify(pContext->pvMddContext, UFN_MSG_BUS_EVENTS, UFN_RESET);
ClearAllOutEpNak(pContext);
}
if (bUSBBusIrqStat & INT_SDE)
{
WriteReg(pContext, GINTSTS, INT_SDE);
DWORD dwDSTS = ReadReg(pContext, DSTS);
if (((dwDSTS & 0x6)>>1) == USB_HIGH)
{
pContext->dwDetectedSpeed = USB_HIGH;
SetMaxPktSizes(pContext, USB_HIGH);
}
else if(((dwDSTS & 0x6) >> 1) == USB_FULL)
{
pContext->dwDetectedSpeed = USB_FULL;
SetMaxPktSizes(pContext, USB_FULL);
}
else
{
RETAILMSG(1,(TEXT("[UFNPDD] INT_SDE_EXEPTION Occured! \r\n")));
}
SetEndpoint(pContext);
}
if (bUSBBusIrqStat & INT_RESUME)
{
if(USBClassInfo == USB_MSF)
{
Sleep(1000); //for MSF Class. on booting, to generate SD Detect INT and to to mount before storage detectetcion on BOT
}
WriteReg(pContext, GINTSTS, INT_RESUME);
pContext->pfnNotify(pContext->pvMddContext, UFN_MSG_BUS_EVENTS, UFN_RESUME);
}
if (bUSBBusIrqStat & INT_SUSPEND)
{
WriteReg(pContext, GINTSTS, INT_SUSPEND);
pContext->pfnNotify(pContext->pvMddContext, UFN_MSG_BUS_EVENTS, UFN_SUSPEND);
}
if (bUSBBusIrqStat & INT_OTG)
{
DWORD dwGotgint = ReadReg(pContext, GOTGINT);
if (dwGotgint & SesEndDet)
{
RETAILMSG(1,(TEXT("[UFNPDD] OTG Cable Detached\r\n")));
pContext->pfnNotify(pContext->pvMddContext, UFN_MSG_BUS_EVENTS, UFN_DETACH);
pContext->attachedState = UFN_DETACH;
}
else
{
RETAILMSG(1,(TEXT("[UFNPDD] OTG Interrupt Exeption %x\r\n"),dwGotgint));
}
WriteReg(pContext, GOTGINT, dwGotgint);
}
FUNCTION_LEAVE_MSG();
}
static
VOID
HandleUSBEvent(
PCTRLR_PDD_CONTEXT pContext
)
{
SETFNAME();
FUNCTION_ENTER_MSG();
ValidateContext(pContext);
DWORD dwGintsts = ReadReg(pContext, GINTSTS);
DWORD dwDaint = ReadReg(pContext, DAINT);
if (dwGintsts & (INT_RESUME | INT_SDE | INT_RESET | INT_SUSPEND | INT_OTG))
{
HandleUSBBusIrq(pContext, dwGintsts);
}
if (dwGintsts & (INT_OUT_EP | INT_IN_EP | INT_RX_FIFO_NOT_EMPTY))
{
// Interrupt is not occured by Out EP interrupt. it is disabled.
// But if DMA mode is used, Out EP interrupt should be need. so i'm not blocking the code.
if (dwGintsts & INT_OUT_EP)
{
if (dwDaint & EP0_OUT_INT)
{
volatile DWORD dwDoepint0 = ReadReg(pContext, DOEPINT0);
if (dwDoepint0 & SETUPPHASEDONE)
{
pContext->fSetUpPhaseDone = TRUE;
}
WriteReg(pContext, DOEPINT0, dwDoepint0);
}
for(DWORD dwEndpoint = 1; dwEndpoint < ENDPOINT_COUNT; ++ dwEndpoint)
{
DWORD dwEpBit = EpToIrqStatBit(dwEndpoint) << ENDPOINT_COUNT;
if (dwDaint & dwEpBit)
{
volatile DWORD dwDoepint2 = ReadReg(pContext, DOEPINT2);
// Not Call HandleEndpointEvent function
// because in USB CPU mode, you should check the INT_RX_FIFO_NOT_EMPTY
WriteReg(pContext, DOEPINT2, dwDoepint2);
}
}
}
if (dwGintsts & INT_IN_EP)
{
if (dwDaint & EP0_IN_INT)
{
volatile DWORD dwDiepint0 = ReadReg(pContext, DIEPINT0);
if (dwDiepint0 & IN_TKN_RECEIVED)
{
HandleEndpoint0Event(pContext);
}
if (dwDiepint0 & TIMEOUT_CONDITION)
{
RETAILMSG(1,(TEXT("Time Out EP0\r\n")));
WriteReg(pContext, DCTL, CLEAR_GNPINNAK);
}
WriteReg(pContext, DIEPINT0, dwDiepint0);
}
for(DWORD dwEndpoint = 1; dwEndpoint < ENDPOINT_COUNT; ++ dwEndpoint)
{
DWORD dwEpBit = EpToIrqStatBit(dwEndpoint);
if (dwDaint & dwEpBit)
{
volatile DWORD dwDiepint = ReadEPSpecificReg(pContext, dwEndpoint, DIEPINT);
if (dwDiepint & IN_TKN_RECEIVED)
{
HandleEndpointEvent(pContext, dwEndpoint, dwDaint);
}
if (dwDiepint & TIMEOUT_CONDITION)
{
RETAILMSG(1,(TEXT("Time Out EP%x\r\n"),dwEndpoint));
WriteReg(pContext, DCTL, CLEAR_GNPINNAK);
}
WriteEPSpecificReg(pContext, dwEndpoint, DIEPINT, dwDiepint);
}
}
}
if (dwGintsts & INT_RX_FIFO_NOT_EMPTY)
{
volatile DWORD dwGINTMSK = ReadReg(pContext, GINTMSK);
// Mask INT_RX_FIFO_NOT_EMPTY interrupt
dwGINTMSK = dwGINTMSK & (~INT_RX_FIFO_NOT_EMPTY);
WriteReg(pContext, GINTMSK, dwGINTMSK);
DWORD dwGrxstsp = ReadReg(pContext, GRXSTSP);
DWORD dwEpnum = dwGrxstsp & 0xf;
if (dwEpnum == 0)
{
if ((dwGrxstsp & PKTSTS) == SETUP_PKT_RECEIVED)
{
pContext->CntValue = (dwGrxstsp & 0x7ff0) >> 4;
HandleEndpoint0Event(pContext);
WriteReg(pContext, DOEPTSIZ0, 1<<29|1<<19|pContext->dwEp0MaxPktSize);
WriteReg(pContext, DOEPCTL0, (1<<31)| (1<<26));
}
else if((dwGrxstsp & PKTSTS) == OUT_PKT_RECEIVED)
{
pContext->CntValue = (dwGrxstsp & 0x7ff0) >> 4;
HandleEndpoint0Event(pContext);
}
}
else if ((dwGrxstsp & PKTSTS) == OUT_PKT_RECEIVED)
{
DWORD dwDaintmsk = ReadReg(pContext, DAINTMSK);
pContext->CntValue = (dwGrxstsp & 0x7ff0) >> 4;
if (dwDaintmsk & ((0x1<<dwEpnum)<<ENDPOINT_COUNT))
{
HandleEndpointEvent(pContext, dwEpnum, dwDaint);
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -