diff --git a/libfwupdplugin/fu-common.c b/libfwupdplugin/fu-common.c index d2084b205..710a47b08 100644 --- a/libfwupdplugin/fu-common.c +++ b/libfwupdplugin/fu-common.c @@ -877,6 +877,34 @@ fu_common_write_uint16(guint8 *buf, guint16 val_native, FuEndianType endian) memcpy(buf, &val_hw, sizeof(val_hw)); } +/** + * fu_common_write_uint24: + * @buf: a writable buffer + * @val_native: a value in host byte-order + * @endian: an endian type, e.g. %G_LITTLE_ENDIAN + * + * Writes a value to a buffer using a specified endian. + * + * Since: 1.8.0 + **/ +void +fu_common_write_uint24(guint8 *buf, guint32 val_native, FuEndianType endian) +{ + guint32 val_hw; + switch (endian) { + case G_BIG_ENDIAN: + val_hw = GUINT32_TO_BE(val_native); + memcpy(buf, ((const guint8 *)&val_hw) + 0x1, 0x3); + break; + case G_LITTLE_ENDIAN: + val_hw = GUINT32_TO_LE(val_native); + memcpy(buf, &val_hw, 0x3); + break; + default: + g_assert_not_reached(); + } +} + /** * fu_common_write_uint32: * @buf: a writable buffer @@ -960,6 +988,37 @@ fu_common_read_uint16(const guint8 *buf, FuEndianType endian) return val_native; } +/** + * fu_common_read_uint24: + * @buf: a readable buffer + * @endian: an endian type, e.g. %G_LITTLE_ENDIAN + * + * Read a value from a buffer using a specified endian. + * + * Returns: a value in host byte-order + * + * Since: 1.8.0 + **/ +guint32 +fu_common_read_uint24(const guint8 *buf, FuEndianType endian) +{ + guint32 val_hw = 0; + guint32 val_native; + switch (endian) { + case G_BIG_ENDIAN: + memcpy(((guint8 *)&val_hw) + 0x1, buf, 0x3); + val_native = GUINT32_FROM_BE(val_hw); + break; + case G_LITTLE_ENDIAN: + memcpy(&val_hw, buf, 0x3); + val_native = GUINT32_FROM_LE(val_hw); + break; + default: + g_assert_not_reached(); + } + return val_native; +} + /** * fu_common_read_uint32: * @buf: a readable buffer diff --git a/libfwupdplugin/fu-common.h b/libfwupdplugin/fu-common.h index af69a1933..c8b084745 100644 --- a/libfwupdplugin/fu-common.h +++ b/libfwupdplugin/fu-common.h @@ -365,12 +365,16 @@ fu_byte_array_compare(GByteArray *buf1, GByteArray *buf2, GError **error); void fu_common_write_uint16(guint8 *buf, guint16 val_native, FuEndianType endian); void +fu_common_write_uint24(guint8 *buf, guint32 val_native, FuEndianType endian); +void fu_common_write_uint32(guint8 *buf, guint32 val_native, FuEndianType endian); void fu_common_write_uint64(guint8 *buf, guint64 val_native, FuEndianType endian); guint16 fu_common_read_uint16(const guint8 *buf, FuEndianType endian); guint32 +fu_common_read_uint24(const guint8 *buf, FuEndianType endian); +guint32 fu_common_read_uint32(const guint8 *buf, FuEndianType endian); guint64 fu_common_read_uint64(const guint8 *buf, FuEndianType endian); diff --git a/libfwupdplugin/fu-self-test.c b/libfwupdplugin/fu-self-test.c index caf1253c1..000cb4de2 100644 --- a/libfwupdplugin/fu-self-test.c +++ b/libfwupdplugin/fu-self-test.c @@ -1057,7 +1057,7 @@ fu_common_spawn_timeout_func(void) static void fu_common_endian_func(void) { - guint8 buf[2]; + guint8 buf[3]; fu_common_write_uint16(buf, 0x1234, G_LITTLE_ENDIAN); g_assert_cmpint(buf[0], ==, 0x34); @@ -1068,6 +1068,18 @@ fu_common_endian_func(void) g_assert_cmpint(buf[0], ==, 0x12); g_assert_cmpint(buf[1], ==, 0x34); g_assert_cmpint(fu_common_read_uint16(buf, G_BIG_ENDIAN), ==, 0x1234); + + fu_common_write_uint24(buf, 0x123456, G_LITTLE_ENDIAN); + g_assert_cmpint(buf[0], ==, 0x56); + g_assert_cmpint(buf[1], ==, 0x34); + g_assert_cmpint(buf[2], ==, 0x12); + g_assert_cmpint(fu_common_read_uint24(buf, G_LITTLE_ENDIAN), ==, 0x123456); + + fu_common_write_uint24(buf, 0x123456, G_BIG_ENDIAN); + g_assert_cmpint(buf[0], ==, 0x12); + g_assert_cmpint(buf[1], ==, 0x34); + g_assert_cmpint(buf[2], ==, 0x56); + g_assert_cmpint(fu_common_read_uint24(buf, G_BIG_ENDIAN), ==, 0x123456); } static GBytes * diff --git a/libfwupdplugin/fwupdplugin.map b/libfwupdplugin/fwupdplugin.map index f39ebb3c8..47250c498 100644 --- a/libfwupdplugin/fwupdplugin.map +++ b/libfwupdplugin/fwupdplugin.map @@ -1024,7 +1024,9 @@ LIBFWUPDPLUGIN_1.8.0 { fu_byte_array_compare; fu_cfi_device_chip_select; fu_cfi_device_chip_select_locker_new; + fu_common_read_uint24; fu_common_reverse_uint8; + fu_common_write_uint24; fu_coswid_firmware_get_type; fu_coswid_firmware_new; fu_device_has_inhibit; diff --git a/plugins/dfu-csr/fu-dfu-csr-device.c b/plugins/dfu-csr/fu-dfu-csr-device.c index 0df9ea63d..2281a3195 100644 --- a/plugins/dfu-csr/fu-dfu-csr-device.c +++ b/plugins/dfu-csr/fu-dfu-csr-device.c @@ -104,7 +104,7 @@ fu_dfu_csr_device_get_status(FuDfuCsrDevice *self, GError **error) } self->dfu_state = buf[5]; - self->dnload_timeout = buf[2] + (((guint32)buf[3]) << 8) + (((guint32)buf[4]) << 16); + self->dnload_timeout = fu_common_read_uint24(&buf[2], G_LITTLE_ENDIAN); g_debug("timeout=%" G_GUINT32_FORMAT, self->dnload_timeout); g_debug("state=%s", fu_dfu_state_to_string(self->dfu_state)); g_debug("status=%s", fu_dfu_status_to_string(buf[6])); diff --git a/plugins/dfu/fu-dfu-device.c b/plugins/dfu/fu-dfu-device.c index 68e1e1fe4..bb5289dee 100644 --- a/plugins/dfu/fu-dfu-device.c +++ b/plugins/dfu/fu-dfu-device.c @@ -889,8 +889,7 @@ fu_dfu_device_refresh(FuDfuDevice *self, GError **error) if (fu_device_has_private_flag(FU_DEVICE(self), FU_DFU_DEVICE_FLAG_IGNORE_POLLTIMEOUT)) { priv->dnload_timeout = DFU_DEVICE_DNLOAD_TIMEOUT_DEFAULT; } else { - priv->dnload_timeout = - buf[1] + (((guint32)buf[2]) << 8) + (((guint32)buf[3]) << 16); + priv->dnload_timeout = fu_common_read_uint24(&buf[1], G_LITTLE_ENDIAN); if (priv->dnload_timeout == 0 && !fu_device_has_private_flag(FU_DEVICE(self), FU_DFU_DEVICE_FLAG_ALLOW_ZERO_POLLTIMEOUT)) {