如何在驱动中使用中断Word文档格式.docx
《如何在驱动中使用中断Word文档格式.docx》由会员分享,可在线阅读,更多相关《如何在驱动中使用中断Word文档格式.docx(7页珍藏版)》请在冰豆网上搜索。
中断时系统的稀缺资源,一旦不再使用,最好将中断号释放。
释放中断通过free_irq()实现。
与request_irq()一样,free_ire()函数在<
中声明,其函数原型如下:
voidfree_irq(unsignedintirq,void*dev_id)
第一个参数是将要释放的irq中断号。
第二个参数标志设备。
如果中断是该设备独占的,这里设置为NULL;
如果是共享中断,需要设置为中断处理程序指针。
3.设置触发条件
中断需要设置触发条件,如上升沿中断或者下降沿中断等。
Linux提设置触发条件的接口函数为irq_set_irq_type(),在<
linux/irq.h>
定义,函数原型为:
externintirq_set_irq_type(unsignedintirq,unsignedinttype);
irq为中断号,type为终端类型。
在<
中定义了如下中断类型:
IRQ_TYPE_NONE
=0x00000000,
IRQ_TYPE_EDGE_RISING
=0x00000001,
IRQ_TYPE_EDGE_FALLING
=0x00000002,
IRQ_TYPE_EDGE_BOTH
=(IRQ_TYPE_EDGE_FALLING|IRQ_TYPE_EDGE_RISING),
IRQ_TYPE_LEVEL_HIGH
=0x00000004,
IRQ_TYPE_LEVEL_LOW
=0x00000008,
IRQ_TYPE_LEVEL_MASK
=(IRQ_TYPE_LEVEL_LOW|IRQ_TYPE_LEVEL_HIGH),
IRQ_TYPE_SENSE_MASK
=0x0000000f,
IRQ_TYPE_PROBE
=0x00000010,
通常情况下,一般采用边沿触发和电平触发类型,具体如何设置,还需与实际硬件匹配。
4.使能和禁止中断
如果没有在系统中使能中断,就算设置了触发条件,即使满足了触发条件也是不会产生中断的。
Linux下使能中断的函数为enable_irq(),在<
linux/interrupt.h>
中定义,函数原型如下:
externvoidenable_irq(unsignedintirq);
irq为需要使能的中断号。
5.禁止中断
如果一个中断使用完毕不再使用,可以将该中断禁止。
禁止中断的函数为disable_irq(),在<
externvoiddisable_irq(unsignedintirq);
irq为要禁止的中断号。
1.1.2中断处理程序编写
中断处理程序返回值irqreturn_t,接受两个参数:
中断号irq和dev_id,dev_id就是request_irq时传递给系统的参数dev:
typedefirqreturn_t(*irq_handler_t)(intirq,void*dev_id);
中断处理完毕,通常返回IRQ_HANDLED。
通常,一个中断处理程序如程序清单2.24所示。
程序清单2.24中断处理程序
staticirqreturn_txxxx_interrupt(intirq,void*dev_id)
{
...中断处理代码
returnIRQ_HANDLED;
/*中断已经处理完毕*/
}
至于中断处理程序要做些什么,应当做些什么,取决于具体系统的具体应用,没有统一的要求,但是中断处理程序应当尽量短,处理只能在中断上下文中处理的事情,能放到进程上下文的工作都不要放到中断上下文中处理。
1.1.3按键驱动
1.背景交代
本节提供的按键驱动范例基于EPC-28x工控主板。
EPC-28x硬件上有不少用户可用GPIO,本节选取其中一个GPIO,用作按键,并编写驱动,用于演示中断的基本用法。
本节范例按键对应的GPIO为GPIO2_6,对应IO在系统中的编号为70。
IO端口平时处于高电平,按键按下后为低电平。
Linux系统为每个中断都分配了一个编号。
i.MX28x处理器的每个IO端口都可以产生中断,IO引脚编号GPIOn和中断号IRQn之间的换算公式为:
IRQn=GPIOn+128,在代码中可通过gpio_to_irq函数来完成转换。
2.驱动实现
按键通常来说无需进行读写操作,也无需进行其它ioctl操作,因此,这些方法都无需实现。
范例程序仅仅实现了open、release和close三种方法,参考程序清单2.25。
第10~13的3个宏定义分别行定义了IO端口、中断编号和设备名称。
第20~26行列举了可用的中断触发条件,在代码中根据实际需要来使用。
根据硬件情况,代码中实际使用下降沿中断IRQ_TYPE_EDGE_FALLING。
范例代码中有一点需要说明一下,就是代码中使用了GPIO申请和释放函数,见第59行和108行。
在Linux系统中,为了防止某个IO被在多个地方被重复使用,在使用之前需通过gpio_request_one()函数进行申请。
在没有被释放之前,其它驱动程序是不能获得该IO端口的,能有效防止资源混乱。
使用完毕,可通过gpio_free()函数释放该端口。
程序清单2.25按键驱动范例
1#include<
linux/init.h>
2#include<
linux/module.h>
3#include<
linux/fs.h>
4#include<
linux/cdev.h>
5#include<
linux/device.h>
6#include<
7#include<
8#include<
linux/gpio.h>
9
10#defineKEY_GPIO
70
/*GPIO2_6
*/
11#defineKEY_GPIO_IRQ
gpio_to_irq(KEY_GPIO)
/*中断号
12#defineDEVICE_NAME
"
key_irq"
13
14staticintmajor;
15staticintminor;
16structcdev*key_irq;
/*cdev数据结构
17staticdev_tdevno;
/*设备编号
18staticstructclass*key_irq_class;
19
20charconstirq_types[5]={
21
IRQ_TYPE_EDGE_RISING,
22
IRQ_TYPE_EDGE_FALLING,
23
IRQ_TYPE_EDGE_BOTH,
24
IRQ_TYPE_LEVEL_HIGH,
25
IRQ_TYPE_LEVEL_LOW
26};
27
28staticintkey_irq_open(structinode*inode,structfile*file)
29{
30
try_module_get(THIS_MODULE);
31
printk(KERN_INFODEVICE_NAME"
opened!
\n"
);
32
return0;
33}
34
35staticintkey_irq_release(structinode*inode,structfile*file)
36{
37
closed!
38
module_put(THIS_MODULE);
39
40}
41
42staticirqreturn_tkey_irq_irq_handler(unsignedintirq,void*dev_id)
43{
44
printk("
KEYIRQHAPPENED!
45
returnIRQ_HANDLED;
46}
47
48structfile_operationskey_irq_fops={
49
.owner
=THIS_MODULE,
50
.open
=key_irq_open,
51
.release=key_irq_release,
52};
53
54staticint__initkey_irq_init(void)
55{
56
intret;
57
58
gpio_free(KEY_GPIO);
59
ret=gpio_request_one(KEY_GPIO,GPIOF_IN,"
KEYIRQ"
/*申请IO
60
if(ret<
0){
61
printk(KERN_ERR"
FailedtorequestGPIOforKEY\n"
62
}
63
64
gpio_direction_input(KEY_GPIO);
/*设置GPIO为输入
65
if(request_irq(KEY_GPIO_IRQ,key_irq_irq_handler,IRQF_DISABLED,"
key_irqirq"
NULL))
{
/*申请中断*/
66
printk(KERN_WARNINGDEVICE_NAME"
:
Can'
tgetIRQ:
%d!
KEY_GPIO_IRQ);
67
68
set_irq_type(KEY_GPIO_IRQ,irq_types[1]);
69
disable_irq(KEY_GPIO_IRQ);
70
enable_irq(KEY_GPIO_IRQ);
71
72
ret=alloc_chrdev_region(&
devno,minor,1,DEVICE_NAME);
/*从系统获取主设备号
73
major=MAJOR(devno);
74
75
cannotgetmajor%d\n"
major);
76
return-1;
77
78
79
key_irq=cdev_alloc();
/*分配key_irq结构
80
if(key_irq!
=NULL){
81
cdev_init(key_irq,&
key_irq_fops);
/*初始化key_irq结构
82
key_irq->
owner=THIS_MODULE;
83
if(cdev_add(key_irq,devno,1)!
=0){
/*增加key_irq到系统中
84
addcdeverror!
85
gotoerror;
86
87
}else{
88
cdev_allocerror!
89
90
91
92
key_irq_class=class_create(THIS_MODULE,"
key_irq_class"
93
if(IS_ERR(key_irq_class)){
94
printk(KERN_INFO"
createclasserror\n"
95
96
97
98
device_create(key_irq_class,NULL,devno,NULL,DEVICE_NAME);
99
100
101error:
102
unregister_chrdev_region(devno,1);
/*释放已经获得的设备号*/
103
returnret;
104}
105
106staticvoid__exitkey_irq_exit(void)
107{
108
109
110
free_irq(KEY_GPIO_IRQ,NULL);
111
cdev_del(key_irq);
/*移除字符设备
112
/*释放设备号
113
device_destroy(key_irq_class,devno);
114
class_destroy(key_irq_class);
115}
116
117module_init(key_irq_init);
118module_exit(key_irq_exit);
119
120MODULE_LICENSE("
GPL"
121MODULE_AUTHOR("
Chenxibing,linux@"
3.驱动测试
编译驱动后,将驱动模块插入系统,然后按下按键,可以看到按键中断发生并打印提示信息:
[root@EPC-28xmnt]#insmodkey_irq.ko
此时,查看/proc/interrupts文件,可以看到中断的发生次数:
[root@EPC-28xmnt]#cat/proc/interrupts
CPU0
...
220:
26
GPIO
key_irqirq