美文网首页
[读书笔记]中断处理(第十章)

[读书笔记]中断处理(第十章)

作者: c枫_撸码的日子 | 来源:发表于2018-10-29 20:42 被阅读0次

    综述

    终于看到这一章了,中断在Android系统源码中太常见了,学好本章十分重要!

    中断

    1.中断的申请以及释放

    #include <linux/sched.h>
    int request_irq(unsigned int irq
                    irqreturn_t (*handler)(int,void*,struct pt_regs *)),
                    unsigned long flags,
                    const char *dev_name,
                    void *dev_id);
    参数:
    unsigned int irq:
    要申请的中断号
    
    irqreturn_t (*handler)(int,void*,struct pt_regs *))
    中断处理函数
    
    unsigned long flags
    与中断管理有关的掩码选项
    (1.SA_INTERRUPT 2.SA_SHIRQ 3.SA_SAMPLE_RANDOM).    
    const char *dev_name
    中断名称,在proc/interrupts中可以显示
    
    void *dev_id
    该指针用于共享的中断信号线。它是唯一的标识符,在中断信号线空闲的时候可以使用它。
    驱动程序也可以使用执行驱动自己的私有数据区,用来识别是哪个设备产生的中断。
    没有强制使用共享方式时,设置为NULL;
    void free_irq(unsigned int irq,void *dev_id);
    

    ps:中断处理函数不能向用户空间发送或者接收数据,因为它不是在任何进程的上下文中执行的,不能发生休眠的操作,如调用wait_event、使用不带GFP_ATOMIC分配内存的操作,或者锁住一个信号量。不能调用schdule函数。

    中断处理函数的典型任务:如果中断来了,就唤醒相关休眠的进程。
    启用和禁用中断
    有时驱动程序必须在一个较短的时间内阻塞中断产生,例如必须在拥有自旋锁的时候阻塞中断,以避免系统死锁!
    1.禁用单个中断

    #include <asm/irq.h>
    void disable_irq(int irq);
    void disable_irq_nosync(int irq);
    void enable_irq(int irq);
    

    2.禁用和打开所有中断

    void local_irq_save(unsigned long flags);
    void local_irq_disable(void);
    

    local_irq_save把当前中断状态保存在flags中,然后禁用当前处理器上的中断。
    local_irq_disable不保存中断状态而直接关闭中断发送,只有我们知道中断没有在其他地方禁用时,才能使用这个版本。

    void local_irq_restore(unsigned long flags);
    void local_irq_enable(void);
    

    中断的顶半部和底半部

    中断处理的一个主要问题就是如何在中断处理函数中完成耗时任务。
    响应一次设备中断需要完成一定数量的工作,但是中断处理函数需要尽快结束,不能阻塞时间过长。
    因此,解决方案就是把中断处理函数分成两部分来解决,分别为顶半部和底半部。
    “顶半部”是实际相应中断的例程,也就是request_irq注册的中断例程。
    即-接收和响应中断请求。
    “底半部”是一个被顶半部调用,并在稍后更安全的时间里执行的函数。
    即-处理中断的业务逻辑

    这样分工允许底半部工作期间,顶半部可以继续接受和响应新的中断!

    2种实现底半部处理的方式
    1.tasklet通常是底半部处理的优选机制,因为这种方式非常快,但是所有的tasklet的代码必须都是原子的。

    1.声明
    DECLARE_TASKLET(name,function,data);
    name:tasklet的名称
    function:执行tasklet时调用的函数
    data:传递给tasklet函数的unsigned long 类型的值
    2.调用
    tasklet_schedule();
    

    2.使用工作队列实现,可以具有更高的延迟和允许休眠。

    1.声明并且初始化自己的工作队列
    static struct work_struct short_wq;
    INIT_WORK(&short_wq,short_do_tasklet,NULL);
    2.调用
    schedule_work(&short_wq);
    

    共享中断

    1.和普通的中断一样,通过irq_request申请。需要注意

    1.请求中断时,必须指定flags为SA_SHIRQ.
    2.dev_id参数必须是唯一的。任何指向模块地址空间的指针都可以使用,但不能设置为NULL。
    3.不能使用enable_irq和disable_irq。
    

    相关文章

      网友评论

          本文标题:[读书笔记]中断处理(第十章)

          本文链接:https://www.haomeiwen.com/subject/oombtqtx.html