An OS/2 device-driver specialist talks shop
AUTHOR:   Steve Mastrianni
In January of 1989, I was giving a presentation on OS/2 to
representatives of a prospective client. They had a DOS-based system
for data acquisition that lacked the ability to simultaneously gather
and process data. They had done their homework and concluded that OS/2
could do the job, but they weren't convinced that Unix could not do
the job as well.
It was a perfect application for OS/2. The system had to monitor
serial-bus transactions and voltage level in real time, and it had to
act on certain conditions immediately. This quickly ruled out Unix,
which lacks a preemptive, everything was going well until one of the
senior engineers asked an obvious question: "Of course, we can get
device drivers for our special hardware, right?" I did some handwaving
and went on to other topics, promising I'd get back to them regarding
the drivers.
When I called the various hardware vendors, I got the same answer
every time. "Sorry, we only have DOS drivers. We'd like to support
OS/2, but we don't have anyone who knows how to write them. We
understand they are extremely hard to write, and only a few customers
have asked for them anyway." I decided to find out why. Why should
writing a device driver for OS/2 be so difficult?
I packed my bags and headed out to Microsoft University for the OS/2
Driver Writing course. The class ran for one week, and it was one of
the most intense I have ever attended.
Device-Driver Basics
When an OS/2 application needs to perform I/O, it makes an I/O request
call to the kernel. The kernel verifies the request,translates it into
a driver request packet, and calls the device driver for service. The
driver handles all the hardware details: I/O addressing, timing,
register setup, interrupt handling, and error checking. When the
device responds, the driver massages the data into a format
recognizable by the application, sends back the data (or a status
message), and notifies the kernel that the request is complete.
If it can't handle the request right away, the driver may either block
the requesting thread or return a "request not done" to the kernel.
Either way, the driver relinquishes the CPU and lets other threads
run. If there's an error, the driver relays it to the kernel along
with a "request complete" status.
What makes OS/2 drivers unique is the need to operate in both real
mode and protected mode. Addresses computed in real mode are not valid
if the system switched to protected mode, and vice versa. The driver
has to handle such mode switches on the fly. Understanding this bimodal
operation is the key to writing OS/2 1.x drivers. Several Device Helper
(DevHlp) routines support bimodal operation, but learning how to
organize them properly can be harrowing.
Jumping into the Deep End
When I got back from Microsoft University, I was anxious to plunge
into my first driver. I ordered the device-driver development kit
(DDK) from Microsoft, which comes with the all-important kernel
debugger. KDB is a replacement kernel that, among other things, has
knowledge of driver structures. For instance, to display a request
packet, you can use the command .d req es:bx. KDB formats the data and
displays it in request packet form. Don't even think about writing an
OS/2 driver without this tool!
I began with a simple, do-nothing driver based on examples given in
the course. It worked perfectly. Next, I tackled the real project. My
client needed a driver for an eight-channel A/D board. The board used
an intelligent interrupt-driven controller and could do DMA transfers.
I fumbled furiously through my student documentation for examples of
how to implement such a driver and broke out in a cold sweat. There
were no examples of interrupt handlers, no examples of DMA operation,
and no examples of user-defined I/O control functions.
Microsoft, when I called for help, referred me to Compaq (I'm using
its version of OS/2). Compaq referred me back to Microsoft. I searched
the compute bookstores to no avail. Finally, I just rolled up my
sleeves and began to experiment.
The driver's job is simple -- in principle. It has to manage requests
from the kernel and return results to the application. An OS/2 driver
receives two kinds of requests: Some can be completed immediately, and
some can't. Requests come in by way of a standard data structure
called a request packet. The kernel sends the driver a bimodal pointer
to the request packet. Since the driver must operate in real mode or
protected mode, the bimodal pointer ensures that the request packet
will be accessible in either mode.
When a request can't be handled right away (e.g., in the case of a
disk seek), the driver (by means of a set of DevHlp routines) places
it in a queue. Disk drivers can choose to sort pending requests for
disk seeks in sector order, to minimize seek time.
OS/2's threaded architecture assigns one extra responsibility to the
device driver. When a driver can't handle a request right away, it
blocks the requesting thread; when it completes the request, it
unblocks the thread.
Tools for Driver Development
The DDK comes with a three-ring binder containing driver structures,
descriptions of the DevHlp routines, and instructions for using the
KDB. I found only the first 40 or so pages useful. The book does
describe the DevHlp routines in detail, but it contains no examples of
working drivers.
I write all my device drivers, including interrupt handlers, in
Microsoft C 6.0 with maximum optimization. Don't waste your time
writing your driver in assembly. Writing a device driver in C takes
about half the time it would take to write the same driver in
assembly, and the driver will work just as well.
Another useful tool is DDC.LIB, which is a C-callable device-driver
library from PentaSoft (17541 Stone Ave. N, Seattle, WA 98133, (206)
546-0470). Probably the most important function in DDC.LIB is
Transfer, which transfers data between the driver and applications and
accounts for mode switching during the transfer. It handles transfer
of data from virtual memory to physical memory, physical to virtual,
virtual to virtual, and physical to physical. If you're serious about
OS/2 driver development, this library is a must.
Light at the End of the Tunnel?
Anyone who has written drivers for other multitasking operating systems
(e.g., Unix or VMS) will have a good foundation for OS/2 driver
development. Microsoft estimates that it takes an experienced C
programmer who has attended the Microsoft University OS/2 Driver
Writing course four to six months to write his or her first OS/2
driver. Subsequent drivers should take two to four months. Disk
drivers are significantly more complex and may take longer.
My first driver took roughly three months to write. The next one took
only two months, and I was able to write a few simple drivers in a
week or so, so it does get easier with practice.
Although OS/2 device drivers are becoming more common nowadays, the
situation remains farly grim. Most of them are for specialized
hardware and aren't readily available. What's needed are standard,
general-purpose drivers that can be adapted to more generic hardware.
For instance, I would like to see an OS/2 driver for a CD-ROM drive,
fax card, or tape drive, yet none are available. Why not? There are
certainly more customers now who need OS/2 drivers. Without them, the
operating system of choice may not be OS/2.
OS/2 2.0 won't make the task of writing device drivers any easier.
True, version 2.0 will run DOS applications in protected mode, so the
driver won't have to concern itself with bimodal operation. But the
driver architecture for DOS programs will change radically. DOS
programs will now call a Virtual Device Driver instead of accessing
the device hardware directly. The VDD will massage the request and
send it to a Physical Device Drive. The PDD will perform the low-level
hardware communication with the device and send the data back to the
The VDD interface is new, while the PDD is nothing more than an OS/2
1.x bimodal driver with the real-mode sections removed. The VDD will
emulate the BIOS and other interrupt functions, letting a DOS
application assume it is talking directly with the device when it is
actually communicating with the VDD. Protected-mode applications will
continue to call OS/2 drivers, as in version 1.x, but can use 0:32
("flat model") addressing.
In June, Microsoft announced a new device-driver architecture for mass
storage devices called the layered device driver architecture (LADDR)
Microsoft claims that LADDR can reduce by 90 percent the time to
develop an OS/2 mass storage device driver. I hope this is true, but
based on what I've seen so far, I wouldn't bet the farm on it.
A new DDK will come with standard driver code, so the developer need
only add the code specific to the device itself to implement a fully
functional driver. I haven't seen the new DDK yet, so I can't verify
Microsoft's claims. At the time of this writing, Microsoft still had
no firm release date for the LADDR kit. Non-mass storage drivers will
continue to be written using conventional methods.
Neither IBM nor Microsoft has done enough to help the people trying to
produce the drivers that OS/2 so desperately needs. The DDK upgrade
from version 1.1 to 1.2 is way behind schedule, and the NDDK, used to
develop network card drivers for the Extended Edition, is also late.
The version 1.1 DDK does not work with PS/2 machines, so drivers must
be developed on Industry Standard Architecture bus systems.
Information is still sketchy and incomplete. Although more books have
appeared, none show examples of device drivers written in C. Most of
the available documentation describes the DevHlp routines and their
calling sequences, but not how to organize them into an actual driver.
What is needed is a driver writer's guide to take the mystery out of
OS/2 driver writing. The guide should contain examples of actual
drivers written in C, not scattered code fragments in assembly. It
should also contain a list of helpful functions to aid in driver
coding and debugging. Until such information becomes available, device
drivers will remain the Achilles' heel of OS/2.