Jump to content

Kernel-Mode Driver Framework

From Wikipedia, the free encyclopedia
This is an old revision of this page, as edited by N1cholson (talk | contribs) at 17:20, 16 June 2008 (Relationship to WDM: Made link to synchrization unambiguous). The present address (URL) is a permanent link to this revision, which may differ significantly from the current revision.

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:

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

  1. ^ . The original release of KMDF only supported Windows XP and Server 2003. Support for Windows 2000 was added in KMDF version 1.1.

References