1、sysfs文件系统是一种特殊的文件系统,与/proc相似,通常被安装于 /sys目录。/proc文件系统首次被设计成允许用户态应用程序访问内核内部数据结构的一种文件系统。/sysfs文件系统本质上与/proc文件系统有相同的目的,但它还提供关于内核数据结构的附加信息。(摘自深入理解Linux内核第525页)
2、sysfs文件系统的目标是要展现设备驱动程序模型组件间的层次关系。该文件系统的相应高层目录是:
block :块设备,它们独立于所连接的总线。
bus:系统中用于连接设备的总线。每个总线目录包含两个子目录:devices、drivers;devices:包含了再整个系统中发现的属于该 总线类型的设备,drivers:包含注册到该总线的所有设备驱动。
devices:所有被内核识别的硬件设备,依照连接他们的总线进行组织。
drivers:在内核中注册的设备驱动程序。
classs:系统中的设备类型(声卡、网卡、显卡等等);同一类可能包含由不同总线连接的设备,于是由不同的驱动程序驱动。(按 照功能进行分类)
power:处理一些硬件设备电源状态的文件。
firmware:处理一些硬件设备的固件文件。
3、设备驱动程序模型的核心数据结构是一个普通的数据结构,j叫做kobject,它与sysfs文件系统自然的绑定在一起:每个kobject对应于sysfs文件系统中的一个目录。kobject被嵌入一个叫做”容器“的更大的对象中,容器描述设备驱动程序模型中的组件。容器的典型例子有总线、设备以及驱动程序的描述符;例如,第一个IDE磁盘的第一个分区描述符对应于/sys/block/hda/hda1目录。
每个kobject由kobject数据结构描述,各字段如下所示:
/
char * k_name; //指向含有容器名称的字符串
char [] name; //含有容器名称的字符串
struct kref kref; //容器的引用计数器
struct list_head entry; //用于kobject所插入的链表的指针
struct kobject * parent; //指向父kobject(如果存在的话)
struct kset * kest;//指向包含的kset
struct kobj_type * ktype; //指向kobject的类型描述符
struct dentry * dentry; //指向与kobject相对应的sysfs文件的dentry数据结构
/
ktype字段指向kobj_type对象,该对象描述了kobject的 ”类型“,本质上它描述的是包括kobject的容器的类型。kobj_type数据结构包括三个字段:release方法(当kobject被释放时执行),指向sysfs操作表的sysfs_ops指针以及sysfs文件系统的缺省属性链表。
struct attribute{
const char *name;//属性文件名
struct module *owner;
mode_t mode;
}
4、kobject对象操作
1)voidkobject_init(struct kobject * kobj)初始化kobject结构
2)intkobject_add(struct kobject * kobj)将kobject对象注册到Linux系统
3)intkobject_init_and_add(struct kobject *kobj, struct kobj_type*ktype,struct kobject *parent, const char *fmt, ...)初始化kobject,并将其注册到linux系统
4)voidkobject_del(struct kobject * kobj)从Linux系统中删除kobject对象
5)structkobject *kobject_get(struct kobject*kobj)将kobject对象的引用计数加1,同时返回该对象指针。
6)voidkobject_put(struct kobject *kobj)将kobject对象的引用计数减1,如果引用计数降为0,则调用release方法释放该kobject对象。
5、下面是一个简单的kobject的例子:
#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>
MODULE_AUTHOR("David Xie");//定义驱动的编程者为 "David Xie"
MODULE_LICENSE("Dual BSD/GPL");//告诉内核,该模块采用自由许可证
void obj_test_release(struct kobject *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);
struct attribute test_attr = {//sysfs文件系统的属性
.name = "kobj_config", //属性文件名称
.mode = S_IRWXUGO, //属性文件访问权限
};
static struct attribute *def_attrs[] = {
&test_attr,
NULL,
};
//struct sysfs_ops中包含show和store两个函数指针,它们分别在sysfs文件读和文件写时调用。
struct sysfs_ops obj_test_sysops =
{
.show = kobj_test_show,
.store = kobj_test_store,
};
struct kobj_type ktype =
{
.release = obj_test_release,//kobject释放的时候被调用
.sysfs_ops=&obj_test_sysops,//操作的函数
.default_attrs=def_attrs,//属性
};
void obj_test_release(struct kobject *kobject)
{
printk("eric_test: release .\n");
}
ssize_t kobj_test_show(struct kobject *kobject, struct attribute *attr,char *buf)
{
printk("have show.\n");
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("havestore\n");
printk("write: %s\n",buf);
return count;
}
struct kobject kobj;
static int kobj_test_init()
{
printk("kboject test init.\n");
kobject_init_and_add(&kobj,&ktype,NULL,"kobject_test");
return 0;
}
static int kobj_test_exit()
{
printk("kobject test exit.\n");
kobject_del(&kobj);
return 0;
}
module_init(kobj_test_init);//insmod时候,调用初始化函数
module_exit(kobj_test_exit);//rmmod,调用退出函数
///
假设这个代码,编译后的模块的名称为kobject.ko,则运行结果如下
insmod kobject.ko
kboject test init.
lsmod
kobject 1884 0 - Live 0xbf000000
此时在查看/sys文件的时候,发现多了一个名称为"kobject_test"文件夹。
进入kobject_test目录,会发现多了一个文件
cd kobject_test
ls
kobj_config