3. 内核蓝牙驱动模型

Linux 内核蓝牙子系统采用分层架构设计,将蓝牙协议栈与底层硬件解耦。理解驱动模型是调试 HCI 日志和定位硬件问题的前提。本章聚焦于 HCI 设备驱动、传输层驱动(UART/USB/PCI)以及驱动注册与回调机制。

3.1 蓝牙驱动分层架构

蓝牙驱动在 Linux 内核中主要分为三层:

  • HCI 核心层:位于 net/bluetooth/,提供通用 HCI 命令/事件处理、连接管理、SMP 等协议实现。
  • HCI 设备驱动层:位于 drivers/bluetooth/,负责与具体蓝牙芯片交互,实现 HCI 传输接口。
  • 传输层驱动:位于 drivers/bluetooth/ 或 drivers/tty/、drivers/usb/,提供 UART、USB、PCI 等物理总线适配。
关键概念: HCI 设备驱动通过注册 struct hci_dev 结构体与核心层通信,传输层驱动则通过 struct hci_transport_ops 或直接操作 tty/usb 接口实现数据收发。
蓝牙驱动分层架构图 蓝牙驱动分层架构 用户空间 (BlueZ / bluetoothd) 内核 HCI 核心层 (net/bluetooth/) HCI 设备驱动层 (drivers/bluetooth/) 传输层驱动 (UART / USB / PCI / SDIO) 蓝牙硬件 (UART/USB/PCI 设备)

3.2 HCI 设备驱动核心结构

每个蓝牙控制器在内核中对应一个 struct hci_dev 实例。驱动开发的核心工作是填充该结构体并注册到 HCI 核心。

字段/操作 类型 说明
name char[] 设备名称,如 hci0
bus __u8 总线类型:HCI_UART、HCI_USB、HCI_PCI 等
open int (*open)(struct hci_dev *) 打开设备,初始化硬件
close int (*close)(struct hci_dev *) 关闭设备,释放资源
flush int (*flush)(struct hci_dev *) 清空待发送数据
send int (*send)(struct hci_dev *, struct sk_buff *) 发送 HCI 数据帧
recv int (*recv)(struct hci_dev *, struct sk_buff *) 接收 HCI 数据帧(通常由传输层调用)
调试提示: 在 send 和 recv 回调中添加 bt_dev_dbg() 打印,可以精确追踪每个 HCI 数据包的收发路径,是定位驱动层丢包或数据损坏的首选方法。

3.3 传输层驱动:UART / USB / PCI

传输层驱动负责在物理总线上收发 HCI 数据帧。不同总线有各自的适配方式。

3.3.1 UART 传输层

UART 传输层通过 tty 驱动与蓝牙芯片通信。核心数据结构为 struct hci_uart_proto,每个协议(如 H4、BCSP、3-Wire)需实现该接口。

struct hci_uart_proto {
    unsigned int id;          // 协议 ID
    const char *name;         // 协议名称
    int (*open)(struct hci_uart *hu);
    int (*close)(struct hci_uart *hu);
    int (*recv)(struct hci_uart *hu, const void *data, int len);
    int (*enqueue)(struct hci_uart *hu, struct sk_buff *skb);
    struct sk_buff *(*dequeue)(struct hci_uart *hu);
};

UART 驱动通过 hci_uart_register_proto() 注册协议,并在 tty 线路规程(line discipline)中调用。

3.3.2 USB 传输层

USB 蓝牙适配器使用 struct usb_device_id 匹配,通过 usb_fill_bulk_urb() 创建 URB 进行批量传输。典型实现位于 drivers/bluetooth/btusb.c。

USB 端点类型 方向 用途
Bulk OUT 主机 → 设备 发送 HCI 命令和数据
Bulk IN 设备 → 主机 接收 HCI 事件和数据
Interrupt IN 设备 → 主机 接收 HCI 事件(部分芯片)

3.3.3 PCI 传输层

PCI 蓝牙控制器(如 Intel AX200 中的蓝牙模块)通过 struct pci_driver 注册,使用 MMIO 或 DMA 进行数据交换。驱动需实现 probe、remove 以及中断处理函数。

传输层驱动数据流图 传输层驱动数据流 HCI 核心层 HCI 设备驱动 UART 传输层 USB 传输层 PCI 传输层 UART 蓝牙芯片 USB 蓝牙适配器 PCI 蓝牙模块

3.4 驱动注册与回调函数机制

驱动注册是蓝牙设备被内核识别的入口。以 USB 蓝牙驱动为例,注册流程如下:

  1. 模块初始化:调用 usb_register() 注册 struct usb_driver。
  2. probe 回调:当 USB 设备插入且 VID/PID 匹配时,内核调用 probe 函数。
  3. HCI 设备分配:调用 hci_alloc_dev() 分配 struct hci_dev。
  4. 设置回调:填充 open、close、send 等操作函数。
  5. 注册 HCI 设备:调用 hci_register_dev() 将设备加入 HCI 核心。
static int btusb_probe(struct usb_interface *intf,
                       const struct usb_device_id *id)
{
    struct hci_dev *hdev;
    // 1. 分配 HCI 设备
    hdev = hci_alloc_dev();
    if (!hdev)
        return -ENOMEM;

    // 2. 设置总线类型
    hdev->bus = HCI_USB;

    // 3. 绑定回调函数
    hdev->open  = btusb_open;
    hdev->close = btusb_close;
    hdev->send  = btusb_send_frame;

    // 4. 注册到 HCI 核心
    return hci_register_dev(hdev);
}
常见错误: 在 probe 中未正确初始化硬件状态就调用 hci_register_dev(),会导致 HCI 核心在 open 回调中访问未就绪的资源,引发内核崩溃或设备无响应。

3.5 回调函数执行流程

回调函数是 HCI 核心与驱动之间的契约。以数据发送为例,典型调用链如下:

步骤 调用者 函数 说明
1 用户空间 / 协议栈 hci_send_frame() 构造 sk_buff,调用驱动 send
2 HCI 核心 hdev->send(hdev, skb) 调用驱动注册的 send 回调
3 传输层驱动 btusb_send_frame() 将 skb 数据通过 USB URB 发送
4 USB 核心 usb_submit_urb() 提交 URB 到硬件

接收路径则相反:硬件中断 → 传输层接收 → 调用 hci_recv_frame() → HCI 核心处理。

调试要点: 在 send 回调入口和 recv 回调出口添加 print_hex_dump() 打印 skb 数据,可以快速判断数据是否在传输层被篡改或截断。

3.6 驱动模型调试技巧

  • 查看已注册 HCI 设备:ls /sys/class/bluetooth/ 或 hciconfig -a。
  • 检查驱动 probe 是否成功:dmesg | grep -i bluetooth 查看内核日志。
  • 验证回调是否被调用:在回调函数中添加 bt_dev_info(hdev, "send callback invoked")。
  • 使用 ftrace 跟踪:echo function > /sys/kernel/debug/tracing/current_tracer 并过滤 btusb_* 函数。
实战建议: 在开发新蓝牙芯片驱动时,先实现一个最小化的 open/close/send/recv 回调,用 hcitool cmd 发送测试命令,验证双向数据通路是否正常,再逐步添加高级功能。