blob: 022b59f97a71abed9e5ed788e263b6d68e33e07e [file]
// Copyright 2024 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.
#ifndef LIB_DRIVER_DEVICETREE_VISITORS_PROPERTY_PARSER_H_
#define LIB_DRIVER_DEVICETREE_VISITORS_PROPERTY_PARSER_H_
#include <lib/driver/devicetree/manager/visitor.h>
#include <lib/fit/function.h>
#include <zircon/assert.h>
#include <zircon/errors.h>
#include <any>
#include <cstdint>
#include <map>
#include <memory>
#include <optional>
#include <utility>
#include <variant>
#include <vector>
namespace fdf_devicetree {
using PropertyName = std::string;
// Cells specific to the property represented in a prop-encoded-array.
using PropertyCells = devicetree::ByteView;
// Abstract class to represent a property type.
// To create an instance of Property, use the specific property types.
// Eg: Uint32ArrayProperty, StringListProperty, ReferenceProperty etc.
class Property {
public:
explicit Property(PropertyName name, bool required = false)
: name_(std::move(name)), required_(required) {}
virtual ~Property() = default;
virtual zx::result<> Parse(Node& node, std::map<PropertyName, std::any>& values) const = 0;
PropertyName name() const { return name_; }
bool required() const { return required_; }
private:
PropertyName name_;
bool required_;
};
using Properties = std::vector<std::unique_ptr<Property>>;
class BoolProperty : public Property {
public:
explicit BoolProperty(PropertyName name, bool required = false)
: Property(std::move(name), required) {}
zx::result<> Parse(Node& node, std::map<PropertyName, std::any>& values) const override;
};
class Uint32Property : public Property {
public:
explicit Uint32Property(PropertyName name, bool required = false)
: Property(std::move(name), required) {}
zx::result<> Parse(Node& node, std::map<PropertyName, std::any>& values) const override;
};
class Uint64Property : public Property {
public:
explicit Uint64Property(PropertyName name, bool required = false)
: Property(std::move(name), required) {}
zx::result<> Parse(Node& node, std::map<PropertyName, std::any>& values) const override;
};
class StringProperty : public Property {
public:
explicit StringProperty(PropertyName name, bool required = false)
: Property(std::move(name), required) {}
zx::result<> Parse(Node& node, std::map<PropertyName, std::any>& values) const override;
};
// Property of uint32 array type.
class Uint32ArrayProperty : public Property {
public:
explicit Uint32ArrayProperty(PropertyName name, bool required = false)
: Property(std::move(name), required) {}
zx::result<> Parse(Node& node, std::map<PropertyName, std::any>& values) const override;
};
// Property of string list type.
class StringListProperty : public Property {
public:
explicit StringListProperty(PropertyName name, bool required = false)
: Property(std::move(name), required) {}
zx::result<> Parse(Node& node, std::map<PropertyName, std::any>& values) const override;
};
// Represents a property that contains one or more references to other devicetree nodes (phandles),
// each potentially followed by a set of arguments (cells).
//
// For example: `gpios = <&gpio1 1 2>, <&gpio2 3 4 0>;`
// This property contains two references: one to `gpio1` with cells `{1, 2}` and one to `gpio2` with
// cells `{3, 4, 0}`.
class ReferenceProperty : public Property {
public:
// Constructs a `ReferenceProperty` parser.
//
// The `cell_specifier` determines how many cells (u32 values) follow each phandle in the
// property. It can be either:
//
// 1. A `PropertyName` (e.g., "#interrupt-cells"): The number of cells is determined by reading
// the value of that property from the referenced node. This is the most common case.
//
// Example:
// intc: interrupt-controller@... {
// #interrupt-cells = <2>;
// };
// my_device: my_device@... {
// interrupts = <&intc 1 8>; // Parsed using `ReferenceProperty("interrupts",
// // "#interrupt-cells")`.
// };
//
// 2. A `uint32_t`: A fixed number of cells that applies to all references within this property.
//
// Example:
// my_device: my_device@... {
// mboxes = <&mbox 0>, <&mbox 1>; // Parsed using `ReferenceProperty("mboxes", 1)`.
// };
explicit ReferenceProperty(PropertyName name, std::variant<PropertyName, uint32_t> cell_specifier,
bool required = false)
: Property(std::move(name), required), cell_specifier_(std::move(cell_specifier)) {}
zx::result<> Parse(Node& node, std::map<PropertyName, std::any>& values) const override;
private:
std::variant<PropertyName, uint32_t> cell_specifier_;
};
// A handle to a reference property. It consists of the referenced node and the property cells if
// any.
class Reference {
public:
Reference(ReferenceNode node, PropertyCells cells)
: reference_node_(node), property_cells_(cells) {}
// Returns the referenced devicetree node.
//
// For example, in the devicetree fragment:
// interrupt-parent = <&intc>;
// this would return the node object for `intc`.
ReferenceNode& reference_node() { return reference_node_; }
// Returns the property cells associated with the reference. These are the
// arguments that qualify the reference.
//
// For example, in the devicetree fragment:
// gpios = <&gpio1 1 8>, <&gpio2 2 8 7>;
//
// For the first reference, `property_cells()` would return a view of
// the bytes corresponding to `{1, 8}`.
//
// For the second reference, `property_cells()` would return a view of
// the bytes corresponding to `{2, 8, 7}`.
PropertyCells property_cells() { return property_cells_; }
private:
ReferenceNode reference_node_;
PropertyCells property_cells_;
};
using References = std::vector<Reference>;
// Helper class to hold the parsed properties and provide utility functions to access the values
// appropriately.
class ParsedProperties {
public:
explicit ParsedProperties(std::map<PropertyName, std::any> properties)
: properties_(std::move(properties)) {}
// Gets the parsed value for a property named `name`, cast to type `T`.
//
// Returns an `std::optional<T>` containing the value if the property exists
// and can be cast to `T`. Otherwise, returns `std::nullopt`.
//
// Example usage:
//
// To get a single string property:
// auto str_prop = props.Get<std::string>("string-property");
//
// To get an array of uint32s:
// auto arr_prop = props.Get<std::vector<uint32_t>>("uint32-array-property");
//
// To get a list of references:
// auto ref_prop = props.Get<fdf_devicetree::References>("reference-property");
// if (ref_prop) {
// for (const auto& ref : *ref_prop) {
// // process reference
// }
//
// A special case is provided for `bool`. `Get<bool>("property-name")` will
// return `true` if the property exists and is true, and `false` otherwise
// (if it does not exist or is false).
template <typename T>
auto Get(const PropertyName& name) const {
if constexpr (std::is_same_v<T, bool>) {
auto it = properties_.find(name);
if (it == properties_.end()) {
return false;
}
if (auto* value = std::any_cast<bool>(&it->second)) {
return *value;
}
return false;
} else {
auto it = properties_.find(name);
if (it == properties_.end()) {
return std::optional<T>(std::nullopt);
}
if (auto* value = std::any_cast<T>(&it->second)) {
return std::optional<T>(*value);
}
return std::optional<T>(std::nullopt);
}
}
void AddProperty(const PropertyName& name, std::any value);
private:
std::map<PropertyName, std::any> properties_;
};
// Helper class to parse properties concerning a visitor. A visitor can bunch all the necessary
// properties it needs to extract from a node and call the |PropertyParser::Parse| method.
// Properties can be a string list, uint32 array or reference properties - see below for classes
// that inherit from |Property| for the complete list of supported property types. The visitor can
// also use this collect all connected properties and associate them appropriately using the vector
// index.
class PropertyParser {
public:
explicit PropertyParser(Properties properties) : properties_(std::move(properties)) {}
PropertyParser(PropertyParser&&) = default;
PropertyParser& operator=(PropertyParser&&) = default;
virtual ~PropertyParser() = default;
virtual zx::result<ParsedProperties> Parse(Node& node);
private:
Properties properties_;
};
} // namespace fdf_devicetree
#endif // LIB_DRIVER_DEVICETREE_VISITORS_PROPERTY_PARSER_H_