Chinaunix首页 | 论坛 | 博客
  • 博客访问: 149032
  • 博文数量: 17
  • 博客积分: 359
  • 博客等级: 一等列兵
  • 技术积分: 382
  • 用 户 组: 普通用户
  • 注册时间: 2012-04-08 19:51
文章分类

全部博文(17)

文章存档

2012年(17)

我的朋友

分类: LINUX

2012-04-17 21:51:30

中断处理模型结构

中断处理模型如下图所示,

其中NR_IRQS表示最大的中断号,在include/asm/arch/irq.h中定义。

irq_desc[]是一个指向irq_desc_t结构的数组, irq_desc_t结构是各个设备中断服务例程的描述符。Irq_desc_t结构体中的成员action指向该中断号对应的irqaction结构体链表。Irqaction结构体定义在include/linux/interrupt.h中,如下:

truct irqaction {
irq_handler_t handler; //中断处理函数,注册时提供
unsigned long flags; //中断标志,注册时提供
cpumask_t mask; //中断掩码
const char *name; //中断名称
void *dev_id; //设备id,本文后面部分介绍中断共享时会详细说明这个参数的作用
struct irqaction *next; //如果有中断共享,则继续执行,
int irq; //中断号,注册时提供
struct proc_dir_entry *dir; //指向IRQn相关的/proc/irq/n目录的描述符

};

2.6.32内核的irqaction为:

  1. struct irqaction {
  2.     irq_handler_t handler;
  3.     unsigned long flags;
  4.     const char *name;
  5.     void *dev_id;
  6.     struct irqaction *next;
  7.     int irq;
  8.     struct proc_dir_entry *dir;
  9.     irq_handler_t thread_fn;
  10.     struct task_struct *thread;
  11.     unsigned long thread_flags;
  12. };

在注册中断号为irq的中断服务程序时,系统会根据注册参数封装相应的irqaction结构体。并把中断号为irq的irqaction结构体写入irq_desc [irq]->action。这样就把设备的中断请求号与该设备的中断服务例程irqaction联系在一起了。样当CPU接收到中断请求后,就可以根据中断号通过irq_desc []找到该设备的中断服务程序。

以下为中断请求函数:

  1. int request_threaded_irq(unsigned int irq, irq_handler_t handler,
  2.              irq_handler_t thread_fn, unsigned long irqflags,
  3.              const char *devname, void *dev_id)
  4. {
  5.     struct irqaction *action;
  6.     struct irq_desc *desc;
  7.     int retval;

  8.     /*
  9.      * handle_IRQ_event() always ignores IRQF_DISABLED except for
  10.      * the _first_ irqaction (sigh). That can cause oopsing, but
  11.      * the behavior is classified as "will not fix" so we need to
  12.      * start nudging drivers away from using that idiom.
  13.      */
  14.     if ((irqflags & (IRQF_SHARED|IRQF_DISABLED)) ==
  15.                     (IRQF_SHARED|IRQF_DISABLED)) {
  16.         pr_warning(
  17.          "IRQ %d/%s: IRQF_DISABLED is not guaranteed on shared IRQs\n",
  18.             irq, devname);
  19.     }

  20. #ifdef CONFIG_LOCKDEP
  21.     /*
  22.      * Lockdep wants atomic interrupt handlers:
  23.      */
  24.     irqflags |= IRQF_DISABLED;
  25. #endif
  26.     /*
  27.      * Sanity-check: shared interrupts must pass in a real dev-ID,
  28.      * otherwise we'll have trouble later trying to figure out
  29.      * which interrupt is which (messes up the interrupt freeing
  30.      * logic etc).
  31.      */
  32.     if ((irqflags & IRQF_SHARED) && !dev_id)
  33.         return -EINVAL;

  34.     desc = irq_to_desc(irq); //把申请中断号加下中断链表
  35.     if (!desc)
  36.         return -EINVAL;

  37.     if (desc->status & IRQ_NOREQUEST)
  38.         return -EINVAL;

  39.     if (!handler) {
  40.         if (!thread_fn)
  41.             return -EINVAL;
  42.         handler = irq_default_primary_handler;
  43.     }

  44.     action = kzalloc(sizeof(struct irqaction), GFP_KERNEL);
  45.     if (!action)
  46.         return -ENOMEM;

  47.     action->handler = handler;  //此处开始根据注册参数封装相应的irqaction结构体
  48.     action->thread_fn = thread_fn;
  49.     action->flags = irqflags;
  50.     action->name = devname;
  51.     action->dev_id = dev_id;

  52.     chip_bus_lock(irq, desc);
  53.     retval = __setup_irq(irq, desc, action);
  54.     chip_bus_sync_unlock(irq, desc);

  55.     if (retval)
  56.         kfree(action);

  57. #ifdef CONFIG_DEBUG_SHIRQ
  58.     if (irqflags & IRQF_SHARED) {
  59.         /*
  60.          * It's a shared IRQ -- the driver ought to be prepared for it
  61.          * to happen immediately, so let's make sure....
  62.          * We disable the irq to make sure that a 'real' IRQ doesn't
  63.          * run in parallel with our fake.
  64.          */
  65.         unsigned long flags;

  66.         disable_irq(irq);
  67.         local_irq_save(flags);

  68.         handler(irq, dev_id);

  69.         local_irq_restore(flags);
  70.         enable_irq(irq);
  71.     }
  72. #endif
  73.     return retval;
  74. }

 * request_threaded_irq - allocate an interrupt line
 * @irq: Interrupt line to allocate
 * @handler: Function to be called when the IRQ occurs.
 *    Primary handler for threaded interrupts
 *    If NULL and thread_fn != NULL the default
 *    primary handler is installed
 * @thread_fn: Function called from the irq handler thread
 *      If NULL, no irq thread is created
 * @irqflags: Interrupt type flags
 * @devname: An ascii name for the claiming device
 * @dev_id: A cookie passed back to the handler function

 * Flags:
 *
 * IRQF_SHARED  Interrupt is shared
 * IRQF_DISABLED Disable local interrupts while processing
 * IRQF_SAMPLE_RANDOM The interrupt can be used for entropy
 * IRQF_TRIGGER_*  Specify active edge(s) or level

老版的request_irq 则调用 request_threaded_irq 如下:

  1. request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags,
  2.      const char *name, void *dev)
  3. {
  4.     return request_threaded_irq(irq, handler, NULL, flags, name, dev);
  5. }


 

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