blob: 0426a7bc2085319988a5037879843e0f818cc49e [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 "acpi_controller.h"
#include <bind/fuchsia/acpi/cpp/bind.h>
#include <bind/fuchsia/hardware/acpi/cpp/bind.h>
namespace acpi_multiply {
zx::result<> AcpiMultiplyController::Start() {
node_.Bind(std::move(node()));
auto server_result = InitializeServer();
if (server_result.is_error()) {
FDF_SLOG(ERROR, "Failed to initialize ACPI Server.",
KV("status", server_result.status_string()));
return server_result.take_error();
}
// Serve the fuchsia.hardware.acpi/Device protocol to clients through the
// fuchsia.hardware.acpi/Service wrapper.
component::ServiceInstanceHandler handler;
fuchsia_hardware_acpi::Service::Handler service(&handler);
auto result =
service.add_device([this](fidl::ServerEnd<fuchsia_hardware_acpi::Device> request) -> void {
AcpiDeviceServer::BindDeviceClient(server_, dispatcher(), std::move(request));
});
if (result.is_error()) {
return result.take_error();
}
result = context().outgoing()->AddService<fuchsia_hardware_acpi::Service>(std::move(handler));
if (result.is_error()) {
FDF_SLOG(ERROR, "Failed to add service.", KV("status", result.status_string()));
return result.take_error();
}
// Publish `fuchsia.driver.compat.Service` to the outgoing directory.
child_ = compat::DeviceServer(std::string(name()), 0, std::string(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)));
return zx::error(status);
}
// Create a child node and offer capabilities to bound drivers.
result = AddChild();
if (!result.is_ok()) {
FDF_SLOG(ERROR, "Failed to create child node.", KV("status", result.status_string()));
return result.take_error();
}
return zx::ok();
}
zx::result<> AcpiMultiplyController::InitializeServer() {
// Allocate an MMIO buffer representing the ACPI multiply device
zx::vmo vmo;
zx_status_t raw_status = zx::vmo::create(zx_system_get_page_size(), 0, &vmo);
if (raw_status != ZX_OK) {
FDF_SLOG(ERROR, "Failed to create vmo.", KV("status", zx_status_get_string(raw_status)));
return zx::error(raw_status);
}
auto buffer = fdf::MmioBuffer::Create(0, zx_system_get_page_size(), std::move(vmo),
ZX_CACHE_POLICY_UNCACHED_DEVICE);
if (buffer.is_error()) {
FDF_SLOG(ERROR, "Failed to create mmio buffer.", KV("status", buffer.status_string()));
return buffer.take_error();
}
// Create an IRQ resource for the ACPI multiply device
zx::interrupt irq;
raw_status = zx::interrupt::create(zx::resource(), 0, ZX_INTERRUPT_VIRTUAL, &irq);
if (raw_status != ZX_OK) {
FDF_SLOG(ERROR, "Failed to create interrupt.", KV("status", zx_status_get_string(raw_status)));
return zx::error(raw_status);
}
server_ = std::make_shared<AcpiDeviceServer>(std::move(irq), std::move(buffer.value()), &logger(),
dispatcher());
return zx::ok();
}
zx::result<> AcpiMultiplyController::AddChild() {
fidl::Arena arena;
auto offers = child_->CreateOffers(arena);
// Offer fuchsia.hardware.acpi.Service to the driver that binds to the node.
auto service_offer =
driver::MakeOffer<fuchsia_hardware_acpi::Service>(arena, component::kDefaultInstance);
offers.push_back(service_offer);
// Set the properties of the node that a driver binds to.
auto properties = fidl::VectorView<fuchsia_driver_framework::wire::NodeProperty>(arena, 2);
properties[0] = driver::MakeProperty(arena, bind_fuchsia_hardware_acpi::SERVICE,
bind_fuchsia_hardware_acpi::SERVICE_ZIRCONTRANSPORT);
properties[1] = driver::MakeProperty(arena, bind_fuchsia_acpi::HID, "FDFS0001");
auto args = fuchsia_driver_framework::wire::NodeAddArgs::Builder(arena)
.name(arena, "acpi-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 endpoints.take_error();
}
auto result = node_->AddChild(args, std::move(endpoints->server), {});
if (!result.ok()) {
FDF_SLOG(ERROR, "Failed to add child.", KV("error_desc", result.FormatDescription().c_str()));
return zx::error(result.status());
}
if (result->is_error()) {
FDF_SLOG(ERROR, "Failed to add child.",
KV("status", std::to_string(static_cast<uint32_t>(result->error_value())).c_str()));
return zx::error(ZX_ERR_INTERNAL);
}
controller_.Bind(std::move(endpoints->client));
return zx::ok();
}
} // namespace acpi_multiply
FUCHSIA_DRIVER_RECORD_CPP_V2(driver::Record<acpi_multiply::AcpiMultiplyController>);