For every common type of peripheral device, the system defines a set of I/O control codes for IRP_MJ_DEVICE_CONTROL requests that new drivers for each type of device must support. In most cases, these public I/O control codes for a given type of device are not exported to user-mode applications.
Some of these system-defined I/O control codes are used by higher-level NT drivers that create IRPs with IoBuildDeviceIoControlRequest for the underlying device driver. Others are used by Win32 drivers or particular Win32 components to communicate with an underlying device driver by calling the Win32 function DeviceIoControl. In turn, this Win32 function calls an NT system service, and the I/O Manager sets up an IRP with the major function code IRP_MJ_DEVICE_CONTROL and the given I/O control code in the I/O stack location at Parameters.DeviceIoControl.IoControlCode. Then, the I/O Manager calls the DispatchDeviceControl routine of the highest-level driver in the chain with the IRP.
For certain system-supplied drivers designed to interoperate with and support new NT drivers, Windows NT® also defines a set of I/O control codes for IRP_MJ_INTERNAL_DEVICE_CONTROL requests. In most cases, these public I/O control codes allow add-on higher-level NT drivers to interoperate with an underlying device driver.
For example, the IOCTL_SCSI_GET_INQUIRY_DATA and IOCTL_SCSI_GET_CAPABILITIES codes support the initialization and configuration of NT SCSI class drivers. SCSI class drivers send these device control requests down to the NT SCSI port driver to find SCSI peripheral devices of each class driver’s type and, for those SCSI buses with a connected peripheral of the class driver’s type, to collect relevant information about the underlying SCSI miniport’s HBA, such as its maximum transfer capacity and maximum number of page breaks per DMA transfer operation.
As another example, the system parallel port driver supports a set of public I/O control codes that add-on parallel class drivers set up in IRP_MJ_INTERNAL_DEVICE_CONTROL requests to communicate with their devices through a parallel port. The system parallel port driver can be replaced, as long as such a new NT parallel port driver continues to support the same set of internal device control requests for use by existing and new NT parallel class drivers.
Almost all system-defined I/O control codes are defined to use buffered I/O, because this type of request seldom requires the transfer of large amounts of data. That is, even drivers that set up their device objects for direct I/O are sent IRPs for device control requests with data to be transferred in(to) the buffer at Irp->AssociatedIrp.SystemBuffer, except for certain types of highest-level device drivers with closely coupled Win32 multimedia drivers.
NT driver writers can define a set of private I/O control codes that their written-together drivers can use to communicate with each other. New public I/O control codes can be added to the system only with the cooperation of Microsoft Corporation, because public I/O control codes are built into Windows NT itself.
For specific information about the set of public I/O control codes that different kinds of NT drivers must support and about defining private I/O control codes, see the Kernel-mode Driver Reference.