📄 s3c6410otgdevice.cpp
字号:
FUNCTION_ENTER_MSG();
ValidateContext(pContext);
PREFAST_DEBUGCHK(peps);
// Since Reset can be called before/after an Endpoint has been configured,
// it is best to clear all IN and OUT bits associated with endpoint.
DWORD dwEndpoint = peps->dwEndpointNumber;
// All Endpoints interrupt register clear
if(dwEndpoint == 0)
{
WriteEPSpecificReg(dwEndpoint, DIEPINT, 0x3f);
WriteEPSpecificReg(dwEndpoint, DOEPINT, 0x3f);
}
else if (dwEndpoint < ENDPOINT_COUNT)
{
WriteEPSpecificReg(dwEndpoint, DIEPINT, 0x3f);
WriteEPSpecificReg(dwEndpoint, DOEPINT, 0x3f);
DisableEndpointInterrupt(pContext, peps->dwEndpointNumber, peps->dwDirectionAssigned);
}
FUNCTION_LEAVE_MSG();
}
// Initialize OTG device register
static
VOID
InitDevice(
PCTRLR_PDD_CONTEXT pContext
)
{
WriteReg(GUSBCFG, NP_TXFIFO_REWIND_EN | TURNAROUND_TIME | PHYIF_16BIT | 0x7<<HS_FS_TIMEOUT);
WriteReg(DCFG, 0x1f<<IN_EP_MISS_CNT_IDX | DEVICE_SPEED_HIGH);
WriteReg(DAINTMSK, EP0_OUT_INT | EP0_IN_INT); // EP0 IN,OUT interrupt Unmask
WriteReg(GOTGCTL,SESSION_REQUEST);
WriteReg(GRXFSIZ, RXFIFO_DEPTH); // Rx FIFO Size
WriteReg(GNPTXFSIZ, NPTXFIFO_DEPTH<<NPTXFIFO_DEPTH_IDX | RXFIFO_DEPTH<<0); // Non Periodic Tx FIFO Size
WriteReg(DOEPMSK, SETUP_PHASE_DONE | XFER_COMPLETE);
WriteReg(DIEPMSK, TIMEOUT_CONDITION | XFER_COMPLETE);
WriteReg(GINTMSK, INT_RESUME | INT_OUT_EP | INT_IN_EP | INT_EPMIS | INT_SDE | INT_RESET | INT_SUSPEND | INT_OTG); //gint unmask
WriteReg(GAHBCFG, NPTXFEMPLVL_COMPLETE_EMPTY | MODE_DMA | BURST_SINGLE | GBL_INT_UNMASK);
WriteReg(GRSTCTL, TXFFLSH | RXFFLSH);
while(!((ReadReg(GRSTCTL) & (TXFFLSH | RXFFLSH))==0)); // Wait Until the FIFO Flush bit Cleared
}
static
VOID
InitPDDContext(
PCTRLR_PDD_CONTEXT pContext
)
{
pContext->dwPipelinedEP = 0;
pContext->bRingBufferFull = FALSE;
pContext->dwPipelinedStrIdx = pContext->dwPipelinedEndIdx = 0;
pContext->dwPipelinedXferSize = 1024*64;
pContext->dwXmittingEP = 0;
pContext->dwXmitReadyCnt = 0;
pContext->bOutEPDMAStartFlag = FALSE;
for(DWORD i=0; i<ENDPOINT_COUNT; ++i)
{
pContext->dwInEPRunning[i] = 0;
for(DWORD depth=0; depth<PIPELINED_FIFO_DEPTH; depth++)
pContext->dwPipelinedXfered[i][depth] = 0;
}
}
static
inline
VOID
SetSoftDisconnect()
{
SetClearReg(DCTL, SOFT_DISCONNECT, SET);
}
// This function is used to dicconnect to host.
// As long as this function is called, the host will not see that the device is connected,
// and the device will not receive signals on the USB.
static
inline
VOID
ClearSoftDisconnect()
{
SetClearReg(DCTL, SOFT_DISCONNECT, CLEAR);
}
// USB signal mask to prevent unwanted leakage
// This function should be called before USB PHY is used
void MaskUSBSignal(
PCTRLR_PDD_CONTEXT pContext
)
{
volatile DWORD dwRegValue;
dwRegValue = pContext->pSYSCONregs->OTHERS;
dwRegValue |= USB_SIG_MASK;
pContext->pSYSCONregs->OTHERS = dwRegValue;
}
// All module state machines (except the AHB Slave Unit) are reset to the IDLE state,
// and all the transmit FIFOs and the receive FIFO are flushed.
static
void
SoftResetCore(
PCTRLR_PDD_CONTEXT pContext
)
{
WriteReg(GRSTCTL, CSFTRST);
while(!(ReadReg(GRSTCTL) & AHBIDLE)); // Wait until AHB Master IDLE
}
// Reset the device and EP0.
static
VOID
ResetDevice(
PCTRLR_PDD_CONTEXT pContext
)
{
SETFNAME();
FUNCTION_ENTER_MSG();
DEBUGCHK(IS_VALID_SC6410_CONTEXT(pContext));
SoftResetCore(pContext);
InitDevice(pContext);
// Reset all endpoints
for (DWORD dwEpIdx = 0; dwEpIdx < ENDPOINT_COUNT; ++dwEpIdx)
{
EP_STATUS *peps = GetEpStatus(pContext, dwEpIdx);
ResetEndpoint(pContext, peps);
}
FUNCTION_LEAVE_MSG();
}
// After transmit a packet, this function should be called to let MDD know.
static
VOID
CompleteTransfer(
PCTRLR_PDD_CONTEXT pContext,
PEP_STATUS peps,
DWORD dwUsbError
)
{
SETFNAME();
FUNCTION_ENTER_MSG();
PSTransfer pTransfer = peps->pTransfer;
peps->pTransfer = NULL;
pTransfer->dwUsbError = dwUsbError;
pContext->pfnNotify(pContext->pvMddContext, UFN_MSG_TRANSFER_COMPLETE, (DWORD) pTransfer);
FUNCTION_LEAVE_MSG();
}
// Wating until TxFIFO Empty ++//
static
BOOL
WatiForTxFIFOEmpty(
DWORD dwWaitCount
)
{
for(DWORD i = 0 ; i < dwWaitCount ; i++)
{
if(ReadReg(GINTSTS) & INT_TX_FIFO_EMPTY)
{
break;
}
Sleep(1);
if (i >= (dwWaitCount-1))
{
RETAILMSG(UFN_ZONE_ERROR,(_T("TX FIFO Not Empty Error!!! Wait Coutnt %d - StartPreparedInTrasfer\r\n"),i));
return FALSE;
}
}
return TRUE;
}
// Wating until TxFIFO Empty --//
// This function is only vaild in debug build.
#ifdef DEBUG
static
VOID
ValidateTransferDirection(
PCTRLR_PDD_CONTEXT pContext,
PEP_STATUS peps,
PSTransfer pTransfer
)
{
DEBUGCHK(pContext);
PREFAST_DEBUGCHK(peps);
PREFAST_DEBUGCHK(pTransfer);
if (peps->dwEndpointNumber != 0)
{
DEBUGCHK(peps->dwDirectionAssigned == pTransfer->dwFlags);
}
}
#else
#define ValidateTransferDirection(ptr1, ptr2, ptr3)
#endif
#if TEST_MODE_SUPPORT
static BOOL
CheckForUSBTestModeRequest(
PCTRLR_PDD_CONTEXT pContext
)
{
bool fTest = FALSE;
volatile DWORD dwDCTL;
PEP_STATUS peps = GetEpStatus(pContext, 0);
LOCK_ENDPOINT(peps);
// is this a request to enter a test mode?
if( pContext->UDR.bmRequestType == (USB_REQUEST_HOST_TO_DEVICE | USB_REQUEST_STANDARD | USB_REQUEST_FOR_DEVICE)
&& pContext->UDR.bRequest == USB_REQUEST_SET_FEATURE
&& pContext->UDR.wValue == USB_FEATURE_TEST_MODE
&& (pContext->UDR.wIndex & 0xFF) == 0)
{
pContext->sendDataEnd = TRUE;
pContext->Ep0State = EP0_STATE_IDLE;
RETAILMSG(UFN_ZONE_USB_EVENTS, (_T("USBF:USB_FEATURE_TEST_MODE\r\n")));
// Set TEST MODE
RETAILMSG(UFN_ZONE_USB_EVENTS, (_T("USBF:TEST_FORCE_ENABLE\r\n")));
//Set Test Force Enable
WriteReg(DIEPTSIZ0, 1<<PACKET_COUTNT_IDX | 0);
WriteReg(DIEPCTL0, EP_ENABLE | CLEAR_NAK | 3<<0); //ep0 enable, clear nak, 8byte
dwDCTL = ReadReg(DCTL);
TM_Enabled(dwDCTL);
WriteReg(DCTL, dwDCTL);
USHORT wTestMode = pContext->UDR.wIndex >> 8;
switch( wTestMode)
{
case USB_TEST_J:
RETAILMSG(UFN_ZONE_USB_EVENTS, (_T("USBF:USB_TEST_J\r\n")));
WriteReg(DIEPTSIZ0, 1<<PACKET_COUTNT_IDX | 0);
WriteReg(DIEPCTL0, EP_ENABLE | CLEAR_NAK | 3<<0); //ep0 enable, clear nak, 8byte
dwDCTL = ReadReg( DCTL);
TM_J_Selected(dwDCTL);
WriteReg(DCTL, dwDCTL);
break;
case USB_TEST_K:
RETAILMSG(UFN_ZONE_USB_EVENTS, (_T("USBF:USB_TEST_K\r\n")));
WriteReg(DIEPTSIZ0, 1<<PACKET_COUTNT_IDX | 0);
WriteReg(DIEPCTL0, EP_ENABLE | CLEAR_NAK | 3<<0); //ep0 enable, clear nak, 8byte
dwDCTL = ReadReg( DCTL);
TM_K_Selected(dwDCTL);
WriteReg(DCTL, dwDCTL);
break;
case USB_TEST_SE0_NAK:
RETAILMSG(UFN_ZONE_USB_EVENTS, (_T("USBF:USB_TEST_SE0_NAK\r\n")));
WriteReg(DIEPTSIZ0, 1<<PACKET_COUTNT_IDX | 0);
WriteReg(DIEPCTL0, EP_ENABLE | CLEAR_NAK | 3<<0); //ep0 enable, clear nak, 8byte
dwDCTL = ReadReg( DCTL);
TM_SN_Selected(dwDCTL);
WriteReg(DCTL, dwDCTL);
break;
case USB_TEST_PACKET:
{
RETAILMSG(UFN_ZONE_USB_EVENTS, (_T("USBF:USB_TEST_PACKET\r\n")));
DWORD cbWritten = 0;
WORD WriteData = 0;
memcpy( pContext->pVAddrEP[0][IN_EP] ,ahwTestPkt, TEST_PKT_SIZE);
WatiForTxFIFOEmpty(100);
WriteReg(DIEPDMA0, pContext->pPAddrEP[0][IN_EP]);
WriteReg(DIEPTSIZ0, 1<<PACKET_COUTNT_IDX | 0);
WriteReg(DIEPCTL0, EP_ENABLE | CLEAR_NAK | 3<<0); //ep0 enable, clear nak, 8byte
WriteReg(DIEPTSIZ0, 1<<PACKET_COUTNT_IDX | TEST_PKT_SIZE);
WriteReg(DIEPCTL0, EP_ENABLE | CLEAR_NAK | EP0_MAX_PK_SIZ); //ep0 enable, clear nak, 64byte
WatiForTxFIFOEmpty(100);
dwDCTL = ReadReg(DCTL);
TM_PKT_Selected(dwDCTL);
RETAILMSG(UFN_ZONE_USB_EVENTS,(_T("USBF:DCTL : 0x%x\r\n"),dwDCTL));
WriteReg(DCTL, dwDCTL);
}
break;
case USB_TEST_FORCE_ENABLE:
RETAILMSG(UFN_ZONE_USB_EVENTS, (_T("USBF:TEST_FORCE_ENABLE\r\n")));
//Set Test Force Enable
WriteReg(DIEPTSIZ0, 1<<PACKET_COUTNT_IDX | 0);
WriteReg(DIEPCTL0, EP_ENABLE | CLEAR_NAK | 3<<0); //ep0 enable, clear nak, 8byte
dwDCTL = ReadReg(DCTL);
TM_Enabled(dwDCTL);
WriteReg(DCTL, dwDCTL);
break;
}
fTest = TRUE;
}
UNLOCK_ENDPOINT(peps);
return fTest;
}
#endif
// Process an endpoint0 interrupt.
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.
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 support both FULL and HIGH speed.
// It will be process in HandleUSBBusIrq INT_SDE.
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
{
DEBUGMSG(ZONE_ERROR,(_T("SPEED Exeption LowSpeed \r\n")));
}
pContext->fSpeedReported = TRUE;
}
if (pContext->bRdySetupPkt == TRUE)
{
pContext->bRdySetupPkt = FALSE;
// Initialize EP0 Out DMA to get a SetUp packet
WriteReg(DOEPDMA0, pContext->pPAddrEP[0][OUT_EP]);
WriteReg(DOEPTSIZ0, 1<<SETUP_PKT_CNT_IDX | 1<<PACKET_COUTNT_IDX | 8);
WriteReg(DOEPCTL0, EP_ENABLE | CLEAR_NAK | EP0_MAX_PK_SIZ);
}
else
{
PDWORD pbUDR = (PDWORD) &pContext->UDR;
memcpy(pbUDR, pContext->pVAddrEP[0][OUT_EP] ,sizeof(pContext->UDR));
#if TEST_MODE_SUPPORT
if(CheckForUSBTestModeRequest(pContext)) //for testmode
{
// DO NOTHING
}
else if (8 != sizeof(pContext->UDR))
#else
if (8 != sizeof(pContext->UDR))
#endif
{
DEBUGMSG(ZONE_ERROR, (_T("%s Setup packet was only !!\r\n"), pszFname));
// Ideally this should not hapen. This is a recovery mechanism if
// we get out of sync somehow.
}
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 IN State Machine
pContext->Ep0State = EP0_STATE_IN_DATA_PHASE;
}
else
{
// Start the SW OUT State Machine
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -