本文基于 AOSP 的 android-11.0.0_r48 分支。
1. Overview
在 AOSP 中,蓝牙协议栈通过 HIDL 接口向 Vendor 发送 HCI CMD 主要通过两个函数:
- btu_hcif_send_cmd_with_cb - 自定义回调
- btu_hcif_send_cmd - 协议栈的默认回调
ACL、SCO、ISO 等数据包的发送也可以参考该流程,但应该有稍许不同。
2. Initialization
发送 HCI CMD 的函数主要涉及到 4 个源文件:
- system/bt/stack/btu/btu_hcif.cc
- system/bt/hci/src/hci_layer.cc
- system/bt/hci/src/packet_fragmenter.cc
- system/bt/hci/src/hci_layer_android.cc
其中有些存在依赖关系,因此先介绍初始化流程中的依赖部分。
2.1 hci_layer_get_interface() in btu_hcif.cc
system/bt/stack/btu/btu_hcif.cc
void btu_hcif_send_cmd_with_cb(const base::Location& posted_from,
uint16_t opcode, uint8_t* params,
uint8_t params_len, hci_cmd_cb cb) {
......
hci_layer_get_interface()->transmit_command(
p, btu_hcif_command_complete_evt_with_cb,
btu_hcif_command_status_evt_with_cb, (void*)cb_wrapper);
}
void btu_hcif_send_cmd(UNUSED_ATTR uint8_t controller_id, BT_HDR* p_buf) {
......
hci_layer_get_interface()->transmit_command(
p_buf, btu_hcif_command_complete_evt, btu_hcif_command_status_evt,
vsc_callback);
}
由以上源代码可知,两个 HCI 发送函数最终都调用了 hci_layer_get_interface(),然后再调用发送命令的函数,那么首先确定 hci_layer_get_interface() 函数获取的内容是什么。
system/bt/hci/src/hci_layer.cc
static hci_t interface;
const hci_t* hci_layer_get_interface() {
if (bluetooth::shim::is_gd_shim_enabled()) { // 1
return bluetooth::shim::hci_layer_get_interface();
} else {
return bluetooth::legacy::hci_layer_get_interface(); // 2
}
}
namespace bluetooth {
namespace shim {
const hci_t* hci_layer_get_interface();
} // namespace shim
} // namespace bluetooth
// 定义在这里,具体是现在 system/bt/main/shim/hci_layer.cc
const hci_t* bluetooth::legacy::hci_layer_get_interface() { // 3
buffer_allocator = buffer_allocator_get_interface();
btsnoop = btsnoop_get_interface();
packet_fragmenter = packet_fragmenter_get_interface();
init_layer_interface(); // 4
return &interface;
}
static void init_layer_interface() { // 5
if (!interface_created) {
interface.set_data_cb = set_data_cb;
interface.transmit_command = transmit_command; // 6
interface.transmit_command_futured = transmit_command_futured;
interface.transmit_downward = transmit_downward;
interface_created = true;
}
}
- 由于在 Android 11 上 默认没有启用 Gabeldorsche 协议栈,因此注释 // 1 处的函数返回值是 false,即执行注释 // 2 处的:bluetooth::legacy::hci_layer_get_interface()。
- 注释 // 2 的实现于注释 // 3 处,执行了一个重要的注释 // 4 函数。
- 注释 // 4 的实现于注释 // 5 处,执行了一个重要的赋值操作,即注释 // 6 处。
综合以上分析可知:
- 若设备的 Gabeldorsche 协议栈开启,那么执行 system/bt/main/shim/hci_layer.cc 源文件中的 transmit_command() 函数;
- 若设备的 Gabeldorsche 协议栈没有启用,那么执行 system/bt/hci/src/hci_layer.cc 源文件中的 transmit_command() 函数。 Android 11 执行此处
2.2 system/bt/hci/src/hci_layer.cc - initialization
2.2.1 hci_layer_get_interface()
system/bt/hci/src/hci_layer.cc
const hci_t* hci_layer_get_interface() {
if (bluetooth::shim::is_gd_shim_enabled()) {
......
} else {
return bluetooth::legacy::hci_layer_get_interface();
}
}
const hci_t* bluetooth::legacy::hci_layer_get_interface() {
buffer_allocator = buffer_allocator_get_interface();
btsnoop = btsnoop_get_interface();
packet_fragmenter = packet_fragmenter_get_interface(); // 1
init_layer_interface();
return &interface;
}
// 仅初始化一次
static void init_layer_interface() {
if (!interface_created) {
interface.set_data_cb = set_data_cb;
interface.transmit_command = transmit_command;
interface.transmit_command_futured = transmit_command_futured;
interface.transmit_downward = transmit_downward;
interface_created = true;
}
}
以上代码在 2.1 中分析了一部分,不再赘述,仅分析注释 // 1 处的函数 packet_fragmenter_get_interface()
system/bt/hci/src/packet_fragmenter.cc
const packet_fragmenter_t* packet_fragmenter_get_interface() {
controller = controller_get_interface();
buffer_allocator = buffer_allocator_get_interface();
return &interface;
}
static const packet_fragmenter_t interface = {init, cleanup,
fragment_and_dispatch,
reassemble_and_dispatch};
从以上源码可知:hci_layer.cc 获取到了 packet_fragmenter.cc 的函数入口。
2.2.2 hci_module_start_up()
system/bt/hci/src/hci_layer.cc
static future_t* hci_module_start_up(void) {
command_credits = 1;
......
hci_thread.StartUp(); // 1
if (!hci_thread.IsRunning()) {.......}
if (!hci_thread.EnableRealTimeScheduling()) {......}
......
packet_fragmenter->init(&packet_fragmenter_callbacks); // 2
......
hci_thread.DoInThread(FROM_HERE, base::Bind(&hci_initialize)); // 3
......
}
// 1
static MessageLoopThread hci_thread("bt_hci_thread");
// 2
static const packet_fragmenter_callbacks_t packet_fragmenter_callbacks = {
transmit_fragment, dispatch_reassembled, fragmenter_transmit_finished};
// 3
extern void hci_initialize();
- 注释 // 1 处创建了名为 bt_hci_thread 的 HCI 工作线程;
- 注释 // 2 处初始化了 static const packet_fragmenter_t* packet_fragmenter,并传递了函数的数组,用于后续执行相应的代码时回调,该初始化函数 init() 将在 2.3 进行分析;
- 注释 // 3 处在 hci_thread 中执行了 hci_initialize() 初始化函数,该函数在 hci_layer_android.cc 中,在 2.4 分析。
2.3 system/bt/hci/src/packet_fragmenter.cc - initialization
在 2.2.2 中出现了 packet_fragmenter.cc 的初始化函数 init(),并传递了参数列表。
参数:
system/bt/hci/src/hci_layer.cc
static const packet_fragmenter_callbacks_t packet_fragmenter_callbacks = {
transmit_fragment, dispatch_reassembled, fragmenter_transmit_finished};
初始化函数:
system/bt/hci/src/packet_fragmenter.cc
static void init(const packet_fragmenter_callbacks_t* result_callbacks) {
callbacks = result_callbacks;
}
static const packet_fragmenter_callbacks_t* callbacks;
system/bt/hci/include/packet_fragmenter.h
typedef struct {
packet_fragmented_cb fragmented;
packet_reassembled_cb reassembled;
transmit_finished_cb transmit_finished;
} packet_fragmenter_callbacks_t;
那么 packet_fragmenter.cc 回调 hci_layer.cc 的函数的映射关系如下表,即在 packet_fragmenter.cc 中调用第一列的某个函数相当于调用 hci_layer.cc 中的第二列的对应函数。
system/bt/hci/src/packet_fragmenter.cc | system/bt/hci/src/hci_layer.cc |
---|---|
fragmented | transmit_fragment |
reassembled | dispatch_reassembled |
transmit_finished | fragmenter_transmit_finished |
2.4 system/bt/hci/src/hci_layer_android.cc - initialization
system/bt/hci/src/hci_layer_android.cc
void hci_initialize() {
btHci_1_1 = V1_1::IBluetoothHci::getService();
if (btHci_1_1 != nullptr) {
btHci = btHci_1_1;
} else {
btHci = V1_0::IBluetoothHci::getService();
}
......
{
android::sp<V1_1::IBluetoothHciCallbacks> callbacks =
new BluetoothHciCallbacks();
if (btHci_1_1 != nullptr) {
btHci_1_1->initialize_1_1(callbacks);
} else {
btHci->initialize(callbacks);
}
}
}
初始化 HCI 的 HIDL 接口、设置对应的回调函数,用于蓝牙协议栈与 Vendor 进程之间的双向通信。
3. Bluetooth send HCI CMD flow
3.1 常用的 HCI CMD 发送方法
system/bt/stack/btu/btu_hcif.cc
void btu_hcif_send_cmd_with_cb(const Location& posted_from, uint16_t opcode,
uint8_t* params, uint8_t params_len,
hci_cmd_cb cb) {
BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
uint8_t* pp = (uint8_t*)(p + 1);
p->len = HCIC_PREAMBLE_SIZE + params_len;
p->offset = 0;
UINT16_TO_STREAM(pp, opcode);
UINT8_TO_STREAM(pp, params_len);
if (params) {
memcpy(pp, params, params_len);
}
btu_hcif_log_command_metrics(opcode, pp,
android::bluetooth::hci::STATUS_UNKNOWN, false);
cmd_with_cb_data* cb_wrapper =
(cmd_with_cb_data*)osi_malloc(sizeof(cmd_with_cb_data));
cmd_with_cb_data_init(cb_wrapper);
cb_wrapper->cb = std::move(cb);
cb_wrapper->posted_from = posted_from;
hci_layer_get_interface()->transmit_command(
p, btu_hcif_command_complete_evt_with_cb,
btu_hcif_command_status_evt_with_cb, (void*)cb_wrapper);
}
void btu_hcif_send_cmd(UNUSED_ATTR uint8_t controller_id, BT_HDR* p_buf) {
if (!p_buf) return;
uint16_t opcode;
uint8_t* stream = p_buf->data + p_buf->offset;
void* vsc_callback = NULL;
STREAM_TO_UINT16(opcode, stream);
// Eww...horrible hackery here
/* If command was a VSC, then extract command_complete callback */
if ((opcode & HCI_GRP_VENDOR_SPECIFIC) == HCI_GRP_VENDOR_SPECIFIC ||
(opcode == HCI_BLE_RAND) || (opcode == HCI_BLE_ENCRYPT)) {
vsc_callback = *((void**)(p_buf + 1));
}
// Skip parameter length before logging
stream++;
btu_hcif_log_command_metrics(opcode, stream,
android::bluetooth::hci::STATUS_UNKNOWN, false);
hci_layer_get_interface()->transmit_command(
p_buf, btu_hcif_command_complete_evt, btu_hcif_command_status_evt,
vsc_callback);
}
3.2 发送内容与回调内容的封装
system/bt/hci/src/hci_layer.cc
static void transmit_command(BT_HDR* command,
command_complete_cb complete_callback,
command_status_cb status_callback, void* context) {
waiting_command_t* wait_entry = reinterpret_cast<waiting_command_t*>(
osi_calloc(sizeof(waiting_command_t)));
uint8_t* stream = command->data + command->offset;
STREAM_TO_UINT16(wait_entry->opcode, stream);
wait_entry->complete_callback = complete_callback;
wait_entry->status_callback = status_callback;
wait_entry->command = command;
wait_entry->context = context;
// Store the command message type in the event field
// in case the upper layer didn't already
command->event = MSG_STACK_TO_HC_HCI_CMD;
enqueue_command(wait_entry);
}
将参数封装到 waiting_command_t 结构体中,便于后续使用。
3.3 HCI CMD 立即执行与队列缓存执行
system/bt/hci/src/hci_layer.cc
static void enqueue_command(waiting_command_t* wait_entry) {
base::Closure callback = base::Bind(&event_command_ready, wait_entry); // 1
std::lock_guard<std::mutex> command_credits_lock(command_credits_mutex);
if (command_credits > 0) {
if (!hci_thread.DoInThread(FROM_HERE, std::move(callback))) { // 2
// HCI Layer was shut down or not running
buffer_allocator->free(wait_entry->command);
osi_free(wait_entry);
return;
}
command_credits--;
} else {
command_queue.push(std::move(callback)); // 3
}
}
- 注释 // 1 处,将函数 event_command_ready 和参数 wait_entry 构成一个 callback ,便于使用;
- 若 command_credits 符合条件,则立即在 hci_thread 中执行 callback;
- 若 command_credits 不符合条件,则将 callback 放到命令队列 command_queue 中,待后续执行。
3.3.1 队列缓存执行的路径
具体的从命令队列 command_queue 中取出并执行命令的函数如下:
system/bt/hci/src/hci_layer.cc
void process_command_credits(int credits) {
......
command_credits = credits - get_num_waiting_commands();
while (command_credits > 0 && !command_queue.empty()) {
if (!hci_thread.DoInThread(FROM_HERE, std::move(command_queue.front()))) { // 1
......
}
command_queue.pop(); // 2
command_credits--;
}
}
- 注释 // 1 处,从命令队列 command_queue 获取头部 callback 元素进行执行;
- 注释 // 2 处,从命令队列 command_queue 移除成功执行的元素;
3.3.1.1 process_command_credits 的调用路径
system/bt/hci/src/hci_layer_android.cc
class BluetoothHciCallbacks : public V1_1::IBluetoothHciCallbacks {
Return<void> hciEventReceived(const hidl_vec<uint8_t>& event) override {
BT_HDR* packet = WrapPacketAndCopy(MSG_HC_TO_STACK_HCI_EVT, event);
hci_event_received(FROM_HERE, packet); // 1
return Void();
}
}
system/bt/hci/src/hci_layer.cc
void hci_event_received(const base::Location& from_here, BT_HDR* packet) {
......
if (!filter_incoming_event(packet)) { // 2
......
}
}
static bool filter_incoming_event(BT_HDR* packet) {
......
if (event_code == HCI_COMMAND_COMPLETE_EVT) {
......
process_command_credits(credits); // 3.1
......
} else if (event_code == HCI_COMMAND_STATUS_EVT) {
......
process_command_credits(credits); // 3.2
......
} else if (event_code == HCI_VENDOR_SPECIFIC_EVT) {
......
}
return false;
intercepted:
......
return true;
}
从以上注释 // 1、// 2 、// 3.1 、 // 3.2 可知,一个同步 HCI CMD 完成后或者异步 HCI CMD 的状态回复后,会检测是否执行队列中的下一条命令。
3.3.2 立即执行与缓存执行的总结
- 立即执行 event_command_ready;
- 在上一条 HCI CMD 执行完毕后或命令的状态回复之后,有机会执行下一条命令,即执行 event_command_ready。
3.4 hci_thread 中执行 HCI CMD 的发送
system/bt/hci/src/hci_layer.cc
static void event_command_ready(waiting_command_t* wait_entry) {
{
/// Move it to the list of commands awaiting response
std::lock_guard<std::recursive_timed_mutex> lock(
commands_pending_response_mutex);
wait_entry->timestamp = std::chrono::steady_clock::now();
list_append(commands_pending_response, wait_entry);
}
packet_fragmenter->fragment_and_dispatch(wait_entry->command);
update_command_response_timer();
}
3.5 HCI CMD 的分包
system/bt/hci/src/packet_fragmenter.cc
static void fragment_and_dispatch(BT_HDR* packet) {
CHECK(packet != NULL);
uint16_t event = packet->event & MSG_EVT_MASK;
if (event == MSG_STACK_TO_HC_HCI_ACL) {
fragment_and_dispatch_acl(packet);
} else if (event == MSG_STACK_TO_HC_HCI_ISO) {
fragment_and_dispatch_iso(packet);
} else {
// 根据 system/bt/hci/src/hci_layer.cc # transmit_command() 的 MSG_STACK_TO_HC_HCI_CMD 可知:
// HCI CMD 在此处执行,即命令不需要分包。
callbacks->fragmented(packet, true);
}
}
- ACL 和 ISO 数据需要执行分包;
- CMD 不需要分包;
- Host 向 Controller 发送的数据,在 Host 端不存在 event 类型。
根据 2.3 的回调函数映射表可知:callbacks->fragmented(packet, true) 执行的函数是
system/bt/hci/src/hci_layer.cc - transmit_fragment(...)
static void transmit_fragment(BT_HDR* packet, bool send_transmit_finished) {
......
hci_transmit(packet);
......
}
3.6 调用 HIDL 接口发送 HCI CMD
system/bt/hci/src/hci_layer_android.cc
void hci_transmit(BT_HDR* packet) {
HciPacket data;
data.setToExternal(packet->data + packet->offset, packet->len);
uint16_t event = packet->event & MSG_EVT_MASK;
switch (event & MSG_EVT_MASK) {
case MSG_STACK_TO_HC_HCI_CMD:
btHci->sendHciCommand(data);
break;
case MSG_STACK_TO_HC_HCI_ACL:
btHci->sendAclData(data);
break;
case MSG_STACK_TO_HC_HCI_SCO:
btHci->sendScoData(data);
break;
case MSG_STACK_TO_HC_HCI_ISO:
if (btHci_1_1 != nullptr) {
btHci_1_1->sendIsoData(data);
} else {
......
}
break;
default:
......
break;
}
}
直接调用了 HIDL 接口,发送 HCI 的命令和不同类型的数据。
4. HCI CMD Callback flow
HCI CMD 发送后,Controller 会回复该命令状态的 Event,某些命令是异步处理,还会发送命令执行完成的Event。
接收来自 Controller 的 Event 由 hci_event_received() 函数进行分发,存在 filter_incoming_event() 函数,HCI CMD 发送时设置的回调函数,在该函数中分发。
system/bt/hci/src/hci_layer.cc
void hci_event_received(const base::Location& from_here, BT_HDR* packet) {
btsnoop->capture(packet, true);
if (!filter_incoming_event(packet)) { // 1
send_data_upwards.Run(from_here, packet); // 2
}
}
static bool filter_incoming_event(BT_HDR* packet) { // 3
waiting_command_t* wait_entry = NULL;
......
if (event_code == HCI_COMMAND_COMPLETE_EVT) { // 4
......
wait_entry = get_waiting_command(opcode);
process_command_credits(credits);
if (!wait_entry) {
......
} else {
update_command_response_timer();
if (wait_entry->complete_callback) {
wait_entry->complete_callback(packet, wait_entry->context); // 5
} else if (wait_entry->complete_future) {
......
}
}
goto intercepted;
} else if (event_code == HCI_COMMAND_STATUS_EVT) { // 6
......
wait_entry = get_waiting_command(opcode);
process_command_credits(credits);
if (!wait_entry) {
......
} else {
update_command_response_timer();
if (wait_entry->status_callback)
wait_entry->status_callback(status, wait_entry->command, wait_entry->context); // 7
}
goto intercepted;
} else if (event_code == HCI_VENDOR_SPECIFIC_EVT) {
......
}
return false;
intercepted:
......
return true;
}
- hci_event_received() 是处理来自 Controller 的 EVENT 的必经之路,在此函数中根据不同的条件执行两个分支;
- 分支一: filter_incoming_event(),注释 // 1、// 3 处即为调用和实现;
2.1. 注释 // 4 和 // 5 对应了 Host 收到来自之前 Host 发给 Controller 的命令执行完毕时,执行该回调;(4.1 介绍)
2.2. 注释 // 6 和 // 7 对应了 Host 收到来自之前 Host 发给 Controller 的命令的执行状态的回复时,执行该回调;(4.2 介绍) - 分支二:send_data_upwards.Run(from_here, packet),注释 // 2 处。(4.3 介绍)
4.1 btu_hcif_send_cmd_with_cb 的回调流程
发送命令时,自定义回调函数。
system/bt/stack/btu/btu_hcif.cc
void btu_hcif_send_cmd_with_cb(const base::Location& posted_from,
uint16_t opcode, uint8_t* params,
uint8_t params_len, hci_cmd_cb cb) {
......
cb_wrapper->cb = std::move(cb);
......
hci_layer_get_interface()->transmit_command(
p, btu_hcif_command_complete_evt_with_cb,
btu_hcif_command_status_evt_with_cb, (void*)cb_wrapper);
}
由发送命令可知,用户设置的回调函数是 hci_cmd_cb cb,即为 cb_wrapper->cb。
4.1.1 btu_hcif_command_complete_evt_with_cb
system/bt/stack/btu/btu_hcif.cc
static void btu_hcif_command_complete_evt_with_cb(BT_HDR* response,
void* context) {
do_in_main_thread(FROM_HERE,
base::Bind(btu_hcif_command_complete_evt_with_cb_on_task,
response, context));
}
static void btu_hcif_command_complete_evt_with_cb_on_task(BT_HDR* event,
void* context) {
......
cmd_with_cb_data* cb_wrapper = (cmd_with_cb_data*)context;
......
uint16_t param_len = static_cast<uint16_t>(event->len - 5);
std::move(cb_wrapper->cb).Run(stream, param_len); // 1
......
}
- 注释 // 1 处的代码执行了 cb_wrapper->cb,即执行了用户设置的回调函数。
4.1.2 btu_hcif_command_status_evt_with_cb
system/bt/stack/btu/btu_hcif.cc
static void btu_hcif_command_status_evt_with_cb(uint8_t status, BT_HDR* command,
void* context) {
do_in_main_thread(
FROM_HERE, base::Bind(btu_hcif_command_status_evt_with_cb_on_task, status,
command, context));
}
static void btu_hcif_command_status_evt_with_cb_on_task(uint8_t status,
BT_HDR* event,
void* context) {
......
cmd_with_cb_data* cb_wrapper = (cmd_with_cb_data*)context;
std::move(cb_wrapper->cb).Run(&status, sizeof(uint16_t)); // 1
......
}
- 注释 // 1 处的代码执行了 cb_wrapper->cb,即执行了用户设置的回调函数。
4.2 btu_hcif_send_cmd 的回调流程
发送命令时,不设置自定义的回调,则采用蓝牙协议栈的默认回调。
默认回调一般用于处理既定的流程。
4.2.1 btu_hcif_command_complete_evt
system/bt/stack/btu/btu_hcif.cc
static void btu_hcif_command_complete_evt(BT_HDR* response, void* context) {
do_in_main_thread(FROM_HERE, base::Bind(btu_hcif_command_complete_evt_on_task,
response, context));
}
static void btu_hcif_command_complete_evt_on_task(BT_HDR* event,
void* context) {
......
uint16_t param_len = static_cast<uint16_t>(event->len - 5);
btu_hcif_hdl_command_complete(opcode, stream, param_len, context);
......
}
static void btu_hcif_hdl_command_complete(uint16_t opcode, uint8_t* p,
uint16_t evt_len,
void* p_cplt_cback) {
...... // 根据不同的事件,走不同的流程,不详述。
}
4.2.2 btu_hcif_command_status_evt
system/bt/stack/btu/btu_hcif.cc
static void btu_hcif_command_status_evt(uint8_t status, BT_HDR* command,
void* context) {
do_in_main_thread(FROM_HERE, base::Bind(btu_hcif_command_status_evt_on_task,
status, command, context));
}
static void btu_hcif_command_status_evt_on_task(uint8_t status, BT_HDR* event,
void* context) {
......
btu_hcif_hdl_command_status(opcode, status, stream, context);
......
}
static void btu_hcif_hdl_command_status(uint16_t opcode, uint8_t status,
uint8_t* p_cmd,
void* p_vsc_status_cback) {
...... // 根据不同的事件,走不同的流程,不详述。
}
4.3 send_data_upwards.Run(from_here, packet)
4.3.1 send_data_upwards - initialization
void bte_main_boot_entry(void) {
......
hci = hci_layer_get_interface();
......
hci->set_data_cb(base::Bind(&post_to_main_message_loop));
......
}
system/bt/hci/src/hci_layer.cc
static void set_data_cb(
base::Callback<void(const base::Location&, BT_HDR*)> send_data_cb) {
send_data_upwards = std::move(send_data_cb);
}
static base::Callback<void(const base::Location&, BT_HDR*)> send_data_upwards;
根据以上代码流程可知,执行 send_data_upwards 即为执行 post_to_main_message_loop。
4.3.2 post_to_main_message_loop 执行
void post_to_main_message_loop(const base::Location& from_here, BT_HDR* p_msg) {
if (do_in_main_thread(from_here, base::Bind(&btu_hci_msg_process, p_msg)) !=
BT_STATUS_SUCCESS) {
......
}
}
执行 post_to_main_message_loop() 相当于在 main 线程中执行 btu_hci_msg_process() 函数,如下。
system/bt/stack/btu/btu_task.cc
void btu_hci_msg_process(BT_HDR* p_msg) {
/* Determine the input message type. */
switch (p_msg->event & BT_EVT_MASK) {
case BT_EVT_TO_BTU_HCI_ACL:
/* All Acl Data goes to L2CAP */
l2c_rcv_acl_data(p_msg);
break;
case BT_EVT_TO_BTU_L2C_SEG_XMIT:
/* L2CAP segment transmit complete */
l2c_link_segments_xmitted(p_msg);
break;
case BT_EVT_TO_BTU_HCI_SCO:
btm_route_sco_data(p_msg);
break;
case BT_EVT_TO_BTU_HCI_EVT:
btu_hcif_process_event((uint8_t)(p_msg->event & BT_SUB_EVT_MASK), p_msg);
osi_free(p_msg);
break;
case BT_EVT_TO_BTU_HCI_CMD:
btu_hcif_send_cmd((uint8_t)(p_msg->event & BT_SUB_EVT_MASK), p_msg);
break;
case BT_EVT_TO_BTU_HCI_ISO:
// TODO: implement handler
osi_free(p_msg);
break;
default:
osi_free(p_msg);
break;
}
}
至此,蓝牙的 HCI CMD 发送流程和命令执行状态的回调流程结束。
网友评论