mirror of
https://git.proxmox.com/git/fwupd
synced 2025-08-04 01:20:25 +00:00
1110 lines
33 KiB
C
1110 lines
33 KiB
C
/*
|
|
* Copyright (C) 2012 Andrew Duggan
|
|
* Copyright (C) 2012 Synaptics Inc.
|
|
* Copyright (C) 2019 Richard Hughes <richard@hughsie.com>
|
|
*
|
|
* SPDX-License-Identifier: LGPL-2.1+
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include <fwupdplugin.h>
|
|
|
|
#include "fu-synaptics-rmi-v7-device.h"
|
|
|
|
#define RMI_F34_ERASE_WAIT_MS 10000 /* ms */
|
|
|
|
typedef enum {
|
|
RMI_FLASH_CMD_IDLE = 0x00,
|
|
RMI_FLASH_CMD_ENTER_BL,
|
|
RMI_FLASH_CMD_READ,
|
|
RMI_FLASH_CMD_WRITE,
|
|
RMI_FLASH_CMD_ERASE,
|
|
RMI_FLASH_CMD_ERASE_AP,
|
|
RMI_FLASH_CMD_SENSOR_ID,
|
|
RMI_FLASH_CMD_SIGNATURE,
|
|
} RmiFlashCommand;
|
|
|
|
typedef enum {
|
|
RMI_PARTITION_ID_NONE = 0x00,
|
|
RMI_PARTITION_ID_BOOTLOADER = 0x01,
|
|
RMI_PARTITION_ID_DEVICE_CONFIG,
|
|
RMI_PARTITION_ID_FLASH_CONFIG,
|
|
RMI_PARTITION_ID_MANUFACTURING_BLOCK,
|
|
RMI_PARTITION_ID_GUEST_SERIALIZATION,
|
|
RMI_PARTITION_ID_GLOBAL_PARAMETERS,
|
|
RMI_PARTITION_ID_CORE_CODE,
|
|
RMI_PARTITION_ID_CORE_CONFIG,
|
|
RMI_PARTITION_ID_GUEST_CODE,
|
|
RMI_PARTITION_ID_DISPLAY_CONFIG,
|
|
RMI_PARTITION_ID_EXTERNAL_TOUCH_AFE_CONFIG,
|
|
RMI_PARTITION_ID_UTILITY_PARAMETER,
|
|
RMI_PARTITION_ID_PUBKEY,
|
|
RMI_PARTITION_ID_FIXED_LOCATION_DATA = 0x0E,
|
|
} RmiPartitionId;
|
|
|
|
static const gchar *
|
|
rmi_firmware_partition_id_to_string(RmiPartitionId partition_id)
|
|
{
|
|
if (partition_id == RMI_PARTITION_ID_NONE)
|
|
return "none";
|
|
if (partition_id == RMI_PARTITION_ID_BOOTLOADER)
|
|
return "bootloader";
|
|
if (partition_id == RMI_PARTITION_ID_DEVICE_CONFIG)
|
|
return "device-config";
|
|
if (partition_id == RMI_PARTITION_ID_FLASH_CONFIG)
|
|
return "flash-config";
|
|
if (partition_id == RMI_PARTITION_ID_MANUFACTURING_BLOCK)
|
|
return "manufacturing-block";
|
|
if (partition_id == RMI_PARTITION_ID_GUEST_SERIALIZATION)
|
|
return "guest-serialization";
|
|
if (partition_id == RMI_PARTITION_ID_GLOBAL_PARAMETERS)
|
|
return "global-parameters";
|
|
if (partition_id == RMI_PARTITION_ID_CORE_CODE)
|
|
return "core-code";
|
|
if (partition_id == RMI_PARTITION_ID_CORE_CONFIG)
|
|
return "core-config";
|
|
if (partition_id == RMI_PARTITION_ID_GUEST_CODE)
|
|
return "guest-code";
|
|
if (partition_id == RMI_PARTITION_ID_DISPLAY_CONFIG)
|
|
return "display-config";
|
|
if (partition_id == RMI_PARTITION_ID_EXTERNAL_TOUCH_AFE_CONFIG)
|
|
return "external-touch-afe-config";
|
|
if (partition_id == RMI_PARTITION_ID_UTILITY_PARAMETER)
|
|
return "utility-parameter";
|
|
if (partition_id == RMI_PARTITION_ID_PUBKEY)
|
|
return "pubkey";
|
|
if (partition_id == RMI_PARTITION_ID_FIXED_LOCATION_DATA)
|
|
return "fixed-location-data";
|
|
return NULL;
|
|
}
|
|
|
|
gboolean
|
|
fu_synaptics_rmi_v7_device_detach(FuDevice *device, FuProgress *progress, GError **error)
|
|
{
|
|
FuSynapticsRmiDevice *self = FU_SYNAPTICS_RMI_DEVICE(device);
|
|
g_autoptr(GByteArray) enable_req = g_byte_array_new();
|
|
FuSynapticsRmiFlash *flash = fu_synaptics_rmi_device_get_flash(self);
|
|
FuSynapticsRmiFunction *f34;
|
|
|
|
/* f34 */
|
|
f34 = fu_synaptics_rmi_device_get_function(self, 0x34, error);
|
|
if (f34 == NULL)
|
|
return FALSE;
|
|
|
|
/* disable interrupts */
|
|
if (!fu_synaptics_rmi_device_disable_irqs(self, error))
|
|
return FALSE;
|
|
|
|
/* enter BL */
|
|
fu_byte_array_append_uint8(enable_req, RMI_PARTITION_ID_BOOTLOADER);
|
|
fu_byte_array_append_uint32(enable_req, 0x0, G_LITTLE_ENDIAN);
|
|
fu_byte_array_append_uint8(enable_req, RMI_FLASH_CMD_ENTER_BL);
|
|
fu_byte_array_append_uint8(enable_req, flash->bootloader_id[0]);
|
|
fu_byte_array_append_uint8(enable_req, flash->bootloader_id[1]);
|
|
if (!fu_synaptics_rmi_device_write(self,
|
|
f34->data_base + 1,
|
|
enable_req,
|
|
FU_SYNAPTICS_RMI_DEVICE_FLAG_NONE,
|
|
error)) {
|
|
g_prefix_error(error, "failed to enable programming: ");
|
|
return FALSE;
|
|
}
|
|
|
|
/* wait for idle */
|
|
if (!fu_synaptics_rmi_device_wait_for_idle(self,
|
|
RMI_F34_ENABLE_WAIT_MS,
|
|
RMI_DEVICE_WAIT_FOR_IDLE_FLAG_NONE,
|
|
error))
|
|
return FALSE;
|
|
if (!fu_synaptics_rmi_device_poll_wait(self, error))
|
|
return FALSE;
|
|
g_usleep(1000 * RMI_F34_ENABLE_WAIT_MS);
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
fu_synaptics_rmi_v7_device_erase_partition(FuSynapticsRmiDevice *self,
|
|
guint8 partition_id,
|
|
GError **error)
|
|
{
|
|
FuSynapticsRmiFunction *f34;
|
|
FuSynapticsRmiFlash *flash = fu_synaptics_rmi_device_get_flash(self);
|
|
g_autoptr(GByteArray) erase_cmd = g_byte_array_new();
|
|
|
|
/* f34 */
|
|
f34 = fu_synaptics_rmi_device_get_function(self, 0x34, error);
|
|
if (f34 == NULL)
|
|
return FALSE;
|
|
fu_byte_array_append_uint8(erase_cmd, partition_id);
|
|
fu_byte_array_append_uint32(erase_cmd, 0x0, G_LITTLE_ENDIAN);
|
|
fu_byte_array_append_uint8(erase_cmd, RMI_FLASH_CMD_ERASE);
|
|
|
|
fu_byte_array_append_uint8(erase_cmd, flash->bootloader_id[0]);
|
|
fu_byte_array_append_uint8(erase_cmd, flash->bootloader_id[1]);
|
|
|
|
g_usleep(1000 * 1000);
|
|
if (!fu_synaptics_rmi_device_write(self,
|
|
f34->data_base + 1,
|
|
erase_cmd,
|
|
FU_SYNAPTICS_RMI_DEVICE_FLAG_NONE,
|
|
error)) {
|
|
g_prefix_error(error, "failed to unlock erasing: ");
|
|
return FALSE;
|
|
}
|
|
g_usleep(1000 * 100);
|
|
|
|
/* wait for ATTN */
|
|
if (!fu_synaptics_rmi_device_wait_for_idle(self,
|
|
RMI_F34_ERASE_WAIT_MS,
|
|
RMI_DEVICE_WAIT_FOR_IDLE_FLAG_NONE,
|
|
error)) {
|
|
g_prefix_error(error, "failed to wait for idle: ");
|
|
return FALSE;
|
|
}
|
|
|
|
if (!fu_synaptics_rmi_device_poll_wait(self, error)) {
|
|
g_prefix_error(error, "failed to get flash success: ");
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
fu_synaptics_rmi_v7_device_erase_all(FuSynapticsRmiDevice *self, GError **error)
|
|
{
|
|
FuSynapticsRmiFunction *f34;
|
|
FuSynapticsRmiFlash *flash = fu_synaptics_rmi_device_get_flash(self);
|
|
g_autoptr(GByteArray) erase_cmd = g_byte_array_new();
|
|
|
|
/* f34 */
|
|
f34 = fu_synaptics_rmi_device_get_function(self, 0x34, error);
|
|
if (f34 == NULL)
|
|
return FALSE;
|
|
|
|
fu_byte_array_append_uint8(erase_cmd, RMI_PARTITION_ID_CORE_CODE);
|
|
fu_byte_array_append_uint32(erase_cmd, 0x0, G_LITTLE_ENDIAN);
|
|
if (flash->bootloader_id[1] >= 8) {
|
|
/* For bootloader v8 */
|
|
fu_byte_array_append_uint8(erase_cmd, RMI_FLASH_CMD_ERASE_AP);
|
|
} else {
|
|
/* For bootloader v7 */
|
|
fu_byte_array_append_uint8(erase_cmd, RMI_FLASH_CMD_ERASE);
|
|
}
|
|
fu_byte_array_append_uint8(erase_cmd, flash->bootloader_id[0]);
|
|
fu_byte_array_append_uint8(erase_cmd, flash->bootloader_id[1]);
|
|
/* for BL8 device, we need hold 1 seconds after querying F34 status to
|
|
* avoid not get attention by following giving erase command */
|
|
if (flash->bootloader_id[1] >= 8)
|
|
g_usleep(1000 * 1000);
|
|
if (!fu_synaptics_rmi_device_write(self,
|
|
f34->data_base + 1,
|
|
erase_cmd,
|
|
FU_SYNAPTICS_RMI_DEVICE_FLAG_NONE,
|
|
error)) {
|
|
g_prefix_error(error, "failed to unlock erasing: ");
|
|
return FALSE;
|
|
}
|
|
g_usleep(1000 * 100);
|
|
if (flash->bootloader_id[1] >= 8) {
|
|
/* wait for ATTN */
|
|
if (!fu_synaptics_rmi_device_wait_for_idle(self,
|
|
RMI_F34_ERASE_WAIT_MS,
|
|
RMI_DEVICE_WAIT_FOR_IDLE_FLAG_NONE,
|
|
error)) {
|
|
g_prefix_error(error, "failed to wait for idle: ");
|
|
return FALSE;
|
|
}
|
|
}
|
|
if (!fu_synaptics_rmi_device_poll_wait(self, error)) {
|
|
g_prefix_error(error, "failed to get flash success: ");
|
|
return FALSE;
|
|
}
|
|
|
|
/* for BL7, we need erase config partition */
|
|
if (flash->bootloader_id[1] == 7) {
|
|
g_autoptr(GByteArray) erase_config_cmd = g_byte_array_new();
|
|
|
|
fu_byte_array_append_uint8(erase_config_cmd, RMI_PARTITION_ID_CORE_CONFIG);
|
|
fu_byte_array_append_uint32(erase_config_cmd, 0x0, G_LITTLE_ENDIAN);
|
|
fu_byte_array_append_uint8(erase_config_cmd, RMI_FLASH_CMD_ERASE);
|
|
|
|
g_usleep(1000 * 100);
|
|
if (!fu_synaptics_rmi_device_write(self,
|
|
f34->data_base + 1,
|
|
erase_config_cmd,
|
|
FU_SYNAPTICS_RMI_DEVICE_FLAG_NONE,
|
|
error)) {
|
|
g_prefix_error(error, "failed to erase core config: ");
|
|
return FALSE;
|
|
}
|
|
|
|
/* wait for ATTN */
|
|
g_usleep(1000 * 100);
|
|
if (!fu_synaptics_rmi_device_wait_for_idle(
|
|
self,
|
|
RMI_F34_ERASE_WAIT_MS,
|
|
RMI_DEVICE_WAIT_FOR_IDLE_FLAG_REFRESH_F34,
|
|
error)) {
|
|
g_prefix_error(error, "failed to wait for idle: ");
|
|
return FALSE;
|
|
}
|
|
if (!fu_synaptics_rmi_device_poll_wait(self, error)) {
|
|
g_prefix_error(error, "failed to get flash success: ");
|
|
return FALSE;
|
|
}
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
fu_synaptics_rmi_v7_device_write_blocks(FuSynapticsRmiDevice *self,
|
|
guint32 address,
|
|
const guint8 *data,
|
|
guint32 datasz,
|
|
GError **error)
|
|
{
|
|
FuSynapticsRmiFlash *flash = fu_synaptics_rmi_device_get_flash(self);
|
|
g_autoptr(GPtrArray) chunks = NULL;
|
|
|
|
/* write FW blocks */
|
|
chunks = fu_chunk_array_new(data,
|
|
datasz,
|
|
0x00, /* start addr */
|
|
0x00, /* page_sz */
|
|
flash->block_size);
|
|
for (guint i = 0; i < chunks->len; i++) {
|
|
FuChunk *chk = g_ptr_array_index(chunks, i);
|
|
g_autoptr(GByteArray) req = g_byte_array_new();
|
|
g_byte_array_append(req, fu_chunk_get_data(chk), fu_chunk_get_data_sz(chk));
|
|
if (!fu_synaptics_rmi_device_write(self,
|
|
address,
|
|
req,
|
|
FU_SYNAPTICS_RMI_DEVICE_FLAG_NONE,
|
|
error)) {
|
|
g_prefix_error(error,
|
|
"failed to write block @0x%x:%x: ",
|
|
address,
|
|
fu_chunk_get_address(chk));
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
/* wait for idle */
|
|
if (!fu_synaptics_rmi_device_wait_for_idle(self,
|
|
RMI_F34_IDLE_WAIT_MS,
|
|
RMI_DEVICE_WAIT_FOR_IDLE_FLAG_NONE,
|
|
error)) {
|
|
g_prefix_error(error, "failed to wait for idle @0x%x: ", address);
|
|
return FALSE;
|
|
}
|
|
|
|
/* success */
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
fu_synaptics_rmi_v7_device_write_partition_signature(FuSynapticsRmiDevice *self,
|
|
FuFirmware *firmware,
|
|
const gchar *id,
|
|
RmiPartitionId partition_id,
|
|
GError **error)
|
|
{
|
|
FuSynapticsRmiFunction *f34;
|
|
FuSynapticsRmiFlash *flash = fu_synaptics_rmi_device_get_flash(self);
|
|
g_autoptr(GByteArray) req_offset = g_byte_array_new();
|
|
g_autoptr(GPtrArray) chunks = NULL;
|
|
g_autoptr(GBytes) bytes = NULL;
|
|
|
|
/* f34 */
|
|
f34 = fu_synaptics_rmi_device_get_function(self, 0x34, error);
|
|
if (f34 == NULL)
|
|
return FALSE;
|
|
|
|
/*check if signature exists */
|
|
bytes =
|
|
fu_firmware_get_image_by_id_bytes(firmware, g_strdup_printf("%s-signature", id), NULL);
|
|
if (bytes == NULL) {
|
|
return TRUE;
|
|
}
|
|
|
|
/* write partition signature */
|
|
g_debug("writing partition signature %s…",
|
|
rmi_firmware_partition_id_to_string(partition_id));
|
|
|
|
fu_byte_array_append_uint16(req_offset, 0x0, G_LITTLE_ENDIAN);
|
|
if (!fu_synaptics_rmi_device_write(self,
|
|
f34->data_base + 0x2,
|
|
req_offset,
|
|
FU_SYNAPTICS_RMI_DEVICE_FLAG_NONE,
|
|
error)) {
|
|
g_prefix_error(error, "failed to write offset: ");
|
|
return FALSE;
|
|
}
|
|
|
|
chunks =
|
|
fu_chunk_array_new_from_bytes(bytes,
|
|
0x00, /* start addr */
|
|
0x00, /* page_sz */
|
|
(gsize)flash->payload_length * (gsize)flash->block_size);
|
|
for (guint i = 0; i < chunks->len; i++) {
|
|
FuChunk *chk = g_ptr_array_index(chunks, i);
|
|
g_autoptr(GByteArray) req_trans_sz = g_byte_array_new();
|
|
g_autoptr(GByteArray) req_cmd = g_byte_array_new();
|
|
fu_byte_array_append_uint16(req_trans_sz,
|
|
fu_chunk_get_data_sz(chk) / flash->block_size,
|
|
G_LITTLE_ENDIAN);
|
|
if (!fu_synaptics_rmi_device_write(self,
|
|
f34->data_base + 0x3,
|
|
req_trans_sz,
|
|
FU_SYNAPTICS_RMI_DEVICE_FLAG_NONE,
|
|
error)) {
|
|
g_prefix_error(error, "failed to write transfer length: ");
|
|
return FALSE;
|
|
}
|
|
fu_byte_array_append_uint8(req_cmd, RMI_FLASH_CMD_SIGNATURE);
|
|
if (!fu_synaptics_rmi_device_write(self,
|
|
f34->data_base + 0x4,
|
|
req_cmd,
|
|
FU_SYNAPTICS_RMI_DEVICE_FLAG_NONE,
|
|
error)) {
|
|
g_prefix_error(error, "failed to write signature command: ");
|
|
return FALSE;
|
|
}
|
|
if (!fu_synaptics_rmi_v7_device_write_blocks(self,
|
|
f34->data_base + 0x5,
|
|
fu_chunk_get_data(chk),
|
|
fu_chunk_get_data_sz(chk),
|
|
error))
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
fu_synaptics_rmi_v7_device_write_partition(FuSynapticsRmiDevice *self,
|
|
FuFirmware *firmware,
|
|
const gchar *id,
|
|
RmiPartitionId partition_id,
|
|
GBytes *bytes,
|
|
FuProgress *progress,
|
|
GError **error)
|
|
{
|
|
FuSynapticsRmiFunction *f34;
|
|
FuSynapticsRmiFlash *flash = fu_synaptics_rmi_device_get_flash(self);
|
|
g_autoptr(GByteArray) req_offset = g_byte_array_new();
|
|
g_autoptr(GByteArray) req_partition_id = g_byte_array_new();
|
|
g_autoptr(GPtrArray) chunks = NULL;
|
|
|
|
/* f34 */
|
|
f34 = fu_synaptics_rmi_device_get_function(self, 0x34, error);
|
|
if (f34 == NULL)
|
|
return FALSE;
|
|
|
|
/* write partition id */
|
|
g_debug("writing partition %s…", rmi_firmware_partition_id_to_string(partition_id));
|
|
fu_byte_array_append_uint8(req_partition_id, partition_id);
|
|
if (!fu_synaptics_rmi_device_write(self,
|
|
f34->data_base + 0x1,
|
|
req_partition_id,
|
|
FU_SYNAPTICS_RMI_DEVICE_FLAG_NONE,
|
|
error)) {
|
|
g_prefix_error(error, "failed to write flash partition: ");
|
|
return FALSE;
|
|
}
|
|
fu_byte_array_append_uint16(req_offset, 0x0, G_LITTLE_ENDIAN);
|
|
if (!fu_synaptics_rmi_device_write(self,
|
|
f34->data_base + 0x2,
|
|
req_offset,
|
|
FU_SYNAPTICS_RMI_DEVICE_FLAG_NONE,
|
|
error)) {
|
|
g_prefix_error(error, "failed to write offset: ");
|
|
return FALSE;
|
|
}
|
|
|
|
/* write partition */
|
|
chunks =
|
|
fu_chunk_array_new_from_bytes(bytes,
|
|
0x00, /* start addr */
|
|
0x00, /* page_sz */
|
|
(gsize)flash->payload_length * (gsize)flash->block_size);
|
|
fu_progress_set_id(progress, G_STRLOC);
|
|
fu_progress_set_steps(progress, chunks->len + 1);
|
|
for (guint i = 0; i < chunks->len; i++) {
|
|
FuChunk *chk = g_ptr_array_index(chunks, i);
|
|
g_autoptr(GByteArray) req_trans_sz = g_byte_array_new();
|
|
g_autoptr(GByteArray) req_cmd = g_byte_array_new();
|
|
fu_byte_array_append_uint16(req_trans_sz,
|
|
fu_chunk_get_data_sz(chk) / flash->block_size,
|
|
G_LITTLE_ENDIAN);
|
|
if (!fu_synaptics_rmi_device_write(self,
|
|
f34->data_base + 0x3,
|
|
req_trans_sz,
|
|
FU_SYNAPTICS_RMI_DEVICE_FLAG_NONE,
|
|
error)) {
|
|
g_prefix_error(error, "failed to write transfer length: ");
|
|
return FALSE;
|
|
}
|
|
fu_byte_array_append_uint8(req_cmd, RMI_FLASH_CMD_WRITE);
|
|
if (!fu_synaptics_rmi_device_write(self,
|
|
f34->data_base + 0x4,
|
|
req_cmd,
|
|
FU_SYNAPTICS_RMI_DEVICE_FLAG_NONE,
|
|
error)) {
|
|
g_prefix_error(error, "failed to flash command: ");
|
|
return FALSE;
|
|
}
|
|
if (!fu_synaptics_rmi_v7_device_write_blocks(self,
|
|
f34->data_base + 0x5,
|
|
fu_chunk_get_data(chk),
|
|
fu_chunk_get_data_sz(chk),
|
|
error))
|
|
return FALSE;
|
|
fu_progress_step_done(progress);
|
|
}
|
|
if (!fu_synaptics_rmi_v7_device_write_partition_signature(self,
|
|
firmware,
|
|
id,
|
|
partition_id,
|
|
error))
|
|
return FALSE;
|
|
fu_progress_step_done(progress);
|
|
return TRUE;
|
|
}
|
|
|
|
GBytes *
|
|
fu_synaptics_rmi_v7_device_get_pubkey(FuSynapticsRmiDevice *self, GError **error)
|
|
{
|
|
FuSynapticsRmiFlash *flash = fu_synaptics_rmi_device_get_flash(self);
|
|
FuSynapticsRmiFunction *f34;
|
|
const gsize key_size = RMI_KEY_SIZE_2K;
|
|
g_autoptr(GByteArray) req_addr_zero = g_byte_array_new();
|
|
g_autoptr(GByteArray) req_cmd = g_byte_array_new();
|
|
g_autoptr(GByteArray) req_partition_id = g_byte_array_new();
|
|
g_autoptr(GByteArray) req_transfer_length = g_byte_array_new();
|
|
g_autoptr(GByteArray) res = NULL;
|
|
g_autoptr(GByteArray) pubkey = g_byte_array_new();
|
|
|
|
/* f34 */
|
|
f34 = fu_synaptics_rmi_device_get_function(self, 0x34, error);
|
|
if (f34 == NULL)
|
|
return NULL;
|
|
|
|
/* set partition id for bootloader 7 */
|
|
fu_byte_array_append_uint8(req_partition_id, RMI_PARTITION_ID_PUBKEY);
|
|
if (!fu_synaptics_rmi_device_write(self,
|
|
f34->data_base + 0x1,
|
|
req_partition_id,
|
|
FU_SYNAPTICS_RMI_DEVICE_FLAG_NONE,
|
|
error)) {
|
|
g_prefix_error(error, "failed to write flash partition id: ");
|
|
return NULL;
|
|
}
|
|
fu_byte_array_append_uint16(req_addr_zero, 0x0, G_LITTLE_ENDIAN);
|
|
if (!fu_synaptics_rmi_device_write(self,
|
|
f34->data_base + 0x2,
|
|
req_addr_zero,
|
|
FU_SYNAPTICS_RMI_DEVICE_FLAG_NONE,
|
|
error)) {
|
|
g_prefix_error(error, "failed to write flash config address: ");
|
|
return NULL;
|
|
}
|
|
|
|
/* set transfer length */
|
|
fu_byte_array_append_uint16(req_transfer_length,
|
|
key_size / flash->block_size,
|
|
G_LITTLE_ENDIAN);
|
|
if (!fu_synaptics_rmi_device_write(self,
|
|
f34->data_base + 0x3,
|
|
req_transfer_length,
|
|
FU_SYNAPTICS_RMI_DEVICE_FLAG_NONE,
|
|
error)) {
|
|
g_prefix_error(error, "failed to set transfer length: ");
|
|
return NULL;
|
|
}
|
|
|
|
/* set command to read */
|
|
fu_byte_array_append_uint8(req_cmd, RMI_FLASH_CMD_READ);
|
|
if (!fu_synaptics_rmi_device_write(self,
|
|
f34->data_base + 0x4,
|
|
req_cmd,
|
|
FU_SYNAPTICS_RMI_DEVICE_FLAG_NONE,
|
|
error)) {
|
|
g_prefix_error(error, "failed to write command to read: ");
|
|
return NULL;
|
|
}
|
|
if (!fu_synaptics_rmi_device_poll_wait(self, error)) {
|
|
g_prefix_error(error, "failed to wait: ");
|
|
return NULL;
|
|
}
|
|
|
|
/* read back entire buffer in blocks */
|
|
res = fu_synaptics_rmi_device_read(self, f34->data_base + 0x5, (guint32)key_size, error);
|
|
if (res == NULL) {
|
|
g_prefix_error(error, "failed to read: ");
|
|
return NULL;
|
|
}
|
|
|
|
for (guint i = 0; i < res->len; i++)
|
|
fu_byte_array_append_uint8(pubkey, res->data[res->len - i - 1]);
|
|
|
|
/* success */
|
|
return g_byte_array_free_to_bytes(g_steal_pointer(&pubkey));
|
|
}
|
|
|
|
gboolean
|
|
fu_synaptics_rmi_v7_device_secure_check(FuSynapticsRmiDevice *self,
|
|
FuFirmware *firmware,
|
|
GError **error)
|
|
{
|
|
FuSynapticsRmiFlash *flash = fu_synaptics_rmi_device_get_flash(self);
|
|
g_autoptr(GBytes) pubkey = NULL;
|
|
g_autoptr(GPtrArray) imgs = NULL;
|
|
|
|
if (flash->bootloader_id[1] >= 10 || flash->has_pubkey == FALSE)
|
|
return TRUE;
|
|
|
|
pubkey = fu_synaptics_rmi_v7_device_get_pubkey(self, error);
|
|
if (pubkey == NULL) {
|
|
g_prefix_error(error, "get pubkey failed: ");
|
|
return FALSE;
|
|
}
|
|
|
|
imgs = fu_firmware_get_images(firmware);
|
|
for (guint i = 0; i < imgs->len; i++) {
|
|
FuFirmware *img = g_ptr_array_index(imgs, i);
|
|
const gchar *id = fu_firmware_get_id(img);
|
|
g_autoptr(GBytes) byte_payload = NULL;
|
|
g_autoptr(GBytes) byte_signature = NULL;
|
|
g_autofree gchar *id_signature = NULL;
|
|
|
|
if (g_str_has_suffix(id, "-signature"))
|
|
continue;
|
|
id_signature = g_strdup_printf("%s-signature", id);
|
|
byte_signature = fu_firmware_get_image_by_id_bytes(firmware, id_signature, NULL);
|
|
if (byte_signature == NULL)
|
|
continue;
|
|
byte_payload = fu_firmware_get_bytes(img, error);
|
|
if (byte_payload == NULL)
|
|
return FALSE;
|
|
if (!fu_synaptics_verify_sha256_signature(byte_payload,
|
|
pubkey,
|
|
byte_signature,
|
|
error)) {
|
|
g_prefix_error(error, "%s secure check failed: ", id);
|
|
return FALSE;
|
|
}
|
|
g_debug("%s signature verified successfully", id);
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
gboolean
|
|
fu_synaptics_rmi_v7_device_write_firmware(FuDevice *device,
|
|
FuFirmware *firmware,
|
|
FuProgress *progress,
|
|
FwupdInstallFlags flags,
|
|
GError **error)
|
|
{
|
|
FuSynapticsRmiDevice *self = FU_SYNAPTICS_RMI_DEVICE(device);
|
|
FuSynapticsRmiFlash *flash = fu_synaptics_rmi_device_get_flash(self);
|
|
FuSynapticsRmiFunction *f34;
|
|
g_autoptr(GBytes) bytes_bin = NULL;
|
|
g_autoptr(GBytes) bytes_cfg = NULL;
|
|
g_autoptr(GBytes) bytes_flashcfg = NULL;
|
|
g_autoptr(GBytes) bytes_fld = NULL;
|
|
g_autoptr(GBytes) bytes_afe = NULL;
|
|
g_autoptr(GBytes) bytes_displayconfig = NULL;
|
|
|
|
/* progress */
|
|
fu_progress_set_id(progress, G_STRLOC);
|
|
if (flash->bootloader_id[1] > 8) {
|
|
fu_progress_add_step(progress, FWUPD_STATUS_DEVICE_BUSY, 0, "disable-sleep");
|
|
fu_progress_add_step(progress, FWUPD_STATUS_DEVICE_READ, 0, "verify-signature");
|
|
fu_progress_add_step(progress, FWUPD_STATUS_DEVICE_WRITE, 1, "fixed-location-data");
|
|
fu_progress_add_step(progress, FWUPD_STATUS_DEVICE_WRITE, 8, "flash-config");
|
|
fu_progress_add_step(progress, FWUPD_STATUS_DEVICE_ERASE, 9, NULL);
|
|
fu_progress_add_step(progress, FWUPD_STATUS_DEVICE_WRITE, 81, "core-code");
|
|
fu_progress_add_step(progress, FWUPD_STATUS_DEVICE_WRITE, 1, "core-config");
|
|
fu_progress_add_step(progress,
|
|
FWUPD_STATUS_DEVICE_WRITE,
|
|
0,
|
|
"external-touch-afe-config");
|
|
fu_progress_add_step(progress, FWUPD_STATUS_DEVICE_WRITE, 0, "display-config");
|
|
} else if (flash->bootloader_id[1] == 8) {
|
|
fu_progress_add_step(progress, FWUPD_STATUS_DEVICE_BUSY, 0, "disable-sleep");
|
|
fu_progress_add_step(progress, FWUPD_STATUS_DEVICE_READ, 0, "verify-signature");
|
|
fu_progress_add_step(progress, FWUPD_STATUS_DEVICE_WRITE, 0, "fixed-location-data");
|
|
fu_progress_add_step(progress, FWUPD_STATUS_DEVICE_ERASE, 16, NULL);
|
|
fu_progress_add_step(progress, FWUPD_STATUS_DEVICE_WRITE, 0, "flash-config");
|
|
fu_progress_add_step(progress, FWUPD_STATUS_DEVICE_WRITE, 81, "core-code");
|
|
fu_progress_add_step(progress, FWUPD_STATUS_DEVICE_WRITE, 1, "core-config");
|
|
fu_progress_add_step(progress,
|
|
FWUPD_STATUS_DEVICE_WRITE,
|
|
0,
|
|
"external-touch-afe-config");
|
|
fu_progress_add_step(progress, FWUPD_STATUS_DEVICE_WRITE, 0, "display-config");
|
|
} else {
|
|
fu_progress_add_flag(progress, FU_PROGRESS_FLAG_GUESSED);
|
|
fu_progress_add_step(progress, FWUPD_STATUS_DEVICE_BUSY, 0, "disable-sleep");
|
|
fu_progress_add_step(progress, FWUPD_STATUS_DEVICE_READ, 2, "verify-signature");
|
|
fu_progress_add_step(progress, FWUPD_STATUS_DEVICE_WRITE, 2, "fixed-location-data");
|
|
fu_progress_add_step(progress, FWUPD_STATUS_DEVICE_ERASE, 3, NULL);
|
|
fu_progress_add_step(progress, FWUPD_STATUS_DEVICE_WRITE, 89, "core-code");
|
|
fu_progress_add_step(progress, FWUPD_STATUS_DEVICE_WRITE, 2, "core-config");
|
|
fu_progress_add_step(progress,
|
|
FWUPD_STATUS_DEVICE_WRITE,
|
|
2,
|
|
"external-touch-afe-config");
|
|
fu_progress_add_step(progress, FWUPD_STATUS_DEVICE_WRITE, 2, "display-config");
|
|
}
|
|
|
|
/* we should be in bootloader mode now, but check anyway */
|
|
if (!fu_device_has_flag(device, FWUPD_DEVICE_FLAG_IS_BOOTLOADER)) {
|
|
g_set_error_literal(error,
|
|
FWUPD_ERROR,
|
|
FWUPD_ERROR_NOT_SUPPORTED,
|
|
"not bootloader, perhaps need detach?!");
|
|
return FALSE;
|
|
}
|
|
|
|
/* f34 */
|
|
f34 = fu_synaptics_rmi_device_get_function(self, 0x34, error);
|
|
if (f34 == NULL)
|
|
return FALSE;
|
|
|
|
/* get both images */
|
|
bytes_bin = fu_firmware_get_image_by_id_bytes(firmware, "ui", error);
|
|
if (bytes_bin == NULL)
|
|
return FALSE;
|
|
bytes_cfg = fu_firmware_get_image_by_id_bytes(firmware, "config", error);
|
|
if (bytes_cfg == NULL)
|
|
return FALSE;
|
|
if (flash->bootloader_id[1] >= 8) {
|
|
bytes_flashcfg = fu_firmware_get_image_by_id_bytes(firmware, "flash-config", error);
|
|
if (bytes_flashcfg == NULL)
|
|
return FALSE;
|
|
}
|
|
bytes_fld = fu_firmware_get_image_by_id_bytes(firmware, "fixed-location-data", NULL);
|
|
bytes_afe = fu_firmware_get_image_by_id_bytes(firmware, "afe-config", NULL);
|
|
bytes_displayconfig = fu_firmware_get_image_by_id_bytes(firmware, "display-config", NULL);
|
|
|
|
/* disable powersaving */
|
|
if (!fu_synaptics_rmi_device_disable_sleep(self, error))
|
|
return FALSE;
|
|
fu_progress_step_done(progress);
|
|
|
|
/* verify signature */
|
|
if (!fu_synaptics_rmi_v7_device_secure_check(self, firmware, error))
|
|
return FALSE;
|
|
fu_progress_step_done(progress);
|
|
|
|
/* write fld before erase if exists */
|
|
if (bytes_fld != NULL) {
|
|
if (!fu_synaptics_rmi_v7_device_write_partition(
|
|
self,
|
|
firmware,
|
|
"fixed-location-data",
|
|
RMI_PARTITION_ID_FIXED_LOCATION_DATA,
|
|
bytes_fld,
|
|
fu_progress_get_child(progress),
|
|
error))
|
|
return FALSE;
|
|
}
|
|
fu_progress_step_done(progress);
|
|
|
|
/* write flash config for BL > v8 */
|
|
if (flash->bootloader_id[1] > 8) {
|
|
if (!fu_synaptics_rmi_v7_device_erase_partition(self,
|
|
RMI_PARTITION_ID_FLASH_CONFIG,
|
|
error))
|
|
return FALSE;
|
|
if (!fu_synaptics_rmi_v7_device_write_partition(self,
|
|
firmware,
|
|
"flash-config",
|
|
RMI_PARTITION_ID_FLASH_CONFIG,
|
|
bytes_flashcfg,
|
|
fu_progress_get_child(progress),
|
|
error))
|
|
return FALSE;
|
|
fu_progress_step_done(progress);
|
|
}
|
|
|
|
/* erase all */
|
|
if (!fu_synaptics_rmi_v7_device_erase_all(self, error)) {
|
|
g_prefix_error(error, "failed to erase all: ");
|
|
return FALSE;
|
|
}
|
|
fu_progress_step_done(progress);
|
|
|
|
/* write flash config for v8 */
|
|
if (flash->bootloader_id[1] == 8) {
|
|
if (!fu_synaptics_rmi_v7_device_write_partition(self,
|
|
firmware,
|
|
"flash-config",
|
|
RMI_PARTITION_ID_FLASH_CONFIG,
|
|
bytes_flashcfg,
|
|
fu_progress_get_child(progress),
|
|
error))
|
|
return FALSE;
|
|
fu_progress_step_done(progress);
|
|
}
|
|
|
|
/* write core code */
|
|
if (!fu_synaptics_rmi_v7_device_write_partition(self,
|
|
firmware,
|
|
"ui",
|
|
RMI_PARTITION_ID_CORE_CODE,
|
|
bytes_bin,
|
|
fu_progress_get_child(progress),
|
|
error))
|
|
return FALSE;
|
|
fu_progress_step_done(progress);
|
|
|
|
/* write core config */
|
|
if (!fu_synaptics_rmi_v7_device_write_partition(self,
|
|
firmware,
|
|
"config",
|
|
RMI_PARTITION_ID_CORE_CONFIG,
|
|
bytes_cfg,
|
|
fu_progress_get_child(progress),
|
|
error))
|
|
return FALSE;
|
|
fu_progress_step_done(progress);
|
|
|
|
/* write afe-config if exists */
|
|
if (bytes_afe != NULL) {
|
|
if (!fu_synaptics_rmi_v7_device_write_partition(
|
|
self,
|
|
firmware,
|
|
"afe-config",
|
|
RMI_PARTITION_ID_EXTERNAL_TOUCH_AFE_CONFIG,
|
|
bytes_afe,
|
|
fu_progress_get_child(progress),
|
|
error))
|
|
return FALSE;
|
|
}
|
|
fu_progress_step_done(progress);
|
|
|
|
/* write display config if exists */
|
|
if (bytes_displayconfig != NULL) {
|
|
if (!fu_synaptics_rmi_v7_device_write_partition(self,
|
|
firmware,
|
|
"display-config",
|
|
RMI_PARTITION_ID_DISPLAY_CONFIG,
|
|
bytes_displayconfig,
|
|
fu_progress_get_child(progress),
|
|
error))
|
|
return FALSE;
|
|
}
|
|
fu_progress_step_done(progress);
|
|
|
|
/* success */
|
|
return TRUE;
|
|
}
|
|
|
|
typedef struct __attribute__((packed)) {
|
|
guint16 partition_id;
|
|
guint16 partition_len;
|
|
guint16 partition_addr;
|
|
guint16 partition_prop;
|
|
} RmiPartitionTbl;
|
|
|
|
G_STATIC_ASSERT(sizeof(RmiPartitionTbl) == 8);
|
|
|
|
static gboolean
|
|
fu_synaptics_rmi_device_read_flash_config_v7(FuSynapticsRmiDevice *self, GError **error)
|
|
{
|
|
FuSynapticsRmiFlash *flash = fu_synaptics_rmi_device_get_flash(self);
|
|
FuSynapticsRmiFunction *f34;
|
|
g_autoptr(GByteArray) req_addr_zero = g_byte_array_new();
|
|
g_autoptr(GByteArray) req_cmd = g_byte_array_new();
|
|
g_autoptr(GByteArray) req_partition_id = g_byte_array_new();
|
|
g_autoptr(GByteArray) req_transfer_length = g_byte_array_new();
|
|
g_autoptr(GByteArray) res = NULL;
|
|
gsize partition_size = sizeof(RmiPartitionTbl);
|
|
|
|
/* f34 */
|
|
f34 = fu_synaptics_rmi_device_get_function(self, 0x34, error);
|
|
if (f34 == NULL)
|
|
return FALSE;
|
|
|
|
/* set partition id for bootloader 7 */
|
|
fu_byte_array_append_uint8(req_partition_id, RMI_PARTITION_ID_FLASH_CONFIG);
|
|
if (!fu_synaptics_rmi_device_write(self,
|
|
f34->data_base + 0x1,
|
|
req_partition_id,
|
|
FU_SYNAPTICS_RMI_DEVICE_FLAG_NONE,
|
|
error)) {
|
|
g_prefix_error(error, "failed to write flash partition id: ");
|
|
return FALSE;
|
|
}
|
|
fu_byte_array_append_uint16(req_addr_zero, 0x0, G_LITTLE_ENDIAN);
|
|
if (!fu_synaptics_rmi_device_write(self,
|
|
f34->data_base + 0x2,
|
|
req_addr_zero,
|
|
FU_SYNAPTICS_RMI_DEVICE_FLAG_NONE,
|
|
error)) {
|
|
g_prefix_error(error, "failed to write flash config address: ");
|
|
return FALSE;
|
|
}
|
|
|
|
/* set transfer length */
|
|
fu_byte_array_append_uint16(req_transfer_length, flash->config_length, G_LITTLE_ENDIAN);
|
|
if (!fu_synaptics_rmi_device_write(self,
|
|
f34->data_base + 0x3,
|
|
req_transfer_length,
|
|
FU_SYNAPTICS_RMI_DEVICE_FLAG_NONE,
|
|
error)) {
|
|
g_prefix_error(error, "failed to set transfer length: ");
|
|
return FALSE;
|
|
}
|
|
|
|
/* set command to read */
|
|
fu_byte_array_append_uint8(req_cmd, RMI_FLASH_CMD_READ);
|
|
if (!fu_synaptics_rmi_device_write(self,
|
|
f34->data_base + 0x4,
|
|
req_cmd,
|
|
FU_SYNAPTICS_RMI_DEVICE_FLAG_NONE,
|
|
error)) {
|
|
g_prefix_error(error, "failed to write command to read: ");
|
|
return FALSE;
|
|
}
|
|
if (!fu_synaptics_rmi_device_poll_wait(self, error)) {
|
|
g_prefix_error(error, "failed to wait: ");
|
|
return FALSE;
|
|
}
|
|
|
|
/* read back entire buffer in blocks */
|
|
res =
|
|
fu_synaptics_rmi_device_read(self,
|
|
f34->data_base + 0x5,
|
|
(guint32)flash->block_size * (guint32)flash->config_length,
|
|
error);
|
|
if (res == NULL) {
|
|
g_prefix_error(error, "failed to read: ");
|
|
return FALSE;
|
|
}
|
|
|
|
/* debugging */
|
|
if (g_getenv("FWUPD_SYNAPTICS_RMI_VERBOSE") != NULL) {
|
|
fu_dump_full(G_LOG_DOMAIN,
|
|
"FlashConfig",
|
|
res->data,
|
|
res->len,
|
|
80,
|
|
FU_DUMP_FLAGS_NONE);
|
|
}
|
|
|
|
if ((res->data[0] & 0x0f) == 1)
|
|
partition_size = sizeof(RmiPartitionTbl) + 2;
|
|
|
|
/* parse the config length */
|
|
for (guint i = 0x2; i < res->len; i += partition_size) {
|
|
RmiPartitionTbl tbl;
|
|
if (!fu_memcpy_safe((guint8 *)&tbl,
|
|
sizeof(tbl),
|
|
0x0, /* dst */
|
|
res->data,
|
|
res->len,
|
|
i, /* src */
|
|
sizeof(tbl),
|
|
error))
|
|
return FALSE;
|
|
g_debug("found partition %s (0x%02x)",
|
|
rmi_firmware_partition_id_to_string(tbl.partition_id),
|
|
tbl.partition_id);
|
|
if (tbl.partition_id == RMI_PARTITION_ID_CORE_CONFIG) {
|
|
flash->block_count_cfg = tbl.partition_len;
|
|
continue;
|
|
}
|
|
if (tbl.partition_id == RMI_PARTITION_ID_CORE_CODE) {
|
|
flash->block_count_fw = tbl.partition_len;
|
|
continue;
|
|
}
|
|
if (tbl.partition_id == RMI_PARTITION_ID_PUBKEY) {
|
|
flash->has_pubkey = TRUE;
|
|
continue;
|
|
}
|
|
if (tbl.partition_id == RMI_PARTITION_ID_NONE)
|
|
break;
|
|
}
|
|
|
|
/* success */
|
|
return TRUE;
|
|
}
|
|
|
|
gboolean
|
|
fu_synaptics_rmi_v7_device_setup(FuSynapticsRmiDevice *self, GError **error)
|
|
{
|
|
FuSynapticsRmiFlash *flash = fu_synaptics_rmi_device_get_flash(self);
|
|
FuSynapticsRmiFunction *f34;
|
|
guint8 offset;
|
|
g_autoptr(GByteArray) f34_data0 = NULL;
|
|
g_autoptr(GByteArray) f34_dataX = NULL;
|
|
|
|
/* f34 */
|
|
f34 = fu_synaptics_rmi_device_get_function(self, 0x34, error);
|
|
if (f34 == NULL)
|
|
return FALSE;
|
|
|
|
f34_data0 = fu_synaptics_rmi_device_read(self, f34->query_base, 1, error);
|
|
if (f34_data0 == NULL) {
|
|
g_prefix_error(error, "failed to read bootloader ID: ");
|
|
return FALSE;
|
|
}
|
|
offset = (f34_data0->data[0] & 0b00000111) + 1;
|
|
f34_dataX = fu_synaptics_rmi_device_read(self, f34->query_base + offset, 21, error);
|
|
if (f34_dataX == NULL)
|
|
return FALSE;
|
|
if (!fu_memread_uint8_safe(f34_dataX->data,
|
|
f34_dataX->len,
|
|
0x0,
|
|
&flash->bootloader_id[0],
|
|
error))
|
|
return FALSE;
|
|
if (!fu_memread_uint8_safe(f34_dataX->data,
|
|
f34_dataX->len,
|
|
0x1,
|
|
&flash->bootloader_id[1],
|
|
error))
|
|
return FALSE;
|
|
if (!fu_memread_uint16_safe(f34_dataX->data,
|
|
f34_dataX->len,
|
|
0x07,
|
|
&flash->block_size,
|
|
G_LITTLE_ENDIAN,
|
|
error))
|
|
return FALSE;
|
|
if (!fu_memread_uint16_safe(f34_dataX->data,
|
|
f34_dataX->len,
|
|
0x0d,
|
|
&flash->config_length,
|
|
G_LITTLE_ENDIAN,
|
|
error))
|
|
return FALSE;
|
|
if (!fu_memread_uint16_safe(f34_dataX->data,
|
|
f34_dataX->len,
|
|
0x0f,
|
|
&flash->payload_length,
|
|
G_LITTLE_ENDIAN,
|
|
error))
|
|
return FALSE;
|
|
if (!fu_memread_uint32_safe(f34_dataX->data,
|
|
f34_dataX->len,
|
|
0x02,
|
|
&flash->build_id,
|
|
G_LITTLE_ENDIAN,
|
|
error))
|
|
return FALSE;
|
|
|
|
/* sanity check */
|
|
if ((guint32)flash->block_size * (guint32)flash->config_length > G_MAXUINT16) {
|
|
g_set_error(error,
|
|
FWUPD_ERROR,
|
|
FWUPD_ERROR_NOT_SUPPORTED,
|
|
"block size 0x%x or config length 0x%x invalid",
|
|
flash->block_size,
|
|
flash->config_length);
|
|
return FALSE;
|
|
}
|
|
|
|
/* read flash config */
|
|
return fu_synaptics_rmi_device_read_flash_config_v7(self, error);
|
|
}
|
|
|
|
gboolean
|
|
fu_synaptics_rmi_v7_device_query_status(FuSynapticsRmiDevice *self, GError **error)
|
|
{
|
|
FuSynapticsRmiFunction *f34;
|
|
guint8 status;
|
|
g_autoptr(GByteArray) f34_data = NULL;
|
|
|
|
/* f34 */
|
|
f34 = fu_synaptics_rmi_device_get_function(self, 0x34, error);
|
|
if (f34 == NULL)
|
|
return FALSE;
|
|
f34_data = fu_synaptics_rmi_device_read(self, f34->data_base, 0x1, error);
|
|
if (f34_data == NULL) {
|
|
g_prefix_error(error, "failed to read the f01 data base: ");
|
|
return FALSE;
|
|
}
|
|
status = f34_data->data[0];
|
|
if (status & 0x80) {
|
|
fu_device_add_flag(FU_DEVICE(self), FWUPD_DEVICE_FLAG_IS_BOOTLOADER);
|
|
} else {
|
|
fu_device_remove_flag(FU_DEVICE(self), FWUPD_DEVICE_FLAG_IS_BOOTLOADER);
|
|
}
|
|
if (status == 0x01) {
|
|
g_set_error_literal(error,
|
|
FWUPD_ERROR,
|
|
FWUPD_ERROR_NOT_SUPPORTED,
|
|
"operation only supported in bootloader mode");
|
|
return FALSE;
|
|
}
|
|
if (status == 0x02) {
|
|
g_set_error_literal(error,
|
|
FWUPD_ERROR,
|
|
FWUPD_ERROR_NOT_SUPPORTED,
|
|
"partition ID is not supported by the bootloader");
|
|
return FALSE;
|
|
}
|
|
if (status == 0x03) {
|
|
g_set_error_literal(error,
|
|
FWUPD_ERROR,
|
|
FWUPD_ERROR_NOT_SUPPORTED,
|
|
"partition supported, but command not supported");
|
|
return FALSE;
|
|
}
|
|
if (status == 0x04) {
|
|
g_set_error_literal(error,
|
|
FWUPD_ERROR,
|
|
FWUPD_ERROR_INVALID_FILE,
|
|
"invalid block offset");
|
|
return FALSE;
|
|
}
|
|
if (status == 0x05) {
|
|
g_set_error_literal(error,
|
|
FWUPD_ERROR,
|
|
FWUPD_ERROR_INVALID_FILE,
|
|
"invalid transfer");
|
|
return FALSE;
|
|
}
|
|
if (status == 0x06) {
|
|
g_set_error_literal(error,
|
|
FWUPD_ERROR,
|
|
FWUPD_ERROR_NOT_SUPPORTED,
|
|
"partition has not been erased");
|
|
return FALSE;
|
|
}
|
|
if (status == 0x07) {
|
|
g_set_error_literal(error,
|
|
FWUPD_ERROR,
|
|
FWUPD_ERROR_SIGNATURE_INVALID,
|
|
"flash programming key incorrect");
|
|
return FALSE;
|
|
}
|
|
if (status == 0x08) {
|
|
g_set_error_literal(error,
|
|
FWUPD_ERROR,
|
|
FWUPD_ERROR_INTERNAL,
|
|
"bad partition table");
|
|
return FALSE;
|
|
}
|
|
if (status == 0x09) {
|
|
g_set_error_literal(error,
|
|
FWUPD_ERROR,
|
|
FWUPD_ERROR_INVALID_FILE,
|
|
"transfer checksum failed");
|
|
return FALSE;
|
|
}
|
|
if (status == 0x1f) {
|
|
g_set_error_literal(error,
|
|
FWUPD_ERROR,
|
|
FWUPD_ERROR_INVALID_FILE,
|
|
"flash hardware failure");
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|