Installable ISRs and the Kernel (Windows CE 5.0)
An installable interrupt service routine (ISR) is one that can be installed and allowed to hook an interrupt after the kernel is built. Usually, if an interrupt had to be hooked to service some event, the code had to be built into the kernel when it was originally built. If a new device was inserted into a PCI bus for example, the code to handle the interrupt request (IRQ) would need to already be in the kernel; otherwise, the IRQ could not be hooked. OEMs could have planned for some expansion and built an OEM adaptation layer (OAL) that accommodated various devices in a flexible way. However, if an unknown device was inserted into the board support package (BSP), there would be a high likelihood that you would not be able to access it.
OEMs must plan only what IRQ will be exposed to an ISR that is not built into the kernel. When an ISR is installed, the following considerations must be taken into account:
The driver DLL is similar to any driver DLL that creates an interrupt service thread (IST) and waits for it to be triggered. To install the ISR DLL, call the LoadIntChainHandler function, which loads the ISR DLL into the kernel's address space and initializes it. This function also forces the kernel to create a list of installed ISRs that will handle a particular interrupt.
Note The installable ISR DLL must be in the FILES section with no fixup variable or in the MODULES section with the kernel flag, K, set for a kernel-style fixup variable. A fixup variable is functionality of ROMIMAGE that allows you to initialize a global variable in the Nk.exe at MAKEIMG time.
The ISR DLL is a stripped-down DLL that can be loaded by the kernel and used to service an IRQ. Like a regular ISR, an installed ISR returns a SYSINTR_* value that triggers a waiting IST in the driver DLL.
It is up to the OEM to forward any IRQs to the installed ISRs. The OEM is still the first call that the kernel makes if an OEM has hooked an IRQ by calling HookInterrupt. The OEM can handle any IRQs they want in the traditional ISRs that are built into the kernel. OEMs must decide if an IRQ should be handled by an installed ISR. Any IRQ that the OEM enables to be handled by an installed ISR will be triggered by a call to NKCallIntChain. When the kernel is called and passed an interrupt value from the OEM, the kernel looks for all the installed ISRs that have registered for the same value. Then, based on a first in, first out (FIFO) ordering, the kernel goes through the list until the first ISR in the list returns a value other than SYSINTR_CHAIN. Once a non-SYSINTR_CHAIN value is returned, the kernel stops calling additional installed ISRs and returns this value to the caller of NKCallIntChain.
The following list shows what OEMs need to do based on the return value from NKCallIntChain:
- If the entire list is processed and the ISR does not handle the IRQ, the NKCallIntChain function returns SYSINTR_CHAIN.
- If the return value from NKCallIntChain is not SYSINTR_CHAIN, OEMs should disable the interrupt and return the SYSINTR_* value to the kernel.
- If the value returned from NKCallIntChain is SYSINTR_CHAIN, OEMs should return SYSINTR_NOP to the kernel and leave the interrupt enabled.
You can map multiple system interrupts to a single shared IRQ. The following list shows different ways to map multiple system interrupts to a single shared IRQ:
- Use IOCTL_HAL_REQUEST_SYSINTR and pass the OAL your IRQ and the OAL returns a Sysintr value that you can use. If your driver unloads, use IOCTL_HAL_RELEASE_SYSINTR.
- Hard-code the Sysintr values into your OAL. Multiple Sysintr values can correspond to one IRQ. IRQ values and Sysintr values have up to a one-to-one relationship, which defines the default Sysintr value for the IRQ. For examples, see SETUP_INTERRUPT_MAP and OEMRequestSysIntr. You can add the hard-coded Sysintr values, beginning at SYSINTR_FIRMWARE + 16, to OEMInit, immediately after the last SETUP_INTERRUPT_MAP. You cannot use SETUP_INTERRUPT_MAP directly because it includes instances of DEBUGCHK, which ensure that the same IRQ is not mapped twice. Although this method is not as flexible as the one above, once you have configured the OAL, you can simply update the registry to inform the serial drivers which Sysintr to use.
The generic installable ISR sample code is located in %_WINCEROOT%\Public\Common\Oak\Drivers\GIISR. The generic installable ISR needs to export the following functions:
The following I/O control codes are specific to the driver:
- IOCTL_GIISR_INFO
- IOCTL_GIISR_PORTVALUE
See Also
Defining an Interrupt Identifier | Implementing an ISR | Loader | PCI Bus Driver | Real-Time Priority System
Send Feedback on this topic to the authors