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

Linux客户端驱动运行时声明/定义hwmon传感器属性的实现方法

实现方案

你可以通过动态分配属性结构体+通用回调函数+私有数据标识传感器的方式实现运行时动态创建hwmon sysfs节点,无需在编译阶段预定义传感器列表,具体实现如下:

1. 定义通用数据结构与回调函数

首先定义传感器私有数据结构存储运行时获取的传感器信息,同时实现所有传感器共用的show回调,通过私有数据区分不同传感器:

/* 自定义传感器私有结构,存储运行时从firmware获取的传感器参数 */
struct my_sensor_info {
    int id;
    char name[32]; // 传感器名称
    int reg_addr; // 传感器读取地址等自定义参数
};

/* 通用show回调,所有传感器共用 */
static ssize_t show_sensor_info(struct device *dev, struct device_attribute *da, char *buf)
{
    struct sensor_device_attribute *s_attr = to_sensor_dev_attr(da);
    struct my_sensor_info *sensor = s_attr->dev_attr.private;
    
    /* 按传感器私有参数读取对应数据 */
    int val = read_sensor_hw(sensor);
    return sysfs_emit(buf, "%d\n", val);
}

2. probe函数中动态注册节点

在probe阶段获取firmware的传感器列表后,循环为每个传感器分配属性结构并注册sysfs节点:

static int my_hwmon_probe(struct platform_device *pdev)
{
    int err, sensor_cnt, i;
    struct my_sensor_info *sensor_list;
    struct sensor_device_attribute *dyn_attrs;
    struct device *hwmon_dev;

    /* 从firmware获取传感器列表与数量 */
    err = firmware_query_sensor_list(&sensor_list, &sensor_cnt);
    if (err)
        return err;

    /* 注册hwmon设备 */
    hwmon_dev = hwmon_device_register(&pdev->dev);
    if (IS_ERR(hwmon_dev)) {
        err = PTR_ERR(hwmon_dev);
        goto free_sensor_list;
    }
    platform_set_drvdata(pdev, hwmon_dev);

    /* 动态分配属性结构体数组 */
    dyn_attrs = devm_kzalloc(&pdev->dev, sizeof(*dyn_attrs) * sensor_cnt, GFP_KERNEL);
    if (!dyn_attrs) {
        err = -ENOMEM;
        goto unreg_hwmon;
    }

    /* 循环初始化并注册每个传感器的sysfs节点 */
    for (i = 0; i < sensor_cnt; i++) {
        sysfs_attr_init(&dyn_attrs[i].dev_attr.attr);
        dyn_attrs[i].dev_attr.attr.name = sensor_list[i].name;
        dyn_attrs[i].dev_attr.attr.mode = 0444;
        dyn_attrs[i].dev_attr.show = show_sensor_info;
        dyn_attrs[i].dev_attr.store = NULL;
        dyn_attrs[i].index = i;
        dyn_attrs[i].dev_attr.private = &sensor_list[i];

        err = device_create_file(hwmon_dev, &dyn_attrs[i].dev_attr);
        if (err) {
            /* 出错时清理已注册的节点 */
            for (int j = 0; j < i; j++)
                device_remove_file(hwmon_dev, &dyn_attrs[j].dev_attr);
            goto unreg_hwmon;
        }
    }
    return 0;

unreg_hwmon:
    hwmon_device_unregister(hwmon_dev);
free_sensor_list:
    kfree(sensor_list);
    return err;
}

3. 实现remove逻辑释放资源

static int my_hwmon_remove(struct platform_device *pdev)
{
    struct device *hwmon_dev = platform_get_drvdata(pdev);
    hwmon_device_unregister(hwmon_dev);
    /* devm分配的属性结构会自动释放,firmware获取的sensor_list按需释放 */
    return 0;
}

注意事项

  • 传感器名称必须符合sysfs命名规范,不可包含空格、斜杠等特殊字符
  • 建议使用内核devm_系列内存分配函数,可自动在驱动卸载时释放内存,避免泄漏
  • Linux 4.10及以上内核更推荐使用hwmon_device_register_with_info()接口,通过struct hwmon_chip_info构造动态属性组,无需手动调用device_create_file,接口安全性更高
  • 若传感器支持可写配置,只要补充实现通用的store回调即可,逻辑和show回调一致

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 02:54:03