- Programming Drivers for the Kernel Mode Driver Framework
- Sample Drivers by Model
- Sample Drivers by Features
- KMDF Driver Structure and Concepts
- A Minimal KMDF Driver: The Simple Toaster
- Creating a WDF Driver Object: <em>DriverEntry</em>
- Creating the Device Object, Device Interface, and I/O Queue: EvtDriverDeviceAdd
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 area.
- 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 areas, 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_SCCESS; 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 = WdfDevice(CreateDeviceInterface ( 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; }
Conclusion
You can see from this article’s discussion that the sample drivers can give you a good place to start the development of your Kernel Mode driver.