USB-HID

1、设备描述符

设备描述符USB设备中的一个标准化的数据结构,它包含了该设备最基本、最核心的信息。当USB设备首次连接到电脑(主机)时,主机会首先向设备请求“设备描述符”,通过读取这段信息,主机才能知道“我连接上了一个什么东西”,并据此决定如何与这个设备进行后续的通信。

可以将其想象成设备的“身份证”或者是“产品规格说明书首页”。

根据USB规范,设备描述符是一个长度为18字节的固定结构。包含以下字段:

字段偏移字段名长度(字节)描述与示例
0bLength1描述符本身的长度。对于设备描述符,这个值固定为 18 (0x12)。
1bDescriptorType1描述符类型。固定为 1 (0x01),代表这是一个“设备描述符”。
2bcdUSB2USB 规范发布号。表示设备所遵循的 USB 版本。
• 0x0200 表示 USB 2.0
• 0x0310 表示 USB 3.1
• 0x0210 表示 USB 2.1
4bDeviceClass1设备类代码。由 USB-IF 定义,标识设备的宏观类别。
• 0x00:由接口描述符定义类
• 0x02:通信设备(如 Modem)
• 0x09:Hub(集线器)
• 0xEF:多功能设备
• 0xFF:厂商自定义类
5bDeviceSubClass1设备子类代码。对设备类进行进一步细分。
6bDeviceProtocol1设备协议代码。指定设备使用的协议。
7bMaxPacketSize01端点0的最大数据包大小。端点0是每个USB设备都必须有的控制端点。
• 全速设备:64 字节
• 高速设备:64 字节
• 低速设备:8 字节
8idVendor2厂商ID。由 USB-IF 分配给设备制造商的唯一标识符。
例如,0x05AC 代表苹果公司,0x04F2 代表群光电子。
10idProduct2产品ID。由制造商自行分配,用于区分其不同产品。
12bcdDevice2设备发布号。表示设备的版本号,由制造商定义。
14iManufacturer1制造商字符串描述符的索引。指向描述制造商名称的字符串。
15iProduct1产品字符串描述符的索引。指向描述产品名称的字符串。
16iSerialNumber1序列号字符串描述符的索引。指向设备的唯一序列号。
17bNumConfigurations1设备支持的配置数量。至少为1。

示例:一个普通USB 2.0U盘

//设备描述符
CTL    80 06 00 01    00 00 12 00
IN     12 01 10 01    00 00 00 08     2C 1A 24 21     10 01 01 02     00 01

原始数据:12 01 00 02 00 00 00 40 5E 04 36 05 01 02 00 01 01

偏移字段值(16进制)值(10进制)解释
0bLength1218描述符长度:18字节,正确。
1bDescriptorType011描述符类型:1,代表是设备描述符。
2-3bcdUSB00 020x0200USB版本:USB 2.0。
4bDeviceClass000设备类:0,表示类别在接口描述符中定义。
5bDeviceSubClass000设备子类:0。
6bDeviceProtocol000设备协议:0。
7bMaxPacketSize04064端点0最大包大小:64字节,这是USB 2.0高速设备的典型值。
8-9idVendor5E 040x045E厂商ID:0x045E 是 Microsoft Corp.
10-11idProduct36 050x0536产品ID:这是微软分配给某个具体产品(如Xbox控制器、鼠标等)的ID。
12-13bcdDevice01 020x0201设备版本号:2.01。
14iManufacturer011制造商字符串索引:指向字符串描述符1,通常是"Microsoft"。
15iProduct022产品字符串索引:指向字符串描述符2,可能是"Xbox 360 Controller"等。
16iSerialNumber000序列号索引:0,表示该设备没有提供序列号。
17bNumConfigurations011配置数量:该设备只有1种配置。

2、配置描述符

配置描述符是USB设备中用于描述其一种完整工作模式的数据结构。一个USB设备可以有一种或多种配置,但同一时间只能启用一种配置。

为什么需要配置?一个复杂的设备可能具有多种功能。例如,一个带麦克风的网络摄像头,可能有以下几种配置:

        (1)配置1(高功耗模式):同时启用高清视频和高质量音频

        (2)配置2(低功耗模式):仅启用低分辨率视频和单声道音频。

        主机可以根据当前的电量清空或用户需求,选择激活其中一种配置。

配置的组成:配置描述符本身指是一个“头”,它后面会紧跟这零个或多个接口描述符,以及每个接口描述符后面的零个或多个端点描述符。这些描述符共同定义了一种完整的设备工作方式。

根据USB规范,配置描述符是一个长度为9字节的固定结构

字段偏移字段名长度(字节)描述
0bLength1描述符本身的长度。对于配置描述符,这个值固定为 9 (0x09)。
1bDescriptorType1描述符类型。固定为 2 (0x02),代表这是一个“配置描述符”。
2-3wTotalLength2配置信息总长度。这是本配置描述符及其下属的所有接口描述符端点描述符设备类特定描述符供应商特定描述符的字节数之和。主机依靠这个值来一次性读取整个配置的所有信息。
4bNumInterfaces1此配置支持的接口数量。这是该配置下最核心的参数,指明了这个配置包含几个“功能集”。
5bConfigurationValue1用作 Set Configuration 命令参数的配置值。主机通过这个值来选择激活此配置。
6iConfiguration1描述此配置的字符串描述符的索引。如果为0,则表示没有字符串描述。
7bmAttributes1配置特性。这是一个按位编码的字段:
• Bit 7: 保留(必须设为1)
• Bit 6: 自供电(1-自供电,0-总线供电)
• Bit 5: 远程唤醒(1-支持,0-不支持)
• Bit 4-0: 保留(设为0)
8bMaxPower1最大功耗。单位是 2mA。例如,0x32 (50) 表示 50 * 2mA = 100mA。对于高功耗设备,这个值可能达到 0xFA (250),即 500mA。
//获取配置描述符
CTL    80 06 00 02    00 00 09 00
IN     09 02 22 00    01 01 00 A0    31

示例:USB网络摄像头

原始数据:09 02 49 00 02 01 00 A0 32

偏移字段值(16进制)值(10进制)解释
0bLength099描述符长度:9字节,正确。
1bDescriptorType022描述符类型:2,代表是配置描述符。
2-3wTotalLength49 000x0049配置信息总长度:73字节。这意味着这个配置(包括其所有接口和端点)总共需要73字节来描述。
4bNumInterfaces022接口数量2。这告诉我们,这个摄像头配置包含两个独立的功能集(接口)。
5bConfigurationValue011配置值:1。主机发送 Set Configuration(1) 命令即可激活此配置。
6iConfiguration000配置字符串索引:0,表示没有描述此配置的字符串。
7bmAttributesA00xA0配置特性
• Bit 7: 1 (保留位,必须为1)
• Bit 6: 1 → 设备为自供电
• Bit 5: 0 → 不支持远程唤醒
• Bit 4-0: 0 0000
8bMaxPower3250最大功耗:50 * 2mA = 100mA

3、接口描述符

接口描述符是USB设备种用于描述一个独立功能功能集的数据结构。一个配置下可以包含一个或多个接口,每个接口代表一个逻辑上的设备。

为什么需要接口?这是为了实现复合设备。一个物理的USB设备,在操作系统看来可以是多个逻辑设备的集合。

经典例子:USB音响

        配置:全功能模式

                接口0:音频控制接口-用于调节音量、高低音等

                接口1:音频流接口-专门用于传输时间的音频数据流

                接口2:HID接口-用于控制音箱上的物理按钮(如静音键)

        操作系统会为每个接口单独加载一个驱动程序。在上面的例子中,系统可能会为接口0和1加载通用的USB音频驱动,为接口2加载标准的HID驱动。

接口与端点的关系:接口是功能的抽象,而实现这个功能所需要的具体数据通道则由端点来描述。一个接口必须包含至少一个端点(控制端点0是默认存在的,不算在内)。

根据USB规范,接口描述符是一个长度为9字节的固定结构。

字段偏移字段名长度(字节)描述
0bLength1描述符本身的长度。固定为 9 (0x09)。
1bDescriptorType1描述符类型。固定为 4 (0x04),代表这是一个“接口描述符”。
2bInterfaceNumber1接口编号。用于区分同一配置下的不同接口。从0开始顺序编号。这是Set Interface命令用的参数。
3bAlternateSetting1备用设置编号。允许一个接口在不同的带宽、功耗或协议下工作。通常默认为0。如果存在备用设置,主机可以通过Set Interface命令在不同设置间切换。
4bNumEndpoints1此接口使用的端点数量不包括默认的控制端点0)。如果这个值为0,表示此接口只使用端点0进行通信。
5bInterfaceClass1接口类代码。这是最重要的字段之一,直接告诉主机应该加载什么驱动。
6bInterfaceSubClass1接口子类代码。对接口类进行进一步细分。
7bInterfaceProtocol1接口协议代码。指定接口所使用的协议。
8iInterface1描述此接口的字符串描述符的索引。如果为0,则表示没有字符串描述。

关键字段详解:bInterfaceClass

类代码 (16进制)描述常见设备
0x01Audio音箱、麦克风、耳机
0x03HID键盘、鼠标、游戏手柄
0x08Mass StorageU盘、移动硬盘
0x0EVideo摄像头
0x0BChip/Smart Card智能卡读卡器
0xE0Wireless Controller蓝牙适配器、Wi-Fi适配器
0xFFVendor Specific

厂商自定义设备,需要专用驱动

实际示例:

USB网络摄像头,查看它的两个接口:

接口0:HID接口(用于控制物理按钮)

原始数据(16进制):09 04 00 00 01 03 01 02 00

偏移字段解释
0bLength09描述符长度:9字节。
1bDescriptorType04描述符类型:接口描述符。
2bInterfaceNumber00接口编号0(第一个接口)。
3bAlternateSetting00备用设置:0(默认设置)。
4bNumEndpoints01端点数量:1(此接口有1个非0端点)。
5bInterfaceClass03接口类0x03,代表这是HID设备
6bInterfaceSubClass01接口子类:0x01,代表支持BIOS引导协议。
7bInterfaceProtocol02接口协议:0x02,代表是鼠标设备。
8iInterface00接口字符串:0,无描述。

解读:这个接口告诉主机,它是一个HID设备,很可能用于处理摄像头上的物理按钮(如拍照键),并将按键事件作为鼠标类事件上报。它拥有1个额外的端点(通常是一个中断输入端点)来传输这些事件数据。

4、HID描述符

HID描述符是一个类特定描述符,它的主要作用是作为HID设备通信协议的“头”或“索引”,用于向主机指明后续至关重要的报告描述符的位置和大小。

定位:它紧随在接口描述符之后

核心功能:他回答了这样一个问题:“要理解这个HID设备,你需要去读取的报告描述符在哪里?有多大?

身份:它是HID设备的“身份证”,表明了其遵循的HID规范版本

字节偏移字段名长度(字节)值(示例)含义与说明
0bLength10x09描述符长度固定为9字节。这是HID描述符的标准大小。
1bDescriptorType10x21描述符类型固定为0x21。这个魔法数字明确标识了这是一个“HID描述符”。
2-3bcdHID20x0100HID规范版本。以BCD码格式表示设备遵循的HID规范版本。例如:
• 0x0100: HID 1.00
• 0x0111: HID 1.11 (非常常见)
4bCountryCode10x00国家/地区代码。表示硬件是否针对特定地区进行了本地化。
• 0x00: 不支持本地化(最常见)
• 0x21: 法语(加拿大)键盘布局等。
5bNumDescriptors10x01附属类描述符数量。指示在此HID描述符之后,还关联了多少个其他类描述符。至少为1(必须有一个报告描述符)。
6bDescriptorType10x22附属描述符类型。指定第一个附属描述符的类型。
• 0x22: 报告描述符(几乎总是这个)
• 0x23: 物理描述符(极其罕见)
7-8wDescriptorLength20x0021附属描述符长度。指定第一个附属描述符(通常是报告描述符)的总长度,以字节为单位。例如 0x0021 表示报告描述符有 33 字节

5、端点描述符

端点描述符描述了USB设备中除默认控制端点(端点0)之外的一个数据通道。每个端点都是一个单向的通信端口,要么用于设备向主机发送数据(IN),要么用于主机向设备发送数据(OUT)。

端点是数据的出入口:可以将USB设备想象成一个房子,接口是房子里的不同房间(客厅、厨房),而端点就是每个房间的门(IN门是进,OUT是出)。数据必须通过门(端点)才能进出房间(接口)。

端点0:每个USB设备都必须有一个控制端点0.它是一个双向端点,用于所有基本的USB命令和控制传输,例如读取描述符。端点0没有端点描述符,它的存在是隐式的。

端点的地址:每个端点由一个端点号方向唯一标识

        端点号:4位,范围1-15

        方向:IN(设备到主机)或 OUT(主机到设备)

根据USB规范,端点描述符是一个长度为7字节(USB 2.0)或(USB 3.0+)的固定结构

字段偏移字段名长度(字节)描述
0bLength1描述符本身的长度。对于USB 2.0端点描述符,这个值固定为 7 (0x07)。
1bDescriptorType1描述符类型。固定为 5 (0x05),代表这是一个“端点描述符”。
2bEndpointAddress1端点地址。这是一个按位编码的字段:
• Bit 7方向 (1=IN, 0=OUT)
• Bit 6-4: 保留(设为0)
• Bit 3-0端点号 (1-15)
3bmAttributes1端点的属性。主要定义传输类型
• Bit 1-0传输类型
00: 控制传输
01: 等时传输
10: 批量传输
11: 中断传输
• Bit 7-2: 其他属性,取决于传输类型(尤其是等时传输)。
4-5wMaxPacketSize2端点支持的最大数据包大小。这是单次传输能承载的最大字节数。对于高速设备,这个字段有更复杂的编码。
6bInterval1轮询间隔。主机检查该端点是否有数据的时间间隔。单位是帧/微帧(1ms/125μs)。
• 对中断/等时端点:值越小,频率越高(如 0x01 表示每1ms轮询一次)。
• 对批量/控制端点:忽略。

示例:

USB键盘(中断IN端点)

原始数据:07 05 81 03 08 00 0A

偏移字段解释
0bLength07描述符长度:7字节。
1bDescriptorType05描述符类型:端点描述符。
2bEndpointAddress81端点地址1000 0001 → 端点 1 IN
3bmAttributes03属性0000 0011 → 传输类型 = 11 (中断传输)
4-5wMaxPacketSize08 00最大包大小0x0008 = 8 字节。一个键盘报告通常就是8字节。
6bInterval0A轮询间隔0x0A (10) → 10ms。主机每10ms检查一次键盘是否有新数据。

6、字符串描述符

字符串描述是可选的可读文本信息,用于向用户和开发者提供设备、制造商、产品型号等的友好名称。它不是设备运行所必需的。

字符串描述符的结构相对灵活,其长度取决于字符串的字符数量。

字段偏移字段名长度(字节)描述
0bLength1描述符本身的长度。值为 2 + (2 * N),其中 N 是字符串的字符数。
1bDescriptorType1描述符类型。固定为 3 (0x03),代表这是一个“字符串描述符”。
2, 4, ...bStringbLength - 2字符串本身。以 UNICODE (UTF-16LE) 格式存储的字符串。

特殊字符串索引0:

索引0保留给一个特殊的字符串描述符,它包含语言标识符的数组,用于告知主机设备支持哪些语言的字符串。

示例:

示例:0x0a,0x03,'a',0x00,'b',0x00,'c',0x00,'d',0x00

0x0a:描述符长度 ,有10个字符

0x03:描述符类型为字符串描述符

‘a',0x00:UNICODE 字符’a‘

............

7、HID类报表描述符

简化的鼠标报告描述符例子:

这个描述符告诉主机:我将发送一个包含3个按钮(各占1位)和两个8位有符号整数(X位移和Y位移)的报告

//这是一个简化的逻辑表示,并非原始字节
USAGE_PAGE (Generic Desktop)   05 01     //这是一个桌面控制设备
USAGE (Mouse)  09 02                     //具体来说,是个鼠标
COLLECTION (Application)  A1 01          //开始一个应用集合
    USAGE (Pointer)  09 01               //这是一个指针设备
    COLLECTION (Physical)  A1 00          //开始一个物理集合
        USAGE_PAGE (Buttons)  05 09      //接下来描述按钮
        USAGE_MINIMUM (1)  19 01
        USAGE_MAXIMUM (3)  29 03        //我有三个按钮,编号1到3
        LOGICAL_MINIMUM (0) 15 00
        LOGICAL_MAXIMUM (1) 25 01        //按钮的值:0(表示松开)  1(表示按下)
        REPORT COUNT (3)   95 03         //报告中有3个按钮字段
        REPORT_SIZE (1)    75 01         //每个按钮字段占1位
        INPUT (Data,Variable,Absolute)  81 02  //这是输入数据

        REPORT_COUNT (1)  75 01      //接下来是1个字段.....
        REPORT_SIZE (5)   95 05     //...占位5位(填充,使字节对齐)
        INPUT (Constat)   81 03     //这是常量(填充为,主机忽略)

        USAGE_PAGE (Generic Desktop) 05 01  //切换回通用桌面用法页
        USAGE (X)  09 30      //X位移
        USAGE (Y)  09 31      //Y位移
        LOGICAL_MINIMUM (-127) 15 81
        LOGICAL_MAXIMUM (127)  25 7F     //位移范围是-127到127
        REPORT_SIZE (8)   75 08           //每个位移占8位(1字节)
        REPORT_COUNT (2)  95 02           //有2个这样的字段(X和Y)
        INPUT(Data,Variable,Relative) 81 06   //这是输入数据,值是相对的
    END_COLLECTION   C0 //结束物理集合

    COLLECTION (Physical)    A1 00 //垂直滚轮
        USAGE_PAGE (Generic Desktop Controls) 05 01
        USAGE (Wheel) 09 38 //
        REPORT_SIZE (8)   75 08           //每个位移占8位(1字节)
        REPORT_COUNT (1)  95 02           //有1个这样的字段()
        LOGICAL_MINIMUM (-127) 15 81
        LOGICAL_MAXIMUM (127)  25 7F     //位移范围是-127到127
        INPUT(Data,Variable,Relative) 81 06   //这是输入数据,值是相对的
     END_COLLECTION   C0 //结束物理集合
 END_COLLECTION    C0    //结束应用集合

报告数据示例:

uint8_t report[4] = {
    0x01;      //字节0:左键按下(00000001)
    0x05;      //字节1:X = +5
    0xfd;      //字节2:Y = -3 (0xfd = -1 的补码)
    0xff       //字节3:滚轮 = -1 (0xff = -1 的补码)
}

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值