Ejemplo n.º 1
0
/**
 * dfu_firmware_from_raw: (skip)
 * @firmware: a #DfuFirmware
 * @bytes: data to parse
 * @flags: some #DfuFirmwareParseFlags
 * @error: a #GError, or %NULL
 *
 * Unpacks into a firmware object from raw data.
 *
 * Returns: %TRUE for success
 **/
gboolean
dfu_firmware_from_raw (DfuFirmware *firmware,
		       GBytes *bytes,
		       DfuFirmwareParseFlags flags,
		       GError **error)
{
	g_autoptr(DfuElement) element = NULL;
	g_autoptr(DfuImage) image = NULL;
	image = dfu_image_new ();
	element = dfu_element_new ();
	dfu_element_set_contents (element, bytes);
	dfu_image_add_element (image, element);
	dfu_firmware_add_image (firmware, image);
	return TRUE;
}
Ejemplo n.º 2
0
/**
 * dfu_element_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 element from DfuSe data.
 *
 * Returns: a #DfuElement, or %NULL for error
 **/
static DfuElement *
dfu_element_from_dfuse (const guint8 *data,
			guint32 length,
			guint32 *consumed,
			GError **error)
{
	DfuElement *element = NULL;
	DfuSeElementPrefix *el = (DfuSeElementPrefix *) data;
	guint32 size;
	g_autoptr(GBytes) contents = NULL;

	g_assert_cmpint(sizeof(DfuSeElementPrefix), ==, 8);

	/* check input buffer size */
	if (length < sizeof(DfuSeElementPrefix)) {
		g_set_error (error,
			     FWUPD_ERROR,
			     FWUPD_ERROR_INTERNAL,
			     "invalid element data size %u",
			     (guint32) length);
		return NULL;
	}

	/* check size */
	size = GUINT32_FROM_LE (el->size);
	if (size + sizeof(DfuSeElementPrefix) > length) {
		g_set_error (error,
			     FWUPD_ERROR,
			     FWUPD_ERROR_INTERNAL,
			     "invalid element size %u, only %u bytes left",
			     size,
			     (guint32) (length - sizeof(DfuSeElementPrefix)));
		return NULL;
	}

	/* create new element */
	element = dfu_element_new ();
	dfu_element_set_address (element, GUINT32_FROM_LE (el->address));
	contents = g_bytes_new (data + sizeof(DfuSeElementPrefix), size);
	dfu_element_set_contents (element, contents);

	/* return size */
	if (consumed != NULL)
		*consumed = (guint32) sizeof(DfuSeElementPrefix) + size;

	return element;
}
Ejemplo n.º 3
0
/**
 * dfu_target_upload_element:
 **/
static DfuElement *
dfu_target_upload_element (DfuTarget *target,
			   guint32 address,
			   gsize expected_size,
			   GCancellable *cancellable,
			   GError **error)
{
	DfuTargetPrivate *priv = GET_PRIVATE (target);
	DfuSector *sector;
	DfuElement *element = NULL;
	GBytes *chunk_tmp;
	gsize chunk_size;
	gsize offset = 0;
	gsize total_size = 0;
	guint16 transfer_size = dfu_device_get_transfer_size (priv->device);
	guint8 *buffer;
	guint32 last_sector_id = G_MAXUINT;
	guint dfuse_sector_offset = 0;
	guint i;
	guint old_percentage = G_MAXUINT;
	g_autoptr(GBytes) contents = NULL;
	g_autoptr(GPtrArray) chunks = NULL;

	/* ST uses wBlockNum=0 for DfuSe commands and wBlockNum=1 is reserved */
	if (dfu_device_has_dfuse_support (priv->device)) {
		offset += address;
		dfuse_sector_offset = 2;
	}

	/* get all the chunks from the hardware */
	chunks = g_ptr_array_new_with_free_func ((GDestroyNotify) g_bytes_unref);
	for (i = 0; i < 0xffff; i++) {

		/* for DfuSe devices we need to handle the address manually */
		if (dfu_device_has_dfuse_support (priv->device)) {

			/* check the sector with this element address is suitable */
			sector = dfu_target_get_sector_for_addr (target, offset);
			if (sector == NULL) {
				g_set_error (error,
					     DFU_ERROR,
					     DFU_ERROR_INVALID_DEVICE,
					     "no memory sector at 0x%04x",
					     (guint) offset);
				return FALSE;
			}
			if (!dfu_sector_has_cap (sector, DFU_SECTOR_CAP_READABLE)) {
				g_set_error (error,
					     DFU_ERROR,
					     DFU_ERROR_INVALID_DEVICE,
					     "memory sector at 0x%04x is not readble",
					     (guint) offset);
				return FALSE;
			}

			/* manually set the sector address */
			if (dfu_sector_get_id (sector) != last_sector_id) {
				g_debug ("setting DfuSe address to 0x%04x", (guint) offset);
				if (!dfu_target_set_address (target,
							     offset,
							     cancellable,
							     error))
					return FALSE;
				last_sector_id = dfu_sector_get_id (sector);
			}
		}

		/* read chunk of data */
		chunk_tmp = dfu_target_upload_chunk (target,
						     i + dfuse_sector_offset,
						     cancellable,
						     error);
		if (chunk_tmp == NULL)
			return NULL;

		/* keep a sum of all the chunks */
		chunk_size = g_bytes_get_size (chunk_tmp);
		total_size += chunk_size;
		offset += chunk_size;

		/* add to array */
		g_debug ("got #%04x chunk of size %" G_GSIZE_FORMAT,
			 i, chunk_size);
		g_ptr_array_add (chunks, chunk_tmp);

		/* update UI */
		if (chunk_size > 0) {
			guint percentage = (total_size * 100) / expected_size;
			if (percentage != old_percentage) {
				g_signal_emit (target,
					       signals[SIGNAL_PERCENTAGE_CHANGED],
					       0, percentage);
			}
		}

		/* detect short write as EOF */
		if (chunk_size < transfer_size)
			break;
	}

	/* check final size */
	if (expected_size > 0) {
		if (total_size != expected_size) {
			g_set_error (error,
				     DFU_ERROR,
				     DFU_ERROR_INVALID_FILE,
				     "invalid size, got %" G_GSIZE_FORMAT ", "
				     "expected %" G_GSIZE_FORMAT ,
				     total_size, expected_size);
			return NULL;
		}
	}

	/* stitch them all together */
	offset = 0;
	buffer = g_malloc0 (total_size);
	for (i = 0; i < chunks->len; i++) {
		const guint8 *chunk_data;
		chunk_tmp = g_ptr_array_index (chunks, i);
		chunk_data = g_bytes_get_data (chunk_tmp, &chunk_size);
		memcpy (buffer + offset, chunk_data, chunk_size);
		offset += chunk_size;
	}

	/* create new image */
	contents = g_bytes_new_take (buffer, total_size);
	element = dfu_element_new ();
	dfu_element_set_contents (element, contents);
	return element;
}