Skip to content

Commit

Permalink
rust: add fwnode api to access unified device tree
Browse files Browse the repository at this point in the history
Added abstraction APIs for accessing device's fwnode.

Signed-off-by: Vinay Varma <[email protected]>
  • Loading branch information
vvarma committed Nov 9, 2022
1 parent d9b2e84 commit cf5a983
Show file tree
Hide file tree
Showing 2 changed files with 112 additions and 0 deletions.
111 changes: 111 additions & 0 deletions rust/kernel/fwnode.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
// SPDX-License-Identifier: GPL-2.0

//! Unified device property interface.
//!
//! C header: [`include/linux/property.h`](../../../../include/linux/property.h)

use crate::{bindings, device, sync::Arc};
use core::ptr::null_mut;

fn next_endpoint(handle: &DeviceNode, curr: &Option<Arc<Node>>) -> Option<Arc<Node>> {
let res_ptr = match curr {
// SAFETY: By the type invariants, `handle` owns a reference, so it is safe to access `ptr`
None => unsafe {
bindings::fwnode_graph_get_next_endpoint(
handle.ptr,
null_mut::<bindings::fwnode_handle>(),
)
},
// SAFETY: By the type invariants, `handle` owns a reference, so it safe to access it's
// `ptr`. `node` is a reference counted object (Arc) and hence its safe to access the
// internal `ptr`
Some(node) => unsafe {
bindings::fwnode_graph_get_next_endpoint(handle.ptr, node.as_ref().ptr)
},
};
if res_ptr.is_null() {
None
} else {
Arc::try_new(Node { ptr: res_ptr }).ok()
}
}

/// Represents the root `struct fwnode_handle *` associated to a device
///
/// # Invariants
///
/// The pointer is valid.
pub struct DeviceNode {
ptr: *mut bindings::fwnode_handle,
}

impl DeviceNode {
/// Creates a new DeviceNode instance from an existing [`device::Device`] instance.
pub fn from(dev: &device::Device) -> Self {
Self {
// SAFETY: By the type invariants, `dev` owns a reference, so it is safe to access
// `ptr`
ptr: unsafe { bindings::dev_fwnode(dev.ptr) },
}
}
/// Creates an instance of `NodeIterator`
///
/// This provides an `Iterator` wrapping the internal C functionality of invoking
/// `fwnode_graph_get_next_endpoint`
pub fn endpoints(self) -> NodeIterator {
NodeIterator {
handle: self,
curr_node: None,
iter_fn: next_endpoint,
}
}
}

// SAFETY: `DeviceNode` only holds a pointer to a C fwnode_handle, which is safe to be used from any thread.
unsafe impl Send for DeviceNode {}

// SAFETY: `DeviceNode` only holds a pointer to a C fwnode_handle, references to which are safe to be used
// from any thread.
unsafe impl Sync for DeviceNode {}
impl Drop for DeviceNode {
fn drop(&mut self) {
// SAFETY: By the type invariants, `self` owns a reference, so it is safe to
// relinquish it now.
unsafe { bindings::fwnode_handle_put(self.ptr) }
}
}

/// Represents a `struct fwnode_handle *` part of a device's fwnode graph
///
/// # Invariants
///
/// The pointer is valid.
pub struct Node {
pub(crate) ptr: *mut bindings::fwnode_handle,
}

impl Drop for Node {
fn drop(&mut self) {
// SAFETY: By the type invariants, `self` owns a reference, so it is safe to
// relinquish it now.
unsafe { bindings::fwnode_handle_put(self.ptr) }
}
}

/// A function that optionally returns a `Node` given the `parent` and `prev`
type NodeIteratorFn = fn(parent: &DeviceNode, prev: &Option<Arc<Node>>) -> Option<Arc<Node>>;

/// Implements the Iterator trait to iterate the device's fwnode graph given the `DeviceNode` and a `NodeIteratorFn`
pub struct NodeIterator {
handle: DeviceNode,
curr_node: Option<Arc<Node>>,
iter_fn: NodeIteratorFn,
}
impl Iterator for NodeIterator {
type Item = Arc<Node>;

fn next(&mut self) -> Option<Self::Item> {
self.curr_node = (self.iter_fn)(&self.handle, &self.curr_node);
self.curr_node.clone()
}
}
1 change: 1 addition & 0 deletions rust/kernel/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ pub mod driver;
pub mod error;
pub mod file;
pub mod fs;
pub mod fwnode;
pub mod gpio;
pub mod hwrng;
pub mod irq;
Expand Down

0 comments on commit cf5a983

Please sign in to comment.