Enabling the PCI Bus Driver
Other versions of this page are also available for the following:
8/28/2008
The PCI Bus driver is in %_WINCEROOT%\Public\Common\Oak\Drivers\PCIbus. It is responsible for enumerating the PCI bus and loading device drivers for all PCI devices it finds and recognizes on the bus.
To support driver loading, driver unloading, and PCI bus power management, the PCI bus driver remains loaded. This allows dynamic loading of device drivers for PCI devices. Individual device drivers do not need to enumerate their bus on their own.
All PCI bus enumeration code is contained in one DLL and all device drivers can reuse this code.
Note
For the CEPC or any hardware platform that uses a BIOS to set up the PCI bus, the PCI bus driver does not need to configure the bus.
Note
The PCI bus driver enumerates or reads the state of the bus and provides this information into the Instance key for a device and the driver, and the I/O Resource Manager.
Note
You can skip the configuration step by setting NoConfig equal to 1. This value is a subkey of RootKey\PCI.
Note
If you need to configure, set NoConfig equal to 0 (zero), or remove it.
The following steps show you how to enable the PCI bus driver and the associated installable interrupt service routines (ISRs).
To enable the PCI bus driver
Modify the boot loader and initialization code.
Typically, the boot loader and startup code enumerates the entire PCI bus. Modify this functionality so that the boot loader and startup code enumerates only the debugging devices that reside on the PCI bus. This is typically the Ethernet debugging adapter. Serial is usually a legacy ISA port.
Make sure the enumerator handles the case where the debug device is behind a PCI to PCI bridge or PCI to PCI bridges.
The host to PCI bridge is set up with the largest possible windows, while any PCI to PCI bridges between the host and the Ethernet debugging device will be set up with windows that are only as large as the debugging devices.
This window starts at the beginning of the host to PCI bridge window. This allows the PCI bus driver to expand this window to accommodate additional devices.
If there is more than one debugging device that shares the same resource type, memory or I/O space, their resources must be placed next to each other, or as close as possible allowed by natural alignment.
Any devices and bridges other than the debugging devices must be disabled by setting the three least significant bits of the command register equal to zero. At power-on, this is the default state.
The registry needs to be populated with information about the debugging device. This is needed for the PCI bus enumerator to recognize that the device is already set up and is using resources.
The PCI_DEV_INFO structure is filled with information about the device. This information includes bus, device and function numbers, memory, I/O base addresses, and so on, when the debugging device is set up.
For an example, see %_WINCEROOT%\Public\Common\OAK\Drivers\PCIBus\PCIcfg.c. The structure is written to the registry key HKEY_LOCAL_MACHINE\Drivers\BuiltIn\PCI\Instance\KITL in this example, with a call to IOCTL_HAL_INITREGISTRY by the kernel.
Set up the host to PCI bridge.
Typically, the boot loader and startup code have already properly set up the host to PCI bridge. The PCI window must match that of the resources described in the registry under the main PCI key.
Implement OAL functions.
Implement the following functions in your OAL. These are declared in %_WINCEROOT%\Platform\<Hardware platform>\Inc\Oalintr.h.
Function Description Used by the PCI bus enumerator to request an IRQ for a PCI device.
Used in the OEMIoControl routine to implement IOCTL_HAL_TRANSLATE_IRQ and IOCTL_HAL_REQUEST_SYSINTR.
Used by the main ISR to translate a non-shareable IRQ into a SYSINTR, or the last shared IRQ that is not covered by an installable ISR.
This is a direct one-to-one mapping of IRQ to SYSINTR.
Maps a SYSINTR to its corresponding IRQ.
Update OEMIoControl.
Update OEMIoControl to include IOCTL_HAL_TRANSLATE_IRQ, IOCTL_HAL_REQUEST_SYSINTR, and IOCTL_HAL_REQUEST_IRQ.
See %_WINCEROOT%\Platform\<Hardware platform>\Src\Kernel\OAL and %_WINCEROOT%\Platform\<Hardware platform>\Src\Inc for example implementations.
Update the main OAL ISR routine.
Call the chain of installed interrupts first to see if anything claims the interrupt. If nothing does, perform the standard action of translating the IRQ into a SYSINTR and then return. You can slightly optimize this by calling NKCallIntChain only on IRQs for which installable ISRs are allowed.
See %_WINCEROOT%\Platform\Common\Src\X86\Common\Intr\fwpc.c for an example implementation.
This implementation is also shown in the code example below.
// Call interrupt chain to see if any installed ISRs handle this interrupt nSysIntr = NKCallIntChain(nIRQ); // IRQ not claimed by installed ISR; translate into SYSINTR if (nSysIntr == SYSINTR_CHAIN) { nSysIntr = OEMTranslateIrq(nIRQ); } // If we have found a valid interrupt, disable it and return SYSINTR if (nSysIntr != -1) { OEMInterruptDisable(nSysIntr); return nSysIntr; } else { return SYSINTR_NOP; }
Update Platform.reg and Platform.bib.
The MemBase, MemLen, IoBase and IoLen values under the PCI key indicate the PCI bus windows used by the system. These are logical, physical, PCI bus-relative addresses. These addresses are not translated.
Add PCIbus.dll to Platform.bib, and add the following to Platform.reg.
The values for MemBase, MemLen, IoBase, and IoLen are sample values and are not expected to work with every hardware platform.
When NoConfig is set to 1, the MemBase, MemLen, IoBase, and IoLen values are not used.
[HKEY_LOCAL_MACHINE\Drivers\BuiltIn\PCI] "Dll"="PCIbus.dll" "Order"=dword:20 "Flags"=dword:1 "NoConfig"=dword:0 "MemBase"=dword:40000000 "MemLen"=dword:20000000 "IoBase"=dword:00800000 "IoLen"=dword:00800000