新的 Windows 驱动框架 WDF (Windows Driver Foundation)

原创 2004年07月07日 20:09:00

http://www.blogcn.com/user8/flier_lu/index.html?id=2507847

    WDM (Windows Driver Model) 都还没有完全弄明白,M$ 居然在 WinHEC 上又推出了将全面取代 WDM 的 WDF (Windows Driver Foundation)。OSR Online 上几篇文章简要地介绍了 WDF 的一些新特性,并在 A New Framework 一文中给出了一个实际的 WDF 例子。
    因为没有开发环境,只能粗略看了一下文章,感觉对我的需求来说结构上调整不算很大。亮点主要是针对新的 PnP/Power 模型的进一步优化和调整、可放弃的驱动创建(例如在 Longhorn 中可以中断并放弃 IRP_MJ_CREATE 操作)、新的存储架构(不明白 :()、灵活的任务请求队列(支持串行、并行和定制任务分发)、以及一些其他细节方面的改进。

    在驱动模型方面,WDF 使用一些新的类型驱动 WDM 的相应类型,并做了一定的扩展:

    WDF 类型      WDM 类型

    WDFDRIVER     DRIVER_OBJECT
    WDFDEVICE     DEVICE_OBJECT
    WDFREQUEST    IRP
    WDFQUEUE      DPC 队列
    WDFINTERRUPT  ISR & DPCforISR

    DriverEntry 在 WDF 中只负责 WDFDRIVER 类型对象的初始化和构造工作,将设备的管理完全丢到 DioEvtDeviceAdd 函数中,由 WDF 框架在合适的时候调用。

以下内容为程序代码:

NTSTATUS
DriverEntry(PDRIVER_OBJECT DriverObj, PUNICODE_STRING RegistryPath)
{
    NTSTATUS code;
    WDF_DRIVER_CONFIG config;
    WDFDRIVER hDriver;

    DbgPrint(" WDFDIO Driver -- Compiled %s %s ",__DATE__, __TIME__);

    //
    // Initialize the Driver Config structure:
    //      Specify our Device Add event callback.
    //
    WDF_DRIVER_CONFIG_INIT_NO_CONSTRAINTS(&config, DioEvtDeviceAdd);

    //
    //
    // Create a WDFDRIVER object
    //
    // We specify no object attributes, because we do not need a cleanup
    // or destroy event callback, or any per-driver context.
    //
    code = WdfDriverCreate(DriverObj,
                             RegistryPath,
                             WDF_NO_OBJECT_ATTRIBUTES,
                             &config,   // Ptr to config structure
                             NULL);     // Optional ptr to get WDFDRIVER handle

    if (!NT_SUCCESS(code)) {

        DbgPrint("WdfDriverCreate failed with status 0x%0x ", code);
    }

#if DBG
    DbgPrint("DriverEntry: Leaving ");
#endif

    return(code);
}

    而 DioEvtDeviceAdd 函数则首先初始化 PnP 和电源管理相关结构。
以下内容为程序代码:

WDFSTATUS
DioEvtDeviceAdd(WDFDRIVER Driver, PWDFDEVICE_INIT DeviceInit)
{
    WDFSTATUS status = STATUS_SUCCESS;
    WDF_PNPPOWER_EVENT_CALLBACKS pnpPowerCallbacks;
    WDF_OBJECT_ATTRIBUTES objAttributes;
    WDFDEVICE device;
    PDIO_DEVICE_CONTEXT devContext;
    WDF_IO_QUEUE_CONFIG ioCallbacks;
    WDF_INTERRUPT_CONFIG interruptConfig;
    WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS idleSettings;

    //
    // Initialize the PnpPowerCallbacks structure.
    //
    WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnpPowerCallbacks);

    //
    // Setup the callbacks to manage our hardware resources.
    //
    // Prepare is called at START_DEVICE time
    // Release is called at STOP_DEVICE or REMOVE_DEVICE time
    //
    pnpPowerCallbacks.EvtDevicePrepareHardware = DioEvtPrepareHardware;
    pnpPowerCallbacks.EvtDeviceReleaseHardware = DioEvtReleaseHardware;

    //
    // These two callbacks set up and tear down hardware state that must

    // be done every time the device moves in and out of the D0-working
    // state.

    //
    pnpPowerCallbacks.EvtDeviceD0Entry= DioEvtDeviceD0Entry;
    pnpPowerCallbacks.EvtDeviceD0Exit = DioEvtDeviceD0Exit;

    //
    // Register the PnP and power callbacks.

    //
    WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit,

                                           pnpPowerCallbacks);
    // ...
}

    然后初始化并构造设备对象,类似以前 WDM 中的 CreateDevice 和 IoCreateSymbolicLink 调用。
以下内容为程序代码:

WDFSTATUS
DioEvtDeviceAdd(WDFDRIVER Driver, PWDFDEVICE_INIT DeviceInit)
{
    // ...

    // Create our Device Object and its associated context
    //
    WDF_OBJECT_ATTRIBUTES_INIT(&objAttributes);

    WDF_OBJECT_ATTRIBUTES_SET_CONTEXT_TYPE(&objAttributes,

                                           DIO_DEVICE_CONTEXT);

    //
    // We want our device object NAMED, thank you very much
    //
    status = WdfDeviceInitUpdateName(DeviceInit, L"/device/WDFDIO");

    if (!NT_SUCCESS(status)) {
        DbgPrint("WdfDeviceInitUpdateName failed 0x%0x ", status);
        return(status);
    }

    //
    // Because we DO NOT provide callbacks for Create or Close, WDF will
    // just succeed them automagically.
    //

    //
    // Create the device now
    //
    status = WdfDeviceCreate(&DeviceInit,   // Device Init structure
                            &objAttributes, // Attributes for WDF Device
                            &device);      // returns pointer to new

                                                                WDF Device

    if ( !NT_SUCCESS(status)) {
        DbgPrint("WdfDeviceInitialize failed 0x%0x ", status);
        return(status);
    }

    //
    // Device creation is complete
    //
    // Get our device extension
    //
    devContext = DioGetContextFromDevice(device);

    devContext->WdfDevice = device;

    //
    // Create a symbolic link for the control object so that usermode can
    // open the device.
    //
    status = WdfDeviceCreateSymbolicLink(device, L"/DosDevices/WDFDIO");

    if (!NT_SUCCESS(status)) {
        DbgPrint("WdfDeviceCreateSymbolicLink failed 0x%0x ", status);
        return(status);
    }

    // ...
}

    比较有趣的是,WDF 直接提供了请求队列的概念。一个设备可以有多个请求队列,每个请求队列可以有一种模式,如最简单的 WdfIoQueueDispatchSerial 模式下,请求队列将请求串行化后进行处理;而 WdfIoQueueDispatchParallel 模式则自动在每个请求到来时调用 IO 回调函数;最后也可以通过 WdfIoQueueDispatchManual 模式,在请求到来时调用 EvtIoStart 事件处理函数来手工分发请求,类似现在 WDM 的工作方式。而请求队列更是提供了在 Power down 时对请求队列当前请求的自动保存和恢复机制。这样一来驱动的开发又可以剩一些事情了,呵呵。
    A New Framework 一文中过于队列有较为广泛的讨论,这儿就不罗嗦了。
以下内容为程序代码:

WDFSTATUS DioEvtDeviceAdd(WDFDRIVER Driver, PWDFDEVICE_INIT DeviceInit)
{
    // ...

    //
    // Configure our queue of incoming requests
    //
    // We only use the default queue, and we only support

    // IRP_MJ_DEVICE_CONTROL.

    //
    // Not supplying a callback results in the request being completed
    // with STATUS_NOT_SUPPORTED.
    //
    WDF_IO_QUEUE_CONFIG_INIT(&ioCallbacks,
                             WdfIoQueueDispatchSerial,
                             WDF_NO_EVENT_CALLBACK,     // StartIo
                             WDF_NO_EVENT_CALLBACK);    // CancelRoutine

    ioCallbacks.EvtIoDeviceControl = DioEvtDeviceControlIoctl;

    status = WdfDeviceCreateDefaultQueue(device,
                                        &ioCallbacks,
                                        WDF_NO_OBJECT_ATTRIBUTES,
                                        NULL); // pointer to default queue

    if (!NT_SUCCESS(status)) {
        DbgPrint("WdfDeviceCreateDefaultQueue failed 0x%0x ", status);
        return(status);
    }

    // ...
}

    对中断的处理,WDF 也使用 OO 思想将 WDM 中的几个回调函数组织了起来,但功能上还是类似的。
以下内容为程序代码:

WDFSTATUS DioEvtDeviceAdd(WDFDRIVER Driver, PWDFDEVICE_INIT DeviceInit)
{
    // ...

    //
    // Create an interrupt object that will later be associated with the
    // device's interrupt resource and connected by the Framework.
    //



    //
    // Configure the Interrupt object
    //
    WDF_INTERRUPT_CONFIG_INIT(&interruptConfig,
                              FALSE,                // auto-queue DPC?
                              DioIsr,
                              DioDpc);

    interruptConfig.EvtInterruptEnable  = DioEvtInterruptEnable;
    interruptConfig.EvtInterruptDisable = DioEvtInterruptDisable;

    status = WdfInterruptCreate(device,
                                &interruptConfig,
                                &objAttributes,
                                &devContext->WdfInterrupt);
    if (!NT_SUCCESS (status))
    {
        DbgPrint("WdfInterruptCreate failed 0x%0x ", status);
        return status;
    }

    // ...
}

    最后,WDF 中为了支持电源管理的多种状态切换,提供了一些辅助的状态变迁时的回调函数,简化了驱动中的管理代码实现。
以下内容为程序代码:

WDFSTATUS DioEvtDeviceAdd(WDFDRIVER Driver, PWDFDEVICE_INIT DeviceInit)
{
    // ...

    //
    // Initialize our idle policy
    //
    WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_INIT(&idleSettings,
                                               IdleCannotWakeFromS0);


    status = WdfDeviceUpdateS0IdleSettings(device, &idleSettings);

    if (!NT_SUCCESS(status)) {
        DbgPrint("WdfDeviceUpdateS0IdleSettings failed 0x%0x ", status);
        return status;
    }


    return(status);
}

    因为还没有拿到开发调试环境,连 OSR 的例子都下载不下来,只能泛泛而谈。等弄到实际东西再详细讨论吧,呵呵,有兴趣的朋友可以先看看 OSR Online 上几篇相关文章,讲的还是比较详细的。

[Windows驱动开发](四)Windows驱动框架

转自: http://blog.csdn.net/baggiowangyu/article/details/7839938 一、NT式驱动的基本例程 1. 驱动入口函数—...
  • huangxy10
  • huangxy10
  • 2013年11月11日 01:24
  • 1636

基于WDF的PCI/PCIe接口卡Windows驱动程序(2)-开发者需要了解的WDF中的一些重要的概念

原文出处:http://www.cnblogs.com/jacklu/p/4646601.html 1、WinDBG是唯一的内核驱动调试利器,但是开发PCIe的WDF驱动可以采用...
  • wolfman125
  • wolfman125
  • 2016年07月11日 14:32
  • 680

解决开机之后svhost.exe进程高CPU和高内存问题

看来看去这个答案最详细最靠谱: http://www.online-tech-tips.com/computer-tips/how-to-fix-svchostexe-errors-and-prob...
  • stereohomology
  • stereohomology
  • 2015年04月18日 07:39
  • 3570

学习windows驱动(WDF USB设备驱动开发)

学习WDF USB驱动开发, 那么怎么进行WDF USB设备驱动开发呢? 我们需要懂什么? 需要做什么呢? 根据《竹林蹊径 深入浅出Windows驱动开发》第4章 WDF USB设备驱动开发里...
  • mofabang
  • mofabang
  • 2015年10月29日 18:01
  • 1478

从零开始学习Windows WDF驱动程序开发

从零开始学习Windows WDF驱动程序开发 ▼ 目录: 1. 第一部分 编译安装测试一个简单的WDF驱动程序    1.1 编译安装测试    1.2 Windo...
  • chenchong_219
  • chenchong_219
  • 2014年03月20日 23:09
  • 13046

使用TraceView观察Windows PCIE驱动设备加载和卸载过程

本文主要结合TraceView.exe工具,介绍一个典型的KMDF驱动程序的加载和卸载过程。相关理论主要来自《Win7设备驱动程序开发》一书。关于TraceView.exe的使用,可以参考我之前的博客...
  • Sagittarius_Warrior
  • Sagittarius_Warrior
  • 2016年05月06日 16:47
  • 1638

基于WDF的PCI/PCIe接口卡Windows驱动程序(3)- 驱动程序代码(头文件)

原文出处:http://www.cnblogs.com/jacklu/p/4679304.html 在WDF的PCIe驱动程序中,共有四个.h文件(Public.h  Driver.h  Dev...
  • wolfman125
  • wolfman125
  • 2016年07月11日 14:34
  • 635

win7 vs2012+wdk8.0 搭建wdf驱动开发环境

开发环境搭建:系统:win7 x64工具:vs2012 + WDK8.0插件:wdfcoinstaller.msi(1)先安装vs2012,再安装wdk8.0,这样在打开vs2012时可以创建wind...
  • mao0514
  • mao0514
  • 2016年07月13日 15:08
  • 2602

谈WDM与WDF (windows驱动开发)

WDF驱动模型 如所周知,自Windows 2000开始,开发驱动程序必以WDM为基础的,但其开发难度之大,根本不能奢望像用户模式应用程序开发那样容易。为改善这种局面,微软推出了新的驱动程序开发环境。...
  • u011191259
  • u011191259
  • 2014年12月10日 21:25
  • 1389

菜鸟WDF驱动开发系列(2):调试第一个KMDF驱动程序

根据系列上一篇的内容,已经基本作好了驱动调试环境的配置,现在着手开始试一下怎么用WinDBG调试。每一位新手在开始学习驱动开发的时候相信总会看大量的资料,如我第一篇提到的几本书的确是不错的,但名著总有...
  • w10800337
  • w10800337
  • 2014年03月27日 14:33
  • 1527
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:新的 Windows 驱动框架 WDF (Windows Driver Foundation)
举报原因:
原因补充:

(最多只允许输入30个字)