mirror of
https://git.proxmox.com/git/fwupd
synced 2025-08-08 05:17:31 +00:00
elantp: Add support for more haptic hardware
Support ic_type 0x12 & 0x13, iap_ver 0x3 & 0x5 iap flow.
This commit is contained in:
parent
be8fb81103
commit
f93f5ebffa
@ -23,8 +23,10 @@
|
|||||||
#define ETP_CMD_I2C_OSM_VERSION 0x0103
|
#define ETP_CMD_I2C_OSM_VERSION 0x0103
|
||||||
#define ETP_CMD_I2C_GET_HID_ID 0x0100
|
#define ETP_CMD_I2C_GET_HID_ID 0x0100
|
||||||
#define ETP_CMD_I2C_IAP_TYPE 0x0304
|
#define ETP_CMD_I2C_IAP_TYPE 0x0304
|
||||||
|
#define ETP_CMD_I2C_FW_PW 0x030E
|
||||||
|
#define ETP_CMD_FORCE_ADDR 0x03AD
|
||||||
|
|
||||||
#define ETP_CMD_I2C_FLIM_TYPE_ENABLE 0x0104
|
#define ETP_CMD_I2C_FORCE_TYPE_ENABLE 0x0104
|
||||||
#define ETP_CMD_I2C_SET_EEPROM_CTRL 0x0321
|
#define ETP_CMD_I2C_SET_EEPROM_CTRL 0x0321
|
||||||
#define ETP_CMD_I2C_GET_EEPROM_FW_VERSION 0x0710
|
#define ETP_CMD_I2C_GET_EEPROM_FW_VERSION 0x0710
|
||||||
#define ETP_CMD_I2C_GET_EEPROM_IAP_VERSION 0x0711
|
#define ETP_CMD_I2C_GET_EEPROM_IAP_VERSION 0x0711
|
||||||
@ -40,15 +42,18 @@
|
|||||||
#define ETP_CMD_I2C_EEPROM_WRITE_INFOMATION 0x4600
|
#define ETP_CMD_I2C_EEPROM_WRITE_INFOMATION 0x4600
|
||||||
#define ETP_CMD_I2C_EEPROM_WRITE_CHECKSUM 0x048B
|
#define ETP_CMD_I2C_EEPROM_WRITE_CHECKSUM 0x048B
|
||||||
|
|
||||||
#define ETP_FW_FLIM_TYPE_ENABLE_BIT 0x1
|
#define ETP_I2C_IC13_IAPV5_PW 0x37CA
|
||||||
#define ETP_FW_EEPROM_ENABLE_BIT 0x2
|
|
||||||
|
#define ETP_FW_FORCE_TYPE_ENABLE_BIT 0x1
|
||||||
|
#define ETP_FW_EEPROM_ENABLE_BIT 0x2
|
||||||
|
|
||||||
#define ETP_I2C_IAP_TYPE_REG 0x0040
|
#define ETP_I2C_IAP_TYPE_REG 0x0040
|
||||||
|
|
||||||
#define ETP_I2C_ENABLE_REPORT 0x0800
|
#define ETP_I2C_ENABLE_REPORT 0x0800
|
||||||
|
|
||||||
#define ETP_I2C_IAP_RESET 0xF0F0
|
#define ETP_I2C_IAP_RESET 0xF0F0
|
||||||
#define ETP_I2C_MAIN_MODE_ON (1 << 9)
|
#define ETP_I2C_MAIN_MODE_ON (1 << 9)
|
||||||
|
#define ETP_I2C_MAIN_MODE_ON2 (1 << 12)
|
||||||
|
|
||||||
#define ETP_I2C_IAP_REG_L 0x01
|
#define ETP_I2C_IAP_REG_L 0x01
|
||||||
#define ETP_I2C_IAP_REG_H 0x06
|
#define ETP_I2C_IAP_REG_H 0x06
|
||||||
|
@ -14,13 +14,20 @@
|
|||||||
struct _FuElantpFirmware {
|
struct _FuElantpFirmware {
|
||||||
FuFirmwareClass parent_instance;
|
FuFirmwareClass parent_instance;
|
||||||
guint16 module_id;
|
guint16 module_id;
|
||||||
|
guint16 ic_type;
|
||||||
guint16 iap_addr;
|
guint16 iap_addr;
|
||||||
|
guint16 iap_ver;
|
||||||
|
gboolean force_table_support;
|
||||||
|
guint32 force_table_addr;
|
||||||
};
|
};
|
||||||
|
|
||||||
G_DEFINE_TYPE(FuElantpFirmware, fu_elantp_firmware, FU_TYPE_FIRMWARE)
|
G_DEFINE_TYPE(FuElantpFirmware, fu_elantp_firmware, FU_TYPE_FIRMWARE)
|
||||||
|
|
||||||
/* firmware block update */
|
/* firmware block update */
|
||||||
#define ETP_IAP_START_ADDR_WRDS 0x0083
|
#define ETP_IC_TYPE_ADDR_WRDS 0x0080
|
||||||
|
#define ETP_IAP_VER_ADDR_WRDS 0x0082
|
||||||
|
#define ETP_IAP_START_ADDR_WRDS 0x0083
|
||||||
|
#define ETP_IAP_FORCETABLE_ADDR_V5 0x0085
|
||||||
|
|
||||||
const guint8 elantp_signature[] = {0xAA, 0x55, 0xCC, 0x33, 0xFF, 0xFF};
|
const guint8 elantp_signature[] = {0xAA, 0x55, 0xCC, 0x33, 0xFF, 0xFF};
|
||||||
|
|
||||||
@ -31,6 +38,13 @@ fu_elantp_firmware_get_module_id(FuElantpFirmware *self)
|
|||||||
return self->module_id;
|
return self->module_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
guint16
|
||||||
|
fu_elantp_firmware_get_ic_type(FuElantpFirmware *self)
|
||||||
|
{
|
||||||
|
g_return_val_if_fail(FU_IS_ELANTP_FIRMWARE(self), 0);
|
||||||
|
return self->ic_type;
|
||||||
|
}
|
||||||
|
|
||||||
guint16
|
guint16
|
||||||
fu_elantp_firmware_get_iap_addr(FuElantpFirmware *self)
|
fu_elantp_firmware_get_iap_addr(FuElantpFirmware *self)
|
||||||
{
|
{
|
||||||
@ -38,6 +52,27 @@ fu_elantp_firmware_get_iap_addr(FuElantpFirmware *self)
|
|||||||
return self->iap_addr;
|
return self->iap_addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
guint16
|
||||||
|
fu_elantp_firmware_get_iap_ver(FuElantpFirmware *self)
|
||||||
|
{
|
||||||
|
g_return_val_if_fail(FU_IS_ELANTP_FIRMWARE(self), 0);
|
||||||
|
return self->iap_ver;
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
fu_elantp_firmware_get_forcetable_support(FuElantpFirmware *self)
|
||||||
|
{
|
||||||
|
g_return_val_if_fail(FU_IS_ELANTP_FIRMWARE(self), FALSE);
|
||||||
|
return self->force_table_support;
|
||||||
|
}
|
||||||
|
|
||||||
|
guint32
|
||||||
|
fu_elantp_firmware_get_forcetable_addr(FuElantpFirmware *self)
|
||||||
|
{
|
||||||
|
g_return_val_if_fail(FU_IS_ELANTP_FIRMWARE(self), 0);
|
||||||
|
return self->force_table_addr;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
fu_elantp_firmware_export(FuFirmware *firmware, FuFirmwareExportFlags flags, XbBuilderNode *bn)
|
fu_elantp_firmware_export(FuFirmware *firmware, FuFirmwareExportFlags flags, XbBuilderNode *bn)
|
||||||
{
|
{
|
||||||
@ -49,6 +84,7 @@ fu_elantp_firmware_export(FuFirmware *firmware, FuFirmwareExportFlags flags, XbB
|
|||||||
static gboolean
|
static gboolean
|
||||||
fu_elantp_firmware_check_magic(FuFirmware *firmware, GBytes *fw, gsize offset, GError **error)
|
fu_elantp_firmware_check_magic(FuFirmware *firmware, GBytes *fw, gsize offset, GError **error)
|
||||||
{
|
{
|
||||||
|
FuElantpFirmware *self = FU_ELANTP_FIRMWARE(firmware);
|
||||||
gsize bufsz = g_bytes_get_size(fw);
|
gsize bufsz = g_bytes_get_size(fw);
|
||||||
const guint8 *buf = g_bytes_get_data(fw, NULL);
|
const guint8 *buf = g_bytes_get_data(fw, NULL);
|
||||||
|
|
||||||
@ -72,6 +108,28 @@ fu_elantp_firmware_check_magic(FuFirmware *firmware, GBytes *fw, gsize offset, G
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (self->force_table_addr != 0) {
|
||||||
|
for (gsize i = 0; i < sizeof(elantp_signature); i++) {
|
||||||
|
guint8 tmp = 0x0;
|
||||||
|
if (!fu_memread_uint8_safe(buf,
|
||||||
|
bufsz,
|
||||||
|
self->force_table_addr - 1 -
|
||||||
|
sizeof(elantp_signature) + i,
|
||||||
|
&tmp,
|
||||||
|
error))
|
||||||
|
return FALSE;
|
||||||
|
if (tmp != elantp_signature[i]) {
|
||||||
|
g_set_error(error,
|
||||||
|
FWUPD_ERROR,
|
||||||
|
FWUPD_ERROR_INVALID_FILE,
|
||||||
|
"signature[%u] invalid: got 0x%2x, expected 0x%02x",
|
||||||
|
(guint)i,
|
||||||
|
tmp,
|
||||||
|
elantp_signature[i]);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
/* success */
|
/* success */
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
@ -86,8 +144,10 @@ fu_elantp_firmware_parse(FuFirmware *firmware,
|
|||||||
FuElantpFirmware *self = FU_ELANTP_FIRMWARE(firmware);
|
FuElantpFirmware *self = FU_ELANTP_FIRMWARE(firmware);
|
||||||
gsize bufsz = 0;
|
gsize bufsz = 0;
|
||||||
guint16 iap_addr_wrds;
|
guint16 iap_addr_wrds;
|
||||||
|
guint16 force_table_addr_wrds;
|
||||||
guint16 module_id_wrds;
|
guint16 module_id_wrds;
|
||||||
const guint8 *buf = g_bytes_get_data(fw, &bufsz);
|
const guint8 *buf = g_bytes_get_data(fw, &bufsz);
|
||||||
|
g_autoptr(GError) error_local = NULL;
|
||||||
|
|
||||||
/* presumably in words */
|
/* presumably in words */
|
||||||
if (!fu_memread_uint16_safe(buf,
|
if (!fu_memread_uint16_safe(buf,
|
||||||
@ -130,6 +190,50 @@ fu_elantp_firmware_parse(FuFirmware *firmware,
|
|||||||
G_LITTLE_ENDIAN,
|
G_LITTLE_ENDIAN,
|
||||||
error))
|
error))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
if (!fu_memread_uint16_safe(buf,
|
||||||
|
bufsz,
|
||||||
|
offset + ETP_IC_TYPE_ADDR_WRDS * 2,
|
||||||
|
&self->ic_type,
|
||||||
|
G_LITTLE_ENDIAN,
|
||||||
|
error))
|
||||||
|
return FALSE;
|
||||||
|
if (!fu_memread_uint16_safe(buf,
|
||||||
|
bufsz,
|
||||||
|
offset + ETP_IAP_VER_ADDR_WRDS * 2,
|
||||||
|
&self->iap_ver,
|
||||||
|
G_LITTLE_ENDIAN,
|
||||||
|
error))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
if (self->ic_type != 0x12 && self->ic_type != 0x13)
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
if (self->iap_ver <= 4) {
|
||||||
|
if (!fu_memread_uint16_safe(buf,
|
||||||
|
bufsz,
|
||||||
|
offset + (self->iap_addr + 6),
|
||||||
|
&force_table_addr_wrds,
|
||||||
|
G_LITTLE_ENDIAN,
|
||||||
|
&error_local)) {
|
||||||
|
g_debug("forcetable address wrong: %s", error_local->message);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!fu_memread_uint16_safe(buf,
|
||||||
|
bufsz,
|
||||||
|
offset + ETP_IAP_FORCETABLE_ADDR_V5 * 2,
|
||||||
|
&force_table_addr_wrds,
|
||||||
|
G_LITTLE_ENDIAN,
|
||||||
|
&error_local)) {
|
||||||
|
g_debug("forcetable address wrong: %s", error_local->message);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (force_table_addr_wrds % 32 == 0) {
|
||||||
|
self->force_table_addr = force_table_addr_wrds * 2;
|
||||||
|
self->force_table_support = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
/* success */
|
/* success */
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
@ -16,4 +16,12 @@ fu_elantp_firmware_new(void);
|
|||||||
guint16
|
guint16
|
||||||
fu_elantp_firmware_get_module_id(FuElantpFirmware *self);
|
fu_elantp_firmware_get_module_id(FuElantpFirmware *self);
|
||||||
guint16
|
guint16
|
||||||
|
fu_elantp_firmware_get_ic_type(FuElantpFirmware *self);
|
||||||
|
guint16
|
||||||
fu_elantp_firmware_get_iap_addr(FuElantpFirmware *self);
|
fu_elantp_firmware_get_iap_addr(FuElantpFirmware *self);
|
||||||
|
guint16
|
||||||
|
fu_elantp_firmware_get_iap_ver(FuElantpFirmware *self);
|
||||||
|
gboolean
|
||||||
|
fu_elantp_firmware_get_forcetable_support(FuElantpFirmware *self);
|
||||||
|
guint32
|
||||||
|
fu_elantp_firmware_get_forcetable_addr(FuElantpFirmware *self);
|
||||||
|
@ -19,11 +19,15 @@
|
|||||||
struct _FuElantpHidDevice {
|
struct _FuElantpHidDevice {
|
||||||
FuUdevDevice parent_instance;
|
FuUdevDevice parent_instance;
|
||||||
guint16 ic_page_count;
|
guint16 ic_page_count;
|
||||||
|
guint16 ic_type;
|
||||||
guint16 iap_type;
|
guint16 iap_type;
|
||||||
guint16 iap_ctrl;
|
guint16 iap_ctrl;
|
||||||
guint16 iap_password;
|
guint16 iap_password;
|
||||||
|
guint16 iap_ver;
|
||||||
guint16 module_id;
|
guint16 module_id;
|
||||||
guint16 fw_page_size;
|
guint16 fw_page_size;
|
||||||
|
gboolean force_table_support;
|
||||||
|
guint32 force_table_addr;
|
||||||
guint8 pattern;
|
guint8 pattern;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -152,6 +156,14 @@ fu_elantp_hid_device_ensure_iap_ctrl(FuElantpHidDevice *self, GError **error)
|
|||||||
self->iap_ctrl = fu_memread_uint16(buf, G_LITTLE_ENDIAN);
|
self->iap_ctrl = fu_memread_uint16(buf, G_LITTLE_ENDIAN);
|
||||||
|
|
||||||
/* in bootloader mode? */
|
/* in bootloader mode? */
|
||||||
|
if (self->force_table_support && self->iap_ver <= 5) {
|
||||||
|
if ((self->iap_ctrl & ETP_I2C_MAIN_MODE_ON2) == 0)
|
||||||
|
fu_device_add_flag(FU_DEVICE(self), FWUPD_DEVICE_FLAG_IS_BOOTLOADER);
|
||||||
|
else
|
||||||
|
fu_device_remove_flag(FU_DEVICE(self), FWUPD_DEVICE_FLAG_IS_BOOTLOADER);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
if ((self->iap_ctrl & ETP_I2C_MAIN_MODE_ON) == 0)
|
if ((self->iap_ctrl & ETP_I2C_MAIN_MODE_ON) == 0)
|
||||||
fu_device_add_flag(FU_DEVICE(self), FWUPD_DEVICE_FLAG_IS_BOOTLOADER);
|
fu_device_add_flag(FU_DEVICE(self), FWUPD_DEVICE_FLAG_IS_BOOTLOADER);
|
||||||
else
|
else
|
||||||
@ -160,13 +172,47 @@ fu_elantp_hid_device_ensure_iap_ctrl(FuElantpHidDevice *self, GError **error)
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
fu_elantp_hid_device_read_force_table_enable(FuElantpHidDevice *self, GError **error)
|
||||||
|
{
|
||||||
|
guint8 buf[2] = {0x0};
|
||||||
|
guint16 value;
|
||||||
|
|
||||||
|
if (!fu_elantp_hid_device_read_cmd(self,
|
||||||
|
ETP_CMD_I2C_FORCE_TYPE_ENABLE,
|
||||||
|
buf,
|
||||||
|
sizeof(buf),
|
||||||
|
error)) {
|
||||||
|
g_prefix_error(error, "failed to read force type cmd: ");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
value = fu_memread_uint16(buf, G_LITTLE_ENDIAN);
|
||||||
|
if (value == 0xFFFF || value == ETP_CMD_I2C_FORCE_TYPE_ENABLE) {
|
||||||
|
g_set_error(error,
|
||||||
|
FWUPD_ERROR,
|
||||||
|
FWUPD_ERROR_NOT_SUPPORTED,
|
||||||
|
"forcetype cmd not supported");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
if ((buf[0] & ETP_FW_FORCE_TYPE_ENABLE_BIT) == 0) {
|
||||||
|
g_set_error(error,
|
||||||
|
FWUPD_ERROR,
|
||||||
|
FWUPD_ERROR_NOT_SUPPORTED,
|
||||||
|
"force type table not supported");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* success */
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
fu_elantp_hid_device_read_hatpic_enable(FuElantpHidDevice *self, GError **error)
|
fu_elantp_hid_device_read_hatpic_enable(FuElantpHidDevice *self, GError **error)
|
||||||
{
|
{
|
||||||
guint8 buf[2] = {0x0};
|
guint8 buf[2] = {0x0};
|
||||||
guint16 value;
|
guint16 value;
|
||||||
if (!fu_elantp_hid_device_read_cmd(self,
|
if (!fu_elantp_hid_device_read_cmd(self,
|
||||||
ETP_CMD_I2C_FLIM_TYPE_ENABLE,
|
ETP_CMD_I2C_FORCE_TYPE_ENABLE,
|
||||||
buf,
|
buf,
|
||||||
sizeof(buf),
|
sizeof(buf),
|
||||||
error)) {
|
error)) {
|
||||||
@ -174,12 +220,12 @@ fu_elantp_hid_device_read_hatpic_enable(FuElantpHidDevice *self, GError **error)
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
value = fu_memread_uint16(buf, G_LITTLE_ENDIAN);
|
value = fu_memread_uint16(buf, G_LITTLE_ENDIAN);
|
||||||
if (value == 0xFFFF || value == ETP_CMD_I2C_FLIM_TYPE_ENABLE) {
|
if (value == 0xFFFF || value == ETP_CMD_I2C_FORCE_TYPE_ENABLE) {
|
||||||
g_set_error(error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED, "not hapticpad");
|
g_set_error(error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED, "not hapticpad");
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((buf[0] & ETP_FW_FLIM_TYPE_ENABLE_BIT) == 0 ||
|
if ((buf[0] & ETP_FW_FORCE_TYPE_ENABLE_BIT) == 0 ||
|
||||||
(buf[0] & ETP_FW_EEPROM_ENABLE_BIT) == 0) {
|
(buf[0] & ETP_FW_EEPROM_ENABLE_BIT) == 0) {
|
||||||
g_set_error(error,
|
g_set_error(error,
|
||||||
FWUPD_ERROR,
|
FWUPD_ERROR,
|
||||||
@ -192,19 +238,84 @@ fu_elantp_hid_device_read_hatpic_enable(FuElantpHidDevice *self, GError **error)
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
fu_elantp_hid_device_get_forcetable_address(FuElantpHidDevice *self, GError **error)
|
||||||
|
{
|
||||||
|
guint8 buf[2] = {0x0};
|
||||||
|
guint16 addr_wrds;
|
||||||
|
|
||||||
|
if (self->iap_ver == 0x3) {
|
||||||
|
self->force_table_addr = 0xFF40 * 2;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
if (!fu_elantp_hid_device_read_cmd(self, ETP_CMD_FORCE_ADDR, buf, sizeof(buf), error)) {
|
||||||
|
g_prefix_error(error, "failed to read force table address cmd: ");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
addr_wrds = fu_memread_uint16(buf, G_LITTLE_ENDIAN);
|
||||||
|
if (addr_wrds % 32 != 0) {
|
||||||
|
g_set_error(error,
|
||||||
|
FWUPD_ERROR,
|
||||||
|
FWUPD_ERROR_NOT_SUPPORTED,
|
||||||
|
"illegal force table address (%x)",
|
||||||
|
addr_wrds);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
self->force_table_addr = addr_wrds * 2;
|
||||||
|
|
||||||
|
/* success */
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
fu_elantp_hid_device_write_fw_password(FuElantpHidDevice *self,
|
||||||
|
guint16 ic_type,
|
||||||
|
guint16 iap_ver,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
guint8 buf[2] = {0x0};
|
||||||
|
guint16 pw = ETP_I2C_IC13_IAPV5_PW;
|
||||||
|
guint16 value;
|
||||||
|
|
||||||
|
if (iap_ver < 0x5 || ic_type != 0x13)
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
if (!fu_elantp_hid_device_write_cmd(self, ETP_CMD_I2C_FW_PW, pw, error)) {
|
||||||
|
g_prefix_error(error, "failed to write fw password cmd: ");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!fu_elantp_hid_device_read_cmd(self, ETP_CMD_I2C_FW_PW, buf, sizeof(buf), error)) {
|
||||||
|
g_prefix_error(error, "failed to read fw password cmd: ");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
value = fu_memread_uint16(buf, G_LITTLE_ENDIAN);
|
||||||
|
if (value != pw) {
|
||||||
|
g_set_error(error,
|
||||||
|
FWUPD_ERROR,
|
||||||
|
FWUPD_ERROR_NOT_SUPPORTED,
|
||||||
|
"can't set fw password got:%x",
|
||||||
|
value);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* success */
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
fu_elantp_hid_device_setup(FuDevice *device, GError **error)
|
fu_elantp_hid_device_setup(FuDevice *device, GError **error)
|
||||||
{
|
{
|
||||||
FuElantpHidDevice *self = FU_ELANTP_HID_DEVICE(device);
|
FuElantpHidDevice *self = FU_ELANTP_HID_DEVICE(device);
|
||||||
FuUdevDevice *udev_device = FU_UDEV_DEVICE(device);
|
FuUdevDevice *udev_device = FU_UDEV_DEVICE(device);
|
||||||
guint16 fwver;
|
guint16 fwver;
|
||||||
guint16 iap_ver;
|
|
||||||
guint16 tmp;
|
guint16 tmp;
|
||||||
guint8 buf[2] = {0x0};
|
guint8 buf[2] = {0x0};
|
||||||
guint8 ic_type;
|
|
||||||
g_autofree gchar *version_bl = NULL;
|
g_autofree gchar *version_bl = NULL;
|
||||||
g_autofree gchar *version = NULL;
|
g_autofree gchar *version = NULL;
|
||||||
g_autoptr(GError) error_local = NULL;
|
g_autoptr(GError) error_local = NULL;
|
||||||
|
g_autoptr(GError) error_forcetable = NULL;
|
||||||
|
|
||||||
/* get pattern */
|
/* get pattern */
|
||||||
if (!fu_elantp_hid_device_read_cmd(self, ETP_CMD_I2C_GET_HID_ID, buf, sizeof(buf), error)) {
|
if (!fu_elantp_hid_device_read_cmd(self, ETP_CMD_I2C_GET_HID_ID, buf, sizeof(buf), error)) {
|
||||||
@ -236,11 +347,11 @@ fu_elantp_hid_device_setup(FuDevice *device, GError **error)
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
if (self->pattern >= 1) {
|
if (self->pattern >= 1) {
|
||||||
iap_ver = buf[1];
|
self->iap_ver = buf[1];
|
||||||
} else {
|
} else {
|
||||||
iap_ver = fu_memread_uint16(buf, G_LITTLE_ENDIAN);
|
self->iap_ver = fu_memread_uint16(buf, G_LITTLE_ENDIAN);
|
||||||
}
|
}
|
||||||
version_bl = fu_version_from_uint16(iap_ver, FWUPD_VERSION_FORMAT_HEX);
|
version_bl = fu_version_from_uint16(self->iap_ver, FWUPD_VERSION_FORMAT_HEX);
|
||||||
fu_device_set_version_bootloader(device, version_bl);
|
fu_device_set_version_bootloader(device, version_bl);
|
||||||
|
|
||||||
/* get module ID */
|
/* get module ID */
|
||||||
@ -276,13 +387,13 @@ fu_elantp_hid_device_setup(FuDevice *device, GError **error)
|
|||||||
g_prefix_error(error, "failed to read IC body: ");
|
g_prefix_error(error, "failed to read IC body: ");
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
ic_type = fu_memread_uint16(buf, G_LITTLE_ENDIAN) & 0xFF;
|
self->ic_type = fu_memread_uint16(buf, G_LITTLE_ENDIAN) & 0xFF;
|
||||||
} else {
|
} else {
|
||||||
ic_type = (tmp >> 8) & 0xFF;
|
self->ic_type = (tmp >> 8) & 0xFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* define the extra instance IDs (ic_type + module_id + driver) */
|
/* define the extra instance IDs (ic_type + module_id + driver) */
|
||||||
fu_device_add_instance_u8(device, "ICTYPE", ic_type);
|
fu_device_add_instance_u8(device, "ICTYPE", self->ic_type);
|
||||||
fu_device_build_instance_id(device, NULL, "ELANTP", "ICTYPE", NULL);
|
fu_device_build_instance_id(device, NULL, "ELANTP", "ICTYPE", NULL);
|
||||||
fu_device_build_instance_id(device, NULL, "ELANTP", "ICTYPE", "MOD", NULL);
|
fu_device_build_instance_id(device, NULL, "ELANTP", "ICTYPE", "MOD", NULL);
|
||||||
fu_device_add_instance_str(device, "DRIVER", "HID");
|
fu_device_add_instance_str(device, "DRIVER", "HID");
|
||||||
@ -294,7 +405,7 @@ fu_elantp_hid_device_setup(FuDevice *device, GError **error)
|
|||||||
FWUPD_ERROR,
|
FWUPD_ERROR,
|
||||||
FWUPD_ERROR_NOT_SUPPORTED,
|
FWUPD_ERROR_NOT_SUPPORTED,
|
||||||
"no page count for ELANTP\\ICTYPE_%02X",
|
"no page count for ELANTP\\ICTYPE_%02X",
|
||||||
ic_type);
|
self->ic_type);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -305,6 +416,25 @@ fu_elantp_hid_device_setup(FuDevice *device, GError **error)
|
|||||||
if (!fu_elantp_hid_device_ensure_iap_ctrl(self, error))
|
if (!fu_elantp_hid_device_ensure_iap_ctrl(self, error))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
|
if (self->ic_type != 0x12 && self->ic_type != 0x13)
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
if (!fu_elantp_hid_device_read_force_table_enable(self, &error_forcetable)) {
|
||||||
|
g_debug("no forcetable detected: %s", error_forcetable->message);
|
||||||
|
} else {
|
||||||
|
if (!fu_elantp_hid_device_get_forcetable_address(self, error)) {
|
||||||
|
g_set_error(error,
|
||||||
|
FWUPD_ERROR,
|
||||||
|
FWUPD_ERROR_NOT_SUPPORTED,
|
||||||
|
"get forcetable address fail");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
self->force_table_support = TRUE;
|
||||||
|
/* is in bootloader mode */
|
||||||
|
if (!fu_elantp_hid_device_ensure_iap_ctrl(self, error))
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
if (!fu_elantp_hid_device_read_hatpic_enable(self, &error_local)) {
|
if (!fu_elantp_hid_device_read_hatpic_enable(self, &error_local)) {
|
||||||
g_debug("no haptic device detected: %s", error_local->message);
|
g_debug("no haptic device detected: %s", error_local->message);
|
||||||
} else {
|
} else {
|
||||||
@ -323,6 +453,8 @@ fu_elantp_hid_device_prepare_firmware(FuDevice *device,
|
|||||||
{
|
{
|
||||||
FuElantpHidDevice *self = FU_ELANTP_HID_DEVICE(device);
|
FuElantpHidDevice *self = FU_ELANTP_HID_DEVICE(device);
|
||||||
guint16 module_id;
|
guint16 module_id;
|
||||||
|
guint16 ic_type;
|
||||||
|
gboolean force_table_support;
|
||||||
g_autoptr(FuFirmware) firmware = fu_elantp_firmware_new();
|
g_autoptr(FuFirmware) firmware = fu_elantp_firmware_new();
|
||||||
|
|
||||||
/* check is compatible with hardware */
|
/* check is compatible with hardware */
|
||||||
@ -338,11 +470,123 @@ fu_elantp_hid_device_prepare_firmware(FuDevice *device,
|
|||||||
self->module_id);
|
self->module_id);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
ic_type = fu_elantp_firmware_get_ic_type(FU_ELANTP_FIRMWARE(firmware));
|
||||||
|
if (self->ic_type != ic_type) {
|
||||||
|
g_set_error(error,
|
||||||
|
FWUPD_ERROR,
|
||||||
|
FWUPD_ERROR_INVALID_FILE,
|
||||||
|
"firmware ic type incompatible, got 0x%04x, expected 0x%04x",
|
||||||
|
ic_type,
|
||||||
|
self->ic_type);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
force_table_support =
|
||||||
|
fu_elantp_firmware_get_forcetable_support(FU_ELANTP_FIRMWARE(firmware));
|
||||||
|
if (self->force_table_support != force_table_support) {
|
||||||
|
g_set_error(error,
|
||||||
|
FWUPD_ERROR,
|
||||||
|
FWUPD_ERROR_INVALID_FILE,
|
||||||
|
"firmware incompatible, forcetable incorrect.");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (self->force_table_support) {
|
||||||
|
guint32 force_table_addr;
|
||||||
|
guint32 diff_size;
|
||||||
|
force_table_addr =
|
||||||
|
fu_elantp_firmware_get_forcetable_addr(FU_ELANTP_FIRMWARE(firmware));
|
||||||
|
if (self->force_table_addr < force_table_addr) {
|
||||||
|
g_set_error(
|
||||||
|
error,
|
||||||
|
FWUPD_ERROR,
|
||||||
|
FWUPD_ERROR_INVALID_FILE,
|
||||||
|
"firmware forcetable address incompatible, got 0x%04x, expected 0x%04x",
|
||||||
|
force_table_addr / 2,
|
||||||
|
self->force_table_addr / 2);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
diff_size = self->force_table_addr - force_table_addr;
|
||||||
|
if (diff_size % 64 != 0) {
|
||||||
|
g_set_error(
|
||||||
|
error,
|
||||||
|
FWUPD_ERROR,
|
||||||
|
FWUPD_ERROR_INVALID_FILE,
|
||||||
|
"firmware forcetable address incompatible, got 0x%04x, expected 0x%04x",
|
||||||
|
force_table_addr / 2,
|
||||||
|
self->force_table_addr / 2);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* success */
|
/* success */
|
||||||
return g_steal_pointer(&firmware);
|
return g_steal_pointer(&firmware);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
fu_elantp_hid_device_filling_forcetable_firmware(FuDevice *device,
|
||||||
|
guint8 *fw_data,
|
||||||
|
gsize fw_size,
|
||||||
|
guint32 force_table_addr,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
FuElantpHidDevice *self = FU_ELANTP_HID_DEVICE(device);
|
||||||
|
const guint8 fillature[] = {0x77, 0x33, 0x44, 0xaa};
|
||||||
|
const guint8 signature[] = {0xAA, 0x55, 0xCC, 0x33, 0xFF, 0xFF};
|
||||||
|
guint8 buf[64] = {[0 ... 63] = 0xFF};
|
||||||
|
guint16 block_checksum;
|
||||||
|
guint16 filling_value;
|
||||||
|
|
||||||
|
if (self->force_table_addr == force_table_addr)
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
if (self->force_table_addr < force_table_addr) {
|
||||||
|
g_set_error(error,
|
||||||
|
FWUPD_ERROR,
|
||||||
|
FWUPD_ERROR_INVALID_FILE,
|
||||||
|
"forcetable address wrong (%x,%x): ",
|
||||||
|
force_table_addr,
|
||||||
|
self->force_table_addr);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!fu_memcpy_safe(buf,
|
||||||
|
sizeof(buf),
|
||||||
|
0, /* dst */
|
||||||
|
fillature,
|
||||||
|
sizeof(fillature),
|
||||||
|
0x0, /* src */
|
||||||
|
sizeof(fillature),
|
||||||
|
error))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
fu_memwrite_uint16(buf + 0x4, self->force_table_addr / 2, G_LITTLE_ENDIAN);
|
||||||
|
if (!fu_memcpy_safe(buf,
|
||||||
|
sizeof(buf),
|
||||||
|
sizeof(buf) - 6, /* dst */
|
||||||
|
signature,
|
||||||
|
sizeof(signature),
|
||||||
|
0x0, /* src */
|
||||||
|
sizeof(signature),
|
||||||
|
error))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
block_checksum = fu_sum16w(buf, sizeof(buf), G_LITTLE_ENDIAN) - 0xFFFF;
|
||||||
|
filling_value = 0x10000 - (block_checksum & 0xFFFF);
|
||||||
|
fu_memwrite_uint16(buf + 0x6, filling_value, G_LITTLE_ENDIAN);
|
||||||
|
|
||||||
|
for (guint i = force_table_addr; i < self->force_table_addr; i += 64) {
|
||||||
|
if (!fu_memcpy_safe(fw_data,
|
||||||
|
fw_size,
|
||||||
|
i, /* dst */
|
||||||
|
buf,
|
||||||
|
sizeof(buf),
|
||||||
|
0x0, /* src */
|
||||||
|
sizeof(buf),
|
||||||
|
error))
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
fu_elantp_hid_device_write_firmware(FuDevice *device,
|
fu_elantp_hid_device_write_firmware(FuDevice *device,
|
||||||
FuFirmware *firmware,
|
FuFirmware *firmware,
|
||||||
@ -360,6 +604,7 @@ fu_elantp_hid_device_write_firmware(FuDevice *device,
|
|||||||
guint8 csum_buf[2] = {0x0};
|
guint8 csum_buf[2] = {0x0};
|
||||||
g_autoptr(GBytes) fw = NULL;
|
g_autoptr(GBytes) fw = NULL;
|
||||||
g_autoptr(GPtrArray) chunks = NULL;
|
g_autoptr(GPtrArray) chunks = NULL;
|
||||||
|
guint total_pages;
|
||||||
|
|
||||||
/* progress */
|
/* progress */
|
||||||
fu_progress_set_id(progress, G_STRLOC);
|
fu_progress_set_id(progress, G_STRLOC);
|
||||||
@ -382,8 +627,56 @@ fu_elantp_hid_device_write_firmware(FuDevice *device,
|
|||||||
/* write each block */
|
/* write each block */
|
||||||
buf = g_bytes_get_data(fw, &bufsz);
|
buf = g_bytes_get_data(fw, &bufsz);
|
||||||
iap_addr = fu_elantp_firmware_get_iap_addr(firmware_elantp);
|
iap_addr = fu_elantp_firmware_get_iap_addr(firmware_elantp);
|
||||||
chunks = fu_chunk_array_new(buf + iap_addr, bufsz - iap_addr, 0x0, 0x0, self->fw_page_size);
|
|
||||||
for (guint i = 0; i < chunks->len; i++) {
|
if (self->force_table_support &&
|
||||||
|
self->force_table_addr >=
|
||||||
|
fu_elantp_firmware_get_forcetable_addr(FU_ELANTP_FIRMWARE(firmware))) {
|
||||||
|
g_autofree guint8 *buf2 = g_malloc0(bufsz);
|
||||||
|
if (!fu_memcpy_safe(buf2,
|
||||||
|
bufsz,
|
||||||
|
0x0, /* dst */
|
||||||
|
buf,
|
||||||
|
bufsz,
|
||||||
|
0x0, /* src */
|
||||||
|
bufsz,
|
||||||
|
error))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
if (!fu_elantp_hid_device_filling_forcetable_firmware(
|
||||||
|
device,
|
||||||
|
buf2,
|
||||||
|
bufsz,
|
||||||
|
fu_elantp_firmware_get_forcetable_addr(FU_ELANTP_FIRMWARE(firmware)),
|
||||||
|
error)) {
|
||||||
|
g_set_error(error,
|
||||||
|
FWUPD_ERROR,
|
||||||
|
FWUPD_ERROR_WRITE,
|
||||||
|
"filling forcetable failed");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
chunks = fu_chunk_array_new(buf2 + iap_addr,
|
||||||
|
bufsz - iap_addr,
|
||||||
|
0x0,
|
||||||
|
0x0,
|
||||||
|
self->fw_page_size);
|
||||||
|
total_pages = (self->force_table_addr - iap_addr - 1) / self->fw_page_size + 1;
|
||||||
|
if (total_pages > chunks->len) {
|
||||||
|
g_set_error(error,
|
||||||
|
FWUPD_ERROR,
|
||||||
|
FWUPD_ERROR_WRITE,
|
||||||
|
"total pages wrong (%u)",
|
||||||
|
total_pages);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
chunks = fu_chunk_array_new(buf + iap_addr,
|
||||||
|
bufsz - iap_addr,
|
||||||
|
0x0,
|
||||||
|
0x0,
|
||||||
|
self->fw_page_size);
|
||||||
|
total_pages = chunks->len;
|
||||||
|
}
|
||||||
|
for (guint i = 0; i < total_pages; i++) {
|
||||||
FuChunk *chk = g_ptr_array_index(chunks, i);
|
FuChunk *chk = g_ptr_array_index(chunks, i);
|
||||||
guint16 csum_tmp =
|
guint16 csum_tmp =
|
||||||
fu_sum16w(fu_chunk_get_data(chk), fu_chunk_get_data_sz(chk), G_LITTLE_ENDIAN);
|
fu_sum16w(fu_chunk_get_data(chk), fu_chunk_get_data_sz(chk), G_LITTLE_ENDIAN);
|
||||||
@ -402,7 +695,6 @@ fu_elantp_hid_device_write_firmware(FuDevice *device,
|
|||||||
error))
|
error))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
fu_memwrite_uint16(blk + fu_chunk_get_data_sz(chk) + 1, csum_tmp, G_LITTLE_ENDIAN);
|
fu_memwrite_uint16(blk + fu_chunk_get_data_sz(chk) + 1, csum_tmp, G_LITTLE_ENDIAN);
|
||||||
|
|
||||||
if (!fu_elantp_hid_device_send_cmd(self, blk, blksz, NULL, 0, error))
|
if (!fu_elantp_hid_device_send_cmd(self, blk, blksz, NULL, 0, error))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
g_usleep(self->fw_page_size == 512 ? ELANTP_DELAY_WRITE_BLOCK_512 * 1000
|
g_usleep(self->fw_page_size == 512 ? ELANTP_DELAY_WRITE_BLOCK_512 * 1000
|
||||||
@ -552,6 +844,8 @@ fu_elantp_hid_device_detach(FuDevice *device, FuProgress *progress, GError **err
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (!fu_elantp_hid_device_write_fw_password(self, ic_type, iap_ver, error))
|
||||||
|
return FALSE;
|
||||||
if (!fu_elantp_hid_device_write_cmd(self, ETP_CMD_I2C_IAP, self->iap_password, error))
|
if (!fu_elantp_hid_device_write_cmd(self, ETP_CMD_I2C_IAP, self->iap_password, error))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
g_usleep(ELANTP_DELAY_UNLOCK * 1000);
|
g_usleep(ELANTP_DELAY_UNLOCK * 1000);
|
||||||
|
@ -20,6 +20,8 @@ struct _FuElantpHidHapticDevice {
|
|||||||
guint16 ic_page_count;
|
guint16 ic_page_count;
|
||||||
guint16 iap_type;
|
guint16 iap_type;
|
||||||
guint16 tp_iap_ctrl;
|
guint16 tp_iap_ctrl;
|
||||||
|
guint16 tp_iap_ver;
|
||||||
|
guint16 tp_ic_type;
|
||||||
guint16 iap_ctrl;
|
guint16 iap_ctrl;
|
||||||
guint16 iap_password;
|
guint16 iap_password;
|
||||||
guint16 module_id;
|
guint16 module_id;
|
||||||
@ -157,6 +159,14 @@ fu_elantp_hid_haptic_device_ensure_iap_ctrl(FuDevice *parent,
|
|||||||
self->tp_iap_ctrl = fu_memread_uint16(buf, G_LITTLE_ENDIAN);
|
self->tp_iap_ctrl = fu_memread_uint16(buf, G_LITTLE_ENDIAN);
|
||||||
|
|
||||||
/* in bootloader mode? */
|
/* in bootloader mode? */
|
||||||
|
if (self->tp_iap_ver <= 5) {
|
||||||
|
if ((self->tp_iap_ctrl & ETP_I2C_MAIN_MODE_ON2) == 0)
|
||||||
|
fu_device_add_flag(FU_DEVICE(parent), FWUPD_DEVICE_FLAG_IS_BOOTLOADER);
|
||||||
|
else
|
||||||
|
fu_device_remove_flag(FU_DEVICE(parent), FWUPD_DEVICE_FLAG_IS_BOOTLOADER);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
if ((self->tp_iap_ctrl & ETP_I2C_MAIN_MODE_ON) == 0)
|
if ((self->tp_iap_ctrl & ETP_I2C_MAIN_MODE_ON) == 0)
|
||||||
fu_device_add_flag(FU_DEVICE(parent), FWUPD_DEVICE_FLAG_IS_BOOTLOADER);
|
fu_device_add_flag(FU_DEVICE(parent), FWUPD_DEVICE_FLAG_IS_BOOTLOADER);
|
||||||
else
|
else
|
||||||
@ -201,7 +211,7 @@ fu_elantp_hid_haptic_device_get_hatpic_driver_ic(FuDevice *parent,
|
|||||||
guint8 buf[2] = {0x0};
|
guint8 buf[2] = {0x0};
|
||||||
guint16 value;
|
guint16 value;
|
||||||
if (!fu_elantp_hid_haptic_device_read_cmd(parent,
|
if (!fu_elantp_hid_haptic_device_read_cmd(parent,
|
||||||
ETP_CMD_I2C_FLIM_TYPE_ENABLE,
|
ETP_CMD_I2C_FORCE_TYPE_ENABLE,
|
||||||
buf,
|
buf,
|
||||||
sizeof(buf),
|
sizeof(buf),
|
||||||
error)) {
|
error)) {
|
||||||
@ -209,7 +219,7 @@ fu_elantp_hid_haptic_device_get_hatpic_driver_ic(FuDevice *parent,
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
value = fu_memread_uint16(buf, G_LITTLE_ENDIAN);
|
value = fu_memread_uint16(buf, G_LITTLE_ENDIAN);
|
||||||
if (value == 0xFFFF || value == ETP_CMD_I2C_FLIM_TYPE_ENABLE) {
|
if (value == 0xFFFF || value == ETP_CMD_I2C_FORCE_TYPE_ENABLE) {
|
||||||
g_set_error_literal(error,
|
g_set_error_literal(error,
|
||||||
G_IO_ERROR,
|
G_IO_ERROR,
|
||||||
G_IO_ERROR_NOT_SUPPORTED,
|
G_IO_ERROR_NOT_SUPPORTED,
|
||||||
@ -217,7 +227,7 @@ fu_elantp_hid_haptic_device_get_hatpic_driver_ic(FuDevice *parent,
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((buf[0] & ETP_FW_FLIM_TYPE_ENABLE_BIT) == 0 ||
|
if ((buf[0] & ETP_FW_FORCE_TYPE_ENABLE_BIT) == 0 ||
|
||||||
(buf[0] & ETP_FW_EEPROM_ENABLE_BIT) == 0) {
|
(buf[0] & ETP_FW_EEPROM_ENABLE_BIT) == 0) {
|
||||||
g_set_error_literal(error,
|
g_set_error_literal(error,
|
||||||
G_IO_ERROR,
|
G_IO_ERROR,
|
||||||
@ -285,9 +295,51 @@ fu_elantp_hid_haptic_device_get_version(FuDevice *parent,
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
fu_elantp_hid_haptic_device_write_fw_password(FuDevice *parent,
|
||||||
|
guint16 tp_ic_type,
|
||||||
|
guint16 tp_iap_ver,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
guint8 buf[2] = {0x0};
|
||||||
|
guint16 pw = ETP_I2C_IC13_IAPV5_PW;
|
||||||
|
guint16 value;
|
||||||
|
|
||||||
|
if (tp_iap_ver < 0x5 || tp_ic_type != 0x13)
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
if (!fu_elantp_hid_haptic_device_write_cmd(parent, ETP_CMD_I2C_FW_PW, pw, error)) {
|
||||||
|
g_prefix_error(error, "failed to write fw password cmd: ");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!fu_elantp_hid_haptic_device_read_cmd(parent,
|
||||||
|
ETP_CMD_I2C_FW_PW,
|
||||||
|
buf,
|
||||||
|
sizeof(buf),
|
||||||
|
error)) {
|
||||||
|
g_prefix_error(error, "failed to read fw password cmd: ");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
value = fu_memread_uint16(buf, G_LITTLE_ENDIAN);
|
||||||
|
if (value != pw) {
|
||||||
|
g_set_error(error,
|
||||||
|
FWUPD_ERROR,
|
||||||
|
FWUPD_ERROR_NOT_SUPPORTED,
|
||||||
|
"can't set fw password got:%x",
|
||||||
|
value);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* success */
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
guint16 checksum;
|
guint16 checksum;
|
||||||
guint16 iap_password;
|
guint16 iap_password;
|
||||||
|
guint16 tp_iap_ver;
|
||||||
|
guint16 tp_ic_type;
|
||||||
} FuElantpHaptictpWaitFlashEEPROMChecksumHelper;
|
} FuElantpHaptictpWaitFlashEEPROMChecksumHelper;
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
@ -322,6 +374,11 @@ fu_elantp_hid_haptic_device_write_checksum_cb(FuDevice *parent, gpointer user_da
|
|||||||
value);
|
value);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
if (!fu_elantp_hid_haptic_device_write_fw_password(parent,
|
||||||
|
helper->tp_ic_type,
|
||||||
|
helper->tp_iap_ver,
|
||||||
|
error))
|
||||||
|
return FALSE;
|
||||||
if (!fu_elantp_hid_haptic_device_write_cmd(parent,
|
if (!fu_elantp_hid_haptic_device_write_cmd(parent,
|
||||||
ETP_CMD_I2C_IAP,
|
ETP_CMD_I2C_IAP,
|
||||||
helper->iap_password,
|
helper->iap_password,
|
||||||
@ -788,6 +845,8 @@ fu_elantp_hid_haptic_device_write_firmware(FuDevice *device,
|
|||||||
|
|
||||||
helper.checksum = checksum_device;
|
helper.checksum = checksum_device;
|
||||||
helper.iap_password = self->iap_password;
|
helper.iap_password = self->iap_password;
|
||||||
|
helper.tp_ic_type = self->tp_ic_type;
|
||||||
|
helper.tp_iap_ver = self->tp_iap_ver;
|
||||||
if (!fu_device_retry_full(FU_DEVICE(parent),
|
if (!fu_device_retry_full(FU_DEVICE(parent),
|
||||||
fu_elantp_hid_haptic_device_write_checksum_cb,
|
fu_elantp_hid_haptic_device_write_checksum_cb,
|
||||||
3,
|
3,
|
||||||
@ -831,8 +890,6 @@ fu_elantp_hid_haptic_device_detach(FuDevice *device, FuProgress *progress, GErro
|
|||||||
{
|
{
|
||||||
FuElantpHidDevice *parent;
|
FuElantpHidDevice *parent;
|
||||||
FuElantpHidHapticDevice *self = FU_ELANTP_HID_HAPTIC_DEVICE(device);
|
FuElantpHidHapticDevice *self = FU_ELANTP_HID_HAPTIC_DEVICE(device);
|
||||||
guint16 tp_iap_ver;
|
|
||||||
guint16 tp_ic_type;
|
|
||||||
guint8 buf[2] = {0x0};
|
guint8 buf[2] = {0x0};
|
||||||
guint16 ctrl;
|
guint16 ctrl;
|
||||||
guint16 tmp;
|
guint16 tmp;
|
||||||
@ -878,9 +935,9 @@ fu_elantp_hid_haptic_device_detach(FuDevice *device, FuProgress *progress, GErro
|
|||||||
g_prefix_error(error, "failed to read IC body: ");
|
g_prefix_error(error, "failed to read IC body: ");
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
tp_ic_type = fu_memread_uint16(buf, G_LITTLE_ENDIAN) & 0xFF;
|
self->tp_ic_type = fu_memread_uint16(buf, G_LITTLE_ENDIAN) & 0xFF;
|
||||||
} else
|
} else
|
||||||
tp_ic_type = (tmp >> 8) & 0xFF;
|
self->tp_ic_type = (tmp >> 8) & 0xFF;
|
||||||
|
|
||||||
/* get IAP firmware version */
|
/* get IAP firmware version */
|
||||||
if (!fu_elantp_hid_haptic_device_read_cmd(FU_DEVICE(parent),
|
if (!fu_elantp_hid_haptic_device_read_cmd(FU_DEVICE(parent),
|
||||||
@ -893,16 +950,17 @@ fu_elantp_hid_haptic_device_detach(FuDevice *device, FuProgress *progress, GErro
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
if (self->pattern >= 1)
|
if (self->pattern >= 1)
|
||||||
tp_iap_ver = buf[1];
|
self->tp_iap_ver = buf[1];
|
||||||
else
|
else
|
||||||
tp_iap_ver = fu_memread_uint16(buf, G_LITTLE_ENDIAN);
|
self->tp_iap_ver = fu_memread_uint16(buf, G_LITTLE_ENDIAN);
|
||||||
|
|
||||||
/* set the page size */
|
/* set the page size */
|
||||||
self->fw_page_size = 64;
|
self->fw_page_size = 64;
|
||||||
if (tp_ic_type >= 0x10) {
|
if (self->tp_ic_type >= 0x10) {
|
||||||
if (tp_iap_ver >= 1) {
|
if (self->tp_iap_ver >= 1) {
|
||||||
/* set the IAP type, presumably some kind of ABI */
|
/* set the IAP type, presumably some kind of ABI */
|
||||||
if (tp_iap_ver >= 2 && (tp_ic_type == 0x14 || tp_ic_type == 0x15)) {
|
if (self->tp_iap_ver >= 2 &&
|
||||||
|
(self->tp_ic_type == 0x14 || self->tp_ic_type == 0x15)) {
|
||||||
self->fw_page_size = 512;
|
self->fw_page_size = 512;
|
||||||
} else {
|
} else {
|
||||||
self->fw_page_size = 128;
|
self->fw_page_size = 128;
|
||||||
|
Loading…
Reference in New Issue
Block a user