mirror of
https://git.proxmox.com/git/fwupd
synced 2025-06-12 00:19:11 +00:00

We tried to solve this by matching the org.fwupd.hsi AppStream ID, but in some cases the resolution depends on what actually failed. Add "the action the user is supposed to do" as flags so that the front-end can translate this in the appropriate way, for instance, using a different string for log events and HSI dialogs.
550 lines
16 KiB
C
550 lines
16 KiB
C
/*
|
|
* Copyright (C) 2021 Richard Hughes <richard@hughsie.com>
|
|
*
|
|
* SPDX-License-Identifier: GPL-2+
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include <fwupdplugin.h>
|
|
|
|
#include <fcntl.h>
|
|
#include <sys/mman.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/types.h>
|
|
#ifdef HAVE_ERRNO_H
|
|
#include <errno.h>
|
|
#endif
|
|
|
|
#include <gio/gunixinputstream.h>
|
|
|
|
#include "fu-ifd-device.h"
|
|
#include "fu-intel-spi-common.h"
|
|
#include "fu-intel-spi-device.h"
|
|
#include "fu-pci-device.h"
|
|
|
|
struct _FuIntelSpiDevice {
|
|
FuDevice parent_instance;
|
|
FuIntelSpiKind kind;
|
|
gchar *spibar_proxy;
|
|
guint32 phys_spibar;
|
|
gpointer spibar;
|
|
guint16 hsfs;
|
|
guint16 frap;
|
|
guint32 freg[4];
|
|
guint32 flvalsig;
|
|
guint32 descriptor_map0;
|
|
guint32 descriptor_map1;
|
|
guint32 descriptor_map2;
|
|
guint32 components_rcd;
|
|
guint32 illegal_jedec;
|
|
guint32 flpb;
|
|
guint32 flash_master[4];
|
|
guint32 protected_range[4];
|
|
};
|
|
|
|
#define FU_INTEL_SPI_PHYS_SPIBAR_SIZE 0x10000 /* bytes */
|
|
#define FU_INTEL_SPI_READ_TIMEOUT 10 /* ms */
|
|
|
|
#define PCI_BASE_ADDRESS_0 0x0010
|
|
|
|
#define HSFS_FDOPSS_BIT 13 /* Flash Descriptor Override Pin-Strap Status */
|
|
#define HSFS_FDV_BIT 14 /* Flash Descriptor Valid */
|
|
|
|
/**
|
|
* FU_INTEL_SPI_DEVICE_FLAG_ICH:
|
|
*
|
|
* Device is an I/O Controller Hub.
|
|
*/
|
|
#define FU_INTEL_SPI_DEVICE_FLAG_ICH (1 << 0)
|
|
/**
|
|
* FU_INTEL_SPI_DEVICE_FLAG_PCH:
|
|
*
|
|
* Device is a Platform Controller Hub.
|
|
*/
|
|
#define FU_INTEL_SPI_DEVICE_FLAG_PCH (1 << 1)
|
|
|
|
G_DEFINE_TYPE(FuIntelSpiDevice, fu_intel_spi_device, FU_TYPE_DEVICE)
|
|
|
|
static void
|
|
fu_intel_spi_device_to_string(FuDevice *device, guint idt, GString *str)
|
|
{
|
|
FuIntelSpiDevice *self = FU_INTEL_SPI_DEVICE(device);
|
|
fu_string_append(str, idt, "Kind", fu_intel_spi_kind_to_string(self->kind));
|
|
fu_string_append_kx(str, idt, "SPIBAR", self->phys_spibar);
|
|
fu_string_append_kx(str, idt, "HSFS", self->hsfs);
|
|
fu_string_append_kx(str, idt, "FRAP", self->frap);
|
|
for (guint i = 0; i < 4; i++) {
|
|
g_autofree gchar *title = g_strdup_printf("FREG%u", i);
|
|
fu_string_append_kx(str, idt, title, self->freg[i]);
|
|
}
|
|
for (guint i = 0; i < 4; i++) {
|
|
g_autofree gchar *title = g_strdup_printf("FLMSTR%u", i);
|
|
fu_string_append_kx(str, idt, title, self->flash_master[i]);
|
|
}
|
|
fu_string_append_kx(str, idt, "FLVALSIG", self->flvalsig);
|
|
fu_string_append_kx(str, idt, "FLMAP0", self->descriptor_map0);
|
|
fu_string_append_kx(str, idt, "FLMAP1", self->descriptor_map1);
|
|
fu_string_append_kx(str, idt, "FLMAP2", self->descriptor_map2);
|
|
fu_string_append_kx(str, idt, "FLCOMP", self->components_rcd);
|
|
fu_string_append_kx(str, idt, "FLILL", self->illegal_jedec);
|
|
fu_string_append_kx(str, idt, "FLPB", self->flpb);
|
|
|
|
/* PRx */
|
|
for (guint i = 0; i < 4; i++) {
|
|
guint32 limit = 0;
|
|
guint32 base = 0;
|
|
FuIfdAccess access = FU_IFD_ACCESS_NONE;
|
|
g_autofree gchar *title = NULL;
|
|
g_autofree gchar *tmp = NULL;
|
|
|
|
if (self->protected_range[i] == 0x0)
|
|
continue;
|
|
if ((self->protected_range[i] >> 31) & 0b1)
|
|
access |= FU_IFD_ACCESS_WRITE;
|
|
if ((self->protected_range[i] >> 15) & 0b1)
|
|
access |= FU_IFD_ACCESS_READ;
|
|
if (access != FU_IFD_ACCESS_NONE) {
|
|
base = ((self->protected_range[i] >> 0) & 0x1FFF) << 12;
|
|
limit = (((self->protected_range[i] >> 16) & 0x1FFF) << 12) | 0xFFFF;
|
|
}
|
|
title = g_strdup_printf("PR%u", i);
|
|
tmp = g_strdup_printf("blocked %s from 0x%x to 0x%x [0x%x]",
|
|
fu_ifd_access_to_string(access),
|
|
base,
|
|
limit,
|
|
self->protected_range[i]);
|
|
fu_string_append(str, idt, title, tmp);
|
|
}
|
|
}
|
|
|
|
static gboolean
|
|
fu_intel_spi_device_open(FuDevice *device, GError **error)
|
|
{
|
|
FuIntelSpiDevice *self = FU_INTEL_SPI_DEVICE(device);
|
|
int fd;
|
|
g_autoptr(GInputStream) istr = NULL;
|
|
|
|
/* this will fail if the kernel is locked down */
|
|
fd = open("/dev/mem", O_SYNC | O_RDWR);
|
|
if (fd == -1) {
|
|
g_set_error(error,
|
|
G_IO_ERROR,
|
|
G_IO_ERROR_FAILED,
|
|
#ifdef HAVE_ERRNO_H
|
|
"failed to open /dev/mem: %s",
|
|
strerror(errno));
|
|
#else
|
|
"failed to open /dev/mem");
|
|
#endif
|
|
return FALSE;
|
|
}
|
|
istr = g_unix_input_stream_new(fd, TRUE);
|
|
if (istr == NULL) {
|
|
g_set_error_literal(error,
|
|
G_IO_ERROR,
|
|
G_IO_ERROR_FAILED,
|
|
"failed to create input stream");
|
|
return FALSE;
|
|
}
|
|
self->spibar = mmap(NULL,
|
|
FU_INTEL_SPI_PHYS_SPIBAR_SIZE,
|
|
PROT_READ | PROT_WRITE,
|
|
MAP_SHARED,
|
|
fd,
|
|
self->phys_spibar);
|
|
if (self->spibar == MAP_FAILED) {
|
|
g_set_error(error,
|
|
G_IO_ERROR,
|
|
G_IO_ERROR_FAILED,
|
|
#ifdef HAVE_ERRNO_H
|
|
"failed to mmap SPIBAR: %s",
|
|
strerror(errno));
|
|
#else
|
|
"failed to mmap SPIBAR");
|
|
#endif
|
|
return FALSE;
|
|
}
|
|
|
|
/* success */
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
fu_intel_spi_device_close(FuDevice *device, GError **error)
|
|
{
|
|
FuIntelSpiDevice *self = FU_INTEL_SPI_DEVICE(device);
|
|
|
|
/* close */
|
|
if (self->spibar != NULL) {
|
|
if (munmap(self->spibar, FU_INTEL_SPI_PHYS_SPIBAR_SIZE) == -1) {
|
|
g_set_error(error,
|
|
G_IO_ERROR,
|
|
G_IO_ERROR_FAILED,
|
|
#ifdef HAVE_ERRNO_H
|
|
"failed to unmap SPIBAR: %s",
|
|
strerror(errno));
|
|
#else
|
|
"failed to unmap SPIBAR");
|
|
#endif
|
|
return FALSE;
|
|
}
|
|
self->spibar = NULL;
|
|
}
|
|
|
|
/* success */
|
|
return TRUE;
|
|
}
|
|
|
|
static guint32
|
|
fu_intel_spi_device_read_reg(FuIntelSpiDevice *self, guint8 section, guint16 offset)
|
|
{
|
|
guint32 control = 0;
|
|
control |= (((guint32)section) << 12) & FDOC_FDSS;
|
|
control |= (((guint32)offset) << 2) & FDOC_FDSI;
|
|
fu_mmio_write32_le(self->spibar, PCH100_REG_FDOC, control);
|
|
return fu_mmio_read32_le(self->spibar, PCH100_REG_FDOD);
|
|
}
|
|
|
|
static void
|
|
fu_intel_spi_device_add_security_attrs(FuDevice *device, FuSecurityAttrs *attrs)
|
|
{
|
|
FuIntelSpiDevice *self = FU_INTEL_SPI_DEVICE(device);
|
|
FuIfdAccess access_global = FU_IFD_ACCESS_NONE;
|
|
g_autoptr(FwupdSecurityAttr) attr = NULL;
|
|
|
|
/* create attr */
|
|
attr = fwupd_security_attr_new(FWUPD_SECURITY_ATTR_ID_SPI_DESCRIPTOR);
|
|
fwupd_security_attr_set_plugin(attr, fu_device_get_plugin(FU_DEVICE(self)));
|
|
fwupd_security_attr_set_level(attr, FWUPD_SECURITY_ATTR_LEVEL_CRITICAL);
|
|
fwupd_security_attr_add_guids(attr, fu_device_get_guids(device));
|
|
fu_security_attrs_append(attrs, attr);
|
|
|
|
/* check for read access from other regions */
|
|
for (guint j = FU_IFD_REGION_BIOS; j < 4; j++) {
|
|
FuIfdAccess access;
|
|
access =
|
|
fu_ifd_region_to_access(FU_IFD_REGION_DESC, self->flash_master[j - 1], TRUE);
|
|
fwupd_security_attr_add_metadata(attr,
|
|
fu_ifd_region_to_string(j),
|
|
fu_ifd_access_to_string(access));
|
|
access_global |= access;
|
|
}
|
|
|
|
/* any region can write to the flash descriptor */
|
|
if (access_global & FU_IFD_ACCESS_WRITE) {
|
|
fwupd_security_attr_set_result(attr, FWUPD_SECURITY_ATTR_RESULT_NOT_VALID);
|
|
fwupd_security_attr_add_flag(attr, FWUPD_SECURITY_ATTR_FLAG_ACTION_CONTACT_OEM);
|
|
return;
|
|
}
|
|
|
|
/* FLOCKDN is unset */
|
|
if ((self->hsfs >> 15 & 0b1) == 0) {
|
|
fwupd_security_attr_set_result(attr, FWUPD_SECURITY_ATTR_RESULT_NOT_LOCKED);
|
|
fwupd_security_attr_add_flag(attr, FWUPD_SECURITY_ATTR_FLAG_ACTION_CONTACT_OEM);
|
|
return;
|
|
}
|
|
|
|
/* success */
|
|
fwupd_security_attr_add_flag(attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS);
|
|
fwupd_security_attr_set_result(attr, FWUPD_SECURITY_ATTR_RESULT_LOCKED);
|
|
}
|
|
|
|
static gboolean
|
|
fu_intel_spi_device_probe(FuDevice *device, GError **error)
|
|
{
|
|
FuIntelSpiDevice *self = FU_INTEL_SPI_DEVICE(device);
|
|
|
|
/* verify this was set in the quirk file */
|
|
if (self->kind == FU_INTEL_SPI_KIND_UNKNOWN) {
|
|
g_set_error_literal(error,
|
|
G_IO_ERROR,
|
|
G_IO_ERROR_NOT_SUPPORTED,
|
|
"IntelSpiKind not set");
|
|
return FALSE;
|
|
}
|
|
|
|
/* use a hidden PCI device to get the RCBA */
|
|
if (self->spibar_proxy != NULL) {
|
|
g_autoptr(FuDevice) pcidev = NULL;
|
|
g_autoptr(FuDeviceLocker) locker = NULL;
|
|
|
|
/* get SPIBAR from a hidden (VID set to 0xFFFF) PCI device */
|
|
pcidev = fu_pci_device_new(self->spibar_proxy, error);
|
|
if (pcidev == NULL)
|
|
return FALSE;
|
|
locker = fu_device_locker_new(pcidev, error);
|
|
if (locker == NULL)
|
|
return FALSE;
|
|
self->phys_spibar =
|
|
fu_pci_device_read_config(FU_PCI_DEVICE(pcidev), PCI_BASE_ADDRESS_0);
|
|
if (self->phys_spibar == 0 || self->phys_spibar == G_MAXUINT32) {
|
|
g_set_error(error,
|
|
G_IO_ERROR,
|
|
G_IO_ERROR_NOT_SUPPORTED,
|
|
"SPIBAR not valid: 0x%x",
|
|
self->phys_spibar);
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
/* specified explicitly as a physical address */
|
|
if (self->phys_spibar == 0) {
|
|
g_set_error_literal(error,
|
|
G_IO_ERROR,
|
|
G_IO_ERROR_NOT_SUPPORTED,
|
|
"IntelSpiBar not set");
|
|
return FALSE;
|
|
}
|
|
|
|
/* success */
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
fu_intel_spi_device_setup(FuDevice *device, GError **error)
|
|
{
|
|
FuIntelSpiDevice *self = FU_INTEL_SPI_DEVICE(device);
|
|
guint64 total_size = 0;
|
|
guint8 comp1_density;
|
|
guint8 comp2_density;
|
|
gboolean me_is_locked;
|
|
guint16 reg_pr0 = fu_device_has_private_flag(device, FU_INTEL_SPI_DEVICE_FLAG_ICH)
|
|
? ICH9_REG_PR0
|
|
: PCH100_REG_FPR0;
|
|
|
|
/* dump everything */
|
|
if (g_getenv("FWUPD_INTEL_SPI_VERBOSE") != NULL) {
|
|
for (guint i = 0; i < 0xff; i += 4) {
|
|
guint32 tmp = fu_mmio_read32(self->spibar, i);
|
|
g_print("SPIBAR[0x%02x] = 0x%x\n", i, tmp);
|
|
}
|
|
}
|
|
|
|
/* read from descriptor */
|
|
self->hsfs = fu_mmio_read16(self->spibar, ICH9_REG_HSFS);
|
|
self->frap = fu_mmio_read16(self->spibar, ICH9_REG_FRAP);
|
|
for (guint i = FU_IFD_REGION_DESC; i < 4; i++)
|
|
self->freg[i] = fu_mmio_read32(self->spibar, ICH9_REG_FREG0 + i * 4);
|
|
self->flvalsig = fu_intel_spi_device_read_reg(self, 0, 0);
|
|
self->descriptor_map0 = fu_intel_spi_device_read_reg(self, 0, 1);
|
|
self->descriptor_map1 = fu_intel_spi_device_read_reg(self, 0, 2);
|
|
self->descriptor_map2 = fu_intel_spi_device_read_reg(self, 0, 3);
|
|
self->components_rcd = fu_intel_spi_device_read_reg(self, 1, 0);
|
|
self->illegal_jedec = fu_intel_spi_device_read_reg(self, 1, 1);
|
|
self->flpb = fu_intel_spi_device_read_reg(self, 1, 2);
|
|
|
|
for (guint i = 0; i < 4; i++)
|
|
self->flash_master[i] = fu_intel_spi_device_read_reg(self, 3, i);
|
|
for (guint i = 0; i < 4; i++) {
|
|
self->protected_range[i] =
|
|
fu_mmio_read32(self->spibar, reg_pr0 + i * sizeof(guint32));
|
|
}
|
|
|
|
/* set size */
|
|
comp1_density = (self->components_rcd & 0x0f) >> 0;
|
|
if (comp1_density != 0xf)
|
|
total_size += 1ull << (19 + comp1_density);
|
|
comp2_density = (self->components_rcd & 0xf0) >> 4;
|
|
if (comp2_density != 0xf)
|
|
total_size += 1ull << (19 + comp2_density);
|
|
fu_device_set_firmware_size(device, total_size);
|
|
|
|
me_is_locked = !(self->hsfs & (1 << HSFS_FDV_BIT)) || /* assume locked if not valid */
|
|
(self->hsfs & (1 << HSFS_FDOPSS_BIT)); /* use status bit if valid */
|
|
/* add children */
|
|
for (guint i = FU_IFD_REGION_BIOS; i < 4; i++) {
|
|
g_autoptr(FuDevice) child = NULL;
|
|
if (self->freg[i] == 0x0)
|
|
continue;
|
|
child = fu_ifd_device_new(fu_device_get_context(device), i, self->freg[i]);
|
|
for (guint j = 1; j < 4; j++) {
|
|
FuIfdAccess access;
|
|
access = fu_ifd_region_to_access(i, self->flash_master[j - 1], TRUE);
|
|
fu_ifd_device_set_access(FU_IFD_DEVICE(child), j, access);
|
|
}
|
|
|
|
if (i == FU_IFD_REGION_ME && me_is_locked)
|
|
fu_device_add_flag(child, FWUPD_DEVICE_FLAG_LOCKED);
|
|
|
|
fu_device_add_child(device, child);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
fu_intel_spi_device_wait(FuIntelSpiDevice *self, guint timeout_ms, GError **error)
|
|
{
|
|
g_usleep(1);
|
|
for (guint i = 0; i < timeout_ms * 100; i++) {
|
|
guint16 hsfs = fu_mmio_read16(self->spibar, ICH9_REG_HSFS);
|
|
if (hsfs & HSFS_FDONE)
|
|
return TRUE;
|
|
if (hsfs & HSFS_FCERR) {
|
|
g_set_error(error, G_IO_ERROR, G_IO_ERROR_FAILED, "HSFS transaction error");
|
|
return FALSE;
|
|
}
|
|
g_usleep(10);
|
|
}
|
|
g_set_error(error, G_IO_ERROR, G_IO_ERROR_TIMED_OUT, "HSFS timed out");
|
|
return FALSE;
|
|
}
|
|
|
|
static void
|
|
fu_intel_spi_device_set_addr(FuIntelSpiDevice *self, guint32 addr)
|
|
{
|
|
guint32 addr_old = fu_mmio_read32(self->spibar, ICH9_REG_FADDR) & ~PCH100_FADDR_FLA;
|
|
fu_mmio_write32(self->spibar, ICH9_REG_FADDR, (addr & PCH100_FADDR_FLA) | addr_old);
|
|
}
|
|
|
|
GBytes *
|
|
fu_intel_spi_device_dump(FuIntelSpiDevice *self,
|
|
FuDevice *device,
|
|
guint32 offset,
|
|
guint32 length,
|
|
FuProgress *progress,
|
|
GError **error)
|
|
{
|
|
guint8 block_len = 0x40;
|
|
g_autoptr(GByteArray) buf = g_byte_array_sized_new(length);
|
|
|
|
/* set FDONE, FCERR, AEL */
|
|
fu_progress_set_status(progress, FWUPD_STATUS_DEVICE_READ);
|
|
fu_mmio_write16(self->spibar, ICH9_REG_HSFS, fu_mmio_read16(self->spibar, ICH9_REG_HSFS));
|
|
for (guint32 addr = offset; addr < offset + length; addr += block_len) {
|
|
guint16 hsfc;
|
|
guint32 buftmp32 = 0;
|
|
|
|
/* set up read */
|
|
fu_intel_spi_device_set_addr(self, addr);
|
|
hsfc = fu_mmio_read16(self->spibar, ICH9_REG_HSFC);
|
|
hsfc &= ~PCH100_HSFC_FCYCLE;
|
|
hsfc &= ~HSFC_FDBC;
|
|
|
|
/* set byte count */
|
|
hsfc |= ((block_len - 1) << 8) & HSFC_FDBC;
|
|
hsfc |= HSFC_FGO;
|
|
fu_mmio_write16(self->spibar, ICH9_REG_HSFC, hsfc);
|
|
if (!fu_intel_spi_device_wait(self, FU_INTEL_SPI_READ_TIMEOUT, error)) {
|
|
g_prefix_error(error, "failed @0x%x: ", addr);
|
|
return NULL;
|
|
}
|
|
|
|
/* copy out data */
|
|
for (guint i = 0; i < block_len; i++) {
|
|
if (i % 4 == 0)
|
|
buftmp32 = fu_mmio_read32(self->spibar, ICH9_REG_FDATA0 + i);
|
|
fu_byte_array_append_uint8(buf, buftmp32 >> ((i % 4) * 8));
|
|
}
|
|
|
|
/* progress */
|
|
fu_progress_set_percentage_full(progress, addr - offset + block_len, length);
|
|
}
|
|
|
|
/* success */
|
|
return g_byte_array_free_to_bytes(g_steal_pointer(&buf));
|
|
}
|
|
|
|
static GBytes *
|
|
fu_intel_spi_device_dump_firmware2(FuDevice *device, FuProgress *progress, GError **error)
|
|
{
|
|
FuIntelSpiDevice *self = FU_INTEL_SPI_DEVICE(device);
|
|
guint64 total_size = fu_device_get_firmware_size_max(device);
|
|
return fu_intel_spi_device_dump(self, device, 0x0, total_size, progress, error);
|
|
}
|
|
|
|
static GBytes *
|
|
fu_intel_spi_device_dump_firmware(FuDevice *device, FuProgress *progress, GError **error)
|
|
{
|
|
return fu_intel_spi_device_dump_firmware2(device, progress, error);
|
|
}
|
|
|
|
static FuFirmware *
|
|
fu_intel_spi_device_read_firmware(FuDevice *device, FuProgress *progress, GError **error)
|
|
{
|
|
g_autoptr(FuFirmware) firmware = fu_ifd_firmware_new();
|
|
g_autoptr(GBytes) blob = NULL;
|
|
|
|
blob = fu_intel_spi_device_dump_firmware2(device, progress, error);
|
|
if (blob == NULL)
|
|
return NULL;
|
|
if (!fu_firmware_parse(firmware, blob, FWUPD_INSTALL_FLAG_NONE, error))
|
|
return NULL;
|
|
return g_steal_pointer(&firmware);
|
|
}
|
|
|
|
static gboolean
|
|
fu_intel_spi_device_set_quirk_kv(FuDevice *device,
|
|
const gchar *key,
|
|
const gchar *value,
|
|
GError **error)
|
|
{
|
|
FuIntelSpiDevice *self = FU_INTEL_SPI_DEVICE(device);
|
|
if (g_strcmp0(key, "IntelSpiBar") == 0) {
|
|
guint64 tmp = 0;
|
|
if (!fu_strtoull(value, &tmp, 0, G_MAXUINT32, error))
|
|
return FALSE;
|
|
self->phys_spibar = tmp;
|
|
return TRUE;
|
|
}
|
|
if (g_strcmp0(key, "IntelSpiKind") == 0) {
|
|
/* validate */
|
|
self->kind = fu_intel_spi_kind_from_string(value);
|
|
if (self->kind == FU_INTEL_SPI_KIND_UNKNOWN) {
|
|
g_set_error(error,
|
|
G_IO_ERROR,
|
|
G_IO_ERROR_NOT_SUPPORTED,
|
|
"%s not supported",
|
|
value);
|
|
return FALSE;
|
|
}
|
|
|
|
/* get things like SPIBAR */
|
|
fu_device_add_instance_strup(device, "ID", value);
|
|
return fu_device_build_instance_id(device, error, "INTEL_SPI_CHIPSET", "ID", NULL);
|
|
}
|
|
if (g_strcmp0(key, "IntelSpiBarProxy") == 0) {
|
|
self->spibar_proxy = g_strdup(value);
|
|
return TRUE;
|
|
}
|
|
g_set_error_literal(error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, "no supported");
|
|
return FALSE;
|
|
}
|
|
|
|
static void
|
|
fu_intel_spi_device_finalize(GObject *object)
|
|
{
|
|
FuIntelSpiDevice *self = FU_INTEL_SPI_DEVICE(object);
|
|
g_free(self->spibar_proxy);
|
|
G_OBJECT_CLASS(fu_intel_spi_device_parent_class)->finalize(object);
|
|
}
|
|
|
|
static void
|
|
fu_intel_spi_device_init(FuIntelSpiDevice *self)
|
|
{
|
|
fu_device_add_flag(FU_DEVICE(self), FWUPD_DEVICE_FLAG_INTERNAL);
|
|
fu_device_add_flag(FU_DEVICE(self), FWUPD_DEVICE_FLAG_CAN_VERIFY_IMAGE);
|
|
fu_device_add_icon(FU_DEVICE(self), "computer");
|
|
fu_device_set_physical_id(FU_DEVICE(self), "intel_spi");
|
|
fu_device_register_private_flag(FU_DEVICE(self), FU_INTEL_SPI_DEVICE_FLAG_ICH, "ich");
|
|
fu_device_register_private_flag(FU_DEVICE(self), FU_INTEL_SPI_DEVICE_FLAG_PCH, "pch");
|
|
}
|
|
|
|
static void
|
|
fu_intel_spi_device_class_init(FuIntelSpiDeviceClass *klass)
|
|
{
|
|
GObjectClass *object_class = G_OBJECT_CLASS(klass);
|
|
FuDeviceClass *klass_device = FU_DEVICE_CLASS(klass);
|
|
object_class->finalize = fu_intel_spi_device_finalize;
|
|
klass_device->to_string = fu_intel_spi_device_to_string;
|
|
klass_device->probe = fu_intel_spi_device_probe;
|
|
klass_device->setup = fu_intel_spi_device_setup;
|
|
klass_device->dump_firmware = fu_intel_spi_device_dump_firmware;
|
|
klass_device->read_firmware = fu_intel_spi_device_read_firmware;
|
|
klass_device->open = fu_intel_spi_device_open;
|
|
klass_device->close = fu_intel_spi_device_close;
|
|
klass_device->set_quirk_kv = fu_intel_spi_device_set_quirk_kv;
|
|
klass_device->add_security_attrs = fu_intel_spi_device_add_security_attrs;
|
|
}
|