4.2. Creating the Device Object, Device Interface, and I/O Queue: EvtDriverDeviceAdd
Every KMDF driver that supports Plug and Play must have an EvtDriverDeviceAdd
callback function, which is called each time the system enumerates a
device that belongs to the driver. This callback performs actions
required at device enumeration, such as the following:
Creates and initializes a device object (WDFDEVICE) and corresponding context areas.
Sets entry points for the driver’s Plug and Play and power management callbacks.
Creates a device interface.
Configures and creates one or more I/O queues.
Creates an interrupt object, if the device controls physical hardware that generates interrupts.
The EvtDriverDeviceAdd function is called with two parameters: a handle to the WDFDRIVER object that the driver created during DriverEntry and a handle to a WDFDEVICE_INIT object.
The Simple Toaster
does not control hardware, so it does not set Plug and Play or power
management callbacks, nor does it create an interrupt object. Its EvtDriverDeviceAdd
callback creates the device object and context area, device interface,
and a single default I/O queue. The following shows the source code for
this function:
NTSTATUS
ToasterEvtDeviceAdd(
IN WDFDRIVER Driver,
IN PWDFDEVICE_INIT DeviceInit
)
{
NTSTATUS status = STATUS_SUCCESS;
PFDO_DATA fdoData;
WDF_IO_QUEUE_CONFIG queueConfig;
WDF_OBJECT_ATTRIBUTES fdoAttributes;
WDFDEVICE hDevice;
WDFQUEUE queue;
UNREFERENCED_PARAMETER(Driver);
PAGED_CODE();
KdPrint(("ToasterEvtDEviceAdd called\n"));
//
// Initialize attributes and a context area for the
// device object.
//
//
WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE
(&fdoAttributes, FDO_DATA);
//
// Create a framework device object.
status = WdfDEviceCreate(&DeviceInit, &fdoAttributes,
&hDevice);
if(!NT_SUCCESS(status)) {
KdPrint(("WdfDeviceCreate failed with status code"
"0x%x\n", status));
return status;
}
// Get the device context by using the accessor function
// specified in the WDF_DECLARE_CONTEXT_TYPE_WITH_NAME
// macro for FDO_DATA.
//
fdoData = ToasterFdoGetData(hDevice);
//
// Create device interface.
//
status = WdfDEviceCreateDeviceInterface(
hDevice,
(LPUID) &GUID)DEVINTERFACE_TOASTER,
NULL // Reference String
);
if(!NT_SUCCESS(status)) {
KdPrint(("WdfDeviceCreateDeviceInterface failed
"0x%x\n", status));
return status;
}
//
// Configure the default I/O queue.
//
WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&queueConfig,
WdfIoQueueDispatchParallel);
// Register I/O callbacks for IRP_MJ_READ, IRP_MJ_WRITE,
// and IRP_MJ_DEVICE_CONTROL request.
queueConfig.EvtIoRead = ToasterEvtIoRead;
queueConfig.EvtIoWrite = ToasterEvtIoWrite;
queueConfig.EvtIoDeviceControl =
ToasterEvtIoDeviceControl;
// Create the queue.
status = WdfIoQueueCreate (
hDevice,
&queueConfig,
WDF_NO_OBJECT_ATTRIBUTES,
&queue
);
if(!NT_SUCCESS (status)) {
KdPrint(("WdfIoQueueCreate failed 0x%x\n, status));
return status;
}
return status;
}
The following discussions step through the actions of this function.