DispatchReadWrite Using Buffered I/O
Any lowest-level device driver that sets up its device objects for buffered I/O satisfies a read request by returning data transferred from its device into a locked down system-space buffer at Irp->AssociatedIrp.SystemBuffer. It satisfies a write request by transferring data from the same buffer out to its device.
Consequently, the DispatchReadWrite routine of such a device driver usually does the following on receipt of a transfer request:
Calls IoGetCurrentIrpStackLocation and determines the direction of the transfer request.
Checks the validity of the parameters for the request.
For a read request, the routine usually checks the driver's IoStackLocation->Parameters.Read.Length value to determine whether the buffer is large enough to receive data transferred from the device.
For example, the system keyboard class driver processes read requests that come only from the Win32 user input thread. This driver defines a structure, KEYBOARD_INPUT_DATA, in which to store keystrokes from the device and, at any given moment, holds some number of these structures in an internal ring buffer in order to satisfy read requests as they come in.
For a write request, the routine usually checks the value at Parameters.Write.Length, and checks the data at Irp->AssociatedIrp.SystemBuffer for validity if necessary: that is, if its device accepts only structured data packets containing members with defined value ranges.
If any parameters are invalid, the DispatchReadWrite routine completes the IRP immediately, as already described in Completing IRPs. Otherwise, the routine passes the IRP on for further processing by other driver routines, as described in Passing IRPs down the Driver Stack.
Lowest-level device drivers that use buffered I/O usually must satisfy a transfer request by reading or writing data of a size specified by that the originator of the request. Such a driver is likely to define a structure for data coming in from or being sent to its device and is likely to buffer structured data internally, as the system keyboard class driver does.
Drivers that buffer data internally should support IRP_MJ_FLUSH_BUFFERS requests, and can also support IRP_MJ_SHUTDOWN requests.
The highest-level driver in a chain is usually responsible for checking the input IRP's parameters before passing a read/write request on to lower drivers. Consequently, many lower-level drivers can assume that their I/O stack locations in a read/write IRP have valid parameters. If a lowest-level driver in a chain is aware of device-specific constraints on data transfers, that driver is required to check the validity of the parameters in its I/O stack location.