Porting AddDevice to EvtDriverDeviceAdd
Every Kernel-Mode Driver Framework (KMDF) or User-Mode Driver Framework (UMDF) driver that supports Plug and Play must have an EvtDriverDeviceAdd callback, which is the functional equivalent of a WDM driver’s AddDevice function.
A WDM AddDevice function creates the device object, creates the device interfaces, and initializes WMI but also initializes numerous variables in the driver’s device extension. WDM drivers typically defer the creation of I/O queues and the interrupt object until the DispatchPnP function is called to handle an IRP_MN_START_DEVICE request.
The framework-based driver’s EvtDriverDeviceAdd callback creates a WDFDEVICE object to represent the device that has just been enumerated. It also performs numerous additional initialization tasks to provide the framework with the information that it requires to set up its own internal structures and the underlying WDM structures.
As a result, for most framework-based drivers the EvtDriverDeviceAdd callback is significantly longer than the corresponding WDM AddDevice function. In a framework-based driver, nearly all of the device’s initialization code is in the EvtDriverDeviceAdd function. However, in the WDM version, the initialization code tends to be spread out through multiple functions in the driver.
The code in EvtDriverDeviceAdd appears in the following order:
- Fill in the WDFDEVICE_INIT structure, which supplies information that is used to create the device object. For more information about using WDFDEVICE_INIT, see Creating a Framework Device Object.
- Set up the device object’s context area, which is analogous to the WDM device extension.
- Create the device object.
- Perform additional initialization and start-up tasks, such as creating I/O queues and interrupt objects.
A KMDF bus driver typically creates multiple device objects: an FDO for its role as the function driver for the bus itself and a PDO for each child device that is attached to the bus. The framework calls the driver’s EvtDriverDeviceAdd function when the system enumerates the bus. The driver itself then enumerates its child devices and creates PDOs to represent them. KMDF supports both static and dynamic enumeration of child devices. It also includes additional PDO-specific features.
Drivers typically require storage that is associated with a device object to maintain pointers and object-specific data. In a WDM driver, the DeviceExtension field of the DEVICE_OBJECT structure provides such storage. In a framework-based driver, the object context area of the WDFDEVICE object serves the same purpose.
For information about allocating and accessing context space for framework objects, see Framework Object Context Space.
A WDM driver creates a DEVICE_OBJECT structure to represent each device object and attaches the device object to the Plug and Play device stack. Framework-based drivers also create device objects, which are referred to by using WDFDEVICE handles.
After the WDF driver calls the required initialization methods, it sets attributes for the device object (typically, the size and type of the context area) and then calls WdfDeviceCreate to create the device object. WdfDeviceCreate creates a WDFDEVICE object and an underlying WDM DEVICE_OBJECT, attaches the WDM DEVICE_OBJECT to the device stack, and returns a handle to the WDFDEVICE object.
After the framework-based driver creates the device object, it should:
- Create I/O queues and specify request handlers for the device object.
- Create device interfaces.
- Set device idle policy and wake settings, if the device object owns power policy.
- Create an interrupt object, if the hardware supports interrupts.
- Initialize WMI.†
† This functionality is only available to KMDF drivers.
A framework-based driver should set up the I/O queues and create the interrupt object in the EvtDriverDeviceAdd callback, immediately after creating the device object. The framework connects the interrupt object and starts the queues at the appropriate time later, during start-device processing.
A driver that controls a bus typically creates multiple device objects: an FDO for its role as the function driver for the bus itself and a PDO for each child device that is attached to the bus. KMDF supports both static and dynamic enumeration of child devices. It also includes additional PDO-specific features.
The framework invokes the driver’s EvtDriverDeviceAdd function when the Plug and Play manager enumerates the bus. EvtDriverDeviceAdd creates an FDO for the bus, and then enumerates the child devices and creates a PDO for each one. The driver can enumerate the child devices either statically or dynamically.
Certain callback functions apply only to device objects that represent PDOs. When the driver initializes the device object, it registers the corresponding callbacks. PDOs respond to queries about device resources and resource requirements, requests to lock or eject the device, and requests to enable and disable the device wake signal.
In WDM drivers, these requests arrive as minor IRP codes in an IRP_MJ_PNP or IRP_MJ_POWER request. KMDF drivers handle them by implementing callbacks and registering the callbacks during device object initialization by calling WdfPdoInitSetEventCallbacks. The following table lists the PDO-specific callbacks:
|KMDF callback||WDM IRP|
Additional WdfPdoInitXxx methods enable the driver to specify device-specific data, such as device IDs.