3、蓝牙核心数据结构:hci_dev结构体、hci_conn结构体、hci_cb回调机制

好,咱们今天来啃三块硬骨头。这三块东西,说白了就是蓝牙驱动的骨架和血脉。你搞懂了它们,写驱动的时候心里就有底了。我当年刚接触蓝牙协议栈时,对着这些结构体看了三天,才慢慢摸出门道来。

3.1 hci_dev:蓝牙控制器的“身份证”

hci_dev 这个结构体,你可以把它理解成蓝牙控制器的完整档案。每个蓝牙芯片,无论是 USB 的还是 UART 的,在内核里都会对应一个 hci_dev 实例。

它长什么样?我挑几个最关键的字段给你看:

struct hci_dev {
    struct list_head list;          // 链表节点,所有hci_dev串在一起
    struct mutex    lock;           // 互斥锁,保护结构体不被乱改
    char            name[8];        // 设备名,比如"hci0"
    struct device   *parent;        // 父设备,指向实际的硬件设备
    __u8            bus;            // 总线类型:USB、UART、SDIO等
    __u8            dev_type;       // 设备类型:BR/EDR还是LE
    bdaddr_t        bdaddr;         // 蓝牙地址,每个设备唯一的MAC
    __u8            dev_name[248];  // 本地设备名称
    __u8            features[8];    // 支持的特性集
    __u16           manufacturer;   // 制造商ID
    __u8            hci_ver;        // HCI规范版本
    __u16           hci_rev;        // HCI修订版本
    __u8            lmp_ver;        // LMP版本
    __u16           lmp_subver;     // LMP子版本
    
    // 发送和接收队列
    struct sk_buff_head rx_q;       // 接收队列
    struct sk_buff_head raw_q;      // 原始数据队列
    struct sk_buff_head cmd_q;      // 命令队列
    
    // 连接管理
    struct list_head conn_list;     // 所有连接的链表
    __u16           conn_hash[16];  // 连接哈希表,快速查找
    
    // 回调函数
    int (*open)(struct hci_dev *hdev);
    int (*close)(struct hci_dev *hdev);
    int (*flush)(struct hci_dev *hdev);
    int (*send)(struct hci_dev *hdev, struct sk_buff *skb);
};

核心要点:每个蓝牙控制器在内核中只有一个 hci_dev 实例。它贯穿了整个蓝牙驱动的生命周期——从注册、初始化、运行到卸载。

我记得有一次调试一个 USB 蓝牙适配器,死活注册不上。后来发现是 open 回调里没有正确初始化 USB 端点。嗯,这种问题排查起来特别费劲,因为错误信息往往很模糊。

3.2 hci_conn:连接的“户口本”

如果说 hci_dev 是控制器本身,那 hci_conn 就是控制器上建立的每一条连接。一个蓝牙耳机连上来,就会创建一个 hci_conn

来看看它的核心字段:

struct hci_conn {
    struct list_head list;          // 链表节点,挂在hci_dev的conn_list上
    struct hci_dev   *hdev;         // 所属的控制器
    bdaddr_t         dst;           // 对端设备地址
    __u8             dst_type;      // 地址类型:公开地址还是随机地址
    __u16            handle;        // 连接句柄,唯一标识这条连接
    __u16            state;         // 连接状态:OPEN、CLOSED、CONNECTING等
    __u8             link_mode;     // 链路模式
    __u8             enc_key_size;  // 加密密钥长度
    __u8             key_type;      // 密钥类型
    
    // ACL连接相关
    __u16            pkt_type;      // 包类型
    __u16            tx_len;        // 发送缓冲区长度
    struct sk_buff_head data_q;     // 数据队列
    
    // SCO/eSCO连接相关
    __u16            sco_tx_len;    // SCO发送长度
    __u8             sco_mode;      // SCO模式
    
    // 定时器和回调
    struct timer_list disc_timer;   // 断开连接定时器
    struct timer_list idle_timer;   // 空闲定时器
    struct work_struct work;        // 工作队列
    
    // 连接建立回调
    void (*connect_cfm_cb)(struct hci_conn *conn, __u8 status);
    void (*security_cfm_cb)(struct hci_conn *conn, __u8 status);
    void (*disconn_cfm_cb)(struct hci_conn *conn, __u8 reason);
};

个人经验:我建议你在调试连接问题时,先打印 handlestate 这两个字段。它们能告诉你连接是否真的建立起来了,以及当前处于什么阶段。我曾经花了一整天查一个断连问题,最后发现是 disc_timer 超时时间设得太短了。

你想想看,一个蓝牙耳机同时连手机和电脑,那就会有两个 hci_conn 实例,分别挂在各自控制器的 conn_list 上。每个连接都有自己的状态机,从 CONNECTINGOPEN,再到 DISCONNECTING

3.3 hci_cb:回调机制的“总控开关”

hci_cb 是个全局结构体,它定义了一组回调函数。这些回调是协议栈和驱动之间的桥梁。当底层硬件有事件发生时,驱动通过回调通知上层协议栈。

struct hci_cb {
    struct list_head list;
    char *name;
    
    // 连接相关回调
    void (*connect_cfm)(struct hci_conn *conn, __u8 status);
    void (*disconn_cfm)(struct hci_conn *conn, __u8 reason);
    
    // 安全相关回调
    void (*security_cfm)(struct hci_conn *conn, __u8 status, __u8 encrypt);
    
    // 密钥相关回调
    void (*key_change_cfm)(struct hci_conn *conn, __u8 status);
    
    // 角色切换回调
    void (*role_switch_cfm)(struct hci_conn *conn, __u8 status, __u8 role);
};

避坑指南:我曾经在注册回调时忘记检查 hci_cbconnect_cfm 回调,导致连接建立时回调被调用了两次,状态机直接乱掉了。所以,注册回调前一定要检查是否已被占用。

回调机制的工作流程其实很简单:

  1. 上层协议栈(比如 L2CAP、SMP)调用 hci_register_cb() 注册回调
  2. 底层驱动在事件发生时(比如收到连接完成事件),调用对应的回调函数
  3. 回调函数里,协议栈根据事件类型做进一步处理

说白了,这就是个观察者模式。驱动是事件源,协议栈是观察者。事件来了,驱动喊一嗓子,协议栈们各自处理。

3.4 三者如何协同工作?

我画个简单的流程给你看:

// 1. 驱动初始化时,创建hci_dev
struct hci_dev *hdev = hci_alloc_dev();
hdev->bus = HCI_USB;
hdev->open = usb_open;
hdev->close = usb_close;
hdev->send = usb_send;

// 2. 注册到协议栈
hci_register_dev(hdev);

// 3. 当有设备连接时,创建hci_conn
struct hci_conn *conn = hci_conn_add(hdev, ACL_LINK, &bdaddr, ACL_LINK);
conn->state = BT_CONNECTED;

// 4. 连接建立后,触发回调
if (hdev->connect_cfm_cb)
    hdev->connect_cfm_cb(conn, 0x00);

// 5. 协议栈收到回调,做进一步处理
void l2cap_connect_cfm(struct hci_conn *conn, __u8 status) {
    if (status == 0x00) {
        // 连接成功,开始L2CAP层处理
        l2cap_conn_add(conn);
    }
}

关键理解:hci_dev 是控制器,hci_conn 是连接,hci_cb 是通知机制。三者缺一不可,构成了蓝牙驱动的核心骨架。

我个人习惯在调试时,把这三个结构体的关键字段打印出来。比如:

// 调试打印示例
printk("hci_dev: name=%s, bus=%d, state=%d\n", 
       hdev->name, hdev->bus, hdev->dev_type);
printk("hci_conn: handle=0x%04x, state=%d, dst=%pMR\n",
       conn->handle, conn->state, &conn->dst);
printk("hci_cb: connect_cfm=%p, disconn_cfm=%p\n",
       hdev->connect_cfm_cb, hdev->disconn_cfm_cb);

嗯,今天就先讲到这里。这三个结构体你得多看几遍源码,最好自己动手写个简单的驱动,注册一个 hci_dev,然后看看它怎么和协议栈交互。下一章我们讲蓝牙驱动的初始化流程,到时候你会看到这些结构体是怎么被创建和串联起来的。

课后练习:去内核源码里找到 net/bluetooth/hci_core.c,看看 hci_register_dev() 函数是怎么初始化 hci_dev 的。重点关注 conn_listhci_cb 的初始化过程。