📄 sc2440pdd.cpp
字号:
)
{
SETFNAME();
FUNCTION_ENTER_MSG();
// Clear the Endpoint Interrupt
BYTE bIntBit = EpToIrqStatBit(dwEndpoint);
WriteReg(pContext, EP_INT_REG_OFFSET, bIntBit);
FUNCTION_LEAVE_MSG();
} // _ClearInterrupt
// 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 ) {
// Clear all EP0 Status bits
WriteIndexedReg(pContext, 0, IN_CSR1_REG_OFFSET,
(SERVICED_OUT_PKT_RDY | SERVICED_SETUP_END));
}
else if(dwEndpoint < ENDPOINT_COUNT) {
// Clear the desired Endpoint - Clear both the In & Out Status bits
BYTE bRegIn;
BYTE bRegOut;
if(peps->fInitialized){
PREFAST_DEBUGCHK(peps->fInitialized); // Give prefast a clue.
// First Read the CSR2 Reg bit so that it can be restored
bRegIn = ReadIndexedReg(pContext, dwEndpoint, IN_CSR2_REG_OFFSET);
bRegOut = ReadIndexedReg(pContext, dwEndpoint, OUT_CSR2_REG_OFFSET);
}
// Clear the in register - Must set the Mode_in to IN
WriteIndexedReg(pContext, dwEndpoint, IN_CSR2_REG_OFFSET,(SET_MODE_IN | IN_DMA_INT_DISABLE));
WriteIndexedReg(pContext, dwEndpoint, IN_CSR1_REG_OFFSET, ( IN_CLR_DATA_TOGGLE));
// Clear the Out register - Must set the Mode_in to OUT
WriteIndexedReg(pContext, dwEndpoint, IN_CSR2_REG_OFFSET, (IN_DMA_INT_DISABLE)); // mode_in bit = OUT
WriteIndexedReg(pContext, dwEndpoint, OUT_CSR1_REG_OFFSET, (FLUSH_OUT_FIFO | OUT_CLR_DATA_TOGGLE));
WriteIndexedReg(pContext, dwEndpoint, OUT_CSR2_REG_OFFSET, OUT_DMA_INT_DISABLE);
if(peps->fInitialized) {
// Set the Mode_In, ISO and other Modality type bits back to the way it was - this allows
// ResetEndpoint to be called without having to re-init the endpoint.
WriteIndexedReg(pContext, dwEndpoint, IN_CSR2_REG_OFFSET, bRegIn);
WriteIndexedReg(pContext, dwEndpoint, OUT_CSR2_REG_OFFSET, bRegOut);
}
// Clear and disable interrupt
WriteReg(pContext, EP_INT_REG_OFFSET, EpToIrqStatBit(peps->dwEndpointNumber));
DisableEndpointInterrupt(pContext, peps->dwEndpointNumber);
}
else {
DEBUGCHK(FALSE);
}
FUNCTION_LEAVE_MSG();
}
// Reset the device and EP0.
static
VOID
ResetDevice(
PCTRLR_PDD_CONTEXT pContext
)
{
SETFNAME();
FUNCTION_ENTER_MSG();
DEBUGCHK(IS_VALID_SC2440_CONTEXT(pContext));
// Disable Device interrupts - write Zeros to Disable
WriteReg(pContext, USB_INT_EN_REG_OFFSET, 0 );
// Disable endpoint interrupts - write Zeros to Disable
WriteReg(pContext, EP_INT_EN_REG_OFFSET, 0);
// Clear any outstanding device & endpoint interrupts
// USB Device Interrupt Status - Write a '1' to Clear
WriteReg(pContext, USB_INT_REG_OFFSET,
(USB_RESET_INTR | USB_RESUME_INTR | USB_SUSPEND_INTR));
// End point Interrupt Status - Write a '1' to Clear
WriteReg(pContext, EP_INT_REG_OFFSET, CLEAR_ALL_EP_INTRS);
// 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);
DWORD dwCurrentPermissions = GetCurrentPermissions();
SetProcPermissions(pTransfer->dwCallerPermissions);
__try {
volatile ULONG *pulFifoReg = _GetDataRegister(dwEndpoint);
DEBUGCHK(pulFifoReg != NULL);
PBYTE pbBuffer = (PBYTE)pTransfer->pvBuffer + pTransfer->cbTransferred;
DWORD cbBuffer = pTransfer->cbBuffer - pTransfer->cbTransferred;
DWORD cbFifo = ReadIndexedReg(pContext, dwEndpoint, OUT_FIFO_CNT1_REG_OFFSET);
DEBUGCHK(cbFifo <= peps->dwPacketSizeAssigned);
// Read from the FIFO
const DWORD cbRead = min(cbFifo, cbBuffer);
DWORD cbToRead = cbRead;
while (cbToRead--) {
*pbBuffer++ = (BYTE) *pulFifoReg;
}
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;
}
if (dwEndpoint == 0) {
bRet |= SERVICED_OUT_PKT_RDY;
if (fCompleted) {
bRet |= DATA_END;
pContext->Ep0State = EP0_STATE_IDLE;
}
}
else {
// Clear Out Packet Ready - Allow next packet to come in.
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;
}
SetProcPermissions(dwCurrentPermissions);
DEBUGMSG(ZONE_RECEIVE, (_T("%s Rx Ep%x BufferSize=%u,Xfrd=%u \r\n"),
pszFname, dwEndpoint, pTransfer->cbBuffer, pTransfer->cbTransferred));
if (fCompleted) {
DEBUGMSG(ZONE_RECEIVE, (_T("%s RxDone 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;
if (pTransfer) {
ValidateTransferDirection(pContext, peps, pTransfer);
DEBUGCHK(pTransfer->dwFlags == USB_IN_TRANSFER);
DEBUGCHK(pTransfer->dwUsbError == UFN_NOT_COMPLETE_ERROR);
DWORD dwCurrentPermissions = GetCurrentPermissions();
SetProcPermissions(pTransfer->dwCallerPermissions);
// Transfer is ready
__try {
PBYTE pbBuffer = (PBYTE) 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
DWORD cbToWrite = min(cbBuffer, peps->dwPacketSizeAssigned);
BYTE bRegStatus = ReadIndexedReg(pContext, dwEndpoint,
IN_CSR1_REG_OFFSET);
DEBUGMSG(ZONE_SEND, (_T("%s Tx on EP %u, Bytes = %u\r\n"),
pszFname, dwEndpoint, cbToWrite));
if (dwEndpoint == 0) {
for (cbWritten = 0; cbWritten < cbToWrite; cbWritten++) {
*pulFifoReg = *pbBuffer++;
}
/* 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 += cbWritten;
if (pTransfer->cbTransferred == pTransfer->cbBuffer && pTransfer->pvPddData == 0) {
dwStatus = UFN_NO_ERROR;
fCompleted = TRUE;
pContext->Ep0State = EP0_STATE_IDLE;
bRet |= DATA_END;
}
/* Update the register - Set the IPR bit
and possibly data end*/
if( (cbWritten > 0) || (pTransfer->cbBuffer == 0) ) {
bRet |= EP0_IN_PACKET_RDY;
}
// Also set IPR if a 0 byte packet needs to go out.
else if(pTransfer->pvPddData) {
bRet |= EP0_IN_PACKET_RDY;
pTransfer->pvPddData = 0;
}
}
else {
// 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);
}
// Write to the FIFO directly to send the bytes.
for (cbWritten = 0; cbWritten < cbToWrite; cbWritten++) {
*pulFifoReg = (ULONG) *pbBuffer++;
}
// 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;
}
else {
/* Set In Packet Ready , this will Tells the HW the FIFO is
ready to be transitted to be sent
*/
bRet |= IN_PACKET_READY;
}
// Update the Transfered Count
pTransfer->cbTransferred += cbWritten;
}
}
__except(EXCEPTION_EXECUTE_HANDLER) {
DEBUGMSG(ZONE_ERROR, (_T("%s Exception!\r\n"), pszFname));
fCompleted = TRUE;
dwStatus = UFN_CLIENT_BUFFER_ERROR;
}
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 (peps->dwEndpointNumber != 0) {
DisableEndpointInterrupt(pContext, peps->dwEndpointNumber);
}
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));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -