kobject
来源:互联网 发布:罗马2 兵种数据修改 编辑:程序博客网 时间:2024/06/10 01:34
核心结论:
1、sys 目录下的层次结构依赖于 kobject.parent ,未指定parent时,默认使用 kobject.kset.kobject 作为 parent,如果都没有,就出现在 /sys 目录下。
2、该 kobject 目录下的属性文件依赖于 kobject.ktype
在Linux的驱动表示中,主要有三个基本的结构,分别是kobject,kset,ktype.Kobject,kset,kypte这三个结构是设备模型中的下层架构。模型中的每一个元素都对应一个kobject.kset和ktype可以看成是kobject在层次结构与属性结构方面的扩充。将三者之间的关系用图的方示描述如下:
如上图所示:我们知道。在sysfs中每一个目录都对应一个kobject.这些kobject都有自己的parent。在没有指定parent的情况下,都会指向它所属的kset->object。其次,kset也内嵌了kobject.这个kobject又可以指它上一级的parent。就这样。构成了一个空间上面的层次关系。
其实,每个对象都有属性。例如,电源管理,执插拨事性管理等等。因为大部份的同类设备都有相同的属性,因此将这个属性隔离开来,存放在ktype中。这样就可以灵活的管理了.记得在分析sysfs的时候。对于sysfs中的普通文件读写操作都是由kobject->ktype->sysfs_ops来完成的.
kobject
- truct 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;
- };
在Linux内核里,kobject是组成Linux设备模型的基础,一个kobject对应sysfs里的一个目录。从面向对象的角度来说,kobject可以看作是所有设备对象的基类,因为C语言并没有面向对象的语法,所以一般是把kobject内嵌到其他结构体里来实现类似的作用,这里的其他结构体可以看作是kobject的派生类。Kobject为Linux设备模型提供了很多有用的功能,比如引用计数,接口抽象,父子关系等等,所以,在内核中,没有用kobject直接定义的变量,kobject只是作为一个抽象的基类而存在。一般都是将kobject嵌入到另一个结构,这个结构就可以看做是kobject的一个子类。而kobject的子类会比较关心kobject的属性和方法。
内核里的设备之间是以树状形式组织的,在这种组织架构里比较靠上层的节点可以看作是下层节点的父节点,反映到sysfs里就是上级目录和下级目录之间的关系,在内核里,正是kobject帮助我们实现这种父子关系。在kobject的定义里,name表示的是kobject在sysfs中的名字;指针parent用来指向kobject的父对象;Kref大家应该比较熟悉了,kobject通过它来实现引用计数;Kset指针用来指向这个kobject所属的kset;对于ktype,如果只是望文生义的话,应该是用来描述kobject的类型信息。
- struct kref
- {
- atomic_t refcount;
- }
kobject的作用: 1、sysfs 表述:在 sysfs 中出现的每个对象都对应一个 kobject, 它和内核交互来创建它的可见表述。
2、数据结构关联:整体来看, 设备模型是一个极端复杂的数据结构,通过其间的大量链接而构成一个多层次的体系结构。kobject 实现了该结构并将其聚合在一起。
3、热插拔事件处理 :kobject 子系统将产生的热插拔事件通知用户空间。
一个kobject对自身并不感兴趣,它存在的意义在于把高级对象连接到设备模型上。因此内核代码很少(甚至不知道)创建一个单独的 kobject;而kobject 被用来控制对大型域(domain)相关对象的访问,所以kobject 被嵌入到其他结构中。kobject 可被看作一个最顶层的基类,其他类都它的派生产物。 kobject 实现了一系列方法,对自身并没有特殊作用,而对其他对象却非常有效。
对于给定的kobject指针,可使用container_of宏得到包含它的结构体的指针
kobject相关操作函数:
1、初始化---kobject_init
- 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) {
-
- 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();
- }
- 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;
- }
2、将kobject加入到分层结构-----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; </span>
kobject_add_varg():
- static int kobject_add_varg(struct kobject *kobj, struct kobject *parent,
- const char *fmt, va_list vargs)
- {
- int retval;
-
- 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;
- return kobject_add_internal(kobj);
- } </span>
- 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 = kobject_get(kobj->parent);
-
-
- 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;
-
-
- 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;
- }
- static int create_dir(struct kobject *kobj)
- {
- int error = 0;
- if (kobject_name(kobj)) {
- error = sysfs_create_dir(kobj);
- if (!error) {
- error = populate_dir(kobj);
- if (error)
- sysfs_remove_dir(kobj);
- }
- }
- return error;
- } </span>
我们先看一下kobject所表示的目录创建过程。这是在sysfs_create_dir()中完成的
- int sysfs_create_dir(struct kobject * kobj)
- {
- enum kobj_ns_type type;
- struct sysfs_dirent *parent_sd, *sd;
- const void *ns = NULL;
- int error = 0;
-
- BUG_ON(!kobj);
-
-
-
-
-
- if (kobj->parent)
- parent_sd = kobj->parent->sd;
- else
- parent_sd = &sysfs_root;
-
- if (sysfs_ns_type(parent_sd))
- ns = kobj->ktype->namespace(kobj);
- type = sysfs_read_ns_type(kobj);
-
-
- error = create_dir(kobj, parent_sd, type, ns, kobject_name(kobj), &sd);
- if (!error)
- kobj->sd = sd;
- return error;
- } </span>
接着看为kobject->ktype中的属性创建文件。这是在populate_dir()中完成的- static int populate_dir(struct kobject *kobj)
- {
- struct kobj_type *t = get_ktype(kobj);
- struct attribute *attr;
- int error = 0;
- int i;
-
- if (t && t->default_attrs) {
- for (i = 0; (attr = t->default_attrs[i]) != NULL; i++) {
- error = sysfs_create_file(kobj, attr);
- if (error)
- break;
- }
- }
- return error;
- }
另外一个常用的函数就是kobject_init_and_add,直接初始化并进行添加操作
- int kobject_init_and_add(struct kobject *kobj, struct kobj_type *ktype,
- struct kobject *parent, const char *fmt, ...)
- {
- va_list args;
- int retval;
-
- kobject_init(kobj, ktype);
-
- va_start(args, fmt);
- retval = kobject_add_varg(kobj, parent, fmt, args);
- va_end(args);
-
- return retval;
- }
这里面调用的也就是init和add操作了。
还有一个kobj的删除函数:
- void kobject_del(struct kobject *kobj)
- {
- if (!kobj)
- return;
-
- sysfs_remove_dir(kobj);
- kobj->state_in_sysfs = 0;
- kobj_kset_leave(kobj);
- kobject_put(kobj->parent);
- kobj->parent = NULL;
- }
基于 linux2.6.32.2 的驱动
- #include <linux/device.h>
- #include <linux/module.h>
- #include <linux/kernel.h>
- #include <linux/init.h>
- #include <linux/string.h>
- #include <linux/sysfs.h>
- #include <linux/stat.h>
-
- MODULE_AUTHOR("David Xie");
- MODULE_LICENSE("Dual BSD/GPL");
-
-
-
- void obj_test_release(struct kobject *kobject);
- ssize_t kobj_test_show(struct kobject *kobject, struct attribute *attr,char *buf);
- ssize_t kobj_test_store(struct kobject *kobject,struct attribute *attr,const char *buf, size_t count);
-
-
- struct attribute test_attr = {
- .name = "kobj_config",
- .mode = S_IRWXUGO,
- };
-
- static struct attribute *def_attrs[] = {
- &test_attr,
- NULL,
- };
-
-
- struct sysfs_ops obj_test_sysops =
- {
- .show = kobj_test_show,
- .store = kobj_test_store,
- };
-
-
- struct kobj_type ktype =
- {
- .release = obj_test_release,
- .sysfs_ops=&obj_test_sysops,
- .default_attrs=def_attrs,
- };
-
-
- void obj_test_release(struct kobject *kobject)
- {
- printk("eric_test: release .\n");
- }
-
-
- ssize_t kobj_test_show(struct kobject *kobject, struct attribute *attr,char *buf)
- {
- printk("have show.\n");
- printk("attrname:%s.\n", attr->name);
- sprintf(buf,"%s\n",attr->name);
- return strlen(attr->name)+2;
- }
-
-
- ssize_t kobj_test_store(struct kobject *kobject,struct attribute *attr,const char *buf, size_t count)
- {
- printk("havestore\n");
- printk("write: %s\n",buf);
- return count;
- }
-
- struct kobject kobj;
-
- static int kobj_test_init(void)
- {
- printk("kboject test init.\n");
- kobject_init_and_add(&kobj,&ktype,NULL,"kobject_test");
-
-
-
-
-
- return 0;
- }
-
- static void kobj_test_exit(void)
- {
- printk("kobject test exit.\n");
- kobject_del(&kobj);
- }
-
- module_init(kobj_test_init);
- module_exit(kobj_test_exit);