1、中断申请函数request_irq
函数原型:
request_irq(unsigned int irq, irq_handler_t handler,
unsigned long flags, const char *name, void *dev);
参数详解:
1、irq:中断编号(每个中断源有唯一编号),中断来临时,通过该编号识别中断,并调用处理程序
一般通过函数gpio_to_irq(unsigned int gpio),将对应引脚号转换为中断号
2、handler:中断服务函数指针,原型typedef irqreturn_t (*irq_handler_t)(int , void *);
void *是由request_irq注册函数传递的*dev数据,在handler中可以可以取出数据dev以备使用
3、flag:中断属性,如快速中断,共享中断,如果是外部中断还有:上升沿,下降沿触发这类标志。
#define IRQF_TRIGGER_NONE 0x00000000
#define IRQF_TRIGGER_RISING 0x00000001
#define IRQF_TRIGGER_FALLING 0x00000002
#define IRQF_TRIGGER_HIGH 0x00000004
#define IRQF_TRIGGER_LOW 0x00000008
#define IRQF_TRIGGER_PROBE 0x00000010
#define IRQF_TRIGGER_MASK (IRQF_TRIGGER_HIGH | IRQF_TRIGGER_LOW | \
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)
4、name:中断名字,注册后会在/proc/irq/``irq号name文件夹出现。
5、dev: 一般来说都会传递一个有意义的指针,一般是驱动程序管理的与设备相关的数据结构对象的指针作为dev的实参,然后传递给中断处理函数使用
6、返回值:0表示成功,返回-EINVAL表示中断号无效 ,返回-EBUSY表示中断被占用。
2、中断释放函数free_irq
函数原型:
void free_irq(unsigned int irq, void *dev_id)
参数意义同上
3、中断例程
#if 0
1.本例子使用面向对象的思想来编写
2.开发板上的4个按键,每个按键是操作的方法是一样,
所以把一个按键需要使用的信息封装成一个结构体,要多个按键只需要定义结构体数组即可。
3.展示如何使用dev_id来简化编程
4.按键信息: gpio编号,按键编号,按键名
#endif
#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/miscdevice.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <linux/interrupt.h>
#include <linux/gpio.h>
#define KEY_NUM 4
//定义按键缓冲区,'0'表示松开,'1'表示按下
char keybuf[KEY_NUM] = {'0', '0', '0', '0'};
//定义按键对象
typedef struct button_desc{
int gpio; //io编号
int num; //按键编号
char *name; //按键名
}button_desc_t;
//定义结构体数组
button_desc_t buttons[KEY_NUM]={
{EXYNOS4_GPX3(2),0,"KEY1"},
{EXYNOS4_GPX3(3),1,"KEY2"},
{EXYNOS4_GPX3(4),2,"KEY3"},
{EXYNOS4_GPX3(5),3,"KEY4"}
};
//以下是文件操作方法的具体实现代码
static int xxx_open(struct inode *pinode, struct file *pfile )
{
printk(KERN_EMERG"file:%s\r\nline:%d, %s is call\n", __FILE__, __LINE__, __FUNCTION__);
return 0;
}
static int xxx_release (struct inode *pinode, struct file *pfile)
{
printk(KERN_EMERG"file:%s\r\nline:%d, %s is call\n", __FILE__, __LINE__, __FUNCTION__);
return 0;
}
static ssize_t xxx_read(struct file *pfile,
char __user *buf,
size_t count, loff_t *poff)
{
int ret;
if(count > KEY_NUM) {
count = KEY_NUM;
}
//给用户返回按键的状态
ret = copy_to_user(buf, keybuf, count);
if(ret) {
printk("copy_to_user error!");
return -EFAULT;
}
return count;
}
//文件操作方法集合指针
static const struct file_operations mymisc_fops = {
.open = xxx_open,
.read = xxx_read,
.release = xxx_release,
};
//定义核心结构
static struct miscdevice misc = {
.minor = 255,
.name = "mybutton", ///dev目录下的设备名
.fops = &mymisc_fops,
};
//中断服务函数
//注意:request_irq时候传递了每个按键元素首地址做为dev_id
irqreturn_t mybuttons_handler(int irq, void *dev_id)
{
int id ;
button_desc_t * pdata;
//把void*类型转换成原来传入的类型,得到按键的结构内存首地址
pdata = (button_desc_t*)dev_id;
id = pdata->num;
if(!gpio_get_value(pdata->gpio)) { /*按下*/
keybuf[id] = '1';
printk("%s is dn\n",pdata->name);
} else {
keybuf[id] = '0';
printk("%s is up\n",pdata->name);
}
return IRQ_HANDLED;
}
static int __init mymisdevice_init(void)
{
int i;
int ret;
unsigned int irq;
unsigned long flags;
//看原理图可以知道使用外部中断 26~29四个中断
for ( i = 0 ; i < 4 ; i++ ) {
//通过io编号转换成中断编号
irq = gpio_to_irq(buttons[i].gpio);
//中断标志:对于外部中断才有IRQF_TRIGGER_FALLING,IRQF_TRIGGER_RISING
//IRQF_SHARED 对于共用 中断编号的情况需要指定,如果不指定,则这个中断号只能被注册一次
//IRQF_SAMPLE_RANDOM 表示对系统产生随机数据有贡献,要不要都可以。
//flags = IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING | IRQF_SHARED | IRQF_SAMPLE_RANDOM;
flags = IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING ;
//注意:这里传递了每个按键元素首地址做为dev_id
ret = request_irq(irq, mybuttons_handler, flags, buttons[i].name, (void *)&buttons[i]);
if(ret < 0) {
printk("request_irq error\r\n");
return ret;
}
printk("request irq:%d,\n", irq);
}
//注册核心结构
ret = misc_register(&misc);
if(ret < 0) {
printk(KERN_EMERG"misc_register error\n");
return ret;
}
printk(KERN_EMERG"misc_register ok\n");
return 0;
}
static void __exit mymisdevice_exit(void)
{
int ret;
int i;
int irq;
//注销核心结构
ret = misc_deregister(&misc);
if(ret < 0) {
printk(KERN_EMERG"misc_deregister error\n");
return ;
}
//释放中断
for ( i = 0 ; i < 4 ; i++ ) {
irq = gpio_to_irq(buttons[i].gpio);
free_irq(irq, (void *)&buttons[i]);
}
printk(KERN_EMERG"misc_deregister ok\n");
}
module_init(mymisdevice_init);
module_exit(mymisdevice_exit);
MODULE_LICENSE("GPL");