occurred that requires immediate attention, such as timer events or keyboard events. In response to an interrupt, the CPU stops executing the current thread, jumps to a trap handler in the kernel to respond to the event, and then resumes executing the original thread after the interrupt is handled. In this way, integrated and peripheral hardware components, such as system clock, serial ports, network adapters, keyboards, mouse, touchscreen, and other devices, can get the attention of the CPU and have the kernel exception handler run appropriate code in interrupt service routines (ISRs) within the kernel or in associated device drivers. To implement interrupt processing in a device driver efficiently, you must have a detailed understanding of Windows Embedded CE 6.0 interrupt handling mechanisms, including the registration of ISRs in the kernel and the execution of interrupt service threads (ISTs) within the Device Manager process.
After this lesson, you will be able to:
¦ Implement an interrupt handler in the OEM adaptation layer (OAL).
¦ Register and handle interrupts in a device driver interrupt service thread (IST).
Estimated lesson time: 40 minutes.
Interrupt Handling Architecture
Windows Embedded CE 6.0 is a portable operating system that supports different CPU types with varying interrupt schemes by implementing a flexible interrupt handling architecture. Most importantly, the interrupt handling architecture takes advantage of interrupt-synchronization capabilities in the OAL and thread- synchronization capabilities of Windows Embedded CE to split the interrupt processing into ISRs and ISTs, as illustrated in Figure 6-6.
Figure 6-6 IRQs, ISRs, SYSINTRs, and ISTs
Windows Embedded CE 6.0 interrupt handling is based on the following concepts:
1. During the boot process, the kernel calls the OEMInit function in the OAL to register all available ISRs built into the kernel with their corresponding hardware interrupts based on their interrupt request (IRQ) values. IRQ values are numbers that identify the source of the interrupt in the processor interrupt controller registers.
2. Device drivers can dynamically install ISRs implemented in ISR DLLs by calling the LoadIntChainHandler function. LoadIntChainHandler loads the ISR DLL into kernel memory space and registers the specified ISR routine with the specified IRQ value in the kernel's interrupt dispatch table.
3. An interrupt occurs to notify the CPU that an event requires suspending the current thread of execution and transferring control to a different routine.
4. In response to the interrupt, the CPU stops executing the current thread and jumps to the kernel exception handler as the primary target of all interrupts.
5. The exception handler masks off all interrupts of an equal or lower priority and then calls the appropriate ISR registered to handle the current interrupt. Most hardware platforms use interrupt masks and interrupt priorities to implement hardware-based interrupt synchronization mechanisms.
6. The ISR performs any necessary tasks, such as masking the current interrupt so that the current hardware device cannot trigger further interrupts, which would interfere with the current processing, and then returns a SYSINTR value to the exception handler. The SYSINTR value is a logical interrupt identifier.
7. The exception handler passes the SYSINTR value to the kernel's interrupt support handler, which determines the event for the SYSINTR value, and, if found, signals that event for any waiting ISTs for the interrupt.
8. The interrupt support handler unmasks all interrupts, with the exception of the interrupt currently in processing. Keeping the current interrupt masked off explicitly prevents the current hardware device from triggering another interrupt while the IST runs.
9. The IST runs in response to the signaled event to perform and finish the interrupt handling without blocking other devices on the system.
10. The IST calls the InterruptDone function to inform the kernel's interrupt support handler that the IST has finished its processing and is ready for another interrupt event.
11. The interrupt support handler calls the OEMInterruptDone function in the OAL to complete the interrupt handling process and reenable the interrupt.
Interrupt Service Routines
In general, ISRs are small blocks of code that run in response to a hardware interrupt. Because the kernel exception handler masks off all interrupts of equal or lesser priority while this ISR runs, it is important to complete the ISR and return a SYSINTR value as quickly as possible so that the kernel can re-enable (unmask) all IRQs with minimal delay (except the currently processed interrupt). System performance can suffer significantly if too much time is spent in ISRs, leading to missed interrupts or overrun buffers on some devices. Another important aspect is that the ISR runs in kernel mode and does not have access to higher-level operating system APIs. For these reasons, ISRs usually perform no more than the most basic tasks, such as quickly copying data from hardware registers to memory buffers. On Windows Embedded CE, time-consuming interrupt processing is usually performed in an IST.
The primary task of the ISR is to determine the interrupt source, mask off or clear the interrupt at the device, and then return a SYSINTR value for the interrupt to notify the kernel about an IST to run. In the simplest case, the ISR returns SYSINTR_NOP to indicate that no further processing is necessary. Accordingly, the kernel does not signal an event for an IST to handle the interrupt. On the other hand, if the device driver uses an IST to handle the interrupt, the ISR passes the logical interrupt identifier to the kernel, the kernel determines and signals the interrupt event, and the IST typically resumes from a WaitForSingleObject call and executes the interrupt processing instructions in a loop. The latency between the ISR and the IST depends on the priority of the thread and other threads running in the system, as explained in Chapter 3, 'Performing System Programming.' Typically, ISTs run with a high thread priority.
Interrupt Service Threads
An IST is a regular thread that performs additional processing in response to an interrupt, after the ISR has completed. The IST function typically includes a loop and a WaitForSingleObject call to block the thread infinitely until the kernel signals the specified IST event, as illustrated in the following code snippet. However, before you can use the IST event, you must call InterruptInitialize with the SYSINTR value and an event handle as parameters so that the CE kernel can signal this event whenever an ISR returns the SYSINTR value. Chapter 3 provides detailed information about multithreaded programming and thread synchronization based on events and other kernel objects.
CeSetThreadPriority(GetCurrentThread(), 200);
// Loop until told to stop
while(!pIst->stop) {
// Wait for the IST event.
WaitForSingleObject(pIst->hevIrq, INFINITE)