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.
Every kernel-mode driver must handle create requests.
None
None
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.
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.
Drivers that have Cancel routines also must handle cleanup requests.
None
None
Receipt of this request indicates that the handle for the file object, representing the target device object, is being released.
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.
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.
None
None
Receipt of this request indicates that the handle of the file object that represents the target device object has been released.
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
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.
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.
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:
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.
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.
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.
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:
None
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.
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.
Drivers of devices with internal caches for data and drivers that maintain internal buffers for data must handle this request.
None
None
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.
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.
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.
None
None
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.
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.
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.
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:
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.
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.
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.
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.
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:
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.
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.
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.