基于异步通知机制的按键驱动

原创 2017年03月01日 17:40:02

按下按键是驱动程序通知应用程序


应用程序里面要注册信号处理函数

驱动程序给应用程序发信号

发给谁,这就要应用程序告诉驱动pid了

怎么发,是驱动里面调用kill_fasync



为了使设备支持异步通知机制,驱动程序涉及以下3项工作

1.支持F_SETOWN命令,能在这个控制命令处理中设置filp->f_owner为对应进程ID

   不过此项工作已经有内核完成,设备驱动无需处理

2.支持F_SETFL命令的处理,每当FASYNC标志改变时,驱动程序中的fasync()函数将得以执行

   驱动中应该实现fasync函数

3.在设备资源可以获得时,调用kill_fasync()函数激发相应的信号


应用程序会调用fcntl(fd,F_SETOWN,pid)把它的pid告诉驱动程序

然后还要读出flags

oflags = fcntl(fd,F_GETFL)

要把这个flag进行修改fcntl(fd,F_SETFL,oflags | FASYNC);当应用程序调用这个接口的时候,fasync_helper就会被调用

#include <linux/device.h>
#include <linux/interrupt.h>
#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 <mach/gpio.h>
#include<linux/cdev.h>
#include <linux/poll.h>
int key_id;
struct cdev cdev;
dev_t devno;


static struct fasync_struct *button_fasync;


/*定义并初始化等待队列的头*/
static DECLARE_WAIT_QUEUE_HEAD(key_qaq);




/*中断事件标志,中断服务程序将它置为1,read函数将它置为0*/
unsigned int wait_val=0;
struct class *my_class;




static irqreturn_t key_func(int irq,void *dev_id)
{
key_id=(int)dev_id;


/*唤醒*/
wait_val=1;
wake_up(&key_qaq);


kill_fasync(&button_fasync,SIGIO,POLL_IN);//发出信号
return 0;
}


static int key_open(struct inode *inode,struct file *file)
{


request_irq(IRQ_EINT(16),key_func,IRQF_TRIGGER_FALLING,"k1",1);
request_irq(IRQ_EINT(17),key_func,IRQF_TRIGGER_FALLING,"k2",2);
request_irq(IRQ_EINT(18),key_func,IRQF_TRIGGER_FALLING,"k3",3);
request_irq(IRQ_EINT(19),key_func,IRQF_TRIGGER_FALLING,"k4",4);
request_irq(IRQ_EINT(24),key_func,IRQF_TRIGGER_FALLING,"k5",5);
request_irq(IRQ_EINT(25),key_func,IRQF_TRIGGER_FALLING,"k6",6);
request_irq(IRQ_EINT(26),key_func,IRQF_TRIGGER_FALLING,"k7",7);
request_irq(IRQ_EINT(27),key_func,IRQF_TRIGGER_FALLING,"k8",8);


return 0;
}


static int key_close(struct inode *inode,struct file *file)
{


free_irq(IRQ_EINT(16),1);
free_irq(IRQ_EINT(17),2);
free_irq(IRQ_EINT(18),3);
free_irq(IRQ_EINT(19),4);
free_irq(IRQ_EINT(24),5);
free_irq(IRQ_EINT(25),6);
free_irq(IRQ_EINT(26),7);
free_irq(IRQ_EINT(27),8);


return 0;
}


ssize_t key_read(struct file *filp, char __user *buf, size_t size,loff_t *pos)
{
/*如果没有按键按下,休眠,让出CPU*/
wait_event(key_qaq,wait_val);
/*如果有按键按下*/
copy_to_user(buf,&key_id,sizeof(key_id)); 
wait_val=0;


return 0;
}




static int key_fasync(int fd,struct file *filp,int on)
{
return fasync_helper(fd,filp,on,&button_fasync);//初始化button_fasync这个结构体;


}


static unsigned key_poll(struct file *file, poll_table *wait)
{
unsigned int mask=0;
poll_wait(file,&key_qaq,wait);/*不会立即休眠,只是挂在那个队列上面去*/
if(wait_val)
mask |= POLLIN | POLLRDNORM;


return mask;
}


static struct file_operations key_fops =
{
.owner = THIS_MODULE,
.open = key_open,
.release = key_close,
.read = key_read,
.poll = key_poll,
.fasync = key_fasync,
};




static int __init key_fasync_init(void)
{
cdev_init(&cdev,&key_fops);
alloc_chrdev_region(&devno, 0 , 1 , "mykey_fasync");
cdev_add(&cdev, devno, 1);
my_class = class_create(THIS_MODULE, "key_fasync_class");
if(IS_ERR(my_class))
{
printk("Err: failed in creating class.\n");
return -1;
}
device_create(my_class, NULL, devno,NULL,"key_fasync_driver");
return 0;
}


static void key_fasync_exit(void)
{
device_destroy(my_class,devno);
class_destroy(my_class);
cdev_del(&cdev);
unregister_chrdev_region(devno,1);
}


module_init(key_fasync_init);
module_exit(key_fasync_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("EIGHT_FIVE");


测试程序如下:

#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<stdio.h>
#include<poll.h>
#include<signal.h>
#include<unistd.h>
#include<fcntl.h>
int fd;


void my_signal_func(int signum)
{
unsigned int key_val;


read(fd,&key_val,4);


printf("key_val = %d\n",key_val);
}
int main(int argc,char **argv)
{
signal(SIGIO,my_signal_func);
int flag;
fd=open("/dev/key_fasync_driver",O_RDWR);
if(fd<0)
{
printf("can't open!\n");
}

fcntl(fd,F_SETOWN,getpid());
flag=fcntl(fd,F_GETFL);


fcntl(fd,F_SETFL,flag | FASYNC);


while(1);
return 0;


}






按键驱动深化-异步通知机制

在以前的实验中获得按键值的方法有:
  • ychongx
  • ychongx
  • 2014年06月06日 22:16
  • 464

linux内核中异步通知机制--信号处理机制

什么是异步通知:很简单,一旦设备准备好,就主动通知应用程序,这种情况下应用程序就不需要查询设备状态, 特像硬件上常提的“中断的概念”。 比较准确的说法其实应该叫做“信号驱动的异步I/O”,信号是在软件...
  • yusiguyuan
  • yusiguyuan
  • 2014年04月08日 11:09
  • 4289

【Linux 驱动】异步通知机制

异步通知机制:一旦设备就绪,则主动通知应用程序,这样应用程序根本就不需要查询设备状态,是一种“信号驱动的异步I/O”。 信号是在软件层次上对中断机制的一种模拟,在原理上,一个进程收到一个信号与处理器...
  • yeswenqian
  • yeswenqian
  • 2015年12月16日 22:41
  • 1010

Tiny6410 + Linux2.6.38 按键驱动改写和说明

四个按键分别接在GPN11, GPL8, GPL9, GPL10
  • zgrjkflmkyc
  • zgrjkflmkyc
  • 2014年11月14日 16:45
  • 923

Linux驱动开发之八-----按键驱动(异步通知机制)

在Linux下,异步通知类似于信号机制,内核和应用程序之间采用通知方法来告知是否发生对应的事件,并进一步采取相应的动作,当产生按键动作时,发生中断,由驱动程序使用kill_fasync函数告知应用程序...
  • jefbai
  • jefbai
  • 2013年12月11日 23:50
  • 807

arm驱动linux异步通知与异步IO

《[ arm驱动] linux异步通知与 异步IO》涉及内核驱动函数二个,内核结构体一个,分析了内核驱动函数二个;可参考的相关应用程序模板或内核驱动模板二个,可参考的相关应用程序模板或内核驱动三个 ...
  • chinazhangzhong123
  • chinazhangzhong123
  • 2016年06月11日 23:59
  • 164

异步通知机制的总结

异步通知机制可以达到这样一个效果:应用程序不用主动查询,而是当事件发生时,驱动程序主动给应用程序发信号,然后应用程序再进行处理。要实现这一个目的,需要解决以下几个问题: ①注册信号处理函数 ②谁发...
  • guoguoguilai
  • guoguoguilai
  • 2017年02月05日 14:44
  • 70

异步消息处理机制总结(AsynTask和handler)

写了几篇博客,感觉挺充实的,虽然技术含量不高,其中错误肯定也不少,理解并不深入,但是也算是对自己学习一步一个脚印的交代,毕竟自己是一个本科大三狗,如果能坚持写写博客,研究下技术,将来也能增强 实力为自...
  • ayo464434914
  • ayo464434914
  • 2015年10月29日 20:47
  • 2734

USB 3.0规范中译本 第4章 超高速数据流模型

转自:http://www.cnblogs.com/coryxie/p/3956235.html 本文为CoryXie原创译文,转载及有任何问题请联系cory.xie#gmail.c...
  • bcs_01
  • bcs_01
  • 2016年10月31日 10:05
  • 906

设备驱动之异步通知机制

异步通知:意思就是,一旦设备就绪,则主动通知应用程序,这样应用程序根本不需要查询设备状态,非常类似于硬件上"中断的概念" 准确一点就叫:信号驱动(SIGIO)的异步I/O 实现异步通知,内核需要知道几...
  • mz454619501
  • mz454619501
  • 2014年12月03日 17:45
  • 477
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:基于异步通知机制的按键驱动
举报原因:
原因补充:

(最多只允许输入30个字)