zerons's Blog

For The Dream

chanllenge 06 misc device

zerons posted @ 2014年12月21日 20:42 in chanllenge , 531 阅读

misc device 模块需要的东西比较少, 两个结构体和几个函数

struct miscdevice, stuct file_operations,

文件操作结构体一般填充前三个域

struct file_operations this_fops = {
        .owner = THIS_MODULE,
        .read  = this_read,
        .write = this_write,
        .llseek = this_lseek,
};

另外一个结构体

struct miscdevice this_miscdev = {
        .minor = MISC_DYNAMIC_MINOR,
        .name  = "this", /* 会出现在/dev 目录下 */
        .fops  = &this_fops,
};

在模块加载的时候应该调用misc_register, 退出时调用misc_deregister

#include <linux/module.h>
#include <linux/miscdevice.h>
#include <linux/fs.h>
#include <linux/types.h>
#include <linux/string.h>
#include <linux/uaccess.h>

static const char assigned_id[] = "************";
static const int len = 13;

static ssize_t task06_read(struct file *file, char __user *buf,
				size_t size, loff_t *offset)
{
	return simple_read_from_buffer(buf, size, offset, assigned_id, len);
}

static ssize_t task06_write(struct file *file, const char __user *buf,
				size_t size, loff_t *offset)
{
	char tmp[len];
	int ret;

	if (size != len-1)
		return -EINVAL;
	memset(tmp, '\0', len);
	ret = simple_write_to_buffer(tmp, len-1, offset, buf, size);
	if ((ret != len-1) || (strncmp(tmp, assigned_id, len)))
		return -EINVAL;

	return ret;
}

static loff_t task06_lseek(struct file *file, loff_t offset, int a)
{
	loff_t tmp;

	switch (a) {
	case SEEK_SET:
		file->f_pos = (offset < 0) ? 0 : offset;
		break;
	case SEEK_CUR:
	case SEEK_END:
		tmp = file->f_pos + offset;
		file->f_pos = (tmp < 0) ? 0 : tmp;
		break;
	default:
		break;
	}
	return file->f_pos;
}

struct file_operations task06_fops = {
	.owner		= THIS_MODULE,
	.read		= task06_read,
	.write		= task06_write,
/*	.llseek		= task06_lseek, */
};

struct miscdevice task06_miscdev = {
	.minor		= MISC_DYNAMIC_MINOR,
	.name		= "eudyptula",
	.fops		= &task06_fops,
};

static int task06_init(void)
{
	int err;

	err = misc_register(&task06_miscdev);
	if (err)
		pr_info("register error");
	return err;
}

static void task06_exit(void)
{
	int err;

	err = misc_deregister(&task06_miscdev);
	if (err)
		pr_info("no need to deregister");
}

module_init(task06_init);
module_exit(task06_exit);

MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("task06");
MODULE_AUTHOR("************");

文件操作函数, read/write/llseek/

当对/dev/this 进行读写的时候, 会调用这三个函数,

ssize_t read(struct file *, char __user *, size_t, lofft_t *)

ssize_t write(struct file *, const char __user *, size_t, loff_t *)

lofft_t llseek(struct file *, lofft_t, int)

前两个函数用到用户空间数据, 因此可以调用copy_from_user, copy_to_user, simple_read_from_buffer, simple_write_to_buffer, 等来进行内核与用户空间的数据交换, 其中, 后面两个会调用前面两个函数.

*read和*write会对当前文件位置(loff_t *)进行操作 源文件在fs/read_write.c中. 所以在一个程序中对/dev/this进行读写操作, 应该处理文件位置, 或者:) 操作一次再重新打开


登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter