]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - sim/common/hw-tree.c
Update years in copyright notice for the GDB files.
[thirdparty/binutils-gdb.git] / sim / common / hw-tree.c
CommitLineData
b85e4829
AC
1/* The common simulator framework for GDB, the GNU Debugger.
2
8acc9f48 3 Copyright 2002-2013 Free Software Foundation, Inc.
b85e4829
AC
4
5 Contributed by Andrew Cagney and Red Hat.
6
7 This file is part of GDB.
8
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
4744ac1b 11 the Free Software Foundation; either version 3 of the License, or
b85e4829
AC
12 (at your option) any later version.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
4744ac1b 20 along with this program. If not, see <http://www.gnu.org/licenses/>. */
b85e4829 21
c906108c
SS
22
23#include "hw-main.h"
24#include "hw-base.h"
25#include "hw-tree.h"
26
c2c6d25f 27#include "sim-io.h"
c906108c
SS
28#include "sim-assert.h"
29
30#ifdef HAVE_STDLIB_H
31#include <stdlib.h>
32#endif
33
34#ifdef HAVE_STRING_H
35#include <string.h>
36#else
37#ifdef HAVE_STRINGS_H
38#include <strings.h>
39#endif
40#endif
41
42#include <ctype.h>
43
44/* manipulate/lookup device names */
45
12c4cbd5
MF
46typedef struct _name_specifier
47{
028f6515 48
c906108c
SS
49 /* components in the full length name */
50 char *path;
51 char *property;
52 char *value;
028f6515 53
c906108c
SS
54 /* current device */
55 char *family;
56 char *name;
57 char *unit;
58 char *args;
028f6515 59
c906108c
SS
60 /* previous device */
61 char *last_name;
62 char *last_family;
63 char *last_unit;
64 char *last_args;
028f6515 65
c906108c
SS
66 /* work area */
67 char buf[1024];
028f6515 68
c906108c
SS
69} name_specifier;
70
71
72
73/* Given a device specifier, break it up into its main components:
74 path (and if present) property name and property value. */
75
76static int
77split_device_specifier (struct hw *current,
78 const char *device_specifier,
79 name_specifier *spec)
80{
81 char *chp = NULL;
028f6515 82
c906108c
SS
83 /* expand any leading alias if present */
84 if (current != NULL
85 && *device_specifier != '\0'
86 && *device_specifier != '.'
87 && *device_specifier != '/')
88 {
89 struct hw *aliases = hw_tree_find_device (current, "/aliases");
90 char alias[32];
91 int len = 0;
92 while (device_specifier[len] != '\0'
93 && device_specifier[len] != '/'
94 && device_specifier[len] != ':'
95 && !isspace (device_specifier[len]))
96 {
97 alias[len] = device_specifier[len];
98 len++;
34b47c38 99 if (len >= sizeof (alias))
c906108c
SS
100 hw_abort (NULL, "split_device_specifier: buffer overflow");
101 }
102 alias[len] = '\0';
103 if (aliases != NULL
104 && hw_find_property (aliases, alias))
105 {
34b47c38 106 strcpy (spec->buf, hw_find_string_property (aliases, alias));
c906108c
SS
107 strcat (spec->buf, device_specifier + len);
108 }
109 else
110 {
111 strcpy (spec->buf, device_specifier);
112 }
113 }
114 else
115 {
34b47c38 116 strcpy (spec->buf, device_specifier);
c906108c 117 }
028f6515 118
c906108c 119 /* check no overflow */
34b47c38 120 if (strlen (spec->buf) >= sizeof (spec->buf))
c906108c 121 hw_abort (NULL, "split_device_specifier: buffer overflow\n");
028f6515 122
c906108c
SS
123 /* strip leading spaces */
124 chp = spec->buf;
34b47c38 125 while (*chp != '\0' && isspace (*chp))
c906108c
SS
126 chp++;
127 if (*chp == '\0')
128 return 0;
028f6515 129
c906108c
SS
130 /* find the path and terminate it with null */
131 spec->path = chp;
34b47c38 132 while (*chp != '\0' && !isspace (*chp))
c906108c
SS
133 chp++;
134 if (*chp != '\0')
135 {
136 *chp = '\0';
137 chp++;
138 }
028f6515 139
c906108c 140 /* and any value */
34b47c38 141 while (*chp != '\0' && isspace (*chp))
c906108c
SS
142 chp++;
143 spec->value = chp;
028f6515 144
c906108c
SS
145 /* now go back and chop the property off of the path */
146 if (spec->value[0] == '\0')
147 {
148 spec->property = NULL; /*not a property*/
149 spec->value = NULL;
150 }
151 else if (spec->value[0] == '>'
152 || spec->value[0] == '<')
153 {
154 /* an interrupt spec */
155 spec->property = NULL;
156 }
12c4cbd5
MF
157 else
158 {
34b47c38 159 chp = strrchr (spec->path, '/');
12c4cbd5
MF
160 if (chp == NULL)
161 {
162 spec->property = spec->path;
34b47c38 163 spec->path = strchr (spec->property, '\0');
12c4cbd5
MF
164 }
165 else
166 {
167 *chp = '\0';
168 spec->property = chp+1;
169 }
c906108c 170 }
028f6515 171
c906108c
SS
172 /* and mark the rest as invalid */
173 spec->name = NULL;
174 spec->family = NULL;
175 spec->unit = NULL;
176 spec->args = NULL;
177 spec->last_name = NULL;
178 spec->last_family = NULL;
179 spec->last_unit = NULL;
180 spec->last_args = NULL;
028f6515 181
c906108c
SS
182 return 1;
183}
184
185
186/* given a device specifier break it up into its main components -
187 path and property name - assuming that the last `device' is a
188 property name. */
189
190static int
191split_property_specifier (struct hw *current,
192 const char *property_specifier,
193 name_specifier *spec)
194{
195 if (split_device_specifier (current, property_specifier, spec))
196 {
197 if (spec->property == NULL)
198 {
199 /* force the last name to be a property name */
200 char *chp = strrchr (spec->path, '/');
201 if (chp == NULL)
202 {
203 spec->property = spec->path;
204 spec->path = strrchr (spec->property, '\0');;
205 }
206 else
207 {
208 *chp = '\0';
209 spec->property = chp + 1;
210 }
211 }
212 return 1;
213 }
214 else
215 return 0;
216}
217
218
219/* device the next device name and split it up, return 0 when no more
220 names to struct hw */
221
222static int
223split_device_name (name_specifier *spec)
224{
225 char *chp;
226 /* remember what came before */
227 spec->last_name = spec->name;
228 spec->last_family = spec->family;
229 spec->last_unit = spec->unit;
230 spec->last_args = spec->args;
231 /* finished? */
232 if (spec->path[0] == '\0')
233 {
234 spec->name = NULL;
235 spec->family = NULL;
236 spec->unit = NULL;
237 spec->args = NULL;
238 return 0;
239 }
240 /* break the current device spec from the path */
241 spec->name = spec->path;
242 chp = strchr (spec->name, '/');
243 if (chp == NULL)
244 spec->path = strchr (spec->name, '\0');
028f6515 245 else
c906108c
SS
246 {
247 spec->path = chp+1;
248 *chp = '\0';
249 }
250 /* break out the base */
251 if (spec->name[0] == '(')
252 {
34b47c38 253 chp = strchr (spec->name, ')');
c906108c
SS
254 if (chp == NULL)
255 {
256 spec->family = spec->name;
257 }
258 else
259 {
260 *chp = '\0';
261 spec->family = spec->name + 1;
262 spec->name = chp + 1;
263 }
264 }
265 else
266 {
267 spec->family = spec->name;
268 }
269 /* now break out the unit */
34b47c38 270 chp = strchr (spec->name, '@');
c906108c
SS
271 if (chp == NULL)
272 {
273 spec->unit = NULL;
274 chp = spec->name;
275 }
276 else
277 {
278 *chp = '\0';
279 chp += 1;
280 spec->unit = chp;
281 }
282 /* finally any args */
34b47c38 283 chp = strchr (chp, ':');
c906108c
SS
284 if (chp == NULL)
285 spec->args = NULL;
286 else
287 {
288 *chp = '\0';
289 spec->args = chp+1;
290 }
291 return 1;
292}
293
294
295/* device the value, returning the next non-space token */
296
297static char *
298split_value (name_specifier *spec)
299{
300 char *token;
301 if (spec->value == NULL)
302 return NULL;
303 /* skip leading white space */
304 while (isspace (spec->value[0]))
305 spec->value++;
306 if (spec->value[0] == '\0')
307 {
308 spec->value = NULL;
309 return NULL;
310 }
311 token = spec->value;
312 /* find trailing space */
313 while (spec->value[0] != '\0' && !isspace (spec->value[0]))
314 spec->value++;
315 /* chop this value out */
316 if (spec->value[0] != '\0')
317 {
318 spec->value[0] = '\0';
319 spec->value++;
320 }
321 return token;
322}
323
324
325
326/* traverse the path specified by spec starting at current */
327
328static struct hw *
329split_find_device (struct hw *current,
330 name_specifier *spec)
331{
332 /* strip off (and process) any leading ., .., ./ and / */
333 while (1)
334 {
335 if (strncmp (spec->path, "/", strlen ("/")) == 0)
336 {
337 /* cd /... */
338 while (current != NULL && hw_parent (current) != NULL)
339 current = hw_parent (current);
340 spec->path += strlen ("/");
341 }
342 else if (strncmp (spec->path, "./", strlen ("./")) == 0)
343 {
344 /* cd ./... */
345 current = current;
346 spec->path += strlen ("./");
347 }
348 else if (strncmp (spec->path, "../", strlen ("../")) == 0)
349 {
350 /* cd ../... */
351 if (current != NULL && hw_parent (current) != NULL)
352 current = hw_parent (current);
353 spec->path += strlen ("../");
354 }
355 else if (strcmp (spec->path, ".") == 0)
356 {
357 /* cd . */
358 current = current;
359 spec->path += strlen (".");
360 }
361 else if (strcmp (spec->path, "..") == 0)
362 {
363 /* cd .. */
364 if (current != NULL && hw_parent (current) != NULL)
365 current = hw_parent (current);
366 spec->path += strlen ("..");
367 }
368 else
369 break;
370 }
028f6515 371
c906108c 372 /* now go through the path proper */
028f6515 373
c906108c
SS
374 if (current == NULL)
375 {
376 split_device_name (spec);
377 return NULL;
378 }
028f6515 379
c906108c
SS
380 while (split_device_name (spec))
381 {
382 struct hw *child;
383 for (child = hw_child (current);
384 child != NULL; child = hw_sibling (child))
385 {
386 if (strcmp (spec->name, hw_name (child)) == 0)
387 {
388 if (spec->unit == NULL)
389 break;
390 else
391 {
392 hw_unit phys;
393 hw_unit_decode (current, spec->unit, &phys);
394 if (memcmp (&phys, hw_unit_address (child),
395 sizeof (hw_unit)) == 0)
396 break;
397 }
398 }
399 }
400 if (child == NULL)
401 return current; /* search failed */
402 current = child;
403 }
028f6515 404
c906108c
SS
405 return current;
406}
407
408
409static struct hw *
410split_fill_path (struct hw *current,
411 const char *device_specifier,
412 name_specifier *spec)
413{
414 /* break it up */
415 if (!split_device_specifier (current, device_specifier, spec))
416 hw_abort (current, "error parsing %s\n", device_specifier);
028f6515 417
c906108c
SS
418 /* fill our tree with its contents */
419 current = split_find_device (current, spec);
028f6515 420
c906108c
SS
421 /* add any additional devices as needed */
422 if (spec->name != NULL)
423 {
424 do
425 {
426 if (current != NULL && !hw_finished_p (current))
427 hw_finish (current);
428 current = hw_create (NULL,
429 current,
430 spec->family,
431 spec->name,
432 spec->unit,
433 spec->args);
434 }
435 while (split_device_name (spec));
436 }
028f6515 437
c906108c
SS
438 return current;
439}
440
441\f
442/* <non-white-space> */
443
444static const char *
34b47c38 445skip_token (const char *chp)
c906108c 446{
34b47c38 447 while (!isspace (*chp) && *chp != '\0')
c906108c 448 chp++;
34b47c38 449 while (isspace (*chp) && *chp != '\0')
c906108c
SS
450 chp++;
451 return chp;
452}
453
454
455/* count the number of entries */
456
457static int
458count_entries (struct hw *current,
459 const char *property_name,
460 const char *property_value,
461 int modulo)
462{
463 const char *chp = property_value;
464 int nr_entries = 0;
465 while (*chp != '\0')
466 {
467 nr_entries += 1;
468 chp = skip_token (chp);
469 }
470 if ((nr_entries % modulo) != 0)
471 {
472 hw_abort (current, "incorrect number of entries for %s property %s, should be multiple of %d",
473 property_name, property_value, modulo);
474 }
475 return nr_entries / modulo;
476}
477
478
479
480/* parse: <address> ::= <token> ; device dependant */
481
482static const char *
483parse_address (struct hw *current,
484 struct hw *bus,
485 const char *chp,
486 hw_unit *address)
487{
488 if (hw_unit_decode (bus, chp, address) < 0)
489 hw_abort (current, "invalid unit address in %s", chp);
490 return skip_token (chp);
491}
492
493
494/* parse: <size> ::= <number> { "," <number> } ; */
495
496static const char *
497parse_size (struct hw *current,
498 struct hw *bus,
499 const char *chp,
500 hw_unit *size)
501{
502 int i;
503 int nr;
504 const char *curr = chp;
34b47c38 505 memset (size, 0, sizeof (*size));
c906108c
SS
506 /* parse the numeric list */
507 size->nr_cells = hw_unit_nr_size_cells (bus);
508 nr = 0;
509 while (1)
510 {
511 char *next;
512 size->cells[nr] = strtoul (curr, &next, 0);
513 if (curr == next)
514 hw_abort (current, "Problem parsing <size> %s", chp);
515 nr += 1;
516 if (next[0] != ',')
517 break;
518 if (nr == size->nr_cells)
519 hw_abort (current, "Too many values in <size> %s", chp);
520 curr = next + 1;
521 }
522 ASSERT (nr > 0 && nr <= size->nr_cells);
523 /* right align the numbers */
524 for (i = 1; i <= size->nr_cells; i++)
525 {
526 if (i <= nr)
527 size->cells[size->nr_cells - i] = size->cells[nr - i];
528 else
529 size->cells[size->nr_cells - i] = 0;
530 }
531 return skip_token (chp);
532}
533
534
535/* parse: <reg> ::= { <address> <size> } ; */
536
537static void
538parse_reg_property (struct hw *current,
539 const char *property_name,
540 const char *property_value)
541{
542 int nr_regs;
543 int reg_nr;
544 reg_property_spec *regs;
545 const char *chp;
028f6515 546
c906108c
SS
547 /* determine the number of reg entries by counting tokens */
548 nr_regs = count_entries (current, property_name, property_value, 2);
028f6515 549
c906108c
SS
550 /* create working space */
551 regs = zalloc (nr_regs * sizeof (*regs));
028f6515 552
c906108c
SS
553 /* fill it in */
554 chp = property_value;
555 for (reg_nr = 0; reg_nr < nr_regs; reg_nr++)
556 {
34b47c38 557 chp = parse_address (current, hw_parent (current),
c906108c 558 chp, &regs[reg_nr].address);
34b47c38 559 chp = parse_size (current, hw_parent (current),
c906108c
SS
560 chp, &regs[reg_nr].size);
561 }
028f6515 562
c906108c
SS
563 /* create it */
564 hw_add_reg_array_property (current, property_name,
565 regs, nr_regs);
028f6515 566
d79fe0d6 567 free (regs);
c906108c
SS
568}
569
570
571/* { <child-address> <parent-address> <child-size> }* */
572
573static void
574parse_ranges_property (struct hw *current,
575 const char *property_name,
576 const char *property_value)
577{
578 int nr_ranges;
579 int range_nr;
580 range_property_spec *ranges;
581 const char *chp;
028f6515 582
c906108c
SS
583 /* determine the number of ranges specified */
584 nr_ranges = count_entries (current, property_name, property_value, 3);
028f6515 585
c906108c 586 /* create a property of that size */
34b47c38 587 ranges = zalloc (nr_ranges * sizeof (*ranges));
028f6515 588
c906108c
SS
589 /* fill it in */
590 chp = property_value;
591 for (range_nr = 0; range_nr < nr_ranges; range_nr++)
592 {
593 chp = parse_address (current, current,
594 chp, &ranges[range_nr].child_address);
34b47c38 595 chp = parse_address (current, hw_parent (current),
c906108c
SS
596 chp, &ranges[range_nr].parent_address);
597 chp = parse_size (current, current,
598 chp, &ranges[range_nr].size);
599 }
028f6515 600
c906108c
SS
601 /* create it */
602 hw_add_range_array_property (current, property_name, ranges, nr_ranges);
028f6515 603
d79fe0d6 604 free (ranges);
c906108c
SS
605}
606
607
608/* <integer> ... */
609
610static void
611parse_integer_property (struct hw *current,
612 const char *property_name,
613 const char *property_value)
614{
615 int nr_entries;
616 unsigned_cell words[1024];
617 /* integer or integer array? */
618 nr_entries = 0;
619 while (1)
620 {
621 char *end;
622 words[nr_entries] = strtoul (property_value, &end, 0);
623 if (property_value == end)
624 break;
625 nr_entries += 1;
626 if (nr_entries * sizeof (words[0]) >= sizeof (words))
627 hw_abort (current, "buffer overflow");
628 property_value = end;
629 }
630 if (nr_entries == 0)
631 hw_abort (current, "error parsing integer property %s (%s)",
632 property_name, property_value);
633 else if (nr_entries == 1)
634 hw_add_integer_property (current, property_name, words[0]);
635 else
636 {
637 int i;
638 for (i = 0; i < nr_entries; i++)
639 {
640 H2BE (words[i]);
641 }
109d3db3 642 /* perhaps integer array property is better */
c906108c 643 hw_add_array_property (current, property_name, words,
34b47c38 644 sizeof (words[0]) * nr_entries);
c906108c
SS
645 }
646}
647
648
649/* <string> ... */
650
651static void
652parse_string_property (struct hw *current,
653 const char *property_name,
654 const char *property_value)
655{
656 char **strings;
657 const char *chp;
658 int nr_strings;
659 int approx_nr_strings;
028f6515 660
c906108c
SS
661 /* get an estimate as to the number of strings by counting double
662 quotes */
663 approx_nr_strings = 2;
664 for (chp = property_value; *chp; chp++)
665 {
666 if (*chp == '"')
667 approx_nr_strings++;
668 }
669 approx_nr_strings = (approx_nr_strings) / 2;
028f6515 670
c906108c 671 /* create a string buffer for that many (plus a null) */
34b47c38 672 strings = (char**) zalloc ((approx_nr_strings + 1) * sizeof (char*));
028f6515 673
c906108c
SS
674 /* now find all the strings */
675 chp = property_value;
676 nr_strings = 0;
677 while (1)
678 {
028f6515 679
c906108c
SS
680 /* skip leading space */
681 while (*chp != '\0' && isspace (*chp))
682 chp += 1;
683 if (*chp == '\0')
684 break;
028f6515 685
c906108c
SS
686 /* copy it in */
687 if (*chp == '"')
688 {
6439295f 689 /* a quoted string - watch for '\' et al. */
c906108c
SS
690 /* estimate the size and allocate space for it */
691 int pos;
692 chp++;
693 pos = 0;
694 while (chp[pos] != '\0' && chp[pos] != '"')
695 {
696 if (chp[pos] == '\\' && chp[pos+1] != '\0')
697 pos += 2;
698 else
699 pos += 1;
700 }
701 strings[nr_strings] = zalloc (pos + 1);
702 /* copy the string over */
703 pos = 0;
704 while (*chp != '\0' && *chp != '"')
705 {
12c4cbd5
MF
706 if (*chp == '\\' && *(chp+1) != '\0')
707 {
708 strings[nr_strings][pos] = *(chp+1);
709 chp += 2;
710 pos++;
711 }
c906108c
SS
712 else
713 {
714 strings[nr_strings][pos] = *chp;
715 chp += 1;
716 pos++;
717 }
718 }
719 if (*chp != '\0')
720 chp++;
721 strings[nr_strings][pos] = '\0';
722 }
723 else
724 {
725 /* copy over a single unquoted token */
726 int len = 0;
34b47c38 727 while (chp[len] != '\0' && !isspace (chp[len]))
c906108c 728 len++;
34b47c38
MF
729 strings[nr_strings] = zalloc (len + 1);
730 strncpy (strings[nr_strings], chp, len);
c906108c
SS
731 strings[nr_strings][len] = '\0';
732 chp += len;
733 }
734 nr_strings++;
735 if (nr_strings > approx_nr_strings)
736 hw_abort (current, "String property %s badly formatted",
737 property_name);
738 }
739 ASSERT (strings[nr_strings] == NULL); /* from zalloc */
028f6515 740
c906108c
SS
741 /* install it */
742 if (nr_strings == 0)
743 hw_add_string_property (current, property_name, "");
744 else if (nr_strings == 1)
745 hw_add_string_property (current, property_name, strings[0]);
746 else
747 {
748 const char **specs = (const char**) strings; /* stop a bogus error */
749 hw_add_string_array_property (current, property_name,
750 specs, nr_strings);
751 }
028f6515 752
c906108c
SS
753 /* flush the created string */
754 while (nr_strings > 0)
755 {
756 nr_strings--;
d79fe0d6 757 free (strings[nr_strings]);
c906108c 758 }
34b47c38 759 free (strings);
c906108c
SS
760}
761
762
763/* <path-to-ihandle-device> */
764
765#if NOT_YET
766static void
767parse_ihandle_property (struct hw *current,
768 const char *property,
769 const char *value)
770{
771 ihandle_runtime_property_spec ihandle;
028f6515 772
c906108c
SS
773 /* pass the full path */
774 ihandle.full_path = value;
028f6515 775
c906108c
SS
776 /* save this ready for the ihandle create */
777 hw_add_ihandle_runtime_property (current, property,
778 &ihandle);
779}
780#endif
781
782
783struct hw *
784hw_tree_create (SIM_DESC sd,
785 const char *family)
786{
787 return hw_create (sd, NULL, family, family, NULL, NULL);
788}
789
790void
791hw_tree_delete (struct hw *me)
792{
793 /* Need to allow devices to disapear under our feet */
794 while (hw_child (me) != NULL)
795 {
796 hw_tree_delete (hw_child (me));
797 }
798 hw_delete (me);
799}
800
801
802struct hw *
803hw_tree_parse (struct hw *current,
804 const char *fmt,
805 ...)
806{
807 va_list ap;
808 va_start (ap, fmt);
809 current = hw_tree_vparse (current, fmt, ap);
810 va_end (ap);
811 return current;
812}
028f6515 813
c906108c
SS
814struct hw *
815hw_tree_vparse (struct hw *current,
816 const char *fmt,
817 va_list ap)
818{
819 char device_specifier[1024];
820 name_specifier spec;
028f6515 821
c906108c
SS
822 /* format the path */
823 vsprintf (device_specifier, fmt, ap);
824 if (strlen (device_specifier) >= sizeof (device_specifier))
825 hw_abort (NULL, "device_tree_add_deviced: buffer overflow\n");
028f6515 826
c906108c
SS
827 /* construct the tree down to the final struct hw */
828 current = split_fill_path (current, device_specifier, &spec);
028f6515 829
c906108c
SS
830 /* is there an interrupt spec */
831 if (spec.property == NULL
832 && spec.value != NULL)
833 {
834 char *op = split_value (&spec);
835 switch (op[0])
836 {
837 case '>':
838 {
839 char *my_port_name = split_value (&spec);
840 int my_port;
841 char *dest_port_name = split_value (&spec);
842 int dest_port;
843 name_specifier dest_spec;
844 char *dest_hw_name = split_value (&spec);
845 struct hw *dest;
846 /* find my name */
847 if (!hw_finished_p (current))
848 hw_finish (current);
849 my_port = hw_port_decode (current, my_port_name, output_port);
850 /* find the dest device and port */
851 dest = split_fill_path (current, dest_hw_name, &dest_spec);
852 if (!hw_finished_p (dest))
853 hw_finish (dest);
854 dest_port = hw_port_decode (dest, dest_port_name,
855 input_port);
856 /* connect the two */
857 hw_port_attach (current,
858 my_port,
859 dest,
860 dest_port,
861 permenant_object);
862 break;
863 }
864 default:
865 hw_abort (current, "unreconised interrupt spec %s\n", spec.value);
866 break;
867 }
868 }
028f6515 869
c906108c
SS
870 /* is there a property */
871 if (spec.property != NULL)
872 {
873 if (strcmp (spec.value, "true") == 0)
874 hw_add_boolean_property (current, spec.property, 1);
875 else if (strcmp (spec.value, "false") == 0)
876 hw_add_boolean_property (current, spec.property, 0);
877 else
878 {
879 const struct hw_property *property;
880 switch (spec.value[0])
881 {
882#if NOT_YET
883 case '*':
884 {
885 parse_ihandle_property (current, spec.property, spec.value + 1);
886 break;
887 }
888#endif
889 case '[':
890 {
891 unsigned8 words[1024];
892 char *curr = spec.value + 1;
893 int nr_words = 0;
894 while (1)
895 {
896 char *next;
897 words[nr_words] = H2BE_1 (strtoul (curr, &next, 0));
898 if (curr == next)
899 break;
900 curr = next;
901 nr_words += 1;
902 }
903 hw_add_array_property (current, spec.property,
34b47c38 904 words, sizeof (words[0]) * nr_words);
c906108c
SS
905 break;
906 }
907 case '"':
908 {
909 parse_string_property (current, spec.property, spec.value);
910 break;
911 }
912 case '!':
913 {
914 spec.value++;
915 property = hw_tree_find_property (current, spec.value);
916 if (property == NULL)
917 hw_abort (current, "property %s not found\n", spec.value);
918 hw_add_duplicate_property (current,
919 spec.property,
920 property);
921 break;
922 }
923 default:
924 {
925 if (strcmp (spec.property, "reg") == 0
926 || strcmp (spec.property, "assigned-addresses") == 0
927 || strcmp (spec.property, "alternate-reg") == 0)
928 {
929 parse_reg_property (current, spec.property, spec.value);
930 }
931 else if (strcmp (spec.property, "ranges") == 0)
932 {
933 parse_ranges_property (current, spec.property, spec.value);
934 }
34b47c38
MF
935 else if (isdigit (spec.value[0])
936 || (spec.value[0] == '-' && isdigit (spec.value[1]))
937 || (spec.value[0] == '+' && isdigit (spec.value[1])))
c906108c 938 {
34b47c38 939 parse_integer_property (current, spec.property, spec.value);
c906108c
SS
940 }
941 else
34b47c38 942 parse_string_property (current, spec.property, spec.value);
c906108c
SS
943 break;
944 }
945 }
946 }
947 }
948 return current;
949}
950
951
952static void
953finish_hw_tree (struct hw *me,
954 void *data)
955{
956 if (!hw_finished_p (me))
957 hw_finish (me);
958}
959
960void
961hw_tree_finish (struct hw *root)
962{
963 hw_tree_traverse (root, finish_hw_tree, NULL, NULL);
964}
965
966
967
968void
969hw_tree_traverse (struct hw *root,
970 hw_tree_traverse_function *prefix,
971 hw_tree_traverse_function *postfix,
972 void *data)
973{
974 struct hw *child;
975 if (prefix != NULL)
976 prefix (root, data);
977 for (child = hw_child (root);
978 child != NULL;
979 child = hw_sibling (child))
980 {
981 hw_tree_traverse (child, prefix, postfix, data);
982 }
983 if (postfix != NULL)
984 postfix (root, data);
985}
986
987
988\f
12c4cbd5
MF
989struct printer
990{
c906108c
SS
991 hw_tree_print_callback *print;
992 void *file;
993};
994
995static void
996print_address (struct hw *bus,
997 const hw_unit *phys,
998 struct printer *p)
999{
1000 char unit[32];
34b47c38 1001 hw_unit_encode (bus, phys, unit, sizeof (unit));
c906108c
SS
1002 p->print (p->file, " %s", unit);
1003}
1004
1005static void
1006print_size (struct hw *bus,
1007 const hw_unit *size,
1008 struct printer *p)
1009{
1010 int i;
1011 for (i = 0; i < size->nr_cells; i++)
1012 if (size->cells[i] != 0)
1013 break;
12c4cbd5
MF
1014 if (i < size->nr_cells)
1015 {
1016 p->print (p->file, " 0x%lx", (unsigned long) size->cells[i]);
1017 i++;
1018 for (; i < size->nr_cells; i++)
1019 p->print (p->file, ",0x%lx", (unsigned long) size->cells[i]);
1020 }
c906108c
SS
1021 else
1022 p->print (p->file, " 0");
1023}
1024
1025static void
1026print_reg_property (struct hw *me,
1027 const struct hw_property *property,
1028 struct printer *p)
1029{
1030 int reg_nr;
1031 reg_property_spec reg;
1032 for (reg_nr = 0;
1033 hw_find_reg_array_property (me, property->name, reg_nr, &reg);
12c4cbd5
MF
1034 reg_nr++)
1035 {
1036 print_address (hw_parent (me), &reg.address, p);
1037 print_size (me, &reg.size, p);
1038 }
c906108c
SS
1039}
1040
1041static void
1042print_ranges_property (struct hw *me,
1043 const struct hw_property *property,
1044 struct printer *p)
1045{
1046 int range_nr;
1047 range_property_spec range;
1048 for (range_nr = 0;
1049 hw_find_range_array_property (me, property->name, range_nr, &range);
1050 range_nr++)
1051 {
1052 print_address (me, &range.child_address, p);
1053 print_address (hw_parent (me), &range.parent_address, p);
1054 print_size (me, &range.size, p);
1055 }
1056}
1057
1058static void
1059print_string (struct hw *me,
1060 const char *string,
1061 struct printer *p)
1062{
1063 p->print (p->file, " \"");
12c4cbd5
MF
1064 while (*string != '\0')
1065 {
1066 switch (*string)
1067 {
1068 case '"':
1069 p->print (p->file, "\\\"");
1070 break;
1071 case '\\':
1072 p->print (p->file, "\\\\");
1073 break;
1074 default:
1075 p->print (p->file, "%c", *string);
1076 break;
1077 }
1078 string++;
c906108c 1079 }
c906108c
SS
1080 p->print (p->file, "\"");
1081}
1082
1083static void
1084print_string_array_property (struct hw *me,
1085 const struct hw_property *property,
1086 struct printer *p)
1087{
1088 int nr;
1089 string_property_spec string;
1090 for (nr = 0;
1091 hw_find_string_array_property (me, property->name, nr, &string);
1092 nr++)
1093 {
1094 print_string (me, string, p);
1095 }
1096}
1097
1098static void
1099print_properties (struct hw *me,
1100 struct printer *p)
1101{
1102 const struct hw_property *property;
1103 for (property = hw_find_property (me, NULL);
1104 property != NULL;
1105 property = hw_next_property (property))
1106 {
1107 if (hw_parent (me) == NULL)
1108 p->print (p->file, "/%s", property->name);
1109 else
1110 p->print (p->file, "%s/%s", hw_path (me), property->name);
1111 if (property->original != NULL)
1112 {
1113 p->print (p->file, " !");
028f6515 1114 p->print (p->file, "%s/%s",
c906108c
SS
1115 hw_path (property->original->owner),
1116 property->original->name);
1117 }
1118 else
1119 {
1120 switch (property->type)
1121 {
1122 case array_property:
1123 {
1124 if ((property->sizeof_array % sizeof (signed_cell)) == 0)
1125 {
1126 unsigned_cell *w = (unsigned_cell*) property->array;
1127 int cell_nr;
1128 for (cell_nr = 0;
1129 cell_nr < (property->sizeof_array / sizeof (unsigned_cell));
1130 cell_nr++)
1131 {
1132 p->print (p->file, " 0x%lx", (unsigned long) BE2H_cell (w[cell_nr]));
1133 }
1134 }
1135 else
1136 {
1137 unsigned8 *w = (unsigned8*)property->array;
1138 p->print (p->file, " [");
12c4cbd5
MF
1139 while ((char*)w - (char*)property->array < property->sizeof_array)
1140 {
1141 p->print (p->file, " 0x%2x", BE2H_1 (*w));
1142 w++;
1143 }
c906108c
SS
1144 }
1145 break;
1146 }
1147 case boolean_property:
1148 {
34b47c38 1149 int b = hw_find_boolean_property (me, property->name);
c906108c
SS
1150 p->print (p->file, " %s", b ? "true" : "false");
1151 break;
1152 }
1153#if NOT_YET
1154 case ihandle_property:
1155 {
1156 if (property->array != NULL)
1157 {
1158 device_instance *instance = hw_find_ihandle_property (me, property->name);
34b47c38 1159 p->print (p->file, " *%s", device_instance_path (instance));
c906108c
SS
1160 }
1161 else
1162 {
1163 /* not yet initialized, ask the device for the path */
1164 ihandle_runtime_property_spec spec;
1165 hw_find_ihandle_runtime_property (me, property->name, &spec);
1166 p->print (p->file, " *%s", spec.full_path);
1167 }
1168 break;
1169 }
1170#endif
1171 case integer_property:
1172 {
1173 unsigned_word w = hw_find_integer_property (me, property->name);
1174 p->print (p->file, " 0x%lx", (unsigned long)w);
1175 break;
1176 }
1177 case range_array_property:
1178 {
1179 print_ranges_property (me, property, p);
1180 break;
1181 }
1182 case reg_array_property:
1183 {
1184 print_reg_property (me, property, p);
1185 break;
1186 }
1187 case string_property:
1188 {
1189 const char *s = hw_find_string_property (me, property->name);
1190 print_string (me, s, p);
1191 break;
1192 }
1193 case string_array_property:
1194 {
1195 print_string_array_property (me, property, p);
1196 break;
1197 }
1198 }
1199 }
1200 p->print (p->file, "\n");
1201 }
1202}
1203
1204static void
1205print_interrupts (struct hw *me,
1206 int my_port,
1207 struct hw *dest,
1208 int dest_port,
1209 void *data)
1210{
1211 struct printer *p = data;
1212 char src[32];
1213 char dst[32];
34b47c38
MF
1214 hw_port_encode (me, my_port, src, sizeof (src), output_port);
1215 hw_port_encode (dest, dest_port, dst, sizeof (dst), input_port);
c906108c
SS
1216 p->print (p->file,
1217 "%s > %s %s %s\n",
1218 hw_path (me),
1219 src, dst,
1220 hw_path (dest));
1221}
1222
1223static void
1224print_device (struct hw *me,
1225 void *data)
1226{
1227 struct printer *p = data;
1228 p->print (p->file, "%s\n", hw_path (me));
1229 print_properties (me, p);
1230 hw_port_traverse (me, print_interrupts, data);
1231}
1232
1233void
1234hw_tree_print (struct hw *root,
1235 hw_tree_print_callback *print,
1236 void *file)
1237{
1238 struct printer p;
1239 p.print = print;
1240 p.file = file;
1241 hw_tree_traverse (root,
1242 print_device, NULL,
1243 &p);
1244}
1245
1246
1247\f
1248#if NOT_YET
1249device_instance *
34b47c38
MF
1250tree_instance (struct hw *root,
1251 const char *device_specifier)
c906108c
SS
1252{
1253 /* find the device node */
1254 struct hw *me;
1255 name_specifier spec;
34b47c38 1256 if (!split_device_specifier (root, device_specifier, &spec))
c906108c 1257 return NULL;
34b47c38 1258 me = split_find_device (root, &spec);
c906108c
SS
1259 if (spec.name != NULL)
1260 return NULL;
1261 /* create the instance */
34b47c38 1262 return device_create_instance (me, device_specifier, spec.last_args);
c906108c
SS
1263}
1264#endif
1265
1266struct hw *
1267hw_tree_find_device (struct hw *root,
1268 const char *path_to_device)
1269{
1270 struct hw *node;
1271 name_specifier spec;
028f6515 1272
c906108c
SS
1273 /* parse the path */
1274 split_device_specifier (root, path_to_device, &spec);
1275 if (spec.value != NULL)
1276 return NULL; /* something wierd */
028f6515 1277
c906108c
SS
1278 /* now find it */
1279 node = split_find_device (root, &spec);
1280 if (spec.name != NULL)
1281 return NULL; /* not a leaf */
028f6515 1282
c906108c
SS
1283 return node;
1284}
1285
1286
1287const struct hw_property *
1288hw_tree_find_property (struct hw *root,
1289 const char *path_to_property)
1290{
1291 name_specifier spec;
1292 if (!split_property_specifier (root, path_to_property, &spec))
1293 hw_abort (root, "Invalid property path %s", path_to_property);
1294 root = split_find_device (root, &spec);
1295 if (spec.name != NULL)
1296 return NULL; /* not a leaf */
1297 return hw_find_property (root, spec.property);
1298}
1299
1300int
1301hw_tree_find_boolean_property (struct hw *root,
1302 const char *path_to_property)
1303{
1304 name_specifier spec;
1305 if (!split_property_specifier (root, path_to_property, &spec))
1306 hw_abort (root, "Invalid property path %s", path_to_property);
1307 root = split_find_device (root, &spec);
1308 if (spec.name != NULL)
1309 hw_abort (root, "device \"%s\" not found (property \"%s\")",
1310 spec.name, path_to_property);
1311 return hw_find_boolean_property (root, spec.property);
1312}
1313
1314signed_cell
1315hw_tree_find_integer_property (struct hw *root,
1316 const char *path_to_property)
1317{
1318 name_specifier spec;
1319 if (!split_property_specifier (root, path_to_property, &spec))
1320 hw_abort (root, "Invalid property path %s", path_to_property);
1321 root = split_find_device (root, &spec);
1322 if (spec.name != NULL)
1323 hw_abort (root, "device \"%s\" not found (property \"%s\")",
1324 spec.name, path_to_property);
1325 return hw_find_integer_property (root, spec.property);
1326}
1327
1328#if NOT_YET
1329device_instance *
1330hw_tree_find_ihandle_property (struct hw *root,
1331 const char *path_to_property)
1332{
1333 struct hw *root;
1334 name_specifier spec;
1335 if (!split_property_specifier (root, path_to_property, &spec))
1336 hw_abort (root, "Invalid property path %s", path_to_property);
1337 root = split_find_device (root, &spec);
1338 if (spec.name != NULL)
1339 hw_abort (root, "device \"%s\" not found (property \"%s\")",
1340 spec.name, path_to_property);
1341 return hw_find_ihandle_property (root, spec.property);
1342}
1343#endif
1344
1345const char *
1346hw_tree_find_string_property (struct hw *root,
1347 const char *path_to_property)
1348{
1349 name_specifier spec;
1350 if (!split_property_specifier (root, path_to_property, &spec))
1351 hw_abort (root, "Invalid property path %s", path_to_property);
1352 root = split_find_device (root, &spec);
1353 if (spec.name != NULL)
1354 hw_abort (root, "device \"%s\" not found (property \"%s\")",
1355 spec.name, path_to_property);
1356 return hw_find_string_property (root, spec.property);
1357}