1 /* This file is part of the program psim.
3 Copyright (C) 1994-1995, Andrew Cagney <cagney@highland.com.au>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 #ifndef _DEVICE_TREE_C_
23 #define _DEVICE_TREE_C_
25 #ifndef STATIC_INLINE_DEVICE_TREE
26 #define STATIC_INLINE_DEVICE_TREE STATIC_INLINE
34 #include "device_tree.h"
44 static char *node_type_names
[] = {
56 device_tree
*children
;
69 STATIC_INLINE_DEVICE_TREE device_tree
*
70 new_device_tree(device_tree
*parent
,
74 device_tree
*new_node
;
75 new_node
= ZALLOC(device_tree
);
76 new_node
->parent
= parent
;
77 new_node
->name
= strdup(name
);
78 new_node
->type
= type
;
80 device_tree
**sibling
= &parent
->children
;
81 while ((*sibling
) != NULL
)
82 sibling
= &(*sibling
)->sibling
;
89 /* find/create a node in the device tree */
93 device_tree_return_null
= 2,
94 device_tree_abort
= 3,
97 STATIC_INLINE_DEVICE_TREE device_tree
*
98 device_tree_find_node(device_tree
*root
,
100 const char *full_path
,
102 device_tree_action action
)
108 /* strip off any leading `/', `../' or `./' */
110 if (strncmp(path
, "/", strlen("/")) == 0) {
111 while (root
!= NULL
&& root
->parent
!= NULL
)
115 else if (strncmp(path
, "./", strlen("./")) == 0) {
117 path
+= strlen("./");
119 else if (strncmp(path
, "../", strlen("../")) == 0) {
120 if (root
!= NULL
&& root
->parent
!= NULL
)
122 path
+= strlen("../");
129 /* find the qualified (with @) and unqualified names in the path,
130 remembering to skip any "\/" */
133 chp
= strchr(chp
+1, '/');
134 } while (chp
!= NULL
&& chp
[-1] == '\\');
135 name_len
= (chp
== NULL
139 /* leaf? and growing? */
141 for (child
= root
->children
;
143 child
= child
->sibling
) {
144 if (strncmp(path
, child
->name
, name_len
) == 0
145 && (strlen(child
->name
) == name_len
146 || (strchr(child
->name
, '@')
147 == child
->name
+ name_len
))) {
148 if (path
[name_len
] == '\0') {
149 if (action
== device_tree_grow
)
150 error("device_tree_find_node() node %s already present\n",
152 if (type
!= node_any
&& child
->type
!= type
) {
153 if (action
== device_tree_return_null
)
156 error("device_tree_find_node() node %s is not of type %s\n",
157 full_path
, node_type_names
[type
]);
163 return device_tree_find_node(child
,
172 /* search failed, take default action */
174 case device_tree_grow
:
175 if (path
[name_len
] != '\0')
176 error("device_tree_find_node() a parent of %s missing\n",
178 return new_device_tree(root
, path
, type
);
179 case device_tree_return_null
:
181 case device_tree_abort
:
182 error("device_tree_find_node() could not find %s in tree\n",
186 error("device_tree_find_node() invalid default action %d\n", action
);
192 /* grow the device tree */
194 INLINE_DEVICE_TREE device_tree
*
195 device_tree_add_passthrough(device_tree
*root
,
198 device_tree
*new_node
;
199 TRACE(trace_device_tree
,
200 ("device_tree_add_passthrough(root=0x%x, path=%s)\n", root
, path
));
201 new_node
= device_tree_find_node(root
,
206 new_node
->device
= device_create_from(new_node
->name
,
209 passthrough_device_callbacks(),
210 new_node
->parent
->device
);
212 TRACE(trace_device_tree
,
213 ("device_tree_add_passthrough() = 0x%x\n", new_node
));
218 INLINE_DEVICE_TREE device_tree
*
219 device_tree_add_device(device_tree
*root
,
223 device_tree
*new_node
;
224 TRACE(trace_device_tree
,
225 ("device_tree_add_device(root=0x%x, path=%s, dev=0x%x)\n",
227 new_node
= device_tree_find_node(root
,
229 path
, /* full-path */
232 new_node
->device
= dev
;
233 TRACE(trace_device_tree
,
234 ("device_tree_add_device() = 0x%x\n", new_node
));
238 INLINE_DEVICE_TREE device_tree
*
239 device_tree_add_integer(device_tree
*root
,
243 device_tree
*new_node
;
244 TRACE(trace_device_tree
,
245 ("device_tree_add_integer(root=0x%x, path=%s, integer=%d)\n",
246 root
, path
, integer
));
247 new_node
= device_tree_find_node(root
,
249 path
, /* full-name */
252 new_node
->integer
= integer
;
253 TRACE(trace_device_tree
,
254 ("device_tree_add_integer() = 0x%x\n", new_node
));
258 INLINE_DEVICE_TREE device_tree
*
259 device_tree_add_string(device_tree
*root
,
263 device_tree
*new_node
;
264 TRACE(trace_device_tree
,
265 ("device_tree_add_device(root=0x%x, path=%s, string=%s)\n",
266 root
, path
, string
));
267 new_node
= device_tree_find_node(root
,
269 path
, /* full-name */
272 new_node
->string
= string
;
273 TRACE(trace_device_tree
,
274 ("device_tree_add_string() = 0x%x\n", new_node
));
278 INLINE_DEVICE_TREE device_tree
*
279 device_tree_add_boolean(device_tree
*root
,
283 device_tree
*new_node
;
284 TRACE(trace_device_tree
,
285 ("device_tree_add_boolean(root=0x%x, path=%s, boolean=%d)\n",
286 root
, path
, boolean
));
287 new_node
= device_tree_find_node(root
,
289 path
, /* full-name */
292 new_node
->boolean
= boolean
;
293 TRACE(trace_device_tree
,
294 ("device_tree_add_boolean() = 0x%x\n", new_node
));
298 INLINE_DEVICE_TREE device_tree
*
299 device_tree_add_found_device(device_tree
*root
,
302 device_tree
*new_node
;
303 TRACE(trace_device_tree
,
304 ("device_tree_add_found_device(root=0x%x, path=%s)\n",
306 new_node
= device_tree_add_device(root
, path
, NULL
);
307 new_node
->device
= device_create(new_node
->name
,
309 new_node
->parent
->device
);
310 TRACE(trace_device_tree
,
311 ("device_tree_add_found_device() = 0x%x\n", new_node
));
316 /* look up the device tree */
318 INLINE_DEVICE_TREE
const device
*
319 device_tree_find_device(device_tree
*root
,
323 TRACE(trace_device_tree
,
324 ("device_tree_find_device(root=0x%x, path=%s)\n", root
, path
));
325 node
= device_tree_find_node(root
,
327 path
, /* full-name */
330 TRACE(trace_device_tree
,
331 ("device_tree_find_device() = 0x%x\n", node
->device
));
335 INLINE_DEVICE_TREE signed_word
336 device_tree_find_integer(device_tree
*root
,
340 TRACE(trace_device_tree
,
341 ("device_tree_find_integer(root=0x%x, path=%s)\n", root
, path
));
342 node
= device_tree_find_node(root
,
344 path
, /* full-name */
347 TRACE(trace_device_tree
,
348 ("device_tree_find_integer() = %d\n", node
->integer
));
349 return node
->integer
;
352 INLINE_DEVICE_TREE
const char *
353 device_tree_find_string(device_tree
*root
,
357 TRACE(trace_device_tree
,
358 ("device_tree_find_string(root=0x%x, path=%s)\n", root
, path
));
359 node
= device_tree_find_node(root
,
361 path
, /* full-name */
364 TRACE(trace_device_tree
,
365 ("device_tree_find_string() = 0x%x\n", node
->string
));
369 INLINE_DEVICE_TREE
int
370 device_tree_find_boolean(device_tree
*root
,
374 TRACE(trace_device_tree
,
375 ("device_tree_find_boolean(root=0x%x, path=%s)\n", root
, path
));
376 node
= device_tree_find_node(root
,
378 path
, /* full-name */
381 TRACE(trace_device_tree
,
382 ("device_tree_find_boolean() = %d\n", node
->boolean
));
383 return node
->boolean
;
387 /* init all the devices */
389 STATIC_INLINE_DEVICE_TREE
void
390 device_tree_init_device(device_tree
*root
,
394 system
= (psim
*)data
;
395 if (root
->type
== node_device
) {
396 TRACE(trace_device_tree
,
397 ("device_tree_init() initializing device=0x%x:%s\n",
398 root
->device
, root
->device
->full_name
));
399 root
->device
->callback
->init(root
->device
, system
);
404 INLINE_DEVICE_TREE
void
405 device_tree_init(device_tree
*root
,
408 TRACE(trace_device_tree
,
409 ("device_tree_init(root=0x%x, system=0x%x)\n", root
, system
));
410 device_tree_traverse(root
, device_tree_init_device
, NULL
, system
);
411 TRACE(trace_device_tree
,
412 ("device_tree_init() = void\n"));
416 /* traverse a device tree applying prefix/postfix functions to it */
418 INLINE_DEVICE_TREE
void
419 device_tree_traverse(device_tree
*root
,
420 device_tree_traverse_function
*prefix
,
421 device_tree_traverse_function
*postfix
,
427 for (child
= root
->children
; child
!= NULL
; child
= child
->sibling
) {
428 device_tree_traverse(child
, prefix
, postfix
, data
);
435 /* dump out a device node and addresses */
437 INLINE_DEVICE_TREE
void
438 device_tree_dump(device_tree
*device
,
439 void *ignore_data_argument
)
441 printf_filtered("(device_tree@0x%x\n", device
);
442 printf_filtered(" (parent 0x%x)\n", device
->parent
);
443 printf_filtered(" (children 0x%x)\n", device
->children
);
444 printf_filtered(" (sibling 0x%x)\n", device
->sibling
);
445 printf_filtered(" (type %d)\n", device
->type
);
446 printf_filtered(" (name %s)\n", device
->name
);
447 printf_filtered(" (device 0x%x)\n", device
->device
);
448 printf_filtered(" (boolean %d)\n", device
->boolean
);
449 printf_filtered(" (string %s)\n", device
->string
);
450 printf_filtered(" (integer %d)\n", device
->integer
);
451 printf_filtered(")\n");
455 /* Parse a device name, various formats */
457 #define SCAN_INIT(START, END, COUNT, NAME) \
458 char *START = NULL; \
459 char *END = strchr(NAME, '@'); \
465 #define SCAN_U(START, END, COUNT, U) \
467 *U = strtoul(START, &END, 0); \
476 #define SCAN_P(START, END, COUNT, P) \
478 *P = (void*)(unsigned)strtouq(START, &END, 0); \
487 #define SCAN_C(START, END, COUNT, C, SIZE) \
491 while (*END != '\0' && *END != ',') { \
497 if ((SIZE) <= ((END) - (START))) \
498 return COUNT; /* overflow */ \
509 INLINE_DEVICE_TREE
int
510 scand_uw(const char *name
,
513 SCAN_INIT(start
, end
, count
, name
);
514 SCAN_U(start
, end
, count
, uw1
);
518 INLINE_DEVICE_TREE
int
519 scand_uw_u(const char *name
,
523 SCAN_INIT(start
, end
, count
, name
);
524 SCAN_U(start
, end
, count
, uw1
);
525 SCAN_U(start
, end
, count
, u2
);
529 INLINE_DEVICE_TREE
int
530 scand_uw_u_u(const char *name
,
535 SCAN_INIT(start
, end
, count
, name
);
536 SCAN_U(start
, end
, count
, uw1
);
537 SCAN_U(start
, end
, count
, u2
);
538 SCAN_U(start
, end
, count
, u3
);
542 INLINE_DEVICE_TREE
int
543 scand_uw_uw_u(const char *name
,
548 SCAN_INIT(start
, end
, count
, name
);
549 SCAN_U(start
, end
, count
, uw1
);
550 SCAN_U(start
, end
, count
, uw2
);
551 SCAN_U(start
, end
, count
, u3
);
555 INLINE_DEVICE_TREE
int
556 scand_c(const char *name
,
557 char *c1
, int c1size
)
559 SCAN_INIT(start
, end
, count
, name
);
560 SCAN_C(start
, end
, count
, c1
, c1size
);
564 INLINE_DEVICE_TREE
int
565 scand_c_uw_u(const char *name
,
566 char *c1
, int c1size
,
570 SCAN_INIT(start
, end
, count
, name
);
571 SCAN_C(start
, end
, count
, c1
, c1size
);
572 SCAN_U(start
, end
, count
, uw2
);
573 SCAN_U(start
, end
, count
, u3
);
578 STATIC_INLINE_DEVICE_TREE
void
582 if (MASKED64(uw
, 32, 63) == uw
583 || WITH_HOST_WORD_BITSIZE
== 64) {
584 char *end
= strchr(buf
, '\0');
585 sprintf(end
, "0x%x", (unsigned)uw
);
588 char *end
= strchr(buf
, '\0');
589 sprintf(end
, "0x%x%08x",
590 (unsigned)EXTRACTED64(uw
, 0, 31),
591 (unsigned)EXTRACTED64(uw
, 32, 63));
595 STATIC_INLINE_DEVICE_TREE
void
599 char *end
= strchr(buf
, '\0');
601 if (*c
== '/' || *c
== ',')
608 STATIC_INLINE_DEVICE_TREE
int
609 c_strlen(const char *c
)
613 if (*c
== '/' || *c
== ',')
622 strlen_unsigned
= 10,
623 strlen_unsigned_word
= 18,
626 INLINE_DEVICE_TREE
char *
627 printd_uw_u(const char *name
,
631 int sizeof_buf
= (strlen(name
)
633 + strlen_unsigned_word
637 char *buf
= (char*)zalloc(sizeof_buf
);
643 ASSERT(strlen(buf
) < sizeof_buf
);
647 INLINE_DEVICE_TREE
char *
648 printd_uw_u_u(const char *name
,
653 int sizeof_buf
= (strlen(name
)
655 + strlen_unsigned_word
661 char *buf
= (char*)zalloc(sizeof_buf
);
669 ASSERT(strlen(buf
) < sizeof_buf
);
673 INLINE_DEVICE_TREE
char *
674 printd_uw_u_u_c(const char *name
,
680 int sizeof_buf
= (strlen(name
)
682 + strlen_unsigned_word
690 char *buf
= (char*)zalloc(sizeof_buf
);
700 ASSERT(strlen(buf
) < sizeof_buf
);
704 INLINE_DEVICE_TREE
char *
705 printd_c(const char *name
,
708 int sizeof_buf
= (strlen(name
)
712 char *buf
= (char*)zalloc(sizeof_buf
);
716 ASSERT(strlen(buf
) < sizeof_buf
);
720 INLINE_DEVICE_TREE
char *
721 printd_c_uw(const char *name
,
725 int sizeof_buf
= (strlen(name
)
729 + strlen_unsigned_word
731 char *buf
= (char*)zalloc(sizeof_buf
);
737 ASSERT(strlen(buf
) < sizeof_buf
);
741 #endif /* _DEVICE_TREE_C_ */