获取thermal_zone0引用返回错误指针,树莓派4B内核模块如何读取温度?
问题:树莓派4B内核模块读取thermal_zone0温度失败
我正在为运行64位树莓派OS的树莓派4B编写一个简单的Linux内核模块,目标是读取thermal_zone0的温度。通过cat /sys/class/thermal/thermal_zone0/temp可以正常获取温度,但用内核模块实现时遇到问题。
我的代码如下:
#include <linux/module.h> #include <linux/kernel.h> #include <linux/thermal.h> static int __init my_module_init(void) { struct thermal_zone_device *thermal_zone; thermal_zone = thermal_zone_get_zone_by_name("thermal_zone0"); if (!thermal_zone) { pr_err("Failed to get thermal zone 0\n"); return -ENODEV; } if(thermal_zone->ops->get_temp) // <-- 加载时触发段错误 pr_info("Get temp is defined"); return 0; } static void __exit my_module_exit(void) { pr_info("Module unloaded\n"); } module_init(my_module_init); module_exit(my_module_exit); MODULE_AUTHOR("Your Name"); MODULE_DESCRIPTION("Example kernel module to interact with thermal_zone0"); MODULE_LICENSE("GPL");
目前的问题:
- 加载模块时触发段错误,原因是
thermal_zone为错误指针,解引用thermal_zone->ops出问题 - 之前尝试读取温度时结果始终为0,确认由指针错误导致
已确认内核配置相关热模块已启用:
CONFIG_THERMAL = y CONFIG_THERMAL_HWMON = y # Broadcom热驱动 CONFIG_BCM2711_THERMAL=y
我的疑问:如何正确获取thermal_zone0的引用并读取其温度?
解决方案
1. 核心问题说明
thermal_zone_get_zone_by_name失败时返回错误指针而非NULL,直接用!thermal_zone判断会忽略错误;同时直接访问thermal_zone->ops不安全,应该使用内核封装的API操作。
2. 修正后的代码
#include <linux/module.h> #include <linux/kernel.h> #include <linux/thermal.h> #include <linux/err.h> static int __init my_module_init(void) { struct thermal_zone_device *thermal_zone; int ret; unsigned long temp; // 获取thermal_zone0引用,该函数会增加设备引用计数 thermal_zone = thermal_zone_get_zone_by_name("thermal_zone0"); if (IS_ERR(thermal_zone)) { pr_err("Failed to get thermal zone 0, err: %ld\n", PTR_ERR(thermal_zone)); return PTR_ERR(thermal_zone); } // 使用内核封装函数读取温度,避免直接访问ops ret = thermal_zone_get_temp(thermal_zone, &temp); if (ret) { pr_err("Failed to get temperature, err: %d\n", ret); goto put_thermal_zone; } // 转换为摄氏度输出(内核返回单位为毫摄氏度) pr_info("Current temperature: %lu.%03lu °C\n", temp / 1000, temp % 1000); put_thermal_zone: // 释放thermal zone引用,防止内存泄漏 thermal_zone_put(thermal_zone); return ret; } static void __exit my_module_exit(void) { pr_info("Module unloaded\n"); } module_init(my_module_init); module_exit(my_module_exit); MODULE_AUTHOR("Your Name"); MODULE_DESCRIPTION("Example kernel module to read thermal_zone0 temperature"); MODULE_LICENSE("GPL");
3. 关键修正点
- 用
IS_ERR宏判断返回值:正确识别错误指针类型的失败返回 - 使用
thermal_zone_get_temp读取温度:内核封装的安全函数,内部会检查ops->get_temp有效性 - 添加
thermal_zone_put:获取引用后必须释放,避免内核内存泄漏 - 温度单位转换:将内核返回的毫摄氏度转换为常用的摄氏度格式
4. 编译与测试示例
Makefile参考:
obj-m += thermal_reader.o KDIR := /lib/modules/$(shell uname -r)/build PWD := $(shell pwd) all: $(MAKE) -C $(KDIR) M=$(PWD) modules clean: $(MAKE) -C $(KDIR) M=$(PWD) clean
- 编译:执行
make - 加载模块:
sudo insmod thermal_reader.ko - 查看输出:
dmesg | tail - 卸载模块:
sudo rmmod thermal_reader
内容的提问来源于stack exchange,提问作者thapro
相关产品推荐
相关产品推荐

