Linux驱动程序学习笔记(4)——使用中断的按键驱动程序

一,难点

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




 

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值