/*
 * Copyright 2026 JS Park <mameforever2@gmail.com>
 *
 * SPDX-License-Identifier: LGPL-2.1-or-later
 */

#include "config.h"

#include "fu-lxs-touch-firmware.h"
#include "fu-lxs-touch-struct.h"

struct _FuLxsTouchFirmware {
	FuFirmware parent_instance;
	guint32 fw_offset;
};

G_DEFINE_TYPE(FuLxsTouchFirmware, fu_lxs_touch_firmware, FU_TYPE_FIRMWARE)

/* firmware sizes */
#define FU_LXS_TOUCH_FW_SIZE_APP_ONLY	(112 * 1024) /* 0x1C000 */
#define FU_LXS_TOUCH_FW_SIZE_BOOT_APP	(128 * 1024) /* 0x20000 */
#define FU_LXS_TOUCH_FW_OFFSET_APP_ONLY 0x4000

static gboolean
fu_lxs_touch_firmware_parse(FuFirmware *firmware,
			    GInputStream *stream,
			    FuFirmwareParseFlags flags,
			    GError **error)
{
	FuLxsTouchFirmware *self = FU_LXS_TOUCH_FIRMWARE(firmware);
	gsize streamsz = 0;

	/* validate firmware size */
	if (!fu_input_stream_size(stream, &streamsz, error))
		return FALSE;
	if (streamsz != FU_LXS_TOUCH_FW_SIZE_APP_ONLY &&
	    streamsz != FU_LXS_TOUCH_FW_SIZE_BOOT_APP) {
		g_set_error(error,
			    FWUPD_ERROR,
			    FWUPD_ERROR_INVALID_FILE,
			    "invalid firmware size 0x%x, expected 0x%x or 0x%x",
			    (guint)streamsz,
			    (guint)FU_LXS_TOUCH_FW_SIZE_APP_ONLY,
			    (guint)FU_LXS_TOUCH_FW_SIZE_BOOT_APP);
		return FALSE;
	}

	/* determine firmware type and offset */
	if (streamsz == FU_LXS_TOUCH_FW_SIZE_APP_ONLY) {
		self->fw_offset = FU_LXS_TOUCH_FW_OFFSET_APP_ONLY;
		g_debug("application-only firmware detected (112KB), offset=0x%04x",
			self->fw_offset);
	} else if (streamsz == FU_LXS_TOUCH_FW_SIZE_BOOT_APP) {
		self->fw_offset = 0x0;
		g_debug("boot+application firmware detected (128KB), offset=0x%04x",
			self->fw_offset);
	}

	/* success */
	return TRUE;
}

guint32
fu_lxs_touch_firmware_get_offset(FuLxsTouchFirmware *self)
{
	g_return_val_if_fail(FU_IS_LXS_TOUCH_FIRMWARE(self), 0);
	return self->fw_offset;
}

static void
fu_lxs_touch_firmware_init(FuLxsTouchFirmware *self)
{
	fu_firmware_set_images_max(FU_FIRMWARE(self), 2048);
	fu_firmware_set_size_max(FU_FIRMWARE(self), 4 * FU_MB);
	fu_firmware_add_flag(FU_FIRMWARE(self), FU_FIRMWARE_FLAG_NO_AUTO_DETECTION);
}

static void
fu_lxs_touch_firmware_class_init(FuLxsTouchFirmwareClass *klass)
{
	FuFirmwareClass *firmware_class = FU_FIRMWARE_CLASS(klass);
	firmware_class->parse = fu_lxs_touch_firmware_parse;
}
