Table 6-11 PCI-related registry entries for device drivers
Registry Entry | Type | Description |
---|---|---|
DeviceNumber | REG_DWORD | The PCI device number. |
FunctionNumber | REG_DWORD | The PCI function number of the device, which indicates a single function device on a multifunction PCI card. |
InstanceIndex | REG_DWORD | The instance number of the device. |
DeviceID | REG_DWORD | The type of the device |
ProgIF | REG_DWORD | A register-specific programming interface, for example, USB OHCI or UHCI. |
RevisionId | REG_DWORD | The revision number of the device. |
Subclass | REG_DWORD | The basic function of the device; for example, an IDE controller. |
SubSystemId | REG_DWORD | The type of card or subsystem that uses the device. |
SubVendorId | REG_DWORD | The vendor of the card or subsystem that uses the device. |
VendorId | REG_MULTI_SZ | The manufacturer of the device. |
Developing Bus-Agnostic Drivers
Similar to settings for installable ISRs, memory-mapped windows, and PCI device instance information, you can maintain any GPIO numbers or timing configurations in the registry and achieve in this way a bus-agnostic driver design. The underlying idea of a bus-agnostic driver is the support of multiple bus implementations for the same hardware chipset, such as PCI or PCMCIA, without requiring code modifications.
To implement a bus-agnostic driver, use the following approach:
1. Maintain all necessary configuration parameters in the driver's registry subkey, and use the Windows Embedded CE registry helper functions DDKReg_GetIsrInfo, DDKReg_GetWindowInfo, and DDKReg_GetPciInfo to retrieve these settings during driver initialization.
2. Call HalTranslateBusAddress to translate bus-specific addresses to system physical addresses and then call MmMapIoSpace to map the physical addresses to virtual addresses.
3. Reset the hardware, mask the interrupt, and load an installable ISR by calling the LoadIntChainHandler function with information obtained from DDKReg_GetIsrInfo.
4. Load any initialization settings for the installable ISR from the registry by using RegQueryValueEx and pass the values to the installable ISR in a call to KernelLibIoControl with a user-defined IOCTL. For example, the Generic Installable Interrupt Service Routine (GIISR) included in Windows Embedded CE uses an IOCTL_GIISR_INFO handler to initialize instance information that enables GIISR to recognize when the device's interrupt bit is set and return the corresponding SYSINTR value. You can find the source code in the C:\Wince600\Public\Common\Oak\Drivers\Giisr folder.
5. Begin the IST by calling the CreateThread function and unmask the interrupt.
Lesson Summary
To increase the portability of a device driver, you can configure the registry entries in the driver's registry subkey. Windows Embedded CE provides several registry helper functions that you can then use to retrieve these settings, such as DDKReg_GetIsrInfo, DDKReg_GetWindowInfo, and DDKReg_GetPciInfo. These helper functions query specific information for installable ISRs, memory-mapped windows, and PCI device instance information, yet you can also call RegQueryValueEx to retrieve values from other registry entries. However, to use any of these registry functions, you must first obtain a handle to the driver's registry subkey by calling OpenDeviceKey. OpenDeviceKey expects a registry path, which Device Manager passes to the driver in the XXX_Init function call. Do not forget to close the registry handle when it is no longer needed.
Lab 6: Developing Device Drivers
In this lab, you implement a stream driver that stores and retrieves a string of 128 Unicode characters in memory. A base version of this driver is available in the companion material for this book. You only need to add the code as a subproject to an OS design. You then configure .bib file and registry settings to load this driver automatically during boot time and create a WCE Console Application to test the driver's functionality. In a last step, you add power management support to the string driver.
To help you successfully master the procedures presented in this Lab, see the document "Detailed Step-by-Step Instructions for Lab 6" in the companion material for this book.
► Add a Stream Interface Driver to a Run-Time Image
1. Clone the Device Emulator BSP and create an OS design based on this BSP as outlined in Lab 2, "Building and Deploying a Run-Time Image."
2. Copy the string driver source code that you can find on the companion CD in the \Labs\StringDriver\String folder into your BSP folder in the path %_WINCEROOT%\Platform\<BSPName>\Src\Drivers. This should result in a folder named String in your platform in the Drivers folder, and immediately inside this folder you should have the files from the driver on the companion CD, such as sources, string.c, string.def. It's possible to write a driver from scratch, but starting from a working example such as this is much quicker.
3. Add an entry to the Dirs file in the Drivers folder above your new String folder to include the string driver into the build process.
Do not use the Include In Build option in Solution Explorer to include the string driver into the build process. Solution Explorer removes important CESYSGEN directives from the Dirs file.
4. Add an entry to Platform.bib to add the built string driver, contained in $(_FLATRELEASEDIR), to the run-time image. Mark the driver module as a hidden system file.
5. Add the following line to Platform.reg to include the string driver's .reg file into the run-time image's registry:
#include "$(_TARGETPLATROOT)\SRC\DRIVERS\String\string.reg"
6. Build the string driver by right clicking it in Solution Explorer and selecting Build.