1 /* The common simulator framework for GDB, the GNU Debugger.
2 
3    Copyright 2002 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
split_device_specifier(struct hw * current,const char * device_specifier,name_specifier * spec)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
split_property_specifier(struct hw * current,const char * property_specifier,name_specifier * spec)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
split_device_name(name_specifier * spec)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 *
split_value(name_specifier * spec)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 *
split_find_device(struct hw * current,name_specifier * spec)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 *
split_fill_path(struct hw * current,const char * device_specifier,name_specifier * spec)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 
441 /* <non-white-space> */
442 
443 static const char *
skip_token(const char * chp)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
count_entries(struct hw * current,const char * property_name,const char * property_value,int modulo)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 *
parse_address(struct hw * current,struct hw * bus,const char * chp,hw_unit * address)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 *
parse_size(struct hw * current,struct hw * bus,const char * chp,hw_unit * size)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
parse_reg_property(struct hw * current,const char * property_name,const char * property_value)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
parse_ranges_property(struct hw * current,const char * property_name,const char * property_value)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
parse_integer_property(struct hw * current,const char * property_name,const char * property_value)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       /* perhaphs 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
parse_string_property(struct hw * current,const char * property_name,const char * property_value)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
parse_ihandle_property(struct hw * current,const char * property,const char * value)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 *
hw_tree_create(SIM_DESC sd,const char * family)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
hw_tree_delete(struct hw * me)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 *
hw_tree_parse(struct hw * current,const char * fmt,...)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 *
hw_tree_vparse(struct hw * current,const char * fmt,va_list ap)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
finish_hw_tree(struct hw * me,void * data)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
hw_tree_finish(struct hw * root)959 hw_tree_finish (struct hw *root)
960 {
961   hw_tree_traverse (root, finish_hw_tree, NULL, NULL);
962 }
963 
964 
965 
966 void
hw_tree_traverse(struct hw * root,hw_tree_traverse_function * prefix,hw_tree_traverse_function * postfix,void * data)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 
987 struct printer {
988   hw_tree_print_callback *print;
989   void *file;
990 };
991 
992 static void
print_address(struct hw * bus,const hw_unit * phys,struct printer * p)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
print_size(struct hw * bus,const hw_unit * size,struct printer * p)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
print_reg_property(struct hw * me,const struct hw_property * property,struct printer * p)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
print_ranges_property(struct hw * me,const struct hw_property * property,struct printer * p)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
print_string(struct hw * me,const char * string,struct printer * p)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
print_string_array_property(struct hw * me,const struct hw_property * property,struct printer * p)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
print_properties(struct hw * me,struct printer * p)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
print_interrupts(struct hw * me,int my_port,struct hw * dest,int dest_port,void * data)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
print_device(struct hw * me,void * data)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
hw_tree_print(struct hw * root,hw_tree_print_callback * print,void * file)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 
1240 #if NOT_YET
1241 device_instance *
tree_instance(struct hw * root,const char * device_specifier)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 *
hw_tree_find_device(struct hw * root,const char * path_to_device)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 *
hw_tree_find_property(struct hw * root,const char * path_to_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
hw_tree_find_boolean_property(struct hw * root,const char * path_to_property)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
hw_tree_find_integer_property(struct hw * root,const char * path_to_property)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 *
hw_tree_find_ihandle_property(struct hw * root,const char * path_to_property)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 *
hw_tree_find_string_property(struct hw * root,const char * path_to_property)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 }
1350