[驱动程序] 中断的实现(中断上半部)

头文件:

#include <mach/devices.h> //中断号
#include <linux/interrupt.h> //常用的函数接口

1.申请注册中断

1.1 request_irq

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

irq:中断号,每个中断源有一个唯一的中断号。
irq_handler_t handler:中断服务程序,中断响应的时候,执行的函数。
flags:中断的标志,外部中断:触发方式。
name :自定义中断的名称,如果申请成功,则在/proc/interrupts文件能够看到很多的中断信息。
dev: 向中断服务程序发送的参数。
返回值:成功,返回0;失败,返回负数的错误码。

常见的中断标志:
在这里插入图片描述

1.2 request_threaded_irq

使用中断线程化。为什么需要将中断下半部处理线程化,原因如下:
①中断具有最高优先级,有中断发生时,会抢占进程,导致实时任务不能及时处理。
②中断上下文总是可以抢占进程上下文,这样不利于高优先级进展。
③将中断下半部当成内核线程,和其他线程在同一舞台上竞争CPU。实时进程优先级高于中断线程,使得搞优先级的进程具有更好的实时性。

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

irq:要注册的中断处理函数对应的软件中断号。
handler:注册的中断处理函数,中断发生时优先执行该函数,为NULL时,执行系统默认的函数。
thread_fn:中断线程化处理函数,该值不为NULL时,会创建kernel thread
flags:中断的标志,外部中断:触发方式。
name :自定义中断的名称,如果申请成功,则在/proc/interrupts文件能够看到很多的中断信息。
dev: 向中断服务程序发送的参数。
返回值:成功,返回0;失败,返回负数的错误码。
在这里插入图片描述
如果使用request_threaded_irq,大都是使用第三种组合,irq_default_primary_harder返回IRQ_WAKE_THREAD,将工作交给thread_fn进行处理。
第二种组合相当于request_irq。
第四种组合不被允许,因为中断得不到处理。
第一种组合比较复杂,在handler中根据实际情况返回IRQ_WAKE_THREAD(唤醒内核中断线程)或者IRQ_HANDLED(中断已经处理完毕,不需要唤醒中断内核线程)。

1.3 devm_request_threaded_irq

支持资源管理,函数参数定义同request_threaded_irq。

2.中断服务程序

中断服务程序是一个原子过程,这个过程是一个连续的过程,该过程不能产生阻塞,不能被打断。
中断服务程序的执行过程就是一个原子过程,中断服务程序执行的过程中,使用的就是原子上下文。
上下文—>程序执行过程中,使用的环境:代码、stack、heap。

irqreturn_t (*irq_handler_t)(int irq, void *dev);

参数说明:
int irq ----> 中断号
void *dev —>申请中断的时候,传递的参数
返回值:

/**
* enum irqreturn
* @IRQ_NONE interrupt was not from this device
* @IRQ_HANDLED interrupt was handled by this device
* ......
*/
enum irqreturn {
    //中断处理程序检测到一个中断,但该中断对应的设备并不是在注册处理函数期间指定的产生源时,返回这个值
    IRQ_NONE = (0 << 0),

     //中断处理程序被正确调用且确实是它对应的设备产生了中断,返回这个值
     IRQ_HANDLED = (1 << 0), ---->中断处理结束,正常返回
     
     IRQ_WAKE_THREAD = (1 << 1), ----> 唤醒内核线程                         
 };

3.释放中断

void free_irq(int irq, void *dev);

参数说明:
irq,中断号。
void *dev,申请中断的时候,传递的参数。

4.打开和关闭中断

4.1 enable_irq

void enable_irq(unsigned int irq)

参数说明: irq,中断号

4.2 disable_irq

关闭中断并等待中断处理完后返回

void disable_irq(unsigned int irq)

参数说明: irq,中断号
注:
在非中断处理函数中使用,会阻塞。
不能在中断服务函数中执行,会导致系统将会出现死锁状态,最后死机,然后重启。原因由于在disable_irq中会调用synchronize_irq函数等待中断返回, 所以在中断处理程序中不能使用disable_irq, 否则会导致cpu被synchronize_irq独占而发生系统崩溃。

4.3 disable_irq_nosync

关闭中断并立即返回

void disable_irq_nosync(unsigned int irq)

参数说明:irq,中断号
注:
可在中断处理函数中使用,不会阻塞。
常见用法:中断服务函数调用disable_irq_nosync关闭中断,中断下半部调用enable_irq打开中断

4.4 其他

local_irq_disable()、local_irq_enable() 关闭当前处理器的整个中断系统。
local_irq_save(flags)、local_irq_restore(flags) 除了能够屏蔽中断外还能保存目前CPU的中断位信息。
local_bh_disable()、local_bh_enable(),屏蔽和使能下半部中断。

5.获取中断号

5.1 irq_of_parse_and_map

irq_of_parse_and_map 函数从 interupts 属性中提取到对应的设备号,函数原型如下:

unsigned int irq_of_parse_and_map(struct device_node *dev, int index)

函数参数和返回值含义如下:
dev :设备节点。
index:索引号,interrupts 属性可能包含多条中断信息,通过 index 指定要获取的信息。
返回值:中断号。

5.2 gpio_to_irq

gpio_to_irq 函数来获取 gpio 对应的中断号,函数原型如下:
int gpio_to_irq(unsigned int gpio)
函数参数和返回值含义如下:
gpio :要获取的 GPIO 编号。
返回值:GPIO 对应的中断号。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值