// 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 "src/acpi_multiply/test_acpi_implementation.h"

#include <fidl/fuchsia.component.decl/cpp/wire_types.h>
#include <fidl/fuchsia.driver.framework/cpp/wire.h>
#include <fidl/fuchsia.hardware.acpi/cpp/wire_types.h>
#include <fidl/fuchsia.mem/cpp/wire_types.h>
#include <lib/async/cpp/task.h>
#include <lib/driver2/record_cpp.h>
#include <lib/driver2/structured_logger.h>
#include <lib/fidl/cpp/wire/connect_service.h>
#include <lib/zx/clock.h>
#include <zircon/errors.h>
#include <zircon/syscalls.h>
#include <zircon/types.h>

#include "registers.h"

namespace fdf {
using namespace fuchsia_driver_framework;
}  // namespace fdf

namespace test_acpi_implementation {

namespace fcd = fuchsia_component_decl::wire;
namespace facpi = fuchsia_hardware_acpi::wire;

zx::status<std::unique_ptr<TestAcpiImplementation>> TestAcpiImplementation::Start(
    fuchsia_driver_framework::wire::DriverStartArgs &start_args, fdf::UnownedDispatcher dispatcher,
    fidl::WireSharedClient<fuchsia_driver_framework::Node> node, driver::Namespace ns,
    driver::Logger logger) {
  auto driver = std::make_unique<TestAcpiImplementation>(
      dispatcher->async_dispatcher(), std::move(node), std::move(ns), std::move(logger));

  auto result = driver->Run(std::move(start_args.outgoing_dir()));
  if (result.is_error()) {
    return result.take_error();
  }

  return zx::ok(std::move(driver));
}

zx::status<> TestAcpiImplementation::Run(fidl::ServerEnd<fuchsia_io::Directory> outgoing_dir) {
  zx::vmo vmo;
  zx_status_t raw_status = zx::vmo::create(zx_system_get_page_size(), 0, &vmo);
  if (raw_status != ZX_OK) {
    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()) {
    return buffer.take_error();
  }
  buffer_ = std::move(buffer.value());

  raw_status = zx::interrupt::create(zx::resource(), 0, ZX_INTERRUPT_VIRTUAL, &irq_);
  if (raw_status != ZX_OK) {
    return zx::error(raw_status);
  }

  auto service = [this](fidl::ServerEnd<fuchsia_hardware_acpi::Device> server_end) {
    fidl::BindServer(dispatcher_, std::move(server_end), this);
  };

  auto status = outgoing_.AddProtocol<fuchsia_hardware_acpi::Device>(std::move(service));
  if (status.is_error()) {
    FDF_SLOG(ERROR, "Failed to add protocol", KV("status", status.status_string()));
    return status;
  }

  status = AddChild();
  if (status.is_error()) {
    return status;
  }

  return outgoing_.Serve(std::move(outgoing_dir));
}

zx::status<> TestAcpiImplementation::AddChild() {
  fidl::Arena arena;

  // Offer fuchsia.hardware.acpi.Device to the driver that binds to the node.
  auto protocol_offer =
      fcd::OfferProtocol::Builder(arena)
          .source_name(arena, fidl::DiscoverableProtocolName<fuchsia_hardware_acpi::Device>)
          .target_name(arena, fidl::DiscoverableProtocolName<fuchsia_hardware_acpi::Device>)
          .dependency_type(fcd::DependencyType::kStrong)
          .Build();
  fcd::Offer offer = fcd::Offer::WithProtocol(arena, protocol_offer);

  // Set the properties of the node that a driver will bind to.
  auto properties = fidl::VectorView<fdf::wire::NodeProperty>(arena, 2);
  properties[0] = fdf::wire::NodeProperty::Builder(arena)
                      .key(fdf::wire::NodePropertyKey::WithIntValue(1 /* BIND_PROTOCOL */))
                      .value(fdf::wire::NodePropertyValue::WithIntValue(30 /* ZX_PROTOCOL_ACPI */))
                      .Build();

  properties[1] = fdf::wire::NodeProperty::Builder(arena)
                      .key(fdf::wire::NodePropertyKey::WithStringValue(
                          arena, fidl::StringView::FromExternal("fuchsia.acpi.hid")))
                      .value(fdf::wire::NodePropertyValue::WithStringValue(
                          arena, fidl::StringView::FromExternal("FDFS0001")))
                      .Build();

  auto args = fdf::wire::NodeAddArgs::Builder(arena)
                  .name(arena, "acpi-child")
                  .offers(fidl::VectorView<fcd::Offer>::FromExternal(&offer, 1))
                  .properties(properties)
                  .Build();

  // Create endpoints of the `NodeController` for the node.
  auto endpoints = fidl::CreateEndpoints<fdf::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());
  }

  return zx::ok();
}

void TestAcpiImplementation::GetMmio(GetMmioRequestView request,
                                     GetMmioCompleter::Sync &completer) {
  if (request->index != 0) {
    completer.ReplyError(ZX_ERR_OUT_OF_RANGE);
    return;
  }

  zx::vmo clone;
  zx_status_t status = buffer_->get_vmo()->duplicate(ZX_RIGHT_SAME_RIGHTS, &clone);
  if (status != ZX_OK) {
    completer.ReplyError(status);
    return;
  }

  completer.ReplySuccess(fuchsia_mem::wire::Range{
      .vmo = std::move(clone),
      .offset = 0,
      .size = zx_system_get_page_size(),
  });
}

void TestAcpiImplementation::MapInterrupt(MapInterruptRequestView request,
                                          MapInterruptCompleter::Sync &completer) {
  if (request->index != 0) {
    completer.ReplyError(ZX_ERR_OUT_OF_RANGE);
    return;
  }

  zx::interrupt clone;
  zx_status_t status = irq_.duplicate(ZX_RIGHT_SAME_RIGHTS, &clone);
  if (status != ZX_OK) {
    completer.ReplyError(status);
    return;
  }

  completer.ReplySuccess(std::move(clone));
}

void TestAcpiImplementation::EvaluateObject(EvaluateObjectRequestView request,
                                            EvaluateObjectCompleter::Sync &completer) {
  if (request->mode != facpi::EvaluateObjectMode::kPlainObject) {
    completer.ReplyError(facpi::Status::kNotSupported);
    return;
  }

  if (request->path.get() != "_MUL") {
    completer.ReplyError(facpi::Status::kNotFound);
    return;
  }

  fidl::Arena arena;
  completer.ReplySuccess(facpi::EncodedObject());
  // To simulate asynchronous hardware, we post a delayed task and trigger an interrupt when the
  // task is complete.
  async::PostDelayedTask(
      dispatcher_,
      [this]() mutable {
        auto value1 = acpi_multiply::MultiplyArgumentReg::Get(true).ReadFrom(&buffer_.value());
        auto value2 = acpi_multiply::MultiplyArgumentReg::Get(false).ReadFrom(&buffer_.value());
        auto status_reg = acpi_multiply::MultiplyStatusReg::Get().FromValue(0);
        auto result_reg = acpi_multiply::MultiplyResultReg::Get().FromValue(0);

        uint32_t result = value1.operand() * value2.operand();
        // Check for overflow
        if (value1.operand() != 0 && result / value1.operand() != value2.operand()) {
          status_reg.set_overflow(true);
        }
        result_reg.set_result(result);
        result_reg.WriteTo(&buffer_.value());
        status_reg.set_finished(true).WriteTo(&buffer_.value());
        zx_status_t status = irq_.trigger(0, zx::clock::get_monotonic());
        if (status != ZX_OK) {
          FDF_SLOG(ERROR, "Failed to trigger interrupt",
                   KV("status", zx_status_get_string(status)));
        }
      },
      zx::msec(10));
}

}  // namespace test_acpi_implementation

FUCHSIA_DRIVER_RECORD_CPP_V1(test_acpi_implementation::TestAcpiImplementation);
