Communicating between child devices of different subsystems

35 views
Skip to first unread message

Sanjay Sheth

unread,
Apr 12, 2023, 3:56:17 AM4/12/23
to fwupd

We have composite device that has two subsystems (video4linux & hidraw). Both are FuUdevDevice, and resides under different USB hubs.

Unfortunately only hidraw device supports API to trigger composite device reboot. So after we update video4linux firmware, we need some way to signal hidraw device to trigger the reboot. How to achieve that? Anyway other way to trigger reboot programatically? Possible to leverage counterpart_guid, incorporate, create hidraw instance on the fly and invoke it, store hidraw instance as private?

Condensed Tree view:
# lsusb -v -t
/:  Bus 02
    ID 1d6b:0003 Linux 3.0 root hub
    |__ Port 1
        ID 046d:0878 USB3 HUB
        |__ Port 2
            ID 046d:0876 video4linux-HDMI
/:  Bus 01
    ID 1d6b:0002 Linux 2.0 root hub
    |__ Port 6
        ID 046d:0879 USB2 HUB1
        |__ Port 4
            ID 046d:0877 USB2 HUB2
            |__ Port 1
                ID 046d:0872 hidraw-SENSOR

Pushed the code for reference: https://github.com/fwupd/fwupd/tree/wip/vcdmp/tap1
fu_logitech_tap_device_write_firmware() invokes fu_logitech_tap_hdmi_device_write_firmware(), and after that ideally it needs to invoke fu_logitech_tap_sensor_device_reboot_device() to trigger reboot.

Attached the console output of both get-devices & install-blob commands
install-blob captures following:
Step 1: Invoke install-blob with deviceId of video4linux, it successfully writes new firmware
Step 2: Invoke install-blob again with deviceId of hidraw, successfully triggers the device reboot
Step 3: Invoke get-device to reflect new video4linux firmware version

We are looking for a way to merge Step1 & Step2 into single step.

Please provide any pointers, will refactor code based on recommendation.
install_blob
get_devices

Richard Hughes

unread,
Apr 17, 2023, 12:03:35 PM4/17/23
to Sanjay Sheth, fwupd
On Wed, 12 Apr 2023 at 08:56, Sanjay Sheth <ssh...@logitech.com> wrote:
> We have composite device that has two subsystems (video4linux & hidraw). Both are FuUdevDevice, and resides under different USB hubs.

Got it.

> Unfortunately only hidraw device supports API to trigger composite device reboot. So after we update video4linux firmware, we need some way to signal hidraw device to trigger the reboot.

The way this works right now is:

composite_prepare(device1+device2)
prepare(device1)
detach(device1)
write_firmware(device1)
attach(device1)
cleanup(device1)
prepare(device2)
detach(device2)
write_firmware(device2)
attach(device2)
cleanup(device2)
composite_cleanup(device1+device2)

--- is it possible to handle the reboot using the composite_cleanup()
vfunc? You get a GPtrArray for devices to inspect, and you'd have to
verify it's the video4linux one that's been updated.

Richard.

Sanjay Sheth

unread,
Apr 22, 2023, 12:04:48 AM4/22/23
to fwupd
Is there any flags or special handling to let framework know that this is composite device. Because with install-blob, it always prompt us to Choose a device, whether we specify single deviceId, or multiple or none. And GPtrArray in composite_cleanup always has one entry.  Seems like that is how it is coded in fu_util_install_blob(). 

I was able to leverage devices in FuPlugin. I have created PullRequest: https://github.com/fwupd/fwupd/pull/5746
Verbose logs attached to the PullRequest. Will refactor based on input.

Richard Hughes

unread,
Apr 24, 2023, 6:32:06 AM4/24/23
to Sanjay Sheth, fwupd
On Sat, 22 Apr 2023 at 05:04, Sanjay Sheth <ssh...@logitech.com> wrote:
> Is there any flags or special handling to let framework know that this is composite device.

Ahh, so the composite update is formed when there are multiple updates
to deploy to multiple sub-devices. I guess in this case we're only
*using* the other device for a specific step rather than deploying
firmware onto it.

> Verbose logs attached to the PullRequest. Will refactor based on input.

So in this case I think we want to add a
plugin_class->device_registered vfunc that gets called for each device
that gets added to the daemon (which can happen in either order). You
can look for the helper device and match against an instance ID or
plugin name there, and on match save this to the plugin private object
(and unref it if not NULL on finalize).

If the device detected in device_registered is the device you're doing
the update on then you can call fu_device_set_proxy() with the
previously detected helper device. e.g. I'd do something like this:

static void
foo_registered(FuPlugin *plugin, FuDevice *device)
{
if (_is_updatable_device(device)) {
g_set_object(&self->updatable_device, device);
fu_device_set_proxy(self->updatable_device,
self->helper_device);
}
if (_is_helper_device(device)) {
g_set_object(&self->helper_device, device);
fu_device_set_proxy(self->updatable_device,
self->helper_device);
}
}

plugin_class->device_registered = foo_registered;

And then when the updatable device needs to use the helper device it
can call fu_device_get_proxy(). Does that help?

Richard.

Sanjay Sheth

unread,
Apr 26, 2023, 7:52:23 PM4/26/23
to fwupd
Thanks a lot Richard. That helped. Refactor code accordingly

Sanjay Sheth

unread,
Jun 5, 2023, 11:13:44 AM6/5/23
to fwupd
How do we achieve same using fwupdmgr? Is there a way to do USB level reset/reboot?

Sanjay Sheth

unread,
Jun 8, 2023, 7:23:40 PM6/8/23
to fwupd
Sorry, my bad. Please ignore it. It works with fwupdmgr. composite_cleanup() gets invoked with fwupdmgr as well.
Reply all
Reply to author
Forward
0 new messages