【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
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;
相关推荐
千里马学框架21 小时前
一起学 Android 14:ShellTransition 屏幕旋转过程深度剖析
android·智能手机·性能优化·framework·性能·屏幕旋转·rotation
美狐美颜SDK开放平台21 小时前
开发直播APP时如何接入视频美颜SDK?开发流程与注意事项
android·人工智能·计算机视觉·音视频·直播美颜sdk
AFinalStone1 天前
Android7 SystemUI源码解析(七)Keyguard锁屏模块深度解析
android·systemui
致远ccc1 天前
Google Play 上架前如何测试 App?多国家 Android 环境测试
android·app测试·googleplay·多国家应用测试
ttyyttemo1 天前
Kotlin 协程中的 Job 结构化并发与取消
android
sun0077001 天前
tbox 4g/5g切换,导致wan ip 改变,导致车机旧网络不可用。需要重启车机才行
android
其实防守也摸鱼1 天前
内网穿透与反向代理:原理、工具与实战指南
android·大数据·运维·安全·网络安全·自动化·渗透
AFinalStone1 天前
Android7 SystemUI 源码解析(四)NavigationBar 导航栏与 SystemBars
android·systemui
JMchen1 天前
属性动画原理与高级动画实现
android·kotlin·canvas
AFinalStone1 天前
Android7 SystemUI 源码解析(二)启动流程深度解析
android·systemui