📄 pdd.c
字号:
// Put the device in the D2 state.
// Note that putting the device in D4 causes an endless loop if
// no USB cable is currently plugged in. The suspend bit is set
// when we get a suspend interrupt; if we turn the power off,
// the suspend bit gets cleared, triggering a resume interrupt.
// If no USB cable is plugged in, then a suspend interrupt gets
// generated since no USB device is present. The suspend interrupt
// then triggers the power off, which clears the suspend bit,
// which triggers the resume interrupt, and we enter an infinite
// loop from which there is no escape.
pPdd->m_NewPowerState = D2;
UpdateDevicePower(pPdd);
#ifndef USE_OLD_CABLE_DETECT_METHOD
// This is a work-around for what is fundamentally a hardware design flaw.
// We can't use the ATT bit in the DEV_STAT register to determine when
// a cable is removed since the ATT bit is always set since we set the
// BSESSVLD bit in the InitializeHardware() function. We are supposed to
// be able to check to see whether a cable is connected to the device
// and set BSESSVLD as appropriate, but the hardware design for the H4
// lacks this functionality.
// As a result, we treat SUSPEND interrupts as if they indicate both a
// suspend and a cable removal.
DEBUGMSG(ZONE_PDD, (L"USBD DevStatEvent() - "
L"Detected Cable Removal Event!\r\n"));
// We are not configured anymore
OUTREG32(&pUSBDRegs->SYSCON2, USBD_SYSCON2_CLR_CFG);
// TODO: Call bus driver (OTG?) to move HW to deep sleep
// Let MDD process change
pPdd->pfnNotify(pPdd->pMddContext, UFN_MSG_BUS_EVENTS, UFN_DETACH);
// Don't process other changes (we are disconnected)
goto DevStatClean;
#endif // ! USE_OLD_CABLE_DETECT_METHOD
}
else
{
DEBUGMSG(ZONE_PDD, (L"USBD DevStatEvent() - "
L"Detected Device Resume Event!\r\n"));
pPdd->m_NewPowerState = D0;
UpdateDevicePower(pPdd);
// Let MDD process change
pPdd->pfnNotify(pPdd->pMddContext, UFN_MSG_BUS_EVENTS, UFN_RESUME);
#ifndef USE_OLD_CABLE_DETECT_METHOD
// This is a work-around for what is fundamentally a hardware design flaw.
// We can't use the ATT bit in the DEV_STAT register to determine when
// a cable is inserted since the ATT bit is always set since we set the
// BSESSVLD bit in the InitializeHardware() function. We are supposed to
// be able to check to see whether a cable is connected to the device
// and set BSESSVLD as appropriate, but the hardware design for the H4
// lacks this functionality.
// As a result, we treat RESUME interrupts as if they indicate both a
// resume and a cable insertion.
DEBUGMSG(ZONE_PDD, (L"USBD DevStatEvent() - "
L"Detected Cable Insertion Event!\r\n"));
// Let MDD process change
pPdd->pfnNotify(pPdd->pMddContext, UFN_MSG_BUS_EVENTS, UFN_ATTACH);
pPdd->pfnNotify(pPdd->pMddContext, UFN_MSG_BUS_SPEED, BS_FULL_SPEED);
#endif // ! USE_OLD_CABLE_DETECT_METHOD
}
}
// Configured
// if ((change & USBD_DEVSTAT_CFG) != 0)
// {
// }
// Addressed
if ((change & USBD_DEVSTAT_ADD) != 0)
{
DEBUGMSG(ZONE_PDD, (L"USBD DevStatEvent() - "
L"Detected Device Address Event!\r\n"));
if ((state & USBD_DEVSTAT_ADD) != 0)
{
// Let MDD process change
pPdd->pfnNotify(pPdd->pMddContext, UFN_MSG_SET_ADDRESS, 1);
}
else
{
// Let MDD process change
pPdd->pfnNotify(pPdd->pMddContext, UFN_MSG_CONFIGURED, 0);
pPdd->pfnNotify(pPdd->pMddContext, UFN_MSG_SET_ADDRESS, 0);
}
}
DevStatClean:
// Save device state for next interrupt
pPdd->devState = state;
DEBUGMSG(ZONE_FUNCTION, (L"USBD DevStatEvent() - END\r\n"));
}
//------------------------------------------------------------------------------
//
// Function: InterruptThread
//
// This is interrupt thread. It controls responsed to hardware interrupt. To
// reduce code length it calls interrupt specific functions.
//
static DWORD WINAPI InterruptThread(VOID *pPddContext)
{
USBFN_PDD *pPdd = pPddContext;
OMAP2420_USBD_REGS *pUSBDRegs = pPdd->pUSBDRegs;
DWORD code;
DWORD source;
DWORD ep;
DEBUGMSG(ZONE_INTERRUPTS, (L"USBD InterruptThread() - START\r\n"));
while (!pPdd->exitIntrThread)
{
// Wait for interrupt
code = WaitForSingleObject(pPdd->hIntrEvent, INFINITE);
DEBUGMSG(ZONE_INTERRUPTS, (L"USBD InterruptThread() - "
L"Interrupt Event Signalled!\r\n"));
if (code != WAIT_OBJECT_0)
{
break;
}
// Exit thread when we are told to do so...
if (pPdd->exitIntrThread)
{
DEBUGMSG(ZONE_INTERRUPTS, (L"USBD InterruptThread() - "
L"Exiting Thread\r\n"));
break;
}
if ((pPdd->m_CurrentPowerState == D3) || (pPdd->m_CurrentPowerState == D4))
{
pPdd->m_NewPowerState = D2;
UpdateDevicePower(pPdd);
}
// Get interrupt source
source = INREG32(&pUSBDRegs->IRQ_SRC);
DEBUGMSG(ZONE_INTERRUPTS, (L"USBD InterruptThread() - "
L"Interrupt Source: 0x%04X\r\n", (source & 0x07BF)));
// Device state
if ((source & USBD_INT_DS_CHG) != 0 || pPdd->fakeDsChange)
{
DEBUGMSG(ZONE_INTERRUPTS, (L"USBD InterruptThread() - "
L"Processing Device Status Change Interrupt\r\n"));
// Handle device state change
DevStatEvent(pPdd);
// Clear fake DsChange flag
pPdd->fakeDsChange = FALSE;
if ((source & USBD_INT_DS_CHG) != 0)
{
OUTREG32(&pUSBDRegs->IRQ_SRC, USBD_INT_DS_CHG);
}
}
// EP0 RX interrupt
if ((source & USBD_INT_EP0_RX) != 0)
{
DEBUGMSG(ZONE_INTERRUPTS, (L"USBD InterruptThread() - "
L"Processing Endpoint 0 RX Interrupt\r\n"));
// Clear source bit
OUTREG32(&pUSBDRegs->IRQ_SRC, USBD_INT_EP0_RX);
// Issue next Rx transfer
IssueRxTransfer(pPdd, 0);
}
// EP0 TX interrupt
if ((source & USBD_INT_EP0_TX) != 0)
{
DEBUGMSG(ZONE_INTERRUPTS, (L"USBD InterruptThread() - "
L"Processing Endpoint 0 TX Interrupt\r\n"));
// Clear source bit
OUTREG32(&pUSBDRegs->IRQ_SRC, USBD_INT_EP0_TX);
// Issue next Tx transfer
IssueTxTransfer(pPdd, 0);
}
// EPn RX interrupt
if ((source & USBD_INT_EP_RX) != 0)
{
// Get EP number
ep = (INREG32(&pUSBDRegs->EP_STAT) >> 8) & USBD_EP_NUM;
DEBUGMSG(ZONE_INTERRUPTS, (L"USBD InterruptThread() - "
L"Processing Endpoint %d RX Interrupt\r\n", ep));
// Clear source bit
OUTREG32(&pUSBDRegs->IRQ_SRC, USBD_INT_EP_RX);
// Handle event
IssueRxTransfer(pPdd, ep);
}
// EPn TX interrupt
if ((source & USBD_INT_EP_TX) != 0)
{
// Get EP number
ep = INREG32(&pUSBDRegs->EP_STAT) & USBD_EP_NUM;
DEBUGMSG(ZONE_INTERRUPTS, (L"USBD InterruptThread() - "
L"Processing Endpoint %d RX Interrupt\r\n", ep));
// Clear source bit
OUTREG32(&pUSBDRegs->IRQ_SRC, USBD_INT_EP_TX);
// Handle event
IssueTxTransfer(pPdd, ep);
}
// Setup Packet
if ((source & USBD_INT_SETUP) != 0)
{
DEBUGMSG(ZONE_INTERRUPTS, (L"USBD InterruptThread() - "
L"Processing Setup Interrupt\r\n"));
// Reading setup FIFO clears interrupt
SetupEvent(pPdd);
}
// Finish interrupt
InterruptDone(pPdd->sysIntr);
}
DEBUGMSG(ZONE_INTERRUPTS, (L"USBD InterruptThread() - END\r\n"));
return ERROR_SUCCESS;
}
//------------------------------------------------------------------------------
//
// Function: UfnPdd_IssueTransfer
//
DWORD WINAPI UfnPdd_IssueTransfer(VOID * pPddContext,
DWORD endPoint,
STransfer * pTransfer)
{
USBFN_PDD *pPdd = pPddContext;
OMAP2420_USBD_REGS *pUSBDRegs = pPdd->pUSBDRegs;
DWORD epNum;
// Save transfer for interrupt thread
pPdd->ep[endPoint].pTransfer = pTransfer;
if (pTransfer->pvBuffer == NULL)
{
// Sync Length with buffer.
pTransfer->cbBuffer = 0;
}
DEBUGCHK(pTransfer->dwUsbError == UFN_NOT_COMPLETE_ERROR);
// Depending on direction
if (TRANSFER_IS_IN(pTransfer))
{
pPdd->ep[endPoint].fZeroLengthNeeded = (pTransfer->cbBuffer==0);
IssueTxTransfer(pPdd, endPoint);
}
else
{
pPdd->ep[endPoint].fZeroLengthNeeded = FALSE;
// Select EP
epNum = USBD_EP_NUM & endPoint;
SelectEp(pPdd, epNum);
// Enable EP FIFO
OUTREG32(&pUSBDRegs->CTRL, USBD_CTRL_FIFO_EN);
// Deselect EP
DeselectEp(pPdd, epNum);
}
return ERROR_SUCCESS;
}
//------------------------------------------------------------------------------
//
// Function: UfnPdd_AbortTransfer
//
DWORD WINAPI UfnPdd_AbortTransfer(VOID *pPddContext, DWORD endPoint, STransfer *pTransfer)
{
USBFN_PDD *pPdd = pPddContext;
OMAP2420_USBD_REGS *pUSBDRegs = pPdd->pUSBDRegs;
DWORD epNum;
// Select EP
epNum = USBD_EP_NUM & endPoint;
if (TRANSFER_IS_IN(pTransfer))
{
epNum |= USBD_EP_NUM_DIRIN;
}
SelectEp(pPdd, epNum);
// Clear EP
OUTREG32(&pUSBDRegs->CTRL, USBD_CTRL_CLR_EP);
// Deselect EP
DeselectEp(pPdd, epNum);
// Finish transfer
pPdd->ep[endPoint].pTransfer = NULL;
pTransfer->dwUsbError = UFN_CANCELED_ERROR;
pPdd->pfnNotify(pPdd->pMddContext, UFN_MSG_TRANSFER_COMPLETE, (DWORD)pTransfer);
// Done
return ERROR_SUCCESS;
}
//------------------------------------------------------------------------------
//
// Function: UfnPdd_StallEndpoint
//
// This function is called by MDD to set end point to stall mode (halted).
//
DWORD WINAPI UfnPdd_StallEndpoint(VOID *pPddContext, DWORD endPoint)
{
USBFN_PDD *pPdd = pPddContext;
OMAP2420_USBD_REGS *pUSBDRegs = pPdd->pUSBDRegs;
DWORD epNum;
DEBUGMSG(ZONE_PDD, (L"UsbFnPdd_StallEndpoint %d\r\n", endPoint));
if (endPoint == 0)
{
// Stall next EP0 transaction
OUTREG32(&pUSBDRegs->SYSCON2, USBD_SYSCON2_STALL_CMD);
}
else
{
// Select EP
epNum = USBD_EP_NUM & endPoint;
if (!pPdd->ep[endPoint].dirRx)
{
epNum |= USBD_EP_NUM_DIRIN;
}
SelectEp(pPdd, epNum);
// Halt EP
OUTREG32(&pUSBDRegs->CTRL, USBD_CTRL_SET_HALT);
// Deselect EP
DeselectEp(pPdd, epNum);
}
// Done
return ERROR_SUCCESS;
}
//------------------------------------------------------------------------------
//
// Function: UfnPdd_ClearEndpointStall
//
// This function is called by MDD to clear end point stall mode (halted).
//
DWORD WINAPI UfnPdd_ClearEndpointStall(VOID *pPddContext, DWORD endPoint)
{
DWORD rc = ERROR_INVALID_FUNCTION;
USBFN_PDD *pPdd = pPddContext;
OMAP2420_USBD_REGS *pUSBDRegs = pPdd->pUSBDRegs;
DWORD epNum;
DEBUGMSG(ZONE_PDD, (L"UsbFnPdd_ClearEndpoint %d\r\n", endPoint));
// Endpoint can't be zero
if (endPoint != 0)
{
// Select EP
epNum = USBD_EP_NUM & endPoint;
if (!pPdd->ep[endPoint].dirRx)
{
epNum |= USBD_EP_NUM_DIRIN;
}
SelectEp(pPdd, epNum);
// Clear suspend, Clear data toggle
OUTREG32(&pUSBDRegs->CTRL, USBD_CTRL_CLR_HALT | USBD_CTRL_CLR_DATA_TOGGLE);
// Deselect EP
DeselectEp(pPdd, epNum);
// Done
rc = ERROR_SUCCESS;
}
return rc;
}
//------------------------------------------------------------------------------
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -