// 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 <fidl/fuchsia.hardware.acpi/cpp/wire_types.h>
#include <fidl/sample.acpi.multiply/cpp/wire_types.h>
#include <lib/async/cpp/irq.h>
#include <lib/async/cpp/task.h>
#include <lib/driver2/record_cpp.h>
#include <lib/driver2/structured_logger.h>
#include <lib/mmio/mmio-buffer.h>
#include <zircon/errors.h>
#include <zircon/types.h>

#include "registers.h"

namespace acpi_multiply {

zx::status<std::unique_ptr<AcpiMultiplyDriver>> AcpiMultiplyDriver::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<AcpiMultiplyDriver>(
      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<> AcpiMultiplyDriver::Run(fidl::ServerEnd<fuchsia_io::Directory> outgoing_dir) {
  auto status = outgoing_.AddProtocol<sample_acpi_multiply::Device>(this, Name());
  if (status.is_error()) {
    FDF_SLOG(ERROR, "Failed to add protocol", KV("status", status.status_string()));
    return status.take_error();
  }

  // Connect to the ACPI protocol exposed by the parent driver.
  auto client = ns_.Connect<fuchsia_hardware_acpi::Device>();
  if (client.is_error()) {
    FDF_SLOG(ERROR, "Failed to connect to ACPI", KV("status", client.status_string()));
    return client.take_error();
  }
  acpi_.Bind(std::move(client.value()));

  // Get interrupt.
  auto irq_result = acpi_->MapInterrupt(0);
  if (!irq_result.ok() || irq_result->is_error()) {
    return irq_result.ok() ? irq_result->take_error() : zx::error(irq_result.error().status());
  }

  irq_ = std::move(irq_result->value()->irq);
  // Start listening for interrupts.
  irq_method_.set_object(irq_.get());
  irq_method_.Begin(dispatcher_);

  // Get MMIO region.
  auto mmio_result = acpi_->GetMmio(0);
  if (!mmio_result.ok() || mmio_result->is_error()) {
    return mmio_result.ok() ? mmio_result->take_error() : zx::error(mmio_result.error().status());
  }

  auto& mmio = mmio_result->value()->mmio;
  auto buf_result = fdf::MmioBuffer::Create(mmio.offset, mmio.size, std::move(mmio.vmo),
                                            ZX_CACHE_POLICY_UNCACHED_DEVICE);
  if (buf_result.is_error()) {
    return buf_result.take_error();
  }
  mmio_ = std::move(buf_result.value());

  // 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<sample_acpi_multiply::Device>();
    if (endpoints.is_error()) {
      FDF_LOG(ERROR, "Failed to create endpoints");
      return;
    }

    fidl::BindServer(dispatcher_, std::move(endpoints->server), this);
    client_.Bind(std::move(endpoints->client), dispatcher_);
    // Do the multiply
    client_->Multiply(UINT32_MAX, 9)
        .Then([this](fidl::WireUnownedResult<sample_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<sample_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();
}

// Protocol method in `sample.acpi.multiply` to execute a multiply operation
void AcpiMultiplyDriver::Multiply(MultiplyRequestView request, MultiplyCompleter::Sync& completer) {
  std::scoped_lock lock(completer_lock_);
  // Queue operations if there is already one in-flight.
  if (cur_completer_.has_value()) {
    operation_queue_.emplace_back(Operation{
        .a = request->a,
        .b = request->b,
        .completer = completer.ToAsync(),
    });
    return;
  }

  DoMultiply(Operation{
      .a = request->a,
      .b = request->b,
      .completer = completer.ToAsync(),
  });
}

// Call the underlying hardware resources (MMIO, Interrupt) to perform a multiply operation.
void AcpiMultiplyDriver::DoMultiply(Operation operation) {
  // Write the operands to the two MMIO registers.
  MultiplyArgumentReg::Get(true).FromValue(0).set_operand(operation.a).WriteTo(&mmio_.value());
  MultiplyArgumentReg::Get(false).FromValue(0).set_operand(operation.b).WriteTo(&mmio_.value());

  cur_completer_ = std::move(operation.completer);
  fidl::Arena arena;
  // Call the ACPI method that will trigger the multiply operation.
  auto result =
      acpi_->EvaluateObject(fidl::StringView::FromExternal("_MUL"),
                            fuchsia_hardware_acpi::wire::EvaluateObjectMode::kPlainObject,
                            fidl::VectorView<fuchsia_hardware_acpi::wire::Object>(arena, 0));
  if (!result.ok() || result->is_error()) {
    FDF_SLOG(ERROR, "Failed to send EvaluateObject",
             KV("error", (const char*)(result.ok() ? std::to_string(result->error_value()).data()
                                                   : result.FormatDescription().data())));
    cur_completer_->ReplyError(ZX_ERR_INTERNAL);
    cur_completer_ = std::nullopt;
    return;
  }

  // We will receive an interrupt when the operation is done.
}

// Callback when the ACPI device raises an interrupt, signaling the multiply operation is complete.
void AcpiMultiplyDriver::HandleIrq(async_dispatcher_t* dispatcher, async::IrqBase* irq,
                                   zx_status_t status, const zx_packet_interrupt_t* interrupt) {
  irq_.ack();
  std::scoped_lock lock(completer_lock_);
  if (!cur_completer_.has_value()) {
    FDF_LOG(ERROR, "Spurious interrupt!");
    return;
  }
  auto completer = std::move(cur_completer_.value());
  cur_completer_ = std::nullopt;
  if (status != ZX_OK) {
    FDF_SLOG(ERROR, "Failed to wait for interrupt", KV("status", zx_status_get_string(status)));
    completer.ReplyError(status);
    return;
  }

  auto status_reg = MultiplyStatusReg::Get().ReadFrom(&mmio_.value());
  if (!status_reg.finished()) {
    FDF_LOG(ERROR, "Interrupt came too soon!");
    completer.ReplyError(ZX_ERR_BAD_STATE);
    return;
  }

  auto result = MultiplyResultReg::Get().ReadFrom(&mmio_.value());
  completer.ReplySuccess(result.result(), status_reg.overflow());

  // Start the next operation if there is one.
  if (!operation_queue_.empty()) {
    DoMultiply(std::move(operation_queue_.front()));
    operation_queue_.pop_front();
  }
}

}  // namespace acpi_multiply

FUCHSIA_DRIVER_RECORD_CPP_V1(acpi_multiply::AcpiMultiplyDriver);
