📄 trans.cpp
字号:
CQTD * pPrevTD=m_pCQTDList;
if ( m_pCQTDList==NULL && m_sTransfer.dwBufferSize == 0 ) { // No Control but Zero Length
ASSERT((m_sTransfer.dwFlags & USB_IN_TRANSFER)==0);// No meaning for IN Zero length packet.
CQTD * pCurTD = new( m_pCPhysMem) CQTD(this, ((CQueuedPipe * const)m_pCPipe)->GetQHead());
if (pCurTD) {
PhysBufferArray bufferArray;
bufferArray.dwNumOfBlock=0;
bufferArray.dwBlockSize=0;
bufferArray.dwStartOffset=0;
bufferArray.dwArrayBlockAddr[0]=0;
bufferArray.dwArrayBlockAddr[1]=0;// Terminate
pCurTD->IssueTransfer( (m_sTransfer.dwFlags & USB_IN_TRANSFER)!=0? TD_IN_PID: TD_OUT_PID,
bDataToggle1, 0 ,&bufferArray,TRUE);
if (pPrevTD) {
pPrevTD->QueueNextTD(pCurTD);
pPrevTD=pCurTD;
}
else { // THis is First. So update m_pQTDList
pPrevTD= m_pCQTDList = pCurTD;
}
}
else {
if ( pStatusTD) {
pStatusTD->~CQTD();
m_pCPhysMem->FreeMemory((PBYTE)pStatusTD,m_pCPhysMem->VaToPa((PBYTE)pStatusTD), CPHYSMEM_FLAG_HIGHPRIORITY | CPHYSMEM_FLAG_NOBLOCK );
}
return FALSE;
}
}
else
if (m_sTransfer.lpvBuffer && m_sTransfer.paBuffer && m_sTransfer.dwBufferSize) {
DWORD dwCurPos=0;
while ( dwCurPos< m_sTransfer.dwBufferSize) {
CQTD * pCurTD = new( m_pCPhysMem) CQTD(this, ((CQueuedPipe * const)m_pCPipe)->GetQHead());
ASSERT(pCurTD!=NULL);
if (pCurTD==NULL) {
// delete pStatusTD;
if ( pStatusTD) {
pStatusTD->~CQTD();
m_pCPhysMem->FreeMemory((PBYTE)pStatusTD,m_pCPhysMem->VaToPa((PBYTE)pStatusTD), CPHYSMEM_FLAG_HIGHPRIORITY | CPHYSMEM_FLAG_NOBLOCK );
}
return FALSE;
}
DWORD dwCurPhysAddr= m_sTransfer.paBuffer + dwCurPos;
// We only can queue maximun 4 page for one TD and Align with Packet Size.
// Note: Even though we can limit to 16K, but if start offset != 0, it would require 5 buffer pointers, instead of 4.
DWORD dwPacketSize= (m_pCPipe->GetEndptDescriptor()).wMaxPacketSize & 0x7ff;
ASSERT(dwPacketSize!=0);
DWORD dwCurLength = ((EHCI_PAGE_SIZE * MAX_QTD_PAGE_SIZE)/dwPacketSize)*dwPacketSize;
dwCurLength = min( m_sTransfer.dwBufferSize- dwCurPos,dwCurLength);
PhysBufferArray bufferArray;
bufferArray.dwStartOffset= dwCurPhysAddr & EHCI_PAGE_OFFSET_MASK;
bufferArray.dwNumOfBlock= (bufferArray.dwStartOffset + dwCurLength + EHCI_PAGE_SIZE -1 ) /EHCI_PAGE_SIZE;
ASSERT(bufferArray.dwNumOfBlock<=(MAX_QTD_PAGE_SIZE+1) && bufferArray.dwNumOfBlock!=0);
bufferArray.dwBlockSize = min (bufferArray.dwStartOffset + m_sTransfer.dwBufferSize- dwCurPos,EHCI_PAGE_SIZE);
for (DWORD dwIndex=0;dwIndex<bufferArray.dwNumOfBlock+1 && dwIndex<5;dwIndex++) {
bufferArray.dwArrayBlockAddr[dwIndex] = (dwCurPhysAddr & EHCI_PAGE_ADDR_MASK);
dwCurPhysAddr += EHCI_PAGE_SIZE;
}
DWORD dwReturnLength = pCurTD->IssueTransfer( (m_sTransfer.dwFlags & USB_IN_TRANSFER)!=0?TD_IN_PID:TD_OUT_PID,
bDataToggle1, dwCurLength,&bufferArray,TRUE);
ASSERT(dwReturnLength == dwCurLength);
// Setup for Short Packet
if ( pStatusTD) {
pCurTD->SetAltNextQTDPointer(pStatusTD->GetPhysAddr());
}
DWORD dwNumOfPacket = (dwReturnLength + dwPacketSize-1)/dwPacketSize;
dwCurPos += dwReturnLength;
if (pPrevTD) {
pPrevTD->QueueNextTD(pCurTD);
pPrevTD=pCurTD;
}
else { // THis is First. So update m_pQTDList
pPrevTD= m_pCQTDList = pCurTD;
}
if ((dwNumOfPacket & 1)!=0) // if it is odd packet number. Toggle the data toggle.
bDataToggle1 = !bDataToggle1;
}
}
// We have to append Status TD here.
if (pStatusTD) { // This is setup packet.
if (pPrevTD) {
pPrevTD->QueueNextTD(pStatusTD);
pPrevTD=pStatusTD;
}
else { // Something Wrong.
ASSERT(FALSE);
//delete pCurTD;
pStatusTD->~CQTD();
m_pCPhysMem->FreeMemory((PBYTE)pStatusTD,m_pCPhysMem->VaToPa((PBYTE)pStatusTD), CPHYSMEM_FLAG_HIGHPRIORITY | CPHYSMEM_FLAG_NOBLOCK );
return FALSE;
}
};
return TRUE;
}
//***********************************************************************************************
BOOL CQTransfer::DoneTransfer()
//
// Purpose: Check if transfer is done and success, acknowledge back into MDD
//
// Parameters: None
//
// Returns: TRUE - success, FALSE - failure
//
// Notes:
// ******************************************************************
{
DEBUGMSG( ZONE_TRANSFER && ZONE_VERBOSE, (TEXT("CQTransfer::DoneTransfer (this=0x%x,id=0x%x)\r\n"),this,m_dwTransferID));
BOOL bIsTransDone = IsTransferDone();
ASSERT(bIsTransDone == TRUE);
if (bIsTransDone && !m_fDoneTransferCalled) {
DWORD dwUsbError = USB_NO_ERROR;
DWORD dwDataNotTransferred = 0;
m_fDoneTransferCalled = TRUE;
CQTD * pCurTD = m_pCQTDList;
BOOL bReturn=TRUE;
while ( pCurTD!=NULL) {
pCurTD->CheckStructure();
if ( pCurTD->qTD_Token.qTD_TContext.PID != 2) // Do not count Setup TD
dwDataNotTransferred += pCurTD ->qTD_Token.qTD_TContext.BytesToTransfer ;
if (pCurTD->qTD_Token.qTD_TContext.Halted==1) { // This Transfer Has been halted due to error.
// This is error. We do not have error code for EHCI so generically we set STALL error.
if (pCurTD->qTD_Token.qTD_TContext.BabbleDetected) {// Babble.
dwUsbError = USB_DATA_OVERRUN_ERROR ;
}
else if (pCurTD->qTD_Token.qTD_TContext.DataBufferError) {
dwUsbError = ((m_sTransfer.dwFlags &USB_IN_TRANSFER)!=0? USB_BUFFER_OVERRUN_ERROR : USB_BUFFER_UNDERRUN_ERROR);
}
else if (dwUsbError == USB_NO_ERROR)
dwUsbError = USB_STALL_ERROR;
}
else
if (pCurTD->qTD_Token.qTD_TContext.Active ==1) {
if (dwUsbError == USB_NO_ERROR)
dwUsbError = USB_NOT_COMPLETE_ERROR;
break;
}
pCurTD = pCurTD->GetNextTD();
}
ASSERT(dwDataNotTransferred <= m_sTransfer.dwBufferSize);
if (dwDataNotTransferred >= m_sTransfer.dwBufferSize)
dwDataNotTransferred = m_sTransfer.dwBufferSize;
m_DataTransferred = m_sTransfer.dwBufferSize - dwDataNotTransferred ;
// We have to update the buffer when this is IN Transfer.
if ((m_sTransfer.dwFlags & USB_IN_TRANSFER)!=NULL && m_pAllocatedForClient!=NULL && m_sTransfer.dwBufferSize!=0) {
__try { // copying client buffer for OUT transfer
memcpy( m_sTransfer.lpvBuffer, m_pAllocatedForClient, m_sTransfer.dwBufferSize );
} __except( EXCEPTION_EXECUTE_HANDLER ) {
// bad lpvBuffer.
if (dwUsbError == USB_NO_ERROR)
dwUsbError = USB_CLIENT_BUFFER_ERROR;
}
}
if (m_fCanceled && dwUsbError == USB_NO_ERROR) {
dwUsbError = USB_CANCELED_ERROR ;
}
__try { // setting transfer status and executing callback function
if (m_sTransfer.lpfComplete !=NULL)
*m_sTransfer.lpfComplete = TRUE;
if (m_sTransfer.lpdwError!=NULL)
*m_sTransfer.lpdwError = dwUsbError;
if (m_sTransfer.lpdwBytesTransferred)
*m_sTransfer.lpdwBytesTransferred = m_DataTransferred;
if ( m_sTransfer.lpStartAddress ) {
( *m_sTransfer.lpStartAddress )(m_sTransfer.lpvNotifyParameter );
m_sTransfer.lpStartAddress = NULL ; // Make sure only do once.
}
} __except( EXCEPTION_EXECUTE_HANDLER ) {
DEBUGMSG( ZONE_ERROR, (TEXT("CQueuedPipe(%s)::CheckForDoneTransfers - exception setting transfer status to complete\n"), m_pCPipe->GetPipeType() ) );
}
return (dwUsbError==USB_NO_ERROR);
}
else
return TRUE;
}
//**********************************************************************************
BOOL CQTransfer::AbortTransfer()
//
// Purpose: Abort the current transfer
//
// Parameters: None
//
// Returns: TRUE - success, FALSE - failure
//
// Notes:
// ******************************************************************
{
DEBUGMSG( ZONE_TRANSFER && ZONE_VERBOSE, (TEXT("CQTransfer::AbortTransfer (this=0x%x,id=0x%x)\r\n"),this,m_dwTransferID));
CQTD * pCurTD = m_pCQTDList;
while ( pCurTD!=NULL) {
pCurTD->DeActiveTD();
pCurTD = pCurTD->GetNextTD();
}
m_fCanceled = TRUE;
Sleep(2);// Make sure the shcdule has advanced. and current Transfer has completeded.
return TRUE;
}
//*********************************************************************
BOOL CQTransfer::IsTransferDone()
//
// Purpose: This is to read the current transfer descriptor and see if there is
// any error or if the transfer is still active.
//
// Parameters: None
//
// Returns: TRUE - completed, FALSE - not completed
//
// Notes:
// ******************************************************************
{
DEBUGMSG( ZONE_TRANSFER && ZONE_VERBOSE, (TEXT("CQTransfer::IsTransferDone (this=0x%x,id=0x%x)\r\n"),this,m_dwTransferID));
if (m_pCQTDList==NULL) { // Has been created. Somthing wrong.
return TRUE;
}
CQTD * pCurTD = m_pCQTDList;
BOOL bReturn=TRUE;
while ( pCurTD!=NULL) {
ASSERT(pCurTD->m_pTrans == this);
if (pCurTD->qTD_Token.qTD_TContext.XactErr == 1)
RETAILMSG(1, (TEXT("TD Token: XactErr\r\n")));
if (pCurTD->qTD_Token.qTD_TContext.DataBufferError == 1)
{
if ((m_sTransfer.dwFlags & USB_IN_TRANSFER) != 0x00)
RETAILMSG(1, (TEXT("TD Token: DataBufferError in IN\r\n")));
else
RETAILMSG(1, (TEXT("TD Token: DataBufferError in OUT\r\n")));
}
if (pCurTD->qTD_Token.qTD_TContext.Halted==1) { // This Transfer Has been halted due to error.
RETAILMSG(1, (TEXT("CQTransfer: Halted\r\n")));
break;
}
if (pCurTD->qTD_Token.qTD_TContext.Active == 1) {
bReturn = FALSE;
break;
}
if (pCurTD ->GetLinkValid() == FALSE) { // No like connected. This Transfer is aborted.
break;
}
pCurTD = pCurTD ->GetNextTD();
}
DEBUGMSG( ZONE_TRANSFER && ZONE_VERBOSE, (TEXT("CQTransfer::IsTransferDone (this=0x%x) return %d \r\n"),this,bReturn));
return bReturn;
}
//*************************************************************************************************
CIsochTransfer::CIsochTransfer(IN CIsochronousPipe * const pCPipe,IN CEhcd * const pCEhcd,STransfer sTransfer)
: CTransfer(pCPipe,pCEhcd->GetPhysMem(),sTransfer)
,m_pCEhcd(pCEhcd)
//
// Purpose: Constructor of CIsochTransfer
//
// Parameters:
//
// Returns: Nothing
//
// Notes:
// ******************************************************************
{
m_dwFrameIndexStart = m_sTransfer.dwStartingFrame;
m_dwNumOfTD =0;
m_dwSchedTDIndex=0;
m_dwDequeuedTDIndex=0;
m_dwArmedTDIndex =0;
m_dwArmedBufferIndex=0;
m_dwFirstError = USB_NO_ERROR;
m_dwLastFrameIndex = 0;
};
// ******************************************************************
CITransfer::CITransfer(IN CIsochronousPipe * const pCPipe, IN CEhcd * const pCEhcd,STransfer sTransfer)
:CIsochTransfer (pCPipe, pCEhcd,sTransfer)
//
// Purpose: Constructor of High Speed Isochronous Transfer
//
// Parameters:
//
// Returns: Nothing
//
// Notes:
// ******************************************************************
{
m_pCITDList =0;
}
//*******************************************************************
CITransfer::~CITransfer()
//
// Purpose: Destructor of High Speed Isochronous Transfer
//
// Parameters:
//
// Returns: Nothing
//
// Notes:
// ******************************************************************
{
ASSERT(m_dwSchedTDIndex==m_dwNumOfTD || m_dwLastFrameIndex<m_dwNumOfTD);
ASSERT(m_dwDequeuedTDIndex == m_dwNumOfTD||m_dwLastFrameIndex<m_dwNumOfTD );
if (m_pCITDList && m_dwNumOfTD) {
AbortTransfer();
for (DWORD dwIndex=0;dwIndex<m_dwNumOfTD;dwIndex++)
if (*(m_pCITDList + dwIndex)) {
ASSERT((*(m_pCITDList + dwIndex) )->GetLinkValid() != TRUE); // Invalid Next Link
//Free *(m_pCITDList + dwIndex);
GetPipe()->FreeCITD(*(m_pCITDList + dwIndex));
*(m_pCITDList + dwIndex) = NULL;
}
delete m_pCITDList;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -