BY USB 偶现掉线日志分析

A133

Posted by LXG on December 18, 2025

现象

重复启动设备,偶现一次无法识别到USB身份证模块

内核正常日志


[   23.705662] insmod_host_driver
[   23.705662] 
[   23.705666] [ehci0-controller]: sunxi_usb_enable_ehci
[   23.705672] [sunxi-ehci0]: probe, pdev->name: 5101000.ehci0-controller, sunxi_ehci: 0xffffff800960aa58, 0x:ffffff80097c4000, irq_no:166
[   23.752831] sunxi-ehci 5101000.ehci0-controller: SW USB2.0 'Enhanced' Host Controller (EHCI) Driver
[   23.753568] sunxi-ehci 5101000.ehci0-controller: new USB bus registered, assigned bus number 3
[   23.773479] sunxi-ehci 5101000.ehci0-controller: irq 358, io mem 0xffffffc03f711b00
[   23.785720] sunxi-ehci 5101000.ehci0-controller: USB 0.0 started, EHCI 1.00
[   23.785729] sunxi-ehci 5101000.ehci0-controller: ehci_irq: highspeed device connect

[   23.792290] hub 3-0:1.0: USB hub found
[   23.792378] hub 3-0:1.0: 1 port detected

[   23.792818] [ohci0-controller]: sunxi_usb_enable_ohci
[   23.792824] [sunxi-ohci0]: probe, pdev->name: 5101000.ohci0-controller, sunxi_ohci: 0xffffff800960b4f0
[   23.793192] sunxi-ohci 5101000.ohci0-controller: SW USB2.0 'Open' Host Controller (OHCI) Driver
[   23.793729] sunxi-ohci 5101000.ohci0-controller: new USB bus registered, assigned bus number 4
[   23.793802] sunxi-ohci 5101000.ohci0-controller: irq 359, io mem 0xffffffc03f711b00
[   23.854740] hub 4-0:1.0: USB hub found
[   23.854797] hub 4-0:1.0: 1 port detected
[   24.063170] sunxi-ehci 5101000.ehci0-controller: ehci_irq: highspeed device disconnect
[   24.405559] usb 4-1: new full-speed USB device number 2 using sunxi-ohci


内核异常日志


12-16 18:21:25.860270[   19.387334] insmod_host_driver
# 使能 EHCI(USB2.0 高速)控制器
12-16 18:21:25.860458[   19.387347] [ehci0-controller]: sunxi_usb_enable_ehci
12-16 18:21:25.860521[   19.387359] [sunxi-ehci0]: probe, pdev->name: 5101000.ehci0-controller, sunxi_ehci: 0xffffff800960aa58, 0x:ffffff80097c4000, irq_no:166
12-16 18:21:25.860581[   19.389818] sunxi-ehci 5101000.ehci0-controller: SW USB2.0 'Enhanced' Host Controller (EHCI) Driver
12-16 18:21:25.860640[   19.390456] sunxi-ehci 5101000.ehci0-controller: new USB bus registered, assigned bus number 3
12-16 18:21:25.863487[   19.393111] sunxi-ehci 5101000.ehci0-controller: irq 358, io mem 0x00000002
12-16 18:21:25.877041[   19.403975] sunxi-ehci 5101000.ehci0-controller: USB 0.0 started, EHCI 1.00

# 检测到 高速 USB 设备接入(High-Speed)
12-16 18:21:25.877209[   19.403989] sunxi-ehci 5101000.ehci0-controller: ehci_irq: highspeed device connect
12-16 18:21:25.877270[   19.405770] hub 3-0:1.0: USB hub found
12-16 18:21:25.877327[   19.406247] hub 3-0:1.0: 1 port detected

# 使能 OHCI(USB1.1 全速)控制器
12-16 18:21:25.877385[   19.406666] [ohci0-controller]: sunxi_usb_enable_ohci
12-16 18:21:25.877442[   19.406674] [sunxi-ohci0]: probe, pdev->name: 5101000.ohci0-controller, sunxi_ohci: 0xffffff800960b4f0
12-16 18:21:25.877500[   19.407046] sunxi-ohci 5101000.ohci0-controller: SW USB2.0 'Open' Host Controller (OHCI) Driver
12-16 18:21:25.880137[   19.408699] sunxi-ohci 5101000.ohci0-controller: new USB bus registered, assigned bus number 4
12-16 18:21:25.880316[   19.408791] sunxi-ohci 5101000.ohci0-controller: irq 359, io mem 0xffffffc03e0f8000
12-16 18:21:25.940616[   19.469431] hub 4-0:1.0: USB hub found
12-16 18:21:25.940780[   19.469469] hub 4-0:1.0: 1 port detected

# 关键异常:高速枚举失败 → 设备掉线
12-16 18:21:26.136911[   19.667395] sunxi-ehci 5101000.ehci0-controller: ehci_irq: highspeed device disconnect

# 设备 以 Full-Speed(USB1.1)重新接入
# Host 在做兼容性回退
12-16 18:21:26.460186[   19.987402] usb 4-1: new full-speed USB device number 2 using sunxi-ohci

# 致命错误:USB 描述符非法(根因)
12-16 18:21:26.616832[   20.145752] usb 4-1: config index 0 descriptor too short (expected 32, got 9)
12-16 18:21:26.617015[   20.145767] usb 4-1: config 1 has 0 interfaces, different from the descriptor's value: 1

日志分析

  1. USB Host(EHCI / OHCI)初始化完全正常
  2. USB 设备尝试以 High-Speed 枚举,但迅速断开
  3. Host 回退到 Full-Speed 重新枚举
  4. 设备返回了非法的 Configuration Descriptor(长度不足、接口数量不一致)
  5. 枚举失败,后续 Android Framework 解析 Descriptor 时必然异常

sunxi_usb_enable_ohci降级到了sunxi-ohci

原因 说明
PHY 初始化失败 高速 PHY 可能没上电或复位失败
电流不足 EHCI 端口无法稳定供电,高速设备无法枚举
硬件兼容性 某些 USB 设备在 EHCI 下握手失败
内核驱动 fallback 机制 EHCI 初始化失败 → USB core 尝试 OHCI,保证低速设备能用

sunxi_ehci 对比 sunxi_ohci

维度 sunxi_ehci sunxi_ohci
USB 规范 USB 2.0 USB 1.1
速率 High-Speed 480 Mbps Full-Speed 12 Mbps / Low-Speed 1.5 Mbps
控制器角色 优先尝试者 失败回退兜底
是否必须存在 可选(失败可退出) 必须存在
对时序/信号要求 非常苛刻 非常宽松
对设备描述符要求 严格 相对宽松
常见问题暴露 HS chirp / HS 描述符 很少
在 A133 上 和 OHCI 共享同一 PHY 和 EHCI 共享同一 PHY

A133 USB 口分配


         ┌─────────────┐
         │ 物理 USB 口0 │  <─ EHCI0 / OHCI0 共用
         └─────┬───────┘
               │
         ┌─────┴───────┐
         │ Root Hub 1  │  (EHCI0/OHCI0)
         │ 1 port       │
         └─────┬───────┘
               │
      ┌────────┴────────┐
      │ USB 设备 (高速尝试失败, fallback 全速) │
      └─────────────────┘

         ┌─────────────┐
         │ 物理 USB 口1 │  <─ EHCI1 / OHCI1 共用
         └─────┬───────┘
               │
         ┌─────┴───────┐
         │ Root Hub 2  │  (EHCI1/OHCI1)
         │ 1 port       │
         └─────┬───────┘
               │
      ┌────────┴────────┐
      │ 其他 USB 设备    │
      └─────────────────┘

注解:
- EHCIx = 高速 USB 2.0 控制器
- OHCIx = 全速/低速 USB 1.1 控制器
- 同一个物理口的 EHCI 和 OHCI 共用 PHY
- 高速设备如果枚举失败,会 fallback 到 OHCI(full-speed)
- OTG 功能可复用 EHCI0/OHCI0,但当前为 Host 模式

android 日志


12-16 18:21:26.621237  2027  2226 I UsbDescriptorParser: Unknown Descriptor len: 0 type:0x0
12-16 18:21:26.624328  2027  2226 E UsbDescriptorParser: Exception allocating USB descriptor.
12-16 18:21:26.624328  2027  2226 E UsbDescriptorParser: java.lang.IllegalArgumentException
12-16 18:21:26.624328  2027  2226 E UsbDescriptorParser: 	at com.android.server.usb.descriptors.UsbDescriptor.<init>(UsbDescriptor.java:140)
12-16 18:21:26.624328  2027  2226 E UsbDescriptorParser: 	at com.android.server.usb.descriptors.UsbUnknown.<init>(UsbUnknown.java:26)
12-16 18:21:26.624328  2027  2226 E UsbDescriptorParser: 	at com.android.server.usb.descriptors.UsbDescriptorParser.allocDescriptor(UsbDescriptorParser.java:201)
12-16 18:21:26.624328  2027  2226 E UsbDescriptorParser: 	at com.android.server.usb.descriptors.UsbDescriptorParser.parseDescriptors(UsbDescriptorParser.java:227)
12-16 18:21:26.624328  2027  2226 E UsbDescriptorParser: 	at com.android.server.usb.descriptors.UsbDescriptorParser.<init>(UsbDescriptorParser.java:64)
12-16 18:21:26.624328  2027  2226 E UsbDescriptorParser: 	at com.android.server.usb.UsbHostManager.usbDeviceAdded(UsbHostManager.java:372)
12-16 18:21:26.624328  2027  2226 E UsbDescriptorParser: 	at com.android.server.usb.UsbHostManager.monitorUsbHostBus(Native Method)
12-16 18:21:26.624328  2027  2226 E UsbDescriptorParser: 	at com.android.server.usb.UsbHostManager.lambda$XT3F5aQci4H6VWSBYBQQNSzpnvs(Unknown Source:0)
12-16 18:21:26.624328  2027  2226 E UsbDescriptorParser: 	at com.android.server.usb.-$$Lambda$UsbHostMa

日志分析

Android 在解析 USB 设备上报的 Descriptor 时,收到了一个“非法的 USB 描述符(bLength=0)”,直接违反 USB 规范,因此 framework 直接抛异常

AI 分析


【硬件】
USB 设备上电 / 复位
    ↓
【Kernel】
USB Host Controller 枚举设备
  ├─ 发 GET_DESCRIPTOR
  ├─ 收到 descriptor 数据(⚠️ 这里已可能异常)
  ├─ 生成 usb_device / uevent
    ↓
【Framework】
UsbHostManager 收到 uevent
  └─ UsbDescriptorParser 解析 descriptor
      └─ 抛出 IllegalArgumentException

分析结论

  • ❌ 不是 Framework bug
  • ❌ 不是 App bug
  • ⚠️ Framework 只是“放大器” ✅ 问题根因 100% 在:
    • USB 设备端上电 / 复位时序
    • USB HUB / PHY
    • Host Controller 在设备未 ready 时读取 descriptor

核心问题实际上是 EHCI 控制器无法正确初始化高速设备,所以内核 fallback 到 OHCI。OHCI 的低速/全速端口在枚举高速设备时往往会出现 descriptor 不完整、字段异常等情况,才导致 Framework 抛异常

可能触发降级的原因

(1) PHY/硬件原因

  • PHY 初始化失败或时序不稳定
  • 电源不足或波动(尤其是板载 HUB 或长线)
  • USB 上电/复位顺序不对
  • 设备未完全 ready,EHCI 就发送 GET_DESCRIPTOR
  • 触发高速枚举失败

(2) 内核/驱动限制

  • EHCI 驱动超时(默认 50~100ms)
  • 设备 descriptor 超出 EHCI 支持范围或返回异常

(3) 设备端问题

  • 高速设备在刚上电时响应慢
  • Descriptor 不符合 USB 2.0 标准

报错源码

A133_android_10/longan/kernel/linux-4.9/drivers/usb/core/config.c


/*
 * Get the USB config descriptors, cache and parse'em
 *
 * hub-only!! ... and only in reset path, or usb_new_device()
 * (used by real hubs and virtual root hubs)
 */
int usb_get_configuration(struct usb_device *dev)
{
	struct device *ddev = &dev->dev;    // 指向该 USB 设备的 device 结构
	int ncfg = dev->descriptor.bNumConfigurations; // 设备声明的配置数量
	int result = 0;
	unsigned int cfgno, length;
	unsigned char *bigbuffer;
	struct usb_config_descriptor *desc;

	cfgno = 0;
	result = -ENOMEM;

	// 如果设备声明的配置数量超过内核允许的最大值,则截断
	if (ncfg > USB_MAXCONFIG) {
		dev_warn(ddev, "too many configurations: %d, "
		    "using maximum allowed: %d\n", ncfg, USB_MAXCONFIG);
		dev->descriptor.bNumConfigurations = ncfg = USB_MAXCONFIG;
	}

	// 如果没有配置,直接报错返回
	if (ncfg < 1) {
		dev_err(ddev, "no configurations\n");
		return -EINVAL;
	}

	// 为每个配置分配内核缓存结构 usb_host_config
	length = ncfg * sizeof(struct usb_host_config);
	dev->config = kzalloc(length, GFP_KERNEL);
	if (!dev->config)
		goto err2;

	// 为每个配置分配 raw descriptor 指针数组
	length = ncfg * sizeof(char *);
	dev->rawdescriptors = kzalloc(length, GFP_KERNEL);
	if (!dev->rawdescriptors)
		goto err2;

	// 临时缓冲区,用于读取配置描述符的起始部分
	desc = kmalloc(USB_DT_CONFIG_SIZE, GFP_KERNEL); // USB_DT_CONFIG_SIZE = 9
	if (!desc)
		goto err2;

	result = 0;
	for (; cfgno < ncfg; cfgno++) {
		/* 
		 * 先读取配置描述符前 9 字节,以获取 wTotalLength,
		 * 用于知道整个配置描述符的长度
		 */
		result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno,
		    desc, USB_DT_CONFIG_SIZE);
		if (result < 0) {
			dev_err(ddev, "unable to read config index %d "
			    "descriptor/%s: %d\n", cfgno, "start", result);
			if (result != -EPIPE)
				goto err;
			// 如果管道错误,说明设备不能读取该配置
			dev_err(ddev, "chopping to %d config(s)\n", cfgno);
			dev->descriptor.bNumConfigurations = cfgno;
			break;
		} else if (result < 4) {
			// descriptor 太短,至少要 4 字节(USB规范要求)
			dev_err(ddev, "config index %d descriptor too short "
			    "(expected %i, got %i)\n", cfgno,
			    USB_DT_CONFIG_SIZE, result);
			result = -EINVAL;
			goto err;
		}

		// wTotalLength 指出整个配置描述符的总长度
		length = max((int) le16_to_cpu(desc->wTotalLength),
		    USB_DT_CONFIG_SIZE);

		/* 
		 * 根据 wTotalLength 分配 bigbuffer,读取整个配置描述符
		 */
		bigbuffer = kmalloc(length, GFP_KERNEL);
		if (!bigbuffer) {
			result = -ENOMEM;
			goto err;
		}

		// 某些设备需要延时初始化
		if (dev->quirks & USB_QUIRK_DELAY_INIT)
			msleep(200);

		// 读取整个配置描述符,包括接口和端点
		result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno,
		    bigbuffer, length);
		if (result < 0) {
			dev_err(ddev, "unable to read config index %d "
			    "descriptor/%s\n", cfgno, "all");
			kfree(bigbuffer);
			goto err;
		}
		if (result < length) {
			// 如果读取长度小于 wTotalLength,打印警告
			dev_warn(ddev, "config index %d descriptor too short "
			    "(expected %i, got %i)\n", cfgno, length, result);
			length = result;
		}

		// 保存 raw descriptor,供后续解析使用
		dev->rawdescriptors[cfgno] = bigbuffer;

		// 解析配置描述符到内核结构
		result = usb_parse_configuration(dev, cfgno,
		    &dev->config[cfgno], bigbuffer, length);
		if (result < 0) {
			++cfgno;
			goto err;
		}
	}
	result = 0;

err:
	// 释放临时缓冲区
	kfree(desc);
	// 更新设备配置数量
	dev->descriptor.bNumConfigurations = cfgno;
err2:
	if (result == -ENOMEM)
		dev_err(ddev, "out of memory\n");
	return result;
}

这段代码是 Linux 内核 usb_get_configuration() 函数的实现(hub-only 情况下),它就是负责读取 USB 设备的 配置描述符 并解析成内核可用结构

可能的原因

设备端固件缺陷

  • 配置描述符只返回了起始 9 字节,wTotalLength 指向的长度不对或者设备没有提供完整接口描述符。
  • bNumInterfaces = 1,但实际读取到的接口描述符 = 0。

USB 通信异常

  • 数据传输被截断(线材、USB hub、信号干扰),导致内核拿不到完整描述符。

内核/quirks 不匹配

  • 某些自研 USB 设备需要 USB_QUIRK_* 才能兼容(例如强制延时、修正 wTotalLength 等)。
  • 你的代码里有:

if (dev->quirks & USB_QUIRK_DELAY_INIT)
    msleep(200);

如果设备需要特殊延时或 workaround,但没有设置 quirks,也可能返回不全。

修改方案


/*
 * Get the USB config descriptors, cache and parse'em
 *
 * hub-only!! ... and only in reset path, or usb_new_device()
 * (used by real hubs and virtual root hubs)
 */
int usb_get_configuration(struct usb_device *dev)
{
	struct device *ddev = &dev->dev;
	int ncfg = dev->descriptor.bNumConfigurations;
	int result = 0;
	unsigned int cfgno, length;
	unsigned char *bigbuffer;
	struct usb_config_descriptor *desc;

	//lixiaogang add start
	int retry;
	//lixiaogang add end

	cfgno = 0;
	result = -ENOMEM;
	if (ncfg > USB_MAXCONFIG) {
		dev_warn(ddev, "too many configurations: %d, "
		    "using maximum allowed: %d\n", ncfg, USB_MAXCONFIG);
		dev->descriptor.bNumConfigurations = ncfg = USB_MAXCONFIG;
	}

	if (ncfg < 1) {
		dev_err(ddev, "no configurations\n");
		return -EINVAL;
	}

	length = ncfg * sizeof(struct usb_host_config);
	dev->config = kzalloc(length, GFP_KERNEL);
	if (!dev->config)
		goto err2;

	length = ncfg * sizeof(char *);
	dev->rawdescriptors = kzalloc(length, GFP_KERNEL);
	if (!dev->rawdescriptors)
		goto err2;

	desc = kmalloc(USB_DT_CONFIG_SIZE, GFP_KERNEL);
	if (!desc)
		goto err2;

	result = 0;
	for (; cfgno < ncfg; cfgno++) {
		/* We grab just the first descriptor so we know how long
		 * the whole configuration is */
		result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno,
		    desc, USB_DT_CONFIG_SIZE);
		if (result < 0) {
			dev_err(ddev, "unable to read config index %d "
			    "descriptor/%s: %d\n", cfgno, "start", result);
			if (result != -EPIPE)
				goto err;
			dev_err(ddev, "chopping to %d config(s)\n", cfgno);
			dev->descriptor.bNumConfigurations = cfgno;
			break;
		} else if (result < 4) {
			dev_err(ddev, "config index %d descriptor too short "
			    "(expected %i, got %i)\n", cfgno,
			    USB_DT_CONFIG_SIZE, result);
			result = -EINVAL;
			goto err;
		}
		length = max((int) le16_to_cpu(desc->wTotalLength),
		    USB_DT_CONFIG_SIZE);

		/* Now that we know the length, get the whole thing */
		bigbuffer = kmalloc(length, GFP_KERNEL);
		if (!bigbuffer) {
			result = -ENOMEM;
			goto err;
		}

		if (dev->quirks & USB_QUIRK_DELAY_INIT)
			msleep(200);

		//modify by lixiaogang start
		//result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno,
		//    bigbuffer, length);
		/* 只在读取完整配置 descriptor 时增加重试 */
		for (retry = 0; retry < 5; retry++) {
		    result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, bigbuffer, length);
		    if (result >= length)
		        break; // 成功读取完整 descriptor
		    dev_warn(ddev, "full config index %d descriptor too short (attempt %d, got %d bytes)\n",
		             cfgno, retry+1, result);
		    msleep(50); // 偶发问题加小延时
		}
		//modify by lixiaogang end

		if (result < 0) {
			dev_err(ddev, "unable to read config index %d "
			    "descriptor/%s\n", cfgno, "all");
			kfree(bigbuffer);
			goto err;
		}
		if (result < length) {
			dev_warn(ddev, "config index %d descriptor too short "
			    "(expected %i, got %i)\n", cfgno, length, result);
			length = result;
		}

		// lixiaogang add start
		dev_info(&dev->dev, "cfg%d raw descriptor (%d bytes):", cfgno, length);
		int i;
		for (i = 0; i < length; i++) {
		    dev_info(&dev->dev, " %02x", bigbuffer[i]);
		}
		dev_info(&dev->dev, "\n");
		// lixiaogang add end

		dev->rawdescriptors[cfgno] = bigbuffer;

		result = usb_parse_configuration(dev, cfgno,
		    &dev->config[cfgno], bigbuffer, length);
		if (result < 0) {
			++cfgno;
			goto err;
		}
	}
	result = 0;

err:
	kfree(desc);
	dev->descriptor.bNumConfigurations = cfgno;
err2:
	if (result == -ENOMEM)
		dev_err(ddev, "out of memory\n");
	return result;
}

修改后的打印日志如下


[   24.261716] hub 4-0:1.0: USB hub found
[   24.261763] hub 4-0:1.0: 1 port detected
[   24.463807] sunxi-ehci 5101000.ehci0-controller: ehci_irq: highspeed device disconnect
[   24.825425] usb 4-1: new full-speed USB device number 2 using sunxi-ohci
[   24.994858] usb 4-1: full config index 0 descriptor too short (attempt 1, got 9 bytes)
[   25.050783] usb 4-1: cfg0 raw descriptor (32 bytes):
[   25.050790] usb 4-1:  09
[   25.050793] usb 4-1:  02
[   25.050796] usb 4-1:  20
[   25.050799] usb 4-1:  00
[   25.050802] usb 4-1:  01
[   25.050805] usb 4-1:  01
[   25.050808] usb 4-1:  00
[   25.050810] usb 4-1:  40
[   25.050813] usb 4-1:  32
[   25.050816] usb 4-1:  09
[   25.050819] usb 4-1:  04
[   25.050822] usb 4-1:  00
[   25.050824] usb 4-1:  00
[   25.050827] usb 4-1:  02
[   25.050830] usb 4-1:  00
[   25.050833] usb 4-1:  00
[   25.050836] usb 4-1:  00
[   25.050839] usb 4-1:  00
[   25.050842] usb 4-1:  07
[   25.050845] usb 4-1:  05
[   25.050848] usb 4-1:  81
[   25.050850] usb 4-1:  02
[   25.050853] usb 4-1:  40
[   25.050856] usb 4-1:  00
[   25.050859] usb 4-1:  0a
[   25.050862] usb 4-1:  07
[   25.050865] usb 4-1:  05
[   25.050867] usb 4-1:  01
[   25.050870] usb 4-1:  02
[   25.050873] usb 4-1:  40
[   25.050876] usb 4-1:  00
[   25.050879] usb 4-1:  0a
[   25.050882] usb 4-1: 

完整描述符


usb 4-1: cfg0 raw descriptor (32 bytes):
usb 4-1:  09 02 20 00 01 01 00 40 32 09 04 00 00 02 00 00 00 00 07 05 81 02 40 00 0a 07 05 01 02 40 00 0a


配置描述符 (Configuration Descriptor)

字节位置 字段 说明
0 09 bLength 描述符长度 = 9 字节
1 02 bDescriptorType 描述符类型 = CONFIGURATION (0x02)
2-3 20 00 wTotalLength 总长度 = 0x0020 = 32 字节(包括配置 + 接口 + 端点)
4 01 bNumInterfaces 接口数量 = 1
5 01 bConfigurationValue 配置值 = 1
6 00 iConfiguration 配置描述符字符串索引 = 0(无字符串)
7 40 bmAttributes 属性 = 0x40 → 自供电 (0x40)
8 32 bMaxPower 最大功率 = 0x32 × 2 mA = 100 mA

接口描述符 (Interface Descriptor)

字节位置 字段 说明
9 09 bLength 描述符长度 = 9
10 04 bDescriptorType INTERFACE (0x04)
11 00 bInterfaceNumber 接口号 = 0
12 00 bAlternateSetting 备用设置 = 0
13 02 bNumEndpoints 端点数量 = 2
14 00 bInterfaceClass 类 = 0 (未指定)
15 00 bInterfaceSubClass 子类 = 0
16 00 bInterfaceProtocol 协议 = 0
17 00 iInterface 接口字符串索引 = 0

第一个端点描述符 (Endpoint Descriptor)

字节位置 字段 说明
18 07 bLength 描述符长度 = 7
19 05 bDescriptorType ENDPOINT (0x05)
20 81 bEndpointAddress 0x81 → IN 端点 1
21 02 bmAttributes 传输类型 = BULK (0x02)
22-23 40 00 wMaxPacketSize 最大包大小 = 0x0040 = 64 bytes
24 0a bInterval 轮询间隔 = 10 ms(对 BULK 端点一般无意义)

第二个端点描述符 (Endpoint Descriptor)

字节位置 字段 说明
25 07 bLength 描述符长度 = 7
26 05 bDescriptorType ENDPOINT (0x05)
27 01 bEndpointAddress 0x01 → OUT 端点 1
28 02 bmAttributes BULK 端点
29-30 40 00 wMaxPacketSize 64 bytes
31 0a bInterval 10 ms

这个 USB 设备的配置描述符翻译如下:

  • 配置:1 个接口,自供电,最大功率 100 mA
  • 接口 0:2 个端点,类和协议未指定
  • 端点 1 IN:BULK, 64 bytes
  • 端点 1 OUT:BULK, 64 bytes

这是一种典型的 USB BULK 设备(比如 USB 串口、USB CDC 设备)配置。