头文件:
#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 对应的中断号。