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