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