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