| // 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_multiply.h" |
| |
| #include <fidl/fuchsia.hardware.acpi/cpp/wire.h> |
| #include <lib/async/cpp/task.h> |
| #include <lib/driver2/service_client.h> |
| |
| #include "multiply_server.h" |
| |
| namespace acpi_multiply { |
| |
| zx::result<> AcpiMultiplyDriver::Start() { |
| // Connect to the ACPI protocol exposed by the parent driver. |
| auto client_endpoint = |
| driver::Connect<fuchsia_hardware_acpi::Service::Device>(*context().incoming(), "default"); |
| if (client_endpoint.is_error()) { |
| FDF_SLOG(ERROR, "Failed to connect to ACPI", KV("status", client_endpoint.status_string())); |
| return client_endpoint.take_error(); |
| } |
| auto acpi_client = fidl::WireSyncClient(std::move(*client_endpoint)); |
| |
| // Initialize ACPI hardware resources |
| multiplier_ = std::make_shared<AcpiMultiplier>(&logger(), dispatcher(), std::move(acpi_client)); |
| auto init_result = multiplier_->SetupMmioAndInterrupts(); |
| if (init_result.is_error()) { |
| FDF_SLOG(ERROR, "Failed to initialize ACPI resources.", |
| KV("status", init_result.status_string())); |
| return init_result.take_error(); |
| } |
| |
| // Serve the fuchsia.examples.acpi.multiply/Device protocol to clients through the |
| // fuchsia.examples.acpi.multiply/Service wrapper. |
| driver::ServiceInstanceHandler handler; |
| fuchsia_examples_acpi_multiply::Service::Handler service(&handler); |
| |
| auto result = service.add_device( |
| [this](fidl::ServerEnd<fuchsia_examples_acpi_multiply::Device> request) -> void { |
| AcpiMultiplyServer::BindDeviceClient(&logger(), dispatcher(), multiplier_, |
| std::move(request)); |
| }); |
| ZX_ASSERT(result.is_ok()); |
| |
| result = |
| context().outgoing()->AddService<fuchsia_examples_acpi_multiply::Service>(std::move(handler)); |
| if (result.is_error()) { |
| FDF_SLOG(ERROR, "Failed to add service", KV("status", result.status_string())); |
| return result.take_error(); |
| } |
| |
| // This is not strictly necessary, but it does a multiplication to prove that the driver |
| // behaves as expected. |
| async::PostTask(dispatcher(), [this]() { |
| auto endpoints = fidl::CreateEndpoints<fuchsia_examples_acpi_multiply::Device>(); |
| if (endpoints.is_error()) { |
| FDF_LOG(ERROR, "Failed to create endpoints"); |
| return; |
| } |
| |
| auto server_impl = std::make_unique<AcpiMultiplyServer>(&logger(), multiplier_); |
| fidl::BindServer(dispatcher(), std::move(endpoints->server), std::move(server_impl), |
| std::mem_fn(&AcpiMultiplyServer::OnUnbound)); |
| client_.Bind(std::move(endpoints->client), dispatcher()); |
| // Do the multiply |
| client_->Multiply(UINT32_MAX, 9) |
| .Then([this](fidl::WireUnownedResult<fuchsia_examples_acpi_multiply::Device::Multiply>& |
| response) { |
| if (response.ok() && response->is_ok()) { |
| FDF_SLOG(INFO, "UINT32_MAX*9: Got result", |
| KV("result", response.value().value()->result), |
| KV("overflowed", response.value().value()->overflowed)); |
| } else { |
| FDF_SLOG(ERROR, "Multiply failed", |
| KV("fidl status", (const char*)response.FormatDescription().data()), |
| KV("device status", |
| (const char*)(response.ok() ? response.status_string() : "N/A"))); |
| } |
| }); |
| client_->Multiply(2, 9).Then( |
| [this]( |
| fidl::WireUnownedResult<fuchsia_examples_acpi_multiply::Device::Multiply>& response) { |
| if (response.ok() && response->is_ok()) { |
| FDF_SLOG(INFO, "2*9: Got result", KV("result", response.value().value()->result), |
| KV("overflowed", response.value().value()->overflowed)); |
| } else { |
| FDF_SLOG(ERROR, "Multiply failed", |
| KV("fidl status", (const char*)response.FormatDescription().data()), |
| KV("device status", |
| (const char*)(response.ok() ? response.status_string() : "N/A"))); |
| } |
| }); |
| }); |
| return zx::ok(); |
| } |
| |
| } // namespace acpi_multiply |
| |
| FUCHSIA_DRIVER_RECORD_CPP_V2(driver::Record<acpi_multiply::AcpiMultiplyDriver>); |