一、kobject与ktype的关系
在sysfs目录下存在许多子目录,每一个目录对应一个kobject对象.这些kobject对象都有自己的parent指针。在没有指定parent的情况下,都会指向它所属的kset->kobject。其次,kset也内嵌了kobject.这个kobject又可以指它上一级的parent。就这样。构成了一个空间上的层次关系。
而每个对象都有属性。例如,电源管理,执插拨事性管理等等。因为大部份的同类设备都有相同的属性,因此将这个属性隔离开来,存放在ktype中。这样就可以灵活的管理了.在分析sysfs的时候。对于sysfs中的普通文件读写操作都是由kobject->ktype->sysfs_ops来完成的.
二、核心结构体:
struct kobject {
const char*name;名
struct list_headentry;用于连接到同类kobjects的链表
struct kobject*parent;用于实现层次,指向其父对象。
struct kset*kset;用于实现层次,所属的集合
struct kobj_type*ktype;指向属性操作函数。
struct sysfs_dirent*sd;
struct krefkref;计数
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;
};
struct kobj_type{
void (*release)(struct kobject *);
struct sysfs_ops *sysfs_ops;/*提供实现以下属性的方法*/
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);
};
struct attribute{
char *name;/*属性的名字(在kobject的sysfs目录中显示,如上文的dev、uvent)*/
struct module *owner;/*指向模块的指针(如果有),此模块负责实现这个属性*/
mode_t mode; /*属性的保护位,modes的宏定义在<linux/stat.h>:例如S_IRUGO为只读属性等等*/
}; /*default_attrs列表中的最后一个元素必须用0填充*/
三、集大成者
常用的对kobject的操作函数有一下这些:
void kobject_init(struct kobject *kobj, struct kobj_type *ktype);//初始化函数。
int kobject_set_name(struct kobject *kobj, const char *format, ...);“设置指定kobject的名称。”
struct kobject *kobject_get(struct kobject *kobj);“将kobj对象的引用计数加1,同时返回该对象的指针。”
void kobject_put(struct kobject * kobj);“将kobj对象的引用计数减1,如果引用计数降为0,则调用kobject release()释放该kobject对象。”
int kobject_add(struct kobject * kobj);是对kobject_add_varg的封装,“将kobj对象加入Linux设备层次。挂接该kobject对象到kset的list链中,增加父目录各级kobject的引用计数,在其parent指向的目录下创建文件节点,并启动该类型内核对象的hotplug函数。”
int kobject_register(struct kobject * kobj);“kobject注册函数。通过调用kobject init()初始化kobj,再调用kobject_add()完成该内核对象的注册。”
void kobject_del(struct kobject * kobj);“从Linux设备层次(hierarchy)中删除kobj对象。”
void kobject_unregister(struct kobject * kobj);“kobject注销函数。与kobject register()相反,它首先调用kobject del从设备层次中删除该对象,再调用kobject put()减少该对象的引用计数,如果引用计数降为0,则释放kobject对象。”
int kobject_init_and_add(struct kobject *kobj, struct kobj_type *ktype, struct kobject *parent, const char *fmt, ...);//是对kobject_init和kobject_add_varg的封装。
因为kobject_init_and_add集合了对kobj对象的初始化操作,是将来我们分析源码中关于设备模型底层架构最常见到一个函数,这里对它做一些细致的分析,先看一下整体的调用情况:
图1、kobject_init_and_add函数调用流程
(1)、kobject_init_and_add除了对kobject_add_varg包装,还指定了操作方法——ktype。
(2)、kobject_add_varg完成了对kobj的命名和对父节点kobj>parent的初始化。
(3)、kobject_add_internal负责归类,即如果集合kset对象,就将父节点重新指向该kset对象,同时将kobj加到kset的链表里。
(4)、create_dir通过调用sysfs_create_dir和populate_dir创建kobject在sysfs文件系统下的目录,以及在该目录下创建kobj的属性文件。
四、测试例子
图2:kobject、kobj_type简易系统模型
#include<linux/module.h>
#include<linux/fs.h>
#include<linux/types.h>
#include<linux/kobject.h>
#include<linux/sysfs.h>
struct attribute attr1=
{
.name="attr1",
.mode=S_IRWXUGO,
};
struct attribute* def_attr[]=//自定义属性
{
&attr1,
NULL,
} ;
ssize_t sysops_show(struct kobject *kobj, struct attribute *attr,char *buf)
{
printk("sysops_show.\n") ;
printk("attr->name=%s.\n",attr->name) ;
sprintf(buf,"%s\n",attr->name) ;
return strlen(buf)+2;
}
ssize_t sysops_store(struct kobject *kobj,struct attribute *attr,const char *buf, size_t count)
{
printk("sysops_store.\n") ;
printk("write:%s",buf) ;
return strlen(buf)+2 ;
}
struct sysfs_ops ktype_sysops=//自定义sysfs属性文件操作方法
{
.show=sysops_show,
.store=sysops_store,
};
void ktype_release(struct kobject* kobj)
{
printk("ktype release.\n") ;
}
struct kobj_type ktype=//自定义kobj操作方法
{
.release=ktype_release,
.sysfs_ops=&ktype_sysops,
.default_attrs=def_attr,
} ;
struct kobject kobj ;
static int __init DEMO_init(void)//模块加载所调用的函数
{
int ret=0 ;
printk("kobj test init.\n") ;
ret=kobject_init_and_add(&kobj, &ktype, NULL, "kobj_test") ;
if(ret)
{
printk("kobjct init and add error.\n") ;
return -EFAULT ;
}
return 0 ;
}
static void __exit DEMO_exit(void)//模块卸载调用的函数
{
printk("kobj test exit.\n") ;
kobject_del(&kobj) ;
}
module_init(DEMO_init) ;
module_exit(DEMO_exit) ;
MODULE_LICENSE("GPL") ;
使用cat会调用show函数,如cat kobj_test;而使用echo则相应调用store,如echo hello>kobj_test。
生成模块之后,
[root@wlqLinuxFedora10 kobj_test]# insmod kobj_test.ko
[root@wlqLinuxFedora10 wlq_kobjtest]#ls
kobj_test
用cat察看此文件:
[root@wlqLinuxFedora10 wlq_kobjtest]# cat kobj_test
kobj_test
再用echo往里面写点东西;
[root@wlqLinuxFedora10 wlq_kobjtest]# echo hello > kobj_test
Dmesg的输出如下:
sysops_show.
attr->name=attr1.
sysops_store.
write: hello
这样简洁地描述了kobj_type与kobject之间的关系,但这仅仅是复杂的设备模型的冰山一角。