4. 蓝牙子系统与HID的接口:BlueZ协议栈、HCI层、L2CAP层、HID over GATT
在嵌入式Linux系统中,蓝牙HID设备的驱动开发核心在于理解蓝牙协议栈的分层架构以及HID数据在各层之间的流转路径。本章将深入剖析BlueZ协议栈的层次结构,重点讲解HCI、L2CAP以及HID over GATT这三个关键接口,为后续的设备树配置与数据收发测试奠定理论基础。
4.1 BlueZ协议栈整体架构
BlueZ是Linux官方蓝牙协议栈,采用分层设计,从内核空间到用户空间,每一层都承担着特定的协议处理职责。理解其架构是进行HID驱动开发的前提。
4.2 HCI层:主机与控制器之间的桥梁
HCI(Host Controller Interface)是蓝牙协议栈中连接主机(CPU侧)与蓝牙控制器(芯片侧)的关键接口。它定义了命令、事件和数据包的传输规范。
4.2.1 HCI数据包类型
| 包类型 | 方向 | 用途 | 示例 |
|---|---|---|---|
| HCI Command | 主机 → 控制器 | 发送控制指令(如扫描、连接) | HCI_LE_Create_Connection |
| HCI Event | 控制器 → 主机 | 上报状态变化或事件 | HCI_Connection_Complete |
| HCI ACL Data | 双向 | 传输面向连接的数据(L2CAP承载) | HID报告数据 |
| HCI SCO Data | 双向 | 传输同步面向连接的数据(语音) | 音频流 |
4.2.2 HCI层在HID驱动中的角色
- 设备发现与连接:通过HCI命令发起扫描,建立ACL连接。
- 参数配置:设置连接间隔、延迟、超时等参数,直接影响HID设备的响应性能。
- 数据收发:HID报告数据封装在ACL数据包中,通过HCI层传递给上层协议。
hcidump 或 btmon 工具抓取HCI日志,可以直观地看到HCI命令与事件的交互过程,是定位连接问题的第一道防线。
4.3 L2CAP层:逻辑链路控制与适配
L2CAP(Logical Link Control and Adaptation Protocol)位于HCI层之上,为上层协议提供多路复用、分段重组和服务质量(QoS)管理。对于HID设备,L2CAP层负责建立专用的HID控制通道和中断通道。
4.3.1 L2CAP通道类型
| 通道类型 | CID (Channel ID) | 用途 | HID相关 |
|---|---|---|---|
| 面向连接通道 | 动态分配 (0x0040 - 0xFFFF) | 承载上层协议数据 | HID控制通道 (PSM=0x0011) |
| 面向连接通道 | 动态分配 | 承载中断数据 | HID中断通道 (PSM=0x0013) |
| 信令通道 | 0x0001 | L2CAP层管理(连接请求/响应) | 建立HID通道前的握手 |
4.3.2 L2CAP与HIDP的协作
在经典蓝牙(BR/EDR)模式下,HID Profile(HIDP)直接运行在L2CAP之上。HIDP定义了HID设备如何通过L2CAP通道交换报告数据。
4.4 HID over GATT:低功耗蓝牙的HID实现
随着BLE(Bluetooth Low Energy)的普及,HID over GATT(HOGP)成为蓝牙HID设备的主流实现方式。它利用GATT(Generic Attribute Profile)协议,将HID报告定义为服务(Service)和特征(Characteristic)。
4.4.1 HID over GATT 服务结构
| 服务/特征 | UUID | 属性 | 说明 |
|---|---|---|---|
| HID Service | 0x1812 | Primary Service | HID设备的核心服务 |
| Protocol Mode | 0x2A4E | Read / Write | 设置协议模式(Boot/Report) |
| Report Map | 0x2A4B | Read | HID报告描述符 |
| Report | 0x2A4D | Read / Write / Notify | 具体的HID报告数据 |
| Boot Keyboard Input Report | 0x2A22 | Read / Notify | Boot模式键盘输入 |
| Boot Mouse Input Report | 0x2A33 | Read / Notify | Boot模式鼠标输入 |
4.4.2 数据收发流程
- 发现服务:GATT客户端(主机)发现HID Service (0x1812)。
- 读取报告映射:读取Report Map特征,获取HID报告描述符,解析报告格式。
- 配置通知:在Report特征上启用CCCD(Client Characteristic Configuration Descriptor),使能通知。
- 接收数据:HID设备通过Notify方式发送输入报告,主机在回调中接收。
- 发送数据:主机通过Write命令向Report特征写入输出报告(如键盘LED状态)。
4.5 三种接口的对比与选择
| 特性 | HCI 层 | L2CAP 层 | HID over GATT |
|---|---|---|---|
| 协议位置 | 最底层接口 | 中间层适配 | 应用层Profile |
| 适用场景 | 控制器调试、底层驱动 | 经典蓝牙HID (BR/EDR) | 低功耗蓝牙HID (BLE) |
| 数据封装 | HCI数据包 | L2CAP帧 (含PSM/CID) | ATT PDU (GATT操作) |
| 开发复杂度 | 高(需处理字节流) | 中(需管理通道) | 低(服务/特征模型) |
| Linux内核接口 | /dev/hciX 或 hci_sock |
l2cap_sock (PF_BLUETOOTH) |
ioctl + BlueZ D-Bus API |
4.6 内核中的HID over GATT驱动实现
Linux内核从4.x版本开始,引入了原生的HID over GATT驱动(drivers/hid/hid-google-hammer.c 和 drivers/bluetooth/hidp/hidp_core.c 相关实现)。该驱动在蓝牙子系统中注册为一个HID传输层,使得上层HID驱动无需关心底层是USB、I2C还是蓝牙。
4.6.1 关键数据结构
/* 内核中 HID over GATT 设备描述 */
struct hogp_device {
struct hci_dev *hdev; /* 关联的蓝牙控制器 */
struct l2cap_chan *chan; /* L2CAP 通道 */
struct hid_device *hid; /* HID 核心设备 */
struct work_struct work; /* 工作队列 */
__u8 protocol; /* 协议模式 (Boot/Report) */
};
/* HID 报告回调注册 */
int hogp_register_report(struct hogp_device *hogp,
u8 report_type,
u8 report_id,
u8 *data, size_t len);
4.6.2 数据流路径
- 输入路径:蓝牙控制器接收数据 → HCI层 → L2CAP层 → HID over GATT驱动 → HID核心层 → HID设备驱动 → 用户空间(通过evdev)。
- 输出路径:用户空间写入(如LED设置) → HID核心层 → HID over GATT驱动 → L2CAP层 → HCI层 → 蓝牙控制器发送。
serial 或 usb)使能后,BlueZ会自动处理GATT服务发现。但如果需要强制指定HID传输参数(如连接间隔),可以在蓝牙控制器节点中添加 max-connection-interval 等属性。
4.7 本章小结
本章详细介绍了蓝牙HID驱动开发中涉及的三个核心接口:
- HCI层:作为主机与控制器之间的命令/数据通道,是调试和底层控制的基础。
- L2CAP层:提供多路复用和通道管理,经典蓝牙HID通过PSM=0x0011和0x0013建立控制与中断通道。
- HID over GATT:BLE HID的标准实现,利用GATT服务/特征模型,简化了数据收发流程。