linux驱动学习之异步通知
来源:互联网 发布:cyc指标源码dzh 编辑:程序博客网 时间:2024/05/16 23:39
http://blog.csdn.net/fontlose/article/details/8257201
异步通知是设备状态改变后主动通知应用程序,这样应用程序就不需要阻塞或查询设备了。应用通过信号来处理内核的异步通知,上次使用poll select来查询设备的可读状态,下面这个例子类似,不同的是当设备有数据时主动通知应用去读数据。
应用的C代码很简单,主要设置对信号的处理方式,内核有数据时会收到SIGIO信号,应用会自动调用signal设置的函数去读数据。
main.c
- #include <stdio.h>
- #include <fcntl.h>
- #include <signal.h>
- #include <stdlib.h>
- unsigned char rdBuf[1024];
- int fd;
- void hand_signal(int sign)
- {
- if(sign==SIGIO)
- {
- if (read(fd,rdBuf,1024)>0)
- printf("read data:%s\n",rdBuf);
- }
- }
- int main (int *argc,char**argv)
- {
- int fd,flags;
- /*处理SIGIO信号 驱动例子中收到数据时向应用发送的也是SIGIO信号*/
- signal(SIGIO,hand_signal);
- fd=open("/dev/moduledev60",O_RDWR);
- if(fd<0)
- {
- printf("open file error\n");
- return -1;
- }
- /*告诉驱动信号发送给谁 第三个参数传的是进程号*/
- fcntl(fd, F_SETOWN, getpid());
- /*设置FASYNC 执行后驱动的fasync方法被调用*/
- flags = fcntl(fd, F_GETFL);
- fcntl(fd, F_SETFL, flags | FASYNC);
- while(1);
- }
#include <stdio.h>#include <fcntl.h>#include <signal.h>#include <stdlib.h>unsigned char rdBuf[1024]; int fd;void hand_signal(int sign){ if(sign==SIGIO) { if (read(fd,rdBuf,1024)>0) printf("read data:%s\n",rdBuf); }}int main (int *argc,char**argv){ int fd,flags; /*处理SIGIO信号 驱动例子中收到数据时向应用发送的也是SIGIO信号*/ signal(SIGIO,hand_signal); fd=open("/dev/moduledev60",O_RDWR); if(fd<0) {printf("open file error\n");return -1; } /*告诉驱动信号发送给谁 第三个参数传的是进程号*/ fcntl(fd, F_SETOWN, getpid()); /*设置FASYNC 执行后驱动的fasync方法被调用*/ flags = fcntl(fd, F_GETFL); fcntl(fd, F_SETFL, flags | FASYNC); while(1);}
驱动主要代码,读操作只返回最后一次写入的字符串,写操作后向设置的进程发送SIGIO信号
- struct file_operations ops=
- {
- .owner=THIS_MODULE ,
- .read =fileops_read ,
- .write=fileops_write,
- .fasync=fileops_fasync,
- .close=fileops_release
- };
- int fileops_release(struct inode *inode,struct file *filp)
- {
- printk(KERN_ALERT "fileops_release\n");
- fileops_fasync(-1,filp,0); //第三个参数为0时,第一个参数未用,用来释放申请的内存
- return 0;
- }
- ssize_t fileops_read(struct file *filp, char __user *buff, size_t count, loff_t *offp)
- {
- unsigned int len;
- if(rdFlag==0) return 0;
- len=strlen(rdBuf);
- copy_to_user(buff,rdBuf,len);
- rdFlag=0;
- return len;
- }
- ssize_t fileops_write(struct file *filp, const char __user *buff, size_t count, loff_t *offp)
- {
- copy_from_user(rdBuf,buff,count);
- rdBuf[count]=0;
- rdFlag=1;
- kill_fasync(&fasync_queue,SIGIO ,POLL_IN); //有数据写入 向设置的进程发送SIGIO信号
- printk(KERN_ALERT "signal %d \n",SIGIO);
- return count;
- }
- int fileops_fasync (int fd, struct file *filp, int mode)
- {
- int res=fasync_helper(fd,filp,mode,&fasync_queue); //初始化fasync_queue
- printk(KERN_ALERT "filp %x\n",(int)filp);
- if(res<0) return res;
- else return 0;
- }
struct file_operations ops={ .owner=THIS_MODULE , .read =fileops_read , .write=fileops_write, .fasync=fileops_fasync, .close=fileops_release};int fileops_release(struct inode *inode,struct file *filp){ printk(KERN_ALERT "fileops_release\n"); fileops_fasync(-1,filp,0); //第三个参数为0时,第一个参数未用,用来释放申请的内存 return 0;}ssize_t fileops_read(struct file *filp, char __user *buff, size_t count, loff_t *offp){ unsigned int len; if(rdFlag==0) return 0; len=strlen(rdBuf); copy_to_user(buff,rdBuf,len); rdFlag=0; return len;}ssize_t fileops_write(struct file *filp, const char __user *buff, size_t count, loff_t *offp){ copy_from_user(rdBuf,buff,count); rdBuf[count]=0; rdFlag=1; kill_fasync(&fasync_queue,SIGIO ,POLL_IN); //有数据写入 向设置的进程发送SIGIO信号 printk(KERN_ALERT "signal %d \n",SIGIO); return count;}int fileops_fasync (int fd, struct file *filp, int mode){ int res=fasync_helper(fd,filp,mode,&fasync_queue); //初始化fasync_queue printk(KERN_ALERT "filp %x\n",(int)filp); if(res<0) return res; else return 0;}
测试结果
- 先编译加载驱动
- [root@localhost ctest]# insmod moddev.ko
- 运行应用
- [root@localhost ctest]# ./main 打开另一终端向设备写入数据
- [root@localhost ctest]# echo 111 > /dev/moduledev60
- 应用输出,每次数据写入数据后,驱动通知应用读取设备
- [root@localhost ctest]# ./main
- read data:111
先编译加载驱动[root@localhost ctest]# insmod moddev.ko运行应用[root@localhost ctest]# ./main 打开另一终端向设备写入数据[root@localhost ctest]# echo 111 > /dev/moduledev60应用输出,每次数据写入数据后,驱动通知应用读取设备[root@localhost ctest]# ./main read data:111
- 附fasync_helper源码
- /*
- * fasync_helper() is used by some character device drivers (mainly mice)
- * to set up the fasync queue. It returns negative on error, 0 if it did
- * no changes and positive if it added/deleted the entry.
- */
- int fasync_helper(int fd, struct file * filp, int on, struct fasync_struct **fapp)
- { /*这个函数维护一个线性表,用于创建和释放异步通知结构链表*/
- struct fasync_struct *fa, **fp;
- struct fasync_struct *new = NULL;
- int result = 0;
- if (on) {
- new = kmem_cache_alloc(fasync_cache, GFP_KERNEL); //申请异步通知结构变量
- if (!new)
- return -ENOMEM;
- }
- write_lock_irq(&fasync_lock);
- for (fp = fapp; (fa = *fp) != NULL; fp = &fa->fa_next) {
- if (fa->fa_file == filp) {
- if(on) {//已经存在filp节点
- fa->fa_fd = fd;
- kmem_cache_free(fasync_cache, new);
- } else {//释放找到的节点
- *fp = fa->fa_next;
- kmem_cache_free(fasync_cache, fa);
- result = 1;
- }
- goto out;
- }
- }
- if (on) {//将申请的节点加入链表
- new->magic = FASYNC_MAGIC;
- new->fa_file = filp;
- new->fa_fd = fd;
- new->fa_next = *fapp;
- *fapp = new;
- result = 1;
- }
- out:
- write_unlock_irq(&fasync_lock);
- return result;
- }
- Linux 设备驱动学习之 异步通知
- linux驱动学习之异步通知
- linux驱动学习之异步通知
- linux驱动学习之异步通知 .
- linux 驱动之异步通知
- linux驱动之异步通知
- 驱动学习 之 异步通知
- linux设备驱动开发学习之旅--异步通知
- Linux驱动学习10(异步通知 )
- Linux设备驱动编程之异步通知
- 嵌入式linux之按键驱动,异步通知
- Linux字符设备驱动之异步通知
- linux字符设备驱动之异步通知
- linux设备驱动之异步通知
- Linux设备驱动之异步通知
- Linux字符设备驱动之异步通知
- linux设备驱动之异步通知与异步I/O
- linux字符驱动之异步通知按键驱动
- loner_li windows 多线程实例 文件下载、面积计算、多线程下载等
- Linux设备驱动开发基础---Linux内核中断原理
- Linux 热插拔(Hot Plug)处理机制
- Silverlight实用窍门系列:75.Silverlight中DataGrid制作复杂表头
- Win7 删除wifi热点
- linux驱动学习之异步通知
- 向内存卡写入图片
- android之HttpURLConnection
- squid 的配置详解 (转)--SeriesIV
- hdu3630
- [求教]RewriteRule中的诡异现象
- DataTorrent 将数据分析速度从“实时”提升至“现在时”
- Ext.grid.GridPanel
- ruby methods block moudle 3