分享

linux字符设备驱动之异步通知

 nt_bookworm 2012-03-23
1、异步通知概念:
         一旦设备就绪则主动通知应用程序,比较准确的称谓是“信号驱动的异步I/O”.信号是软件层次上对中断机制的一种模拟。信号时一步的,一个进程不必通过任何操作来等待信号的到达,事实上,进程也不知道信号什么时候到达。

2、信号操作的关键:
                                    (1)、注册一个信号处理函数;
                                    (2)、谁发送此信号;
                                    (3)、把信号发给谁;
                                    (4)、怎么发该信号。

3、注册信号处理函数   
     void (*signal(int signum, void (*handler) (int) ) ) (int)
      分析此函数: 
                         (1)void (*handler) (int)   这是一个函数指针,指向的函数返回值为void,只有一个参数int
                         (2)signal(int signum, void (*handler) (int) )) 这是一个函数,有两个参数, 一个是int型,另一个是函数指针,  该函数指针指向的函数返回值为void,只有一个参数int;
                         (3)void (*signal(int signum, void (*handler) (int) ) ) (int),这样就可以看成是signal(int signum, void (*handler) (int) )) 函数执行之后,它的返回值是一个函数指针,这个函数指针指向参数为int型,返回值为void的函数。
                         (4)void (*signal(int signum, void (*handler) (int) ) ) (int)  使用typedef进行简化:
                                            typedef void (*HANDLER)(int);
                  HANDLER signal(int,HANDLER);

    使用例子:signal(SIGIO, my_signal_fun);这是一个注册或说设置对应信号的处理函数,SIGIO这是一个IO信号,my_signal_fun是要注册的处理信号。信号处理函数在应用程序中完成,此操作表示当应用程序接收到SIGIO信号时调用my_signal_fun函数进行处理,即在该进程内把信号和函数绑定。

 4、驱动程序发送信号
    以按键中断为例,当中断发生时,中断处理程序调用向应用程序发送信号。调用下面函数:
              kill_fasync (&button_async, SIGIO, POLL_IN); 
              button_async的定义:          
              static struct fasync_struct *button_async;

              struct fasync_struct {
                           int magic;
                           int fa_fd;
                           struct fasync_struct *fa_next;
                           struct file *fa_file;
                                   };  
                          
       对于struct fasync_struct这个数据结构在编写驱动时并不需要特别关注,它会由内核来维护,驱动程序中调用它即可。
       button_async该结构体变量用来区分方向,谁发送信号,由结构体中的int fa_fd变量确定;发送SIGIO信号,POLL_IN表示该信号可读。

 
 5、发信号发给应用程序
        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) {
                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;
}
 
         fcntl(fd, F_SETOWN, getpid());
fd为打开的该设备文件
 F_SETOWN设置设备文件的拥有者为本进程,这样从驱动发出的信号才能被本进程接收。  
                 getpid()获得本进程的PID
Oflags = fcntl(fd, F_GETFL); 
获得FASYNC标志位
fcntl(fd, F_SETFL, Oflags | FASYNC);      
                       更改FASYNC标志位调用fasync_helper函数启动异步通知机制。

6、总结               
                                  驱动程序

static int fifth_drv_fasync (int fd, struct file *filp, int on)
{
printk("driver: fifth_drv_fasync\n");
return fasync_helper (fd, filp, on, &button_async);
}

static struct file_operations sencod_drv_fops = {
    .owner   =  THIS_MODULE,    /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */
    .open    =  fifth_drv_open,     
.read = fifth_drv_read,   
.release =  fifth_drv_close,
.poll    =  fifth_drv_poll,
.fasync =  fifth_drv_fasync,
};
       
1、编写.fasync函数,给启动异步通知机制时调用
2、中断发生时调用发送信号函数kill_fasync (&button_async, SIGIO, POLL_IN);

                                   应用程序

1、signal(SIGIO, my_signal_fun);   //绑定信号与处理函数
2、fcntl(fd, F_SETOWN, getpid());  //告诉驱动该进程号,并设置设备文件只属于该进程
Oflags = fcntl(fd, F_GETFL);     //读取FASYNC标志位
fcntl(fd, F_SETFL, Oflags | FASYNC);  //更改标志位启动异步通知机制


框图: 
 

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多