首页 最新 热门 推荐

  • 首页
  • 最新
  • 热门
  • 推荐

Linux 的 sysfs 伪文件系统介绍【用户可以通过文件操作与内核交互(如调用内核函数),而无需编写内核代码】

  • 25-03-05 03:28
  • 3834
  • 8380
blog.csdn.net

1. 什么是 sysfs伪文件系统?

sysfs 是 Linux 内核提供的 伪文件系统,用于向用户空间暴露内核对象的信息和控制接口。它是 procfs 的补充,主要用于管理 设备、驱动、内核子系统 等信息,使用户可以通过文件操作(如用户空间中的open函数、write函数、read函数、 cat命令、echo命令)与内核交互【对文件的操作其实直接转换为调用相应的内核函数】,而无需编写内核代码。

  • 挂载位置:通常挂载在 /sys 目录下。
  • 作用:
    • 提供系统信息(如 CPU、设备、驱动程序、总线)。
    • 提供设备控制接口(如 GPIO、PWM、I2C、SPI 等)。
    • 支持热插拔设备管理(如 USB、PCI、SATA 设备)。

sysfs伪文件系统实际上和设备文件很类似,它们都是用户空间与内核空间交互的媒介,不同的是设备文件是内核空间中驱动程序中的概念,而sysfs伪文件系统则是内核空间中别的需要向用户空间暴露的内核对象的信息和控制接口。所以它的使用实际上和设备文件很类似。

在终端中使用sysfs伪文件系统时,表面上我们是在用相关函数或cat、echo命令进行读或写相关的文件,实际上会转换为对某个内核函数的调用。具体的例子见本篇博文后面列出的“一个实际的例子分析”
而在程序代码中使用sysfs伪文件系统时,就和操作设备文件差不多。具体的例子见 http://iyenn.com/rec/1709286.html【搜索“led_init(void)”】


2. sysfs 的目录结构

sysfs 目录下的结构主要分为以下几部分:

/sys/
 ├── block/            # 块设备(如磁盘、分区)
 ├── bus/              # 设备总线(如 i2c, usb, spi, pci, platform)
 ├── class/            # 设备类(如 gpio, net, tty, input)
 ├── devices/          # 设备层次结构
 ├── firmware/         # 固件接口
 ├── kernel/           # 内核参数
 ├── module/           # 加载的内核模块
 └── power/            # 电源管理
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

3. sysfs 目录详解

(1)/sys/class/

  • 组织 设备 按类别分类(如 GPIO、网络、输入设备)。

  • 例子:

    ls /sys/class/
    
    • 1

    输出:

    gpio/   net/   input/   sound/   thermal/   tty/   usb_device/
    
    • 1
  • GPIO 设备(使用 sysfs 方式操作 GPIO)

    echo 131 > /sys/class/gpio/export    # 申请 GPIO 131
    echo out > /sys/class/gpio/gpio131/direction   # 设置方向
    echo 1 > /sys/class/gpio/gpio131/value   # 设为高电平
    
    • 1
    • 2
    • 3

    我后面会对这三句命令作详细解释,其实就是以这三句命令活生生地展现 sysfs 伪文件系统是怎么实现与内核的交互的。

  • 网卡信息

    ls /sys/class/net/
    eth0  lo  wlan0
    
    • 1
    • 2
    • cat /sys/class/net/eth0/address # 查看 MAC 地址
    • cat /sys/class/net/eth0/statistics/rx_bytes # 接收的字节数

(2)/sys/bus/

  • 组织 设备按总线分类(如 PCI、USB、I2C、SPI)。

  • 例子:

    ls /sys/bus/
    
    • 1

    输出:

    i2c/   pci/   platform/   scsi/   spi/   usb/
    
    • 1
    • /sys/bus/i2c/devices/ # I2C 设备
    • /sys/bus/usb/devices/ # USB 设备
    • /sys/bus/pci/devices/ # PCI 设备
  • 示例:列出所有 USB 设备

    ls /sys/bus/usb/devices/
    
    • 1

(3)/sys/devices/

  • 按 设备拓扑结构 组织设备信息(如 /sys/devices/pci0000:00/0000:00:1f.2/)。

  • 例子:

    ls /sys/devices/
    
    • 1
    system/  virtual/  pci0000:00/
    
    • 1
  • 查看 CPU 信息

    cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor
    
    • 1

(4)/sys/module/

  • 显示 已加载的内核模块 及其参数。
  • 例子:
    ls /sys/module/
    
    • 1
    • cat /sys/module/gpio/parameters/
    • cat /sys/module/usbcore/parameters/autosuspend

(5)/sys/kernel/

  • 提供与 内核相关的配置信息。

  • 例子:

    ls /sys/kernel/
    
    • 1
    debug/   security/   tracing/
    
    • 1
  • 查看系统调试信息

    cat /sys/kernel/debug/gpio
    
    • 1

4. sysfs 的工作机制

  • sysfs 由 kobject 和 kset 组成:
    • kobject 代表 内核对象(如设备、驱动)。
    • kset 是 kobject 的集合(如 devices、bus)。
  • 设备驱动注册时,sysfs 自动创建目录和文件。
  • 用户空间可以通过 cat、echo 直接访问内核数据。

示例:
设备驱动代码:

static struct class *my_class;
my_class = class_create(THIS_MODULE, "my_device");
device_create(my_class, NULL, MKDEV(200, 0), NULL, "mydev0");
  • 1
  • 2
  • 3

sysfs 生成的目录:

/sys/class/my_device/mydev0/
  • 1

5. sysfs 的优缺点

优点缺点
允许用户空间与内核交互只能操作文本,效率低
结构清晰,按类别组织不适用于高频操作
可用于设备驱动调试已被 libgpiod 等替代

6. sysfs 与 udev、procfs 的区别

文件系统作用特点
sysfs (/sys/)设备、驱动、总线信息设备管理,与 kobject 相关
procfs (/proc/)进程、内核信息进程管理,虚拟文件
udev (/dev/)设备文件动态创建 /dev/ 设备节点

7. 结论

  • sysfs 是 Linux 设备模型的核心部分,用于暴露设备和驱动信息。
  • 用户空间可以直接 cat 读取信息,echo 进行控制,简化了驱动开发。
  • sysfs 已逐渐被 libgpiod、udev 替代,但仍然广泛使用,特别是在嵌入式系统中。

8.一个实际的例子分析

我们可以通过下面的三条命令实现将编号为131的GPIO口(GPIO5_IO03)的值设为逻辑1值,如果GPIO没有被标记为低电平有效,则逻辑1值就是物理上的高电平,否则就是物理上的低电平,在这里,我实测了一下,GPIO5_IO03并没有被标记为低电平有效。即运行完成后在下面的原理图基础上,灯灭了。
在这里插入图片描述

echo 131 > /sys/class/gpio/export
echo out > /sys/class/gpio/gpio131/direction
echo 1 > /sys/class/gpio/gpio131/value
  • 1
  • 2
  • 3

这三条命令是通过 sysfs 接口 操作 GPIO 口 131,本质上是用户空间通过 echo 命令向 sysfs 伪文件系统写入数据,触发内核的 GPIO 相关操作【实际上就是去调用内核中的相关GPIO子系统的函数】。

在看下面的分析前可以参考下博文 http://iyenn.com/rec/1709341.html 是如何利用GPIO子系统实现LED灯的驱动的,实际上这篇博文中调用的函数也就是下面三条echo命令触发的内核函数。


1. echo 命令与 sysfs GPIO 实现的关系

echo 命令的作用是 向文件写入内容,但当目标文件是 sysfs 文件时,写入的值会被内核的 GPIO 处理函数拦截,并执行相应的 GPIO 操作。

下面具体分析你的 echo 命令是如何作用到 GPIO 上的:

(1)导出 GPIO

echo 131 > /sys/class/gpio/export
  • 1
  • 作用:请求使用 GPIO 131,让内核创建 /sys/class/gpio/gpio131/ 目录。

  • sysfs 机制:

    1. echo 131 > /sys/class/gpio/export 相当于向 export 文件 写入 131。
    2. 内核中的 export_store() 处理该写入,并调用 gpio_request(131, NULL) 申请 GPIO 资源。
    3. 申请成功后,内核会创建 /sys/class/gpio/gpio131/ 目录,用于控制 GPIO 131。
  • 相关的内核代码(在 drivers/gpio/gpiolib-sysfs.c 中):

    static ssize_t export_store(struct class *class,
                                struct class_attribute *attr,
                                const char *buf, size_t count)
    {
        int gpio;
        int ret;
    
        ret = kstrtoint(buf, 0, &gpio);
        if (ret)
            return ret;
    
        ret = gpio_request(gpio, NULL);
        if (ret)
            return ret;
    
        return count;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

(2)设置 GPIO 方向

echo out > /sys/class/gpio/gpio131/direction
  • 1
  • 作用:设置 GPIO 131 为 输出模式。

  • sysfs 机制:

    1. echo out > /sys/class/gpio/gpio131/direction 相当于向 direction 文件 写入字符串 "out"。
    2. gpio_direction_output(131, 0) 被调用,将 GPIO 131 配置为 输出模式(初始值 0)。
    3. 内核 GPIO 驱动最终会调用 gpio_chip->direction_output() 这个函数,该函数是具体的 GPIO 控制器驱动 提供的,执行底层的寄存器操作,配置 GPIO 方向。
  • 相关的内核代码(在 drivers/gpio/gpiolib-sysfs.c 中):

    static ssize_t direction_store(struct device *dev,
                                   struct device_attribute *attr,
                                   const char *buf, size_t count)
    {
        struct gpio_desc *desc = dev_get_drvdata(dev);
    
        if (!strncmp(buf, "out", 3))
            gpiod_direction_output(desc, 0);
        else
            gpiod_direction_input(desc);
    
        return count;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

(3)设置 GPIO 输出值

echo 1 > /sys/class/gpio/gpio131/value
  • 1
  • 作用:设置 GPIO 131 输出 高电平(1)。

  • sysfs 机制:

    1. echo 1 > /sys/class/gpio/gpio131/value 向 value 文件 写入 "1"。
    2. gpio_set_value(131, 1) 被调用,更新 GPIO 131 的输出电平。
    3. 底层驱动(gpio_chip->set())负责具体的寄存器操作,将 GPIO 置高。
  • 相关的内核代码(在 drivers/gpio/gpiolib-sysfs.c 中):

    static ssize_t value_store(struct device *dev,
                               struct device_attribute *attr,
                               const char *buf, size_t count)
    {
        struct gpio_desc *desc = dev_get_drvdata(dev);
        int value;
    
        if (buf[0] == '0')
            value = 0;
        else
            value = 1;
    
        gpiod_set_value(desc, value);
    
        return count;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

2. sysfs GPIO 实现的局限

虽然 sysfs 提供了一种 简单的方式 来访问 GPIO,但它有以下局限性:

  1. 效率低:sysfs 通过文件操作控制 GPIO,比 ioctl 或 mmap 慢。
  2. 无法高效处理中断:sysfs 方式不适合监听 GPIO 变化(如按键)。
  3. 已被 libgpiod 取代:新版本的 Linux 内核推荐使用 libgpiod(基于 ioctl 的 GPIO 操作)。

3. 结论

? sysfs 方式是 Linux 早期的 GPIO 控制方法,echo 命令本质上是向 sysfs 伪文件系统写入数据,触发内核调用 GPIO 操作函数。
? 每个 echo 命令最终都会调用 gpiolib 提供的 API,如 gpio_request()、gpio_direction_output() 和 gpio_set_value(),再由底层 GPIO 驱动完成实际的硬件操作。
? sysfs 方式简单直观,但不适用于高效 GPIO 访问,现代 Linux 推荐使用 libgpiod 代替 sysfs GPIO。(实际上在Linux 5.10以上版本中已经把sysfs这种对GPIO的操作方式废弃了)
比如上面的三条命令等效于下面这条gpiod API的命令:

gpioset gpiochip0 131=1
  • 1
昊虹嵌入式技术交流群
QQ群名片
注:本文转载自blog.csdn.net的昊虹AI笔记的文章"https://blog.csdn.net/wenhao_ir/article/details/145453877"。版权归原作者所有,此博客不拥有其著作权,亦不承担相应法律责任。如有侵权,请联系我们删除。
复制链接
复制链接
相关推荐
发表评论
登录后才能发表评论和回复 注册

/ 登录

评论记录:

未查询到任何数据!
回复评论:

分类栏目

后端 (14832) 前端 (14280) 移动开发 (3760) 编程语言 (3851) Java (3904) Python (3298) 人工智能 (10119) AIGC (2810) 大数据 (3499) 数据库 (3945) 数据结构与算法 (3757) 音视频 (2669) 云原生 (3145) 云平台 (2965) 前沿技术 (2993) 开源 (2160) 小程序 (2860) 运维 (2533) 服务器 (2698) 操作系统 (2325) 硬件开发 (2492) 嵌入式 (2955) 微软技术 (2769) 软件工程 (2056) 测试 (2865) 网络空间安全 (2948) 网络与通信 (2797) 用户体验设计 (2592) 学习和成长 (2593) 搜索 (2744) 开发工具 (7108) 游戏 (2829) HarmonyOS (2935) 区块链 (2782) 数学 (3112) 3C硬件 (2759) 资讯 (2909) Android (4709) iOS (1850) 代码人生 (3043) 阅读 (2841)

热门文章

101
推荐
关于我们 隐私政策 免责声明 联系我们
Copyright © 2020-2025 蚁人论坛 (iYenn.com) All Rights Reserved.
Scroll to Top