Like many other computer architectures, Windows CE–based platforms use interrupts to signal the operating system when devices need servicing by their drivers. For example, when a user presses a key or taps a screen, the keyboard hardware or the touch screen generates an interrupt.
However, Windows CE does not support nested interrupts, meaning that interrupts cannot occur simultaneously. Processing of one interrupt must finish before another begins. While this limits the real-time scheduling capabilities of Windows CE, it vastly simplifies the process of writing interrupt handlers.
Windows CE balances performance and ease of implementation by breaking interrupt processing into two parts, a kernel-mode part and a user-mode part. The kernel-mode part is called the interrupt service routine (ISR), and the user-mode part is called the interrupt service thread (IST). The ISR is the part that cannot be nested; therefore, keep your ISRs short and fast so that interrupts are disabled as little as possible. The ISR resides in the OEM adaptation layer (OAL) and has direct access to hardware registers. Its sole job is to determine which interrupt identifier, such as SYSINTR_SERIAL, to return to the kernel interrupt handler. Essentially, ISRs map physical interrupts onto logical interrupts. Platform-independent interrupt identifiers are declared in the Nkintr.h header file, and platform-specific interrupt identifiers are declared in platform header files, such as Platform\Cepc\Inc\Oalintr.h.
Because an ISR is small and does very little processing, the interrupt handler calls an IST to perform the bulk of processing required to handle an interrupt. The IST remains idle until it receives a signal from the WaitForSingleObject function that an interrupt has occurred. When an IST receives the signal, it calls subroutines in the PDD layer of the native device driver; these routines in turn access the hardware to retrieve information or to set the hardware state. The IST is a standard secondary thread that can be pre-empted and scheduled by the operating system. However, to enhance real-time performance, Windows CE uses the two highest thread-priority levels, THREAD_PRIORITY_HIGHEST and THREAD_PRIORITY_TIME_CRITICAL, for ISTs. These priority levels are not reserved for ISTs; any secondary thread can also have those priority levels.
On a Windows CE–based reference platform, which uses the Hitachi SH3 microprocessor, the system can start an ISR in 2 to 5 microseconds. The system can start the corresponding IST in 90 to 170 microseconds. Many actual Windows CE-based platforms have better response times than these, depending on factors such as CPU type, clock speed, bus speed, and so on. Aside from hardware performance, the IST start times vary from one interrupt event to the next due to unpredictable factors, such as the state of the processor cache and whether the IST happens to be the currently running thread.
If your platform is not meeting your real-time performance requirements, you have the following options:
The following illustration shows the interaction of components during the interrupt process.
The exception handler is the primary target of all interrupts. When an interrupt occurs, the kernel jumps directly to the exception handler. The exception handler then calls whichever ISR is registered to handle the current interrupt.
OEMs register their ISRs with the exception handler at startup time. First, the kernel calls the OEMInit function in the OAL. Next, OEMInit calls the HookInterrupt function to inform the exception handler of which ISRs correspond to individual physical interrupt lines. A few subroutines in the OAL, such as the OEMInterruptEnable, OEMInterruptDisable, and OEMInterruptDone functions, are also used in interrupt processing.
The interrupt handler manages the details of registering a driver for a particular interrupt and deregistering it later. It also maintains communication among the ISR, the IST, and subroutines within the OAL.
Monolithic drivers can use the Interrupt Event Handler Support interface provided by the kernel. This interface is a lightweight process-synchronization model based on standard Win32 events. The interface consists of event-related functions, such as CreateEvent, SetEvent, ResetEvent, and WaitForSingleObject, and the Windows CE kernel InterruptDone, InterruptDisable, InterruptEnable, and InterruptInitialize functions. Layered drivers use the same functions to process interrupts, but you need not use these functions to port layered drivers because the MDD layer—which does not require modification—already contains the proper calls to these functions.
The following sections discuss in greater detail how to register an interrupt handler, process it, and deregister it.