Linux代码版本:linux3.0
开发板环境: tiny4412
导读:说起linux设备驱动,很容易想到一切皆文件的思想、bus、device、driver还有sysfs文件系统。说起总线又很容易想到platform、I2c、USB等等,device和driver都挂接在一种总线上,然后通过xxx_match函数进行匹配,各种书籍资料也更多的是介绍如果调用接口进行驱动开发,却很少谈及注册一个设备和驱动的时候都发生了什么,驱动和设备是如何匹配的,sys下的目录和文件是如何产生的。如果不去理解驱动内部的机制,那么就只能开发过一种驱动学会一种驱动框架,而这种积累方式未免会显得低效,时间长了不用还容易忘。当了解驱动模型的内部机制后,就会发现各种类型的驱动框架有很大相似性,即使要开发一种新的硬件的驱动,看一下代码很快就知道框架是怎样的。
一、kobject和kset
俗话说万丈高楼平地起,再高的大楼也是由砖和钢筋等基本材料堆积起来的,同样linux驱动模型也有自己的基本材料,那就是kobject和kset。sys下的每一个目录,都对应一个kobject,sys下的目录层次结构,其实也就是kobject的层次结构。而kset则是kobject的集合。
下面先看kobject和kset的结构体
struct kobject {
const char *name;
struct list_head entry;
struct kobject *parent;
struct kset *kset;
struct kobj_type *ktype;
struct sysfs_dirent *sd;
struct kref kref;
unsigned int state_initialized:1;
unsigned int state_in_sysfs:1;
unsigned int state_add_uevent_sent:1;
unsigned int state_remove_uevent_sent:1;
unsigned int uevent_suppress:1;
};
const char *name:
kobject 名称,当包含此kobject的内核对象被加入内核时,那么将会以这个name在sys建立一个目录。
struct list_head entry:
用于将一系列内核对象构成链表
struct kobject *parent:
指该kobject的上一层节点,在sys表现为上一层目录,用于表现层次关系
struct kset *kset:
前面说kset是一系列kobject的集合,该成员指向所属的kset
struct kobj_type *ktype:
该kobject对象的类型,不同的内核对象类型有不同的属性和操作函数如下面的device_type和kset_type,具体用途后面用到的时候再详说。
static struct kobj_type device_ktype = {
.release = device_release,
.sysfs_ops = &dev_sysfs_ops,
.namespace = device_namespace,
};
static struct kobj_type kset_ktype = {
.sysfs_ops = &kobj_sysfs_ops,
.release = kset_release,
};
struct sysfs_dirent *sd:
该kobject在sysfs中对应的目录目录实例
unsigned int state_initialized:
表示该内核对象是否初始化过,表示已经初始化,表示未初始化
unsigned int state_in_sysfs:
表示该kobject所代表的内核对象是否在sys中是否建立的目录
unsigned int state_add_uevent_sent:
unsigned int state_remove_uevent_sent
add和让remove事件的标志位
unsigned int uevent_suppress:
该kobject对象发生变化时,将会导致该对象所属的kset向用户空间发送event消息,uevent_suppress是用来表明当kobject状态发生变化时,是否允许ket向用户空间发送event消息。0表示允许,1表示不允许。
一般应用都是将kobject嵌入对象中,单独说kobject每个成员也很难理解,当kobject成员被使用时就容易理解其用途。其实kset也是一个嵌入了kobject的内核对象,是一个很好的例子。
struct kset {
struct list_head list;
spinlock_t list_lock;
struct kobject kobj;
const struct kset_uevent_ops *uevent_ops;
};
struct list_head list:
前面说了kset就是 kobject的集合,此成员就是要将kobject串起来(还记得kobject中的entry成员吗)
spinlock_t list_lock:
自旋锁,用来进行互斥访问
struct kobject kobj:
kset也是封装了kobject
const struct kset_uevent_ops *uevent_ops
当kset中的某些kobject成员状态发生变化需要通知用户空间时,调用其中的函数
struct kset_uevent_ops {
int (* const filter)(struct kset *kset, struct kobject *kobj);
const char *(* const name)(struct kset *kset, struct kobject *kobj);
int (* const uevent)(struct kset *kset, struct kobject *kobj,
struct kobj_uevent_env *env);
};
这三个函数将会在kobject_uevent中调用到,后面具体实例再分析。
二、kset和kobject实例
一块砖,怎么看也很难想象出来和高楼大厦有啥关系,可当你看着工人一块一块用起来就知道它的作用。对于kobject和kset做再详细的说明,也很难理解,当我们看到他们的每个成员在代码中的应用时,自然很容易理解其用途,所以对于kobject和kset结构体就知道它有些什么进行了,具体用途在代码中进行理解。
很多资料都会说sysfs是用户和内核空间的交互接口,kobject对应sys的一个目录(kset也是封装了一个kobject,kset对应的目录还是通过kobect实现),下面就看一下kset和kobject究竟是怎么对应的sys下的目录的。
先看下sys下的几个目录
[root@FriendlyARM /sys]# ls
block class devices fs module
bus dev firmware kernel power
下面是 创建这些目录的函数:
block:
sys目录下创建bolck目录
static int __init genhd_device_init(void)
{
......
block_depr = kobject_create_and_add("block", NULL);
......
}
class:
sys目录下创建class目录
int __init classes_init(void)
{
......
class_kset = kset_create_and_add("class", NULL, NULL);
......
}
devices 和dev:
在sys下创建了devices 和dev 目录,又在dev目录下创建了block和char两个目录
int __init devices_init(void)
{
......
devices_kset = kset_create_and_add("devices", &device_uevent_ops, NULL);
......
dev_kobj = kobject_create_and_add("dev", NULL);
sysfs_dev_block_kobj = kobject_create_and_add("block", dev_kobj);
sysfs_dev_char_kobj = kobject_create_and_add("char", dev_kobj);
}
fs:
sys目录下创建fs目录
void __init mnt_init(void)
{
......
fs_kobj = kobject_create_and_add("fs", NULL);
......
}
module:
在sys目录下创建module目录
static int __init param_sysfs_init(void)
{
......
module_kset = kset_create_and_add("module",
&module_uevent_ops, NULL);
......
}
bus
在sys目录下创建bus目录
int __init buses_init(void)
{
......
bus_kset = kset_create_and_add("bus", &bus_uevent_ops, NULL);
......
}
firmware:
sys目录下创建firmware目录
int __init firmware_init(void)
{
......
firmware_kobj = kobject_create_and_add("firmware", NULL);
......
}
kernel:
sys目录下创建kernel目录
static int __init ksysfs_init(void)
{
......
kernel_kobj = kobject_create_and_add("kernel", NULL);
......
}
power:
sys目录下创建power目录
static int __init pm_init(void)
{
......
power_kobj = kobject_create_and_add("power", NULL);
......
}
从函数名字上也可以看出,class、devices、module和bus为kset,其它的为kobject。接下来先解析kset_create_and_add,第一个参数为name,第二个为kset_uevent_ops,第三个为parent_kobj,注意当parent_kobj为NULL时,则是在sys创建目录,后面从代码上看到;
struct kset *kset_create_and_add(const char *name,
const struct kset_uevent_ops *uevent_ops,
struct kobject *parent_kobj)
{
struct kset *kset;
int error;
/*创建一个kset并初始化*/
kset = kset_create(name, uevent_ops, parent_kobj);
if (!kset)
return NULL;
error = kset_register(kset);
if (error) {
kfree(kset);
return NULL;
}
return kset;
}
接下来看一下几个kset的kset_uevent_ops,class的为NULL,device_uevent_ops为device_uevent_ops,module的为module_uevent_ops,bus的为bus_uevent_ops
static const struct kset_uevent_ops device_uevent_ops = {
.filter = dev_uevent_filter,
.name = dev_uevent_name,
.uevent = dev_uevent,
};
static const struct kset_uevent_ops module_uevent_ops = {
.filter = uevent_filter,
};
static const struct kset_uevent_ops bus_uevent_ops = {
.filter = bus_uevent_filter,
};
再看filter成员
static int dev_uevent_filter(struct kset *kset, struct kobject *kobj)
{
struct kobj_type *ktype = get_ktype(kobj);
/*先判断是该kobject是不是device_type类型,再判断是否挂接在某个bus上或者是否属某个class*/
if (ktype == &device_ktype) {
struct device *dev = to_dev(kobj);
if (dev->bus)
return 1;
if (dev->class)
return 1;
}
return 0;
}
static int uevent_filter(struct kset *kset, struct kobject *kobj)
{
struct kobj_type *ktype = get_ktype(kobj);
/* 判断该kobject是否为module_ktype类型*/
if (ktype == &module_ktype)
return 1;
return 0;
}
static int bus_uevent_filter(struct kset *kset, struct kobject *kobj)
{
struct kobj_type *ktype = get_ktype(kobj);
/* 判断该kobject是否为bus_ktype类型*/
if (ktype == &bus_ktype)
return 1;
return 0;
}
filter 的作用就是检查某些条件,除了devices的要求kobject的type,挂接在某个bus或某个class上,其它两个都只检查kobject的type,符合要求才允许上报。
再看dev_uevent_name,就是返回所指向bus或class的name
devices_kset = kset_create_and_add("devices", &device_uevent_ops, NULL);
struct kset *kset_create_and_add(const char *name,
const struct kset_uevent_ops *uevent_ops,
struct kobject *parent_kobj)
{
struct kset *kset;
int error;
/*创建一个kset*/
kset = kset_create(name, uevent_ops, parent_kobj);
{
struct kset *kset;
int retval;
/*先为kset申请内存*/
kset = kzalloc(sizeof(*kset), GFP_KERNEL);
if (!kset)
return NULL;
/*设置kobject名字,kset->kobj->name = “devices”*/
retval = kobject_set_name(&kset->kobj, name);
if (retval) {
kfree(kset);
return NULL;
}
/*kset->uevent_ops = device_uevent_ops*/
kset->uevent_ops = uevent_ops;
/*kset->kobj.parent = NULL*/
kset->kobj.parent = parent_kobj;
/*
* The kobject of this kset will have a type of kset_ktype and belong to
* no kset itself. That way we can properly free it when it is
* finished being used.
*/
kset->kobj.ktype = &kset_ktype;
kset->kobj.kset = NULL;
return kset;
}
if (!kset)
return NULL;
/*注册kset*/
error = kset_register(kset);
{
int err;
if (!k)
return -EINVAL;
/*初始化kset*/
kset_init(k);
{
kobject_init_internal(&k->kobj);
{
if (!kobj)
return;
/*引用计数初始化为1*/
kref_init(&kobj->kref);
/*list初始化*/
INIT_LIST_HEAD(&kobj->entry);
/*还未在sysfs中创建目录*/
kobj->state_in_sysfs = 0;
kobj->state_add_uevent_sent = 0;
kobj->state_remove_uevent_sent = 0;
/*已经初始化*/
kobj->state_initialized = 1;
}
INIT_LIST_HEAD(&k->list);
spin_lock_init(&k->list_lock);
}
err = kobject_add_internal(&k->kobj);
{
int error = 0;
struct kobject *parent;
if (!kobj)
return -ENOENT;
/*初始化时设置为 kobj->name = “devices”*/
if (!kobj->name || !kobj->name[0]) {
WARN(1, "kobject: (%p): attempted to be registered with empty "
"name!
", kobj);
return -EINVAL;
}
/*获取kobj的parent,前面初始化时设置为kset->kobj.parent = NULL*/
parent = kobject_get(kobj->parent);
/* join kset if set, use it as parent if we do not already have one */
/* 前面初始设置为kset->kobj.kset = NULL */
if (kobj->kset) {
if (!parent)
/*如果kobj有kset但没有parent,则将kset所谓parent*/
parent = kobject_get(&kobj->kset->kobj);
/*将kobj键入kset->list中*/
kobj_kset_join(kobj);
{
if (!kobj->kset)
return;
kset_get(kobj->kset);
spin_lock(&kobj->kset->list_lock);
list_add_tail(&kobj->entry, &kobj->kset->list);
spin_unlock(&kobj->kset->list_lock);
}
kobj->parent = parent;
}
pr_debug("kobject: '%s' (%p): %s: parent: '%s', set: '%s'
",
kobject_name(kobj), kobj, __func__,
parent ? kobject_name(parent) : "",
kobj->kset ? kobject_name(&kobj->kset->kobj) : "");
/*在sys下创建devices目录*/
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.
",
__func__, kobject_name(kobj));
else
printk(KERN_ERR "%s failed for %s (%d)
",
__func__, kobject_name(kobj), error);
dump_stack();
} else
/*已在sys创建devices目录,将标记置1*/
kobj->state_in_sysfs = 1;
return error;
}
if (err)
return err;
kobject_uevent(&k->kobj, KOBJ_ADD);
{
return kobject_uevent_env(kobj, action, NULL);
{
struct kobj_uevent_env *env;
const char *action_string = kobject_actions[action];
const char *devpath = NULL;
const char *subsystem;
struct kobject *top_kobj;
struct kset *kset;
const struct kset_uevent_ops *uevent_ops;
int i = 0;
int retval = 0;
#ifdef CONFIG_NET
struct uevent_sock *ue_sk;
#endif
pr_debug("kobject: '%s' (%p): %s
",
kobject_name(kobj), kobj, __func__);
/* search the kset we belong to */
/*查找kobj所属的kset,看前面kset->kobj.kset = NULL,kset->kobj->parent = NULL*/
top_kobj = kobj;
while (!top_kobj->kset && top_kobj->parent)
top_kobj = top_kobj->parent;
if (!top_kobj->kset) {
pr_debug("kobject: '%s' (%p): %s: attempted to send uevent "
"without kset!
", kobject_name(kobj), kobj,
__func__);
return -EINVAL;
}
/*kset = NULL*/
kset = top_kobj->kset;
uevent_ops = kset->uevent_ops;
/* skip the event, if uevent_suppress is set*/
/*如果被置1,不报uevent,看前面的代码,此位并没有被置位*/
if (kobj->uevent_suppress) {
pr_debug("kobject: '%s' (%p): %s: uevent_suppress "
"caused the event to drop!
",
kobject_name(kobj), kobj, __func__);
return 0;
}
/* skip the event, if the filter returns zero. */
/*kset->uevent_ops在此有用了,但kset->kobj.kset = NULL ,函数在此返回*/
if (uevent_ops && uevent_ops->filter)
if (!uevent_ops->filter(kset, kobj)) {
pr_debug("kobject: '%s' (%p): %s: filter function "
"caused the event to drop!
",
kobject_name(kobj), kobj, __func__);
return 0;
}
/*下面的代码将在以后能执行至此的实例中分析*/
/* originating subsystem */
............
}
return 0;
}
if (error) {
kfree(kset);
return NULL;
}
return kset;
}
/*创建一个kset*/
kset = kset_create(name, uevent_ops, parent_kobj);
{
struct kset *kset;
int retval;
/*先为kset申请内存*/
kset = kzalloc(sizeof(*kset), GFP_KERNEL);
if (!kset)
return NULL;
/*设置kobject名字,kset->kobj->name = “devices”*/
retval = kobject_set_name(&kset->kobj, name);
if (retval) {
kfree(kset);
return NULL;
}
/*kset->uevent_ops = device_uevent_ops*/
kset->uevent_ops = uevent_ops;
/*kset->kobj.parent = NULL*/
kset->kobj.parent = parent_kobj;
/*
* The kobject of this kset will have a type of kset_ktype and belong to
* no kset itself. That way we can properly free it when it is
* finished being used.
*/
kset->kobj.ktype = &kset_ktype;
kset->kobj.kset = NULL;
return kset;
}
if (!kset)
return NULL;
/*注册kset*/
error = kset_register(kset);
{
int err;
if (!k)
return -EINVAL;
/*初始化kset*/
kset_init(k);
{
kobject_init_internal(&k->kobj);
{
if (!kobj)
return;
/*引用计数初始化为1*/
kref_init(&kobj->kref);
/*list初始化*/
INIT_LIST_HEAD(&kobj->entry);
/*还未在sysfs中创建目录*/
kobj->state_in_sysfs = 0;
kobj->state_add_uevent_sent = 0;
kobj->state_remove_uevent_sent = 0;
/*已经初始化*/
kobj->state_initialized = 1;
}
INIT_LIST_HEAD(&k->list);
spin_lock_init(&k->list_lock);
}
err = kobject_add_internal(&k->kobj);
{
int error = 0;
struct kobject *parent;
if (!kobj)
return -ENOENT;
/*初始化时设置为 kobj->name = “devices”*/
if (!kobj->name || !kobj->name[0]) {
WARN(1, "kobject: (%p): attempted to be registered with empty "
"name!
", kobj);
return -EINVAL;
}
/*获取kobj的parent,前面初始化时设置为kset->kobj.parent = NULL*/
parent = kobject_get(kobj->parent);
/* join kset if set, use it as parent if we do not already have one */
/* 前面初始设置为kset->kobj.kset = NULL */
if (kobj->kset) {
if (!parent)
/*如果kobj有kset但没有parent,则将kset所谓parent*/
parent = kobject_get(&kobj->kset->kobj);
/*将kobj键入kset->list中*/
kobj_kset_join(kobj);
{
if (!kobj->kset)
return;
kset_get(kobj->kset);
spin_lock(&kobj->kset->list_lock);
list_add_tail(&kobj->entry, &kobj->kset->list);
spin_unlock(&kobj->kset->list_lock);
}
kobj->parent = parent;
}
pr_debug("kobject: '%s' (%p): %s: parent: '%s', set: '%s'
",
kobject_name(kobj), kobj, __func__,
parent ? kobject_name(parent) : "",
kobj->kset ? kobject_name(&kobj->kset->kobj) : "");
/*在sys下创建devices目录*/
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.
",
__func__, kobject_name(kobj));
else
printk(KERN_ERR "%s failed for %s (%d)
",
__func__, kobject_name(kobj), error);
dump_stack();
} else
/*已在sys创建devices目录,将标记置1*/
kobj->state_in_sysfs = 1;
return error;
}
if (err)
return err;
kobject_uevent(&k->kobj, KOBJ_ADD);
{
return kobject_uevent_env(kobj, action, NULL);
{
struct kobj_uevent_env *env;
const char *action_string = kobject_actions[action];
const char *devpath = NULL;
const char *subsystem;
struct kobject *top_kobj;
struct kset *kset;
const struct kset_uevent_ops *uevent_ops;
int i = 0;
int retval = 0;
#ifdef CONFIG_NET
struct uevent_sock *ue_sk;
#endif
pr_debug("kobject: '%s' (%p): %s
",
kobject_name(kobj), kobj, __func__);
/* search the kset we belong to */
/*查找kobj所属的kset,看前面kset->kobj.kset = NULL,kset->kobj->parent = NULL*/
top_kobj = kobj;
while (!top_kobj->kset && top_kobj->parent)
top_kobj = top_kobj->parent;
if (!top_kobj->kset) {
pr_debug("kobject: '%s' (%p): %s: attempted to send uevent "
"without kset!
", kobject_name(kobj), kobj,
__func__);
return -EINVAL;
}
/*kset = NULL*/
kset = top_kobj->kset;
uevent_ops = kset->uevent_ops;
/* skip the event, if uevent_suppress is set*/
/*如果被置1,不报uevent,看前面的代码,此位并没有被置位*/
if (kobj->uevent_suppress) {
pr_debug("kobject: '%s' (%p): %s: uevent_suppress "
"caused the event to drop!
",
kobject_name(kobj), kobj, __func__);
return 0;
}
/* skip the event, if the filter returns zero. */
/*kset->uevent_ops在此有用了,但kset->kobj.kset = NULL ,函数在此返回*/
if (uevent_ops && uevent_ops->filter)
if (!uevent_ops->filter(kset, kobj)) {
pr_debug("kobject: '%s' (%p): %s: filter function "
"caused the event to drop!
",
kobject_name(kobj), kobj, __func__);
return 0;
}
/*下面的代码将在以后能执行至此的实例中分析*/
/* originating subsystem */
............
}
return 0;
}
if (error) {
kfree(kset);
return NULL;
}
return kset;
}
对于kobject,以firmware为例
firmware_kobj = kobject_create_and_add("firmware", NULL);
{
struct kobject *kobj;
int retval;
/*创建kobj*/
kobj = kobject_create();
{
struct kobject *kobj;
/*为kobj申请内存*/
kobj = kzalloc(sizeof(*kobj), GFP_KERNEL);
if (!kobj)
return NULL;
/*初始化kobj*/
kobject_init(kobj, &dynamic_kobj_ktype);
{
char *err_str;
if (!kobj) {
err_str = "invalid kobject pointer!";
goto error;
}
/*kobj 必须有ktype,此例为dynamic_kobj_ktype*/
if (!ktype) {
err_str = "must have a ktype to be initialized properly!
";
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.
", kobj);
dump_stack();
}
kobject_init_internal(kobj);
{
if (!kobj)
return;
/*引用计数初始化为1*/
kref_init(&kobj->kref);
/*list初始化*/
INIT_LIST_HEAD(&kobj->entry);
/*还未在sysfs中创建目录*/
kobj->state_in_sysfs = 0;
kobj->state_add_uevent_sent = 0;
kobj->state_remove_uevent_sent = 0;
/*初始化标志置1*/
kobj->state_initialized = 1;
}
/*kobj->ktype = dynamic_kobj_ktype*/
kobj->ktype = ktype;
return;
error:
printk(KERN_ERR "kobject (%p): %s
", kobj, err_str);
dump_stack();
}
return kobj;
}
if (!kobj)
return NULL;
retval = kobject_add(kobj, parent, "%s", name);
{
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.
",
kobject_name(kobj), kobj);
dump_stack();
return -EINVAL;
}
va_start(args, fmt);
retval = kobject_add_varg(kobj, parent, fmt, args);
{
int retval;
/*设置kobj->name = “firmware”*/
retval = kobject_set_name_vargs(kobj, fmt, vargs);
if (retval) {
printk(KERN_ERR "kobject: can not set name properly!
");
return retval;
}
/*设置kobj->parent = NULL*/
kobj->parent = parent;
/*又是kobject_add_internal,是不是很熟悉,创建kset也走这个函数*/
return kobject_add_internal(kobj);
{
int error = 0;
struct kobject *parent;
if (!kobj)
return -ENOENT;
/* kobj->name = “firmware”*/
if (!kobj->name || !kobj->name[0]) {
WARN(1, "kobject: (%p): attempted to be registered with empty "
"name!
", kobj);
return -EINVAL;
}
/*获取kobj的patent,前面初始化时设置为kobj.parent = NULL*/
parent = kobject_get(kobj->parent);
/* join kset if set, use it as parent if we do not already have one */
/* 前面未初始kobj.kset则为NULL */
if (kobj->kset) {
if (!parent)
/*如果kobj有kset但没有parent,则将kset所谓parent*/
parent = kobject_get(&kobj->kset->kobj);
/*将kobj键入kset->list中*/
kobj_kset_join(kobj);
{
if (!kobj->kset)
return;
kset_get(kobj->kset);
spin_lock(&kobj->kset->list_lock);
list_add_tail(&kobj->entry, &kobj->kset->list);
spin_unlock(&kobj->kset->list_lock);
}
kobj->parent = parent;
}
pr_debug("kobject: '%s' (%p): %s: parent: '%s', set: '%s'
",
kobject_name(kobj), kobj, __func__,
parent ? kobject_name(parent) : "",
kobj->kset ? kobject_name(&kobj->kset->kobj) : "");
/*在sys下创建firmware目录*/
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.
",
__func__, kobject_name(kobj));
else
printk(KERN_ERR "%s failed for %s (%d)
",
__func__, kobject_name(kobj), error);
dump_stack();
} else
/*已在sys创建firmware目录,将标记置1*/
kobj->state_in_sysfs = 1;
return error;
}
}
va_end(args);
return retval;
}
if (retval) {
printk(KERN_WARNING "%s: kobject_add error: %d
",
__func__, retval);
kobject_put(kobj);
kobj = NULL;
}
return kobj;
}
/*创建kobj*/
kobj = kobject_create();
{
struct kobject *kobj;
/*为kobj申请内存*/
kobj = kzalloc(sizeof(*kobj), GFP_KERNEL);
if (!kobj)
return NULL;
/*初始化kobj*/
kobject_init(kobj, &dynamic_kobj_ktype);
{
char *err_str;
if (!kobj) {
err_str = "invalid kobject pointer!";
goto error;
}
/*kobj 必须有ktype,此例为dynamic_kobj_ktype*/
if (!ktype) {
err_str = "must have a ktype to be initialized properly!
";
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.
", kobj);
dump_stack();
}
kobject_init_internal(kobj);
{
if (!kobj)
return;
/*引用计数初始化为1*/
kref_init(&kobj->kref);
/*list初始化*/
INIT_LIST_HEAD(&kobj->entry);
/*还未在sysfs中创建目录*/
kobj->state_in_sysfs = 0;
kobj->state_add_uevent_sent = 0;
kobj->state_remove_uevent_sent = 0;
/*初始化标志置1*/
kobj->state_initialized = 1;
}
/*kobj->ktype = dynamic_kobj_ktype*/
kobj->ktype = ktype;
return;
error:
printk(KERN_ERR "kobject (%p): %s
", kobj, err_str);
dump_stack();
}
return kobj;
}
if (!kobj)
return NULL;
retval = kobject_add(kobj, parent, "%s", name);
{
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.
",
kobject_name(kobj), kobj);
dump_stack();
return -EINVAL;
}
va_start(args, fmt);
retval = kobject_add_varg(kobj, parent, fmt, args);
{
int retval;
/*设置kobj->name = “firmware”*/
retval = kobject_set_name_vargs(kobj, fmt, vargs);
if (retval) {
printk(KERN_ERR "kobject: can not set name properly!
");
return retval;
}
/*设置kobj->parent = NULL*/
kobj->parent = parent;
/*又是kobject_add_internal,是不是很熟悉,创建kset也走这个函数*/
return kobject_add_internal(kobj);
{
int error = 0;
struct kobject *parent;
if (!kobj)
return -ENOENT;
/* kobj->name = “firmware”*/
if (!kobj->name || !kobj->name[0]) {
WARN(1, "kobject: (%p): attempted to be registered with empty "
"name!
", kobj);
return -EINVAL;
}
/*获取kobj的patent,前面初始化时设置为kobj.parent = NULL*/
parent = kobject_get(kobj->parent);
/* join kset if set, use it as parent if we do not already have one */
/* 前面未初始kobj.kset则为NULL */
if (kobj->kset) {
if (!parent)
/*如果kobj有kset但没有parent,则将kset所谓parent*/
parent = kobject_get(&kobj->kset->kobj);
/*将kobj键入kset->list中*/
kobj_kset_join(kobj);
{
if (!kobj->kset)
return;
kset_get(kobj->kset);
spin_lock(&kobj->kset->list_lock);
list_add_tail(&kobj->entry, &kobj->kset->list);
spin_unlock(&kobj->kset->list_lock);
}
kobj->parent = parent;
}
pr_debug("kobject: '%s' (%p): %s: parent: '%s', set: '%s'
",
kobject_name(kobj), kobj, __func__,
parent ? kobject_name(parent) : "",
kobj->kset ? kobject_name(&kobj->kset->kobj) : "");
/*在sys下创建firmware目录*/
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.
",
__func__, kobject_name(kobj));
else
printk(KERN_ERR "%s failed for %s (%d)
",
__func__, kobject_name(kobj), error);
dump_stack();
} else
/*已在sys创建firmware目录,将标记置1*/
kobj->state_in_sysfs = 1;
return error;
}
}
va_end(args);
return retval;
}
if (retval) {
printk(KERN_WARNING "%s: kobject_add error: %d
",
__func__, retval);
kobject_put(kobj);
kobj = NULL;
}
return kobj;
}
所以,从上面 看出无论kset还是kobject,最终都是根据kobject在sys下面创建目录的,其它几个的目录创建过程类似。