每个内核版本的代码都会有小部分不同,但是大体流程基本相同,只是调用关系和函数名称有些变化,下面来分析中断流程

1:在 arch/arm/kernel/ 下有个traps.c 文件中的 void __init early_trap_init(void *vectors_base) 函数 进行重定位中断向量列表

 

搜索 __vectors_start 可以知道 在arch/arm/kernel/entry_armv.S 中有宏定义 在这个文件中找到 vector_stub irq, IRQ_MODE, 4 以这个为例分析一下游程

vector_stub 是一个宏。

下面以 __irq_usr 用户模式的中断来找流程 搜索 __irq_usr

 

有个 irq_handler 这也是一个宏,继续搜索 还是在这个 entry_armv.S 中

 

搜索 arch_irq_handler_default  后里面会调用 asm_do_IRQ

 

到这里 前面都是用汇编写的,asm_do_IRQ 后面都用C函数实现的

  调用关系如下:

  early_trap_init  //内核用的是虚拟地址,这里只是把原来的中断向量复制到新的虚拟地址去 在内核配置文件有 0xffff0000 或 0x00000000都可以

    vector_stub irq  //以这用户模式中断为倒分析

      __irq_usr

        irq_handler

          arch_irq_handler_default

            asm_do_IRQ

下面来分析一下 asm_do_IRQ 了解中断是如何进行的 

2:先列出调用关系图

  asm_do_IRQ

    handle_IRQ

      generic_handle_irq

        struct irq_desc *desc = irq_to_desc(irq);

        generic_handle_irq_desc

          desc->handle_irq(irq, desc);  //desc是一个结构体  这个函数实现了 1:分辨是那一个中断 2:调用处理函数 3:清中断

=================================================分割线=====================================================

  desc->handle_irq(irq, desc); 分析它 handle_irq指向那个函数?搜索它 在 kernel/irq/chip.c 中找到 __irq_set_handler 这个函里调用了 desc->handle_irq = handle;

  再搜索 __irq_set_handler 这个函数,看谁调用 include/linux/ irq.h 中 irq_set_chained_handler 里调用了 再搜这个函数在那调用 得到 在 arch/arm/plat-s3c24xx 里

  s3c24xx_init_irq 这个函数调用 在这个函数里构造了 irq_desc 结构体 即初始化中断里的设置这个函数里调用  这只是例子,不同的中断初始化函数都可以调用这__irq_set_handler

  handle_edge_irq

    handle_irq_event(desc);    //这个函数就是处理中断

  层次就是这样的,我们还需要分析一下 irq_desc 结构体 这个结构体在 include/linux/irqdesc.h 中定义 下面只列出一部分

以上这些都是内核中断体系架构都做好的,这就是中断框架,我们如果要用我们自已的中断,我们怎么告诉内核呢?用 request_irq 注册,下面再来分析

irq_desc 是一个以中断号为下标的数组,里面有各种处理函数,链表等内容,我们要使用自已的中断驱动,就需要构造 填充 然后 注册到这个链表里。

 

request_irq

  request_threaded_irq

    action = kzalloc(sizeof(struct irqaction), GFP_KERNEL);    //分配一个irqaction结构体

    action->handler = handler;                //填充 把传入的参数填充到结构体
    action->thread_fn = thread_fn;
    action->flags = irqflags;
    action->name = devname;
    action->dev_id = dev_id;

    retval = __setup_irq(irq, desc, action);          //设置中断

       __irq_set_trigger

        ret = chip->irq_set_type(&desc->irq_data, flags);  //设置中断类型

    __enable_irq(desc, irq, false);              //使能中断

 

到此基本分析完毕,下一节 写一个基本中断的按键驱动程序

 

posted on 2019-10-22 11:05  荧火虫  阅读(380)  评论(0编辑  收藏  举报