Dynamic Enumeration Made Simpler in WDF

Dynamic Enumeration Made Simpler in WDF

Introduction

The Windows driver foundation (WDF) is a library that provides a set of DDIs (Device Driver Interface) that makes the life of a Windows driver writer so easy. This article describes functionalities provided by WDF to support dynamic enumeration of devices, which is a normal functionality of a bus driver.

Writing bus driver in WDM involves handling IRPs for bus driver FDO as well as IRPs for PDOs created by bus driver.

WDF applies an object-oriented approach to do this and introduces a data structure called "WDFCHILDLIST," to simplify the overall process of dynamic enumeration. This document provides some initial guidelines for using WDF to implement dynamic bus enumerator.

This article assumes that user has previous experience with WDM concepts.

Dynamic Enumeration in WDM

Take a brief look at dynamic enumerators implemented using WDM:

  • A WDM bus driver enumerates its children in response to an IRP_MN_QUERY_DEVICE_RELATIONS request with a relation type of BusRelations.
  • After enumerating PDO, Bus Driver needs to handle IRP_MN_QUERY_ID sent by the PnP Manager to successfully install FDO for the child.

    The PnP Manager issues this request in several forms to determine which device identifiers it will use to locate the INF file for a child device. Bus Driver responds by returning (in IoStatus.Information) a MULTI_SZ value containing the requisite device identifiers.

  • Handle PnP IRPs for bus driver FDO as well as child PDO. The common task across all bus drivers is to maintain the child-parent relationship for devices enumerated by it. It involves functionalities such as:
    • Maintain unique identification for child PDOs.
    • Delete all child PDOs while handling IRP_MN_SURPRISE_REMOVAL/IRP_MN_REMOVE_DEVICE for bus driver FDO.
    • After every modification in the child list, call IoInvalidateDeviceRelations to notify the PnP manager that the relations for a device (such as bus relations, ejection relations, removal relations, and the target device relation) have changed.
    • The major task is to handle IRP_MN_QUERY_DEVICE_RELATIONS to provide information about child PDOs.

Dynamic Enumeration in WDF

To simplify Bus Driver's task, WDF provides a WDFCHILDLIST object. Logically, you can explain the WDFCHILDLIST object as follows:

  • The framework creates an empty default WDFCHILDLIST object for every FDO and sets the FDO as the parent of the WDFCHILDLIST. The child-list object maintains information about the child devices that are enumerated by a parent device.
  • So, dynamic enumeration now will happen in the following way:
    1. The Bus Driver calls WdfFdoInitSetDefaultChildListConfig from EvtDriverDeviceAdd to configure the child list and register the EvtChildListXxx callbacks before it creates the FDO for the bus.

      For example, inside EvtDriverDeviceAdd of the bus driver:

    2. // Initialize WDF_CHILD_LIST_CONFIG to set
      // EvtChildListCreateDevice and
      // IndentificationDescriptionSize
      WDF_CHILD_LIST_CONFIG_INIT(&config,
         sizeof(PDO_IDENTIFICATION_DESCRIPTION),
         // callback to create a child device.
         Bus_EvtDeviceListCreatePdo
      );
      // Configure bus driver's default child list
      WdfFdoInitSetDefaultChildListConfig(DeviceInit,
         &config, WDF_NO_OBJECT_ATTRIBUTES);
      
    3. Enumerate the child devices after creating the FDO and use WdfChildListXxx methods to populate the child list:
    4. // obtain handle to default child list
      list = WdfFdoGetDefaultChildList(Device);
      
      PDO_IDENTIFICATION_DESCRIPTION description;
      WDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER_INIT(
         description.Header, sizeof(description))
      );
      description.SwitchNumber = i;
      
      WdfChildListBeginScan(list);
      
      // enumerate new PDO, by adding new identification
      // description
      status = WdfChildListAddOrUpdateChildDescriptionAsPresent(
               list,
               &description.Header,
               NULL
               );
      
      WdfChildListEndScan(list);
      if (!NT_SUCCESS(status) && status !=
          STATUS_OBJECT_NAME_EXISTS){return status;
      }
      
    5. Implement EvtChildListCreateDevice, which creates the PDO for a child device. The framework passes a pointer to a WDFDEVICE_INIT structure when it invokes this callback. The callback fills in the structure and calls WdfDeviceCreate to create the child PDO.
    6. NTSTATUS
      SampleDriver_EvtChildListCreatePdo(
         WDFCHILDLIST DeviceList,
         PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER
            IdentificationDescription,
         PWDFDEVICE_INIT ChildInit
         )
      {
         // Call WdfPdoInitXxx DDIs to initialize PDO
         // Provide DeviceID, HardwareIDs, CompatibleIDs,
         // and InstanceId
         RtlInitUnicodeString(&deviceId, HardwareIds);
         status = WdfPdoInitAssignDeviceID(DeviceInit,
            &deviceId);
         b&
         // Create PDO
         status = WdfDeviceCreate(&DeviceInit,
                                  &pdoAttributes,
                                  &hChild);
         b&
      }
      
    7. Implement other EvtChildListXxx callbacks as required to support the device's children.
    8. A driver that performs dynamic enumeration uses WdfChildListXxx methods to change its child list. Following is list of DDIs provided for child list handling:
      • WdfChildListAddOrUpdateChildDescriptionAsPresent
      • WdfChildListUpdateAllChildDescriptionsAsPresent
      • WdfChildListBeginIteration
      • WdfChildListBeginScan
      • WdfChildListEndIteration
      • WdfChildListEndScan
      • WdfChildListRequestChildEject
      • WdfChildListGetDevice
      • WdfChildListRetrieveAddressDescription
      • WdfChildListRetrieveNextDevice
      • WdfChildListRetrievePdo

Dynamic Enumeration Made Simpler in WDF

Identification Description and Address Description for the Child PDO

Identification Description

To maintain unique identification for Child PDOs, KMDF provides WDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER structure. The driver provides information about this structure while calling WdfFdoInitSetDefaultChildListConfig/WdfChildListCreate.

Following are the set of callbacks associated with this structure:

  • EvtChildListIdentificationDescriptionCompare: Compares the contents of two identification description structures.
  • EvtChildListIdentificationDescriptionCopy: Copies the contents of one identification description structure to another.
  • EvtChildListIdentificationDescriptionDuplicate: Creates a new identification description by duplicating an existing identification description structure and, if necessary, allocating additional buffers.
  • EvtChildListIdentificationDescriptionCleanup: Deallocates buffers that were allocated by the EvtChildListIdentificationDescriptionDuplicate callback function.

These callbacks are optional, and needed when the structure contains dynamic data.

Address Description

An address description is a structure that contains information that the driver requires so that it can access the device on its bus, if the information can change while the device is plugged in.

The driver can provide the following set of callback functions to manipulate the information in an address description:

  • EvtChildListAddressDescriptionCopy: Copies the contents of one address description structure to another.
  • EvtChildListAddressDescriptionDuplicate: Creates a new address description by duplicating an existing address description structure and, if necessary, allocating additional buffers.
  • EvtChildListAddressDescriptionCleanup: Deallocates buffers that were allocated by the EvtChildListIdentificationDescriptionDuplicate callback function.

WdfPdoInitXxx Methods

Below is a list of WdfPdoInitXxx DDIs provided by the framework for PDO initialization.

WdfPdoInitXxx DDIs for IRP_MN_QUERY_ID

WDF bus drivers don't need to handle IRP_MN_QUERY_ID. Instead, the WDF Bus driver needs to call the following DDIs for child PDO initialization:

  • WdfPdoInitAssignDeviceID
  • WdfPdoInitAssignInstanceID
  • WdfPdoInitAddHardwareID
  • WdfPdoInitAddCompatibleID

After this, the framework responds to the IRP_MN_QUERY_ID request by returning information provided by the driver for WdfPdoInitXxx calls.

WdfPdoInitSetEventCallbacks

The Bus Driver can provide callbacks to handle PDO specific PnP IRPs. WdfPdoInitSetEventCallbacks is the method supplied by the framework to set these callbacks.

Advantages

Here are the Bus Driver responsibilities that were mentioned in the "Dynamic Enumeration in WDM" section.

WDM WDF
Maintain unique identification for child PDOs

For WDF Bus drivers, this task is more structured with the help of an Identification description and address description structure associated with every child list.

In addition to this, if the Identification description and Address description structures do not contain any dynamically allocated fields, the driver writers don't need to provide any callbacks for comparing, copying, and deleting these descriptions. The framework will call RtlCompareMemory to compare descriptions and RtlCopyMemory to duplicate/copy descriptions.

Delete all child PDOs while handling IRP_MN_SURPRISE_REMOVAL/ IRP_MN_REMOVE_DEVICE for the bus driver FDO. The parent of each child-list object is the device's framework device object. Therefore, the framework will delete the child list before removing the parent FDO.
After every modification in the child list, call IoInvalidateDeviceRelations to notify the PnP manager that the relations for a device (such as bus relations, ejection relations, removal relations, and the target device relation) have changed. Framework drivers don't need to call IoInvalidateDeviceRelations explicitly. Instead, the framework will in turn call IoInvalidateDeviceRelations while handling WDFCHILDLIST manipulations.
The major task is to handle IRP_MN_QUERY_DEVICE_RELATIONS. KMDF bus drivers no longer need to handle IRP_MN_DEVICE_QUERY_RELATIONS. Instead, the framework will handle this IRP and will return required information by using the child list.

Summary

This whole study can be summarized in the following table:

Serial No. WDM Bus Driver WDF Bus Driver (Event handler/DDIs)
1 IRP_MN_QUERY_BUS_INFORMATION Calls WdfDeviceSetBusInformationForChildren; framework handles IRP_MN_QUERY_BUS_INFORMATION on behalf of driver and returns appropriate information
2 IRP_MN_QUERY_CAPABILITIES Calls WdfDeviceSetPnpCapabilities / WdfDeviceSetPowerCapabilities; framework will handle the IRP on behalf of the driver
3 IRP_MN_QUERY_DEVICE_RELATIONS
(bus, removal, and ejection relations)
EvtDeviceRelationsQuery
4 IRP_MN_QUERY_DEVICE_TEXT Framework driver calls WdfPdoInitAddDeviceText before creating the PDO; framework will handle IRP_MN_QUERY_DEVICE_TEXT on behalf of the bus driver.
5 IRP_MN_QUERY_ID Framework driver calls following DDIs to assign various IDs:
  • WdfPdoInitAssignDeviceID
  • WdfPdoInitAssignInstanceID
  • WdfPdoInitAddHardwareID
  • WdfPdoInitAddCompatibleID
Framework will handle IRP_MN_QUERY_ID for bus driver now.
6 IRP_MN_QUERY_RESOURCE EvtDeviceResourcesQuery
7 IRP_MN_QUERY_RESOURCE_REQUIREMENTS EvtDeviceResourceRequirementsQuery
8 IRP_MN_EJECT
  • EvtDeviceEject
  • Framework bus drivers can call WdfChildListRequestChildEject / WdfPdoRequestEject to send IRP_MN_EJECT for a PDO.
9 IRP_MN_SET_LOCK EvtDeviceSetLock
10 IRP_MN_WAIT_WAKE EvtDeviceEnableWakeAtBus
EvtDeviceDisableWakeAtBus

References

  1. Kernel-Mode Driver Framework Design Guide
  2. Kernel-Mode Driver Framework Reference
  3. Summary of KMDF and WDM Equivalents: http://www.microsoft.com/whdc/driver/wdf/WDF_Port.mspx
  4. Windows Driver Model by Walter Oney (book)


Comments

  • There are no comments yet. Be the first to comment!

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Hybrid cloud platforms need to think in terms of sweet spots when it comes to application platform interface (API) integration. Cloud Velocity has taken a unique approach to tight integration with the API sweet spot; enough to support the agility of physical and virtual apps, including multi-tier environments and databases, while reducing capital and operating costs. Read this case study to learn how a global-level Fortune 1000 company was able to deploy an entire 6+ TB Oracle eCommerce stack in Amazon Web …

  • Live Event Date: August 20, 2014 @ 1:00 p.m. ET / 10:00 a.m. PT When you look at natural user interfaces as a developer, it isn't just fun and games. There are some very serious, real-world usage models of how things can help make the world a better place – things like Intel® RealSense™ technology. Check out this upcoming eSeminar and join the panel of experts, both from inside and outside of Intel, as they discuss how natural user interfaces will likely be getting adopted in a wide variety …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds