Jump to content

Kernel-Mode Driver Framework

From Wikipedia, the free encyclopedia

This is an old revision of this page, as edited by 62.40.79.66 (talk) at 11:27, 8 September 2009 (The driver entry point: bad wiki markup). 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