前面發(fā)了好幾篇wince串口的學(xué)習(xí)的文章,,由于是學(xué)習(xí)性質(zhì)的,,弄的比較亂,,還請網(wǎng)友們原諒,。以前只是搞懂了大體框架,,對這個中斷線程等底層的東西還沒有了解,現(xiàn)在來來學(xué)習(xí)一下,。
- 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的實現(xiàn)代碼來看,,這個SerialEventHandler幾乎包括了所有串口功能的操作。把讀寫線程等都集成在一起了,。通過判斷中斷類型來執(zhí)行不同的函數(shù),。
SerialEventHandler函數(shù)被兩個地方調(diào)用
一、在49行處調(diào)用,,
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 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函數(shù)是等待線程啟動的作用,,微軟的代碼還是寫的比較清晰的,,來看看SerialDispatchThread函數(shù)在哪里調(diào)用了,。
-
-
-
-
-
-
-
-
-
- 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被誰調(diào)用了
(1)COM_Init調(diào)用了
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調(diào)用了
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調(diào)用了SerialEventHandler函數(shù)
//NotifyPDDInterrupt在PDD和中間層被調(diào)用了 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; } +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
現(xiàn)在來看看這個中斷到底怎么回事,,感覺和4.2的區(qū)別太大了。
———————————————————————————————————————————————
我找了好久,,終于找到PDD線程相關(guān)的地方,,這里值得注意的是C++語言的構(gòu)造函數(shù)和析構(gòu)函數(shù)的作用,在第一次
建類對象的時候會調(diào)用構(gòu)造函數(shù)(構(gòu)造函數(shù)可以用來初始化對象),,而清除類對象的時候調(diào)用析構(gòu)函數(shù)(如果不懂
C++的,,比如我,找了好久才知道在析構(gòu)函數(shù)關(guān)閉了串口線程句柄,,慚愧,。)
//構(gòu)造函數(shù),當(dāng)創(chuàng)建對象的時候會自動調(diào)用
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 ; }
//析構(gòu)函數(shù),,當(dāng)清除類對象的時候會自動調(diào)用 CPdd2440Uart::~CPdd2440Uart() { InitModem(FALSE); if (m_hISTEvent) { m_bTerminated=TRUE; ThreadStart(); SetEvent(m_hISTEvent); ThreadTerminated(1000); InterruptDisable( m_dwSysIntr ); //禁止中斷 CloseHandle(m_hISTEvent);//關(guān)閉串口線程句柄 }; if (m_pReg2440Uart) delete m_pReg2440Uart; if (m_XmitFlushDone) CloseHandle(m_XmitFlushDone); if (m_pRegVirtualAddr != NULL) { MmUnmapIoSpace((PVOID)m_pRegVirtualAddr,0UL);//釋放虛擬內(nèi)存 } if (m_pINTregs!=NULL) { MmUnmapIoSpace((PVOID)m_pINTregs,0UL));//釋放虛擬內(nèi)存
} }
//---------至于更進一步分析,,明天做個比較完整的總結(jié)吧,看來年前的時間都用來學(xué)C++比較合適
————————————上面都是比較亂,,現(xiàn)在總結(jié)一下一個正常的線程架構(gòu)——————————————
首先是創(chuàng)建線程 pSerialHead->hSerialEvent = CreateEvent(0,FALSE,FALSE,NULL);
InterruptInitialize(pSerialHead->pHWObj->dwIntID,//這個中斷和PDD的中斷以及相關(guān)線程到底有什么不同,? pSerialHead->hSerialEvent, NULL, 0) )
SetEvent(pSerialHead->hSerialEvent);
WaitReturn = WaitForSingleObject(pSerialHead->hSerialEvent, INFINITE);
SerialEventHandler(pSerialHead);//開始執(zhí)行串口線程
CloseHandle(pSerialHead->hSerialEvent);//關(guān)閉線程句柄
—————————————————————————————————————————————————
WaitForSingleObject函數(shù)用來檢測hHandle事件的信號狀態(tài),當(dāng)函數(shù)的執(zhí)行時間超過dwMilliseconds就返回,,但如果參數(shù)dwMilliseconds為INFINITE時函數(shù)將直到相應(yīng)時間事件變成有信號狀態(tài)才返回,,否則就一直等待下去,直到WaitForSingleObject有返回直才執(zhí)行后面的代碼,。在這里舉個例子:
先創(chuàng)建一個全局Event對象g_event: CEvent g_event; 在程序中可以通過調(diào)用CEvent::SetEvent設(shè)置事件為有信號狀態(tài),。
在驅(qū)動程序中,因為線程往往和硬件中斷相關(guān),,中斷產(chǎn)生就執(zhí)行線程,,中斷關(guān)閉就不執(zhí)行線程,所以串口提供了
兩種執(zhí)行線程的方法(1)產(chǎn)生中斷.(2)SetEvent(線程句柄)
—————————————————————————————————————————————————
MDD中的中斷是怎么回事?
在SerialEventHandler函數(shù)中調(diào)用了HWGetIntrType函數(shù)(其實是調(diào)用了轉(zhuǎn)換函數(shù)表的SerGetInterruptType函數(shù))
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被誰調(diào)用了就知道怎么回事了,。
在PDD層的ThreadRun函數(shù)調(diào)用了NotifyPDDInterrupt函數(shù)
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; } ——————————————————————————————————————————
這個有點奇怪,這個是硬件中斷相關(guān)的東西,,但是在MMD層有個中斷實在讓人費解
InterruptInitialize(pSerialHead->pHWObj->dwIntID,//這個中斷和PDD的中斷以及相關(guān)線程到底有什么不同,? pSerialHead->hSerialEvent, NULL, 0) )
在中間層的SerInit函數(shù)有
//為什么會這樣做呢,中斷和 //DeviceArrayIndex()注冊表扯上關(guān)系? 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并不是什么硬件中斷,這樣調(diào)用怎么能成功,? //而是注冊表中的DeviceArrayIndex的值why? if ( !InterruptInitialize(pSerialHead->pHWObj->dwIntID, pSerialHead->hSerialEvent, NULL, 0) )
——————————————————————————————
按照道理,,上面是這個所謂的“中斷”(dwIntID )綁定了句柄為hSerialEvent的線程。只要dwIntID 有硬件動作
才會啟動句柄為hSerialEvent的線程,。但是這個中斷是假的,,不知道微軟是怎么弄的,搞定這個,,串口的架構(gòu)基本是算完成了,。
——————引用何宗健老師的回答
InterruptInitialize函數(shù)要調(diào)用成功,必須要求目前的event沒有對象正在等待,。因此,,如果你先創(chuàng)建了線程,并且已經(jīng)執(zhí)行了WaitForSingleObject一句的話,,肯定就不能滿足這個要求了,。
其實InterruptInitialize函數(shù)在WinCE里面是有完整源代碼的,在/WINCE600/PRIVATE/WINCEOS/COREOS/NK/KERNEL/intrapi.c中,,你可以順藤摸瓜,,看看它是如何把中斷跟event連上的。
中斷是硬件與軟件打交道的重要方法,,因此,,大多數(shù)驅(qū)動程序都涉及到對中斷的處理,本文就驅(qū)動程序的開發(fā)人員以及BSP的開發(fā)人員的角度,,來談?wù)刉indows CE中中斷的處理過程,。
如果一個驅(qū)動程序要處理一個中斷,那么驅(qū)動程序需要首先建立一個事件,,可以使用CreateEvent函數(shù),,然后調(diào)用InterruptInitialize將該事件與中斷號綁定,這一步就會使能該中斷,,OAL中的OEMInerrupteEnable就會被調(diào)用,,如果該函數(shù)不返回true的話,,InterruptInitialize就會失敗。然后驅(qū)動程序中的IST就可以使用WaitForSingleObject函數(shù)來等待中斷的發(fā)生,。
當(dāng)一個硬件中斷發(fā)生之后,,操作系統(tǒng)陷入異常,中斷向量指示進入CE的異常處理程序,,該異常處理程序然后調(diào)用OAL的OEMInterruptHandler函數(shù),,該函數(shù)檢測硬件之后,將硬件中斷轉(zhuǎn)換為軟件的中斷號,,返回給系統(tǒng),。該中斷號就是上面提到的InterruptInitialize中使用的那個中斷號。系統(tǒng)得到該中斷號之后,,就會找到該中斷號對應(yīng)的事件,,并喚醒等待相應(yīng)事件的線程(IST),然后IST就可以在用戶態(tài)進行中斷處理,。處理完成之后,,IST需要調(diào)用InterruptDone來告訴操作系統(tǒng)中斷處理結(jié)束,操作系統(tǒng)再次調(diào)用OAL中的OEMInterruptDone函數(shù),,最后完成中斷的處理。
在上面的描述中,,驅(qū)動程序需要使用的是InterruptInitialize,,WaitForSingleObject和InterruptDone三個函數(shù),而BSP開發(fā)者需要主要考慮的是OEMInerrupteEnable,,OEMInterruptHandler,,OEMInterruptDone三個函數(shù)。當(dāng)然,,這是上面提到的一些函數(shù),,實際上BSP開發(fā)者在中斷部分還需要考慮Init以及Disable等等函數(shù),這里就不再討論了,。
——對于這個問題我還是無法解釋,,怎么想也不會使用這種注冊表的一些參數(shù)來啊,要徹底明白,,只能看看InterruptInitialize源碼到底是怎么回事了,。
————————————————————
wogoyixikexie@gliet 說: WaitReturn = WaitForSingleObject(pSerialHead->hSerialEvent, INFINITE);
SerialEventHandler(pSerialHead);//開始執(zhí)行串口線程 CSDN-廣州天河wince6.0 說:
wogoyixikexie@gliet 說: 要有信號來才會執(zhí)行這個線程,可是我發(fā)現(xiàn)這個 SetEvent(pSerialHead->hSerialEvent); 在StopDispatchThread函數(shù)里面,,而StopDispatchThread是被COM_Deinit函數(shù)調(diào)用的 wogoyixikexie@gliet 說: 那么這樣導(dǎo)致了關(guān)閉驅(qū)動的時候才執(zhí)行上面那個串口發(fā)送接收相關(guān)的線程SerialEventHandler wogoyixikexie@gliet 說: 我看后實在不解,,不過它是能正常工作的 wogoyixikexie@gliet 說: 我想求個讓人信服的理由 加密助手 說: --- 系統(tǒng)提示: 以下會話未被加密 --- CSDN-廣州天河wince6.0 說: 兩個事件是不一樣的吧 wogoyixikexie@gliet 說: 一樣的 wogoyixikexie@gliet 說: 這個線程句柄就是用來控制線程是否執(zhí)行的 wogoyixikexie@gliet 說: 如果沒有信號,就等待 CSDN-廣州天河wince6.0 說: WaitReturn = WaitForSingleObject(pSerialHead->hSerialEvent, INFINITE); 是在那個函數(shù)中 CSDN-廣州天河wince6.0 說: threadrun(_)? wogoyixikexie@gliet 說: SerialDispatchThread wogoyixikexie@gliet 說: 這個是MDD的線程 wogoyixikexie@gliet 說: PDD的線程是和硬件中斷相關(guān)的 wogoyixikexie@gliet 說: 真是神了,,這樣使用注冊表一個配置產(chǎn)生了一個線程 加密助手 說: --- 系統(tǒng)提示: 以下會話未被加密 --- CSDN-廣州天河wince6.0 說: 不太清楚它為什么要這樣子做 wogoyixikexie@gliet 說: 呵呵,,先放一下了,,以后再補充了。 CSDN-廣州天河wince6.0 說: 好像這個線程一直都是阻塞的
|