1. Required Driver Functionality
Every UMDF driver must provide the following functionality:
Support the DllMain export as its primary entry point.
The driver must support DllMain as its primary entry point. After the system creates the UMDF driver host process, the host process loads the driver by calling the DllMain
function. In a UMDF driver, this function does very little; typically,
it enables tracing and then returns. As in all DLLs, the driver must not
make blocking calls such as WaitForSingleObject, which can deadlock the system. Drivers should defer resource allocation to IDriverEntry::OnInitialize, instead of DllMain.
Support the DllGetClassObject export, which must return a pointer to an IClassFactory interface that creates an instance of the driver callback object.
The driver must also support the DllGetClassObject function, which COM requires. This function returns a pointer to an IClassFactory
interface with which UMDF can create an instance of the driver callback
object. The UMDF sample drivers show how to implement this function.
Alternatively, the Active Template Library (ATL) wizard can be used to
generate the supporting COM code.
Implement the IDriverEntry interface on the driver class.
Finally, every User Mode WDF driver must implement the IDriverEntry
interface on the driver class. This interface includes methods that
initialize and uninitialize driver-wide data. UMDF calls the OnInitialize method when the first device for the driver is loaded and calls the OnDeinitialize method when the driver is unloaded. IDriverEntry also includes the OnAddDevice method, which UMDF calls when the Plug and Play manager enumerates one of the driver’s devices.
Figure 1 shows the interactions of the functionality of a driver with UMDF and the system.
When the system starts, the driver manager is loaded and the following actions occur:
The driver manager creates the driver host process and then loads the driver library by calling the DllMain entry point. DllMain performs any required global initialization for the driver, such as starting tracing.
UMDF creates a framework driver object and calls the driver at DllGetClassObject to get an interface that I can use to create a corresponding callback object in the driver. DllGetClassObject returns a pointer to the driver’s IClassFactory interface.
UMDF calls the CreateInstance method of the IClassFactory
interface to create an instance of the driver callback object. The
driver callback object implements methods to initialize the driver, to
notify it that one of its devices has been enumerated, and to prepare it
for unloading.
UMDF calls the OnInitialize method of the driver callback object to initialize the driver.
Whenever one of the driver’s devices is enumerated, UMDF calls OnDeviceAdd. OnDeviceAdd
performs any required configuration, creates a device callback object
to represent the device, creates any required device interfaces, and
creates and configures the queues into which UMDF will place I/O
requests that are targeted at the driver. A device interface is a device
feature that driver exposes to applications or other system components,
whereas a COM interface is a related group of functions that act on an
object.
UMDF queries for the Plug and Play and queue interfaces that it will use to handle I/O requests.
When
the device is removed, UMDF calls the Plug and Play methods that are
appropriate for the type of removal (orderly or surprise), deletes the
objects, and calls the IDriverEntry::OnDeinitialize method to clean up. It then unloads the DLL and deletes the driver host process.
2. UMDF Sample Drivers
The UMDF release for Windows 7
includes several sample User Mode Drivers, which are installed at
WDF\UMDF\src in the Windows Driver Kit (WDK) installation directory. You
can use these samples as the basis for your own driver. Table 1 lists the UMDF samples.
Table 1. List of UMDF Sample Drivers
Name | Description |
---|
Skeleton | Minimal software-only driver that shows the structure and fundamental components of a simple UMDF driver. |
Echo | Simple
driver that uses a serial I/O queue and handles one I/O request at a
time. The Echo sample defers the completion of each I/O request to a
worker thread and shows how to mark a request cancelable while it is
pending in the driver. This sample was adapted from the KMDF Echo sample
and is functionally similar to the WDM sample of the same name. |
USB\Driver | Hardware
driver for the USB-FX2 Learning Kit from OSR. This sample supports a
parallel I/O queue. It is similar to the Echo sample, but can handle
multiple independent requests at one time. This driver also demonstrates
how a User Mode Driver controls a device. It uses the memory in the
OSR-USBFx2 device as a buffer and uses the WinUSB API and WinUSB Kernel
Mode Driver to control the hardware. The driver demonstrates how to
escape from UMDF and send I/O by using an alternate path and how to
synchronize I/O on the alternate path with cancellation and file
closure. |
USB\Filter | Filter
driver for the WinUSB driver stack. This sample modifies the data in
read and write requests as they flow through the device stack and uses
I/O targets to communicate with a lower driver. |
Use the WDK build environment to build the samples. To build a particular sample:
1. | Start a build environment window.
|
2. | Set the working directory to the directory that contains the sample to build.
|
3. | Type the following command: build –ceZ
|
2.1. Minimal UMDF Driver: The Skeleton Driver
The Skeleton driver
contains the minimum amount of code that is required in a loadable UMDF
driver. It was designed as a starting point from which to build drivers
for actual hardware. In addition to demonstrating the minimal required
features and best practices, the Skeleton driver splits into appropriate
modules the common code that is required in all UMDF drivers.
The Skeleton driver supports a
driver entry point, functions to create and initialize the driver and
device callback objects, and functions for COM support. It does not
support any I/O or Plug and Play operations. Table 2 lists the component source files.
Table 2. Component Source Files
Filename | Description |
---|
Comsup.cpp | Source code for the CUnknown and CClassFactory classes. |
Comsup.h | Header file for COM support functions and classes. |
Device.cpp | Source code for the device callback object class, CMyDevice. |
Device.h | Header file for the device callback object. |
Dllsup.cpp | Source code for the driver entry point and exported COM support functions. |
Driver.cpp | Source code for the driver callback object class, CMyDriver. |
Driver.h | Header file for the driver callback object. |
Exports.def | Definition file that identifies the library name and exported entry point for driver. |
Internal.h | Header file for local type definitions. |
Makefile | Generic makefile for building the sample. |
Makefile.inc | Additional commands input to the makefile. |
Skeleton.htm | Help file that describes the sample. |
Skeleton.rc | Resource file for the sample. |
Sources | Source file for the build procedure. |
UMDF_Skeleton_OSR.inx | INF that installs the Skeleton sample as a driver for the OSR USBFX2 device. |
UMDF_Skeleton_OSR_xp.inx | INF that installs the Skeleton sample as a driver for the OSR USBFX2 device on Windows 7. |
UMDF_Skeleton_root.inx | INF that installs the Skeleton sample as a driver for a root-enumerated device. |
UMDF_Skeleton_root_xp.inx | INF that installs the Skeleton sample as a driver for a root-enumerated device on Windows 7. |
2.2. Skeleton Driver Classes, Objects, and Interfaces
The Skeleton driver implements the four classes that are listed in Table 3.
Table 3. Classes Implemented in Skeleton Driver
Class Name | Description | Public Interfaces |
---|
CUnknown | Base Class from which others derive | IUnknown |
CClassFactory | Class factory that instantiates the driver class | IClassFactory |
CMyDriver | Driver callback object class | IDriverEntry IUnknown |
CMyDevice | Device callback object | IUnknown |
Figure 2 shows how the objects that are instantiated from these classes interact with the corresponding framework objects.
As Figure 2 shows, the framework implements a driver object and a device object. The framework’s driver object uses the IDriverEntry interface on the Skeleton driver’s CMyDriver object, and the CMyDriver object, in turn, uses the IWdfDriver interface on the framework’s driver object. The framework’s device object exposes the IWdfDevice and IWdfDeviceInitialize interfaces, which the driver’s CMyDevice object uses. The Skeleton driver’s CMyDevice
class does not implement additional interfaces because it does not
support hardware or handle I/O requests. The device object in a typical
driver would implement additional interfaces for Plug and Play
notifications, I/O requests, I/O queues, and so forth.