linux驱动是一个整体的设备模型,这个模型是以kobject和kset作为基石的,因此搞懂kset和kobject的内部运作关系才能很好的理解统一设备模型.
首先linux对设备的抽象就是将设备描述为一个文件节点,因为设备有属性,比如说亮度、颜色等。因此kobject也就有属性.有了属性还要有统一的读写接口,写入的属性值通过内部再真正写到设备里面去.因此可以将一个kobject看成一个文件夹,里面有许多文件,一个文件描述一个属性.
而kset就可以看成是一个更大的文件夹,可以理解为类别,比如将所有驱动看成一个文件夹,这个文件夹是一个kset,然后这个文件夹下面有许多具体的驱动,这些驱动看成kobject.
先上图再看代码
struct kobject {
const char *name; //名称,文件名称
struct list_head entry; //同一级kobject链接结点
struct kobject *parent; //指向父级的kobject
struct kset *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;
};
struct kset {
struct list_head list; //连接下一级的链接结点
spinlock_t list_lock; //当链接结点时的锁
struct kobject kobj; //kset本身包含一个kobject对象
struct kset_uevent_ops *uevent_ops;
};
举个例子:
#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>
void obj_test_release(struct 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);MODULE_LICENSE("Dual BSD/GPL");
void obj_test_release(struct kobject *kobj)
{
printk("%s release\n", kobj->name);
}
ssize_t kobj_test_show(struct kobject *kobject,
struct attribute *attr,char *buf)
{
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("store\n");
printk("write %s\n", buf);
return count;
}
struct attribute test1 = {
"kobject_test1",
THIS_MODULE,
S_IRWXUGO,
};
struct attribute test2 = {
"kobject_test2",
THIS_MODULE,
S_IRUGO|S_IWUGO,
};
struct attribute *attr[] = {
&test1,
&test2,
NULL,
};
struct sysfs_ops fops = {
//对结点读写的操作函数
kobj_test_show,
kobj_test_store,
};
struct kobject kobj;
struct kobj_type ktype = {
obj_test_release,
&fops,
attr,
};
static int kobj_test_init(void)
{
printk("enter kobj_test_init\n");
kobject_init_and_add(&kobj, &ktype, NULL, "kobject_config");
return 0;
}
static void kobj_test_exit(void)
{
printk("exit kobj\n");
kobject_del(&kobj);
//return 0;
}
module_init(kobj_test_init);
module_exit(kobj_test_exit);
MODULE_LICENSE("Dual BSD/GPL");
上面这段代码运行之后,会在/sys目录下面产生一个kobject_config目录,这个目录下面有两个文件kobject_test,kobject_test2.这两个文件可以写入和读出内容.
常用的操作kobject和kset的接口如下:
void kobject_init(struct kobject *kobj, struct kobj_type *ktype);
int kobject_add(struct kobject *kobj, struct kobject *parent,
const char *fmt, ...);
这些函数的逻辑其实就是要理解上面的图.