分析中断3大结构体irq_desc、irq_chip、irqaction

我们先来看看irq_desc中断描述结构体有什么内容:

struct irq_desc {
         irq_flow_handler_t       handle_irq;  //指向中断函数, 中断产生后,就会执行这个handle_irq
         struct irq_chip   *chip; //指向irq_chip结构体,用于底层的硬件访问,下面会介绍
         struct msi_desc             *msi_desc; 
         void                     *handler_data;  
         void                     *chip_data;
         struct irqaction     *action;      /* IRQ action list */   //action链表,用于中断处理函数
         unsigned int                  status;                  /* IRQ status */
         unsigned int                  depth;                  /* nested irq disables */
         unsigned int                  wake_depth;        /* nested wake enables */
         unsigned int                  irq_count;   /* For detecting broken IRQs */
         unsigned int                  irqs_unhandled;
         spinlock_t            lock;          
     ... ...
         const char            *name;              //产生中断的硬件名字
} ;

这 个结构体用来描述中断源,数组irq_descNR_IRQS中每一项都对应一个相应的中断源,他的每一项对应着中断向量 表中的一项,即该数组的第一项对应着中断向量表中的第32项(中断向量号为0x20),往下依次对应。中断向量表一共有256项。
部分成员解释:
status:或者是0,或者是从一个特定的集合中抽取的一个标志位(不太清楚)。这些标志位代表了IRQ的状态--是否被禁止,有关IRQ的设备当前是否正被自动检测等。
chip:是一个指向hw_interrupt_type(或者irq_chip)的指针。下面对此有介绍。
action:是一个指向由irqaction结构体组成的一个单向链表的头的指针。若一个IRQ只被一个中断源使用,那么该链表的长度就是1,当有多个设备共享一个中断源时,该链表就会由多个irqaction结构体组成,下面对此有介绍。
depth:irq_desc_t的当前用户的个数,主要用来保证事件正在处理的过程中IRQ不会被禁止。

期中得结构体指针chip,指向一个irq_chip结构体,用于访问底层硬件,irq_chip结构体类型如下:

struct irq_chip {
         const char   *name;
         unsigned int    (*startup)(unsigned int irq);       //启动中断 
         void            (*shutdown)(unsigned int irq);      //关闭中断
         void            (*enable)(unsigned int irq);         //使能中断
         void            (*disable)(unsigned int irq);        //禁止中断
         void            (*ack)(unsigned int irq);       //响应中断,就是清除当前中断使得可以再接收下个中断
         void            (*mask)(unsigned int irq);     //屏蔽中断源 
         void            (*mask_ack)(unsigned int irq);  //屏蔽和响应中断
         void            (*unmask)(unsigned int irq);   //开启中断源
         ... ...
     int              (*set_type)(unsigned int irq, unsigned int flow_type);  //将对应的引脚设置为中断类型的引脚
     ... ...
#ifdef CONFIG_IRQ_RELEASE_METHOD
         void            (*release)(unsigned int irq, void *dev_id);       //释放中断服务函数
#endif

};

struct irqaction *action,主要是用来存用户注册的中断处理函数,
一个中断可以有多个处理函数 ,当一个中断有多个处理函数,说明这个是共享中断.
所谓共享中断就是一个中断的来源有很多,这些来源共享同一个引脚。
所以在irq_desc结构体中的action成员是个链表,以action为表头,若是一个以上的链表就是共享中断

irqaction结构定义如下:

struct 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/

};

这个结构体包含了处理一种中断所需要的各种信息,它代表了内核接受到特定IRQ之后应该采取的操作。
主要成员:
handler—该指针所指向的函数就是在中断服务程序,当中断发生时内核便会调用这个指针指向的函数。
flags: 该标志位可以是0,也可以是:SA_INTERRUPT(表示此中断处理程序是一个快速中断处理程序,在2.6中默认情况下没有这个标 志)SA_SAMPLE_RANDOM(表示这个中断对内核池有贡献,我理解为就是在中断时产生一些随机数,这些随机数被用来作为加密密匙,因为中断是随 机发生的,如果某种中断是有频率的被产生,那么它就不要设置此标志位,还有就是那种设备容易被攻击也不应该设置此标志位)SA_SHIRQ(此标志位表示 允许多个中断服务程序共享一个中断号,如不设则一个程序对应一个中断线)。
mask:在x86上不会用到。
name:产生中断的硬件的名字.
dev_id:该标志位主要在共享中断号时使用,即你设置flags=SA_SHIRQ时,有多个中断服务程序共享一个中断号时,内核就需要知道在用完中断程序后该删除那个中断服务程序。不共享时此成员为null。
next:如果flags=SA_SHIRQ,那么这就是指向对列中下一个struct irqaction结构体的指针,否则为空。
irq:就是中断号

上面3个结构体的关系如下图所示:
在这里插入图片描述
中断过程中使用到的函数:
trap_init(): 初始化异常向量的虚拟基地址,一般为0XFFFF0000
s3c24xx_init_irq():初始化各个中断
set_irq_chip(irqno, &s3c_irq_eint0t4):设置irq_desc[irqno]->chip等于第二个参数
set_irq_handler(irqno, handle_edge_irq); 设置irq_desc[irqno]->handle_irq等于第二个参数
asm_do_IRQ():中断产生后,会进入这个函数,最终执行 desc->handle_irq(irq, desc);
handle_edge_irq(irq, desc):执行中断函数,主要是执行以下两步骤:
(1) desc->chip->ack(irq):相应中断,也就是清中断,使能再次接受中断
(2) handle_IRQ_event(irq, action):执行中断的服务函数,desc->action->handler

中断运行总结:

当产生一个中断异常
1.进入异常向量vector,比如中断异常: vector_irq + stubs_offset
2.比如中断异常之前是用户模式(正常工作),则进入 __irq_usr,然后最终进入asm_do_IRQ函数,
3.然后执行irq_desc [irq]->handle_irq(irq, irq_desc [irq]);
通过刚才的分析,外部中断0(irq_desc[16])的handle_irq成员等于handle_edge_irq函数,
所以就是执行handle_edge_irq(irq, irq_desc [irq]);
4.以外部中断0为例,在handle_edge_irq函数中主要执行两步:
->4.1 desc->chip->ack //使用chip成员中的ack函数来清中断
->4.2 执行action链表 irq_desc->action->handler

这4步都是系统给做好的(中断的框架),当我们想自己写个中断处理程序,去执行自己的代码,就需要写irq_desc->action->handler,然后通过request_irq()来向内核申请注册中断

  • 0
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值