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