Книга: Writing Windows WDM Device Drivers

Driver Design Guide

Driver Design Guide

A good device driver needs to be well written. Remember that it is a trusted part of the operating system. The PC will not get the protection that a normal Win32 application has. If anything goes wrong, it is likely that the system will crash, or worse — destroy valuable data before crashing.

For important projects, my ultimate design philosophy is to design code three times. At the outset, it is definitely worth while knowing where I am going and what features I am going to implement. I then prefer an incremental approach, in which each individual section of code is designed as I go along. However, as with many programs, it often only when I have finished a first-cut prototype of the whole driver that I really understand what is going on.

Doing some real hardware interactions might invalidate some of my initial design decisions. Similarly, I might decide to expose an IOCTL interface instead of reads and writes. In the end, it might be best to scrap some sections of code and start again[4].

Documentation

It is particularly important that you document your driver well and provide ample comments in your code. Device drivers are complicated enough at the best of times. Having to look at someone else's code without any explanation of what is going on can be difficult.

Your hardware and firmware engineering colleagues should have provided you with a suitable interface specification for the device you have to control. You will bring these requirements together with the specification of any bus or class drivers you intend to use. At the end of the day you will have specified your driver's lower edge — the hardware and software interactions that you use to get your job done.

Similarly, you should define your upper edge. This is the interface that your driver presents to user mode applications or higher-level drivers. You need to define what devices you make available and which Win32 functions can be used to access the devices. Specify the parameters in detail and the contents of all buffers. Give your Win32 colleagues a suitable header file.

Good Design

Whatever your approach, a good design needs to be configurable, portable, preemptive, interruptible, and multiprocessor-safe.

A driver should be as configurable as possible — at least as configurable as the hardware allows. A device on a configurable bus ought to have a Plug and Play driver. Use the registry and the control panel to control how a driver runs.

Making a driver portable between platforms is usually fairly straightforward. Drivers should be easily recompiled to support non-x86 processors. WDM drivers need to run on W98 and W2000. Make sure that you only use routines that are available on both platforms. Write the driver in C or C++ and avoid using assembly language. Use the appropriate kernel routines to access hardware. Beware of data types that have different sizes on different processors. Other processors may have different virtual memory page sizes.

When your driver is running at a low interrupt level (see the following text), the operating system may perform a context switch at any time. Remember that higher priority interrupts can occur at any time, so your driver must bear this in mind. Even your ISR can be interrupted.

In an NT/W2000 multiprocessor system, your driver could be called simultaneously on different processors, so the code needs to be reentrant. As NT/W2000 supports symmetric multiprocessing, an interrupt may be handled on any processor. Even on a single processor system, your code needs to be reentrant. Your code could block while processing one IRP, or a context switch could occur. This could allow another IRP to start processing before the first IRP has completed.

Various techniques and routines are used to handle interrupts and multiprocessor systems. For example, critical sections ensure that a device operation is not interrupted. Spin lock tokens can guard access to work queues. Various dispatcher objects (events, Mutexes, semaphores, timers, and threads) can be used to signal conditions and synchronize with the other parts of your driver.

The kernel also provides mechanisms to arbitrate access to shared hardware devices such as the system DMA controllers. In NT7W2000, if your own hardware has a controller that is shared between devices, use the Controller object to arbitrate access, rather than rolling your own.

Look to see if the kernel already provides you with a feature (e.g., string manipulation facilities and management of a pool of memory blocks). These facilities are discussed as appropriate throughout the book.

A good driver checks each and every return value from any routines that it uses (e.g., in the kernel or other drivers). If an error occurs, make sure you rollback your transaction correctly before returning the error.


The layered device driver design

By now you will, of course, be writing Y2K-compliant code. However, this problem may not occur all that often in drivers. If appropriate, your driver should include accessibility options for people who have difficulty performing certain tasks. Bear in mind that many of your users may not use English as their first language, so internationalize as necessary. For example, provide different language event messages. Note that the strings that drivers must use are in Unicode.

Finally, it is best if you follow the driver routine naming conventions described later. Document and test your work as you go along. At the end, go through all the comments and make sure they are up to date.

Оглавление книги


Генерация: 0.036. Запросов К БД/Cache: 0 / 0
поделиться
Вверх Вниз