In general, only a subset of device I/O control requests are passed on from the DispatchDevice(Internal)Control routine for further processing by a device driver’s StartIo routine. That is, any device driver’s StartIo routine must handle only valid device control requests that require device state changes or return volatile information about the current state of the device.
Each new NT device driver must support the same set of public I/O control codes as all other NT drivers for the same kind of device. The system defines public, device-type-specific I/O control codes for IRP_MJ_DEVICE_CONTROL requests as buffered requests.
Consequently, NT device drivers make data transfers to or from a system-space buffer that each driver finds in the IRP at Irp->AssociatedIrp.SystemBuffer for device control requests. Even NT drivers that set up their device objects for direct I/O use buffered I/O to satisfy device control requests with public I/O control codes.
The definition of each I/O control code determines whether data transferred for that request is buffered. Any privately defined I/O control codes for driver-specific IRP_MJ_INTERNAL_DEVICE_CONTROL requests between paired NT drivers can define a code with method buffered, method direct, or method neither. As a general rule, any privately defined I/O control code should be defined with method neither if a closely coupled higher-level NT driver must allocate a buffer for that request.
For more information about the I/O control codes that a new driver for any common type of PC device must support and about defining private I/O control codes, see the Kernel-mode Driver Reference.