blob: 58d286812e00c16d7ab6853b86116d7942b59100 [file] [log] [blame]
// 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]