xref: /netbsd-src/external/gpl3/gdb/dist/sim/common/hw-tree.c (revision 88241920d21b339bf319c0e979ffda80c49a2936)
14e98e3e1Schristos /* The common simulator framework for GDB, the GNU Debugger.
24e98e3e1Schristos 
3*88241920Schristos    Copyright 2002-2024 Free Software Foundation, Inc.
44e98e3e1Schristos 
54e98e3e1Schristos    Contributed by Andrew Cagney and Red Hat.
64e98e3e1Schristos 
74e98e3e1Schristos    This file is part of GDB.
84e98e3e1Schristos 
94e98e3e1Schristos    This program is free software; you can redistribute it and/or modify
104e98e3e1Schristos    it under the terms of the GNU General Public License as published by
114e98e3e1Schristos    the Free Software Foundation; either version 3 of the License, or
124e98e3e1Schristos    (at your option) any later version.
134e98e3e1Schristos 
144e98e3e1Schristos    This program is distributed in the hope that it will be useful,
154e98e3e1Schristos    but WITHOUT ANY WARRANTY; without even the implied warranty of
164e98e3e1Schristos    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
174e98e3e1Schristos    GNU General Public License for more details.
184e98e3e1Schristos 
194e98e3e1Schristos    You should have received a copy of the GNU General Public License
204e98e3e1Schristos    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
214e98e3e1Schristos 
224b169a6bSchristos /* This must come before any other includes.  */
234b169a6bSchristos #include "defs.h"
244b169a6bSchristos 
254b169a6bSchristos #include <ctype.h>
264b169a6bSchristos #include <stdarg.h>
274b169a6bSchristos #include <stdlib.h>
284b169a6bSchristos #include <string.h>
294e98e3e1Schristos 
304e98e3e1Schristos #include "hw-main.h"
314e98e3e1Schristos #include "hw-base.h"
324e98e3e1Schristos #include "hw-tree.h"
334e98e3e1Schristos 
344e98e3e1Schristos #include "sim-io.h"
354e98e3e1Schristos #include "sim-assert.h"
364e98e3e1Schristos 
374e98e3e1Schristos /* manipulate/lookup device names */
384e98e3e1Schristos 
394e98e3e1Schristos typedef struct _name_specifier
404e98e3e1Schristos {
414e98e3e1Schristos 
424e98e3e1Schristos   /* components in the full length name */
434e98e3e1Schristos   char *path;
444e98e3e1Schristos   char *property;
454e98e3e1Schristos   char *value;
464e98e3e1Schristos 
474e98e3e1Schristos   /* current device */
484e98e3e1Schristos   char *family;
494e98e3e1Schristos   char *name;
504e98e3e1Schristos   char *unit;
514e98e3e1Schristos   char *args;
524e98e3e1Schristos 
534e98e3e1Schristos   /* previous device */
544e98e3e1Schristos   char *last_name;
554e98e3e1Schristos   char *last_family;
564e98e3e1Schristos   char *last_unit;
574e98e3e1Schristos   char *last_args;
584e98e3e1Schristos 
594e98e3e1Schristos   /* work area */
604e98e3e1Schristos   char buf[1024];
614e98e3e1Schristos 
624e98e3e1Schristos } name_specifier;
634e98e3e1Schristos 
644e98e3e1Schristos 
654e98e3e1Schristos 
664e98e3e1Schristos /* Given a device specifier, break it up into its main components:
674e98e3e1Schristos    path (and if present) property name and property value. */
684e98e3e1Schristos 
694e98e3e1Schristos static int
704e98e3e1Schristos split_device_specifier (struct hw *current,
714e98e3e1Schristos 			const char *device_specifier,
724e98e3e1Schristos 			name_specifier *spec)
734e98e3e1Schristos {
744e98e3e1Schristos   char *chp = NULL;
754e98e3e1Schristos 
764e98e3e1Schristos   /* expand any leading alias if present */
774e98e3e1Schristos   if (current != NULL
784e98e3e1Schristos       && *device_specifier != '\0'
794e98e3e1Schristos       && *device_specifier != '.'
804e98e3e1Schristos       && *device_specifier != '/')
814e98e3e1Schristos     {
824e98e3e1Schristos       struct hw *aliases = hw_tree_find_device (current, "/aliases");
834e98e3e1Schristos       char alias[32];
844e98e3e1Schristos       int len = 0;
854e98e3e1Schristos       while (device_specifier[len] != '\0'
864e98e3e1Schristos 	     && device_specifier[len] != '/'
874e98e3e1Schristos 	     && device_specifier[len] != ':'
884e98e3e1Schristos 	     && !isspace (device_specifier[len]))
894e98e3e1Schristos 	{
904e98e3e1Schristos 	  alias[len] = device_specifier[len];
914e98e3e1Schristos 	  len++;
924e98e3e1Schristos 	  if (len >= sizeof (alias))
934e98e3e1Schristos 	    hw_abort (NULL, "split_device_specifier: buffer overflow");
944e98e3e1Schristos 	}
954e98e3e1Schristos       alias[len] = '\0';
964e98e3e1Schristos       if (aliases != NULL
974e98e3e1Schristos 	  && hw_find_property (aliases, alias))
984e98e3e1Schristos 	{
994e98e3e1Schristos 	  strcpy (spec->buf, hw_find_string_property (aliases, alias));
1004e98e3e1Schristos 	  strcat (spec->buf, device_specifier + len);
1014e98e3e1Schristos 	}
1024e98e3e1Schristos       else
1034e98e3e1Schristos 	{
1044e98e3e1Schristos 	  strcpy (spec->buf, device_specifier);
1054e98e3e1Schristos 	}
1064e98e3e1Schristos     }
1074e98e3e1Schristos   else
1084e98e3e1Schristos     {
1094e98e3e1Schristos       strcpy (spec->buf, device_specifier);
1104e98e3e1Schristos     }
1114e98e3e1Schristos 
1124e98e3e1Schristos   /* check no overflow */
1134e98e3e1Schristos   if (strlen (spec->buf) >= sizeof (spec->buf))
1144e98e3e1Schristos     hw_abort (NULL, "split_device_specifier: buffer overflow\n");
1154e98e3e1Schristos 
1164e98e3e1Schristos   /* strip leading spaces */
1174e98e3e1Schristos   chp = spec->buf;
1184e98e3e1Schristos   while (*chp != '\0' && isspace (*chp))
1194e98e3e1Schristos     chp++;
1204e98e3e1Schristos   if (*chp == '\0')
1214e98e3e1Schristos     return 0;
1224e98e3e1Schristos 
1234e98e3e1Schristos   /* find the path and terminate it with null */
1244e98e3e1Schristos   spec->path = chp;
1254e98e3e1Schristos   while (*chp != '\0' && !isspace (*chp))
1264e98e3e1Schristos     chp++;
1274e98e3e1Schristos   if (*chp != '\0')
1284e98e3e1Schristos     {
1294e98e3e1Schristos       *chp = '\0';
1304e98e3e1Schristos       chp++;
1314e98e3e1Schristos     }
1324e98e3e1Schristos 
1334e98e3e1Schristos   /* and any value */
1344e98e3e1Schristos   while (*chp != '\0' && isspace (*chp))
1354e98e3e1Schristos     chp++;
1364e98e3e1Schristos   spec->value = chp;
1374e98e3e1Schristos 
1384e98e3e1Schristos   /* now go back and chop the property off of the path */
1394e98e3e1Schristos   if (spec->value[0] == '\0')
1404e98e3e1Schristos     {
1414e98e3e1Schristos       spec->property = NULL; /*not a property*/
1424e98e3e1Schristos       spec->value = NULL;
1434e98e3e1Schristos     }
1444e98e3e1Schristos   else if (spec->value[0] == '>'
1454e98e3e1Schristos 	   || spec->value[0] == '<')
1464e98e3e1Schristos     {
1474e98e3e1Schristos       /* an interrupt spec */
1484e98e3e1Schristos       spec->property = NULL;
1494e98e3e1Schristos     }
1504e98e3e1Schristos   else
1514e98e3e1Schristos     {
1524e98e3e1Schristos       chp = strrchr (spec->path, '/');
1534e98e3e1Schristos       if (chp == NULL)
1544e98e3e1Schristos 	{
1554e98e3e1Schristos 	  spec->property = spec->path;
1564e98e3e1Schristos 	  spec->path = strchr (spec->property, '\0');
1574e98e3e1Schristos 	}
1584e98e3e1Schristos       else
1594e98e3e1Schristos 	{
1604e98e3e1Schristos 	  *chp = '\0';
1614e98e3e1Schristos 	  spec->property = chp+1;
1624e98e3e1Schristos 	}
1634e98e3e1Schristos     }
1644e98e3e1Schristos 
1654e98e3e1Schristos   /* and mark the rest as invalid */
1664e98e3e1Schristos   spec->name = NULL;
1674e98e3e1Schristos   spec->family = NULL;
1684e98e3e1Schristos   spec->unit = NULL;
1694e98e3e1Schristos   spec->args = NULL;
1704e98e3e1Schristos   spec->last_name = NULL;
1714e98e3e1Schristos   spec->last_family = NULL;
1724e98e3e1Schristos   spec->last_unit = NULL;
1734e98e3e1Schristos   spec->last_args = NULL;
1744e98e3e1Schristos 
1754e98e3e1Schristos   return 1;
1764e98e3e1Schristos }
1774e98e3e1Schristos 
1784e98e3e1Schristos 
1794e98e3e1Schristos /* given a device specifier break it up into its main components -
1804e98e3e1Schristos    path and property name - assuming that the last `device' is a
1814e98e3e1Schristos    property name. */
1824e98e3e1Schristos 
1834e98e3e1Schristos static int
1844e98e3e1Schristos split_property_specifier (struct hw *current,
1854e98e3e1Schristos 			  const char *property_specifier,
1864e98e3e1Schristos 			  name_specifier *spec)
1874e98e3e1Schristos {
1884e98e3e1Schristos   if (split_device_specifier (current, property_specifier, spec))
1894e98e3e1Schristos     {
1904e98e3e1Schristos       if (spec->property == NULL)
1914e98e3e1Schristos 	{
1924e98e3e1Schristos 	  /* force the last name to be a property name */
1934e98e3e1Schristos 	  char *chp = strrchr (spec->path, '/');
1944e98e3e1Schristos 	  if (chp == NULL)
1954e98e3e1Schristos 	    {
1964e98e3e1Schristos 	      spec->property = spec->path;
1974e98e3e1Schristos 	      spec->path = strrchr (spec->property, '\0');;
1984e98e3e1Schristos 	    }
1994e98e3e1Schristos 	  else
2004e98e3e1Schristos 	    {
2014e98e3e1Schristos 	      *chp = '\0';
2024e98e3e1Schristos 	      spec->property = chp + 1;
2034e98e3e1Schristos 	    }
2044e98e3e1Schristos 	}
2054e98e3e1Schristos       return 1;
2064e98e3e1Schristos     }
2074e98e3e1Schristos   else
2084e98e3e1Schristos     return 0;
2094e98e3e1Schristos }
2104e98e3e1Schristos 
2114e98e3e1Schristos 
2124e98e3e1Schristos /* device the next device name and split it up, return 0 when no more
2134e98e3e1Schristos    names to struct hw */
2144e98e3e1Schristos 
2154e98e3e1Schristos static int
2164e98e3e1Schristos split_device_name (name_specifier *spec)
2174e98e3e1Schristos {
2184e98e3e1Schristos   char *chp;
2194e98e3e1Schristos   /* remember what came before */
2204e98e3e1Schristos   spec->last_name = spec->name;
2214e98e3e1Schristos   spec->last_family = spec->family;
2224e98e3e1Schristos   spec->last_unit = spec->unit;
2234e98e3e1Schristos   spec->last_args = spec->args;
2244e98e3e1Schristos   /* finished? */
2254e98e3e1Schristos   if (spec->path[0] == '\0')
2264e98e3e1Schristos     {
2274e98e3e1Schristos       spec->name = NULL;
2284e98e3e1Schristos       spec->family = NULL;
2294e98e3e1Schristos       spec->unit = NULL;
2304e98e3e1Schristos       spec->args = NULL;
2314e98e3e1Schristos       return 0;
2324e98e3e1Schristos     }
2334e98e3e1Schristos   /* break the current device spec from the path */
2344e98e3e1Schristos   spec->name = spec->path;
2354e98e3e1Schristos   chp = strchr (spec->name, '/');
2364e98e3e1Schristos   if (chp == NULL)
2374e98e3e1Schristos     spec->path = strchr (spec->name, '\0');
2384e98e3e1Schristos   else
2394e98e3e1Schristos     {
2404e98e3e1Schristos       spec->path = chp+1;
2414e98e3e1Schristos       *chp = '\0';
2424e98e3e1Schristos     }
2434e98e3e1Schristos   /* break out the base */
2444e98e3e1Schristos   if (spec->name[0] == '(')
2454e98e3e1Schristos     {
2464e98e3e1Schristos       chp = strchr (spec->name, ')');
2474e98e3e1Schristos       if (chp == NULL)
2484e98e3e1Schristos 	{
2494e98e3e1Schristos 	  spec->family = spec->name;
2504e98e3e1Schristos 	}
2514e98e3e1Schristos       else
2524e98e3e1Schristos 	{
2534e98e3e1Schristos 	  *chp = '\0';
2544e98e3e1Schristos 	  spec->family = spec->name + 1;
2554e98e3e1Schristos 	  spec->name = chp + 1;
2564e98e3e1Schristos 	}
2574e98e3e1Schristos     }
2584e98e3e1Schristos   else
2594e98e3e1Schristos     {
2604e98e3e1Schristos       spec->family = spec->name;
2614e98e3e1Schristos     }
2624e98e3e1Schristos   /* now break out the unit */
2634e98e3e1Schristos   chp = strchr (spec->name, '@');
2644e98e3e1Schristos   if (chp == NULL)
2654e98e3e1Schristos     {
2664e98e3e1Schristos       spec->unit = NULL;
2674e98e3e1Schristos       chp = spec->name;
2684e98e3e1Schristos     }
2694e98e3e1Schristos   else
2704e98e3e1Schristos     {
2714e98e3e1Schristos       *chp = '\0';
2724e98e3e1Schristos       chp += 1;
2734e98e3e1Schristos       spec->unit = chp;
2744e98e3e1Schristos     }
2754e98e3e1Schristos   /* finally any args */
2764e98e3e1Schristos   chp = strchr (chp, ':');
2774e98e3e1Schristos   if (chp == NULL)
2784e98e3e1Schristos     spec->args = NULL;
2794e98e3e1Schristos   else
2804e98e3e1Schristos     {
2814e98e3e1Schristos       *chp = '\0';
2824e98e3e1Schristos       spec->args = chp+1;
2834e98e3e1Schristos     }
2844e98e3e1Schristos   return 1;
2854e98e3e1Schristos }
2864e98e3e1Schristos 
2874e98e3e1Schristos 
2884e98e3e1Schristos /* device the value, returning the next non-space token */
2894e98e3e1Schristos 
2904e98e3e1Schristos static char *
2914e98e3e1Schristos split_value (name_specifier *spec)
2924e98e3e1Schristos {
2934e98e3e1Schristos   char *token;
2944e98e3e1Schristos   if (spec->value == NULL)
2954e98e3e1Schristos     return NULL;
2964e98e3e1Schristos   /* skip leading white space */
2974e98e3e1Schristos   while (isspace (spec->value[0]))
2984e98e3e1Schristos     spec->value++;
2994e98e3e1Schristos   if (spec->value[0] == '\0')
3004e98e3e1Schristos     {
3014e98e3e1Schristos       spec->value = NULL;
3024e98e3e1Schristos       return NULL;
3034e98e3e1Schristos     }
3044e98e3e1Schristos   token = spec->value;
3054e98e3e1Schristos   /* find trailing space */
3064e98e3e1Schristos   while (spec->value[0] != '\0' && !isspace (spec->value[0]))
3074e98e3e1Schristos     spec->value++;
3084e98e3e1Schristos   /* chop this value out */
3094e98e3e1Schristos   if (spec->value[0] != '\0')
3104e98e3e1Schristos     {
3114e98e3e1Schristos       spec->value[0] = '\0';
3124e98e3e1Schristos       spec->value++;
3134e98e3e1Schristos     }
3144e98e3e1Schristos   return token;
3154e98e3e1Schristos }
3164e98e3e1Schristos 
3174e98e3e1Schristos 
3184e98e3e1Schristos 
3194e98e3e1Schristos /* traverse the path specified by spec starting at current */
3204e98e3e1Schristos 
3214e98e3e1Schristos static struct hw *
3224e98e3e1Schristos split_find_device (struct hw *current,
3234e98e3e1Schristos 		   name_specifier *spec)
3244e98e3e1Schristos {
3254e98e3e1Schristos   /* strip off (and process) any leading ., .., ./ and / */
3264e98e3e1Schristos   while (1)
3274e98e3e1Schristos     {
3284e98e3e1Schristos       if (strncmp (spec->path, "/", strlen ("/")) == 0)
3294e98e3e1Schristos 	{
3304e98e3e1Schristos 	  /* cd /... */
3314e98e3e1Schristos 	  while (current != NULL && hw_parent (current) != NULL)
3324e98e3e1Schristos 	    current = hw_parent (current);
3334e98e3e1Schristos 	  spec->path += strlen ("/");
3344e98e3e1Schristos 	}
3354e98e3e1Schristos       else if (strncmp (spec->path, "./", strlen ("./")) == 0)
3364e98e3e1Schristos 	{
3374e98e3e1Schristos 	  /* cd ./... */
3384e98e3e1Schristos 	  spec->path += strlen ("./");
3394e98e3e1Schristos 	}
3404e98e3e1Schristos       else if (strncmp (spec->path, "../", strlen ("../")) == 0)
3414e98e3e1Schristos 	{
3424e98e3e1Schristos 	  /* cd ../... */
3434e98e3e1Schristos 	  if (current != NULL && hw_parent (current) != NULL)
3444e98e3e1Schristos 	    current = hw_parent (current);
3454e98e3e1Schristos 	  spec->path += strlen ("../");
3464e98e3e1Schristos 	}
3474e98e3e1Schristos       else if (strcmp (spec->path, ".") == 0)
3484e98e3e1Schristos 	{
3494e98e3e1Schristos 	  /* cd . */
3504e98e3e1Schristos 	  spec->path += strlen (".");
3514e98e3e1Schristos 	}
3524e98e3e1Schristos       else if (strcmp (spec->path, "..") == 0)
3534e98e3e1Schristos 	{
3544e98e3e1Schristos 	  /* cd .. */
3554e98e3e1Schristos 	  if (current != NULL && hw_parent (current) != NULL)
3564e98e3e1Schristos 	    current = hw_parent (current);
3574e98e3e1Schristos 	  spec->path += strlen ("..");
3584e98e3e1Schristos 	}
3594e98e3e1Schristos       else
3604e98e3e1Schristos 	break;
3614e98e3e1Schristos     }
3624e98e3e1Schristos 
3634e98e3e1Schristos   /* now go through the path proper */
3644e98e3e1Schristos 
3654e98e3e1Schristos   if (current == NULL)
3664e98e3e1Schristos     {
3674e98e3e1Schristos       split_device_name (spec);
3684e98e3e1Schristos       return NULL;
3694e98e3e1Schristos     }
3704e98e3e1Schristos 
3714e98e3e1Schristos   while (split_device_name (spec))
3724e98e3e1Schristos     {
3734e98e3e1Schristos       struct hw *child;
3744e98e3e1Schristos       for (child = hw_child (current);
3754e98e3e1Schristos 	   child != NULL; child = hw_sibling (child))
3764e98e3e1Schristos 	{
3774e98e3e1Schristos 	  if (strcmp (spec->name, hw_name (child)) == 0)
3784e98e3e1Schristos 	    {
3794e98e3e1Schristos 	      if (spec->unit == NULL)
3804e98e3e1Schristos 		break;
3814e98e3e1Schristos 	      else
3824e98e3e1Schristos 		{
3834e98e3e1Schristos 		  hw_unit phys;
3844e98e3e1Schristos 		  hw_unit_decode (current, spec->unit, &phys);
3854e98e3e1Schristos 		  if (memcmp (&phys, hw_unit_address (child),
3864e98e3e1Schristos 			      sizeof (hw_unit)) == 0)
3874e98e3e1Schristos 		    break;
3884e98e3e1Schristos 		}
3894e98e3e1Schristos 	    }
3904e98e3e1Schristos 	}
3914e98e3e1Schristos       if (child == NULL)
3924e98e3e1Schristos 	return current; /* search failed */
3934e98e3e1Schristos       current = child;
3944e98e3e1Schristos     }
3954e98e3e1Schristos 
3964e98e3e1Schristos   return current;
3974e98e3e1Schristos }
3984e98e3e1Schristos 
3994e98e3e1Schristos 
4004e98e3e1Schristos static struct hw *
4014e98e3e1Schristos split_fill_path (struct hw *current,
4024e98e3e1Schristos 		 const char *device_specifier,
4034e98e3e1Schristos 		 name_specifier *spec)
4044e98e3e1Schristos {
4054e98e3e1Schristos   /* break it up */
4064e98e3e1Schristos   if (!split_device_specifier (current, device_specifier, spec))
4074e98e3e1Schristos     hw_abort (current, "error parsing %s\n", device_specifier);
4084e98e3e1Schristos 
4094e98e3e1Schristos   /* fill our tree with its contents */
4104e98e3e1Schristos   current = split_find_device (current, spec);
4114e98e3e1Schristos 
4124e98e3e1Schristos   /* add any additional devices as needed */
4134e98e3e1Schristos   if (spec->name != NULL)
4144e98e3e1Schristos     {
4154e98e3e1Schristos       do
4164e98e3e1Schristos 	{
4174e98e3e1Schristos 	  if (current != NULL && !hw_finished_p (current))
4184e98e3e1Schristos 	    hw_finish (current);
4194e98e3e1Schristos 	  current = hw_create (NULL,
4204e98e3e1Schristos 			       current,
4214e98e3e1Schristos 			       spec->family,
4224e98e3e1Schristos 			       spec->name,
4234e98e3e1Schristos 			       spec->unit,
4244e98e3e1Schristos 			       spec->args);
4254e98e3e1Schristos 	}
4264e98e3e1Schristos       while (split_device_name (spec));
4274e98e3e1Schristos     }
4284e98e3e1Schristos 
4294e98e3e1Schristos   return current;
4304e98e3e1Schristos }
4314e98e3e1Schristos 
4324e98e3e1Schristos 
4334e98e3e1Schristos /* <non-white-space> */
4344e98e3e1Schristos 
4354e98e3e1Schristos static const char *
4364e98e3e1Schristos skip_token (const char *chp)
4374e98e3e1Schristos {
4384e98e3e1Schristos   while (!isspace (*chp) && *chp != '\0')
4394e98e3e1Schristos     chp++;
4404e98e3e1Schristos   while (isspace (*chp) && *chp != '\0')
4414e98e3e1Schristos     chp++;
4424e98e3e1Schristos   return chp;
4434e98e3e1Schristos }
4444e98e3e1Schristos 
4454e98e3e1Schristos 
4464e98e3e1Schristos /* count the number of entries */
4474e98e3e1Schristos 
4484e98e3e1Schristos static int
4494e98e3e1Schristos count_entries (struct hw *current,
4504e98e3e1Schristos 	       const char *property_name,
4514e98e3e1Schristos 	       const char *property_value,
4524e98e3e1Schristos 	       int modulo)
4534e98e3e1Schristos {
4544e98e3e1Schristos   const char *chp = property_value;
4554e98e3e1Schristos   int nr_entries = 0;
4564e98e3e1Schristos   while (*chp != '\0')
4574e98e3e1Schristos     {
4584e98e3e1Schristos       nr_entries += 1;
4594e98e3e1Schristos       chp = skip_token (chp);
4604e98e3e1Schristos     }
4614e98e3e1Schristos   if ((nr_entries % modulo) != 0)
4624e98e3e1Schristos     {
4634e98e3e1Schristos       hw_abort (current, "incorrect number of entries for %s property %s, should be multiple of %d",
4644e98e3e1Schristos 		property_name, property_value, modulo);
4654e98e3e1Schristos     }
4664e98e3e1Schristos   return nr_entries / modulo;
4674e98e3e1Schristos }
4684e98e3e1Schristos 
4694e98e3e1Schristos 
4704e98e3e1Schristos 
4714e98e3e1Schristos /* parse: <address> ::= <token> ; device dependant */
4724e98e3e1Schristos 
4734e98e3e1Schristos static const char *
4744e98e3e1Schristos parse_address (struct hw *current,
4754e98e3e1Schristos 	       struct hw *bus,
4764e98e3e1Schristos 	       const char *chp,
4774e98e3e1Schristos 	       hw_unit *address)
4784e98e3e1Schristos {
4794e98e3e1Schristos   if (hw_unit_decode (bus, chp, address) < 0)
4804e98e3e1Schristos     hw_abort (current, "invalid unit address in %s", chp);
4814e98e3e1Schristos   return skip_token (chp);
4824e98e3e1Schristos }
4834e98e3e1Schristos 
4844e98e3e1Schristos 
4854e98e3e1Schristos /* parse: <size> ::= <number> { "," <number> } ; */
4864e98e3e1Schristos 
4874e98e3e1Schristos static const char *
4884e98e3e1Schristos parse_size (struct hw *current,
4894e98e3e1Schristos 	    struct hw *bus,
4904e98e3e1Schristos 	    const char *chp,
4914e98e3e1Schristos 	    hw_unit *size)
4924e98e3e1Schristos {
4934e98e3e1Schristos   int i;
4944e98e3e1Schristos   int nr;
4954e98e3e1Schristos   const char *curr = chp;
4964e98e3e1Schristos   memset (size, 0, sizeof (*size));
4974e98e3e1Schristos   /* parse the numeric list */
4984e98e3e1Schristos   size->nr_cells = hw_unit_nr_size_cells (bus);
4994e98e3e1Schristos   nr = 0;
5004e98e3e1Schristos   while (1)
5014e98e3e1Schristos     {
5024e98e3e1Schristos       char *next;
5034e98e3e1Schristos       size->cells[nr] = strtoul (curr, &next, 0);
5044e98e3e1Schristos       if (curr == next)
5054e98e3e1Schristos 	hw_abort (current, "Problem parsing <size> %s", chp);
5064e98e3e1Schristos       nr += 1;
5074e98e3e1Schristos       if (next[0] != ',')
5084e98e3e1Schristos 	break;
5094e98e3e1Schristos       if (nr == size->nr_cells)
5104e98e3e1Schristos 	hw_abort (current, "Too many values in <size> %s", chp);
5114e98e3e1Schristos       curr = next + 1;
5124e98e3e1Schristos     }
5134e98e3e1Schristos   ASSERT (nr > 0 && nr <= size->nr_cells);
5144e98e3e1Schristos   /* right align the numbers */
5154e98e3e1Schristos   for (i = 1; i <= size->nr_cells; i++)
5164e98e3e1Schristos     {
5174e98e3e1Schristos       if (i <= nr)
5184e98e3e1Schristos 	size->cells[size->nr_cells - i] = size->cells[nr - i];
5194e98e3e1Schristos       else
5204e98e3e1Schristos 	size->cells[size->nr_cells - i] = 0;
5214e98e3e1Schristos     }
5224e98e3e1Schristos   return skip_token (chp);
5234e98e3e1Schristos }
5244e98e3e1Schristos 
5254e98e3e1Schristos 
5264e98e3e1Schristos /* parse: <reg> ::= { <address> <size> } ; */
5274e98e3e1Schristos 
5284e98e3e1Schristos static void
5294e98e3e1Schristos parse_reg_property (struct hw *current,
5304e98e3e1Schristos 		    const char *property_name,
5314e98e3e1Schristos 		    const char *property_value)
5324e98e3e1Schristos {
5334e98e3e1Schristos   int nr_regs;
5344e98e3e1Schristos   int reg_nr;
5354e98e3e1Schristos   reg_property_spec *regs;
5364e98e3e1Schristos   const char *chp;
5374e98e3e1Schristos 
5384e98e3e1Schristos   /* determine the number of reg entries by counting tokens */
5394e98e3e1Schristos   nr_regs = count_entries (current, property_name, property_value, 2);
5404e98e3e1Schristos 
5414e98e3e1Schristos   /* create working space */
5424e98e3e1Schristos   regs = zalloc (nr_regs * sizeof (*regs));
5434e98e3e1Schristos 
5444e98e3e1Schristos   /* fill it in */
5454e98e3e1Schristos   chp = property_value;
5464e98e3e1Schristos   for (reg_nr = 0; reg_nr < nr_regs; reg_nr++)
5474e98e3e1Schristos     {
5484e98e3e1Schristos       chp = parse_address (current, hw_parent (current),
5494e98e3e1Schristos 			   chp, &regs[reg_nr].address);
5504e98e3e1Schristos       chp = parse_size (current, hw_parent (current),
5514e98e3e1Schristos 			chp, &regs[reg_nr].size);
5524e98e3e1Schristos     }
5534e98e3e1Schristos 
5544e98e3e1Schristos   /* create it */
5554e98e3e1Schristos   hw_add_reg_array_property (current, property_name,
5564e98e3e1Schristos 			     regs, nr_regs);
5574e98e3e1Schristos 
5584e98e3e1Schristos   free (regs);
5594e98e3e1Schristos }
5604e98e3e1Schristos 
5614e98e3e1Schristos 
5624e98e3e1Schristos /* { <child-address> <parent-address> <child-size> }* */
5634e98e3e1Schristos 
5644e98e3e1Schristos static void
5654e98e3e1Schristos parse_ranges_property (struct hw *current,
5664e98e3e1Schristos 		       const char *property_name,
5674e98e3e1Schristos 		       const char *property_value)
5684e98e3e1Schristos {
5694e98e3e1Schristos   int nr_ranges;
5704e98e3e1Schristos   int range_nr;
5714e98e3e1Schristos   range_property_spec *ranges;
5724e98e3e1Schristos   const char *chp;
5734e98e3e1Schristos 
5744e98e3e1Schristos   /* determine the number of ranges specified */
5754e98e3e1Schristos   nr_ranges = count_entries (current, property_name, property_value, 3);
5764e98e3e1Schristos 
5774e98e3e1Schristos   /* create a property of that size */
5784e98e3e1Schristos   ranges = zalloc (nr_ranges * sizeof (*ranges));
5794e98e3e1Schristos 
5804e98e3e1Schristos   /* fill it in */
5814e98e3e1Schristos   chp = property_value;
5824e98e3e1Schristos   for (range_nr = 0; range_nr < nr_ranges; range_nr++)
5834e98e3e1Schristos     {
5844e98e3e1Schristos       chp = parse_address (current, current,
5854e98e3e1Schristos 			   chp, &ranges[range_nr].child_address);
5864e98e3e1Schristos       chp = parse_address (current, hw_parent (current),
5874e98e3e1Schristos 			   chp, &ranges[range_nr].parent_address);
5884e98e3e1Schristos       chp = parse_size (current, current,
5894e98e3e1Schristos 			chp, &ranges[range_nr].size);
5904e98e3e1Schristos     }
5914e98e3e1Schristos 
5924e98e3e1Schristos   /* create it */
5934e98e3e1Schristos   hw_add_range_array_property (current, property_name, ranges, nr_ranges);
5944e98e3e1Schristos 
5954e98e3e1Schristos   free (ranges);
5964e98e3e1Schristos }
5974e98e3e1Schristos 
5984e98e3e1Schristos 
5994e98e3e1Schristos /* <integer> ... */
6004e98e3e1Schristos 
6014e98e3e1Schristos static void
6024e98e3e1Schristos parse_integer_property (struct hw *current,
6034e98e3e1Schristos 			const char *property_name,
6044e98e3e1Schristos 			const char *property_value)
6054e98e3e1Schristos {
6064e98e3e1Schristos   int nr_entries;
6074e98e3e1Schristos   unsigned_cell words[1024];
6084e98e3e1Schristos   /* integer or integer array? */
6094e98e3e1Schristos   nr_entries = 0;
6104e98e3e1Schristos   while (1)
6114e98e3e1Schristos     {
6124e98e3e1Schristos       char *end;
6134e98e3e1Schristos       words[nr_entries] = strtoul (property_value, &end, 0);
6144e98e3e1Schristos       if (property_value == end)
6154e98e3e1Schristos 	break;
6164e98e3e1Schristos       nr_entries += 1;
6174e98e3e1Schristos       if (nr_entries * sizeof (words[0]) >= sizeof (words))
6184e98e3e1Schristos 	hw_abort (current, "buffer overflow");
6194e98e3e1Schristos       property_value = end;
6204e98e3e1Schristos     }
6214e98e3e1Schristos   if (nr_entries == 0)
6224e98e3e1Schristos     hw_abort (current, "error parsing integer property %s (%s)",
6234e98e3e1Schristos 	      property_name, property_value);
6244e98e3e1Schristos   else if (nr_entries == 1)
6254e98e3e1Schristos     hw_add_integer_property (current, property_name, words[0]);
6264e98e3e1Schristos   else
6274e98e3e1Schristos     {
6284e98e3e1Schristos       int i;
6294e98e3e1Schristos       for (i = 0; i < nr_entries; i++)
6304e98e3e1Schristos 	{
6314e98e3e1Schristos 	  H2BE (words[i]);
6324e98e3e1Schristos 	}
6334e98e3e1Schristos       /* perhaps integer array property is better */
6344e98e3e1Schristos       hw_add_array_property (current, property_name, words,
6354e98e3e1Schristos 			     sizeof (words[0]) * nr_entries);
6364e98e3e1Schristos     }
6374e98e3e1Schristos }
6384e98e3e1Schristos 
6394e98e3e1Schristos 
6404e98e3e1Schristos /* <string> ... */
6414e98e3e1Schristos 
6424e98e3e1Schristos static void
6434e98e3e1Schristos parse_string_property (struct hw *current,
6444e98e3e1Schristos 		       const char *property_name,
6454e98e3e1Schristos 		       const char *property_value)
6464e98e3e1Schristos {
6474e98e3e1Schristos   char **strings;
6484e98e3e1Schristos   const char *chp;
6494e98e3e1Schristos   int nr_strings;
6504e98e3e1Schristos   int approx_nr_strings;
6514e98e3e1Schristos 
6524e98e3e1Schristos   /* get an estimate as to the number of strings by counting double
6534e98e3e1Schristos      quotes */
6544e98e3e1Schristos   approx_nr_strings = 2;
6554e98e3e1Schristos   for (chp = property_value; *chp; chp++)
6564e98e3e1Schristos     {
6574e98e3e1Schristos       if (*chp == '"')
6584e98e3e1Schristos 	approx_nr_strings++;
6594e98e3e1Schristos     }
6604e98e3e1Schristos   approx_nr_strings = (approx_nr_strings) / 2;
6614e98e3e1Schristos 
6624e98e3e1Schristos   /* create a string buffer for that many (plus a null) */
6634e98e3e1Schristos   strings = (char**) zalloc ((approx_nr_strings + 1) * sizeof (char*));
6644e98e3e1Schristos 
6654e98e3e1Schristos   /* now find all the strings */
6664e98e3e1Schristos   chp = property_value;
6674e98e3e1Schristos   nr_strings = 0;
6684e98e3e1Schristos   while (1)
6694e98e3e1Schristos     {
6704e98e3e1Schristos 
6714e98e3e1Schristos       /* skip leading space */
6724e98e3e1Schristos       while (*chp != '\0' && isspace (*chp))
6734e98e3e1Schristos 	chp += 1;
6744e98e3e1Schristos       if (*chp == '\0')
6754e98e3e1Schristos 	break;
6764e98e3e1Schristos 
6774e98e3e1Schristos       /* copy it in */
6784e98e3e1Schristos       if (*chp == '"')
6794e98e3e1Schristos 	{
6804e98e3e1Schristos 	  /* a quoted string - watch for '\' et al. */
6814e98e3e1Schristos 	  /* estimate the size and allocate space for it */
6824e98e3e1Schristos 	  int pos;
6834e98e3e1Schristos 	  chp++;
6844e98e3e1Schristos 	  pos = 0;
6854e98e3e1Schristos 	  while (chp[pos] != '\0' && chp[pos] != '"')
6864e98e3e1Schristos 	    {
6874e98e3e1Schristos 	      if (chp[pos] == '\\' && chp[pos+1] != '\0')
6884e98e3e1Schristos 		pos += 2;
6894e98e3e1Schristos 	      else
6904e98e3e1Schristos 		pos += 1;
6914e98e3e1Schristos 	    }
6924e98e3e1Schristos 	  strings[nr_strings] = zalloc (pos + 1);
6934e98e3e1Schristos 	  /* copy the string over */
6944e98e3e1Schristos 	  pos = 0;
6954e98e3e1Schristos 	  while (*chp != '\0' && *chp != '"')
6964e98e3e1Schristos 	    {
6974e98e3e1Schristos 	      if (*chp == '\\' && *(chp+1) != '\0')
6984e98e3e1Schristos 		{
6994e98e3e1Schristos 		  strings[nr_strings][pos] = *(chp+1);
7004e98e3e1Schristos 		  chp += 2;
7014e98e3e1Schristos 		  pos++;
7024e98e3e1Schristos 		}
7034e98e3e1Schristos 	      else
7044e98e3e1Schristos 		{
7054e98e3e1Schristos 		  strings[nr_strings][pos] = *chp;
7064e98e3e1Schristos 		  chp += 1;
7074e98e3e1Schristos 		  pos++;
7084e98e3e1Schristos 		}
7094e98e3e1Schristos 	    }
7104e98e3e1Schristos 	  if (*chp != '\0')
7114e98e3e1Schristos 	    chp++;
7124e98e3e1Schristos 	  strings[nr_strings][pos] = '\0';
7134e98e3e1Schristos 	}
7144e98e3e1Schristos       else
7154e98e3e1Schristos 	{
7164e98e3e1Schristos 	  /* copy over a single unquoted token */
7174e98e3e1Schristos 	  int len = 0;
7184e98e3e1Schristos 	  while (chp[len] != '\0' && !isspace (chp[len]))
7194e98e3e1Schristos 	    len++;
7204e98e3e1Schristos 	  strings[nr_strings] = zalloc (len + 1);
7214e98e3e1Schristos 	  strncpy (strings[nr_strings], chp, len);
7224e98e3e1Schristos 	  strings[nr_strings][len] = '\0';
7234e98e3e1Schristos 	  chp += len;
7244e98e3e1Schristos 	}
7254e98e3e1Schristos       nr_strings++;
7264e98e3e1Schristos       if (nr_strings > approx_nr_strings)
7274e98e3e1Schristos 	hw_abort (current, "String property %s badly formatted",
7284e98e3e1Schristos 		  property_name);
7294e98e3e1Schristos     }
7304e98e3e1Schristos   ASSERT (strings[nr_strings] == NULL); /* from zalloc */
7314e98e3e1Schristos 
7324e98e3e1Schristos   /* install it */
7334e98e3e1Schristos   if (nr_strings == 0)
7344e98e3e1Schristos     hw_add_string_property (current, property_name, "");
7354e98e3e1Schristos   else if (nr_strings == 1)
7364e98e3e1Schristos     hw_add_string_property (current, property_name, strings[0]);
7374e98e3e1Schristos   else
7384e98e3e1Schristos     {
7394e98e3e1Schristos       const char **specs = (const char**) strings; /* stop a bogus error */
7404e98e3e1Schristos       hw_add_string_array_property (current, property_name,
7414e98e3e1Schristos 				    specs, nr_strings);
7424e98e3e1Schristos     }
7434e98e3e1Schristos 
7444e98e3e1Schristos   /* flush the created string */
7454e98e3e1Schristos   while (nr_strings > 0)
7464e98e3e1Schristos     {
7474e98e3e1Schristos       nr_strings--;
7484e98e3e1Schristos       free (strings[nr_strings]);
7494e98e3e1Schristos     }
7504e98e3e1Schristos   free (strings);
7514e98e3e1Schristos }
7524e98e3e1Schristos 
7534e98e3e1Schristos 
7544e98e3e1Schristos /* <path-to-ihandle-device> */
7554e98e3e1Schristos 
7564e98e3e1Schristos #if NOT_YET
7574e98e3e1Schristos static void
7584e98e3e1Schristos parse_ihandle_property (struct hw *current,
7594e98e3e1Schristos 			const char *property,
7604e98e3e1Schristos 			const char *value)
7614e98e3e1Schristos {
7624e98e3e1Schristos   ihandle_runtime_property_spec ihandle;
7634e98e3e1Schristos 
7644e98e3e1Schristos   /* pass the full path */
7654e98e3e1Schristos   ihandle.full_path = value;
7664e98e3e1Schristos 
7674e98e3e1Schristos   /* save this ready for the ihandle create */
7684e98e3e1Schristos   hw_add_ihandle_runtime_property (current, property,
7694e98e3e1Schristos 				   &ihandle);
7704e98e3e1Schristos }
7714e98e3e1Schristos #endif
7724e98e3e1Schristos 
7734e98e3e1Schristos 
7744e98e3e1Schristos struct hw *
7754e98e3e1Schristos hw_tree_create (SIM_DESC sd,
7764e98e3e1Schristos 		const char *family)
7774e98e3e1Schristos {
7784e98e3e1Schristos   return hw_create (sd, NULL, family, family, NULL, NULL);
7794e98e3e1Schristos }
7804e98e3e1Schristos 
7814e98e3e1Schristos void
7824e98e3e1Schristos hw_tree_delete (struct hw *me)
7834e98e3e1Schristos {
7844e98e3e1Schristos   /* Need to allow devices to disapear under our feet */
7854e98e3e1Schristos   while (hw_child (me) != NULL)
7864e98e3e1Schristos     {
7874e98e3e1Schristos       hw_tree_delete (hw_child (me));
7884e98e3e1Schristos     }
7894e98e3e1Schristos   hw_delete (me);
7904e98e3e1Schristos }
7914e98e3e1Schristos 
7924e98e3e1Schristos 
7934e98e3e1Schristos struct hw *
7944e98e3e1Schristos hw_tree_parse (struct hw *current,
7954e98e3e1Schristos 	       const char *fmt,
7964e98e3e1Schristos 	       ...)
7974e98e3e1Schristos {
7984e98e3e1Schristos     va_list ap;
7994e98e3e1Schristos     va_start (ap, fmt);
8004e98e3e1Schristos     current = hw_tree_vparse (current, fmt, ap);
8014e98e3e1Schristos     va_end (ap);
8024e98e3e1Schristos     return current;
8034e98e3e1Schristos }
8044e98e3e1Schristos 
8054e98e3e1Schristos struct hw *
8064e98e3e1Schristos hw_tree_vparse (struct hw *current,
8074e98e3e1Schristos 		const char *fmt,
8084e98e3e1Schristos 		va_list ap)
8094e98e3e1Schristos {
8104e98e3e1Schristos   char device_specifier[1024];
8114e98e3e1Schristos   name_specifier spec;
8124e98e3e1Schristos 
8134e98e3e1Schristos   /* format the path */
8144e98e3e1Schristos   vsprintf (device_specifier, fmt, ap);
8154e98e3e1Schristos   if (strlen (device_specifier) >= sizeof (device_specifier))
8164e98e3e1Schristos     hw_abort (NULL, "device_tree_add_deviced: buffer overflow\n");
8174e98e3e1Schristos 
8184e98e3e1Schristos   /* construct the tree down to the final struct hw */
8194e98e3e1Schristos   current = split_fill_path (current, device_specifier, &spec);
8204e98e3e1Schristos 
8214e98e3e1Schristos   /* is there an interrupt spec */
8224e98e3e1Schristos   if (spec.property == NULL
8234e98e3e1Schristos       && spec.value != NULL)
8244e98e3e1Schristos     {
8254e98e3e1Schristos       char *op = split_value (&spec);
8264e98e3e1Schristos       switch (op[0])
8274e98e3e1Schristos 	{
8284e98e3e1Schristos 	case '>':
8294e98e3e1Schristos 	  {
8304e98e3e1Schristos 	    char *my_port_name = split_value (&spec);
8314e98e3e1Schristos 	    int my_port;
8324e98e3e1Schristos 	    char *dest_port_name = split_value (&spec);
8334e98e3e1Schristos 	    int dest_port;
8344e98e3e1Schristos 	    name_specifier dest_spec;
8354e98e3e1Schristos 	    char *dest_hw_name = split_value (&spec);
8364e98e3e1Schristos 	    struct hw *dest;
8374e98e3e1Schristos 	    /* find my name */
8384e98e3e1Schristos 	    if (!hw_finished_p (current))
8394e98e3e1Schristos 	      hw_finish (current);
8404e98e3e1Schristos 	    my_port = hw_port_decode (current, my_port_name, output_port);
8414e98e3e1Schristos 	    /* find the dest device and port */
8424e98e3e1Schristos 	    dest = split_fill_path (current, dest_hw_name, &dest_spec);
8434e98e3e1Schristos 	    if (!hw_finished_p (dest))
8444e98e3e1Schristos 	      hw_finish (dest);
8454e98e3e1Schristos 	    dest_port = hw_port_decode (dest, dest_port_name,
8464e98e3e1Schristos 					input_port);
8474e98e3e1Schristos 	    /* connect the two */
8484e98e3e1Schristos 	    hw_port_attach (current,
8494e98e3e1Schristos 			    my_port,
8504e98e3e1Schristos 			    dest,
8514e98e3e1Schristos 			    dest_port,
852*88241920Schristos 			    permanent_object);
8534e98e3e1Schristos 	    break;
8544e98e3e1Schristos 	  }
8554e98e3e1Schristos 	default:
8564e98e3e1Schristos 	  hw_abort (current, "unreconised interrupt spec %s\n", spec.value);
8574e98e3e1Schristos 	  break;
8584e98e3e1Schristos 	}
8594e98e3e1Schristos     }
8604e98e3e1Schristos 
8614e98e3e1Schristos   /* is there a property */
8624e98e3e1Schristos   if (spec.property != NULL)
8634e98e3e1Schristos     {
8644e98e3e1Schristos       if (strcmp (spec.value, "true") == 0)
8654e98e3e1Schristos 	hw_add_boolean_property (current, spec.property, 1);
8664e98e3e1Schristos       else if (strcmp (spec.value, "false") == 0)
8674e98e3e1Schristos 	hw_add_boolean_property (current, spec.property, 0);
8684e98e3e1Schristos       else
8694e98e3e1Schristos 	{
8704e98e3e1Schristos 	  const struct hw_property *property;
8714e98e3e1Schristos 	  switch (spec.value[0])
8724e98e3e1Schristos 	    {
8734e98e3e1Schristos #if NOT_YET
8744e98e3e1Schristos 	    case '*':
8754e98e3e1Schristos 	      {
8764e98e3e1Schristos 		parse_ihandle_property (current, spec.property, spec.value + 1);
8774e98e3e1Schristos 		break;
8784e98e3e1Schristos 	      }
8794e98e3e1Schristos #endif
8804e98e3e1Schristos 	    case '[':
8814e98e3e1Schristos 	      {
8824b169a6bSchristos 		uint8_t words[1024];
8834e98e3e1Schristos 		char *curr = spec.value + 1;
8844e98e3e1Schristos 		int nr_words = 0;
8854e98e3e1Schristos 		while (1)
8864e98e3e1Schristos 		  {
8874e98e3e1Schristos 		    char *next;
8884e98e3e1Schristos 		    words[nr_words] = H2BE_1 (strtoul (curr, &next, 0));
8894e98e3e1Schristos 		    if (curr == next)
8904e98e3e1Schristos 		      break;
8914e98e3e1Schristos 		    curr = next;
8924e98e3e1Schristos 		    nr_words += 1;
8934e98e3e1Schristos 		  }
8944e98e3e1Schristos 		hw_add_array_property (current, spec.property,
8954e98e3e1Schristos 				       words, sizeof (words[0]) * nr_words);
8964e98e3e1Schristos 		break;
8974e98e3e1Schristos 	      }
8984e98e3e1Schristos 	    case '"':
8994e98e3e1Schristos 	      {
9004e98e3e1Schristos 		parse_string_property (current, spec.property, spec.value);
9014e98e3e1Schristos 		break;
9024e98e3e1Schristos 	      }
9034e98e3e1Schristos 	    case '!':
9044e98e3e1Schristos 	      {
9054e98e3e1Schristos 		spec.value++;
9064e98e3e1Schristos 		property = hw_tree_find_property (current, spec.value);
9074e98e3e1Schristos 		if (property == NULL)
9084e98e3e1Schristos 		  hw_abort (current, "property %s not found\n", spec.value);
9094e98e3e1Schristos 		hw_add_duplicate_property (current,
9104e98e3e1Schristos 					   spec.property,
9114e98e3e1Schristos 					   property);
9124e98e3e1Schristos 		break;
9134e98e3e1Schristos 	      }
9144e98e3e1Schristos 	    default:
9154e98e3e1Schristos 	      {
9164e98e3e1Schristos 		if (strcmp (spec.property, "reg") == 0
9174e98e3e1Schristos 		    || strcmp (spec.property, "assigned-addresses") == 0
9184e98e3e1Schristos 		    || strcmp (spec.property, "alternate-reg") == 0)
9194e98e3e1Schristos 		  {
9204e98e3e1Schristos 		    parse_reg_property (current, spec.property, spec.value);
9214e98e3e1Schristos 		  }
9224e98e3e1Schristos 		else if (strcmp (spec.property, "ranges") == 0)
9234e98e3e1Schristos 		  {
9244e98e3e1Schristos 		    parse_ranges_property (current, spec.property, spec.value);
9254e98e3e1Schristos 		  }
9264e98e3e1Schristos 		else if (isdigit (spec.value[0])
9274e98e3e1Schristos 			 || (spec.value[0] == '-' && isdigit (spec.value[1]))
9284e98e3e1Schristos 			 || (spec.value[0] == '+' && isdigit (spec.value[1])))
9294e98e3e1Schristos 		  {
9304e98e3e1Schristos 		    parse_integer_property (current, spec.property, spec.value);
9314e98e3e1Schristos 		  }
9324e98e3e1Schristos 		else
9334e98e3e1Schristos 		  parse_string_property (current, spec.property, spec.value);
9344e98e3e1Schristos 		break;
9354e98e3e1Schristos 	      }
9364e98e3e1Schristos 	    }
9374e98e3e1Schristos 	}
9384e98e3e1Schristos     }
9394e98e3e1Schristos   return current;
9404e98e3e1Schristos }
9414e98e3e1Schristos 
9424e98e3e1Schristos 
9434e98e3e1Schristos static void
9444e98e3e1Schristos finish_hw_tree (struct hw *me,
9454e98e3e1Schristos 		void *data)
9464e98e3e1Schristos {
9474e98e3e1Schristos   if (!hw_finished_p (me))
9484e98e3e1Schristos     hw_finish (me);
9494e98e3e1Schristos }
9504e98e3e1Schristos 
9514e98e3e1Schristos void
9524e98e3e1Schristos hw_tree_finish (struct hw *root)
9534e98e3e1Schristos {
9544e98e3e1Schristos   hw_tree_traverse (root, finish_hw_tree, NULL, NULL);
9554e98e3e1Schristos }
9564e98e3e1Schristos 
9574e98e3e1Schristos 
9584e98e3e1Schristos 
9594e98e3e1Schristos void
9604e98e3e1Schristos hw_tree_traverse (struct hw *root,
9614e98e3e1Schristos 		  hw_tree_traverse_function *prefix,
9624e98e3e1Schristos 		  hw_tree_traverse_function *postfix,
9634e98e3e1Schristos 		  void *data)
9644e98e3e1Schristos {
9654e98e3e1Schristos   struct hw *child;
9664e98e3e1Schristos   if (prefix != NULL)
9674e98e3e1Schristos     prefix (root, data);
9684e98e3e1Schristos   for (child = hw_child (root);
9694e98e3e1Schristos        child != NULL;
9704e98e3e1Schristos        child = hw_sibling (child))
9714e98e3e1Schristos     {
9724e98e3e1Schristos       hw_tree_traverse (child, prefix, postfix, data);
9734e98e3e1Schristos     }
9744e98e3e1Schristos   if (postfix != NULL)
9754e98e3e1Schristos     postfix (root, data);
9764e98e3e1Schristos }
9774e98e3e1Schristos 
9784e98e3e1Schristos 
9794e98e3e1Schristos 
9804e98e3e1Schristos struct printer
9814e98e3e1Schristos {
9824e98e3e1Schristos   hw_tree_print_callback *print;
9834e98e3e1Schristos   void *file;
9844e98e3e1Schristos };
9854e98e3e1Schristos 
9864e98e3e1Schristos static void
9874e98e3e1Schristos print_address (struct hw *bus,
9884e98e3e1Schristos 	       const hw_unit *phys,
9894e98e3e1Schristos 	       struct printer *p)
9904e98e3e1Schristos {
9914e98e3e1Schristos   char unit[32];
9924e98e3e1Schristos   hw_unit_encode (bus, phys, unit, sizeof (unit));
9934e98e3e1Schristos   p->print (p->file, " %s", unit);
9944e98e3e1Schristos }
9954e98e3e1Schristos 
9964e98e3e1Schristos static void
9974e98e3e1Schristos print_size (struct hw *bus,
9984e98e3e1Schristos 	    const hw_unit *size,
9994e98e3e1Schristos 	    struct printer *p)
10004e98e3e1Schristos {
10014e98e3e1Schristos   int i;
10024e98e3e1Schristos   for (i = 0; i < size->nr_cells; i++)
10034e98e3e1Schristos     if (size->cells[i] != 0)
10044e98e3e1Schristos       break;
10054e98e3e1Schristos   if (i < size->nr_cells)
10064e98e3e1Schristos     {
10074e98e3e1Schristos       p->print (p->file, " 0x%lx", (unsigned long) size->cells[i]);
10084e98e3e1Schristos       i++;
10094e98e3e1Schristos       for (; i < size->nr_cells; i++)
10104e98e3e1Schristos 	p->print (p->file, ",0x%lx", (unsigned long) size->cells[i]);
10114e98e3e1Schristos     }
10124e98e3e1Schristos   else
10134e98e3e1Schristos     p->print (p->file, " 0");
10144e98e3e1Schristos }
10154e98e3e1Schristos 
10164e98e3e1Schristos static void
10174e98e3e1Schristos print_reg_property (struct hw *me,
10184e98e3e1Schristos 		    const struct hw_property *property,
10194e98e3e1Schristos 		    struct printer *p)
10204e98e3e1Schristos {
10214e98e3e1Schristos   int reg_nr;
10224e98e3e1Schristos   reg_property_spec reg;
10234e98e3e1Schristos   for (reg_nr = 0;
10244e98e3e1Schristos        hw_find_reg_array_property (me, property->name, reg_nr, &reg);
10254e98e3e1Schristos        reg_nr++)
10264e98e3e1Schristos     {
10274e98e3e1Schristos       print_address (hw_parent (me), &reg.address, p);
10284e98e3e1Schristos       print_size (me, &reg.size, p);
10294e98e3e1Schristos     }
10304e98e3e1Schristos }
10314e98e3e1Schristos 
10324e98e3e1Schristos static void
10334e98e3e1Schristos print_ranges_property (struct hw *me,
10344e98e3e1Schristos 		       const struct hw_property *property,
10354e98e3e1Schristos 		       struct printer *p)
10364e98e3e1Schristos {
10374e98e3e1Schristos   int range_nr;
10384e98e3e1Schristos   range_property_spec range;
10394e98e3e1Schristos   for (range_nr = 0;
10404e98e3e1Schristos        hw_find_range_array_property (me, property->name, range_nr, &range);
10414e98e3e1Schristos        range_nr++)
10424e98e3e1Schristos     {
10434e98e3e1Schristos       print_address (me, &range.child_address, p);
10444e98e3e1Schristos       print_address (hw_parent (me), &range.parent_address, p);
10454e98e3e1Schristos       print_size (me, &range.size, p);
10464e98e3e1Schristos     }
10474e98e3e1Schristos }
10484e98e3e1Schristos 
10494e98e3e1Schristos static void
10504e98e3e1Schristos print_string (struct hw *me,
10514e98e3e1Schristos 	      const char *string,
10524e98e3e1Schristos 	      struct printer *p)
10534e98e3e1Schristos {
10544e98e3e1Schristos   p->print (p->file, " \"");
10554e98e3e1Schristos   while (*string != '\0')
10564e98e3e1Schristos     {
10574e98e3e1Schristos       switch (*string)
10584e98e3e1Schristos 	{
10594e98e3e1Schristos 	case '"':
10604e98e3e1Schristos 	  p->print (p->file, "\\\"");
10614e98e3e1Schristos 	  break;
10624e98e3e1Schristos 	case '\\':
10634e98e3e1Schristos 	  p->print (p->file, "\\\\");
10644e98e3e1Schristos 	  break;
10654e98e3e1Schristos 	default:
10664e98e3e1Schristos 	  p->print (p->file, "%c", *string);
10674e98e3e1Schristos 	  break;
10684e98e3e1Schristos 	}
10694e98e3e1Schristos       string++;
10704e98e3e1Schristos     }
10714e98e3e1Schristos   p->print (p->file, "\"");
10724e98e3e1Schristos }
10734e98e3e1Schristos 
10744e98e3e1Schristos static void
10754e98e3e1Schristos print_string_array_property (struct hw *me,
10764e98e3e1Schristos 			     const struct hw_property *property,
10774e98e3e1Schristos 			     struct printer *p)
10784e98e3e1Schristos {
10794e98e3e1Schristos   int nr;
10804e98e3e1Schristos   string_property_spec string;
10814e98e3e1Schristos   for (nr = 0;
10824e98e3e1Schristos        hw_find_string_array_property (me, property->name, nr, &string);
10834e98e3e1Schristos        nr++)
10844e98e3e1Schristos     {
10854e98e3e1Schristos       print_string (me, string, p);
10864e98e3e1Schristos     }
10874e98e3e1Schristos }
10884e98e3e1Schristos 
10894e98e3e1Schristos static void
10904e98e3e1Schristos print_properties (struct hw *me,
10914e98e3e1Schristos 		  struct printer *p)
10924e98e3e1Schristos {
10934e98e3e1Schristos   const struct hw_property *property;
10944e98e3e1Schristos   for (property = hw_find_property (me, NULL);
10954e98e3e1Schristos        property != NULL;
10964e98e3e1Schristos        property = hw_next_property (property))
10974e98e3e1Schristos     {
10984e98e3e1Schristos       if (hw_parent (me) == NULL)
10994e98e3e1Schristos 	p->print (p->file, "/%s", property->name);
11004e98e3e1Schristos       else
11014e98e3e1Schristos 	p->print (p->file, "%s/%s", hw_path (me), property->name);
11024e98e3e1Schristos       if (property->original != NULL)
11034e98e3e1Schristos 	{
11044e98e3e1Schristos 	  p->print (p->file, " !");
11054e98e3e1Schristos 	  p->print (p->file, "%s/%s",
11064e98e3e1Schristos 		     hw_path (property->original->owner),
11074e98e3e1Schristos 		     property->original->name);
11084e98e3e1Schristos 	}
11094e98e3e1Schristos       else
11104e98e3e1Schristos 	{
11114e98e3e1Schristos 	  switch (property->type)
11124e98e3e1Schristos 	    {
11134e98e3e1Schristos 	    case array_property:
11144e98e3e1Schristos 	      {
11154e98e3e1Schristos 		if ((property->sizeof_array % sizeof (signed_cell)) == 0)
11164e98e3e1Schristos 		  {
11174e98e3e1Schristos 		    unsigned_cell *w = (unsigned_cell*) property->array;
11184e98e3e1Schristos 		    int cell_nr;
11194e98e3e1Schristos 		    for (cell_nr = 0;
11204e98e3e1Schristos 			 cell_nr < (property->sizeof_array / sizeof (unsigned_cell));
11214e98e3e1Schristos 			 cell_nr++)
11224e98e3e1Schristos 		      {
11234e98e3e1Schristos 			p->print (p->file, " 0x%lx", (unsigned long) BE2H_cell (w[cell_nr]));
11244e98e3e1Schristos 		      }
11254e98e3e1Schristos 		  }
11264e98e3e1Schristos 		else
11274e98e3e1Schristos 		  {
11284b169a6bSchristos 		    uint8_t *w = (uint8_t*)property->array;
11294e98e3e1Schristos 		    p->print (p->file, " [");
11304e98e3e1Schristos 		    while ((char*)w - (char*)property->array < property->sizeof_array)
11314e98e3e1Schristos 		      {
11324e98e3e1Schristos 			p->print (p->file, " 0x%2x", BE2H_1 (*w));
11334e98e3e1Schristos 			w++;
11344e98e3e1Schristos 		      }
11354e98e3e1Schristos 		  }
11364e98e3e1Schristos 		break;
11374e98e3e1Schristos 	      }
11384e98e3e1Schristos 	    case boolean_property:
11394e98e3e1Schristos 	      {
11404e98e3e1Schristos 		int b = hw_find_boolean_property (me, property->name);
11414e98e3e1Schristos 		p->print (p->file, " %s", b ? "true"  : "false");
11424e98e3e1Schristos 		break;
11434e98e3e1Schristos 	      }
11444e98e3e1Schristos #if NOT_YET
11454e98e3e1Schristos 	    case ihandle_property:
11464e98e3e1Schristos 	      {
11474e98e3e1Schristos 		if (property->array != NULL)
11484e98e3e1Schristos 		  {
11494e98e3e1Schristos 		    device_instance *instance = hw_find_ihandle_property (me, property->name);
11504e98e3e1Schristos 		    p->print (p->file, " *%s", device_instance_path (instance));
11514e98e3e1Schristos 		  }
11524e98e3e1Schristos 		else
11534e98e3e1Schristos 		  {
11544e98e3e1Schristos 		    /* not yet initialized, ask the device for the path */
11554e98e3e1Schristos 		    ihandle_runtime_property_spec spec;
11564e98e3e1Schristos 		    hw_find_ihandle_runtime_property (me, property->name, &spec);
11574e98e3e1Schristos 		    p->print (p->file, " *%s", spec.full_path);
11584e98e3e1Schristos 		  }
11594e98e3e1Schristos 		break;
11604e98e3e1Schristos 	      }
11614e98e3e1Schristos #endif
11624e98e3e1Schristos 	    case integer_property:
11634e98e3e1Schristos 	      {
11644e98e3e1Schristos 		unsigned_word w = hw_find_integer_property (me, property->name);
11654e98e3e1Schristos 		p->print (p->file, " 0x%lx", (unsigned long)w);
11664e98e3e1Schristos 		break;
11674e98e3e1Schristos 	      }
11684e98e3e1Schristos 	    case range_array_property:
11694e98e3e1Schristos 	      {
11704e98e3e1Schristos 		print_ranges_property (me, property, p);
11714e98e3e1Schristos 		break;
11724e98e3e1Schristos 	      }
11734e98e3e1Schristos 	    case reg_array_property:
11744e98e3e1Schristos 	      {
11754e98e3e1Schristos 		print_reg_property (me, property, p);
11764e98e3e1Schristos 		break;
11774e98e3e1Schristos 	      }
11784e98e3e1Schristos 	    case string_property:
11794e98e3e1Schristos 	      {
11804e98e3e1Schristos 		const char *s = hw_find_string_property (me, property->name);
11814e98e3e1Schristos 		print_string (me, s, p);
11824e98e3e1Schristos 		break;
11834e98e3e1Schristos 	      }
11844e98e3e1Schristos 	    case string_array_property:
11854e98e3e1Schristos 	      {
11864e98e3e1Schristos 		print_string_array_property (me, property, p);
11874e98e3e1Schristos 		break;
11884e98e3e1Schristos 	      }
11894e98e3e1Schristos 	    }
11904e98e3e1Schristos 	}
11914e98e3e1Schristos       p->print (p->file, "\n");
11924e98e3e1Schristos     }
11934e98e3e1Schristos }
11944e98e3e1Schristos 
11954e98e3e1Schristos static void
11964e98e3e1Schristos print_interrupts (struct hw *me,
11974e98e3e1Schristos                   int my_port,
11984e98e3e1Schristos 		  struct hw *dest,
11994e98e3e1Schristos 		  int dest_port,
12004e98e3e1Schristos 		  void *data)
12014e98e3e1Schristos {
12024e98e3e1Schristos   struct printer *p = data;
12034e98e3e1Schristos   char src[32];
12044e98e3e1Schristos   char dst[32];
12054e98e3e1Schristos   hw_port_encode (me, my_port, src, sizeof (src), output_port);
12064e98e3e1Schristos   hw_port_encode (dest, dest_port, dst, sizeof (dst), input_port);
12074e98e3e1Schristos   p->print (p->file,
12084e98e3e1Schristos 	    "%s > %s %s %s\n",
12094e98e3e1Schristos 	    hw_path (me),
12104e98e3e1Schristos 	    src, dst,
12114e98e3e1Schristos 	    hw_path (dest));
12124e98e3e1Schristos }
12134e98e3e1Schristos 
12144e98e3e1Schristos static void
12154e98e3e1Schristos print_device (struct hw *me,
12164e98e3e1Schristos 	      void *data)
12174e98e3e1Schristos {
12184e98e3e1Schristos   struct printer *p = data;
12194e98e3e1Schristos   p->print (p->file, "%s\n", hw_path (me));
12204e98e3e1Schristos   print_properties (me, p);
12214e98e3e1Schristos   hw_port_traverse (me, print_interrupts, data);
12224e98e3e1Schristos }
12234e98e3e1Schristos 
12244e98e3e1Schristos void
12254e98e3e1Schristos hw_tree_print (struct hw *root,
12264e98e3e1Schristos 	       hw_tree_print_callback *print,
12274e98e3e1Schristos 	       void *file)
12284e98e3e1Schristos {
12294e98e3e1Schristos   struct printer p;
12304e98e3e1Schristos   p.print = print;
12314e98e3e1Schristos   p.file = file;
12324e98e3e1Schristos   hw_tree_traverse (root,
12334e98e3e1Schristos 		    print_device, NULL,
12344e98e3e1Schristos 		    &p);
12354e98e3e1Schristos }
12364e98e3e1Schristos 
12374e98e3e1Schristos 
12384e98e3e1Schristos 
12394e98e3e1Schristos #if NOT_YET
12404e98e3e1Schristos device_instance *
12414e98e3e1Schristos tree_instance (struct hw *root,
12424e98e3e1Schristos 	       const char *device_specifier)
12434e98e3e1Schristos {
12444e98e3e1Schristos   /* find the device node */
12454e98e3e1Schristos   struct hw *me;
12464e98e3e1Schristos   name_specifier spec;
12474e98e3e1Schristos   if (!split_device_specifier (root, device_specifier, &spec))
12484e98e3e1Schristos     return NULL;
12494e98e3e1Schristos   me = split_find_device (root, &spec);
12504e98e3e1Schristos   if (spec.name != NULL)
12514e98e3e1Schristos     return NULL;
12524e98e3e1Schristos   /* create the instance */
12534e98e3e1Schristos   return device_create_instance (me, device_specifier, spec.last_args);
12544e98e3e1Schristos }
12554e98e3e1Schristos #endif
12564e98e3e1Schristos 
12574e98e3e1Schristos struct hw *
12584e98e3e1Schristos hw_tree_find_device (struct hw *root,
12594e98e3e1Schristos 		     const char *path_to_device)
12604e98e3e1Schristos {
12614e98e3e1Schristos   struct hw *node;
12624e98e3e1Schristos   name_specifier spec;
12634e98e3e1Schristos 
12644e98e3e1Schristos   /* parse the path */
12654e98e3e1Schristos   split_device_specifier (root, path_to_device, &spec);
12664e98e3e1Schristos   if (spec.value != NULL)
12674e98e3e1Schristos     return NULL; /* something wierd */
12684e98e3e1Schristos 
12694e98e3e1Schristos   /* now find it */
12704e98e3e1Schristos   node = split_find_device (root, &spec);
12714e98e3e1Schristos   if (spec.name != NULL)
12724e98e3e1Schristos     return NULL; /* not a leaf */
12734e98e3e1Schristos 
12744e98e3e1Schristos   return node;
12754e98e3e1Schristos }
12764e98e3e1Schristos 
12774e98e3e1Schristos 
12784e98e3e1Schristos const struct hw_property *
12794e98e3e1Schristos hw_tree_find_property (struct hw *root,
12804e98e3e1Schristos 		       const char *path_to_property)
12814e98e3e1Schristos {
12824e98e3e1Schristos   name_specifier spec;
12834e98e3e1Schristos   if (!split_property_specifier (root, path_to_property, &spec))
12844e98e3e1Schristos     hw_abort (root, "Invalid property path %s", path_to_property);
12854e98e3e1Schristos   root = split_find_device (root, &spec);
12864e98e3e1Schristos   if (spec.name != NULL)
12874e98e3e1Schristos     return NULL; /* not a leaf */
12884e98e3e1Schristos   return hw_find_property (root, spec.property);
12894e98e3e1Schristos }
12904e98e3e1Schristos 
12914e98e3e1Schristos int
12924e98e3e1Schristos hw_tree_find_boolean_property (struct hw *root,
12934e98e3e1Schristos 			       const char *path_to_property)
12944e98e3e1Schristos {
12954e98e3e1Schristos   name_specifier spec;
12964e98e3e1Schristos   if (!split_property_specifier (root, path_to_property, &spec))
12974e98e3e1Schristos     hw_abort (root, "Invalid property path %s", path_to_property);
12984e98e3e1Schristos   root = split_find_device (root, &spec);
12994e98e3e1Schristos   if (spec.name != NULL)
13004e98e3e1Schristos     hw_abort (root, "device \"%s\" not found (property \"%s\")",
13014e98e3e1Schristos 	      spec.name, path_to_property);
13024e98e3e1Schristos   return hw_find_boolean_property (root, spec.property);
13034e98e3e1Schristos }
13044e98e3e1Schristos 
13054e98e3e1Schristos signed_cell
13064e98e3e1Schristos hw_tree_find_integer_property (struct hw *root,
13074e98e3e1Schristos 			       const char *path_to_property)
13084e98e3e1Schristos {
13094e98e3e1Schristos   name_specifier spec;
13104e98e3e1Schristos   if (!split_property_specifier (root, path_to_property, &spec))
13114e98e3e1Schristos     hw_abort (root, "Invalid property path %s", path_to_property);
13124e98e3e1Schristos   root = split_find_device (root, &spec);
13134e98e3e1Schristos   if (spec.name != NULL)
13144e98e3e1Schristos     hw_abort (root, "device \"%s\" not found (property \"%s\")",
13154e98e3e1Schristos 	      spec.name, path_to_property);
13164e98e3e1Schristos   return hw_find_integer_property (root, spec.property);
13174e98e3e1Schristos }
13184e98e3e1Schristos 
13194e98e3e1Schristos #if NOT_YET
13204e98e3e1Schristos device_instance *
13214e98e3e1Schristos hw_tree_find_ihandle_property (struct hw *root,
13224e98e3e1Schristos 			       const char *path_to_property)
13234e98e3e1Schristos {
13244e98e3e1Schristos   struct hw *root;
13254e98e3e1Schristos   name_specifier spec;
13264e98e3e1Schristos   if (!split_property_specifier (root, path_to_property, &spec))
13274e98e3e1Schristos     hw_abort (root, "Invalid property path %s", path_to_property);
13284e98e3e1Schristos   root = split_find_device (root, &spec);
13294e98e3e1Schristos   if (spec.name != NULL)
13304e98e3e1Schristos     hw_abort (root, "device \"%s\" not found (property \"%s\")",
13314e98e3e1Schristos 	      spec.name, path_to_property);
13324e98e3e1Schristos   return hw_find_ihandle_property (root, spec.property);
13334e98e3e1Schristos }
13344e98e3e1Schristos #endif
13354e98e3e1Schristos 
13364e98e3e1Schristos const char *
13374e98e3e1Schristos hw_tree_find_string_property (struct hw *root,
13384e98e3e1Schristos 			      const char *path_to_property)
13394e98e3e1Schristos {
13404e98e3e1Schristos   name_specifier spec;
13414e98e3e1Schristos   if (!split_property_specifier (root, path_to_property, &spec))
13424e98e3e1Schristos     hw_abort (root, "Invalid property path %s", path_to_property);
13434e98e3e1Schristos   root = split_find_device (root, &spec);
13444e98e3e1Schristos   if (spec.name != NULL)
13454e98e3e1Schristos     hw_abort (root, "device \"%s\" not found (property \"%s\")",
13464e98e3e1Schristos 	      spec.name, path_to_property);
13474e98e3e1Schristos   return hw_find_string_property (root, spec.property);
13484e98e3e1Schristos }
1349