1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
|
/*
* Copyright 2022 Richard Hughes <richard@hughsie.com>
* Copyright 2022 Google LLC
* Written by Simon Glass <sjg@chromium.org>
*
* SPDX-License-Identifier: LGPL-2.1-or-later
*/
#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_literal(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_literal(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_constructed(GObject *obj)
{
FuPlugin *plugin = FU_PLUGIN(obj);
fu_plugin_add_device_gtype(plugin, FU_TYPE_VBE_SIMPLE_DEVICE); /* coverage */
}
static void
fu_vbe_plugin_class_init(FuVbePluginClass *klass)
{
FuPluginClass *plugin_class = FU_PLUGIN_CLASS(klass);
plugin_class->constructed = fu_vbe_plugin_constructed;
plugin_class->coldplug = fu_vbe_plugin_coldplug;
}
|