From 409a2c958c14364e710616797b372a24ffb6acb7 Mon Sep 17 00:00:00 2001 From: Jerry Zhang Date: Mon, 31 Aug 2020 12:33:24 -0500 Subject: [PATCH] dfu: Support polling the status from device in dfuManifest state Some devices may accumulate the firmware image and perform the entire reprogramming operation at one time. In this case, the device enters dfuMANIFEST-SYNC or dfuMANIFEST state after dfuDNLOAD-IDLE. The fwupd shall be able to poll the status from the device via DFU_GETSTATUS until the device completes the reprogramming or reports an error. For details, please refer to Section 7. Manifestation Phase and A.1 Interface State Transition Diagram in the USB DFU protocol. https://www.usb.org/sites/default/files/DFU_1.1.pdf For not affecting the other DFU capable devices, introduce a quirk "manifest-poll" to limit the logic. --- plugins/dfu/dfu-device.c | 1 + plugins/dfu/dfu-target.c | 47 ++++++++++++++++++++++++++++++++++++++++ plugins/dfu/dfu.quirk | 40 ++++++++++++++++++++++++++++++++++ 3 files changed, 88 insertions(+) diff --git a/plugins/dfu/dfu-device.c b/plugins/dfu/dfu-device.c index 2138f5a46..792f12f43 100644 --- a/plugins/dfu/dfu-device.c +++ b/plugins/dfu/dfu-device.c @@ -44,6 +44,7 @@ * * `legacy-protocol`: Use a legacy protocol version * * `detach-for-attach`: Requires a DFU_REQUEST_DETACH to attach * * `absent-sector-size`: In absence of sector size, assume byte + * * `manifest-poll`: Requires polling via GetStatus in dfuManifest state * * Default value: `none` * diff --git a/plugins/dfu/dfu-target.c b/plugins/dfu/dfu-target.c index ac5e9f683..e9d13d856 100644 --- a/plugins/dfu/dfu-target.c +++ b/plugins/dfu/dfu-target.c @@ -30,6 +30,8 @@ #include "fwupd-error.h" +#define DFU_TARGET_MANIFEST_MAX_POLLING_TRIES 200 + static void dfu_target_finalize (GObject *object); typedef struct { @@ -472,6 +474,46 @@ dfu_target_status_to_error_msg (DfuStatus status) return NULL; } +static gboolean +dfu_target_manifest_wait (DfuTarget *target, GError **error) +{ + DfuTargetPrivate *priv = GET_PRIVATE (target); + guint polling_count = 0; + + /* get the status */ + if (!dfu_device_refresh (priv->device, error)) + return FALSE; + + /* wait for DFU_STATE_DFU_MANIFEST to not be set */ + while (dfu_device_get_state (priv->device) == DFU_STATE_DFU_MANIFEST_SYNC || + dfu_device_get_state (priv->device) == DFU_STATE_DFU_MANIFEST) { + g_debug ("waiting for DFU_STATE_DFU_MANIFEST to clear"); + + if (polling_count++ > DFU_TARGET_MANIFEST_MAX_POLLING_TRIES) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "reach to max polling tries"); + return FALSE; + } + + g_usleep ((dfu_device_get_download_timeout (priv->device) + 1000) * 1000); + if (!dfu_device_refresh (priv->device, error)) + return FALSE; + } + + /* in an error state */ + if (dfu_device_get_state (priv->device) == DFU_STATE_DFU_ERROR) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + dfu_target_status_to_error_msg (dfu_device_get_status (priv->device))); + return FALSE; + } + + return TRUE; +} + gboolean dfu_target_check_status (DfuTarget *target, GError **error) { @@ -1285,6 +1327,11 @@ dfu_target_download (DfuTarget *target, DfuImage *image, return FALSE; } + if (fu_device_has_custom_flag (FU_DEVICE (dfu_target_get_device (target)), "manifest-poll") && + dfu_device_has_attribute (priv->device, DFU_DEVICE_ATTRIBUTE_MANIFEST_TOL)) + if (!dfu_target_manifest_wait (target, error)) + return FALSE; + /* success */ return TRUE; } diff --git a/plugins/dfu/dfu.quirk b/plugins/dfu/dfu.quirk index bbf172a72..5639c7cd0 100644 --- a/plugins/dfu/dfu.quirk +++ b/plugins/dfu/dfu.quirk @@ -329,3 +329,43 @@ Flags = absent-sector-size Plugin = dfu DfuForceVersion = 011a DfuForceTimeout = 5000 + +# Poly Studio +[DeviceInstanceId=USB\VID_095D&PID_9217] +Plugin = dfu +Flags = manifest-poll +[DeviceInstanceId=USB\VID_095D&PID_9218] +Plugin = dfu +Flags = manifest-poll + +# Poly Eagle Eye Cube +[DeviceInstanceId=USB\VID_095D&PID_9212] +Plugin = dfu +Flags = manifest-poll +[DeviceInstanceId=USB\VID_095D&PID_9213] +Plugin = dfu +Flags = manifest-poll + +# Poly P30 +[DeviceInstanceId=USB\VID_095D&PID_9290] +Plugin = dfu +Flags = manifest-poll +[DeviceInstanceId=USB\VID_095D&PID_9291] +Plugin = dfu +Flags = manifest-poll + +# Poly ULCC +[DeviceInstanceId=USB\VID_095D&PID_9160] +Plugin = dfu +Flags = manifest-poll +[DeviceInstanceId=USB\VID_095D&PID_927B] +Plugin = dfu +Flags = manifest-poll + +# Poly Eagle Eye Mini +[DeviceInstanceId=USB\VID_095D&PID_3001] +Plugin = dfu +Flags = manifest-poll +[DeviceInstanceId=USB\VID_095D&PID_3002] +Plugin = dfu +Flags = manifest-poll