[PATCH 4/4 v2 dfu-util] main: Always try to retrieve the DFU functional descriptor

Tormod Volden lists.tormod at gmail.com
Sun Sep 18 14:42:39 CEST 2011


From: Tormod Volden <debian.tormod at gmail.com>

It should exist both in run-time and DFU mode, and should
report the transfer size.

Also print out the device DFU version as reported by this
descriptor. For DFU 1.0 devices the descriptor does not contain
the version field, so set it to 1.00 if the field is missing.

Some devices seems to not provide the descriptor at all, for
now assume they are otherwise conforming to DFU 1.0 and use the
default transfer size of 1024.

Signed-off-by: Tormod Volden <debian.tormod at gmail.com>
---

Please consider this patch instead.

Once we know more about the broken devices we can add quirks, but
for now this will provide enough compatibility.

Tormod


 src/main.c |   52 ++++++++++++++++++++++++++++++++++++++++------------
 1 files changed, 40 insertions(+), 12 deletions(-)

diff --git a/src/main.c b/src/main.c
index 819e26c..e03ec3f 100644
--- a/src/main.c
+++ b/src/main.c
@@ -106,6 +106,7 @@ static int find_dfu_if(libusb_device *dev,
 						intf->bInterfaceNumber;
 					dfu_if->altsetting =
 						intf->bAlternateSetting;
+					/* FIXME: always 0 for DFU 1.0 */
 					if (intf->bInterfaceProtocol == 2)
 						dfu_if->flags |= DFU_IFF_DFU;
 					else
@@ -517,7 +518,7 @@ int main(int argc, char **argv)
 	unsigned int host_page_size;
 	enum mode mode = MODE_NONE;
 	struct dfu_status status;
-	struct usb_dfu_func_descriptor func_dfu;
+	struct usb_dfu_func_descriptor func_dfu, func_dfu_rt;
 	libusb_context *ctx;
 	struct dfu_file file;
 	char *alt_name = NULL; /* query alt name if non-NULL */
@@ -682,6 +683,22 @@ int main(int argc, char **argv)
 	/* find set of quirks for this device */
 	set_quirks(_rt_dif.vendor, _rt_dif.product);
 
+	/* Retrieve run-time DFU functional descriptor */
+	ret = usb_get_extra_descriptor(&_rt_dif, USB_DT_DFU, _rt_dif.interface,
+				       &func_dfu_rt, sizeof(func_dfu_rt));
+	if (ret == 7) {
+		/* DFU 1.0 does not have this field */
+		printf("Deducing device DFU version from functional descriptor "
+		       "length\n");
+		func_dfu_rt.bcdDFUVersion = libusb_cpu_to_le16(0x0100);
+	} else if (ret < 9) {
+		printf("Error obtaining DFU functional descriptor\n");
+		printf("Warning: Assuming DFU version 1.0\n");
+		func_dfu_rt.bcdDFUVersion = libusb_cpu_to_le16(0x0100);
+	}
+	printf("Run-time device DFU version %x\n",
+	       libusb_le16_to_cpu(func_dfu_rt.bcdDFUVersion));
+
 	if (!(_rt_dif.flags & DFU_IFF_DFU)) {
 		/* In the 'first round' during runtime mode, there can only be one
 		* DFU Interface descriptor according to the DFU Spec. */
@@ -888,19 +905,30 @@ status_again:
 		break;
 	}
 
+	/* Retrieve DFU mode DFU functional descriptor */
+	ret = usb_get_extra_descriptor(dif, USB_DT_DFU, dif->interface,
+				       &func_dfu, sizeof(func_dfu));
+	if (ret == 7) {
+		/* DFU 1.0 does not have this field */
+		func_dfu.bcdDFUVersion = libusb_cpu_to_le16(0x0100);
+	} else if (ret < 9) {
+		printf("Error obtaining DFU functional descriptor\n");
+		printf("Warning: Assuming DFU version 1.0\n");
+		func_dfu.bcdDFUVersion = libusb_cpu_to_le16(0x0100);
+		printf("Warning: Transfer size can not be detected\n");
+		func_dfu.wTransferSize = 0;
+	}
+	if (func_dfu.bcdDFUVersion != func_dfu_rt.bcdDFUVersion) {
+		fprintf(stderr, "DFU functional descriptor mismatch\n");
+		exit(1);
+	}
+
+	/* if not specified by user */
 	if (!transfer_size) {
-		/* Obtain DFU functional descriptor */
-		ret = usb_get_extra_descriptor(dif, USB_DT_DFU,
-				dif->interface, &func_dfu, sizeof(func_dfu));
-		if (ret < 0) {
-			fprintf(stderr, "Error obtaining DFU functional "
-				"descriptor\n");
-		} else {
-			transfer_size = libusb_le16_to_cpu(func_dfu.wTransferSize);
-			printf("Device returned transfer size %i\n",
-				transfer_size);
-		}
+		transfer_size = libusb_le16_to_cpu(func_dfu.wTransferSize);
+		printf("Device reported transfer size %i\n", transfer_size);
 	}
+
 	/* if returned zero or not detected (and not user specified) */
 	if (!transfer_size) {
 		transfer_size = DEFAULT_TRANSFER_SIZE;
-- 
1.7.5.4




More information about the devel mailing list