📄 sc2440pdd.cpp
字号:
// Write 0 to SEND_STALL and SENT_STALL to clear them, so we need to
// leave them unchanged by default.
BYTE bEp0CsrToWrite = 0;
if (bEP0IrqStatus & SETUP_END) {
bEp0CsrToWrite |= SERVICED_SETUP_END;
pContext->Ep0State = EP0_STATE_IDLE;
PSTransfer pTransfer = peps->pTransfer;
// Make MDD think everything is ok.
if(pTransfer) {
pContext->sendDataEnd = FALSE;
CompleteTransfer(pContext, peps, UFN_NO_ERROR);
}
DEBUGMSG(ZONE_USB_EVENTS, (_T("%s Setup End, %x\r\n"),
pszFname, bEP0IrqStatus));
}
// Set By USB if protocol violation detected
if (bEP0IrqStatus & EP0_SENT_STALL) {
// Must Clear both Send and Sent Stall
pContext->Ep0State = EP0_STATE_IDLE;
}
BOOL fSendUdr = FALSE;
DWORD cbFifo = ReadIndexedReg(pContext, 0, OUT_FIFO_CNT1_REG_OFFSET);
BOOL fCompleted = FALSE;
DWORD dwStatus;
if (pContext->Ep0State == EP0_STATE_IDLE) {
if (bEP0IrqStatus & EP0_OUT_PACKET_RDY) {
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;
}
// New setup packet
const DWORD cbOutFifo = ReadIndexedReg(pContext, 0,
OUT_FIFO_CNT1_REG_OFFSET);
PBYTE pbUdr = (PBYTE) &pContext->udr;
volatile ULONG *pulFifoReg = _GetDataRegister(0);
DWORD cbBytesRemaining = cbOutFifo;
while (cbBytesRemaining--) {
*pbUdr++ = (BYTE) *pulFifoReg;
}
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_PKT_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) {
if (bEP0IrqStatus & OUT_PACKET_READY) {
bEp0CsrToWrite |= SERVICED_OUT_PKT_RDY;
// Check For out packet read && receive fifo not empty -> out token event
if (cbFifo) {
DEBUGMSG(ZONE_RECEIVE, (_T("%s out token packet on endpoint 0 \r\n"),
pszFname));
bEp0CsrToWrite |= HandleRx(pContext, peps, &fCompleted, &dwStatus);
}
// 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 {
DEBUGMSG(ZONE_SEND, (_T("%s Data Phase In Token\r\n"), pszFname));
DEBUGCHK(pContext->Ep0State == EP0_STATE_IN_DATA_PHASE);
BOOL bHandleTx = FALSE;
// IN Data Phase and IPR is cleared
// Check For status stage - End control transfer; zero-length packet received
if ( (bEP0IrqStatus & OUT_PACKET_READY) && (cbFifo == 0) ) {
bHandleTx = TRUE;
DEBUGMSG(ZONE_SEND, (_T("%s In - end xfer\r\n"),
pszFname));
}
else if ((bEP0IrqStatus & IN_PACKET_READY) == 0) {
bHandleTx = TRUE;
}
if (bHandleTx) {
bEp0CsrToWrite |= HandleTx(pContext, peps, 0);
}
}
// Clear any interrupts
DEBUGMSG(ZONE_COMMENT, (_T("%s Writing 0x%02x to EP0_CSR\r\n"), pszFname, bEp0CsrToWrite));
WriteIndexedReg(pContext, 0, EP0_CSR_REG_OFFSET, 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);
ClearEndpointInterrupt(pContext, dwEndpoint);
BYTE bEpIrqStat;
BYTE bEpIrqStatToWrite;
DWORD dwIndexRegOffset;
if (peps->dwDirectionAssigned == USB_IN_TRANSFER) {
dwIndexRegOffset = IN_CSR1_REG_OFFSET;
}
else {
dwIndexRegOffset = OUT_CSR1_REG_OFFSET;
}
bEpIrqStat = ReadIndexedReg(pContext, dwEndpoint, dwIndexRegOffset);
if (peps->dwDirectionAssigned == USB_IN_TRANSFER) {
bEpIrqStatToWrite = bEpIrqStat & (IN_SEND_STALL | IN_SENT_STALL) &
~(IN_CLR_DATA_TOGGLE);
DEBUGMSG(ZONE_COMMENT, (_T("%s Endpoint %u IN_CSR1_REG = 0x%02x\r\n"),
pszFname, dwEndpoint, bEpIrqStat));
// Stall "acknowledged" from Host
if (bEpIrqStat & IN_SENT_STALL) {
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 IN_SENT_STALL EP%u \r\n"),
pszFname, dwEndpoint));
pContext->pfnNotify(pContext->pvMddContext, UFN_MSG_SETUP_PACKET, (DWORD) &udr);
// Must Clear both Send and Sent Stall
bEpIrqStatToWrite &= ~(IN_SEND_STALL | IN_SENT_STALL);
}
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;
}
}
else {
bEpIrqStatToWrite = bEpIrqStat & (OUT_SEND_STALL | OUT_SENT_STALL) &
~(OUT_CLR_DATA_TOGGLE);
DEBUGMSG(ZONE_COMMENT, (_T("%s Endpoint %u OUT_CSR1_REG = 0x%02x\r\n"),
pszFname, dwEndpoint, bEpIrqStat));
// Stall "acknowledged" from Host
if (bEpIrqStat & OUT_SENT_STALL) {
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_PIPE, (_T("%s Got OUT_SENT_STALL EP%u \r\n"),
pszFname, dwEndpoint));
pContext->pfnNotify(pContext->pvMddContext, UFN_MSG_SETUP_PACKET, (DWORD) &udr);
// Must Clear both Send and Sent Stall
bEpIrqStatToWrite &= ~(OUT_SEND_STALL | OUT_SENT_STALL);
}
// 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;
}
}
BOOL fCompleted = FALSE;
DWORD dwStatus;
if (dwPendingEvents == IN_TRANSFER) {
bEpIrqStatToWrite |= HandleTx(pContext, peps, 0);
}
else if (dwPendingEvents == OUT_TRANSFER) {
if (peps->pTransfer) {
bEpIrqStatToWrite |= HandleRx(pContext, peps, &fCompleted, &dwStatus);
}
else {
// FIFO unload failed, so leave OUT_PKT_RDY bit alone.
DEBUGMSG(ZONE_WARNING, (_T(" %s failed to unload FIFO, so preserving OUT_PKT_RDY bit."), pszFname));
bEpIrqStatToWrite |= OUT_PACKET_READY;
}
}
if (fCompleted) {
// Disable transfer interrupts until another transfer is issued.
DisableEndpointInterrupt(pContext, peps->dwEndpointNumber);
}
DEBUGMSG(ZONE_COMMENT, (_T("%s Writing 0x%02x to index 0x%02x\r\n"), pszFname,
bEpIrqStatToWrite, dwIndexRegOffset));
WriteIndexedReg(pContext, dwEndpoint, dwIndexRegOffset, bEpIrqStatToWrite);
if (fCompleted) {
CompleteTransfer(pContext, peps, dwStatus);
}
FUNCTION_LEAVE_MSG();
UNLOCK_ENDPOINT(peps);
}
// Process USB Bus interrupt
static
VOID
HandleUSBBusIrq(
PCTRLR_PDD_CONTEXT pContext,
BYTE bUSBBusIrqStat
)
{
SETFNAME();
FUNCTION_ENTER_MSG();
#if 0
if (bUSBBusIrqStat & USB_SUSPEND_INTR) {
WriteReg(pContext, USB_INT_REG_OFFSET, USB_SUSPEND_INTR);
// 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_RESUME_INTR, SET);
if (pContext->attachedState == UFN_ATTACH) {
DEBUGMSG(ZONE_USB_EVENTS, (_T("%s Suspend\r\n"), pszFname));
// pContext->pfnNotify(pContext->pvMddContext, UFN_MSG_BUS_EVENTS, UFN_SUSPEND);
pContext->pfnNotify(pContext->pvMddContext, UFN_MSG_BUS_EVENTS, UFN_DETACH);
pContext->attachedState = UFN_DETACH;
}
}
if (bUSBBusIrqStat & USB_RESUME_INTR) {
WriteReg(pContext, USB_INT_REG_OFFSET, USB_RESUME_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_DETACH) {
DEBUGMSG(ZONE_USB_EVENTS, (_T("%s Resume\r\n"), pszFname));
// pContext->pfnNotify(pContext->pvMddContext, UFN_MSG_BUS_EVENTS, UFN_RESUME);
pContext->pfnNotify(pContext->pvMddContext, UFN_MSG_BUS_EVENTS, UFN_ATTACH);
pContext->attachedState = UFN_ATTACH;
}
}
#endif
if (bUSBBusIrqStat & USB_RESET_INTR) {
WriteReg(pContext, USB_INT_REG_OFFSET, USB_RESET_INTR);
DEBUGMSG(ZONE_USB_EVENTS, (_T("%s Reset\r\n"), pszFname));
pContext->fSpeedReported = FALSE;
#if 0
// 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;
}
if (pContext->attachedState == UFN_DETACH){
pContext->pfnNotify(pContext->pvMddContext,
UFN_MSG_BUS_EVENTS, UFN_ATTACH);
pContext->attachedState = UFN_ATTACH;
}
#endif
if (pContext->attachedState == UFN_DETACH){
pContext->pfnNotify(pContext->pvMddContext, UFN_MSG_BUS_EVENTS, UFN_ATTACH);
pContext->attachedState = UFN_ATTACH;
}
pContext->Ep0State = EP0_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);
}
FUNCTION_LEAVE_MSG();
}
// Process a SC2440 interrupt.
static
VOID
HandleUSBEvent(
PCTRLR_PDD_CONTEXT pContext
)
{
SETFNAME();
FUNCTION_ENTER_MSG();
ValidateContext(pContext);
BYTE bEpIrqStat = ReadReg(pContext, EP_INT_REG_OFFSET);
BYTE bUSBBusIrqStat = ReadReg(pContext, USB_INT_REG_OFFSET);
while (bEpIrqStat || bUSBBusIrqStat) {
if (bUSBBusIrqStat) {
DEBUGMSG(ZONE_COMMENT, (_T("%s USB_INT_REG = 0x%02x\r\n"),
pszFname, bUSBBusIrqStat));
HandleUSBBusIrq(pContext, bUSBBusIrqStat);
}
if (bEpIrqStat) {
DEBUGMSG(ZONE_COMMENT, (_T("%s EP_INT_REG = 0x%02x\r\n"),
pszFname, bEpIrqStat));
if (bEpIrqStat & EP0_INT_INTR) {
HandleEndpoint0Event(pContext);
}
// Process All Other (besides EP0) Endpoints
for (DWORD dwEndpoint = 1; dwEndpoint < ENDPOINT_COUNT; ++dwEndpoint) {
// Check the Interrupt Mask
// Check the Interrupt Status
BYTE bEpBit = EpToIrqStatBit(dwEndpoint);
if (bEpIrqStat & bEpBit) {
HandleEndpointEvent(pContext, dwEndpoint, bEpIrqStat);
}
}
}
bEpIrqStat = ReadReg(pContext, EP_INT_REG_OFFSET);
bUSBBusIrqStat = ReadReg(pContext, USB_INT_REG_OFFSET);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -