前面发了好几篇wince串口的学习的文章,由于是学习性质的,弄的比较乱,还请网友们原谅。以前只是搞懂了大体框架,对这个中断线程等底层的东西还没有了解,现在来来学习一下。
- VOID
- SerialEventHandler(PHW_INDEP_INFO pSerialHead)
- {
- PHW_VTBL pFuncTbl = pSerialHead->pHWObj->pFuncTbl;
- PVOID pHWHead = pSerialHead->pHWHead;
- ULONG CharIndex;
- ULONG RoomLeft = 0;
- ULONG TotalLeft = 0;
- INTERRUPT_TYPE it = INTR_NONE;
- BOOL RxDataAvail = FALSE;
- DEBUGMSG (ZONE_THREAD, (TEXT("+SerialEventHandler, pHead 0x%X/r/n"),
- pSerialHead));
- if ( pSerialHead->KillRxThread ||
- !pSerialHead->hSerialEvent ) {
- DEBUGMSG (ZONE_THREAD, (TEXT("Exitting thread/r/n")));
- SetEvent(pSerialHead->hKillDispatchThread);
- ExitThread(0);
- }
-
-
-
-
- if ( pSerialHead->pAccessOwner )
- COM_INC_USAGE_CNT(pSerialHead->pAccessOwner);
- while ( 1 ) {
- if ( !(it = pFuncTbl->HWGetIntrType(pHWHead)) ) {
- DEBUGMSG (ZONE_THREAD,
- (TEXT("SerialEventHandler, No Interrupt./r/n")));
- break;
- }
- DEBUGMSG (ZONE_THREAD,
- (TEXT("SerialEventHandler, Interrupts 0x%X/r/n"), it));
- if ( it & INTR_RX ) {
-
-
-
-
-
-
- register DWORD RxWIndex=RxWrite(pSerialHead), RxRIndex=RxRead(pSerialHead);
- DEBUGMSG (ZONE_THREAD|ZONE_READ , (TEXT("Rx Event/r/n")));
- if ( RxRIndex == 0 ) {
-
- RoomLeft = RxLength(pSerialHead) - RxWIndex - 1;
- } else {
- RoomLeft = RxLength(pSerialHead) - RxWIndex;
- }
- if ( RxRIndex > RxWIndex ) {
- RoomLeft = RxRIndex - RxWIndex - 1;
- }
- if ( RoomLeft ) {
- pSerialHead->DroppedBytesPDD +=
- pFuncTbl->HWRxIntrHandler(pHWHead,
- RxBuffWrite(pSerialHead),
- &RoomLeft);
- } else {
- BYTE TempBuf[16];
- RoomLeft = 16;
- pFuncTbl->HWRxIntrHandler(pHWHead,
- TempBuf,
- &RoomLeft);
- pSerialHead->DroppedBytesMDD += RoomLeft;
- DEBUGMSG (ZONE_WARN|ZONE_READ, (TEXT("Tossed %d bytes/r/n"),
- RoomLeft));
- RoomLeft = 0;
- }
- DEBUGMSG (ZONE_READ ,
- (TEXT("After HWGetBytes, Fifo(R=%d,W=%d,BA=%d,L=%d) ByteRead=%d/r/n"),
- RxRead(pSerialHead), RxWrite(pSerialHead),
- RxBytesAvail(pSerialHead), RxLength(pSerialHead),
- RoomLeft));
-
-
- if ( pSerialHead->XFlow ) {
- for ( CharIndex=0; CharIndex < RoomLeft; ) {
- if ( RxBuffWrite(pSerialHead)[CharIndex] ==
- pSerialHead->DCB.XoffChar ) {
- DEBUGMSG (ZONE_FLOW, (TEXT("Received XOFF/r/n")));
- pSerialHead->StopXmit = 1;
- memmove (RxBuffWrite(pSerialHead)+CharIndex,
- RxBuffWrite(pSerialHead)+CharIndex+1,
- RoomLeft - CharIndex);
- RoomLeft--;
- continue;
- } else if ( RxBuffWrite(pSerialHead)[CharIndex] ==
- pSerialHead->DCB.XonChar ) {
- pSerialHead->StopXmit = 0;
- DEBUGMSG (ZONE_FLOW, (TEXT("Received XON/r/n")));
- memmove (RxBuffWrite(pSerialHead)+CharIndex,
- RxBuffWrite(pSerialHead)+CharIndex+1,
- RoomLeft - CharIndex);
- RoomLeft--;
-
-
- it |= INTR_TX;
- continue;
- }
- CharIndex++;
- }
- }
- pSerialHead->RxBytes += RoomLeft;
- RxWrite(pSerialHead) =
- (RxWrite(pSerialHead)+RoomLeft<RxLength(pSerialHead)? RxWrite(pSerialHead)+RoomLeft: RxWrite(pSerialHead)+RoomLeft-RxLength(pSerialHead));
- if ( RoomLeft ) {
- RxDataAvail = TRUE;
- }
-
-
-
- if ( (pSerialHead->DCB.fDtrControl == DTR_CONTROL_HANDSHAKE) &
- (!pSerialHead->DtrFlow) &&
- (4*RxBytesAvail(pSerialHead) > (3*RxLength(pSerialHead))) ) {
- DEBUGMSG (ZONE_READ|ZONE_FLOW,
- (TEXT("DTR_CONTROL_HANDSHAKE Clearing DTR/r/n")));
- pSerialHead->DtrFlow = 1;
- pFuncTbl->HWClearDTR(pHWHead);
- }
- if ( (pSerialHead->DCB.fRtsControl == RTS_CONTROL_HANDSHAKE) &
- (!pSerialHead->RtsFlow) &
- (4*RxBytesAvail(pSerialHead) > (3*RxLength(pSerialHead))) ) {
- DEBUGMSG (ZONE_READ|ZONE_FLOW,
- (TEXT("RTS_CONTROL_HANDSHAKE Clearing RTS/r/n")));
- pSerialHead->RtsFlow = 1;
- pFuncTbl->HWClearRTS(pHWHead);
- }
-
-
-
- if ( pSerialHead->DCB.fInX && !(pSerialHead->SentXoff) &
- ( pSerialHead->DCB.XoffLim >=
- (RxLength(pSerialHead) - RxBytesAvail(pSerialHead))) ) {
- DEBUGMSG (ZONE_FLOW, (TEXT("Sending XOFF/r/n")));
- pFuncTbl->HWXmitComChar(pHWHead, pSerialHead->DCB.XoffChar);
- pSerialHead->SentXoff = 1;
- if ( !pSerialHead->DCB.fTXContinueOnXoff ) {
- pSerialHead->StopXmit = 1;
- }
- }
- }
-
- if ( it & INTR_TX ) {
- DEBUGMSG (ZONE_THREAD|ZONE_WRITE , (TEXT("Tx Event/r/n")));
- DoTxData( pSerialHead );
- }
- if ( (it & INTR_MODEM) ) {
- DEBUGMSG (ZONE_THREAD, (TEXT("Other Event, it:%x/r/n"), it));
-
-
- pFuncTbl->HWModemIntrHandler(pHWHead);
- }
- if ( it & INTR_LINE ) {
- DEBUGMSG (ZONE_THREAD, (TEXT("Line Event, it:%x/r/n"), it));
-
-
-
- pFuncTbl->HWLineIntrHandler(pHWHead);
- }
- }
-
- if ( RxDataAvail ) {
-
- SetEvent(pSerialHead->hReadEvent);
- EvaluateEventFlag(pSerialHead, EV_RXCHAR);
- }
- DEBUGMSG (ZONE_THREAD ,
- (TEXT("-SerialEventHandler, Fifo(R=%d,W=%d,L=%d)/r/n"),
- RxRead(pSerialHead), RxWrite(pSerialHead),
- RxLength(pSerialHead)));
- if ( pSerialHead->pAccessOwner )
- COM_DEC_USAGE_CNT(pSerialHead->pAccessOwner);
- return;
- }
从这个SerialEventHandler的实现代码来看,这个SerialEventHandler几乎包括了所有串口功能的操作。把读写线程等都集成在一起了。通过判断中断类型来执行不同的函数。
SerialEventHandler函数被两个地方调用
一、在49行处调用,
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- static DWORD WINAPI
- SerialDispatchThread(
- PVOID pContext
- )
- {
- PHW_INDEP_INFO pSerialHead = (PHW_INDEP_INFO)pContext;
- ULONG WaitReturn;
-
- DEBUGMSG (ZONE_THREAD, (TEXT("Entered SerialDispatchThread %X/r/n"),
- pSerialHead));
-
-
-
- if ( pSerialHead->pHWObj->BindFlags & THREAD_IN_MDD ) {
- DEBUGMSG(ZONE_INIT,
- (TEXT("Spinning in dispatch thread %X %X/n/r"), pSerialHead, pSerialHead->pHWObj));
- while ( !pSerialHead->pDispatchThread ) {
- Sleep(20);
- }
- }
-
-
-
- while ( !pSerialHead->KillRxThread ) {
- DEBUGMSG (ZONE_THREAD, (TEXT("Event %X, %d/r/n"),
- pSerialHead->hSerialEvent,
- pSerialHead->pHWObj->dwIntID ));
- WaitReturn = WaitForSingleObject(pSerialHead->hSerialEvent, INFINITE);
-
- SerialEventHandler(pSerialHead);
- InterruptDone(pSerialHead->pHWObj->dwIntID);
- }
-
- DEBUGMSG (ZONE_THREAD, (TEXT("SerialDispatchThread %x exiting/r/n"),
- pSerialHead));
- return(0);
- }
SerialDispatchThread函数是等待线程启动的作用,微软的代码还是写的比较清晰的,来看看SerialDispatchThread函数在哪里调用了。
-
-
-
-
-
-
-
-
-
- BOOL
- StartDispatchThread(
- PHW_INDEP_INFO pSerialHead
- )
- {
-
-
-
-
-
- DEBUGMSG(ZONE_INIT,
- (TEXT("Initializing interrupt 0x%X, 0x%X/n/r"),
- pSerialHead->pHWObj->dwIntID, pSerialHead->hSerialEvent));
-
-
- if ( !InterruptInitialize(pSerialHead->pHWObj->dwIntID,
- pSerialHead->hSerialEvent,
- NULL,
- 0) ) {
- DEBUGMSG(ZONE_INIT | ZONE_ERROR,
- (TEXT("Error initializing interrupt/n/r")));
- return(FALSE);
- }
-
- InterruptDone(pSerialHead->pHWObj->dwIntID);
-
-
-
- pSerialHead->KillRxThread = 0;
- pSerialHead->pDispatchThread = NULL;
-
- DEBUGMSG(ZONE_INIT,
- (TEXT("Spinning thread%X/n/r"), pSerialHead));
-
- pSerialHead->pDispatchThread = CreateThread(NULL,0, SerialDispatchThread,
- pSerialHead, 0,NULL);
- if ( pSerialHead->pDispatchThread == NULL ) {
- DEBUGMSG(ZONE_INIT|ZONE_ERROR,
- (TEXT("Error creating dispatch thread (%d)/n/r"),
- GetLastError()));
- return(FALSE);
- }
-
- DEBUGMSG (ZONE_INIT, (TEXT("Created receive thread %X/r/n"),
- pSerialHead->pDispatchThread));
- return(TRUE);
- }
再来看这个StartDispatchThread被谁调用了
(1)COM_Init调用了
if ( pSerialHead->pHWObj->BindFlags & THREAD_AT_INIT ) { // Hook the interrupt and start the associated thread. if ( ! StartDispatchThread( pSerialHead ) ) { // Failed on InterruptInitialize or CreateThread. Bail. COM_Deinit(pSerialHead); return(NULL); }
}
(2)COM_Open调用了
if ( pSerialHead->pHWObj->BindFlags & THREAD_AT_OPEN ) { DEBUGMSG(ZONE_INIT|ZONE_OPEN, (TEXT("COM_Open: Starting DispatchThread x%X/n/r"), pOpenHead)); // Hook the interrupt and start the associated thread. if ( ! StartDispatchThread( pSerialHead ) ) { // Failed on InterruptInitialize or CreateThread. Bail. DEBUGMSG(ZONE_INIT|ZONE_OPEN, (TEXT("COM_Open: Failed StartDispatchThread x%X/n/r"), pOpenHead)); goto OpenFail; } }
二、NotifyPDDInterrupt调用了SerialEventHandler函数
//NotifyPDDInterrupt在PDD和中间层被调用了 BOOL CSerialPDD::NotifyPDDInterrupt(INTERRUPT_TYPE interruptType) { m_InterruptLock.Lock(); // The interrupt is define as Bit event. m_dwInterruptFlag |= (DWORD)interruptType; m_InterruptLock.Unlock(); if (IsPowerResumed ( )) { if (m_lOpenCount) { // If application is opened. EventCallback( EV_POWER ); } else { if (GetModemStatus() & MS_RLSD_ON) CeEventHasOccurred (NOTIFICATION_EVENT_RS232_DETECTED, NULL); } } SerialEventHandler(m_pMdd); return TRUE; } +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
现在来看看这个中断到底怎么回事,感觉和4.2的区别太大了。
———————————————————————————————————————————————
我找了好久,终于找到PDD线程相关的地方,这里值得注意的是C++语言的构造函数和析构函数的作用,在第一次
建类对象的时候会调用构造函数(构造函数可以用来初始化对象),而清除类对象的时候调用析构函数(如果不懂
C++的,比如我,找了好久才知道在析构函数关闭了串口线程句柄,惭愧。)
//构造函数,当创建对象的时候会自动调用
CPdd2440Uart::CPdd2440Uart (LPTSTR lpActivePath, PVOID pMdd, PHWOBJ pHwObj ) : CSerialPDD(lpActivePath,pMdd, pHwObj) , m_ActiveReg(HKEY_LOCAL_MACHINE,lpActivePath) , CMiniThread (0, TRUE) { m_pReg2440Uart = NULL; m_pINTregs = NULL; m_dwIntShift = 0; m_dwSysIntr = MAXDWORD; m_hISTEvent = NULL; m_dwDevIndex = 0; m_pRegVirtualAddr = NULL; m_XmitFlushDone = CreateEvent(0, FALSE, FALSE, NULL); m_XmitFifoEnable = FALSE; m_dwWaterMark = 8 ; }
//析构函数,当清除类对象的时候会自动调用 CPdd2440Uart::~CPdd2440Uart() { InitModem(FALSE); if (m_hISTEvent) { m_bTerminated=TRUE; ThreadStart(); SetEvent(m_hISTEvent); ThreadTerminated(1000); InterruptDisable( m_dwSysIntr ); //禁止中断 CloseHandle(m_hISTEvent);//关闭串口线程句柄 }; if (m_pReg2440Uart) delete m_pReg2440Uart; if (m_XmitFlushDone) CloseHandle(m_XmitFlushDone); if (m_pRegVirtualAddr != NULL) { MmUnmapIoSpace((PVOID)m_pRegVirtualAddr,0UL);//释放虚拟内存 } if (m_pINTregs!=NULL) { MmUnmapIoSpace((PVOID)m_pINTregs,0UL));//释放虚拟内存
} }
//---------至于更进一步分析,明天做个比较完整的总结吧,看来年前的时间都用来学C++比较合适
————————————上面都是比较乱,现在总结一下一个正常的线程架构——————————————
首先是创建线程 pSerialHead->hSerialEvent = CreateEvent(0,FALSE,FALSE,NULL);
InterruptInitialize(pSerialHead->pHWObj->dwIntID,//这个中断和PDD的中断以及相关线程到底有什么不同? pSerialHead->hSerialEvent, NULL, 0) )
SetEvent(pSerialHead->hSerialEvent);
WaitReturn = WaitForSingleObject(pSerialHead->hSerialEvent, INFINITE);
SerialEventHandler(pSerialHead);//开始执行串口线程
CloseHandle(pSerialHead->hSerialEvent);//关闭线程句柄
—————————————————————————————————————————————————
WaitForSingleObject函数用来检测hHandle事件的信号状态,当函数的执行时间超过dwMilliseconds就返回,但如果参数dwMilliseconds为INFINITE时函数将直到相应时间事件变成有信号状态才返回,否则就一直等待下去,直到WaitForSingleObject有返回直才执行后面的代码。在这里举个例子:
先创建一个全局Event对象g_event: CEvent g_event; 在程序中可以通过调用CEvent::SetEvent设置事件为有信号状态。
在驱动程序中,因为线程往往和硬件中断相关,中断产生就执行线程,中断关闭就不执行线程,所以串口提供了
两种执行线程的方法(1)产生中断.(2)SetEvent(线程句柄)
—————————————————————————————————————————————————
MDD中的中断是怎么回事?
在SerialEventHandler函数中调用了HWGetIntrType函数(其实是调用了转换函数表的SerGetInterruptType函数)
INTERRUPT_TYPE SerGetInterruptType( PVOID pHead // Pointer to hardware head ) { CSerialPDD * pSerialPDD = ( CSerialPDD * )pHead; INTERRUPT_TYPE interrupts=INTR_NONE; DEBUGMSG (ZONE_EVENTS,(TEXT("+SerGetInterruptType 0x%X/r/n"), pHead)); if (pSerialPDD) interrupts= pSerialPDD->GetInterruptType(); DEBUGMSG (ZONE_EVENTS,(TEXT("-SerGetInterruptType (0x%X) return %X/r/n"), pHead, interrupts)); return interrupts; }
——————————
INTERRUPT_TYPE CSerialPDD::GetInterruptType() { m_InterruptLock.Lock(); // The interrupt is define as Bit event. INTERRUPT_TYPE lIntrFlagRet= (INTERRUPT_TYPE )m_dwInterruptFlag; m_dwInterruptFlag = INTR_NONE; m_InterruptLock.Unlock(); return lIntrFlagRet; }
——
BOOL CSerialPDD::NotifyPDDInterrupt(INTERRUPT_TYPE interruptType) { m_InterruptLock.Lock(); // The interrupt is define as Bit event. m_dwInterruptFlag |= (DWORD)interruptType; m_InterruptLock.Unlock(); if (IsPowerResumed ( )) { if (m_lOpenCount) { // If application is opened. EventCallback( EV_POWER ); } else { if (GetModemStatus() & MS_RLSD_ON) CeEventHasOccurred (NOTIFICATION_EVENT_RS232_DETECTED, NULL); } } SerialEventHandler(m_pMdd); return TRUE; }
——看看这个NotifyPDDInterrupt被谁调用了就知道怎么回事了。
在PDD层的ThreadRun函数调用了NotifyPDDInterrupt函数
DWORD CPdd2440Uart::ThreadRun() { while ( m_hISTEvent!=NULL && !IsTerminated()) { if (WaitForSingleObject( m_hISTEvent,m_dwISTTimeout)==WAIT_OBJECT_0) { m_HardwareLock.Lock(); while (!IsTerminated() ) { DWORD dwData = (GetInterruptStatus() & (S2440UART_INT_RXD|S2440UART_INT_TXD|S2440UART_INT_ERR)); DWORD dwMask = (GetIntrruptMask() & (S2440UART_INT_RXD|S2440UART_INT_TXD|S2440UART_INT_ERR)); DEBUGMSG(ZONE_THREAD, (TEXT(" CPdd2440Uart::ThreadRun INT=%x, MASK =%x/r/n"),dwData,dwMask)); dwMask &= dwData; if (dwMask) { DEBUGMSG(ZONE_THREAD, (TEXT(" CPdd2440Uart::ThreadRun Active INT=%x/r/n"),dwMask)); DWORD interrupts=INTR_MODEM; // Always check Modem when we have change. It may work at polling mode. if ((dwMask & S2440UART_INT_RXD)!=0) interrupts |= INTR_RX; if ((dwMask & S2440UART_INT_TXD)!=0) interrupts |= INTR_TX; if ((dwMask & S2440UART_INT_ERR)!=0) interrupts |= INTR_LINE|INTR_RX; NotifyPDDInterrupt((INTERRUPT_TYPE)interrupts); ClearInterrupt(dwData); } else break; } m_HardwareLock.Unlock(); InterruptDone(m_dwSysIntr); } else { // Polling Modem. NotifyPDDInterrupt(INTR_MODEM); DEBUGMSG(ZONE_THREAD,(TEXT(" CPdd2440Uart::ThreadRun timeout INT=%x,MASK=%d/r/n"),m_pINTregs->SUBSRCPND,m_pINTregs->INTSUBMSK)); #ifdef DEBUG if ( ZONE_THREAD ) m_pReg2440Uart->DumpRegister(); #endif } } return 1; } ——————————————————————————————————————————
这个有点奇怪,这个是硬件中断相关的东西,但是在MMD层有个中断实在让人费解
InterruptInitialize(pSerialHead->pHWObj->dwIntID,//这个中断和PDD的中断以及相关线程到底有什么不同? pSerialHead->hSerialEvent, NULL, 0) )
在中间层的SerInit函数有
//为什么会这样做呢,中断和 //DeviceArrayIndex()注册表扯上关系? DWORD dwIndex= pHWObj->dwIntID; pHWObj->dwIntID = 0;
——————————————————————
找到了
// GetSerialObj : The purpose of this function is to allow multiple PDDs to be // linked with a single MDD creating a multiport driver. In such a driver, the // MDD must be able to determine the correct vtbl and associated parameters for // each PDD. Immediately prior to calling HWInit, the MDD calls GetSerialObject // to get the correct function pointers and parameters. // extern "C" PHWOBJ GetSerialObject( DWORD DeviceArrayIndex ) { PHWOBJ pSerObj;
// Unlike many other serial samples, we do not have a statically allocated // array of HWObjs. Instead, we allocate a new HWObj for each instance // of the driver. The MDD will always call GetSerialObj/HWInit/HWDeinit in // that order, so we can do the alloc here and do any subsequent free in // HWDeInit. // Allocate space for the HWOBJ. pSerObj=(PHWOBJ)LocalAlloc( LPTR ,sizeof(HWOBJ) ); if ( !pSerObj ) return (NULL);
// Fill in the HWObj structure that we just allocated.
pSerObj->BindFlags = THREAD_IN_PDD; // PDD create thread when device is first attached. pSerObj->dwIntID = DeviceArrayIndex; // Only it is useful when set set THREAD_AT_MDD. We use this to transfer DeviceArrayIndex pSerObj->pFuncTbl = (HW_VTBL *) &IoVTbl; // Return pointer to appropriate functions
// Now return this structure to the MDD. return (pSerObj); }
果然是注册表中的DeviceArrayIndex值就是dwIntID ,不过我始终对前面的线程绑定dwIntID 有点不解
//中断绑定串口线程SerialEventHandler,这个dwIntID并不是什么硬件中断,这样调用怎么能成功? //而是注册表中的DeviceArrayIndex的值why? if ( !InterruptInitialize(pSerialHead->pHWObj->dwIntID, pSerialHead->hSerialEvent, NULL, 0) )
——————————————————————————————
按照道理,上面是这个所谓的“中断”(dwIntID )绑定了句柄为hSerialEvent的线程。只要dwIntID 有硬件动作
才会启动句柄为hSerialEvent的线程。但是这个中断是假的,不知道微软是怎么弄的,搞定这个,串口的架构基本是算完成了。
——————引用何宗健老师的回答
InterruptInitialize函数要调用成功,必须要求目前的event没有对象正在等待。因此,如果你先创建了线程,并且已经执行了WaitForSingleObject一句的话,肯定就不能满足这个要求了。
其实InterruptInitialize函数在WinCE里面是有完整源代码的,在/WINCE600/PRIVATE/WINCEOS/COREOS/NK/KERNEL/intrapi.c中,你可以顺藤摸瓜,看看它是如何把中断跟event连上的。
中断是硬件与软件打交道的重要方法,因此,大多数驱动程序都涉及到对中断的处理,本文就驱动程序的开发人员以及BSP的开发人员的角度,来谈谈Windows CE中中断的处理过程。
如果一个驱动程序要处理一个中断,那么驱动程序需要首先建立一个事件,可以使用CreateEvent函数,然后调用InterruptInitialize将该事件与中断号绑定,这一步就会使能该中断,OAL中的OEMInerrupteEnable就会被调用,如果该函数不返回true的话,InterruptInitialize就会失败。然后驱动程序中的IST就可以使用WaitForSingleObject函数来等待中断的发生。
当一个硬件中断发生之后,操作系统陷入异常,中断向量指示进入CE的异常处理程序,该异常处理程序然后调用OAL的OEMInterruptHandler函数,该函数检测硬件之后,将硬件中断转换为软件的中断号,返回给系统。该中断号就是上面提到的InterruptInitialize中使用的那个中断号。系统得到该中断号之后,就会找到该中断号对应的事件,并唤醒等待相应事件的线程(IST),然后IST就可以在用户态进行中断处理。处理完成之后,IST需要调用InterruptDone来告诉操作系统中断处理结束,操作系统再次调用OAL中的OEMInterruptDone函数,最后完成中断的处理。
在上面的描述中,驱动程序需要使用的是InterruptInitialize,WaitForSingleObject和InterruptDone三个函数,而BSP开发者需要主要考虑的是OEMInerrupteEnable,OEMInterruptHandler,OEMInterruptDone三个函数。当然,这是上面提到的一些函数,实际上BSP开发者在中断部分还需要考虑Init以及Disable等等函数,这里就不再讨论了。
——对于这个问题我还是无法解释,怎么想也不会使用这种注册表的一些参数来啊,要彻底明白,只能看看InterruptInitialize源码到底是怎么回事了。
————————————————————
wogoyixikexie@gliet 说: WaitReturn = WaitForSingleObject(pSerialHead->hSerialEvent, INFINITE);
SerialEventHandler(pSerialHead);//开始执行串口线程 CSDN-广州天河wince6.0 说:
wogoyixikexie@gliet 说: 要有信号来才会执行这个线程,可是我发现这个 SetEvent(pSerialHead->hSerialEvent); 在StopDispatchThread函数里面,而StopDispatchThread是被COM_Deinit函数调用的 wogoyixikexie@gliet 说: 那么这样导致了关闭驱动的时候才执行上面那个串口发送接收相关的线程SerialEventHandler wogoyixikexie@gliet 说: 我看后实在不解,不过它是能正常工作的 wogoyixikexie@gliet 说: 我想求个让人信服的理由 加密助手 说: --- 系统提示: 以下会话未被加密 --- CSDN-广州天河wince6.0 说: 两个事件是不一样的吧 wogoyixikexie@gliet 说: 一样的 wogoyixikexie@gliet 说: 这个线程句柄就是用来控制线程是否执行的 wogoyixikexie@gliet 说: 如果没有信号,就等待 CSDN-广州天河wince6.0 说: WaitReturn = WaitForSingleObject(pSerialHead->hSerialEvent, INFINITE); 是在那个函数中 CSDN-广州天河wince6.0 说: threadrun(_)? wogoyixikexie@gliet 说: SerialDispatchThread wogoyixikexie@gliet 说: 这个是MDD的线程 wogoyixikexie@gliet 说: PDD的线程是和硬件中断相关的 wogoyixikexie@gliet 说: 真是神了,这样使用注册表一个配置产生了一个线程 加密助手 说: --- 系统提示: 以下会话未被加密 --- CSDN-广州天河wince6.0 说: 不太清楚它为什么要这样子做 wogoyixikexie@gliet 说: 呵呵,先放一下了,以后再补充了。 CSDN-广州天河wince6.0 说: 好像这个线程一直都是阻塞的
|