mirror of
https://git.proxmox.com/git/fwupd
synced 2025-08-07 15:46:30 +00:00
libdfu: Support download and upload to ST DfuSe devices
Also, simplify the general download and upload API now we can deal with element data in chunks.
This commit is contained in:
parent
0256f04338
commit
e7ba943cf5
@ -52,6 +52,7 @@ IGNORE_HFILES= \
|
|||||||
dfu-device-private.h \
|
dfu-device-private.h \
|
||||||
dfu-element-private.h \
|
dfu-element-private.h \
|
||||||
dfu-image-private.h \
|
dfu-image-private.h \
|
||||||
|
dfu-sector-private.h \
|
||||||
dfu-target-private.h
|
dfu-target-private.h
|
||||||
|
|
||||||
# Images to copy into HTML directory.
|
# Images to copy into HTML directory.
|
||||||
|
@ -80,6 +80,7 @@ if (!dfu_device_download (dfu_device, dfu_firmware,
|
|||||||
<xi:include href="xml/dfu-firmware.xml"/>
|
<xi:include href="xml/dfu-firmware.xml"/>
|
||||||
<xi:include href="xml/dfu-image.xml"/>
|
<xi:include href="xml/dfu-image.xml"/>
|
||||||
<xi:include href="xml/dfu-element.xml"/>
|
<xi:include href="xml/dfu-element.xml"/>
|
||||||
|
<xi:include href="xml/dfu-sector.xml"/>
|
||||||
<xi:include href="xml/dfu-target.xml"/>
|
<xi:include href="xml/dfu-target.xml"/>
|
||||||
<xi:include href="xml/dfu-common.xml"/>
|
<xi:include href="xml/dfu-common.xml"/>
|
||||||
<xi:include href="xml/dfu-error.xml"/>
|
<xi:include href="xml/dfu-error.xml"/>
|
||||||
|
@ -34,6 +34,9 @@ libdfu_private_la_SOURCES = \
|
|||||||
dfu-image.c \
|
dfu-image.c \
|
||||||
dfu-image.h \
|
dfu-image.h \
|
||||||
dfu-image-private.h \
|
dfu-image-private.h \
|
||||||
|
dfu-sector.c \
|
||||||
|
dfu-sector.h \
|
||||||
|
dfu-sector-private.h \
|
||||||
dfu-target.c \
|
dfu-target.c \
|
||||||
dfu-target.h \
|
dfu-target.h \
|
||||||
dfu-target-private.h
|
dfu-target-private.h
|
||||||
|
@ -603,7 +603,6 @@ dfu_device_reset (DfuDevice *device, GError **error)
|
|||||||
/**
|
/**
|
||||||
* dfu_device_upload:
|
* dfu_device_upload:
|
||||||
* @device: a #DfuDevice
|
* @device: a #DfuDevice
|
||||||
* @expected_size: the expected size of the firmware, or 0 for unknown
|
|
||||||
* @flags: flags to use, e.g. %DFU_TARGET_TRANSFER_FLAG_VERIFY
|
* @flags: flags to use, e.g. %DFU_TARGET_TRANSFER_FLAG_VERIFY
|
||||||
* @cancellable: a #GCancellable, or %NULL
|
* @cancellable: a #GCancellable, or %NULL
|
||||||
* @progress_cb: a #GFileProgressCallback, or %NULL
|
* @progress_cb: a #GFileProgressCallback, or %NULL
|
||||||
@ -618,7 +617,6 @@ dfu_device_reset (DfuDevice *device, GError **error)
|
|||||||
**/
|
**/
|
||||||
DfuFirmware *
|
DfuFirmware *
|
||||||
dfu_device_upload (DfuDevice *device,
|
dfu_device_upload (DfuDevice *device,
|
||||||
gsize expected_size,
|
|
||||||
DfuTargetTransferFlags flags,
|
DfuTargetTransferFlags flags,
|
||||||
GCancellable *cancellable,
|
GCancellable *cancellable,
|
||||||
DfuProgressCallback progress_cb,
|
DfuProgressCallback progress_cb,
|
||||||
@ -646,25 +644,30 @@ dfu_device_upload (DfuDevice *device,
|
|||||||
dfu_firmware_set_release (firmware, 0xffff);
|
dfu_firmware_set_release (firmware, 0xffff);
|
||||||
|
|
||||||
/* APP -> DFU */
|
/* APP -> DFU */
|
||||||
if (flags & DFU_TARGET_TRANSFER_FLAG_DETACH) {
|
target_default = dfu_device_get_target_default (device, error);
|
||||||
target_default = dfu_device_get_target_default (device, error);
|
if (target_default == NULL)
|
||||||
if (target_default == NULL)
|
return NULL;
|
||||||
return NULL;
|
if (dfu_target_get_mode (target_default) == DFU_MODE_RUNTIME) {
|
||||||
if (dfu_target_get_mode (target_default) == DFU_MODE_RUNTIME) {
|
if ((flags & DFU_TARGET_TRANSFER_FLAG_DETACH) == 0) {
|
||||||
g_debug ("detaching");
|
g_set_error (error,
|
||||||
|
DFU_ERROR,
|
||||||
/* inform UI there's going to be a detach:attach */
|
DFU_ERROR_NOT_SUPPORTED,
|
||||||
if (progress_cb != NULL) {
|
"device is not in DFU mode");
|
||||||
progress_cb (DFU_STATE_APP_DETACH, 0, 0,
|
return FALSE;
|
||||||
progress_cb_data);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* detach and USB reset */
|
|
||||||
if (!dfu_target_detach (target_default, NULL, error))
|
|
||||||
return NULL;
|
|
||||||
if (!dfu_device_wait_for_replug (device, 5000, NULL, error))
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
g_debug ("detaching");
|
||||||
|
|
||||||
|
/* inform UI there's going to be a detach:attach */
|
||||||
|
if (progress_cb != NULL) {
|
||||||
|
progress_cb (DFU_STATE_APP_DETACH, 0, 0,
|
||||||
|
progress_cb_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* detach and USB reset */
|
||||||
|
if (!dfu_target_detach (target_default, NULL, error))
|
||||||
|
return NULL;
|
||||||
|
if (!dfu_device_wait_for_replug (device, 5000, NULL, error))
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* upload from each target */
|
/* upload from each target */
|
||||||
@ -673,7 +676,12 @@ dfu_device_upload (DfuDevice *device,
|
|||||||
DfuTarget *target;
|
DfuTarget *target;
|
||||||
g_autoptr(DfuImage) image = NULL;
|
g_autoptr(DfuImage) image = NULL;
|
||||||
target = g_ptr_array_index (targets, i);
|
target = g_ptr_array_index (targets, i);
|
||||||
image = dfu_target_upload (target, 0,
|
if (!dfu_target_open (target,
|
||||||
|
DFU_TARGET_OPEN_FLAG_NONE,
|
||||||
|
cancellable,
|
||||||
|
error))
|
||||||
|
return NULL;
|
||||||
|
image = dfu_target_upload (target,
|
||||||
DFU_TARGET_TRANSFER_FLAG_NONE,
|
DFU_TARGET_TRANSFER_FLAG_NONE,
|
||||||
cancellable,
|
cancellable,
|
||||||
progress_cb,
|
progress_cb,
|
||||||
@ -811,7 +819,18 @@ dfu_device_download (DfuDevice *device,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* APP -> DFU */
|
/* APP -> DFU */
|
||||||
if (flags & DFU_TARGET_TRANSFER_FLAG_DETACH) {
|
/* detach and USB reset */
|
||||||
|
target_default = dfu_device_get_target_default (device, error);
|
||||||
|
if (target_default == NULL)
|
||||||
|
return FALSE;
|
||||||
|
if (dfu_target_get_mode (target_default) == DFU_MODE_RUNTIME) {
|
||||||
|
if ((flags & DFU_TARGET_TRANSFER_FLAG_DETACH) == 0) {
|
||||||
|
g_set_error (error,
|
||||||
|
DFU_ERROR,
|
||||||
|
DFU_ERROR_NOT_SUPPORTED,
|
||||||
|
"device is not in DFU mode");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
/* inform UI there's going to be a detach:attach */
|
/* inform UI there's going to be a detach:attach */
|
||||||
if (progress_cb != NULL) {
|
if (progress_cb != NULL) {
|
||||||
@ -819,17 +838,11 @@ dfu_device_download (DfuDevice *device,
|
|||||||
progress_cb_data);
|
progress_cb_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* detach and USB reset */
|
g_debug ("detaching");
|
||||||
target_default = dfu_device_get_target_default (device, error);
|
if (!dfu_target_detach (target_default, NULL, error))
|
||||||
if (target_default == NULL)
|
return FALSE;
|
||||||
|
if (!dfu_device_wait_for_replug (device, 5000, NULL, error))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
if (dfu_target_get_mode (target_default) == DFU_MODE_RUNTIME) {
|
|
||||||
g_debug ("detaching");
|
|
||||||
if (!dfu_target_detach (target_default, NULL, error))
|
|
||||||
return FALSE;
|
|
||||||
if (!dfu_device_wait_for_replug (device, 5000, NULL, error))
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* download each target */
|
/* download each target */
|
||||||
|
@ -62,7 +62,6 @@ gboolean dfu_device_wait_for_replug (DfuDevice *device,
|
|||||||
GCancellable *cancellable,
|
GCancellable *cancellable,
|
||||||
GError **error);
|
GError **error);
|
||||||
DfuFirmware *dfu_device_upload (DfuDevice *device,
|
DfuFirmware *dfu_device_upload (DfuDevice *device,
|
||||||
gsize expected_size,
|
|
||||||
DfuTargetTransferFlags flags,
|
DfuTargetTransferFlags flags,
|
||||||
GCancellable *cancellable,
|
GCancellable *cancellable,
|
||||||
DfuProgressCallback progress_cb,
|
DfuProgressCallback progress_cb,
|
||||||
|
@ -928,7 +928,13 @@ dfu_firmware_write_data (DfuFirmware *firmware, GError **error)
|
|||||||
image = dfu_firmware_get_image_default (firmware);
|
image = dfu_firmware_get_image_default (firmware);
|
||||||
g_assert (image != NULL);
|
g_assert (image != NULL);
|
||||||
element = dfu_image_get_element (image, 0);
|
element = dfu_image_get_element (image, 0);
|
||||||
g_assert (element != NULL);
|
if (element == NULL) {
|
||||||
|
g_set_error (error,
|
||||||
|
DFU_ERROR,
|
||||||
|
DFU_ERROR_NOT_FOUND,
|
||||||
|
"no firmware element data to write");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
contents = dfu_element_get_contents (element);
|
contents = dfu_element_get_contents (element);
|
||||||
return g_bytes_ref (contents);
|
return g_bytes_ref (contents);
|
||||||
}
|
}
|
||||||
@ -940,7 +946,13 @@ dfu_firmware_write_data (DfuFirmware *firmware, GError **error)
|
|||||||
image = dfu_firmware_get_image_default (firmware);
|
image = dfu_firmware_get_image_default (firmware);
|
||||||
g_assert (image != NULL);
|
g_assert (image != NULL);
|
||||||
element = dfu_image_get_element (image, 0);
|
element = dfu_image_get_element (image, 0);
|
||||||
g_assert (element != NULL);
|
if (element == NULL) {
|
||||||
|
g_set_error (error,
|
||||||
|
DFU_ERROR,
|
||||||
|
DFU_ERROR_NOT_FOUND,
|
||||||
|
"no firmware element data to write");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
contents = dfu_element_get_contents (element);
|
contents = dfu_element_get_contents (element);
|
||||||
g_assert (contents != NULL);
|
g_assert (contents != NULL);
|
||||||
return dfu_firmware_add_footer (firmware, contents);
|
return dfu_firmware_add_footer (firmware, contents);
|
||||||
|
38
libdfu/dfu-sector-private.h
Normal file
38
libdfu/dfu-sector-private.h
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
|
||||||
|
*
|
||||||
|
* Copyright (C) 2015 Richard Hughes <richard@hughsie.com>
|
||||||
|
*
|
||||||
|
* Licensed under the GNU Lesser General Public License Version 2.1
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __DFU_SECTOR_PRIVATE_H
|
||||||
|
#define __DFU_SECTOR_PRIVATE_H
|
||||||
|
|
||||||
|
#include "dfu-sector.h"
|
||||||
|
|
||||||
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
DfuSector *dfu_sector_new (guint32 address,
|
||||||
|
guint32 size,
|
||||||
|
guint32 size_left,
|
||||||
|
guint16 zone,
|
||||||
|
guint16 number,
|
||||||
|
DfuSectorCap cap);
|
||||||
|
|
||||||
|
G_END_DECLS
|
||||||
|
|
||||||
|
#endif /* __DFU_SECTOR_PRIVATE_H */
|
229
libdfu/dfu-sector.c
Normal file
229
libdfu/dfu-sector.c
Normal file
@ -0,0 +1,229 @@
|
|||||||
|
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
|
||||||
|
*
|
||||||
|
* Copyright (C) 2015 Richard Hughes <richard@hughsie.com>
|
||||||
|
*
|
||||||
|
* Licensed under the GNU Lesser General Public License Version 2.1
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SECTION:dfu-sector
|
||||||
|
* @short_description: Object representing a sector on a chip
|
||||||
|
*
|
||||||
|
* This object represents an sector of memory at a specific address on the
|
||||||
|
* device itself.
|
||||||
|
*
|
||||||
|
* This allows relocatable data segments to be stored in different
|
||||||
|
* locations on the device itself.
|
||||||
|
*
|
||||||
|
* You can think of these objects as flash segments on devices, where a
|
||||||
|
* complete block can be erased and then written to.
|
||||||
|
*
|
||||||
|
* See also: #DfuElement
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "dfu-common.h"
|
||||||
|
#include "dfu-sector-private.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DfuSectorPrivate:
|
||||||
|
*
|
||||||
|
* Private #DfuSector data
|
||||||
|
**/
|
||||||
|
typedef struct {
|
||||||
|
guint32 address;
|
||||||
|
guint32 size;
|
||||||
|
guint32 size_left;
|
||||||
|
guint16 zone;
|
||||||
|
guint16 number;
|
||||||
|
DfuSectorCap cap;
|
||||||
|
} DfuSectorPrivate;
|
||||||
|
|
||||||
|
G_DEFINE_TYPE_WITH_PRIVATE (DfuSector, dfu_sector, G_TYPE_OBJECT)
|
||||||
|
#define GET_PRIVATE(o) (dfu_sector_get_instance_private (o))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* dfu_sector_class_init:
|
||||||
|
**/
|
||||||
|
static void
|
||||||
|
dfu_sector_class_init (DfuSectorClass *klass)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* dfu_sector_init:
|
||||||
|
**/
|
||||||
|
static void
|
||||||
|
dfu_sector_init (DfuSector *sector)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* dfu_sector_new: (skip)
|
||||||
|
* address: the address for the sector
|
||||||
|
* size: the size of this sector
|
||||||
|
* size_left: the size of the rest of the sector
|
||||||
|
* zone: the zone of memory the setor belongs
|
||||||
|
* number: the sector number in the zone
|
||||||
|
* cap: the #DfuSectorCap
|
||||||
|
*
|
||||||
|
* Creates a new DFU sector object.
|
||||||
|
*
|
||||||
|
* Return value: a new #DfuSector
|
||||||
|
*
|
||||||
|
* Since: 0.5.4
|
||||||
|
**/
|
||||||
|
DfuSector *
|
||||||
|
dfu_sector_new (guint32 address, guint32 size, guint32 size_left,
|
||||||
|
guint16 zone, guint16 number, DfuSectorCap cap)
|
||||||
|
{
|
||||||
|
DfuSectorPrivate *priv;
|
||||||
|
DfuSector *sector;
|
||||||
|
sector = g_object_new (DFU_TYPE_SECTOR, NULL);
|
||||||
|
priv = GET_PRIVATE (sector);
|
||||||
|
priv->address = address;
|
||||||
|
priv->size = size;
|
||||||
|
priv->size_left = size_left;
|
||||||
|
priv->zone = zone;
|
||||||
|
priv->number = number;
|
||||||
|
priv->cap = cap;
|
||||||
|
return sector;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* dfu_sector_get_address:
|
||||||
|
* @sector: a #DfuSector
|
||||||
|
*
|
||||||
|
* Gets the alternate setting.
|
||||||
|
*
|
||||||
|
* Return value: integer, or 0x00 for unset
|
||||||
|
*
|
||||||
|
* Since: 0.5.4
|
||||||
|
**/
|
||||||
|
guint32
|
||||||
|
dfu_sector_get_address (DfuSector *sector)
|
||||||
|
{
|
||||||
|
DfuSectorPrivate *priv = GET_PRIVATE (sector);
|
||||||
|
g_return_val_if_fail (DFU_IS_SECTOR (sector), 0x00);
|
||||||
|
return priv->address;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* dfu_sector_get_size:
|
||||||
|
* @sector: a #DfuSector
|
||||||
|
*
|
||||||
|
* Gets the alternate setting.
|
||||||
|
*
|
||||||
|
* Return value: integer, or 0x00 for unset
|
||||||
|
*
|
||||||
|
* Since: 0.5.4
|
||||||
|
**/
|
||||||
|
guint32
|
||||||
|
dfu_sector_get_size (DfuSector *sector)
|
||||||
|
{
|
||||||
|
DfuSectorPrivate *priv = GET_PRIVATE (sector);
|
||||||
|
g_return_val_if_fail (DFU_IS_SECTOR (sector), 0x00);
|
||||||
|
return priv->size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* dfu_sector_get_size_left:
|
||||||
|
* @sector: a #DfuSector
|
||||||
|
*
|
||||||
|
* Gets the alternate setting.
|
||||||
|
*
|
||||||
|
* Return value: integer, or 0x00 for unset
|
||||||
|
*
|
||||||
|
* Since: 0.5.4
|
||||||
|
**/
|
||||||
|
guint32
|
||||||
|
dfu_sector_get_size_left (DfuSector *sector)
|
||||||
|
{
|
||||||
|
DfuSectorPrivate *priv = GET_PRIVATE (sector);
|
||||||
|
g_return_val_if_fail (DFU_IS_SECTOR (sector), 0x00);
|
||||||
|
return priv->size_left;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* dfu_sector_get_id:
|
||||||
|
* @sector: a #DfuSector
|
||||||
|
*
|
||||||
|
* Gets the sector ID which is a combination of the zone and sector number.
|
||||||
|
* You can use this number to check if the segment is the 'same' as the last
|
||||||
|
* written or read sector.
|
||||||
|
*
|
||||||
|
* Return value: integer ID, or 0x00 for unset
|
||||||
|
*
|
||||||
|
* Since: 0.5.4
|
||||||
|
**/
|
||||||
|
guint32
|
||||||
|
dfu_sector_get_id (DfuSector *sector)
|
||||||
|
{
|
||||||
|
DfuSectorPrivate *priv = GET_PRIVATE (sector);
|
||||||
|
g_return_val_if_fail (DFU_IS_SECTOR (sector), 0x00);
|
||||||
|
return (((guint32) priv->zone) << 16) | priv->number;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* dfu_sector_has_cap:
|
||||||
|
* @sector: a #DfuSector
|
||||||
|
* @cap: a #DfuSectorCap, e.g. %DFU_SECTOR_CAP_ERASEABLE
|
||||||
|
*
|
||||||
|
* Finds out if the sector has the required capability.
|
||||||
|
*
|
||||||
|
* Return value: %TRUE if the sector has the capabilily
|
||||||
|
*
|
||||||
|
* Since: 0.5.4
|
||||||
|
**/
|
||||||
|
gboolean
|
||||||
|
dfu_sector_has_cap (DfuSector *sector, DfuSectorCap cap)
|
||||||
|
{
|
||||||
|
DfuSectorPrivate *priv = GET_PRIVATE (sector);
|
||||||
|
g_return_val_if_fail (DFU_IS_SECTOR (sector), FALSE);
|
||||||
|
return priv->cap & cap;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* dfu_sector_to_string:
|
||||||
|
* @sector: a #DfuSector
|
||||||
|
*
|
||||||
|
* Returns a string representaiton of the object.
|
||||||
|
*
|
||||||
|
* Return value: NULL terminated string, or %NULL for invalid
|
||||||
|
*
|
||||||
|
* Since: 0.5.4
|
||||||
|
**/
|
||||||
|
gchar *
|
||||||
|
dfu_sector_to_string (DfuSector *sector)
|
||||||
|
{
|
||||||
|
DfuSectorPrivate *priv = GET_PRIVATE (sector);
|
||||||
|
GString *str;
|
||||||
|
|
||||||
|
g_return_val_if_fail (DFU_IS_SECTOR (sector), NULL);
|
||||||
|
|
||||||
|
str = g_string_new ("");
|
||||||
|
g_string_append_printf (str,
|
||||||
|
"Zone:%i, Sec#:%i, Addr:0x%08x, "
|
||||||
|
"Size:0x%04x, Caps:0x%01x",
|
||||||
|
priv->zone, priv->number, priv->address,
|
||||||
|
priv->size, priv->cap);
|
||||||
|
return g_string_free (str, FALSE);
|
||||||
|
}
|
66
libdfu/dfu-sector.h
Normal file
66
libdfu/dfu-sector.h
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
|
||||||
|
*
|
||||||
|
* Copyright (C) 2015 Richard Hughes <richard@hughsie.com>
|
||||||
|
*
|
||||||
|
* Licensed under the GNU Lesser General Public License Version 2.1
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __DFU_SECTOR_H
|
||||||
|
#define __DFU_SECTOR_H
|
||||||
|
|
||||||
|
#include <glib-object.h>
|
||||||
|
#include <gio/gio.h>
|
||||||
|
|
||||||
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
#define DFU_TYPE_SECTOR (dfu_sector_get_type ())
|
||||||
|
G_DECLARE_DERIVABLE_TYPE (DfuSector, dfu_sector, DFU, SECTOR, GObject)
|
||||||
|
|
||||||
|
struct _DfuSectorClass
|
||||||
|
{
|
||||||
|
GObjectClass parent_class;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DfuSectorCap:
|
||||||
|
* @DFU_SECTOR_CAP_NONE: No operations possible
|
||||||
|
* @DFU_SECTOR_CAP_READABLE: Sector can be read
|
||||||
|
* @DFU_SECTOR_CAP_WRITEABLE: Sector can be written
|
||||||
|
* @DFU_SECTOR_CAP_ERASEABLE: Sector can be erased
|
||||||
|
*
|
||||||
|
* The flags indicating what the sector can do.
|
||||||
|
**/
|
||||||
|
typedef enum {
|
||||||
|
DFU_SECTOR_CAP_NONE = 0,
|
||||||
|
DFU_SECTOR_CAP_READABLE = 1 << 0,
|
||||||
|
DFU_SECTOR_CAP_WRITEABLE = 1 << 1,
|
||||||
|
DFU_SECTOR_CAP_ERASEABLE = 1 << 2,
|
||||||
|
/*< private >*/
|
||||||
|
DFU_SECTOR_CAP_LAST
|
||||||
|
} DfuSectorCap;
|
||||||
|
|
||||||
|
guint32 dfu_sector_get_id (DfuSector *sector);
|
||||||
|
guint32 dfu_sector_get_address (DfuSector *sector);
|
||||||
|
guint32 dfu_sector_get_size (DfuSector *sector);
|
||||||
|
guint32 dfu_sector_get_size_left (DfuSector *sector);
|
||||||
|
gboolean dfu_sector_has_cap (DfuSector *sector,
|
||||||
|
DfuSectorCap cap);
|
||||||
|
gchar *dfu_sector_to_string (DfuSector *sector);
|
||||||
|
|
||||||
|
G_END_DECLS
|
||||||
|
|
||||||
|
#endif /* __DFU_SECTOR_H */
|
@ -28,7 +28,8 @@
|
|||||||
#include "dfu-device.h"
|
#include "dfu-device.h"
|
||||||
#include "dfu-error.h"
|
#include "dfu-error.h"
|
||||||
#include "dfu-firmware.h"
|
#include "dfu-firmware.h"
|
||||||
#include "dfu-target.h"
|
#include "dfu-sector-private.h"
|
||||||
|
#include "dfu-target-private.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* dfu_test_get_filename:
|
* dfu_test_get_filename:
|
||||||
@ -322,6 +323,7 @@ dfu_device_func (void)
|
|||||||
static void
|
static void
|
||||||
dfu_colorhug_plus_func (void)
|
dfu_colorhug_plus_func (void)
|
||||||
{
|
{
|
||||||
|
GPtrArray *elements;
|
||||||
gboolean ret;
|
gboolean ret;
|
||||||
gboolean seen_app_idle = FALSE;
|
gboolean seen_app_idle = FALSE;
|
||||||
g_autoptr(DfuDevice) device = NULL;
|
g_autoptr(DfuDevice) device = NULL;
|
||||||
@ -425,10 +427,13 @@ dfu_colorhug_plus_func (void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* get a dump of the existing firmware */
|
/* get a dump of the existing firmware */
|
||||||
image = dfu_target_upload (target, 0, DFU_TARGET_TRANSFER_FLAG_NONE,
|
image = dfu_target_upload (target, DFU_TARGET_TRANSFER_FLAG_NONE,
|
||||||
NULL, NULL, NULL, &error);
|
NULL, NULL, NULL, &error);
|
||||||
g_assert_no_error (error);
|
g_assert_no_error (error);
|
||||||
g_assert (DFU_IS_IMAGE (image));
|
g_assert (DFU_IS_IMAGE (image));
|
||||||
|
elements = dfu_image_get_elements (image);
|
||||||
|
g_assert_nonnull (elements);
|
||||||
|
g_assert_cmpint (elements->len, ==, 1);
|
||||||
|
|
||||||
/* download a new firmware */
|
/* download a new firmware */
|
||||||
ret = dfu_target_download (target, image,
|
ret = dfu_target_download (target, image,
|
||||||
@ -460,6 +465,102 @@ dfu_colorhug_plus_func (void)
|
|||||||
g_assert (ret);
|
g_assert (ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* _dfu_target_sectors_to_string:
|
||||||
|
**/
|
||||||
|
static gchar *
|
||||||
|
_dfu_target_sectors_to_string (DfuTarget *target)
|
||||||
|
{
|
||||||
|
DfuSector *sector;
|
||||||
|
GPtrArray *sectors;
|
||||||
|
GString *str;
|
||||||
|
guint i;
|
||||||
|
|
||||||
|
str = g_string_new ("");
|
||||||
|
sectors = dfu_target_get_sectors (target);
|
||||||
|
for (i = 0; i < sectors->len; i++) {
|
||||||
|
g_autofree gchar *tmp = NULL;
|
||||||
|
sector = g_ptr_array_index (sectors, i);
|
||||||
|
tmp = dfu_sector_to_string (sector);
|
||||||
|
g_string_append_printf (str, "%s\n", tmp);
|
||||||
|
}
|
||||||
|
if (str->len > 0)
|
||||||
|
g_string_truncate (str, str->len - 1);
|
||||||
|
return g_string_free (str, FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
dfu_target_dfuse_func (void)
|
||||||
|
{
|
||||||
|
gboolean ret;
|
||||||
|
gchar *tmp;
|
||||||
|
g_autoptr(DfuTarget) target = NULL;
|
||||||
|
g_autoptr(GError) error = NULL;
|
||||||
|
|
||||||
|
/* NULL */
|
||||||
|
target = g_object_new (DFU_TYPE_TARGET, NULL);
|
||||||
|
ret = dfu_target_parse_sectors (target, NULL, &error);
|
||||||
|
g_assert_no_error (error);
|
||||||
|
g_assert (ret);
|
||||||
|
tmp = _dfu_target_sectors_to_string (target);
|
||||||
|
g_assert_cmpstr (tmp, ==, "");
|
||||||
|
g_free (tmp);
|
||||||
|
|
||||||
|
/* no addresses */
|
||||||
|
ret = dfu_target_parse_sectors (target, "@Flash3", &error);
|
||||||
|
g_assert_no_error (error);
|
||||||
|
g_assert (ret);
|
||||||
|
tmp = _dfu_target_sectors_to_string (target);
|
||||||
|
g_assert_cmpstr (tmp, ==, "");
|
||||||
|
g_free (tmp);
|
||||||
|
|
||||||
|
/* one sector, no space */
|
||||||
|
ret = dfu_target_parse_sectors (target, "@Internal Flash /0x08000000/2*001Ka", &error);
|
||||||
|
g_assert_no_error (error);
|
||||||
|
g_assert (ret);
|
||||||
|
tmp = _dfu_target_sectors_to_string (target);
|
||||||
|
g_assert_cmpstr (tmp, ==, "Zone:0, Sec#:0, Addr:0x08000000, Size:0x0400, Caps:0x1\n"
|
||||||
|
"Zone:0, Sec#:0, Addr:0x08000400, Size:0x0400, Caps:0x1");
|
||||||
|
g_free (tmp);
|
||||||
|
|
||||||
|
/* multiple sectors */
|
||||||
|
ret = dfu_target_parse_sectors (target, "@Flash1 /0x08000000/2*001 Ka,4*001 Kg", &error);
|
||||||
|
g_assert_no_error (error);
|
||||||
|
g_assert (ret);
|
||||||
|
tmp = _dfu_target_sectors_to_string (target);
|
||||||
|
g_assert_cmpstr (tmp, ==, "Zone:0, Sec#:0, Addr:0x08000000, Size:0x0400, Caps:0x1\n"
|
||||||
|
"Zone:0, Sec#:0, Addr:0x08000400, Size:0x0400, Caps:0x1\n"
|
||||||
|
"Zone:0, Sec#:1, Addr:0x08000000, Size:0x0400, Caps:0x7\n"
|
||||||
|
"Zone:0, Sec#:1, Addr:0x08000400, Size:0x0400, Caps:0x7\n"
|
||||||
|
"Zone:0, Sec#:1, Addr:0x08000800, Size:0x0400, Caps:0x7\n"
|
||||||
|
"Zone:0, Sec#:1, Addr:0x08000c00, Size:0x0400, Caps:0x7");
|
||||||
|
g_free (tmp);
|
||||||
|
|
||||||
|
/* non-contiguous */
|
||||||
|
ret = dfu_target_parse_sectors (target, "@Flash2 /0xF000/4*100Ba/0xE000/3*8Kg/0x80000/2*24Kg", &error);
|
||||||
|
g_assert_no_error (error);
|
||||||
|
g_assert (ret);
|
||||||
|
tmp = _dfu_target_sectors_to_string (target);
|
||||||
|
g_assert_cmpstr (tmp, ==, "Zone:0, Sec#:0, Addr:0x0000f000, Size:0x0064, Caps:0x1\n"
|
||||||
|
"Zone:0, Sec#:0, Addr:0x0000f064, Size:0x0064, Caps:0x1\n"
|
||||||
|
"Zone:0, Sec#:0, Addr:0x0000f0c8, Size:0x0064, Caps:0x1\n"
|
||||||
|
"Zone:0, Sec#:0, Addr:0x0000f12c, Size:0x0064, Caps:0x1\n"
|
||||||
|
"Zone:1, Sec#:0, Addr:0x0000e000, Size:0x2000, Caps:0x7\n"
|
||||||
|
"Zone:1, Sec#:0, Addr:0x00010000, Size:0x2000, Caps:0x7\n"
|
||||||
|
"Zone:1, Sec#:0, Addr:0x00012000, Size:0x2000, Caps:0x7\n"
|
||||||
|
"Zone:2, Sec#:0, Addr:0x00080000, Size:0x6000, Caps:0x7\n"
|
||||||
|
"Zone:2, Sec#:0, Addr:0x00086000, Size:0x6000, Caps:0x7");
|
||||||
|
g_free (tmp);
|
||||||
|
|
||||||
|
/* invalid */
|
||||||
|
ret = dfu_target_parse_sectors (target, "Flash", NULL);
|
||||||
|
g_assert (ret);
|
||||||
|
ret = dfu_target_parse_sectors (target, "@Internal Flash /0x08000000", NULL);
|
||||||
|
g_assert (!ret);
|
||||||
|
ret = dfu_target_parse_sectors (target, "@Internal Flash /0x08000000/12*001a", NULL);
|
||||||
|
g_assert (!ret);
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
main (int argc, char **argv)
|
main (int argc, char **argv)
|
||||||
{
|
{
|
||||||
@ -470,6 +571,7 @@ main (int argc, char **argv)
|
|||||||
|
|
||||||
/* tests go here */
|
/* tests go here */
|
||||||
g_test_add_func ("/libdfu/enums", dfu_enums_func);
|
g_test_add_func ("/libdfu/enums", dfu_enums_func);
|
||||||
|
g_test_add_func ("/libdfu/target(DfuSe}", dfu_target_dfuse_func);
|
||||||
g_test_add_func ("/libdfu/firmware{raw}", dfu_firmware_raw_func);
|
g_test_add_func ("/libdfu/firmware{raw}", dfu_firmware_raw_func);
|
||||||
g_test_add_func ("/libdfu/firmware{dfu}", dfu_firmware_dfu_func);
|
g_test_add_func ("/libdfu/firmware{dfu}", dfu_firmware_dfu_func);
|
||||||
g_test_add_func ("/libdfu/firmware{dfuse}", dfu_firmware_dfuse_func);
|
g_test_add_func ("/libdfu/firmware{dfuse}", dfu_firmware_dfuse_func);
|
||||||
|
@ -36,6 +36,11 @@ gboolean _dfu_target_update (DfuTarget *target,
|
|||||||
GCancellable *cancellable,
|
GCancellable *cancellable,
|
||||||
GError **error);
|
GError **error);
|
||||||
|
|
||||||
|
/* export this just for the self tests */
|
||||||
|
gboolean dfu_target_parse_sectors (DfuTarget *target,
|
||||||
|
const gchar *alt_name,
|
||||||
|
GError **error);
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
|
||||||
#endif /* __DFU_TARGET_PRIVATE_H */
|
#endif /* __DFU_TARGET_PRIVATE_H */
|
||||||
|
1121
libdfu/dfu-target.c
1121
libdfu/dfu-target.c
File diff suppressed because it is too large
Load Diff
@ -90,6 +90,7 @@ gboolean dfu_target_close (DfuTarget *target,
|
|||||||
DfuMode dfu_target_get_mode (DfuTarget *target);
|
DfuMode dfu_target_get_mode (DfuTarget *target);
|
||||||
DfuState dfu_target_get_state (DfuTarget *target);
|
DfuState dfu_target_get_state (DfuTarget *target);
|
||||||
DfuStatus dfu_target_get_status (DfuTarget *target);
|
DfuStatus dfu_target_get_status (DfuTarget *target);
|
||||||
|
GPtrArray *dfu_target_get_sectors (DfuTarget *target);
|
||||||
gboolean dfu_target_can_upload (DfuTarget *target);
|
gboolean dfu_target_can_upload (DfuTarget *target);
|
||||||
gboolean dfu_target_can_download (DfuTarget *target);
|
gboolean dfu_target_can_download (DfuTarget *target);
|
||||||
gboolean dfu_target_refresh (DfuTarget *target,
|
gboolean dfu_target_refresh (DfuTarget *target,
|
||||||
@ -105,7 +106,6 @@ gboolean dfu_target_clear_status (DfuTarget *target,
|
|||||||
GCancellable *cancellable,
|
GCancellable *cancellable,
|
||||||
GError **error);
|
GError **error);
|
||||||
DfuImage *dfu_target_upload (DfuTarget *target,
|
DfuImage *dfu_target_upload (DfuTarget *target,
|
||||||
gsize expected_size,
|
|
||||||
DfuTargetTransferFlags flags,
|
DfuTargetTransferFlags flags,
|
||||||
GCancellable *cancellable,
|
GCancellable *cancellable,
|
||||||
DfuProgressCallback progress_cb,
|
DfuProgressCallback progress_cb,
|
||||||
|
@ -861,7 +861,7 @@ dfu_tool_upload_target (DfuToolPrivate *priv, gchar **values, GError **error)
|
|||||||
helper.last_state = DFU_STATE_DFU_ERROR;
|
helper.last_state = DFU_STATE_DFU_ERROR;
|
||||||
helper.marks_total = 30;
|
helper.marks_total = 30;
|
||||||
helper.marks_shown = 0;
|
helper.marks_shown = 0;
|
||||||
image = dfu_target_upload (target, 0, flags, NULL,
|
image = dfu_target_upload (target, flags, NULL,
|
||||||
fu_tool_transfer_progress_cb, &helper,
|
fu_tool_transfer_progress_cb, &helper,
|
||||||
error);
|
error);
|
||||||
if (image == NULL)
|
if (image == NULL)
|
||||||
@ -928,7 +928,7 @@ dfu_tool_upload (DfuToolPrivate *priv, gchar **values, GError **error)
|
|||||||
helper.last_state = DFU_STATE_DFU_ERROR;
|
helper.last_state = DFU_STATE_DFU_ERROR;
|
||||||
helper.marks_total = 30;
|
helper.marks_total = 30;
|
||||||
helper.marks_shown = 0;
|
helper.marks_shown = 0;
|
||||||
firmware = dfu_device_upload (device, 0, flags, NULL,
|
firmware = dfu_device_upload (device, flags, NULL,
|
||||||
fu_tool_transfer_progress_cb, &helper,
|
fu_tool_transfer_progress_cb, &helper,
|
||||||
error);
|
error);
|
||||||
if (firmware == NULL)
|
if (firmware == NULL)
|
||||||
@ -1181,6 +1181,7 @@ dfu_tool_list_target (DfuTarget *target)
|
|||||||
{
|
{
|
||||||
const gchar *tmp;
|
const gchar *tmp;
|
||||||
gboolean ret;
|
gboolean ret;
|
||||||
|
guint i;
|
||||||
g_autofree gchar *alt_id = NULL;
|
g_autofree gchar *alt_id = NULL;
|
||||||
g_autoptr(GError) error_local = NULL;
|
g_autoptr(GError) error_local = NULL;
|
||||||
|
|
||||||
@ -1199,6 +1200,7 @@ dfu_tool_list_target (DfuTarget *target)
|
|||||||
DFU_TARGET_OPEN_FLAG_NONE,
|
DFU_TARGET_OPEN_FLAG_NONE,
|
||||||
NULL, &error_local);
|
NULL, &error_local);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
|
GPtrArray *sectors;
|
||||||
tmp = dfu_status_to_string (dfu_target_get_status (target));
|
tmp = dfu_status_to_string (dfu_target_get_status (target));
|
||||||
/* TRANSLATORS: device status, e.g. "OK" */
|
/* TRANSLATORS: device status, e.g. "OK" */
|
||||||
dfu_tool_print_indent (_("Status"), tmp, 2);
|
dfu_tool_print_indent (_("Status"), tmp, 2);
|
||||||
@ -1206,6 +1208,19 @@ dfu_tool_list_target (DfuTarget *target)
|
|||||||
tmp = dfu_state_to_string (dfu_target_get_state (target));
|
tmp = dfu_state_to_string (dfu_target_get_state (target));
|
||||||
/* TRANSLATORS: device state, i.e. appIDLE */
|
/* TRANSLATORS: device state, i.e. appIDLE */
|
||||||
dfu_tool_print_indent (_("State"), tmp, 2);
|
dfu_tool_print_indent (_("State"), tmp, 2);
|
||||||
|
|
||||||
|
/* print sector information */
|
||||||
|
sectors = dfu_target_get_sectors (target);
|
||||||
|
for (i = 0; i < sectors->len; i++) {
|
||||||
|
DfuSector *sector;
|
||||||
|
g_autofree gchar *msg = NULL;
|
||||||
|
g_autofree gchar *title = NULL;
|
||||||
|
sector = g_ptr_array_index (sectors, i);
|
||||||
|
msg = dfu_sector_to_string (sector);
|
||||||
|
/* TRANSLATORS: these are areas of memory on the chip */
|
||||||
|
title = g_strdup_printf ("%s 0x%02x", _("Region"), i);
|
||||||
|
dfu_tool_print_indent (title, msg, 3);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if (g_error_matches (error_local,
|
if (g_error_matches (error_local,
|
||||||
DFU_ERROR,
|
DFU_ERROR,
|
||||||
@ -1217,6 +1232,7 @@ dfu_tool_list_target (DfuTarget *target)
|
|||||||
dfu_tool_print_indent (_("Status"), error_local->message, 2);
|
dfu_tool_print_indent (_("Status"), error_local->message, 2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dfu_target_close (target, NULL);
|
dfu_target_close (target, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,6 +35,7 @@
|
|||||||
#include <libdfu/dfu-error.h>
|
#include <libdfu/dfu-error.h>
|
||||||
#include <libdfu/dfu-firmware.h>
|
#include <libdfu/dfu-firmware.h>
|
||||||
#include <libdfu/dfu-image.h>
|
#include <libdfu/dfu-image.h>
|
||||||
|
#include <libdfu/dfu-sector.h>
|
||||||
#include <libdfu/dfu-target.h>
|
#include <libdfu/dfu-target.h>
|
||||||
|
|
||||||
#undef __DFU_H_INSIDE__
|
#undef __DFU_H_INSIDE__
|
||||||
|
@ -417,7 +417,6 @@ fu_provider_usb_verify (FuProvider *provider,
|
|||||||
|
|
||||||
/* get data from hardware */
|
/* get data from hardware */
|
||||||
dfu_firmware = dfu_device_upload (dfu_device,
|
dfu_firmware = dfu_device_upload (dfu_device,
|
||||||
0,
|
|
||||||
DFU_TARGET_TRANSFER_FLAG_DETACH |
|
DFU_TARGET_TRANSFER_FLAG_DETACH |
|
||||||
DFU_TARGET_TRANSFER_FLAG_BOOT_RUNTIME,
|
DFU_TARGET_TRANSFER_FLAG_BOOT_RUNTIME,
|
||||||
NULL,
|
NULL,
|
||||||
|
Loading…
Reference in New Issue
Block a user