加载中…
个人资料
  • 博客等级:
  • 博客积分:
  • 博客访问:
  • 关注人气:
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
正文 字体大小:

linux kobject设备模型详解(转)

(2014-09-21 10:51:17)
分类: LINUX


kobjectlinux设备模型中最基本的结构。要说明的是,linux内核虽然由C语言编写,但是内核在实现时,到处都体现出开发者面向对象的思想。所以,kobject也可以理解为所有驱动对象的基类。后面用到的驱动对象,几乎都是kobject的派生类。作为基类的kobject并不关心自己是如何实现的,所以,在内核中,没有用kobject直接定义的变量,kobject只是作为一个抽象的基类而存在。一般都是将kobject嵌入到另一个结构,这个结构就可以看做是kobject的一个子类。kobject的子类会比较关心kobject的属性和方法。

kobject包含一个名字和一个引用计数器,这个引用计数器会记录由kobject派生的内核对象被引用的次数。所以,一个结构最多只能包含一个kobject对象,否则,该结构的引用计数会乱套的。

上面提到,关心kobject实现的并不是kobject自身而是包含kobject的结构,所以当不同的结构包含kobject后,kobject的属性会不同,kobject销毁时所做的操作会不同,kobject所表现出的类型也会不同。所以,kobject中包含了一个叫作kobj_type的结构。kobj_type的目标就是为不同类型的kobject提供不同的属性以及销毁方法。

有时候,某个设备的可能具有多个kobject的子类对象,或者某些设备具有相同的特性,为了便于管理,应该把这些对象统一放入一个容器中。这里要用到的容器就是ksetkset只是kobject的一个集合。对应到linux文件系统中,一个kset就是/sys下的一个文件夹。

 kobject使用方法说明:

 法一、 静态生成或动态生成,自己动态生成需要自己分配、释放

1若没用kobject_create而是自己定义的kobject,初始化kobject之前,应该用memset函数将整个kobject设置为0

2调用kobject_init初始化kobject一些成员

3调用kobject_set_name设置自己的名字(至少调用这个)或调用kobject_add

上面的23可变为一个调用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{

    const char    *name;            //可以给kobject起一个名字

    struct list_head  entry;

    struct kobject       *parent;   //kobject的父指针

    struct kset       *kset;            //kobject所属的kset

    struct kobj_type  *ktype;

    struct sysfs_dirent  *sd;              //kobjectsysfs中的层次结构,关于sysfs这里不做讨论

    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;

};

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的名字

{

    return kobj->name;

}

若没用kobject_create而是自己定义的kobject,初始化kobject之前,应该用memset函数将整个kobject设置为0

 能指定自己的ktype就可编写自己的ktype类型的release等函数。release函数一定要释放kobject。其它函数也有相应规则。

extern void kobject_init(struct kobject *kobj, struct kobj_type *ktype);

此函数初始化kobject中的entrykref,将state_in_sysfs设为0state_add_uevent_sent设为0state_remove_uevent_sent设为0state_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, struct kobject *parent,const char *fmt, ...);

从名字就可以看出来,这个函数是kobject_initkobject_add的组合.自己制定ktype

 

extern void kobject_del(struct kobject *kobj);

此函数只是将kobjectsysfskset中去掉(初始化kobjectlist_head),并不是删除kobject,删除kobject得靠kobject->ktype->release才行。kobject_del在把kobjectkset中去掉后,会把kset的引用值减1

 

extern struct kobject * __must_check kobject_create(void);

动态分配一个kobject,将kobjectktype设为&dynamic_kobj_ktype后,并初始化之(调用了kobject_init)。之后必须用kobject_put释放,不能用kfree

 

extern struct kobject * __must_check kobject_create_and_add(const char *name,struct kobject *parent);

从名字就可以看出来,这个函数是kobject_createkobject_add的组合。ktypedynamic_kobj_ktype

以上两个函数的流程图如下:

http://s11/bmiddle/001ouJ7Fzy6MdKshC9Yba&690

 

extern int __must_check kobject_rename(struct kobject *, const char *new_name);

此函数可以为一个已经添加到sysfs中的kobject重命名,同时也会改变kobjectsysfs中对应的文件名。此函数在重命名之前会先把kobject的引用值加1,在改完名后,会再把kobject的引用值减1

 

extern int __must_check kobject_move(struct kobject *, struct kobject *);

此函数可以改变一个kobjectparent,并同时更新kobjectsysfs中的路径,更换完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_delktyperelease),最后一步释放的name是在kobject_add中调用的kobject_set_name_vargs中分配的。

上面这两个函数的流程图如下:

http://s14/bmiddle/001ouJ7Fzy6MdKy3EqVad&690

 

extern char *kobject_get_path(struct kobject *kobj, gfp_t flag);

获取kobjectsysfs中的路径。(基本上是根据parent/ksetname决定路径)

ktype详细介绍

struct kobj_type {

    void (*release)(struct kobject *kobj);     //kobject销毁时所调用的函数,由kobject_put调用

    const struct sysfs_ops *sysfs_ops;         //对于attribute的操作

    struct attribute **default_attrs;

};

struct sysfs_ops {

    ssize_t    (*show)(struct kobject *, struct attribute *,char *);

    ssize_t    (*store)(struct kobject *,struct attribute *,const char *, size_t);

};

kobj_type中的后两个成员表示了kobjectsysfs中的各个属性,及各个属性的操作方法。

需要说明的是,每一个kobject都必须有一个release函数,而已每个kobject不能在release函数被调用之前被销毁。release的作用是清除为kobject分配的内存空间,不过在release被调用时,kobject->name是有效的,但是,release函数不能改变name,因为name的释放是在函数kobject_cleanup中做的。

 kobject.c中定义了一个struct kobj_type dynamic_kobj_ktypekobject_create时指定了dynamic_kobj_ktype,但是kobject_initkobject_init_and_add设定了自己的ktype,而kobject_create_and_add制定了dynamic_kobj_ktype.

static struct kobj_type dynamic_kobj_ktype = {

              .release            = dynamic_kobj_release,                                 //kfree(kobj)释放object对象

              .sysfs_ops       = &kobj_sysfs_ops,

};

struct sysfs_ops kobj_sysfs_ops = {

              .show  = kobj_attr_show,

              .store  = kobj_attr_store,

};

kset详细介绍

struct kset {

    struct list_head list;       //此链表中保存了kset中所有的kobject,是所有相同ktypekobjectlist_head的表头

    spinlock_t list_lock;        //当遍历list时,使用的锁

    struct kobject kobj;         //这说明kobject是最基本的结构,就相当于是基类一样

    const struct kset_uevent_ops *uevent_ops;  //暂时不讨论uevent

};

kset关联的操作:

extern void kset_init(struct kset *kset);                初始化kset中各个成员。

 kobject_init_internal和初始化kset->list,没设定kobjnameparentktype

extern int __must_check kset_register(struct kset *kset);

此函数首先将kset加入sysfskset加入sysfs是通过kset中的成员kobject实现的,其实加入sysfs的不是kset本身,而是kset的成员kobject,可以通过kobjectcontainer_of找到kset)然后发出一个KOBJ_ADDuevent

由于kobject_add是将kobject加入到kset中,也可以把kset->kobj加入的上一层的kset

 kset_init()      

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 = {

              .sysfs_ops       = &kobj_sysfs_ops,                 //和普通kobject的一样

              .release = kset_release,                                    // kfree(kset)

};

extern struct kset * __must_check kset_create_and_add(const char *name,const struct kset_uevent_ops *u,struct kobject *parent_kobj);

此函数只是kset_createkset_register的组合,其中kset_create会动态生成一个kset,并将其初始化。如果想简单地生成一个kset并将其加入系统,可以调用此函数。

以上三个函数的流程图如下:

http://s1/bmiddle/001ouJ7Fzy6MdKB2foAf0&690

extern void kset_unregister(struct kset *kset);              

此函数将ksetsysfs中移出,也就是将kset的成员kobjectsysfs中移出。只调用了kobject_put(&k->kobj),此时kobjktype已经改成了kset_ktype,最终就调用kset_ktype中的release(kset_release)

其它功能函数:

static inline struct kset *to_kset(struct kobject *kobj)            //kobject找到包含它的kset

{

         return kobj ? container_of(kobj, struct kset, kobj) : NULL;

}

 

static inline struct kset *kset_get(struct kset *k)                     //kset对应kobj计数增加

{

         return k ? to_kset(kobject_get(&k->kobj)) : NULL;

}

 

static inline void kset_put(struct kset *k)

{

         kobject_put(&k->kobj);

}

 

static inline struct kobj_type *get_ktype(struct kobject *kobj)               //获得Kobjktype

{

         return kobj->ktype;

}

extern struct kobject *kset_find_obj(struct kset *, const char *name);

//查找kset中名字为namekobject

其它为热插拔函数,暂时不分析。

内部函数:

 

populate_dircreate_dirget_kobj_path_lengthfill_kobj_pathkobj_kset_joinkobj_kset_leavekobject_init_internalkobject_add_internalkobject_set_name_vargskobject_add_vargkobject_movekobject_cleanupkobject_releasedynamic_kobj_releasekobj_attr_showkobj_attr_storekset_releasekset_create

0

阅读 收藏 喜欢 打印举报/Report
  

新浪BLOG意见反馈留言板 欢迎批评指正

新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 产品答疑

新浪公司 版权所有