USB枚举流程

USB连接过程

UACId1.png

这个过程包括Attached、Powered、Reset(进入Default状态)、Set Address(进入Address状态)。然后会进入config阶段,如下:

Config过程

请求device描述符

UACId2.png
  • bmRequestType:0x80表示从设备到主机,请求标准命令,接收者为设备
  • bRequest:0x06表示读取描述符
  • wValue: 表示要获取描述符的索类型。(高字节为描述符类型,低字节为描述符索引)
1
2
3
4
5
6
描述符的类型有:
1——设备描述符
2——配置描述符
3——字符串描述符
4——接口描述符 //随配置描述符一并获取
5——端点描述符 //随配置描述符一并获取

这里0x0100,表示设备描述符,索引为0

  • wIndex:字段表示字符串描述符的语言ID, 其它描述符为0
  • wLength:指定了描述符的字节数,这里为0x12(18)字节

device的设备描述符

UACId3.png
  • bLength:设备描述符的字节数大小,这里长度为0x12(18)字节
  • bDescriptorType:描述符类型编号,0x01代表设备描述符
  • bdcUSB:USB版本号,0x200表示USB version 2.0
  • bDeviceClass:USB分配的设备类代码,0x01~0xfe为标准设备类,0xff为厂商自定义类型,0x00不是在设备描述符中定义的,如HID
  • bDeviceSubClass:usb分配的子类代码,同上,值由USB规定和分配的,这里是0x00
  • bDeviceProtocol:USB分配的设备协议代码,同上
  • bMaxPacketSize0:端点0的最大包的大小,这里是0x40(64 bytes)
  • idVendor:0x18d1,我们在configfs中配置的
  • idProduct:0x4e26,我们在configfs中配置的
  • bcdDevice:设备出厂编号 这里是0x0606
  • iManufacturer:描述厂商字符串的索引,这里是1(字符串为amlogic)
  • iProduct:描述产品字符串的索引(p2101)
  • iSerialNumber:描述设备序列号字符串的索引 (ap2228096a10802321724)
  • bNumConfiguration:可能的配置数量 (1)
UACId4.png

请求config描述符 UACId5.png

与请求设备描述符差别在于wValue,bDescriptorType=0x02表示配置描述符

获得的配置描述符

配置描述符在USB设备的枚举过程中,需要获取两次:第一次只获取配置描述符的基本长度9字节,获取后从wTotalLength字节中解析出配置描述符的总长度,然后再次获取全部的描述符。如下图所示,第一次获取描述符基本数据得到的respond是配置描述符有301字节,需要再获取一次301字节的请求,第二次数据量太大包含配置描述符的拓扑结构这里不列出来,只把第一次请求返回的结果列出来,如下图所示。 UACId6.png

UACId8.png 抓包数据和windows显示的描述符两者是一致的。

获取其他描述符

之后就是相同的流程继续获取各string描述符。

对于UAC的FU,会有获取CUR、MIN、MAX、RANGE、RES等流程以及设置CUR的流程。

其中获取CUR、MIN、MAX、RANGE、RES等是通过USB设备请求format获取的,其相关字段解释如下:

Format of Setup Data UACId7.png

UACId9.png

问题现象

  • 前提:我们的公版和客户的板子usb驱动和uac驱动完全一致
  • 我们的公版UAC1+ADB+Feature Unit接PC和手机都可以识别
  • 客户板子UAC1+ADB+Feature Unit设备接手机时UAC设备不识别,接PC的时候能够被识别
  • 客户板子UAC1+Feature Unit接手机可以被识别
  • 客户板子UAC1+Feature Unit(disabled int ep)+ADB接手机可以被识别

问题分析

通过以上现象发现UAC1不识别跟端点相关,但是统计发现端点数量是够用的,可以支持同时开启UAC1+Feature Unit+ADB。可以对比同时开启UAC1+Feature Unit+ADB公版和客户版的usb包。 UACId10.png

端点号统计

只有低4bit位代表端点号 harman Board.(UAC先申请的EP)

  • uac 端点号:
  • FU:129->1
  • OUT: 1
  • IN: 130->2
  • FFS 端点号:
  • 2
  • 131->3

手机下发的endpoint=130->2 匹配到FFS端点2上了

公版 Board:(FFS先申请的ep)

  • uac 端点号:
  • FU:130->2
  • OUT: 2
  • IN: 131->3
  • FFS 端点号:
  • 1
  • 129->1

手机下发131->3,对应UAC IN端口 UACId11.png

这是wIndex各bit组成,通过测试发现,客户的板子先初始化了UAC后初始化了ADB,我们公版先初始化了ADB后初始化了UAC 由于FFS驱动在匹配端点号的时候只匹配了低4bit,也就是只匹配了ep num,而忽略了dir,导致FFS匹配错端点号了,手机下发的wIndex是130实际对应的是UAC的IN端点,但是FFS驱动在匹配端点的函数中(ffs_func_req_match)忽略了dir bit,导致手机下发的UAC IN端点号130取低4bit=2跟FFS的端点2重复了。本来该UAC处理的请求被FFS驱动匹配端点号后由FFS驱动处理了。导致后续很多异常包。

UACId12.png

解决办法

  • 可以修改启动脚本,先初始化ADB后初始化UAC来绕过这个问题
  • 修改FFS端点匹配机制,除了低4bit的ep num需要匹配外,dir也要匹配
  • 修改EP num编号,IN和OUT使用不同的endpoint number,例如IN使用奇数,OUT使用偶数