Writing Windows WDMDevice Drivers Covers NT 4, Win 98, and Win 2000 Chris Cant Preface Chapter 1 Introduction The Windows Driver Model A New Frame of Mind Win32 Program Interface Conclusion Chapter 2 The Big Picture Device Driver Components Types of Device Driver Driver Choices WDM Rationale Conclusion Chapter 3 Device Driver Design Introduction Driver Design Guide Kernel Calls Processor Model Using Memory IRP Processing Conclusion Chapter 4 WDM Driver Environment System Set Up Utilities Driver Targets Driver Language and Libraries Good Code build UtilityVC++ Projects The Wdm1 Driver Code Installing Wdm1 Installation Details Managing Devices and Drivers Conclusion Chapter 5 Device Interfaces Devices Device Objects and Device Extensions Creating and Deleting Device Objects Device Names Device Interfaces Win32 Device Interface Access Conclusion Chapter 6 Testing and Debugging Test, Test, Test Driver Tests Debugging Debugging Techniques Debugging Tools DebugPrint Debugging Notes Bugcheck Codes Conclusion Chapter 7 Dispatch Routines Dispatch Routine IRPs I/O Request Packets IRP Structure Common IRP Parameters User Buffers Conclusion Chapter 8 Plug and Play and Device Stacks Design Overview Plug and Play Messages Device Enumeration Device Stacks Upper Edges Conclusion Chapter 9 Plug and Play Implementation Implementing Plug and Play Testing Wdm2 Other PnP IRPs Plug and Play Notification Advanced Plug and Play Conclusion Chapter 10 Power Management The Power Picture System Power Policies Power IRPs Device Power Policy Owner Handling Set Power IRPs Dispatch Routine Power Handling Testing Wdm2 Power Capabilities Device Capabilities Advanced Power Management Conclusion Chapter 11 Installation WDM Driver Installation Process INF Files Standard Sections INF File Section Hierarchy Cross-Platform and WDM INF Files Locating Drivers NT Style Driver Installation Installing NT Style Drivers in Windows 98 Conclusion Chapter 12 Windows Management Instrumentation Overview A WMI Driver WMI in Action Conclusion Chapter 13 Event Reporting Overview Message Files Registering as an Event Source Generating Events Testing Wdm3 Events Conclusion Chapter 14 DebugPrint Design Specification Design Implementation Test Driver Code DebugPrint Driver DebugPrint Monitor Conclusion Chapter 15 WdmIo and PHDIo Drivers Win32 Interface LPT Printer Driver Application Testing WdmIo Testing PHDIo Analyzing WdmIo and PHDIo Conclusion Chapter 16 Hardware I/O IRP Queuing Hardware Access IRP Queuing Processing Commands Cancelling Queued IRPs Cleanup IRP Handling Supplemental Device Queues Conclusion Chapter 17 Interrupt-Driven I/O Interrupt Handling WdmIo Reads and Writes Interrupt Handler Deferred Procedure Calls Timers Conclusion Chapter 18 NT Hardware NT Style Driver Construction Device Creation and Deletion Claiming Resources Translating Resources Finding Resources Conclusion Chapter 19 WDM System Drivers Writing Client Drivers Filter Drivers NT Layering Conclusion Chapter 20 The Universal Serial Bus Device Classes The Big Picture USB Low Level Structure USB Device Framework Client Design Conclusion Chapter 21 USB Driver Interface USB Client Driver Design USBDI IOCTLs Talking USB Testing UsbKbd USBDI Structure Reference USBDI URB Reference Conclusion Chapter 22 The Human Input Device Model HID Hides The HID Model HID Model Representation Conclusion Chapter 23 HID Clients HID Class Driver User Mode HID Clients Sending Output Reports Kernel Mode HID Clients Conclusion Appendix A Information Resources Newsgroups and Mail Lists Books Appendix B PC 99 Drivers The Specification IBM-Compatible PCs Changing World ACPI, OnNow, and Plug and Play PC 99 Conformance Appendix C Direct Memory Access Glossary Acronyms and Tools
Conclusion This chapter has shown how to set up a development computer for device driver development. A very basic WDM driver has been written and installed in Windows 98 and Windows 2000.
The following chapters explain how to access this driver from a user program and enhance this driver to implement the correct Plug and Play and Power Management handling.
Listing 4.7 Wdm1.h
///////////////////////////////////////////////////////////////////////
//Copyright © 1998 Chris Cant, PHD Computer Consultants Ltd
//WDM Book for Ramp;D Books, Miller Freeman Inc
//
//Wdm1 example
///////////////////////////////////////////////////////////////////////
//wdm1.hCommon header
///////////////////////////////////////////////////////////////////////
//Version history
//27-Apr-991.0.0CCcreation
///////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////
//Include WDM standard header with C linkage
#ifdef __cplusplus
extern "C" {
#endif
#include "wdm.h"
#ifdef __cplusplus
}
#endif
///////////////////////////////////////////////////////////////////////
//DebugPrint and Guid headers
#include "DebugPrint.h"
#include "GUIDs.h"
///////////////////////////////////////////////////////////////////////
//Spin lock to protect access to shared memory buffer
extern KSPIN_LOCK BufferLock;
extern PUCHAR Buffer;
///////////////////////////////////////////////////////////////////////
//Our device extension
typedef struct _WDM1_DEVICE_EXTENSION {
PDEVICE_OBJECT fdo;
PDEVICE_OBJECT NextStackDevice;
UNICODE_STRIN GifSymLinkName;
} WDM1_DEVICE_EXTENSION, *PWDM1_DEVICE_EXTENSION;
///////////////////////////////////////////////////////////////////////
// Forward declarations of global functions
VOID Wdm1Unload(IN PDRIVER_OBJECT DriverObject);
NTSTATUS Wdm1Power(IN PDEVICE_OBJECT fdo, IN PIRP Irp);
NTSTATUS Wdm1Pnp(IN PDEVICE_OBJECT fdo, IN PIRP Irp);
NTSTATUS Wdm1AddDevice(IN PDRIVER_OBJECT DriverObject, IN PDEVICE_OBJECT pdo);
NTSTATUS Wdm1Create(IN PDEVICE_OBJECT fdo, IN PIRP Irp);
NTSTATUS Wdm1Close(IN PDEVICE_OBJECT fdo, IN PIRP Irp);
NTSTATUS Wdm1Write(IN PDEVICE_OBJECT fdo, IN PIRP Irp);
NTSTATUS Wdm1Read(IN PDEVICE_OBJECT fdo, IN PIRP Irp);
NTSTATUS Wdm1DeviceControl(IN PDEVICE_OBJECT fdo, IN PIRP Irp);
NTSTATUS Wdm1SystemControl(IN PDEVICE_OBJECT fdo, IN PIRP Irp);
///////////////////////////////////////////////////////////////////////
// NTSTATUS CompleteIrp(PIRP Irp, NTSTATUS status, ULONG info);
///////////////////////////////////////////////////////////////////////
Listing 4.8 Init.cpp
///////////////////////////////////////////////////////////////////////
//Copyright © 1998 Chris Cant, PHD Computer Consultants Ltd
//WDM Book for Ramp;D Books, Miller Freeman Inc
//
//Wdm1 example
///////////////////////////////////////////////////////////////////////
//init.cpp:Driver initialization code
///////////////////////////////////////////////////////////////////////
//DriverEntryInitialisation entry point
//Wdm1UnloadUnload driver routine
///////////////////////////////////////////////////////////////////////
//Version history //27-Apr-991.0.0CCcreation
///////////////////////////////////////////////////////////////////////
#include "wdm1.h"
#pragma code_seg("INIT") // start INIT section
///////////////////////////////////////////////////////////////////////
//DriverEntry:
//
//Description:
//This function initializes the driver, and creates
//any objects needed to process I/O requests.
//
//Arguments:
//Pointer to the Driver object
//Registry path string for driver service key
//
//Return Value:
//This function returns STATUS_XXX
extern "C"
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath) {
NTSTATUS status = STATUS_SUCCESS;
#if DBG
DebugPrint Init("Wdm1 checked");
#else
DebugPrintInit("Wdm1 free");
#endif
DebugPrint("RegistryPath is %T", RegistryPath);
// Export other driver entry points…
DriverObject-gt;DriverExtension-gt;AddDevice = Wdm1AddDevice;
DriverObject-gt;DriverUnload = Wdm1Unload;
OriverObject-gt;MajorFunction[IRP_MJ_CREATE] = Wdm1Create;
DriverObject-gt;MajorFunction[IRP_MJ_CLOSE] = Wdm1Close;
DriverObject-gt;MajorFunction[IRP_MJ_PNP] = Wdm1Pnp;
DriverObject-gt;MajorFunction[IRP_MJ_POWER] = Wdm1Power;
DriverObject-gt;MajorFunction[IRP_MJ_READ] = Wdm1Read;
DriverObject-gt;MajorFunction[IRP_MJ_WRITE] = Wdm1Write;
DriverObject-gt;MajorFunction[IRP_MJ_DEVICE_CONTROL] = Wdm1DeviceControl;
DriverObject-gt;MajorFunction[IRP_MJ_SYSTEM_CONTROl] = Wdm1SystemControl;
//Initialise spin lock which protects access to shared memory buffer
KeInitializeSpinLock(amp;BufferLock);
DebugPrintMsg("DriverEntry completed");
return status;
}
#pragma code_seg() // end INIT section
///////////////////////////////////////////////////////////////////////
//Wdm1Unload
//
//Description:
//Unload the driver by removing any remaining objects, etc.
//
//Arguments:
//Pointer to the Driver object
//
//Return Value:
//None
#pragma code_seg("PAGE") // start PAGE section
VOID Wdm1Unload(IN PDRIVER_OBJECT DriverObject) {
// Free buffer (do not need to acquire spin lock)
if (Buffer!=NULL) ExFreePool(Buffer);
DebugPrintMsg("WdmlUnload");
DebugPrintClose();
}
///////////////////////////////////////////////////////////////////////
# pragma code_seg() // end PAGE section
Listing 4.9 Pnp.cpp
///////////////////////////////////////////////////////////////////////
//Copyright © 1998 Chris Cant, PHD Computer Consultants Ltd
//WDM Book for Ramp;D Books, Miller Freeman Inc
//
//Wdm1 example
///////////////////////////////////////////////////////////////////////
//pnp.cpp:Plug and Play and Power IRP handlers
///////////////////////////////////////////////////////////////////////
//Wdm1AddDeviceAdd device routine
//Wdm1PnpPNP IRP dispatcher
//Wdm1PowerPOWER IRP dispatcher
///////////////////////////////////////////////////////////////////////
//Version history //27-Apr-991.0.0CCcreation
///////////////////////////////////////////////////////////////////////
#define INITGUID// initialize WDM1_GUID in this module
#include "wdm1.h"
#pragma code_seg("PAGE")// start PAGE section
///////////////////////////////////////////////////////////////////////
//Wdm1AddDevice:
//
//Description:
//Cope with a new Pnp device being added here.
//Usually just attach to the top of the driver stack.
//Do not talk to device here!
//
//Arguments:
//Pointer to the Driver object
//Pointer to Physical Device Object
//
//Return Value:
//This function returns STATUS_XXX
NTSTATUS WdmlAddDevice(IN PDRIVER_OBJECT DriverObject, IN PDEVICE_OBJECT pdo) {
DebugPrint("AddDevice");
NTSTATUS status;
PDEVICE_OBJECT fdo;
// Create our Functional Device Object in fdo
status = IoCreateDevice(DriverObject, sizeof(WDM1_DEVICE_EXTENSION),
NULL,// No Name
FILE_DEVICE_UNKNOWN, 0,
FALSE,// Not exclusive
amp;fdo);
if (!NT_SUCCESS(status)) return status;
// Remember fdo in our device extension
PWDM1_DEVICE_EXTENSION dx = (PWDM1_DEVICE_EXTENSION)fdo-gt;DeviceExtension;
dx-gt;fdo = fdo;
DebugPrint("FDO is %x",fdo);
// Register and enable our device interface
status = IoRegisterDeviceInterface(pdo, amp;WDM1_GUID, NULL, amp;dx-gt;ifSymLinkName);
if (!NT_SUCCESS(status)) {
IoDeleteDevice(fdo);
return status;
}
IoSetDeviceInterfaceState(amp;dx-gt;ifSymLinkName, TRUE);
DebugPrint("Symbolic Link Name is %T", amp;dx-gt;ifSymLinkName);
// Attach to the driver stack below us
dx-gt;NextStackDevice = IoAttachDeviceToDeviceStack(fdo.pdo);
// Set fdo flags appropriately
fdo-gt;Flags amp;= ~DO_DEVICE_INITIALIZING;
fdo-gt;Flags |= DO_BUFFERED_IO;
return STATUS_SUCCESS;
}
///////////////////////////////////////////////////////////////////////
//Wdm1Pnp:
//
//Description:
//Handle IRP_MJ_PNP requests
//
//Arguments:
//Pointer to our FDO
//Pointer to the IRP
//Various minor codes
//IrpStack-gt;Parameters.QueryDeviceRelations
//IrpStack-gt;Parameters.QueryInterface
//IrpStack-gt;Parameters.DeviceCapabilities
//IrpStack-gt;Parameters.FilterResourceRequirements
//IrpStack-gt;Parameters.ReadWriteConfig
//IrpStack-gt;Parameters.SetLock
//IrpStack-gt;Parameters.QueryId
//IrpStack-gt;Parameters.QueryDeviceText
//IrpStack-gt;Parameters.UsageNotification
//
//Return Value:
//This function returns STATUS_XXX
NTSTATUS Wdm1Pnp(IN PDEVICE_OBJECT fdo, IN PIRP Irp) {
DebugPrint("PnP %I", Irp);
PWDM1_DEVICE_EXTENSION dx=(PWDMl_DEVICE_EXTENSION)fdo-gt;DeviceExtension;
// Remember minor function
PIO_STACK_LOCATION IrpStack = IoGetCurrentIrpStackLocation(Irp);
ULONG MinorFunction = IrpStack-gt;MinorFunction;
// Just pass to lower driver
IoSkipCurrentIrpStackLocation(Irp);
NTSTATUS status = IoCallDriver(dx-gt;NextStackDevice, Irp);
// Device removed
if (MinorFunction==IRP_MN_REMOVE_DEVICE) {
DebugPrint("PnP RemoveDevice");
// disable device interface
IoSetDeviceInterfaceState(amp;dx-gt;ifSymLinkName, FALSE);
RtlFreeUnicodeString(amp;dx-gt;ifSymLinkName);
// unattach from stack
if (dx-gt;NextStackDevice) IoDetachDevice(dx-gt;NextStackDevice);
// delete our fdo IoDeleteDevice(fdo);
}
return status;
}
///////////////////////////////////////////////////////////////////////
//Wdm1Power:
//
//Description:
//Handle IRP_MJ_POWER requests
//
//Arguments:
//Pointer to the FDO
//Pointer to the IRP
//IRP_MN_WAIT_WAKE:IrpStack-gt;Parameters.WaitWake.Xxx
//IRP_MN_POWER_SEOUENCE:IrpStack-gt;Parameters.PowerSequence.Xxx
//IRP_MN_SET_POWER:
//IRP_MN_QUERY_POWER:IrpStack-gt;Parameters.Power.Xxx
//
//Return Value:
//This function returns STATUS_XXX
NTSTATUS Wdm1Power(IN PDEVICE_OBJECT fdo, IN PIRP Irp) {
DebugPrint("Power %I",Irp);
PWDM1_DEVICE_EXTENSION dx = (PWDM1_DEVICE_EXTENSION)fdo-gt;DeviceExtension;
// Just pass to lower driver
PoStartNextPowerIrp(Irp);
IoSkipCurrentIrpStackLocation(Irp);
return PoCallDriver(dx-gt;NextStackDevice, Irp);
}
#pragma code_seg()// end PAGE section
Listing 4.10 Dispatch.cpp
///////////////////////////////////////////////////////////////////////
//Copyright © 1998 Chris Cant, PHD Computer Consultants Ltd
//WDM Book for Ramp;D Books, Miller Freeman Inc
//
//Wdm1 example
///////////////////////////////////////////////////////////////////////
//dispatch.cpp:Other IRP handlers
///////////////////////////////////////////////////////////////////////
//Wdm1CreateHandle Create/Open file IRP
//Wdm1CloseHandle Close file IRPs
//Wdm1ReadHandle Read IRPs
//Wdm1WriteHandle Write IRPs
//Wdm1DeviceControlHandle DeviceIoControl IRPs
//Wdm1SystemControlHandle WMI IRPs
///////////////////////////////////////////////////////////////////////
//Version history
//27-Apr-991.0.0CCcreation
///////////////////////////////////////////////////////////////////////
#include "wdm1.h"
#include "Ioctl.h"
///////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////
//Buffer and BufferSize and guarding spin lock globals (in unpaged memory)
KSPIN_LOCK BufferLock;
PUCHARBuffer = NULL;
ULONGBufferSize = 0;
///////////////////////////////////////////////////////////////////////
//Wdm1Create:
//
//Description:
//Handle IRP_MJ_CREATE requests
//
//Arguments:
//Pointer to our FDO
//Pointer to the IRP
//IrpStack-gt;Parameters.Create.xxx has create parameters
//IrpStack-gt;FileObject-gt;FileName has file name of device
//
//Return Value:
//This function returns STATUS_XXX
NTSTATUS Wdm1Create(IN PDEVICE_OBJECT fdo, IN PIRP Irp) {
PIO_STACK_LOCATION IrpStack = IoGetCurrentIrpStackLocation(Irp);
DebugPrint("Create File is %T", amp;(IrpStack-gt;FileObject-gt;FileName);
// Complete successfully
return CompleteIrp(Irp,STATUS_SUCCESS,0);
}
///////////////////////////////////////////////////////////////////////
//Wdm1Close:
//
//Description:
//Handle IRP_MJ_CLOSE requests
//
//Arguments:
//Pointer to our FDO
//Pointer to the IRP
//
//Return Value:
//This function returns STATUS_XXX
NTSTATUS Wdm1Close(IN PDEVICE_OBJECT fdo, IN PIRP Irp) {
DebugPrintMsg("Close");
// Complete successfully
return CompleteIrp(Irp,STATUS_SUCCESS,0);
}
///////////////////////////////////////////////////////////////////////
//Wdm1Read:
//
//Description:
//Handle IRP_MJ_READ requests
//
//Arguments:
//Pointer to our FDO
//Pointer to the IRP
//IrpStack-gt;Parameters.Read.xxx has read parameters
//User buffer at:AssociatedIrp.SystemBuffer(buffered I/O)
//MdlAddress(direct I/O)
//
//Return Value:
//This function returns STATUS_XXX
NTSTATUS Wdm1Read(IN PDEVICE_OBJECT fdo, IN PIRP Irp) {
PIO_STACK_LOCATION IrpStack = IoGetCurrentIrpStackLocation(Irp);
NTSTATUS status = STATUS_SUCCESS;
LONG BytesTxd = 0;
// Get call parameters
LONGLONG FilePointer = IrpStack-gt;Parameters.Read.ByteOffset.QuadPart;
ULONG ReadLen = IrpStack-gt;Parameters.Read.Length;
DebugPrint("Read %d bytes from file pointer %d",(int)ReadLen,(int)FilePointer);
// Get access to the shared buffer
KIRQL irql;
KeAcquireSpinLock(amp;BufferLock,amp;irql);
// Check file pointer
if (FilePointerlt;0) status = STATUS_INVALID_PARAMETER;
if (FilePointergt;=(LONGLONG)BufferSize) status = STATUS_END_OF_FILE;
if (status==STATUS_SUCCESS) {
// Get transfer count
if ( ((ULONG)FilePointer)+ReadLengt;BufferSize) {
BytesTxd = BufferSize – (ULONG)FilePointer;
if (BytesTxdlt;0) BytesTxd = 0;
} else BytesTxd = ReadLen;
// Read from shared buffer
if (BytesTxdgt;0 amp;amp; Buffer!=NULL) RtlCopyMemory(Irp-gt;AssociatedIrp.SystemBuffer, Buffer+FilePointer, BytesTxd);
}
// Release shared buffer
KeReleaseSpinlock(amp;BufferLock,irql);
DebugPrint("Read: %d bytes returned",(int)BytesTxd);
// Complete IRP
return Completelrp(Irp.status.BytesTxd);
}
///////////////////////////////////////////////////////////////////////
//Wdm1Write: //
//Description:
//Handle IRP_MJ_WRITE requests
//
//Arguments:
//Pointer to our FDO
//Pointer to the IRP
//IrpStack-gt;Parameters.Write.xxx has write parameters
//User buffer at:AssociatedIrp.SystemBuffer(buffered I/O)
//MdlAddress(direct I/O)
//
//Return Value:
//This function returns STATUS_XXX
NTSTATUS Wdm1Write(IN PDEVICE_OBJECT fdo, IN PIRP Irp) {
PIO_STACK_LOCATION IrpStack = IoGetCurrentIrpStackLocation(Irp);
NTSTATUS status = STATUS_SUCCESS;
LONG BytesTxd = 0;
// Get call parameters
LONGLONG FilePointer = IrpStack-gt;Parameters.Write.ByteOffset.QuadPart;
ULONG WriteLen = IrpStack-gt;Parameters.Write.Length;
DebugPrint("Write %d bytes from file pointer %d",(int)WriteLen,(int)FilePointer);
if (FilePointerlt;0) status = STATUS_INVALID_PARAMETER;
else {
// Get access to the shared buffer
KIRQL irql;
KeAcquireSpinLock(amp;BufferLock,amp;irql);
BytesTxd = WriteLen;
// (Re)allocate buffer if necessary
if ( ((ULONG)FilePointer)+WriteLengt;BufferSize) {
ULONG NewBufferSize = ((ULONG)FilePointer)+WriteLen;
PVOID NewBuffer = ExAllocatePool(NonPagedPool.NewBufferSize);
if (NewBuffer==NULL) {
BytesTxd = BufferSize – (ULONG)FilePointer;
if (BytesTxdlt;0) BytesTxd = 0;
} else {
RtlZeroMemory(NewBuffer,NewBufferSize);
if (Buffer==NULL) {
RtlCopyMemory(NewBuffer,Buffer,BufferSize);
ExFreePool(Buffer);
}
Buffer = (PUCHAR)NewBuffer;
BufferSize = NewBufferSize;
}
}
// Write to shared memory
if (BytesTxdgt;0 amp;amp; Buffer!=NULL) RtlCopyMemory(Buffer+FilePointer, Irp-gt;AssociatedIrp.SystemBuffer, BytesTxd);
// Release shared buffer
KeReleaseSpinLock(amp;BufferLock,irq1);
}
DebugPrint("Write: %d bytes written", (int)BytesTxd);
// Complete IRP
return CompleteIrp(Irp,status,BytesTxd);
}
///////////////////////////////////////////////////////////////////////
//WdmlDeviceControl:
//
//Description:
//Handle IRP_MJ_DEVICE_CONTROL requests
//
//Arguments:
//Pointer to our FDO
//Pointer to the IRP
//Buffered:AssociatedIrp.SystemBuffer (and IrpStack-Parameters.DeviceIoControl.Type3InputBuffer)
//Direct:MdlAddress
//
//IrpStack-gt;Parameters.DeviceIoControl.InputBufferLength
//IrpStack-gt;Parameters.DeviceIoControl.OutputBufferLength
//
//Return Value:
//This function returns STATUS_XXX
NTSTATUS Wdm1DeviceControl(IN PDEVICE_OBJECT fdo, IN PIRP Irp) {
PIO_STACK_LOCATION IrpStack = IoGetCurrentIrpStackLocation(Irp);
NTSTATUS status – STATUS_SUCCESS;
ULONG BytesTxd = 0;
ULONG ControlCode = IrpStack-gt;Parameters.DeviceIoControl.IoControlCode;
ULONG InputLength = IrpStack-gt;Parameters.DeviceIoControl.InputBufferLength;
ULONG OutputLength = IrpStack-gt;Parameters.DeviceIoControl.OutputBufferLength;
DebugPrint("DeviceIoControl: Control code %x InputLength %d OutputLength %d", ControlCode, InputLength, OutputLength);
// Get access to the shared buffer KIRQL irql ;
KeAcquireSpinLock(amp;BufferLock,amp;irql);
switch (ControlCode) {
///////Zero Buffer
case IOCTL_WDM1_ZERO_BUFFER:
// Zero the buffer
if (Buffer!=NULL amp;amp; BufferSizegt;0) RtlZeroMemory(Buffer,BufferSize);
break;
///////Remove Buffer
case IOCTL_WDM1_REMOVE_BUFFER:
if (Buffer!=NULL) {
ExFreePool(Buffer);
Buffer = NULL;
BufferSize = 0;
}
break;
///////Get Buffer Size as ULONG
case IOCTL_WDM1_GET_BUFFER_SIZE:
if (OutputLengthlt;sizeof(ULONG)) status = STATUS_INVALID_PARAMETER;
else {
BytesTxd = sizeof(ULONG);
RtlCopyMemory(Irp-gt;AssociatedIrp.SystemBuffer,amp;BufferSize,sizeof(ULONG));
}
break;
///////Get Buffer
case IOCTL_WDM1_GET_BUFFER:
if (OutputLengthgt;BufferSize) status = STATUS_INVALID_PARAMETER;
else {
BytesTxd = OutputLength;
RtlCopyMemory(Irp-gt;AssociatedIrp.SystemBuffer,Buffer,BytesTxd);
}
break;
///////Invalid request
default:
status = STATUS_INVALID_DEVICE_REQUEST;
}
// Release shared buffer
KeReleaseSpinlock(amp;BufferLock,irql);
DebugPrint("DeviceIoControl: %d bytes written", (int)BytesTxd);
// Complete IRP
return CompleteIrp(Irp,status.BytesTxd);
}
///////////////////////////////////////////////////////////////////////
//Wdm1SystemControl:
//
//Description:
//Handle IRP_MJ_SYSTEM_C0NTROL requests
//
//Arguments:
//Pointer to our FDO
//Pointer to the IRP
//Various minor parameters
//IrpStack-gt;Parameters.WMI.xxx has WMI parameters
//
//Return Value:
//This function returns STATUS_XXX
NTSTATUS WdmlSystemControl(IN PDEVICE_OBJECT fdo, IN PIRP Irp) {
DebugPrintMsg("SystemControl");
// Just pass to lower driver
IoSkipCurrentIrpStackLocation(Irp);
PWDM1_DEVICE_EXTENSION dx = (PWDM1_DEVICE_EXTENSION)fdo-gt;DeviceExtension;
return IoCallDriver(dx-gt;NextStackDevice, Irp);
}
///////////////////////////////////////////////////////////////////////
//Wdm1Cleanup:
//
//Description:
//Handle IRP_MJ_CLEANUP requests
//Cancel queued IRPs which match given FileObject
//
//Arguments:
//Pointer to our FDO
//Pointer to the IRP
//IrpStack-gt;FileObject has handle to file
//
//Return Value:
//This function returns STATUS_XXX
//Not needed for Wdm1
///////////////////////////////////////////////////////////////////////
//CompleteIrp:Sets IoStatus and completes the IRP
NTSTATUS CompleteIrp(PIRP Irp, NTSTATUS status, ULONG info) {
Irp-gt;IoStatus.Status = status;
Irp-gt;IoStatus.Information = info;
IoCompleteRequest(Irp,IO_NO_INCREMENT);
return status;
}
///////////////////////////////////////////////////////////////////////
Listing 4.11 Wdm1.rc
//Microsoft Developer Studio generated resource script.
//
#include "resource.h"
#define APSTUDIO_READONLY_SYMBOLS
///////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "afxres.h"
///////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
///////////////////////////////////////////////////////////////////////
// English (U.S.) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
#ifdef _WIN32
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
#pragma code_page(1252)
#endif //_WIN32
#ifndef _MAC
///////////////////////////////////////////////////////////////////////
//
// Version
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,0,5,0
PRODUCTVERSION 1,0,0,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
#else
FILEFLAGS 0x0L
#endif
FILEOS 0x4L
FILETYPE 0x2L
FILESUBTYPE 0x0L
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "080904b0"
BEGIN
VALUE "Comments", "Chris Cant\0"
VALUE "CompanyName", "PHD Computer Consultants Ltd\0"
VALUE "FileDescription", "Wdm1\0"
VALUE "FileVersion", "1, 0, 5, 0\0"
VALUE "InternalName", "Wdm1 driver\0"
VALUE "LegalCopyright", "Copyright © 1998,1999 PHD Computer Consultants Ltd\0"
VALUE "OriginalFilename", "Wdm1.sys\0"
VALUE "ProductName", "WDM Book\0"
VALUE "ProductVersion", "1, 0, 0, 0\0"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x809, 1200
END
END
#endif // !_MAC
#endif // English (U.S.) resources
///////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////
// English (U.K.) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENG)
#ifdef _WIN32
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_UK
#pragma codepage(1252)
#endif //_WIN32
#ifdef APSTUDIO_INVOKED
///////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//
1 TEXTINCLUDE DISCARDABLE
BEGIN
"resource.h\0"
END
2 TEXTINCLUDE DISCARDABLE
BEGIN
"#include ""afxres.h""\r\n" "\0"
END
3 TEXTINCLUDE DISCARDABLE
BEGIN
"\r\n" "\0"
END
#endif // APSTUDIO_INVOKED
#endif // English (U.K.) resources
///////////////////////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED
///////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
///////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED
Listing 4.12 Ioctl.h
//DeviceIoControl IOCTL codes supported by Wdm1
#define IOCTL_WDM1_ZERO_BUFFER CTL_CODE(\
FILE_DEVICE_UNKNOWN,\
0x801,\
METHOD_BUFFERED,\
FILE_ANY_ACCESS)
#define IOCTL_WDM1_REMOVE_BUFFER CTL_CODE(\
FILE_DEVICE_UNKNOWN,\
0x802,\
METHOD_BUFFERED,\
FILE_ANY_ACCESS)
#define IOCTL_WDM1_GET_BUFFER_SIZE CTL_CODE(\
FILE_DEVICE_UNKNOWN,\
0x803, \
METHOD_BUFFERED,\
FILE_ANY_ACCESS)
#define IOCTL_WDM1_GET_BUFFER CTL_CODE(\
FILE_DEVICE_UNKNOWN,\
0x804,\
METHOD_BUFFERED,\
FILE_ANY_ACCESS)
#define IOCTL_WDM1_UNRECOGNISED CTL_CODE(\
FILE_DEVICE_UNKNOWN,\
0x805,\
METHOD_BUFFERED,\
FILE_ANY_ACCESS)
Listing 4.13 GUIDs.h
///////////////////////////////////////////////////////////////////////
//Wdm1 device interface GUID
// {C0CF0640-5F6E-11d2-B677-00C0DFE4C1F3}
DEFINE_GUID(WDM1_GUID, 0xc0cf0640, 0x5f6e, 0x11d2, 0xb6, 0x77, 0x0, 0xc0, 0xdf, 0xe4, 0xc1, 0xf3);
///////////////////////////////////////////////////////////////////////
//Wdm2 device interface GUID
// {C0CF0641-5F6E-11d2-B677-00C0DFE4C1F3}
DEFINE_GUID(WDM2_GUID, 0xc0cf0641, 0x5f6e, 0x11d2, 0xb6, 0x77, 0x0, 0xc0, 0xdf, 0xe4, 0xd, 0xf3);
///////////////////////////////////////////////////////////////////////
//Wdm3 device interface GUID
// {C0CF0642-5F6E-11d2-B677-00C0DFE4C1F3}
DEFINE_GUID(WDM3_GUID, 0xc0cf0642, 0x5f6e, 0x11d2, 0xb6, 0x77, 0x0, 0xc0, 0xdf, 0xe4, 0xd, 0xf3);
///////////////////////////////////////////////////////////////////////
//Wdm3 WMI data block GUID
// {C0CF0643-5F6E-11d2-B677-00C0DFE4C1F3}
DEFINE_GUID(WDM3_WMI_GUID, 0xc0cf0643, 0x5f6e, 0x11d2, 0xb6, 0x77, 0x0, 0xc0, 0xdf, 0xe4, 0xc1, 0xf3);
///////////////////////////////////////////////////////////////////////
//Wdm3 WMI event block GUID
// {C0CF0644-5F6E-11d2-B677-00C0DFE4C1F3}
DEFINE_GUID(WDM3_WMI_EVENT_GUID, 0xc0cf0644, 0x5f6e, 0x11d2, 0xb6, 0x77, 0x0, 0, 0xdf, 0xe4, 0xc1, 0xf3);
/*
// {C0CF0645-5F6E-11d2-B677-00C0DFE4C1F3}
DEFINE_GUID(lt;lt;namegt;gt;,
0xc0cf0645, 0x5f6e, 0x11d2, 0xb6, 0x77, 0x0, 0xc0, 0xdf, 0xe4, 0xc1, 0xf3);
// {C0CF0646-5F6E-11d2-B677-00C0DFE4C1F31
DEFINE_GUID(lt;lt;namegt;gt;,
0xc0cf0646, 0x5f6e, 0x11d2, 0xb6, 0x77, 0x0, 0xc0, 0xdf, 0xe4, 0xc1, 0xf3);
// {C0CF0647-5F6E-11d2-B677-00C0DFE4C1F3}
DEFINE GUID(lt;lt;namegt;gt;,
0xc0cf0647, 0x5f6e, 0x11d2, 0xb6, 0x77, 0x0, 0xc0, 0xdf, 0xe4, 0xc1, 0xf3);
// {C0CF0648-5F6E-11d2-B677-00C0DFE4C1F3}
DEFINE_GUID(lt;lt;namegt;gt;,
0xc0cf0648, 0x5f6e, 0x11d2, 0xb6, 0x77, 0x0, 0xc0, 0xdf, 0xe4, 0xc1, 0xf3);
*/
///////////////////////////////////////////////////////////////////////
Listing 4.14 resource.h
//{{NO_DEPENDENCIES}}
// Microsoft Developer Studio generated include file.
// Used by Wdm1.rc
//
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NO_MFC 1
#define _APS_NEXT_RESOURCE_VALUE 101
#define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1000
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif
Listing 4.15 Wdm1free.inf
; Wdm1free.Inf – install information file
; Copyright © 1998,1999 Chris Cant, PHD Computer Consultants Ltd
[Version]
Signature="$Chicago$"
Class=Unknown
Provider=%WDMBook%
DriverVer=04/26/1999,1.0.5.0
[Manufacturer]
%WDMRook% = WDM.Book
[WDM.Book]
%Wdm1%=Wdm1.Install, *wdmBook\Wdm1
[DestinationDirs]
Wdm1.Files.Driver=10,System32\Drivers
Wdm1.Files.Driver.NTx86=10,System32\Drivers
[SourceDisksNames]
1="Wdm1 build directory",,,
[SourceDisksFiles]
Wdm1.sys=1,obj\i386\free
[SourceDisksFiles.x86] Wdm1.sys=1,objfre\i386
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Windows 98
[Wdm1.Install]
CopyFiles=Wdm1.Files.Driver
AddReg=Wdm1.AddReg
[Wdm1.AddReg]
HKR,,DevLoader,,*ntkern
HKR,,NTMPDriver,,Wdm1.sys
[Wdm1.Files.Driver]
Wdm1.sys
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Windows 2000
[Wdm1.Install.NTx86]
CopyFiles=Wdm1.Files.Driver.NTx86
[Wdm1.Files.Driver.NTx86]
Wdm1.sys,,,%COPYFLG_NOSKIP%
[Wdm1.Install.NTx86.Services]
AddService = Wdm1, %SPSVCINST_ASSOCSERVICE%, Wdm1.Service
[Wdm1.Service]
DisplayName = %Wdm1.ServiceName%
ServiceType = %SERVICE_KERNEL_DRIVER%
StartType = %SERVICE_DEMAND_START%
ErrorControl = %SERVICE_ERROR_NORMAL%
ServiceBinary = %10%\System32\Drivers\Wdm1.sys
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Strings
[Strings]
WDMBook="WDM Book"
Wdm1="WDM Book: Wdm1 Example, free build"
Wdm1.ServiceName="WDM Book Wdm1 Driver"
SPSVCINST_ASSOCSERVICE=0x00000002; Driver service is associated with device being installed
COPYFLG_NOSKIP=2; Do not allow user to skip file
SERVICE_KERNEL_DRIVER=1
SERVICE_AUTO_START=2
SERVICE_DEMAND_START=3
SERVICE_ERROR_NORMAL=1
Listing 4.16 SOURCES
TARGETNAME=Wdm1
TARGETTYPE=DRIVER
DRIVERTYPE=WDM
TARGETPATH=OBJ
INCLUDES=$(BASEDIR)\inc;
SOURCES=init.cpp \
dispatch.cpp \
pnp.cpp \
DebugPrint.c \
Wdm1.rc
NTTARGETFILES=PostBuildSteps
Listing 4.17 makefile.inc
PostBuildSteps: $(TARGET)
!if "$(DDKBUILDENV)"="free"
rebase –B 0x10000 –X . $(TARGET)
!endif
copy $(TARGET) $(WINDIR)\system32\drivers
Listing 4.18 makefile
#
# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new. source
# file to this component. This file merely indirects to the real make file
# that is shared by all the driver components of the Windows NT DDK
#
!INCLUDE $(NTMAKEENV)\makefile.def
Listing 4.19 MakeDrvr.bat
@echo off
if "%1"=="" goto usage
if "%3"=="" goto usage
if not exist %1\bin\setenv.bat goto usage
call %1\bin\setenv %1 %4
%2
cd %3
build –b –w %5 %6 %1 %8 %9
goto exit
:usage
echo usage MakeDrvr DDK_dir Driver_Drive Driver_Dir free/checked [build_options]
echo eg MakeDrvr %%DDKROOT%% C: %%WDMBOOK%% free –cef
:exit