// 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.

// [START imports]
#include "qemu_edu.h"
// [END imports]

// [START compat_imports]
#include <lib/driver/component/cpp/service_client.h>
// [END compat_imports]

// [START fidl_imports]
#include "edu_server.h"
// [END fidl_imports]

// [START namespace_start]
namespace qemu_edu {
// [END namespace_start]

// [START start_method_start]
// Initialize this driver instance
zx::result<> QemuEduDriver::Start() {
  // [END start_method_start]
  // [START connect_device]
  // Connect to the parent device node.
  auto compat_parent =
      driver::Connect<fuchsia_driver_compat::Service::Device>(*context().incoming());
  if (compat_parent.is_error()) {
    FDF_SLOG(ERROR, "Failed to connect to compat", KV("status", compat_parent.status_string()));
    return compat_parent.take_error();
  }

  auto parent = fidl::WireSyncClient(std::move(compat_parent.value()));

  // Connect to fuchsia.hardware.pci FIDL protocol from the parent device
  auto pci_endpoints = fidl::CreateEndpoints<fuchsia_hardware_pci::Device>();
  if (pci_endpoints.is_error()) {
    return pci_endpoints.take_error();
  }

  auto connect_result = parent->ConnectFidl(
      fidl::StringView::FromExternal(fidl::DiscoverableProtocolName<fuchsia_hardware_pci::Device>),
      pci_endpoints->server.TakeChannel());

  if (!connect_result.ok()) {
    return zx::error(connect_result.status());
  }
  // [END connect_device]

  // [START hw_resources]
  // Map hardware resources from the PCI device
  device_ = std::make_shared<edu_device::QemuEduDevice>(&logger(), dispatcher(),
                                                        std::move(pci_endpoints->client));
  auto pci_status = device_->MapInterruptAndMmio();
  if (pci_status.is_error()) {
    return pci_status.take_error();
  }
  // [END hw_resources]

  // [START device_registers]
  // Report the version information from the edu device.
  auto version_reg = device_->IdentificationRegister();
  FDF_SLOG(INFO, "edu device version", KV("major", version_reg.major_version()),
           KV("minor", version_reg.minor_version()));
  // [END device_registers]

  // [START serve_outgoing]
  // Serve the examples.qemuedu/Service capability.
  component::ServiceInstanceHandler handler;
  examples_qemuedu::Service::Handler service(&handler);

  auto result =
      service.add_device([this](fidl::ServerEnd<examples_qemuedu::Device> request) -> void {
        QemuEduServer::BindDeviceClient(&logger(), dispatcher(), device_, std::move(request));
      });
  ZX_ASSERT(result.is_ok());

  result = context().outgoing()->AddService<examples_qemuedu::Service>(std::move(handler));
  if (result.is_error()) {
    FDF_SLOG(ERROR, "Failed to add Device service", KV("status", result.status_string()));
    return result.take_error();
  }
  // [END serve_outgoing]

  // [START devfs_export]
  // Create and export a devfs entry for the driver service.
  compat::Context::ConnectAndCreate(
      &context(), dispatcher(),
      [this](zx::result<std::unique_ptr<compat::Context>> result) mutable {
        if (result.is_error()) {
          FDF_SLOG(ERROR, "Failed to get compat::Context", KV("status", result.status_string()));
          // Reset the node to signal unbind to the driver framework.
          node().reset();
          return;
        }
        compat_context_ = std::move(result.value());

        // Construct a devfs path that matches the device nodes topological path
        auto devfs_path = compat_context_->TopologicalPath(name());
        auto service_path = std::string(examples_qemuedu::Service::Name) + "/" +
                            component::kDefaultInstance + "/" +
                            examples_qemuedu::Service::Device::Name;

        // Export an entry to devfs for examples.qemuedu as a generic device
        auto status = compat_context_->devfs_exporter().ExportSync(
            service_path, devfs_path, fuchsia_device_fs::ExportOptions(), 0);
        if (status != ZX_OK) {
          FDF_SLOG(ERROR, "Failed to export to devfs: %s",
                   KV("status", zx_status_get_string(status)));
          // Reset the node to signal unbind to the driver framework.
          node().reset();
          return;
        }

        FDF_SLOG(INFO, "Exported", KV("service_path", service_path.c_str()),
                 KV("devfs_path", devfs_path.c_str()));
      });
  // [END devfs_export]

  // [START start_method_end]
  return zx::ok();
}
// [END start_method_end]

// [START namespace_end]
}  // namespace qemu_edu
// [END namespace_end]

// [START driver_hook]
// Register driver hooks with the framework
FUCHSIA_DRIVER_RECORD_CPP_V2(driver::Record<qemu_edu::QemuEduDriver>);
// [END driver_hook]
