4. 蓝牙子系统与HID的接口:BlueZ协议栈、HCI层、L2CAP层、HID over GATT

在嵌入式Linux系统中,蓝牙HID设备的驱动开发核心在于理解蓝牙协议栈的分层架构以及HID数据在各层之间的流转路径。本章将深入剖析BlueZ协议栈的层次结构,重点讲解HCI、L2CAP以及HID over GATT这三个关键接口,为后续的设备树配置与数据收发测试奠定理论基础。

4.1 BlueZ协议栈整体架构

BlueZ是Linux官方蓝牙协议栈,采用分层设计,从内核空间到用户空间,每一层都承担着特定的协议处理职责。理解其架构是进行HID驱动开发的前提。

BlueZ 协议栈分层架构 用户空间 (User Space) bluetoothd (核心守护进程) | hcitool | gatttool | bluetoothctl HID 应用层 (如蓝牙鼠标/键盘驱动用户态部分) 内核空间 (Kernel Space) L2CAP 层 | RFCOMM 层 | HIDP 层 SMP (安全管理协议) | ATT 层 HCI 层 (Host Controller Interface) HCI 命令 | HCI 事件 | HCI 数据包 (ACL/SCO) 固件与硬件 (Firmware & Hardware) 蓝牙控制器 (UART/USB/SDIO 接口) 射频 (RF) | 基带 (Baseband) | 链路管理 (LM) HID 驱动开发主要关注:HCI 层、L2CAP 层以及 HID over GATT 协议

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层传递给上层协议。
开发提示: 在调试HID设备时,使用 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通道交换报告数据。

L2CAP 通道与 HIDP 协议栈 HID 应用 (鼠标/键盘) HIDP (HID Profile) L2CAP 层 控制通道 (PSM=0x0011) | 中断通道 (PSM=0x0013) HCI 层 (ACL 数据包) HID 控制通道用于发送/接收 Set_Report、Get_Report 等管理命令;中断通道用于实时传输输入报告

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 数据收发流程

  1. 发现服务:GATT客户端(主机)发现HID Service (0x1812)。
  2. 读取报告映射:读取Report Map特征,获取HID报告描述符,解析报告格式。
  3. 配置通知:在Report特征上启用CCCD(Client Characteristic Configuration Descriptor),使能通知。
  4. 接收数据:HID设备通过Notify方式发送输入报告,主机在回调中接收。
  5. 发送数据:主机通过Write命令向Report特征写入输出报告(如键盘LED状态)。
HID over GATT 数据收发流程 GATT 客户端 (主机/Computer) GATT 服务器 (HID 设备) ① 发现 HID Service (0x1812) ② 读取 Report Map (0x2A4B) ③ 配置 Report 特征 CCCD (启用通知) ④ 接收 Notify (输入报告) ⑤ 发送 Write (输出报告/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
注意事项: 在开发BLE HID设备时,不要直接操作HCI层来发送HID报告。正确的做法是通过BlueZ的GATT API(如D-Bus接口或内核的HID over GATT驱动)来注册服务和特征。直接操作HCI层会绕过GATT协议,导致兼容性问题。

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层 → 蓝牙控制器发送。
关键点: 在设备树中配置蓝牙HID设备时,通常不需要为HID over GATT单独添加节点。蓝牙控制器节点(如 serial 或 usb)使能后,BlueZ会自动处理GATT服务发现。但如果需要强制指定HID传输参数(如连接间隔),可以在蓝牙控制器节点中添加 max-connection-interval 等属性。

4.7 本章小结

本章详细介绍了蓝牙HID驱动开发中涉及的三个核心接口:

  • HCI层:作为主机与控制器之间的命令/数据通道,是调试和底层控制的基础。
  • L2CAP层:提供多路复用和通道管理,经典蓝牙HID通过PSM=0x0011和0x0013建立控制与中断通道。
  • HID over GATT:BLE HID的标准实现,利用GATT服务/特征模型,简化了数据收发流程。