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