【android bluetooth 协议分析 02】【bluetooth hal 层详解 6】【bt_vendor_opcode_t 介绍】
bt_vendor_opcode_t 介绍
在 AOSP 的 Bluetooth Vendor 接口中,bt_vendor_opcode_t
定义了一组供上层调用的操作指令。这些操作在蓝牙初始化、使用和关闭过程中由协议栈(如 Bluedroid)驱动调用,按照一定的顺序执行。
这些枚举项代表 Vendor Interface API 的操作码,协议栈通过调用 vendor_call()
接口并传入这些 opcodes 来控制蓝牙芯片的底层行为。其设计目的在于:
- 平台差异适配(如不同 SoC 的上电、串口打开方式)
- 硬件加速支持(如 A2DP offload)
- 功耗优化(如 LPM 控制)
- 音频子系统协同(如 SCO、音频状态)
1. 详解介绍
- hidl_hci/1.0/default/bt_vendor_lib.h
/** Vendor specific operations OPCODE */
typedef enum {/* [operation]* Power on or off the BT Controller.* [input param]* A pointer to int type with content of bt_vendor_power_state_t.* Typecasting conversion: (int *) param.* [return]* 0 - default, don't care.* [callback]* None.*/BT_VND_OP_POWER_CTRL,/* [operation]* Perform any vendor specific initialization or configuration* on the BT Controller. This is called before stack initialization.* [input param]* None.* [return]* 0 - default, don't care.* [callback]* Must call fwcfg_cb to notify the stack of the completion of vendor* specific initialization once it has been done.*/BT_VND_OP_FW_CFG,/* [operation]* Perform any vendor specific SCO/PCM configuration on the BT* Controller.* This is called after stack initialization.* [input param]* None.* [return]* 0 - default, don't care.* [callback]* Must call scocfg_cb to notify the stack of the completion of vendor* specific SCO configuration once it has been done.*/BT_VND_OP_SCO_CFG,/* [operation]* Open UART port on where the BT Controller is attached.* This is called before stack initialization.* [input param]* A pointer to int array type for open file descriptors.* The mapping of HCI channel to fd slot in the int array is given in* bt_vendor_hci_channels_t.* And, it requires the vendor lib to fill up the content before* returning* the call.* Typecasting conversion: (int (*)[]) param.* [return]* Numbers of opened file descriptors.* Valid number:* 1 - CMD/EVT/ACL-In/ACL-Out via the same fd (e.g. UART)* 2 - CMD/EVT on one fd, and ACL-In/ACL-Out on the other fd* 4 - CMD, EVT, ACL-In, ACL-Out are on their individual fd* [callback]* None.*/BT_VND_OP_USERIAL_OPEN,/* [operation]* Close the previously opened UART port.* [input param]* None.* [return]* 0 - default, don't care.* [callback]* None.*/BT_VND_OP_USERIAL_CLOSE,/* [operation]* Get the LPM idle timeout in milliseconds.* The stack uses this information to launch a timer delay before it* attempts to de-assert LPM WAKE signal once downstream HCI packet* has been delivered.* [input param]* A pointer to uint32_t type which is passed in by the stack. And, it* requires the vendor lib to fill up the content before returning* the call.* Typecasting conversion: (uint32_t *) param.* [return]* 0 - default, don't care.* [callback]* None.*/BT_VND_OP_GET_LPM_IDLE_TIMEOUT,/* [operation]* Enable or disable LPM mode on BT Controller.* [input param]* A pointer to uint8_t type with content of bt_vendor_lpm_mode_t.* Typecasting conversion: (uint8_t *) param.* [return]* 0 - default, don't care.* [callback]* Must call lpm_cb to notify the stack of the completion of LPM* disable/enable process once it has been done.*/BT_VND_OP_LPM_SET_MODE,/* [operation]* Assert or Deassert LPM WAKE on BT Controller.* [input param]* A pointer to uint8_t type with content of bt_vendor_lpm_wake_state_t.* Typecasting conversion: (uint8_t *) param.* [return]* 0 - default, don't care.* [callback]* None.*/BT_VND_OP_LPM_WAKE_SET_STATE,/* [operation]* Perform any vendor specific commands related to audio state changes.* [input param]* a pointer to bt_vendor_op_audio_state_t indicating what audio state is* set.* [return]* 0 - default, don't care.* [callback]* None.*/BT_VND_OP_SET_AUDIO_STATE,/* [operation]* The epilog call to the vendor module so that it can perform any* vendor-specific processes (e.g. send a HCI_RESET to BT Controller)* before the caller calls for cleanup().* [input param]* None.* [return]* 0 - default, don't care.* [callback]* Must call epilog_cb to notify the stack of the completion of vendor* specific epilog process once it has been done.*/BT_VND_OP_EPILOG,/* [operation]* Call to the vendor module so that it can perform all vendor-specific* operations to start offloading a2dp media encode & tx.* [input param]* pointer to bt_vendor_op_a2dp_offload_start_t containing elements* required for VND FW to setup a2dp offload.* [return]* 0 - default, dont care.* [callback]* Must call a2dp_offload_start_cb to notify the stack of the* completion of vendor specific setup process once it has been done.*/BT_VND_OP_A2DP_OFFLOAD_START,/* [operation]* Call to the vendor module so that it can perform all vendor-specific* operations to suspend offloading a2dp media encode & tx.* [input param]* pointer to bt_vendor_op_a2dp_offload_t containing elements* required for VND FW to setup a2dp offload.* [return]* 0 - default, dont care.* [callback]* Must call a2dp_offload_cb to notify the stack of the* completion of vendor specific setup process once it has been done.*/BT_VND_OP_A2DP_OFFLOAD_STOP,} bt_vendor_opcode_t;
枚举项 | 作用说明 | 触发时机 | 典型应用场合 |
---|---|---|---|
BT_VND_OP_POWER_CTRL | 控制蓝牙芯片上电/断电 | 蓝牙开启或关闭前后 | 控制 BT SoC 电源,如初始化前上电,退出前下电 |
BT_VND_OP_FW_CFG | 执行厂商特有的固件初始化配置 | 蓝牙协议栈初始化前 | 加载 firmware patch、设置特有寄存器等,完成后调用 fwcfg_cb 通知上层 |
BT_VND_OP_SCO_CFG | 执行厂商特定的 SCO/PCM 音频配置 | 协议栈初始化之后(有 SCO 功能时) | 设置 HCI SCO 路径,配置 PCM 接口参数,完成后需调用 scocfg_cb |
BT_VND_OP_USERIAL_OPEN | 打开串口或类似物理连接接口,用于 HCI 通信 | 初始化前 | 为主控和 BT 控制器之间建立 HCI 通道(如 UART),返回 fd 列表供上层使用 |
BT_VND_OP_USERIAL_CLOSE | 关闭串口或物理连接接口 | 清理蓝牙前 | 关闭 UART、SPI、USB 接口文件描述符 |
BT_VND_OP_GET_LPM_IDLE_TIMEOUT | 获取低功耗空闲超时(单位 ms) | 启用 LPM 功能后,发送数据后启动 idle 计时器 | 控制下行数据发送后 LPM WAKE deassert 的延迟时间,避免频繁切换 |
BT_VND_OP_LPM_SET_MODE | 设置是否启用低功耗模式(LPM) | 蓝牙初始化后,根据策略动态设置 | 进入低功耗模式(例如未连接时)、退出低功耗(如开始通信时),需调用 lpm_cb |
BT_VND_OP_LPM_WAKE_SET_STATE | 设置 WAKE 状态:assert 或 deassert | LPM 状态切换时,通常由协议栈驱动 | 控制 LPM 的 WAKE GPIO,保持通信或释放资源 |
BT_VND_OP_SET_AUDIO_STATE | 通知音频状态变化以执行特定命令 | 音频连接或断开时 | 比如 HFP 通话开始/结束,通知底层做相关设置 |
BT_VND_OP_EPILOG | 蓝牙关闭前的收尾工作 | cleanup() 调用前 | 发出 HCI_RESET 等命令,释放资源,完成后调用 epilog_cb |
BT_VND_OP_A2DP_OFFLOAD_START | 启动 A2DP 硬件 offload(编码和传输) | 开始播放 A2DP 音乐时 | 将音频流交给底层硬件加速处理,完成后调用 a2dp_offload_start_cb |
BT_VND_OP_A2DP_OFFLOAD_STOP | 停止 A2DP offload | 暂停或停止音乐播放时 | 通知底层停止 offload 模块,完成后调用 a2dp_offload_cb |
2. 如何触发调用
例如:
ALOGI("Turn On BT power");powerstate = BT_VND_PWR_ON;ret = lib_interface_->op(BT_VND_OP_POWER_CTRL, &powerstate);
/** Bluetooth Host/Controller VENDOR Interface*/
typedef struct {/** Set to sizeof(bt_vndor_interface_t) */size_t size;/** Functions need to be implemented in Vendor libray (libbt-vendor.so).*//*** Caller will open the interface and pass in the callback routines* to the implemenation of this interface.*/int (*init)(const bt_vendor_callbacks_t* p_cb, unsigned char* local_bdaddr);/** Vendor specific operations */int (*op)(bt_vendor_opcode_t opcode, void* param);/** Closes the interface */void (*cleanup)(void);
} bt_vendor_interface_t;
2. 案例赏析
1. 一般蓝牙操作流程
下面是一个典型的蓝牙开启、使用、关闭的完整流程,配合 Vendor 操作指令说明。
1. 蓝牙初始化阶段(Bluetooth Turn ON)
顺序 | 操作 | opcode | 描述 |
---|---|---|---|
1 | 打开串口 | BT_VND_OP_USERIAL_OPEN | 打开与 BT 芯片通信的物理接口(如 UART) |
2 | 芯片上电 | BT_VND_OP_POWER_CTRL | 通知 vendor 上电;若芯片已供电则可能为 no-op |
3 | 固件配置 | BT_VND_OP_FW_CFG | 执行固件加载或寄存器配置,完成后需调用 fwcfg_cb() |
4 | 低功耗模式设置 | BT_VND_OP_LPM_SET_MODE | 启用或禁用 LPM(低功耗)模式,完成后调用 lpm_cb() |
5 | 获取 LPM 超时 | BT_VND_OP_GET_LPM_IDLE_TIMEOUT | 获取 LPM 模式下的空闲超时时间 |
⚠️ 有 SCO 功能设备还会执行:
BT_VND_OP_SCO_CFG
:设置 PCM 参数,完成后调用scocfg_cb()
。
2. 音频使用阶段(如通话、播放音乐)
情况 | 操作 | opcode | 描述 |
---|---|---|---|
开始通话(HFP) | BT_VND_OP_SET_AUDIO_STATE | 通知底层开始 SCO 语音传输 | |
播放音乐(A2DP) | BT_VND_OP_A2DP_OFFLOAD_START | 启动音频硬件 offload | |
暂停音乐 | BT_VND_OP_A2DP_OFFLOAD_STOP | 停止 A2DP 硬件 offload | |
通信中 | BT_VND_OP_LPM_WAKE_SET_STATE | 发送数据前 deassert WAKE;空闲后再 assert |
3. 蓝牙关闭阶段(Bluetooth Turn OFF)
顺序 | 操作 | opcode | 描述 |
---|---|---|---|
1 | 执行 epilog 清理流程 | BT_VND_OP_EPILOG | 可能发送 HCI_RESET 或其他定制命令,完成后需调用 epilog_cb() |
2 | 关闭串口 | BT_VND_OP_USERIAL_CLOSE | 关闭 UART、SPI 或 USB 接口 |
3 | 芯片断电 | BT_VND_OP_POWER_CTRL | 通知 Vendor 关闭 BT 电源(如果支持) |
Bluetooth ON 流程:┌───────────────────────────────┐│ USERIAL_OPEN ││ POWER_CTRL (ON) ││ FW_CFG → fwcfg_cb ││ SCO_CFG → scocfg_cb (可选) ││ LPM_SET_MODE → lpm_cb ││ GET_LPM_IDLE_TIMEOUT │└───────────────────────────────┘使用过程:┌───────────────────────────────┐│ SET_AUDIO_STATE ││ A2DP_OFFLOAD_START / STOP ││ LPM_WAKE_SET_STATE │└───────────────────────────────┘Bluetooth OFF 流程:┌───────────────────────────────┐│ EPILOG → epilog_cb ││ USERIAL_CLOSE ││ POWER_CTRL (OFF) │└───────────────────────────────┘
3. 补充说明
- 所有
*_cb()
结尾的操作都需要在异步完成后由 vendor 层手动调用回调通知协议栈。 vendor lib
是一个中间层,负责将这些操作转换为实际硬件控制动作(如 ioctl、GPIO 控制、UART 操作等)。- 上层
bt_vendor_interface_t->op()
接口在vendor.c
中实现,内部 switch-case 匹配这些 opcode。
typedef struct {/** set to sizeof(bt_vendor_callbacks_t) */size_t size;/** Callback and callout functions have implemented in HCI libray* (libbt-hci.so).*//* notifies caller result of firmware configuration request */cfg_result_cb fwcfg_cb;/* notifies caller result of sco configuration request */cfg_result_cb scocfg_cb;/* notifies caller result of lpm enable/disable */cfg_result_cb lpm_cb;/* notifies the result of codec setting */cfg_result_cb audio_state_cb;/* buffer allocation request */malloc_cb alloc;/* buffer deallocation request */mdealloc_cb dealloc;/* hci command packet transmit request */cmd_xmit_cb xmit_cb;/* notifies caller completion of epilog process */cfg_result_cb epilog_cb;/* notifies status of a2dp offload cmd's */cfg_a2dp_cb a2dp_offload_cb;
} bt_vendor_callbacks_t;