Linux内核修炼之misc设备源码分析

====本文系本站原创,欢迎转载! 转载请注明出处:http://blog.csdn.net/yyplc==== 

前面分析了字符设备,接下来分析misc混杂设备。

混杂设备是字符设备的一种,算是字符设备的一种附加品吧。
混杂驱动程序是那些简单的字符驱动程序,它们拥有一些相同的特性。内核将这些性抽象至一个API中,这个API能简化驱动程序初始化的方式。所有的混杂设备的主设备号为10,每个设备可选择一个单独的次设备号。
混杂设备定义以下参数:
#define DYNAMIC_MINORS 64 /* like dynamic majors */
static unsigned char misc_minors[DYNAMIC_MINORS / 8];
说明可以动态分配64个次设备号(0~63)对应8组misc_minors[]。每组的位对应表示64个次设备号.
misc_minors[7]对应63,62,61,60,59,58,57,56 并且用misc_minors[7]的8位来标记:1表示已分配,0表是未分配
misc_minors[6]对应55,54,53,52,51,50,49,48 并且用misc_minors[6]的8位来标记:1表示已分配,0表是未分配
...
misc_minors[0]对应 7, 6, 5, 4, 3, 2, 1, 0 并且用misc_minors[0]的8位来标记:1表示已分配,0表示未分配
//内核初始化时,通过调用subsys_init()调用misc_init()形成misc子系统
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)) //根据主设备号10,注册字符设备
	goto fail_printk;
	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;
}
subsys_initcall(misc_init);   //系统在do_basic_setup()-->do_initcalls调用
分析一下miscdevice结构
struct miscdevice  {
	int minor;
	const char *name; //设备名
	const struct file_operations *fops; //操作函数
	struct list_head list;   //链表
	struct device *parent;   //指向父设备
	struct device *this_device;  //指向设备本身
};
//misc设备的注册API
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) { //如果minor已被分配,则退出
	mutex_unlock(&misc_mtx);
	return -EBUSY;
	}
}




	if (misc->minor == MISC_DYNAMIC_MINOR) { //如果是动态分配minor则找出minor为相应位为0的次设备号
		int i = DYNAMIC_MINORS;    
		while (--i >= 0)
			if ( (misc_minors[i>>3] & (1 << (i&7))) == 0)
			break;
			if (i<0) {
			mutex_unlock(&misc_mtx);
			return -EBUSY;
		}
		misc->minor = i;
	}




	if (misc->minor < DYNAMIC_MINORS) 
	misc_minors[misc->minor >> 3] |= 1 << (misc->minor & 7);  //相应位置位 
	dev = MKDEV(MISC_MAJOR, misc->minor);  //获取设备号(32位)




	misc->this_device = device_create(misc_class, misc->parent, dev, NULL,
				 "%s", misc->name);  //在/dev下生成设备节点
	if (IS_ERR(misc->this_device)) {
		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设备的注销API
int misc_deregister(struct miscdevice *misc)
{
	int i = misc->minor;




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




	mutex_lock(&misc_mtx);
	list_del(&misc->list);
	device_destroy(misc_class, MKDEV(MISC_MAJOR, misc->minor));
	if (i < DYNAMIC_MINORS && i>0) {
		misc_minors[i>>3] &= ~(1 << (misc->minor & 7)); //相应位复位
	}
	mutex_unlock(&misc_mtx);
	return 0;
}

测试例程:

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/list.h>
#include <asm/uaccess.h>
#include <linux/delay.h>
#include <linux/cdev.h>
#include <linux/miscdevice.h>

#define DEBUG
#ifdef DEBUG
#define dbg(fmt, arg...) printk(KERN_DEBUG "my_debug:%s," fmt "\n", __FUNCTION__, ##arg)
#else
#define dbg(fmt, arg...) (void)(0)
#endif

#define DEVICE_NAME "my_dev"

static int my_misc_open(struct inode *inode, struct file *filp)
{

	dbg("dev ok.");

	return 0;
}

static const struct file_operations my_fops = {
	.open = my_misc_open,
};

struct miscdevice my_dev = {
	.minor = MISC_DYNAMIC_MINOR,
	.name = DEVICE_NAME,
	.fops = &my_fops,
};

static int __init my_module_init(void)
{

	int ret;
	
	ret = misc_register(&my_dev);
	if (ret)
		dbg("misc_register error.");
	else
		dbg("misc_register ok.");

	return 0;
}

static void __exit my_module_exit(void)
{
	misc_deregister(&my_dev);
} 

module_init(my_module_init);
module_exit(my_module_exit);
MODULE_AUTHOR("itspy.wei<itspy.wei@gmail.com");
MODULE_DESCRIPTION("my_misc demo");
MODULE_LICENSE("GPL");

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值