作者:ARM-WinCE
在WinCE中,串口驱动实际上就是一个流设备驱动,具体架构如图:
串口驱动本身分为MDD层和PDD层。MDD层对上层的Device Manager提供了标准的流设备驱动接口(COM_xxx),PDD层实现了HWOBJ结构及结构中若干针对于串口硬件操作的函数指针,这些函数指针将指向PDD层中的串口操作函数。DDSI是指MDD层与PDD层的接口,在串口驱动中实际上就是指HWOBJ,PDD层会传给MDD层一个HWOBJ结构的指针,这样MDD层就可以调用PDD层的函数来操作串口。
微软针对于串口驱动提供了参考源代码,可以在下面的目录下找到:”/WINCE600/PUBLIC/COMMON/OAK/DRIVERS/SERIAL”。
串口驱动的结构也就是这样了,下面介绍相关的驱动中的接口。
1. HWOBJ结构
BindFlags:用于控制MDD层如何来处理IST,具体值如下:
THREAD_IN_PDD:MDD层不处理,中断在PDD层处理。
THREAD_AT_INIT:在驱动初始化的时候,MDD层启动IST。
THREAD_AT_OPEN:在驱动被Open的时候,MDD层启动IST。
dwInitID: 系统的中断号 pFuncTbl: 指向一个PHW_VTBL结构,该结构中包含一个函数指针列表,这些函数指针指向串口硬件操作函数,用于操作串口。
- typedef struct __HW_VTBL
- {
- PVOID (*HWInit)(ULONG Identifier, PVOID pMDDContext);
- ULONG (*HWDeinit)(PVOID pHead);
- BOOL (*HWOpen)(PVOID pHead);
- ULONG (*HWClose)(PVOID pHead);
- ULONG (*HWGetBytes)(PVOID pHead, PUCHAR pTarget, PULONG pBytes);
- PVOID (*HWGetRxStart)(PVOID pHead);
- INTERRUPT_TYPE (*HWGetIntrType)(PVOID pHead);
- VOID (*HWOtherIntrHandler)(PVOID pHead);
- VOID (*HWLineIntrHandler)(PVOID pHead);
- ULONG (*HWGetRxBufferSize)(PVOID pHead);
- VOID (*HWTxIntrHandler)(PVOID pHead);
- ULONG (*HWPutBytes)(PVOID pHead, PUCHAR pSrc, ULONG NumBytes, PULONG pBytesSent);
- 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 (*HWReset)(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;
typedef struct __HW_VTBL { PVOID (*HWInit)(ULONG Identifier, PVOID pMDDContext); ULONG (*HWDeinit)(PVOID pHead); BOOL (*HWOpen)(PVOID pHead); ULONG (*HWClose)(PVOID pHead); ULONG (*HWGetBytes)(PVOID pHead, PUCHAR pTarget, PULONG pBytes); PVOID (*HWGetRxStart)(PVOID pHead); INTERRUPT_TYPE (*HWGetIntrType)(PVOID pHead); VOID (*HWOtherIntrHandler)(PVOID pHead); VOID (*HWLineIntrHandler)(PVOID pHead); ULONG (*HWGetRxBufferSize)(PVOID pHead); VOID (*HWTxIntrHandler)(PVOID pHead); ULONG (*HWPutBytes)(PVOID pHead, PUCHAR pSrc, ULONG NumBytes, PULONG pBytesSent); 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 (*HWReset)(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;
这些函数将在PDD层实现,用于实际的串口硬件操作。
2. MDD层API
MDD层向上提供了流设备接口,这部分代码微软已经实现,用于管理串口。虽然我们不需要实现这部分,但是还是对相应的接口做个简单介绍。
2.1HANDLE COM_Init(ULONG Identifier):
初始化串口设备,该函数通过读取注册表获得串口设备号,并获得相应的HWOBJ的结构指针,通过该指针调用PDD层的硬件初始化函数初始化串口。
Identifier:如果驱动被设备管理器加载,那么这个参数将包含一个注册表键值在” HKEY_LOCAL_MACHINE/Drivers/Active”路径下。如果驱动是通过调用RegisterDevice函数来加载的,那么这个值等于dwInfo的值。在COM_Init中,会先打开该键值,用返回的句柄来查询DeviceArrayIndex值,并根据该值获得PDD层的HWOBJ结构指针。
2.2 BOOL COM_Deinit(void):
卸载串口设备,该函数中主要做了一些释放资源的操作。也可以被DeregisterDevice函数调用。
2.3 HANDLE COM_Open(HANDLE pContext, DWORD AccessCode, DWORD ShareMode):
打开串口设备。应用程序调用CreateFile函数打开串口时,该函数会被调用。
pContext:COM_Init函数返回的Handle。
AccessCode:设置访问模式,比如共享读或者是读写模式。
ShareMode:在参数从应用程序中的CreateFile函数中传来,表示是否支持独自占有。
2.4 BOOL COM_Close(DWORD pContext):
关闭串口设备。应用程序调用CloseHandle函数关闭串口时,该函数会被调用。
pContext:该参数为COM_Open函数返回的Handle。
2.5 ULONG COM_Read(HANDLE pContext, PUCHAR pTargetBuffer, ULONG BufferLength, PULONG pBytesRead):
读串口数据。应用程序调用ReadFile函数读串口的时候,该函数被调用。
pContext:COM_Open函数返回的Handle。
pTargetBuffer:指向一个用于存放读到数据的Buffer。
BufferLength:pTargetBuffer指向的Buffer的大小。
pBytesRead:实际读到的数据的大小。
2.6 ULONG COM_Write(HANDLE pContext, PUCHAR pSourceBytes, ULONG NumberOfBytes):
写串口数据。应用程序调用WriteFile函数写串口的时候,该函数被调用。
pContext:COM_Open函数返回的Handle。
pSourceBytes:指向一个Buffer,该Buffer包含要写入串口的数据。
NumberOfBytes:要写入串口的数据的大小。
2.7 BOOL COM_PowerUp(HANDLE pContext):
该函数主要用于串口设备从suspend模式恢复到正常模式。
pContext:串口设备的Handle。
2.8 BOOL COM_PowerDown(HANDLE pContext):
该函数主要用于串口设备从正常模式进入suspend状态。
pContext:串口设备的Handle。
2.9 BOOL COM_IOControl(DWORD dwOpenData, DWORD dwCode, PBYTE pBufIn, DOWRD dwLenIn, PBYTE pBufOut, DWORD dwLenOut, PDWORD pdwActualOut):
该函数主要实现了一些串口的IO控制,他会被应用层的一些串口函数调用来获得或者设置串口的状态。
dwOpenData:COM_Open函数返回的Handle。
dwCode:I/O控制操作码。
pBufIn:传入的Buffer。
dwLenIn:传入的Buffer的大小。
pBufOut:传出的Buffer。
dwLenOut:传出的Buffer的大小。
pdwActualOut:实际传出的数据的大小。
对于串口驱动来说,COM_IOControl函数非常有用,应用程序通过调用COM_IOControl函数并传入不同的操作码,实现了控制串口的功能。这里列举一些操作码如下:
操作码 | 解释 |
IOCTL_SERIAL_CLR_DTR | 设置串口的DTR管脚为低 |
IOCTL_SERIAL_CLR_RTS | 设置串口的RTS管脚为低 |
IOCTL_SERIAL_DISABLE_IR | 禁用串口的红外模式 |
IOCTL_SERIAL_ENABLE_IR | 启用串口的红外模式 |
IOCTL_SERIAL_GET_COMMSTATUS | 清除串口设备的异常标记并返回当前状态 |
IOCTL_SERIAL_GET_DCB | 获得串口的DCB结构 |
IOCTL_SERIAL_GET_MODEMSTATUS | 获得当前Modem的控制寄存器值 |
IOCTL_SERIAL_GET_PROPERTIES | 重新获得当前串口设备的硬件属性 |
IOCTL_SERIAL_GET_TIMEOUTS | 获得串口设备的读写超时 |
IOCTL_SERIAL_GET_WAIT_MASK | 获得等待事件标记掩码 |
IOCTL_SERIAL_IMMEDIATE_CHAR | 在发送数据前,先发送一个特定的字符 |
IOCTL_SERIAL_PURGE | 清除串口中的输入输出Buffer,也可以中止未进行的读写操作 |
IOCTL_SERIAL_SET_BREAK_OFF | 串口通讯从中断状态恢复 |
IOCTL_SERIAL_SET_BREAK_ON | 设置串口为中断状态,停止发送接收数据 |
IOCTL_SERIAL_SET_DCB | 设置串口的DCB结构 |
IOCTL_SERIAL_SET_DTR | 设置串口的DTR管脚为高 |
IOCTL_SERIAL_SET_QUEUE_SIZE | 目前,在微软的MDD层代码中没有支持 |
IOCTL_SERIAL_SET_RTS | 设置串口的RTS管脚为高 |
IOCTL_SERIAL_SET_TIMEOUTS | 设置串口的读写操作超时 |
IOCTL_SERIAL_SET_WAIT_MASK | 设置等待事件标记掩码 |
IOCTL_SERIAL_SET_XOFF | 软件流控模式下,终止数据传输 |
IOCTL_SERIAL_SET_XON | 软件流控模式下,启动数据传输 |
IOCTL_SERIAL_WAIT_ON_MASK | 等待一个与事件掩码中匹配的事件 |
上述的操作码,很多都会被应用程序调用,看看MDD层中的实现,其中一些也是调用了PDD层下的函数来完成对串口硬件的设置。
3. PDD层API
PDD层的函数主要是实现了对串口硬件的操作,函数比较多,不过还是都说一下吧:
3.1 PHWOBJ GetSerialObject(DWORD DeviceArrayIndex):
该函数返回一个指向HWOBJ结构的指针,该结构包含了相关硬件接口函数的函数指针。
DeviceArrayIndex:串口索引号
3.2 VOID HWClearBreak(PVOID pContext):
清除串口中断状态,用于串口从中断状态恢复。
pConText:指向HWInit函数返回的指针。
3.3 VOID HWClearDTR(PVOID pContext):
设置串口的DTR管脚为低
pConText:指向HWInit函数返回的指针。
3.4 VOID HWClearRTS(PVOID pContext):
设置串口的RTS管脚为低
pConText:指向HWInit函数返回的指针。
3.5 VOID HWClose(PVOID pContext):
关闭由HWInit函数初始化的设备
pConText:指向HWInit函数返回的指针。
3.6 VOID HWDeinit(PVOID pContext):
当设备驱动被卸载的时候,该函数被调用。
pConText:指向HWInit函数返回的指针。
3.7 VOID HWDisableIR(PVOID pContext):
禁用串口的红外模式
pConText:指向HWInit函数返回的指针。
3.8 VOID HWEnableIR(PVOID pContext):
启用串口的红外模式
pConText:指向HWInit函数返回的指针。
3.9 VOID HWGetCommProperties(PVOID pContext, LPCOMMPROP pCommProp):
重新获得当前串口设备的硬件属性。
pConText:指向HWInit函数返回的指针。
pCommProp:指向一个COMMPROP结构,该结构描述硬件设备的属性,比如最大波特率,停止位以及流控模式等。
3.10 INTERRUPT_TYPE HWGetIntrType(PVOID pContext):
获得当前的中断类型。返回值可以是INTR_NONE,INTR_LINE,INTR_RX,INTR_TX和INTR_MODEM,这些值在Serhw.h中定义。
pConText:指向HWInit函数返回的指针。
3.11 VOID HWGetModemStatus(PVOID pContext, PULONG pModemStatus):
获得Modem的状态。
pConText:指向HWInit函数返回的指针。
pModemStatus:Modem的状态。
3.12 ULONG HWGetRxBufferSize(PVOID pContext):
获得串口硬件接收Buffer的大小。
pConText:指向HWInit函数返回的指针。
3.13 PVOID HWGetRxStart(PVOID pContext):
返回硬件接收Buffer的起始位置。
pConText:没有被使用。
3.14 ULONG HWGetStatus(PVOID pContext, LPCOMSTAT lpStat):
获得硬件状态信息。
pConText:指向HWInit函数返回的指针。
lpStat:指向COMSTAT结构,该结构描述硬件状态。
3.15 PVOID HWInit(ULONG Identifier, PVOID pMDDContext, PHWOBJ pHWObj):
初始化串口硬件设备。
Identifier:该驱动的键值,从MDD层传到PDD层。
pMDDContext:指向MDD层串口相关信息,从MDD层传给PDD层。
pHWObj:指向HWOBJ结构。
3.16 BOOL HWIoctl(DWORD dwOpenData, DWORD dwCode, PBYTE pBufIn, DWORD dwLenIn, PBYTE pBufOut, DWORD dwLenOut, PDWORD pdwActualOut):
执行I/O控制
dwOpenData:COM_Open函数返回的Handle。
dwCode:I/O控制操作码。
pBufIn:传入的Buffer。
dwLenIn:传入的Buffer的大小。
pBufOut:传出的Buffer。
dwLenOut:传出的Buffer的大小。
pdwActualOut:实际传出的数据的大小。
3.17 VOID HWLineIntrHandler(PVOID pContext):
线路状态信息中断处理函数
pContext:指向HWInit函数返回的指针。
3.18 VOID HWModemIntrHandler(PVOID pContext):
该函数检测Modem状态,并对相关中断进行处理。
pContext:指向HWInit函数返回的指针。
3.19 BOOL HWOpen(PVOID pContext):
打开串口设备,可以在该函数中打开串口硬件供电。
pContext:指向HWInit函数返回的指针。
3.20 VOID HWOtherHandler(PVOID pContext):
该函数已经被HWModemIntrHandler取代,实现与HWModemIntrHandler一样。
pContext:指向HWInit函数返回的指针。
3.21 BOOL HWPostInit(PVOID pContext):
该函数在COM_Init中被调用,但是在串口数据,硬件以及IST初始化后备调用。
pContext:指向HWInit函数返回的指针。
3.22 BOOL HWPowerOff(PVOID pContext):
串口硬件进入Suspend模式。
pContext:指向HWInit函数返回的指针。
3.23 BOOL HWPowerOn(PVOID pContext):
串口硬件从Suspend模式恢复到工作模式。
pContext:指向HWInit函数返回的指针。
3.24 VOID HWPurgeComm(PVOID pContext, DWORD fdwAction):
清除串口硬件buffer的信息。
pContext:指向HWInit函数返回的指针。
fdwAction:
PURGE_TXABORT:终止写操作立即返回。
PURGE_RXABORT:终止读操作立即返回。
PURGE_TXCLEAR:清空写Buffer。
PURGE_RXCLEAR:清空读Buffer。
3.25 ULONG HWPutBytes(PVOID pContext, PUCHAR pSrc, ULONG NumberOfBytes, PULONG pBytesSent):
通过写数据到硬件中来直接发送数据。
pContext:指向HWInit函数返回的指针。
pSrc:指向要发送的数据Buffer。
NumberOfBytes:要发送的数据长度。
pBytesSent:实际发送的数据长度。
3.26 VOID HWReset(PVOID pContext):
复位串口硬件。
pContext:指向HWInit函数返回的指针。
3.27 ULONG HWRxIntrHandler(PVOID pContext, PUCHAR pTargetBuffer, PULONG pByteNumber):
接收数据中断处理函数。
pContext:指向HWInit函数返回的指针。
pTargetBuffer:接收数据Buffer。
pByteNumber:接收数据Buffer的大小。
3.28 VOID HWSetBreak(PVOID pContext):
设置串口为中断状态,停止发送接收数据。
pContext:指向HWInit函数返回的指针。
3.29 BOOL HWSetCommTimeouts(PVOID pContext, LPCOMMTIMEOUT lpCommTO):
设置串口操作超时时间。
pContext:指向HWInit函数返回的指针。
lpComTO:指向一个超时的结构,其中包括读写超时。
3.30 BOOL HWSetDCB(PVOID pContext, LPDCB pDCB):
设置串口硬件设备信息。
pContext:指向HWInit函数返回的指针。
pDCB:指向DCB结构,该结构描述相关的串口硬件设置信息。
3.31 VOID HWSetDTR(PVOID pContext):
设置串口的DTR管脚为高
pContext:指向HWInit函数返回的指针。
3.32 VOID HWSetRTS(PVOID pContext):
设置串口的RTS管脚为高
pContext:指向HWInit函数返回的指针。
3.23 VOID HWTxIntrHandler(PVOID pContext, PUCHAR pSourceBuffer, PULONG pByteNumber):
串口发送中断处理函数。
pContext:指向HWInit函数返回的指针。
pSourceBuffer:发送数据Buffer。
pByteNumber:最大能够发送的数据的大小。函数返回时,指向实际发送的数据的大小。
3.24 VOID HWXmitComChar(PVOID pContext, UCHAR ComChar):
发送一个字符
pContext:指向HWInit函数返回的指针。
ComChar:要被发送的字符。
上述这些函数不一定串口驱动中都会被用到,根据具体要求来实现吧。在这里我还要给自己找条退路,由于本人并未实现上面的所有函数,一些是通过读文档和看源码分析得来,而且本人水平有限,如果有错误的地方,请谅解并欢迎指正。