hwmon: (corsair-cpro) Add firmware and bootloader information

Add support for reporting firmware and bootloader version using debugfs.
Update documentation accordingly.

Signed-off-by: Marius Zachmann <mail@mariuszachmann.de>
Link: https://lore.kernel.org/r/20240513194734.43040-2-mail@mariuszachmann.de
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
This commit is contained in:
Marius Zachmann 2024-05-13 21:47:34 +02:00 committed by Guenter Roeck
parent 1613e604df
commit 5997eb60f8
2 changed files with 96 additions and 0 deletions

View File

@ -39,3 +39,11 @@ fan[1-6]_target Sets fan speed target rpm.
pwm[1-6] Sets the fan speed. Values from 0-255. Can only be read if pwm
was set directly.
======================= =====================================================================
Debugfs entries
---------------
======================= ===================
firmware_version Firmware version
bootloader_version Bootloader version
======================= ===================

View File

@ -10,11 +10,13 @@
#include <linux/bitops.h>
#include <linux/completion.h>
#include <linux/debugfs.h>
#include <linux/hid.h>
#include <linux/hwmon.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/seq_file.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/types.h>
@ -28,6 +30,8 @@
#define LABEL_LENGTH 11
#define REQ_TIMEOUT 300
#define CTL_GET_FW_VER 0x02 /* returns the firmware version in bytes 1-3 */
#define CTL_GET_BL_VER 0x06 /* returns the bootloader version in bytes 1-2 */
#define CTL_GET_TMP_CNCT 0x10 /*
* returns in bytes 1-4 for each temp sensor:
* 0 not connected
@ -78,6 +82,7 @@
struct ccp_device {
struct hid_device *hdev;
struct device *hwmon_dev;
struct dentry *debugfs;
/* For reinitializing the completion below */
spinlock_t wait_input_report_lock;
struct completion wait_input_report;
@ -88,6 +93,8 @@ struct ccp_device {
DECLARE_BITMAP(temp_cnct, NUM_TEMP_SENSORS);
DECLARE_BITMAP(fan_cnct, NUM_FANS);
char fan_label[6][LABEL_LENGTH];
u8 firmware_ver[3];
u8 bootloader_ver[2];
};
/* converts response error in buffer to errno */
@ -496,6 +503,83 @@ static int get_temp_cnct(struct ccp_device *ccp)
return 0;
}
/* read firmware version */
static int get_fw_version(struct ccp_device *ccp)
{
int ret;
ret = send_usb_cmd(ccp, CTL_GET_FW_VER, 0, 0, 0);
if (ret) {
hid_notice(ccp->hdev, "Failed to read firmware version.\n");
return ret;
}
ccp->firmware_ver[0] = ccp->buffer[1];
ccp->firmware_ver[1] = ccp->buffer[2];
ccp->firmware_ver[2] = ccp->buffer[3];
return 0;
}
/* read bootloader version */
static int get_bl_version(struct ccp_device *ccp)
{
int ret;
ret = send_usb_cmd(ccp, CTL_GET_BL_VER, 0, 0, 0);
if (ret) {
hid_notice(ccp->hdev, "Failed to read bootloader version.\n");
return ret;
}
ccp->bootloader_ver[0] = ccp->buffer[1];
ccp->bootloader_ver[1] = ccp->buffer[2];
return 0;
}
static int firmware_show(struct seq_file *seqf, void *unused)
{
struct ccp_device *ccp = seqf->private;
seq_printf(seqf, "%d.%d.%d\n",
ccp->firmware_ver[0],
ccp->firmware_ver[1],
ccp->firmware_ver[2]);
return 0;
}
DEFINE_SHOW_ATTRIBUTE(firmware);
static int bootloader_show(struct seq_file *seqf, void *unused)
{
struct ccp_device *ccp = seqf->private;
seq_printf(seqf, "%d.%d\n",
ccp->bootloader_ver[0],
ccp->bootloader_ver[1]);
return 0;
}
DEFINE_SHOW_ATTRIBUTE(bootloader);
static void ccp_debugfs_init(struct ccp_device *ccp)
{
char name[32];
int ret;
scnprintf(name, sizeof(name), "corsaircpro-%s", dev_name(&ccp->hdev->dev));
ccp->debugfs = debugfs_create_dir(name, NULL);
ret = get_fw_version(ccp);
if (!ret)
debugfs_create_file("firmware_version", 0444,
ccp->debugfs, ccp, &firmware_fops);
ret = get_bl_version(ccp);
if (!ret)
debugfs_create_file("bootloader_version", 0444,
ccp->debugfs, ccp, &bootloader_fops);
}
static int ccp_probe(struct hid_device *hdev, const struct hid_device_id *id)
{
struct ccp_device *ccp;
@ -542,6 +626,9 @@ static int ccp_probe(struct hid_device *hdev, const struct hid_device_id *id)
ret = get_fan_cnct(ccp);
if (ret)
goto out_hw_close;
ccp_debugfs_init(ccp);
ccp->hwmon_dev = hwmon_device_register_with_info(&hdev->dev, "corsaircpro",
ccp, &ccp_chip_info, NULL);
if (IS_ERR(ccp->hwmon_dev)) {
@ -562,6 +649,7 @@ static void ccp_remove(struct hid_device *hdev)
{
struct ccp_device *ccp = hid_get_drvdata(hdev);
debugfs_remove_recursive(ccp->debugfs);
hwmon_device_unregister(ccp->hwmon_dev);
hid_hw_close(hdev);
hid_hw_stop(hdev);