Chinaunix首页 | 论坛 | 博客
  • 博客访问: 326335
  • 博文数量: 81
  • 博客积分: 4016
  • 博客等级: 上校
  • 技术积分: 800
  • 用 户 组: 普通用户
  • 注册时间: 2006-03-17 18:38
文章分类

全部博文(81)

文章存档

2016年(5)

2015年(2)

2010年(1)

2008年(1)

2007年(4)

2006年(68)

我的朋友

分类: LINUX

2006-04-19 22:54:10

   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 */
};
 
#define NO_IRQ 
 
/**
 * 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;
}
 

 
阅读(1574) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~