linux kobject设备模型详解(转)

分类: LINUX |
kobject包含一个名字和一个引用计数器,这个引用计数器会记录由kobject派生的内核对象被引用的次数。所以,一个结构最多只能包含一个kobject对象,否则,该结构的引用计数会乱套的。
上面提到,关心kobject实现的并不是kobject自身而是包含kobject的结构,所以当不同的结构包含kobject后,kobject的属性会不同,kobject销毁时所做的操作会不同,kobject所表现出的类型也会不同。所以,kobject中包含了一个叫作kobj_type的结构。kobj_type的目标就是为不同类型的kobject提供不同的属性以及销毁方法。
有时候,某个设备的可能具有多个kobject的子类对象,或者某些设备具有相同的特性,为了便于管理,应该把这些对象统一放入一个容器中。这里要用到的容器就是kset。kset只是kobject的一个集合。对应到linux文件系统中,一个kset就是/sys下的一个文件夹。
1若没用kobject_create而是自己定义的kobject,初始化kobject之前,应该用memset函数将整个kobject设置为0
2调用kobject_init初始化kobject一些成员
3调用kobject_set_name设置自己的名字(至少调用这个)或调用kobject_add
上面的2、3可变为一个调用kobject_init_and_add
kobject_del
法二、动态生成kobject
1kobject_create(ktype设为了&dynamic_kobj_ktype)
2kobject_add
前两步可合并调用一个kobject_init_and_add
kobject_put释放kobject详细介绍
先看看kobject的结构:
struct kobject{
};
kobject的操作:
extern int kobject_set_name(struct kobject *kobj, const char *name, ...)__attribute__((format(printf, 2, 3)));
extern int
kobject_set_name_vargs(struct kobject *kobj, const char
*fmt,va_list
vargs);
上两个函数为设定kobject的名字。虽然从上面的结构定义中可以看到kobject的名字就是成员name所指向的字符串,但为kobject设定名字时,还是函数kobject_set_name,这样可以提高代码的可移植性。此函数为name分配了空间,所以后面的kobject_cleanup释放name。
static inline const char *kobject_name(const struct kobject *kobj) 获得kobject的名字
{
}
若没用kobject_create而是自己定义的kobject,初始化kobject之前,应该用memset函数将整个kobject设置为0
extern void kobject_init(struct kobject *kobj, struct kobj_type *ktype);
此函数初始化kobject中的entry,kref,将state_in_sysfs设为0,state_add_uevent_sent设为0,state_remove_uevent_sent设为0,state_initialized设为1,并根据传入的ktype设定kobj->ktype,而且ktype不能为空。自己制定ktype
extern int __must_check kobject_add(struct kobject *kobj,struct kobject *parent,const char *fmt, ...);
此函数将一个已初始化好的kobject加入系统,第一个参数是需要加入的kobject,第二个参数是kobject的父结点,第三个参数是kobject的名字。若parent为空,且kobj->kset不为空,则将kobj->prent设为&kobj->kset->kobj。若kobj->kset为空,则把kobject置于sysfs的根目录下。还有一些注意事项见代码。此函数的流程图如下:
http://s13/bmiddle/001ouJ7Fzy6MdKo0LgMcc&690
extern int __must_check
kobject_init_and_add(struct
kobject *kobj,struct kobj_type *ktype,
从名字就可以看出来,这个函数是kobject_init和kobject_add的组合.自己制定ktype
extern void kobject_del(struct kobject *kobj);
此函数只是将kobject从sysfs和kset中去掉(初始化kobject的list_head),并不是删除kobject,删除kobject得靠kobject->ktype->release才行。kobject_del在把kobject从kset中去掉后,会把kset的引用值减1。
extern struct kobject * __must_check kobject_create(void);
动态分配一个kobject,将kobject的ktype设为&dynamic_kobj_ktype后,并初始化之(调用了kobject_init)。之后必须用kobject_put释放,不能用kfree。
extern struct kobject * __must_check kobject_create_and_add(const char *name,struct kobject *parent);
从名字就可以看出来,这个函数是kobject_create和kobject_add的组合。ktype为dynamic_kobj_ktype
以上两个函数的流程图如下:
http://s11/bmiddle/001ouJ7Fzy6MdKshC9Yba&690
extern int __must_check kobject_rename(struct kobject *, const char *new_name);
此函数可以为一个已经添加到sysfs中的kobject重命名,同时也会改变kobject在sysfs中对应的文件名。此函数在重命名之前会先把kobject的引用值加1,在改完名后,会再把kobject的引用值减1。
extern int __must_check kobject_move(struct kobject *, struct kobject *);
此函数可以改变一个kobject的parent,并同时更新kobject在sysfs中的路径,更换完parent之后,函数会把kobject以前的parent的引用值减1。
extern struct kobject *kobject_get(struct kobject *kobj);
此函数为kobject的引用值加1。
extern void kobject_put(struct kobject *kobj);
此函数为kobject的引用值减1,若引用值减为0,则销毁此kobject(调用kobject_release调用kobject_cleanup,最终调用kobject_del、ktype的release),最后一步释放的name是在kobject_add中调用的kobject_set_name_vargs中分配的。
上面这两个函数的流程图如下:
http://s14/bmiddle/001ouJ7Fzy6MdKy3EqVad&690
extern char *kobject_get_path(struct kobject *kobj, gfp_t flag);
获取kobject在sysfs中的路径。(基本上是根据parent/kset和name决定路径)
ktype详细介绍
struct kobj_type {
};
struct sysfs_ops {
};
kobj_type中的后两个成员表示了kobject在sysfs中的各个属性,及各个属性的操作方法。
需要说明的是,每一个kobject都必须有一个release函数,而已每个kobject不能在release函数被调用之前被销毁。release的作用是清除为kobject分配的内存空间,不过在release被调用时,kobject->name是有效的,但是,release函数不能改变name,因为name的释放是在函数kobject_cleanup中做的。
static struct kobj_type dynamic_kobj_ktype = {
};
struct sysfs_ops kobj_sysfs_ops = {
};
kset详细介绍
struct kset {
};
kset关联的操作:
extern void kset_init(struct
kset *kset);
extern int __must_check kset_register(struct kset *kset);
此函数首先将kset加入sysfs(kset加入sysfs是通过kset中的成员kobject实现的,其实加入sysfs的不是kset本身,而是kset的成员kobject,可以通过kobject和container_of找到kset)然后发出一个KOBJ_ADD的uevent。
由于kobject_add是将kobject加入到kset中,也可以把kset->kobj加入的上一层的kset中
kobject_add_internal,name是空则错误,所以之前应该设置过name的
kobject_uevent
kset_create内部函数:
分配kset
kobject_set_name按参数设置kset->kobj->name
kset->uevent_ops = uevent_ops;
按参数设置kset->kobj->parent
kset->kobj.ktype = &kset_ktype;
kset->kobj.kset = NULL;
static struct kobj_type kset_ktype = {
};
extern struct kset * __must_check kset_create_and_add(const char *name,const struct kset_uevent_ops *u,struct kobject *parent_kobj);
此函数只是kset_create和kset_register的组合,其中kset_create会动态生成一个kset,并将其初始化。如果想简单地生成一个kset并将其加入系统,可以调用此函数。
以上三个函数的流程图如下:
http://s1/bmiddle/001ouJ7Fzy6MdKB2foAf0&690
extern void kset_unregister(struct
kset
*kset);
此函数将kset从sysfs中移出,也就是将kset的成员kobject从sysfs中移出。只调用了kobject_put(&k->kobj),此时kobj的ktype已经改成了kset_ktype,最终就调用kset_ktype中的release(kset_release)。
其它功能函数:
static inline struct kset
*to_kset(struct kobject
*kobj)
{
}
static inline struct kset
*kset_get(struct
kset
*k)
{
}
static inline void kset_put(struct kset *k)
{
}
static inline struct kobj_type
*get_ktype(struct
kobject
*kobj)
{
}
extern struct kobject *kset_find_obj(struct kset *, const char *name);
//查找kset中名字为name的kobject
其它为热插拔函数,暂时不分析。
内部函数:
populate_dir、create_dir、get_kobj_path_length、fill_kobj_path、kobj_kset_join、kobj_kset_leave、kobject_init_internal、kobject_add_internal、kobject_set_name_vargs、kobject_add_varg、kobject_move、kobject_cleanup、kobject_release、dynamic_kobj_release、kobj_attr_show、kobj_attr_store、kset_release、kset_create