青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

唐吉訶德

  C++博客 :: 首頁 :: 聯系 :: 聚合  :: 管理
  5 Posts :: 75 Stories :: 3 Comments :: 0 Trackbacks

常用鏈接

留言簿(2)

我參與的團隊

搜索

  •  

最新評論

閱讀排行榜

評論排行榜

1. PDD層代碼簡單分析

PDD層的主要包含了以下2個類:CSerialPDDPowerUpCallback, CSerialPDD, 下面簡單的分析這2個類的作用。

1.1 CSerialPDDPowerUpCallback

CSerialPDDPowerUpCallback 類用于串口電源上電時的處理。

在調用CSerialPDD::Init()后會創建一個CSerialPDDPowerUpCallback類型的對象

在CSerialPDD::PowerOn()函數中會調用此對象的SignalCallBack()函數, 這樣RunThread就開始運行, 進而通過調用CSerialPDD::NotifyPDDInterrupt()進行后續處理, 包括調用

CeEventHasOccurred (NOTIFICATION_EVENT_RS232_DETECTED, NULL) 通知系統有串口被探測到.

以及調用SerialEventHandler()進行MDD層上的處理.

更詳細的細節可以參考微軟的源代碼:

%WINCEROOT%\PUBLIC\COMMON\OAK\DRIVERS\SERIAL\SERPDDCM\cserpdd.cpp

%WINCEROOT%\PUBLIC\COMMON\OAK\INC\cserpdd.h

2.2 CSerialPDD

CSerialPDD 是串口PDD層的關鍵,實現對硬件的操作,開發者開發的驅動就是繼承這個類,并實現重載相關的函數來完成特定設備的PDD功能的。

這個類抽象了以下這些接口:

//  Tx Function.

    virtual BOOL    InitXmit(BOOL bInit) = 0;

    virtual void    XmitInterruptHandler(PUCHAR pTxBuffer, ULONG *pBuffLen) = 0;

    virtual void    XmitComChar(UCHAR ComChar) = 0;

    virtual BOOL    EnableXmitInterrupt(BOOL bEnable)= 0;

    virtual BOOL    CancelXmit() = 0 ;

//  Rx Function.

    virtual BOOL    InitReceive(BOOL bInit) = 0;

    virtual ULONG   ReceiveInterruptHandler(PUCHAR pRxBuffer,ULONG *pBufflen) = 0;

    virtual ULONG   CancelReceive() = 0;

//  Modem

    virtual BOOL    InitModem(BOOL bInit) = 0;

    virtual void    ModemInterruptHandler()= 0; // This is Used to Indicate Modem Signal Changes.

    virtual ULONG   GetModemStatus() = 0;

    virtual void    SetDTR(BOOL bSet)= 0;

    virtual void    SetRTS(BOOL bSet)= 0;

    virtual BOOL    IsCTSOff() {  return ((GetModemStatus() & MS_CTS_ON)==0) ; };

    virtual BOOL    IsDSROff() {  return ((GetModemStatus() & MS_DSR_ON)==0) ; };

//  Line Function

    virtual BOOL    InitLine(BOOL bInit) = 0;

    virtual void    LineInterruptHandler() = 0;

    virtual void    SetBreak(BOOL bSet) = 0 ;   

    virtual BOOL    SetBaudRate(ULONG BaudRate,BOOL bIrModule) = 0;

    virtual BOOL    SetByteSize(ULONG ByteSize) = 0;

    virtual BOOL    SetParity(ULONG Parity)= 0;

    virtual BOOL    SetStopBits(ULONG StopBits)= 0;

    以上這些接口都是純虛函數, 在實現PDD層時, 必須實現這些接口.

當然不需要的功能你可以簡單的用類似virtual BOOL func() {;} 的形式來實現。

其他的非純虛函數的虛函數也可以被用戶重載, 以實現自己特定的功能。

    我們知道PDD層的函數為如下函數:

GetSerialObject

 This function returns a pointer to a HWOBJ structure. The structure contains the function pointers and parameters for the hardware interface functions of the relevant lower layer.

HWClearBreak

 This function clears an RS-232 line break condition.

HWClearDTR

 This function clears the Data Terminal Ready (DTR) signal.

HWClearRTS

 This function clears the Request to Send (RTS) signal.

HWClose

 This function closes the device initialized by the HWInit function.

HWDeinit

 This function is called by the upper layer to de-initialize the hardware when a device driver is unloaded.

HWDisableIR

 This function disables the infrared (IR) serial interface.

HWEnableIR

 This function enables the infrared (IR) serial interface.

HWGetCommProperties

 This function retrieves the current properties of the communications device.

HWGetIntrType

 This function returns the current interrupt type.

HWGetModemStatus

 This function retrieves the modem status.

HWGetRxBufferSize

 This function returns the maximum number of bytes that the hardware buffer can hold, not including the padding, stop, and start bits.

HWGetRxStart

 This function returns the start of the hardware-receive buffer.

HWGetStatus

 This function specifies the hardware status API.

HWInit

 This function initializes a serial device.

HWIoctl

 This function executes device I/O control (IOCTL) routines.

HWLineIntrHandler

 This function handles line interrupts for serial port devices.

HWModemIntrHandler

 This function handles the modem interrupt. In the serial port upper layer implementation available in Microsoft Windows CE 3.0 and later, this function replaces the HWOtherIntrHandler function.

HWOpen

 This function is called by the upper layer to open the serial device.

HWOtherIntrHandler

 In Windows CE 3.0 and later, this function has been replaced with the new function HWModemIntrHandler.

HWPostInit

 This function performs necessary operations after it initializes all data structures and prepares the serial IST to begin handling interrupts. It is called by the upper layer.

HWPowerOff

 This function notifies the platform-dependent driver that the hardware platform is about to enter suspend mode. It is called by the model device driver (MDD).

HWPowerOn

 This function notifies the platform-dependent driver that the hardware platform is resuming from suspend mode. It is called by the MDD.

HWPurgeComm

 This function purges the communications device.

HWPutBytes

 This function writes bytes to hardware. The driver calls this function.

HWReset

 This function resets the hardware API.

HWRxIntrHandler

 This function handles serial port interrupts.

HWSetBreak

 This function sets the line break condition on the transmit line.

HWSetCommTimeouts

 This function sets the communications time-out events in response to a call to the SetCommTimeouts function.

HWSetDCB

 This function sets the device control block.

HWSetDTR

 This function sets the Data Terminal Ready (DTR) signal.

HWSetRTS

 This function sets the Request to Send (RTS) signal.

HWTxIntrHandler

 This function handles the transmit interrupt for serial port devices.

HWXmitComChar

 This function transmits a single character.

更具體的細節可以參考:MSDN幫助 ms-help://MS.WindowsCE.500/wceddk5/html/wce50grfserialportdriverfunctions.htm

    微軟用一堆SerXXXXX()的函數封裝了CSerialPdd相關的操作,來完成PDD功能。

2. PDD與MDD層的交互

2.1 PDD層的函數是如何能夠被MDD層所調用

1.2節介紹的那一堆SerXXXXX()函數會被記錄到一個函數指針表里,真是通過這個函數指針表來實現與MDD層的交互的。此函數指針表是HW_VTBL類型的, 在微軟的代碼里是命名為IoVTbl的函數指針表。

    MDD層通過調用 GetSerialObject(DWORD DeviceArrayIndex)函數來獲取一個HWOBJ結構的指針, 這個結構包含以下成員:

    ULONG  BindFlags; // Flags controlling MDD behaviour.  Se above.

    DWORD   dwIntID;   // Interrupt Identifier used if THREAD_AT_INIT or THREAD_AT_OPEN

    PHW_VTBL   pFuncTbl;

    其中pFuncTbl正是指向我們之前說到的 IoVTbl 函數指針結構的地址.

這樣MDD層就可以通過->pFuncTbl.DDSIFunction()來對特定的硬件做特定的操作了.

2.2 GetSerialObject函數

這個函數的原型是:PHWOBJ GetSerialObject(DWORD DeviceArrayIndex) ,它是連接MDD和PDD層的關鍵函數, 也是實現多端口驅動的關鍵, 這個函數允許一個MDD層連接多個PDD層。

在MDD層的COM_Init函數中,驅動會通過查詢DeviceArrayIndex鍵值, 得到我們需要打開的是普通串口或者是其他種類的串口設備。

而正是這個數值決定了GetSerialObject是返回哪個串口的PHWOBJ指針, PHWOBJ包含了pFuncTbl,這個正是前一節說到的PDD層函數指針表,通過這個函數表我們就可以實現對相應的串口設備進行操作。(串口有可能是標準的串口,也有可能是紅外設備)

2.3 CreateSerialObject 函數

如果開發者選擇直接繼承微軟CSerialPdd類來實現串口的PDD層,還要實現CreateSerialObject及DeleteSerialObject函數。

在MDD層的COM_Init函數被調用時,驅動會通過查詢注冊表來得到相關參數并調用PDD層的HWInit函數,HWInit函數又會調用CreateSerialObject來初始化串口設備,在關閉串口以后DeleteSerialObject函數會被調用。

3. 其他

3.1 COM_Init函數如何被調用

此函數通常是由Device.exe進程調用的, 而此函數的參數Identifier 是一個指向注冊表HKEY_LOCAL_MACHINE\Drivers\Active.下的一個鍵值,這也是決定驅動如何操作硬件的關鍵。

對于使用ActivateDeviceEx函數調用的情況,請參照MSND, http://msdn.microsoft.com/en-us/library/aa447677.aspx

3.2 相關代碼段:

view plaincopy to clipboardprint?

HANDLE 

COM_Init(  

        ULONG   Identifier  

        )  

{  

    PVOID           pHWHead     = NULL;  

    PHW_INDEP_INFO  pSerialHead = NULL;  

    ULONG           HWBufferSize;  

    DWORD           DevIndex;  

    HKEY            hKey;  

    ULONG           kreserved = 0, kvaluetype;  

    ULONG           datasize = sizeof(ULONG);  

    /* 

     *  INTERNAL: this routine initializes the hardware abstraction interface 

     *  via HWInit(). It allocates a data structure representing this 

     *  instantiation of the device. It also creates an event and initializes 

     *  a critical section for receiving as well as registering the logical 

     *  interrupt dwIntID with NK via InterruptInitialize. This call 

     *  requires that the hardware dependent portion export apis that return 

     *  the physical address of the receive buffer and the size of that buffer. 

     *  Finally, it creates a buffer to act as an intermediate 

     *  buffer when receiving. 

     */ 

    DEBUGMSG (ZONE_INIT | ZONE_FUNCTION, (TEXT("+COM_Init\r\n")));  

    // Allocate our control structure.  

    pSerialHead  =  (PHW_INDEP_INFO)LocalAlloc(LPTR, sizeof(HW_INDEP_INFO));  

    // Check that LocalAlloc did stuff ok too.  

    if ( !pSerialHead ) {  

        DEBUGMSG(ZONE_INIT | ZONE_ERROR,  

                 (TEXT("Error allocating memory for pSerialHead, COM_Init failed\n\r")));  

        return(NULL);  

    }  

    // Initially, open list is empty.  

    InitializeListHead( &pSerialHead->OpenList );  

    InitializeCriticalSection(&(pSerialHead->OpenCS));  

    pSerialHead->pAccessOwner = NULL;  

    pSerialHead->fEventMask = 0;  

    // Init CommTimeouts.  

    pSerialHead->CommTimeouts.ReadIntervalTimeout = READ_TIMEOUT;  

    pSerialHead->CommTimeouts.ReadTotalTimeoutMultiplier =  

    READ_TIMEOUT_MULTIPLIER;  

    pSerialHead->CommTimeouts.ReadTotalTimeoutConstant =  

    READ_TIMEOUT_CONSTANT;  

    pSerialHead->CommTimeouts.WriteTotalTimeoutMultiplier=  0;  

    pSerialHead->CommTimeouts.WriteTotalTimeoutConstant =   0;  

    /* Create tx and rx events and stash in global struct field. Check return. 

     */ 

    pSerialHead->hSerialEvent = CreateEvent(0,FALSE,FALSE,NULL);  

    pSerialHead->hKillDispatchThread = CreateEvent(0, FALSE, FALSE, NULL);  

    pSerialHead->hTransmitEvent = CreateEvent(0, FALSE, FALSE, NULL);  

    pSerialHead->hReadEvent = CreateEvent(0, FALSE, FALSE, NULL);  

    if ( !pSerialHead->hSerialEvent || !pSerialHead->hKillDispatchThread ||  

         !pSerialHead->hTransmitEvent || !pSerialHead->hReadEvent ) {  

        DEBUGMSG(ZONE_ERROR | ZONE_INIT,  

                 (TEXT("Error creating event, COM_Init failed\n\r")));  

        LocalFree(pSerialHead);  

        return(NULL);  

    }  

    /* Initialize the critical sections that will guard the parts of 

     * the receive and transmit buffers. 

     */ 

    InitializeCriticalSection(&(pSerialHead->ReceiveCritSec1));  

    InitializeCriticalSection(&(pSerialHead->TransmitCritSec1));  

    /* Want to use the Identifier to do RegOpenKey and RegQueryValue (?) 

     * to get the index to be passed to GetHWObj. 

     * The HWObj will also have a flag denoting whether to start the 

     * listening thread or provide the callback. 

     */ 

    DEBUGMSG (ZONE_INIT,(TEXT("Try to open %s\r\n"), (LPCTSTR)Identifier));  

    hKey = OpenDeviceKey((LPCTSTR)Identifier);  

    // 通過調用OpenDeviceKey, 驅動可以通過Identifier找到驅動的注冊表鍵的所在.  

    if ( !hKey ) {  

        DEBUGMSG (ZONE_INIT | ZONE_ERROR,  

                  (TEXT("Failed to open devkeypath, COM_Init failed\r\n")));  

        LocalFree(pSerialHead);  

        return(NULL);  

    }  

    datasize = sizeof(DWORD);  

    // 通過查詢DeviceArrayIndex鍵值, 我們可以知道需要打開的是普通串口或者是其他類型的串口設備.  

    if ( RegQueryValueEx(hKey, L"DeviceArrayIndex", NULL, &kvaluetype,  

                         (LPBYTE)&DevIndex, &datasize) ) {  

        DEBUGMSG (ZONE_INIT | ZONE_ERROR,  

                  (TEXT("Failed to get DeviceArrayIndex value, COM_Init failed\r\n")));  

        RegCloseKey (hKey);  

        LocalFree(pSerialHead);  

        return(NULL);  

    }  

    datasize = sizeof(DWORD);  

    // 通過查詢Priority256鍵值, 我們可以知道IST的優先級,  在后面會通過這個值來改變IST的優先級.  

    if ( RegQueryValueEx(hKey, L"Priority256", NULL, &kvaluetype,  

                         (LPBYTE)&pSerialHead->Priority256, &datasize) ) {  

        pSerialHead->Priority256 = DEFAULT_CE_THREAD_PRIORITY;  

        DEBUGMSG (ZONE_INIT | ZONE_WARN,  

                  (TEXT("Failed to get Priority256 value, defaulting to %d\r\n"), pSerialHead->Priority256));  

    }  

    RegCloseKey (hKey);  

    DEBUGMSG (ZONE_INIT,  

              (TEXT("DevIndex %X\r\n"), DevIndex));  

    // Initialize hardware dependent data.  

    // GetSerialObject是連接MDD和PDD層的關鍵函數, 在這個函數里面決定了DevIndex是對什么設備進行操作.  

    // 可能是標準的串口, 也可能是紅外接口  

    pSerialHead->pHWObj = GetSerialObject( DevIndex );  

    if ( !pSerialHead->pHWObj ) {  

        DEBUGMSG(ZONE_ERROR | ZONE_INIT,  

                 (TEXT("Error in GetSerialObject, COM_Init failed\n\r")));  

        LocalFree(pSerialHead);  

        return(NULL);  

    }  

    DEBUGMSG (ZONE_INIT, (TEXT("About to call HWInit(%s,0x%X)\r\n"),  

                          Identifier, pSerialHead));  

    // 這里調用了PDD層的HWInit  

    pHWHead = pSerialHead->pHWObj->pFuncTbl->HWInit(Identifier, pSerialHead, pSerialHead->pHWObj);  

    pSerialHead->pHWHead = pHWHead;  

    /* Check that HWInit did stuff ok.  From here on out, call Deinit function 

     * when things fail.  

     */ 

    if ( !pHWHead ) {  

        DEBUGMSG (ZONE_INIT | ZONE_ERROR,  

                  (TEXT("Hardware doesn't init correctly, COM_Init failed\r\n")));  

        COM_Deinit(pSerialHead);  

        return(NULL);  

    }  

    DEBUGMSG (ZONE_INIT,  

              (TEXT("Back from hardware init\r\n")));  

    // Allocate at least twice the hardware buffer size so we have headroom  

    HWBufferSize        = 2 * pSerialHead->pHWObj->pFuncTbl->HWGetRxBufferSize(pHWHead);  

    // Init rx buffer and buffer length here.  

    pSerialHead->RxBufferInfo.Length =  

    HWBufferSize > RX_BUFFER_SIZE ? HWBufferSize:RX_BUFFER_SIZE;  

    pSerialHead->RxBufferInfo.RxCharBuffer =  

    LocalAlloc(LPTR, pSerialHead->RxBufferInfo.Length);  

    if ( !pSerialHead->RxBufferInfo.RxCharBuffer ) {  

        DEBUGMSG(ZONE_INIT|ZONE_ERROR,  

                 (TEXT("Error allocating receive buffer, COM_Init failed\n\r")));  

        COM_Deinit(pSerialHead);  

        return(NULL);  

    }  

    DEBUGMSG (ZONE_INIT, (TEXT("RxHead init'ed\r\n")));  

    RxResetFifo(pSerialHead);  

    InitializeCriticalSection(&(pSerialHead->RxBufferInfo.CS));  

    InitializeCriticalSection(&(pSerialHead->TxBufferInfo.CS));  

    DEBUGMSG (ZONE_INIT, (TEXT("RxBuffer init'ed with start at %x\r\n"),  

                          pSerialHead->RxBufferInfo.RxCharBuffer));  

    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);          

        }  

    }  

    // OK, now that everything is ready on our end, give the PDD  

    // one last chance to init interrupts, etc.  

    (void) pSerialHead->pHWObj->pFuncTbl->HWPostInit( pHWHead );  

    DEBUGMSG (ZONE_INIT | ZONE_FUNCTION, (TEXT("-COM_Init\r\n")));  

    return(pSerialHead);  

HANDLE

COM_Init(

        ULONG   Identifier

        )

{

    PVOID           pHWHead     = NULL;

    PHW_INDEP_INFO  pSerialHead = NULL;

    ULONG           HWBufferSize;

    DWORD           DevIndex;

    HKEY            hKey;

    ULONG           kreserved = 0, kvaluetype;

    ULONG           datasize = sizeof(ULONG);

    /*

     *  INTERNAL: this routine initializes the hardware abstraction interface

     *  via HWInit(). It allocates a data structure representing this

     *  instantiation of the device. It also creates an event and initializes

     *  a critical section for receiving as well as registering the logical

     *  interrupt dwIntID with NK via InterruptInitialize. This call

     *  requires that the hardware dependent portion export apis that return

     *  the physical address of the receive buffer and the size of that buffer.

     *  Finally, it creates a buffer to act as an intermediate

     *  buffer when receiving.

     */

    DEBUGMSG (ZONE_INIT | ZONE_FUNCTION, (TEXT("+COM_Init\r\n")));

    // Allocate our control structure.

    pSerialHead = (PHW_INDEP_INFO)LocalAlloc(LPTR, sizeof(HW_INDEP_INFO));

    // Check that LocalAlloc did stuff ok too.

    if ( !pSerialHead ) {

        DEBUGMSG(ZONE_INIT | ZONE_ERROR,

                 (TEXT("Error allocating memory for pSerialHead, COM_Init failed\n\r")));

        return(NULL);

    }

    // Initially, open list is empty.

    InitializeListHead( &pSerialHead->OpenList );

    InitializeCriticalSection(&(pSerialHead->OpenCS));

    pSerialHead->pAccessOwner = NULL;

    pSerialHead->fEventMask = 0;

    // Init CommTimeouts.

    pSerialHead->CommTimeouts.ReadIntervalTimeout = READ_TIMEOUT;

    pSerialHead->CommTimeouts.ReadTotalTimeoutMultiplier =

    READ_TIMEOUT_MULTIPLIER;

    pSerialHead->CommTimeouts.ReadTotalTimeoutConstant =

    READ_TIMEOUT_CONSTANT;

    pSerialHead->CommTimeouts.WriteTotalTimeoutMultiplier=  0;

    pSerialHead->CommTimeouts.WriteTotalTimeoutConstant =   0;

    /* Create tx and rx events and stash in global struct field. Check return.

     */

    pSerialHead->hSerialEvent = CreateEvent(0,FALSE,FALSE,NULL);

    pSerialHead->hKillDispatchThread = CreateEvent(0, FALSE, FALSE, NULL);

    pSerialHead->hTransmitEvent = CreateEvent(0, FALSE, FALSE, NULL);

    pSerialHead->hReadEvent = CreateEvent(0, FALSE, FALSE, NULL);

    if ( !pSerialHead->hSerialEvent || !pSerialHead->hKillDispatchThread ||

         !pSerialHead->hTransmitEvent || !pSerialHead->hReadEvent ) {

        DEBUGMSG(ZONE_ERROR | ZONE_INIT,

                 (TEXT("Error creating event, COM_Init failed\n\r")));

        LocalFree(pSerialHead);

        return(NULL);

    }

    /* Initialize the critical sections that will guard the parts of

     * the receive and transmit buffers.

     */

    InitializeCriticalSection(&(pSerialHead->ReceiveCritSec1));

    InitializeCriticalSection(&(pSerialHead->TransmitCritSec1));

    /* Want to use the Identifier to do RegOpenKey and RegQueryValue (?)

     * to get the index to be passed to GetHWObj.

     * The HWObj will also have a flag denoting whether to start the

     * listening thread or provide the callback.

     */

    DEBUGMSG (ZONE_INIT,(TEXT("Try to open %s\r\n"), (LPCTSTR)Identifier));

    hKey = OpenDeviceKey((LPCTSTR)Identifier);

    // 通過調用OpenDeviceKey, 驅動可以通過Identifier找到驅動的注冊表鍵的所在.

    if ( !hKey ) {

        DEBUGMSG (ZONE_INIT | ZONE_ERROR,

                  (TEXT("Failed to open devkeypath, COM_Init failed\r\n")));

        LocalFree(pSerialHead);

        return(NULL);

    }

    datasize = sizeof(DWORD);

    // 通過查詢DeviceArrayIndex鍵值, 我們可以知道需要打開的是普通串口或者是其他類型的串口設備.

    if ( RegQueryValueEx(hKey, L"DeviceArrayIndex", NULL, &kvaluetype,

                         (LPBYTE)&DevIndex, &datasize) ) {

        DEBUGMSG (ZONE_INIT | ZONE_ERROR,

                  (TEXT("Failed to get DeviceArrayIndex value, COM_Init failed\r\n")));

        RegCloseKey (hKey);

        LocalFree(pSerialHead);

        return(NULL);

    }

    datasize = sizeof(DWORD);

    // 通過查詢Priority256鍵值, 我們可以知道IST的優先級,  在后面會通過這個值來改變IST的優先級.

    if ( RegQueryValueEx(hKey, L"Priority256", NULL, &kvaluetype,

                         (LPBYTE)&pSerialHead->Priority256, &datasize) ) {

        pSerialHead->Priority256 = DEFAULT_CE_THREAD_PRIORITY;

        DEBUGMSG (ZONE_INIT | ZONE_WARN,

                  (TEXT("Failed to get Priority256 value, defaulting to %d\r\n"), pSerialHead->Priority256));

    }

    RegCloseKey (hKey);

    DEBUGMSG (ZONE_INIT,

              (TEXT("DevIndex %X\r\n"), DevIndex));

    // Initialize hardware dependent data.

    // GetSerialObject是連接MDD和PDD層的關鍵函數, 在這個函數里面決定了DevIndex是對什么設備進行操作.

    // 可能是標準的串口, 也可能是紅外接口

    pSerialHead->pHWObj = GetSerialObject( DevIndex );

    if ( !pSerialHead->pHWObj ) {

        DEBUGMSG(ZONE_ERROR | ZONE_INIT,

                 (TEXT("Error in GetSerialObject, COM_Init failed\n\r")));

        LocalFree(pSerialHead);

        return(NULL);

    }

    DEBUGMSG (ZONE_INIT, (TEXT("About to call HWInit(%s,0x%X)\r\n"),

                          Identifier, pSerialHead));

    // 這里調用了PDD層的HWInit

    pHWHead = pSerialHead->pHWObj->pFuncTbl->HWInit(Identifier, pSerialHead, pSerialHead->pHWObj);

    pSerialHead->pHWHead = pHWHead;

    /* Check that HWInit did stuff ok.  From here on out, call Deinit function

     * when things fail.

     */

    if ( !pHWHead ) {

        DEBUGMSG (ZONE_INIT | ZONE_ERROR,

                  (TEXT("Hardware doesn't init correctly, COM_Init failed\r\n")));

        COM_Deinit(pSerialHead);

        return(NULL);

    }

    DEBUGMSG (ZONE_INIT,

              (TEXT("Back from hardware init\r\n")));

    // Allocate at least twice the hardware buffer size so we have headroom

    HWBufferSize = 2 * pSerialHead->pHWObj->pFuncTbl->HWGetRxBufferSize(pHWHead);

    // Init rx buffer and buffer length here.

    pSerialHead->RxBufferInfo.Length =

    HWBufferSize > RX_BUFFER_SIZE ? HWBufferSize:RX_BUFFER_SIZE;

    pSerialHead->RxBufferInfo.RxCharBuffer =

    LocalAlloc(LPTR, pSerialHead->RxBufferInfo.Length);

    if ( !pSerialHead->RxBufferInfo.RxCharBuffer ) {

        DEBUGMSG(ZONE_INIT|ZONE_ERROR,

                 (TEXT("Error allocating receive buffer, COM_Init failed\n\r")));

        COM_Deinit(pSerialHead);

        return(NULL);

    }

    DEBUGMSG (ZONE_INIT, (TEXT("RxHead init'ed\r\n")));

    RxResetFifo(pSerialHead);

    InitializeCriticalSection(&(pSerialHead->RxBufferInfo.CS));

    InitializeCriticalSection(&(pSerialHead->TxBufferInfo.CS));

    DEBUGMSG (ZONE_INIT, (TEXT("RxBuffer init'ed with start at %x\r\n"),

                          pSerialHead->RxBufferInfo.RxCharBuffer));

    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);

        }

    }

    // OK, now that everything is ready on our end, give the PDD

    // one last chance to init interrupts, etc.

    (void) pSerialHead->pHWObj->pFuncTbl->HWPostInit( pHWHead );

    DEBUGMSG (ZONE_INIT | ZONE_FUNCTION, (TEXT("-COM_Init\r\n")));

    return(pSerialHead);

}


posted on 2011-03-01 16:13 心羽 閱讀(588) 評論(0)  編輯 收藏 引用 所屬分類: wince
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            国产精品久久久久久av下载红粉| 一区二区三区福利| 亚洲国产精品999| 伊人激情综合| 精品88久久久久88久久久| 国产亚洲一级高清| 国产偷自视频区视频一区二区| 国产午夜精品视频免费不卡69堂| 国产欧美日韩精品专区| 一区二区三区在线观看国产| 在线观看亚洲专区| 亚洲免费观看在线视频| 亚洲视频图片小说| 欧美中文在线免费| 欧美国产精品一区| 在线视频日本亚洲性| 香蕉亚洲视频| 免费的成人av| 欧美黑人在线观看| 裸体丰满少妇做受久久99精品| 欧美一进一出视频| 榴莲视频成人在线观看| 美女主播精品视频一二三四| 亚洲日本理论电影| 一区二区三区不卡视频在线观看 | 你懂的亚洲视频| 欧美日韩国产一中文字不卡| 国产精品二区二区三区| 在线免费观看视频一区| 在线天堂一区av电影| 久久久久国产精品人| 亚洲日本一区二区三区| 欧美一区二区精品| 欧美日韩大片| 亚洲第一福利在线观看| 亚洲欧美日韩一区在线观看| 亚洲国产精品999| 久久精品国产免费看久久精品| 欧美日韩一区二区三区免费看| 国产亚洲成人一区| 亚洲欧美综合v| 91久久精品国产91性色| 久久精品国产欧美亚洲人人爽| 欧美三级网址| 亚洲美女视频网| 欧美刺激午夜性久久久久久久| 亚洲欧美日韩精品在线| 欧美日韩美女在线| 亚洲黄网站黄| 男女激情视频一区| 久久久久国产一区二区| 国产欧美日本一区二区三区| 在线亚洲一区| 一二三区精品福利视频| 欧美日产一区二区三区在线观看| 亚洲大胆女人| 六月婷婷久久| 久久女同互慰一区二区三区| 狠狠色综合网站久久久久久久| 香蕉国产精品偷在线观看不卡| 一本久久a久久精品亚洲| 欧美国产先锋| 99精品国产在热久久| 亚洲国产高清在线| 欧美激情国产日韩| 亚洲美女av黄| 日韩亚洲在线观看| 欧美揉bbbbb揉bbbbb| 亚洲欧美国产毛片在线| 一区二区三区精品视频| 国产精品每日更新| 午夜精品亚洲| 久久久久久久久久久久久久一区| 久久国产福利国产秒拍| 香蕉久久精品日日躁夜夜躁| 国产日产精品一区二区三区四区的观看方式| 亚洲男女自偷自拍| 亚洲图片欧美日产| 国产午夜精品全部视频播放 | 亚洲美女区一区| 欧美福利一区| 一区二区三区欧美成人| 宅男噜噜噜66国产日韩在线观看| 欧美日韩中文在线观看| 亚洲欧美资源在线| 欧美一区2区三区4区公司二百| 韩国v欧美v日本v亚洲v| 欧美激情91| 欧美三日本三级三级在线播放| 羞羞答答国产精品www一本| 欧美在线观看一二区| 亚洲精品小视频在线观看| 一区二区成人精品| 精品成人在线视频| 日韩视频在线免费| 好男人免费精品视频| 亚洲国产视频一区二区| 国产精品综合色区在线观看| 欧美凹凸一区二区三区视频| 欧美日本不卡高清| 久久亚洲综合| 欧美午夜免费电影| 欧美激情精品久久久久久黑人| 国产精品久久激情| 蜜臀久久99精品久久久画质超高清 | 香蕉尹人综合在线观看| 久久久成人网| 亚洲女女做受ⅹxx高潮| 麻豆九一精品爱看视频在线观看免费 | 亚洲欧美不卡| 亚洲国内精品| 午夜精品一区二区在线观看 | 欧美一区二区三区的| 亚洲久久成人| 久久久久久久91| 欧美一区二区三区免费在线看| 美女视频黄 久久| 久久久一本精品99久久精品66| 欧美三区不卡| 亚洲国产精品精华液2区45| 国产一区二区福利| 亚洲夜间福利| 亚洲天堂网在线观看| 欧美成人精品一区二区| 久久亚洲午夜电影| 国产一区激情| 性欧美精品高清| 欧美日本精品| 中文精品99久久国产香蕉| 久久一区欧美| 免费成人av资源网| 国产无一区二区| 亚洲欧美日本日韩| 亚洲一区二区免费在线| 欧美日韩国产123| 最新日韩中文字幕| 99re6热只有精品免费观看| 久久综合久久综合这里只有精品| 久久精品五月婷婷| 国产日产欧美精品| 欧美一区二区观看视频| 久久久久久婷| 经典三级久久| 裸体一区二区三区| 欧美黄色影院| 一区二区久久久久| 欧美天堂亚洲电影院在线播放| 亚洲精品婷婷| 亚洲欧美久久久| 国产欧美日韩不卡| 久久成人综合网| 欧美风情在线观看| 一本一本大道香蕉久在线精品| 欧美三级电影一区| 亚洲图片在区色| 久久亚洲捆绑美女| 亚洲高清免费在线| 欧美日韩aaaaa| 亚洲综合欧美日韩| 免费影视亚洲| 一区二区欧美国产| 国产日韩欧美一区在线| 久久久久久一区二区三区| 欧美黑人在线观看| 亚洲欧美韩国| 伊人伊人伊人久久| 欧美区一区二区三区| 亚洲在线视频观看| 免费看成人av| 亚洲欧美日韩一区| 尤物yw午夜国产精品视频明星| 欧美激情成人在线| 亚洲欧美日韩精品久久久| 欧美高清在线一区| 午夜精品久久久99热福利| 精品福利免费观看| 国产精品v一区二区三区 | 亚洲愉拍自拍另类高清精品| 久久这里有精品视频| 亚洲乱码国产乱码精品精可以看| 国产精品九九久久久久久久| 久久久国产一区二区| 日韩视频免费大全中文字幕| 久久综合九色99| 亚洲一区二区三区在线播放| 亚洲电影在线播放| 国产精品日韩二区| 欧美福利精品| 久久全国免费视频| 亚洲综合视频在线| 99精品视频网| 欧美风情在线观看| 久久久久久久网| 亚洲欧美日韩天堂| 夜夜爽av福利精品导航| 影音先锋日韩精品| 国产亚洲欧美一区在线观看| 欧美三级日本三级少妇99| 日韩视频免费在线观看| 毛片基地黄久久久久久天堂|