WinCE USB 驱动中IssueTransfer调用相关
IssueTransfer调用相关
在CHub类中的AttachDevice函数中,经常会调用到类CControlPipe的函数IssueTransfer。本文介绍一下函数CControlPipe::IssueTransfer的调用过程,以及具体实现。
首先说说对函数CControlPipe::IssueTransfer的调用。
首先调用函数CControlPipe::IssueTransfer:
status = pControlPipe->IssueTransfer(
.
.
.
TransferDoneCallbackSetEvent, // 回调函数
m_hHubStatusChangeEvent, // 回调函数的参数
.
.
.
);
传输处理完后,会使用传入的回调函数参数来调用回调函数。即set event m_hHubStatusChangeEvent。
等待事件m_hHubStatusChangeEvent,即等待传输处理结束。
WaitForSingleObject( m_hHubStatusChangeEvent, ATTACH_TIMEOUT )
若Timeout,则中断传输:
pControlPipe->AbortTransfer( NULL, // callback function
NULL, // callback parameter
this ); // cancel ID
判断线程退出标志,若为True,则中断传输:
pControlPipe->AbortTransfer( NULL, // callback function
NULL, // callback parameter
this ); // cancel ID
下面来说说函数CControlPipe::IssueTransfer的实现。
首先判断是否需要change address:
if (m_bDeviceAddress ==0 && address !=0) { // Address Changed.m_bDeviceAddress在类CPipe的构造函数中被初始化。请参考Pipe相关类的继承关系。
// CQueuedPipe的构造函数中,将m_pQueuedTransfer赋值为NULL。
// 函数CQueuedPipe::AbortTransfer和函数CQueuedPipe::AbortQueue中会根据条件,将m_pQueuedTransfer赋值为NULL。
// 函数CQueuedPipe::ScheduleTransfer中会取m_pUnQueuedTransfer的第一个,赋值给m_pQueuedTransfer。
// 函数CQueuedPipe::CheckForDoneTransfers中,如果Pipe Halt了,会将m_pQueuedTransfer赋值为NULL。
// m_pPipeQHead在函数CControlPipe::OpenPipe中被创建
if ( m_pQueuedTransfer == NULL && m_pPipeQHead && m_pPipeQHead->IsActive()==FALSE) { // We need cqueue new Transfer.
m_bDeviceAddress = address;
// 函数CQH::SetDeviceAddress的实现:qH_StaticEndptState.qH_SESContext.DeviceAddress = dwDeviceAddress;
m_pPipeQHead ->SetDeviceAddress(m_bDeviceAddress);
}
else {
ASSERT(FALSE);
return requestFailed;
}
}
接下来调用函数CQueuedPipe::IssueTransfer。
函数CQueuedPipe::IssueTransfer中:
根据传入的参数定义一个STransfer对象。
检查STransfer对象中的Transfer参数是否合法。
AreTransferParametersValid(&sTransfer)
判断QHead是否已经创建成功。
检查成员变量m_bDeviceAddress与传入的address是否一致。
如果以上条件满足。则:
进入临界区。
Disables the PREfast warnings
#pragma prefast(disable: 322, "Recover gracefully from hardware failure")
进入一个__try... __except模块。
在该模块中,执行以下操作:
初始化Transfer状态参数。
用当前对象的this指针和先前创建的Transfer对象在CEhcd对象的Physical Memory上创建一个CQTransfer对象。CQTransfer是CTransfer的子类。
CQTransfer * pTransfer = new CQTransfer(this,m_pCEhcd->GetPhysMem(),sTransfer);
如果创建成功,调用CQTransfer对象的Init函数。
pTransfer->Init()
函数CTransfer::Init中检查是否需要分配Control Header Memory和Data Buffer。若需要,则进行分配。
若函数函数CTransfer::Init调用成功,则声明一个CQTransfer指针,并将其指向m_pUnQueuedTransfer。
接下来就是将新创建的Transfer对象追加到m_pUnQueuedTransfer末尾。
执行完后,恢复PREfast warnings
#pragma prefast(pop)
退出临界区。
调用函数CQueuedPipe::ScheduleTransfer。
函数CQueuedPipe::ScheduleTransfe执行的操作如下:
首先判断是否需要queue new Transfer,若不需要,则不进行任何操作。
判断的条件是m_pQueuedTransfer为空,m_pUnQueuedTransfer非空。QHead存在,并且不是Active的。
从m_pUnQueuedTransfer中取出第一个Transfer对象。
调用函数CQTransfer::GetCQTDList获取m_pCQTDList。
在函数CQTransfer::AddTransfer中会对m_pCQTDList赋值。
m_pCQTDList = new(m_pCPhysMem) CQTD(this, ((CQueuedPipe * const)m_pCPipe)->GetQHead())
pPrevTD= m_pCQTDList = pCurTD;
调用函数CQH::QueueTD,将QHead的nextQTDPointer指向前面获取到底m_pCQTDList。
GetQHead()->QueueTD(pCurTransfer->GetCQTDList())
将先前从m_pUnQueuedTransfer中取出的Transfer对象赋值给m_pQueuedTransfer。
m_pQueuedTransfer = pCurTransfer;
++参考+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1、Pipe相关类的继承关系
// CPipe (ADT)
// / /
// CQueuedPipe (ADT) CIsochronousPipe
// / | /
// / | /
// CControlPipe CInterruptPipe CBulkPipe