blob: a8648f3e66c8d7534afdfeda305e67e0b08340c4 [file] [log] [blame]
// Copyright 2018 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 "host.h"
#include "garnet/drivers/bluetooth/lib/hci/device_wrapper.h"
#include "garnet/drivers/bluetooth/lib/hci/transport.h"
#include "fidl/host_server.h"
#include "gatt_host.h"
using namespace btlib;
namespace bthost {
Host::Host(const bt_hci_protocol_t& hci_proto) : hci_proto_(hci_proto) {}
Host::~Host() {}
bool Host::Initialize(InitCallback callback) {
auto dev = std::make_unique<hci::DdkDeviceWrapper>(hci_proto_);
auto hci = hci::Transport::Create(std::move(dev));
if (!hci)
return false;
FXL_VLOG(1) << "bt-host: initializing HCI";
if (!hci->Initialize()) {
FXL_LOG(ERROR) << "bt-host: failed to initialize HCI transport";
return false;
}
l2cap_ = l2cap::L2CAP::Create(hci, "bt-host (l2cap)");
if (!l2cap_)
return false;
gatt_host_ = GattHost::Create("bt-host (gatt)");
if (!gatt_host_)
return false;
gap_ = std::make_unique<gap::Adapter>(hci, l2cap_, gatt_host_->profile());
if (!gap_)
return false;
FXL_DCHECK(thread_checker_.IsCreationThreadCurrent());
FXL_DCHECK(l2cap_);
// Called when the GAP layer is ready. We initialize L2CAP and the GATT
// profile after initial setup in GAP (which sets up ACL data).
auto gap_init_callback = [l2cap = l2cap_, gatt_host = gatt_host_,
callback = std::move(callback)](bool success) {
FXL_VLOG(1) << "bt-host: GAP initialized";
if (success) {
l2cap->Initialize();
gatt_host->Initialize();
}
callback(success);
};
FXL_VLOG(1) << "bt-host: initializing GAP";
return gap_->Initialize(std::move(gap_init_callback), [] {
FXL_VLOG(1) << "bt-host: HCI transport has closed";
});
}
void Host::ShutDown() {
FXL_DCHECK(thread_checker_.IsCreationThreadCurrent());
FXL_VLOG(1) << "bt-host: shutting down";
// Closes all FIDL channels owned by |host_server_|.
host_server_ = nullptr;
// This shuts down the GATT profile and L2CAP and all of their clients.
gatt_host_->ShutDown();
l2cap_->ShutDown();
// Make sure that |gap_| gets shut down and destroyed on its creation thread
// as it is not thread-safe.
gap_ = nullptr;
}
void Host::BindHostInterface(zx::channel channel) {
FXL_DCHECK(thread_checker_.IsCreationThreadCurrent());
if (host_server_) {
FXL_LOG(WARNING) << "bt-host: Host interface channel already open!";
return;
}
FXL_DCHECK(gap_);
FXL_DCHECK(gatt_host_);
host_server_ = std::make_unique<HostServer>(std::move(channel),
gap_->AsWeakPtr(), gatt_host_);
host_server_->set_error_handler([this] {
FXL_DCHECK(host_server_);
FXL_VLOG(1) << "bt-host: Host interface disconnected";
host_server_ = nullptr;
});
}
} // namespace bthost