📄 s3c6400otgdevice.cpp
字号:
)
{
SETFNAME();
FUNCTION_ENTER_MSG();
EnableDisableEndpointInterrupt(pContext, dwEndpoint, dwDirection, FALSE);
FUNCTION_LEAVE_MSG();
}
// Reset an endpoint
static
VOID
ResetEndpoint(
PCTRLR_PDD_CONTEXT pContext,
EP_STATUS *peps
)
{
SETFNAME();
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;
if(dwEndpoint == 0)
{
WriteEPSpecificReg(pContext, dwEndpoint, DIEPINT, 0x3f);
WriteEPSpecificReg(pContext, dwEndpoint, DOEPINT, 0x3f);
}
else if (dwEndpoint < ENDPOINT_COUNT)
{
WriteEPSpecificReg(pContext, dwEndpoint, DIEPINT, 0x3f);
WriteEPSpecificReg(pContext, dwEndpoint, DOEPINT, 0x3f);
DisableEndpointInterrupt(pContext, peps->dwEndpointNumber, peps->dwDirectionAssigned);
}
FUNCTION_LEAVE_MSG();
}
static
VOID
InitPhyCon(
PCTRLR_PDD_CONTEXT pContext
)
{
pContext->pOTGPhyregs->OPHYPWR = 0x0;
pContext->pOTGPhyregs->OPHYCLK = 0x20;
pContext->pOTGPhyregs->ORSTCON = 0x1;
Delay(100);
// Sleep(10);
pContext->pOTGPhyregs->ORSTCON = 0x0;
Delay(100); //10000
// Sleep(100);
}
static
VOID
InitDevice(
PCTRLR_PDD_CONTEXT pContext
)
{
WriteReg(pContext, GUSBCFG,
0<<15 // PHY Low Power Clock sel
|1<<14 // Non-Periodic TxFIFO Rewind Enable
|0x5<<10 // Turnaround time
|0<<9|0<<8 // [0:HNP disable, 1:HNP enable][ 0:SRP disable, 1:SRP enable]
|0<<7 // Ulpi DDR sel
|0<<6 // 0: high speed utmi+, 1: full speed serial
|0<<4 // 0: utmi+, 1:ulpi
|1<<3 // phy i/f 0:8bit, 1:16bit
|0x7<<0 // HS/FS Timeout*
);
WriteReg(pContext, DCFG, 1<<18|0<<0); // [][1: full speed(30Mhz) 0:high speed]
WriteReg(pContext, DAINTMSK, (1<<0)<<ENDPOINT_COUNT |(1<<0)); //IN, OUT ep int unmask
WriteReg(pContext, DOEPMSK, 0); // Not use OUT EP Interrupt in slave(cpu) mode, but if you use DMA it should be use.
WriteReg(pContext, DIEPMSK, IN_TKN_RECEIVED | TIMEOUT_CONDITION); // Tkn Rcvd when TxFIFO Empty, ep timeout
WriteReg(pContext, GOTGCTL,
0<<11 // 0:HNP disable, 1:HNP enable
|0<<9 // 0:No HNP req, 1:HNP req
|1<<1 // 0:No session req, 1:session req
);
WriteReg(pContext, GRXFSIZ, 0x800); // Rx FIFO Size
WriteReg(pContext, GNPTXFSIZ, 0x800<<16|0x800<<0); // Non Periodic Tx FIFO Size
WriteReg(pContext, GINTMSK, INT_RESUME | INT_IN_EP|INT_SDE|INT_RESET |INT_SUSPEND|INT_RX_FIFO_NOT_EMPTY | INT_OTG); //gint unmask
WriteReg(pContext, GAHBCFG, MODE_SLAVE|BURST_SINGLE|GBL_INT_UNMASK);
WriteReg(pContext, GRSTCTL, (1<<5)|(1<<4));
while(!((ReadReg(pContext, GRSTCTL) & (0x3<<4)) == 0)); // Wait Until the FIFO Flush bit Cleared
}
void SetSoftDisconnect(
PCTRLR_PDD_CONTEXT pContext
)
{
volatile DWORD dwTemp = ReadReg(pContext, DCTL);
dwTemp |= SOFT_DISCONNECT;
WriteReg(pContext, DCTL, dwTemp);
}
void ClearSoftDisconnect(
PCTRLR_PDD_CONTEXT pContext
)
{
volatile DWORD dwTemp = ReadReg(pContext, DCTL);
dwTemp = dwTemp & ~SOFT_DISCONNECT;
WriteReg(pContext, DCTL, dwTemp);
}
void MaskUSBSignal(
PCTRLR_PDD_CONTEXT pContext
)
{
volatile DWORD dwRegValue;
dwRegValue = pContext->pSYSCONregs->OTHERS;
dwRegValue |= (1<<16);
pContext->pSYSCONregs->OTHERS = dwRegValue;
}
static
void
SoftResetCore(
PCTRLR_PDD_CONTEXT pContext
)
{
DWORD dwTemp;
WriteReg(pContext, GRSTCTL, 0x1);
do
{
dwTemp = ReadReg(pContext, GRSTCTL);
}while(!(dwTemp & (0x1<<31))); //Wait until AHB Master IDLE
}
// Reset the device and EP0.
static
VOID
ResetDevice(
PCTRLR_PDD_CONTEXT pContext
)
{
SETFNAME();
FUNCTION_ENTER_MSG();
DEBUGCHK(IS_VALID_SC6400_CONTEXT(pContext));
MaskUSBSignal(pContext);
pContext->eSpeed = USB_FULL;
InitPhyCon(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();
}
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();
}
#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
// Read data from an endpoint.
static
BYTE
HandleRx(
PCTRLR_PDD_CONTEXT pContext,
PEP_STATUS peps,
PBOOL pfCompleted,
PDWORD pdwStatus
)
{
BOOL fCompleted = FALSE;
DWORD dwStatus = ERROR_GEN_FAILURE;
DWORD dwEndpoint = peps->dwEndpointNumber;
BYTE bRet = 0;
SETFNAME();
FUNCTION_ENTER_MSG();
PSTransfer pTransfer = peps->pTransfer;
pTransfer = peps->pTransfer;
if (pTransfer)
{
DEBUGCHK(pTransfer->dwFlags == USB_OUT_TRANSFER);
DEBUGCHK(pTransfer->dwUsbError == UFN_NOT_COMPLETE_ERROR);
ValidateTransferDirection(pContext, peps, pTransfer);
DEBUGCHK(peps->fInitialized);
#ifndef WCE600 // by dodan2
DWORD dwCurrentPermissions = GetCurrentPermissions();
SetProcPermissions(pTransfer->dwCallerPermissions);
#endif
__try
{
volatile ULONG *pulFifoReg = _GetDataRegister(dwEndpoint);
DEBUGCHK(pulFifoReg != NULL);
PBYTE pbBuffer = (PBYTE)pTransfer->pvBuffer + pTransfer->cbTransferred;
DWORD cbBuffer = pTransfer->cbBuffer - pTransfer->cbTransferred;
DWORD cbFifo = pContext->CntValue;
pContext->CntValue = 0;
DEBUGCHK(cbFifo <= peps->dwPacketSizeAssigned);
// Read from the FIFO
const DWORD cbRead = min(cbFifo, cbBuffer);
DWORD cbToRead;
DWORD ReadData = 0;
if ((cbRead == 512) && (((DWORD)pbBuffer & 0x3)==0))
{
RxData512(pbBuffer, pulFifoReg);
}
else
{
for(cbToRead = 0; cbToRead < cbRead; cbToRead += 4)
{
ReadData = (DWORD)*pulFifoReg;
*pbBuffer = (BYTE)ReadData;
*(pbBuffer+1) = (BYTE)(ReadData>>8);
*(pbBuffer+2) = (BYTE)(ReadData>>16);
*(pbBuffer+3) = (BYTE)(ReadData>>24);
pbBuffer += 4;
}
}
DEBUGCHK(cbRead <= pTransfer->cbBuffer - pTransfer->cbTransferred);
pTransfer->cbTransferred += cbRead;
if ( (cbRead < peps->dwPacketSizeAssigned) || (pTransfer->cbTransferred == pTransfer->cbBuffer) )
{
// Short packet or filled buffer. Complete transfer.
fCompleted = TRUE;
dwStatus = UFN_NO_ERROR;
}
else
{
if (dwEndpoint == 0)
{
WriteReg(pContext, DOEPTSIZ0, 1<<19 | pContext->dwEp0MaxPktSize);
WriteReg(pContext, DOEPCTL0, (1<<31)|(1<<26)|(0<<0));
}
else
{
WriteEPSpecificReg(pContext, dwEndpoint, DOEPTSIZ, 1<<19 | peps->dwPacketSizeAssigned);
WriteEPSpecificReg(pContext, dwEndpoint, DOEPCTL, 1<<31|1<<26|2<<18|1<<15 |peps->dwPacketSizeAssigned);
}
}
if (dwEndpoint == 0)
{
bRet |= SERVICED_OUT_PKY_RDY;
if (fCompleted)
{
bRet |= DATA_END;
pContext->Ep0State = EP0_STATE_IDLE;
}
}
else
{
DEBUGCHK( (bRet & OUT_PACKET_READY) == 0);
}
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
DEBUGMSG(ZONE_ERROR, (_T("%s Exception!\r\n"), pszFname));
fCompleted = TRUE;
dwStatus = UFN_CLIENT_BUFFER_ERROR;
}
#ifndef WCE600 // by dodan2
SetProcPermissions(dwCurrentPermissions);
#endif
DEBUGMSG(ZONE_RECEIVE, (_T("%s Rx Ep%x BufferSize=%u,Xfrd=%u \r\n"),
pszFname, dwEndpoint, pTransfer->cbBuffer, pTransfer->cbTransferred));
}
*pfCompleted = fCompleted;
*pdwStatus = dwStatus;
FUNCTION_LEAVE_MSG();
return bRet;
}
// Write data to an endpoint.
static
BYTE
HandleTx(
PCTRLR_PDD_CONTEXT pContext,
PEP_STATUS peps,
BOOL fEnableInterrupts
)
{
SETFNAME();
DEBUGCHK(pContext);
PREFAST_DEBUGCHK(peps);
// This routine can be entered from both ISTMain and MDD/Client threads so
// need critical section.
FUNCTION_ENTER_MSG();
BYTE bRet = 0;
BOOL fCompleted = FALSE;
PSTransfer pTransfer = peps->pTransfer;
DWORD dwStatus = ERROR_GEN_FAILURE;
DEBUGCHK(peps->fInitialized);
DWORD dwEndpoint = peps->dwEndpointNumber;
pTransfer = peps->pTransfer;
DWORD WriteData = 0;
if (pTransfer)
{
ValidateTransferDirection(pContext, peps, pTransfer);
DEBUGCHK(pTransfer->dwFlags == USB_IN_TRANSFER);
DEBUGCHK(pTransfer->dwUsbError == UFN_NOT_COMPLETE_ERROR);
#ifndef WCE600 // by dodan2
DWORD dwCurrentPermissions = GetCurrentPermissions();
SetProcPermissions(pTransfer->dwCallerPermissions);
#endif
// Transfer is ready
__try
{
PBYTE pbBuffer = (PBYTE) pTransfer->pvBuffer + pTransfer->cbTransferred;
// PDWORD pbBuffer = (PDWORD)pTransfer->pvBuffer + pTransfer->cbTransferred;
DWORD cbBuffer = pTransfer->cbBuffer - pTransfer->cbTransferred;
volatile ULONG *pulFifoReg = _GetDataRegister(dwEndpoint);
DWORD cbWritten = 0;
// Min of input byte count and supported size
volatile DWORD cbToWrite = min(cbBuffer, peps->dwPacketSizeAssigned);
if (dwEndpoint == 0)
{
WriteReg(pContext, DIEPTSIZ0, 1<<19 | cbToWrite);
WriteReg(pContext, DIEPCTL0, (1<<31)|(1<<26)|(1<<11)|(0<<0));
if (((DWORD)pbBuffer % 4) != 0)
RETAILMSG(1,(TEXT("Tx EP0 Not Alligned %x\r\n"),(DWORD)pbBuffer));
for (cbWritten = 0; cbWritten <cbToWrite; cbWritten+=4)
{
WriteData = ((*(pbBuffer+3))<<24) | ((*(pbBuffer+2))<<16) | ((*(pbBuffer+1))<<8) | *pbBuffer;
*pulFifoReg = WriteData;
pbBuffer += 4;
// (DWORD)*pulFifoReg = (DWORD)*(pbBuffer);
// pbBuffer += 1;
}
/* We can complete on a packet which is full. We need to wait till
* next time and generate a zero length packet, so only complete
* if we're at the end and it is not the max packet size.
*/
pTransfer->cbTransferred += cbToWrite;
if ((pTransfer->cbTransferred >= pTransfer->cbBuffer) && (pTransfer->pvPddData == 0))
{
dwStatus = UFN_NO_ERROR;
fCompleted = TRUE;
pContext->Ep0State = EP0_STATE_IDLE;
}
}
else// if (cbToWrite != 0)
{
// Enable Interrupts before writing to the FIFO. This insures
// That any interrupts generated because of the write will be
// "latched"
if (fEnableInterrupts)
{
DEBUGCHK(dwEndpoint != 0);
EnableEndpointInterrupt(pContext, dwEndpoint, peps->dwDirectionAssigned);
}
if(cbToWrite !=0)
{
WriteEPSpecificReg(pContext, dwEndpoint, DIEPTSIZ, 1<<29 | 1<<19 | cbToWrite);
WriteEPSpecificReg(pContext, dwEndpoint, DIEPCTL, (1<<31) |(1<<26) |(2<<18)|(1<<15)|(1<<11)|(peps->dwPacketSizeAssigned<<0));
}
if (((DWORD)pbBuffer % 4) != 0)
RETAILMSG(1,(TEXT("Tx Not Alligned %x\r\n"),(DWORD)pbBuffer));
if ((cbToWrite == 512) && (((DWORD)pbBuffer & 0x3)==0))
{
TxData512(pbBuffer, pulFifoReg);
cbWritten += 512;
}
else
{
for (cbWritten = 0; cbWritten <cbToWrite; cbWritten+=4)
{
WriteData = ((*(pbBuffer+3))<<24) | ((*(pbBuffer+2))<<16) | ((*(pbBuffer+1))<<8) | *pbBuffer;
*pulFifoReg = WriteData;
pbBuffer += 4;
}
}
// Update the Transfered Count
pTransfer->cbTransferred += cbToWrite;
// By Placing the check for packet complete here, before
// cbTransferred is updated, there is a 1 interrupt cycle delay
// That is complete is not declared until the data has actually
// been ACKd (TPC set) by the host
if ( (pTransfer->cbTransferred >= pTransfer->cbBuffer) || (cbWritten == 0))
{
fCompleted = TRUE;
dwStatus = UFN_NO_ERROR;
}
}
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
DEBUGMSG(ZONE_ERROR, (_T("%s Exception!\r\n"), pszFname));
fCompleted = TRUE;
dwStatus = UFN_CLIENT_BUFFER_ERROR;
}
#ifndef WCE600 // by dodan2
SetProcPermissions(dwCurrentPermissions);
#endif
}
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 (peps->dwEndpointNumber != 0)
{
DisableEndpointInterrupt(pContext, peps->dwEndpointNumber, peps->dwDirectionAssigned);
}
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();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -