blob: fefe65e4dd8c6579d618b881b6f59895702fe008 [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 Hughesae3d65f2016-12-16 09:38:01 +0000381 g_debug ("waiting a small time for other plugins");
382 helper = g_new0 (FuPluginHelper, 1);
383 helper->plugin = g_object_ref (plugin);
384 helper->device = g_object_ref (device);
385 helper->timeout_id = g_timeout_add (500, fu_plugin_device_add_delay_cb, helper);
Richard Hughesd4184cf2016-12-21 16:05:17 +0000386 helper->devices = g_hash_table_ref (priv->devices_delay);
387 g_hash_table_insert (helper->devices, device, helper);
Richard Hughesae3d65f2016-12-16 09:38:01 +0000388}
389
Richard Hughes57d18222017-01-10 16:02:59 +0000390/**
391 * fu_plugin_device_add:
392 * @plugin: A #FuPlugin
393 * @device: A #FuDevice
394 *
395 * Asks the daemon to remove a device from the exported list.
396 *
397 * Since: 0.8.0
398 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000399void
400fu_plugin_device_remove (FuPlugin *plugin, FuDevice *device)
401{
Richard Hughesae3d65f2016-12-16 09:38:01 +0000402 FuPluginPrivate *priv = GET_PRIVATE (plugin);
403 FuPluginHelper *helper;
404
Richard Hughesccd78a92017-01-11 16:57:41 +0000405 g_return_if_fail (FU_IS_PLUGIN (plugin));
406 g_return_if_fail (FU_IS_DEVICE (device));
407
Richard Hughesae3d65f2016-12-16 09:38:01 +0000408 /* waiting for add */
409 helper = g_hash_table_lookup (priv->devices_delay, device);
410 if (helper != NULL) {
411 g_debug ("ignoring remove from delayed addition");
412 g_source_remove (helper->timeout_id);
Richard Hughesd4184cf2016-12-21 16:05:17 +0000413 g_hash_table_remove (priv->devices_delay, helper->device);
Richard Hughesae3d65f2016-12-16 09:38:01 +0000414 fu_plugin_helper_free (helper);
415 return;
416 }
417
Richard Hughescff38bc2016-12-12 12:03:37 +0000418 g_debug ("emit removed from %s: %s",
419 fu_plugin_get_name (plugin),
420 fu_device_get_id (device));
421 g_signal_emit (plugin, signals[SIGNAL_DEVICE_REMOVED], 0, device);
422}
423
Richard Hughes57d18222017-01-10 16:02:59 +0000424/**
425 * fu_plugin_set_status:
426 * @plugin: A #FuPlugin
427 * @status: A #FwupdStatus, e.g. #FWUPD_STATUS_DECOMPRESSING
428 *
429 * Sets the global state of the daemon according to the current plugin action.
430 *
431 * Since: 0.8.0
432 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000433void
434fu_plugin_set_status (FuPlugin *plugin, FwupdStatus status)
435{
Richard Hughesccd78a92017-01-11 16:57:41 +0000436 g_return_if_fail (FU_IS_PLUGIN (plugin));
Richard Hughescff38bc2016-12-12 12:03:37 +0000437 g_signal_emit (plugin, signals[SIGNAL_STATUS_CHANGED], 0, status);
438}
439
Richard Hughes57d18222017-01-10 16:02:59 +0000440/**
441 * fu_plugin_set_percentage:
442 * @plugin: A #FuPlugin
443 * @percentage: the percentage complete
444 *
445 * Sets the global completion of the daemon according to the current plugin
446 * action.
447 *
448 * Since: 0.8.0
449 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000450void
451fu_plugin_set_percentage (FuPlugin *plugin, guint percentage)
452{
Richard Hughesccd78a92017-01-11 16:57:41 +0000453 g_return_if_fail (FU_IS_PLUGIN (plugin));
454 g_return_if_fail (percentage <= 100);
Richard Hughescff38bc2016-12-12 12:03:37 +0000455 g_signal_emit (plugin, signals[SIGNAL_PERCENTAGE_CHANGED], 0,
456 percentage);
Richard Hughesd0905142016-03-13 09:46:49 +0000457}
458
Richard Hughes362d6d72017-01-07 21:42:14 +0000459/**
460 * fu_plugin_recoldplug:
461 * @plugin: A #FuPlugin
462 *
463 * Ask all the plugins to coldplug all devices, which will include the prepare()
464 * and cleanup() phases. Duplicate devices added will be ignored.
465 *
466 * Since: 0.8.0
467 **/
468void
469fu_plugin_recoldplug (FuPlugin *plugin)
470{
Richard Hughesccd78a92017-01-11 16:57:41 +0000471 g_return_if_fail (FU_IS_PLUGIN (plugin));
Richard Hughes362d6d72017-01-07 21:42:14 +0000472 g_signal_emit (plugin, signals[SIGNAL_RECOLDPLUG], 0);
473}
474
Richard Hughesb0829032017-01-10 09:27:08 +0000475/**
476 * fu_plugin_set_coldplug_delay:
477 * @plugin: A #FuPlugin
478 * @duration: A delay in milliseconds
479 *
480 * Set the minimum time that should be waited inbetween the call to
481 * fu_plugin_coldplug_prepare() and fu_plugin_coldplug(). This is usually going
482 * to be the minimum hardware initialisation time from a datasheet.
483 *
484 * It is better to use this function rather than using a sleep() in the plugin
485 * itself as then only one delay is done in the daemon rather than waiting for
486 * each coldplug prepare in a serial way.
487 *
488 * Additionally, very long delays should be avoided as the daemon will be
489 * blocked from processing requests whilst the coldplug delay is being
490 * performed.
491 *
492 * Since: 0.8.0
493 **/
494void
495fu_plugin_set_coldplug_delay (FuPlugin *plugin, guint duration)
496{
497 g_return_if_fail (FU_IS_PLUGIN (plugin));
498 g_return_if_fail (duration > 0);
499
500 /* check sanity */
501 if (duration > FU_PLUGIN_COLDPLUG_DELAY_MAXIMUM) {
502 g_warning ("duration of %ums is crazy, truncating to %ums",
503 duration,
504 FU_PLUGIN_COLDPLUG_DELAY_MAXIMUM);
505 duration = FU_PLUGIN_COLDPLUG_DELAY_MAXIMUM;
506 }
507
508 /* emit */
509 g_signal_emit (plugin, signals[SIGNAL_SET_COLDPLUG_DELAY], 0, duration);
510}
511
Richard Hughesd0905142016-03-13 09:46:49 +0000512gboolean
Richard Hughescff38bc2016-12-12 12:03:37 +0000513fu_plugin_runner_startup (FuPlugin *plugin, GError **error)
Richard Hughesd0905142016-03-13 09:46:49 +0000514{
Richard Hughescff38bc2016-12-12 12:03:37 +0000515 FuPluginPrivate *priv = GET_PRIVATE (plugin);
Richard Hughes7b8b2022016-12-12 16:15:03 +0000516 FuPluginStartupFunc func = NULL;
Richard Hughesd0905142016-03-13 09:46:49 +0000517
518 /* not enabled */
Richard Hughescff38bc2016-12-12 12:03:37 +0000519 if (!priv->enabled)
Richard Hughesd0905142016-03-13 09:46:49 +0000520 return TRUE;
521
522 /* optional */
Richard Hughescff38bc2016-12-12 12:03:37 +0000523 g_module_symbol (priv->module, "fu_plugin_startup", (gpointer *) &func);
524 if (func == NULL)
Richard Hughesd0905142016-03-13 09:46:49 +0000525 return TRUE;
Richard Hughescff38bc2016-12-12 12:03:37 +0000526 g_debug ("performing startup() on %s", priv->name);
Richard Hughesd0905142016-03-13 09:46:49 +0000527 if (!func (plugin, error)) {
Richard Hughescff38bc2016-12-12 12:03:37 +0000528 g_prefix_error (error, "failed to startup %s: ", priv->name);
529 return FALSE;
530 }
531 return TRUE;
532}
533
534static gboolean
535fu_plugin_runner_offline_invalidate (GError **error)
536{
537 g_autoptr(GError) error_local = NULL;
538 g_autoptr(GFile) file1 = NULL;
539
540 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
541
542 file1 = g_file_new_for_path (FU_OFFLINE_TRIGGER_FILENAME);
543 if (!g_file_query_exists (file1, NULL))
544 return TRUE;
545 if (!g_file_delete (file1, NULL, &error_local)) {
546 g_set_error (error,
547 FWUPD_ERROR,
548 FWUPD_ERROR_INTERNAL,
549 "Cannot delete %s: %s",
550 FU_OFFLINE_TRIGGER_FILENAME,
551 error_local->message);
552 return FALSE;
553 }
554 return TRUE;
555}
556
557static gboolean
558fu_plugin_runner_offline_setup (GError **error)
559{
560 gint rc;
561
562 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
563
564 /* create symlink for the systemd-system-update-generator */
565 rc = symlink ("/var/lib/fwupd", FU_OFFLINE_TRIGGER_FILENAME);
566 if (rc < 0) {
567 g_set_error (error,
568 FWUPD_ERROR,
569 FWUPD_ERROR_INTERNAL,
570 "Failed to create symlink %s to %s: %s",
571 FU_OFFLINE_TRIGGER_FILENAME,
572 "/var/lib", strerror (errno));
Richard Hughesd0905142016-03-13 09:46:49 +0000573 return FALSE;
574 }
575 return TRUE;
576}
577
Richard Hughesd0905142016-03-13 09:46:49 +0000578gboolean
Richard Hughescff38bc2016-12-12 12:03:37 +0000579fu_plugin_runner_coldplug (FuPlugin *plugin, GError **error)
Richard Hughesd0905142016-03-13 09:46:49 +0000580{
Richard Hughescff38bc2016-12-12 12:03:37 +0000581 FuPluginPrivate *priv = GET_PRIVATE (plugin);
Richard Hughes7b8b2022016-12-12 16:15:03 +0000582 FuPluginStartupFunc func = NULL;
Richard Hughesd0905142016-03-13 09:46:49 +0000583
584 /* not enabled */
Richard Hughescff38bc2016-12-12 12:03:37 +0000585 if (!priv->enabled)
Richard Hughesd0905142016-03-13 09:46:49 +0000586 return TRUE;
587
588 /* optional */
Richard Hughescff38bc2016-12-12 12:03:37 +0000589 g_module_symbol (priv->module, "fu_plugin_coldplug", (gpointer *) &func);
590 if (func == NULL)
Richard Hughesd0905142016-03-13 09:46:49 +0000591 return TRUE;
Richard Hughescff38bc2016-12-12 12:03:37 +0000592 g_debug ("performing coldplug() on %s", priv->name);
593 if (!func (plugin, error)) {
594 g_prefix_error (error, "failed to coldplug %s: ", priv->name);
595 return FALSE;
596 }
597 return TRUE;
598}
599
Richard Hughes7b8b2022016-12-12 16:15:03 +0000600gboolean
Richard Hughes46487c92017-01-07 21:26:34 +0000601fu_plugin_runner_coldplug_prepare (FuPlugin *plugin, GError **error)
602{
603 FuPluginPrivate *priv = GET_PRIVATE (plugin);
604 FuPluginStartupFunc func = NULL;
605
606 /* not enabled */
607 if (!priv->enabled)
608 return TRUE;
609
610 /* optional */
611 g_module_symbol (priv->module, "fu_plugin_coldplug_prepare", (gpointer *) &func);
612 if (func == NULL)
613 return TRUE;
614 g_debug ("performing coldplug_prepare() on %s", priv->name);
615 if (!func (plugin, error)) {
616 g_prefix_error (error, "failed to prepare for coldplug %s: ", priv->name);
617 return FALSE;
618 }
619 return TRUE;
620}
621
622gboolean
623fu_plugin_runner_coldplug_cleanup (FuPlugin *plugin, GError **error)
624{
625 FuPluginPrivate *priv = GET_PRIVATE (plugin);
626 FuPluginStartupFunc func = NULL;
627
628 /* not enabled */
629 if (!priv->enabled)
630 return TRUE;
631
632 /* optional */
633 g_module_symbol (priv->module, "fu_plugin_coldplug_cleanup", (gpointer *) &func);
634 if (func == NULL)
635 return TRUE;
636 g_debug ("performing coldplug_cleanup() on %s", priv->name);
637 if (!func (plugin, error)) {
638 g_prefix_error (error, "failed to cleanup coldplug %s: ", priv->name);
639 return FALSE;
640 }
641 return TRUE;
642}
643
644gboolean
Richard Hughes7b8b2022016-12-12 16:15:03 +0000645fu_plugin_runner_update_prepare (FuPlugin *plugin, FuDevice *device, GError **error)
646{
647 FuPluginPrivate *priv = GET_PRIVATE (plugin);
648 FuPluginDeviceFunc func = NULL;
649
650 /* not enabled */
651 if (!priv->enabled)
652 return TRUE;
653
654 /* optional */
655 g_module_symbol (priv->module, "fu_plugin_update_prepare", (gpointer *) &func);
656 if (func == NULL)
657 return TRUE;
658 g_debug ("performing update_prepare() on %s", priv->name);
659 if (!func (plugin, device, error)) {
660 g_prefix_error (error, "failed to prepare for update %s: ", priv->name);
661 return FALSE;
662 }
663 return TRUE;
664}
665
666gboolean
667fu_plugin_runner_update_cleanup (FuPlugin *plugin, FuDevice *device, GError **error)
668{
669 FuPluginPrivate *priv = GET_PRIVATE (plugin);
670 FuPluginDeviceFunc func = NULL;
671
672 /* not enabled */
673 if (!priv->enabled)
674 return TRUE;
675
676 /* optional */
677 g_module_symbol (priv->module, "fu_plugin_update_cleanup", (gpointer *) &func);
678 if (func == NULL)
679 return TRUE;
680 g_debug ("performing update_cleanup() on %s", priv->name);
681 if (!func (plugin, device, error)) {
682 g_prefix_error (error, "failed to cleanup update %s: ", priv->name);
683 return FALSE;
684 }
685 return TRUE;
686}
687
Richard Hughescff38bc2016-12-12 12:03:37 +0000688static gboolean
689fu_plugin_runner_schedule_update (FuPlugin *plugin,
690 FuDevice *device,
691 GBytes *blob_cab,
692 GError **error)
693{
694 gchar tmpname[] = {"XXXXXX.cap"};
695 g_autofree gchar *dirname = NULL;
696 g_autofree gchar *filename = NULL;
697 g_autoptr(FwupdResult) res_tmp = NULL;
698 g_autoptr(FuPending) pending = NULL;
699 g_autoptr(GFile) file = NULL;
700
701 /* id already exists */
702 pending = fu_pending_new ();
703 res_tmp = fu_pending_get_device (pending, fu_device_get_id (device), NULL);
704 if (res_tmp != NULL) {
705 g_set_error (error,
706 FWUPD_ERROR,
707 FWUPD_ERROR_ALREADY_PENDING,
708 "%s is already scheduled to be updated",
709 fu_device_get_id (device));
710 return FALSE;
711 }
712
713 /* create directory */
714 dirname = g_build_filename (LOCALSTATEDIR, "lib", "fwupd", NULL);
715 file = g_file_new_for_path (dirname);
716 if (!g_file_query_exists (file, NULL)) {
717 if (!g_file_make_directory_with_parents (file, NULL, error))
718 return FALSE;
719 }
720
721 /* get a random filename */
722 for (guint i = 0; i < 6; i++)
723 tmpname[i] = (gchar) g_random_int_range ('A', 'Z');
724 filename = g_build_filename (dirname, tmpname, NULL);
725
726 /* just copy to the temp file */
727 fu_plugin_set_status (plugin, FWUPD_STATUS_SCHEDULING);
728 if (!g_file_set_contents (filename,
729 g_bytes_get_data (blob_cab, NULL),
730 (gssize) g_bytes_get_size (blob_cab),
731 error))
732 return FALSE;
733
734 /* schedule for next boot */
735 g_debug ("schedule %s to be installed to %s on next boot",
736 filename, fu_device_get_id (device));
737 fu_device_set_update_filename (device, filename);
738
739 /* add to database */
740 if (!fu_pending_add_device (pending, FWUPD_RESULT (device), error))
741 return FALSE;
742
743 /* next boot we run offline */
744 return fu_plugin_runner_offline_setup (error);
745}
746
747gboolean
748fu_plugin_runner_verify (FuPlugin *plugin,
749 FuDevice *device,
750 FuPluginVerifyFlags flags,
751 GError **error)
752{
753 FuPluginPrivate *priv = GET_PRIVATE (plugin);
Richard Hughes7b8b2022016-12-12 16:15:03 +0000754 FuPluginVerifyFunc func = NULL;
Richard Hughescff38bc2016-12-12 12:03:37 +0000755
756 /* not enabled */
757 if (!priv->enabled)
758 return TRUE;
759
760 /* optional */
761 g_module_symbol (priv->module, "fu_plugin_verify", (gpointer *) &func);
762 if (func == NULL)
763 return TRUE;
764 g_debug ("performing verify() on %s", priv->name);
765 if (!func (plugin, device, flags, error)) {
766 g_prefix_error (error, "failed to verify %s: ", priv->name);
Richard Hughesd0905142016-03-13 09:46:49 +0000767 return FALSE;
768 }
769 return TRUE;
770}
771
Richard Hughesd0905142016-03-13 09:46:49 +0000772gboolean
Richard Hughescff38bc2016-12-12 12:03:37 +0000773fu_plugin_runner_unlock (FuPlugin *plugin, FuDevice *device, GError **error)
Richard Hughesd0905142016-03-13 09:46:49 +0000774{
Richard Hughescff38bc2016-12-12 12:03:37 +0000775 guint64 flags;
776 FuPluginPrivate *priv = GET_PRIVATE (plugin);
Richard Hughes7b8b2022016-12-12 16:15:03 +0000777 FuPluginDeviceFunc func = NULL;
Richard Hughesd0905142016-03-13 09:46:49 +0000778
779 /* not enabled */
Richard Hughescff38bc2016-12-12 12:03:37 +0000780 if (!priv->enabled)
781 return TRUE;
782
783 /* final check */
784 flags = fu_device_get_flags (device);
785 if ((flags & FWUPD_DEVICE_FLAG_LOCKED) == 0) {
786 g_set_error (error,
787 FWUPD_ERROR,
788 FWUPD_ERROR_NOT_SUPPORTED,
789 "Device %s is not locked",
790 fu_device_get_id (device));
791 return FALSE;
792 }
793
794 /* optional */
795 g_module_symbol (priv->module, "fu_plugin_unlock", (gpointer *) &func);
796 if (func != NULL) {
797 g_debug ("performing unlock() on %s", priv->name);
798 if (!func (plugin, device, error)) {
Richard Hughes7b8b2022016-12-12 16:15:03 +0000799 g_prefix_error (error, "failed to unlock %s: ", priv->name);
Richard Hughescff38bc2016-12-12 12:03:37 +0000800 return FALSE;
801 }
802 }
803
804 /* update with correct flags */
805 flags = fu_device_get_flags (device);
806 fu_device_set_flags (device, flags &= ~FWUPD_DEVICE_FLAG_LOCKED);
807 fu_device_set_modified (device, (guint64) g_get_real_time () / G_USEC_PER_SEC);
808 return TRUE;
809}
810
811gboolean
812fu_plugin_runner_update (FuPlugin *plugin,
813 FuDevice *device,
814 GBytes *blob_cab,
815 GBytes *blob_fw,
816 FwupdInstallFlags flags,
817 GError **error)
818{
819 FuPluginPrivate *priv = GET_PRIVATE (plugin);
820 FuPluginUpdateFunc func_online;
821 FuPluginUpdateFunc func_offline;
822 g_autoptr(FuPending) pending = NULL;
823 g_autoptr(FwupdResult) res_pending = NULL;
824 GError *error_update = NULL;
825
826 /* not enabled */
827 if (!priv->enabled)
Richard Hughesd0905142016-03-13 09:46:49 +0000828 return TRUE;
829
830 /* optional */
Richard Hughescff38bc2016-12-12 12:03:37 +0000831 g_module_symbol (priv->module, "fu_plugin_update_online", (gpointer *) &func_online);
832 g_module_symbol (priv->module, "fu_plugin_update_offline", (gpointer *) &func_offline);
Richard Hughesd0905142016-03-13 09:46:49 +0000833
Richard Hughescff38bc2016-12-12 12:03:37 +0000834 /* schedule for next reboot, or handle in the plugin */
835 if (flags & FWUPD_INSTALL_FLAG_OFFLINE) {
836 if (func_offline == NULL) {
837 return fu_plugin_runner_schedule_update (plugin,
838 device,
839 blob_cab,
840 error);
841 }
842 return func_offline (plugin, device, blob_fw, flags, error);
843 }
844
845 /* cancel the pending action */
846 if (!fu_plugin_runner_offline_invalidate (error))
847 return FALSE;
848
849 /* online */
850 if (func_online == NULL) {
851 g_set_error_literal (error,
852 FWUPD_ERROR,
853 FWUPD_ERROR_NOT_SUPPORTED,
854 "No online update possible");
Richard Hughesd0905142016-03-13 09:46:49 +0000855 return FALSE;
856 }
Richard Hughescff38bc2016-12-12 12:03:37 +0000857 pending = fu_pending_new ();
858 res_pending = fu_pending_get_device (pending, fu_device_get_id (device), NULL);
859 if (!func_online (plugin, device, blob_fw, flags, &error_update)) {
860 /* save the error to the database */
861 if (res_pending != NULL) {
862 fu_pending_set_error_msg (pending, FWUPD_RESULT (device),
863 error_update->message, NULL);
864 }
865 g_propagate_error (error, error_update);
866 return FALSE;
867 }
868
869 /* cleanup */
870 if (res_pending != NULL) {
871 const gchar *tmp;
872
873 /* update pending database */
874 fu_pending_set_state (pending, FWUPD_RESULT (device),
875 FWUPD_UPDATE_STATE_SUCCESS, NULL);
876
877 /* delete cab file */
878 tmp = fwupd_result_get_update_filename (res_pending);
879 if (tmp != NULL && g_str_has_prefix (tmp, LIBEXECDIR)) {
880 g_autoptr(GError) error_local = NULL;
881 g_autoptr(GFile) file = NULL;
882 file = g_file_new_for_path (tmp);
883 if (!g_file_delete (file, NULL, &error_local)) {
884 g_set_error (error,
885 FWUPD_ERROR,
886 FWUPD_ERROR_INVALID_FILE,
887 "Failed to delete %s: %s",
888 tmp, error_local->message);
889 return FALSE;
890 }
891 }
892 }
Richard Hughesd0905142016-03-13 09:46:49 +0000893 return TRUE;
894}
Richard Hughescff38bc2016-12-12 12:03:37 +0000895
896gboolean
897fu_plugin_runner_clear_results (FuPlugin *plugin, FuDevice *device, GError **error)
898{
899 FuPluginPrivate *priv = GET_PRIVATE (plugin);
Richard Hughes7b8b2022016-12-12 16:15:03 +0000900 FuPluginDeviceFunc func = NULL;
Richard Hughescff38bc2016-12-12 12:03:37 +0000901 g_autoptr(GError) error_local = NULL;
902 g_autoptr(FwupdResult) res_pending = NULL;
903 g_autoptr(FuPending) pending = NULL;
904
905 /* not enabled */
906 if (!priv->enabled)
907 return TRUE;
908
909 /* use the plugin if the vfunc is provided */
910 g_module_symbol (priv->module, "fu_plugin_clear_result", (gpointer *) &func);
911 if (func != NULL) {
912 g_debug ("performing clear_result() on %s", priv->name);
913 if (!func (plugin, device, error)) {
914 g_prefix_error (error, "failed to clear_result %s: ", priv->name);
915 return FALSE;
916 }
917 return TRUE;
918 }
919
920 /* handled using the database */
921 pending = fu_pending_new ();
922 res_pending = fu_pending_get_device (pending,
923 fu_device_get_id (device),
924 &error_local);
925 if (res_pending == NULL) {
926 g_set_error (error,
927 FWUPD_ERROR,
928 FWUPD_ERROR_INVALID_FILE,
929 "Failed to find %s in pending database: %s",
930 fu_device_get_id (device),
931 error_local->message);
932 return FALSE;
933 }
934
935 /* remove from pending database */
936 return fu_pending_remove_device (pending, FWUPD_RESULT (device), error);
937}
938
939gboolean
940fu_plugin_runner_get_results (FuPlugin *plugin, FuDevice *device, GError **error)
941{
942 FuPluginPrivate *priv = GET_PRIVATE (plugin);
Richard Hughes7b8b2022016-12-12 16:15:03 +0000943 FuPluginDeviceFunc func = NULL;
Richard Hughescff38bc2016-12-12 12:03:37 +0000944 FwupdUpdateState update_state;
945 const gchar *tmp;
946 g_autoptr(GError) error_local = NULL;
947 g_autoptr(FwupdResult) res_pending = NULL;
948 g_autoptr(FuPending) pending = NULL;
949
950 /* not enabled */
951 if (!priv->enabled)
952 return TRUE;
953
954 /* use the plugin if the vfunc is provided */
955 g_module_symbol (priv->module, "fu_plugin_get_results", (gpointer *) &func);
956 if (func != NULL) {
957 g_debug ("performing get_results() on %s", priv->name);
958 if (!func (plugin, device, error)) {
959 g_prefix_error (error, "failed to get_results %s: ", priv->name);
960 return FALSE;
961 }
962 return TRUE;
963 }
964
965 /* handled using the database */
966 pending = fu_pending_new ();
967 res_pending = fu_pending_get_device (pending,
968 fu_device_get_id (device),
969 &error_local);
970 if (res_pending == NULL) {
971 g_set_error (error,
972 FWUPD_ERROR,
973 FWUPD_ERROR_NOTHING_TO_DO,
974 "Failed to find %s in pending database: %s",
975 fu_device_get_id (device),
976 error_local->message);
977 return FALSE;
978 }
979
980 /* copy the important parts from the pending device to the real one */
981 update_state = fwupd_result_get_update_state (res_pending);
982 if (update_state == FWUPD_UPDATE_STATE_UNKNOWN ||
983 update_state == FWUPD_UPDATE_STATE_PENDING) {
984 g_set_error (error,
985 FWUPD_ERROR,
986 FWUPD_ERROR_NOTHING_TO_DO,
987 "Device %s has not been updated offline yet",
988 fu_device_get_id (device));
989 return FALSE;
990 }
991
992 /* copy */
993 fu_device_set_update_state (device, update_state);
994 tmp = fwupd_result_get_update_error (res_pending);
995 if (tmp != NULL)
996 fu_device_set_update_error (device, tmp);
997 tmp = fwupd_result_get_device_version (res_pending);
998 if (tmp != NULL)
999 fu_device_set_version (device, tmp);
1000 tmp = fwupd_result_get_update_version (res_pending);
1001 if (tmp != NULL)
1002 fu_device_set_update_version (device, tmp);
1003 return TRUE;
1004}
1005
1006static void
1007fu_plugin_class_init (FuPluginClass *klass)
1008{
1009 GObjectClass *object_class = G_OBJECT_CLASS (klass);
1010 object_class->finalize = fu_plugin_finalize;
1011 signals[SIGNAL_DEVICE_ADDED] =
1012 g_signal_new ("device-added",
1013 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
1014 G_STRUCT_OFFSET (FuPluginClass, device_added),
1015 NULL, NULL, g_cclosure_marshal_VOID__OBJECT,
1016 G_TYPE_NONE, 1, FU_TYPE_DEVICE);
1017 signals[SIGNAL_DEVICE_REMOVED] =
1018 g_signal_new ("device-removed",
1019 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
1020 G_STRUCT_OFFSET (FuPluginClass, device_removed),
1021 NULL, NULL, g_cclosure_marshal_VOID__OBJECT,
1022 G_TYPE_NONE, 1, FU_TYPE_DEVICE);
1023 signals[SIGNAL_STATUS_CHANGED] =
1024 g_signal_new ("status-changed",
1025 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
1026 G_STRUCT_OFFSET (FuPluginClass, status_changed),
1027 NULL, NULL, g_cclosure_marshal_VOID__UINT,
1028 G_TYPE_NONE, 1, G_TYPE_UINT);
1029 signals[SIGNAL_PERCENTAGE_CHANGED] =
1030 g_signal_new ("percentage-changed",
1031 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
1032 G_STRUCT_OFFSET (FuPluginClass, percentage_changed),
1033 NULL, NULL, g_cclosure_marshal_VOID__UINT,
1034 G_TYPE_NONE, 1, G_TYPE_UINT);
Richard Hughes362d6d72017-01-07 21:42:14 +00001035 signals[SIGNAL_RECOLDPLUG] =
1036 g_signal_new ("recoldplug",
1037 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
1038 G_STRUCT_OFFSET (FuPluginClass, recoldplug),
1039 NULL, NULL, g_cclosure_marshal_VOID__VOID,
1040 G_TYPE_NONE, 0);
Richard Hughesb0829032017-01-10 09:27:08 +00001041 signals[SIGNAL_SET_COLDPLUG_DELAY] =
1042 g_signal_new ("set-coldplug-delay",
1043 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
1044 G_STRUCT_OFFSET (FuPluginClass, set_coldplug_delay),
1045 NULL, NULL, g_cclosure_marshal_VOID__UINT,
1046 G_TYPE_NONE, 1, G_TYPE_UINT);
Richard Hughescff38bc2016-12-12 12:03:37 +00001047}
1048
1049static void
1050fu_plugin_init (FuPlugin *plugin)
1051{
1052 FuPluginPrivate *priv = GET_PRIVATE (plugin);
1053 priv->enabled = TRUE;
1054 priv->devices = g_hash_table_new_full (g_str_hash, g_str_equal,
1055 g_free, (GDestroyNotify) g_object_unref);
Richard Hughesae3d65f2016-12-16 09:38:01 +00001056 priv->devices_delay = g_hash_table_new (g_str_hash, g_str_equal);
Richard Hughescff38bc2016-12-12 12:03:37 +00001057}
1058
1059static void
1060fu_plugin_finalize (GObject *object)
1061{
1062 FuPlugin *plugin = FU_PLUGIN (object);
1063 FuPluginPrivate *priv = GET_PRIVATE (plugin);
1064 FuPluginInitFunc func = NULL;
1065
1066 /* optional */
1067 if (priv->module != NULL) {
1068 g_module_symbol (priv->module, "fu_plugin_destroy", (gpointer *) &func);
1069 if (func != NULL) {
1070 g_debug ("performing destroy() on %s", priv->name);
1071 func (plugin);
1072 }
1073 }
1074
1075 if (priv->usb_ctx != NULL)
1076 g_object_unref (priv->usb_ctx);
1077 if (priv->module != NULL)
1078 g_module_close (priv->module);
1079 g_hash_table_unref (priv->devices);
Richard Hughesae3d65f2016-12-16 09:38:01 +00001080 g_hash_table_unref (priv->devices_delay);
Richard Hughescff38bc2016-12-12 12:03:37 +00001081 g_free (priv->name);
1082 g_free (priv->data);
1083
1084 G_OBJECT_CLASS (fu_plugin_parent_class)->finalize (object);
1085}
1086
1087FuPlugin *
1088fu_plugin_new (void)
1089{
1090 FuPlugin *plugin;
1091 plugin = g_object_new (FU_TYPE_PLUGIN, NULL);
1092 return plugin;
1093}
1094
1095GChecksumType
1096fu_plugin_get_checksum_type (FuPluginVerifyFlags flags)
1097{
1098 if (flags & FU_PLUGIN_VERIFY_FLAG_USE_SHA256)
1099 return G_CHECKSUM_SHA256;
1100 return G_CHECKSUM_SHA1;
1101}