/** * dfu_image_from_dfuse: (skip) * @data: data buffer * @length: length of @data we can access * @consumed: (out): the number of bytes we consued * @error: a #GError, or %NULL * * Unpacks an image from DfuSe data. * * Returns: a #DfuImage, or %NULL for error **/ static DfuImage * dfu_image_from_dfuse (const guint8 *data, guint32 length, guint32 *consumed, GError **error) { DfuSeImagePrefix *im; guint32 elements; guint32 offset = sizeof(DfuSeImagePrefix); g_autoptr(DfuImage) image = NULL; g_assert_cmpint(sizeof(DfuSeImagePrefix), ==, 274); /* check input buffer size */ if (length < sizeof(DfuSeImagePrefix)) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, "invalid image data size %u", (guint32) length); return NULL; } /* verify image signature */ im = (DfuSeImagePrefix *) data; if (memcmp (im->sig, "Target", 6) != 0) { g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, "invalid DfuSe target signature"); return NULL; } /* create new image */ image = dfu_image_new (); dfu_image_set_alt_setting (image, im->alt_setting); if (GUINT32_FROM_LE (im->target_named) == 0x01) dfu_image_set_name (image, im->target_name); /* parse elements */ length -= offset; elements = GUINT32_FROM_LE (im->elements); for (guint j = 0; j < elements; j++) { guint32 consumed_local; g_autoptr(DfuElement) element = NULL; element = dfu_element_from_dfuse (data + offset, length, &consumed_local, error); if (element == NULL) return NULL; dfu_image_add_element (image, element); offset += consumed_local; length -= consumed_local; } /* return size */ if (consumed != NULL) *consumed = offset; return g_object_ref (image); }
/** * dfu_target_upload: * @target: a #DfuTarget * @flags: flags to use, e.g. %DFU_TARGET_TRANSFER_FLAG_VERIFY * @cancellable: a #GCancellable, or %NULL * @error: a #GError, or %NULL * * Uploads firmware from the target to the host. * * Return value: (transfer full): the uploaded image, or %NULL for error * * Since: 0.5.4 **/ DfuImage * dfu_target_upload (DfuTarget *target, DfuTargetTransferFlags flags, GCancellable *cancellable, GError **error) { DfuTargetPrivate *priv = GET_PRIVATE (target); DfuSector *sector; guint i; guint32 last_sector_id = G_MAXUINT; g_autoptr(DfuImage) image = NULL; g_return_val_if_fail (DFU_IS_TARGET (target), NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); /* ensure populated */ if (!dfu_target_setup (target, error)) return NULL; /* can the target do this? */ if (!dfu_device_can_upload (priv->device)) { g_set_error_literal (error, DFU_ERROR, DFU_ERROR_NOT_SUPPORTED, "target cannot do uploading"); return NULL; } /* use correct alt */ if (!dfu_target_use_alt_setting (target, error)) return NULL; /* no open?! */ if (priv->sectors->len == 0) { g_set_error_literal (error, DFU_ERROR, DFU_ERROR_NOT_SUPPORTED, "no sectors defined for target"); return NULL; } /* create a new image */ image = dfu_image_new (); dfu_image_set_name (image, priv->alt_name); dfu_image_set_alt_setting (image, priv->alt_setting); /* get all the sectors for the device */ for (i = 0; i < priv->sectors->len; i++) { g_autoptr(DfuElement) element = NULL; /* only upload to the start of any zone:sector */ sector = g_ptr_array_index (priv->sectors, i); if (dfu_sector_get_id (sector) == last_sector_id) continue; /* get the first element from the hardware */ g_debug ("starting upload from 0x%08x (0x%04x)", dfu_sector_get_address (sector), dfu_sector_get_size_left (sector)); element = dfu_target_upload_element (target, dfu_sector_get_address (sector), dfu_sector_get_size_left (sector), cancellable, error); if (element == NULL) return NULL; /* this element was uploaded okay */ dfu_image_add_element (image, element); /* ignore sectors until one of these changes */ last_sector_id = dfu_sector_get_id (sector); } /* do host reset */ if ((flags & DFU_TARGET_TRANSFER_FLAG_ATTACH) > 0 || (flags & DFU_TARGET_TRANSFER_FLAG_WAIT_RUNTIME) > 0) { if (!dfu_device_attach (priv->device, error)) return NULL; } /* boot to runtime */ if (flags & DFU_TARGET_TRANSFER_FLAG_WAIT_RUNTIME) { g_debug ("booting to runtime"); if (!dfu_device_wait_for_replug (priv->device, DFU_DEVICE_REPLUG_TIMEOUT, cancellable, error)) return NULL; } /* success */ return g_object_ref (image); }