diff --git a/src/fu-self-test.c b/src/fu-self-test.c index b479fe782..edc040eb7 100644 --- a/src/fu-self-test.c +++ b/src/fu-self-test.c @@ -3145,6 +3145,32 @@ _plugin_device_register_cb(FuPlugin *plugin, FuDevice *device, gpointer user_dat fu_plugin_runner_device_register(plugin, device); } +static void +fu_backend_usb_hotplug_cb(FuBackend *backend, FuDevice *device, gpointer user_data) +{ + guint *cnt = (guint *)user_data; + (*cnt)++; +} + +static void +fu_backend_usb_load_file(FuBackend *backend, const gchar *fn) +{ + gboolean ret; + g_autoptr(GError) error = NULL; + g_autoptr(JsonParser) parser = json_parser_new(); + + ret = json_parser_load_from_file(parser, fn, &error); + g_assert_no_error(error); + g_assert_true(ret); + ret = fu_backend_load(backend, + json_node_get_object(json_parser_get_root(parser)), + NULL, + FU_BACKEND_LOAD_FLAG_NONE, + &error); + g_assert_no_error(error); + g_assert_true(ret); +} + /* * To generate the fwupd DS20 descriptor in the usb-devices.json file save fw-ds20.builder.xml: * @@ -3174,8 +3200,12 @@ fu_backend_usb_func(gconstpointer user_data) #ifdef HAVE_GUSB FuTest *self = (FuTest *)user_data; gboolean ret; + guint cnt_added = 0; + guint cnt_removed = 0; FuDevice *device_tmp; g_autofree gchar *gusb_emulate_fn = NULL; + g_autofree gchar *gusb_emulate_fn2 = NULL; + g_autofree gchar *gusb_emulate_fn3 = NULL; g_autofree gchar *devicestr = NULL; g_autoptr(FuBackend) backend = fu_usb_backend_new(self->ctx); g_autoptr(FuDeviceLocker) locker = NULL; @@ -3183,33 +3213,37 @@ fu_backend_usb_func(gconstpointer user_data) g_autoptr(GError) error = NULL; g_autoptr(GPtrArray) devices = NULL; g_autoptr(GPtrArray) possible_plugins = NULL; - g_autoptr(JsonParser) parser = json_parser_new(); -#if !G_USB_CHECK_VERSION(0, 4, 2) +#if !G_USB_CHECK_VERSION(0, 4, 4) g_test_skip("GUsb version too old"); return; #endif + /* check there were events */ + g_signal_connect(backend, + "device-added", + G_CALLBACK(fu_backend_usb_hotplug_cb), + &cnt_added); + g_signal_connect(backend, + "device-removed", + G_CALLBACK(fu_backend_usb_hotplug_cb), + &cnt_removed); /* load the JSON into the backend */ - gusb_emulate_fn = g_test_build_filename(G_TEST_DIST, "tests", "usb-devices.json", NULL); - ret = json_parser_load_from_file(parser, gusb_emulate_fn, &error); - g_assert_no_error(error); - g_assert_true(ret); g_assert_cmpstr(fu_backend_get_name(backend), ==, "usb"); g_assert_true(fu_backend_get_enabled(backend)); ret = fu_backend_setup(backend, progress, &error); g_assert_no_error(error); g_assert_true(ret); - ret = fu_backend_load(backend, - json_node_get_object(json_parser_get_root(parser)), - NULL, - FU_BACKEND_LOAD_FLAG_NONE, - &error); - g_assert_no_error(error); - g_assert_true(ret); + gusb_emulate_fn = g_test_build_filename(G_TEST_DIST, "tests", "usb-devices.json", NULL); + g_assert_nonnull(gusb_emulate_fn); + fu_backend_usb_load_file(backend, gusb_emulate_fn); + g_assert_cmpint(cnt_added, ==, 0); + g_assert_cmpint(cnt_removed, ==, 0); ret = fu_backend_coldplug(backend, progress, &error); g_assert_no_error(error); g_assert_true(ret); + g_assert_cmpint(cnt_added, ==, 1); + g_assert_cmpint(cnt_removed, ==, 0); devices = fu_backend_get_devices(backend); g_assert_cmpint(devices->len, ==, 1); device_tmp = g_ptr_array_index(devices, 0); @@ -3217,6 +3251,7 @@ fu_backend_usb_func(gconstpointer user_data) locker = fu_device_locker_new(device_tmp, &error); g_assert_no_error(error); g_assert_nonnull(locker); + g_assert_true(fu_device_has_flag(device_tmp, FWUPD_DEVICE_FLAG_EMULATED)); /* for debugging */ devicestr = fu_device_to_string(device_tmp); @@ -3232,6 +3267,22 @@ fu_backend_usb_func(gconstpointer user_data) possible_plugins = fu_device_get_possible_plugins(device_tmp); g_assert_cmpint(possible_plugins->len, ==, 1); g_assert_cmpstr(g_ptr_array_index(possible_plugins, 0), ==, "dfu"); + + /* load another device with the same VID:PID, and check that we did not get a replug */ + gusb_emulate_fn2 = + g_test_build_filename(G_TEST_DIST, "tests", "usb-devices-replace.json", NULL); + g_assert_nonnull(gusb_emulate_fn2); + fu_backend_usb_load_file(backend, gusb_emulate_fn2); + g_assert_cmpint(cnt_added, ==, 1); + g_assert_cmpint(cnt_removed, ==, 0); + + /* load another device with a different VID:PID, and check that we *did* get a replug */ + gusb_emulate_fn3 = + g_test_build_filename(G_TEST_DIST, "tests", "usb-devices-bootloader.json", NULL); + g_assert_nonnull(gusb_emulate_fn3); + fu_backend_usb_load_file(backend, gusb_emulate_fn3); + g_assert_cmpint(cnt_added, ==, 2); + g_assert_cmpint(cnt_removed, ==, 1); #else g_test_skip("No GUsb support"); #endif diff --git a/src/fu-usb-backend.c b/src/fu-usb-backend.c index 92439c175..c4aa9e48f 100644 --- a/src/fu-usb-backend.c +++ b/src/fu-usb-backend.c @@ -50,8 +50,25 @@ fu_usb_backend_device_notify_flags_cb(FuDevice *device, GParamSpec *pspec, FuBac static void fu_usb_backend_device_added_cb(GUsbContext *ctx, GUsbDevice *usb_device, FuBackend *backend) { + FuDevice *device_tmp; g_autoptr(FuUsbDevice) device = NULL; + /* is emulated? */ + device_tmp = fu_backend_lookup_by_id(backend, g_usb_device_get_platform_id(usb_device)); + if (device_tmp != NULL && fu_device_has_flag(device_tmp, FWUPD_DEVICE_FLAG_EMULATED)) { + if (g_usb_device_get_vid(usb_device) == + fu_usb_device_get_vid(FU_USB_DEVICE(device_tmp)) && + g_usb_device_get_pid(usb_device) == + fu_usb_device_get_pid(FU_USB_DEVICE(device_tmp))) { + g_debug("replacing GUsbDevice of emulated device %s", + fu_device_get_id(device_tmp)); + fu_usb_device_set_dev(FU_USB_DEVICE(device_tmp), usb_device); + return; + } + g_debug("delayed removal of emulated device as VID:PID changed"); + fu_backend_device_removed(backend, device_tmp); + } + /* success */ device = fu_usb_device_new(fu_backend_get_context(backend), usb_device); fu_backend_device_added(backend, FU_DEVICE(device)); @@ -66,8 +83,14 @@ fu_usb_backend_device_removed_cb(GUsbContext *ctx, GUsbDevice *usb_device, FuBac /* find the device we enumerated */ device_tmp = fu_backend_lookup_by_id(FU_BACKEND(self), g_usb_device_get_platform_id(usb_device)); - if (device_tmp != NULL) + if (device_tmp != NULL) { + if (fu_device_has_flag(device_tmp, FWUPD_DEVICE_FLAG_EMULATED)) { + g_debug("ignoring removal of emulated device %s", + fu_device_get_id(device_tmp)); + return; + } fu_backend_device_removed(backend, device_tmp); + } } static void diff --git a/src/tests/usb-devices-bootloader.json b/src/tests/usb-devices-bootloader.json new file mode 100644 index 000000000..9288704ce --- /dev/null +++ b/src/tests/usb-devices-bootloader.json @@ -0,0 +1,9 @@ +{ + "UsbDevices": [ + { + "PlatformId": "usb:01:00:06", + "IdVendor": 999, + "IdProduct": 999 + } + ] +} diff --git a/src/tests/usb-devices-replace.json b/src/tests/usb-devices-replace.json new file mode 100644 index 000000000..378afbcd0 --- /dev/null +++ b/src/tests/usb-devices-replace.json @@ -0,0 +1,9 @@ +{ + "UsbDevices": [ + { + "PlatformId": "usb:01:00:06", + "IdVendor": 10047, + "IdProduct": 4100 + } + ] +}