USB设备开发---- usb描述符概述

来源:互联网 发布:最伟大的意大利人知乎 编辑:程序博客网 时间:2024/05/16 12:08


说到USB设备,不得不提到各种描述符(descriptors), 一般来说,描述符有如下几种:

    1:设备描述符(Device Descriptors)

    2:配置描述符(Configuration Descriptors)

    2:接口描述符(Interface Descriptors)

    3:端点描述符(Endpoint Descriptors)

     一个USB设备只有一个设备描述符,设备描述符里面定义了该设备有多少种配置,每种配置描述符对应着配置描述符;而在配置描述符中又定义了该配置里面有多少个接口,每个接口有对应的接口描述符;在接口描述符里面又定义了该接口有多少个端点,每个端点对应一个端点描述符;端点描述符定义了端点的大小,类型等等。由此我们可以看出,USB的描述符之间的关系是一层一层的,最上一层是设备描述符,下面是配置描述符,再下面是接口描述符,再下面是端点描述符。在获取描述符时,先获取设备描述符,然后再获取配置描述符,根据配置描述符中的配置集合长度,一次将配置描述符、接口描述符、端点描述符一起一次读回。其中可能还会有获取设备序列号,厂商字符串,产品字符串等。

详细关系如下图所示:




==================================================

USB 复合设备上的描述符

如 USB 规范所述,每个 USB 设备都会提供一组分层描述符来定义其功能。在顶层,每个设备具有一个或多个 USB 配置描述符,其中每一个都具有一个或多个接口描述符。有关 USB 配置描述符的详细信息,请参阅 USB 配置描述符。配置是相互排斥的,因此,一次只能选择一种配置来进行操作。

在 Windows Vista 之前,Microsoft 提供的驱动程序仅选择配置 1。在 Windows Vista 和更高版本的 Windows 中,你可以设置注册表值来指定 USB 通用父驱动程序 (Usbccgp.sys) 将使用哪个配置。有关在复合设备上选择设备配置的详细信息,请参阅如何选择 USB 设备配置。


https://msdn.microsoft.com/zh-cn/library/ff537071


===========================================

开发无线键鼠有2年多了,一直对HID这东西一知半解。赶在新项目需要重新编写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个中断间隔

};

 

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

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

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

        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,结束,等待设备上传端点键盘鼠标数据。
 
剩下的是字符串这个不是必须的还没讲到。


from: 

http://blog.csdn.net/xiliang_pan/article/details/51028712

http://lastnight1034.blog.163.com/blog/static/167118149201211710164820/

原创粉丝点击