1.2 Input and Output Parameters for Common I/O Requests
Device drivers handle IRPs set with some or all of the following major function codes:
IRP_MJ_CREATE
IRP_MJ_CLEANUP
IRP_MJ_CLOSE
IRP_MJ_READ
IRP_MJ_WRITE
IRP_MJ_FLUSH_BUFFERS
IRP_MJ_SHUTDOWN
IRP_MJ_DEVICE_CONTROL //with device-type-specific
//(public) I/O control codes
IRP_MJ_INTERNAL_DEVICE_CONTROL //with device-specific
//or driver-specific I/O control codes
As a general rule, an intermediate driver must handle at least the same IRP_MJ_XXX as the next-lower driver. That is, an intermediate driver must provide a Dispatch entry point for every IRP_MJ_XXX that the I/O Manager or a higher-level driver might send to the underlying device.
The specific operations a driver carries out for a given IRP_MJ_XXX depends somewhat on the underlying device, particularly for IRP_MJ_DEVICE_CONTROL and IRP_MJ_INTERNAL_DEVICE_CONTROL requests. However, the I/O Manager defines the parameters and I/O stack location contents for each major function code that it sets in IRPs.
The rest of this section summarizes request-specific information about parameters for the IRP_MJ_XXX that device and intermediate drivers handle, as well as general information about what kinds of drivers must handle each type of request and how they satisfy each type of request. See also Chapter 12 in Part I of this manual for more information about the IRP, I/O stack location, and I/O status block structures.
The input and output parameters described in this section are the function-specific parameters in the IRP.
IRP_MJ_CREATE
Every kernel-mode driver must handle create requests.
Input Parameters
None
Output Parameters
None
When Sent
Receipt of this request indicates that a user-mode protected subsystem, possibly on behalf of an application, has requested a handle for the file object that represents the target device object, or that a higher-level driver is connecting or attaching its device object to the target device object.
Operation
Many device and intermediate drivers merely set STATUS_SUCCESS in the I/O status block of the IRP and complete the create request. However, what a given driver does on receipt of a create request depends on the driver’s design. For example, a driver with pageable-image sections, like the system serial driver, maps in its paged-out code and allocates any resources necessary to handle subsequent I/O requests for the user-mode thread that is attempting to open the device for I/O.
IRP_MJ_CLEANUP
Drivers that have Cancel routines also must handle cleanup requests.
Input Parameters
None
Output Parameters
None
When Sent
Receipt of this request indicates that the handle for the file object, representing the target device object, is being released.
Operation
If the driver’s device objects were set up as exclusive, thereby allowing only a single thread to use the device at any given time, the driver completes every IRP currently queued to the target device object with STATUS_CANCELLED set in each IRP’s I/O status block. Otherwise, the driver must cancel and complete any currently queued IRPs for the holder of the file object handle that is being released. After cancelling outstanding IRPs in the queue, the driver completes the cleanup IRP with STATUS_SUCCESS set in its I/O status block.
IRP_MJ_CLOSE
Every Windows NT driver must handle close requests, with the possible exception of a driver whose device cannot be disabled or removed from the machine without bringing down the system. A disk driver whose device holds the system page file is an example of such a driver. Note that the driver of such a device also cannot be unloaded dynamically.
Input Parameters
None
Output Parameters
None
When Sent
Receipt of this request indicates that the handle of the file object that represents the target device object has been released.
Operation
Many device and intermediate drivers merely set STATUS_SUCCESS in the I/O status block of the IRP and complete the close request. However, what a given driver does on receipt of a close request depends on the driver’s design. In general, a driver should undo whatever actions it takes on receipt of the create request. Device drivers whose device object(s) are exclusive, such as a serial driver, also can reset the hardware on receipt of a close request
IRP_MJ_READ
Every device driver that transfers data from its device to the system must handle read requests, as must any higher-level driver layered over such a device driver.
Input Parameters
The driver’s I/O stack location in the IRP indicates how many bytes to transfer at Parameters.Read.Length.
Some drivers use the value at Parameters.Read.Key to sort incoming read requests into a driver-determined order in the device queue or in a driver-managed internal queue of IRPs. Certain types of drivers also use the value at Parameters.Read.ByteOffset, which indicates the starting offset for the transfer operation.
Output Parameters
Depending on whether the underlying device driver sets up the target device object’s Flags with DO_BUFFERED_IO or with DO_DIRECT_IO, data is transferred into one of the following:
·The buffer at Irp->AssociatedIrp.SystemBuffer if the driver uses buffered I/O
·The buffer described by the MDL at Irp->MdlAddress if the underlying device driver uses direct I/O (DMA or PIO)
When Sent
Any time following the successful completion of a create request
Possibly, a user-mode application or Win32® component with a handle for the file object representing the target device object has requested a data transfer from the device. Possibly, a higher-level driver has created and set up the read IRP.
Operation
On receipt of a read request, a higher-level driver sets up the I/O stack location in the IRP for the next-lower driver, or it creates and sets up additional IRP(s) for one or more lower drivers. It can set up its IoCompletion routine, which is optional for the input IRP but required for driver-created IRPs, by calling IoSetCompletionRoutine. Then, the driver passes the request on to the next-lower driver with IoCallDriver.
On receipt of a read request, a device driver transfers data from its device to system memory. The device driver sets the Information field of the I/O status block to the number of bytes transferred when it completes the IRP.
IRP_MJ_WRITE
Every device driver that transfers data from the system to its device must handle write requests, as must any higher-level driver layered over such a device driver.
Input Parameters
The driver’s I/O stack location in the IRP indicates how many bytes to transfer at Parameters.Write.Length.
Some drivers use the value at Parameters.Write.Key to sort incoming write requests into a driver-determined order in the device queue or in a driver-managed internal queue of IRPs. Certain types of drivers also use the value at Parameters.Write.ByteOffset, which indicates the starting offset for the transfer operation.
Depending on whether the underlying device driver sets up the target device object’s Flags with DO_BUFFERED_IO or with DO_DIRECT_IO, data is transferred from one of the following:
·The buffer at Irp->AssociatedIrp.SystemBuffer if the driver uses buffered I/O
·The buffer described by the MDL at Irp->MdlAddress if the underlying device driver uses direct I/O (DMA or PIO)
Output Parameters
None
When Sent
Any time following the successful completion of a create request
Possibly, a user-mode application or Win32 component with a handle for the file object representing the target device object has requested a data transfer to the device. Possibly, a higher-level driver has created and set up the write IRP.
Operation
On receipt of a write request, a higher-level driver sets up the I/O stack location in the IRP for the next-lower driver, or it creates and sets up additional IRP(s) for one or more lower drivers. It can set up its IoCompletion routine, which is optional for the input IRP but required for driver-created IRPs, by calling IoSetCompletionRoutine. Then, the driver passes the request on to the next-lower driver with IoCallDriver.
On receipt of a write request, a device driver transfers data from system memory to its device. The device driver sets the Information field of the I/O status block to the number of bytes transferred when it completes the IRP.
IRP_MJ_FLUSH_BUFFERS
Drivers of devices with internal caches for data and drivers that maintain internal buffers for data must handle this request.
Input Parameters
None
Output Parameters
None
When Sent
Receipt of a flush request indicates that the driver should flush the device’s cache or its internal buffer, or, possibly, should discard the data in its internal buffer.
Operation
The driver transfers any data currently cached in the device or held in the driver’s internal buffer(s) before completing the flush request. The driver of an input-only device that buffers data internally might simply discard the currently buffered device data before completing the flush IRP, depending on the nature of its device.
IRP_MJ_SHUTDOWN
Drivers of mass-storage devices that have internal caches for data must handle this request. Drivers of mass-storage devices and intermediate drivers layered over them also must handle this request if an underlying driver maintains internal buffers for data.
Input Parameters
None
Output Parameters
None
When Sent
Receipt of a shutdown request indicates that a file system driver is sending notice that the system is being shut down.
One or more file system drivers can send such a lower-level driver more than one shutdown request when a user logs off or when the system is being shut down for some other reason.
Operation
The driver must complete the transfer of any data currently cached in the device or held in the driver’s internal buffer(s) before completing the shutdown request.
IRP_MJ_DEVICE_CONTROL
Every driver whose device objects are of the same type (see Section 1.1), is required to support this request. Every higher-level driver usually passes these requests on to an underlying device driver. Each device driver of a given type is assumed to support this request and a device-type-specific set of system-defined (also called public) I/O control codes (IOCTL_XXX) that determine what the driver does on receipt of this request.
Input Parameters
Depending on the I/O control code at Parameters.DeviceIoControl.IoControlCode in the driver’s I/O stack location of the IRP, can be one of the following:
1.Caller-supplied data in the buffer at Irp->AssociatedIrp.SystemBuffer, together with the buffer’s size in the I/O stack location at Parameters.DeviceIoControl.InputBufferLength and/or a pointer to an additional input buffer in the I/O stack location at Parameters.DeviceIoControl.Type3InputBuffer
2.Caller-supplied data in the buffer described by the MDL at
Irp->MdlAddress, with the buffer’s size in the I/O stack location at Parameters.DeviceIoControl.InputBufferLength if the lowest-level driver’s device uses DMA or PIO and if the requested operation requires the transfer of a large amount of data quickly
3.Parameters.DeviceIoControl.OutputBufferLength in the I/O stack location of the IRP indicates the size in bytes of the buffer into which the driver transfers data
Output Parameters
Also determined by the I/O control code in the I/O stack location of the IRP
Data can be written into the buffer at Irp->AssociatedIrp.SystemBuffer or, using DMA or PIO, into the buffer described by the MDL at
Irp->MdlAddress, as long as the transfer does not exceed the buffer’s size.
When Sent
Any time following the successful completion of a create request
A user-mode thread has called the Win32 DeviceIoControl function, or a higher-level kernel-mode driver has set up the request. Possibly, a user-mode driver has called DeviceIoControl, passing in a driver-defined (also called private) I/O control code, to request device- or driver-specific support from a closely coupled, kernel-mode device driver.
Operation
On receipt of a device I/O control request, a higher-level driver usually passes the IRP on to the next-lower driver. However, there are some exceptions to this practice. For example, a class driver that has stored configuration information obtained from the underlying port driver might complete certain IOCTL_XXX requests without passing the IRP down to the corresponding port driver.
On receipt of a device I/O control request, a device driver examines the I/O control code to determine how to satisfy the request. For most public I/O control codes, device drivers transfer a small amount of data to or from the buffer at Irp->AssociatedIrp.SystemBuffer.
IRP_MJ_INTERNAL_DEVICE_CONTROL
In general, any replacement for an existing driver that supports internal device control requests should handle this request. Such a driver also should support at least the same set of internal I/O control codes as the driver it replaces. Otherwise, existing higher-level drivers might not work with the new driver.
Drivers that replace certain lower-level system drivers are required to handle this request. For example, a replacement for the system parallel port driver must continue to support existing parallel class drivers. Note that certain system drivers that handle this request cannot be replaced, in particular, the system-supplied SCSI and video port drivers.
Input Parameters
Depending on the I/O control code at Parameters.DeviceIoControl.IoControlCode in the I/O stack location of the IRP, can be one of the following:
1.Caller-supplied data in the buffer at Irp->AssociatedIrp.SystemBuffer, together with the buffer’s size in the I/O stack location at Parameters.DeviceIoControl.InputBufferLength and/or a pointer to an additional input buffer in the I/O stack location at Parameters.DeviceIoControl.Type3InputBuffer
2.Caller-supplied data in the buffer described by the MDL at
Irp->MdlAddress, with the buffer’s size in the I/O stack location at Parameters.DeviceIoControl.InputBufferLength if the lowest-level driver’s device uses DMA or PIO and if the requested operation requires the transfer of a large amount of data quickly
3.Parameters.DeviceIoControl.OutputBufferLength in the I/O stack location of the IRP indicates the size in bytes of the buffer into which the driver transfers data
Output Parameters
Also determined by the I/O control code in the I/O stack location of the IRP
Data can be written into the buffer at Irp->AssociatedIrp.SystemBuffer or, using DMA or PIO, into the buffer described by the MDL at
Irp->MdlAddress, as long as the transfer does not exceed the buffer’s size.
When Sent
Any time after the successful completion of a create request
For this request, the I/O control code (IOCTL_INTERNAL_XXX) has been defined for communication between paired and layered kernel-mode drivers, such as one or more class drivers layered over a port driver. The higher-level driver sets up IRPs with device- or driver-specific I/O control codes, requesting support from the next-lower driver.
Operation
The requested operation is device- or driver-specific.
For general information about I/O control codes for IRP_MJ_DEVICE_CONTROL or IRP_MJ_INTERNAL_DEVICE_CONTROL requests, see Section 1.3. For more information about device-type-specific I/O control codes, see Section 1.4.