📄 sc2440pdd.cpp
字号:
}
SetProcPermissions(dwCurrentPermissions);
}
else {
// It is possible for an interrupt to come in while still in this
// function for first pass of transfer. If this happens it is possible
// to complete the transfer and have that interrupt be unnecessary
// so... just ignore it.
goto EXIT;
}
if (fCompleted) {
// Disable transfer interrupts until another transfer is issued.
#if 1
if (peps->dwEndpointNumber != 0) {
DisableEndpointInterrupt(pContext, peps->dwEndpointNumber);
}
#endif
DEBUGMSG(ZONE_SEND, (_T("%s Tx Done Ep%x Status %u\r\n"), pszFname,
dwEndpoint, dwStatus));
CompleteTransfer(pContext, peps, dwStatus);
}
else {
DEBUGMSG(ZONE_SEND, (_T("%s Tx EP%x BufferSize=%u, Xfrd=%u\r\n"),
pszFname, dwEndpoint, pTransfer->cbBuffer, pTransfer->cbTransferred));
}
EXIT:
FUNCTION_LEAVE_MSG();
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);
ClearEndpointInterrupt(pContext, 0);
BYTE bEP0IrqStatus = ReadIndexedReg(pContext, 0, EP0_CSR_REG_OFFSET);
DEBUGMSG(ZONE_USB_EVENTS, (_T("%s EP0_CSR_REG = 0x%02x. Data phase = %u\r\n"),
pszFname, bEP0IrqStatus, pContext->Ep0State));
// 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_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) {
if (bEP0IrqStatus & OUT_PACKET_READY) {
bEp0CsrToWrite |= SERVICED_OUT_PKY_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 & EP0_IN_PACKET_RDY) == 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;
PREFAST_SUPPRESS(12006, "Buffer access index expression 'udr.wIndex=(USHORT)dwEndpoint' is being truncated in a shortening cast.");
udr.wIndex = (USHORT) 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) {
bEpIrqStatToWrite |= HandleRx(pContext, peps, &fCompleted, &dwStatus);
// We have not yet cleared the interrupt so no other packets
// should be in the FIFO.
DEBUGCHK(ReadIndexedReg(pContext, peps->dwEndpointNumber, OUT_FIFO_CNT1_REG_OFFSET) == 0);
}
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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -