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
c
/** 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. 如何触发调用
例如:
c
ALOGI("Turn On BT power");
powerstate = BT_VND_PWR_ON;
ret = lib_interface_->op(BT_VND_OP_POWER_CTRL, &powerstate);
c
/*
* 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 电源(如果支持) |
c
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。
c
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;