mirror of
https://git.proxmox.com/git/fwupd
synced 2025-08-06 18:35:41 +00:00
cfu: Add an initial outline CFU plugin
There's no actual hardware to test this against yet, but this is how I would lay out a plugin if there was. We still need to work out a generic encapsulation for the offer and payload (for each component and bank) so this can work with LVFS and fwupd.
This commit is contained in:
parent
d1dff82803
commit
8e24fa77cf
@ -415,6 +415,7 @@ done
|
||||
%{_libdir}/fwupd-plugins-%{fwupdplugin_version}/libfu_plugin_ata.so
|
||||
%{_libdir}/fwupd-plugins-%{fwupdplugin_version}/libfu_plugin_bcm57xx.so
|
||||
%{_libdir}/fwupd-plugins-%{fwupdplugin_version}/libfu_plugin_ccgx.so
|
||||
%{_libdir}/fwupd-plugins-%{fwupdplugin_version}/libfu_plugin_cfu.so
|
||||
%{_libdir}/fwupd-plugins-%{fwupdplugin_version}/libfu_plugin_colorhug.so
|
||||
%{_libdir}/fwupd-plugins-%{fwupdplugin_version}/libfu_plugin_cros_ec.so
|
||||
%{_libdir}/fwupd-plugins-%{fwupdplugin_version}/libfu_plugin_cpu.so
|
||||
|
38
plugins/cfu/README.md
Normal file
38
plugins/cfu/README.md
Normal file
@ -0,0 +1,38 @@
|
||||
# Component Firmware update
|
||||
|
||||
## Introduction
|
||||
|
||||
CFU is a protocol from Microsoft to make it easy to install firmware on HID devices.
|
||||
|
||||
This protocol is unique in that it requires has a pre-download phase before sending the firmware to
|
||||
the microcontroller. This is so the device can check if the firmware is required and compatible.
|
||||
CFU also requires devices to be able to transfer the entire new transfer mode in runtime mode.
|
||||
|
||||
See <https://docs.microsoft.com/en-us/windows-hardware/drivers/cfu/cfu-specification> for more
|
||||
details.
|
||||
|
||||
This plugin supports the following protocol ID:
|
||||
|
||||
* com.microsoft.cfu
|
||||
|
||||
## GUID Generation
|
||||
|
||||
These devices use standard USB DeviceInstanceId values, as well as two extra for the component ID
|
||||
and the bank, e.g.
|
||||
|
||||
* `HIDRAW\VEN_17EF&DEV_7226&CID_01&BANK_1`
|
||||
* `HIDRAW\VEN_17EF&DEV_7226&CID_01`
|
||||
* `HIDRAW\VEN_17EF&DEV_7226`
|
||||
|
||||
## Update Behavior
|
||||
|
||||
The device has to support runtime updates and does not have a detach-into-bootloader mode -- but
|
||||
after the install has completed the device still has to reboot into the new firmware.
|
||||
|
||||
## Vendor ID Security
|
||||
|
||||
The vendor ID is set from the USB vendor, in this instance set to `HIDRAW:0x17EF`
|
||||
|
||||
## External Interface Access
|
||||
|
||||
This plugin requires read/write access to `/dev/bus/usb`.
|
2
plugins/cfu/cfu.quirk
Normal file
2
plugins/cfu/cfu.quirk
Normal file
@ -0,0 +1,2 @@
|
||||
[USB\VID_273F&PID_100A]
|
||||
Plugin = cfu
|
293
plugins/cfu/fu-cfu-device.c
Normal file
293
plugins/cfu/fu-cfu-device.c
Normal file
@ -0,0 +1,293 @@
|
||||
/*
|
||||
* Copyright (C) 2021 Richard Hughes <richard@hughsie.com>
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1+
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <fwupdplugin.h>
|
||||
|
||||
#include "fu-cfu-device.h"
|
||||
#include "fu-cfu-module.h"
|
||||
|
||||
struct _FuCfuDevice {
|
||||
FuHidDevice parent_instance;
|
||||
guint8 protocol_version;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE(FuCfuDevice, fu_cfu_device, FU_TYPE_HID_DEVICE)
|
||||
|
||||
#define FU_CFU_DEVICE_TIMEOUT 5000 /* ms */
|
||||
#define FU_CFU_FEATURE_SIZE 60 /* bytes */
|
||||
|
||||
#define FU_CFU_CMD_GET_FIRMWARE_VERSION 0x00
|
||||
#define FU_CFU_CMD_SEND_OFFER 0x00 // TODO
|
||||
|
||||
static void
|
||||
fu_cfu_device_to_string(FuDevice *device, guint idt, GString *str)
|
||||
{
|
||||
FuCfuDevice *self = FU_CFU_DEVICE(device);
|
||||
|
||||
/* FuUdevDevice->to_string */
|
||||
FU_DEVICE_CLASS(fu_cfu_device_parent_class)->to_string(device, idt, str);
|
||||
|
||||
fu_common_string_append_kx(str, idt, "ProtocolVersion", self->protocol_version);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
fu_cfu_device_write_offer(FuCfuDevice *self,
|
||||
FuFirmware *firmware,
|
||||
FuProgress *progress,
|
||||
FwupdInstallFlags flags,
|
||||
GError **error)
|
||||
{
|
||||
const guint8 *buf;
|
||||
gsize bufsz = 0;
|
||||
guint8 buf2[FU_CFU_FEATURE_SIZE] = {0};
|
||||
g_autofree guint8 *buf_tmp = NULL;
|
||||
g_autoptr(GBytes) blob = NULL;
|
||||
|
||||
/* generate a offer blob */
|
||||
if (flags & FWUPD_INSTALL_FLAG_FORCE)
|
||||
fu_cfu_offer_set_force_ignore_version(FU_CFU_OFFER(firmware), TRUE);
|
||||
blob = fu_firmware_write(firmware, error);
|
||||
if (blob == NULL)
|
||||
return FALSE;
|
||||
|
||||
/* send it to the hardware */
|
||||
buf = g_bytes_get_data(blob, &bufsz);
|
||||
buf_tmp = fu_memdup_safe(buf, bufsz, error);
|
||||
if (buf_tmp == NULL)
|
||||
return FALSE;
|
||||
if (!fu_hid_device_set_report(FU_HID_DEVICE(self),
|
||||
FU_CFU_CMD_SEND_OFFER,
|
||||
buf_tmp,
|
||||
bufsz,
|
||||
FU_CFU_DEVICE_TIMEOUT,
|
||||
FU_HID_DEVICE_FLAG_IS_FEATURE,
|
||||
error)) {
|
||||
g_prefix_error(error, "failed to send offer: ");
|
||||
return FALSE;
|
||||
}
|
||||
if (!fu_hid_device_get_report(FU_HID_DEVICE(self),
|
||||
FU_CFU_CMD_SEND_OFFER,
|
||||
buf2,
|
||||
sizeof(buf2),
|
||||
FU_CFU_DEVICE_TIMEOUT,
|
||||
FU_HID_DEVICE_FLAG_IS_FEATURE,
|
||||
error)) {
|
||||
return FALSE;
|
||||
}
|
||||
g_debug("status:%s reject:%s",
|
||||
fu_cfu_device_offer_to_string(buf2[13]),
|
||||
fu_cfu_device_reject_to_string(buf2[9]));
|
||||
if (buf2[13] != FU_CFU_DEVICE_OFFER_ACCEPT) {
|
||||
g_set_error(error,
|
||||
G_IO_ERROR,
|
||||
G_IO_ERROR_NOT_SUPPORTED,
|
||||
"not supported: %s",
|
||||
fu_cfu_device_offer_to_string(buf2[13]));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* success */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
fu_cfu_device_write_payload(FuCfuDevice *self,
|
||||
FuFirmware *firmware,
|
||||
FuProgress *progress,
|
||||
GError **error)
|
||||
{
|
||||
g_autoptr(GPtrArray) chunks = NULL;
|
||||
|
||||
/* write each chunk */
|
||||
chunks = fu_firmware_get_chunks(firmware, error);
|
||||
if (chunks == NULL)
|
||||
return FALSE;
|
||||
fu_progress_set_id(progress, G_STRLOC);
|
||||
fu_progress_set_steps(progress, chunks->len);
|
||||
for (guint i = 0; i < chunks->len; i++) {
|
||||
FuChunk *chk = g_ptr_array_index(chunks, i);
|
||||
guint8 databuf[60] = {0};
|
||||
guint8 buf2[60] = {0};
|
||||
|
||||
/* flags */
|
||||
if (i == 0)
|
||||
databuf[0] = FU_CFU_DEVICE_FLAG_FIRST_BLOCK;
|
||||
else if (i == chunks->len - 1)
|
||||
databuf[0] = FU_CFU_DEVICE_FLAG_LAST_BLOCK;
|
||||
|
||||
/* length */
|
||||
databuf[1] = fu_chunk_get_data_sz(chk);
|
||||
|
||||
/* sequence number */
|
||||
if (!fu_common_write_uint16_safe(databuf,
|
||||
sizeof(databuf),
|
||||
0x2,
|
||||
i + 1,
|
||||
G_LITTLE_ENDIAN,
|
||||
error))
|
||||
return FALSE;
|
||||
|
||||
/* address */
|
||||
if (!fu_common_write_uint32_safe(databuf,
|
||||
sizeof(databuf),
|
||||
0x4,
|
||||
fu_chunk_get_address(chk),
|
||||
G_LITTLE_ENDIAN,
|
||||
error))
|
||||
return FALSE;
|
||||
|
||||
/* data */
|
||||
if (!fu_memcpy_safe(databuf,
|
||||
sizeof(databuf),
|
||||
0x8, /* dst */
|
||||
fu_chunk_get_data(chk),
|
||||
fu_chunk_get_data_sz(chk),
|
||||
0x0, /* src */
|
||||
fu_chunk_get_data_sz(chk),
|
||||
error)) {
|
||||
g_prefix_error(error, "memory copy for payload fail: ");
|
||||
return FALSE;
|
||||
}
|
||||
// send
|
||||
// revc
|
||||
if (buf2[5] != FU_CFU_DEVICE_STATUS_SUCCESS) {
|
||||
g_set_error(error,
|
||||
G_IO_ERROR,
|
||||
G_IO_ERROR_INVALID_DATA,
|
||||
"failed to send chunk %u: %s",
|
||||
i + 1,
|
||||
fu_cfu_device_status_to_string(buf2[5]));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
fu_progress_step_done(progress);
|
||||
}
|
||||
|
||||
/* success */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
fu_cfu_device_write_firmware(FuDevice *device,
|
||||
FuFirmware *firmware,
|
||||
FuProgress *progress,
|
||||
FwupdInstallFlags flags,
|
||||
GError **error)
|
||||
{
|
||||
FuCfuDevice *self = FU_CFU_DEVICE(device);
|
||||
g_autoptr(FuFirmware) fw_offer = NULL;
|
||||
g_autoptr(FuFirmware) fw_payload = NULL;
|
||||
|
||||
/* progress */
|
||||
fu_progress_set_id(progress, G_STRLOC);
|
||||
fu_progress_add_flag(progress, FU_PROGRESS_FLAG_GUESSED);
|
||||
fu_progress_add_step(progress, FWUPD_STATUS_DEVICE_BUSY, 2); /* offer */
|
||||
fu_progress_add_step(progress, FWUPD_STATUS_DEVICE_WRITE, 98); /* payload */
|
||||
|
||||
/* send offer */
|
||||
fw_offer = fu_firmware_get_image_by_id(firmware, FU_FIRMWARE_ID_HEADER, error);
|
||||
if (fw_offer == NULL)
|
||||
return FALSE;
|
||||
if (!fu_cfu_device_write_offer(self,
|
||||
fw_offer,
|
||||
fu_progress_get_child(progress),
|
||||
flags,
|
||||
error))
|
||||
return FALSE;
|
||||
fu_progress_step_done(progress);
|
||||
|
||||
/* send payload */
|
||||
fw_payload = fu_firmware_get_image_by_id(firmware, FU_FIRMWARE_ID_PAYLOAD, error);
|
||||
if (fw_payload == NULL)
|
||||
return FALSE;
|
||||
if (!fu_cfu_device_write_payload(self, fw_payload, fu_progress_get_child(progress), error))
|
||||
return FALSE;
|
||||
fu_progress_step_done(progress);
|
||||
|
||||
/* success */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
fu_cfu_device_setup(FuDevice *device, GError **error)
|
||||
{
|
||||
FuCfuDevice *self = FU_CFU_DEVICE(device);
|
||||
guint8 buf[FU_CFU_FEATURE_SIZE] = {0};
|
||||
guint8 component_cnt = 0;
|
||||
guint8 tmp = 0;
|
||||
gsize offset = 0;
|
||||
g_autoptr(GHashTable) modules_by_cid = NULL;
|
||||
|
||||
/* FuHidDevice->setup */
|
||||
if (!FU_DEVICE_CLASS(fu_cfu_device_parent_class)->setup(device, error))
|
||||
return FALSE;
|
||||
|
||||
/* get version */
|
||||
if (!fu_hid_device_get_report(FU_HID_DEVICE(device),
|
||||
FU_CFU_CMD_GET_FIRMWARE_VERSION,
|
||||
buf,
|
||||
sizeof(buf),
|
||||
FU_CFU_DEVICE_TIMEOUT,
|
||||
FU_HID_DEVICE_FLAG_IS_FEATURE,
|
||||
error)) {
|
||||
return FALSE;
|
||||
}
|
||||
if (!fu_common_read_uint8_safe(buf, sizeof(buf), 0x0, &component_cnt, error))
|
||||
return FALSE;
|
||||
if (!fu_common_read_uint8_safe(buf, sizeof(buf), 0x3, &tmp, error))
|
||||
return FALSE;
|
||||
self->protocol_version = tmp & 0b1111;
|
||||
|
||||
/* keep track of all modules so we can work out which are dual bank */
|
||||
modules_by_cid = g_hash_table_new(g_int_hash, g_int_equal);
|
||||
|
||||
/* read each component module version */
|
||||
offset += 4;
|
||||
for (guint i = 0; i < component_cnt; i++) {
|
||||
g_autoptr(FuCfuModule) module = fu_cfu_module_new(device);
|
||||
FuCfuModule *module_tmp;
|
||||
|
||||
if (!fu_cfu_module_setup(module, buf, sizeof(buf), offset, error))
|
||||
return FALSE;
|
||||
fu_device_add_child(device, FU_DEVICE(module));
|
||||
|
||||
/* same module already exists, so mark both as being dual bank */
|
||||
module_tmp =
|
||||
g_hash_table_lookup(modules_by_cid,
|
||||
GINT_TO_POINTER(fu_cfu_module_get_component_id(module)));
|
||||
if (module_tmp != NULL) {
|
||||
fu_device_add_flag(FU_DEVICE(module), FWUPD_DEVICE_FLAG_DUAL_IMAGE);
|
||||
fu_device_add_flag(FU_DEVICE(module_tmp), FWUPD_DEVICE_FLAG_DUAL_IMAGE);
|
||||
} else {
|
||||
g_hash_table_insert(modules_by_cid,
|
||||
GINT_TO_POINTER(fu_cfu_module_get_component_id(module)),
|
||||
module);
|
||||
}
|
||||
|
||||
/* done */
|
||||
offset += 0x8;
|
||||
}
|
||||
|
||||
/* success */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
fu_cfu_device_init(FuCfuDevice *self)
|
||||
{
|
||||
fu_device_add_flag(FU_DEVICE(self), FWUPD_DEVICE_FLAG_USABLE_DURING_UPDATE);
|
||||
}
|
||||
|
||||
static void
|
||||
fu_cfu_device_class_init(FuCfuDeviceClass *klass)
|
||||
{
|
||||
FuDeviceClass *klass_device = FU_DEVICE_CLASS(klass);
|
||||
klass_device->setup = fu_cfu_device_setup;
|
||||
klass_device->to_string = fu_cfu_device_to_string;
|
||||
klass_device->write_firmware = fu_cfu_device_write_firmware;
|
||||
}
|
12
plugins/cfu/fu-cfu-device.h
Normal file
12
plugins/cfu/fu-cfu-device.h
Normal file
@ -0,0 +1,12 @@
|
||||
/*
|
||||
* Copyright (C) 2021 Richard Hughes <richard@hughsie.com>
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1+
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <fwupdplugin.h>
|
||||
|
||||
#define FU_TYPE_CFU_DEVICE (fu_cfu_device_get_type())
|
||||
G_DECLARE_FINAL_TYPE(FuCfuDevice, fu_cfu_device, FU, CFU_DEVICE, FuHidDevice)
|
200
plugins/cfu/fu-cfu-module.c
Normal file
200
plugins/cfu/fu-cfu-module.c
Normal file
@ -0,0 +1,200 @@
|
||||
/*#
|
||||
* Copyright (C) 2021 Richard Hughes <richard@hughsie.com>
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1+
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <fwupdplugin.h>
|
||||
|
||||
#include "fu-cfu-module.h"
|
||||
|
||||
struct _FuCfuModule {
|
||||
FuDevice parent_instance;
|
||||
guint8 component_id;
|
||||
guint8 bank;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE(FuCfuModule, fu_cfu_module, FU_TYPE_DEVICE)
|
||||
|
||||
static void
|
||||
fu_cfu_module_to_string(FuDevice *device, guint idt, GString *str)
|
||||
{
|
||||
FuCfuModule *self = FU_CFU_MODULE(device);
|
||||
fu_common_string_append_kx(str, idt, "ComponentId", self->component_id);
|
||||
fu_common_string_append_kx(str, idt, "Bank", self->bank);
|
||||
}
|
||||
|
||||
guint8
|
||||
fu_cfu_module_get_component_id(FuCfuModule *self)
|
||||
{
|
||||
return self->component_id;
|
||||
}
|
||||
|
||||
guint8
|
||||
fu_cfu_module_get_bank(FuCfuModule *self)
|
||||
{
|
||||
return self->bank;
|
||||
}
|
||||
|
||||
gboolean
|
||||
fu_cfu_module_setup(FuCfuModule *self, const guint8 *buf, gsize bufsz, gsize offset, GError **error)
|
||||
{
|
||||
FuDevice *parent = fu_device_get_proxy(FU_DEVICE(self));
|
||||
guint32 version_raw = 0;
|
||||
guint8 tmp = 0;
|
||||
g_autofree gchar *instance_id0 = NULL;
|
||||
g_autofree gchar *instance_id1 = NULL;
|
||||
g_autofree gchar *instance_id2 = NULL;
|
||||
g_autofree gchar *logical_id = NULL;
|
||||
g_autofree gchar *version = NULL;
|
||||
|
||||
/* component ID */
|
||||
if (!fu_common_read_uint8_safe(buf, bufsz, offset + 0x5, &self->component_id, error))
|
||||
return FALSE;
|
||||
|
||||
/* these GUIDs may cause the name or version-format to be overwritten */
|
||||
instance_id0 = g_strdup_printf("HIDRAW\\VEN_%04X&DEV_%04X",
|
||||
fu_udev_device_get_vendor(FU_UDEV_DEVICE(parent)),
|
||||
fu_udev_device_get_model(FU_UDEV_DEVICE(parent)));
|
||||
fu_device_add_instance_id(FU_DEVICE(self), instance_id0);
|
||||
instance_id1 = g_strdup_printf("HIDRAW\\VEN_%04X&DEV_%04X&CID_%02X",
|
||||
fu_udev_device_get_vendor(FU_UDEV_DEVICE(parent)),
|
||||
fu_udev_device_get_model(FU_UDEV_DEVICE(parent)),
|
||||
self->component_id);
|
||||
fu_device_add_instance_id(FU_DEVICE(self), instance_id1);
|
||||
|
||||
/* bank */
|
||||
if (!fu_common_read_uint8_safe(buf, bufsz, offset + 0x4, &tmp, error))
|
||||
return FALSE;
|
||||
self->bank = tmp & 0b11;
|
||||
instance_id2 = g_strdup_printf("HIDRAW\\VEN_%04X&DEV_%04X&CID_%02X&BANK_%01X",
|
||||
fu_udev_device_get_vendor(FU_UDEV_DEVICE(parent)),
|
||||
fu_udev_device_get_model(FU_UDEV_DEVICE(parent)),
|
||||
self->component_id,
|
||||
self->bank);
|
||||
fu_device_add_instance_id(FU_DEVICE(self), instance_id2);
|
||||
|
||||
/* set name, if not already set using a quirk */
|
||||
if (fu_device_get_name(FU_DEVICE(self)) == NULL) {
|
||||
g_autofree gchar *name = NULL;
|
||||
name = g_strdup_printf("%s (0x%02X:0x%02x)",
|
||||
fu_device_get_name(parent),
|
||||
self->component_id,
|
||||
self->bank);
|
||||
fu_device_set_name(FU_DEVICE(self), name);
|
||||
}
|
||||
|
||||
/* version */
|
||||
if (!fu_common_read_uint32_safe(buf, bufsz, offset, &version_raw, G_LITTLE_ENDIAN, error))
|
||||
return FALSE;
|
||||
fu_device_set_version_raw(FU_DEVICE(self), version_raw);
|
||||
version = fu_common_version_from_uint32(version_raw,
|
||||
fu_device_get_version_format(FU_DEVICE(self)));
|
||||
|
||||
/* logical ID */
|
||||
logical_id = g_strdup_printf("CID:0x%02x,BANK:0x%02x", self->component_id, self->bank);
|
||||
fu_device_set_logical_id(FU_DEVICE(self), logical_id);
|
||||
|
||||
/* success */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static FuFirmware *
|
||||
fu_cfu_module_prepare_firmware(FuDevice *device,
|
||||
GBytes *fw,
|
||||
FwupdInstallFlags flags,
|
||||
GError **error)
|
||||
{
|
||||
g_autoptr(FuFirmware) firmware = fu_firmware_new();
|
||||
g_autoptr(FuFirmware) offer = fu_cfu_offer_new();
|
||||
g_autoptr(FuFirmware) payload = fu_cfu_payload_new();
|
||||
g_autoptr(GBytes) fw_offset = NULL;
|
||||
|
||||
/* offer */
|
||||
if (!fu_firmware_parse(offer, fw, flags, error))
|
||||
return NULL;
|
||||
fu_firmware_set_id(offer, FU_FIRMWARE_ID_HEADER);
|
||||
fu_firmware_add_image(firmware, offer);
|
||||
|
||||
/* payload */
|
||||
fw_offset = fu_common_bytes_new_offset(fw, 0x10, g_bytes_get_size(fw) - 0x10, error);
|
||||
if (fw_offset == NULL)
|
||||
return NULL;
|
||||
if (!fu_firmware_parse(payload, fw_offset, flags, error))
|
||||
return NULL;
|
||||
fu_firmware_set_id(payload, FU_FIRMWARE_ID_PAYLOAD);
|
||||
fu_firmware_add_image(firmware, payload);
|
||||
|
||||
/* success */
|
||||
return g_steal_pointer(&firmware);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
fu_cfu_module_write_firmware(FuDevice *device,
|
||||
FuFirmware *firmware,
|
||||
FuProgress *progress,
|
||||
FwupdInstallFlags flags,
|
||||
GError **error)
|
||||
{
|
||||
FuDevice *proxy;
|
||||
g_autoptr(GBytes) fw = NULL;
|
||||
|
||||
/* get the whole image */
|
||||
fw = fu_firmware_get_bytes(firmware, error);
|
||||
if (fw == NULL)
|
||||
return FALSE;
|
||||
|
||||
/* process by the parent */
|
||||
proxy = fu_device_get_proxy(device);
|
||||
if (proxy == NULL) {
|
||||
g_set_error(error,
|
||||
G_IO_ERROR,
|
||||
G_IO_ERROR_NOT_SUPPORTED,
|
||||
"no proxy device assigned");
|
||||
return FALSE;
|
||||
}
|
||||
return fu_device_write_firmware(proxy, fw, progress, flags, error);
|
||||
}
|
||||
|
||||
static void
|
||||
fu_cfu_module_set_progress(FuDevice *self, FuProgress *progress)
|
||||
{
|
||||
fu_progress_set_id(progress, G_STRLOC);
|
||||
fu_progress_add_flag(progress, FU_PROGRESS_FLAG_GUESSED);
|
||||
fu_progress_add_step(progress, FWUPD_STATUS_DEVICE_RESTART, 2); /* detach */
|
||||
fu_progress_add_step(progress, FWUPD_STATUS_DEVICE_WRITE, 96); /* write */
|
||||
fu_progress_add_step(progress, FWUPD_STATUS_DEVICE_RESTART, 2); /* attach */
|
||||
fu_progress_add_step(progress, FWUPD_STATUS_DEVICE_BUSY, 2); /* reload */
|
||||
}
|
||||
|
||||
static void
|
||||
fu_cfu_module_init(FuCfuModule *self)
|
||||
{
|
||||
fu_device_add_protocol(FU_DEVICE(self), "com.microsoft.cfu");
|
||||
fu_device_set_version_format(FU_DEVICE(self), FWUPD_VERSION_FORMAT_QUAD);
|
||||
}
|
||||
|
||||
static void
|
||||
fu_cfu_module_class_init(FuCfuModuleClass *klass)
|
||||
{
|
||||
FuDeviceClass *klass_device = FU_DEVICE_CLASS(klass);
|
||||
klass_device->to_string = fu_cfu_module_to_string;
|
||||
klass_device->prepare_firmware = fu_cfu_module_prepare_firmware;
|
||||
klass_device->write_firmware = fu_cfu_module_write_firmware;
|
||||
klass_device->set_progress = fu_cfu_module_set_progress;
|
||||
}
|
||||
|
||||
FuCfuModule *
|
||||
fu_cfu_module_new(FuDevice *parent)
|
||||
{
|
||||
FuCfuModule *self;
|
||||
self = g_object_new(FU_TYPE_CFU_MODULE,
|
||||
"ctx",
|
||||
fu_device_get_context(parent),
|
||||
"proxy",
|
||||
parent,
|
||||
NULL);
|
||||
return self;
|
||||
}
|
25
plugins/cfu/fu-cfu-module.h
Normal file
25
plugins/cfu/fu-cfu-module.h
Normal file
@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright (C) 2021 Richard Hughes <richard@hughsie.com>
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1+
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <fwupdplugin.h>
|
||||
|
||||
#define FU_TYPE_CFU_MODULE (fu_cfu_module_get_type())
|
||||
G_DECLARE_FINAL_TYPE(FuCfuModule, fu_cfu_module, FU, CFU_MODULE, FuDevice)
|
||||
|
||||
guint8
|
||||
fu_cfu_module_get_component_id(FuCfuModule *self);
|
||||
guint8
|
||||
fu_cfu_module_get_bank(FuCfuModule *self);
|
||||
gboolean
|
||||
fu_cfu_module_setup(FuCfuModule *self,
|
||||
const guint8 *buf,
|
||||
gsize bufsz,
|
||||
gsize offset,
|
||||
GError **error);
|
||||
FuCfuModule *
|
||||
fu_cfu_module_new(FuDevice *parent);
|
18
plugins/cfu/fu-plugin-cfu.c
Normal file
18
plugins/cfu/fu-plugin-cfu.c
Normal file
@ -0,0 +1,18 @@
|
||||
/*
|
||||
* Copyright (C) 2021 Richard Hughes <richard@hughsie.com>
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1+
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <fwupdplugin.h>
|
||||
|
||||
#include "fu-cfu-device.h"
|
||||
|
||||
void
|
||||
fu_plugin_init(FuPlugin *plugin)
|
||||
{
|
||||
fu_plugin_set_build_hash(plugin, FU_BUILD_HASH);
|
||||
fu_plugin_add_device_gtype(plugin, FU_TYPE_CFU_DEVICE);
|
||||
}
|
31
plugins/cfu/meson.build
Normal file
31
plugins/cfu/meson.build
Normal file
@ -0,0 +1,31 @@
|
||||
cargs = ['-DG_LOG_DOMAIN="FuPluginCfu"']
|
||||
|
||||
install_data([
|
||||
'cfu.quirk',
|
||||
],
|
||||
install_dir: join_paths(datadir, 'fwupd', 'quirks.d')
|
||||
)
|
||||
|
||||
shared_module('fu_plugin_cfu',
|
||||
fu_hash,
|
||||
sources : [
|
||||
'fu-cfu-device.c',
|
||||
'fu-cfu-module.c',
|
||||
'fu-plugin-cfu.c',
|
||||
],
|
||||
include_directories : [
|
||||
root_incdir,
|
||||
fwupd_incdir,
|
||||
fwupdplugin_incdir,
|
||||
],
|
||||
install : true,
|
||||
install_dir: plugin_dir,
|
||||
link_with : [
|
||||
fwupd,
|
||||
fwupdplugin,
|
||||
],
|
||||
c_args : cargs,
|
||||
dependencies : [
|
||||
plugin_deps,
|
||||
],
|
||||
)
|
@ -8,6 +8,7 @@ subdir('ata')
|
||||
subdir('bcm57xx')
|
||||
subdir('bios')
|
||||
subdir('ccgx')
|
||||
subdir('cfu')
|
||||
subdir('colorhug')
|
||||
subdir('cpu')
|
||||
subdir('cros-ec')
|
||||
|
Loading…
Reference in New Issue
Block a user