OSDN Git Service

4252b0d7c9244122ce8467cfa059ce3705f287cc
[pf3gnuchains/sourceware.git] / sim / common / hw-tree.c
1 /* The common simulator framework for GDB, the GNU Debugger.
2
3    Copyright 2002, 2007, 2008, 2009, 2010, 2011 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   /* 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
75 static int
76 split_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
187 static int
188 split_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
219 static int
220 split_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
294 static char *
295 split_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
325 static struct hw *
326 split_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
406 static struct hw *
407 split_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
441 static const char *
442 skip_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
454 static int
455 count_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
479 static const char *
480 parse_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
493 static const char *
494 parse_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
534 static void
535 parse_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   
564   free (regs);
565 }
566
567
568 /* { <child-address> <parent-address> <child-size> }* */
569
570 static void
571 parse_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   
601   free (ranges);
602 }
603
604
605 /* <integer> ... */
606
607 static void
608 parse_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         }
639       /* perhaps integer array property is better */
640       hw_add_array_property (current, property_name, words,
641                              sizeof(words[0]) * nr_entries);
642     }
643 }
644
645
646 /* <string> ... */
647
648 static void
649 parse_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         {
686           /* a quoted string - watch for '\' et al. */
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--;
753       free (strings[nr_strings]);
754     }
755   free(strings);
756 }
757
758
759 /* <path-to-ihandle-device> */
760
761 #if NOT_YET
762 static void
763 parse_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
779 struct hw *
780 hw_tree_create (SIM_DESC sd,
781                 const char *family)
782 {
783   return hw_create (sd, NULL, family, family, NULL, NULL);
784 }
785
786 void
787 hw_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
798 struct hw *
799 hw_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   
810 struct hw *
811 hw_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
948 static void
949 finish_hw_tree (struct hw *me,
950                 void *data)
951 {
952   if (!hw_finished_p (me))
953     hw_finish (me);
954 }
955
956 void
957 hw_tree_finish (struct hw *root)
958 {
959   hw_tree_traverse (root, finish_hw_tree, NULL, NULL);
960 }
961
962
963
964 void
965 hw_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
985 struct printer {
986   hw_tree_print_callback *print;
987   void *file;
988 };
989
990 static void
991 print_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
1000 static void
1001 print_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
1019 static void
1020 print_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
1034 static void
1035 print_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
1051 static void
1052 print_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
1074 static void
1075 print_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
1089 static void
1090 print_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
1194 static void
1195 print_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
1213 static void
1214 print_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
1223 void
1224 hw_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
1239 device_instance *
1240 tree_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
1256 struct hw *
1257 hw_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
1277 const struct hw_property *
1278 hw_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
1290 int
1291 hw_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
1304 signed_cell
1305 hw_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
1319 device_instance *
1320 hw_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
1335 const char *
1336 hw_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 }