Dr. Dobb's is part of the Informa Tech Division of Informa PLC

This site is operated by a business or businesses owned by Informa PLC and all copyright resides with them. Informa PLC's registered office is 5 Howick Place, London SW1P 1WG. Registered in England and Wales. Number 8860726.


Channels ▼
RSS

Windows CE Device Driver Development, Part I


Oct98: Windows CE Device Driver Development, Part I

Jim is director of software engineering for Cruise Technologies Inc. He can be reached at [email protected].


Every couple of weeks, my grandmother would make a trip to the bank to deposit her retirement check. Charged with the task of keeping me out of mischief, she would put me in my Radio Flyer wagon and pull me along to the bank.

Once there, I was bored with the quiet atmosphere of the financial institution. The only thing of interest was the ominous security guard standing in the corner, bearing a large gun in a leather holster. As I examined him, it always seemed he looked as bored as I -- just standing there with no criminals to slay. His gun seemed useless, and in my child's imagination, I wondered if he even knew how to pull the trigger.

Freshly installed in a few hundred megabytes of disk space, the Microsoft Windows CE Embedded Toolkit is like this armed security guard -- equipped with the weapons to attack almost any embedded task, but without the ability to pull the trigger unless you provide the needed stimulus by writing a device driver or two. In this first installment of a two-part article, I'll provide a crash course in CE device-driver development. This month, I'll begin by describing what you need to get started in CE driver development. Next month, I'll focus on the aspects of driver development that have caused me particular consternation, in the hope that you will be spared similar difficulty.

Getting Started

Microsoft currently sells two development kits for CE:

  • Microsoft Windows CE Toolkit for Visual C++ 5.0 (VCCE), an add-on to Visual C++ that provides support for application development on handheld (H/PC) devices.
  • Microsoft Windows CE Embedded Toolkit for Visual C++ 5.0 (ETK), another add-on product that provides support for embedded-driver development.

If your driver needs to support an end-user installable device (such as a PC Card device), VCCE can be used for driver development. It is also possible to use VCCE for the development of drivers that provide application services exposed using a defined driver model interface, but do not require device I/O. If your driver must support an onboard (hardwired to your CE device's main board) CE device, which uses predefined hardware resources (IRQ lines, port address, I/O memory regions, and so on), you will need the ETK. The ETK is used to build a CE ROM image, which would include your driver and any other optional components you select through various environment variables and makefile macros. As a superset of the VCCE, the ETK contains two distinct installations -- one containing the VCCE, and the other containing the ETK itself. It should be noted that the edition of VCCE that accompanies the ETK includes support for an additional x86 target CPU, as opposed to x86 emulation, which is the only x86 support provided in the nonETK edition of VCCE. You should not need to buy both the VCCE and the ETK products. At this writing, only the VCCE is available with the MSDN subscription products, not the ETK.

CE Architecture

No discussion of CE Device Driver Development would be complete without an overview of the CE architecture. The discussion of each of the following topics may just leave you with more questions than answers, since I will only be scratching the surface of a very large subject. For more information, refer to "The Windows CE SDK: The Tools You Need to Program the Handheld PC," by Neil Fishman and Jeffrey Richter (Microsoft Systems Journal, Volume 12, No.4).

Figure 1 is a high-level overview of the CE architecture, partitioned into two distinct protection modes -- user mode and privilege mode. Drivers, applications, and SDK modules run in user mode, while CE memory management, process management, exception handling, multitasking, and multithreading all run in privilege mode. The obvious advantage of this approach is that it allows drivers to access all of the same resources and services available to applications, which coexist with your drivers in user mode. Overhead from application calls into a driver service is minimized because a time-consuming mode transition is unnecessary. In fact, other than the OEM Adaptation Layer (OAL), the only recommended mechanism provided for writing privilege mode code is in the development of a CE Interrupt Service Routine (ISR). And just in case you are not yet convinced of the wisdom of this approach, debugging drivers in user mode has the added advantage of allowing the privilege mode code to support the debugging process with a software-only approach that does not rely on expensive emulator technology.

Many past complaints directed at Microsoft operating systems were addressed in the development of CE. Nowhere is this more apparent than in the feature list of the CE kernel, most notably in the use of reentrant DLLs for the implementation of system calls. If your process needs to call one of these DLLs, it will not be blocked while waiting for a return from the call of another process. This also has the added advantage of allowing the update of core CE kernel components without requiring a new CE ROM image.

The CE kernel provides support for virtual memory and protection of the address space of individual processes. The entire CE address space consists of a single four-GB region, which is shared by all processes within individual 32-MB slots. The system is limited to 33 of these slots with one reserved for the currently running process. The number of threads, however, is limited only by available memory so your designs will necessarily favor the use of multiple DLLs over multiple EXEs. Each process slot is provided with a separate message queue to receive Win32 and user- defined events.

The CE kernel manages thread resources and scheduling. Threads are preemptively multitasked according to an assigned priority, of which there are eight distinct levels. (This has been a common focus of complaint, and my guess is that future versions will provide support for more levels.) Threads with the same priority level are scheduled for round-robin activation.

Out of the box the ETK provides support for many different processor cores -- x86, MIPS, SHx, PowerPC, and ARM and StrongARM in Q2 '98. Ports of the CE kernel to other processors is provided only by Microsoft, so if you are interested in support for a processor not listed you should contact Microsoft directly to determine if your processor is at least on their road map.

If you are planning on building your own CE device, you will be required to modify a certain category of functions known as the "OEM Adaptation Layer" (OAL). These functions are platform specific and focus on the hardware initialization required for system startup, interrupt service routines for onboard peripherals, serial- and parallel-port functions, and power-management functions. The ETK provides sample implementations of the OAL for various platforms (as of this writing, Hitachi D9000- and x86-based PCs) and it is best to start here. If your platform is comparable to a well-known CE reference design, often supplied by a processor vendor, you may also be able to purchase the implementation of an OAL for your platform from one of the many licensed CE integrators. Even though you will still need to modify the OAL to support your platform's unique features, these modifications may not be as numerous as those required for the Microsoft examples.

RAM is partitioned between program memory (stack space, heap, shared memory, and so on) and the CE object store. The object store supports a variety of data types in both ROM and RAM and is useful to both drivers and applications. A Windows-like registry is maintained in RAM by the object store and may be accessed by drivers and applications using standard Win32 registry functions. Compressed data files and programs may also exist in the RAM of the object store and are opened using unicode formatted, long path names. The object store also supports PC Card flash media as additional file-system volumes, through the use of block device drivers. Typically you would develop a block device driver to allow the CE file system to access your proprietary storage media.

When you build the CE ROM image, which is burned into your devices ROM, you can also specify the files that are maintained by the object store in ROM and whether they are compressed. Compression of files in ROM is commonly used to store data files, such as fonts and help files. The files are compressed at build time by the CE ROM image-build utilities provided in the ETK, and are transparently decompressed as they are accessed by running programs. The object store can also maintain compressed executable modules in ROM, which are later decompressed into RAM, one page at a time as needed. This minimizes the RAM requirements of compressed executables (residing in either RAM or ROM), by decompressing only the portion of the executable that needs to be run.

The object store also maintains a database that may be commonly accessed by all programs. The database is transactioned to facilitate recovery from a power failure that might have occurred during an update of a database record.

If you will be developing a CE device with any kind of user interface, you need to include the Graphics, Windowing, and Event Subsystem (GWES) in your build. As its name implies, GWES provides the infrastructure for user input device drivers (such as the keyboard driver and touch panel driver) and display drivers. The latter, as been significantly expanded since the H/PC-centric release of CE 1.x to include support for displays with VGA resolution and beyond. Support for Win32 messaging and a bevy of other Win32 APIs is also provided by GWES.

CE provides support for a variety of communications protocols, including TCP/IP for access to the Internet, PPP and SLIP for dial-up networking, IrDA for communication from one CE device to another, and DHCP for obtaining IP address information from a DHCP server on the network. RAS connections to a host PC, and most-recently remote-file system access through the use of an SMB redirector, are also supported. If you have a unique communications device that you would like CE to recognize, a subset of the NDIS 4.0 driver model is supported, allowing you to leverage your NDIS desktop development experience.

As you become familiar with writing CE device drivers, the module you will hear a lot about is the Device Manager, which supports a category of installable drivers know as "stream I/O drivers." It is responsible for driver loading and unloading, and the mapping of the driver to a three-character prefix, which may be referenced by the caller using the CreateFile call. At system startup the Device Manager examines the contents of the HKEY_LOCAL_MACHINE\Drivers\Builtin registry key and loads each driver as directed by various subkeys. Using certain subkeys, it is also possible to delay loading of the driver and allow it to be loaded by an application which calls RegisterDevice. (Next month, I'll explain the purpose of certain Device Manager keys, and demonstrate how to write a stream I/O driver for an onboard peripheral.)

Device Driver Models

When I first began developing drivers for CE, I was confused by the references to "Built-in Drivers" and "Installable Drivers." The CE ETK and CE DDK documentation seemed to divide the world of CE drivers into these two broad categories, implying from the name that if a driver must be loaded on startup that it would be considered a "Built-in Device Driver" and that a driver loaded on demand at the time an external peripheral was connected would be supported with an "Installable Device Driver." After a few more days of investigation, I realized that these terms do not really describe the driver as it relates to the device, but simply describe a type of interface or driver model. Built-in Drivers are always loaded during system startup, while Installable Drivers can be loaded either during system startup (thus supporting built-in devices) or dynamically loaded when an associated device is detected. The latter is a capability not limited to Installable Drivers, however, since NDIS device drivers can also be installable. If you are still confused, just remember that an Installable Driver simply provides a particular type of API, which may be used to support all types of devices, either onboard or end-user installable.

Various device classes are supported by CE with layered drivers. Each layer provides a different type of device abstraction and isolates your development task to specific modifications, which most frequently differ from one vendor's implementation to another. The device classes currently supported are the keyboard, mouse, touch panel, audio, audio compression, display, battery, notification LED, PC Card adapter, serial port, and block devices (for SRAM or Flash PC Cards). At this writing, additional device classes were being developed by Microsoft for the next release of the CE ETK, so check your ETK documentation if you don't see a class for your particular device.

If you have a type of onboard device whose I/O matches or resembles any of these device classes, you will probably begin your development efforts by focusing on the Platform Dependent Driver layer of the sample driver for the particular class. The files containing the sample implementation of the PDD layer for each device class are located under the Platform\[ODO|CEPC]\Drivers directory tree and generally contain the characters PDD somewhere in the file name. Each device class defines a different set of PDD functions that are collectively referred to as the Device Driver Service provider Interface (DDSI). If your device conforms to an industry standard (the 16550 UART interface, for example), you may not need to change the PDD layer code at all.

The Model Device Driver (MDD) layer provides the functions, which a Microsoft supplied module such as the Graphics, Windowing, and Event Subsystem (GWES) module requires to communicate with a driver of a particular class. The files containing the sample implementation of the MDD layer for each device class are located under the Public\Common\Oak\ Drivers directory tree. Like the PDD layer, the MDD layer also defines a different set of MDD functions for each class. The MDD functions satisfy the requirements of an upper-layer interface referred to in the ETK documentation as the "Device Driver Interface" or DDI. In most cases, you will not need to modify this layer even if you are required to modify the PDD layer, since it contains functions considered platform independent.

Occasionally, the CE ETK documentation will refer to "Monolithic Drivers" to differentiate them from Layered Drivers. Unlike Layered Drivers, Monolithic Drivers provide a single interface that is called directly for device I/O and does not attempt to generalize its functionality to support a broad category of similar devices. Drivers that are implemented using the stream I/O interface of Installable Drivers are considered monolithic drivers. Also, it is possible to modify both the PDD and MDD layers of a layered driver to replace the Microsoft supplied DDSI with your own implementation, thus transforming the layered device driver into a monolithic one.

Just as in the world of the Windows desktop, no one interface or Driver Model will satisfy the requirements of all device classes. In an effort to support the porting efforts of those of you with Win9x or WinNT drivers, a few of the desktop driver models such as that for NDIS 4.0 and Audio Compression Manager (ACM) drivers have made it into CE. Table 1 lists the known CE driver models (as of the time of this writing) by the device class and its associated interface.

WDM Device Driver Model

If you are familiar with the Windows Driver Model (WDM) you may be surprised to find that the file WDM.H is included in Version 2.0 of the ETK, especially since there is no mention of it anywhere in the documentation. You will also notice that the environment variable WINCE_WDM is used in CESYSGEN.BAT to determine if certain WDM modules should be included in the build, thus supporting a modular implementation of WDM. Another environment variable IMGWDMTEST is defined to include a sample WDM driver WDMSMPL.DLL and its test application WDMAPP.EXE. If you search the ETK directory tree for the source or executable forms for either of these modules, you will not find them. The modules associated with the WINCE_WDM environment variable, however, are available in executable form allowing you to produce a build with WDM support, but with no source samples or documentation to guide you on its usage. Considering all this, I am forced to assume that WDM support is a work in progress, though I would have preferred a more definitive statement to this effect, at least something in the README file. Consequently, beyond mentioning its existence, WDM is not discussed in this article as a viable driver model alternative for CE. I have a feeling this will change in a subsequent release of the ETK.

Conclusion

The Windows CE device driver model provides support for a variety of core services needed to facilitate the creation of drivers for most any device type. By running in user mode, CE drivers are able to access the same services available to applications, allowing Win32 preemptive multithreading and synchronization, messaging, and driver loading on demand. To coin a familiar Redmonian superlative, CE definitely provides a rich feature set for driver development.

In the next installment of this article, I'll focus on the basic skills needed to develop CE device drivers, and demonstrate these principles with an example of a device driver for an onboard peripheral device.

DDJ


Copyright © 1998, Dr. Dobb's Journal

Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.