/* * Copyright 2019 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define LOG_TAG "bt_shim_hci" #include #include #include #include #include "btcore/include/module.h" #include "main/shim/hci_layer.h" #include "main/shim/shim.h" #include "osi/include/allocator.h" #include "osi/include/future.h" #include "stack/include/bt_types.h" /** * Callback data wrapped as opaque token bundled with the command * transmit request to the Gd layer. * * Upon completion a token for a corresponding command transmit. * request is returned from the Gd layer. */ using CommandCallbackData = struct { void* context; command_complete_cb complete_callback; command_status_cb status_callback; }; constexpr size_t kBtHdrSize = sizeof(BT_HDR); constexpr size_t kCommandLengthSize = sizeof(uint8_t); constexpr size_t kCommandOpcodeSize = sizeof(uint16_t); static hci_t interface; static base::Callback send_data_upwards; static future_t* hci_module_shut_down(void); static future_t* hci_module_start_up(void); static void OnCommandComplete(uint16_t command_op_code, std::vector data, const void* token) { BT_HDR* response = static_cast(osi_calloc(data.size() + kBtHdrSize)); std::copy(data.begin(), data.end(), response->data); response->len = data.size(); const CommandCallbackData* command_callback_data = static_cast(token); CHECK(command_callback_data->complete_callback != nullptr); command_callback_data->complete_callback(response, command_callback_data->context); delete command_callback_data; } static void OnCommandStatus(uint16_t command_op_code, std::vector data, const void* token, uint8_t status) { BT_HDR* response = static_cast(osi_calloc(data.size() + kBtHdrSize)); std::copy(data.begin(), data.end(), response->data); response->len = data.size(); const CommandCallbackData* command_callback_data = static_cast(token); CHECK(command_callback_data->status_callback != nullptr); command_callback_data->status_callback(status, response, command_callback_data->context); delete command_callback_data; } EXPORT_SYMBOL extern const module_t gd_hci_module = { .name = GD_HCI_MODULE, .init = nullptr, .start_up = hci_module_start_up, .shut_down = hci_module_shut_down, .clean_up = nullptr, .dependencies = {GD_SHIM_MODULE, nullptr}}; static future_t* hci_module_start_up(void) { bluetooth::shim::GetHciLayer()->RegisterCommandComplete(OnCommandComplete); bluetooth::shim::GetHciLayer()->RegisterCommandStatus(OnCommandStatus); return nullptr; } static future_t* hci_module_shut_down(void) { bluetooth::shim::GetHciLayer()->UnregisterCommandComplete(); bluetooth::shim::GetHciLayer()->UnregisterCommandStatus(); return nullptr; } static void set_data_cb( base::Callback send_data_cb) { send_data_upwards = std::move(send_data_cb); } static void transmit_command(BT_HDR* command, command_complete_cb complete_callback, command_status_cb status_callback, void* context) { CHECK(command != nullptr); uint8_t* data = command->data + command->offset; size_t len = command->len; CHECK(len >= (kCommandOpcodeSize + kCommandLengthSize)); // little endian command opcode uint16_t command_op_code = (data[1] << 8 | data[0]); // Gd stack API requires opcode specification and calculates length, so // no need to provide opcode or length here. data += (kCommandOpcodeSize + kCommandLengthSize); len -= (kCommandOpcodeSize + kCommandLengthSize); const CommandCallbackData* command_callback_data = new CommandCallbackData{ context, complete_callback, status_callback, }; bluetooth::shim::GetHciLayer()->TransmitCommand( command_op_code, const_cast(data), len, static_cast(command_callback_data)); } const hci_t* bluetooth::shim::hci_layer_get_interface() { static bool loaded = false; if (!loaded) { loaded = true; interface.set_data_cb = set_data_cb; interface.transmit_command = transmit_command; interface.transmit_command_futured = nullptr; interface.transmit_downward = nullptr; } return &interface; }