基于exynos4412的按键驱动实验的异步IO的实现

驱动代码:

#include <linux/module.h>
#include <linux/init.h>
#include <linux/of.h>
#include <linux/device.h>
#include <linux/fs.h>
#include <linux/interrupt.h>
#include <linux/of_irq.h>
#include <linux/slab.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <linux/sched.h>
#include <linux/poll.h>

#define GPX1CON 0x11000c20
#define KEY2_ENTER 28
#define KEY3_ENTER 29

struct key_event{
	int code;
	int value;
};
struct dev_desc{
	void *reg_addr;
	int key_major;	
	unsigned int irqno1;
	unsigned int irqno2;
	struct class *cls;
	struct device *dev;
	struct key_event event;
	wait_queue_head_t wq_head;//等待队列头
	int key_state;//是否有数据
	struct fasync_struct *fasync;
};

struct dev_desc *key_dev;

//中断处理函数
irqreturn_t key2_handler(int irqno, void *dev)
{
	unsigned int value;
	printk("-----------------%s--------------------\n",__FUNCTION__);
	//读取key2的状态
	value = readl(key_dev->reg_addr+4) & (0x1<<1);
	if(value){
		key_dev->event.code = KEY2_ENTER;
		key_dev->event.value = 1;
		printk("key2 up\n");
	}else{
		key_dev->event.code = KEY2_ENTER;
		key_dev->event.value = 0;
		printk("key2 down\n");
	}
	//表示有数据了,唤醒等待队列,同时设置标志位
	wake_up_interruptible(&key_dev->wq_head);
	key_dev->key_state = 1;

	//发送信号
	kill_fasync(&key_dev->fasync,SIGIO,POLLIN);
	
	return IRQ_HANDLED;
}

irqreturn_t key3_handler(int irqno, void *dev)
{

	unsigned int value;
	printk("-----------------%s--------------------\n",__FUNCTION__);
	//读取key3的状态
	value = readl(key_dev->reg_addr+4) & (0x1<<2);
	if(value){
		key_dev->event.code = KEY3_ENTER;
		key_dev->event.value = 1;
		printk("key3 up\n");
	}else{
		key_dev->event.code = KEY3_ENTER;
		key_dev->event.value = 0;
		printk("key3 down\n");
	}

	//表示有数据了,唤醒等待队列,同时设置标志位
	wake_up_interruptible(&key_dev->wq_head);
	key_dev->key_state = 1;
	return IRQ_HANDLED;
	
}

ssize_t key_read (struct file *filp, char __user *buf, size_t count, loff_t *fpos)
{
	int ret;

	printk("-----------------%s--------------------\n",__FUNCTION__);
	//如果当前是非阻塞模式且没有数据就立即返回
	/*
	if(filp->f_flags & O_NONBLOCK && !key_dev->key_state){
		return -EAGAIN;
	}
	*/
	//没有数据的时候就休眠(阻塞模式)
	wait_event_interruptible(key_dev->wq_head,key_dev->key_state);
	//表示有数据
	ret = copy_to_user(buf, &key_dev->event, count);
	if(ret){
		printk("copy_from_user failed\n");
		return -EFAULT;
	}

	memset(&key_dev->event, 0, sizeof(key_dev->event));
	key_dev->key_state = 0;
	
	return count;
}

ssize_t key_write (struct file *filp, const char __user *buf, size_t count, loff_t *fpos)
{
	printk("-----------------%s--------------------\n",__FUNCTION__);

	return 0;
}

int key_open (struct inode *inode, struct file *filp)
{
	printk("-----------------%s--------------------\n",__FUNCTION__);

	return 0;
}

int key_close (struct inode *inode, struct file *filp)
{
	printk("-----------------%s--------------------\n",__FUNCTION__);

	return 0;
}

unsigned int key_poll (struct file *filp, struct poll_table_struct *pts)
{
	unsigned int mask = 0;

	poll_wait(filp, &key_dev->wq_head, pts);
	if(!key_dev->key_state){
		mask = 0;
	}else{
		mask |= POLLIN;
	}
	
	return mask;
}

int key_fasync(int fd, struct file *filp, int on)
{
	//初始化fasync_struct结构体,记录信号发送给谁
	return fasync_helper(fd, filp,on, &key_dev->fasync);
}

const struct file_operations fops = {
	.open = key_open,
	.read = key_read,
	.write = key_write,
	.release = key_close,
	.poll = key_poll,
	.fasync = key_fasync,
};

static int __init key_dev_init(void)
{
	struct device_node *np1,*np2;
	int err = 0;

	printk("-----------------%s--------------------\n",__FUNCTION__);
	//分配空间
	key_dev = kzalloc(sizeof(struct dev_desc), GFP_KERNEL);
	if(key_dev == NULL){
		printk("kzalloc failed\n");
		return -ENOMEM;
	}
	//获取key2的设备树节点
	np1 = of_find_node_by_path("/key2_node");
	if(np1 == NULL){
		printk("key2 of_find_node_by_path failed\n");
	}
	
	//获取key3的设备树节点
	np2 = of_find_node_by_path("/key3_node");
	if(np2 == NULL){
		printk("key3 of_find_node_by_path failed\n");
	}
	
	//获取key2中断号
	key_dev->irqno1 = irq_of_parse_and_map(np1,0);
	//获取key3中断号
	key_dev->irqno2 = irq_of_parse_and_map(np2,0);
	
	//打印中断号
	printk("irqno of key2 is %d\n",key_dev->irqno1);
	printk("irqno of key3 is %d\n",key_dev->irqno2);

	//申请主设备号
	key_dev->key_major = register_chrdev(0, "key_drv",&fops);
	if(key_dev->key_major < 0){
		printk("register_chrdev failed\n");
		err = -ENODEV;
		goto err_0;
	}
	//创建设备节点
	key_dev->cls = class_create(THIS_MODULE, "key_class");
	if(IS_ERR(key_dev->cls)){
		printk(KERN_ERR "class_create failed\n");
		err = PTR_ERR(key_dev->cls);
		goto err_1;
	}
	key_dev->dev = device_create(key_dev->cls, NULL, MKDEV(key_dev->key_major, 0), NULL, "key");
	if(IS_ERR(key_dev->dev)){
		printk(KERN_ERR "device_create failed\n");
		err = PTR_ERR(key_dev->dev);
		goto err_2;
	}
	//key2申请中断
	if(request_irq(key_dev->irqno1,key2_handler,IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING,"key2_irq",NULL)){
		printk("key2 request_irq failed\n");
	}
	//key3申请中断
	if(request_irq(key_dev->irqno2,key3_handler,IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING,"key3_irq",NULL)){
		printk("key3 request_irq failed\n");
	}
	//将GPX1CON物理地址映射为虚拟地址reg_addr
	key_dev->reg_addr = ioremap(GPX1CON,8);
	if(key_dev->reg_addr == NULL){
		printk("ioremap error\n");
		err = -EFAULT;
		goto err_3;
	}
	//初始化等待队列
	init_waitqueue_head(&key_dev->wq_head);
	
	return 0;
	
err_3:
	device_destroy(key_dev->cls,MKDEV(key_dev->key_major, 0));
err_2:
	class_destroy(key_dev->cls);
err_1:
	unregister_chrdev(key_dev->key_major, "key_drv");
err_0:
	kfree(key_dev);
	return err;
}

static void __exit key_dev_exit(void)
{
	printk("-----------------%s--------------------\n",__FUNCTION__);

	//释放地址映射
	iounmap(key_dev->reg_addr);
	//释放key2中断
	free_irq(key_dev->irqno1,NULL);
	//释放key3中断
	free_irq(key_dev->irqno2,NULL);
	//释放设备节点
	device_destroy(key_dev->cls,MKDEV(key_dev->key_major, 0));
	class_destroy(key_dev->cls);
	//释放设备号
	unregister_chrdev(key_dev->key_major, "key_drv");
	//释放key_dev
	kfree(key_dev);
}

module_init(key_dev_init);
module_exit(key_dev_exit);
MODULE_LICENSE("GPL");







测试代码:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <signal.h>

#define KEY2_ENTER 28
#define KEY3_ENTER 29

struct key_event{
	int code;
	int value;
};
struct key_event event;
int fd;

void catch_signal(int signo)
{
	printf("get signal\n");
	if(signo == SIGIO){
		read(fd,&event,sizeof(struct key_event));
		if(event.code == KEY2_ENTER){
			if(event.value == 1){
				printf("user key2 up\n");
			}else{
				printf("user key2 down\n");
			}
		}
		if(event.code == KEY3_ENTER){
			if(event.value == 1){
				printf("user key3 up\n");
			}else{
				printf("user key3 down\n");
			}
		}
	}
}

int main()
{
	int flags;
	
	fd = open("/dev/key",O_RDWR);
	if(fd < 0){
		perror("open");
		exit(-1);
	}
	//设置信号处理方法
	signal(SIGIO,catch_signal);
	//将当前进程PID设置成驱动程序将要发送SIGIO信号的进程PID
	fcntl(fd,F_SETOWN,getpid());
	//将io模式设置成异步模式
	flags = fcntl(fd,F_GETFL);
	/*该代码执行将会触发驱动程序中的file_operations->fasync函数,fasync函数将会调用fasync_helper函数初始化一个struct fasync_struct,
	该结构体描述了将要发送信号的进程PID                */
	fcntl(fd,F_SETFL,flags|FASYNC);

	while(1){
		printf("i am waitting...\n");
		sleep(1);
	}
	
	close(fd);
	
	return 0;
}

实验效果


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值