Wince的串口模型是固定的,其网络协议是符合ISO/OS模型的,在典型的应用中,serialAPI与间接通过TAPI或直接与ActiveSync交互,组成CE网络的一部分。其实整个驱动模型是相当复杂的,好在驱动仅仅使用到SerialAPI这一层,在这个层次上串口的行为相对比较简单。在WinCE中,串口驱动模型是作为Stream来实现的(即:流设备驱动)。
串口驱动本身分为PDD层和MDD层:
MDD层提供了框架性的实现,负责提供OS所需的的基本实现,它为上层的设备管理器提供标准的流驱动接口(COM_XXX),而PDD层是针对串口硬件的相应操作,PDD层主要实现了HWOBJ结构以及结构中关于串口硬件的函数指针,在MDD层和PDD层之间有一个DSSI的接口,这个接口是人为设定的,在串口驱动中这个接口主要指的是HWOBJ结构体,PDD层会传给MDD层一个HWOBJ结构体指针,这样MDD层就可以通过HWOBJ来调用PDD层的函数来操控串口硬件了,在实际的开发中我们只需要实现MDD层的相关函数就可以对串口进行操作了。
具体函数分析:
数据结构:
1.HWOBJ结构体:
typedef struct __HWOBJ
{
ULONG BindFlags;
DWORD dwIntID;
PHW_VTBL pFuncTbl;
} HWOBJ, *PHWOBJ;
BindFlags:用于控制MDD层如何来处理IST,具体值如下:
THREAD_IN_PDD:MDD层不处理,中断在PDD层处理。
THREAD_AT_INIT:在驱动初始化的时候,MDD层启动IST。
THREAD_AT_OPEN:在驱动被Open的时候,MDD层启动IST。
dwInitID: 系统的中断号 ,
pFuncTbl: 指向一个PHW_VTBL结构,该结构中包含一个函数指针列表,这些函数指针指向串口硬件操作函数,用于操作串口,
2.PHW_VTBL结构体定义了一系列指向串口硬件的指针:
typedef struct __HW_VTBL {
PVOID (*HWInit)(ULONG Identifier, PVOID pMDDContext, PHWOBJ pHWObj);
BOOL (*HWPostInit)(PVOID pHead);
ULONG (*HWDeinit)(PVOID pHead);
BOOL (*HWOpen)(PVOID pHead);
ULONG (*HWClose)(PVOID pHead);
INTERRUPT_TYPE (*HWGetIntrType)(PVOID pHead);
ULONG (*HWRxIntrHandler)(PVOID pHead, PUCHAR pTarget, PULONG pBytes);
VOID (*HWTxIntrHandler)(PVOID pHead, PUCHAR pSrc, PULONG pBytes);
VOID (*HWModemIntrHandler)(PVOID pHead);
VOID (*HWLineIntrHandler)(PVOID pHead);
//ULONG (*HWGetRxBufferSize)(PVOID pHead); // orginal MDD
ULONG (*HWGetRxBufferSize)(PVOID pHead, PULONG pBufaddr); // tcc modify
BOOL (*HWPowerOff)(PVOID pHead);
BOOL (*HWPowerOn)(PVOID pHead);
VOID (*HWClearDTR)(PVOID pHead);
VOID (*HWSetDTR)(PVOID pHead);
VOID (*HWClearRTS)(PVOID pHead);
VOID (*HWSetRTS)(PVOID pHead);
BOOL (*HWEnableIR)(PVOID pHead, ULONG BaudRate);
BOOL (*HWDisableIR)(PVOID pHead);
VOID (*HWClearBreak)(PVOID pHead);
VOID (*HWSetBreak)(PVOID pHead);
BOOL (*HWXmitComChar)(PVOID pHead, UCHAR ComChar);
ULONG (*HWGetStatus)(PVOID pHead, LPCOMSTAT lpStat);
VOID (*HWPreDeinit)(PVOID pHead);
VOID (*HWGetModemStatus)(PVOID pHead, PULONG pModemStatus);
VOID (*HWGetCommProperties)(PVOID pHead, LPCOMMPROP pCommProp);
VOID (*HWPurgeComm)(PVOID pHead, DWORD fdwAction);
BOOL (*HWSetDCB)(PVOID pHead, LPDCB pDCB);
BOOL (*HWSetCommTimeouts)(PVOID pHead, LPCOMMTIMEOUTS lpCommTO);
BOOL (*HWIoctl)(PVOID pHead, DWORD dwCode,PBYTE pBufIn,DWORD dwLenIn,
PBYTE pBufOut,DWORD dwLenOut,PDWORD pdwActualOut);
} HW_VTBL, *PHW_VTBL;
这些对串口的操作包括初始化,打开,关闭,加载,注销等操作,很多设置是针对9针串口(DCD,RXD,TXD,DTR,GND,DSR,RTS,CTS,DELL)的,相对于我们常用的3针串口(RXD,TXD,GND),9针串口大多用于modem模式,这些函数的具体功能在MSDN上是可以查到的。
3.typedef struct __HW_INDEP_INFO {
CRITICAL_SECTIONTransmitCritSec1;// @field Protects tx action
CRITICAL_SECTIONReceiveCritSec1; // @field Protects rx action
PHWOBJ pHWObj; // @field Represents PDD object.
PVOID pHWHead;// @field Device context for PDD.
HANDLE hSerialEvent; // @field Serial event, both rx and tx
HANDLE hReadEvent; // @field Serial event, both rx and tx
HANDLE hKillDispatchThread; // @field Synchonize thread end
HANDLE hTransmitEvent; // @field transmit event, both rx and tx
HANDLE pDispatchThread; // @field ReceiveThread
ULONG Priority256; // @field CeThreadPriority of Dispatch Thread.
ULONG DroppedBytesMDD;// @field Record of bytes dropped by MDD.
ULONG DroppedBytesPDD;// @field Record of bytes dropped by PDD.
ULONG RxBytes; // @field Record of total bytes received.
ULONG TxBytes; // @field Record of total bytes transmitted.
ULONG TxBytesPending;// @field Record of total bytes awaiting transmit.
ULONG TxBytesSent;// @field Record of bytes sent in one transmission
DCB DCB;// @field DCB (see Win32 Documentation.
COMMTIMEOUTS CommTimeouts; // @field Time control field.
DWORD OpenCnt;// @field Protects use of this port
DWORD KillRxThread:1;// @field Flag to terminate SerialDispatch thread.
DWORD XFlow:1;// @field True if Xon/Xoff flow ctrl.
DWORD StopXmit:1;// @field Stop transmission flag.
DWORD SentXoff:1;// @field True if XOFF sent.
DWORD DtrFlow:1;// @field True if currently DTRFlowed
DWORD RtsFlow:1;// @field True if currently RTSFlowed
DWORD fAbortRead:1; // @field Used for PURGE
DWORD fAbortTransmit:1;// @field Used for PURGE
DWORD Reserved:24;// @field remaining bits.
ULONG fEventMask;// @field Sum of event mask for all opens
RX_BUFFER_INFORxBufferInfo;// @field rx buffer info.
TX_BUFFER_INFOTxBufferInfo;// @field tx buffer info.
LIST_ENTRY OpenList; // @field Head of linked list of OPEN_INFOs
CRITICAL_SECTION OpenCS; // @field Protects Open Linked List + ref counts
PHW_OPEN_INFO pAccessOwner; // @field Points to whichever open has acess permissions
} HW_INDEP_INFO, *PHW_INDEP_INFO;
这个结构体是独立于串口硬件的头信息,这个结构体定义了一系列与串口操作有关的变量接收,发送缓存,字节数,事件等等,具体功能要参见源码中的实现。
MDD层:
下面正式介绍与我们开发密切相关的MDD层驱动模型,串口驱动的MDD层实现是标准的流驱动,包括:
1.COM_Init (ULONG Identifier):
它是该驱动的初始化函数,通过硬件抽象接口HWInit初始化硬件。如果驱动被设备管理器加载,参数Identifier包含一个注册表键值在“HKEY_LOCAL_MACHINE\Drivers\Active”的路径下。
2. COM_Deinit(void):当驱动被称被卸下的时候该事件启动,用作与COM_Init相反的操作。停止在MDD中的所有IST,释放内存资源和临界区等系统资源。
3.COM_Open(HANDLE pContext, DWORD AccessCode, DWORD ShareMode):
COM_Oepn在CreateFile后被调用,用于以读/写模式打开设备,并初始化所需要的空间/资源等,创建相应的实例。Open操作完成后,驱动就进入了工作状态。
4.COM_Close(DWORD pContext):
COM_Close释放COM_Open所使用的系统资源,停止IST线程,恢复驱动状态。
5.COM_Read(HANDLE pContext, PUCHAR pTargetBuffer,
ULONG BufferLength, PULONG pBytesRead):
COM_Read是获取串口所接收到数据的操作,在前面的IST中没有看到对RX buffer进行修改Read标记的操作,也就是这儿来完成的。
6.COM_Write(HANDLE pContext, PUCHAR pSourceBytes,
ULONG NumberOfBytes):
COM_Write是与COM_Read相对应的操作,是写串口数据的。应用程序调用WriteFile函数写串口的时候,该函数被调用。在程序的开始,同样也是参数检查,内容与COM_Read一致。其中pContext参数是COM_Open函数返回的Handle。pSourceBytes指向一个Buffer,该Buffer包含要写入串口的数据。NumberOfBytes表示要写入串口的数据的大小。
7.COM_PowerUp/ COM_PowerDown (HANDLE pContext):
这两个函数的调用都由CE的电源事件来引发,MDD并没有对这两个函数进行处理,仅仅是将其传递给PDD。
8.COM_IOControl (DWORD dwOpenData, DWORD dwCode, PBYTE pBufIn, DOWRD dwLenIn, PBYTE pBufOut, DWORD dwLenOut, PDWORD pdwActualOut):
该函数主要实现了一些串口的IO控制,他会被应用层的一些串口函数调用来获得或者设置串口的状态。
PDD层:
实际上,在PDD层的主要工作就2个:一是控制硬件;二是和上层打好关系。先说上层接口,上层用了GetSerialHead()来获得接口,所以PDD里面要实现GetSerialHead()的函数,并且将接口返回给上层。
GetSerialObject( DWORD DeviceArrayIndex )
{
PHWOBJ pSerObj;
pSerObj=(PHWOBJ)LocalAlloc( LPTR ,sizeof(HWOBJ) );
if ( !pSerObj )
return (NULL);
pSerObj->BindFlags = THREAD_IN_PDD;
pSerObj->dwIntID = DeviceArrayIndex;
pSerObj->pFuncTbl = (HW_VTBL *) & IoVTbl;
return (pSerObj);
}
PDD层的函数主要是实现了对串口硬件的操作,函数不少,可以参考以下列表:
序号 | 函数 | 说明 |
1 | GetSerialObject | 返回一个指向HWOBJ结构的指针,该结构包含了相关硬件接口函数的函数指针 |
2 | HWClearBreak | 清除串口中断状态,用于串口从中断状态恢复 |
3 | HWClearDTR | 设置串口的DTR管脚为低 |
4 | HWClearRTS | 设置串口的RTS管脚为低 |
5 | HWClose | 关闭由HWInit函数初始化的设备 |
6 | HWDisableIR | 禁用串口的红外模式 |
7 | HWEnableIR | 启用串口的红外模式 |
8 | HWGetCommProperties | 重新获得当前串口设备的硬件属性 |
9 | HWGetIntrType | 获得当前的中断类型 |
10 | HWGetModemStatus | 获得Modem的状态 |
11 | HWGetRxBufferSize | 获得串口硬件接收Buffer的大小 |
12 | HWGetRxStart | 返回硬件接收Buffer的起始位置 |
13 | HWGetStatus | 获得硬件状态信息 |
14 | HWInit | 初始化串口硬件设备 |
15 | HWIoctl | 执行I/O控制 |
16 | HWLineIntrHandler | 线路状态信息中断处理函数 |
17 | HWOpen | 打开串口设备 |
18 | HWPowerOff | 串口硬件进入Suspend模式 |
19 | HWPowerOn | 串口硬件从Suspend模式恢复到工作模式 |
20 | HWSetDCB | 设置串口硬件设备信息 |
21 | HWSetDTR | 设置串口的DTR管脚为高 |
22 | HWSetRTS | 设置串口的RTS管脚为高 |
23 | HWPurgeComm | 清除串口硬件buffer的信息 |
24 | HWPutBytes | 通过写数据到硬件中来直接发送数据 |
25 | HWReset | 复位串口硬件 |
26 | HWRxIntrHandler | 接收数据中断处理函数 |
27 | HWSetBreak | 设置串口为中断状态,停止发送接收数据 |
28 | HWTxIntrHandler | 串口发送中断处理函数 |