mirror of
https://git.proxmox.com/git/fwupd
synced 2025-05-29 20:32:50 +00:00
vli-usbhub: Add support for updating V2 devices
This commit is contained in:
parent
a58510b246
commit
f04be98153
@ -67,4 +67,25 @@ void
|
||||
fu_vli_usbhub_header_to_string (FuVliUsbhubHeader *hdr, guint idt, GString *str)
|
||||
{
|
||||
fu_common_string_append_kx (str, idt, "DevId", GUINT16_FROM_BE(hdr->dev_id));
|
||||
fu_common_string_append_kx (str, idt, "Variant", hdr->variant);
|
||||
if (hdr->usb2_fw_sz > 0) {
|
||||
fu_common_string_append_kx (str, idt, "Usb2FwAddr",
|
||||
GUINT16_FROM_BE(hdr->usb2_fw_addr));
|
||||
fu_common_string_append_kx (str, idt, "Usb2FwSz",
|
||||
GUINT16_FROM_BE(hdr->usb2_fw_sz));
|
||||
}
|
||||
fu_common_string_append_kx (str, idt, "Usb3FwAddr",
|
||||
GUINT16_FROM_BE(hdr->usb3_fw_addr));
|
||||
fu_common_string_append_kx (str, idt, "Usb3FwSz",
|
||||
GUINT16_FROM_BE(hdr->usb3_fw_sz));
|
||||
if (hdr->prev_ptr != VLI_USBHUB_FLASHMAP_IDX_INVALID) {
|
||||
fu_common_string_append_kx (str, idt, "PrevPtr",
|
||||
VLI_USBHUB_FLASHMAP_IDX_TO_ADDR(hdr->prev_ptr));
|
||||
}
|
||||
if (hdr->next_ptr != VLI_USBHUB_FLASHMAP_IDX_INVALID) {
|
||||
fu_common_string_append_kx (str, idt, "NextPtr",
|
||||
VLI_USBHUB_FLASHMAP_IDX_TO_ADDR(hdr->next_ptr));
|
||||
}
|
||||
fu_common_string_append_kb (str, idt, "ChecksumOK",
|
||||
hdr->checksum == fu_vli_usbhub_header_crc8 (hdr));
|
||||
}
|
||||
|
@ -31,22 +31,49 @@ typedef enum {
|
||||
|
||||
typedef struct __attribute__ ((packed)) {
|
||||
guint16 dev_id; /* 0x00, BE */
|
||||
guint8 unknown_02; /* 0x02 */
|
||||
guint8 unknown_03; /* 0x03 */
|
||||
guint16 u3_addr; /* 0x04 */
|
||||
guint16 u3_sz; /* 0x06, BE */
|
||||
guint16 u2_addr; /* 0x08 */
|
||||
guint16 unknown_0a; /* 0x0a */
|
||||
guint8 u3_addr_h; /* 0x0c */
|
||||
guint8 unknown_0d[15]; /* 0x0d */
|
||||
guint8 prev_ptr; /* 0x1c */
|
||||
guint8 next_ptr; /* 0x1d */
|
||||
guint8 unknown_1e; /* 0x1e */
|
||||
guint8 strapping1; /* 0x02 */
|
||||
guint8 strapping2; /* 0x03 */
|
||||
guint16 usb3_fw_addr; /* 0x04, BE */
|
||||
guint16 usb3_fw_sz; /* 0x06, BE */
|
||||
guint16 usb2_fw_addr; /* 0x08, BE */
|
||||
guint16 usb2_fw_sz; /* 0x0a, BE */
|
||||
guint8 usb3_fw_addr_high; /* 0x0c */
|
||||
guint8 unknown_0d[3]; /* 0x0d */
|
||||
guint8 usb2_fw_addr_high; /* 0x10 */
|
||||
guint8 unknown_11[10]; /* 0x11 */
|
||||
guint8 inverse_pe41; /* 0x1b */
|
||||
guint8 prev_ptr; /* 0x1c, addr / 0x20 */
|
||||
guint8 next_ptr; /* 0x1d, addr / 0x20 */
|
||||
guint8 variant; /* 0x1e */
|
||||
guint8 checksum; /* 0x1f */
|
||||
} FuVliUsbhubHeader;
|
||||
|
||||
G_STATIC_ASSERT(sizeof(FuVliUsbhubHeader) == 0x20);
|
||||
|
||||
#define FU_VLI_USBHUB_HEADER_STRAPPING1_SELFW1 (1 << 1)
|
||||
#define FU_VLI_USBHUB_HEADER_STRAPPING1_76PIN (1 << 2)
|
||||
#define FU_VLI_USBHUB_HEADER_STRAPPING1_B3UP (1 << 3)
|
||||
#define FU_VLI_USBHUB_HEADER_STRAPPING1_LPC (1 << 4)
|
||||
#define FU_VLI_USBHUB_HEADER_STRAPPING1_U1U2 (1 << 5)
|
||||
#define FU_VLI_USBHUB_HEADER_STRAPPING1_BC (1 << 6)
|
||||
#define FU_VLI_USBHUB_HEADER_STRAPPING1_Q4S (1 << 7)
|
||||
|
||||
#define FU_VLI_USBHUB_HEADER_STRAPPING2_IDXEN (1 << 0)
|
||||
#define FU_VLI_USBHUB_HEADER_STRAPPING2_FWRTY (1 << 1)
|
||||
#define FU_VLI_USBHUB_HEADER_STRAPPING2_SELFW2 (1 << 7)
|
||||
|
||||
#define VLI_USBHUB_FLASHMAP_ADDR_TO_IDX(addr) (addr / 0x20)
|
||||
#define VLI_USBHUB_FLASHMAP_IDX_TO_ADDR(addr) (addr * 0x20)
|
||||
|
||||
#define VLI_USBHUB_FLASHMAP_IDX_HD1 0x00 /* factory firmware */
|
||||
#define VLI_USBHUB_FLASHMAP_IDX_HD2 0x80 /* update firmware */
|
||||
#define VLI_USBHUB_FLASHMAP_IDX_INVALID 0xff
|
||||
|
||||
#define VLI_USBHUB_FLASHMAP_ADDR_HD1 0x0
|
||||
#define VLI_USBHUB_FLASHMAP_ADDR_HD1_BACKUP 0x1800
|
||||
#define VLI_USBHUB_FLASHMAP_ADDR_HD2 0x1000
|
||||
#define VLI_USBHUB_FLASHMAP_ADDR_FW 0x2000
|
||||
|
||||
guint8 fu_vli_usbhub_header_crc8 (FuVliUsbhubHeader *hdr);
|
||||
void fu_vli_usbhub_header_to_string (FuVliUsbhubHeader *hdr,
|
||||
guint idt,
|
||||
|
@ -25,7 +25,8 @@ struct _FuVliUsbhubDevice
|
||||
FuVliUsbhubDeviceKind kind;
|
||||
gboolean disable_powersave;
|
||||
guint8 update_protocol;
|
||||
FuVliUsbhubHeader hdr;
|
||||
FuVliUsbhubHeader hd1_hdr; /* factory */
|
||||
FuVliUsbhubHeader hd2_hdr; /* update */
|
||||
guint32 flash_id;
|
||||
guint8 spi_cmd_read_id;
|
||||
guint8 spi_cmd_read_id_sz;
|
||||
@ -72,9 +73,11 @@ fu_vli_usbhub_device_to_string (FuDevice *device, guint idt, GString *str)
|
||||
fu_common_string_append_kx (str, idt, "SpiCmdSectorErase", self->spi_cmd_sector_erase);
|
||||
fu_common_string_append_kx (str, idt, "SpiCmdWriteEn", self->spi_cmd_write_en);
|
||||
fu_common_string_append_kx (str, idt, "SpiCmdWriteStatus", self->spi_cmd_write_status);
|
||||
if (self->update_protocol > 0x2) {
|
||||
fu_common_string_append_kv (str, idt, "Version2RootHdr", NULL);
|
||||
fu_vli_usbhub_header_to_string (&self->hdr, idt + 1, str);
|
||||
if (self->update_protocol >= 0x2) {
|
||||
fu_common_string_append_kv (str, idt, "H1Hdr@0x0", NULL);
|
||||
fu_vli_usbhub_header_to_string (&self->hd1_hdr, idt + 1, str);
|
||||
fu_common_string_append_kv (str, idt, "H2Hdr@0x1000", NULL);
|
||||
fu_vli_usbhub_header_to_string (&self->hd2_hdr, idt + 1, str);
|
||||
}
|
||||
}
|
||||
|
||||
@ -172,6 +175,33 @@ fu_vli_usbhub_device_spi_read_flash_id (FuVliUsbhubDevice *self, GError **error)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
fu_vli_usbhub_device_spi_read_status (FuVliUsbhubDevice *self, guint8 *status, GError **error)
|
||||
{
|
||||
GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (self));
|
||||
|
||||
/* sanity check */
|
||||
if (self->spi_cmd_read_status == 0x0) {
|
||||
g_set_error_literal (error,
|
||||
G_IO_ERROR,
|
||||
G_IO_ERROR_NOT_SUPPORTED,
|
||||
"No value for SpiCmdReadStatus");
|
||||
return FALSE;
|
||||
}
|
||||
if (!g_usb_device_control_transfer (usb_device,
|
||||
G_USB_DEVICE_DIRECTION_DEVICE_TO_HOST,
|
||||
G_USB_DEVICE_REQUEST_TYPE_VENDOR,
|
||||
G_USB_DEVICE_RECIPIENT_DEVICE,
|
||||
0xc1, self->spi_cmd_read_status, 0x0000,
|
||||
status, 0x1, NULL,
|
||||
FU_VLI_USBHUB_DEVICE_TIMEOUT,
|
||||
NULL, error)) {
|
||||
g_prefix_error (error, "failed to read status: ");
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
fu_vli_usbhub_device_spi_read_data (FuVliUsbhubDevice *self,
|
||||
guint32 data_addr,
|
||||
@ -289,6 +319,35 @@ fu_vli_usbhub_device_spi_erase_chip (FuVliUsbhubDevice *self, GError **error)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
fu_vli_usbhub_device_spi_erase_sector (FuVliUsbhubDevice *self, guint32 data_addr, GError **error)
|
||||
{
|
||||
guint16 index = ((data_addr << 8) & 0xff00) | ((data_addr >> 8) & 0x00ff);
|
||||
guint16 value = ((data_addr >> 8) & 0xff00) | self->spi_cmd_sector_erase;
|
||||
GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (self));
|
||||
|
||||
/* sanity check */
|
||||
if (self->spi_cmd_sector_erase == 0x0) {
|
||||
g_set_error_literal (error,
|
||||
G_IO_ERROR,
|
||||
G_IO_ERROR_NOT_SUPPORTED,
|
||||
"No value for SpiCmdSectorErase");
|
||||
return FALSE;
|
||||
}
|
||||
if (!g_usb_device_control_transfer (usb_device,
|
||||
G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE,
|
||||
G_USB_DEVICE_REQUEST_TYPE_VENDOR,
|
||||
G_USB_DEVICE_RECIPIENT_DEVICE,
|
||||
0xd4, value, index,
|
||||
NULL, 0x0, NULL,
|
||||
FU_VLI_USBHUB_DEVICE_TIMEOUT,
|
||||
NULL, error)) {
|
||||
g_prefix_error (error, "failed to erase SPI sector @0x%x: ", data_addr);
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
fu_vli_usbhub_device_spi_write_data (FuVliUsbhubDevice *self,
|
||||
guint32 data_addr,
|
||||
@ -322,6 +381,116 @@ fu_vli_usbhub_device_spi_write_data (FuVliUsbhubDevice *self,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
fu_vli_usbhub_device_spi_wait_finish (FuVliUsbhubDevice *self, GError **error)
|
||||
{
|
||||
const guint32 rdy_cnt = 2;
|
||||
guint32 cnt = 0;
|
||||
|
||||
/* sanity check */
|
||||
if (self->spi_cmd_read_status == 0x0) {
|
||||
g_set_error_literal (error,
|
||||
G_IO_ERROR,
|
||||
G_IO_ERROR_NOT_SUPPORTED,
|
||||
"No value for SpiCmdReadStatus");
|
||||
return FALSE;
|
||||
}
|
||||
for (guint32 idx = 0; idx < 1000; idx++) {
|
||||
guint8 status = 0x7f;
|
||||
|
||||
/* must get bit[1:0] == 0 twice in a row for success */
|
||||
if (!fu_vli_usbhub_device_spi_read_status (self, &status, error))
|
||||
return FALSE;
|
||||
if ((status & 0x03) == 0x00) {
|
||||
if (cnt++ >= rdy_cnt)
|
||||
return TRUE;
|
||||
} else {
|
||||
cnt = 0;
|
||||
}
|
||||
g_usleep (500 * 1000);
|
||||
}
|
||||
g_set_error (error,
|
||||
G_IO_ERROR,
|
||||
G_IO_ERROR_FAILED,
|
||||
"failed to wait for SPI");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
fu_vli_usbhub_device_erase_sector (FuVliUsbhubDevice *self, guint32 addr, GError **error)
|
||||
{
|
||||
const guint32 bufsz = 0x1000;
|
||||
|
||||
/* erase sector */
|
||||
if (!fu_vli_usbhub_device_spi_write_enable (self, error)) {
|
||||
g_prefix_error (error, "fu_vli_usbhub_device_spi_write_enable failed: ");
|
||||
return FALSE;
|
||||
}
|
||||
if (!fu_vli_usbhub_device_spi_write_status (self, 0x00, error)) {
|
||||
g_prefix_error (error, "fu_vli_usbhub_device_spi_write_status failed: ");
|
||||
return FALSE;
|
||||
}
|
||||
if (!fu_vli_usbhub_device_spi_write_enable (self, error)) {
|
||||
g_prefix_error (error, "fu_vli_usbhub_device_spi_write_enable failed: ");
|
||||
return FALSE;
|
||||
}
|
||||
if (!fu_vli_usbhub_device_spi_erase_sector (self, addr, error)) {
|
||||
g_prefix_error (error, "fu_vli_usbhub_device_spi_erase_sector failed");
|
||||
return FALSE;
|
||||
}
|
||||
if (!fu_vli_usbhub_device_spi_wait_finish (self, error)) {
|
||||
g_prefix_error (error, "fu_vli_usbhub_device_spi_wait_finish failed");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* verify it really was blanked */
|
||||
for (guint32 offset = 0; offset < bufsz; offset += FU_VLI_USBHUB_TXSIZE) {
|
||||
guint8 buf[FU_VLI_USBHUB_TXSIZE] = { 0x0 };
|
||||
if (!fu_vli_usbhub_device_spi_read_data (self,
|
||||
addr + offset,
|
||||
buf, sizeof (buf),
|
||||
error)) {
|
||||
g_prefix_error (error, "failed to read back empty: ");
|
||||
return FALSE;
|
||||
}
|
||||
for (guint i = 0; i < sizeof(buf); i++) {
|
||||
if (buf[i] != 0xff) {
|
||||
g_set_error (error,
|
||||
G_IO_ERROR,
|
||||
G_IO_ERROR_FAILED,
|
||||
"failed to check blank @0x%x",
|
||||
addr + offset + i);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* success */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
fu_vli_usbhub_device_erase_sectors (FuVliUsbhubDevice *self,
|
||||
guint32 addr,
|
||||
gsize sz,
|
||||
GError **error)
|
||||
{
|
||||
g_autoptr(GPtrArray) chunks = fu_chunk_array_new (NULL, sz, addr, 0x0, 0x1000);
|
||||
for (guint i = 0; i < chunks->len; i++) {
|
||||
FuChunk *chunk = g_ptr_array_index (chunks, i);
|
||||
g_debug ("erasing @0x%x", chunk->address);
|
||||
if (!fu_vli_usbhub_device_erase_sector (self, chunk->address, error)) {
|
||||
g_prefix_error (error,
|
||||
"failed to erase FW sector @0x%x",
|
||||
chunk->address);
|
||||
return FALSE;
|
||||
}
|
||||
fu_device_set_progress_full (FU_DEVICE (self),
|
||||
(gsize) i, (gsize) chunks->len);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* disable hub sleep states -- not really required by 815~ hubs */
|
||||
static gboolean
|
||||
fu_vli_usbhub_device_disable_u1u2 (FuVliUsbhubDevice *self, GError **error)
|
||||
@ -508,6 +677,20 @@ fu_vli_usbhub_device_dump_firmware (FuVliUsbhubDevice *self, gsize bufsz, GError
|
||||
return g_bytes_new_take (g_steal_pointer (&buf), bufsz);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
fu_vli_usbhub_device_probe (FuDevice *device, GError **error)
|
||||
{
|
||||
/* quirks now applied... */
|
||||
if (fu_device_has_custom_flag (device, "usb3")) {
|
||||
fu_device_set_summary (device, "USB 3.x Hub");
|
||||
} else if (fu_device_has_custom_flag (device, "usb2")) {
|
||||
fu_device_set_summary (device, "USB 2.x Hub");
|
||||
} else {
|
||||
fu_device_set_summary (device, "USB Hub");
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
fu_vli_usbhub_device_setup (FuDevice *device, GError **error)
|
||||
{
|
||||
@ -517,13 +700,13 @@ fu_vli_usbhub_device_setup (FuDevice *device, GError **error)
|
||||
|
||||
/* try to read a block of data which will fail for 813-type devices */
|
||||
if (fu_device_has_custom_flag (device, "needs-unlock-legacy813") &&
|
||||
!fu_vli_usbhub_device_spi_read_data (self, 0x0, (guint8 *) &self->hdr,
|
||||
sizeof(self->hdr), &error_tmp)) {
|
||||
!fu_vli_usbhub_device_spi_read_data (self, 0x0, (guint8 *) &self->hd1_hdr,
|
||||
sizeof(self->hd1_hdr), &error_tmp)) {
|
||||
g_warning ("failed to read, trying to unlock 813: %s", error_tmp->message);
|
||||
if (!fu_vli_usbhub_device_vdr_unlock_813 (self, error))
|
||||
return FALSE;
|
||||
if (!fu_vli_usbhub_device_spi_read_data (self, 0x0, (guint8 *) &self->hdr,
|
||||
sizeof(self->hdr), error)) {
|
||||
if (!fu_vli_usbhub_device_spi_read_data (self, 0x0, (guint8 *) &self->hd1_hdr,
|
||||
sizeof(self->hd1_hdr), error)) {
|
||||
g_prefix_error (error, "813 unlock fail: ");
|
||||
return FALSE;
|
||||
}
|
||||
@ -566,33 +749,49 @@ fu_vli_usbhub_device_setup (FuDevice *device, GError **error)
|
||||
|
||||
}
|
||||
|
||||
/* read root header */
|
||||
if (!fu_vli_usbhub_device_spi_read_data (self, 0x0, (guint8 *) &self->hdr,
|
||||
sizeof(self->hdr), error)) {
|
||||
g_prefix_error (error, "failed to read root header");
|
||||
/* read HD1 (factory) header */
|
||||
if (!fu_vli_usbhub_device_spi_read_data (self, VLI_USBHUB_FLASHMAP_ADDR_HD1,
|
||||
(guint8 *) &self->hd1_hdr,
|
||||
sizeof(self->hd1_hdr), error)) {
|
||||
g_prefix_error (error, "failed to read HD1 header");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* detect update protocol from the device ID */
|
||||
switch (GUINT16_FROM_BE(self->hdr.dev_id) >> 8) {
|
||||
switch (GUINT16_FROM_BE(self->hd1_hdr.dev_id) >> 8) {
|
||||
/* VL810~VL813 */
|
||||
case 0x0d:
|
||||
self->update_protocol = 0x1;
|
||||
self->disable_powersave = TRUE;
|
||||
fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_UPDATABLE);
|
||||
fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_CAN_VERIFY_IMAGE);
|
||||
fu_device_set_install_duration (FU_DEVICE (self), 10); /* seconds */
|
||||
break;
|
||||
/* VL817~ */
|
||||
case 0x05:
|
||||
self->update_protocol = 0x2;
|
||||
fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_DUAL_IMAGE);
|
||||
fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_SELF_RECOVERY);
|
||||
fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_UPDATABLE);
|
||||
fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_CAN_VERIFY_IMAGE);
|
||||
fu_device_set_install_duration (FU_DEVICE (self), 15); /* seconds */
|
||||
break;
|
||||
default:
|
||||
g_warning ("unknown update protocol, device_id=0x%x",
|
||||
GUINT16_FROM_BE(self->hdr.dev_id));
|
||||
GUINT16_FROM_BE(self->hd1_hdr.dev_id));
|
||||
break;
|
||||
}
|
||||
|
||||
/* read HD2 (update) header */
|
||||
if (self->update_protocol >= 0x2) {
|
||||
if (!fu_vli_usbhub_device_spi_read_data (self, VLI_USBHUB_FLASHMAP_ADDR_HD2,
|
||||
(guint8 *) &self->hd2_hdr,
|
||||
sizeof(self->hd2_hdr), error)) {
|
||||
g_prefix_error (error, "failed to read HD2 header");
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/* success */
|
||||
return TRUE;
|
||||
}
|
||||
@ -643,12 +842,12 @@ fu_vli_usbhub_device_prepare_firmware (FuDevice *device,
|
||||
return NULL;
|
||||
}
|
||||
device_id = fu_vli_usbhub_firmware_get_device_id (FU_VLI_USBHUB_FIRMWARE (firmware));
|
||||
if (GUINT16_FROM_BE(self->hdr.dev_id) != device_id) {
|
||||
if (GUINT16_FROM_BE(self->hd1_hdr.dev_id) != device_id) {
|
||||
g_set_error (error,
|
||||
FWUPD_ERROR,
|
||||
FWUPD_ERROR_INVALID_FILE,
|
||||
"firmware incompatible, got 0x%04x, expected 0x%04x",
|
||||
device_id, GUINT16_FROM_BE(self->hdr.dev_id));
|
||||
device_id, GUINT16_FROM_BE(self->hd1_hdr.dev_id));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -771,11 +970,17 @@ fu_vli_usbhub_device_write_blocks (FuVliUsbhubDevice *self,
|
||||
|
||||
static gboolean
|
||||
fu_vli_usbhub_device_update_v1 (FuVliUsbhubDevice *self,
|
||||
GBytes *fw,
|
||||
FuFirmware *firmware,
|
||||
GError **error)
|
||||
{
|
||||
gsize bufsz = 0;
|
||||
const guint8 *buf = g_bytes_get_data (fw, &bufsz);
|
||||
const guint8 *buf;
|
||||
g_autoptr(GBytes) fw = NULL;
|
||||
|
||||
/* simple image */
|
||||
fw = fu_firmware_get_image_default_bytes (firmware, error);
|
||||
if (fw == NULL)
|
||||
return FALSE;
|
||||
|
||||
/* erase */
|
||||
fu_device_set_status (FU_DEVICE (self), FWUPD_STATUS_DEVICE_ERASE);
|
||||
@ -786,6 +991,7 @@ fu_vli_usbhub_device_update_v1 (FuVliUsbhubDevice *self,
|
||||
|
||||
/* write in chunks */
|
||||
fu_device_set_status (FU_DEVICE (self), FWUPD_STATUS_DEVICE_WRITE);
|
||||
buf = g_bytes_get_data (fw, &bufsz);
|
||||
if (!fu_vli_usbhub_device_write_blocks (self, 0x0, buf, bufsz, error))
|
||||
return FALSE;
|
||||
|
||||
@ -793,6 +999,202 @@ fu_vli_usbhub_device_update_v1 (FuVliUsbhubDevice *self,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* if no header1 or ROM code update, write data directly */
|
||||
static gboolean
|
||||
fu_vli_usbhub_device_update_v2_recovery (FuVliUsbhubDevice *self, GBytes *fw, GError **error)
|
||||
{
|
||||
gsize bufsz = 0;
|
||||
const guint8 *buf = g_bytes_get_data (fw, &bufsz);
|
||||
|
||||
/* erase */
|
||||
fu_device_set_status (FU_DEVICE (self), FWUPD_STATUS_DEVICE_ERASE);
|
||||
for (guint32 addr = 0; addr < bufsz; addr += 0x1000) {
|
||||
if (!fu_vli_usbhub_device_erase_sector (self, addr, error)) {
|
||||
g_prefix_error (error, "failed to erase sector @0x%x", addr);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/* write in chunks */
|
||||
fu_device_set_status (FU_DEVICE (self), FWUPD_STATUS_DEVICE_WRITE);
|
||||
if (!fu_vli_usbhub_device_write_blocks (self, VLI_USBHUB_FLASHMAP_ADDR_HD1,
|
||||
buf, bufsz, error))
|
||||
return FALSE;
|
||||
|
||||
/* success */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
fu_vli_usbhub_device_hd1_is_valid (FuVliUsbhubHeader *hdr)
|
||||
{
|
||||
if (hdr->prev_ptr != VLI_USBHUB_FLASHMAP_IDX_INVALID)
|
||||
return FALSE;
|
||||
if (hdr->checksum != fu_vli_usbhub_header_crc8 (hdr))
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
fu_vli_usbhub_device_hd1_recover (FuVliUsbhubDevice *self, FuVliUsbhubHeader *hdr, GError **error)
|
||||
{
|
||||
/* point to HD2, i.e. updated firmware */
|
||||
if (hdr->next_ptr != VLI_USBHUB_FLASHMAP_IDX_HD2) {
|
||||
hdr->next_ptr = VLI_USBHUB_FLASHMAP_IDX_HD2;
|
||||
hdr->checksum = fu_vli_usbhub_header_crc8 (hdr);
|
||||
}
|
||||
|
||||
/* write new header block */
|
||||
if (!fu_vli_usbhub_device_erase_sector (self, VLI_USBHUB_FLASHMAP_ADDR_HD1, error)) {
|
||||
g_prefix_error (error,
|
||||
"failed to erase header1 sector at 0x%x: ",
|
||||
(guint) VLI_USBHUB_FLASHMAP_ADDR_HD1);
|
||||
return FALSE;
|
||||
}
|
||||
if (!fu_vli_usbhub_device_write_block (self, VLI_USBHUB_FLASHMAP_ADDR_HD1,
|
||||
(const guint8 *) hdr,
|
||||
sizeof(FuVliUsbhubHeader),
|
||||
error)) {
|
||||
g_prefix_error (error,
|
||||
"failed to write header1 block at 0x%x: ",
|
||||
(guint) VLI_USBHUB_FLASHMAP_ADDR_HD1);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* update the cached copy */
|
||||
memcpy (&self->hd1_hdr, hdr, sizeof(self->hd1_hdr));
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
fu_vli_usbhub_device_update_v2 (FuVliUsbhubDevice *self, FuFirmware *firmware, GError **error)
|
||||
{
|
||||
gsize buf_fwsz = 0;
|
||||
guint32 hd1_fw_sz;
|
||||
guint32 hd2_fw_sz;
|
||||
guint32 hd2_fw_addr;
|
||||
guint32 hd2_fw_offset;
|
||||
const guint8 *buf_fw;
|
||||
FuVliUsbhubHeader hdr = { 0x0 };
|
||||
g_autoptr(GBytes) fw = NULL;
|
||||
|
||||
/* simple image */
|
||||
fw = fu_firmware_get_image_default_bytes (firmware, error);
|
||||
if (fw == NULL)
|
||||
return FALSE;
|
||||
|
||||
/* root header is valid */
|
||||
if (fu_vli_usbhub_device_hd1_is_valid (&self->hd1_hdr)) {
|
||||
|
||||
/* no update has ever been done */
|
||||
if (self->hd1_hdr.next_ptr != VLI_USBHUB_FLASHMAP_IDX_HD2) {
|
||||
|
||||
/* backup HD1 before recovering */
|
||||
if (!fu_vli_usbhub_device_erase_sector (self, VLI_USBHUB_FLASHMAP_ADDR_HD2, error)) {
|
||||
g_prefix_error (error, "failed to erase sector at header 1: ");
|
||||
return FALSE;
|
||||
}
|
||||
if (!fu_vli_usbhub_device_write_block (self, VLI_USBHUB_FLASHMAP_ADDR_HD1_BACKUP,
|
||||
(const guint8 *) &self->hd1_hdr, sizeof(hdr),
|
||||
error)) {
|
||||
g_prefix_error (error, "failed to write block at header 1: ");
|
||||
return FALSE;
|
||||
}
|
||||
if (!fu_vli_usbhub_device_hd1_recover (self, &self->hd1_hdr, error)) {
|
||||
g_prefix_error (error, "failed to write header: ");
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/* copy the header from the backup zone */
|
||||
} else {
|
||||
g_debug ("HD1 was invalid, reading backup");
|
||||
if (!fu_vli_usbhub_device_spi_read_data (self, VLI_USBHUB_FLASHMAP_ADDR_HD1_BACKUP,
|
||||
(guint8 *) &self->hd1_hdr, sizeof(hdr),
|
||||
error)) {
|
||||
g_prefix_error (error,
|
||||
"failed to read root header from 0x%x",
|
||||
(guint) VLI_USBHUB_FLASHMAP_ADDR_HD1_BACKUP);
|
||||
return FALSE;
|
||||
}
|
||||
if (!fu_vli_usbhub_device_hd1_is_valid (&self->hd1_hdr)) {
|
||||
g_debug ("backup header is also invalid, starting recovery");
|
||||
return fu_vli_usbhub_device_update_v2_recovery (self, fw, error);
|
||||
}
|
||||
if (!fu_vli_usbhub_device_hd1_recover (self, &self->hd1_hdr, error)) {
|
||||
g_prefix_error (error, "failed to get root header in backup zone: ");
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/* align the update fw address to the sector after the factory size */
|
||||
hd1_fw_sz = GUINT16_FROM_BE(self->hd1_hdr.usb3_fw_sz);
|
||||
if (hd1_fw_sz > 0xF000) {
|
||||
g_set_error (error,
|
||||
G_IO_ERROR,
|
||||
G_IO_ERROR_FAILED,
|
||||
"FW1 size abnormal 0x%x",
|
||||
(guint) hd1_fw_sz);
|
||||
return FALSE;
|
||||
}
|
||||
hd2_fw_addr = (hd1_fw_sz + 0xfff) & 0xf000;
|
||||
hd2_fw_addr += VLI_USBHUB_FLASHMAP_ADDR_FW;
|
||||
|
||||
/* get the size and offset of the update firmware */
|
||||
buf_fw = g_bytes_get_data (fw, &buf_fwsz);
|
||||
memcpy (&hdr, buf_fw, sizeof(hdr));
|
||||
hd2_fw_sz = GUINT16_FROM_BE(hdr.usb3_fw_sz);
|
||||
hd2_fw_offset = GUINT16_FROM_BE(hdr.usb3_fw_addr);
|
||||
g_debug ("FW2 @0x%x (length 0x%x, offset 0x%x)",
|
||||
hd2_fw_addr, hd2_fw_sz, hd2_fw_offset);
|
||||
|
||||
/* make space */
|
||||
fu_device_set_status (FU_DEVICE (self), FWUPD_STATUS_DEVICE_ERASE);
|
||||
if (!fu_vli_usbhub_device_erase_sectors (self, hd2_fw_addr, hd2_fw_sz, error))
|
||||
return FALSE;
|
||||
|
||||
/* perform the actual write */
|
||||
fu_device_set_status (FU_DEVICE (self), FWUPD_STATUS_DEVICE_WRITE);
|
||||
if (!fu_vli_usbhub_device_write_blocks (self,
|
||||
hd2_fw_addr,
|
||||
buf_fw + hd2_fw_offset,
|
||||
hd2_fw_sz,
|
||||
error)) {
|
||||
g_prefix_error (error, "failed to write payload: ");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* map into header */
|
||||
if (!fu_memcpy_safe ((guint8 *) &self->hd2_hdr, sizeof(hdr), 0x0,
|
||||
buf_fw, buf_fwsz, 0x0, sizeof(hdr), error)) {
|
||||
g_prefix_error (error, "failed to read header: ");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* write new HD2 */
|
||||
self->hd2_hdr.usb3_fw_addr = GUINT16_TO_BE(hd2_fw_addr & 0xffff);
|
||||
self->hd2_hdr.usb3_fw_addr_high = (guint8) (hd2_fw_addr >> 16);
|
||||
self->hd2_hdr.prev_ptr = VLI_USBHUB_FLASHMAP_IDX_HD1;
|
||||
self->hd2_hdr.next_ptr = VLI_USBHUB_FLASHMAP_IDX_INVALID;
|
||||
self->hd2_hdr.checksum = fu_vli_usbhub_header_crc8 (&self->hd2_hdr);
|
||||
if (!fu_vli_usbhub_device_erase_sector (self, VLI_USBHUB_FLASHMAP_ADDR_HD2, error)) {
|
||||
g_prefix_error (error, "failed to erase sectors for HD2: ");
|
||||
return FALSE;
|
||||
}
|
||||
if (!fu_vli_usbhub_device_write_block (self,
|
||||
VLI_USBHUB_FLASHMAP_ADDR_HD2,
|
||||
(const guint8 *) &self->hd2_hdr,
|
||||
sizeof(self->hd2_hdr),
|
||||
error)) {
|
||||
g_prefix_error (error, "failed to write HD2: ");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* success */
|
||||
fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_IS_BOOTLOADER);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static FuFirmware *
|
||||
fu_vli_usbhub_device_read_firmware (FuDevice *device, GError **error)
|
||||
{
|
||||
@ -812,12 +1214,6 @@ fu_vli_usbhub_device_write_firmware (FuDevice *device,
|
||||
GError **error)
|
||||
{
|
||||
FuVliUsbhubDevice *self = FU_VLI_USBHUB_DEVICE (device);
|
||||
g_autoptr(GBytes) fw = NULL;
|
||||
|
||||
/* simple image */
|
||||
fw = fu_firmware_get_image_default_bytes (firmware, error);
|
||||
if (fw == NULL)
|
||||
return FALSE;
|
||||
|
||||
/* disable powersaving if required */
|
||||
if (self->disable_powersave) {
|
||||
@ -829,7 +1225,9 @@ fu_vli_usbhub_device_write_firmware (FuDevice *device,
|
||||
|
||||
/* use correct method */
|
||||
if (self->update_protocol == 0x1)
|
||||
return fu_vli_usbhub_device_update_v1 (self, fw, error);
|
||||
return fu_vli_usbhub_device_update_v1 (self, firmware, error);
|
||||
if (self->update_protocol == 0x2)
|
||||
return fu_vli_usbhub_device_update_v2 (self, firmware, error);
|
||||
|
||||
/* not sure what to do */
|
||||
g_set_error (error,
|
||||
@ -859,7 +1257,10 @@ fu_vli_usbhub_device_attach (FuDevice *device, GError **error)
|
||||
NULL, &error_local)) {
|
||||
if (g_error_matches (error_local,
|
||||
G_USB_DEVICE_ERROR,
|
||||
G_USB_DEVICE_ERROR_NO_DEVICE)) {
|
||||
G_USB_DEVICE_ERROR_NO_DEVICE) ||
|
||||
g_error_matches (error_local,
|
||||
G_USB_DEVICE_ERROR,
|
||||
G_USB_DEVICE_ERROR_FAILED)) {
|
||||
g_debug ("ignoring %s", error_local->message);
|
||||
} else {
|
||||
g_propagate_prefixed_error (error,
|
||||
@ -909,12 +1310,11 @@ fu_vli_usbhub_device_init (FuVliUsbhubDevice *self)
|
||||
self->spi_cmd_read_data = 0x03;
|
||||
self->spi_cmd_read_status = 0x05;
|
||||
self->spi_cmd_write_en = 0x06;
|
||||
self->spi_cmd_sector_erase = 0x20;
|
||||
self->spi_cmd_chip_erase = 0x60;
|
||||
self->spi_cmd_read_id = 0x9f;
|
||||
self->spi_cmd_read_id_sz = 2;
|
||||
fu_device_add_icon (FU_DEVICE (self), "audio-card");
|
||||
fu_device_set_summary (FU_DEVICE (self), "Expand a single USB port into several");
|
||||
fu_device_set_install_duration (FU_DEVICE (self), 3); /* seconds */
|
||||
fu_device_set_firmware_size_max (FU_DEVICE (self), 0x20000);
|
||||
fu_device_set_remove_delay (FU_DEVICE (self), FU_DEVICE_REMOVE_DELAY_RE_ENUMERATE);
|
||||
}
|
||||
@ -925,6 +1325,7 @@ fu_vli_usbhub_device_class_init (FuVliUsbhubDeviceClass *klass)
|
||||
FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass);
|
||||
klass_device->to_string = fu_vli_usbhub_device_to_string;
|
||||
klass_device->set_quirk_kv = fu_vli_usbhub_device_set_quirk_kv;
|
||||
klass_device->probe = fu_vli_usbhub_device_probe;
|
||||
klass_device->setup = fu_vli_usbhub_device_setup;
|
||||
klass_device->read_firmware = fu_vli_usbhub_device_read_firmware;
|
||||
klass_device->write_firmware = fu_vli_usbhub_device_write_firmware;
|
||||
|
@ -13,8 +13,8 @@
|
||||
|
||||
struct _FuVliUsbhubFirmware {
|
||||
FuFirmwareClass parent_instance;
|
||||
guint16 device_id;
|
||||
FuVliUsbhubDeviceKind device_kind;
|
||||
FuVliUsbhubHeader hdr;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (FuVliUsbhubFirmware, fu_vli_usbhub_firmware, FU_TYPE_FIRMWARE)
|
||||
@ -30,16 +30,16 @@ guint16
|
||||
fu_vli_usbhub_firmware_get_device_id (FuVliUsbhubFirmware *self)
|
||||
{
|
||||
g_return_val_if_fail (FU_IS_VLI_USBHUB_FIRMWARE (self), 0);
|
||||
return self->device_id;
|
||||
return GUINT16_FROM_BE(self->hdr.dev_id);
|
||||
}
|
||||
|
||||
static void
|
||||
fu_vli_usbhub_firmware_to_string (FuFirmware *firmware, guint idt, GString *str)
|
||||
{
|
||||
FuVliUsbhubFirmware *self = FU_VLI_USBHUB_FIRMWARE (firmware);
|
||||
fu_common_string_append_kx (str, idt, "DeviceId", self->device_id);
|
||||
fu_common_string_append_kv (str, idt, "DeviceKind",
|
||||
fu_vli_usbhub_device_kind_to_string (self->device_kind));
|
||||
fu_vli_usbhub_header_to_string (&self->hdr, idt, str);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
@ -55,20 +55,18 @@ fu_vli_usbhub_firmware_parse (FuFirmware *firmware,
|
||||
guint16 adr_ofs = 0;
|
||||
guint16 version = 0x0;
|
||||
guint8 tmp = 0x0;
|
||||
FuVliUsbhubHeader hdr = { 0x0 };
|
||||
const guint8 *buf = g_bytes_get_data (fw, &bufsz);
|
||||
g_autoptr(FuFirmwareImage) img = fu_firmware_image_new (fw);
|
||||
|
||||
/* map into header */
|
||||
if (!fu_memcpy_safe ((guint8 *) &hdr, sizeof(hdr), 0x0,
|
||||
buf, bufsz, 0x0, sizeof(hdr), error)) {
|
||||
if (!fu_memcpy_safe ((guint8 *) &self->hdr, sizeof(self->hdr), 0x0,
|
||||
buf, bufsz, 0x0, sizeof(self->hdr), error)) {
|
||||
g_prefix_error (error, "failed to read header: ");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* get firmware versions */
|
||||
self->device_id = GUINT16_FROM_BE(hdr.dev_id);
|
||||
switch (self->device_id) {
|
||||
switch (GUINT16_FROM_BE(self->hdr.dev_id)) {
|
||||
case 0x0d12:
|
||||
/* VL81x */
|
||||
if (!fu_common_read_uint16_safe (buf, bufsz, 0x1f4c,
|
||||
@ -76,7 +74,7 @@ fu_vli_usbhub_firmware_parse (FuFirmware *firmware,
|
||||
g_prefix_error (error, "failed to get version: ");
|
||||
return FALSE;
|
||||
}
|
||||
version |= (hdr.unknown_02 >> 4) & 0x07;
|
||||
version |= (self->hdr.strapping1 >> 4) & 0x07;
|
||||
if ((version & 0x0f) == 0x04 ) {
|
||||
if (!fu_common_read_uint8_safe (buf, bufsz, 0x700d, &tmp, error)) {
|
||||
g_prefix_error (error, "failed to get version increment: ");
|
||||
@ -93,7 +91,7 @@ fu_vli_usbhub_firmware_parse (FuFirmware *firmware,
|
||||
g_prefix_error (error, "failed to get version: ");
|
||||
return FALSE;
|
||||
}
|
||||
version |= (hdr.unknown_02 >> 4) & 0x07;
|
||||
version |= (self->hdr.strapping1 >> 4) & 0x07;
|
||||
if ((version & 0x0f) == 0x04)
|
||||
version += 1;
|
||||
break;
|
||||
@ -109,7 +107,7 @@ fu_vli_usbhub_firmware_parse (FuFirmware *firmware,
|
||||
g_prefix_error (error, "failed to get offset version: ");
|
||||
return FALSE;
|
||||
}
|
||||
version |= (hdr.unknown_02 >> 4) & 0x07;
|
||||
version |= (self->hdr.strapping1 >> 4) & 0x07;
|
||||
}
|
||||
|
||||
/* version is set */
|
||||
@ -120,19 +118,19 @@ fu_vli_usbhub_firmware_parse (FuFirmware *firmware,
|
||||
}
|
||||
|
||||
/* get device type from firmware image */
|
||||
switch (self->device_id) {
|
||||
switch (GUINT16_FROM_BE(self->hdr.dev_id)) {
|
||||
case 0x0d12:
|
||||
{
|
||||
guint16 binver1 = 0x0;
|
||||
guint16 binver2 = 0x0;
|
||||
guint16 u2_addr = GUINT16_FROM_BE(hdr.u2_addr) + 0x1ff1;
|
||||
guint16 u3_addr = GUINT16_FROM_BE(hdr.u3_addr) + 0x1ffa;
|
||||
if (!fu_common_read_uint16_safe (buf, bufsz, u2_addr,
|
||||
guint16 usb2_fw_addr = GUINT16_FROM_BE(self->hdr.usb2_fw_addr) + 0x1ff1;
|
||||
guint16 usb3_fw_addr = GUINT16_FROM_BE(self->hdr.usb3_fw_addr) + 0x1ffa;
|
||||
if (!fu_common_read_uint16_safe (buf, bufsz, usb2_fw_addr,
|
||||
&binver1, G_LITTLE_ENDIAN, error)) {
|
||||
g_prefix_error (error, "failed to get binver1: ");
|
||||
return FALSE;
|
||||
}
|
||||
if (!fu_common_read_uint16_safe (buf, bufsz, u3_addr,
|
||||
if (!fu_common_read_uint16_safe (buf, bufsz, usb3_fw_addr,
|
||||
&binver2, G_LITTLE_ENDIAN, error)) {
|
||||
g_prefix_error (error, "failed to get binver2: ");
|
||||
return FALSE;
|
||||
@ -144,13 +142,13 @@ fu_vli_usbhub_firmware_parse (FuFirmware *firmware,
|
||||
self->device_kind = FU_VLI_USBHUB_DEVICE_KIND_VL813;
|
||||
|
||||
/* VLQ4S == VT3470 (Q4S) */
|
||||
} else if (hdr.unknown_02 & (1 << 7)) {
|
||||
} else if (self->hdr.strapping1 & FU_VLI_USBHUB_HEADER_STRAPPING1_Q4S) {
|
||||
self->device_kind = FU_VLI_USBHUB_DEVICE_KIND_VL812Q4S;
|
||||
|
||||
/* VL812 == VT3470 (812/813) */
|
||||
} else if (hdr.unknown_02 & (1 << 2)) {
|
||||
} else if (self->hdr.strapping1 & FU_VLI_USBHUB_HEADER_STRAPPING1_76PIN) {
|
||||
/* is B3 */
|
||||
if (hdr.unknown_02 & (1 << 3))
|
||||
if (self->hdr.strapping1 & FU_VLI_USBHUB_HEADER_STRAPPING1_B3UP)
|
||||
self->device_kind = FU_VLI_USBHUB_DEVICE_KIND_VL812B3;
|
||||
else
|
||||
self->device_kind = FU_VLI_USBHUB_DEVICE_KIND_VL812B0;
|
||||
@ -158,7 +156,7 @@ fu_vli_usbhub_firmware_parse (FuFirmware *firmware,
|
||||
/* VL811P == VT3470 */
|
||||
} else {
|
||||
/* is B3 */
|
||||
if (hdr.unknown_02 & (1 << 3))
|
||||
if (self->hdr.strapping1 & FU_VLI_USBHUB_HEADER_STRAPPING1_B3UP)
|
||||
self->device_kind = FU_VLI_USBHUB_DEVICE_KIND_VL811PB3;
|
||||
else
|
||||
self->device_kind = FU_VLI_USBHUB_DEVICE_KIND_VL811PB0;
|
||||
|
@ -1,6 +1,9 @@
|
||||
cargs = ['-DG_LOG_DOMAIN="FuPluginVliUsbhub"']
|
||||
|
||||
install_data(['vli-usbhub.quirk'],
|
||||
install_data([
|
||||
'vli-usbhub.quirk',
|
||||
'vli-usbhub-lenovo.quirk',
|
||||
],
|
||||
install_dir: join_paths(datadir, 'fwupd', 'quirks.d')
|
||||
)
|
||||
|
||||
|
160
plugins/vli-usbhub/vli-usbhub-lenovo.quirk
Normal file
160
plugins/vli-usbhub/vli-usbhub-lenovo.quirk
Normal file
@ -0,0 +1,160 @@
|
||||
# Lenovo CS18 Ultra Dock
|
||||
[DeviceInstanceId=USB\VID_17EF&PID_3070]
|
||||
Plugin = vli_usbhub
|
||||
Flags = usb3
|
||||
[DeviceInstanceId=USB\VID_17EF&PID_3071]
|
||||
Plugin = vli_usbhub
|
||||
Flags = usb2
|
||||
|
||||
# Lenovo CS18 Pro and Basic Dock
|
||||
[DeviceInstanceId=USB\VID_17EF&PID_3072]
|
||||
Plugin = vli_usbhub
|
||||
Flags = usb3
|
||||
[DeviceInstanceId=USB\VID_17EF&PID_3073]
|
||||
Plugin = vli_usbhub
|
||||
Flags = usb2
|
||||
|
||||
# Lenovo TR Dock
|
||||
[DeviceInstanceId=USB\VID_17EF&PID_307F]
|
||||
Plugin = vli_usbhub
|
||||
Flags = usb3
|
||||
[DeviceInstanceId=USB\VID_17EF&PID_3080]
|
||||
Plugin = vli_usbhub
|
||||
Flags = usb2
|
||||
|
||||
# Lenovo CS13 KG Dock
|
||||
[DeviceInstanceId=USB\VID_17EF&PID_1010]
|
||||
Plugin = vli_usbhub
|
||||
Flags = usb2,usb3
|
||||
|
||||
# Lenovo CS13 GD Dock
|
||||
[DeviceInstanceId=USB\VID_17EF&PID_1012]
|
||||
Plugin = vli_usbhub
|
||||
Flags = usb2,usb3
|
||||
|
||||
# Lenovo CS13 MO Dock
|
||||
[DeviceInstanceId=USB\VID_17EF&PID_1013]
|
||||
Plugin = vli_usbhub
|
||||
Flags = usb2,usb3
|
||||
|
||||
# Lenovo Payton dock
|
||||
[DeviceInstanceId=USB\VID_17EF&PID_305A]
|
||||
Plugin = vli_usbhub
|
||||
Flags = tier1,usb2,usb3
|
||||
[DeviceInstanceId=USB\VID_17EF&PID_305B]
|
||||
Plugin = vli_usbhub
|
||||
Flags = tier2,usb2,usb3
|
||||
|
||||
# Lenovo USB3 Ultra Dock
|
||||
[DeviceInstanceId=USB\VID_17EF&PID_1014]
|
||||
Plugin = vli_usbhub
|
||||
Flags = tier1,usb2,usb3
|
||||
[DeviceInstanceId=USB\VID_17EF&PID_1015]
|
||||
Plugin = vli_usbhub
|
||||
Flags = tier2,usb2,usb3
|
||||
|
||||
# Lenovo USB3 Pro Dock
|
||||
[DeviceInstanceId=USB\VID_17EF&PID_1016]
|
||||
Plugin = vli_usbhub
|
||||
Flags = tier1,usb2,usb3
|
||||
[DeviceInstanceId=USB\VID_17EF&PID_1018]
|
||||
Plugin = vli_usbhub
|
||||
Flags = tier2,usb2,usb3
|
||||
|
||||
# Lenovo Workstation D40
|
||||
[DeviceInstanceId=USB\VID_17EF&PID_1033]
|
||||
Plugin = vli_usbhub
|
||||
Flags = usb2,usb3
|
||||
|
||||
# Lenovo Workstation S40
|
||||
[DeviceInstanceId=USB\VID_17EF&PID_1034]
|
||||
Plugin = vli_usbhub
|
||||
Flags = usb2,usb3
|
||||
|
||||
# Lenovo Workstation v40
|
||||
[DeviceInstanceId=USB\VID_17EF&PID_1035]
|
||||
Plugin = vli_usbhub
|
||||
Flags = usb2,usb3
|
||||
|
||||
# Lenovo One Link Plus
|
||||
[DeviceInstanceId=USB\VID_17EF&PID_1018]
|
||||
Plugin = vli_usbhub
|
||||
Flags = tier1,usb2,usb3
|
||||
[DeviceInstanceId=USB\VID_17EF&PID_1019]
|
||||
Plugin = vli_usbhub
|
||||
Flags = tier2,usb2,usb3
|
||||
|
||||
# Lenovo Hybrid dock
|
||||
[DeviceInstanceId=USB\VID_17EF&PID_A356]
|
||||
Plugin = vli_usbhub
|
||||
Flags = tier1,usb3
|
||||
[DeviceInstanceId=USB\VID_17EF&PID_1028]
|
||||
Plugin = vli_usbhub
|
||||
Flags = tier1,usb2
|
||||
[DeviceInstanceId=USB\VID_17EF&PID_A357]
|
||||
Plugin = vli_usbhub
|
||||
Flags = tier2,usb3
|
||||
[DeviceInstanceId=USB\VID_17EF&PID_1029]
|
||||
Plugin = vli_usbhub
|
||||
Flags = tier2,usb2
|
||||
|
||||
# Lenovo Travel hub
|
||||
[DeviceInstanceId=USB\VID_17EF&PID_7216]
|
||||
Plugin = vli_usbhub
|
||||
Flags = usb3
|
||||
[DeviceInstanceId=USB\VID_17EF&PID_7224]
|
||||
Plugin = vli_usbhub
|
||||
Flags = usb2
|
||||
|
||||
# Lenovo Travel hub Gen2
|
||||
[DeviceInstanceId=USB\VID_17EF&PID_721D]
|
||||
Plugin = vli_usbhub
|
||||
Flags = usb3
|
||||
[DeviceInstanceId=USB\VID_17EF&PID_7225]
|
||||
Plugin = vli_usbhub
|
||||
Flags = usb2
|
||||
|
||||
# Lenovo Mini dock
|
||||
[DeviceInstanceId=USB\VID_17EF&PID_3074]
|
||||
Plugin = vli_usbhub
|
||||
Flags = usb3
|
||||
[DeviceInstanceId=USB\VID_17EF&PID_3095]
|
||||
Plugin = vli_usbhub
|
||||
Flags = usb2
|
||||
|
||||
# Lenovo Lenovo Travel Hub 1in3
|
||||
[DeviceInstanceId=USB\VID_17EF&PID_7228]
|
||||
Plugin = vli_usbhub
|
||||
Flags = usb3
|
||||
[DeviceInstanceId=USB\VID_17EF&PID_7226]
|
||||
Plugin = vli_usbhub
|
||||
Flags = usb2
|
||||
|
||||
# Lenovo Lenovo 1转7 Hub
|
||||
[DeviceInstanceId=USB\VID_17EF&PID_722A]
|
||||
Plugin = vli_usbhub
|
||||
Flags = usb3
|
||||
[DeviceInstanceId=USB\VID_17EF&PID_7229]
|
||||
Plugin = vli_usbhub
|
||||
Flags = usb2
|
||||
|
||||
# Lenovo Lenovo Gen2 dock
|
||||
[DeviceInstanceId=USB\VID_17EF&PID_A391]
|
||||
Plugin = vli_usbhub
|
||||
Flags = tier1,usb3
|
||||
[DeviceInstanceId=USB\VID_17EF&PID_A392]
|
||||
Plugin = vli_usbhub
|
||||
Flags = tier1,usb2
|
||||
[DeviceInstanceId=USB\VID_17EF&PID_A393]
|
||||
Plugin = vli_usbhub
|
||||
Flags = tier2,usb3
|
||||
[DeviceInstanceId=USB\VID_17EF&PID_A394]
|
||||
Plugin = vli_usbhub
|
||||
Flags = tier2,usb2
|
||||
[DeviceInstanceId=USB\VID_17EF&PID_A395]
|
||||
Plugin = vli_usbhub
|
||||
|
||||
# Lenovo Powered Hub
|
||||
[DeviceInstanceId=USB\VID_17EF&PID_721C]
|
||||
Plugin = vli_usbhub
|
||||
Flags = usb2
|
@ -27,6 +27,22 @@ Plugin = vli_usbhub
|
||||
[DeviceInstanceId=USB\VID_2109&PID_2212]
|
||||
Plugin = vli_usbhub
|
||||
|
||||
# VL817
|
||||
[DeviceInstanceId=USB\VID_2109&PID_0817]
|
||||
Plugin = vli_usbhub
|
||||
Flags = usb3
|
||||
[DeviceInstanceId=USB\VID_2109&PID_2817]
|
||||
Plugin = vli_usbhub
|
||||
Flags = usb2
|
||||
|
||||
# VL820
|
||||
[DeviceInstanceId=USB\VID_2109&PID_0820]
|
||||
Plugin = vli_usbhub
|
||||
Flags = usb3
|
||||
[DeviceInstanceId=USB\VID_2109&PID_2820]
|
||||
Plugin = vli_usbhub
|
||||
Flags = usb2
|
||||
|
||||
# A25Lxxx
|
||||
[Guid=VLI_USBHUB\\SPI_3730]
|
||||
SpiCmdChipErase = 0xc7
|
||||
|
Loading…
Reference in New Issue
Block a user