linux驱动之中断处理过程C程序部分

Posted 上善若水,止于至善

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了linux驱动之中断处理过程C程序部分相关的知识,希望对你有一定的参考价值。

      当发生中断之后,linux系统在汇编阶段经过一系列跳转,最终跳转到asm_do_irq()函数,开始C程序阶段的处理。在汇编阶段,程序已经计算出发生中断的中断号irq,这个关键参数最终传递给asm_do_irq()。linux驱动中断处理C程序部分,主要涉及linux中断系统数据结构的初始化和C程序的具体执行跳转。

一、中断处理数据结构

      linux内核将所有的中断统一编号,使用一个irq_desc[NR_IRQS]的结构体数组来描述这些中断:每个数组项对应着一个中断源(可能是一个中断,也可能是一组中断),记录了中断的入口处理函数(不是用户注册的处理函数)、中断标记,并提供了中断的底层硬件访问函数(中断清除、屏蔽、使能)。另外,通过这个结构体数组项成员action,能够找到用户注册的中断处理函数。结构体irq_desc的数据类型在include/linux/irq.h中定义,内容如下:

struct irq_desc {
    irq_flow_handler_t    handle_irq;   /* 当前中断的处理函数入口 */
    struct irq_chip        *chip;       /* 低层的硬件访问 */
    struct msi_desc        *msi_desc;
    void            *handler_data;
    void            *chip_data;
    struct irqaction    *action;        /* 用户提供的中断处理函数链表 */
    unsigned int        status;         /* IRQ状态 */

    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;            /* 中断名称 */
} ____cacheline_internodealigned_in_smp;

      irq_desc成员变量handle_irq是这个或这组中断的入口处理函数,成员变量chip结构体包含了这个中断的清除、屏蔽或者使能等底层函数,结构体类型irq_chip的定义也在include/linux/irq.h中,内容如下:

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);
    const char    *typename;
};

      irq_desc成员变量action记录了用户注册的中断处理函数、中断标志等等内容,其类型irqaction类型定义在include/linux/interrupt.h中,内容如下:

struct irqaction {
    irq_handler_t handler;       /* 用户注册的中断处理函数 */
    unsigned long flags;         /* 中断标志,是否共享中断,电平触发还是边沿触发等 */
    cpumask_t mask;              /* 用于SMP */
    const char *name;            /* 用户注册的中断名字,/proc/interrupts */
    void *dev_id;                /* 用户传递给handler的参数,还可以用来区分共享中断 */
    struct irqaction *next;      /* 指向下一个irqaciton结构体指针 */
    int irq;                     /* 中断号 */
    struct proc_dir_entry *dir;
};

      用户注册的每个中断处理函数对应一个irqaciton结构体,一个中断源可以有多个处理函数(共享终端),它们的irqaciton结构体可以构成一个单项链表,irq_desc[irqn].action则是表头。irq_desc[NR_IRQS]结构体数组的构成情况如下图所示:

 

以上是关于linux驱动之中断处理过程C程序部分的主要内容,如果未能解决你的问题,请参考以下文章

linux驱动编写之中断处理

Linux设备驱动基础02之中断处理

Linux设备驱动基础02之中断处理

Linux设备驱动基础02之中断处理

linux驱动之中断方式获取键值

(笔记)Linux内核学习之中断推后处理机制