Device driver writers possess a special blend of software and hardwareskills (among other things). They need to write highly structured andelegant code as well as debug down to the register level of thehardware. They have to do their tasks with less then optimal debughardware. They often make do without JTAG or Ethernet debug tools andfix tough problems with just their wit and a GPIO line. If you have thetenacity to write device drivers read on.
Writing device drivers for Windows CE is very similar to creatingthem on other operating systems. The operating system provides ahandful of driver models that define the functions your driver mustexpose and their operation. What sets Windows CE apart is the rich setof driver frameworks that it provides. These allow driver writers toconcentrate on the hardware specific bits while the framework handlesthe common tasks like queue management and interrupt routing.
A device driver abstracts the functionality of a physical or virtualdevice and manages the operation of these devices. Examples of physicaldevices are network adapters, timers, and universal asynchronousreceiver-transmitters (UARTs). An example of a virtual device is a filesystem. Implementing a device driver allows the functionality of yourdevice to be exposed to applications and other parts of the operatingsystem. Windows CE device drivers are trusted modules but they do nothave to run in kernel mode.
There are three main processes in Windows CE that load devicedrivers. Each process expects the driver to conform to a particulardriver mode. The first process loaded by the kernel is filesys.exe, thefile system process. This process loads file system drivers which mustconform to the file system driver model.
After the file system and registry are loaded the device managerprocess, device.exe, is loaded. This process loads the majority of thedevice drivers in the system and they all expose the stream driverinterface. Lastly, the graphics, windowing, and events subsystem(gwes.exe) runs and loads specialized drivers like display and keyboarddrivers. These drivers conform to specialized driver models for theirparticular function. The following Table 1 below summarizes the threesystem processes that load device drivers.
Windows CE supports the concept of installable file systems. When adevice is attached such as a CompactFlash or SD/MMC drive the operatingsystem will parse the partitions for the file system type and load theappropriate driver.
A file system driver (FSD) is a dynamic-link library (DLL) thatexports file system entry points that map to standard Windows CE filesystem functions, such as CreateFile and CreateDirectory. When anapplication calls a file system function, and the function references afile on a volume registered by the FSD, the FSD Manager maps the callto the FSD. The FSD Manager manages all system interactions withinstallable FSDs.
The operating system provides a template for functions that you needto develop for a file system. The FSD may export the full range offunctions entry points or it can exclude particular file systemfunctions if you do not want that function to be available.
For example, to prevent applications from creating or destroyingdirectories inside volumes belonging to your FSD, do not includeCreateDirectory and RemoveDirectory in your FSD. The FSD Managerautomatically supplies stub functions for any functions that you choosenot to supply for your file system. These stub functions return anerror code. As a result, if an application tries to create or remove adirectory 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 andFSD_UnmountDisk functions.The Device Manager calls FSD_MountDisk whena target device for which that FSD has been registered is inserted orremoved. The FSD_MountDisk and FSD_UnmountDisk entrypoints are eachpassed a value that uniquely identifies the disk being mounted. Thisvalue is passed back to the FSD Manager services that query, read, andwrite to that disk.
Stream Interface Drivers
The most common driver model in Windows CE is the stream interfacedriver. This driver model has roots in the earliest implementations ofUnix. 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 bethought of logically as a data source or a data sink. That is, anyperipheral that produces or consumes streams of data as its primaryfunction is a good candidate to expose the stream interface. A goodexample is a serial port device. An example of a device that does notproduce or consume data in the traditional sense would be a displaydevice, and indeed, the stream interface is not exposed for controllingdisplay hardware.
A stream interface driver receives commands from the Device Managerand from applications by means of file system calls. The driverencapsulates all of the information that is necessary to translatethose commands into appropriate actions on the devices that itcontrols.
All stream interface drivers, whether they manage built-in devicesor installable devices, or whether they are loaded at boot time orloaded dynamically, have similar interactions with other systemcomponents.
The following illustrations show the interactions between systemcomponents for a generic stream interface driver that manages abuilt-in device, and for a stream interface driver for a PC Card Clientdevice. Figure 1 , below , showsthe architecture for stream interfacedrivers for built-in devices that are loaded by the Device Manager atboot time.
A block driver allows reads and writes of the underlying hardwareresource through fixed sized block of data. Block devices do not allowyou to read or write individual bytes of data. Common block sizes are512 bytes, 1 kilobyte (KB), 2 KB, and 4 KB. Block devices are ideallysuited for mass storage and persistent storage applications, such asdisk drives or nonvolatile RAM disks.
Some common types of block devices are hard disks and AdvancedTechnology Attachment (ATA) flash memory disks in miniature card, PCCard, and Compact Flash card form factors.
Drivers for block devices generally expose the stream interface, andthe block devices appear as ordinary disk drives. Applications accessfiles on a block device through standard file APIs such as CreateFile and ReadFile . The applicationcalls the ReadFile function using ahandle to a file that is stored on the block device.
The FAT file system for example, translates the read request tological blocks. The FAT file system searches the buffer cache for therequested blocks. If these are not present, it issues an IOControlrequest to the corresponding block device driver to read bytes from theblock device. Then, the block device driver receives the IOControlrequest, and then fulfills the request by accessing the block devicethrough one of its low-level interfaces.
The FAT file system implementation supports block devices. The FATfile system does not read or write to block devices directly; it usesunderlying block device drivers for all access to block devicehardware. The block device driver must present the block device to theFAT file system as a block-oriented device. Block device driverstransparently manage or emulate ordinary disk drives, so applicationsdo not need to behave differently when reading and writing files to theblock device.
The FAT file system provides an abstraction between files in theapplication name space, such as StorageCardExcel DocsExpensereport.px l, and devices in the device name space, such as DSK1:. Blockdevice drivers must respond to the I/O control codes shown inTable 2below to interface properly with the FAT file system.
A bus driver is any software that loads other drivers. In this sensedevice.exe is considered the “root” bus driver. A bus driver can bethought of as having a hierarchical structure starting with the rootbus 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 aphysical bus that the bus driver does not directly manage.An example is the Bus Enumerator (regenum.dll) ,which is a bus driverthat loads built-in drivers and PCI bus drivers.
3. Calling ActivateDeviceEx directly to load a device driver.
4. The loaded device drivermight manage hardware indirectly through anotherdevice driver.
To allow access to a device driver with CreateFile , bus driversshould provide the Device Manager with enough information to createbus-relative names and enable device handles. They should also provideenough information to identify themselves to drivers and applicationsfor bus control (IOCTL )operations.
A bus driver can specify a busrelative name for the driver, but fordrivers and applications to be able to access the bus driver for buscontrol operations, the bus driver must expose a stream interface. The$bus namespace provides a way to perform operations on a device thatare different from typical device operations. By controlling access tothe $bus namespace , you canalso provide security for your system.
Bus Agnostic Drivers
A bus agnostic driver is written without knowledge where the underlyinghardware device that it manages is located. The device may reside onthe local microprocessor bus or it may be on a CompactFlash cardinserted into the system.
A bus agnostic driver does not call functions that are specific to ahardware platform. Each driver gets its resources from the registry,requests configuration information from its parent bus driver, setspower states through its parent bus driver, and translates busaddresses to system addresses through its parent bus driver. Typically,you can migrate bus agnostic drivers more easily between hardwareplatforms than other types of drivers.
A bus agnostic driver must adhere to the following tasks todetermine the location of its hardware resources in the system:
1. Open the device key bycalling the OpenDeviceKey function.
2. Obtain ISR information bycalling the DDKReg_GetIsrInfo function.
3. Obtain hardware I/O ormemory window information by calling the DDKReg_GetWindowInfo function.
4. Obtain a hardware and bycalling the HalTranslateBusAddress function to translate thebus-specific address to a system physical address.
5. Obtain a virtual address bycalling the MnMapIoSpace function to map the system physical address.
6. Reset your hardware anddisable the interrupt.
7. Load the installable ISR bycalling the LoadIntChainHandler function with information obtained fromDDKReg_GetIsrInfo. You should assume that your ISR will access the cardregister to identify the interrupt. TransBusAddrToStatic is needed tomap the system physical address for hardware.
8. Begin the IST and enable theinterrupt.
Layered vs. Monolithic Drivers
Most device drivers consist of platform or hardware specific code andmodel or device type specific code. Windows CE refers to these twopieces as the platform dependent driver (PDD) and the model dependentdriver (MDD).
This is a slight misnomer because the two pieces are actuallysoftware modules or a way of organizing the source code. It is notuntil you link the two pieces together do you truly have a “driver”. Ifa device driver is organized in this way it is referred to as a layereddriver.
A monolithic driver is one that does not separate the source code inthis fashion. Because the monolithic driver does not define an APIisolating the MDD and PDD modules it contains less code and isgenerally faster (more efficient). However, this does make the drivermore difficult to maintain and less portable to future versions ofWindows CE.
The obvious advantage of the MDD/PDD model is that it encouragescode reuse. The device type or device model code is theoretically thesame regardless of the underlying hardware.
For example all serial drivers will need to process receive andtransmit buffers and handle flow control logic. These operations areindependent of the hardware and should be isolated into a MDD modulefor code reuse. Because the MDD module is at the topmost layer of thedriver it exposes the stream interface to the Device Manager. Someexamples of tasks performed by the MDD module are:
1. Contain code that iscommon to all drivers of a given type.
2. Call PDD functions to accessthe hardware.
3. Link to the PDD layer anddefine the device driver service provider interface (DDSI) functionsthat the MDD expects to call in that layer.
4. Expose device driverinterface (DDI) functions to the operating system (OS). Other parts ofthe OS can call these functions. Related devices can share the sameDDI. Monolithic drivers also expose the DDI functions.
5. Handle interrupt processing.
6. Provide for reuse bydevelopers.
7. Can link to multiple PDDs.
8. Generally require nochanges. (If changed, you might have trouble migrating drivers tofuture versions.)
9. Contain any interruptservice threads (ISTs).
The PDD module has the following characteristics:
1. Consist of hardwareplatform specific code.
2. Might require modificationfor your hardware platform.
3. Are designed to work withspecific MDD implementations.
4. Expose the DDSI functionsthat the MDD calls. (Monolithic drivers do not expose the DDSIfunctions.)
Windows CE provides many MDD modules for a variety of device types.
The serial port driver handles any I/O devices that behave like serialports, including those based on 16450 and 16550 universal asynchronousreceiver-transmitter (UART) chips and those that use direct memoryaccess (DMA).
Many hardware platforms have devices of this type, includingordinary 9-pin serial ports, infrared I/O ports, and PC Card serialdevices, such as modems. If multiple types of serial ports exist on ahardware platform, you can either create several different serialdrivers, one for each serial port type, or create several differentlower layers (PDD) and link them to a single upper layer (MDD). Thiscreates one multipurpose serial driver. Creating separate drivers cansimplify debugging and maintenance because each driver supports onlyone type of port. Creating a multipurpose driver, such as the sampleserial port driver, is more complex but gives a small memory savings.
Because the functionality of serial ports maps to the functionalityprovided by standard stream interface functions, the serial port driveruses the stream interface as its device interface. The serial portdriver is a classic example of the MDD/PDD model. The MDD modulesupplied with Windows CE strives to handle all of thedevice-independent serial port functions leaving the PDD module assimple as possible.
Serial port devices make extensive use of I/O control codes to setand query various attributes of a serial port. For example, there areI/O control codes for setting and clearing the Data Terminal Ready(DTR) line, for purging any undelivered data and for getting the statusof a modem device. Therefore, you should support as many serial I/Ocontrol codes as possible in your implementation of COM_IOControl.
Window CE supports two driver models for audio devices: the MDD/PDDmodel and the unified audio model (UAM). The MDD/PDD model is suitablefor only the simplest of audio devices.
Because the MDD is designed to support the most common subset offunctions that audio devices require there is bound to be functionalityon more complex audio devices that is not covered. Instead of forcingdevelopers to modify the MDD in that situation the unified audio modelwas created. A driver that conforms to the UAM is a structuredmonolithic driver. The UAM gives the developer complete control overthe audio device but in a structured manner. Figure 2a and 2b belowillustrate the subtle differences in the two driver models.
Window CE supports the same network driver interface specification(NDIS) that the desktop version of Windows supports. This makes portingnetwork device drivers from the desktop to Windows CE verystraightforward. NDIS also provides a pair of abstraction layers thatconnect network drivers to an overlying protocol stack, such as TCP/IPor Infrared Data Association (IrDA) and an underlying network adapter.
NDIS performs a set of external functions for network adapterdrivers, such as registering and intercepting hardware interrupts andcommunicating with underlying network adapters. As shown in Figure 3below , NDIS provides driver interfaces (API) for accessing theupper-layer network stack and for accessing hardware. This high levelof structure makes NDIS drivers very portable.
The only thing constant is change
Windows CE 6.0 introduces user-mode drivers. These drivers run in theuser space of memory and it is very difficult for these drivers tocrash the system. The traditional kernel-mode drivers share the samememory space as the kernel and other drivers and could potentiallyoverwrite the memory of other processes and crash the system.
The following text is excerpted from the release notes included withthe beta.
The new virtualmemory architecture hassignificant implications for device drivers. Previous versions of theOS used special processes to add functionality to the base kernel. Forexample, one process managed loadable device drivers, another managedregistry 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. Thisimproves the performance of intra-kernel calls that, in previousreleases, required multiple traps into the kernel.
In Windows CE 6Beta, devicedrivers need to be aware of any process that passes them pointers tomemory buffers. In previous versions, each process had a unique virtualaddress space, so this was not a significant consideration. In WindowsCE 6 Beta, a particular user-mode address might be valid in multipleprocesses. Changes to drivers are documented in detail in the Help. Inmany cases, drivers from previous releases are relatively easy to portto Windows CE 6 Beta OS .
Windows CE 6.0 is now in beta testing and will likely be releasedsometime in 2006.
David Heil ischief engineer at CalAmp Solutions Corp.
|This article is excerpted from a paper ofthe same name presented atthe Embedded Systems Conference Boston 2006. Used with permission ofthe Embedded Systems Conference. For more information, please visit www.embedded.com/esc/boston/|