A quick search in the web reveals that the number of the books that are related to windows device drivers can be counted with the fingers of one hand. Even worse, most of the books are either too old (published before or around windows 2000) and/or not easily readable. Another problem is that the Windows Driver Model (WDM) is becoming more complex as time passes, so the newer books are relatively more complex to read than the older ones.
Based on all of this and after looking at different book reviews, I decided to read a few books that make it easier for a beginner to get an insight on driver development.
So, I think that the best book to start with regarding driver development is Windows NT Device Driver Development (OSR Classic Reprints) (original version was published in 1997) by Peter G. Viscarola and W. Anthony Mason. This book is divided into 3 parts. The first part (chapters 1-8) talk about Windows internals fundamental concepts, like HAL, scheduling, virtual memory, registry, etc. The second part (chapters 9-20) is the bulk of the book and talks about the development of device drivers. Actually, this can be further subdivided into chapters 8-10, which talk about the I/O manager, 11-17, which is the core part of the book (DriverEntry, Dispatch routines, Interrupt Service Routines, Deffered Procedure Calls, Programmed I/O and DMA), and chapters 18-20, which talk about building and debugging a driver. Finally, chapters 21-24 talk about alternate NT driver architectures, like File system drivers, SCSI drivers, Video miniport drivers and NDIS (network) miniport drivers. I think that there are both advantages and disadvantages in this book. I'll start with the advantages:
- It's very easy to read. It starts with very fundamental stuff, builds on top of them and explains the concepts in an easy-to-understand way. This is really to hard to find in the rest of the books. Possibly the fact that both writers teach driver development courses make it easier for them to understand what questions and problems a beginner driver developer might have, so they try to answer them in front.
- It focuses on explaining the concepts and doesn't present pages and pages of un-understandable code. It just presents the functions, explains how they work and shows a cumulative example that shows the use of a few functions bundled together.
- It's a short book (the first 20 chapters take less than 550 pages) and has small chapters. I think that this fine grain analysis helps the reader. I like the fact that I can read a few small chapters within a day and then pickup the book the next day (or a few days later) without breaking my reading in the middle of the chapter and trying to remember what the first part of the chapter was saying.
Of course, the book has also some disadvantages:
- It doesn't cover plug-n-play, power management and other WDM concepts. This is normal, since the book covers NT drivers and not WDM drivers.I haven't found many outdated parts of the book (i.e. almost everything that is written in the book applies even for WDM drivers in Windows XP), apart from the fact that the DriverEntry chapter (chapter 13) talks a lot about manually finding the resources (memory+I/O) that the driver should be using, whereas for WDM drivers this is done automatically. It also doesn't cover Physical Device Objects (PDOs), Function Device Objects (FDOs) and Filter Device Objects (FiDOs), since they didn't exist at that time.
- The examples are small and after understanding the concepts, it's nice to be able to look at some code that will explain them.
So, in order to solve the disadvantages of the first book, I think that the solution is to read The Windows 2000 Device Driver Book: A Guide for Programmers (2nd Edition) (published in 2000) by Art Baker and Jerry Lozano. The strengths of this book are exactly those above:
- The book covers Windows 2000 drivers, so it covers Power Management, Plug-n-Play, Windows Management Instrumentation (WMI) and many WDM concepts that were not covered by the first book.
- The book is full of examples. The writer also provides the source code in the accompanying cd-rom, so it's easy to build them and learn from the source.
- Again, the book is easy to read and short. I like a lot compact books that stick to the topic and don't provide stuff that distract the reader. This book is one of those. The whole book is around 400 pages, so it can be finished quite quickly.
So, after finishing both these books and playing with the source code (and with the source code that can be found in the WDK or elsewhere in the net), I think that the next step is to read Programming the Microsoft Windows Driver Model, Second Edition (published in 2002) by Walter Oney. Again, this book has both advantages and disadvantages. This time, I'll start with the disadvantages 🙂 :
- This book is definately NOT for beginners. I consider it hard to understand and it considers way too many things as known.
- I don't like the structure of the book very well. For example, even though the author mentions that the first 7 chapters are fundamentals and the rest go deeper, he puts the I/O control operations after the plug-n-play or the power management. Of course, this is a personal view, however I was overwhelmed, when I managed to reach the 6th chapter. The first 3 chapters are very good, however I think that after that the difficulty grows exponentially, at least for a beginner.
- The material presented in the book is very dense, so a lot of stuff is presented within a small number of pages and then you look at a big code listing that should explain everything. As I said above, I prefer a slower approach that goes step by step and builds on top of fundamental concepts.
- I don't think that the book gives a a clear high-level view of what a device driver is composed of (I'll explain this below). I had the feeling that the author explains one thing, then the next and the next, but it's hard to understand how everything fits together and how all of these components are related.
On the other hand, this book has some advantages that cannot be covered by any other existing book:
- It is the newest book, so it provides the best picture about the current version of the Windows Driver Model (WDM).
- It's the only book that covers Windows XP, so it's the only choice for somebody, who wants to take advantage of this platform.
- I think that each section is described more deeply than from the rest of the books.
Finally, I think that such a review would be incomplete, if I didn't refer to Microsoft Windows Internals, Fourth Edition: Microsoft Windows Server(TM) 2003, Windows XP, and Windows 2000 (Pro-Developer) (published in December 2004) by Mark E. Russinovich and David A. Solomon. This book doesn' t talk directly about writing device drivers, but it talks about windows internals in general. Some of them are covered in the above mentioned books, however this book is the newest of all and provides the most in-depth analysis. Also, chapter 9 is devoted specifically to the I/O manager and to windows device drivers, so it's definately worth to read. I especially like one particular section in chapter 9 that is titled "Structure of a Driver" and gives a high-level overview of all the components of a driver. That's exactly an important thing that is missing from Walter Oney's book and is not clearly explained in the rest of the books. So, according to the book, a windows device driver is composed of:
- An initialization routine: This function is named DriverEntry (for WDM drivers) and is called by the I/O manager only once, when the driver is initially loaded. It is used by the driver to initialize its internal (global) structures.
- An add-on device routine: This function is named AddDevice and is called by the I/O manager, whenever a new device, for which the driver is responsible, is detected. It is used by the driver to initialize the device object (i.e. the internal structure) that corresponds to the newly-found device.
- A set of dispatch routines: These are the functions that are called by an application (or another driver) to communicate with the device. They include functions like read, write, open, close, control, etc. When called to perform an I/O operation, the I/O manager creates an IRP (I/O Request Packet), which is a structure that descibes the request, and sends it to the driver.
- An Interrupt Service Routine (ISR): One of the ways that an external device can communicate with the CPU is through interrupts (the other way is polling, but let's forget about it for now). So, whenever the device wants to communicate with the CPU, it sends an interrupt to the CPU and the CPU executes some code that needs to serve the device (e.g. find if the device finished some calculation or received a packet, etc and find what to do afterwards). The code that is executed is called the Interrupt Service Routine (ISR). Therefore, the driver that controls the device needs to implement this ISR.
- Deffered Procedure Call (DPC): Whenever an ISR is executing, the IRQL (IRQ Level) of the CPU is high, so all the interrupts that have lower IRQL than the current interrupt cannot be served. In order to solve this problem, drivers perform only very basic calculation in their ISR and for the rest of the processing they schedule a DPC. This function executes in a low IRQL (which is named DISPATCH_LEVEL), so that the rest of the interrupts can be serviced. Therefore, the DPC can be considered as just an extension to the ISR (they serve the same purpose, but they execute at different IRQL). Of course, a driver can execute DPCs not only from an ISR, but from any other function, however this is the main use of a DPC.
- A start I/O routine: Some drivers wants to process the incoming I/O requests serially, i.e. one at a time. Therefore, they ask the I/O manager to queue the incoming IRPs. This function is used to initiate the next data transfer to or from the device.
- One or more I/O completion routines: Sometimes a driver, which receives an I/O request does some processing and passes the IRP to the next driver in the stack, without finalizing the IRP processing (finalizing means that the I/O operation was completed successfully, failed or cancelled). The I/O completion routine informs the driver that another driver in the stack has marked the I/O as "finalized", so the current driver's I/O completion routine can be called, in order to perform some cleanup operations.
- A cancel I/O routine: This function is called, when the I/O manager wants to cancel the processing of an IRP. This function mostly releases any resources that were acquired during the processing of the IRP and it also marks the IRP as "cancelled". Not all IRPs can be cancelled, though.
- An unload routine: The I/O manager calls this routine, when it wants to unload the driver from memory. The drives releases any resources that it might have acquired.
- A system shutdown notification routine: The I/O manager calls this routine, when the system is about to shutdown.
- Error-logging routines: Whenever an error occurs, the driver uses these routines to log the error and notify the I/O manager.
Here I would like to note that all the above books are for the Windows Driver Model. As I've mentioned many times before, Microsoft is changing the driver model for Windows Vista. However, there aren't any books for the Windows Driver Foundation (WDF - the new windows model) yet. The only public announcement for such a book is the Introduction to the Windows Driver Foundation - Kernel Mode Driver Framework by Peter Viscarola, Tony Mason, Mark Cariddi, Brenda Ryan, Scott Noone, and OSR.