【Linux中断】Linux系统中断机制简述

Linux中断

Linux中断处理过程

1.使能中断,初始化相应的寄存器
2.注册中断服务函数,也就是向irqTable数组的指定标号处写入中断服务函数
3.中断发生以后进入IRQ中断服务函数,IRQ的中断服务函数在irqTable里面查找具体的中断处理函数,找到以后执行相应的中断处理函数

Linux中断处理API函数

request_irq(注册中断处理程序)

request_irq函数用于申请中断,但是可能会导致睡眠,因此不能在中断上下文或者其他禁止睡眠的代码段中使用request_irq函数。request_irq函数会使能中断,所以不需要我们手动去使能中断。

函数原型:

int request_irq(unsigned int irq,
                irq_handler_t handler,
                unsigned long flags,
                const char *name,
                void *dev);

参数说明:

irq:要申请中断的中断号
handler:中断处理函数,当中断发生以后就会执行此中断处理函数
flags:中断标志,可以在include/linux/interrupt.h里面查看所有的中断标志
name:中断名字,设置以后可以在/proc/interrupts文件中可以看到对应的中断名字
dev:如果flags设置为IRQF_SHARED的话,dev用来区分不同的中断,一般情况下将dev设置为设备结构体,dev会传递给中断处理函数irq_handler_t的第二个参数

第二个参数handler是一个指针,指向处理这个中断的实际中断处理程序。只要操作系统一接收到中断,该函数就被调用

typedef irqreturn_t (*irq_handler_t)(int,void *);     // handler函数的原型,接受两个参数,返回值为irqreturn_t

常用中断标志:

标志 描述
IRQF_SHARED 多个设备共享一个中断线,共享的所有中断都必须指定此标志。如果使用共享中断的话,request_irq函数的dev参数就是唯一区分他们的标志。
IRQF_ONESHOT 单次中断,中断执行一次就结束
IRQF_TRIGGER_NONE 无触发
IRQF_TRIGGER_RASING 上升沿触发
IRQF_TRIGGER_FALLING 下降沿触发
IRQF_TRIGGER_HIGH 高电平触发
IRQF_TRIGGER_LOW 低电平触发

代码实例:

// irq:请求的中断线
// my_interrupt:中断处理程序
// IRQF_SHARED:中断线可以共享
// my_device:中断名字
// my_dev:传递my_dev变量给dev形参。如果请求失败将直接返回
if(request_irq(irqn,my_interrupt,IRQF_SHARED,"my_device",my_dev))
{
    return -EIO;
}

free_irq(释放中断)

释放相应的中断,注释掉相应的中断处理程序,并释放中断线。如果中断不是共享的,那么free_irq会删除中断处理函数并且禁止中断.

函数原型:

void free_irq(unsigned int irq,void *dev);

参数说明:

irq:要释放的中断。
dev:如果flags设置为IRQF_SHARED的话,dev用来区分不同的中断。共享中断只有在释放最后中断处理函数的时候才会被禁止掉

中断处理函数

使用request_irq函数申请中断的时候需要设置中断处理函数

函数原型:

irqreturn (*irq_handler_t)(int , void *);

参数说明:

第一参数:中断处理函数相对应的中断号
第二参数:指向void的指针,也就是一个通用指针,需要与request_irq函数的dev参数保持一致,用于区分共享中断的不同设备

返回值:

enum irqreturn
{
    IRQ_NONE   = (0 << 0),
    IRQ_HANDLED = (1 << 0),
    IRQ_WAKE_THREAD = (1 << 1),
};

中断使能与禁止函数

常用中断使用和禁止函数

void enable_irq(unsigned int irq);
void disable_irq(unsigned int irq);

enable_irq和disable_irq用于使能和禁止指定的中断,irq就是要禁止的中断号。disable_irq函数要等到当前正在执行的中断处理函数执行完才返回,因此需要保证不会产生新的中断,并且确保所有已经开始执行的中断处理程序已经全部退出。在这种情况下,可以使用另外一个中断禁止函数:

void disable_irq_nosync(unsigned int irq);

disable_irq_nosync函数调用以后立即返回,不会等待当前中断处理程序执行完毕。上面三个函数都是使能或者禁止某一个中断,如果需要关闭全局中断需要使用一下函数:

local_irq_enbale();                 // 使能当前处理器中断系统
local_irq_disbale();                // 禁止当前处理器中断系统
local_irq_save(flags);                                  //   用于禁止中断,并且将中断状态保存到flags中
local_irq_restore(flags);                             //    用于恢复中断,将中断恢复到flags状态。

中断处理上下部

为了实现中断处理函数的快进快出,对于一些对时间敏感、执行速度快的操作可以放到中断处理函数中,也就是上半部,剩下执行时间久的工作都可以放到下半部执行。

上半部

上半部就是中断处理函数,一些处理过程比较快,不会占用较长时间可以放到上半部执行。

下半部

如果中断处理过程比较耗时,那么就将这些比较耗时的代码提出来,交给下半部去执行,这样中断处理函数就可以快进快出。

上半部与下半部使用场景:

1、如果要处理的内容不希望被其他中断打断,可以放在上半部

2、如果要处理的任务对时间敏感,可以放在上半部

3、如果要处理的任务与硬件有关,可以放在上半部

4、除了以上三点外的其他任务,优先考虑放在下半部

上半部的处理比较简单,直接为中断号编写中断处理函数即可,关键是下半部要如何处理,下办部处理机制有3种,软中断,tasklet和workqueue。

posted @ 2023-06-03 17:39  Emma1111  阅读(417)  评论(0)    收藏  举报