You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在内核模块中与sysfs或导出到sysfs的驱动进行交互

结论
  • 不需要重写DS18B20驱动,强烈不建议在内核空间直接读取sysfs文件:sysfs是面向用户空间设计的交互接口,内核态直接调用VFS接口读取sysfs既不符合内核开发规范,还容易引发锁竞争、权限校验绕过、跨版本兼容性差等问题,稳定性没有保障。
  • 最优方案是直接调用Linux w1子系统对外暴露的标准内核API,和已加载的w1总线驱动交互,直接在你的自研模块里完成温度读取,不需要改动现有驱动,也不会产生资源冲突。
具体实现步骤

你的模块只要依赖内核w1核心层(对应内核配置项CONFIG_W1)即可,不需要依赖w1_therm模块的内部符号,实现流程如下:

  1. 引入必要的头文件
#include <linux/w1.h>
#include <linux/delay.h>
#include <linux/mutex.h>
  1. 匹配目标DS18B20设备
    DS18B20的w1家族固定ID为0x28,你可以遍历w1总线上注册的所有从设备,匹配你已知的设备ROM ID(即sysfs路径里28-后面的062194159c7d),拿到对应的设备句柄,参考代码:
struct w1_slave *find_target_ds18b20(void)
{
    struct w1_bus_master *master;
    struct w1_slave *slave = NULL;
    // 替换为你自己的设备ROM ID,注意字节序匹配
    const u8 target_id[8] = {0x28, 0x06, 0x21, 0x94, 0x15, 0x9c, 0x7d, 0x00};

    mutex_lock(&w1_mlock);
    list_for_each_entry(master, &w1_masters, w1_master_entry) {
        mutex_lock(&master->mutex);
        list_for_each_entry(slave, &master->slist, w1_slave_entry) {
            if (slave->reg_num.family == 0x28 &&
                !memcmp(slave->reg_num.id, target_id + 1, 7)) {
                get_device(&slave->dev); // 增加引用计数,防止设备被意外释放
                mutex_unlock(&master->mutex);
                goto found;
            }
        }
        mutex_unlock(&master->mutex);
    }
    slave = NULL;
found:
    mutex_unlock(&w1_mlock);
    return slave;
}

注意:如果遇到匹配不到设备的问题,可以先遍历所有0x28家族的设备,打印slave->reg_num.id的十六进制值,和你的设备ROM ID比对调整字节序即可,不要硬猜字节顺序。

  1. 读取温度值
    拿到w1_slave指针后,直接调用w1核心封装的总线读写接口,按照DS18B20的标准指令流程读取温度即可,不需要自己实现单总线时序,参考代码:
int read_ds18b20_temp(struct w1_slave *slave, int *temp_millic)
{
    u8 txbuf[1], rxbuf[9];
    s16 raw_temp;
    u8 crc;

    if (!slave || !temp_millic)
        return -EINVAL;

    mutex_lock(&slave->master->mutex);
    // 1. 复位总线,选通目标从设备
    w1_reset_select_slave(slave);
    // 2. 发送0x44指令启动温度转换,12位精度最长转换时间750ms
    txbuf[0] = 0x44;
    w1_write_block(slave->master, txbuf, 1);
    mutex_unlock(&slave->master->mutex);

    msleep(800); // 等待转换完成

    mutex_lock(&slave->master->mutex);
    // 3. 复位选通设备,发送0xBE指令读取暂存器
    w1_reset_select_slave(slave);
    txbuf[0] = 0xBE;
    w1_write_block(slave->master, txbuf, 1);
    w1_read_block(slave->master, rxbuf, 9);
    mutex_unlock(&slave->master->mutex);

    // 4. CRC校验,w1核心自带标准crc8校验函数
    crc = w1_calc_crc8(rxbuf, 8);
    if (crc != rxbuf[8])
        return -EIO;

    // 5. 转换为毫摄氏度单位,比如返回25000对应25.000℃
    raw_temp = le16_to_cpup((__le16 *)rxbuf);
    *temp_millic = raw_temp * 625;

    return 0;
}
  1. 资源回收
    设备使用完之后,记得调用put_device(&slave->dev);释放之前持有的设备引用计数,避免内存泄漏。
其他方案的问题说明
  • 重写DS18B20驱动属于重复造轮子,而且会和已加载的w1-gpio驱动产生GPIO资源、总线控制权冲突,最终导致两个驱动都无法正常读取传感器数据,没有必要。
  • 内核态读取sysfs的方案本质是绕开内核驱动框架走用户空间接口,不仅性能差,还可能因为内核版本迭代、sysfs节点权限变化、锁顺序错误触发死锁或者内核panic,生产环境绝对不要用。

内容的提问来源于stack exchange,提问作者SSBjY_Dave

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 22:30:43