From 1910e84c72a8ab7831b5ad9e057dfa236588c693 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Fri, 17 Jan 2020 11:42:21 +0000 Subject: [PATCH] Add a plugin to update PD controllers by Fresco Logic --- contrib/fwupd.spec.in | 1 + plugins/fresco-pd/README.md | 35 ++ plugins/fresco-pd/fresco-pd.quirk | 7 + plugins/fresco-pd/fu-fresco-pd-common.c | 18 + plugins/fresco-pd/fu-fresco-pd-common.h | 12 + plugins/fresco-pd/fu-fresco-pd-device.c | 417 ++++++++++++++++++++++ plugins/fresco-pd/fu-fresco-pd-device.h | 17 + plugins/fresco-pd/fu-fresco-pd-firmware.c | 81 +++++ plugins/fresco-pd/fu-fresco-pd-firmware.h | 16 + plugins/fresco-pd/fu-plugin-fresco-pd.c | 21 ++ plugins/fresco-pd/lsusb.txt | 72 ++++ plugins/fresco-pd/meson.build | 30 ++ plugins/meson.build | 1 + 13 files changed, 728 insertions(+) create mode 100644 plugins/fresco-pd/README.md create mode 100644 plugins/fresco-pd/fresco-pd.quirk create mode 100644 plugins/fresco-pd/fu-fresco-pd-common.c create mode 100644 plugins/fresco-pd/fu-fresco-pd-common.h create mode 100644 plugins/fresco-pd/fu-fresco-pd-device.c create mode 100644 plugins/fresco-pd/fu-fresco-pd-device.h create mode 100644 plugins/fresco-pd/fu-fresco-pd-firmware.c create mode 100644 plugins/fresco-pd/fu-fresco-pd-firmware.h create mode 100644 plugins/fresco-pd/fu-plugin-fresco-pd.c create mode 100644 plugins/fresco-pd/lsusb.txt create mode 100644 plugins/fresco-pd/meson.build diff --git a/contrib/fwupd.spec.in b/contrib/fwupd.spec.in index 9afa3c035..f4a68a17c 100644 --- a/contrib/fwupd.spec.in +++ b/contrib/fwupd.spec.in @@ -339,6 +339,7 @@ rm ${RPM_BUILD_ROOT}%{_sbindir}/flashrom %if 0%{?enable_flashrom} %{_libdir}/fwupd-plugins-3/libfu_plugin_flashrom.so %endif +%{_libdir}/fwupd-plugins-3/libfu_plugin_fresco_pd.so %{_libdir}/fwupd-plugins-3/libfu_plugin_jabra.so %if 0%{?have_modem_manager} %{_libdir}/fwupd-plugins-3/libfu_plugin_modem_manager.so diff --git a/plugins/fresco-pd/README.md b/plugins/fresco-pd/README.md new file mode 100644 index 000000000..c592e9059 --- /dev/null +++ b/plugins/fresco-pd/README.md @@ -0,0 +1,35 @@ +Fresco PD Support +================= + +Introduction +------------ + +This plugin is used to update Power Devlivery devices by Fresco. + +Firmware Format +--------------- + +The daemon will decompress the cabinet archive and extract a firmware blob in +an unspecifed binary format. + +This plugin supports the following protocol ID: + + * com.frescologic.pd + +GUID Generation +--------------- + +These devices use the standard USB DeviceInstanceId values, e.g. + + * `USB\VID_1D5C&PID_7102&REV_0001` + * `USB\VID_1D5C&PID_7102` + * `USB\VID_1D5C` + +These devices also use custom GUID values, e.g. + + * `USB\VID_1D5C&PID_7102&CID_01` + +Vendor ID Security +------------------ + +The vendor ID is set from the USB vendor, in this instance set to `USB:0x1D5C` diff --git a/plugins/fresco-pd/fresco-pd.quirk b/plugins/fresco-pd/fresco-pd.quirk new file mode 100644 index 000000000..b8cfd9341 --- /dev/null +++ b/plugins/fresco-pd/fresco-pd.quirk @@ -0,0 +1,7 @@ +# FL7102 +[Guid=USB\VID_1D5C&PID_7102] +Plugin = fresco_pd + +# FL7112 +[Guid=USB\VID_1D5C&PID_7112] +Plugin = fresco_pd diff --git a/plugins/fresco-pd/fu-fresco-pd-common.c b/plugins/fresco-pd/fu-fresco-pd-common.c new file mode 100644 index 000000000..3070a78cf --- /dev/null +++ b/plugins/fresco-pd/fu-fresco-pd-common.c @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2020 Fresco Logic + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-fresco-pd-common.h" + +gchar * +fu_fresco_pd_version_from_buf (const guint8 ver[4]) +{ + if (ver[3] == 1 || ver[3] == 2) + return g_strdup_printf ("%u.%u.%u.%u", ver[0], ver[1], ver[2], ver[3]); + return g_strdup_printf ("%u.%u.%u.%u", ver[3], ver[1], ver[2], ver[0]); +} diff --git a/plugins/fresco-pd/fu-fresco-pd-common.h b/plugins/fresco-pd/fu-fresco-pd-common.h new file mode 100644 index 000000000..8d742be48 --- /dev/null +++ b/plugins/fresco-pd/fu-fresco-pd-common.h @@ -0,0 +1,12 @@ +/* + * Copyright (C) 2020 Fresco Logic + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include "fu-plugin.h" + +gchar *fu_fresco_pd_version_from_buf (const guint8 ver[4]); diff --git a/plugins/fresco-pd/fu-fresco-pd-device.c b/plugins/fresco-pd/fu-fresco-pd-device.c new file mode 100644 index 000000000..5649440b9 --- /dev/null +++ b/plugins/fresco-pd/fu-fresco-pd-device.c @@ -0,0 +1,417 @@ +/* + * Copyright (C) 2020 Fresco Logic + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-fresco-pd-common.h" +#include "fu-fresco-pd-device.h" +#include "fu-fresco-pd-firmware.h" + +struct _FuFrescoPdDevice +{ + FuUsbDevice parent_instance; + guint8 customer_id; +}; + +G_DEFINE_TYPE (FuFrescoPdDevice, fu_fresco_pd_device, FU_TYPE_USB_DEVICE) + +static void +fu_fresco_pd_device_to_string (FuDevice *device, guint idt, GString *str) +{ + FuFrescoPdDevice *self = FU_FRESCO_PD_DEVICE (device); + fu_common_string_append_ku (str, idt, "CustomerID", self->customer_id); +} + +static gboolean +fu_fresco_pd_device_transfer_read (FuFrescoPdDevice *self, + guint16 offset, + guint8 *buf, + guint16 bufsz, + GError **error) +{ + GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (self)); + gsize actual_length = 0; + + g_return_val_if_fail (buf != NULL, FALSE); + g_return_val_if_fail (bufsz != 0, FALSE); + + /* to device */ + if (g_getenv ("FWUPD_FRESCO_PD_VERBOSE") != NULL) + fu_common_dump_raw (G_LOG_DOMAIN, "read", buf, bufsz); + 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, + 0x40, 0x0, offset, + buf, bufsz, &actual_length, + 5000, NULL, error)) { + g_prefix_error (error, "failed to read from offset 0x%x: ", offset); + return FALSE; + } + if (bufsz != actual_length) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "read 0x%x bytes of 0x%x", + (guint) actual_length, bufsz); + return FALSE; + } + + /* success */ + return TRUE; +} + +static gboolean +fu_fresco_pd_device_transfer_write (FuFrescoPdDevice *self, + guint16 offset, + guint8 *buf, + guint16 bufsz, + GError **error) +{ + GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (self)); + gsize actual_length = 0; + + g_return_val_if_fail (buf != NULL, FALSE); + g_return_val_if_fail (bufsz != 0, FALSE); + + /* to device */ + if (g_getenv ("FWUPD_FRESCO_PD_VERBOSE") != NULL) + fu_common_dump_raw (G_LOG_DOMAIN, "write", 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, + 0x41, 0x0, offset, + buf, bufsz, &actual_length, + 5000, NULL, error)) { + g_prefix_error (error, "failed to write offset 0x%x: ", offset); + return FALSE; + } + if (bufsz != actual_length) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "wrote 0x%x bytes of 0x%x", + (guint) actual_length, bufsz); + return FALSE; + } + + /* success */ + return TRUE; +} + +static gboolean +fu_fresco_pd_device_read_byte (FuFrescoPdDevice *self, + guint16 offset, + guint8 *buf, + GError **error) +{ + return fu_fresco_pd_device_transfer_read (self, offset, buf, 1, error); +} + +static gboolean +fu_fresco_pd_device_write_byte (FuFrescoPdDevice *self, + guint16 offset, + guint8 buf, + GError **error) +{ + return fu_fresco_pd_device_transfer_write (self, offset, &buf, 1, error); +} + +static gboolean +fu_fresco_pd_device_set_byte (FuFrescoPdDevice *self, + guint16 offset, + guint8 val, + GError **error) +{ + guint8 buf = 0x0; + if (!fu_fresco_pd_device_read_byte (self, offset, &buf, error)) + return FALSE; + if (buf == val) + return TRUE; + return fu_fresco_pd_device_write_byte (self, offset, val, error); +} + +static gboolean +fu_fresco_pd_device_and_byte (FuFrescoPdDevice *self, + guint16 offset, + guint8 val, + GError **error) +{ + guint8 buf = 0xff; + if (!fu_fresco_pd_device_read_byte (self, offset, &buf, error)) + return FALSE; + buf &= val; + return fu_fresco_pd_device_write_byte (self, offset, buf, error); +} + +static gboolean +fu_fresco_pd_device_or_byte (FuFrescoPdDevice *self, + guint16 offset, + guint8 val, + GError **error) +{ + guint8 buf; + if (!fu_fresco_pd_device_read_byte (self, offset, &buf, error)) + return FALSE; + buf |= val; + return fu_fresco_pd_device_write_byte (self, offset, buf, error); +} + +static gboolean +fu_fresco_pd_device_setup (FuDevice *device, GError **error) +{ + FuFrescoPdDevice *self = FU_FRESCO_PD_DEVICE (device); + FuUsbDevice *usb_device = FU_USB_DEVICE (device); + guint8 ver[4] = { 0x0 }; + g_autofree gchar *instance_id = NULL; + g_autofree gchar *version = NULL; + + /* read existing device version */ + for (guint i = 0; i < 4; i++) { + if (!fu_fresco_pd_device_transfer_read (self, 0x3000 + i, &ver[i], 1, error)) { + g_prefix_error (error, "failed to read device version [%u]: ", i); + return FALSE; + } + } + version = fu_fresco_pd_version_from_buf (ver); + fu_device_set_version (FU_DEVICE (self), version, FWUPD_VERSION_FORMAT_QUAD); + + /* get customer ID */ + self->customer_id = ver[1]; + instance_id = g_strdup_printf ("USB\\VID_%04X&PID_%04X&CID_%02X", + fu_usb_device_get_vid (usb_device), + fu_usb_device_get_pid (usb_device), + self->customer_id); + fu_device_add_instance_id (device, instance_id); + + /* success */ + return TRUE; +} + +static FuFirmware * +fu_fresco_pd_device_prepare_firmware (FuDevice *device, + GBytes *fw, + FwupdInstallFlags flags, + GError **error) +{ + FuFrescoPdDevice *self = FU_FRESCO_PD_DEVICE (device); + guint8 customer_id; + g_autoptr(FuFirmware) firmware = fu_fresco_pd_firmware_new (); + + /* check size */ + if (g_bytes_get_size (fw) < fu_device_get_firmware_size_min (device)) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "firmware too small, got 0x%x, expected >= 0x%x", + (guint) g_bytes_get_size (fw), + (guint) fu_device_get_firmware_size_min (device)); + return NULL; + } + + /* check firmware is suitable */ + fu_device_set_status (device, FWUPD_STATUS_DECOMPRESSING); + if (!fu_firmware_parse (firmware, fw, flags, error)) + return NULL; + customer_id = fu_fresco_pd_firmware_get_customer_id (FU_FRESCO_PD_FIRMWARE (firmware)); + if (customer_id != self->customer_id) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "device is incompatible with firmware x.%u.x.x", + customer_id); + return NULL; + } + return g_steal_pointer (&firmware); +} + +static gboolean +fu_fresco_pd_device_panther_reset_device (FuFrescoPdDevice *self, GError **error) +{ + g_autoptr(GError) error_local = NULL; + + g_debug ("resetting target device"); + fu_device_set_status (FU_DEVICE (self), FWUPD_STATUS_DEVICE_RESTART); + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG); + + /* ignore when the device reset before completing the transaction */ + if (!fu_fresco_pd_device_or_byte (self, 0xA003, 1 << 3, &error_local)) { + if (g_error_matches (error_local, + G_USB_DEVICE_ERROR, + G_USB_DEVICE_ERROR_FAILED)) { + g_debug ("ignoring %s", error_local->message); + return TRUE; + } + g_propagate_prefixed_error (error, g_steal_pointer (&error_local), + "failed to reset device [%i]", + error_local->code); + return FALSE; + } + return TRUE; +} + +static gboolean +fu_fresco_pd_device_write_firmware (FuDevice *device, + FuFirmware *firmware, + FwupdInstallFlags flags, + GError **error) +{ + FuFrescoPdDevice *self = FU_FRESCO_PD_DEVICE (device); + const guint8 *buf; + gsize bufsz = 0x0; + guint16 begin_addr = 0x6420; + guint8 config[3] = { 0x0 }; + guint8 start_symbols[2] = { 0x0 }; + g_autoptr(GBytes) fw = NULL; + + /* get default blob, which we know is already bigger than FirmwareMin */ + fw = fu_firmware_get_image_default_bytes (firmware, error); + if (fw == NULL) + return FALSE; + buf = g_bytes_get_data (fw, &bufsz); + + /* get start symbols, and be slightly paranoid */ + if (!fu_memcpy_safe (start_symbols, sizeof(start_symbols), 0x0, /* dst */ + buf, bufsz, 0x4000, /* src */ + sizeof(start_symbols), error)) + return FALSE; + + /* 0xA001 = b'0 + * 0x6C00 = b'0 + * 0x6C04 = 0x08 */ + fu_device_set_status (device, FWUPD_STATUS_DEVICE_BUSY); + g_debug ("disable MCU, and enable mtp write"); + if (!fu_fresco_pd_device_and_byte (self, 0xa001, ~(1 << 2), error)) { + g_prefix_error (error, "failed to disable MCU bit 2: "); + return FALSE; + } + if (!fu_fresco_pd_device_and_byte (self, 0x6c00, ~(1 << 1), error)) { + g_prefix_error (error, "failed to disable MCU bit 1: "); + return FALSE; + } + if (!fu_fresco_pd_device_write_byte (self, 0x6c04, 0x08, error)) { + g_prefix_error (error, "failed to disable MCU: "); + return FALSE; + } + + /* fill safe code in the boot code */ + fu_device_set_status (device, FWUPD_STATUS_DEVICE_WRITE); + for (guint16 i = 0; i < 0x400; i += 3) { + for (guint j = 0; j < 3; j++) { + if (!fu_fresco_pd_device_read_byte (self, + begin_addr + i + j, + &config[j], + error)) { + g_prefix_error (error, "failed to read config byte %u: ", j); + return FALSE; + } + } + if (config[0] == start_symbols[0] && + config[1] == start_symbols[1]) { + begin_addr = 0x6420 + i; + break; + } + if (config[0] == 0 && config[1] == 0 && config[2] == 0) + break; + } + g_debug ("begin_addr: 0x%04x", begin_addr); + for (guint16 i = begin_addr + 3; i < begin_addr + 0x400; i += 3) { + for (guint j = 0; j < 3; j++) { + if (!fu_fresco_pd_device_read_byte (self, i + j, &config[j], error)) { + g_prefix_error (error, "failed to read config byte %u: ", j); + return FALSE; + } + } + if (config[0] == 0x74 && config[1] == 0x06 && config[2] != 0x22) { + if (!fu_fresco_pd_device_write_byte (self, i + 2, 0x22, error)) + return FALSE; + } else if (config[0] == 0x6c && config[1] == 0x00 && config[2] != 0x01) { + if (!fu_fresco_pd_device_write_byte (self, i + 2, 0x01, error)) + return FALSE; + } else if (config[0] == 0x00 && config[1] == 0x00 && config[2] != 0x00) + break; + } + + /* copy buf offset [0 - 0x3FFFF] to mmio address [0x2000 - 0x5FFF] */ + g_debug ("fill firmware body"); + for (guint16 byte_index = 0; byte_index < 0x4000; byte_index++) { + if (!fu_fresco_pd_device_set_byte (self, byte_index + 0x2000, buf[byte_index], error)) + return FALSE; + fu_device_set_progress_full (device, (gsize) byte_index, 0x4000); + } + + /* write file buf 0x4200 ~ 0x4205, 6 bytes to internal address 0x6600 ~ 0x6605 + * write file buf 0x4210 ~ 0x4215, 6 bytes to internal address 0x6610 ~ 0x6615 + * write file buf 0x4220 ~ 0x4225, 6 bytes to internal address 0x6620 ~ 0x6625 + * write file buf 0x4230, 1 byte, to internal address 0x6630 */ + g_debug ("update customize data"); + for (guint16 byte_index = 0; byte_index < 6; byte_index++) { + if (!fu_fresco_pd_device_set_byte (self, + 0x6600 + byte_index, + buf[0x4200 + byte_index], + error)) + return FALSE; + if (!fu_fresco_pd_device_set_byte (self, + 0x6610 + byte_index, + buf[0x4210 + byte_index], + error)) + return FALSE; + if (!fu_fresco_pd_device_set_byte (self, + 0x6620 + byte_index, + buf[0x4220 + byte_index], + error)) + return FALSE; + } + if (!fu_fresco_pd_device_set_byte (self, 0x6630, buf[0x4230], error)) + return FALSE; + + /* overwrite firmware file's boot code area (0x4020 ~ 0x41ff) to the area on the device marked by begin_addr + * example: if the begin_addr = 0x6420, then copy file buf [0x4020 ~ 0x41ff] to device offset[0x6420 ~ 0x65ff] */ + g_debug ("write boot configuration area"); + for (guint16 byte_index = 0; byte_index < 0x1e0; byte_index += 3) { + if (!fu_fresco_pd_device_set_byte (self, + begin_addr + byte_index + 0, + buf[0x4020 + byte_index], + error)) + return FALSE; + if (!fu_fresco_pd_device_set_byte (self, + begin_addr + byte_index + 1, + buf[0x4021 + byte_index], + error)) + return FALSE; + if (!fu_fresco_pd_device_set_byte (self, + begin_addr + byte_index + 2, + buf[0x4022 + byte_index], + error)) + return FALSE; + } + + /* reset the device */ + return fu_fresco_pd_device_panther_reset_device (self, error); +} + +static void +fu_fresco_pd_device_init (FuFrescoPdDevice *self) +{ + fu_device_add_icon (FU_DEVICE (self), "audio-card"); + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_UPDATABLE); + fu_device_set_protocol (FU_DEVICE (self), "com.frescologic.pd"); + fu_device_set_install_duration (FU_DEVICE (self), 15); + fu_device_set_remove_delay (FU_DEVICE (self), 20000); + fu_device_set_firmware_size (FU_DEVICE (self), 0x4400); +} + +static void +fu_fresco_pd_device_class_init (FuFrescoPdDeviceClass *klass) +{ + FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); + klass_device->to_string = fu_fresco_pd_device_to_string; + klass_device->setup = fu_fresco_pd_device_setup; + klass_device->write_firmware = fu_fresco_pd_device_write_firmware; + klass_device->prepare_firmware = fu_fresco_pd_device_prepare_firmware; +} diff --git a/plugins/fresco-pd/fu-fresco-pd-device.h b/plugins/fresco-pd/fu-fresco-pd-device.h new file mode 100644 index 000000000..aff0da4e5 --- /dev/null +++ b/plugins/fresco-pd/fu-fresco-pd-device.h @@ -0,0 +1,17 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include "fu-plugin.h" + +#define FU_TYPE_FRESCO_PD_DEVICE (fu_fresco_pd_device_get_type ()) +G_DECLARE_FINAL_TYPE (FuFrescoPdDevice, fu_fresco_pd_device, FU, FRESCO_PD_DEVICE, FuUsbDevice) + +struct _FuFrescoPdDeviceClass +{ + FuUsbDeviceClass parent_class; +}; diff --git a/plugins/fresco-pd/fu-fresco-pd-firmware.c b/plugins/fresco-pd/fu-fresco-pd-firmware.c new file mode 100644 index 000000000..beab8fa94 --- /dev/null +++ b/plugins/fresco-pd/fu-fresco-pd-firmware.c @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2020 Fresco Logic + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-fresco-pd-common.h" +#include "fu-fresco-pd-firmware.h" + +struct _FuFrescoPdFirmware { + FuFirmwareClass parent_instance; + guint8 customer_id; +}; + +G_DEFINE_TYPE (FuFrescoPdFirmware, fu_fresco_pd_firmware, FU_TYPE_FIRMWARE) + +guint8 +fu_fresco_pd_firmware_get_customer_id (FuFrescoPdFirmware *self) +{ + return self->customer_id; +} + +static void +fu_fresco_pd_firmware_to_string (FuFirmware *firmware, guint idt, GString *str) +{ + FuFrescoPdFirmware *self = FU_FRESCO_PD_FIRMWARE (firmware); + fu_common_string_append_ku (str, idt, "CustomerID", self->customer_id); +} + +static gboolean +fu_fresco_pd_firmware_parse (FuFirmware *firmware, + GBytes *fw, + guint64 addr_start, + guint64 addr_end, + FwupdInstallFlags flags, + GError **error) +{ + FuFrescoPdFirmware *self = FU_FRESCO_PD_FIRMWARE (firmware); + guint8 ver[4] = { 0x0 }; + gsize bufsz = 0; + const guint8 *buf = g_bytes_get_data (fw, &bufsz); + g_autofree gchar *version = NULL; + g_autoptr(FuFirmwareImage) img = fu_firmware_image_new (fw); + + /* read version block */ + if (!fu_memcpy_safe (ver, sizeof(ver), 0x0, /* dst */ + buf, bufsz, 0x1000, /* src */ + sizeof(ver), error)) + return FALSE; + + /* customer ID is always the 2nd byte */ + self->customer_id = ver[1]; + + /* set version number */ + version = fu_fresco_pd_version_from_buf (ver); + fu_firmware_image_set_version (img, version); + fu_firmware_add_image (firmware, img); + return TRUE; +} + +static void +fu_fresco_pd_firmware_init (FuFrescoPdFirmware *self) +{ +} + +static void +fu_fresco_pd_firmware_class_init (FuFrescoPdFirmwareClass *klass) +{ + FuFirmwareClass *klass_firmware = FU_FIRMWARE_CLASS (klass); + klass_firmware->parse = fu_fresco_pd_firmware_parse; + klass_firmware->to_string = fu_fresco_pd_firmware_to_string; +} + +FuFirmware * +fu_fresco_pd_firmware_new (void) +{ + return FU_FIRMWARE (g_object_new (FU_TYPE_FRESCO_PD_FIRMWARE, NULL)); +} diff --git a/plugins/fresco-pd/fu-fresco-pd-firmware.h b/plugins/fresco-pd/fu-fresco-pd-firmware.h new file mode 100644 index 000000000..675c41be3 --- /dev/null +++ b/plugins/fresco-pd/fu-fresco-pd-firmware.h @@ -0,0 +1,16 @@ +/* + * Copyright (C) 2020 Fresco Logic + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include "fu-firmware.h" + +#define FU_TYPE_FRESCO_PD_FIRMWARE (fu_fresco_pd_firmware_get_type ()) +G_DECLARE_FINAL_TYPE (FuFrescoPdFirmware, fu_fresco_pd_firmware, FU, FRESCO_PD_FIRMWARE, FuFirmware) + +FuFirmware *fu_fresco_pd_firmware_new (void); +guint8 fu_fresco_pd_firmware_get_customer_id (FuFrescoPdFirmware *self); diff --git a/plugins/fresco-pd/fu-plugin-fresco-pd.c b/plugins/fresco-pd/fu-plugin-fresco-pd.c new file mode 100644 index 000000000..88fd54730 --- /dev/null +++ b/plugins/fresco-pd/fu-plugin-fresco-pd.c @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-plugin-vfuncs.h" +#include "fu-hash.h" + +#include "fu-fresco-pd-device.h" +#include "fu-fresco-pd-firmware.h" + +void +fu_plugin_init (FuPlugin *plugin) +{ + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); + fu_plugin_set_device_gtype (plugin, FU_TYPE_FRESCO_PD_DEVICE); + fu_plugin_add_firmware_gtype (plugin, "fresco-pd", FU_TYPE_FRESCO_PD_FIRMWARE); +} diff --git a/plugins/fresco-pd/lsusb.txt b/plugins/fresco-pd/lsusb.txt new file mode 100644 index 000000000..e91fb4c9b --- /dev/null +++ b/plugins/fresco-pd/lsusb.txt @@ -0,0 +1,72 @@ +Bus 003 Device 002: ID 1d5c:7102 Fresco Logic Generic Billboard Device +Device Descriptor: + bLength 18 + bDescriptorType 1 + bcdUSB 2.01 + bDeviceClass 17 + bDeviceSubClass 0 + bDeviceProtocol 0 + bMaxPacketSize0 64 + idVendor 0x1d5c Fresco Logic + idProduct 0x7102 + bcdDevice 1.00 + iManufacturer 1 Fresco Logic, Inc + iProduct 2 Generic Billboard Device + iSerial 0 + bNumConfigurations 1 + Configuration Descriptor: + bLength 9 + bDescriptorType 2 + wTotalLength 0x0012 + bNumInterfaces 1 + bConfigurationValue 1 + iConfiguration 0 + bmAttributes 0xc0 + Self Powered + MaxPower 0mA + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 0 + bAlternateSetting 0 + bNumEndpoints 0 + bInterfaceClass 17 + bInterfaceSubClass 0 + bInterfaceProtocol 0 + iInterface 0 +Binary Object Store Descriptor: + bLength 5 + bDescriptorType 15 + wTotalLength 0x0050 + bNumDeviceCaps 3 + USB 2.0 Extension Device Capability: + bLength 7 + bDescriptorType 16 + bDevCapabilityType 2 + bmAttributes 0x00000006 + BESL Link Power Management (LPM) Supported + Container ID Device Capability: + bLength 20 + bDescriptorType 16 + bDevCapabilityType 4 + bReserved 0 + ContainerID {00000000-0000-0000-0000-000000000000} + Billboard Capability: + bLength 48 + bDescriptorType 16 + bDevCapabilityType 13 + iAddtionalInfoURL 4 www.frescologic.com + bNumberOfAlternateModes 1 + bPreferredAlternateMode 0 + VCONN Power 0 1W + bmConfigured 03 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + bcdVersion 1.10 + bAdditionalFailureInfo 0 + bReserved 0 + Alternate Modes supported by Device Container: + Alternate Mode 0 : Alternate Mode configuration successful + wSVID[0] 0x0000 + bAlternateMode[0] 0 + iAlternateModeString[0] 0 +Device Status: 0x0001 + Self Powered diff --git a/plugins/fresco-pd/meson.build b/plugins/fresco-pd/meson.build new file mode 100644 index 000000000..7425156ee --- /dev/null +++ b/plugins/fresco-pd/meson.build @@ -0,0 +1,30 @@ +cargs = ['-DG_LOG_DOMAIN="FuPluginFrescoPd"'] + +install_data(['fresco-pd.quirk'], + install_dir: join_paths(datadir, 'fwupd', 'quirks.d') +) + +shared_module('fu_plugin_fresco_pd', + fu_hash, + sources : [ + 'fu-plugin-fresco-pd.c', + 'fu-fresco-pd-common.c', + 'fu-fresco-pd-device.c', + 'fu-fresco-pd-firmware.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, + ], +) diff --git a/plugins/meson.build b/plugins/meson.build index 9dfa1bc76..3fad95b53 100644 --- a/plugins/meson.build +++ b/plugins/meson.build @@ -2,6 +2,7 @@ subdir('dfu') subdir('colorhug') subdir('ebitdo') subdir('fastboot') +subdir('fresco-pd') subdir('jabra') subdir('steelseries') subdir('dell-dock')