📄 sc2440pdd.cpp
字号:
// so... just ignore it.
goto EXIT;
}
if (fCompleted) {
// Disable transfer interrupts until another transfer is issued.
if (peps->dwEndPointNumber != 0) {
DisableEndpointInterrupt(pContext, peps->dwEndPointNumber);
ClearEndpointInterrupt(pContext, peps->dwEndPointNumber);
}
CompleteTransfer(pContext, peps, dwStatus);
DEBUGMSG(ZONE_SEND, (_T("%s Tx Done Ep%x %u\r\n"), pszFname,
dwEndpoint, 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();
}
// 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);
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,IN_CSR1_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 & OUT_PACKET_READY) && ( 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 & OUT_PACKET_READY) && ( 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,OUT_CSR1_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 & OUT_PACKET_READY) && ( bWordCount == 0) ) {
dwPendingEvents = IN_TRANSFER;
DEBUGMSG(ZONE_SEND, (_T("%s In - end xfer; UDCCS0 = 0x%x \r\n"),
pszFname, bEP0IrqStatus));
}
else if ((bEP0IrqStatus & IN_PACKET_READY) == 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
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 )
{
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 | IN_SENT_STALL), SET);
}
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) {
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) {
HandleTx(pContext, peps, 0);
}
else if (dwPendingEvents & OUT_TRANSFER) {
HandleRx(pContext, peps);
}
FUNCTION_LEAVE_MSG();
UNLOCK_ENDPOINT(peps);
}
// Process a SC2440 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 (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);
}
}
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_ATTACH) {
DEBUGMSG(ZONE_USB_EVENTS, (_T("%s Resume\r\n"), pszFname));
pContext->pfnNotify(pContext->pvMddContext, UFN_MSG_BUS_EVENTS, UFN_RESUME);
}
}
if (bUSBBusIrqStat & USB_RESET_INTR) {
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;
}
if (pContext->attachedState == UFN_DETACH){
pContext->pfnNotify(pContext->pvMddContext,
UFN_MSG_BUS_EVENTS, UFN_ATTACH);
pContext->attachedState = 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);
DEBUGMSG(ZONE_USB_EVENTS, (_T("%s Reset\r\n"), pszFname));
}
// Setup Token Processing
if (bEpIrqStat & EP0_INT_INTR) {
//Read the Ep0 Interrupt Status Register
BYTE bEP0IrqStatus = ReadIndexedReg(pContext, 0, IN_CSR1_REG_OFFSET);
// Clear End Point 0 Interrupt
ClearEndpointInterrupt(pContext, 0);
DEBUGMSG(ZONE_USB_EVENTS, (_T("%s Status, %x\r\n"), pszFname, bEP0IrqStatus));
if (bEP0IrqStatus & SETUP_END) {
SetClearIndexedReg(pContext, 0, IN_CSR1_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) {
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, IN_CSR1_REG_OFFSET,
(EP0_SEND_STALL | EP0_SEND_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 (bEP0IrqStatus & EP0_OUT_PACKET_RDY) {
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, OUT_CSR1_REG_OFFSET,
EP0_IN_PACKET_RDY, CLEAR);
}
}
else {
DEBUGMSG(ZONE_USB_EVENTS || ZONE_WARNING, (_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 (fUdrValid) {
// Only clear OPR if sending data back - else it will be done in
// ControlStatusHandshake
if(udr.wLength == 0){
pContext->sendDataEnd = TRUE;
}
else {
// Clear Out Packet Ready - receive FIFO should be empty
SetClearIndexedReg(pContext,0,OUT_CSR1_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 Out Packet ready and No Data then must be an End Transfer
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -