1. 程式人生 > >裝置驅動模型之:kobject,kset,ktype(二)

裝置驅動模型之: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;
}