xref: /DragonOS/docs/kernel/filesystem/sysfs.md (revision e0de0fd6a52199753a3127cfbb5d12f0a1555aae)
1*e0de0fd6STingHuang# SysFS
2*e0de0fd6STingHuang
3*e0de0fd6STingHuang:::{note}
4*e0de0fd6STingHuang本文作者:黄厅
5*e0de0fd6STingHuang
6*e0de0fd6STingHuangEmail: <huangting@DragonOS.org>
7*e0de0fd6STingHuang:::
8*e0de0fd6STingHuang
9*e0de0fd6STingHuang## 1. SysFS和设备驱动模型
10*e0de0fd6STingHuang
11*e0de0fd6STingHuang### 1.1. 设备、驱动、总线等彼此之间关系错综复杂
12*e0de0fd6STingHuang
13*e0de0fd6STingHuang&emsp;&emsp;如果想让内核运行流畅,那就必须为每个模块编码实现这些功能。如此一来,内核将变得非常臃肿、冗余。而设备模型的理念即是将这些代码抽象成各模块共用的框架,这样不但代码简洁了,也可让设备驱动开发者摆脱这本让人头痛但又必不可少的一劫,将有限的精力放于设备差异性的实现。
14*e0de0fd6STingHuang
15*e0de0fd6STingHuang&emsp;&emsp;设备模型恰是提供了一个模板,一个被证明过的最优的思路和流程,这减少了开发者设计过程中不必要的错误,也给以后的维护扫除了障碍。
16*e0de0fd6STingHuang
17*e0de0fd6STingHuang### 1.2. sysfs是一个基于内存的文件系统,它的作用是将内核信息以文件的方式提供给用户程序使用。
18*e0de0fd6STingHuang
19*e0de0fd6STingHuang&emsp;&emsp;sysfs可以看成与proc,devfs和devpty同类别的文件系统,该文件系统是虚拟的文件系统,可以更方便对系统设备进行管理。它可以产生一个包含所有系统硬件层次视图,与提供进程和状态信息的proc文件系统十分类似。sysfs把连接在系统上的设备和总线组织成为一个分级的文件,它们可以由用户空间存取,向用户空间导出内核的数据结构以及它们的属性。
20*e0de0fd6STingHuang
21*e0de0fd6STingHuang## 2. DragosOS中的设备驱动模型
22*e0de0fd6STingHuang
23*e0de0fd6STingHuang### 2.1 由设备和驱动构成基本元素
24*e0de0fd6STingHuang
25*e0de0fd6STingHuang#### 2.1.1. 设备
26*e0de0fd6STingHuang
27*e0de0fd6STingHuang```rust
28*e0de0fd6STingHuang/// @brief: 所有设备都应该实现该trait
29*e0de0fd6STingHuangpub trait Device: Any + Send + Sync + Debug {}
30*e0de0fd6STingHuang```
31*e0de0fd6STingHuang
32*e0de0fd6STingHuang&emsp;&emsp;DragonOS采用全局设备管理器管理系统中所有的设备。
33*e0de0fd6STingHuang
34*e0de0fd6STingHuang```rust
35*e0de0fd6STingHuang/// @brief Device管理器
36*e0de0fd6STingHuang#[derive(Debug, Clone)]
37*e0de0fd6STingHuangpub struct DeviceManager {
38*e0de0fd6STingHuang    devices: BTreeMap<IdTable, Arc<dyn Device>>, // 所有设备
39*e0de0fd6STingHuang    sys_info: Option<Arc<dyn IndexNode>>,  // sys information
40*e0de0fd6STingHuang}
41*e0de0fd6STingHuang```
42*e0de0fd6STingHuang
43*e0de0fd6STingHuang#### 2.1.2. 驱动
44*e0de0fd6STingHuang
45*e0de0fd6STingHuang```rust
46*e0de0fd6STingHuang/// @brief: 所有驱动驱动都应该实现该trait
47*e0de0fd6STingHuangpub trait Driver: Any + Send + Sync + Debug {}
48*e0de0fd6STingHuang```
49*e0de0fd6STingHuang
50*e0de0fd6STingHuang&emsp;&emsp;同样的,驱动也使用全局的驱动管理器来管理
51*e0de0fd6STingHuang
52*e0de0fd6STingHuang```rust
53*e0de0fd6STingHuang/// @brief: 驱动管理器
54*e0de0fd6STingHuang#[derive(Debug, Clone)]
55*e0de0fd6STingHuangpub struct DriverManager {
56*e0de0fd6STingHuang    drivers: BTreeMap<IdTable, Arc<dyn Driver>>, // 所有驱动
57*e0de0fd6STingHuang    sys_info: Option<Arc<dyn IndexNode>>, // sys information
58*e0de0fd6STingHuang}
59*e0de0fd6STingHuang```
60*e0de0fd6STingHuang
61*e0de0fd6STingHuang### 2.2. 总线
62*e0de0fd6STingHuang
63*e0de0fd6STingHuang&emsp;&emsp;总线属于设备的一种类型,同样需要驱动来初始化,同时由于总线的特殊性,使用全局的总线管理器来进行管理。
64*e0de0fd6STingHuang
65*e0de0fd6STingHuang```rust
66*e0de0fd6STingHuang/// @brief: 总线驱动trait,所有总线驱动都应实现该trait
67*e0de0fd6STingHuangpub trait BusDriver: Driver {}
68*e0de0fd6STingHuang
69*e0de0fd6STingHuang/// @brief: 总线设备trait,所有总线都应实现该trait
70*e0de0fd6STingHuangpub trait Bus: Device {}
71*e0de0fd6STingHuang
72*e0de0fd6STingHuang/// @brief: 总线管理结构体
73*e0de0fd6STingHuang#[derive(Debug, Clone)]
74*e0de0fd6STingHuangpub struct BusManager {
75*e0de0fd6STingHuang    buses: BTreeMap<IdTable, Arc<dyn Bus>>,          // 总线设备表
76*e0de0fd6STingHuang    bus_drvs: BTreeMap<IdTable, Arc<dyn BusDriver>>, // 总线驱动表
77*e0de0fd6STingHuang    sys_info: Option<Arc<dyn IndexNode>>,            // 总线inode
78*e0de0fd6STingHuang}
79*e0de0fd6STingHuang```
80*e0de0fd6STingHuang
81*e0de0fd6STingHuang&emsp;&emsp;可以看到,每个管理器中均存在sys_info,设备模型通过该成员与sysfs建立联系,sys_info指向sysfs中唯一的inode。对于device而言,对应sysfs下的devices文件夹,其他亦是如此。
82*e0de0fd6STingHuang
83*e0de0fd6STingHuang## 3. 驱动开发如何进行
84*e0de0fd6STingHuang
85*e0de0fd6STingHuang&emsp;&emsp;以平台总线platform为例,platform总线是一种虚拟总线,可以对挂载在其上的设备和驱动进行匹配,并驱动设备。该总线是一类设备,同时也是一类总线,编程时需要创建该设备实例,并为设备实例实现Device trait和Bus trait,以表明该结构是一类总线设备。同时,应该实现总线上的匹配规则,不同的总线匹配规则不同,该总线采用匹配表方式进行匹配,设备和驱动都应该存在一份匹配表,表示驱动支持的设备以及设备支持的驱动。
86*e0de0fd6STingHuang
87*e0de0fd6STingHuang```rust
88*e0de0fd6STingHuangpub struct CompatibleTable(BTreeSet<&'static str>);
89*e0de0fd6STingHuang```
90*e0de0fd6STingHuang
91*e0de0fd6STingHuang&emsp;&emsp;对于bus设备而言,需要调用bus_register,将bus注册进系统,并在sysfs中可视化。
92*e0de0fd6STingHuang
93*e0de0fd6STingHuang```rust
94*e0de0fd6STingHuang/// @brief: 总线注册,将总线加入全局总线管理器中,并根据id table在sys/bussys/devices下生成文件夹
95*e0de0fd6STingHuang/// @parameter bus: Bus设备实体
96*e0de0fd6STingHuang/// @return: 成功:()   失败:DeviceError
97*e0de0fd6STingHuangpub fn bus_register<T: Bus>(bus: Arc<T>) -> Result<(), DeviceError> {
98*e0de0fd6STingHuang    BUS_MANAGER.add_bus(bus.get_id_table(), bus.clone());
99*e0de0fd6STingHuang    match sys_bus_register(&bus.get_id_table().to_name()) {
100*e0de0fd6STingHuang        Ok(inode) => {
101*e0de0fd6STingHuang            let _ = sys_bus_init(&inode);
102*e0de0fd6STingHuang            return device_register(bus);
103*e0de0fd6STingHuang        }
104*e0de0fd6STingHuang        Err(_) => Err(DeviceError::RegisterError),
105*e0de0fd6STingHuang    }
106*e0de0fd6STingHuang}
107*e0de0fd6STingHuang```
108*e0de0fd6STingHuang
109*e0de0fd6STingHuang&emsp;&emsp;通过bus_register源码可知,该函数不仅在sysfs/bus下生成总线文件夹,同时内部调用device_register,该函数将总线加入设备管理器中,同时在sys/devices下生成设备文件夹。
110