Writing Windows CE Device Drivers: Principle to Practice(转)

Writing Windows CE Device Drivers: Principle to Practice

By David G. Heil, CalAmp, September 22, 2006

0 Comments

David Heil of CalAmp provides an overview of the new Windows CE 6.0 kernel architecture and describes the various driver models and device types supported, as well some guidance in creating CE drivers. 
Device driver writers possess a special blend of software and hardware skills (among other things). They need to write highly structured and elegant code as well as debug down to the register level of the hardware. They have to do their tasks with less then optimal debug hardware. They often make do without JTAG or Ethernet debug tools and fix tough problems with just their wit and a GPIO line. If you have the tenacity to write device drivers read on.

Writing device drivers for Windows CE is very similar to creating them on other operating systems. The operating system provides a handful of driver models that define the functions your driver must expose and their operation. What sets Windows CE apart is the rich set of driver frameworks that it provides. These allow driver writers to concentrate on the hardware specific bits while the framework handles the common tasks like queue management and interrupt routing.

Model Behavior
A device driver abstracts the functionality of a physical or virtual device and manages the operation of these devices. Examples of physical devices are network adapters, timers, and universal asynchronous receiver-transmitters (UARTs). An example of a virtual device is a file system. Implementing a device driver allows the functionality of your device to be exposed to applications and other parts of the operating system. Windows CE device drivers are trusted modules but they do not have to run in kernel mode.

There are three main processes in Windows CE that load device drivers. Each process expects the driver to conform to a particular driver mode. The first process loaded by the kernel is filesys.exe, the file system process. This process loads file system drivers which must conform to the file system driver model.

After the file system and registry are loaded the device manager process, device.exe, is loaded. This process loads the majority of the device drivers in the system and they all expose the stream driver interface. Lastly, the graphics, windowing, and events subsystem (gwes.exe) runs and loads specialized drivers like display and keyboard drivers. These drivers conform to specialized driver models for their particular function. The following Table 1 below summarizes the three system processes that load device drivers.

 

 

Table 1

 

Windows CE supports the concept of installable file systems. When a device is attached such as a CompactFlash or SD/MMC drive the operating system will parse the partitions for the file system type and load the appropriate driver.

A file system driver (FSD) is a dynamic-link library (DLL) that exports file system entry points that map to standard Windows CE file system functions, such as CreateFile and CreateDirectory. When an application calls a file system function, and the function references a file on a volume registered by the FSD, the FSD Manager maps the call to the FSD. The FSD Manager manages all system interactions with installable FSDs.

The operating system provides a template for functions that you need to develop for a file system. The FSD may export the full range of functions entry points or it can exclude particular file system functions if you do not want that function to be available.

For example, to prevent applications from creating or destroying directories inside volumes belonging to your FSD, do not include CreateDirectory and RemoveDirectory in your FSD. The FSD Manager automatically supplies stub functions for any functions that you choose not to supply for your file system. These stub functions return an error code. As a result, if an application tries to create or remove a directory on a volume that belongs to your FSD, the call fails.

In addition to exporting entry points for the file system functions, an FSD must export entry points for the FSD_MountDisk and FSD_UnmountDisk functions. The Device Manager callsFSD_MountDisk when a target device for which that FSD has been registered is inserted or removed. The FSD_MountDisk and FSD_UnmountDisk entry points are each passed a value that uniquely identifies the disk being mounted. This value is passed back to the FSD Manager services that query, read, and write to that disk.

Stream Interface Drivers
The most common driver model in Windows CE is the stream interface driver. This driver model has roots in the earliest implementations of Unix. A stream driver exports functions to open, close, read, write, seek, or control the underlying hardware.

The stream interface is appropriate for any I/O device that can be thought of logically as a data source or a data sink. That is, any peripheral that produces or consumes streams of data as its primary function is a good candidate to expose the stream interface. A good example is a serial port device. An example of a device that does not produce or consume data in the traditional sense would be a display device, and indeed, the stream interface is not exposed for controlling display hardware.

A stream interface driver receives commands from the Device Manager and from applications by means of file system calls. The driver encapsulates all of the information that is necessary to translate those commands into appropriate actions on the devices that it controls.

All stream interface drivers, whether they manage built-in devices or installable devices, or whether they are loaded at boot time or loaded dynamically, have similar interactions with other system components.

The following illustrations show the interactions between system components for a generic stream interface driver that manages a built-in device, and for a stream interface driver for a PC CardClient device. Figure 1, below, shows the architecture for stream interface drivers for built-in devices that are loaded by the Device Manager at boot time.

 

 

Figure 1

 

Block Drivers
A block driver allows reads and writes of the underlying hardware resource through fixed sized block of data. Block devices do not allow you to read or write individual bytes of data. Common block sizes are 512 bytes, 1 kilobyte (KB), 2 KB, and 4 KB. Block devices are ideally suited for mass storage and persistent storage applications, such as disk drives or nonvolatile RAM disks.

Some common types of block devices are hard disks and Advanced Technology Attachment(ATA) flash memory disks in miniature card, PC Card, and Compact Flash card form factors.

Drivers for block devices generally expose the stream interface, and the block devices appear as ordinary disk drives. Applications access files on a block device through standard file APIs such as CreateFile and ReadFile. The application calls the ReadFile function using a handle to a file that is stored on the block device.

The FAT file system for example, translates the read request to logical blocks. The FAT file system searches the buffer cache for the requested blocks. If these are not present, it issues an IOControl request to the corresponding block device driver to read bytes from the block device. Then, the block device driver receives the IOControl request, and then fulfills the request by accessing the block device through one of its low-level interfaces.

The FAT file system implementation supports block devices. The FAT file system does not read or write to block devices directly; it uses underlying block device drivers for all access to block device hardware. The block device driver must present the block device to the FAT file system as a block-oriented device. Block device drivers transparently manage or emulate ordinary disk drives, so applications do not need to behave differently when reading and writing files to the block device.

The FAT file system provides an abstraction between files in the application name space, such as/Storage Card/Excel Docs/Expense report.pxl, and devices in the device name space, such asDSK1:. Block device drivers must respond to the I/O control codes shown in Table 2 below to interface properly with the FAT file system.

 

 

Table 2

 

Bus Drivers
A bus driver is any software that loads other drivers. In this sense device.exe is considered the "root" bus driver. A bus driver can be thought of as having a hierarchical structure starting with the root bus driver. Bus drivers have one or more of these responsibilities:

1. Managing physical busses, such as PC Card, USB, or PCI.
2. Loading drivers on a physical bus that the bus driver does not directly manage. An example is the Bus Enumerator (regenum.dll), which is a bus driver that loads built-in drivers and PCI bus drivers. 
3. Calling ActivateDeviceEx directly to load a device driver. 
4. The loaded device driver might manage hardware indirectly through another device driver.

To allow access to a device driver with CreateFile, bus drivers should provide the Device Manager with enough information to create bus-relative names and enable device handles. They should also provide enough information to identify themselves to drivers and applications for bus control (IOCTL) operations.

A bus driver can specify a busrelative name for the driver, but for drivers and applications to be able to access the bus driver for bus control operations, the bus driver must expose a stream interface. The $bus namespace provides a way to perform operations on a device that are different from typical device operations. By controlling access to the $bus namespace, you can also provide security for your system.

Bus Agnostic Drivers
A bus agnostic driver is written without knowledge where the underlying hardware device that it manages is located. The device may reside on the local microprocessor bus or it may be on a CompactFlash card inserted into the system.

A bus agnostic driver does not call functions that are specific to a hardware platform. Each driver gets its resources from the registry, requests configuration information from its parent bus driver, sets power states through its parent bus driver, and translates bus addresses to system addresses through its parent bus driver. Typically, you can migrate bus agnostic drivers more easily between hardware platforms than other types of drivers.

A bus agnostic driver must adhere to the following tasks to determine the location of its hardware resources in the system:

1. Open the device key by calling the OpenDeviceKey function. 
2. Obtain ISR information by calling the DDKReg_GetIsrInfo function. 
3. Obtain hardware I/O or memory window information by calling the DDKReg_GetWindowInfo function. 
4. Obtain a hardware and by calling the HalTranslateBusAddress function to translate the bus-specific address to a system physical address. 
5. Obtain a virtual address by calling the MnMapIoSpace function to map the system physical address. 
6. Reset your hardware and disable the interrupt. 
7. Load the installable ISR by calling the LoadIntChainHandler function with information obtained from DDKReg_GetIsrInfo. You should assume that your ISR will access the card register to identify the interrupt. TransBusAddrToStatic is needed to map the system physical address for hardware. 
8. Begin the IST and enable the interrupt.

Layered vs. Monolithic Drivers
Most device drivers consist of platform or hardware specific code and model or device type specific code. Windows CE refers to these two pieces as the platform dependent driver (PDD) and the model dependent driver (MDD).

This is a slight misnomer because the two pieces are actually software modules or a way of organizing the source code. It is not until you link the two pieces together do you truly have a "driver". If a device driver is organized in this way it is referred to as a layered driver.

A monolithic driver is one that does not separate the source code in this fashion. Because the monolithic driver does not define an API isolating the MDD and PDD modules it contains less code and is generally faster (more efficient). However, this does make the driver more difficult to maintain and less portable to future versions of Windows CE.

The obvious advantage of the MDD/PDD model is that it encourages code reuse. The device type or device model code is theoretically the same regardless of the underlying hardware.

For example all serial drivers will need to process receive and transmit buffers and handle flow control logic. These operations are independent of the hardware and should be isolated into a MDD module for code reuse. Because the MDD module is at the topmost layer of the driver it exposes the stream interface to the Device Manager. Some examples of tasks performed by the MDD module are:

1. Contain code that is common to all drivers of a given type. 
2. Call PDD functions to access the hardware. 
3. Link to the PDD layer and define the device driver service provider interface (DDSI) functions that the MDD expects to call in that layer. 
4. Expose device driver interface (DDI) functions to the operating system (OS). Other parts of the OS can call these functions. Related devices can share the same DDI. Monolithic drivers also expose the DDI functions. 
5. Handle interrupt processing. 
6. Provide for reuse by developers. 
7. Can link to multiple PDDs. 
8. Generally require no changes. (If changed, you might have trouble migrating drivers to future versions.) 
9. Contain any interrupt service threads (ISTs).

The PDD module has the following characteristics:

1. Consist of hardware platform specific code. 
2. Might require modification for your hardware platform. 
3. Are designed to work with specific MDD implementations. 
4. Expose the DDSI functions that the MDD calls. (Monolithic drivers do not expose the DDSI functions.)

Windows CE provides many MDD modules for a variety of device types.

Serial Drivers
The serial port driver handles any I/O devices that behave like serial ports, including those based on 16450 and 16550 universal asynchronous receiver-transmitter (UART) chips and those that use direct memory access (DMA).

Many hardware platforms have devices of this type, including ordinary 9-pin serial ports, infrared I/O ports, and PC Card serial devices, such as modems. If multiple types of serial ports exist on a hardware platform, you can either create several different serial drivers, one for each serial port type, or create several different lower layers (PDD) and link them to a single upper layer (MDD). This creates one multipurpose serial driver. Creating separate drivers can simplify debugging and maintenance because each driver supports only one type of port. Creating a multipurpose driver, such as the sample serial port driver, is more complex but gives a small memory savings.

Because the functionality of serial ports maps to the functionality provided by standard stream interface functions, the serial port driver uses the stream interface as its device interface. The serial port driver is a classic example of the MDD/PDD model. The MDD module supplied with Windows CE strives to handle all of the device-independent serial port functions leaving the PDD module as simple as possible.

Serial port devices make extensive use of I/O control codes to set and query various attributes of a serial port. For example, there are I/O control codes for setting and clearing the Data Terminal Ready (DTR) line, for purging any undelivered data and for getting the status of a modem device. Therefore, you should support as many serial I/O control codes as possible in your implementation of COM_IOControl.

Audio Drivers
Window CE supports two driver models for audio devices: the MDD/PDD model and the unified audio model (UAM). The MDD/PDD model is suitable for only the simplest of audio devices.

Because the MDD is designed to support the most common subset of functions that audio devices require there is bound to be functionality on more complex audio devices that is not covered. Instead of forcing developers to modify the MDD in that situation the unified audio model was created. A driver that conforms to the UAM is a structured monolithic driver. The UAM gives the developer complete control over the audio device but in a structured manner. Figure 2a and 2b below illustrate the subtle differences in the two driver models.

 

 

Figure 2a

Figure 2b

 

Network Drivers
Window CE supports the same network driver interface specification (NDIS) that the desktop version of Windows supports. This makes porting network device drivers from the desktop to Windows CE very straightforward. NDIS also provides a pair of abstraction layers that connect network drivers to an overlying protocol stack, such as TCP/IP or Infrared Data Association (IrDA) and an underlying network adapter.

NDIS performs a set of external functions for network adapter drivers, such as registering and intercepting hardware interrupts and communicating with underlying network adapters. As shown in Figure 3 below, NDIS provides driver interfaces (API) for accessing the upper-layer network stack and for accessing hardware. This high level of structure makes NDIS drivers very portable.

 

 

Figure 3

 

The only thing constant is change
Windows CE 6.0 introduces user-mode drivers. These drivers run in the user space of memory and it is very difficult for these drivers to crash the system. The traditional kernel-mode drivers share the same memory space as the kernel and other drivers and could potentially overwrite the memory of other processes and crash the system.

The following text is excerpted from the release notes included with the beta.

The new virtual memory architecture has significant implications for device drivers. Previous versions of the OS used special processes to add functionality to the base kernel. For example, one process managed loadable device drivers, another managed registry and file systems, another managed the windowing system, another managed system services, and so forth. In Windows CE 6 Beta, many system services execute in the context of the kernel. This improves the performance of intra-kernel calls that, in previous releases, required multiple traps into the kernel.

In Windows CE 6 Beta, device drivers need to be aware of any process that passes them pointers to memory buffers. In previous versions, each process had a unique virtual address space, so this was not a significant consideration. In Windows CE 6 Beta, a particular user-mode address might be valid in multiple processes. Changes to drivers are documented in detail in the Help. In many cases, drivers from previous releases are relatively easy to port to Windows CE 6 Beta OS.

Windows CE 6.0 is now in beta testing and will likely be released sometime in 2006.

posted @ 2010-06-21 22:20  andriod2012  阅读(184)  评论(0编辑  收藏  举报