registering an IRQ
/ I-R-Q, 'eye-ar-cue' /
A device often cannot tell you instantly when it is ready — a network packet arrives whenever it arrives, a key is pressed at an unpredictable moment. Rather than have the CPU constantly ask 'are you done yet?', the device raises an interrupt: a hardware signal that yanks the CPU away from whatever it was doing to run a special handler. Registering an IRQ is the driver telling the kernel 'when interrupt line N fires, call MY function.'
In Linux a driver calls request_irq(irq, handler, flags, name, dev_id). The irq is the interrupt number the device uses; handler is the function to run when it fires; dev_id is a cookie passed back so a shared handler can find its data. From then on, whenever the device signals, the kernel switches into interrupt context and calls your handler. Crucially, an interrupt handler runs with interrupts (often) disabled, cannot sleep, and must be fast — it should do the bare minimum (acknowledge the device, grab the data) and defer slower work to a bottom half (a softirq, tasklet, or workqueue) that runs later in a more relaxed context. This is the top-half/bottom-half split: the top half is the tiny urgent handler, the bottom half is the deferred remainder. The handler returns IRQ_HANDLED if the interrupt was its device's, or IRQ_NONE if not (which matters for shared lines).
This matters because interrupts are how devices get attention without wasting the CPU on polling, and getting the handler discipline right is essential to a responsive system. Two honest cautions: a slow or sleeping interrupt handler can freeze the machine, because it runs with higher priority than any process and may hold off other interrupts. And several devices can share one IRQ line, so a shared handler must check its own device's status register and return IRQ_NONE when the interrupt was not for it, or it will swallow another device's interrupt.
static irqreturn_t my_isr(int irq, void *dev_id) { if (!(read_status() & MY_IRQ_BIT)) // not my device? return IRQ_NONE; // (shared line) ack_device(); // do the minimum schedule_work(&bottom_half); // defer the rest return IRQ_HANDLED; } // request_irq(irq, my_isr, IRQF_SHARED, "mydev", dev);
A top-half handler: check it is really our interrupt, acknowledge it, defer slow work, return HANDLED or NONE.
An interrupt handler runs in interrupt context: it must not sleep, must be fast, and on a shared line must return IRQ_NONE when the interrupt was not its own — otherwise it steals another device's interrupt.