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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-old/] [gdb-7.1/] [sim/] [ppc/] [device.c] - Diff between revs 227 and 816

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

Rev 227 Rev 816
/*  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 _DEVICE_C_
#ifndef _DEVICE_C_
#define _DEVICE_C_
#define _DEVICE_C_
 
 
#include <stdio.h>
#include <stdio.h>
 
 
#include "device_table.h"
#include "device_table.h"
#include "cap.h"
#include "cap.h"
 
 
#include "events.h"
#include "events.h"
#include "psim.h"
#include "psim.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>
 
 
STATIC_INLINE_DEVICE (void) clean_device_properties(device *);
STATIC_INLINE_DEVICE (void) clean_device_properties(device *);
 
 
/* property entries */
/* property entries */
 
 
typedef struct _device_property_entry device_property_entry;
typedef struct _device_property_entry device_property_entry;
struct _device_property_entry {
struct _device_property_entry {
  device_property_entry *next;
  device_property_entry *next;
  device_property *value;
  device_property *value;
  const void *init_array;
  const void *init_array;
  unsigned sizeof_init_array;
  unsigned sizeof_init_array;
};
};
 
 
 
 
/* Interrupt edges */
/* Interrupt edges */
 
 
typedef struct _device_interrupt_edge device_interrupt_edge;
typedef struct _device_interrupt_edge device_interrupt_edge;
struct _device_interrupt_edge {
struct _device_interrupt_edge {
  int my_port;
  int my_port;
  device *dest;
  device *dest;
  int dest_port;
  int dest_port;
  device_interrupt_edge *next;
  device_interrupt_edge *next;
  object_disposition disposition;
  object_disposition disposition;
};
};
 
 
STATIC_INLINE_DEVICE\
STATIC_INLINE_DEVICE\
(void)
(void)
attach_device_interrupt_edge(device_interrupt_edge **list,
attach_device_interrupt_edge(device_interrupt_edge **list,
                             int my_port,
                             int my_port,
                             device *dest,
                             device *dest,
                             int dest_port,
                             int dest_port,
                             object_disposition disposition)
                             object_disposition disposition)
{
{
  device_interrupt_edge *new_edge = ZALLOC(device_interrupt_edge);
  device_interrupt_edge *new_edge = ZALLOC(device_interrupt_edge);
  new_edge->my_port = my_port;
  new_edge->my_port = my_port;
  new_edge->dest = dest;
  new_edge->dest = dest;
  new_edge->dest_port = dest_port;
  new_edge->dest_port = dest_port;
  new_edge->next = *list;
  new_edge->next = *list;
  new_edge->disposition = disposition;
  new_edge->disposition = disposition;
  *list = new_edge;
  *list = new_edge;
}
}
 
 
STATIC_INLINE_DEVICE\
STATIC_INLINE_DEVICE\
(void)
(void)
detach_device_interrupt_edge(device *me,
detach_device_interrupt_edge(device *me,
                             device_interrupt_edge **list,
                             device_interrupt_edge **list,
                             int my_port,
                             int my_port,
                             device *dest,
                             device *dest,
                             int dest_port)
                             int dest_port)
{
{
  while (*list != NULL) {
  while (*list != NULL) {
    device_interrupt_edge *old_edge = *list;
    device_interrupt_edge *old_edge = *list;
    if (old_edge->dest == dest
    if (old_edge->dest == dest
        && old_edge->dest_port == dest_port
        && old_edge->dest_port == dest_port
        && old_edge->my_port == my_port) {
        && old_edge->my_port == my_port) {
      if (old_edge->disposition == permenant_object)
      if (old_edge->disposition == permenant_object)
        device_error(me, "attempt to delete permenant interrupt");
        device_error(me, "attempt to delete permenant interrupt");
      *list = old_edge->next;
      *list = old_edge->next;
      zfree(old_edge);
      zfree(old_edge);
      return;
      return;
    }
    }
  }
  }
  device_error(me, "attempt to delete unattached interrupt");
  device_error(me, "attempt to delete unattached interrupt");
}
}
 
 
STATIC_INLINE_DEVICE\
STATIC_INLINE_DEVICE\
(void)
(void)
clean_device_interrupt_edges(device_interrupt_edge **list)
clean_device_interrupt_edges(device_interrupt_edge **list)
{
{
  while (*list != NULL) {
  while (*list != NULL) {
    device_interrupt_edge *old_edge = *list;
    device_interrupt_edge *old_edge = *list;
    switch (old_edge->disposition) {
    switch (old_edge->disposition) {
    case permenant_object:
    case permenant_object:
      list = &old_edge->next;
      list = &old_edge->next;
      break;
      break;
    case tempoary_object:
    case tempoary_object:
      *list = old_edge->next;
      *list = old_edge->next;
      zfree(old_edge);
      zfree(old_edge);
      break;
      break;
    }
    }
  }
  }
}
}
 
 
 
 
/* A device */
/* A device */
 
 
struct _device {
struct _device {
 
 
  /* my name is ... */
  /* my name is ... */
  const char *name;
  const char *name;
  device_unit unit_address;
  device_unit unit_address;
  const char *path;
  const char *path;
  int nr_address_cells;
  int nr_address_cells;
  int nr_size_cells;
  int nr_size_cells;
 
 
  /* device tree */
  /* device tree */
  device *parent;
  device *parent;
  device *children;
  device *children;
  device *sibling;
  device *sibling;
 
 
  /* its template methods */
  /* its template methods */
  void *data; /* device specific data */
  void *data; /* device specific data */
  const device_callbacks *callback;
  const device_callbacks *callback;
 
 
  /* device properties */
  /* device properties */
  device_property_entry *properties;
  device_property_entry *properties;
 
 
  /* interrupts */
  /* interrupts */
  device_interrupt_edge *interrupt_destinations;
  device_interrupt_edge *interrupt_destinations;
 
 
  /* any open instances of this device */
  /* any open instances of this device */
  device_instance *instances;
  device_instance *instances;
 
 
  /* the internal/external mappings and other global requirements */
  /* the internal/external mappings and other global requirements */
  cap *ihandles;
  cap *ihandles;
  cap *phandles;
  cap *phandles;
  psim *system;
  psim *system;
 
 
  /* debugging */
  /* debugging */
  int trace;
  int trace;
};
};
 
 
 
 
/* an instance of a device */
/* an instance of a device */
struct _device_instance {
struct _device_instance {
  void *data;
  void *data;
  char *args;
  char *args;
  char *path;
  char *path;
  const device_instance_callbacks *callback;
  const device_instance_callbacks *callback;
  /* the root instance */
  /* the root instance */
  device *owner;
  device *owner;
  device_instance *next;
  device_instance *next;
  /* interposed instance */
  /* interposed instance */
  device_instance *parent;
  device_instance *parent;
  device_instance *child;
  device_instance *child;
};
};
 
 
 
 


/* creation */
/* creation */
 
 
STATIC_INLINE_DEVICE\
STATIC_INLINE_DEVICE\
(const char *)
(const char *)
device_full_name(device *leaf,
device_full_name(device *leaf,
                 char *buf,
                 char *buf,
                 unsigned sizeof_buf)
                 unsigned sizeof_buf)
{
{
  /* get a buffer */
  /* get a buffer */
  char full_name[1024];
  char full_name[1024];
  if (buf == (char*)0) {
  if (buf == (char*)0) {
    buf = full_name;
    buf = full_name;
    sizeof_buf = sizeof(full_name);
    sizeof_buf = sizeof(full_name);
  }
  }
 
 
  /* construct a name */
  /* construct a name */
  if (leaf->parent == NULL) {
  if (leaf->parent == NULL) {
    if (sizeof_buf < 1)
    if (sizeof_buf < 1)
      error("device_full_name: buffer overflow");
      error("device_full_name: buffer overflow");
    *buf = '\0';
    *buf = '\0';
  }
  }
  else {
  else {
    char unit[1024];
    char unit[1024];
    device_full_name(leaf->parent, buf, sizeof_buf);
    device_full_name(leaf->parent, buf, sizeof_buf);
    if (leaf->parent != NULL
    if (leaf->parent != NULL
        && device_encode_unit(leaf->parent,
        && device_encode_unit(leaf->parent,
                              &leaf->unit_address,
                              &leaf->unit_address,
                              unit+1,
                              unit+1,
                              sizeof(unit)-1) > 0)
                              sizeof(unit)-1) > 0)
      unit[0] = '@';
      unit[0] = '@';
    else
    else
      unit[0] = '\0';
      unit[0] = '\0';
    if (strlen(buf) + strlen("/") + strlen(leaf->name) + strlen(unit)
    if (strlen(buf) + strlen("/") + strlen(leaf->name) + strlen(unit)
        >= sizeof_buf)
        >= sizeof_buf)
      error("device_full_name: buffer overflow");
      error("device_full_name: buffer overflow");
    strcat(buf, "/");
    strcat(buf, "/");
    strcat(buf, leaf->name);
    strcat(buf, leaf->name);
    strcat (buf, unit);
    strcat (buf, unit);
  }
  }
 
 
  /* return it usefully */
  /* return it usefully */
  if (buf == full_name)
  if (buf == full_name)
    buf = (char *) strdup(full_name);
    buf = (char *) strdup(full_name);
  return buf;
  return buf;
}
}
 
 
STATIC_INLINE_DEVICE\
STATIC_INLINE_DEVICE\
(device *)
(device *)
device_create_from(const char *name,
device_create_from(const char *name,
                   const device_unit *unit_address,
                   const device_unit *unit_address,
                   void *data,
                   void *data,
                   const device_callbacks *callbacks,
                   const device_callbacks *callbacks,
                   device *parent)
                   device *parent)
{
{
  device *new_device = ZALLOC(device);
  device *new_device = ZALLOC(device);
 
 
  /* insert it into the device tree */
  /* insert it into the device tree */
  new_device->parent = parent;
  new_device->parent = parent;
  new_device->children = NULL;
  new_device->children = NULL;
  if (parent != NULL) {
  if (parent != NULL) {
    device **sibling = &parent->children;
    device **sibling = &parent->children;
    while ((*sibling) != NULL)
    while ((*sibling) != NULL)
      sibling = &(*sibling)->sibling;
      sibling = &(*sibling)->sibling;
    *sibling = new_device;
    *sibling = new_device;
  }
  }
 
 
  /* give it a name */
  /* give it a name */
  new_device->name = (char *) strdup(name);
  new_device->name = (char *) strdup(name);
  new_device->unit_address = *unit_address;
  new_device->unit_address = *unit_address;
  new_device->path = device_full_name(new_device, NULL, 0);
  new_device->path = device_full_name(new_device, NULL, 0);
 
 
  /* its template */
  /* its template */
  new_device->data = data;
  new_device->data = data;
  new_device->callback = callbacks;
  new_device->callback = callbacks;
 
 
  /* its properties - already null */
  /* its properties - already null */
  /* interrupts - already null */
  /* interrupts - already null */
 
 
  /* mappings - if needed */
  /* mappings - if needed */
  if (parent == NULL) {
  if (parent == NULL) {
    new_device->ihandles = cap_create(name);
    new_device->ihandles = cap_create(name);
    new_device->phandles = cap_create(name);
    new_device->phandles = cap_create(name);
  }
  }
  else {
  else {
    new_device->ihandles = device_root(parent)->ihandles;
    new_device->ihandles = device_root(parent)->ihandles;
    new_device->phandles = device_root(parent)->phandles;
    new_device->phandles = device_root(parent)->phandles;
  }
  }
 
 
  cap_add(new_device->phandles, new_device);
  cap_add(new_device->phandles, new_device);
  return new_device;
  return new_device;
}
}
 
 
 
 
 
 
INLINE_DEVICE\
INLINE_DEVICE\
(device *)
(device *)
device_create(device *parent,
device_create(device *parent,
              const char *base,
              const char *base,
              const char *name,
              const char *name,
              const char *unit_address,
              const char *unit_address,
              const char *args)
              const char *args)
{
{
  const device_descriptor *const *table;
  const device_descriptor *const *table;
  for (table = device_table; *table != NULL; table++) {
  for (table = device_table; *table != NULL; table++) {
    const device_descriptor *descr;
    const device_descriptor *descr;
    for (descr = *table; descr->name != NULL; descr++) {
    for (descr = *table; descr->name != NULL; descr++) {
      if (strcmp(base, descr->name) == 0) {
      if (strcmp(base, descr->name) == 0) {
        device_unit address = { 0 };
        device_unit address = { 0 };
        void *data = NULL;
        void *data = NULL;
        if (parent != NULL)
        if (parent != NULL)
          if (device_decode_unit(parent, unit_address, &address) < 0)
          if (device_decode_unit(parent, unit_address, &address) < 0)
            device_error(parent, "invalid address %s for device %s",
            device_error(parent, "invalid address %s for device %s",
                         unit_address, name);
                         unit_address, name);
        if (descr->creator != NULL)
        if (descr->creator != NULL)
          data = descr->creator(name, &address, args);
          data = descr->creator(name, &address, args);
        return device_create_from(name, &address, data,
        return device_create_from(name, &address, data,
                                  descr->callbacks, parent);
                                  descr->callbacks, parent);
      }
      }
    }
    }
  }
  }
  device_error(parent, "attempt to attach unknown device %s", name);
  device_error(parent, "attempt to attach unknown device %s", name);
  return NULL;
  return NULL;
}
}
 
 
 
 
 
 
INLINE_DEVICE\
INLINE_DEVICE\
(void)
(void)
device_usage(int verbose)
device_usage(int verbose)
{
{
  const device_descriptor *const *table;
  const device_descriptor *const *table;
  if (verbose == 1) {
  if (verbose == 1) {
    int pos = 0;
    int pos = 0;
    for (table = device_table; *table != NULL; table++) {
    for (table = device_table; *table != NULL; table++) {
      const device_descriptor *descr;
      const device_descriptor *descr;
      for (descr = *table; descr->name != NULL; descr++) {
      for (descr = *table; descr->name != NULL; descr++) {
        pos += strlen(descr->name) + 2;
        pos += strlen(descr->name) + 2;
        if (pos > 75) {
        if (pos > 75) {
          pos = strlen(descr->name) + 2;
          pos = strlen(descr->name) + 2;
          printf_filtered("\n");
          printf_filtered("\n");
        }
        }
        printf_filtered("  %s", descr->name);
        printf_filtered("  %s", descr->name);
      }
      }
      printf_filtered("\n");
      printf_filtered("\n");
    }
    }
  }
  }
  if (verbose > 1) {
  if (verbose > 1) {
    for (table = device_table; *table != NULL; table++) {
    for (table = device_table; *table != NULL; table++) {
      const device_descriptor *descr;
      const device_descriptor *descr;
      for (descr = *table; descr->name != NULL; descr++) {
      for (descr = *table; descr->name != NULL; descr++) {
        printf_filtered("  %s:\n", descr->name);
        printf_filtered("  %s:\n", descr->name);
        /* interrupt ports */
        /* interrupt ports */
        if (descr->callbacks->interrupt.ports != NULL) {
        if (descr->callbacks->interrupt.ports != NULL) {
          const device_interrupt_port_descriptor *ports =
          const device_interrupt_port_descriptor *ports =
            descr->callbacks->interrupt.ports;
            descr->callbacks->interrupt.ports;
          printf_filtered("    interrupt ports:");
          printf_filtered("    interrupt ports:");
          while (ports->name != NULL) {
          while (ports->name != NULL) {
            printf_filtered(" %s", ports->name);
            printf_filtered(" %s", ports->name);
            ports++;
            ports++;
          }
          }
          printf_filtered("\n");
          printf_filtered("\n");
        }
        }
        /* general info */
        /* general info */
        if (descr->callbacks->usage != NULL)
        if (descr->callbacks->usage != NULL)
          descr->callbacks->usage(verbose);
          descr->callbacks->usage(verbose);
      }
      }
    }
    }
  }
  }
}
}
 
 
 
 
 
 
 
 


/* Device node: */
/* Device node: */
 
 
INLINE_DEVICE\
INLINE_DEVICE\
(device *)
(device *)
device_parent(device *me)
device_parent(device *me)
{
{
  return me->parent;
  return me->parent;
}
}
 
 
INLINE_DEVICE\
INLINE_DEVICE\
(device *)
(device *)
device_root(device *me)
device_root(device *me)
{
{
  ASSERT(me != NULL);
  ASSERT(me != NULL);
  while (me->parent != NULL)
  while (me->parent != NULL)
    me = me->parent;
    me = me->parent;
  return me;
  return me;
}
}
 
 
INLINE_DEVICE\
INLINE_DEVICE\
(device *)
(device *)
device_sibling(device *me)
device_sibling(device *me)
{
{
  return me->sibling;
  return me->sibling;
}
}
 
 
INLINE_DEVICE\
INLINE_DEVICE\
(device *)
(device *)
device_child(device *me)
device_child(device *me)
{
{
  return me->children;
  return me->children;
}
}
 
 
INLINE_DEVICE\
INLINE_DEVICE\
(const char *)
(const char *)
device_name(device *me)
device_name(device *me)
{
{
  return me->name;
  return me->name;
}
}
 
 
INLINE_DEVICE\
INLINE_DEVICE\
(const char *)
(const char *)
device_path(device *me)
device_path(device *me)
{
{
  return me->path;
  return me->path;
}
}
 
 
INLINE_DEVICE\
INLINE_DEVICE\
(void *)
(void *)
device_data(device *me)
device_data(device *me)
{
{
  return me->data;
  return me->data;
}
}
 
 
INLINE_DEVICE\
INLINE_DEVICE\
(psim *)
(psim *)
device_system(device *me)
device_system(device *me)
{
{
  return me->system;
  return me->system;
}
}
 
 
INLINE_DEVICE\
INLINE_DEVICE\
(const device_unit *)
(const device_unit *)
device_unit_address(device *me)
device_unit_address(device *me)
{
{
  return &me->unit_address;
  return &me->unit_address;
}
}
 
 
 
 
INLINE_DEVICE\
INLINE_DEVICE\
(int)
(int)
device_address_to_attach_address(device *me,
device_address_to_attach_address(device *me,
                                 const device_unit *address,
                                 const device_unit *address,
                                 int *attach_space,
                                 int *attach_space,
                                 unsigned_word *attach_address,
                                 unsigned_word *attach_address,
                                 device *client)
                                 device *client)
{
{
  if (me->callback->convert.address_to_attach_address == NULL)
  if (me->callback->convert.address_to_attach_address == NULL)
    device_error(me, "no convert.address_to_attach_address method");
    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);
  return me->callback->convert.address_to_attach_address(me, address, attach_space, attach_address, client);
}
}
 
 
 
 
INLINE_DEVICE\
INLINE_DEVICE\
(int)
(int)
device_size_to_attach_size(device *me,
device_size_to_attach_size(device *me,
                           const device_unit *size,
                           const device_unit *size,
                           unsigned *nr_bytes,
                           unsigned *nr_bytes,
                           device *client)
                           device *client)
{
{
  if (me->callback->convert.size_to_attach_size == NULL)
  if (me->callback->convert.size_to_attach_size == NULL)
    device_error(me, "no convert.size_to_attach_size method");
    device_error(me, "no convert.size_to_attach_size method");
  return me->callback->convert.size_to_attach_size(me, size, nr_bytes, client);
  return me->callback->convert.size_to_attach_size(me, size, nr_bytes, client);
}
}
 
 
 
 
INLINE_DEVICE\
INLINE_DEVICE\
(int)
(int)
device_decode_unit(device *bus,
device_decode_unit(device *bus,
                   const char *unit,
                   const char *unit,
                   device_unit *address)
                   device_unit *address)
{
{
  if (bus->callback->convert.decode_unit == NULL)
  if (bus->callback->convert.decode_unit == NULL)
    device_error(bus, "no convert.decode_unit method");
    device_error(bus, "no convert.decode_unit method");
  return bus->callback->convert.decode_unit(bus, unit, address);
  return bus->callback->convert.decode_unit(bus, unit, address);
}
}
 
 
 
 
INLINE_DEVICE\
INLINE_DEVICE\
(int)
(int)
device_encode_unit(device *bus,
device_encode_unit(device *bus,
                   const device_unit *unit_address,
                   const device_unit *unit_address,
                   char *buf,
                   char *buf,
                   int sizeof_buf)
                   int sizeof_buf)
{
{
  if (bus->callback->convert.encode_unit == NULL)
  if (bus->callback->convert.encode_unit == NULL)
    device_error(bus, "no convert.encode_unit method");
    device_error(bus, "no convert.encode_unit method");
  return bus->callback->convert.encode_unit(bus, unit_address, buf, sizeof_buf);
  return bus->callback->convert.encode_unit(bus, unit_address, buf, sizeof_buf);
}
}
 
 
INLINE_DEVICE\
INLINE_DEVICE\
(unsigned)
(unsigned)
device_nr_address_cells(device *me)
device_nr_address_cells(device *me)
{
{
  if (me->nr_address_cells == 0) {
  if (me->nr_address_cells == 0) {
    if (device_find_property(me, "#address-cells") != NULL)
    if (device_find_property(me, "#address-cells") != NULL)
      me->nr_address_cells = device_find_integer_property(me, "#address-cells");
      me->nr_address_cells = device_find_integer_property(me, "#address-cells");
    else
    else
      me->nr_address_cells = 2;
      me->nr_address_cells = 2;
  }
  }
  return me->nr_address_cells;
  return me->nr_address_cells;
}
}
 
 
INLINE_DEVICE\
INLINE_DEVICE\
(unsigned)
(unsigned)
device_nr_size_cells(device *me)
device_nr_size_cells(device *me)
{
{
  if (me->nr_size_cells == 0) {
  if (me->nr_size_cells == 0) {
    if (device_find_property(me, "#size-cells") != NULL)
    if (device_find_property(me, "#size-cells") != NULL)
      me->nr_size_cells = device_find_integer_property(me, "#size-cells");
      me->nr_size_cells = device_find_integer_property(me, "#size-cells");
    else
    else
      me->nr_size_cells = 1;
      me->nr_size_cells = 1;
  }
  }
  return me->nr_size_cells;
  return me->nr_size_cells;
}
}
 
 
 
 


/* device-instance: */
/* device-instance: */
 
 
INLINE_DEVICE\
INLINE_DEVICE\
(device_instance *)
(device_instance *)
device_create_instance_from(device *me,
device_create_instance_from(device *me,
                            device_instance *parent,
                            device_instance *parent,
                            void *data,
                            void *data,
                            const char *path,
                            const char *path,
                            const char *args,
                            const char *args,
                            const device_instance_callbacks *callbacks)
                            const device_instance_callbacks *callbacks)
{
{
  device_instance *instance = ZALLOC(device_instance);
  device_instance *instance = ZALLOC(device_instance);
  if ((me == NULL) == (parent == NULL))
  if ((me == NULL) == (parent == NULL))
    device_error(me, "can't have both parent instance and parent device");
    device_error(me, "can't have both parent instance and parent device");
  /*instance->unit*/
  /*instance->unit*/
  /* link this instance into the devices list */
  /* link this instance into the devices list */
  if (me != NULL) {
  if (me != NULL) {
    ASSERT(parent == NULL);
    ASSERT(parent == NULL);
    instance->owner = me;
    instance->owner = me;
    instance->parent = NULL;
    instance->parent = NULL;
    /* link this instance into the front of the devices instance list */
    /* link this instance into the front of the devices instance list */
    instance->next = me->instances;
    instance->next = me->instances;
    me->instances = instance;
    me->instances = instance;
  }
  }
  if (parent != NULL) {
  if (parent != NULL) {
    device_instance **previous;
    device_instance **previous;
    ASSERT(parent->child == NULL);
    ASSERT(parent->child == NULL);
    parent->child = instance;
    parent->child = instance;
    ASSERT(me == NULL);
    ASSERT(me == NULL);
    instance->owner = parent->owner;
    instance->owner = parent->owner;
    instance->parent = parent;
    instance->parent = parent;
    /* in the devices instance list replace the parent instance with
    /* in the devices instance list replace the parent instance with
       this one */
       this one */
    instance->next = parent->next;
    instance->next = parent->next;
    /* replace parent with this new node */
    /* replace parent with this new node */
    previous = &instance->owner->instances;
    previous = &instance->owner->instances;
    while (*previous != parent) {
    while (*previous != parent) {
      ASSERT(*previous != NULL);
      ASSERT(*previous != NULL);
      previous = &(*previous)->next;
      previous = &(*previous)->next;
    }
    }
    *previous = instance;
    *previous = instance;
  }
  }
  instance->data = data;
  instance->data = data;
  instance->args = (args == NULL ? NULL : (char *) strdup(args));
  instance->args = (args == NULL ? NULL : (char *) strdup(args));
  instance->path = (path == NULL ? NULL : (char *) strdup(path));
  instance->path = (path == NULL ? NULL : (char *) strdup(path));
  instance->callback = callbacks;
  instance->callback = callbacks;
  cap_add(instance->owner->ihandles, instance);
  cap_add(instance->owner->ihandles, instance);
  return instance;
  return instance;
}
}
 
 
 
 
INLINE_DEVICE\
INLINE_DEVICE\
(device_instance *)
(device_instance *)
device_create_instance(device *me,
device_create_instance(device *me,
                       const char *path,
                       const char *path,
                       const char *args)
                       const char *args)
{
{
  /* create the instance */
  /* create the instance */
  if (me->callback->instance_create == NULL)
  if (me->callback->instance_create == NULL)
    device_error(me, "no instance_create method");
    device_error(me, "no instance_create method");
  return me->callback->instance_create(me, path, args);
  return me->callback->instance_create(me, path, args);
}
}
 
 
 
 
STATIC_INLINE_DEVICE\
STATIC_INLINE_DEVICE\
(void)
(void)
clean_device_instances(device *me)
clean_device_instances(device *me)
{
{
  device_instance **instance = &me->instances;
  device_instance **instance = &me->instances;
  while (*instance != NULL) {
  while (*instance != NULL) {
    device_instance *old_instance = *instance;
    device_instance *old_instance = *instance;
    device_instance_delete(old_instance);
    device_instance_delete(old_instance);
    instance = &me->instances;
    instance = &me->instances;
  }
  }
}
}
 
 
 
 
INLINE_DEVICE\
INLINE_DEVICE\
(void)
(void)
device_instance_delete(device_instance *instance)
device_instance_delete(device_instance *instance)
{
{
  device *me = instance->owner;
  device *me = instance->owner;
  if (instance->callback->delete == NULL)
  if (instance->callback->delete == NULL)
    device_error(me, "no delete method");
    device_error(me, "no delete method");
  instance->callback->delete(instance);
  instance->callback->delete(instance);
  if (instance->args != NULL)
  if (instance->args != NULL)
    zfree(instance->args);
    zfree(instance->args);
  if (instance->path != NULL)
  if (instance->path != NULL)
    zfree(instance->path);
    zfree(instance->path);
  if (instance->child == NULL) {
  if (instance->child == NULL) {
    /* only remove leaf nodes */
    /* only remove leaf nodes */
    device_instance **curr = &me->instances;
    device_instance **curr = &me->instances;
    while (*curr != instance) {
    while (*curr != instance) {
      ASSERT(*curr != NULL);
      ASSERT(*curr != NULL);
      curr = &(*curr)->next;
      curr = &(*curr)->next;
    }
    }
    *curr = instance->next;
    *curr = instance->next;
  }
  }
  else {
  else {
    /* check it isn't in the instance list */
    /* check it isn't in the instance list */
    device_instance *curr = me->instances;
    device_instance *curr = me->instances;
    while (curr != NULL) {
    while (curr != NULL) {
      ASSERT(curr != instance);
      ASSERT(curr != instance);
      curr = curr->next;
      curr = curr->next;
    }
    }
    /* unlink the child */
    /* unlink the child */
    ASSERT(instance->child->parent == instance);
    ASSERT(instance->child->parent == instance);
    instance->child->parent = NULL;
    instance->child->parent = NULL;
  }
  }
  cap_remove(me->ihandles, instance);
  cap_remove(me->ihandles, instance);
  zfree(instance);
  zfree(instance);
}
}
 
 
INLINE_DEVICE\
INLINE_DEVICE\
(int)
(int)
device_instance_read(device_instance *instance,
device_instance_read(device_instance *instance,
                     void *addr,
                     void *addr,
                     unsigned_word len)
                     unsigned_word len)
{
{
  device *me = instance->owner;
  device *me = instance->owner;
  if (instance->callback->read == NULL)
  if (instance->callback->read == NULL)
    device_error(me, "no read method");
    device_error(me, "no read method");
  return instance->callback->read(instance, addr, len);
  return instance->callback->read(instance, addr, len);
}
}
 
 
INLINE_DEVICE\
INLINE_DEVICE\
(int)
(int)
device_instance_write(device_instance *instance,
device_instance_write(device_instance *instance,
                      const void *addr,
                      const void *addr,
                      unsigned_word len)
                      unsigned_word len)
{
{
  device *me = instance->owner;
  device *me = instance->owner;
  if (instance->callback->write == NULL)
  if (instance->callback->write == NULL)
    device_error(me, "no write method");
    device_error(me, "no write method");
  return instance->callback->write(instance, addr, len);
  return instance->callback->write(instance, addr, len);
}
}
 
 
INLINE_DEVICE\
INLINE_DEVICE\
(int)
(int)
device_instance_seek(device_instance *instance,
device_instance_seek(device_instance *instance,
                     unsigned_word pos_hi,
                     unsigned_word pos_hi,
                     unsigned_word pos_lo)
                     unsigned_word pos_lo)
{
{
  device *me = instance->owner;
  device *me = instance->owner;
  if (instance->callback->seek == NULL)
  if (instance->callback->seek == NULL)
    device_error(me, "no seek method");
    device_error(me, "no seek method");
  return instance->callback->seek(instance, pos_hi, pos_lo);
  return instance->callback->seek(instance, pos_hi, pos_lo);
}
}
 
 
INLINE_DEVICE\
INLINE_DEVICE\
(int)
(int)
device_instance_call_method(device_instance *instance,
device_instance_call_method(device_instance *instance,
                            const char *method_name,
                            const char *method_name,
                            int n_stack_args,
                            int n_stack_args,
                            unsigned_cell stack_args[/*n_stack_args*/],
                            unsigned_cell stack_args[/*n_stack_args*/],
                            int n_stack_returns,
                            int n_stack_returns,
                            unsigned_cell stack_returns[/*n_stack_args*/])
                            unsigned_cell stack_returns[/*n_stack_args*/])
{
{
  device *me = instance->owner;
  device *me = instance->owner;
  const device_instance_methods *method = instance->callback->methods;
  const device_instance_methods *method = instance->callback->methods;
  if (method == NULL) {
  if (method == NULL) {
    device_error(me, "no methods (want %s)", method_name);
    device_error(me, "no methods (want %s)", method_name);
  }
  }
  while (method->name != NULL) {
  while (method->name != NULL) {
    if (strcmp(method->name, method_name) == 0) {
    if (strcmp(method->name, method_name) == 0) {
      return method->method(instance,
      return method->method(instance,
                            n_stack_args, stack_args,
                            n_stack_args, stack_args,
                            n_stack_returns, stack_returns);
                            n_stack_returns, stack_returns);
    }
    }
    method++;
    method++;
  }
  }
  device_error(me, "no %s method", method_name);
  device_error(me, "no %s method", method_name);
  return 0;
  return 0;
}
}
 
 
 
 
INLINE_DEVICE\
INLINE_DEVICE\
(device *)
(device *)
device_instance_device(device_instance *instance)
device_instance_device(device_instance *instance)
{
{
  return instance->owner;
  return instance->owner;
}
}
 
 
INLINE_DEVICE\
INLINE_DEVICE\
(const char *)
(const char *)
device_instance_path(device_instance *instance)
device_instance_path(device_instance *instance)
{
{
  return instance->path;
  return instance->path;
}
}
 
 
INLINE_DEVICE\
INLINE_DEVICE\
(void *)
(void *)
device_instance_data(device_instance *instance)
device_instance_data(device_instance *instance)
{
{
  return instance->data;
  return instance->data;
}
}
 
 
 
 


/* Device Properties: */
/* Device Properties: */
 
 
STATIC_INLINE_DEVICE\
STATIC_INLINE_DEVICE\
(device_property_entry *)
(device_property_entry *)
find_property_entry(device *me,
find_property_entry(device *me,
                     const char *property)
                     const char *property)
{
{
  device_property_entry *entry;
  device_property_entry *entry;
  ASSERT(property != NULL);
  ASSERT(property != NULL);
  entry = me->properties;
  entry = me->properties;
  while (entry != NULL) {
  while (entry != NULL) {
    if (strcmp(entry->value->name, property) == 0)
    if (strcmp(entry->value->name, property) == 0)
      return entry;
      return entry;
    entry = entry->next;
    entry = entry->next;
  }
  }
  return NULL;
  return NULL;
}
}
 
 
STATIC_INLINE_DEVICE\
STATIC_INLINE_DEVICE\
(void)
(void)
device_add_property(device *me,
device_add_property(device *me,
                    const char *property,
                    const char *property,
                    device_property_type type,
                    device_property_type type,
                    const void *init_array,
                    const void *init_array,
                    unsigned sizeof_init_array,
                    unsigned sizeof_init_array,
                    const void *array,
                    const void *array,
                    unsigned sizeof_array,
                    unsigned sizeof_array,
                    const device_property *original,
                    const device_property *original,
                    object_disposition disposition)
                    object_disposition disposition)
{
{
  device_property_entry *new_entry = NULL;
  device_property_entry *new_entry = NULL;
  device_property *new_value = NULL;
  device_property *new_value = NULL;
 
 
  /* find the list end */
  /* find the list end */
  device_property_entry **insertion_point = &me->properties;
  device_property_entry **insertion_point = &me->properties;
  while (*insertion_point != NULL) {
  while (*insertion_point != NULL) {
    if (strcmp((*insertion_point)->value->name, property) == 0)
    if (strcmp((*insertion_point)->value->name, property) == 0)
      return;
      return;
    insertion_point = &(*insertion_point)->next;
    insertion_point = &(*insertion_point)->next;
  }
  }
 
 
  /* create a new value */
  /* create a new value */
  new_value = ZALLOC(device_property);
  new_value = ZALLOC(device_property);
  new_value->name = (char *) strdup(property);
  new_value->name = (char *) strdup(property);
  new_value->type = type;
  new_value->type = type;
  if (sizeof_array > 0) {
  if (sizeof_array > 0) {
    void *new_array = zalloc(sizeof_array);
    void *new_array = zalloc(sizeof_array);
    memcpy(new_array, array, sizeof_array);
    memcpy(new_array, array, sizeof_array);
    new_value->array = new_array;
    new_value->array = new_array;
    new_value->sizeof_array = sizeof_array;
    new_value->sizeof_array = sizeof_array;
  }
  }
  new_value->owner = me;
  new_value->owner = me;
  new_value->original = original;
  new_value->original = original;
  new_value->disposition = disposition;
  new_value->disposition = disposition;
 
 
  /* insert the value into the list */
  /* insert the value into the list */
  new_entry = ZALLOC(device_property_entry);
  new_entry = ZALLOC(device_property_entry);
  *insertion_point = new_entry;
  *insertion_point = new_entry;
  if (sizeof_init_array > 0) {
  if (sizeof_init_array > 0) {
    void *new_init_array = zalloc(sizeof_init_array);
    void *new_init_array = zalloc(sizeof_init_array);
    memcpy(new_init_array, init_array, sizeof_init_array);
    memcpy(new_init_array, init_array, sizeof_init_array);
    new_entry->init_array = new_init_array;
    new_entry->init_array = new_init_array;
    new_entry->sizeof_init_array = sizeof_init_array;
    new_entry->sizeof_init_array = sizeof_init_array;
  }
  }
  new_entry->value = new_value;
  new_entry->value = new_value;
}
}
 
 
 
 
/* local - not available externally */
/* local - not available externally */
STATIC_INLINE_DEVICE\
STATIC_INLINE_DEVICE\
(void)
(void)
device_set_property(device *me,
device_set_property(device *me,
                    const char *property,
                    const char *property,
                    device_property_type type,
                    device_property_type type,
                    const void *array,
                    const void *array,
                    int sizeof_array)
                    int sizeof_array)
{
{
  /* find the property */
  /* find the property */
  device_property_entry *entry = find_property_entry(me, property);
  device_property_entry *entry = find_property_entry(me, property);
  if (entry != NULL) {
  if (entry != NULL) {
    /* existing property - update it */
    /* existing property - update it */
    void *new_array = 0;
    void *new_array = 0;
    device_property *value = entry->value;
    device_property *value = entry->value;
    /* check the type matches */
    /* check the type matches */
    if (value->type != type)
    if (value->type != type)
      device_error(me, "conflict between type of new and old value for property %s", property);
      device_error(me, "conflict between type of new and old value for property %s", property);
    /* replace its value */
    /* replace its value */
    if (value->array != NULL)
    if (value->array != NULL)
      zfree((void*)value->array);
      zfree((void*)value->array);
    new_array = (sizeof_array > 0
    new_array = (sizeof_array > 0
                 ? zalloc(sizeof_array)
                 ? zalloc(sizeof_array)
                 : (void*)0);
                 : (void*)0);
    value->array = new_array;
    value->array = new_array;
    value->sizeof_array = sizeof_array;
    value->sizeof_array = sizeof_array;
    if (sizeof_array > 0)
    if (sizeof_array > 0)
      memcpy(new_array, array, sizeof_array);
      memcpy(new_array, array, sizeof_array);
    return;
    return;
  }
  }
  else {
  else {
    /* new property - create it */
    /* new property - create it */
    device_add_property(me, property, type,
    device_add_property(me, property, type,
                        NULL, 0, array, sizeof_array,
                        NULL, 0, array, sizeof_array,
                        NULL, tempoary_object);
                        NULL, tempoary_object);
  }
  }
}
}
 
 
 
 
STATIC_INLINE_DEVICE\
STATIC_INLINE_DEVICE\
(void)
(void)
clean_device_properties(device *me)
clean_device_properties(device *me)
{
{
  device_property_entry **delete_point = &me->properties;
  device_property_entry **delete_point = &me->properties;
  while (*delete_point != NULL) {
  while (*delete_point != NULL) {
    device_property_entry *current = *delete_point;
    device_property_entry *current = *delete_point;
    switch (current->value->disposition) {
    switch (current->value->disposition) {
    case permenant_object:
    case permenant_object:
      /* zap the current value, will be initialized later */
      /* zap the current value, will be initialized later */
      ASSERT(current->init_array != NULL);
      ASSERT(current->init_array != NULL);
      if (current->value->array != NULL) {
      if (current->value->array != NULL) {
        zfree((void*)current->value->array);
        zfree((void*)current->value->array);
        current->value->array = NULL;
        current->value->array = NULL;
      }
      }
      delete_point = &(*delete_point)->next;
      delete_point = &(*delete_point)->next;
      break;
      break;
    case tempoary_object:
    case tempoary_object:
      /* zap the actual property, was created during simulation run */
      /* zap the actual property, was created during simulation run */
      ASSERT(current->init_array == NULL);
      ASSERT(current->init_array == NULL);
      *delete_point = current->next;
      *delete_point = current->next;
      if (current->value->array != NULL)
      if (current->value->array != NULL)
        zfree((void*)current->value->array);
        zfree((void*)current->value->array);
      zfree(current->value);
      zfree(current->value);
      zfree(current);
      zfree(current);
      break;
      break;
    }
    }
  }
  }
}
}
 
 
 
 
INLINE_DEVICE\
INLINE_DEVICE\
(void)
(void)
device_init_static_properties(device *me,
device_init_static_properties(device *me,
                              void *data)
                              void *data)
{
{
  device_property_entry *property;
  device_property_entry *property;
  for (property = me->properties;
  for (property = me->properties;
       property != NULL;
       property != NULL;
       property = property->next) {
       property = property->next) {
    ASSERT(property->init_array != NULL);
    ASSERT(property->init_array != NULL);
    ASSERT(property->value->array == NULL);
    ASSERT(property->value->array == NULL);
    ASSERT(property->value->disposition == permenant_object);
    ASSERT(property->value->disposition == permenant_object);
    switch (property->value->type) {
    switch (property->value->type) {
    case array_property:
    case array_property:
    case boolean_property:
    case boolean_property:
    case range_array_property:
    case range_array_property:
    case reg_array_property:
    case reg_array_property:
    case string_property:
    case string_property:
    case string_array_property:
    case string_array_property:
    case integer_property:
    case integer_property:
      /* delete the property, and replace it with the original */
      /* delete the property, and replace it with the original */
      device_set_property(me, property->value->name,
      device_set_property(me, property->value->name,
                          property->value->type,
                          property->value->type,
                          property->init_array,
                          property->init_array,
                          property->sizeof_init_array);
                          property->sizeof_init_array);
      break;
      break;
    case ihandle_property:
    case ihandle_property:
      break;
      break;
    }
    }
  }
  }
}
}
 
 
 
 
INLINE_DEVICE\
INLINE_DEVICE\
(void)
(void)
device_init_runtime_properties(device *me,
device_init_runtime_properties(device *me,
                               void *data)
                               void *data)
{
{
  device_property_entry *property;
  device_property_entry *property;
  for (property = me->properties;
  for (property = me->properties;
       property != NULL;
       property != NULL;
       property = property->next) {
       property = property->next) {
    switch (property->value->disposition) {
    switch (property->value->disposition) {
    case permenant_object:
    case permenant_object:
      switch (property->value->type) {
      switch (property->value->type) {
      case ihandle_property:
      case ihandle_property:
        {
        {
          device_instance *ihandle;
          device_instance *ihandle;
          ihandle_runtime_property_spec spec;
          ihandle_runtime_property_spec spec;
          ASSERT(property->init_array != NULL);
          ASSERT(property->init_array != NULL);
          ASSERT(property->value->array == NULL);
          ASSERT(property->value->array == NULL);
          device_find_ihandle_runtime_property(me, property->value->name, &spec);
          device_find_ihandle_runtime_property(me, property->value->name, &spec);
          ihandle = tree_instance(me, spec.full_path);
          ihandle = tree_instance(me, spec.full_path);
          device_set_ihandle_property(me, property->value->name, ihandle);
          device_set_ihandle_property(me, property->value->name, ihandle);
          break;
          break;
        }
        }
      case array_property:
      case array_property:
      case boolean_property:
      case boolean_property:
      case range_array_property:
      case range_array_property:
      case integer_property:
      case integer_property:
      case reg_array_property:
      case reg_array_property:
      case string_property:
      case string_property:
      case string_array_property:
      case string_array_property:
        ASSERT(property->init_array != NULL);
        ASSERT(property->init_array != NULL);
        ASSERT(property->value->array != NULL);
        ASSERT(property->value->array != NULL);
        break;
        break;
      }
      }
      break;
      break;
    case tempoary_object:
    case tempoary_object:
      ASSERT(property->init_array == NULL);
      ASSERT(property->init_array == NULL);
      ASSERT(property->value->array != NULL);
      ASSERT(property->value->array != NULL);
      break;
      break;
    }
    }
  }
  }
}
}
 
 
 
 
INLINE_DEVICE\
INLINE_DEVICE\
(const device_property *)
(const device_property *)
device_next_property(const device_property *property)
device_next_property(const device_property *property)
{
{
  /* find the property in the list */
  /* find the property in the list */
  device *owner = property->owner;
  device *owner = property->owner;
  device_property_entry *entry = owner->properties;
  device_property_entry *entry = owner->properties;
  while (entry != NULL && entry->value != property)
  while (entry != NULL && entry->value != property)
    entry = entry->next;
    entry = entry->next;
  /* now return the following property */
  /* now return the following property */
  ASSERT(entry != NULL); /* must be a member! */
  ASSERT(entry != NULL); /* must be a member! */
  if (entry->next != NULL)
  if (entry->next != NULL)
    return entry->next->value;
    return entry->next->value;
  else
  else
    return NULL;
    return NULL;
}
}
 
 
 
 
INLINE_DEVICE\
INLINE_DEVICE\
(const device_property *)
(const device_property *)
device_find_property(device *me,
device_find_property(device *me,
                     const char *property)
                     const char *property)
{
{
  if (me == NULL) {
  if (me == NULL) {
    return NULL;
    return NULL;
  }
  }
  else if (property == NULL || strcmp(property, "") == 0) {
  else if (property == NULL || strcmp(property, "") == 0) {
    if (me->properties == NULL)
    if (me->properties == NULL)
      return NULL;
      return NULL;
    else
    else
      return me->properties->value;
      return me->properties->value;
  }
  }
  else {
  else {
    device_property_entry *entry = find_property_entry(me, property);
    device_property_entry *entry = find_property_entry(me, property);
    if (entry != NULL)
    if (entry != NULL)
      return entry->value;
      return entry->value;
  }
  }
  return NULL;
  return NULL;
}
}
 
 
 
 
INLINE_DEVICE\
INLINE_DEVICE\
(void)
(void)
device_add_array_property(device *me,
device_add_array_property(device *me,
                          const char *property,
                          const char *property,
                          const void *array,
                          const void *array,
                          int sizeof_array)
                          int sizeof_array)
{
{
  device_add_property(me, property, array_property,
  device_add_property(me, property, array_property,
                      array, sizeof_array, array, sizeof_array,
                      array, sizeof_array, array, sizeof_array,
                      NULL, permenant_object);
                      NULL, permenant_object);
}
}
 
 
INLINE_DEVICE\
INLINE_DEVICE\
(void)
(void)
device_set_array_property(device *me,
device_set_array_property(device *me,
                          const char *property,
                          const char *property,
                          const void *array,
                          const void *array,
                          int sizeof_array)
                          int sizeof_array)
{
{
  device_set_property(me, property, array_property, array, sizeof_array);
  device_set_property(me, property, array_property, array, sizeof_array);
}
}
 
 
INLINE_DEVICE\
INLINE_DEVICE\
(const device_property *)
(const device_property *)
device_find_array_property(device *me,
device_find_array_property(device *me,
                           const char *property)
                           const char *property)
{
{
  const device_property *node;
  const device_property *node;
  node = device_find_property(me, property);
  node = device_find_property(me, property);
  if (node == (device_property*)0
  if (node == (device_property*)0
      || node->type != array_property)
      || node->type != array_property)
    device_error(me, "property %s not found or of wrong type", property);
    device_error(me, "property %s not found or of wrong type", property);
  return node;
  return node;
}
}
 
 
 
 
INLINE_DEVICE\
INLINE_DEVICE\
(void)
(void)
device_add_boolean_property(device *me,
device_add_boolean_property(device *me,
                            const char *property,
                            const char *property,
                            int boolean)
                            int boolean)
{
{
  signed32 new_boolean = (boolean ? -1 : 0);
  signed32 new_boolean = (boolean ? -1 : 0);
  device_add_property(me, property, boolean_property,
  device_add_property(me, property, boolean_property,
                      &new_boolean, sizeof(new_boolean),
                      &new_boolean, sizeof(new_boolean),
                      &new_boolean, sizeof(new_boolean),
                      &new_boolean, sizeof(new_boolean),
                      NULL, permenant_object);
                      NULL, permenant_object);
}
}
 
 
INLINE_DEVICE\
INLINE_DEVICE\
(int)
(int)
device_find_boolean_property(device *me,
device_find_boolean_property(device *me,
                             const char *property)
                             const char *property)
{
{
  const device_property *node;
  const device_property *node;
  unsigned_cell boolean;
  unsigned_cell boolean;
  node = device_find_property(me, property);
  node = device_find_property(me, property);
  if (node == (device_property*)0
  if (node == (device_property*)0
      || node->type != boolean_property)
      || node->type != boolean_property)
    device_error(me, "property %s not found or of wrong type", property);
    device_error(me, "property %s not found or of wrong type", property);
  ASSERT(sizeof(boolean) == node->sizeof_array);
  ASSERT(sizeof(boolean) == node->sizeof_array);
  memcpy(&boolean, node->array, sizeof(boolean));
  memcpy(&boolean, node->array, sizeof(boolean));
  return boolean;
  return boolean;
}
}
 
 
 
 
INLINE_DEVICE\
INLINE_DEVICE\
(void)
(void)
device_add_ihandle_runtime_property(device *me,
device_add_ihandle_runtime_property(device *me,
                                    const char *property,
                                    const char *property,
                                    const ihandle_runtime_property_spec *ihandle)
                                    const ihandle_runtime_property_spec *ihandle)
{
{
  /* enter the full path as the init array */
  /* enter the full path as the init array */
  device_add_property(me, property, ihandle_property,
  device_add_property(me, property, ihandle_property,
                      ihandle->full_path, strlen(ihandle->full_path) + 1,
                      ihandle->full_path, strlen(ihandle->full_path) + 1,
                      NULL, 0,
                      NULL, 0,
                      NULL, permenant_object);
                      NULL, permenant_object);
}
}
 
 
INLINE_DEVICE\
INLINE_DEVICE\
(void)
(void)
device_find_ihandle_runtime_property(device *me,
device_find_ihandle_runtime_property(device *me,
                                     const char *property,
                                     const char *property,
                                     ihandle_runtime_property_spec *ihandle)
                                     ihandle_runtime_property_spec *ihandle)
{
{
  device_property_entry *entry = find_property_entry(me, property);
  device_property_entry *entry = find_property_entry(me, property);
  TRACE(trace_devices,
  TRACE(trace_devices,
        ("device_find_ihandle_runtime_property(me=0x%lx, property=%s)\n",
        ("device_find_ihandle_runtime_property(me=0x%lx, property=%s)\n",
         (long)me, property));
         (long)me, property));
  if (entry == NULL
  if (entry == NULL
      || entry->value->type != ihandle_property
      || entry->value->type != ihandle_property
      || entry->value->disposition != permenant_object)
      || entry->value->disposition != permenant_object)
    device_error(me, "property %s not found or of wrong type", property);
    device_error(me, "property %s not found or of wrong type", property);
  ASSERT(entry->init_array != NULL);
  ASSERT(entry->init_array != NULL);
  /* the full path */
  /* the full path */
  ihandle->full_path = entry->init_array;
  ihandle->full_path = entry->init_array;
}
}
 
 
 
 
 
 
INLINE_DEVICE\
INLINE_DEVICE\
(void)
(void)
device_set_ihandle_property(device *me,
device_set_ihandle_property(device *me,
                            const char *property,
                            const char *property,
                            device_instance *ihandle)
                            device_instance *ihandle)
{
{
  unsigned_cell cells;
  unsigned_cell cells;
  cells = H2BE_cell(device_instance_to_external(ihandle));
  cells = H2BE_cell(device_instance_to_external(ihandle));
  device_set_property(me, property, ihandle_property,
  device_set_property(me, property, ihandle_property,
                      &cells, sizeof(cells));
                      &cells, sizeof(cells));
 
 
}
}
 
 
INLINE_DEVICE\
INLINE_DEVICE\
(device_instance *)
(device_instance *)
device_find_ihandle_property(device *me,
device_find_ihandle_property(device *me,
                             const char *property)
                             const char *property)
{
{
  const device_property *node;
  const device_property *node;
  unsigned_cell ihandle;
  unsigned_cell ihandle;
  device_instance *instance;
  device_instance *instance;
 
 
  node = device_find_property(me, property);
  node = device_find_property(me, property);
  if (node == NULL || node->type != ihandle_property)
  if (node == NULL || node->type != ihandle_property)
    device_error(me, "property %s not found or of wrong type", property);
    device_error(me, "property %s not found or of wrong type", property);
  if (node->array == NULL)
  if (node->array == NULL)
    device_error(me, "runtime property %s not yet initialized", property);
    device_error(me, "runtime property %s not yet initialized", property);
 
 
  ASSERT(sizeof(ihandle) == node->sizeof_array);
  ASSERT(sizeof(ihandle) == node->sizeof_array);
  memcpy(&ihandle, node->array, sizeof(ihandle));
  memcpy(&ihandle, node->array, sizeof(ihandle));
  instance = external_to_device_instance(me, BE2H_cell(ihandle));
  instance = external_to_device_instance(me, BE2H_cell(ihandle));
  ASSERT(instance != NULL);
  ASSERT(instance != NULL);
  return instance;
  return instance;
}
}
 
 
 
 
INLINE_DEVICE\
INLINE_DEVICE\
(void)
(void)
device_add_integer_property(device *me,
device_add_integer_property(device *me,
                            const char *property,
                            const char *property,
                            signed_cell integer)
                            signed_cell integer)
{
{
  H2BE(integer);
  H2BE(integer);
  device_add_property(me, property, integer_property,
  device_add_property(me, property, integer_property,
                      &integer, sizeof(integer),
                      &integer, sizeof(integer),
                      &integer, sizeof(integer),
                      &integer, sizeof(integer),
                      NULL, permenant_object);
                      NULL, permenant_object);
}
}
 
 
INLINE_DEVICE\
INLINE_DEVICE\
(signed_cell)
(signed_cell)
device_find_integer_property(device *me,
device_find_integer_property(device *me,
                             const char *property)
                             const char *property)
{
{
  const device_property *node;
  const device_property *node;
  signed_cell integer;
  signed_cell integer;
  TRACE(trace_devices,
  TRACE(trace_devices,
        ("device_find_integer(me=0x%lx, property=%s)\n",
        ("device_find_integer(me=0x%lx, property=%s)\n",
         (long)me, property));
         (long)me, property));
  node = device_find_property(me, property);
  node = device_find_property(me, property);
  if (node == (device_property*)0
  if (node == (device_property*)0
      || node->type != integer_property)
      || node->type != integer_property)
    device_error(me, "property %s not found or of wrong type", property);
    device_error(me, "property %s not found or of wrong type", property);
  ASSERT(sizeof(integer) == node->sizeof_array);
  ASSERT(sizeof(integer) == node->sizeof_array);
  memcpy(&integer, node->array, sizeof(integer));
  memcpy(&integer, node->array, sizeof(integer));
  return BE2H_cell(integer);
  return BE2H_cell(integer);
}
}
 
 
INLINE_DEVICE\
INLINE_DEVICE\
(int)
(int)
device_find_integer_array_property(device *me,
device_find_integer_array_property(device *me,
                                   const char *property,
                                   const char *property,
                                   unsigned index,
                                   unsigned index,
                                   signed_cell *integer)
                                   signed_cell *integer)
{
{
  const device_property *node;
  const device_property *node;
  int sizeof_integer = sizeof(*integer);
  int sizeof_integer = sizeof(*integer);
  signed_cell *cell;
  signed_cell *cell;
  TRACE(trace_devices,
  TRACE(trace_devices,
        ("device_find_integer(me=0x%lx, property=%s)\n",
        ("device_find_integer(me=0x%lx, property=%s)\n",
         (long)me, property));
         (long)me, property));
 
 
  /* check things sane */
  /* check things sane */
  node = device_find_property(me, property);
  node = device_find_property(me, property);
  if (node == (device_property*)0
  if (node == (device_property*)0
      || (node->type != integer_property
      || (node->type != integer_property
          && node->type != array_property))
          && node->type != array_property))
    device_error(me, "property %s not found or of wrong type", property);
    device_error(me, "property %s not found or of wrong type", property);
  if ((node->sizeof_array % sizeof_integer) != 0)
  if ((node->sizeof_array % sizeof_integer) != 0)
    device_error(me, "property %s contains an incomplete number of cells", property);
    device_error(me, "property %s contains an incomplete number of cells", property);
  if (node->sizeof_array <= sizeof_integer * index)
  if (node->sizeof_array <= sizeof_integer * index)
    return 0;
    return 0;
 
 
  /* Find and convert the value */
  /* Find and convert the value */
  cell = ((signed_cell*)node->array) + index;
  cell = ((signed_cell*)node->array) + index;
  *integer = BE2H_cell(*cell);
  *integer = BE2H_cell(*cell);
 
 
  return node->sizeof_array / sizeof_integer;
  return node->sizeof_array / sizeof_integer;
}
}
 
 
 
 
STATIC_INLINE_DEVICE\
STATIC_INLINE_DEVICE\
(unsigned_cell *)
(unsigned_cell *)
unit_address_to_cells(const device_unit *unit,
unit_address_to_cells(const device_unit *unit,
                      unsigned_cell *cell,
                      unsigned_cell *cell,
                      int nr_cells)
                      int nr_cells)
{
{
  int i;
  int i;
  ASSERT(nr_cells == unit->nr_cells);
  ASSERT(nr_cells == unit->nr_cells);
  for (i = 0; i < unit->nr_cells; i++) {
  for (i = 0; i < unit->nr_cells; i++) {
    *cell = H2BE_cell(unit->cells[i]);
    *cell = H2BE_cell(unit->cells[i]);
    cell += 1;
    cell += 1;
  }
  }
  return cell;
  return cell;
}
}
 
 
 
 
STATIC_INLINE_DEVICE\
STATIC_INLINE_DEVICE\
(const unsigned_cell *)
(const unsigned_cell *)
cells_to_unit_address(const unsigned_cell *cell,
cells_to_unit_address(const unsigned_cell *cell,
                      device_unit *unit,
                      device_unit *unit,
                      int nr_cells)
                      int nr_cells)
{
{
  int i;
  int i;
  memset(unit, 0, sizeof(*unit));
  memset(unit, 0, sizeof(*unit));
  unit->nr_cells = nr_cells;
  unit->nr_cells = nr_cells;
  for (i = 0; i < unit->nr_cells; i++) {
  for (i = 0; i < unit->nr_cells; i++) {
    unit->cells[i] = BE2H_cell(*cell);
    unit->cells[i] = BE2H_cell(*cell);
    cell += 1;
    cell += 1;
  }
  }
  return cell;
  return cell;
}
}
 
 
 
 
STATIC_INLINE_DEVICE\
STATIC_INLINE_DEVICE\
(unsigned)
(unsigned)
nr_range_property_cells(device *me,
nr_range_property_cells(device *me,
                        int nr_ranges)
                        int nr_ranges)
{
{
  return ((device_nr_address_cells(me)
  return ((device_nr_address_cells(me)
           + device_nr_address_cells(device_parent(me))
           + device_nr_address_cells(device_parent(me))
           + device_nr_size_cells(me))
           + device_nr_size_cells(me))
          ) * nr_ranges;
          ) * nr_ranges;
}
}
 
 
INLINE_DEVICE\
INLINE_DEVICE\
(void)
(void)
device_add_range_array_property(device *me,
device_add_range_array_property(device *me,
                                const char *property,
                                const char *property,
                                const range_property_spec *ranges,
                                const range_property_spec *ranges,
                                unsigned nr_ranges)
                                unsigned nr_ranges)
{
{
  unsigned sizeof_cells = (nr_range_property_cells(me, nr_ranges)
  unsigned sizeof_cells = (nr_range_property_cells(me, nr_ranges)
                           * sizeof(unsigned_cell));
                           * sizeof(unsigned_cell));
  unsigned_cell *cells = zalloc(sizeof_cells);
  unsigned_cell *cells = zalloc(sizeof_cells);
  unsigned_cell *cell;
  unsigned_cell *cell;
  int i;
  int i;
 
 
  /* copy the property elements over */
  /* copy the property elements over */
  cell = cells;
  cell = cells;
  for (i = 0; i < nr_ranges; i++) {
  for (i = 0; i < nr_ranges; i++) {
    const range_property_spec *range = &ranges[i];
    const range_property_spec *range = &ranges[i];
    /* copy the child address */
    /* copy the child address */
    cell = unit_address_to_cells(&range->child_address, cell,
    cell = unit_address_to_cells(&range->child_address, cell,
                                 device_nr_address_cells(me));
                                 device_nr_address_cells(me));
    /* copy the parent address */
    /* copy the parent address */
    cell = unit_address_to_cells(&range->parent_address, cell,
    cell = unit_address_to_cells(&range->parent_address, cell,
                                 device_nr_address_cells(device_parent(me)));
                                 device_nr_address_cells(device_parent(me)));
    /* copy the size */
    /* copy the size */
    cell = unit_address_to_cells(&range->size, cell,
    cell = unit_address_to_cells(&range->size, cell,
                                 device_nr_size_cells(me));
                                 device_nr_size_cells(me));
  }
  }
  ASSERT(cell == &cells[nr_range_property_cells(me, nr_ranges)]);
  ASSERT(cell == &cells[nr_range_property_cells(me, nr_ranges)]);
 
 
  /* add it */
  /* add it */
  device_add_property(me, property, range_array_property,
  device_add_property(me, property, range_array_property,
                      cells, sizeof_cells,
                      cells, sizeof_cells,
                      cells, sizeof_cells,
                      cells, sizeof_cells,
                      NULL, permenant_object);
                      NULL, permenant_object);
 
 
  zfree(cells);
  zfree(cells);
}
}
 
 
INLINE_DEVICE\
INLINE_DEVICE\
(int)
(int)
device_find_range_array_property(device *me,
device_find_range_array_property(device *me,
                                 const char *property,
                                 const char *property,
                                 unsigned index,
                                 unsigned index,
                                 range_property_spec *range)
                                 range_property_spec *range)
{
{
  const device_property *node;
  const device_property *node;
  unsigned sizeof_entry = (nr_range_property_cells(me, 1)
  unsigned sizeof_entry = (nr_range_property_cells(me, 1)
                           * sizeof(unsigned_cell));
                           * sizeof(unsigned_cell));
  const unsigned_cell *cells;
  const unsigned_cell *cells;
 
 
  /* locate the property */
  /* locate the property */
  node = device_find_property(me, property);
  node = device_find_property(me, property);
  if (node == (device_property*)0
  if (node == (device_property*)0
      || node->type != range_array_property)
      || node->type != range_array_property)
    device_error(me, "property %s not found or of wrong type", property);
    device_error(me, "property %s not found or of wrong type", property);
 
 
  /* aligned ? */
  /* aligned ? */
  if ((node->sizeof_array % sizeof_entry) != 0)
  if ((node->sizeof_array % sizeof_entry) != 0)
    device_error(me, "property %s contains an incomplete number of entries",
    device_error(me, "property %s contains an incomplete number of entries",
                 property);
                 property);
 
 
  /* within bounds? */
  /* within bounds? */
  if (node->sizeof_array < sizeof_entry * (index + 1))
  if (node->sizeof_array < sizeof_entry * (index + 1))
    return 0;
    return 0;
 
 
  /* find the range of interest */
  /* find the range of interest */
  cells = (unsigned_cell*)((char*)node->array + sizeof_entry * index);
  cells = (unsigned_cell*)((char*)node->array + sizeof_entry * index);
 
 
  /* copy the child address out - converting as we go */
  /* copy the child address out - converting as we go */
  cells = cells_to_unit_address(cells, &range->child_address,
  cells = cells_to_unit_address(cells, &range->child_address,
                                device_nr_address_cells(me));
                                device_nr_address_cells(me));
 
 
  /* copy the parent address out - converting as we go */
  /* copy the parent address out - converting as we go */
  cells = cells_to_unit_address(cells, &range->parent_address,
  cells = cells_to_unit_address(cells, &range->parent_address,
                                device_nr_address_cells(device_parent(me)));
                                device_nr_address_cells(device_parent(me)));
 
 
  /* copy the size - converting as we go */
  /* copy the size - converting as we go */
  cells = cells_to_unit_address(cells, &range->size,
  cells = cells_to_unit_address(cells, &range->size,
                                device_nr_size_cells(me));
                                device_nr_size_cells(me));
 
 
  return node->sizeof_array / sizeof_entry;
  return node->sizeof_array / sizeof_entry;
}
}
 
 
 
 
STATIC_INLINE_DEVICE\
STATIC_INLINE_DEVICE\
(unsigned)
(unsigned)
nr_reg_property_cells(device *me,
nr_reg_property_cells(device *me,
                      int nr_regs)
                      int nr_regs)
{
{
  return (device_nr_address_cells(device_parent(me))
  return (device_nr_address_cells(device_parent(me))
          + device_nr_size_cells(device_parent(me))
          + device_nr_size_cells(device_parent(me))
          ) * nr_regs;
          ) * nr_regs;
}
}
 
 
INLINE_DEVICE\
INLINE_DEVICE\
(void)
(void)
device_add_reg_array_property(device *me,
device_add_reg_array_property(device *me,
                              const char *property,
                              const char *property,
                              const reg_property_spec *regs,
                              const reg_property_spec *regs,
                              unsigned nr_regs)
                              unsigned nr_regs)
{
{
  unsigned sizeof_cells = (nr_reg_property_cells(me, nr_regs)
  unsigned sizeof_cells = (nr_reg_property_cells(me, nr_regs)
                           * sizeof(unsigned_cell));
                           * sizeof(unsigned_cell));
  unsigned_cell *cells = zalloc(sizeof_cells);
  unsigned_cell *cells = zalloc(sizeof_cells);
  unsigned_cell *cell;
  unsigned_cell *cell;
  int i;
  int i;
 
 
  /* copy the property elements over */
  /* copy the property elements over */
  cell = cells;
  cell = cells;
  for (i = 0; i < nr_regs; i++) {
  for (i = 0; i < nr_regs; i++) {
    const reg_property_spec *reg = &regs[i];
    const reg_property_spec *reg = &regs[i];
    /* copy the address */
    /* copy the address */
    cell = unit_address_to_cells(&reg->address, cell,
    cell = unit_address_to_cells(&reg->address, cell,
                                 device_nr_address_cells(device_parent(me)));
                                 device_nr_address_cells(device_parent(me)));
    /* copy the size */
    /* copy the size */
    cell = unit_address_to_cells(&reg->size, cell,
    cell = unit_address_to_cells(&reg->size, cell,
                                 device_nr_size_cells(device_parent(me)));
                                 device_nr_size_cells(device_parent(me)));
  }
  }
  ASSERT(cell == &cells[nr_reg_property_cells(me, nr_regs)]);
  ASSERT(cell == &cells[nr_reg_property_cells(me, nr_regs)]);
 
 
  /* add it */
  /* add it */
  device_add_property(me, property, reg_array_property,
  device_add_property(me, property, reg_array_property,
                      cells, sizeof_cells,
                      cells, sizeof_cells,
                      cells, sizeof_cells,
                      cells, sizeof_cells,
                      NULL, permenant_object);
                      NULL, permenant_object);
 
 
  zfree(cells);
  zfree(cells);
}
}
 
 
INLINE_DEVICE\
INLINE_DEVICE\
(int)
(int)
device_find_reg_array_property(device *me,
device_find_reg_array_property(device *me,
                               const char *property,
                               const char *property,
                               unsigned index,
                               unsigned index,
                               reg_property_spec *reg)
                               reg_property_spec *reg)
{
{
  const device_property *node;
  const device_property *node;
  unsigned sizeof_entry = (nr_reg_property_cells(me, 1)
  unsigned sizeof_entry = (nr_reg_property_cells(me, 1)
                           * sizeof(unsigned_cell));
                           * sizeof(unsigned_cell));
  const unsigned_cell *cells;
  const unsigned_cell *cells;
 
 
  /* locate the property */
  /* locate the property */
  node = device_find_property(me, property);
  node = device_find_property(me, property);
  if (node == (device_property*)0
  if (node == (device_property*)0
      || node->type != reg_array_property)
      || node->type != reg_array_property)
    device_error(me, "property %s not found or of wrong type", property);
    device_error(me, "property %s not found or of wrong type", property);
 
 
  /* aligned ? */
  /* aligned ? */
  if ((node->sizeof_array % sizeof_entry) != 0)
  if ((node->sizeof_array % sizeof_entry) != 0)
    device_error(me, "property %s contains an incomplete number of entries",
    device_error(me, "property %s contains an incomplete number of entries",
                 property);
                 property);
 
 
  /* within bounds? */
  /* within bounds? */
  if (node->sizeof_array < sizeof_entry * (index + 1))
  if (node->sizeof_array < sizeof_entry * (index + 1))
    return 0;
    return 0;
 
 
  /* find the range of interest */
  /* find the range of interest */
  cells = (unsigned_cell*)((char*)node->array + sizeof_entry * index);
  cells = (unsigned_cell*)((char*)node->array + sizeof_entry * index);
 
 
  /* copy the address out - converting as we go */
  /* copy the address out - converting as we go */
  cells = cells_to_unit_address(cells, &reg->address,
  cells = cells_to_unit_address(cells, &reg->address,
                                device_nr_address_cells(device_parent(me)));
                                device_nr_address_cells(device_parent(me)));
 
 
  /* copy the size out - converting as we go */
  /* copy the size out - converting as we go */
  cells = cells_to_unit_address(cells, &reg->size,
  cells = cells_to_unit_address(cells, &reg->size,
                                device_nr_size_cells(device_parent(me)));
                                device_nr_size_cells(device_parent(me)));
 
 
  return node->sizeof_array / sizeof_entry;
  return node->sizeof_array / sizeof_entry;
}
}
 
 
 
 
INLINE_DEVICE\
INLINE_DEVICE\
(void)
(void)
device_add_string_property(device *me,
device_add_string_property(device *me,
                           const char *property,
                           const char *property,
                           const char *string)
                           const char *string)
{
{
  device_add_property(me, property, string_property,
  device_add_property(me, property, string_property,
                      string, strlen(string) + 1,
                      string, strlen(string) + 1,
                      string, strlen(string) + 1,
                      string, strlen(string) + 1,
                      NULL, permenant_object);
                      NULL, permenant_object);
}
}
 
 
INLINE_DEVICE\
INLINE_DEVICE\
(const char *)
(const char *)
device_find_string_property(device *me,
device_find_string_property(device *me,
                            const char *property)
                            const char *property)
{
{
  const device_property *node;
  const device_property *node;
  const char *string;
  const char *string;
  node = device_find_property(me, property);
  node = device_find_property(me, property);
  if (node == (device_property*)0
  if (node == (device_property*)0
      || node->type != string_property)
      || node->type != string_property)
    device_error(me, "property %s not found or of wrong type", property);
    device_error(me, "property %s not found or of wrong type", property);
  string = node->array;
  string = node->array;
  ASSERT(strlen(string) + 1 == node->sizeof_array);
  ASSERT(strlen(string) + 1 == node->sizeof_array);
  return string;
  return string;
}
}
 
 
INLINE_DEVICE\
INLINE_DEVICE\
(void)
(void)
device_add_string_array_property(device *me,
device_add_string_array_property(device *me,
                                 const char *property,
                                 const char *property,
                                 const string_property_spec *strings,
                                 const string_property_spec *strings,
                                 unsigned nr_strings)
                                 unsigned nr_strings)
{
{
  int sizeof_array;
  int sizeof_array;
  int string_nr;
  int string_nr;
  char *array;
  char *array;
  char *chp;
  char *chp;
  if (nr_strings == 0)
  if (nr_strings == 0)
    device_error(me, "property %s must be non-null", property);
    device_error(me, "property %s must be non-null", property);
  /* total up the size of the needed array */
  /* total up the size of the needed array */
  for (sizeof_array = 0, string_nr = 0;
  for (sizeof_array = 0, string_nr = 0;
       string_nr < nr_strings;
       string_nr < nr_strings;
       string_nr ++) {
       string_nr ++) {
    sizeof_array += strlen(strings[string_nr]) + 1;
    sizeof_array += strlen(strings[string_nr]) + 1;
  }
  }
  /* create the array */
  /* create the array */
  array = (char*)zalloc(sizeof_array);
  array = (char*)zalloc(sizeof_array);
  chp = array;
  chp = array;
  for (string_nr = 0;
  for (string_nr = 0;
       string_nr < nr_strings;
       string_nr < nr_strings;
       string_nr++) {
       string_nr++) {
    strcpy(chp, strings[string_nr]);
    strcpy(chp, strings[string_nr]);
    chp += strlen(chp) + 1;
    chp += strlen(chp) + 1;
  }
  }
  ASSERT(chp == array + sizeof_array);
  ASSERT(chp == array + sizeof_array);
  /* now enter it */
  /* now enter it */
  device_add_property(me, property, string_array_property,
  device_add_property(me, property, string_array_property,
                      array, sizeof_array,
                      array, sizeof_array,
                      array, sizeof_array,
                      array, sizeof_array,
                      NULL, permenant_object);
                      NULL, permenant_object);
}
}
 
 
INLINE_DEVICE\
INLINE_DEVICE\
(int)
(int)
device_find_string_array_property(device *me,
device_find_string_array_property(device *me,
                                  const char *property,
                                  const char *property,
                                  unsigned index,
                                  unsigned index,
                                  string_property_spec *string)
                                  string_property_spec *string)
{
{
  const device_property *node;
  const device_property *node;
  node = device_find_property(me, property);
  node = device_find_property(me, property);
  if (node == (device_property*)0)
  if (node == (device_property*)0)
    device_error(me, "property %s not found", property);
    device_error(me, "property %s not found", property);
  switch (node->type) {
  switch (node->type) {
  default:
  default:
    device_error(me, "property %s of wrong type", property);
    device_error(me, "property %s of wrong type", property);
    break;
    break;
  case string_property:
  case string_property:
    if (index == 0) {
    if (index == 0) {
      *string = node->array;
      *string = node->array;
      ASSERT(strlen(*string) + 1 == node->sizeof_array);
      ASSERT(strlen(*string) + 1 == node->sizeof_array);
      return 1;
      return 1;
    }
    }
    break;
    break;
  case array_property:
  case array_property:
    if (node->sizeof_array == 0
    if (node->sizeof_array == 0
        || ((char*)node->array)[node->sizeof_array - 1] != '\0')
        || ((char*)node->array)[node->sizeof_array - 1] != '\0')
      device_error(me, "property %s invalid for string array", property);
      device_error(me, "property %s invalid for string array", property);
    /* FALL THROUGH */
    /* FALL THROUGH */
  case string_array_property:
  case string_array_property:
    ASSERT(node->sizeof_array > 0);
    ASSERT(node->sizeof_array > 0);
    ASSERT(((char*)node->array)[node->sizeof_array - 1] == '\0');
    ASSERT(((char*)node->array)[node->sizeof_array - 1] == '\0');
    {
    {
      const char *chp = node->array;
      const char *chp = node->array;
      int nr_entries = 0;
      int nr_entries = 0;
      /* count the number of strings, keeping an eye out for the one
      /* count the number of strings, keeping an eye out for the one
         we're looking for */
         we're looking for */
      *string = chp;
      *string = chp;
      do {
      do {
        if (*chp == '\0') {
        if (*chp == '\0') {
          /* next string */
          /* next string */
          nr_entries++;
          nr_entries++;
          chp++;
          chp++;
          if (nr_entries == index)
          if (nr_entries == index)
            *string = chp;
            *string = chp;
        }
        }
        else {
        else {
          chp++;
          chp++;
        }
        }
      } while (chp < (char*)node->array + node->sizeof_array);
      } while (chp < (char*)node->array + node->sizeof_array);
      if (index < nr_entries)
      if (index < nr_entries)
        return nr_entries;
        return nr_entries;
      else {
      else {
        *string = NULL;
        *string = NULL;
        return 0;
        return 0;
      }
      }
    }
    }
    break;
    break;
  }
  }
  return 0;
  return 0;
}
}
 
 
INLINE_DEVICE\
INLINE_DEVICE\
(void)
(void)
device_add_duplicate_property(device *me,
device_add_duplicate_property(device *me,
                              const char *property,
                              const char *property,
                              const device_property *original)
                              const device_property *original)
{
{
  device_property_entry *master;
  device_property_entry *master;
  TRACE(trace_devices,
  TRACE(trace_devices,
        ("device_add_duplicate_property(me=0x%lx, property=%s, ...)\n",
        ("device_add_duplicate_property(me=0x%lx, property=%s, ...)\n",
         (long)me, property));
         (long)me, property));
  if (original->disposition != permenant_object)
  if (original->disposition != permenant_object)
    device_error(me, "Can only duplicate permenant objects");
    device_error(me, "Can only duplicate permenant objects");
  /* find the original's master */
  /* find the original's master */
  master = original->owner->properties;
  master = original->owner->properties;
  while (master->value != original) {
  while (master->value != original) {
    master = master->next;
    master = master->next;
    ASSERT(master != NULL);
    ASSERT(master != NULL);
  }
  }
  /* now duplicate it */
  /* now duplicate it */
  device_add_property(me, property,
  device_add_property(me, property,
                      original->type,
                      original->type,
                      master->init_array, master->sizeof_init_array,
                      master->init_array, master->sizeof_init_array,
                      original->array, original->sizeof_array,
                      original->array, original->sizeof_array,
                      original, permenant_object);
                      original, permenant_object);
}
}
 
 
 
 


/* Device Hardware: */
/* Device Hardware: */
 
 
INLINE_DEVICE\
INLINE_DEVICE\
(unsigned)
(unsigned)
device_io_read_buffer(device *me,
device_io_read_buffer(device *me,
                      void *dest,
                      void *dest,
                      int space,
                      int space,
                      unsigned_word addr,
                      unsigned_word addr,
                      unsigned nr_bytes,
                      unsigned nr_bytes,
                      cpu *processor,
                      cpu *processor,
                      unsigned_word cia)
                      unsigned_word cia)
{
{
  if (me->callback->io.read_buffer == NULL)
  if (me->callback->io.read_buffer == NULL)
    device_error(me, "no io.read_buffer method");
    device_error(me, "no io.read_buffer method");
  return me->callback->io.read_buffer(me, dest, space,
  return me->callback->io.read_buffer(me, dest, space,
                                      addr, nr_bytes,
                                      addr, nr_bytes,
                                      processor, cia);
                                      processor, cia);
}
}
 
 
INLINE_DEVICE\
INLINE_DEVICE\
(unsigned)
(unsigned)
device_io_write_buffer(device *me,
device_io_write_buffer(device *me,
                       const void *source,
                       const void *source,
                       int space,
                       int space,
                       unsigned_word addr,
                       unsigned_word addr,
                       unsigned nr_bytes,
                       unsigned nr_bytes,
                       cpu *processor,
                       cpu *processor,
                       unsigned_word cia)
                       unsigned_word cia)
{
{
  if (me->callback->io.write_buffer == NULL)
  if (me->callback->io.write_buffer == NULL)
    device_error(me, "no io.write_buffer method");
    device_error(me, "no io.write_buffer method");
  return me->callback->io.write_buffer(me, source, space,
  return me->callback->io.write_buffer(me, source, space,
                                       addr, nr_bytes,
                                       addr, nr_bytes,
                                       processor, cia);
                                       processor, cia);
}
}
 
 
INLINE_DEVICE\
INLINE_DEVICE\
(unsigned)
(unsigned)
device_dma_read_buffer(device *me,
device_dma_read_buffer(device *me,
                       void *dest,
                       void *dest,
                       int space,
                       int space,
                       unsigned_word addr,
                       unsigned_word addr,
                       unsigned nr_bytes)
                       unsigned nr_bytes)
{
{
  if (me->callback->dma.read_buffer == NULL)
  if (me->callback->dma.read_buffer == NULL)
    device_error(me, "no dma.read_buffer method");
    device_error(me, "no dma.read_buffer method");
  return me->callback->dma.read_buffer(me, dest, space,
  return me->callback->dma.read_buffer(me, dest, space,
                                       addr, nr_bytes);
                                       addr, nr_bytes);
}
}
 
 
INLINE_DEVICE\
INLINE_DEVICE\
(unsigned)
(unsigned)
device_dma_write_buffer(device *me,
device_dma_write_buffer(device *me,
                        const void *source,
                        const void *source,
                        int space,
                        int space,
                        unsigned_word addr,
                        unsigned_word addr,
                        unsigned nr_bytes,
                        unsigned nr_bytes,
                        int violate_read_only_section)
                        int violate_read_only_section)
{
{
  if (me->callback->dma.write_buffer == NULL)
  if (me->callback->dma.write_buffer == NULL)
    device_error(me, "no dma.write_buffer method");
    device_error(me, "no dma.write_buffer method");
  return me->callback->dma.write_buffer(me, source, space,
  return me->callback->dma.write_buffer(me, source, space,
                                        addr, nr_bytes,
                                        addr, nr_bytes,
                                        violate_read_only_section);
                                        violate_read_only_section);
}
}
 
 
INLINE_DEVICE\
INLINE_DEVICE\
(void)
(void)
device_attach_address(device *me,
device_attach_address(device *me,
                      attach_type attach,
                      attach_type attach,
                      int space,
                      int space,
                      unsigned_word addr,
                      unsigned_word addr,
                      unsigned nr_bytes,
                      unsigned nr_bytes,
                      access_type access,
                      access_type access,
                      device *client) /*callback/default*/
                      device *client) /*callback/default*/
{
{
  if (me->callback->address.attach == NULL)
  if (me->callback->address.attach == NULL)
    device_error(me, "no address.attach method");
    device_error(me, "no address.attach method");
  me->callback->address.attach(me, attach, space,
  me->callback->address.attach(me, attach, space,
                               addr, nr_bytes, access, client);
                               addr, nr_bytes, access, client);
}
}
 
 
INLINE_DEVICE\
INLINE_DEVICE\
(void)
(void)
device_detach_address(device *me,
device_detach_address(device *me,
                      attach_type attach,
                      attach_type attach,
                      int space,
                      int space,
                      unsigned_word addr,
                      unsigned_word addr,
                      unsigned nr_bytes,
                      unsigned nr_bytes,
                      access_type access,
                      access_type access,
                      device *client) /*callback/default*/
                      device *client) /*callback/default*/
{
{
  if (me->callback->address.detach == NULL)
  if (me->callback->address.detach == NULL)
    device_error(me, "no address.detach method");
    device_error(me, "no address.detach method");
  me->callback->address.detach(me, attach, space,
  me->callback->address.detach(me, attach, space,
                               addr, nr_bytes, access, client);
                               addr, nr_bytes, access, client);
}
}
 
 
 
 


/* Interrupts: */
/* Interrupts: */
 
 
INLINE_DEVICE(void)
INLINE_DEVICE(void)
device_interrupt_event(device *me,
device_interrupt_event(device *me,
                       int my_port,
                       int my_port,
                       int level,
                       int level,
                       cpu *processor,
                       cpu *processor,
                       unsigned_word cia)
                       unsigned_word cia)
{
{
  int found_an_edge = 0;
  int found_an_edge = 0;
  device_interrupt_edge *edge;
  device_interrupt_edge *edge;
  /* device's interrupt lines directly connected */
  /* device's interrupt lines directly connected */
  for (edge = me->interrupt_destinations;
  for (edge = me->interrupt_destinations;
       edge != NULL;
       edge != NULL;
       edge = edge->next) {
       edge = edge->next) {
    if (edge->my_port == my_port) {
    if (edge->my_port == my_port) {
      if (edge->dest->callback->interrupt.event == NULL)
      if (edge->dest->callback->interrupt.event == NULL)
        device_error(me, "no interrupt method");
        device_error(me, "no interrupt method");
      edge->dest->callback->interrupt.event(edge->dest,
      edge->dest->callback->interrupt.event(edge->dest,
                                            edge->dest_port,
                                            edge->dest_port,
                                            me,
                                            me,
                                            my_port,
                                            my_port,
                                            level,
                                            level,
                                            processor, cia);
                                            processor, cia);
      found_an_edge = 1;
      found_an_edge = 1;
    }
    }
  }
  }
  if (!found_an_edge) {
  if (!found_an_edge) {
    device_error(me, "No interrupt edge for port %d", my_port);
    device_error(me, "No interrupt edge for port %d", my_port);
  }
  }
}
}
 
 
INLINE_DEVICE\
INLINE_DEVICE\
(void)
(void)
device_interrupt_attach(device *me,
device_interrupt_attach(device *me,
                        int my_port,
                        int my_port,
                        device *dest,
                        device *dest,
                        int dest_port,
                        int dest_port,
                        object_disposition disposition)
                        object_disposition disposition)
{
{
  attach_device_interrupt_edge(&me->interrupt_destinations,
  attach_device_interrupt_edge(&me->interrupt_destinations,
                               my_port,
                               my_port,
                               dest,
                               dest,
                               dest_port,
                               dest_port,
                               disposition);
                               disposition);
}
}
 
 
INLINE_DEVICE\
INLINE_DEVICE\
(void)
(void)
device_interrupt_detach(device *me,
device_interrupt_detach(device *me,
                        int my_port,
                        int my_port,
                        device *dest,
                        device *dest,
                        int dest_port)
                        int dest_port)
{
{
  detach_device_interrupt_edge(me,
  detach_device_interrupt_edge(me,
                               &me->interrupt_destinations,
                               &me->interrupt_destinations,
                               my_port,
                               my_port,
                               dest,
                               dest,
                               dest_port);
                               dest_port);
}
}
 
 
INLINE_DEVICE\
INLINE_DEVICE\
(void)
(void)
device_interrupt_traverse(device *me,
device_interrupt_traverse(device *me,
                          device_interrupt_traverse_function *handler,
                          device_interrupt_traverse_function *handler,
                          void *data)
                          void *data)
{
{
  device_interrupt_edge *interrupt_edge;
  device_interrupt_edge *interrupt_edge;
  for (interrupt_edge = me->interrupt_destinations;
  for (interrupt_edge = me->interrupt_destinations;
       interrupt_edge != NULL;
       interrupt_edge != NULL;
       interrupt_edge = interrupt_edge->next) {
       interrupt_edge = interrupt_edge->next) {
    handler(me, interrupt_edge->my_port,
    handler(me, interrupt_edge->my_port,
            interrupt_edge->dest, interrupt_edge->dest_port,
            interrupt_edge->dest, interrupt_edge->dest_port,
            data);
            data);
  }
  }
}
}
 
 
INLINE_DEVICE\
INLINE_DEVICE\
(int)
(int)
device_interrupt_decode(device *me,
device_interrupt_decode(device *me,
                        const char *port_name,
                        const char *port_name,
                        port_direction direction)
                        port_direction direction)
{
{
  if (port_name == NULL || port_name[0] == '\0')
  if (port_name == NULL || port_name[0] == '\0')
    return 0;
    return 0;
  if (isdigit(port_name[0])) {
  if (isdigit(port_name[0])) {
    return strtoul(port_name, NULL, 0);
    return strtoul(port_name, NULL, 0);
  }
  }
  else {
  else {
    const device_interrupt_port_descriptor *ports =
    const device_interrupt_port_descriptor *ports =
      me->callback->interrupt.ports;
      me->callback->interrupt.ports;
    if (ports != NULL) {
    if (ports != NULL) {
      while (ports->name != NULL) {
      while (ports->name != NULL) {
        if (ports->direction == bidirect_port
        if (ports->direction == bidirect_port
            || ports->direction == direction) {
            || ports->direction == direction) {
          if (ports->nr_ports > 0) {
          if (ports->nr_ports > 0) {
            int len = strlen(ports->name);
            int len = strlen(ports->name);
            if (strncmp(port_name, ports->name, len) == 0) {
            if (strncmp(port_name, ports->name, len) == 0) {
              if (port_name[len] == '\0')
              if (port_name[len] == '\0')
                return ports->number;
                return ports->number;
              else if(isdigit(port_name[len])) {
              else if(isdigit(port_name[len])) {
                int port = ports->number + strtoul(&port_name[len], NULL, 0);
                int port = ports->number + strtoul(&port_name[len], NULL, 0);
                if (port >= ports->number + ports->nr_ports)
                if (port >= ports->number + ports->nr_ports)
                  device_error(me, "Interrupt port %s out of range",
                  device_error(me, "Interrupt port %s out of range",
                               port_name);
                               port_name);
                return port;
                return port;
              }
              }
            }
            }
          }
          }
          else if (strcmp(port_name, ports->name) == 0)
          else if (strcmp(port_name, ports->name) == 0)
            return ports->number;
            return ports->number;
        }
        }
        ports++;
        ports++;
      }
      }
    }
    }
  }
  }
  device_error(me, "Unreconized interrupt port %s", port_name);
  device_error(me, "Unreconized interrupt port %s", port_name);
  return 0;
  return 0;
}
}
 
 
INLINE_DEVICE\
INLINE_DEVICE\
(int)
(int)
device_interrupt_encode(device *me,
device_interrupt_encode(device *me,
                        int port_number,
                        int port_number,
                        char *buf,
                        char *buf,
                        int sizeof_buf,
                        int sizeof_buf,
                        port_direction direction)
                        port_direction direction)
{
{
  const device_interrupt_port_descriptor *ports = NULL;
  const device_interrupt_port_descriptor *ports = NULL;
  ports = me->callback->interrupt.ports;
  ports = me->callback->interrupt.ports;
  if (ports != NULL) {
  if (ports != NULL) {
    while (ports->name != NULL) {
    while (ports->name != NULL) {
      if (ports->direction == bidirect_port
      if (ports->direction == bidirect_port
          || ports->direction == direction) {
          || ports->direction == direction) {
        if (ports->nr_ports > 0) {
        if (ports->nr_ports > 0) {
          if (port_number >= ports->number
          if (port_number >= ports->number
              && port_number < ports->number + ports->nr_ports) {
              && port_number < ports->number + ports->nr_ports) {
            strcpy(buf, ports->name);
            strcpy(buf, ports->name);
            sprintf(buf + strlen(buf), "%d", port_number - ports->number);
            sprintf(buf + strlen(buf), "%d", port_number - ports->number);
            if (strlen(buf) >= sizeof_buf)
            if (strlen(buf) >= sizeof_buf)
              error("device_interrupt_encode: buffer overflow");
              error("device_interrupt_encode: buffer overflow");
            return strlen(buf);
            return strlen(buf);
          }
          }
        }
        }
        else {
        else {
          if (ports->number == port_number) {
          if (ports->number == port_number) {
            if (strlen(ports->name) >= sizeof_buf)
            if (strlen(ports->name) >= sizeof_buf)
              error("device_interrupt_encode: buffer overflow");
              error("device_interrupt_encode: buffer overflow");
            strcpy(buf, ports->name);
            strcpy(buf, ports->name);
            return strlen(buf);
            return strlen(buf);
          }
          }
        }
        }
      }
      }
      ports++;
      ports++;
    }
    }
  }
  }
  sprintf(buf, "%d", port_number);
  sprintf(buf, "%d", port_number);
  if (strlen(buf) >= sizeof_buf)
  if (strlen(buf) >= sizeof_buf)
    error("device_interrupt_encode: buffer overflow");
    error("device_interrupt_encode: buffer overflow");
  return strlen(buf);
  return strlen(buf);
}
}
 
 
 
 


/* IOCTL: */
/* IOCTL: */
 
 
EXTERN_DEVICE\
EXTERN_DEVICE\
(int)
(int)
device_ioctl(device *me,
device_ioctl(device *me,
             cpu *processor,
             cpu *processor,
             unsigned_word cia,
             unsigned_word cia,
             device_ioctl_request request,
             device_ioctl_request request,
             ...)
             ...)
{
{
  int status;
  int status;
  va_list ap;
  va_list ap;
  va_start(ap, request);
  va_start(ap, request);
  if (me->callback->ioctl == NULL)
  if (me->callback->ioctl == NULL)
    device_error(me, "no ioctl method");
    device_error(me, "no ioctl method");
  status = me->callback->ioctl(me, processor, cia, request, ap);
  status = me->callback->ioctl(me, processor, cia, request, ap);
  va_end(ap);
  va_end(ap);
  return status;
  return status;
}
}
 
 
 
 


/* I/O */
/* I/O */
 
 
EXTERN_DEVICE\
EXTERN_DEVICE\
(void volatile)
(void volatile)
device_error(device *me,
device_error(device *me,
             const char *fmt,
             const char *fmt,
             ...)
             ...)
{
{
  char message[1024];
  char message[1024];
  va_list ap;
  va_list ap;
  /* format the message */
  /* format the message */
  va_start(ap, fmt);
  va_start(ap, fmt);
  vsprintf(message, fmt, ap);
  vsprintf(message, fmt, ap);
  va_end(ap);
  va_end(ap);
  /* sanity check */
  /* sanity check */
  if (strlen(message) >= sizeof(message))
  if (strlen(message) >= sizeof(message))
    error("device_error: buffer overflow");
    error("device_error: buffer overflow");
  if (me == NULL)
  if (me == NULL)
    error("device: %s", message);
    error("device: %s", message);
  else if (me->path != NULL && me->path[0] != '\0')
  else if (me->path != NULL && me->path[0] != '\0')
    error("%s: %s", me->path, message);
    error("%s: %s", me->path, message);
  else if (me->name != NULL && me->name[0] != '\0')
  else if (me->name != NULL && me->name[0] != '\0')
    error("%s: %s", me->name, message);
    error("%s: %s", me->name, message);
  else
  else
    error("device: %s", message);
    error("device: %s", message);
  while(1);
  while(1);
}
}
 
 
INLINE_DEVICE\
INLINE_DEVICE\
(int)
(int)
device_trace(device *me)
device_trace(device *me)
{
{
  return me->trace;
  return me->trace;
}
}
 
 


/* External representation */
/* External representation */
 
 
INLINE_DEVICE\
INLINE_DEVICE\
(device *)
(device *)
external_to_device(device *tree_member,
external_to_device(device *tree_member,
                   unsigned_cell phandle)
                   unsigned_cell phandle)
{
{
  device *me = cap_internal(tree_member->phandles, phandle);
  device *me = cap_internal(tree_member->phandles, phandle);
  return me;
  return me;
}
}
 
 
INLINE_DEVICE\
INLINE_DEVICE\
(unsigned_cell)
(unsigned_cell)
device_to_external(device *me)
device_to_external(device *me)
{
{
  unsigned_cell phandle = cap_external(me->phandles, me);
  unsigned_cell phandle = cap_external(me->phandles, me);
  return phandle;
  return phandle;
}
}
 
 
INLINE_DEVICE\
INLINE_DEVICE\
(device_instance *)
(device_instance *)
external_to_device_instance(device *tree_member,
external_to_device_instance(device *tree_member,
                            unsigned_cell ihandle)
                            unsigned_cell ihandle)
{
{
  device_instance *instance = cap_internal(tree_member->ihandles, ihandle);
  device_instance *instance = cap_internal(tree_member->ihandles, ihandle);
  return instance;
  return instance;
}
}
 
 
INLINE_DEVICE\
INLINE_DEVICE\
(unsigned_cell)
(unsigned_cell)
device_instance_to_external(device_instance *instance)
device_instance_to_external(device_instance *instance)
{
{
  unsigned_cell ihandle = cap_external(instance->owner->ihandles, instance);
  unsigned_cell ihandle = cap_external(instance->owner->ihandles, instance);
  return ihandle;
  return ihandle;
}
}
 
 
 
 
/* Map onto the event functions */
/* Map onto the event functions */
 
 
INLINE_DEVICE\
INLINE_DEVICE\
(event_entry_tag)
(event_entry_tag)
device_event_queue_schedule(device *me,
device_event_queue_schedule(device *me,
                            signed64 delta_time,
                            signed64 delta_time,
                            device_event_handler *handler,
                            device_event_handler *handler,
                            void *data)
                            void *data)
{
{
  return event_queue_schedule(psim_event_queue(me->system),
  return event_queue_schedule(psim_event_queue(me->system),
                              delta_time,
                              delta_time,
                              handler,
                              handler,
                              data);
                              data);
}
}
 
 
INLINE_DEVICE\
INLINE_DEVICE\
(void)
(void)
device_event_queue_deschedule(device *me,
device_event_queue_deschedule(device *me,
                              event_entry_tag event_to_remove)
                              event_entry_tag event_to_remove)
{
{
  event_queue_deschedule(psim_event_queue(me->system),
  event_queue_deschedule(psim_event_queue(me->system),
                         event_to_remove);
                         event_to_remove);
}
}
 
 
INLINE_DEVICE\
INLINE_DEVICE\
(signed64)
(signed64)
device_event_queue_time(device *me)
device_event_queue_time(device *me)
{
{
  return event_queue_time(psim_event_queue(me->system));
  return event_queue_time(psim_event_queue(me->system));
}
}
 
 
 
 
/* Initialization: */
/* Initialization: */
 
 
 
 
INLINE_DEVICE\
INLINE_DEVICE\
(void)
(void)
device_clean(device *me,
device_clean(device *me,
             void *data)
             void *data)
{
{
  psim *system;
  psim *system;
  system = (psim*)data;
  system = (psim*)data;
  TRACE(trace_device_init, ("device_clean - initializing %s", me->path));
  TRACE(trace_device_init, ("device_clean - initializing %s", me->path));
  clean_device_interrupt_edges(&me->interrupt_destinations);
  clean_device_interrupt_edges(&me->interrupt_destinations);
  clean_device_instances(me);
  clean_device_instances(me);
  clean_device_properties(me);
  clean_device_properties(me);
}
}
 
 
/* Device initialization: */
/* Device initialization: */
 
 
INLINE_DEVICE\
INLINE_DEVICE\
(void)
(void)
device_init_address(device *me,
device_init_address(device *me,
                    void *data)
                    void *data)
{
{
  psim *system = (psim*)data;
  psim *system = (psim*)data;
  int nr_address_cells;
  int nr_address_cells;
  int nr_size_cells;
  int nr_size_cells;
  TRACE(trace_device_init, ("device_init_address - initializing %s", me->path));
  TRACE(trace_device_init, ("device_init_address - initializing %s", me->path));
 
 
  /* ensure the cap database is valid */
  /* ensure the cap database is valid */
  if (me->parent == NULL) {
  if (me->parent == NULL) {
    cap_init(me->ihandles);
    cap_init(me->ihandles);
    cap_init(me->phandles);
    cap_init(me->phandles);
  }
  }
 
 
  /* some basics */
  /* some basics */
  me->system = system; /* misc things not known until now */
  me->system = system; /* misc things not known until now */
  me->trace = (device_find_property(me, "trace")
  me->trace = (device_find_property(me, "trace")
               ? device_find_integer_property(me, "trace")
               ? device_find_integer_property(me, "trace")
               : 0);
               : 0);
 
 
  /* Ensure that the first address found in the reg property matches
  /* Ensure that the first address found in the reg property matches
     anything that was specified as part of the devices name */
     anything that was specified as part of the devices name */
  if (device_find_property(me, "reg") != NULL) {
  if (device_find_property(me, "reg") != NULL) {
    reg_property_spec unit;
    reg_property_spec unit;
    device_find_reg_array_property(me, "reg", 0, &unit);
    device_find_reg_array_property(me, "reg", 0, &unit);
    if (memcmp(device_unit_address(me), &unit.address, sizeof(unit.address))
    if (memcmp(device_unit_address(me), &unit.address, sizeof(unit.address))
        != 0)
        != 0)
      device_error(me, "Unit address as specified by the reg property in conflict with the value previously specified in the devices path");
      device_error(me, "Unit address as specified by the reg property in conflict with the value previously specified in the devices path");
  }
  }
 
 
  /* ensure that the devices #address/size-cells is consistent */
  /* ensure that the devices #address/size-cells is consistent */
  nr_address_cells = device_nr_address_cells(me);
  nr_address_cells = device_nr_address_cells(me);
  if (device_find_property(me, "#address-cells") != NULL
  if (device_find_property(me, "#address-cells") != NULL
      && (nr_address_cells
      && (nr_address_cells
          != device_find_integer_property(me, "#address-cells")))
          != device_find_integer_property(me, "#address-cells")))
    device_error(me, "#address-cells property used before defined");
    device_error(me, "#address-cells property used before defined");
  nr_size_cells = device_nr_size_cells(me);
  nr_size_cells = device_nr_size_cells(me);
  if (device_find_property(me, "#size-cells") != NULL
  if (device_find_property(me, "#size-cells") != NULL
      && (nr_size_cells
      && (nr_size_cells
          != device_find_integer_property(me, "#size-cells")))
          != device_find_integer_property(me, "#size-cells")))
    device_error(me, "#size-cells property used before defined");
    device_error(me, "#size-cells property used before defined");
 
 
  /* now init it */
  /* now init it */
  if (me->callback->init.address != NULL)
  if (me->callback->init.address != NULL)
    me->callback->init.address(me);
    me->callback->init.address(me);
}
}
 
 
INLINE_DEVICE\
INLINE_DEVICE\
(void)
(void)
device_init_data(device *me,
device_init_data(device *me,
                    void *data)
                    void *data)
{
{
  TRACE(trace_device_init, ("device_init_data - initializing %s", me->path));
  TRACE(trace_device_init, ("device_init_data - initializing %s", me->path));
  if (me->callback->init.data != NULL)
  if (me->callback->init.data != NULL)
    me->callback->init.data(me);
    me->callback->init.data(me);
}
}
 
 
#endif /* _DEVICE_C_ */
#endif /* _DEVICE_C_ */
 
 

powered by: WebSVN 2.1.0

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