sim: ppc: netbsd: Sync errno codes with NetBSD 9.99.49
[deliverable/binutils-gdb.git] / sim / ppc / device.c
index 5dc69cb2498745a02a32f87a1991fa976d65b914..d5093bbdadb192c0c8b83871d4e95d530fb646ac 100644 (file)
@@ -1,10 +1,10 @@
 /*  This file is part of the program psim.
 
-    Copyright (C) 1994-1995, 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
     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 3 of the License, or
     (at your option) any later version.
 
     This program is distributed in the hope that it will be useful,
@@ -13,8 +13,7 @@
     GNU General Public License for more details.
  
     You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+    along with this program; if not, see <http://www.gnu.org/licenses/>.
  
     */
 
 #include <stdio.h>
 
 #include "device_table.h"
+#include "cap.h"
+
+#include "events.h"
+#include "psim.h"
 
 #ifdef HAVE_STDLIB_H
 #include <stdlib.h>
 
 #include <ctype.h>
 
+STATIC_INLINE_DEVICE (void) clean_device_properties(device *);
 
+/* property entries */
 
 typedef struct _device_property_entry device_property_entry;
 struct _device_property_entry {
-  const char *name;
   device_property_entry *next;
   device_property *value;
+  const void *init_array;
+  unsigned sizeof_init_array;
+};
+
+
+/* Interrupt edges */
+
+typedef struct _device_interrupt_edge device_interrupt_edge;
+struct _device_interrupt_edge {
+  int my_port;
+  device *dest;
+  int dest_port;
+  device_interrupt_edge *next;
+  object_disposition disposition;
 };
 
+STATIC_INLINE_DEVICE\
+(void)
+attach_device_interrupt_edge(device_interrupt_edge **list,
+                            int my_port,
+                            device *dest,
+                            int dest_port,
+                            object_disposition disposition)
+{
+  device_interrupt_edge *new_edge = ZALLOC(device_interrupt_edge);
+  new_edge->my_port = my_port;
+  new_edge->dest = dest;
+  new_edge->dest_port = dest_port;
+  new_edge->next = *list;
+  new_edge->disposition = disposition;
+  *list = new_edge;
+}
+
+STATIC_INLINE_DEVICE\
+(void)
+detach_device_interrupt_edge(device *me,
+                            device_interrupt_edge **list,
+                            int my_port,
+                            device *dest,
+                            int dest_port)
+{
+  while (*list != NULL) {
+    device_interrupt_edge *old_edge = *list;
+    if (old_edge->dest == dest
+       && old_edge->dest_port == dest_port
+       && old_edge->my_port == my_port) {
+      if (old_edge->disposition == permenant_object)
+       device_error(me, "attempt to delete permenant interrupt");
+      *list = old_edge->next;
+      free(old_edge);
+      return;
+    }
+  }
+  device_error(me, "attempt to delete unattached interrupt");
+}
+
+STATIC_INLINE_DEVICE\
+(void)
+clean_device_interrupt_edges(device_interrupt_edge **list)
+{
+  while (*list != NULL) {
+    device_interrupt_edge *old_edge = *list;
+    switch (old_edge->disposition) {
+    case permenant_object:
+      list = &old_edge->next;
+      break;
+    case tempoary_object:
+      *list = old_edge->next;
+      free(old_edge);
+      break;
+    }
+  }
+}
+
 
 /* A device */
+
 struct _device {
+
   /* my name is ... */
   const char *name;
-  const char *full_name;
+  device_unit unit_address;
+  const char *path;
+  int nr_address_cells;
+  int nr_size_cells;
+
   /* device tree */
   device *parent;
   device *children;
   device *sibling;
-  /* hw/sw callbacks */
+
+  /* its template methods */
   void *data; /* device specific data */
   const device_callbacks *callback;
+
   /* device properties */
   device_property_entry *properties;
+
+  /* interrupts */
+  device_interrupt_edge *interrupt_destinations;
+
+  /* any open instances of this device */
+  device_instance *instances;
+
+  /* the internal/external mappings and other global requirements */
+  cap *ihandles;
+  cap *phandles;
+  psim *system;
+
+  /* debugging */
+  int trace;
+};
+
+
+/* an instance of a device */
+struct _device_instance {
+  void *data;
+  char *args;
+  char *path;
+  const device_instance_callbacks *callback;
+  /* the root instance */
+  device *owner;
+  device_instance *next;
+  /* interposed instance */
+  device_instance *parent;
+  device_instance *child;
 };
 
 
-device INLINE_DEVICE *
-device_create(const char *name,
-             device *parent)
+\f
+/* creation */
+
+STATIC_INLINE_DEVICE\
+(const char *)
+device_full_name(device *leaf,
+                 char *buf,
+                 unsigned sizeof_buf)
 {
-  device_descriptor *descr;
-  int name_len;
-  char *chp;
-  chp = strchr(name, '@');
-  name_len = (chp == NULL ? strlen(name) : chp - name);
-  for (descr = device_table; descr->name != NULL; descr++) {
-    if (strncmp(name, descr->name, name_len) == 0
-       && (descr->name[name_len] == '\0'
-           || descr->name[name_len] == '@')) {
-      void *data = (descr->creator != NULL
-                   ? descr->creator(name, parent)
-                   : NULL);
-      return device_create_from(name, data, descr->callbacks, parent);
-    }
+  /* get a buffer */
+  char full_name[1024];
+  if (buf == (char*)0) {
+    buf = full_name;
+    sizeof_buf = sizeof(full_name);
   }
-  error("device_create() unknown device %s\n", name);
-  return NULL;
+
+  /* construct a name */
+  if (leaf->parent == NULL) {
+    if (sizeof_buf < 1)
+      error("device_full_name: buffer overflow");
+    *buf = '\0';
+  }
+  else {
+    char unit[1024];
+    device_full_name(leaf->parent, buf, sizeof_buf);
+    if (leaf->parent != NULL
+        && device_encode_unit(leaf->parent,
+                              &leaf->unit_address,
+                              unit+1,
+                              sizeof(unit)-1) > 0)
+      unit[0] = '@';
+    else
+      unit[0] = '\0';
+    if (strlen(buf) + strlen("/") + strlen(leaf->name) + strlen(unit)
+        >= sizeof_buf)
+      error("device_full_name: buffer overflow");
+    strcat(buf, "/");
+    strcat(buf, leaf->name);
+    strcat (buf, unit);
+  }
+  
+  /* return it usefully */
+  if (buf == full_name)
+    buf = (char *) strdup(full_name);
+  return buf;
 }
 
-device INLINE_DEVICE *
+STATIC_INLINE_DEVICE\
+(device *)
 device_create_from(const char *name,
+                  const device_unit *unit_address,
                   void *data,
                   const device_callbacks *callbacks,
                   device *parent)
 {
   device *new_device = ZALLOC(device);
+
+  /* insert it into the device tree */
+  new_device->parent = parent;
+  new_device->children = NULL;
+  if (parent != NULL) {
+    device **sibling = &parent->children;
+    while ((*sibling) != NULL)
+      sibling = &(*sibling)->sibling;
+    *sibling = new_device;
+  }
+
+  /* give it a name */
+  new_device->name = (char *) strdup(name);
+  new_device->unit_address = *unit_address;
+  new_device->path = device_full_name(new_device, NULL, 0);
+
+  /* its template */
   new_device->data = data;
-  new_device->name = strdup(name);
   new_device->callback = callbacks;
-  new_device->parent = parent;
+
+  /* its properties - already null */
+  /* interrupts - already null */
+
+  /* mappings - if needed */
+  if (parent == NULL) {
+    new_device->ihandles = cap_create(name);
+    new_device->phandles = cap_create(name);
+  }
+  else {
+    new_device->ihandles = device_root(parent)->ihandles;
+    new_device->phandles = device_root(parent)->phandles;
+  }
+
+  cap_add(new_device->phandles, new_device);
   return new_device;
 }
 
 
-device INLINE_DEVICE *
-device_parent(device *me)
+
+INLINE_DEVICE\
+(device *)
+device_create(device *parent,
+             const char *base,
+             const char *name,
+             const char *unit_address,
+             const char *args)
 {
-  return me->parent;
+  const device_descriptor *const *table;
+  for (table = device_table; *table != NULL; table++) {
+    const device_descriptor *descr;
+    for (descr = *table; descr->name != NULL; descr++) {
+      if (strcmp(base, descr->name) == 0) {
+       device_unit address = { 0 };
+       void *data = NULL;
+       if (parent != NULL)
+         if (device_decode_unit(parent, unit_address, &address) < 0)
+           device_error(parent, "invalid address %s for device %s",
+                        unit_address, name);
+       if (descr->creator != NULL)
+         data = descr->creator(name, &address, args);
+       return device_create_from(name, &address, data,
+                                 descr->callbacks, parent);
+      }
+    }
+  }
+  device_error(parent, "attempt to attach unknown device %s", name);
+  return NULL;
 }
 
-const char INLINE_DEVICE *
-device_name(device *me)
+
+
+INLINE_DEVICE\
+(void)
+device_usage(int verbose)
 {
-  return me->name;
+  const device_descriptor *const *table;
+  if (verbose == 1) {
+    int pos = 0;
+    for (table = device_table; *table != NULL; table++) {
+      const device_descriptor *descr;
+      for (descr = *table; descr->name != NULL; descr++) {
+       pos += strlen(descr->name) + 2;
+       if (pos > 75) {
+         pos = strlen(descr->name) + 2;
+         printf_filtered("\n");
+       }
+       printf_filtered("  %s", descr->name);
+      }
+      printf_filtered("\n");
+    }
+  }
+  if (verbose > 1) {
+    for (table = device_table; *table != NULL; table++) {
+      const device_descriptor *descr;
+      for (descr = *table; descr->name != NULL; descr++) {
+       printf_filtered("  %s:\n", descr->name);
+       /* interrupt ports */
+       if (descr->callbacks->interrupt.ports != NULL) {
+         const device_interrupt_port_descriptor *ports =
+           descr->callbacks->interrupt.ports;
+         printf_filtered("    interrupt ports:");
+         while (ports->name != NULL) {
+           printf_filtered(" %s", ports->name);
+           ports++;
+         }
+         printf_filtered("\n");
+       }
+       /* general info */
+       if (descr->callbacks->usage != NULL)
+         descr->callbacks->usage(verbose);
+      }
+    }
+  }
 }
 
-void INLINE_DEVICE *
-device_data(device *me)
+
+
+\f
+/* Device node: */
+
+INLINE_DEVICE\
+(device *)
+device_parent(device *me)
 {
-  return me->data;
+  return me->parent;
 }
 
-void INLINE_DEVICE
-device_traverse_properties(device *me,
-                          device_traverse_property_function *traverse,
-                          void *data)
+INLINE_DEVICE\
+(device *)
+device_root(device *me)
 {
-  device_property_entry *entry = me->properties;
-  while (entry != NULL) {
-    traverse(me, entry->name, data);
-    entry = entry->next;
-  }
+  ASSERT(me != NULL);
+  while (me->parent != NULL)
+    me = me->parent;
+  return me;
 }
 
-void INLINE_DEVICE
-device_init(device *me,
-           psim *system)
+INLINE_DEVICE\
+(device *)
+device_sibling(device *me)
 {
-  me->callback->init(me, system);
+  return me->sibling;
 }
 
-void INLINE_DEVICE
-device_attach_address(device *me,
-                     const char *name,
-                     attach_type attach,
-                     int space,
-                     unsigned_word addr,
-                     unsigned nr_bytes,
-                     access_type access,
-                     device *who) /*callback/default*/
+INLINE_DEVICE\
+(device *)
+device_child(device *me)
 {
-  me->callback->attach_address(me, name, attach, space,
-                               addr, nr_bytes, access, who);
+  return me->children;
 }
 
-void INLINE_DEVICE
-device_detach_address(device *me,
-                     const char *name,
-                     attach_type attach,
-                     int space,
-                     unsigned_word addr,
-                     unsigned nr_bytes,
-                     access_type access,
-                     device *who) /*callback/default*/
+INLINE_DEVICE\
+(const char *)
+device_name(device *me)
 {
-  me->callback->detach_address(me, name, attach, space,
-                               addr, nr_bytes, access, who);
+  return me->name;
 }
 
-unsigned INLINE_DEVICE
-device_io_read_buffer(device *me,
-                     void *dest,
-                     int space,
-                     unsigned_word addr,
-                     unsigned nr_bytes,
-                     cpu *processor,
-                     unsigned_word cia)
+INLINE_DEVICE\
+(const char *)
+device_path(device *me)
 {
-  return me->callback->io_read_buffer(me, dest, space,
-                                      addr, nr_bytes,
-                                      processor, cia);
+  return me->path;
 }
 
-unsigned INLINE_DEVICE
-device_io_write_buffer(device *me,
-                      const void *source,
-                      int space,
-                      unsigned_word addr,
-                      unsigned nr_bytes,
-                      cpu *processor,
-                      unsigned_word cia)
+INLINE_DEVICE\
+(void *)
+device_data(device *me)
 {
-  return me->callback->io_write_buffer(me, source, space,
-                                      addr, nr_bytes,
-                                      processor, cia);
+  return me->data;
 }
 
-unsigned INLINE_DEVICE
-device_dma_read_buffer(device *me,
-                      void *dest,
-                      int space,
-                      unsigned_word addr,
-                      unsigned nr_bytes)
+INLINE_DEVICE\
+(psim *)
+device_system(device *me)
 {
-  return me->callback->dma_read_buffer(me, dest, space,
-                                      addr, nr_bytes);
+  return me->system;
 }
 
-unsigned INLINE_DEVICE
-device_dma_write_buffer(device *me,
-                       const void *source,
-                       int space,
-                       unsigned_word addr,
-                       unsigned nr_bytes,
-                       int violate_read_only_section)
+INLINE_DEVICE\
+(const device_unit *)
+device_unit_address(device *me)
 {
-  return me->callback->dma_write_buffer(me, source, space,
-                                       addr, nr_bytes,
-                                       violate_read_only_section);
+  return &me->unit_address;
 }
 
-void INLINE_DEVICE
-device_attach_interrupt(device *me,
-                       device *who,
-                       int interrupt_line,
-                       const char *name)
+
+INLINE_DEVICE\
+(int)
+device_address_to_attach_address(device *me,
+                                const device_unit *address,
+                                int *attach_space,
+                                unsigned_word *attach_address,
+                                device *client)
 {
-  me->callback->attach_interrupt(me, who, interrupt_line, name);
+  if (me->callback->convert.address_to_attach_address == NULL)
+    device_error(me, "no convert.address_to_attach_address method");
+  return me->callback->convert.address_to_attach_address(me, address, attach_space, attach_address, client);
 }
 
-void INLINE_DEVICE
-device_detach_interrupt(device *me,
-                       device *who,
-                       int interrupt_line,
-                       const char *name)
+
+INLINE_DEVICE\
+(int)
+device_size_to_attach_size(device *me,
+                          const device_unit *size,
+                          unsigned *nr_bytes,
+                          device *client)
 {
-  me->callback->detach_interrupt(me, who, interrupt_line, name);
+  if (me->callback->convert.size_to_attach_size == NULL)
+    device_error(me, "no convert.size_to_attach_size method");
+  return me->callback->convert.size_to_attach_size(me, size, nr_bytes, client);
 }
 
-void INLINE_DEVICE
-device_interrupt(device *me,
-                device *who,
-                int interrupt_line,
-                int interrupt_status,
-                cpu *processor,
-                unsigned_word cia)
+
+INLINE_DEVICE\
+(int)
+device_decode_unit(device *bus,
+                  const char *unit,
+                  device_unit *address)
 {
-  me->callback->interrupt(me, who, interrupt_line, interrupt_status,
-                          processor, cia);
+  if (bus->callback->convert.decode_unit == NULL)
+    device_error(bus, "no convert.decode_unit method");
+  return bus->callback->convert.decode_unit(bus, unit, address);
 }
 
-void INLINE_DEVICE
-device_interrupt_ack(device *me,
-                    int interrupt_line,
-                    int interrupt_status)
+
+INLINE_DEVICE\
+(int)
+device_encode_unit(device *bus,
+                  const device_unit *unit_address,
+                  char *buf,
+                  int sizeof_buf)
 {
-  me->callback->interrupt_ack(me, interrupt_line, interrupt_status);
+  if (bus->callback->convert.encode_unit == NULL)
+    device_error(bus, "no convert.encode_unit method");
+  return bus->callback->convert.encode_unit(bus, unit_address, buf, sizeof_buf);
 }
 
-void EXTERN_DEVICE
-device_ioctl(device *me,
-            psim *system,
-            cpu *processor,
-            unsigned_word cia,
-            ...)
+INLINE_DEVICE\
+(unsigned)
+device_nr_address_cells(device *me)
 {
-  va_list ap;
-  va_start(ap, cia);
-  me->callback->ioctl(me, system, processor, cia, ap);
-  va_end(ap);
+  if (me->nr_address_cells == 0) {
+    if (device_find_property(me, "#address-cells") != NULL)
+      me->nr_address_cells = device_find_integer_property(me, "#address-cells");
+    else
+      me->nr_address_cells = 2;
+  }
+  return me->nr_address_cells;
 }
-      
 
-/* Manipulate properties attached to devices */
+INLINE_DEVICE\
+(unsigned)
+device_nr_size_cells(device *me)
+{
+  if (me->nr_size_cells == 0) {
+    if (device_find_property(me, "#size-cells") != NULL)
+      me->nr_size_cells = device_find_integer_property(me, "#size-cells");
+    else
+      me->nr_size_cells = 1;
+  }
+  return me->nr_size_cells;
+}
 
-device_property STATIC_INLINE_DEVICE *
-device_add_property(device *me,
-                   const char *property,
-                   device_property_type type,
-                   const void *array,
-                   int sizeof_array)
+
+\f
+/* device-instance: */
+
+INLINE_DEVICE\
+(device_instance *)
+device_create_instance_from(device *me,
+                           device_instance *parent,
+                           void *data,
+                           const char *path,
+                           const char *args,
+                           const device_instance_callbacks *callbacks)
 {
-  device_property_entry *new_entry = 0;
-  device_property *new_value = 0;
-  void *new_array = 0;
-  /* find the list end */
-  device_property_entry **insertion_point = &me->properties;
-  while (*insertion_point != NULL) {
-    if (strcmp((**insertion_point).name, property) == 0)
-      return (**insertion_point).value;
-    insertion_point = &(**insertion_point).next;
+  device_instance *instance = ZALLOC(device_instance);
+  if ((me == NULL) == (parent == NULL))
+    device_error(me, "can't have both parent instance and parent device");
+  /*instance->unit*/
+  /* link this instance into the devices list */
+  if (me != NULL) {
+    ASSERT(parent == NULL);
+    instance->owner = me;
+    instance->parent = NULL;
+    /* link this instance into the front of the devices instance list */
+    instance->next = me->instances;
+    me->instances = instance;
   }
-  /* alloc data for the new property */
-  new_entry = ZALLOC(device_property_entry);
-  new_value = ZALLOC(device_property);
-  new_array = (sizeof_array > 0
-              ? zalloc(sizeof_array)
-              : (void*)0);
-  /* insert the new property into the list */
-  *insertion_point = new_entry;
-  new_entry->name = strdup(property);
-  new_entry->value = new_value;
-  new_value->type = type;
-  new_value->sizeof_array = sizeof_array;
-  new_value->array = new_array;
-  if (sizeof_array > 0)
-    memcpy(new_array, array, sizeof_array);
-  return new_value;
+  if (parent != NULL) {
+    device_instance **previous;
+    ASSERT(parent->child == NULL);
+    parent->child = instance;
+    ASSERT(me == NULL);
+    instance->owner = parent->owner;
+    instance->parent = parent;
+    /* in the devices instance list replace the parent instance with
+       this one */
+    instance->next = parent->next;
+    /* replace parent with this new node */
+    previous = &instance->owner->instances;
+    while (*previous != parent) {
+      ASSERT(*previous != NULL);
+      previous = &(*previous)->next;
+    }
+    *previous = instance;
+  }
+  instance->data = data;
+  instance->args = (args == NULL ? NULL : (char *) strdup(args));
+  instance->path = (path == NULL ? NULL : (char *) strdup(path));
+  instance->callback = callbacks;
+  cap_add(instance->owner->ihandles, instance);
+  return instance;
 }
 
-void INLINE_DEVICE
-device_add_array_property(device *me,
-                         const char *property,
-                         const void *array,
-                         int sizeof_array)
+
+INLINE_DEVICE\
+(device_instance *)
+device_create_instance(device *me,
+                      const char *path,
+                      const char *args)
 {
-  TRACE(trace_devices,
-       ("device_add_array_property(me=0x%lx, property=%s, ...)\n",
-        (long)me, property));
-  device_add_property(me, property,
-                     array_property, array, sizeof_array);
+  /* create the instance */
+  if (me->callback->instance_create == NULL)
+    device_error(me, "no instance_create method");
+  return me->callback->instance_create(me, path, args);
 }
 
-void INLINE_DEVICE
-device_add_integer_property(device *me,
-                           const char *property,
-                           signed32 integer)
+
+STATIC_INLINE_DEVICE\
+(void)
+clean_device_instances(device *me)
 {
-  TRACE(trace_devices,
-       ("device_add_integer_property(me=0x%lx, property=%s, integer=%ld)\n",
-        (long)me, property, (long)integer));
-  H2BE(integer);
-  device_add_property(me, property, integer_property,
-                     &integer, sizeof(integer));
+  device_instance **instance = &me->instances;
+  while (*instance != NULL) {
+    device_instance *old_instance = *instance;
+    device_instance_delete(old_instance);
+    instance = &me->instances;
+  }
 }
 
-void INLINE_DEVICE
-device_add_boolean_property(device *me,
-                           const char *property,
-                           int boolean)
+
+INLINE_DEVICE\
+(void)
+device_instance_delete(device_instance *instance)
 {
-  signed32 new_boolean = (boolean ? -1 : 0);
-  TRACE(trace_devices,
-       ("device_add_boolean(me=0x%lx, property=%s, boolean=%d)\n",
-        (long)me, property, boolean));
-  device_add_property(me, property, boolean_property,
-                     &new_boolean, sizeof(new_boolean));
+  device *me = instance->owner;
+  if (instance->callback->delete == NULL)
+    device_error(me, "no delete method");
+  instance->callback->delete(instance);
+  if (instance->args != NULL)
+    free(instance->args);
+  if (instance->path != NULL)
+    free(instance->path);
+  if (instance->child == NULL) {
+    /* only remove leaf nodes */
+    device_instance **curr = &me->instances;
+    while (*curr != instance) {
+      ASSERT(*curr != NULL);
+      curr = &(*curr)->next;
+    }
+    *curr = instance->next;
+  }
+  else {
+    /* check it isn't in the instance list */
+    device_instance *curr = me->instances;
+    while (curr != NULL) {
+      ASSERT(curr != instance);
+      curr = curr->next;
+    }
+    /* unlink the child */
+    ASSERT(instance->child->parent == instance);
+    instance->child->parent = NULL;
+  }
+  cap_remove(me->ihandles, instance);
+  free(instance);
 }
 
-void INLINE_DEVICE
-device_add_null_property(device *me,
-                        const char *property)
+INLINE_DEVICE\
+(int)
+device_instance_read(device_instance *instance,
+                    void *addr,
+                    unsigned_word len)
 {
-  TRACE(trace_devices,
-       ("device_add_null(me=0x%lx, property=%s)\n",
-        (long)me, property));
-  device_add_property(me, property, null_property,
-                     NULL, 0);
+  device *me = instance->owner;
+  if (instance->callback->read == NULL)
+    device_error(me, "no read method");
+  return instance->callback->read(instance, addr, len);
 }
 
-void INLINE_DEVICE
-device_add_string_property(device *me,
-                          const char *property,
-                          const char *string)
+INLINE_DEVICE\
+(int)
+device_instance_write(device_instance *instance,
+                     const void *addr,
+                     unsigned_word len)
 {
+  device *me = instance->owner;
+  if (instance->callback->write == NULL)
+    device_error(me, "no write method");
+  return instance->callback->write(instance, addr, len);
+}
 
-  TRACE(trace_devices,
-       ("device_add_property(me=0x%lx, property=%s, string=%s)\n",
-        (long)me, property, string));
-  device_add_property(me, property, string_property,
-                     string, strlen(string) + 1);
+INLINE_DEVICE\
+(int)
+device_instance_seek(device_instance *instance,
+                    unsigned_word pos_hi,
+                    unsigned_word pos_lo)
+{
+  device *me = instance->owner;
+  if (instance->callback->seek == NULL)
+    device_error(me, "no seek method");
+  return instance->callback->seek(instance, pos_hi, pos_lo);
 }
 
-const device_property INLINE_DEVICE *
-device_find_property(device *me,
-                    const char *property)
+INLINE_DEVICE\
+(int)
+device_instance_call_method(device_instance *instance,
+                           const char *method_name,
+                           int n_stack_args,
+                           unsigned_cell stack_args[/*n_stack_args*/], 
+                           int n_stack_returns,
+                           unsigned_cell stack_returns[/*n_stack_args*/])
 {
-  if (me != (device*)0) {
-    device_property_entry *entry = me->properties;
-    while (entry != (device_property_entry*)0) {
-      if (strcmp(entry->name, property) == 0)
-       return entry->value;
-      entry = entry->next;
+  device *me = instance->owner;
+  const device_instance_methods *method = instance->callback->methods;
+  if (method == NULL) {
+    device_error(me, "no methods (want %s)", method_name);
+  }
+  while (method->name != NULL) {
+    if (strcmp(method->name, method_name) == 0) {
+      return method->method(instance,
+                           n_stack_args, stack_args,
+                           n_stack_returns, stack_returns);
     }
+    method++;
   }
-  return (device_property*)0;
+  device_error(me, "no %s method", method_name);
+  return 0;
 }
 
-const char INLINE_DEVICE *
-device_find_next_property(device *me,
-                         const char *property)
+
+INLINE_DEVICE\
+(device *)
+device_instance_device(device_instance *instance)
 {
-  if (me != NULL) {
-    if (property == NULL || strcmp(property, "") == 0) {
-      return (me->properties != NULL
-             ? me->properties->name
-             : NULL);
-    }
-    else {
-      device_property_entry *entry = me->properties;
-      while (entry != NULL) {
-       if (strcmp(entry->name, property) == 0)
-         return (entry->next != NULL
-                 ? entry->next->name
-                 : NULL);
-       entry = entry->next;
-      }
-    }
-  }
-  return NULL;
+  return instance->owner;
 }
 
-const device_property INLINE_DEVICE *
-device_find_array_property(device *me,
-                          const char *property)
+INLINE_DEVICE\
+(const char *)
+device_instance_path(device_instance *instance)
 {
-  const device_property *node;
-  TRACE(trace_devices,
-       ("device_find_integer(me=0x%lx, property=%s)\n",
-        (long)me, property));
-  node = device_find_property(me, property);
-  if (node == (device_property*)0
-      || node->type != array_property)
-    error("%s property %s not found or of wrong type\n",
-         me->name, property);
-  return node;
+  return instance->path;
 }
 
-signed_word INLINE_DEVICE
-device_find_integer_property(device *me,
-                            const char *property)
+INLINE_DEVICE\
+(void *)
+device_instance_data(device_instance *instance)
 {
-  const device_property *node;
-  signed32 integer;
-  TRACE(trace_devices,
-       ("device_find_integer(me=0x%lx, property=%s)\n",
-        (long)me, property));
-  node = device_find_property(me, property);
-  if (node == (device_property*)0
-      || node->type != integer_property)
-    error("%s property %s not found or of wrong type\n",
-         me->name, property);
-  ASSERT(sizeof(integer) == node->sizeof_array);
-  memcpy(&integer, node->array, sizeof(integer));
-  BE2H(integer);
-  return integer;
+  return instance->data;
 }
 
-int INLINE_DEVICE
-device_find_boolean_property(device *me,
-                            const char *property)
+
+\f
+/* Device Properties: */
+
+STATIC_INLINE_DEVICE\
+(device_property_entry *)
+find_property_entry(device *me,
+                    const char *property)
 {
-  const device_property *node;
-  unsigned32 boolean;
-  TRACE(trace_devices,
-       ("device_find_boolean(me=0x%lx, property=%s)\n",
-        (long)me, property));
+  device_property_entry *entry;
+  ASSERT(property != NULL);
+  entry = me->properties;
+  while (entry != NULL) {
+    if (strcmp(entry->value->name, property) == 0)
+      return entry;
+    entry = entry->next;
+  }
+  return NULL;
+}
+
+STATIC_INLINE_DEVICE\
+(void)
+device_add_property(device *me,
+                   const char *property,
+                   device_property_type type,
+                   const void *init_array,
+                   unsigned sizeof_init_array,
+                   const void *array,
+                   unsigned sizeof_array,
+                   const device_property *original,
+                   object_disposition disposition)
+{
+  device_property_entry *new_entry = NULL;
+  device_property *new_value = NULL;
+
+  /* find the list end */
+  device_property_entry **insertion_point = &me->properties;
+  while (*insertion_point != NULL) {
+    if (strcmp((*insertion_point)->value->name, property) == 0)
+      return;
+    insertion_point = &(*insertion_point)->next;
+  }
+
+  /* create a new value */
+  new_value = ZALLOC(device_property);
+  new_value->name = (char *) strdup(property);
+  new_value->type = type;
+  if (sizeof_array > 0) {
+    void *new_array = zalloc(sizeof_array);
+    memcpy(new_array, array, sizeof_array);
+    new_value->array = new_array;
+    new_value->sizeof_array = sizeof_array;
+  }
+  new_value->owner = me;
+  new_value->original = original;
+  new_value->disposition = disposition;
+
+  /* insert the value into the list */
+  new_entry = ZALLOC(device_property_entry);
+  *insertion_point = new_entry;
+  if (sizeof_init_array > 0) {
+    void *new_init_array = zalloc(sizeof_init_array);
+    memcpy(new_init_array, init_array, sizeof_init_array);
+    new_entry->init_array = new_init_array;
+    new_entry->sizeof_init_array = sizeof_init_array;
+  }
+  new_entry->value = new_value;
+}
+
+
+/* local - not available externally */
+STATIC_INLINE_DEVICE\
+(void)
+device_set_property(device *me,
+                   const char *property,
+                   device_property_type type,
+                   const void *array,
+                   int sizeof_array)
+{
+  /* find the property */
+  device_property_entry *entry = find_property_entry(me, property);
+  if (entry != NULL) {
+    /* existing property - update it */
+    void *new_array = 0;
+    device_property *value = entry->value;
+    /* check the type matches */
+    if (value->type != type)
+      device_error(me, "conflict between type of new and old value for property %s", property);
+    /* replace its value */
+    if (value->array != NULL)
+      free((void*)value->array);
+    new_array = (sizeof_array > 0
+                ? zalloc(sizeof_array)
+                : (void*)0);
+    value->array = new_array;
+    value->sizeof_array = sizeof_array;
+    if (sizeof_array > 0)
+      memcpy(new_array, array, sizeof_array);
+    return;
+  }
+  else {
+    /* new property - create it */
+    device_add_property(me, property, type,
+                       NULL, 0, array, sizeof_array,
+                       NULL, tempoary_object);
+  }
+}
+
+
+STATIC_INLINE_DEVICE\
+(void)
+clean_device_properties(device *me)
+{
+  device_property_entry **delete_point = &me->properties;
+  while (*delete_point != NULL) {
+    device_property_entry *current = *delete_point;
+    switch (current->value->disposition) {
+    case permenant_object:
+      /* zap the current value, will be initialized later */
+      ASSERT(current->init_array != NULL);
+      if (current->value->array != NULL) {
+       free((void*)current->value->array);
+       current->value->array = NULL;
+      }
+      delete_point = &(*delete_point)->next;
+      break;
+    case tempoary_object:
+      /* zap the actual property, was created during simulation run */
+      ASSERT(current->init_array == NULL);
+      *delete_point = current->next;
+      if (current->value->array != NULL)
+       free((void*)current->value->array);
+      free(current->value);
+      free(current);
+      break;
+    }
+  }
+}
+
+
+INLINE_DEVICE\
+(void)
+device_init_static_properties(device *me,
+                             void *data)
+{
+  device_property_entry *property;
+  for (property = me->properties;
+       property != NULL;
+       property = property->next) {
+    ASSERT(property->init_array != NULL);
+    ASSERT(property->value->array == NULL);
+    ASSERT(property->value->disposition == permenant_object);
+    switch (property->value->type) {
+    case array_property:
+    case boolean_property:
+    case range_array_property:
+    case reg_array_property:
+    case string_property:
+    case string_array_property:
+    case integer_property:
+      /* delete the property, and replace it with the original */
+      device_set_property(me, property->value->name,
+                         property->value->type,
+                         property->init_array,
+                         property->sizeof_init_array);
+      break;
+    case ihandle_property:
+      break;
+    }
+  }
+}
+
+
+INLINE_DEVICE\
+(void)
+device_init_runtime_properties(device *me,
+                              void *data)
+{
+  device_property_entry *property;
+  for (property = me->properties;
+       property != NULL;
+       property = property->next) {
+    switch (property->value->disposition) {
+    case permenant_object:
+      switch (property->value->type) {
+      case ihandle_property:
+       {
+         device_instance *ihandle;
+         ihandle_runtime_property_spec spec;
+         ASSERT(property->init_array != NULL);
+         ASSERT(property->value->array == NULL);
+         device_find_ihandle_runtime_property(me, property->value->name, &spec);
+         ihandle = tree_instance(me, spec.full_path);
+         device_set_ihandle_property(me, property->value->name, ihandle);
+         break;
+       }
+      case array_property:
+      case boolean_property:
+      case range_array_property:
+      case integer_property:
+      case reg_array_property:
+      case string_property:
+      case string_array_property:
+       ASSERT(property->init_array != NULL);
+       ASSERT(property->value->array != NULL);
+       break;
+      }
+      break;
+    case tempoary_object:
+      ASSERT(property->init_array == NULL);
+      ASSERT(property->value->array != NULL);
+      break;
+    }
+  }
+}
+
+
+INLINE_DEVICE\
+(const device_property *)
+device_next_property(const device_property *property)
+{
+  /* find the property in the list */
+  device *owner = property->owner;
+  device_property_entry *entry = owner->properties;
+  while (entry != NULL && entry->value != property)
+    entry = entry->next;
+  /* now return the following property */
+  ASSERT(entry != NULL); /* must be a member! */
+  if (entry->next != NULL)
+    return entry->next->value;
+  else
+    return NULL;
+}
+
+
+INLINE_DEVICE\
+(const device_property *)
+device_find_property(device *me,
+                    const char *property)
+{
+  if (me == NULL) {
+    return NULL;
+  }
+  else if (property == NULL || strcmp(property, "") == 0) {
+    if (me->properties == NULL)
+      return NULL;
+    else
+      return me->properties->value;
+  }
+  else {
+    device_property_entry *entry = find_property_entry(me, property);
+    if (entry != NULL)
+      return entry->value;
+  }
+  return NULL;
+}
+
+
+INLINE_DEVICE\
+(void)
+device_add_array_property(device *me,
+                          const char *property,
+                          const void *array,
+                          int sizeof_array)
+{
+  device_add_property(me, property, array_property,
+                      array, sizeof_array, array, sizeof_array,
+                      NULL, permenant_object);
+}
+
+INLINE_DEVICE\
+(void)
+device_set_array_property(device *me,
+                         const char *property,
+                         const void *array,
+                         int sizeof_array)
+{
+  device_set_property(me, property, array_property, array, sizeof_array);
+}
+
+INLINE_DEVICE\
+(const device_property *)
+device_find_array_property(device *me,
+                          const char *property)
+{
+  const device_property *node;
+  node = device_find_property(me, property);
+  if (node == (device_property*)0
+      || node->type != array_property)
+    device_error(me, "property %s not found or of wrong type", property);
+  return node;
+}
+
+
+INLINE_DEVICE\
+(void)
+device_add_boolean_property(device *me,
+                            const char *property,
+                            int boolean)
+{
+  signed32 new_boolean = (boolean ? -1 : 0);
+  device_add_property(me, property, boolean_property,
+                      &new_boolean, sizeof(new_boolean),
+                      &new_boolean, sizeof(new_boolean),
+                      NULL, permenant_object);
+}
+
+INLINE_DEVICE\
+(int)
+device_find_boolean_property(device *me,
+                            const char *property)
+{
+  const device_property *node;
+  unsigned_cell boolean;
   node = device_find_property(me, property);
   if (node == (device_property*)0
       || node->type != boolean_property)
-    error("%s property %s not found or of wrong type\n",
-         me->name, property);
+    device_error(me, "property %s not found or of wrong type", property);
   ASSERT(sizeof(boolean) == node->sizeof_array);
   memcpy(&boolean, node->array, sizeof(boolean));
   return boolean;
 }
 
-const char INLINE_DEVICE *
+
+INLINE_DEVICE\
+(void)
+device_add_ihandle_runtime_property(device *me,
+                                   const char *property,
+                                   const ihandle_runtime_property_spec *ihandle)
+{
+  /* enter the full path as the init array */
+  device_add_property(me, property, ihandle_property,
+                     ihandle->full_path, strlen(ihandle->full_path) + 1,
+                     NULL, 0,
+                     NULL, permenant_object);
+}
+
+INLINE_DEVICE\
+(void)
+device_find_ihandle_runtime_property(device *me,
+                                    const char *property,
+                                    ihandle_runtime_property_spec *ihandle)
+{
+  device_property_entry *entry = find_property_entry(me, property);
+  TRACE(trace_devices,
+       ("device_find_ihandle_runtime_property(me=0x%lx, property=%s)\n",
+        (long)me, property));
+  if (entry == NULL
+      || entry->value->type != ihandle_property
+      || entry->value->disposition != permenant_object)
+    device_error(me, "property %s not found or of wrong type", property);
+  ASSERT(entry->init_array != NULL);
+  /* the full path */
+  ihandle->full_path = entry->init_array;
+}
+
+
+
+INLINE_DEVICE\
+(void)
+device_set_ihandle_property(device *me,
+                           const char *property,
+                           device_instance *ihandle)
+{
+  unsigned_cell cells;
+  cells = H2BE_cell(device_instance_to_external(ihandle));
+  device_set_property(me, property, ihandle_property,
+                     &cells, sizeof(cells));
+                     
+}
+
+INLINE_DEVICE\
+(device_instance *)
+device_find_ihandle_property(device *me,
+                            const char *property)
+{
+  const device_property *node;
+  unsigned_cell ihandle;
+  device_instance *instance;
+
+  node = device_find_property(me, property);
+  if (node == NULL || node->type != ihandle_property)
+    device_error(me, "property %s not found or of wrong type", property);
+  if (node->array == NULL)
+    device_error(me, "runtime property %s not yet initialized", property);
+
+  ASSERT(sizeof(ihandle) == node->sizeof_array);
+  memcpy(&ihandle, node->array, sizeof(ihandle));
+  instance = external_to_device_instance(me, BE2H_cell(ihandle));
+  ASSERT(instance != NULL);
+  return instance;
+}
+
+
+INLINE_DEVICE\
+(void)
+device_add_integer_property(device *me,
+                           const char *property,
+                           signed_cell integer)
+{
+  H2BE(integer);
+  device_add_property(me, property, integer_property,
+                      &integer, sizeof(integer),
+                      &integer, sizeof(integer),
+                      NULL, permenant_object);
+}
+
+INLINE_DEVICE\
+(signed_cell)
+device_find_integer_property(device *me,
+                            const char *property)
+{
+  const device_property *node;
+  signed_cell integer;
+  TRACE(trace_devices,
+       ("device_find_integer(me=0x%lx, property=%s)\n",
+        (long)me, property));
+  node = device_find_property(me, property);
+  if (node == (device_property*)0
+      || node->type != integer_property)
+    device_error(me, "property %s not found or of wrong type", property);
+  ASSERT(sizeof(integer) == node->sizeof_array);
+  memcpy(&integer, node->array, sizeof(integer));
+  return BE2H_cell(integer);
+}
+
+INLINE_DEVICE\
+(int)
+device_find_integer_array_property(device *me,
+                                  const char *property,
+                                  unsigned index,
+                                  signed_cell *integer)
+{
+  const device_property *node;
+  int sizeof_integer = sizeof(*integer);
+  signed_cell *cell;
+  TRACE(trace_devices,
+       ("device_find_integer(me=0x%lx, property=%s)\n",
+        (long)me, property));
+
+  /* check things sane */
+  node = device_find_property(me, property);
+  if (node == (device_property*)0
+      || (node->type != integer_property
+         && node->type != array_property))
+    device_error(me, "property %s not found or of wrong type", property);
+  if ((node->sizeof_array % sizeof_integer) != 0)
+    device_error(me, "property %s contains an incomplete number of cells", property);
+  if (node->sizeof_array <= sizeof_integer * index)
+    return 0;
+
+  /* Find and convert the value */
+  cell = ((signed_cell*)node->array) + index;
+  *integer = BE2H_cell(*cell);
+
+  return node->sizeof_array / sizeof_integer;
+}
+
+
+STATIC_INLINE_DEVICE\
+(unsigned_cell *)
+unit_address_to_cells(const device_unit *unit,
+                     unsigned_cell *cell,
+                     int nr_cells)
+{
+  int i;
+  ASSERT(nr_cells == unit->nr_cells);
+  for (i = 0; i < unit->nr_cells; i++) {
+    *cell = H2BE_cell(unit->cells[i]);
+    cell += 1;
+  }
+  return cell;
+}
+
+
+STATIC_INLINE_DEVICE\
+(const unsigned_cell *)
+cells_to_unit_address(const unsigned_cell *cell,
+                     device_unit *unit,
+                     int nr_cells)
+{
+  int i;
+  memset(unit, 0, sizeof(*unit));
+  unit->nr_cells = nr_cells;
+  for (i = 0; i < unit->nr_cells; i++) {
+    unit->cells[i] = BE2H_cell(*cell);
+    cell += 1;
+  }
+  return cell;
+}
+
+
+STATIC_INLINE_DEVICE\
+(unsigned)
+nr_range_property_cells(device *me,
+                       int nr_ranges)
+{
+  return ((device_nr_address_cells(me)
+          + device_nr_address_cells(device_parent(me))
+          + device_nr_size_cells(me))
+         ) * nr_ranges;
+}
+
+INLINE_DEVICE\
+(void)
+device_add_range_array_property(device *me,
+                               const char *property,
+                               const range_property_spec *ranges,
+                               unsigned nr_ranges)
+{
+  unsigned sizeof_cells = (nr_range_property_cells(me, nr_ranges)
+                          * sizeof(unsigned_cell));
+  unsigned_cell *cells = zalloc(sizeof_cells);
+  unsigned_cell *cell;
+  int i;
+
+  /* copy the property elements over */
+  cell = cells;
+  for (i = 0; i < nr_ranges; i++) {
+    const range_property_spec *range = &ranges[i];
+    /* copy the child address */
+    cell = unit_address_to_cells(&range->child_address, cell,
+                                device_nr_address_cells(me));
+    /* copy the parent address */
+    cell = unit_address_to_cells(&range->parent_address, cell, 
+                                device_nr_address_cells(device_parent(me)));
+    /* copy the size */
+    cell = unit_address_to_cells(&range->size, cell, 
+                                device_nr_size_cells(me));
+  }
+  ASSERT(cell == &cells[nr_range_property_cells(me, nr_ranges)]);
+
+  /* add it */
+  device_add_property(me, property, range_array_property,
+                     cells, sizeof_cells,
+                     cells, sizeof_cells,
+                     NULL, permenant_object);
+
+  free(cells);
+}
+
+INLINE_DEVICE\
+(int)
+device_find_range_array_property(device *me,
+                                const char *property,
+                                unsigned index,
+                                range_property_spec *range)
+{
+  const device_property *node;
+  unsigned sizeof_entry = (nr_range_property_cells(me, 1)
+                          * sizeof(unsigned_cell));
+  const unsigned_cell *cells;
+
+  /* locate the property */
+  node = device_find_property(me, property);
+  if (node == (device_property*)0
+      || node->type != range_array_property)
+    device_error(me, "property %s not found or of wrong type", property);
+
+  /* aligned ? */
+  if ((node->sizeof_array % sizeof_entry) != 0)
+    device_error(me, "property %s contains an incomplete number of entries",
+                property);
+
+  /* within bounds? */
+  if (node->sizeof_array < sizeof_entry * (index + 1))
+    return 0;
+
+  /* find the range of interest */
+  cells = (unsigned_cell*)((char*)node->array + sizeof_entry * index);
+
+  /* copy the child address out - converting as we go */
+  cells = cells_to_unit_address(cells, &range->child_address,
+                               device_nr_address_cells(me));
+
+  /* copy the parent address out - converting as we go */
+  cells = cells_to_unit_address(cells, &range->parent_address,
+                               device_nr_address_cells(device_parent(me)));
+
+  /* copy the size - converting as we go */
+  cells = cells_to_unit_address(cells, &range->size,
+                               device_nr_size_cells(me));
+
+  return node->sizeof_array / sizeof_entry;
+}
+
+
+STATIC_INLINE_DEVICE\
+(unsigned)
+nr_reg_property_cells(device *me,
+                     int nr_regs)
+{
+  return (device_nr_address_cells(device_parent(me))
+         + device_nr_size_cells(device_parent(me))
+         ) * nr_regs;
+}
+
+INLINE_DEVICE\
+(void)
+device_add_reg_array_property(device *me,
+                             const char *property,
+                             const reg_property_spec *regs,
+                             unsigned nr_regs)
+{
+  unsigned sizeof_cells = (nr_reg_property_cells(me, nr_regs)
+                          * sizeof(unsigned_cell));
+  unsigned_cell *cells = zalloc(sizeof_cells);
+  unsigned_cell *cell;
+  int i;
+
+  /* copy the property elements over */
+  cell = cells;
+  for (i = 0; i < nr_regs; i++) {
+    const reg_property_spec *reg = &regs[i];
+    /* copy the address */
+    cell = unit_address_to_cells(&reg->address, cell,
+                                device_nr_address_cells(device_parent(me)));
+    /* copy the size */
+    cell = unit_address_to_cells(&reg->size, cell,
+                                device_nr_size_cells(device_parent(me)));
+  }
+  ASSERT(cell == &cells[nr_reg_property_cells(me, nr_regs)]);
+
+  /* add it */
+  device_add_property(me, property, reg_array_property,
+                     cells, sizeof_cells,
+                     cells, sizeof_cells,
+                     NULL, permenant_object);
+
+  free(cells);
+}
+
+INLINE_DEVICE\
+(int)
+device_find_reg_array_property(device *me,
+                              const char *property,
+                              unsigned index,
+                              reg_property_spec *reg)
+{
+  const device_property *node;
+  unsigned sizeof_entry = (nr_reg_property_cells(me, 1)
+                          * sizeof(unsigned_cell));
+  const unsigned_cell *cells;
+
+  /* locate the property */
+  node = device_find_property(me, property);
+  if (node == (device_property*)0
+      || node->type != reg_array_property)
+    device_error(me, "property %s not found or of wrong type", property);
+
+  /* aligned ? */
+  if ((node->sizeof_array % sizeof_entry) != 0)
+    device_error(me, "property %s contains an incomplete number of entries",
+                property);
+
+  /* within bounds? */
+  if (node->sizeof_array < sizeof_entry * (index + 1))
+    return 0;
+
+  /* find the range of interest */
+  cells = (unsigned_cell*)((char*)node->array + sizeof_entry * index);
+
+  /* copy the address out - converting as we go */
+  cells = cells_to_unit_address(cells, &reg->address,
+                               device_nr_address_cells(device_parent(me)));
+
+  /* copy the size out - converting as we go */
+  cells = cells_to_unit_address(cells, &reg->size,
+                               device_nr_size_cells(device_parent(me)));
+
+  return node->sizeof_array / sizeof_entry;
+}
+
+
+INLINE_DEVICE\
+(void)
+device_add_string_property(device *me,
+                           const char *property,
+                           const char *string)
+{
+  device_add_property(me, property, string_property,
+                      string, strlen(string) + 1,
+                      string, strlen(string) + 1,
+                      NULL, permenant_object);
+}
+
+INLINE_DEVICE\
+(const char *)
 device_find_string_property(device *me,
                            const char *property)
 {
   const device_property *node;
   const char *string;
-  TRACE(trace_devices,
-       ("device_find_string(me=0x%lx, property=%s)\n",
-        (long)me, property));
   node = device_find_property(me, property);
   if (node == (device_property*)0
       || node->type != string_property)
-    error("%s property %s not found or of wrong type\n",
-         me->name, property);
+    device_error(me, "property %s not found or of wrong type", property);
   string = node->array;
   ASSERT(strlen(string) + 1 == node->sizeof_array);
   return string;
 }
 
-
-/* determine the full name of the device.  If buf is specified it is
-   stored in there.  Failing that, a safe area of memory is allocated */
-const char STATIC_INLINE_DEVICE *
-device_tree_full_name(device *leaf,
-                     char *buf,
-                     unsigned sizeof_buf)
+INLINE_DEVICE\
+(void)
+device_add_string_array_property(device *me,
+                                const char *property,
+                                const string_property_spec *strings,
+                                unsigned nr_strings)
 {
-  /* get a buffer */
-  char full_name[1024];
-  if (buf == (char*)0) {
-    buf = full_name;
-    sizeof_buf = sizeof(full_name);
+  int sizeof_array;
+  int string_nr;
+  char *array;
+  char *chp;
+  if (nr_strings == 0)
+    device_error(me, "property %s must be non-null", property);
+  /* total up the size of the needed array */
+  for (sizeof_array = 0, string_nr = 0;
+       string_nr < nr_strings;
+       string_nr ++) {
+    sizeof_array += strlen(strings[string_nr]) + 1;
+  }
+  /* create the array */
+  array = (char*)zalloc(sizeof_array);
+  chp = array;
+  for (string_nr = 0;
+       string_nr < nr_strings;
+       string_nr++) {
+    strcpy(chp, strings[string_nr]);
+    chp += strlen(chp) + 1;
   }
+  ASSERT(chp == array + sizeof_array);
+  /* now enter it */
+  device_add_property(me, property, string_array_property,
+                     array, sizeof_array,
+                     array, sizeof_array,
+                     NULL, permenant_object);
+}
 
-  /* construct a name */
-  if (leaf->parent == NULL) {
-    if (sizeof_buf < 1)
-      error("device_full_name() buffer overflow\n");
-    *buf = '\0';
+INLINE_DEVICE\
+(int)
+device_find_string_array_property(device *me,
+                                 const char *property,
+                                 unsigned index,
+                                 string_property_spec *string)
+{
+  const device_property *node;
+  node = device_find_property(me, property);
+  if (node == (device_property*)0)
+    device_error(me, "property %s not found", property);
+  switch (node->type) {
+  default:
+    device_error(me, "property %s of wrong type", property);
+    break;
+  case string_property:
+    if (index == 0) {
+      *string = node->array;
+      ASSERT(strlen(*string) + 1 == node->sizeof_array);
+      return 1;
+    }
+    break;
+  case array_property:
+    if (node->sizeof_array == 0
+       || ((char*)node->array)[node->sizeof_array - 1] != '\0')
+      device_error(me, "property %s invalid for string array", property);
+    /* FALL THROUGH */
+  case string_array_property:
+    ASSERT(node->sizeof_array > 0);
+    ASSERT(((char*)node->array)[node->sizeof_array - 1] == '\0');
+    {
+      const char *chp = node->array;
+      int nr_entries = 0;
+      /* count the number of strings, keeping an eye out for the one
+         we're looking for */
+      *string = chp;
+      do {
+       if (*chp == '\0') {
+         /* next string */
+         nr_entries++;
+         chp++;
+         if (nr_entries == index)
+           *string = chp;
+       }
+       else {
+         chp++;
+       }
+      } while (chp < (char*)node->array + node->sizeof_array);
+      if (index < nr_entries)
+       return nr_entries;
+      else {
+       *string = NULL;
+       return 0;
+      }
+    }
+    break;
   }
-  else {
-    device_tree_full_name(leaf->parent, buf, sizeof_buf);
-    if (strlen(buf) + strlen("/") + strlen(leaf->name) + 1 > sizeof_buf)
-      error("device_full_name() buffer overflow\n");
-    strcat(buf, "/");
-    strcat(buf, leaf->name);
+  return 0;
+}
+
+INLINE_DEVICE\
+(void)
+device_add_duplicate_property(device *me,
+                             const char *property,
+                             const device_property *original)
+{
+  device_property_entry *master;
+  TRACE(trace_devices,
+       ("device_add_duplicate_property(me=0x%lx, property=%s, ...)\n",
+        (long)me, property));
+  if (original->disposition != permenant_object)
+    device_error(me, "Can only duplicate permenant objects");
+  /* find the original's master */
+  master = original->owner->properties;
+  while (master->value != original) {
+    master = master->next;
+    ASSERT(master != NULL);
   }
-  
-  /* return it usefully */
-  if (buf == full_name)
-    buf = strdup(full_name);
-  return buf;
+  /* now duplicate it */
+  device_add_property(me, property,
+                     original->type,
+                     master->init_array, master->sizeof_init_array,
+                     original->array, original->sizeof_array,
+                     original, permenant_object);
 }
 
 
-/* find/create a node in the device tree */
+\f
+/* Device Hardware: */
+
+INLINE_DEVICE\
+(unsigned)
+device_io_read_buffer(device *me,
+                     void *dest,
+                     int space,
+                     unsigned_word addr,
+                     unsigned nr_bytes,
+                     cpu *processor,
+                     unsigned_word cia)
+{
+  if (me->callback->io.read_buffer == NULL)
+    device_error(me, "no io.read_buffer method");
+  return me->callback->io.read_buffer(me, dest, space,
+                                     addr, nr_bytes,
+                                     processor, cia);
+}
 
-typedef enum {
-  device_tree_return_null = 2,
-  device_tree_abort = 3,
-} device_tree_action;
+INLINE_DEVICE\
+(unsigned)
+device_io_write_buffer(device *me,
+                      const void *source,
+                      int space,
+                      unsigned_word addr,
+                      unsigned nr_bytes,
+                      cpu *processor,
+                      unsigned_word cia)
+{
+  if (me->callback->io.write_buffer == NULL)
+    device_error(me, "no io.write_buffer method");
+  return me->callback->io.write_buffer(me, source, space,
+                                      addr, nr_bytes,
+                                      processor, cia);
+}
 
-device STATIC_INLINE_DEVICE *
-device_tree_find_node(device *root,
-                     const char *path,
-                     const char *full_path,
-                     device_tree_action action)
+INLINE_DEVICE\
+(unsigned)
+device_dma_read_buffer(device *me,
+                      void *dest,
+                      int space,
+                      unsigned_word addr,
+                      unsigned nr_bytes)
 {
-  const char *name;
-  int strlen_name;
-  device *child;
-
-  /* strip off any leading `/', `../' or `./' */
-  while (1) {
-    if (strncmp(path, "/", strlen("/")) == 0) {
-      while (root != NULL && root->parent != NULL)
-       root = root->parent;
-      path += strlen("/");
-    }
-    else if (strncmp(path, "./", strlen("./")) == 0) {
-      root = root;
-      path += strlen("./");
-    }
-    else if (strncmp(path, "../", strlen("../")) == 0) {
-      if (root != NULL && root->parent != NULL)
-       root = root->parent;
-      path += strlen("../");
-    }
-    else {
-      break;
-    }
-  }
+  if (me->callback->dma.read_buffer == NULL)
+    device_error(me, "no dma.read_buffer method");
+  return me->callback->dma.read_buffer(me, dest, space,
+                                      addr, nr_bytes);
+}
+
+INLINE_DEVICE\
+(unsigned)
+device_dma_write_buffer(device *me,
+                       const void *source,
+                       int space,
+                       unsigned_word addr,
+                       unsigned nr_bytes,
+                       int violate_read_only_section)
+{
+  if (me->callback->dma.write_buffer == NULL)
+    device_error(me, "no dma.write_buffer method");
+  return me->callback->dma.write_buffer(me, source, space,
+                                       addr, nr_bytes,
+                                       violate_read_only_section);
+}
+
+INLINE_DEVICE\
+(void)
+device_attach_address(device *me,
+                     attach_type attach,
+                     int space,
+                     unsigned_word addr,
+                     unsigned nr_bytes,
+                     access_type access,
+                     device *client) /*callback/default*/
+{
+  if (me->callback->address.attach == NULL)
+    device_error(me, "no address.attach method");
+  me->callback->address.attach(me, attach, space,
+                              addr, nr_bytes, access, client);
+}
+
+INLINE_DEVICE\
+(void)
+device_detach_address(device *me,
+                     attach_type attach,
+                     int space,
+                     unsigned_word addr,
+                     unsigned nr_bytes,
+                     access_type access,
+                     device *client) /*callback/default*/
+{
+  if (me->callback->address.detach == NULL)
+    device_error(me, "no address.detach method");
+  me->callback->address.detach(me, attach, space,
+                              addr, nr_bytes, access, client);
+}
+
+
+\f
+/* Interrupts: */
 
-  /* parse the driver_name/unit-address */
-  ASSERT(*path != '/');
-  name = path;
-  while (isalnum(*path)
-        || *path == ',' || *path == ',' || *path == '_'
-        || *path == '+' || *path == '-')
-    path++;
-  if ((*path != '/' && *path != '@' && *path != ':' && *path != '\0')
-      || (name == path && *name != '\0'))
-    error("device_tree: path %s invalid at %s\n", full_path, path);
-
-  /* parse the unit-address */
-  if (*path == '@') {
-    path++;
-    while ((*path != '\0' && *path != ':' && *path != '/')
-          || (*path == ':' && path[-1] == '\\')
-          || (*path == '/' && path[-1] == '\\'))
-      path++;
+INLINE_DEVICE(void)
+device_interrupt_event(device *me,
+                      int my_port,
+                      int level,
+                      cpu *processor,
+                      unsigned_word cia)
+{
+  int found_an_edge = 0;
+  device_interrupt_edge *edge;
+  /* device's interrupt lines directly connected */
+  for (edge = me->interrupt_destinations;
+       edge != NULL;
+       edge = edge->next) {
+    if (edge->my_port == my_port) {
+      if (edge->dest->callback->interrupt.event == NULL)
+       device_error(me, "no interrupt method");
+      edge->dest->callback->interrupt.event(edge->dest,
+                                           edge->dest_port,
+                                           me,
+                                           my_port,
+                                           level,
+                                           processor, cia);
+      found_an_edge = 1;
+    }
   }
-  strlen_name = path - name;
-
-  /* skip the device-arguments */
-  if (*path == ':') {
-    path++;
-    while ((*path != '\0' && *path != '/' && *path != ':' && *path != '@')
-          || (*path == '/' && path[-1] == '\\')
-          || (*path == ':' && path[-1] == '\\')
-          || (*path == '@' && path[-1] == '\\'))
-      path++;
+  if (!found_an_edge) {
+    device_error(me, "No interrupt edge for port %d", my_port);
   }
+}
 
-  /* sanity checks */
-  if (*path != '\0' && *path != '/')
-    error("device_tree: path %s invalid at %s\n", full_path, path);
+INLINE_DEVICE\
+(void)
+device_interrupt_attach(device *me,
+                       int my_port,
+                       device *dest,
+                       int dest_port,
+                       object_disposition disposition)
+{
+  attach_device_interrupt_edge(&me->interrupt_destinations,
+                              my_port,
+                              dest,
+                              dest_port,
+                              disposition);
+}
+
+INLINE_DEVICE\
+(void)
+device_interrupt_detach(device *me,
+                       int my_port,
+                       device *dest,
+                       int dest_port)
+{
+  detach_device_interrupt_edge(me,
+                              &me->interrupt_destinations,
+                              my_port,
+                              dest,
+                              dest_port);
+}
+
+INLINE_DEVICE\
+(void)
+device_interrupt_traverse(device *me,
+                         device_interrupt_traverse_function *handler,
+                         void *data)
+{
+  device_interrupt_edge *interrupt_edge;
+  for (interrupt_edge = me->interrupt_destinations;
+       interrupt_edge != NULL;
+       interrupt_edge = interrupt_edge->next) {
+    handler(me, interrupt_edge->my_port,
+           interrupt_edge->dest, interrupt_edge->dest_port,
+           data);
+  }
+}
 
-  /* leaf? and growing? */
-  if (name[0] == '\0') {
-    return root;
+INLINE_DEVICE\
+(int)
+device_interrupt_decode(device *me,
+                       const char *port_name,
+                       port_direction direction)
+{
+  if (port_name == NULL || port_name[0] == '\0')
+    return 0;
+  if (isdigit(port_name[0])) {
+    return strtoul(port_name, NULL, 0);
   }
-  else if (root != NULL) {
-    for (child = root->children;
-        child != NULL;
-        child = child->sibling) {
-      if (strncmp(name, child->name, strlen_name) == 0
-         && strlen(child->name) == strlen_name) {
-       if (*path == '\0')
-         return child;
-       else
-         return device_tree_find_node(child,
-                                      path + 1/* / */,
-                                      full_path,
-                                      action);
+  else {
+    const device_interrupt_port_descriptor *ports =
+      me->callback->interrupt.ports;
+    if (ports != NULL) {
+      while (ports->name != NULL) {
+       if (ports->direction == bidirect_port
+           || ports->direction == direction) {
+         if (ports->nr_ports > 0) {
+           int len = strlen(ports->name);
+           if (strncmp(port_name, ports->name, len) == 0) {
+             if (port_name[len] == '\0')
+               return ports->number;
+             else if(isdigit(port_name[len])) {
+               int port = ports->number + strtoul(&port_name[len], NULL, 0);
+               if (port >= ports->number + ports->nr_ports)
+                 device_error(me, "Interrupt port %s out of range",
+                              port_name);
+               return port;
+             }
+           }
+         }
+         else if (strcmp(port_name, ports->name) == 0)
+           return ports->number;
+       }
+       ports++;
       }
     }
   }
+  device_error(me, "Unreconized interrupt port %s", port_name);
+  return 0;
+}
 
-  /* search failed, take default action */
-  switch (action) {
-  case device_tree_return_null:
-    return NULL;
-  case device_tree_abort:
-    error("device_tree_find_node() could not find %s in tree\n",
-         full_path);
-    return NULL;
-  default:
-    error("device_tree_find_node() invalid default action %d\n", action);
-    return NULL;
+INLINE_DEVICE\
+(int)
+device_interrupt_encode(device *me,
+                       int port_number,
+                       char *buf,
+                       int sizeof_buf,
+                       port_direction direction)
+{
+  const device_interrupt_port_descriptor *ports = NULL;
+  ports = me->callback->interrupt.ports;
+  if (ports != NULL) {
+    while (ports->name != NULL) {
+      if (ports->direction == bidirect_port
+         || ports->direction == direction) {
+       if (ports->nr_ports > 0) {
+         if (port_number >= ports->number
+             && port_number < ports->number + ports->nr_ports) {
+           strcpy(buf, ports->name);
+           sprintf(buf + strlen(buf), "%d", port_number - ports->number);
+           if (strlen(buf) >= sizeof_buf)
+             error("device_interrupt_encode: buffer overflow");
+           return strlen(buf);
+         }
+       }
+       else {
+         if (ports->number == port_number) {
+           if (strlen(ports->name) >= sizeof_buf)
+             error("device_interrupt_encode: buffer overflow");
+           strcpy(buf, ports->name);
+           return strlen(buf);
+         }
+       }
+      }
+      ports++;
+    }
   }
+  sprintf(buf, "%d", port_number);
+  if (strlen(buf) >= sizeof_buf)
+    error("device_interrupt_encode: buffer overflow");
+  return strlen(buf);
 }
 
 
-/* grow the device tree */
+\f
+/* IOCTL: */
 
-device INLINE_DEVICE *
-device_tree_add_device(device *root,
-                      const char *prefix,
-                      device *new_sub_tree)
+EXTERN_DEVICE\
+(int)
+device_ioctl(device *me,
+            cpu *processor,
+            unsigned_word cia,
+            device_ioctl_request request,
+            ...)
 {
-  device *parent;
-  TRACE(trace_device_tree,
-       ("device_tree_add_device(root=0x%lx, prefix=%s, dev=0x%lx)\n",
-        (long)root, prefix, (long)new_sub_tree));
-
-  /* find our parent */
-  parent = device_tree_find_node(root,
-                                prefix,
-                                prefix, /* full-path */
-                                device_tree_abort);
-
-  /* create/insert a new child */
-  new_sub_tree->parent = parent;
-  if (parent != NULL) {
-    device **sibling = &parent->children;
-    while ((*sibling) != NULL)
-      sibling = &(*sibling)->sibling;
-    *sibling = new_sub_tree;
-  }
+  int status;
+  va_list ap;
+  va_start(ap, request);
+  if (me->callback->ioctl == NULL)
+    device_error(me, "no ioctl method");
+  status = me->callback->ioctl(me, processor, cia, request, ap);
+  va_end(ap);
+  return status;
+}
+      
+
+\f
+/* I/O */
 
-  return new_sub_tree;
+EXTERN_DEVICE\
+(void)
+device_error(device *me,
+            const char *fmt,
+            ...)
+{
+  char message[1024];
+  va_list ap;
+  /* format the message */
+  va_start(ap, fmt);
+  vsprintf(message, fmt, ap);
+  va_end(ap);
+  /* sanity check */
+  if (strlen(message) >= sizeof(message))
+    error("device_error: buffer overflow");
+  if (me == NULL)
+    error("device: %s", message);
+  else if (me->path != NULL && me->path[0] != '\0')
+    error("%s: %s", me->path, message);
+  else if (me->name != NULL && me->name[0] != '\0')
+    error("%s: %s", me->name, message);
+  else
+    error("device: %s", message);
+  while(1);
 }
 
-device INLINE_DEVICE *
-device_tree_find_device(device *root,
-                       const char *path)
+INLINE_DEVICE\
+(int)
+device_trace(device *me)
 {
-  device *node;
-  TRACE(trace_device_tree,
-       ("device_tree_find_device_tree(root=0x%lx, path=%s)\n",
-        (long)root, path));
-  node = device_tree_find_node(root,
-                              path,
-                              path, /* full-name */
-                              device_tree_return_null);
-  return node;
+  return me->trace;
 }
 
+\f
+/* External representation */
 
-/* init all the devices */
+INLINE_DEVICE\
+(device *)
+external_to_device(device *tree_member,
+                  unsigned_cell phandle)
+{
+  device *me = cap_internal(tree_member->phandles, phandle);
+  return me;
+}
 
-void STATIC_INLINE_DEVICE
-device_tree_init_device(device *root,
-                       void *data)
+INLINE_DEVICE\
+(unsigned_cell)
+device_to_external(device *me)
 {
-  psim *system;
-  system = (psim*)data;
-  TRACE(trace_device_tree,
-       ("device_tree_init() initializing device=0x%lx:%s\n",
-        (long)root, root->full_name));
-  device_init(root, system);
+  unsigned_cell phandle = cap_external(me->phandles, me);
+  return phandle;
 }
 
+INLINE_DEVICE\
+(device_instance *)
+external_to_device_instance(device *tree_member,
+                           unsigned_cell ihandle)
+{
+  device_instance *instance = cap_internal(tree_member->ihandles, ihandle);
+  return instance;
+}
 
-void INLINE_DEVICE
-device_tree_init(device *root,
-                psim *system)
+INLINE_DEVICE\
+(unsigned_cell)
+device_instance_to_external(device_instance *instance)
 {
-  TRACE(trace_device_tree,
-       ("device_tree_init(root=0x%lx, system=0x%lx)\n", (long)root, (long)system));
-  device_tree_traverse(root, device_tree_init_device, NULL, system);
-  TRACE(trace_device_tree,
-       ("device_tree_init() = void\n"));
+  unsigned_cell ihandle = cap_external(instance->owner->ihandles, instance);
+  return ihandle;
 }
 
 
-/* traverse a device tree applying prefix/postfix functions to it */
+/* Map onto the event functions */
 
-void INLINE_DEVICE
-device_tree_traverse(device *root,
-                    device_tree_traverse_function *prefix,
-                    device_tree_traverse_function *postfix,
-                    void *data)
+INLINE_DEVICE\
+(event_entry_tag)
+device_event_queue_schedule(device *me,
+                           signed64 delta_time,
+                           device_event_handler *handler,
+                           void *data)
 {
-  device *child;
-  if (prefix != NULL)
-    prefix(root, data);
-  for (child = root->children; child != NULL; child = child->sibling) {
-    device_tree_traverse(child, prefix, postfix, data);
-  }
-  if (postfix != NULL)
-    postfix(root, data);
+  return event_queue_schedule(psim_event_queue(me->system),
+                             delta_time,
+                             handler,
+                             data);
 }
 
+INLINE_DEVICE\
+(void)
+device_event_queue_deschedule(device *me,
+                             event_entry_tag event_to_remove)
+{
+  event_queue_deschedule(psim_event_queue(me->system),
+                        event_to_remove);
+}
 
-/* dump out a device node and addresses */
-
-void INLINE_DEVICE
-device_tree_dump(device *device,
-                void *ignore_data_argument)
+INLINE_DEVICE\
+(signed64)
+device_event_queue_time(device *me)
 {
-  printf_filtered("(device_tree@0x%lx\n", (long)device);
-  printf_filtered(" (parent 0x%lx)\n", (long)device->parent);
-  printf_filtered(" (children 0x%lx)\n", (long)device->children);
-  printf_filtered(" (sibling 0x%lx)\n", (long)device->sibling);
-  printf_filtered(" (name %s)\n", device->name);
-  error("FIXME - need to print out properties\n");
-  printf_filtered(")\n");
+  return event_queue_time(psim_event_queue(me->system));
 }
 
 
-/* lookup/create a device various formats */
+/* Initialization: */
+
 
-void STATIC_INLINE_DEVICE
-u_strcat(char *buf,
-        unsigned_word uw)
+INLINE_DEVICE\
+(void)
+device_clean(device *me,
+            void *data)
 {
-  if (MASKED64(uw, 32, 63) == uw
-      || WITH_HOST_WORD_BITSIZE == 64) {
-    char *end = strchr(buf, '\0');
-    sprintf(end, "0x%x", (unsigned)uw);
-  }
-  else {
-    char *end = strchr(buf, '\0');
-    sprintf(end, "0x%x%08x",
-           (unsigned)EXTRACTED64(uw, 0, 31),
-           (unsigned)EXTRACTED64(uw, 32, 63));
-  }
+  psim *system;
+  system = (psim*)data;
+  TRACE(trace_device_init, ("device_clean - initializing %s", me->path));
+  clean_device_interrupt_edges(&me->interrupt_destinations);
+  clean_device_instances(me);
+  clean_device_properties(me);
 }
 
-void STATIC_INLINE_DEVICE
-c_strcat(char *buf,
-       const char *c)
+/* Device initialization: */
+
+INLINE_DEVICE\
+(void)
+device_init_address(device *me,
+                   void *data)
 {
-  char *end = strchr(buf, '\0');
-  while (*c) {
-    if (*c == '/' || *c == ',')
-      *end++ = '\\';
-    *end++ = *c++;
+  psim *system = (psim*)data;
+  int nr_address_cells;
+  int nr_size_cells;
+  TRACE(trace_device_init, ("device_init_address - initializing %s", me->path));
+
+  /* ensure the cap database is valid */
+  if (me->parent == NULL) {
+    cap_init(me->ihandles);
+    cap_init(me->phandles);
   }
-  *end = '\0';
-}
 
-device INLINE_DEVICE *
-device_tree_add_found(device *root,
-                     const char *prefix,
-                     const char *name)
-{
-  device *parent;
-  device *new_device;
-  device *new_node;
-  TRACE(trace_device_tree,
-       ("device_tree_add_found(root=0x%lx, prefix=%s, name=%x)\n",
-        (long)root, prefix, name));
-  parent = device_tree_find_node(root, prefix, prefix,
-                                device_tree_abort);
-  new_device = device_tree_find_device(parent, name);
-  if (new_device != NULL)
-    return new_device;
-  else {
-    new_device = device_create(name, parent);
-    new_node = device_tree_add_device(parent, "", new_device);
-    ASSERT(new_device == new_node);
-    return new_node;
+  /* some basics */
+  me->system = system; /* misc things not known until now */
+  me->trace = (device_find_property(me, "trace")
+              ? device_find_integer_property(me, "trace")
+              : 0);
+
+  /* Ensure that the first address found in the reg property matches
+     anything that was specified as part of the devices name */
+  if (device_find_property(me, "reg") != NULL) {
+    reg_property_spec unit;
+    device_find_reg_array_property(me, "reg", 0, &unit);
+    if (memcmp(device_unit_address(me), &unit.address, sizeof(unit.address))
+       != 0)
+      device_error(me, "Unit address as specified by the reg property in conflict with the value previously specified in the devices path");
   }
-}
 
-device INLINE_DEVICE *
-device_tree_add_found_c(device *root,
-                       const char *prefix,
-                       const char *name,
-                       const char *c1)
-{
-  char buf[1024];
-  strcpy(buf, name);
-  strcat(buf, "@");
-  c_strcat(buf, c1);
-  if (strlen(buf) + 1 >= sizeof(buf))
-    error("device_tree_add_found_c - buffer overflow\n");
-  return device_tree_add_found(root, prefix, buf);
-}
-
-device INLINE_DEVICE *
-device_tree_add_found_c_uw(device *root,
-                          const char *prefix,
-                          const char *name,
-                          const char *c1,
-                          unsigned_word uw2)
-{
-  char buf[1024];
-  strcpy(buf, name);
-  strcat(buf, "@");
-  c_strcat(buf, c1);
-  strcat(buf, ",");
-  u_strcat(buf, uw2);
-  if (strlen(buf) + 1 >= sizeof(buf))
-    error("device_tree_add_found_* - buffer overflow\n");
-  return device_tree_add_found(root, prefix, buf);
-}
-
-device INLINE_DEVICE *
-device_tree_add_found_uw_u(device *root,
-                          const char *prefix,
-                          const char *name,
-                          unsigned_word uw1,
-                          unsigned u2)
-{
-  char buf[1024];
-  strcpy(buf, name);
-  strcat(buf, "@");
-  u_strcat(buf, uw1);
-  strcat(buf, ",");
-  u_strcat(buf, u2);
-  if (strlen(buf) + 1 >= sizeof(buf))
-    error("device_tree_add_found_* - buffer overflow\n");
-  return device_tree_add_found(root, prefix, buf);
-}
-
-device INLINE_DEVICE *
-device_tree_add_found_uw_u_u(device *root,
-                            const char *prefix,
-                            const char *name,
-                            unsigned_word uw1,
-                            unsigned u2,
-                            unsigned u3)
-{
-  char buf[1024];
-  strcpy(buf, name);
-  strcat(buf, "@");
-  u_strcat(buf, uw1);
-  strcat(buf, ",");
-  u_strcat(buf, u2);
-  strcat(buf, ",");
-  u_strcat(buf, u3);
-  if (strlen(buf) + 1 >= sizeof(buf))
-    error("device_tree_add_found_* - buffer overflow\n");
-  return device_tree_add_found(root, prefix, buf);
-}
-
-device INLINE_DEVICE *
-device_tree_add_found_uw_u_u_c(device *root,
-                              const char *prefix,
-                              const char *name,
-                              unsigned_word uw1,
-                              unsigned u2,
-                              unsigned u3,
-                              const char *c4)
-{
-  char buf[1024];
-  strcpy(buf, name);
-  strcat(buf, "@");
-  u_strcat(buf, uw1);
-  strcat(buf, ",");
-  u_strcat(buf, u2);
-  strcat(buf, ",");
-  u_strcat(buf, u3);
-  strcat(buf, ",");
-  c_strcat(buf, c4);
-  if (strlen(buf) + 1 >= sizeof(buf))
-    error("device_tree_add_found_* - buffer overflow\n");
-  return device_tree_add_found(root, prefix, buf);
-}
-
-device INLINE_DEVICE *
-device_tree_add_found_uw_uw_u_u_c(device *root,
-                                 const char *prefix,
-                                 const char *name,
-                                 unsigned_word uw1,
-                                 unsigned_word uw2,
-                                 unsigned u3,
-                                 unsigned u4,
-                                 const char *c5)
-{
-  char buf[1024];
-  strcpy(buf, name);
-  strcat(buf, "@");
-  u_strcat(buf, uw1);
-  strcat(buf, ",");
-  u_strcat(buf, uw2);
-  strcat(buf, ",");
-  u_strcat(buf, u3);
-  strcat(buf, ",");
-  u_strcat(buf, u4);
-  strcat(buf, ",");
-  c_strcat(buf, c5);
-  if (strlen(buf) + 1 >= sizeof(buf))
-    error("device_tree_add_found_* - buffer overflow\n");
-  return device_tree_add_found(root, prefix, buf);
-}
-
-device INLINE_DEVICE *
-device_tree_add_found_uw_uw_u_u_u(device *root,
-                                 const char *prefix,
-                                 const char *name,
-                                 unsigned_word uw1,
-                                 unsigned_word uw2,
-                                 unsigned u3,
-                                 unsigned u4,
-                                 unsigned u5)
-{
-  char buf[1024];
-  strcpy(buf, name);
-  strcat(buf, "@");
-  u_strcat(buf, uw1);
-  strcat(buf, ",");
-  u_strcat(buf, uw2);
-  strcat(buf, ",");
-  u_strcat(buf, u3);
-  strcat(buf, ",");
-  u_strcat(buf, u4);
-  strcat(buf, ",");
-  u_strcat(buf, u5);
-  if (strlen(buf) + 1 >= sizeof(buf))
-    error("device_tree_add_found_* - buffer overflow\n");
-  return device_tree_add_found(root, prefix, buf);
-}
-
-
-/* Parse a device name, various formats */
-
-#define SCAN_INIT(NAME) \
-  char *START = (char*)0; \
-  char *END = (char*)0; \
-  int COUNT = -1; \
-  /* find the first element */ \
-  END = strchr(NAME, '@'); \
-  if (END == (char*)0) \
-    return COUNT; \
-  COUNT += 1; \
-  START = END + 1
-
-#define SCAN_END \
-  return COUNT
-
-#define SCAN_U(U) \
-do { \
-  *U = strtoul(START, &END, 0); \
-  if (START == END) \
-    return COUNT; \
-  COUNT += 1; \
-  if (*END != ',') \
-    return COUNT; \
-  START = END + 1; \
-} while (0)
-
-#define SCAN_P(P) \
-do { \
-  *P = (void*)(unsigned)strtouq(START, END, 0); \
-  if (START == END) \
-    return COUNT; \
-  COUNT += 1; \
-  if (*END != ',') \
-    return COUNT; \
-  START = END + 1; \
-} while (0)
-
-#define SCAN_C(C, SIZE) \
-do { \
-  char *chp = C; \
-  END = START; \
-  while (*END != '\0' && *END != ',') { \
-    if (*END == '\\') \
-      END += 1; \
-    *chp = *END; \
-    chp += 1; \
-    END += 1; \
-    if ((SIZE) <= ((END) - (START))) \
-      return COUNT; /* overflow */ \
-  } \
-  *chp = '\0'; \
-  if (START == END) \
-    return COUNT; \
-  COUNT += 1; \
-  if (*END != ',') \
-    return COUNT; \
-  START = END + 1; \
-} while (0)
-
-int INLINE_DEVICE
-scand_c(const char *name,
-       char *c1,
-       unsigned c1size)
-{
-  SCAN_INIT(name);
-  SCAN_C(c1, c1size);
-  SCAN_END;
-}
-
-int INLINE_DEVICE
-scand_c_uw_u(const char *name,
-            char *c1,
-            unsigned c1size,
-            unsigned_word *uw2,
-            unsigned *u3)
-{
-  SCAN_INIT(name);
-  SCAN_C(c1, c1size);
-  SCAN_U(uw2);
-  SCAN_U(u3);
-  SCAN_END;
-}
-
-int INLINE_DEVICE
-scand_uw(const char *name,
-        unsigned_word *uw1)
-{
-  SCAN_INIT(name);
-  SCAN_U(uw1);
-  SCAN_END;
-}
-
-int INLINE_DEVICE
-scand_uw_c(const char *name,
-          unsigned_word *uw1,
-          char *c2,
-          unsigned c2size)
-{
-  SCAN_INIT(name);
-  SCAN_U(uw1);
-  SCAN_C(c2, c2size);
-  SCAN_END;
-}
-
-int INLINE_DEVICE
-scand_uw_u(const char *name,
-          unsigned_word *uw1,
-          unsigned *u2)
-{
-  SCAN_INIT(name);
-  SCAN_U(uw1);
-  SCAN_U(u2);
-  SCAN_END;
-}
-
-int INLINE_DEVICE
-scand_uw_u_u(const char *name,
-            unsigned_word *uw1,
-            unsigned *u2,
-            unsigned *u3)
-{
-  SCAN_INIT(name);
-  SCAN_U(uw1);
-  SCAN_U(u2);
-  SCAN_U(u3);
-  SCAN_END;
-}
-
-int INLINE_DEVICE
-scand_uw_u_u_c(const char *name,
-              unsigned_word *uw1,
-              unsigned *u2,
-              unsigned *u3,
-              char *c4,
-              unsigned c4size)
-{
-  SCAN_INIT(name);
-  SCAN_U(uw1);
-  SCAN_U(u2);
-  SCAN_U(u3);
-  SCAN_C(c4, c4size);
-  SCAN_END;
-}
-
-int INLINE_DEVICE
-scand_uw_uw(const char *name,
-           unsigned_word *uw1,
-           unsigned_word *uw2)
-{
-  SCAN_INIT(name);
-  SCAN_U(uw1);
-  SCAN_U(uw2);
-  SCAN_END;
-}
-
-int INLINE_DEVICE
-scand_uw_uw_u(const char *name,
-             unsigned_word *uw1,
-             unsigned_word *uw2,
-             unsigned *u3)
-{
-  SCAN_INIT(name);
-  SCAN_U(uw1);
-  SCAN_U(uw2);
-  SCAN_U(u3);
-  SCAN_END;
-}
-
-int INLINE_DEVICE
-scand_uw_uw_u_u_c(const char *name,
-                 unsigned_word *uw1,
-                 unsigned_word *uw2,
-                 unsigned *u3,
-                 unsigned *u4,
-                 char *c5,
-                 unsigned c5size)
-{
-  SCAN_INIT(name);
-  SCAN_U(uw1);
-  SCAN_U(uw2);
-  SCAN_U(u3);
-  SCAN_U(u4);
-  SCAN_C(c5, c5size);
-  SCAN_END;
-}
-
-int INLINE_DEVICE
-scand_uw_uw_u_u_u(const char *name,
-                 unsigned_word *uw1,
-                 unsigned_word *uw2,
-                 unsigned *u3,
-                 unsigned *u4,
-                 unsigned *u5)
-{
-  SCAN_INIT(name);
-  SCAN_U(uw1);
-  SCAN_U(uw2);
-  SCAN_U(u3);
-  SCAN_U(u4);
-  SCAN_U(u5);
-  SCAN_END;
+  /* ensure that the devices #address/size-cells is consistent */
+  nr_address_cells = device_nr_address_cells(me);
+  if (device_find_property(me, "#address-cells") != NULL
+      && (nr_address_cells
+         != device_find_integer_property(me, "#address-cells")))
+    device_error(me, "#address-cells property used before defined");
+  nr_size_cells = device_nr_size_cells(me);
+  if (device_find_property(me, "#size-cells") != NULL
+      && (nr_size_cells
+         != device_find_integer_property(me, "#size-cells")))
+    device_error(me, "#size-cells property used before defined");
+
+  /* now init it */
+  if (me->callback->init.address != NULL)
+    me->callback->init.address(me);
 }
 
+INLINE_DEVICE\
+(void)
+device_init_data(device *me,
+                   void *data)
+{
+  TRACE(trace_device_init, ("device_init_data - initializing %s", me->path));
+  if (me->callback->init.data != NULL)
+    me->callback->init.data(me);
+}
 
 #endif /* _DEVICE_C_ */
This page took 0.048954 seconds and 4 git commands to generate.