📄 cpipe.cpp
字号:
if (MaxLength == (DWORD)-1) {
// zero-length transfer
pTD->paCurBuffer = 0;
pTD->paBufferEnd = 0;
} else {
DEBUGCHK( MaxLength <= 0x2000 /*8K*/ );
pTD->paCurBuffer = paBuffer;
pTD->paBufferEnd = paBuffer+MaxLength;
}
}
// ******************************************************************
// Scope: public
CQueuedPipe::CQueuedPipe( IN const LPCUSB_ENDPOINT_DESCRIPTOR lpEndpointDescriptor,
IN const BOOL fIsLowSpeed,
IN const UCHAR bDeviceAddress,
IN CUhcd * const pCUhcd)
//
// Purpose: Constructor for CQueuedPipe
//
// Parameters: See CPipe::CPipe
//
// Returns: Nothing
//
// Notes: Do not modify static variables here!!
// ******************************************************************
: CPipe( lpEndpointDescriptor, fIsLowSpeed, bDeviceAddress,pCUhcd ) // constructor for base class
, m_fIsReclamationPipe( FALSE ) // this gets set to TRUE later as need arises
//, m_dataToggle( 1 ) // data toggle for this pipe
{
DEBUGMSG( ZONE_PIPE && ZONE_VERBOSE, (TEXT("+CQueuedPipe::CQueuedPipe\n")) );
DEBUGMSG( ZONE_PIPE && ZONE_VERBOSE, (TEXT("-CQueuedPipe::CQueuedPipe\n")) );
}
// ******************************************************************
// Scope: public virtual
CQueuedPipe::~CQueuedPipe( )
//
// Purpose: Destructor for CQueuedPipe
//
// Parameters: None
//
// Returns: Nothing
//
// Notes: Do not modify static variables here!!
// ******************************************************************
{
DEBUGMSG( ZONE_PIPE && ZONE_VERBOSE, (TEXT("+CQueuedPipe::~CQueuedPipe\n")) );
// queue should be freed via ClosePipe before calling destructor
DEBUGMSG( ZONE_PIPE && ZONE_VERBOSE, (TEXT("-CQueuedPipe::~CQueuedPipe\n")) );
}
// ******************************************************************
// Scope: public (Implements CPipe::ClosePipe = 0)
HCD_REQUEST_STATUS CQueuedPipe::ClosePipe( void )
//
// Purpose: Abort any transfers associated with this pipe, and
// remove its data structures from the schedule
//
// Parameters: None
//
// Returns: requestOK
//
// Notes:
// ******************************************************************
{
HCD_REQUEST_STATUS status = requestOK;
DEBUGMSG( ZONE_PIPE, (TEXT("+CQueuedPipe(%s)::ClosePipe\n"), GetPipeType() ) );
// Don't enter CS before calling AbortTransfer, since
// that function will need to leave the pipe CS
// at a certain point to avoid deadlock, and
// won't be able to do so if the CS is nested.
while (m_fTransferInProgress)
AbortTransfer( NULL, // callback function
NULL, // callback param
m_transfer.lpvCancelId );
EnterCriticalSection( &m_csPipeLock );
// transfer was either never issued, finished before we got to
// this function, or aborted above.
DEBUGCHK( !m_fTransferInProgress );
m_pED->bfSkip = 1;
m_pCUhcd->CHW::WaitOneFrame();
ULONG *pNextPhys = GetListHead(FALSE);
ULONG thisPhys = GetQHPhysAddr(m_pED);
while (*pNextPhys != 0 && *pNextPhys != thisPhys) {
P_ED pnext = (P_ED) m_pCUhcd->CHCCAera::m_pCPhysMem->PaToVa(*pNextPhys);
pNextPhys = &pnext->paNextEd;
}
if (*pNextPhys == 0) {
DEBUGMSG(ZONE_WARNING, (TEXT("!CQueuedPipe(%s)::ClosePipe %08x doesn't exist!\n"), GetPipeType(), m_pED));
status = requestFailed;
} else {
DEBUGCHK( *pNextPhys == thisPhys );
*pNextPhys = m_pED->paNextEd;
DEBUGCHK( (m_pED->paTdQueueHead & ~3) == m_pED->paTdQueueTail );
DEBUGCHK( (m_pED->paTdQueueHead & ~3) == m_pCUhcd->CHCCAera::m_pCPhysMem->VaToPa((PUCHAR)m_pDummyTd.td) );
m_pCUhcd->CHCCAera::m_pCPhysMem->FreeMemory((PUCHAR)m_pDummyTd.td, m_pCUhcd->CHCCAera::m_pCPhysMem->VaToPa((PUCHAR)m_pDummyTd.td),
GetMemoryAllocationFlags());
m_pDummyTd.td = 0;
m_pCUhcd->CHCCAera::m_pCPhysMem->FreeMemory((PUCHAR)m_pED, m_pCUhcd->CHCCAera::m_pCPhysMem->VaToPa((PUCHAR)m_pED),
GetMemoryAllocationFlags());
m_pED = 0;
}
(void) GetListHead(TRUE);
LeaveCriticalSection( &m_csPipeLock );
DEBUGMSG( ZONE_PIPE, (TEXT("-CQueuedPipe(%s)::ClosePipe\n"), GetPipeType() ) );
return status;
}
// ******************************************************************
// Scope: public (implements CPipe::AbortTransfer = 0)
HCD_REQUEST_STATUS CQueuedPipe::AbortTransfer(
IN const LPTRANSFER_NOTIFY_ROUTINE lpCancelAddress,
IN const LPVOID lpvNotifyParameter,
IN LPCVOID lpvCancelId )
//
// Purpose: Abort any transfer on this pipe if its cancel ID matches
// that which is passed in.
//
// Parameters: lpCancelAddress - routine to callback after aborting transfer
//
// lpvNotifyParameter - parameter for lpCancelAddress callback
//
// lpvCancelId - identifier for transfer to abort
//
// Returns: requestOK if transfer aborted
// requestFailed if lpvCancelId doesn't match currently executing
// transfer, or if there is no transfer in progress
//
// Notes:
// ******************************************************************
{
DEBUGMSG( ZONE_TRANSFER, (TEXT("+CQueuedPipe(%s)::AbortTransfer - lpvCancelId = 0x%x\n"), GetPipeType(), lpvCancelId) );
HCD_REQUEST_STATUS status = requestFailed;
STransfer *pTransfer = 0;
EnterCriticalSection( &m_csPipeLock );
if (m_fTransferInProgress) {
if (m_transfer.lpvCancelId == lpvCancelId) {
// Now we need to ensure that the hardware is no longer accessing
// the TDs which made up this transfer. Accomplish this by skipping
// the ED, relinquishing the critsec, and waiting for the next frame.
// At the start of the next frame, the WDH interrupt should fire and
// that will cause the CFDT thread (which has higher priority than
// whoever is calling AbortTransfer) to run. CFDT will flush leftover
// TDs (and potentially complete the transfer pre-abortion).
m_pED->bfSkip = 1;
// Wait for all TDs being held by hardware are released.
P_TD pTD;
for(DWORD dwIndex=0;dwIndex<1000;dwIndex++) {
LeaveCriticalSection( &m_csPipeLock );
m_pCUhcd->CHW::WaitOneFrame();
EnterCriticalSection( &m_csPipeLock );
pTD = m_pDummyTd.td;
if (m_fTransferInProgress && m_transfer.lpvCancelId == lpvCancelId) { // Still in the this transfer.
if ( m_transfer.numTDsComplete>0 && m_transfer.numTDsComplete < m_transfer.numTDsInList)
pTD = &(m_transfer.vaTDList.td[m_transfer.numTDsComplete]);
if ( GetTDPhysAddr(pTD) == (m_pED->paTdQueueHead & ~3)) // No more outstanding TD
break;
}
else
break;
}
if (!m_fTransferInProgress || m_transfer.lpvCancelId != lpvCancelId) {
// Too late; the transfer already completed.
m_pED->bfSkip = 0;
pTransfer = NULL;
} else {
ASSERT(GetTDPhysAddr(pTD) == (m_pED->paTdQueueHead & ~3));
// Set the discard bit on any TDs not yet processed in the done queue
// Since the CFDT thread has higher priority than this thread, the fact
// that we are executing here means it's OK to tweak the bits.
m_pDummyTd.td->bfDiscard = 1;
for (int i = 1; i < m_transfer.numTDsInList; ++i) {
m_transfer.vaTDList.td[i].bfDiscard = 1;
}
// We need to complete the transfer ourselves
m_pED->paTdQueueHead = m_pED->paTdQueueTail = GetTDPhysAddr( m_pDummyTd.td );
m_pED->bfSkip = 0;
pTransfer = &m_transfer;
}
} else {
// Transfer is not the current one so just nuke it from the list of pending transfers
for (pTransfer = &m_transfer;
pTransfer != NULL && pTransfer->lpvCancelId != lpvCancelId;
pTransfer = pTransfer->lpNextTransfer)
if (pTransfer->lpNextTransfer == m_pLastTransfer)
// if anything gets removed, it'll be the last one in the list;
// otherwise, we'll need to reset this later.
m_pLastTransfer = pTransfer;
if (pTransfer == NULL && m_pLastTransfer->lpNextTransfer != NULL)
// oops - didn't find one, so reset my state
m_pLastTransfer = m_pLastTransfer->lpNextTransfer;
}
}
if ( pTransfer != NULL ) {
DEBUGCHK( pTransfer->lpvCancelId == lpvCancelId );
DEBUGCHK( AreTransferParametersValid(pTransfer) );
DWORD dwOldPermissions = SetProcPermissions(m_transfer.dwCurrentPermissions);
__try { // accessing caller's memory
*pTransfer->lpdwError = USB_CANCELED_ERROR;
*pTransfer->lpfComplete = TRUE;
*pTransfer->lpdwBytesTransferred = 0;
} __except( EXCEPTION_EXECUTE_HANDLER ) {
}
SetProcPermissions(dwOldPermissions);
// cache the callback info because *pTransfer will be transmogrified
LPTRANSFER_NOTIFY_ROUTINE lpfnCompletion = pTransfer->lpfnCallback;
LPVOID lpvParam = pTransfer->lpvCallbackParameter;
STransfer *pNext = pTransfer->lpNextTransfer;
if (pNext == m_pLastTransfer)
m_pLastTransfer = pTransfer;
FreeTransferMemory(pTransfer);
if (pNext) {
*pTransfer = *pNext; // yes, yes, it's a copy.
delete pNext;
} else {
if (m_pLastTransfer == pTransfer) {
// this is the only transfer in the queue
DEBUGCHK( pTransfer == &m_transfer );
m_fTransferInProgress = FALSE;
m_pLastTransfer = NULL;
} else {
DEBUGCHK( m_pLastTransfer->lpNextTransfer == pTransfer );
m_pLastTransfer->lpNextTransfer = NULL;
}
}
// from this point on, pTransfer is no longer what it was.
if (pTransfer == &m_transfer && m_pLastTransfer != NULL)
ScheduleTransfer();
// ok, transfer has been aborted. Perform callback if needed.
if ( lpfnCompletion ) {
__try { // calling the transfer complete callback
( *lpfnCompletion )( lpvParam );
} __except( EXCEPTION_EXECUTE_HANDLER ) {
DEBUGMSG( ZONE_ERROR, (TEXT("CQueuedPipe::AbortTransfer - exception executing completion callback function\n")) );
}
}
if ( lpCancelAddress ) {
__try { // calling the Cancel function
( *lpCancelAddress )( lpvNotifyParameter );
} __except( EXCEPTION_EXECUTE_HANDLER ) {
DEBUGMSG( ZONE_ERROR, (TEXT("CQueuedPipe::AbortTransfer - exception executing cancellation callback function\n")) );
}
}
status = requestOK;
}
LeaveCriticalSection( &m_csPipeLock );
DEBUGMSG( ZONE_TRANSFER, (TEXT("-CQueuedPipe(%s)::AbortTransfer - lpvCancelId = 0x%x, returning HCD_REQUEST_STATUS %d\n"), GetPipeType(), lpvCancelId, status) );
return status;
}
// ******************************************************************
// Scope: private
void CQueuedPipe::AbortQueue( void )
//
// Purpose: Abort the current transfer (i.e., queue of TDs).
//
// Parameters: pQH - pointer to Queue Head for transfer to abort
//
// Returns: Nothing
//
// Notes: not used for OHCI
// ******************************************************************
{
DEBUGCHK(0);
}
// ******************************************************************
// Scope: protected (Implements CPipe::CheckForDoneTransfers = 0)
BOOL CQueuedPipe::CheckForDoneTransfers( void )
//
// Purpose: Check if the transfer on this pipe is finished, and
// take the appropriate actions - i.e. remove the transfer
// data structures and call any notify routines
//
// Parameters: None
//
// Returns: TRUE if transfer is done, else FALSE
//
// Notes:
// *****************************************************************
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -