diff --git a/plugins/vli-usbhub/README.md b/plugins/vli-usbhub/README.md index 558c0e039..72192f31d 100644 --- a/plugins/vli-usbhub/README.md +++ b/plugins/vli-usbhub/README.md @@ -35,6 +35,10 @@ Optional PD child devices use just one extra GUID, e.g. * `VLI_USBHUB_PD\VID_17EF&PID_3083` +Optional I²C child devices use just one extra GUID, e.g. + + * `VLI_USBHUB_I2C\MSP430` + Quirk Use --------- diff --git a/plugins/vli-usbhub/fu-vli-usbhub-device.c b/plugins/vli-usbhub/fu-vli-usbhub-device.c index 12e4f7bd2..f018893e8 100644 --- a/plugins/vli-usbhub/fu-vli-usbhub-device.c +++ b/plugins/vli-usbhub/fu-vli-usbhub-device.c @@ -15,6 +15,7 @@ #include "fu-vli-usbhub-common.h" #include "fu-vli-usbhub-device.h" #include "fu-vli-usbhub-firmware.h" +#include "fu-vli-usbhub-i2c-device.h" #include "fu-vli-usbhub-pd-common.h" #include "fu-vli-usbhub-pd-device.h" @@ -83,6 +84,83 @@ fu_vli_usbhub_device_to_string (FuDevice *device, guint idt, GString *str) } } +gboolean +fu_vli_usbhub_device_i2c_read (FuVliUsbhubDevice *self, + guint8 cmd, guint8 *buf, gsize bufsz, + GError **error) +{ + GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (self)); + guint16 value = ((guint16) FU_VLI_USBHUB_I2C_ADDR_WRITE << 8) | cmd; + guint16 index = (guint16) FU_VLI_USBHUB_I2C_ADDR_READ << 8; + if (!g_usb_device_control_transfer (usb_device, + G_USB_DEVICE_DIRECTION_DEVICE_TO_HOST, + G_USB_DEVICE_REQUEST_TYPE_VENDOR, + G_USB_DEVICE_RECIPIENT_DEVICE, + FU_VLI_USBHUB_I2C_R_VDR, value, index, + buf, bufsz, NULL, + FU_VLI_USBHUB_DEVICE_TIMEOUT, + NULL, error)) { + g_prefix_error (error, "failed to read I2C: "); + return FALSE; + } + if (g_getenv ("FWUPD_VLI_USBHUB_VERBOSE") != NULL) + fu_common_dump_raw (G_LOG_DOMAIN, "I2cReadData", buf, 0x1); + return TRUE; +} + +gboolean +fu_vli_usbhub_device_i2c_read_status (FuVliUsbhubDevice *self, + FuVliUsbhubI2cStatus *status, + GError **error) +{ + guint8 buf[1] = { 0xff }; + if (!fu_vli_usbhub_device_i2c_read (self, + FU_VLI_USBHUB_I2C_CMD_READ_STATUS, + buf, sizeof(buf), + error)) + return FALSE; + if (status != NULL) + *status = buf[0]; + return TRUE; +} + +gboolean +fu_vli_usbhub_device_i2c_write_data (FuVliUsbhubDevice *self, + guint8 skip_s, + guint8 skip_p, + const guint8 *buf, + gsize bufsz, + GError **error) +{ + GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (self)); + guint16 value = (((guint16) skip_s) << 8) | skip_p; + if (g_getenv ("FWUPD_VLI_USBHUB_VERBOSE") != NULL) + fu_common_dump_raw (G_LOG_DOMAIN, "I2cWriteData", buf, bufsz); + if (!g_usb_device_control_transfer (usb_device, + G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE, + G_USB_DEVICE_REQUEST_TYPE_VENDOR, + G_USB_DEVICE_RECIPIENT_DEVICE, + FU_VLI_USBHUB_I2C_W_VDR, value, 0x0, + (guint8 *) buf, bufsz, NULL, + FU_VLI_USBHUB_DEVICE_TIMEOUT, + NULL, error)) { + g_prefix_error (error, "failed to write I2C @0x%x: ", value); + return FALSE; + } + return TRUE; +} + +gboolean +fu_vli_usbhub_device_i2c_write (FuVliUsbhubDevice *self, guint8 cmd, + const guint8 *buf, gsize bufsz, GError **error) +{ + guint8 buf2[10] = { FU_VLI_USBHUB_I2C_ADDR_WRITE, cmd, 0x0 }; + if (!fu_memcpy_safe (buf2, sizeof(buf2), 0x2, + buf, bufsz, 0x0, bufsz, error)) + return FALSE; + return fu_vli_usbhub_device_i2c_write_data (self, 0x0, 0x0, buf2, bufsz + 2, error); +} + static gboolean fu_vli_usbhub_device_vdr_unlock_813 (FuVliUsbhubDevice *self, GError **error) { @@ -699,7 +777,7 @@ fu_vli_usbhub_device_probe (FuDevice *device, GError **error) } static gboolean -fu_vli_usbhub_device_setup_children (FuVliUsbhubDevice *self, GError **error) +fu_vli_usbhub_device_pd_setup (FuVliUsbhubDevice *self, GError **error) { FuVliUsbhubPdHdr hdr = { 0x0 }; g_autoptr(FuDevice) dev = NULL; @@ -757,6 +835,31 @@ fu_vli_usbhub_device_setup_children (FuVliUsbhubDevice *self, GError **error) return TRUE; } +static gboolean +fu_vli_usbhub_device_i2c_setup (FuVliUsbhubDevice *self, GError **error) +{ + g_autoptr(FuDevice) dev = NULL; + g_autoptr(GError) error_local = NULL; + + /* add child */ + dev = fu_vli_usbhub_i2c_device_new (self); + if (!fu_device_probe (dev, error)) + return FALSE; + if (!fu_device_setup (dev, &error_local)) { + if (g_error_matches (error_local, + FWUPD_ERROR, + FWUPD_ERROR_NOT_FOUND)) { + g_debug ("%s", error_local->message); + } else { + g_warning ("cannot create I²C device: %s", + error_local->message); + } + return TRUE; + } + fu_device_add_child (FU_DEVICE (self), dev); + return TRUE; +} + static gboolean fu_vli_usbhub_device_setup (FuDevice *device, GError **error) { @@ -859,7 +962,11 @@ fu_vli_usbhub_device_setup (FuDevice *device, GError **error) } /* detect the PD child */ - if (!fu_vli_usbhub_device_setup_children (self, error)) + if (!fu_vli_usbhub_device_pd_setup (self, error)) + return FALSE; + + /* detect the PD child */ + if (!fu_vli_usbhub_device_i2c_setup (self, error)) return FALSE; /* success */ diff --git a/plugins/vli-usbhub/fu-vli-usbhub-device.h b/plugins/vli-usbhub/fu-vli-usbhub-device.h index a430631cb..6bfe64fd4 100644 --- a/plugins/vli-usbhub/fu-vli-usbhub-device.h +++ b/plugins/vli-usbhub/fu-vli-usbhub-device.h @@ -8,6 +8,8 @@ #include "fu-plugin.h" +#include "fu-vli-usbhub-i2c-common.h" + #define FU_TYPE_VLI_USBHUB_DEVICE (fu_vli_usbhub_device_get_type ()) G_DECLARE_FINAL_TYPE (FuVliUsbhubDevice, fu_vli_usbhub_device, FU, VLI_USBHUB_DEVICE, FuUsbDevice) @@ -29,3 +31,22 @@ GBytes *fu_vli_usbhub_device_spi_read (FuVliUsbhubDevice *self, guint32 address, gsize bufsz, GError **error); +gboolean fu_vli_usbhub_device_i2c_read (FuVliUsbhubDevice *self, + guint8 cmd, + guint8 *buf, + gsize bufsz, + GError **error); +gboolean fu_vli_usbhub_device_i2c_read_status (FuVliUsbhubDevice *self, + FuVliUsbhubI2cStatus *status, + GError **error); +gboolean fu_vli_usbhub_device_i2c_write (FuVliUsbhubDevice *self, + guint8 cmd, + const guint8 *buf, + gsize bufsz, + GError **error); +gboolean fu_vli_usbhub_device_i2c_write_data (FuVliUsbhubDevice *self, + guint8 skip_s, + guint8 skip_p, + const guint8 *buf, + gsize bufsz, + GError **error); diff --git a/plugins/vli-usbhub/fu-vli-usbhub-i2c-common.c b/plugins/vli-usbhub/fu-vli-usbhub-i2c-common.c new file mode 100644 index 000000000..5d06a80b3 --- /dev/null +++ b/plugins/vli-usbhub/fu-vli-usbhub-i2c-common.c @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2017-2019 VIA Corporation + * Copyright (C) 2019 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-vli-usbhub-i2c-common.h" + +const gchar * +fu_vli_usbhub_i2c_chip_to_string (FuVliUsbhubI2cChip chip) +{ + if (chip == FU_VLI_USBHUB_I2C_CHIP_MSP430) + return "MSP430"; + return NULL; +} + +gboolean +fu_vli_usbhub_i2c_check_status (FuVliUsbhubI2cStatus status, GError **error) +{ + if (status == FU_VLI_USBHUB_I2C_STATUS_OK) + return TRUE; + if (status == FU_VLI_USBHUB_I2C_STATUS_HEADER) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "Incorrect header value of data frame"); + return FALSE; + } + if (status == FU_VLI_USBHUB_I2C_STATUS_COMMAND) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "Invalid command data"); + return FALSE; + } + if (status == FU_VLI_USBHUB_I2C_STATUS_ADDRESS) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "Invalid address range"); + return FALSE; + } + if (status == FU_VLI_USBHUB_I2C_STATUS_PACKETSIZE) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "Incorrect payload data length"); + return FALSE; + } + if (status == FU_VLI_USBHUB_I2C_STATUS_CHECKSUM) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "Incorrect frame data checksum"); + return FALSE; + } + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "Unknown error [0x%02x]", status); + return FALSE; +} diff --git a/plugins/vli-usbhub/fu-vli-usbhub-i2c-common.h b/plugins/vli-usbhub/fu-vli-usbhub-i2c-common.h new file mode 100644 index 000000000..8fa7e3c99 --- /dev/null +++ b/plugins/vli-usbhub/fu-vli-usbhub-i2c-common.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2017-2019 VIA Corporation + * Copyright (C) 2019 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include "fu-plugin.h" + +typedef enum { + FU_VLI_USBHUB_I2C_CHIP_UNKNOWN, + FU_VLI_USBHUB_I2C_CHIP_MSP430, +} FuVliUsbhubI2cChip; + +typedef enum { + FU_VLI_USBHUB_I2C_STATUS_OK, + FU_VLI_USBHUB_I2C_STATUS_HEADER, + FU_VLI_USBHUB_I2C_STATUS_COMMAND, + FU_VLI_USBHUB_I2C_STATUS_ADDRESS, + FU_VLI_USBHUB_I2C_STATUS_PACKETSIZE, + FU_VLI_USBHUB_I2C_STATUS_CHECKSUM, +} FuVliUsbhubI2cStatus; + +/* Texas Instruments BSL */ +#define FU_VLI_USBHUB_I2C_ADDR_WRITE 0x18 +#define FU_VLI_USBHUB_I2C_ADDR_READ 0x19 + +#define FU_VLI_USBHUB_I2C_CMD_WRITE 0x32 +#define FU_VLI_USBHUB_I2C_CMD_READ_STATUS 0x33 +#define FU_VLI_USBHUB_I2C_CMD_UPGRADE 0x34 +#define FU_VLI_USBHUB_I2C_CMD_READ_VERSIONS 0x40 + +#define FU_VLI_USBHUB_I2C_R_VDR 0xa0 /* read vendor comand */ +#define FU_VLI_USBHUB_I2C_W_VDR 0xb0 /* write vendor comand */ + +const gchar *fu_vli_usbhub_i2c_chip_to_string (FuVliUsbhubI2cChip chip); +gboolean fu_vli_usbhub_i2c_check_status (FuVliUsbhubI2cStatus status, + GError **error); diff --git a/plugins/vli-usbhub/fu-vli-usbhub-i2c-device.c b/plugins/vli-usbhub/fu-vli-usbhub-i2c-device.c new file mode 100644 index 000000000..1d74f9d1c --- /dev/null +++ b/plugins/vli-usbhub/fu-vli-usbhub-i2c-device.c @@ -0,0 +1,279 @@ +/* + * Copyright (C) 2017-2019 VIA Corporation + * Copyright (C) 2019 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-firmware-common.h" +#include "fu-ihex-firmware.h" + +#include "fu-vli-usbhub-common.h" +#include "fu-vli-usbhub-device.h" +#include "fu-vli-usbhub-i2c-common.h" +#include "fu-vli-usbhub-i2c-device.h" + +struct _FuVliUsbhubI2cDevice +{ + FuDevice parent_instance; + FuVliUsbhubDevice *parent; + FuVliUsbhubI2cChip chip; +}; + +G_DEFINE_TYPE (FuVliUsbhubI2cDevice, fu_vli_usbhub_i2c_device, FU_TYPE_DEVICE) + +static void +fu_vli_usbhub_i2c_device_to_string (FuDevice *device, guint idt, GString *str) +{ + FuVliUsbhubI2cDevice *self = FU_VLI_USBHUB_I2C_DEVICE (device); + fu_common_string_append_kv (str, idt, "ChipId", + fu_vli_usbhub_i2c_chip_to_string (self->chip)); +} + +static gboolean +fu_vli_usbhub_i2c_device_setup (FuDevice *device, GError **error) +{ + FuVliUsbhubI2cDevice *self = FU_VLI_USBHUB_I2C_DEVICE (device); + guint8 buf[11] = { 0x0 }; + g_autofree gchar *instance_id = NULL; + g_autofree gchar *version = NULL; + g_autoptr(FuVliUsbhubDevice) parent = g_steal_pointer (&self->parent); + + /* get versions */ + if (!fu_vli_usbhub_device_i2c_read (parent, + FU_VLI_USBHUB_I2C_CMD_READ_VERSIONS, + buf, sizeof(buf), error)) { + g_prefix_error (error, "failed to read versions: "); + return FALSE; + } + if ((buf[0] == 0x00 && buf[1] == 0x00 && buf[2] == 0x00) || + (buf[0] == 0xff && buf[1] == 0xff && buf[2] == 0xff)) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_FOUND, + "no %s device detected", + fu_vli_usbhub_i2c_chip_to_string (self->chip)); + return FALSE; + } + + /* add instance ID */ + instance_id = g_strdup_printf ("VLI_USBHUB_I2C\\%s", + fu_vli_usbhub_i2c_chip_to_string (self->chip)); + fu_device_add_instance_id (device, instance_id); + + /* set version */ + version = g_strdup_printf ("%x.%x.%x", buf[0], buf[1], buf[2]); + fu_device_set_version (device, version, FWUPD_VERSION_FORMAT_TRIPLET); + return TRUE; +} + +static gboolean +fu_vli_usbhub_i2c_device_detach (FuDevice *device, GError **error) +{ + FuVliUsbhubDevice *parent = FU_VLI_USBHUB_DEVICE (fu_device_get_parent (device)); + const guint8 buf[] = { + FU_VLI_USBHUB_I2C_ADDR_WRITE, + FU_VLI_USBHUB_I2C_CMD_UPGRADE, + }; + if (!fu_vli_usbhub_device_i2c_write_data (parent, 0, 0, buf, sizeof(buf), error)) + return FALSE; + + /* avoid power instability */ + fu_device_set_status (device, FWUPD_STATUS_DEVICE_RESTART); + g_usleep (5000); + + /* success */ + return TRUE; +} + +static FuFirmware * +fu_vli_usbhub_i2c_device_prepare_firmware (FuDevice *device, + GBytes *fw, + FwupdInstallFlags flags, + GError **error) +{ + g_autoptr(FuFirmware) firmware = fu_ihex_firmware_new (); + fu_device_set_status (device, FWUPD_STATUS_DECOMPRESSING); + if (!fu_firmware_tokenize (firmware, fw, flags, error)) + return NULL; + return g_steal_pointer (&firmware); +} + +static gboolean +fu_vli_usbhub_i2c_device_write_firmware (FuDevice *device, + FuFirmware *firmware, + FwupdInstallFlags flags, + GError **error) +{ + FuVliUsbhubDevice *parent = FU_VLI_USBHUB_DEVICE (fu_device_get_parent (device)); + GPtrArray *records = fu_ihex_firmware_get_records (FU_IHEX_FIRMWARE (firmware)); + guint16 usbver = fu_usb_device_get_spec (FU_USB_DEVICE (device)); + + /* transfer by I²C write, and check status by I²C read */ + fu_device_set_status (device, FWUPD_STATUS_DEVICE_WRITE); + for (guint j = 0; j < records->len; j++) { + FuIhexFirmwareRecord *rcd = g_ptr_array_index (records, j); + const gchar *line = rcd->buf->str; + gsize bufsz; + guint8 buf[0x40] = { 0x0 }; + guint8 req_len; + guint retry; + + /* check there's enough data for the smallest possible record */ + if (rcd->buf->len < 11) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "line %u is incomplete, length %u", + rcd->ln, (guint) rcd->buf->len); + return FALSE; + } + + /* check starting token */ + if (line[0] != ':') { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "invalid starting token on line %u: %s", + rcd->ln, line); + return FALSE; + } + + /* length, 16-bit address, type */ + req_len = fu_firmware_strparse_uint8 (line + 1); + if (req_len > 64) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "max write is 64 bytes"); + return FALSE; + } + if (9 + (guint) req_len * 2 > (guint) rcd->buf->len) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "line %u malformed", rcd->ln); + return FALSE; + } + + /* write each record directly to the hardware */ + buf[0] = FU_VLI_USBHUB_I2C_ADDR_WRITE; + buf[1] = FU_VLI_USBHUB_I2C_CMD_WRITE; + buf[2] = 0x3a; /* ':' */ + buf[3] = req_len; + buf[4] = fu_firmware_strparse_uint8 (line + 3); + buf[5] = fu_firmware_strparse_uint8 (line + 5); + buf[6] = fu_firmware_strparse_uint8 (line + 7); + for (guint8 i = 0; i < req_len; i++) + buf[7 + i] = fu_firmware_strparse_uint8 (line + 9 + (i * 2)); + buf[7 + req_len] = fu_firmware_strparse_uint8 (line + 9+ (req_len * 2)); + bufsz = req_len + 8; + + for (retry = 0; retry < 5; retry++) { + FuVliUsbhubI2cStatus status = 0xff; + g_autoptr(GError) error_local = NULL; + + g_usleep (5 * 1000); + if (usbver >= 0x0300 || bufsz <= 32) { + if (!fu_vli_usbhub_device_i2c_write_data (parent, + 0, 0, + buf, + bufsz, + error)) + return FALSE; + } else { + /* for U2, hub data buffer <= 32 bytes */ + if (!fu_vli_usbhub_device_i2c_write_data (parent, + 0, 1, + buf, + 32, + error)) + return FALSE; + if (!fu_vli_usbhub_device_i2c_write_data (parent, + 1, 0, + buf + 32, + bufsz - 32, + error)) + return FALSE; + } + + /* end of file, no need to check status */ + if (req_len == 0 && buf[6] == 0x01 && buf[7] == 0xFF) + break; + + /* read data to check status */ + g_usleep (5 * 1000); + if (!fu_vli_usbhub_device_i2c_read_status (parent, + &status, + error)) + return FALSE; + if (!fu_vli_usbhub_i2c_check_status (status, &error_local)) { + g_warning ("error on try %u: %s", + retry + 1, error_local->message); + } else { + break; + } + } + if (retry >= 5) { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "I²C status retry failed"); + return FALSE; + } + fu_device_set_progress_full (device, (gsize) j, (gsize) records->len); + } + + /* success */ + return TRUE; +} + +static gboolean +fu_vli_usbhub_i2c_device_probe (FuDevice *device, GError **error) +{ + FuVliUsbhubI2cDevice *self = FU_VLI_USBHUB_I2C_DEVICE (device); + self->chip = FU_VLI_USBHUB_I2C_CHIP_MSP430; + fu_device_set_name (device, fu_vli_usbhub_i2c_chip_to_string (self->chip)); + return TRUE; +} + +static void +fu_vli_usbhub_i2c_device_init (FuVliUsbhubI2cDevice *self) +{ + fu_device_add_icon (FU_DEVICE (self), "audio-card"); + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_UPDATABLE); + fu_device_set_logical_id (FU_DEVICE (self), "I2C"); + fu_device_set_summary (FU_DEVICE (self), "I²C Dock Management Device"); +} + +static void +fu_vli_usbhub_i2c_device_finalize (GObject *object) +{ + FuVliUsbhubI2cDevice *self = FU_VLI_USBHUB_I2C_DEVICE (object); + g_clear_object (&self->parent); + G_OBJECT_CLASS (fu_vli_usbhub_i2c_device_parent_class)->finalize (object); +} + +static void +fu_vli_usbhub_i2c_device_class_init (FuVliUsbhubI2cDeviceClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); + object_class->finalize = fu_vli_usbhub_i2c_device_finalize; + klass_device->to_string = fu_vli_usbhub_i2c_device_to_string; + klass_device->probe = fu_vli_usbhub_i2c_device_probe; + klass_device->setup = fu_vli_usbhub_i2c_device_setup; + klass_device->detach = fu_vli_usbhub_i2c_device_detach; + klass_device->write_firmware = fu_vli_usbhub_i2c_device_write_firmware; + klass_device->prepare_firmware = fu_vli_usbhub_i2c_device_prepare_firmware; +} + +FuDevice * +fu_vli_usbhub_i2c_device_new (FuVliUsbhubDevice *parent) +{ + FuVliUsbhubI2cDevice *self = g_object_new (FU_TYPE_VLI_USBHUB_I2C_DEVICE, NULL); + self->parent = g_object_ref (parent); + return FU_DEVICE (self); +} diff --git a/plugins/vli-usbhub/fu-vli-usbhub-i2c-device.h b/plugins/vli-usbhub/fu-vli-usbhub-i2c-device.h new file mode 100644 index 000000000..27615ed62 --- /dev/null +++ b/plugins/vli-usbhub/fu-vli-usbhub-i2c-device.h @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2019 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include "fu-plugin.h" + +#define FU_TYPE_VLI_USBHUB_I2C_DEVICE (fu_vli_usbhub_i2c_device_get_type ()) +G_DECLARE_FINAL_TYPE (FuVliUsbhubI2cDevice, fu_vli_usbhub_i2c_device, FU, VLI_USBHUB_I2C_DEVICE, FuDevice) + +struct _FuVliUsbhubI2cDeviceClass +{ + FuDeviceClass parent_class; +}; + +FuDevice *fu_vli_usbhub_i2c_device_new (FuVliUsbhubDevice *parent); diff --git a/plugins/vli-usbhub/meson.build b/plugins/vli-usbhub/meson.build index 0cb47bf6e..f12f6c93f 100644 --- a/plugins/vli-usbhub/meson.build +++ b/plugins/vli-usbhub/meson.build @@ -14,6 +14,8 @@ shared_module('fu_plugin_vli_usbhub', 'fu-vli-usbhub-common.c', 'fu-vli-usbhub-device.c', 'fu-vli-usbhub-firmware.c', + 'fu-vli-usbhub-i2c-common.c', + 'fu-vli-usbhub-i2c-device.c', 'fu-vli-usbhub-pd-common.c', 'fu-vli-usbhub-pd-device.c', 'fu-vli-usbhub-pd-firmware.c',