Linux中断

        1,中断号,在 Linux 内核中使用一个 int 变量表示中断号,
2,irq_request()

在 Linux 内核中要想使用某个中断是需要申请的, request_irq 函数用于申请中断, 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 里面查看所有的中断标志,这里我们介绍几个常用的中断标志,如表 51.1.1.1 所示:

****表 51.1.1.1 中的这些标志可以通过“|”来实现多种组合。

name:中断名字,设置以后可以在/proc/interrupts 文件中看到对应的中断名字。

dev: 如果将 flags 设置为 IRQF_SHARED 的话, dev 用来区分不同的中断,一般情况下将dev 设置为设备结构体, dev 会传递给中断处理函数 irq_handler_t 的第二个参数。

返回值: 0 中断申请成功,其他负值 中断申请失败,如果返回-EBUSY 的话表示中断已经被申请了

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

表 51.1.1.1 常用的中断标志

3.free_irq()

使用中断的时候需要通过 request_irq 函数申请,使用完成以后就要通过 free_irq 函数释放掉相应的中断。如果中断不是共享的,那么 free_irq 会删除中断处理函数并且禁止中断。 free_irq函数原型如下所示:

void free_irq(unsigned int irq,

void *dev)

函数参数和返回值含义如下:

irq: 要释放的中断。

dev:如果中断设置为共享(IRQF_SHARED)的话,此参数用来区分具体的中断。共享中断只有在释放最后中断处理函数的时候才会被禁止掉。

返回值:无

4,中断处理函数

使用 request_irq 函数申请中断的时候需要设置中断处理函数,中断处理函数格式如下所示: irqreturn_t (*irq_handler_t) (int, void *)

第一个参数是要中断处理函数要相应的中断号。第二个参数是一个指向 void 的指针,也就是个通用指针,需要与 request_irq 函数的 dev 参数保持一致。

用于区分共享中断的不同设备, dev 也可以指向设备数据结构。中断处理函数的返回值为 irqreturn_t 类型, irqreturn_t 类型定义如下所示:

示例代码 51.1.1.1 irqreturn_t 结构

10 enum irqreturn {

11         IRQ_NONE = (0 << 0),

12         IRQ_HANDLED = (1 << 0),

13         IRQ_WAKE_THREAD = (1 << 1),

14 };

 typedef enum irqreturn irqreturn_t;

可以看出 irqreturn_t 是个枚举类型,一共有三种返回值。一般中断服务函数返回值使用如下形式:

return IRQ_RETVAL(IRQ_HANDLED)

5、中断使能与禁止函数

常用的中断使用和禁止函数如下所示:
1,void enable_irq(unsigned int irq)

2,void disable_irq(unsigned int irq)

enable_irq 和 disable_irq 用于使能和禁止指定的中断, irq 就是要禁止的中断号。 disable_irq

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

3,void disable_irq_nosync(unsigned int irq)

disable_irq_nosync 函数调用以后立即返回,不会等待当前中断处理程序执行完毕。

上面三个函数都是使能或者禁止某一个中断,有时候我们需要关闭当前处理器的整个中断系统,也就是在学习 STM32 的时候常说的关闭全局中断,这个时候可以使用如下两个函数:

4,local_irq_enable() local_irq_disable()

5,local_irq_enable 用于使能当前处理器中断系统, local_irq_disable 用于禁止当前处理器中断系统。

6,local_irq_save 函数用于禁止中断,并且将中断状态保存在 flags 中。

7,local_irq_restore 用于恢复中断,将中断到 flags 状态

/*重点*/

上半部与下半部

时间简短的中断放在上半部,长的利用某些方式放下半部

下半部执行机制:
1.用软中断,由于不被建议暂时不做

2.tasklet

tasklet 是利用软中断来实现的另外一种下半部机制,在软中断和 tasklet 之间,建议大家使用 tasklet。 Linux 内核使用 tasklet_struct 结构体来表示 tasklet:

sklet_struct 结构体来表示 tasklet:

示例代码 51.1.2.5 tasklet_struct 结构体

(struct tasklet_struct的结构体如下)

484 struct tasklet_struct

485 {

486         struct tasklet_struct *next; /* 下一个 tasklet */

487         unsigned long state; /* tasklet 状态 */

488         atomic_t count; /* 计数器,记录对 tasklet 的引用数 */

489         void (*func)(unsigned long); /* tasklet 执行的函数 */

490         unsigned long data; /* 函数 func 的参数 */

491 };

第 489 行的 func 函数就是 tasklet 要执行的处理函数,用户定义函数内容,相当于中断处理函数。****(重点)如果要使用 tasklet,必须先定义一个 tasklet,然后使用 tasklet_init 函数初始化 tasklet, taskled_init 函数原型如下

void tasklet_init(struct tasklet_struct *t,

                        void (*func)(unsigned long),

                        unsigned long data);

 

函数参数和返回值含义如下: t:要初始化的 tasklet     。

func: tasklet 的处理函数。      data: 要传递给 func 函数的参数 。   

    返回值: 没有返回值。

另外的函数注册task_let

也 可 以 使 用 宏 DECLARE_TASKLET 来 一 次 性 完 成 tasklet 的 定 义 和 初 始 化 , DECLARE_TASKLET 定义在 include/linux/interrupt.h 文件中,定义如下:

DECLARE_TASKLET(name, func, data);

其中 name 为要定义的 tasklet 名字,这个名字就是一个 tasklet_struct 类型的时候变量, func就是 tasklet 的处理函数, data 是传递给 func 函数的参数。

在上半部,也就是中断处理函数中调用 tasklet_schedule 函数就能使 tasklet 在合适的时间运行, tasklet_schedule 函数原型如下:

void tasklet_schedule(struct tasklet_struct *t)函数参数和返回值含义如下:

t:要调度的 tasklet,也就是 DECLARE_TASKLET 宏里面的 name。返回值: 没有返回值

3.工作队列

工作队列是另外一种下半部执行方式,工作队列在进程上下文执行,工作队列将要推后的工作交给一个内核线程去执行,因为工作队列工作在进程上下文,因此工作队列允许睡眠或重新调度。因此如果你要推后的工作可以睡眠那么就可以选择工作队列,否则的话就只能选择软中断或 tasklet。


 

  • 15
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值