裝置驅動模型之:kobject,kset,ktype(二)
阿新 • • 發佈:2018-12-08
之前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;
}