diff --git a/common.h b/common.h new file mode 100644 index 0000000..4ccec88 --- /dev/null +++ b/common.h @@ -0,0 +1,108 @@ + +#include + +/** + * 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; +} + +#endif diff --git a/list.h b/list.h new file mode 100644 index 0000000..c17b5d4 --- /dev/null +++ b/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/of.c b/of.c new file mode 100644 index 0000000..4e5e6c6 --- /dev/null +++ b/of.c @@ -0,0 +1,2206 @@ +/* + * base.c - basic devicetree functions + * + * Copyright (c) 2012 Sascha Hauer , 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. + */ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "of.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; + + asprintf(&cur, "%s/%s", path, dirent->d_name); + ret = stat(cur, &s); + if (ret) + return ret; + + 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 ret; + 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, "/proc/device-tree"); + if (ret) { + of_delete_node(root); + return NULL; + } + + return root; +} + +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) { + printf("Can't create udev\n"); + exit(1); + } + + 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; + + /* Create the udev object */ + udev = udev_new(); + if (!udev) { + printf("Can't create udev\n"); + exit(1); + } + + 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 { + char *devpath; + off_t offset; + size_t size; + struct udev_device *dev; + struct device_node *node; +}; + +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; + } + + asprintf(&op->devpath, "%s/eeprom", udev_device_get_syspath(op->dev)); + ret = stat(op->devpath, &s); + if (ret) + return ret; + + 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 ":". Currently supported + * for are: + * + * 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, char **outpath) +{ + struct of_path op = {}; + struct device_node *rnode; + const char *path, *str; + int i, len, ret; + + 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; + + printf("devpath: %s ofs: 0x%08lx size: 0x%08x\n", op.devpath, op.offset, op.size); + + return 0; +} + +int main(int argc, char *argv[]) +{ + struct device_node *root, *node; + char *devnode; + + root = of_read_proc_devicetree(); + root_node = root; + + node = of_find_node_by_path_or_alias(root, argv[1]); + if (!node) { + printf("no such node: %s\n", argv[1]); + return 1; + } + + of_find_path(node, argv[2], &devnode); + + return 0; + + of_print_nodes(root, 0); + + for_each_compatible_node(node, NULL, "barebox,state") { + of_print_nodes(node, 0); + } + + return 0; +} diff --git a/of.h b/of.h new file mode 100644 index 0000000..a0d613e --- /dev/null +++ b/of.h @@ -0,0 +1,368 @@ +#ifndef __OF_H +#define __OF_H + +#include "list.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); +int of_find_path(struct device_node *node, const char *propname, char **outpath); + +#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; +} +#endif /* __OF_H */