mirror of
https://git.proxmox.com/git/fwupd
synced 2025-08-16 00:45:53 +00:00
usi-dock: Add support for various TBT4 docks for Lenovo and HP
With much help from Victor Cheng <victor_cheng@usiglobal.com>
This commit is contained in:
parent
f6833f96c3
commit
56f6f99633
@ -484,6 +484,7 @@ done
|
|||||||
%{_libdir}/fwupd-plugins-%{fwupdplugin_version}/libfu_plugin_uefi_pk.so
|
%{_libdir}/fwupd-plugins-%{fwupdplugin_version}/libfu_plugin_uefi_pk.so
|
||||||
%{_libdir}/fwupd-plugins-%{fwupdplugin_version}/libfu_plugin_uefi_recovery.so
|
%{_libdir}/fwupd-plugins-%{fwupdplugin_version}/libfu_plugin_uefi_recovery.so
|
||||||
%endif
|
%endif
|
||||||
|
%{_libdir}/fwupd-plugins-%{fwupdplugin_version}/libfu_plugin_usi_dock.so
|
||||||
%{_libdir}/fwupd-plugins-%{fwupdplugin_version}/libfu_plugin_logind.so
|
%{_libdir}/fwupd-plugins-%{fwupdplugin_version}/libfu_plugin_logind.so
|
||||||
%{_libdir}/fwupd-plugins-%{fwupdplugin_version}/libfu_plugin_logitech_bulkcontroller.so
|
%{_libdir}/fwupd-plugins-%{fwupdplugin_version}/libfu_plugin_logitech_bulkcontroller.so
|
||||||
%{_libdir}/fwupd-plugins-%{fwupdplugin_version}/libfu_plugin_logitech_hidpp.so
|
%{_libdir}/fwupd-plugins-%{fwupdplugin_version}/libfu_plugin_logitech_hidpp.so
|
||||||
|
@ -71,6 +71,7 @@ subdir('uefi-dbx')
|
|||||||
subdir('uefi-pk')
|
subdir('uefi-pk')
|
||||||
subdir('uefi-recovery')
|
subdir('uefi-recovery')
|
||||||
subdir('upower')
|
subdir('upower')
|
||||||
|
subdir('usi-dock')
|
||||||
subdir('vli')
|
subdir('vli')
|
||||||
subdir('wacom-raw')
|
subdir('wacom-raw')
|
||||||
subdir('wacom-usb')
|
subdir('wacom-usb')
|
||||||
|
37
plugins/usi-dock/README.md
Normal file
37
plugins/usi-dock/README.md
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
# USI Dock
|
||||||
|
|
||||||
|
## Introduction
|
||||||
|
|
||||||
|
This plugin uses the MCU to write all the dock firmware components. The MCU version
|
||||||
|
is provided by the DMC bcdDevice.
|
||||||
|
|
||||||
|
This plugin supports the following protocol ID:
|
||||||
|
|
||||||
|
* com.usi.dock
|
||||||
|
|
||||||
|
## GUID Generation
|
||||||
|
|
||||||
|
These devices use the standard USB DeviceInstanceId values, e.g.
|
||||||
|
|
||||||
|
* `USB\VID_17EF&PID_7226&REV_0001`
|
||||||
|
* `USB\VID_17EF&PID_7226`
|
||||||
|
* `USB\VID_17EF`
|
||||||
|
|
||||||
|
Additionally, some extra "component ID" instance IDs are added.
|
||||||
|
|
||||||
|
* `USB\VID_17EF&PID_7226&CID_TBT4`
|
||||||
|
* `USB\VID_17EF&PID_7226&CID_USB3`
|
||||||
|
|
||||||
|
## Update Behavior
|
||||||
|
|
||||||
|
The device usually presents in runtime mode, but on detach re-enumerates with
|
||||||
|
the same USB PID in an unlocked mode. On attach the device again re-enumerates
|
||||||
|
back to the runtime locked mode.
|
||||||
|
|
||||||
|
## Vendor ID Security
|
||||||
|
|
||||||
|
The vendor ID is set from the USB vendor.
|
||||||
|
|
||||||
|
## External Interface Access
|
||||||
|
|
||||||
|
This plugin requires read/write access to `/dev/bus/usb`.
|
68
plugins/usi-dock/data/lsusb.txt
Normal file
68
plugins/usi-dock/data/lsusb.txt
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
Bus 001 Device 024: ID 17ef:30b4 Lenovo ThinkPad Thunderbolt 4 Dock MCU Controller
|
||||||
|
Device Descriptor:
|
||||||
|
bLength 18
|
||||||
|
bDescriptorType 1
|
||||||
|
bcdUSB 2.00
|
||||||
|
bDeviceClass 0
|
||||||
|
bDeviceSubClass 0
|
||||||
|
bDeviceProtocol 0
|
||||||
|
bMaxPacketSize0 64
|
||||||
|
idVendor 0x17ef Lenovo
|
||||||
|
idProduct 0x30b4
|
||||||
|
bcdDevice 1.00
|
||||||
|
iManufacturer 1 Lenovo
|
||||||
|
iProduct 2 ThinkPad Thunderbolt 4 Dock MCU Controller
|
||||||
|
iSerial 3
|
||||||
|
bNumConfigurations 1
|
||||||
|
Configuration Descriptor:
|
||||||
|
bLength 9
|
||||||
|
bDescriptorType 2
|
||||||
|
wTotalLength 0x0029
|
||||||
|
bNumInterfaces 1
|
||||||
|
bConfigurationValue 1
|
||||||
|
iConfiguration 0
|
||||||
|
bmAttributes 0x80
|
||||||
|
(Bus Powered)
|
||||||
|
MaxPower 100mA
|
||||||
|
Interface Descriptor:
|
||||||
|
bLength 9
|
||||||
|
bDescriptorType 4
|
||||||
|
bInterfaceNumber 0
|
||||||
|
bAlternateSetting 0
|
||||||
|
bNumEndpoints 2
|
||||||
|
bInterfaceClass 3 Human Interface Device
|
||||||
|
bInterfaceSubClass 0
|
||||||
|
bInterfaceProtocol 0
|
||||||
|
iInterface 0
|
||||||
|
HID Device Descriptor:
|
||||||
|
bLength 9
|
||||||
|
bDescriptorType 33
|
||||||
|
bcdHID 1.11
|
||||||
|
bCountryCode 0 Not supported
|
||||||
|
bNumDescriptors 1
|
||||||
|
bDescriptorType 34 Report
|
||||||
|
wDescriptorLength 39
|
||||||
|
Report Descriptors:
|
||||||
|
** UNAVAILABLE **
|
||||||
|
Endpoint Descriptor:
|
||||||
|
bLength 7
|
||||||
|
bDescriptorType 5
|
||||||
|
bEndpointAddress 0x81 EP 1 IN
|
||||||
|
bmAttributes 3
|
||||||
|
Transfer Type Interrupt
|
||||||
|
Synch Type None
|
||||||
|
Usage Type Data
|
||||||
|
wMaxPacketSize 0x0040 1x 64 bytes
|
||||||
|
bInterval 1
|
||||||
|
Endpoint Descriptor:
|
||||||
|
bLength 7
|
||||||
|
bDescriptorType 5
|
||||||
|
bEndpointAddress 0x02 EP 2 OUT
|
||||||
|
bmAttributes 3
|
||||||
|
Transfer Type Interrupt
|
||||||
|
Synch Type None
|
||||||
|
Usage Type Data
|
||||||
|
wMaxPacketSize 0x0040 1x 64 bytes
|
||||||
|
bInterval 1
|
||||||
|
Device Status: 0x0000
|
||||||
|
(Bus Powered)
|
43
plugins/usi-dock/fu-plugin-usi-dock.c
Normal file
43
plugins/usi-dock/fu-plugin-usi-dock.c
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2021 Richard Hughes <richard@hughsie.com>
|
||||||
|
* Copyright (C) 2021 Victor Cheng <victor_cheng@usiglobal.com>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: LGPL-2.1+
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#include <fwupdplugin.h>
|
||||||
|
|
||||||
|
#include "fu-usi-dock-dmc-device.h"
|
||||||
|
#include "fu-usi-dock-mcu-device.h"
|
||||||
|
|
||||||
|
#define USI_DOCK_TBT_INSTANCE_ID "THUNDERBOLT\\VEN_0108&DEV_2031"
|
||||||
|
|
||||||
|
static void
|
||||||
|
fu_plugin_usi_dock_dmc_registered(FuPlugin *plugin, FuDevice *device)
|
||||||
|
{
|
||||||
|
/* usb device from thunderbolt plugin */
|
||||||
|
if (g_strcmp0(fu_device_get_plugin(device), "thunderbolt") == 0 &&
|
||||||
|
fu_device_has_guid(device, USI_DOCK_TBT_INSTANCE_ID)) {
|
||||||
|
g_autofree gchar *msg = NULL;
|
||||||
|
msg = g_strdup_printf("firmware update inhibited by [%s] plugin",
|
||||||
|
fu_plugin_get_name(plugin));
|
||||||
|
fu_device_inhibit(device, "usb-blocked", msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
fu_usi_dock_init(FuPlugin *plugin)
|
||||||
|
{
|
||||||
|
fu_plugin_add_device_gtype(plugin, FU_TYPE_USI_DOCK_MCU_DEVICE);
|
||||||
|
fu_plugin_add_device_gtype(plugin, FU_TYPE_USI_DOCK_DMC_DEVICE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
fu_plugin_init_vfuncs(FuPluginVfuncs *vfuncs)
|
||||||
|
{
|
||||||
|
vfuncs->build_hash = FU_BUILD_HASH;
|
||||||
|
vfuncs->init = fu_usi_dock_init;
|
||||||
|
vfuncs->device_registered = fu_plugin_usi_dock_dmc_registered;
|
||||||
|
}
|
88
plugins/usi-dock/fu-usi-dock-child-device.c
Normal file
88
plugins/usi-dock/fu-usi-dock-child-device.c
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2021 Richard Hughes <richard@hughsie.com>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: LGPL-2.1+
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#include "fu-usi-dock-child-device.h"
|
||||||
|
#include "fu-usi-dock-mcu-device.h"
|
||||||
|
|
||||||
|
struct _FuUsiDockChildDevice {
|
||||||
|
FuDevice parent_instance;
|
||||||
|
guint8 chip_idx;
|
||||||
|
};
|
||||||
|
|
||||||
|
G_DEFINE_TYPE(FuUsiDockChildDevice, fu_usi_dock_child_device, FU_TYPE_DEVICE)
|
||||||
|
|
||||||
|
void
|
||||||
|
fu_usi_dock_child_device_set_chip_idx(FuUsiDockChildDevice *self, guint8 chip_idx)
|
||||||
|
{
|
||||||
|
self->chip_idx = chip_idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
fu_usi_dock_child_device_to_string(FuDevice *device, guint idt, GString *str)
|
||||||
|
{
|
||||||
|
FuUsiDockChildDevice *self = FU_USI_DOCK_CHILD_DEVICE(device);
|
||||||
|
fu_common_string_append_kx(str, idt, "ChipIdx", self->chip_idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* use the parents parser */
|
||||||
|
static FuFirmware *
|
||||||
|
fu_usi_dock_mcu_device_prepare_firmware(FuDevice *device,
|
||||||
|
GBytes *fw,
|
||||||
|
FwupdInstallFlags flags,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
FuDevice *parent = fu_device_get_parent(device);
|
||||||
|
if (parent == NULL) {
|
||||||
|
g_set_error_literal(error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, "no parent");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return fu_device_prepare_firmware(parent, fw, flags, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* only update this specific child component */
|
||||||
|
static gboolean
|
||||||
|
fu_usi_dock_mcu_device_write_firmware(FuDevice *device,
|
||||||
|
FuFirmware *firmware,
|
||||||
|
FuProgress *progress,
|
||||||
|
FwupdInstallFlags flags,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
FuUsiDockChildDevice *self = FU_USI_DOCK_CHILD_DEVICE(device);
|
||||||
|
FuDevice *parent = fu_device_get_parent(device);
|
||||||
|
if (parent == NULL) {
|
||||||
|
g_set_error_literal(error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, "no parent");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
return fu_usi_dock_mcu_device_write_firmware_with_idx(FU_USI_DOCK_MCU_DEVICE(parent),
|
||||||
|
firmware,
|
||||||
|
self->chip_idx,
|
||||||
|
progress,
|
||||||
|
flags,
|
||||||
|
error);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
fu_usi_dock_child_device_init(FuUsiDockChildDevice *self)
|
||||||
|
{
|
||||||
|
fu_device_add_internal_flag(FU_DEVICE(self), FU_DEVICE_INTERNAL_FLAG_USE_PARENT_FOR_OPEN);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
fu_usi_dock_child_device_class_init(FuUsiDockChildDeviceClass *klass)
|
||||||
|
{
|
||||||
|
FuDeviceClass *klass_device = FU_DEVICE_CLASS(klass);
|
||||||
|
klass_device->to_string = fu_usi_dock_child_device_to_string;
|
||||||
|
klass_device->prepare_firmware = fu_usi_dock_mcu_device_prepare_firmware;
|
||||||
|
klass_device->write_firmware = fu_usi_dock_mcu_device_write_firmware;
|
||||||
|
}
|
||||||
|
|
||||||
|
FuDevice *
|
||||||
|
fu_usi_dock_child_new(FuContext *ctx)
|
||||||
|
{
|
||||||
|
return g_object_new(FU_TYPE_USI_DOCK_CHILD_DEVICE, "context", ctx, NULL);
|
||||||
|
}
|
21
plugins/usi-dock/fu-usi-dock-child-device.h
Normal file
21
plugins/usi-dock/fu-usi-dock-child-device.h
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2021 Richard Hughes <richard@hughsie.com>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: LGPL-2.1+
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <fwupdplugin.h>
|
||||||
|
|
||||||
|
#define FU_TYPE_USI_DOCK_CHILD_DEVICE (fu_usi_dock_child_device_get_type())
|
||||||
|
G_DECLARE_FINAL_TYPE(FuUsiDockChildDevice,
|
||||||
|
fu_usi_dock_child_device,
|
||||||
|
FU,
|
||||||
|
USI_DOCK_CHILD_DEVICE,
|
||||||
|
FuDevice)
|
||||||
|
|
||||||
|
FuDevice *
|
||||||
|
fu_usi_dock_child_new(FuContext *ctx);
|
||||||
|
void
|
||||||
|
fu_usi_dock_child_device_set_chip_idx(FuUsiDockChildDevice *self, guint8 chip_idx);
|
40
plugins/usi-dock/fu-usi-dock-common.c
Normal file
40
plugins/usi-dock/fu-usi-dock-common.c
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2021 Richard Hughes <richard@hughsie.com>
|
||||||
|
* Copyright (C) 2021 Victor Cheng <victor_cheng@usiglobal.com>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: LGPL-2.1+
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#include "fu-usi-dock-common.h"
|
||||||
|
|
||||||
|
const gchar *
|
||||||
|
fu_usi_dock_spi_state_to_string(guint8 val)
|
||||||
|
{
|
||||||
|
if (val == SPI_STATE_NONE)
|
||||||
|
return "none";
|
||||||
|
if (val == SPI_STATE_SWITCH_SUCCESS)
|
||||||
|
return "switch-success";
|
||||||
|
if (val == SPI_STATE_SWITCH_FAIL)
|
||||||
|
return "switch-fail";
|
||||||
|
if (val == SPI_STATE_CMD_SUCCESS)
|
||||||
|
return "cmd-success";
|
||||||
|
if (val == SPI_STATE_CMD_FAIL)
|
||||||
|
return "cmd-fail";
|
||||||
|
if (val == SPI_STATE_RW_SUCCESS)
|
||||||
|
return "rw-success";
|
||||||
|
if (val == SPI_STATE_RW_FAIL)
|
||||||
|
return "rw-fail";
|
||||||
|
if (val == SPI_STATE_READY)
|
||||||
|
return "ready";
|
||||||
|
if (val == SPI_STATE_BUSY)
|
||||||
|
return "busy";
|
||||||
|
if (val == SPI_STATE_TIMEOUT)
|
||||||
|
return "timeout";
|
||||||
|
if (val == SPI_STATE_FLASH_FOUND)
|
||||||
|
return "flash-found";
|
||||||
|
if (val == SPI_STATE_FLASH_NOT_FOUND)
|
||||||
|
return "flash-not-found";
|
||||||
|
return NULL;
|
||||||
|
}
|
107
plugins/usi-dock/fu-usi-dock-common.h
Normal file
107
plugins/usi-dock/fu-usi-dock-common.h
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2021 Richard Hughes <richard@hughsie.com>
|
||||||
|
* Copyright (C) 2021 Victor Cheng <victor_cheng@usiglobal.com>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: LGPL-2.1+
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <glib-object.h>
|
||||||
|
|
||||||
|
#define USB_HID_REPORT_ID1 1u
|
||||||
|
#define USB_HID_REPORT_ID2 2u
|
||||||
|
|
||||||
|
#define USBUID_ISP_DEVICE_CMD_MCU_NONE 0x0
|
||||||
|
#define USBUID_ISP_DEVICE_CMD_MCU_STATUS 0x1
|
||||||
|
#define USBUID_ISP_DEVICE_CMD_MCU_JUMP2BOOT 0x2
|
||||||
|
#define USBUID_ISP_DEVICE_CMD_READ_MCU_VERSIONPAGE 0x3
|
||||||
|
#define USBUID_ISP_DEVICE_CMD_SET_I225_PWR 0x4
|
||||||
|
#define USBUID_ISP_DEVICE_CMD_DOCK_RESET 0x5
|
||||||
|
#define USBUID_ISP_DEVICE_CMD_VERSION_WRITEBACK 0x6
|
||||||
|
|
||||||
|
#define USBUID_ISP_DEVICE_CMD_FWBUFER_INITIAL 0x01
|
||||||
|
#define USBUID_ISP_DEVICE_CMD_FWBUFER_ERASE_FLASH 0x02
|
||||||
|
#define USBUID_ISP_DEVICE_CMD_FWBUFER_PROGRAM 0x03
|
||||||
|
#define USBUID_ISP_DEVICE_CMD_FWBUFER_WRITE_RESPONSE 0x04
|
||||||
|
#define USBUID_ISP_DEVICE_CMD_FWBUFER_READ_STATUS 0x05
|
||||||
|
#define USBUID_ISP_DEVICE_CMD_FWBUFER_CHECKSUM 0x06
|
||||||
|
#define USBUID_ISP_DEVICE_CMD_FWBUFER_END 0x07
|
||||||
|
#define USBUID_ISP_DEVICE_CMD_FWBUFER_TRANSFER_FINISH 0x08
|
||||||
|
#define USBUID_ISP_DEVICE_CMD_FWBUFER_ERROR_END 0x09
|
||||||
|
|
||||||
|
#define USBUID_ISP_INTERNAL_FW_CMD_INITAL 0x0A
|
||||||
|
#define USBUID_ISP_INTERNAL_FW_CMD_UPDATE_FW 0x0B
|
||||||
|
#define USBUID_ISP_INTERNAL_FW_CMD_TARGET_CHECKSUM 0x0C
|
||||||
|
#define USBUID_ISP_INTERNAL_FW_CMD_ISP_END 0x0D
|
||||||
|
#define USBUID_ISP_CMD_ALL 0xFF
|
||||||
|
|
||||||
|
#define TAG_TAG2_ISP_BOOT 0 /* before Common CMD for bootload, with TAG0, TAG1, CMD */
|
||||||
|
#define TAG_TAG2_ISP 0x5a /* before Common, with TAG0, TAG1, CMD */
|
||||||
|
#define TAG_TAG2_CMD_MCU 0x6a /* USB->MCU(Common-cmd mode), with TAG0, TAG1, CMD */
|
||||||
|
#define TAG_TAG2_CMD_SPI 0x7a /* USB->MCU->SPI(Common-cmd mode), with TAG0, TAG1, CMD */
|
||||||
|
#define TAG_TAG2_CMD_I2C 0x8a /* USB->MCU->I2C(Mass data transmission) */
|
||||||
|
#define TAG_TAG2_MASS_DATA_MCU 0x6b /* MASS data transfer for MCU 0xA0 */
|
||||||
|
#define TAG_TAG2_MASS_DATA_SPI 0x7b /* MASS data transfer for External flash 0xA1 */
|
||||||
|
#define TAG_TAG2_MASS_DATA_I2C 0x8b /* MASS data transfer for TBT flash */
|
||||||
|
|
||||||
|
#define DP_VERSION_FROM_MCU 0x01 /* if in use */
|
||||||
|
#define NIC_VERSION_FROM_MCU 0x2 /* if in use */
|
||||||
|
|
||||||
|
#define External_Valid_Value 0x37
|
||||||
|
#define TX_ISP_LENGTH 61
|
||||||
|
|
||||||
|
#define W25Q16DV_PAGE_SIZE 256
|
||||||
|
|
||||||
|
#define FIRMWARE_IDX_NONE 0x00
|
||||||
|
#define FIRMWARE_IDX_DMC_PD 0x01
|
||||||
|
#define FIRMWARE_IDX_DP 0x02
|
||||||
|
#define FIRMWARE_IDX_TBT4 0x04
|
||||||
|
#define FIRMWARE_IDX_USB3 0x08
|
||||||
|
#define FIRMWARE_IDX_USB2 0x10
|
||||||
|
#define FIRMWARE_IDX_AUDIO 0x20
|
||||||
|
#define FIRMWARE_IDX_I225 0x40
|
||||||
|
#define FIRMWARE_IDX_MCU 0x80
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
SPI_STATE_NONE,
|
||||||
|
SPI_STATE_SWITCH_SUCCESS,
|
||||||
|
SPI_STATE_SWITCH_FAIL,
|
||||||
|
SPI_STATE_CMD_SUCCESS,
|
||||||
|
SPI_STATE_CMD_FAIL,
|
||||||
|
SPI_STATE_RW_SUCCESS,
|
||||||
|
SPI_STATE_RW_FAIL,
|
||||||
|
SPI_STATE_READY,
|
||||||
|
SPI_STATE_BUSY,
|
||||||
|
SPI_STATE_TIMEOUT,
|
||||||
|
SPI_STATE_FLASH_FOUND,
|
||||||
|
SPI_STATE_FLASH_NOT_FOUND,
|
||||||
|
} SPI_BUS_STATE;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
guint8 DMC[5];
|
||||||
|
guint8 PD[5];
|
||||||
|
guint8 DP5x[5];
|
||||||
|
guint8 DP6x[5];
|
||||||
|
guint8 TBT4[5];
|
||||||
|
guint8 USB3[5];
|
||||||
|
guint8 USB2[5];
|
||||||
|
guint8 AUDIO[5];
|
||||||
|
guint8 I255[5];
|
||||||
|
guint8 MCU[2];
|
||||||
|
guint8 bcdVersion[2];
|
||||||
|
} IspVersionInMcu_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
guint8 id;
|
||||||
|
guint8 length;
|
||||||
|
guint8 mcutag1;
|
||||||
|
guint8 mcutag2;
|
||||||
|
guint8 inbuf[59];
|
||||||
|
guint8 mcutag3;
|
||||||
|
} UsiDockSetReportBuf;
|
||||||
|
|
||||||
|
const gchar *
|
||||||
|
fu_usi_dock_idx_to_string(guint8 val);
|
||||||
|
const gchar *
|
||||||
|
fu_usi_dock_spi_state_to_string(guint8 val);
|
55
plugins/usi-dock/fu-usi-dock-dmc-device.c
Normal file
55
plugins/usi-dock/fu-usi-dock-dmc-device.c
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2021 Richard Hughes <richard@hughsie.com>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: LGPL-2.1+
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#include "fu-usi-dock-dmc-device.h"
|
||||||
|
|
||||||
|
struct _FuUsiDockDmcDevice {
|
||||||
|
FuUsbDevice parent_instance;
|
||||||
|
};
|
||||||
|
|
||||||
|
G_DEFINE_TYPE(FuUsiDockDmcDevice, fu_usi_dock_dmc_device, FU_TYPE_USB_DEVICE)
|
||||||
|
|
||||||
|
static void
|
||||||
|
fu_usi_dock_dmc_device_parent_notify_cb(FuDevice *device, GParamSpec *pspec, gpointer user_data)
|
||||||
|
{
|
||||||
|
FuDevice *parent = fu_device_get_parent(device);
|
||||||
|
if (parent != NULL) {
|
||||||
|
g_autofree gchar *instance_id = NULL;
|
||||||
|
|
||||||
|
/* slightly odd: the MCU device uses the DMC version number */
|
||||||
|
g_debug("absorbing DMC version into MCU");
|
||||||
|
fu_device_set_version_format(parent, fu_device_get_version_format(device));
|
||||||
|
fu_device_set_version(parent, fu_device_get_version(device));
|
||||||
|
fu_device_set_serial(parent, fu_device_get_serial(device));
|
||||||
|
|
||||||
|
/* allow matching firmware */
|
||||||
|
instance_id = g_strdup_printf("USB\\VID_%04X&PID_%04X&CID_%s",
|
||||||
|
fu_usb_device_get_vid(FU_USB_DEVICE(parent)),
|
||||||
|
fu_usb_device_get_pid(FU_USB_DEVICE(parent)),
|
||||||
|
fu_device_get_name(device));
|
||||||
|
fu_device_add_instance_id(parent, instance_id);
|
||||||
|
|
||||||
|
/* don't allow firmware updates on this */
|
||||||
|
fu_device_set_name(device, "Dock Management Controller Information");
|
||||||
|
fu_device_inhibit(device, "dummy", "Use the MCU to update the DMC device");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
fu_usi_dock_dmc_device_init(FuUsiDockDmcDevice *self)
|
||||||
|
{
|
||||||
|
g_signal_connect(self,
|
||||||
|
"notify::parent",
|
||||||
|
G_CALLBACK(fu_usi_dock_dmc_device_parent_notify_cb),
|
||||||
|
NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
fu_usi_dock_dmc_device_class_init(FuUsiDockDmcDeviceClass *klass)
|
||||||
|
{
|
||||||
|
}
|
16
plugins/usi-dock/fu-usi-dock-dmc-device.h
Normal file
16
plugins/usi-dock/fu-usi-dock-dmc-device.h
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2021 Richard Hughes <richard@hughsie.com>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: LGPL-2.1+
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <fwupdplugin.h>
|
||||||
|
|
||||||
|
#define FU_TYPE_USI_DOCK_DMC_DEVICE (fu_usi_dock_dmc_device_get_type())
|
||||||
|
G_DECLARE_FINAL_TYPE(FuUsiDockDmcDevice,
|
||||||
|
fu_usi_dock_dmc_device,
|
||||||
|
FU,
|
||||||
|
USI_DOCK_DMC_DEVICE,
|
||||||
|
FuUsbDevice)
|
738
plugins/usi-dock/fu-usi-dock-mcu-device.c
Normal file
738
plugins/usi-dock/fu-usi-dock-mcu-device.c
Normal file
@ -0,0 +1,738 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2021 Richard Hughes <richard@hughsie.com>
|
||||||
|
* Copyright (C) 2021 Victor Cheng <victor_cheng@usiglobal.com>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: LGPL-2.1+
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#include "fu-usi-dock-child-device.h"
|
||||||
|
#include "fu-usi-dock-common.h"
|
||||||
|
#include "fu-usi-dock-dmc-device.h"
|
||||||
|
#include "fu-usi-dock-mcu-device.h"
|
||||||
|
|
||||||
|
struct _FuUsiDockMcuDevice {
|
||||||
|
FuHidDevice parent_instance;
|
||||||
|
};
|
||||||
|
|
||||||
|
G_DEFINE_TYPE(FuUsiDockMcuDevice, fu_usi_dock_mcu_device, FU_TYPE_HID_DEVICE)
|
||||||
|
|
||||||
|
#define FU_USI_DOCK_MCU_DEVICE_TIMEOUT 5000 /* ms */
|
||||||
|
|
||||||
|
#define FU_USI_DOCK_DEVICE_FLAG_VERFMT_HP (1 << 0)
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
fu_usi_dock_mcu_device_tx(FuUsiDockMcuDevice *self,
|
||||||
|
guint8 tag2,
|
||||||
|
const guint8 *inbuf,
|
||||||
|
gsize inbufsz,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
UsiDockSetReportBuf tx_buffer = {
|
||||||
|
.id = USB_HID_REPORT_ID2,
|
||||||
|
.length = 0x3 + inbufsz,
|
||||||
|
.mcutag1 = 0xFE,
|
||||||
|
.mcutag2 = 0xFF,
|
||||||
|
.mcutag3 = tag2,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (inbuf != NULL) {
|
||||||
|
if (!fu_memcpy_safe(tx_buffer.inbuf,
|
||||||
|
sizeof(tx_buffer.inbuf),
|
||||||
|
0x0, /* dst */
|
||||||
|
inbuf,
|
||||||
|
inbufsz,
|
||||||
|
0x0, /* src */
|
||||||
|
inbufsz,
|
||||||
|
error))
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* special cases */
|
||||||
|
if (tx_buffer.inbuf[0] == USBUID_ISP_INTERNAL_FW_CMD_UPDATE_FW) {
|
||||||
|
tx_buffer.inbuf[1] = 0xFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
return fu_hid_device_set_report(FU_HID_DEVICE(self),
|
||||||
|
USB_HID_REPORT_ID2,
|
||||||
|
(guint8 *)&tx_buffer,
|
||||||
|
sizeof(tx_buffer),
|
||||||
|
FU_USI_DOCK_MCU_DEVICE_TIMEOUT,
|
||||||
|
FU_HID_DEVICE_FLAG_NONE,
|
||||||
|
error);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
fu_usi_dock_mcu_device_rx(FuUsiDockMcuDevice *self,
|
||||||
|
guint8 cmd,
|
||||||
|
guint8 *outbuf,
|
||||||
|
gsize outbufsz,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
guint8 buf[64] = {0};
|
||||||
|
|
||||||
|
if (!fu_hid_device_get_report(FU_HID_DEVICE(self),
|
||||||
|
USB_HID_REPORT_ID2,
|
||||||
|
buf,
|
||||||
|
sizeof(buf),
|
||||||
|
FU_USI_DOCK_MCU_DEVICE_TIMEOUT,
|
||||||
|
FU_HID_DEVICE_FLAG_NONE,
|
||||||
|
error)) {
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
if (buf[0] != USB_HID_REPORT_ID2) {
|
||||||
|
g_set_error(error,
|
||||||
|
G_IO_ERROR,
|
||||||
|
G_IO_ERROR_INVALID_DATA,
|
||||||
|
"invalid ID, expected 0x%02x, got 0x%02x",
|
||||||
|
USB_HID_REPORT_ID2,
|
||||||
|
buf[0]);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
if (buf[2] != 0xFE || buf[3] != 0xFF) {
|
||||||
|
g_set_error(error,
|
||||||
|
G_IO_ERROR,
|
||||||
|
G_IO_ERROR_INVALID_DATA,
|
||||||
|
"invalid tags, expected 0x%02x:0x%02x, got 0x%02x:0x%02x",
|
||||||
|
0xFEu,
|
||||||
|
0xFFu,
|
||||||
|
buf[2],
|
||||||
|
buf[3]);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (outbuf != NULL) {
|
||||||
|
if (!fu_memcpy_safe(outbuf,
|
||||||
|
outbufsz,
|
||||||
|
0x0, /* dst */
|
||||||
|
buf,
|
||||||
|
sizeof(buf),
|
||||||
|
0x5, /* src */
|
||||||
|
outbufsz,
|
||||||
|
error))
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
fu_usi_dock_mcu_device_txrx(FuUsiDockMcuDevice *self,
|
||||||
|
guint8 tag2,
|
||||||
|
const guint8 *inbuf,
|
||||||
|
gsize inbufsz,
|
||||||
|
guint8 *outbuf,
|
||||||
|
gsize outbufsz,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
if (!fu_usi_dock_mcu_device_tx(self, tag2, inbuf, inbufsz, error))
|
||||||
|
return FALSE;
|
||||||
|
return fu_usi_dock_mcu_device_rx(self, USBUID_ISP_CMD_ALL, outbuf, outbufsz, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
fu_usi_dock_mcu_device_get_status(FuUsiDockMcuDevice *self, GError **error)
|
||||||
|
{
|
||||||
|
guint8 cmd = USBUID_ISP_DEVICE_CMD_MCU_STATUS;
|
||||||
|
guint8 response = 0;
|
||||||
|
|
||||||
|
if (!fu_usi_dock_mcu_device_txrx(self,
|
||||||
|
TAG_TAG2_CMD_MCU,
|
||||||
|
&cmd,
|
||||||
|
sizeof(cmd),
|
||||||
|
&response,
|
||||||
|
sizeof(response),
|
||||||
|
error))
|
||||||
|
return FALSE;
|
||||||
|
if (response == 0x1) {
|
||||||
|
g_set_error_literal(error, G_IO_ERROR, G_IO_ERROR_BUSY, "device is busy");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
if (response == 0xFF) {
|
||||||
|
g_set_error_literal(error, G_IO_ERROR, G_IO_ERROR_TIMED_OUT, "device timed out");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* success */
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
fu_usi_dock_mcu_device_enumerate_children(FuUsiDockMcuDevice *self, GError **error)
|
||||||
|
{
|
||||||
|
guint8 inbuf[] = {USBUID_ISP_DEVICE_CMD_READ_MCU_VERSIONPAGE,
|
||||||
|
DP_VERSION_FROM_MCU | NIC_VERSION_FROM_MCU};
|
||||||
|
guint8 outbuf[49] = {0x0};
|
||||||
|
struct {
|
||||||
|
const gchar *name;
|
||||||
|
guint8 chip_idx;
|
||||||
|
gsize offset;
|
||||||
|
} components[] = {
|
||||||
|
{"DMC", FIRMWARE_IDX_DMC_PD, G_STRUCT_OFFSET(IspVersionInMcu_t, DMC)},
|
||||||
|
{"PD", FIRMWARE_IDX_DP, G_STRUCT_OFFSET(IspVersionInMcu_t, PD)},
|
||||||
|
{"DP5x", FIRMWARE_IDX_NONE, G_STRUCT_OFFSET(IspVersionInMcu_t, DP5x)},
|
||||||
|
{"DP6x", FIRMWARE_IDX_NONE, G_STRUCT_OFFSET(IspVersionInMcu_t, DP6x)},
|
||||||
|
{"TBT4", FIRMWARE_IDX_TBT4, G_STRUCT_OFFSET(IspVersionInMcu_t, TBT4)},
|
||||||
|
{"USB3", FIRMWARE_IDX_USB3, G_STRUCT_OFFSET(IspVersionInMcu_t, USB3)},
|
||||||
|
{"USB2", FIRMWARE_IDX_USB2, G_STRUCT_OFFSET(IspVersionInMcu_t, USB2)},
|
||||||
|
{"AUDIO", FIRMWARE_IDX_AUDIO, G_STRUCT_OFFSET(IspVersionInMcu_t, AUDIO)},
|
||||||
|
{"I255", FIRMWARE_IDX_I225, G_STRUCT_OFFSET(IspVersionInMcu_t, I255)},
|
||||||
|
{"MCU", FIRMWARE_IDX_MCU, G_STRUCT_OFFSET(IspVersionInMcu_t, MCU)},
|
||||||
|
{"bcdVersion", FIRMWARE_IDX_NONE, G_STRUCT_OFFSET(IspVersionInMcu_t, bcdVersion)},
|
||||||
|
{NULL, 0, 0}};
|
||||||
|
|
||||||
|
/* assume DP and NIC in-use */
|
||||||
|
if (!fu_usi_dock_mcu_device_txrx(self,
|
||||||
|
TAG_TAG2_CMD_MCU,
|
||||||
|
inbuf,
|
||||||
|
sizeof(inbuf),
|
||||||
|
outbuf,
|
||||||
|
sizeof(outbuf),
|
||||||
|
error))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
for (guint i = 0; components[i].name != NULL; i++) {
|
||||||
|
const guint8 *val = outbuf + components[i].offset;
|
||||||
|
g_autofree gchar *version = NULL;
|
||||||
|
g_autofree gchar *instance_id = NULL;
|
||||||
|
g_autoptr(FuDevice) child = NULL;
|
||||||
|
|
||||||
|
child = fu_usi_dock_child_new(fu_device_get_context(FU_DEVICE(self)));
|
||||||
|
if (g_strcmp0(components[i].name, "bcdVersion") == 0) {
|
||||||
|
if ((val[0] == 0x00 && val[1] == 0x00) ||
|
||||||
|
(val[0] == 0xFF && val[1] == 0xFF)) {
|
||||||
|
g_debug("ignoring %s", components[i].name);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (fu_device_has_private_flag(FU_DEVICE(self),
|
||||||
|
FU_USI_DOCK_DEVICE_FLAG_VERFMT_HP)) {
|
||||||
|
version = g_strdup_printf("%x.%x.%x.%x",
|
||||||
|
val[0] >> 4,
|
||||||
|
val[0] & 0xFu,
|
||||||
|
val[1] >> 4,
|
||||||
|
val[1] & 0xFu);
|
||||||
|
fu_device_set_version_format(FU_DEVICE(self),
|
||||||
|
FWUPD_VERSION_FORMAT_QUAD);
|
||||||
|
fu_device_set_version(FU_DEVICE(self), version);
|
||||||
|
} else {
|
||||||
|
version = g_strdup_printf("%x.%x.%02x",
|
||||||
|
val[0] & 0xFu,
|
||||||
|
val[0] >> 4,
|
||||||
|
val[1]);
|
||||||
|
g_debug("ignoring %s --> %s", components[i].name, version);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
} else if (g_strcmp0(components[i].name, "DMC") == 0) {
|
||||||
|
if ((val[2] == 0x00 && val[3] == 0x00 && val[4] == 0x00) ||
|
||||||
|
(val[2] == 0xFF && val[3] == 0xFF && val[4] == 0xFF)) {
|
||||||
|
g_debug("ignoring %s", components[i].name);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
version = g_strdup_printf("%d.%d.%d", val[2], val[3], val[4]);
|
||||||
|
fu_device_set_version_format(child, FWUPD_VERSION_FORMAT_TRIPLET);
|
||||||
|
fu_device_set_version(child, version);
|
||||||
|
fu_device_set_name(child, "Dock Management Controller");
|
||||||
|
} else if (g_strcmp0(components[i].name, "PD") == 0) {
|
||||||
|
if ((val[1] == 0x00 && val[2] == 0x00 && val[3] == 0x00 &&
|
||||||
|
val[4] == 0x00) ||
|
||||||
|
(val[1] == 0xFF && val[2] == 0xFF && val[3] == 0xFF &&
|
||||||
|
val[4] == 0xFF)) {
|
||||||
|
g_debug("ignoring %s", components[i].name);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (fu_device_has_private_flag(FU_DEVICE(self),
|
||||||
|
FU_USI_DOCK_DEVICE_FLAG_VERFMT_HP)) {
|
||||||
|
version =
|
||||||
|
g_strdup_printf("%d.%d.%d.%d", val[3], val[4], val[1], val[2]);
|
||||||
|
fu_device_set_version_format(child, FWUPD_VERSION_FORMAT_QUAD);
|
||||||
|
} else {
|
||||||
|
version = g_strdup_printf("%d.%d.%d", val[2], val[3], val[4]);
|
||||||
|
fu_device_set_version_format(child, FWUPD_VERSION_FORMAT_TRIPLET);
|
||||||
|
}
|
||||||
|
fu_device_set_version(child, version);
|
||||||
|
fu_device_set_name(child, "Power Delivery");
|
||||||
|
} else if (g_strcmp0(components[i].name, "TBT4") == 0) {
|
||||||
|
if ((val[1] == 0x00 && val[2] == 0x00 && val[3] == 0x00) ||
|
||||||
|
(val[1] == 0xFF && val[2] == 0xFF && val[3] == 0xFF)) {
|
||||||
|
g_debug("ignoring %s", components[i].name);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
version = g_strdup_printf("%02x.%02x.%02x", val[1], val[2], val[3]);
|
||||||
|
fu_device_set_version_format(child, FWUPD_VERSION_FORMAT_TRIPLET);
|
||||||
|
fu_device_set_version(child, version);
|
||||||
|
fu_device_add_icon(child, "thunderbolt");
|
||||||
|
fu_device_set_name(child, "Thunderbolt 4 Controller");
|
||||||
|
} else if (g_strcmp0(components[i].name, "DP5x") == 0) {
|
||||||
|
if ((val[2] == 0x00 && val[3] == 0x00 && val[4] == 0x00) ||
|
||||||
|
(val[2] == 0xFF && val[3] == 0xFF && val[4] == 0xFF)) {
|
||||||
|
g_debug("ignoring %s", components[i].name);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
version = g_strdup_printf("%d.%02d.%03d", val[2], val[3], val[4]);
|
||||||
|
fu_device_set_version_format(child, FWUPD_VERSION_FORMAT_TRIPLET);
|
||||||
|
fu_device_set_version(child, version);
|
||||||
|
fu_device_add_icon(child, "video-display");
|
||||||
|
fu_device_set_name(child, "Display Port 5");
|
||||||
|
} else if (g_strcmp0(components[i].name, "DP6x") == 0) {
|
||||||
|
if ((val[2] == 0x00 && val[3] == 0x00 && val[4] == 0x00) ||
|
||||||
|
(val[2] == 0xFF && val[3] == 0xFF && val[4] == 0xFF)) {
|
||||||
|
g_debug("ignoring %s", components[i].name);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (fu_device_has_private_flag(FU_DEVICE(self),
|
||||||
|
FU_USI_DOCK_DEVICE_FLAG_VERFMT_HP)) {
|
||||||
|
version =
|
||||||
|
g_strdup_printf("%x.%x.%x.%x", val[3], val[4], val[2], val[1]);
|
||||||
|
fu_device_set_version_format(child, FWUPD_VERSION_FORMAT_QUAD);
|
||||||
|
fu_device_set_name(child, "USB/PD HUB");
|
||||||
|
} else {
|
||||||
|
version = g_strdup_printf("%d.%02d.%03d", val[2], val[3], val[4]);
|
||||||
|
fu_device_set_version_format(child, FWUPD_VERSION_FORMAT_TRIPLET);
|
||||||
|
fu_device_set_name(child, "Display Port 6");
|
||||||
|
}
|
||||||
|
fu_device_set_version(child, version);
|
||||||
|
fu_device_add_icon(child, "video-display");
|
||||||
|
} else if (g_strcmp0(components[i].name, "USB3") == 0) {
|
||||||
|
if ((val[3] == 0x00 && val[4] == 0x00) ||
|
||||||
|
(val[3] == 0xFF && val[4] == 0xFF)) {
|
||||||
|
g_debug("ignoring %s", components[i].name);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
version = g_strdup_printf("%02X%02X", val[3], val[4]);
|
||||||
|
fu_device_set_version_format(child, FWUPD_VERSION_FORMAT_NUMBER);
|
||||||
|
fu_device_set_version(child, version);
|
||||||
|
fu_device_set_name(child, "USB 3 Hub");
|
||||||
|
} else if (g_strcmp0(components[i].name, "USB2") == 0) {
|
||||||
|
if ((val[0] == 0x00 && val[1] == 0x00 && val[2] == 0x00 && val[3] == 0x00 &&
|
||||||
|
val[4] == 0x00) ||
|
||||||
|
(val[0] == 0xFF && val[1] == 0xFF && val[2] == 0xFF && val[3] == 0xFF &&
|
||||||
|
val[4] == 0xFF)) {
|
||||||
|
g_debug("ignoring %s", components[i].name);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
version =
|
||||||
|
g_strdup_printf("%c%c%c%c%c", val[0], val[1], val[2], val[3], val[4]);
|
||||||
|
fu_device_set_version_format(child, FWUPD_VERSION_FORMAT_PLAIN);
|
||||||
|
fu_device_set_version(child, version);
|
||||||
|
fu_device_set_name(child, "USB 2 Hub");
|
||||||
|
} else if (g_strcmp0(components[i].name, "AUDIO") == 0) {
|
||||||
|
if ((val[2] == 0x00 && val[3] == 0x00 && val[4] == 0x00) ||
|
||||||
|
(val[2] == 0xFF && val[3] == 0xFF && val[4] == 0xFF)) {
|
||||||
|
g_debug("ignoring %s", components[i].name);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
version = g_strdup_printf("%02X-%02X-%02X", val[2], val[3], val[4]);
|
||||||
|
fu_device_set_version_format(child, FWUPD_VERSION_FORMAT_PLAIN);
|
||||||
|
fu_device_set_version(child, version);
|
||||||
|
fu_device_set_name(child, "Audio Controller");
|
||||||
|
} else if (g_strcmp0(components[i].name, "I255") == 0) {
|
||||||
|
if ((val[2] == 0x00 && val[3] == 0x00 && val[4] == 0x00) ||
|
||||||
|
(val[2] == 0xFF && val[3] == 0xFF && val[4] == 0xFF)) {
|
||||||
|
g_debug("ignoring %s", components[i].name);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
version = g_strdup_printf("%x.%x.%x", val[2] >> 4, val[3], val[4]);
|
||||||
|
fu_device_set_version_format(child, FWUPD_VERSION_FORMAT_TRIPLET);
|
||||||
|
fu_device_set_version(child, version);
|
||||||
|
fu_device_add_icon(child, "network-wired");
|
||||||
|
fu_device_set_name(child, "Ethernet Adapter");
|
||||||
|
} else if (g_strcmp0(components[i].name, "MCU") == 0) {
|
||||||
|
if ((val[0] == 0x00 && val[1] == 0x00) ||
|
||||||
|
(val[0] == 0xFF && val[1] == 0xFF)) {
|
||||||
|
g_debug("ignoring %s", components[i].name);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (fu_device_has_private_flag(FU_DEVICE(self),
|
||||||
|
FU_USI_DOCK_DEVICE_FLAG_VERFMT_HP)) {
|
||||||
|
version = g_strdup_printf("%x.%x.%x.%x",
|
||||||
|
val[0] >> 4,
|
||||||
|
val[0] & 0xFu,
|
||||||
|
val[1] >> 4,
|
||||||
|
val[1] & 0xFu);
|
||||||
|
fu_device_set_version_format(child, FWUPD_VERSION_FORMAT_QUAD);
|
||||||
|
} else {
|
||||||
|
version = g_strdup_printf("%X.%X", val[0], val[1]);
|
||||||
|
fu_device_set_version_format(child, FWUPD_VERSION_FORMAT_PLAIN);
|
||||||
|
}
|
||||||
|
fu_device_set_version(child, version);
|
||||||
|
fu_device_set_name(child, "Dock Management Controller");
|
||||||
|
} else {
|
||||||
|
g_warning("unhandled %s", components[i].name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* add virtual device */
|
||||||
|
instance_id = g_strdup_printf("USB\\VID_%04X&PID_%04X&CID_%s",
|
||||||
|
fu_usb_device_get_vid(FU_USB_DEVICE(self)),
|
||||||
|
fu_usb_device_get_pid(FU_USB_DEVICE(self)),
|
||||||
|
components[i].name);
|
||||||
|
fu_device_add_instance_id(child, instance_id);
|
||||||
|
if (fu_device_get_name(child) == NULL)
|
||||||
|
fu_device_set_name(child, components[i].name);
|
||||||
|
fu_device_set_logical_id(child, components[i].name);
|
||||||
|
fu_usi_dock_child_device_set_chip_idx(FU_USI_DOCK_CHILD_DEVICE(child),
|
||||||
|
components[i].chip_idx);
|
||||||
|
fu_device_add_child(FU_DEVICE(self), child);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* success */
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
fu_usi_dock_mcu_device_setup(FuDevice *device, GError **error)
|
||||||
|
{
|
||||||
|
FuUsiDockMcuDevice *self = FU_USI_DOCK_MCU_DEVICE(device);
|
||||||
|
|
||||||
|
/* FuUsbDevice->setup */
|
||||||
|
if (!FU_DEVICE_CLASS(fu_usi_dock_mcu_device_parent_class)->setup(device, error))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
/* get status and component versions */
|
||||||
|
if (!fu_usi_dock_mcu_device_get_status(self, error))
|
||||||
|
return FALSE;
|
||||||
|
if (!fu_usi_dock_mcu_device_enumerate_children(self, error))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
/* success */
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
fu_usi_dock_mcu_device_write_chunk(FuUsiDockMcuDevice *self, FuChunk *chk, GError **error)
|
||||||
|
{
|
||||||
|
guint8 buf[64] = {0x0};
|
||||||
|
guint32 length = 0;
|
||||||
|
guint32 pagesize = fu_chunk_get_data_sz(chk);
|
||||||
|
|
||||||
|
while (pagesize != 0) {
|
||||||
|
memset(buf, 0x0, sizeof(buf));
|
||||||
|
buf[63] = TAG_TAG2_MASS_DATA_SPI;
|
||||||
|
buf[0] = USB_HID_REPORT_ID2;
|
||||||
|
|
||||||
|
/* set length and buffer */
|
||||||
|
if (pagesize >= TX_ISP_LENGTH) {
|
||||||
|
length = TX_ISP_LENGTH;
|
||||||
|
pagesize -= TX_ISP_LENGTH;
|
||||||
|
} else {
|
||||||
|
length = pagesize;
|
||||||
|
pagesize = 0;
|
||||||
|
}
|
||||||
|
buf[1] = length;
|
||||||
|
|
||||||
|
/* SetReport */
|
||||||
|
if (!fu_memcpy_safe(buf,
|
||||||
|
sizeof(buf),
|
||||||
|
0x2, /* dst */
|
||||||
|
fu_chunk_get_data(chk),
|
||||||
|
fu_chunk_get_data_sz(chk),
|
||||||
|
fu_chunk_get_data_sz(chk) - pagesize - length, /* src */
|
||||||
|
length,
|
||||||
|
error))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
if (!fu_hid_device_set_report(FU_HID_DEVICE(self),
|
||||||
|
USB_HID_REPORT_ID2,
|
||||||
|
buf,
|
||||||
|
sizeof(buf),
|
||||||
|
FU_USI_DOCK_MCU_DEVICE_TIMEOUT,
|
||||||
|
FU_HID_DEVICE_FLAG_NONE,
|
||||||
|
error))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
/* GetReport */
|
||||||
|
memset(buf, 0x0, sizeof(buf));
|
||||||
|
if (!fu_hid_device_get_report(FU_HID_DEVICE(self),
|
||||||
|
USB_HID_REPORT_ID2,
|
||||||
|
buf,
|
||||||
|
sizeof(buf),
|
||||||
|
FU_USI_DOCK_MCU_DEVICE_TIMEOUT,
|
||||||
|
FU_HID_DEVICE_FLAG_NONE,
|
||||||
|
error)) {
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
if (buf[0] != USB_HID_REPORT_ID2) {
|
||||||
|
g_set_error(error,
|
||||||
|
G_IO_ERROR,
|
||||||
|
G_IO_ERROR_INVALID_DATA,
|
||||||
|
"invalid ID, expected 0x%02x, got 0x%02x",
|
||||||
|
USB_HID_REPORT_ID2,
|
||||||
|
buf[0]);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
if (buf[63] != TAG_TAG2_CMD_SPI) {
|
||||||
|
g_set_error(error,
|
||||||
|
G_IO_ERROR,
|
||||||
|
G_IO_ERROR_INVALID_DATA,
|
||||||
|
"invalid tag2, expected 0x%02x, got 0x%02x",
|
||||||
|
(guint)TAG_TAG2_CMD_SPI,
|
||||||
|
buf[58]);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
fu_usi_dock_mcu_device_write_chunks(FuUsiDockMcuDevice *self,
|
||||||
|
GPtrArray *chunks,
|
||||||
|
FuProgress *progress,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
fu_progress_set_id(progress, G_STRLOC);
|
||||||
|
fu_progress_set_steps(progress, chunks->len);
|
||||||
|
for (guint i = 0; i < chunks->len; i++) {
|
||||||
|
FuChunk *chk = g_ptr_array_index(chunks, i);
|
||||||
|
if (!fu_usi_dock_mcu_device_write_chunk(self, chk, error)) {
|
||||||
|
g_prefix_error(error, "failed to write chunk 0x%x", i);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
fu_progress_step_done(progress);
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
fu_usi_dock_mcu_device_wait_for_spi_ready_cb(FuDevice *device, gpointer user_data, GError **error)
|
||||||
|
{
|
||||||
|
FuUsiDockMcuDevice *self = FU_USI_DOCK_MCU_DEVICE(device);
|
||||||
|
guint8 buf[] = {USBUID_ISP_DEVICE_CMD_FWBUFER_READ_STATUS};
|
||||||
|
guint8 val = 0;
|
||||||
|
|
||||||
|
if (!fu_usi_dock_mcu_device_txrx(self,
|
||||||
|
TAG_TAG2_CMD_SPI,
|
||||||
|
buf,
|
||||||
|
sizeof(buf),
|
||||||
|
&val,
|
||||||
|
sizeof(val),
|
||||||
|
error))
|
||||||
|
return FALSE;
|
||||||
|
if (val != SPI_STATE_READY) {
|
||||||
|
g_set_error(error,
|
||||||
|
G_IO_ERROR,
|
||||||
|
G_IO_ERROR_BUSY,
|
||||||
|
"SPI state is %s [0x%02x]",
|
||||||
|
fu_usi_dock_spi_state_to_string(val),
|
||||||
|
val);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* success */
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
fu_usi_dock_mcu_device_wait_for_checksum_cb(FuDevice *device, gpointer user_data, GError **error)
|
||||||
|
{
|
||||||
|
FuUsiDockMcuDevice *self = FU_USI_DOCK_MCU_DEVICE(device);
|
||||||
|
|
||||||
|
if (!fu_usi_dock_mcu_device_rx(self,
|
||||||
|
USBUID_ISP_CMD_ALL,
|
||||||
|
(guint8 *)user_data,
|
||||||
|
sizeof(guint8),
|
||||||
|
error))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
/* success */
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
fu_usi_dock_mcu_device_write_firmware_with_idx(FuUsiDockMcuDevice *self,
|
||||||
|
FuFirmware *firmware,
|
||||||
|
guint8 chip_idx,
|
||||||
|
FuProgress *progress,
|
||||||
|
FwupdInstallFlags flags,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
guint8 cmd;
|
||||||
|
guint8 val = 0x0;
|
||||||
|
g_autoptr(GBytes) fw = NULL;
|
||||||
|
g_autoptr(GPtrArray) chunks = NULL;
|
||||||
|
guint8 checksum = 0xFF;
|
||||||
|
|
||||||
|
/* progress */
|
||||||
|
fu_progress_set_id(progress, G_STRLOC);
|
||||||
|
fu_progress_add_flag(progress, FU_PROGRESS_FLAG_GUESSED);
|
||||||
|
fu_progress_add_step(progress, FWUPD_STATUS_DEVICE_BUSY, 0);
|
||||||
|
fu_progress_add_step(progress, FWUPD_STATUS_DEVICE_ERASE, 6);
|
||||||
|
fu_progress_add_step(progress, FWUPD_STATUS_DEVICE_WRITE, 40);
|
||||||
|
fu_progress_add_step(progress, FWUPD_STATUS_DEVICE_WRITE, 13);
|
||||||
|
fu_progress_add_step(progress, FWUPD_STATUS_DEVICE_WRITE, 42);
|
||||||
|
|
||||||
|
/* initial external flash */
|
||||||
|
cmd = USBUID_ISP_DEVICE_CMD_FWBUFER_INITIAL;
|
||||||
|
if (!fu_usi_dock_mcu_device_txrx(self,
|
||||||
|
TAG_TAG2_CMD_SPI,
|
||||||
|
&cmd,
|
||||||
|
sizeof(cmd),
|
||||||
|
&val,
|
||||||
|
sizeof(val),
|
||||||
|
error))
|
||||||
|
return FALSE;
|
||||||
|
if (val != SPI_STATE_READY) {
|
||||||
|
g_set_error(error,
|
||||||
|
G_IO_ERROR,
|
||||||
|
G_IO_ERROR_INVALID_DATA,
|
||||||
|
"invalid state for CMD_FWBUFER_INITIAL, got 0x%02x",
|
||||||
|
val);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
fu_progress_step_done(progress);
|
||||||
|
|
||||||
|
/* erase external flash */
|
||||||
|
cmd = USBUID_ISP_DEVICE_CMD_FWBUFER_ERASE_FLASH;
|
||||||
|
if (!fu_usi_dock_mcu_device_txrx(self,
|
||||||
|
TAG_TAG2_CMD_SPI,
|
||||||
|
&cmd,
|
||||||
|
sizeof(cmd),
|
||||||
|
NULL,
|
||||||
|
0x0,
|
||||||
|
error))
|
||||||
|
return FALSE;
|
||||||
|
if (!fu_device_retry(FU_DEVICE(self),
|
||||||
|
fu_usi_dock_mcu_device_wait_for_spi_ready_cb,
|
||||||
|
30,
|
||||||
|
NULL,
|
||||||
|
error)) {
|
||||||
|
g_prefix_error(error, "failed to wait for erase: ");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
fu_progress_step_done(progress);
|
||||||
|
|
||||||
|
/* write external flash */
|
||||||
|
cmd = USBUID_ISP_DEVICE_CMD_FWBUFER_PROGRAM;
|
||||||
|
if (!fu_usi_dock_mcu_device_txrx(self,
|
||||||
|
TAG_TAG2_CMD_SPI,
|
||||||
|
&cmd,
|
||||||
|
sizeof(cmd),
|
||||||
|
NULL,
|
||||||
|
0x0,
|
||||||
|
error))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
fw = fu_firmware_get_bytes(firmware, error);
|
||||||
|
if (fw == NULL)
|
||||||
|
return FALSE;
|
||||||
|
chunks = fu_chunk_array_new_from_bytes(fw, 0x0, 0x0, W25Q16DV_PAGE_SIZE);
|
||||||
|
if (!fu_usi_dock_mcu_device_write_chunks(self,
|
||||||
|
chunks,
|
||||||
|
fu_progress_get_child(progress),
|
||||||
|
error))
|
||||||
|
return FALSE;
|
||||||
|
fu_progress_step_done(progress);
|
||||||
|
|
||||||
|
/* file transfer – finished */
|
||||||
|
cmd = USBUID_ISP_DEVICE_CMD_FWBUFER_TRANSFER_FINISH;
|
||||||
|
if (!fu_usi_dock_mcu_device_txrx(self,
|
||||||
|
TAG_TAG2_CMD_SPI,
|
||||||
|
&cmd,
|
||||||
|
sizeof(cmd),
|
||||||
|
NULL,
|
||||||
|
0x0,
|
||||||
|
error))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
/* MCU checksum */
|
||||||
|
if (!fu_device_retry(FU_DEVICE(self),
|
||||||
|
fu_usi_dock_mcu_device_wait_for_checksum_cb,
|
||||||
|
300,
|
||||||
|
&checksum,
|
||||||
|
error)) {
|
||||||
|
g_prefix_error(error, "failed to wait for checksum: ");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (checksum != 0x0) {
|
||||||
|
g_set_error(error,
|
||||||
|
G_IO_ERROR,
|
||||||
|
G_IO_ERROR_INVALID_DATA,
|
||||||
|
"invalid checksum result for CMD_FWBUFER_CHECKSUM, got 0x%02x",
|
||||||
|
checksum);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
fu_progress_step_done(progress);
|
||||||
|
|
||||||
|
/* internal flash */
|
||||||
|
cmd = USBUID_ISP_INTERNAL_FW_CMD_UPDATE_FW;
|
||||||
|
if (!fu_usi_dock_mcu_device_txrx(self,
|
||||||
|
TAG_TAG2_CMD_MCU,
|
||||||
|
&cmd,
|
||||||
|
sizeof(cmd),
|
||||||
|
NULL,
|
||||||
|
0x0,
|
||||||
|
error))
|
||||||
|
return FALSE;
|
||||||
|
fu_progress_step_done(progress);
|
||||||
|
|
||||||
|
/* success */
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
fu_usi_dock_mcu_device_write_firmware(FuDevice *device,
|
||||||
|
FuFirmware *firmware,
|
||||||
|
FuProgress *progress,
|
||||||
|
FwupdInstallFlags flags,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
return fu_usi_dock_mcu_device_write_firmware_with_idx(FU_USI_DOCK_MCU_DEVICE(device),
|
||||||
|
firmware,
|
||||||
|
0xFF, /* all */
|
||||||
|
progress,
|
||||||
|
flags,
|
||||||
|
error);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
fu_usi_dock_mcu_device_attach(FuDevice *device, FuProgress *progress, GError **error)
|
||||||
|
{
|
||||||
|
fu_device_set_remove_delay(device, 500000);
|
||||||
|
fu_device_add_flag(device, FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG);
|
||||||
|
|
||||||
|
/* success */
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
fu_usi_dock_mcu_device_set_progress(FuDevice *self, FuProgress *progress)
|
||||||
|
{
|
||||||
|
fu_progress_set_id(progress, G_STRLOC);
|
||||||
|
fu_progress_add_flag(progress, FU_PROGRESS_FLAG_GUESSED);
|
||||||
|
fu_progress_add_step(progress, FWUPD_STATUS_DEVICE_ERASE, 2); /* erase */
|
||||||
|
fu_progress_add_step(progress, FWUPD_STATUS_DEVICE_WRITE, 90); /* write */
|
||||||
|
fu_progress_add_step(progress, FWUPD_STATUS_DEVICE_RESTART, 6); /* attach */
|
||||||
|
fu_progress_add_step(progress, FWUPD_STATUS_DEVICE_BUSY, 2); /* reload */
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
fu_usi_dock_mcu_device_init(FuUsiDockMcuDevice *self)
|
||||||
|
{
|
||||||
|
fu_device_add_flag(FU_DEVICE(self), FWUPD_DEVICE_FLAG_UPDATABLE);
|
||||||
|
fu_device_add_flag(FU_DEVICE(self), FWUPD_DEVICE_FLAG_REQUIRE_AC);
|
||||||
|
fu_device_add_flag(FU_DEVICE(self), FWUPD_DEVICE_FLAG_DUAL_IMAGE);
|
||||||
|
|
||||||
|
fu_device_add_internal_flag(FU_DEVICE(self), FU_DEVICE_INTERNAL_FLAG_NO_SERIAL_NUMBER);
|
||||||
|
fu_device_add_internal_flag(FU_DEVICE(self), FU_DEVICE_INTERNAL_FLAG_INHIBIT_CHILDREN);
|
||||||
|
fu_device_add_internal_flag(FU_DEVICE(self), FU_DEVICE_INTERNAL_FLAG_REPLUG_MATCH_GUID);
|
||||||
|
|
||||||
|
fu_device_register_private_flag(FU_DEVICE(self),
|
||||||
|
FU_USI_DOCK_DEVICE_FLAG_VERFMT_HP,
|
||||||
|
"verfmt-hp");
|
||||||
|
fu_hid_device_add_flag(FU_HID_DEVICE(self), FU_HID_DEVICE_FLAG_USE_INTERRUPT_TRANSFER);
|
||||||
|
fu_device_add_protocol(FU_DEVICE(self), "com.usi.dock");
|
||||||
|
fu_device_set_version_format(FU_DEVICE(self), FWUPD_VERSION_FORMAT_NUMBER);
|
||||||
|
fu_device_set_remove_delay(FU_DEVICE(self), FU_DEVICE_REMOVE_DELAY_RE_ENUMERATE);
|
||||||
|
fu_device_retry_set_delay(FU_DEVICE(self), 1000);
|
||||||
|
fu_device_add_icon(FU_DEVICE(self), "dock");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
fu_usi_dock_mcu_device_class_init(FuUsiDockMcuDeviceClass *klass)
|
||||||
|
{
|
||||||
|
FuDeviceClass *klass_device = FU_DEVICE_CLASS(klass);
|
||||||
|
|
||||||
|
klass_device->write_firmware = fu_usi_dock_mcu_device_write_firmware;
|
||||||
|
klass_device->attach = fu_usi_dock_mcu_device_attach;
|
||||||
|
klass_device->setup = fu_usi_dock_mcu_device_setup;
|
||||||
|
klass_device->set_progress = fu_usi_dock_mcu_device_set_progress;
|
||||||
|
}
|
23
plugins/usi-dock/fu-usi-dock-mcu-device.h
Normal file
23
plugins/usi-dock/fu-usi-dock-mcu-device.h
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2021 Richard Hughes <richard@hughsie.com>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: LGPL-2.1+
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <fwupdplugin.h>
|
||||||
|
|
||||||
|
#define FU_TYPE_USI_DOCK_MCU_DEVICE (fu_usi_dock_mcu_device_get_type())
|
||||||
|
G_DECLARE_FINAL_TYPE(FuUsiDockMcuDevice,
|
||||||
|
fu_usi_dock_mcu_device,
|
||||||
|
FU,
|
||||||
|
USI_DOCK_MCU_DEVICE,
|
||||||
|
FuHidDevice)
|
||||||
|
gboolean
|
||||||
|
fu_usi_dock_mcu_device_write_firmware_with_idx(FuUsiDockMcuDevice *self,
|
||||||
|
FuFirmware *firmware,
|
||||||
|
guint8 chip_idx,
|
||||||
|
FuProgress *progress,
|
||||||
|
FwupdInstallFlags flags,
|
||||||
|
GError **error);
|
33
plugins/usi-dock/meson.build
Normal file
33
plugins/usi-dock/meson.build
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
if get_option('gusb')
|
||||||
|
cargs = ['-DG_LOG_DOMAIN="FuPluginUsiDock"']
|
||||||
|
|
||||||
|
install_data(['usi-dock.quirk'],
|
||||||
|
install_dir: join_paths(datadir, 'fwupd', 'quirks.d')
|
||||||
|
)
|
||||||
|
|
||||||
|
shared_module('fu_plugin_usi_dock',
|
||||||
|
fu_hash,
|
||||||
|
sources : [
|
||||||
|
'fu-usi-dock-common.c',
|
||||||
|
'fu-usi-dock-child-device.c',
|
||||||
|
'fu-usi-dock-dmc-device.c',
|
||||||
|
'fu-usi-dock-mcu-device.c',
|
||||||
|
'fu-plugin-usi-dock.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,
|
||||||
|
],
|
||||||
|
)
|
||||||
|
endif
|
15
plugins/usi-dock/usi-dock.quirk
Normal file
15
plugins/usi-dock/usi-dock.quirk
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
[USB\VID_17EF&PID_30B4]
|
||||||
|
Plugin = usi_dock
|
||||||
|
GType = FuUsiDockMcuDevice
|
||||||
|
Name = ThinkPad Thunderbolt 4 Dock
|
||||||
|
|
||||||
|
[USB\VID_17EF&PID_30B5]
|
||||||
|
Plugin = usi_dock
|
||||||
|
GType = FuUsiDockDmcDevice
|
||||||
|
ParentGuid = USB\VID_17EF&PID_30B4
|
||||||
|
|
||||||
|
[USB\VID_03F0&PID_0505]
|
||||||
|
Plugin = usi_dock
|
||||||
|
GType = FuUsiDockMcuDevice
|
||||||
|
Name = USB-C G2 Multiport Hub MCU Controller
|
||||||
|
Flags = verfmt-hp
|
Loading…
Reference in New Issue
Block a user