说到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的博客](http://img4.ph.126.net/So82YKbwH629qkdCvoKxiA==/6597991157400760084.jpg)
![USB学习之描述符篇--枚举 - lastnight1034 - lastnight1034的博客](http://img3.ph.126.net/8NS5pA3xRP_OmDmuhVQRQw==/6597816335051943153.jpg)
from:
http://blog.csdn.net/xiliang_pan/article/details/51028712
http://lastnight1034.blog.163.com/blog/static/167118149201211710164820/