设备驱动模型之:kobject,kset,ktype(二)

之前https://mp.csdn.net/mdeditor/84722837#这个博客里面介绍了关于kobject,set,ktype三个结构体之间的关系以及作用,可以做为参考,下面介绍一下这三个结构体相关的函数的使用以及作用;

static void kobject_init_internal(struct kobject *kobj)
{
        if (!kobj)
                return;
        kref_init(&kobj->kref);
        INIT_LIST_HEAD(&kobj->entry);
        kobj->state_in_sysfs = 0;
        kobj->state_add_uevent_sent = 0;
        kobj->state_remove_uevent_sent = 0;
        kobj->state_initialized = 1;
}

kobject_init_internetl函数介绍:

函数功能:
 	1. 初始化使用计数,使使用计数计为1;
 	2. 初始化链表操作
 函数参数:
	struct kobject * kobj,要初始化的对象;
void kobject_init(struct kobject *kobj, struct kobj_type *ktype)
{
        char *err_str;

        if (!kobj) {
                err_str = "invalid kobject pointer!";
                goto error;
        }
        if (!ktype) {
                err_str = "must have a ktype to be initialized properly!\n";
                goto error;
        }
        if (kobj->state_initialized) {
                /* do not error out as sometimes we can recover */
                printk(KERN_ERR "kobject (%p): tried to init an initialized "
                       "object, something is seriously wrong.\n", kobj);
                dump_stack();
        }

        kobject_init_internal(kobj);
        kobj->ktype = ktype;
        return;

error:
        printk(KERN_ERR "kobject (%p): %s\n", kobj, err_str);
        dump_stack();
}

kobj_init函数介绍如下:

函数参数:
 	struct kobject* kobj要初始化的kobject实例
 	struct kobj_type * ktype要初始化kobject是什么ktype,本函数中直接赋予kobj->ktype
函数功能:
	1.先判断kobject->state_initialized是否已经被初始化了,如果已经被初始化,则发生一个内核的panic
	2.(在kobject_init_internel中)初始化kobject实例,主要负责引用计数初始化以及kobject.entry链表初始化;然后把kobject->state_initialized置为1,表示已经被初始化了
	3.把ktype指针赋予kobj->ktype;

kobject_add函数如下:

int kobject_add(struct kobject *kobj, struct kobject *parent,
                const char *fmt, ...)
{
        va_list args;
        int retval;

        if (!kobj)
                return -EINVAL;

        if (!kobj->state_initialized) {
                printk(KERN_ERR "kobject '%s' (%p): tried to add an "
                       "uninitialized object, something is seriously wrong.\n",
                       kobject_name(kobj), kobj);
                dump_stack();
                return -EINVAL;
        }
        va_start(args, fmt);
        retval = kobject_add_varg(kobj, parent, fmt, args);
        va_end(args);

        return retval;
}

kobject_add函数介绍如下:

函数参数:
 	struct kobject* kboj要增加的kobject实例;
 	struct kobject* parent要增加的kobject的parent指针指向;
 	const char * fmt ,  va_list vargs;  要增加的kobject名字;
函数功能:
	1.先判断kobj->state_initialized是否已经被初始化了,1表示已经初始化,0表示没有被初始化;
	2.把const char * fmt, va_list vargs组合成一个字符串,并且把kobject->name指向这个字符串;
	3.如果kobject->kset!= NULL,在kset目录下创建kobject->name文件夹;如果为空,则在/sys/目录下创建文件夹;
	4.在kobject->name目录下创建kobject->ktype->default_attrs文件;
	其中3.4步骤交与kobject_add_vargs和kobject_add_internel函数;

kobject_add_vargs和kobect_add_internel函数原型如下:

static int kobject_add_varg(struct kobject *kobj, struct kobject *parent,
                            const char *fmt, va_list vargs)
{
        int retval;
	/**kobj->name赋予名字*/
        retval = kobject_set_name_vargs(kobj, fmt, vargs);
        if (retval) {
                printk(KERN_ERR "kobject: can not set name properly!\n");
                return retval;
        }
        kobj->parent = parent;//把kobj->parent赋予parent指针
        return kobject_add_internal(kobj);//增加文件以及文件夹;
}


static int kobject_add_internal(struct kobject *kobj)
{
        int error = 0;
        struct kobject *parent;

        if (!kobj)
                return -ENOENT;

        if (!kobj->name || !kobj->name[0]) {
                WARN(1, "kobject: (%p): attempted to be registered with empty "
                         "name!\n", kobj);
                return -EINVAL;
        }
	//增加parent的引用计数
        parent = kobject_get(kobj->parent);

        /* join kset if set, use it as parent if we do not already have one */
        if (kobj->kset) {
                if (!parent)
                        parent = kobject_get(&kobj->kset->kobj);
                kobj_kset_join(kobj);
                kobj->parent = parent;
        }

        pr_debug("kobject: '%s' (%p): %s: parent: '%s', set: '%s'\n",
                 kobject_name(kobj), kobj, __func__,
                 parent ? kobject_name(parent) : "<NULL>",
                 kobj->kset ? kobject_name(&kobj->kset->kobj) : "<NULL>");

        error = create_dir(kobj);
        if (error) {
                kobj_kset_leave(kobj);
                kobject_put(parent);
                kobj->parent = NULL;

                /* be noisy on error issues */
                if (error == -EEXIST)
                        printk(KERN_ERR "%s failed for %s with "
                               "-EEXIST, don't try to register things with "
                               "the same name in the same directory.\n",
                               __func__, kobject_name(kobj));
                else
                        printk(KERN_ERR "%s failed for %s (%d)\n",
                               __func__, kobject_name(kobj), error);
                dump_stack();
        } else
                kobj->state_in_sysfs = 1;
         return error;}

以上操作全是对于struct kobject函数增加到内核里面的操作,总体概括如下:

 1. kobject_init可以初始化一个Kobject,主要初始化kref,entry(链表操作),state_initialized。没有对于/sys/文件夹做任何操作;
 2. kobject_add主要是对于/sys/文件夹下的操作以及kobject->parent逻辑关系还有kobject->name的操作;
 3. 以上操作可以总结,先使用kobject_init初始化再使用kobject_add函数增加逻辑关系(kset,parent)和向用户空间增加文件操作;
 4. 第三条操作可以使用kobject_create_and_add一条增加;

对于以上操作的逆操作可以使用kobject_del函数和kobject_put共同完成,原型如下:
注意:如果只使用kobject_del函数来释放,可能会有问题,因为初始化的时候对于kobject->kref有置1操作,所有需要使用kobject_put来完成对于kobject的释放操作,这样kobject才会释放完成;

void kobject_del(struct kobject *kobj)
{
        if (!kobj)
                return;
	/***移除文件/sys/xxxx
	设置state_in_sysfs为0,
	**/
        sysfs_remove_dir(kobj);
        kobj->state_in_sysfs = 0;
        kobj_kset_leave(kobj);
        kobject_put(kobj->parent);
        kobj->parent = NULL;
}

猜你喜欢

转载自blog.csdn.net/weixin_37867857/article/details/84727652