blob: 7ce60ca96ad99a56fb91b3443078d7985fe8268d [file] [log] [blame]
// Copyright 2017 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "device_wrapper.h"
#include <fuchsia/hardware/bluetooth/c/fidl.h>
#include <zircon/assert.h>
#include <zircon/device/bt-hci.h>
#include <zircon/status.h>
#include <zircon/types.h>
#include "src/connectivity/bluetooth/core/bt-host/common/log.h"
namespace bt::hci {
// ================= FidlDeviceWrapper =================
FidlDeviceWrapper::FidlDeviceWrapper(zx::channel device) : device_(std::move(device)) {
ZX_DEBUG_ASSERT(device_.is_valid());
}
zx::channel FidlDeviceWrapper::GetCommandChannel() {
zx::channel ours, theirs;
zx_status_t status = zx::channel::create(0, &ours, &theirs);
if (status != ZX_OK) {
bt_log(ERROR, "hci", "Failed to create command channel: %s", zx_status_get_string(status));
}
zx_handle_t dev_handle = device_.release();
status = fuchsia_hardware_bluetooth_HciOpenCommandChannel(dev_handle, theirs.release());
*device_.reset_and_get_address() = dev_handle;
if (status != ZX_OK) {
bt_log(ERROR, "hci", "Failed to bind command channel: %s", zx_status_get_string(status));
}
return ours;
}
zx::channel FidlDeviceWrapper::GetACLDataChannel() {
zx::channel ours, theirs;
zx_status_t status = zx::channel::create(0, &ours, &theirs);
if (status != ZX_OK) {
bt_log(ERROR, "hci", "Failed to create ACL channel: %s", zx_status_get_string(status));
}
zx_handle_t dev_handle = device_.release();
status = fuchsia_hardware_bluetooth_HciOpenAclDataChannel(dev_handle, theirs.release());
*device_.reset_and_get_address() = dev_handle;
if (status != ZX_OK) {
bt_log(ERROR, "hci", "Failed to bind ACL channel: %s", zx_status_get_string(status));
}
return ours;
}
// ================= DdkDeviceWrapper =================
DdkDeviceWrapper::DdkDeviceWrapper(const bt_hci_protocol_t& hci,
std::optional<bt_vendor_protocol_t> vendor)
: hci_proto_(hci), vendor_proto_(vendor) {}
zx::channel DdkDeviceWrapper::GetCommandChannel() {
zx::channel ours, theirs;
zx_status_t status = zx::channel::create(0, &ours, &theirs);
if (status != ZX_OK) {
bt_log(ERROR, "hci", "Failed to create command channel: %s", zx_status_get_string(status));
}
status = bt_hci_open_command_channel(&hci_proto_, theirs.release());
if (status != ZX_OK) {
bt_log(ERROR, "hci", "Failed to bind command channel: %s", zx_status_get_string(status));
}
return ours;
}
zx::channel DdkDeviceWrapper::GetACLDataChannel() {
zx::channel ours, theirs;
zx_status_t status = zx::channel::create(0, &ours, &theirs);
if (status != ZX_OK) {
bt_log(ERROR, "hci", "Failed to create ACL channel: %s", zx_status_get_string(status));
}
status = bt_hci_open_acl_data_channel(&hci_proto_, theirs.release());
if (status != ZX_OK) {
bt_log(ERROR, "hci", "Failed to bind ACL channel: %s", zx_status_get_string(status));
}
return ours;
}
bt_vendor_features_t DdkDeviceWrapper::GetVendorFeatures() {
if (!vendor_proto_) {
return 0;
}
return bt_vendor_get_features(&vendor_proto_.value());
};
fit::result<DynamicByteBuffer> DdkDeviceWrapper::EncodeVendorCommand(bt_vendor_command_t command,
bt_vendor_params_t& params) {
if (!vendor_proto_) {
return fit::error();
}
auto buffer = std::unique_ptr<uint8_t[]>(new uint8_t[BT_VENDOR_MAX_COMMAND_BUFFER_LEN]);
size_t actual = 0;
auto status = bt_vendor_encode_command(&vendor_proto_.value(), command, &params, buffer.get(),
BT_VENDOR_MAX_COMMAND_BUFFER_LEN, &actual);
if (status != ZX_OK || !actual || actual > BT_VENDOR_MAX_COMMAND_BUFFER_LEN) {
bt_log(DEBUG, "hci", "Failed to encode vendor command: %s", zx_status_get_string(status));
return fit::error();
}
return fit::ok(DynamicByteBuffer(actual, std::move(buffer)));
};
// ================= DummyDeviceWrapper =================
DummyDeviceWrapper::DummyDeviceWrapper(zx::channel cmd_channel, zx::channel acl_data_channel,
bt_vendor_features_t vendor_features,
EncodeCallback vendor_encode_cb)
: cmd_channel_(std::move(cmd_channel)),
acl_data_channel_(std::move(acl_data_channel)),
vendor_features_(vendor_features),
vendor_encode_cb_(std::move(vendor_encode_cb)) {}
zx::channel DummyDeviceWrapper::GetCommandChannel() { return std::move(cmd_channel_); }
zx::channel DummyDeviceWrapper::GetACLDataChannel() { return std::move(acl_data_channel_); }
fit::result<DynamicByteBuffer> DummyDeviceWrapper::EncodeVendorCommand(bt_vendor_command_t command,
bt_vendor_params_t& params) {
if (vendor_encode_cb_) {
return vendor_encode_cb_(command, params);
}
return fit::error();
}
} // namespace bt::hci