mirror of
https://git.proxmox.com/git/fwupd
synced 2025-06-01 13:00:06 +00:00

When fwupd is installed in long-term support distros it's very hard to backport new versions as new hardware is released. There are several reasons why we can't just include the mapping and quirk information in the AppStream metadata: * The extra data is hugely specific to the installed fwupd plugin versions * The device-id is per-device, and the mapping is usually per-plugin * Often the information is needed before the FuDevice is created * There are security implications in allowing plugins to handle new devices The idea with quirks is that the end user can drop an additional (or replace an existing) file in a .d director with a simple format and the hardware will magically start working. This assumes no new quirks are required, as this would obviously need code changes, but allows us to get most existing devices working in an easy way without the user compiling anything. This allows us to fix issues like https://github.com/hughsie/fwupd/issues/265
354 lines
13 KiB
XML
354 lines
13 KiB
XML
<?xml version="1.0"?>
|
|
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
|
|
"http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd"
|
|
[
|
|
<!ENTITY % local.common.attrib "xmlns:xi CDATA #FIXED 'http://www.w3.org/2003/XInclude'">
|
|
]>
|
|
<book id="index">
|
|
<bookinfo>
|
|
<title>fwupd Reference Manual</title>
|
|
</bookinfo>
|
|
|
|
<reference id="intro">
|
|
<title>About fwupd</title>
|
|
<partintro>
|
|
<para>
|
|
fwupd is a daemon for updating firmware.
|
|
</para>
|
|
</partintro>
|
|
</reference>
|
|
|
|
<reference id="libfwupd">
|
|
<title>libfwupd</title>
|
|
<partintro>
|
|
<para>
|
|
Functionality exported by libfwupd for client applications.
|
|
</para>
|
|
</partintro>
|
|
<xi:include href="xml/fwupd-client.xml"/>
|
|
<xi:include href="xml/fwupd-device.xml"/>
|
|
<xi:include href="xml/fwupd-release.xml"/>
|
|
<xi:include href="xml/fwupd-remote.xml"/>
|
|
<xi:include href="xml/fwupd-error.xml"/>
|
|
<xi:include href="xml/fwupd-enums.xml"/>
|
|
<xi:include href="xml/fwupd-version.xml"/>
|
|
</reference>
|
|
|
|
<reference id="plugin-reference">
|
|
<title>Plugin Reference</title>
|
|
<partintro>
|
|
<para>
|
|
Functionality available to plugins.
|
|
</para>
|
|
</partintro>
|
|
<xi:include href="xml/fu-plugin.xml"/>
|
|
<xi:include href="xml/fu-device.xml"/>
|
|
<xi:include href="xml/fu-device-locker.xml"/>
|
|
<xi:include href="xml/fu-common.xml"/>
|
|
<xi:include href="xml/fu-quirks.xml"/>
|
|
<xi:include href="xml/fu-device-metadata.xml"/>
|
|
</reference>
|
|
|
|
<reference id="tutorial">
|
|
<title>Plugin Tutorial</title>
|
|
<partintro>
|
|
<section>
|
|
<title>Introduction</title>
|
|
<para>
|
|
At the heart of fwupd is a plugin loader that gets run at startup,
|
|
when devices get hotplugged and when updates are done.
|
|
The idea is we have lots of small plugins that each do one thing, and
|
|
are ordered by dependencies against each other at runtime.
|
|
Using plugins we can add support for new hardware or new policies
|
|
without making big changes all over the source tree.
|
|
</para>
|
|
<para>
|
|
There are broadly 3 types of plugin methods:
|
|
</para>
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para>
|
|
<emphasis role="strong">Mechanism</emphasis>: Upload binary data
|
|
into a specific hardware device.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
<emphasis role="strong">Policy</emphasis>: Control the system when
|
|
updates are happening, e.g. preventing the user from powering-off.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
<emphasis role="strong">Helpers</emphasis>: Providing more
|
|
metadata about devices, for instance handling device quirks.
|
|
</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
<para>
|
|
In general, building things out-of-tree isn't something that we think is
|
|
a very good idea; the API and ABI <emphasis>internal</emphasis> to fwupd is still
|
|
changing and there's a huge benefit to getting plugins upstream where
|
|
they can undergo review and be ported as the API adapts.
|
|
For this reason we don't install the plugin headers onto the system,
|
|
although you can of course just install the <code>.so</code> binary file
|
|
manually.
|
|
</para>
|
|
|
|
<para>
|
|
A plugin only needs to define the vfuncs that are required, and the
|
|
plugin name is taken automatically from the suffix of the
|
|
<filename>.so</filename> file.
|
|
</para>
|
|
<example>
|
|
<title>A sample plugin</title>
|
|
<programlisting>
|
|
/*
|
|
* Copyright (C) 2017 Richard Hughes
|
|
*/
|
|
|
|
#include <fu-plugin.h>
|
|
#include <fu-plugin-vfuncs.h>
|
|
|
|
struct FuPluginData {
|
|
gpointer proxy;
|
|
};
|
|
|
|
void
|
|
fu_plugin_initialize (FuPlugin *plugin)
|
|
{
|
|
fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_RUN_BEFORE, "dfu");
|
|
fu_plugin_alloc_data (plugin, sizeof (FuPluginData));
|
|
}
|
|
|
|
void
|
|
fu_plugin_destroy (FuPlugin *plugin)
|
|
{
|
|
FuPluginData *data = fu_plugin_get_data (plugin);
|
|
destroy_proxy (data->proxy);
|
|
}
|
|
|
|
gboolean
|
|
fu_plugin_startup (FuPlugin *plugin, GError **error)
|
|
{
|
|
FuPluginData *data = fu_plugin_get_data (plugin);
|
|
data->proxy = create_proxy ();
|
|
if (data->proxy == NULL) {
|
|
g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED,
|
|
"failed to create proxy");
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
</programlisting>
|
|
</example>
|
|
|
|
<para>
|
|
We have to define when our plugin is run in reference to other plugins,
|
|
in this case, making sure we run before the <code>dfu</code> plugin.
|
|
For most plugins it does not matter in what order they are run and
|
|
this information is not required.
|
|
</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title>Creating an abstact device</title>
|
|
<para>
|
|
This section shows how you would create a device which is exported
|
|
to the daemon and thus can be queried and updated by the client software.
|
|
The example here is all hardcoded, and a true plugin would have to
|
|
derive the details about the <code>FuDevice</code> from the hardware,
|
|
for example reading data from <code>sysfs</code> or <code>/dev</code>.
|
|
</para>
|
|
<example>
|
|
<title>Example adding a custom device</title>
|
|
<programlisting>
|
|
#include <fu-plugin.h>
|
|
|
|
gboolean
|
|
fu_plugin_coldplug (FuPlugin *plugin, GError **error)
|
|
{
|
|
g_autoptr(FuDevice) dev = NULL;
|
|
fu_device_set_id (dev, "dummy-1:2:3");
|
|
fu_device_add_guid (dev, "2d47f29b-83a2-4f31-a2e8-63474f4d4c2e");
|
|
fu_device_set_version (dev, "1.2.3");
|
|
fu_device_get_version_lowest (dev, "1.2.2");
|
|
fu_device_get_version_bootloader (dev, "0.1.2");
|
|
fu_device_add_icon (dev, "computer");
|
|
fu_device_add_flag (dev, FWUPD_DEVICE_FLAG_UPDATABLE);
|
|
fu_plugin_device_add (plugin, dev);
|
|
return TRUE;
|
|
}
|
|
</programlisting>
|
|
</example>
|
|
<para>
|
|
This shows a lot of the plugin architecture in action. Some notable points:
|
|
</para>
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para>
|
|
The device ID (<code>dummy-1:2:3</code>) has to be unique on the
|
|
system between all plugins, so including the plugin name as a
|
|
prefix is probably a good idea.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
The GUID value can be generated automatically using
|
|
<code>fu_device_add_guid(dev,"some-identifier")</code> but is quoted
|
|
here explicitly.
|
|
The GUID value has to match the <code>provides</code> value in the
|
|
<code>.metainfo.xml</code> file for the firmware update to succeed.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
Setting a display name and an icon is a good idea in case the
|
|
GUI software needs to display the device to the user.
|
|
Icons can be specified using a full path, although icon theme names
|
|
should be preferred for most devices.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
The <code>FWUPD_DEVICE_FLAG_UPDATABLE</code> flag tells the client
|
|
code that the device is in a state where it can be updated.
|
|
If the device needs to be in a special mode (e.g. a bootloader) then
|
|
the <code>FWUPD_DEVICE_FLAG_NEEDS_BOOTLOADER</code> flag can also be
|
|
used.
|
|
If the update should only be allowed when there is AC power available
|
|
to the computer (i.e. not on battery) then
|
|
<code>FWUPD_DEVICE_FLAG_REQUIRE_AC</code> should be used as well.
|
|
There are other flags and the API documentation should be used when
|
|
choosing what flags to use for each kind of device.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
Setting the lowest allows client software to refuse downgrading
|
|
the device to specific versions.
|
|
This is required in case the upgrade migrates some kind of data-store
|
|
so as to be incompatible with previous versions.
|
|
Similarly, setting the version of the bootloader (if known) allows
|
|
the firmware to depend on a specific bootloader version, for instance
|
|
allowing signed firmware to only be installable on hardware with
|
|
a bootloader new enough to deploy it
|
|
</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
</section>
|
|
|
|
<section>
|
|
<title>Mechanism Plugins</title>
|
|
<para>
|
|
Although it would be a wonderful world if we could update all hardware
|
|
using a standard shared protocol this is not the universe we live in.
|
|
Using a mechanism like DFU or UpdateCapsule means that fwupd will just
|
|
work without requiring any special code, but for the real world we need
|
|
to support vendor-specific update protocols with layers of backwards
|
|
compatibility.
|
|
</para>
|
|
<para>
|
|
When a plugin has created a device that is <code>FWUPD_DEVICE_FLAG_UPDATABLE</code>
|
|
we can ask the daemon to update the device with a suitable
|
|
<code>.cab</code> file.
|
|
When this is done the daemon checks the update for compatibility with
|
|
the device, and then calls the vfuncs to update the device.
|
|
</para>
|
|
|
|
<example>
|
|
<title>Updating a device</title>
|
|
<programlisting>
|
|
gboolean
|
|
fu_plugin_update (FuPlugin *plugin,
|
|
FuDevice *dev,
|
|
GBytes *blob_fw,
|
|
FwupdInstallFlags flags,
|
|
GError **error)
|
|
{
|
|
gsize sz = 0;
|
|
guint8 *buf = g_bytes_get_data (blob_fw, &sz);
|
|
/* write 'buf' of size 'sz' to the hardware */
|
|
return TRUE;
|
|
}
|
|
</programlisting>
|
|
</example>
|
|
<para>
|
|
It's important to note that the <code>blob_fw</code> is the binary
|
|
firmware file (e.g. <code>.dfu</code>) and <emphasis role="strong">not</emphasis>
|
|
the <code>.cab</code> binary data.
|
|
</para>
|
|
<para>
|
|
If <code>FWUPD_INSTALL_FLAG_FORCE</code> is used then the usual checks
|
|
done by the flashing process can be relaxed (e.g. checking for quirks),
|
|
but please don't brick the users hardware even if they ask you to.
|
|
</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title>Policy Helpers</title>
|
|
<para>
|
|
For some hardware, we might want to do an action before or after
|
|
the actual firmware is squirted into the device.
|
|
This could be something as simple as checking the system battery
|
|
level is over a certain theshold, or it could be as complicated as
|
|
ensuring a vendor-specific GPIO is asserted when specific types
|
|
of hardware are updated.
|
|
</para>
|
|
|
|
<example>
|
|
<title>Running before a device update</title>
|
|
<programlisting>
|
|
gboolean
|
|
fu_plugin_update_prepare (FuPlugin *plugin, FuDevice *device, GError **error)
|
|
{
|
|
if (fu_device_has_flag (device, FWUPD_DEVICE_FLAG_REQUIRE_AC && !on_ac_power ()) {
|
|
g_set_error_literal (error,
|
|
FWUPD_ERROR,
|
|
FWUPD_ERROR_AC_POWER_REQUIRED,
|
|
"Cannot install update "
|
|
"when not on AC power");
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
</programlisting>
|
|
</example>
|
|
<example>
|
|
<title>Running after a device update</title>
|
|
<programlisting>
|
|
gboolean
|
|
fu_plugin_update_cleanup (FuPlugin *plugin, FuDevice *device, GError **error)
|
|
{
|
|
return g_file_set_contents ("/var/lib/fwupd/something",
|
|
fu_device_get_id (device), -1, error);
|
|
}
|
|
</programlisting>
|
|
</example>
|
|
</section>
|
|
|
|
<section>
|
|
<title>The Plugin Object Cache</title>
|
|
<para>
|
|
The fwupd daemon provides a per-plugin cache which allows objects
|
|
to be added, removed and queried using a specified key.
|
|
Objects added to the cache must be <code>GObject</code>s to enable the
|
|
cache objects to be properly refcounted.
|
|
</para>
|
|
</section>
|
|
|
|
</partintro>
|
|
</reference>
|
|
|
|
<index id="api-index-full">
|
|
<title>API Index</title>
|
|
<xi:include href="xml/api-index-full.xml"><xi:fallback /></xi:include>
|
|
</index>
|
|
|
|
<index id="deprecated-api-index" role="deprecated">
|
|
<title>Index of deprecated API</title>
|
|
<xi:include href="xml/api-index-deprecated.xml"><xi:fallback /></xi:include>
|
|
</index>
|
|
<xi:include href="xml/annotation-glossary.xml"><xi:fallback /></xi:include>
|
|
</book>
|