Plug and Play and Power Management in Software-Only Drivers


A software-only driver is a driver that does not control any hardware, either directly or through a protocol such as USB. For example, a root-enumerated function driver is a software-only driver and some filter drivers are software-only drivers. The devnode for a root-enumerated function driver is enumerated from the root of the device tree, and the driver is not associated with any hardware. Software-only drivers can be written for either user mode or kernel mode.

A root-enumerated, software-only KMDF driver creates an FDO and thus is by default considered the power policy owner for its stack. However, because the driver does not control physical hardware, it does not perform any specific power policy actions-the WDF defaults are sufficient to manage power policy.

Filter drivers are rarely power policy owners for their stacks. However, if a filter driver is the power policy manager for its stack, the driver notifies the framework as part of device object initialization so that WDF can initialize the device object appropriately. If the framework's defaults are otherwise adequate for the driver, the driver does not require any additional Plug and Play or power callbacks. The framework can manage Plug and Play and power for the driver, just as for the software-only function driver. If the framework's defaults are not adequate, a filter driver can implement Plug and Play and power callbacks to satisfy its requirements.

By default, the framework implements power management for all I/O queue objects that are children of FDOs and PDOs. Queues associated with filter DOs are not power managed. Because device hardware is not accessible when the device is in a state other than D0, the framework dispatches requests from a power-managed queue to the driver only when the device is in the D0 state.

Software-only drivers, by definition, do not access any device hardware. Therefore, such drivers should typically disable power management for all of their queues. Disabling power management for the queues means that the framework dispatches requests to the driver regardless of the state of the underlying device hardware. The driver can then process the request as usual and forward it, if necessary, to the next lower driver. A driver disables power management for a queue object when it creates the queue.

Chapter 8, "I/O Flow and Dispatch," provides information about queues.

Tip 

Chapter 24, "Static Driver Verifier," describes how to annotate your driver's callback functions so that SDV can analyze compliance with KMDF rules that specify that a driver that is not a power policy owner cannot call these power management functions: WdfDeviceInitSetPowerPolicyEventCallbacks, WdfDeviceAssignS0IdleSettings, and WdfDeviceAssignSxWakeSettings.

UMDF Example: Plug and Play in a Software-Only Filter Driver

The USB Filter sample requires no special code to handle plug and play or power management. Instead, the driver simply:

  • Initializes the device object as a filter.

  • Indicates that the device object does not own power policy. This call is not required because UMDF by default assumes that the driver is not the power policy owner.

  • Creates non-power-managed queues.

All of these tasks are part of IDriverEntry::OnDeviceAdd processing. In the USB Filter sample driver, this processing includes the Initialize method, which is implemented on the device callback object in Device.cpp, as Listing 7-1 shows.

Listing 7-1: Sample PnP initialization in a UMDF filter driver

image from book
 HRESULT CMyDevice::Initialize(     __in IWDFDriver           * FxDriver,     __in IWDFDeviceInitialize * FxDeviceInit     ) {     IWDFDevice *fxDevice;     HRESULT hr;     FxDeviceInit->SetLockingConstraint(None); FxDeviceInit->SetFilter();     FxDeviceInit->SetPowerPolicyOwnership(FALSE);     {         IUnknown *unknown = this->QueryIUnknown();         hr = FxDriver->CreateDevice (FxDeviceInit, unknown, &fxDevice);         unknown->Release();     }     if (SUCCEEDED(hr)) {         m_FxDevice = fxDevice;         fxDevice->Release();     }     return hr; } 
image from book

 Chapter 6 describes initialization of device objects  The Initialize function in Listing 7-1 initializes and creates the framework's device object. The significant steps here are in bold. The call to IWDFDeviceInitialize::SetFilter tells the framework that the driver acts as a filter, so the framework should change its default for request types that the driver does not handle. Instead of failing such requests, the framework passes them to the next lower driver. The call to IWDFInitialize::SetPowerPolicyOwnership indicates to the framework that the driver does not own power policy for the device. This call is not required in this driver, but is included for demonstration purposes.

The only other required step in a UMDF filter driver is to create non-power-managed queues. The driver does this when it calls IWDFDevice::CreateIoQueue, as the following shows:

 hr = FxDevice->CreateIoQueue( unknown,                               TRUE,  // bDefaultQueue                               WdfIoQueueDispatchParallel,                               FALSE, // bPowerManaged                               TRUE, // bAllowZeroLengthRequests                               &fxQueue                               ); 

In this call, the important item is the fourth parameter (bPowerManaged), which indicates whether the framework should manage power for the queues. A software-only driver passes FALSE for this parameter so that the framework dispatches requests to the driver whether or not the device is in the working power state.

KMDF Example: Plug and Play in a Software-Only Filter Driver

As described earlier, the framework automatically handles Plug and Play and power management tasks for software-only drivers by default.

Listing 7-2, which is adapted from the Toaster Filter sample, shows a basic EvtDriverDeviceAdd function for a software-only KMDF filter driver. This function sets up two Plug and Play or power management features, which are highlighted in this listing:

  • An optional cleanup event callback for the device object.

  • A non-power-managed I/O queue.

Listing 7-2: Sample PnP initialization in a KMDF software-only filter driver

image from book
 NTSTATUS FilterEvtDriverDeviceAdd(                         IN WDFDRIVER Driver,                         IN PWDFDEVICE_INIT DeviceInit) {     NTSTATUS status =          STATUS_SUCCESS;     PFDO_DATA                  fdoData;     WDF_IO_QUEUE_CONFIG        queueConfig;     WDF_OBJECT_ATTRIBUTES      fdoAttributes;     WDFDEVICE                  hDevice; WdfFdoInitSetFilter(DeviceInit);     // Initialize the object attributes for our WDFDEVICE.     WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&fdoAttributes, FDO_DATA); fdoAttributes.EvtCleanupCallback = FilterEvtDeviceContextCleanup;     // Create a framework device object.     status = WdfDeviceCreate(&DeviceInit, &fdoAttributes, &hDevice);     if (!NT_SUCCESS(status)) {         return status;     }     status = WdfDeviceCreateDeviceInterface(hDevice, &GUID_DEVINTERFACE_FILTER, NULL);     if (!NT_SUCCESS (status)) {         return status;     }     // Initialize the default queue.     WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&queueConfig, WdfIoQueueDispatchParallel);     queueConfig.PowerManaged = FALSE; // Specify event processing callbacks. queueConfig.EvtIoWrite = FilterEvtIoWrite; // Create the queue status = WdfIoQueueCreate(hDevice, &queueConfig, WDF_NO_OBJECT_ATTRIBUTES, NULL); if (!NT_SUCCESS (status)) { return status; } return STATUS_SUCCESS; } 
image from book

The EvtDriverDeviceAdd function in Listing 7-2 is called with a pointer to the WDF driver object and a pointer to a WDFDEVICE_INIT structure. The WDFDEVICE_INIT structure is used to initialize a variety of characteristics that are applied when the device object is created.

To indicate that the device object represents a filter, the driver passes the WDFDEVICE_INIT pointer to WdfFdoInitSetFilter. As a result, the framework changes its default processing for any I/O queues that are children of the device object. Instead of failing request types that the driver does not handle, the framework passes them to the next lower driver. In addition, the framework creates I/O queues that are not power managed.

The driver registers the device object's context type (FDO_DATA) as part of the WDF_OBJECT_ATTRIBUTES structure. By filling in the EvtCleanupCallback member of this same structure, the driver registers to be called at its FilterEvtDeviceContextCleanup function when the device object is deleted. A driver should implement this callback if, for example, it has allocated memory other than that provided by the standard WDF object context structures and the memory must be freed when the device object is deleted.

The driver then creates the device object and the device interface by calling WdfDeviceCreate and WdfDeviceCreateDeviceInterface, respectively.

Following this, the driver initializes a WDF_IO_QUEUE_CONFIG structure for its default queue, providing a callback for handling write requests. It sets the PowerManaged field of the WDF_IO_QUEUE_CONFIG structure to FALSE to indicate that the I/O queue being created should not be power managed. The driver passes this structure as input to WdfIoQueueCreate to create a single default queue to handle requests for the driver.

Creating a non-power-managed queue means that the framework calls the driver whenever a write request arrives, regardless of the power state of the device.

Framework Actions for Software-Only Drivers

In software-only and filter drivers, the framework handles nearly all Plug and Play and power management operations. Because the driver does not control any hardware, it is not required to provide any additional event callbacks. The framework automatically processes all power management requests properly.

The UMDF driver's only Plug and Play callback function is IDriverEntry::OnDeviceAdd, and the KMDF driver's only Plug and Play callback is EvtDriverDeviceAdd. Although the KMDF example also provides an optional EvtCleanupCallback, nothing in the example driver code above actually requires implementing this callback.

The sample drivers disable power management for their queues. As a result, the framework does not automatically hold and release the queue based on arriving Plug and Play and power management events. Instead, the driver continues to receive I/O requests regardless of the Plug and Play and power state of the device.




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

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net