mirror of
https://git.proxmox.com/git/fwupd
synced 2025-08-05 08:47:39 +00:00
Add a ->udev_device_changed plugin vfunc
This allows plugins to rescan hardware based on uevents of any device class registered with fu_plugin_add_udev_subsystem(). Additionally, the events are rate limited to avoid causing lots of extra plugin processing when replugging hardware.
This commit is contained in:
parent
751e125634
commit
5e952ce35f
@ -70,6 +70,7 @@ struct _FuEngine
|
||||
FuPluginList *plugin_list;
|
||||
GPtrArray *plugin_filter;
|
||||
GPtrArray *udev_subsystems;
|
||||
GHashTable *udev_changed_ids; /* sysfs:FuEngineUdevChangedHelper */
|
||||
FuSmbios *smbios;
|
||||
FuHwids *hwids;
|
||||
FuQuirks *quirks;
|
||||
@ -3938,10 +3939,69 @@ fu_engine_udev_device_remove (FuEngine *self, GUdevDevice *udev_device)
|
||||
}
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
FuEngine *self;
|
||||
GUdevDevice *udev_device;
|
||||
guint idle_id;
|
||||
} FuEngineUdevChangedHelper;
|
||||
|
||||
static void
|
||||
fu_engine_udev_changed_helper_free (FuEngineUdevChangedHelper *helper)
|
||||
{
|
||||
if (helper->idle_id != 0)
|
||||
g_source_remove (helper->idle_id);
|
||||
g_object_unref (helper->self);
|
||||
g_object_unref (helper->udev_device);
|
||||
g_free (helper);
|
||||
}
|
||||
|
||||
static FuEngineUdevChangedHelper *
|
||||
fu_engine_udev_changed_helper_new (FuEngine *self, GUdevDevice *udev_device)
|
||||
{
|
||||
FuEngineUdevChangedHelper *helper = g_new0 (FuEngineUdevChangedHelper, 1);
|
||||
helper->self = g_object_ref (self);
|
||||
helper->udev_device = g_object_ref (udev_device);
|
||||
return helper;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
fu_engine_udev_changed_cb (gpointer user_data)
|
||||
{
|
||||
FuEngineUdevChangedHelper *helper = (FuEngineUdevChangedHelper *) user_data;
|
||||
GPtrArray *plugins = fu_plugin_list_get_all (helper->self->plugin_list);
|
||||
g_autoptr(FuUdevDevice) device = fu_udev_device_new (helper->udev_device);
|
||||
|
||||
/* run all plugins */
|
||||
for (guint j = 0; j < plugins->len; j++) {
|
||||
FuPlugin *plugin_tmp = g_ptr_array_index (plugins, j);
|
||||
g_autoptr(GError) error = NULL;
|
||||
if (!fu_plugin_runner_udev_device_changed (plugin_tmp, device, &error)) {
|
||||
if (g_error_matches (error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED)) {
|
||||
g_debug ("%s ignoring: %s",
|
||||
fu_plugin_get_name (plugin_tmp),
|
||||
error->message);
|
||||
continue;
|
||||
}
|
||||
g_warning ("%s failed to change udev device %s: %s",
|
||||
fu_plugin_get_name (plugin_tmp),
|
||||
g_udev_device_get_sysfs_path (helper->udev_device),
|
||||
error->message);
|
||||
}
|
||||
}
|
||||
|
||||
/* device done, so remove ref */
|
||||
helper->idle_id = 0;
|
||||
g_hash_table_remove (helper->self->udev_changed_ids,
|
||||
g_udev_device_get_sysfs_path (helper->udev_device));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
fu_engine_udev_device_changed (FuEngine *self, GUdevDevice *udev_device)
|
||||
{
|
||||
const gchar *sysfs_path = g_udev_device_get_sysfs_path (udev_device);
|
||||
g_autoptr(GPtrArray) devices = NULL;
|
||||
FuEngineUdevChangedHelper *helper;
|
||||
|
||||
/* emit changed on any that match */
|
||||
devices = fu_device_list_get_all (self->device_list);
|
||||
@ -3950,10 +4010,20 @@ fu_engine_udev_device_changed (FuEngine *self, GUdevDevice *udev_device)
|
||||
if (!FU_IS_UDEV_DEVICE (device))
|
||||
continue;
|
||||
if (g_strcmp0 (fu_udev_device_get_sysfs_path (FU_UDEV_DEVICE (device)),
|
||||
g_udev_device_get_sysfs_path (udev_device)) == 0) {
|
||||
sysfs_path) == 0) {
|
||||
fu_udev_device_emit_changed (FU_UDEV_DEVICE (device));
|
||||
}
|
||||
}
|
||||
|
||||
/* run all plugins, with per-device rate limiting */
|
||||
if (g_hash_table_remove (self->udev_changed_ids, sysfs_path)) {
|
||||
g_debug ("re-adding rate-limited timeout for %s", sysfs_path);
|
||||
} else {
|
||||
g_debug ("adding rate-limited timeout for %s", sysfs_path);
|
||||
}
|
||||
helper = fu_engine_udev_changed_helper_new (self, udev_device);
|
||||
helper->idle_id = g_timeout_add (500, fu_engine_udev_changed_cb, helper);
|
||||
g_hash_table_insert (self->udev_changed_ids, g_strdup (sysfs_path), helper);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -4676,6 +4746,8 @@ fu_engine_init (FuEngine *self)
|
||||
self->plugin_list = fu_plugin_list_new ();
|
||||
self->plugin_filter = g_ptr_array_new_with_free_func (g_free);
|
||||
self->udev_subsystems = g_ptr_array_new_with_free_func (g_free);
|
||||
self->udev_changed_ids = g_hash_table_new_full (g_str_hash, g_str_equal,
|
||||
g_free, (GDestroyNotify) fu_engine_udev_changed_helper_free);
|
||||
self->runtime_versions = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
|
||||
self->compile_versions = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
|
||||
self->approved_firmware = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
|
||||
@ -4733,6 +4805,7 @@ fu_engine_finalize (GObject *obj)
|
||||
g_object_unref (self->device_list);
|
||||
g_ptr_array_unref (self->plugin_filter);
|
||||
g_ptr_array_unref (self->udev_subsystems);
|
||||
g_hash_table_unref (self->udev_changed_ids);
|
||||
g_hash_table_unref (self->runtime_versions);
|
||||
g_hash_table_unref (self->compile_versions);
|
||||
g_hash_table_unref (self->approved_firmware);
|
||||
|
@ -86,6 +86,9 @@ gboolean fu_plugin_runner_usb_device_added (FuPlugin *self,
|
||||
gboolean fu_plugin_runner_udev_device_added (FuPlugin *self,
|
||||
FuUdevDevice *device,
|
||||
GError **error);
|
||||
gboolean fu_plugin_runner_udev_device_changed (FuPlugin *self,
|
||||
FuUdevDevice *device,
|
||||
GError **error);
|
||||
void fu_plugin_runner_device_removed (FuPlugin *self,
|
||||
FuDevice *device);
|
||||
void fu_plugin_runner_device_register (FuPlugin *self,
|
||||
|
@ -80,6 +80,9 @@ gboolean fu_plugin_usb_device_added (FuPlugin *plugin,
|
||||
gboolean fu_plugin_udev_device_added (FuPlugin *plugin,
|
||||
FuUdevDevice *device,
|
||||
GError **error);
|
||||
gboolean fu_plugin_udev_device_changed (FuPlugin *plugin,
|
||||
FuUdevDevice *device,
|
||||
GError **error);
|
||||
gboolean fu_plugin_device_removed (FuPlugin *plugin,
|
||||
FuDevice *device,
|
||||
GError **error);
|
||||
|
@ -1305,6 +1305,43 @@ fu_plugin_runner_udev_device_added (FuPlugin *self, FuUdevDevice *device, GError
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
fu_plugin_runner_udev_device_changed (FuPlugin *self, FuUdevDevice *device, GError **error)
|
||||
{
|
||||
FuPluginPrivate *priv = GET_PRIVATE (self);
|
||||
FuPluginUdevDeviceAddedFunc func = NULL;
|
||||
g_autoptr(GError) error_local = NULL;
|
||||
|
||||
/* not enabled */
|
||||
if (!priv->enabled)
|
||||
return TRUE;
|
||||
|
||||
/* no object loaded */
|
||||
if (priv->module == NULL)
|
||||
return TRUE;
|
||||
|
||||
/* optional */
|
||||
g_module_symbol (priv->module, "fu_plugin_udev_device_changed", (gpointer *) &func);
|
||||
if (func == NULL)
|
||||
return TRUE;
|
||||
g_debug ("performing udev_device_changed() on %s", priv->name);
|
||||
if (!func (self, device, &error_local)) {
|
||||
if (error_local == NULL) {
|
||||
g_critical ("unset error in plugin %s for udev_device_changed()",
|
||||
priv->name);
|
||||
g_set_error_literal (&error_local,
|
||||
FWUPD_ERROR,
|
||||
FWUPD_ERROR_INTERNAL,
|
||||
"unspecified error");
|
||||
}
|
||||
g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
|
||||
"failed to change device on %s: ",
|
||||
priv->name);
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
fu_plugin_runner_device_removed (FuPlugin *self, FuDevice *device)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user