6.3.4.1 DispatchDeviceControl in Lowest-Level Drivers
An IRP_MJ_DEVICE_CONTROL request for a lowest-level NT driver either requires the driver to change the state of its device or to provide information about the state of its device. Because most kinds of NT drivers are required to handle a number of I/O control codes, their DispatchDeviceControl routines usually contain a switch statement somewhat like the following:
: :
switch(irpSp->Parameters.DeviceIoControl.IoControlCode) {
case IOCTL_DeviceType_XXX:
case IOCTL_DeviceType_YYY:
if (irpSp->Parameters.DeviceIoControl.InputBufferLength <
(sizeof(IOCTL_XXXYYY_STRUCTURE))) {
status = STATUS_BUFFER_TOO_SMALL;
break;
} else {
IoMarkIrpPending(Irp);
: : // pass IRP on for further processing
case ...
: :
As this code fragment shows, a DispatchDeviceControl routine also checks parameters, sometimes on each I/O control code that the driver must support, sometimes on groups of these IOCTL_XXX.
Consider these implementation guidelines for device drivers' DispatchDeviceControl routines:
·As for any IRP and driver Dispatch routine, DispatchDeviceControl must check the parameters for validity and complete IRPs with parameter errors immediately, as described in Section 6.2.3.
·Switching first on any I/O control codes for which the DispatchDeviceControl routine can satisfy and complete the IRP improves performance because the driver can return control faster.
For better performance, every NT device driver should satisfy any device control request that it can, without queueing the IRP to other driver routines, in its DispatchDeviceControl routine.
·Switching later on I/O control codes that specify infrequently requested operations also can improve the driver's performance in processing IRP_MJ_DEVICE_CONTROL_REQUESTS.
·Grouping cases of I/O control codes as possible when testing for valid parameters is economical both in term of driver performance/size and in code maintenance. As the preceding code fragment suggests, I/O control codes that use a common structure are natural candidates for such a case group.
For those IRPs that the DispatchDeviceControl routine can complete, it should call IoCompleteRequest with a PriorityBoost of IO_NO_INCREMENT. The DispatchDeviceControl routine must call IoMarkIrpPending with each request that it queues for further processing on the device and it must return STATUS_PENDING.