blob: e6e267ba4388b98fe22871618388aeb2a066cb37 [file] [log] [blame]
Richard Hughesd0905142016-03-13 09:46:49 +00001/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
2 *
3 * Copyright (C) 2016 Richard Hughes <richard@hughsie.com>
4 *
5 * Licensed under the GNU General Public License Version 2
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 */
21
22#include "config.h"
23
Richard Hughescff38bc2016-12-12 12:03:37 +000024#include <fwupd.h>
25#include <gmodule.h>
26#include <appstream-glib.h>
27#include <errno.h>
28#include <string.h>
29#include <gio/gunixinputstream.h>
Richard Hughesd0905142016-03-13 09:46:49 +000030
Richard Hughescff38bc2016-12-12 12:03:37 +000031#include "fu-plugin-private.h"
32#include "fu-pending.h"
Richard Hughesd0905142016-03-13 09:46:49 +000033
Richard Hughesb0829032017-01-10 09:27:08 +000034#define FU_PLUGIN_COLDPLUG_DELAY_MAXIMUM 3000u /* ms */
35
Richard Hughescff38bc2016-12-12 12:03:37 +000036static void fu_plugin_finalize (GObject *object);
37
38typedef struct {
39 GModule *module;
40 GUsbContext *usb_ctx;
41 gboolean enabled;
42 gchar *name;
43 GHashTable *devices; /* platform_id:GObject */
Richard Hughesae3d65f2016-12-16 09:38:01 +000044 GHashTable *devices_delay; /* FuDevice:FuPluginHelper */
Richard Hughescff38bc2016-12-12 12:03:37 +000045 FuPluginData *data;
46} FuPluginPrivate;
47
48enum {
49 SIGNAL_DEVICE_ADDED,
50 SIGNAL_DEVICE_REMOVED,
51 SIGNAL_STATUS_CHANGED,
52 SIGNAL_PERCENTAGE_CHANGED,
Richard Hughes362d6d72017-01-07 21:42:14 +000053 SIGNAL_RECOLDPLUG,
Richard Hughesb0829032017-01-10 09:27:08 +000054 SIGNAL_SET_COLDPLUG_DELAY,
Richard Hughescff38bc2016-12-12 12:03:37 +000055 SIGNAL_LAST
56};
57
58static guint signals[SIGNAL_LAST] = { 0 };
59
60G_DEFINE_TYPE_WITH_PRIVATE (FuPlugin, fu_plugin, G_TYPE_OBJECT)
61#define GET_PRIVATE(o) (fu_plugin_get_instance_private (o))
62
63typedef const gchar *(*FuPluginGetNameFunc) (void);
64typedef void (*FuPluginInitFunc) (FuPlugin *plugin);
65typedef gboolean (*FuPluginStartupFunc) (FuPlugin *plugin,
66 GError **error);
67typedef gboolean (*FuPluginDeviceFunc) (FuPlugin *plugin,
68 FuDevice *device,
69 GError **error);
70typedef gboolean (*FuPluginVerifyFunc) (FuPlugin *plugin,
71 FuDevice *device,
72 FuPluginVerifyFlags flags,
73 GError **error);
74typedef gboolean (*FuPluginUpdateFunc) (FuPlugin *plugin,
75 FuDevice *device,
76 GBytes *blob_fw,
77 FwupdInstallFlags flags,
78 GError **error);
79
Richard Hughes57d18222017-01-10 16:02:59 +000080/**
81 * fu_plugin_get_name:
82 * @plugin: A #FuPlugin
83 *
84 * Gets the plugin name.
85 *
86 * Returns: a plugin name, or %NULL for unknown.
87 *
88 * Since: 0.8.0
89 **/
Richard Hughescff38bc2016-12-12 12:03:37 +000090const gchar *
91fu_plugin_get_name (FuPlugin *plugin)
Richard Hughesd0905142016-03-13 09:46:49 +000092{
Richard Hughescff38bc2016-12-12 12:03:37 +000093 FuPluginPrivate *priv = GET_PRIVATE (plugin);
Richard Hughesccd78a92017-01-11 16:57:41 +000094 g_return_val_if_fail (FU_IS_PLUGIN (plugin), NULL);
Richard Hughescff38bc2016-12-12 12:03:37 +000095 return priv->name;
96}
Richard Hughesd0905142016-03-13 09:46:49 +000097
Richard Hughes57d18222017-01-10 16:02:59 +000098/**
99 * fu_plugin_cache_lookup:
100 * @plugin: A #FuPlugin
101 * @id: the key
102 *
103 * Finds an object in the per-plugin cache.
104 *
105 * Returns: (transfer none): a #GObject, or %NULL for unfound.
106 *
107 * Since: 0.8.0
108 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000109gpointer
110fu_plugin_cache_lookup (FuPlugin *plugin, const gchar *id)
111{
112 FuPluginPrivate *priv = GET_PRIVATE (plugin);
Richard Hughesccd78a92017-01-11 16:57:41 +0000113 g_return_val_if_fail (FU_IS_PLUGIN (plugin), NULL);
114 g_return_val_if_fail (id != NULL, NULL);
Richard Hughescff38bc2016-12-12 12:03:37 +0000115 return g_hash_table_lookup (priv->devices, id);
116}
Richard Hughesd0905142016-03-13 09:46:49 +0000117
Richard Hughes57d18222017-01-10 16:02:59 +0000118/**
119 * fu_plugin_cache_add:
120 * @plugin: A #FuPlugin
121 * @id: the key
122 * @dev: a #GObject, typically a #FuDevice
123 *
124 * Adds an object to the per-plugin cache.
125 *
126 * Since: 0.8.0
127 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000128void
129fu_plugin_cache_add (FuPlugin *plugin, const gchar *id, gpointer dev)
130{
131 FuPluginPrivate *priv = GET_PRIVATE (plugin);
Richard Hughesccd78a92017-01-11 16:57:41 +0000132 g_return_if_fail (FU_IS_PLUGIN (plugin));
133 g_return_if_fail (id != NULL);
Richard Hughescff38bc2016-12-12 12:03:37 +0000134 g_hash_table_insert (priv->devices, g_strdup (id), g_object_ref (dev));
135}
136
Richard Hughes57d18222017-01-10 16:02:59 +0000137/**
138 * fu_plugin_cache_remove:
139 * @plugin: A #FuPlugin
140 * @id: the key
141 *
142 * Removes an object from the per-plugin cache.
143 *
144 * Since: 0.8.0
145 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000146void
147fu_plugin_cache_remove (FuPlugin *plugin, const gchar *id)
148{
149 FuPluginPrivate *priv = GET_PRIVATE (plugin);
Richard Hughesccd78a92017-01-11 16:57:41 +0000150 g_return_if_fail (FU_IS_PLUGIN (plugin));
151 g_return_if_fail (id != NULL);
Richard Hughescff38bc2016-12-12 12:03:37 +0000152 g_hash_table_remove (priv->devices, id);
153}
154
Richard Hughes57d18222017-01-10 16:02:59 +0000155/**
156 * fu_plugin_get_data:
157 * @plugin: A #FuPlugin
158 *
159 * Gets the per-plugin allocated private data.
160 *
161 * Returns: (transfer full): a pointer to a structure, or %NULL for unset.
162 *
163 * Since: 0.8.0
164 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000165FuPluginData *
166fu_plugin_get_data (FuPlugin *plugin)
167{
168 FuPluginPrivate *priv = GET_PRIVATE (plugin);
Richard Hughesccd78a92017-01-11 16:57:41 +0000169 g_return_val_if_fail (FU_IS_PLUGIN (plugin), NULL);
Richard Hughescff38bc2016-12-12 12:03:37 +0000170 return priv->data;
171}
172
Richard Hughes57d18222017-01-10 16:02:59 +0000173/**
174 * fu_plugin_alloc_data:
175 * @plugin: A #FuPlugin
176 * @data_sz: the size to allocate
177 *
178 * Allocates the per-plugin allocated private data.
179 *
180 * Returns: (transfer full): a pointer to a structure, or %NULL for unset.
181 *
182 * Since: 0.8.0
183 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000184FuPluginData *
185fu_plugin_alloc_data (FuPlugin *plugin, gsize data_sz)
186{
187 FuPluginPrivate *priv = GET_PRIVATE (plugin);
Richard Hughesccd78a92017-01-11 16:57:41 +0000188 g_return_val_if_fail (FU_IS_PLUGIN (plugin), NULL);
Richard Hughes44dee882017-01-11 08:31:10 +0000189 if (priv->data != NULL) {
190 g_critical ("fu_plugin_alloc_data() already used by plugin");
191 return priv->data;
192 }
Richard Hughescff38bc2016-12-12 12:03:37 +0000193 priv->data = g_malloc0 (data_sz);
194 return priv->data;
Richard Hughesd0905142016-03-13 09:46:49 +0000195}
196
Richard Hughes57d18222017-01-10 16:02:59 +0000197/**
198 * fu_plugin_get_usb_context:
199 * @plugin: A #FuPlugin
200 *
201 * Gets the shared USB context that all plugins can use.
202 *
203 * Returns: (transfer none): a #GUsbContext.
204 *
205 * Since: 0.8.0
206 **/
Richard Hughesbc93e4a2016-12-08 17:29:51 +0000207GUsbContext *
208fu_plugin_get_usb_context (FuPlugin *plugin)
209{
Richard Hughescff38bc2016-12-12 12:03:37 +0000210 FuPluginPrivate *priv = GET_PRIVATE (plugin);
Richard Hughesccd78a92017-01-11 16:57:41 +0000211 g_return_val_if_fail (FU_IS_PLUGIN (plugin), NULL);
Richard Hughescff38bc2016-12-12 12:03:37 +0000212 return priv->usb_ctx;
Richard Hughesbc93e4a2016-12-08 17:29:51 +0000213}
214
215void
216fu_plugin_set_usb_context (FuPlugin *plugin, GUsbContext *usb_ctx)
217{
Richard Hughescff38bc2016-12-12 12:03:37 +0000218 FuPluginPrivate *priv = GET_PRIVATE (plugin);
219 g_set_object (&priv->usb_ctx, usb_ctx);
220}
221
Richard Hughes57d18222017-01-10 16:02:59 +0000222/**
223 * fu_plugin_get_enabled:
224 * @plugin: A #FuPlugin
225 *
226 * Returns if the plugin is enabled.
227 *
228 * Returns: %TRUE if the plugin is currently enabled.
229 *
230 * Since: 0.8.0
231 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000232gboolean
233fu_plugin_get_enabled (FuPlugin *plugin)
234{
235 FuPluginPrivate *priv = GET_PRIVATE (plugin);
Richard Hughesccd78a92017-01-11 16:57:41 +0000236 g_return_val_if_fail (FU_IS_PLUGIN (plugin), FALSE);
Richard Hughescff38bc2016-12-12 12:03:37 +0000237 return priv->enabled;
Richard Hughesbc93e4a2016-12-08 17:29:51 +0000238}
239
Richard Hughes57d18222017-01-10 16:02:59 +0000240/**
241 * fu_plugin_set_enabled:
242 * @plugin: A #FuPlugin
243 * @enabled: the enabled value
244 *
245 * Enables or disables a plugin. Plugins can self-disable at any point.
246 *
247 * Since: 0.8.0
248 **/
Richard Hughesd0905142016-03-13 09:46:49 +0000249void
Richard Hughescff38bc2016-12-12 12:03:37 +0000250fu_plugin_set_enabled (FuPlugin *plugin, gboolean enabled)
Richard Hughesd0905142016-03-13 09:46:49 +0000251{
Richard Hughescff38bc2016-12-12 12:03:37 +0000252 FuPluginPrivate *priv = GET_PRIVATE (plugin);
Richard Hughesccd78a92017-01-11 16:57:41 +0000253 g_return_if_fail (FU_IS_PLUGIN (plugin));
Richard Hughescff38bc2016-12-12 12:03:37 +0000254 priv->enabled = enabled;
255}
256
257gboolean
258fu_plugin_open (FuPlugin *plugin, const gchar *filename, GError **error)
259{
260 FuPluginPrivate *priv = GET_PRIVATE (plugin);
261 FuPluginInitFunc func = NULL;
262 gchar *str;
263
264 priv->module = g_module_open (filename, 0);
265 if (priv->module == NULL) {
266 g_set_error (error,
267 G_IO_ERROR,
268 G_IO_ERROR_FAILED,
269 "failed to open plugin: %s",
270 g_module_error ());
271 return FALSE;
272 }
273
274 /* set automatically */
275 str = g_strstr_len (filename, -1, "libfu_plugin_");
276 if (str != NULL) {
277 priv->name = g_strdup (str + 13);
278 g_strdelimit (priv->name, ".", '\0');
279 }
Richard Hughesd0905142016-03-13 09:46:49 +0000280
281 /* optional */
Richard Hughescff38bc2016-12-12 12:03:37 +0000282 g_module_symbol (priv->module, "fu_plugin_init", (gpointer *) &func);
283 if (func != NULL) {
284 g_debug ("performing init() on %s", filename);
Richard Hughesd0905142016-03-13 09:46:49 +0000285 func (plugin);
286 }
287
Richard Hughescff38bc2016-12-12 12:03:37 +0000288 return TRUE;
289}
290
Richard Hughes57d18222017-01-10 16:02:59 +0000291/**
292 * fu_plugin_device_add:
293 * @plugin: A #FuPlugin
294 * @device: A #FuDevice
295 *
296 * Asks the daemon to add a device to the exported list. If this device ID
297 * has already been added by a different plugin then this request will be
298 * ignored.
299 *
300 * Plugins should use fu_plugin_device_add_delay() if they are not capable of
301 * actually flashing an image to the hardware so that higher-priority plugins
302 * can add the device themselves.
303 *
304 * Since: 0.8.0
305 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000306void
307fu_plugin_device_add (FuPlugin *plugin, FuDevice *device)
308{
Richard Hughesccd78a92017-01-11 16:57:41 +0000309 g_return_if_fail (FU_IS_PLUGIN (plugin));
310 g_return_if_fail (FU_IS_DEVICE (device));
311
Richard Hughescff38bc2016-12-12 12:03:37 +0000312 g_debug ("emit added from %s: %s",
313 fu_plugin_get_name (plugin),
314 fu_device_get_id (device));
315 fu_device_set_created (device, (guint64) g_get_real_time () / G_USEC_PER_SEC);
316 fu_device_set_plugin (device, fu_plugin_get_name (plugin));
317 g_signal_emit (plugin, signals[SIGNAL_DEVICE_ADDED], 0, device);
318}
319
Richard Hughesae3d65f2016-12-16 09:38:01 +0000320typedef struct {
321 FuPlugin *plugin;
322 FuDevice *device;
323 guint timeout_id;
Richard Hughesd4184cf2016-12-21 16:05:17 +0000324 GHashTable *devices;
Richard Hughesae3d65f2016-12-16 09:38:01 +0000325} FuPluginHelper;
326
327static void
328fu_plugin_helper_free (FuPluginHelper *helper)
329{
330 g_object_unref (helper->plugin);
331 g_object_unref (helper->device);
Richard Hughesd4184cf2016-12-21 16:05:17 +0000332 g_hash_table_unref (helper->devices);
Richard Hughesae3d65f2016-12-16 09:38:01 +0000333 g_free (helper);
334}
335
336static gboolean
337fu_plugin_device_add_delay_cb (gpointer user_data)
338{
339 FuPluginHelper *helper = (FuPluginHelper *) user_data;
Richard Hughesf0a799e2017-01-17 20:13:30 +0000340 g_hash_table_remove (helper->devices, helper->device);
Richard Hughesae3d65f2016-12-16 09:38:01 +0000341 fu_plugin_device_add (helper->plugin, helper->device);
342 fu_plugin_helper_free (helper);
343 return FALSE;
344}
345
Richard Hughes57d18222017-01-10 16:02:59 +0000346/**
Richard Hughesf0a799e2017-01-17 20:13:30 +0000347 * fu_plugin_has_device_delay:
348 * @plugin: A #FuPlugin
349 *
350 * Returns if the device has a pending device that is waiting to be added.
351 *
352 * Returns: %TRUE if a device is waiting to be added
353 *
354 * Since: 0.8.0
355 **/
356gboolean
357fu_plugin_has_device_delay (FuPlugin *plugin)
358{
359 FuPluginPrivate *priv = GET_PRIVATE (plugin);
360 return g_hash_table_size (priv->devices_delay) > 0;
361}
362
363/**
Richard Hughes57d18222017-01-10 16:02:59 +0000364 * fu_plugin_device_add_delay:
365 * @plugin: A #FuPlugin
366 * @device: A #FuDevice
367 *
368 * Asks the daemon to add a device to the exported list after a small delay.
369 *
370 * Since: 0.8.0
371 **/
Richard Hughesae3d65f2016-12-16 09:38:01 +0000372void
373fu_plugin_device_add_delay (FuPlugin *plugin, FuDevice *device)
374{
375 FuPluginPrivate *priv = GET_PRIVATE (plugin);
376 FuPluginHelper *helper;
Richard Hughesccd78a92017-01-11 16:57:41 +0000377
378 g_return_if_fail (FU_IS_PLUGIN (plugin));
379 g_return_if_fail (FU_IS_DEVICE (device));
380
Richard Hughes6ad951d2017-02-03 10:12:12 +0000381 /* already waiting for add */
382 helper = g_hash_table_lookup (priv->devices_delay, device);
383 if (helper != NULL) {
384 g_warning ("ignoring add-delay as device %s already pending",
385 fu_device_get_id (device));
386 return;
387 }
388
389 /* add after a small delay */
Richard Hughesae3d65f2016-12-16 09:38:01 +0000390 g_debug ("waiting a small time for other plugins");
391 helper = g_new0 (FuPluginHelper, 1);
392 helper->plugin = g_object_ref (plugin);
393 helper->device = g_object_ref (device);
394 helper->timeout_id = g_timeout_add (500, fu_plugin_device_add_delay_cb, helper);
Richard Hughesd4184cf2016-12-21 16:05:17 +0000395 helper->devices = g_hash_table_ref (priv->devices_delay);
396 g_hash_table_insert (helper->devices, device, helper);
Richard Hughesae3d65f2016-12-16 09:38:01 +0000397}
398
Richard Hughes57d18222017-01-10 16:02:59 +0000399/**
400 * fu_plugin_device_add:
401 * @plugin: A #FuPlugin
402 * @device: A #FuDevice
403 *
404 * Asks the daemon to remove a device from the exported list.
405 *
406 * Since: 0.8.0
407 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000408void
409fu_plugin_device_remove (FuPlugin *plugin, FuDevice *device)
410{
Richard Hughesae3d65f2016-12-16 09:38:01 +0000411 FuPluginPrivate *priv = GET_PRIVATE (plugin);
412 FuPluginHelper *helper;
413
Richard Hughesccd78a92017-01-11 16:57:41 +0000414 g_return_if_fail (FU_IS_PLUGIN (plugin));
415 g_return_if_fail (FU_IS_DEVICE (device));
416
Richard Hughesae3d65f2016-12-16 09:38:01 +0000417 /* waiting for add */
418 helper = g_hash_table_lookup (priv->devices_delay, device);
419 if (helper != NULL) {
420 g_debug ("ignoring remove from delayed addition");
421 g_source_remove (helper->timeout_id);
Richard Hughesd4184cf2016-12-21 16:05:17 +0000422 g_hash_table_remove (priv->devices_delay, helper->device);
Richard Hughesae3d65f2016-12-16 09:38:01 +0000423 fu_plugin_helper_free (helper);
424 return;
425 }
426
Richard Hughescff38bc2016-12-12 12:03:37 +0000427 g_debug ("emit removed from %s: %s",
428 fu_plugin_get_name (plugin),
429 fu_device_get_id (device));
430 g_signal_emit (plugin, signals[SIGNAL_DEVICE_REMOVED], 0, device);
431}
432
Richard Hughes57d18222017-01-10 16:02:59 +0000433/**
434 * fu_plugin_set_status:
435 * @plugin: A #FuPlugin
436 * @status: A #FwupdStatus, e.g. #FWUPD_STATUS_DECOMPRESSING
437 *
438 * Sets the global state of the daemon according to the current plugin action.
439 *
440 * Since: 0.8.0
441 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000442void
443fu_plugin_set_status (FuPlugin *plugin, FwupdStatus status)
444{
Richard Hughesccd78a92017-01-11 16:57:41 +0000445 g_return_if_fail (FU_IS_PLUGIN (plugin));
Richard Hughescff38bc2016-12-12 12:03:37 +0000446 g_signal_emit (plugin, signals[SIGNAL_STATUS_CHANGED], 0, status);
447}
448
Richard Hughes57d18222017-01-10 16:02:59 +0000449/**
450 * fu_plugin_set_percentage:
451 * @plugin: A #FuPlugin
452 * @percentage: the percentage complete
453 *
454 * Sets the global completion of the daemon according to the current plugin
455 * action.
456 *
457 * Since: 0.8.0
458 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000459void
460fu_plugin_set_percentage (FuPlugin *plugin, guint percentage)
461{
Richard Hughesccd78a92017-01-11 16:57:41 +0000462 g_return_if_fail (FU_IS_PLUGIN (plugin));
463 g_return_if_fail (percentage <= 100);
Richard Hughescff38bc2016-12-12 12:03:37 +0000464 g_signal_emit (plugin, signals[SIGNAL_PERCENTAGE_CHANGED], 0,
465 percentage);
Richard Hughesd0905142016-03-13 09:46:49 +0000466}
467
Richard Hughes362d6d72017-01-07 21:42:14 +0000468/**
469 * fu_plugin_recoldplug:
470 * @plugin: A #FuPlugin
471 *
472 * Ask all the plugins to coldplug all devices, which will include the prepare()
473 * and cleanup() phases. Duplicate devices added will be ignored.
474 *
475 * Since: 0.8.0
476 **/
477void
478fu_plugin_recoldplug (FuPlugin *plugin)
479{
Richard Hughesccd78a92017-01-11 16:57:41 +0000480 g_return_if_fail (FU_IS_PLUGIN (plugin));
Richard Hughes362d6d72017-01-07 21:42:14 +0000481 g_signal_emit (plugin, signals[SIGNAL_RECOLDPLUG], 0);
482}
483
Richard Hughesb0829032017-01-10 09:27:08 +0000484/**
485 * fu_plugin_set_coldplug_delay:
486 * @plugin: A #FuPlugin
487 * @duration: A delay in milliseconds
488 *
489 * Set the minimum time that should be waited inbetween the call to
490 * fu_plugin_coldplug_prepare() and fu_plugin_coldplug(). This is usually going
491 * to be the minimum hardware initialisation time from a datasheet.
492 *
493 * It is better to use this function rather than using a sleep() in the plugin
494 * itself as then only one delay is done in the daemon rather than waiting for
495 * each coldplug prepare in a serial way.
496 *
497 * Additionally, very long delays should be avoided as the daemon will be
498 * blocked from processing requests whilst the coldplug delay is being
499 * performed.
500 *
501 * Since: 0.8.0
502 **/
503void
504fu_plugin_set_coldplug_delay (FuPlugin *plugin, guint duration)
505{
506 g_return_if_fail (FU_IS_PLUGIN (plugin));
507 g_return_if_fail (duration > 0);
508
509 /* check sanity */
510 if (duration > FU_PLUGIN_COLDPLUG_DELAY_MAXIMUM) {
511 g_warning ("duration of %ums is crazy, truncating to %ums",
512 duration,
513 FU_PLUGIN_COLDPLUG_DELAY_MAXIMUM);
514 duration = FU_PLUGIN_COLDPLUG_DELAY_MAXIMUM;
515 }
516
517 /* emit */
518 g_signal_emit (plugin, signals[SIGNAL_SET_COLDPLUG_DELAY], 0, duration);
519}
520
Richard Hughesd0905142016-03-13 09:46:49 +0000521gboolean
Richard Hughescff38bc2016-12-12 12:03:37 +0000522fu_plugin_runner_startup (FuPlugin *plugin, GError **error)
Richard Hughesd0905142016-03-13 09:46:49 +0000523{
Richard Hughescff38bc2016-12-12 12:03:37 +0000524 FuPluginPrivate *priv = GET_PRIVATE (plugin);
Richard Hughes7b8b2022016-12-12 16:15:03 +0000525 FuPluginStartupFunc func = NULL;
Richard Hughesd0905142016-03-13 09:46:49 +0000526
527 /* not enabled */
Richard Hughescff38bc2016-12-12 12:03:37 +0000528 if (!priv->enabled)
Richard Hughesd0905142016-03-13 09:46:49 +0000529 return TRUE;
530
531 /* optional */
Richard Hughescff38bc2016-12-12 12:03:37 +0000532 g_module_symbol (priv->module, "fu_plugin_startup", (gpointer *) &func);
533 if (func == NULL)
Richard Hughesd0905142016-03-13 09:46:49 +0000534 return TRUE;
Richard Hughescff38bc2016-12-12 12:03:37 +0000535 g_debug ("performing startup() on %s", priv->name);
Richard Hughesd0905142016-03-13 09:46:49 +0000536 if (!func (plugin, error)) {
Richard Hughescff38bc2016-12-12 12:03:37 +0000537 g_prefix_error (error, "failed to startup %s: ", priv->name);
538 return FALSE;
539 }
540 return TRUE;
541}
542
543static gboolean
544fu_plugin_runner_offline_invalidate (GError **error)
545{
546 g_autoptr(GError) error_local = NULL;
547 g_autoptr(GFile) file1 = NULL;
548
549 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
550
551 file1 = g_file_new_for_path (FU_OFFLINE_TRIGGER_FILENAME);
552 if (!g_file_query_exists (file1, NULL))
553 return TRUE;
554 if (!g_file_delete (file1, NULL, &error_local)) {
555 g_set_error (error,
556 FWUPD_ERROR,
557 FWUPD_ERROR_INTERNAL,
558 "Cannot delete %s: %s",
559 FU_OFFLINE_TRIGGER_FILENAME,
560 error_local->message);
561 return FALSE;
562 }
563 return TRUE;
564}
565
566static gboolean
567fu_plugin_runner_offline_setup (GError **error)
568{
569 gint rc;
570
571 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
572
573 /* create symlink for the systemd-system-update-generator */
574 rc = symlink ("/var/lib/fwupd", FU_OFFLINE_TRIGGER_FILENAME);
575 if (rc < 0) {
576 g_set_error (error,
577 FWUPD_ERROR,
578 FWUPD_ERROR_INTERNAL,
579 "Failed to create symlink %s to %s: %s",
580 FU_OFFLINE_TRIGGER_FILENAME,
581 "/var/lib", strerror (errno));
Richard Hughesd0905142016-03-13 09:46:49 +0000582 return FALSE;
583 }
584 return TRUE;
585}
586
Richard Hughesd0905142016-03-13 09:46:49 +0000587gboolean
Richard Hughescff38bc2016-12-12 12:03:37 +0000588fu_plugin_runner_coldplug (FuPlugin *plugin, GError **error)
Richard Hughesd0905142016-03-13 09:46:49 +0000589{
Richard Hughescff38bc2016-12-12 12:03:37 +0000590 FuPluginPrivate *priv = GET_PRIVATE (plugin);
Richard Hughes7b8b2022016-12-12 16:15:03 +0000591 FuPluginStartupFunc func = NULL;
Richard Hughesd0905142016-03-13 09:46:49 +0000592
593 /* not enabled */
Richard Hughescff38bc2016-12-12 12:03:37 +0000594 if (!priv->enabled)
Richard Hughesd0905142016-03-13 09:46:49 +0000595 return TRUE;
596
597 /* optional */
Richard Hughescff38bc2016-12-12 12:03:37 +0000598 g_module_symbol (priv->module, "fu_plugin_coldplug", (gpointer *) &func);
599 if (func == NULL)
Richard Hughesd0905142016-03-13 09:46:49 +0000600 return TRUE;
Richard Hughescff38bc2016-12-12 12:03:37 +0000601 g_debug ("performing coldplug() on %s", priv->name);
602 if (!func (plugin, error)) {
603 g_prefix_error (error, "failed to coldplug %s: ", priv->name);
604 return FALSE;
605 }
606 return TRUE;
607}
608
Richard Hughes7b8b2022016-12-12 16:15:03 +0000609gboolean
Richard Hughes46487c92017-01-07 21:26:34 +0000610fu_plugin_runner_coldplug_prepare (FuPlugin *plugin, GError **error)
611{
612 FuPluginPrivate *priv = GET_PRIVATE (plugin);
613 FuPluginStartupFunc func = NULL;
614
615 /* not enabled */
616 if (!priv->enabled)
617 return TRUE;
618
619 /* optional */
620 g_module_symbol (priv->module, "fu_plugin_coldplug_prepare", (gpointer *) &func);
621 if (func == NULL)
622 return TRUE;
623 g_debug ("performing coldplug_prepare() on %s", priv->name);
624 if (!func (plugin, error)) {
625 g_prefix_error (error, "failed to prepare for coldplug %s: ", priv->name);
626 return FALSE;
627 }
628 return TRUE;
629}
630
631gboolean
632fu_plugin_runner_coldplug_cleanup (FuPlugin *plugin, GError **error)
633{
634 FuPluginPrivate *priv = GET_PRIVATE (plugin);
635 FuPluginStartupFunc func = NULL;
636
637 /* not enabled */
638 if (!priv->enabled)
639 return TRUE;
640
641 /* optional */
642 g_module_symbol (priv->module, "fu_plugin_coldplug_cleanup", (gpointer *) &func);
643 if (func == NULL)
644 return TRUE;
645 g_debug ("performing coldplug_cleanup() on %s", priv->name);
646 if (!func (plugin, error)) {
647 g_prefix_error (error, "failed to cleanup coldplug %s: ", priv->name);
648 return FALSE;
649 }
650 return TRUE;
651}
652
653gboolean
Richard Hughes7b8b2022016-12-12 16:15:03 +0000654fu_plugin_runner_update_prepare (FuPlugin *plugin, FuDevice *device, GError **error)
655{
656 FuPluginPrivate *priv = GET_PRIVATE (plugin);
657 FuPluginDeviceFunc func = NULL;
658
659 /* not enabled */
660 if (!priv->enabled)
661 return TRUE;
662
663 /* optional */
664 g_module_symbol (priv->module, "fu_plugin_update_prepare", (gpointer *) &func);
665 if (func == NULL)
666 return TRUE;
667 g_debug ("performing update_prepare() on %s", priv->name);
668 if (!func (plugin, device, error)) {
669 g_prefix_error (error, "failed to prepare for update %s: ", priv->name);
670 return FALSE;
671 }
672 return TRUE;
673}
674
675gboolean
676fu_plugin_runner_update_cleanup (FuPlugin *plugin, FuDevice *device, GError **error)
677{
678 FuPluginPrivate *priv = GET_PRIVATE (plugin);
679 FuPluginDeviceFunc func = NULL;
680
681 /* not enabled */
682 if (!priv->enabled)
683 return TRUE;
684
685 /* optional */
686 g_module_symbol (priv->module, "fu_plugin_update_cleanup", (gpointer *) &func);
687 if (func == NULL)
688 return TRUE;
689 g_debug ("performing update_cleanup() on %s", priv->name);
690 if (!func (plugin, device, error)) {
691 g_prefix_error (error, "failed to cleanup update %s: ", priv->name);
692 return FALSE;
693 }
694 return TRUE;
695}
696
Richard Hughescff38bc2016-12-12 12:03:37 +0000697static gboolean
698fu_plugin_runner_schedule_update (FuPlugin *plugin,
699 FuDevice *device,
700 GBytes *blob_cab,
701 GError **error)
702{
703 gchar tmpname[] = {"XXXXXX.cap"};
704 g_autofree gchar *dirname = NULL;
705 g_autofree gchar *filename = NULL;
706 g_autoptr(FwupdResult) res_tmp = NULL;
707 g_autoptr(FuPending) pending = NULL;
708 g_autoptr(GFile) file = NULL;
709
710 /* id already exists */
711 pending = fu_pending_new ();
712 res_tmp = fu_pending_get_device (pending, fu_device_get_id (device), NULL);
713 if (res_tmp != NULL) {
714 g_set_error (error,
715 FWUPD_ERROR,
716 FWUPD_ERROR_ALREADY_PENDING,
717 "%s is already scheduled to be updated",
718 fu_device_get_id (device));
719 return FALSE;
720 }
721
722 /* create directory */
723 dirname = g_build_filename (LOCALSTATEDIR, "lib", "fwupd", NULL);
724 file = g_file_new_for_path (dirname);
725 if (!g_file_query_exists (file, NULL)) {
726 if (!g_file_make_directory_with_parents (file, NULL, error))
727 return FALSE;
728 }
729
730 /* get a random filename */
731 for (guint i = 0; i < 6; i++)
732 tmpname[i] = (gchar) g_random_int_range ('A', 'Z');
733 filename = g_build_filename (dirname, tmpname, NULL);
734
735 /* just copy to the temp file */
736 fu_plugin_set_status (plugin, FWUPD_STATUS_SCHEDULING);
737 if (!g_file_set_contents (filename,
738 g_bytes_get_data (blob_cab, NULL),
739 (gssize) g_bytes_get_size (blob_cab),
740 error))
741 return FALSE;
742
743 /* schedule for next boot */
744 g_debug ("schedule %s to be installed to %s on next boot",
745 filename, fu_device_get_id (device));
746 fu_device_set_update_filename (device, filename);
747
748 /* add to database */
749 if (!fu_pending_add_device (pending, FWUPD_RESULT (device), error))
750 return FALSE;
751
752 /* next boot we run offline */
753 return fu_plugin_runner_offline_setup (error);
754}
755
756gboolean
757fu_plugin_runner_verify (FuPlugin *plugin,
758 FuDevice *device,
759 FuPluginVerifyFlags flags,
760 GError **error)
761{
762 FuPluginPrivate *priv = GET_PRIVATE (plugin);
Richard Hughes7b8b2022016-12-12 16:15:03 +0000763 FuPluginVerifyFunc func = NULL;
Richard Hughescff38bc2016-12-12 12:03:37 +0000764
765 /* not enabled */
766 if (!priv->enabled)
767 return TRUE;
768
769 /* optional */
770 g_module_symbol (priv->module, "fu_plugin_verify", (gpointer *) &func);
771 if (func == NULL)
772 return TRUE;
773 g_debug ("performing verify() on %s", priv->name);
774 if (!func (plugin, device, flags, error)) {
775 g_prefix_error (error, "failed to verify %s: ", priv->name);
Richard Hughesd0905142016-03-13 09:46:49 +0000776 return FALSE;
777 }
778 return TRUE;
779}
780
Richard Hughesd0905142016-03-13 09:46:49 +0000781gboolean
Richard Hughescff38bc2016-12-12 12:03:37 +0000782fu_plugin_runner_unlock (FuPlugin *plugin, FuDevice *device, GError **error)
Richard Hughesd0905142016-03-13 09:46:49 +0000783{
Richard Hughescff38bc2016-12-12 12:03:37 +0000784 guint64 flags;
785 FuPluginPrivate *priv = GET_PRIVATE (plugin);
Richard Hughes7b8b2022016-12-12 16:15:03 +0000786 FuPluginDeviceFunc func = NULL;
Richard Hughesd0905142016-03-13 09:46:49 +0000787
788 /* not enabled */
Richard Hughescff38bc2016-12-12 12:03:37 +0000789 if (!priv->enabled)
790 return TRUE;
791
792 /* final check */
793 flags = fu_device_get_flags (device);
794 if ((flags & FWUPD_DEVICE_FLAG_LOCKED) == 0) {
795 g_set_error (error,
796 FWUPD_ERROR,
797 FWUPD_ERROR_NOT_SUPPORTED,
798 "Device %s is not locked",
799 fu_device_get_id (device));
800 return FALSE;
801 }
802
803 /* optional */
804 g_module_symbol (priv->module, "fu_plugin_unlock", (gpointer *) &func);
805 if (func != NULL) {
806 g_debug ("performing unlock() on %s", priv->name);
807 if (!func (plugin, device, error)) {
Richard Hughes7b8b2022016-12-12 16:15:03 +0000808 g_prefix_error (error, "failed to unlock %s: ", priv->name);
Richard Hughescff38bc2016-12-12 12:03:37 +0000809 return FALSE;
810 }
811 }
812
813 /* update with correct flags */
814 flags = fu_device_get_flags (device);
815 fu_device_set_flags (device, flags &= ~FWUPD_DEVICE_FLAG_LOCKED);
816 fu_device_set_modified (device, (guint64) g_get_real_time () / G_USEC_PER_SEC);
817 return TRUE;
818}
819
820gboolean
821fu_plugin_runner_update (FuPlugin *plugin,
822 FuDevice *device,
823 GBytes *blob_cab,
824 GBytes *blob_fw,
825 FwupdInstallFlags flags,
826 GError **error)
827{
828 FuPluginPrivate *priv = GET_PRIVATE (plugin);
829 FuPluginUpdateFunc func_online;
830 FuPluginUpdateFunc func_offline;
831 g_autoptr(FuPending) pending = NULL;
832 g_autoptr(FwupdResult) res_pending = NULL;
833 GError *error_update = NULL;
834
835 /* not enabled */
836 if (!priv->enabled)
Richard Hughesd0905142016-03-13 09:46:49 +0000837 return TRUE;
838
839 /* optional */
Richard Hughescff38bc2016-12-12 12:03:37 +0000840 g_module_symbol (priv->module, "fu_plugin_update_online", (gpointer *) &func_online);
841 g_module_symbol (priv->module, "fu_plugin_update_offline", (gpointer *) &func_offline);
Richard Hughesd0905142016-03-13 09:46:49 +0000842
Richard Hughescff38bc2016-12-12 12:03:37 +0000843 /* schedule for next reboot, or handle in the plugin */
844 if (flags & FWUPD_INSTALL_FLAG_OFFLINE) {
845 if (func_offline == NULL) {
846 return fu_plugin_runner_schedule_update (plugin,
847 device,
848 blob_cab,
849 error);
850 }
851 return func_offline (plugin, device, blob_fw, flags, error);
852 }
853
854 /* cancel the pending action */
855 if (!fu_plugin_runner_offline_invalidate (error))
856 return FALSE;
857
858 /* online */
859 if (func_online == NULL) {
860 g_set_error_literal (error,
861 FWUPD_ERROR,
862 FWUPD_ERROR_NOT_SUPPORTED,
863 "No online update possible");
Richard Hughesd0905142016-03-13 09:46:49 +0000864 return FALSE;
865 }
Richard Hughescff38bc2016-12-12 12:03:37 +0000866 pending = fu_pending_new ();
867 res_pending = fu_pending_get_device (pending, fu_device_get_id (device), NULL);
868 if (!func_online (plugin, device, blob_fw, flags, &error_update)) {
869 /* save the error to the database */
870 if (res_pending != NULL) {
871 fu_pending_set_error_msg (pending, FWUPD_RESULT (device),
872 error_update->message, NULL);
873 }
874 g_propagate_error (error, error_update);
875 return FALSE;
876 }
877
878 /* cleanup */
879 if (res_pending != NULL) {
880 const gchar *tmp;
881
882 /* update pending database */
883 fu_pending_set_state (pending, FWUPD_RESULT (device),
884 FWUPD_UPDATE_STATE_SUCCESS, NULL);
885
886 /* delete cab file */
887 tmp = fwupd_result_get_update_filename (res_pending);
888 if (tmp != NULL && g_str_has_prefix (tmp, LIBEXECDIR)) {
889 g_autoptr(GError) error_local = NULL;
890 g_autoptr(GFile) file = NULL;
891 file = g_file_new_for_path (tmp);
892 if (!g_file_delete (file, NULL, &error_local)) {
893 g_set_error (error,
894 FWUPD_ERROR,
895 FWUPD_ERROR_INVALID_FILE,
896 "Failed to delete %s: %s",
897 tmp, error_local->message);
898 return FALSE;
899 }
900 }
901 }
Richard Hughesd0905142016-03-13 09:46:49 +0000902 return TRUE;
903}
Richard Hughescff38bc2016-12-12 12:03:37 +0000904
905gboolean
906fu_plugin_runner_clear_results (FuPlugin *plugin, FuDevice *device, GError **error)
907{
908 FuPluginPrivate *priv = GET_PRIVATE (plugin);
Richard Hughes7b8b2022016-12-12 16:15:03 +0000909 FuPluginDeviceFunc func = NULL;
Richard Hughescff38bc2016-12-12 12:03:37 +0000910 g_autoptr(GError) error_local = NULL;
911 g_autoptr(FwupdResult) res_pending = NULL;
912 g_autoptr(FuPending) pending = NULL;
913
914 /* not enabled */
915 if (!priv->enabled)
916 return TRUE;
917
918 /* use the plugin if the vfunc is provided */
919 g_module_symbol (priv->module, "fu_plugin_clear_result", (gpointer *) &func);
920 if (func != NULL) {
921 g_debug ("performing clear_result() on %s", priv->name);
922 if (!func (plugin, device, error)) {
923 g_prefix_error (error, "failed to clear_result %s: ", priv->name);
924 return FALSE;
925 }
926 return TRUE;
927 }
928
929 /* handled using the database */
930 pending = fu_pending_new ();
931 res_pending = fu_pending_get_device (pending,
932 fu_device_get_id (device),
933 &error_local);
934 if (res_pending == NULL) {
935 g_set_error (error,
936 FWUPD_ERROR,
937 FWUPD_ERROR_INVALID_FILE,
938 "Failed to find %s in pending database: %s",
939 fu_device_get_id (device),
940 error_local->message);
941 return FALSE;
942 }
943
944 /* remove from pending database */
945 return fu_pending_remove_device (pending, FWUPD_RESULT (device), error);
946}
947
948gboolean
949fu_plugin_runner_get_results (FuPlugin *plugin, FuDevice *device, GError **error)
950{
951 FuPluginPrivate *priv = GET_PRIVATE (plugin);
Richard Hughes7b8b2022016-12-12 16:15:03 +0000952 FuPluginDeviceFunc func = NULL;
Richard Hughescff38bc2016-12-12 12:03:37 +0000953 FwupdUpdateState update_state;
954 const gchar *tmp;
955 g_autoptr(GError) error_local = NULL;
956 g_autoptr(FwupdResult) res_pending = NULL;
957 g_autoptr(FuPending) pending = NULL;
958
959 /* not enabled */
960 if (!priv->enabled)
961 return TRUE;
962
963 /* use the plugin if the vfunc is provided */
964 g_module_symbol (priv->module, "fu_plugin_get_results", (gpointer *) &func);
965 if (func != NULL) {
966 g_debug ("performing get_results() on %s", priv->name);
967 if (!func (plugin, device, error)) {
968 g_prefix_error (error, "failed to get_results %s: ", priv->name);
969 return FALSE;
970 }
971 return TRUE;
972 }
973
974 /* handled using the database */
975 pending = fu_pending_new ();
976 res_pending = fu_pending_get_device (pending,
977 fu_device_get_id (device),
978 &error_local);
979 if (res_pending == NULL) {
980 g_set_error (error,
981 FWUPD_ERROR,
982 FWUPD_ERROR_NOTHING_TO_DO,
983 "Failed to find %s in pending database: %s",
984 fu_device_get_id (device),
985 error_local->message);
986 return FALSE;
987 }
988
989 /* copy the important parts from the pending device to the real one */
990 update_state = fwupd_result_get_update_state (res_pending);
991 if (update_state == FWUPD_UPDATE_STATE_UNKNOWN ||
992 update_state == FWUPD_UPDATE_STATE_PENDING) {
993 g_set_error (error,
994 FWUPD_ERROR,
995 FWUPD_ERROR_NOTHING_TO_DO,
996 "Device %s has not been updated offline yet",
997 fu_device_get_id (device));
998 return FALSE;
999 }
1000
1001 /* copy */
1002 fu_device_set_update_state (device, update_state);
1003 tmp = fwupd_result_get_update_error (res_pending);
1004 if (tmp != NULL)
1005 fu_device_set_update_error (device, tmp);
1006 tmp = fwupd_result_get_device_version (res_pending);
1007 if (tmp != NULL)
1008 fu_device_set_version (device, tmp);
1009 tmp = fwupd_result_get_update_version (res_pending);
1010 if (tmp != NULL)
1011 fu_device_set_update_version (device, tmp);
1012 return TRUE;
1013}
1014
1015static void
1016fu_plugin_class_init (FuPluginClass *klass)
1017{
1018 GObjectClass *object_class = G_OBJECT_CLASS (klass);
1019 object_class->finalize = fu_plugin_finalize;
1020 signals[SIGNAL_DEVICE_ADDED] =
1021 g_signal_new ("device-added",
1022 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
1023 G_STRUCT_OFFSET (FuPluginClass, device_added),
1024 NULL, NULL, g_cclosure_marshal_VOID__OBJECT,
1025 G_TYPE_NONE, 1, FU_TYPE_DEVICE);
1026 signals[SIGNAL_DEVICE_REMOVED] =
1027 g_signal_new ("device-removed",
1028 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
1029 G_STRUCT_OFFSET (FuPluginClass, device_removed),
1030 NULL, NULL, g_cclosure_marshal_VOID__OBJECT,
1031 G_TYPE_NONE, 1, FU_TYPE_DEVICE);
1032 signals[SIGNAL_STATUS_CHANGED] =
1033 g_signal_new ("status-changed",
1034 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
1035 G_STRUCT_OFFSET (FuPluginClass, status_changed),
1036 NULL, NULL, g_cclosure_marshal_VOID__UINT,
1037 G_TYPE_NONE, 1, G_TYPE_UINT);
1038 signals[SIGNAL_PERCENTAGE_CHANGED] =
1039 g_signal_new ("percentage-changed",
1040 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
1041 G_STRUCT_OFFSET (FuPluginClass, percentage_changed),
1042 NULL, NULL, g_cclosure_marshal_VOID__UINT,
1043 G_TYPE_NONE, 1, G_TYPE_UINT);
Richard Hughes362d6d72017-01-07 21:42:14 +00001044 signals[SIGNAL_RECOLDPLUG] =
1045 g_signal_new ("recoldplug",
1046 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
1047 G_STRUCT_OFFSET (FuPluginClass, recoldplug),
1048 NULL, NULL, g_cclosure_marshal_VOID__VOID,
1049 G_TYPE_NONE, 0);
Richard Hughesb0829032017-01-10 09:27:08 +00001050 signals[SIGNAL_SET_COLDPLUG_DELAY] =
1051 g_signal_new ("set-coldplug-delay",
1052 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
1053 G_STRUCT_OFFSET (FuPluginClass, set_coldplug_delay),
1054 NULL, NULL, g_cclosure_marshal_VOID__UINT,
1055 G_TYPE_NONE, 1, G_TYPE_UINT);
Richard Hughescff38bc2016-12-12 12:03:37 +00001056}
1057
1058static void
1059fu_plugin_init (FuPlugin *plugin)
1060{
1061 FuPluginPrivate *priv = GET_PRIVATE (plugin);
1062 priv->enabled = TRUE;
1063 priv->devices = g_hash_table_new_full (g_str_hash, g_str_equal,
1064 g_free, (GDestroyNotify) g_object_unref);
Richard Hughesae3d65f2016-12-16 09:38:01 +00001065 priv->devices_delay = g_hash_table_new (g_str_hash, g_str_equal);
Richard Hughescff38bc2016-12-12 12:03:37 +00001066}
1067
1068static void
1069fu_plugin_finalize (GObject *object)
1070{
1071 FuPlugin *plugin = FU_PLUGIN (object);
1072 FuPluginPrivate *priv = GET_PRIVATE (plugin);
1073 FuPluginInitFunc func = NULL;
1074
1075 /* optional */
1076 if (priv->module != NULL) {
1077 g_module_symbol (priv->module, "fu_plugin_destroy", (gpointer *) &func);
1078 if (func != NULL) {
1079 g_debug ("performing destroy() on %s", priv->name);
1080 func (plugin);
1081 }
1082 }
1083
1084 if (priv->usb_ctx != NULL)
1085 g_object_unref (priv->usb_ctx);
1086 if (priv->module != NULL)
1087 g_module_close (priv->module);
1088 g_hash_table_unref (priv->devices);
Richard Hughesae3d65f2016-12-16 09:38:01 +00001089 g_hash_table_unref (priv->devices_delay);
Richard Hughescff38bc2016-12-12 12:03:37 +00001090 g_free (priv->name);
1091 g_free (priv->data);
1092
1093 G_OBJECT_CLASS (fu_plugin_parent_class)->finalize (object);
1094}
1095
1096FuPlugin *
1097fu_plugin_new (void)
1098{
1099 FuPlugin *plugin;
1100 plugin = g_object_new (FU_TYPE_PLUGIN, NULL);
1101 return plugin;
1102}
1103
1104GChecksumType
1105fu_plugin_get_checksum_type (FuPluginVerifyFlags flags)
1106{
1107 if (flags & FU_PLUGIN_VERIFY_FLAG_USE_SHA256)
1108 return G_CHECKSUM_SHA256;
1109 return G_CHECKSUM_SHA1;
1110}