linux駆動学習の非同期通知

8428 ワード

http://blog.csdn.net/fontlose/article/details/8257201
   非同期通知は、デバイスのステータスが変更された後にアプリケーションにアクティブに通知することであり、アプリケーションがデバイスをブロックしたりクエリーしたりする必要はありません.カーネルの非同期通知を信号で処理し、poll selectを最後に使用してデバイスの読み取り可能な状態を問合せた場合、以下の例は同様であり、デバイスにデータがある場合、アプリケーションにデータの読み取りをアクティブに通知するのとは異なる.
    アプリケーションのCコードは簡単で、主に信号の処理方式を設定して、カーネルはデータがある時SIGIO信号を受け取って、アプリケーションは自動的にsignal設定の関数を呼び出してデータを読みます.
 main.c
[cpp] view plain copy print ?
#include    
  • #include    

  • #include    
  • #include    

  • unsigned char rdBuf[1024];    
  • int fd;  

  • void hand_signal(int sign)  
  • {  

  •    if(sign==SIGIO)  
  •    {  

  •      if (read(fd,rdBuf,1024)>0)      
  •        printf("read data:%s",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");      

  •     return -1;  
  •     }  

  •   
  •     /*ドライバ信号が誰に送信されるかを伝える 3番目のパラメータはプロセス番号*/です.  

  •     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
    ",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
    "); return -1;     }     /* */ fcntl(fd, F_SETOWN, getpid());         /* FASYNC fasync */ flags = fcntl(fd, F_GETFL); fcntl(fd, F_SETFL, flags | FASYNC);     while(1); }

    プライマリコードを駆動し、読み取り操作は最後に書き込まれた文字列のみを返し、書き込み操作後に設定されたプロセスにSIGIO信号を送信する
    [cpp] view plain copy print ?
    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");  
  •   fileops_fasync(-1,filp,0);            //3番目のパラメータが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 ",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",(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
    ");   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
    ",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
    ",(int)filp);    if(res<0) return res;    else return 0; }

    テスト結果
    [plain] view plain copy print ?
    プリコンパイルロードドライバ  
  • [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

     
    [cpp] view plain copy print ?
    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;  

  • }