COM也被称之为串口,这是一种非常简单的通讯接口,这种结构简单的接口被广泛的应用在开发中,几乎所有系统都能支持这种通讯接口,它有RS232和RS485等分支,但一般我们都会使用RS232作为常见的串口,因为它足够简单和高效。
几乎所有的开发板,都会提供用于烧录、调试、日志的串口;大部分常见的底层协议也会使用串口来作为数据上报的主要接口;USB甚至为COM口提供了单独而专用的驱动,故用它来作为入门是足够简单和方便。
COM也会被称为Serial或者UART,同时也容易和windows的另外一项技术相混淆,Serial或者UART在物理或者机制上是有区别的,但我们主要关注的是windows 驱动的编写,故我们会使用windows为这一类设备提供的类命名方式"COM"来在本文中表示这一类驱动。
选择合适和案例
windows 直接提供的驱动案例如下:
kmdfecho: 这个例子来源于WinDDK,是一个软件驱动,本身的设备节点位于root上,这个驱动是kmdf的演示驱动,代码演示了顺序队列对呈现给驱动程序的读写请求进行序列化,分为同步和异步两个子驱动;默认情况下需要修改inx文件里面的Sample字段;
serial: 这个系列是COM驱动最齐全的例程之一,包含对硬件ID的物理设备的直接支持(serial),包含基于UMDF1.0和UMDF2.0的virtualserial的支持;包含配合serial的Filter驱动serenum;
serialhcibus:基本总线驱动程序以支持新的蓝牙可扩展性传输DDI,通过UART传输。这种串行总线驱动器可以通过UART传输支持多无线电设备,并利用通用的蓝牙HCI数据包进行通信。此驱动程序的下边缘按照蓝牙SIG的UART(H4)传输协议与UART控制器连接;注意这个驱动需要实现基于供应商的部分才能正常工作;
由于接下来的代码将用于演示,故我们选择基于UMDF2.0的virtualserial用于演示。
项目改造
新建一个UMDF2.0的空项目:
将案例UMDF2.0virtualserial里面的源代码文件拷贝进来,不需要拷贝文件夹里面的内容:
注意,我们生成UMDF驱动项目的时候,已经有了inf文件了,接下来就是对整个驱动文件进行处理,事实上这个驱动编写得非常出色,可以直接编译成功运行的:
这里需要修改默认的inf文件,这个案例的INF文件如下:
;
; umdfserial.inf
;
[Version]
Signature="$Windows NT$"
; 默认情况下这里的class是system,但是我们需要一个串口驱动,故改为PORT
; 对应的GUID也需要修改,下面是修改之后的
Class=Ports
ClassGuid={4D36E978-E325-11CE-BFC1-08002BE10318}
Provider=%ManufacturerName%
CatalogFile=umdfserial.cat
DriverVer=09/22/2024,1.0.0.0 ; TODO: set DriverVer in stampinf property pages
PnpLockdown=1
[Manufacturer]
%ManufacturerName%=Standard,NT$ARCH$
[Standard.NT$ARCH$]
%DeviceName%=MyDevice_Install, Root\umdfserial ; TODO: edit hw-id
[SourceDisksFiles]
umdfserial.dll=1
[SourceDisksNames]
1 = %DiskName%
; =================== UMDF Device ==================================
[MyDevice_Install.NT]
CopyFiles=UMDriverCopy
[MyDevice_Install.NT.hw]
[MyDevice_Install.NT.Services]
AddService=WUDFRd,0x000001fa,WUDFRD_ServiceInstall
[MyDevice_Install.NT.CoInstallers]
AddReg=CoInstallers_AddReg
[MyDevice_Install.NT.Wdf]
UmdfService=umdfserial,umdfserial_Install
UmdfServiceOrder=umdfserial
[umdfserial_Install]
UmdfLibraryVersion=$UMDFVERSION$
ServiceBinary=%12%\UMDF\umdfserial.dll
[WUDFRD_ServiceInstall]
DisplayName = %WudfRdDisplayName%
ServiceType = 1
StartType = 3
ErrorControl = 1
ServiceBinary = %12%\WUDFRd.sys
[CoInstallers_AddReg]
HKR,,CoInstallers32,0x00010000,"WUDFCoinstaller.dll"
[DestinationDirs]
UMDriverCopy=12,UMDF ; copy to drivers\umdf
[UMDriverCopy]
umdfserial.dll
; =================== Generic ==================================
[Strings]
ManufacturerName="<Your manufacturer name>" ;TODO: Replace with your manufacturer name
DiskName = "umdfserial Installation Disk"
WudfRdDisplayName="Windows Driver Foundation - User-mode Driver Framework Reflector"
DeviceName="umdfserial Device"
driver.c 解读
这个文件主要处理驱动相关的代码,主要是DriverEntry和EvtDeviceAdd函数,下面分别来看这两个函数
NTSTATUS
DriverEntry(
_In_ PDRIVER_OBJECT DriverObject,
_In_ PUNICODE_STRING RegistryPath
)
{
NTSTATUS status;
WDF_DRIVER_CONFIG driverConfig;
WDF_DRIVER_CONFIG_INIT(&driverConfig,
EvtDeviceAdd);
status = WdfDriverCreate(DriverObject,