blob: 29dc02c0aa67a7dd4850f095fea3c0bc38dcc670 [file] [log] [blame]
Richard Hughes02c90d82018-08-09 12:13:03 +01001/*
Richard Hughes2de8f132018-01-17 09:12:02 +00002 * Copyright (C) 2016-2018 Richard Hughes <richard@hughsie.com>
Richard Hughesd0905142016-03-13 09:46:49 +00003 *
Mario Limonciello51308e62018-05-28 20:05:46 -05004 * SPDX-License-Identifier: LGPL-2.1+
Richard Hughesd0905142016-03-13 09:46:49 +00005 */
6
Richard Hughesb08e7bc2018-09-11 10:51:13 +01007#define G_LOG_DOMAIN "FuPlugin"
8
Richard Hughesd0905142016-03-13 09:46:49 +00009#include "config.h"
10
Richard Hughescff38bc2016-12-12 12:03:37 +000011#include <fwupd.h>
12#include <gmodule.h>
Richard Hughescff38bc2016-12-12 12:03:37 +000013#include <errno.h>
14#include <string.h>
Richard Hughes68f12dd2018-08-09 14:43:31 +010015#include <unistd.h>
Mario Limonciello6d0aa3d2017-02-28 08:22:27 -060016#ifdef HAVE_VALGRIND
Richard Hughes576c0122017-02-24 09:47:00 +000017#include <valgrind.h>
Mario Limonciello6d0aa3d2017-02-28 08:22:27 -060018#endif /* HAVE_VALGRIND */
Richard Hughesd0905142016-03-13 09:46:49 +000019
Richard Hughes9dde04f2017-09-13 12:07:15 +010020#include "fu-device-private.h"
Richard Hughescff38bc2016-12-12 12:03:37 +000021#include "fu-plugin-private.h"
Richard Hughes37d09432018-09-09 10:39:45 +010022#include "fu-mutex.h"
Richard Hughesd0905142016-03-13 09:46:49 +000023
Richard Hughes4eada342017-10-03 21:20:32 +010024/**
25 * SECTION:fu-plugin
26 * @short_description: a daemon plugin
27 *
28 * An object that represents a plugin run by the daemon.
29 *
30 * See also: #FuDevice
31 */
32
Richard Hughesb0829032017-01-10 09:27:08 +000033#define FU_PLUGIN_COLDPLUG_DELAY_MAXIMUM 3000u /* ms */
34
Richard Hughescff38bc2016-12-12 12:03:37 +000035static void fu_plugin_finalize (GObject *object);
36
37typedef struct {
38 GModule *module;
39 GUsbContext *usb_ctx;
40 gboolean enabled;
Richard Hughes08a37992017-09-12 12:57:43 +010041 guint order;
Richard Hughes81c427c2018-08-06 15:20:17 +010042 guint priority;
Richard Hughes08a37992017-09-12 12:57:43 +010043 GPtrArray *rules[FU_PLUGIN_RULE_LAST];
Richard Hughescff38bc2016-12-12 12:03:37 +000044 gchar *name;
Richard Hughesf425d292019-01-18 17:57:39 +000045 gchar *build_hash;
Richard Hughesd7704d42017-08-08 20:29:09 +010046 FuHwids *hwids;
Richard Hughes9c028f02017-10-28 21:14:28 +010047 FuQuirks *quirks;
Richard Hughes0eb123b2018-04-19 12:00:04 +010048 GHashTable *runtime_versions;
Richard Hughes34e0dab2018-04-20 16:43:00 +010049 GHashTable *compile_versions;
Richard Hughes9d6e0e72018-08-24 20:20:17 +010050 GPtrArray *udev_subsystems;
Richard Hughes1354ea92017-09-19 15:58:31 +010051 FuSmbios *smbios;
Richard Hughes989acf12019-10-05 20:16:47 +010052 GType device_gtype;
Richard Hughescff38bc2016-12-12 12:03:37 +000053 GHashTable *devices; /* platform_id:GObject */
Richard Hughes161e9b52019-06-12 14:22:45 +010054 GRWLock devices_mutex;
Richard Hughes80b79bb2018-01-11 21:11:06 +000055 GHashTable *report_metadata; /* key:value */
Richard Hughescff38bc2016-12-12 12:03:37 +000056 FuPluginData *data;
57} FuPluginPrivate;
58
59enum {
60 SIGNAL_DEVICE_ADDED,
61 SIGNAL_DEVICE_REMOVED,
Richard Hughese1fd34d2017-08-24 14:19:51 +010062 SIGNAL_DEVICE_REGISTER,
Richard Hughes75b965d2018-11-15 13:51:21 +000063 SIGNAL_RULES_CHANGED,
Richard Hughes362d6d72017-01-07 21:42:14 +000064 SIGNAL_RECOLDPLUG,
Richard Hughesb0829032017-01-10 09:27:08 +000065 SIGNAL_SET_COLDPLUG_DELAY,
Richard Hughesaabdc372018-11-14 10:11:08 +000066 SIGNAL_CHECK_SUPPORTED,
Richard Hughes95c98a92019-10-22 16:03:15 +010067 SIGNAL_ADD_FIRMWARE_GTYPE,
Richard Hughescff38bc2016-12-12 12:03:37 +000068 SIGNAL_LAST
69};
70
71static guint signals[SIGNAL_LAST] = { 0 };
72
73G_DEFINE_TYPE_WITH_PRIVATE (FuPlugin, fu_plugin, G_TYPE_OBJECT)
74#define GET_PRIVATE(o) (fu_plugin_get_instance_private (o))
75
76typedef const gchar *(*FuPluginGetNameFunc) (void);
Richard Hughes12724852018-09-04 13:53:44 +010077typedef void (*FuPluginInitFunc) (FuPlugin *self);
78typedef gboolean (*FuPluginStartupFunc) (FuPlugin *self,
Richard Hughescff38bc2016-12-12 12:03:37 +000079 GError **error);
Richard Hughes12724852018-09-04 13:53:44 +010080typedef void (*FuPluginDeviceRegisterFunc) (FuPlugin *self,
Richard Hughese1fd34d2017-08-24 14:19:51 +010081 FuDevice *device);
Richard Hughes12724852018-09-04 13:53:44 +010082typedef gboolean (*FuPluginDeviceFunc) (FuPlugin *self,
Richard Hughescff38bc2016-12-12 12:03:37 +000083 FuDevice *device,
84 GError **error);
Richard Hughes12724852018-09-04 13:53:44 +010085typedef gboolean (*FuPluginFlaggedDeviceFunc) (FuPlugin *self,
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -050086 FwupdInstallFlags flags,
87 FuDevice *device,
88 GError **error);
Richard Hughes12724852018-09-04 13:53:44 +010089typedef gboolean (*FuPluginDeviceArrayFunc) (FuPlugin *self,
Richard Hughesdbd8c762018-06-15 20:31:40 +010090 GPtrArray *devices,
91 GError **error);
Richard Hughes12724852018-09-04 13:53:44 +010092typedef gboolean (*FuPluginVerifyFunc) (FuPlugin *self,
Richard Hughescff38bc2016-12-12 12:03:37 +000093 FuDevice *device,
94 FuPluginVerifyFlags flags,
95 GError **error);
Richard Hughes12724852018-09-04 13:53:44 +010096typedef gboolean (*FuPluginUpdateFunc) (FuPlugin *self,
Richard Hughescff38bc2016-12-12 12:03:37 +000097 FuDevice *device,
98 GBytes *blob_fw,
99 FwupdInstallFlags flags,
100 GError **error);
Richard Hughes12724852018-09-04 13:53:44 +0100101typedef gboolean (*FuPluginUsbDeviceAddedFunc) (FuPlugin *self,
Richard Hughesff704412018-09-04 11:28:32 +0100102 FuUsbDevice *device,
Richard Hughes104f6512017-11-24 11:44:57 +0000103 GError **error);
Richard Hughes12724852018-09-04 13:53:44 +0100104typedef gboolean (*FuPluginUdevDeviceAddedFunc) (FuPlugin *self,
Richard Hughesff704412018-09-04 11:28:32 +0100105 FuUdevDevice *device,
Richard Hughes9d6e0e72018-08-24 20:20:17 +0100106 GError **error);
Richard Hughescff38bc2016-12-12 12:03:37 +0000107
Richard Hughes57d18222017-01-10 16:02:59 +0000108/**
Mario Limonciello52e75ba2019-11-22 13:21:19 -0600109 * fu_plugin_is_open:
110 * @self: A #FuPlugin
111 *
112 * Determines if the plugin is opened
113 *
114 * Returns: TRUE for opened, FALSE for not
115 *
116 * Since: 1.3.5
117 **/
118gboolean
119fu_plugin_is_open (FuPlugin *self)
120{
121 FuPluginPrivate *priv = GET_PRIVATE (self);
122 return priv->module != NULL;
123}
124
125/**
Richard Hughes57d18222017-01-10 16:02:59 +0000126 * fu_plugin_get_name:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100127 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000128 *
129 * Gets the plugin name.
130 *
131 * Returns: a plugin name, or %NULL for unknown.
132 *
133 * Since: 0.8.0
134 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000135const gchar *
Richard Hughes12724852018-09-04 13:53:44 +0100136fu_plugin_get_name (FuPlugin *self)
Richard Hughesd0905142016-03-13 09:46:49 +0000137{
Richard Hughes12724852018-09-04 13:53:44 +0100138 FuPluginPrivate *priv = GET_PRIVATE (self);
139 g_return_val_if_fail (FU_IS_PLUGIN (self), NULL);
Richard Hughescff38bc2016-12-12 12:03:37 +0000140 return priv->name;
141}
Richard Hughesd0905142016-03-13 09:46:49 +0000142
Mario Limonciello1a680f32019-11-25 19:44:53 -0600143/**
144 * fu_plugin_set_name:
145 * @self: A #FuPlugin
146 * @name: A string
147 *
148 * Sets the plugin name.
149 *
150 * Since: 0.8.0
151 **/
Richard Hughes34834102017-11-21 21:55:00 +0000152void
Richard Hughes12724852018-09-04 13:53:44 +0100153fu_plugin_set_name (FuPlugin *self, const gchar *name)
Richard Hughes34834102017-11-21 21:55:00 +0000154{
Richard Hughes12724852018-09-04 13:53:44 +0100155 FuPluginPrivate *priv = GET_PRIVATE (self);
156 g_return_if_fail (FU_IS_PLUGIN (self));
Richard Hughes34834102017-11-21 21:55:00 +0000157 g_return_if_fail (name != NULL);
158 g_free (priv->name);
159 priv->name = g_strdup (name);
160}
161
Richard Hughes57d18222017-01-10 16:02:59 +0000162/**
Richard Hughesf425d292019-01-18 17:57:39 +0000163 * fu_plugin_set_build_hash:
164 * @self: A #FuPlugin
165 * @build_hash: A checksum
166 *
167 * Sets the plugin build hash, typically a SHA256 checksum. All plugins must
168 * set the correct checksum to avoid the daemon being marked as tainted.
169 *
170 * Since: 1.2.4
171 **/
172void
173fu_plugin_set_build_hash (FuPlugin *self, const gchar *build_hash)
174{
175 FuPluginPrivate *priv = GET_PRIVATE (self);
176 g_return_if_fail (FU_IS_PLUGIN (self));
177 g_return_if_fail (build_hash != NULL);
178 g_free (priv->build_hash);
179 priv->build_hash = g_strdup (build_hash);
180}
181
Mario Limonciello1a680f32019-11-25 19:44:53 -0600182/**
183 * fu_plugin_get_build_hash:
184 * @self: A #FuPlugin
185 *
186 * Gets the build hash a plugin was generated with.
187 *
188 * Returns: (transfer none): a #gchar, or %NULL for unset.
189 *
190 * Since: 1.2.4
191 **/
Richard Hughesf425d292019-01-18 17:57:39 +0000192const gchar *
193fu_plugin_get_build_hash (FuPlugin *self)
194{
195 FuPluginPrivate *priv = GET_PRIVATE (self);
196 g_return_val_if_fail (FU_IS_PLUGIN (self), NULL);
197 return priv->build_hash;
198}
199
200/**
Richard Hughes57d18222017-01-10 16:02:59 +0000201 * fu_plugin_cache_lookup:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100202 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000203 * @id: the key
204 *
205 * Finds an object in the per-plugin cache.
206 *
207 * Returns: (transfer none): a #GObject, or %NULL for unfound.
208 *
209 * Since: 0.8.0
210 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000211gpointer
Richard Hughes12724852018-09-04 13:53:44 +0100212fu_plugin_cache_lookup (FuPlugin *self, const gchar *id)
Richard Hughescff38bc2016-12-12 12:03:37 +0000213{
Richard Hughes12724852018-09-04 13:53:44 +0100214 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes161e9b52019-06-12 14:22:45 +0100215 g_autoptr(GRWLockReaderLocker) locker = g_rw_lock_reader_locker_new (&priv->devices_mutex);
Richard Hughes12724852018-09-04 13:53:44 +0100216 g_return_val_if_fail (FU_IS_PLUGIN (self), NULL);
Richard Hughesccd78a92017-01-11 16:57:41 +0000217 g_return_val_if_fail (id != NULL, NULL);
Richard Hughes37d09432018-09-09 10:39:45 +0100218 g_return_val_if_fail (locker != NULL, NULL);
Richard Hughescff38bc2016-12-12 12:03:37 +0000219 return g_hash_table_lookup (priv->devices, id);
220}
Richard Hughesd0905142016-03-13 09:46:49 +0000221
Richard Hughes57d18222017-01-10 16:02:59 +0000222/**
223 * fu_plugin_cache_add:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100224 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000225 * @id: the key
226 * @dev: a #GObject, typically a #FuDevice
227 *
228 * Adds an object to the per-plugin cache.
229 *
230 * Since: 0.8.0
231 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000232void
Richard Hughes12724852018-09-04 13:53:44 +0100233fu_plugin_cache_add (FuPlugin *self, const gchar *id, gpointer dev)
Richard Hughescff38bc2016-12-12 12:03:37 +0000234{
Richard Hughes12724852018-09-04 13:53:44 +0100235 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes0fe49142019-11-22 16:56:38 +0000236 g_autoptr(GRWLockWriterLocker) locker = g_rw_lock_writer_locker_new (&priv->devices_mutex);
Richard Hughes12724852018-09-04 13:53:44 +0100237 g_return_if_fail (FU_IS_PLUGIN (self));
Richard Hughesccd78a92017-01-11 16:57:41 +0000238 g_return_if_fail (id != NULL);
Richard Hughes37d09432018-09-09 10:39:45 +0100239 g_return_if_fail (locker != NULL);
Richard Hughescff38bc2016-12-12 12:03:37 +0000240 g_hash_table_insert (priv->devices, g_strdup (id), g_object_ref (dev));
241}
242
Richard Hughes57d18222017-01-10 16:02:59 +0000243/**
244 * fu_plugin_cache_remove:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100245 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000246 * @id: the key
247 *
248 * Removes an object from the per-plugin cache.
249 *
250 * Since: 0.8.0
251 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000252void
Richard Hughes12724852018-09-04 13:53:44 +0100253fu_plugin_cache_remove (FuPlugin *self, const gchar *id)
Richard Hughescff38bc2016-12-12 12:03:37 +0000254{
Richard Hughes12724852018-09-04 13:53:44 +0100255 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes0fe49142019-11-22 16:56:38 +0000256 g_autoptr(GRWLockWriterLocker) locker = g_rw_lock_writer_locker_new (&priv->devices_mutex);
Richard Hughes12724852018-09-04 13:53:44 +0100257 g_return_if_fail (FU_IS_PLUGIN (self));
Richard Hughesccd78a92017-01-11 16:57:41 +0000258 g_return_if_fail (id != NULL);
Richard Hughes37d09432018-09-09 10:39:45 +0100259 g_return_if_fail (locker != NULL);
Richard Hughescff38bc2016-12-12 12:03:37 +0000260 g_hash_table_remove (priv->devices, id);
261}
262
Richard Hughes57d18222017-01-10 16:02:59 +0000263/**
264 * fu_plugin_get_data:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100265 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000266 *
Richard Hughes4eada342017-10-03 21:20:32 +0100267 * Gets the per-plugin allocated private data. This will return %NULL unless
268 * fu_plugin_alloc_data() has been called by the plugin.
Richard Hughes57d18222017-01-10 16:02:59 +0000269 *
Richard Hughes4eada342017-10-03 21:20:32 +0100270 * Returns: (transfer none): a pointer to a structure, or %NULL for unset.
Richard Hughes57d18222017-01-10 16:02:59 +0000271 *
272 * Since: 0.8.0
273 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000274FuPluginData *
Richard Hughes12724852018-09-04 13:53:44 +0100275fu_plugin_get_data (FuPlugin *self)
Richard Hughescff38bc2016-12-12 12:03:37 +0000276{
Richard Hughes12724852018-09-04 13:53:44 +0100277 FuPluginPrivate *priv = GET_PRIVATE (self);
278 g_return_val_if_fail (FU_IS_PLUGIN (self), NULL);
Richard Hughescff38bc2016-12-12 12:03:37 +0000279 return priv->data;
280}
281
Richard Hughes57d18222017-01-10 16:02:59 +0000282/**
Richard Hughes00f66f62019-11-27 11:42:53 +0000283 * fu_plugin_alloc_data: (skip):
Richard Hughes2c0635a2018-09-04 14:52:46 +0100284 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000285 * @data_sz: the size to allocate
286 *
287 * Allocates the per-plugin allocated private data.
288 *
289 * Returns: (transfer full): a pointer to a structure, or %NULL for unset.
290 *
291 * Since: 0.8.0
292 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000293FuPluginData *
Richard Hughes12724852018-09-04 13:53:44 +0100294fu_plugin_alloc_data (FuPlugin *self, gsize data_sz)
Richard Hughescff38bc2016-12-12 12:03:37 +0000295{
Richard Hughes12724852018-09-04 13:53:44 +0100296 FuPluginPrivate *priv = GET_PRIVATE (self);
297 g_return_val_if_fail (FU_IS_PLUGIN (self), NULL);
Richard Hughes44dee882017-01-11 08:31:10 +0000298 if (priv->data != NULL) {
299 g_critical ("fu_plugin_alloc_data() already used by plugin");
300 return priv->data;
301 }
Richard Hughescff38bc2016-12-12 12:03:37 +0000302 priv->data = g_malloc0 (data_sz);
303 return priv->data;
Richard Hughesd0905142016-03-13 09:46:49 +0000304}
305
Richard Hughes57d18222017-01-10 16:02:59 +0000306/**
307 * fu_plugin_get_usb_context:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100308 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000309 *
310 * Gets the shared USB context that all plugins can use.
311 *
312 * Returns: (transfer none): a #GUsbContext.
313 *
314 * Since: 0.8.0
315 **/
Richard Hughesbc93e4a2016-12-08 17:29:51 +0000316GUsbContext *
Richard Hughes12724852018-09-04 13:53:44 +0100317fu_plugin_get_usb_context (FuPlugin *self)
Richard Hughesbc93e4a2016-12-08 17:29:51 +0000318{
Richard Hughes12724852018-09-04 13:53:44 +0100319 FuPluginPrivate *priv = GET_PRIVATE (self);
320 g_return_val_if_fail (FU_IS_PLUGIN (self), NULL);
Richard Hughescff38bc2016-12-12 12:03:37 +0000321 return priv->usb_ctx;
Richard Hughesbc93e4a2016-12-08 17:29:51 +0000322}
323
Mario Limonciello1a680f32019-11-25 19:44:53 -0600324/**
325 * fu_plugin_set_usb_context:
326 * @self: A #FuPlugin
327 * @usb_ctx: A #FGUsbContext
328 *
329 * Sets the shared USB context for a plugin
330 *
331 * Since: 0.8.0
332 **/
Richard Hughesbc93e4a2016-12-08 17:29:51 +0000333void
Richard Hughes12724852018-09-04 13:53:44 +0100334fu_plugin_set_usb_context (FuPlugin *self, GUsbContext *usb_ctx)
Richard Hughesbc93e4a2016-12-08 17:29:51 +0000335{
Richard Hughes12724852018-09-04 13:53:44 +0100336 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughescff38bc2016-12-12 12:03:37 +0000337 g_set_object (&priv->usb_ctx, usb_ctx);
338}
339
Richard Hughes57d18222017-01-10 16:02:59 +0000340/**
341 * fu_plugin_get_enabled:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100342 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000343 *
Richard Hughes4eada342017-10-03 21:20:32 +0100344 * Returns if the plugin is enabled. Plugins may self-disable using
345 * fu_plugin_set_enabled() or can be disabled by the daemon.
Richard Hughes57d18222017-01-10 16:02:59 +0000346 *
347 * Returns: %TRUE if the plugin is currently enabled.
348 *
349 * Since: 0.8.0
350 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000351gboolean
Richard Hughes12724852018-09-04 13:53:44 +0100352fu_plugin_get_enabled (FuPlugin *self)
Richard Hughescff38bc2016-12-12 12:03:37 +0000353{
Richard Hughes12724852018-09-04 13:53:44 +0100354 FuPluginPrivate *priv = GET_PRIVATE (self);
355 g_return_val_if_fail (FU_IS_PLUGIN (self), FALSE);
Richard Hughescff38bc2016-12-12 12:03:37 +0000356 return priv->enabled;
Richard Hughesbc93e4a2016-12-08 17:29:51 +0000357}
358
Richard Hughes57d18222017-01-10 16:02:59 +0000359/**
360 * fu_plugin_set_enabled:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100361 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000362 * @enabled: the enabled value
363 *
364 * Enables or disables a plugin. Plugins can self-disable at any point.
365 *
366 * Since: 0.8.0
367 **/
Richard Hughesd0905142016-03-13 09:46:49 +0000368void
Richard Hughes12724852018-09-04 13:53:44 +0100369fu_plugin_set_enabled (FuPlugin *self, gboolean enabled)
Richard Hughesd0905142016-03-13 09:46:49 +0000370{
Richard Hughes12724852018-09-04 13:53:44 +0100371 FuPluginPrivate *priv = GET_PRIVATE (self);
372 g_return_if_fail (FU_IS_PLUGIN (self));
Richard Hughescff38bc2016-12-12 12:03:37 +0000373 priv->enabled = enabled;
374}
375
Mario Limonciello1a680f32019-11-25 19:44:53 -0600376/**
377 * fu_plugin_guess_name_from_fn:
378 * @filename: filename to guess
379 *
380 * Tries to guess the name of the plugin from a filename
381 *
382 * Returns: (transfer full): the guessed name of the plugin
383 *
384 * Since: 1.0.8
385 **/
Richard Hughes1e456bc2018-05-10 20:16:16 +0100386gchar *
387fu_plugin_guess_name_from_fn (const gchar *filename)
388{
389 const gchar *prefix = "libfu_plugin_";
390 gchar *name;
391 gchar *str = g_strstr_len (filename, -1, prefix);
392 if (str == NULL)
393 return NULL;
394 name = g_strdup (str + strlen (prefix));
395 g_strdelimit (name, ".", '\0');
396 return name;
397}
398
Mario Limonciello1a680f32019-11-25 19:44:53 -0600399/**
400 * fu_plugin_open:
401 * @self: A #FuPlugin
402 * @filename: The shared object filename to open
403 * @error: A #GError or NULL
404 *
405 * Opens the plugin module
406 *
407 * Returns: TRUE for success, FALSE for fail
408 *
409 * Since: 0.8.0
410 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000411gboolean
Richard Hughes12724852018-09-04 13:53:44 +0100412fu_plugin_open (FuPlugin *self, const gchar *filename, GError **error)
Richard Hughescff38bc2016-12-12 12:03:37 +0000413{
Richard Hughes12724852018-09-04 13:53:44 +0100414 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughescff38bc2016-12-12 12:03:37 +0000415 FuPluginInitFunc func = NULL;
Richard Hughescff38bc2016-12-12 12:03:37 +0000416
417 priv->module = g_module_open (filename, 0);
418 if (priv->module == NULL) {
419 g_set_error (error,
420 G_IO_ERROR,
421 G_IO_ERROR_FAILED,
Mario Limonciellof5605532019-11-04 07:49:50 -0600422 "failed to open plugin %s: %s",
423 filename, g_module_error ());
Richard Hughescff38bc2016-12-12 12:03:37 +0000424 return FALSE;
425 }
426
427 /* set automatically */
Richard Hughes1e456bc2018-05-10 20:16:16 +0100428 if (priv->name == NULL)
429 priv->name = fu_plugin_guess_name_from_fn (filename);
Richard Hughesd0905142016-03-13 09:46:49 +0000430
431 /* optional */
Richard Hughescff38bc2016-12-12 12:03:37 +0000432 g_module_symbol (priv->module, "fu_plugin_init", (gpointer *) &func);
433 if (func != NULL) {
434 g_debug ("performing init() on %s", filename);
Richard Hughes12724852018-09-04 13:53:44 +0100435 func (self);
Richard Hughesd0905142016-03-13 09:46:49 +0000436 }
437
Richard Hughescff38bc2016-12-12 12:03:37 +0000438 return TRUE;
439}
440
Richard Hughes57d18222017-01-10 16:02:59 +0000441/**
442 * fu_plugin_device_add:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100443 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000444 * @device: A #FuDevice
445 *
446 * Asks the daemon to add a device to the exported list. If this device ID
447 * has already been added by a different plugin then this request will be
448 * ignored.
449 *
450 * Plugins should use fu_plugin_device_add_delay() if they are not capable of
451 * actually flashing an image to the hardware so that higher-priority plugins
452 * can add the device themselves.
453 *
454 * Since: 0.8.0
455 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000456void
Richard Hughes12724852018-09-04 13:53:44 +0100457fu_plugin_device_add (FuPlugin *self, FuDevice *device)
Richard Hughescff38bc2016-12-12 12:03:37 +0000458{
Richard Hughes5e447292018-04-27 14:25:54 +0100459 GPtrArray *children;
Richard Hughesc125ec02018-09-05 19:35:17 +0100460 g_autoptr(GError) error = NULL;
Richard Hughes5e447292018-04-27 14:25:54 +0100461
Richard Hughes12724852018-09-04 13:53:44 +0100462 g_return_if_fail (FU_IS_PLUGIN (self));
Richard Hughesccd78a92017-01-11 16:57:41 +0000463 g_return_if_fail (FU_IS_DEVICE (device));
464
Richard Hughesc125ec02018-09-05 19:35:17 +0100465 /* ensure the device ID is set from the physical and logical IDs */
466 if (!fu_device_ensure_id (device, &error)) {
467 g_warning ("ignoring add: %s", error->message);
468 return;
469 }
470
Richard Hughescff38bc2016-12-12 12:03:37 +0000471 g_debug ("emit added from %s: %s",
Richard Hughes12724852018-09-04 13:53:44 +0100472 fu_plugin_get_name (self),
Richard Hughescff38bc2016-12-12 12:03:37 +0000473 fu_device_get_id (device));
474 fu_device_set_created (device, (guint64) g_get_real_time () / G_USEC_PER_SEC);
Richard Hughes12724852018-09-04 13:53:44 +0100475 fu_device_set_plugin (device, fu_plugin_get_name (self));
476 g_signal_emit (self, signals[SIGNAL_DEVICE_ADDED], 0, device);
Richard Hughes5e447292018-04-27 14:25:54 +0100477
Richard Hughes128c0162018-08-10 11:00:29 +0100478 /* add children if they have not already been added */
Richard Hughes5e447292018-04-27 14:25:54 +0100479 children = fu_device_get_children (device);
480 for (guint i = 0; i < children->len; i++) {
481 FuDevice *child = g_ptr_array_index (children, i);
Richard Hughes128c0162018-08-10 11:00:29 +0100482 if (fu_device_get_created (child) == 0)
Richard Hughes12724852018-09-04 13:53:44 +0100483 fu_plugin_device_add (self, child);
Richard Hughes5e447292018-04-27 14:25:54 +0100484 }
Richard Hughescff38bc2016-12-12 12:03:37 +0000485}
486
Richard Hughese1fd34d2017-08-24 14:19:51 +0100487/**
488 * fu_plugin_device_register:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100489 * @self: A #FuPlugin
Richard Hughese1fd34d2017-08-24 14:19:51 +0100490 * @device: A #FuDevice
491 *
492 * Registers the device with other plugins so they can set metadata.
493 *
494 * Plugins do not have to call this manually as this is done automatically
495 * when using fu_plugin_device_add(). They may wish to use this manually
Richard Hughes21eaeef2020-01-14 12:10:01 +0000496 * if for instance the coldplug should be ignored based on the metadata
Richard Hughese1fd34d2017-08-24 14:19:51 +0100497 * set from other plugins.
498 *
499 * Since: 0.9.7
500 **/
501void
Richard Hughes12724852018-09-04 13:53:44 +0100502fu_plugin_device_register (FuPlugin *self, FuDevice *device)
Richard Hughese1fd34d2017-08-24 14:19:51 +0100503{
Richard Hughesc125ec02018-09-05 19:35:17 +0100504 g_autoptr(GError) error = NULL;
505
Richard Hughes12724852018-09-04 13:53:44 +0100506 g_return_if_fail (FU_IS_PLUGIN (self));
Richard Hughese1fd34d2017-08-24 14:19:51 +0100507 g_return_if_fail (FU_IS_DEVICE (device));
508
Richard Hughesc125ec02018-09-05 19:35:17 +0100509 /* ensure the device ID is set from the physical and logical IDs */
510 if (!fu_device_ensure_id (device, &error)) {
511 g_warning ("ignoring registration: %s", error->message);
512 return;
513 }
514
Richard Hughese1fd34d2017-08-24 14:19:51 +0100515 g_debug ("emit device-register from %s: %s",
Richard Hughes12724852018-09-04 13:53:44 +0100516 fu_plugin_get_name (self),
Richard Hughese1fd34d2017-08-24 14:19:51 +0100517 fu_device_get_id (device));
Richard Hughes12724852018-09-04 13:53:44 +0100518 g_signal_emit (self, signals[SIGNAL_DEVICE_REGISTER], 0, device);
Richard Hughese1fd34d2017-08-24 14:19:51 +0100519}
520
Richard Hughes57d18222017-01-10 16:02:59 +0000521/**
Richard Hughes4eada342017-10-03 21:20:32 +0100522 * fu_plugin_device_remove:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100523 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000524 * @device: A #FuDevice
525 *
526 * Asks the daemon to remove a device from the exported list.
527 *
528 * Since: 0.8.0
529 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000530void
Richard Hughes12724852018-09-04 13:53:44 +0100531fu_plugin_device_remove (FuPlugin *self, FuDevice *device)
Richard Hughescff38bc2016-12-12 12:03:37 +0000532{
Richard Hughes12724852018-09-04 13:53:44 +0100533 g_return_if_fail (FU_IS_PLUGIN (self));
Richard Hughesccd78a92017-01-11 16:57:41 +0000534 g_return_if_fail (FU_IS_DEVICE (device));
535
Richard Hughescff38bc2016-12-12 12:03:37 +0000536 g_debug ("emit removed from %s: %s",
Richard Hughes12724852018-09-04 13:53:44 +0100537 fu_plugin_get_name (self),
Richard Hughescff38bc2016-12-12 12:03:37 +0000538 fu_device_get_id (device));
Richard Hughes12724852018-09-04 13:53:44 +0100539 g_signal_emit (self, signals[SIGNAL_DEVICE_REMOVED], 0, device);
Richard Hughescff38bc2016-12-12 12:03:37 +0000540}
541
Richard Hughes57d18222017-01-10 16:02:59 +0000542/**
Richard Hughes2de8f132018-01-17 09:12:02 +0000543 * fu_plugin_request_recoldplug:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100544 * @self: A #FuPlugin
Richard Hughes362d6d72017-01-07 21:42:14 +0000545 *
546 * Ask all the plugins to coldplug all devices, which will include the prepare()
547 * and cleanup() phases. Duplicate devices added will be ignored.
548 *
549 * Since: 0.8.0
550 **/
551void
Richard Hughes12724852018-09-04 13:53:44 +0100552fu_plugin_request_recoldplug (FuPlugin *self)
Richard Hughes362d6d72017-01-07 21:42:14 +0000553{
Richard Hughes12724852018-09-04 13:53:44 +0100554 g_return_if_fail (FU_IS_PLUGIN (self));
555 g_signal_emit (self, signals[SIGNAL_RECOLDPLUG], 0);
Richard Hughes362d6d72017-01-07 21:42:14 +0000556}
557
Richard Hughesb0829032017-01-10 09:27:08 +0000558/**
Richard Hughesb8f8db22017-04-25 15:56:00 +0100559 * fu_plugin_check_hwid:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100560 * @self: A #FuPlugin
Richard Hughes4eada342017-10-03 21:20:32 +0100561 * @hwid: A Hardware ID GUID, e.g. `6de5d951-d755-576b-bd09-c5cf66b27234`
Richard Hughesb8f8db22017-04-25 15:56:00 +0100562 *
Richard Hughesd7704d42017-08-08 20:29:09 +0100563 * Checks to see if a specific GUID exists. All hardware IDs on a
Richard Hughesb8f8db22017-04-25 15:56:00 +0100564 * specific system can be shown using the `fwupdmgr hwids` command.
565 *
Richard Hughes4eada342017-10-03 21:20:32 +0100566 * Returns: %TRUE if the HwId is found on the system.
567 *
Richard Hughesb8f8db22017-04-25 15:56:00 +0100568 * Since: 0.9.1
569 **/
570gboolean
Richard Hughes12724852018-09-04 13:53:44 +0100571fu_plugin_check_hwid (FuPlugin *self, const gchar *hwid)
Richard Hughesb8f8db22017-04-25 15:56:00 +0100572{
Richard Hughes12724852018-09-04 13:53:44 +0100573 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughesb8f8db22017-04-25 15:56:00 +0100574 if (priv->hwids == NULL)
575 return FALSE;
Richard Hughesd7704d42017-08-08 20:29:09 +0100576 return fu_hwids_has_guid (priv->hwids, hwid);
577}
578
579/**
Patrick Rudolpha60b5472019-10-16 10:43:03 +0200580 * fu_plugin_get_hwid_replace_value:
581 * @self: A #FuPlugin
582 * @keys: A key, e.g. `HardwareID-3` or %FU_HWIDS_KEY_PRODUCT_SKU
583 * @error: A #GError or %NULL
584 *
585 * Gets the replacement value for a specific key. All hardware IDs on a
586 * specific system can be shown using the `fwupdmgr hwids` command.
587 *
588 * Returns: (transfer full): a string, or %NULL for error.
589 *
590 * Since: 1.3.3
591 **/
592gchar *
593fu_plugin_get_hwid_replace_value (FuPlugin *self, const gchar *keys, GError **error)
594{
595 FuPluginPrivate *priv = GET_PRIVATE (self);
596 if (priv->hwids == NULL)
597 return NULL;
598
599 return fu_hwids_get_replace_values (priv->hwids, keys, error);
600}
601
602/**
Richard Hughes69a5f352018-08-08 11:58:15 +0100603 * fu_plugin_get_hwids:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100604 * @self: A #FuPlugin
Richard Hughes69a5f352018-08-08 11:58:15 +0100605 *
606 * Returns all the HWIDs defined in the system. All hardware IDs on a
607 * specific system can be shown using the `fwupdmgr hwids` command.
608 *
Mario Limonciello1a680f32019-11-25 19:44:53 -0600609 * Returns: (transfer none) (element-type utf8): An array of GUIDs
Richard Hughes69a5f352018-08-08 11:58:15 +0100610 *
611 * Since: 1.1.1
612 **/
613GPtrArray *
Richard Hughes12724852018-09-04 13:53:44 +0100614fu_plugin_get_hwids (FuPlugin *self)
Richard Hughes69a5f352018-08-08 11:58:15 +0100615{
Richard Hughes12724852018-09-04 13:53:44 +0100616 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes69a5f352018-08-08 11:58:15 +0100617 if (priv->hwids == NULL)
618 return NULL;
619 return fu_hwids_get_guids (priv->hwids);
620}
621
622/**
Richard Hughes19841802019-09-10 16:48:00 +0100623 * fu_plugin_has_custom_flag:
624 * @self: A #FuPlugin
625 * @flag: A custom text flag, specific to the plugin, e.g. `uefi-force-enable`
626 *
627 * Returns if a per-plugin HwId custom flag exists, typically added from a DMI quirk.
628 *
629 * Returns: %TRUE if the quirk entry exists
630 *
631 * Since: 1.3.1
632 **/
633gboolean
634fu_plugin_has_custom_flag (FuPlugin *self, const gchar *flag)
635{
636 FuPluginPrivate *priv = GET_PRIVATE (self);
637 GPtrArray *hwids = fu_plugin_get_hwids (self);
638
639 g_return_val_if_fail (FU_IS_PLUGIN (self), FALSE);
640 g_return_val_if_fail (flag != NULL, FALSE);
641
642 /* never set up, e.g. in tests */
643 if (hwids == NULL)
644 return FALSE;
645
646 /* search each hwid */
647 for (guint i = 0; i < hwids->len; i++) {
648 const gchar *hwid = g_ptr_array_index (hwids, i);
649 const gchar *value;
650 g_autofree gchar *key = g_strdup_printf ("HwId=%s", hwid);
651
652 /* does prefixed quirk exist */
653 value = fu_quirks_lookup_by_id (priv->quirks, key, FU_QUIRKS_FLAGS);
654 if (value != NULL) {
655 g_auto(GStrv) quirks = g_strsplit (value, ",", -1);
656 if (g_strv_contains ((const gchar * const *) quirks, flag))
657 return TRUE;
658 }
659 }
660 return FALSE;
661}
662
663/**
Richard Hughes1354ea92017-09-19 15:58:31 +0100664 * fu_plugin_check_supported:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100665 * @self: A #FuPlugin
Richard Hughes4eada342017-10-03 21:20:32 +0100666 * @guid: A Hardware ID GUID, e.g. `6de5d951-d755-576b-bd09-c5cf66b27234`
Richard Hughes1354ea92017-09-19 15:58:31 +0100667 *
668 * Checks to see if a specific device GUID is supported, i.e. available in the
669 * AppStream metadata.
670 *
Richard Hughes4eada342017-10-03 21:20:32 +0100671 * Returns: %TRUE if the device is supported.
672 *
Richard Hughes1354ea92017-09-19 15:58:31 +0100673 * Since: 1.0.0
674 **/
Richard Hughesd8a8d5e2019-10-08 13:05:02 +0100675static gboolean
Richard Hughes12724852018-09-04 13:53:44 +0100676fu_plugin_check_supported (FuPlugin *self, const gchar *guid)
Richard Hughes1354ea92017-09-19 15:58:31 +0100677{
Richard Hughesaabdc372018-11-14 10:11:08 +0000678 gboolean retval = FALSE;
679 g_signal_emit (self, signals[SIGNAL_CHECK_SUPPORTED], 0, guid, &retval);
680 return retval;
Richard Hughes1354ea92017-09-19 15:58:31 +0100681}
682
683/**
Richard Hughesd7704d42017-08-08 20:29:09 +0100684 * fu_plugin_get_dmi_value:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100685 * @self: A #FuPlugin
Richard Hughes4eada342017-10-03 21:20:32 +0100686 * @dmi_id: A DMI ID, e.g. `BiosVersion`
Richard Hughesd7704d42017-08-08 20:29:09 +0100687 *
688 * Gets a hardware DMI value.
689 *
Richard Hughes4eada342017-10-03 21:20:32 +0100690 * Returns: The string, or %NULL
691 *
Richard Hughesd7704d42017-08-08 20:29:09 +0100692 * Since: 0.9.7
693 **/
694const gchar *
Richard Hughes12724852018-09-04 13:53:44 +0100695fu_plugin_get_dmi_value (FuPlugin *self, const gchar *dmi_id)
Richard Hughesd7704d42017-08-08 20:29:09 +0100696{
Richard Hughes12724852018-09-04 13:53:44 +0100697 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughesd7704d42017-08-08 20:29:09 +0100698 if (priv->hwids == NULL)
Richard Hughes7ef96b82017-08-23 18:28:24 +0100699 return NULL;
Richard Hughesd7704d42017-08-08 20:29:09 +0100700 return fu_hwids_get_value (priv->hwids, dmi_id);
Richard Hughesb8f8db22017-04-25 15:56:00 +0100701}
702
Richard Hughes49e5e052017-09-03 12:15:41 +0100703/**
704 * fu_plugin_get_smbios_string:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100705 * @self: A #FuPlugin
Richard Hughes49e5e052017-09-03 12:15:41 +0100706 * @structure_type: A SMBIOS structure type, e.g. %FU_SMBIOS_STRUCTURE_TYPE_BIOS
707 * @offset: A SMBIOS offset
708 *
709 * Gets a hardware SMBIOS string.
710 *
711 * The @type and @offset can be referenced from the DMTF SMBIOS specification:
712 * https://www.dmtf.org/sites/default/files/standards/documents/DSP0134_3.1.1.pdf
713 *
Richard Hughes4eada342017-10-03 21:20:32 +0100714 * Returns: A string, or %NULL
715 *
Richard Hughes49e5e052017-09-03 12:15:41 +0100716 * Since: 0.9.8
717 **/
718const gchar *
Richard Hughes12724852018-09-04 13:53:44 +0100719fu_plugin_get_smbios_string (FuPlugin *self, guint8 structure_type, guint8 offset)
Richard Hughes49e5e052017-09-03 12:15:41 +0100720{
Richard Hughes12724852018-09-04 13:53:44 +0100721 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes49e5e052017-09-03 12:15:41 +0100722 if (priv->smbios == NULL)
723 return NULL;
724 return fu_smbios_get_string (priv->smbios, structure_type, offset, NULL);
725}
726
727/**
728 * fu_plugin_get_smbios_data:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100729 * @self: A #FuPlugin
Richard Hughes49e5e052017-09-03 12:15:41 +0100730 * @structure_type: A SMBIOS structure type, e.g. %FU_SMBIOS_STRUCTURE_TYPE_BIOS
731 *
732 * Gets a hardware SMBIOS data.
733 *
Richard Hughesdfaca2d2019-08-01 08:08:03 +0100734 * Returns: (transfer full): A #GBytes, or %NULL
Richard Hughes4eada342017-10-03 21:20:32 +0100735 *
Richard Hughes49e5e052017-09-03 12:15:41 +0100736 * Since: 0.9.8
737 **/
738GBytes *
Richard Hughes12724852018-09-04 13:53:44 +0100739fu_plugin_get_smbios_data (FuPlugin *self, guint8 structure_type)
Richard Hughes49e5e052017-09-03 12:15:41 +0100740{
Richard Hughes12724852018-09-04 13:53:44 +0100741 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes49e5e052017-09-03 12:15:41 +0100742 if (priv->smbios == NULL)
743 return NULL;
744 return fu_smbios_get_data (priv->smbios, structure_type, NULL);
745}
746
Mario Limonciello1a680f32019-11-25 19:44:53 -0600747/**
748 * fu_plugin_set_hwids:
749 * @self: A #FuPlugin
750 * @hwids: A #FuHwids
751 *
752 * Sets the hwids for a plugin
753 *
754 * Since: 0.9.7
755 **/
Richard Hughesb8f8db22017-04-25 15:56:00 +0100756void
Richard Hughes12724852018-09-04 13:53:44 +0100757fu_plugin_set_hwids (FuPlugin *self, FuHwids *hwids)
Richard Hughesb8f8db22017-04-25 15:56:00 +0100758{
Richard Hughes12724852018-09-04 13:53:44 +0100759 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughesd7704d42017-08-08 20:29:09 +0100760 g_set_object (&priv->hwids, hwids);
Richard Hughesb8f8db22017-04-25 15:56:00 +0100761}
762
Mario Limonciello1a680f32019-11-25 19:44:53 -0600763/**
764 * fu_plugin_set_udev_subsystems:
765 * @self: A #FuPlugin
Richard Hughesa0d81c72019-11-27 11:41:54 +0000766 * @udev_subsystems: (element-type utf8): A #GPtrArray
Mario Limonciello1a680f32019-11-25 19:44:53 -0600767 *
768 * Sets the udev subsystems used by a plugin
769 *
770 * Since: 1.1.2
771 **/
Richard Hughes49e5e052017-09-03 12:15:41 +0100772void
Richard Hughes12724852018-09-04 13:53:44 +0100773fu_plugin_set_udev_subsystems (FuPlugin *self, GPtrArray *udev_subsystems)
Richard Hughes9d6e0e72018-08-24 20:20:17 +0100774{
Richard Hughes12724852018-09-04 13:53:44 +0100775 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes9d6e0e72018-08-24 20:20:17 +0100776 if (priv->udev_subsystems != NULL)
777 g_ptr_array_unref (priv->udev_subsystems);
778 priv->udev_subsystems = g_ptr_array_ref (udev_subsystems);
779}
780
Mario Limonciello1a680f32019-11-25 19:44:53 -0600781/**
782 * fu_plugin_set_quirks:
783 * @self: A #FuPlugin
784 * @quirks: A #FuQuirks
785 *
786 * Sets the quirks for a plugin
787 *
788 * Since: 1.0.1
789 **/
Richard Hughes9d6e0e72018-08-24 20:20:17 +0100790void
Richard Hughes12724852018-09-04 13:53:44 +0100791fu_plugin_set_quirks (FuPlugin *self, FuQuirks *quirks)
Richard Hughes9c028f02017-10-28 21:14:28 +0100792{
Richard Hughes12724852018-09-04 13:53:44 +0100793 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes9c028f02017-10-28 21:14:28 +0100794 g_set_object (&priv->quirks, quirks);
795}
796
797/**
798 * fu_plugin_get_quirks:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100799 * @self: A #FuPlugin
Richard Hughes9c028f02017-10-28 21:14:28 +0100800 *
801 * Returns the hardware database object. This can be used to discover device
802 * quirks or other device-specific settings.
803 *
804 * Returns: (transfer none): a #FuQuirks, or %NULL if not set
805 *
806 * Since: 1.0.1
807 **/
808FuQuirks *
Richard Hughes12724852018-09-04 13:53:44 +0100809fu_plugin_get_quirks (FuPlugin *self)
Richard Hughes9c028f02017-10-28 21:14:28 +0100810{
Richard Hughes12724852018-09-04 13:53:44 +0100811 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes9c028f02017-10-28 21:14:28 +0100812 return priv->quirks;
813}
814
Mario Limonciello1a680f32019-11-25 19:44:53 -0600815/**
816 * fu_plugin_set_runtime_versions:
817 * @self: A #FuPlugin
818 * @runtime_versions: A #GHashTables
819 *
820 * Sets the runtime versions for a plugin
821 *
822 * Since: 1.0.7
823 **/
Richard Hughes0eb123b2018-04-19 12:00:04 +0100824void
Richard Hughes12724852018-09-04 13:53:44 +0100825fu_plugin_set_runtime_versions (FuPlugin *self, GHashTable *runtime_versions)
Richard Hughes0eb123b2018-04-19 12:00:04 +0100826{
Richard Hughes12724852018-09-04 13:53:44 +0100827 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes0eb123b2018-04-19 12:00:04 +0100828 priv->runtime_versions = g_hash_table_ref (runtime_versions);
829}
830
831/**
832 * fu_plugin_add_runtime_version:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100833 * @self: A #FuPlugin
Richard Hughes0eb123b2018-04-19 12:00:04 +0100834 * @component_id: An AppStream component id, e.g. "org.gnome.Software"
835 * @version: A version string, e.g. "1.2.3"
836 *
Richard Hughesdce91202019-04-08 12:47:45 +0100837 * Sets a runtime version of a specific dependency.
Richard Hughes0eb123b2018-04-19 12:00:04 +0100838 *
839 * Since: 1.0.7
840 **/
841void
Richard Hughes12724852018-09-04 13:53:44 +0100842fu_plugin_add_runtime_version (FuPlugin *self,
Richard Hughes0eb123b2018-04-19 12:00:04 +0100843 const gchar *component_id,
844 const gchar *version)
845{
Richard Hughes12724852018-09-04 13:53:44 +0100846 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughesb01b4862018-04-20 16:39:48 +0100847 if (priv->runtime_versions == NULL)
848 return;
Richard Hughes0eb123b2018-04-19 12:00:04 +0100849 g_hash_table_insert (priv->runtime_versions,
850 g_strdup (component_id),
851 g_strdup (version));
852}
853
Mario Limonciello1a680f32019-11-25 19:44:53 -0600854/**
855 * fu_plugin_set_compile_versions:
856 * @self: A #FuPlugin
857 * @compile_versions: A #GHashTables
858 *
859 * Sets the compile time versions for a plugin
860 *
861 * Since: 1.0.7
862 **/
Richard Hughes34e0dab2018-04-20 16:43:00 +0100863void
Richard Hughes12724852018-09-04 13:53:44 +0100864fu_plugin_set_compile_versions (FuPlugin *self, GHashTable *compile_versions)
Richard Hughes34e0dab2018-04-20 16:43:00 +0100865{
Richard Hughes12724852018-09-04 13:53:44 +0100866 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes34e0dab2018-04-20 16:43:00 +0100867 priv->compile_versions = g_hash_table_ref (compile_versions);
868}
869
870/**
871 * fu_plugin_add_compile_version:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100872 * @self: A #FuPlugin
Richard Hughes34e0dab2018-04-20 16:43:00 +0100873 * @component_id: An AppStream component id, e.g. "org.gnome.Software"
874 * @version: A version string, e.g. "1.2.3"
875 *
Richard Hughesdce91202019-04-08 12:47:45 +0100876 * Sets a compile-time version of a specific dependency.
Richard Hughes34e0dab2018-04-20 16:43:00 +0100877 *
878 * Since: 1.0.7
879 **/
880void
Richard Hughes12724852018-09-04 13:53:44 +0100881fu_plugin_add_compile_version (FuPlugin *self,
Richard Hughes34e0dab2018-04-20 16:43:00 +0100882 const gchar *component_id,
883 const gchar *version)
884{
Richard Hughes12724852018-09-04 13:53:44 +0100885 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes34e0dab2018-04-20 16:43:00 +0100886 if (priv->compile_versions == NULL)
887 return;
888 g_hash_table_insert (priv->compile_versions,
889 g_strdup (component_id),
890 g_strdup (version));
891}
892
Richard Hughes9c028f02017-10-28 21:14:28 +0100893/**
894 * fu_plugin_lookup_quirk_by_id:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100895 * @self: A #FuPlugin
Richard Hughes87fb9ff2018-06-28 12:55:59 +0100896 * @group: A string, e.g. "DfuFlags"
897 * @key: An ID to match the entry, e.g. "Summary"
Richard Hughes9c028f02017-10-28 21:14:28 +0100898 *
899 * Looks up an entry in the hardware database using a string value.
900 *
901 * Returns: (transfer none): values from the database, or %NULL if not found
902 *
903 * Since: 1.0.1
904 **/
905const gchar *
Richard Hughes12724852018-09-04 13:53:44 +0100906fu_plugin_lookup_quirk_by_id (FuPlugin *self, const gchar *group, const gchar *key)
Richard Hughes9c028f02017-10-28 21:14:28 +0100907{
Richard Hughes12724852018-09-04 13:53:44 +0100908 FuPluginPrivate *priv = GET_PRIVATE (self);
909 g_return_val_if_fail (FU_IS_PLUGIN (self), NULL);
Richard Hughes9c028f02017-10-28 21:14:28 +0100910
Richard Hughes9c028f02017-10-28 21:14:28 +0100911 /* exact ID */
Richard Hughes87fb9ff2018-06-28 12:55:59 +0100912 return fu_quirks_lookup_by_id (priv->quirks, group, key);
Richard Hughes9c028f02017-10-28 21:14:28 +0100913}
914
915/**
Richard Hughes8fe7cdd2018-08-23 10:02:44 +0100916 * fu_plugin_lookup_quirk_by_id_as_uint64:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100917 * @self: A #FuPlugin
Richard Hughes8fe7cdd2018-08-23 10:02:44 +0100918 * @group: A string, e.g. "DfuFlags"
919 * @key: An ID to match the entry, e.g. "Size"
920 *
921 * Looks up an entry in the hardware database using a string key, returning
922 * an integer value. Values are assumed base 10, unless prefixed with "0x"
923 * where they are parsed as base 16.
924 *
Mario Limonciello1a680f32019-11-25 19:44:53 -0600925 * Returns: guint64 id or 0 if not found
Richard Hughes8fe7cdd2018-08-23 10:02:44 +0100926 *
927 * Since: 1.1.2
928 **/
929guint64
Richard Hughes12724852018-09-04 13:53:44 +0100930fu_plugin_lookup_quirk_by_id_as_uint64 (FuPlugin *self, const gchar *group, const gchar *key)
Richard Hughes8fe7cdd2018-08-23 10:02:44 +0100931{
Richard Hughes12724852018-09-04 13:53:44 +0100932 return fu_common_strtoull (fu_plugin_lookup_quirk_by_id (self, group, key));
Richard Hughes8fe7cdd2018-08-23 10:02:44 +0100933}
934
Mario Limonciello1a680f32019-11-25 19:44:53 -0600935/**
936 * fu_plugin_set_smbios:
937 * @self: A #FuPlugin
938 * @smbios: A #FuSmbios
939 *
940 * Sets the smbios for a plugin
941 *
942 * Since: 1.0.0
943 **/
Richard Hughes1354ea92017-09-19 15:58:31 +0100944void
Richard Hughes12724852018-09-04 13:53:44 +0100945fu_plugin_set_smbios (FuPlugin *self, FuSmbios *smbios)
Richard Hughes49e5e052017-09-03 12:15:41 +0100946{
Richard Hughes12724852018-09-04 13:53:44 +0100947 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes49e5e052017-09-03 12:15:41 +0100948 g_set_object (&priv->smbios, smbios);
949}
950
Richard Hughesb8f8db22017-04-25 15:56:00 +0100951/**
Richard Hughesb0829032017-01-10 09:27:08 +0000952 * fu_plugin_set_coldplug_delay:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100953 * @self: A #FuPlugin
Richard Hughesb0829032017-01-10 09:27:08 +0000954 * @duration: A delay in milliseconds
955 *
Richard Hughes21eaeef2020-01-14 12:10:01 +0000956 * Set the minimum time that should be waited in-between the call to
Richard Hughesb0829032017-01-10 09:27:08 +0000957 * fu_plugin_coldplug_prepare() and fu_plugin_coldplug(). This is usually going
958 * to be the minimum hardware initialisation time from a datasheet.
959 *
960 * It is better to use this function rather than using a sleep() in the plugin
961 * itself as then only one delay is done in the daemon rather than waiting for
962 * each coldplug prepare in a serial way.
963 *
964 * Additionally, very long delays should be avoided as the daemon will be
965 * blocked from processing requests whilst the coldplug delay is being
966 * performed.
967 *
968 * Since: 0.8.0
969 **/
970void
Richard Hughes12724852018-09-04 13:53:44 +0100971fu_plugin_set_coldplug_delay (FuPlugin *self, guint duration)
Richard Hughesb0829032017-01-10 09:27:08 +0000972{
Richard Hughes12724852018-09-04 13:53:44 +0100973 g_return_if_fail (FU_IS_PLUGIN (self));
Richard Hughesb0829032017-01-10 09:27:08 +0000974 g_return_if_fail (duration > 0);
975
976 /* check sanity */
977 if (duration > FU_PLUGIN_COLDPLUG_DELAY_MAXIMUM) {
978 g_warning ("duration of %ums is crazy, truncating to %ums",
979 duration,
980 FU_PLUGIN_COLDPLUG_DELAY_MAXIMUM);
981 duration = FU_PLUGIN_COLDPLUG_DELAY_MAXIMUM;
982 }
983
984 /* emit */
Richard Hughes12724852018-09-04 13:53:44 +0100985 g_signal_emit (self, signals[SIGNAL_SET_COLDPLUG_DELAY], 0, duration);
Richard Hughesb0829032017-01-10 09:27:08 +0000986}
987
Richard Hughes4b303802019-10-04 13:22:51 +0100988static gboolean
989fu_plugin_device_attach (FuPlugin *self, FuDevice *device, GError **error)
990{
991 g_autoptr(FuDeviceLocker) locker = NULL;
Richard Hughes4b303802019-10-04 13:22:51 +0100992 locker = fu_device_locker_new (device, error);
993 if (locker == NULL)
994 return FALSE;
995 return fu_device_attach (device, error);
996}
997
998static gboolean
999fu_plugin_device_detach (FuPlugin *self, FuDevice *device, GError **error)
1000{
1001 g_autoptr(FuDeviceLocker) locker = NULL;
Richard Hughes4b303802019-10-04 13:22:51 +01001002 locker = fu_device_locker_new (device, error);
1003 if (locker == NULL)
1004 return FALSE;
1005 return fu_device_detach (device, error);
1006}
1007
1008static gboolean
Richard Hughes4b303802019-10-04 13:22:51 +01001009fu_plugin_device_activate (FuPlugin *self, FuDevice *device, GError **error)
1010{
1011 g_autoptr(FuDeviceLocker) locker = NULL;
1012 locker = fu_device_locker_new (device, error);
1013 if (locker == NULL)
1014 return FALSE;
1015 return fu_device_activate (device, error);
1016}
1017
1018static gboolean
1019fu_plugin_device_write_firmware (FuPlugin *self, FuDevice *device,
1020 GBytes *fw, FwupdInstallFlags flags,
1021 GError **error)
1022{
1023 g_autoptr(FuDeviceLocker) locker = NULL;
1024 locker = fu_device_locker_new (device, error);
1025 if (locker == NULL)
1026 return FALSE;
1027 return fu_device_write_firmware (device, fw, flags, error);
1028}
1029
Richard Hughes7f677212019-10-05 16:19:40 +01001030static gboolean
1031fu_plugin_device_read_firmware (FuPlugin *self, FuDevice *device, GError **error)
1032{
1033 g_autoptr(FuDeviceLocker) locker = NULL;
Richard Hughesf0eb0912019-10-10 11:37:22 +01001034 g_autoptr(FuFirmware) firmware = NULL;
Richard Hughes7f677212019-10-05 16:19:40 +01001035 g_autoptr(GBytes) fw = NULL;
1036 GChecksumType checksum_types[] = {
1037 G_CHECKSUM_SHA1,
1038 G_CHECKSUM_SHA256,
1039 0 };
1040 locker = fu_device_locker_new (device, error);
1041 if (locker == NULL)
1042 return FALSE;
1043 if (!fu_device_detach (device, error))
1044 return FALSE;
Richard Hughesf0eb0912019-10-10 11:37:22 +01001045 firmware = fu_device_read_firmware (device, error);
1046 if (firmware == NULL) {
1047 g_autoptr(GError) error_local = NULL;
1048 if (!fu_device_attach (device, &error_local))
1049 g_debug ("ignoring attach failure: %s", error_local->message);
1050 g_prefix_error (error, "failed to read firmware: ");
1051 return FALSE;
1052 }
1053 fw = fu_firmware_write (firmware, error);
Richard Hughes7f677212019-10-05 16:19:40 +01001054 if (fw == NULL) {
1055 g_autoptr(GError) error_local = NULL;
1056 if (!fu_device_attach (device, &error_local))
Richard Hughesf0eb0912019-10-10 11:37:22 +01001057 g_debug ("ignoring attach failure: %s", error_local->message);
1058 g_prefix_error (error, "failed to write firmware: ");
Richard Hughes7f677212019-10-05 16:19:40 +01001059 return FALSE;
1060 }
1061 for (guint i = 0; checksum_types[i] != 0; i++) {
1062 g_autofree gchar *hash = NULL;
1063 hash = g_compute_checksum_for_bytes (checksum_types[i], fw);
1064 fu_device_add_checksum (device, hash);
1065 }
1066 return fu_device_attach (device, error);
1067}
1068
Mario Limonciello1a680f32019-11-25 19:44:53 -06001069/**
1070 * fu_plugin_runner_startup:
1071 * @self: a #FuPlugin
1072 * @error: a #GError or NULL
1073 *
1074 * Runs the startup routine for the plugin
1075 *
1076 * Returns: #TRUE for success, #FALSE for failure
1077 *
1078 * Since: 0.8.0
1079 **/
Richard Hughesd0905142016-03-13 09:46:49 +00001080gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001081fu_plugin_runner_startup (FuPlugin *self, GError **error)
Richard Hughesd0905142016-03-13 09:46:49 +00001082{
Richard Hughes12724852018-09-04 13:53:44 +01001083 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes7b8b2022016-12-12 16:15:03 +00001084 FuPluginStartupFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001085 g_autoptr(GError) error_local = NULL;
Richard Hughesd0905142016-03-13 09:46:49 +00001086
1087 /* not enabled */
Richard Hughescff38bc2016-12-12 12:03:37 +00001088 if (!priv->enabled)
Richard Hughesd0905142016-03-13 09:46:49 +00001089 return TRUE;
1090
Richard Hughes639da472018-01-06 22:35:04 +00001091 /* no object loaded */
1092 if (priv->module == NULL)
1093 return TRUE;
1094
Richard Hughesd0905142016-03-13 09:46:49 +00001095 /* optional */
Richard Hughescff38bc2016-12-12 12:03:37 +00001096 g_module_symbol (priv->module, "fu_plugin_startup", (gpointer *) &func);
1097 if (func == NULL)
Richard Hughesd0905142016-03-13 09:46:49 +00001098 return TRUE;
Richard Hughescff38bc2016-12-12 12:03:37 +00001099 g_debug ("performing startup() on %s", priv->name);
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001100 if (!func (self, &error_local)) {
1101 if (error_local == NULL) {
1102 g_critical ("unset error in plugin %s for startup()",
1103 priv->name);
1104 g_set_error_literal (&error_local,
1105 FWUPD_ERROR,
1106 FWUPD_ERROR_INTERNAL,
1107 "unspecified error");
1108 }
1109 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1110 "failed to startup using %s: ",
1111 priv->name);
Richard Hughescff38bc2016-12-12 12:03:37 +00001112 return FALSE;
1113 }
1114 return TRUE;
1115}
1116
1117static gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001118fu_plugin_runner_device_generic (FuPlugin *self, FuDevice *device,
Richard Hughes4b303802019-10-04 13:22:51 +01001119 const gchar *symbol_name,
1120 FuPluginDeviceFunc device_func,
1121 GError **error)
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001122{
Richard Hughes12724852018-09-04 13:53:44 +01001123 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001124 FuPluginDeviceFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001125 g_autoptr(GError) error_local = NULL;
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001126
1127 /* not enabled */
1128 if (!priv->enabled)
1129 return TRUE;
1130
Richard Hughesd3d96cc2017-11-14 11:34:33 +00001131 /* no object loaded */
1132 if (priv->module == NULL)
1133 return TRUE;
1134
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001135 /* optional */
1136 g_module_symbol (priv->module, symbol_name, (gpointer *) &func);
Richard Hughes4b303802019-10-04 13:22:51 +01001137 if (func == NULL) {
1138 if (device_func != NULL) {
1139 g_debug ("running superclassed %s() on %s",
1140 symbol_name + 10, priv->name);
1141 return device_func (self, device, error);
1142 }
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001143 return TRUE;
Richard Hughes4b303802019-10-04 13:22:51 +01001144 }
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001145 g_debug ("performing %s() on %s", symbol_name + 10, priv->name);
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001146 if (!func (self, device, &error_local)) {
1147 if (error_local == NULL) {
1148 g_critical ("unset error in plugin %s for %s()",
1149 priv->name, symbol_name + 10);
1150 g_set_error_literal (&error_local,
1151 FWUPD_ERROR,
1152 FWUPD_ERROR_INTERNAL,
1153 "unspecified error");
1154 }
1155 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1156 "failed to %s using %s: ",
1157 symbol_name + 10, priv->name);
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001158 return FALSE;
1159 }
1160 return TRUE;
1161}
1162
Richard Hughesdbd8c762018-06-15 20:31:40 +01001163static gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001164fu_plugin_runner_flagged_device_generic (FuPlugin *self, FwupdInstallFlags flags,
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -05001165 FuDevice *device,
1166 const gchar *symbol_name, GError **error)
1167{
Richard Hughes12724852018-09-04 13:53:44 +01001168 FuPluginPrivate *priv = GET_PRIVATE (self);
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -05001169 FuPluginFlaggedDeviceFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001170 g_autoptr(GError) error_local = NULL;
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -05001171
1172 /* not enabled */
1173 if (!priv->enabled)
1174 return TRUE;
1175
1176 /* no object loaded */
1177 if (priv->module == NULL)
1178 return TRUE;
1179
1180 /* optional */
1181 g_module_symbol (priv->module, symbol_name, (gpointer *) &func);
1182 if (func == NULL)
1183 return TRUE;
1184 g_debug ("performing %s() on %s", symbol_name + 10, priv->name);
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001185 if (!func (self, flags, device, &error_local)) {
1186 if (error_local == NULL) {
1187 g_critical ("unset error in plugin %s for %s()",
1188 priv->name, symbol_name + 10);
1189 g_set_error_literal (&error_local,
1190 FWUPD_ERROR,
1191 FWUPD_ERROR_INTERNAL,
1192 "unspecified error");
1193 }
1194 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1195 "failed to %s using %s: ",
1196 symbol_name + 10, priv->name);
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -05001197 return FALSE;
1198 }
1199 return TRUE;
1200
1201}
1202
1203static gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001204fu_plugin_runner_device_array_generic (FuPlugin *self, GPtrArray *devices,
Richard Hughesdbd8c762018-06-15 20:31:40 +01001205 const gchar *symbol_name, GError **error)
1206{
Richard Hughes12724852018-09-04 13:53:44 +01001207 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughesdbd8c762018-06-15 20:31:40 +01001208 FuPluginDeviceArrayFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001209 g_autoptr(GError) error_local = NULL;
Richard Hughesdbd8c762018-06-15 20:31:40 +01001210
1211 /* not enabled */
1212 if (!priv->enabled)
1213 return TRUE;
1214
1215 /* no object loaded */
1216 if (priv->module == NULL)
1217 return TRUE;
1218
1219 /* optional */
1220 g_module_symbol (priv->module, symbol_name, (gpointer *) &func);
1221 if (func == NULL)
1222 return TRUE;
1223 g_debug ("performing %s() on %s", symbol_name + 10, priv->name);
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001224 if (!func (self, devices, &error_local)) {
1225 if (error_local == NULL) {
1226 g_critical ("unset error in plugin %s for %s()",
1227 priv->name, symbol_name + 10);
1228 g_set_error_literal (&error_local,
1229 FWUPD_ERROR,
1230 FWUPD_ERROR_INTERNAL,
1231 "unspecified error");
1232 }
1233 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1234 "failed to %s using %s: ",
1235 symbol_name + 10, priv->name);
Richard Hughesdbd8c762018-06-15 20:31:40 +01001236 return FALSE;
1237 }
1238 return TRUE;
1239}
1240
Mario Limonciello1a680f32019-11-25 19:44:53 -06001241/**
1242 * fu_plugin_runner_coldplug:
1243 * @self: a #FuPlugin
1244 * @error: a #GError or NULL
1245 *
1246 * Runs the coldplug routine for the plugin
1247 *
1248 * Returns: #TRUE for success, #FALSE for failure
1249 *
1250 * Since: 0.8.0
1251 **/
Richard Hughesd0905142016-03-13 09:46:49 +00001252gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001253fu_plugin_runner_coldplug (FuPlugin *self, GError **error)
Richard Hughesd0905142016-03-13 09:46:49 +00001254{
Richard Hughes12724852018-09-04 13:53:44 +01001255 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes7b8b2022016-12-12 16:15:03 +00001256 FuPluginStartupFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001257 g_autoptr(GError) error_local = NULL;
Richard Hughesd0905142016-03-13 09:46:49 +00001258
1259 /* not enabled */
Richard Hughescff38bc2016-12-12 12:03:37 +00001260 if (!priv->enabled)
Richard Hughesd0905142016-03-13 09:46:49 +00001261 return TRUE;
1262
Richard Hughes639da472018-01-06 22:35:04 +00001263 /* no object loaded */
1264 if (priv->module == NULL)
1265 return TRUE;
1266
Richard Hughesd0905142016-03-13 09:46:49 +00001267 /* optional */
Richard Hughescff38bc2016-12-12 12:03:37 +00001268 g_module_symbol (priv->module, "fu_plugin_coldplug", (gpointer *) &func);
1269 if (func == NULL)
Richard Hughesd0905142016-03-13 09:46:49 +00001270 return TRUE;
Richard Hughescff38bc2016-12-12 12:03:37 +00001271 g_debug ("performing coldplug() on %s", priv->name);
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001272 if (!func (self, &error_local)) {
1273 if (error_local == NULL) {
1274 g_critical ("unset error in plugin %s for coldplug()",
1275 priv->name);
1276 g_set_error_literal (&error_local,
1277 FWUPD_ERROR,
1278 FWUPD_ERROR_INTERNAL,
1279 "unspecified error");
1280 }
1281 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1282 "failed to coldplug using %s: ", priv->name);
Richard Hughescff38bc2016-12-12 12:03:37 +00001283 return FALSE;
1284 }
1285 return TRUE;
1286}
1287
Mario Limonciello1a680f32019-11-25 19:44:53 -06001288/**
1289 * fu_plugin_runner_recoldplug:
1290 * @self: a #FuPlugin
1291 * @error: a #GError or NULL
1292 *
1293 * Runs the recoldplug routine for the plugin
1294 *
1295 * Returns: #TRUE for success, #FALSE for failure
1296 *
1297 * Since: 1.0.4
1298 **/
Richard Hughes7b8b2022016-12-12 16:15:03 +00001299gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001300fu_plugin_runner_recoldplug (FuPlugin *self, GError **error)
Richard Hughes2de8f132018-01-17 09:12:02 +00001301{
Richard Hughes12724852018-09-04 13:53:44 +01001302 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes2de8f132018-01-17 09:12:02 +00001303 FuPluginStartupFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001304 g_autoptr(GError) error_local = NULL;
Richard Hughes2de8f132018-01-17 09:12:02 +00001305
1306 /* not enabled */
1307 if (!priv->enabled)
1308 return TRUE;
1309
1310 /* no object loaded */
1311 if (priv->module == NULL)
1312 return TRUE;
1313
1314 /* optional */
1315 g_module_symbol (priv->module, "fu_plugin_recoldplug", (gpointer *) &func);
1316 if (func == NULL)
1317 return TRUE;
1318 g_debug ("performing recoldplug() on %s", priv->name);
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001319 if (!func (self, &error_local)) {
1320 if (error_local == NULL) {
1321 g_critical ("unset error in plugin %s for recoldplug()",
1322 priv->name);
1323 g_set_error_literal (&error_local,
1324 FWUPD_ERROR,
1325 FWUPD_ERROR_INTERNAL,
1326 "unspecified error");
1327 }
1328 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1329 "failed to recoldplug using %s: ",
1330 priv->name);
Richard Hughes2de8f132018-01-17 09:12:02 +00001331 return FALSE;
1332 }
1333 return TRUE;
1334}
1335
Mario Limonciello1a680f32019-11-25 19:44:53 -06001336/**
1337 * fu_plugin_runner_coldplug_prepare:
1338 * @self: a #FuPlugin
1339 * @error: a #GError or NULL
1340 *
1341 * Runs the coldplug_prepare routine for the plugin
1342 *
1343 * Returns: #TRUE for success, #FALSE for failure
1344 *
1345 * Since: 0.8.0
1346 **/
Richard Hughes2de8f132018-01-17 09:12:02 +00001347gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001348fu_plugin_runner_coldplug_prepare (FuPlugin *self, GError **error)
Richard Hughes46487c92017-01-07 21:26:34 +00001349{
Richard Hughes12724852018-09-04 13:53:44 +01001350 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes46487c92017-01-07 21:26:34 +00001351 FuPluginStartupFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001352 g_autoptr(GError) error_local = NULL;
Richard Hughes46487c92017-01-07 21:26:34 +00001353
1354 /* not enabled */
1355 if (!priv->enabled)
1356 return TRUE;
1357
Richard Hughes639da472018-01-06 22:35:04 +00001358 /* no object loaded */
1359 if (priv->module == NULL)
1360 return TRUE;
1361
Richard Hughes46487c92017-01-07 21:26:34 +00001362 /* optional */
1363 g_module_symbol (priv->module, "fu_plugin_coldplug_prepare", (gpointer *) &func);
1364 if (func == NULL)
1365 return TRUE;
1366 g_debug ("performing coldplug_prepare() on %s", priv->name);
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001367 if (!func (self, &error_local)) {
1368 if (error_local == NULL) {
1369 g_critical ("unset error in plugin %s for coldplug_prepare()",
1370 priv->name);
1371 g_set_error_literal (&error_local,
1372 FWUPD_ERROR,
1373 FWUPD_ERROR_INTERNAL,
1374 "unspecified error");
1375 }
1376 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1377 "failed to coldplug_prepare using %s: ",
1378 priv->name);
Richard Hughes46487c92017-01-07 21:26:34 +00001379 return FALSE;
1380 }
1381 return TRUE;
1382}
1383
Mario Limonciello1a680f32019-11-25 19:44:53 -06001384/**
1385 * fu_plugin_runner_coldplug_cleanup:
1386 * @self: a #FuPlugin
1387 * @error: a #GError or NULL
1388 *
1389 * Runs the coldplug_cleanup routine for the plugin
1390 *
1391 * Returns: #TRUE for success, #FALSE for failure
1392 *
1393 * Since: 0.8.0
1394 **/
Richard Hughes46487c92017-01-07 21:26:34 +00001395gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001396fu_plugin_runner_coldplug_cleanup (FuPlugin *self, GError **error)
Richard Hughes46487c92017-01-07 21:26:34 +00001397{
Richard Hughes12724852018-09-04 13:53:44 +01001398 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes46487c92017-01-07 21:26:34 +00001399 FuPluginStartupFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001400 g_autoptr(GError) error_local = NULL;
Richard Hughes46487c92017-01-07 21:26:34 +00001401
1402 /* not enabled */
1403 if (!priv->enabled)
1404 return TRUE;
1405
Richard Hughes639da472018-01-06 22:35:04 +00001406 /* no object loaded */
1407 if (priv->module == NULL)
1408 return TRUE;
1409
Richard Hughes46487c92017-01-07 21:26:34 +00001410 /* optional */
1411 g_module_symbol (priv->module, "fu_plugin_coldplug_cleanup", (gpointer *) &func);
1412 if (func == NULL)
1413 return TRUE;
1414 g_debug ("performing coldplug_cleanup() on %s", priv->name);
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001415 if (!func (self, &error_local)) {
1416 if (error_local == NULL) {
1417 g_critical ("unset error in plugin %s for coldplug_cleanup()",
1418 priv->name);
1419 g_set_error_literal (&error_local,
1420 FWUPD_ERROR,
1421 FWUPD_ERROR_INTERNAL,
1422 "unspecified error");
1423 }
1424 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1425 "failed to coldplug_cleanup using %s: ",
1426 priv->name);
Richard Hughes46487c92017-01-07 21:26:34 +00001427 return FALSE;
1428 }
1429 return TRUE;
1430}
1431
Mario Limonciello1a680f32019-11-25 19:44:53 -06001432/**
1433 * fu_plugin_runner_composite_prepare:
1434 * @self: a #FuPlugin
Richard Hughesa0d81c72019-11-27 11:41:54 +00001435 * @devices: (element-type FuDevice): a #GPtrArray of devices
Mario Limonciello1a680f32019-11-25 19:44:53 -06001436 * @error: a #GError or NULL
1437 *
1438 * Runs the composite_prepare routine for the plugin
1439 *
1440 * Returns: #TRUE for success, #FALSE for failure
1441 *
1442 * Since: 1.0.9
1443 **/
Richard Hughes46487c92017-01-07 21:26:34 +00001444gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001445fu_plugin_runner_composite_prepare (FuPlugin *self, GPtrArray *devices, GError **error)
Richard Hughesdbd8c762018-06-15 20:31:40 +01001446{
Richard Hughes12724852018-09-04 13:53:44 +01001447 return fu_plugin_runner_device_array_generic (self, devices,
Richard Hughesdbd8c762018-06-15 20:31:40 +01001448 "fu_plugin_composite_prepare",
1449 error);
1450}
1451
Mario Limonciello1a680f32019-11-25 19:44:53 -06001452/**
1453 * fu_plugin_runner_composite_cleanup:
1454 * @self: a #FuPlugin
Richard Hughesa0d81c72019-11-27 11:41:54 +00001455 * @devices: (element-type FuDevice): a #GPtrArray of devices
Mario Limonciello1a680f32019-11-25 19:44:53 -06001456 * @error: a #GError or NULL
1457 *
1458 * Runs the composite_cleanup routine for the plugin
1459 *
1460 * Returns: #TRUE for success, #FALSE for failure
1461 *
1462 * Since: 1.0.9
1463 **/
Richard Hughesdbd8c762018-06-15 20:31:40 +01001464gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001465fu_plugin_runner_composite_cleanup (FuPlugin *self, GPtrArray *devices, GError **error)
Richard Hughesdbd8c762018-06-15 20:31:40 +01001466{
Richard Hughes12724852018-09-04 13:53:44 +01001467 return fu_plugin_runner_device_array_generic (self, devices,
Richard Hughesdbd8c762018-06-15 20:31:40 +01001468 "fu_plugin_composite_cleanup",
1469 error);
1470}
1471
Mario Limonciello1a680f32019-11-25 19:44:53 -06001472/**
1473 * fu_plugin_runner_update_prepare:
1474 * @self: a #FuPlugin
1475 * @error: a #GError or NULL
1476 *
1477 * Runs the update_prepare routine for the plugin
1478 *
1479 * Returns: #TRUE for success, #FALSE for failure
1480 *
1481 * Since: 1.1.2
1482 **/
Richard Hughesdbd8c762018-06-15 20:31:40 +01001483gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001484fu_plugin_runner_update_prepare (FuPlugin *self, FwupdInstallFlags flags, FuDevice *device,
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -05001485 GError **error)
Richard Hughes7b8b2022016-12-12 16:15:03 +00001486{
Richard Hughes12724852018-09-04 13:53:44 +01001487 return fu_plugin_runner_flagged_device_generic (self, flags, device,
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -05001488 "fu_plugin_update_prepare",
1489 error);
Richard Hughes7b8b2022016-12-12 16:15:03 +00001490}
1491
Mario Limonciello1a680f32019-11-25 19:44:53 -06001492/**
1493 * fu_plugin_runner_update_cleanup:
1494 * @self: a #FuPlugin
1495 * @error: a #GError or NULL
1496 *
1497 * Runs the update_cleanup routine for the plugin
1498 *
1499 * Returns: #TRUE for success, #FALSE for failure
1500 *
1501 * Since: 1.1.2
1502 **/
Richard Hughes7b8b2022016-12-12 16:15:03 +00001503gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001504fu_plugin_runner_update_cleanup (FuPlugin *self, FwupdInstallFlags flags, FuDevice *device,
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -05001505 GError **error)
Richard Hughes7b8b2022016-12-12 16:15:03 +00001506{
Richard Hughes12724852018-09-04 13:53:44 +01001507 return fu_plugin_runner_flagged_device_generic (self, flags, device,
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -05001508 "fu_plugin_update_cleanup",
1509 error);
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001510}
Richard Hughes7b8b2022016-12-12 16:15:03 +00001511
Mario Limonciello1a680f32019-11-25 19:44:53 -06001512/**
1513 * fu_plugin_runner_update_attach:
1514 * @self: a #FuPlugin
1515 * @device: a #FuDevice
1516 * @error: a #GError or NULL
1517 *
1518 * Runs the update_attach routine for the plugin
1519 *
1520 * Returns: #TRUE for success, #FALSE for failure
1521 *
1522 * Since: 1.1.2
1523 **/
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001524gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001525fu_plugin_runner_update_attach (FuPlugin *self, FuDevice *device, GError **error)
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001526{
Richard Hughes12724852018-09-04 13:53:44 +01001527 return fu_plugin_runner_device_generic (self, device,
Richard Hughes4b303802019-10-04 13:22:51 +01001528 "fu_plugin_update_attach",
1529 fu_plugin_device_attach,
1530 error);
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001531}
Richard Hughes7b8b2022016-12-12 16:15:03 +00001532
Mario Limonciello1a680f32019-11-25 19:44:53 -06001533/**
1534 * fu_plugin_runner_update_detach:
1535 * @self: a #FuPlugin
1536 * @device: A #FuDevice
1537 * @error: a #GError or NULL
1538 *
1539 * Runs the update_detach routine for the plugin
1540 *
1541 * Returns: #TRUE for success, #FALSE for failure
1542 *
1543 * Since: 1.1.2
1544 **/
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001545gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001546fu_plugin_runner_update_detach (FuPlugin *self, FuDevice *device, GError **error)
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001547{
Richard Hughes12724852018-09-04 13:53:44 +01001548 return fu_plugin_runner_device_generic (self, device,
Richard Hughes4b303802019-10-04 13:22:51 +01001549 "fu_plugin_update_detach",
1550 fu_plugin_device_detach,
1551 error);
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001552}
1553
Mario Limonciello1a680f32019-11-25 19:44:53 -06001554/**
1555 * fu_plugin_runner_update_reload:
1556 * @self: a #FuPlugin
1557 * @error: a #GError or NULL
1558 *
1559 * Runs reload routine for a device
1560 *
1561 * Returns: #TRUE for success, #FALSE for failure
1562 *
1563 * Since: 1.1.2
1564 **/
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001565gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001566fu_plugin_runner_update_reload (FuPlugin *self, FuDevice *device, GError **error)
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001567{
Richard Hughes42f33df2019-10-05 20:52:33 +01001568 FuPluginPrivate *priv = GET_PRIVATE (self);
1569 g_autoptr(FuDeviceLocker) locker = NULL;
1570
1571 /* not enabled */
1572 if (!priv->enabled)
1573 return TRUE;
1574
1575 /* no object loaded */
1576 locker = fu_device_locker_new (device, error);
1577 if (locker == NULL)
1578 return FALSE;
1579 return fu_device_reload (device, error);
Richard Hughes7b8b2022016-12-12 16:15:03 +00001580}
1581
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001582/**
Richard Hughes196c6c62020-05-11 19:42:47 +01001583 * fu_plugin_runner_add_security_attrs:
1584 * @self: a #FuPlugin
1585 * @attrs: (element-type FwupdSecurityAttr): a #GPtrArray of attributes
1586 * @error: a #GError or NULL
1587 *
1588 * Runs the composite_prepare routine for the plugin
1589 *
1590 * Returns: #TRUE for success, #FALSE for failure
1591 *
1592 * Since: 1.5.0
1593 **/
1594gboolean
1595fu_plugin_runner_add_security_attrs (FuPlugin *self, GPtrArray *attrs, GError **error)
1596{
1597 return fu_plugin_runner_device_array_generic (self, attrs,
1598 "fu_plugin_add_security_attrs",
1599 error);
1600}
1601
1602/**
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001603 * fu_plugin_add_udev_subsystem:
Richard Hughes2c0635a2018-09-04 14:52:46 +01001604 * @self: a #FuPlugin
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001605 * @subsystem: a subsystem name, e.g. `pciport`
1606 *
1607 * Registers the udev subsystem to be watched by the daemon.
1608 *
1609 * Plugins can use this method only in fu_plugin_init()
Mario Limonciello1a680f32019-11-25 19:44:53 -06001610 *
1611 * Since: 1.1.2
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001612 **/
1613void
Richard Hughes12724852018-09-04 13:53:44 +01001614fu_plugin_add_udev_subsystem (FuPlugin *self, const gchar *subsystem)
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001615{
Richard Hughes12724852018-09-04 13:53:44 +01001616 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001617 for (guint i = 0; i < priv->udev_subsystems->len; i++) {
1618 const gchar *subsystem_tmp = g_ptr_array_index (priv->udev_subsystems, i);
1619 if (g_strcmp0 (subsystem_tmp, subsystem) == 0)
1620 return;
1621 }
1622 g_debug ("added udev subsystem watch of %s", subsystem);
1623 g_ptr_array_add (priv->udev_subsystems, g_strdup (subsystem));
1624}
1625
Richard Hughes989acf12019-10-05 20:16:47 +01001626/**
1627 * fu_plugin_set_device_gtype:
1628 * @self: a #FuPlugin
1629 * @device_gtype: a #GType `FU_TYPE_DEVICE`
1630 *
1631 * Sets the device #GType which is used when creating devices.
1632 *
1633 * If this method is used then fu_plugin_usb_device_added() is not called, and
1634 * instead the object is created in the daemon for the plugin.
1635 *
1636 * Plugins can use this method only in fu_plugin_init()
1637 *
1638 * Since: 1.3.3
1639 **/
1640void
1641fu_plugin_set_device_gtype (FuPlugin *self, GType device_gtype)
1642{
1643 FuPluginPrivate *priv = GET_PRIVATE (self);
1644 priv->device_gtype = device_gtype;
1645}
1646
Mario Limonciello1a680f32019-11-25 19:44:53 -06001647/**
1648 * fu_plugin_add_firmware_gtype:
1649 * @self: a #FuPlugin
1650 * @id: A string describing the type
1651 * @gtype: a #GType `FU_TYPE_DEVICE`
1652 *
1653 * Adds a firmware #GType which is used when creating devices.
1654 * *
1655 * Plugins can use this method only in fu_plugin_init()
1656 *
1657 * Since: 1.3.3
1658 **/
Richard Hughes95c98a92019-10-22 16:03:15 +01001659void
1660fu_plugin_add_firmware_gtype (FuPlugin *self, const gchar *id, GType gtype)
1661{
1662 g_signal_emit (self, signals[SIGNAL_ADD_FIRMWARE_GTYPE], 0, id, gtype);
1663}
1664
Richard Hughes989acf12019-10-05 20:16:47 +01001665static gboolean
Richard Hughesd8a8d5e2019-10-08 13:05:02 +01001666fu_plugin_check_supported_device (FuPlugin *self, FuDevice *device)
1667{
1668 GPtrArray *instance_ids = fu_device_get_instance_ids (device);
1669 for (guint i = 0; i < instance_ids->len; i++) {
1670 const gchar *instance_id = g_ptr_array_index (instance_ids, i);
1671 g_autofree gchar *guid = fwupd_guid_hash_string (instance_id);
1672 if (fu_plugin_check_supported (self, guid))
1673 return TRUE;
1674 }
1675 return FALSE;
1676}
1677
1678static gboolean
Richard Hughes989acf12019-10-05 20:16:47 +01001679fu_plugin_usb_device_added (FuPlugin *self, FuUsbDevice *device, GError **error)
1680{
1681 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughesd8a8d5e2019-10-08 13:05:02 +01001682 GType device_gtype = fu_device_get_specialized_gtype (FU_DEVICE (device));
Richard Hughes989acf12019-10-05 20:16:47 +01001683 g_autoptr(FuDevice) dev = NULL;
1684 g_autoptr(FuDeviceLocker) locker = NULL;
Richard Hughesd8a8d5e2019-10-08 13:05:02 +01001685
1686 /* fall back to plugin default */
1687 if (device_gtype == G_TYPE_INVALID)
1688 device_gtype = priv->device_gtype;
1689
1690 /* create new device and incorporate existing properties */
1691 dev = g_object_new (device_gtype, NULL);
1692 fu_device_incorporate (dev, FU_DEVICE (device));
Richard Hughes0f66a022020-02-19 18:54:38 +00001693 if (!fu_plugin_runner_device_created (self, dev, error))
1694 return FALSE;
Richard Hughesd8a8d5e2019-10-08 13:05:02 +01001695
1696 /* there are a lot of different devices that match, but not all respond
1697 * well to opening -- so limit some ones with issued updates */
1698 if (fu_device_has_flag (dev, FWUPD_DEVICE_FLAG_ONLY_SUPPORTED)) {
1699 if (!fu_device_probe (dev, error))
1700 return FALSE;
1701 fu_device_convert_instance_ids (dev);
1702 if (!fu_plugin_check_supported_device (self, dev)) {
1703 g_autofree gchar *guids = fu_device_get_guids_as_str (dev);
1704 g_debug ("%s has no updates, so ignoring device", guids);
1705 return TRUE;
1706 }
1707 }
1708
1709 /* open and add */
1710 locker = fu_device_locker_new (dev, error);
1711 if (locker == NULL)
1712 return FALSE;
1713 fu_plugin_device_add (self, dev);
Richard Hughes6a078702020-05-09 20:36:33 +01001714 fu_plugin_runner_device_added (self, dev);
Richard Hughesd8a8d5e2019-10-08 13:05:02 +01001715 return TRUE;
1716}
1717
1718static gboolean
Mario Limonciello096e3cf2020-04-28 15:01:33 -05001719fu_plugin_udev_device_changed (FuPlugin *self, FuUdevDevice *device, GError **error)
1720{
1721 g_autoptr(FuDeviceLocker) locker = NULL;
1722
1723 /* open */
1724 locker = fu_device_locker_new (FU_DEVICE (device), error);
1725 if (locker == NULL)
1726 return FALSE;
1727 return fu_device_rescan (FU_DEVICE (device), error);
1728}
1729
1730static gboolean
Richard Hughesd8a8d5e2019-10-08 13:05:02 +01001731fu_plugin_udev_device_added (FuPlugin *self, FuUdevDevice *device, GError **error)
1732{
1733 FuPluginPrivate *priv = GET_PRIVATE (self);
1734 GType device_gtype = fu_device_get_specialized_gtype (FU_DEVICE (device));
1735 g_autoptr(FuDevice) dev = NULL;
1736 g_autoptr(FuDeviceLocker) locker = NULL;
1737
1738 /* fall back to plugin default */
1739 if (device_gtype == G_TYPE_INVALID)
1740 device_gtype = priv->device_gtype;
1741
1742 /* create new device and incorporate existing properties */
1743 dev = g_object_new (device_gtype, NULL);
Richard Hughes989acf12019-10-05 20:16:47 +01001744 fu_device_incorporate (FU_DEVICE (dev), FU_DEVICE (device));
Richard Hughes0f66a022020-02-19 18:54:38 +00001745 if (!fu_plugin_runner_device_created (self, dev, error))
1746 return FALSE;
Richard Hughesd8a8d5e2019-10-08 13:05:02 +01001747
1748 /* there are a lot of different devices that match, but not all respond
1749 * well to opening -- so limit some ones with issued updates */
1750 if (fu_device_has_flag (dev, FWUPD_DEVICE_FLAG_ONLY_SUPPORTED)) {
1751 if (!fu_device_probe (dev, error))
1752 return FALSE;
1753 fu_device_convert_instance_ids (dev);
1754 if (!fu_plugin_check_supported_device (self, dev)) {
1755 g_autofree gchar *guids = fu_device_get_guids_as_str (dev);
1756 g_debug ("%s has no updates, so ignoring device", guids);
1757 return TRUE;
1758 }
1759 }
1760
1761 /* open and add */
Richard Hughes989acf12019-10-05 20:16:47 +01001762 locker = fu_device_locker_new (dev, error);
1763 if (locker == NULL)
1764 return FALSE;
1765 fu_plugin_device_add (self, FU_DEVICE (dev));
Richard Hughes6a078702020-05-09 20:36:33 +01001766 fu_plugin_runner_device_added (self, dev);
Richard Hughes989acf12019-10-05 20:16:47 +01001767 return TRUE;
1768}
1769
Mario Limonciello1a680f32019-11-25 19:44:53 -06001770/**
1771 * fu_plugin_runner_usb_device_added:
1772 * @self: a #FuPlugin
1773 * @device: a #FuUsbDevice
1774 * @error: a #GError or NULL
1775 *
1776 * Call the usb_device_added routine for the plugin
1777 *
1778 * Returns: #TRUE for success, #FALSE for failure
1779 *
1780 * Since: 1.0.2
1781 **/
Richard Hughes104f6512017-11-24 11:44:57 +00001782gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001783fu_plugin_runner_usb_device_added (FuPlugin *self, FuUsbDevice *device, GError **error)
Richard Hughes104f6512017-11-24 11:44:57 +00001784{
Richard Hughes12724852018-09-04 13:53:44 +01001785 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes104f6512017-11-24 11:44:57 +00001786 FuPluginUsbDeviceAddedFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001787 g_autoptr(GError) error_local = NULL;
Richard Hughes104f6512017-11-24 11:44:57 +00001788
1789 /* not enabled */
1790 if (!priv->enabled)
1791 return TRUE;
Richard Hughes639da472018-01-06 22:35:04 +00001792
1793 /* no object loaded */
Richard Hughes104f6512017-11-24 11:44:57 +00001794 if (priv->module == NULL)
1795 return TRUE;
1796
1797 /* optional */
1798 g_module_symbol (priv->module, "fu_plugin_usb_device_added", (gpointer *) &func);
Richard Hughes989acf12019-10-05 20:16:47 +01001799 if (func == NULL) {
Richard Hughesd8a8d5e2019-10-08 13:05:02 +01001800 if (priv->device_gtype != G_TYPE_INVALID ||
1801 fu_device_get_specialized_gtype (FU_DEVICE (device)) != G_TYPE_INVALID) {
Mario Limonciello0e500322019-10-17 18:41:04 -05001802 if (!fu_plugin_usb_device_added (self, device, error))
Mario Limoncielloa9be5362019-10-12 13:17:45 -05001803 return FALSE;
Richard Hughes989acf12019-10-05 20:16:47 +01001804 }
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001805 return TRUE;
Richard Hughes989acf12019-10-05 20:16:47 +01001806 }
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001807 g_debug ("performing usb_device_added() on %s", priv->name);
1808 if (!func (self, device, &error_local)) {
1809 if (error_local == NULL) {
1810 g_critical ("unset error in plugin %s for usb_device_added()",
1811 priv->name);
1812 g_set_error_literal (&error_local,
1813 FWUPD_ERROR,
1814 FWUPD_ERROR_INTERNAL,
1815 "unspecified error");
1816 }
1817 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1818 "failed to add device using on %s: ",
1819 priv->name);
1820 return FALSE;
Richard Hughes104f6512017-11-24 11:44:57 +00001821 }
1822 return TRUE;
1823}
1824
Mario Limonciello1a680f32019-11-25 19:44:53 -06001825/**
1826 * fu_plugin_runner_udev_device_added:
1827 * @self: a #FuPlugin
1828 * @device: a #FuUdevDevice
1829 * @error: a #GError or NULL
1830 *
1831 * Call the udev_device_added routine for the plugin
1832 *
1833 * Returns: #TRUE for success, #FALSE for failure
1834 *
1835 * Since: 1.0.2
1836 **/
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001837gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001838fu_plugin_runner_udev_device_added (FuPlugin *self, FuUdevDevice *device, GError **error)
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001839{
Richard Hughes12724852018-09-04 13:53:44 +01001840 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001841 FuPluginUdevDeviceAddedFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001842 g_autoptr(GError) error_local = NULL;
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001843
1844 /* not enabled */
1845 if (!priv->enabled)
1846 return TRUE;
1847
1848 /* no object loaded */
1849 if (priv->module == NULL)
1850 return TRUE;
1851
1852 /* optional */
1853 g_module_symbol (priv->module, "fu_plugin_udev_device_added", (gpointer *) &func);
Richard Hughesd8a8d5e2019-10-08 13:05:02 +01001854 if (func == NULL) {
1855 if (priv->device_gtype != G_TYPE_INVALID ||
1856 fu_device_get_specialized_gtype (FU_DEVICE (device)) != G_TYPE_INVALID) {
Mario Limonciello0e500322019-10-17 18:41:04 -05001857 if (!fu_plugin_udev_device_added (self, device, error))
Mario Limoncielloa9be5362019-10-12 13:17:45 -05001858 return FALSE;
Richard Hughesd8a8d5e2019-10-08 13:05:02 +01001859 }
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001860 return TRUE;
Richard Hughesd8a8d5e2019-10-08 13:05:02 +01001861 }
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001862 g_debug ("performing udev_device_added() on %s", priv->name);
1863 if (!func (self, device, &error_local)) {
1864 if (error_local == NULL) {
1865 g_critical ("unset error in plugin %s for udev_device_added()",
1866 priv->name);
1867 g_set_error_literal (&error_local,
1868 FWUPD_ERROR,
1869 FWUPD_ERROR_INTERNAL,
1870 "unspecified error");
1871 }
1872 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1873 "failed to add device using on %s: ",
1874 priv->name);
1875 return FALSE;
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001876 }
1877 return TRUE;
1878}
1879
Mario Limonciello1a680f32019-11-25 19:44:53 -06001880/**
1881 * fu_plugin_runner_udev_device_changed:
1882 * @self: a #FuPlugin
1883 * @device: a #FuUdevDevice
1884 * @error: a #GError or NULL
1885 *
1886 * Call the udev_device_changed routine for the plugin
1887 *
1888 * Returns: #TRUE for success, #FALSE for failure
1889 *
1890 * Since: 1.0.2
1891 **/
Richard Hughes5e952ce2019-08-26 11:09:46 +01001892gboolean
1893fu_plugin_runner_udev_device_changed (FuPlugin *self, FuUdevDevice *device, GError **error)
1894{
1895 FuPluginPrivate *priv = GET_PRIVATE (self);
1896 FuPluginUdevDeviceAddedFunc func = NULL;
1897 g_autoptr(GError) error_local = NULL;
1898
1899 /* not enabled */
1900 if (!priv->enabled)
1901 return TRUE;
1902
1903 /* no object loaded */
1904 if (priv->module == NULL)
1905 return TRUE;
1906
1907 /* optional */
1908 g_module_symbol (priv->module, "fu_plugin_udev_device_changed", (gpointer *) &func);
Mario Limonciello096e3cf2020-04-28 15:01:33 -05001909 if (func == NULL) {
1910 if (priv->device_gtype != G_TYPE_INVALID ||
1911 fu_device_get_specialized_gtype (FU_DEVICE (device)) != G_TYPE_INVALID) {
1912 if (!fu_plugin_udev_device_changed (self, device, error))
1913 return FALSE;
1914 }
Richard Hughes5e952ce2019-08-26 11:09:46 +01001915 return TRUE;
Mario Limonciello096e3cf2020-04-28 15:01:33 -05001916 }
Richard Hughes5e952ce2019-08-26 11:09:46 +01001917 g_debug ("performing udev_device_changed() on %s", priv->name);
1918 if (!func (self, device, &error_local)) {
1919 if (error_local == NULL) {
1920 g_critical ("unset error in plugin %s for udev_device_changed()",
1921 priv->name);
1922 g_set_error_literal (&error_local,
1923 FWUPD_ERROR,
1924 FWUPD_ERROR_INTERNAL,
1925 "unspecified error");
1926 }
1927 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1928 "failed to change device on %s: ",
1929 priv->name);
1930 return FALSE;
1931 }
1932 return TRUE;
1933}
1934
Mario Limonciello1a680f32019-11-25 19:44:53 -06001935/**
Richard Hughes6a078702020-05-09 20:36:33 +01001936 * fu_plugin_runner_device_added:
1937 * @self: a #FuPlugin
1938 * @device: a #FuDevice
1939 *
1940 * Call the device_added routine for the plugin
1941 *
1942 * Since: 1.5.0
1943 **/
1944void
1945fu_plugin_runner_device_added (FuPlugin *self, FuDevice *device)
1946{
1947 FuPluginPrivate *priv = GET_PRIVATE (self);
1948 FuPluginDeviceRegisterFunc func = NULL;
1949
1950 /* not enabled */
1951 if (!priv->enabled)
1952 return;
1953 if (priv->module == NULL)
1954 return;
1955
1956 /* optional */
1957 g_module_symbol (priv->module, "fu_plugin_device_added", (gpointer *) &func);
1958 if (func == NULL)
1959 return;
1960 g_debug ("performing fu_plugin_device_added() on %s", priv->name);
1961 func (self, device);
1962}
1963
1964/**
Mario Limonciello1a680f32019-11-25 19:44:53 -06001965 * fu_plugin_runner_device_removed:
1966 * @self: a #FuPlugin
1967 * @device: a #FuDevice
1968 *
1969 * Call the device_removed routine for the plugin
1970 *
1971 * Since: 1.1.2
1972 **/
Richard Hughese1fd34d2017-08-24 14:19:51 +01001973void
Richard Hughes12724852018-09-04 13:53:44 +01001974fu_plugin_runner_device_removed (FuPlugin *self, FuDevice *device)
Mario Limoncielloe260ead2018-09-01 09:19:24 -05001975{
1976 g_autoptr(GError) error_local= NULL;
1977
Richard Hughes12724852018-09-04 13:53:44 +01001978 if (!fu_plugin_runner_device_generic (self, device,
Mario Limoncielloe260ead2018-09-01 09:19:24 -05001979 "fu_plugin_device_removed",
Richard Hughes4b303802019-10-04 13:22:51 +01001980 NULL,
Mario Limoncielloe260ead2018-09-01 09:19:24 -05001981 &error_local))
1982 g_warning ("%s", error_local->message);
1983}
1984
Mario Limonciello1a680f32019-11-25 19:44:53 -06001985/**
1986 * fu_plugin_runner_device_register:
1987 * @self: a #FuPlugin
1988 * @device: a #FuDevice
1989 *
1990 * Call the device_registered routine for the plugin
1991 *
1992 * Since: 0.9.7
1993 **/
Mario Limoncielloe260ead2018-09-01 09:19:24 -05001994void
Richard Hughes12724852018-09-04 13:53:44 +01001995fu_plugin_runner_device_register (FuPlugin *self, FuDevice *device)
Richard Hughese1fd34d2017-08-24 14:19:51 +01001996{
Richard Hughes12724852018-09-04 13:53:44 +01001997 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughese1fd34d2017-08-24 14:19:51 +01001998 FuPluginDeviceRegisterFunc func = NULL;
1999
2000 /* not enabled */
2001 if (!priv->enabled)
2002 return;
Richard Hughes34834102017-11-21 21:55:00 +00002003 if (priv->module == NULL)
2004 return;
Richard Hughese1fd34d2017-08-24 14:19:51 +01002005
Mario Limonciello4910b242018-06-22 15:04:21 -05002006 /* don't notify plugins on their own devices */
Richard Hughes12724852018-09-04 13:53:44 +01002007 if (g_strcmp0 (fu_device_get_plugin (device), fu_plugin_get_name (self)) == 0)
Mario Limonciello4910b242018-06-22 15:04:21 -05002008 return;
2009
Richard Hughese1fd34d2017-08-24 14:19:51 +01002010 /* optional */
2011 g_module_symbol (priv->module, "fu_plugin_device_registered", (gpointer *) &func);
2012 if (func != NULL) {
Richard Hughes1bf7ff92018-08-24 20:21:35 +01002013 g_debug ("performing fu_plugin_device_registered() on %s", priv->name);
Richard Hughes12724852018-09-04 13:53:44 +01002014 func (self, device);
Richard Hughese1fd34d2017-08-24 14:19:51 +01002015 }
2016}
2017
Mario Limonciello1a680f32019-11-25 19:44:53 -06002018/**
Richard Hughes0f66a022020-02-19 18:54:38 +00002019 * fu_plugin_runner_device_created:
2020 * @self: a #FuPlugin
2021 * @device: a #FuDevice
2022 * @error: a #GError or NULL
2023 *
2024 * Call the device_created routine for the plugin
2025 *
2026 * Returns: #TRUE for success, #FALSE for failure
2027 *
Mario Limonciello96117d12020-02-28 10:17:56 -06002028 * Since: 1.4.0
Richard Hughes0f66a022020-02-19 18:54:38 +00002029 **/
2030gboolean
2031fu_plugin_runner_device_created (FuPlugin *self, FuDevice *device, GError **error)
2032{
2033 FuPluginPrivate *priv = GET_PRIVATE (self);
2034 FuPluginDeviceFunc func = NULL;
2035
2036 /* not enabled */
2037 if (!priv->enabled)
2038 return TRUE;
2039 if (priv->module == NULL)
2040 return TRUE;
2041
2042 /* optional */
2043 g_module_symbol (priv->module, "fu_plugin_device_created", (gpointer *) &func);
2044 if (func == NULL)
2045 return TRUE;
2046 g_debug ("performing fu_plugin_device_created() on %s", priv->name);
2047 return func (self, device, error);
2048}
2049
2050/**
Mario Limonciello1a680f32019-11-25 19:44:53 -06002051 * fu_plugin_runner_verify:
2052 * @self: a #FuPlugin
2053 * @device: a #FuDevice
2054 * @flags: #FuPluginVerifyFlags
2055 * @error: A #GError or NULL
2056 *
2057 * Call into the plugin's verify routine
2058 *
2059 * Returns: #TRUE for success, #FALSE for failure
2060 *
2061 * Since: 0.8.0
2062 **/
Richard Hughescff38bc2016-12-12 12:03:37 +00002063gboolean
Richard Hughes12724852018-09-04 13:53:44 +01002064fu_plugin_runner_verify (FuPlugin *self,
Richard Hughescff38bc2016-12-12 12:03:37 +00002065 FuDevice *device,
2066 FuPluginVerifyFlags flags,
2067 GError **error)
2068{
Richard Hughes12724852018-09-04 13:53:44 +01002069 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes7b8b2022016-12-12 16:15:03 +00002070 FuPluginVerifyFunc func = NULL;
Richard Hughesababbb72017-06-15 20:18:36 +01002071 GPtrArray *checksums;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00002072 g_autoptr(GError) error_local = NULL;
Richard Hughescff38bc2016-12-12 12:03:37 +00002073
2074 /* not enabled */
2075 if (!priv->enabled)
2076 return TRUE;
2077
Richard Hughes639da472018-01-06 22:35:04 +00002078 /* no object loaded */
2079 if (priv->module == NULL)
2080 return TRUE;
2081
Richard Hughescff38bc2016-12-12 12:03:37 +00002082 /* optional */
2083 g_module_symbol (priv->module, "fu_plugin_verify", (gpointer *) &func);
Richard Hughes7f677212019-10-05 16:19:40 +01002084 if (func == NULL) {
Richard Hughes7f677212019-10-05 16:19:40 +01002085 return fu_plugin_device_read_firmware (self, device, error);
2086 }
Richard Hughes1812fc72018-12-14 11:37:54 +00002087
2088 /* clear any existing verification checksums */
2089 checksums = fu_device_get_checksums (device);
2090 g_ptr_array_set_size (checksums, 0);
2091
Richard Hughesc9223be2019-03-18 08:46:42 +00002092 /* run additional detach */
2093 if (!fu_plugin_runner_device_generic (self, device,
Richard Hughes42f33df2019-10-05 20:52:33 +01002094 "fu_plugin_update_detach",
Richard Hughes4b303802019-10-04 13:22:51 +01002095 fu_plugin_device_detach,
Richard Hughesc9223be2019-03-18 08:46:42 +00002096 error))
2097 return FALSE;
2098
Richard Hughes1812fc72018-12-14 11:37:54 +00002099 /* run vfunc */
Richard Hughescff38bc2016-12-12 12:03:37 +00002100 g_debug ("performing verify() on %s", priv->name);
Richard Hughescd2fb3e2018-11-29 19:58:09 +00002101 if (!func (self, device, flags, &error_local)) {
Richard Hughesc9223be2019-03-18 08:46:42 +00002102 g_autoptr(GError) error_attach = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00002103 if (error_local == NULL) {
2104 g_critical ("unset error in plugin %s for verify()",
2105 priv->name);
2106 g_set_error_literal (&error_local,
2107 FWUPD_ERROR,
2108 FWUPD_ERROR_INTERNAL,
2109 "unspecified error");
2110 }
2111 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
2112 "failed to verify using %s: ",
2113 priv->name);
Richard Hughesc9223be2019-03-18 08:46:42 +00002114 /* make the device "work" again, but don't prefix the error */
2115 if (!fu_plugin_runner_device_generic (self, device,
Richard Hughes42f33df2019-10-05 20:52:33 +01002116 "fu_plugin_update_attach",
Richard Hughes4b303802019-10-04 13:22:51 +01002117 fu_plugin_device_attach,
Richard Hughesc9223be2019-03-18 08:46:42 +00002118 &error_attach)) {
2119 g_warning ("failed to attach whilst aborting verify(): %s",
2120 error_attach->message);
2121 }
Richard Hughesd0905142016-03-13 09:46:49 +00002122 return FALSE;
2123 }
Richard Hughesc9223be2019-03-18 08:46:42 +00002124
2125 /* run optional attach */
2126 if (!fu_plugin_runner_device_generic (self, device,
Richard Hughes42f33df2019-10-05 20:52:33 +01002127 "fu_plugin_update_attach",
Richard Hughes4b303802019-10-04 13:22:51 +01002128 fu_plugin_device_attach,
Richard Hughesc9223be2019-03-18 08:46:42 +00002129 error))
2130 return FALSE;
2131
2132 /* success */
Richard Hughesd0905142016-03-13 09:46:49 +00002133 return TRUE;
2134}
2135
Mario Limonciello1a680f32019-11-25 19:44:53 -06002136/**
2137 * fu_plugin_runner_activate:
2138 * @self: a #FuPlugin
2139 * @device: a #FuDevice
2140 * @error: A #GError or NULL
2141 *
2142 * Call into the plugin's activate routine
2143 *
2144 * Returns: #TRUE for success, #FALSE for failure
2145 *
2146 * Since: 1.2.6
2147 **/
Richard Hughesd0905142016-03-13 09:46:49 +00002148gboolean
Mario Limonciello96a0dd52019-02-25 13:50:03 -06002149fu_plugin_runner_activate (FuPlugin *self, FuDevice *device, GError **error)
2150{
2151 guint64 flags;
2152
2153 /* final check */
2154 flags = fu_device_get_flags (device);
2155 if ((flags & FWUPD_DEVICE_FLAG_NEEDS_ACTIVATION) == 0) {
2156 g_set_error (error,
2157 FWUPD_ERROR,
2158 FWUPD_ERROR_NOT_SUPPORTED,
2159 "Device %s does not need activation",
2160 fu_device_get_id (device));
2161 return FALSE;
2162 }
2163
2164 /* run vfunc */
2165 if (!fu_plugin_runner_device_generic (self, device,
Richard Hughes4b303802019-10-04 13:22:51 +01002166 "fu_plugin_activate",
2167 fu_plugin_device_activate,
2168 error))
Mario Limonciello96a0dd52019-02-25 13:50:03 -06002169 return FALSE;
2170
2171 /* update with correct flags */
2172 fu_device_remove_flag (device, FWUPD_DEVICE_FLAG_NEEDS_ACTIVATION);
2173 fu_device_set_modified (device, (guint64) g_get_real_time () / G_USEC_PER_SEC);
2174 return TRUE;
2175}
2176
Mario Limonciello1a680f32019-11-25 19:44:53 -06002177/**
2178 * fu_plugin_runner_unlock:
2179 * @self: a #FuPlugin
2180 * @device: a #FuDevice
2181 * @error: A #GError or NULL
2182 *
2183 * Call into the plugin's unlock routine
2184 *
2185 * Returns: #TRUE for success, #FALSE for failure
2186 *
2187 * Since: 0.8.0
2188 **/
Mario Limonciello96a0dd52019-02-25 13:50:03 -06002189gboolean
Richard Hughes12724852018-09-04 13:53:44 +01002190fu_plugin_runner_unlock (FuPlugin *self, FuDevice *device, GError **error)
Richard Hughesd0905142016-03-13 09:46:49 +00002191{
Richard Hughescff38bc2016-12-12 12:03:37 +00002192 guint64 flags;
Richard Hughescff38bc2016-12-12 12:03:37 +00002193
2194 /* final check */
2195 flags = fu_device_get_flags (device);
2196 if ((flags & FWUPD_DEVICE_FLAG_LOCKED) == 0) {
2197 g_set_error (error,
2198 FWUPD_ERROR,
2199 FWUPD_ERROR_NOT_SUPPORTED,
2200 "Device %s is not locked",
2201 fu_device_get_id (device));
2202 return FALSE;
2203 }
2204
Richard Hughes9c4b5312017-11-14 11:34:53 +00002205 /* run vfunc */
Richard Hughes12724852018-09-04 13:53:44 +01002206 if (!fu_plugin_runner_device_generic (self, device,
Richard Hughes4b303802019-10-04 13:22:51 +01002207 "fu_plugin_unlock",
2208 NULL,
2209 error))
Richard Hughes9c4b5312017-11-14 11:34:53 +00002210 return FALSE;
Richard Hughescff38bc2016-12-12 12:03:37 +00002211
2212 /* update with correct flags */
2213 flags = fu_device_get_flags (device);
2214 fu_device_set_flags (device, flags &= ~FWUPD_DEVICE_FLAG_LOCKED);
2215 fu_device_set_modified (device, (guint64) g_get_real_time () / G_USEC_PER_SEC);
2216 return TRUE;
2217}
2218
Mario Limonciello1a680f32019-11-25 19:44:53 -06002219/**
2220 * fu_plugin_runner_update:
2221 * @self: a #FuPlugin
2222 * @device: a #FuDevice
2223 * @blob_fw: A #GBytes
2224 * @flags: A #FwupdInstallFlags
2225 * @error: A #GError or NULL
2226 *
2227 * Call into the plugin's update routine
2228 *
2229 * Returns: #TRUE for success, #FALSE for failure
2230 *
2231 * Since: 0.8.0
2232 **/
Richard Hughescff38bc2016-12-12 12:03:37 +00002233gboolean
Richard Hughes12724852018-09-04 13:53:44 +01002234fu_plugin_runner_update (FuPlugin *self,
Richard Hughesa785a1c2017-08-25 16:00:58 +01002235 FuDevice *device,
Richard Hughesa785a1c2017-08-25 16:00:58 +01002236 GBytes *blob_fw,
2237 FwupdInstallFlags flags,
2238 GError **error)
Richard Hughescff38bc2016-12-12 12:03:37 +00002239{
Richard Hughes12724852018-09-04 13:53:44 +01002240 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughesa785a1c2017-08-25 16:00:58 +01002241 FuPluginUpdateFunc update_func;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00002242 g_autoptr(GError) error_local = NULL;
Richard Hughescff38bc2016-12-12 12:03:37 +00002243
2244 /* not enabled */
Richard Hughes41c15482018-02-01 22:07:21 +00002245 if (!priv->enabled) {
2246 g_debug ("plugin not enabled, skipping");
Richard Hughesd0905142016-03-13 09:46:49 +00002247 return TRUE;
Richard Hughes41c15482018-02-01 22:07:21 +00002248 }
Richard Hughesd0905142016-03-13 09:46:49 +00002249
Richard Hughes639da472018-01-06 22:35:04 +00002250 /* no object loaded */
Richard Hughes41c15482018-02-01 22:07:21 +00002251 if (priv->module == NULL) {
2252 g_debug ("module not enabled, skipping");
Richard Hughes639da472018-01-06 22:35:04 +00002253 return TRUE;
Richard Hughes41c15482018-02-01 22:07:21 +00002254 }
Richard Hughes639da472018-01-06 22:35:04 +00002255
Richard Hughesd0905142016-03-13 09:46:49 +00002256 /* optional */
Richard Hughesa785a1c2017-08-25 16:00:58 +01002257 g_module_symbol (priv->module, "fu_plugin_update", (gpointer *) &update_func);
2258 if (update_func == NULL) {
Richard Hughes4b303802019-10-04 13:22:51 +01002259 g_debug ("running superclassed write_firmware() on %s", priv->name);
2260 return fu_plugin_device_write_firmware (self, device, blob_fw, flags, error);
Richard Hughesa785a1c2017-08-25 16:00:58 +01002261 }
Richard Hughesd0905142016-03-13 09:46:49 +00002262
Richard Hughescff38bc2016-12-12 12:03:37 +00002263 /* online */
Richard Hughescd2fb3e2018-11-29 19:58:09 +00002264 if (!update_func (self, device, blob_fw, flags, &error_local)) {
2265 if (error_local == NULL) {
2266 g_critical ("unset error in plugin %s for update()",
2267 priv->name);
2268 g_set_error_literal (&error_local,
Richard Hughes3c8ada32018-10-12 10:08:58 +01002269 FWUPD_ERROR,
2270 FWUPD_ERROR_INTERNAL,
2271 "unspecified error");
Richard Hughescd2fb3e2018-11-29 19:58:09 +00002272 return FALSE;
Richard Hughes3c8ada32018-10-12 10:08:58 +01002273 }
Richard Hughescd2fb3e2018-11-29 19:58:09 +00002274 fu_device_set_update_error (device, error_local->message);
2275 g_propagate_error (error, g_steal_pointer (&error_local));
Richard Hughescff38bc2016-12-12 12:03:37 +00002276 return FALSE;
2277 }
2278
Richard Hughesf556d372017-06-15 19:49:18 +01002279 /* no longer valid */
Richard Hughesf8039642019-01-16 12:22:22 +00002280 if (!fu_device_has_flag (device, FWUPD_DEVICE_FLAG_NEEDS_REBOOT) &&
2281 !fu_device_has_flag (device, FWUPD_DEVICE_FLAG_NEEDS_SHUTDOWN)) {
Richard Hughes08435162018-12-12 10:34:16 +00002282 GPtrArray *checksums = fu_device_get_checksums (device);
2283 g_ptr_array_set_size (checksums, 0);
2284 }
Richard Hughesf556d372017-06-15 19:49:18 +01002285
Richard Hughes019a1bc2019-11-26 10:19:33 +00002286 /* success */
Richard Hughesd0905142016-03-13 09:46:49 +00002287 return TRUE;
2288}
Richard Hughescff38bc2016-12-12 12:03:37 +00002289
Mario Limonciello1a680f32019-11-25 19:44:53 -06002290/**
2291 * fu_plugin_runner_clear_results:
2292 * @self: a #FuPlugin
2293 * @device: a #FuDevice
2294 * @error: A #GError or NULL
2295 *
2296 * Call into the plugin's clear results routine
2297 *
2298 * Returns: #TRUE for success, #FALSE for failure
2299 *
2300 * Since: 0.8.0
2301 **/
Richard Hughescff38bc2016-12-12 12:03:37 +00002302gboolean
Richard Hughes12724852018-09-04 13:53:44 +01002303fu_plugin_runner_clear_results (FuPlugin *self, FuDevice *device, GError **error)
Richard Hughescff38bc2016-12-12 12:03:37 +00002304{
Richard Hughes12724852018-09-04 13:53:44 +01002305 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes7b8b2022016-12-12 16:15:03 +00002306 FuPluginDeviceFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00002307 g_autoptr(GError) error_local = NULL;
Richard Hughescff38bc2016-12-12 12:03:37 +00002308
2309 /* not enabled */
2310 if (!priv->enabled)
2311 return TRUE;
2312
Richard Hughes639da472018-01-06 22:35:04 +00002313 /* no object loaded */
2314 if (priv->module == NULL)
2315 return TRUE;
2316
Richard Hughes65e44ca2018-01-30 17:26:30 +00002317 /* optional */
Richard Hughescd644902019-11-01 12:35:17 +00002318 g_module_symbol (priv->module, "fu_plugin_clear_results", (gpointer *) &func);
Richard Hughes65e44ca2018-01-30 17:26:30 +00002319 if (func == NULL)
Richard Hughescff38bc2016-12-12 12:03:37 +00002320 return TRUE;
Richard Hughes65e44ca2018-01-30 17:26:30 +00002321 g_debug ("performing clear_result() on %s", priv->name);
Richard Hughescd2fb3e2018-11-29 19:58:09 +00002322 if (!func (self, device, &error_local)) {
2323 if (error_local == NULL) {
2324 g_critical ("unset error in plugin %s for clear_result()",
2325 priv->name);
2326 g_set_error_literal (&error_local,
2327 FWUPD_ERROR,
2328 FWUPD_ERROR_INTERNAL,
2329 "unspecified error");
2330 }
2331 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
2332 "failed to clear_result using %s: ",
2333 priv->name);
Richard Hughescff38bc2016-12-12 12:03:37 +00002334 return FALSE;
2335 }
Richard Hughes65e44ca2018-01-30 17:26:30 +00002336 return TRUE;
Richard Hughescff38bc2016-12-12 12:03:37 +00002337}
2338
Mario Limonciello1a680f32019-11-25 19:44:53 -06002339/**
2340 * fu_plugin_runner_get_results:
2341 * @self: a #FuPlugin
2342 * @device: a #FuDevice
2343 * @error: A #GError or NULL
2344 *
2345 * Call into the plugin's get results routine
2346 *
2347 * Returns: #TRUE for success, #FALSE for failure
2348 *
2349 * Since: 0.8.0
2350 **/
Richard Hughescff38bc2016-12-12 12:03:37 +00002351gboolean
Richard Hughes12724852018-09-04 13:53:44 +01002352fu_plugin_runner_get_results (FuPlugin *self, FuDevice *device, GError **error)
Richard Hughescff38bc2016-12-12 12:03:37 +00002353{
Richard Hughes12724852018-09-04 13:53:44 +01002354 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes7b8b2022016-12-12 16:15:03 +00002355 FuPluginDeviceFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00002356 g_autoptr(GError) error_local = NULL;
Richard Hughescff38bc2016-12-12 12:03:37 +00002357
2358 /* not enabled */
2359 if (!priv->enabled)
2360 return TRUE;
2361
Richard Hughes639da472018-01-06 22:35:04 +00002362 /* no object loaded */
2363 if (priv->module == NULL)
2364 return TRUE;
2365
Richard Hughes65e44ca2018-01-30 17:26:30 +00002366 /* optional */
Richard Hughescff38bc2016-12-12 12:03:37 +00002367 g_module_symbol (priv->module, "fu_plugin_get_results", (gpointer *) &func);
Richard Hughes65e44ca2018-01-30 17:26:30 +00002368 if (func == NULL)
Richard Hughescff38bc2016-12-12 12:03:37 +00002369 return TRUE;
Richard Hughes65e44ca2018-01-30 17:26:30 +00002370 g_debug ("performing get_results() on %s", priv->name);
Richard Hughescd2fb3e2018-11-29 19:58:09 +00002371 if (!func (self, device, &error_local)) {
2372 if (error_local == NULL) {
2373 g_critical ("unset error in plugin %s for get_results()",
2374 priv->name);
2375 g_set_error_literal (&error_local,
2376 FWUPD_ERROR,
2377 FWUPD_ERROR_INTERNAL,
2378 "unspecified error");
2379 }
2380 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
2381 "failed to get_results using %s: ",
2382 priv->name);
Richard Hughescff38bc2016-12-12 12:03:37 +00002383 return FALSE;
2384 }
Richard Hughescff38bc2016-12-12 12:03:37 +00002385 return TRUE;
2386}
2387
Richard Hughes08a37992017-09-12 12:57:43 +01002388/**
2389 * fu_plugin_get_order:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002390 * @self: a #FuPlugin
Richard Hughes08a37992017-09-12 12:57:43 +01002391 *
2392 * Gets the plugin order, where higher numbers are run after lower
2393 * numbers.
2394 *
2395 * Returns: the integer value
Mario Limonciello1a680f32019-11-25 19:44:53 -06002396 *
2397 * Since: 1.0.0
Richard Hughes08a37992017-09-12 12:57:43 +01002398 **/
2399guint
Richard Hughes12724852018-09-04 13:53:44 +01002400fu_plugin_get_order (FuPlugin *self)
Richard Hughes08a37992017-09-12 12:57:43 +01002401{
Richard Hughes12724852018-09-04 13:53:44 +01002402 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughes08a37992017-09-12 12:57:43 +01002403 return priv->order;
2404}
2405
2406/**
2407 * fu_plugin_set_order:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002408 * @self: a #FuPlugin
Richard Hughes08a37992017-09-12 12:57:43 +01002409 * @order: a integer value
2410 *
2411 * Sets the plugin order, where higher numbers are run after lower
2412 * numbers.
Mario Limonciello1a680f32019-11-25 19:44:53 -06002413 *
2414 * Since: 1.0.0
Richard Hughes08a37992017-09-12 12:57:43 +01002415 **/
2416void
Richard Hughes12724852018-09-04 13:53:44 +01002417fu_plugin_set_order (FuPlugin *self, guint order)
Richard Hughes08a37992017-09-12 12:57:43 +01002418{
Richard Hughes12724852018-09-04 13:53:44 +01002419 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughes08a37992017-09-12 12:57:43 +01002420 priv->order = order;
2421}
2422
2423/**
Richard Hughes81c427c2018-08-06 15:20:17 +01002424 * fu_plugin_get_priority:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002425 * @self: a #FuPlugin
Richard Hughes81c427c2018-08-06 15:20:17 +01002426 *
2427 * Gets the plugin priority, where higher numbers are better.
2428 *
2429 * Returns: the integer value
Mario Limonciello1a680f32019-11-25 19:44:53 -06002430 *
2431 * Since: 1.1.1
Richard Hughes81c427c2018-08-06 15:20:17 +01002432 **/
2433guint
Richard Hughes12724852018-09-04 13:53:44 +01002434fu_plugin_get_priority (FuPlugin *self)
Richard Hughes81c427c2018-08-06 15:20:17 +01002435{
Richard Hughes12724852018-09-04 13:53:44 +01002436 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughes81c427c2018-08-06 15:20:17 +01002437 return priv->priority;
2438}
2439
2440/**
2441 * fu_plugin_set_priority:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002442 * @self: a #FuPlugin
Richard Hughes81c427c2018-08-06 15:20:17 +01002443 * @priority: a integer value
2444 *
2445 * Sets the plugin priority, where higher numbers are better.
Mario Limonciello1a680f32019-11-25 19:44:53 -06002446 *
2447 * Since: 1.0.0
Richard Hughes81c427c2018-08-06 15:20:17 +01002448 **/
2449void
Richard Hughes12724852018-09-04 13:53:44 +01002450fu_plugin_set_priority (FuPlugin *self, guint priority)
Richard Hughes81c427c2018-08-06 15:20:17 +01002451{
Richard Hughes12724852018-09-04 13:53:44 +01002452 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughes81c427c2018-08-06 15:20:17 +01002453 priv->priority = priority;
2454}
2455
2456/**
Richard Hughes08a37992017-09-12 12:57:43 +01002457 * fu_plugin_add_rule:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002458 * @self: a #FuPlugin
Richard Hughes08a37992017-09-12 12:57:43 +01002459 * @rule: a #FuPluginRule, e.g. %FU_PLUGIN_RULE_CONFLICTS
Richard Hughes4eada342017-10-03 21:20:32 +01002460 * @name: a plugin name, e.g. `upower`
Richard Hughes08a37992017-09-12 12:57:43 +01002461 *
2462 * If the plugin name is found, the rule will be used to sort the plugin list,
2463 * for example the plugin specified by @name will be ordered after this plugin
2464 * when %FU_PLUGIN_RULE_RUN_AFTER is used.
2465 *
2466 * NOTE: The depsolver is iterative and may not solve overly-complicated rules;
2467 * If depsolving fails then fwupd will not start.
Mario Limonciello1a680f32019-11-25 19:44:53 -06002468 *
2469 * Since: 1.0.0
Richard Hughes08a37992017-09-12 12:57:43 +01002470 **/
2471void
Richard Hughes12724852018-09-04 13:53:44 +01002472fu_plugin_add_rule (FuPlugin *self, FuPluginRule rule, const gchar *name)
Richard Hughes08a37992017-09-12 12:57:43 +01002473{
Richard Hughes12724852018-09-04 13:53:44 +01002474 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughes08a37992017-09-12 12:57:43 +01002475 g_ptr_array_add (priv->rules[rule], g_strdup (name));
Richard Hughes75b965d2018-11-15 13:51:21 +00002476 g_signal_emit (self, signals[SIGNAL_RULES_CHANGED], 0);
Richard Hughes08a37992017-09-12 12:57:43 +01002477}
2478
2479/**
2480 * fu_plugin_get_rules:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002481 * @self: a #FuPlugin
Richard Hughes08a37992017-09-12 12:57:43 +01002482 * @rule: a #FuPluginRule, e.g. %FU_PLUGIN_RULE_CONFLICTS
2483 *
2484 * Gets the plugin IDs that should be run after this plugin.
2485 *
2486 * Returns: (element-type utf8) (transfer none): the list of plugin names, e.g. ['appstream']
Mario Limonciello1a680f32019-11-25 19:44:53 -06002487 *
2488 * Since: 1.0.0
Richard Hughes08a37992017-09-12 12:57:43 +01002489 **/
2490GPtrArray *
Richard Hughes12724852018-09-04 13:53:44 +01002491fu_plugin_get_rules (FuPlugin *self, FuPluginRule rule)
Richard Hughes08a37992017-09-12 12:57:43 +01002492{
Richard Hughes12724852018-09-04 13:53:44 +01002493 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughesdad35972019-12-06 11:00:25 +00002494 g_return_val_if_fail (rule < FU_PLUGIN_RULE_LAST, NULL);
Richard Hughes08a37992017-09-12 12:57:43 +01002495 return priv->rules[rule];
2496}
2497
Richard Hughes80b79bb2018-01-11 21:11:06 +00002498/**
Richard Hughes5f3a56b2018-06-28 12:13:59 +01002499 * fu_plugin_has_rule:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002500 * @self: a #FuPlugin
Richard Hughes5f3a56b2018-06-28 12:13:59 +01002501 * @rule: a #FuPluginRule, e.g. %FU_PLUGIN_RULE_CONFLICTS
2502 * @name: a plugin name, e.g. `upower`
2503 *
Richard Hughes87fb9ff2018-06-28 12:55:59 +01002504 * Gets the plugin IDs that should be run after this plugin.
Richard Hughes5f3a56b2018-06-28 12:13:59 +01002505 *
2506 * Returns: %TRUE if the name exists for the specific rule
Mario Limonciello1a680f32019-11-25 19:44:53 -06002507 *
2508 * Since: 1.0.0
Richard Hughes5f3a56b2018-06-28 12:13:59 +01002509 **/
2510gboolean
Richard Hughes12724852018-09-04 13:53:44 +01002511fu_plugin_has_rule (FuPlugin *self, FuPluginRule rule, const gchar *name)
Richard Hughes5f3a56b2018-06-28 12:13:59 +01002512{
Richard Hughes12724852018-09-04 13:53:44 +01002513 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughes5f3a56b2018-06-28 12:13:59 +01002514 for (guint i = 0; i < priv->rules[rule]->len; i++) {
2515 const gchar *tmp = g_ptr_array_index (priv->rules[rule], i);
2516 if (g_strcmp0 (tmp, name) == 0)
2517 return TRUE;
2518 }
2519 return FALSE;
2520}
2521
2522/**
Richard Hughes80b79bb2018-01-11 21:11:06 +00002523 * fu_plugin_add_report_metadata:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002524 * @self: a #FuPlugin
Richard Hughes80b79bb2018-01-11 21:11:06 +00002525 * @key: a string, e.g. `FwupdateVersion`
2526 * @value: a string, e.g. `10`
2527 *
2528 * Sets any additional metadata to be included in the firmware report to aid
2529 * debugging problems.
2530 *
2531 * Any data included here will be sent to the metadata server after user
2532 * confirmation.
Mario Limonciello1a680f32019-11-25 19:44:53 -06002533 *
2534 * Since: 1.0.4
Richard Hughes80b79bb2018-01-11 21:11:06 +00002535 **/
2536void
Richard Hughes12724852018-09-04 13:53:44 +01002537fu_plugin_add_report_metadata (FuPlugin *self, const gchar *key, const gchar *value)
Richard Hughes80b79bb2018-01-11 21:11:06 +00002538{
Richard Hughes12724852018-09-04 13:53:44 +01002539 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughes80b79bb2018-01-11 21:11:06 +00002540 g_hash_table_insert (priv->report_metadata, g_strdup (key), g_strdup (value));
2541}
2542
2543/**
2544 * fu_plugin_get_report_metadata:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002545 * @self: a #FuPlugin
Richard Hughes80b79bb2018-01-11 21:11:06 +00002546 *
2547 * Returns the list of additional metadata to be added when filing a report.
2548 *
2549 * Returns: (transfer none): the map of report metadata
Mario Limonciello1a680f32019-11-25 19:44:53 -06002550 *
2551 * Since: 1.0.4
Richard Hughes80b79bb2018-01-11 21:11:06 +00002552 **/
2553GHashTable *
Richard Hughes12724852018-09-04 13:53:44 +01002554fu_plugin_get_report_metadata (FuPlugin *self)
Richard Hughes80b79bb2018-01-11 21:11:06 +00002555{
Richard Hughes12724852018-09-04 13:53:44 +01002556 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughes80b79bb2018-01-11 21:11:06 +00002557 return priv->report_metadata;
2558}
2559
Mario Limonciello963dc422018-02-27 14:26:58 -06002560/**
2561 * fu_plugin_get_config_value:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002562 * @self: a #FuPlugin
Mario Limonciello963dc422018-02-27 14:26:58 -06002563 * @key: A settings key
2564 *
2565 * Return the value of a key if it's been configured
2566 *
2567 * Since: 1.0.6
2568 **/
2569gchar *
Richard Hughes12724852018-09-04 13:53:44 +01002570fu_plugin_get_config_value (FuPlugin *self, const gchar *key)
Mario Limonciello963dc422018-02-27 14:26:58 -06002571{
Richard Hughes4be17d12018-05-30 20:36:29 +01002572 g_autofree gchar *conf_dir = NULL;
Mario Limonciello963dc422018-02-27 14:26:58 -06002573 g_autofree gchar *conf_file = NULL;
2574 g_autofree gchar *conf_path = NULL;
2575 g_autoptr(GKeyFile) keyfile = NULL;
2576 const gchar *plugin_name;
2577
Richard Hughes4be17d12018-05-30 20:36:29 +01002578 conf_dir = fu_common_get_path (FU_PATH_KIND_SYSCONFDIR_PKG);
Richard Hughes12724852018-09-04 13:53:44 +01002579 plugin_name = fu_plugin_get_name (self);
Mario Limonciello963dc422018-02-27 14:26:58 -06002580 conf_file = g_strdup_printf ("%s.conf", plugin_name);
Richard Hughes4be17d12018-05-30 20:36:29 +01002581 conf_path = g_build_filename (conf_dir, conf_file, NULL);
Mario Limonciello963dc422018-02-27 14:26:58 -06002582 if (!g_file_test (conf_path, G_FILE_TEST_IS_REGULAR))
2583 return NULL;
2584 keyfile = g_key_file_new ();
2585 if (!g_key_file_load_from_file (keyfile, conf_path,
2586 G_KEY_FILE_NONE, NULL))
2587 return NULL;
2588 return g_key_file_get_string (keyfile, plugin_name, key, NULL);
2589}
2590
Richard Hughes8c71a3f2018-05-22 19:19:52 +01002591/**
Richard Hughes334ba792020-02-19 20:44:56 +00002592 * fu_plugin_get_config_value_boolean:
2593 * @self: a #FuPlugin
2594 * @key: A settings key
2595 *
2596 * Return the boolean value of a key if it's been configured
2597 *
2598 * Returns: %TRUE if the value is `true` (case insensitive), %FALSE otherwise
2599 *
Mario Limonciello96117d12020-02-28 10:17:56 -06002600 * Since: 1.4.0
Richard Hughes334ba792020-02-19 20:44:56 +00002601 **/
2602gboolean
2603fu_plugin_get_config_value_boolean (FuPlugin *self, const gchar *key)
2604{
2605 g_autofree gchar *tmp = fu_plugin_get_config_value (self, key);
2606 if (tmp == NULL)
2607 return FALSE;
Richard Hughes5337a432020-02-21 12:04:32 +00002608 return g_ascii_strcasecmp (tmp, "true") == 0;
Richard Hughes334ba792020-02-19 20:44:56 +00002609}
2610
2611/**
Richard Hughes8c71a3f2018-05-22 19:19:52 +01002612 * fu_plugin_name_compare:
2613 * @plugin1: first #FuPlugin to compare.
2614 * @plugin2: second #FuPlugin to compare.
2615 *
2616 * Compares two plugins by their names.
2617 *
2618 * Returns: 1, 0 or -1 if @plugin1 is greater, equal, or less than @plugin2.
Mario Limonciello1a680f32019-11-25 19:44:53 -06002619 *
2620 * Since: 1.0.8
Richard Hughes8c71a3f2018-05-22 19:19:52 +01002621 **/
2622gint
2623fu_plugin_name_compare (FuPlugin *plugin1, FuPlugin *plugin2)
2624{
2625 FuPluginPrivate *priv1 = fu_plugin_get_instance_private (plugin1);
2626 FuPluginPrivate *priv2 = fu_plugin_get_instance_private (plugin2);
2627 return g_strcmp0 (priv1->name, priv2->name);
2628}
2629
2630/**
2631 * fu_plugin_order_compare:
2632 * @plugin1: first #FuPlugin to compare.
2633 * @plugin2: second #FuPlugin to compare.
2634 *
2635 * Compares two plugins by their depsolved order.
2636 *
2637 * Returns: 1, 0 or -1 if @plugin1 is greater, equal, or less than @plugin2.
Mario Limonciello1a680f32019-11-25 19:44:53 -06002638 *
2639 * Since: 1.0.8
Richard Hughes8c71a3f2018-05-22 19:19:52 +01002640 **/
2641gint
2642fu_plugin_order_compare (FuPlugin *plugin1, FuPlugin *plugin2)
2643{
2644 FuPluginPrivate *priv1 = fu_plugin_get_instance_private (plugin1);
2645 FuPluginPrivate *priv2 = fu_plugin_get_instance_private (plugin2);
2646 if (priv1->order < priv2->order)
2647 return -1;
2648 if (priv1->order > priv2->order)
2649 return 1;
2650 return 0;
2651}
2652
Richard Hughescff38bc2016-12-12 12:03:37 +00002653static void
2654fu_plugin_class_init (FuPluginClass *klass)
2655{
2656 GObjectClass *object_class = G_OBJECT_CLASS (klass);
2657 object_class->finalize = fu_plugin_finalize;
2658 signals[SIGNAL_DEVICE_ADDED] =
2659 g_signal_new ("device-added",
2660 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
2661 G_STRUCT_OFFSET (FuPluginClass, device_added),
2662 NULL, NULL, g_cclosure_marshal_VOID__OBJECT,
2663 G_TYPE_NONE, 1, FU_TYPE_DEVICE);
2664 signals[SIGNAL_DEVICE_REMOVED] =
2665 g_signal_new ("device-removed",
2666 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
2667 G_STRUCT_OFFSET (FuPluginClass, device_removed),
2668 NULL, NULL, g_cclosure_marshal_VOID__OBJECT,
2669 G_TYPE_NONE, 1, FU_TYPE_DEVICE);
Richard Hughese1fd34d2017-08-24 14:19:51 +01002670 signals[SIGNAL_DEVICE_REGISTER] =
2671 g_signal_new ("device-register",
2672 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
2673 G_STRUCT_OFFSET (FuPluginClass, device_register),
2674 NULL, NULL, g_cclosure_marshal_VOID__OBJECT,
2675 G_TYPE_NONE, 1, FU_TYPE_DEVICE);
Richard Hughes362d6d72017-01-07 21:42:14 +00002676 signals[SIGNAL_RECOLDPLUG] =
2677 g_signal_new ("recoldplug",
2678 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
2679 G_STRUCT_OFFSET (FuPluginClass, recoldplug),
2680 NULL, NULL, g_cclosure_marshal_VOID__VOID,
2681 G_TYPE_NONE, 0);
Richard Hughesb0829032017-01-10 09:27:08 +00002682 signals[SIGNAL_SET_COLDPLUG_DELAY] =
2683 g_signal_new ("set-coldplug-delay",
2684 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
2685 G_STRUCT_OFFSET (FuPluginClass, set_coldplug_delay),
2686 NULL, NULL, g_cclosure_marshal_VOID__UINT,
2687 G_TYPE_NONE, 1, G_TYPE_UINT);
Richard Hughesaabdc372018-11-14 10:11:08 +00002688 signals[SIGNAL_CHECK_SUPPORTED] =
2689 g_signal_new ("check-supported",
2690 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
2691 G_STRUCT_OFFSET (FuPluginClass, check_supported),
2692 NULL, NULL, g_cclosure_marshal_generic,
2693 G_TYPE_BOOLEAN, 1, G_TYPE_STRING);
Richard Hughes75b965d2018-11-15 13:51:21 +00002694 signals[SIGNAL_RULES_CHANGED] =
2695 g_signal_new ("rules-changed",
2696 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
2697 G_STRUCT_OFFSET (FuPluginClass, rules_changed),
2698 NULL, NULL, g_cclosure_marshal_VOID__VOID,
2699 G_TYPE_NONE, 0);
Richard Hughes95c98a92019-10-22 16:03:15 +01002700 signals[SIGNAL_ADD_FIRMWARE_GTYPE] =
2701 g_signal_new ("add-firmware-gtype",
2702 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
2703 G_STRUCT_OFFSET (FuPluginClass, add_firmware_gtype),
2704 NULL, NULL, g_cclosure_marshal_generic,
2705 G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_GTYPE);
Richard Hughescff38bc2016-12-12 12:03:37 +00002706}
2707
2708static void
Richard Hughes12724852018-09-04 13:53:44 +01002709fu_plugin_init (FuPlugin *self)
Richard Hughescff38bc2016-12-12 12:03:37 +00002710{
Richard Hughes12724852018-09-04 13:53:44 +01002711 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughescff38bc2016-12-12 12:03:37 +00002712 priv->enabled = TRUE;
Richard Hughesb1065422019-08-15 16:44:34 +01002713 priv->udev_subsystems = g_ptr_array_new_with_free_func (g_free);
Richard Hughescff38bc2016-12-12 12:03:37 +00002714 priv->devices = g_hash_table_new_full (g_str_hash, g_str_equal,
2715 g_free, (GDestroyNotify) g_object_unref);
Richard Hughes161e9b52019-06-12 14:22:45 +01002716 g_rw_lock_init (&priv->devices_mutex);
Richard Hughes80b79bb2018-01-11 21:11:06 +00002717 priv->report_metadata = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
Richard Hughes08a37992017-09-12 12:57:43 +01002718 for (guint i = 0; i < FU_PLUGIN_RULE_LAST; i++)
2719 priv->rules[i] = g_ptr_array_new_with_free_func (g_free);
Richard Hughescff38bc2016-12-12 12:03:37 +00002720}
2721
2722static void
2723fu_plugin_finalize (GObject *object)
2724{
Richard Hughes12724852018-09-04 13:53:44 +01002725 FuPlugin *self = FU_PLUGIN (object);
2726 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughescff38bc2016-12-12 12:03:37 +00002727 FuPluginInitFunc func = NULL;
2728
2729 /* optional */
2730 if (priv->module != NULL) {
2731 g_module_symbol (priv->module, "fu_plugin_destroy", (gpointer *) &func);
2732 if (func != NULL) {
2733 g_debug ("performing destroy() on %s", priv->name);
Richard Hughes12724852018-09-04 13:53:44 +01002734 func (self);
Richard Hughescff38bc2016-12-12 12:03:37 +00002735 }
2736 }
2737
Richard Hughes08a37992017-09-12 12:57:43 +01002738 for (guint i = 0; i < FU_PLUGIN_RULE_LAST; i++)
2739 g_ptr_array_unref (priv->rules[i]);
2740
Richard Hughescff38bc2016-12-12 12:03:37 +00002741 if (priv->usb_ctx != NULL)
2742 g_object_unref (priv->usb_ctx);
Richard Hughesb8f8db22017-04-25 15:56:00 +01002743 if (priv->hwids != NULL)
Richard Hughesd7704d42017-08-08 20:29:09 +01002744 g_object_unref (priv->hwids);
Richard Hughes9c028f02017-10-28 21:14:28 +01002745 if (priv->quirks != NULL)
2746 g_object_unref (priv->quirks);
Richard Hughes9d6e0e72018-08-24 20:20:17 +01002747 if (priv->udev_subsystems != NULL)
2748 g_ptr_array_unref (priv->udev_subsystems);
Richard Hughes49e5e052017-09-03 12:15:41 +01002749 if (priv->smbios != NULL)
2750 g_object_unref (priv->smbios);
Richard Hughes275d3b42018-04-20 16:40:37 +01002751 if (priv->runtime_versions != NULL)
2752 g_hash_table_unref (priv->runtime_versions);
Richard Hughes34e0dab2018-04-20 16:43:00 +01002753 if (priv->compile_versions != NULL)
2754 g_hash_table_unref (priv->compile_versions);
Richard Hughescff38bc2016-12-12 12:03:37 +00002755 g_hash_table_unref (priv->devices);
Richard Hughes80b79bb2018-01-11 21:11:06 +00002756 g_hash_table_unref (priv->report_metadata);
Richard Hughes161e9b52019-06-12 14:22:45 +01002757 g_rw_lock_clear (&priv->devices_mutex);
Richard Hughes84999302019-05-02 10:18:32 +01002758 g_free (priv->build_hash);
Richard Hughescff38bc2016-12-12 12:03:37 +00002759 g_free (priv->name);
2760 g_free (priv->data);
Mario Limonciello3f9a1c12018-06-06 14:06:40 -05002761 /* Must happen as the last step to avoid prematurely
2762 * freeing memory held by the plugin */
2763#ifndef RUNNING_ON_VALGRIND
2764 if (priv->module != NULL)
2765 g_module_close (priv->module);
2766#endif
Richard Hughescff38bc2016-12-12 12:03:37 +00002767
2768 G_OBJECT_CLASS (fu_plugin_parent_class)->finalize (object);
2769}
2770
Mario Limonciello1a680f32019-11-25 19:44:53 -06002771/**
2772 * fu_plugin_new:
2773 *
2774 * Creates a new #FuPlugin
2775 *
2776 * Since: 0.8.0
2777 **/
Richard Hughescff38bc2016-12-12 12:03:37 +00002778FuPlugin *
2779fu_plugin_new (void)
2780{
Richard Hughes12724852018-09-04 13:53:44 +01002781 return FU_PLUGIN (g_object_new (FU_TYPE_PLUGIN, NULL));
Richard Hughescff38bc2016-12-12 12:03:37 +00002782}