It doesn't work on all GD32V devices. Some of them do actually require a DFU_GETSTATUS request to leave, but then leave without responding to the request. Others leave as soon as they see a DFU_DNLOAD request with zero data length without even responding to that (which causes a warning message from dfuse_download());
File downloaded successfully
dfu-util: dfuse_download: libusb_control_transfer returned -1 (LIBUSB_ERROR_IO)
So I think this quirk needs to cover 4 possible cases;
Leaves without responding to the zero length DFU_DNLOAD request. I have a SeeedStudio GD32 RISC-V kit which does this (GD32VF103VBT6 which is a 100-pin version of the CBT6 with more peripherals and an EXMC memory controller). All works perfectly apart from the above warning message.
Leaves after responding to the DFU_DNLOAD request. I guess that the board from ticket #104 does this since they don't mention any warning message after changing the code.
Leaves without responding to the DFU_GETSTATUS request. The Sipeed Longan Nano (GD32VF103CBT6) does this. With the current QUIRK_DFUSE_LEAVE code it doesn't leave DFU mode (easily proved by running dfu-util a second time, which sees it in DFU mode and then it leaves when dfu-util does a DFU_GETSTATUS). Before that change it worked correctly but with the same error 74 as ticket #104.
Actually works according to the spec. Maybe there are GD32V devices that do :)
I can provide further info and logs if you need them, but I'm 99.9% certain that this diagnosis is correct.
This is my quick hack attempt at fixing it. It just sends both requests whether required or not, completely ignores any response or errors, and suppresses the warning from dfuse_download(). It's not great but in the end these devices are non-compliant and there's only so much you can do.
Feel free to use this code or not, I do not require any attribution if you do.
---
src/dfuse.c | 16 +++++++++++-----
1 file changed, 11 insertions(+), 5 deletions(-)
diff --git a/src/dfuse.c b/src/dfuse.c
index a0218e1..e68203b 100644
--- a/src/dfuse.c
+++ b/src/dfuse.c
@@ -165,8 +165,10 @@ static int dfuse_download(struct dfu_if *dif, const unsigned short length,
/* wLength */ length,
DFU_TIMEOUT);
if (status < 0) {
- warnx("dfuse_download: libusb_control_transfer returned %d (%s)",
- status, libusb_error_name(status));
+ if (!((dif->quirks & QUIRK_DFUSE_LEAVE) && !length && !data && transaction == 2)) {
+ warnx("dfuse_download: libusb_control_transfer returned %d (%s)",
+ status, libusb_error_name(status));
+ }
}
return status;
}
@@ -323,12 +325,16 @@ static int dfuse_dnload_chunk(struct dfu_if *dif, unsigned char *data, int size,
static void dfuse_do_leave(struct dfu_if *dif)
{
+ struct dfu_status dst;
+
if (dfuse_address_present)
dfuse_special_command(dif, dfuse_address, SET_ADDRESS);
- if (dif->quirks & QUIRK_DFUSE_LEAVE)
- /* leave without DFU_GETSTATUS */
+ if (dif->quirks & QUIRK_DFUSE_LEAVE) {
+ /* The device might leave after this request, with or without a response */
dfuse_download(dif, 0, NULL, 2);
- else
+ /* Or it might leave after this request, with or without a response */
+ dfu_get_status(dif, &dst);
+ } else
dfuse_dnload_chunk(dif, NULL, 0, 2);
}
--
2.30.0
Anonymous
Thanks for this info and code! I was afraid this was going to be more complicated :)
Thanks, I have applied this (slightly amended) in https://sourceforge.net/p/dfu-util/dfu-util/ci/ef7ba94e6e920ecb827a4f0611c27f7403df491c/
Tested on both my devices, works perfectly. Thanks!
In case it's useful info to anyone in the future this is a summary of the two different bootloaders I've seen. (I considered writing code to specifically identify them but I think that would be fragile. Anyway, there are 14 different devices in the GD32VF103 series of which I only have these two, so no idea how the other 12 behave).
GD32VF103VBT6 on a SeeedStudio GD32 RISC-V kit has version "1000", serial "3VBJ", incorrect flash count and page size, and option bytes on alt1. This device leaves as soon as it sees a zero length DFU_DNLOAD request, without responding.
GD32VF103CBT6 on a Sipeed Longan Nano has version "0100", serial "3CBJ", correct flash count and page size, no option bytes. This device handles the zero length DFU_DNLOAD request correctly but then leaves after DFU_GETSTATUS without responding.