Linux 设备驱动轮询编程

Linux系统下网络模型数select最为常用,当然,select只是检测文件系统数据状态,并不只局限于网络编程,select的功能需要底层驱动提供支持,其中核心应用即为等待队列,其他模型,如poll和epoll,对驱动来说并无区别,驱动只是返回数据状态而已。驱动支持select,需要实现file_operations结构中的poll函数指针,其实现也非常简单,只是poll_wait函数的调用,原型如下:

unsigned int (*poll) (struct file *, struct poll_table_struct *); void poll_wait(struct file *filp, wait_queue_head_t *queue, poll_table * wait);

需要注意的是poll_wait函数不会像它名字一样处于wait状态,仅供上层查询之用。其编程基本框架也比较固定,现修改simple等待队列驱动之中如下:

unsigned int simple_poll (struct file * filp, struct poll_table_struct * wait) { unsigned int mask = 0; poll_wait(filp, &simple_queue, wait); if (len > 0) { mask |= POLLIN | POLLRDNORM; } return mask; }

在每次read之后都把len赋值为0,调用write把len赋值为数据长,poll中只需判断len,如果len大于0,则返回可读,整理之后,整个程序代码如下:

#include <linux/init.h> #include <linux/module.h> #include <linux/fs.h> #include <linux/types.h> #include <linux/cdev.h> #include <linux/mm.h> #include <linux/sched.h> #include <asm/io.h> #include <asm/uaccess.h> #include <asm/system.h> #include <linux/device.h> #include <linux/poll.h> dev_t devno; struct class * simple_class; static struct cdev cdev; wait_queue_head_t simple_queue; char test_data[255]; int len = 0; unsigned int simple_poll (struct file * filp, struct poll_table_struct * wait) { unsigned int mask = 0; poll_wait(filp, &simple_queue, wait); if (len > 0) { mask |= POLLIN | POLLRDNORM; } return mask; } ssize_t simple_read(struct file * pfile, char __user * buf, size_t size, loff_t * ppos) { int ret = len; len = 0; if (copy_to_user(buf, test_data, ret)) return -EFAULT; else return ret; } ssize_t simple_write(struct file * pfile, const char __user * buf, size_t count, loff_t * ppos) { if (count > 255) { return -EFAULT; } if (!copy_from_user(test_data, buf, count)) { len = count; wake_up(&simple_queue); } return len; } int simple_open(struct inode * pnode, struct file * pfile) { printk(KERN_INFO "open simple\n"); return 0; } int simple_release(struct inode * pnode, struct file * pfile) { printk(KERN_INFO "close simple\n"); return 0; } static struct file_operations simple_op = { .owner = THIS_MODULE, .read = simple_read, .open = simple_open, .release = simple_release, .write = simple_write, .poll = simple_poll, }; static int __init initialization(void) { int result; result = alloc_chrdev_region(&devno, 0, 1, "simple"); if (result < 0) return result; cdev_init(&cdev, &simple_op); result = cdev_add(&cdev, devno, 1); simple_class = class_create(THIS_MODULE, "simple"); device_create(simple_class, NULL, devno, NULL, "simple"); printk(KERN_INFO " init simple\n"); init_waitqueue_head(&simple_queue); return result; } static void __exit cleanup(void) { device_destroy(simple_class, devno); class_destroy(simple_class); cdev_del(&cdev); unregister_chrdev_region(devno, 1); printk(KERN_INFO " cleanup simple\n"); } module_init(initialization); module_exit(cleanup); MODULE_AUTHOR("alloc cppbreak@gmail.com"); MODULE_DESCRIPTION("A simple linux kernel module"); MODULE_VERSION("V0.1"); MODULE_LICENSE("Dual BSD/GPL");

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/efabf6e357527dde945becfe100a0775.html