mirror of
				https://git.proxmox.com/git/fwupd
				synced 2025-11-04 15:10:22 +00:00 
			
		
		
		
	This allows us to 'nest' firmware formats, and removes a ton of duplication. The aim here is to deprecate FuFirmwareImage -- it's almost always acting as a 'child' FuFirmware instance, and even copies most of the vfuncs to allow custom types. If I'm struggling to work out what should be a FuFirmware and what should be a FuFirmwareImage then a plugin author has no hope. For simple payloads we were adding bytes into an image and then the image into a firmware. This gets really messy when most plugins are treating the FuFirmware *as* the binary firmware file. The GBytes saved in the FuFirmware would be considered the payload with the aim of not using FuFirmwareImage in the single-image case.
		
			
				
	
	
		
			120 lines
		
	
	
		
			3.1 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			120 lines
		
	
	
		
			3.1 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
 * Copyright (C) 2016 Richard Hughes <richard@hughsie.com>
 | 
						|
 *
 | 
						|
 * SPDX-License-Identifier: LGPL-2.1+
 | 
						|
 */
 | 
						|
 | 
						|
#include "config.h"
 | 
						|
 | 
						|
#include "fu-common.h"
 | 
						|
#include "fu-ebitdo-firmware.h"
 | 
						|
 | 
						|
struct _FuEbitdoFirmware {
 | 
						|
	FuFirmwareClass		 parent_instance;
 | 
						|
};
 | 
						|
 | 
						|
G_DEFINE_TYPE (FuEbitdoFirmware, fu_ebitdo_firmware, FU_TYPE_FIRMWARE)
 | 
						|
 | 
						|
/* little endian */
 | 
						|
typedef struct __attribute__((packed)) {
 | 
						|
	guint32		version;
 | 
						|
	guint32		destination_addr;
 | 
						|
	guint32		destination_len;
 | 
						|
	guint32		reserved[4];
 | 
						|
} FuEbitdoFirmwareHeader;
 | 
						|
 | 
						|
static gboolean
 | 
						|
fu_ebitdo_firmware_parse (FuFirmware *firmware,
 | 
						|
			  GBytes *fw,
 | 
						|
			  guint64 addr_start,
 | 
						|
			  guint64 addr_end,
 | 
						|
			  FwupdInstallFlags flags,
 | 
						|
			  GError **error)
 | 
						|
{
 | 
						|
	FuEbitdoFirmwareHeader *hdr;
 | 
						|
	guint32 payload_len;
 | 
						|
	g_autofree gchar *version = NULL;
 | 
						|
	g_autoptr(FuFirmware) img_hdr = fu_firmware_new ();
 | 
						|
	g_autoptr(GBytes) fw_hdr = NULL;
 | 
						|
	g_autoptr(GBytes) fw_payload = NULL;
 | 
						|
 | 
						|
	/* corrupt */
 | 
						|
	if (g_bytes_get_size (fw) < sizeof (FuEbitdoFirmwareHeader)) {
 | 
						|
		g_set_error_literal (error,
 | 
						|
				     G_IO_ERROR,
 | 
						|
				     G_IO_ERROR_INVALID_DATA,
 | 
						|
				     "firmware too small for header");
 | 
						|
		return FALSE;
 | 
						|
	}
 | 
						|
 | 
						|
	/* check the file size */
 | 
						|
	hdr = (FuEbitdoFirmwareHeader *) g_bytes_get_data (fw, NULL);
 | 
						|
	payload_len = (guint32) (g_bytes_get_size (fw) - sizeof (FuEbitdoFirmwareHeader));
 | 
						|
	if (payload_len != GUINT32_FROM_LE(hdr->destination_len)) {
 | 
						|
		g_set_error (error,
 | 
						|
			     G_IO_ERROR,
 | 
						|
			     G_IO_ERROR_INVALID_DATA,
 | 
						|
			     "file size incorrect, expected 0x%04x got 0x%04x",
 | 
						|
			     (guint) GUINT32_FROM_LE (hdr->destination_len),
 | 
						|
			     (guint) payload_len);
 | 
						|
		return FALSE;
 | 
						|
	}
 | 
						|
 | 
						|
	/* check if this is firmware */
 | 
						|
	for (guint i = 0; i < 4; i++) {
 | 
						|
		if (hdr->reserved[i] != 0x0) {
 | 
						|
			g_set_error (error,
 | 
						|
				     G_IO_ERROR,
 | 
						|
				     G_IO_ERROR_INVALID_DATA,
 | 
						|
				     "data invalid, reserved[%u] = 0x%04x",
 | 
						|
				     i, hdr->reserved[i]);
 | 
						|
			return FALSE;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	/* parse version */
 | 
						|
	version = g_strdup_printf ("%.2f", GUINT32_FROM_LE(hdr->version) / 100.f);
 | 
						|
	fu_firmware_set_version (firmware, version);
 | 
						|
	fu_firmware_set_version_raw (firmware, GUINT32_FROM_LE(hdr->version));
 | 
						|
 | 
						|
	/* add header */
 | 
						|
	fw_hdr = fu_common_bytes_new_offset (fw, 0x0,
 | 
						|
					     sizeof(FuEbitdoFirmwareHeader),
 | 
						|
					     error);
 | 
						|
	if (fw_hdr == NULL)
 | 
						|
		return FALSE;
 | 
						|
	fu_firmware_set_id (img_hdr, FU_FIRMWARE_ID_HEADER);
 | 
						|
	fu_firmware_set_bytes (img_hdr, fw_hdr);
 | 
						|
	fu_firmware_add_image (firmware, img_hdr);
 | 
						|
 | 
						|
	/* add payload */
 | 
						|
	fw_payload = fu_common_bytes_new_offset (fw,
 | 
						|
						 sizeof(FuEbitdoFirmwareHeader),
 | 
						|
						 payload_len,
 | 
						|
						 error);
 | 
						|
	if (fw_payload == NULL)
 | 
						|
		return FALSE;
 | 
						|
	fu_firmware_set_id (firmware, FU_FIRMWARE_ID_PAYLOAD);
 | 
						|
	fu_firmware_set_addr (firmware, GUINT32_FROM_LE(hdr->destination_addr));
 | 
						|
	fu_firmware_set_bytes (firmware, fw_payload);
 | 
						|
	return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
fu_ebitdo_firmware_init (FuEbitdoFirmware *self)
 | 
						|
{
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
fu_ebitdo_firmware_class_init (FuEbitdoFirmwareClass *klass)
 | 
						|
{
 | 
						|
	FuFirmwareClass *klass_firmware = FU_FIRMWARE_CLASS (klass);
 | 
						|
	klass_firmware->parse = fu_ebitdo_firmware_parse;
 | 
						|
}
 | 
						|
 | 
						|
FuFirmware *
 | 
						|
fu_ebitdo_firmware_new (void)
 | 
						|
{
 | 
						|
	return FU_FIRMWARE (g_object_new (FU_TYPE_EBITDO_FIRMWARE, NULL));
 | 
						|
}
 |