第七章 中断和中断处理-----读书笔记(Linux kernel development)

一、注册中断处理程序

       中断处理程序是管理硬件的驱动程序的组成部分。每个设备都有相关的驱动程序,如果设备使用过中断,那么相应的驱动程序就注册一个中断处理程序。

       驱动程序可以通过request_irq()函数注册一个中断处理程序,并且激活给定的中断线。

       /* request_irq:分配一条给定的中断线 */

       int request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags, const char *name, void *dev)

       第一个参数irq表示要分配的中断号。

       第二个参数handler是一个指针,指向处理这个中断的实际中断处理程序。

      第三个参数flags可以是0,也可以是下列标志的位掩码:

     1、IRQF_DISABLED-------该标志被设置后,意味着内核在处理中断处理程序本身期间,要禁止所有的其他中断。如果不设置,中断处理程序可以与除本身外其他任何中断同时运行。多数中断处理程序是不会设置该位,因为禁止所有中断是一种野蛮行为。

     2、IRQF_SAMPLE_RANDOM------此标志表明这个设备产生的中断对内核熵池有贡献。

     3、IRQF_TIMER-----该标志是特别为系统定时器的中断处理而准备的。

     4、IRQF_SHARED-----该标志表明可以在多个中断处理程序中共享中断线。在同一个给定线上注册的每个处理程序必须指定这个标志;否则,在每条线上只能有一个处理程序。

     第四个参数 name 是与中断相关的设备的ASCII文本表示,例如pc机上键盘中断对应的这个值是“keyboard”。

     第五个参数dev 用于共享中断线,当一个中断处理程序需要释放时,dev将提供唯一的标志信息,以便从共享中断线的诸多中断处理程序中删除指定的那一个。

     request_irq()成功执行会返回0,如果返回非0值,表示有错误发生,这种情况指定的中断处理程序不会被注册。

    一个中断例子:在一个驱动程序中请求一个中断线,并在通过request_irq()安装中断处理程序  

                             requset_irq():

                             if(request_irq(irqn, my_interrupt, IRQF_SHARED, "my_device", my_dev)){

                                     printk(KERN_ERR "my_device: cannot register IRQ %d\n", irqn);

                                     return -EIO;

                              }

          irqn时请求的中断线,my_interrupt是中断处理程序,IRQF_SHARED设置中断线可以共享,设备名“my_device”,将my_dev传递给dev参数。如果返回非0值表示请求失败,打印错误。返回0表示成功。

二、释放中断处理程序

       卸载驱动程序时,需要注销相应的中断处理程序,并释放中断线。

       void free_irq(unsigned int irq, void *dev)

       如果指定的中断线不是共享的,那么删除该中断处理程序的时候会禁用这条中断线,如果中断线共享,就只会删除dev对应的处理程序,而这条中断线本身只有在删除最后一个处理程序时才会禁用。对于共享的中断线,需要一个唯一的信息来区分其上面的多个处理程序,并让free_irq仅仅删除指定的处理程序。唯一的信息就是dev。

三、编写中断处理程序

      static  irqreturn_t  intr_handler(int irq, void *dev)

      第一个参数irq就是这个处理程序要响应的中断的中断号。

      第二个参数dev是一个通用指针,该值具有唯一确定性,可以用来区分共享同一中断处理程序的多个设备。

     中断处理程序的返回值是一个特殊类型:irqreturn_t。中断处理程序可能返回两个特殊的值:IRQ_NONE和IRQ_HANDLED。当中断处理程序检测到一个中断,但该中断对应的设备并不是在注册处理函数期间指定的产生源,返回IRQ_NONE;当中断处理程序被正确调用,且确实是它所对应的设备产生了中断时,返回IRQ_HANDLED。

四、共享的中断处理程序

       共享的处理程序与非共享的处理程序的差异主要有以下三处:

       1、request_irq()的参数flags必须设置IRQF_SHARED标志

       2、对于每个注册的中断程序来说,dev参数必须唯一。不能给共享的处理程序传递NULL值。

       3、中断处理程序必须能够区分它的设备是否真的产生中断,这既需要硬件支持,也需要处理程序中相关的处理逻辑。

       所有共享中断线的驱动程序都必须满足以上要求,只要有任何一个设备没有按规则进行共享,那么中断线就无法共享了。指定IRQF_SHARED标志以调用request_irq()时,只有在以下两种情况下才可能成功:中断线当前未被注册,或者在该线上的所有已注册处理程序都指定了IRQF_SHARED。

五、中断上下文

      当执行一个中断处理程序时,内核处于中断上下文中。中断上下文具有严格的时间限制,因为它打断其他代码。中断上下文中的代码应当迅速,简洁,尽量不要使用循环去处理繁复的工作。

六、中断处理机制的实现

        

七、中断控制

       Linux内核提供了一组接口用于操作机器上的中断状态,这些接口为我们提供了能够禁止当前处理器的中断系统,或屏蔽整个机器的一条中断线的能力。通过禁止中断,可以确保某个中断处理程序不会抢占当前的代码。内核代码一般都需要获取某种锁,防止其他处理对共享数据的并发访问,获取这些锁的同时也伴随着禁止本地中断。锁提供保护机制,防止来自其他处理器对共享数据的并发访问,而禁止中断提供保护机制,则是防止来自其他中断处理程序的并发访问。

八、禁止和激活中断

       用于禁止当前处理器上的本地中断,随后又激活它们的语句是:

       local_irq_disable();

       /* 禁止中断*/

     local_irq_enable();

      简单的禁止和激活存在潜在危险,在禁止前保存中断系统的状态,在准备激活中断时,恢复状态。

     unsigned long flags;

     local_irq_save(flags);

     /* ...........*/

    local_irq_restore(flags);

九、禁止指定中断线

      在某些情况下,只禁止整个系统中一条特定的中断线就够了。这就是所谓的屏蔽一条中断线。为此,linux提供了四个接口:

      void disable_irq(unsigned int irq);

     void  disable_irq_nosync(unsigned int irq);

     void enable_irq(unsigned int irq);

     void synchronize_irq(unsigned int irq);

    前两个函数禁止中断控制器上指定的中断线,即禁止给定中断向系统中所有处理器的传递。另外disable_irq() 只有当正在执行的所有处理程序完成后,才返回。函数disable_irq_nosync() 不会等待当前中断处理程序从执行完毕。 函数synchronize_irq()等待一个特定的中断处理程序的退出。 对disable_irq()或disable_irq_nosync()的每次调用,都需要相应调用一次enable_irq()。只有在对enable_irq()完成最后一次调用后,才真正重新激活了中断线。

 

 

 

 

 

 

 

 

 

        

 

 

 

 

 

 

 

      

posted @   爱看夕阳的乌龟  阅读(136)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示