From 35ca4cbc616da565d7d154b0d66e342ed74e6440 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Tue, 14 Apr 2020 17:09:01 +0100 Subject: [PATCH] Allow devices to match the proxy device by GUID This allows us to use a proxy even if the proxy device was created in a different plugin or where the GTypes are not known to each other. --- libfwupdplugin/fu-device.c | 49 +++++++++++++++++++++++++++++++- libfwupdplugin/fu-device.h | 3 ++ libfwupdplugin/fu-quirks.h | 1 + libfwupdplugin/fwupdplugin.map | 2 ++ src/fu-engine.c | 51 ++++++++++++++++++++++++++++++++++ 5 files changed, 105 insertions(+), 1 deletion(-) diff --git a/libfwupdplugin/fu-device.c b/libfwupdplugin/fu-device.c index 9b2f3b5e1..3af23d04d 100644 --- a/libfwupdplugin/fu-device.c +++ b/libfwupdplugin/fu-device.c @@ -36,6 +36,7 @@ typedef struct { gchar *equivalent_id; gchar *physical_id; gchar *logical_id; + gchar *proxy_guid; FuDevice *alternate; FuDevice *parent; /* noref */ FuDevice *proxy; /* noref */ @@ -1005,6 +1006,10 @@ fu_device_set_quirk_kv (FuDevice *self, fu_device_add_parent_guid (self, value); return TRUE; } + if (g_strcmp0 (key, FU_QUIRKS_PROXY_GUID) == 0) { + fu_device_set_proxy_guid (self, value); + return TRUE; + } if (g_strcmp0 (key, FU_QUIRKS_FIRMWARE_SIZE_MIN) == 0) { fu_device_set_firmware_size_min (self, fu_common_strtoull (value)); return TRUE; @@ -1833,6 +1838,43 @@ fu_device_set_logical_id (FuDevice *self, const gchar *logical_id) priv->logical_id = g_strdup (logical_id); } +/** + * fu_device_get_proxy_guid: + * @self: A #FuDevice + * + * Gets the proxy GUID device, which which is set to let the engine match up the + * proxy between plugins. + * + * Returns: a string value, or %NULL if never set. + * + * Since: 1.4.1 + **/ +const gchar * +fu_device_get_proxy_guid (FuDevice *self) +{ + FuDevicePrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FU_IS_DEVICE (self), NULL); + return priv->proxy_guid; +} + +/** + * fu_device_set_proxy_guid: + * @self: A #FuDevice + * @proxy_guid: a string, e.g. `USB\VID_413C&PID_B06E&hub` + * + * Sets the GUID of the proxy device. The proxy device may update @self. + * + * Since: 1.4.1 + **/ +void +fu_device_set_proxy_guid (FuDevice *self, const gchar *proxy_guid) +{ + FuDevicePrivate *priv = GET_PRIVATE (self); + g_return_if_fail (FU_IS_DEVICE (self)); + g_free (priv->proxy_guid); + priv->proxy_guid = g_strdup (proxy_guid); +} + /** * fu_device_get_protocol: * @self: A #FuDevice @@ -2199,7 +2241,9 @@ fu_device_add_string (FuDevice *self, guint idt, GString *str) if (priv->logical_id != NULL) fu_common_string_append_kv (str, idt + 1, "LogicalId", priv->logical_id); if (priv->proxy != NULL) - fu_common_string_append_kv (str, idt + 1, "Proxy", fu_device_get_id (priv->proxy)); + fu_common_string_append_kv (str, idt + 1, "ProxyId", fu_device_get_id (priv->proxy)); + if (priv->proxy_guid != NULL) + fu_common_string_append_kv (str, idt + 1, "ProxyGuid", priv->proxy_guid); if (priv->size_min > 0) { g_autofree gchar *sz = g_strdup_printf ("%" G_GUINT64_FORMAT, priv->size_min); fu_common_string_append_kv (str, idt + 1, "FirmwareSizeMin", sz); @@ -2936,6 +2980,8 @@ fu_device_incorporate (FuDevice *self, FuDevice *donor) fu_device_set_logical_id (self, priv_donor->logical_id); if (priv->proxy == NULL && priv_donor->proxy != NULL) fu_device_set_proxy (self, priv_donor->proxy); + if (priv->proxy_guid == NULL && priv_donor->proxy_guid != NULL) + fu_device_set_proxy_guid (self, priv_donor->proxy_guid); if (priv->quirks == NULL) fu_device_set_quirks (self, fu_device_get_quirks (donor)); g_rw_lock_reader_lock (&priv_donor->parent_guids_mutex); @@ -3096,6 +3142,7 @@ fu_device_finalize (GObject *object) g_free (priv->equivalent_id); g_free (priv->physical_id); g_free (priv->logical_id); + g_free (priv->proxy_guid); G_OBJECT_CLASS (fu_device_parent_class)->finalize (object); } diff --git a/libfwupdplugin/fu-device.h b/libfwupdplugin/fu-device.h index 7a5003335..d7d310d92 100644 --- a/libfwupdplugin/fu-device.h +++ b/libfwupdplugin/fu-device.h @@ -220,6 +220,9 @@ void fu_device_set_physical_id (FuDevice *self, const gchar *fu_device_get_logical_id (FuDevice *self); void fu_device_set_logical_id (FuDevice *self, const gchar *logical_id); +const gchar *fu_device_get_proxy_guid (FuDevice *self); +void fu_device_set_proxy_guid (FuDevice *self, + const gchar *proxy_guid); const gchar *fu_device_get_protocol (FuDevice *self); void fu_device_set_protocol (FuDevice *self, const gchar *protocol); diff --git a/libfwupdplugin/fu-quirks.h b/libfwupdplugin/fu-quirks.h index 61fcd8b79..1ebfdab8c 100644 --- a/libfwupdplugin/fu-quirks.h +++ b/libfwupdplugin/fu-quirks.h @@ -51,6 +51,7 @@ gboolean fu_quirks_lookup_by_id_iter (FuQuirks *self, #define FU_QUIRKS_GUID "Guid" #define FU_QUIRKS_COUNTERPART_GUID "CounterpartGuid" #define FU_QUIRKS_PARENT_GUID "ParentGuid" +#define FU_QUIRKS_PROXY_GUID "ProxyGuid" #define FU_QUIRKS_CHILDREN "Children" #define FU_QUIRKS_VERSION "Version" #define FU_QUIRKS_VENDOR "Vendor" diff --git a/libfwupdplugin/fwupdplugin.map b/libfwupdplugin/fwupdplugin.map index 0dcc4094f..875afc744 100644 --- a/libfwupdplugin/fwupdplugin.map +++ b/libfwupdplugin/fwupdplugin.map @@ -575,6 +575,8 @@ LIBFWUPDPLUGIN_1.4.0 { LIBFWUPDPLUGIN_1.4.1 { global: fu_device_get_proxy; + fu_device_get_proxy_guid; fu_device_set_proxy; + fu_device_set_proxy_guid; local: *; } LIBFWUPDPLUGIN_1.4.0; diff --git a/src/fu-engine.c b/src/fu-engine.c index 269bcb1e8..cc6267be9 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -4390,6 +4390,54 @@ fu_engine_adopt_children (FuEngine *self, FuDevice *device) } } +static void +fu_engine_set_proxy_device (FuEngine *self, FuDevice *device) +{ + GPtrArray *guids; + g_autoptr(FuDevice) proxy = NULL; + g_autoptr(GPtrArray) devices = NULL; + + if (fu_device_get_proxy (device) != NULL) + return; + if (fu_device_get_proxy_guid (device) == NULL) + return; + + /* find the proxy GUID in any existing device */ + proxy = fu_device_list_get_by_guid (self->device_list, + fu_device_get_proxy_guid (device), + NULL); + if (proxy != NULL) { + g_debug ("setting proxy of %s to %s for %s", + fu_device_get_id (proxy), + fu_device_get_id (device), + fu_device_get_proxy_guid (device)); + fu_device_set_proxy (device, proxy); + return; + } + + /* are we the parent of an existing device */ + guids = fu_device_get_guids (device); + for (guint j = 0; j < guids->len; j++) { + const gchar *guid = g_ptr_array_index (guids, j); + devices = fu_device_list_get_active (self->device_list); + for (guint i = 0; i < devices->len; i++) { + FuDevice *device_tmp = g_ptr_array_index (devices, i); + if (g_strcmp0 (fu_device_get_proxy_guid (device_tmp), guid) == 0) { + g_debug ("adding proxy of %s to %s for %s", + fu_device_get_id (device), + fu_device_get_id (device_tmp), + guid); + fu_device_set_proxy (device_tmp, device); + return; + } + } + } + + /* nothing found */ + g_warning ("did not find proxy device %s", + fu_device_get_proxy_guid (device)); +} + static void fu_engine_device_inherit_history (FuEngine *self, FuDevice *device) { @@ -4488,6 +4536,9 @@ fu_engine_add_device (FuEngine *self, FuDevice *device) /* adopt any required children, which may or may not already exist */ fu_engine_adopt_children (self, device); + /* set the proxy device if specified by GUID */ + fu_engine_set_proxy_device (self, device); + /* set any alternate objects on the device from the ID */ if (fu_device_get_alternate_id (device) != NULL) { g_autoptr(FuDevice) device_alt = NULL;