source: mainline/boot/genarch/src/ofw_tree.c@ 0aa06cbe

Last change on this file since 0aa06cbe was a35b458, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 8 years ago

style: Remove trailing whitespace on _all_ lines, including empty ones, for particular file types.

Command used: tools/srepl '\s\+$' '' -- *.c *.h *.py *.sh *.s *.S *.ag

Currently, whitespace on empty lines is very inconsistent.
There are two basic choices: Either remove the whitespace, or keep empty lines
indented to the level of surrounding code. The former is AFAICT more common,
and also much easier to do automatically.

Alternatively, we could write script for automatic indentation, and use that
instead. However, if such a script exists, it's possible to use the indented
style locally, by having the editor apply relevant conversions on load/save,
without affecting remote repository. IMO, it makes more sense to adopt
the simpler rule.

  • Property mode set to 100644
File size: 7.3 KB
Line 
1/*
2 * Copyright (c) 2006 Jakub Jermar
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#include <genarch/ofw_tree.h>
30#include <genarch/ofw.h>
31#include <arch/ofw.h>
32#include <stddef.h>
33#include <str.h>
34#include <balloc.h>
35#include <memstr.h>
36
37static char path[OFW_TREE_PATH_MAX_LEN + 1];
38static char name[OFW_TREE_PROPERTY_MAX_NAMELEN];
39static char name2[OFW_TREE_PROPERTY_MAX_NAMELEN];
40
41static ofw_tree_node_t *ofw_tree_node_alloc(void)
42{
43 return balloc(sizeof(ofw_tree_node_t), sizeof(ofw_tree_node_t));
44}
45
46static ofw_tree_property_t *ofw_tree_properties_alloc(size_t count)
47{
48 return balloc(count * sizeof(ofw_tree_property_t),
49 sizeof(ofw_tree_property_t));
50}
51
52static void *ofw_tree_space_alloc(size_t size)
53{
54 /*
55 * What we do here is a nasty hack :-)
56 * Problem: string property values that are allocated via this
57 * function typically do not contain the trailing '\0'. This
58 * is very uncomfortable for kernel, which is supposed to deal
59 * with the properties.
60 * Solution: when allocating space via this function, we always
61 * allocate space for the extra '\0' character that we store
62 * behind the requested memory.
63 */
64 char *addr = balloc(size + 1, 4);
65 if (addr)
66 addr[size] = '\0';
67
68 return addr;
69}
70
71/** Transfer information from one OpenFirmware node into its memory
72 * representation.
73 *
74 * Transfer entire information from the OpenFirmware device tree 'current' node
75 * to its memory representation in 'current_node'. This function recursively
76 * processes all node's children. Node's peers are processed iteratively in
77 * order to prevent stack from overflowing.
78 *
79 * @param current_node Pointer to uninitialized ofw_tree_node structure that
80 * will become the memory represenation of 'current'.
81 * @param parent_node Parent ofw_tree_node structure or NULL in case of root
82 * node.
83 * @param current OpenFirmware phandle to the current device tree node.
84 *
85 */
86static void ofw_tree_node_process(ofw_tree_node_t *current_node,
87 ofw_tree_node_t *parent_node, phandle current)
88{
89 while (current_node) {
90 /*
91 * Initialize node.
92 */
93 current_node->parent = (ofw_tree_node_t *) balloc_rebase(parent_node);
94 current_node->peer = NULL;
95 current_node->child = NULL;
96 current_node->node_handle = current;
97 current_node->properties = 0;
98 current_node->property = NULL;
99 current_node->device = NULL;
100
101 /*
102 * Get the disambigued name.
103 */
104 size_t len = ofw_package_to_path(current, path, OFW_TREE_PATH_MAX_LEN);
105 if (len == (size_t) -1)
106 return;
107
108 path[len] = '\0';
109
110 /* Find last slash */
111 size_t i;
112 for (i = len; (i > 0) && (path[i - 1] != '/'); i--);
113
114 /* Do not include the slash */
115 len -= i;
116
117 /* Add space for trailing '\0' */
118 char *da_name = ofw_tree_space_alloc(len + 1);
119 if (!da_name)
120 return;
121
122 memcpy(da_name, &path[i], len);
123 da_name[len] = '\0';
124 current_node->da_name = (char *) balloc_rebase(da_name);
125
126 /*
127 * Recursively process the potential child node.
128 */
129 phandle child = ofw_get_child_node(current);
130 if ((child != 0) && (child != (phandle) -1)) {
131 ofw_tree_node_t *child_node = ofw_tree_node_alloc();
132 if (child_node) {
133 ofw_tree_node_process(child_node, current_node,
134 child);
135 current_node->child =
136 (ofw_tree_node_t *) balloc_rebase(child_node);
137 }
138 }
139
140 /*
141 * Count properties.
142 */
143 name[0] = '\0';
144 while (ofw_next_property(current, name, name2) == 1) {
145 current_node->properties++;
146 memcpy(name, name2, OFW_TREE_PROPERTY_MAX_NAMELEN);
147 }
148
149 if (!current_node->properties)
150 return;
151
152 /*
153 * Copy properties.
154 */
155 ofw_tree_property_t *property =
156 ofw_tree_properties_alloc(current_node->properties);
157 if (!property)
158 return;
159
160 name[0] = '\0';
161 for (i = 0; ofw_next_property(current, name, name2) == 1; i++) {
162 if (i == current_node->properties)
163 break;
164
165 memcpy(name, name2, OFW_TREE_PROPERTY_MAX_NAMELEN);
166 memcpy(property[i].name, name, OFW_TREE_PROPERTY_MAX_NAMELEN);
167 property[i].name[OFW_TREE_PROPERTY_MAX_NAMELEN - 1] = '\0';
168
169 size_t size = ofw_get_proplen(current, name);
170 property[i].size = size;
171
172 if (size) {
173 void *buf = ofw_tree_space_alloc(size);
174 if (buf) {
175 /*
176 * Copy property value to memory node.
177 */
178 (void) ofw_get_property(current, name, buf, size);
179 property[i].value = balloc_rebase(buf);
180 }
181 } else
182 property[i].value = NULL;
183 }
184
185 /* Just in case we ran out of memory. */
186 current_node->properties = i;
187 current_node->property = (ofw_tree_property_t *) balloc_rebase(property);
188
189 /*
190 * Iteratively process the next peer node.
191 * Note that recursion is a bad idea here.
192 * Due to the topology of the OpenFirmware device tree,
193 * the nesting of peer nodes could be to wide and the
194 * risk of overflowing the stack is too real.
195 */
196 phandle peer = ofw_get_peer_node(current);
197 if ((peer != 0) && (peer != (phandle) -1)) {
198 ofw_tree_node_t *peer_node = ofw_tree_node_alloc();
199 if (peer_node) {
200 current_node->peer = (ofw_tree_node_t *) balloc_rebase(peer_node);
201 current_node = peer_node;
202 current = peer;
203 /*
204 * Process the peer in next iteration.
205 */
206 continue;
207 }
208 }
209
210 /*
211 * No more peers on this level.
212 */
213 break;
214 }
215}
216
217/** Construct memory representation of OpenFirmware device tree.
218 *
219 * @return NULL on failure or kernel pointer to the root node.
220 *
221 */
222ofw_tree_node_t *ofw_tree_build(void)
223{
224 ofw_tree_node_t *root = ofw_tree_node_alloc();
225 if (root)
226 ofw_tree_node_process(root, NULL, ofw_root);
227
228 /*
229 * The firmware client interface does not automatically include the
230 * "ssm" node in the list of children of "/". A nasty yet working
231 * solution is to explicitly stick "ssm" to the OFW tree.
232 */
233 phandle ssm_node = ofw_find_device("/ssm@0,0");
234 if (ssm_node != (phandle) -1) {
235 ofw_tree_node_t *ssm = ofw_tree_node_alloc();
236 if (ssm) {
237 ofw_tree_node_process(ssm, root,
238 ofw_find_device("/ssm@0,0"));
239 ssm->peer = root->child;
240 root->child = (ofw_tree_node_t *) balloc_rebase(ssm);
241 }
242 }
243
244 return (ofw_tree_node_t *) balloc_rebase(root);
245}
Note: See TracBrowser for help on using the repository browser.