Kernel-Mode Driver Framework
The Kernel-Mode Driver Framework (KMDF) is a driver framework developed by Microsoft as a tool to aid driver developers create and maintain Kernel mode device drivers for Windows 2000[1] and later releases. It is one of the frameworks included in the Windows Driver Foundation. The current version is 1.7.
Relationship to WDM
In general, KMDF supports drivers that were written for the Windows Driver Model, and it runs on WDM. WDM is the driver model used since the advent of Windows 98, whereas KMDF is the driver framework Microsoft advocates and uses for Windows 2000 and beyond.
In general, since more features like Power Management and Plug and Play are handled by the framework, a KMDF driver is less complicated and has less code than an equivalent WDM driver.
KMDF is object-based, built on top of WDM. It provides an object-based perspective to WDM, following the architectural mandate of its superset, WDF. The functionality is contained in different types of objects. KMDF implementation consists of:
- Plug and Play and power management
- I/O queues
- Direct memory access (DMA)
- Windows Management Instrumentation (WMI)
- Synchronization
The driver entry point
Every driver starts with a DriverEntry function in Windows. DriverEntry, as its name suggests, is the driver entry point. In DriverEntry implementation, the WDFDRIVER object has to be instantiated, and provides WDF with the callbacks to the device driver.
NTSTATUS DriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
)
{
WDF_DRIVER_CONFIG config;
NTSTATUS status = S_OK;
KdPrint((__DRIVER_NAME "DriverEntry Begin\n"));
WDF_DRIVER_CONFIG_INIT(&config, EvtDeviceAdd);
status = WdfDriverCreate(
DriverObject,
RegistryPath,
WDF_NO_OBJECT_ATTRIBUTES,
&config, // Pointer to config structure
WDF_NO_HANDLE); // or NULL, Pointer to get WDFDRIVER handle
if(!NT_SUCCESS(status))
{
KdPrint((__DRIVER_NAME "WdfDriverCreate failed with status 0x%08x\n", status));
}
KdPrint((__DRIVER_NAME "DriverEntry End\n"));
return status;
}
Add Device
In WDF, EvtDeviceAdd event is called from the PnP manager with a handle to the WDFDRIVER object, and a pointer to a WDFDEVICE_INIT structure. The EvtDeviceAdd function is called whenever the PnP Manager detects a new device has been connected.
The driver needs to configure and initialize the device when EvtDeviceAdd event triggers this callback.
WDFSTATUS DioEvtDeviceAdd(WDFDRIVER Driver, PWDFDEVICE_INIT DeviceInit)
{
WDFSTATUS status = STATUS_SUCCESS;
WDF_PNPPOWER_EVENT_CALLBACKS pnpPowerCallbacks;
WDF_OBJECT_ATTRIBUTES objAttributes;
WDFDEVICE device;
PDIO_DEVICE_CONTEXT devContext;
WDF_IO_QUEUE_CONFIG ioCallbacks;
WDF_INTERRUPT_CONFIG interruptConfig;
WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS idleSettings;
WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnpPowerCallbacks);
pnpPowerCallbacks.EvtDevicePrepareHardware = DioEvtPrepareHardware;
pnpPowerCallbacks.EvtDeviceReleaseHardware = DioEvtReleaseHardware;
pnpPowerCallbacks.EvtDeviceD0Entry= DioEvtDeviceD0Entry;
pnpPowerCallbacks.EvtDeviceD0Exit = DioEvtDeviceD0Exit;
WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, pnpPowerCallbacks);
WDF_OBJECT_ATTRIBUTES_INIT(&objAttributes);
WDF_OBJECT_ATTRIBUTES_SET_CONTEXT_TYPE(&objAttributes, DIO_DEVICE_CONTEXT);
status = WdfDeviceInitUpdateName(DeviceInit, L"\\device\\WDFDIO");
status = WdfDeviceCreate(&DeviceInit, // Device Init structure
&objAttributes, // Attributes for WDF Device
&device); // return new WDF Device pointer,
devContext = DioGetContextFromDevice(device); // Get device extension
devContext->WdfDevice = device;
// Create a symbolic link for the control object
status = WdfDeviceCreateSymbolicLink(device, L"\\DosDevices\\WDFDIO");
WDF_IO_QUEUE_CONFIG_INIT(&ioCallbacks,
WdfIoQueueDispatchSerial,
WDF_NO_EVENT_CALLBACK, // StartIo
WDF_NO_EVENT_CALLBACK); // CancelRoutine
ioCallbacks.EvtIoDeviceControl = DioEvtDeviceControlIoctl;
status = WdfDeviceCreateDefaultQueue(device,
&ioCallbacks,
''WDF_NO_OBJECT_ATTRIBUTES'',
NULL); // pointer to default queue
WDF_INTERRUPT_CONFIG_INIT(&interruptConfig, // Configure the Interrupt object
DioIsr, // ISR
DioDpc); // Deferred Procedure Call
interruptConfig.EvtInterruptEnable = DioEvtInterruptEnable;
interruptConfig.EvtInterruptDisable = DioEvtInterruptDisable;
status = WdfInterruptCreate(device,
&interruptConfig,
&objAttributes,
&devContext->WdfInterrupt);
WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_INIT(&idleSettings, // Initialize idle policy
IdleCannotWakeFromS0);
status = WdfDeviceUpdateS0IdleSettings(device, &idleSettings);
return status;
}
Prepare Hardware
On the success of EvtDeviceAdd callback function, EvtDevicePrepareHardware is the next callback function processed by the framework, to verify that the driver can access the hardware, before the driver could be called by the subsequent operations of the framework.
NTSTATUS EvtDevicePrepareHardware(
IN WDFDEVICE Device,
IN WDFCMRESLIST ResourceList,
IN WDFCMRESLIST ResourceListTranslated
)
{
NTSTATUS status = STATUS_SUCCESS;
UNREFERENCED_PARAMETER(Device);
UNREFERENCED_PARAMETER(ResourceList);
UNREFERENCED_PARAMETER(ResourceListTranslated);
return status;
}
EvtDeviceD0Entry is next called, after EvtDevicePrepareHardware has been called. EvtDeviceD0Entry function is responsible for starting the activities that the driver is to perform during the D0 power phase. On the other hand, when the device leaves the D0 power phase, the EvtDeviceD0Exit function performs actions that are opposite to the EvtDeviceD0Entry function.
NTSTATUS EvtDeviceD0Entry(
IN WDFDEVICE Device,
IN WDF_POWER_DEVICE_STATE PreviousState
)
{
NTSTATUS status = STATUS_SUCCESS;
return status;
}
NTSTATUS EvtDeviceD0Exit(
IN WDFDEVICE Device,
IN WDF_POWER_DEVICE_STATE TargetState
)
{
NTSTATUS status = STATUS_SUCCESS;
return status;
}
IO requests
Only one IO handler is registered - EvtDeviceIoDefault, when the default IO queue is created. At this juncture, the EvtDeviceIoDefault function will accept any request, but will fail unless and until further IO functionality is implemented.
VOID EvtDeviceIoDefault(
IN WDFQUEUE Queue,
IN WDFREQUEST Request
)
{
WdfRequestComplete(Request, STATUS_NOT_IMPLEMENTED);
}
See also
Notes
- ^ . The original release of KMDF only supported Windows XP and Server 2003. Support for Windows 2000 was added in KMDF version 1.1.