An ARM CPU typically has two pins (FIQ and IRQ) that are asserted by devices when they want to generate an interrupt. When this happens, the CPU simply switches modes and jumps to address 0x00000018
.
However, because there are usually more devices than the number of interrupt pins, there's usually an interrupt controller that goes between the CPU and the devices. You can think of this as a hub for connecting more interrupts to the CPU. The interrupt controller can be configured to assert FIQ for certain kinds of interrupts it receives.
The interrupt handler usually asks the interrupt controller which pin caused the interrupt, then calls the appropriate handler.
Here's a stripped down version without error checking of interrupt handler code that I used in a small project.
#include <types.h>
#include <irq.h>
static void (*irq_handlers[32])(void);
void __attribute__((interrupt)) handle_irq() {
int irq = irq_hw_get_and_ack();
if (irq_handlers[irq]) {
irq_handlers[irq]();
}
}
void setup_irq() {
irq_hw_init();
cpu_enable_irq();
}
void irq_request(int irq, void (*func)(void)) {
irq_handlers[irq] = func;
irq_hw_enable(irq);
}
void irq_unrequest(int irq) {
irq_hw_disable(irq);
irq_handlers[irq] = NULL;
}