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