If at all possible, you should use one of the standard bus or class drivers, as these will usually have implemented a large amount of the functionality that you need. Indeed, for many types of devices, using the system driver is the only way to access it. The only drawback is that you will have to study the detailed documentation in the DDK for the class of device that you are using. However, I can assure you that it is a darn sight easier to write a USB client than having to write a huge monolithic USB driver from scratch.

Operating System

If using a standard bus or class driver, you will usually be writing a driver that supports Plug and Play. Your driver should usually, therefore, run in W98 and W2000.

Most of the standard bus and class drivers are not available in NT 4 and earlier. In fact, any driver that supports NT 4 or earlier must be an NT style driver. In some cases, it still makes sense to write an NT style driver for W98 and W2000.

Layered Device Drivers

Plug and Play drivers are always layered drivers, as they always form a layer in a device stack. However, NT style drivers can also layer themselves over other drivers. Drivers in a device stack will receive IRPs sent to any of the devices in the stack.

It is quite possible for a driver to use a device stack but not include itself in the stack. For example, drivers that use Plug and Play Notification are usually NT style drivers. Whenever a suitable device is inserted, such a driver will want to use the device. It can layer itself into the device stack, and so receive all IRPs sent to the device stack. Alternatively, it can just store a pointer to the device object at the top of the device stack. This way, it can issue requests to the device without receiving unwanted requests from above. The HID client driver described in Chapter 23 shows how to use this technique.

Monolithic Drivers

It will soon become evident that in some cases, you need to write a low-level driver to talk to your device. The question now is whether yours is a general purpose device or not. If it is has just one specialized use, then writing a monolithic driver to handle all device requests may well be the simplest solution.

However if you want your device to interface into Windows smoothly, you will usually [ need to write a suitable minidriver, miniclass, or miniport driver. The DDK and supporting documentation must be used to determine the exact requirements for these types of drivers. In extreme cases, you may decide to write a whole new class driver, but I would not recommend it.

Recommended and Optional Features

As mentioned earlier, your driver should support Power Management, Windows Management Instrumentation (WMI), and NT event reporting. It is best to build in Power Management support from the beginning. It is possible to bolt on the other two aspects later. However, if you wish to collect performance information for your WMI reporting, it is best to design this in from the start.

WDM Rationale

I am willing to hazard a few comments about the Windows Driver Model (WDM) design to give you my ideas of how well it achieves its goals.

It is the role of device drivers to interface the operating system to hardware devices. They must eventually support the information flows that users and their applications require. In Windows, the specification of Win32, with multiple processes and threads, has implications for device drivers. And a user requirement for fast processing of video and audio data means that device drivers now have to do much more than just receive and send data.

One Core Model

Device drivers have to process a wide variety of data. The simplest example of input data is a keyboard keypress. Keypresses do not happen very often, but they do need to get to an application with visual feedback provided quickly. The next important type of data is the blocks of data that make up file systems. Speed and data integrity are the crucial issues here. Finally, for isochronous data, being able to keep up with the data is the most important factor, even if it means dropping some samples.

The Windows Driver Model defines one basic model to handle all these types of data. In effect, the model is extended for each type of device. For example, the USB class drivers provide an abstract model for all USB devices, with a defined interface that is used by all client drivers. Having a core driver model that is common to all device types makes it easier for driver writers to move from one type of device to another. And it also means that the kernel implementation of the driver model is more likely to be solid. Having a different model for each type of device would almost certainly make life harder for us.

Is this extensible core model too complicated? If you are writing a monolithic simple low-level driver, I think that IRPs will appear to you as quite difficult beasts. Supporting Plug and Play properly is a task too onerous for simple drivers, as described in the following text.

Complexity

Any discussion of device drivers can be fairly 'heavy'. By their very nature, you have to interact with complicated hardware systems that may have exacting timing constraints. Any operating system interface to hardware will have a complicated job to do. Another factor is that each type of device is different, so you need to know about the details of its technology, including its hardware implementation. For example, the network device drivers field is a subject that can easily fill a whole book. All this means that any aspiring device driver writer will have a steep learning curve.

Plug and Play and Layers

When Plug and Play is first described to you, it will probably sound fairly straightforward. You are told when a device arrives. You are told when it leaves. However, some of the follow-on implications are hard work for device drivers. In a brief look, I am not convinced that any of Microsoft examples do the job fully.

The first problem is that the sudden removal of a device will interrupt a whole host of activities that your driver may be doing. However, I guess that there is no easy way round this.

A stickier problem occurs when the Plug and Play (PnP) Manager tries to juggle the system resources when a new device is inserted. The PnP Manager can ask to 'stop' your device (i.e., pause it while your resource assignments are changed). Again, this may interrupt the current flow of operations. However, more importantly, you are supposed to queue up any received IRPs while your device is stopped[3]. At worst, the user is only supposed to experience a tiny delay in the functioning of a device that is paused temporarily. However, implementing an IRP queue is not a trivial exercise, especially as you have to be prepared for the worst. For example, if a device is removed while stopped, you will have to chug through all the queued IRPs completing them with an appropriate error status. (The Ks… series of Kernel Streaming IRP handling routines might provide all this functionality.)

Another potential criticism of the Plug and Play system is that too many layers of drivers are involved. Passing requests between layers can take some time. If a request has to pass through many layers of filter drivers, it could have a noticeable effect on performance.

Range of Functionality

For good reasons, device drivers cannot use many standard C or C++ functions. This makes it more complicated for driver writers as they have to learn what routines to use instead. I find the Unicode string handling routines particularly unwieldy.

I understand that Microsoft is trying remove some older areas of functionality. For example, WMI is effectively going to replace NT events. However, you have to support both in the mean time, which is more effort.

Development Environment

There is plenty of documentation available in the various DDKs. However, it is slightly confusing to have Windows 98 and Windows 2000 DDKs covering the same subject. As is usual, the documentation lags a few months behind when any new developments arise, which can be frustrating. It is worth while checking the relevant Microsoft websites regularly for appropriate articles.

The provision of lots of example source in the DDKs is great. Give us more! These show how real drivers work and show us how to use various kernel calls and techniques.

The driver build environment is still essentially command line. Although it is easy enough to provide a Visual Studio wrapper for this build environment, a fully integrated system would be appreciated. The provision of a nice debugger that can be run on the same computer as the driver you are testing would be a boon.

Developer Support

You will have to make do with the DDK documentation and any colleagues that you can find to help out. First, scour the DDKs, the DDK source, documents in the DDK source, the Microsoft website, and the Platform SDK. Your next port of call might well be the newsgroups and mailing lists. Finally, you can pay Microsoft for help.

Conclusion

In this chapter, I have tried to give the device driver big picture, showing what components your driver will need and how it fits into the general scheme of things. There are different types of device driver and different ways of implementing the same driver functionality. Some driver components are not compulsory, but it is certainly recommended that you support Plug and Play, Power Management, and Windows Management Instrumentation, if possible.

A crucial part of the Windows Driver Model is the provision of several bus and class drivers. These make it considerably easier to write many types of driver.

In the next chapter, I will look at the crucial background concepts that are needed before device driver development in earnest.

Chapter 3

Device Driver Design

Introduction

This chapter introduces the basic concepts and structures that you will need to write drivers. Some ideas are sufficiently important and deserve to be mentioned now. All the other techniques, routines, and objects are covered in the following chapters.

Windows uses a layered design for passing requests from the end user to a driver stack and eventually to the hardware. As a trusted part of the operating system, a driver must be written well to fit into the kernel. It should use the kernel's abstract model of the processor and use memory carefully. Wherever possible, a driver should use the recommended techniques, routines, and structures.

Добавить отзыв
ВСЕ ОТЗЫВЫ О КНИГЕ В ИЗБРАННОЕ

0

Вы можете отметить интересные вам фрагменты текста, которые будут доступны по уникальной ссылке в адресной строке браузера.

Отметить Добавить цитату