前面所写到的系统调用号,设备号对于内核来说是一种非常宝贵的资源。
同样,硬件中断对于内核来说也是一种非常宝贵的资源!
在使用的时候也要去向内核去申请中断资源。
中断处理流程包括4个部分:
1.建立异常向量表
2.编写保存现场的代码
3.恢复之前保存的代码
4.编写硬件中断对应的服务程序
一般的ARM逻板程序都是自己实现这几个功能的。
但是在内核中断编程时,内核帮你写好了前三部,我们只要做剩下的那一部就好啦。也就是编写硬件中断对应的服务程序。
1.中断编程所设计的头文件:
#include
#include
2.那么怎么样去申请硬件中断资源和注册对应的硬件中断的服务程序呢?
int request_irq (unsigned int irq, irq_handler_t handler, unsigned long irqflags, const char *name, void *dev_id);
函数功能:
1.向内核申请中断资源。
2.注册这个硬件中断对应的服务程序,一旦这个中断被触发,内核就会调用这个中断对应的服务程序。
参数说明:
irq:待申请的中断号,在内核空间中,用中断号来表示硬件中断资源
IRQ_EINT(0)表示外部中断0,
IRQ_EINT(1)表示外部中断1,
...(这些宏都是在内核平台头文件中定义的,由芯片公司实现,中断号0~31内核保留)
handler:待注册的中断处理函数,一旦注册成功,中断发生时,内核就会调用此函数来处理中断。
irqflags:中断标志
IRQF_SHARED: 表示多个设备共享中断
IRQF_SAMPLE_RANDOM: 用于随机数种子的随机采样
IRQF_TRIGGER_RISING: 上升沿触变中断
IRQF_TRIGGER_FALLING: 下降沿触变中断
IRQF_TRIGGER_HIGH: 高电平触变中断
IRQF_TRIGGER_LOW: 低电平触变中断
IRQF_DISABLE:本中断在处理的时候,其他中断进行屏蔽!
以上宏能够进行位或运算,例如对于按键,如果指定它的硬件中断触发方式为上升沿和下降沿触发:
例:IRQF_TRIGGER_RISING|IRQF_TRIGGER_FALLING,这个宏最终是给中断控制器配置!
如果硬件中断是内部中断(外设涉及中断触发方式无法人为去配置),这个参数一般给0;
name:中断设备名称(用cat /proc/interrupts可以查看是否注册成功)
dev_id:可以通过dev_id来给中断处理函数传递参数,如果不传递那么指定为NULL。
返回值:成功返回0, 失败返回-1
-EINVAL:表示申请的中断号无效或者中断处理函数指针为空。
-EBUSY:表示中断号已经被占用并且不能共享。
3.硬件中断如果不再使用,一定要释放硬件中断资源和卸载对应的处理函数哦:
free_irq (int irq, void *dev_id);
函数功能:释放中断和卸载对应的处理函数
函数参数:
irq:表示中断和卸载对应的处理函数
dev_id:这个参数和注册时传递的参数必须保持一致!(否则内核会崩溃)
4.中断处理函数原型:
irqreturn_t (*irq_handler_t)(int irq, void *dev_id);
irq:中断号
dev_id:在注册中断处理函数时传递过来的参数
返回值:
IRQ_NONE:中断未做处理
IRQ_HANDLED:正常处理后应该返回的
5.放一个我们学过的实例:
-
#include <linux/init.h>
-
#include <linux/module.h>
-
#include <linux/irq.h>
-
#include <linux/interrupt.h>
-
-
//定义按键数据结构
-
struct btn_resource {
-
int irq; //中断号
-
char *name; //标签
-
};
-
-
//分配初始化8个按键硬件信息
-
static struct btn_resource btn_info[] = {
-
[0] = {
-
.irq = IRQ_EINT(0),
-
.name = "KEY_UP"
-
},
-
[1] = {
-
.irq = IRQ_EINT(1),
-
.name = "KEY_DOWN"
-
}
-
};
-
-
//中断处理函数
-
//运行在内核空间
-
static irqreturn_t button_isr(int irq, void *dev_id)
-
{
-
//1.获取中断号对应的硬件资源
-
struct btn_resource *pdata =
-
(struct btn_resource *)dev_id;
-
-
printk("%s: irq = %d, name = %s\n",
-
__func__, pdata->irq, pdata->name);
-
-
return IRQ_HANDLED; //正常处理中断
-
}
-
-
static int btn_init(void)
-
{
-
int i;
-
-
for (i = 0; i < ARRAY_SIZE(btn_info); i++) {
-
//1.申请外部中断0资源和注册对应的处理函数
-
//共用一个处理函数
-
request_irq(btn_info[i].irq,
-
button_isr,
-
IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING,
-
btn_info[i].name,
-
&btn_info[i]);
-
}
-
printk("request irq!\n");
-
return 0;
-
}
-
-
static void btn_exit(void)
-
{
-
int i;
-
for (i = 0; i < ARRAY_SIZE(btn_info); i++)
-
//2.释放中断资源和卸载处理函数
-
free_irq(btn_info[i].irq, &btn_info[i]);
-
}
-
module_init(btn_init);
-
module_exit(btn_exit);
-
MODULE_LICENSE("GPL");
6.Linux中断处理函数编程的要求:
(1)之前所说的中断有优先级,那个仅仅适用于中断控制器。
(2)Linux内核对硬件中断没有优先级
(3)不过Linux内核硬件中断的优先级高于软中断,而软中断的优先级又高于进程。(硬件中断 > 软中断 > 进程)
(4)因为硬件中断没有优先级,所以要求中断处理函数的执行速度一定要快!让中断及时的释放CPU资源,给别的中断或者进程使用,如果老是占着茅坑不拉屎,会影响别的中断,影响系统的执行速度。
(5)在处理中断函数的时候千万不能调用能够引起阻塞的函数,比如:copy_to_user,copy_from_user,kmalloc...
(6)中断不属于任何的进程,不参与进程的调度。(哥是自由主义者,想管我?没门)
(7)欲知后事如何,请看下回分析!
阅读(1251) | 评论(0) | 转发(0) |