mirror of
https://git.proxmox.com/git/fwupd
synced 2025-05-16 06:09:14 +00:00

Until now, the unifying plugin was a 'special snowflake' and did things in very different ways to the other plugins. Refactor each object to derive from either FuUsbDevice or FuUdevDevice, and then remove LuDevice and the LuContext layers.
232 lines
6.8 KiB
C
232 lines
6.8 KiB
C
/*
|
|
* Copyright (C) 2016-2018 Richard Hughes <richard@hughsie.com>
|
|
*
|
|
* SPDX-License-Identifier: LGPL-2.1+
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include <string.h>
|
|
|
|
#include "fu-unifying-common.h"
|
|
#include "fu-unifying-bootloader-texas.h"
|
|
|
|
struct _FuUnifyingBootloaderTexas
|
|
{
|
|
FuUnifyingBootloader parent_instance;
|
|
};
|
|
|
|
G_DEFINE_TYPE (FuUnifyingBootloaderTexas, fu_unifying_bootloader_texas, FU_TYPE_UNIFYING_BOOTLOADER)
|
|
|
|
static gboolean
|
|
fu_unifying_bootloader_texas_erase_all (FuUnifyingBootloader *self, GError **error)
|
|
{
|
|
g_autoptr(FuUnifyingBootloaderRequest) req = fu_unifying_bootloader_request_new ();
|
|
req->cmd = FU_UNIFYING_BOOTLOADER_CMD_FLASH_RAM;
|
|
req->len = 0x01; /* magic number */
|
|
req->data[0] = 0x00; /* magic number */
|
|
if (!fu_unifying_bootloader_request (self, req, error)) {
|
|
g_prefix_error (error, "failed to erase all pages: ");
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
fu_unifying_bootloader_texas_compute_and_test_crc (FuUnifyingBootloader *self, GError **error)
|
|
{
|
|
g_autoptr(FuUnifyingBootloaderRequest) req = fu_unifying_bootloader_request_new ();
|
|
req->cmd = FU_UNIFYING_BOOTLOADER_CMD_FLASH_RAM;
|
|
req->len = 0x01; /* magic number */
|
|
req->data[0] = 0x03; /* magic number */
|
|
if (!fu_unifying_bootloader_request (self, req, error)) {
|
|
g_prefix_error (error, "failed to compute and test CRC: ");
|
|
return FALSE;
|
|
}
|
|
if (req->cmd == FU_UNIFYING_BOOTLOADER_CMD_FLASH_RAM_WRONG_CRC) {
|
|
g_set_error_literal (error,
|
|
G_IO_ERROR,
|
|
G_IO_ERROR_FAILED,
|
|
"CRC is incorrect");
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
fu_unifying_bootloader_texas_flash_ram_buffer (FuUnifyingBootloader *self, guint16 addr, GError **error)
|
|
{
|
|
g_autoptr(FuUnifyingBootloaderRequest) req = fu_unifying_bootloader_request_new ();
|
|
req->cmd = FU_UNIFYING_BOOTLOADER_CMD_FLASH_RAM;
|
|
req->addr = addr;
|
|
req->len = 0x01; /* magic number */
|
|
req->data[0] = 0x01; /* magic number */
|
|
if (!fu_unifying_bootloader_request (self, req, error)) {
|
|
g_prefix_error (error, "failed to flash ram buffer @%04x: ", addr);
|
|
return FALSE;
|
|
}
|
|
if (req->cmd == FU_UNIFYING_BOOTLOADER_CMD_FLASH_RAM_INVALID_ADDR) {
|
|
g_set_error (error,
|
|
G_IO_ERROR,
|
|
G_IO_ERROR_FAILED,
|
|
"failed to flash ram buffer @%04x: invalid flash page",
|
|
addr);
|
|
return FALSE;
|
|
}
|
|
if (req->cmd == FU_UNIFYING_BOOTLOADER_CMD_FLASH_RAM_PAGE0_INVALID) {
|
|
g_set_error (error,
|
|
G_IO_ERROR,
|
|
G_IO_ERROR_FAILED,
|
|
"failed to flash ram buffer @%04x: invalid App JMP vector",
|
|
addr);
|
|
return FALSE;
|
|
}
|
|
if (req->cmd == FU_UNIFYING_BOOTLOADER_CMD_FLASH_RAM_INVALID_ORDER) {
|
|
g_set_error (error,
|
|
G_IO_ERROR,
|
|
G_IO_ERROR_FAILED,
|
|
"failed to flash ram buffer @%04x: page flashed before page 0",
|
|
addr);
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
fu_unifying_bootloader_texas_clear_ram_buffer (FuUnifyingBootloader *self, GError **error)
|
|
{
|
|
g_autoptr(FuUnifyingBootloaderRequest) req = fu_unifying_bootloader_request_new ();
|
|
req->cmd = FU_UNIFYING_BOOTLOADER_CMD_FLASH_RAM;
|
|
req->addr = 0x0000;
|
|
req->len = 0x01; /* magic number */
|
|
req->data[0] = 0x02; /* magic number */
|
|
if (!fu_unifying_bootloader_request (self, req, error)) {
|
|
g_prefix_error (error, "failed to clear ram buffer @%04x: ", req->addr);
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
fu_unifying_bootloader_texas_write_firmware (FuDevice *device, GBytes *fw, GError **error)
|
|
{
|
|
FuUnifyingBootloader *self = FU_UNIFYING_BOOTLOADER (device);
|
|
const FuUnifyingBootloaderRequest *payload;
|
|
g_autoptr(GPtrArray) reqs = NULL;
|
|
g_autoptr(FuUnifyingBootloaderRequest) req = fu_unifying_bootloader_request_new ();
|
|
|
|
/* transfer payload */
|
|
reqs = fu_unifying_bootloader_parse_requests (self, fw, error);
|
|
if (reqs == NULL)
|
|
return FALSE;
|
|
|
|
/* erase all flash pages */
|
|
fu_device_set_status (device, FWUPD_STATUS_DEVICE_ERASE);
|
|
if (!fu_unifying_bootloader_texas_erase_all (self, error))
|
|
return FALSE;
|
|
|
|
/* set existing RAM buffer to 0xff's */
|
|
if (!fu_unifying_bootloader_texas_clear_ram_buffer (self, error))
|
|
return FALSE;
|
|
|
|
/* write to RAM buffer */
|
|
fu_device_set_status (device, FWUPD_STATUS_DEVICE_WRITE);
|
|
for (guint i = 0; i < reqs->len; i++) {
|
|
payload = g_ptr_array_index (reqs, i);
|
|
|
|
/* check size */
|
|
if (payload->len != 16) {
|
|
g_set_error (error,
|
|
G_IO_ERROR,
|
|
G_IO_ERROR_FAILED,
|
|
"payload size invalid @%04x: got 0x%02x",
|
|
payload->addr, payload->len);
|
|
return FALSE;
|
|
}
|
|
|
|
/* build packet */
|
|
req->cmd = payload->cmd;
|
|
|
|
/* signature addresses do not need to fit inside 128 bytes */
|
|
if (req->cmd == FU_UNIFYING_BOOTLOADER_CMD_WRITE_SIGNATURE)
|
|
req->addr = payload->addr;
|
|
else
|
|
req->addr = payload->addr % 0x80;
|
|
|
|
req->len = payload->len;
|
|
memcpy (req->data, payload->data, payload->len);
|
|
if (!fu_unifying_bootloader_request (self, req, error)) {
|
|
g_prefix_error (error,
|
|
"failed to write ram bufer @0x%02x: ",
|
|
req->addr);
|
|
return FALSE;
|
|
}
|
|
if (req->cmd == FU_UNIFYING_BOOTLOADER_CMD_WRITE_RAM_BUFFER_INVALID_ADDR) {
|
|
g_set_error (error,
|
|
G_IO_ERROR,
|
|
G_IO_ERROR_FAILED,
|
|
"failed to write ram buffer @%04x: invalid location",
|
|
req->addr);
|
|
return FALSE;
|
|
}
|
|
if (req->cmd == FU_UNIFYING_BOOTLOADER_CMD_WRITE_RAM_BUFFER_OVERFLOW) {
|
|
g_set_error (error,
|
|
G_IO_ERROR,
|
|
G_IO_ERROR_FAILED,
|
|
"failed to write ram buffer @%04x: invalid size 0x%02x",
|
|
req->addr, req->len);
|
|
return FALSE;
|
|
}
|
|
|
|
/* flush RAM buffer to EEPROM */
|
|
if ((payload->addr + 0x10) % 0x80 == 0 &&
|
|
req->cmd != FU_UNIFYING_BOOTLOADER_CMD_WRITE_SIGNATURE) {
|
|
guint16 addr_start = payload->addr - (7 * 0x10);
|
|
g_debug ("addr flush @ 0x%04x for 0x%04x",
|
|
payload->addr, addr_start);
|
|
if (!fu_unifying_bootloader_texas_flash_ram_buffer (self,
|
|
addr_start,
|
|
error)) {
|
|
g_prefix_error (error,
|
|
"failed to flash ram buffer @0x%04x: ",
|
|
addr_start);
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
/* update progress */
|
|
fu_device_set_progress_full (device, i * 32, reqs->len * 32);
|
|
}
|
|
|
|
/* check CRC */
|
|
if (!fu_unifying_bootloader_texas_compute_and_test_crc (self, error))
|
|
return FALSE;
|
|
|
|
/* mark as complete */
|
|
fu_device_set_progress_full (device, reqs->len * 32, reqs->len * 32);
|
|
|
|
/* success! */
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
fu_unifying_bootloader_texas_setup (FuUnifyingBootloader *self, GError **error)
|
|
{
|
|
fu_device_set_version (FU_DEVICE (self), "RQR24.00_B0000");
|
|
return TRUE;
|
|
}
|
|
|
|
static void
|
|
fu_unifying_bootloader_texas_class_init (FuUnifyingBootloaderTexasClass *klass)
|
|
{
|
|
FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass);
|
|
FuUnifyingBootloaderClass *klass_device_bootloader = FU_UNIFYING_BOOTLOADER_CLASS (klass);
|
|
klass_device->write_firmware = fu_unifying_bootloader_texas_write_firmware;
|
|
klass_device_bootloader->setup = fu_unifying_bootloader_texas_setup;
|
|
}
|
|
|
|
static void
|
|
fu_unifying_bootloader_texas_init (FuUnifyingBootloaderTexas *self)
|
|
{
|
|
}
|