blob: ba21cae85db66857201a8548fca29470bd65ea8b [file] [log] [blame]
/*
* 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 <base/bind.h>
#include <frameworks/base/core/proto/android/bluetooth/hci/enums.pb.h>
#include <algorithm>
#include <cstdint>
#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<void(const base::Location&, BT_HDR*)> 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<const uint8_t> data,
const void* token) {
BT_HDR* response = static_cast<BT_HDR*>(osi_calloc(data.size() + kBtHdrSize));
std::copy(data.begin(), data.end(), response->data);
response->len = data.size();
const CommandCallbackData* command_callback_data =
static_cast<const CommandCallbackData*>(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<const uint8_t> data, const void* token,
uint8_t status) {
BT_HDR* response = static_cast<BT_HDR*>(osi_calloc(data.size() + kBtHdrSize));
std::copy(data.begin(), data.end(), response->data);
response->len = data.size();
const CommandCallbackData* command_callback_data =
static_cast<const CommandCallbackData*>(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<void(const base::Location&, BT_HDR*)> 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<const uint8_t*>(data), len,
static_cast<const void*>(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;
}