mirror of
https://git.proxmox.com/git/fwupd
synced 2025-05-15 18:36:32 +00:00
158 lines
4.5 KiB
C
158 lines
4.5 KiB
C
/*
|
|
* Copyright (C) 2015-2016 Richard Hughes <richard@hughsie.com>
|
|
*
|
|
* SPDX-License-Identifier: LGPL-2.1+
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include <string.h>
|
|
|
|
#include "fu-dfu-firmware.h"
|
|
|
|
#include "dfu-element.h"
|
|
#include "dfu-format-dfu.h"
|
|
#include "dfu-format-dfuse.h"
|
|
#include "dfu-format-raw.h"
|
|
#include "dfu-image.h"
|
|
|
|
#include "fwupd-error.h"
|
|
|
|
/**
|
|
* dfu_firmware_detect_dfu: (skip)
|
|
* @bytes: data to parse
|
|
*
|
|
* Attempts to sniff the data and work out the firmware format
|
|
*
|
|
* Returns: a #DfuFirmwareFormat, e.g. %DFU_FIRMWARE_FORMAT_RAW
|
|
**/
|
|
DfuFirmwareFormat
|
|
dfu_firmware_detect_dfu (GBytes *bytes)
|
|
{
|
|
g_autoptr(FuFirmware) firmware = fu_dfu_firmware_new ();
|
|
/* check versions */
|
|
if (!fu_firmware_parse (firmware, bytes, FWUPD_INSTALL_FLAG_NONE, NULL))
|
|
return DFU_FIRMWARE_FORMAT_UNKNOWN;
|
|
switch (fu_dfu_firmware_get_version (FU_DFU_FIRMWARE (firmware))) {
|
|
case DFU_VERSION_DFU_1_0:
|
|
case DFU_VERSION_DFU_1_1:
|
|
return DFU_FIRMWARE_FORMAT_DFU;
|
|
case DFU_VERSION_DFUSE:
|
|
return DFU_FIRMWARE_FORMAT_DFUSE;
|
|
default:
|
|
break;
|
|
}
|
|
return DFU_FIRMWARE_FORMAT_UNKNOWN;
|
|
}
|
|
|
|
/**
|
|
* dfu_firmware_from_dfu: (skip)
|
|
* @firmware: a #DfuFirmware
|
|
* @bytes: data to parse
|
|
* @flags: some #FwupdInstallFlags
|
|
* @error: a #GError, or %NULL
|
|
*
|
|
* Unpacks into a firmware object from dfu data.
|
|
*
|
|
* Returns: %TRUE for success
|
|
**/
|
|
gboolean
|
|
dfu_firmware_from_dfu (DfuFirmware *firmware,
|
|
GBytes *bytes,
|
|
FwupdInstallFlags flags,
|
|
GError **error)
|
|
{
|
|
g_autoptr(FuFirmware) native = fu_dfu_firmware_new ();
|
|
g_autoptr(GBytes) contents = NULL;
|
|
if (!fu_firmware_parse (native, bytes, flags, error))
|
|
return FALSE;
|
|
|
|
fu_dfu_firmware_set_vid (FU_DFU_FIRMWARE (firmware),
|
|
fu_dfu_firmware_get_vid (FU_DFU_FIRMWARE (native)));
|
|
fu_dfu_firmware_set_pid (FU_DFU_FIRMWARE (firmware),
|
|
fu_dfu_firmware_get_pid (FU_DFU_FIRMWARE (native)));
|
|
fu_dfu_firmware_set_release (FU_DFU_FIRMWARE (firmware),
|
|
fu_dfu_firmware_get_release (FU_DFU_FIRMWARE (native)));
|
|
|
|
/* parse DfuSe prefix */
|
|
contents = fu_firmware_get_image_default_bytes (native, error);
|
|
if (contents == NULL)
|
|
return FALSE;
|
|
if (dfu_firmware_get_format (firmware) == DFU_FIRMWARE_FORMAT_DFUSE)
|
|
return dfu_firmware_from_dfuse (firmware, contents, flags, error);
|
|
|
|
/* just copy old-plain DFU file */
|
|
return dfu_firmware_from_raw (firmware, contents, flags, error);
|
|
}
|
|
|
|
static DfuVersion
|
|
dfu_convert_version (DfuFirmwareFormat format)
|
|
{
|
|
if (format == DFU_FIRMWARE_FORMAT_DFU)
|
|
return DFU_VERSION_DFU_1_0;
|
|
if (format == DFU_FIRMWARE_FORMAT_DFUSE)
|
|
return DFU_VERSION_DFUSE;
|
|
return DFU_VERSION_UNKNOWN;
|
|
}
|
|
|
|
static GBytes *
|
|
dfu_firmware_add_footer (DfuFirmware *firmware, GBytes *contents, GError **error)
|
|
{
|
|
g_autoptr(FuFirmware) native = fu_dfu_firmware_new ();
|
|
g_autoptr(FuFirmwareImage) image = fu_firmware_image_new (contents);
|
|
fu_dfu_firmware_set_vid (FU_DFU_FIRMWARE (native),
|
|
fu_dfu_firmware_get_vid (FU_DFU_FIRMWARE (firmware)));
|
|
fu_dfu_firmware_set_pid (FU_DFU_FIRMWARE (native),
|
|
fu_dfu_firmware_get_pid (FU_DFU_FIRMWARE (firmware)));
|
|
fu_dfu_firmware_set_release (FU_DFU_FIRMWARE (native),
|
|
fu_dfu_firmware_get_release (FU_DFU_FIRMWARE (firmware)));
|
|
fu_dfu_firmware_set_version (FU_DFU_FIRMWARE (native),
|
|
dfu_convert_version (dfu_firmware_get_format (firmware)));
|
|
fu_firmware_add_image (native, image);
|
|
return fu_firmware_write (native, error);
|
|
}
|
|
/**
|
|
* dfu_firmware_to_dfu: (skip)
|
|
* @firmware: a #DfuFirmware
|
|
* @error: a #GError, or %NULL
|
|
*
|
|
* Packs dfu firmware
|
|
*
|
|
* Returns: (transfer full): the packed data
|
|
**/
|
|
GBytes *
|
|
dfu_firmware_to_dfu (DfuFirmware *firmware, GError **error)
|
|
{
|
|
/* plain DFU */
|
|
if (dfu_firmware_get_format (firmware) == DFU_FIRMWARE_FORMAT_DFU) {
|
|
GBytes *contents;
|
|
DfuElement *element;
|
|
g_autoptr(DfuImage) image = NULL;
|
|
image = DFU_IMAGE (fu_firmware_get_image_default (FU_FIRMWARE (firmware), error));
|
|
if (image == NULL)
|
|
return NULL;
|
|
element = dfu_image_get_element (image, 0);
|
|
if (element == NULL) {
|
|
g_set_error (error,
|
|
FWUPD_ERROR,
|
|
FWUPD_ERROR_NOT_FOUND,
|
|
"no firmware element data to write");
|
|
return NULL;
|
|
}
|
|
contents = dfu_element_get_contents (element);
|
|
return dfu_firmware_add_footer (firmware, contents, error);
|
|
}
|
|
|
|
/* DfuSe */
|
|
if (dfu_firmware_get_format (firmware) == DFU_FIRMWARE_FORMAT_DFUSE) {
|
|
g_autoptr(GBytes) contents = NULL;
|
|
contents = dfu_firmware_to_dfuse (firmware, error);
|
|
if (contents == NULL)
|
|
return NULL;
|
|
return dfu_firmware_add_footer (firmware, contents, error);
|
|
}
|
|
|
|
g_assert_not_reached ();
|
|
return NULL;
|
|
}
|