fwupd/plugins/udev/fu-plugin-udev.c
Richard Hughes ff704414f6 Use superclassed versions of FuDevice when calling udev_added() and usb_added()
The daemon creates a baseclass of either FuUsbDevice or FuUdevDevice when the
devices are added or coldplugged to match the quirk database and to find out
what plugin to run.

This is proxied to plugins, but they are given the GUsbDevice or GUdevDevice and
the FuDevice is just thrown away. Most plugins either use a FuUsbDevice or
superclassed version like FuNvmeDevice and so we re-create the FuDevice, re-probe
the hardware, re-query the quirk database and then return this to the daemon.

In some cases, plugins actually probe the hardware three times (!) by creating
a FuUsbDevice to get the quirks, so that the plugin knows what kind of
superclass to create, which then itself probes the hardware again.

Passing the temporary FuDevice to the plugins means that the simplest ones can
just fu_plugin_device_add() the passed in object, or create a superclass and
incorporate the actual GUsbDevice and all the GUIDs.

This breaks internal plugin API but speeds up startup substantially and deletes
a lot of code.
2018-09-04 08:22:39 -05:00

102 lines
2.8 KiB
C

/*
* Copyright (C) 2015-2016 Richard Hughes <richard@hughsie.com>
*
* SPDX-License-Identifier: LGPL-2.1+
*/
#include "config.h"
#include <appstream-glib.h>
#include "fu-plugin.h"
#include "fu-rom.h"
#include "fu-plugin-vfuncs.h"
void
fu_plugin_init (FuPlugin *plugin)
{
fu_plugin_add_udev_subsystem (plugin, "pci");
}
gboolean
fu_plugin_verify (FuPlugin *plugin,
FuDevice *device,
FuPluginVerifyFlags flags,
GError **error)
{
GPtrArray *checksums;
const gchar *rom_fn;
g_autoptr(GFile) file = NULL;
g_autoptr(FuRom) rom = NULL;
/* open the file */
rom_fn = fu_device_get_metadata (device, "RomFilename");
if (rom_fn == NULL) {
g_set_error_literal (error,
FWUPD_ERROR,
FWUPD_ERROR_INTERNAL,
"Unable to read firmware from device");
return FALSE;
}
file = g_file_new_for_path (rom_fn);
rom = fu_rom_new ();
if (!fu_rom_load_file (rom, file, FU_ROM_LOAD_FLAG_BLANK_PPID, NULL, error))
return FALSE;
/* update version */
if (g_strcmp0 (fu_device_get_version (device),
fu_rom_get_version (rom)) != 0) {
g_debug ("changing version of %s from %s to %s",
fu_device_get_platform_id (device),
fu_device_get_version (device),
fu_rom_get_version (rom));
fu_device_set_version (device, fu_rom_get_version (rom));
}
/* Also add the GUID from the firmware as the firmware may be more
* generic, which also allows us to match the GUID when doing 'verify'
* on a device with a different PID to the firmware */
fu_device_add_guid (device, fu_rom_get_guid (rom));
/* update checksums */
checksums = fu_rom_get_checksums (rom);
for (guint i = 0; i < checksums->len; i++) {
const gchar *checksum = g_ptr_array_index (checksums, i);
fu_device_add_checksum (device, checksum);
}
return TRUE;
}
gboolean
fu_plugin_udev_device_added (FuPlugin *plugin, FuUdevDevice *device, GError **error)
{
const gchar *guid = NULL;
g_autofree gchar *rom_fn = NULL;
g_autoptr(AsProfile) profile = as_profile_new ();
g_autoptr(AsProfileTask) ptask = NULL;
/* interesting device? */
if (g_strcmp0 (fu_udev_device_get_subsystem (device), "pci") != 0)
return TRUE;
guid = g_udev_device_get_property (fu_udev_device_get_dev (device), "FWUPD_GUID");
if (guid == NULL)
return TRUE;
/* get data */
ptask = as_profile_start (profile, "FuPluginUdev:client-add{%s}", guid);
g_assert (ptask != NULL);
/* did we get enough data */
fu_device_add_flag (device, FWUPD_DEVICE_FLAG_INTERNAL);
fu_device_add_icon (device, "audio-card");
/* get the FW version from the rom when unlocked */
rom_fn = g_build_filename (fu_device_get_platform_id (FU_DEVICE (device)), "rom", NULL);
if (g_file_test (rom_fn, G_FILE_TEST_EXISTS))
fu_device_set_metadata (FU_DEVICE (device), "RomFilename", rom_fn);
/* insert to hash */
fu_plugin_device_add_delay (plugin, FU_DEVICE (device));
return TRUE;
}