// 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.
  examples_qemuedu::Service::InstanceHandler handler({
    .device = [this](fidl::ServerEnd<examples_qemuedu::Device> request) -> void {
        QemuEduServer::BindDeviceClient(&logger(), dispatcher(), device_, std::move(request));
      }
  });

  auto 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]
