From patchwork Thu Aug 25 06:41:08 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Peter A. G. Crosthwaite" X-Patchwork-Id: 111468 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [140.186.70.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id B7D71B6F6F for ; Thu, 25 Aug 2011 16:43:29 +1000 (EST) Received: from localhost ([::1]:38785 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1QwTer-0007Nm-Q1 for incoming@patchwork.ozlabs.org; Thu, 25 Aug 2011 02:43:21 -0400 Received: from eggs.gnu.org ([140.186.70.92]:46798) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1QwTeg-0007C0-3T for qemu-devel@nongnu.org; Thu, 25 Aug 2011 02:43:11 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1QwTee-0003vd-F5 for qemu-devel@nongnu.org; Thu, 25 Aug 2011 02:43:10 -0400 Received: from mail-yx0-f173.google.com ([209.85.213.173]:38508) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1QwTee-0003vW-5X for qemu-devel@nongnu.org; Thu, 25 Aug 2011 02:43:08 -0400 Received: by yxt3 with SMTP id 3so1679833yxt.4 for ; Wed, 24 Aug 2011 23:43:07 -0700 (PDT) Received: by 10.236.179.98 with SMTP id g62mr37952200yhm.2.1314254587476; Wed, 24 Aug 2011 23:43:07 -0700 (PDT) Received: from localhost ([124.148.20.9]) by mx.google.com with ESMTPS id e21sm466027yhn.63.2011.08.24.23.43.03 (version=TLSv1/SSLv3 cipher=OTHER); Wed, 24 Aug 2011 23:43:06 -0700 (PDT) From: "Peter A. G. Crosthwaite" To: qemu-devel@nongnu.org, stefanha@linux.vnet.ibm.com, edgar.iglesias@gmail.com, john.williams@petalogix.com, michal.simek@petalogix.com Date: Thu, 25 Aug 2011 16:41:08 +1000 Message-Id: <1314254480-22438-3-git-send-email-peter.crosthwaite@petalogix.com> X-Mailer: git-send-email 1.7.3.2 In-Reply-To: <1314254480-22438-1-git-send-email-peter.crosthwaite@petalogix.com> References: <1314254480-22438-1-git-send-email-peter.crosthwaite@petalogix.com> X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.6 (newer, 2) X-Received-From: 209.85.213.173 Cc: "Peter A. G. Crosthwaite" Subject: [Qemu-devel] [RFC PATCH V1 02/14] device_tree: Extended interface for fdt_generic X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Extended the wrapper interface (around libfdt) for device tree. Node Property getters have been added (qemu_devtree_getprop*) as well as helpers to search/ navigate the nodes of a FDT blob. Signed-off-by: Peter A. G. Crosthwaite --- device_tree.c | 202 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ device_tree.h | 30 +++++++++ 2 files changed, 232 insertions(+), 0 deletions(-) diff --git a/device_tree.c b/device_tree.c index 3a224d1..c48c90a 100644 --- a/device_tree.c +++ b/device_tree.c @@ -107,3 +107,205 @@ int qemu_devtree_setprop_string(void *fdt, const char *node_path, return fdt_setprop_string(fdt, offset, property, string); } + +/* FIXME: guard against move argument running off the end of the parameter */ + +int qemu_devtree_getprop(void *fdt, int *err, const char *node_path, + const char *type, int move, int inherit) +{ + int offset = fdt_path_offset(fdt, node_path); + unsigned int *temp; + + if (err) { + *err = 0; + } + + temp = (unsigned int *)fdt_getprop(fdt, offset, type, NULL); + + if (temp) { + return be32_to_cpu(*(temp + move)); + } else if (inherit) { + char parent [DT_PATH_LENGTH]; + if (!qemu_devtree_getparent(fdt, parent, node_path)) { + return qemu_devtree_getprop(fdt, err, parent, type, move, 1); + } + } + if (err) { + *err = 1; + } + return 0; +} + +char *qemu_devtree_getprop_string(void *fdt, const char *node_path, + const char *type, int move, int *len, int inherit) +{ + int offset = fdt_path_offset(fdt, node_path); + int llen; + const char *temp; + if (!len) { + len = &llen; + } + temp = fdt_getprop(fdt, offset, type, len); + + if (temp) { + char *ret; + while (move) { + char *next = memchr(temp, '\0', *len) + 1; + *len -= (next - temp); + temp = next; + if (*len <= 0) { + printf("Can't get %s property - not enough elements\n", type); + return NULL; + } + move--; + } + ret = g_malloc0(*len); + memcpy(ret, temp, *len); + return ret; + } else if (inherit) { + char parent [DT_PATH_LENGTH]; + if (!qemu_devtree_getparent(fdt, parent, node_path)) { + return qemu_devtree_getprop_string(fdt, parent, type, move, len, + 1); + } + } + return NULL; +} + +char *qemu_devtree_get_node_name(void *fdt, const char *node_path) { + char *ret = fdt_get_name(fdt, fdt_path_offset(fdt, node_path), NULL); + return ret ? strdup(ret) : NULL; +} + +int qemu_devtree_get_node_depth(void *fdt, const char *node_path) +{ + return fdt_node_depth(fdt, fdt_path_offset(fdt, node_path)); +} + +static void qemu_devtree_children_info(void *fdt, const char *node_path, + int depth, int *num, char **returned_paths) { + int offset = fdt_path_offset(fdt, node_path); + int root_depth = fdt_node_depth(fdt, offset); + int cur_depth = root_depth; + *num = 0; + for (;;) { + offset = fdt_next_node(fdt, offset, &cur_depth); + if (cur_depth <= root_depth) { + break; + } + if (cur_depth <= root_depth + depth || depth == 0) { + if (returned_paths) { + returned_paths[*num] = g_malloc0(DT_PATH_LENGTH); + fdt_get_path(fdt, offset, returned_paths[*num], DT_PATH_LENGTH); + } + (*num)++; + } + } +} + +char **qemu_devtree_get_children(void *fdt, const char *node_path, int depth) +{ + int num_children = qemu_devtree_get_num_children(fdt, node_path, depth); + char **ret = g_malloc0(sizeof(*ret) * num_children); + qemu_devtree_children_info(fdt, node_path, depth, &num_children, ret); + return ret; +} + +int qemu_devtree_get_num_children(void *fdt, const char *node_path, int depth) +{ + int ret; + qemu_devtree_children_info(fdt, node_path, depth, &ret, NULL); + return ret; +} + +int qemu_devtree_node_by_compatible(void *fdt, char *node_path, + const char *compats) +{ + int offset = fdt_node_offset_by_compatible(fdt, 0, compats); + return offset > 0 ? + fdt_get_path(fdt, offset, node_path, DT_PATH_LENGTH) : 1; +} + +int qemu_devtree_get_node_by_name(void *fdt, char *node_path, + const char *cmpname) { + int offset = 0; + char *name = NULL; + do { + offset = fdt_next_node(fdt, offset, NULL); + name = (void *)fdt_get_name(fdt, offset, NULL); + if (!name) { + continue; + } + if (!strncmp(name, cmpname, strlen(cmpname))) { + break; + } + } while (offset > 0); + return offset > 0 ? + fdt_get_path(fdt, offset, node_path, DT_PATH_LENGTH) : 1; +} + +int qemu_devtree_get_node_by_phandle(void *fdt, char *node_path, int phandle) +{ + return fdt_get_path(fdt, fdt_node_offset_by_phandle(fdt, phandle), + node_path, DT_PATH_LENGTH); +} + +int qemu_devtree_getparent(void *fdt, char *node_path, const char *current) +{ + int offset = fdt_path_offset(fdt, current); + int parent_offset = fdt_supernode_atdepth_offset(fdt, offset, + fdt_node_depth(fdt, offset) -1, NULL); + return parent_offset > 0 ? + fdt_get_path(fdt, parent_offset, node_path, DT_PATH_LENGTH) : 1; +} + +static void devtree_scan(void *fdt, int *num_nodes, int info_dump) +{ + int depth = 0, offset = 0; + if (num_nodes) { + *num_nodes = 0; + } + for (;;) { + offset = fdt_next_node(fdt, offset, &depth); + if (num_nodes) + (*num_nodes)++; + if (offset <= 0 || depth <= 0) + break; + + if (info_dump) { + char node_path[DT_PATH_LENGTH]; + char *all_compats = 0; + int compat_len; + if (fdt_get_path(fdt, offset, node_path, DT_PATH_LENGTH)) + sprintf(node_path, "(none)"); + else + all_compats = qemu_devtree_getprop_string(fdt, node_path, + "compatible", 0, &compat_len, 0); + if (all_compats) { + char *i = all_compats; + for (;;) { + char *j = rawmemchr(i, '\0'); + compat_len -= ((j+1)-i); + if (!compat_len) + break; + *j = ' '; + i = j+1; + } + } + printf("OFFSET: %d, DEPTH: %d, PATH: %s, COMPATS: %s\n", offset, + depth, node_path, all_compats ? all_compats : "(none)"); + } + } +} + +void devtree_info_dump(void *fdt) +{ + devtree_scan(fdt, NULL, 1); +} + +int devtree_get_num_nodes(void *fdt) +{ + int ret; + devtree_scan(fdt, &ret, 0); + return ret; +} diff --git a/device_tree.h b/device_tree.h index cecd98f..e4f2d8a 100644 --- a/device_tree.h +++ b/device_tree.h @@ -16,6 +16,8 @@ void *load_device_tree(const char *filename_path, int *sizep); +/* property setters */ + int qemu_devtree_setprop(void *fdt, const char *node_path, const char *property, void *val_array, int size); int qemu_devtree_setprop_cell(void *fdt, const char *node_path, @@ -23,4 +25,32 @@ int qemu_devtree_setprop_cell(void *fdt, const char *node_path, int qemu_devtree_setprop_string(void *fdt, const char *node_path, const char *property, const char *string); +/* property getters */ + +int qemu_devtree_getprop(void *fdt, int *err, const char *node_path, + const char *type, int move, int inherit); +char *qemu_devtree_getprop_string(void *fdt, const char *node_path, + const char *type, int move, int *len, int inherit); +char *qemu_devtree_get_node_name(void *fdt, const char *node_path); +int qemu_devtree_get_node_depth(void *fdt, const char *node_path); +int qemu_devtree_get_num_children(void *fdt, const char *node_path, int depth); +char **qemu_devtree_get_children(void *fdt, const char *node_path, int depth); + +/* node getters */ + +int qemu_devtree_node_by_compatible(void *fdt, char *node_path, + const char *compats); +int qemu_devtree_get_node_by_name(void *fdt, char *node_path, + const char *cmpname); +int qemu_devtree_get_node_by_phandle(void *fdt, char *node_path, int phandle); +int qemu_devtree_getparent(void *fdt, char *node_path, + const char *current); + +/* misc */ + +int devtree_get_num_nodes(void *fdt); +void devtree_info_dump(void *fdt); + +#define DT_PATH_LENGTH 1024 + #endif /* __DEVICE_TREE_H__ */