xref: /netbsd/external/gpl3/gdb/dist/sim/common/hw-tree.c (revision 1424dfb3)
166e63ce3Schristos /* The common simulator framework for GDB, the GNU Debugger.
266e63ce3Schristos 
3*1424dfb3Schristos    Copyright 2002-2020 Free Software Foundation, Inc.
466e63ce3Schristos 
566e63ce3Schristos    Contributed by Andrew Cagney and Red Hat.
666e63ce3Schristos 
766e63ce3Schristos    This file is part of GDB.
866e63ce3Schristos 
966e63ce3Schristos    This program is free software; you can redistribute it and/or modify
1066e63ce3Schristos    it under the terms of the GNU General Public License as published by
1166e63ce3Schristos    the Free Software Foundation; either version 3 of the License, or
1266e63ce3Schristos    (at your option) any later version.
1366e63ce3Schristos 
1466e63ce3Schristos    This program is distributed in the hope that it will be useful,
1566e63ce3Schristos    but WITHOUT ANY WARRANTY; without even the implied warranty of
1666e63ce3Schristos    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1766e63ce3Schristos    GNU General Public License for more details.
1866e63ce3Schristos 
1966e63ce3Schristos    You should have received a copy of the GNU General Public License
2066e63ce3Schristos    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
2166e63ce3Schristos 
2266e63ce3Schristos 
2366e63ce3Schristos #include "hw-main.h"
2466e63ce3Schristos #include "hw-base.h"
2566e63ce3Schristos #include "hw-tree.h"
2666e63ce3Schristos 
2766e63ce3Schristos #include "sim-io.h"
2866e63ce3Schristos #include "sim-assert.h"
2966e63ce3Schristos 
3066e63ce3Schristos #ifdef HAVE_STDLIB_H
3166e63ce3Schristos #include <stdlib.h>
3266e63ce3Schristos #endif
3366e63ce3Schristos 
3466e63ce3Schristos #ifdef HAVE_STRING_H
3566e63ce3Schristos #include <string.h>
3666e63ce3Schristos #else
3766e63ce3Schristos #ifdef HAVE_STRINGS_H
3866e63ce3Schristos #include <strings.h>
3966e63ce3Schristos #endif
4066e63ce3Schristos #endif
4166e63ce3Schristos 
4266e63ce3Schristos #include <ctype.h>
4366e63ce3Schristos 
4466e63ce3Schristos /* manipulate/lookup device names */
4566e63ce3Schristos 
4666e63ce3Schristos typedef struct _name_specifier
4766e63ce3Schristos {
4866e63ce3Schristos 
4966e63ce3Schristos   /* components in the full length name */
5066e63ce3Schristos   char *path;
5166e63ce3Schristos   char *property;
5266e63ce3Schristos   char *value;
5366e63ce3Schristos 
5466e63ce3Schristos   /* current device */
5566e63ce3Schristos   char *family;
5666e63ce3Schristos   char *name;
5766e63ce3Schristos   char *unit;
5866e63ce3Schristos   char *args;
5966e63ce3Schristos 
6066e63ce3Schristos   /* previous device */
6166e63ce3Schristos   char *last_name;
6266e63ce3Schristos   char *last_family;
6366e63ce3Schristos   char *last_unit;
6466e63ce3Schristos   char *last_args;
6566e63ce3Schristos 
6666e63ce3Schristos   /* work area */
6766e63ce3Schristos   char buf[1024];
6866e63ce3Schristos 
6966e63ce3Schristos } name_specifier;
7066e63ce3Schristos 
7166e63ce3Schristos 
7266e63ce3Schristos 
7366e63ce3Schristos /* Given a device specifier, break it up into its main components:
7466e63ce3Schristos    path (and if present) property name and property value. */
7566e63ce3Schristos 
7666e63ce3Schristos static int
split_device_specifier(struct hw * current,const char * device_specifier,name_specifier * spec)7766e63ce3Schristos split_device_specifier (struct hw *current,
7866e63ce3Schristos 			const char *device_specifier,
7966e63ce3Schristos 			name_specifier *spec)
8066e63ce3Schristos {
8166e63ce3Schristos   char *chp = NULL;
8266e63ce3Schristos 
8366e63ce3Schristos   /* expand any leading alias if present */
8466e63ce3Schristos   if (current != NULL
8566e63ce3Schristos       && *device_specifier != '\0'
8666e63ce3Schristos       && *device_specifier != '.'
8766e63ce3Schristos       && *device_specifier != '/')
8866e63ce3Schristos     {
8966e63ce3Schristos       struct hw *aliases = hw_tree_find_device (current, "/aliases");
9066e63ce3Schristos       char alias[32];
9166e63ce3Schristos       int len = 0;
9266e63ce3Schristos       while (device_specifier[len] != '\0'
9366e63ce3Schristos 	     && device_specifier[len] != '/'
9466e63ce3Schristos 	     && device_specifier[len] != ':'
9566e63ce3Schristos 	     && !isspace (device_specifier[len]))
9666e63ce3Schristos 	{
9766e63ce3Schristos 	  alias[len] = device_specifier[len];
9866e63ce3Schristos 	  len++;
9966e63ce3Schristos 	  if (len >= sizeof (alias))
10066e63ce3Schristos 	    hw_abort (NULL, "split_device_specifier: buffer overflow");
10166e63ce3Schristos 	}
10266e63ce3Schristos       alias[len] = '\0';
10366e63ce3Schristos       if (aliases != NULL
10466e63ce3Schristos 	  && hw_find_property (aliases, alias))
10566e63ce3Schristos 	{
10666e63ce3Schristos 	  strcpy (spec->buf, hw_find_string_property (aliases, alias));
10766e63ce3Schristos 	  strcat (spec->buf, device_specifier + len);
10866e63ce3Schristos 	}
10966e63ce3Schristos       else
11066e63ce3Schristos 	{
11166e63ce3Schristos 	  strcpy (spec->buf, device_specifier);
11266e63ce3Schristos 	}
11366e63ce3Schristos     }
11466e63ce3Schristos   else
11566e63ce3Schristos     {
11666e63ce3Schristos       strcpy (spec->buf, device_specifier);
11766e63ce3Schristos     }
11866e63ce3Schristos 
11966e63ce3Schristos   /* check no overflow */
12066e63ce3Schristos   if (strlen (spec->buf) >= sizeof (spec->buf))
12166e63ce3Schristos     hw_abort (NULL, "split_device_specifier: buffer overflow\n");
12266e63ce3Schristos 
12366e63ce3Schristos   /* strip leading spaces */
12466e63ce3Schristos   chp = spec->buf;
12566e63ce3Schristos   while (*chp != '\0' && isspace (*chp))
12666e63ce3Schristos     chp++;
12766e63ce3Schristos   if (*chp == '\0')
12866e63ce3Schristos     return 0;
12966e63ce3Schristos 
13066e63ce3Schristos   /* find the path and terminate it with null */
13166e63ce3Schristos   spec->path = chp;
13266e63ce3Schristos   while (*chp != '\0' && !isspace (*chp))
13366e63ce3Schristos     chp++;
13466e63ce3Schristos   if (*chp != '\0')
13566e63ce3Schristos     {
13666e63ce3Schristos       *chp = '\0';
13766e63ce3Schristos       chp++;
13866e63ce3Schristos     }
13966e63ce3Schristos 
14066e63ce3Schristos   /* and any value */
14166e63ce3Schristos   while (*chp != '\0' && isspace (*chp))
14266e63ce3Schristos     chp++;
14366e63ce3Schristos   spec->value = chp;
14466e63ce3Schristos 
14566e63ce3Schristos   /* now go back and chop the property off of the path */
14666e63ce3Schristos   if (spec->value[0] == '\0')
14766e63ce3Schristos     {
14866e63ce3Schristos       spec->property = NULL; /*not a property*/
14966e63ce3Schristos       spec->value = NULL;
15066e63ce3Schristos     }
15166e63ce3Schristos   else if (spec->value[0] == '>'
15266e63ce3Schristos 	   || spec->value[0] == '<')
15366e63ce3Schristos     {
15466e63ce3Schristos       /* an interrupt spec */
15566e63ce3Schristos       spec->property = NULL;
15666e63ce3Schristos     }
15766e63ce3Schristos   else
15866e63ce3Schristos     {
15966e63ce3Schristos       chp = strrchr (spec->path, '/');
16066e63ce3Schristos       if (chp == NULL)
16166e63ce3Schristos 	{
16266e63ce3Schristos 	  spec->property = spec->path;
16366e63ce3Schristos 	  spec->path = strchr (spec->property, '\0');
16466e63ce3Schristos 	}
16566e63ce3Schristos       else
16666e63ce3Schristos 	{
16766e63ce3Schristos 	  *chp = '\0';
16866e63ce3Schristos 	  spec->property = chp+1;
16966e63ce3Schristos 	}
17066e63ce3Schristos     }
17166e63ce3Schristos 
17266e63ce3Schristos   /* and mark the rest as invalid */
17366e63ce3Schristos   spec->name = NULL;
17466e63ce3Schristos   spec->family = NULL;
17566e63ce3Schristos   spec->unit = NULL;
17666e63ce3Schristos   spec->args = NULL;
17766e63ce3Schristos   spec->last_name = NULL;
17866e63ce3Schristos   spec->last_family = NULL;
17966e63ce3Schristos   spec->last_unit = NULL;
18066e63ce3Schristos   spec->last_args = NULL;
18166e63ce3Schristos 
18266e63ce3Schristos   return 1;
18366e63ce3Schristos }
18466e63ce3Schristos 
18566e63ce3Schristos 
18666e63ce3Schristos /* given a device specifier break it up into its main components -
18766e63ce3Schristos    path and property name - assuming that the last `device' is a
18866e63ce3Schristos    property name. */
18966e63ce3Schristos 
19066e63ce3Schristos static int
split_property_specifier(struct hw * current,const char * property_specifier,name_specifier * spec)19166e63ce3Schristos split_property_specifier (struct hw *current,
19266e63ce3Schristos 			  const char *property_specifier,
19366e63ce3Schristos 			  name_specifier *spec)
19466e63ce3Schristos {
19566e63ce3Schristos   if (split_device_specifier (current, property_specifier, spec))
19666e63ce3Schristos     {
19766e63ce3Schristos       if (spec->property == NULL)
19866e63ce3Schristos 	{
19966e63ce3Schristos 	  /* force the last name to be a property name */
20066e63ce3Schristos 	  char *chp = strrchr (spec->path, '/');
20166e63ce3Schristos 	  if (chp == NULL)
20266e63ce3Schristos 	    {
20366e63ce3Schristos 	      spec->property = spec->path;
20466e63ce3Schristos 	      spec->path = strrchr (spec->property, '\0');;
20566e63ce3Schristos 	    }
20666e63ce3Schristos 	  else
20766e63ce3Schristos 	    {
20866e63ce3Schristos 	      *chp = '\0';
20966e63ce3Schristos 	      spec->property = chp + 1;
21066e63ce3Schristos 	    }
21166e63ce3Schristos 	}
21266e63ce3Schristos       return 1;
21366e63ce3Schristos     }
21466e63ce3Schristos   else
21566e63ce3Schristos     return 0;
21666e63ce3Schristos }
21766e63ce3Schristos 
21866e63ce3Schristos 
21966e63ce3Schristos /* device the next device name and split it up, return 0 when no more
22066e63ce3Schristos    names to struct hw */
22166e63ce3Schristos 
22266e63ce3Schristos static int
split_device_name(name_specifier * spec)22366e63ce3Schristos split_device_name (name_specifier *spec)
22466e63ce3Schristos {
22566e63ce3Schristos   char *chp;
22666e63ce3Schristos   /* remember what came before */
22766e63ce3Schristos   spec->last_name = spec->name;
22866e63ce3Schristos   spec->last_family = spec->family;
22966e63ce3Schristos   spec->last_unit = spec->unit;
23066e63ce3Schristos   spec->last_args = spec->args;
23166e63ce3Schristos   /* finished? */
23266e63ce3Schristos   if (spec->path[0] == '\0')
23366e63ce3Schristos     {
23466e63ce3Schristos       spec->name = NULL;
23566e63ce3Schristos       spec->family = NULL;
23666e63ce3Schristos       spec->unit = NULL;
23766e63ce3Schristos       spec->args = NULL;
23866e63ce3Schristos       return 0;
23966e63ce3Schristos     }
24066e63ce3Schristos   /* break the current device spec from the path */
24166e63ce3Schristos   spec->name = spec->path;
24266e63ce3Schristos   chp = strchr (spec->name, '/');
24366e63ce3Schristos   if (chp == NULL)
24466e63ce3Schristos     spec->path = strchr (spec->name, '\0');
24566e63ce3Schristos   else
24666e63ce3Schristos     {
24766e63ce3Schristos       spec->path = chp+1;
24866e63ce3Schristos       *chp = '\0';
24966e63ce3Schristos     }
25066e63ce3Schristos   /* break out the base */
25166e63ce3Schristos   if (spec->name[0] == '(')
25266e63ce3Schristos     {
25366e63ce3Schristos       chp = strchr (spec->name, ')');
25466e63ce3Schristos       if (chp == NULL)
25566e63ce3Schristos 	{
25666e63ce3Schristos 	  spec->family = spec->name;
25766e63ce3Schristos 	}
25866e63ce3Schristos       else
25966e63ce3Schristos 	{
26066e63ce3Schristos 	  *chp = '\0';
26166e63ce3Schristos 	  spec->family = spec->name + 1;
26266e63ce3Schristos 	  spec->name = chp + 1;
26366e63ce3Schristos 	}
26466e63ce3Schristos     }
26566e63ce3Schristos   else
26666e63ce3Schristos     {
26766e63ce3Schristos       spec->family = spec->name;
26866e63ce3Schristos     }
26966e63ce3Schristos   /* now break out the unit */
27066e63ce3Schristos   chp = strchr (spec->name, '@');
27166e63ce3Schristos   if (chp == NULL)
27266e63ce3Schristos     {
27366e63ce3Schristos       spec->unit = NULL;
27466e63ce3Schristos       chp = spec->name;
27566e63ce3Schristos     }
27666e63ce3Schristos   else
27766e63ce3Schristos     {
27866e63ce3Schristos       *chp = '\0';
27966e63ce3Schristos       chp += 1;
28066e63ce3Schristos       spec->unit = chp;
28166e63ce3Schristos     }
28266e63ce3Schristos   /* finally any args */
28366e63ce3Schristos   chp = strchr (chp, ':');
28466e63ce3Schristos   if (chp == NULL)
28566e63ce3Schristos     spec->args = NULL;
28666e63ce3Schristos   else
28766e63ce3Schristos     {
28866e63ce3Schristos       *chp = '\0';
28966e63ce3Schristos       spec->args = chp+1;
29066e63ce3Schristos     }
29166e63ce3Schristos   return 1;
29266e63ce3Schristos }
29366e63ce3Schristos 
29466e63ce3Schristos 
29566e63ce3Schristos /* device the value, returning the next non-space token */
29666e63ce3Schristos 
29766e63ce3Schristos static char *
split_value(name_specifier * spec)29866e63ce3Schristos split_value (name_specifier *spec)
29966e63ce3Schristos {
30066e63ce3Schristos   char *token;
30166e63ce3Schristos   if (spec->value == NULL)
30266e63ce3Schristos     return NULL;
30366e63ce3Schristos   /* skip leading white space */
30466e63ce3Schristos   while (isspace (spec->value[0]))
30566e63ce3Schristos     spec->value++;
30666e63ce3Schristos   if (spec->value[0] == '\0')
30766e63ce3Schristos     {
30866e63ce3Schristos       spec->value = NULL;
30966e63ce3Schristos       return NULL;
31066e63ce3Schristos     }
31166e63ce3Schristos   token = spec->value;
31266e63ce3Schristos   /* find trailing space */
31366e63ce3Schristos   while (spec->value[0] != '\0' && !isspace (spec->value[0]))
31466e63ce3Schristos     spec->value++;
31566e63ce3Schristos   /* chop this value out */
31666e63ce3Schristos   if (spec->value[0] != '\0')
31766e63ce3Schristos     {
31866e63ce3Schristos       spec->value[0] = '\0';
31966e63ce3Schristos       spec->value++;
32066e63ce3Schristos     }
32166e63ce3Schristos   return token;
32266e63ce3Schristos }
32366e63ce3Schristos 
32466e63ce3Schristos 
32566e63ce3Schristos 
32666e63ce3Schristos /* traverse the path specified by spec starting at current */
32766e63ce3Schristos 
32866e63ce3Schristos static struct hw *
split_find_device(struct hw * current,name_specifier * spec)32966e63ce3Schristos split_find_device (struct hw *current,
33066e63ce3Schristos 		   name_specifier *spec)
33166e63ce3Schristos {
33266e63ce3Schristos   /* strip off (and process) any leading ., .., ./ and / */
33366e63ce3Schristos   while (1)
33466e63ce3Schristos     {
33566e63ce3Schristos       if (strncmp (spec->path, "/", strlen ("/")) == 0)
33666e63ce3Schristos 	{
33766e63ce3Schristos 	  /* cd /... */
33866e63ce3Schristos 	  while (current != NULL && hw_parent (current) != NULL)
33966e63ce3Schristos 	    current = hw_parent (current);
34066e63ce3Schristos 	  spec->path += strlen ("/");
34166e63ce3Schristos 	}
34266e63ce3Schristos       else if (strncmp (spec->path, "./", strlen ("./")) == 0)
34366e63ce3Schristos 	{
34466e63ce3Schristos 	  /* cd ./... */
34566e63ce3Schristos 	  current = current;
34666e63ce3Schristos 	  spec->path += strlen ("./");
34766e63ce3Schristos 	}
34866e63ce3Schristos       else if (strncmp (spec->path, "../", strlen ("../")) == 0)
34966e63ce3Schristos 	{
35066e63ce3Schristos 	  /* cd ../... */
35166e63ce3Schristos 	  if (current != NULL && hw_parent (current) != NULL)
35266e63ce3Schristos 	    current = hw_parent (current);
35366e63ce3Schristos 	  spec->path += strlen ("../");
35466e63ce3Schristos 	}
35566e63ce3Schristos       else if (strcmp (spec->path, ".") == 0)
35666e63ce3Schristos 	{
35766e63ce3Schristos 	  /* cd . */
35866e63ce3Schristos 	  current = current;
35966e63ce3Schristos 	  spec->path += strlen (".");
36066e63ce3Schristos 	}
36166e63ce3Schristos       else if (strcmp (spec->path, "..") == 0)
36266e63ce3Schristos 	{
36366e63ce3Schristos 	  /* cd .. */
36466e63ce3Schristos 	  if (current != NULL && hw_parent (current) != NULL)
36566e63ce3Schristos 	    current = hw_parent (current);
36666e63ce3Schristos 	  spec->path += strlen ("..");
36766e63ce3Schristos 	}
36866e63ce3Schristos       else
36966e63ce3Schristos 	break;
37066e63ce3Schristos     }
37166e63ce3Schristos 
37266e63ce3Schristos   /* now go through the path proper */
37366e63ce3Schristos 
37466e63ce3Schristos   if (current == NULL)
37566e63ce3Schristos     {
37666e63ce3Schristos       split_device_name (spec);
37766e63ce3Schristos       return NULL;
37866e63ce3Schristos     }
37966e63ce3Schristos 
38066e63ce3Schristos   while (split_device_name (spec))
38166e63ce3Schristos     {
38266e63ce3Schristos       struct hw *child;
38366e63ce3Schristos       for (child = hw_child (current);
38466e63ce3Schristos 	   child != NULL; child = hw_sibling (child))
38566e63ce3Schristos 	{
38666e63ce3Schristos 	  if (strcmp (spec->name, hw_name (child)) == 0)
38766e63ce3Schristos 	    {
38866e63ce3Schristos 	      if (spec->unit == NULL)
38966e63ce3Schristos 		break;
39066e63ce3Schristos 	      else
39166e63ce3Schristos 		{
39266e63ce3Schristos 		  hw_unit phys;
39366e63ce3Schristos 		  hw_unit_decode (current, spec->unit, &phys);
39466e63ce3Schristos 		  if (memcmp (&phys, hw_unit_address (child),
39566e63ce3Schristos 			      sizeof (hw_unit)) == 0)
39666e63ce3Schristos 		    break;
39766e63ce3Schristos 		}
39866e63ce3Schristos 	    }
39966e63ce3Schristos 	}
40066e63ce3Schristos       if (child == NULL)
40166e63ce3Schristos 	return current; /* search failed */
40266e63ce3Schristos       current = child;
40366e63ce3Schristos     }
40466e63ce3Schristos 
40566e63ce3Schristos   return current;
40666e63ce3Schristos }
40766e63ce3Schristos 
40866e63ce3Schristos 
40966e63ce3Schristos static struct hw *
split_fill_path(struct hw * current,const char * device_specifier,name_specifier * spec)41066e63ce3Schristos split_fill_path (struct hw *current,
41166e63ce3Schristos 		 const char *device_specifier,
41266e63ce3Schristos 		 name_specifier *spec)
41366e63ce3Schristos {
41466e63ce3Schristos   /* break it up */
41566e63ce3Schristos   if (!split_device_specifier (current, device_specifier, spec))
41666e63ce3Schristos     hw_abort (current, "error parsing %s\n", device_specifier);
41766e63ce3Schristos 
41866e63ce3Schristos   /* fill our tree with its contents */
41966e63ce3Schristos   current = split_find_device (current, spec);
42066e63ce3Schristos 
42166e63ce3Schristos   /* add any additional devices as needed */
42266e63ce3Schristos   if (spec->name != NULL)
42366e63ce3Schristos     {
42466e63ce3Schristos       do
42566e63ce3Schristos 	{
42666e63ce3Schristos 	  if (current != NULL && !hw_finished_p (current))
42766e63ce3Schristos 	    hw_finish (current);
42866e63ce3Schristos 	  current = hw_create (NULL,
42966e63ce3Schristos 			       current,
43066e63ce3Schristos 			       spec->family,
43166e63ce3Schristos 			       spec->name,
43266e63ce3Schristos 			       spec->unit,
43366e63ce3Schristos 			       spec->args);
43466e63ce3Schristos 	}
43566e63ce3Schristos       while (split_device_name (spec));
43666e63ce3Schristos     }
43766e63ce3Schristos 
43866e63ce3Schristos   return current;
43966e63ce3Schristos }
44066e63ce3Schristos 
44166e63ce3Schristos 
44266e63ce3Schristos /* <non-white-space> */
44366e63ce3Schristos 
44466e63ce3Schristos static const char *
skip_token(const char * chp)44566e63ce3Schristos skip_token (const char *chp)
44666e63ce3Schristos {
44766e63ce3Schristos   while (!isspace (*chp) && *chp != '\0')
44866e63ce3Schristos     chp++;
44966e63ce3Schristos   while (isspace (*chp) && *chp != '\0')
45066e63ce3Schristos     chp++;
45166e63ce3Schristos   return chp;
45266e63ce3Schristos }
45366e63ce3Schristos 
45466e63ce3Schristos 
45566e63ce3Schristos /* count the number of entries */
45666e63ce3Schristos 
45766e63ce3Schristos static int
count_entries(struct hw * current,const char * property_name,const char * property_value,int modulo)45866e63ce3Schristos count_entries (struct hw *current,
45966e63ce3Schristos 	       const char *property_name,
46066e63ce3Schristos 	       const char *property_value,
46166e63ce3Schristos 	       int modulo)
46266e63ce3Schristos {
46366e63ce3Schristos   const char *chp = property_value;
46466e63ce3Schristos   int nr_entries = 0;
46566e63ce3Schristos   while (*chp != '\0')
46666e63ce3Schristos     {
46766e63ce3Schristos       nr_entries += 1;
46866e63ce3Schristos       chp = skip_token (chp);
46966e63ce3Schristos     }
47066e63ce3Schristos   if ((nr_entries % modulo) != 0)
47166e63ce3Schristos     {
47266e63ce3Schristos       hw_abort (current, "incorrect number of entries for %s property %s, should be multiple of %d",
47366e63ce3Schristos 		property_name, property_value, modulo);
47466e63ce3Schristos     }
47566e63ce3Schristos   return nr_entries / modulo;
47666e63ce3Schristos }
47766e63ce3Schristos 
47866e63ce3Schristos 
47966e63ce3Schristos 
48066e63ce3Schristos /* parse: <address> ::= <token> ; device dependant */
48166e63ce3Schristos 
48266e63ce3Schristos static const char *
parse_address(struct hw * current,struct hw * bus,const char * chp,hw_unit * address)48366e63ce3Schristos parse_address (struct hw *current,
48466e63ce3Schristos 	       struct hw *bus,
48566e63ce3Schristos 	       const char *chp,
48666e63ce3Schristos 	       hw_unit *address)
48766e63ce3Schristos {
48866e63ce3Schristos   if (hw_unit_decode (bus, chp, address) < 0)
48966e63ce3Schristos     hw_abort (current, "invalid unit address in %s", chp);
49066e63ce3Schristos   return skip_token (chp);
49166e63ce3Schristos }
49266e63ce3Schristos 
49366e63ce3Schristos 
49466e63ce3Schristos /* parse: <size> ::= <number> { "," <number> } ; */
49566e63ce3Schristos 
49666e63ce3Schristos static const char *
parse_size(struct hw * current,struct hw * bus,const char * chp,hw_unit * size)49766e63ce3Schristos parse_size (struct hw *current,
49866e63ce3Schristos 	    struct hw *bus,
49966e63ce3Schristos 	    const char *chp,
50066e63ce3Schristos 	    hw_unit *size)
50166e63ce3Schristos {
50266e63ce3Schristos   int i;
50366e63ce3Schristos   int nr;
50466e63ce3Schristos   const char *curr = chp;
50566e63ce3Schristos   memset (size, 0, sizeof (*size));
50666e63ce3Schristos   /* parse the numeric list */
50766e63ce3Schristos   size->nr_cells = hw_unit_nr_size_cells (bus);
50866e63ce3Schristos   nr = 0;
50966e63ce3Schristos   while (1)
51066e63ce3Schristos     {
51166e63ce3Schristos       char *next;
51266e63ce3Schristos       size->cells[nr] = strtoul (curr, &next, 0);
51366e63ce3Schristos       if (curr == next)
51466e63ce3Schristos 	hw_abort (current, "Problem parsing <size> %s", chp);
51566e63ce3Schristos       nr += 1;
51666e63ce3Schristos       if (next[0] != ',')
51766e63ce3Schristos 	break;
51866e63ce3Schristos       if (nr == size->nr_cells)
51966e63ce3Schristos 	hw_abort (current, "Too many values in <size> %s", chp);
52066e63ce3Schristos       curr = next + 1;
52166e63ce3Schristos     }
52266e63ce3Schristos   ASSERT (nr > 0 && nr <= size->nr_cells);
52366e63ce3Schristos   /* right align the numbers */
52466e63ce3Schristos   for (i = 1; i <= size->nr_cells; i++)
52566e63ce3Schristos     {
52666e63ce3Schristos       if (i <= nr)
52766e63ce3Schristos 	size->cells[size->nr_cells - i] = size->cells[nr - i];
52866e63ce3Schristos       else
52966e63ce3Schristos 	size->cells[size->nr_cells - i] = 0;
53066e63ce3Schristos     }
53166e63ce3Schristos   return skip_token (chp);
53266e63ce3Schristos }
53366e63ce3Schristos 
53466e63ce3Schristos 
53566e63ce3Schristos /* parse: <reg> ::= { <address> <size> } ; */
53666e63ce3Schristos 
53766e63ce3Schristos static void
parse_reg_property(struct hw * current,const char * property_name,const char * property_value)53866e63ce3Schristos parse_reg_property (struct hw *current,
53966e63ce3Schristos 		    const char *property_name,
54066e63ce3Schristos 		    const char *property_value)
54166e63ce3Schristos {
54266e63ce3Schristos   int nr_regs;
54366e63ce3Schristos   int reg_nr;
54466e63ce3Schristos   reg_property_spec *regs;
54566e63ce3Schristos   const char *chp;
54666e63ce3Schristos 
54766e63ce3Schristos   /* determine the number of reg entries by counting tokens */
54866e63ce3Schristos   nr_regs = count_entries (current, property_name, property_value, 2);
54966e63ce3Schristos 
55066e63ce3Schristos   /* create working space */
55166e63ce3Schristos   regs = zalloc (nr_regs * sizeof (*regs));
55266e63ce3Schristos 
55366e63ce3Schristos   /* fill it in */
55466e63ce3Schristos   chp = property_value;
55566e63ce3Schristos   for (reg_nr = 0; reg_nr < nr_regs; reg_nr++)
55666e63ce3Schristos     {
55766e63ce3Schristos       chp = parse_address (current, hw_parent (current),
55866e63ce3Schristos 			   chp, &regs[reg_nr].address);
55966e63ce3Schristos       chp = parse_size (current, hw_parent (current),
56066e63ce3Schristos 			chp, &regs[reg_nr].size);
56166e63ce3Schristos     }
56266e63ce3Schristos 
56366e63ce3Schristos   /* create it */
56466e63ce3Schristos   hw_add_reg_array_property (current, property_name,
56566e63ce3Schristos 			     regs, nr_regs);
56666e63ce3Schristos 
56766e63ce3Schristos   free (regs);
56866e63ce3Schristos }
56966e63ce3Schristos 
57066e63ce3Schristos 
57166e63ce3Schristos /* { <child-address> <parent-address> <child-size> }* */
57266e63ce3Schristos 
57366e63ce3Schristos static void
parse_ranges_property(struct hw * current,const char * property_name,const char * property_value)57466e63ce3Schristos parse_ranges_property (struct hw *current,
57566e63ce3Schristos 		       const char *property_name,
57666e63ce3Schristos 		       const char *property_value)
57766e63ce3Schristos {
57866e63ce3Schristos   int nr_ranges;
57966e63ce3Schristos   int range_nr;
58066e63ce3Schristos   range_property_spec *ranges;
58166e63ce3Schristos   const char *chp;
58266e63ce3Schristos 
58366e63ce3Schristos   /* determine the number of ranges specified */
58466e63ce3Schristos   nr_ranges = count_entries (current, property_name, property_value, 3);
58566e63ce3Schristos 
58666e63ce3Schristos   /* create a property of that size */
58766e63ce3Schristos   ranges = zalloc (nr_ranges * sizeof (*ranges));
58866e63ce3Schristos 
58966e63ce3Schristos   /* fill it in */
59066e63ce3Schristos   chp = property_value;
59166e63ce3Schristos   for (range_nr = 0; range_nr < nr_ranges; range_nr++)
59266e63ce3Schristos     {
59366e63ce3Schristos       chp = parse_address (current, current,
59466e63ce3Schristos 			   chp, &ranges[range_nr].child_address);
59566e63ce3Schristos       chp = parse_address (current, hw_parent (current),
59666e63ce3Schristos 			   chp, &ranges[range_nr].parent_address);
59766e63ce3Schristos       chp = parse_size (current, current,
59866e63ce3Schristos 			chp, &ranges[range_nr].size);
59966e63ce3Schristos     }
60066e63ce3Schristos 
60166e63ce3Schristos   /* create it */
60266e63ce3Schristos   hw_add_range_array_property (current, property_name, ranges, nr_ranges);
60366e63ce3Schristos 
60466e63ce3Schristos   free (ranges);
60566e63ce3Schristos }
60666e63ce3Schristos 
60766e63ce3Schristos 
60866e63ce3Schristos /* <integer> ... */
60966e63ce3Schristos 
61066e63ce3Schristos static void
parse_integer_property(struct hw * current,const char * property_name,const char * property_value)61166e63ce3Schristos parse_integer_property (struct hw *current,
61266e63ce3Schristos 			const char *property_name,
61366e63ce3Schristos 			const char *property_value)
61466e63ce3Schristos {
61566e63ce3Schristos   int nr_entries;
61666e63ce3Schristos   unsigned_cell words[1024];
61766e63ce3Schristos   /* integer or integer array? */
61866e63ce3Schristos   nr_entries = 0;
61966e63ce3Schristos   while (1)
62066e63ce3Schristos     {
62166e63ce3Schristos       char *end;
62266e63ce3Schristos       words[nr_entries] = strtoul (property_value, &end, 0);
62366e63ce3Schristos       if (property_value == end)
62466e63ce3Schristos 	break;
62566e63ce3Schristos       nr_entries += 1;
62666e63ce3Schristos       if (nr_entries * sizeof (words[0]) >= sizeof (words))
62766e63ce3Schristos 	hw_abort (current, "buffer overflow");
62866e63ce3Schristos       property_value = end;
62966e63ce3Schristos     }
63066e63ce3Schristos   if (nr_entries == 0)
63166e63ce3Schristos     hw_abort (current, "error parsing integer property %s (%s)",
63266e63ce3Schristos 	      property_name, property_value);
63366e63ce3Schristos   else if (nr_entries == 1)
63466e63ce3Schristos     hw_add_integer_property (current, property_name, words[0]);
63566e63ce3Schristos   else
63666e63ce3Schristos     {
63766e63ce3Schristos       int i;
63866e63ce3Schristos       for (i = 0; i < nr_entries; i++)
63966e63ce3Schristos 	{
64066e63ce3Schristos 	  H2BE (words[i]);
64166e63ce3Schristos 	}
64266e63ce3Schristos       /* perhaps integer array property is better */
64366e63ce3Schristos       hw_add_array_property (current, property_name, words,
64466e63ce3Schristos 			     sizeof (words[0]) * nr_entries);
64566e63ce3Schristos     }
64666e63ce3Schristos }
64766e63ce3Schristos 
64866e63ce3Schristos 
64966e63ce3Schristos /* <string> ... */
65066e63ce3Schristos 
65166e63ce3Schristos static void
parse_string_property(struct hw * current,const char * property_name,const char * property_value)65266e63ce3Schristos parse_string_property (struct hw *current,
65366e63ce3Schristos 		       const char *property_name,
65466e63ce3Schristos 		       const char *property_value)
65566e63ce3Schristos {
65666e63ce3Schristos   char **strings;
65766e63ce3Schristos   const char *chp;
65866e63ce3Schristos   int nr_strings;
65966e63ce3Schristos   int approx_nr_strings;
66066e63ce3Schristos 
66166e63ce3Schristos   /* get an estimate as to the number of strings by counting double
66266e63ce3Schristos      quotes */
66366e63ce3Schristos   approx_nr_strings = 2;
66466e63ce3Schristos   for (chp = property_value; *chp; chp++)
66566e63ce3Schristos     {
66666e63ce3Schristos       if (*chp == '"')
66766e63ce3Schristos 	approx_nr_strings++;
66866e63ce3Schristos     }
66966e63ce3Schristos   approx_nr_strings = (approx_nr_strings) / 2;
67066e63ce3Schristos 
67166e63ce3Schristos   /* create a string buffer for that many (plus a null) */
67266e63ce3Schristos   strings = (char**) zalloc ((approx_nr_strings + 1) * sizeof (char*));
67366e63ce3Schristos 
67466e63ce3Schristos   /* now find all the strings */
67566e63ce3Schristos   chp = property_value;
67666e63ce3Schristos   nr_strings = 0;
67766e63ce3Schristos   while (1)
67866e63ce3Schristos     {
67966e63ce3Schristos 
68066e63ce3Schristos       /* skip leading space */
68166e63ce3Schristos       while (*chp != '\0' && isspace (*chp))
68266e63ce3Schristos 	chp += 1;
68366e63ce3Schristos       if (*chp == '\0')
68466e63ce3Schristos 	break;
68566e63ce3Schristos 
68666e63ce3Schristos       /* copy it in */
68766e63ce3Schristos       if (*chp == '"')
68866e63ce3Schristos 	{
68966e63ce3Schristos 	  /* a quoted string - watch for '\' et al. */
69066e63ce3Schristos 	  /* estimate the size and allocate space for it */
69166e63ce3Schristos 	  int pos;
69266e63ce3Schristos 	  chp++;
69366e63ce3Schristos 	  pos = 0;
69466e63ce3Schristos 	  while (chp[pos] != '\0' && chp[pos] != '"')
69566e63ce3Schristos 	    {
69666e63ce3Schristos 	      if (chp[pos] == '\\' && chp[pos+1] != '\0')
69766e63ce3Schristos 		pos += 2;
69866e63ce3Schristos 	      else
69966e63ce3Schristos 		pos += 1;
70066e63ce3Schristos 	    }
70166e63ce3Schristos 	  strings[nr_strings] = zalloc (pos + 1);
70266e63ce3Schristos 	  /* copy the string over */
70366e63ce3Schristos 	  pos = 0;
70466e63ce3Schristos 	  while (*chp != '\0' && *chp != '"')
70566e63ce3Schristos 	    {
70666e63ce3Schristos 	      if (*chp == '\\' && *(chp+1) != '\0')
70766e63ce3Schristos 		{
70866e63ce3Schristos 		  strings[nr_strings][pos] = *(chp+1);
70966e63ce3Schristos 		  chp += 2;
71066e63ce3Schristos 		  pos++;
71166e63ce3Schristos 		}
71266e63ce3Schristos 	      else
71366e63ce3Schristos 		{
71466e63ce3Schristos 		  strings[nr_strings][pos] = *chp;
71566e63ce3Schristos 		  chp += 1;
71666e63ce3Schristos 		  pos++;
71766e63ce3Schristos 		}
71866e63ce3Schristos 	    }
71966e63ce3Schristos 	  if (*chp != '\0')
72066e63ce3Schristos 	    chp++;
72166e63ce3Schristos 	  strings[nr_strings][pos] = '\0';
72266e63ce3Schristos 	}
72366e63ce3Schristos       else
72466e63ce3Schristos 	{
72566e63ce3Schristos 	  /* copy over a single unquoted token */
72666e63ce3Schristos 	  int len = 0;
72766e63ce3Schristos 	  while (chp[len] != '\0' && !isspace (chp[len]))
72866e63ce3Schristos 	    len++;
72966e63ce3Schristos 	  strings[nr_strings] = zalloc (len + 1);
73066e63ce3Schristos 	  strncpy (strings[nr_strings], chp, len);
73166e63ce3Schristos 	  strings[nr_strings][len] = '\0';
73266e63ce3Schristos 	  chp += len;
73366e63ce3Schristos 	}
73466e63ce3Schristos       nr_strings++;
73566e63ce3Schristos       if (nr_strings > approx_nr_strings)
73666e63ce3Schristos 	hw_abort (current, "String property %s badly formatted",
73766e63ce3Schristos 		  property_name);
73866e63ce3Schristos     }
73966e63ce3Schristos   ASSERT (strings[nr_strings] == NULL); /* from zalloc */
74066e63ce3Schristos 
74166e63ce3Schristos   /* install it */
74266e63ce3Schristos   if (nr_strings == 0)
74366e63ce3Schristos     hw_add_string_property (current, property_name, "");
74466e63ce3Schristos   else if (nr_strings == 1)
74566e63ce3Schristos     hw_add_string_property (current, property_name, strings[0]);
74666e63ce3Schristos   else
74766e63ce3Schristos     {
74866e63ce3Schristos       const char **specs = (const char**) strings; /* stop a bogus error */
74966e63ce3Schristos       hw_add_string_array_property (current, property_name,
75066e63ce3Schristos 				    specs, nr_strings);
75166e63ce3Schristos     }
75266e63ce3Schristos 
75366e63ce3Schristos   /* flush the created string */
75466e63ce3Schristos   while (nr_strings > 0)
75566e63ce3Schristos     {
75666e63ce3Schristos       nr_strings--;
75766e63ce3Schristos       free (strings[nr_strings]);
75866e63ce3Schristos     }
75966e63ce3Schristos   free (strings);
76066e63ce3Schristos }
76166e63ce3Schristos 
76266e63ce3Schristos 
76366e63ce3Schristos /* <path-to-ihandle-device> */
76466e63ce3Schristos 
76566e63ce3Schristos #if NOT_YET
76666e63ce3Schristos static void
parse_ihandle_property(struct hw * current,const char * property,const char * value)76766e63ce3Schristos parse_ihandle_property (struct hw *current,
76866e63ce3Schristos 			const char *property,
76966e63ce3Schristos 			const char *value)
77066e63ce3Schristos {
77166e63ce3Schristos   ihandle_runtime_property_spec ihandle;
77266e63ce3Schristos 
77366e63ce3Schristos   /* pass the full path */
77466e63ce3Schristos   ihandle.full_path = value;
77566e63ce3Schristos 
77666e63ce3Schristos   /* save this ready for the ihandle create */
77766e63ce3Schristos   hw_add_ihandle_runtime_property (current, property,
77866e63ce3Schristos 				   &ihandle);
77966e63ce3Schristos }
78066e63ce3Schristos #endif
78166e63ce3Schristos 
78266e63ce3Schristos 
78366e63ce3Schristos struct hw *
hw_tree_create(SIM_DESC sd,const char * family)78466e63ce3Schristos hw_tree_create (SIM_DESC sd,
78566e63ce3Schristos 		const char *family)
78666e63ce3Schristos {
78766e63ce3Schristos   return hw_create (sd, NULL, family, family, NULL, NULL);
78866e63ce3Schristos }
78966e63ce3Schristos 
79066e63ce3Schristos void
hw_tree_delete(struct hw * me)79166e63ce3Schristos hw_tree_delete (struct hw *me)
79266e63ce3Schristos {
79366e63ce3Schristos   /* Need to allow devices to disapear under our feet */
79466e63ce3Schristos   while (hw_child (me) != NULL)
79566e63ce3Schristos     {
79666e63ce3Schristos       hw_tree_delete (hw_child (me));
79766e63ce3Schristos     }
79866e63ce3Schristos   hw_delete (me);
79966e63ce3Schristos }
80066e63ce3Schristos 
80166e63ce3Schristos 
80266e63ce3Schristos struct hw *
hw_tree_parse(struct hw * current,const char * fmt,...)80366e63ce3Schristos hw_tree_parse (struct hw *current,
80466e63ce3Schristos 	       const char *fmt,
80566e63ce3Schristos 	       ...)
80666e63ce3Schristos {
80766e63ce3Schristos     va_list ap;
80866e63ce3Schristos     va_start (ap, fmt);
80966e63ce3Schristos     current = hw_tree_vparse (current, fmt, ap);
81066e63ce3Schristos     va_end (ap);
81166e63ce3Schristos     return current;
81266e63ce3Schristos }
81366e63ce3Schristos 
81466e63ce3Schristos struct hw *
hw_tree_vparse(struct hw * current,const char * fmt,va_list ap)81566e63ce3Schristos hw_tree_vparse (struct hw *current,
81666e63ce3Schristos 		const char *fmt,
81766e63ce3Schristos 		va_list ap)
81866e63ce3Schristos {
81966e63ce3Schristos   char device_specifier[1024];
82066e63ce3Schristos   name_specifier spec;
82166e63ce3Schristos 
82266e63ce3Schristos   /* format the path */
82366e63ce3Schristos   vsprintf (device_specifier, fmt, ap);
82466e63ce3Schristos   if (strlen (device_specifier) >= sizeof (device_specifier))
82566e63ce3Schristos     hw_abort (NULL, "device_tree_add_deviced: buffer overflow\n");
82666e63ce3Schristos 
82766e63ce3Schristos   /* construct the tree down to the final struct hw */
82866e63ce3Schristos   current = split_fill_path (current, device_specifier, &spec);
82966e63ce3Schristos 
83066e63ce3Schristos   /* is there an interrupt spec */
83166e63ce3Schristos   if (spec.property == NULL
83266e63ce3Schristos       && spec.value != NULL)
83366e63ce3Schristos     {
83466e63ce3Schristos       char *op = split_value (&spec);
83566e63ce3Schristos       switch (op[0])
83666e63ce3Schristos 	{
83766e63ce3Schristos 	case '>':
83866e63ce3Schristos 	  {
83966e63ce3Schristos 	    char *my_port_name = split_value (&spec);
84066e63ce3Schristos 	    int my_port;
84166e63ce3Schristos 	    char *dest_port_name = split_value (&spec);
84266e63ce3Schristos 	    int dest_port;
84366e63ce3Schristos 	    name_specifier dest_spec;
84466e63ce3Schristos 	    char *dest_hw_name = split_value (&spec);
84566e63ce3Schristos 	    struct hw *dest;
84666e63ce3Schristos 	    /* find my name */
84766e63ce3Schristos 	    if (!hw_finished_p (current))
84866e63ce3Schristos 	      hw_finish (current);
84966e63ce3Schristos 	    my_port = hw_port_decode (current, my_port_name, output_port);
85066e63ce3Schristos 	    /* find the dest device and port */
85166e63ce3Schristos 	    dest = split_fill_path (current, dest_hw_name, &dest_spec);
85266e63ce3Schristos 	    if (!hw_finished_p (dest))
85366e63ce3Schristos 	      hw_finish (dest);
85466e63ce3Schristos 	    dest_port = hw_port_decode (dest, dest_port_name,
85566e63ce3Schristos 					input_port);
85666e63ce3Schristos 	    /* connect the two */
85766e63ce3Schristos 	    hw_port_attach (current,
85866e63ce3Schristos 			    my_port,
85966e63ce3Schristos 			    dest,
86066e63ce3Schristos 			    dest_port,
86166e63ce3Schristos 			    permenant_object);
86266e63ce3Schristos 	    break;
86366e63ce3Schristos 	  }
86466e63ce3Schristos 	default:
86566e63ce3Schristos 	  hw_abort (current, "unreconised interrupt spec %s\n", spec.value);
86666e63ce3Schristos 	  break;
86766e63ce3Schristos 	}
86866e63ce3Schristos     }
86966e63ce3Schristos 
87066e63ce3Schristos   /* is there a property */
87166e63ce3Schristos   if (spec.property != NULL)
87266e63ce3Schristos     {
87366e63ce3Schristos       if (strcmp (spec.value, "true") == 0)
87466e63ce3Schristos 	hw_add_boolean_property (current, spec.property, 1);
87566e63ce3Schristos       else if (strcmp (spec.value, "false") == 0)
87666e63ce3Schristos 	hw_add_boolean_property (current, spec.property, 0);
87766e63ce3Schristos       else
87866e63ce3Schristos 	{
87966e63ce3Schristos 	  const struct hw_property *property;
88066e63ce3Schristos 	  switch (spec.value[0])
88166e63ce3Schristos 	    {
88266e63ce3Schristos #if NOT_YET
88366e63ce3Schristos 	    case '*':
88466e63ce3Schristos 	      {
88566e63ce3Schristos 		parse_ihandle_property (current, spec.property, spec.value + 1);
88666e63ce3Schristos 		break;
88766e63ce3Schristos 	      }
88866e63ce3Schristos #endif
88966e63ce3Schristos 	    case '[':
89066e63ce3Schristos 	      {
89166e63ce3Schristos 		unsigned8 words[1024];
89266e63ce3Schristos 		char *curr = spec.value + 1;
89366e63ce3Schristos 		int nr_words = 0;
89466e63ce3Schristos 		while (1)
89566e63ce3Schristos 		  {
89666e63ce3Schristos 		    char *next;
89766e63ce3Schristos 		    words[nr_words] = H2BE_1 (strtoul (curr, &next, 0));
89866e63ce3Schristos 		    if (curr == next)
89966e63ce3Schristos 		      break;
90066e63ce3Schristos 		    curr = next;
90166e63ce3Schristos 		    nr_words += 1;
90266e63ce3Schristos 		  }
90366e63ce3Schristos 		hw_add_array_property (current, spec.property,
90466e63ce3Schristos 				       words, sizeof (words[0]) * nr_words);
90566e63ce3Schristos 		break;
90666e63ce3Schristos 	      }
90766e63ce3Schristos 	    case '"':
90866e63ce3Schristos 	      {
90966e63ce3Schristos 		parse_string_property (current, spec.property, spec.value);
91066e63ce3Schristos 		break;
91166e63ce3Schristos 	      }
91266e63ce3Schristos 	    case '!':
91366e63ce3Schristos 	      {
91466e63ce3Schristos 		spec.value++;
91566e63ce3Schristos 		property = hw_tree_find_property (current, spec.value);
91666e63ce3Schristos 		if (property == NULL)
91766e63ce3Schristos 		  hw_abort (current, "property %s not found\n", spec.value);
91866e63ce3Schristos 		hw_add_duplicate_property (current,
91966e63ce3Schristos 					   spec.property,
92066e63ce3Schristos 					   property);
92166e63ce3Schristos 		break;
92266e63ce3Schristos 	      }
92366e63ce3Schristos 	    default:
92466e63ce3Schristos 	      {
92566e63ce3Schristos 		if (strcmp (spec.property, "reg") == 0
92666e63ce3Schristos 		    || strcmp (spec.property, "assigned-addresses") == 0
92766e63ce3Schristos 		    || strcmp (spec.property, "alternate-reg") == 0)
92866e63ce3Schristos 		  {
92966e63ce3Schristos 		    parse_reg_property (current, spec.property, spec.value);
93066e63ce3Schristos 		  }
93166e63ce3Schristos 		else if (strcmp (spec.property, "ranges") == 0)
93266e63ce3Schristos 		  {
93366e63ce3Schristos 		    parse_ranges_property (current, spec.property, spec.value);
93466e63ce3Schristos 		  }
93566e63ce3Schristos 		else if (isdigit (spec.value[0])
93666e63ce3Schristos 			 || (spec.value[0] == '-' && isdigit (spec.value[1]))
93766e63ce3Schristos 			 || (spec.value[0] == '+' && isdigit (spec.value[1])))
93866e63ce3Schristos 		  {
93966e63ce3Schristos 		    parse_integer_property (current, spec.property, spec.value);
94066e63ce3Schristos 		  }
94166e63ce3Schristos 		else
94266e63ce3Schristos 		  parse_string_property (current, spec.property, spec.value);
94366e63ce3Schristos 		break;
94466e63ce3Schristos 	      }
94566e63ce3Schristos 	    }
94666e63ce3Schristos 	}
94766e63ce3Schristos     }
94866e63ce3Schristos   return current;
94966e63ce3Schristos }
95066e63ce3Schristos 
95166e63ce3Schristos 
95266e63ce3Schristos static void
finish_hw_tree(struct hw * me,void * data)95366e63ce3Schristos finish_hw_tree (struct hw *me,
95466e63ce3Schristos 		void *data)
95566e63ce3Schristos {
95666e63ce3Schristos   if (!hw_finished_p (me))
95766e63ce3Schristos     hw_finish (me);
95866e63ce3Schristos }
95966e63ce3Schristos 
96066e63ce3Schristos void
hw_tree_finish(struct hw * root)96166e63ce3Schristos hw_tree_finish (struct hw *root)
96266e63ce3Schristos {
96366e63ce3Schristos   hw_tree_traverse (root, finish_hw_tree, NULL, NULL);
96466e63ce3Schristos }
96566e63ce3Schristos 
96666e63ce3Schristos 
96766e63ce3Schristos 
96866e63ce3Schristos void
hw_tree_traverse(struct hw * root,hw_tree_traverse_function * prefix,hw_tree_traverse_function * postfix,void * data)96966e63ce3Schristos hw_tree_traverse (struct hw *root,
97066e63ce3Schristos 		  hw_tree_traverse_function *prefix,
97166e63ce3Schristos 		  hw_tree_traverse_function *postfix,
97266e63ce3Schristos 		  void *data)
97366e63ce3Schristos {
97466e63ce3Schristos   struct hw *child;
97566e63ce3Schristos   if (prefix != NULL)
97666e63ce3Schristos     prefix (root, data);
97766e63ce3Schristos   for (child = hw_child (root);
97866e63ce3Schristos        child != NULL;
97966e63ce3Schristos        child = hw_sibling (child))
98066e63ce3Schristos     {
98166e63ce3Schristos       hw_tree_traverse (child, prefix, postfix, data);
98266e63ce3Schristos     }
98366e63ce3Schristos   if (postfix != NULL)
98466e63ce3Schristos     postfix (root, data);
98566e63ce3Schristos }
98666e63ce3Schristos 
98766e63ce3Schristos 
98866e63ce3Schristos 
98966e63ce3Schristos struct printer
99066e63ce3Schristos {
99166e63ce3Schristos   hw_tree_print_callback *print;
99266e63ce3Schristos   void *file;
99366e63ce3Schristos };
99466e63ce3Schristos 
99566e63ce3Schristos static void
print_address(struct hw * bus,const hw_unit * phys,struct printer * p)99666e63ce3Schristos print_address (struct hw *bus,
99766e63ce3Schristos 	       const hw_unit *phys,
99866e63ce3Schristos 	       struct printer *p)
99966e63ce3Schristos {
100066e63ce3Schristos   char unit[32];
100166e63ce3Schristos   hw_unit_encode (bus, phys, unit, sizeof (unit));
100266e63ce3Schristos   p->print (p->file, " %s", unit);
100366e63ce3Schristos }
100466e63ce3Schristos 
100566e63ce3Schristos static void
print_size(struct hw * bus,const hw_unit * size,struct printer * p)100666e63ce3Schristos print_size (struct hw *bus,
100766e63ce3Schristos 	    const hw_unit *size,
100866e63ce3Schristos 	    struct printer *p)
100966e63ce3Schristos {
101066e63ce3Schristos   int i;
101166e63ce3Schristos   for (i = 0; i < size->nr_cells; i++)
101266e63ce3Schristos     if (size->cells[i] != 0)
101366e63ce3Schristos       break;
101466e63ce3Schristos   if (i < size->nr_cells)
101566e63ce3Schristos     {
101666e63ce3Schristos       p->print (p->file, " 0x%lx", (unsigned long) size->cells[i]);
101766e63ce3Schristos       i++;
101866e63ce3Schristos       for (; i < size->nr_cells; i++)
101966e63ce3Schristos 	p->print (p->file, ",0x%lx", (unsigned long) size->cells[i]);
102066e63ce3Schristos     }
102166e63ce3Schristos   else
102266e63ce3Schristos     p->print (p->file, " 0");
102366e63ce3Schristos }
102466e63ce3Schristos 
102566e63ce3Schristos static void
print_reg_property(struct hw * me,const struct hw_property * property,struct printer * p)102666e63ce3Schristos print_reg_property (struct hw *me,
102766e63ce3Schristos 		    const struct hw_property *property,
102866e63ce3Schristos 		    struct printer *p)
102966e63ce3Schristos {
103066e63ce3Schristos   int reg_nr;
103166e63ce3Schristos   reg_property_spec reg;
103266e63ce3Schristos   for (reg_nr = 0;
103366e63ce3Schristos        hw_find_reg_array_property (me, property->name, reg_nr, &reg);
103466e63ce3Schristos        reg_nr++)
103566e63ce3Schristos     {
103666e63ce3Schristos       print_address (hw_parent (me), &reg.address, p);
103766e63ce3Schristos       print_size (me, &reg.size, p);
103866e63ce3Schristos     }
103966e63ce3Schristos }
104066e63ce3Schristos 
104166e63ce3Schristos static void
print_ranges_property(struct hw * me,const struct hw_property * property,struct printer * p)104266e63ce3Schristos print_ranges_property (struct hw *me,
104366e63ce3Schristos 		       const struct hw_property *property,
104466e63ce3Schristos 		       struct printer *p)
104566e63ce3Schristos {
104666e63ce3Schristos   int range_nr;
104766e63ce3Schristos   range_property_spec range;
104866e63ce3Schristos   for (range_nr = 0;
104966e63ce3Schristos        hw_find_range_array_property (me, property->name, range_nr, &range);
105066e63ce3Schristos        range_nr++)
105166e63ce3Schristos     {
105266e63ce3Schristos       print_address (me, &range.child_address, p);
105366e63ce3Schristos       print_address (hw_parent (me), &range.parent_address, p);
105466e63ce3Schristos       print_size (me, &range.size, p);
105566e63ce3Schristos     }
105666e63ce3Schristos }
105766e63ce3Schristos 
105866e63ce3Schristos static void
print_string(struct hw * me,const char * string,struct printer * p)105966e63ce3Schristos print_string (struct hw *me,
106066e63ce3Schristos 	      const char *string,
106166e63ce3Schristos 	      struct printer *p)
106266e63ce3Schristos {
106366e63ce3Schristos   p->print (p->file, " \"");
106466e63ce3Schristos   while (*string != '\0')
106566e63ce3Schristos     {
106666e63ce3Schristos       switch (*string)
106766e63ce3Schristos 	{
106866e63ce3Schristos 	case '"':
106966e63ce3Schristos 	  p->print (p->file, "\\\"");
107066e63ce3Schristos 	  break;
107166e63ce3Schristos 	case '\\':
107266e63ce3Schristos 	  p->print (p->file, "\\\\");
107366e63ce3Schristos 	  break;
107466e63ce3Schristos 	default:
107566e63ce3Schristos 	  p->print (p->file, "%c", *string);
107666e63ce3Schristos 	  break;
107766e63ce3Schristos 	}
107866e63ce3Schristos       string++;
107966e63ce3Schristos     }
108066e63ce3Schristos   p->print (p->file, "\"");
108166e63ce3Schristos }
108266e63ce3Schristos 
108366e63ce3Schristos static void
print_string_array_property(struct hw * me,const struct hw_property * property,struct printer * p)108466e63ce3Schristos print_string_array_property (struct hw *me,
108566e63ce3Schristos 			     const struct hw_property *property,
108666e63ce3Schristos 			     struct printer *p)
108766e63ce3Schristos {
108866e63ce3Schristos   int nr;
108966e63ce3Schristos   string_property_spec string;
109066e63ce3Schristos   for (nr = 0;
109166e63ce3Schristos        hw_find_string_array_property (me, property->name, nr, &string);
109266e63ce3Schristos        nr++)
109366e63ce3Schristos     {
109466e63ce3Schristos       print_string (me, string, p);
109566e63ce3Schristos     }
109666e63ce3Schristos }
109766e63ce3Schristos 
109866e63ce3Schristos static void
print_properties(struct hw * me,struct printer * p)109966e63ce3Schristos print_properties (struct hw *me,
110066e63ce3Schristos 		  struct printer *p)
110166e63ce3Schristos {
110266e63ce3Schristos   const struct hw_property *property;
110366e63ce3Schristos   for (property = hw_find_property (me, NULL);
110466e63ce3Schristos        property != NULL;
110566e63ce3Schristos        property = hw_next_property (property))
110666e63ce3Schristos     {
110766e63ce3Schristos       if (hw_parent (me) == NULL)
110866e63ce3Schristos 	p->print (p->file, "/%s", property->name);
110966e63ce3Schristos       else
111066e63ce3Schristos 	p->print (p->file, "%s/%s", hw_path (me), property->name);
111166e63ce3Schristos       if (property->original != NULL)
111266e63ce3Schristos 	{
111366e63ce3Schristos 	  p->print (p->file, " !");
111466e63ce3Schristos 	  p->print (p->file, "%s/%s",
111566e63ce3Schristos 		     hw_path (property->original->owner),
111666e63ce3Schristos 		     property->original->name);
111766e63ce3Schristos 	}
111866e63ce3Schristos       else
111966e63ce3Schristos 	{
112066e63ce3Schristos 	  switch (property->type)
112166e63ce3Schristos 	    {
112266e63ce3Schristos 	    case array_property:
112366e63ce3Schristos 	      {
112466e63ce3Schristos 		if ((property->sizeof_array % sizeof (signed_cell)) == 0)
112566e63ce3Schristos 		  {
112666e63ce3Schristos 		    unsigned_cell *w = (unsigned_cell*) property->array;
112766e63ce3Schristos 		    int cell_nr;
112866e63ce3Schristos 		    for (cell_nr = 0;
112966e63ce3Schristos 			 cell_nr < (property->sizeof_array / sizeof (unsigned_cell));
113066e63ce3Schristos 			 cell_nr++)
113166e63ce3Schristos 		      {
113266e63ce3Schristos 			p->print (p->file, " 0x%lx", (unsigned long) BE2H_cell (w[cell_nr]));
113366e63ce3Schristos 		      }
113466e63ce3Schristos 		  }
113566e63ce3Schristos 		else
113666e63ce3Schristos 		  {
113766e63ce3Schristos 		    unsigned8 *w = (unsigned8*)property->array;
113866e63ce3Schristos 		    p->print (p->file, " [");
113966e63ce3Schristos 		    while ((char*)w - (char*)property->array < property->sizeof_array)
114066e63ce3Schristos 		      {
114166e63ce3Schristos 			p->print (p->file, " 0x%2x", BE2H_1 (*w));
114266e63ce3Schristos 			w++;
114366e63ce3Schristos 		      }
114466e63ce3Schristos 		  }
114566e63ce3Schristos 		break;
114666e63ce3Schristos 	      }
114766e63ce3Schristos 	    case boolean_property:
114866e63ce3Schristos 	      {
114966e63ce3Schristos 		int b = hw_find_boolean_property (me, property->name);
115066e63ce3Schristos 		p->print (p->file, " %s", b ? "true"  : "false");
115166e63ce3Schristos 		break;
115266e63ce3Schristos 	      }
115366e63ce3Schristos #if NOT_YET
115466e63ce3Schristos 	    case ihandle_property:
115566e63ce3Schristos 	      {
115666e63ce3Schristos 		if (property->array != NULL)
115766e63ce3Schristos 		  {
115866e63ce3Schristos 		    device_instance *instance = hw_find_ihandle_property (me, property->name);
115966e63ce3Schristos 		    p->print (p->file, " *%s", device_instance_path (instance));
116066e63ce3Schristos 		  }
116166e63ce3Schristos 		else
116266e63ce3Schristos 		  {
116366e63ce3Schristos 		    /* not yet initialized, ask the device for the path */
116466e63ce3Schristos 		    ihandle_runtime_property_spec spec;
116566e63ce3Schristos 		    hw_find_ihandle_runtime_property (me, property->name, &spec);
116666e63ce3Schristos 		    p->print (p->file, " *%s", spec.full_path);
116766e63ce3Schristos 		  }
116866e63ce3Schristos 		break;
116966e63ce3Schristos 	      }
117066e63ce3Schristos #endif
117166e63ce3Schristos 	    case integer_property:
117266e63ce3Schristos 	      {
117366e63ce3Schristos 		unsigned_word w = hw_find_integer_property (me, property->name);
117466e63ce3Schristos 		p->print (p->file, " 0x%lx", (unsigned long)w);
117566e63ce3Schristos 		break;
117666e63ce3Schristos 	      }
117766e63ce3Schristos 	    case range_array_property:
117866e63ce3Schristos 	      {
117966e63ce3Schristos 		print_ranges_property (me, property, p);
118066e63ce3Schristos 		break;
118166e63ce3Schristos 	      }
118266e63ce3Schristos 	    case reg_array_property:
118366e63ce3Schristos 	      {
118466e63ce3Schristos 		print_reg_property (me, property, p);
118566e63ce3Schristos 		break;
118666e63ce3Schristos 	      }
118766e63ce3Schristos 	    case string_property:
118866e63ce3Schristos 	      {
118966e63ce3Schristos 		const char *s = hw_find_string_property (me, property->name);
119066e63ce3Schristos 		print_string (me, s, p);
119166e63ce3Schristos 		break;
119266e63ce3Schristos 	      }
119366e63ce3Schristos 	    case string_array_property:
119466e63ce3Schristos 	      {
119566e63ce3Schristos 		print_string_array_property (me, property, p);
119666e63ce3Schristos 		break;
119766e63ce3Schristos 	      }
119866e63ce3Schristos 	    }
119966e63ce3Schristos 	}
120066e63ce3Schristos       p->print (p->file, "\n");
120166e63ce3Schristos     }
120266e63ce3Schristos }
120366e63ce3Schristos 
120466e63ce3Schristos static void
print_interrupts(struct hw * me,int my_port,struct hw * dest,int dest_port,void * data)120566e63ce3Schristos print_interrupts (struct hw *me,
120666e63ce3Schristos                   int my_port,
120766e63ce3Schristos 		  struct hw *dest,
120866e63ce3Schristos 		  int dest_port,
120966e63ce3Schristos 		  void *data)
121066e63ce3Schristos {
121166e63ce3Schristos   struct printer *p = data;
121266e63ce3Schristos   char src[32];
121366e63ce3Schristos   char dst[32];
121466e63ce3Schristos   hw_port_encode (me, my_port, src, sizeof (src), output_port);
121566e63ce3Schristos   hw_port_encode (dest, dest_port, dst, sizeof (dst), input_port);
121666e63ce3Schristos   p->print (p->file,
121766e63ce3Schristos 	    "%s > %s %s %s\n",
121866e63ce3Schristos 	    hw_path (me),
121966e63ce3Schristos 	    src, dst,
122066e63ce3Schristos 	    hw_path (dest));
122166e63ce3Schristos }
122266e63ce3Schristos 
122366e63ce3Schristos static void
print_device(struct hw * me,void * data)122466e63ce3Schristos print_device (struct hw *me,
122566e63ce3Schristos 	      void *data)
122666e63ce3Schristos {
122766e63ce3Schristos   struct printer *p = data;
122866e63ce3Schristos   p->print (p->file, "%s\n", hw_path (me));
122966e63ce3Schristos   print_properties (me, p);
123066e63ce3Schristos   hw_port_traverse (me, print_interrupts, data);
123166e63ce3Schristos }
123266e63ce3Schristos 
123366e63ce3Schristos void
hw_tree_print(struct hw * root,hw_tree_print_callback * print,void * file)123466e63ce3Schristos hw_tree_print (struct hw *root,
123566e63ce3Schristos 	       hw_tree_print_callback *print,
123666e63ce3Schristos 	       void *file)
123766e63ce3Schristos {
123866e63ce3Schristos   struct printer p;
123966e63ce3Schristos   p.print = print;
124066e63ce3Schristos   p.file = file;
124166e63ce3Schristos   hw_tree_traverse (root,
124266e63ce3Schristos 		    print_device, NULL,
124366e63ce3Schristos 		    &p);
124466e63ce3Schristos }
124566e63ce3Schristos 
124666e63ce3Schristos 
124766e63ce3Schristos 
124866e63ce3Schristos #if NOT_YET
124966e63ce3Schristos device_instance *
tree_instance(struct hw * root,const char * device_specifier)125066e63ce3Schristos tree_instance (struct hw *root,
125166e63ce3Schristos 	       const char *device_specifier)
125266e63ce3Schristos {
125366e63ce3Schristos   /* find the device node */
125466e63ce3Schristos   struct hw *me;
125566e63ce3Schristos   name_specifier spec;
125666e63ce3Schristos   if (!split_device_specifier (root, device_specifier, &spec))
125766e63ce3Schristos     return NULL;
125866e63ce3Schristos   me = split_find_device (root, &spec);
125966e63ce3Schristos   if (spec.name != NULL)
126066e63ce3Schristos     return NULL;
126166e63ce3Schristos   /* create the instance */
126266e63ce3Schristos   return device_create_instance (me, device_specifier, spec.last_args);
126366e63ce3Schristos }
126466e63ce3Schristos #endif
126566e63ce3Schristos 
126666e63ce3Schristos struct hw *
hw_tree_find_device(struct hw * root,const char * path_to_device)126766e63ce3Schristos hw_tree_find_device (struct hw *root,
126866e63ce3Schristos 		     const char *path_to_device)
126966e63ce3Schristos {
127066e63ce3Schristos   struct hw *node;
127166e63ce3Schristos   name_specifier spec;
127266e63ce3Schristos 
127366e63ce3Schristos   /* parse the path */
127466e63ce3Schristos   split_device_specifier (root, path_to_device, &spec);
127566e63ce3Schristos   if (spec.value != NULL)
127666e63ce3Schristos     return NULL; /* something wierd */
127766e63ce3Schristos 
127866e63ce3Schristos   /* now find it */
127966e63ce3Schristos   node = split_find_device (root, &spec);
128066e63ce3Schristos   if (spec.name != NULL)
128166e63ce3Schristos     return NULL; /* not a leaf */
128266e63ce3Schristos 
128366e63ce3Schristos   return node;
128466e63ce3Schristos }
128566e63ce3Schristos 
128666e63ce3Schristos 
128766e63ce3Schristos const struct hw_property *
hw_tree_find_property(struct hw * root,const char * path_to_property)128866e63ce3Schristos hw_tree_find_property (struct hw *root,
128966e63ce3Schristos 		       const char *path_to_property)
129066e63ce3Schristos {
129166e63ce3Schristos   name_specifier spec;
129266e63ce3Schristos   if (!split_property_specifier (root, path_to_property, &spec))
129366e63ce3Schristos     hw_abort (root, "Invalid property path %s", path_to_property);
129466e63ce3Schristos   root = split_find_device (root, &spec);
129566e63ce3Schristos   if (spec.name != NULL)
129666e63ce3Schristos     return NULL; /* not a leaf */
129766e63ce3Schristos   return hw_find_property (root, spec.property);
129866e63ce3Schristos }
129966e63ce3Schristos 
130066e63ce3Schristos int
hw_tree_find_boolean_property(struct hw * root,const char * path_to_property)130166e63ce3Schristos hw_tree_find_boolean_property (struct hw *root,
130266e63ce3Schristos 			       const char *path_to_property)
130366e63ce3Schristos {
130466e63ce3Schristos   name_specifier spec;
130566e63ce3Schristos   if (!split_property_specifier (root, path_to_property, &spec))
130666e63ce3Schristos     hw_abort (root, "Invalid property path %s", path_to_property);
130766e63ce3Schristos   root = split_find_device (root, &spec);
130866e63ce3Schristos   if (spec.name != NULL)
130966e63ce3Schristos     hw_abort (root, "device \"%s\" not found (property \"%s\")",
131066e63ce3Schristos 	      spec.name, path_to_property);
131166e63ce3Schristos   return hw_find_boolean_property (root, spec.property);
131266e63ce3Schristos }
131366e63ce3Schristos 
131466e63ce3Schristos signed_cell
hw_tree_find_integer_property(struct hw * root,const char * path_to_property)131566e63ce3Schristos hw_tree_find_integer_property (struct hw *root,
131666e63ce3Schristos 			       const char *path_to_property)
131766e63ce3Schristos {
131866e63ce3Schristos   name_specifier spec;
131966e63ce3Schristos   if (!split_property_specifier (root, path_to_property, &spec))
132066e63ce3Schristos     hw_abort (root, "Invalid property path %s", path_to_property);
132166e63ce3Schristos   root = split_find_device (root, &spec);
132266e63ce3Schristos   if (spec.name != NULL)
132366e63ce3Schristos     hw_abort (root, "device \"%s\" not found (property \"%s\")",
132466e63ce3Schristos 	      spec.name, path_to_property);
132566e63ce3Schristos   return hw_find_integer_property (root, spec.property);
132666e63ce3Schristos }
132766e63ce3Schristos 
132866e63ce3Schristos #if NOT_YET
132966e63ce3Schristos device_instance *
hw_tree_find_ihandle_property(struct hw * root,const char * path_to_property)133066e63ce3Schristos hw_tree_find_ihandle_property (struct hw *root,
133166e63ce3Schristos 			       const char *path_to_property)
133266e63ce3Schristos {
133366e63ce3Schristos   struct hw *root;
133466e63ce3Schristos   name_specifier spec;
133566e63ce3Schristos   if (!split_property_specifier (root, path_to_property, &spec))
133666e63ce3Schristos     hw_abort (root, "Invalid property path %s", path_to_property);
133766e63ce3Schristos   root = split_find_device (root, &spec);
133866e63ce3Schristos   if (spec.name != NULL)
133966e63ce3Schristos     hw_abort (root, "device \"%s\" not found (property \"%s\")",
134066e63ce3Schristos 	      spec.name, path_to_property);
134166e63ce3Schristos   return hw_find_ihandle_property (root, spec.property);
134266e63ce3Schristos }
134366e63ce3Schristos #endif
134466e63ce3Schristos 
134566e63ce3Schristos const char *
hw_tree_find_string_property(struct hw * root,const char * path_to_property)134666e63ce3Schristos hw_tree_find_string_property (struct hw *root,
134766e63ce3Schristos 			      const char *path_to_property)
134866e63ce3Schristos {
134966e63ce3Schristos   name_specifier spec;
135066e63ce3Schristos   if (!split_property_specifier (root, path_to_property, &spec))
135166e63ce3Schristos     hw_abort (root, "Invalid property path %s", path_to_property);
135266e63ce3Schristos   root = split_find_device (root, &spec);
135366e63ce3Schristos   if (spec.name != NULL)
135466e63ce3Schristos     hw_abort (root, "device \"%s\" not found (property \"%s\")",
135566e63ce3Schristos 	      spec.name, path_to_property);
135666e63ce3Schristos   return hw_find_string_property (root, spec.property);
135766e63ce3Schristos }
1358