Linux驱动程序学习笔记(4)——使用中断的按键驱动程序
2012-11-26 14:41
337 查看
一,难点
1,注册用户中断函数
int request_irq(unsigned int irq,irq_handler_t handler,unsigned long flags,const char *devname,void *dev_id);
用户(即驱动程序)通过request_irq函数向内核注册中断处理函数,request_irq函数根据中断号找到irq_desc数组项,然后在它的action链表中添加一个表项。
第一个参数irq为中断好,第二个参数handler为用户编写的中断处理函数(见第2点),第三个参数flags为中断触发模式,第四个参数devname为中断名称(方便用户查看而已),第五个参数dev_id为一个空类型的指针,传递给中断处理函数供用户自定义使用等
2,卸载中断处理函数
void free_irq(unsigned int irq, void *dev_id)
两个参数对应request_irq函数中的中断号irq和dev_id
3,用户编写的中断处理函数
static irqreturn_t irqButton_handle(int irq, void *dev_id) { char **name = (char **)dev_id; printk("%d press %s\n",cnt++,*name); eventPress = 1; wake_up_interruptible(&buttonWaitQueue); return IRQ_RETVAL(IRQ_HANDLED); }
2个参数irq,dev_id由request_irq函数传递过来的,用户在这个函数里做中断发生时候需要做的事情,注意这个函数的返回值为return IRQ_RETVAL(IRQ_HANDLED);
4,有关使进程睡眠的函数
(1)static DECLARE_WAIT_QUEUE_HEAD(buttonWaitQueue);创建一个睡眠队列,队列头为buttonWaitQueue,这个队头在睡眠和唤醒函数里用到
(2)wait_event_interruptible(buttonWaitQueue,eventPress);
当eventPress为0时候进程会进入睡眠
(3)wake_up_interruptible(&button_waitq);
唤醒睡眠的进程
二,使用中断的方法
(1)编写中断处理函数(2)在open函数里注册中断函数,此时中断就打开了
(3)在close函数里卸载中断函数
三,Linux中断处理流程
(1)中断时CPU执行异常向量vector_irq的代码(2)在vector_irq里,最终会调用外部中断处理的总入口函数asm_do_IRQ
(3)在asm_do_IRQ根据中断号调用irq_desc 结构体数组项中的handle_irq
(4)handle_irq会调用irq_desc 结构体数组项中的chip成员中的函数来设置硬件,比如清楚中断,禁止中断等
(5)handle_irq会逐个调用在irq_desc结构体数组项中的action链表中注册的中断处理函数
可见,操作系统的中断体系结构的初始化是构造这些数据结构。用户(我们)注册中断时就是构造action链表,卸载中断就是从action链表里去除不需要的项
四,代码
(1)驱动程序#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/irq.h>
#include <asm/uaccess.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <asm/arch/regs-gpio.h>
#include <asm/hardware.h>
static struct class *irqButton_class;
static struct class_device *irqButton_class_device;
int major;
int cnt = 0;
int eventPress = 0;
//声明一个等待队列,队头为buttonWaitQueue
static DECLARE_WAIT_QUEUE_HEAD(buttonWaitQueue);
struct IrqButtonInfo
{
int irqno;
char *name;
};
struct IrqButtonInfo keys[6]=
{
{IRQ_EINT8,"K1"},
{IRQ_EINT11,"K2"},
{IRQ_EINT13,"K3"},
{IRQ_EINT14,"K4"},
{IRQ_EINT15,"K5"},
{IRQ_EINT19,"K6"}
};
static irqreturn_t irqButton_handle(int irq, void *dev_id) { char **name = (char **)dev_id; printk("%d press %s\n",cnt++,*name); eventPress = 1; wake_up_interruptible(&buttonWaitQueue); return IRQ_RETVAL(IRQ_HANDLED); }
static int irqButton_open(struct inode *inode, struct file *file)
{
//初始化中断
int i;
for(i=0;i<6;i++)
{
request_irq(keys[i].irqno,irqButton_handle,IRQT_FALLING,keys[i].name,&keys[i].name);
}
return 0;
}
static int irqButton_read (struct file *filp, char __user *buffer,
size_t count, loff_t *ppos)
{
wait_event_interruptible(buttonWaitQueue,eventPress);
eventPress = 0;
return 0;
}
static int irqButton_close(struct inode *inode, struct file *file)
{
int i;
for(i=0;i<6;i++)
{
free_irq(keys[i].irqno,&keys[i].name);
}
return 0;
}
static struct file_operations irqButton_ops =
{
.owner = THIS_MODULE,
.open = irqButton_open,
.read = irqButton_read,
.release = irqButton_close
};
static int irqButton_init(void)
{
major = register_chrdev(0,"irqButton_driver",&irqButton_ops);
irqButton_class = class_create(THIS_MODULE,"irqButton_class");
irqButton_class_device = class_device_create(irqButton_class,NULL,MKDEV(major,0),NULL,"irqButton");
return 0;
}
static void irqButton_exit(void)
{
unregister_chrdev(major,"irqButton_driver");
class_device_unregister(irqButton_class_device);
class_destroy(irqButton_class);
}
module_init(irqButton_init);
module_exit(irqButton_exit);
MODULE_LICENSE("GPL");
(2)测试代码
#include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <stdio.h> int main(int argc, char **argv) { int fid; int i; char filename[40] = "/dev/irqButton"; fid = open(filename,O_RDWR); if(fid < 0) { printf("%s Open error!\n",argv[1]); return -1; } while(1) { read(fid,&i,sizeof(i)); } close(fid); return 0; }
相关文章推荐
- Linux按键驱动程序设计(4)-中断分层技术
- <2012 11 6 > linux设备驱动程序开发初探(4) linux的中断体系_按键中断驱动程序编写
- 07-S3C2440驱动学习(一)嵌入式linux字符设备驱动-查询+中断+引入poll机制的按键驱动程序
- linux2.6内核下的一个按键中断驱动程序示例
- 第12课第4.1节 字符设备驱动程序之中断方式的按键驱动_Linux异常处理结构
- 第12课第4.2节 字符设备驱动程序之中断方式的按键驱动_Linux中断处理结构
- Linux按键驱动程序设计(2)-Linux中断处理程序
- linux按键中断驱动程序——S3C2440
- linux2.6内核下的一个按键中断驱动程序示例[zz]
- linux2.6内核下的一个按键中断驱动程序示例
- 12.按键驱动程序设计(2)-Linux中断处理
- 【ARM&Linux】按键中断驱动程序设计
- linux 驱动 -》按键 中断 request_irq 延时防抖mod_timer
- linux中进入man 指令环境后可以使用的按键
- 字符设备驱动程序开发之基于中断的按键驱动加去抖动
- linux-2.6.32在mini2440开发板上移植 ---按键驱动程序移植
- Linux中断(interrupt)子系统之四:驱动程序接口层 & 中断通用逻辑层【转】
- 7.自己写中断方式按键驱动程序(详解)
- arm驱动程序——按键程序6_互斥—信号量(韦东山的视频总结及针对linux-2.6.30)
- 8.中断按键驱动程序之poll机制(详解)