linux 内核, 怎样读取温度?


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 #include #include #include #include MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Virtual Thermal Driver (8 params)"); MODULE_AUTHOR("test"); static struct thermal_zone_device *virt_tz; // 温度获取函数(必须实现) static int virt_get_temp(struct thermal_zone_device *tz, int *temp) { *temp = 45000; // 45℃ return 0; } // 操作函数集 static struct thermal_zone_device_ops virt_ops = { .get_temp = virt_get_temp, }; // 空参数结构体 static struct thermal_zone_params virt_tzp = { }; // 探针函数 static int virt_probe(struct platform_device *pdev) { pr_info("virt_thermal: probe\n"); // ====================== // 8 个参数 完全匹配5.4.156内核 // ====================== 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秒) ); if (IS_ERR(virt_tz)) { pr_err("thermal register failed\n"); return PTR_ERR(virt_tz); } pr_info("virt_thermal: register ok\n"); return 0; } static int virt_remove(struct platform_device *pdev) { thermal_zone_device_unregister(virt_tz); pr_info("virt_thermal: removed\n"); return 0; } static struct platform_driver virt_driver = { .probe = virt_probe, .remove = virt_remove, .driver = { .name = "virtual-thermal", }, }; static struct platform_device *virt_dev; static int __init virt_init(void) { virt_dev = platform_device_alloc("virtual-thermal", -1); platform_device_add(virt_dev); //添加了一个platform device, 名字叫virtual-thermal return platform_driver_register(&virt_driver); //注册了一个platform driver,叫virtual-thermal 与device 匹配 } static void __exit virt_exit(void) { platform_driver_unregister(&virt_driver); platform_device_unregister(virt_dev); } module_init(virt_init); module_exit(virt_exit); ``` 能不能再简化一下,不用platform总线,platform 设备, 直接注册一个thermal_zone 设备呢? 应该可以,去掉外边的这层包装就可以了. 代码还可以再继续缩小, 由此代码使我认识到, 系统提供了接口,驱动提供了实现, 这种接口和实现分离的原则.使得可以支持各种设备. 因为实现时驱动完成的,不同的设备跟不同的驱动就可以了.但都要符合内核规范. ## 7. 简化后的测试代码: ```cpp $ cat virtual_thermal.c #include #include #include #include MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Virtual Thermal Driver (8 params)"); MODULE_AUTHOR("test"); static struct thermal_zone_device *virt_tz; // 温度获取函数(必须实现) static int virt_get_temp(struct thermal_zone_device *tz, int *temp) { *temp = 45000; // 45℃ return 0; } // 操作函数集 static struct thermal_zone_device_ops virt_ops = { .get_temp = virt_get_temp, }; // 空参数结构体 static struct thermal_zone_params virt_tzp = { }; static int __init virt_init(void) { pr_info("virt_thermal: init\n"); // ====================== // 8 个参数 完全匹配5.4.156内核 // ====================== 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_ops 相binding &virt_tzp, // 6 tzp 0, // 7 passive_delay 1000 // 8 polling_delay (1秒) ); if (IS_ERR(virt_tz)) { pr_err("thermal register failed\n"); return PTR_ERR(virt_tz); } pr_info("virt_thermal: register ok\n"); return 0; } static void __exit virt_exit(void) { thermal_zone_device_unregister(virt_tz); pr_info("virt_thermal: removed\n"); } module_init(virt_init); module_exit(virt_exit); ``` 思考: 什么是linux 驱动? Linux 驱动 = 给内核子系统注册一个设备 + 实现这个设备的操作方法 内核里多了一个设备,内核通过驱动来与设备实例交互. 其中platform设备与platform驱动有一个binding 过程.

相关推荐
a7769957991 个月前
驱动里的并发控制--互斥锁
并发·driver
qq_283720051 个月前
Python 模块精讲:platform 获取系统信息,从入门到实战全攻略
python·platform
行者..................2 个月前
第2课:恢复出厂、掌握 Linux 基础命令并完成首次 GCC 编译
linux·qt·driver
大熊猫侯佩7 个月前
思过崖上学「 subprocess 」:令狐冲的 Swift 6.2 跨平台进程心法
spm·xcode·进程控制·platform·subprocess·output·swift 6.2
UWA1 年前
URP相机如何将场景渲染定帧模糊绘制
memory·platform·rendering
qq_282195311 年前
内核spi驱动流程图
linux·流程图·driver
UWA1 年前
如何用GPU Instancing来优化树木草石重复模型
ui·platform·rendering
让子弹飞021 年前
15.1linux设备树下的platform驱动编写(知识)_csdn
linux·ubuntu·platform·stm32mp157·驱动的分离和分层
leoufung1 年前
调度算法 HTB 或 CBQ 简介
linux·网络·kernel·driver·qos