What Kind of Driver Do I Need?
Many kinds of drivers form a complete Windows XP system. Figure 1-4 diagrams several of them.
Figure 1-4. Types of device drivers in Windows XP.
A virtual device driver (VDD) is a user-mode component that allows MS-DOS-based applications to access hardware on Intel x86 platforms. A VDD relies on the I/O permission mask to trap port access, and it essentially simulates the operation of hardware for the benefit of applications that were originally programmed to talk directly to hardware on a bare machine. Don t confuse a Windows XP VDD with a Windows 98/Me VxD. Both are called virtual device drivers, and they serve the same basic purpose of virtualizing hardware, but they employ completely different software technology.
The category kernel-mode drivers includes many subcategories. A PnP driver is a kernel-mode driver that understands the Plug and Play protocols of Windows XP. To be perfectly accurate, this book concerns PnP drivers and nothing else.
A WDM driver is a PnP driver that additionally understands power-management protocols and is source compatible with both Windows 98/Me and Windows 2000/XP. Within the category of WDM driver, you can also distinguish between class drivers (which manage a device belonging to some well-defined class of device) and minidrivers (which supply vendor-specific help to a class driver), and between monolithic function drivers (which embody all the functionality needed to support a hardware device) and filter drivers (which filter the I/O operations for a particular device in order to add or modify behavior).
File system drivers implement the standard PC file system model (which includes the concepts of a hierarchical directory structure containing named files) on local hard disks or over network connections. These, too, are kernel-mode drivers.
Legacy device drivers are kernel-mode drivers that directly control a hardware device without help from other drivers. This category essentially includes drivers for earlier versions of Windows NT that are running without change in Windows XP.
Not all the distinctions implied by this classification scheme are important all of the time. As I remarked in my previous book Systems Programming for Windows 95 (Microsoft Press, 1996), you haven t stumbled into a nest of pedants by buying my book. In particular, I m not always going to carefully distinguish between WDM and PnP drivers in the rigorous way implied by the preceding taxonomy. The distinction is a phenomenological one based on whether a given driver runs both in Windows 2000/XP and Windows 98/Me. Without necessarily using the technically exact term, I ll be very careful to discuss system dependencies when they come up hereafter.
Faced with all these categories of driver, a new driver writer or manager would understandably be confused about what sort of driver he or she needs for a given piece of hardware. For some devices, you don t need to write any driver at all because Microsoft already ships a generic driver that will work with your device. Here are some examples:
SCSI-compatible or ATAPI-compatible mass storage device
Any device connected to a USB port that is fully compatible with an approved specification, provided you re happy with any limitations in the standard Microsoft driver
Standard serial or PS/2 mouse
Standard keyboard
Video adapter without acceleration or other special features
Standard parallel or serial port
Standard floppy disk drive
WDM Drivers
For most devices that Microsoft doesn t directly support, you need to write a WDM driver. You will decide first whether to write a monolithic function driver, a filter driver, or just a minidriver. You ll probably never need to write a class driver because Microsoft would like to reserve that specialty to itself in order to serve the broadest range of hardware makers.
WDM Minidrivers
The basic rule of thumb is that if Microsoft has written a class driver for the type of device you re trying to support, you should write a minidriver to work with that class driver. Your minidriver is nominally in charge of the device, but you ll call subroutines in the class driver that basically take over the management of the hardware and call back to you to do various device-dependent things. The amount of work you need to do in a minidriver varies tremendously from one class of device to another.
Here are some examples of device classes for which you should plan to write a minidriver:
Non-USB human input devices (HID), including mice, keyboards, joysticks, steering wheels, and so on. If you have a USB device for which the generic behavior of HIDUSB.SYS (the Microsoft driver for USB HID devices) is insufficient, you would write a HIDCLASS minidriver too. The main characteristic of these devices is that they report user input by means of reports that can be described by a descriptor data structure. For such devices, HIDCLASS.SYS serves as the class driver and performs many functions that Direct-Input and other higher layers of software depend on, so you re pretty much stuck with using HIDCLASS.SYS. This is hard enough that I ve devoted considerable space to it later in this book. As an aside, HIDUSB.SYS is itself a HIDCLASS minidriver.
Windows Image Acquisition (WIA) devices, including scanners and cameras. You will write a WIA minidriver that essentially implements some COM-style interfaces to support vendor-specific aspects of your hardware.
Streaming devices, such as audio, DVD, and video devices, and software-only filters for multimedia data streams. You will write a stream minidriver.
Network interface devices on nontraditional buses, such as USB or 1394. For such a device, you will write a Network Driver Interface Specification (NDIS) miniport driver with a WDM lower edge, to use the same phrase as the DDK documentation on this subject. Such a driver is unlikely to be portable between operating systems, so you should plan on writing several of them with minor differences to cope with platform dependencies.
Video cards. These devices require a video minidriver that works with the video port class driver.
Printers, which require user-mode DLLs instead of kernel-mode drivers.
Batteries, for which Microsoft supplies a generic class driver. You would write a minidriver (which the DDK calls a miniclass driver, but it s the same thing) to work with BATTC.SYS.
WDM Filter Drivers
You may have a device that operates so closely to a recognized standard that a generic Microsoft driver is almost adequate. In some situations, you may be able to write a filter driver that modifies the behavior of the generic driver just enough to make your hardware work. This doesn t happen very frequently, by the way, because it s often not easy to change the way a generic driver accesses the hardware. I ll discuss filter drivers in great detail in Chapter 16.
Monolithic WDM Function Drivers
With some exceptions to be noted in the next section, most other types of device require what I ve called here a monolithic WDM function driver. Such a driver essentially stands alone and handles all the details of controlling your hardware.
When this style of driver is appropriate, I recommend the following approach so that you can end up with a single binary that will work on Intel x86 platforms in all operating systems. First, build with the most recent DDK I used a beta version of the .NET DDK for the samples in the companion content. You can use IoIsWdmVersionAvailable to decide which operating system you happen to be using. If you happen to be running in Windows 2000 or Windows XP, you can call MmGetSystemRoutineAddress to get a pointer to a Windows XP-only function. I also suggest shipping WDMSTUB.SYS, which is discussed in Appendix A, to define MmGetSystemRoutineAddress and other critical kernel functions in Windows 98/Me; otherwise, your driver simply won t load in Windows 98/Me because of undefined imports.
Here are some examples of devices for which you might write a monolithic WDM function driver:
Any kind of SmartCard reader except one attached to a serial port
Digital-to-analog converter
ISA card supporting proprietary identification tag read/write transducer
More About Binary Compatibility
Originally, WDM was to have been binary portable across all versions of Windows. Because of release schedules and second (and higher-order) thoughts, every release since Windows 98 has included support for more and more kernel functions that are useful, and sometimes even essential, for robust and convenient programming. An example is the IoXxxWork Item family of functions, discussed in Chapter 14, which was added to Windows 2000 and which must be used instead of the similar but less robust ExXxxWorkItem family. Unless you do something extra, a driver that calls IoXxxWorkItem functions simply won t load in Windows 98/Me because the operating system doesn t export the functions. MmGetSystemRoutineAddress is another function that didn t make it into Windows 98/Me, unfortunately, so you can t even make a run-time decision regarding which work item functions to call. As if this weren t enough, the WHQL tests for all drivers flag calls to the ExXxxWorkItem functions.In Windows 98/Me, a VxD named NTKERN implements the WDM subset of kernel support functions. As discussed in more detail in Appendix A, NTKERN relies on defining new export symbols for use by the run-time loader. You can also define your own export symbols, which is how WDMSTUB manages to define missing symbols for use by the kind of binary-portable driver I m advocating you build.
The companion content for this book includes the WDMCHECK utility, which you can run on a Windows 98/Me system to check a driver for missing imports. If you ve developed a driver that works perfectly in Windows XP, I suggest copying the driver to a Windows 98/Me system and running WDMCHECK first thing. If WDMCHECK shows that your driver calls some unsupported functions, the next thing to check is whether WDMSTUB supports those functions. If so, just add WDMSTUB to your driver package as shown in Appendix A. If not, either modify your driver or send me an e-mail asking me to modify WDMSTUB. Either way, you ll eventually end up with a binary-compatible driver.
Other Types of Drivers
A few situations exist in which a monolithic WDM function driver won t suffice because of architectural differences between Windows 98/Me and Windows 2000/XP. In the following cases, you would need to write two drivers: a WDM driver for Windows 2000/XP and a VxD driver for Windows 98/Me:
A driver for a serial port. The Windows 98/Me driver is a VxD that offers the VCOMM port driver interface at its upper edge, whereas the Windows 2000/XP driver is a WDM driver that offers a rich and rigidly specified IOCTL interface at its upper edge. The two upper-edge specifications have nothing in common.
A driver for a device connected to a serial port. The Windows 98/Me driver is a VxD that calls VCOMM in order to talk to the port. The Windows 2000/XP driver is a WDM driver that talks to SERIAL.SYS or some other serial port driver that implements the same IOCTL interface.
A driver for a nonstandard USB mass storage device. For Windows 98/Me, you ll write a VxD that fits into the I/O Supervisor hierarchy of layered drivers. For Windows 2000/XP, you ll write a monolithic WDM function driver that accepts SCSI Request Blocks at its upper edge and communicates with the USB device at its lower edge.
For two classes of device, Microsoft defined a portable driver architecture long before WDM:
Small Computer System Interface (SCSI) adapters use a SCSI miniport driver, which doesn t use any of the standard kernel support functions and relies instead on a special API exported by SCSIPORT.SYS or SCSIPORT.VXD, as the case may be. The miniport is portable between systems.
Network interface cards use an NDIS miniport driver, which relies exclusively on a special API exported by NDIS.SYS or NDIS.VXD, as the case may be. At one time, NDIS miniport drivers were portable between systems, but portability has pretty much been lost by now. Network protocol drivers and so-called intermediate drivers that provide filtering functionality also orbit around NDIS.