====本文系本站原创,欢迎转载! 转载请注明出处: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");