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 shows how to open a connection to a Wdm1 device using device interfaces. The Wdm1Test user mode program puts the Wdm1 driver through its paces.
Chapter 7 shows how Wdm1 implements the read, write, and IOCTL calls. However, before I continue looking at the driver, the next chapter describes how to test and debug drivers. It explains how this book uses the DebugPrint software to see what is going on in a driver.
Listing 5.7 Wdm1Test.cpp
///////////////////////////////////////////////////////////////////////
//Copyright © 1998 Chris Cant, PHD Computer Consultants Ltd
//WDM Book for Ramp;D Books, Miller Freeman Inc
//
//Wdm1Test example
///////////////////////////////////////////////////////////////////////
//WdmlTest.cpp:Win32 console application to exercise Wdm1 devices
///////////////////////////////////////////////////////////////////////
//mainProgram main line
//GetDeviceVialnterfaceOpen a handle via a device interface
///////////////////////////////////////////////////////////////////////
//Version history
//27-Apr-991.0.0CCcreation
///////////////////////////////////////////////////////////////////////
#include "windows.h"
#include "C:\98ddk\inc\win98\setupapi.h"// VC++ 5 one is out of date
#include "stdio.h"
#include "initguid.h"
#include "..\sys\GUIDs.h"
#include "winioctl.h"
#include "..\sys\Ioctl.h"
HANDLE GetDeviceViaInterface(GUID* pGuid, DWORD instance);
int main(int argc, char* argv[]) {
int TestNo = 1;
//////////////////////////////////////////////////////////////////////
// Open device
printf("\nTest %d\n",TestNo++);
HANDLE hWdm1 = GetDeviceViaInterface((LPGUID)amp;WDM1_GUID,0);
if (hWdml==NULL) {
printf("XXX Could not find open Wdm1 device\n");
return 1;
}
printf(" Opened OK\n");
//////////////////////////////////////////////////////////////////////
// Read first ULONG that's left in buffer
printf("\nTest %d\n",TestNo++);
DWORD TxdBytes;
ULONG Rvalue =0;
if (!ReadFile(hWdm1, amp;Rvalue, 4, amp;TxdBytes, NULL)) printf("XXX Could not read value %d\n", GetLastError());
else if(TxdBytes==4) printf(" Read successfully read stored value of 0x%X\n",Rvalue);
else printf("XXX Wrong number of bytes read: %d\n",TxdBytes);
//////////////////////////////////////////////////////////////////////
// Write 0x12345678
printf("\nTest M\n" ,TestNo++);
ULONG Wvalue = 0x12345678;
if (!WriteFile(hWdm1, amp;Wvalue, 4, amp;TxdBytes, NULL)) printf("XXX Could not write %X\n",Wvalue);
else if (TxdBytes==4) printf(" Write 0x12345678 succeeded\n");
else printf("XXX Wrong number of bytes written: %d\n",TxdBytes);
//////////////////////////////////////////////////////////////////////
// Set file pointer
printf("\nTest %d\n",TestNo++);
DWORD dwNewPtr = SetFilePointer(hWdrn1, 3, NULL, FILE_BEGIN);
if (dwNewPtr==0xFFFFFFFF) printf("XXX SetFilePointer failed %d\n", GetLastError());
else printf(" SetFilePointer worked\n");
//////////////////////////////////////////////////////////////////////
// Read
printf("\nTest %d\n",TestNo++);
Rvalue = 0;
if (!ReadFile(hWdm1, amp;Rvalue, 1, amp;TxdBytes, NULL)) printf("XXX Could not read value\n");
else if( TxdBytes==1) printf(" Read successfully read stored value of 0x%X\n",Rvalue);
else printf("XXX Wrong number of bytes read: %d\n",TxdBytes);
//////////////////////////////////////////////////////////////////////
// Write
printf("\nTest %d\n",TestNo++);
if (!WriteFile(hWdm1, amp;Wvalue, 4, amp;TxdBytes, NULL)) printf("XXX Could not write %X\n" ,Wvalue);
else if (TxdBytes==4) printf(" Write at new file pointer succeeded\n");
else printf("XXX Wrong number of bytes written: %d\n",TxdBytes);
//////////////////////////////////////////////////////////////////////
// Get buffer size
printf("\nTest %d\n",TestNo++);
ULONG BufferSize;
DWORD BytesReturned;
if (!DeviceIoControl(hWdm1, IOCTL_WDM1_GET_BUFFER_SIZE,
NULL, 0,// Input
amp;BufferSize, sizeof(ULONG),// Output
amp;BytesReturned, NULL)) printf("XXX Could not get buffer size\n");
else printf(" Buffer size is %i (%d bytes returned)\n",BufferSize,BytesReturned);
//////////////////////////////////////////////////////////////////////
// Get buffer size
printf("\nTest %d\n",TestNo++);
char* Buffer = new char[BufferSize+1];
if (!DeviceIoControl(hWdm1, IOCTL_WDM1_GET_BUFFER,
NULL, 0,// Input
Buffer, BufferSize,// Output
amp;BytesReturned, NULL)) printf("XXX Could not get buffer\n");
else printf(" First DWORD of buffer is %08X (%d bytes returned)\n",*((DWORD*)Buffer),Bytes Returned);
///////////////////////////////////////////////////////////////////////
// Get too big a buffer size
printf("\nTest %d\n",TestNo++);
if (!DeviceIoControl(hWdm1, IOCTL_WDM1_GET_BUFFER,
NULL, 0,// Input
Buffer, BufferSize+1,// Output
amp;BytesReturned, NULL)) printf(" Too big get buffer failed correctly %d\n",GetLastError());
else printf("XXX Too big get buffer unexpectedly succeeded\n");
///////////////////////////////////////////////////////////////////////
// Zero all buffer bytes
printf("\nTest %d\n",TestNo++);
if (!DeviceIoControl(hWdm1, IOCTL_WDM1_ZERO_BUFFER,
NULL, 0,// Input
NULL, 0,// Output
amp;BytesReturned, NULL)) printf("XXX Zero buffer failed %d\n" ,GetLastError());
else printf(" Zero buffer succeeded\n");
if (!DeviceIoControl(hWdm1, IOCTL_WDM1_GET_BUFFER,
NULL, 0,// Input
Buffer, BufferSize,// Output
amp;BytesReturned, NULL)) printf("XXX Could not get buffer\n");
else printf(" First DWORD of buffer is %08X (%d bytes returned)\ n",*((DWORD*)Buffer),BytesReturned);
///////////////////////////////////////////////////////////////////////
// Remove buffer
printf("\nTest %d\n",TestNo++);
if (!DeviceIoControl(hWdm1, IOCTL_WDM1_REMOVE_BUFFER,
NULL, 0,// Input
NULL, 0,// Output
amp;BytesReturned, NULL)) printf("XXX Remove buffer failed %d\n",GetLastError());
else printf(" Remove buffer succeeded\n");
if (!DeviceloControl(hWdm1, IOCTL_WDM1_GET_BUFFER_SIZE,
NULL, 0,// Input
amp;BufferSize, sizeof(ULONG),// Output
amp;BytesReturned, NULL)) printf("XXX Could not get buffer size\n");
else printf(" Buffer size is %i (%d bytes returned)\n",BufferSize,BytesReturned);
///////////////////////////////////////////////////////////////////////
// Unrecognised IOCTL
printf("\nTest %d\n",TestNo++);
if (!DeviceIoControl(hWdm1, IOCTL_WDM1_UNRECOGNISED,
NULL, 0,// Input
NULL, 0,1/ Output
amp;BytesReturned, NULL)) printf(" Unrecognised IOCTL correctly failed %d\n",GetLastError());
else printf("XXX Unrecognised IOCTL unexpectedly succeeded\n");
///////////////////////////////////////////////////////////////////////
// Write 0xabcdef01 to start of buffer
printf("\nTest %d\n",TestNo++);
dwNewPtr = SetFilePointer(hWdm1, 0, NULL, FILE_BEGIN);
if (dwNewPtr==0xFFFFFFFF) printf("XXX SetFilePointer failed %d\n",GetLastError());
else printf(" SetFilePointer worked\n");
Wvalue = 0xabcdef01;
if (!WriteFile(hWdm1, amp;Wvalue, 4, amp;TxdBytes, NULL)) printf("XXX Could not write %X\n", Wvalue);
else if( TxdBytes==4) printf(" Write 0xabcdef01 succeeded\n");
else printf("XXX Wrong number of bytes written: %d\n",TxdBytes);
/////////////////////////////////////////////////////////////////////////
// Close device
printf("\nTest %d\n",TestNo++);
if (!CloseHandle(hWdm1)) printf("XXX CloseHandle failed %d\n", GetLastError());
else printf(" CloseHandle worked\n");
/////////////////////////////////////////////////////////////////////////
delete Buffer;
printf("\nPress enter please");
char line[80];
gets(line);
return 0;
}
//////////////////////////////////////////////////////////////////////////
//GetDeviceViaInterface:Open a handle via a device interface
HANDLE GetDeviceViaInterface(GUID* pGuid, DWORD instance) {
// Get handle to relevant device information set
HDEVINFO info = SetupDiGetClassDevs(pGuid, NULL, NULL, DIGCF_PRESENT | DIGCF_INTERFACEDEVICE);
if (info==INVALID_HANDLE_VALUE) {
printf("No HDEVINFO available for this GUID\n");
return NULL;
}
// Get interface data for the requested instance
SP_INTERFACE_DEVICE_DATA ifdata;
ifdata.cbSize = sizeof(ifdata);
if (!SetupDiEnumDeviceInterfaces(info, NULL, pGuid, instance, amp;ifdata)) {
printf("No SP_INTERFACE_DEVICE_DATA available for this GUID instance\n");
SetupDiDestroyDeviceInfoList(info);
return NULL;
}
// Get size of symbolic link name
DWORD ReqLen;
SetupDiGetDeviceInterfaceDetail(info, amp;ifdata, NULL, 0, amp;ReqLen, NULL);
PSP_INTERFACE_DEVICE_DETAIL_DATA ifDetail = (PSP_INTERFACE_DEVICE_DETAIL_DATA)(new char[ReqLen]);
if (ifDetail==NULL) {
SetupDiDestroyDeviceInfoList(info);
return NULL;
}
// Get symbolic link name
ifDetail-gt;cbSize = sizeof(SP_INTERFACE_DEVICE_DETAIL_DATA);
if (!SetupDiGetDeviceInterfaceDetail(info, amp;ifdata, ifDetail, ReqLen, NULL, NULL)) {
SetupDiDestroyDeviceInfoList(info);
delete ifDetail;
return NULL;
}
printf("Symbolic link is %s\n", ifDetail–gt;DevicePath);
// Open file
HANDLE rv = CreateFile(ifDetail-gt;DevicePath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
delete ifDetail;
SetupDiDestroyDeviceInfoList(info);
return rv;
}
///////////////////////////////////////////////////////////////////////