4. A Minimal KMDF Driver: The Simple Toaster
The Simple Toaster sample provided in toaster\func\simple
is a minimal, software-only function driver. It creates a driver
object, a device object, a device interface, and a single I\O queue.
The driver handles read, write, and device I/O control requests that
are targeted at its device.
This minimal driver includes the following functions:
A DriverEntry routine, which creates the driver object.
An EvtDriverDeviceAdd event callback, which creates the device object, a device interface, and a default I/O queue.
I/O callback functions for read, write, and device I/O control requests.
The driver does not manage any physical hardware, so
no code to support Plug and Play or power management is required; the
driver uses the WDF defaults.
4.1. Creating a WDF Driver Object: DriverEntry
Every KMDF driver must have a DriverEntry routine. The DriverEntry routine is the first driver function called when the driver is loaded. The KMDF DriverEntry routine has the same prototype as that of a WDM driver:
NTSTATUS
DriverEntry(
IN PDRIVER_OBJECT DriverObject,
In PUNICODE_STRING RegistryPath
);
The DriverEntry routine performs the following tasks:
Creates a driver object (WDFDRIVER),
which represents the loaded instance of the driver in memory. In
effect, creating this object “registers” the driver with KMDF.
Registers the driver’s EvtDriverDeviceAdd callback. KMDF calls this function during device enumeration.
Optionally initializes event tracing for the driver.
Optionally allocates resources that are required on a driver-wide (rather than per-device) basis.
The following shows the DriverEntry function for the Simple Toaster sample:
NTSTATUS
DriverEntry(
IN PDRIVER_OBJ DriverObject,
IN PUNICODE_STRING RegistryPath
)
{
NTSTATUS status = STATUS_SUCCESS;
WDF_DRIVER_CONFIG config;
KdPrint(("Toaster Function Driver Sample-"
Driver Framework Edition.\n));
KdPrint(("Built %s %s\n", __DATE__, __TIME__));
WDF_DRIVER_CONFIG_INIT(
&config,
ToasterEvtDeviceAdd
);
//
// Create a framework driver object.
//
Status = WdfDriverCreate(
DriverObject,
RegistryPath,
WDF_NO_OBJECT_ATTRIBUTES // Driver Attributes
&config, // Driver Config Info
WDF_NO_HANDLE
);
if ( !NT_SUCCESS(status)) {
KdPrint(("WdfDriverCreate failed with"
"status 0x%x\n", status));
}
return status;
}
Before creating the WDFDRIVER object, the driver must initialize a driver-object configuration structure (WDF_DRIVER_CONFIG) by using the WDF_DRIVER_CONFIG_INIT function. The function zeroes the structure and then initializes it with a pointer to the driver’s EvtDriverDeviceAdd callback function, which is named ToasterEvtDeviceAdd. KMDF calls this function during device enumeration, when it handles an add-device request that is targeted at the driver.
After setting up the configuration structure, DriverEntry calls WdfDriverCreate to create the WDFDRIVER object, passing as parameters the DriverObject and RegistryPath
that were supplied to it, a pointer to the driver object attributes,
and a pointer to the filled-in driver configuration structure. The
framework’s default attributes are acceptable for the Simple Toaster’s WDFDRIVER object, so the sample specifies WDF_NO_OBJECT_ATTRIBUTES, which KMDF defines as NULL.
WdfDriverCreate can optionally return a handle to the created WDFDRIVER object. The Simple Toaster driver does not require a local copy of this handle, so instead of passing a location to receive the handle, it passes WDF_NO_HANDLE, which is a null pointer.
A WDM driver would typically save pointers to the DriverObject and RegistryPath, but a KMDF driver does not require them because KMDF maintains this information on behalf of the driver.