OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-old/] [gdb-7.1/] [sim/] [ppc/] [tree.c] - Diff between revs 834 and 842

Go to most recent revision | Only display areas with differences | Details | Blame | View Log

Rev 834 Rev 842
/*  This file is part of the program psim.
/*  This file is part of the program psim.
 
 
    Copyright (C) 1994-1997, Andrew Cagney <cagney@highland.com.au>
    Copyright (C) 1994-1997, Andrew Cagney <cagney@highland.com.au>
 
 
    This program is free software; you can redistribute it and/or modify
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.
    (at your option) any later version.
 
 
    This program is distributed in the hope that it will be useful,
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
    GNU General Public License for more details.
 
 
    You should have received a copy of the GNU General Public License
    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 
 
    */
    */
 
 
 
 
#ifndef _PARSE_C_
#ifndef _PARSE_C_
#define _PARSE_C_
#define _PARSE_C_
 
 
#include <stdio.h>
#include <stdio.h>
#include <stdarg.h>
#include <stdarg.h>
 
 
#include "basics.h"
#include "basics.h"
 
 
#include "device.h"
#include "device.h"
#include "tree.h"
#include "tree.h"
 
 
 
 
#ifdef HAVE_STDLIB_H
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#include <stdlib.h>
#endif
#endif
 
 
#ifdef HAVE_STRING_H
#ifdef HAVE_STRING_H
#include <string.h>
#include <string.h>
#else
#else
#ifdef HAVE_STRINGS_H
#ifdef HAVE_STRINGS_H
#include <strings.h>
#include <strings.h>
#endif
#endif
#endif
#endif
 
 
#include <ctype.h>
#include <ctype.h>
 
 
#include "libiberty.h"
#include "libiberty.h"
 
 
/* manipulate/lookup device names */
/* manipulate/lookup device names */
 
 
typedef struct _name_specifier {
typedef struct _name_specifier {
  /* components in the full length name */
  /* components in the full length name */
  char *path;
  char *path;
  char *property;
  char *property;
  char *value;
  char *value;
  /* current device */
  /* current device */
  char *name;
  char *name;
  char *base;
  char *base;
  char *unit;
  char *unit;
  char *args;
  char *args;
  /* previous device */
  /* previous device */
  char *last_name;
  char *last_name;
  char *last_base;
  char *last_base;
  char *last_unit;
  char *last_unit;
  char *last_args;
  char *last_args;
  /* work area */
  /* work area */
  char buf[1024];
  char buf[1024];
} name_specifier;
} name_specifier;
 
 
 
 
 
 
/* Given a device specifier, break it up into its main components:
/* Given a device specifier, break it up into its main components:
   path (and if present) property name and property value. */
   path (and if present) property name and property value. */
 
 
STATIC_INLINE_TREE\
STATIC_INLINE_TREE\
(int)
(int)
split_device_specifier(device *current,
split_device_specifier(device *current,
                       const char *device_specifier,
                       const char *device_specifier,
                       name_specifier *spec)
                       name_specifier *spec)
{
{
  char *chp = NULL;
  char *chp = NULL;
 
 
  /* expand any leading alias if present */
  /* expand any leading alias if present */
  if (current != NULL
  if (current != NULL
      && *device_specifier != '\0'
      && *device_specifier != '\0'
      && *device_specifier != '.'
      && *device_specifier != '.'
      && *device_specifier != '/') {
      && *device_specifier != '/') {
    device *aliases = tree_find_device(current, "/aliases");
    device *aliases = tree_find_device(current, "/aliases");
    char alias[32];
    char alias[32];
    int len = 0;
    int len = 0;
    while (device_specifier[len] != '\0'
    while (device_specifier[len] != '\0'
           && device_specifier[len] != '/'
           && device_specifier[len] != '/'
           && device_specifier[len] != ':'
           && device_specifier[len] != ':'
           && !isspace(device_specifier[len])) {
           && !isspace(device_specifier[len])) {
      alias[len] = device_specifier[len];
      alias[len] = device_specifier[len];
      len++;
      len++;
      if (len >= sizeof(alias))
      if (len >= sizeof(alias))
        error("split_device_specifier: buffer overflow");
        error("split_device_specifier: buffer overflow");
    }
    }
    alias[len] = '\0';
    alias[len] = '\0';
    if (aliases != NULL
    if (aliases != NULL
        && device_find_property(aliases, alias)) {
        && device_find_property(aliases, alias)) {
      strcpy(spec->buf, device_find_string_property(aliases, alias));
      strcpy(spec->buf, device_find_string_property(aliases, alias));
      strcat(spec->buf, device_specifier + len);
      strcat(spec->buf, device_specifier + len);
    }
    }
    else {
    else {
      strcpy(spec->buf, device_specifier);
      strcpy(spec->buf, device_specifier);
    }
    }
  }
  }
  else {
  else {
    strcpy(spec->buf, device_specifier);
    strcpy(spec->buf, device_specifier);
  }
  }
 
 
  /* check no overflow */
  /* check no overflow */
  if (strlen(spec->buf) >= sizeof(spec->buf))
  if (strlen(spec->buf) >= sizeof(spec->buf))
    error("split_device_specifier: buffer overflow\n");
    error("split_device_specifier: buffer overflow\n");
 
 
  /* strip leading spaces */
  /* strip leading spaces */
  chp = spec->buf;
  chp = spec->buf;
  while (*chp != '\0' && isspace(*chp))
  while (*chp != '\0' && isspace(*chp))
    chp++;
    chp++;
  if (*chp == '\0')
  if (*chp == '\0')
    return 0;
    return 0;
 
 
  /* find the path and terminate it with null */
  /* find the path and terminate it with null */
  spec->path = chp;
  spec->path = chp;
  while (*chp != '\0' && !isspace(*chp))
  while (*chp != '\0' && !isspace(*chp))
    chp++;
    chp++;
  if (*chp != '\0') {
  if (*chp != '\0') {
    *chp = '\0';
    *chp = '\0';
    chp++;
    chp++;
  }
  }
 
 
  /* and any value */
  /* and any value */
  while (*chp != '\0' && isspace(*chp))
  while (*chp != '\0' && isspace(*chp))
    chp++;
    chp++;
  spec->value = chp;
  spec->value = chp;
 
 
  /* now go back and chop the property off of the path */
  /* now go back and chop the property off of the path */
  if (spec->value[0] == '\0') {
  if (spec->value[0] == '\0') {
    spec->property = NULL; /*not a property*/
    spec->property = NULL; /*not a property*/
    spec->value = NULL;
    spec->value = NULL;
  }
  }
  else if (spec->value[0] == '>'
  else if (spec->value[0] == '>'
           || spec->value[0] == '<') {
           || spec->value[0] == '<') {
    /* an interrupt spec */
    /* an interrupt spec */
    spec->property = NULL;
    spec->property = NULL;
  }
  }
  else {
  else {
    chp = strrchr(spec->path, '/');
    chp = strrchr(spec->path, '/');
    if (chp == NULL) {
    if (chp == NULL) {
      spec->property = spec->path;
      spec->property = spec->path;
      spec->path = strchr(spec->property, '\0');
      spec->path = strchr(spec->property, '\0');
    }
    }
    else {
    else {
      *chp = '\0';
      *chp = '\0';
      spec->property = chp+1;
      spec->property = chp+1;
    }
    }
  }
  }
 
 
  /* and mark the rest as invalid */
  /* and mark the rest as invalid */
  spec->name = NULL;
  spec->name = NULL;
  spec->base = NULL;
  spec->base = NULL;
  spec->unit = NULL;
  spec->unit = NULL;
  spec->args = NULL;
  spec->args = NULL;
  spec->last_name = NULL;
  spec->last_name = NULL;
  spec->last_base = NULL;
  spec->last_base = NULL;
  spec->last_unit = NULL;
  spec->last_unit = NULL;
  spec->last_args = NULL;
  spec->last_args = NULL;
 
 
  return 1;
  return 1;
}
}
 
 
 
 
/* given a device specifier break it up into its main components -
/* given a device specifier break it up into its main components -
   path and property name - assuming that the last `device' is a
   path and property name - assuming that the last `device' is a
   property name. */
   property name. */
 
 
STATIC_INLINE_DEVICE\
STATIC_INLINE_DEVICE\
(int)
(int)
split_property_specifier(device *current,
split_property_specifier(device *current,
                         const char *property_specifier,
                         const char *property_specifier,
                         name_specifier *spec)
                         name_specifier *spec)
{
{
  if (split_device_specifier(current, property_specifier, spec)) {
  if (split_device_specifier(current, property_specifier, spec)) {
    if (spec->property == NULL) {
    if (spec->property == NULL) {
      /* force the last name to be a property name */
      /* force the last name to be a property name */
      char *chp = strrchr(spec->path, '/');
      char *chp = strrchr(spec->path, '/');
      if (chp == NULL) {
      if (chp == NULL) {
        spec->property = spec->path;
        spec->property = spec->path;
        spec->path = strrchr(spec->property, '\0');;
        spec->path = strrchr(spec->property, '\0');;
      }
      }
      else {
      else {
        *chp = '\0';
        *chp = '\0';
        spec->property = chp+1;
        spec->property = chp+1;
      }
      }
    }
    }
    return 1;
    return 1;
  }
  }
  else
  else
    return 0;
    return 0;
}
}
 
 
 
 
/* device the next device name and split it up, return 0 when no more
/* device the next device name and split it up, return 0 when no more
   names to device */
   names to device */
 
 
STATIC_INLINE_TREE\
STATIC_INLINE_TREE\
(int)
(int)
split_device_name(name_specifier *spec)
split_device_name(name_specifier *spec)
{
{
  char *chp;
  char *chp;
  /* remember what came before */
  /* remember what came before */
  spec->last_name = spec->name;
  spec->last_name = spec->name;
  spec->last_base = spec->base;
  spec->last_base = spec->base;
  spec->last_unit = spec->unit;
  spec->last_unit = spec->unit;
  spec->last_args = spec->args;
  spec->last_args = spec->args;
  /* finished? */
  /* finished? */
  if (spec->path[0] == '\0') {
  if (spec->path[0] == '\0') {
    spec->name = NULL;
    spec->name = NULL;
    spec->base = NULL;
    spec->base = NULL;
    spec->unit = NULL;
    spec->unit = NULL;
    spec->args = NULL;
    spec->args = NULL;
    return 0;
    return 0;
  }
  }
  /* break the current device spec from the path */
  /* break the current device spec from the path */
  spec->name = spec->path;
  spec->name = spec->path;
  chp = strchr(spec->name, '/');
  chp = strchr(spec->name, '/');
  if (chp == NULL)
  if (chp == NULL)
    spec->path = strchr(spec->name, '\0');
    spec->path = strchr(spec->name, '\0');
  else {
  else {
    spec->path = chp+1;
    spec->path = chp+1;
    *chp = '\0';
    *chp = '\0';
  }
  }
  /* break out the base */
  /* break out the base */
  if (spec->name[0] == '(') {
  if (spec->name[0] == '(') {
    chp = strchr(spec->name, ')');
    chp = strchr(spec->name, ')');
    if (chp == NULL) {
    if (chp == NULL) {
      spec->base = spec->name;
      spec->base = spec->name;
    }
    }
    else {
    else {
      *chp = '\0';
      *chp = '\0';
      spec->base = spec->name + 1;
      spec->base = spec->name + 1;
      spec->name = chp + 1;
      spec->name = chp + 1;
    }
    }
  }
  }
  else {
  else {
    spec->base = spec->name;
    spec->base = spec->name;
  }
  }
  /* now break out the unit */
  /* now break out the unit */
  chp = strchr(spec->name, '@');
  chp = strchr(spec->name, '@');
  if (chp == NULL) {
  if (chp == NULL) {
    spec->unit = NULL;
    spec->unit = NULL;
    chp = spec->name;
    chp = spec->name;
  }
  }
  else {
  else {
    *chp = '\0';
    *chp = '\0';
    chp += 1;
    chp += 1;
    spec->unit = chp;
    spec->unit = chp;
  }
  }
  /* finally any args */
  /* finally any args */
  chp = strchr(chp, ':');
  chp = strchr(chp, ':');
  if (chp == NULL)
  if (chp == NULL)
    spec->args = NULL;
    spec->args = NULL;
  else {
  else {
    *chp = '\0';
    *chp = '\0';
    spec->args = chp+1;
    spec->args = chp+1;
  }
  }
  return 1;
  return 1;
}
}
 
 
 
 
/* device the value, returning the next non-space token */
/* device the value, returning the next non-space token */
 
 
STATIC_INLINE_TREE\
STATIC_INLINE_TREE\
(char *)
(char *)
split_value(name_specifier *spec)
split_value(name_specifier *spec)
{
{
  char *token;
  char *token;
  if (spec->value == NULL)
  if (spec->value == NULL)
    return NULL;
    return NULL;
  /* skip leading white space */
  /* skip leading white space */
  while (isspace(spec->value[0]))
  while (isspace(spec->value[0]))
    spec->value++;
    spec->value++;
  if (spec->value[0] == '\0') {
  if (spec->value[0] == '\0') {
    spec->value = NULL;
    spec->value = NULL;
    return NULL;
    return NULL;
  }
  }
  token = spec->value;
  token = spec->value;
  /* find trailing space */
  /* find trailing space */
  while (spec->value[0] != '\0' && !isspace(spec->value[0]))
  while (spec->value[0] != '\0' && !isspace(spec->value[0]))
    spec->value++;
    spec->value++;
  /* chop this value out */
  /* chop this value out */
  if (spec->value[0] != '\0') {
  if (spec->value[0] != '\0') {
    spec->value[0] = '\0';
    spec->value[0] = '\0';
    spec->value++;
    spec->value++;
  }
  }
  return token;
  return token;
}
}
 
 
 
 
 
 
/* traverse the path specified by spec starting at current */
/* traverse the path specified by spec starting at current */
 
 
STATIC_INLINE_TREE\
STATIC_INLINE_TREE\
(device *)
(device *)
split_find_device(device *current,
split_find_device(device *current,
                  name_specifier *spec)
                  name_specifier *spec)
{
{
  /* strip off (and process) any leading ., .., ./ and / */
  /* strip off (and process) any leading ., .., ./ and / */
  while (1) {
  while (1) {
    if (strncmp(spec->path, "/", strlen("/")) == 0) {
    if (strncmp(spec->path, "/", strlen("/")) == 0) {
      /* cd /... */
      /* cd /... */
      while (current != NULL && device_parent(current) != NULL)
      while (current != NULL && device_parent(current) != NULL)
        current = device_parent(current);
        current = device_parent(current);
      spec->path += strlen("/");
      spec->path += strlen("/");
    }
    }
    else if (strncmp(spec->path, "./", strlen("./")) == 0) {
    else if (strncmp(spec->path, "./", strlen("./")) == 0) {
      /* cd ./... */
      /* cd ./... */
      current = current;
      current = current;
      spec->path += strlen("./");
      spec->path += strlen("./");
    }
    }
    else if (strncmp(spec->path, "../", strlen("../")) == 0) {
    else if (strncmp(spec->path, "../", strlen("../")) == 0) {
      /* cd ../... */
      /* cd ../... */
      if (current != NULL && device_parent(current) != NULL)
      if (current != NULL && device_parent(current) != NULL)
        current = device_parent(current);
        current = device_parent(current);
      spec->path += strlen("../");
      spec->path += strlen("../");
    }
    }
    else if (strcmp(spec->path, ".") == 0) {
    else if (strcmp(spec->path, ".") == 0) {
      /* cd . */
      /* cd . */
      current = current;
      current = current;
      spec->path += strlen(".");
      spec->path += strlen(".");
    }
    }
    else if (strcmp(spec->path, "..") == 0) {
    else if (strcmp(spec->path, "..") == 0) {
      /* cd . */
      /* cd . */
      if (current != NULL && device_parent(current) != NULL)
      if (current != NULL && device_parent(current) != NULL)
        current = device_parent(current);
        current = device_parent(current);
      spec->path += strlen("..");
      spec->path += strlen("..");
    }
    }
    else
    else
      break;
      break;
  }
  }
 
 
  /* now go through the path proper */
  /* now go through the path proper */
 
 
  if (current == NULL) {
  if (current == NULL) {
    split_device_name(spec);
    split_device_name(spec);
    return NULL;
    return NULL;
  }
  }
 
 
  while (split_device_name(spec)) {
  while (split_device_name(spec)) {
    device *child;
    device *child;
    for (child = device_child(current);
    for (child = device_child(current);
         child != NULL; child = device_sibling(child)) {
         child != NULL; child = device_sibling(child)) {
      if (strcmp(spec->name, device_name(child)) == 0) {
      if (strcmp(spec->name, device_name(child)) == 0) {
        if (spec->unit == NULL)
        if (spec->unit == NULL)
          break;
          break;
        else {
        else {
          device_unit phys;
          device_unit phys;
          device_decode_unit(current, spec->unit, &phys);
          device_decode_unit(current, spec->unit, &phys);
          if (memcmp(&phys, device_unit_address(child),
          if (memcmp(&phys, device_unit_address(child),
                     sizeof(device_unit)) == 0)
                     sizeof(device_unit)) == 0)
            break;
            break;
        }
        }
      }
      }
    }
    }
    if (child == NULL)
    if (child == NULL)
      return current; /* search failed */
      return current; /* search failed */
    current = child;
    current = child;
  }
  }
 
 
  return current;
  return current;
}
}
 
 
 
 
STATIC_INLINE_TREE\
STATIC_INLINE_TREE\
(device *)
(device *)
split_fill_path(device *current,
split_fill_path(device *current,
                const char *device_specifier,
                const char *device_specifier,
                name_specifier *spec)
                name_specifier *spec)
{
{
  /* break it up */
  /* break it up */
  if (!split_device_specifier(current, device_specifier, spec))
  if (!split_device_specifier(current, device_specifier, spec))
    device_error(current, "error parsing %s\n", device_specifier);
    device_error(current, "error parsing %s\n", device_specifier);
 
 
  /* fill our tree with its contents */
  /* fill our tree with its contents */
  current = split_find_device(current, spec);
  current = split_find_device(current, spec);
 
 
  /* add any additional devices as needed */
  /* add any additional devices as needed */
  if (spec->name != NULL) {
  if (spec->name != NULL) {
    do {
    do {
      current = device_create(current, spec->base, spec->name,
      current = device_create(current, spec->base, spec->name,
                              spec->unit, spec->args);
                              spec->unit, spec->args);
    } while (split_device_name(spec));
    } while (split_device_name(spec));
  }
  }
 
 
  return current;
  return current;
}
}
 
 
 
 
INLINE_TREE\
INLINE_TREE\
(void)
(void)
tree_init(device *root,
tree_init(device *root,
          psim *system)
          psim *system)
{
{
  TRACE(trace_device_tree, ("tree_init(root=0x%lx, system=0x%lx)\n",
  TRACE(trace_device_tree, ("tree_init(root=0x%lx, system=0x%lx)\n",
                            (long)root,
                            (long)root,
                            (long)system));
                            (long)system));
  /* remove the old, rebuild the new */
  /* remove the old, rebuild the new */
  tree_traverse(root, device_clean, NULL, system);
  tree_traverse(root, device_clean, NULL, system);
  tree_traverse(root, device_init_static_properties, NULL, system);
  tree_traverse(root, device_init_static_properties, NULL, system);
  tree_traverse(root, device_init_address, NULL, system);
  tree_traverse(root, device_init_address, NULL, system);
  tree_traverse(root, device_init_runtime_properties, NULL, system);
  tree_traverse(root, device_init_runtime_properties, NULL, system);
  tree_traverse(root, device_init_data, NULL, system);
  tree_traverse(root, device_init_data, NULL, system);
}
}
 
 
 
 


/* <non-white-space> */
/* <non-white-space> */
 
 
STATIC_INLINE_TREE\
STATIC_INLINE_TREE\
(const char *)
(const char *)
skip_token(const char *chp)
skip_token(const char *chp)
{
{
  while (!isspace(*chp) && *chp != '\0')
  while (!isspace(*chp) && *chp != '\0')
    chp++;
    chp++;
  while (isspace(*chp) && *chp != '\0')
  while (isspace(*chp) && *chp != '\0')
    chp++;
    chp++;
  return chp;
  return chp;
}
}
 
 
 
 
/* count the number of entries */
/* count the number of entries */
 
 
STATIC_INLINE_TREE\
STATIC_INLINE_TREE\
(int)
(int)
count_entries(device *current,
count_entries(device *current,
              const char *property_name,
              const char *property_name,
              const char *property_value,
              const char *property_value,
              int modulo)
              int modulo)
{
{
  const char *chp = property_value;
  const char *chp = property_value;
  int nr_entries = 0;
  int nr_entries = 0;
  while (*chp != '\0') {
  while (*chp != '\0') {
    nr_entries += 1;
    nr_entries += 1;
    chp = skip_token(chp);
    chp = skip_token(chp);
  }
  }
  if ((nr_entries % modulo) != 0) {
  if ((nr_entries % modulo) != 0) {
    device_error(current, "incorrect number of entries for %s property %s, should be multiple of %d",
    device_error(current, "incorrect number of entries for %s property %s, should be multiple of %d",
                 property_name, property_value, modulo);
                 property_name, property_value, modulo);
  }
  }
  return nr_entries / modulo;
  return nr_entries / modulo;
}
}
 
 
 
 
 
 
/* parse: <address> ::= <token> ; device dependant */
/* parse: <address> ::= <token> ; device dependant */
 
 
STATIC_INLINE_TREE\
STATIC_INLINE_TREE\
(const char *)
(const char *)
parse_address(device *current,
parse_address(device *current,
              device *bus,
              device *bus,
              const char *chp,
              const char *chp,
              device_unit *address)
              device_unit *address)
{
{
  ASSERT(device_nr_address_cells(bus) > 0);
  ASSERT(device_nr_address_cells(bus) > 0);
  if (device_decode_unit(bus, chp, address) < 0)
  if (device_decode_unit(bus, chp, address) < 0)
    device_error(current, "invalid unit address in %s", chp);
    device_error(current, "invalid unit address in %s", chp);
  return skip_token(chp);
  return skip_token(chp);
}
}
 
 
 
 
/* parse: <size> ::= <number> { "," <number> } ; */
/* parse: <size> ::= <number> { "," <number> } ; */
 
 
STATIC_INLINE_TREE\
STATIC_INLINE_TREE\
(const char *)
(const char *)
parse_size(device *current,
parse_size(device *current,
           device *bus,
           device *bus,
           const char *chp,
           const char *chp,
           device_unit *size)
           device_unit *size)
{
{
  int i;
  int i;
  int nr;
  int nr;
  const char *curr = chp;
  const char *curr = chp;
  memset(size, 0, sizeof(*size));
  memset(size, 0, sizeof(*size));
  /* parse the numeric list */
  /* parse the numeric list */
  size->nr_cells = device_nr_size_cells(bus);
  size->nr_cells = device_nr_size_cells(bus);
  nr = 0;
  nr = 0;
  ASSERT(size->nr_cells > 0);
  ASSERT(size->nr_cells > 0);
  while (1) {
  while (1) {
    char *next;
    char *next;
    size->cells[nr] = strtoul(curr, &next, 0);
    size->cells[nr] = strtoul(curr, &next, 0);
    if (curr == next)
    if (curr == next)
      device_error(current, "Problem parsing <size> %s", chp);
      device_error(current, "Problem parsing <size> %s", chp);
    nr += 1;
    nr += 1;
    if (next[0] != ',')
    if (next[0] != ',')
      break;
      break;
    if (nr == size->nr_cells)
    if (nr == size->nr_cells)
      device_error(current, "Too many values in <size> %s", chp);
      device_error(current, "Too many values in <size> %s", chp);
    curr = next + 1;
    curr = next + 1;
  }
  }
  ASSERT(nr > 0 && nr <= size->nr_cells);
  ASSERT(nr > 0 && nr <= size->nr_cells);
  /* right align the numbers */
  /* right align the numbers */
  for (i = 1; i <= size->nr_cells; i++) {
  for (i = 1; i <= size->nr_cells; i++) {
    if (i <= nr)
    if (i <= nr)
      size->cells[size->nr_cells - i] = size->cells[nr - i];
      size->cells[size->nr_cells - i] = size->cells[nr - i];
    else
    else
      size->cells[size->nr_cells - i] = 0;
      size->cells[size->nr_cells - i] = 0;
  }
  }
  return skip_token(chp);
  return skip_token(chp);
}
}
 
 
 
 
/* parse: <reg> ::= { <address> <size> } ; */
/* parse: <reg> ::= { <address> <size> } ; */
 
 
STATIC_INLINE_TREE\
STATIC_INLINE_TREE\
(void)
(void)
parse_reg_property(device *current,
parse_reg_property(device *current,
                   const char *property_name,
                   const char *property_name,
                   const char *property_value)
                   const char *property_value)
{
{
  int nr_regs;
  int nr_regs;
  int reg_nr;
  int reg_nr;
  reg_property_spec *regs;
  reg_property_spec *regs;
  const char *chp;
  const char *chp;
  device *bus = device_parent(current);
  device *bus = device_parent(current);
 
 
  /* determine the number of reg entries by counting tokens */
  /* determine the number of reg entries by counting tokens */
  nr_regs = count_entries(current, property_name, property_value,
  nr_regs = count_entries(current, property_name, property_value,
                          1 + (device_nr_size_cells(bus) > 0));
                          1 + (device_nr_size_cells(bus) > 0));
 
 
  /* create working space */
  /* create working space */
  regs = zalloc(nr_regs * sizeof(*regs));
  regs = zalloc(nr_regs * sizeof(*regs));
 
 
  /* fill it in */
  /* fill it in */
  chp = property_value;
  chp = property_value;
  for (reg_nr = 0; reg_nr < nr_regs; reg_nr++) {
  for (reg_nr = 0; reg_nr < nr_regs; reg_nr++) {
    chp = parse_address(current, bus, chp, &regs[reg_nr].address);
    chp = parse_address(current, bus, chp, &regs[reg_nr].address);
    if (device_nr_size_cells(bus) > 0)
    if (device_nr_size_cells(bus) > 0)
      chp = parse_size(current, bus, chp, &regs[reg_nr].size);
      chp = parse_size(current, bus, chp, &regs[reg_nr].size);
    else
    else
      memset(&regs[reg_nr].size, 0, sizeof (&regs[reg_nr].size));
      memset(&regs[reg_nr].size, 0, sizeof (&regs[reg_nr].size));
  }
  }
 
 
  /* create it */
  /* create it */
  device_add_reg_array_property(current, property_name,
  device_add_reg_array_property(current, property_name,
                                regs, nr_regs);
                                regs, nr_regs);
 
 
  zfree(regs);
  zfree(regs);
}
}
 
 
 
 
/* { <child-address> <parent-address> <child-size> }* */
/* { <child-address> <parent-address> <child-size> }* */
 
 
STATIC_INLINE_TREE\
STATIC_INLINE_TREE\
(void)
(void)
parse_ranges_property(device *current,
parse_ranges_property(device *current,
                      const char *property_name,
                      const char *property_name,
                      const char *property_value)
                      const char *property_value)
{
{
  int nr_ranges;
  int nr_ranges;
  int range_nr;
  int range_nr;
  range_property_spec *ranges;
  range_property_spec *ranges;
  const char *chp;
  const char *chp;
 
 
  /* determine the number of ranges specified */
  /* determine the number of ranges specified */
  nr_ranges = count_entries(current, property_name, property_value, 3);
  nr_ranges = count_entries(current, property_name, property_value, 3);
 
 
  /* create a property of that size */
  /* create a property of that size */
  ranges = zalloc(nr_ranges * sizeof(*ranges));
  ranges = zalloc(nr_ranges * sizeof(*ranges));
 
 
  /* fill it in */
  /* fill it in */
  chp = property_value;
  chp = property_value;
  for (range_nr = 0; range_nr < nr_ranges; range_nr++) {
  for (range_nr = 0; range_nr < nr_ranges; range_nr++) {
    chp = parse_address(current, current,
    chp = parse_address(current, current,
                        chp, &ranges[range_nr].child_address);
                        chp, &ranges[range_nr].child_address);
    chp = parse_address(current, device_parent(current),
    chp = parse_address(current, device_parent(current),
                        chp, &ranges[range_nr].parent_address);
                        chp, &ranges[range_nr].parent_address);
    chp = parse_size(current, current,
    chp = parse_size(current, current,
                     chp, &ranges[range_nr].size);
                     chp, &ranges[range_nr].size);
  }
  }
 
 
  /* create it */
  /* create it */
  device_add_range_array_property(current, property_name, ranges, nr_ranges);
  device_add_range_array_property(current, property_name, ranges, nr_ranges);
 
 
  zfree(ranges);
  zfree(ranges);
}
}
 
 
 
 
/* <integer> ... */
/* <integer> ... */
 
 
STATIC_INLINE_TREE\
STATIC_INLINE_TREE\
(void)
(void)
parse_integer_property(device *current,
parse_integer_property(device *current,
                       const char *property_name,
                       const char *property_name,
                       const char *property_value)
                       const char *property_value)
{
{
  int nr_entries;
  int nr_entries;
  unsigned_cell words[1024];
  unsigned_cell words[1024];
  /* integer or integer array? */
  /* integer or integer array? */
  nr_entries = 0;
  nr_entries = 0;
  while (1) {
  while (1) {
    char *end;
    char *end;
    words[nr_entries] = strtoul(property_value, &end, 0);
    words[nr_entries] = strtoul(property_value, &end, 0);
    if (property_value == end)
    if (property_value == end)
      break;
      break;
    nr_entries += 1;
    nr_entries += 1;
    if (nr_entries * sizeof(words[0]) >= sizeof(words))
    if (nr_entries * sizeof(words[0]) >= sizeof(words))
      device_error(current, "buffer overflow");
      device_error(current, "buffer overflow");
    property_value = end;
    property_value = end;
  }
  }
  if (nr_entries == 0)
  if (nr_entries == 0)
    device_error(current, "error parsing integer property %s (%s)",
    device_error(current, "error parsing integer property %s (%s)",
                 property_name, property_value);
                 property_name, property_value);
  else if (nr_entries == 1)
  else if (nr_entries == 1)
    device_add_integer_property(current, property_name, words[0]);
    device_add_integer_property(current, property_name, words[0]);
  else {
  else {
    int i;
    int i;
    for (i = 0; i < nr_entries; i++) {
    for (i = 0; i < nr_entries; i++) {
      H2BE(words[i]);
      H2BE(words[i]);
    }
    }
    /* perhaps integer array property is better */
    /* perhaps integer array property is better */
    device_add_array_property(current, property_name, words,
    device_add_array_property(current, property_name, words,
                              sizeof(words[0]) * nr_entries);
                              sizeof(words[0]) * nr_entries);
  }
  }
}
}
 
 
/* PROPERTY_VALUE is a raw property value.  Quote it as required by
/* PROPERTY_VALUE is a raw property value.  Quote it as required by
   parse_string_property.  It is the caller's responsibility to free
   parse_string_property.  It is the caller's responsibility to free
   the memory returned.  */
   the memory returned.  */
 
 
EXTERN_TREE\
EXTERN_TREE\
(char *)
(char *)
tree_quote_property(const char *property_value)
tree_quote_property(const char *property_value)
{
{
  char *p;
  char *p;
  char *ret;
  char *ret;
  const char *chp;
  const char *chp;
  int quotees;
  int quotees;
 
 
  /* Count characters needing quotes in PROPERTY_VALUE.  */
  /* Count characters needing quotes in PROPERTY_VALUE.  */
  quotees = 0;
  quotees = 0;
  for (chp = property_value; *chp; ++chp)
  for (chp = property_value; *chp; ++chp)
    if (*chp == '\\' || *chp == '"')
    if (*chp == '\\' || *chp == '"')
      ++quotees;
      ++quotees;
 
 
  ret = (char *) xmalloc (strlen (property_value)
  ret = (char *) xmalloc (strlen (property_value)
                          + 2 /* quotes */
                          + 2 /* quotes */
                          + quotees
                          + quotees
                          + 1 /* terminator */);
                          + 1 /* terminator */);
 
 
  p = ret;
  p = ret;
  /* Add the opening quote.  */
  /* Add the opening quote.  */
  *p++ = '"';
  *p++ = '"';
  /* Copy the value.  */
  /* Copy the value.  */
  for (chp = property_value; *chp; ++chp)
  for (chp = property_value; *chp; ++chp)
    if (*chp == '\\' || *chp == '"')
    if (*chp == '\\' || *chp == '"')
      {
      {
        /* Quote this character.  */
        /* Quote this character.  */
        *p++ = '\\';
        *p++ = '\\';
        *p++ = *chp;
        *p++ = *chp;
      }
      }
    else
    else
      *p++ = *chp;
      *p++ = *chp;
  /* Add the closing quote.  */
  /* Add the closing quote.  */
  *p++ = '"';
  *p++ = '"';
  /* Terminate the string.  */
  /* Terminate the string.  */
  *p++ = '\0';
  *p++ = '\0';
 
 
  return ret;
  return ret;
}
}
 
 
/* <string> ... */
/* <string> ... */
 
 
STATIC_INLINE_TREE\
STATIC_INLINE_TREE\
(void)
(void)
parse_string_property(device *current,
parse_string_property(device *current,
                      const char *property_name,
                      const char *property_name,
                      const char *property_value)
                      const char *property_value)
{
{
  char **strings;
  char **strings;
  const char *chp;
  const char *chp;
  int nr_strings;
  int nr_strings;
  int approx_nr_strings;
  int approx_nr_strings;
 
 
  /* get an estimate as to the number of strings by counting double
  /* get an estimate as to the number of strings by counting double
     quotes */
     quotes */
  approx_nr_strings = 2;
  approx_nr_strings = 2;
  for (chp = property_value; *chp; chp++) {
  for (chp = property_value; *chp; chp++) {
    if (*chp == '"')
    if (*chp == '"')
      approx_nr_strings++;
      approx_nr_strings++;
  }
  }
  approx_nr_strings = (approx_nr_strings) / 2;
  approx_nr_strings = (approx_nr_strings) / 2;
 
 
  /* create a string buffer for that many (plus a null) */
  /* create a string buffer for that many (plus a null) */
  strings = (char**)zalloc((approx_nr_strings + 1) * sizeof(char*));
  strings = (char**)zalloc((approx_nr_strings + 1) * sizeof(char*));
 
 
  /* now find all the strings */
  /* now find all the strings */
  chp = property_value;
  chp = property_value;
  nr_strings = 0;
  nr_strings = 0;
  while (1) {
  while (1) {
 
 
    /* skip leading space */
    /* skip leading space */
    while (*chp != '\0' && isspace(*chp))
    while (*chp != '\0' && isspace(*chp))
      chp += 1;
      chp += 1;
    if (*chp == '\0')
    if (*chp == '\0')
      break;
      break;
 
 
    /* copy it in */
    /* copy it in */
    if (*chp == '"') {
    if (*chp == '"') {
      /* a quoted string - watch for '\' et.al. */
      /* a quoted string - watch for '\' et.al. */
      /* estimate the size and allocate space for it */
      /* estimate the size and allocate space for it */
      int pos;
      int pos;
      chp++;
      chp++;
      pos = 0;
      pos = 0;
      while (chp[pos] != '\0' && chp[pos] != '"') {
      while (chp[pos] != '\0' && chp[pos] != '"') {
        if (chp[pos] == '\\' && chp[pos+1] != '\0')
        if (chp[pos] == '\\' && chp[pos+1] != '\0')
          pos += 2;
          pos += 2;
        else
        else
          pos += 1;
          pos += 1;
      }
      }
      strings[nr_strings] = zalloc(pos + 1);
      strings[nr_strings] = zalloc(pos + 1);
      /* copy the string over */
      /* copy the string over */
      pos = 0;
      pos = 0;
      while (*chp != '\0' && *chp != '"') {
      while (*chp != '\0' && *chp != '"') {
        if (*chp == '\\' && *(chp+1) != '\0') {
        if (*chp == '\\' && *(chp+1) != '\0') {
          strings[nr_strings][pos] = *(chp+1);
          strings[nr_strings][pos] = *(chp+1);
          chp += 2;
          chp += 2;
          pos++;
          pos++;
        }
        }
        else {
        else {
          strings[nr_strings][pos] = *chp;
          strings[nr_strings][pos] = *chp;
          chp += 1;
          chp += 1;
          pos++;
          pos++;
        }
        }
      }
      }
      if (*chp != '\0')
      if (*chp != '\0')
        chp++;
        chp++;
      strings[nr_strings][pos] = '\0';
      strings[nr_strings][pos] = '\0';
    }
    }
    else {
    else {
      /* copy over a single unquoted token */
      /* copy over a single unquoted token */
      int len = 0;
      int len = 0;
      while (chp[len] != '\0' && !isspace(chp[len]))
      while (chp[len] != '\0' && !isspace(chp[len]))
        len++;
        len++;
      strings[nr_strings] = zalloc(len + 1);
      strings[nr_strings] = zalloc(len + 1);
      strncpy(strings[nr_strings], chp, len);
      strncpy(strings[nr_strings], chp, len);
      strings[nr_strings][len] = '\0';
      strings[nr_strings][len] = '\0';
      chp += len;
      chp += len;
    }
    }
    nr_strings++;
    nr_strings++;
    if (nr_strings > approx_nr_strings)
    if (nr_strings > approx_nr_strings)
      device_error(current, "String property %s badly formatted",
      device_error(current, "String property %s badly formatted",
                   property_name);
                   property_name);
  }
  }
  ASSERT(strings[nr_strings] == NULL); /* from zalloc */
  ASSERT(strings[nr_strings] == NULL); /* from zalloc */
 
 
  /* install it */
  /* install it */
  if (nr_strings == 0)
  if (nr_strings == 0)
    device_add_string_property(current, property_name, "");
    device_add_string_property(current, property_name, "");
  else if (nr_strings == 1)
  else if (nr_strings == 1)
    device_add_string_property(current, property_name, strings[0]);
    device_add_string_property(current, property_name, strings[0]);
  else {
  else {
    const char **specs = (const char**)strings; /* stop a bogus error */
    const char **specs = (const char**)strings; /* stop a bogus error */
    device_add_string_array_property(current, property_name,
    device_add_string_array_property(current, property_name,
                                     specs, nr_strings);
                                     specs, nr_strings);
  }
  }
 
 
  /* flush the created string */
  /* flush the created string */
  while (nr_strings > 0) {
  while (nr_strings > 0) {
    nr_strings--;
    nr_strings--;
    zfree(strings[nr_strings]);
    zfree(strings[nr_strings]);
  }
  }
  zfree(strings);
  zfree(strings);
}
}
 
 
 
 
/* <path-to-ihandle-device> */
/* <path-to-ihandle-device> */
 
 
STATIC_INLINE_TREE\
STATIC_INLINE_TREE\
(void)
(void)
parse_ihandle_property(device *current,
parse_ihandle_property(device *current,
                       const char *property,
                       const char *property,
                       const char *value)
                       const char *value)
{
{
  ihandle_runtime_property_spec ihandle;
  ihandle_runtime_property_spec ihandle;
 
 
  /* pass the full path */
  /* pass the full path */
  ihandle.full_path = value;
  ihandle.full_path = value;
 
 
  /* save this ready for the ihandle create */
  /* save this ready for the ihandle create */
  device_add_ihandle_runtime_property(current, property,
  device_add_ihandle_runtime_property(current, property,
                                      &ihandle);
                                      &ihandle);
}
}
 
 
 
 
 
 
EXTERN_TREE\
EXTERN_TREE\
(device *)
(device *)
tree_parse(device *current,
tree_parse(device *current,
           const char *fmt,
           const char *fmt,
           ...)
           ...)
{
{
  char device_specifier[1024];
  char device_specifier[1024];
  name_specifier spec;
  name_specifier spec;
 
 
  /* format the path */
  /* format the path */
  {
  {
    va_list ap;
    va_list ap;
    va_start(ap, fmt);
    va_start(ap, fmt);
    vsprintf(device_specifier, fmt, ap);
    vsprintf(device_specifier, fmt, ap);
    va_end(ap);
    va_end(ap);
    if (strlen(device_specifier) >= sizeof(device_specifier))
    if (strlen(device_specifier) >= sizeof(device_specifier))
      error("device_tree_add_deviced: buffer overflow\n");
      error("device_tree_add_deviced: buffer overflow\n");
  }
  }
 
 
  /* construct the tree down to the final device */
  /* construct the tree down to the final device */
  current = split_fill_path(current, device_specifier, &spec);
  current = split_fill_path(current, device_specifier, &spec);
 
 
  /* is there an interrupt spec */
  /* is there an interrupt spec */
  if (spec.property == NULL
  if (spec.property == NULL
      && spec.value != NULL) {
      && spec.value != NULL) {
    char *op = split_value(&spec);
    char *op = split_value(&spec);
    switch (op[0]) {
    switch (op[0]) {
    case '>':
    case '>':
      {
      {
        char *my_port_name = split_value(&spec);
        char *my_port_name = split_value(&spec);
        int my_port;
        int my_port;
        char *dest_port_name = split_value(&spec);
        char *dest_port_name = split_value(&spec);
        int dest_port;
        int dest_port;
        name_specifier dest_spec;
        name_specifier dest_spec;
        char *dest_device_name = split_value(&spec);
        char *dest_device_name = split_value(&spec);
        device *dest;
        device *dest;
        /* find my name */
        /* find my name */
        my_port = device_interrupt_decode(current, my_port_name,
        my_port = device_interrupt_decode(current, my_port_name,
                                          output_port);
                                          output_port);
        /* find the dest device and port */
        /* find the dest device and port */
        dest = split_fill_path(current, dest_device_name, &dest_spec);
        dest = split_fill_path(current, dest_device_name, &dest_spec);
        dest_port = device_interrupt_decode(dest, dest_port_name,
        dest_port = device_interrupt_decode(dest, dest_port_name,
                                            input_port);
                                            input_port);
        /* connect the two */
        /* connect the two */
        device_interrupt_attach(current,
        device_interrupt_attach(current,
                                my_port,
                                my_port,
                                dest,
                                dest,
                                dest_port,
                                dest_port,
                                permenant_object);
                                permenant_object);
      }
      }
      break;
      break;
    default:
    default:
      device_error(current, "unreconised interrupt spec %s\n", spec.value);
      device_error(current, "unreconised interrupt spec %s\n", spec.value);
      break;
      break;
    }
    }
  }
  }
 
 
  /* is there a property */
  /* is there a property */
  if (spec.property != NULL) {
  if (spec.property != NULL) {
    if (strcmp(spec.value, "true") == 0)
    if (strcmp(spec.value, "true") == 0)
      device_add_boolean_property(current, spec.property, 1);
      device_add_boolean_property(current, spec.property, 1);
    else if (strcmp(spec.value, "false") == 0)
    else if (strcmp(spec.value, "false") == 0)
      device_add_boolean_property(current, spec.property, 0);
      device_add_boolean_property(current, spec.property, 0);
    else {
    else {
      const device_property *property;
      const device_property *property;
      switch (spec.value[0]) {
      switch (spec.value[0]) {
      case '*':
      case '*':
        parse_ihandle_property(current, spec.property, spec.value + 1);
        parse_ihandle_property(current, spec.property, spec.value + 1);
        break;
        break;
      case '[':
      case '[':
        {
        {
          unsigned8 words[1024];
          unsigned8 words[1024];
          char *curr = spec.value + 1;
          char *curr = spec.value + 1;
          int nr_words = 0;
          int nr_words = 0;
          while (1) {
          while (1) {
            char *next;
            char *next;
            words[nr_words] = H2BE_1(strtoul(curr, &next, 0));
            words[nr_words] = H2BE_1(strtoul(curr, &next, 0));
            if (curr == next)
            if (curr == next)
              break;
              break;
            curr = next;
            curr = next;
            nr_words += 1;
            nr_words += 1;
          }
          }
          device_add_array_property(current, spec.property,
          device_add_array_property(current, spec.property,
                                    words, sizeof(words[0]) * nr_words);
                                    words, sizeof(words[0]) * nr_words);
        }
        }
        break;
        break;
      case '"':
      case '"':
        parse_string_property(current, spec.property, spec.value);
        parse_string_property(current, spec.property, spec.value);
        break;
        break;
      case '!':
      case '!':
        spec.value++;
        spec.value++;
        property = tree_find_property(current, spec.value);
        property = tree_find_property(current, spec.value);
        if (property == NULL)
        if (property == NULL)
          device_error(current, "property %s not found\n", spec.value);
          device_error(current, "property %s not found\n", spec.value);
        device_add_duplicate_property(current,
        device_add_duplicate_property(current,
                                      spec.property,
                                      spec.property,
                                      property);
                                      property);
        break;
        break;
      default:
      default:
        if (strcmp(spec.property, "reg") == 0
        if (strcmp(spec.property, "reg") == 0
            || strcmp(spec.property, "assigned-addresses") == 0
            || strcmp(spec.property, "assigned-addresses") == 0
            || strcmp(spec.property, "alternate-reg") == 0){
            || strcmp(spec.property, "alternate-reg") == 0){
          parse_reg_property(current, spec.property, spec.value);
          parse_reg_property(current, spec.property, spec.value);
        }
        }
        else if (strcmp(spec.property, "ranges") == 0) {
        else if (strcmp(spec.property, "ranges") == 0) {
          parse_ranges_property(current, spec.property, spec.value);
          parse_ranges_property(current, spec.property, spec.value);
        }
        }
        else if (isdigit(spec.value[0])
        else if (isdigit(spec.value[0])
                 || (spec.value[0] == '-' && isdigit(spec.value[1]))
                 || (spec.value[0] == '-' && isdigit(spec.value[1]))
                 || (spec.value[0] == '+' && isdigit(spec.value[1]))) {
                 || (spec.value[0] == '+' && isdigit(spec.value[1]))) {
          parse_integer_property(current, spec.property, spec.value);
          parse_integer_property(current, spec.property, spec.value);
        }
        }
        else
        else
          parse_string_property(current, spec.property, spec.value);
          parse_string_property(current, spec.property, spec.value);
        break;
        break;
      }
      }
    }
    }
  }
  }
  return current;
  return current;
}
}
 
 
 
 
INLINE_TREE\
INLINE_TREE\
(void)
(void)
tree_traverse(device *root,
tree_traverse(device *root,
              tree_traverse_function *prefix,
              tree_traverse_function *prefix,
              tree_traverse_function *postfix,
              tree_traverse_function *postfix,
              void *data)
              void *data)
{
{
  device *child;
  device *child;
  if (prefix != NULL)
  if (prefix != NULL)
    prefix(root, data);
    prefix(root, data);
  for (child = device_child(root);
  for (child = device_child(root);
       child != NULL;
       child != NULL;
       child = device_sibling(child)) {
       child = device_sibling(child)) {
    tree_traverse(child, prefix, postfix, data);
    tree_traverse(child, prefix, postfix, data);
  }
  }
  if (postfix != NULL)
  if (postfix != NULL)
    postfix(root, data);
    postfix(root, data);
}
}
 
 
 
 
STATIC_INLINE_TREE\
STATIC_INLINE_TREE\
(void)
(void)
print_address(device *bus,
print_address(device *bus,
              const device_unit *phys)
              const device_unit *phys)
{
{
  char unit[32];
  char unit[32];
  device_encode_unit(bus, phys, unit, sizeof(unit));
  device_encode_unit(bus, phys, unit, sizeof(unit));
  printf_filtered(" %s", unit);
  printf_filtered(" %s", unit);
}
}
 
 
STATIC_INLINE_TREE\
STATIC_INLINE_TREE\
(void)
(void)
print_size(device *bus,
print_size(device *bus,
           const device_unit *size)
           const device_unit *size)
{
{
  int i;
  int i;
  for (i = 0; i < size->nr_cells; i++)
  for (i = 0; i < size->nr_cells; i++)
    if (size->cells[i] != 0)
    if (size->cells[i] != 0)
      break;
      break;
  if (i < size->nr_cells) {
  if (i < size->nr_cells) {
    printf_filtered(" 0x%lx", (unsigned long)size->cells[i]);
    printf_filtered(" 0x%lx", (unsigned long)size->cells[i]);
    i++;
    i++;
    for (; i < size->nr_cells; i++)
    for (; i < size->nr_cells; i++)
      printf_filtered(",0x%lx", (unsigned long)size->cells[i]);
      printf_filtered(",0x%lx", (unsigned long)size->cells[i]);
  }
  }
  else
  else
    printf_filtered(" 0");
    printf_filtered(" 0");
}
}
 
 
STATIC_INLINE_TREE\
STATIC_INLINE_TREE\
(void)
(void)
print_reg_property(device *me,
print_reg_property(device *me,
                   const device_property *property)
                   const device_property *property)
{
{
  int reg_nr;
  int reg_nr;
  reg_property_spec reg;
  reg_property_spec reg;
  for (reg_nr = 0;
  for (reg_nr = 0;
       device_find_reg_array_property(me, property->name, reg_nr, &reg);
       device_find_reg_array_property(me, property->name, reg_nr, &reg);
       reg_nr++) {
       reg_nr++) {
    print_address(device_parent(me), &reg.address);
    print_address(device_parent(me), &reg.address);
    print_size(me, &reg.size);
    print_size(me, &reg.size);
  }
  }
}
}
 
 
STATIC_INLINE_TREE\
STATIC_INLINE_TREE\
(void)
(void)
print_ranges_property(device *me,
print_ranges_property(device *me,
                      const device_property *property)
                      const device_property *property)
{
{
  int range_nr;
  int range_nr;
  range_property_spec range;
  range_property_spec range;
  for (range_nr = 0;
  for (range_nr = 0;
       device_find_range_array_property(me, property->name, range_nr, &range);
       device_find_range_array_property(me, property->name, range_nr, &range);
       range_nr++) {
       range_nr++) {
    print_address(me, &range.child_address);
    print_address(me, &range.child_address);
    print_address(device_parent(me), &range.parent_address);
    print_address(device_parent(me), &range.parent_address);
    print_size(me, &range.size);
    print_size(me, &range.size);
  }
  }
}
}
 
 
STATIC_INLINE_TREE\
STATIC_INLINE_TREE\
(void)
(void)
print_string(const char *string)
print_string(const char *string)
{
{
  printf_filtered(" \"");
  printf_filtered(" \"");
  while (*string != '\0') {
  while (*string != '\0') {
    switch (*string) {
    switch (*string) {
    case '"':
    case '"':
      printf_filtered("\\\"");
      printf_filtered("\\\"");
      break;
      break;
    case '\\':
    case '\\':
      printf_filtered("\\\\");
      printf_filtered("\\\\");
      break;
      break;
    default:
    default:
      printf_filtered("%c", *string);
      printf_filtered("%c", *string);
      break;
      break;
    }
    }
    string++;
    string++;
  }
  }
  printf_filtered("\"");
  printf_filtered("\"");
}
}
 
 
STATIC_INLINE_TREE\
STATIC_INLINE_TREE\
(void)
(void)
print_string_array_property(device *me,
print_string_array_property(device *me,
                            const device_property *property)
                            const device_property *property)
{
{
  int nr;
  int nr;
  string_property_spec string;
  string_property_spec string;
  for (nr = 0;
  for (nr = 0;
       device_find_string_array_property(me, property->name, nr, &string);
       device_find_string_array_property(me, property->name, nr, &string);
       nr++) {
       nr++) {
    print_string(string);
    print_string(string);
  }
  }
}
}
 
 
STATIC_INLINE_TREE\
STATIC_INLINE_TREE\
(void)
(void)
print_properties(device *me)
print_properties(device *me)
{
{
  const device_property *property;
  const device_property *property;
  for (property = device_find_property(me, NULL);
  for (property = device_find_property(me, NULL);
       property != NULL;
       property != NULL;
       property = device_next_property(property)) {
       property = device_next_property(property)) {
    printf_filtered("%s/%s", device_path(me), property->name);
    printf_filtered("%s/%s", device_path(me), property->name);
    if (property->original != NULL) {
    if (property->original != NULL) {
      printf_filtered(" !");
      printf_filtered(" !");
      printf_filtered("%s/%s",
      printf_filtered("%s/%s",
                      device_path(property->original->owner),
                      device_path(property->original->owner),
                      property->original->name);
                      property->original->name);
    }
    }
    else {
    else {
      switch (property->type) {
      switch (property->type) {
      case array_property:
      case array_property:
        if ((property->sizeof_array % sizeof(signed_cell)) == 0) {
        if ((property->sizeof_array % sizeof(signed_cell)) == 0) {
          unsigned_cell *w = (unsigned_cell*)property->array;
          unsigned_cell *w = (unsigned_cell*)property->array;
          int cell_nr;
          int cell_nr;
          for (cell_nr = 0;
          for (cell_nr = 0;
               cell_nr < (property->sizeof_array / sizeof(unsigned_cell));
               cell_nr < (property->sizeof_array / sizeof(unsigned_cell));
               cell_nr++) {
               cell_nr++) {
            printf_filtered(" 0x%lx", (unsigned long)BE2H_cell(w[cell_nr]));
            printf_filtered(" 0x%lx", (unsigned long)BE2H_cell(w[cell_nr]));
          }
          }
        }
        }
        else {
        else {
          unsigned8 *w = (unsigned8*)property->array;
          unsigned8 *w = (unsigned8*)property->array;
          printf_filtered(" [");
          printf_filtered(" [");
          while ((char*)w - (char*)property->array < property->sizeof_array) {
          while ((char*)w - (char*)property->array < property->sizeof_array) {
            printf_filtered(" 0x%2x", BE2H_1(*w));
            printf_filtered(" 0x%2x", BE2H_1(*w));
            w++;
            w++;
          }
          }
        }
        }
        break;
        break;
      case boolean_property:
      case boolean_property:
        {
        {
          int b = device_find_boolean_property(me, property->name);
          int b = device_find_boolean_property(me, property->name);
          printf_filtered(" %s", b ? "true"  : "false");
          printf_filtered(" %s", b ? "true"  : "false");
        }
        }
        break;
        break;
      case ihandle_property:
      case ihandle_property:
        {
        {
          if (property->array != NULL) {
          if (property->array != NULL) {
            device_instance *instance = device_find_ihandle_property(me, property->name);
            device_instance *instance = device_find_ihandle_property(me, property->name);
            printf_filtered(" *%s", device_instance_path(instance));
            printf_filtered(" *%s", device_instance_path(instance));
          }
          }
          else {
          else {
            /* not yet initialized, ask the device for the path */
            /* not yet initialized, ask the device for the path */
            ihandle_runtime_property_spec spec;
            ihandle_runtime_property_spec spec;
            device_find_ihandle_runtime_property(me, property->name, &spec);
            device_find_ihandle_runtime_property(me, property->name, &spec);
            printf_filtered(" *%s", spec.full_path);
            printf_filtered(" *%s", spec.full_path);
          }
          }
        }
        }
        break;
        break;
      case integer_property:
      case integer_property:
        {
        {
          unsigned_word w = device_find_integer_property(me, property->name);
          unsigned_word w = device_find_integer_property(me, property->name);
          printf_filtered(" 0x%lx", (unsigned long)w);
          printf_filtered(" 0x%lx", (unsigned long)w);
        }
        }
        break;
        break;
      case range_array_property:
      case range_array_property:
        print_ranges_property(me, property);
        print_ranges_property(me, property);
        break;
        break;
      case reg_array_property:
      case reg_array_property:
        print_reg_property(me, property);
        print_reg_property(me, property);
        break;
        break;
      case string_property:
      case string_property:
        {
        {
          const char *s = device_find_string_property(me, property->name);
          const char *s = device_find_string_property(me, property->name);
          print_string(s);
          print_string(s);
        }
        }
        break;
        break;
      case string_array_property:
      case string_array_property:
        print_string_array_property(me, property);
        print_string_array_property(me, property);
        break;
        break;
      }
      }
    }
    }
    printf_filtered("\n");
    printf_filtered("\n");
  }
  }
}
}
 
 
STATIC_INLINE_TREE\
STATIC_INLINE_TREE\
(void)
(void)
print_interrupts(device *me,
print_interrupts(device *me,
                 int my_port,
                 int my_port,
                 device *dest,
                 device *dest,
                 int dest_port,
                 int dest_port,
                 void *ignore_or_null)
                 void *ignore_or_null)
{
{
  char src[32];
  char src[32];
  char dst[32];
  char dst[32];
  device_interrupt_encode(me, my_port, src, sizeof(src), output_port);
  device_interrupt_encode(me, my_port, src, sizeof(src), output_port);
  device_interrupt_encode(dest, dest_port, dst, sizeof(dst), input_port);
  device_interrupt_encode(dest, dest_port, dst, sizeof(dst), input_port);
  printf_filtered("%s > %s %s %s\n",
  printf_filtered("%s > %s %s %s\n",
                  device_path(me),
                  device_path(me),
                  src, dst,
                  src, dst,
                  device_path(dest));
                  device_path(dest));
}
}
 
 
STATIC_INLINE_TREE\
STATIC_INLINE_TREE\
(void)
(void)
print_device(device *me,
print_device(device *me,
             void *ignore_or_null)
             void *ignore_or_null)
{
{
  printf_filtered("%s\n", device_path(me));
  printf_filtered("%s\n", device_path(me));
  print_properties(me);
  print_properties(me);
  device_interrupt_traverse(me, print_interrupts, NULL);
  device_interrupt_traverse(me, print_interrupts, NULL);
}
}
 
 
INLINE_TREE\
INLINE_TREE\
(void)
(void)
tree_print(device *root)
tree_print(device *root)
{
{
  tree_traverse(root,
  tree_traverse(root,
                print_device, NULL,
                print_device, NULL,
                NULL);
                NULL);
}
}
 
 
 
 
INLINE_TREE\
INLINE_TREE\
(void)
(void)
tree_usage(int verbose)
tree_usage(int verbose)
{
{
  if (verbose == 1) {
  if (verbose == 1) {
    printf_filtered("\n");
    printf_filtered("\n");
    printf_filtered("A device/property specifier has the form:\n");
    printf_filtered("A device/property specifier has the form:\n");
    printf_filtered("\n");
    printf_filtered("\n");
    printf_filtered("  /path/to/a/device [ property-value ]\n");
    printf_filtered("  /path/to/a/device [ property-value ]\n");
    printf_filtered("\n");
    printf_filtered("\n");
    printf_filtered("and a possible device is\n");
    printf_filtered("and a possible device is\n");
    printf_filtered("\n");
    printf_filtered("\n");
  }
  }
  if (verbose > 1) {
  if (verbose > 1) {
    printf_filtered("\n");
    printf_filtered("\n");
    printf_filtered("A device/property specifier (<spec>) has the format:\n");
    printf_filtered("A device/property specifier (<spec>) has the format:\n");
    printf_filtered("\n");
    printf_filtered("\n");
    printf_filtered("  <spec> ::= <path> [ <value> ] ;\n");
    printf_filtered("  <spec> ::= <path> [ <value> ] ;\n");
    printf_filtered("  <path> ::= { <prefix> } { <node> \"/\" } <node> ;\n");
    printf_filtered("  <path> ::= { <prefix> } { <node> \"/\" } <node> ;\n");
    printf_filtered("  <prefix> ::= ( | \"/\" | \"../\" | \"./\" ) ;\n");
    printf_filtered("  <prefix> ::= ( | \"/\" | \"../\" | \"./\" ) ;\n");
    printf_filtered("  <node> ::= <name> [ \"@\" <unit> ] [ \":\" <args> ] ;\n");
    printf_filtered("  <node> ::= <name> [ \"@\" <unit> ] [ \":\" <args> ] ;\n");
    printf_filtered("  <unit> ::= <number> { \",\" <number> } ;\n");
    printf_filtered("  <unit> ::= <number> { \",\" <number> } ;\n");
    printf_filtered("\n");
    printf_filtered("\n");
    printf_filtered("Where:\n");
    printf_filtered("Where:\n");
    printf_filtered("\n");
    printf_filtered("\n");
    printf_filtered("  <name>  is the name of a device (list below)\n");
    printf_filtered("  <name>  is the name of a device (list below)\n");
    printf_filtered("  <unit>  is the unit-address relative to the parent bus\n");
    printf_filtered("  <unit>  is the unit-address relative to the parent bus\n");
    printf_filtered("  <args>  additional arguments used when creating the device\n");
    printf_filtered("  <args>  additional arguments used when creating the device\n");
    printf_filtered("  <value> ::= ( <number> # integer property\n");
    printf_filtered("  <value> ::= ( <number> # integer property\n");
    printf_filtered("              | \"[\" { <number> } # array property (byte)\n");
    printf_filtered("              | \"[\" { <number> } # array property (byte)\n");
    printf_filtered("              | \"{\" { <number> } # array property (cell)\n");
    printf_filtered("              | \"{\" { <number> } # array property (cell)\n");
    printf_filtered("              | [ \"true\" | \"false\" ] # boolean property\n");
    printf_filtered("              | [ \"true\" | \"false\" ] # boolean property\n");
    printf_filtered("              | \"*\" <path> # ihandle property\n");
    printf_filtered("              | \"*\" <path> # ihandle property\n");
    printf_filtered("              | \"!\" <path> # copy property\n");
    printf_filtered("              | \"!\" <path> # copy property\n");
    printf_filtered("              | \">\" [ <number> ] <path> # attach interrupt\n");
    printf_filtered("              | \">\" [ <number> ] <path> # attach interrupt\n");
    printf_filtered("              | \"<\" <path> # attach child interrupt\n");
    printf_filtered("              | \"<\" <path> # attach child interrupt\n");
    printf_filtered("              | \"\\\"\" <text> # string property\n");
    printf_filtered("              | \"\\\"\" <text> # string property\n");
    printf_filtered("              | <text> # string property\n");
    printf_filtered("              | <text> # string property\n");
    printf_filtered("              ) ;\n");
    printf_filtered("              ) ;\n");
    printf_filtered("\n");
    printf_filtered("\n");
    printf_filtered("And the following are valid device names:\n");
    printf_filtered("And the following are valid device names:\n");
    printf_filtered("\n");
    printf_filtered("\n");
  }
  }
}
}
 
 
 
 
 
 
INLINE_TREE\
INLINE_TREE\
(device_instance *)
(device_instance *)
tree_instance(device *root,
tree_instance(device *root,
              const char *device_specifier)
              const char *device_specifier)
{
{
  /* find the device node */
  /* find the device node */
  device *me;
  device *me;
  name_specifier spec;
  name_specifier spec;
  if (!split_device_specifier(root, device_specifier, &spec))
  if (!split_device_specifier(root, device_specifier, &spec))
    return NULL;
    return NULL;
  me = split_find_device(root, &spec);
  me = split_find_device(root, &spec);
  if (spec.name != NULL)
  if (spec.name != NULL)
    return NULL;
    return NULL;
  /* create the instance */
  /* create the instance */
  return device_create_instance(me, device_specifier, spec.last_args);
  return device_create_instance(me, device_specifier, spec.last_args);
}
}
 
 
 
 
INLINE_TREE\
INLINE_TREE\
(device *)
(device *)
tree_find_device(device *root,
tree_find_device(device *root,
                 const char *path_to_device)
                 const char *path_to_device)
{
{
  device *node;
  device *node;
  name_specifier spec;
  name_specifier spec;
 
 
  /* parse the path */
  /* parse the path */
  split_device_specifier(root, path_to_device, &spec);
  split_device_specifier(root, path_to_device, &spec);
  if (spec.value != NULL)
  if (spec.value != NULL)
    return NULL; /* something wierd */
    return NULL; /* something wierd */
 
 
  /* now find it */
  /* now find it */
  node = split_find_device(root, &spec);
  node = split_find_device(root, &spec);
  if (spec.name != NULL)
  if (spec.name != NULL)
    return NULL; /* not a leaf */
    return NULL; /* not a leaf */
 
 
  return node;
  return node;
}
}
 
 
 
 
INLINE_TREE\
INLINE_TREE\
(const device_property *)
(const device_property *)
tree_find_property(device *root,
tree_find_property(device *root,
                   const char *path_to_property)
                   const char *path_to_property)
{
{
  name_specifier spec;
  name_specifier spec;
  if (!split_property_specifier(root, path_to_property, &spec))
  if (!split_property_specifier(root, path_to_property, &spec))
    device_error(root, "Invalid property path %s", path_to_property);
    device_error(root, "Invalid property path %s", path_to_property);
  root = split_find_device(root, &spec);
  root = split_find_device(root, &spec);
  return device_find_property(root, spec.property);
  return device_find_property(root, spec.property);
}
}
 
 
INLINE_TREE\
INLINE_TREE\
(int)
(int)
tree_find_boolean_property(device *root,
tree_find_boolean_property(device *root,
                           const char *path_to_property)
                           const char *path_to_property)
{
{
  name_specifier spec;
  name_specifier spec;
  if (!split_property_specifier(root, path_to_property, &spec))
  if (!split_property_specifier(root, path_to_property, &spec))
    device_error(root, "Invalid property path %s", path_to_property);
    device_error(root, "Invalid property path %s", path_to_property);
  root = split_find_device(root, &spec);
  root = split_find_device(root, &spec);
  return device_find_boolean_property(root, spec.property);
  return device_find_boolean_property(root, spec.property);
}
}
 
 
INLINE_TREE\
INLINE_TREE\
(signed_cell)
(signed_cell)
tree_find_integer_property(device *root,
tree_find_integer_property(device *root,
                           const char *path_to_property)
                           const char *path_to_property)
{
{
  name_specifier spec;
  name_specifier spec;
  if (!split_property_specifier(root, path_to_property, &spec))
  if (!split_property_specifier(root, path_to_property, &spec))
    device_error(root, "Invalid property path %s", path_to_property);
    device_error(root, "Invalid property path %s", path_to_property);
  root = split_find_device(root, &spec);
  root = split_find_device(root, &spec);
  return device_find_integer_property(root, spec.property);
  return device_find_integer_property(root, spec.property);
}
}
 
 
INLINE_TREE\
INLINE_TREE\
(device_instance *)
(device_instance *)
tree_find_ihandle_property(device *root,
tree_find_ihandle_property(device *root,
                           const char *path_to_property)
                           const char *path_to_property)
{
{
  name_specifier spec;
  name_specifier spec;
  if (!split_property_specifier(root, path_to_property, &spec))
  if (!split_property_specifier(root, path_to_property, &spec))
    device_error(root, "Invalid property path %s", path_to_property);
    device_error(root, "Invalid property path %s", path_to_property);
  root = split_find_device(root, &spec);
  root = split_find_device(root, &spec);
  return device_find_ihandle_property(root, spec.property);
  return device_find_ihandle_property(root, spec.property);
}
}
 
 
INLINE_TREE\
INLINE_TREE\
(const char *)
(const char *)
tree_find_string_property(device *root,
tree_find_string_property(device *root,
                          const char *path_to_property)
                          const char *path_to_property)
{
{
  name_specifier spec;
  name_specifier spec;
  if (!split_property_specifier(root, path_to_property, &spec))
  if (!split_property_specifier(root, path_to_property, &spec))
    device_error(root, "Invalid property path %s", path_to_property);
    device_error(root, "Invalid property path %s", path_to_property);
  root = split_find_device(root, &spec);
  root = split_find_device(root, &spec);
  return device_find_string_property(root, spec.property);
  return device_find_string_property(root, spec.property);
}
}
 
 
 
 
#endif /* _PARSE_C_ */
#endif /* _PARSE_C_ */
 
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.