This makes devices that come back in bootloader mode with no children
timeout, which is bad UX. We don't even need the feature now that we
can WAIT_FOR_REPLUG on multiple devices now.
If we swap from runtime -> bootloader -> runtime we need to copy the
update state in each step even if we're just switching the swapping the
runtime device.
This regressed, as we optimized away the call to fu_device_list_replace.
This also means we no longer pass in just one device to the
fu_device_list_wait_for_replug() function, but we rather wait for *all*
of the active devices.
This also cleans up the confusion on whether the engine should wait for
the 'root' device or the child device as either (or both) can be set as
required.
This makes the replug far more predictable for devices that have
children even in bootloader mode.
At the moment the device list auto-removes children when the parent is
removed. This was originally working around the bug that the child
devices had no backend ID, and thus were not matched like the parent
in fu_engine_backend_device_removed_cb() and removed automatically.
Using the workaround means that the children are potentially removed
before the parent depending on the order of the device list -- which
might be modified by replug events.
I think the old cleanup is probably an anti-pattern, and going forward
composite devices should probably define _NO_AUTO_REMOVE_CHILDREN but
we don't want to change this behaviour for plugins already expecting
the old flow, or for devices with no parent backend IDs.
At the moment we saving the new state as 'unknown' which explains why
we're getting so few LVFS reports uploaded for USB devices that perform
a replug...
Tested with a ColorHug2.
The CustomFlags feature is a bit of a hack where we just join the flags
and store in the device metadata section as a string. This makes it
inefficient to check if just one flag exists as we have to split the
string to a temporary array each time.
Rather than adding to the hack by splitting, appending (if not exists)
then joining again, store the flags in the plugin privdata directly.
This allows us to support negating custom properties (e.g. ~hint) and
also allows quirks to append custom values without duplicating them on
each GUID match, e.g.
[USB\VID_17EF&PID_307F]
Plugin = customflag1
[USB\VID_17EF&PID_307F&HUB_0002]
Flags = customflag2
...would result in customflag1,customflag2 which is the same as you'd
get from an enumerated device flag doing the same thing.
Until gi-docgen is declared stable support either of them.
This effectively means that hand builds and CI builds will use
gi-docgen, but distro builds use gtk-doc-tools.
It is far too easy to forget to set FWUPD_DEVICE_FLAG_NO_GUID_MATCHING for new
plugins, and without it it all works really well *until* a user has two devices
of the same type installed at the same time and then one 'disappears' for hard
to explain reasons. Typically we only need it for replug anyway!
Explicitly opt-in to this rarely-required behaviour, with the default to just
use the physical and logical IDs. Also document the update behavior for each
plugin to explain why the flag is being used.
This allows you to have two identical Unifying plugged in without one of them
being hidden from the user, at the same time allowing a HIDRAW<->USB transition
when going to and from bootloader and runtime modes.
This removes the workaround added in 99eb3f06b6.
Fixes https://github.com/fwupd/fwupd/issues/2915
Asking the user for the UID mapping isn't working very well, as it requires lots
of manual handholding. It also doesn't work very well when the device vendor
does not actually have a PCI ID or if the vendor has split into two entities.
Just use the OUI address as an additional VendorID and match any of the device
IDs against any of the metadata-supplied values.
Rather than using a recursive GMainLoop, just run a single iteration of the
mainloop every 1ms while we're waiting.
This simplifies the device lifecycle dramatically as we don't have to worry
about reentrant removals. It's also a lot simpler to debug as we know the only
way to return is the timeout elapsing or FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG being
unset.
If multiple devices got removed and we're waiting for one to re-appear, also
wait for all devices to come back before returning to the main loop.
In the worst case, this causes the device list to wait the full removal_delay
for the device rather than returning when the first device matches. This allows
us to simplify the hub update when we reboot the entire device and various
devices from different plugins come back in an unpredictable order.
Fixes the other half of https://github.com/fwupd/fwupd/issues/2376
If we wait for the child of a composite device to reappear and *then* go on to
update the replugged parent in the same transaction then we still use the old
GUsbDevice as the add event is still pending when we quit the replug loop.
Just schedule an idle action to quit the loop to allow the child *and* parent
to be added on replug.
Fixes https://github.com/fwupd/fwupd/issues/2376
If the device parent is added using fu_device_add_parent_guid() or ParentGuid
from a quirk file then the child is not returned in fu_device_get_children() by
design as the physical ID will be likely different.
This means we cannot reliably 'depsolve' the order in FuDevice as we need the
full list of devices that might be parents. The existing algorithm had several
logical problems when dealing with more than a single parent and child.
The FuDeviceList object is the right place to do this as it knows about all
added devices on the system.
This means the addition of a logical device causes the root logical device
(and all it's children, and grandchildren) to be re-ordered. This allows
firmware on deeply nested composite devices like hubs to be installed in the
correct order.
This means we do not do the GUID or counterpart GUID matching when adding
devices. Only an exact device-id match or when both the physical and logical
IDs match will the device be considered the 'same'.
This is to handle devices that could share the same GUIDs in both child and
parent modes where the logical ID differs.
Some plugins are just simple wrappers around custom GType creators and which
specific plugin created is not a good way to make a policy decision.
If this was added to work around a bug, we need to find a better solution or
fix the root cause.
We add the child devices using fu_plugin_device_add() so we have to remove them
the same way. The original fix is wrong, as it leaves child devices when the
parent is removed.
This reverts commit 02b588c035.
In this case, a plugin was doing:
g_autoptr(FuDevice) parent = fu_device_get_parent (device);
Which is not valid as it is `(transfer none)` but that shouldn't be enough to
get the daemon to crash. If the FuDevice refcount drops to zero just print
a critical warning with the pointer (no FuDevice details are available) and
remove the FuDeviceItem from the device list.
Using `G_DEBUG=fatal-criticals` it is very easy to backtrace at the right place
and find out which naughty plugin needs to go on the thinking spot.
Doing this unconditionally means we accidentally 'bleed' one device mode into
another in a non-obvious way. For instance, a device might have two operating
modes with different GUIDs. If firmware is supplied for both modes in the same
cabinet archive then we might accidentally match the 'wrong' firmware when
the daemon has observed a mode switch and added the counterpart GUIDs.
We only really need the counterpart GUIDs when switching between Jabra, 8bitdo
and DFU devices where the DFU bootloader VID:PID is not manually tagged with
`CounterpartGuid` in a quirk file. In the general case lets keep it simple to
avoid difficult to find bugs.
Rather than return the first device with a matching counterpart GUID, and then
check to see if it was removed -- instead just return any item that matches and
has been removed.
This fixes updating the Logitech unifying receiver when more than one type of
device (e.g. RQR12 and RQR24) are connected.
Use only one GMainLoop in FuDeviceList; we can only iterate one loop at a time
anyway, and having the mainloops per-item complicates the lifecycle of the
fu_device_list_wait_for_replug() functionality considerably.
If the device has a child with a longer remove_delay we actually crash because
the FuDeviceList tries to remove the child device twice. Just remove all the
children when the parent remove delay elapsed rather than set up each device
with a unique timeout.
If we say that the version format should be the same for the `version_lowest`
and the `version_bootloader` then it does not always make sense to set it at
the same time.
Moving the `version_format` to a standalone first-class property also means it
can be typically be set in the custom device `_init()` function, which means we
don't need to worry about *changing* ther version format as set by the USB and
UDev superclass helpers.
Some Dell devices offer the exact same GUID in UEFI as well as in NVME
plugins. These devices can be flashed in either way, but the payload
for them is different.
The UEFI payload includes relevant headers and metadata to be acceptable
from a capsule. The NVME payload is raw data that the drive will process.
Since baa9e75ca8, fwupd should enforce that
the correct device is flashed with the correct protocol.
The debug features the object provides are not useful and are much too verbose
to be useful.
Backport the new reader/writer g_autoptr defines to avoid bumping the GLib dep.
Most of the work was done by Kalev Lember <klember@redhat.com>, many thanks.
This leads to madness, as some formats are supersets of the detected types,
e.g. 'intel-me' is detected as 'quad' and 'bcd' is detected as 'pair'.
Where the version format is defined in a specification or hardcoded in the
source use a hardcoded enum value, otherwise use a quirk override.
Additionally, warn if the version does not match the defined version format