linux misc混杂设备驱动

一. misc结构体

struct miscdevice  {
	int minor;		//次设备号
	const char *name;		//设备名
	const struct file_operations *fops;	//操作函数集
	struct list_head list;	//链表头
	struct device *parent;	//父设备设备文件
	struct device *this_device;	//设备文件
	const char *nodename;	//
	mode_t mode;		//
};

二. 设备号
    misc设备的主设备号为10

#define MISC_MAJOR		10

 

三. misc设备系统的初始化 misc_init

static int __init misc_init(void)
{
	int err;

#ifdef CONFIG_PROC_FS
	proc_create("misc", 0, NULL, &misc_proc_fops);
#endif
	misc_class = class_create(THIS_MODULE, "misc");	//创建目录"/sys/class/misc"
	err = PTR_ERR(misc_class);
	if (IS_ERR(misc_class))
		goto fail_remove;

	err = -EIO;
	if (register_chrdev(MISC_MAJOR,"misc",&misc_fops))	//注册为字符设备,捆绑操作函数集
		goto fail_printk;
	misc_class->devnode = misc_devnode;
	return 0;

fail_printk:
	printk("unable to get major %d for misc devices\n", MISC_MAJOR);
	class_destroy(misc_class);
fail_remove:
	remove_proc_entry("misc", NULL);
	return err;
}

再看一下register_chrdev

static inline int register_chrdev(unsigned int major, const char *name,const struct file_operations *fops)
{
	return __register_chrdev(major, 0, 256, name, fops);
}

这里直接根据主设备号创建256个设备,256=2^8,所以它是把所有的杂项设备都给注册成字符设备了
misc_fops作为这所有misc设备捆绑的操作函数集

static const struct file_operations misc_fops = {
	.owner		= THIS_MODULE,
	.open		= misc_open,
	.llseek		= noop_llseek,
};

在misc_open中,也就是我们打开misc设备的时候,misc_open方法会为我们捆绑自定义的操作函数集

static int misc_open(struct inode * inode, struct file * file)
{
	int minor = iminor(inode);		//根据设备节点获取次设备号
	struct miscdevice *c;
	int err = -ENODEV;
	const struct file_operations *old_fops, *new_fops = NULL;

	mutex_lock(&misc_mtx);
	
	list_for_each_entry(c, &misc_list, list) {	//遍历misc_list查看次设备是否注册(misc_list元素在设备注册时添加)
		if (c->minor == minor) {
			new_fops = fops_get(c->fops);	//获取自定义的操作函数集		
			break;
		}
	}
		
	if (!new_fops) {			//若找不到则再找一次,还不行error
		mutex_unlock(&misc_mtx);
		request_module("char-major-%d-%d", MISC_MAJOR, minor);
		mutex_lock(&misc_mtx);

		list_for_each_entry(c, &misc_list, list) {
			if (c->minor == minor) {
				new_fops = fops_get(c->fops);
				break;
			}
		}
		if (!new_fops)
			goto fail;
	}

	err = 0;
	old_fops = file->f_op;	//获取指向旧的设备操作函数集(misc_fops)指针
	file->f_op = new_fops;	//文件操作函数集指针指向新的操作函数集
	if (file->f_op->open) {	//若存在open方法
		file->private_data = c;
		err=file->f_op->open(inode,file);	//则调用其自定义的open方法
		if (err) {
			fops_put(file->f_op);
			file->f_op = fops_get(old_fops);
		}
	}
	fops_put(old_fops);	//释放旧的函数集指针
fail:
	mutex_unlock(&misc_mtx);
	return err;
}

四. misc设备注册 misc_register

int misc_register(struct miscdevice * misc)
{
	struct miscdevice *c;
	dev_t dev;
	int err = 0;

	INIT_LIST_HEAD(&misc->list);	//初始化链表头

	mutex_lock(&misc_mtx);
	list_for_each_entry(c, &misc_list, list) {	//遍历misc_list
		if (c->minor == misc->minor) {	//查看设备号是否被占用
			mutex_unlock(&misc_mtx);
			return -EBUSY;
		}
	}

	if (misc->minor == MISC_DYNAMIC_MINOR) {	//判断是否指定要动态分配次设备号
		int i = find_first_zero_bit(misc_minors, DYNAMIC_MINORS);	//查找可用次设备号
		if (i >= DYNAMIC_MINORS) {
			mutex_unlock(&misc_mtx);
			return -EBUSY;
		}
		misc->minor = DYNAMIC_MINORS - i - 1;	//分配次设备号	
		set_bit(i, misc_minors);		//设置占用标志位
	}

	dev = MKDEV(MISC_MAJOR, misc->minor);	//根据主次设备号获取设备号

	misc->this_device = device_create(misc_class, misc->parent, dev,misc, "%s", misc->name);	//添加设备文件"/dev/xxx"
	if (IS_ERR(misc->this_device)) {
		int i = DYNAMIC_MINORS - misc->minor - 1;
		if (i < DYNAMIC_MINORS && i >= 0)
			clear_bit(i, misc_minors);
		err = PTR_ERR(misc->this_device);
		goto out;
	}

	/*
	 * Add it to the front, so that later devices can "override"
	 * earlier defaults
	 */
	list_add(&misc->list, &misc_list);	//将设备链表头添加到misc_list中
 out:
	mutex_unlock(&misc_mtx);
	return err;
}

五. misc设备注销 misc_deregister

int misc_deregister(struct miscdevice *misc)
{
	int i = DYNAMIC_MINORS - misc->minor - 1;	//通过次设备号计算出位标志

	if (WARN_ON(list_empty(&misc->list)))
		return -EINVAL;

	mutex_lock(&misc_mtx);
	list_del(&misc->list);	//从misc_list删除设备链表头
	device_destroy(misc_class, MKDEV(MISC_MAJOR, misc->minor));	//删除设备节点
	if (i < DYNAMIC_MINORS && i >= 0)
		clear_bit(i, misc_minors);	//清除位标志
	mutex_unlock(&misc_mtx);
	return 0;
}

六. misc简单实例

#include <linux/fs.h>
#include <linux/module.h>
#include <linux/miscdevice.h>

static int test_open(struct inode * inode, struct file * filp)
{
	return 0;
}

static const struct file_operations test_fops = {
	.owner = THIS_MODULE,
	.open  = test_open,
};

static struct miscdevice misc_dev={
	.minor=MISC_DYNAMIC_MINOR,
	.name="misc_test",
	.fops=&test_fops
};

static int __init test_init(void)
{
	return misc_register(&misc_dev);
}

static void __exit  test_exit(void)
{
	misc_deregister(&misc_dev);
}

module_init(test_init);
module_exit(test_exit);
MODULE_LICENSE("GPL");

七. 查看misc信息的方法

加载模块后

lsmod |grep test
test                     829  0 
ls -l /dev/misc_test 
crw-rw---- 1 root root 10, 54 2012-12-18 10:28 /dev/misc_test
ls -l /sys/class/misc/ |grep misc_test
lrwxrwxrwx 1 root root 0 2012-12-18 10:33 misc_test -> ../../devices/virtual/misc/misc_test
cat /proc/misc |grep misc_test
 54 misc_test

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值