此刻插上的 USB 设备地址还没有被配置,默认地址是0,使用 0端点 进行交互。

    总线复位 及 向 默认地址0 发送 GET_DESCRIPTOR指令包 ,请求 设备描述。
    首先,获取 设备描述符,要先 复位设备。
    其次,等待至少100ms(100ms可以满足大多数设备),这里实际只等待了43ms。
    如图一所示:

    5.1 获取设备描述符 GET_DESCRIPTOR - 图1


    1)Index[4 - 5]:表示USB插入总线复位
    2)Index[7 - 8]:表示主机向 默认地址0 发送 GET_DESCRIPTOR指令包 ,详细信息也抓出来了,如图所示:

    5.1 获取设备描述符 GET_DESCRIPTOR - 图2


    3)Index[15 - 17]:表示设备向主机发送设备描述数据Index[16]
    4)Index[18 - 19]:表示主机完成GET_DESCRIPTOR指令后,给设备发送一个空应答;

    5.1 获取设备描述符 GET_DESCRIPTOR - 图3


    可以看到:数据是由二进制数字串构成的,首先数字串构成域(有七种:同步域(SYNC)、标识域(PID)、地址域(ADDR)、端点域(ENDP)、数据域(DATA)、帧号域(FRAM)、校验域(CRC)),域再构成包(比如握手包:格式如下 SYNC+PID,ACK属于PID的一种),包再构成事务(IN、OUT、SETUP,每一种事务都由令牌包、数据包、握手包三个阶段构成),事务最后构成传输(中断传输、并行传输、批量传输和控制传输)。
    可以看到, packets 96,是 DATA0 ,红色部分是带的数据,也就是前面说的 USB 请求部分:

    bmRequestType(1) + bRequest(1) + wvalue(2) + wIndex(2) + wLength(2)

    80 06 00 01 00 00 40 00

    bmRequestType=0x80,bRequest=0x06, wvalue=0x0100, wIndex=0x0000, wLength=0x0040;

    根据usb2.0协议9.4.3节描述,获取描述符时bmRequestType=0x80,bRequest=0x06,这个是协议规定固定的。

    wvalue=0x0100,高字节表示描述符类型,01表示设备,02表示配置;低字节表示索引。比如设备有多个配置,那需要读取不同配置的时候就通过低字节。或者一个配置下有多个接口,通过索引选择不同的接口。

    index=0x0000,这个参数如果为0,则不关心;如果为非零,则表示Langurage ID,每一位都有对应的意义。

    length=0x0040,表示请求的数据包长度为64.

    所以本次设置事务的目的明确了,获取设备描述符,长度为64字节。

    输入事务,是usb设备对请求进行回应,传输了16个字节的数据,为什么是传输了16个字节而不是64字节,看看偏移地址7,bMaxPacketSize0=0x10,即该设备的最大包传输大小为16字节,如果超过16字节,需要多次传输。实际设备描述符大小为18,可以看第三步的图,传输完16字节之后,主机再次发送令牌环,设备把剩下的2字节传输完成。这里我们只要获得bMaxPacketSize0 值就可以了,所以接下来直接对其进行了复位操作,否则设备还在等待传输剩余的2个字节呢。(此地,因为并不知道端点 0 的数据能力)

    struct usb_device_descriptor {
    u8 bLength;
    u8 bDescriptorType;
    u16 bcdUSB;
    u8 bDeviceClass;
    u8 bDeviceSubClass;
    u8 bDeviceProtocol;
    u8 bMaxPacketSize0;
    u16 idVendor;
    u16 idProduct;
    u16 bcdDevice;
    u8 iManufacturer;
    u8 iProduct;
    u8 iSerialNumber;
    u8 bNumConfigurations;
    } __attribute__ ((packed));

    输出事务:因为获取描述符之前把设备包大小的初始值设为了64,所以输入事务之后,就认为传输完成,主机发送了一个输出事务,响应设备,已经收到数据。