中断处理(按键驱动)

本文详细介绍了使用按键驱动程序实现中断处理的过程,包括如何注册中断、编写中断处理函数及利用异步通知机制实现高效的数据读取。通过具体代码示例,深入探讨了驱动程序与应用程序间的交互方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

用今天写的一个按键驱动程序,来说明中断的处理过程:

代码如下:

#define GPH0CON 0xE0300C00

int major = 250;
int minor = 0;
int devno;
void *gphcon=NULL;

struct key_device{
	char val;
	struct cdev cdev;
	struct semaphore sem;
	wait_queue_head_t rwait;
	struct fasync_struct *async_queue;
}key_device;



int key_open(struct inode *inode,struct file *file)
{
	file->private_data = container_of(inode->i_cdev,struct key_device,cdev);
	printk(KERN_INFO"opened\n");
	return 0;
}
int key_fasync(int fd,struct file *file,int mode)
{
	printk("%d\n",mode);
	struct key_device *device = file->private_data;
	return fasync_helper(fd,file,mode,&device->async_queue);

}


int key_release(struct inode *inode,struct file *file)
{
	printk(KERN_INFO"closed\n");
	key_fasync(-1,file,0);
	return 0;
}



ssize_t key_read(struct file *file,char *__user buf,size_t count,loff_t *loff)
{
	struct key_device *device;
	device = file->private_data;
	down(&device->sem);

	while(device->val==0)
	{
		up(&device->sem);
		if(file->f_flags & O_NONBLOCK)
			return -EAGAIN;
		if(wait_event_interruptible(device->rwait,(device->val>0)))
			return -EAGAIN;
		down(&device->sem);
	}
	if(copy_to_user(buf,&(device->val),count))
	{
		up(&device->sem);
		return -EFAULT;
	}
	device->val = 0;
	up(&device->sem);
	return 1;
	
}

struct file_operations fops={
	.open    = key_open,
	.release = key_release,
	.read    = key_read,
	.fasync  = key_fasync,
};


irqreturn_t handler(int irqno,void *dev) //中断处理
{
	static long old_jiffies;
	if((jiffies - old_jiffies) < 20)
		return IRQ_HANDLED;
	old_jiffies = jiffies;

	switch (irqno)
	{
	case IRQ_EINT(1):
		((struct key_device *)dev)->val = 1;
		break;
	case IRQ_EINT(2):
		((struct key_device *)dev)->val = 2;
		break;
	case IRQ_EINT(3):
		((struct key_device *)dev)->val = 3;
		break;
	case IRQ_EINT(4):
		((struct key_device *)dev)->val = 4;
		break;
	case IRQ_EINT(6):
		((struct key_device *)dev)->val = 5;
		break;
	default:
		((struct key_device *)dev)->val = 6;

	}
	wake_up(&((struct key_device *)dev)->rwait );
	if(((struct key_device *)dev)->async_queue)
		kill_fasync(&((struct key_device*)dev)->async_queue,SIGIO,POLL_IN);

	return IRQ_HANDLED;

}

int key_request_irq(void)//注册中断
{
	int ret;
	ret = request_irq(IRQ_EINT(1),handler,IRQF_DISABLED|IRQF_TRIGGER_FALLING,"key",&key_device);
	if(ret) return ret;
	ret = request_irq(IRQ_EINT(2),handler,IRQF_DISABLED|IRQF_TRIGGER_FALLING,"key",&key_device);
	if(ret) goto _errno1;
	ret = request_irq(IRQ_EINT(3),handler,IRQF_DISABLED|IRQF_TRIGGER_FALLING,"key",&key_device);
	if(ret) goto _errno2;
	ret = request_irq(IRQ_EINT(4),handler,IRQF_DISABLED|IRQF_TRIGGER_FALLING,"key",&key_device);
	if(ret) goto _errno3;
	ret = request_irq(IRQ_EINT(6),handler,IRQF_DISABLED|IRQF_TRIGGER_FALLING,"key",&key_device);
	if(ret) goto _errno4;
	ret = request_irq(IRQ_EINT(7),handler,IRQF_DISABLED|IRQF_TRIGGER_FALLING,"key",&key_device);
	if(ret) goto _errno5;
	printk(KERN_INFO"irq_register\n");
		return ret;
	_errno5: free_irq(IRQ_EINT(6),&key_device);
	_errno4: free_irq(IRQ_EINT(4),&key_device);
	_errno3: free_irq(IRQ_EINT(3),&key_device);
	_errno2: free_irq(IRQ_EINT(2),&key_device);
	_errno1: free_irq(IRQ_EINT(1),&key_device);
			 printk("irq_register\n");
			 return -1;
}
static  int key_int(void)
{	
	devno = MKDEV(major,minor);

	cdev_init(&key_device.cdev,&fops);
	key_device.cdev.owner = THIS_MODULE;
	cdev_add(&key_device.cdev,devno,1);
	
	gphcon = ioremap(GPH0CON,4);
	writel((readl(gphcon)&0x00f0000f)|0x22022220,gphcon);
	printk(KERN_INFO"ready for irq\n");
	key_request_irq();
	init_waitqueue_head(&key_device.rwait);
	init_MUTEX(&key_device.sem);
	key_device.val = 0;
	
	return 0;

}
static void key__exit()
{
	iounmap(gphcon);
	free_irq(IRQ_EINT(7),&key_device);
	free_irq(IRQ_EINT(6),&key_device);
	free_irq(IRQ_EINT(4),&key_device);
	free_irq(IRQ_EINT(3),&key_device);
	free_irq(IRQ_EINT(2),&key_device);
	free_irq(IRQ_EINT(1),&key_device);
	cdev_del(&key_device.cdev);
	unregister_chrdev_region(devno,1);
}

module_init(key_int);
module_exit(key__exit);
MODULE_LICENSE("GPL");


总结起来其实就两个要点:注册中断,中断处理函数

(1)注册中断:

request_irq(irqno,handler,flag,"",char *)

此函数把中断号irqno,和中断处理函数handler结合起来。flag是标志位,说明了中断是否共用,中断方式(上升、下降、电平)

我认为最重要的是后面的char *,它可以做为参数传递为中断处理程序,一般传的是设备结构体。

返回值0代表成功,负数代表失败

(2)中断处理函数

irqreturn_t     handler(int irqno,void *)

irqno是发生中断的中断号,void * 就是由此irqno注册时的传参(request_irq的参数char *),传参一般是设备结构体指针,所以还需要对他进行强转。

有中断号,有设备结构体,我们就能完成对设备结构体相应的操作。

返回值是枚举型。


在这个函数中,用到了前面说的异步通知,就是说,当发生按键时,在中断处理函数中会去kill_fasync,给应用进程发送SIGIO信号,在应用程序中,就回去读取按键值,这时候不会发生阻塞。

另一种方法是应用程序读写时,若没有按键按下,就加入等待队列,有按键按下时再去唤醒等待队列。

这两种方法驱动都有所实现。




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值