kobject驱动模型的架构与相关函数

 kobject驱动模型的架构与相关函数_第1张图片

在linux内核中("kernel/include/linux/cdev.h")kobject结构定义如下:

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;
};


 

可以看到 字符驱动中有使用cdev这个主要结构。而cdev实际上有个kobject类型的成员: kobj 。

struct cdev {
    struct kobject kobj;
    struct module *owner;
    const struct file_operations *ops;
    struct list_head list;
    dev_t dev;
    unsigned int count;
};

 

我们可以通过指向kobj的指针,找到cdev的地址:

struct cdev *device = container_of(kobj_ptr, struct cdev, kobj); 


 

 

  

kobject 初始化:

void kobject_init(struct kobject *kobj); 

         kobject_init 设置 kobject 的引用计数为 1.

设置 kobject 的名字. 这也是用在 sysfs 入口的名字:

int kobject_set_name(struct kobject *kobj, const char *format, ...); 

 

当然如果需要我们也必须在初始化时设置 ktype, kset, 和 parent 等成员;

 

引用计数的操作:

struct kobject *kobject_get(struct kobject *kobj);
void kobject_put(struct kobject *kobj);

 

一个对 kobject_get 的成功调用递增 kobject 的 引用计数并且返回一个指向 kobject 的指针.如果, 但是, 这个 kobject 已经在被销毁的过程中, 这个操作失败, 并且 kobject_get 返回 NULL. 所以必须总是检查这个返回值。

 

 

释放函数和 kobject 类型

有趣的是, 释放方法没有存储在 kobject 自身里面; 相反, 它被关联到包含 kobject 的结构类型中. 这个类型被跟踪, 用一个 struct kobj_type 结构类型, 常常简单地称为一个 "ktype". 这个结构看来如下:

struct kobj_type {
    void (*release)(struct kobject *kobj);
    const struct sysfs_ops *sysfs_ops;
    struct attribute **default_attrs;
    const struct kobj_ns_type_operations *(*child_ns_type)(struct kobject *kobj);
    const void *(*namespace)(struct kobject *kobj);
};


但是, 如果这个 kobject 是一个 kset 的成员, kobj_type 指针由 kset 提供

 

struct kobj_type *get_ktype(struct kobject *kobj);

 

parent 指针的主要用途是在 sysfs 层次中定位对象;

 

Ksets 对象

 

/**
 * struct kset - a set of kobjects of a specific type, belonging to a specific subsystem.
 *
 * A kset defines a group of kobjects.  They can be individually
 * different "types" but overall these kobjects all want to be grouped
 * together and operated on in the same manner.  ksets are used to
 * define the attribute callbacks and other common events that happen to
 * a kobject.
 *
 * @list: the list of all kobjects for this kset
 * @list_lock: a lock for iterating over the kobjects
 * @kobj: the embedded kobject for this kset (recursion, isn't it fun...)
 * @uevent_ops: the set of uevent operations for this kset.  These are
 * called whenever a kobject has something happen to it so that the kset
 * can add new environment variables, or filter out the uevents if so
 * desired.
 */
struct kset {
    struct list_head list;
    spinlock_t list_lock;
    struct kobject kobj;
    const struct kset_uevent_ops *uevent_ops;
};


概念(根据上面的注释来解释):

kset 结构: 一系列特定类型的kobjects 的集合,这些kobject都属于特定的子系统(subsystem);

一个kset 定义了一群kobject 。这些kobject 可以有不一样的类型,但是所有的这些kobject都由一些共同的动作或者属性。

而kset是用来定义这些共同属性的回调 和 其他共同的事件。

kset 中的 uevent_ops 成员:  不管什么时候kobject发生什么事件,uevent_ops 中的函数会 被调用。因此kset可以添加新的环境变量,或是过滤出某些需要的uevent。

 

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);
};


 

 

 

一个 kset 的主要功能是容纳; 它可被当作顶层的给 kobjects 的容器类.

值得注意的是 ksets 一直在 sysfs 中出现; 一旦一个 kset 已被建立并且加入到系统, 会有一个 sysfs 目录给它.  kset 成员的 kobject 都出现在那里(那个目录下)

int kobject_add(struct kobject *kobj); 

 

有一个内核提供的方便函数:

extern int kobject_register(struct kobject *kobj); 

这个函数仅仅是一个 kobject_init 和 kobject_add 的结合.

当一个 kobject 被传递给 kobject_add, 它的引用计数被递增. kset 中容纳的, 毕竟, 是一个对这个对象的引用. 某种意义上, kobject 可能要必须从 kset 中移出来清除这个引用; 完成这个使用:

void kobject_del(struct kobject *kobj); 

还有一个 kobject_unregister 函数, 是 kobject_del 和 kobject_put 的结合.

 

一个 kset 保持它的子女在一个标准的内核链表中. 在大部分情况下, 被包含的 kobjects 也有指向这个 kset 的指针( 或者, 严格地, 它的嵌入 kobject)在它们的 parent 的成员. 因此, 典型地, 一个 kset 和它的 kobjects 看来有些象你在图一个简单的 kset 层次中所见. 记住:

  • 所有的被包含的 kobjects 实际上被嵌入在一些其他类型中, 甚至可能其他的 ksets.

  • 一个 kobject 的 parent 不要求是包含 kset。

 

ksets 之上的操作

 对于初始化和设置, ksets 有一个接口非常类似于 kobjects:

void kset_init(struct kset *kset);
int kset_add(struct kset *kset);
int kset_register(struct kset *kset);
void kset_unregister(struct kset *kset);

 

为管理 ksets 的引用计数, 情况大概相同:

struct kset *kset_get(struct kset *kset);
void kset_put(struct kset *kset);

 

一个 kset 还有一个名子, 存储于嵌入的 kobject. 因此, 如果你有一个 kset 称为 my_set, 你将设置它的名子用:

kobject_set_name(&my_set->kobj, "The name");
 

ksets 还有一个指针( 在 ktye 成员 )指向 kobject_type 结构来描述它包含的 kobject. 这个类型优先于在 kobject 自身中的 ktype 成员. 结果, 在典型的应用中, 在 struct kobject 中的 ktype 成员被留为 NULL, 因为 kset 中的相同成员是实际使用的那个.

 
最后, 一个 kset 包含一个子系统指针(称为 subsys). 因此是时候讨论子系统了。
 
 
 
子系统
 

一个子系统是作为一个整体对内核一个高级部分的代表. 子系统常常出现在 sysfs 层次的顶级(即/sys 目录下面的子目录). 一些内核中的例子子系统包括 block_subsys(/sys/block, 给块设备), devices_subsys(/sys/devices, 核心设备层次), 以及一个特殊子系统给每个内核已知的总线类型. 一个驱动作者几乎从不需要创建一个新子系统; 如果你想这样做, 再仔细想想. 你可能需要什么, 最后, 是增加一个新类别, 如同在"类别"一节中描述的.

 

一个子系统由一个简单结构代表:

struct subsystem {
 struct kset kset;
 struct rw_semaphore rwsem; 
}; 

一个子系统, 因此, 其实只是一个对 kset 的包装, 有一个可读写的信号量在里面.

 

每个 kset 必须属于一个子系统. 子系统成员关系帮助建立 kset 的位置在层次中, 但是, 更重要的, 子系统的 rwsem 旗标用来串行化对 kset 的内部链表的存取. 这个成员关系由在 struct kset 中的 subsys 指针所表示. 因此, 可以从 kset 的结构找到每个 kset 的包含子系统, 但是却无法直接从子系统结构发现多个包含在子系统中的 kset.

子系统常常用一个特殊的宏声明:

 
decl_subsys(name, struct kobj_type *type, struct kset_hotplug_ops *hotplug_ops);

 

这个宏创建一个 struct subsystem 使用一个给这个宏的名子并后缀以 _subsys 而形成的名子. 这个宏还初始化内部的 kset 使用给定的 type 和 hotplug_ops. ( 我们在本章后面讨论热插拔操作).

子系统有通常的建立和拆卸函数:

void subsystem_init(struct subsystem *subsys);
int subsystem_register(struct subsystem *subsys);
void subsystem_unregister(struct subsystem *subsys);
struct subsystem *subsys_get(struct subsystem *subsys)
void subsys_put(struct subsystem *subsys);

大部分这些操作只是作用在子系统的 kset上.

 

你可能感兴趣的:(kobject驱动模型的架构与相关函数)