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