[PATCH v3 2/6] USB: serial: mxuport: clean up firmware version handling

From: Crescent Hsieh

Date: Tue Aug 11 2026 - 02:07:34 EST


Add a small helper for parsing firmware versions and use it for the
firmware image. This avoids open-coded firmware image offsets in
probe() and retains the existing image-size validation before reading
the version bytes.

Keep the existing version comparison policy unchanged, but store the
version components explicitly so that the version can be printed
without unpacking a raw integer.

Print the firmware version fields in decimal, as these fields represent
readable version components rather than hexadecimal values.

Signed-off-by: Crescent Hsieh <crescentcy.hsieh@xxxxxxxx>
---
drivers/usb/serial/mxuport.c | 78 ++++++++++++++++++++++++------------
1 file changed, 53 insertions(+), 25 deletions(-)

diff --git a/drivers/usb/serial/mxuport.c b/drivers/usb/serial/mxuport.c
index a4e0467171c6..61d4c6e1a9ce 100644
--- a/drivers/usb/serial/mxuport.c
+++ b/drivers/usb/serial/mxuport.c
@@ -43,9 +43,22 @@
#define DOWN_BLOCK_SIZE 64

/* Definitions for firmware info */
-#define VER_ADDR_1 0x20
-#define VER_ADDR_2 0x24
-#define VER_ADDR_3 0x28
+#define MX_FW_VER_BYTE1_OFF 0x20
+#define MX_FW_VER_BYTE2_OFF 0x24
+#define MX_FW_VER_BYTE3_OFF 0x28
+
+struct mxuport_fw_version {
+ u8 major;
+ u8 minor;
+ u8 build;
+ u32 value;
+};
+
+static const u16 mxuport_fw_ver_offsets[] = {
+ MX_FW_VER_BYTE1_OFF,
+ MX_FW_VER_BYTE2_OFF,
+ MX_FW_VER_BYTE3_OFF,
+};

/* Definitions for USB vendor request */
#define RQ_VENDOR_NONE 0x00
@@ -965,8 +978,31 @@ static int mxuport_calc_num_ports(struct usb_serial *serial,
return num_ports;
}

+static void mxuport_compose_fw_version(struct mxuport_fw_version *version,
+ u8 major, u8 minor, u8 build)
+{
+ version->major = major;
+ version->minor = minor;
+ version->build = build;
+ version->value = (major << 16) | (minor << 8) | build;
+}
+
+static int mxuport_parse_fw_version(const struct firmware *fw,
+ const u16 *offsets,
+ struct mxuport_fw_version *version)
+{
+ if (fw->size <= offsets[2])
+ return -EINVAL;
+
+ mxuport_compose_fw_version(version, fw->data[offsets[0]],
+ fw->data[offsets[1]], fw->data[offsets[2]]);
+
+ return 0;
+}
+
/* Get the version of the firmware currently running. */
-static int mxuport_get_fw_version(struct usb_serial *serial, u32 *version)
+static int mxuport_get_fw_version(struct usb_serial *serial,
+ struct mxuport_fw_version *version)
{
u8 *ver_buf;
int err;
@@ -983,7 +1019,7 @@ static int mxuport_get_fw_version(struct usb_serial *serial, u32 *version)
goto out;
}

- *version = (ver_buf[0] << 16) | (ver_buf[1] << 8) | ver_buf[2];
+ mxuport_compose_fw_version(version, ver_buf[0], ver_buf[1], ver_buf[2]);
err = 0;
out:
kfree(ver_buf);
@@ -1043,9 +1079,8 @@ static int mxuport_probe(struct usb_serial *serial,
const struct usb_device_id *id)
{
u16 productid = le16_to_cpu(serial->dev->descriptor.idProduct);
+ struct mxuport_fw_version version, local_ver;
const struct firmware *fw_p = NULL;
- u32 version;
- int local_ver;
char buf[32];
int err;

@@ -1060,10 +1095,8 @@ static int mxuport_probe(struct usb_serial *serial,
if (err < 0)
return err;

- dev_dbg(&serial->interface->dev, "Device firmware version v%x.%x.%x\n",
- (version & 0xff0000) >> 16,
- (version & 0xff00) >> 8,
- (version & 0xff));
+ dev_dbg(&serial->interface->dev, "Device firmware version v%u.%u.%u\n",
+ version.major, version.minor, version.build);

snprintf(buf, sizeof(buf) - 1, "moxa/moxa-%04x.fw", productid);

@@ -1075,35 +1108,30 @@ static int mxuport_probe(struct usb_serial *serial,
/* Use the firmware already in the device */
err = 0;
} else {
- if (fw_p->size <= VER_ADDR_3) {
+ err = mxuport_parse_fw_version(fw_p, mxuport_fw_ver_offsets, &local_ver);
+ if (err) {
dev_err(&serial->interface->dev,
"Firmware %s is too short\n", buf);
- err = -EINVAL;
goto out;
}

- local_ver = ((fw_p->data[VER_ADDR_1] << 16) |
- (fw_p->data[VER_ADDR_2] << 8) |
- fw_p->data[VER_ADDR_3]);
dev_dbg(&serial->interface->dev,
- "Available firmware version v%x.%x.%x\n",
- fw_p->data[VER_ADDR_1], fw_p->data[VER_ADDR_2],
- fw_p->data[VER_ADDR_3]);
- if (local_ver > version) {
+ "Available firmware version v%u.%u.%u\n",
+ local_ver.major, local_ver.minor, local_ver.build);
+
+ if (local_ver.value > version.value) {
err = mxuport_download_fw(serial, fw_p);
if (err)
goto out;
- err = mxuport_get_fw_version(serial, &version);
+ err = mxuport_get_fw_version(serial, &version);
if (err < 0)
goto out;
}
}

dev_info(&serial->interface->dev,
- "Using device firmware version v%x.%x.%x\n",
- (version & 0xff0000) >> 16,
- (version & 0xff00) >> 8,
- (version & 0xff));
+ "Using device firmware version v%u.%u.%u\n",
+ version.major, version.minor, version.build);

/*
* Contains the features of this hardware. Store away for
--
2.53.0