4. 控制传输调试:Setup包结构解析、控制传输阶段波形分析、标准请求与厂商请求调试案例

控制传输,说白了就是USB通信的“指挥通道”。

设备枚举、配置、状态查询,全得靠它。我见过不少工程师,一上来就盯着BULK传输调,结果设备连枚举都过不去,折腾半天才发现是控制传输没处理好。

这一章,咱们就把控制传输的底裤扒干净。

4.1 Setup包结构:控制传输的“指令信封”

控制传输的第一步,是Host发一个Setup包。这个包固定8字节,结构如下:

偏移 字段 长度(字节) 说明
0 bmRequestType 1 传输方向、请求类型、接收对象
1 bRequest 1 请求编号(标准/厂商/类)
2-3 wValue 2 请求参数(小端序)
4-5 wIndex 2 索引/接口/端点号
6-7 wLength 2 Data阶段传输的字节数

这里有个坑,我一开始也踩过——wValue和wIndex是小端序。你用逻辑分析仪抓包,看到的是0x1200,实际值是0x0012。别搞反了。

bmRequestType 位域解析(我习惯这么记):

  • Bit 7:方向。0=Host→Device,1=Device→Host
  • Bit 6-5:类型。00=标准,01=类,10=厂商,11=保留
  • Bit 4-0:接收者。00000=设备,00001=接口,00010=端点,00011=其他

举个例子:0x80 = 1000 0000,方向是Device→Host,标准请求,接收者是设备。这就是Get Descriptor的Setup包。

4.2 控制传输三阶段:Setup / Data / Status

控制传输不是一把梭,它分三个阶段。我画了张图,帮你理清流程:

控制传输三阶段流程图 Setup 阶段 Host发送8字节Setup包 Data 阶段 可选,传输数据 Status 阶段 握手确认 关键说明: • Setup阶段:Host发送8字节请求包,Device必须接收并解析 • Data阶段:可选。方向由bmRequestType的Bit7决定 • Status阶段:Device返回握手包,确认传输完成 • 如果Data阶段长度为0,则直接跳过,从Setup进入Status

我调试时最常用的方法:先看Status阶段有没有返回ACK。如果Device回了STALL,说明它不认识这个请求。这时候别急着改驱动,先查Setup包内容对不对。

4.3 波形分析:用逻辑分析仪抓控制传输

纸上谈兵没意思,咱们直接看波形。我用的是Saleae逻辑分析仪,配合USB解码插件。

抓一个标准的Get Descriptor请求,波形长这样:

Token: SETUP (ADDR=1, ENDP=0)
Data:  80 06 00 01 00 00 12 00  (8字节Setup包)
Handshake: ACK

Token: IN (ADDR=1, ENDP=0)
Data:  12 01 10 01 00 00 00 08  ... (设备描述符前8字节)
Handshake: ACK

Token: IN (ADDR=1, ENDP=0)
Data:  ... (剩余描述符数据)
Handshake: ACK

Token: OUT (ADDR=1, ENDP=0)
Data:  0长度包
Handshake: ACK

我的调试习惯:

抓包时,重点关注三个地方:

  1. Setup包的8字节是否完整——少一个字节,Device直接STALL
  2. Data阶段的wLength是否匹配——Host要12字节,Device只回了8字节,会出问题
  3. Status阶段有没有ACK——没ACK说明Device没收到或者没处理完

有一次,我调一个U盘驱动,发现枚举到一半就卡死了。抓包一看,Setup包发出去,Device回了STALL。查了半天,原来是wValue的高低位写反了。你说冤不冤?

4.4 标准请求 vs 厂商请求:调试案例

标准请求是USB规范定死的,比如Get Descriptor、Set Address、Set Configuration。这些请求,所有USB设备都必须支持。

厂商请求就不一样了。芯片厂商可以自定义,比如读固件版本、写寄存器、启动OTA升级。

请求类型 bRequest范围 典型用途 调试要点
标准请求 0x00 - 0x0F 枚举、配置、状态查询 必须符合USB 2.0规范
类请求 0x10 - 0x1F HID报告、Mass Storage命令 参考类规范文档
厂商请求 0x20 - 0xFF 私有功能、调试、升级 需要芯片手册

我分享一个真实案例。之前调一个摄像头驱动,厂商提供了一个私有请求,用来设置图像参数。Host发出去,Device没反应。

抓包发现:

  • Setup包:bmRequestType = 0x40 (Host→Device,厂商请求,设备)
  • bRequest = 0xA0 (厂商自定义)
  • wValue = 0x0100 (参数索引)
  • wIndex = 0x0000
  • wLength = 0x0000 (无Data阶段)

看起来没问题。但Device就是不回ACK。我查了芯片手册,发现这个请求需要Data阶段,wLength应该设为4字节。厂商文档写得不清楚,坑了我半天。

避坑指南:

我曾经因为厂商请求的wLength设错,浪费了一整天。调试厂商请求时,务必确认:

  • bmRequestType的方向位是否正确(Host→Device还是Device→Host)
  • wLength是否匹配实际传输的数据长度
  • Device端是否在正确的端点处理了该请求

4.5 实战:用USB分析仪定位控制传输故障

最后,我分享一个通用的调试流程。遇到控制传输问题,按这个步骤来:

  1. 抓原始波形:用逻辑分析仪或USB分析仪抓取USB总线上的D+和D-信号
  2. 解析Setup包:确认8字节内容是否正确,特别是bmRequestType和wLength
  3. 检查Data阶段:如果有Data阶段,确认数据内容和长度是否匹配
  4. 看Status阶段:Device返回的是ACK还是STALL?STALL说明Device拒绝了这个请求
  5. 对比规范:如果是标准请求,对照USB 2.0规范检查;如果是厂商请求,对照芯片手册

嗯,这套流程我用了快十年,基本没失手过。控制传输调通了,后面的BULK和ISO传输才能跑起来。别急,一步一步来。