免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 639 | 回复: 0
打印 上一主题 下一主题

设备驱动的异步通知实现 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2008-03-26 15:38 |只看该作者 |倒序浏览

设备驱动的异步通知实现
主要实现思路是:设备I/O驱动如果准备好数据(用户可读或者可写),向用户进程发送信号,用户进程收到信号后调用相关的信号处理函数对设备的数据进行访问。
实现上述的思路需要两方面的实现:用户程序的实现、设备驱动程序的实现。

用户程序的实现需要:
(1) 设置执行用户程序的PID作为设备文件的所有者。可通过下面语句实现:
fcntl(STDIN_FILENO, F_SETOWN, getpid(  ));
STDIN_FILENO这里是标准输入的文件描述符,我们可以重定向为设备的文件描述符。
F_SETOWN命令表示设置接收SIGIO或SIGURG信号的进程ID或者进程组ID。
(2) 用户程序必须对访问的设备文件设置FASYNC标志。可通过下面语句实现:
fcntl(STDIN_FILENO, F_SETFL, fcntl(STDIN_FILENO, F_GETFL) | FASYNC);
F_SETFL命令表示设置文件状态标志位(取第3个参数的值)

下面的例子来自于LDD3上的asynctest.c:
/*
* asynctest.c: use async notification to read stdin
*
* Copyright (C) 2001 Alessandro Rubini and Jonathan Corbet
* Copyright (C) 2001 O'Reilly & Associates
*
* The source code in this file can be freely used, adapted,
* and redistributed in source or binary form, so long as an
* acknowledgment appears in derived source files.  The citation
* should list that the code comes from the book "Linux Device
* Drivers" by Alessandro Rubini and Jonathan Corbet, published
* by O'Reilly & Associates.   No warranty is attached;
* we cannot take responsibility for errors or fitness for use.
*/

#include
#include
#include
#include
#include
#include

int gotdata=0; //全局flag,判断signal处理函数有没有执行;
void sighandler(int signo) //signal处理函数
{
    if (signo==SIGIO)
        gotdata++;
    return;
}

char buffer[4096]; //全局buffer

int main(int argc, char **argv)
{
    int count;
    struct sigaction action;

//初始化 action
    memset(&action, 0, sizeof(action));
    action.sa_handler = sighandler;
    action.sa_flags = 0;

    sigaction(SIGIO, &action, NULL);//绑定action到SIGIO signal

    fcntl(STDIN_FILENO, F_SETOWN, getpid());//设置STDIN_FILENOD的owner为当前进程
    fcntl(STDIN_FILENO, F_SETFL, fcntl(STDIN_FILENO, F_GETFL) | FASYNC);//设置STDIN_FILENO的文件状态标志(增加了FASYNC标志)。
    while(1) {
        /* this only returns if a signal arrives */
        sleep(86400); /* one day */
              //当SIGIO signal来了,会将当前进程从sleep唤醒
        if (!gotdata)
            continue;
        count=read(0, buffer, 4096);//从标准输入读数据
        /* buggy: if avail data is more than 4kbytes... */
        write(1,buffer,count);//向标准输出写数据
        gotdata=0;
    }
}

驱动程序的实现需要:
当用户程序操作时,从内核驱动的角度来看:
(1)    当用户程序调用F_SETOWN命令时(通过fnctl系统调用),所设置的值保存在了驱动程序中的filp->f_owner结构体。
(2)    当用户程序调用F_SETFL命令设置FASYNC标志时,驱动中的fasync方法相应的被调用。fasync方法的实现样例如下:
static int scull_p_fasync(int fd, struct file *filp, int mode)
{
        struct scull_pipe *dev = filp->private_data;

        return fasync_helper(fd, filp, mode, &dev->async_queue);//
}
(3)    当设备驱动准备好访问数据后,向所有注册异步通知的进程发送SIGIO信号。它的实现样例如下:
        if (dev->async_queue)
                kill_fasync(&dev->async_queue, SIGIO, POLL_IN);//POLL_IN指设备此时准备好供用户可读的数据;如果要对设备可写,这里应该用POLL_OUT
(4)    当设备文件被关闭时,应当将设备文件从内核维护的活动异步读列表中删掉。它的实现样例如下:
/* remove this filp from the asynchronously notified filp's */
scull_p_fasync(-1, filp, 0);





参考资料:
1.       LDD3------6.4 section: “asynchronous notification”
2.       Linux设备驱动开发详解“设备驱动的异步通知“一章
3.       APU(2rd)---3.14 section: “fcntl Function”


本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u/15620/showart_508872.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP