vli: Fix VL103 reboot from ROM mode to FW mode

The logic was wrong; we should have been using command 0xB0 for attach back to
FW mode for both VL10x and VL103. Using a generic reset on VL103 always reset
the device back into bootloader mode as the ROM signatures were being written
by command 0xC0.

As now attach and detach have different code paths, there's no point having a
`FuVliDevice->reset()` vfunc, and so we can make everything a little simpler at
the same time.
This commit is contained in:
Richard Hughes 2020-03-10 10:45:57 +00:00
parent df2ae010d5
commit aebd90baad
4 changed files with 89 additions and 88 deletions

View File

@ -73,19 +73,6 @@ fu_vli_device_get_spi_cmd (FuVliDevice *self,
return TRUE;
}
gboolean
fu_vli_device_reset (FuVliDevice *self, GError **error)
{
FuVliDeviceClass *klass = FU_VLI_DEVICE_GET_CLASS (self);
if (klass->reset != NULL) {
if (!klass->reset (self, error)) {
g_prefix_error (error, "failed to reset device: ");
return FALSE;
}
}
return TRUE;
}
static gboolean
fu_vli_device_spi_write_enable (FuVliDevice *self, GError **error)
{
@ -584,32 +571,6 @@ fu_vli_device_setup (FuDevice *device, GError **error)
return TRUE;
}
static gboolean
fu_vli_device_attach (FuDevice *device, GError **error)
{
g_autoptr(GError) error_local = NULL;
/* replug, and ignore the device going away */
fu_device_set_status (device, FWUPD_STATUS_DEVICE_RESTART);
fu_device_add_flag (device, FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG);
if (!fu_vli_device_reset (FU_VLI_DEVICE (device), &error_local)) {
if (g_error_matches (error_local,
G_USB_DEVICE_ERROR,
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,
g_steal_pointer (&error_local),
"failed to restart device: ");
return FALSE;
}
}
return TRUE;
}
static gboolean
fu_vli_device_set_quirk_kv (FuDevice *device,
const gchar *key,
@ -682,5 +643,4 @@ fu_vli_device_class_init (FuVliDeviceClass *klass)
klass_device->to_string = fu_vli_device_to_string;
klass_device->set_quirk_kv = fu_vli_device_set_quirk_kv;
klass_device->setup = fu_vli_device_setup;
klass_device->attach = fu_vli_device_attach;
}

View File

@ -21,8 +21,6 @@ struct _FuVliDeviceClass
void (*to_string) (FuVliDevice *self,
guint idt,
GString *str);
gboolean (*reset) (FuVliDevice *self,
GError **error);
gboolean (*spi_chip_erase) (FuVliDevice *self,
GError **error);
gboolean (*spi_sector_erase) (FuVliDevice *self,
@ -69,8 +67,6 @@ void fu_vli_device_set_spi_auto_detect (FuVliDevice *self,
gboolean spi_auto_detect);
FuVliDeviceKind fu_vli_device_get_kind (FuVliDevice *self);
guint32 fu_vli_device_get_offset (FuVliDevice *self);
gboolean fu_vli_device_reset (FuVliDevice *self,
GError **error);
gboolean fu_vli_device_get_spi_cmd (FuVliDevice *self,
FuVliDeviceSpiReq req,
guint8 *cmd,

View File

@ -216,32 +216,6 @@ fu_vli_pd_device_spi_write_data (FuVliDevice *self,
return TRUE;
}
static gboolean
fu_vli_pd_device_reset (FuVliDevice *device, GError **error)
{
return g_usb_device_control_transfer (fu_usb_device_get_dev (FU_USB_DEVICE (device)),
G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE,
G_USB_DEVICE_REQUEST_TYPE_VENDOR,
G_USB_DEVICE_RECIPIENT_DEVICE,
0xb0, 0x0000, 0x0000,
NULL, 0x0, NULL,
FU_VLI_DEVICE_TIMEOUT,
NULL, error);
}
static gboolean
fu_vli_pd_device_reset_vl103 (FuVliDevice *device, GError **error)
{
return g_usb_device_control_transfer (fu_usb_device_get_dev (FU_USB_DEVICE (device)),
G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE,
G_USB_DEVICE_REQUEST_TYPE_VENDOR,
G_USB_DEVICE_RECIPIENT_DEVICE,
0xc0, 0x0000, 0x0000,
NULL, 0x0, NULL,
FU_VLI_DEVICE_TIMEOUT,
NULL, error);
}
static gboolean
fu_vli_pd_device_parade_setup (FuVliPdDevice *self, GError **error)
{
@ -277,7 +251,6 @@ fu_vli_pd_device_setup (FuVliDevice *device, GError **error)
guint8 verbuf[4] = { 0x0 };
guint8 tmp = 0;
g_autofree gchar *version_str = NULL;
FuVliDeviceClass *klass = FU_VLI_DEVICE_GET_CLASS (device);
/* get version */
if (!g_usb_device_control_transfer (fu_usb_device_get_dev (FU_USB_DEVICE (self)),
@ -323,10 +296,6 @@ fu_vli_pd_device_setup (FuVliDevice *device, GError **error)
}
}
/* handle this in a different way */
if (fu_vli_device_get_kind (device) == FU_VLI_DEVICE_KIND_VL103)
klass->reset = fu_vli_pd_device_reset_vl103;
/* get bootloader mode */
if (!fu_vli_pd_device_read_reg (self, 0x00F7, &tmp, error))
return FALSE;
@ -459,11 +428,16 @@ fu_vli_pd_device_write_firmware (FuDevice *device,
return TRUE;
}
#define VL10X_CMD1_SET_ROM_SIG 0xa0 /* all VL10x */
#define VL10X_CMD2_CHIP_RESET 0xb0 /* all VL10x */
#define VL10X_CMD3_SET_ROM_SIG_AND_RESET 0xc0 /* VL103 only */
static gboolean
fu_vli_pd_device_detach (FuDevice *device, GError **error)
{
FuVliPdDevice *self = FU_VLI_PD_DEVICE (device);
guint8 tmp = 0;
guint8 cmd = VL10X_CMD2_CHIP_RESET;
g_autoptr(GError) error_local = NULL;
/* write GPIOs */
@ -482,12 +456,19 @@ fu_vli_pd_device_detach (FuDevice *device, GError **error)
return FALSE;
if (!fu_vli_pd_device_write_reg (self, 0x2AE5, 0x87, error))
return FALSE;
}
/* VL103 CMD1 does not work, so use CMD3 whose function is CMD1+CMD2 */
if (fu_vli_device_get_kind (FU_VLI_DEVICE (device)) == FU_VLI_DEVICE_KIND_VL103) {
cmd = VL10X_CMD3_SET_ROM_SIG_AND_RESET;
} else {
/* set ROM sig */
if (!g_usb_device_control_transfer (fu_usb_device_get_dev (FU_USB_DEVICE (device)),
G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE,
G_USB_DEVICE_REQUEST_TYPE_VENDOR,
G_USB_DEVICE_RECIPIENT_DEVICE,
0xa0, 0x0000, 0x0000,
VL10X_CMD1_SET_ROM_SIG,
0x0000, 0x0000,
NULL, 0x0, NULL,
FU_VLI_DEVICE_TIMEOUT,
NULL, error))
@ -496,7 +477,14 @@ fu_vli_pd_device_detach (FuDevice *device, GError **error)
/* reset from SPI_Code into ROM_Code */
fu_device_set_status (device, FWUPD_STATUS_DEVICE_RESTART);
if (!fu_vli_device_reset (FU_VLI_DEVICE (device), &error_local)) {
if (!g_usb_device_control_transfer (fu_usb_device_get_dev (FU_USB_DEVICE (device)),
G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE,
G_USB_DEVICE_REQUEST_TYPE_VENDOR,
G_USB_DEVICE_RECIPIENT_DEVICE,
cmd, 0x0000, 0x0000,
NULL, 0x0, NULL,
FU_VLI_DEVICE_TIMEOUT,
NULL, &error_local)) {
if (g_error_matches (error_local,
G_USB_DEVICE_ERROR,
G_USB_DEVICE_ERROR_FAILED)) {
@ -512,6 +500,43 @@ fu_vli_pd_device_detach (FuDevice *device, GError **error)
return TRUE;
}
static gboolean
fu_vli_pd_device_attach (FuDevice *device, GError **error)
{
g_autoptr(GError) error_local = NULL;
/* replug, and ignore the device going away */
fu_device_set_status (device, FWUPD_STATUS_DEVICE_RESTART);
fu_device_add_flag (device, FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG);
/* CMD2 works for VL10x *and* VL103 */
if (!g_usb_device_control_transfer (fu_usb_device_get_dev (FU_USB_DEVICE (device)),
G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE,
G_USB_DEVICE_REQUEST_TYPE_VENDOR,
G_USB_DEVICE_RECIPIENT_DEVICE,
VL10X_CMD2_CHIP_RESET,
0x0000, 0x0000,
NULL, 0x0, NULL,
FU_VLI_DEVICE_TIMEOUT,
NULL, &error_local)) {
if (g_error_matches (error_local,
G_USB_DEVICE_ERROR,
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,
g_steal_pointer (&error_local),
"failed to restart device: ");
return FALSE;
}
}
return TRUE;
}
static void
fu_vli_pd_device_init (FuVliPdDevice *self)
{
@ -533,9 +558,9 @@ fu_vli_pd_device_class_init (FuVliPdDeviceClass *klass)
klass_device->read_firmware = fu_vli_pd_device_read_firmware;
klass_device->write_firmware = fu_vli_pd_device_write_firmware;
klass_device->prepare_firmware = fu_vli_pd_device_prepare_firmware;
klass_device->attach = fu_vli_pd_device_attach;
klass_device->detach = fu_vli_pd_device_detach;
klass_vli_device->setup = fu_vli_pd_device_setup;
klass_vli_device->reset = fu_vli_pd_device_reset;
klass_vli_device->spi_chip_erase = fu_vli_pd_device_spi_chip_erase;
klass_vli_device->spi_sector_erase = fu_vli_pd_device_spi_sector_erase;
klass_vli_device->spi_read_data = fu_vli_pd_device_spi_read_data;

View File

@ -325,16 +325,36 @@ fu_vli_usbhub_device_spi_write_data (FuVliDevice *self,
}
static gboolean
fu_vli_usbhub_device_reset (FuVliDevice *device, GError **error)
fu_vli_usbhub_device_attach (FuDevice *device, GError **error)
{
return g_usb_device_control_transfer (fu_usb_device_get_dev (FU_USB_DEVICE (device)),
G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE,
G_USB_DEVICE_REQUEST_TYPE_VENDOR,
G_USB_DEVICE_RECIPIENT_DEVICE,
0xf6, 0x0040, 0x0002,
NULL, 0x0, NULL,
FU_VLI_DEVICE_TIMEOUT,
NULL, error);
g_autoptr(GError) error_local = NULL;
/* replug, and ignore the device going away */
fu_device_set_status (device, FWUPD_STATUS_DEVICE_RESTART);
fu_device_add_flag (device, FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG);
if (!g_usb_device_control_transfer (fu_usb_device_get_dev (FU_USB_DEVICE (device)),
G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE,
G_USB_DEVICE_REQUEST_TYPE_VENDOR,
G_USB_DEVICE_RECIPIENT_DEVICE,
0xf6, 0x0040, 0x0002,
NULL, 0x0, NULL,
FU_VLI_DEVICE_TIMEOUT,
NULL, &error_local)) {
if (g_error_matches (error_local,
G_USB_DEVICE_ERROR,
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,
g_steal_pointer (&error_local),
"failed to restart device: ");
return FALSE;
}
}
return TRUE;
}
/* disable hub sleep states -- not really required by 815~ hubs */
@ -995,9 +1015,9 @@ fu_vli_usbhub_device_class_init (FuVliUsbhubDeviceClass *klass)
klass_device->read_firmware = fu_vli_usbhub_device_read_firmware;
klass_device->write_firmware = fu_vli_usbhub_device_write_firmware;
klass_device->prepare_firmware = fu_vli_usbhub_device_prepare_firmware;
klass_device->attach = fu_vli_usbhub_device_attach;
klass_vli_device->to_string = fu_vli_usbhub_device_to_string;
klass_vli_device->setup = fu_vli_usbhub_device_setup;
klass_vli_device->reset = fu_vli_usbhub_device_reset;
klass_vli_device->spi_chip_erase = fu_vli_usbhub_device_spi_chip_erase;
klass_vli_device->spi_sector_erase = fu_vli_usbhub_device_spi_sector_erase;
klass_vli_device->spi_read_data = fu_vli_usbhub_device_spi_read_data;