主程序

本文深入探讨了驱动程序的核心组件之一——DriverEntry函数,以及使用KMDF程序框架创建驱动程序的过程。重点阐述了初始化过程、设备添加回调函数、创建设备对象、配置IO队列等关键步骤,提供了从入门到实践的详细指导。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

驱动程序的入口函数是DriverEntry,这个函数在驱动程序被加载的时候,会被操作系统执行一次。利用KMDF程序框架生成的工程中,Driver.C文件中,就包含了这个程序入口。

值得一提的是:#include "driver.tmh";由于*.tmh不是C/C++标准头文件,加上driver.tmh是编译时才生成;所以driver.tmh中所涉及的内容,在编辑Driver.C文件时,是无法被VS识别的;这也是诸如TraceEvents等内容不能被编辑器识别,但是编译却能成功的原因所在。

如果实在不愿意使用TraceEvents,也可以使用kdPrint,用法如下:KdPrint(("create device done!\n"));  


DriverEntry的主要任务就是初始化:

  1, 初始化WDF_DRIVER_CONFIGWDF_DRIVER_CONFIG_INIT(&config,KMDFPCIEvtDeviceAdd);

系统在添加设备时,在进行设备枚举时,调用...DeviceAdd函数;来初始化WDF_DRIVER_CONFIG结构。

  2, 创建WDFDRIVER对象:

status = WdfDriverCreate(DriverObject,RegistryPath,&attributes,&config, &driver);

NTSTATUS
DriverEntry(_In_ PDRIVER_OBJECT  DriverObject,_In_ PUNICODE_STRING RegistryPath)
{
	NTSTATUS		status= STATUS_SUCCESS;
	WDF_DRIVER_CONFIG	config;  
	WDFDRIVER		driver;
    WDF_OBJECT_ATTRIBUTES	attributes;	
   

    WPP_INIT_TRACING( DriverObject, RegistryPath );
	
    TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_DRIVER, "%!FUNC! Entry");

    WDF_OBJECT_ATTRIBUTES_INIT(&attributes);
    attributes.EvtCleanupCallback = KMDFPCIEvtDriverContextCleanup;

    WDF_DRIVER_CONFIG_INIT(&config,KMDFPCIEvtDeviceAdd);

    status = WdfDriverCreate(DriverObject,RegistryPath,&attributes,&config, &driver);
    if (!NT_SUCCESS(status)) 
	{
        TraceEvents(TRACE_LEVEL_ERROR, TRACE_DRIVER, "WdfDriverCreate failed %!STATUS!", status);
        WPP_CLEANUP(DriverObject);
        return status;
    }
    TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_DRIVER, "%!FUNC! Exit");
    return status;
}

...DeviceAdd回调函数,在设备枚举时系统自动执行。DeviceAdd函数主要执行一下操作:

  1,创建并初始化WDFDEVICE对象的Context,这是一个FDO_DATA结构,可以在.h头文件中定义

typedef struct _FDO_DATA
{
    ULONG                   Signature;          
    WDFDEVICE               WdfDevice;		// device object.

}  FDO_DATA, *PFDO_DATA;

WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(FDO_DATA, FdoGetData)
宏WDF_DECLARE_CONTEXT_TYPE_WITH_NAME创建该类型的访问方法 。

之后,可以在DeviceAdd函数中调用WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&fdoAttributes, FDO_DATA);来指定Context和对象之间的关联。


接下来, 创建Device对象:status = WdfDeviceCreate(&DeviceInit, &fdoAttributes, &device);

获得Context指针:fdoData = FdoGetData(device);


  2,为PNP和电源管理回调函数设置程序入口

  3,创建设备接口

status = WdfDeviceCreateDeviceInterface(device,(LPGUID) &GUID_DEVINTERFACE_KMDFPCI,NULL);

  4,创建、配置I/O队列

使用默认IO队列:WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE( &ioQueueConfig, WdfIoQueueDispatchSequential);

两个参数:WDF_IO_QUEUE_CONFIG结构(ioQueueConfig)的指针;WDF_IO_QUEUE_DISPATHCH_TYPE枚举。

通过指定WdfIoqueueDispatchParallel驱动程序指示IO请求到达,KMDF就从队列调用IO请求。驱动程序可以并行处理多个请求 。

在配置IO队列以后,还需要注册IO回调函数,来支持读、写和IO控制请求;接下来在创建WDFQUEUE对象。

ioQueueConfig.EvtIoRead = PciEventRead;
	ioQueueConfig.EvtIoWrite = PciEventWrite;
	ioQueueConfig.EvtIoDeviceControl = PciEventDeviceControl;
	status = WdfIoQueueCreate( device,&ioQueueConfig,WDF_NO_OBJECT_ATTRIBUTES,&queue);
KMDF只处理驱动程序 配置的队列请求,如果接收到其他请求,则会抛出STATUS_INVALID_DEVICE_REQUEST。


如果驱动程序支持缓冲或者直接IO请求,则可以使用Request的始发者传递的缓冲区,或者其代表的WDFMEMORY对象。使用WDFMEMOY对象,WDF框架会自动处理验证(句柄、Buffer大小)和寻址问题,确保缓冲区不会益处。

读:获得WDFMEMORY句柄:WdfRequestRetriveOutputMemory

驱动程序 获得数据 ,在从内部缓冲区复制到相关的WDFMEMORY对象中:WdfMemoryCopyFromBuffer

写:获得WDFMEMORY句柄:WdfRequestRetriveInputMemory

一般使用EdfMemoryCopyToBuffer,把(WDFMEMORY对象中)数据复制到输出缓冲区 。如果溢出,则返回错误代码。

如果需要使用缓冲区 指针,则使用WdfRequestRetriveInputBuffer,获取指针,返回需要写入的字节数;或者WdfMemoryGetBuffer获取指针和写入的字节数。

在驱动程序完满足IO请求后,他会调用WdfRequestCompleteWithInformation,使用指定的状态完成底层IO请求并传递需要读写的字节数。

  5,(如果需要)创建中断对象

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值