// 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/driver2/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.
  driver::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::status<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]
