[PATCH] Look for DFU functional descriptor in the configuration descriptors

Tormod Volden lists.tormod at gmail.com
Fri Nov 5 22:32:38 CET 2010

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

Some devices are not able to return non-standard type descriptors when
asked explicitly, but will send them with the configuration descriptors.
 src/main.c |   29 ++++++++++++++++++++++++++++-
 1 files changed, 28 insertions(+), 1 deletions(-)

Hi, I am looking at the dfu-util code and trying to make it work with
some devices I have (under Linux). One issue with these devices is
that the usb_get_descriptor(dif->dev_handle, 0x21, ...) in main()
fails so that the transfer_size can not be deducted from the dfu
functional descriptor (type=0x21). I have confirmed that the device
firmware is not able to respond to a get_descriptor request of type
0x21, but only of the device, config and string types. For reference
I checked the Maple bootloader code, and they have explicitly added
support for the 0x21 type.

However, when I read section 9.4.3 of the USB 1.1 specification I am
not sure that my devices are to blame:
"The standard request to a device supports three types of descriptors:
DEVICE, CONFIGURATION, and STRING." and further "Class-specific and/or
vendor-specific descriptors follow the standard descriptors they
extend or modify."

I have checked that the functional descriptor is returned together
with the configuration descriptor as required by the specification (as
I understand it). So should dfu-util look for it there? This patch
makes it look for it there first, and if it is not found, it will do
the direct type=0x21 request like before.

Actually, libusb keeps track of all descriptors found during its
enumeration, and it is possible to pull out these "extra" descriptors
without sending new requests to the device. The libusb 0.1 code
stuffs the 0x21 descriptor in the "extra" field of one of the interface
altsettings. However I found it in altsetting[1] while I expected
it to be in altsetting[0], so either there is a libusb bug or I do not
understand it well enough.

I think also that libusb should be fixed/enhanced to answer
usb_get_descriptor calls by looking up its cached info rather than
sending repeated requests to the device. But that will definitely
not happen in the no-longer maintained libusb 0.1. So IMO we will
have to make these workarounds until 1) it is fixed in libusb 1.0
and 2) we have ported dfu-util to libusb 1.0.

Best regards,

diff --git a/src/main.c b/src/main.c
index fd373fc..9d0b72a 100644
--- a/src/main.c
+++ b/src/main.c
@@ -368,6 +368,33 @@ static int resolve_device_path(struct dfu_if *dif)
 #endif /* !HAVE_USBPATH_H */
+/* Look for descriptor in the configuration descriptor output */
+static int usb_get_extra_descriptor(usb_dev_handle *udev, unsigned char type,
+			unsigned char index, void *resbuf, int size)
+	char *cbuf;
+	int desclen, conflen, smallest;
+	int p = 0;
+	int ret = 0;
+	conflen = (usb_device(udev))->config->wTotalLength;
+	cbuf = malloc(conflen);
+	conflen = usb_get_descriptor(udev, USB_DT_CONFIG, index, cbuf, conflen);
+	while (p + 1 < conflen) {
+		desclen = (int) cbuf[p];
+		if (cbuf[p + 1] == type) {
+			smallest = desclen < size ? desclen : size;
+			memcpy(resbuf, &cbuf[p], smallest);
+			ret = smallest;
+			break;
+		}
+		p += desclen;
+	}
+	free(cbuf);
+	if (ret > 1) return ret;
+	/* try to retrieve it through usb_get_descriptor directly */
+	return usb_get_descriptor(udev, type, index, resbuf, size);
 static void help(void)
@@ -790,7 +817,7 @@ status_again:
 	if (!transfer_size) {
 		/* Obtain DFU functional descriptor */
-		ret = usb_get_descriptor(dif->dev_handle, 0x21, dif->interface,
+		ret = usb_get_extra_descriptor(dif->dev_handle, USB_DT_DFU, dif->interface,
 					 &func_dfu, sizeof(func_dfu));
 		if (ret < 0) {
 			fprintf(stderr, "Error obtaining DFU functional "

More information about the devel mailing list