USB描述符的分类与介绍
USB的符述符分为几类?有人可能会答:设备描述符、配置描述符、接口描述符、端点描述符、字符串描述符等。但这里说的不是这样的。上面的几类描述符属于USB标准描述符。另外还有HID描述符和Hub描述符。所以分类是这样的:
1. 标准描述符
1) 设备描述符
2) 配置描述符
3) 字符串描述符
4) 接口描述符
5) 端点描述符
6) 设备限定描述符
7) 其他速率配置描述符
2. HID描述符
3. Hub描述符
1 标准描述符
标准描述符是指一组设备描述符,包括设备描述符、配置描述符、字符串描述符、接口描述符、端点描述符、设备限定描述符和其他速率配置描述符。这七种 描述符具有类似的格式,比如说它们的第一个字段都是bLength,第二个字段都是bDescriptorType。七种描述符在使用时以 bDescriptorType字段来区分。描述符类型与对应的bDescriptorType字段值对应关系为:
1.1 设备描述符
设备描述符描述的是设备的整体信息,与设备本身一一对应,一个设备只能有一个设备描述符。在主机对USB设备枚举的过程中,首先要做的就是获取设备描述符,以对设备有一个整体的了解。
设备描述符由14个字段组成,总长度18字节:
这些字段都有一个小写字母表示的前缀,它们所表示的意思如下:
b 表一个字节,=8bits;
w 表一个字,=16bits;
bm 表按位寻址;
bcd 用BCD码表示;
i 表索引值
id 表标识码
各字段含义:
bLength: 表示描述符的长度,对于设备描述符来说,其值为18,即0x12。
bDescriptorType: 描述符类型,对应表1中的值,设备描述符为0x01。
bcdUSB:该设备遵循的USB版本号,以BCD码表示,USB1.1为0x0101,USB2.0为0x0200。
bDeviceClass:该设备所属的标准设备类,USB协议中对常见的设备进行了分类。该字段值为0x01~0xFE时,表示是USB协议中已定义的设备类,常用的HID设备类编号为0x03,其它设备类编号参:http://www.usb.org/developers/defined_class
bDeviceProtocol:用于表示USB设备类所采用的设备类协议,其值和bDeviceClass和bDeviceSubClass有关。当此 字段为0时,表示不使用任何设备类协议。如果该USB设备属于某个设备类和设备子类,则应该继续指明所采用的设备类协议。当该字段为0xFF时,表明设备 类协议由供应商自定义。
bMaxPacketSize0:用于表示在USB设备中,端点0所支持最大数据包的长度,它以字节为单位。对于低速USB设 备,bMaxPacketSize0为8;对于全速USB设备,bMaxPacketSize0为8、16、32、64;对于高速USB设 备,bMaxPacketSize0为64。
IdVendor:用于表示USB设备供应商的ID。USB组织中规定每种产品都必须包含一个供应商ID,这样可以使主机加载合适的驱动程序。
idProduct:用于表示USB产品的ID,由设备供应商提供。idProduct用于表示特定的USB设备,在USB设备上电的时候可以帮助USB主机选择合适的驱动程序。
bcdDevice:用于表示USB设备的版本号,它以BCD码的形式表示。一般来说bcdDevcie由设备供应商指定,在USB设备上电的时候可以帮助USB主机选择合适的驱动程序。
iManufacturer:用于表示供应商字符串描述符的索引值。具体字符串的内容在后面字符串描述符中定义。如果没有供应商字符串,可以置0。
这里应该还有一个 iProduct
iSerialNumber:用于表示设备序列号字符串描述符的索引值,如果没有,可以置为0。
bNumConfigurations:用于表示该USB设备所支持的配置数。
by louis:
结合stm32 的usb 设备描述符:
/* USB Standard Device Descriptor */
const u8 Joystick_DeviceDescriptor[JOYSTICK_SIZ_DEVICE_DESC] =
{
0x12, /*bLength */
USB_DEVICE_DESCRIPTOR_TYPE, /*bDescriptorType*/
0x00, /*bcdUSB */
0x02,
0x00, /*bDeviceClass*/
0x00, /*bDeviceSubClass*/
0x00, /*bDeviceProtocol*/
0x40, /*bMaxPacketSize40*/
0x11, /*idVendor (0x1234)*/
0x11,
0x11, /*idProduct = 0x4321*/
0x11,
0x00, /*bcdDevice rel. 2.00*/
0x02,
1, /*Index of string descriptor describing
manufacturer */
2, /*Index of string descriptor describing
product*/
3, /*Index of string descriptor describing the
device serial number */
0x01 /*bNumConfigurations*/
}
; /* Joystick_DeviceDescriptor */
bLength : 描述符大小.固定为0x12.
bDescriptorType : 设备描述符类型.固定为0x01.
bcdUSB : USB 规范发布号.表示了本设备能适用于那种协议,如2.0=0200,1.1=0110等.
bDeviceClass : 类型代码(由USB指定)。当它的值是0时,表示所有接口在配置描述符里,并且所有接口是独立的。当它的值是1到FEH时,表示不同的接口关联的。当它的值是FFH时,它是厂商自己定义的.
bDeviceSubClass : 子类型代码(由USB分配).如果bDeviceClass值是0,一定要设置为0.其它情况就跟据USB-IF组织定义的编码. (louis:这两项如果是在复合设备下,就会和一般的单一设备不太一样了)
bDeviceProtocol : 协议代码(由USB分配).如果使用USB-IF组织定义的协议,就需要设置这里的值,否则直接设置为0。如果厂商自己定义的可以设置为FFH.
bMaxPacketSize0 : 端点0最大分组大小(只有8,16,32,64有效).
idVendor : 供应商ID(由USB分配).
idProduct : 产品ID(由厂商分配).由供应商ID和产品ID,就可以让操作系统加载不同的驱动程序.
bcdDevice : 设备出产编码.由厂家自行设置.
iManufacturer : 厂商描述符字符串索引.索引到对应的字符串描述符. 为0则表示没有.
iProduct : :产品描述符字符串索引.同上.
iSerialNumber : 设备序列号字符串索引.同上.
bNumConfigurations : 可能的配置数.指配置字符串的个数
iManufacturer 之前的还算好理解。
iManufacturer ,iProduct,和 iSerialNumber ,这里的值是 1,2,3 是什么含义?
看看下面的定义,这个是 字符串描述符。
他们在
ONE_DESCRIPTOR String_Descriptor[4] =
{
{(u8*)Joystick_StringLangID, JOYSTICK_SIZ_STRING_LANGID},
{(u8*)Joystick_StringVendor, JOYSTICK_SIZ_STRING_VENDOR},
{(u8*)Joystick_StringProduct, JOYSTICK_SIZ_STRING_PRODUCT},
{(u8*)Joystick_StringSerial, JOYSTICK_SIZ_STRING_SERIAL}
};
里面被引用,我理解的 这个 1 ,2,3,这三个值就这三个字符串在数组中的索引。
/* USB String Descriptors (optional) */
const u8 Joystick_StringLangID[JOYSTICK_SIZ_STRING_LANGID] =
{
JOYSTICK_SIZ_STRING_LANGID,
USB_STRING_DESCRIPTOR_TYPE,
0x09,
0x04
}
; /* LangID = 0x0409: U.S. English */
const u8 Joystick_StringVendor[JOYSTICK_SIZ_STRING_VENDOR] =
{
JOYSTICK_SIZ_STRING_VENDOR, /* Size of Vendor string */
USB_STRING_DESCRIPTOR_TYPE, /* bDescriptorType*/
/* Manufacturer: "STMicroelectronics" */
'S', 0, 'T', 0, 'M', 0, 'i', 0, 'c', 0, 'r', 0, 'o', 0, 'e', 0,
'l', 0, 'e', 0, 'c', 0, 't', 0, 'r', 0, 'o', 0, 'n', 0, 'i', 0,
'c', 0, 's', 0
};
const u8 Joystick_StringProduct[JOYSTICK_SIZ_STRING_PRODUCT] =
{
JOYSTICK_SIZ_STRING_PRODUCT, /* bLength */
USB_STRING_DESCRIPTOR_TYPE, /* bDescriptorType */
'S', 0, 'T', 0, 'M', 0, '3', 0, '2', 0, ' ', 0, 'J', 0,
'o', 0, 'y', 0, 's', 0, 't', 0, 'i', 0, 'c', 0, 'k', 0
};
u8 Joystick_StringSerial[JOYSTICK_SIZ_STRING_SERIAL] =
{
JOYSTICK_SIZ_STRING_SERIAL, /* bLength */
USB_STRING_DESCRIPTOR_TYPE, /* bDescriptorType */
'S', 0, 'T', 0, 'M', 0, '3', 0, '2', 0, '1', 0, '0', 0
};
1.2 配置描述符
一个USB设备可以有多种配置,不同的配置使设备工作在不同的状态下,每个配置必须有一个配置描述符。其格式包括8个字段,共9字节。
各个字段含义:
bLength:用于表示配置描述符的长度,固定为9个字节,即0x09。
bDescriptorType:用于表示配置描述符的类型值,固定为0x02。
wTotalLength:用于表示配置信息的总长度,包括配置描述符、接口描述符、端点描述符长度的总和。
bNumInterfaces:用于表示配置所支持的接口数。一般来说,USB设备的接口至少有一个,因此其最小值为1。
bConfigurationValue:用于表示USB设备的配置值。
iConfiguration:用于指出配置字符串描述符的索引值。具体字符串的内容在后面字符串描述符中定义。如果没有配置字符串,可以置为0。
bmAttributes:用于表示USB设备特性。bmAttributes是接位寻址的,第6位置1表示使用总线电源;第5位置1表示支持远程唤醒功能;该字段其他位均保留,一般来说,第0~4位置0即可,第7位置1即可。
bMaxPower:用于表示USB设备运行时所需要消耗的总线电流,单位以2mA为基准。USB设备可以从USB总线上获得最大的电流为500mA,因此bMaxPower字段的最大值可以设置为250。
by louis:配置描述符的 第一段。
bNumInterfaces: 下面的接口描述部分,有几个就是几。
bConfigurationValue: 当使用SetConfiguration和GetConfiguration请求时所指定的配置索引值。
bConfigurationValue:每个配置都有一个标识值。 看样子这个解释更让人容易理解。 暂时理解为这个配置的唯一标识。
iConfiguration: 描述配置的 字符串描述符索引。
/***************配置描述符***********************/
0x09, //bLength字段
USB_CONFIGURATION_DESCRIPTOR_TYPE, //bDescriptorType字段
//wTotalLength字段
JOYSTICK_SIZ_CONFIG_DESC,
/* wTotalLength: Bytes returned 这个是两字节长度的,后面一个字节就为0了?*/
0x00,
0x01, //bNumInterfaces字段
0x01, //bConfiguration字段
0x00, //iConfigurationz字段
0x80, //bmAttributes字段
0xC8, //bMaxPower字段
1.3 字符串描述符
在USB协议中字符串描述符是可选的。字符串描述符用于保存一些供应商名称、产品序列号等文本信息。它的长度是不固定的,随字符串的数量和信息的长度变化而变化。其格式如下:
各字段含义:
bLength:字符串描述符的长度,其值应为N+2。
bDescriptorType:字符串描述符的类型值,为0x03。
bString:UNICODE编码的字符串。
1.4 接口描述符
接口是端点的集合,负责完成USB的特定功能,例如数据的输入输出。接口描述符用于描述一个接口,包含了接口的特性,如端点个数,所属设备类和子类等。它有9个字段,共9字节。其格式如下:
by louis:
/*******************第一个接口描述符*********************/
0x09, //bLength字段
0x04, //bDescriptorType字段
0x00, //bInterfaceNumber字段 这个是第一个接口,所以是0, 第二个接口的是1
0x00, //bAlternateSetting字段
0x02, //bNumEndpoints字段 这个接口使用的端点数,为啥是两个?
// 参考 Device Class Definition for Human Interface Devices (HID) 下面的三个参数决定了这个接口是个键盘
0x03, //bInterfaceClass字段 0x03 人机接口类(HID) 这还不意味着是键盘,只是表示是HID
0x01, //bInterfaceSubClass字段 0x01 0 No Subclass 1 Boot Interface Subclass 这个只能是 0或者1
0x01, //bInterfaceProtocol字段 Protocol Code Description 0=None ;1=Keyboard 2=Mouse 3 - 255=Reserved
0x00, //iInterface: 描述该接口的字符串描述符的索引
后面还有后续的描述符,参考:
https://blog.csdn.net/tanjiaqi2554/article/details/78440726
https://blog.csdn.net/qq_16777851/article/details/85222030
设备 配置 接口 端点的关系。。
关于USBHID协议以及鼠标键盘描述符的解释
https://blog.csdn.net/jiujiujiuqiuqiuqiu/article/details/47277685
STM32的USB例程JoyStickMouse改成自定义HID设备
https://blog.csdn.net/chiqingjiao7503/article/details/86696875
USB键盘数据解析
https://blog.csdn.net/weixin_30348519/article/details/96396583
五、端点描述符(endpoint)
用于接口的每个端点都有自己的描述符。 此描述符包含主机确定每个端点的带宽要求所需的信息。 始终返回端点描述符作为GetDescriptor(配置)请求返回的配置信息的一部分。 无法使用GetDescriptor()或SetDescriptor()请求直接访问端点描述符。 端点零永远不会有端点描述符。
表9-13显示了标准端点描述。