您的位置:首页 > 运维架构 > Linux

[linux-kernel] 实现支持poll的驱动设备

2013-01-01 22:03 411 查看



作者:董昊 (要转载的同学帮忙把名字和博客链接http://donghao.org/uii/带上,多谢了!)

ldd3上已经讲了如何开发linux下的驱动程序,怎么让该设备支持poll(和epoll),但是不够详细,这里给个例子。假设实现一个misc设备,为了实现poll,当然要有个wait_queue,注意,是dev带wait_queue,我一疏忽把wait_queue带到file上去了,调了半天才发现这个低级错误。

struct sample_dev

{

struct miscdevice misc;

wait_queue_head_t wait;

};

static struct sample_dev s_dev;

s_dev这个设备现在既可以当miscdevice用,同时又有了wait_queue

struct file_operations sample_fops =

{

.owner = THIS_MODULE,

.read = sample_read,

.write = sample_write,

.poll = sample_poll,

};

static int __init init_sample(void)

{

s_dev.misc.minor = MISC_DYNAMIC_MINOR;

s_dev.misc.name = "poll_device_sample";

s_dev.misc.fops = &sample_fops;

init_waitqueue_head(&s_dev.wait);

return misc_register(&s_dev.misc);

}

static void __exit exit_sample(void)

{

misc_unregister(&s_dev.misc);

}

这是设备的注册和注销。下面看sample_poll的做法,和ldd3上说的一样:

unsigned int sample_poll(struct file* file, poll_table* wait)

{

unsigned int mask = 0;

poll_wait(file, &s_dev.wait, wait);

/* if have something to read (代码省略)*/

mask |= POLLIN;

/* if have something to write (代码省略)*/

mask |= POLLOUT;

/* if some error occur (代码省略)*/

mask |= POLLERR;

return mask;

}

poll_wait是linux内核提供的,标准做法,所以最好这么用。在poll_wait里,current进程挂在了s_dev的wait_queue里,只有两种情况让他醒来:一个是poll系统调用超时(poll_table负责),另一个是读写唤醒他(后面的代码)。

sszie_t sample_read(struct file* file, char __user* buff, loff_t* pos)

{

/* do what you want to read(代码省略)*/

wake_up_interruptible(&s_dev.wait);

}

由于读走了一些数据,缓冲区(代码没有详细写)有位置了,可以往里面写了,上面标红的行便唤醒随眠的进程,他(进程)醒来后就到了poll_wait语句的后面,开始查看缓冲区并置mask,最后返回。sample_write也是同样的实现方式。

以上代码只是例子,并不完整,但原理已经充分。这样实现的设备已经可以支持poll和epoll调用,当然,epoll的原理更为复杂,和上面说的过程有一些差异,详情可以参考这里
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: