hwmon: Introduce uhwmon for userspace implementations
Subsystems (3)
cover hwmon: Introduce uhwmon for userspace implementations
This series introduces uhwmon, a generic hwmon interface connecting userspace implementations to the kernel. It exposes hwmon sensor and attribute definitions to userspace through <linux/hwmon.h>, allowing userspace drivers to create standard hwmon sysfs attributes. uhwmon forwards reads and writes through /dev/uhwmon. The hwmon core handles numeric text conversion and newlines for kernel and userspace drivers. The series also adds kernel documentation explaining the interface and how to use its UAPI.
In the October 2024 IT87 discussion [1], a read-only hwmon driver configured from userspace was suggested for chips without datasheets and for testing new chips. Guenter Roeck said he would need proposal details, but questioned whether the hwmon sysfs ABI justified new kernel
infrastructure: userspace drivers would still need hardware knowledge and access. He suggested an API between those drivers and libsensors as an alternative.
But I see practical value in retaining hwmon: the use case below already works with unmodified sensors through its existing hwmon interface. A common bridge can similarly let other daemons expose measurements without adding a new input path to existing hwmon applications, reducing duplicated integration work. The idea is conceptually similar to dummy_hcd with a userspace gadget interface.
uhwmon's goal is to let applications using the standard hwmon interface access sensors without mainline drivers, without adding per-device support to userspace libraries or building and loading separate DKMS modules. In theory, projects such as wireview-hwmon [2] could replace their device-specific DKMS module with uhwmon and adapt their daemon to use it. My current use case is bridging the Tapo API [3] to hwmon, using a TAPO P110M smart plug to measure my system's power draw at the wall in place of an ACPI power meter. I have tested this setup in an Ubuntu VM, including live readings, daemon disconnect and recovery, and reboot startup.
[1] https://lkml.iu.edu/2410.2/11841.html
[2] https://github.com/emaspa/wireview-hwmon
[3] https://github.com/mihai-dinculescu/tapo
Jihong Min (5):
hwmon: Export sensor and attribute definitions to userspace
hwmon: Expose attribute validation and string helpers
hwmon: Add a generic interface for userspace implementations
hwmon: Reject truncated attribute names
docs: hwmon: Document the uhwmon userspace interface
Documentation/hwmon/index.rst | 1 + Documentation/hwmon/uhwmon.rst | 141 +++++ Documentation/userspace-api/ioctl/ioctl-number.rst | 1 + MAINTAINERS | 2 + drivers/hwmon/Kconfig | 9 + drivers/hwmon/Makefile | 1 + drivers/hwmon/hwmon.c | 38 +- drivers/hwmon/uhwmon.c | 641 +++++++++++++++++++++ include/linux/hwmon.h | 356 +----------- include/uapi/linux/hwmon.h | 372 ++++++++++++ include/uapi/linux/uhwmon.h | 64 ++ 11 files changed, 1267 insertions(+), 359 deletions(-) create mode 100644 Documentation/hwmon/uhwmon.rst create mode 100644 drivers/hwmon/uhwmon.c create mode 100644 include/uapi/linux/hwmon.h create mode 100644 include/uapi/linux/uhwmon.h
base-commit: 7b63ef2d55f24519e7e9e5f4d15dbea03f126e40
Sincerely,
Jihong Min
PATCH 1/5 hwmon: Export sensor and attribute definitions to userspace
Move sensor types, attribute identifiers and configuration bits to linux/hwmon.h in the UAPI so kernel and userspace drivers share them. Keep existing values unchanged and use userspace-safe bit definitions.
Keep operations, channel structures and registration helpers in the kernel header.
--- MAINTAINERS | 1 + include/linux/hwmon.h | 353 +---------------------------------- include/uapi/linux/hwmon.h | 372 +++++++++++++++++++++++++++++++++++++ 3 files changed, 374 insertions(+), 352 deletions(-) create mode 100644 include/uapi/linux/hwmon.h
MAINTAINERS +1 -0
@@ -11492,6 +11492,7 @@ F: Documentation/hwmon/ F: drivers/hwmon/ F: include/linux/hwmon*.h F: include/trace/events/hwmon*.h +F: include/uapi/linux/hwmon.h K: (devm_)?hwmon_device_(un)?register(|_with_groups|_with_info) HARDWARE RANDOM NUMBER GENERATOR CORE
include/linux/hwmon.h +1 -352
363 lines not on this page · raw message
include/uapi/linux/hwmon.h new file +372 -0
372 lines not on this page · raw message
[email protected]
AI reviewRe: [PATCH 1/5] hwmon: Export sensor and attribute definitions to userspace
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: - [Medium] hwmon: UAPI exposure of hwmon_max sentinel and internal bitmasks --
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] hwmon: UAPI exposure of hwmon_max sentinel and internal bitmasks --
commit bbc47a707f27865e8c59d7c4ea18a1b742278dfd
Author: Jihong Min <[email protected]>
hwmon: Export sensor and attribute definitions to userspace
Move sensor types, attribute identifiers and configuration bits to linux/hwmon.h in the UAPI so kernel and userspace drivers share them. Keep existing values unchanged and use userspace-safe bit definitions.
Quoted 6 lines
include/uapi/linux/hwmon.h new file +0
-0@@ -0,0 +1,372 @@
[ ... ]
include/uapi/linux/hwmon.h line 31
Quoted 13 lines
include/uapi/linux/hwmon.h new file +13
-0+enum hwmon_sensor_types { + hwmon_chip =0 , + hwmon_temp =1 , + hwmon_in =2 , + hwmon_curr =3 , + hwmon_power =4 , + hwmon_energy =5 , + hwmon_energy64 =6 , + hwmon_humidity =7 , + hwmon_fan =8 , + hwmon_pwm =9 , + hwmon_intrusion =10 , + hwmon_max =11 ,
^^^^^^^^^^^^^^
[Severity: Medium]
Could exporting this expandable max boundary integer to the stable userspace UAPI header lead to out-of-bounds memory accesses in userspace applications?
If a userspace program statically sizes an array based on hwmon_max, and a future kernel release adds a new sensor type (incrementing hwmon_max), the program could index past the end of its array when receiving the new sensor type.
Quoted 11 lines
include/uapi/linux/hwmon.h new file +11
-0+}; + +enum hwmon_chip_attributes { + hwmon_chip_temp_reset_history =0 , + hwmon_chip_in_reset_history =1 , + hwmon_chip_curr_reset_history =2 , + hwmon_chip_power_reset_history =3 , + hwmon_chip_register_tz =4 , + hwmon_chip_update_interval =5 , + hwmon_chip_update_interval_us =6 , + hwmon_chip_alarms =7 ,
include/uapi/linux/hwmon.h line 52
Quoted 10 lines
include/uapi/linux/hwmon.h new file +10
-0+ hwmon_chip_samples =8 , + hwmon_chip_curr_samples =9 , + hwmon_chip_in_samples =10 , + hwmon_chip_power_samples =11 , + hwmon_chip_temp_samples =12 , + hwmon_chip_beep_enable =13 , + hwmon_chip_pec = 14, +}; + +#define HWMON_C_TEMP_RESET_HISTORY _BITUL(hwmon_chip_temp_reset_history)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
[Severity: Medium]
Is it necessary to export these configuration bitmasks to the UAPI?
These bitmasks are strictly used by the kernel-internal struct hwmon_channel_info and provide no value to userspace. Exporting them allows and encourages anti-patterns in userspace.
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=1
Guenter Roeck
maintainerRe: [PATCH 1/5] hwmon: Export sensor and attribute definitions to userspace
In reply to Jihong MinQuoted 9 lines · Jihong Min
Move sensor types, attribute identifiers and configuration bits to
linux/hwmon.hin the UAPI so kernel and userspace drivers share them. Keep existing values unchanged and use userspace-safe bit definitions.Keep operations, channel structures and registration helpers in the kernel header.
Assisted-by Codex:gpt-6-astraSigned-off-by Jihong Min <[email protected]>
NACK. Those definitions are kernel internal and subject to change.
Guenter
Quoted 765 lines
--- MAINTAINERS | 1 + include/linux/hwmon.h | 353 +---------------------------------- include/uapi/linux/hwmon.h | 372 +++++++++++++++++++++++++++++++++++++ 3 files changed, 374 insertions(+), 352 deletions(-) create mode 100644 include/uapi/linux/hwmon.hMAINTAINERS +1
-0@@ -11492,6 +11492,7 @@ F: Documentation/hwmon/ F: drivers/hwmon/ F: include/linux/hwmon*.h F: include/trace/events/hwmon*.h +F: include/uapi/linux/hwmon.h K: (devm_)?hwmon_device_(un)?register(|_with_groups|_with_info) HARDWARE RANDOM NUMBER GENERATOR COREinclude/linux/hwmon.h +1
-352@@ -14,362 +14,11 @@#include <linux/bitops.h> #include <linux/cleanup.h> +#include <uapi/linux/hwmon.h> struct device ;struct attribute_group ; -enum hwmon_sensor_types { - hwmon_chip, - hwmon_temp, - hwmon_in, - hwmon_curr, - hwmon_power, - hwmon_energy, - hwmon_energy64, - hwmon_humidity, - hwmon_fan, - hwmon_pwm, - hwmon_intrusion, - hwmon_max, -}; - -enum hwmon_chip_attributes { - hwmon_chip_temp_reset_history, - hwmon_chip_in_reset_history, - hwmon_chip_curr_reset_history, - hwmon_chip_power_reset_history, - hwmon_chip_register_tz, - hwmon_chip_update_interval, - hwmon_chip_update_interval_us, - hwmon_chip_alarms, - hwmon_chip_samples, - hwmon_chip_curr_samples, - hwmon_chip_in_samples, - hwmon_chip_power_samples, - hwmon_chip_temp_samples, - hwmon_chip_beep_enable, - hwmon_chip_pec, -}; - -#define HWMON_C_TEMP_RESET_HISTORY BIT(hwmon_chip_temp_reset_history) -#define HWMON_C_IN_RESET_HISTORY BIT(hwmon_chip_in_reset_history) -#define HWMON_C_CURR_RESET_HISTORY BIT(hwmon_chip_curr_reset_history) -#define HWMON_C_POWER_RESET_HISTORY BIT(hwmon_chip_power_reset_history) -#define HWMON_C_REGISTER_TZ BIT(hwmon_chip_register_tz) -#define HWMON_C_UPDATE_INTERVAL BIT(hwmon_chip_update_interval) -#define HWMON_C_UPDATE_INTERVAL_US BIT(hwmon_chip_update_interval_us) -#define HWMON_C_ALARMS BIT(hwmon_chip_alarms) -#define HWMON_C_SAMPLES BIT(hwmon_chip_samples) -#define HWMON_C_CURR_SAMPLES BIT(hwmon_chip_curr_samples) -#define HWMON_C_IN_SAMPLES BIT(hwmon_chip_in_samples) -#define HWMON_C_POWER_SAMPLES BIT(hwmon_chip_power_samples) -#define HWMON_C_TEMP_SAMPLES BIT(hwmon_chip_temp_samples) -#define HWMON_C_BEEP_ENABLE BIT(hwmon_chip_beep_enable) -#define HWMON_C_PEC BIT(hwmon_chip_pec) - -enum hwmon_temp_attributes { - hwmon_temp_enable, - hwmon_temp_input, - hwmon_temp_type, - hwmon_temp_lcrit, - hwmon_temp_lcrit_hyst, - hwmon_temp_min, - hwmon_temp_min_hyst, - hwmon_temp_max, - hwmon_temp_max_hyst, - hwmon_temp_crit, - hwmon_temp_crit_hyst, - hwmon_temp_emergency, - hwmon_temp_emergency_hyst, - hwmon_temp_alarm, - hwmon_temp_lcrit_alarm, - hwmon_temp_min_alarm, - hwmon_temp_max_alarm, - hwmon_temp_crit_alarm, - hwmon_temp_emergency_alarm, - hwmon_temp_fault, - hwmon_temp_offset, - hwmon_temp_label, - hwmon_temp_lowest, - hwmon_temp_highest, - hwmon_temp_reset_history, - hwmon_temp_rated_min, - hwmon_temp_rated_max, - hwmon_temp_beep, -}; - -#define HWMON_T_ENABLE BIT(hwmon_temp_enable) -#define HWMON_T_INPUT BIT(hwmon_temp_input) -#define HWMON_T_TYPE BIT(hwmon_temp_type) -#define HWMON_T_LCRIT BIT(hwmon_temp_lcrit) -#define HWMON_T_LCRIT_HYST BIT(hwmon_temp_lcrit_hyst) -#define HWMON_T_MIN BIT(hwmon_temp_min) -#define HWMON_T_MIN_HYST BIT(hwmon_temp_min_hyst) -#define HWMON_T_MAX BIT(hwmon_temp_max) -#define HWMON_T_MAX_HYST BIT(hwmon_temp_max_hyst) -#define HWMON_T_CRIT BIT(hwmon_temp_crit) -#define HWMON_T_CRIT_HYST BIT(hwmon_temp_crit_hyst) -#define HWMON_T_EMERGENCY BIT(hwmon_temp_emergency) -#define HWMON_T_EMERGENCY_HYST BIT(hwmon_temp_emergency_hyst) -#define HWMON_T_ALARM BIT(hwmon_temp_alarm) -#define HWMON_T_MIN_ALARM BIT(hwmon_temp_min_alarm) -#define HWMON_T_MAX_ALARM BIT(hwmon_temp_max_alarm) -#define HWMON_T_CRIT_ALARM BIT(hwmon_temp_crit_alarm) -#define HWMON_T_LCRIT_ALARM BIT(hwmon_temp_lcrit_alarm) -#define HWMON_T_EMERGENCY_ALARM BIT(hwmon_temp_emergency_alarm) -#define HWMON_T_FAULT BIT(hwmon_temp_fault) -#define HWMON_T_OFFSET BIT(hwmon_temp_offset) -#define HWMON_T_LABEL BIT(hwmon_temp_label) -#define HWMON_T_LOWEST BIT(hwmon_temp_lowest) -#define HWMON_T_HIGHEST BIT(hwmon_temp_highest) -#define HWMON_T_RESET_HISTORY BIT(hwmon_temp_reset_history) -#define HWMON_T_RATED_MIN BIT(hwmon_temp_rated_min) -#define HWMON_T_RATED_MAX BIT(hwmon_temp_rated_max) -#define HWMON_T_BEEP BIT(hwmon_temp_beep) - -enum hwmon_in_attributes { - hwmon_in_enable, - hwmon_in_input, - hwmon_in_min, - hwmon_in_max, - hwmon_in_lcrit, - hwmon_in_crit, - hwmon_in_average, - hwmon_in_lowest, - hwmon_in_highest, - hwmon_in_reset_history, - hwmon_in_label, - hwmon_in_alarm, - hwmon_in_min_alarm, - hwmon_in_max_alarm, - hwmon_in_lcrit_alarm, - hwmon_in_crit_alarm, - hwmon_in_rated_min, - hwmon_in_rated_max, - hwmon_in_beep, - hwmon_in_fault, -}; - -#define HWMON_I_ENABLE BIT(hwmon_in_enable) -#define HWMON_I_INPUT BIT(hwmon_in_input) -#define HWMON_I_MIN BIT(hwmon_in_min) -#define HWMON_I_MAX BIT(hwmon_in_max) -#define HWMON_I_LCRIT BIT(hwmon_in_lcrit) -#define HWMON_I_CRIT BIT(hwmon_in_crit) -#define HWMON_I_AVERAGE BIT(hwmon_in_average) -#define HWMON_I_LOWEST BIT(hwmon_in_lowest) -#define HWMON_I_HIGHEST BIT(hwmon_in_highest) -#define HWMON_I_RESET_HISTORY BIT(hwmon_in_reset_history) -#define HWMON_I_LABEL BIT(hwmon_in_label) -#define HWMON_I_ALARM BIT(hwmon_in_alarm) -#define HWMON_I_MIN_ALARM BIT(hwmon_in_min_alarm) -#define HWMON_I_MAX_ALARM BIT(hwmon_in_max_alarm) -#define HWMON_I_LCRIT_ALARM BIT(hwmon_in_lcrit_alarm) -#define HWMON_I_CRIT_ALARM BIT(hwmon_in_crit_alarm) -#define HWMON_I_RATED_MIN BIT(hwmon_in_rated_min) -#define HWMON_I_RATED_MAX BIT(hwmon_in_rated_max) -#define HWMON_I_BEEP BIT(hwmon_in_beep) -#define HWMON_I_FAULT BIT(hwmon_in_fault) - -enum hwmon_curr_attributes { - hwmon_curr_enable, - hwmon_curr_input, - hwmon_curr_min, - hwmon_curr_max, - hwmon_curr_lcrit, - hwmon_curr_crit, - hwmon_curr_average, - hwmon_curr_lowest, - hwmon_curr_highest, - hwmon_curr_reset_history, - hwmon_curr_label, - hwmon_curr_alarm, - hwmon_curr_min_alarm, - hwmon_curr_max_alarm, - hwmon_curr_lcrit_alarm, - hwmon_curr_crit_alarm, - hwmon_curr_rated_min, - hwmon_curr_rated_max, - hwmon_curr_beep, -}; - -#define HWMON_C_ENABLE BIT(hwmon_curr_enable) -#define HWMON_C_INPUT BIT(hwmon_curr_input) -#define HWMON_C_MIN BIT(hwmon_curr_min) -#define HWMON_C_MAX BIT(hwmon_curr_max) -#define HWMON_C_LCRIT BIT(hwmon_curr_lcrit) -#define HWMON_C_CRIT BIT(hwmon_curr_crit) -#define HWMON_C_AVERAGE BIT(hwmon_curr_average) -#define HWMON_C_LOWEST BIT(hwmon_curr_lowest) -#define HWMON_C_HIGHEST BIT(hwmon_curr_highest) -#define HWMON_C_RESET_HISTORY BIT(hwmon_curr_reset_history) -#define HWMON_C_LABEL BIT(hwmon_curr_label) -#define HWMON_C_ALARM BIT(hwmon_curr_alarm) -#define HWMON_C_MIN_ALARM BIT(hwmon_curr_min_alarm) -#define HWMON_C_MAX_ALARM BIT(hwmon_curr_max_alarm) -#define HWMON_C_LCRIT_ALARM BIT(hwmon_curr_lcrit_alarm) -#define HWMON_C_CRIT_ALARM BIT(hwmon_curr_crit_alarm) -#define HWMON_C_RATED_MIN BIT(hwmon_curr_rated_min) -#define HWMON_C_RATED_MAX BIT(hwmon_curr_rated_max) -#define HWMON_C_BEEP BIT(hwmon_curr_beep) - -enum hwmon_power_attributes { - hwmon_power_enable, - hwmon_power_average, - hwmon_power_average_interval, - hwmon_power_average_interval_max, - hwmon_power_average_interval_min, - hwmon_power_average_highest, - hwmon_power_average_lowest, - hwmon_power_average_max, - hwmon_power_average_min, - hwmon_power_input, - hwmon_power_input_highest, - hwmon_power_input_lowest, - hwmon_power_reset_history, - hwmon_power_accuracy, - hwmon_power_cap, - hwmon_power_cap_hyst, - hwmon_power_cap_max, - hwmon_power_cap_min, - hwmon_power_min, - hwmon_power_max, - hwmon_power_crit, - hwmon_power_lcrit, - hwmon_power_label, - hwmon_power_alarm, - hwmon_power_cap_alarm, - hwmon_power_min_alarm, - hwmon_power_max_alarm, - hwmon_power_lcrit_alarm, - hwmon_power_crit_alarm, - hwmon_power_rated_min, - hwmon_power_rated_max, -}; - -#define HWMON_P_ENABLE BIT(hwmon_power_enable) -#define HWMON_P_AVERAGE BIT(hwmon_power_average) -#define HWMON_P_AVERAGE_INTERVAL BIT(hwmon_power_average_interval) -#define HWMON_P_AVERAGE_INTERVAL_MAX BIT(hwmon_power_average_interval_max) -#define HWMON_P_AVERAGE_INTERVAL_MIN BIT(hwmon_power_average_interval_min) -#define HWMON_P_AVERAGE_HIGHEST BIT(hwmon_power_average_highest) -#define HWMON_P_AVERAGE_LOWEST BIT(hwmon_power_average_lowest) -#define HWMON_P_AVERAGE_MAX BIT(hwmon_power_average_max) -#define HWMON_P_AVERAGE_MIN BIT(hwmon_power_average_min) -#define HWMON_P_INPUT BIT(hwmon_power_input) -#define HWMON_P_INPUT_HIGHEST BIT(hwmon_power_input_highest) -#define HWMON_P_INPUT_LOWEST BIT(hwmon_power_input_lowest) -#define HWMON_P_RESET_HISTORY BIT(hwmon_power_reset_history) -#define HWMON_P_ACCURACY BIT(hwmon_power_accuracy) -#define HWMON_P_CAP BIT(hwmon_power_cap) -#define HWMON_P_CAP_HYST BIT(hwmon_power_cap_hyst) -#define HWMON_P_CAP_MAX BIT(hwmon_power_cap_max) -#define HWMON_P_CAP_MIN BIT(hwmon_power_cap_min) -#define HWMON_P_MIN BIT(hwmon_power_min) -#define HWMON_P_MAX BIT(hwmon_power_max) -#define HWMON_P_LCRIT BIT(hwmon_power_lcrit) -#define HWMON_P_CRIT BIT(hwmon_power_crit) -#define HWMON_P_LABEL BIT(hwmon_power_label) -#define HWMON_P_ALARM BIT(hwmon_power_alarm) -#define HWMON_P_CAP_ALARM BIT(hwmon_power_cap_alarm) -#define HWMON_P_MIN_ALARM BIT(hwmon_power_min_alarm) -#define HWMON_P_MAX_ALARM BIT(hwmon_power_max_alarm) -#define HWMON_P_LCRIT_ALARM BIT(hwmon_power_lcrit_alarm) -#define HWMON_P_CRIT_ALARM BIT(hwmon_power_crit_alarm) -#define HWMON_P_RATED_MIN BIT(hwmon_power_rated_min) -#define HWMON_P_RATED_MAX BIT(hwmon_power_rated_max) - -enum hwmon_energy_attributes { - hwmon_energy_enable, - hwmon_energy_input, - hwmon_energy_label, -}; - -#define HWMON_E_ENABLE BIT(hwmon_energy_enable) -#define HWMON_E_INPUT BIT(hwmon_energy_input) -#define HWMON_E_LABEL BIT(hwmon_energy_label) - -enum hwmon_humidity_attributes { - hwmon_humidity_enable, - hwmon_humidity_input, - hwmon_humidity_label, - hwmon_humidity_min, - hwmon_humidity_min_hyst, - hwmon_humidity_max, - hwmon_humidity_max_hyst, - hwmon_humidity_alarm, - hwmon_humidity_fault, - hwmon_humidity_rated_min, - hwmon_humidity_rated_max, - hwmon_humidity_min_alarm, - hwmon_humidity_max_alarm, -}; - -#define HWMON_H_ENABLE BIT(hwmon_humidity_enable) -#define HWMON_H_INPUT BIT(hwmon_humidity_input) -#define HWMON_H_LABEL BIT(hwmon_humidity_label) -#define HWMON_H_MIN BIT(hwmon_humidity_min) -#define HWMON_H_MIN_HYST BIT(hwmon_humidity_min_hyst) -#define HWMON_H_MAX BIT(hwmon_humidity_max) -#define HWMON_H_MAX_HYST BIT(hwmon_humidity_max_hyst) -#define HWMON_H_ALARM BIT(hwmon_humidity_alarm) -#define HWMON_H_FAULT BIT(hwmon_humidity_fault) -#define HWMON_H_RATED_MIN BIT(hwmon_humidity_rated_min) -#define HWMON_H_RATED_MAX BIT(hwmon_humidity_rated_max) -#define HWMON_H_MIN_ALARM BIT(hwmon_humidity_min_alarm) -#define HWMON_H_MAX_ALARM BIT(hwmon_humidity_max_alarm) - -enum hwmon_fan_attributes { - hwmon_fan_enable, - hwmon_fan_input, - hwmon_fan_label, - hwmon_fan_min, - hwmon_fan_max, - hwmon_fan_div, - hwmon_fan_pulses, - hwmon_fan_target, - hwmon_fan_alarm, - hwmon_fan_min_alarm, - hwmon_fan_max_alarm, - hwmon_fan_fault, - hwmon_fan_beep, -}; - -#define HWMON_F_ENABLE BIT(hwmon_fan_enable) -#define HWMON_F_INPUT BIT(hwmon_fan_input) -#define HWMON_F_LABEL BIT(hwmon_fan_label) -#define HWMON_F_MIN BIT(hwmon_fan_min) -#define HWMON_F_MAX BIT(hwmon_fan_max) -#define HWMON_F_DIV BIT(hwmon_fan_div) -#define HWMON_F_PULSES BIT(hwmon_fan_pulses) -#define HWMON_F_TARGET BIT(hwmon_fan_target) -#define HWMON_F_ALARM BIT(hwmon_fan_alarm) -#define HWMON_F_MIN_ALARM BIT(hwmon_fan_min_alarm) -#define HWMON_F_MAX_ALARM BIT(hwmon_fan_max_alarm) -#define HWMON_F_FAULT BIT(hwmon_fan_fault) -#define HWMON_F_BEEP BIT(hwmon_fan_beep) - -enum hwmon_pwm_attributes { - hwmon_pwm_input, - hwmon_pwm_enable, - hwmon_pwm_mode, - hwmon_pwm_freq, - hwmon_pwm_auto_channels_temp, -}; - -#define HWMON_PWM_INPUT BIT(hwmon_pwm_input) -#define HWMON_PWM_ENABLE BIT(hwmon_pwm_enable) -#define HWMON_PWM_MODE BIT(hwmon_pwm_mode) -#define HWMON_PWM_FREQ BIT(hwmon_pwm_freq) -#define HWMON_PWM_AUTO_CHANNELS_TEMP BIT(hwmon_pwm_auto_channels_temp) - -enum hwmon_intrusion_attributes { - hwmon_intrusion_alarm, - hwmon_intrusion_beep, -}; -#define HWMON_INTRUSION_ALARM BIT(hwmon_intrusion_alarm) -#define HWMON_INTRUSION_BEEP BIT(hwmon_intrusion_beep) -/** * struct hwmon_ops - hwmon device operations * @visible: Static visibility. If non-zero, 'is_visible' is ignored. include/uapi/linux/hwmon.h new file +372
-0@@ -0,0 +1,372 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +/* +* Hardware monitoring sensor types, attributes and configuration bits. +* +* Copyright (C) 2005 Mark M. Hoffman <[email protected]> +* Copyright (C) 2026 Jihong Min <[email protected]> +*/ + +#ifndef _UAPI_LINUX_HWMON_H +#define _UAPI_LINUX_HWMON_H + +#include <linux/const.h> + +/* +* Existing identifiers are ABI: never change their values. Append new attributes +* at the end of their enum and new sensor types before hwmon_max. +*/ + +enum hwmon_sensor_types { + hwmon_chip =0 , + hwmon_temp =1 , + hwmon_in =2 , + hwmon_curr =3 , + hwmon_power =4 , + hwmon_energy =5 , + hwmon_energy64 =6 , + hwmon_humidity =7 , + hwmon_fan =8 , + hwmon_pwm =9 , + hwmon_intrusion =10 , + hwmon_max =11 , +}; + +enum hwmon_chip_attributes { + hwmon_chip_temp_reset_history =0 , + hwmon_chip_in_reset_history =1 , + hwmon_chip_curr_reset_history =2 , + hwmon_chip_power_reset_history =3 , + hwmon_chip_register_tz =4 , + hwmon_chip_update_interval =5 , + hwmon_chip_update_interval_us =6 , + hwmon_chip_alarms =7 , + hwmon_chip_samples =8 , + hwmon_chip_curr_samples =9 , + hwmon_chip_in_samples =10 , + hwmon_chip_power_samples =11 , + hwmon_chip_temp_samples =12 , + hwmon_chip_beep_enable =13 , + hwmon_chip_pec =14 , +}; + +#define HWMON_C_TEMP_RESET_HISTORY _BITUL(hwmon_chip_temp_reset_history) +#define HWMON_C_IN_RESET_HISTORY _BITUL(hwmon_chip_in_reset_history) +#define HWMON_C_CURR_RESET_HISTORY _BITUL(hwmon_chip_curr_reset_history) +#define HWMON_C_POWER_RESET_HISTORY _BITUL(hwmon_chip_power_reset_history) +#define HWMON_C_REGISTER_TZ _BITUL(hwmon_chip_register_tz) +#define HWMON_C_UPDATE_INTERVAL _BITUL(hwmon_chip_update_interval) +#define HWMON_C_UPDATE_INTERVAL_US _BITUL(hwmon_chip_update_interval_us) +#define HWMON_C_ALARMS _BITUL(hwmon_chip_alarms) +#define HWMON_C_SAMPLES _BITUL(hwmon_chip_samples) +#define HWMON_C_CURR_SAMPLES _BITUL(hwmon_chip_curr_samples) +#define HWMON_C_IN_SAMPLES _BITUL(hwmon_chip_in_samples) +#define HWMON_C_POWER_SAMPLES _BITUL(hwmon_chip_power_samples) +#define HWMON_C_TEMP_SAMPLES _BITUL(hwmon_chip_temp_samples) +#define HWMON_C_BEEP_ENABLE _BITUL(hwmon_chip_beep_enable) +#define HWMON_C_PEC _BITUL(hwmon_chip_pec) + +enum hwmon_temp_attributes { + hwmon_temp_enable =0 , + hwmon_temp_input =1 , + hwmon_temp_type =2 , + hwmon_temp_lcrit =3 , + hwmon_temp_lcrit_hyst =4 , + hwmon_temp_min =5 , + hwmon_temp_min_hyst =6 , + hwmon_temp_max =7 , + hwmon_temp_max_hyst =8 , + hwmon_temp_crit =9 , + hwmon_temp_crit_hyst =10 , + hwmon_temp_emergency =11 , + hwmon_temp_emergency_hyst =12 , + hwmon_temp_alarm =13 , + hwmon_temp_lcrit_alarm =14 , + hwmon_temp_min_alarm =15 , + hwmon_temp_max_alarm =16 , + hwmon_temp_crit_alarm =17 , + hwmon_temp_emergency_alarm =18 , + hwmon_temp_fault =19 , + hwmon_temp_offset =20 , + hwmon_temp_label =21 , + hwmon_temp_lowest =22 , + hwmon_temp_highest =23 , + hwmon_temp_reset_history =24 , + hwmon_temp_rated_min =25 , + hwmon_temp_rated_max =26 , + hwmon_temp_beep =27 , +}; + +#define HWMON_T_ENABLE _BITUL(hwmon_temp_enable) +#define HWMON_T_INPUT _BITUL(hwmon_temp_input) +#define HWMON_T_TYPE _BITUL(hwmon_temp_type) +#define HWMON_T_LCRIT _BITUL(hwmon_temp_lcrit) +#define HWMON_T_LCRIT_HYST _BITUL(hwmon_temp_lcrit_hyst) +#define HWMON_T_MIN _BITUL(hwmon_temp_min) +#define HWMON_T_MIN_HYST _BITUL(hwmon_temp_min_hyst) +#define HWMON_T_MAX _BITUL(hwmon_temp_max) +#define HWMON_T_MAX_HYST _BITUL(hwmon_temp_max_hyst) +#define HWMON_T_CRIT _BITUL(hwmon_temp_crit) +#define HWMON_T_CRIT_HYST _BITUL(hwmon_temp_crit_hyst) +#define HWMON_T_EMERGENCY _BITUL(hwmon_temp_emergency) +#define HWMON_T_EMERGENCY_HYST _BITUL(hwmon_temp_emergency_hyst) +#define HWMON_T_ALARM _BITUL(hwmon_temp_alarm) +#define HWMON_T_MIN_ALARM _BITUL(hwmon_temp_min_alarm) +#define HWMON_T_MAX_ALARM _BITUL(hwmon_temp_max_alarm) +#define HWMON_T_CRIT_ALARM _BITUL(hwmon_temp_crit_alarm) +#define HWMON_T_LCRIT_ALARM _BITUL(hwmon_temp_lcrit_alarm) +#define HWMON_T_EMERGENCY_ALARM _BITUL(hwmon_temp_emergency_alarm) +#define HWMON_T_FAULT _BITUL(hwmon_temp_fault) +#define HWMON_T_OFFSET _BITUL(hwmon_temp_offset) +#define HWMON_T_LABEL _BITUL(hwmon_temp_label) +#define HWMON_T_LOWEST _BITUL(hwmon_temp_lowest) +#define HWMON_T_HIGHEST _BITUL(hwmon_temp_highest) +#define HWMON_T_RESET_HISTORY _BITUL(hwmon_temp_reset_history) +#define HWMON_T_RATED_MIN _BITUL(hwmon_temp_rated_min) +#define HWMON_T_RATED_MAX _BITUL(hwmon_temp_rated_max) +#define HWMON_T_BEEP _BITUL(hwmon_temp_beep) + +enum hwmon_in_attributes { + hwmon_in_enable =0 , + hwmon_in_input =1 , + hwmon_in_min =2 , + hwmon_in_max =3 , + hwmon_in_lcrit =4 , + hwmon_in_crit =5 , + hwmon_in_average =6 , + hwmon_in_lowest =7 , + hwmon_in_highest =8 , + hwmon_in_reset_history =9 , + hwmon_in_label =10 , + hwmon_in_alarm =11 , + hwmon_in_min_alarm =12 , + hwmon_in_max_alarm =13 , + hwmon_in_lcrit_alarm =14 , + hwmon_in_crit_alarm =15 , + hwmon_in_rated_min =16 , + hwmon_in_rated_max =17 , + hwmon_in_beep =18 , + hwmon_in_fault =19 , +}; + +#define HWMON_I_ENABLE _BITUL(hwmon_in_enable) +#define HWMON_I_INPUT _BITUL(hwmon_in_input) +#define HWMON_I_MIN _BITUL(hwmon_in_min) +#define HWMON_I_MAX _BITUL(hwmon_in_max) +#define HWMON_I_LCRIT _BITUL(hwmon_in_lcrit) +#define HWMON_I_CRIT _BITUL(hwmon_in_crit) +#define HWMON_I_AVERAGE _BITUL(hwmon_in_average) +#define HWMON_I_LOWEST _BITUL(hwmon_in_lowest) +#define HWMON_I_HIGHEST _BITUL(hwmon_in_highest) +#define HWMON_I_RESET_HISTORY _BITUL(hwmon_in_reset_history) +#define HWMON_I_LABEL _BITUL(hwmon_in_label) +#define HWMON_I_ALARM _BITUL(hwmon_in_alarm) +#define HWMON_I_MIN_ALARM _BITUL(hwmon_in_min_alarm) +#define HWMON_I_MAX_ALARM _BITUL(hwmon_in_max_alarm) +#define HWMON_I_LCRIT_ALARM _BITUL(hwmon_in_lcrit_alarm) +#define HWMON_I_CRIT_ALARM _BITUL(hwmon_in_crit_alarm) +#define HWMON_I_RATED_MIN _BITUL(hwmon_in_rated_min) +#define HWMON_I_RATED_MAX _BITUL(hwmon_in_rated_max) +#define HWMON_I_BEEP _BITUL(hwmon_in_beep) +#define HWMON_I_FAULT _BITUL(hwmon_in_fault) + +enum hwmon_curr_attributes { + hwmon_curr_enable =0 , + hwmon_curr_input =1 , + hwmon_curr_min =2 , + hwmon_curr_max =3 , + hwmon_curr_lcrit =4 , + hwmon_curr_crit =5 , + hwmon_curr_average =6 , + hwmon_curr_lowest =7 , + hwmon_curr_highest =8 , + hwmon_curr_reset_history =9 , + hwmon_curr_label =10 , + hwmon_curr_alarm =11 , + hwmon_curr_min_alarm =12 , + hwmon_curr_max_alarm =13 , + hwmon_curr_lcrit_alarm =14 , + hwmon_curr_crit_alarm =15 , + hwmon_curr_rated_min =16 , + hwmon_curr_rated_max =17 , + hwmon_curr_beep =18 , +}; + +#define HWMON_C_ENABLE _BITUL(hwmon_curr_enable) +#define HWMON_C_INPUT _BITUL(hwmon_curr_input) +#define HWMON_C_MIN _BITUL(hwmon_curr_min) +#define HWMON_C_MAX _BITUL(hwmon_curr_max) +#define HWMON_C_LCRIT _BITUL(hwmon_curr_lcrit) +#define HWMON_C_CRIT _BITUL(hwmon_curr_crit) +#define HWMON_C_AVERAGE _BITUL(hwmon_curr_average) +#define HWMON_C_LOWEST _BITUL(hwmon_curr_lowest) +#define HWMON_C_HIGHEST _BITUL(hwmon_curr_highest) +#define HWMON_C_RESET_HISTORY _BITUL(hwmon_curr_reset_history) +#define HWMON_C_LABEL _BITUL(hwmon_curr_label) +#define HWMON_C_ALARM _BITUL(hwmon_curr_alarm) +#define HWMON_C_MIN_ALARM _BITUL(hwmon_curr_min_alarm) +#define HWMON_C_MAX_ALARM _BITUL(hwmon_curr_max_alarm) +#define HWMON_C_LCRIT_ALARM _BITUL(hwmon_curr_lcrit_alarm) +#define HWMON_C_CRIT_ALARM _BITUL(hwmon_curr_crit_alarm) +#define HWMON_C_RATED_MIN _BITUL(hwmon_curr_rated_min) +#define HWMON_C_RATED_MAX _BITUL(hwmon_curr_rated_max) +#define HWMON_C_BEEP _BITUL(hwmon_curr_beep) + +enum hwmon_power_attributes { + hwmon_power_enable =0 , + hwmon_power_average =1 , + hwmon_power_average_interval =2 , + hwmon_power_average_interval_max =3 , + hwmon_power_average_interval_min =4 , + hwmon_power_average_highest =5 , + hwmon_power_average_lowest =6 , + hwmon_power_average_max =7 , + hwmon_power_average_min =8 , + hwmon_power_input =9 , + hwmon_power_input_highest =10 , + hwmon_power_input_lowest =11 , + hwmon_power_reset_history =12 , + hwmon_power_accuracy =13 , + hwmon_power_cap =14 , + hwmon_power_cap_hyst =15 , + hwmon_power_cap_max =16 , + hwmon_power_cap_min =17 , + hwmon_power_min =18 , + hwmon_power_max =19 , + hwmon_power_crit =20 , + hwmon_power_lcrit =21 , + hwmon_power_label =22 , + hwmon_power_alarm =23 , + hwmon_power_cap_alarm =24 , + hwmon_power_min_alarm =25 , + hwmon_power_max_alarm =26 , + hwmon_power_lcrit_alarm =27 , + hwmon_power_crit_alarm =28 , + hwmon_power_rated_min =29 , + hwmon_power_rated_max =30 , +}; + +#define HWMON_P_ENABLE _BITUL(hwmon_power_enable) +#define HWMON_P_AVERAGE _BITUL(hwmon_power_average) +#define HWMON_P_AVERAGE_INTERVAL _BITUL(hwmon_power_average_interval) +#define HWMON_P_AVERAGE_INTERVAL_MAX _BITUL(hwmon_power_average_interval_max) +#define HWMON_P_AVERAGE_INTERVAL_MIN _BITUL(hwmon_power_average_interval_min) +#define HWMON_P_AVERAGE_HIGHEST _BITUL(hwmon_power_average_highest) +#define HWMON_P_AVERAGE_LOWEST _BITUL(hwmon_power_average_lowest) +#define HWMON_P_AVERAGE_MAX _BITUL(hwmon_power_average_max) +#define HWMON_P_AVERAGE_MIN _BITUL(hwmon_power_average_min) +#define HWMON_P_INPUT _BITUL(hwmon_power_input) +#define HWMON_P_INPUT_HIGHEST _BITUL(hwmon_power_input_highest) +#define HWMON_P_INPUT_LOWEST _BITUL(hwmon_power_input_lowest) +#define HWMON_P_RESET_HISTORY _BITUL(hwmon_power_reset_history) +#define HWMON_P_ACCURACY _BITUL(hwmon_power_accuracy) +#define HWMON_P_CAP _BITUL(hwmon_power_cap) +#define HWMON_P_CAP_HYST _BITUL(hwmon_power_cap_hyst) +#define HWMON_P_CAP_MAX _BITUL(hwmon_power_cap_max) +#define HWMON_P_CAP_MIN _BITUL(hwmon_power_cap_min) +#define HWMON_P_MIN _BITUL(hwmon_power_min) +#define HWMON_P_MAX _BITUL(hwmon_power_max) +#define HWMON_P_LCRIT _BITUL(hwmon_power_lcrit) +#define HWMON_P_CRIT _BITUL(hwmon_power_crit) +#define HWMON_P_LABEL _BITUL(hwmon_power_label) +#define HWMON_P_ALARM _BITUL(hwmon_power_alarm) +#define HWMON_P_CAP_ALARM _BITUL(hwmon_power_cap_alarm) +#define HWMON_P_MIN_ALARM _BITUL(hwmon_power_min_alarm) +#define HWMON_P_MAX_ALARM _BITUL(hwmon_power_max_alarm) +#define HWMON_P_LCRIT_ALARM _BITUL(hwmon_power_lcrit_alarm) +#define HWMON_P_CRIT_ALARM _BITUL(hwmon_power_crit_alarm) +#define HWMON_P_RATED_MIN _BITUL(hwmon_power_rated_min) +#define HWMON_P_RATED_MAX _BITUL(hwmon_power_rated_max) + +enum hwmon_energy_attributes { + hwmon_energy_enable =0 , + hwmon_energy_input =1 , + hwmon_energy_label =2 , +}; + +#define HWMON_E_ENABLE _BITUL(hwmon_energy_enable) +#define HWMON_E_INPUT _BITUL(hwmon_energy_input) +#define HWMON_E_LABEL _BITUL(hwmon_energy_label) + +enum hwmon_humidity_attributes { + hwmon_humidity_enable =0 , + hwmon_humidity_input =1 , + hwmon_humidity_label =2 , + hwmon_humidity_min =3 , + hwmon_humidity_min_hyst =4 , + hwmon_humidity_max =5 , + hwmon_humidity_max_hyst =6 , + hwmon_humidity_alarm =7 , + hwmon_humidity_fault =8 , + hwmon_humidity_rated_min =9 , + hwmon_humidity_rated_max =10 , + hwmon_humidity_min_alarm =11 , + hwmon_humidity_max_alarm =12 , +}; + +#define HWMON_H_ENABLE _BITUL(hwmon_humidity_enable) +#define HWMON_H_INPUT _BITUL(hwmon_humidity_input) +#define HWMON_H_LABEL _BITUL(hwmon_humidity_label) +#define HWMON_H_MIN _BITUL(hwmon_humidity_min) +#define HWMON_H_MIN_HYST _BITUL(hwmon_humidity_min_hyst) +#define HWMON_H_MAX _BITUL(hwmon_humidity_max) +#define HWMON_H_MAX_HYST _BITUL(hwmon_humidity_max_hyst) +#define HWMON_H_ALARM _BITUL(hwmon_humidity_alarm) +#define HWMON_H_FAULT _BITUL(hwmon_humidity_fault) +#define HWMON_H_RATED_MIN _BITUL(hwmon_humidity_rated_min) +#define HWMON_H_RATED_MAX _BITUL(hwmon_humidity_rated_max) +#define HWMON_H_MIN_ALARM _BITUL(hwmon_humidity_min_alarm) +#define HWMON_H_MAX_ALARM _BITUL(hwmon_humidity_max_alarm) + +enum hwmon_fan_attributes { + hwmon_fan_enable =0 , + hwmon_fan_input =1 , + hwmon_fan_label =2 , + hwmon_fan_min =3 , + hwmon_fan_max =4 , + hwmon_fan_div =5 , + hwmon_fan_pulses =6 , + hwmon_fan_target =7 , + hwmon_fan_alarm =8 , + hwmon_fan_min_alarm =9 , + hwmon_fan_max_alarm =10 , + hwmon_fan_fault =11 , + hwmon_fan_beep =12 , +}; + +#define HWMON_F_ENABLE _BITUL(hwmon_fan_enable) +#define HWMON_F_INPUT _BITUL(hwmon_fan_input) +#define HWMON_F_LABEL _BITUL(hwmon_fan_label) +#define HWMON_F_MIN _BITUL(hwmon_fan_min) +#define HWMON_F_MAX _BITUL(hwmon_fan_max) +#define HWMON_F_DIV _BITUL(hwmon_fan_div) +#define HWMON_F_PULSES _BITUL(hwmon_fan_pulses) +#define HWMON_F_TARGET _BITUL(hwmon_fan_target) +#define HWMON_F_ALARM _BITUL(hwmon_fan_alarm) +#define HWMON_F_MIN_ALARM _BITUL(hwmon_fan_min_alarm) +#define HWMON_F_MAX_ALARM _BITUL(hwmon_fan_max_alarm) +#define HWMON_F_FAULT _BITUL(hwmon_fan_fault) +#define HWMON_F_BEEP _BITUL(hwmon_fan_beep) + +enum hwmon_pwm_attributes { + hwmon_pwm_input =0 , + hwmon_pwm_enable =1 , + hwmon_pwm_mode =2 , + hwmon_pwm_freq =3 , + hwmon_pwm_auto_channels_temp =4 , +}; + +#define HWMON_PWM_INPUT _BITUL(hwmon_pwm_input) +#define HWMON_PWM_ENABLE _BITUL(hwmon_pwm_enable) +#define HWMON_PWM_MODE _BITUL(hwmon_pwm_mode) +#define HWMON_PWM_FREQ _BITUL(hwmon_pwm_freq) +#define HWMON_PWM_AUTO_CHANNELS_TEMP _BITUL(hwmon_pwm_auto_channels_temp) + +enum hwmon_intrusion_attributes { + hwmon_intrusion_alarm =0 , + hwmon_intrusion_beep =1 , +}; + +#define HWMON_INTRUSION_ALARM _BITUL(hwmon_intrusion_alarm) +#define HWMON_INTRUSION_BEEP _BITUL(hwmon_intrusion_beep) + +#endif /* _UAPI_LINUX_HWMON_H */
PATCH 2/5 hwmon: Expose attribute validation and string helpers
In reply to Jihong MinExpose the core's string classification and sysfs template validation through the kernel hwmon API. Let drivers query these properties without maintaining separate attribute tables.
Reuse the helpers when creating attributes.
--- drivers/hwmon/hwmon.c | 30 +++++++++++++++++++++++++----- include/linux/hwmon.h | 3 +++ 2 files changed, 28 insertions(+), 5 deletions(-)
drivers/hwmon/hwmon.c +25 -5
@@ -502,7 +502,14 @@ static ssize_t hwmon_attr_store(struct device *dev,return count; } -static bool is_string_attr (enum hwmon_sensor_types type,u32 attr) +/** +* hwmon_is_string_attr - test whether an attribute returns a string +* @type: sensor type +* @attr: attribute identifier +* +* Return: true for string attributes, false otherwise. +*/ +bool hwmon_is_string_attr (enum hwmon_sensor_types type,u32 attr) {return (type == hwmon_temp && attr == hwmon_temp_label) || (type == hwmon_in && attr == hwmon_in_label) ||
@@ -513,6 +520,7 @@ static bool is_string_attr(enum hwmon_sensor_types type, u32 attr) (type == hwmon_humidity && attr == hwmon_humidity_label) || (type == hwmon_fan && attr == hwmon_fan_label); } +EXPORT_SYMBOL_GPL (hwmon_is_string_attr); static const struct attribute *hwmon_genattr(const void *drvdata, enum hwmon_sensor_types type,
@@ -526,7 +534,7 @@ static const struct attribute *hwmon_genattr(const void *drvdata,struct attribute *a;umode_t mode;const char *name; -bool is_string =is_string_attr (type, attr); +bool is_string =hwmon_is_string_attr (type, attr); mode =hwmon_is_visible (ops, drvdata, type, attr, index);if (!mode)
@@ -776,6 +784,20 @@ static const int __templates_size[] = { [hwmon_intrusion] = ARRAY_SIZE(hwmon_intrusion_attr_templates), }; +/** +* hwmon_is_valid_attr - test whether an attribute has a sysfs template +* @type: sensor type +* @attr: attribute identifier +* +* Return: true for supported sysfs attributes, false otherwise. +*/ +bool hwmon_is_valid_attr (enum hwmon_sensor_types type,u32 attr) +{ +return (unsigned int )type <ARRAY_SIZE (__templates) && + attr < __templates_size[type] && __templates[type][attr]; +} +EXPORT_SYMBOL_GPL (hwmon_is_valid_attr); +int hwmon_notify_event (struct device *dev,enum hwmon_sensor_types type,u32 attr,int channel) {
@@ -843,14 +865,12 @@ static int hwmon_genattrs(const void *drvdata, const struct hwmon_channel_info *info) {const char *const *templates; -int template_size;int i, aindex =0 ;if (info->type >=ARRAY_SIZE (__templates))return -EINVAL ; templates = __templates[info->type]; - template_size = __templates_size[info->type];for (i =0 ; info->config[i]; i++) {u32 attr_mask = info->config[i];
@@ -861,7 +881,7 @@ static int hwmon_genattrs(const void *drvdata, attr =__ffs (attr_mask); attr_mask &= ~BIT (attr); -if (attr >= template_size || !templates[attr]) +if (!hwmon_is_valid_attr (info->type, attr))continue ;/* attribute is invisible */ a =hwmon_genattr (drvdata, info->type, attr, i, templates[attr], ops);
include/linux/hwmon.h +3 -0
@@ -138,6 +138,9 @@ devm_hwmon_device_register_with_info(struct device *dev,void hwmon_device_unregister (struct device *dev); +bool hwmon_is_valid_attr (enum hwmon_sensor_types type,u32 attr); +bool hwmon_is_string_attr (enum hwmon_sensor_types type,u32 attr); +int hwmon_notify_event (struct device *dev,enum hwmon_sensor_types type,u32 attr,int channel);
[email protected]
AI reviewRe: [PATCH 2/5] hwmon: Expose attribute validation and string helpers
Sashiko has reviewed this patch and found no issues. It looks great!
Quoted 8 lines
Expose the core's string classification and sysfs template validation through the kernel hwmon API. Let drivers query these properties without maintaining separate attribute tables.
Reuse the helpers when creating attributes.
Assisted-by Codex:gpt-6-astraSigned-off-by Jihong Min <[email protected]>
Sashiko has reviewed this patch and found no issues. It looks great!
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=2
PATCH 3/5 hwmon: Add a generic interface for userspace implementations
In reply to Jihong MinAdd /dev/uhwmon so userspace drivers can expose standard hwmon attributes. Use the shared hwmon identifiers directly and forward numeric values or labels through read and write requests.
Reuse hwmon sysfs formatting and notifications. Preserve devices across daemon disconnects and support reconnection or explicit removal.
--- .../userspace-api/ioctl/ioctl-number.rst | 1 + MAINTAINERS | 1 + drivers/hwmon/Kconfig | 9 + drivers/hwmon/Makefile | 1 + drivers/hwmon/uhwmon.c | 641 ++++++++++++++++++ include/uapi/linux/uhwmon.h | 64 ++ 6 files changed, 717 insertions(+) create mode 100644 drivers/hwmon/uhwmon.c create mode 100644 include/uapi/linux/uhwmon.h
Documentation/userspace-api/ioctl/ioctl-number.rst +1 -0
@@ -384,6 +384,7 @@ Code Seq# Include File Comments 0xB8 01-02 uapi/misc/mrvl_cn10k_dpi.h Marvell CN10K DPI driver 0xB8 all uapi/linux/mshv.h Microsoft Hyper-V /dev/mshv driver <mailto:[email protected]> +0xB9 00-02 uapi/linux/uhwmon.h Userspace hardware monitoring 0xBA 00-0F uapi/linux/liveupdate.h Pasha Tatashin <mailto:[email protected]> 0xC0 00-0F linux/usb/iowarrior.h
MAINTAINERS +1 -0
@@ -11493,6 +11493,7 @@ F: drivers/hwmon/ F: include/linux/hwmon*.h F: include/trace/events/hwmon*.h F: include/uapi/linux/hwmon.h +F: include/uapi/linux/uhwmon.h K: (devm_)?hwmon_device_(un)?register(|_with_groups|_with_info) HARDWARE RANDOM NUMBER GENERATOR CORE
drivers/hwmon/Kconfig +9 -0
@@ -2537,6 +2537,15 @@ config SENSORS_TSC1641 This driver can also be built as a module. If so, the module will be called tsc1641. +config SENSORS_UHWMON + tristate "Userspace hardware monitoring devices" + help + Provide a standard interface for userspace hwmon drivers through + /dev/uhwmon. + + This driver can also be built as a module. If so, the module + will be called uhwmon. + config SENSORS_VEXPRESS tristate "Versatile Express" depends on VEXPRESS_CONFIG
drivers/hwmon/Makefile +1 -0
@@ -242,6 +242,7 @@ obj-$(CONFIG_SENSORS_TMP421) += tmp421.o obj-$(CONFIG_SENSORS_TMP464) += tmp464.o obj-$(CONFIG_SENSORS_TMP513) += tmp513.o obj-$(CONFIG_SENSORS_TSC1641) += tsc1641.o +obj-$(CONFIG_SENSORS_UHWMON) += uhwmon.o obj-$(CONFIG_SENSORS_VEXPRESS) += vexpress-hwmon.o obj-$(CONFIG_SENSORS_VIA_CPUTEMP)+= via-cputemp.o obj-$(CONFIG_SENSORS_VIA686A) += via686a.o
drivers/hwmon/uhwmon.c new file +641 -0
641 lines not on this page · raw message
include/uapi/linux/uhwmon.h new file +64 -0
64 lines not on this page · raw message
[email protected]
AI reviewRe: [PATCH 3/5] hwmon: Add a generic interface for userspace implementations
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider: - [High] hwmon: O(N^2) attribute validation loop causes CPU soft lockup - [High] sysfs: 1-byte buffer…
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [High] hwmon: O(N^2) attribute validation loop causes CPU soft lockup
- [High] sysfs: 1-byte buffer overflow in hwmon_attr_show_string due to PAGE_SIZE limit
- [Medium] driver-core: invalid teardown order in uhwmon_exit() destroys parent before children --
commit c2824f78f1fac4c2c5b17a97b2a2b5679a625be3
Author: Jihong Min <[email protected]>
hwmon: Add a generic interface for userspace implementations
Add /dev/uhwmon so userspace drivers can expose standard hwmon attributes. Use the shared hwmon identifiers directly and forward numeric values or labels through read and write requests.
Quoted 27 lines
drivers/hwmon/uhwmon.c new file +19
-0@@ -0,0 +1,641 @@ +static int uhwmon_create (struct file *file,void __user *arg) +{ +for (i =0 ; i < data->num_attrs; i++) { +struct uhwmon_attr *attr = &data->attrs[i]; +u32 type; +bool string; + + ret = -EINVAL ; +if (spec[i].attr >=32 || + !hwmon_is_valid_attr (spec[i].type, spec[i].attr) || + !spec[i].mode || spec[i].mode & ~0644 || + spec[i].flags & ~UHWMON_ATTR_CONSTANT ) + goto out; +if (spec[i].type == hwmon_chip && spec[i].channel) + goto out; +/* +* N is a zero-based channel index: channels 0..N need at least +* N + 1 attribute slots, plus a NULL terminator. The core uses +* int counts, so N + 2 <= INT_MAX. The full count is checked below.
drivers/hwmon/uhwmon.c line 314
Quoted 10 lines
drivers/hwmon/uhwmon.c new file +10
-0+*/ +if (spec[i].channel >INT_MAX -2 ) { + ret = -EOVERFLOW ; + goto out; + } + string =hwmon_is_string_attr (spec[i].type, spec[i].attr); +if (string) { +if (!spec[i].size || spec[i].size >PAGE_SIZE || + spec[i].mode &0222 || spec[i].value) + goto out;
[Severity: High]
Does this PAGE_SIZE check leave enough room for the newline character appended by the hwmon core?
If a daemon writes a string of length PAGE_SIZE - 1 plus a null terminator, when read via sysfs, the hwmon core passes this string to sprintf(buf, "%s\n", s) where buf is exactly PAGE_SIZE bytes.
This would write PAGE_SIZE - 1 characters, followed by the newline and null terminator, totaling PAGE_SIZE + 1 bytes.
Could this cause a 1-byte overflow and memory corruption?
Quoted 6 lines
drivers/hwmon/uhwmon.c new file +5
-0+ }else if (spec[i].size || spec[i].text) { + goto out; + } + type = spec[i].type == hwmon_energy64 ? hwmon_energy : + spec[i].type;
drivers/hwmon/uhwmon.c line 353
Quoted 10 lines
drivers/hwmon/uhwmon.c new file +10
-0+for (j =0 ; j < i; j++) { +u32 other_type = spec[j].type == hwmon_energy64 ? + hwmon_energy : + spec[j].type; + +if (type == other_type && + spec[i].attr == spec[j].attr && + spec[i].channel == spec[j].channel) + goto out; + }
[Severity: High]
Can this nested loop cause a CPU soft lockup?
Since uhwmon_create() accepts a user-provided num_attrs bounded only by kmalloc limits (which could exceed 100,000 attributes depending on max slab size), this loop compares every attribute against all preceding attributes to prevent duplicates.
For a large number of attributes, this results in billions of iterations.
As the loop lacks preemption points like cond_resched(), could it hold the CPU exclusively for multiple seconds and trigger the soft lockup watchdog?
Quoted 7 lines
drivers/hwmon/uhwmon.c new file +6
-0+ attr->spec = spec[i]; + attr->spec.text =0 ; + counts[spec[i].type] = +max (counts[spec[i].type], spec[i].channel +1 ); + } +static void __exit uhwmon_exit(void)
drivers/hwmon/uhwmon.c line 450
Quoted 10 lines
drivers/hwmon/uhwmon.c new file +10
-0+{ +struct uhwmon_device *data, *next; + +misc_deregister (&uhwmon_misc); +list_for_each_entry_safe (data, next, &uhwmon_devices, node) { +uhwmon_unregister (data); +list_del (&data->node); +uhwmon_free (data); + } +}
[Severity: Medium]
Is it safe to deregister the parent miscdevice before unregistering the child hwmon devices?
Calling misc_deregister() destroys uhwmon_misc.this_device, which is the parent of all registered hwmon devices. Destroying a parent device before its children violates the driver core's topological ordering and lifecycle rules.
Could this cause sysfs warnings and potential use-after-free when the children subsequently attempt to unregister their sysfs directories from the already-deleted parent?
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=3
Re: [PATCH 3/5] hwmon: Add a generic interface for userspace implementations
In reply to Jihong Min…
Quoted 2 lines
+++
b/drivers/hwmon/uhwmon.c(quoted diff) +0
-0@@ -0,0 +1,641 @@
…
Quoted 4 lines
drivers/hwmon/uhwmon.c new file +4
-0+static void uhwmon_disconnect (struct uhwmon_device *data) +{ +mutex_lock (&data->lock); + data->online = false;
…
drivers/hwmon/uhwmon.c line 102
Quoted 3 lines
drivers/hwmon/uhwmon.c new file +3
-0+mutex_unlock (&data->lock); +wake_up_all (&data->wait); +}
…
Under which circumstances would you become interested to apply a statement like “guard(mutex)(&data->lock);”?
https://elixir.bootlin.com/linux/v7.3-rc6/source/include/linux/mutex.h#L253
Regards,
Markus
PATCH 4/5 hwmon: Reject truncated attribute names
In reply to Jihong MinLarge channel numbers can produce truncated or conflicting attribute names. Return -EOVERFLOW if a generated name does not fit its buffer.
--- drivers/hwmon/hwmon.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
drivers/hwmon/hwmon.c +6 -2
@@ -553,8 +553,12 @@ static const struct attribute *hwmon_genattr(const void *drvdata,if (type == hwmon_chip) { name = template; }else { -scnprintf (hattr->name,sizeof (hattr->name), template, - index +hwmon_attr_base (type)); +if (snprintf (hattr->name,sizeof (hattr->name), template, + index +hwmon_attr_base (type)) >= +sizeof (hattr->name)) { +kfree (hattr); +return ERR_PTR (-EOVERFLOW ); + } name = hattr->name; }
[email protected]
AI reviewRe: [PATCH 4/5] hwmon: Reject truncated attribute names
Sashiko has reviewed this patch and found no issues. It looks great!
Quoted 5 lines
Large channel numbers can produce truncated or conflicting attribute names. Return
-EOVERFLOWif a generated name does not fit its buffer.Assisted-by Codex:gpt-6-astraSigned-off-by Jihong Min <[email protected]>
Sashiko has reviewed this patch and found no issues. It looks great!
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=4
PATCH 5/5 docs: hwmon: Document the uhwmon userspace interface
In reply to Jihong MinDocument the uhwmon UAPI for developers implementing userspace hwmon drivers. Cover device registration, request handling, notifications and device lifetime.
--- Documentation/hwmon/index.rst | 1 + Documentation/hwmon/uhwmon.rst | 141 +++++++++++++++++++++++++++++++++ 2 files changed, 142 insertions(+) create mode 100644 Documentation/hwmon/uhwmon.rst
Documentation/hwmon/index.rst +1 -0
@@ -12,6 +12,7 @@ Hardware Monitoring submitting-patches sysfs-interface userspace-tools + uhwmon Hardware Monitoring Kernel Drivers ==================================
Documentation/hwmon/uhwmon.rst new file +141 -0
141 lines not on this page · raw message
[email protected]
AI reviewRe: [PATCH 5/5] docs: hwmon: Document the uhwmon userspace interface
Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider: - [High] hwmon: uhwmon: userfaultfd-based unkillable hangs via copy_to_user under mutex - [High] hwmon…
Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:
- [High] hwmon: uhwmon: userfaultfd-based unkillable hangs via copy_to_user under mutex
- [High] hwmon: uhwmon: name collision logic blocks multiple devices and schema updates
- [High] hwmon: wait_event_killable() in uhwmon_request() allows daemon to hang sysfs
- [Medium] hwmon: uhwmon: uhwmon_exit() destroys parent miscdevice before child hwmon devices --
commit b2f6043289b80f507b7c7bd6ff84bc7129c9ba48
Author: Jihong Min <[email protected]>
docs: hwmon: Document the uhwmon userspace interface
This commit introduces the uhwmon userspace API documentation, which connects userspace drivers to hwmon_ops through the /dev/uhwmon control device. It details how developers can register devices, handle requests, notify changes, and manage device lifetimes.
Quoted 6 lines
drivers/hwmon/uhwmon.c new file +0
-0@@ -0,0 +1,641 @@
[ ... ]
Quoted 3 lines
drivers/hwmon/uhwmon.c new file +3
-0+static int uhwmon_request (struct uhwmon_device *data,unsigned int index, +u32 op,s64 *value) +{
[ ... ]
drivers/hwmon/uhwmon.c
Quoted 8 lines
drivers/hwmon/uhwmon.c new file +8
-0+ ret =wait_event_interruptible (data->wait,READ_ONCE (pending.done)); +mutex_lock (&data->lock); +if (!pending.done && !data->readable) { +/* Once delivered, only fatal signals may abort the wait. */ +mutex_unlock (&data->lock); + ret =wait_event_killable (data->wait,READ_ONCE (pending.done)); +mutex_lock (&data->lock); + }
[Severity: High]
Does wait_event_killable() here allow the daemon to hang sysfs?
Because TASK_KILLABLE only responds to fatal signals, monitoring utilities (like sensors or prometheus-node-exporter) that catch SIGTERM or SIGINT will become unkillable and fail to shut down cleanly, delaying system reboots by up to 90 seconds.
Any user with sysfs access can read the sensor, and any bug in the daemon can trigger the hang. Although the daemon requires root to open /dev/uhwmon, a buggy daemon shouldn't cause unkillable kernel deadlocks.
[ ... ]
Quoted 3 lines
drivers/hwmon/uhwmon.c new file +3
-0+static int uhwmon_create (struct file *file,void __user *arg) +{ +struct uhwmon_device *data, *existing;
[ ... ]
drivers/hwmon/uhwmon.c
Quoted 6 lines
drivers/hwmon/uhwmon.c new file +6
-0+ data =kzalloc_obj (*data); +if (!data) +return -ENOMEM ; +mutex_init (&data->lock); +init_waitqueue_head (&data->wait); + data->name =strndup_user (u64_to_user_ptr (create.name),NAME_MAX +1 );
[Severity: High]
Could this strndup_user() combined with memdup_array_user() below cause an unkillable hang?
uhwmon_create() is called from uhwmon_ioctl() which holds the global uhwmon_control_lock. If a daemon issues an ioctl(UHWMON_CREATE) providing a buffer backed by userfaultfd, the kernel will block indefinitely while holding uhwmon_control_lock.
This freezes all device creation, notification, and release, causing a local denial of service.
[ ... ]
drivers/hwmon/uhwmon.c
Quoted 10 lines
drivers/hwmon/uhwmon.c new file +10
-0+list_for_each_entry (existing, &uhwmon_devices, node) { +if (strcmp (existing->name, data->name)) +continue ; + ret = -EBUSY ; +if (existing->online) + goto out; + ret = -EINVAL ; +if (!uhwmon_same_schema (existing, data)) + goto out; +mutex_lock (&existing->lock);
[Severity: High]
Is it possible that this rigid name-matching logic incorrectly rejects valid registrations?
It appears to block multiple independent devices from sharing the same name by returning -EBUSY, breaking standard hwmon functionality.
Additionally, if a daemon crashes (leaving the device offline) and restarts with a modified schema, UHWMON_CREATE returns -EINVAL without attaching the file descriptor.
This permanently locks out the device name because the daemon cannot issue UHWMON_DESTROY to clean up the old offline device.
[ ... ]
Quoted 3 lines
drivers/hwmon/uhwmon.c new file +3
-0+static ssize_t uhwmon_read (struct file *file,char __user *buf,size_t count, +loff_t *offset) +{
[ ... ]
Quoted 2 lines
drivers/hwmon/uhwmon.c new file +2
-0+if (mutex_lock_interruptible (&data->lock)) +return -ERESTARTSYS ;
[ ... ]
drivers/hwmon/uhwmon.c
Quoted 8 lines
drivers/hwmon/uhwmon.c new file +8
-0+ ret = -EFAULT ; +if (copy_to_user (buf, &data->pending->request, +sizeof (data->pending->request))) + goto out; + data->readable = false; + ret =sizeof (data->pending->request); +out: +mutex_unlock (&data->lock);
[Severity: High]
Can this copy_to_user() while holding data->lock allow userfaultfd to block indefinitely?
If a daemon issues a read() providing a buffer backed by userfaultfd, the kernel will block indefinitely while data->lock is held.
Since hwmon core serializes sysfs accesses, any standard monitoring utility (like sensors) reading the sysfs attribute will invoke uhwmon_request(), which calls mutex_lock(&data->lock) and blocks in TASK_UNINTERRUPTIBLE (D-state).
Standard kernel design strictly forbids holding standard mutexes across userspace memory accesses if those mutexes are shared with system-wide reader processes.
[ ... ]
Quoted 3 lines
drivers/hwmon/uhwmon.c new file +3
-0+static ssize_t uhwmon_write (struct file *file,const char __user *buf, +size_t count,loff_t *offset) +{
[ ... ]
Quoted 1 line
drivers/hwmon/uhwmon.c new file +1
-0+mutex_lock (&data->lock);
[ ... ]
drivers/hwmon/uhwmon.c
Quoted 7 lines
drivers/hwmon/uhwmon.c new file +7
-0+if (size) { +if (count <sizeof (reply) + size) + goto out; + ret = -EFAULT ; +if (copy_from_user (data->text, buf +sizeof (reply), + size)) + goto out;
[Severity: High]
Similar to the issue in uhwmon_read(), could this copy_from_user() while holding data->lock also allow a userfaultfd-based unkillable hang?
drivers/hwmon/uhwmon.c
Quoted 4 lines
drivers/hwmon/uhwmon.c new file +4
-0+ length =strnlen (data->text, size); + ret = -EINVAL ; +if (length == size) + goto out;
[Severity: High]
What happens if an invalid string reply is provided here, does it permanently strand the sysfs reader?
If the daemon sends a non-null-terminated string, length == size evaluates to true and the function branches to goto out without setting pending->done = true.
This permanently strands the sysfs reader in the killable wait from uhwmon_request().
Since hwmon core serializes sysfs accesses, this single hung reader deadlocks the entire hwmon device.
[ ... ]
drivers/hwmon/uhwmon.c
Quoted 11 lines
drivers/hwmon/uhwmon.c new file +11
-0+static void __exit uhwmon_exit(void) +{ +struct uhwmon_device *data, *next; + +misc_deregister (&uhwmon_misc); +list_for_each_entry_safe (data, next, &uhwmon_devices, node) { +uhwmon_unregister (data); +list_del (&data->node); +uhwmon_free (data); + } +}
[Severity: Medium]
Is it safe for uhwmon_exit() to destroy the parent miscdevice before the child hwmon devices?
uhwmon_create() registers child hwmon devices using uhwmon_misc.this_device as their parent. These child devices persist even after the userspace daemon closes the control file descriptor.
During module unload, calling misc_deregister(&uhwmon_misc) before iterating the uhwmon_devices list to unregister the child hwmon devices leaves dangling child kobjects.
The driver core strictly requires children to be unregistered before their parent. Unregistering the parent first triggers sysfs warnings and use-after-free bugs when the children are subsequently unregistered.
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=5
Guenter Roeck
maintainerRe: [PATCH 5/5] docs: hwmon: Document the uhwmon userspace interface
In reply to Jihong MinQuoted 6 lines · Jihong Min
Document the uhwmon UAPI for developers implementing userspace hwmon drivers. Cover device registration, request handling, notifications and device lifetime.
Assisted-by Codex:gpt-6-astraSigned-off-by Jihong Min <[email protected]>
I am not going to review, much less apply, this series. Exposing subsystem internals to userspace is a bad idea and would limit future improvements of the hardware monitoring subsystem. User space file systems are bad enough and cause all kinds of trouble. I don't want to have to deal with the same kind of issues in the hardware monitoring subsystem.
Interested parties should implement kernel hardware monitoring drivers instead.
Guenter
Re: [PATCH 5/5] docs: hwmon: Document the uhwmon userspace interface
Ok. Then I will withdraw these patch series.
But then let me ask you the initial question that brought this patch
series: Do you think it is at least OK to add kernel drivers for network-based sensors? Or do you think those are also to be subjected to be rejected (or remained in DKMS projects)?
Sincerely,
Jihong Min
Quoted 18 lines · Guenter Roeck
Quoted 6 lines · Jihong Min
Document the uhwmon UAPI for developers implementing userspace hwmon drivers. Cover device registration, request handling, notifications and device lifetime.
Assisted-by Codex:gpt-6-astraSigned-off-by Jihong Min <[email protected]>I am not going to review, much less apply, this series. Exposing subsystem internals to userspace is a bad idea and would limit future improvements of the hardware monitoring subsystem. User space file systems are bad enough and cause all kinds of trouble. I don't want to have to deal with the same kind of issues in the hardware monitoring subsystem.
Interested parties should implement kernel hardware monitoring drivers instead.
Guenter
A message that is not in the archive (sent off-list or not yet received): CAAwencqEVCjtnJfmnut2zXXPvuwju5T89FDSpHN3wPfrrJnRdQ@mail.gmail.com
Guenter Roeck
maintainerRe: [PATCH 5/5] docs: hwmon: Document the uhwmon userspace interface
Quoted 4 lines · Jihong Min
Ok. Then I will withdraw these patch series.
But then let me ask you the initial question that brought this patch series: Do you think it is at least OK to add kernel drivers for network-based sensors? Or do you think those are also to be subjected to be rejected (or remained in DKMS projects)?
What is a "network-based sensor" ?
Regarding the references, wireview has a USB interface, and I am quite sure that it should be possible to write a kernel driver for it. There are several hwmon kernel drivers implementing access through USB, so the same should be possible here.
The Tapo API reference points to an "Unofficial Tapo API client", written in AI-guided Rust. Google tells me:
"
There is no official public API documentation released by TP-Link for Tapo smart devices. Because Tapo uses a cloud-centric and encrypted local communication protocol, developers rely entirely on reverse-engineered, community-driven API clients to interact with these devices locally or via the cloud.
"
I have no idea if it is possible to implement a kernel driver for this. There are various hwmon drivers with reverse engineered APIs (such as the Corsair power supply drivers), so relying on reverse engineering is not a problem. I am, however, not going to dig through the above mentioned clients to figure out what the API actually is and how to use it. The guidance provided by Google suggests that it requires per-client credentials (account email and password), which would be problematic.
Either case, it appears that this would be about monitoring remote devices. That is really out of scope for the hardware monitoring subsystem. The hardware monitoring subsystem is monitoring _this_ system. Adding support for monitoring remote devices would be a stretch.
Guenter
Quoted 25 lines
Sincerely,
Jihong MinOn Mon, Oct 19, 2026 at 01:06 Guenter Roeck <[email protected] <mailto:[email protected]>> wrote:
On Sat, Oct 10, 2026 at 12:38:44AM +0900, Jihong Min wrote:
> Document the uhwmon UAPI for developers implementing userspace hwmon > drivers. Cover device registration, request handling, notifications > and device lifetime.
>
> Assisted-by: Codex:gpt-6-astra
> Signed-off-by: Jihong Min <[email protected] <mailto:[email protected]>>I am not going to review, much less apply, this series. Exposing subsystem internals to userspace is a bad idea and would limit future improvements of the hardware monitoring subsystem. User space file systems are bad enough and cause all kinds of trouble. I don't want to have to deal with the same kind of issues in the hardware monitoring subsystem.
Interested parties should implement kernel hardware monitoring drivers instead.
Guenter