歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> 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;
	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 [email protected]");
MODULE_DESCRIPTION("A simple linux kernel module");
MODULE_VERSION("V0.1");
MODULE_LICENSE("Dual BSD/GPL");
Copyright © Linux教程網 All Rights Reserved