您的位置:首页 > 运维架构 > 网站架构

Windows CE串口驱动简析(1)-驱动架构(基于WinCE5.0 SMDK2410 BSP的Serial驱动)

2010-06-08 15:05 447 查看
WinCE5.0 SMDK2410 BSP的串口驱动由两个文件组成.一个在BSP目录下的/SRC/DRIVERS/SERIAL/ser_smdk2410.cpp,另一个在/WINCE500/PUBLIC/COMMON/OAK/CSP/ARM/SAMSUNG/S3C2410X/SERIAL/pdds3c2410_ser.cpp,为了实现BSP的完整性,并方便修改,在移植到GEC2410的时候,将该目录下的所有文件放到BSP目录下,特别的对于串口驱动,我把pdds3c2410_ser.cpp同样也放到BSP目录/SRC/DRIVERS/SERIAL/下,只需修改下source文件,将pdds3c2410_ser.cpp加入编译文件即可.
SOURCES= ser_smdk2410.cpp /
pdds3c2410_ser.cpp
其实在WinCE6.0的DEVICEEMULATOR BSP下就是采用这样的目录文件结构.
接下来我们就进入正题.
一. 驱动结构
串口驱动是个流接口驱动,其中流接口函数,比如COM_Init,COM_Open,COM_Read,COM_Write等实现在MDD库com_mdd2.lib中(/WINCE500/PUBLIC/COMMON/OAK/DRIVERS/SERIAL/COM_MDD2/mdd.c),同样还有一个PDD的库serpddcm.lib(/WINCE500/PUBLIC/COMMON/OAK/DRIVERS/SERIAL/SERPDDCM/cserpdd.cpp),这个实际上相当于PDD COMMON层,也是平台无关的.
BSP目录下的SERIAL驱动实际上是真正的PDD层,与实际硬件平台相关的代码.
这里先简单分析下MDD,PDD COMMON和PDD的结构,三者是如何联系的.

MDD(mdd.c)实现了COM_**的流接口函数,中间调用了PDD COMMON层的函数,而PDD COMMON又调用PDD的函数.其中前两者的联系在COM_Init中的:
// Initialize hardware dependent data.
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));
pHWHead = pSerialHead->pHWObj->pFuncTbl->HWInit(Identifier, pSerialHead, pSerialHead->pHWObj);
pSerialHead->pHWHead = pHWHead;

pSerialHead是HW_INDEP_INFO结构的指针,相当于串口设备的句柄,定义在serpriv.h.里面包含串口设备各项信息.
typedef struct __HW_INDEP_INFO {
CRITICAL_SECTION	TransmitCritSec1;		// @field Protects tx action
CRITICAL_SECTION	ReceiveCritSec1;		// @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_INFO	RxBufferInfo;	// @field rx buffer info.
TX_BUFFER_INFO	TxBufferInfo;	// @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;

pHWObj是HWOBJ结构的指针.HWOBJ是HW_INDEP_INFO成员,被称作硬件相关数据.在serhw.h中定义如下:
typedef struct __HWOBJ {
ULONG BindFlags;
DWORD dwIntID;
PHW_VTBL pFuncTbl;
} HWOBJ, *PHWOBJ;

其中pFuncTbl指向的函数指针数组HW_VTBL就是PDD COMMON层(cserpdd.cpp)中实现的各个函数,如SerInit,SerOpen等,如下代码所示:
const
HW_VTBL IoVTbl = {
SerInit,
SerPostInit,
SerDeinit,
SerOpen,
SerClose,
SerGetInterruptType,
SerRxIntr,
SerTxIntrEx,
SerModemIntr,
SerLineIntr,
SerGetRxBufferSize,
SerPowerOff,
SerPowerOn,
SerClearDTR,
SerSetDTR,
SerClearRTS,
SerSetRTS,
SerEnableIR,
SerDisableIR,
SerClearBreak,
SerSetBreak,
SerXmitComChar,
SerGetStatus,
SerReset,
SerGetModemStatus,
SerGetCommProperties,
SerPurgeComm,
SerSetDCB,
SerSetCommTimeouts,
SerIoctl
};

COM_Init通过调用GetSerialObject来获得相应PDD的HWOBJ结构,GetSerialObject是MDD连接PDD的关键函数,而DeviceArrayIndex对应的就是串口的端口序号,一个端口序号对应一个UART端口,也对应一个串口驱动程序PDD层运行时代码,这个值可以从注册表中DeviceArrayIndex项获得.
COM_Init函数调用GetSerialObject将DeviceArrayIndex传递到HWOBJ的dwIntID成员再传给CreateSerialObject函数.这样COM_Init通过适用不同的参数调用GetSerialObject就可以获得同一平台上同时存在不同串口的PDD对象,可以使多个PDD对象共享一个MDD.
以下是GetSerialObject的代码,位于cserpdd.cpp,获得了PDD COMMON中的HW_VTBL结构的函数指针,同时将DeviceArrayIndex传递给dwIntID.
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);
}

COM_Init中的:
pHWHead = pSerialHead->pHWObj->pFuncTbl->HWInit(Identifier, pSerialHead, pSerialHead->pHWObj);
pSerialHead->pHWHead = pHWHead;
HWInit实际上调用的就是cserpdd.cpp中的SerInit,它将调用CreateSerialObject函数来获得串口驱动的PDD层.实际上就是返回PDD中需要实现的串口类的指针.
PVOID
SerInit(
ULONG   Identifier, // @parm Device identifier.
PVOID   pMddHead,   // @parm First argument to mdd callbacks.
PHWOBJ  pHWObj      // @parm Pointer to our own HW OBJ for this device
)
{
DEBUGMSG (ZONE_CLOSE,(TEXT("+SerInit, 0x%X/r/n"), Identifier));
CSerialPDD * pSerialPDD = NULL;
if (pHWObj) {
DWORD dwIndex= pHWObj->dwIntID;
pHWObj->dwIntID = 0;
pSerialPDD = CreateSerialObject((LPTSTR)Identifier,pMddHead, pHWObj,dwIndex);
}
if (pSerialPDD==NULL) {
ASSERT(FALSE);
LocalFree(pHWObj);
}
DEBUGMSG (ZONE_CLOSE,(TEXT("-SerInit, 0x%X/r/n"), pSerialPDD));
return pSerialPDD;
}

CreateSerialObject定义在PDD层,这里是Ser_smdk2410.cpp中的代码:
CSerialPDD * CreateSerialObject(LPTSTR lpActivePath, PVOID pMdd,PHWOBJ pHwObj, DWORD DeviceArrayIndex)
{
CSerialPDD * pSerialPDD = NULL;
switch (DeviceArrayIndex) {
case 0:
pSerialPDD = new CPdd2410Serial1(lpActivePath,pMdd, pHwObj);
break;
case 1:
pSerialPDD = new CPdd2410Serial2(lpActivePath,pMdd, pHwObj);
break;
}
if (pSerialPDD && !pSerialPDD->Init()) {
delete pSerialPDD;
pSerialPDD = NULL;
}
return pSerialPDD;
}

这里的CPdd2410Serial1和CPdd2410Serial2就是PDD需要实现的两个类,分别对应UART0和UART1.下一篇我们就来详细看看串口驱动的PDD层.
关于MDD层更详细的内容,可以参考这篇文章:
http://nasiry.cnblogs.com/archive/2005/04/12/136175.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐