From: Shih-Yuan Lee <fourdollars@debian.org>
To: Henrik Rydberg <rydberg@bitmath.org>, Guenter Roeck <linux@roeck-us.net>
Cc: Armin Wolf <W_Armin@gmx.de>,
linux-hwmon@vger.kernel.org, linux-kernel@vger.kernel.org,
Shih-Yuan Lee <fourdollars@debian.org>
Subject: [PATCH v5 3/3] hwmon: (applesmc) Convert to hwmon_device_register_with_info
Date: Sat, 11 Jul 2026 15:57:54 +0800 [thread overview]
Message-ID: <20260711075754.11358-4-fourdollars@debian.org> (raw)
In-Reply-To: <20260711075754.11358-1-fourdollars@debian.org>
The legacy hwmon_device_register() function is deprecated and triggers
warnings in dmesg. Convert the driver to the modern
hwmon_device_register_with_info() API.
This conversion does the following:
- Dynamically allocates standard HWMON temp, fan, and pwm channels.
- Configures HWMON ops callbacks (.is_visible, .read, .read_string, .write).
- Standardizes attribute naming to match the HWMON ABI:
- fanX_output -> fanX_target (HWMON_F_TARGET)
- fanX_manual -> pwmX_enable (HWMON_PWM_ENABLE)
- Dynamically registers non-standard fanX_safe attributes under the HWMON
class directory via extra_groups.
- Cleans up legacy sysfs nodes, groups, and unused show/store static functions
to avoid unused symbol compiler warnings.
- Avoids recursive mutex deadlocks when writing to pwmX_enable by locklessly
resolving the entry and invoking the underlying raw SMC read/write calls.
- Avoids UAF race condition on module exit by using unmanaged registration and
explicitly calling hwmon_device_unregister() as the first step of applesmc_exit(),
guaranteeing that HWMON nodes are destroyed before static structures are freed.
Signed-off-by: Shih-Yuan Lee <fourdollars@debian.org>
---
drivers/hwmon/applesmc.c | 470 ++++++++++++++++++++++++++-------------
1 file changed, 321 insertions(+), 149 deletions(-)
diff --git a/drivers/hwmon/applesmc.c b/drivers/hwmon/applesmc.c
index 317135fc4b73..bec9e9e98896 100644
--- a/drivers/hwmon/applesmc.c
+++ b/drivers/hwmon/applesmc.c
@@ -145,8 +145,8 @@ static s16 rest_x;
static s16 rest_y;
static u8 backlight_state[2];
-static struct device *hwmon_dev;
static struct input_dev *applesmc_idev;
+static struct device *hwmon_dev;
/*
* Last index written to key_at_index sysfs file, and value to use for all other
@@ -822,33 +822,6 @@ static ssize_t applesmc_light_show(struct device *dev,
return sysfs_emit(sysfsbuf, "(%d,%d)\n", left, right);
}
-/* Displays sensor key as label */
-static ssize_t applesmc_show_sensor_label(struct device *dev,
- struct device_attribute *devattr, char *sysfsbuf)
-{
- const char *key = smcreg.index[to_index(devattr)];
-
- return sysfs_emit(sysfsbuf, "%s\n", key);
-}
-
-/* Displays degree Celsius * 1000 */
-static ssize_t applesmc_show_temperature(struct device *dev,
- struct device_attribute *devattr, char *sysfsbuf)
-{
- const char *key = smcreg.index[to_index(devattr)];
- int ret;
- s16 value;
- int temp;
-
- ret = applesmc_read_s16(key, &value);
- if (ret)
- return ret;
-
- temp = 250 * (value >> 6);
-
- return sysfs_emit(sysfsbuf, "%d\n", temp);
-}
-
static ssize_t applesmc_show_fan_speed(struct device *dev,
struct device_attribute *attr, char *sysfsbuf)
{
@@ -868,99 +841,6 @@ static ssize_t applesmc_show_fan_speed(struct device *dev,
return sysfs_emit(sysfsbuf, "%u\n", speed);
}
-static ssize_t applesmc_store_fan_speed(struct device *dev,
- struct device_attribute *attr,
- const char *sysfsbuf, size_t count)
-{
- int ret;
- unsigned long speed;
- char newkey[5];
- u8 buffer[2];
-
- if (kstrtoul(sysfsbuf, 10, &speed) < 0 || speed >= 0x4000)
- return -EINVAL; /* Bigger than a 14-bit value */
-
- scnprintf(newkey, sizeof(newkey), fan_speed_fmt[to_option(attr)],
- to_index(attr));
-
- buffer[0] = (speed >> 6) & 0xff;
- buffer[1] = (speed << 2) & 0xff;
- ret = applesmc_write_key(newkey, buffer, 2);
-
- if (ret)
- return ret;
- else
- return count;
-}
-
-static ssize_t applesmc_show_fan_manual(struct device *dev,
- struct device_attribute *attr, char *sysfsbuf)
-{
- int ret;
- u16 manual = 0;
- u8 buffer[2];
-
- ret = applesmc_read_key(FANS_MANUAL, buffer, 2);
- if (ret)
- return ret;
-
- manual = ((buffer[0] << 8 | buffer[1]) >> to_index(attr)) & 0x01;
- return sysfs_emit(sysfsbuf, "%d\n", manual);
-}
-
-static ssize_t applesmc_store_fan_manual(struct device *dev,
- struct device_attribute *attr,
- const char *sysfsbuf, size_t count)
-{
- int ret;
- u8 buffer[2];
- unsigned long input;
- u16 val;
-
- if (kstrtoul(sysfsbuf, 10, &input) < 0)
- return -EINVAL;
-
- ret = applesmc_read_key(FANS_MANUAL, buffer, 2);
- if (ret)
- goto out;
-
- val = (buffer[0] << 8 | buffer[1]);
-
- if (input)
- val = val | (0x01 << to_index(attr));
- else
- val = val & ~(0x01 << to_index(attr));
-
- buffer[0] = (val >> 8) & 0xFF;
- buffer[1] = val & 0xFF;
-
- ret = applesmc_write_key(FANS_MANUAL, buffer, 2);
-
-out:
- if (ret)
- return ret;
- else
- return count;
-}
-
-static ssize_t applesmc_show_fan_position(struct device *dev,
- struct device_attribute *attr, char *sysfsbuf)
-{
- int ret;
- char newkey[5];
- u8 buffer[17];
-
- scnprintf(newkey, sizeof(newkey), FAN_ID_FMT, to_index(attr));
-
- ret = applesmc_read_key(newkey, buffer, 16);
- buffer[16] = 0;
-
- if (ret)
- return ret;
-
- return sysfs_emit(sysfsbuf, "%s\n", buffer + 4);
-}
-
static ssize_t applesmc_calibrate_show(struct device *dev,
struct device_attribute *attr, char *sysfsbuf)
{
@@ -1108,22 +988,7 @@ static struct applesmc_node_group light_sensor_group[] = {
{ }
};
-static struct applesmc_node_group fan_group[] = {
- { "fan%d_label", applesmc_show_fan_position },
- { "fan%d_input", applesmc_show_fan_speed, NULL, 0 },
- { "fan%d_min", applesmc_show_fan_speed, applesmc_store_fan_speed, 1 },
- { "fan%d_max", applesmc_show_fan_speed, NULL, 2 },
- { "fan%d_safe", applesmc_show_fan_speed, NULL, 3 },
- { "fan%d_output", applesmc_show_fan_speed, applesmc_store_fan_speed, 4 },
- { "fan%d_manual", applesmc_show_fan_manual, applesmc_store_fan_manual },
- { }
-};
-static struct applesmc_node_group temp_group[] = {
- { "temp%d_label", applesmc_show_sensor_label },
- { "temp%d_input", applesmc_show_temperature },
- { }
-};
/* Module stuff */
@@ -1321,8 +1186,238 @@ static const struct dmi_system_id applesmc_whitelist[] __initconst = {
};
MODULE_DEVICE_TABLE(dmi, applesmc_whitelist);
+static struct applesmc_dev_attr *fan_safe_attrs;
+static struct attribute **fan_safe_attr_list;
+static struct attribute_group fan_safe_group;
+static const struct attribute_group *applesmc_extra_groups[2];
+
+static u32 *applesmc_temp_config;
+static u32 *applesmc_fan_config;
+static u32 *applesmc_pwm_config;
+static struct hwmon_channel_info *applesmc_info_temp;
+static struct hwmon_channel_info *applesmc_info_fan;
+static struct hwmon_channel_info *applesmc_info_pwm;
+static const struct hwmon_channel_info **applesmc_info_arr;
+static struct hwmon_chip_info *applesmc_chip;
+
+static void applesmc_free_hwmon(void)
+{
+ kfree(applesmc_temp_config);
+ kfree(applesmc_fan_config);
+ kfree(applesmc_pwm_config);
+ kfree(applesmc_info_temp);
+ kfree(applesmc_info_fan);
+ kfree(applesmc_info_pwm);
+ kfree(applesmc_info_arr);
+ kfree(applesmc_chip);
+ kfree(fan_safe_attrs);
+ kfree(fan_safe_attr_list);
+}
+
+static umode_t applesmc_hwmon_is_visible(const void *drvdata, enum hwmon_sensor_types type,
+ u32 attr, int channel)
+{
+ switch (type) {
+ case hwmon_temp:
+ if (attr == hwmon_temp_input || attr == hwmon_temp_label)
+ return 0444;
+ break;
+ case hwmon_fan:
+ switch (attr) {
+ case hwmon_fan_input:
+ case hwmon_fan_label:
+ case hwmon_fan_max:
+ return 0444;
+ case hwmon_fan_min:
+ case hwmon_fan_target:
+ return 0644;
+ default:
+ break;
+ }
+ break;
+ case hwmon_pwm:
+ if (attr == hwmon_pwm_enable)
+ return 0644;
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+
+static int applesmc_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
+ u32 attr, int channel, long *val)
+{
+ int ret;
+
+ switch (type) {
+ case hwmon_temp:
+ if (attr == hwmon_temp_input) {
+ const char *key = smcreg.index[channel];
+ s16 value;
+
+ ret = applesmc_read_s16(key, &value);
+ if (ret)
+ return ret;
+ *val = 250 * (value >> 6);
+ return 0;
+ }
+ break;
+ case hwmon_fan:
+ switch (attr) {
+ case hwmon_fan_input: {
+ char key[5];
+ u8 buffer[2];
+
+ scnprintf(key, sizeof(key), "F%dAc", channel);
+ ret = applesmc_read_key(key, buffer, 2);
+ if (ret)
+ return ret;
+ *val = ((buffer[0] << 8 | buffer[1]) >> 2);
+ return 0;
+ }
+ case hwmon_fan_min: {
+ char key[5];
+ u8 buffer[2];
+
+ scnprintf(key, sizeof(key), "F%dMn", channel);
+ ret = applesmc_read_key(key, buffer, 2);
+ if (ret)
+ return ret;
+ *val = ((buffer[0] << 8 | buffer[1]) >> 2);
+ return 0;
+ }
+ case hwmon_fan_max: {
+ char key[5];
+ u8 buffer[2];
+
+ scnprintf(key, sizeof(key), "F%dMx", channel);
+ ret = applesmc_read_key(key, buffer, 2);
+ if (ret)
+ return ret;
+ *val = ((buffer[0] << 8 | buffer[1]) >> 2);
+ return 0;
+ }
+ case hwmon_fan_target: {
+ char key[5];
+ u8 buffer[2];
+
+ scnprintf(key, sizeof(key), "F%dTg", channel);
+ ret = applesmc_read_key(key, buffer, 2);
+ if (ret)
+ return ret;
+ *val = ((buffer[0] << 8 | buffer[1]) >> 2);
+ return 0;
+ }
+ default:
+ break;
+ }
+ break;
+ case hwmon_pwm:
+ if (attr == hwmon_pwm_enable) {
+ u8 buffer[2];
+
+ ret = applesmc_read_key(FANS_MANUAL, buffer, 2);
+ if (ret)
+ return ret;
+ *val = ((buffer[0] << 8 | buffer[1]) >> channel) & 0x01;
+ return 0;
+ }
+ break;
+ default:
+ break;
+ }
+ return -EOPNOTSUPP;
+}
+
+static int applesmc_hwmon_write(struct device *dev, enum hwmon_sensor_types type,
+ u32 attr, int channel, long val)
+{
+ int ret;
+
+ switch (type) {
+ case hwmon_fan:
+ if (attr == hwmon_fan_min || attr == hwmon_fan_target) {
+ char key[5];
+ u8 buffer[2];
+ const char *fmt = (attr == hwmon_fan_min) ? "F%dMn" : "F%dTg";
+
+ if (val < 0 || val >= 0x4000)
+ return -EINVAL;
+ scnprintf(key, sizeof(key), fmt, channel);
+ buffer[0] = (val >> 6) & 0xff;
+ buffer[1] = (val << 2) & 0xff;
+ return applesmc_write_key(key, buffer, 2);
+ }
+ break;
+ case hwmon_pwm:
+ if (attr == hwmon_pwm_enable) {
+ u8 buffer[2];
+ u16 manual_val;
+ const struct applesmc_entry *entry;
+
+ if (val != 0 && val != 1)
+ return -EINVAL;
+
+ entry = applesmc_get_entry_by_key(FANS_MANUAL);
+ if (IS_ERR(entry))
+ return PTR_ERR(entry);
+
+ mutex_lock(&smcreg.mutex);
+ ret = read_smc(APPLESMC_READ_CMD, entry->key, buffer, 2);
+ if (ret)
+ goto out_unlock;
+ manual_val = (buffer[0] << 8 | buffer[1]);
+ if (val)
+ manual_val |= (0x01 << channel);
+ else
+ manual_val &= ~(0x01 << channel);
+ buffer[0] = (manual_val >> 8) & 0xff;
+ buffer[1] = manual_val & 0xff;
+ ret = write_smc(APPLESMC_WRITE_CMD, entry->key, buffer, 2);
+out_unlock:
+ mutex_unlock(&smcreg.mutex);
+ return ret;
+ }
+ break;
+ default:
+ break;
+ }
+ return -EOPNOTSUPP;
+}
+
+static int applesmc_hwmon_read_string(struct device *dev, enum hwmon_sensor_types type,
+ u32 attr, int channel, const char **str)
+{
+ switch (type) {
+ case hwmon_temp:
+ if (attr == hwmon_temp_label) {
+ *str = smcreg.index[channel];
+ return 0;
+ }
+ break;
+ case hwmon_fan:
+ if (attr == hwmon_fan_label) {
+ *str = smcreg.fan_positions[channel] + 4;
+ return 0;
+ }
+ break;
+ default:
+ break;
+ }
+ return -EOPNOTSUPP;
+}
+
+static const struct hwmon_ops applesmc_hwmon_ops = {
+ .is_visible = applesmc_hwmon_is_visible,
+ .read = applesmc_hwmon_read,
+ .write = applesmc_hwmon_write,
+ .read_string = applesmc_hwmon_read_string,
+};
+
static int __init applesmc_init(void)
{
+ int i;
int ret;
if (!dmi_check_system(applesmc_whitelist)) {
@@ -1357,17 +1452,97 @@ static int __init applesmc_init(void)
if (ret)
goto out_smcreg;
- ret = applesmc_create_nodes(fan_group, smcreg.fan_count);
- if (ret)
+ /* allocate hwmon channel configs */
+ applesmc_temp_config = kcalloc(smcreg.index_count + 1,
+ sizeof(*applesmc_temp_config), GFP_KERNEL);
+ applesmc_fan_config = kcalloc(smcreg.fan_count + 1,
+ sizeof(*applesmc_fan_config), GFP_KERNEL);
+ applesmc_pwm_config = kcalloc(smcreg.fan_count + 1,
+ sizeof(*applesmc_pwm_config), GFP_KERNEL);
+ if (!applesmc_temp_config || !applesmc_fan_config || !applesmc_pwm_config) {
+ ret = -ENOMEM;
goto out_info;
+ }
- ret = applesmc_create_nodes(temp_group, smcreg.index_count);
- if (ret)
- goto out_fans;
+ for (i = 0; i < smcreg.index_count; i++)
+ applesmc_temp_config[i] = HWMON_T_INPUT | HWMON_T_LABEL;
+ applesmc_temp_config[smcreg.index_count] = 0;
+
+ for (i = 0; i < smcreg.fan_count; i++) {
+ applesmc_fan_config[i] = HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_MIN |
+ HWMON_F_MAX | HWMON_F_TARGET;
+ applesmc_pwm_config[i] = HWMON_PWM_ENABLE;
+ }
+ applesmc_fan_config[smcreg.fan_count] = 0;
+ applesmc_pwm_config[smcreg.fan_count] = 0;
+
+ applesmc_info_temp = kzalloc_obj(*applesmc_info_temp, GFP_KERNEL);
+ applesmc_info_fan = kzalloc_obj(*applesmc_info_fan, GFP_KERNEL);
+ applesmc_info_pwm = kzalloc_obj(*applesmc_info_pwm, GFP_KERNEL);
+ if (!applesmc_info_temp || !applesmc_info_fan || !applesmc_info_pwm) {
+ ret = -ENOMEM;
+ goto out_info;
+ }
+
+ applesmc_info_temp->type = hwmon_temp;
+ applesmc_info_temp->config = applesmc_temp_config;
+
+ applesmc_info_fan->type = hwmon_fan;
+ applesmc_info_fan->config = applesmc_fan_config;
+
+ applesmc_info_pwm->type = hwmon_pwm;
+ applesmc_info_pwm->config = applesmc_pwm_config;
+
+ applesmc_info_arr = kcalloc(4, sizeof(*applesmc_info_arr), GFP_KERNEL);
+ if (!applesmc_info_arr) {
+ ret = -ENOMEM;
+ goto out_info;
+ }
+
+ applesmc_info_arr[0] = applesmc_info_temp;
+ applesmc_info_arr[1] = applesmc_info_fan;
+ applesmc_info_arr[2] = applesmc_info_pwm;
+ applesmc_info_arr[3] = NULL;
+
+ applesmc_chip = kzalloc_obj(*applesmc_chip, GFP_KERNEL);
+ if (!applesmc_chip) {
+ ret = -ENOMEM;
+ goto out_info;
+ }
+
+ applesmc_chip->ops = &applesmc_hwmon_ops;
+ applesmc_chip->info = applesmc_info_arr;
+
+ /* Create non-standard fanX_safe attributes group */
+ fan_safe_attrs = kcalloc(smcreg.fan_count,
+ sizeof(*fan_safe_attrs), GFP_KERNEL);
+ fan_safe_attr_list = kcalloc(smcreg.fan_count + 1,
+ sizeof(*fan_safe_attr_list), GFP_KERNEL);
+ if (!fan_safe_attrs || !fan_safe_attr_list) {
+ ret = -ENOMEM;
+ goto out_info;
+ }
+
+ for (i = 0; i < smcreg.fan_count; i++) {
+ struct applesmc_dev_attr *node = &fan_safe_attrs[i];
+
+ scnprintf(node->name, sizeof(node->name), "fan%d_safe", i + 1);
+ node->sda.index = (3 << 16) | (i & 0xffff); /* Option 3 (safe speed) */
+ node->sda.dev_attr.show = applesmc_show_fan_speed;
+ node->sda.dev_attr.store = NULL;
+ sysfs_attr_init(&node->sda.dev_attr.attr);
+ node->sda.dev_attr.attr.name = node->name;
+ node->sda.dev_attr.attr.mode = 0444;
+ fan_safe_attr_list[i] = &node->sda.dev_attr.attr;
+ }
+ fan_safe_attr_list[smcreg.fan_count] = NULL;
+ fan_safe_group.attrs = fan_safe_attr_list;
+ applesmc_extra_groups[0] = &fan_safe_group;
+ applesmc_extra_groups[1] = NULL;
ret = applesmc_create_accelerometer();
if (ret)
- goto out_temperature;
+ goto out_info;
ret = applesmc_create_light_sensor();
if (ret)
@@ -1377,7 +1552,8 @@ static int __init applesmc_init(void)
if (ret)
goto out_light_sysfs;
- hwmon_dev = hwmon_device_register(&pdev->dev);
+ hwmon_dev = hwmon_device_register_with_info(&pdev->dev, "applesmc", NULL,
+ applesmc_chip, applesmc_extra_groups);
if (IS_ERR(hwmon_dev)) {
ret = PTR_ERR(hwmon_dev);
goto out_light_ledclass;
@@ -1391,11 +1567,8 @@ static int __init applesmc_init(void)
applesmc_release_light_sensor();
out_accelerometer:
applesmc_release_accelerometer();
-out_temperature:
- applesmc_destroy_nodes(temp_group);
-out_fans:
- applesmc_destroy_nodes(fan_group);
out_info:
+ applesmc_free_hwmon();
applesmc_destroy_nodes(info_group);
out_smcreg:
applesmc_destroy_smcreg();
@@ -1416,13 +1589,12 @@ static void __exit applesmc_exit(void)
applesmc_release_key_backlight();
applesmc_release_light_sensor();
applesmc_release_accelerometer();
- applesmc_destroy_nodes(temp_group);
- applesmc_destroy_nodes(fan_group);
applesmc_destroy_nodes(info_group);
applesmc_destroy_smcreg();
platform_device_unregister(pdev);
platform_driver_unregister(&applesmc_driver);
release_region(APPLESMC_DATA_PORT, APPLESMC_NR_PORTS);
+ applesmc_free_hwmon();
}
module_init(applesmc_init);
--
2.39.5
next prev parent reply other threads:[~2026-07-11 7:58 UTC|newest]
Thread overview: 30+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-10 12:32 [PATCH 0/1] hwmon: (applesmc) Convert to hwmon_device_register_with_info Shih-Yuan Lee
2026-07-10 12:32 ` [PATCH 1/1] " Shih-Yuan Lee
2026-07-10 12:47 ` sashiko-bot
2026-07-10 14:01 ` Guenter Roeck
2026-07-10 21:10 ` Armin Wolf
2026-07-10 22:28 ` Guenter Roeck
2026-07-11 2:51 ` Shih-Yuan Lee (FourDollars)
2026-07-11 3:36 ` [PATCH v2 0/1] " Shih-Yuan Lee
2026-07-11 3:37 ` [PATCH v2 1/1] " Shih-Yuan Lee
2026-07-11 3:47 ` sashiko-bot
2026-07-11 5:39 ` [PATCH v3 0/1] " Shih-Yuan Lee
2026-07-11 5:39 ` [PATCH v3 1/1] " Shih-Yuan Lee
2026-07-11 5:52 ` sashiko-bot
2026-07-11 6:06 ` [PATCH v4 0/1] " Shih-Yuan Lee
2026-07-11 6:06 ` [PATCH v4 1/1] " Shih-Yuan Lee
2026-07-11 6:17 ` sashiko-bot
2026-07-11 7:57 ` [PATCH v5 0/3] " Shih-Yuan Lee
2026-07-11 7:57 ` [PATCH v5 1/3] hwmon: (applesmc) Cache fan positions during register initialization Shih-Yuan Lee
2026-07-11 8:06 ` sashiko-bot
2026-07-11 7:57 ` [PATCH v5 2/3] hwmon: (applesmc) Fix lockless cache validation data race Shih-Yuan Lee
2026-07-11 8:10 ` sashiko-bot
2026-07-11 7:57 ` Shih-Yuan Lee [this message]
2026-07-11 8:12 ` [PATCH v5 3/3] hwmon: (applesmc) Convert to hwmon_device_register_with_info sashiko-bot
2026-07-11 9:33 ` [PATCH v6 0/3] " Shih-Yuan Lee
2026-07-11 9:33 ` [PATCH v6 1/3] hwmon: (applesmc) Cache fan positions during register initialization Shih-Yuan Lee
2026-07-11 9:42 ` sashiko-bot
2026-07-11 9:33 ` [PATCH v6 2/3] hwmon: (applesmc) Fix lockless cache validation data race Shih-Yuan Lee
2026-07-11 9:43 ` sashiko-bot
2026-07-11 9:33 ` [PATCH v6 3/3] hwmon: (applesmc) Convert to hwmon_device_register_with_info Shih-Yuan Lee
2026-07-11 9:42 ` sashiko-bot
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260711075754.11358-4-fourdollars@debian.org \
--to=fourdollars@debian.org \
--cc=W_Armin@gmx.de \
--cc=linux-hwmon@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux@roeck-us.net \
--cc=rydberg@bitmath.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.