hwmon: (corsair-cpro) Add firmware and bootloader information
authorMarius Zachmann <mail@mariuszachmann.de>
Mon, 13 May 2024 19:47:34 +0000 (21:47 +0200)
committerGuenter Roeck <linux@roeck-us.net>
Wed, 29 May 2024 22:23:54 +0000 (15:23 -0700)
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>
Documentation/hwmon/corsair-cpro.rst
drivers/hwmon/corsair-cpro.c

index 751f95476b5718f04be745d554c384847e85e3cb..15077203a2f81d1c5313f0a653fcae59da7c684c 100644 (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
+======================= ===================
index 3e63666a61bd6b275e7140def18184c968e3fd52..e3300f3f4da693da35ae480a56a2c87da41be649 100644 (file)
 
 #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);