您的位置:首页 > 运维架构 > Linux

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;
}


 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: