mirror of
https://git.proxmox.com/git/fwupd
synced 2025-08-16 05:47:16 +00:00
ccgx: Detect factory mode and set a non-zero version
The Element Hub (and several other docks that use the CCGX5 DMC reference design) is in "factory mode" out of the box, displaying a version of `0.0.0.0` Detect factory mode and set a non-zero version -- using the "real" version if possible by matching the CCG5 devx base firmware firmware.
This commit is contained in:
parent
57282a5903
commit
58cbb15e64
@ -108,8 +108,18 @@ This plugin uses the following plugin-specific quirks:
|
|||||||
DMC devices need a specified trigger code to request the device to update
|
DMC devices need a specified trigger code to request the device to update
|
||||||
the firmware and the trigger code depends on the devices.
|
the firmware and the trigger code depends on the devices.
|
||||||
|
|
||||||
|
0x0: Do not update
|
||||||
|
0x1: Update immediately
|
||||||
|
0x2: Update after port disconnected
|
||||||
|
|
||||||
Since: 1.8.0
|
Since: 1.8.0
|
||||||
|
|
||||||
|
### CcgxDmcCompositeVersion
|
||||||
|
|
||||||
|
Set the parent composite version, as a 32 bit integer.
|
||||||
|
|
||||||
|
Since: 1.8.11
|
||||||
|
|
||||||
## External Interface Access
|
## External Interface Access
|
||||||
|
|
||||||
This plugin requires read/write access to `/dev/bus/usb`.
|
This plugin requires read/write access to `/dev/bus/usb`.
|
||||||
|
@ -19,3 +19,115 @@ fu_ccgx_dmc_update_model_type_to_string(DmcUpdateModel val)
|
|||||||
return "Pending Reset";
|
return "Pending Reset";
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const gchar *
|
||||||
|
fu_ccgx_dmc_devx_device_type_to_string(DmcDevxDeviceType device_type)
|
||||||
|
{
|
||||||
|
if (device_type == DMC_DEVX_DEVICE_TYPE_INVALID)
|
||||||
|
return "invalid";
|
||||||
|
if (device_type == DMC_DEVX_DEVICE_TYPE_CCG3)
|
||||||
|
return "ccg3";
|
||||||
|
if (device_type == DMC_DEVX_DEVICE_TYPE_DMC)
|
||||||
|
return "dmc";
|
||||||
|
if (device_type == DMC_DEVX_DEVICE_TYPE_CCG4)
|
||||||
|
return "ccg4";
|
||||||
|
if (device_type == DMC_DEVX_DEVICE_TYPE_CCG5)
|
||||||
|
return "ccg5";
|
||||||
|
if (device_type == DMC_DEVX_DEVICE_TYPE_HX3)
|
||||||
|
return "hx3";
|
||||||
|
if (device_type == DMC_DEVX_DEVICE_TYPE_HX3_PD)
|
||||||
|
return "hx3-pd";
|
||||||
|
if (device_type == DMC_DEVX_DEVICE_TYPE_DMC_PD)
|
||||||
|
return "dmc-pd";
|
||||||
|
if (device_type == DMC_DEVX_DEVICE_TYPE_SPI)
|
||||||
|
return "spi";
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
const gchar *
|
||||||
|
fu_ccgx_dmc_img_mode_to_string(DmcImgMode img_mode)
|
||||||
|
{
|
||||||
|
if (img_mode == DMC_IMG_MODE_SINGLE_IMG)
|
||||||
|
return "single";
|
||||||
|
if (img_mode == DMC_IMG_MODE_DUAL_IMG_SYM)
|
||||||
|
return "dual-sym";
|
||||||
|
if (img_mode == DMC_IMG_MODE_DUAL_IMG_ASYM)
|
||||||
|
return "dual-asym";
|
||||||
|
if (img_mode == DMC_IMG_MODE_SINGLE_IMG_WITH_RAM_IMG)
|
||||||
|
return "single-with-ram-img";
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
const gchar *
|
||||||
|
fu_ccgx_dmc_device_status_to_string(DmcDeviceStatus device_status)
|
||||||
|
{
|
||||||
|
if (device_status == DMC_DEVICE_STATUS_IDLE)
|
||||||
|
return "idle";
|
||||||
|
if (device_status == DMC_DEVICE_STATUS_UPDATE_IN_PROGRESS)
|
||||||
|
return "update-in-progress";
|
||||||
|
if (device_status == DMC_DEVICE_STATUS_UPDATE_PARTIAL)
|
||||||
|
return "update-partial";
|
||||||
|
if (device_status == DMC_DEVICE_STATUS_UPDATE_COMPLETE_FULL)
|
||||||
|
return "update-complete-full";
|
||||||
|
if (device_status == DMC_DEVICE_STATUS_UPDATE_COMPLETE_PARTIAL)
|
||||||
|
return "update-complete-partial";
|
||||||
|
if (device_status == DMC_DEVICE_STATUS_UPDATE_PHASE_1_COMPLETE)
|
||||||
|
return "update-phase1-complete";
|
||||||
|
if (device_status == DMC_DEVICE_STATUS_FW_DOWNLOADED_UPDATE_PEND)
|
||||||
|
return "fw-downloaded-update-pend";
|
||||||
|
if (device_status == DMC_DEVICE_STATUS_FW_DOWNLOADED_PARTIAL_UPDATE_PEND)
|
||||||
|
return "fw-downloaded-partial-update-pend";
|
||||||
|
if (device_status == DMC_DEVICE_STATUS_PHASE2_UPDATE_IN_PROGRESS)
|
||||||
|
return "phase2-update-in-progress";
|
||||||
|
if (device_status == DMC_DEVICE_STATUS_PHASE2_UPDATE_PARTIAL)
|
||||||
|
return "phase2-update-partial";
|
||||||
|
if (device_status == DMC_DEVICE_STATUS_PHASE2_UPDATE_FACTORY_BACKUP)
|
||||||
|
return "phase2-update-factory-backup";
|
||||||
|
if (device_status == DMC_DEVICE_STATUS_PHASE2_UPDATE_COMPLETE_PARTIAL)
|
||||||
|
return "phase2-update-complete-partial";
|
||||||
|
if (device_status == DMC_DEVICE_STATUS_PHASE2_UPDATE_COMPLETE_FULL)
|
||||||
|
return "phase2-update-complete-full";
|
||||||
|
if (device_status == DMC_DEVICE_STATUS_PHASE2_UPDATE_FAIL_INVALID_FWCT)
|
||||||
|
return "phase2-update-fail-invalid-fwct";
|
||||||
|
if (device_status == DMC_DEVICE_STATUS_PHASE2_UPDATE_FAIL_INVALID_DOCK_IDENTITY)
|
||||||
|
return "phase2-update-fail-invalid-dock-identifier";
|
||||||
|
if (device_status == DMC_DEVICE_STATUS_PHASE2_UPDATE_FAIL_INVALID_COMPOSITE_VER)
|
||||||
|
return "phase2-update-fail-invalid-composite-ver";
|
||||||
|
if (device_status == DMC_DEVICE_STATUS_PHASE2_UPDATE_FAIL_AUTHENTICATION_FAILED)
|
||||||
|
return "phase2-update-fail-authentication-failed";
|
||||||
|
if (device_status == DMC_DEVICE_STATUS_PHASE2_UPDATE_FAIL_INVALID_ALGORITHM)
|
||||||
|
return "phase2-update-fail-invalid-algorithm";
|
||||||
|
if (device_status == DMC_DEVICE_STATUS_PHASE2_UPDATE_FAIL_SPI_READ_FAILED)
|
||||||
|
return "phase2-update-fail-spi-read-failed";
|
||||||
|
if (device_status == DMC_DEVICE_STATUS_PHASE2_UPDATE_FAIL_NO_VALID_KEY)
|
||||||
|
return "phase2-update-fail-no-valid-key";
|
||||||
|
if (device_status == DMC_DEVICE_STATUS_PHASE2_UPDATE_FAIL_NO_VALID_SPI_PACKAGE)
|
||||||
|
return "phase2-update-fail-no-valid-spi-package";
|
||||||
|
if (device_status == DMC_DEVICE_STATUS_PHASE2_UPDATE_FAIL_RAM_INIT_FAILED)
|
||||||
|
return "phase2-update-fail-ram-init-failed";
|
||||||
|
if (device_status == DMC_DEVICE_STATUS_PHASE2_UPDATE_FAIL_FACTORY_BACKUP_FAILED)
|
||||||
|
return "phase2-update-fail-factory-backup-failed";
|
||||||
|
if (device_status == DMC_DEVICE_STATUS_PHASE2_UPDATE_FAIL_NO_VALID_FACTORY_PACKAGE)
|
||||||
|
return "phase2-update-fail-no-valid-factory-package";
|
||||||
|
if (device_status == DMC_DEVICE_STATUS_UPDATE_FAIL)
|
||||||
|
return "update-fail";
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
const gchar *
|
||||||
|
fu_ccgx_dmc_img_status_to_string(DmcImgStatus img_status)
|
||||||
|
{
|
||||||
|
if (img_status == DMC_IMG_STATUS_UNKNOWN)
|
||||||
|
return "unknown";
|
||||||
|
if (img_status == DMC_IMG_STATUS_VALID)
|
||||||
|
return "valid";
|
||||||
|
if (img_status == DMC_IMG_STATUS_INVALID)
|
||||||
|
return "invalid";
|
||||||
|
if (img_status == DMC_IMG_STATUS_RECOVERY)
|
||||||
|
return "recovery";
|
||||||
|
if (img_status == DMC_IMG_STATUS_RECOVERED_FROM_SECONDARY)
|
||||||
|
return "recovered-from-secondary";
|
||||||
|
if (img_status == DMC_IMG_STATUS_NOT_SUPPORTED)
|
||||||
|
return "not-supported";
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
@ -80,6 +80,7 @@ typedef enum {
|
|||||||
* image. Secondary acts as recovery */
|
* image. Secondary acts as recovery */
|
||||||
DMC_IMG_MODE_DUAL_IMG_ASYM,
|
DMC_IMG_MODE_DUAL_IMG_ASYM,
|
||||||
DMC_IMG_MODE_SINGLE_IMG_WITH_RAM_IMG,
|
DMC_IMG_MODE_SINGLE_IMG_WITH_RAM_IMG,
|
||||||
|
DMC_IMG_MODE_LAST
|
||||||
} DmcImgMode;
|
} DmcImgMode;
|
||||||
|
|
||||||
/* this data type enumerates the dock status */
|
/* this data type enumerates the dock status */
|
||||||
@ -121,6 +122,18 @@ typedef enum {
|
|||||||
DMC_DEVICE_STATUS_UPDATE_FAIL = 0xFF
|
DMC_DEVICE_STATUS_UPDATE_FAIL = 0xFF
|
||||||
} DmcDeviceStatus;
|
} DmcDeviceStatus;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
DMC_DEVX_DEVICE_TYPE_INVALID = 0x00,
|
||||||
|
DMC_DEVX_DEVICE_TYPE_CCG3 = 0x01,
|
||||||
|
DMC_DEVX_DEVICE_TYPE_DMC = 0x02,
|
||||||
|
DMC_DEVX_DEVICE_TYPE_CCG4 = 0x03,
|
||||||
|
DMC_DEVX_DEVICE_TYPE_CCG5 = 0x04,
|
||||||
|
DMC_DEVX_DEVICE_TYPE_HX3 = 0x05,
|
||||||
|
DMC_DEVX_DEVICE_TYPE_HX3_PD = 0x0A,
|
||||||
|
DMC_DEVX_DEVICE_TYPE_DMC_PD = 0x0B,
|
||||||
|
DMC_DEVX_DEVICE_TYPE_SPI = 0xFF
|
||||||
|
} DmcDevxDeviceType;
|
||||||
|
|
||||||
/* this data type enumerates the request codes for vendor interface */
|
/* this data type enumerates the request codes for vendor interface */
|
||||||
typedef enum {
|
typedef enum {
|
||||||
DMC_RQT_CODE_UPGRADE_START = 0xD0,
|
DMC_RQT_CODE_UPGRADE_START = 0xD0,
|
||||||
@ -282,3 +295,11 @@ typedef struct __attribute__((packed)) {
|
|||||||
|
|
||||||
const gchar *
|
const gchar *
|
||||||
fu_ccgx_dmc_update_model_type_to_string(DmcUpdateModel val);
|
fu_ccgx_dmc_update_model_type_to_string(DmcUpdateModel val);
|
||||||
|
const gchar *
|
||||||
|
fu_ccgx_dmc_device_status_to_string(DmcDeviceStatus device_status);
|
||||||
|
const gchar *
|
||||||
|
fu_ccgx_dmc_devx_device_type_to_string(DmcDevxDeviceType device_type);
|
||||||
|
const gchar *
|
||||||
|
fu_ccgx_dmc_img_status_to_string(DmcImgStatus img_status);
|
||||||
|
const gchar *
|
||||||
|
fu_ccgx_dmc_img_mode_to_string(DmcImgMode img_mode);
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
#include "fu-ccgx-common.h"
|
#include "fu-ccgx-common.h"
|
||||||
#include "fu-ccgx-dmc-common.h"
|
#include "fu-ccgx-dmc-common.h"
|
||||||
#include "fu-ccgx-dmc-device.h"
|
#include "fu-ccgx-dmc-device.h"
|
||||||
|
#include "fu-ccgx-dmc-devx-device.h"
|
||||||
#include "fu-ccgx-dmc-firmware.h"
|
#include "fu-ccgx-dmc-firmware.h"
|
||||||
|
|
||||||
#define DMC_FW_WRITE_STATUS_RETRY_COUNT 3
|
#define DMC_FW_WRITE_STATUS_RETRY_COUNT 3
|
||||||
@ -21,6 +22,7 @@ struct _FuCcgxDmcDevice {
|
|||||||
FuUsbDevice parent_instance;
|
FuUsbDevice parent_instance;
|
||||||
FWImageType fw_image_type;
|
FWImageType fw_image_type;
|
||||||
DmcDockIdentity dock_id;
|
DmcDockIdentity dock_id;
|
||||||
|
DmcDockStatus dock_status;
|
||||||
guint8 ep_intr_in;
|
guint8 ep_intr_in;
|
||||||
guint8 ep_bulk_out;
|
guint8 ep_bulk_out;
|
||||||
DmcUpdateModel update_model;
|
DmcUpdateModel update_model;
|
||||||
@ -37,10 +39,8 @@ struct _FuCcgxDmcDevice {
|
|||||||
G_DEFINE_TYPE(FuCcgxDmcDevice, fu_ccgx_dmc_device, FU_TYPE_USB_DEVICE)
|
G_DEFINE_TYPE(FuCcgxDmcDevice, fu_ccgx_dmc_device, FU_TYPE_USB_DEVICE)
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
fu_ccgx_dmc_device_get_dock_id(FuCcgxDmcDevice *self, DmcDockIdentity *dock_id, GError **error)
|
fu_ccgx_dmc_device_ensure_dock_id(FuCcgxDmcDevice *self, GError **error)
|
||||||
{
|
{
|
||||||
g_return_val_if_fail(dock_id != NULL, FALSE);
|
|
||||||
|
|
||||||
if (!g_usb_device_control_transfer(fu_usb_device_get_dev(FU_USB_DEVICE(self)),
|
if (!g_usb_device_control_transfer(fu_usb_device_get_dev(FU_USB_DEVICE(self)),
|
||||||
G_USB_DEVICE_DIRECTION_DEVICE_TO_HOST,
|
G_USB_DEVICE_DIRECTION_DEVICE_TO_HOST,
|
||||||
G_USB_DEVICE_REQUEST_TYPE_VENDOR,
|
G_USB_DEVICE_REQUEST_TYPE_VENDOR,
|
||||||
@ -48,8 +48,8 @@ fu_ccgx_dmc_device_get_dock_id(FuCcgxDmcDevice *self, DmcDockIdentity *dock_id,
|
|||||||
DMC_RQT_CODE_DOCK_IDENTITY, /* request */
|
DMC_RQT_CODE_DOCK_IDENTITY, /* request */
|
||||||
0, /* value */
|
0, /* value */
|
||||||
0, /* index */
|
0, /* index */
|
||||||
(guint8 *)dock_id, /* data */
|
(guint8 *)&self->dock_id, /* data */
|
||||||
sizeof(DmcDockIdentity), /* length */
|
sizeof(self->dock_id), /* length */
|
||||||
NULL, /* actual length */
|
NULL, /* actual length */
|
||||||
DMC_CONTROL_TRANSFER_DEFAULT_TIMEOUT,
|
DMC_CONTROL_TRANSFER_DEFAULT_TIMEOUT,
|
||||||
NULL,
|
NULL,
|
||||||
@ -61,41 +61,37 @@ fu_ccgx_dmc_device_get_dock_id(FuCcgxDmcDevice *self, DmcDockIdentity *dock_id,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
fu_ccgx_dmc_device_get_dock_status(FuCcgxDmcDevice *self,
|
fu_ccgx_dmc_device_ensure_status(FuCcgxDmcDevice *self, GError **error)
|
||||||
DmcDockStatus *dock_status,
|
|
||||||
GError **error)
|
|
||||||
{
|
{
|
||||||
g_return_val_if_fail(dock_status != NULL, FALSE);
|
|
||||||
|
|
||||||
/* read minimum status length */
|
/* read minimum status length */
|
||||||
if (!g_usb_device_control_transfer(fu_usb_device_get_dev(FU_USB_DEVICE(self)),
|
if (!g_usb_device_control_transfer(fu_usb_device_get_dev(FU_USB_DEVICE(self)),
|
||||||
G_USB_DEVICE_DIRECTION_DEVICE_TO_HOST,
|
G_USB_DEVICE_DIRECTION_DEVICE_TO_HOST,
|
||||||
G_USB_DEVICE_REQUEST_TYPE_VENDOR,
|
G_USB_DEVICE_REQUEST_TYPE_VENDOR,
|
||||||
G_USB_DEVICE_RECIPIENT_DEVICE,
|
G_USB_DEVICE_RECIPIENT_DEVICE,
|
||||||
DMC_RQT_CODE_DOCK_STATUS, /* request */
|
DMC_RQT_CODE_DOCK_STATUS, /* request */
|
||||||
0, /* value */
|
0, /* value */
|
||||||
0, /* index */
|
0, /* index */
|
||||||
(guint8 *)dock_status, /* data */
|
(guint8 *)&self->dock_status, /* data */
|
||||||
DMC_GET_STATUS_MIN_LEN, /* length */
|
DMC_GET_STATUS_MIN_LEN, /* length */
|
||||||
NULL, /* actual length */
|
NULL, /* actual length */
|
||||||
DMC_CONTROL_TRANSFER_DEFAULT_TIMEOUT,
|
DMC_CONTROL_TRANSFER_DEFAULT_TIMEOUT,
|
||||||
NULL,
|
NULL,
|
||||||
error)) {
|
error)) {
|
||||||
g_prefix_error(error, "get_dock_status min size error: ");
|
g_prefix_error(error, "get_dock_status min size error: ");
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
if (dock_status->status_length <= sizeof(DmcDockStatus)) {
|
if (self->dock_status.status_length <= sizeof(self->dock_status)) {
|
||||||
/* read full status length */
|
/* read full status length */
|
||||||
if (!g_usb_device_control_transfer(fu_usb_device_get_dev(FU_USB_DEVICE(self)),
|
if (!g_usb_device_control_transfer(fu_usb_device_get_dev(FU_USB_DEVICE(self)),
|
||||||
G_USB_DEVICE_DIRECTION_DEVICE_TO_HOST,
|
G_USB_DEVICE_DIRECTION_DEVICE_TO_HOST,
|
||||||
G_USB_DEVICE_REQUEST_TYPE_VENDOR,
|
G_USB_DEVICE_REQUEST_TYPE_VENDOR,
|
||||||
G_USB_DEVICE_RECIPIENT_DEVICE,
|
G_USB_DEVICE_RECIPIENT_DEVICE,
|
||||||
DMC_RQT_CODE_DOCK_STATUS, /* request */
|
DMC_RQT_CODE_DOCK_STATUS, /* request */
|
||||||
0, /* value */
|
0, /* value */
|
||||||
0, /* index */
|
0, /* index */
|
||||||
(guint8 *)dock_status, /* data */
|
(guint8 *)&self->dock_status, /* data */
|
||||||
sizeof(DmcDockStatus), /* length */
|
sizeof(self->dock_status), /* length */
|
||||||
NULL, /* actual length */
|
NULL, /* actual length */
|
||||||
DMC_CONTROL_TRANSFER_DEFAULT_TIMEOUT,
|
DMC_CONTROL_TRANSFER_DEFAULT_TIMEOUT,
|
||||||
NULL,
|
NULL,
|
||||||
error)) {
|
error)) {
|
||||||
@ -103,6 +99,21 @@ fu_ccgx_dmc_device_get_dock_status(FuCcgxDmcDevice *self,
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (g_getenv("FWUPD_CCGX_VERBOSE") != NULL) {
|
||||||
|
fu_dump_raw(G_LOG_DOMAIN,
|
||||||
|
"DmcDockStatus",
|
||||||
|
(const guint8 *)&self->dock_status,
|
||||||
|
sizeof(self->dock_status));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* add devx children */
|
||||||
|
for (guint i = 0; i < self->dock_status.device_count; i++) {
|
||||||
|
g_autoptr(FuCcgxDmcDevxDevice) devx =
|
||||||
|
fu_ccgx_dmc_devx_device_new(FU_DEVICE(self), &self->dock_status.devx_status[i]);
|
||||||
|
fu_device_add_child(FU_DEVICE(self), FU_DEVICE(devx));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* success */
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -319,6 +330,13 @@ fu_ccgx_dmc_device_to_string(FuDevice *device, guint idt, GString *str)
|
|||||||
fu_string_append_kx(str, idt, "EpBulkOut", self->ep_bulk_out);
|
fu_string_append_kx(str, idt, "EpBulkOut", self->ep_bulk_out);
|
||||||
fu_string_append_kx(str, idt, "EpIntrIn", self->ep_intr_in);
|
fu_string_append_kx(str, idt, "EpIntrIn", self->ep_intr_in);
|
||||||
fu_string_append_kx(str, idt, "TriggerCode", self->trigger_code);
|
fu_string_append_kx(str, idt, "TriggerCode", self->trigger_code);
|
||||||
|
fu_string_append(str,
|
||||||
|
idt,
|
||||||
|
"DeviceStatus",
|
||||||
|
fu_ccgx_dmc_device_status_to_string(self->dock_status.device_status));
|
||||||
|
fu_string_append_kx(str, idt, "DeviceCount", self->dock_status.device_count);
|
||||||
|
fu_string_append_kx(str, idt, "StatusLength", self->dock_status.status_length);
|
||||||
|
fu_string_append_kx(str, idt, "CompositeVersion", self->dock_status.composite_version);
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
@ -651,41 +669,44 @@ fu_ccgx_dmc_device_attach(FuDevice *device, FuProgress *progress, GError **error
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
fu_ccgx_dmc_device_ensure_factory_version(FuCcgxDmcDevice *self)
|
||||||
|
{
|
||||||
|
for (guint i = 0; i < DMC_DOCK_MAX_DEV_COUNT; i++) {
|
||||||
|
DmcDevxStatus *status = &self->dock_status.devx_status[i];
|
||||||
|
guint64 fwver_img1 = fu_memread_uint64(status->fw_version + 0x08, G_LITTLE_ENDIAN);
|
||||||
|
guint64 fwver_img2 = fu_memread_uint64(status->fw_version + 0x10, G_LITTLE_ENDIAN);
|
||||||
|
if (status->device_type == 0x2 && fwver_img1 == fwver_img2 && fwver_img1 != 0) {
|
||||||
|
g_debug("overriding version as device is in factory mode");
|
||||||
|
fu_device_set_version_from_uint32(FU_DEVICE(self), 0x1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
fu_ccgx_dmc_device_setup(FuDevice *device, GError **error)
|
fu_ccgx_dmc_device_setup(FuDevice *device, GError **error)
|
||||||
{
|
{
|
||||||
FuCcgxDmcDevice *self = FU_CCGX_DMC_DEVICE(device);
|
FuCcgxDmcDevice *self = FU_CCGX_DMC_DEVICE(device);
|
||||||
DmcDockStatus dock_status = {0};
|
|
||||||
DmcDockIdentity dock_id = {0};
|
|
||||||
|
|
||||||
/* FuUsbDevice->setup */
|
/* FuUsbDevice->setup */
|
||||||
if (!FU_DEVICE_CLASS(fu_ccgx_dmc_device_parent_class)->setup(device, error))
|
if (!FU_DEVICE_CLASS(fu_ccgx_dmc_device_parent_class)->setup(device, error))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
/* get dock identity */
|
/* get dock identity */
|
||||||
if (!fu_ccgx_dmc_device_get_dock_id(self, &dock_id, error))
|
if (!fu_ccgx_dmc_device_ensure_dock_id(self, error))
|
||||||
|
return FALSE;
|
||||||
|
if (!fu_ccgx_dmc_device_ensure_status(self, error))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
/* store dock identity */
|
/* use composite version, but also try to detect "factory mode" where the SPI has been
|
||||||
if (!fu_memcpy_safe((guint8 *)&self->dock_id,
|
* imaged but has not been updated manually to the initial version */
|
||||||
sizeof(DmcDockIdentity),
|
fu_device_set_version_from_uint32(device, self->dock_status.composite_version);
|
||||||
0x0, /* dst */
|
if (fu_device_get_version_raw(device) == 0)
|
||||||
(guint8 *)&dock_id,
|
fu_ccgx_dmc_device_ensure_factory_version(self);
|
||||||
sizeof(DmcDockIdentity),
|
|
||||||
0, /* src */
|
|
||||||
sizeof(DmcDockIdentity),
|
|
||||||
error))
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
/* get dock status */
|
|
||||||
if (!fu_ccgx_dmc_device_get_dock_status(self, &dock_status, error))
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
/* set composite version */
|
|
||||||
fu_device_set_version_from_uint32(FU_DEVICE(self), dock_status.composite_version);
|
|
||||||
fu_device_add_flag(FU_DEVICE(self), FWUPD_DEVICE_FLAG_UPDATABLE);
|
fu_device_add_flag(FU_DEVICE(self), FWUPD_DEVICE_FLAG_UPDATABLE);
|
||||||
|
|
||||||
if (dock_id.custom_meta_data_flag > 0)
|
if (self->dock_id.custom_meta_data_flag > 0)
|
||||||
fu_device_add_flag(FU_DEVICE(self), FWUPD_DEVICE_FLAG_SIGNED_PAYLOAD);
|
fu_device_add_flag(FU_DEVICE(self), FWUPD_DEVICE_FLAG_SIGNED_PAYLOAD);
|
||||||
else
|
else
|
||||||
fu_device_add_flag(FU_DEVICE(self), FWUPD_DEVICE_FLAG_UNSIGNED_PAYLOAD);
|
fu_device_add_flag(FU_DEVICE(self), FWUPD_DEVICE_FLAG_UNSIGNED_PAYLOAD);
|
||||||
|
283
plugins/ccgx/fu-ccgx-dmc-devx-device.c
Normal file
283
plugins/ccgx/fu-ccgx-dmc-devx-device.c
Normal file
@ -0,0 +1,283 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2023 Richard Hughes <richard@hughsie.com>
|
||||||
|
* Copyright (C) 2020 Cypress Semiconductor Corporation.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: LGPL-2.1+
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#include <fwupdplugin.h>
|
||||||
|
|
||||||
|
#include "fu-ccgx-dmc-devx-device.h"
|
||||||
|
|
||||||
|
#define DMC_FW_WRITE_STATUS_RETRY_COUNT 3
|
||||||
|
#define DMC_FW_WRITE_STATUS_RETRY_DELAY_MS 30
|
||||||
|
|
||||||
|
struct _FuCcgxDmcDevxDevice {
|
||||||
|
FuDevice parent_instance;
|
||||||
|
DmcDevxStatus status;
|
||||||
|
};
|
||||||
|
|
||||||
|
G_DEFINE_TYPE(FuCcgxDmcDevxDevice, fu_ccgx_dmc_devx_device, FU_TYPE_DEVICE)
|
||||||
|
|
||||||
|
static gchar *
|
||||||
|
fu_ccgx_dmc_devx_status_version_dmc_bfw(DmcDevxStatus *status, gsize offset)
|
||||||
|
{
|
||||||
|
return g_strdup_printf("%u.%u.%u.%u",
|
||||||
|
status->fw_version[offset + 3] >> 4,
|
||||||
|
status->fw_version[offset + 3] & 0xFu,
|
||||||
|
status->fw_version[offset + 2],
|
||||||
|
fu_memread_uint16(status->fw_version + offset, G_LITTLE_ENDIAN));
|
||||||
|
}
|
||||||
|
|
||||||
|
static gchar *
|
||||||
|
fu_ccgx_dmc_devx_status_version_dmc_app(DmcDevxStatus *status, gsize offset)
|
||||||
|
{
|
||||||
|
return g_strdup_printf("%u.%u.%u",
|
||||||
|
status->fw_version[offset + 4 + 3] >> 4,
|
||||||
|
status->fw_version[offset + 4 + 3] & 0xFu,
|
||||||
|
status->fw_version[offset + 4 + 2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gchar *
|
||||||
|
fu_ccgx_dmc_devx_status_version_hx3(DmcDevxStatus *status, gsize offset)
|
||||||
|
{
|
||||||
|
return g_strdup_printf("%u.%u.%u",
|
||||||
|
status->fw_version[offset + 4 + 3],
|
||||||
|
status->fw_version[offset + 4 + 2],
|
||||||
|
status->fw_version[offset + 4 + 1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
fu_ccgx_dmc_devx_device_hexver_to_string(FuCcgxDmcDevxDevice *self,
|
||||||
|
const gchar *kind,
|
||||||
|
gsize offset,
|
||||||
|
guint idt,
|
||||||
|
GString *str)
|
||||||
|
{
|
||||||
|
DmcDevxStatus *status = &self->status;
|
||||||
|
g_autofree gchar *key = g_strdup_printf("FwVersion[%s]", kind);
|
||||||
|
g_autofree gchar *val =
|
||||||
|
fu_version_from_uint64(fu_memread_uint64(status->fw_version + offset, G_LITTLE_ENDIAN),
|
||||||
|
FWUPD_VERSION_FORMAT_HEX);
|
||||||
|
fu_string_append(str, idt, key, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
fu_ccgx_dmc_devx_device_hx3ver_to_string(FuCcgxDmcDevxDevice *self,
|
||||||
|
const gchar *kind,
|
||||||
|
gsize offset,
|
||||||
|
guint idt,
|
||||||
|
GString *str)
|
||||||
|
{
|
||||||
|
DmcDevxStatus *status = &self->status;
|
||||||
|
g_autofree gchar *key = g_strdup_printf("FwVersion[%s]", kind);
|
||||||
|
g_autofree gchar *val = fu_ccgx_dmc_devx_status_version_hx3(status, offset);
|
||||||
|
fu_string_append(str, idt, key, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
fu_ccgx_dmc_devx_device_dmcver_to_string(FuCcgxDmcDevxDevice *self,
|
||||||
|
const gchar *kind,
|
||||||
|
gsize offset,
|
||||||
|
guint idt,
|
||||||
|
GString *str)
|
||||||
|
{
|
||||||
|
DmcDevxStatus *status = &self->status;
|
||||||
|
g_autofree gchar *key = g_strdup_printf("FwVersion[%s]", kind);
|
||||||
|
g_autofree gchar *bfw_val = fu_ccgx_dmc_devx_status_version_dmc_bfw(status, offset);
|
||||||
|
g_autofree gchar *app_val = fu_ccgx_dmc_devx_status_version_dmc_app(status, offset);
|
||||||
|
g_autofree gchar *tmp = g_strdup_printf("base:%s\tapp:%s", bfw_val, app_val);
|
||||||
|
fu_string_append(str, idt, key, tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
static DmcDevxDeviceType
|
||||||
|
fu_ccgx_dmc_devx_device_version_type(FuCcgxDmcDevxDevice *self)
|
||||||
|
{
|
||||||
|
DmcDevxStatus *status = &self->status;
|
||||||
|
if (status->device_type == DMC_DEVX_DEVICE_TYPE_DMC ||
|
||||||
|
status->device_type == DMC_DEVX_DEVICE_TYPE_CCG3 ||
|
||||||
|
status->device_type == DMC_DEVX_DEVICE_TYPE_CCG4 ||
|
||||||
|
status->device_type == DMC_DEVX_DEVICE_TYPE_CCG5 || status->device_type == 0x0B)
|
||||||
|
return DMC_DEVX_DEVICE_TYPE_DMC;
|
||||||
|
if (status->device_type == DMC_DEVX_DEVICE_TYPE_HX3)
|
||||||
|
return DMC_DEVX_DEVICE_TYPE_HX3;
|
||||||
|
return DMC_DEVX_DEVICE_TYPE_INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
fu_ccgx_dmc_devx_device_to_string(FuDevice *device, guint idt, GString *str)
|
||||||
|
{
|
||||||
|
FuCcgxDmcDevxDevice *self = FU_CCGX_DMC_DEVX_DEVICE(device);
|
||||||
|
DmcDevxStatus *status = &self->status;
|
||||||
|
DmcDevxDeviceType device_version_type = fu_ccgx_dmc_devx_device_version_type(self);
|
||||||
|
const gchar *device_type = fu_ccgx_dmc_devx_device_type_to_string(status->device_type);
|
||||||
|
|
||||||
|
if (device_type != NULL) {
|
||||||
|
g_autofree gchar *tmp =
|
||||||
|
g_strdup_printf("0x%x [%s]", status->device_type, device_type);
|
||||||
|
fu_string_append(str, idt, "DeviceType", tmp);
|
||||||
|
} else {
|
||||||
|
fu_string_append_kx(str, idt, "DeviceType", status->device_type);
|
||||||
|
}
|
||||||
|
if (status->image_mode < DMC_IMG_MODE_LAST) {
|
||||||
|
g_autofree gchar *tmp =
|
||||||
|
g_strdup_printf("0x%x [%s]",
|
||||||
|
status->image_mode,
|
||||||
|
fu_ccgx_dmc_img_mode_to_string(status->image_mode));
|
||||||
|
fu_string_append(str, idt, "ImageMode", tmp);
|
||||||
|
} else {
|
||||||
|
fu_string_append_kx(str, idt, "ImageMode", status->image_mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
fu_string_append_kx(str, idt, "CurrentImage", status->current_image);
|
||||||
|
fu_string_append(str,
|
||||||
|
idt,
|
||||||
|
"ImgStatus1",
|
||||||
|
fu_ccgx_dmc_img_status_to_string(status->img_status & 0x0F));
|
||||||
|
fu_string_append(str,
|
||||||
|
idt,
|
||||||
|
"ImgStatus2",
|
||||||
|
fu_ccgx_dmc_img_status_to_string((status->img_status >> 4) & 0x0F));
|
||||||
|
|
||||||
|
/* versions */
|
||||||
|
if (device_version_type == DMC_DEVX_DEVICE_TYPE_DMC) {
|
||||||
|
fu_ccgx_dmc_devx_device_dmcver_to_string(self, "boot", 0x00, idt, str);
|
||||||
|
fu_ccgx_dmc_devx_device_dmcver_to_string(self, "img1", 0x08, idt, str);
|
||||||
|
if (status->image_mode != DMC_IMG_MODE_SINGLE_IMG)
|
||||||
|
fu_ccgx_dmc_devx_device_dmcver_to_string(self, "img2", 0x10, idt, str);
|
||||||
|
} else if (device_version_type == DMC_DEVX_DEVICE_TYPE_HX3) {
|
||||||
|
fu_ccgx_dmc_devx_device_hx3ver_to_string(self, "boot", 0x00, idt, str);
|
||||||
|
fu_ccgx_dmc_devx_device_hx3ver_to_string(self, "img1", 0x08, idt, str);
|
||||||
|
if (status->image_mode != DMC_IMG_MODE_SINGLE_IMG)
|
||||||
|
fu_ccgx_dmc_devx_device_hx3ver_to_string(self, "img2", 0x10, idt, str);
|
||||||
|
} else {
|
||||||
|
fu_ccgx_dmc_devx_device_hexver_to_string(self, "boot", 0x00, idt, str);
|
||||||
|
fu_ccgx_dmc_devx_device_hexver_to_string(self, "img1", 0x08, idt, str);
|
||||||
|
if (status->image_mode != DMC_IMG_MODE_SINGLE_IMG)
|
||||||
|
fu_ccgx_dmc_devx_device_hexver_to_string(self, "img2", 0x10, idt, str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
fu_ccgx_dmc_devx_device_set_quirk_kv(FuDevice *device,
|
||||||
|
const gchar *key,
|
||||||
|
const gchar *value,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
if (g_strcmp0(key, "CcgxDmcCompositeVersion") == 0) {
|
||||||
|
guint64 tmp = 0;
|
||||||
|
FuDevice *proxy = fu_device_get_proxy(device);
|
||||||
|
if (!fu_strtoull(value, &tmp, 0, G_MAXUINT32, error))
|
||||||
|
return FALSE;
|
||||||
|
if (fu_device_get_version_raw(proxy) != tmp) {
|
||||||
|
g_debug("overriding composite version from %u to %u from %s",
|
||||||
|
(guint)fu_device_get_version_raw(proxy),
|
||||||
|
(guint)tmp,
|
||||||
|
fu_device_get_id(device));
|
||||||
|
fu_device_set_version_from_uint32(proxy, tmp);
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
g_set_error_literal(error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, "no supported");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const gchar *
|
||||||
|
fu_ccgx_dmc_devx_device_type_to_name(DmcDevxDeviceType device_type)
|
||||||
|
{
|
||||||
|
if (device_type == DMC_DEVX_DEVICE_TYPE_CCG3)
|
||||||
|
return "CCG3";
|
||||||
|
if (device_type == DMC_DEVX_DEVICE_TYPE_DMC)
|
||||||
|
return "DMC";
|
||||||
|
if (device_type == DMC_DEVX_DEVICE_TYPE_CCG4)
|
||||||
|
return "CCG4";
|
||||||
|
if (device_type == DMC_DEVX_DEVICE_TYPE_CCG5)
|
||||||
|
return "CCG5";
|
||||||
|
if (device_type == DMC_DEVX_DEVICE_TYPE_HX3)
|
||||||
|
return "HX3";
|
||||||
|
if (device_type == DMC_DEVX_DEVICE_TYPE_HX3_PD)
|
||||||
|
return "HX3 PD";
|
||||||
|
if (device_type == DMC_DEVX_DEVICE_TYPE_DMC_PD)
|
||||||
|
return "DMC PD";
|
||||||
|
if (device_type == DMC_DEVX_DEVICE_TYPE_SPI)
|
||||||
|
return "SPI";
|
||||||
|
return "Unknown";
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
fu_ccgx_dmc_devx_device_probe(FuDevice *device, GError **error)
|
||||||
|
{
|
||||||
|
FuCcgxDmcDevxDevice *self = FU_CCGX_DMC_DEVX_DEVICE(device);
|
||||||
|
FuDevice *proxy = fu_device_get_proxy(device);
|
||||||
|
DmcDevxStatus *status = &self->status;
|
||||||
|
DmcDevxDeviceType device_version_type = fu_ccgx_dmc_devx_device_version_type(self);
|
||||||
|
gsize offset = 0;
|
||||||
|
g_autofree gchar *logical_id = g_strdup_printf("0x%02x", status->component_id);
|
||||||
|
g_autofree gchar *version = NULL;
|
||||||
|
|
||||||
|
fu_device_set_name(device, fu_ccgx_dmc_devx_device_type_to_name(status->device_type));
|
||||||
|
fu_device_set_logical_id(device, logical_id);
|
||||||
|
|
||||||
|
/* for the version number */
|
||||||
|
if (status->current_image == 0x01)
|
||||||
|
offset = 4;
|
||||||
|
else if (status->current_image == 0x02)
|
||||||
|
offset = 8;
|
||||||
|
|
||||||
|
/* version, if possible */
|
||||||
|
if (device_version_type == DMC_DEVX_DEVICE_TYPE_DMC) {
|
||||||
|
version = fu_ccgx_dmc_devx_status_version_dmc_bfw(status, offset);
|
||||||
|
fu_device_set_version_format(FU_DEVICE(self), FWUPD_VERSION_FORMAT_QUAD);
|
||||||
|
} else if (device_version_type == DMC_DEVX_DEVICE_TYPE_HX3) {
|
||||||
|
version = fu_ccgx_dmc_devx_status_version_hx3(status, offset);
|
||||||
|
fu_device_set_version_format(FU_DEVICE(self), FWUPD_VERSION_FORMAT_TRIPLET);
|
||||||
|
fu_device_set_version(device, version);
|
||||||
|
}
|
||||||
|
if (version != NULL) {
|
||||||
|
fu_device_set_version(device, version);
|
||||||
|
fu_device_add_instance_strsafe(device, "VER", version);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* add GUIDs */
|
||||||
|
fu_device_add_instance_strup(device,
|
||||||
|
"TYPE",
|
||||||
|
fu_ccgx_dmc_devx_device_type_to_string(status->device_type));
|
||||||
|
fu_device_add_instance_u8(device, "CID", status->component_id);
|
||||||
|
fu_device_add_instance_u16(device, "VID", fu_usb_device_get_vid(FU_USB_DEVICE(proxy)));
|
||||||
|
fu_device_add_instance_u16(device, "PID", fu_usb_device_get_pid(FU_USB_DEVICE(proxy)));
|
||||||
|
fu_device_build_instance_id(device, NULL, "USB", "VID", "PID", "CID", NULL);
|
||||||
|
fu_device_build_instance_id_quirk(device, NULL, "USB", "VID", "PID", "CID", "TYPE", NULL);
|
||||||
|
fu_device_build_instance_id_quirk(device, NULL, "USB", "VID", "PID", "CID", "VER", NULL);
|
||||||
|
|
||||||
|
/* success */
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
fu_ccgx_dmc_devx_device_init(FuCcgxDmcDevxDevice *self)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
fu_ccgx_dmc_devx_device_class_init(FuCcgxDmcDevxDeviceClass *klass)
|
||||||
|
{
|
||||||
|
FuDeviceClass *klass_device = FU_DEVICE_CLASS(klass);
|
||||||
|
klass_device->probe = fu_ccgx_dmc_devx_device_probe;
|
||||||
|
klass_device->to_string = fu_ccgx_dmc_devx_device_to_string;
|
||||||
|
klass_device->set_quirk_kv = fu_ccgx_dmc_devx_device_set_quirk_kv;
|
||||||
|
}
|
||||||
|
|
||||||
|
FuCcgxDmcDevxDevice *
|
||||||
|
fu_ccgx_dmc_devx_device_new(FuDevice *proxy, DmcDevxStatus *status)
|
||||||
|
{
|
||||||
|
FuCcgxDmcDevxDevice *self = g_object_new(FU_TYPE_CCGX_DMC_DEVX_DEVICE,
|
||||||
|
"context",
|
||||||
|
fu_device_get_context(proxy),
|
||||||
|
"proxy",
|
||||||
|
proxy,
|
||||||
|
NULL);
|
||||||
|
self->status = *status;
|
||||||
|
return self;
|
||||||
|
}
|
22
plugins/ccgx/fu-ccgx-dmc-devx-device.h
Normal file
22
plugins/ccgx/fu-ccgx-dmc-devx-device.h
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2023 Richard Hughes <richard@hughsie.com>
|
||||||
|
* Copyright (C) 2020 Cypress Semiconductor Corporation.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: LGPL-2.1+
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <fwupdplugin.h>
|
||||||
|
|
||||||
|
#include "fu-ccgx-dmc-common.h"
|
||||||
|
|
||||||
|
#define FU_TYPE_CCGX_DMC_DEVX_DEVICE (fu_ccgx_dmc_devx_device_get_type())
|
||||||
|
G_DECLARE_FINAL_TYPE(FuCcgxDmcDevxDevice,
|
||||||
|
fu_ccgx_dmc_devx_device,
|
||||||
|
FU,
|
||||||
|
CCGX_DMC_DEVX_DEVICE,
|
||||||
|
FuDevice)
|
||||||
|
|
||||||
|
FuCcgxDmcDevxDevice *
|
||||||
|
fu_ccgx_dmc_devx_device_new(FuDevice *proxy, DmcDevxStatus *status);
|
@ -14,6 +14,7 @@ plugin_builtin_ccgx = static_library('fu_plugin_ccgx',
|
|||||||
'fu-ccgx-hpi-common.c',
|
'fu-ccgx-hpi-common.c',
|
||||||
'fu-ccgx-hpi-device.c',
|
'fu-ccgx-hpi-device.c',
|
||||||
'fu-ccgx-dmc-device.c',
|
'fu-ccgx-dmc-device.c',
|
||||||
|
'fu-ccgx-dmc-devx-device.c',
|
||||||
'fu-ccgx-dmc-firmware.c', # fuzzing
|
'fu-ccgx-dmc-firmware.c', # fuzzing
|
||||||
'fu-ccgx-dmc-common.c', # fuzzing
|
'fu-ccgx-dmc-common.c', # fuzzing
|
||||||
],
|
],
|
||||||
|
Loading…
Reference in New Issue
Block a user