OSDN Git Service

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