嵌入式 Linux 蓝牙框架完整篇:从 HCI、L2CAP 到BlueZ 用户态

嵌入式产品里蓝牙常和 WiFi 共用一颗 combo 芯片。现象却很碎:能扫到手机、连不上;A2DP 有声无控;BLE 广播正常但 GATT 读失败。根因往往不在「蓝牙协议本身」,而在 Linux BlueZ 分层 :硬件/固件 → HCI 驱动 → 内核协议(L2CAP/RFCOMM/SCO)→ 用户态 bluetoothd / D-Bus。

本文把 嵌入式 Linux 蓝牙栈 从芯片到应用串清楚,覆盖经典蓝牙与 BLE、HCI 命令事件、套接字类型、mgmt、音频与排障,读完能对照 btmon 与内核路径定位问题落在哪一层。

源码锚点

路径 作用
include/net/bluetooth/hci_core.h struct hci_devhci_alloc_devhci_register_dev
include/net/bluetooth/hci.h HCI 命令/事件、quirk
include/net/bluetooth/bluetooth.h bt_sock、协议注册
include/net/bluetooth/l2cap.h L2CAP 信道
include/net/bluetooth/rfcomm.h 串口仿真 RFCOMM
include/net/bluetooth/sco.h 同步语音链路
include/net/bluetooth/mgmt.h 用户态管理接口(mgmt)
net/bluetooth/ BlueZ 内核:hci_core、l2cap、smp 等
include/linux/rfkill.h 射频开关(与 WiFi 共用)

控制器注册(概念):

c 复制代码
/* include/net/bluetooth/hci_core.h */
struct hci_dev *hci_alloc_dev(void);
int hci_register_dev(struct hci_dev *hdev);

驱动在 probe 里分配 hci_dev,填 open/close/send 等总线回调,设必要 quirkhci.h),再 hci_register_dev。之后内核出现 hci0

分层总览:别把 HCI 和「蓝牙应用」混为一谈

#mermaid-svg-2jahqZryaOf8u6II{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-2jahqZryaOf8u6II .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-2jahqZryaOf8u6II .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-2jahqZryaOf8u6II .error-icon{fill:#552222;}#mermaid-svg-2jahqZryaOf8u6II .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-2jahqZryaOf8u6II .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-2jahqZryaOf8u6II .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-2jahqZryaOf8u6II .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-2jahqZryaOf8u6II .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-2jahqZryaOf8u6II .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-2jahqZryaOf8u6II .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-2jahqZryaOf8u6II .marker{fill:#333333;stroke:#333333;}#mermaid-svg-2jahqZryaOf8u6II .marker.cross{stroke:#333333;}#mermaid-svg-2jahqZryaOf8u6II svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-2jahqZryaOf8u6II p{margin:0;}#mermaid-svg-2jahqZryaOf8u6II .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-2jahqZryaOf8u6II .cluster-label text{fill:#333;}#mermaid-svg-2jahqZryaOf8u6II .cluster-label span{color:#333;}#mermaid-svg-2jahqZryaOf8u6II .cluster-label span p{background-color:transparent;}#mermaid-svg-2jahqZryaOf8u6II .label text,#mermaid-svg-2jahqZryaOf8u6II span{fill:#333;color:#333;}#mermaid-svg-2jahqZryaOf8u6II .node rect,#mermaid-svg-2jahqZryaOf8u6II .node circle,#mermaid-svg-2jahqZryaOf8u6II .node ellipse,#mermaid-svg-2jahqZryaOf8u6II .node polygon,#mermaid-svg-2jahqZryaOf8u6II .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-2jahqZryaOf8u6II .rough-node .label text,#mermaid-svg-2jahqZryaOf8u6II .node .label text,#mermaid-svg-2jahqZryaOf8u6II .image-shape .label,#mermaid-svg-2jahqZryaOf8u6II .icon-shape .label{text-anchor:middle;}#mermaid-svg-2jahqZryaOf8u6II .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-2jahqZryaOf8u6II .rough-node .label,#mermaid-svg-2jahqZryaOf8u6II .node .label,#mermaid-svg-2jahqZryaOf8u6II .image-shape .label,#mermaid-svg-2jahqZryaOf8u6II .icon-shape .label{text-align:center;}#mermaid-svg-2jahqZryaOf8u6II .node.clickable{cursor:pointer;}#mermaid-svg-2jahqZryaOf8u6II .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-2jahqZryaOf8u6II .arrowheadPath{fill:#333333;}#mermaid-svg-2jahqZryaOf8u6II .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-2jahqZryaOf8u6II .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-2jahqZryaOf8u6II .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-2jahqZryaOf8u6II .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-2jahqZryaOf8u6II .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-2jahqZryaOf8u6II .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-2jahqZryaOf8u6II .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-2jahqZryaOf8u6II .cluster text{fill:#333;}#mermaid-svg-2jahqZryaOf8u6II .cluster span{color:#333;}#mermaid-svg-2jahqZryaOf8u6II div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-2jahqZryaOf8u6II .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-2jahqZryaOf8u6II rect.text{fill:none;stroke-width:0;}#mermaid-svg-2jahqZryaOf8u6II .icon-shape,#mermaid-svg-2jahqZryaOf8u6II .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-2jahqZryaOf8u6II .icon-shape p,#mermaid-svg-2jahqZryaOf8u6II .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-2jahqZryaOf8u6II .icon-shape .label rect,#mermaid-svg-2jahqZryaOf8u6II .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-2jahqZryaOf8u6II .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-2jahqZryaOf8u6II .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-2jahqZryaOf8u6II :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 硬件侧
内核 BlueZ
用户态
bluetoothd / BlueZ
btmgmt / bluetoothctl
应用: GATT / A2DP / SPP
PulseAudio / PipeWire 音频
mgmt / HCI socket
HCI 核心 hci_core
L2CAP / SMP
RFCOMM / SCO / BNEP
HCI 驱动 USB/UART/SDIO
固件
蓝牙控制器芯片

HCI(Host Controller Interface) :主机(Linux)与控制器(芯片+固件)之间的标准命令/事件/ACL/SCO 数据通道。

Linux 侧「蓝牙驱动」多数是 把某总线收发适配成 HCI,真正 802.15 风格跳频在控制器固件里。

调用链

控制器上线

#mermaid-svg-RCWaPIq6uIvgpTqi{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-RCWaPIq6uIvgpTqi .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-RCWaPIq6uIvgpTqi .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-RCWaPIq6uIvgpTqi .error-icon{fill:#552222;}#mermaid-svg-RCWaPIq6uIvgpTqi .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-RCWaPIq6uIvgpTqi .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-RCWaPIq6uIvgpTqi .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-RCWaPIq6uIvgpTqi .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-RCWaPIq6uIvgpTqi .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-RCWaPIq6uIvgpTqi .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-RCWaPIq6uIvgpTqi .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-RCWaPIq6uIvgpTqi .marker{fill:#333333;stroke:#333333;}#mermaid-svg-RCWaPIq6uIvgpTqi .marker.cross{stroke:#333333;}#mermaid-svg-RCWaPIq6uIvgpTqi svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-RCWaPIq6uIvgpTqi p{margin:0;}#mermaid-svg-RCWaPIq6uIvgpTqi .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-RCWaPIq6uIvgpTqi .cluster-label text{fill:#333;}#mermaid-svg-RCWaPIq6uIvgpTqi .cluster-label span{color:#333;}#mermaid-svg-RCWaPIq6uIvgpTqi .cluster-label span p{background-color:transparent;}#mermaid-svg-RCWaPIq6uIvgpTqi .label text,#mermaid-svg-RCWaPIq6uIvgpTqi span{fill:#333;color:#333;}#mermaid-svg-RCWaPIq6uIvgpTqi .node rect,#mermaid-svg-RCWaPIq6uIvgpTqi .node circle,#mermaid-svg-RCWaPIq6uIvgpTqi .node ellipse,#mermaid-svg-RCWaPIq6uIvgpTqi .node polygon,#mermaid-svg-RCWaPIq6uIvgpTqi .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-RCWaPIq6uIvgpTqi .rough-node .label text,#mermaid-svg-RCWaPIq6uIvgpTqi .node .label text,#mermaid-svg-RCWaPIq6uIvgpTqi .image-shape .label,#mermaid-svg-RCWaPIq6uIvgpTqi .icon-shape .label{text-anchor:middle;}#mermaid-svg-RCWaPIq6uIvgpTqi .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-RCWaPIq6uIvgpTqi .rough-node .label,#mermaid-svg-RCWaPIq6uIvgpTqi .node .label,#mermaid-svg-RCWaPIq6uIvgpTqi .image-shape .label,#mermaid-svg-RCWaPIq6uIvgpTqi .icon-shape .label{text-align:center;}#mermaid-svg-RCWaPIq6uIvgpTqi .node.clickable{cursor:pointer;}#mermaid-svg-RCWaPIq6uIvgpTqi .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-RCWaPIq6uIvgpTqi .arrowheadPath{fill:#333333;}#mermaid-svg-RCWaPIq6uIvgpTqi .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-RCWaPIq6uIvgpTqi .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-RCWaPIq6uIvgpTqi .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-RCWaPIq6uIvgpTqi .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-RCWaPIq6uIvgpTqi .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-RCWaPIq6uIvgpTqi .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-RCWaPIq6uIvgpTqi .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-RCWaPIq6uIvgpTqi .cluster text{fill:#333;}#mermaid-svg-RCWaPIq6uIvgpTqi .cluster span{color:#333;}#mermaid-svg-RCWaPIq6uIvgpTqi div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-RCWaPIq6uIvgpTqi .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-RCWaPIq6uIvgpTqi rect.text{fill:none;stroke-width:0;}#mermaid-svg-RCWaPIq6uIvgpTqi .icon-shape,#mermaid-svg-RCWaPIq6uIvgpTqi .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-RCWaPIq6uIvgpTqi .icon-shape p,#mermaid-svg-RCWaPIq6uIvgpTqi .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-RCWaPIq6uIvgpTqi .icon-shape .label rect,#mermaid-svg-RCWaPIq6uIvgpTqi .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-RCWaPIq6uIvgpTqi .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-RCWaPIq6uIvgpTqi .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-RCWaPIq6uIvgpTqi :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 总线 probe: USB/UART/SDIO
hci_alloc_dev
设置 bus 回调 open/close/send
设置 quirk 如需
hci_register_dev
创建 hciX / 初始化命令
bluetoothd 通过 mgmt 管理

经典连接(示意:SPP / RFCOMM)

text 复制代码
应用 connect RFCOMM
  → 内核 RFCOMM → L2CAP → HCI ACL
      → 驱动 send → 控制器
反向:控制器事件/ACL → hci_recv_frame → 协议栈 → socket

BLE GATT(示意)

text 复制代码
用户态/bluetoothd
  → ATT over L2CAP (LE credit / fixed CID)
      → HCI LE ACL
          → 控制器链路层
安全:SMP 配对密钥;内核 smp 与用户态策略协作

重点知识

1. hci_dev:控制器在内核的实体

struct hci_devhci_core.h)保存:

  • 名称、总线类型、厂商特征
  • 命令队列、连接哈希、统计 hci_dev_stats
  • 回调:向控制器发帧、打开关闭传输

用户态看到的 hci0 对应一个已注册的 hci_dev

hciconfig(旧)/ btmgmt info / bluetoothctl list 都围绕它。

2. HCI 三种流量

类型 作用
Command / Event 主机下命令、控制器回事件(复位、查特性、建链)
ACL 异步数据(L2CAP 承载)
SCO / eSCO 同步语音(通话、部分 headset)

调试神器:btmon 抓 HCI 层,相当于蓝牙的 tcpdump。关联失败先看是命令超时、认证失败还是 ACL 断开。

3. 传输驱动(嵌入式最常见)

总线 典型场景 注意
USB USB 蓝牙 dongle、部分模组 电流、固件、reset
UART / H4 / H5 / BCSP 模组接 SoC UART 波特率、流控、串口 DMA
SDIO WiFi/BT combo 与 WiFi 共存、共享晶振/天线、固件组合

UART 蓝牙经典坑:波特率与固件约定不一致 → hci_register 后初始化命令超时。

Combo 芯片:WiFi 驱动与 BT 驱动加载顺序、共享管脚、rfkill 要一起看。

4. 协议栈:L2CAP 以上

#mermaid-svg-GyQDHk6QBo6Xv1Mq{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-GyQDHk6QBo6Xv1Mq .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-GyQDHk6QBo6Xv1Mq .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-GyQDHk6QBo6Xv1Mq .error-icon{fill:#552222;}#mermaid-svg-GyQDHk6QBo6Xv1Mq .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-GyQDHk6QBo6Xv1Mq .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-GyQDHk6QBo6Xv1Mq .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-GyQDHk6QBo6Xv1Mq .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-GyQDHk6QBo6Xv1Mq .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-GyQDHk6QBo6Xv1Mq .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-GyQDHk6QBo6Xv1Mq .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-GyQDHk6QBo6Xv1Mq .marker{fill:#333333;stroke:#333333;}#mermaid-svg-GyQDHk6QBo6Xv1Mq .marker.cross{stroke:#333333;}#mermaid-svg-GyQDHk6QBo6Xv1Mq svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-GyQDHk6QBo6Xv1Mq p{margin:0;}#mermaid-svg-GyQDHk6QBo6Xv1Mq .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-GyQDHk6QBo6Xv1Mq .cluster-label text{fill:#333;}#mermaid-svg-GyQDHk6QBo6Xv1Mq .cluster-label span{color:#333;}#mermaid-svg-GyQDHk6QBo6Xv1Mq .cluster-label span p{background-color:transparent;}#mermaid-svg-GyQDHk6QBo6Xv1Mq .label text,#mermaid-svg-GyQDHk6QBo6Xv1Mq span{fill:#333;color:#333;}#mermaid-svg-GyQDHk6QBo6Xv1Mq .node rect,#mermaid-svg-GyQDHk6QBo6Xv1Mq .node circle,#mermaid-svg-GyQDHk6QBo6Xv1Mq .node ellipse,#mermaid-svg-GyQDHk6QBo6Xv1Mq .node polygon,#mermaid-svg-GyQDHk6QBo6Xv1Mq .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-GyQDHk6QBo6Xv1Mq .rough-node .label text,#mermaid-svg-GyQDHk6QBo6Xv1Mq .node .label text,#mermaid-svg-GyQDHk6QBo6Xv1Mq .image-shape .label,#mermaid-svg-GyQDHk6QBo6Xv1Mq .icon-shape .label{text-anchor:middle;}#mermaid-svg-GyQDHk6QBo6Xv1Mq .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-GyQDHk6QBo6Xv1Mq .rough-node .label,#mermaid-svg-GyQDHk6QBo6Xv1Mq .node .label,#mermaid-svg-GyQDHk6QBo6Xv1Mq .image-shape .label,#mermaid-svg-GyQDHk6QBo6Xv1Mq .icon-shape .label{text-align:center;}#mermaid-svg-GyQDHk6QBo6Xv1Mq .node.clickable{cursor:pointer;}#mermaid-svg-GyQDHk6QBo6Xv1Mq .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-GyQDHk6QBo6Xv1Mq .arrowheadPath{fill:#333333;}#mermaid-svg-GyQDHk6QBo6Xv1Mq .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-GyQDHk6QBo6Xv1Mq .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-GyQDHk6QBo6Xv1Mq .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-GyQDHk6QBo6Xv1Mq .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-GyQDHk6QBo6Xv1Mq .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-GyQDHk6QBo6Xv1Mq .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-GyQDHk6QBo6Xv1Mq .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-GyQDHk6QBo6Xv1Mq .cluster text{fill:#333;}#mermaid-svg-GyQDHk6QBo6Xv1Mq .cluster span{color:#333;}#mermaid-svg-GyQDHk6QBo6Xv1Mq div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-GyQDHk6QBo6Xv1Mq .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-GyQDHk6QBo6Xv1Mq rect.text{fill:none;stroke-width:0;}#mermaid-svg-GyQDHk6QBo6Xv1Mq .icon-shape,#mermaid-svg-GyQDHk6QBo6Xv1Mq .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-GyQDHk6QBo6Xv1Mq .icon-shape p,#mermaid-svg-GyQDHk6QBo6Xv1Mq .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-GyQDHk6QBo6Xv1Mq .icon-shape .label rect,#mermaid-svg-GyQDHk6QBo6Xv1Mq .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-GyQDHk6QBo6Xv1Mq .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-GyQDHk6QBo6Xv1Mq .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-GyQDHk6QBo6Xv1Mq :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} HCI
L2CAP
ATT/GATT BLE
RFCOMM
BNEP 个人网
SMP 配对
串口应用
SCO
语音

  • L2CAP:信道复用、分片重组;BLE 上承载 ATT。
  • RFCOMM:仿串口,Android SPP、很多工控透传。
  • BNEP:蓝牙个人区域网(较少用于现代手机互联)。
  • SCO :语音;音频音乐更多走 A2DP(用户态配置 + 内核支持)。
  • SMP:LE 安全配对。

套接字:AF_BLUETOOTH + BTPROTO_L2CAP / RFCOMM / HCI / SCO 等(见 bluetooth.h 注册路径)。

5. 用户态 BlueZ

现代发行版:

  • bluetoothd :守护进程,经 D-Bus 暴露适配器/设备/GATT API。
  • bluetoothctl:交互式控制。
  • btmgmt:更贴近内核 mgmt 命令。

嵌入式裁剪根文件系统时缺 bluetoothd 或 D-Bus 策略,会出现「内核有 hci0,用户态扫不到」。

6. 经典蓝牙 vs BLE

经典 BR/EDR BLE
功耗 较高
典型 音频、SPP、HID 旧设备 传感器、Beacon、GATT
主机关注 RFCOMM/A2DP/SCO ATT/GATT、广播、连接间隔

同一控制器可双模;能力由 HCI Read Local Supported Features / LE features 事件报告。

7. 配对、绑定与权限

配对产生密钥,绑定后免重复输入。失败常见:

  • 双方 IO 能力不匹配(NoInputNoOutput vs DisplayYesNo)
  • Secure Connections / MITM 策略过严
  • 旧设备不支持 LE Secure Connections

内核 SMP + 用户态 agent(bluetoothctl agent)共同完成。产线常用「预绑定」或固定 PIN(安全性差,仅工控)。

8. 音频路径(嵌入式易踩坑)

  • HFP/HSP:通话,偏 SCO。
  • A2DP:音乐;编解码 SBC/AAC/aptX 取决于用户态与对端。
  • PulseAudio / PipeWire / ALSA 集成;内核只提供链路,策略与编解码在用户态

只有 hci0 没有音频框架插件 → 「能连耳机无声音」。

9. rfkill 与共存

rfkill list 中 Bluetooth 被 soft/hard block 会导致适配器 down。

WiFi/BT 共存:天线隔离、固件共存算法、同模组 SDIO 时序;WiFi 高吞吐时 BT 音频卡顿不一定是 BlueZ bug。

10. 调试与观测

bash 复制代码
dmesg | grep -iE 'bluetooth|hci|firmware|tty.*bt'
hciconfig -a 2>/dev/null; btmgmt info
rfkill list
bluetoothctl show; bluetoothctl devices
# 抓 HCI(需权限)
btmon
# 内核配置:CONFIG_BT、CONFIG_BT_HCIUART、CONFIG_BT_HCIBTUSB 等
现象 方向
无 hci0 总线 probe、固件、UART 波特率、设备树
hci0 在但 up 失败 rfkill、初始化命令超时、quirk
扫不到设备 天线、区域、扫描参数、被 block
能配对不能连配置文件 SDP/GATT 用户态、权限、UUID
BLE 连接秒断 连接间隔、监督超时、供电、干扰
音频无声 Pulse/PipeWire、编解码、profile

Checklist

  • 能区分:HCI 驱动、内核协议栈、bluetoothd 用户态三层职责
  • 知道 hci_alloc_devhci_register_dev 后才有 hci0
  • 会用 btmon 看命令超时还是链路断开
  • 清楚 RFCOMM/L2CAP/SCO 各自典型用途
  • UART 蓝牙查过波特率与固件;combo 查过与 WiFi 共存/rfkill
  • 根文件系统确认 D-Bus + bluetoothd(若用 BlueZ 标准栈)
  • 音频问题先查用户态 profile,再查 SCO/A2DP 链路

成稿:articles/csdn-merged/嵌入式Linux-蓝牙框架完整篇.md

相关推荐
Brilliantwxx1 天前
【STM32】 初认识USART串口
linux·stm32·单片机·嵌入式硬件·架构
aningx1 天前
使用自定义bash脚本预防oom卡死
linux
weixin_444579301 天前
Docker(下):镜像仓库管理
运维·docker·容器
资讯第一线1 天前
斐讯R1免登录配网》 [APP] [安卓版] 下载
运维
ONLYOFFICE1 天前
ONLYOFFICE成为Linux操作系统 – Winux的预装办公套件
linux·运维·服务器
其实防守也摸鱼1 天前
OpenClaw Windows 踩坑实战指南
运维·服务器·数据库·windows·github·copilot
mounter6251 天前
从内核安全到可编程基础设施:Meta 的 eBPF 实践与形式化验证探索
linux·ebpf·linux kernel·kernel
新时代牛马1 天前
嵌入式 Linux WiFi 框架完整篇:从cfg80211、mac80211 到wpa_supplicant
linux·运维·服务器
吴声子夜歌1 天前
Linux命令——打印
linux·运维·服务器