fwupd/plugins/vbe/fu-vbe-plugin.c
Richard Hughes cf4f34572b Add fu_context_get_fdt() to get the Flat Device Tree
This is needed because multiple plugins will soon be consuming the system FDT,
and we don't want to either parse this multiple times, or duplicate the loading
logic.
2023-01-11 16:25:26 +00:00

138 lines
3.3 KiB
C

/*
* Copyright (C) 2022 Richard Hughes <richard@hughsie.com>
* Copyright (C) 2022 Google LLC
* Written by Simon Glass <sjg@chromium.org>
*
* SPDX-License-Identifier: LGPL-2.1+
*/
#include "config.h"
#include "fu-vbe-plugin.h"
#include "fu-vbe-simple-device.h"
struct _FuVbePlugin {
FuPlugin parent_instance;
};
G_DEFINE_TYPE(FuVbePlugin, fu_vbe_plugin, FU_TYPE_PLUGIN)
static gboolean
fu_vbe_plugin_coldplug_img(FuPlugin *plugin,
FuFdtImage *fdt_root,
FuFdtImage *fdt_node,
GError **error)
{
GType device_gtype = G_TYPE_INVALID;
g_autofree gchar *compatible = NULL;
g_auto(GStrv) split = NULL;
g_autoptr(FuDevice) dev = NULL;
/* we expect 'fwupd,vbe-<driver>' */
if (!fu_fdt_image_get_attr_str(fdt_node,
FU_FIT_FIRMWARE_ATTR_COMPATIBLE,
&compatible,
error)) {
g_prefix_error(error, "missing update mechanism: ");
return FALSE;
}
split = g_strsplit(compatible, ",", 2);
if (g_strv_length(split) != 2) {
g_set_error(error,
FWUPD_ERROR,
FWUPD_ERROR_INVALID_FILE,
"update mechanism is invalid: %s",
compatible);
return FALSE;
}
if (g_strcmp0(split[0], "fwupd") != 0) {
g_set_error(error,
FWUPD_ERROR,
FWUPD_ERROR_INVALID_FILE,
"update mechanism should have manufacturer of fwupd: %s",
split[0]);
return FALSE;
}
/* skip past 'vbe-' */
if (!g_str_has_prefix(split[1], "vbe-")) {
g_set_error(error,
FWUPD_ERROR,
FWUPD_ERROR_INVALID_FILE,
"update mechanism is missing vbe prefix: %s",
split[1]);
return FALSE;
}
if (g_strcmp0(split[1], "vbe-simple") == 0) {
device_gtype = FU_TYPE_VBE_SIMPLE_DEVICE;
} else {
g_set_error(error,
FWUPD_ERROR,
FWUPD_ERROR_INVALID_FILE,
"no driver for VBE method '%s'",
split[1]);
return FALSE;
}
/* success */
dev = g_object_new(device_gtype,
"context",
fu_plugin_get_context(plugin),
"fdt-root",
fdt_root,
"fdt-node",
fdt_node,
NULL);
fu_plugin_device_add(plugin, dev);
return TRUE;
}
static gboolean
fu_vbe_plugin_coldplug(FuPlugin *plugin, FuProgress *progress, GError **error)
{
g_autoptr(FuFirmware) fdt = NULL;
g_autoptr(FuFdtImage) fdt_root = NULL;
g_autoptr(GPtrArray) fdt_imgs = NULL;
/* get compatible from root node */
fdt = fu_context_get_fdt(fu_plugin_get_context(plugin), error);
if (fdt == NULL)
return FALSE;
fdt_root = fu_fdt_firmware_get_image_by_path(FU_FDT_FIRMWARE(fdt), "/chosen/fwupd", error);
if (fdt_root == NULL)
return FALSE;
fdt_imgs = fu_firmware_get_images(FU_FIRMWARE(fdt_root));
for (guint i = 0; i < fdt_imgs->len; i++) {
FuFdtImage *fdt_node = g_ptr_array_index(fdt_imgs, i);
g_autoptr(GError) error_local = NULL;
if (!fu_vbe_plugin_coldplug_img(plugin, fdt_root, fdt_node, &error_local)) {
g_warning("%s", error_local->message);
continue;
}
}
/* nothing found? */
if (fu_plugin_get_devices(plugin)->len == 0) {
g_set_error(error,
FWUPD_ERROR,
FWUPD_ERROR_NOT_SUPPORTED,
"no valid VBE update mechanism found");
return FALSE;
}
/* success */
return TRUE;
}
static void
fu_vbe_plugin_init(FuVbePlugin *self)
{
}
static void
fu_vbe_plugin_class_init(FuVbePluginClass *klass)
{
FuPluginClass *plugin_class = FU_PLUGIN_CLASS(klass);
plugin_class->coldplug = fu_vbe_plugin_coldplug;
}