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