新的 Windows 驅動框架 WDF (Windows Driver Foundation)

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 上幾篇相關文章,講的還是比較詳細的。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章