return Completelrp(Irp,status,BytesTxd);
}
The shared memory buffer is implemented using these three global variables.
KSPIN_LOCK BufferLock;
PUCHAR Buffer = NULL;
ULONG BufferSize = 0;
If the buffer size is greater than zero, Buffer points to some nonpaged memory of this size. As mentioned earlier in this chapter, there must be some mechanism to protect access to such global variables in a multiprocessor environment (e.g., to prevent one dispatch routine from changing BufferSize while another, or even the same, routine tries to access or change it simultaneously).
Spin Locks
A kernel
The spin lock is initialized in the Wdm1
KeInitializeSpinLock(&BufferLock);
Use the
As shown in the code example, you must provide a pointer to a KIRQL variable in the call to
The Wdm1 driver acquires the
Write Algorithm
The write dispatch stores the write data in the shared memory buffer, starting from the given file pointer. It extends the buffer, if necessary.
If there is no buffer at all, or the buffer needs to be extended,
A new memory buffer is zeroed using
Finally, Wdm1Write copies the data from the user buffer using
This algorithm is fairly crude, because the buffer may have to be reallocated often. A much-enhanced version of Wdm1 could implement a RAM disk.
The driver unload routine frees any shared memory buffer.
if (Buffer!=NULL) ExFreePool(Buffer);
The read dispatch routine for Wdm1,
The
All these IOCTLs use Buffered I/O, so any input and output data is found at Irp->Associ-atedIrp.SystemBuffer. As usual, the routine acquires the shared buffer spin lock for the duration of the call. The actual implementation of each IOCTL is straightforward. The Get buffer size and Get buffer handlers check that the output buffer is large enough; if not, they return STATUS INVALID_PARAMETER.
Defining IOCTLs
An IOCTL code is a 32-bit value formed using the CTL_CODE macro shown in Table 7.4. The Wdm1 example defines its IOCTL codes in Ioctl.h, as shown in this example.
//define IOCTL_WDM1_ZERO_BUFFER CTL_CODE(
FILE_DEVICE_UNKNOWN,
0x801,
METHOD_BUFFERED,
FILE_ANY_ACCESS)
Table 7.4 CTL_CODE macro parameters
Parameter | Description |
---|---|
DeviceType | FILE_DEVICE_XXX value given to IoCreateDevice. |
Control Code | IOCTL Function Code 0x000–0x7FF Reserved for Microsoft 0x800-0xFFF Private codes |
TransferType | METHOD_BUFFERED METHOD_IN_DIRECT METHOD_OUT_DIRECT METHOD_NEITHER |
RequiredAccess | FILE_ANY_ACCESS FILE READ_DATA FILE_WRITE_DATA FILE READ_DATA|FILE_WRITE_DATA |
Ioctl.h is also included in the
Dispatch.cpp also contains a handler for the Windows Management Instrumentation IRP, IRP_MJ_SYSTEM_CONTROL.
IoSkipCurrentIrpStackLocation(Irp);
PWDM1_DEVICE_EXTENSION dx = (PWDMl_DEVICE_EXTENSION)fdo->DeviceExtension;
return IoCallDriver(dx->NextStackDevice, Irp);
Conclusion
This chapter has looked in detail at I/O Request Packets (IRPs) and how to write dispatch routines to handle common IRPs. In addition, it has covered how to define IOCTL codes, and how to use spin locks. The Wdm1 dispatch routines implement a shared memory buffer, protected by a spin lock.
The next chapter looks at Plug and Play in detail, enhancing Wdm1 to support PnP correctly.
Chapter 8
Plug and Play and Device Stacks
This chapter looks at the design of the Plug and Play (PnP) system and how PnP drivers fit into a device stack. A device stack is the means by which several layers of drivers can work together