Lesson 7: Enhancing Driver Portability
Device drivers help to increase the flexibility and portability of the operating system. Ideally, they require no code changes to run on different target devices with varying communication requirements. There are several relatively straightforward techniques that you can use to make your drivers portable and reusable. One common approach is to maintain configuration settings in the registry instead of hardcoding the parameters into the OAL or the driver. Windows Embedded CE also supports a layered architecture based on MDD and PDD that you can leverage in your device driver design, and there are further techniques that you can use to implement drivers in a bus-agnostic way to support peripheral devices regardless of the bus type to which they are connected.
After this lesson, you will be able to:
■ Describe how to use registry settings to increase the portability and reusability of a device driver.
■ Implement a device driver in a bus-agnostic way.
Estimated lesson time: 15 minutes.
Accessing Registry Settings in a Driver
To increase the portability and reusability of a device driver, you can configure registry entries, which you should add to the driver's registry subkey. For example, you can define I/O-mapped memory addresses or settings for installable ISRs that the device driver loads dynamically. To access the entries in a device driver's registry key, the driver has to identify where its own settings are located. This is not necessarily the HKEY_LOCAL_MACHINE\Drivers\BuiltIn key. However, the correct path information is available in the Key value that you can find under the HKEY_LOCAL_MACHINE\Drivers\Active key in the loaded driver's subkey. Device Manager passes the path to the driver's Drivers\Active subkey to the XXX_Init function in the LPCTSTR pContext parameter. The device driver can then use this LPCTSTR value in a call to OpenDeviceKey to obtain a handle to the device's registry key. It is not necessary to read the Key values from the driver's Drivers\Active subkey directly. The handle returned by OpenDeviceKey points to the driver's registry key, which you can use like any other registry handle. Most importantly, do not forget to close the handle when it is no longer needed.
The XXX_Init function is the best place to determine all configuration settings for a driver defined in the registry. Rather than accessing the registry repeatedly in subsequent stream function calls, it is good practice to store the configuration information in the device context created and returned to Device Manager in response to the XXX_Init call.
Interrupt-Related Registry Settings
If your device driver must load an installable ISR for a device and you want to increase the portability of your code, you can register the ISR handler, IRQ, and SYSINTR values in registry keys, read these values from the registry when initializing the driver, verify that the IRQ and SYSINTR values are valid, and then install the specified ISR by using the LoadIntChainHandler function.
Table 6-9 lists the registry entries that you can configure for this purpose. By calling the DDKReg_GetIsrInfo function, you can then read these values and pass them to the LoadIntChainHandler function dynamically. For more information about interrupt handing in device drivers, see Lesson 4, "Implementing an Interrupt Mechanism in a Device Driver," earlier in this chapter.
Table 6-9 Interrupt-related registry entries for device drivers
Registry Entry | Type | Description |
---|---|---|
IRQ | REG_DWORD | Specifies the IRQ used to request a SYSINTR for setting up an IST within the driver. |
SYSINTR | REG_DWORD | Specifies a SYSINTR value to use for setting up an IST within the driver. |
IsrDll | REG_SZ | The filename of the DLL containing the installable ISR. |
IsrHandler | REG_SZ | Specifies the entry point for the installable ISR that the specified DLL exposes. |
Memory-Related Registry Settings
Memory-related registry values enable you to configure a device through the registry. Table 6-10 lists the memory-related registry information that a driver can obtain in a DDKWINDOWINFO structure by calling DDKReg_GetWindowInfo. By using the BusTransBusAddrToVirtual function, you can map the bus addresses of memory-mapped windows to physical system addresses you can then translate into virtual addresses by using MnMapIoSpace.
Table 6-10 Memory-related registry entries for device drivers
Registry Entry | Type | Description |
---|---|---|
IoBase | REG_DWORD | A bus-relative base of a single memory-mapped window used by the device. |
IoLen | REG_DWORD | Specifies the length of the memory-mapped window defined in IoBase. |
MemBase | REG_MULTI_SZ | A bus-relative base of multiple memory-mapped windows used by the device. |
MemLen | REG_MULTI_SZ | Specifies the length of the memory-mapped memory windows defined in MemBase. |
PCI-Related Registry Settings
Another registry helper function that you can use to populate a DDKPCIINFO structure with the standard PCI device instance information is DDKReg_GetPciInfo. Table 6-11 lists the PCI-related settings you can configure in a driver's registry subkey.