KMDF Device Object Creation and Initialization

Every KMDF driver that supports Plug and Play must have an EvtDriverDeviceAdd callback function. EvtDriverDeviceAdd is responsible for creating and initializing a device object and related resources. The framework calls the driver's EvtDriverDeviceAdd callback when the system discovers a device that the driver controls.

The EvtDriverDeviceAdd callback creates a WDFDEVICE object to represent the device and performs numerous initialization tasks to provide the framework with the information that it requires to set up its own internal structures.

The EvtDriverDeviceAdd function thus proceeds as follows:

  1. Fills in a device initialization structure with information that is used to create the device object.

  2. Sets up the device object's context area.

  3. Creates the device object.

  4. Performs additional initialization and startup tasks, such as creating I/O queues and a device interface.

A bus driver that enumerates child devices typically creates multiple device objects: an FDO for the bus itself and a PDO for each child device that is attached to the bus. After the bus driver creates the PDOs, the system loads the function drivers for the child devices and the framework calls their EvtDriverDeviceAdd functions, which in turn create the FDOs for the child devices.

KMDF Device Initialization Structure

Unlike most other KMDF objects, the device object has no configuration structure. Instead, a driver configures a device object by using a WDFDEVICE_INIT structure. The framework calls EvtDriverDeviceAdd with a pointer to the WDFDEVICE_INIT structure and the driver calls the WdfDeviceInitXxx methods to fill in the structure with information about the device and driver. The framework uses this information later when it creates the WDFDEVICE object.

A driver can call the WdfDeviceInitXxx methods to:

  • Set device characteristics.

  • Set I/O type.

  • Create a context area or set other attributes for I/O requests that the framework delivers to the driver.

  • Register Plug and Play and power management callbacks.

  • Register event callbacks for file create, close, and cleanup.

In addition, specific initialization tasks apply to FDOs, filter DOs, and PDOs. Initialization of FDOs and filter DOs is described in the following sections. PDOs have special requirements; see "Child Device Enumeration (KMDF PDOs Only)" later in this chapter.

KMDF Initialization for an FDO

By default, the FDO controls power policy for its device. If the device can idle in a low-power state or generate a wake signal, the driver typically calls WdfDeviceInitSetPowerPolicyEventCallbacks to register power policy callback functions for the FDO.

FDOs can add and remove resources from the resource requirements list as reported by the bus driver. A KMDF driver implements the EvtDeviceFilterRemoveResourceRequirements and EvtDeviceFilterAddResourceRequirements callbacks and registers them by calling WdfFdoInitSetEventCallbacks.

If the driver adds resources to the requirements list, the driver must remove the added resources from the final list of assigned resources before the device starts. A KMDF driver supplies an EvtDeviceRemoveAddedResources callback. Drivers for legacy devices sometimes add and remove resources, but drivers for modern Plug and Play devices rarely do.

Other WdfFdoInitXxx methods retrieve device properties, return a pointer to the WDM PDO for the device stack, provide access to the registry key for the device, and perform other FDO-specific tasks.

KMDF Initialization for a Filter DO

The driver must call WdfFdoInitSetFilter to notify the framework that the device object represents a filter. This method causes the framework to change its default for I/O requests that the driver does not handle. When an I/O request arrives that the filter DO does not handle, the framework passes the request down to the next lower driver instead of failing the request, as is the default for FDOs and PDOs. For a filter DO, the driver can call the same WdfDeviceInitXxx methods as for an FDO.

Device Object Context Area

 Chapter 5 describes the object context area  Drivers typically store data that pertains to a device object with the object itself. A KMDF driver uses an object context area. The object context area is allocated from the nonpaged pool and has a driver-defined layout. When the KMDF driver creates the device object, it typically initializes the context area and specifies its size and type. When the framework deletes the object, it deletes the context area, too.

Listing 6-5 shows how the Osrusbfx2 driver defines the context area for its device object. This code appears in the Osrusbfx2.h header file.

Listing 6-5: Definition of a device object context area

image from book
 typedef struct _DEVICE_CONTEXT {     WDFUSBDEVICE                    UsbDevice;     WDFUSBINTERFACE                 UsbInterface;     WDFUSBPIPE                      BulkReadPipe;     WDFUSBPIPE                      BulkWritePipe;     WDFUSBPIPE                      InterruptPipe;     UCHAR                           CurrentSwitchState;     WDFQUEUE                        InterrputMsgQueue; } DEVICE_CONTEXT, *PDEVICE_CONTEXT; WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(DEVICE_CONTEXT, GetDeviceContext) 
image from book

As the example shows, the header file defines a context area of type DEVICE_CONTEXT and then invokes the WDF_DECLARE_CONTEXT_TYPE_WITH_NAME macro. This macro creates an accessor method that is associated with a context type. Thus, when the Osrusbfx2 driver's EvtDriverDeviceAdd callback is called, the GetDeviceContext accessor method has already been created to read and write a context area of type DEVICE_CONTEXT.

To associate the named context area with an object, the driver must initialize the object's attributes structure with information about the context area by calling the macro WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE from the EvtDriverDeviceAdd callback.

KMDF Device Object Creation

After the KMDF driver calls the required WdfDeviceInitXxx methods to fill in the WDFDEVICE_INIT structure, it sets attributes for the device object in an attributes structure. For a device object, the attributes nearly always include the size and type of the context area and often include an object cleanup callback and possibly the synchronization scope as well.

The driver passes the attributes structure and the WDFDEVICE_INIT structure to WdfDeviceCreate to create the device object. WdfDeviceCreate creates a WDFDEVICE object, attaches the device object to the Plug and Play device stack, and returns a handle to the object.

Chapter 5, "WDF Object Model," describes the attributes structure.

Additional EvtDriverDeviceAdd Tasks

After the EvtDriverDeviceAdd callback creates the device object, this callback should:

  • Set device idle policy and wake settings if the device object owns power policy.

    Chapter 7, "Plug and Play and Power Management," discusses power policy.

  • Register I/O callbacks and create I/O queues for the device object.

    Chapter 8, "I/O Flow and Dispatching," provides details.

  • Create a device interface, if required, by calling WdfDeviceCreateDeviceInterface.

  • Create an interrupt object if the hardware supports interrupts.

    Chapter 16, "Hardware Resources and Interrupts," discusses interrupt handling.

  • Create WMI objects.

    Chapter 12, "WDF Support Objects," provides implementation guidelines.

The framework starts the queues and connects the interrupt object at the appropriate time later, during start-device processing.

KMDF Example: EvtDriverDeviceAdd Callback Function

Listing 6-6 shows an abridged version of the Osrusbfx2 driver's EvtDriverDeviceAdd callback function. The numbered comments are explained following the example.

Listing 6-6: Sample EvtDriverDeviceAdd callback function

image from book
 NTSTATUS OsrFxEvtDeviceAdd(     IN WDFDRIVER        Driver,     IN PWDFDEVICE_INIT  DeviceInit     ) {     WDF_PNPPOWER_EVENT_CALLBACKS        pnpPowerCallbacks;     WDF_OBJECT_ATTRIBUTES               attributes;     NTSTATUS                            status;     WDFDEVICE                           device;     WDF_DEVICE_PNP_CAPABILITIES         pnpCaps;     UNREFERENCED_PARAMETER(Driver);     PAGED_CODE();     // Initialize the pnpPowerCallbacks structure.     . . .// Code omitted.     //[1] Register Plug and Play and power callbacks     WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, &pnpPowerCallbacks);     //[2] Indicate what type of I/O this driver performs.     WdfDeviceInitSetIoType(DeviceInit, WdfDeviceIoBuffered);     //[3] Intialize the object attributes structure     WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, DEVICE_CONTEXT);     //[4] Call the framework to create the device object.     status = WdfDeviceCreate(&DeviceInit, &attributes, &device);     if (!NT_SUCCESS(status)) {         return status;     }     // Set device PnP capabilities and configure and create I/O queues.     . . .// Code omitted.     //[5] Register a device interface.     status = WdfDeviceCreateDeviceInterface(device,                 &GUID_DEVINTERFACE_OSRUSBFX2,                 NULL);// Reference String     if (!NT_SUCCESS(status)) {         return status;     }     return status; } 
image from book

The EvtDriverDeviceAdd function in the listing proceeds as follows:

  1. Registers Plug and Play and Power callbacks.

    The driver initializes a structure-which is not shown-to contain information about the callback functions that handle Plug and Play and power management events and calls WdfDeviceInitSetPnpPowerEventCallbacks to record this information in the WDFDEVICE_INIT structure.

  2. Sets the I/O type.

    The driver indicates whether this device object performs buffered, direct, or neither buffered nor direct I/O for read and write requests. The driver sets WdfDeviceIoBuffered, which is the default.

  3. Initializes the object attributes structure.

    The driver initializes the object attributes structure with the type of the context area, so that the framework can create the context area for the device object.

  4. Creates the device object.

    The driver calls WdfDeviceCreate to create the device object. It passes the WDFDEVICE_INIT and object attributes structures that it has filled in and receives a handle to the device object in return.

  5. Creates a device interface.

    To create a device interface, the Osrusbfx2 driver calls WdfDeviceCreateInterface. The driver passes a handle to the device object, a pointer to a GUID, and a pointer to an optional reference string. The GUID is defined in the Public.h header file. A driver can use the reference string to distinguish two or more devices of the same interface class, that is, two or more devices that have identical GUIDs. The Osrusbfx2 driver passes NULL for the string.

By default, the framework enables the device's interfaces when the device enters the working state and disables them when the device leaves the working state. Therefore, in most circumstances, the driver is not required to enable or disable an interface.

Developing Drivers with the Microsoft Windows Driver Foundation
Developing Drivers with the Windows Driver Foundation (Pro Developer)
ISBN: 0735623740
EAN: 2147483647
Year: 2007
Pages: 224

Similar book on Amazon
Windows Internals, Part 1: Covering Windows Server 2008 R2 and Windows 7
Windows Internals, Part 1: Covering Windows Server 2008 R2 and Windows 7
Windowsu00ae Internals: Including Windows Server 2008 and Windows Vista, Fifth Edition (Pro Developer)
Windowsu00ae Internals: Including Windows Server 2008 and Windows Vista, Fifth Edition (Pro Developer)
Advanced Windows Debugging
Advanced Windows Debugging
The Windows 2000 Device Driver Book: A Guide for Programmers (2nd Edition)
The Windows 2000 Device Driver Book: A Guide for Programmers (2nd Edition) © 2008-2017.
If you may any questions please contact us: