porting a driver from wdm to kmdf · web viewseptember 12, 2006 abstract this paper provides...

72
Porting a Driver from WDM to KMDF September 12, 2006 Abstract This paper provides information about how to port drivers that conform to the Microsoft® Windows® Driver Model (WDM) to use the kernel-mode driver framework (KMDF) of the Windows Driver Foundation (WDF) for the Microsoft Windows family of operating systems. It assumes that readers are experienced with WDM and acquainted with KMDF. A companion to this paper titled Summary of KMDF and WDM Equivalents provides tables that compare specific aspects of the two models. This information applies for the following operating systems: Microsoft Windows Vista™ Microsoft Windows Server® 2003 Microsoft Windows XP Microsoft Windows 2000 The current version of this paper is maintained on the Web at: http://www.microsoft.com/whdc/driver/wdf/WDF_Port.mspx References and resources discussed here are listed at the end of this paper. Contents Introduction.......................................................4 Which Drivers Can Be Ported........................................5 Why to Port a Driver...............................................6 Differences between WDM and KMDF...................................7 Driver Structure.................................................8 Device Objects and Driver Roles..................................8 Object Model.....................................................9 Object Creation..............................................10 Object Context Area..........................................11 Object Lifetime and Deletion.................................12 Supported IRP Types.............................................13 I/O Queues......................................................14 I/O Targets.....................................................15 Synchronization and Concurrency.................................15 Driver Installation.............................................17 Strategies for Porting............................................17 WDM Driver Analysis.............................................17

Upload: others

Post on 24-Mar-2020

1 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Porting a Driver from WDM to KMDF · Web viewSeptember 12, 2006 Abstract This paper provides information about how to port drivers that conform to the Microsoft® Windows® Driver

Porting a Driver from WDM to KMDFSeptember 12, 2006

AbstractThis paper provides information about how to port drivers that conform to the Microsoft® Windows® Driver Model (WDM) to use the kernel-mode driver framework (KMDF) of the Windows Driver Foundation (WDF) for the Microsoft Windows family of operating systems. It assumes that readers are experienced with WDM and acquainted with KMDF. A companion to this paper titled Summary of KMDF and WDM Equivalents provides tables that compare specific aspects of the two models.

This information applies for the following operating systems:Microsoft Windows Vista™Microsoft Windows Server® 2003Microsoft Windows XPMicrosoft Windows 2000

The current version of this paper is maintained on the Web at: http://www.microsoft.com/whdc/driver/wdf/WDF_Port.mspx

References and resources discussed here are listed at the end of this paper.ContentsIntroduction..............................................................................................................................4Which Drivers Can Be Ported..................................................................................................5Why to Port a Driver.................................................................................................................6Differences between WDM and KMDF....................................................................................7

Driver Structure...................................................................................................................8Device Objects and Driver Roles........................................................................................8Object Model.......................................................................................................................9

Object Creation............................................................................................................10Object Context Area.....................................................................................................11Object Lifetime and Deletion........................................................................................12

Supported IRP Types........................................................................................................13I/O Queues........................................................................................................................14I/O Targets........................................................................................................................15Synchronization and Concurrency....................................................................................15Driver Installation..............................................................................................................17

Strategies for Porting.............................................................................................................17WDM Driver Analysis........................................................................................................17Steps in Porting.................................................................................................................18

DriverEntry Routine................................................................................................................19EvtDriverDeviceAdd Callback................................................................................................19

WDFDEVICE_INIT Structure............................................................................................20Initialization for an FDO................................................................................................21Initialization for a Filter DO...........................................................................................21

Device Object Context Area..............................................................................................21Device Object Creation.....................................................................................................23Additional EvtDriverDeviceAdd Tasks...............................................................................23Child Device Enumeration (PDOs Only)...........................................................................23

Static and Dynamic Enumeration.................................................................................23PDO-Specific Initialization............................................................................................24

Page 2: Porting a Driver from WDM to KMDF · Web viewSeptember 12, 2006 Abstract This paper provides information about how to port drivers that conform to the Microsoft® Windows® Driver

Porting a Driver from WDM to KMDF - 2

Plug and Play and Power Management.................................................................................25Power Policy Ownership...................................................................................................25Event Callbacks for Plug and Play and Power IRPs.........................................................26Device Enumeration and Power-Up..................................................................................27

Power-up Sequence for a Function or Filter Device Object.........................................27Power-Up Sequence for a Physical Device Object......................................................29

Device Power-Down and Removal...................................................................................30Power-Down and Removal Sequence for a Function or Filter Device Object..............31Power-Down and Removal Sequence for a Physical Device Object...........................32Surprise-Removal Sequence.......................................................................................33

Interrupts................................................................................................................................34I/O Queues and I/O Requests................................................................................................35

Create I/O Queues............................................................................................................35Port I/O Dispatch Routines to I/O Event Callback Functions............................................37

Parameters for I/O Requests........................................................................................37Access to Buffers for Buffered and Direct I/O..............................................................37Create Requests..........................................................................................................38Read Requests.............................................................................................................39Write Requests.............................................................................................................39Device I/O Control Requests........................................................................................40Internal Device I/O Control Requests...........................................................................41Access to Buffers for Neither I/O..................................................................................41

Complete a Request.........................................................................................................44Handle a Canceled Request.............................................................................................44Forward a Request to the Next Lower Driver....................................................................45Issue an I/O Request........................................................................................................46

DMA Support.........................................................................................................................48WMI Support..........................................................................................................................49Timers, DPCs, and Work Items.............................................................................................50Requests that KMDF Does Not Support................................................................................51Installation Procedure............................................................................................................52General Guidelines for Porting...............................................................................................53Resources..............................................................................................................................53

September 12, 2006© 2006 Microsoft Corporation. All rights reserved.

Page 3: Porting a Driver from WDM to KMDF · Web viewSeptember 12, 2006 Abstract This paper provides information about how to port drivers that conform to the Microsoft® Windows® Driver

Porting a Driver from WDM to KMDF - 3

DisclaimerThis is a preliminary document and may be changed substantially prior to final commercial release of the software described herein.

The information contained in this document represents the current view of Microsoft Corporation on the issues discussed as of the date of publication. Because Microsoft must respond to changing market conditions, it should not be interpreted to be a commitment on the part of Microsoft, and Microsoft cannot guarantee the accuracy of any information presented after the date of publication.

This White Paper is for informational purposes only. MICROSOFT MAKES NO WARRANTIES, EXPRESS, IMPLIED OR STATUTORY, AS TO THE INFORMATION IN THIS DOCUMENT.

Complying with all applicable copyright laws is the responsibility of the user. Without limiting the rights under copyright, no part of this document may be reproduced, stored in or introduced into a retrieval system, or transmitted in any form or by any means (electronic, mechanical, photocopying, recording, or otherwise), or for any purpose, without the express written permission of Microsoft Corporation.

Microsoft may have patents, patent applications, trademarks, copyrights, or other intellectual property rights covering subject matter in this document. Except as expressly provided in any written license agreement from Microsoft, the furnishing of this document does not give you any license to these patents, trademarks, copyrights, or other intellectual property.

Unless otherwise noted, the example companies, organizations, products, domain names, e-mail addresses, logos, people, places and events depicted herein are fictitious, and no association with any real company, organization, product, domain name, email address, logo, person, place or event is intended or should be inferred.

© 2006 Microsoft Corporation. All rights reserved.

Microsoft, Windows, Windows Server, and Windows Vista are either registered trademarks or trademarks of Microsoft Corporation in the United States and/or other countries.

The names of actual companies and products mentioned herein may be the trademarks of their respective owners.

September 12, 2006© 2006 Microsoft Corporation. All rights reserved.

Page 4: Porting a Driver from WDM to KMDF · Web viewSeptember 12, 2006 Abstract This paper provides information about how to port drivers that conform to the Microsoft® Windows® Driver

Porting a Driver from WDM to KMDF - 4

IntroductionThe kernel-mode driver framework (KMDF) component of the Microsoft® Windows® Driver Foundation (WDF) provides an infrastructure for developing kernel-mode drivers. It is layered on top of the Windows Driver Model (WDM) and implements code to handle many common driver requirements. In essence, the framework is a skeletal device driver that can be customized for specific devices.

Architecturally, KMDF drivers are similar to WDM drivers. A WDM driver consists of a DriverEntry function, various dispatch routines that the operating system calls to service I/O requests, and additional driver-specific utility functions. A KMDF driver consists of a DriverEntry function, various event callback functions that the framework calls to service I/O requests, and additional driver-specific utility functions.

However, within this broad structure, the two models have important differences: Dispatch routines and event callback functions. In the WDM model, each dispatch routine corresponds to a major I/O request packet (IRP) code. IRP codes identify Plug and Play, power management, and Windows Management Instrumentation (WMI) requests in addition to requests for actual device I/O. The driver must determine how to handle each IRP that is based on the current state of the device, driver, and operating system. The driver must therefore maintain information about its own state and that of its device and the system as a whole.In the WDF model, a driver implements event callback functions that map to driver-oriented and device-oriented tasks rather than to broad IRP codes. The framework tracks system, driver, and device state, interprets the request that each IRP represents, and calls a state-specific event callback. Thus, the driver handles only requests that are pertinent to its device and is not required to maintain extensive state information. Interaction with the operating system. WDM drivers must call the operating system directly to handle many common tasks, whereas KMDF drivers can usually call the framework instead. The framework calls the underlying operating system functions after validating all parameters and verifying that the driver is running at the correct interrupt request level (IRQL) to make the call.The framework implements much of the infrastructure that most drivers require to manage queues, synchronization, and cancellation. In most cases, WDM drivers must manage such features on their own.

Most kernel-mode WDM drivers can be ported to use KMDF. This paper provides information about porting such drivers, including:

Which drivers can be ported Advantages of porting Differences between the WDM and KMDF models Details about porting driver code from WDM to KMDF Required revisions to the existing driver’s INF to install the KMDF driver

Readers of this paper should have experience with WDM drivers and be familiar with the architecture of KMDF. For pointers to more information, see "Resources" at the end of this paper.

September 12, 2006© 2006 Microsoft Corporation. All rights reserved.

Page 5: Porting a Driver from WDM to KMDF · Web viewSeptember 12, 2006 Abstract This paper provides information about how to port drivers that conform to the Microsoft® Windows® Driver

Porting a Driver from WDM to KMDF - 5

In addition, see the companion document titled Summary of KMDF and WDM Equivalents for a set of tables that show the corresponding KMDF and WDM object types, KMDF event callback functions and WDM driver-supplied routines, and the KMDF methods and their WDM equivalents.

Which Drivers Can Be PortedWhether a particular driver can be ported to WDF depends on:

The operating system versions on which the driver must run The type of device that the driver supports Which driver model the driver uses

KMDF can be used to create drivers that will run on Microsoft Windows 2000 and later versions of the operating system.

Table 1 summarizes the device and driver types that KMDF supports.Table 1. Device and Driver Types Supported by KMDFDevice or driver type Previous driver modelControl and non-Plug and Play drivers LegacyHuman interface device (HID) drivers HID miniport (WDM-based)IEEE 1394 client drivers1 Depends on device classISA, PCI, PCMCIA, and secure digital (SD) devices2 WDM Network Driver Interface Specification (NDIS) protocol drivers

WDM upper edge and NDIS lower edge

NDIS WDM drivers NDIS upper edge and WDM lower edge

SoftModem drivers WDM with upper-edge support for Telephony Application Programming Interface (TAPI) interface

Storage class drivers and filter drivers WDM Transport driver interface (TDI) client drivers WDM USB client drivers Depends on device classWinsock client drivers WDM with a callback interface for

device-specific requests1 Supported for devices that do not conform to existing device class specifications.2 Supported, if device class or port drivers do not provide the driver dispatch functions.

In general, KMDF can be used to write drivers that conform to WDM, supply entry points for the major I/O dispatch routines, and handle IRPs. For some device types, the device class and port drivers supply driver dispatch functions and call a miniport driver to handle specific I/O details. Such miniport drivers are essentially callback libraries and are not currently supported by KMDF. In addition, KMDF does not support device types that use Windows image acquisition (WIA).

However, a minidriver that is based on a driver model in which the minidriver communicates with other drivers by using WDM interfaces can be ported. For example, the Ndisedge sample drivers that are provided with KMDF show how to use KMDF to implement the WDM lower edge.

Except for drivers that support printers and a few other device types, most Windows drivers run in kernel mode. By using WDF, however, certain additional drivers can run in user mode. If a driver does not service interrupts, perform direct memory access (DMA), require kernel-mode resources such as the nonpaged pool, or act as the client of a kernel-mode driver, consider rewriting it to run in user mode, by using the user-mode driver framework (UMDF). This paper does not cover user-mode

September 12, 2006© 2006 Microsoft Corporation. All rights reserved.

Page 6: Porting a Driver from WDM to KMDF · Web viewSeptember 12, 2006 Abstract This paper provides information about how to port drivers that conform to the Microsoft® Windows® Driver

Porting a Driver from WDM to KMDF - 6

driver implementation. For information about UMDF, see the white paper titled Architecture of the User-Mode Driver Framework, which is listed in "Resources" at the end of this paper.

Why to Port a DriverIf already have a WDM driver, you might wonder why to even consider porting it to KMDF. You have already spent hours learning the intricacies of the WDM model and mastering dozens of rules for handling Plug and Play and power IRPs. Your driver works. Or does it? Are you certain your driver handles all these tasks correctly?

Here are a few advantages of porting a driver to KMDF.

KMDF Drivers Are Simpler and Easier to Maintain. KMDF defines an object-based, event-based driver model. A driver instantiates the KMDF objects that it requires and implements callback functions that respond to specific events. The often complex logic that determines when to invoke the callback functions—particularly for Plug and Play and power management—resides within KMDF.

The KMDF model results in drivers that are more concise and thus much simpler and easier to debug than WDM drivers. KMDF drivers require minimal common code for default operations because most such code resides in the framework, where it has been thoroughly tested and can be globally updated.

Because KMDF event callbacks are clearly and narrowly defined, KMDF-based drivers typically require little code complexity. Each driver event callback routine is designed to perform a specific task. Therefore, compared to WDM drivers, KMDF-based drivers have fewer lines of code and a minimal number of state variables and locks.

As part of the KMDF development effort, Microsoft has converted many of the sample drivers that are shipped with the Windows Driver Kit (WDK) from WDM to KMDF. Without exception, the KMDF drivers are smaller and less complex.

Table 2 shows "before-and-after" statistics for the PCIDRV, Serial, and OSRUSBFX2 drivers.Table 2. Statistics for Sample WDM and KMDF Drivers

Statistic PCIDRV1 Serial2 OSRUSBFX23

WDM KMDF WDM KMDF WDM KMDFTotal lines of code 13,147 7,271 24,000 17,000 16,350 2,300Lines of code required for Plug and Play and power management

7,991 1,795 5,000 2,500 8,700 742

Locks and synchronization primitives

8 3 10 0 9 0

State variables required for Plug and Play and power management

30 0 53 0 21 0

1 The PCIDRV sample supports the Intel E100B NIC card. The WDM and KMDF versions are functionally equivalent.

2 The Serial sample supports a serial device. In this case, the WDM sample supports a multiport device, but the KMDF sample supports only a single port. However, the statistics for the WDM driver do not include code, locks, or variables that are required solely to support multiport devices, so the statistics are comparable.

3 The OSRUSBFX2 sample supports the USB-FX2 board built by OSR. The WDM and KMDF versions are functionally equivalent. The WDM version is available at http://www.osronline.com.

September 12, 2006© 2006 Microsoft Corporation. All rights reserved.

Page 7: Porting a Driver from WDM to KMDF · Web viewSeptember 12, 2006 Abstract This paper provides information about how to port drivers that conform to the Microsoft® Windows® Driver

Porting a Driver from WDM to KMDF - 7

As the table shows, converting these drivers from WDM to KMDF resulted in significant reductions in code size—particularly for Plug and Play and power management. The KMDF samples also require fewer locks and synchronization primitives and state variables.

KMDF Has Built-in Support for Bus and Filter Drivers. A KMDF driver indicates whether it is a bus, function, or filter driver for a particular device. According to the settings that the driver makes and the callbacks that it implements, KMDF invokes the appropriate callbacks at the right times and handles the correct IRPs. The framework calls the driver only for those I/O requests that the driver handles and provides default handling for any other requests.

KMDF Manages Most Interactions with the Operating System. A KMDF driver dynamically links at run time with the framework, which handles many interactions with the operating system. The framework intercepts IRPs that are directed to the driver and handles them by applying defaults and invoking driver callbacks as required. As a result, most of the complicated code to interact with the operating system is implemented in the framework instead of in the driver.

For example, an existing WDM driver typically contains several thousand lines of code to handle Plug and Play and power management IRPs. It must pass IRPs that it does not support to the next lower driver, and it must determine whether to handle other IRPs as they travel down the device stack or whether to set an I/O completion routine and handle them on the way back up. A KMDF driver for the same device requires no code for Plug and Play and power IRPs that it does not support; KMDF provides default handling for those requests. For supported Plug and Play and power requests, the driver implements a set of callback functions and the framework calls them at the appropriate time.

KMDF Supports Versioning and Is Tested for Each Release of the Operating System. Microsoft tests KMDF with each new release of the operating system to ensure that driver behavior remains consistent from one release to the next. Furthermore, KMDF itself has major and minor versions. Driver binaries always run with the most recent available minor version of KMDF, so the existing driver benefits from bug fixes in the underlying framework. Two major versions of KMDF can run side by side on a single system.

Differences between WDM and KMDFThe WDM model is closely tied to the operating system. Drivers interact directly with the operating system by calling system service routines and manipulating operating system structures. Because WDM drivers are trusted kernel-mode components, the system provides limited checks on driver input.

In comparison, the KMDF model focuses on the driver’s requirements and the framework library handles the majority of the interactions with the system. The framework intercepts I/O requests, takes default actions where appropriate, and invokes the driver’s callbacks as required. The KMDF model is object based and event driven. Objects represent common driver constructs, such as a device, a lock, or a queue. The driver thus contains an entry point (DriverEntry), the event-related callback functions that are required to service the device and support I/O, and any additional internal utility functions on which the implementation depends.

September 12, 2006© 2006 Microsoft Corporation. All rights reserved.

Page 8: Porting a Driver from WDM to KMDF · Web viewSeptember 12, 2006 Abstract This paper provides information about how to port drivers that conform to the Microsoft® Windows® Driver

Porting a Driver from WDM to KMDF - 8

The sections that follow summarize important differences between WDM and KMDF in these areas:

Driver structure Device objects and driver roles Object model Supported IRP types I/O queues I/O targets Synchronization and concurrency Driver installation

Driver StructureBoth WDM and KMDF drivers contain a DriverEntry routine, a number of routines that are called to handle particular I/O requests, and various support routines. In a WDM driver, the I/O dispatch routines map to particular major IRP codes. The dispatch routines receive IRPs from the I/O manager, parse them, and respond accordingly. For a KMDF driver, the framework registers its own dispatch routines, which receive IRPs from the I/O manager, parse them, and then invoke the driver’s event callback functions to handle them. The event callback functions typically perform a much more specific task than the more general I/O dispatch routines of the WDM driver.

The typical KMDF driver for a Plug and Play device has: A DriverEntry routine. An EvtDriverDeviceAdd routine, which is similar in function to a WDM AddDevice routine. One or more I/O queues. One or more I/O event callback functions, which are similar in function to a WDM driver’s I/O DispatchXxx routines. Callbacks to handle the Plug and Play and power events that the driver supports. Callbacks to handle the WMI requests that the driver supports. Additional callbacks, as appropriate, for object cleanup, file creation, I/O targets, and so forth.

Device Objects and Driver RolesBoth WDM and KMDF drivers create one or more device objects. Each device object represents a driver role that is the target of I/O requests. A physical device object (PDO) represents a bus driver, a functional device object (FDO) represents a function driver, and a filter device object (filter DO) represents a filter driver.

In WDM drivers, these driver roles are implicit, so the driver must keep track of which role each device object represents and respond to IRPs appropriately. KMDF drivers, however, indicate explicitly whether a device object represents a PDO, FDO, or filter DO and register event callbacks that are specific to that role. For example, PDOs are the target of resource-requirements queries and device ejection requests, whereas FDOs and filter DOs do not handle such requests.

A KMDF driver configures each device object to receive certain types of I/O requests. The framework calls the driver to handle only those I/O requests and

September 12, 2006© 2006 Microsoft Corporation. All rights reserved.

Page 9: Porting a Driver from WDM to KMDF · Web viewSeptember 12, 2006 Abstract This paper provides information about how to port drivers that conform to the Microsoft® Windows® Driver

Porting a Driver from WDM to KMDF - 9

performs a default action for all other requests. If the device object represents a filter driver, the framework passes all other requests to the next lower driver. If the device object represents a bus or function driver, the framework fails all other request types.

For Plug and Play and power requests, the framework calls the KMDF driver only for the requests that are appropriate for each device object—and at the appropriate time. For example, an FDO must respond to certain requests after the underlying PDO has already responded. In a WDM driver, the FDO must set an I/O completion routine, pass the IRP down the stack, and process it after lower drivers. A KMDF driver simply implements the corresponding callback routine, and the framework calls it after lower drivers have completed processing.

Some drivers also handle certain I/O requests that are independent of Plug and Play. A WDM driver creates a DEVICE_OBJECT as the target for such requests, but does not attach it to the Plug and Play device stack. To accomplish the same result, a KMDF driver creates a control device object. Some KMDF drivers use control device objects to implement “sideband” I/O mechanisms, so that they can receive certain types of I/O requests regardless of device state.

Object ModelKMDF supports a coherent object model in which objects are opaque to drivers, provide driver-configurable context areas, and are referenced by a handle. WDM objects are system-wide objects that are accessible to drivers and are referenced by pointers. A driver that corrupts a WDM object can corrupt the entire system. Corrupting a KMDF object is not only more difficult—because the framework validates the data that the driver supplies—but also causes system-wide problems much less often.

KMDF objects have methods, properties, and events, which follow a naming convention.

Methods are functions that perform operations on the object. Methods are named WdfObjectAction, where Object describes the object and Action indicates what the function does. For example, WdfDeviceCreate creates a device object. Properties are methods that get or set a single value. In many cases, properties map directly to the fields in the corresponding WDM objects. Properties that cannot fail are named WdfObjectGetValue and WdfObjectSetValue, and properties that can fail are named WdfObjectRetrieveValue and WdfObjectAssignValue. Object describes the object, and Value identifies the data that the function sets or returns. For example, WdfDeviceGetDriver returns a handle to the driver object that is associated with the device object. Events represent run-time states to which a driver can respond or during which a driver can participate. (An object’s events are not related to the event synchronization primitive.) A driver registers an event callback function to receive notification of a particular event. By convention, the placeholders for event callback functions are called EvtObjectEvent, although you can name these callbacks anything you choose in your driver. For example, a driver registers the EvtDeviceD0Entry event callback to be notified when its device enters the working state.

The framework maintains a reference count for each object, which thus provides some control over its lifetime. Objects are organized hierarchically (with parent/child relationships), and child objects are always deleted before the parent objects. Although the object model is hierarchical, it does not support inheritance in the

September 12, 2006© 2006 Microsoft Corporation. All rights reserved.

Page 10: Porting a Driver from WDM to KMDF · Web viewSeptember 12, 2006 Abstract This paper provides information about how to port drivers that conform to the Microsoft® Windows® Driver

Porting a Driver from WDM to KMDF - 10

object-oriented programming sense. That is, an object does not inherit the methods of its parents.

Although many of the KMDF objects correspond to WDM objects, the KMDF objects support features that would require additional code in a WDM driver. All KMDF objects support driver-definable object context areas, so that a driver can store information that is related to a particular instance of an object with the object itself. Objects typically track state as well. For example, WDFQUEUE objects are more than just a list of I/O requests; they support several types of dispatching, automatic synchronization with Plug and Play, and request cancellation. For WDFMEMORY objects, the framework-managed reference count helps prevent memory leaks and premature release of resources.

Object CreationKMDF drivers follow a regular pattern to create all types of objects:1. Initialize the configuration structure for the object, if one exists.

2. Initialize the attributes structure for the object, if necessary.

3. Call the creation method to create the object.

Object Configuration Structure. The object configuration structure and the object attributes structure supply basic information about the object and how the driver uses it. All object types share the same attributes structure, but the configuration structure for each type of object is different and some objects do not have one.

The configuration structure holds pointers to object-specific information, such as the driver’s event callback functions for the object. The driver fills in this structure and then passes it to the framework when it calls the object creation method. The framework uses the information from the configuration structure to initialize the object. For example, the WDFDRIVER object contains a pointer to the driver’s EvtDriverDeviceAdd callback function, which the framework invokes when a Plug and Play add-device event occurs.

The framework defines functions that are named WDF_Object_CONFIG_INIT to initialize the configuration structures, where Object represents the name of the object type. By convention, the configuration structures themselves are named WDF_Object_CONFIG. The framework also defines additional functions to initialize supplemental object-specific structures that are required to create some objects. These functions are named Structure_INIT, where Structure indicates the name of the structure. For example, the WDF_FDO_EVENT_CALLBACKS_INIT function initializes a WDF_FDO_EVENT_CALLBACKS structure.

Object Attributes Structure. The object attributes structure (WDF_OBJECT_ATTRIBUTES) specifies:

Event callbacks to handle object cleanup and destruction. The IRQL at which the object’s callback functions are invoked and its locks are held. This attribute is not applicable to all objects. An object context area. Information about the context area, such as its size and type. The synchronization scope for the object’s callbacks. This attribute is not applicable to all objects.

The framework defines the following functions for use in initializing object attributes: WDF_OBJECT_ATTRIBUTES_INIT

September 12, 2006© 2006 Microsoft Corporation. All rights reserved.

Page 11: Porting a Driver from WDM to KMDF · Web viewSeptember 12, 2006 Abstract This paper provides information about how to port drivers that conform to the Microsoft® Windows® Driver

Porting a Driver from WDM to KMDF - 11

WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE

The WDF_OBJECT_ATTRIBUTES_INIT function sets values for synchronization scope and execution level, which determine which of the driver’s callbacks the framework invokes concurrently and the highest IRQL at which they can be called. The context-type initialization macro sets information about the object’s context area, which is described in the next section.

Although attributes can apply to any type of object, the defaults are typically acceptable for objects for which the driver does not define a context area and that do not require cleanup or other driver action at deletion. To accept the defaults, a driver specifies WDF_NO_OBJECT_ATTRIBUTES, which KMDF defines as NULL.

Object Creation Method. After initializing the object’s configuration structure and attributes, the driver creates an instance of the object by calling the creation method for the object type (WdfObjectCreate) with a pointer to the attributes structure and any other object-type-specific parameters. The creation method returns a handle to the created object. The driver subsequently uses the handle to refer to the object.

Object Context AreaEvery instance of an object can have one or more object context areas. The object context area is a storage area for data that is related to that particular instance, such as a driver-allocated event object. The driver determines the size and layout of the object context area. For a device object, the object context area is the equivalent of the WDM device extension.

A driver initializes the context area and specifies its size and type when it calls the WdfObjectCreate method. When the framework creates the object, it allocates memory for the context area from the nonpaged pool. A driver can create additional context areas by calling the WdfObjectAllocateContext method. When the framework deletes the object, all of its context areas are deleted, too.

The context area is considered part of the object, which is opaque to drivers. Therefore, the driver must use an accessor function to get a pointer to the context area. Each context area has its own accessor function, and the framework provides macros to create these functions.

For the driver, defining and initializing a context area is a multistep process. First, the driver defines a data structure that describes the context area. This definition typically appears in a header file because it defines a global data structure.

Next, the driver declares the type of the context area, by using either the WDF_DECLARE_CONTEXT_TYPE or WDF_DECLARE_CONTEXT_TYPE_WITH_NAME macro. These macros associate a type with the context area and create a named accessor function that returns a pointer to the context area. WDF_DECLARE_CONTEXT_TYPE_WITH_NAME assigns a driver-specified name to the accessor function. WDF_DECLARE_CONTEXT_TYPE assigns the default name WdfObjectGet_ContextStructure, where ContextStructure is the type name of the context structure. This declaration, too, should typically appear in a header file because it creates a driver-callable routine.

September 12, 2006© 2006 Microsoft Corporation. All rights reserved.

Page 12: Porting a Driver from WDM to KMDF · Web viewSeptember 12, 2006 Abstract This paper provides information about how to port drivers that conform to the Microsoft® Windows® Driver

Porting a Driver from WDM to KMDF - 12

For example, the following shows how the Pcidrv sample driver sets up a context area for the driver object:typedef struct _DRIVER_CONTEXT { // // The assumption here is that the same lookaside list // can be used to do allocations for multiple devices. // WDFLOOKASIDE RecvLookaside;

} DRIVER_CONTEXT, * PDRIVER_CONTEXT;WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(DRIVER_CONTEXT, GetDriverContext)

Finally, the driver associates the context area with a specific instance of an object when it creates that object. To do so, the driver initializes the object attribute structure with information about the context area by using the WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE or WDF_OBJECT_ATTRIBUTES_SET_CONTEXT_TYPE macro. The driver passes the resulting attribute structure when it calls the creation method for the object.

The following code shows how the Pcidrv sample sets up the attribute structure in the DriverEntry function, before it creates the driver object:WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attrib, DRIVER_CONTEXT);// Additional initialization code omittedstatus = WdfDriverCreate(DriverObject, RegistryPath, &attrib, &config, &driver);

Object Lifetime and DeletionEvery KMDF object has a parent and can have one or more children. With a few exceptions, the default parent for most objects is either the WDFDRIVER object or the WDFDEVICE object.

Internally, the framework maintains a reference count for each object and the object persists as long as its reference count is greater than zero. When an object is deleted—either by the framework or explicitly by the driver—the framework deletes the object’s children first and then the object itself.

The framework controls the lifetime of some types of objects: Driver objects (WDFDRIVER) Device objects (WDFDEVICE) for FDO, filter DO, and PDO File objects (WDFFILEOBJECT) Request objects (WDFREQUEST), except for requests that originate with the driver

The driver controls the lifetime of other types of objects and can call the WdfObjectDelete method to delete such objects. In most cases, however, if the driver uses the default parent for each object that it creates, it is not required to explicitly delete the object; the framework will delete the object when it deletes the parent. To perform cleanup tasks at object deletion, a driver registers a EvtCleanupCallback for an object.

By using the framework’s object-lifetime controls, you can: Prevent memory leaks by ensuring that objects are deleted when no longer in use.

September 12, 2006© 2006 Microsoft Corporation. All rights reserved.

Page 13: Porting a Driver from WDM to KMDF · Web viewSeptember 12, 2006 Abstract This paper provides information about how to port drivers that conform to the Microsoft® Windows® Driver

Porting a Driver from WDM to KMDF - 13

Provide for object cleanup at deletion. Prevent errors that are caused by attempting to delete objects that are still referenced.

Because the framework handles object deletion, the driver is not required to delete its device objects, queues (which are children of the device object), and many other such objects.

Supported IRP TypesKMDF supports a subset of Windows IRPs. Table 3 summarizes the major IRP types that are handled by the framework and their corresponding KMDF driver requirements.Table 3. WDM IRPs and KMDF Driver RequirementsWDM IRP major function code KMDF requirementIRP_MJ_CLEANUP Implement EvtFileCleanup.IRP_MJ_CLOSE Implement EvtFileClose.IRP_MJ_CREATE Implement EvtDeviceFileCreate

-or-Create a WDFIOQUEUE object and implement EvtIoDefault.

IRP_MJ_DEVICE_CONTROL Create WDFIOQUEUE object and implement EvtIoDeviceControl or EvtIoDefault.

IRP_MJ_INTERNAL_DEVICE_CONTROL Create WDFIOQUEUE object and implement the EvtIoInternalDeviceControl or EvtIoDefault.

IRP_MJ_PNP Implement Plug and Play/power state-specific callbacks.

IRP_MJ_POWER Implement Plug and Play/power state-specific callbacks.

IRP_MJ_READ Create WDFIOQUEUE object and implement EvtIoRead or EvtIoDefault.

IRP_MJ_SHUTDOWN For control (non-Plug and Play) device objects: implement EvtDeviceShutdownNotification.For FDO, PDO, and filter DO: not supported.

IRP_MJ_SYSTEM_CONTROL Create WDFWMIPROVIDER and WDFWMIINSTANCE objects and implement EvtWmiXxx callbacks.

IRP_MJ_WRITE Create WDFIOQUEUE object and implement EvtIoWrite or EvtIoDefault.

I/O Requests. The framework creates a WDFREQUEST object to represent an I/O request and calls the driver’s I/O event callbacks with this request. In KMDF, a “request” truly represents a request for I/O: IRP_MJ_READ, IRP_MJ_WRITE, IRP_MJ_CREATE, IRP_MJ_DEVICE_CONTROL, or IRP_MJ_INTERNAL_DEVICE_CONTROL.

The framework delivers such I/O requests to the driver’s I/O event callback functions by way of an I/O queue. The framework can also, at the driver’s option, either queue create requests or immediately invoke a callback function. Cleanup (IRP_MJ_CLEANUP), close (IRP_MJ_CLOSE), and shutdown (IRP_MJ_SHUTDOWN) requests trigger calls to specific event callback functions if the driver implements such functions.

For more information on how to handle particular types of I/O requests in the KMDF driver, see "I/O Queues and I/O Requests,” later in this paper. For a complete description of how the framework handles I/O requests, see the white paper titled

September 12, 2006© 2006 Microsoft Corporation. All rights reserved.

Page 14: Porting a Driver from WDM to KMDF · Web viewSeptember 12, 2006 Abstract This paper provides information about how to port drivers that conform to the Microsoft® Windows® Driver

Porting a Driver from WDM to KMDF - 14

I/O Request Flow in WDF Kernel-Mode Drivers, which is listed in "Resources" at the end of this paper.

WMI, Plug and Play, and Power Management Requests. The framework does not create a WDFREQUEST object for a WMI, Plug and Play, or power management IRP. Instead, the KMDF model defines task-specific callbacks, the driver implements the callbacks that are required to support the features of its device, and the framework invokes the callbacks at the appropriate time. The driver is not required to parse and manage such requests. (However, the driver can always access the raw WDM IRP if necessary.)

IRP_MJ_SYSTEM_CONTROL requests represent WMI requests and thus trigger calls to the driver’s EvtWmiXxx callback functions.

For IRP_MJ_PNP and IRP_MJ_POWER requests, the driver implements callbacks that are invoked at well-defined state transitions to perform device-specific actions that correspond to those transitions. If the driver does not supply a particular callback, the framework performs a default action.

For example, during startup, the Windows I/O manager sends an IRP_MJ_PNP request with minor IRP code IRP_MN_START_DEVICE. A WDM driver handles this request in a DispatchPnP routine by performing a variety of tasks that depend on the state of the device and the operating system. For an FDO, some tasks must be performed as the IRP travels down the stack and others must be performed as the IRP travels back up the stack. In a KMDF driver, however, the framework intercepts the request from the I/O manager and calls a series of driver callback functions that perform driver-specific actions at each state during the start-up sequence.

Other Requests. Even if your driver receives IRPs other than those listed in the table, you can port it to KMDF. The framework provides a mechanism through which a driver can receive “raw” WDM IRPs but also use the KMDF features for other types of IRPs. For more information, see “Requests that KMDF Does Not Support,” later in this paper.

I/O QueuesNearly all drivers queue I/O requests. WDM drivers typically use one of the following approaches:

Implement a StartIo function and call IoStartPacket and IoStartNextPacket to use the system’s device queue for I/O requests. Use the IoCsqXxx or other list-management functions to implement its own internal I/O queues. Use the KeXxxDeviceQueue functions to initialize and manage a queue that is protected by a spin lock.

A KMDF driver creates a KMDF queue object (WDFQUEUE) to represent an I/O queue. The KMDF queue object is similar to a cancel-safe queue but provides additional features. For example, the driver specifies whether requests are dispatched from the queue sequentially (one at a time), in parallel (as soon as they arrive), or manually (only upon request from the driver). At the driver’s option, the framework can manage the queue through system and device power transitions. The driver can also stop and start the queue on its own.

Each WDFQUEUE object is associated with one or more callback functions that handle one or more types of I/O requests. Read, write, device I/O control, and internal device I/O control requests are typically delivered to KMDF drivers through

September 12, 2006© 2006 Microsoft Corporation. All rights reserved.

Page 15: Porting a Driver from WDM to KMDF · Web viewSeptember 12, 2006 Abstract This paper provides information about how to port drivers that conform to the Microsoft® Windows® Driver

Porting a Driver from WDM to KMDF - 15

such a queue. Create requests can either be queued or can be handled immediately by a callback routine.

When you port a WDM driver to KMDF, you can use the KMDF queuing mechanism regardless of the mechanism that the WDM driver uses. To receive and handle I/O requests in a KMDF driver, you must decide:

Which I/O requests the driver must handle. How many queues the driver requires. Whether the driver can handle multiple requests from each queue concurrently or whether it should receive such requests one at a time. Whether the driver requires an event callback for each individual request type or whether one event callback will handle multiple requests types. Whether the driver will receive create requests from a queue or whether such requests should bypass the queue and instead immediately trigger a callback. Whether I/O event callbacks for a device object or queue can execute concurrently or whether they should be synchronized. Whether each queue should be power managed; that is, whether the framework should start and stop the queue when the device enters and leaves the working state.

Determining the number of queues and the types of requests that they should handle is relatively straightforward and probably can map closely to the existing queue strategy. The framework provides built-in concurrency control for I/O event callbacks and automatic support for canceled requests, which can simplify the code.

I/O TargetsMost drivers satisfy and complete some I/O requests but pass others down the stack. To send an I/O request to another driver—whether that driver is in its own stack or in a different stack—a KMDF driver uses an I/O target. An I/O target is simply a KMDF object (WDFIOTARGET) that represents a target for an I/O request. A KMDF driver uses an I/O target anywhere that a WDM driver uses IoCallDriver.

An I/O target is more than just a pointer to a device object. Because each I/O target is a KMDF object, it supports methods, events, and properties that track the state of the target, format requests in a target-specific way, return information about the target, and enable the driver to be called when the target is removed. In addition, KMDF can synchronize the sending of an I/O request with the state of the target. For example, the sending driver can be notified if the target is deleted and can specify how to handle the request in that situation.

Synchronization and ConcurrencyKMDF drivers benefit from some built-in synchronization support that is not available to WDM drivers. Although this support does not mean that the driver can ignore concurrency and synchronous access to data, KMDF drivers nevertheless require significantly fewer locks and less synchronization code than do WDM drivers.

KMDF provides several synchronization features: An internal callback synchronization lock for most object types. Driver-configurable device-level and queue-level synchronization scope for I/O event callbacks.

September 12, 2006© 2006 Microsoft Corporation. All rights reserved.

Page 16: Porting a Driver from WDM to KMDF · Web viewSeptember 12, 2006 Abstract This paper provides information about how to port drivers that conform to the Microsoft® Windows® Driver

Porting a Driver from WDM to KMDF - 16

Driver-configurable execution level (IRQL) for certain file and I/O event callbacks. Three queue dispatch types. Two types of lock objects.

Callback synchronization lock. The framework implements a callback synchronization lock for each device object and acquires this lock before calling any of the device object callback functions (EvtDeviceXxx). Thus, such routines do not require additional driver-created locks to access the device object’s context areas.

At the driver’s option, the framework can also synchronize the callbacks for deferred procedure call (DPC), timer, queue, work item, and file objects by using a similar object-specific callback synchronization lock.

For interrupt objects, the framework always acquires a spin lock at device interrupt request level (DIRQL) to synchronize calls to the EvtInterruptEnable, EvtInterruptDisable, and EvtInterruptIsr callbacks.

Synchronization Scope. The framework provides driver-configurable synchronization scope for I/O event callback routines. A driver's I/O queues can have device-level, queue-level, or no synchronization.

With device-level synchronization, the framework acquires the device object’s callback synchronization lock before calling an I/O event callback for any queues that are children of the device object and releases the lock when the event callback returns. The I/O event callbacks for all the device object’s queues are therefore synchronized, so that no such routines are called concurrently. With queue-level synchronization, the framework acquires the callback synchronization lock for each queue before it invokes an I/O event callback for that queue. Therefore, the callback functions are synchronized on a per-queue basis. With no synchronization, the framework does not acquire any callback synchronization locks and the driver must perform all its own locking.

Execution Level. By setting the execution level for a driver, device, file, or general object, the driver can ensure that the framework invokes the file and I/O event callbacks for that object at PASSIVE_LEVEL. If the driver chooses this option, the framework invokes the callbacks from a work item if they would otherwise be invoked at DISPATCH_LEVEL.

Queue Dispatch Types. The driver can opt to receive each request from a queue as soon as it arrives (parallel dispatching), only after the driver has completed the previous request (sequential dispatching), or only at the driver’s explicit request (manual dispatching). The dispatch type thus can limit the number of outstanding requests from each queue. It has no effect on whether the framework invokes the I/O event callbacks for the queue concurrently.

Lock Objects. The framework provides two kinds of locks: wait locks (WDFWAITLOCK) and spin locks (WDFSPINLOCK). For both types of locks, the framework implements deadlock detection and tracks lock acquisition history.

Wait locks are PASSIVE_LEVEL synchronization mechanisms that are similar to the WDM KEVENT primitive. They cannot be acquired recursively. If the driver supplies a time-out for a wait lock, it must acquire the lock at IRQL <= APC_LEVEL, which causes the framework to disable asynchronous procedure calls (APCs) on behalf of the driver while the driver holds the lock. If the driver does not supply a time-out, the driver can acquire the lock at IRQL<= DISPATCH_LEVEL.

September 12, 2006© 2006 Microsoft Corporation. All rights reserved.

Page 17: Porting a Driver from WDM to KMDF · Web viewSeptember 12, 2006 Abstract This paper provides information about how to port drivers that conform to the Microsoft® Windows® Driver

Porting a Driver from WDM to KMDF - 17

Spin locks and the functions that create, acquire, and release them are essentially the same in both KMDF and WDM. Remember, however, that a KMDF spin lock has an object context area that the driver can use to store lock-context-specific data.

Note: Even though porting to KMDF can greatly simplify synchronization, remember that synchronization is an inherently difficult part of driver implementation. KMDF synchronization mechanisms interact in subtle ways, and this paper provides only a brief overview. For details, see the white papers titled Architecture of the Kernel-Mode Driver Framework and Sample Drivers for the Kernel-Mode Driver Framework, and the WDK, which are listed in "Resources" at the end of this paper.

Driver InstallationLike WDM drivers, KMDF drivers are installed by using INF files. However, KMDF driver installation requires the framework co-installer that is provided with the KMDF release. The co-installer ensures that a compatible version of KMDF is present on the target system.

Strategies for PortingIn some ways, converting a driver from WDM to KMDF is more reimplementation than porting. Although that might sound daunting, it is neither as difficult nor as time-consuming as you might expect. Most of the WDM driver’s hardware-specific code can remain relatively intact, although it will use some different object types. KMDF defaults replace much of the boilerplate code that a WDM driver requires—particularly for Plug and Play—and KMDF provides built-in support for many tricky aspects of driver implementation, such as I/O cancellation (and the associated race conditions) and system power state transitions.

Furthermore, the KMDF defaults for WMI, Plug and Play, power management, and I/O requests enable you to code and test incrementally, starting with a basic driver that the system can load and working iteratively to add features.

To see the differences between KMDF and WDM drivers, look closely at the samples that are provided with KMDF. Most of the KMDF samples are ports of the similarly named WDM drivers and demonstrate how implementation of common driver tasks differs in the two models.

WDM Driver AnalysisRegardless of the type of device and driver involved, the single most important issue in porting a driver is to understand the I/O flow through the driver. Before you start writing code, carefully analyze the existing WDM driver. You should be able to answer these questions:

How many device objects does the driver require, and what driver roles (FDO, PDO, filter DO) do they represent? In nearly all cases, the KMDF driver will use the same type and number of device objects as the WDM driver. Which I/O requests must the driver support? How many queues does the driver require for those requests? What are the characteristics of those queues? Which aspects of I/O processing can take place concurrently, and which must be serialized? Which I/O requests does the driver complete, and which does it pass down the stack?

September 12, 2006© 2006 Microsoft Corporation. All rights reserved.

Page 18: Porting a Driver from WDM to KMDF · Web viewSeptember 12, 2006 Abstract This paper provides information about how to port drivers that conform to the Microsoft® Windows® Driver

Porting a Driver from WDM to KMDF - 18

The answers to these questions determine how the core of the KMDF driver is structured, where and when the I/O processing takes place, what type of synchronization the driver requires, and which KMDF objects the driver must create to perform I/O.

If the driver supports hardware, you must also thoroughly understand the device: Does the device generate interrupts? Which DMA model (if any) does the hardware support? Does the driver manage power policy for the device stack?

Finally, if the driver supports WMI, you must understand how to gather the data it exports and thus which WMI callbacks the driver requires.

Do not underestimate the value of such a driver analysis. It can be a valuable tool in creating an efficient and streamlined KMDF driver because it forces you to determine exactly which callback functions the driver requires and what types of synchronization are most appropriate. Furthermore, while you are porting, do not be surprised if you run across previously undiscovered bugs in the existing WDM driver.

Steps in PortingDepending on the type of driver, porting usually involves the following steps:

Port the DriverEntry routine and add code to create the WDFDRIVER object. Port the AddDevice routine to an EvtDriverDeviceAdd callback, and add code to create the WDFDEVICE objects. Add support for Plug and Play and power management. Add support for interrupts if the driver supports interrupt handling. Add support for I/O queues and I/O event callbacks. Add support for DMA, if the device performs DMA. Port WMI code. Port code to handle requests that KMDF does not support. Revise the INF that installs the driver.

After you port the DriverEntry routine, create the EvtDriverDeviceAdd callback, and revise the interrupt-handling code, you can perform the other steps incrementally and in any order, testing and debugging after each incremental addition. For example, you might want to start by implementing the I/O queues and using the KMDF defaults for Plug and Play and power management. After you have debugged the basic I/O support, you might add support for more extensive Plug and Play and power management requests.

The next few sections describe in detail how to accomplish each of these steps. Except as noted, the information presented here applies to all types of drivers (PDO, FDO, and filter DO). However, if you are porting a bus driver (PDO), you will also need to port the device enumeration code, as described in “Child Device Enumeration (PDOs Only),” later in this paper.

For reference information on how the various WDF objects, methods, and event callback functions map to common WDM objects and functions, see the companion white paper titled Summary of KMDF and WDM Equivalents.

September 12, 2006© 2006 Microsoft Corporation. All rights reserved.

Page 19: Porting a Driver from WDM to KMDF · Web viewSeptember 12, 2006 Abstract This paper provides information about how to port drivers that conform to the Microsoft® Windows® Driver

Porting a Driver from WDM to KMDF - 19

DriverEntry RoutineIn both WDM and KMDF drivers, the DriverEntry function is the primary entry point. The function prototype is the same in both models.

In a WDM driver, the system calls DriverEntry when the driver is first loaded into memory. DriverEntry sets a pointer to the driver’s AddDevice routine in the DriverExtension->AddDevice field of the DRIVER_OBJECT structure, sets pointers to its I/O dispatch routines in the MajorFunction array of the DRIVER_OBJECT structure, and then returns.

In a KMDF driver, the system calls the framework’s internal FxDriverEntry function upon loading the driver. This internal function initializes the framework and then calls the driver’s DriverEntry function. DriverEntry sets a pointer to the driver’s EvtDriverDeviceAdd callback and calls back to the framework to create the WDFDRIVER object, as the following example shows:NTSTATUSDriverEntry( IN PDRIVER_OBJECT DriverObject IN PUNICODE_STRING RegistryPath ){ WDF_DRIVER_CONFIG_INIT( &config, ToasterEvtDeviceAdd ); status = WdfDriverCreate( DriverObject RegistryPath WDF_NO_OBJECT_ATTRIBUTES &config WDF_NO_HANDLE );

return STATUS_SUCCESS;}

DriverEntry also initializes any global data or resources that the driver requires, such as creating a lookaside list or initializing tracing. Note that although WdfDriverCreate returns a handle to the WDFDRIVER object, the driver does not retain this handle, just as a WDM driver might not retain the DRIVER_OBJECT pointer that was passed to its DriverEntry routine. The reason is the same: only a few drivers use the pointer to the driver object.

EvtDriverDeviceAdd CallbackEvery KMDF driver that supports Plug and Play must have an EvtDriverDeviceAdd callback, which is the functional equivalent of a WDM driver’s AddDevice function. When the system enumerates one of the driver’s devices, it calls the framework’s internal AddDevice function, which in turn invokes the driver’s EvtDriverDeviceAdd callback. EvtDriverDeviceAdd is responsible for creating and initializing a device object and related resources.

A WDM AddDevice function creates the device object, creates the device interfaces, and initializes WMI but also initializes numerous variables in the driver’s device extension. WDM drivers typically defer the creation of I/O queues and the interrupt object until the DispatchPnP function is called to handle an IRP_MN_START_DEVICE request.

The KMDF driver’s EvtDriverDeviceAdd callback creates a WDFDEVICE object to represent the device that has just been enumerated. It also performs numerous

September 12, 2006© 2006 Microsoft Corporation. All rights reserved.

Page 20: Porting a Driver from WDM to KMDF · Web viewSeptember 12, 2006 Abstract This paper provides information about how to port drivers that conform to the Microsoft® Windows® Driver

Porting a Driver from WDM to KMDF - 20

additional initialization tasks to provide the framework with the information that it requires to set up its own internal structures and the underlying WDM structures.

As a result, for most KMDF drivers the EvtDriverDeviceAdd callback is significantly longer than the corresponding WDM AddDevice function. In a KMDF driver, nearly all of the device’s initialization code is in the EvtDriverDeviceAdd function, but in the WDM version, the initialization code tends to be spread out through multiple functions in the driver.

The code in EvtDriverDeviceAdd thus appears in this order:1. Fill in the WDFDEVICE_INIT structure, which supplies information that is used

to create the device object.

2. Set up the device object’s context area, which is analogous to the WDM device extension.

3. Create the device object.

4. Perform additional initialization and start-up tasks, such as creating I/O queues and interrupt objects.

If the driver controls a bus, it typically creates multiple device objects: an FDO for its role as the function driver for the bus itself and a PDO for each child device that is attached to the bus. The framework calls the driver’s EvtDriverDeviceAdd function when the system enumerates the bus. The driver itself then enumerates its child devices and creates PDOs to represent them. KMDF supports both static and dynamic enumeration of child devices. It also includes additional PDO-specific features.

The following sections describe each of the major tasks of the EvtDriverDeviceAdd callback.

WDFDEVICE_INIT StructureThe framework calls EvtDriverDeviceAdd with a pointer to an opaque WDFDEVICE_INIT structure. The driver calls WdfDeviceInitXxx functions to fill in this structure with information about the device and driver. The framework uses this information later when it creates the WDFDEVICE object and the underlying WDM DEVICE_OBJECT. For example, some WdfDeviceInitXxx functions record information in the WDFDEVICE_INIT structure that the framework uses to set flags in the WDM DEVICE_OBJECT.

For any device object, the driver might call WdfDeviceInitXxx functions to: Set device characteristics. Set I/O type. Create a context area for I/O requests. 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 (PDOs Only),” later in this paper.

Initialization for an FDOBy 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

September 12, 2006© 2006 Microsoft Corporation. All rights reserved.

Page 21: Porting a Driver from WDM to KMDF · Web viewSeptember 12, 2006 Abstract This paper provides information about how to port drivers that conform to the Microsoft® Windows® Driver

Porting a Driver from WDM to KMDF - 21

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. In a WDM driver, the FDO alters the requirements as the Plug and Play IRP_MN_FILTER_RESOURCE_REQUIREMENTS request travels down and then back up the stack. A KMDF driver instead implements the EvtDeviceFilterRemoveResourceRequirements and EvtDeviceFilterAddResourceRequirements callbacks and registers them by calling WdfFdoInitSetEventCallbacks.

If the driver adds resources to the requirements list, it must remove the added resources from the final list of assigned resources before the device starts. A WDM driver does this during processing of the Plug and Play IRP_MN_START_DEVICE request, whereas a KMDF driver supplies an EvtDeviceRemoveAddedResources callback.

The driver might also call other WdfFdoInitXxx methods, which enable the driver to retrieve device properties, get a pointer to the WDM PDO for the device stack, access the registry key for the device, and perform other FDO-specific tasks.

Initialization for a Filter DOThe driver must call WdfFdoInitSetFilter to notify the framework that the device object represents a filter. When an I/O request arrives that the filter DO does not handle, the framework passes the request down to the next lower driver. For a filter DO, the driver can call the same WdfDeviceInitXxx methods as for an FDO.

Device Object Context AreaDrivers typically require storage that is associated with a device object to maintain pointers and object-specific data. In a WDM driver, the DeviceExtension field of the DEVICE_OBJECT structure provides such storage. In a KMDF driver, the object context area of the WDFDEVICE object serves the same purpose.

The object context area, like the DeviceExtension field, is allocated from nonpaged pool and has a driver-defined layout. When the KMDF driver creates the device object, it initializes the context area and specifies its size and type as described in “Object Context Area,” earlier in this paper. The driver can create additional context areas after the device object has been created. When the framework deletes the object, it deletes the context areas, too.

The following code snippet from the KMDF sample Toaster.h header file declares the object context type and accessor function for an FDO://// The device extension for the device object//typedef struct _FDO_DATA{ WDFWMIINSTANCE WmiDeviceArrivalEvent; BOOLEAN WmiPowerDeviceEnableRegistered; TOASTER_INTERFACE_STANDARD BusInterface;

} FDO_DATA, *PFDO_DATA;

WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(FDO_DATA, ToasterFdoGetData)

The driver defines the context area FDO_DATA to store the handle to a WMI event, a Boolean, and a pointer to the device interface. It then calls WDF_DECLARE_CONTEXT_TYPE_WITH_NAME to declare FDO_DATA as the

September 12, 2006© 2006 Microsoft Corporation. All rights reserved.

Page 22: Porting a Driver from WDM to KMDF · Web viewSeptember 12, 2006 Abstract This paper provides information about how to port drivers that conform to the Microsoft® Windows® Driver

Porting a Driver from WDM to KMDF - 22

type of the context area and to assign a name (ToasterFdoGetData) to the accessor function. Any time the driver requires data that is stored in the context area, it calls the accessor function.

Compare this with the device extension for the Featured2 WDM sample driver, which has similar features:typedef struct _FDO_DATA{ ULONG Signature; PDEVICE_OBJECT Self; PDEVICE_OBJECT UnderlyingPDO; PDEVICE_OBJECT NextLowerDriver; DEVICE_PNP_STATE DevicePnPState; DEVICE_PNP_STATE PreviousPnPState; UNICODE_STRING InterfaceName; QUEUE_STATE QueueState; LIST_ENTRY NewRequestsQueue; KSPIN_LOCK QueueLock; KEVENT RemoveEvent; KEVENT StopEvent; ULONG OutstandingIO; BOOLEAN DontDisplayInUI; SYSTEM_POWER_STATE SystemPowerState; DEVICE_POWER_STATE DevicePowerState; WMILIB_CONTEXT WmiLibInfo; TOASTER_WMI_STD_DATA StdDeviceData; DEVICE_CAPABILITIES DeviceCaps; PIRP PendingSIrp; BOOLEAN AllowIdleDetectionRegistration; BOOLEAN AllowWakeArming; WAKESTATE WakeState; PIRP WakeIrp; KEVENT WakeCompletedEvent; KEVENT WakeDisableEnableLock;} FDO_DATA, *PFDO_DATA;

The WDM driver uses the device extension to store pointers to several device objects, information about Plug and Play and power state and capabilities, variables that are required to manage the driver’s I/O queue, and pointers to pending system power IRPs. Consequently, the AddDevice function contains many lines of code to initialize the data in the device extension. The device extension in the WDM driver contains a wide variety of information about the device because it is typically the only context area that is available to the driver. For example, WDM drivers typically store DPC state and interrupt state in the device extension.

The KMDF driver stores almost none of this information because the framework maintains it on behalf of the driver and provides methods that the driver can call to retrieve such information when necessary. Furthermore, a KMDF driver can use an object’s context area to store object-specific information. For example, information about a particular DPC object can be stored in the DPC object’s context area instead of with the device object.

Device Object CreationA WDM driver creates a DEVICE_OBJECT structure to represent each device object and attaches the device object to the Plug and Play device stack. KMDF drivers also create device objects, which are referred to by using WDFDEVICE handles.

September 12, 2006© 2006 Microsoft Corporation. All rights reserved.

Page 23: Porting a Driver from WDM to KMDF · Web viewSeptember 12, 2006 Abstract This paper provides information about how to port drivers that conform to the Microsoft® Windows® Driver

Porting a Driver from WDM to KMDF - 23

After the KMDF driver calls the required initialization methods, it sets attributes for the device object (typically, the size and type of the context area) and then calls WdfDeviceCreate to create the device object. WdfDeviceCreate creates a WDFDEVICE object and an underlying WDM DEVICE_OBJECT, attaches the WDM DEVICE_OBJECT to the device stack, and returns a handle to the WDFDEVICE object.

Additional EvtDriverDeviceAdd TasksAfter the KMDF driver creates the device object it should:

Register I/O callbacks and create I/O queues for the device object. Create device interfaces. Set device idle policy and wake settings if the device object owns power policy. Create an interrupt object if the hardware supports interrupts. Initialize WMI.

A KMDF driver should set up the I/O queues and create the interrupt object in the EvtDriverDeviceAdd callback, immediately after creating the device object. The framework connects the interrupt object and starts the queues at the appropriate time later, during start-device processing.

Child Device Enumeration (PDOs Only)A driver that controls a bus typically creates multiple device objects: an FDO for its role as the function driver for the bus itself and a PDO for each child device that is attached to the bus. KMDF supports both static and dynamic enumeration of child devices. It also includes additional PDO-specific features.

Static and Dynamic EnumerationThe framework invokes the driver’s EvtDriverDeviceAdd function when the Plug and Play manager enumerates the bus. EvtDriverDeviceAdd creates an FDO for the bus, and then enumerates the child devices and creates a PDO for each one. The driver can enumerate the child devices either statically or dynamically.

A WDM driver enumerates its children in response to an IRP_MN_QUERY_DEVICE_RELATIONS request with a relation type of BusRelations. For a KMDF driver, however, the framework intercepts such requests and does not pass them on to the driver. Instead, the driver supplies information about its children in a WDFCHILDLIST object, and the framework reports information from this object to satisfy the device-relations request.

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.

If the driver performs dynamic enumeration, it must at a minimum: Call WdfFdoInitSetDefaultChildListConfig from EvtDriverDeviceAdd to configure the child list and register the EvtChildListXxx callbacks before it creates the FDO for the bus. Enumerate the child devices after creating the FDO and use WdfChildListXxx methods to populate the child list. Implement EvtChildListCreateDevice, which creates the PDO for a child device. The framework passes a pointer to a WDFDEVICE_INIT structure when

September 12, 2006© 2006 Microsoft Corporation. All rights reserved.

Page 24: Porting a Driver from WDM to KMDF · Web viewSeptember 12, 2006 Abstract This paper provides information about how to port drivers that conform to the Microsoft® Windows® Driver

Porting a Driver from WDM to KMDF - 24

it invokes this callback. The callback fills in the structure and calls WdfDeviceCreate to create the child PDO. Implement other EvtChildListXxx callbacks as required to support the device’s children.

A driver that performs dynamic enumeration uses WdfChildListXxx methods to change its child list.

If the driver performs static enumeration, it is not required to implement any EvtChildListXxx callback functions. Instead, its EvtDriverDeviceAdd callback must:

Enumerate the child devices after the driver creates the FDO. Call WdfPdoInitAllocate to obtain a pointer to a WDFDEVICE_INIT structure for each child PDO. Initialize the WDFDEVICE_INIT structure appropriately for each child and create the child PDO by calling WdfDeviceCreate. Update the default child list by calling WdfFdoAddStaticChild.

In general, drivers that perform static enumeration do not change their child lists. However, if changes are required, a driver uses WdfFdoXxx methods to change a static child list.

PDO-Specific InitializationCertain callback functions apply only to device objects that represent PDOs. When the driver initializes the device object, it registers the corresponding callbacks. PDOs respond to queries about device resources and resource requirements, requests to lock or eject the device, and requests to enable and disable the device wake signal.

In WDM drivers, these requests arrive as minor IRP codes in an IRP_MJ_PNP or IRP_MJ_POWER request. KMDF drivers handle them by implementing callbacks and registering the callbacks during device object initialization by calling WdfPdoInitSetEventCallbacks. Table 4 lists the PDO-specific callbacks.Table 4. PDO-Specific CallbacksKMDF callback WDM IRPEvtDeviceResourcesQuery IRP_MN_QUERY_RESOURCEEvtDeviceResourceRequirementsQuery

IRP_MN_QUERY_RESOURCE_REQUIREMENTS

EvtDeviceEject IRP_MN_EJECTEvtDeviceSetLock IRP_MN_SET_LOCKEvtDeviceEnableWakeAtBus IRP_MN_WAIT_WAKEEvtDeviceDisableWakeAtBus IRP_MN_WAIT_WAKE

Additional WdfPdoInitXxx methods enable the driver to specify device-specific data, such as device IDs.

Plug and Play and Power ManagementKMDF implements intelligent defaults for Plug and Play and power management, so that simple drivers (including most filter drivers) do not require additional code to meet the basic requirements for Plug and Play. The framework automatically creates and manages PnP, power management, and power policy state machines. By default:

The FDO owns power policy for the device.

September 12, 2006© 2006 Microsoft Corporation. All rights reserved.

Page 25: Porting a Driver from WDM to KMDF · Web viewSeptember 12, 2006 Abstract This paper provides information about how to port drivers that conform to the Microsoft® Windows® Driver

Porting a Driver from WDM to KMDF - 25

Only the EvtDriverDeviceAdd callback is required; all other PnP and power management callbacks are optional. A driver implements other callbacks to support device-specific features. The framework implements power management for all WDFQUEUE objects, so that by default requests are dispatched from the queue to the driver’s I/O event callbacks only when the device hardware is available (that is, in the D0 state).

If the device does not support interrupts, map memory, or require initialization or deinitialization when power transitions occur, the KMDF driver requires only the EvtDriverDeviceAdd callback. The framework’s defaults are designed to do the right thing, so that the device just works.

Power Policy OwnershipOne driver in each device stack owns power policy for the device and therefore enables certain power policy features and responds to certain power management requests. For example, the power policy owner controls the idle time-out settings for its device.

WDM drivers handle power policy by informal mutual agreement: each driver/device object passes power IRPs down the stack, and the power policy owner handles them as appropriate.

KMDF formalizes policy ownership by setting the FDO as the default power policy owner and defining policy-related event callbacks. A driver registers the event callbacks only for the device object that owns power policy. To override the default, call WdfDeviceInitSetPowerPolicyOwnership before creating the device object.

The power policy event callbacks control wakeup. If the device supports a wake signal and the WDM driver enables and disables wake-up, the KMDF driver should implement one or more of the following:

EvtDeviceArmWakeFromS0 EvtDeviceDisarmWakeFromS0 EvtDeviceWakeFromS0Triggered EvtDeviceArmWakeFromSx EvtDeviceDisarmWakeFromSx EvtDeviceWakeFromSxTriggered

For more information about these callbacks, see the WDK documentation and the white paper titled Introduction to Plug and Play and Power Management in the Windows Driver Foundation, which is listed in "Resources" at the end of this paper.

Event Callbacks for Plug and Play and Power IRPsA WDM driver handles a sequence of IRP_MJ_PNP and IRP_MJ_POWER requests for various minor IRP codes. For each request, the driver must determine which tasks to perform based on the current state of the system, the driver, and the device.

For KMDF drivers, the framework keeps track of state information by using a Plug and Play state machine, a power state machine, and a power policy state machine and defining driver event callback functions that correspond to the tasks that a driver performs at each possible state transition. The driver implements the callback functions that are appropriate for the operation of its device. When the framework

September 12, 2006© 2006 Microsoft Corporation. All rights reserved.

Page 26: Porting a Driver from WDM to KMDF · Web viewSeptember 12, 2006 Abstract This paper provides information about how to port drivers that conform to the Microsoft® Windows® Driver

Porting a Driver from WDM to KMDF - 26

receives an IRP_MJ_PNP or IRP_MJ_POWER request, it invokes the driver callback functions that correspond to the current state.

The framework calls multiple KMDF callback functions for many minor IRP codes, and the same KMDF callback often applies to several minor IRP codes. Each callback function performs a specific task or enables the driver to manipulate its device at a specific state. Most of the callback functions are paired: one function performs a task when the device is inserted, enumerated, or powered up; and the other undoes that task when the device is stopped, powered down, or removed.

For example, a driver typically must perform certain tasks when its device enters and exits the working state. A WDM driver might have to include code to perform these same tasks in response to several different Plug and Play and power IRPs: IRP_MN_START_DEVICE, IRP_MN_SET_POWER, IRP_MN_SURPRISE_REMOVAL, IRP_MN_REMOVE_DEVICE, and IRP_MN_STOP_DEVICE. A KMDF driver instead implements an EvtDeviceD0Entry callback function and an EvtDeviceD0Exit callback function. The framework calls these functions immediately after the device enters the working state and before the device leaves the working state, regardless of the underlying IRP or sequence of IRPs.

A driver can find out the state of its device at any time by calling WdfDeviceGetDevicePnPState. This method returns an enumerator that describes the state. For example, the state WdfDevStatePnpStartedRemoving indicates that the device is currently operating but that the framework has received an IRP_MN_REMOVE_DEVICE request, which is currently in progress.

The following sections show in detail the sequence of callbacks that the framework invokes when a device is enumerated or powered up, powered down or removed, and surprise-removed. For a complete list of the callbacks that correspond to each minor Plug and Play and power IRP code, see the companion white paper titled Summary of KMDF and WDM Equivalents, which is listed in "Resources" at the end of this paper.

Device Enumeration and Power-UpWhen a device is inserted or enumerated, and any time it returns to the working state from a lower-powered state, the framework invokes Plug and Play and power event callbacks in a defined order. The following sections describe that order, which varies slightly for PDOs, FDOs, and filter DOs.

September 12, 2006© 2006 Microsoft Corporation. All rights reserved.

Page 27: Porting a Driver from WDM to KMDF · Web viewSeptember 12, 2006 Abstract This paper provides information about how to port drivers that conform to the Microsoft® Windows® Driver

Porting a Driver from WDM to KMDF - 27

Power-up Sequence for a Function or Filter Device ObjectFigure 1 shows the callbacks for an FDO or filter DO that is involved in bringing a device to the fully operational state, starting from the Device Inserted state at the bottom of the figure.

Device Operational

Notify driver of state change

Enable self-managed I/O, if driver supports it

Enable DMA, if driver supports it

Disarm wake signal, if it was armed

Connect interrupts

Change resource requirements

Create device object

Restart from here if device is in low-power state

Restart from here if rebalancing resources

Device Inserted

Start power-managed queues

Prepare hardware for power EvtDevicePrepareHardware

EvtDeviceD0Entry

EvtDeviceD0EntryPostInterruptsEnabledEvtInterruptEnable

EvtDeviceDisarmWakeFromSxEvtDeviceDisarmWakeFromS0 (called only during power-up; not called during resource rebalance)

EvtDmaEnablerSelfManagedIoStartEvtDmaEnablerEnableEvtDmaEnablerFill

EvtDeviceRemoveAddedResoucesEvtDeviceFilterAddResourceRequirementsEvtDeviceFilterRemoveResourceRequirements

EvtDriverDeviceAdd

EvtIoResume(called only if EvtIoStop was previously called during power-down)

EvtDeviceSelfManagedIoInitorEvtDeviceSelfManagedIoRestart

Figure 1. Device enumeration and power-up sequence for FDO or filter DO

The broad horizontal lines mark the steps that are involved in starting a device. The column on the left side of the figure describes the step, and the column on the right lists the event callbacks that accomplish it.

At the bottom of the figure, the device is not present on the system. When the user inserts the device, the framework begins by calling the driver’s EvtDriverDeviceAdd callback so that the driver can create a device object to represent the device. The framework continues calling the driver’s callback routines by progressing up through the sequence until the device is operational. Remember that the framework invokes the event callbacks in bottom-up order as shown in the figure, so EvtDeviceFilterRemoveResourceRequirements is called before EvtDeviceFilterAddResourceRequirements and so forth.

September 12, 2006© 2006 Microsoft Corporation. All rights reserved.

Page 28: Porting a Driver from WDM to KMDF · Web viewSeptember 12, 2006 Abstract This paper provides information about how to port drivers that conform to the Microsoft® Windows® Driver

Porting a Driver from WDM to KMDF - 28

If the device was stopped to rebalance resources or was physically present but in a low-power state, not all of the steps are required, as the figure shows.

Power-Up Sequence for a Physical Device ObjectFigure 2 shows the callbacks for a bus driver (PDO) that is involved in bringing a device to the fully operational state, starting from the Device Inserted state at the bottom of the figure.

Device Operational

Notify driver of state change

Enable self-managed I/O, if driver supports it

Enable DMA, if driver supports it

Disable wake signal, if it was enabled

Connect interrupts

Enumerate child devices

Create device object

Restart from here if device is in low-power state

Restart from here if rebalancing resources or if device remained physically present after logical removal

Device Inserted

Start power-managed queues

Prepare hardware for power

EvtChildListCreateDevice

EvtDevicePrepareHardware

EvtDeviceD0Entry

EvtDeviceD0EntryPostInterruptsEnabledEvtInterruptEnable

EvtDmaEnablerSelfManagedIoStartEvtDmaEnablerEnableEvtDmaEnablerFill

EvtDriverDeviceAdd

EvtIoResume(called only if EvtIoStop was called during power-down)

EvtDeviceSelfManagedIoInit or EvtDeviceSelfManagedIoRestart

EvtDeviceResourceRequirementsQueryEvtDeviceResourcesQueryReport resource requirements

EvtDeviceEnableWakeAtBus

EvtDeviceDisableWakeAtBus(called only during power-up; not called during resource rebalance)

Enable wake signal, if a wake request from the previous power-down is still pending

Figure 2. Device addition/power-up sequence for PDO

September 12, 2006© 2006 Microsoft Corporation. All rights reserved.

Page 29: Porting a Driver from WDM to KMDF · Web viewSeptember 12, 2006 Abstract This paper provides information about how to port drivers that conform to the Microsoft® Windows® Driver

Porting a Driver from WDM to KMDF - 29

The framework does not physically delete a PDO until the corresponding device is physically removed from the system. For example, if a user disables the device in Device Manager but does not physically remove it, the framework retains its device object. Thus, the three steps at the bottom of the figure occur only during Plug and Play enumeration—that is, during initial boot or when the user inserts a new device.

If the device was previously disabled but not physically removed, the framework starts by calling the EvtDevicePrepareHardware callback.

Device Power-Down and RemovalThe framework can remove a device from the operational state for several reasons:

To put the device in a low-power state because it is idle or the system is entering a sleep state. To rebalance resources. To remove the device after the user has requested an orderly removal. To disable the device in response to the user’s request in Device Manager.

As in enumeration and power-up, the sequence of callbacks depends on the driver’s role in device management.

September 12, 2006© 2006 Microsoft Corporation. All rights reserved.

Page 30: Porting a Driver from WDM to KMDF · Web viewSeptember 12, 2006 Abstract This paper provides information about how to port drivers that conform to the Microsoft® Windows® Driver

Porting a Driver from WDM to KMDF - 30

Power-Down and Removal Sequence for a Function or Filter Device ObjectFigure 3 shows the sequence of callbacks that are involved in power-down and removal for an FDO or filter DO. The sequence starts at the top of the figure with an operational device that is in the working power state (D0).

Device Operational

Notify driver of state change

Suspend self-managed I/O, if driver supports it

Disable DMA, if driver supports it

Arm wake signal, if driver supports it

Disconnect interrupts

Flush I/O buffers, if driver supports self-managed I/O

Delete device object’s context area

Stop here if transitioning to low-power state

Stop here if rebalancing resources

Device Removed

Stop power-managed queues

Release hardware EvtDeviceReleaseHardware

EvtDeviceD0Exit

EvtDeviceD0ExitPreInterruptsDisabledEvtInterruptDisable

EvtDeviceArmWakeFromSxEvtDeviceArmWakeFromS0(called only during transitions to low power, not during resource rebalance or device removal)

EvtDmaEnablerSelfManagedIoStopEvtDmaEnablerDisableEvtDmaEnablerFlush

EvtDeviceSelfManagedIoFlush

EvtCleanupContextEvtDestroyContext

EvtIoStop

EvtDeviceSelfManagedIoSuspend

Clean up I/O buffers, if driver supports self-managed I/O EvtDeviceSelfManagedIoCleanup

Purge non-power-managed queues

Purge power-managed queues EvtIoStop

EvtIoStop

Figure 3. Device power-down and orderly removal sequence for FDO and Filter DO

As the figure shows, the KMDF power-down and removal sequence involves calling the corresponding "undo" callbacks in the reverse order in which the framework called the functions that are involved in making the device operational. The framework deletes the device object after it deletes the device object context area.

September 12, 2006© 2006 Microsoft Corporation. All rights reserved.

Page 31: Porting a Driver from WDM to KMDF · Web viewSeptember 12, 2006 Abstract This paper provides information about how to port drivers that conform to the Microsoft® Windows® Driver

Porting a Driver from WDM to KMDF - 31

Power-Down and Removal Sequence for a Physical Device ObjectFigure 4 shows the callbacks that are involved in power-down and removal for a PDO.

Device Operational

Notify driver of state change

Suspend self-managed I/O, if driver supports it

Disable DMA, if driver supports it

Enable wake signal, if driver supports it

Disconnect interrupts

Flush I/O buffers, if driver supports self-managed I/O

Delete device object’s context area

Stop here if transitioning to low-power state

Stop here if rebalancing resources

Stop here if device is still physically present

Stop power-managed queues

Release hardware EvtDeviceReleaseHardware

EvtDeviceD0Exit

EvtDeviceD0ExitPreInterruptsDisabledEvtInterruptDisable

EvtDmaEnablerSelfManagedIoStopEvtDmaEnablerDisableEvtDmaEnablerFlush

EvtDeviceSelfManagedIoFlush

EvtCleanupContextEvtDestroyContext

EvtIoStop

EvtDeviceSelfManagedIoSuspend

EvtDeviceEnableWakeAtBus(called only during transitions to low power, not during resource rebalance or device removal)

Disable wake signal, if it is enabled EvtDeviceDisableWakeAtBus(called only during device removal)

Device Physically Removed

EvtDeviceSelfManagedIoCleanupClean up I/O buffers, if driver supports self-managed I/O

Purge power-managed I/O queues

Purge non-power-managed I/O queues

EvtIoStop

EvtIoStop

Figure 4. Device power-down and orderly removal sequence for PDO

September 12, 2006© 2006 Microsoft Corporation. All rights reserved.

Page 32: Porting a Driver from WDM to KMDF · Web viewSeptember 12, 2006 Abstract This paper provides information about how to port drivers that conform to the Microsoft® Windows® Driver

Porting a Driver from WDM to KMDF - 32

The framework does not delete the PDO until the device is physically removed from the system. For example, if a user disables the device in Device Manager or stops it in the Safely Remove Hardware utility but does not physically remove the device, the framework retains the PDO. If the device is later re-enabled, the framework uses the same PDO and begins the startup sequence by calling the EvtDevicePrepareHardware callback, as previously shown in Figure 2.

Surprise-Removal SequenceIf the user removes the device without warning, by simply unplugging it without using Device Manager or the Safely Remove Hardware utility, the device is considered "surprise-removed." When this occurs, the framework follows a slightly different removal sequence. It also follows the surprise-removal sequence if another driver calls IoInvalidateDeviceState on the device, even if the device is still physically present.

In the surprise-removal sequence, the framework calls the EvtDeviceSurpriseRemoval callback before calling any of the other callbacks in the removal sequence. When the sequence is complete, the framework destroys the device object.

Drivers for all removable devices must ensure that the callbacks in both the shutdown and startup paths can handle failure, particularly failures that are caused by the removal of the hardware. Any attempts to access the hardware should not wait indefinitely, but should be subject to time-outs or a watchdog timer.

September 12, 2006© 2006 Microsoft Corporation. All rights reserved.

Page 33: Porting a Driver from WDM to KMDF · Web viewSeptember 12, 2006 Abstract This paper provides information about how to port drivers that conform to the Microsoft® Windows® Driver

Porting a Driver from WDM to KMDF - 33

Figure 5 shows the surprise-removal sequence.

Device Removed

Notify driver of state change*

Suspend self-managed I/O*

Disable DMA, if driver supports it*

Disconnect interrupts*

Flush and clean up I/O buffers, if driver supports self-managed I/O

Delete device object’s context area

Removal Processing Complete

Stop power-managed queues*

Release hardware EvtDeviceReleaseHardware

EvtDeviceD0Exit

EvtDeviceD0ExitPreInterruptsDisabledEvtInterruptDisable

EvtDmaEnablerSelfManagedIoStopEvtDmaEnablerDisableEvtDmaEnablerFlush

EvtDeviceSelfManagedIoFlush

EvtCleanupContextEvtDestroyContext

EvtIoStop

EvtDeviceSelfManagedIoSuspend

Notify driver that device has been surprise-removed EvtDeviceSurpriseRemoval

EvtDeviceSelfManagedIoCleanupClean up I/O buffers, if driver supports self-managed I/O

Purge non-power-managed queues EvtIoStop

Purge power-managed queues EvtIoStop

*Called only if the device was in the working state at removal

Figure 5. Surprise-removal sequence

If the device was not in the working state when it was removed, the framework calls the EvtDeviceReleaseHardware event callback immediately after EvtDeviceSurpriseRemoval. It omits the intervening steps, which were already performed when the device exited from the working state.

InterruptsThe code to support and service interrupts is similar in KMDF and WDM drivers. The primary difference is that a KMDF driver creates the WDFINTERRUPT object and registers its interrupt service routine (ISR) callback by calling WdfInterruptCreate from its EvtDriverDeviceAdd callback; a WDM driver creates a KINTERRUPT structure and connects it during IRP_MN_START_DEVICE processing.

The EvtInterruptIsr callback in a KMDF driver performs the same tasks as the WDM driver’s InterruptService routine. The EvtInterruptIsr callback calls

September 12, 2006© 2006 Microsoft Corporation. All rights reserved.

Page 34: Porting a Driver from WDM to KMDF · Web viewSeptember 12, 2006 Abstract This paper provides information about how to port drivers that conform to the Microsoft® Windows® Driver

Porting a Driver from WDM to KMDF - 34

WdfInterruptQueueDpcForIsr to queue the EvtInterruptDpc callback for later processing at DISPATCH_LEVEL. In response, the framework adds a DPC object to the system queue that runs this callback.

KMDF drivers can also implement additional interrupt-related callback functions: The EvtInterruptEnable and EvtInterruptDisable callback functions enable and disable the interrupt in the hardware. The EvtDeviceD0EntryPostInterruptsEnabled and EvtDeviceD0ExitPreInterruptsDisabled callback functions perform device-specific operations that are required after the driver has enabled the device's hardware interrupts and before it disables them. The EvtInterruptSynchronize event callback function performs actions at DIRQL that must be synchronized with the EvtInterruptIsr callback. It is analogous to a WDM driver’s SynchCritSection routine.

For Windows Vista and later releases, KMDF supports message signaled interrupts (MSIs). If the device generates MSI messages, the driver should create a WDFINTERRUPT object for each message and implement event callback functions accordingly. If the system cannot assign all of the messages that the device can support, it will assign only one message to the device. The extra interrupt objects will not be used, and their callback functions will not be invoked.

I/O Queues and I/O RequestsKMDF drivers handle I/O requests by creating one or more queues and associating one or more I/O event callback functions with each queue. To port a WDM driver’s I/O handling code to KMDF:

Create I/O queues in the EvtDriverDeviceAdd function. Port I/O dispatch routines to I/O event callbacks. Revise code that handles completed requests. Revise code that handles canceled requests. Revise code that forwards requests. Revise code that issues I/O requests.

Create I/O QueuesKMDF drivers create queues and register I/O event callbacks in the EvtDriverDeviceAdd callback. By default, each I/O queue object is the child of a device object. The KMDF driver can configure the following for each queue:

Which I/O request types are directed to the queue. Whether requests are dispatched in parallel (as soon as they arrive), sequentially (one at a time), or manually (upon driver request). Whether I/O event callback routines are called concurrently or serially. Whether the framework or the driver manages the queue through system and device power transitions.

Like a WDM driver, a KMDF driver can create any number of queues. However, a KMDF queue can be configured for one or more specific request types, for which the driver supplies an I/O event callback function.

One queue for each device object can be configured as a default queue, into which the framework places requests for which the driver has not specifically configured

September 12, 2006© 2006 Microsoft Corporation. All rights reserved.

Page 35: Porting a Driver from WDM to KMDF · Web viewSeptember 12, 2006 Abstract This paper provides information about how to port drivers that conform to the Microsoft® Windows® Driver

Porting a Driver from WDM to KMDF - 35

any other queue. If the device object has a default queue and one or more other queues, the framework queues requests of the specified types to the correspondingly configured queues and queues all other requests to the default queue. If the device object has no default queue, the framework queues only the specified request types to the configured queues and, for an FDO or PDO, fails all other requests. (For a filter DO, the framework passes all other requests to the next lower driver.)

A KMDF driver can also create internal queues, into which only the driver—not the framework—places requests. The driver does not configure such an internal queue for any specific request type because the driver alone determines which requests to place in the queue. Typically drivers use such queues for pending requests and configure them for manual dispatching.

The following sample, from the Featured Toaster function driver, shows how to set up an I/O queue. The driver creates the queue in its EvtDriverDeviceAdd callback after it creates the device object and the device interface. WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&queueConfig, WdfIoQueueDispatchParallel);

queueConfig.EvtIoRead = ToasterEvtIoRead; queueConfig.EvtIoWrite = ToasterEvtIoWrite; queueConfig.EvtIoDeviceControl = ToasterEvtIoDeviceControl;

status = WdfIoQueueCreate(device, &queueConfig, WDF_NO_OBJECT_ATTRIBUTES, &queue ); if (!NT_SUCCESS (status)) {

KdPrint( ("WdfIoQueueCreate failed 0x%x\n", status)); return status; }

In the sample, the first line initializes the configuration structure for a default queue. The default queue is power managed by the framework and receives any requests for which the driver has not configured any other queue. The queue is configured for parallel dispatching, which means that the framework dispatches requests to the driver as soon as they arrive. Consequently, more than one request can be active in the driver at a time.

Next, the driver registers the I/O event callbacks for read, write, and device I/O control requests in the queue configuration structure (queueConfig in the example). Because this is a function driver, the framework fails any other I/O request types (IRP_MJ_INTERNAL_DEVICE_IO_CONTROL) that are sent to the driver. The callbacks are registered on a per-queue basis.

The call to WdfIoQueueCreate creates the queue and returns a queue handle. By default, the queue is a child of the WDFDEVICE object that is the first parameter to the call.

Unlike a WDM driver, the KMDF driver does not require a lock for the queue because the framework ensures that queuing operations are properly synchronized for any WDFQUEUE object.

By default, queues are power managed, which means that the framework stops and starts them according to the power and Plug and Play state of the device. A driver

September 12, 2006© 2006 Microsoft Corporation. All rights reserved.

Page 36: Porting a Driver from WDM to KMDF · Web viewSeptember 12, 2006 Abstract This paper provides information about how to port drivers that conform to the Microsoft® Windows® Driver

Porting a Driver from WDM to KMDF - 36

can override this default when it creates the queue or can use WdfQueueXxx methods at any time to stop, start, and otherwise manipulate the queue.

Port I/O Dispatch Routines to I/O Event Callback FunctionsThe core of a WDM driver’s I/O dispatch routines map to the KMDF driver’s I/O event callback functions. However, the I/O event callback functions differ in several important ways from a WDM driver’s I/O dispatch routines:

When the framework invokes a KMDF driver’s I/O event callback, the callback receives the request in a noncancelable state. The request cannot be canceled unless the driver explicitly marks it as cancelable. The driver can specify whether the framework synchronizes calls to the I/O event callbacks so that only one such callback runs concurrently for each queue or for each device object, or whether the framework applies no synchronization at all.

These differences mean that most I/O event callback functions contain significantly less code to synchronize access and to prevent race conditions than the corresponding WDM DispatchXxx routines.

Aside from synchronization, the primary differences between a WDM driver’s I/O dispatch routines and a KMDF driver’s I/O event callback functions lie in how the driver retrieves parameters and how it accesses I/O buffers.

Parameters for I/O RequestsDepending on the types of requests that a KMDF driver handles and the way it configures its I/O queues, a driver might not be required to parse the parameters to an I/O request as a WDM driver does. When the framework calls the I/O event callbacks for read, write, and device I/O control requests (EvtIoRead, EvtIoWrite, EvtIoDeviceControl, EvtIoInternalDeviceControl), it extracts the most commonly used parameters from the IRP and passes them as parameters to the callback. For example, the framework calls a driver’s EvtIoRead callback with a handle to the WDFREQUEST object and the number of bytes to read. If the driver does not require a device offset or a sort key, it can simply retrieve the buffer from the WDFREQUEST object by calling one of the WdfRequestRetrieveOutputXxx methods; it does not need to retrieve additional parameters.In an EvtIoDefault callback, however, the framework passes only a handle to the queue and a handle to the request object. Consequently, the driver must call WdfRequestGetParameters to get the parameters, including the type of request (WdfRequestTypeXxx). WdfRequestGetParameters returns a WDF_REQUEST_PARAMETERS structure that contains the parameters that were passed with a create, read, write, device I/O control, or internal device I/O control request.

Access to Buffers for Buffered and Direct I/OWhen the framework receives a request for I/O, it creates a WDFREQUEST object that encapsulates the underlying WDM IRP. It then queues the WDFREQUEST object and eventually dispatches the WDFREQUEST object according to the driver’s dispatch specification for the queue. The driver uses KMDF methods to retrieve parameters and buffers for the I/O request. A driver can get the underlying WDM IRP at any time by calling WdfRequestGetWdmIrp.

Like WDM drivers, KMDF drivers can support buffered, direct, or neither I/O. A driver sets the type of I/O that is supported for each device object by calling WdfDeviceInitSetIoType in the EvtDriverDeviceAdd callback before creating the device object. Unlike a WDM driver, however, a KMDF driver accesses the buffers

September 12, 2006© 2006 Microsoft Corporation. All rights reserved.

Page 37: Porting a Driver from WDM to KMDF · Web viewSeptember 12, 2006 Abstract This paper provides information about how to port drivers that conform to the Microsoft® Windows® Driver

Porting a Driver from WDM to KMDF - 37

in the same way whether it performs buffered or direct I/O and uses the same methods for each.

If the KMDF driver performs buffered I/O, the I/O manager creates an intermediate buffer. The framework wraps the intermediate buffer in a WDFMEMORY object and passes it to the driver in the WDFREQUEST object.

If the driver performs direct I/O, the framework similarly creates a WDFMEMORY object and passes this to the driver in the WDFREQUEST. In this case, however, the WDFMEMORY object wraps the user buffer that was passed in the IRP. No intermediate buffer is required.

Requests for neither I/O require special handling. If the driver performs neither I/O, the framework passes the user-mode buffer pointer in the WDFREQUEST object. The driver must implement an EvtIoInCallerContext callback, so that it can retrieve the user-mode buffer while running in the context of the application that sent the request. For details, see “Access to Buffers for Neither I/O,” later in this paper.

Although a KMDF driver accesses buffers in the same way for both buffered and direct I/O, it uses different methods to retrieve the buffers depending on the type of I/O request. The following sections describe how the driver handles each type of I/O request:

Create requests Read requests Write requests Device I/O control requests Internal device I/O control requests

Create RequestsA KMDF driver can handle create requests (IRP_MJ_CREATE) in either of two ways:

Bypass queuing and instead supply an EvtDeviceFileCreate callback. Have the framework queue create requests and implement an EvtIoDefault callback to handle such requests from the queue.

By default, when the framework receives a create request, it creates a WDFFILEOBJECT to represent the file. If the driver has registered an EvtDeviceFileCreate callback, the framework invokes this function and passes it a handle to a WDFREQUEST object and a handle to the WDFFILEOBJECT. The KMDF driver can get parameters for the request by calling WdfRequestGetParameters and can get information about the file object (such as its name) by calling WdfFileObjectXxx methods.

If the driver instead queues create requests, the framework dispatches those requests from the queue according to the queue’s dispatch type (sequentially, in parallel, or manually), just as it dispatches other I/O requests. However, create requests cannot be directed to a default I/O queue. Instead, the driver must explicitly configure a queue to receive them. When the framework dispatches the create request, the EvtIoDefault callback function or the WdfIoQueueRetrieveXxx method receives a handle to the WDFREQUEST object but not a handle to the WDFFILEOBJECT. The driver calls WdfRequestGetParameters to get the parameters for the I/O request. If the driver requires a handle to the file object, it calls WdfRequestGetFileObject.

September 12, 2006© 2006 Microsoft Corporation. All rights reserved.

Page 38: Porting a Driver from WDM to KMDF · Web viewSeptember 12, 2006 Abstract This paper provides information about how to port drivers that conform to the Microsoft® Windows® Driver

Porting a Driver from WDM to KMDF - 38

If the driver neither queues create requests nor implements the EvtDeviceFileCreate callback, the framework takes a default action that depends on the type of device object. For an FDO, the framework completes the request with STATUS_SUCCESS. For a filter DO, the framework forwards the request to the next lower driver.

Read RequestsTo retrieve a buffer for a read request (IRP_MJ_READ), a KMDF driver calls one of the WdfRequestRetrieveOutputXxx methods. The buffer that each of these methods returns depends on whether the driver performs buffered or direct I/O.

If the driver performs buffered I/O: WdfRequestRetrieveOutputBuffer returns Irp->AssociatedIrp.SystemBuffer. WdfRequestRetrieveOutputWdmMdl builds a memory descriptor list (MDL) for Irp-> AssociatedIrp.SystemBuffer and returns the MDL. WdfRequestRetrieveOutputMemory returns a WDFMEMORY object. The driver calls WdfMemoryGetBuffer on this object to get Irp-> AssociatedIrp.SystemBuffer.

If the driver performs direct I/O: WdfRequestRetrieveOutputBuffer returnsMmGetSystemAddressForMdlSafe (Irp->MdlAddress). .WdfRequestRetrieveOutputWdmMdl returns Irp->MdlAddress. WdfRequestRetrieveOutputMemory returns a WDFMEMORY object. The driver calls WdfMemoryGetBuffer on this object to get MmGetSystemAddressForMdlSafe (Irp->MdlAddress).

If the driver performs neither I/O, it must implement an EvtIoInCallerContext callback, so that it can retrieve the user-mode buffer while running in the context of the application that sent the request. For details, see “Access to Buffers for Neither I/O,” later in this paper.

Write RequestsTo retrieve a buffer for a write request (IRP_MJ_WRITE), a KMDF driver calls one of the WdfRequestRetrieveInputXxx methods. The buffer that each of these methods returns depends on whether the driver performs buffered or direct I/O.

If the driver performs buffered I/O: WdfRequestRetrieveInputBuffer returns Irp->AssociatedIrp.SystemBuffer. WdfRequestRetrieveInputWdmMdl builds an MDL for Irp-> AssociatedIrp.SystemBuffer and returns the MDL. WdfRequestRetrieveInputMemory returns a WDFMEMORY object. The driver calls WdfMemoryGetBuffer on this object to get Irp-> AssociatedIrp.SystemBuffer.

If the driver performs direct I/O: WdfRequestRetrieveInputBuffer returnsMmGetSystemAddressForMdlSafe (Irp->MdlAddress). .WdfRequestRetrieveInputWdmMdl returns Irp->MdlAddress.

September 12, 2006© 2006 Microsoft Corporation. All rights reserved.

Page 39: Porting a Driver from WDM to KMDF · Web viewSeptember 12, 2006 Abstract This paper provides information about how to port drivers that conform to the Microsoft® Windows® Driver

Porting a Driver from WDM to KMDF - 39

WdfRequestRetrieveInputMemory returns a WDFMEMORY object. The driver calls WdfMemoryGetBuffer on this object to get MmGetSystemAddressForMdlSafe (Irp->MdlAddress).

If the driver performs neither I/O, it must implement an EvtIoInCallerContext callback, so that it can retrieve the user-mode buffer while running in the context of the application that sent the request. For details, see “Access to Buffers for Neither I/O,” later in this paper.

Device I/O Control RequestsTo handle a device I/O control request (IRP_MJ_DEVICE_CONTROL), a KMDF driver calls either WdfRequestRetrieveInputXxx methods or WdfRequestRetrieveOutputXxx methods to get buffers for buffered and direct I/O. The corresponding input and output methods return the same buffer, so the driver can use either one. The buffer that each of these methods returns depends on whether the driver performs buffered or direct I/O, just as in read and write requests.

If the driver performs buffered I/O: WdfRequestRetrieveXxxBuffer returns Irp->AssociatedIrp.SystemBuffer. WdfRequestRetrieveXxxWdmMdl builds an MDL for Irp-> AssociatedIrp.SystemBuffer and returns the MDL. WdfRequestRetrieveXxxMemory returns a WDFMEMORY object. The driver calls WdfMemoryGetBuffer on this object to get Irp-> AssociatedIrp.SystemBuffer.

If the driver performs direct I/O: WdfRequestRetrieveInputBuffer returns Irp->AssociatedIrp.SystemBuffer. WdfRequestRetrieveInputWdmMdl builds an MDL for Irp-> AssociatedIrp.SystemBuffer and returns the MDL. WdfRequestRetrieveInputMemory returns a WDFMEMORY object. The driver calls WdfMemoryGetBuffer on this object to get Irp->AssociatedIrp.SystemBuffer. WdfRequestRetrieveOutputBuffer returnsMmGetSystemAddressForMdlSafe (Irp->MdlAddress). .WdfRequestRetrieveOutputWdmMdl returns Irp->MdlAddress. WdfRequestRetrieveOutputMemory returns a WDFMEMORY object. The driver calls WdfMemoryGetBuffer on this object to get MmGetSystemAddressForMdlSafe (Irp->MdlAddress).

If the driver handles device I/O control requests that originate in another device stack or use the Parameters.Other fields, the driver should call WdfRequestGetParameters to get a buffer pointer instead of calling WdfRequestRetrieveInputBuffer and WdfRequestRetrieveOutputBuffer. Because the source of these requests is guaranteed to be a kernel-mode component, the driver can trust the returned buffer pointer. However, it must still validate the buffer lengths and any other parameters.

If the driver performs neither I/O, it must implement an EvtIoInCallerContext callback, so that it can retrieve the user-mode buffer while running in the context of the application that sent the request. For details, see “Access to Buffers for Neither I/O,” later in this paper.

September 12, 2006© 2006 Microsoft Corporation. All rights reserved.

Page 40: Porting a Driver from WDM to KMDF · Web viewSeptember 12, 2006 Abstract This paper provides information about how to port drivers that conform to the Microsoft® Windows® Driver

Porting a Driver from WDM to KMDF - 40

Internal Device I/O Control RequestsInternal device I/O control requests (IRP_MJ_INTERNAL_DEVICE_CONTROL) are issued only by kernel-mode components and are used internally by some operating system components to pass request blocks (xRB protocols such as SCSI request blocks [SRBs] or universal request blocks [URBs]). Many different types of buffers can accompany such requests.

Retrieving and interpreting parameters for internal device I/O control requests can be problematic. The problem occurs because some such requests pass the length in the InputBufferLength and OutputBufferLength fields of the Parameters.DeviceIoControl structure of the WDM IRP, but some do not. Nevertheless, the framework extracts whatever values are in the InputBufferLength and OutputBufferLength fields and passes them as parameters to the EvtIoInternalDeviceControl callback. It does not perform any internal validation on these values.

To get the buffers themselves, the driver calls one of the following methods: WdfRequestRetrieveInputBuffer, which returns the Parameters.DeviceIoControl.Type3InputBuffer field of the IRP. WdfRequestRetrieveOutputBuffer, which returns the UserBuffer field of the IRP.

If the buffer lengths that the driver receives do not match the actual buffer lengths, these methods can return incorrect results. To avoid this problem, ensure that you know exactly what the caller passes in such cases.

Access to Buffers for Neither I/OA driver that performs neither buffered nor direct I/O (also called “neither I/O” or Type 3 I/O) receives a pointer to a user-mode buffer if the request originates with a user-mode caller. The driver must validate the pointer and lock the user-mode buffer into memory before accessing it. The driver must be running in the context of the requesting user-mode process to validate the buffer pointer and lock down the buffer. It should then store the buffer pointer in the request object’s context area for later use in completing the requested I/O. (If the request originates in kernel mode, no such requirements apply.)

To ensure that it is called in the user’s context, a KMDF driver that performs neither I/O must implement an EvtIoInCallerContext callback and register this callback when it initializes the device object by calling WdfDeviceInitSetIoInCallerContextCallback. The framework calls this function in the user-mode caller’s context every time it receives an I/O request for the device object. This function should get the buffer pointer from the request, validate it, and lock the user-mode buffer into memory. The Nonpnp sample that is provided with KMDF shows how to do this.

KMDF supplies two methods that EvtIoInCallerContext can call to get the buffers that are supplied in neither I/O requests:

WdfRequestRetrieveUnsafeUserInputBuffer gets the buffer for a write or device I/O control request. WdfRequestRetrieveUnsafeUserOutputBuffer gets the buffer for a read or device I/O control request.

September 12, 2006© 2006 Microsoft Corporation. All rights reserved.

Page 41: Porting a Driver from WDM to KMDF · Web viewSeptember 12, 2006 Abstract This paper provides information about how to port drivers that conform to the Microsoft® Windows® Driver

Porting a Driver from WDM to KMDF - 41

These functions validate the buffer lengths that are supplied in the request and return a pointer to the user-mode buffer. They must be called from within a driver’s EvtIoInCallerContext callback. Table 5 shows what each of these methods returns in WDM terms.Table 5. Buffer Retrieval for Neither I/OKMDF method WDM equivalentWdfRequestRetrieveUnsafeUserInputBuffer For an IOCTL:

irpStack-> Parameters.DeviceIoControl.Type3InputBufferFor a write request:Irp->UserBufferFor any other request:STATUS_INVALID_DEVICE_REQUEST

WdfRequestRetrieveUnsafeUserOutputBuffer

For an IOCTL or read request:Irp->UserBufferFor any other request:STATUS_INVALID_DEVICE_REQUEST

Before using the returned pointer to access the buffer, the KMDF driver must probe and lock the user-mode buffer by calling WdfRequestProbeAndLockUserBufferForRead or WdfRequestProbeAndLockUserBufferForWrite. These functions do the following (in WDM terms):

Allocate an MDL for the user-mode buffer. Call MmProbeAndLockPages to validate the user-mode buffer and lock it into memory. Call MmGetSystemAddressForMdlSafe to get a kernel-mode address for the user buffer. Create a WDFMEMORY object to represent the buffer. Associate the WDFMEMORY object with the request and set the request as the parent of the WDFMEMORY object. Set the WDFMEMORY object to point to the MDL.

After the driver has locked the buffer into memory, it should store the buffer pointer in the context area of the WDFREQUEST object.

The following code sample is excerpted from the Nonpnp sample, which uses neither I/O for a device I/O control request. It shows how to create an object context area for the request and store the buffer pointers. By creating a new context area, the driver ensures that any data that it saves in the context area remains private. Additional KMDF drivers in the stack might also create their own context areas for their own private, request-related data.

In the header file, the driver declares the context type and names the accessor function as follows:typedef struct _REQUEST_CONTEXT {

WDFMEMORY InputMemoryBuffer; WDFMEMORY OutputMemoryBuffer;

} REQUEST_CONTEXT, *PREQUEST_CONTEXT;

WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(REQUEST_CONTEXT, GetRequestContext)

September 12, 2006© 2006 Microsoft Corporation. All rights reserved.

Page 42: Porting a Driver from WDM to KMDF · Web viewSeptember 12, 2006 Abstract This paper provides information about how to port drivers that conform to the Microsoft® Windows® Driver

Porting a Driver from WDM to KMDF - 42

In its EvtIoInCallerContext routine, the driver allocates a context area for this request, probes and locks the input and output buffers, stores the buffer pointers in the context area, and then returns the request to the framework for queuing.

// // Allocate a context for this request so that we can store the // memory objects created for the input and output buffer. // WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, REQUEST_CONTEXT);

status = WdfObjectAllocateContext(Request, &attributes, &reqContext); if(!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, "Error WdfObjectAllocateContext failed 0x%x", status); goto End; }

// status = WdfRequestProbeAndLockUserBufferForRead(Request, inBuf, inBufLen, &reqContext->InputMemoryBuffer);

if(!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, "Error WdfRequestProbeAndLockUserBufferForRead failed 0x%x", status); goto End; }

status = WdfRequestProbeAndLockUserBufferForWrite(Request, outBuf, outBufLen, &reqContext->OutputMemoryBuffer);

status = WdfDeviceEnqueueRequest(Device, Request);

If the driver has configured parallel or sequential dispatching for the queue, the framework later invokes the I/O event callback for the I/O type that is specified in the request. If the driver has configured manual dispatching, the driver calls one of the WdfQueueRetrieveXxx methods when it is ready to receive and handle the request. Before the driver accesses the buffer, it uses the accessor function for the WDFREQUEST (in the example, GetRequestContext) to get a pointer to the context area from which it can retrieve the buffer pointer.

The EvtIoInCallerContext callback requires somewhat different synchronization from other EvtIoXxx functions. Because the request has not yet been queued, it can be canceled. Usually, the driver merely locks the buffer, stores the pointer, and returns the request to the framework. If the request is canceled during this time, the cancellation does not affect the driver and the framework simply completes the request later with STATUS_CANCELLED. If the request is canceled after the driver calls WdfDeviceEnqueueRequest, the framework invokes the EvtIoCanceledOnQueue callback (if the driver registered one).The driver should provide an EvtObjectCleanup callback that cleans up the mapped data.

If the driver does not return the request to the framework for queuing, it must be prepared to handle cancellation and must provide any other required

September 12, 2006© 2006 Microsoft Corporation. All rights reserved.

Page 43: Porting a Driver from WDM to KMDF · Web viewSeptember 12, 2006 Abstract This paper provides information about how to port drivers that conform to the Microsoft® Windows® Driver

Porting a Driver from WDM to KMDF - 43

synchronization. Generally, drivers should use framework queuing and queue management instead of attempting to implement their own.

Complete a RequestKMDF provides three methods that complete I/O requests:

WdfRequestComplete WdfRequestCompleteWithInformation WdfRequestCompleteWithPriorityBoost

When the driver calls one of these methods, the framework proceeds as follows: If the driver called WdfRequestCompleteWithInformation, records the value of the supplied Information parameter in the IoStatus.Information field of the underlying IRP. Releases any context memory that the driver allocated for the request. Calls the EvtCleanupCallback callback for the WDFREQUEST object if one exists. Destroys the children of the WDFREQUEST object, including any WDFMEMORY objects, calling their EvtCleanupCallback and EvtDestroyCallback routines if such callbacks exist. Records the supplied status in the IoStatus.Status field of the underlying IRP. Calls IoCompleteRequest, passing a priority boost if the driver specified one.

After any of the three request completion methods returns, the handles to the WDFREQUEST object and its children are no longer valid.

Depending on the original source of the I/O buffer and the WDFMEMORY object that is embedded in the WDFREQUEST object, deleting the WDFREQUEST object might also cause the WDFMEMORY object to be deleted and the buffer pointers to become invalid—or it might not. For a detailed explanation, see the driver tip “Is That Handle Still Valid?,” which is listed in "Resources" at the end of this paper.

Handle a Canceled RequestWhen an I/O request is canceled, a WDM driver must manage several difficult race conditions. A request might be canceled while it is in a queue or while the driver is processing it, and in each case the driver must use a combination of locks to ensure that it cancels and completes the request only once.

The KMDF queuing mechanism greatly simplifies cancellation. If a request is canceled while it is on a queue, the framework handles cancellation without notifying the driver. The driver can request notification by registering an EvtIoCanceledOnQueue callback function. After the framework has delivered a request to the driver, the request is not cancelable by default. A driver can call WdfRequestIsCanceled at any time to find out whether the request has been canceled.

To make a request cancelable, the driver must call WdfRequestMarkCancelable, which registers an EvtRequestCancel callback. Like a WDM driver’s Cancel routine, the EvtRequestCancel callback performs whatever tasks are required to stop processing the request and then completes the request.

September 12, 2006© 2006 Microsoft Corporation. All rights reserved.

Page 44: Porting a Driver from WDM to KMDF · Web viewSeptember 12, 2006 Abstract This paper provides information about how to port drivers that conform to the Microsoft® Windows® Driver

Porting a Driver from WDM to KMDF - 44

If the driver uses device-level synchronization, the EvtRequestCancel routine does not require code to synchronize with other I/O callback routines for the device object. In this case, the framework acquires the callback synchronization lock for the device object before it calls the EvtRequestCancel, so that any other routines (such as I/O event callbacks and possibly timer and DPC callbacks) that use the same synchronization lock cannot run concurrently.

However, the EvtRequestCancel callback must still synchronize with any other code that calls WdfRequestComplete to ensure that the driver completes the request only once. In the EvtRequestCancel callback, the driver should complete the request with STATUS_CANCELLED. In any other function, the driver should mark the request as not cancelable before completing it, and then check for cancellation before calling WdfRequestComplete, as in the following example:Status = WdfRequestUnmarkCancelable(Request);if( Status != STATUS_CANCELLED ) {    WdfRequestComplete(Request, RequestStatus);

After the call to WdfRequestUnmarkCancelable returns, the request can no longer be cancelled. By checking for cancellation status in the next line, the driver prevents a race condition that could result if cancellation was already in progress on another thread. If the request has not already been canceled, the driver can then be certain that it calls WdfRequestComplete only once for the request.

Table 6 summarizes what happens when a request is canceled.Table 6. Request Cancellation When cancellation occurs What the framework doesBefore the request has ever been delivered to the driver.

Cancels the request with STATUS_CANCELLED. No driver code is required, and no notification is sent to the driver.

While the request is in a queue but after it has been delivered to the driver. (This situation could occur if the driver receives an I/O request and then requeues it by calling WdfRequestRequeue or manually forwards it to a different I/O queue by calling WdfRequestForwardToIoQueue.)

If the driver has registered an EvtIoCanceledOnQueue callback for the queue, invokes this callback and then cancels the request.

If the driver has not registered EvtIoCanceledOnQueue, cancels the request with STATUS_CANCELLED. No notification is sent to the driver.

While the driver owns the request. If the driver has called WdfRequestMarkCancelable, calls the EvtRequestCancel callback that the driver registered for the request.

If the driver has not called WdfRequestMarkCancelable, does nothing. The driver can call WdfRequestIsCanceled to find out whether the request has been canceled.

Forward a Request to the Next Lower DriverIf a driver cannot complete a request by itself, it passes the request down the stack to the next lower driver. For a KMDF driver, the next lower driver is considered the default I/O target and is represented by a WDFIOTARGET object. To get a handle to this object, the driver calls WdfDeviceGetIoTarget.

To pass a request down to the next lower driver in the stack, a KMDF driver: Sets an I/O completion callback by calling WdfRequestSetCompletion if the driver must do additional processing on the request after lower drivers have

September 12, 2006© 2006 Microsoft Corporation. All rights reserved.

Page 45: Porting a Driver from WDM to KMDF · Web viewSeptember 12, 2006 Abstract This paper provides information about how to port drivers that conform to the Microsoft® Windows® Driver

Porting a Driver from WDM to KMDF - 45

completed it. The framework sets its own I/O completion function in the IRP, and the framework’s I/O completion function calls the driver’s I/O completion callback. Formats the request by calling WdfRequestFormatRequestUsingCurrentType. Calls WdfRequestSend to send the request to the I/O target.

WdfRequestFormatRequestUsingCurrentType sets up the I/O stack location in the underlying IRP by calling IoCopyCurrentIrpStackLocationToNext.

Issue an I/O RequestKMDF defines several methods that a driver can use to create and format I/O requests. Table 7 summarizes these methods.Table 7. Formatting and Sending I/O RequestsKMDF method ActionWdfIoTargetFormatRequestForIoctlWdfIoTargetFormatRequestForInternalIoctlWdfIoTargetFormatRequestForInternalIoctlOthers

Similar to manually formatting the next I/O stack location.

WdfIoTargetFormatRequestForReadWdfIoTargetFormatRequestForWrite

Similar to IoBuildAsynchronousFsdRequest.

WdfIoTargetSendIoctlSynchronouslyWdfIoTargetSendInternalIoctlSynchronouslyWdfIoTargetSendInternalIoctlOthersSynchronously

Similar to IoBuildDeviceIoControlRequest followed by IoCallDriver.

WdfIoTargetSendReadSynchronouslyWdfIoTargetSendWriteSynchronously

Similar to IoBuildSynchronousFsdRequest followed by IoCallDriver.

WdfRequestCancelSentRequest Similar to IoCancelIrp for a PIRP that was sent with IoCallDriver. The framework provides locks to ensure that the PIRP is not completed or freed between the calls to IoCallDriver and IoCancelIrp.

WdfRequestCreate Similar to IoAllocateIrp. Creates a new WDFREQUEST object, sets attributes, and returns handle to caller.

WdfRequestFormatRequestUsingCurrentType Similar to IoForwardIrpSynchronously but does not call IoCallDriver; driver must call WdfRequestSend.

WdfRequestSend Validates I/O target handle and calls IoCallDriver to forward request.

To send a request to another device stack, a KMDF driver uses a remote I/O target. Where a WDM driver would get a pointer to the PDO of the target stack by calling IoGetDeviceObjectPointer and ZwCreateFile and would register for target device changes by calling IoRegisterPlugPlayNotification, a KMDF driver:

Implements any callback functions that the driver requires to respond in case of target removal or query removal. Calls WdfIoTargetCreate to create the WDFIOTARGET object. Sets parameters in the WDF_IO_TARGET_OPEN_PARAMS structure to identify the I/O target, register the driver’s callback functions for the target, and indicate the type of access that the driver requires to the target.

September 12, 2006© 2006 Microsoft Corporation. All rights reserved.

Page 46: Porting a Driver from WDM to KMDF · Web viewSeptember 12, 2006 Abstract This paper provides information about how to port drivers that conform to the Microsoft® Windows® Driver

Porting a Driver from WDM to KMDF - 46

Calls WdfIoTargetOpen to open the target device.

The following example shows how the Ndisedge sample driver creates and opens a remote I/O target. status = WdfIoTargetCreate(Adapter->WdfDevice, WDF_NO_OBJECT_ATTRIBUTES, &Adapter->IoTarget); if (!NT_SUCCESS(status)) { DEBUGP(MP_ERROR, ("WdfIoTargetCreate failed 0x%x\n", status)); return status; }

WDF_IO_TARGET_OPEN_PARAMS_INIT_CREATE_BY_NAME(&openParams, &fileName, STANDARD_RIGHTS_ALL );

status = WdfIoTargetOpen(Adapter->IoTarget, &openParams); if (!NT_SUCCESS(status)) { DEBUGP(MP_ERROR, ("WdfIoTargetOpen failed 0x%x\n", status)); return status; }

The WdfIoTargetCreate method takes a pointer to the device object that is the parent of the I/O target (that is, the current device object), an attribute structure, and a location to receive a handle to the created I/O target object. After the driver creates the object, it initializes the required parameters to open the target. A driver can open an I/O target by passing either its name or a pointer to its WDM DEVICE_OBJECT. (In some conditions, a driver can also reopen a previously closed target.) In the example, the driver opens the target by name, so it calls WDF_IO_TARGET_OPEN_PARAMS_INIT_CREATE_BY_NAME to set up the parameter structure. It then calls WdfIoTargetOpen to open the I/O target.

After the driver has opened the I/O target, it can send I/O requests to the target. The following example shows how to send a synchronous I/O control (IOCTL) request. NTSTATUS status; WDF_MEMORY_DESCRIPTOR inputDesc, outputDesc; PWDF_MEMORY_DESCRIPTOR pInputDesc = NULL, pOutputDesc = NULL; ULONG_PTR bytesReturned;

UNREFERENCED_PARAMETER(FileObject);

if (InputBuffer) { WDF_MEMORY_DESCRIPTOR_INIT_BUFFER(&inputDesc, InputBuffer, InputBufferLength); pInputDesc = &inputDesc; }

if (OutputBuffer) { WDF_MEMORY_DESCRIPTOR_INIT_BUFFER(&outputDesc, OutputBuffer, OutputBufferLength); pOutputDesc = &outputDesc; }

September 12, 2006© 2006 Microsoft Corporation. All rights reserved.

Page 47: Porting a Driver from WDM to KMDF · Web viewSeptember 12, 2006 Abstract This paper provides information about how to port drivers that conform to the Microsoft® Windows® Driver

Porting a Driver from WDM to KMDF - 47

status = WdfIoTargetSendIoctlSynchronously( IoTarget, WDF_NO_HANDLE, // Request IoctlControlCode, pInputDesc, pOutputDesc, NULL, // PWDF_REQUEST_SEND_OPTIONS &bytesReturned); if (!NT_SUCCESS(status)) { DEBUGP(MP_ERROR, ("WdfIoTargetSendIoctlSynchronously failed 0x%x\n", status)); }

*BytesReadOrWritten = (ULONG)bytesReturned;

The WdfIoTargetSendIoctlSynchronously method sends an IOCTL and waits for a response. It requires pointers to WDF_MEMORY_DESCRIPTOR structures, which describe the input and output buffers for the request. To initialize these structures for buffered I/O, the driver calls WDF_MEMORY_DESCRIPTOR_INIT_BUFFER with a pointer to the descriptor, a pointer to the buffer, and the buffer length. It then calls WdfIoTargetSendIoctlSynchronously to send the request to the I/O target.

WdfIoTargetSendIoctlSynchronously returns the request’s completion status because it sends the request synchronously. To get the completion status for an asynchronous request or for any request that is sent by calling WdfRequestSend, the driver calls WdfRequestGetStatus. For a synchronous request, it can retrieve status immediately. For an asynchronous request, the driver’s I/O completion callback typically retrieves status.

To get additional information about the completed request, the driver calls WdfRequestGetCompletionParams and WdfRequestGetInformation.

DMA SupportPerforming DMA in a KMDF driver is simpler than in a WDM driver because the framework handles many of the details on behalf of the driver. In essence, the KMDF driver creates a DMA enabler object, specifies the DMA capabilities of the device, and supplies a callback function that manipulates the hardware to perform the transfer. The framework determines the number of map registers that are required for the transfer, allocates the map registers, builds a scatter/gather list (if the device supports scatter/gather DMA), and flushes the processor cache and the buffers whenever necessary.

To support DMA, a KMDF driver does the following in its EvtDriverDeviceAdd callback:

Creates a DMAENABLER object and initializes it with information about the DMA capabilities of the device. Creates a common buffer object, if the device supports common-buffer DMA.

When an I/O request arrives that requires DMA, the I/O event callback initiates the DMA transaction for a packet-based DMA device as follows:

Creates a new DMA transaction object by calling WdfDmaTransactionCreate. The transaction object manages the DMA transaction and supports methods with which the driver can manage the transaction and retrieve properties of the transaction.

September 12, 2006© 2006 Microsoft Corporation. All rights reserved.

Page 48: Porting a Driver from WDM to KMDF · Web viewSeptember 12, 2006 Abstract This paper provides information about how to port drivers that conform to the Microsoft® Windows® Driver

Porting a Driver from WDM to KMDF - 48

Initializes the DMA transaction to handle the current request by calling WdfDmaTransactionInitializeUsingRequest. Calls WdfDmaTransactionExecute to start the transaction. The framework flushes the processor cache, allocates map registers and creates a scatter/gather list as required, and calls the driver’s EvtProgramDma callback function.

The EvtProgramDma callback programs the device hardware to perform DMA and returns TRUE if it successfully starts the transfer. When the device interrupts to indicate that the transfer is finished, the driver’s EvtInterruptDpc calls one or more of the WdfDmaTransactionXxx methods to get information about the transfer and to inform the framework that the transfer is complete.

For a complete description of the KMDF and WDM DMA mechanisms, see the white paper titled DMA Support in Windows Drivers, which is listed in "Resources" at the end of this paper. For sample code, see the Pcidrv, AMCC5933, and PLx5x9x sample drivers that are supplied with the WDK.

WMI SupportAn IRP_MJ_SYSTEM_CONTROL request represents a request for WMI data. WDM drivers handle such requests by implementing a DispatchSystemControl function and registering as a WMI data provider. WDM drivers that do not respond to such requests implement a DispatchSystemControl routine that simply passes the IRPs down to the next lower driver.

For KMDF drivers, the framework provides default handling for IRP_MJ_SYSTEM_CONTROL. Drivers that do not provide WMI data are not required to include any WMI-related code. Instead, the framework passes the request to the next lower driver on behalf of the driver.

A KMDF driver that provides WMI data: Registers as a WMI data provider. Create one or more WMI instance objects to represent the data blocks it can read or write. Optionally implements one or more event callback functions to supply the WMI data that the driver provides. Optionally fires WMI events.

Like all WDF objects, WMI instance objects (WDFWMIINSTANCE) have a context area. A driver can use the context area of a WDFWMIINSTANCE object as a source of read-only data, thus enabling easy data collection with minimal effort. A driver can delete WDFWMIINSTANCE objects any time after their creation.

To initialize its WMI support, a KMDF driver follows these steps, typically within its EvtDriverDeviceAdd or EvtDeviceSelfManagedIoInit callback:1. Register the name of the driver’s managed object format (MOF) resource by

calling the WdfDeviceAssignMofResourceName method.

2. Initialize a WMI provider configuration structure and optionally create a WMI provider object (WDFWMIPROVIDER).

3. Initialize a WMI instance configuration structure and create a WMI instance object (WDFWMIINSTANCE).

The framework creates a WMI provider by default when a KMDF driver creates its first WMI instance. Therefore, if the driver requires only one WMI provider, it is not

September 12, 2006© 2006 Microsoft Corporation. All rights reserved.

Page 49: Porting a Driver from WDM to KMDF · Web viewSeptember 12, 2006 Abstract This paper provides information about how to port drivers that conform to the Microsoft® Windows® Driver

Porting a Driver from WDM to KMDF - 49

required to call the provider-creation method (WdfWmiProviderCreate). However, the driver must fill in the provider configuration structure because this structure supplies information about the provider that the framework uses when it creates the instance.

A driver implements EvtWmiInstanceXxx callbacks to respond to WMI requests. The framework provides an additional shortcut for supplying instance data. A driver can store read-only data in the WMI instance object’s context area. When the driver creates an instance, it can indicate that the framework should use the data in the context area to satisfy requests for instance data. No callbacks are required if the driver has only a single WMI instance that provides read-only, fixed-length data from its object context area.

A KMDF driver can notify registered clients of WMI events by firing an event in much the same way as WDM driver. The KMDF driver calls WdfWmiInstanceFireEvent, passing a handle to a WMIINSTANCE object, a pointer to a buffer that contains additional event data, and a buffer length. The framework builds the event block and passes the information to the client.

The framework also includes support for WMI event tracing. To supply event tracing data, a KMDF driver:

Configures a WMI provider object for event tracing by setting the WdfWmiProviderTracing flag when it initializes the provider object. Gets a handle to an event logger by using the WdfWmiProviderGetTracingHandle method. Call WmiTraceMessage to write a message to the log.

Timers, DPCs, and Work ItemsTimer (WDFTIMER), deferred procedure call (WDFDPC), and work item (WDFWORKITEM) objects serve the same purposes as their WDM counterparts. A timer expires once or periodically, triggering the execution of a callback function. A DPC runs at DISPATCH_LEVEL, typically to perform tasks that were deferred from an interrupt service routine. A work item runs in a system worker thread at PASSIVE_LEVEL to perform tasks that cannot be done at DISPATCH_LEVEL.

In a KMDF driver, DPC, timer, and work item objects can be the children of device objects or of queue objects, and the framework can synchronize the execution of their callbacks with those of either the associated queue object or the device object (which might be the parent or the grandparent of the DPC, timer, or work item).

A driver sets callback synchronization on interrupt, DPC, timer, and work item objects by setting AutomaticSerialization in the object’s configuration structure during object creation. If you choose such synchronization, however, you should ensure that all of the callback functions that are subject to synchronization are called at the same IRQL. In practice, this means that you should not set the PASSIVE_LEVEL execution constraint (WdfExecutionLevelPassive) for the associated queue or device object.

Requests that KMDF Does Not SupportKMDF does not support I/O requests that have the following major IRP codes:

IRP_MJ_CREATE_MAILSLOTIRP_MJ_CREATE_NAMED_PIPEIRP_MJ_DEVICE_CHANGE

September 12, 2006© 2006 Microsoft Corporation. All rights reserved.

Page 50: Porting a Driver from WDM to KMDF · Web viewSeptember 12, 2006 Abstract This paper provides information about how to port drivers that conform to the Microsoft® Windows® Driver

Porting a Driver from WDM to KMDF - 50

IRP_MJ_DIRECTORY_CONTROLIRP_MJ_FILE_SYSTEM_CONTROLIRP_MJ_FLUSH_BUFFERSIRP_MJ_LOCK_CONTROLIRP_MJ_QUERY_EAIRP_MJ_QUERY_INFORMATIONIRP_MJ_QUERY_QUOTAIRP_MJ_QUERY_SECURITYIRP_MJ_QUERY_VOLUME_INFORMATIONIRP_MJ_SET_EAIRP_MJ_SET_INFORMATIONIRP_MJ_SET_QUOTAIRP_MJ_SET_SECURITYIRP_MJ_SET_VOLUME_INFORMATION

When the framework receives such a request, its default action depends on the device object that was the target of the request. For an FDO or PDO, the framework completes the IRP with the status STATUS_INVALID_DEVICE_REQUEST. For a filter DO, the framework passes the IRP to the next lower driver.

Although the framework does not support these request types, the driver can still handle them. The framework defines a WDM IRP preprocessing event callback through which the driver can receive the WDM IRP. To handle such IRPs.

In the EvtDriverDeviceAdd callback, call WdfDeviceInitAssignWdmIrpPreprocessCallback, specifying the name of the EvtDeviceWdmIrpPreprocess callback function and indicating the major IRP function code and any minor function codes for which the framework should call it. In the EvtDeviceWdmIrpPreprocess callback, perform whatever tasks the driver requires to handle the IRP in the usual way for a WDM driver. When the driver has finished handling the IRP, it either calls IoCompleteRequest to complete the IRP or sets up the I/O stack location and calls IoCallDriver to pass the IRP to the next lower driver, just as a WDM driver would. If the driver passes the IRP down the device stack but requires access to the IRP after lower drivers have completed it (that is, the driver post-processes the IRP), EvtDeviceWdmIrpPreprocess must call IoSetCompletion routine for the IRP before passing it to the next lower driver. The IoCompletion routine post-processes the IRP.

The EvtDeviceWdmIrpPreprocess callback and the IoCompletion routine that it sets must follow the normal WDM rules for handling IRPs.

The Serial sample shows how to implement and use the EvtDeviceWdmPreprocessIrp callback to handle and complete IRP_MJ_FLUSH_BUFFERS, IRP_MJ_QUERY_INFORMATION, and IRP_MJ_SET_INFORMATION requests. The sample calls WdfDeviceInitAssignWdmIrpPreprocessCallback three times, once for each of the major IRP codes. It registers three EvtDeviceWdmPreprocessIrp callbacks: one to handle the flush-buffer IRP (SerialFlush), one to handle the query information IRP (SerialQueryInformationFile), and one to handle the set information IRP (SerialSetInformationFile).

September 12, 2006© 2006 Microsoft Corporation. All rights reserved.

Page 51: Porting a Driver from WDM to KMDF · Web viewSeptember 12, 2006 Abstract This paper provides information about how to port drivers that conform to the Microsoft® Windows® Driver

Porting a Driver from WDM to KMDF - 51

Installation ProcedureKMDF drivers are installed by using INF files, just as WDM drivers are. However, KMDF drivers must use the KMDF co-installer and must add information about the additional service that is required for KMDF drivers.

To modify an existing WDM driver INF file to install a KMDF driver: Change the existing DDInstall.CoInstallers section to install the KMDF co-installer, or add such a section if the existing driver installation package does not have a co-installer. Add a DDInstall.Wdf section that specifies the name of the driver service. Add a WDF install section that specifies the KMDF library version.

The DDInstall.CoInstallers section installs the KMDF co-installer. For example:[MyDevice.NT.CoInstallers]AddReg=MyDevice_CoInstaller_AddRegCopyFiles=MyDevice_CoInstaller_CopyFiles

After the co-installer has been installed, it reads the DDInstall.Wdf section, which specifies a name for the driver service and references an additional INF section that specifies KMDF library version, as follows:KmdfService = DriverService, Wdf-install-section

For example:[ECHO_Device.NT.Wdf]KmdfService = Echo, Echo_wdfsect

In the example, Echo is the name that the operating system assigns to the driver’s kernel-mode service and Echo_wdfsect is the name of the INF section that provides additional information about the driver.

The INF section that Wdf-install-section identifies must contain the following directive:KmdfLibraryVersion = WdfLibraryVersion

WdfLibraryVersion represents a library version number, such as "1.0" or "2.2".

For example:[Echo_wdfsect]KmdfLibraryVersion = 1.0

General Guidelines for PortingThe following are some general guidelines for porting a driver:

Refer to the samples. KMDF ships with a rich set of samples, most of which are ports of the similarly named WDM drivers. Work incrementally. Because the framework implements default behavior for I/O, Plug and Play, power management, and WMI requests, you can code and debug one device or driver feature at a time. Implement WMI event tracing to provide detailed trace logs for use in debugging. Remember that, for KMDF drivers, less is more. In many situations, the KMDF defaults provide greater functionality than the existing WDM driver might have implemented. Before trying to port complicated code—particularly for

September 12, 2006© 2006 Microsoft Corporation. All rights reserved.

Page 52: Porting a Driver from WDM to KMDF · Web viewSeptember 12, 2006 Abstract This paper provides information about how to port drivers that conform to the Microsoft® Windows® Driver

Porting a Driver from WDM to KMDF - 52

synchronization or queue management—be certain what KMDF provides. It might save a considerable amount of time spent porting the driver. Use the KMDF-specific debugger extensions that are provided with the KMDF release. Enable the KMDF verifier while debugging.

ResourcesWindows Driver Foundation (WDF) on the WHDC Web site

http://www.microsoft.com/whdc/driver/wdf/default.mspxCurrent White Papers

Summary of KMDF and WDM Equivalentshttp://www.microsoft.com/whdc/driver/wdf/WDF_Port.mspxArchitecture of the Windows Driver Foundationhttp://www.microsoft.com/whdc/driver/wdf/wdf-arch.mspxArchitecture of the Kernel-Mode Driver Frameworkhttp://www.microsoft.com/whdc/driver/wdf/kmdf-arch.mspxArchitecture of the User-Mode Driver Frameworkhttp://www.microsoft.com/whdc/driver/wdf/UMDF-arch.mspxSample Drivers for the Kernel-Mode Driver Frameworkhttp://www.microsoft.com/whdc/driver/wdf/KMDF-samp.mspxIntroduction to Plug and Play and Power Management in the Windows Driver Foundationhttp://www.microsoft.com/whdc/driver/wdf/WDF_pnpPower.mspxDMA Support in Windows Drivershttp://www.microsoft.com/whdc/driver/kernel/dma.mspxI/O Request Flow in WDF Kernel-Mode Drivershttp://www.microsoft.com/whdc/driver/wdf/ioreq_flow.mspx

KMDF Driver Tipshttp://www.microsoft.com/whdc/driver/tips/default.mspxIs That Handle Still Valid?http://www.microsoft.com/whdc/driver/tips/WDFmem.mspx

Windows Driver Kit (WDK)Kernel-Mode Driver Framework Design Guidehttp://msdn.microsoft.com/library/default.asp?url=/library/en-us/kmdf_d/hh/KMDF_d/Ch0_DFArchOverview_2f03cf4c-72b3-4af5-ad00-0ea37c69bbbf.xml.aspKernel-Mode Driver Framework Referencehttp://msdn.microsoft.com/library/en-us/KMDF_r/hh/KMDF_r/DFRef_da43cbdb-35fa-4c6f-b288-5bca10785390.xml.asp

September 12, 2006© 2006 Microsoft Corporation. All rights reserved.