synaptics-rmi: Support parsing and writing signed firmware

Validate the firmware signature if provided
This commit is contained in:
Richard Hughes 2021-01-12 10:25:41 +00:00
parent 643d7b16b1
commit edc0c08065
11 changed files with 354 additions and 3 deletions

View File

@ -262,6 +262,9 @@ else
if get_option('plugin_uefi_pk')
error('plugin_uefi_pk needs -Dgnutls=true to work')
endif
if get_option('plugin_synaptics_rmi')
error('plugin_synaptics_rmi needs -Dgnutls=true to work')
endif
endif
platform_deps = []

View File

@ -17,6 +17,7 @@ option('plugin_dell', type : 'boolean', value : true, description : 'enable Dell
option('plugin_dummy', type : 'boolean', value : false, description : 'enable the dummy device')
option('plugin_emmc', type : 'boolean', value : true, description : 'enable eMMC support')
option('plugin_synaptics_mst', type: 'boolean', value: true, description : 'enable Synaptics MST hub support')
option('plugin_synaptics_rmi', type: 'boolean', value: true, description : 'enable Synaptics RMI support')
option('plugin_thunderbolt', type : 'boolean', value : true, description : 'enable Thunderbolt support')
option('plugin_redfish', type : 'boolean', value : true, description : 'enable Redfish support')
option('plugin_uefi_capsule', type : 'boolean', value : true, description : 'enable UEFI capsule support')

View File

@ -25,11 +25,14 @@ subdir('ata')
subdir('elantp')
subdir('optionrom')
subdir('superio')
subdir('synaptics-rmi')
subdir('thelio-io')
subdir('wacom-raw')
endif
if get_option('gudev') and get_option('plugin_synaptics_rmi')
subdir('synaptics-rmi')
endif
if get_option('gudev') and get_option('gusb')
subdir('logitech-hidpp')
endif

View File

@ -14,6 +14,9 @@
#include <gio/gio.h>
#include <gnutls/abstract.h>
#include <gnutls/crypto.h>
#include "fu-common.h"
#include "fu-io-channel.h"
#include "fu-synaptics-rmi-common.h"
@ -30,6 +33,14 @@
#define RMI_FUNCTION_VERSION_MASK 0x60
#define RMI_FUNCTION_INTERRUPT_SOURCES_MASK 0x7
typedef guchar gnutls_data_t;
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-function"
G_DEFINE_AUTOPTR_CLEANUP_FUNC(gnutls_data_t, gnutls_free)
G_DEFINE_AUTO_CLEANUP_FREE_FUNC(gnutls_pubkey_t, gnutls_pubkey_deinit, NULL)
#pragma clang diagnostic pop
guint32
fu_synaptics_rmi_generate_checksum (const guint8 *data, gsize len)
{
@ -100,3 +111,67 @@ fu_synaptics_rmi_device_writeln (const gchar *fn, const gchar *buf, GError **err
return fu_io_channel_write_raw (io, (const guint8 *) buf, strlen (buf),
1000, FU_IO_CHANNEL_FLAG_NONE, error);
}
gboolean
fu_synaptics_verify_sha256_signature (GBytes *payload,
GBytes *pubkey,
GBytes *signature,
GError **error)
{
gnutls_datum_t hash;
gnutls_datum_t m;
gnutls_datum_t e;
gnutls_datum_t sig;
gnutls_hash_hd_t sha2;
g_auto(gnutls_pubkey_t) pub = NULL;
gint ec;
guint8 exponent[] = { 1, 0, 1 };
guint hash_length = gnutls_hash_get_len (GNUTLS_DIG_SHA256);
g_autoptr(gnutls_data_t) hash_data = NULL;
/* hash firmware data */
hash_data = gnutls_malloc (hash_length);
gnutls_hash_init (&sha2, GNUTLS_DIG_SHA256);
gnutls_hash (sha2, g_bytes_get_data (payload, NULL), g_bytes_get_size (payload));
gnutls_hash_deinit (sha2, hash_data);
/* hash */
hash.size = hash_length;
hash.data = hash_data;
/* modulus */
m.size = g_bytes_get_size (pubkey);
m.data = (guint8 *) g_bytes_get_data (pubkey, NULL);
/* exponent */
e.size = sizeof(exponent);
e.data = exponent;
/* signature */
sig.size = g_bytes_get_size (signature);
sig.data = (guint8 *) g_bytes_get_data (signature, NULL);
gnutls_pubkey_init (&pub);
ec = gnutls_pubkey_import_rsa_raw (pub, &m, &e);
if (ec < 0) {
g_set_error (error,
FWUPD_ERROR,
FWUPD_ERROR_NOT_SUPPORTED,
"failed to import RSA key: %s",
gnutls_strerror (ec));
return FALSE;
}
ec = gnutls_pubkey_verify_hash2 (pub, GNUTLS_SIGN_RSA_SHA256,
0, &hash, &sig);
if (ec < 0) {
g_set_error (error,
FWUPD_ERROR,
FWUPD_ERROR_NOT_SUPPORTED,
"failed to verify firmware: %s",
gnutls_strerror (ec));
return FALSE;
}
/* success */
return TRUE;
}

View File

@ -34,3 +34,7 @@ FuSynapticsRmiFunction *fu_synaptics_rmi_function_parse (GByteArray *buf,
gboolean fu_synaptics_rmi_device_writeln (const gchar *fn,
const gchar *buf,
GError **error);
gboolean fu_synaptics_verify_sha256_signature (GBytes *payload,
GBytes *pubkey,
GBytes *signature,
GError **error);

View File

@ -91,6 +91,7 @@ typedef struct
FuSynapticsRmiFunction *f01;
FuSynapticsRmiFunction *f34;
guint8 current_page;
guint16 sig_size; /* 0x0 for non-secure update */
} FuSynapticsRmiDevicePrivate;
G_DEFINE_TYPE_WITH_PRIVATE (FuSynapticsRmiDevice, fu_synaptics_rmi_device, FU_TYPE_UDEV_DEVICE)
@ -127,6 +128,7 @@ fu_synaptics_rmi_device_to_string (FuUdevDevice *device, guint idt, GString *str
FuSynapticsRmiDevice *self = FU_SYNAPTICS_RMI_DEVICE (device);
FuSynapticsRmiDevicePrivate *priv = GET_PRIVATE (self);
fu_common_string_append_kx (str, idt, "CurrentPage", priv->current_page);
fu_common_string_append_kx (str, idt, "SigSize", priv->sig_size);
if (priv->f34 != NULL) {
fu_common_string_append_kx (str, idt, "BlVer",
priv->f34->function_version + 0x5);
@ -265,6 +267,19 @@ fu_synaptics_rmi_device_read (FuSynapticsRmiDevice *self, guint16 addr, gsize re
return g_steal_pointer (&buf);
}
GByteArray *
fu_synaptics_rmi_device_read_packet_register (FuSynapticsRmiDevice *self,
guint16 addr,
gsize req_sz,
GError **error)
{
g_set_error_literal (error,
FWUPD_ERROR,
FWUPD_ERROR_NOT_SUPPORTED,
"packet register reads not supported");
return NULL;
}
gboolean
fu_synaptics_rmi_device_write (FuSynapticsRmiDevice *self, guint16 addr, GByteArray *req, GError **error)
{
@ -401,6 +416,21 @@ fu_synaptics_rmi_device_scan_pdt (FuSynapticsRmiDevice *self, GError **error)
return TRUE;
}
void
fu_synaptics_rmi_device_set_sig_size (FuSynapticsRmiDevice *self,
guint16 sig_size)
{
FuSynapticsRmiDevicePrivate *priv = GET_PRIVATE (self);
priv->sig_size = sig_size;
}
guint16
fu_synaptics_rmi_device_get_sig_size (FuSynapticsRmiDevice *self)
{
FuSynapticsRmiDevicePrivate *priv = GET_PRIVATE (self);
return priv->sig_size;
}
typedef enum {
HID_RMI4_MODE_MOUSE = 0,
HID_RMI4_MODE_ATTN_REPORTS = 1,
@ -670,7 +700,8 @@ fu_synaptics_rmi_device_prepare_firmware (FuDevice *device,
bytes_bin = fu_firmware_get_image_by_id_bytes (firmware, "ui", error);
if (bytes_bin == NULL)
return NULL;
size_expected = (gsize) priv->flash.block_count_fw * (gsize) priv->flash.block_size;
size_expected = ((gsize) priv->flash.block_count_fw * (gsize) priv->flash.block_size) +
fu_synaptics_rmi_firmware_get_sig_size (FU_SYNAPTICS_RMI_FIRMWARE (firmware));
if (g_bytes_get_size (bytes_bin) != size_expected) {
g_set_error (error,
FWUPD_ERROR,

View File

@ -54,6 +54,10 @@ GByteArray *fu_synaptics_rmi_device_read (FuSynapticsRmiDevice *self,
guint16 addr,
gsize req_sz,
GError **error);
GByteArray *fu_synaptics_rmi_device_read_packet_register (FuSynapticsRmiDevice *self,
guint16 addr,
gsize req_sz,
GError **error);
gboolean fu_synaptics_rmi_device_write (FuSynapticsRmiDevice *self,
guint16 addr,
GByteArray *req,
@ -74,3 +78,6 @@ gboolean fu_synaptics_rmi_device_rebind_driver (FuSynapticsRmiDevice *self,
GError **error);
gboolean fu_synaptics_rmi_device_poll_wait (FuSynapticsRmiDevice *self,
GError **error);
void fu_synaptics_rmi_device_set_sig_size (FuSynapticsRmiDevice *self,
guint16 sig_size);
guint16 fu_synaptics_rmi_device_get_sig_size (FuSynapticsRmiDevice *self);

View File

@ -31,6 +31,7 @@ struct _FuSynapticsRmiFirmware {
guint32 package_id;
guint16 product_info;
gchar *product_id;
guint32 sig_size;
};
G_DEFINE_TYPE (FuSynapticsRmiFirmware, fu_synaptics_rmi_firmware, FU_TYPE_FIRMWARE)
@ -42,6 +43,7 @@ G_DEFINE_TYPE (FuSynapticsRmiFirmware, fu_synaptics_rmi_firmware, FU_TYPE_FIRMWA
#define RMI_IMG_CONFIG_SIZE_OFFSET 0x0c
#define RMI_IMG_PACKAGE_ID_OFFSET 0x1a
#define RMI_IMG_FW_BUILD_ID_OFFSET 0x50
#define RMI_IMG_SIGNATURE_SIZE_OFFSET 0x54
#define RMI_IMG_PRODUCT_ID_OFFSET 0x10
#define RMI_IMG_PRODUCT_INFO_OFFSET 0x1e
#define RMI_IMG_FW_OFFSET 0x100
@ -174,6 +176,7 @@ fu_synaptics_rmi_firmware_to_string (FuFirmware *firmware, guint idt, GString *s
fu_common_string_append_kx (str, idt, "BuildId", self->build_id);
fu_common_string_append_kx (str, idt, "PackageId", self->package_id);
fu_common_string_append_kx (str, idt, "ProductInfo", self->product_info);
fu_common_string_append_kx (str, idt, "SigSize", self->sig_size);
}
static gboolean
@ -318,6 +321,7 @@ fu_synaptics_rmi_firmware_parse_v10 (FuFirmware *firmware, GBytes *fw, GError **
static gboolean
fu_synaptics_rmi_firmware_parse_v0x (FuFirmware *firmware, GBytes *fw, GError **error)
{
FuSynapticsRmiFirmware *self = FU_SYNAPTICS_RMI_FIRMWARE (firmware);
guint32 cfg_sz;
guint32 img_sz = 0;
gsize sz = 0;
@ -331,6 +335,15 @@ fu_synaptics_rmi_firmware_parse_v0x (FuFirmware *firmware, GBytes *fw, GError **
error))
return FALSE;
if (img_sz > 0) {
/* payload, then signature appended */
if (self->sig_size > 0) {
img_sz -= self->sig_size;
if (!fu_synaptics_rmi_firmware_add_image (firmware, "sig", fw,
RMI_IMG_FW_OFFSET + img_sz,
self->sig_size,
error))
return FALSE;
}
if (!fu_synaptics_rmi_firmware_add_image (firmware, "ui", fw,
RMI_IMG_FW_OFFSET,
img_sz, error))
@ -363,6 +376,7 @@ fu_synaptics_rmi_firmware_parse (FuFirmware *firmware,
FuSynapticsRmiFirmware *self = FU_SYNAPTICS_RMI_FIRMWARE (firmware);
gsize sz = 0;
guint32 checksum_calculated;
guint32 firmware_size = 0;
const guint8 *data = g_bytes_get_data (fw, &sz);
/* check minimum size */
@ -425,6 +439,12 @@ fu_synaptics_rmi_firmware_parse (FuFirmware *firmware,
G_LITTLE_ENDIAN,
error))
return FALSE;
if (!fu_common_read_uint32_safe (data, sz,
RMI_IMG_IMAGE_SIZE_OFFSET,
&firmware_size,
G_LITTLE_ENDIAN,
error))
return FALSE;
/* parse partitions, but ignore lockdown */
switch (self->bootloader_version) {
@ -433,6 +453,14 @@ fu_synaptics_rmi_firmware_parse (FuFirmware *firmware,
case 4:
case 5:
case 6:
if ((self->io & 0x10) >> 1) {
if (!fu_common_read_uint32_safe (data, sz,
RMI_IMG_SIGNATURE_SIZE_OFFSET,
&self->sig_size,
G_LITTLE_ENDIAN,
error))
return FALSE;
}
if (!fu_synaptics_rmi_firmware_parse_v0x (firmware, fw, error))
return FALSE;
self->kind = RMI_FIRMWARE_KIND_0X;
@ -455,6 +483,12 @@ fu_synaptics_rmi_firmware_parse (FuFirmware *firmware,
return TRUE;
}
guint32
fu_synaptics_rmi_firmware_get_sig_size (FuSynapticsRmiFirmware *self)
{
return self->sig_size;
}
static GBytes *
fu_synaptics_rmi_firmware_write_v0x (FuFirmware *firmware, GError **error)
{

View File

@ -12,3 +12,4 @@
G_DECLARE_FINAL_TYPE (FuSynapticsRmiFirmware, fu_synaptics_rmi_firmware, FU, SYNAPTICS_RMI_FIRMWARE, FuFirmware)
FuFirmware *fu_synaptics_rmi_firmware_new (void);
guint32 fu_synaptics_rmi_firmware_get_sig_size (FuSynapticsRmiFirmware *self);

View File

@ -10,6 +10,7 @@
#include "fu-chunk.h"
#include "fu-common.h"
#include "fu-synaptics-rmi-firmware.h"
#include "fu-synaptics-rmi-v5-device.h"
#include "fwupd-error.h"
@ -18,6 +19,7 @@
#define RMI_F34_ERASE_ALL 0x03
#define RMI_F34_WRITE_LOCKDOWN_BLOCK 0x04
#define RMI_F34_WRITE_CONFIG_BLOCK 0x06
#define RMI_F34_WRITE_SIGNATURE 0x0b
#define RMI_F34_ENABLE_FLASH_PROG 0x0f
#define RMI_F34_BLOCK_SIZE_OFFSET 1
@ -118,19 +120,110 @@ fu_synaptics_rmi_v5_device_write_block (FuSynapticsRmiDevice *self,
return TRUE;
}
static gboolean
fu_synaptics_rmi_v5_device_secure_check (FuDevice *device,
GBytes *payload,
GBytes *signature,
GError **error)
{
FuSynapticsRmiDevice *self = FU_SYNAPTICS_RMI_DEVICE (device);
FuSynapticsRmiFunction *f34;
guint16 rsa_pubkey_len = fu_synaptics_rmi_device_get_sig_size (self) / 8;
guint16 rsa_block_cnt = rsa_pubkey_len / 3;
guint16 rsa_block_remain = rsa_pubkey_len % 3;
g_autoptr(GByteArray) pubkey_buf = g_byte_array_new ();
g_autoptr(GBytes) pubkey = NULL;
if (g_getenv ("FWUPD_SYNAPTICS_RMI_VERBOSE") != NULL)
fu_common_dump_bytes (G_LOG_DOMAIN, "Signature", signature);
f34 = fu_synaptics_rmi_device_get_function (self, 0x34, error);
if (f34 == NULL)
return FALSE;
/* parse RSA public key modulus */
if (rsa_block_remain > 0)
rsa_block_cnt += 1;
for (guint retries = 0; ; retries++) {
/* need read another register to reset the offset of packet register */
if (!fu_synaptics_rmi_v5_device_query_status (self, error)) {
g_prefix_error (error, "failed to read status: ");
return FALSE;
}
for (guint16 block_num = 0; block_num < rsa_block_cnt; block_num++) {
g_autoptr(GByteArray) res = NULL;
res = fu_synaptics_rmi_device_read_packet_register (self,
f34->query_base + 14, /* addr of flash properties + 5 */
0x3,
error);
if (res == NULL)
return FALSE;
if (res->len != 0x3)
g_debug ("read %u bytes in return", res->len);
if (rsa_block_remain && block_num + 1 == rsa_block_cnt) {
g_byte_array_remove_range (res,
rsa_block_remain,
res->len - rsa_block_remain);
}
for (guint i = 0 ; i < res->len / 2 ; i++) {
guint8 tmp = res->data[i];
res->data[i] = res->data[res->len - i - 1];
res->data[res->len - i - 1] = tmp;
}
if (rsa_block_remain && block_num + 1 == rsa_block_cnt) {
g_byte_array_prepend (pubkey_buf, res->data, rsa_block_remain);
} else {
g_byte_array_prepend (pubkey_buf, res->data, res->len);
}
}
if (rsa_pubkey_len != pubkey_buf->len) {
if (retries++ > 2) {
g_set_error (error,
G_IO_ERROR, G_IO_ERROR_FAILED,
"RSA public key length not matched %u: after %u retries: ",
pubkey_buf->len, retries);
return FALSE;
}
g_byte_array_set_size (pubkey_buf, 0);
continue;
}
/* success */
break;
}
if (g_getenv ("FWUPD_SYNAPTICS_RMI_VERBOSE") != NULL) {
fu_common_dump_full (G_LOG_DOMAIN, "RSA public key",
pubkey_buf->data, pubkey_buf->len,
16, FU_DUMP_FLAGS_NONE);
}
/* sanity check size */
if (rsa_pubkey_len != pubkey_buf->len) {
g_set_error (error,
FWUPD_ERROR,
FWUPD_ERROR_NOT_SUPPORTED,
"RSA public key length did not match: %u != %u: ",
rsa_pubkey_len, pubkey_buf->len);
return FALSE;
}
pubkey = g_bytes_new (pubkey_buf->data, pubkey_buf->len);
return fu_synaptics_verify_sha256_signature (payload, pubkey, signature, error);
}
gboolean
fu_synaptics_rmi_v5_device_write_firmware (FuDevice *device,
FuFirmware *firmware,
FwupdInstallFlags flags,
GError **error)
{
FuSynapticsRmiDevice *self = FU_SYNAPTICS_RMI_DEVICE (device);
FuSynapticsRmiFlash *flash = fu_synaptics_rmi_device_get_flash (self);
FuSynapticsRmiFunction *f34;
FuSynapticsRmiFirmware *rmi_firmware = FU_SYNAPTICS_RMI_FIRMWARE (firmware);
guint32 address;
g_autoptr(GBytes) bytes_bin = NULL;
g_autoptr(GBytes) bytes_cfg = NULL;
g_autoptr(GBytes) signature_bin = NULL;
g_autoptr(GPtrArray) chunks_bin = NULL;
g_autoptr(GPtrArray) chunks_cfg = NULL;
g_autoptr(GByteArray) req_addr = g_byte_array_new ();
@ -151,6 +244,22 @@ fu_synaptics_rmi_v5_device_write_firmware (FuDevice *device,
g_prefix_error (error, "not idle: ");
return FALSE;
}
if (fu_synaptics_rmi_firmware_get_sig_size (rmi_firmware) == 0 &&
fu_synaptics_rmi_device_get_sig_size (self) != 0) {
g_set_error_literal (error,
FWUPD_ERROR,
FWUPD_ERROR_INVALID_FILE,
"device secure but firmware not secure");
return FALSE;
}
if (fu_synaptics_rmi_firmware_get_sig_size (rmi_firmware) != 0 &&
fu_synaptics_rmi_device_get_sig_size (self) == 0) {
g_set_error_literal (error,
FWUPD_ERROR,
FWUPD_ERROR_INVALID_FILE,
"device not secure but firmware secure");
return FALSE;
}
/* f34 */
f34 = fu_synaptics_rmi_device_get_function (self, 0x34, error);
@ -165,6 +274,18 @@ fu_synaptics_rmi_v5_device_write_firmware (FuDevice *device,
if (bytes_cfg == NULL)
return FALSE;
/* verify signature if set */
signature_bin = fu_firmware_get_image_by_id_bytes (firmware, "sig", NULL);
if (signature_bin != NULL) {
if (!fu_synaptics_rmi_v5_device_secure_check (device,
bytes_bin,
signature_bin,
error)) {
g_prefix_error (error, "secure check failed: ");
return FALSE;
}
}
/* disable powersaving */
if (!fu_synaptics_rmi_device_disable_sleep (self, error)) {
g_prefix_error (error, "failed to disable sleep: ");
@ -220,6 +341,35 @@ fu_synaptics_rmi_v5_device_write_firmware (FuDevice *device,
(gsize) chunks_bin->len + chunks_cfg->len);
}
/* payload signature */
if (signature_bin != NULL &&
fu_synaptics_rmi_device_get_sig_size (self) != 0) {
g_autoptr(GPtrArray) chunks_sig = NULL;
chunks_sig = fu_chunk_array_new_from_bytes (signature_bin,
0x00, /* start addr */
0x00, /* page_sz */
flash->block_size);
if (!fu_synaptics_rmi_device_write (self, f34->data_base, req_addr, error)) {
g_prefix_error (error, "failed to write 1st address zero: ");
return FALSE;
}
for (guint i = 0; i < chunks_sig->len; i++) {
FuChunk *chk = g_ptr_array_index (chunks_sig, i);
if (!fu_synaptics_rmi_v5_device_write_block (self,
RMI_F34_WRITE_SIGNATURE,
address,
chk->data,
chk->data_sz,
error)) {
g_prefix_error (error, "failed to write bin block %u: ", chk->idx);
return FALSE;
}
fu_device_set_progress_full (device, (gsize) i,
(gsize) chunks_bin->len + chunks_cfg->len);
}
g_usleep (1000 * 1000);
}
/* program the configuration image */
if (!fu_synaptics_rmi_device_write (self, f34->data_base, req_addr, error)) {
g_prefix_error (error, "failed to 2nd write address zero: ");
@ -250,8 +400,10 @@ fu_synaptics_rmi_v5_device_setup (FuSynapticsRmiDevice *self, GError **error)
{
FuSynapticsRmiFunction *f34;
FuSynapticsRmiFlash *flash = fu_synaptics_rmi_device_get_flash (self);
guint8 flash_properties2 = 0;
g_autoptr(GByteArray) f34_data0 = NULL;
g_autoptr(GByteArray) f34_data2 = NULL;
g_autoptr(GByteArray) buf_flash_properties2 = NULL;
/* f34 */
f34 = fu_synaptics_rmi_device_get_function (self, 0x34, error);
@ -267,6 +419,45 @@ fu_synaptics_rmi_v5_device_setup (FuSynapticsRmiDevice *self, GError **error)
flash->bootloader_id[0] = f34_data0->data[0];
flash->bootloader_id[1] = f34_data0->data[1];
/* get flash properties */
buf_flash_properties2 = fu_synaptics_rmi_device_read (self, f34->query_base + 0x9, 1, error);
if (buf_flash_properties2 == NULL) {
g_prefix_error (error, "failed to read Flash Properties 2: ");
return FALSE;
}
if (!fu_common_read_uint8_safe (buf_flash_properties2->data,
buf_flash_properties2->len,
0x0, /* offset */
&flash_properties2,
error)) {
g_prefix_error (error, "failed to parse Flash Properties 2: ");
return FALSE;
}
if (flash_properties2 & 0x01) {
guint16 sig_size = 0;
g_autoptr(GByteArray) buf_rsa_key = NULL;
buf_rsa_key = fu_synaptics_rmi_device_read (self,
f34->query_base + 0x9 + 0x1,
2,
error);
if (buf_rsa_key == NULL) {
g_prefix_error (error, "failed to read RSA key length: ");
return FALSE;
}
if (!fu_common_read_uint16_safe (buf_rsa_key->data,
buf_rsa_key->len,
0x0, /* offset */
&sig_size,
G_LITTLE_ENDIAN,
error)) {
g_prefix_error (error, "failed to parse RSA key length: ");
return FALSE;
}
fu_synaptics_rmi_device_set_sig_size (self, sig_size);
} else {
fu_synaptics_rmi_device_set_sig_size (self, 0);
}
/* get flash properties */
f34_data2 = fu_synaptics_rmi_device_read (self, f34->query_base + 0x2, 0x7, error);
if (f34_data2 == NULL)

View File

@ -25,6 +25,7 @@ shared_module('fu_plugin_synaptics_rmi',
c_args : cargs,
dependencies : [
plugin_deps,
gnutls,
],
link_with : [
fwupd,