初识Linux设备驱动模型与sysfs(1)


1 sysfs 是什么
”sysfs is a ram-based filesystem initially based on ramfs. It provides a means
to export kernel data structures, their attributes, and the linkages between them to userspace.“ --sysfs.txt
一种虚拟的基于内存的文件系统,
除了与 proc 相同的具有查看和设定内核参数功能之外,更重要的是为 Linux 统一设备模型作为管理之用。

新设计的内核机制应该尽量使用 sysfs 机制,而将 proc 保留给纯净的“进程文件系统”。
sysfs 文件系统总是被挂载在 /sys 挂载点上。

2 /sys文件系统的目录
/sys 目录下有 block, bus, , devices, firmware, fs, kernel, module, power 等,
这些目录展示了内核对各种设备进行统一管理的模型和方式。
/sys/devices   
这是内核对系统中所有设备的分层次表达模型,也是 /sys 文件系统管理设备的最重要的目录结构。

/sys/dev
这个目录下维护一个按字符设备和块设备的主次号码(major:minor)链接到真实的设备(/sys/devices下)的符号链接文件。

/sys/bus   
内核设备按总线类型分层放置的目录结构, devices 中的所有设备都是连接于某种总线之下,在这里的每一种具体总线之下可以找到每一个具体设备的符号链接.

/sys/class   
这是按照设备功能分类的设备模型,如系统所有输入设备都会出现在 /sys/class/input 之下,而不论它们是以何种总线连接到系统。

/sys/block   
系统中当前所有的块设备所在
(有资料说, 在 2.6.26 内核中已正式移到 /sys/class/block, 旧的接口 /sys/block 为了向后兼容保留存在,但其中的内容已经变为指向它们在 /sys/devices/ 中真实设备的符号链接文件,但好像不对)

/sys/firmware   
系统加载固件机制的对用户空间的接口

/sys/fs   
这里按照设计是用于描述系统中所有文件系统,包括文件系统本身和按文件系统分类存放的已挂载点,但目前只有 fuse,gfs2 等少数文件系统支持 sysfs 接口,一些传统的虚拟文件系统(VFS)层次控制参数仍然在 sysctl (/proc/sys/fs) 接口中中;

/sys/kernel   
这里是内核所有可调整参数的位置,目前只有 uevent_helper, kexec_loaded, mm, 和新式的 slab 分配器等几项较新的设计在使用它,其它内核可调整参数仍然位于 sysctl (/proc/sys/kernel) 接口中 ;

/sys/module   
这里有系统中所有模块的信息,不论这些模块是以内联(inlined)方式编译到内核映像文件(vmlinuz)中还是编译为外部模块(ko文件),都可能会出现在 /sys/module 中:

    * 编译为外部模块(ko文件)在加载后会出现对应的 /sys/module/<module_name>/, 并且在这个目录下会出现一些属性文件和属性目录来表示此外部模块的一些信息,如版本号、加载状态、所提供的驱动程序等;
    * 编译为内联方式的模块则只在当它有非0属性的模块参数时会出现对应的 /sys/module/<module_name>, 这些模块的可用参数会出现在 /sys/modules/<modname>/parameters/<param_name> 中,
          o 如 /sys/module/printk/parameters/time 这个可读写参数控制着内联模块 printk 在打印内核消息时是否加上时间前缀;
          o 所有内联模块的参数也可以由 "<module_name>.<param_name>=<value>" 的形式写在内核启动参数上,如启动内核时加上参数 "printk.time=1" 与 向 "/sys/module/printk/parameters/time" 写入1的效果相同;
    * 没有非0属性参数的内联模块不会出现于此。

/sys/power   
这里是系统中电源选项,这个目录下有几个属性文件可以用于控制整个机器的电源状态,如可以向其中写入控制命令让机器关机、重启等。


sysfs的底层结构 kset、kobj

Linux 统一设备模型的基本结构主要为:
1 设备  2 设备驱动   3 总线类型   4 设备类别  

-设备(Devices)
设备是此模型中最基本的类型,以设备本身的连接按层次组织,对应于内核的struct device数据结构,位于/sys/devices
-设备驱动(Device Drivers)
为设备提供驱动支持,管理驱动程序,对应于内核中的struct device_driver数据结构
-总线类型(Bus Types)  
在整个总线级别对此总线上连接的所有设备进行管理,内核struct bus_type数据结构 位于/sys/bus/
-设备类别(Device Classes)
这是按照功能进行分类组织的设备层次树;如 USB 接口和 PS/2 接口的鼠标都是输入设备,都会出现在/sys/class/input/ 下
当向系统添加一个/种设备的设备驱动时,需要定义相应的总线类型(struct bus_type)和设备类型(struct device),并调用提供的函数进行相应的注册(bus_register(), device_register())、初始化等。

而Linux 统一设备模型以kset和kobject两种基本数据结构进行树型和链表型结构来组织以上单元:

kobject: 在 Linux 设备模型中最基本的对象,bus,devices, drivers等通过kobject连接起来,形成了一个树状结构,这个树状结构就与/sys向对应。
kobject 结构为一些大的数据结构和子系统提供了基本的对象管理,避免了类似机能的重复实现。这些机能包括
- 对象引用计数.
- 维护对象链表(集合).
- 对象上锁.
- 在用户空间的表示.

struct kobject {
const char *name;
struct list_head entry;
struct kobject *parent;
struct 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;
};

其中 struct kref 内含一个 atomic_t 类型用于引用计数, parent 是单个指向父节点的指针, entry 用于父 kset 以链表头结构将 kobject 结构维护成双向链表;

 kset: 它用来对同类型对象提供一个包装集合,在内核数据结构上它也是由内嵌一个 kboject 实现,因而它同时也是一个 kobject (面向对象 OOP 概念中的继承关系) ,具有 kobject 的全部功能;

struct kset {
struct list_head list;
spinlock_t list_lock;
struct kobject kobj;
struct kset_uevent_ops *uevent_ops;
};

其中的 struct list_head list 用于将集合中的 kobject 按 struct list_head entry 维护成双向链表;

kset与kobj相互包含,Kobject通过kset组织成层次化的结构,kset是具有相同类型的kobject的集合,更多的是一种组合关系,用组合的方式来实现面向对象的思想,而不是继承。这样理解对不?


那么,疑问是,为什么要通过纷繁复杂的连接来实现这样一个设备驱动模型呢??


参考文章:

使用 /sys 文件系统访问 Linux 内核
Linux那些事儿之我是Sysfs

你可能感兴趣的:(数据结构,linux,list,struct,Module,attributes)