author: hjjdebug
date: 2026年 05月 26日 星期二 17:15:39 CST
descrip: linux 内核, 怎样读取温度?
文章目录
- [1. 添加platrform设备](#1. 添加platrform设备)
- [2. 注册platform驱动,](#2. 注册platform驱动,)
- [3. platform设备是怎样找到它的驱动的 ?](#3. platform设备是怎样找到它的驱动的 ?)
- [4. 热区,温度区. thermal_zone.](#4. 热区,温度区. thermal_zone.)
- [5. 小结:](#5. 小结:)
- [6. 测试代码](#6. 测试代码)
- [7. 简化后的测试代码:](#7. 简化后的测试代码:)
目的: 以最简单的温度测量为例, 了解一下linux下的驱动架构模型.
写到最后发现,附录2是最简单的,附录1还挂载了platform设备,platform驱动框架.
温度,首先要有一个测温设备, 这里我们没有具体的测温设备,假想用一个platfrom设备.
我们假想用platform 设备,
有设备则必有驱动, 来与设备进行数据交互, 这里用platform 驱动来对应platform设备
platform 设备是用来测温度的, 所以驱动中可用 内置的thermal-zone 设备来读取.
编译成.ko
执行:
$ insmod virtual_thermal.ko
查看打印信息:
$ dmesg
28904.713790\] virt_thermal: probe
\[28904.713841\] virt_thermal: register ok
进一步查看系统目录及文件变化
## 1. 添加platrform设备
virt_dev = platform_device_alloc("virtual-thermal", -1);
platform_device_add(virt_dev); //添加了一个platform device, 名字叫virtual-thermal
查看/sysfs 文件系统:
/sys/devices/platform/ 目录下新增加一个virtual-thermal 目录
/sys/devices/platform/virtual-thermal$ ls -l
总用量 0
lrwxrwxrwx 1 root root 0 5月 26 15:53 driver -\> .../.../.../bus/platform/drivers/virtual-thermal
-rw-r--r-- 1 root root 4096 5月 26 16:09 driver_override
-r--r--r-- 1 root root 4096 5月 26 16:09 modalias
drwxr-xr-x 2 root root 0 5月 26 16:09 power
lrwxrwxrwx 1 root root 0 5月 26 16:09 subsystem -\> .../.../.../bus/platform
-rw-r--r-- 1 root root 4096 5月 26 15:53 uevent
hjj@hjj-laptop:/sys/devices/platform/virtual-thermal$ cat driver_override
(null)
hjj@hjj-laptop:/sys/devices/platform/virtual-thermal$ cat modalias
platform:virtual-thermal
hjj@hjj-laptop:/sys/devices/platform/virtual-thermal$ cat uevent
DRIVER=virtual-thermal
MODALIAS=platform:virtual-thermal
有一个子系统链接指向子系统 bus/platform
匹配成功后
有一个driver链接指向对应的driver 目录
## 2. 注册platform驱动,
static struct platform_driver virt_driver = {
.probe = virt_probe,
.remove = virt_remove,
.driver = {
.name = "virtual-thermal",
},
};
platform_driver_register(\&virt_driver); //注册了一个platform driver,叫virtual-thermal 与device 匹配
查看/sysfs 文件系统:
/sys/bus/platform/drivers/ 目录下新增加一个virtual-thermal 目录
hjj@hjj-laptop:/sys/bus/platform/drivers/virtual-thermal$ ls -l
总用量 0
drwxr-xr-x 2 root root 0 5月 26 15:53 ./
drwxr-xr-x 15 root root 0 5月 26 07:35 .../
--w------- 1 root root 4096 5月 26 15:57 bind
lrwxrwxrwx 1 root root 0 5月 26 15:57 module -\> .../.../.../.../module/virtual_thermal/
--w------- 1 root root 4096 5月 26 15:53 uevent
--w------- 1 root root 4096 5月 26 15:57 unbind
lrwxrwxrwx 1 root root 0 5月 26 15:57 virtual-thermal -\> .../.../.../.../devices/platform/virtual-thermal/
有一个module 链接指向 driver 的module 目录
匹配成功后, 有一个virtual-thermal 链接指向driver的设备链接
## 3. platform设备是怎样找到它的驱动的 ?
靠名称匹配. 驱动叫virtual-thermal, 设备也叫virtual-thermal, 这是最原始的一种匹配方式
## 4. 热区,温度区. thermal_zone.
virt_tz = thermal_zone_device_register( //注册一个thremal_zone,热区,温度区域
"virtual_thermal", // 1 type
0, // 2 trips
0, // 3 mask
NULL, // 4 devdata
&virt_ops, // 5 ops
&virt_tzp, // 6 tzp
0, // 7 passive_delay
1000 // 8 polling_delay (1秒)
);
thermal_zone 是指一个温度监控对象.
thermal_zone_device_register , 向内核温度子系统(thermal 子系统)
注册一个热区设备. 这样就可以在/sys/class/thermal/ 目录下生成对应的节点. 查是thermal_zone4.
lrwxrwxrwx 1 root root 0 5月 26 16:30 thermal_zone4 -\> .../.../devices/virtual/thermal/thermal_zone4/
这个节点对应的设备: /sys/devices/virtual/thermal/thermal_zone4
hjj@hjj-laptop:/sys/devices/virtual/thermal/thermal_zone4$ ls -l
总用量 0
drwxr-xr-x 4 root root 0 5月 26 16:30 ./
drwxr-xr-x 16 root root 0 5月 26 07:35 .../
-r--r--r-- 1 root root 4096 5月 26 16:33 available_policies
drwxr-xr-x 3 root root 0 5月 26 16:30 hwmon3/
-rw-r--r-- 1 root root 4096 5月 26 16:33 integral_cutoff
-rw-r--r-- 1 root root 4096 5月 26 16:33 k_d
-rw-r--r-- 1 root root 4096 5月 26 16:33 k_i
-rw-r--r-- 1 root root 4096 5月 26 16:33 k_po
-rw-r--r-- 1 root root 4096 5月 26 16:33 k_pu
-rw-r--r-- 1 root root 4096 5月 26 16:33 offset
-rw-r--r-- 1 root root 4096 5月 26 16:33 passive
-rw-r--r-- 1 root root 4096 5月 26 16:33 policy
drwxr-xr-x 2 root root 0 5月 26 16:33 power/
-rw-r--r-- 1 root root 4096 5月 26 16:33 slope
lrwxrwxrwx 1 root root 0 5月 26 16:30 subsystem -\> .../.../.../.../class/thermal/
-rw-r--r-- 1 root root 4096 5月 26 16:33 sustainable_power
-r--r--r-- 1 root root 4096 5月 26 16:33 temp
-r--r--r-- 1 root root 4096 5月 26 16:33 type
-rw-r--r-- 1 root root 4096 5月 26 16:30 uevent
这么多文件可读写,
hjj@hjj-laptop:/sys/devices/virtual/thermal/thermal_zone4$ cat k_d
0
hjj@hjj-laptop:/sys/devices/virtual/thermal/thermal_zone4$ cat k_i
0
hjj@hjj-laptop:/sys/devices/virtual/thermal/thermal_zone4$ cat k_po
0
hjj@hjj-laptop:/sys/devices/virtual/thermal/thermal_zone4$ cat k_pu
0
hjj@hjj-laptop:/sys/devices/virtual/thermal/thermal_zone4$ cat offset
0
hjj@hjj-laptop:/sys/devices/virtual/thermal/thermal_zone4$ cat passive
0
hjj@hjj-laptop:/sys/devices/virtual/thermal/thermal_zone4$ cat policy
step_wise
hjj@hjj-laptop:/sys/devices/virtual/thermal/thermal_zone4$ cat slope
0
hjj@hjj-laptop:/sys/devices/virtual/thermal/thermal_zone4$ cat temp \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
45000
hjj@hjj-laptop:/sys/devices/virtual/thermal/thermal_zone4$ cat type
virtual_thermal
hjj@hjj-laptop:/sys/devices/virtual/thermal/thermal_zone4$ cat uevent
其中temp文件暴露温度给用户态读取. 它会调用到我们驱动中的代码
其它文件不用关心,它是系统自动生成的.
static int virt_get_temp(struct thermal_zone_device \*tz, int \*temp)
{
\*temp = 45000; // 45℃
return 0;
}
//用户态接口通过系统调用到驱动的回调函数, 要求设备提供温度. 设备把测量的温度反馈回去.
为什么设备会挂靠在devices/virtual/ 总线下?
这是thermal_zone_device_register 函数调用决定的.
thermal 子系统提前提前注册了一个虚拟 class:
static struct class thermal_class = {
.name = "thermal",
.dev_groups = thermal_groups,
};
thermal_class 本身的属性,决定了设备会自动挂靠到 virtual 总线下
结果,最终自动生成路径:/sys/devices/virtual/thermal/thermal_zoneX
## 5. 小结:
本来,读取温度,在简单的嵌入式系统中, 只要从一个io地址读取数据就够了.
可是到了linux世界里却变得如此复杂.
主要是因为linux 内核管理之下,用户态程序不能访问I/O.
module 属于内核态, module 可以直接访问I/O,
但当温度由一个外部设备来提供时. 而且外部设备可能千奇百怪.
此时,内核要把外部测温设备想象成一个虚拟设备.
外部设备的数据都要符合一定的规范, 这样不管是任何外部测温设备,都能够和系统接上口.
其中thermal_tone 规范, 就是对外部设备的数据要求规范.
这样,系统屏蔽了具体的测温设备的差异, 具体的测温设备,靠它们的驱动绑定到系统上.
## 6. 测试代码
```cpp
$ cat virtual_thermal.c
#include