hwmon子系统——属性文件
hwmon子系统作为Linux内核中的一个子系统,用于监控硬件传感器的状态和提供对硬件传感器的访问接口。
在应用层,对传感器信息的读取,本质上是对驱动中hwmon子系统在注册传感器设备时所创建的各个属性文件进行读取操作
在Linux系统下,这些属性文件是直观存在的,如下图中的路径(my_hwmon为驱动中手动修改的结果,默认是hwmon);
需要注意,下面这一长串目录才是hwmon子系统根据驱动流程所创建的最原始且完整的目录,其他父级目录能够进入这个目录基本都是存在链接进行指向,并非完整的目录;
目录下的name文件存储了当前集成传感器的芯片设备的设备名,EMC1413为一种温度传感器;
目录下存在各种temp为前缀的文件(温度传感器的属性文件),这些就是驱动在注册设备时所创建的各种属性文件;
这些传感器所对应的芯片设备,实际是挂在从I2C-1总线上所扩展的一个I2C-Mux设备上,hwmon子系统和i2c子系统很大程度上不能算作一种从属关系,更多类似于一种协作关系,不过目录结构上还是将hwmon子系统对应的目录创建在了i2c子系统的目录之下;
hwmon子系统——设备注册函数
目前驱动中将一个hwmon子系统下的设备注册到驱动中时,主要有三个注册用的函数:hwmon_device_register
/* hwmon_device_register() is deprecated */
struct device *hwmon_device_register(struct device *dev);
hwmon_device_register_with_groups
struct device *hwmon_device_register_with_groups(
struct device *dev,
const char *name,
void *drvdata,
const struct attribute_group **groups);
hwmon_device_register_with_info
struct device *hwmon_device_register_with_info(
struct device *dev,
const char *name,
void *drvdata,
const struct hwmon_chip_info *info,
const struct attribute_group **extra_groups);
其中hwmon_device_register作为早期版本的注册函数已经弃用,不做分析;
hwmon_device_register_with_groups以及hwmon_device_register_with_info进行设备注册时,都需要将设备的属性信息进行传递,区别在于,hwmon_device_register_with_groups只能以groups方式传递,hwmon_device_register_with_info则能既能够使用info传递,也能够使用extra_groups进行传递(但是info不能为空,否则会异常return,extra_groups代码流程看只是在attribute_group不止1个时使用);
hwmon子系统——hwmon_device_register_with_groups注册时属性文件的指定及读写函数
hwmon_device_register_with_groups方式注册时,在驱动程序侧将会有较为繁琐的属性信息创建流程,下方的emc1402_group是一个attribute_group类型的全局静态变量,存有emc1402对应的各种属性信息;
static int emc1403_probe(struct i2c_client *client)
{
struct thermal_data *data;
struct device *hwmon_dev;
const struct i2c_device_id *id = i2c_match_id(emc1403_idtable, client);
data = devm_kzalloc(&client->dev, sizeof(struct thermal_data),
GFP_KERNEL);
if (data == NULL)
return -ENOMEM;
data->regmap = devm_regmap_init_i2c(client, &emc1403_regmap_config);
if (IS_ERR(data->regmap))
return PTR_ERR(data->regmap);
mutex_init(&data->mutex);
switch (id->driver_data) {
case emc1404:
data->groups[2] = &emc1404_group;
fallthrough;
case emc1403:
data->groups[1] = &emc1403_group;
fallthrough;
case emc1402:
data->groups[0] = &emc1402_group;
}
if (id->driver_data == emc1402)
data->groups[1] = &emc1402_alarm_group;
hwmon_dev = devm_hwmon_device_register_with_groups(&client->dev,
client->name, data,
data->groups);