📄 trans.cpp
字号:
//*********************************************************************
BOOL CITransfer::ArmTD()
//
// Purpose: Arm/schedule the transfer descriptor - this is to setup the transfer descriptor
// and perform the IssueTransfer on the iTD to do the actual transfer. Called by
// AddTransfer()
//
// Parameters:
//
// Returns: TRUE - something has to be scheduled/armed
// FALSE - nothing
//
// Notes:
// ******************************************************************
{
BOOL bAnyArmed = FALSE;
if (m_pCITDList && m_dwArmedTDIndex<m_dwNumOfTD ) { // Something TD wait for Arm.
DWORD dwCurDataPhysAddr = m_sTransfer.paBuffer + m_dwArmedBufferIndex;
DWORD dwFrameIndex = m_dwArmedTDIndex * MAX_TRNAS_PER_ITD ;
while (dwFrameIndex< m_sTransfer.dwFrames && m_dwArmedTDIndex < m_dwNumOfTD) {
*(m_pCITDList + m_dwArmedTDIndex) = GetPipe()->AllocateCITD( this);
if (*(m_pCITDList + m_dwArmedTDIndex) == NULL)
break;
DWORD dwTransLenArray[MAX_TRNAS_PER_ITD+1]; // Reserved one for cross boundary condition
DWORD dwFrameAddrArray[MAX_TRNAS_PER_ITD+1]; // Reserved one for cross boundary condition
for (DWORD i = 0; i < MAX_TRNAS_PER_ITD+1; i++)
dwTransLenArray[i] = dwFrameAddrArray[i] = 0;
for (DWORD dwTransIndex=0; dwTransIndex < MAX_TRNAS_PER_ITD && dwFrameIndex < m_sTransfer.dwFrames ; dwTransIndex ++) {
dwTransLenArray[dwTransIndex]= *(m_sTransfer.aLengths + dwFrameIndex);
dwFrameAddrArray[dwTransIndex] = dwCurDataPhysAddr;
RETAILMSG(0, (TEXT("FrameIndex(%d):dwFrameAddrArray[%d] = 0x%x - max frame(%d)\r\n"), dwFrameIndex,dwTransIndex, dwCurDataPhysAddr, m_sTransfer.dwFrames));
dwCurDataPhysAddr +=dwTransLenArray[dwTransIndex];
m_dwArmedBufferIndex += dwTransLenArray[dwTransIndex];
dwFrameIndex ++;
}
// Not at page 6, we want to avoid the cross page boundary
// According to EHCI Specification 4.7.1, we should have one extra buffer pointer
// in case of cross-boundary.
if ((dwTransIndex > 0) && (dwTransIndex < MAX_TRNAS_PER_ITD+1 ))
{
RETAILMSG(0, (TEXT("Last dwFrameAddrArray = 0x%x\r\n"), dwFrameAddrArray[dwTransIndex-1]));
if (((dwFrameAddrArray[dwTransIndex-1]+dwTransLenArray[dwTransIndex-1]) & EHCI_PAGE_ADDR_MASK)!=
(dwFrameAddrArray[dwTransIndex-1] & EHCI_PAGE_ADDR_MASK))
{
dwFrameAddrArray[MAX_TRNAS_PER_ITD] = ((dwFrameAddrArray[dwTransIndex-1] +0x1000) & EHCI_PAGE_ADDR_MASK);
RETAILMSG(0, (TEXT("Add dwFrameAddrArray[%d] = 0x%x\r\n"), MAX_TRNAS_PER_ITD, dwFrameAddrArray[MAX_TRNAS_PER_ITD]));
}
}
if (dwTransIndex !=0) {
(*(m_pCITDList + m_dwArmedTDIndex))->IssueTransfer(
dwTransIndex,dwTransLenArray, dwFrameAddrArray,
dwFrameIndex>= m_sTransfer.dwFrames ,
(m_sTransfer.dwFlags & USB_IN_TRANSFER)!=0);
(*(m_pCITDList+ m_dwArmedTDIndex ))->SetIOC(TRUE); // Interrupt On every TD.
}
else {
ASSERT(FALSE);
break;
}
m_dwArmedTDIndex ++;
bAnyArmed=TRUE;
}
}
return bAnyArmed;
}
//***********************************************************************************************
BOOL CITransfer::AddTransfer ()
//
// Purpose: Setup all the queue transfer descriptor list and called up ArmTD to do the transfer
//
// Parameters: None
//
// Returns: TRUE - success, FALSE - failure
//
// Notes:
// ******************************************************************
{
DEBUGMSG( ZONE_TRANSFER && ZONE_VERBOSE, (TEXT("CITransfer::AddTransfer (this=0x%x,id=0x%x)\r\n"),this,m_dwTransferID));
if (m_dwNumOfTD!=0 || m_pCITDList != NULL) {
ASSERT(FALSE);
return FALSE;
}
m_dwNumOfTD = (m_sTransfer.dwFrames + MAX_TRNAS_PER_ITD-1)/MAX_TRNAS_PER_ITD;
//DEBUGMSG(1, (TEXT("CITransfer:AddTransfer: NumberOfTD(%d), dwFrames(%d)\r\n"),
// m_dwNumOfTD, m_sTransfer.dwFrames));
m_dwSchedTDIndex=0;
m_dwArmedBufferIndex=0;
m_dwArmedTDIndex = 0 ;
m_dwFirstError = USB_NO_ERROR;
if (m_sTransfer.lpvBuffer && m_sTransfer.paBuffer && m_sTransfer.dwBufferSize) {
// Allocate space for CITD List
m_pCITDList =(CITD **) new PVOID[m_dwNumOfTD];
if (m_pCITDList!=NULL) {
memset(m_pCITDList,0,sizeof(CITD *)*m_dwNumOfTD);
ArmTD();
return TRUE;
}
}
ASSERT(FALSE);
return FALSE;
}
//****************************************************************************************************
BOOL CITransfer::ScheduleTD(DWORD dwCurFrameIndex,DWORD /*dwCurMicroFrameIndex*/)
//
// Purpose: Schedule a USB Transfer on this pipe, this is used by AbortTransfer only.
//
// Parameters: dwCurrFrameIndex - current frame index
//
// Returns: requestOK if transfer issued ok, else requestFailed
//
// Notes:
//******************************************************************************************************
{
DEBUGMSG( ZONE_TRANSFER && ZONE_VERBOSE, (TEXT("CITransfer::ScheduleTD (this=0x%x,id=0x%x,curFrameIndex=0x%x)\r\n"),this,m_dwTransferID, dwCurFrameIndex));
BOOL bReturn = FALSE;
ArmTD();
if (m_dwSchedTDIndex < m_dwNumOfTD && m_pCITDList !=0 && m_pCEhcd ) {
if ((long)(dwCurFrameIndex - m_dwFrameIndexStart) > (long)m_dwSchedTDIndex) {
m_dwSchedTDIndex = dwCurFrameIndex - m_dwFrameIndexStart;
}
m_dwSchedTDIndex = min( m_dwSchedTDIndex , m_dwNumOfTD);
DWORD EndShedTDIndex = dwCurFrameIndex + (m_pCEhcd->GetPeriodicMgr()).GetFrameSize()-1;
DWORD dwNumTDCanSched;
if ( (long)(EndShedTDIndex - m_dwFrameIndexStart ) >= 0)
dwNumTDCanSched =EndShedTDIndex - m_dwFrameIndexStart ;
else // Too Early.
dwNumTDCanSched = 0;
dwNumTDCanSched= min(m_dwNumOfTD ,dwNumTDCanSched);
dwNumTDCanSched = min (m_dwArmedTDIndex, dwNumTDCanSched);
if (m_dwSchedTDIndex < dwNumTDCanSched) { // Do scudule those index.
for (DWORD dwIndex = m_dwSchedTDIndex ; dwIndex<dwNumTDCanSched; dwIndex++) {
m_pCEhcd->PeriodQueueITD(*(m_pCITDList+dwIndex),m_dwFrameIndexStart + dwIndex );
(*(m_pCITDList+dwIndex))->CheckStructure ();
ASSERT((*(m_pCITDList+dwIndex))->m_pTrans == this);
}
m_dwSchedTDIndex = dwNumTDCanSched;
bReturn = TRUE;
}
}
DEBUGMSG( ZONE_TRANSFER && ZONE_VERBOSE, (TEXT("CITransfer::ScheduleTD (this=0x%x) return %d\r\n"),this,bReturn));
return bReturn;
}
//***************************************************************************************
BOOL CITransfer::IsTransferDone(DWORD dwCurFrameIndex,DWORD /*dwCurMicroFrameIndex*/)
//
// Purpose: This is to check if the transfer has been completed for Isochronous High Speed Transfer
//
// Parameters: dwCurFrameIndex - minimal frame index to which the transfer to check against if completed.
//
// Returns: TRUE - successfully tranferred, FALSE - failure
//
// Notes:
//****************************************************************************************
{
// Dequeue those TD has Transfered.
m_dwLastFrameIndex = dwCurFrameIndex - m_dwFrameIndexStart;
if ((long)(dwCurFrameIndex - m_dwFrameIndexStart)>= 1 ) {
DWORD dwTransfered = min(dwCurFrameIndex - m_dwFrameIndexStart , m_dwSchedTDIndex);
for (DWORD dwIndex=m_dwDequeuedTDIndex;dwIndex<dwTransfered && dwIndex<m_dwNumOfTD ; dwIndex++) {
if ( *(m_pCITDList+dwIndex) != NULL ) {
ASSERT((*(m_pCITDList+dwIndex))->m_pTrans == this);
BOOL bResult =m_pCEhcd->PeriodDeQueueTD((*(m_pCITDList+dwIndex))->GetPhysAddr(),dwIndex + m_dwFrameIndexStart);
ASSERT(bResult == TRUE);
(*(m_pCITDList + dwIndex) )->SetLinkValid(FALSE);
(*(m_pCITDList+ dwIndex))->CheckStructure ();
DWORD dwFrameIndex = dwIndex * MAX_TRNAS_PER_ITD;
for (DWORD dwTrans=0; dwTrans<MAX_TRNAS_PER_ITD && dwFrameIndex< m_sTransfer.dwFrames; dwTrans++) {
DWORD dwTDError= USB_NO_ERROR;
if ((*(m_pCITDList + dwIndex))->iTD_StatusControl[dwTrans].iTD_SCContext.Active!=0)
dwTDError = USB_NOT_COMPLETE_ERROR;
else
if ((*(m_pCITDList + dwIndex))->iTD_StatusControl[dwTrans].iTD_SCContext.XactErr!=0)
dwTDError = USB_ISOCH_ERROR;
else
if ((*(m_pCITDList + dwIndex))->iTD_StatusControl[dwTrans].iTD_SCContext.BabbleDetected!=0)
dwTDError = USB_STALL_ERROR;
else
if ((*(m_pCITDList + dwIndex))->iTD_StatusControl[dwTrans].iTD_SCContext.DataBufferError!=0)
dwTDError = ((m_sTransfer.dwFlags & USB_IN_TRANSFER)!=0?USB_DATA_OVERRUN_ERROR:USB_DATA_UNDERRUN_ERROR);
if (m_dwFirstError == USB_NO_ERROR ) { // only update first time
m_dwFirstError = dwTDError;
}
DWORD dwTransLength =(*(m_pCITDList + dwIndex))->iTD_StatusControl[dwTrans].iTD_SCContext.TransactionLength;
if (dwFrameIndex< m_sTransfer.dwFrames) {
#pragma prefast(disable: 322, "Recover gracefully from hardware failure")
__try { // setting isoch OUT status parameters
m_sTransfer.adwIsochErrors[ dwFrameIndex ] = dwTDError;
// Document said length is only update for Isoch IN 3.3.2
m_sTransfer.adwIsochLengths[ dwFrameIndex ] = ((m_sTransfer.dwFlags & USB_IN_TRANSFER)!=0?
dwTransLength : *(m_sTransfer.aLengths + dwFrameIndex ));
m_DataTransferred += m_sTransfer.adwIsochLengths[ dwFrameIndex ];
} __except( EXCEPTION_EXECUTE_HANDLER ) {
}
#pragma prefast(pop)
}
dwFrameIndex ++;
}
GetPipe()->FreeCITD(*(m_pCITDList + dwIndex));
*(m_pCITDList + dwIndex) = NULL;
}
}
m_dwDequeuedTDIndex = dwIndex;
}
BOOL bReturn = ((long)(dwCurFrameIndex-m_dwFrameIndexStart)>= (long)m_dwNumOfTD);
DEBUGMSG( ZONE_TRANSFER && ZONE_VERBOSE, (TEXT("CITransfer:::IsTransferDone (this=0x%x,curFrameIndex=0x%x) return %d \r\n"),this, dwCurFrameIndex,bReturn));
return bReturn;
}
//**********************************************************************
BOOL CITransfer::AbortTransfer()
//
// Purpose: Abort current high speed isochronous transfer
//
// Parameters: None (all parameters are in m_transfer)
//
// Returns: TRUE - success, FALSE - failure
//
// Notes:
//**********************************************************************
{
DEBUGMSG( ZONE_TRANSFER && ZONE_VERBOSE, (TEXT("CITransfer::AbortTransfer (this=0x%x,id=0x%x) \r\n"),this,m_dwTransferID));
for (DWORD dwIndex=m_dwDequeuedTDIndex;dwIndex < m_dwNumOfTD && dwIndex< m_dwSchedTDIndex; dwIndex++) {
if ( *(m_pCITDList+dwIndex) != NULL) {
BOOL bResult=m_pCEhcd->PeriodDeQueueTD((*(m_pCITDList+dwIndex))->GetPhysAddr(),dwIndex + m_dwFrameIndexStart);
ASSERT(bResult == TRUE);
(*(m_pCITDList + dwIndex) )->SetLinkValid(FALSE);
DWORD dwFrameIndex = dwIndex * MAX_TRNAS_PER_ITD;
for (DWORD dwTrans=0; dwTrans<MAX_TRNAS_PER_ITD && dwFrameIndex< m_sTransfer.dwFrames; dwTrans++) {
if (dwFrameIndex< m_sTransfer.dwFrames) {
#pragma prefast(disable: 322, "Recover gracefully from hardware failure")
__try { // setting isoch OUT status parameters
m_sTransfer.adwIsochErrors[ dwFrameIndex ] = USB_NOT_COMPLETE_ERROR;;
m_sTransfer.adwIsochLengths[ dwFrameIndex ] = 0;
} __except( EXCEPTION_EXECUTE_HANDLER ) {
}
#pragma prefast(pop)
}
dwFrameIndex ++;
}
if (m_dwFirstError == USB_NO_ERROR ) { // only update first time
m_dwFirstError = USB_NOT_COMPLETE_ERROR;
}
}
}
m_dwDequeuedTDIndex = m_dwSchedTDIndex = m_dwNumOfTD;
Sleep(2); // Make Sure EHCI nolong reference to those TD;
return DoneTransfer(m_dwFrameIndexStart+m_dwNumOfTD, 0);
};
//**************************************************************************************
BOOL CITransfer::DoneTransfer(DWORD dwCurFrameIndex,DWORD dwCurMicroFrameIndex)
//
// Purpose: This is to check if high speed isochronous transfer is done through IsTransferDone, copying
// the data if IN transfer and then performing the acknowledgement back into MDD
//
// Parameters:
//
// Returns: TRUE - success, FALSE - failure
//
// Notes:
//***************************************************************************************
{
BOOL bIsTransDone = IsTransferDone(dwCurFrameIndex,dwCurMicroFrameIndex);
DEBUGMSG( ZONE_TRANSFER && ZONE_VERBOSE, (TEXT("CITransfer::DoneTransfer (this=0x%x,id=0x%x,curFrameIndex=0x%x, bIsTransDone=%d \r\n")
,this, m_dwTransferID, dwCurFrameIndex,bIsTransDone));
ASSERT(bIsTransDone == TRUE);
if (bIsTransDone && !m_fDoneTransferCalled ) {
DWORD dwUsbError = USB_NO_ERROR;
DWORD dwDataNotTransferred = 0;
DWORD dwFrameIndex =0 ;
m_fDoneTransferCalled = TRUE;
// We have to update the buffer when this is IN Transfer.
if ((m_sTransfer.dwFlags & USB_IN_TRANSFER)!=NULL && m_pAllocatedForClient!=NULL) {
__try { // copying client buffer for OUT transfer
memcpy( m_sTransfer.lpvBuffer, m_pAllocatedForClient, m_sTransfer.dwBufferSize );
//DEBUGMSG(1, (TEXT("IN Transfer of size 0x%x\r\n"), m_sTransfer.dwBufferSize));
//memdump((unsigned char *)m_sTransfer.lpvBuffer, (USHORT)m_sTransfer.dwBufferSize, 0);
} __except( EXCEPTION_EXECUTE_HANDLER ) {
// bad lpvBuffer.
if (dwUsbError == USB_NO_ERROR)
dwUsbError = USB_CLIENT_BUFFER_ERROR;
}
}
#pragma prefast(disable: 322, "Recover gracefully from hardware failure")
__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 ) {
}
#pragma prefast(pop)
return (dwUsbError==USB_NO_ERROR);
}
else
return TRUE;
}
//************************************************************************************************
CSITransfer::CSITransfer (IN CIsochronousPipe * const pCPipe,IN CEhcd * const pCEhcd,STransfer sTransfer)
:CIsochTransfer(pCPipe, pCEhcd,sTransfer)
//
// Purpose: Constructor for CSITransfer (Class for Full/Low Speed isochronous transfer)
//
// Parameters:
//
// Returns: Nothing
//
// Notes:
//**************************************************************************************************
{
m_pCSITDList =0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -