Installable ISRs and the Kernel

Other versions of this page are also available for the following:

Windows Mobile Not SupportedWindows Embedded CE Supported

8/28/2008

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 has to be hooked to provide service to some event, the code has to be built in when the kernel is originally built. If a new device is inserted into a Peripheral Component Interconnect (PCI) bus for example, the code to handle the interrupt request (IRQ) has to be in the kernel already; otherwise, the IRQ cannot be hooked. OEMs can plan for some expansion and build an OEM adaptation layer (OAL) that accommodates various devices in a flexible way. However, if an unknown device is inserted into the board support package (BSP), there is a high likelihood that you cannot access it.

OEMs must plan only for what IRQ is 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 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 the 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 provide a service to an IRQ. Like a regular ISR, an installed ISR returns a SYSINTR_* value that triggers a waiting IST in the driver DLL.

The OEM must 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 to 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 is triggered by a call to NKCallIntChain. When the kernel is called and is 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. After a value, that is not an 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 must 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 can have 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, after you have configured the OAL, you can update the registry to inform the serial drivers about which Sysintr to use.

The generic installable ISR sample code is located in %_WINCEROOT%\Public\Common\Oak\Drivers\GIISR. The generic installable ISR must export the following functions:

The following I/O control codes are specific to the driver:

  • IOCTL_GIISR_INFO
  • IOCTL_GIISR_PORTVALUE

See Also

Other Resources

Defining an Interrupt Identifier
Implementing an ISR
Loader
PCI Bus Driver
Real-Time Priority System