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
相关产品推荐
相关产品推荐

