blob: 422c8ca42dedb789cf3f6eab54cdf4db1ee2a43a [file] [log] [blame]
// Copyright 2022 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 "i2c_controller.h"
// [START bind_imports]
#include <bind/fuchsia/hardware/i2c/cpp/bind.h>
// [END bind_imports]
namespace i2c_temperature {
zx::result<> I2cTemperatureController::Start() {
node_.Bind(std::move(node()), dispatcher());
i2c_server_ = std::make_shared<I2cDeviceServer>(&logger());
// Serve the fuchsia.hardware.i2c/Device protocol to clients through the
// fuchsia.hardware.i2c/Service wrapper.
driver::ServiceInstanceHandler handler;
fuchsia_hardware_i2c::Service::Handler service(&handler);
auto result =
service.add_device([this](fidl::ServerEnd<fuchsia_hardware_i2c::Device> request) -> void {
I2cDeviceServer::BindDeviceClient(i2c_server_, dispatcher(), std::move(request));
});
if (result.is_error()) {
return result.take_error();
}
result = context().outgoing()->AddService<fuchsia_hardware_i2c::Service>(std::move(handler));
if (result.is_error()) {
FDF_SLOG(ERROR, "Failed to add service", KV("status", result.status_string()));
return result.take_error();
}
// Initialize the driver compat service context.
compat::Context::ConnectAndCreate(
&context(), dispatcher(),
fit::bind_member<&I2cTemperatureController::InitializeCompatService>(this));
return zx::ok();
}
zx::result<> I2cTemperatureController::AddChild() {
fidl::Arena arena;
// Offer `fuchsia.driver.compat.Service` to drivers that bind to the node.
auto offers = child_->CreateOffers(arena);
// [START add_child_offer]
// Offer `fuchsia.hardware.i2c.Device` to drivers that bind to the node.
auto service_offer =
driver::MakeOffer<fuchsia_hardware_i2c::Service>(arena, component::kDefaultInstance);
// [END add_child_offer]
offers.push_back(service_offer);
// [START add_child_properties]
// Set the properties of the node for drivers to target.
auto properties = fidl::VectorView<fuchsia_driver_framework::wire::NodeProperty>(arena, 2);
properties[0] = driver::MakeEnumProperty(arena, bind_fuchsia_hardware_i2c::SERVICE,
bind_fuchsia_hardware_i2c::SERVICE_ZIRCONTRANSPORT);
properties[1] = driver::MakeProperty(arena, 0x0A02 /* BIND_I2C_ADDRESS */, 0xff);
// [END add_child_properties]
// [START add_child_node]
auto args = fuchsia_driver_framework::wire::NodeAddArgs::Builder(arena)
.name(arena, "i2c-child")
.offers(offers)
.properties(properties)
.Build();
// Create endpoints of the `NodeController` for the node.
auto endpoints = fidl::CreateEndpoints<fuchsia_driver_framework::NodeController>();
if (endpoints.is_error()) {
FDF_SLOG(ERROR, "Failed to create endpoint", KV("status", endpoints.status_string()));
return zx::error(endpoints.status_value());
}
auto result = node_.sync()->AddChild(args, std::move(endpoints->server), {});
if (!result.ok()) {
FDF_SLOG(ERROR, "Failed to add child", KV("status", result.status_string()));
return zx::error(result.status());
}
controller_.Bind(std::move(endpoints->client), dispatcher());
// [END add_child_node]
return zx::ok();
}
// Construct and serve the `fuchsia.driver.compat.Service` after the context is initialized.
void I2cTemperatureController::InitializeCompatService(
zx::result<std::shared_ptr<compat::Context>> compat_result) {
if (!compat_result.is_ok()) {
FDF_SLOG(ERROR, "Failed to create compat context.",
KV("status", compat_result.status_string()));
node().reset();
return;
}
compat_context_ = std::move(*compat_result);
// Publish `fuchsia.driver.compat.Service` to the outgoing directory.
child_ = compat::DeviceServer(std::string(name()), 0, compat_context_->TopologicalPath(name()));
auto status = child_->Serve(dispatcher(), context().outgoing().get());
if (status != ZX_OK) {
FDF_SLOG(ERROR, "Failed to serve compat device server.",
KV("status", zx_status_get_string(status)));
node().reset();
return;
}
// Create a child node and offer capabilities to bound drivers.
auto result = AddChild();
if (!result.is_ok()) {
FDF_SLOG(ERROR, "Failed to create child node.", KV("status", result.status_string()));
node().reset();
return;
}
}
} // namespace i2c_temperature
FUCHSIA_DRIVER_RECORD_CPP_V2(driver::Record<i2c_temperature::I2cTemperatureController>);