WinCE串口驱动解析

PS:第一篇技术博客,轻拍。。


题记:

今天把WinCE的整个串口驱动看了一遍,硬件是S5PV210的开发板,从MDD到PDD,有些收获,怕忘了,就写下来。由于个人文笔不好,可能会有些乱。假如有不对的地方,欢迎指正。


MDD层微软已经写好了,源码位于\WINCE600\PUBLIC\COMMON\OAK\DRIVERS\SERIAL\COM_MDD2,主要实现了标准流驱动的接口:

COM_Init

COM_Deinit

COM_PreDeinit

COM_Open

COM_Close

COM_PreClose

COM_Read

COM_Write

COM_Seek

COM_PowerDown

COM_PowerUp

COM_IOControl

这些接口都跟硬件无关。

这里只分析一个COM_Init,只要理清楚了一个,再看其他的就简单多了。系统开机时,通过COM_Init加载驱动,注册串口,并对硬件进行一定的初始化。要注册和初始化哪个串口(S5PV210上芯片上有4个)是通过读取注册表来得知的,这个值被定义为DevIndex。然后调用GetSerialObject( DevIndex )进行函数映射,然后就可以进行硬件的初始化了:

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

接着完成其他的初始化任务(这里只说明了一小部分COM_Init的源码)。


那么那个HWInit函数到底是什么呢?这里就说到了上面提到的函数映射了。实现方式如下:

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

pFuncTbl是一个HW_VTBL类型的指针,它里面的函数被映射到IoVTbl中对应的函数。两者的定义如表所示

HW_VTBLIoVTbl
HWInit
HWPostInit
HWDeinit
HWOpen
HWClose
HWGetIntrType
HWRxIntrHandler
HWTxIntrHandler
HWModemIntrHandler
HWLineIntrHandler
HWGetRxBufferSize
HWPowerOff
HWPowerOn
HWClearDTR
HWSetDTR
HWClearRTS
HWSetRTS
HWEnableIR
HWDisableIR
HWClearBreak
HWSetBreak
HWXmitComChar
HWGetStatus
HWPreDeini
HWGetModemStatus
HWGetCommProperties
HWPurgeComm
HWSetDCB
HWSetCommTimeouts
HWIoctl
SerInit,
SerPostInit,
SerDeinit,
SerOpen,
SerClose,
SerGetInterruptType,
SerRxIntr,
SerTxIntrEx,
SerModemIntr,
SerLineIntr,
SerGetRxBufferSize,
SerPowerOff,
SerPowerOn,
SerClearDTR,
SerSetDTR,
SerClearRTS,
SerSetRTS,
SerEnableIR,
SerDisableIR,
SerClearBreak,
SerSetBreak,
SerXmitComChar,
SerGetStatus,
PreDeinit,
SerGetModemStatus,
SerGetCommProperties,
SerPurgeComm,
SerSetDCB,
SerSetCommTimeouts,
SerIoctl

而IoVTbl中的函数则最终调用到硬件。下面是SerSetBreak的函数体:

VOID
SerSetBreak(
           PVOID   pHead // @parm PVOID returned by HWinit.
           )
{
    DEBUGMSG (ZONE_FUNCTION, (TEXT("+SL_SetBreak, 0x%X\r\n"), pHead));
    if (pHead)
        ((CSerialPDD *)pHead)->SetBreak(TRUE);
    DEBUGMSG (ZONE_FUNCTION, (TEXT("-SL_SetBreak, 0x%X\r\n"), pHead));
}

为了方便说明,这里先解释一下串口驱动用到的几个类:

类CSerialPDD:由类CRegistryEdit派生而来;

类CPddUart:由类CSerialPDD和类CMiniThread派生而来;

类CPddSerial:由CPddUart派生而来,分别实现对4个串口的寄存器的配置等。


回到函数SerSetBreak,SerSetBreak中参数pHead为SerInit()返回的指针,它指向类CPddSerial。而在CPddSerial中最终实现了函数SetBreak()。

(SerInit()中定义了一个类CPddSerial,并返回一个指向它的指针。)


这样就可以基本理清系统是如何从MDD层一步步执行PDD层,再到最底层的硬件寄存器了。


另外,对于串口,系统还提供了SetCommState这样的函数来对其进行设置。这些函数是在coredll.dll中实现:

BOOL WINAPI
SetCommState(HANDLE hCommDev, LPDCB lpDCB)
{
	DWORD	dwBytesReturned;
	return DeviceIoControl (hCommDev, IOCTL_SERIAL_SET_DCB,
							(LPVOID)lpDCB, sizeof(DCB),
							(LPVOID)0, 0, &dwBytesReturned, 0);
}

它通过调用IOControl来实现其目的,而在COM_IOControl中则实现了这些IOCTL。


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值