/** * dfu_image_to_dfuse: (skip) * @image: a #DfuImage * * Packs a DfuSe image * * Returns: (transfer full): the packed data **/ static GBytes * dfu_image_to_dfuse (DfuImage *image) { DfuSeImagePrefix *im; GPtrArray *elements; guint32 length_total = 0; guint32 offset = sizeof (DfuSeImagePrefix); guint8 *buf; g_autoptr(GPtrArray) element_array = NULL; /* get total size */ element_array = g_ptr_array_new_with_free_func ((GDestroyNotify) g_bytes_unref); elements = dfu_image_get_elements (image); for (guint i = 0; i < elements->len; i++) { DfuElement *element = g_ptr_array_index (elements, i); GBytes *bytes = dfu_element_to_dfuse (element); g_ptr_array_add (element_array, bytes); length_total += (guint32) g_bytes_get_size (bytes); } /* add prefix */ buf = g_malloc0 (length_total + sizeof (DfuSeImagePrefix)); im = (DfuSeImagePrefix *) buf; memcpy (im->sig, "Target", 6); im->alt_setting = dfu_image_get_alt_setting (image); if (dfu_image_get_name (image) != NULL) { im->target_named = GUINT32_TO_LE (0x01); memcpy (im->target_name, dfu_image_get_name (image), 255); } im->target_size = GUINT32_TO_LE (length_total); im->elements = GUINT32_TO_LE (elements->len); /* copy data */ for (guint i = 0; i < element_array->len; i++) { gsize length; GBytes *bytes = g_ptr_array_index (element_array, i); const guint8 *data = g_bytes_get_data (bytes, &length); memcpy (buf + offset, data, length); offset += (guint32) length; } return g_bytes_new_take (buf, length_total + sizeof (DfuSeImagePrefix)); }
/** * dfu_target_download: * @target: a #DfuTarget * @image: a #DfuImage * @flags: flags to use, e.g. %DFU_TARGET_TRANSFER_FLAG_VERIFY * @cancellable: a #GCancellable, or %NULL * @error: a #GError, or %NULL * * Downloads firmware from the host to the target, optionally verifying * the transfer. * * Return value: %TRUE for success * * Since: 0.5.4 **/ gboolean dfu_target_download (DfuTarget *target, DfuImage *image, DfuTargetTransferFlags flags, GCancellable *cancellable, GError **error) { DfuTargetPrivate *priv = GET_PRIVATE (target); DfuElement *element; GPtrArray *elements; gboolean ret; guint i; g_return_val_if_fail (DFU_IS_TARGET (target), FALSE); g_return_val_if_fail (DFU_IS_IMAGE (image), FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); /* ensure populated */ if (!dfu_target_setup (target, error)) return NULL; /* can the target do this? */ if (!dfu_device_can_download (priv->device)) { g_set_error_literal (error, DFU_ERROR, DFU_ERROR_NOT_SUPPORTED, "target cannot do downloading"); return FALSE; } /* use correct alt */ if (!dfu_target_use_alt_setting (target, error)) return FALSE; /* mark these as all erased */ if (dfu_device_has_dfuse_support (priv->device)) g_hash_table_remove_all (priv->sectors_erased); /* download all elements in the image to the device */ elements = dfu_image_get_elements (image); if (elements->len == 0) { g_set_error_literal (error, DFU_ERROR, DFU_ERROR_INVALID_FILE, "no image elements"); return FALSE; } for (i = 0; i < elements->len; i++) { element = dfu_image_get_element (image, i); g_debug ("downloading element at 0x%04x", dfu_element_get_address (element)); ret = dfu_target_download_element (target, element, flags, cancellable, error); if (!ret) return FALSE; } /* attempt to switch back to runtime */ if ((flags & DFU_TARGET_TRANSFER_FLAG_ATTACH) > 0 || (flags & DFU_TARGET_TRANSFER_FLAG_WAIT_RUNTIME) > 0) { if (!dfu_device_attach (priv->device, error)) return FALSE; } /* boot to runtime */ if (flags & DFU_TARGET_TRANSFER_FLAG_WAIT_RUNTIME) { g_debug ("booting to runtime to set auto-boot"); if (!dfu_device_wait_for_replug (priv->device, DFU_DEVICE_REPLUG_TIMEOUT, cancellable, error)) return FALSE; } /* success */ return TRUE; }