Linux休眠后对中断的处理

同事在调试一个外设时发现:
a. 系统正常运行的情况下,使用这个设备会触发中断并调用它的中断处理函数。
b. 系统休眠之后,使用这个设备可以唤醒系统,但中断处理函数却没有被调用。

能够唤醒系统,说明中断一定是触发了。另发现小板上的键盘是可以的,休眠后按键可以
调到keyboard的中断处理函数。

跟踪这个问题,发现以下几点:

1. Linux在系统休眠时会调用dpm_suspend_noirq()-> suspend_device_irqs()。

  当系统休眠时,设备驱动需要禁止接收中断,suspend_device_irqs()屏蔽所有正在
  使用的中断(置IRQ_DISABLED标志),timer中断除外,因为Timer中段标志中设置了
  IRQF_NO_SUSPEND。如果禁止原因是suspend,则设置标志中的IRQ_SUSPENDED位。

  所以休眠之后,desc->status |= IRQ_DISABLED;
  
2. 中断触发类型有很多种,比如边沿触发和电平触发。在Linux里分别用
   handle_edge_irq() / handle_level_irq() 来处理它们。

  handle_edge_irq() : 
  * 如果中断有标志 IRQ_INPROGRESS 或 IRQ_DISABLED,说明此中断已经在处理或
    已经禁止。边沿触发锁存这次中断请求(置标记IRQ_PENDING),然后退出。
    由于中断请求已经锁存了,所以中断处理函数一定会被调用到。

  handle_level_irq() : 
  * 电平都会延续一段时间,在这段时间内电平中断会一直被触发。因此进入电平
    中断处理之前会先屏蔽该中断,到最后处理完毕之后再开启。
 

  * 电平中断不允许嵌套。正在处理的中断(IRQ_INPROGRESS)或被禁止的中断(IRQ_DISABLED)

    都不会被处理。

 
3. 平台处理函数在初始化的时候将所有GPIO都设置为电平触发 set_irq_handler(gpio, handle_level_irq),
    而键盘设备自己注册了handle_edge_irq。

   


posted @ 2012-09-17 18:32  sammei  阅读(1243)  评论(2编辑  收藏  举报