linux驱动学习之异步通知

来源:互联网 发布:cyc指标源码dzh 编辑:程序博客网 时间:2024/05/16 23:39

http://blog.csdn.net/fontlose/article/details/8257201

   异步通知是设备状态改变后主动通知应用程序,这样应用程序就不需要阻塞或查询设备了。应用通过信号来处理内核的异步通知,上次使用poll select来查询设备的可读状态,下面这个例子类似,不同的是当设备有数据时主动通知应用去读数据。

    应用的C代码很简单,主要设置对信号的处理方式,内核有数据时会收到SIGIO信号,应用会自动调用signal设置的函数去读数据。


 main.c

[cpp] view plaincopyprint?
  1. #include <stdio.h>   
  2. #include <fcntl.h>   
  3. #include <signal.h>   
  4. #include <stdlib.h>   
  5. unsigned char rdBuf[1024];    
  6. int fd;  
  7. void hand_signal(int sign)  
  8. {  
  9.    if(sign==SIGIO)  
  10.    {  
  11.      if (read(fd,rdBuf,1024)>0)      
  12.        printf("read data:%s\n",rdBuf);    
  13.    }  
  14. }  
  15.   
  16.   
  17.   
  18. int main (int *argc,char**argv)  
  19. {  
  20.     int fd,flags;  
  21.     /*处理SIGIO信号 驱动例子中收到数据时向应用发送的也是SIGIO信号*/  
  22.     signal(SIGIO,hand_signal);  
  23.     fd=open("/dev/moduledev60",O_RDWR);  
  24.     if(fd<0)  
  25.     {  
  26.     printf("open file error\n");      
  27.     return -1;  
  28.     }  
  29.   
  30.     /*告诉驱动信号发送给谁 第三个参数传的是进程号*/  
  31.     fcntl(fd, F_SETOWN, getpid());  
  32.       
  33.     /*设置FASYNC 执行后驱动的fasync方法被调用*/  
  34.     flags = fcntl(fd, F_GETFL);  
  35.     fcntl(fd, F_SETFL, flags | FASYNC);  
  36.   
  37.     while(1);  
  38. }  



驱动主要代码,读操作只返回最后一次写入的字符串,写操作后向设置的进程发送SIGIO信号

[cpp] view plaincopyprint?
  1. struct file_operations ops=  
  2. {  
  3.    .owner=THIS_MODULE  ,  
  4.    .read =fileops_read ,  
  5.    .write=fileops_write,  
  6.    .fasync=fileops_fasync,     
  7.    .close=fileops_release  
  8. };  
  9.   
  10.   
  11. int fileops_release(struct inode *inode,struct file *filp)  
  12. {  
  13.   printk(KERN_ALERT "fileops_release\n");  
  14.   fileops_fasync(-1,filp,0);            //第三个参数为0时,第一个参数未用,用来释放申请的内存   
  15.   return 0;  
  16. }  
  17.   
  18. ssize_t fileops_read(struct file *filp, char __user *buff, size_t count, loff_t *offp)  
  19. {  
  20.   unsigned int len;  
  21.   if(rdFlag==0) return 0;    
  22.   len=strlen(rdBuf);  
  23.   copy_to_user(buff,rdBuf,len);  
  24.   rdFlag=0;  
  25.   return len;  
  26. }  
  27.   
  28. ssize_t fileops_write(struct file *filp, const char __user *buff, size_t count, loff_t *offp)  
  29. {  
  30.   copy_from_user(rdBuf,buff,count);  
  31.   rdBuf[count]=0;  
  32.   rdFlag=1;  
  33.   kill_fasync(&fasync_queue,SIGIO ,POLL_IN);  //有数据写入 向设置的进程发送SIGIO信号  
  34.   printk(KERN_ALERT "signal %d \n",SIGIO);  
  35.   return count;  
  36. }  
  37.   
  38. int fileops_fasync (int fd, struct file *filp, int mode)  
  39. {  
  40.    int res=fasync_helper(fd,filp,mode,&fasync_queue); //初始化fasync_queue  
  41.    printk(KERN_ALERT "filp %x\n",(int)filp);  
  42.    if(res<0) return res;  
  43.    else return 0;  
  44. }  


测试结果

[plain] view plaincopyprint?
  1. 先编译加载驱动  
  2. [root@localhost ctest]# insmod moddev.ko  
  3.   
  4. 运行应用  
  5. [root@localhost ctest]# ./main 打开另一终端向设备写入数据  
  6. [root@localhost ctest]# echo 111 > /dev/moduledev60  
  7. 应用输出,每次数据写入数据后,驱动通知应用读取设备  
  8. [root@localhost ctest]# ./main   
  9. read data:111  



 

[cpp] view plaincopyprint?
  1. 附fasync_helper源码  
  2. /* 
  3.  
  4.  * fasync_helper() is used by some character device drivers (mainly mice) 
  5.  * to set up the fasync queue. It returns negative on error, 0 if it did 
  6.  * no changes and positive if it added/deleted the entry. 
  7.  */  
  8. int fasync_helper(int fd, struct file * filp, int on, struct fasync_struct **fapp)  
  9. {       /*这个函数维护一个线性表,用于创建和释放异步通知结构链表*/  
  10.     struct fasync_struct *fa, **fp;  
  11.     struct fasync_struct *new = NULL;  
  12.     int result = 0;  
  13.   
  14.     if (on) {  
  15.         new = kmem_cache_alloc(fasync_cache, GFP_KERNEL); //申请异步通知结构变量  
  16.         if (!new)  
  17.             return -ENOMEM;  
  18.     }  
  19.     write_lock_irq(&fasync_lock);  
  20.     for (fp = fapp; (fa = *fp) != NULL; fp = &fa->fa_next) {  
  21.         if (fa->fa_file == filp) {  
  22.             if(on) {//已经存在filp节点  
  23.                 fa->fa_fd = fd;  
  24.                 kmem_cache_free(fasync_cache, new);  
  25.             } else {//释放找到的节点  
  26.                 *fp = fa->fa_next;  
  27.                 kmem_cache_free(fasync_cache, fa);  
  28.                 result = 1;  
  29.             }  
  30.             goto out;  
  31.         }  
  32.     }  
  33.   
  34.     if (on) {//将申请的节点加入链表  
  35.         new->magic = FASYNC_MAGIC;  
  36.         new->fa_file = filp;  
  37.         new->fa_fd = fd;  
  38.         new->fa_next = *fapp;  
  39.         *fapp = new;  
  40.         result = 1;  
  41.     }  
  42. out:  
  43.     write_unlock_irq(&fasync_lock);  
  44.     return result;  
  45. }