diff --git a/src/fu-device-list.c b/src/fu-device-list.c index 21fa70dca..932b65cab 100644 --- a/src/fu-device-list.c +++ b/src/fu-device-list.c @@ -78,6 +78,35 @@ fu_device_list_emit_device_changed (FuDeviceList *self, FuDevice *device) g_signal_emit (self, signals[SIGNAL_CHANGED], 0, device); } +static gchar * +fu_device_list_to_string (FuDeviceList *self) +{ + GString *str = g_string_new (NULL); + g_rw_lock_reader_lock (&self->devices_mutex); + for (guint i = 0; i < self->devices->len; i++) { + FuDeviceItem *item = g_ptr_array_index (self->devices, i); + gboolean wfr; + + g_string_append_printf (str, "%u [%p]\n", i, item); + wfr = fu_device_has_flag (item->device, + FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG); + g_string_append_printf (str, "new: %s [%p] %s\n", + fu_device_get_id (item->device), + item->device, + wfr ? "WAIT_FOR_REPLUG" : ""); + if (item->device_old != NULL) { + wfr = fu_device_has_flag (item->device_old, + FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG); + g_string_append_printf (str, "old: %s [%p] %s\n", + fu_device_get_id (item->device_old), + item->device_old, + wfr ? "WAIT_FOR_REPLUG" : ""); + } + } + g_rw_lock_reader_unlock (&self->devices_mutex); + return g_string_free (str, FALSE); +} + /* we cannot use fu_device_get_children() as this will not find "parent-only" * logical relationships added using fu_device_add_parent_guid() */ static GPtrArray * @@ -544,6 +573,25 @@ fu_device_list_item_set_device (FuDeviceItem *item, FuDevice *device) g_set_object (&item->device, device); } +static void +fu_device_list_clear_wait_for_replug (FuDeviceList *self, FuDeviceItem *item) +{ + if (fu_device_has_flag (item->device, FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG)) { + g_debug ("%s device came back, clearing flag", fu_device_get_id (item->device)); + fu_device_remove_flag (item->device, FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG); + } + if (item->device_old != NULL) { + if (fu_device_has_flag (item->device_old, FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG)) { + g_debug ("%s old device came back, clearing flag", fu_device_get_id (item->device_old)); + fu_device_remove_flag (item->device_old, FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG); + } + } + if (g_getenv ("FWUPD_DEVICE_LIST_VERBOSE") != NULL) { + g_autofree gchar *str = fu_device_list_to_string (self); + g_debug ("\n%s", str); + } +} + static void fu_device_list_replace (FuDeviceList *self, FuDeviceItem *item, FuDevice *device) { @@ -627,12 +675,13 @@ fu_device_list_replace (FuDeviceList *self, FuDeviceItem *item, FuDevice *device g_set_object (&item->device_old, item->device); fu_device_list_item_set_device (item, device); fu_device_list_emit_device_changed (self, device); + if (g_getenv ("FWUPD_DEVICE_LIST_VERBOSE") != NULL) { + g_autofree gchar *str = fu_device_list_to_string (self); + g_debug ("\n%s", str); + } /* we were waiting for this... */ - if (fu_device_has_flag (item->device_old, FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG)) { - g_debug ("device came back, clearing flag"); - fu_device_remove_flag (item->device_old, FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG); - } + fu_device_list_clear_wait_for_replug (self, item); } /** @@ -668,6 +717,33 @@ fu_device_list_add (FuDeviceList *self, FuDevice *device) /* is the device waiting to be replugged? */ item = fu_device_list_find_by_id (self, fu_device_get_id (device), NULL); if (item != NULL) { + + /* literally the same object */ + if (g_strcmp0 (fu_device_get_id (device), + fu_device_get_id (item->device)) == 0) { + g_debug ("found existing device %s", + fu_device_get_id (device)); + if (device != item->device) + fu_device_list_item_set_device (item, device); + fu_device_list_clear_wait_for_replug (self, item); + fu_device_list_emit_device_changed (self, device); + return; + } + + /* the old device again */ + if (item->device_old != NULL && + g_strcmp0 (fu_device_get_id (device), + fu_device_get_id (item->device_old)) == 0) { + g_debug ("found old device %s, swapping", + fu_device_get_id (device)); + g_set_object (&item->device_old, item->device); + fu_device_list_item_set_device (item, device); + fu_device_list_clear_wait_for_replug (self, item); + fu_device_list_emit_device_changed (self, device); + return; + } + + /* same ID, different object */ g_debug ("found existing device %s, reusing item", fu_device_get_id (item->device)); fu_device_list_replace (self, item, device); diff --git a/src/fu-self-test.c b/src/fu-self-test.c index 9f00e4a28..28da72208 100644 --- a/src/fu-self-test.c +++ b/src/fu-self-test.c @@ -2294,6 +2294,7 @@ fu_device_list_replug_user_func (gconstpointer user_data) /* fake devices */ fu_device_set_id (device1, "device1"); + fu_device_set_name (device1, "device1"); fu_device_add_internal_flag (device1, FU_DEVICE_INTERNAL_FLAG_REPLUG_MATCH_GUID); fu_device_add_instance_id (device1, "foo"); fu_device_add_instance_id (device1, "bar"); @@ -2301,6 +2302,7 @@ fu_device_list_replug_user_func (gconstpointer user_data) fu_device_set_remove_delay (device1, FU_DEVICE_REMOVE_DELAY_USER_REPLUG); fu_device_convert_instance_ids (device1); fu_device_set_id (device2, "device2"); + fu_device_set_name (device2, "device2"); fu_device_add_internal_flag (device2, FU_DEVICE_INTERNAL_FLAG_REPLUG_MATCH_GUID); fu_device_add_instance_id (device2, "baz"); fu_device_add_instance_id (device2, "bar"); /* matches */ @@ -2316,6 +2318,11 @@ fu_device_list_replug_user_func (gconstpointer user_data) /* add device */ fu_device_list_add (device_list, device1); + /* add duplicate */ + fu_device_add_flag (device1, FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG); + fu_device_list_add (device_list, device1); + g_assert_false (fu_device_has_flag (device1, FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG)); + /* not waiting */ ret = fu_device_list_wait_for_replug (device_list, &error); g_assert_no_error (error); @@ -2332,6 +2339,21 @@ fu_device_list_replug_user_func (gconstpointer user_data) g_assert_no_error (error); g_assert (ret); g_assert_false (fu_device_has_flag (device1, FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG)); + + /* should not be possible, but here we are */ + fu_device_add_flag (device1, FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG); + fu_device_add_flag (device2, FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG); + fu_device_list_add (device_list, device1); + g_assert_false (fu_device_has_flag (device1, FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG)); + g_assert_false (fu_device_has_flag (device2, FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG)); + + /* add back the old device */ + fu_device_add_flag (device1, FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG); + fu_device_add_flag (device2, FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG); + fu_device_list_remove (device_list, device2); + fu_device_list_add (device_list, device1); + g_assert_false (fu_device_has_flag (device1, FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG)); + g_assert_false (fu_device_has_flag (device2, FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG)); } static void @@ -3322,6 +3344,7 @@ main (int argc, char **argv) /* only critical and error are fatal */ g_log_set_fatal_mask (NULL, G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL); g_setenv ("G_MESSAGES_DEBUG", "all", TRUE); + g_setenv ("FWUPD_DEVICE_LIST_VERBOSE", "1", TRUE); g_setenv ("FWUPD_DATADIR", TESTDATADIR_SRC, TRUE); g_setenv ("FWUPD_PLUGINDIR", TESTDATADIR_SRC, TRUE); g_setenv ("FWUPD_SYSCONFDIR", TESTDATADIR_SRC, TRUE);