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