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