📄 sc2440pdd.cpp
字号:
FUNCTION_LEAVE_MSG();
} // DisableEndpointInterrupt
/*++
Routine Description:
Clear the interrupt status register index of an endpoint.
Arguments:
dwEndpoint - the target endpoint
Return Value:
None.
--*/
static
VOID
ClearEndpointInterrupt(
PCTRLR_PDD_CONTEXT pContext,
DWORD dwEndpoint
)
{
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_PKY_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, IN_CSR2_REG_OFFSET, bRegOut);
}
}
else {
DEBUGCHK(FALSE);
}
// Clear any outstanding Interrupts
// Note that Endpoint 0 WILL NOT BE DISABLED
DisableEndpointInterrupt(pContext, peps->dwEndPointNumber);
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
VOID
HandleRx(
PCTRLR_PDD_CONTEXT pContext,
PEP_STATUS peps
)
{
DWORD dwBytesRead = 0;
BOOL fCompleted = FALSE;
DWORD dwStatus = ERROR_GEN_FAILURE;
DWORD dwEndpoint = peps->dwEndPointNumber;
SETFNAME();
PSTransfer pTransfer = peps->pTransfer;
pTransfer = peps->pTransfer;
if (pTransfer) {
FUNCTION_ENTER_MSG();
DEBUGCHK(pTransfer->dwFlags == USB_OUT_TRANSFER);
DEBUGCHK(pTransfer->dwUsbError == UFN_NOT_COMPLETE_ERROR);
ValidateTransferDirection(pContext, peps, pTransfer);
DEBUGCHK(peps->fInitialized);
DWORD cbToRead = 0;
volatile ULONG *pulFifoReg = _GetDataRegister(dwEndpoint);
DEBUGCHK(pulFifoReg != NULL);
DWORD dwCurrentPermissions = GetCurrentPermissions();
SetProcPermissions(pTransfer->dwCallerPermissions);
__try {
PBYTE pbBuffer = (PBYTE)pTransfer->pvBuffer + pTransfer->cbTransferred;
PUSB_DEVICE_REQUEST udr = (PUSB_DEVICE_REQUEST) pbBuffer;
DWORD cbBuffer = pTransfer->cbBuffer - pTransfer->cbTransferred;
DWORD cbRead =0;
DWORD cbFifo = ReadIndexedReg(pContext, dwEndpoint, OUT_FIFO_CNT1_REG_OFFSET);
// Read From the FIFO
dwBytesRead = 0;
cbToRead = min(cbFifo, cbBuffer);
for (dwBytesRead = 0; dwBytesRead < cbToRead ; dwBytesRead++) {
pbBuffer [dwBytesRead] = (UCHAR) *pulFifoReg;
}
if(dwBytesRead < peps->dwPacketSizeAssigned) {
// This is a short packet check to signal end of transfer
fCompleted = TRUE;
dwStatus = UFN_NO_ERROR;
}
cbRead = dwBytesRead;
DEBUGCHK(cbRead <= pTransfer->cbBuffer - pTransfer->cbTransferred);
pTransfer->cbTransferred += cbRead;
if (pTransfer->cbTransferred == pTransfer->cbBuffer) {
fCompleted = TRUE;
dwStatus = UFN_NO_ERROR;
}
if (dwEndpoint != 0) {
//Clear Receive Packet Complete - Allow next packet to come in.
BYTE bEpIrqStat = ReadIndexedReg(pContext, peps->dwEndPointNumber,OUT_CSR1_REG_OFFSET);
if (bEpIrqStat & OUT_PACKET_READY) {
SetClearIndexedReg(pContext,dwEndpoint,OUT_CSR1_REG_OFFSET,
OUT_PACKET_READY, CLEAR);
}
}
}
__except(EXCEPTION_EXECUTE_HANDLER) {
DEBUGMSG(ZONE_ERROR, (_T("%s Exception!\r\n"), pszFname));
fCompleted = TRUE;
dwStatus = UFN_CLIENT_BUFFER_ERROR;
}
SetProcPermissions(dwCurrentPermissions);
}
else {
goto EXIT;
}
DEBUGMSG(ZONE_RECEIVE, (_T("%s Rx Ep%x BufferSize=%u,Xfrd=%u \r\n"),
pszFname, dwEndpoint, pTransfer->cbBuffer, pTransfer->cbTransferred));
if (fCompleted) {
// Disable transfer interrupts until another transfer is issued.
if (peps->dwEndPointNumber != 0) {
ClearEndpointInterrupt(pContext, peps->dwEndPointNumber);
DisableEndpointInterrupt(pContext, peps->dwEndPointNumber);
}
CompleteTransfer(pContext, peps, dwStatus);
DEBUGMSG(ZONE_RECEIVE, (_T("%s RxDone Ep%x BufferSize=%u,Xfrd=%u \r\n"),
pszFname, dwEndpoint,pTransfer->cbBuffer, pTransfer->cbTransferred));
}
EXIT:
FUNCTION_LEAVE_MSG();
}
// Write data to an endpoint.
static VOID
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();
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);
BYTE bValToWrite = 0;
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);
if (dwEndpoint == 0) {
for (cbWritten = 0; cbWritten < cbToWrite; cbWritten++) {
*pulFifoReg = (ULONG)*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) {
dwStatus = UFN_NO_ERROR;
if(cbWritten != peps->dwPacketSizeAssigned){
fCompleted = TRUE;
peps->dwEpState = EP_STATE_IDLE;
bValToWrite |= DATA_END;
}
}
/* Update the register - Set the IPR bit
and possibly data end*/
if( (cbWritten >0) || (pTransfer->cbBuffer == 0) ) {
bValToWrite |= EP0_IN_PACKET_RDY;
}
// Also set IPR if a 0 byte packet needs to go out.
else if( (pTransfer->cbTransferred == pTransfer->cbBuffer) &&
(pTransfer->cbBuffer % peps->dwPacketSizeAssigned == 0) ) {
bValToWrite |= EP0_IN_PACKET_RDY;
}
SetClearIndexedReg(pContext, dwEndpoint,
IN_CSR1_REG_OFFSET, bValToWrite, SET);
}
else if (dwEndpoint < ENDPOINT_COUNT) {
DEBUGMSG(ZONE_SEND, (_T("%s Tx on EP %u , Bytes = %u\r\n"),
pszFname, dwEndpoint,cbToWrite));
// Enable Interrupts before writing to the FIFO. This insures
// That any interrupts generated because of the write will be
// "latched"
if (fEnableInterrupts)
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
*/
SetClearIndexedReg(pContext, dwEndpoint,
IN_CSR1_REG_OFFSET, IN_PACKET_READY, SET);
}
// 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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -