We’ve already discussed some details about the Windows Driver Foundation (WDF) in Chapter 2, “System Architecture,” in Part 1. In this section, we’ll take a deeper look at the components and func-tionality provided by the kernel-mode part of the framework, KMDF. Note that this section will only briefly touch on some of the core architecture of KMDF. For a much more complete overview on the subject, please refer to http://msdn.microsoft.com/en-us/library/windows/hardware/gg463370.aspx.
Structure and Operation of a KMDF DriverFirst, let’s take a look at which kinds of drivers or devices are supported by KMDF. In general, any WDM-conformant driver should be supported by KMDF, as long as it performs standard I/O process-ing and IRP manipulation. KMDF is not suitable for drivers that don’t use the Windows kernel API directly but instead perform library calls into existing port and class drivers. These types of drivers cannot use KMDF because they only provide callbacks for the actual WDM drivers that do the I/O processing. Additionally, if a driver provides its own dispatch functions instead of relying on a port or class driver, IEEE 1394 and ISA, PCI, PCMCIA, and SD Client (for Secure Digital storage devices) drivers can also make use of KMDF.
Although KMDF provides an abstraction on top of WDM, the basic driver structure shown earlier also generally applies to KMDF drivers. At their core, KMDF drivers must have the following functions:
■ An initialization routine Just like any other driver, a KMDF driver has a DriverEntry function that initializes the driver. KMDF drivers will initiate the framework at this point and perform any configuration and initialization steps that are part of the driver or part of describing the driver to the framework. For non–Plug and Play drivers, this is where the first device object should be created.
■ An add-device routine KMDF driver operation is based on events and callbacks (described shortly), and the EvtDriverDeviceAdd callback is the single most important one for PnP devices because it receives notifications when the PnP manager in the kernel enumerates one of the driver’s devices.
■ One or more EvtIo* routines Just like a WDM driver’s dispatch routines, these callback routines handle specific types of I/O requests from a particular device queue. A driver typically creates one or more queues in which KMDF places I/O requests for the driver’s devices. These queues can be configured by request type and dispatching type.
The simplest KMDF driver might need to have only an initialization and add-device routine because the framework will provide the default, generic functionality that’s required for most types of I/O processing, including power and Plug and Play events. In the KMDF model, events refer to run-time states to which a driver can respond or during which a driver can participate. These events are not related to the synchronization primitives (synchronization is discussed in Chapter 3 in Part 1), but are internal to the framework.
For events that are critical to a driver’s operation, or which need specialized processing, the driver registers a given callback routine to handle this event. In other cases, a driver can allow KMDF to perform a default, generic action instead. For example, during an eject event (EvtDeviceEject), a driver can choose to support ejection and supply a callback or to fall back to the default KMDF code that will tell the user that the device is not ejectable. Not all events have a default behavior, however, and callbacks must be provided by the driver. One notable example is the EvtDriverDeviceAdd event that is at the core of any Plug and Play driver.
EXPERIMENT: Displaying KMDF Drivers
The Wdfkd.dll extension that ships with the Debugging Tools for Windows package provides many commands that can be used to debug and analyze KMDF drivers and devices (instead of using the built-in WDM-style debugging extension that may not offer the same kind of WDF-specific information). You can display installed KMDF drivers with the !wdfkd.wdfldr debugger command. In the following example, the output from a typical Windows computer is shown, displaying the built-in drivers that are installed.
Version v1.9 build(7600)
Associated Clients: 16
ImageName Version WdfGlobals FxGlobals ImageAddress
peauth.sys v1.7(6001) 0xfffffa8004754210 0xfffffa80047540c0 0xfffff880074cc000
scfilter.sys v1.5(6000) 0xfffffa8002ef34e0 0xfffffa8002ef3390 0xfffff880040b3000
WinUSB.sys v1.9(7600) 0xfffffa8002eefd20 0xfffffa8002eefbd0 0xfffff88004000000
monitor.sys v1.9(7600) 0xfffffa8004854a10 0xfffffa80048548c0 0xfffff8800412a000
vmswitch.sys v1.5(6000) 0xfffffa8002de5d60 0xfffffa8002de5c10 0xfffff88003e9b000
vmbus.sys v1.5(6000) 0xfffffa8002d7fcf0 0xfffffa8002d7fba0 0xfffff88003e5f000
Vid.sys v1.5(6000) 0xfffffa8002ddacf0 0xfffffa8002ddaba0 0xfffff88002a00000
umbus.sys v1.9(7600) 0xfffffa8002e57e70 0xfffffa8002e57d20 0xfffff880035db000
storvsp.sys v1.5(6000) 0xfffffa8002e48b10 0xfffffa8002e489c0 0xfffff88003575000
CompositeBus.sys v1.9(7600) 0xfffffa8002d79160 0xfffffa8002d79010 0xfffff88002936000
HDAudBus.sys v1.7(6001) 0xfffffa8002e357f0 0xfffffa8002e356a0 0xfffff880037a9000
intelppm.sys v1.9(7600) 0xfffffa8002c518f0 0xfffffa8002c517a0 0xfffff880027e7000
cdrom.sys v1.9(7600) 0xfffffa80028bf8f0 0xfffffa80028bf7a0 0xfffff880011c4000
vmstorfl.sys v1.5(6000) 0xfffffa8002b2cdd0 0xfffffa8002b2cc80 0xfffff8800144a000
vdrvroot.sys v1.9(7600) 0xfffffa80027887c0 0xfffffa8002788670 0xfffff8800139c000
msisadrv.sys v1.9(7600) 0xfffffa80029c5430 0xfffffa80029c52e0 0xfffff8800135f000
Total: 1 library loaded