Browse Source

libfdt: Add functions for handling the "compatible" property

This patch adds functions for dealing with the compatible property.
fdt_node_check_compatible() can be used to determine whether a node is
compatible with a given string and fdt_node_offset_by_compatible()
locates nodes with a given compatible string.

Testcases for these functions are also included.

Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
main
David Gibson 17 years ago committed by Jon Loeliger
parent
commit
333542fabf
  1. 83
      libfdt/fdt_ro.c
  2. 5
      libfdt/libfdt.h
  3. 1
      tests/Makefile.tests
  4. 86
      tests/node_offset_by_compatible.c
  5. 2
      tests/run_tests.sh
  6. 7
      tests/rw_tree1.c
  7. 7
      tests/sw_tree1.c
  8. 4
      tests/test_tree1.dts
  9. 5
      tests/trees.S

83
libfdt/fdt_ro.c

@ -477,3 +477,86 @@ int fdt_node_offset_by_prop_value(const void *fdt, int startoffset, @@ -477,3 +477,86 @@ int fdt_node_offset_by_prop_value(const void *fdt, int startoffset,

return -FDT_ERR_NOTFOUND;
}

int _stringlist_contains(const void *strlist, int listlen, const char *str)
{
int len = strlen(str);
const void *p;

while (listlen >= len) {
if (memcmp(str, strlist, len+1) == 0)
return 1;
p = memchr(strlist, '\0', listlen);
if (!p)
return 0; /* malformed strlist.. */
listlen -= (p-strlist) + 1;
strlist = p + 1;
}
return 0;
}

int fdt_node_check_compatible(const void *fdt, int nodeoffset,
const char *compatible)
{
const void *prop;
int len;

prop = fdt_getprop(fdt, nodeoffset, "compatible", &len);
if (!prop)
return len;
if (_stringlist_contains(prop, len, compatible))
return 0;
else
return 1;
}

int fdt_node_offset_by_compatible(const void *fdt, int startoffset,
const char *compatible)
{
uint32_t tag;
int offset, nextoffset;
int err;

CHECK_HEADER(fdt);

if (startoffset >= 0) {
tag = _fdt_next_tag(fdt, startoffset, &nextoffset);
if (tag != FDT_BEGIN_NODE)
return -FDT_ERR_BADOFFSET;
} else {
nextoffset = 0;
}

/* FIXME: The algorithm here is pretty horrible: we scan each
* property of a node in fdt_node_check_compatible(), then if
* that didn't find what we want, we scan over them again
* making our way to the next node. Still it's the easiest to
* implement approach; performance can come later. */
do {
offset = nextoffset;
tag = _fdt_next_tag(fdt, offset, &nextoffset);

switch (tag) {
case FDT_BEGIN_NODE:
err = fdt_node_check_compatible(fdt, offset,
compatible);
if ((err < 0)
&& (err != -FDT_ERR_NOTFOUND))
return err;
else if (err == 0)
return offset;
break;

case FDT_PROP:
case FDT_END:
case FDT_END_NODE:
case FDT_NOP:
break;

default:
return -FDT_ERR_BADSTRUCTURE;
}
} while (tag != FDT_END);

return -FDT_ERR_NOTFOUND;
}

5
libfdt/libfdt.h

@ -153,6 +153,11 @@ int fdt_node_offset_by_prop_value(const void *fdt, int startoffset, @@ -153,6 +153,11 @@ int fdt_node_offset_by_prop_value(const void *fdt, int startoffset,
const char *propname,
const void *propval, int proplen);

int fdt_node_check_compatible(const void *fdt, int nodeoffset,
const char *compatible);
int fdt_node_offset_by_compatible(const void *fdt, int startoffset,
const char *compatible);

/* Write-in-place functions */
int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name,
const void *val, int len);

1
tests/Makefile.tests

@ -2,6 +2,7 @@ LIB_TESTS_L = get_mem_rsv \ @@ -2,6 +2,7 @@ LIB_TESTS_L = get_mem_rsv \
root_node find_property subnode_offset path_offset \
get_name getprop get_path supernode_atdepth_offset parent_offset \
node_offset_by_prop_value \
node_check_compatible node_offset_by_compatible \
notfound \
setprop_inplace nop_property nop_node \
sw_tree1 \

86
tests/node_offset_by_compatible.c

@ -0,0 +1,86 @@ @@ -0,0 +1,86 @@
/*
* libfdt - Flat Device Tree manipulation
* Testcase for fdt_node_offset_by_compatible()
* 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
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <stdarg.h>

#include <fdt.h>
#include <libfdt.h>

#include "tests.h"
#include "testdata.h"

void check_search(void *fdt, const char *compat, ...)
{
va_list ap;
int offset = -1, target;

va_start(ap, compat);
do {
target = va_arg(ap, int);
verbose_printf("Searching (target = %d): %d ->",
target, offset);
offset = fdt_node_offset_by_compatible(fdt, offset, compat);
verbose_printf("%d\n", offset);

if (offset != target)
FAIL("fdt_node_offset_by_compatible(%s) returns %d "
"instead of %d", compat, offset, target);
} while (target >= 0);

va_end(ap);
}

int main(int argc, char *argv[])
{
void *fdt;
int subnode1_offset, subnode2_offset;
int subsubnode1_offset, subsubnode2_offset;

test_init(argc, argv);
fdt = load_blob_arg(argc, argv);

subnode1_offset = fdt_path_offset(fdt, "/subnode@1");
subnode2_offset = fdt_path_offset(fdt, "/subnode@2");
subsubnode1_offset = fdt_path_offset(fdt, "/subnode@1/subsubnode");
subsubnode2_offset = fdt_path_offset(fdt, "/subnode@2/subsubnode@0");

if ((subnode1_offset < 0) || (subnode2_offset < 0)
|| (subsubnode1_offset < 0) || (subsubnode2_offset < 0))
FAIL("Can't find required nodes");

check_search(fdt, "test_tree1", 0, -FDT_ERR_NOTFOUND);
check_search(fdt, "subnode1", subnode1_offset, -FDT_ERR_NOTFOUND);
check_search(fdt, "subsubnode1", subsubnode1_offset, -FDT_ERR_NOTFOUND);
check_search(fdt, "subsubnode2", subsubnode2_offset, -FDT_ERR_NOTFOUND);
/* Eek.. HACK to make this work whatever the order in the
* example tree */
if (subsubnode1_offset < subsubnode2_offset)
check_search(fdt, "subsubnode", subsubnode1_offset,
subsubnode2_offset, -FDT_ERR_NOTFOUND);
else
check_search(fdt, "subsubnode", subsubnode2_offset,
subsubnode1_offset, -FDT_ERR_NOTFOUND);
check_search(fdt, "nothing-like-this", -FDT_ERR_NOTFOUND);

PASS();
}

2
tests/run_tests.sh

@ -42,6 +42,8 @@ tree1_tests () { @@ -42,6 +42,8 @@ tree1_tests () {
run_test supernode_atdepth_offset $TREE
run_test parent_offset $TREE
run_test node_offset_by_prop_value $TREE
run_test node_check_compatible $TREE
run_test node_offset_by_compatible $TREE
run_test notfound $TREE

# Write-in-place tests

7
tests/rw_tree1.c

@ -72,18 +72,23 @@ int main(int argc, char *argv[]) @@ -72,18 +72,23 @@ int main(int argc, char *argv[])
CHECK(fdt_add_mem_rsv(fdt, TEST_ADDR_1, TEST_SIZE_1));
CHECK(fdt_add_mem_rsv(fdt, TEST_ADDR_2, TEST_SIZE_2));

CHECK(fdt_setprop_string(fdt, 0, "compatible", "test_tree1"));
CHECK(fdt_setprop_typed(fdt, 0, "prop-int", TEST_VALUE_1));
CHECK(fdt_setprop_string(fdt, 0, "prop-str", TEST_STRING_1));

OFF_CHECK(offset, fdt_add_subnode(fdt, 0, "subnode@1"));
CHECK(fdt_setprop_string(fdt, offset, "compatible", "subnode1"));
CHECK(fdt_setprop_typed(fdt, offset, "prop-int", TEST_VALUE_1));
OFF_CHECK(offset, fdt_add_subnode(fdt, offset, "subsubnode"));
CHECK(fdt_setprop(fdt, offset, "compatible",
"subsubnode1\0subsubnode", 23));
CHECK(fdt_setprop_typed(fdt, offset, "prop-int", TEST_VALUE_1));

OFF_CHECK(offset, fdt_add_subnode(fdt, 0, "subnode@2"));
CHECK(fdt_setprop_typed(fdt, offset, "prop-int", TEST_VALUE_2));
OFF_CHECK(offset, fdt_add_subnode(fdt, offset, "subsubnode@0"));

CHECK(fdt_setprop(fdt, offset, "compatible",
"subsubnode2\0subsubnode", 23));
CHECK(fdt_setprop_typed(fdt, offset, "prop-int", TEST_VALUE_2));

CHECK(fdt_pack(fdt));

7
tests/sw_tree1.c

@ -54,12 +54,17 @@ int main(int argc, char *argv[]) @@ -54,12 +54,17 @@ int main(int argc, char *argv[])
CHECK(fdt_finish_reservemap(fdt));

CHECK(fdt_begin_node(fdt, ""));
CHECK(fdt_property_string(fdt, "compatible", "test_tree1"));
CHECK(fdt_property_typed(fdt, "prop-int", TEST_VALUE_1));
CHECK(fdt_property_string(fdt, "prop-str", TEST_STRING_1));

CHECK(fdt_begin_node(fdt, "subnode@1"));
CHECK(fdt_property_string(fdt, "compatible", "subnode1"));
CHECK(fdt_property_typed(fdt, "prop-int", TEST_VALUE_1));
CHECK(fdt_begin_node(fdt, "subsubnode"));
CHECK(fdt_property(fdt, "compatible", "subsubnode1\0subsubnode",
23));
CHECK(fdt_property_string(fdt, "compatible", "subsubnode1\0"));
CHECK(fdt_property_typed(fdt, "prop-int", TEST_VALUE_1));
CHECK(fdt_end_node(fdt));
CHECK(fdt_end_node(fdt));
@ -67,6 +72,8 @@ int main(int argc, char *argv[]) @@ -67,6 +72,8 @@ int main(int argc, char *argv[])
CHECK(fdt_begin_node(fdt, "subnode@2"));
CHECK(fdt_property_typed(fdt, "prop-int", TEST_VALUE_2));
CHECK(fdt_begin_node(fdt, "subsubnode@0"));
CHECK(fdt_property(fdt, "compatible", "subsubnode2\0subsubnode",
23));
CHECK(fdt_property_typed(fdt, "prop-int", TEST_VALUE_2));
CHECK(fdt_end_node(fdt));
CHECK(fdt_end_node(fdt));

4
tests/test_tree1.dts

@ -2,13 +2,16 @@ @@ -2,13 +2,16 @@
/memreserve/ abcd1234 00001234;

/ {
compatible = "test_tree1";
prop-int = <deadbeef>;
prop-str = "hello world";

subnode@1 {
compatible = "subnode1";
prop-int = <deadbeef>;

subsubnode {
compatible = "subsubnode1", "subsubnode";
prop-int = <deadbeef>;
};
};
@ -17,6 +20,7 @@ @@ -17,6 +20,7 @@
prop-int = <abcd1234>;

subsubnode@0 {
compatible = "subsubnode2", "subsubnode";
prop-int = <abcd1234>;
};
};

5
tests/trees.S

@ -83,13 +83,16 @@ test_tree1_rsvmap: @@ -83,13 +83,16 @@ test_tree1_rsvmap:

test_tree1_struct:
BEGIN_NODE("")
PROP_STR(test_tree1, compatible, "test_tree1")
PROP_INT(test_tree1, prop_int, TEST_VALUE_1)
PROP_STR(test_tree1, prop_str, TEST_STRING_1)

BEGIN_NODE("subnode@1")
PROP_STR(test_tree1, compatible, "subnode1")
PROP_INT(test_tree1, prop_int, TEST_VALUE_1)

BEGIN_NODE("subsubnode")
PROP_STR(test_tree1, compatible, "subsubnode1\0subsubnode")
PROP_INT(test_tree1, prop_int, TEST_VALUE_1)
END_NODE
END_NODE
@ -98,6 +101,7 @@ test_tree1_struct: @@ -98,6 +101,7 @@ test_tree1_struct:
PROP_INT(test_tree1, prop_int, TEST_VALUE_2)

BEGIN_NODE("subsubnode@0")
PROP_STR(test_tree1, compatible, "subsubnode2\0subsubnode")
PROP_INT(test_tree1, prop_int, TEST_VALUE_2)
END_NODE
END_NODE
@ -106,6 +110,7 @@ test_tree1_struct: @@ -106,6 +110,7 @@ test_tree1_struct:
FDTLONG(FDT_END)

test_tree1_strings:
STRING(test_tree1, compatible, "compatible")
STRING(test_tree1, prop_int, "prop-int")
STRING(test_tree1, prop_str, "prop-str")
test_tree1_end:

Loading…
Cancel
Save