All of lore.kernel.org
 help / color / mirror / Atom feed
From: David Gibson <david@gibson.dropbear.id.au>
To: Jon Loeliger <jdl@freescale.com>
Cc: linuxppc-dev@ozlabs.org
Subject: [PATCH 3/3] libfdt: Add fdt_parent_offset() and supporting functions
Date: Thu, 30 Aug 2007 14:54:04 +1000 (EST)	[thread overview]
Message-ID: <20070830045404.28064DDE32@ozlabs.org> (raw)
In-Reply-To: <20070830045253.GA32543@localhost.localdomain>

This patch adds an fdt_parent_offset() function which returns an
offset to the parent node of a given node.  It also adds two helper
functions which are used to implement fdt_parent_offset() but are also
exported: fdt_supernode_atdepth_offset() which returns the ancestor of
a given node at a specified depth from the root of the tree, and
fdt_node_depth() which returns the depth of a given node.

Signed-off-by: David Gibson <david@gibson.dropbear.id.au>

---
 libfdt/fdt_ro.c                  |   68 ++++++++++++++++++
 libfdt/libfdt.h                  |   10 ++
 tests/Makefile.tests             |    2 
 tests/parent_offset.c            |   90 ++++++++++++++++++++++++
 tests/run_tests.sh               |    2 
 tests/supernode_atdepth_offset.c |  144 +++++++++++++++++++++++++++++++++++++++
 6 files changed, 314 insertions(+), 2 deletions(-)

Index: dtc/libfdt/fdt_ro.c
===================================================================
--- dtc.orig/libfdt/fdt_ro.c	2007-08-29 14:28:32.000000000 +1000
+++ dtc/libfdt/fdt_ro.c	2007-08-30 14:28:35.000000000 +1000
@@ -349,3 +349,71 @@ int fdt_get_path(const void *fdt, int no
 	buf[p] = '\0';
 	return p;
 }
+
+int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset,
+				 int supernodedepth, int *nodedepth)
+{
+	int level = -1;
+	uint32_t tag;
+	int offset, nextoffset = 0;
+	int supernodeoffset = -FDT_ERR_INTERNAL;
+
+	CHECK_HEADER(fdt);
+
+	if (supernodedepth < 0)
+		return -FDT_ERR_NOTFOUND;
+
+	do {
+		offset = nextoffset;
+		tag = _fdt_next_tag(fdt, offset, &nextoffset);
+		switch (tag) {
+		case FDT_END:
+			return -FDT_ERR_BADOFFSET;
+
+		case FDT_BEGIN_NODE:
+			level++;
+			if (level == supernodedepth)
+				supernodeoffset = offset;
+			break;
+
+		case FDT_END_NODE:
+			level--;
+			break;
+
+		case FDT_PROP:
+		case FDT_NOP:
+			break;
+
+		default:
+			return -FDT_ERR_BADSTRUCTURE;
+		}
+	} while (offset < nodeoffset);
+
+	if (nodedepth)
+		*nodedepth = level;
+
+	if (supernodedepth > level)
+		return -FDT_ERR_NOTFOUND;
+	return supernodeoffset;
+}
+
+int fdt_node_depth(const void *fdt, int nodeoffset)
+{
+	int nodedepth;
+	int err;
+
+	err = fdt_supernode_atdepth_offset(fdt, nodeoffset, 0, &nodedepth);
+	if (err)
+		return (err < 0) ? err : -FDT_ERR_INTERNAL;
+	return nodedepth;
+}
+
+int fdt_parent_offset(const void *fdt, int nodeoffset)
+{
+	int nodedepth = fdt_node_depth(fdt, nodeoffset);
+
+	if (nodedepth < 0)
+		return nodedepth;
+	return fdt_supernode_atdepth_offset(fdt, nodeoffset,
+					    nodedepth - 1, NULL);
+}
Index: dtc/libfdt/libfdt.h
===================================================================
--- dtc.orig/libfdt/libfdt.h	2007-08-30 13:26:56.000000000 +1000
+++ dtc/libfdt/libfdt.h	2007-08-30 14:26:40.000000000 +1000
@@ -74,7 +74,10 @@
 #define FDT_ERR_BADSTRUCTURE	10
 #define FDT_ERR_BADLAYOUT	11
 
-#define FDT_ERR_MAX		11
+/* "Can't happen" error indicating a bug in libfdt */
+#define FDT_ERR_INTERNAL	12
+
+#define FDT_ERR_MAX		12
 
 #define fdt_get_header(fdt, field) \
 	(fdt32_to_cpu(((const struct fdt_header *)(fdt))->field))
@@ -138,6 +141,11 @@ static inline void *fdt_getprop_w(void *
 
 int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen);
 
+int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset,
+				 int supernodedepth, int *nodedepth);
+int fdt_node_depth(const void *fdt, int nodeoffset);
+int fdt_parent_offset(const void *fdt, int nodeoffset);
+
 /* Write-in-place functions */
 int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name,
 			const void *val, int len);
Index: dtc/tests/Makefile.tests
===================================================================
--- dtc.orig/tests/Makefile.tests	2007-08-30 13:43:53.000000000 +1000
+++ dtc/tests/Makefile.tests	2007-08-30 14:17:07.000000000 +1000
@@ -1,5 +1,5 @@
 LIB_TESTS_L = root_node find_property subnode_offset path_offset \
-	get_name getprop get_path \
+	get_name getprop get_path supernode_atdepth_offset parent_offset \
 	notfound \
 	setprop_inplace nop_property nop_node \
 	sw_tree1 \
Index: dtc/tests/run_tests.sh
===================================================================
--- dtc.orig/tests/run_tests.sh	2007-08-30 13:44:15.000000000 +1000
+++ dtc/tests/run_tests.sh	2007-08-30 14:17:14.000000000 +1000
@@ -38,6 +38,8 @@ tree1_tests () {
     run_test get_name $TREE
     run_test getprop $TREE
     run_test get_path $TREE
+    run_test supernode_atdepth_offset $TREE
+    run_test parent_offset $TREE
     run_test notfound $TREE
 
     # Write-in-place tests
Index: dtc/tests/supernode_atdepth_offset.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ dtc/tests/supernode_atdepth_offset.c	2007-08-30 13:51:45.000000000 +1000
@@ -0,0 +1,144 @@
+/*
+ * libfdt - Flat Device Tree manipulation
+ *	Testcase for fdt_supernode_atdepth_offset()
+ * Copyright (C) 2006 David Gibson, IBM Corporation.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#define _GNU_SOURCE
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+
+#include <fdt.h>
+#include <libfdt.h>
+
+#include "tests.h"
+#include "testdata.h"
+
+int path_depth(const char *path)
+{
+	const char *p;
+	int depth = 0;
+
+	if (path[0] != '/')
+		TEST_BUG();
+
+	if (strcmp(path, "/") == 0)
+		return 0;
+	for (p = path; *p; p++)
+		if (*p == '/')
+			depth++;
+
+	/* Special case for path == "/" */
+	if (p == (path + 1))
+		return 0;
+	else
+		return depth;
+}
+
+int path_prefix(const char *path, int depth)
+{
+	const char *p;
+	int i;
+
+	if (path[0] != '/')
+		TEST_BUG();
+
+	if (depth == 0)
+		return 1;
+
+	p = path;
+	for (i = 0; i < depth; i++)
+		p = strchrnul(p+1, '/');
+
+	return p - path;
+}
+
+void check_supernode_atdepth(struct fdt_header *fdt, const char *path,
+			     int depth)
+{
+	int pdepth = path_depth(path);
+	char *superpath;
+	int nodeoffset, supernodeoffset, superpathoffset;
+	int nodedepth;
+
+	superpath = strndupa(path, path_prefix(path, depth));
+	verbose_printf("Path %s (%d), depth %d, supernode is %s\n",
+		       path, pdepth, depth, superpath);
+
+	nodeoffset = fdt_path_offset(fdt, path);
+	if (nodeoffset < 0)
+		FAIL("fdt_path_offset(%s): %s", path, fdt_strerror(nodeoffset));
+	superpathoffset = fdt_path_offset(fdt, superpath);
+	if (superpathoffset < 0)
+		FAIL("fdt_path_offset(%s): %s", superpath,
+		     fdt_strerror(superpathoffset));
+
+	supernodeoffset = fdt_supernode_atdepth_offset(fdt, nodeoffset,
+						       depth, &nodedepth);
+	if (supernodeoffset < 0)
+		FAIL("fdt_supernode_atdepth_offset(): %s",
+		     fdt_strerror(supernodeoffset));
+
+	if (supernodeoffset != superpathoffset)
+		FAIL("fdt_supernode_atdepth_offset() returns %d instead of %d",
+		     supernodeoffset, superpathoffset);
+
+	if (nodedepth != pdepth)
+		FAIL("fdt_supernode_atdept_offset() returns node depth %d "
+		     "instead of %d", nodedepth, pdepth);
+}
+
+void check_supernode_overdepth(struct fdt_header *fdt, const char *path)
+{
+	int pdepth = path_depth(path);
+	int nodeoffset, err;
+
+	nodeoffset = fdt_path_offset(fdt, path);
+	if (nodeoffset < 0)
+		FAIL("fdt_path_offset(%s): %s", path, fdt_strerror(nodeoffset));
+
+	err = fdt_supernode_atdepth_offset(fdt, nodeoffset, pdepth + 1, NULL);
+	if (err != -FDT_ERR_NOTFOUND)
+		FAIL("fdt_supernode_atdept_offset(%s, %d) returns %d instead "
+		     "of FDT_ERR_NOTFOUND", path, pdepth+1, err);
+}
+
+void check_path(struct fdt_header *fdt, const char *path)
+{
+	int i;
+
+	for (i = 0; i <= path_depth(path); i++)
+		check_supernode_atdepth(fdt, path, i);
+	check_supernode_overdepth(fdt, path);
+}
+int main(int argc, char *argv[])
+{
+	void *fdt;
+
+	test_init(argc, argv);
+	fdt = load_blob_arg(argc, argv);
+
+	check_path(fdt, "/");
+	check_path(fdt, "/subnode1");
+	check_path(fdt, "/subnode2");
+	check_path(fdt, "/subnode1/subsubnode");
+	check_path(fdt, "/subnode2/subsubnode");
+
+	PASS();
+}
Index: dtc/tests/parent_offset.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ dtc/tests/parent_offset.c	2007-08-30 14:21:10.000000000 +1000
@@ -0,0 +1,90 @@
+/*
+ * libfdt - Flat Device Tree manipulation
+ *	Testcase for fdt_parent_offset()
+ * Copyright (C) 2006 David Gibson, IBM Corporation.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#define _GNU_SOURCE
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+
+#include <fdt.h>
+#include <libfdt.h>
+
+#include "tests.h"
+#include "testdata.h"
+
+int path_parent_len(const char *path)
+{
+	const char *p = strrchr(path, '/');
+
+	if (!p)
+		TEST_BUG();
+	if (p == path)
+		return 1;
+	else
+		return p - path;
+}
+
+void check_path(struct fdt_header *fdt, const char *path)
+{
+	char *parentpath;
+	int nodeoffset, parentoffset, parentpathoffset;
+
+	parentpath = strndupa(path, path_parent_len(path));
+
+	verbose_printf("Path: \"%s\"\tParent: \"%s\"\n", path, parentpath);
+
+	nodeoffset = fdt_path_offset(fdt, path);
+	if (nodeoffset < 0)
+		FAIL("fdt_path_offset(%s): %s", path, fdt_strerror(nodeoffset));
+
+	parentpathoffset = fdt_path_offset(fdt, parentpath);
+	if (parentpathoffset < 0)
+		FAIL("fdt_path_offset(%s): %s", parentpath,
+		     fdt_strerror(parentpathoffset));
+
+	parentoffset = fdt_parent_offset(fdt, nodeoffset);
+	if (parentoffset < 0)
+		FAIL("fdt_parent_offset(): %s", fdt_strerror(parentoffset));
+
+	if (parentoffset != parentpathoffset)
+		FAIL("fdt_parent_offset() returns %d instead of %d",
+		     parentoffset, parentpathoffset);
+}
+
+int main(int argc, char *argv[])
+{
+	void *fdt;
+	int err;
+
+	test_init(argc, argv);
+	fdt = load_blob_arg(argc, argv);
+
+	check_path(fdt, "/subnode1");
+	check_path(fdt, "/subnode2");
+	check_path(fdt, "/subnode1/subsubnode");
+	check_path(fdt, "/subnode2/subsubnode");
+	err = fdt_parent_offset(fdt, 0);
+	if (err != -FDT_ERR_NOTFOUND)
+		FAIL("fdt_parent_offset(/) returns %d instead of "
+		     "-FDT_ERR_NOTFOUND", err);
+
+	PASS();
+}

  parent reply	other threads:[~2007-08-30  4:54 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2007-08-30  4:52 libfdt: Several new functions David Gibson
2007-08-30  4:54 ` [PATCH 2/3] libfdt: Add fdt_get_path() function David Gibson
2007-08-30  4:54 ` David Gibson [this message]
2007-08-30  4:54 ` [PATCH 1/3] libfdt: Add fdt_get_name() to retrieve a node's name David Gibson
2007-08-30 13:52 ` libfdt: Several new functions Jon Loeliger

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20070830045404.28064DDE32@ozlabs.org \
    --to=david@gibson.dropbear.id.au \
    --cc=jdl@freescale.com \
    --cc=linuxppc-dev@ozlabs.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.