summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorSascha Hauer <s.hauer@pengutronix.de>2013-11-13 15:00:57 +0100
committerSascha Hauer <s.hauer@pengutronix.de>2014-01-27 11:52:06 +0100
commit136ce91fb5d9194546bfcf49ac87a614a3a458c5 (patch)
treeb243649344d993e48469f77fd6eace4a4d9f56da /src
parent6c37a935b85774f56871a75f2069c8041068d34c (diff)
downloaddt-utils-136ce91fb5d9194546bfcf49ac87a614a3a458c5.tar.gz
dt-utils-136ce91fb5d9194546bfcf49ac87a614a3a458c5.tar.xz
2nd commitv0.2.0
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Diffstat (limited to 'src')
-rw-r--r--src/.gitignore7
-rw-r--r--src/crc32.c112
-rw-r--r--src/dt/common.h125
-rw-r--r--src/dt/dt.h383
-rw-r--r--src/dt/fdt.h73
-rw-r--r--src/dt/list.h627
-rw-r--r--src/fdt.c485
-rw-r--r--src/fdtdump.c76
-rw-r--r--src/libdt.c2185
-rw-r--r--src/libdt.pc.in11
-rw-r--r--src/libdt.sym74
-rw-r--r--src/state.c1309
12 files changed, 5467 insertions, 0 deletions
diff --git a/src/.gitignore b/src/.gitignore
new file mode 100644
index 0000000..5e25d6d
--- /dev/null
+++ b/src/.gitignore
@@ -0,0 +1,7 @@
+.dirstamp
+.deps/
+.libs/
+*.la
+*.lo
+libabc.pc
+test-libabc
diff --git a/src/crc32.c b/src/crc32.c
new file mode 100644
index 0000000..8d4dddc
--- /dev/null
+++ b/src/crc32.c
@@ -0,0 +1,112 @@
+/*
+ * This file is derived from crc32.c from the zlib-1.1.3 distribution
+ * by Jean-loup Gailly and Mark Adler.
+ */
+
+/* crc32.c -- compute the CRC-32 of a data stream
+ * Copyright (C) 1995-1998 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include <stdint.h>
+
+/* ========================================================================
+ * Table of CRC-32's of all single-byte values (made by make_crc_table)
+ */
+static const uint32_t crc_table[256] = {
+ 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
+ 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
+ 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
+ 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
+ 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
+ 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
+ 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
+ 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
+ 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
+ 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
+ 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
+ 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
+ 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
+ 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
+ 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
+ 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
+ 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
+ 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
+ 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
+ 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
+ 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
+ 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
+ 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
+ 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
+ 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
+ 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
+ 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
+ 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
+ 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
+ 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
+ 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
+ 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
+ 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
+ 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
+ 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
+ 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
+ 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
+ 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
+ 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
+ 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
+ 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
+ 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
+ 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
+ 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
+ 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
+ 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
+ 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
+ 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
+ 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
+ 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
+ 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
+ 0x2d02ef8dL
+};
+
+/* ========================================================================= */
+#define DO1(buf) crc = crc_table[((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8);
+#define DO2(buf) DO1(buf); DO1(buf);
+#define DO4(buf) DO2(buf); DO2(buf);
+#define DO8(buf) DO4(buf); DO4(buf);
+
+/* ========================================================================= */
+uint32_t crc32(uint32_t crc, const void *_buf, unsigned int len)
+{
+ const unsigned char *buf = _buf;
+
+ crc = crc ^ 0xffffffffL;
+ while (len >= 8) {
+ DO8(buf);
+ len -= 8;
+ }
+
+ if (len) do {
+ DO1(buf);
+ } while (--len);
+
+ return crc ^ 0xffffffffL;
+}
+
+/* No ones complement version. JFFS2 (and other things ?)
+ * don't use ones compliment in their CRC calculations.
+ */
+uint32_t crc32_no_comp(uint32_t crc, const void *_buf, unsigned int len)
+{
+ const unsigned char *buf = _buf;
+
+ while (len >= 8) {
+ DO8(buf);
+ len -= 8;
+ }
+
+ if (len) do {
+ DO1(buf);
+ } while (--len);
+
+ return crc;
+}
diff --git a/src/dt/common.h b/src/dt/common.h
new file mode 100644
index 0000000..9668c4e
--- /dev/null
+++ b/src/dt/common.h
@@ -0,0 +1,125 @@
+#ifndef __DT_COMMON_H
+#define __DT_COMMON_H
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+
+/**
+ * container_of - cast a member of a structure out to the containing structure
+ * @ptr: the pointer to the member.
+ * @type: the type of the container struct this is embedded in.
+ * @member: the name of the member within the struct.
+ *
+ */
+#define container_of(ptr, type, member) ({ \
+ const typeof( ((type *)0)->member ) *__mptr = (ptr); \
+ (type *)( (char *)__mptr - offsetof(type,member) );})
+
+#undef offsetof
+#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
+
+#ifdef DEBUG
+#define pr_debug(fmt, arg...) printf(fmt, ##arg)
+#else
+#define pr_debug(fmt, arg...)
+#endif
+
+#define pr_err(fmt, arg...) printf(fmt, ##arg)
+
+static inline void *xzalloc(size_t size)
+{
+ return calloc(1, size);
+}
+
+typedef _Bool bool;
+
+enum {
+ false = 0,
+ true = 1
+};
+
+/*
+ * Kernel pointers have redundant information, so we can use a
+ * scheme where we can return either an error code or a dentry
+ * pointer with the same return value.
+ *
+ * This should be a per-architecture thing, to allow different
+ * error and pointer decisions.
+ */
+#define MAX_ERRNO 4095
+
+#ifndef __ASSEMBLY__
+
+#define IS_ERR_VALUE(x) ((x) >= (unsigned long)-MAX_ERRNO)
+
+static inline void *ERR_PTR(long error)
+{
+ return (void *) error;
+}
+
+static inline long PTR_ERR(const void *ptr)
+{
+ return (long) ptr;
+}
+
+static inline long IS_ERR(const void *ptr)
+{
+ return IS_ERR_VALUE((unsigned long)ptr);
+}
+
+static inline long IS_ERR_OR_NULL(const void *ptr)
+{
+ return !ptr || IS_ERR_VALUE((unsigned long)ptr);
+}
+
+/**
+ * ERR_CAST - Explicitly cast an error-valued pointer to another pointer type
+ * @ptr: The pointer to cast.
+ *
+ * Explicitly cast an error-valued pointer to another pointer type in such a
+ * way as to make it clear that's what's going on.
+ */
+static inline void *ERR_CAST(const void *ptr)
+{
+ /* cast away the const */
+ return (void *) ptr;
+}
+
+/**
+ * strlcpy - Copy a %NUL terminated string into a sized buffer
+ * @dest: Where to copy the string to
+ * @src: Where to copy the string from
+ * @size: size of destination buffer
+ *
+ * Compatible with *BSD: the result is always a valid
+ * NUL-terminated string that fits in the buffer (unless,
+ * of course, the buffer size is zero). It does not pad
+ * out the result like strncpy() does.
+ */
+static inline size_t strlcpy(char *dest, const char *src, size_t size)
+{
+ size_t ret = strlen(src);
+
+ if (size) {
+ size_t len = (ret >= size) ? size - 1 : ret;
+ memcpy(dest, src, len);
+ dest[len] = '\0';
+ }
+ return ret;
+}
+
+#define cpu_to_be32 __cpu_to_be32
+#define be32_to_cpu __be32_to_cpu
+
+#define ALIGN(x, a) __ALIGN_MASK(x, (typeof(x))(a) - 1)
+#define __ALIGN_MASK(x, mask) (((x) + (mask)) & ~(mask))
+
+#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
+
+#endif
+
+uint32_t crc32(uint32_t crc, const void *_buf, unsigned int len);
+uint32_t crc32_no_comp(uint32_t crc, const void *_buf, unsigned int len);
+
+#endif /* __DT_COMMON_H */
diff --git a/src/dt/dt.h b/src/dt/dt.h
new file mode 100644
index 0000000..086edfe
--- /dev/null
+++ b/src/dt/dt.h
@@ -0,0 +1,383 @@
+#ifndef __DT_DT_H
+#define __DT_DT_H
+
+#include <stdint.h>
+#include <dt/list.h>
+#include <dt/common.h>
+#include <asm/byteorder.h>
+
+/* Default string compare functions */
+#define of_compat_cmp(s1, s2, l) strcasecmp((s1), (s2))
+#define of_prop_cmp(s1, s2) strcmp((s1), (s2))
+#define of_node_cmp(s1, s2) strcasecmp((s1), (s2))
+
+#define OF_BAD_ADDR ((uint64_t)-1)
+
+typedef uint32_t phandle;
+
+struct property {
+ char *name;
+ int length;
+ void *value;
+ struct list_head list;
+};
+
+struct device_node {
+ char *name;
+ char *full_name;
+
+ struct list_head properties;
+ struct device_node *parent;
+ struct list_head children;
+ struct list_head parent_list;
+ struct list_head list;
+ phandle phandle;
+};
+
+struct of_device_id {
+ char *compatible;
+ unsigned long data;
+};
+
+#define MAX_PHANDLE_ARGS 8
+struct of_phandle_args {
+ struct device_node *np;
+ int args_count;
+ uint32_t args[MAX_PHANDLE_ARGS];
+};
+
+#define OF_MAX_RESERVE_MAP 16
+struct of_reserve_map {
+ uint64_t start[OF_MAX_RESERVE_MAP];
+ uint64_t end[OF_MAX_RESERVE_MAP];
+ int num_entries;
+};
+
+int of_add_reserve_entry(uint64_t start, uint64_t end);
+struct of_reserve_map *of_get_reserve_map(void);
+void of_clean_reserve_map(void);
+void fdt_add_reserve_map(void *fdt);
+
+struct device_d;
+struct driver_d;
+
+int of_fix_tree(struct device_node *);
+int of_register_fixup(int (*fixup)(struct device_node *, void *), void *context);
+
+int of_match(struct device_d *dev, struct driver_d *drv);
+
+struct fdt_header *fdt_get_tree(void);
+
+struct fdt_header *of_get_fixed_tree(struct device_node *node);
+
+/* Helper to read a big number; size is in cells (not bytes) */
+static inline uint64_t of_read_number(const __be32 *cell, int size)
+{
+ uint64_t r = 0;
+ while (size--)
+ r = (r << 32) | __be32_to_cpu(*(cell++));
+ return r;
+}
+
+/* Helper to write a big number; size is in cells (not bytes) */
+static inline void of_write_number(void *__cell, uint64_t val, int size)
+{
+ __be32 *cell = __cell;
+
+ while (size--) {
+ cell[size] = __cpu_to_be32(val);
+ val >>= 32;
+ }
+}
+
+void of_print_property(const void *data, int len);
+void of_print_cmdline(struct device_node *root);
+
+void of_print_nodes(struct device_node *node, int indent);
+int of_probe(void);
+int of_parse_dtb(struct fdt_header *fdt);
+struct device_node *of_unflatten_dtb(struct device_node *root, void *fdt);
+
+struct cdev;
+
+extern int of_n_addr_cells(struct device_node *np);
+extern int of_n_size_cells(struct device_node *np);
+
+extern struct property *of_find_property(const struct device_node *np,
+ const char *name, int *lenp);
+extern const void *of_get_property(const struct device_node *np,
+ const char *name, int *lenp);
+
+extern int of_set_property(struct device_node *node, const char *p,
+ const void *val, int len, int create);
+extern struct property *of_new_property(struct device_node *node,
+ const char *name, const void *data, int len);
+extern void of_delete_property(struct property *pp);
+
+extern struct device_node *of_find_node_by_name(struct device_node *from,
+ const char *name);
+extern struct device_node *of_find_node_by_path_from(struct device_node *from,
+ const char *path);
+extern struct device_node *of_find_node_by_path(const char *path);
+extern struct device_node *of_find_node_by_phandle(phandle phandle);
+extern struct device_node *of_find_node_by_type(struct device_node *from,
+ const char *type);
+extern struct device_node *of_find_compatible_node(struct device_node *from,
+ const char *type, const char *compat);
+extern const struct of_device_id *of_match_node(
+ const struct of_device_id *matches, const struct device_node *node);
+extern struct device_node *of_find_matching_node_and_match(
+ struct device_node *from,
+ const struct of_device_id *matches,
+ const struct of_device_id **match);
+extern struct device_node *of_find_node_with_property(
+ struct device_node *from, const char *prop_name);
+
+extern struct device_node *of_new_node(struct device_node *parent,
+ const char *name);
+extern struct device_node *of_create_node(struct device_node *root,
+ const char *path);
+extern void of_delete_node(struct device_node *node);
+
+extern int of_machine_is_compatible(const char *compat);
+extern int of_device_is_compatible(const struct device_node *device,
+ const char *compat);
+extern int of_device_is_available(const struct device_node *device);
+
+extern struct device_node *of_get_parent(const struct device_node *node);
+extern struct device_node *of_get_next_available_child(
+ const struct device_node *node, struct device_node *prev);
+extern int of_get_child_count(const struct device_node *parent);
+extern int of_get_available_child_count(const struct device_node *parent);
+extern struct device_node *of_get_child_by_name(const struct device_node *node,
+ const char *name);
+
+extern int of_property_read_u32_index(const struct device_node *np,
+ const char *propname,
+ uint32_t index, uint32_t *out_value);
+extern int of_property_read_u8_array(const struct device_node *np,
+ const char *propname, uint8_t *out_values, size_t sz);
+extern int of_property_read_u16_array(const struct device_node *np,
+ const char *propname, uint16_t *out_values, size_t sz);
+extern int of_property_read_u32_array(const struct device_node *np,
+ const char *propname,
+ uint32_t *out_values,
+ size_t sz);
+extern int of_property_read_u64(const struct device_node *np,
+ const char *propname, uint64_t *out_value);
+
+extern int of_property_read_string(struct device_node *np,
+ const char *propname,
+ const char **out_string);
+extern int of_property_read_string_index(struct device_node *np,
+ const char *propname,
+ int index, const char **output);
+extern int of_property_match_string(struct device_node *np,
+ const char *propname,
+ const char *string);
+extern int of_property_count_strings(struct device_node *np,
+ const char *propname);
+
+extern const __be32 *of_prop_next_u32(struct property *prop,
+ const __be32 *cur, uint32_t *pu);
+extern const char *of_prop_next_string(struct property *prop, const char *cur);
+
+extern int of_property_write_bool(struct device_node *np,
+ const char *propname, const bool value);
+extern int of_property_write_u8_array(struct device_node *np,
+ const char *propname, const uint8_t *values,
+ size_t sz);
+extern int of_property_write_u16_array(struct device_node *np,
+ const char *propname, const uint16_t *values,
+ size_t sz);
+extern int of_property_write_u32_array(struct device_node *np,
+ const char *propname, const uint32_t *values,
+ size_t sz);
+extern int of_property_write_u64_array(struct device_node *np,
+ const char *propname, const uint64_t *values,
+ size_t sz);
+
+extern struct device_node *of_parse_phandle(const struct device_node *np,
+ const char *phandle_name,
+ int index);
+extern int of_parse_phandle_with_args(const struct device_node *np,
+ const char *list_name, const char *cells_name, int index,
+ struct of_phandle_args *out_args);
+extern int of_count_phandle_with_args(const struct device_node *np,
+ const char *list_name, const char *cells_name);
+
+extern void of_alias_scan(void);
+extern int of_alias_get_id(struct device_node *np, const char *stem);
+extern const char *of_alias_get(struct device_node *np);
+extern int of_modalias_node(struct device_node *node, char *modalias, int len);
+
+extern struct device_node *of_get_root_node(void);
+extern int of_set_root_node(struct device_node *node);
+
+extern int of_platform_populate(struct device_node *root,
+ const struct of_device_id *matches,
+ struct device_d *parent);
+extern struct device_d *of_find_device_by_node(struct device_node *np);
+
+struct cdev *of_parse_partition(struct cdev *cdev, struct device_node *node);
+int of_parse_partitions(struct cdev *cdev, struct device_node *node);
+int of_device_is_stdout_path(struct device_d *dev);
+const char *of_get_model(void);
+void *of_flatten_dtb(struct device_node *node);
+int of_add_memory(struct device_node *node, bool dump);
+void of_add_memory_bank(struct device_node *node, bool dump, int r,
+ uint64_t base, uint64_t size);
+
+struct of_path {
+ char *devpath;
+ off_t offset;
+ size_t size;
+ struct udev_device *dev;
+ struct device_node *node;
+};
+
+int of_find_path(struct device_node *node, const char *propname, struct of_path *op);
+
+#define for_each_node_by_name(dn, name) \
+ for (dn = of_find_node_by_name(NULL, name); dn; \
+ dn = of_find_node_by_name(dn, name))
+#define for_each_compatible_node(dn, type, compatible) \
+ for (dn = of_find_compatible_node(NULL, type, compatible); dn; \
+ dn = of_find_compatible_node(dn, type, compatible))
+static inline struct device_node *of_find_matching_node(
+ struct device_node *from,
+ const struct of_device_id *matches)
+{
+ return of_find_matching_node_and_match(from, matches, NULL);
+}
+#define for_each_matching_node(dn, matches) \
+ for (dn = of_find_matching_node(NULL, matches); dn; \
+ dn = of_find_matching_node(dn, matches))
+#define for_each_matching_node_and_match(dn, matches, match) \
+ for (dn = of_find_matching_node_and_match(NULL, matches, match); \
+ dn; dn = of_find_matching_node_and_match(dn, matches, match))
+#define for_each_node_with_property(dn, prop_name) \
+ for (dn = of_find_node_with_property(NULL, prop_name); dn; \
+ dn = of_find_node_with_property(dn, prop_name))
+
+#define for_each_child_of_node(parent, child) \
+ list_for_each_entry(child, &parent->children, parent_list)
+#define for_each_available_child_of_node(parent, child) \
+ for (child = of_get_next_available_child(parent, NULL); child != NULL; \
+ child = of_get_next_available_child(parent, child))
+
+/**
+ * of_property_read_bool - Findfrom a property
+ * @np: device node from which the property value is to be read.
+ * @propname: name of the property to be searched.
+ *
+ * Search for a property in a device node.
+ * Returns true if the property exist false otherwise.
+ */
+static inline bool of_property_read_bool(const struct device_node *np,
+ const char *propname)
+{
+ struct property *prop = of_find_property(np, propname, NULL);
+
+ return prop ? true : false;
+}
+
+static inline int of_property_read_u8(const struct device_node *np,
+ const char *propname,
+ uint8_t *out_value)
+{
+ return of_property_read_u8_array(np, propname, out_value, 1);
+}
+
+static inline int of_property_read_u16(const struct device_node *np,
+ const char *propname,
+ uint16_t *out_value)
+{
+ return of_property_read_u16_array(np, propname, out_value, 1);
+}
+
+static inline int of_property_read_u32(const struct device_node *np,
+ const char *propname,
+ uint32_t *out_value)
+{
+ return of_property_read_u32_array(np, propname, out_value, 1);
+}
+
+/*
+ * struct property *prop;
+ * const __be32 *p;
+ * uint32_t u;
+ *
+ * of_property_for_each_u32(np, "propname", prop, p, u)
+ * printk("U32 value: %x\n", u);
+ */
+#define of_property_for_each_u32(np, propname, prop, p, u) \
+ for (prop = of_find_property(np, propname, NULL), \
+ p = of_prop_next_u32(prop, NULL, &u); \
+ p; \
+ p = of_prop_next_u32(prop, p, &u))
+
+/*
+ * struct property *prop;
+ * const char *s;
+ *
+ * of_property_for_each_string(np, "propname", prop, s)
+ * printk("String value: %s\n", s);
+ */
+#define of_property_for_each_string(np, propname, prop, s) \
+ for (prop = of_find_property(np, propname, NULL), \
+ s = of_prop_next_string(prop, NULL); \
+ s; \
+ s = of_prop_next_string(prop, s))
+
+static inline int of_property_write_u8(struct device_node *np,
+ const char *propname, uint8_t value)
+{
+ return of_property_write_u8_array(np, propname, &value, 1);
+}
+
+static inline int of_property_write_u16(struct device_node *np,
+ const char *propname, uint16_t value)
+{
+ return of_property_write_u16_array(np, propname, &value, 1);
+}
+
+static inline int of_property_write_u32(struct device_node *np,
+ const char *propname,
+ uint32_t value)
+{
+ return of_property_write_u32_array(np, propname, &value, 1);
+}
+
+static inline int of_property_write_u64(struct device_node *np,
+ const char *propname,
+ uint64_t value)
+{
+ return of_property_write_u64_array(np, propname, &value, 1);
+}
+
+extern const struct of_device_id of_default_bus_match_table[];
+
+int of_device_enable(struct device_node *node);
+int of_device_enable_path(const char *path);
+int of_device_disable(struct device_node *node);
+int of_device_disable_path(const char *path);
+
+phandle of_get_tree_max_phandle(struct device_node *root);
+phandle of_node_create_phandle(struct device_node *node);
+struct device_node *of_find_node_by_alias(struct device_node *root,
+ const char *alias);
+struct device_node *of_find_node_by_path_or_alias(struct device_node *root,
+ const char *str);
+
+static inline struct device_node *of_find_root_node(struct device_node *node)
+{
+ while (node->parent)
+ node = node->parent;
+
+ return node;
+}
+
+struct device_node *of_read_proc_devicetree(void);
+
+#endif /* __DT_DT_H */
diff --git a/src/dt/fdt.h b/src/dt/fdt.h
new file mode 100644
index 0000000..35278e3
--- /dev/null
+++ b/src/dt/fdt.h
@@ -0,0 +1,73 @@
+#ifndef _FDT_H
+#define _FDT_H
+
+#ifndef __ASSEMBLY__
+
+#define _B(n) ((unsigned long long)((uint8_t *)&x)[n])
+
+#define fdt32_to_cpu(x) be32_to_cpu(x)
+#define cpu_to_fdt32(x) cpu_to_be32(x)
+
+static inline uint64_t fdt64_to_cpu(uint64_t x)
+{
+ return (_B(0) << 56) | (_B(1) << 48) | (_B(2) << 40) | (_B(3) << 32)
+ | (_B(4) << 24) | (_B(5) << 16) | (_B(6) << 8) | _B(7);
+}
+#define cpu_to_fdt64(x) fdt64_to_cpu(x)
+#undef _B
+
+struct fdt_header {
+ uint32_t magic; /* magic word FDT_MAGIC */
+ uint32_t totalsize; /* total size of DT block */
+ uint32_t off_dt_struct; /* offset to structure */
+ uint32_t off_dt_strings; /* offset to strings */
+ uint32_t off_mem_rsvmap; /* offset to memory reserve map */
+ uint32_t version; /* format version */
+ uint32_t last_comp_version; /* last compatible version */
+
+ /* version 2 fields below */
+ uint32_t boot_cpuid_phys; /* Which physical CPU id we're
+ booting on */
+ /* version 3 fields below */
+ uint32_t size_dt_strings; /* size of the strings block */
+
+ /* version 17 fields below */
+ uint32_t size_dt_struct; /* size of the structure block */
+};
+
+struct fdt_reserve_entry {
+ uint64_t address;
+ uint64_t size;
+};
+
+struct fdt_node_header {
+ uint32_t tag;
+ char name[0];
+};
+
+struct fdt_property {
+ uint32_t tag;
+ uint32_t len;
+ uint32_t nameoff;
+ char data[0];
+};
+
+#endif /* !__ASSEMBLY */
+
+#define FDT_MAGIC 0xd00dfeed /* 4: version, 4: total size */
+#define FDT_TAGSIZE sizeof(uint32_t)
+
+#define FDT_BEGIN_NODE 0x1 /* Start node: full name */
+#define FDT_END_NODE 0x2 /* End node */
+#define FDT_PROP 0x3 /* Property: name off,
+ size, content */
+#define FDT_NOP 0x4 /* nop */
+#define FDT_END 0x9
+
+#define FDT_V1_SIZE (7*sizeof(uint32_t))
+#define FDT_V2_SIZE (FDT_V1_SIZE + sizeof(uint32_t))
+#define FDT_V3_SIZE (FDT_V2_SIZE + sizeof(uint32_t))
+#define FDT_V16_SIZE FDT_V3_SIZE
+#define FDT_V17_SIZE (FDT_V16_SIZE + sizeof(uint32_t))
+
+#endif /* _FDT_H */
diff --git a/src/dt/list.h b/src/dt/list.h
new file mode 100644
index 0000000..c17b5d4
--- /dev/null
+++ b/src/dt/list.h
@@ -0,0 +1,627 @@
+#ifndef _LINUX_LIST_H
+#define _LINUX_LIST_H
+
+#include "common.h"
+
+/*
+ * Simple doubly linked list implementation.
+ *
+ * Some of the internal functions ("__xxx") are useful when
+ * manipulating whole lists rather than single entries, as
+ * sometimes we already know the next/prev entries and we can
+ * generate better code by using them directly rather than
+ * using the generic single-entry routines.
+ */
+
+#define LIST_POISON1 ((void *) 0x00100100)
+#define LIST_POISON2 ((void *) 0x00200200)
+static inline void prefetch(const void *x) {;}
+
+struct list_head {
+ struct list_head *next, *prev;
+};
+
+#define LIST_HEAD_INIT(name) { &(name), &(name) }
+
+#define LIST_HEAD(name) \
+ struct list_head name = LIST_HEAD_INIT(name)
+
+static inline void INIT_LIST_HEAD(struct list_head *list)
+{
+ list->next = list;
+ list->prev = list;
+}
+
+/*
+ * Insert a new entry between two known consecutive entries.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+#ifndef CONFIG_DEBUG_LIST
+static inline void __list_add(struct list_head *new,
+ struct list_head *prev,
+ struct list_head *next)
+{
+ next->prev = new;
+ new->next = next;
+ new->prev = prev;
+ prev->next = new;
+}
+#else
+extern void __list_add(struct list_head *new,
+ struct list_head *prev,
+ struct list_head *next);
+#endif
+
+/**
+ * list_add - add a new entry
+ * @new: new entry to be added
+ * @head: list head to add it after
+ *
+ * Insert a new entry after the specified head.
+ * This is good for implementing stacks.
+ */
+#ifndef CONFIG_DEBUG_LIST
+static inline void list_add(struct list_head *new, struct list_head *head)
+{
+ __list_add(new, head, head->next);
+}
+#else
+extern void list_add(struct list_head *new, struct list_head *head);
+#endif
+
+
+/**
+ * list_add_tail - add a new entry
+ * @new: new entry to be added
+ * @head: list head to add it before
+ *
+ * Insert a new entry before the specified head.
+ * This is useful for implementing queues.
+ */
+static inline void list_add_tail(struct list_head *new, struct list_head *head)
+{
+ __list_add(new, head->prev, head);
+}
+
+/*
+ * Delete a list entry by making the prev/next entries
+ * point to each other.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static inline void __list_del(struct list_head * prev, struct list_head * next)
+{
+ next->prev = prev;
+ prev->next = next;
+}
+
+/**
+ * list_del - deletes entry from list.
+ * @entry: the element to delete from the list.
+ * Note: list_empty() on entry does not return true after this, the entry is
+ * in an undefined state.
+ */
+#ifndef CONFIG_DEBUG_LIST
+static inline void list_del(struct list_head *entry)
+{
+ __list_del(entry->prev, entry->next);
+ entry->next = LIST_POISON1;
+ entry->prev = LIST_POISON2;
+}
+#else
+extern void list_del(struct list_head *entry);
+#endif
+
+/**
+ * list_replace - replace old entry by new one
+ * @old : the element to be replaced
+ * @new : the new element to insert
+ *
+ * If @old was empty, it will be overwritten.
+ */
+static inline void list_replace(struct list_head *old,
+ struct list_head *new)
+{
+ new->next = old->next;
+ new->next->prev = new;
+ new->prev = old->prev;
+ new->prev->next = new;
+}
+
+static inline void list_replace_init(struct list_head *old,
+ struct list_head *new)
+{
+ list_replace(old, new);
+ INIT_LIST_HEAD(old);
+}
+
+/**
+ * list_del_init - deletes entry from list and reinitialize it.
+ * @entry: the element to delete from the list.
+ */
+static inline void list_del_init(struct list_head *entry)
+{
+ __list_del(entry->prev, entry->next);
+ INIT_LIST_HEAD(entry);
+}
+
+/**
+ * list_move - delete from one list and add as another's head
+ * @list: the entry to move
+ * @head: the head that will precede our entry
+ */
+static inline void list_move(struct list_head *list, struct list_head *head)
+{
+ __list_del(list->prev, list->next);
+ list_add(list, head);
+}
+
+/**
+ * list_move_tail - delete from one list and add as another's tail
+ * @list: the entry to move
+ * @head: the head that will follow our entry
+ */
+static inline void list_move_tail(struct list_head *list,
+ struct list_head *head)
+{
+ __list_del(list->prev, list->next);
+ list_add_tail(list, head);
+}
+
+/**
+ * list_is_last - tests whether @list is the last entry in list @head
+ * @list: the entry to test
+ * @head: the head of the list
+ */
+static inline int list_is_last(const struct list_head *list,
+ const struct list_head *head)
+{
+ return list->next == head;
+}
+
+/**
+ * list_empty - tests whether a list is empty
+ * @head: the list to test.
+ */
+static inline int list_empty(const struct list_head *head)
+{
+ return head->next == head;
+}
+
+/**
+ * list_empty_careful - tests whether a list is empty and not being modified
+ * @head: the list to test
+ *
+ * Description:
+ * tests whether a list is empty _and_ checks that no other CPU might be
+ * in the process of modifying either member (next or prev)
+ *
+ * NOTE: using list_empty_careful() without synchronization
+ * can only be safe if the only activity that can happen
+ * to the list entry is list_del_init(). Eg. it cannot be used
+ * if another CPU could re-list_add() it.
+ */
+static inline int list_empty_careful(const struct list_head *head)
+{
+ struct list_head *next = head->next;
+ return (next == head) && (next == head->prev);
+}
+
+/**
+ * list_is_singular - tests whether a list has just one entry.
+ * @head: the list to test.
+ */
+static inline int list_is_singular(const struct list_head *head)
+{
+ return !list_empty(head) && (head->next == head->prev);
+}
+
+static inline void __list_splice(struct list_head *list,
+ struct list_head *head)
+{
+ struct list_head *first = list->next;
+ struct list_head *last = list->prev;
+ struct list_head *at = head->next;
+
+ first->prev = head;
+ head->next = first;
+
+ last->next = at;
+ at->prev = last;
+}
+
+/**
+ * list_splice - join two lists
+ * @list: the new list to add.
+ * @head: the place to add it in the first list.
+ */
+static inline void list_splice(struct list_head *list, struct list_head *head)
+{
+ if (!list_empty(list))
+ __list_splice(list, head);
+}
+
+/**
+ * list_splice_init - join two lists and reinitialise the emptied list.
+ * @list: the new list to add.
+ * @head: the place to add it in the first list.
+ *
+ * The list at @list is reinitialised
+ */
+static inline void list_splice_init(struct list_head *list,
+ struct list_head *head)
+{
+ if (!list_empty(list)) {
+ __list_splice(list, head);
+ INIT_LIST_HEAD(list);
+ }
+}
+
+/**
+ * list_entry - get the struct for this entry
+ * @ptr: the &struct list_head pointer.
+ * @type: the type of the struct this is embedded in.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_entry(ptr, type, member) \
+ container_of(ptr, type, member)
+
+/**
+ * list_first_entry - get the first element from a list
+ * @ptr: the list head to take the element from.
+ * @type: the type of the struct this is embedded in.
+ * @member: the name of the list_struct within the struct.
+ *
+ * Note, that list is expected to be not empty.
+ */
+#define list_first_entry(ptr, type, member) \
+ list_entry((ptr)->next, type, member)
+
+/**
+ * list_last_entry - get the last element from a list
+ * @head: the list head to take the element from.
+ * @type: the type of the struct this is embedded in.
+ * @member: the name of the list_struct within the struct.
+ *
+ * Note, that list is expected to be not empty.
+ */
+#define list_last_entry(head, type, member) \
+ list_entry((head)->prev, type, member)
+
+/**
+ * list_for_each - iterate over a list
+ * @pos: the &struct list_head to use as a loop cursor.
+ * @head: the head for your list.
+ */
+#define list_for_each(pos, head) \
+ for (pos = (head)->next; prefetch(pos->next), pos != (head); \
+ pos = pos->next)
+
+/**
+ * __list_for_each - iterate over a list
+ * @pos: the &struct list_head to use as a loop cursor.
+ * @head: the head for your list.
+ *
+ * This variant differs from list_for_each() in that it's the
+ * simplest possible list iteration code, no prefetching is done.
+ * Use this for code that knows the list to be very short (empty
+ * or 1 entry) most of the time.
+ */
+#define __list_for_each(pos, head) \
+ for (pos = (head)->next; pos != (head); pos = pos->next)
+
+/**
+ * list_for_each_prev - iterate over a list backwards
+ * @pos: the &struct list_head to use as a loop cursor.
+ * @head: the head for your list.
+ */
+#define list_for_each_prev(pos, head) \
+ for (pos = (head)->prev; prefetch(pos->prev), pos != (head); \
+ pos = pos->prev)
+
+/**
+ * list_for_each_safe - iterate over a list safe against removal of list entry
+ * @pos: the &struct list_head to use as a loop cursor.
+ * @n: another &struct list_head to use as temporary storage
+ * @head: the head for your list.
+ */
+#define list_for_each_safe(pos, n, head) \
+ for (pos = (head)->next, n = pos->next; pos != (head); \
+ pos = n, n = pos->next)
+
+/**
+ * list_for_each_entry - iterate over list of given type
+ * @pos: the type * to use as a loop cursor.
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_for_each_entry(pos, head, member) \
+ for (pos = list_entry((head)->next, typeof(*pos), member); \
+ prefetch(pos->member.next), &pos->member != (head); \
+ pos = list_entry(pos->member.next, typeof(*pos), member))
+
+/**
+ * list_for_each_entry_reverse - iterate backwards over list of given type.
+ * @pos: the type * to use as a loop cursor.
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_for_each_entry_reverse(pos, head, member) \
+ for (pos = list_entry((head)->prev, typeof(*pos), member); \
+ prefetch(pos->member.prev), &pos->member != (head); \
+ pos = list_entry(pos->member.prev, typeof(*pos), member))
+
+/**
+ * list_prepare_entry - prepare a pos entry for use in list_for_each_entry_continue()
+ * @pos: the type * to use as a start point
+ * @head: the head of the list
+ * @member: the name of the list_struct within the struct.
+ *
+ * Prepares a pos entry for use as a start point in list_for_each_entry_continue().
+ */
+#define list_prepare_entry(pos, head, member) \
+ ((pos) ? : list_entry(head, typeof(*pos), member))
+
+/**
+ * list_for_each_entry_continue - continue iteration over list of given type
+ * @pos: the type * to use as a loop cursor.
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ *
+ * Continue to iterate over list of given type, continuing after
+ * the current position.
+ */
+#define list_for_each_entry_continue(pos, head, member) \
+ for (pos = list_entry(pos->member.next, typeof(*pos), member); \
+ prefetch(pos->member.next), &pos->member != (head); \
+ pos = list_entry(pos->member.next, typeof(*pos), member))
+
+/**
+ * list_for_each_entry_from - iterate over list of given type from the current point
+ * @pos: the type * to use as a loop cursor.
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ *
+ * Iterate over list of given type, continuing from current position.
+ */
+#define list_for_each_entry_from(pos, head, member) \
+ for (; prefetch(pos->member.next), &pos->member != (head); \
+ pos = list_entry(pos->member.next, typeof(*pos), member))
+
+/**
+ * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
+ * @pos: the type * to use as a loop cursor.
+ * @n: another type * to use as temporary storage
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_for_each_entry_safe(pos, n, head, member) \
+ for (pos = list_entry((head)->next, typeof(*pos), member), \
+ n = list_entry(pos->member.next, typeof(*pos), member); \
+ &pos->member != (head); \
+ pos = n, n = list_entry(n->member.next, typeof(*n), member))
+
+/**
+ * list_for_each_entry_safe_continue
+ * @pos: the type * to use as a loop cursor.
+ * @n: another type * to use as temporary storage
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ *
+ * Iterate over list of given type, continuing after current point,
+ * safe against removal of list entry.
+ */
+#define list_for_each_entry_safe_continue(pos, n, head, member) \
+ for (pos = list_entry(pos->member.next, typeof(*pos), member), \
+ n = list_entry(pos->member.next, typeof(*pos), member); \
+ &pos->member != (head); \
+ pos = n, n = list_entry(n->member.next, typeof(*n), member))
+
+/**
+ * list_for_each_entry_safe_from
+ * @pos: the type * to use as a loop cursor.
+ * @n: another type * to use as temporary storage
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ *
+ * Iterate over list of given type from current point, safe against
+ * removal of list entry.
+ */
+#define list_for_each_entry_safe_from(pos, n, head, member) \
+ for (n = list_entry(pos->member.next, typeof(*pos), member); \
+ &pos->member != (head); \
+ pos = n, n = list_entry(n->member.next, typeof(*n), member))
+
+/**
+ * list_for_each_entry_safe_reverse
+ * @pos: the type * to use as a loop cursor.
+ * @n: another type * to use as temporary storage
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ *
+ * Iterate backwards over list of given type, safe against removal
+ * of list entry.
+ */
+#define list_for_each_entry_safe_reverse(pos, n, head, member) \
+ for (pos = list_entry((head)->prev, typeof(*pos), member), \
+ n = list_entry(pos->member.prev, typeof(*pos), member); \
+ &pos->member != (head); \
+ pos = n, n = list_entry(n->member.prev, typeof(*n), member))
+
+/**
+ * list_add_sort - add a new entry to a sorted list
+ * @new: new entry to be added
+ * @head: list head to add it in
+ * @compare: Compare function to compare two list entries
+ *
+ * Insert a new entry before the specified head.
+ * This is useful for implementing queues.
+ */
+static inline void list_add_sort(struct list_head *new, struct list_head *head,
+ int (*compare)(struct list_head *a, struct list_head *b))
+{
+ struct list_head *pos, *insert = head;
+
+ list_for_each(pos, head) {
+ if (compare(pos, new) < 0)
+ continue;
+ insert = pos;
+ break;
+ }
+
+ list_add_tail(new, insert);
+}
+
+/*
+ * Double linked lists with a single pointer list head.
+ * Mostly useful for hash tables where the two pointer list head is
+ * too wasteful.
+ * You lose the ability to access the tail in O(1).
+ */
+
+struct hlist_head {
+ struct hlist_node *first;
+};
+
+struct hlist_node {
+ struct hlist_node *next, **pprev;
+};
+
+#define HLIST_HEAD_INIT { .first = NULL }
+#define HLIST_HEAD(name) struct hlist_head name = { .first = NULL }
+#define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL)
+static inline void INIT_HLIST_NODE(struct hlist_node *h)
+{
+ h->next = NULL;
+ h->pprev = NULL;
+}
+
+static inline int hlist_unhashed(const struct hlist_node *h)
+{
+ return !h->pprev;
+}
+
+static inline int hlist_empty(const struct hlist_head *h)
+{
+ return !h->first;
+}
+
+static inline void __hlist_del(struct hlist_node *n)
+{
+ struct hlist_node *next = n->next;
+ struct hlist_node **pprev = n->pprev;
+ *pprev = next;
+ if (next)
+ next->pprev = pprev;
+}
+
+static inline void hlist_del(struct hlist_node *n)
+{
+ __hlist_del(n);
+ n->next = LIST_POISON1;
+ n->pprev = LIST_POISON2;
+}
+
+static inline void hlist_del_init(struct hlist_node *n)
+{
+ if (!hlist_unhashed(n)) {
+ __hlist_del(n);
+ INIT_HLIST_NODE(n);
+ }
+}
+
+static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h)
+{
+ struct hlist_node *first = h->first;
+ n->next = first;
+ if (first)
+ first->pprev = &n->next;
+ h->first = n;
+ n->pprev = &h->first;
+}
+
+/* next must be != NULL */
+static inline void hlist_add_before(struct hlist_node *n,
+ struct hlist_node *next)
+{
+ n->pprev = next->pprev;
+ n->next = next;
+ next->pprev = &n->next;
+ *(n->pprev) = n;
+}
+
+static inline void hlist_add_after(struct hlist_node *n,
+ struct hlist_node *next)
+{
+ next->next = n->next;
+ n->next = next;
+ next->pprev = &n->next;
+
+ if(next->next)
+ next->next->pprev = &next->next;
+}
+
+#define hlist_entry(ptr, type, member) container_of(ptr,type,member)
+
+#define hlist_for_each(pos, head) \
+ for (pos = (head)->first; pos && ({ prefetch(pos->next); 1; }); \
+ pos = pos->next)
+
+#define hlist_for_each_safe(pos, n, head) \
+ for (pos = (head)->first; pos && ({ n = pos->next; 1; }); \
+ pos = n)
+
+/**
+ * hlist_for_each_entry - iterate over list of given type
+ * @tpos: the type * to use as a loop cursor.
+ * @pos: the &struct hlist_node to use as a loop cursor.
+ * @head: the head for your list.
+ * @member: the name of the hlist_node within the struct.
+ */
+#define hlist_for_each_entry(tpos, pos, head, member) \
+ for (pos = (head)->first; \
+ pos && ({ prefetch(pos->next); 1;}) && \
+ ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
+ pos = pos->next)
+
+/**
+ * hlist_for_each_entry_continue - iterate over a hlist continuing after current point
+ * @tpos: the type * to use as a loop cursor.
+ * @pos: the &struct hlist_node to use as a loop cursor.
+ * @member: the name of the hlist_node within the struct.
+ */
+#define hlist_for_each_entry_continue(tpos, pos, member) \
+ for (pos = (pos)->next; \
+ pos && ({ prefetch(pos->next); 1;}) && \
+ ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
+ pos = pos->next)
+
+/**
+ * hlist_for_each_entry_from - iterate over a hlist continuing from current point
+ * @tpos: the type * to use as a loop cursor.
+ * @pos: the &struct hlist_node to use as a loop cursor.
+ * @member: the name of the hlist_node within the struct.
+ */
+#define hlist_for_each_entry_from(tpos, pos, member) \
+ for (; pos && ({ prefetch(pos->next); 1;}) && \
+ ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
+ pos = pos->next)
+
+/**
+ * hlist_for_each_entry_safe - iterate over list of given type safe against removal of list entry
+ * @tpos: the type * to use as a loop cursor.
+ * @pos: the &struct hlist_node to use as a loop cursor.
+ * @n: another &struct hlist_node to use as temporary storage
+ * @head: the head for your list.
+ * @member: the name of the hlist_node within the struct.
+ */
+#define hlist_for_each_entry_safe(tpos, pos, n, head, member) \
+ for (pos = (head)->first; \
+ pos && ({ n = pos->next; 1; }) && \
+ ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
+ pos = n)
+
+#endif
diff --git a/src/fdt.c b/src/fdt.c
new file mode 100644
index 0000000..903ed68
--- /dev/null
+++ b/src/fdt.c
@@ -0,0 +1,485 @@
+/*
+ * dtb.c - flat devicetree functions
+ *
+ * Copyright (c) 2013 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
+ *
+ * based on Linux devicetree support
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ */
+
+#include <stdio.h>
+#include <linux/types.h>
+#include <asm/byteorder.h>
+#include <stdint.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <libudev.h>
+#include <dt/fdt.h>
+#include <dt/dt.h>
+
+static inline uint32_t dt_struct_advance(struct fdt_header *f, uint32_t dt, int size)
+{
+ dt += size;
+ dt = ALIGN(dt, 4);
+
+ if (dt > f->off_dt_struct + f->size_dt_struct)
+ return 0;
+
+ return dt;
+}
+
+static inline char *dt_string(struct fdt_header *f, char *strstart, uint32_t ofs)
+{
+ if (ofs > f->size_dt_strings)
+ return NULL;
+ else
+ return strstart + ofs;
+}
+
+/**
+ * of_unflatten_dtb - unflatten a dtb binary blob
+ * @root - node in which the fdt blob should be merged into or NULL
+ * @infdt - the fdt blob to unflatten
+ *
+ * Parse a flat device tree binary blob and return a pointer to the
+ * unflattened tree.
+ */
+struct device_node *of_unflatten_dtb(struct device_node *root, void *infdt)
+{
+ const void *nodep; /* property node pointer */
+ uint32_t tag; /* tag */
+ int len; /* length of the property */
+ const struct fdt_property *fdt_prop;
+ const char *pathp, *name;
+ struct device_node *node = NULL;
+ struct property *p;
+ uint32_t dt_struct;
+ struct fdt_node_header *fnh;
+ void *dt_strings;
+ struct fdt_header f;
+ int ret, merge = 0;
+ unsigned int maxlen;
+ struct fdt_header *fdt = infdt;
+
+ if (fdt->magic != cpu_to_fdt32(FDT_MAGIC)) {
+ pr_err("bad magic: 0x%08x\n", fdt32_to_cpu(fdt->magic));
+ return ERR_PTR(-EINVAL);
+ }
+
+ if (fdt->version != cpu_to_fdt32(17)) {
+ pr_err("bad dt version: 0x%08x\n", fdt32_to_cpu(fdt->version));
+ return ERR_PTR(-EINVAL);
+ }
+
+ f.totalsize = fdt32_to_cpu(fdt->totalsize);
+ f.off_dt_struct = fdt32_to_cpu(fdt->off_dt_struct);
+ f.size_dt_struct = fdt32_to_cpu(fdt->size_dt_struct);
+ f.off_dt_strings = fdt32_to_cpu(fdt->off_dt_strings);
+ f.size_dt_strings = fdt32_to_cpu(fdt->size_dt_strings);
+
+ if (f.off_dt_struct + f.size_dt_struct > f.totalsize) {
+ pr_err("unflatten: dt size exceeds total size\n");
+ return ERR_PTR(-ESPIPE);
+ }
+
+ if (f.off_dt_strings + f.size_dt_strings > f.totalsize) {
+ pr_err("unflatten: string size exceeds total size\n");
+ return ERR_PTR(-ESPIPE);
+ }
+
+ dt_struct = f.off_dt_struct;
+ dt_strings = (void *)fdt + f.off_dt_strings;
+
+ if (root) {
+ pr_debug("unflatten: merging into existing tree\n");
+ merge = 1;
+ } else {
+ root = of_new_node(NULL, NULL);
+ if (!root)
+ return ERR_PTR(-ENOMEM);
+ }
+
+ while (1) {
+ tag = be32_to_cpu(*(uint32_t *)(infdt + dt_struct));
+
+ switch (tag) {
+ case FDT_BEGIN_NODE:
+ fnh = infdt + dt_struct;
+ pathp = name = fnh->name;
+ maxlen = (unsigned long)fdt + f.off_dt_struct +
+ f.size_dt_struct - (unsigned long)name;
+
+ len = strnlen(name, maxlen + 1);
+ if (len > maxlen) {
+ ret = -ESPIPE;
+ goto err;
+ }
+
+ dt_struct = dt_struct_advance(&f, dt_struct,
+ sizeof(struct fdt_node_header) + len + 1);
+ if (!dt_struct) {
+ ret = -ESPIPE;
+ goto err;
+ }
+
+ if (!node) {
+ node = root;
+ } else {
+ if (merge)
+ node = of_get_child_by_name(node,
+ pathp);
+ if (!merge || !node)
+ node = of_new_node(node, pathp);
+ }
+
+ break;
+
+ case FDT_END_NODE:
+ if (!node) {
+ pr_err("unflatten: too many end nodes\n");
+ ret = -EINVAL;
+ goto err;
+ }
+
+ node = node->parent;
+
+ dt_struct = dt_struct_advance(&f, dt_struct, FDT_TAGSIZE);
+ if (!dt_struct) {
+ ret = -ESPIPE;
+ goto err;
+ }
+
+ break;
+
+ case FDT_PROP:
+ fdt_prop = infdt + dt_struct;
+ len = fdt32_to_cpu(fdt_prop->len);
+ nodep = fdt_prop->data;
+
+ name = dt_string(&f, dt_strings, fdt32_to_cpu(fdt_prop->nameoff));
+ if (!name) {
+ ret = -ESPIPE;
+ goto err;
+ }
+
+ dt_struct = dt_struct_advance(&f, dt_struct,
+ sizeof(struct fdt_property) + len);
+ if (!dt_struct) {
+ ret = -ESPIPE;
+ goto err;
+ }
+
+ p = NULL;
+ if (merge)
+ p = of_find_property(node, name, NULL);
+ if (merge && p) {
+ free(p->value);
+ p->value = xzalloc(len);
+ p->length = len;
+ memcpy(p->value, nodep, len);
+ } else {
+ p = of_new_property(node, name, nodep, len);
+ if (!strcmp(name, "phandle") && len == 4)
+ node->phandle = be32_to_cpu(*(__be32 *)p->value);
+ }
+
+ break;
+
+ case FDT_NOP:
+ dt_struct = dt_struct_advance(&f, dt_struct, FDT_TAGSIZE);
+ if (!dt_struct) {
+ ret = -ESPIPE;
+ goto err;
+ }
+
+ break;
+
+ case FDT_END:
+ return root;
+
+ default:
+ pr_err("unflatten: Unknown tag 0x%08X\n", tag);
+ ret = -EINVAL;
+ goto err;
+ }
+ }
+err:
+ of_delete_node(root);
+
+ return ERR_PTR(ret);
+}
+
+struct fdt {
+ void *dt;
+ uint32_t dt_nextofs;
+ uint32_t dt_size;
+ char *strings;
+ uint32_t str_nextofs;
+ uint32_t str_size;
+};
+
+static inline uint32_t dt_next_ofs(uint32_t curofs, uint32_t len)
+{
+ return ALIGN(curofs + len, 4);
+}
+
+static int lstrcpy(char *dest, const char *src)
+{
+ int len = 0;
+ int maxlen = 1023;
+
+ while (*src) {
+ *dest++ = *src++;
+ len++;
+ if (!maxlen)
+ return -ENOSPC;
+ maxlen--;
+ }
+
+ return len;
+}
+
+static int fdt_ensure_space(struct fdt *fdt, int dtsize)
+{
+ /*
+ * We assume strings and names have a maximum length of 1024
+ * whereas properties can be longer. We allocate new memory
+ * if we have less than 1024 bytes (+ the property size left.
+ */
+ if (fdt->str_size - fdt->str_nextofs < 1024) {
+ fdt->strings = realloc(fdt->strings, fdt->str_size * 2);
+ if (!fdt->strings)
+ return -ENOMEM;
+ fdt->str_size *= 2;
+ }
+
+ if (fdt->dt_size - fdt->dt_nextofs < 1024 + dtsize) {
+ fdt->dt = realloc(fdt->dt, fdt->dt_size * 2);
+ if (!fdt->dt)
+ return -ENOMEM;
+ fdt->dt_size *= 2;
+ }
+
+ return 0;
+}
+
+static inline int dt_add_string(struct fdt *fdt, const char *str)
+{
+ uint32_t ret;
+ int len;
+
+ if (fdt_ensure_space(fdt, 0) < 0)
+ return -ENOMEM;
+
+ len = lstrcpy(fdt->strings + fdt->str_nextofs, str);
+ if (len < 0)
+ return -ENOSPC;
+
+ ret = fdt->str_nextofs;
+
+ fdt->str_nextofs += len + 1;
+
+ return ret;
+}
+
+static int __of_flatten_dtb(struct fdt *fdt, struct device_node *node)
+{
+ struct property *p;
+ struct device_node *n;
+ int ret;
+ unsigned int len;
+ struct fdt_node_header *nh;
+
+ if (fdt_ensure_space(fdt, 0) < 0)
+ return -ENOMEM;
+
+ nh = fdt->dt + fdt->dt_nextofs;
+ nh->tag = cpu_to_fdt32(FDT_BEGIN_NODE);
+ len = lstrcpy(nh->name, node->name);
+ fdt->dt_nextofs = dt_next_ofs(fdt->dt_nextofs, 4 + len + 1);
+
+ list_for_each_entry(p, &node->properties, list) {
+ struct fdt_property *fp;
+
+ if (fdt_ensure_space(fdt, p->length) < 0)
+ return -ENOMEM;
+
+ fp = fdt->dt + fdt->dt_nextofs;
+
+ fp->tag = cpu_to_fdt32(FDT_PROP);
+ fp->len = cpu_to_fdt32(p->length);
+ fp->nameoff = cpu_to_fdt32(dt_add_string(fdt, p->name));
+ memcpy(fp->data, p->value, p->length);
+ fdt->dt_nextofs = dt_next_ofs(fdt->dt_nextofs,
+ sizeof(struct fdt_property) + p->length);
+ }
+
+ list_for_each_entry(n, &node->children, parent_list) {
+ ret = __of_flatten_dtb(fdt, n);
+ if (ret)
+ return ret;
+ }
+
+ nh = fdt->dt + fdt->dt_nextofs;
+ nh->tag = cpu_to_fdt32(FDT_END_NODE);
+ fdt->dt_nextofs = dt_next_ofs(fdt->dt_nextofs,
+ sizeof(struct fdt_node_header));
+
+ if (fdt_ensure_space(fdt, 0) < 0)
+ return -ENOMEM;
+
+ return 0;
+}
+
+#define BUFSIZE (64 * 1024)
+
+/**
+ * of_flatten_dtb - flatten a barebox internal devicetree to a dtb
+ * @node - the root node of the tree to be unflattened
+ */
+void *of_flatten_dtb(struct device_node *node)
+{
+ int ret;
+ struct fdt_header header = {};
+ struct fdt fdt = {};
+ uint32_t ofs;
+ struct fdt_node_header *nh;
+
+ header.magic = cpu_to_fdt32(FDT_MAGIC);
+ header.version = cpu_to_fdt32(0x11);
+ header.last_comp_version = cpu_to_fdt32(0x10);
+
+ fdt.dt = xzalloc(BUFSIZE);
+ fdt.dt_size = BUFSIZE;
+
+ fdt.strings = xzalloc(BUFSIZE);
+ fdt.str_size = BUFSIZE;
+
+ memset(fdt.dt, 0, BUFSIZE);
+
+ ofs = sizeof(struct fdt_header);
+
+ header.off_mem_rsvmap = cpu_to_fdt32(ofs);
+ ofs += sizeof(struct fdt_reserve_entry) * OF_MAX_RESERVE_MAP;
+
+ fdt.dt_nextofs = ofs;
+
+ ret = __of_flatten_dtb(&fdt, node);
+ if (ret)
+ goto out_free;
+ nh = fdt.dt + fdt.dt_nextofs;
+ nh->tag = cpu_to_fdt32(FDT_END);
+ fdt.dt_nextofs = dt_next_ofs(fdt.dt_nextofs, sizeof(struct fdt_node_header));
+
+ header.off_dt_struct = cpu_to_fdt32(ofs);
+ header.size_dt_struct = cpu_to_fdt32(fdt.dt_nextofs - ofs);
+
+ header.off_dt_strings = cpu_to_fdt32(fdt.dt_nextofs);
+ header.size_dt_strings = cpu_to_fdt32(fdt.str_nextofs);
+
+ if (fdt.dt_size - fdt.dt_nextofs < fdt.str_nextofs) {
+ fdt.dt = realloc(fdt.dt, fdt.dt_nextofs + fdt.str_nextofs);
+ if (!fdt.dt)
+ goto out_free;
+ }
+
+ memcpy(fdt.dt + fdt.dt_nextofs, fdt.strings, fdt.str_nextofs);
+
+ header.totalsize = cpu_to_fdt32(fdt.dt_nextofs + fdt.str_nextofs);
+
+ memcpy(fdt.dt, &header, sizeof(header));
+
+ free(fdt.strings);
+
+ return fdt.dt;
+
+out_free:
+ free(fdt.strings);
+ free(fdt.dt);
+
+ return NULL;
+}
+
+/*
+ * The last entry is the zeroed sentinel, the one before is
+ * reserved for the reservemap entry for the dtb itself.
+ */
+#define OF_MAX_FREE_RESERVE_MAP (OF_MAX_RESERVE_MAP - 2)
+
+static struct of_reserve_map of_reserve_map;
+
+int of_add_reserve_entry(uint64_t start, uint64_t end)
+{
+ int e = of_reserve_map.num_entries;
+
+ if (e >= OF_MAX_FREE_RESERVE_MAP)
+ return -ENOSPC;
+
+ of_reserve_map.start[e] = start;
+ of_reserve_map.end[e] = end;
+ of_reserve_map.num_entries++;
+
+ return 0;
+}
+
+struct of_reserve_map *of_get_reserve_map(void)
+{
+ return &of_reserve_map;
+}
+
+void of_clean_reserve_map(void)
+{
+ of_reserve_map.num_entries = 0;
+}
+
+/**
+ * fdt_add_reserve_map - Add reserve map entries to a devicetree binary
+ * @__fdt: The devicetree blob
+ *
+ * This adds the reservemap entries previously colllected in
+ * of_add_reserve_entry() to a devicetree binary blob. This also
+ * adds the devicetree itself to the reserved list, so after calling
+ * this function the tree should not be relocated anymore.
+ */
+void fdt_add_reserve_map(void *__fdt)
+{
+ struct fdt_header *fdt = __fdt;
+ struct of_reserve_map *res = &of_reserve_map;
+ struct fdt_reserve_entry *fdt_res =
+ __fdt + be32_to_cpu(fdt->off_mem_rsvmap);
+ int i;
+
+ for (i = 0; i < res->num_entries; i++) {
+ of_write_number(&fdt_res->address, res->start[i], 2);
+ of_write_number(&fdt_res->size, res->end[i] - res->start[i] + 1,
+ 2);
+ fdt_res++;
+ }
+
+ of_write_number(&fdt_res->address, (unsigned long)__fdt, 2);
+ of_write_number(&fdt_res->size, be32_to_cpu(fdt->totalsize), 2);
+ fdt_res++;
+
+ of_write_number(&fdt_res->address, 0, 2);
+ of_write_number(&fdt_res->size, 0, 2);
+}
diff --git a/src/fdtdump.c b/src/fdtdump.c
new file mode 100644
index 0000000..d438a84
--- /dev/null
+++ b/src/fdtdump.c
@@ -0,0 +1,76 @@
+#include <linux/types.h>
+
+#include <stdio.h>
+#include <dt/dt.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+
+void *read_file(const char *filename, size_t *size)
+{
+ int fd;
+ struct stat s;
+ void *buf = NULL;
+ int ret;
+
+ if (stat(filename, &s))
+ return NULL;
+
+ buf = xzalloc(s.st_size + 1);
+
+ fd = open(filename, O_RDONLY);
+ if (fd < 0)
+ goto err_out;
+
+ if (read(fd, buf, s.st_size) < s.st_size)
+ goto err_out1;
+
+ close(fd);
+
+ if (size)
+ *size = s.st_size;
+
+ return buf;
+
+err_out1:
+ close(fd);
+err_out:
+ free(buf);
+
+ return NULL;
+}
+
+int main(int argc, char *argv[])
+{
+ void *fdt;
+ struct device_node *root;
+ const char *dtbfile = NULL;
+
+ if (argc > 1)
+ dtbfile = argv[1];
+
+ if (dtbfile) {
+ fdt = read_file(dtbfile, NULL);
+ if (!fdt) {
+ fprintf(stderr, "Could not read %s: %s\n", dtbfile, strerror(errno));
+ exit(1);
+ }
+
+ root = of_unflatten_dtb(NULL, fdt);
+ } else {
+ root = of_read_proc_devicetree();
+ }
+
+ if (IS_ERR(root)) {
+ fprintf(stderr, "Could not unflatten dtb: %s\n", strerror(-PTR_ERR(root)));
+ exit(1);
+ }
+
+ printf("/dts-v1/;\n/");
+
+ of_print_nodes(root, 0);
+
+ exit(0);
+}
diff --git a/src/libdt.c b/src/libdt.c
new file mode 100644
index 0000000..4a3ce1e
--- /dev/null
+++ b/src/libdt.c
@@ -0,0 +1,2185 @@
+/*
+ * of.c - basic devicetree functions
+ *
+ * Copyright (c) 2012 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
+ *
+ * based on Linux devicetree support
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ */
+#include <stdio.h>
+#include <linux/types.h>
+#include <asm/byteorder.h>
+#include <stdint.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <libudev.h>
+#include <dt.h>
+
+static int is_printable_string(const void *data, int len)
+{
+ const char *s = data;
+
+ /* zero length is not */
+ if (len == 0)
+ return 0;
+
+ /* must terminate with zero */
+ if (s[len - 1] != '\0')
+ return 0;
+
+ /* printable or a null byte (concatenated strings) */
+ while (((*s == '\0') || isprint(*s)) && (len > 0)) {
+ /*
+ * If we see a null, there are three possibilities:
+ * 1) If len == 1, it is the end of the string, printable
+ * 2) Next character also a null, not printable.
+ * 3) Next character not a null, continue to check.
+ */
+ if (s[0] == '\0') {
+ if (len == 1)
+ return 1;
+ if (s[1] == '\0')
+ return 0;
+ }
+ s++;
+ len--;
+ }
+
+ /* Not the null termination, or not done yet: not printable */
+ if (*s != '\0' || (len != 0))
+ return 0;
+
+ return 1;
+}
+
+/*
+ * Print the property in the best format, a heuristic guess. Print as
+ * a string, concatenated strings, a byte, word, double word, or (if all
+ * else fails) it is printed as a stream of bytes.
+ */
+void of_print_property(const void *data, int len)
+{
+ int j;
+
+ /* no data, don't print */
+ if (len == 0)
+ return;
+
+ /*
+ * It is a string, but it may have multiple strings (embedded '\0's).
+ */
+ if (is_printable_string(data, len)) {
+ printf("\"");
+ j = 0;
+ while (j < len) {
+ if (j > 0)
+ printf("\", \"");
+ printf(data);
+ j += strlen(data) + 1;
+ data += strlen(data) + 1;
+ }
+ printf("\"");
+ return;
+ }
+
+ if ((len % 4) == 0) {
+ const uint32_t *p;
+
+ printf("<");
+ for (j = 0, p = data; j < len/4; j ++)
+ printf("0x%x%s", __be32_to_cpu(p[j]), j < (len/4 - 1) ? " " : "");
+ printf(">");
+ } else { /* anything else... hexdump */
+ const uint8_t *s;
+
+ printf("[");
+ for (j = 0, s = data; j < len; j++)
+ printf("%02x%s", s[j], j < len - 1 ? " " : "");
+ printf("]");
+ }
+}
+
+/*
+ * Iterate over all nodes of a tree. As a devicetree does not
+ * have a dedicated list head, the start node (usually the root
+ * node) will not be iterated over.
+ */
+static inline struct device_node *of_next_node(struct device_node *node)
+{
+ struct device_node *next;
+
+ next = list_first_entry(&node->list, struct device_node, list);
+
+ return next->parent ? next : NULL;
+}
+
+#define of_tree_for_each_node_from(node, from) \
+ for (node = of_next_node(from); node; node = of_next_node(node))
+
+/**
+ * struct alias_prop - Alias property in 'aliases' node
+ * @link: List node to link the structure in aliases_lookup list
+ * @alias: Alias property name
+ * @np: Pointer to device_node that the alias stands for
+ * @id: Index value from end of alias name
+ * @stem: Alias string without the index
+ *
+ * The structure represents one alias property of 'aliases' node as
+ * an entry in aliases_lookup list.
+ */
+struct alias_prop {
+ struct list_head link;
+ const char *alias;
+ struct device_node *np;
+ int id;
+ char stem[0];
+};
+
+static LIST_HEAD(aliases_lookup);
+
+struct device_node *root_node;
+
+struct device_node *of_aliases;
+
+#define OF_ROOT_NODE_SIZE_CELLS_DEFAULT 1
+#define OF_ROOT_NODE_ADDR_CELLS_DEFAULT 1
+
+int of_n_addr_cells(struct device_node *np)
+{
+ const __be32 *ip;
+
+ do {
+ if (np->parent)
+ np = np->parent;
+ ip = of_get_property(np, "#address-cells", NULL);
+ if (ip)
+ return __be32_to_cpup(ip);
+ } while (np->parent);
+ /* No #address-cells property for the root node */
+ return OF_ROOT_NODE_ADDR_CELLS_DEFAULT;
+}
+
+int of_n_size_cells(struct device_node *np)
+{
+ const __be32 *ip;
+
+ do {
+ if (np->parent)
+ np = np->parent;
+ ip = of_get_property(np, "#size-cells", NULL);
+ if (ip)
+ return __be32_to_cpup(ip);
+ } while (np->parent);
+ /* No #size-cells property for the root node */
+ return OF_ROOT_NODE_SIZE_CELLS_DEFAULT;
+}
+
+struct property *of_find_property(const struct device_node *np,
+ const char *name, int *lenp)
+{
+ struct property *pp;
+
+ if (!np)
+ return NULL;
+
+ list_for_each_entry(pp, &np->properties, list)
+ if (of_prop_cmp(pp->name, name) == 0) {
+ if (lenp)
+ *lenp = pp->length;
+ return pp;
+ }
+
+ return NULL;
+}
+
+static void of_alias_add(struct alias_prop *ap, struct device_node *np,
+ int id, const char *stem, int stem_len)
+{
+ ap->np = np;
+ ap->id = id;
+ strncpy(ap->stem, stem, stem_len);
+ ap->stem[stem_len] = 0;
+ list_add_tail(&ap->link, &aliases_lookup);
+ pr_debug("adding DT alias:%s: stem=%s id=%i node=%s\n",
+ ap->alias, ap->stem, ap->id, np->full_name);
+}
+
+/**
+ * of_alias_scan - Scan all properties of 'aliases' node
+ *
+ * The function scans all the properties of 'aliases' node and populates
+ * the global lookup table with the properties. It returns the
+ * number of alias_prop found, or error code in error case.
+ */
+void of_alias_scan(void)
+{
+ struct property *pp;
+ struct alias_prop *app, *tmp;
+
+ list_for_each_entry_safe(app, tmp, &aliases_lookup, link)
+ free(app);
+
+ INIT_LIST_HEAD(&aliases_lookup);
+
+ if (!root_node)
+ return;
+
+ of_aliases = of_find_node_by_path("/aliases");
+ if (!of_aliases)
+ return;
+
+ list_for_each_entry(pp, &of_aliases->properties, list) {
+ const char *start = pp->name;
+ const char *end = start + strlen(start);
+ struct device_node *np;
+ struct alias_prop *ap;
+ int id, len;
+
+ /* Skip those we do not want to proceed */
+ if (!of_prop_cmp(pp->name, "name") ||
+ !of_prop_cmp(pp->name, "phandle") ||
+ !of_prop_cmp(pp->name, "linux,phandle"))
+ continue;
+
+ np = of_find_node_by_path(pp->value);
+ if (!np)
+ continue;
+
+ /* walk the alias backwards to extract the id and work out
+ * the 'stem' string */
+ while (isdigit(*(end-1)) && end > start)
+ end--;
+ len = end - start;
+
+ id = strtol(end, 0, 10);
+ if (id < 0)
+ continue;
+
+ /* Allocate an alias_prop with enough space for the stem */
+ ap = xzalloc(sizeof(*ap) + len + 1);
+ if (!ap)
+ continue;
+ ap->alias = start;
+ of_alias_add(ap, np, id, start, len);
+ }
+}
+
+/**
+ * of_alias_get_id - Get alias id for the given device_node
+ * @np: Pointer to the given device_node
+ * @stem: Alias stem of the given device_node
+ *
+ * The function travels the lookup table to get alias id for the given
+ * device_node and alias stem. It returns the alias id if find it.
+ */
+int of_alias_get_id(struct device_node *np, const char *stem)
+{
+ struct alias_prop *app;
+ int id = -ENODEV;
+
+ list_for_each_entry(app, &aliases_lookup, link) {
+ if (of_node_cmp(app->stem, stem) != 0)
+ continue;
+
+ if (np == app->np) {
+ id = app->id;
+ break;
+ }
+ }
+
+ return id;
+}
+
+const char *of_alias_get(struct device_node *np)
+{
+ struct property *pp;
+
+ list_for_each_entry(pp, &of_aliases->properties, list) {
+ if (!of_node_cmp(np->full_name, pp->value))
+ return pp->name;
+ }
+
+ return NULL;
+}
+
+/*
+ * of_find_node_by_alias - Find a node given an alias name
+ * @root: the root node of the tree. If NULL, use internal tree
+ * @alias: the alias name to find
+ */
+struct device_node *of_find_node_by_alias(struct device_node *root, const char *alias)
+{
+ struct device_node *aliasnp;
+ int ret;
+ const char *path;
+
+ if (!root)
+ root = root_node;
+
+ aliasnp = of_find_node_by_path_from(root, "/aliases");
+ if (!aliasnp)
+ return NULL;
+
+ ret = of_property_read_string(aliasnp, alias, &path);
+ if (ret)
+ return NULL;
+
+ return of_find_node_by_path_from(root, path);
+}
+
+/*
+ * of_find_node_by_phandle - Find a node given a phandle
+ * @handle: phandle of the node to find
+ */
+struct device_node *of_find_node_by_phandle(phandle phandle)
+{
+ struct device_node *node;
+
+ of_tree_for_each_node_from(node, root_node)
+ if (node->phandle == phandle)
+ return node;
+
+ return NULL;
+}
+
+/*
+ * of_get_tree_max_phandle - Find the maximum phandle of a tree
+ * @root: root node of the tree to search in. If NULL use the
+ * internal tree.
+ */
+phandle of_get_tree_max_phandle(struct device_node *root)
+{
+ struct device_node *n;
+ phandle max;
+
+ if (!root)
+ root = root_node;
+
+ if (!root)
+ return 0;
+
+ max = root->phandle;
+
+ of_tree_for_each_node_from(n, root) {
+ if (n->phandle > max)
+ max = n->phandle;
+ }
+
+ return max;
+}
+
+/*
+ * of_node_create_phandle - create a phandle for a node
+ * @node: The node to create a phandle in
+ *
+ * returns the new phandle or the existing phandle if the node
+ * already has a phandle.
+ */
+phandle of_node_create_phandle(struct device_node *node)
+{
+ phandle p;
+ struct device_node *root;
+
+ if (node->phandle)
+ return node->phandle;
+
+ root = of_find_root_node(node);
+
+ p = of_get_tree_max_phandle(root) + 1;
+
+ node->phandle = p;
+
+ p = __cpu_to_be32(p);
+
+ of_set_property(node, "phandle", &p, sizeof(p), 1);
+
+ return node->phandle;
+}
+
+/*
+ * Find a property with a given name for a given node
+ * and return the value.
+ */
+const void *of_get_property(const struct device_node *np, const char *name,
+ int *lenp)
+{
+ struct property *pp = of_find_property(np, name, lenp);
+
+ return pp ? pp->value : NULL;
+}
+
+/** Checks if the given "compat" string matches one of the strings in
+ * the device's "compatible" property
+ */
+int of_device_is_compatible(const struct device_node *device,
+ const char *compat)
+{
+ const char *cp;
+ int cplen, l;
+
+ cp = of_get_property(device, "compatible", &cplen);
+ if (cp == NULL)
+ return 0;
+ while (cplen > 0) {
+ if (of_compat_cmp(cp, compat, strlen(compat)) == 0)
+ return 1;
+ l = strlen(cp) + 1;
+ cp += l;
+ cplen -= l;
+ }
+
+ return 0;
+}
+
+/**
+ * of_find_node_by_name - Find a node by its "name" property
+ * @from: The node to start searching from or NULL, the node
+ * you pass will not be searched, only the next one
+ * will; typically, you pass what the previous call
+ * returned.
+ * @name: The name string to match against
+ *
+ * Returns a pointer to the node found or NULL.
+ */
+struct device_node *of_find_node_by_name(struct device_node *from,
+ const char *name)
+{
+ struct device_node *np;
+
+ if (!from)
+ from = root_node;
+
+ of_tree_for_each_node_from(np, from)
+ if (np->name && !of_node_cmp(np->name, name))
+ return np;
+
+ return NULL;
+}
+
+/**
+ * of_find_node_by_type - Find a node by its "device_type" property
+ * @from: The node to start searching from, or NULL to start searching
+ * the entire device tree. The node you pass will not be
+ * searched, only the next one will; typically, you pass
+ * what the previous call returned.
+ * @type: The type string to match against.
+ *
+ * Returns a pointer to the node found or NULL.
+ */
+struct device_node *of_find_node_by_type(struct device_node *from,
+ const char *type)
+{
+ struct device_node *np;
+ const char *device_type;
+ int ret;
+
+ if (!from)
+ from = root_node;
+
+ of_tree_for_each_node_from(np, from) {
+ ret = of_property_read_string(np, "device_type", &device_type);
+ if (!ret && !of_node_cmp(device_type, type))
+ return np;
+ }
+ return NULL;
+}
+
+/**
+ * of_find_compatible_node - Find a node based on type and one of the
+ * tokens in its "compatible" property
+ * @from: The node to start searching from or NULL, the node
+ * you pass will not be searched, only the next one
+ * will; typically, you pass what the previous call
+ * returned.
+ * @type: The type string to match "device_type" or NULL to ignore
+ * (currently always ignored in barebox)
+ * @compatible: The string to match to one of the tokens in the device
+ * "compatible" list.
+ *
+ * Returns a pointer to the node found or NULL.
+ */
+struct device_node *of_find_compatible_node(struct device_node *from,
+ const char *type, const char *compatible)
+{
+ struct device_node *np;
+
+ if (!from)
+ from = root_node;
+
+ of_tree_for_each_node_from(np, from)
+ if (of_device_is_compatible(np, compatible))
+ return np;
+
+ return NULL;
+}
+
+/**
+ * of_find_node_with_property - Find a node which has a property with
+ * the given name.
+ * @from: The node to start searching from or NULL, the node
+ * you pass will not be searched, only the next one
+ * will; typically, you pass what the previous call
+ * returned.
+ * @prop_name: The name of the property to look for.
+ *
+ * Returns a pointer to the node found or NULL.
+ */
+struct device_node *of_find_node_with_property(struct device_node *from,
+ const char *prop_name)
+{
+ struct device_node *np;
+
+ if (!from)
+ from = root_node;
+
+ of_tree_for_each_node_from(np, from) {
+ struct property *pp = of_find_property(np, prop_name, NULL);
+ if (pp)
+ return np;
+ }
+
+ return NULL;
+}
+
+/**
+ * of_match_node - Tell if an device_node has a matching of_match structure
+ * @matches: array of of device match structures to search in
+ * @node: the of device structure to match against
+ *
+ * Low level utility function used by device matching.
+ */
+const struct of_device_id *of_match_node(const struct of_device_id *matches,
+ const struct device_node *node)
+{
+ if (!matches || !node)
+ return NULL;
+
+ while (matches->compatible) {
+ if (of_device_is_compatible(node, matches->compatible) == 1)
+ return matches;
+ matches++;
+ }
+
+ return NULL;
+}
+
+/**
+ * of_find_matching_node_and_match - Find a node based on an of_device_id
+ * match table.
+ * @from: The node to start searching from or NULL, the node
+ * you pass will not be searched, only the next one
+ * will; typically, you pass what the previous call
+ * returned.
+ * @matches: array of of device match structures to search in
+ * @match Updated to point at the matches entry which matched
+ *
+ * Returns a pointer to the node found or NULL.
+ */
+struct device_node *of_find_matching_node_and_match(struct device_node *from,
+ const struct of_device_id *matches,
+ const struct of_device_id **match)
+{
+ struct device_node *np;
+
+ if (match)
+ *match = NULL;
+
+ if (!from)
+ from = root_node;
+
+ of_tree_for_each_node_from(np, from) {
+ const struct of_device_id *m = of_match_node(matches, np);
+ if (m) {
+ if (match)
+ *match = m;
+ return np;
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ * of_find_property_value_of_size
+ *
+ * @np: device node from which the property value is to be read.
+ * @propname: name of the property to be searched.
+ * @len: requested length of property value
+ *
+ * Search for a property in a device node and valid the requested size.
+ * Returns the property value on success, -EINVAL if the property does not
+ * exist, -ENODATA if property does not have a value, and -EOVERFLOW if the
+ * property data isn't large enough.
+ *
+ */
+static void *of_find_property_value_of_size(const struct device_node *np,
+ const char *propname, uint32_t len)
+{
+ struct property *prop = of_find_property(np, propname, NULL);
+
+ if (!prop)
+ return ERR_PTR(-EINVAL);
+ if (!prop->value)
+ return ERR_PTR(-ENODATA);
+ if (len > prop->length)
+ return ERR_PTR(-EOVERFLOW);
+
+ return prop->value;
+}
+
+/**
+ * of_property_read_u32_index - Find and read a uint32_t from a multi-value property.
+ *
+ * @np: device node from which the property value is to be read.
+ * @propname: name of the property to be searched.
+ * @index: index of the uint32_t in the list of values
+ * @out_value: pointer to return value, modified only if no error.
+ *
+ * Search for a property in a device node and read nth 32-bit value from
+ * it. Returns 0 on success, -EINVAL if the property does not exist,
+ * -ENODATA if property does not have a value, and -EOVERFLOW if the
+ * property data isn't large enough.
+ *
+ * The out_value is modified only if a valid uint32_t value can be decoded.
+ */
+int of_property_read_u32_index(const struct device_node *np,
+ const char *propname,
+ uint32_t index, uint32_t *out_value)
+{
+ const uint32_t *val = of_find_property_value_of_size(np, propname,
+ ((index + 1) * sizeof(*out_value)));
+
+ if (IS_ERR(val))
+ return PTR_ERR(val);
+
+ *out_value = __be32_to_cpup(((__be32 *)val) + index);
+ return 0;
+}
+
+/**
+ * of_property_read_u8_array - Find and read an array of uint8_t from a property.
+ *
+ * @np: device node from which the property value is to be read.
+ * @propname: name of the property to be searched.
+ * @out_value: pointer to return value, modified only if return value is 0.
+ * @sz: number of array elements to read
+ *
+ * Search for a property in a device node and read 8-bit value(s) from
+ * it. Returns 0 on success, -EINVAL if the property does not exist,
+ * -ENODATA if property does not have a value, and -EOVERFLOW if the
+ * property data isn't large enough.
+ *
+ * dts entry of array should be like:
+ * property = /bits/ 8 <0x50 0x60 0x70>;
+ *
+ * The out_value is modified only if a valid uint8_t value can be decoded.
+ */
+int of_property_read_u8_array(const struct device_node *np,
+ const char *propname, uint8_t *out_values, size_t sz)
+{
+ const uint8_t *val = of_find_property_value_of_size(np, propname,
+ (sz * sizeof(*out_values)));
+
+ if (IS_ERR(val))
+ return PTR_ERR(val);
+
+ while (sz--)
+ *out_values++ = *val++;
+ return 0;
+}
+
+/**
+ * of_property_read_u16_array - Find and read an array of uint16_t from a property.
+ *
+ * @np: device node from which the property value is to be read.
+ * @propname: name of the property to be searched.
+ * @out_value: pointer to return value, modified only if return value is 0.
+ * @sz: number of array elements to read
+ *
+ * Search for a property in a device node and read 16-bit value(s) from
+ * it. Returns 0 on success, -EINVAL if the property does not exist,
+ * -ENODATA if property does not have a value, and -EOVERFLOW if the
+ * property data isn't large enough.
+ *
+ * dts entry of array should be like:
+ * property = /bits/ 16 <0x5000 0x6000 0x7000>;
+ *
+ * The out_value is modified only if a valid uint16_t value can be decoded.
+ */
+int of_property_read_u16_array(const struct device_node *np,
+ const char *propname, uint16_t *out_values, size_t sz)
+{
+ const __be16 *val = of_find_property_value_of_size(np, propname,
+ (sz * sizeof(*out_values)));
+
+ if (IS_ERR(val))
+ return PTR_ERR(val);
+
+ while (sz--)
+ *out_values++ = __be16_to_cpup(val++);
+ return 0;
+}
+
+/**
+ * of_property_read_u32_array - Find and read an array of 32 bit integers
+ * from a property.
+ *
+ * @np: device node from which the property value is to be read.
+ * @propname: name of the property to be searched.
+ * @out_value: pointer to return value, modified only if return value is 0.
+ * @sz: number of array elements to read
+ *
+ * Search for a property in a device node and read 32-bit value(s) from
+ * it. Returns 0 on success, -EINVAL if the property does not exist,
+ * -ENODATA if property does not have a value, and -EOVERFLOW if the
+ * property data isn't large enough.
+ *
+ * The out_value is modified only if a valid uint32_t value can be decoded.
+ */
+int of_property_read_u32_array(const struct device_node *np,
+ const char *propname, uint32_t *out_values,
+ size_t sz)
+{
+ const __be32 *val = of_find_property_value_of_size(np, propname,
+ (sz * sizeof(*out_values)));
+
+ if (IS_ERR(val))
+ return PTR_ERR(val);
+
+ while (sz--)
+ *out_values++ = __be32_to_cpup(val++);
+ return 0;
+}
+
+/**
+ * of_property_read_u64 - Find and read a 64 bit integer from a property
+ * @np: device node from which the property value is to be read.
+ * @propname: name of the property to be searched.
+ * @out_value: pointer to return value, modified only if return value is 0.
+ *
+ * Search for a property in a device node and read a 64-bit value from
+ * it. Returns 0 on success, -EINVAL if the property does not exist,
+ * -ENODATA if property does not have a value, and -EOVERFLOW if the
+ * property data isn't large enough.
+ *
+ * The out_value is modified only if a valid uint64_t value can be decoded.
+ */
+int of_property_read_u64(const struct device_node *np, const char *propname,
+ uint64_t *out_value)
+{
+ const __be32 *val = of_find_property_value_of_size(np, propname,
+ sizeof(*out_value));
+
+ if (IS_ERR(val))
+ return PTR_ERR(val);
+
+ *out_value = of_read_number(val, 2);
+ return 0;
+}
+
+/**
+ * of_property_read_string - Find and read a string from a property
+ * @np: device node from which the property value is to be read.
+ * @propname: name of the property to be searched.
+ * @out_string: pointer to null terminated return string, modified only if
+ * return value is 0.
+ *
+ * Search for a property in a device tree node and retrieve a null
+ * terminated string value (pointer to data, not a copy). Returns 0 on
+ * success, -EINVAL if the property does not exist, -ENODATA if property
+ * does not have a value, and -EILSEQ if the string is not null-terminated
+ * within the length of the property data.
+ *
+ * The out_string pointer is modified only if a valid string can be decoded.
+ */
+int of_property_read_string(struct device_node *np, const char *propname,
+ const char **out_string)
+{
+ struct property *prop = of_find_property(np, propname, NULL);
+ if (!prop)
+ return -EINVAL;
+ if (!prop->value)
+ return -ENODATA;
+ if (strnlen(prop->value, prop->length) >= prop->length)
+ return -EILSEQ;
+ *out_string = prop->value;
+ return 0;
+}
+
+/**
+ * of_property_read_string_index - Find and read a string from a multiple
+ * strings property.
+ * @np: device node from which the property value is to be read.
+ * @propname: name of the property to be searched.
+ * @index: index of the string in the list of strings
+ * @out_string: pointer to null terminated return string, modified only if
+ * return value is 0.
+ *
+ * Search for a property in a device tree node and retrieve a null
+ * terminated string value (pointer to data, not a copy) in the list of strings
+ * contained in that property.
+ * Returns 0 on success, -EINVAL if the property does not exist, -ENODATA if
+ * property does not have a value, and -EILSEQ if the string is not
+ * null-terminated within the length of the property data.
+ *
+ * The out_string pointer is modified only if a valid string can be decoded.
+ */
+int of_property_read_string_index(struct device_node *np, const char *propname,
+ int index, const char **output)
+{
+ struct property *prop = of_find_property(np, propname, NULL);
+ int i = 0;
+ size_t l = 0, total = 0;
+ const char *p;
+
+ if (!prop)
+ return -EINVAL;
+ if (!prop->value)
+ return -ENODATA;
+ if (strnlen(prop->value, prop->length) >= prop->length)
+ return -EILSEQ;
+
+ p = prop->value;
+
+ for (i = 0; total < prop->length; total += l, p += l) {
+ l = strlen(p) + 1;
+ if (i++ == index) {
+ *output = p;
+ return 0;
+ }
+ }
+ return -ENODATA;
+}
+
+/**
+ * of_property_match_string() - Find string in a list and return index
+ * @np: pointer to node containing string list property
+ * @propname: string list property name
+ * @string: pointer to string to search for in string list
+ *
+ * This function searches a string list property and returns the index
+ * of a specific string value.
+ */
+int of_property_match_string(struct device_node *np, const char *propname,
+ const char *string)
+{
+ struct property *prop = of_find_property(np, propname, NULL);
+ size_t l;
+ int i;
+ const char *p, *end;
+
+ if (!prop)
+ return -EINVAL;
+ if (!prop->value)
+ return -ENODATA;
+
+ p = prop->value;
+ end = p + prop->length;
+
+ for (i = 0; p < end; i++, p += l) {
+ l = strlen(p) + 1;
+ if (p + l > end)
+ return -EILSEQ;
+ pr_debug("comparing %s with %s\n", string, p);
+ if (strcmp(string, p) == 0)
+ return i; /* Found it; return index */
+ }
+ return -ENODATA;
+}
+
+/**
+ * of_property_count_strings - Find and return the number of strings from a
+ * multiple strings property.
+ * @np: device node from which the property value is to be read.
+ * @propname: name of the property to be searched.
+ *
+ * Search for a property in a device tree node and retrieve the number of null
+ * terminated string contain in it. Returns the number of strings on
+ * success, -EINVAL if the property does not exist, -ENODATA if property
+ * does not have a value, and -EILSEQ if the string is not null-terminated
+ * within the length of the property data.
+ */
+int of_property_count_strings(struct device_node *np, const char *propname)
+{
+ struct property *prop = of_find_property(np, propname, NULL);
+ int i = 0;
+ size_t l = 0, total = 0;
+ const char *p;
+
+ if (!prop)
+ return -EINVAL;
+ if (!prop->value)
+ return -ENODATA;
+ if (strnlen(prop->value, prop->length) >= prop->length)
+ return -EILSEQ;
+
+ p = prop->value;
+
+ for (i = 0; total < prop->length; total += l, p += l, i++)
+ l = strlen(p) + 1;
+
+ return i;
+}
+
+const __be32 *of_prop_next_u32(struct property *prop, const __be32 *cur,
+ uint32_t *pu)
+{
+ const void *curv = cur;
+
+ if (!prop)
+ return NULL;
+
+ if (!cur) {
+ curv = prop->value;
+ goto out_val;
+ }
+
+ curv += sizeof(*cur);
+ if (curv >= prop->value + prop->length)
+ return NULL;
+
+out_val:
+ *pu = __be32_to_cpup(curv);
+ return curv;
+}
+
+const char *of_prop_next_string(struct property *prop, const char *cur)
+{
+ const void *curv = cur;
+
+ if (!prop)
+ return NULL;
+
+ if (!cur)
+ return prop->value;
+
+ curv += strlen(cur) + 1;
+ if (curv >= prop->value + prop->length)
+ return NULL;
+
+ return curv;
+}
+
+/**
+ * of_property_write_bool - Create/Delete empty (bool) property.
+ *
+ * @np: device node from which the property is to be set.
+ * @propname: name of the property to be set.
+ *
+ * Search for a property in a device node and create or delete the property.
+ * If the property already exists and write value is false, the property is
+ * deleted. If write value is true and the property does not exist, it is
+ * created. Returns 0 on success, -ENOMEM if the property or array
+ * of elements cannot be created.
+ */
+int of_property_write_bool(struct device_node *np, const char *propname,
+ const bool value)
+{
+ struct property *prop = of_find_property(np, propname, NULL);
+
+ if (!value) {
+ if (prop)
+ of_delete_property(prop);
+ return 0;
+ }
+
+ if (!prop)
+ prop = of_new_property(np, propname, NULL, 0);
+ if (!prop)
+ return -ENOMEM;
+
+ return 0;
+}
+
+/**
+ * of_property_write_u8_array - Write an array of uint8_t to a property. If
+ * the property does not exist, it will be created and appended to the given
+ * device node.
+ *
+ * @np: device node to which the property value is to be written.
+ * @propname: name of the property to be written.
+ * @values: pointer to array elements to write.
+ * @sz: number of array elements to write.
+ *
+ * Search for a property in a device node and write 8-bit value(s) to
+ * it. If the property does not exist, it will be created and appended to
+ * the device node. Returns 0 on success, -ENOMEM if the property or array
+ * of elements cannot be created.
+ */
+int of_property_write_u8_array(struct device_node *np,
+ const char *propname, const uint8_t *values,
+ size_t sz)
+{
+ struct property *prop = of_find_property(np, propname, NULL);
+ uint8_t *val;
+
+ if (prop)
+ of_delete_property(prop);
+
+ prop = of_new_property(np, propname, NULL, sizeof(*val) * sz);
+ if (!prop)
+ return -ENOMEM;
+
+ val = prop->value;
+ while (sz--)
+ *val++ = *values++;
+
+ return 0;
+}
+
+/**
+ * of_property_write_u16_array - Write an array of uint16_t to a property. If
+ * the property does not exist, it will be created and appended to the given
+ * device node.
+ *
+ * @np: device node to which the property value is to be written.
+ * @propname: name of the property to be written.
+ * @values: pointer to array elements to write.
+ * @sz: number of array elements to write.
+ *
+ * Search for a property in a device node and write 16-bit value(s) to
+ * it. If the property does not exist, it will be created and appended to
+ * the device node. Returns 0 on success, -ENOMEM if the property or array
+ * of elements cannot be created.
+ */
+int of_property_write_u16_array(struct device_node *np,
+ const char *propname, const uint16_t *values,
+ size_t sz)
+{
+ struct property *prop = of_find_property(np, propname, NULL);
+ __be16 *val;
+
+ if (prop)
+ of_delete_property(prop);
+
+ prop = of_new_property(np, propname, NULL, sizeof(*val) * sz);
+ if (!prop)
+ return -ENOMEM;
+
+ val = prop->value;
+ while (sz--)
+ *val++ = __cpu_to_be16(*values++);
+
+ return 0;
+}
+
+/**
+ * of_property_write_u32_array - Write an array of uint32_t to a property. If
+ * the property does not exist, it will be created and appended to the given
+ * device node.
+ *
+ * @np: device node to which the property value is to be written.
+ * @propname: name of the property to be written.
+ * @values: pointer to array elements to write.
+ * @sz: number of array elements to write.
+ *
+ * Search for a property in a device node and write 32-bit value(s) to
+ * it. If the property does not exist, it will be created and appended to
+ * the device node. Returns 0 on success, -ENOMEM if the property or array
+ * of elements cannot be created.
+ */
+int of_property_write_u32_array(struct device_node *np,
+ const char *propname, const uint32_t *values,
+ size_t sz)
+{
+ struct property *prop = of_find_property(np, propname, NULL);
+ __be32 *val;
+
+ if (prop)
+ of_delete_property(prop);
+
+ prop = of_new_property(np, propname, NULL, sizeof(*val) * sz);
+ if (!prop)
+ return -ENOMEM;
+
+ val = prop->value;
+ while (sz--)
+ *val++ = __cpu_to_be32(*values++);
+
+ return 0;
+}
+
+/**
+ * of_property_write_u64_array - Write an array of uint64_t to a property. If
+ * the property does not exist, it will be created and appended to the given
+ * device node.
+ *
+ * @np: device node to which the property value is to be written.
+ * @propname: name of the property to be written.
+ * @values: pointer to array elements to write.
+ * @sz: number of array elements to write.
+ *
+ * Search for a property in a device node and write 64-bit value(s) to
+ * it. If the property does not exist, it will be created and appended to
+ * the device node. Returns 0 on success, -ENOMEM if the property or array
+ * of elements cannot be created.
+ */
+int of_property_write_u64_array(struct device_node *np,
+ const char *propname, const uint64_t *values,
+ size_t sz)
+{
+ struct property *prop = of_find_property(np, propname, NULL);
+ __be32 *val;
+
+ if (prop)
+ of_delete_property(prop);
+
+ prop = of_new_property(np, propname, NULL, 2 * sizeof(*val) * sz);
+ if (!prop)
+ return -ENOMEM;
+
+ val = prop->value;
+ while (sz--) {
+ of_write_number(val, *values++, 2);
+ val += 2;
+ }
+
+ return 0;
+}
+
+/**
+ * of_parse_phandle - Resolve a phandle property to a device_node pointer
+ * @np: Pointer to device node holding phandle property
+ * @phandle_name: Name of property holding a phandle value
+ * @index: For properties holding a table of phandles, this is the index into
+ * the table
+ *
+ * Returns the device_node pointer found or NULL.
+ */
+struct device_node *of_parse_phandle(const struct device_node *np,
+ const char *phandle_name, int index)
+{
+ const __be32 *phandle;
+ int size;
+
+ phandle = of_get_property(np, phandle_name, &size);
+ if ((!phandle) || (size < sizeof(*phandle) * (index + 1)))
+ return NULL;
+
+ return of_find_node_by_phandle(__be32_to_cpup(phandle + index));
+}
+
+/**
+ * of_parse_phandle_with_args() - Find a node pointed by phandle in a list
+ * @np: pointer to a device tree node containing a list
+ * @list_name: property name that contains a list
+ * @cells_name: property name that specifies phandles' arguments count
+ * @index: index of a phandle to parse out
+ * @out_args: optional pointer to output arguments structure (will be filled)
+ *
+ * This function is useful to parse lists of phandles and their arguments.
+ * Returns 0 on success and fills out_args, on error returns appropriate
+ * errno value.
+ *
+ * Example:
+ *
+ * phandle1: node1 {
+ * #list-cells = <2>;
+ * }
+ *
+ * phandle2: node2 {
+ * #list-cells = <1>;
+ * }
+ *
+ * node3 {
+ * list = <&phandle1 1 2 &phandle2 3>;
+ * }
+ *
+ * To get a device_node of the `node2' node you may call this:
+ * of_parse_phandle_with_args(node3, "list", "#list-cells", 1, &args);
+ */
+static int __of_parse_phandle_with_args(const struct device_node *np,
+ const char *list_name,
+ const char *cells_name, int index,
+ struct of_phandle_args *out_args)
+{
+ const __be32 *list, *list_end;
+ int rc = 0, size, cur_index = 0;
+ uint32_t count = 0;
+ struct device_node *node = NULL;
+ phandle phandle;
+
+ /* Retrieve the phandle list property */
+ list = of_get_property(np, list_name, &size);
+ if (!list)
+ return -ENOENT;
+ list_end = list + size / sizeof(*list);
+
+ /* Loop over the phandles until all the requested entry is found */
+ while (list < list_end) {
+ rc = -EINVAL;
+ count = 0;
+
+ /*
+ * If phandle is 0, then it is an empty entry with no
+ * arguments. Skip forward to the next entry.
+ */
+ phandle = __be32_to_cpup(list++);
+ if (phandle) {
+ /*
+ * Find the provider node and parse the #*-cells
+ * property to determine the argument length
+ */
+ node = of_find_node_by_phandle(phandle);
+ if (!node) {
+ pr_err("%s: could not find phandle\n",
+ np->full_name);
+ goto err;
+ }
+ if (of_property_read_u32(node, cells_name, &count)) {
+ pr_err("%s: could not get %s for %s\n",
+ np->full_name, cells_name,
+ node->full_name);
+ goto err;
+ }
+
+ /*
+ * Make sure that the arguments actually fit in the
+ * remaining property data length
+ */
+ if (list + count > list_end) {
+ pr_err("%s: arguments longer than property\n",
+ np->full_name);
+ goto err;
+ }
+ }
+
+ /*
+ * All of the error cases above bail out of the loop, so at
+ * this point, the parsing is successful. If the requested
+ * index matches, then fill the out_args structure and return,
+ * or return -ENOENT for an empty entry.
+ */
+ rc = -ENOENT;
+ if (cur_index == index) {
+ if (!phandle)
+ goto err;
+
+ if (out_args) {
+ int i;
+ if (count > MAX_PHANDLE_ARGS)
+ count = MAX_PHANDLE_ARGS;
+ out_args->np = node;
+ out_args->args_count = count;
+ for (i = 0; i < count; i++)
+ out_args->args[i] =
+ __be32_to_cpup(list++);
+ }
+
+ /* Found it! return success */
+ return 0;
+ }
+
+ node = NULL;
+ list += count;
+ cur_index++;
+ }
+
+ /*
+ * Unlock node before returning result; will be one of:
+ * -ENOENT : index is for empty phandle
+ * -EINVAL : parsing error on data
+ * [1..n] : Number of phandle (count mode; when index = -1)
+ */
+ rc = index < 0 ? cur_index : -ENOENT;
+ err:
+ return rc;
+}
+
+int of_parse_phandle_with_args(const struct device_node *np,
+ const char *list_name, const char *cells_name, int index,
+ struct of_phandle_args *out_args)
+{
+ if (index < 0)
+ return -EINVAL;
+ return __of_parse_phandle_with_args(np, list_name, cells_name,
+ index, out_args);
+}
+
+/**
+ * of_count_phandle_with_args() - Find the number of phandles references in a property
+ * @np: pointer to a device tree node containing a list
+ * @list_name: property name that contains a list
+ * @cells_name: property name that specifies phandles' arguments count
+ *
+ * Returns the number of phandle + argument tuples within a property. It
+ * is a typical pattern to encode a list of phandle and variable
+ * arguments into a single property. The number of arguments is encoded
+ * by a property in the phandle-target node. For example, a gpios
+ * property would contain a list of GPIO specifies consisting of a
+ * phandle and 1 or more arguments. The number of arguments are
+ * determined by the #gpio-cells property in the node pointed to by the
+ * phandle.
+ */
+int of_count_phandle_with_args(const struct device_node *np,
+ const char *list_name, const char *cells_name)
+{
+ return __of_parse_phandle_with_args(np, list_name, cells_name,
+ -1, NULL);
+}
+
+/**
+ * of_machine_is_compatible - Test root of device tree for a given compatible value
+ * @compat: compatible string to look for in root node's compatible property.
+ *
+ * Returns true if the root node has the given value in its
+ * compatible property.
+ */
+int of_machine_is_compatible(const char *compat)
+{
+ if (!root_node)
+ return 0;
+
+ return of_device_is_compatible(root_node, compat);
+}
+
+/**
+ * of_find_node_by_path_from - Find a node matching a full OF path
+ * relative to a given root node.
+ * @path: The full path to match
+ *
+ * Returns a pointer to the node found or NULL.
+ */
+struct device_node *of_find_node_by_path_from(struct device_node *from,
+ const char *path)
+{
+ char *slash, *p, *freep;
+
+ if (!from)
+ from = root_node;
+
+ if (!from || !path || *path != '/')
+ return NULL;
+
+ path++;
+
+ freep = p = strdup(path);
+
+ while (1) {
+ if (!*p)
+ goto out;
+
+ slash = strchr(p, '/');
+ if (slash)
+ *slash = 0;
+
+ from = of_get_child_by_name(from, p);
+ if (!from)
+ goto out;
+
+ if (!slash)
+ goto out;
+
+ p = slash + 1;
+ }
+out:
+ free(freep);
+
+ return from;
+}
+
+/**
+ * of_find_node_by_path - Find a node matching a full OF path
+ * @path: The full path to match
+ *
+ * Returns a pointer to the node found or NULL.
+ */
+struct device_node *of_find_node_by_path(const char *path)
+{
+ return of_find_node_by_path_from(root_node, path);
+}
+
+/**
+ * of_find_node_by_path_or_alias - Find a node matching a full OF path
+ * or an alias
+ * @root: The root node. If NULL the internal tree is used
+ * @str: the full path or alias
+ *
+ * Returns a pointer to the node found or NULL.
+ */
+struct device_node *of_find_node_by_path_or_alias(struct device_node *root,
+ const char *str)
+{
+ if (*str == '/')
+ return of_find_node_by_path_from(root, str);
+ else
+ return of_find_node_by_alias(root, str);
+
+}
+
+/**
+ * of_modalias_node - Lookup appropriate modalias for a device node
+ * @node: pointer to a device tree node
+ * @modalias: Pointer to buffer that modalias value will be copied into
+ * @len: Length of modalias value
+ *
+ * Based on the value of the compatible property, this routine will attempt
+ * to choose an appropriate modalias value for a particular device tree node.
+ * It does this by stripping the manufacturer prefix (as delimited by a ',')
+ * from the first entry in the compatible list property.
+ *
+ * This routine returns 0 on success, <0 on failure.
+ */
+int of_modalias_node(struct device_node *node, char *modalias, int len)
+{
+ const char *compatible, *p;
+ int cplen;
+
+ compatible = of_get_property(node, "compatible", &cplen);
+ if (!compatible || strlen(compatible) > cplen)
+ return -ENODEV;
+ p = strchr(compatible, ',');
+ strlcpy(modalias, p ? p + 1 : compatible, len);
+ return 0;
+}
+
+struct device_node *of_get_root_node(void)
+{
+ return root_node;
+}
+
+int of_set_root_node(struct device_node *node)
+{
+ if (node && root_node)
+ return -EBUSY;
+
+ root_node = node;
+
+ of_alias_scan();
+
+ return 0;
+}
+
+/**
+ * of_device_is_available - check if a device is available for use
+ *
+ * @device: Node to check for availability
+ *
+ * Returns 1 if the status property is absent or set to "okay" or "ok",
+ * 0 otherwise
+ */
+int of_device_is_available(const struct device_node *device)
+{
+ const char *status;
+ int statlen;
+
+ status = of_get_property(device, "status", &statlen);
+ if (status == NULL)
+ return 1;
+
+ if (statlen > 0) {
+ if (!strcmp(status, "okay") || !strcmp(status, "ok"))
+ return 1;
+ }
+
+ return 0;
+}
+
+/**
+ * of_get_parent - Get a node's parent if any
+ * @node: Node to get parent
+ *
+ * Returns a pointer to the parent node or NULL if already at root.
+ */
+struct device_node *of_get_parent(const struct device_node *node)
+{
+ return (!node) ? NULL : node->parent;
+}
+
+/**
+ * of_get_next_available_child - Find the next available child node
+ * @node: parent node
+ * @prev: previous child of the parent node, or NULL to get first
+ *
+ * This function is like of_get_next_child(), except that it
+ * automatically skips any disabled nodes (i.e. status = "disabled").
+ */
+struct device_node *of_get_next_available_child(const struct device_node *node,
+ struct device_node *prev)
+{
+ prev = list_prepare_entry(prev, &node->children, parent_list);
+ list_for_each_entry_continue(prev, &node->children, parent_list)
+ if (of_device_is_available(prev))
+ return prev;
+ return NULL;
+}
+
+/**
+ * of_get_child_count - Count child nodes of given parent node
+ * @parent: parent node
+ *
+ * Returns the number of child nodes or -EINVAL on NULL parent node.
+ */
+int of_get_child_count(const struct device_node *parent)
+{
+ struct device_node *child;
+ int num = 0;
+
+ if (!parent)
+ return -EINVAL;
+
+ for_each_child_of_node(parent, child)
+ num++;
+
+ return num;
+}
+
+/**
+ * of_get_available_child_count - Count available child nodes of given
+ * parent node
+ * @parent: parent node
+ *
+ * Returns the number of available child nodes or -EINVAL on NULL parent
+ * node.
+ */
+int of_get_available_child_count(const struct device_node *parent)
+{
+ struct device_node *child;
+ int num = 0;
+
+ if (!parent)
+ return -EINVAL;
+
+ for_each_child_of_node(parent, child)
+ if (of_device_is_available(child))
+ num++;
+
+ return num;
+}
+
+/**
+ * of_get_child_by_name - Find the child node by name for a given parent
+ * @node: parent node
+ * @name: child name to look for.
+ *
+ * This function looks for child node for given matching name
+ *
+ * Returns a node pointer if found or NULL.
+ */
+struct device_node *of_get_child_by_name(const struct device_node *node,
+ const char *name)
+{
+ struct device_node *child;
+
+ for_each_child_of_node(node, child)
+ if (child->name && (of_node_cmp(child->name, name) == 0))
+ return child;
+
+ return NULL;
+}
+
+void of_print_nodes(struct device_node *node, int indent)
+{
+ struct device_node *n;
+ struct property *p;
+ int i;
+
+ if (!node)
+ return;
+
+ for (i = 0; i < indent; i++)
+ printf("\t");
+
+ printf("%s%s\n", node->name, node->name ? " {" : "{");
+
+ list_for_each_entry(p, &node->properties, list) {
+ for (i = 0; i < indent + 1; i++)
+ printf("\t");
+ printf("%s", p->name);
+ if (p->length) {
+ printf(" = ");
+ of_print_property(p->value, p->length);
+ }
+ printf(";\n");
+ }
+
+ list_for_each_entry(n, &node->children, parent_list) {
+ of_print_nodes(n, indent + 1);
+ }
+
+ for (i = 0; i < indent; i++)
+ printf("\t");
+ printf("};\n");
+}
+
+struct device_node *of_new_node(struct device_node *parent, const char *name)
+{
+ struct device_node *node;
+ int ret;
+
+ node = xzalloc(sizeof(*node));
+ node->parent = parent;
+ if (parent)
+ list_add_tail(&node->parent_list, &parent->children);
+
+ INIT_LIST_HEAD(&node->children);
+ INIT_LIST_HEAD(&node->properties);
+
+ if (parent) {
+ node->name = strdup(name);
+ ret = asprintf(&node->full_name, "%s/%s", node->parent->full_name, name);
+ if (ret < 0)
+ return NULL;
+ list_add(&node->list, &parent->list);
+ } else {
+ node->name = strdup("");
+ node->full_name = strdup("");
+ INIT_LIST_HEAD(&node->list);
+ }
+
+ return node;
+}
+
+struct property *of_new_property(struct device_node *node, const char *name,
+ const void *data, int len)
+{
+ struct property *prop;
+
+ prop = xzalloc(sizeof(*prop));
+ prop->name = strdup(name);
+ if (!prop->name) {
+ free(prop);
+ return NULL;
+ }
+
+ prop->length = len;
+ prop->value = xzalloc(len);
+
+ if (data)
+ memcpy(prop->value, data, len);
+
+ list_add_tail(&prop->list, &node->properties);
+
+ return prop;
+}
+
+void of_delete_property(struct property *pp)
+{
+ if (!pp)
+ return;
+
+ list_del(&pp->list);
+
+ free(pp->name);
+ free(pp->value);
+ free(pp);
+}
+
+/**
+ * of_set_property - create a property for a given node
+ * @node - the node
+ * @name - the name of the property
+ * @val - the value for the property
+ * @len - the length of the properties value
+ * @create - if true, the property is created if not existing already
+ */
+int of_set_property(struct device_node *np, const char *name, const void *val, int len,
+ int create)
+{
+ struct property *pp = of_find_property(np, name, NULL);
+
+ if (!np)
+ return -ENOENT;
+
+ if (!pp && !create)
+ return -ENOENT;
+
+ of_delete_property(pp);
+
+ pp = of_new_property(np, name, val, len);
+ if (!pp)
+ return -ENOMEM;
+
+ return 0;
+}
+
+struct device_node *of_chosen;
+const char *of_model;
+
+const char *of_get_model(void)
+{
+ return of_model;
+}
+
+const struct of_device_id of_default_bus_match_table[] = {
+ {
+ .compatible = "simple-bus",
+ }, {
+ /* sentinel */
+ }
+};
+
+/**
+ * of_create_node - create a new node including its parents
+ * @path - the nodepath to create
+ */
+struct device_node *of_create_node(struct device_node *root, const char *path)
+{
+ char *slash, *p, *freep;
+ struct device_node *tmp, *dn = root;
+
+ if (*path != '/')
+ return NULL;
+
+ path++;
+
+ p = freep = strdup(path);
+
+ while (1) {
+ if (!*p)
+ goto out;
+
+ slash = strchr(p, '/');
+ if (slash)
+ *slash = 0;
+
+ tmp = of_get_child_by_name(dn, p);
+ if (tmp)
+ dn = tmp;
+ else
+ dn = of_new_node(dn, p);
+
+ if (!dn)
+ goto out;
+
+ if (!slash)
+ goto out;
+
+ p = slash + 1;
+ }
+out:
+ free(freep);
+
+ return dn;
+}
+
+void of_delete_node(struct device_node *node)
+{
+ struct device_node *n, *nt;
+ struct property *p, *pt;
+
+ if (!node)
+ return;
+
+ list_for_each_entry_safe(p, pt, &node->properties, list)
+ of_delete_property(p);
+
+ list_for_each_entry_safe(n, nt, &node->children, parent_list)
+ of_delete_node(n);
+
+ if (node->parent) {
+ list_del(&node->parent_list);
+ list_del(&node->list);
+ }
+
+ free(node->name);
+ free(node->full_name);
+ free(node);
+
+ if (node == root_node)
+ of_set_root_node(NULL);
+}
+
+/**
+ * of_device_enable - enable a devicenode device
+ * @node - the node to enable
+ *
+ * This deletes the status property of a devicenode effectively
+ * enabling the device.
+ */
+int of_device_enable(struct device_node *node)
+{
+ struct property *pp;
+
+ pp = of_find_property(node, "status", NULL);
+ if (!pp)
+ return 0;
+
+ of_delete_property(pp);
+
+ return 0;
+}
+
+/**
+ * of_device_enable_path - enable a devicenode
+ * @path - the nodepath to enable
+ *
+ * wrapper around of_device_enable taking the nodepath as argument
+ */
+int of_device_enable_path(const char *path)
+{
+ struct device_node *node;
+
+ node = of_find_node_by_path(path);
+ if (!node)
+ return -ENODEV;
+
+ return of_device_enable(node);
+}
+
+/**
+ * of_device_enable - disable a devicenode device
+ * @node - the node to disable
+ *
+ * This sets the status of a devicenode to "disabled"
+ */
+int of_device_disable(struct device_node *node)
+{
+ return of_set_property(node, "status", "disabled", sizeof("disabled"), 1);
+}
+
+/**
+ * of_device_disable_path - disable a devicenode
+ * @path - the nodepath to disable
+ *
+ * wrapper around of_device_disable taking the nodepath as argument
+ */
+int of_device_disable_path(const char *path)
+{
+ struct device_node *node;
+
+ node = of_find_node_by_path(path);
+ if (!node)
+ return -ENODEV;
+
+ return of_device_disable(node);
+}
+
+int scan_proc_dir(struct device_node *node, const char *path)
+{
+ DIR *dir;
+ struct dirent *dirent;
+ struct stat s;
+ int ret;
+ void *buf;
+
+ dir = opendir(path);
+ if (!dir)
+ return -errno;
+
+ while (1) {
+ char *cur;
+
+ dirent = readdir(dir);
+ if (!dirent)
+ break;
+
+ if (dirent->d_name[0] == '.')
+ continue;
+
+ ret = asprintf(&cur, "%s/%s", path, dirent->d_name);
+ if (ret < 0)
+ return -ENOMEM;
+
+ ret = stat(cur, &s);
+ if (ret)
+ return -errno;
+
+ if (S_ISREG(s.st_mode)) {
+ int fd;
+
+ fd = open(cur, O_RDONLY);
+ if (fd < 0)
+ return -errno;
+
+ buf = xzalloc(s.st_size);
+ ret = read(fd, buf, s.st_size);
+ if (ret < 0)
+ return -errno;
+ close(fd);
+
+ of_new_property(node, dirent->d_name, buf, s.st_size);
+ }
+
+ if (S_ISDIR(s.st_mode)) {
+ struct device_node *new;
+ new = of_new_node(node, dirent->d_name);
+ scan_proc_dir(new, cur);
+ }
+
+ free(cur);
+ }
+
+ closedir(dir);
+
+ return 0;
+}
+
+struct device_node *of_read_proc_devicetree(void)
+{
+ struct device_node *root;
+ int ret;
+
+ root = of_new_node(NULL, NULL);
+
+ ret = scan_proc_dir(root, "/sys/firmware/devicetree/base");
+ if (!ret)
+ return root;
+
+ ret = scan_proc_dir(root, "/proc/device-tree");
+ if (!ret)
+ return root;
+
+ of_delete_node(root);
+ return ERR_PTR(ret);
+}
+
+struct udev_device *of_find_device_by_node_path(const char *of_full_path)
+{
+ struct udev *udev;
+ struct udev_enumerate *enumerate;
+ struct udev_list_entry *devices, *dev_list_entry;
+ struct udev_device *dev;
+
+ udev = udev_new();
+ if (!udev) {
+ fprintf(stderr, "Can't create udev\n");
+ return NULL;
+ }
+
+ enumerate = udev_enumerate_new(udev);
+ udev_enumerate_add_match_property(enumerate, "OF_FULLNAME", of_full_path);
+ udev_enumerate_scan_devices(enumerate);
+ devices = udev_enumerate_get_list_entry(enumerate);
+
+ udev_list_entry_foreach(dev_list_entry, devices) {
+ const char *path;
+
+ /*
+ * Get the filename of the /sys entry for the device
+ * and create a udev_device object (dev) representing it
+ */
+ path = udev_list_entry_get_name(dev_list_entry);
+ dev = udev_device_new_from_syspath(udev, path);
+
+ goto out;
+ }
+
+ dev = NULL;
+out:
+ udev_enumerate_unref(enumerate);
+ udev_unref(udev);
+
+ return dev;
+}
+
+struct udev_device *device_find_partition(struct udev_device *dev, const char *name)
+{
+ struct udev *udev;
+ struct udev_enumerate *enumerate;
+ struct udev_list_entry *devices, *dev_list_entry;
+ struct udev_device *part;
+
+ udev = udev_new();
+ if (!udev) {
+ fprintf(stderr, "Can't create udev\n");
+ return NULL;
+ }
+
+ enumerate = udev_enumerate_new(udev);
+ udev_enumerate_add_match_parent(enumerate, dev);
+ udev_enumerate_scan_devices(enumerate);
+ devices = udev_enumerate_get_list_entry(enumerate);
+ udev_list_entry_foreach(dev_list_entry, devices) {
+ const char *path, *partname;
+ path = udev_list_entry_get_name(dev_list_entry);
+ part = udev_device_new_from_syspath(udev, path);
+ partname = udev_device_get_sysattr_value(part, "name");
+ if (!partname)
+ continue;
+ if (!strcmp(partname, name))
+ return part;
+ }
+
+ udev_enumerate_unref(enumerate);
+ udev_unref(udev);
+
+ return NULL;
+}
+
+struct of_path_type {
+ const char *name;
+ int (*parse)(struct of_path *op, const char *str);
+};
+
+/**
+ * of_path_type_partname - find a partition based on physical device and
+ * partition name
+ * @op: of_path context
+ * @name: the partition name to find
+ */
+static int of_path_type_partname(struct of_path *op, const char *name)
+{
+ struct udev_device *part;
+ struct stat s;
+ int ret;
+ struct device_node *node;
+
+ if (!op->dev)
+ return -EINVAL;
+
+ part = device_find_partition(op->dev, name);
+ if (part) {
+ op->devpath = strdup(udev_device_get_devnode(part));
+ pr_debug("%s: found part '%s'\n", __func__, name);
+ return 0;
+ }
+
+ ret = asprintf(&op->devpath, "%s/eeprom", udev_device_get_syspath(op->dev));
+ if (ret < 0)
+ return -ENOMEM;
+
+ ret = stat(op->devpath, &s);
+ if (ret)
+ return -errno;
+
+ for_each_child_of_node(op->node, node) {
+ const char *partname;
+ int len;
+
+ partname = of_get_property(node, "label", &len);
+ if (!strcmp(partname, name)) {
+ const __be32 *reg;
+ int a_cells, s_cells;
+
+ reg = of_get_property(node, "reg", &len);
+ if (!reg)
+ continue;
+
+ a_cells = of_n_addr_cells(node);
+ s_cells = of_n_size_cells(node);
+
+ op->offset = of_read_number(reg, a_cells);
+ op->size = of_read_number(reg + a_cells, s_cells);
+
+ break;
+ }
+ }
+
+ return 0;
+}
+
+static struct of_path_type of_path_types[] = {
+ {
+ .name = "partname",
+ .parse = of_path_type_partname,
+ },
+};
+#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
+
+static int of_path_parse_one(struct of_path *op, const char *str)
+{
+ int i, ret;
+ char *name, *desc;
+
+ pr_debug("parsing: %s\n", str);
+
+ name = strdup(str);
+ desc = strchr(name, ':');
+ if (!desc) {
+ free(name);
+ return -EINVAL;
+ }
+
+ *desc = 0;
+ desc++;
+
+ for (i = 0; i < ARRAY_SIZE(of_path_types); i++) {
+ if (!strcmp(of_path_types[i].name, name)) {
+ ret = of_path_types[i].parse(op, desc);
+ goto out;
+ }
+ }
+
+ ret = -EINVAL;
+out:
+ free(name);
+
+ return ret;
+}
+
+/**
+ * of_find_path - translate a path description in the devicetree to a device node
+ * path
+ *
+ * @node: the node containing the property with the path description
+ * @propname: the property name of the path description
+ * @outpath: if this function returns 0 outpath will contain the path belonging
+ * to the input path description. Must be freed with free().
+ *
+ * pathes in the devicetree have the form of a multistring property. The first
+ * string contains the full path to the physical device containing the path.
+ * The remaining strings have the form "<type>:<options>". Currently supported
+ * for <type> are:
+ *
+ * partname:<partname> - find a partition by its partition name. For mtd
+ * partitions this is the label. For DOS partitions
+ * this is the number beginning with 0.
+ *
+ * examples:
+ *
+ * device-path = &mmc0, "partname:0";
+ * device-path = &norflash, "partname:barebox-environment";
+ */
+int of_find_path(struct device_node *node, const char *propname, struct of_path *op)
+{
+ struct device_node *rnode;
+ const char *path, *str;
+ int i, len, ret;
+
+ memset(op, 0, sizeof(*op));
+
+ path = of_get_property(node, propname, &len);
+ if (!path)
+ return -EINVAL;
+
+ rnode = of_find_node_by_path(path);
+ if (!rnode)
+ return -ENODEV;
+
+ op->node = rnode;
+
+ op->dev = of_find_device_by_node_path(rnode->full_name);
+ if (!op->dev)
+ return -ENODEV;
+
+ i = 1;
+
+ while (1) {
+ ret = of_property_read_string_index(node, propname, i++, &str);
+ if (ret)
+ break;
+
+ ret = of_path_parse_one(op, str);
+ if (ret)
+ return ret;
+ }
+
+ if (!op->devpath)
+ return -ENOENT;
+
+ pr_debug("%s: devpath: %s ofs: 0x%08llx size: 0x%08lx\n",
+ __func__, op->devpath, op->offset, op->size);
+
+ return 0;
+}
diff --git a/src/libdt.pc.in b/src/libdt.pc.in
new file mode 100644
index 0000000..2fc7b76
--- /dev/null
+++ b/src/libdt.pc.in
@@ -0,0 +1,11 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: libabc
+Description: Library for something with abc
+Version: @VERSION@
+Libs: -L${libdir} -labc
+Libs.private:
+Cflags: -I${includedir}
diff --git a/src/libdt.sym b/src/libdt.sym
new file mode 100644
index 0000000..c034ea2
--- /dev/null
+++ b/src/libdt.sym
@@ -0,0 +1,74 @@
+LIBDT_1 {
+global:
+ of_print_property;
+ of_n_addr_cells;
+ of_n_size_cells;
+ of_find_property;
+ of_alias_scan;
+ of_alias_get_id;
+ of_alias_get;
+ of_find_node_by_alias;
+ of_find_node_by_phandle;
+ of_get_tree_max_phandle;
+ of_node_create_phandle;
+ of_get_property;
+ of_device_is_compatible;
+ of_find_node_by_name;
+ of_find_node_by_type;
+ of_find_compatible_node;
+ of_find_node_with_property;
+ of_match_node;
+ of_find_matching_node_and_match;
+ of_property_read_u32_index;
+ of_property_read_u8_array;
+ of_property_read_u16_array;
+ of_property_read_u32_array;
+ of_property_read_u64;
+ of_property_read_string;
+ of_property_read_string_index;
+ of_property_match_string;
+ of_property_count_strings;
+ of_prop_next_u32;
+ of_prop_next_string;
+ of_property_write_bool;
+ of_property_write_u8_array;
+ of_property_write_u16_array;
+ of_property_write_u32_array;
+ of_property_write_u64_array;
+ of_parse_phandle;
+ of_parse_phandle_with_args;
+ of_count_phandle_with_args;
+ of_machine_is_compatible;
+ of_find_node_by_path_from;
+ of_find_node_by_path;
+ of_find_node_by_path_or_alias;
+ of_modalias_node;
+ of_get_root_node;
+ of_set_root_node;
+ of_device_is_available;
+ of_get_parent;
+ of_get_next_available_child;
+ of_get_child_count;
+ of_get_available_child_count;
+ of_get_child_by_name;
+ of_print_nodes;
+ of_new_node;
+ of_new_property;
+ of_delete_property;
+ of_set_property;
+ of_create_node;
+ of_delete_node;
+ of_device_enable;
+ of_device_enable_path;
+ of_device_disable;
+ of_device_disable_path;
+ of_read_proc_devicetree;
+ of_find_device_by_node_path;
+ device_find_partition;
+ of_find_path;
+ of_unflatten_dtb;
+ crc32;
+ crc32_no_comp;
+local:
+ *;
+};
diff --git a/src/state.c b/src/state.c
new file mode 100644
index 0000000..97c6b4a
--- /dev/null
+++ b/src/state.c
@@ -0,0 +1,1309 @@
+/*
+ * state.c - state handling tool
+ *
+ * Copyright (c) 2014 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ */
+#include <libudev.h>
+#include <common.h>
+#include <dirent.h>
+#include <getopt.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <dt.h>
+
+#include <asm/byteorder.h>
+#include <linux/types.h>
+#include <mtd/mtd-abi.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+static int verbose;
+
+enum state_variable_type {
+ STATE_TYPE_INVALID = 0,
+ STATE_TYPE_ENUM,
+ STATE_TYPE_U32,
+ STATE_TYPE_MAC,
+};
+
+struct state_backend;
+
+struct state {
+ struct list_head variables;
+ const char *name;
+ struct list_head list;
+ struct state_backend *backend;
+ uint32_t magic;
+ int dirty;
+};
+
+struct state_backend {
+ int (*load)(struct state_backend *backend, struct state *state);
+ int (*save)(struct state_backend *backend, struct state *state);
+ const char *name;
+ char *path;
+};
+
+/* list of all registered state instances */
+static LIST_HEAD(state_list);
+
+/* instance of a single variable */
+struct state_variable {
+ enum state_variable_type type;
+ struct list_head list;
+ char *name;
+ void *raw;
+ int raw_size;
+ int index;
+};
+
+/* A variable type (uint32, enum32) */
+struct variable_type {
+ enum state_variable_type type;
+ const char *type_name;
+ struct list_head list;
+ int (*export)(struct state_variable *, struct device_node *);
+ int (*init)(struct state_variable *, struct device_node *);
+ struct state_variable *(*create)(struct state *state,
+ const char *name, struct device_node *);
+ char *(*get)(struct state_variable *);
+ int (*set)(struct state_variable *, const char *val);
+ void (*info)(struct state_variable *);
+};
+
+/*
+ * uint32
+ */
+struct state_uint32 {
+ struct state_variable var;
+ struct param_d *param;
+ uint32_t value;
+ uint32_t value_default;
+};
+
+static int state_var_compare(struct list_head *a, struct list_head *b)
+{
+ struct state_variable *va = list_entry(a, struct state_variable, list);
+ struct state_variable *vb = list_entry(b, struct state_variable, list);
+
+ if (va->index == vb->index)
+ return 0;
+
+ return va->index < vb->index ? -1 : 1;
+}
+
+static int state_add_variable(struct state *state, struct state_variable *var)
+{
+ list_add_sort(&var->list, &state->variables, state_var_compare);
+
+ return 0;
+}
+
+static inline struct state_uint32 *to_state_uint32(struct state_variable *s)
+{
+ return container_of(s, struct state_uint32, var);
+}
+
+static int state_uint32_export(struct state_variable *var,
+ struct device_node *node)
+{
+ struct state_uint32 *su32 = to_state_uint32(var);
+ int ret;
+
+ ret = of_property_write_u32(node, "default", su32->value_default);
+ if (ret)
+ return ret;
+
+ return of_property_write_u32(node, "value", su32->value);
+}
+
+static int state_uint32_init(struct state_variable *sv,
+ struct device_node *node)
+{
+ int len;
+ const __be32 *value, *value_default;
+ struct state_uint32 *su32 = to_state_uint32(sv);
+
+ value_default = of_get_property(node, "default", &len);
+ if (value_default && len != sizeof(uint32_t))
+ return -EINVAL;
+
+ value = of_get_property(node, "value", &len);
+ if (value && len != sizeof(uint32_t))
+ return -EINVAL;
+
+ if (value_default)
+ su32->value_default = be32_to_cpu(*value_default);
+ if (value)
+ su32->value = be32_to_cpu(*value);
+ else
+ su32->value = su32->value_default;
+
+ return 0;
+}
+
+static struct state_variable *state_uint32_create(struct state *state,
+ const char *name, struct device_node *node)
+{
+ struct state_uint32 *su32;
+
+ su32 = xzalloc(sizeof(*su32));
+
+ pr_debug("%s: %s\n", __func__, name);
+
+ su32->var.raw_size = sizeof(uint32_t);
+ su32->var.raw = &su32->value;
+
+ return &su32->var;
+}
+
+static int state_uint32_set(struct state_variable *var, const char *val)
+{
+ struct state_uint32 *su32 = to_state_uint32(var);
+
+ su32->value = strtoul(val, NULL, 0);
+
+ return 0;
+}
+
+static char *state_uint32_get(struct state_variable *var)
+{
+ struct state_uint32 *su32 = to_state_uint32(var);
+ char *str;
+ int ret;
+
+ ret = asprintf(&str, "%d", su32->value);
+ if (ret < 0)
+ return ERR_PTR(-ENOMEM);
+
+ return str;
+}
+
+/*
+ * enum32
+ */
+struct state_enum32 {
+ struct state_variable var;
+ struct param_d *param;
+ uint32_t value;
+ uint32_t value_default;
+ const char **names;
+ int num_names;
+};
+
+static inline struct state_enum32 *to_state_enum32(struct state_variable *s)
+{
+ return container_of(s, struct state_enum32, var);
+}
+
+static int state_enum32_export(struct state_variable *var,
+ struct device_node *node)
+{
+ struct state_enum32 *enum32 = to_state_enum32(var);
+ int ret, i, len;
+ char *prop, *str;
+
+ ret = of_property_write_u32(node, "default", enum32->value_default);
+ if (ret)
+ return ret;
+
+ ret = of_property_write_u32(node, "value", enum32->value);
+ if (ret)
+ return ret;
+
+ len = 0;
+
+ for (i = 0; i < enum32->num_names; i++)
+ len += strlen(enum32->names[i]) + 1;
+
+ prop = xzalloc(len);
+ str = prop;
+
+ for (i = 0; i < enum32->num_names; i++)
+ str += sprintf(str, "%s", enum32->names[i]) + 1;
+
+ ret = of_set_property(node, "names", prop, len, 1);
+
+ free(prop);
+
+ return ret;
+}
+
+static int state_enum32_init(struct state_variable *sv, struct device_node *node)
+{
+ struct state_enum32 *enum32 = to_state_enum32(sv);
+ int len;
+ const __be32 *value, *value_default;
+
+ value = of_get_property(node, "value", &len);
+ if (value && len != sizeof(uint32_t))
+ return -EINVAL;
+
+ value_default = of_get_property(node, "default", &len);
+ if (value_default && len != sizeof(uint32_t))
+ return -EINVAL;
+
+ if (value_default)
+ enum32->value_default = be32_to_cpu(*value_default);
+ if (value)
+ enum32->value = be32_to_cpu(*value);
+ else
+ enum32->value = enum32->value_default;
+
+ return 0;
+}
+
+static struct state_variable *state_enum32_create(struct state *state,
+ const char *name, struct device_node *node)
+{
+ struct state_enum32 *enum32;
+ int ret, i, num_names;
+
+ enum32 = xzalloc(sizeof(*enum32));
+
+ num_names = of_property_count_strings(node, "names");
+
+ enum32->names = xzalloc(sizeof(char *) * num_names);
+ enum32->num_names = num_names;
+ enum32->var.raw_size = sizeof(uint32_t);
+ enum32->var.raw = &enum32->value;
+
+ for (i = 0; i < num_names; i++) {
+ const char *name;
+
+ ret = of_property_read_string_index(node, "names", i, &name);
+ if (ret)
+ goto out;
+ enum32->names[i] = strdup(name);
+ }
+
+ pr_debug("%s: %s\n", __func__, name);
+
+ return &enum32->var;
+out:
+ free(enum32->names);
+ free(enum32);
+ return ERR_PTR(ret);
+}
+
+static int state_enum32_set(struct state_variable *sv, const char *val)
+{
+ struct state_enum32 *enum32 = to_state_enum32(sv);
+ int i;
+
+ for (i = 0; i < enum32->num_names; i++) {
+ if (!strcmp(enum32->names[i], val)) {
+ enum32->value = i;
+ return 0;
+ }
+ }
+
+ return -EINVAL;
+}
+
+static char *state_enum32_get(struct state_variable *var)
+{
+ struct state_enum32 *enum32 = to_state_enum32(var);
+ char *str;
+ int ret;
+
+ ret = asprintf(&str, "%s", enum32->names[enum32->value]);
+ if (ret < 0)
+ return ERR_PTR(-ENOMEM);
+
+ return str;
+}
+
+static void state_enum32_info(struct state_variable *var)
+{
+ struct state_enum32 *enum32 = to_state_enum32(var);
+ int i;
+
+ printf(", values=[");
+
+ for (i = 0; i < enum32->num_names; i++)
+ printf("%s%s", enum32->names[i],
+ i == enum32->num_names - 1 ? "" : ",");
+ printf("]");
+}
+
+/*
+ * MAC address
+ */
+struct state_mac {
+ struct state_variable var;
+ struct param_d *param;
+ uint8_t value[6];
+ uint8_t value_default[6];
+};
+
+static inline struct state_mac *to_state_mac(struct state_variable *s)
+{
+ return container_of(s, struct state_mac, var);
+}
+
+static int state_mac_export(struct state_variable *var,
+ struct device_node *node)
+{
+ struct state_mac *mac = to_state_mac(var);
+ int ret;
+
+ ret = of_property_write_u8_array(node, "default", mac->value_default, 6);
+ if (ret)
+ return ret;
+
+ return of_property_write_u8_array(node, "value", mac->value, 6);
+}
+
+static int state_mac_init(struct state_variable *sv, struct device_node *node)
+{
+ struct state_mac *mac = to_state_mac(sv);
+ uint8_t value[6] = {};
+ uint8_t value_default[6] = {};
+
+ of_property_read_u8_array(node, "default", value_default, 6);
+ memcpy(mac->value_default, value_default, 6);
+
+ if (!of_property_read_u8_array(node, "value", value, 6))
+ memcpy(mac->value, value, 6);
+ else
+ memcpy(mac->value, value_default, 6);
+
+ return 0;
+}
+
+static struct state_variable *state_mac_create(struct state *state,
+ const char *name, struct device_node *node)
+{
+ struct state_mac *mac;
+ int ret;
+
+ mac = xzalloc(sizeof(*mac));
+
+ mac->var.raw_size = 6;
+ mac->var.raw = mac->value;
+
+ pr_debug("%s: %s\n", __func__, name);
+
+ return &mac->var;
+out:
+ free(mac);
+ return ERR_PTR(ret);
+}
+
+int string_to_ethaddr(const char *str, uint8_t enetaddr[6])
+{
+ int reg;
+ char *e;
+
+ if (!str || strlen(str) != 17) {
+ memset(enetaddr, 0, 6);
+ return -EINVAL;
+ }
+
+ if (str[2] != ':' || str[5] != ':' || str[8] != ':' ||
+ str[11] != ':' || str[14] != ':')
+ return -EINVAL;
+
+ for (reg = 0; reg < 6; ++reg) {
+ enetaddr[reg] = strtoul(str, &e, 16);
+ str = e + 1;
+ }
+
+ return 0;
+}
+
+static int state_mac_set(struct state_variable *var, const char *val)
+{
+ struct state_mac *mac = to_state_mac(var);
+ char mac_save[6];
+ int ret;
+
+ ret = string_to_ethaddr(val, mac_save);
+ if (ret)
+ return ret;
+
+ memcpy(mac->value, mac_save, 6);
+
+ return 0;
+}
+
+static char *state_mac_get(struct state_variable *var)
+{
+ struct state_mac *mac = to_state_mac(var);
+ char *str;
+ int ret;
+
+ ret = asprintf(&str, "%02x:%02x:%02x:%02x:%02x:%02x",
+ mac->value[0], mac->value[1], mac->value[2],
+ mac->value[3], mac->value[4], mac->value[5]);
+ if (ret < 0)
+ return ERR_PTR(-ENOMEM);
+
+ return str;
+}
+
+static struct variable_type types[] = {
+ {
+ .type = STATE_TYPE_U32,
+ .type_name = "uint32",
+ .export = state_uint32_export,
+ .init = state_uint32_init,
+ .create = state_uint32_create,
+ .set = state_uint32_set,
+ .get = state_uint32_get,
+ }, {
+ .type = STATE_TYPE_ENUM,
+ .type_name = "enum32",
+ .export = state_enum32_export,
+ .init = state_enum32_init,
+ .create = state_enum32_create,
+ .set = state_enum32_set,
+ .get = state_enum32_get,
+ .info = state_enum32_info,
+ }, {
+ .type = STATE_TYPE_MAC,
+ .type_name = "mac",
+ .export = state_mac_export,
+ .init = state_mac_init,
+ .create = state_mac_create,
+ .set = state_mac_set,
+ .get = state_mac_get,
+ },
+};
+
+static struct variable_type *state_find_type(enum state_variable_type type)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(types); i++) {
+ if (type == types[i].type) {
+ return &types[i];
+ }
+ }
+
+ return NULL;
+}
+
+static struct variable_type *state_find_type_by_name(const char *name)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(types); i++) {
+ if (!strcmp(name, types[i].type_name)) {
+ return &types[i];
+ }
+ }
+
+ return NULL;
+}
+
+/*
+ * Generic state functions
+ */
+
+static struct state *state_new(const char *name)
+{
+ struct state *state;
+ int ret;
+
+ state = xzalloc(sizeof(*state));
+ state->name = name;
+ INIT_LIST_HEAD(&state->variables);
+
+ list_add_tail(&state->list, &state_list);
+
+ return state;
+}
+
+static void state_release(struct state *state)
+{
+ free(state);
+}
+
+static struct device_node *state_to_node(struct state *state)
+{
+ struct device_node *root, *node;
+ struct state_variable *sv;
+ int ret;
+
+ root = of_new_node(NULL, NULL);
+
+ list_for_each_entry(sv, &state->variables, list) {
+ struct variable_type *vtype;
+ char *name;
+
+ asprintf(&name, "%s@%d", sv->name, sv->index);
+ node = of_new_node(root, name);
+ free(name);
+
+ vtype = state_find_type(sv->type);
+ if (!vtype) {
+ ret = -ENOENT;
+ goto out;
+ }
+
+ of_set_property(node, "type", vtype->type_name,
+ strlen(vtype->type_name) + 1, 1);
+
+ ret = vtype->export(sv, node);
+ if (ret)
+ goto out;
+ }
+
+ of_property_write_u32(root, "magic", state->magic);
+
+ return root;
+out:
+ of_delete_node(root);
+ return ERR_PTR(ret);
+}
+
+static struct state_variable *state_find_var(struct state *state, const char *name)
+{
+ struct state_variable *sv;
+
+ list_for_each_entry(sv, &state->variables, list) {
+ if (!strcmp(sv->name, name))
+ return sv;
+ }
+
+ return NULL;
+}
+
+static char *state_get_var(struct state *state, const char *var)
+{
+ struct state_variable *sv;
+ struct variable_type *vtype;
+
+ sv = state_find_var(state, var);
+ if (!sv)
+ return NULL;
+
+ vtype = state_find_type(sv->type);
+
+ return vtype->get(sv);
+}
+
+static int state_set_var(struct state *state, const char *var, const char *val)
+{
+ struct state_variable *sv;
+ struct variable_type *vtype;
+ int ret;
+
+ sv = state_find_var(state, var);
+ if (!sv)
+ return -ENOENT;
+
+ vtype = state_find_type(sv->type);
+
+ if (!vtype->set)
+ return -EPERM;
+
+ ret = vtype->set(sv, val);
+ if (ret)
+ return ret;
+
+ state->dirty = 1;
+
+ return 0;
+}
+
+static int state_variable_from_node(struct state *state, struct device_node *node,
+ bool create)
+{
+ struct variable_type *vtype;
+ struct state_variable *sv;
+ char *name, *indexs;
+ int index = 0;
+ const char *type_name = NULL;
+
+ of_property_read_string(node, "type", &type_name);
+ if (!type_name)
+ return -EINVAL;
+
+ vtype = state_find_type_by_name(type_name);
+ if (!vtype)
+ return -ENOENT;
+
+ name = strdup(node->name);
+ indexs = strchr(name, '@');
+ if (indexs) {
+ *indexs++ = 0;
+ index = strtoul(indexs, NULL, 10);
+ }
+
+ if (create) {
+ sv = vtype->create(state, name, node);
+ if (IS_ERR(sv)) {
+ int ret = PTR_ERR(sv);
+ pr_err("failed to create %s: %s\n", name, strerror(-ret));
+ return ret;
+ }
+ sv->name = name;
+ sv->type = vtype->type;
+ sv->index = index;
+ state_add_variable(state, sv);
+ } else {
+ sv = state_find_var(state, name);
+ if (IS_ERR(sv)) {
+ int ret = PTR_ERR(sv);
+ pr_err("no such variable: %s: %s\n", name, strerror(-ret));
+ return ret;
+ }
+ }
+
+ vtype->init(sv, node);
+
+ return 0;
+}
+
+int state_from_node(struct state *state, struct device_node *node, bool create)
+{
+ struct device_node *child;
+ int ret;
+ uint32_t magic;
+
+ of_property_read_u32(node, "magic", &magic);
+
+ if (create) {
+ state->magic = magic;
+ } else {
+ if (state->magic && state->magic != magic) {
+ pr_err("invalid magic 0x%08x, should be 0x%08x\n",
+ magic, state->magic);
+ return -EINVAL;
+ }
+ }
+
+ for_each_child_of_node(node, child) {
+ ret = state_variable_from_node(state, child, create);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+/*
+ * state_new_from_node - create a new state instance from a device_node
+ *
+ * @name The name of the new state instance
+ * @node The device_node describing the new state instance
+ */
+struct state *state_new_from_node(const char *name, struct device_node *node)
+{
+ struct state *state;
+ int ret;
+
+ state = state_new(name);
+ if (!state)
+ return ERR_PTR(-EINVAL);
+
+ ret = state_from_node(state, node, 1);
+ if (ret) {
+ state_release(state);
+ return ERR_PTR(ret);
+ }
+
+ return state;
+}
+
+/*
+ * state_by_name - find a state instance by name
+ *
+ * @name The name of the state instance
+ */
+struct state *state_by_name(const char *name)
+{
+ struct state *s;
+
+ list_for_each_entry(s, &state_list, list) {
+ if (!strcmp(name, s->name))
+ return s;
+ }
+
+ return NULL;
+}
+
+/*
+ * state_load - load a state from the backing store
+ *
+ * @state The state instance to load
+ */
+int state_load(struct state *state)
+{
+ int ret;
+
+ if (!state->backend)
+ return -ENOSYS;
+
+ ret = state->backend->load(state->backend, state);
+ if (ret)
+ return ret;
+
+ state->dirty = 0;
+
+ return 0;
+}
+
+/*
+ * state_save - save a state to the backing store
+ *
+ * @state The state instance to save
+ */
+int state_save(struct state *state)
+{
+ int ret;
+
+ if (!state->backend)
+ return -ENOSYS;
+
+ ret = state->backend->save(state->backend, state);
+ if (ret)
+ return ret;
+
+ state->dirty = 0;
+
+ return 0;
+}
+
+void state_info(void)
+{
+ struct state *s;
+
+ printf("registered state instances:\n");
+
+ list_for_each_entry(s, &state_list, list) {
+ printf("%-20s ", s->name);
+ if (s->backend)
+ printf("(backend: %s, path: %s)\n", s->backend->name, s->backend->path);
+ else
+ printf("(no backend)\n");
+ }
+}
+
+static int get_meminfo(const char *path, struct mtd_info_user *meminfo)
+{
+ int fd, ret;
+
+ fd = open(path, O_RDWR);
+ if (fd < 0)
+ return -errno;
+
+ ret = ioctl(fd, MEMGETINFO, meminfo);
+
+ close(fd);
+
+ if (ret)
+ return -errno;
+
+ return 0;
+}
+
+/*
+ * Raw backend implementation
+ */
+struct state_backend_raw {
+ struct state_backend backend;
+ struct state *state;
+ unsigned long size_data; /* The raw data size (without magic and crc) */
+ unsigned long size_full;
+ unsigned long step; /* The step in bytes between two copies */
+ off_t offset; /* offset in the storage file */
+ size_t size; /* size of the storage area */
+ int need_erase;
+ int num_copy_read; /* The first successfully read copy */
+};
+
+struct backend_raw_header {
+ uint32_t magic;
+ uint16_t reserved;
+ uint16_t data_len;
+ uint32_t data_crc;
+ uint32_t header_crc;
+};
+
+static int backend_raw_load_one(struct state_backend_raw *backend_raw,
+ int fd, off_t offset)
+{
+ struct state *state = backend_raw->state;
+ uint32_t crc;
+ void *off;
+ struct state_variable *sv;
+ struct backend_raw_header header = {};
+ int ret, len;
+ void *buf;
+
+ ret = lseek(fd, offset, SEEK_SET);
+ if (ret < 0)
+ return ret;
+
+ ret = read(fd, &header, sizeof(header));
+ if (ret < 0)
+ return ret;
+ if (ret < sizeof(header))
+ return -EINVAL;
+
+ crc = crc32(0, &header, sizeof(header) - sizeof(uint32_t));
+ if (crc != header.header_crc) {
+ pr_err("invalid header crc, calculated 0x%08x, found 0x%08x\n",
+ crc, header.header_crc);
+ return -EINVAL;
+ }
+
+ if (state->magic && state->magic != header.magic) {
+ pr_err("invalid magic 0x%08x, should be 0x%08x\n",
+ header.magic, state->magic);
+ return -EINVAL;
+ }
+
+ buf = xzalloc(header.data_len);
+
+ ret = read(fd, buf, header.data_len);
+ if (ret < 0)
+ return ret;
+ if (ret < header.data_len)
+ return -EINVAL;
+
+ crc = crc32(0, buf, header.data_len);
+ if (crc != header.data_crc) {
+ pr_err("invalid crc, calculated 0x%08x, found 0x%08x\n",
+ crc, header.data_crc);
+ return -EINVAL;
+ }
+
+ off = buf;
+ len = header.data_len;
+
+ list_for_each_entry(sv, &state->variables, list) {
+ if (len < sv->raw_size) {
+ break;
+ }
+ memcpy(sv->raw, off, sv->raw_size);
+ off += sv->raw_size;
+ len -= sv->raw_size;
+ }
+
+ free(buf);
+
+ return 0;
+}
+
+static int state_backend_raw_load(struct state_backend *backend, struct state *state)
+{
+ struct state_backend_raw *backend_raw = container_of(backend,
+ struct state_backend_raw, backend);
+ int ret = 0, fd, i;
+
+ fd = open(backend->path, O_RDONLY);
+ if (fd < 0)
+ return fd;
+
+ for (i = 0; i < 2; i++) {
+ off_t offset = backend_raw->offset + i * backend_raw->step;
+
+ ret = backend_raw_load_one(backend_raw, fd, offset);
+ if (!ret) {
+ backend_raw->num_copy_read = i;
+ pr_debug("copy %d successfully loaded\n", i);
+ break;
+ }
+ }
+
+ close(fd);
+
+ return ret;
+}
+
+static int backend_raw_write_one(struct state_backend_raw *backend_raw,
+ int fd, int num, void *buf, size_t size)
+{
+ int ret;
+ off_t offset = backend_raw->offset + num * backend_raw->step;
+
+ pr_debug(&backend_raw->state->dev, "%s: 0x%08lx 0x%08x\n",
+ __func__, offset, size);
+
+ if (backend_raw->need_erase) {
+ struct erase_info_user erase = {
+ .start = offset,
+ .length = backend_raw->step,
+ };
+
+ ret = ioctl(fd, MEMERASE, &erase);
+ if (ret < 0)
+ return -errno;
+ }
+
+ ret = lseek(fd, offset, SEEK_SET);
+ if (ret < 0)
+ return -errno;
+
+ ret = write(fd, buf, size);
+ if (ret < 0)
+ return -errno;
+
+ return 0;
+}
+
+static int state_backend_raw_save(struct state_backend *backend, struct state *state)
+{
+ struct state_backend_raw *backend_raw = container_of(backend,
+ struct state_backend_raw, backend);
+ int ret = 0, size, fd;
+ void *buf, *freep, *off, *data, *tmp;
+ struct backend_raw_header *header;
+ struct state_variable *sv;
+
+ size = backend_raw->size_data + sizeof(struct backend_raw_header);
+
+ freep = off = buf = xzalloc(size);
+
+ header = buf;
+ data = buf + sizeof(*header);
+
+ tmp = data;
+ list_for_each_entry(sv, &state->variables, list) {
+ memcpy(tmp, sv->raw, sv->raw_size);
+ tmp += sv->raw_size;
+ }
+
+ header->magic = state->magic;
+ header->data_len = backend_raw->size_data;
+ header->data_crc = crc32(0, data, backend_raw->size_data);
+ header->header_crc = crc32(0, header, sizeof(*header) - sizeof(uint32_t));
+
+ fd = open(backend->path, O_WRONLY);
+ if (fd < 0)
+ return fd;
+
+ ret = backend_raw_write_one(backend_raw, fd, !backend_raw->num_copy_read, buf, size);
+ if (ret)
+ goto out;
+
+ ret = backend_raw_write_one(backend_raw, fd, backend_raw->num_copy_read, buf, size);
+ if (ret)
+ goto out;
+
+ pr_debug("wrote state to %s\n", backend->path);
+out:
+ close(fd);
+ free(buf);
+
+ return ret;
+}
+
+/*
+ * state_backend_raw_file - create a raw file backend store for a state instance
+ *
+ * @state The state instance to work on
+ * @path The path where the state will be stored to
+ * @offset The offset in the storage file
+ * @size The maximum size to use in the storage file
+ *
+ * This backend stores raw binary data from a state instance. The binary data is
+ * protected with a magic value which has to match and a crc32 that must be valid.
+ * Up to four copies are stored if there is sufficient space available.
+ * @path can be a path to a device or a regular file. When it's a device @size may
+ * be 0. The four copies a spread to different eraseblocks if approriate for this
+ * device.
+ */
+int state_backend_raw_file(struct state *state, const char *path, off_t offset,
+ size_t size)
+{
+ struct state_backend_raw *backend_raw;
+ struct state_backend *backend;
+ struct state_variable *sv;
+ int ret;
+ struct stat s;
+ struct mtd_info_user meminfo;
+
+ if (state->backend)
+ return -EBUSY;
+
+ ret = stat(path, &s);
+ if (!ret && !S_ISCHR(s.st_mode)) {
+ if (size == 0)
+ size = s.st_size;
+ else if (offset + size > s.st_size)
+ return -EINVAL;
+ }
+
+ backend_raw = xzalloc(sizeof(*backend_raw));
+ backend = &backend_raw->backend;
+
+ backend->load = state_backend_raw_load;
+ backend->save = state_backend_raw_save;
+ backend->path = strdup(path);
+ backend->name = "raw";
+
+ list_for_each_entry(sv, &state->variables, list)
+ backend_raw->size_data += sv->raw_size;
+
+ backend_raw->state = state;
+ backend_raw->offset = offset;
+ backend_raw->size_full = backend_raw->size_data + sizeof(struct backend_raw_header);
+
+ state->backend = backend;
+
+ ret = get_meminfo(backend->path, &meminfo);
+ if (!ret) {
+ if (!size)
+ size = meminfo.size;
+ backend_raw->need_erase = 1;
+ backend_raw->step = ALIGN(backend_raw->size_full, meminfo.erasesize);
+ if (verbose)
+ fprintf(stderr, "%s is a mtd of size %d, adjust stepsize to %ld\n",
+ path, meminfo.size, backend_raw->step);
+ } else {
+ backend_raw->step = backend_raw->size_full;
+ }
+
+ backend_raw->size = size;
+
+ if (backend_raw->size / backend_raw->step < 2) {
+ pr_err("not enough space for two copies, have %d, need %d\n",
+ backend_raw->size, backend_raw->step * 2);
+ ret = -ENOSPC;
+ goto err;
+ }
+
+ return 0;
+err:
+ free(backend_raw);
+ return ret;
+}
+
+static struct state *state_get(const char *name)
+{
+ struct device_node *root, *node;
+ char *path;
+ struct state *state;
+ int ret;
+ const char *backend_type = NULL;
+ struct of_path op;
+ struct state_variable *v;
+
+ root = of_read_proc_devicetree();
+ if (IS_ERR(root)) {
+ fprintf(stderr, "Unable to read devicetree from /proc/device-tree: %s\n",
+ strerror(-PTR_ERR(root)));
+ return ERR_CAST(root);
+ }
+
+ of_set_root_node(root);
+
+ node = of_find_node_by_path_or_alias(root, name);
+ if (!node) {
+ fprintf(stderr, "no such node: %s\n", name);
+ return ERR_PTR(-ENOENT);
+ }
+
+ if (verbose > 1) {
+ printf("found state node %s:\n", node->full_name);
+ of_print_nodes(node, 0);
+ }
+
+ state = state_new_from_node("state", node);
+ if (IS_ERR(state)) {
+ fprintf(stderr, "unable to initlialize state: %s\n",
+ strerror(PTR_ERR(state)));
+ return ERR_CAST(state);
+ }
+
+ ret = of_find_path(node, "backend", &op);
+ if (ret) {
+ fprintf(stderr, "Cannot find backend path in %s\n", node->full_name);
+ return ERR_PTR(ret);
+ }
+
+ of_property_read_string(node, "backend-type", &backend_type);
+ if (!strcmp(backend_type, "raw"))
+ ret = state_backend_raw_file(state, op.devpath, op.offset, op.size);
+ else
+ fprintf(stderr, "invalid backend type: %s\n", backend_type);
+
+ if (ret) {
+ fprintf(stderr, "Cannot initialize backend: %s\n", strerror(-ret));
+ return ERR_PTR(ret);
+ }
+
+ return state;
+}
+
+enum opt {
+ OPT_DUMP_SHELL = 1,
+};
+
+static struct option long_options[] = {
+ {"get", required_argument, 0, 'g' },
+ {"set", required_argument, 0, 's' },
+ {"name", required_argument, 0, 'n' },
+ {"dump", no_argument, 0, 'd' },
+ {"dump-shell", no_argument, 0, OPT_DUMP_SHELL },
+ {"init", no_argument, 0, 'i' },
+ {"verbose", no_argument, 0, 'v' },
+ {"help", no_argument, 0, 'h' },
+};
+
+static void usage(char *name)
+{
+ printf(
+"Usage: %s [OPTIONS]\n"
+"\n"
+"-g, --get <variable> get the value of a variable\n"
+"-s, --set <variable>=<value> set the value of a variable\n"
+"-n, --name <name> specify the state to use (default=\"state\")\n"
+"-d, --dump dump the state\n"
+"--dump-shell dump the state suitable for shell sourcing\n"
+"--init initialize the state (do not load from storage)\n"
+"-v, --verbose increase verbosity\n"
+"--help this help\n",
+ name);
+}
+
+#define state_for_each_var(state, var) \
+ list_for_each_entry(var, &(state)->variables, list)
+
+struct state_set_get {
+ char *arg;
+ int get;
+ struct list_head list;
+};
+
+int main(int argc, char *argv[])
+{
+ struct state *state;
+ struct state_variable *v;
+ int ret, c, option_index;
+ int do_dump = 0, do_dump_shell = 0, do_initialize = 0;
+ struct state_set_get *sg;
+ struct list_head sg_list;
+ char *statename = "state";
+
+ INIT_LIST_HEAD(&sg_list);
+
+ while (1) {
+ c = getopt_long(argc, argv, "hg:s:divn:", long_options, &option_index);
+ if (c < 0)
+ break;
+ switch (c) {
+ case 'h':
+ usage(argv[0]);
+ exit(0);
+ case 'g':
+ sg = xzalloc(sizeof(*sg));
+ sg->get = 1;
+ sg->arg = optarg;
+ list_add_tail(&sg->list, &sg_list);
+ break;
+ case 's':
+ sg = xzalloc(sizeof(*sg));
+ sg->get = 0;
+ sg->arg = optarg;
+ list_add_tail(&sg->list, &sg_list);
+ break;
+ case 'd':
+ do_dump = 1;
+ break;
+ case 'i':
+ do_initialize = 1;
+ break;
+ case OPT_DUMP_SHELL:
+ do_dump_shell = 1;
+ break;
+ case 'v':
+ verbose++;
+ break;
+ case 'n':
+ statename = optarg;
+ }
+ }
+
+ state = state_get(statename);
+ if (IS_ERR(state))
+ exit(1);
+
+ ret = state_load(state);
+ if (!do_initialize && ret) {
+ fprintf(stderr, "Cannot load state: %s\n", strerror(-ret));
+ exit(1);
+ }
+
+ if (do_dump) {
+ state_for_each_var(state, v) {
+ struct variable_type *vtype;
+ vtype = state_find_type(v->type);
+ printf("%s=%s", v->name, vtype->get(v));
+ if (verbose) {
+ printf(", type=%s", vtype->type_name);
+ if (vtype->info)
+ vtype->info(v);
+ }
+ printf("\n");
+ }
+ }
+
+ if (do_dump_shell) {
+ state_for_each_var(state, v) {
+ struct variable_type *vtype;
+ vtype = state_find_type(v->type);
+ printf("STATE_%s=\"%s\"\n", v->name, vtype->get(v));
+ }
+ }
+
+ list_for_each_entry(sg, &sg_list, list) {
+ if (sg->get) {
+ char *val = state_get_var(state, sg->arg);
+ if (!val) {
+ fprintf(stderr, "no such variable: %s\n", sg->arg);
+ exit (1);
+ }
+
+ printf("%s\n", val);
+ } else {
+ char *var, *val;
+
+ var = sg->arg;
+ val = index(sg->arg, '=');
+ if (!val) {
+ fprintf(stderr, "usage: -s var=val\n");
+ exit (1);
+ }
+ *val++ = '\0';
+ ret = state_set_var(state, var, val);
+ if (ret) {
+ fprintf(stderr, "Failed to set variable %s to %s: %s\n",
+ var, val, strerror(-ret));
+ exit(1);
+ }
+ }
+ }
+
+ if (state->dirty) {
+ ret = state_save(state);
+ if (ret) {
+ fprintf(stderr, "Failed to save state: %s\n", strerror(-ret));
+ exit(1);
+ }
+ }
+
+ return 0;
+}