本帖最后由 yyplc 于 2012-4-23 21:17 编辑
前面分析了字符设备,接下来分析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;}
编写misc设备驱动很简单,主要调用misc 的API:
misc_regiseter(&);
misc_deregister(&); |