You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

USB标准中Functional Descriptor是什么?DFU开发及libusb使用疑问

Understanding USB DFU Functional Descriptors with libusb

Let's break down your questions clearly— I remember being confused about class-specific descriptors when I first started with USB DFU too, so I get where you're coming from.

1. What is a Functional Descriptor?

Unlike standard USB descriptors (Device, Configuration, Interface, Endpoint) that define basic hardware capabilities, Functional Descriptors are class-specific—they exist to share extra details unique to a particular USB device class (in your case, DFU).

For Run-Time DFU, this descriptor tells the host critical information about how the device behaves in DFU mode, like:

  • Whether the device supports firmware downloads (bmAttributes bit 0) or uploads (bit 1)
  • How long the device waits before detaching from USB to enter DFU mode (wDetachTimeOut)
  • The maximum size of data transfers allowed during DFU operations (wTransferSize)
  • The version of the DFU specification the device complies with (bcdDFUVersion)

It’s always tied to a specific DFU interface, and sits right after the Interface Descriptor in the configuration descriptor hierarchy.

2. How to Retrieve a DFU Functional Descriptor with libusb

Libusb doesn’t have a built-in function to directly fetch this descriptor, but you can extract it from the configuration descriptor’s extra data. Here’s a practical, commented example:

First, define the DFU Functional Descriptor structure (matching the DFU 1.1 spec):

#include <libusb-1.0/libusb.h>
#include <stdint.h>
#include <stdio.h>
#include <endian.h>

// DFU Functional Descriptor structure from the DFU 1.1 specification
typedef struct {
    uint8_t  bLength;          // Size of this descriptor (always 9 bytes)
    uint8_t  bDescriptorType;  // DFU descriptor type (0x21)
    uint8_t  bDescriptorSubtype;// Run-Time DFU subtype (0x01)
    uint16_t bmAttributes;     // Device DFU capabilities (bits 0-4)
    uint16_t wDetachTimeOut;   // Timeout in ms before detaching to DFU mode
    uint16_t wTransferSize;    // Maximum DFU data transfer size
    uint16_t bcdDFUVersion;    // DFU spec version (0x0110 for v1.1)
} dfu_functional_descriptor;

Then, the code to locate and parse the descriptor:

int main() {
    libusb_context *ctx = NULL;
    libusb_device_handle *dev_handle = NULL;
    int r;

    // Initialize libusb context
    r = libusb_init(&ctx);
    if (r < 0) {
        fprintf(stderr, "Failed to initialize libusb: %s\n", libusb_strerror(r));
        return 1;
    }

    // Replace with your device's actual VID/PID
    dev_handle = libusb_open_device_with_vid_pid(ctx, 0x1234, 0x5678);
    if (!dev_handle) {
        fprintf(stderr, "Could not open target device\n");
        libusb_exit(ctx);
        return 1;
    }

    // Fetch the active configuration descriptor
    struct libusb_config_descriptor *config = NULL;
    r = libusb_get_active_config_descriptor(libusb_get_device(dev_handle), &config);
    if (r < 0) {
        fprintf(stderr, "Failed to get config descriptor: %s\n", libusb_strerror(r));
        libusb_close(dev_handle);
        libusb_exit(ctx);
        return 1;
    }

    // Iterate through interfaces to find the DFU interface
    for (int i = 0; i < config->bNumInterfaces; i++) {
        const struct libusb_interface *iface = &config->interface[i];
        for (int j = 0; j < iface->num_altsetting; j++) {
            const struct libusb_interface_descriptor *iface_desc = &iface->altsetting[j];
            
            // Check if this is a DFU interface (Class 0xFE, Subclass 0x01)
            if (iface_desc->bInterfaceClass == 0xFE && iface_desc->bInterfaceSubClass == 0x01) {
                printf("Found DFU interface\n");

                // Scan the interface's extra data for the Functional Descriptor
                const uint8_t *extra = iface_desc->extra;
                int extra_len = iface_desc->extra_length;

                while (extra_len > 0) {
                    uint8_t desc_len = extra[0];
                    uint8_t desc_type = extra[1];

                    // Match the DFU Functional Descriptor (type 0x21, correct length)
                    if (desc_type == 0x21 && desc_len == sizeof(dfu_functional_descriptor)) {
                        const dfu_functional_descriptor *dfu_desc = (const dfu_functional_descriptor *)extra;
                        
                        // Print parsed details (convert little-endian to host byte order)
                        printf("\nDFU Functional Descriptor Details:\n");
                        printf("- Capabilities (bmAttributes): 0x%04X\n", le16toh(dfu_desc->bmAttributes));
                        printf("- Detach Timeout: %d ms\n", le16toh(dfu_desc->wDetachTimeOut));
                        printf("- Max Transfer Size: %d bytes\n", le16toh(dfu_desc->wTransferSize));
                        printf("- DFU Spec Version: %d.%d\n", 
                              (dfu_desc->bcdDFUVersion >> 8) & 0xFF, 
                              dfu_desc->bcdDFUVersion & 0xFF);
                    }

                    // Move to the next descriptor in the extra data buffer
                    extra += desc_len;
                    extra_len -= desc_len;
                }
            }
        }
    }

    // Cleanup resources
    libusb_free_config_descriptor(config);
    libusb_close(dev_handle);
    libusb_exit(ctx);
    return 0;
}

Key Tips for This Example:

  • Swap 0x1234 and 0x5678 with your device’s actual Vendor ID and Product ID.
  • Use le16toh() to convert USB’s little-endian values to your host system’s byte order (critical for cross-platform compatibility).
  • DFU interfaces are identified by bInterfaceClass = 0xFE (Application Specific) and bInterfaceSubClass = 0x01 (DFU).
  • Class-specific descriptors like this one are stored in the interface’s extra data buffer.

内容的提问来源于stack exchange,提问作者Monku

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 09:07:48