Linux Interrupt API
===================
Russell King <>
The Linux Interrupt API provides a flexible mechanism to handle and
control interrupts within the kernel. The design requirements for
this API are:
- must have as little overhead as possible for commodity hardware
- must be easy and obvious to use
- must allow complex multi-level interrupt implementations to exist
transparently to device drivers
- must be compatible with the existing API
Essentially, this means that implementation of the existing API must
be simple.
------------------------------------------------------------------------------
The API.
========
struct irq {
/* architecture defined information */
/* must not be dereferenced by drivers */
};
/**
* irq_get - increment reference count on the IRQ descriptor
* @irq: interrupt descriptor
*
* IRQ descriptor reference counting is mandatory for
* implementations which provide dynamically allocated IRQ
* descriptors. statically allocated IRQ descriptor
* implementations may define these to be no-ops.
*/
struct irq *irq_get(struct irq *irq);
/**
* irq_put - decrement reference count on IRQ descriptor
* @irq: interrupt descriptor
*
* Decrement the reference counter in an IRQ descriptor.
* If the reference counter drops to zero, the IRQ descriptor
* will be freed.
*
* IRQ descriptor reference counting is mandatory for
* implementations which provide dynamically allocated IRQ
* descriptors. statically allocated IRQ descriptor
* implementations may define these to be no-ops.
*/
void irq_put(struct irq *irq);
/**
* irq_disable_nosync - disable an irq without waiting
* @irq: Interrupt descriptor to disable
*
* Disable the selected interrupt line. Disables and Enables are
* nested.
* Unlike irq_disable(), this function does not ensure existing
* instances of the IRQ handler have completed before returning.
*
* This function may be called from IRQ context.
*/
void irq_disable_nosync(struct irq *irq);
/**
* irq_disable - disable an irq and wait for completion
* @irq: Interrupt descriptor to disable
*
* Disable the selected interrupt line. Enables and Disables are
* nested.
* This function waits for any pending IRQ handlers for this interrupt
* to complete before returning. If you use this function while
* holding a resource the IRQ handler may need you will deadlock.
*
* This function may be called - with care - from IRQ context.
*/
void irq_disable(struct irq *irq);
/**
* irq_enable - enable the specified IRQ source.
* @irq: Interrupt descriptor to enable
*
* Undoes the effect of one call to irq_disable(). If this
* matches the last disable, processing of interrupts on this
* IRQ line is re-enabled.
*
* This function may be called from IRQ context.
*/
void irq_enable(struct irq *irq);
/**
* irq_request - request the use of an IRQ.
* @irq: irq descriptor
* @irqflags: interrupt type flags (SA_SHIRQ, SA_INTERRUPT)
* @devname: ascii name for the claiming device
* @dev_id: A cookie passed back to the handler function
*
* Request use of an interrupt line. We don't actually hook
* the interrupt immediately; any resources necessary are
* allocated. As such, this function may sleep.
*
* This function takes a reference on the IRQ descriptor.
*/
int irq_request(struct irq *irq, unsigned long irqflags, char *devname, void *dev_id);
/**
* irq_register - register an interrupt function to be called
* @irq: interrupt descriptor
* @fn: interrupt handler function
* @dev_id: A cookie passed back to the handler function
*
* Hook a previously registered interrupt line. If the
* interrupt has not been hooked by this instance, we fail.
*/
int irq_register(struct irq *irq,
irqreturn_t (*handler)(void *dev_id, struct pt_regs *regs),
void *dev_id);
/**
* irq_release - free an interrupt line
* @irq: interrupt descriptor
* @dev_id: device identity to free.
*
* Remove an interrupt handler. The handler is removed and if the
* interrupt line is no longer in use by any driver it is disabled.
* On a shared IRQ the caller must ensure the interrupt is disabled
* on the card it drives before calling this function. The function
* does not return until any executing interrupts for this IRQ
* have completed.
*
* We drop a reference on the IRQ descriptor, and therefore may be
* freed by irq_release.
*
* This function must not be called from interrupt context.
*/
void irq_release(struct irq *irq, void *devid);
/**
* irq_name - fill in and return the name of an IRQ
* @buf: buffer to fill with name
* @size: size of buffer
* @irq: irq descriptor
*
* Create an ASCII name of an IRQ and place it in buf.
* Returns the address of the buffer.
*/
const char *irq_name(char *buf, size_t size, struct irq *irq);
/**
* irqisa_to_desc - convert an ISA interrupt number to irq descriptor
* @irqnr: ISA interrupt number
*
* Return the IRQ descriptor for a given "ISA" interrupt number.
* Returns NULL if the "ISA" interrupt number is invalid.
*
* The returned IRQ has been "gotten" so irq_put will be required
* to balance once the IRQ is no longer required.
*/
struct irq *irqisa_to_desc(int irqnr);
/**
* irqdesc_to_isa - convert an irq descriptor to an ISA interrupt number
* @irq: Interrupt descriptor
*
* Returns the "ISA" interrupt number given an interrupt
* descriptor. Other interrupts return NO_IRQ.
*/
int irqdesc_to_isa(struct irq *irq);
/**
* irq_probe_on - begin an interrupt autodetect
*
* Commence probing for an interrupt. The interrupts are scanned
* and a cookie is returned.
*
* The IRQ probe semaphore is taken prior to the commencement of
* interrupt probing.
*/
void *irq_probe_on(void);
/**
* irq_probe_mask - scan a bitmap of interrupt lines
* @cookie: cookie returned from irq_probe_on
*
* Scan the ISA bus interrupt lines and return a bitmap of
* active interrupts. The interrupt probe logic state is then
* returned to its previous value.
*
* The IRQ probe semaphore is released and the cookie destroyed;
* irq_probe_off must not be called.
*/
unsigned int irq_probe_mask(void *cookie);
/**
* irq_probe_off - end an interrupt autodetect
* @cookie: cookie returned from irq_probe_on
*
* Scans the unused interrupt lines and returns the irq descriptor
* which appears to have triggered the interrupt. If no interrupt
* was found then NULL is returned.
*
* The IRQ probe semaphore is released and the cookie destroyed;
* irq_probe_off must not be called.
*/
struct irq *irq_probe_off(void *cookie);
------------------------------------------------------------------------------
Example backwards-compatible IRQ code.
======================================
The following example code shows the expected back-compat code required
for the x86 architecture. Since x86 uses a fixed table of interrupts,
this is relatively straight forward and simple.
static inline void disable_irq_nosync(int inr)
{
irq_disable_nosync(irq_desc + inr);
}
static inline void disable_irq(int inr)
{
irq_disable(irq_desc + inr);
}
static inline void enable_irq(int inr)
{
irq_enable(irq_desc + inr);
}
static inline int request_irq(int inr,
irqreturn_t (*handler)(int, void *, struct pt_regs *),
unsigned long irqflags,
const char * devname,
void *dev_id)
{
struct irq *irq = irq_desc + inr;
int ret;
ret = irq_request(irq, irqflags, devname, dev_id);
if (ret == 0) {
/*
* irq_register_legacy is only implemented for
* implementations providing this compatible
* interface.
*/
ret = irq_register_legacy(irq, handler, dev_id);
if (ret)
irq_release(irq, dev_id);
}
return ret;
}
static inline void free_irq(int inr, void *dev_id)
{
irq_release(irq_desc + inr, dev_id);
}
static inline unsigned long probe_irq_on(void)
{
return (unsigned long)irq_probe_on();
}
static inline unsigned int probe_irq_mask(unsigned long mask)
{
return irq_probe_mask((void *)mask);
}
static inline unsigned int probe_irq_off(unsigned long mask)
{
struct irq *irq = irq_probe_off((void *)mask);
return irq ? irq - irq_desc : 0;
}