USB描述符

  • Post author:
  • Post category:其他




一.设备描述符配置包
typedef struct
{
    uint8_t bmRequestType;
    uint8_t bRequest;
    uint16_t wValue;
    uint16_t wIndex;
    uint16_t wLength;
}USB_SETUP_PACKET;

​ 假设数据包为:

80 06 00 01 00 00 40 00


  1. bmRequestType

    bit 7: data transfer direction 传输方向
           0:HOST-to-device 下传
           1:Device-to-host 上传
    bit 6-5: Type 请求类型
             0:Standard 标准请求
             1:Class 类请求
             2:Vendor 厂商请求
             3:Reserved 保留
    bit 4-0: Recipient 接收对象
             0:Device 设备接收
             1:Interface 接口接收
             2:Endpoint 端点接收
             3:Other 其他
             4-31:Reserved 保留
    

  2. bRequest

    描述符的请求类型

    GET_STATUS				0
    CLEAR_FEATURE			1
    Reserved for future use	2
    SET_FEATURE				3
    Reserved for future use	4
    SET_ADDRESS				5
    GET_DESCRIPTOR			6
    SET_DESCRIPTOR			7
    GET_CONFIGUARTION		8
    SET_CONFIGUARTION		9
    GET_INTERFACE			10
    SET_INTERFACE			11
    SYNCH_FRAME				12
    


    06

    :表示

    GET_DESCRIPTOR

    ,可以得知主机想要获取

    USB

    设备的描述符,但是还不清楚具体是什么类型的描述符。


  3. wValue



    GET_DESCRIPTOR

    这个字节中,低字节表示描述符的索引,高字节表示描述符的类型,高字节的类型如下:

    DEVICE						1
    CONFIGUARTION				2
    STRING						3
    INTERFACE					4
    ENDPOINT					5
    DEVICE_QUALIFIER			6
    OTHER_SPEED_CONFIGURATION	7
    INTERFACE_POWER1 			8
    


    wVlaue:00 01

    :表示从偏移地址

    0

    开始读取描述符,

    01

    表示设备描述符。


  4. wIndex

    是根据不同的请求而设置不同的值,一般用来说明端点号或者说明接口标识,在获取描述符里,设置为

    0

    ,或者是语言

    ID

    ,在这个发送的描述符里,它是设置为

    00 00


  5. wLength

    是根据请求来决定下一阶段发送数据的长度。前面请求第一个字节里,已经说明下一阶段数据传送的方向,这里说明了传送数据的长度,不管是发送数据还是接收数据,都不要超过这个数据长度,在这个获取设备描述符里,它的长度是

    40 00

    ,按小端格式解释,就是

    64

    个字节。



二.回应设备描述符
typedef struct
{
    u8 bLength;             //描述结构体大小
    u8 bDescriptorType;     //描述符类型
    u16 bcdUSB;             //USB版本号
    u8 bDeviceClass;        //设备类代码
    u8 bDeviceSubClass;     //子类代码
    u8 bDeviceProtocol;     //设备协议代码
    u8 bMaxPacketSize0;     //端点0的最大包大小
    u16 idVendor;           //生产厂商编号
    u16 idProduct;          //产品编号
    u16 bcdDevice;          //设备出厂编号
    u8 iManufacturer;       //设备厂商字符串索引
    u8 iProduct;            //产品描述字符串索引
    u8 iSeriaNumber;        //设备序列号字符串索引
    u8 bNumConfigurations;  //当前速度下载能支持的配置数量
}

​ 返回给主控制器的数据结构就是上面的内容,只要把上面的结构体填写合适的内容,就可以发送给主控制器,

12 01 10 01 00 00 00 40 00 80 00 80 00 01 04 2C 4A 01


  1. bLength

    是本结构体的大小,本次返回的结构体长度是

    0X12

    ,也就是

    18

    个字节。


  2. bDescriptorType

    是描述符的类型,它的定义跟主控制器发下来的描述符类型是一样的,如下:

    DEVICE						1
    CONFIGUARTION				2
    STRING						3
    INTERFACE					4
    ENDPOINT					5
    DEVICE_QUALIFIER			6
    OTHER_SPEED_CONFIGURATION	7
    INTERFACE_POWER1 			8
    

    由于返回的是设备描述符,所以就选择了

    0x01

    ,用这个类型来区分不同的描述符。


  3. bcdUSB



    USB

    发布的版本协议,

    USB1.1

    表示为

    0x0110

    .


  4. bDeviceClass

    是设备分类,当它的值是

    0

    时,表示所有接口在配置描述符里,并且所有接口是独立的。当它的值是

    1



    FEH

    时,表示不同的接口关联的。当它的值是

    FFH

    时,它是厂商自己定义的。在这个设备里,它的值为

    0

    .


  5. bDeviceSubClass

    是设备子分类码,当前面的

    bDeviceClass

    值是

    0

    时,这里一定要设置为

    0

    ,其他就根据

    USB-IF

    组织定义的编码。


  6. bDeviceProtocols

    是设备使用的协议,如果使用

    USB-IF

    组织定义的协议,就需要设置这里的值,如果不使用,就直接设置为

    0

    ,如果厂商自己定义的可以设置为

    FFH

    ,以上三个值,在本设备中全部设置为

    0

    .


  7. bMaxPacketSize0

    是端点0收发最大包的大小,仅允许设置8、16、32、64中的任何一个大小。


  8. idVendor

    是厂商标识,由

    USB-IF

    分配的编码,这里使用

    0x8000

    .


  9. idProduct

    是厂商定义的产品标识,可以让操作系统加载不同的驱动程序。


  10. bcdDevice

    是用

    BCD

    表示的设备发布的版本号,这里是

    1.00

    .


  11. iManufacturer

    是厂商字符串的偏移值,这个值主要说明了它在字符串描述符里的偏移位置,如果它设置为0,表示没有厂商字符串,在这里是

    0x04

    .


  12. iProduct

    是产品字符串的偏移值…,在这里是

    0x2C

    .


  13. iSerialNumber

    是序列号字符串的偏移值…,在这里是

    0x4A

    .


  14. bNumConfigurations

    是配置描述符的个数,在这里只使用了一个配置描述符,所以设置为

    1

    .



三.设置USB地址

​ 前面已经解释了主控制器怎样发送设备描述符下来,然后设备返回相应的设备描述符,下一步就是主控制器分配地址给设备,

USB

的设备地址是从

1

开始到

127

,下面就是接收到主控制器发下来的数据包:

00 05 01 00 00 00 00 00

.

​ 由

USB_SETUP_PACKET

定义具体的分析这个数据,就知道应做什么样的响应了。先取得

bmRequestType

的类型,也就是第一个字节,它是

00

,从

USB

协议里查看,它的方向位是主控制器发送给设备,由

bit5和bit6

位可以得知它是

USB

协议里定义的标准请求,由

bit4-0

位知道它是

USB

设备接收这个包数据。



bRequest



05

,为设置地址

SET_ADDRESS

,所以这个包需要按设置地址的格式去解释后面的数据。



wValue

存放

USB

的设备地址,因为它的值是

01 00

,按小端格式解释就是

0x0001

.



USB

的串行引擎通过这个地址来判断是否接收总线上的数据,如果发送的地址跟它一致,就会接收主控制器发过来的数据,当然从这个设备发出去的数据也带有这个地址,因此就可以让主控制器识别不同的

USB

设备数据了。



四.配置描述符

​ 在有了设备地址后,主机会再次发送获取上面已经读取的设备描述符:

80 06 00 01 00 00 12 00

,然后

USB

设备也再次回应它,但这次发送的长度是

0x0012

了,不会是第一次

64

个字节长度了。接着

USB

设备就返回下面的描述符给主控制器,也就是第一次已经发送的设备描述符,如下:

12 01 10 01 00 00 00 40 00 80 00 80 00 01 04 2C 4A 01

,这样分配地址之后,再次获取设备描述符成功了。

​ 接着就是主控制器获取配置描述符,下面就是收到的配置描述符数据:

80 06 00 02 00 00 09 00

,分析以上数据:


  1. bmRequestType:80

    ,表示方向是从

    USB

    设备发送给主机,接收设备是

    USB

    设备。


  2. bRequest:06

    ,表示获取描述符,

    GET_DESCRIPTOR


  3. wValue:00 02

    ,低字节表示偏移地址

    00

    ,高字节表示描述符的类型,

    CONFIGURATION

    ,返回的是配置描述符。


  4. wIndex:00 00


  5. wLength:09 00

    ,表示返回描述符的长度,这里是9个字节

    接下来就是设备返回配置描述符给主控制器,发送的数据如下:

    09 02 22 00 01 01 00 01 32

    ,发送的数据是按下面的结构来定义,这也是在

    USB

    协议里定义的格式:

    typedef struct 
    {
        u8 bLength;             //描述结构体大小
        u8 bDescriptorType;     //描述符类型
        u16 wTotallLength;      //配置描述符集合总长度
        u8 bNumInterfaces;      //配置支持的接口数
        u8 bConfigurationValue; //该配置的值
        u8 iConfiguartion;      //描述该配置的字符串索引值
        u8 bmAttributes;        //供电模式选择
        u8 bMaxPower;           //设备需要的最大电源
    }
    

    1. bLength

      配置的长度,也就是配置结构的整个长度,这里为9字节。

    2. bDescriptorType

      是描述符的类型,这里是配置描述符,所以设置为

      02


    3. wTotallLength

      是所有配置设置的结构长度,包括配置描述符、接口描述符、

      HID

      描述符、端点描述符或者其他描述符。这里是

      22 00

      ,也就是

      0x0022

      个字节。

    4. bNumInterfaces

      是接口个数,这里一个。

    5. bConfigurationValue

      是配置的个数,当设置配置时发送的值,这个设置为

      1

      个配置。

    6. iConfiguration

      是说明配置的字符的偏移,这里是

      0


    7. bMAttributes

      是配置特性,

      D7

      位保留,

      D6

      位是说明是否自供电,

      D5

      位是否支持远程唤醒,

      D4-D0

      是保留。

    8. bMaxPower

      是使用的功率,它采用电流来表示,每

      2mA

      为单位,通过这样的说明,主控制器就知道这个设备是什么样的的设备,有多少功能。


    五.字符串描述符

    ​ 如果在设备描述符那里指定没有字符串描述符的话,在这里是不会收到字符串描述符的,由于我在设备描述符里有字符串描述符的偏移地址,因此,就收到主控制器发出请求字符串描述符,收到的数据如下:

    80 06 00 03 00 00 FF 00


    1. bmRequestType:80

      表示方向是从

      USB

      设备发送给主控制器,接收设备是

      USB

      设备。


    2. bRequest:06

      表示这是获取描述符,

      GET_DESCRIPTOR


    3. wValue:00 03

      ,低字节表示偏移地址

      00

      ,高字节表示描述符的类型

      STRING


    4. wIndex:00 00


    5. wLength:FF 00

      ,它表示返回描述符的长度,这里是

      256

      个字节。

      因此,这个获取字符串描述符,就是从字符串描述符内存里,0偏移地址开始的位置读取第一个字符串描述符返回给主控制器。接着就返回下面的数据给主控制器:

      04 03 09 04

      typedef struct
      {
          u8 bLength;
          u8 bDescriptorType;
          u16 bString;
      }
      

      1. bLength

        是所有数据的长度,这里为4。


      2. bDescriptorType

        是描述类型,这里字符串描述符,所以这是3.


      3. bString

        是可变的字符串数组,不超过254个都应该是可以的,并且它是使用UNICODE编码的字符串,在这里

        09 04

        ,这是美国英语的标识,

        0x0409

        。如果想输入中文的标识,只要改为

        0x0804

        就可以了。

        通过这个字符串描述符,主控制器就知道字符串描述符是使用什么语言说明的了,这样就可以支持全世界的语言标识。

      原文链接:https://www.cnblogs.com/Daniel-G/p/3993883.html



版权声明:本文为wuyanboplus原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。