博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
中断触发流程
阅读量:4104 次
发布时间:2019-05-25

本文共 4270 字,大约阅读时间需要 14 分钟。

在响应一个特定的中断的时候,内核会执行一个函数,该函数叫做中断处理程序(interrupt handler)或中断服务例程(interrupt service routine ,ISP).产生中断的每个设备都有一个相应的中断处理程序,中断处理程序通常不和特定的设备关联,而是和特定的中断关联的,也就是说,如果一个设备可以 产生多种不同的中断,那么该就可以对应多个中断处理程序,相应的,该设备的驱动程序也就要准备多个这样的函数。在Linux内核中处理中断是分为上半部 (top half),和下半部(bottom half)之分的。上半部只做有严格时限的工作,例如对接收到的中断进行应答或复位硬件,这些工作是在所有的中断被禁止的情况下完成的,能够被允许稍后完 成的工作会推迟到下半部去。

其实中断的整个过程分为2个部分:

1 注册

2 执行或者叫触发

如上图:首先中断触发,cpu响应,去执行IRQ中断总的服务子程序(就是所有的IRQ中断都经过这一步),去读两个寄存器,确定中断号,再根据中断号,在子程序链表中找到对应的中断服务子程序,结束了。为了达到这样的目的,把中断号与中断子程序联系起来。request_irq()做的就只是这个工作。而GPIO与中断号的联系是定死的,或者这两个中断号还不一样。后面讲吧。

先说说request_irq(),就是把中断例程添加到中断子程序链表中去。

request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags,                                                                                                const char *name, void *dev)                                                                                                                    {                                                                                                                                                                    return request_threaded_irq(irq, handler, NULL, flags, name, dev);     }include/linux/interrupt.h
kernel/kernel/irq/manage.cint request_threaded_irq(unsigned int irq, irq_handler_t handler,                         irq_handler_t thread_fn, unsigned long irqflags,                         const char *devname, void *dev_id){        struct irqaction *action;//每一个action结构体中存放着一个中断子程序的入口地址及相关信息        struct irq_desc *desc;//每一个desc结构体中存放着一个中断号的相关信息,一个中断号可以有多个子程序,以链表形式存在,以dev_id名字区别        int retval; //IRQF_DISABLED:快速中断标志,对应老版本中的SA_INTERRUPT标志,表明在处理本中断时屏蔽CPU所有中断(屏蔽其他中断线上的中断,本中断线上本来就是屏蔽的),//而在没设置此标志位的程序中,都是开中断处理的,可以进行中断嵌套。嵌套与中断线优先级有关,有中断控制器控制。

  //  IRQF_SAMPLE_RANDOM:用于随机数据产生;告诉内核,本中断源可以用作随机数生成器的熵池(这个不太理解)

  //  IRQF_SHARED:用于共享中断,设置此标志时,request_irq最后一个参数dev不能为NULL,对应老版本内核的SA_SHIRQ;表示共享中断线。

 

  //   IRQF_PROBE_SHARED:探测共享中断;

 

  //  IRQF_TIMER:专用于定时中断;

if ((irqflags & (IRQF_SHARED|IRQF_DISABLED)) ==                                        (IRQF_SHARED|IRQF_DISABLED)) {//共享中断不能做快速中断                pr_warning(                  "IRQ %d/%s: IRQF_DISABLED is not guaranteed on shared IRQs\n",                        irq, devname);        }#ifdef CONFIG_LOCKDEP    //若定义此宏,则禁止中断嵌套,所有中断都关中断运行。        /*         * Lockdep wants atomic interrupt handlers:         */        irqflags |= IRQF_DISABLED;#endif if ((irqflags & IRQF_SHARED) && !dev_id)//如果状态是共享,那么就必须要有dev_id,而且还不能与已经存在的重合,否则无法区别                return -EINVAL;        desc = irq_to_desc(irq);//根据中断号,找到对应的desc结构体,应该也包括创建新的desc结构体吧?        if (!desc)              //所有irq_desc在系统启动时,通过init_IRQ初始化。                return -EINVAL;        if (desc->status & IRQ_NOREQUEST) //若此中断禁止响应,则返回。                return -EINVAL;        if (!handler) {      //没有处理函数也不行                if (!thread_fn)                        return -EINVAL;                handler = irq_default_primary_handler;        }        action = kzalloc(sizeof(struct irqaction), GFP_KERNEL);//在内核空间分配一个action,用于存放一个中断子程序的信息        //中断的入口是irq_desc->handle_irq,这只是电平触发或者边沿触发的处理,但我们注册的中断处理程序都是irq_desc下的一个action。        if (!action)                return -ENOMEM;        action->handler = handler;    //我们定义的中断处理子程序        action->thread_fn = thread_fn;        action->flags = irqflags;  //中断的属性        action->name = devname;//与该中断相关联的名称,在/proc/interrupt中可看到。        action->dev_id = dev_id;//中断服务程序的参数,可以为NULL,但在注册共享中断时,此参数不能为NULL。        chip_bus_lock(irq, desc);        retval = __setup_irq(irq, desc, action);   //添加进action链表,上下还锁起来了。        chip_bus_sync_unlock(irq, desc);        if (retval)                kfree(action);#ifdef CONFIG_DEBUG_SHIRQ   //调试用的        if (irqflags & IRQF_SHARED) {                /*                 * It's a shared IRQ -- the driver ought to be prepared for it                 * to happen immediately, so let's make sure....                 * We disable the irq to make sure that a 'real' IRQ doesn't                 * run in parallel with our fake.                 */                unsigned long flags;                disable_irq(irq);                local_irq_save(flags);                handler(irq, dev_id);                local_irq_restore(flags);                enable_irq(irq);        }#endif        return retval;}EXPORT_SYMBOL(request_threaded_irq);

转载地址:http://skbsi.baihongyu.com/

你可能感兴趣的文章
C 语言 学习---获取文本框内容及字符串拼接
查看>>
C 语言学习 --设置文本框内容及进制转换
查看>>
C 语言 学习---判断文本框取得的数是否是整数
查看>>
C 语言 学习---ComboBox相关、简单计算器
查看>>
C 语言 学习---ComboBox相关、简易“假”管理系统
查看>>
C 语言 学习---回调、时间定时更新程序
查看>>
C 语言 学习---复选框及列表框的使用
查看>>
第四章 - 程序计数器
查看>>
第七章 - 本地方法栈
查看>>
第十一章 - 直接内存
查看>>
JDBC核心技术 - 上篇
查看>>
JDBC核心技术 - 下篇
查看>>
一篇搞懂Java反射机制
查看>>
一篇彻底搞懂Java注解与枚举类
查看>>
【2021-MOOC-浙江大学-陈越、何钦铭-数据结构】树
查看>>
【2021-MOOC-浙江大学-陈越、何钦铭-数据结构】树-中
查看>>
【2021-MOOC-浙江大学-陈越、何钦铭-数据结构】线性结构
查看>>
【2021-MOOC-浙江大学-陈越、何钦铭-数据结构】图
查看>>
程序员,应该掌握的英语词汇
查看>>
程序员的十大烦恼
查看>>