blob: 20fde167b786bbf229086476f06d519cd55e5722 [file] [log] [blame] [edit]
// Copyright 2023 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 "sdk/lib/driver/devicetree/node.h"
#include <fidl/fuchsia.driver.framework/cpp/fidl.h>
#include <fidl/fuchsia.hardware.platform.bus/cpp/fidl.h>
#include <lib/driver/logging/cpp/logger.h>
#include <string>
#include <bind/fuchsia/platform/cpp/bind.h>
#include <sdk/lib/driver/component/cpp/composite_node_spec.h>
#include <sdk/lib/driver/legacy-bind-constants/legacy-bind-constants.h>
namespace fdf {
using namespace fuchsia_driver_framework;
}
namespace fdf_devicetree {
Node::Node(const std::string_view name, devicetree::Properties properties, uint32_t id)
: name_(name), id_(id) {
pbus_node_.did() = bind_fuchsia_platform::BIND_PLATFORM_DEV_DID_DEVICETREE;
pbus_node_.vid() = bind_fuchsia_platform::BIND_PLATFORM_DEV_VID_GENERIC;
pbus_node_.instance_id() = id;
pbus_node_.name() = std::string(name_);
for (auto property : properties) {
properties_.emplace(property.name, property.value);
}
}
void Node::AddBindProperty(fuchsia_driver_framework::NodeProperty prop) {
node_properties_.emplace_back(std::move(prop));
}
void Node::AddMmio(fuchsia_hardware_platform_bus::Mmio mmio) {
if (!pbus_node_.mmio()) {
pbus_node_.mmio() = std::vector<fuchsia_hardware_platform_bus::Mmio>();
}
pbus_node_.mmio()->emplace_back(std::move(mmio));
}
zx::result<> Node::Publish(fdf::WireSyncClient<fuchsia_hardware_platform_bus::PlatformBus> &pbus,
fidl::SyncClient<fuchsia_driver_framework::CompositeNodeManager> &mgr) {
if (node_properties_.empty()) {
FDF_LOG(DEBUG, "Not publishing node '%.*s' because it has no bind properties.",
(int)name().size(), name().data());
return zx::ok();
}
// Pass properties to pbus node directly if we are not adding a composite spec.
if (!composite_) {
pbus_node_.properties() = node_properties_;
}
FDF_LOG(DEBUG, "Adding node '%.*s' to pbus.", (int)name().size(), name().data());
fdf::Arena arena('PBUS');
fidl::Arena fidl_arena;
auto result = pbus.buffer(arena)->NodeAdd(fidl::ToWire(fidl_arena, pbus_node_));
if (!result.ok()) {
FDF_LOG(ERROR, "NodeAdd request failed: %s", result.FormatDescription().data());
return zx::error(result.status());
}
if (result->is_error()) {
FDF_LOG(ERROR, "NodeAdd failed: %s", zx_status_get_string(result->error_value()));
return zx::error(result->error_value());
}
// Add composite node spec if composite.
if (composite_) {
// Construct the platform bus node.
fdf::ParentSpec platform_node;
platform_node.properties() = std::vector<fdf::NodeProperty>(node_properties_);
platform_node.properties().emplace_back(fdf::NodeProperty{{
.key = fdf::NodePropertyKey::WithIntValue(BIND_PROTOCOL),
.value = fdf::NodePropertyValue::WithIntValue(bind_fuchsia_platform::BIND_PROTOCOL_DEVICE),
}});
platform_node.bind_rules() = std::vector<fdf::BindRule>{
fdf::MakeAcceptBindRule(BIND_PLATFORM_DEV_VID,
bind_fuchsia_platform::BIND_PLATFORM_DEV_VID_GENERIC),
fdf::MakeAcceptBindRule(BIND_PLATFORM_DEV_DID,
bind_fuchsia_platform::BIND_PLATFORM_DEV_DID_DEVICETREE),
fdf::MakeAcceptBindRule(BIND_PLATFORM_DEV_INSTANCE_ID, id_),
};
// pbus node is always the primary parent for now.
parents_.insert(parents_.begin(), std::move(platform_node));
fdf::CompositeNodeSpec group;
std::string name_final(name());
// '@' is not a valid character in Node names as per driver framework.
std::replace(name_final.begin(), name_final.end(), '@', '-');
group.name() = name_final;
group.parents() = std::move(parents_);
auto devicegroup_result = mgr->AddSpec({std::move(group)});
if (devicegroup_result.is_error()) {
FDF_LOG(ERROR, "Failed to create composite node: %s",
devicegroup_result.error_value().FormatDescription().data());
return zx::error(devicegroup_result.error_value().is_framework_error()
? devicegroup_result.error_value().framework_error().status()
: ZX_ERR_INVALID_ARGS);
}
}
return zx::ok();
}
} // namespace fdf_devicetree