WINCE官方提供的串口驱动PDD层代码简单分析
作者:FLandY1982(flandy1982@sina.com)
日期:2010-1-11
版本:1.0
修改:
转载请注明出处:http://blog.csdn.net/FLandY1982/archive/2010/01/11/5175162.aspx
注意:
1.关于MDD层的代码详细分析,可以参考文章:http://blog.csdn.net/FLandY1982/archive/2009/12/24/5070059.aspx
2.文中所引用的代码, 都在目录%WINCEROOT%/PUBLIC/COMMON/OAK/DRIVERS/SERIAL/下
3.开发者在实现PDD层时, 可以直接继承CSerialPdd类, 然后对相关的接口进行实现和重载,也可以直接实现PDD层函数, 如果是直接实现PDD层函数本文第1章内容可以不用阅读。
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层的函数为如下函数:
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. | |
This function clears an RS-232 line break condition. | |
This function clears the Data Terminal Ready (DTR) signal. | |
This function clears the Request to Send (RTS) signal. | |
This function closes the device initialized by the HWInit function. | |
This function is called by the upper layer to de-initialize the hardware when a device driver is unloaded. | |
This function disables the infrared (IR) serial interface. | |
This function enables the infrared (IR) serial interface. | |
This function retrieves the current properties of the communications device. | |
This function returns the current interrupt type. | |
This function retrieves the modem status. | |
This function returns the maximum number of bytes that the hardware buffer can hold, not including the padding, stop, and start bits. | |
This function returns the start of the hardware-receive buffer. | |
This function specifies the hardware status API. | |
This function initializes a serial device. | |
This function executes device I/O control (IOCTL) routines. | |
This function handles line interrupts for serial port devices. | |
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. | |
This function is called by the upper layer to open the serial device. | |
In Windows CE 3.0 and later, this function has been replaced with the new function HWModemIntrHandler. | |
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. | |
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). | |
This function notifies the platform-dependent driver that the hardware platform is resuming from suspend mode. It is called by the MDD. | |
This function purges the communications device. | |
This function writes bytes to hardware. The driver calls this function. | |
This function resets the hardware API. | |
This function handles serial port interrupts. | |
This function sets the line break condition on the transmit line. | |
This function sets the communications time-out events in response to a call to the SetCommTimeouts function. | |
This function sets the device control block. | |
This function sets the Data Terminal Ready (DTR) signal. | |
This function sets the Request to Send (RTS) signal. | |
This function handles the transmit interrupt for serial port devices. | |
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