Welcome 微信登录
编程资源 图片资源库 蚂蚁家优选 PDF转换器

首页 / 操作系统 / Linux / 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;elsereturn 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 ");return 0;}int simple_release(struct inode * pnode, struct file * pfile){printk(KERN_INFO "close simple ");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 ");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 ");}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");