Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1006582
  • 博文数量: 153
  • 博客积分: 4195
  • 博客等级: 上校
  • 技术积分: 2631
  • 用 户 组: 普通用户
  • 注册时间: 2009-06-22 11:32
文章存档

2012年(7)

2010年(35)

2009年(111)

分类: LINUX

2009-06-22 12:35:00

分析linux中断中常用的两个中断函数:

Disable_irq(int irq)

Enable_irq(int irq)

 

第一步:

●对于关中断

跟踪代码到arch/arm/kernel/irq.c

void disable_irq(unsigned int irq)

{

       struct irqdesc *desc = irq_desc + irq;

disable_irq_nosync(irq);

       if (desc->action)

              synchronize_irq(irq);

}

Irqdesc结构体中有一个irqchip的结构体,这个结构体中有maskunmask等函数,这些函数是在arch/arm/mach-sep4020/irq.c中注册进去的,继续跟踪disable_irq_nosync(irq);

 

void disable_irq_nosync(unsigned int irq)

{

       struct irqdesc *desc = irq_desc + irq;

       unsigned long flags;

 

       spin_lock_irqsave(&irq_controller_lock, flags); //获得自旋锁,并保存中断标志位

//仅仅是增加相应中断线的irqdesc结构中的disable_depth值,把自己从irq_pending链表中摘除,再等待现在正在执行的hangdler运行完毕。
irqdeschandle函数do_level_IRQ(),标记triggered,调用chip->ack()应答一下后,如果disable_depth不为0,说明该中断线已经disable,不做其他处理,但每次该中断线有中断触发,还是会应答一下,只是不做__do_irq()函数做的真正的工作,

       desc->disable_depth++;

       list_del_init(&desc->pend);

       spin_unlock_irqrestore(&irq_controller_lock, flags); //释放自旋锁,并返回之前保存的中断位

}

disable_irq 不但会禁止给定的中断,而且也会等待当前正在执行的中断处理程序完成。另一方面,disable_irq_nosync 是立即返回的。这样,使用后者将会更快,但是可能会让你的驱动程序处于竞态下——这是百度搜索的结果。

但我们可以看到其实disable_irq也是使用的disable_irq_nosync的函数体,这里纳闷!

 

●对于开中断

void enable_irq(unsigned int irq)

{

       struct irqdesc *desc = irq_desc + irq;

       unsigned long flags;

 

       spin_lock_irqsave(&irq_controller_lock, flags); //获得自旋锁,并保存中断标志位

       if (unlikely(!desc->disable_depth)) {

              printk("enable_irq(%u) unbalanced from %p\n", irq,

                     __builtin_return_address(0));

       } else if (!--desc->disable_depth) {

              desc->probing = 0;

              desc->chip->unmask(irq);//实现了开中断

//如果中断正在等待处理,尝试重新运行它;我们不能直接从这里运行,因为caller可能在一个中断保护的区域

              if (desc->pending && list_empty(&desc->pend)) {

                     desc->pending = 0;

                     if (!desc->chip->retrigger ||

                         desc->chip->retrigger(irq))

                            list_add(&desc->pend, &irq_pending);

              }

       }

       spin_unlock_irqrestore(&irq_controller_lock, flags); //释放自旋锁,并返回之前保存的中断位

}

 

第二步:

●在arch/arm/mach-sep4020/irq.c中对irq进行初始化,其中有部分重要代码如下:

void __init sep4020_init_irq(void)

 {

       ……

       for(i = 0; i < NR_IRQS; i++)

                {

                set_irq_handler(i, do_level_IRQ); //先初始化所有的中断的处理函数为一个简单的,低级的handler

                set_irq_chip(i, &sep4020_chip);//将我们所写的irqchip注册到Irqdesc结构体中的irqchipchip,就是这一步实现了arch/arm/mach-sep4020/irq.c中的函数到系统函数的注册

                set_irq_flags(i, IRQF_VALID | IRQF_PROBE);//如果设置为IRQF_VALID,则表示此中断可用,设置为IRQF_PROBE,则表示此中断可探测,如果设置为IRQF_NOAUTOEN则表示不能自动enable此中断

                }

}

 

通过这几个函数就能实现了中断的整个过程,分析完毕,呵呵。

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