| // 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, ¶ms, 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 |