zoukankan      html  css  js  c++  java
  • USB描述符解析-->枚举.

     枚举可以理解为主机按不定的顺序向USB设备讨要设备信息,好给它分配资源,若枚举不成功,就放弃分配资源,免得浪费资源。一般都是使用中断传输方式通信。

        常用的描述符有以下几种:01H、设备描述符  02H、配置描述符  03H、字符串描述符  04H、接口描述符  05H、端点描述符

    21H:HID描述符 22H:HID报告

        一个设备只能有一个设备描述符,而一个设备描述符可以包含多个配置描述符(bNumConfigurations  ),一个配置描述符又可以包含多个接口描述符,一个接口使用了几个端点,就有几个端点描述符。

    以下为HID描述:(一个USB设备同时包含键盘和鼠标,使用2个接口)

    一、设备描述符:Device descriptor

    hid_device_descriptor =
    {

       0x12 ,                       // bLength   该段描述符总长18个,不可变
       0x01,                        // bDescriptorType:常用的如下0x01:设备  0x02配置 0x03字符 0x04接口 0x05端点 0x21HID
       0x0200,                    // bcdUSB  USB版本号: 1.1--0x0110   2.0--0x0200  3.0--0x0300
       0x00,                        // bDeviceClass  HID 不使用接口联合描述字与下面一起设置为00H
       0x00,                        // bDeviceSubClass
       0x00,                        // bDeviceProtocol
       8,                              // bMaxPacketSize0 端点0最大包的大小  USB2.0:低速--8  全速:8、16、32、64  高速:64
       0x1223,                    // idVendor     VID
       0x3F07,                    // idProduct     PID
       0x1110,                     // bcdDevice   厂商指定的设备版本号
       0x01,                         // iManufacturer  指向描述制造商字符串的索引
       0x02,                         // iProduct           指向描述产品的字符串索引
       0x00,                         // iSerialNumber  指向设备序列号的字符串索引
       0x01                          // bNumConfigurations  定义配置描述符的数量
    };

    二、配置描述符

    hid_configuration_descriptor =

    {
       0x09,                         // bLength  长度9个,不可变
       0x02,                         // bDescriptorType 配置描述符
       0x3b00,                     // wTotallength= 9+(9+9+7)+(9+9+7)  配置描述符+(接口描述符+HID描述符+端点描述符)*接口数

                         配置描述符信息总的大小,包括接口描述符、端点描述符等等
       0x02,                         // bNumInterfaces   接口数量=2(键盘+鼠标)
       0x01,                         // bConfigurationValue  Set_Configuration命令需要的参数值
       0x00,                         // iConfiguration 配置字符串索引
       0xa0,                         // bmAttributes bit7=1 bit6:1--自供电 0--总线供电 bit5:1--远程唤起 0--不支持 bit[4:0]=0

       0x32                          // MaxPower (in 2mA units) 50*2mA=100mA
    };

    三、接口配置符

    keyboard_interface_descriptor =
    {  
       0x09,                               // bLength                长度9个,不可变
       0x04,                               // bDescriptorType   接口描述符
       0x00,                               // bInterfaceNumber  接口0  (接口从0开始,键盘定义0,鼠标定义1)
       0x00,                               // bAlternateSetting   接口索引值
       0x01,                               // bNumEndpoints     端点个数1(端点0不可用,比如EP1)
       0x03,                               // bInterfaceClass     (3 = HID)
       0x01,                               // bInterfaceSubClass  接口子类型:01为Boot Device,键鼠在BIOS下就启动
       0x01,                               // bInterfaceProcotol    接口协议:00--None  01--Keyboard  02--Mouse
       0x00                                // iInterface                  描述该接口的字符串索引
    };

    mouse_interface_descriptor =
    {  
       0x09,                               // bLength   长度9个,不可变
       0x04,                               // bDescriptorType   接口描述符
       0x01,                               // bInterfaceNumber  接口1   不同接口
       0x00,                               // bAlternateSetting   接口索引值
       0x01,                               // bNumEndpoints     端点个数1(端点0不可用,比如EP2)
       0x03,                               // bInterfaceClass     (3 = HID)
       0x01,                               // bInterfaceSubClass  
    接口子类型:01为Boot Device,键鼠在BIOS下就启动
       0x02,                               // bInterfaceProcotol    
    接口协议:00--None  01--Keyboard  02--Mouse
       0x00                                // iInterface                  描述该接口的字符串索引
    };

    四、HID描述符

     keyboard_hid_descriptor =
    {   
       0x09,                               // bLength                 长度9个,不可变
       0x21,                               // bDescriptorType    HID描述符
       0x0110,                           // bcdHID                   HID专属版本号
       0x00,                               // bCountryCode       国家代码
       0x01,                               // bNumDescriptors   附属类描述字的数目1个
       0x22,                               // bDescriptorType    描述字类型:报告   
       HID_KEYBOARD_REPORT_DESCRIPTOR_SIZE  // 键盘HID报告描述字总字节数,比如:0x75,0x00,低字节在前      
    };

     mouse_hid_descriptor =
    {   
       0x09,                               // bLength                 长度9个,不可变
       0x21,                               // bDescriptorType    HID描述符
       0x0110,                           // bcdHID                   HID专属版本号
       0x00,                               // bCountryCode       国家代码
       0x01,                               // bNumDescriptors   附属类描述字的数目1个
       0x22,                               // bDescriptorType    描述字类型:报告   
       HID_MOUSE_REPORT_DESCRIPTOR_SIZE  // 鼠标HID报告描述字总字节数,比如0x34, 0x00,低字节在前       
    };

    五、端点描述符

    hid_keyboard_endpoint1_in_descriptor  = 
    {   
       0x07,                               // bLength                   长度7个,不可变
       0x05,                               // bDescriptorType      端点描述符
       0x81,                               // bEndpointAddress   bit[7]:1--IN  0--OUT  地址为EP1,输入
       0x03,                               // bmAttributes            传输类型(中断--03H)
       0x08,                               // MaxPacketSize_LSB   端点1最大信息包尺寸
       0x00,                               // MaxPacketSize_MSB               
       0x08,                               // bInterval                   轮询间隔 一帧为8个中断间隔

    };

    hid_mouse_endpoint2_in_descriptor  = 
    {   
       0x07,                               // bLength                   长度7个,不可变
       0x05,                               // bDescriptorType      端点描述符
       0x82,                               // bEndpointAddress   bit[7]:1--IN  0--OUT  地址为EP2,输入
       0x03,                               // bmAttributes            传输类型(中断--03H)
       0x08,                               // MaxPacketSize_LSB   端点1最大信息包尺寸
       0x00,                               // MaxPacketSize_MSB               
       0x08,                               // bInterval                   轮询间隔 一帧为8个中断间隔

    };

    说完上述几个重要描述符后,我们再来看字符串描述符.

    在USB中,字符串描述符是可选的,也就是可有可无的角色,USB并没有强制规定必须有,但是一般产品是有的,至少能说明生产厂家,产品信息等,要不然这个产品看谁还敢用.哈哈哈...

    如果设备没有字符串描述符,那么在设备描述符、配置描述符、接口描述符等处的字符串索引值必须为0,要不然在枚举过程中,USB主机会尝试去获取字符串描述符,而刚好你又没有,那么枚举就会失败,所以必须指定为0

    字符串描述符使用UNICODE编码,可以支持多种语言,所以字符串描述符首先要指定语言ID,语言ID代码可以参考这个网站:http://www.usb.org/developers/docs/USB_LANGIDs.pdf,例如:简体中文的ID值为0x0804,美式英语ID值为0x0409。

    语言ID字符串描述符结构定义如下:

    在枚举过程中,USB主机会向USB设备发送GET_DESCRIPTOR请求,同时wValue字段高字节为描述符类型,字符串描述符的类型为0x03,低字节为字符串描述符索引值,对于语言ID的索引为0,其它字符串描述符索引由设备描述符指定,wIndex字段为语言ID。

    字符串描述符结构定义如下:

    bLength为描述符长度,bDescriptorType为描述符类型,字符编码统一采用UNICODE编码,UNICODE采用两个字节字节表示一个字符,如果是英语字符的话,那就很简单了,直接在ASCII码前面补上一个为0x00的字节数据就组成UNICODE编码了,如果是其它语言的话,网上有很多的UNICODE编码转换工具,可以直接拿来使用就行了。

    最后补上我的USB鼠标字符串描述符信息。

    语言ID信息:

    厂商字符串描述符如下:

    我在Virtual Box中捕获的信息,所以厂商字符串为VirtualBox。

    产品字符串描述符信息如下:

    主机通过标准请求命令来获得以上HID描述符和HID报告:

         标准USB设备请求命令共有11个,大小都是8个字节,具有相同的结构,由5 个字段构成(字段是标准请求命令的数据部分),结构如下(括号中的数字表示字节数,首字母bm,b,w分别表示位图、字节,双字节):
    bmRequestType(1) +bRequest(1) +wvalue(2) +wIndex(2) +wLength(2)
    一、bmRequestType:

            bit[7]: 说明请求的传输方向  1--设备到主机(IN)   0--主机到设备(OUT)

            bit[6:5]:00--标准请求命令    01--专门类请求   10--用户定义的请求    11--保留

            bit[4:0]:00000--接收者为设备   00001--接收者为接口   00010--接收者为端点  00011--接收者为其他元件 其他设置保留

    二、bRequest:

          请求命令代码,在标准的USB命令中,每一个命令都定义了编号,编号的值就为字段的值,编号与命令名称如下(要注意这里的命令代码要与其他字段结合使用,可以说命令代码是标准请求命令代码的核心,正是因为这些命令代码而决定了11个USB标准请求命令):
        1、Get Status (00H)  获取状态 

           wValue:0000H    wIndex:0000H(设备)、接口号或端点号  wLength:0002H
           A:[To Device]获取设备的状态:
              位0:自供电(0表示总线供电;1表示自供电).
              位1:远程唤醒(0表示不支持远程唤醒;1表示远程唤醒).
              位2~15:保留.
              一般选择总线供电,不支持远程唤醒,所以返回数据就是0x0000.
           B:[To Interface]获取接口的状态:
              接口状态的16位字节全部保留,所以返回数据就是0x0000.
           C:[To Endpoint]获取端点的状态:
              位0:Halt(0表示端点允许;1表示端点禁止).
              位1~15:保留(复位为0).

          
        2、Clear Feature (01H) 清除特性 

          wValue:所要禁用的特征   wIndex:0000H(设备)、接口号或端点号  wLength:0000H
           A:[To Device]清除设备的远程唤醒功能,并返回一个空包.
           B:[To Endpoint]解禁端点.
       
        3、Set Feature (03H) 设置特性 

         wValue:所要使能的特征   wIndex:0000H(设备)、接口号或端点号  wLength:0000H

           A:[To Device]设置设备的远程唤醒功能,并返回一个空包.
           B:[To Endpoint]禁止端点.


        4、Set Address (05H) 设置地址 

          wValue:新的设备地址,范围0001H到007FH   wIndex:0000H  wLength:0000H
           A:设置设备地址.


        5、Get Descriptor (06H) 获取描述符 

         wValue:高字节--描述符类型  低字节--描述符索引   wIndex:0000H或ID  wLength:需返回的字节数
           A:[To Device]获取设备描述符:
              描述当前USB协议的版本号.设备端点0的FIFO大小.USB设备的ID号等.
           B:[To Configuration]获取配置描述符:
              描述USB设备接口个数及是否有自供电能力等.
           C:[To Interface]获取接口描述符:
              描述端点0以外的物理端点个数等信息.
           D:[To Endpoint]获取端点描述符:
              描述端点0各端点的传输类型和最大信息包大小和端点的传输方向(IN/OUT).


        6、Set Descriptor (07H) 设置描述符(可选,无法更新) 

        wValue:高字节--描述符类型  低字节--描述符索引   wIndex:0000H或ID  wLength:需传输给设备的字节数


        7、Get Configuration (08H) 获取配置信息 

        wValue:0000H   wIndex:0000H   wLength:0001H


        8、Set Configuration (09H) 设置配置 

        wValue:低字节规定了一个配置,若此值与设备支持的配置匹配,设备将实现所请求配置   wIndex:0000H  wLength:0000H
           A:[To Configuration]设置配置描述符.
           B:[To Interface]设置接口描述符.
           C:[To Endpoint]设置端点描述符.


        9、Get Interface (0AH) 获取接口信息    
        wValue:0000H   wIndex:接口号(bInterfaceNumber)  wLength:0001H


        10、Set Interface (0BH) 设置接口 

        wValue:要选择的替代设置(bAlternateSetting)   wIndex:接口号(bInterfaceNumber)  wLength:0000H


        11、SYNCH_FRAME(0CH)

        wValue:0000H   wIndex:0000H  wLength:0006H
            用于设备设置和报告一个端点的同步帧.

    一个描述设备描述符和描述配置描述符过程如下图:

    USB学习之描述符篇--枚举 - lastnight1034 - lastnight1034的博客
    可以看到80  06  00  01  00  00  12  00主机发给设备的请求:
    bmRequestType=80H说明这是主机发给设备的标准请求;
    bRequest=06H说明这句的作用是Get Descriptor
    wValue=0100H(注意这是小端模式,高字节在图片里显示在后)说明需要设备上传设备描述符(01)
    wLength=0012H(注意这是小端模式,高字节在图片里显示在后)说明设备必须上传12H个字节长度的数据
    于是设备上传了0012H长的设备描述符:12  01  00  02  00  00  00  08  23  12  07  3f  10  11  01  02  00  01
    第四行80  06  00  02  00  00  09  00主机发给设备请求:
    按上面的解释,说明这是主机要求设备上传配置描述符(02H),因为主机无法得知配置描述符里的wTotallength多大,所以先发个标准长度0009H来试探。
    于是设备上传了09H长的配置描述符:09  02  3b  00  02  01  00  a0  32
    主机得知配置总的含有003bH个字节,于是再次发给设备上传配置描述符的请求:80  06 00 02 00 00 3b  00,要求的总字节长度为003bH
    之后设备上传了003bH的数据:9个配置描述符+9个接口0描述符+9个HID描述符+7个端点1描述符+9个接口1描述符+9个HID描述符+7个端点1描述符
    后主机进行设置配置:00  09  01  00  00  00  00  00 设置了配置描述符,使能端点1和端点2
    USB学习之描述符篇--枚举 - lastnight1034 - lastnight1034的博客
    因为有2个接口,所以分2次分别设置:
    EP1:读取设备描述符,试探性配置描述符,返回键盘的配置描述符长度0022H,再次以0022H长度读取配置描述符。设置配置描述符,挂起等配置完成。
    配置完成后读取HID报告:81  06  00  22  00  00  b5  00
    81代表主机发给设备的接口   06代表Get Descriptor   22H为HID报告  wIndex:00为接口0  长度为75H+40H=b5H(?)
    设备上传接口0的0075H长度字节HID报告。
    开始设置接口1,仍然继续读取设备描述符试探性配置描述符,返回键盘的配置描述符长度0022H,再次以0022H长度读取配置描述符。设置配置描述符,挂起等配置完成。
    配置完成后读取HID报告:不同的是wIndex:0001H 配置接口1,长度为34H+40H=74H(?)
    设备上传接口1的0034H长度字节HID报告。结束后SET REPORT,结束,等待设备上传端点键盘鼠标数据。
     

    HID设备描述符

    温习了以上内容,我们再来看看HID协议与这些描述符之间的关系。

    当插入USB设备后,主机会向设备请求各种描述符来识别设备。

    为了把一个设备识别为HID类别,设备在定义描述符的时候必须遵守HID规范。

    从框图中,可以看出除了USB标准定义的一些描述符外,HID设备还必须定义HID描述符。另外设备和主机的通信是通过报告的形式来实现的,所以还必须定义报告描述符;而物理描述符不是必需的。还有就是HID描述符是关联于接口(而不是端点)的,所以设备不需要为每个端点都提供一个HID描述符。

    接口描述符中bInterfaceClass的值必须为0x03,bInterfaceSubClass的值为0或1,为1表示HID设备符是一个启动设备(Boot Device,一般对PC机而言才有意义,意思是BIOS启动时能识别并使用您的HID设备,且只有标准鼠标或键盘类设备才能成为Boot Device。如果为0则只有在操作系统启动后才能识别并使用您的HID设备)。

    USB HID类描述符的结构

    偏移量

    大小

    描述

    0

    bLength

    1

    数字

    此描述符的长度(以字节为单位)

    1

    bDescriptorType

    1

    常量

    描述符种类(此处为0x21即HID类描述符)

    2

    bcdHID

    2

    数字

    HID规范版本号(BCD码),采用4个16进制的BCD格式编码,如版本1.0的BCD码为0x0100,版本为1.1的BCD码为0x0110

    4

    bCountryCode

    1

    数字

    硬件目的国家的识别码(BCD码)(见表3)

    5

    bNumDescritors

    1

    数字

    支持的附属描述符数目

    6

    bDescriptorType

    1

    常量

    HID相关描述符的类型

    0x21:HID描述符

    0x22:报告描述符

    0x23:物理描述符

    7

    wDescriptorLength

    2

    数字

    报告描述符总长度

    9

    bDescriptorType

    1

    常量

    用于识别描述符类型的常量,使用在有一个以上描述符的设备

    10

    wDescriptorLength

    2

    数字

    描述符总长度,使用在有一个以上描述符的设备

    报告描述符

    报告描述符比较复杂,它是以item形式排列组合而成,无固定长途,用户可以自定义长度以及每一bit的含义。item类型分三种:main,global和local,其中main类型又可分为5种tag:

    • input item tag:指的是从设备的一个或多个类似控制管道得到的数据
    • output item tag:指的是发送给一个或多个类似控制管道的数据
    • feature item tag:表示设备的输入输出不面向最终用户
    • collection item tag:一个有意义的input,output和feature的组合项目
    • end collection item tag:指定一个collectionitem的终止

    每一个main item tag(input,output,feature)都表明了来自一个特定管道的数据的大小,数据相对还是独立,以及其他相关信息。在此之前,global和local item定义了数据的最大值和最小值,等等。local item仅仅描述下一个main item定义的数据域,而global item是这一个报告描述符中所有后续数据段的默认属性。

     一个报告描述符可能包含多个main item,为了准确描述来自一个控制管道的数据,一个报告描述符必须包括以下内容:

    • input(output,feature)
    • usage
    • usage page
    • Logical Minimum
    • Logical Maximum
    • Report Size
    • Report Count

    下面用一个三键鼠标举例说明:

    Usage Page (Generic Desktop);    //global item

    Usage (Mouse);    //global item 
    Collection (Application);    //Start Mouse collection
    Usage (Pointer);    //
    Collection (Physical);    //Start Pointer collection
    Usage Page (Buttons)
    Usage Minimum (1),
    Usage Maximum (3),
    Logical Minimum (0),
    Logical Maximum (1) ;   //Fields return values from 0 to 1
    Report Count (3),
    Report Size (1);   //Create three 1 bit fields (button 1, 2, & 3)
    Input (Data, Variable, Absolute);   //Add fields to the input report.
    Report Count (1),
    Report Size (5);   //Create 5 bit constant field
    Input (Constant), ;Add field to the input report
    Usage Page (Generic Desktop),
    Usage (X),
    Usage (Y),
    Logical Minimum (-127),
    Logical Maximum (127);    //Fields return values from -127 to 127
    Report Size (8),
    Report Count (2);    //Create two 8 bit fields (X & Y position)
    Input (Data, Variable, Relative);   //Add fields to the input report
    End Collection;   //Close Pointer collection
    End Collection;   //Close Mouse collection

    item的数据格式有两种,分别是短item和长item。

    短item格式

    bSize

    0:0个字节

    1:1个字节

    2:2个字节

    3:4个字节

    bType

    0:main

    1:global

    2:local

    3:保留

    bTag

    item类型

    8:input

    9:output

    A:collection

    B:feature

    C:end collection

    长item,其bType位值为3,bTag值为F

    bDataSize

    0:0个字节

    1:1个字节

    2:2个字节

    3:4个字节

    bLongItemTag

    0:main

    1:global

    2:local

    3:保留

    data 数据

    物理描述符用来描述行为特性,是可选的。

    USB HID类可采用的通信管道

    所有的HID设备通过USB的控制管道(默认管道,即端点0)和中断管道与主机通信。

    控制管道主要用于以下3个方面:

    接收/响应USB主机的控制请示及相关的类数据

    在USB主机查询时传输数据(如响应Get_Report请求等)

    接收USB主机的数据

    中断管道主要用于以下两个方面:

    USB主机接收USB设备的异步传输数据

    USB主机发送有实时性要求的数据给USB设备

    从USB主机到USB设备的中断输出数据传输是可选的,当不支持中断输出数据传输时,USB主机通过控制管道将数据传输给USB设备。

     

    表1、USB HID规范定义的HID设备可用端点

    管道

    要求

    说明

    控制(端点0)

    必须

    传输USB描述符、类请求代码以及供查询的消息数据等

    中断输入

    必须

    传输从设备到主机的输入数据

    中断输出

    可选

    传输从主机到设备的输出数据

    HID设备6种特定请求

    HID类请求(命令)包格式

    偏移量

    大小

    说明

    0

    bmRequestType

    1

    HID设备类请求特性如下:
    位7:
    0=从USB HOST到USB设备
    1=从USB设备到USB HOST
    位6~5:
    01=请求类型为设备类请求
    位4~0:
    0001=请求对象为接口(interface)

    因而,针对HID的设备类请求,仅仅10100001和00100001有效

    1

    bRequest

    1

    HID类请求(参考下表)

    2

    wValue

    2

    高字节说明描述符的类型

    0x21:HID描述符

    0x22:报告描述符

    0x23:物理描述符

    低字节为非0值时被用来选定实体描述符。

    4

    wIndex

    2

    2字节数值,根据不同的bRequest有不同的意义

    6

    wLength

    2

    该请求的数据段长度

    HID类请求

    数值

    HID类请求描述符

    注释

    0x01

    GET_REPORT

     主机用控制传输从设备接收数据,所有HID类设备都要支持这个请求;

    0x02

    GET_IDLE

     主机读取设备当前的空闲速率,设备可以不支持此请求;

    0x03

    GET_PROTOCOL

    仅仅适应于支持启动功能的HID设备(Boot Device)

    0x09

    SET_REPORT

     设备用控制传输接收主机的数据,设备可以不支持此请求;

    0x0A

    SET_IDLE

     设置闲置状态,设备可不支持此请求;

    0x0B

    SET_PROTOCOL

    仅仅适应于支持启动功能的HID设备(Boot Device)

    GET_REPORT:主机通过控制端点获取一个Report

    描述

    bmRequestType

    0xA1

    bRequest

    0x01

    wValue

    高字节表示报告类型

    0x01:input

    0x02:output

    0x03:feature

    other:reserved

    低字节表示ReportID,如不使用设为0

    wIndex

    HID的interface索引值

    wLength

    Report长度

    Data

    Report内容

    SET_REPORT:主机发送一个Report给设备,用以设置input,output或者feature

     

    描述

    bmRequestType

    0x21

    bRequest

    0x09

    wValue

    高字节表示报告类型

    0x01:input

    0x02:output

    0x03:feature

    other:reserved

    低字节表示ReportID,如不使用设为0

    wIndex

    HID的interface索引值

    wLength

    Report长度

    Data

    Report内容

    GET_IDLE

     

    描述

    bmRequestType

    0xA1

    bRequest

    0x02

    wValue

    高字节0

    低字节表示ReportID,如不使用设为0

    wIndex

    HID的interface索引值

    wLength

    1

    Data

    空闲速率

    SET_IDLE

    描述

    bmRequestType

    0x21

    bRequest

    0x0A

    wValue

    新的速率

    低字节表示ReportID,如不使用设为0

    wIndex

    HID的interface索引值

    wLength

    0

    Data

    GET_PROTOCOL

    描述

    bmRequestType

    0xA1

    bRequest

    0x03

    wValue

    0

    wIndex

    HID的interface索引值

    wLength

    1

    Data

    0 = Boot Protocol

    1 = Report Protocol

    SET_PROTOCOL

    描述

    bmRequestType

    0x21

    bRequest

    0x0B

    wValue

    0 = Boot Protocol

    1 = Report Protocol

    wIndex

    HID的interface索引值

    wLength

    0

    Data

  • 相关阅读:
    arcgis开发笔记【silverlight开发资料】
    arcgis开发笔记【系统介绍】
    Vs2010架构设计概述
    arcgis开发笔记【Oracle使用汇总】
    arcgis开发笔记【silverlight 发布rest地图服务】
    arcgis开发笔记【系统的安装】
    关于处理Ajax请求的一些心得
    IE浏览器Css选择的优先问题
    requestFeature() must be called before adding content错误
    Error inflating class错误
  • 原文地址:https://www.cnblogs.com/AlwaysOnLines/p/3848461.html
Copyright © 2011-2022 走看看