mirror of
https://git.proxmox.com/git/fwupd
synced 2025-08-13 08:51:49 +00:00
libdfu: Do not do a zero-byte download when in DfuSe mode
For ST devices this means 'boot into APP mode' which we can also now populate.
This commit is contained in:
parent
8a3c18b4a3
commit
73b63c87e8
@ -1708,7 +1708,23 @@ dfu_device_attach (DfuDevice *device, GError **error)
|
||||
|
||||
/* there's a a special command for ST devices */
|
||||
if (priv->dfuse_supported) {
|
||||
//FIXME
|
||||
g_autoptr(DfuTarget) target = NULL;
|
||||
g_autoptr(GBytes) bytes_tmp = NULL;
|
||||
|
||||
/* get default target */
|
||||
target = dfu_device_get_target_by_alt_setting (device, 0, error);
|
||||
if (target == NULL)
|
||||
return FALSE;
|
||||
|
||||
/* do zero byte download */
|
||||
bytes_tmp = g_bytes_new (NULL, 0);
|
||||
if (!dfu_target_download_chunk (target,
|
||||
0 + 2,
|
||||
bytes_tmp,
|
||||
NULL,
|
||||
error))
|
||||
return FALSE;
|
||||
|
||||
dfu_device_set_action (device, DFU_ACTION_IDLE);
|
||||
return TRUE;
|
||||
}
|
||||
|
@ -36,6 +36,11 @@ GBytes *dfu_target_upload_chunk (DfuTarget *target,
|
||||
guint8 index,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
gboolean dfu_target_download_chunk (DfuTarget *target,
|
||||
guint8 index,
|
||||
GBytes *bytes,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
|
||||
/* export this just for the self tests */
|
||||
gboolean dfu_target_parse_sectors (DfuTarget *target,
|
||||
|
@ -648,7 +648,7 @@ dfu_target_setup (DfuTarget *target, GError **error)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gboolean
|
||||
dfu_target_download_chunk (DfuTarget *target, guint8 index, GBytes *bytes,
|
||||
GCancellable *cancellable, GError **error)
|
||||
{
|
||||
@ -1242,26 +1242,19 @@ _g_bytes_compare_verbose (GBytes *bytes1, GBytes *bytes2)
|
||||
}
|
||||
|
||||
static gboolean
|
||||
dfu_target_download_element (DfuTarget *target,
|
||||
dfu_target_download_element_dfu (DfuTarget *target,
|
||||
DfuElement *element,
|
||||
DfuTargetTransferFlags flags,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
DfuTargetPrivate *priv = GET_PRIVATE (target);
|
||||
DfuSector *sector;
|
||||
GBytes *bytes;
|
||||
guint i;
|
||||
guint nr_chunks;
|
||||
guint dfuse_sector_offset = 0;
|
||||
guint last_sector_id = G_MAXUINT;
|
||||
guint16 transfer_size = dfu_device_get_transfer_size (priv->device);
|
||||
g_autoptr(GError) error_local = NULL;
|
||||
|
||||
/* ST uses wBlockNum=0 for DfuSe commands and wBlockNum=1 is reserved */
|
||||
if (dfu_device_has_dfuse_support (priv->device))
|
||||
dfuse_sector_offset = 2;
|
||||
|
||||
/* round up as we have to transfer incomplete blocks */
|
||||
bytes = dfu_element_get_contents (element);
|
||||
nr_chunks = (guint) ceil ((gdouble) g_bytes_get_size (bytes) /
|
||||
@ -1274,6 +1267,78 @@ dfu_target_download_element (DfuTarget *target,
|
||||
return FALSE;
|
||||
}
|
||||
for (i = 0; i < nr_chunks + 1; i++) {
|
||||
gsize length;
|
||||
guint32 offset;
|
||||
g_autoptr(GBytes) bytes_tmp = NULL;
|
||||
|
||||
/* caclulate the offset into the element data */
|
||||
offset = i * transfer_size;
|
||||
|
||||
/* we have to write one final zero-sized chunk for EOF */
|
||||
if (i < nr_chunks) {
|
||||
length = g_bytes_get_size (bytes) - offset;
|
||||
if (length > transfer_size)
|
||||
length = transfer_size;
|
||||
bytes_tmp = g_bytes_new_from_bytes (bytes, offset, length);
|
||||
} else {
|
||||
bytes_tmp = g_bytes_new (NULL, 0);
|
||||
}
|
||||
g_debug ("writing #%04x chunk of size %" G_GSIZE_FORMAT,
|
||||
i, g_bytes_get_size (bytes_tmp));
|
||||
if (!dfu_target_download_chunk (target,
|
||||
(guint8) i,
|
||||
bytes_tmp,
|
||||
cancellable,
|
||||
error))
|
||||
return FALSE;
|
||||
|
||||
/* update UI */
|
||||
dfu_target_set_percentage (target, offset, g_bytes_get_size (bytes));
|
||||
|
||||
/* give the target a chance to update */
|
||||
g_usleep (dfu_device_get_download_timeout (priv->device) * 1000);
|
||||
|
||||
/* getting the status moves the state machine to DNLOAD-IDLE */
|
||||
if (!dfu_device_refresh (priv->device, cancellable, error))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* done */
|
||||
dfu_target_set_percentage_raw (target, 100);
|
||||
dfu_target_set_action (target, DFU_ACTION_IDLE);
|
||||
|
||||
/* success */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
dfu_target_download_element_dfuse (DfuTarget *target,
|
||||
DfuElement *element,
|
||||
DfuTargetTransferFlags flags,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
DfuTargetPrivate *priv = GET_PRIVATE (target);
|
||||
DfuSector *sector;
|
||||
GBytes *bytes;
|
||||
guint i;
|
||||
guint nr_chunks;
|
||||
guint last_sector_id = G_MAXUINT;
|
||||
guint16 transfer_size = dfu_device_get_transfer_size (priv->device);
|
||||
g_autoptr(GError) error_local = NULL;
|
||||
|
||||
/* round up as we have to transfer incomplete blocks */
|
||||
bytes = dfu_element_get_contents (element);
|
||||
nr_chunks = (guint) ceil ((gdouble) g_bytes_get_size (bytes) /
|
||||
(gdouble) transfer_size);
|
||||
if (nr_chunks == 0) {
|
||||
g_set_error_literal (error,
|
||||
DFU_ERROR,
|
||||
DFU_ERROR_INVALID_FILE,
|
||||
"zero-length firmware");
|
||||
return FALSE;
|
||||
}
|
||||
for (i = 0; i < nr_chunks; i++) {
|
||||
gsize length;
|
||||
guint32 offset;
|
||||
guint32 offset_dev;
|
||||
@ -1284,10 +1349,7 @@ dfu_target_download_element (DfuTarget *target,
|
||||
offset_dev = dfu_element_get_address (element) + offset;
|
||||
|
||||
/* for DfuSe devices we need to handle the erase and setting
|
||||
* the address manually */
|
||||
if (dfu_device_has_dfuse_support (priv->device)) {
|
||||
|
||||
/* check the sector with this element address is suitable */
|
||||
* the sectory address manually */
|
||||
sector = dfu_target_get_sector_for_addr (target, offset_dev);
|
||||
if (sector == NULL) {
|
||||
g_set_error (error,
|
||||
@ -1330,21 +1392,17 @@ dfu_target_download_element (DfuTarget *target,
|
||||
return FALSE;
|
||||
last_sector_id = dfu_sector_get_id (sector);
|
||||
}
|
||||
}
|
||||
|
||||
/* we have to write one final zero-sized chunk for EOF */
|
||||
if (i < nr_chunks) {
|
||||
length = g_bytes_get_size (bytes) - offset;
|
||||
if (length > transfer_size)
|
||||
length = transfer_size;
|
||||
bytes_tmp = g_bytes_new_from_bytes (bytes, offset, length);
|
||||
} else {
|
||||
bytes_tmp = g_bytes_new (NULL, 0);
|
||||
}
|
||||
g_debug ("writing #%04x chunk of size %" G_GSIZE_FORMAT,
|
||||
i, g_bytes_get_size (bytes_tmp));
|
||||
/* ST uses wBlockNum=0 for DfuSe commands and wBlockNum=1 is reserved */
|
||||
if (!dfu_target_download_chunk (target,
|
||||
(guint8) (i + dfuse_sector_offset),
|
||||
(guint8) (i + 2),
|
||||
bytes_tmp,
|
||||
cancellable,
|
||||
error))
|
||||
@ -1365,11 +1423,43 @@ dfu_target_download_element (DfuTarget *target,
|
||||
dfu_target_set_percentage_raw (target, 100);
|
||||
dfu_target_set_action (target, DFU_ACTION_IDLE);
|
||||
|
||||
/* success */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
dfu_target_download_element (DfuTarget *target,
|
||||
DfuElement *element,
|
||||
DfuTargetTransferFlags flags,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
DfuTargetPrivate *priv = GET_PRIVATE (target);
|
||||
|
||||
/* DfuSe specific */
|
||||
if (dfu_device_has_dfuse_support (priv->device)) {
|
||||
if (!dfu_target_download_element_dfuse (target,
|
||||
element,
|
||||
flags,
|
||||
cancellable,
|
||||
error))
|
||||
return FALSE;
|
||||
} else {
|
||||
if (!dfu_target_download_element_dfu (target,
|
||||
element,
|
||||
flags,
|
||||
cancellable,
|
||||
error))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* verify */
|
||||
if (flags & DFU_TARGET_TRANSFER_FLAG_VERIFY) {
|
||||
GBytes *bytes;
|
||||
GBytes *bytes_tmp;
|
||||
g_autoptr(DfuElement) element_tmp = NULL;
|
||||
dfu_target_set_action (target, DFU_ACTION_VERIFY);
|
||||
bytes = dfu_element_get_contents (element);
|
||||
element_tmp = dfu_target_upload_element (target,
|
||||
dfu_element_get_address (element),
|
||||
g_bytes_get_size (bytes),
|
||||
|
Loading…
Reference in New Issue
Block a user