Linux设备驱动模型之Sysfs

Sysfs 是 Linux 设备驱动模型中至关重要的组成部分,它通过虚拟文件系统 /sys 向用户空间暴露内核对象(如设备、驱动、总线等)的属性和关系。作为驱动开发者,理解 Sysfs 的作用和实现机制,能够帮助你更好地调试设备、动态配置硬件,并与用户空间工具(如 udev)交互。


1. Sysfs 的核心概念

  • 虚拟文件系统:挂载在 /sys 目录下,以文件和目录的形式展示内核对象(kobject)的层次结构。
  • 内核对象(kobject)​:Sysfs 的基础单元,每个 kobject 对应 /sys 中的一个目录,例如:
    • /sys/bus(总线)、/sys/devices(设备)、/sys/class(设备类)等。
  • 属性(Attribute)​:文件的抽象,表示内核对象的某个属性(如设备名称、状态、配置参数等),支持读写操作。

2. Sysfs 与 kobject 的关系

Sysfs 的目录结构由内核对象(kobject)的层次关系决定:

  • kobject 是内核中所有对象的基础结构(如 struct devicestruct device_driver 内部均包含 kobject)。
  • 每个 kobject 在 Sysfs 中对应一个目录,其父 kobject 决定目录的位置。
  • 示例
    /sys/devices/pci0000:00/0000:00:1c.0/0000:03:00.0/   # PCI 设备目录
      ├── power/       # 电源管理属性
      ├── vendor       # 只读文件,设备厂商 ID
      └── uevent       # 发送 uevent 事件的文件

3. 属性(Attribute)的实现

属性文件允许用户空间通过读写文件与内核交互。驱动开发者需要为设备或驱动定义属性,并实现其读写函数。

3.1 定义属性

使用 struct device_attribute 或宏 DEVICE_ATTR 定义属性:

// 定义属性结构体
static DEVICE_ATTR(foo, 0644, show_foo, store_foo);

// 实现读写函数
static ssize_t show_foo(struct device *dev, 
                        struct device_attribute *attr, 
                        char *buf) {
    return sprintf(buf, "%d\n", device_foo_value(dev));
}

static ssize_t store_foo(struct device *dev,
                         struct device_attribute *attr,
                         const char *buf, size_t count) {
    int value;
    sscanf(buf, "%d", &value);
    device_set_foo_value(dev, value);
    return count;
}
3.2 创建/删除属性文件

在设备注册时创建属性文件,注销时删除:

// 在 probe 函数中创建属性
device_create_file(&my_device->dev, &dev_attr_foo);

// 在 remove 函数中删除属性
device_remove_file(&my_device->dev, &dev_attr_foo);

4. Sysfs 的典型应用场景

4.1 设备调试与配置
  • 查看设备信息
    cat /sys/devices/pci0000:00/0000:00:1c.0/0000:03:00.0/vendor
  • 动态修改参数
    echo 1 > /sys/class/gpio/gpio17/value  # 控制 GPIO 电平
4.2 与 udev 交互
  • uevent 事件:当设备状态变化时(如插入 USB 设备),内核通过 Sysfs 的 uevent 文件触发事件,用户空间的 udev 根据规则创建设备节点(如 /dev/sda)。

5. 驱动开发中的 Sysfs 操作示例

5.1 定义一个 LED 控制属性
#include <linux/device.h>

static ssize_t led_show(struct device *dev, 
                       struct device_attribute *attr, 
                       char *buf) {
    return sprintf(buf, "LED state: %s\n", led_get_state() ? "ON" : "OFF");
}

static ssize_t led_store(struct device *dev,
                        struct device_attribute *attr,
                        const char *buf, size_t count) {
    int state;
    if (sscanf(buf, "%d", &state) != 1)
        return -EINVAL;
    led_set_state(state);
    return count;
}

// 定义属性
static DEVICE_ATTR(led, 0644, led_show, led_store);

// 注册属性(在 probe 函数中)
device_create_file(dev, &dev_attr_led);

// 用户空间操作示例:
// echo 1 > /sys/devices/.../my_device/led  # 点亮 LED
// cat /sys/devices/.../my_device/led       # 查看状态
5.2 通过 Sysfs 暴露设备统计信息...................................................
static ssize_t stats_show(struct device *dev,
                         struct device_attribute *attr,
                         char *buf) {
    return sprintf(buf, "Interrupts: %u\nBytes Transferred: %lu\n",
                   dev->interrupt_count, dev->bytes_transferred);
}
static DEVICE_ATTR_RO(stats);  // 只读属性宏

6. 注意事项

  1. 权限控制:属性文件的权限需合理设置(如 0644 表示用户可读写,其他用户只读)。
  2. 并发安全:确保读写函数(show/store)是线程安全的,必要时使用锁。
  3. 避免过度暴露:仅暴露必要的属性,防止敏感信息泄漏。
  4. 内存管理show 函数中的 sprintf 需确保缓冲区不溢出。

总结

Sysfs 是 Linux 驱动模型中连接内核与用户空间的关键桥梁,通过它开发者可以:

  • 动态调试设备:查看硬件状态、配置参数。
  • 实现用户空间控制:通过文件读写操作硬件(如 GPIO、传感器)。
  • 与系统工具集成udev 依赖 Sysfs 自动创建设备节点。

深入理解 Sysfs 的实现和 API,能显著提升驱动开发的灵活性和调试效率。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

浩瀚之水_csdn

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值