2cb4acf214
devm_hwmon_device_unregister() has no in-tree user, and its implementation is wrong since it does not pass the to-be-removed hardware monitoring device as parameter. I do not envision a valid use for it; drivers needing it should not have called devm_hwmon_device_register_with_info() in the first place. Remove it. Reported-by: Matthew Sanders <m@ttsande.rs> Closes: https://lore.kernel.org/linux-hwmon/488b3bdf870ea76c4b943dbe5fd15ac8113019dc.camel@kernel.org/ Signed-off-by: Guenter Roeck <linux@roeck-us.net>
368 lines
12 KiB
ReStructuredText
368 lines
12 KiB
ReStructuredText
The Linux Hardware Monitoring kernel API
|
|
========================================
|
|
|
|
Guenter Roeck
|
|
|
|
Introduction
|
|
------------
|
|
|
|
This document describes the API that can be used by hardware monitoring
|
|
drivers that want to use the hardware monitoring framework.
|
|
|
|
This document does not describe what a hardware monitoring (hwmon) Driver or
|
|
Device is. It also does not describe the API which can be used by user space
|
|
to communicate with a hardware monitoring device. If you want to know this
|
|
then please read the following file: Documentation/hwmon/sysfs-interface.rst.
|
|
|
|
For additional guidelines on how to write and improve hwmon drivers, please
|
|
also read Documentation/hwmon/submitting-patches.rst.
|
|
|
|
The API
|
|
-------
|
|
Each hardware monitoring driver must #include <linux/hwmon.h> and, in some
|
|
cases, <linux/hwmon-sysfs.h>. linux/hwmon.h declares the following
|
|
register/unregister functions::
|
|
|
|
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);
|
|
|
|
struct device *
|
|
devm_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);
|
|
|
|
void hwmon_device_unregister(struct device *dev);
|
|
|
|
char *hwmon_sanitize_name(const char *name);
|
|
|
|
char *devm_hwmon_sanitize_name(struct device *dev, const char *name);
|
|
|
|
hwmon_device_register_with_info registers a hardware monitoring device.
|
|
It creates the standard sysfs attributes in the hardware monitoring core,
|
|
letting the driver focus on reading from and writing to the chip instead
|
|
of having to bother with sysfs attributes. The parent device parameter
|
|
as well as the chip parameter must not be NULL. Its parameters are described
|
|
in more detail below.
|
|
|
|
devm_hwmon_device_register_with_info is similar to
|
|
hwmon_device_register_with_info. However, it is device managed, meaning the
|
|
hwmon device does not have to be removed explicitly by the removal function.
|
|
|
|
All other hardware monitoring device registration functions are deprecated
|
|
and must not be used in new drivers.
|
|
|
|
hwmon_device_unregister deregisters a registered hardware monitoring device.
|
|
The parameter of this function is the pointer to the registered hardware
|
|
monitoring device structure. This function must be called from the driver
|
|
remove function if the hardware monitoring device was registered with
|
|
hwmon_device_register_with_info.
|
|
|
|
All supported hwmon device registration functions only accept valid device
|
|
names. Device names including invalid characters (whitespace, '*', or '-')
|
|
will be rejected. The 'name' parameter is mandatory.
|
|
|
|
If the driver doesn't use a static device name (for example it uses
|
|
dev_name()), and therefore cannot make sure the name only contains valid
|
|
characters, hwmon_sanitize_name can be used. This convenience function
|
|
will duplicate the string and replace any invalid characters with an
|
|
underscore. It will allocate memory for the new string and it is the
|
|
responsibility of the caller to release the memory when the device is
|
|
removed.
|
|
|
|
devm_hwmon_sanitize_name is the resource managed version of
|
|
hwmon_sanitize_name; the memory will be freed automatically on device
|
|
removal.
|
|
|
|
Using devm_hwmon_device_register_with_info()
|
|
--------------------------------------------
|
|
|
|
hwmon_device_register_with_info() registers a hardware monitoring device.
|
|
The parameters to this function are
|
|
|
|
=============================================== ===============================================
|
|
`struct device *dev` Pointer to parent device
|
|
`const char *name` Device name
|
|
`void *drvdata` Driver private data
|
|
`const struct hwmon_chip_info *info` Pointer to chip description.
|
|
`const struct attribute_group **extra_groups` Null-terminated list of additional non-standard
|
|
sysfs attribute groups.
|
|
=============================================== ===============================================
|
|
|
|
This function returns a pointer to the created hardware monitoring device
|
|
on success and a negative error code for failure.
|
|
|
|
The hwmon_chip_info structure looks as follows::
|
|
|
|
struct hwmon_chip_info {
|
|
const struct hwmon_ops *ops;
|
|
const struct hwmon_channel_info * const *info;
|
|
};
|
|
|
|
It contains the following fields:
|
|
|
|
* ops:
|
|
Pointer to device operations.
|
|
* info:
|
|
NULL-terminated list of device channel descriptors.
|
|
|
|
The list of hwmon operations is defined as::
|
|
|
|
struct hwmon_ops {
|
|
umode_t (*is_visible)(const void *, enum hwmon_sensor_types type,
|
|
u32 attr, int);
|
|
int (*read)(struct device *, enum hwmon_sensor_types type,
|
|
u32 attr, int, long *);
|
|
int (*write)(struct device *, enum hwmon_sensor_types type,
|
|
u32 attr, int, long);
|
|
};
|
|
|
|
It defines the following operations.
|
|
|
|
* is_visible:
|
|
Pointer to a function to return the file mode for each supported
|
|
attribute. This function is mandatory.
|
|
|
|
* read:
|
|
Pointer to a function for reading a value from the chip. This function
|
|
is optional, but must be provided if any readable attributes exist.
|
|
|
|
* write:
|
|
Pointer to a function for writing a value to the chip. This function is
|
|
optional, but must be provided if any writeable attributes exist.
|
|
|
|
Each sensor channel is described with struct hwmon_channel_info, which is
|
|
defined as follows::
|
|
|
|
struct hwmon_channel_info {
|
|
enum hwmon_sensor_types type;
|
|
u32 *config;
|
|
};
|
|
|
|
It contains following fields:
|
|
|
|
* type:
|
|
The hardware monitoring sensor type.
|
|
|
|
Supported sensor types are
|
|
|
|
================== ==================================================
|
|
hwmon_chip A virtual sensor type, used to describe attributes
|
|
which are not bound to a specific input or output
|
|
hwmon_temp Temperature sensor
|
|
hwmon_in Voltage sensor
|
|
hwmon_curr Current sensor
|
|
hwmon_power Power sensor
|
|
hwmon_energy Energy sensor
|
|
hwmon_humidity Humidity sensor
|
|
hwmon_fan Fan speed sensor
|
|
hwmon_pwm PWM control
|
|
================== ==================================================
|
|
|
|
* config:
|
|
Pointer to a 0-terminated list of configuration values for each
|
|
sensor of the given type. Each value is a combination of bit values
|
|
describing the attributes supposed by a single sensor.
|
|
|
|
As an example, here is the complete description file for a LM75 compatible
|
|
sensor chip. The chip has a single temperature sensor. The driver wants to
|
|
register with the thermal subsystem (HWMON_C_REGISTER_TZ), and it supports
|
|
the update_interval attribute (HWMON_C_UPDATE_INTERVAL). The chip supports
|
|
reading the temperature (HWMON_T_INPUT), it has a maximum temperature
|
|
register (HWMON_T_MAX) as well as a maximum temperature hysteresis register
|
|
(HWMON_T_MAX_HYST)::
|
|
|
|
static const u32 lm75_chip_config[] = {
|
|
HWMON_C_REGISTER_TZ | HWMON_C_UPDATE_INTERVAL,
|
|
0
|
|
};
|
|
|
|
static const struct hwmon_channel_info lm75_chip = {
|
|
.type = hwmon_chip,
|
|
.config = lm75_chip_config,
|
|
};
|
|
|
|
static const u32 lm75_temp_config[] = {
|
|
HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MAX_HYST,
|
|
0
|
|
};
|
|
|
|
static const struct hwmon_channel_info lm75_temp = {
|
|
.type = hwmon_temp,
|
|
.config = lm75_temp_config,
|
|
};
|
|
|
|
static const struct hwmon_channel_info * const lm75_info[] = {
|
|
&lm75_chip,
|
|
&lm75_temp,
|
|
NULL
|
|
};
|
|
|
|
The HWMON_CHANNEL_INFO() macro can and should be used when possible.
|
|
With this macro, the above example can be simplified to
|
|
|
|
static const struct hwmon_channel_info * const lm75_info[] = {
|
|
HWMON_CHANNEL_INFO(chip,
|
|
HWMON_C_REGISTER_TZ | HWMON_C_UPDATE_INTERVAL),
|
|
HWMON_CHANNEL_INFO(temp,
|
|
HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MAX_HYST),
|
|
NULL
|
|
};
|
|
|
|
The remaining declarations are as follows.
|
|
|
|
static const struct hwmon_ops lm75_hwmon_ops = {
|
|
.is_visible = lm75_is_visible,
|
|
.read = lm75_read,
|
|
.write = lm75_write,
|
|
};
|
|
|
|
static const struct hwmon_chip_info lm75_chip_info = {
|
|
.ops = &lm75_hwmon_ops,
|
|
.info = lm75_info,
|
|
};
|
|
|
|
A complete list of bit values indicating individual attribute support
|
|
is defined in include/linux/hwmon.h. Definition prefixes are as follows.
|
|
|
|
=============== =================================================
|
|
HWMON_C_xxxx Chip attributes, for use with hwmon_chip.
|
|
HWMON_T_xxxx Temperature attributes, for use with hwmon_temp.
|
|
HWMON_I_xxxx Voltage attributes, for use with hwmon_in.
|
|
HWMON_C_xxxx Current attributes, for use with hwmon_curr.
|
|
Notice the prefix overlap with chip attributes.
|
|
HWMON_P_xxxx Power attributes, for use with hwmon_power.
|
|
HWMON_E_xxxx Energy attributes, for use with hwmon_energy.
|
|
HWMON_H_xxxx Humidity attributes, for use with hwmon_humidity.
|
|
HWMON_F_xxxx Fan speed attributes, for use with hwmon_fan.
|
|
HWMON_PWM_xxxx PWM control attributes, for use with hwmon_pwm.
|
|
=============== =================================================
|
|
|
|
Driver callback functions
|
|
-------------------------
|
|
|
|
Each driver provides is_visible, read, and write functions. Parameters
|
|
and return values for those functions are as follows::
|
|
|
|
umode_t is_visible_func(const void *data, enum hwmon_sensor_types type,
|
|
u32 attr, int channel)
|
|
|
|
Parameters:
|
|
data:
|
|
Pointer to device private data structure.
|
|
type:
|
|
The sensor type.
|
|
attr:
|
|
Attribute identifier associated with a specific attribute.
|
|
For example, the attribute value for HWMON_T_INPUT would be
|
|
hwmon_temp_input. For complete mappings of bit fields to
|
|
attribute values please see include/linux/hwmon.h.
|
|
channel:
|
|
The sensor channel number.
|
|
|
|
Return value:
|
|
The file mode for this attribute. Typically, this will be 0 (the
|
|
attribute will not be created), 0444, or 0644.
|
|
|
|
::
|
|
|
|
int read_func(struct device *dev, enum hwmon_sensor_types type,
|
|
u32 attr, int channel, long *val)
|
|
|
|
Parameters:
|
|
dev:
|
|
Pointer to the hardware monitoring device.
|
|
type:
|
|
The sensor type.
|
|
attr:
|
|
Attribute identifier associated with a specific attribute.
|
|
For example, the attribute value for HWMON_T_INPUT would be
|
|
hwmon_temp_input. For complete mappings please see
|
|
include/linux/hwmon.h.
|
|
channel:
|
|
The sensor channel number.
|
|
val:
|
|
Pointer to attribute value.
|
|
|
|
Return value:
|
|
0 on success, a negative error number otherwise.
|
|
|
|
::
|
|
|
|
int write_func(struct device *dev, enum hwmon_sensor_types type,
|
|
u32 attr, int channel, long val)
|
|
|
|
Parameters:
|
|
dev:
|
|
Pointer to the hardware monitoring device.
|
|
type:
|
|
The sensor type.
|
|
attr:
|
|
Attribute identifier associated with a specific attribute.
|
|
For example, the attribute value for HWMON_T_INPUT would be
|
|
hwmon_temp_input. For complete mappings please see
|
|
include/linux/hwmon.h.
|
|
channel:
|
|
The sensor channel number.
|
|
val:
|
|
The value to write to the chip.
|
|
|
|
Return value:
|
|
0 on success, a negative error number otherwise.
|
|
|
|
|
|
Driver-provided sysfs attributes
|
|
--------------------------------
|
|
|
|
In most situations it should not be necessary for a driver to provide sysfs
|
|
attributes since the hardware monitoring core creates those internally.
|
|
Only additional non-standard sysfs attributes need to be provided.
|
|
|
|
The header file linux/hwmon-sysfs.h provides a number of useful macros to
|
|
declare and use hardware monitoring sysfs attributes.
|
|
|
|
In many cases, you can use the existing define DEVICE_ATTR or its variants
|
|
DEVICE_ATTR_{RW,RO,WO} to declare such attributes. This is feasible if an
|
|
attribute has no additional context. However, in many cases there will be
|
|
additional information such as a sensor index which will need to be passed
|
|
to the sysfs attribute handling function.
|
|
|
|
SENSOR_DEVICE_ATTR and SENSOR_DEVICE_ATTR_2 can be used to define attributes
|
|
which need such additional context information. SENSOR_DEVICE_ATTR requires
|
|
one additional argument, SENSOR_DEVICE_ATTR_2 requires two.
|
|
|
|
Simplified variants of SENSOR_DEVICE_ATTR and SENSOR_DEVICE_ATTR_2 are available
|
|
and should be used if standard attribute permissions and function names are
|
|
feasible. Standard permissions are 0644 for SENSOR_DEVICE_ATTR[_2]_RW,
|
|
0444 for SENSOR_DEVICE_ATTR[_2]_RO, and 0200 for SENSOR_DEVICE_ATTR[_2]_WO.
|
|
Standard functions, similar to DEVICE_ATTR_{RW,RO,WO}, have _show and _store
|
|
appended to the provided function name.
|
|
|
|
SENSOR_DEVICE_ATTR and its variants define a struct sensor_device_attribute
|
|
variable. This structure has the following fields::
|
|
|
|
struct sensor_device_attribute {
|
|
struct device_attribute dev_attr;
|
|
int index;
|
|
};
|
|
|
|
You can use to_sensor_dev_attr to get the pointer to this structure from the
|
|
attribute read or write function. Its parameter is the device to which the
|
|
attribute is attached.
|
|
|
|
SENSOR_DEVICE_ATTR_2 and its variants define a struct sensor_device_attribute_2
|
|
variable, which is defined as follows::
|
|
|
|
struct sensor_device_attribute_2 {
|
|
struct device_attribute dev_attr;
|
|
u8 index;
|
|
u8 nr;
|
|
};
|
|
|
|
Use to_sensor_dev_attr_2 to get the pointer to this structure. Its parameter
|
|
is the device to which the attribute is attached.
|