Home | History | Annotate | Line # | Download | only in ppc
device.c revision 1.2
      1 /*  This file is part of the program psim.
      2 
      3     Copyright (C) 1994-1997, Andrew Cagney <cagney (at) highland.com.au>
      4 
      5     This program is free software; you can redistribute it and/or modify
      6     it under the terms of the GNU General Public License as published by
      7     the Free Software Foundation; either version 3 of the License, or
      8     (at your option) any later version.
      9 
     10     This program is distributed in the hope that it will be useful,
     11     but WITHOUT ANY WARRANTY; without even the implied warranty of
     12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13     GNU General Public License for more details.
     14 
     15     You should have received a copy of the GNU General Public License
     16     along with this program; if not, see <http://www.gnu.org/licenses/>.
     17 
     18     */
     19 
     20 
     21 #ifndef _DEVICE_C_
     22 #define _DEVICE_C_
     23 
     24 #include <stdio.h>
     25 
     26 #include "device_table.h"
     27 #include "cap.h"
     28 
     29 #include "events.h"
     30 #include "psim.h"
     31 
     32 #ifdef HAVE_STDLIB_H
     33 #include <stdlib.h>
     34 #endif
     35 
     36 #ifdef HAVE_STRING_H
     37 #include <string.h>
     38 #else
     39 #ifdef HAVE_STRINGS_H
     40 #include <strings.h>
     41 #endif
     42 #endif
     43 
     44 #include <ctype.h>
     45 
     46 STATIC_INLINE_DEVICE (void) clean_device_properties(device *);
     47 
     48 /* property entries */
     49 
     50 typedef struct _device_property_entry device_property_entry;
     51 struct _device_property_entry {
     52   device_property_entry *next;
     53   device_property *value;
     54   const void *init_array;
     55   unsigned sizeof_init_array;
     56 };
     57 
     58 
     59 /* Interrupt edges */
     60 
     61 typedef struct _device_interrupt_edge device_interrupt_edge;
     62 struct _device_interrupt_edge {
     63   int my_port;
     64   device *dest;
     65   int dest_port;
     66   device_interrupt_edge *next;
     67   object_disposition disposition;
     68 };
     69 
     70 STATIC_INLINE_DEVICE\
     71 (void)
     72 attach_device_interrupt_edge(device_interrupt_edge **list,
     73 			     int my_port,
     74 			     device *dest,
     75 			     int dest_port,
     76 			     object_disposition disposition)
     77 {
     78   device_interrupt_edge *new_edge = ZALLOC(device_interrupt_edge);
     79   new_edge->my_port = my_port;
     80   new_edge->dest = dest;
     81   new_edge->dest_port = dest_port;
     82   new_edge->next = *list;
     83   new_edge->disposition = disposition;
     84   *list = new_edge;
     85 }
     86 
     87 STATIC_INLINE_DEVICE\
     88 (void)
     89 detach_device_interrupt_edge(device *me,
     90 			     device_interrupt_edge **list,
     91 			     int my_port,
     92 			     device *dest,
     93 			     int dest_port)
     94 {
     95   while (*list != NULL) {
     96     device_interrupt_edge *old_edge = *list;
     97     if (old_edge->dest == dest
     98 	&& old_edge->dest_port == dest_port
     99 	&& old_edge->my_port == my_port) {
    100       if (old_edge->disposition == permenant_object)
    101 	device_error(me, "attempt to delete permenant interrupt");
    102       *list = old_edge->next;
    103       free(old_edge);
    104       return;
    105     }
    106   }
    107   device_error(me, "attempt to delete unattached interrupt");
    108 }
    109 
    110 STATIC_INLINE_DEVICE\
    111 (void)
    112 clean_device_interrupt_edges(device_interrupt_edge **list)
    113 {
    114   while (*list != NULL) {
    115     device_interrupt_edge *old_edge = *list;
    116     switch (old_edge->disposition) {
    117     case permenant_object:
    118       list = &old_edge->next;
    119       break;
    120     case tempoary_object:
    121       *list = old_edge->next;
    122       free(old_edge);
    123       break;
    124     }
    125   }
    126 }
    127 
    128 
    129 /* A device */
    130 
    131 struct _device {
    132 
    133   /* my name is ... */
    134   const char *name;
    135   device_unit unit_address;
    136   const char *path;
    137   int nr_address_cells;
    138   int nr_size_cells;
    139 
    140   /* device tree */
    141   device *parent;
    142   device *children;
    143   device *sibling;
    144 
    145   /* its template methods */
    146   void *data; /* device specific data */
    147   const device_callbacks *callback;
    148 
    149   /* device properties */
    150   device_property_entry *properties;
    151 
    152   /* interrupts */
    153   device_interrupt_edge *interrupt_destinations;
    154 
    155   /* any open instances of this device */
    156   device_instance *instances;
    157 
    158   /* the internal/external mappings and other global requirements */
    159   cap *ihandles;
    160   cap *phandles;
    161   psim *system;
    162 
    163   /* debugging */
    164   int trace;
    165 };
    166 
    167 
    168 /* an instance of a device */
    169 struct _device_instance {
    170   void *data;
    171   char *args;
    172   char *path;
    173   const device_instance_callbacks *callback;
    174   /* the root instance */
    175   device *owner;
    176   device_instance *next;
    177   /* interposed instance */
    178   device_instance *parent;
    179   device_instance *child;
    180 };
    181 
    182 
    183 
    184 /* creation */
    186 
    187 STATIC_INLINE_DEVICE\
    188 (const char *)
    189 device_full_name(device *leaf,
    190                  char *buf,
    191                  unsigned sizeof_buf)
    192 {
    193   /* get a buffer */
    194   char full_name[1024];
    195   if (buf == (char*)0) {
    196     buf = full_name;
    197     sizeof_buf = sizeof(full_name);
    198   }
    199 
    200   /* construct a name */
    201   if (leaf->parent == NULL) {
    202     if (sizeof_buf < 1)
    203       error("device_full_name: buffer overflow");
    204     *buf = '\0';
    205   }
    206   else {
    207     char unit[1024];
    208     device_full_name(leaf->parent, buf, sizeof_buf);
    209     if (leaf->parent != NULL
    210         && device_encode_unit(leaf->parent,
    211                               &leaf->unit_address,
    212                               unit+1,
    213                               sizeof(unit)-1) > 0)
    214       unit[0] = '@';
    215     else
    216       unit[0] = '\0';
    217     if (strlen(buf) + strlen("/") + strlen(leaf->name) + strlen(unit)
    218         >= sizeof_buf)
    219       error("device_full_name: buffer overflow");
    220     strcat(buf, "/");
    221     strcat(buf, leaf->name);
    222     strcat (buf, unit);
    223   }
    224 
    225   /* return it usefully */
    226   if (buf == full_name)
    227     buf = (char *) strdup(full_name);
    228   return buf;
    229 }
    230 
    231 STATIC_INLINE_DEVICE\
    232 (device *)
    233 device_create_from(const char *name,
    234 		   const device_unit *unit_address,
    235 		   void *data,
    236 		   const device_callbacks *callbacks,
    237 		   device *parent)
    238 {
    239   device *new_device = ZALLOC(device);
    240 
    241   /* insert it into the device tree */
    242   new_device->parent = parent;
    243   new_device->children = NULL;
    244   if (parent != NULL) {
    245     device **sibling = &parent->children;
    246     while ((*sibling) != NULL)
    247       sibling = &(*sibling)->sibling;
    248     *sibling = new_device;
    249   }
    250 
    251   /* give it a name */
    252   new_device->name = (char *) strdup(name);
    253   new_device->unit_address = *unit_address;
    254   new_device->path = device_full_name(new_device, NULL, 0);
    255 
    256   /* its template */
    257   new_device->data = data;
    258   new_device->callback = callbacks;
    259 
    260   /* its properties - already null */
    261   /* interrupts - already null */
    262 
    263   /* mappings - if needed */
    264   if (parent == NULL) {
    265     new_device->ihandles = cap_create(name);
    266     new_device->phandles = cap_create(name);
    267   }
    268   else {
    269     new_device->ihandles = device_root(parent)->ihandles;
    270     new_device->phandles = device_root(parent)->phandles;
    271   }
    272 
    273   cap_add(new_device->phandles, new_device);
    274   return new_device;
    275 }
    276 
    277 
    278 
    279 INLINE_DEVICE\
    280 (device *)
    281 device_create(device *parent,
    282 	      const char *base,
    283 	      const char *name,
    284 	      const char *unit_address,
    285 	      const char *args)
    286 {
    287   const device_descriptor *const *table;
    288   for (table = device_table; *table != NULL; table++) {
    289     const device_descriptor *descr;
    290     for (descr = *table; descr->name != NULL; descr++) {
    291       if (strcmp(base, descr->name) == 0) {
    292 	device_unit address = { 0 };
    293 	void *data = NULL;
    294 	if (parent != NULL)
    295 	  if (device_decode_unit(parent, unit_address, &address) < 0)
    296 	    device_error(parent, "invalid address %s for device %s",
    297 			 unit_address, name);
    298 	if (descr->creator != NULL)
    299 	  data = descr->creator(name, &address, args);
    300 	return device_create_from(name, &address, data,
    301 				  descr->callbacks, parent);
    302       }
    303     }
    304   }
    305   device_error(parent, "attempt to attach unknown device %s", name);
    306   return NULL;
    307 }
    308 
    309 
    310 
    311 INLINE_DEVICE\
    312 (void)
    313 device_usage(int verbose)
    314 {
    315   const device_descriptor *const *table;
    316   if (verbose == 1) {
    317     int pos = 0;
    318     for (table = device_table; *table != NULL; table++) {
    319       const device_descriptor *descr;
    320       for (descr = *table; descr->name != NULL; descr++) {
    321 	pos += strlen(descr->name) + 2;
    322 	if (pos > 75) {
    323 	  pos = strlen(descr->name) + 2;
    324 	  printf_filtered("\n");
    325 	}
    326 	printf_filtered("  %s", descr->name);
    327       }
    328       printf_filtered("\n");
    329     }
    330   }
    331   if (verbose > 1) {
    332     for (table = device_table; *table != NULL; table++) {
    333       const device_descriptor *descr;
    334       for (descr = *table; descr->name != NULL; descr++) {
    335 	printf_filtered("  %s:\n", descr->name);
    336 	/* interrupt ports */
    337 	if (descr->callbacks->interrupt.ports != NULL) {
    338 	  const device_interrupt_port_descriptor *ports =
    339 	    descr->callbacks->interrupt.ports;
    340 	  printf_filtered("    interrupt ports:");
    341 	  while (ports->name != NULL) {
    342 	    printf_filtered(" %s", ports->name);
    343 	    ports++;
    344 	  }
    345 	  printf_filtered("\n");
    346 	}
    347 	/* general info */
    348 	if (descr->callbacks->usage != NULL)
    349 	  descr->callbacks->usage(verbose);
    350       }
    351     }
    352   }
    353 }
    354 
    355 
    356 
    357 
    358 
    359 /* Device node: */
    361 
    362 INLINE_DEVICE\
    363 (device *)
    364 device_parent(device *me)
    365 {
    366   return me->parent;
    367 }
    368 
    369 INLINE_DEVICE\
    370 (device *)
    371 device_root(device *me)
    372 {
    373   ASSERT(me != NULL);
    374   while (me->parent != NULL)
    375     me = me->parent;
    376   return me;
    377 }
    378 
    379 INLINE_DEVICE\
    380 (device *)
    381 device_sibling(device *me)
    382 {
    383   return me->sibling;
    384 }
    385 
    386 INLINE_DEVICE\
    387 (device *)
    388 device_child(device *me)
    389 {
    390   return me->children;
    391 }
    392 
    393 INLINE_DEVICE\
    394 (const char *)
    395 device_name(device *me)
    396 {
    397   return me->name;
    398 }
    399 
    400 INLINE_DEVICE\
    401 (const char *)
    402 device_path(device *me)
    403 {
    404   return me->path;
    405 }
    406 
    407 INLINE_DEVICE\
    408 (void *)
    409 device_data(device *me)
    410 {
    411   return me->data;
    412 }
    413 
    414 INLINE_DEVICE\
    415 (psim *)
    416 device_system(device *me)
    417 {
    418   return me->system;
    419 }
    420 
    421 INLINE_DEVICE\
    422 (const device_unit *)
    423 device_unit_address(device *me)
    424 {
    425   return &me->unit_address;
    426 }
    427 
    428 
    429 INLINE_DEVICE\
    430 (int)
    431 device_address_to_attach_address(device *me,
    432 				 const device_unit *address,
    433 				 int *attach_space,
    434 				 unsigned_word *attach_address,
    435 				 device *client)
    436 {
    437   if (me->callback->convert.address_to_attach_address == NULL)
    438     device_error(me, "no convert.address_to_attach_address method");
    439   return me->callback->convert.address_to_attach_address(me, address, attach_space, attach_address, client);
    440 }
    441 
    442 
    443 INLINE_DEVICE\
    444 (int)
    445 device_size_to_attach_size(device *me,
    446 			   const device_unit *size,
    447 			   unsigned *nr_bytes,
    448 			   device *client)
    449 {
    450   if (me->callback->convert.size_to_attach_size == NULL)
    451     device_error(me, "no convert.size_to_attach_size method");
    452   return me->callback->convert.size_to_attach_size(me, size, nr_bytes, client);
    453 }
    454 
    455 
    456 INLINE_DEVICE\
    457 (int)
    458 device_decode_unit(device *bus,
    459 		   const char *unit,
    460 		   device_unit *address)
    461 {
    462   if (bus->callback->convert.decode_unit == NULL)
    463     device_error(bus, "no convert.decode_unit method");
    464   return bus->callback->convert.decode_unit(bus, unit, address);
    465 }
    466 
    467 
    468 INLINE_DEVICE\
    469 (int)
    470 device_encode_unit(device *bus,
    471 		   const device_unit *unit_address,
    472 		   char *buf,
    473 		   int sizeof_buf)
    474 {
    475   if (bus->callback->convert.encode_unit == NULL)
    476     device_error(bus, "no convert.encode_unit method");
    477   return bus->callback->convert.encode_unit(bus, unit_address, buf, sizeof_buf);
    478 }
    479 
    480 INLINE_DEVICE\
    481 (unsigned)
    482 device_nr_address_cells(device *me)
    483 {
    484   if (me->nr_address_cells == 0) {
    485     if (device_find_property(me, "#address-cells") != NULL)
    486       me->nr_address_cells = device_find_integer_property(me, "#address-cells");
    487     else
    488       me->nr_address_cells = 2;
    489   }
    490   return me->nr_address_cells;
    491 }
    492 
    493 INLINE_DEVICE\
    494 (unsigned)
    495 device_nr_size_cells(device *me)
    496 {
    497   if (me->nr_size_cells == 0) {
    498     if (device_find_property(me, "#size-cells") != NULL)
    499       me->nr_size_cells = device_find_integer_property(me, "#size-cells");
    500     else
    501       me->nr_size_cells = 1;
    502   }
    503   return me->nr_size_cells;
    504 }
    505 
    506 
    507 
    508 /* device-instance: */
    510 
    511 INLINE_DEVICE\
    512 (device_instance *)
    513 device_create_instance_from(device *me,
    514 			    device_instance *parent,
    515 			    void *data,
    516 			    const char *path,
    517 			    const char *args,
    518 			    const device_instance_callbacks *callbacks)
    519 {
    520   device_instance *instance = ZALLOC(device_instance);
    521   if ((me == NULL) == (parent == NULL))
    522     device_error(me, "can't have both parent instance and parent device");
    523   /*instance->unit*/
    524   /* link this instance into the devices list */
    525   if (me != NULL) {
    526     ASSERT(parent == NULL);
    527     instance->owner = me;
    528     instance->parent = NULL;
    529     /* link this instance into the front of the devices instance list */
    530     instance->next = me->instances;
    531     me->instances = instance;
    532   }
    533   if (parent != NULL) {
    534     device_instance **previous;
    535     ASSERT(parent->child == NULL);
    536     parent->child = instance;
    537     ASSERT(me == NULL);
    538     instance->owner = parent->owner;
    539     instance->parent = parent;
    540     /* in the devices instance list replace the parent instance with
    541        this one */
    542     instance->next = parent->next;
    543     /* replace parent with this new node */
    544     previous = &instance->owner->instances;
    545     while (*previous != parent) {
    546       ASSERT(*previous != NULL);
    547       previous = &(*previous)->next;
    548     }
    549     *previous = instance;
    550   }
    551   instance->data = data;
    552   instance->args = (args == NULL ? NULL : (char *) strdup(args));
    553   instance->path = (path == NULL ? NULL : (char *) strdup(path));
    554   instance->callback = callbacks;
    555   cap_add(instance->owner->ihandles, instance);
    556   return instance;
    557 }
    558 
    559 
    560 INLINE_DEVICE\
    561 (device_instance *)
    562 device_create_instance(device *me,
    563 		       const char *path,
    564 		       const char *args)
    565 {
    566   /* create the instance */
    567   if (me->callback->instance_create == NULL)
    568     device_error(me, "no instance_create method");
    569   return me->callback->instance_create(me, path, args);
    570 }
    571 
    572 
    573 STATIC_INLINE_DEVICE\
    574 (void)
    575 clean_device_instances(device *me)
    576 {
    577   device_instance **instance = &me->instances;
    578   while (*instance != NULL) {
    579     device_instance *old_instance = *instance;
    580     device_instance_delete(old_instance);
    581     instance = &me->instances;
    582   }
    583 }
    584 
    585 
    586 INLINE_DEVICE\
    587 (void)
    588 device_instance_delete(device_instance *instance)
    589 {
    590   device *me = instance->owner;
    591   if (instance->callback->delete == NULL)
    592     device_error(me, "no delete method");
    593   instance->callback->delete(instance);
    594   if (instance->args != NULL)
    595     free(instance->args);
    596   if (instance->path != NULL)
    597     free(instance->path);
    598   if (instance->child == NULL) {
    599     /* only remove leaf nodes */
    600     device_instance **curr = &me->instances;
    601     while (*curr != instance) {
    602       ASSERT(*curr != NULL);
    603       curr = &(*curr)->next;
    604     }
    605     *curr = instance->next;
    606   }
    607   else {
    608     /* check it isn't in the instance list */
    609     device_instance *curr = me->instances;
    610     while (curr != NULL) {
    611       ASSERT(curr != instance);
    612       curr = curr->next;
    613     }
    614     /* unlink the child */
    615     ASSERT(instance->child->parent == instance);
    616     instance->child->parent = NULL;
    617   }
    618   cap_remove(me->ihandles, instance);
    619   free(instance);
    620 }
    621 
    622 INLINE_DEVICE\
    623 (int)
    624 device_instance_read(device_instance *instance,
    625 		     void *addr,
    626 		     unsigned_word len)
    627 {
    628   device *me = instance->owner;
    629   if (instance->callback->read == NULL)
    630     device_error(me, "no read method");
    631   return instance->callback->read(instance, addr, len);
    632 }
    633 
    634 INLINE_DEVICE\
    635 (int)
    636 device_instance_write(device_instance *instance,
    637 		      const void *addr,
    638 		      unsigned_word len)
    639 {
    640   device *me = instance->owner;
    641   if (instance->callback->write == NULL)
    642     device_error(me, "no write method");
    643   return instance->callback->write(instance, addr, len);
    644 }
    645 
    646 INLINE_DEVICE\
    647 (int)
    648 device_instance_seek(device_instance *instance,
    649 		     unsigned_word pos_hi,
    650 		     unsigned_word pos_lo)
    651 {
    652   device *me = instance->owner;
    653   if (instance->callback->seek == NULL)
    654     device_error(me, "no seek method");
    655   return instance->callback->seek(instance, pos_hi, pos_lo);
    656 }
    657 
    658 INLINE_DEVICE\
    659 (int)
    660 device_instance_call_method(device_instance *instance,
    661 			    const char *method_name,
    662 			    int n_stack_args,
    663 			    unsigned_cell stack_args[/*n_stack_args*/],
    664 			    int n_stack_returns,
    665 			    unsigned_cell stack_returns[/*n_stack_args*/])
    666 {
    667   device *me = instance->owner;
    668   const device_instance_methods *method = instance->callback->methods;
    669   if (method == NULL) {
    670     device_error(me, "no methods (want %s)", method_name);
    671   }
    672   while (method->name != NULL) {
    673     if (strcmp(method->name, method_name) == 0) {
    674       return method->method(instance,
    675 			    n_stack_args, stack_args,
    676 			    n_stack_returns, stack_returns);
    677     }
    678     method++;
    679   }
    680   device_error(me, "no %s method", method_name);
    681   return 0;
    682 }
    683 
    684 
    685 INLINE_DEVICE\
    686 (device *)
    687 device_instance_device(device_instance *instance)
    688 {
    689   return instance->owner;
    690 }
    691 
    692 INLINE_DEVICE\
    693 (const char *)
    694 device_instance_path(device_instance *instance)
    695 {
    696   return instance->path;
    697 }
    698 
    699 INLINE_DEVICE\
    700 (void *)
    701 device_instance_data(device_instance *instance)
    702 {
    703   return instance->data;
    704 }
    705 
    706 
    707 
    708 /* Device Properties: */
    710 
    711 STATIC_INLINE_DEVICE\
    712 (device_property_entry *)
    713 find_property_entry(device *me,
    714 		     const char *property)
    715 {
    716   device_property_entry *entry;
    717   ASSERT(property != NULL);
    718   entry = me->properties;
    719   while (entry != NULL) {
    720     if (strcmp(entry->value->name, property) == 0)
    721       return entry;
    722     entry = entry->next;
    723   }
    724   return NULL;
    725 }
    726 
    727 STATIC_INLINE_DEVICE\
    728 (void)
    729 device_add_property(device *me,
    730 		    const char *property,
    731 		    device_property_type type,
    732 		    const void *init_array,
    733 		    unsigned sizeof_init_array,
    734 		    const void *array,
    735 		    unsigned sizeof_array,
    736 		    const device_property *original,
    737 		    object_disposition disposition)
    738 {
    739   device_property_entry *new_entry = NULL;
    740   device_property *new_value = NULL;
    741 
    742   /* find the list end */
    743   device_property_entry **insertion_point = &me->properties;
    744   while (*insertion_point != NULL) {
    745     if (strcmp((*insertion_point)->value->name, property) == 0)
    746       return;
    747     insertion_point = &(*insertion_point)->next;
    748   }
    749 
    750   /* create a new value */
    751   new_value = ZALLOC(device_property);
    752   new_value->name = (char *) strdup(property);
    753   new_value->type = type;
    754   if (sizeof_array > 0) {
    755     void *new_array = zalloc(sizeof_array);
    756     memcpy(new_array, array, sizeof_array);
    757     new_value->array = new_array;
    758     new_value->sizeof_array = sizeof_array;
    759   }
    760   new_value->owner = me;
    761   new_value->original = original;
    762   new_value->disposition = disposition;
    763 
    764   /* insert the value into the list */
    765   new_entry = ZALLOC(device_property_entry);
    766   *insertion_point = new_entry;
    767   if (sizeof_init_array > 0) {
    768     void *new_init_array = zalloc(sizeof_init_array);
    769     memcpy(new_init_array, init_array, sizeof_init_array);
    770     new_entry->init_array = new_init_array;
    771     new_entry->sizeof_init_array = sizeof_init_array;
    772   }
    773   new_entry->value = new_value;
    774 }
    775 
    776 
    777 /* local - not available externally */
    778 STATIC_INLINE_DEVICE\
    779 (void)
    780 device_set_property(device *me,
    781 		    const char *property,
    782 		    device_property_type type,
    783 		    const void *array,
    784 		    int sizeof_array)
    785 {
    786   /* find the property */
    787   device_property_entry *entry = find_property_entry(me, property);
    788   if (entry != NULL) {
    789     /* existing property - update it */
    790     void *new_array = 0;
    791     device_property *value = entry->value;
    792     /* check the type matches */
    793     if (value->type != type)
    794       device_error(me, "conflict between type of new and old value for property %s", property);
    795     /* replace its value */
    796     if (value->array != NULL)
    797       free((void*)value->array);
    798     new_array = (sizeof_array > 0
    799 		 ? zalloc(sizeof_array)
    800 		 : (void*)0);
    801     value->array = new_array;
    802     value->sizeof_array = sizeof_array;
    803     if (sizeof_array > 0)
    804       memcpy(new_array, array, sizeof_array);
    805     return;
    806   }
    807   else {
    808     /* new property - create it */
    809     device_add_property(me, property, type,
    810 			NULL, 0, array, sizeof_array,
    811 			NULL, tempoary_object);
    812   }
    813 }
    814 
    815 
    816 STATIC_INLINE_DEVICE\
    817 (void)
    818 clean_device_properties(device *me)
    819 {
    820   device_property_entry **delete_point = &me->properties;
    821   while (*delete_point != NULL) {
    822     device_property_entry *current = *delete_point;
    823     switch (current->value->disposition) {
    824     case permenant_object:
    825       /* zap the current value, will be initialized later */
    826       ASSERT(current->init_array != NULL);
    827       if (current->value->array != NULL) {
    828 	free((void*)current->value->array);
    829 	current->value->array = NULL;
    830       }
    831       delete_point = &(*delete_point)->next;
    832       break;
    833     case tempoary_object:
    834       /* zap the actual property, was created during simulation run */
    835       ASSERT(current->init_array == NULL);
    836       *delete_point = current->next;
    837       if (current->value->array != NULL)
    838 	free((void*)current->value->array);
    839       free(current->value);
    840       free(current);
    841       break;
    842     }
    843   }
    844 }
    845 
    846 
    847 INLINE_DEVICE\
    848 (void)
    849 device_init_static_properties(device *me,
    850 			      void *data)
    851 {
    852   device_property_entry *property;
    853   for (property = me->properties;
    854        property != NULL;
    855        property = property->next) {
    856     ASSERT(property->init_array != NULL);
    857     ASSERT(property->value->array == NULL);
    858     ASSERT(property->value->disposition == permenant_object);
    859     switch (property->value->type) {
    860     case array_property:
    861     case boolean_property:
    862     case range_array_property:
    863     case reg_array_property:
    864     case string_property:
    865     case string_array_property:
    866     case integer_property:
    867       /* delete the property, and replace it with the original */
    868       device_set_property(me, property->value->name,
    869 			  property->value->type,
    870 			  property->init_array,
    871 			  property->sizeof_init_array);
    872       break;
    873     case ihandle_property:
    874       break;
    875     }
    876   }
    877 }
    878 
    879 
    880 INLINE_DEVICE\
    881 (void)
    882 device_init_runtime_properties(device *me,
    883 			       void *data)
    884 {
    885   device_property_entry *property;
    886   for (property = me->properties;
    887        property != NULL;
    888        property = property->next) {
    889     switch (property->value->disposition) {
    890     case permenant_object:
    891       switch (property->value->type) {
    892       case ihandle_property:
    893 	{
    894 	  device_instance *ihandle;
    895 	  ihandle_runtime_property_spec spec;
    896 	  ASSERT(property->init_array != NULL);
    897 	  ASSERT(property->value->array == NULL);
    898 	  device_find_ihandle_runtime_property(me, property->value->name, &spec);
    899 	  ihandle = tree_instance(me, spec.full_path);
    900 	  device_set_ihandle_property(me, property->value->name, ihandle);
    901 	  break;
    902 	}
    903       case array_property:
    904       case boolean_property:
    905       case range_array_property:
    906       case integer_property:
    907       case reg_array_property:
    908       case string_property:
    909       case string_array_property:
    910 	ASSERT(property->init_array != NULL);
    911 	ASSERT(property->value->array != NULL);
    912 	break;
    913       }
    914       break;
    915     case tempoary_object:
    916       ASSERT(property->init_array == NULL);
    917       ASSERT(property->value->array != NULL);
    918       break;
    919     }
    920   }
    921 }
    922 
    923 
    924 INLINE_DEVICE\
    925 (const device_property *)
    926 device_next_property(const device_property *property)
    927 {
    928   /* find the property in the list */
    929   device *owner = property->owner;
    930   device_property_entry *entry = owner->properties;
    931   while (entry != NULL && entry->value != property)
    932     entry = entry->next;
    933   /* now return the following property */
    934   ASSERT(entry != NULL); /* must be a member! */
    935   if (entry->next != NULL)
    936     return entry->next->value;
    937   else
    938     return NULL;
    939 }
    940 
    941 
    942 INLINE_DEVICE\
    943 (const device_property *)
    944 device_find_property(device *me,
    945 		     const char *property)
    946 {
    947   if (me == NULL) {
    948     return NULL;
    949   }
    950   else if (property == NULL || strcmp(property, "") == 0) {
    951     if (me->properties == NULL)
    952       return NULL;
    953     else
    954       return me->properties->value;
    955   }
    956   else {
    957     device_property_entry *entry = find_property_entry(me, property);
    958     if (entry != NULL)
    959       return entry->value;
    960   }
    961   return NULL;
    962 }
    963 
    964 
    965 INLINE_DEVICE\
    966 (void)
    967 device_add_array_property(device *me,
    968                           const char *property,
    969                           const void *array,
    970                           int sizeof_array)
    971 {
    972   device_add_property(me, property, array_property,
    973                       array, sizeof_array, array, sizeof_array,
    974                       NULL, permenant_object);
    975 }
    976 
    977 INLINE_DEVICE\
    978 (void)
    979 device_set_array_property(device *me,
    980 			  const char *property,
    981 			  const void *array,
    982 			  int sizeof_array)
    983 {
    984   device_set_property(me, property, array_property, array, sizeof_array);
    985 }
    986 
    987 INLINE_DEVICE\
    988 (const device_property *)
    989 device_find_array_property(device *me,
    990 			   const char *property)
    991 {
    992   const device_property *node;
    993   node = device_find_property(me, property);
    994   if (node == (device_property*)0
    995       || node->type != array_property)
    996     device_error(me, "property %s not found or of wrong type", property);
    997   return node;
    998 }
    999 
   1000 
   1001 INLINE_DEVICE\
   1002 (void)
   1003 device_add_boolean_property(device *me,
   1004                             const char *property,
   1005                             int boolean)
   1006 {
   1007   signed32 new_boolean = (boolean ? -1 : 0);
   1008   device_add_property(me, property, boolean_property,
   1009                       &new_boolean, sizeof(new_boolean),
   1010                       &new_boolean, sizeof(new_boolean),
   1011                       NULL, permenant_object);
   1012 }
   1013 
   1014 INLINE_DEVICE\
   1015 (int)
   1016 device_find_boolean_property(device *me,
   1017 			     const char *property)
   1018 {
   1019   const device_property *node;
   1020   unsigned_cell boolean;
   1021   node = device_find_property(me, property);
   1022   if (node == (device_property*)0
   1023       || node->type != boolean_property)
   1024     device_error(me, "property %s not found or of wrong type", property);
   1025   ASSERT(sizeof(boolean) == node->sizeof_array);
   1026   memcpy(&boolean, node->array, sizeof(boolean));
   1027   return boolean;
   1028 }
   1029 
   1030 
   1031 INLINE_DEVICE\
   1032 (void)
   1033 device_add_ihandle_runtime_property(device *me,
   1034 				    const char *property,
   1035 				    const ihandle_runtime_property_spec *ihandle)
   1036 {
   1037   /* enter the full path as the init array */
   1038   device_add_property(me, property, ihandle_property,
   1039 		      ihandle->full_path, strlen(ihandle->full_path) + 1,
   1040 		      NULL, 0,
   1041 		      NULL, permenant_object);
   1042 }
   1043 
   1044 INLINE_DEVICE\
   1045 (void)
   1046 device_find_ihandle_runtime_property(device *me,
   1047 				     const char *property,
   1048 				     ihandle_runtime_property_spec *ihandle)
   1049 {
   1050   device_property_entry *entry = find_property_entry(me, property);
   1051   TRACE(trace_devices,
   1052 	("device_find_ihandle_runtime_property(me=0x%lx, property=%s)\n",
   1053 	 (long)me, property));
   1054   if (entry == NULL
   1055       || entry->value->type != ihandle_property
   1056       || entry->value->disposition != permenant_object)
   1057     device_error(me, "property %s not found or of wrong type", property);
   1058   ASSERT(entry->init_array != NULL);
   1059   /* the full path */
   1060   ihandle->full_path = entry->init_array;
   1061 }
   1062 
   1063 
   1064 
   1065 INLINE_DEVICE\
   1066 (void)
   1067 device_set_ihandle_property(device *me,
   1068 			    const char *property,
   1069 			    device_instance *ihandle)
   1070 {
   1071   unsigned_cell cells;
   1072   cells = H2BE_cell(device_instance_to_external(ihandle));
   1073   device_set_property(me, property, ihandle_property,
   1074 		      &cells, sizeof(cells));
   1075 
   1076 }
   1077 
   1078 INLINE_DEVICE\
   1079 (device_instance *)
   1080 device_find_ihandle_property(device *me,
   1081 			     const char *property)
   1082 {
   1083   const device_property *node;
   1084   unsigned_cell ihandle;
   1085   device_instance *instance;
   1086 
   1087   node = device_find_property(me, property);
   1088   if (node == NULL || node->type != ihandle_property)
   1089     device_error(me, "property %s not found or of wrong type", property);
   1090   if (node->array == NULL)
   1091     device_error(me, "runtime property %s not yet initialized", property);
   1092 
   1093   ASSERT(sizeof(ihandle) == node->sizeof_array);
   1094   memcpy(&ihandle, node->array, sizeof(ihandle));
   1095   instance = external_to_device_instance(me, BE2H_cell(ihandle));
   1096   ASSERT(instance != NULL);
   1097   return instance;
   1098 }
   1099 
   1100 
   1101 INLINE_DEVICE\
   1102 (void)
   1103 device_add_integer_property(device *me,
   1104 			    const char *property,
   1105 			    signed_cell integer)
   1106 {
   1107   H2BE(integer);
   1108   device_add_property(me, property, integer_property,
   1109                       &integer, sizeof(integer),
   1110                       &integer, sizeof(integer),
   1111                       NULL, permenant_object);
   1112 }
   1113 
   1114 INLINE_DEVICE\
   1115 (signed_cell)
   1116 device_find_integer_property(device *me,
   1117 			     const char *property)
   1118 {
   1119   const device_property *node;
   1120   signed_cell integer;
   1121   TRACE(trace_devices,
   1122 	("device_find_integer(me=0x%lx, property=%s)\n",
   1123 	 (long)me, property));
   1124   node = device_find_property(me, property);
   1125   if (node == (device_property*)0
   1126       || node->type != integer_property)
   1127     device_error(me, "property %s not found or of wrong type", property);
   1128   ASSERT(sizeof(integer) == node->sizeof_array);
   1129   memcpy(&integer, node->array, sizeof(integer));
   1130   return BE2H_cell(integer);
   1131 }
   1132 
   1133 INLINE_DEVICE\
   1134 (int)
   1135 device_find_integer_array_property(device *me,
   1136 				   const char *property,
   1137 				   unsigned index,
   1138 				   signed_cell *integer)
   1139 {
   1140   const device_property *node;
   1141   int sizeof_integer = sizeof(*integer);
   1142   signed_cell *cell;
   1143   TRACE(trace_devices,
   1144 	("device_find_integer(me=0x%lx, property=%s)\n",
   1145 	 (long)me, property));
   1146 
   1147   /* check things sane */
   1148   node = device_find_property(me, property);
   1149   if (node == (device_property*)0
   1150       || (node->type != integer_property
   1151 	  && node->type != array_property))
   1152     device_error(me, "property %s not found or of wrong type", property);
   1153   if ((node->sizeof_array % sizeof_integer) != 0)
   1154     device_error(me, "property %s contains an incomplete number of cells", property);
   1155   if (node->sizeof_array <= sizeof_integer * index)
   1156     return 0;
   1157 
   1158   /* Find and convert the value */
   1159   cell = ((signed_cell*)node->array) + index;
   1160   *integer = BE2H_cell(*cell);
   1161 
   1162   return node->sizeof_array / sizeof_integer;
   1163 }
   1164 
   1165 
   1166 STATIC_INLINE_DEVICE\
   1167 (unsigned_cell *)
   1168 unit_address_to_cells(const device_unit *unit,
   1169 		      unsigned_cell *cell,
   1170 		      int nr_cells)
   1171 {
   1172   int i;
   1173   ASSERT(nr_cells == unit->nr_cells);
   1174   for (i = 0; i < unit->nr_cells; i++) {
   1175     *cell = H2BE_cell(unit->cells[i]);
   1176     cell += 1;
   1177   }
   1178   return cell;
   1179 }
   1180 
   1181 
   1182 STATIC_INLINE_DEVICE\
   1183 (const unsigned_cell *)
   1184 cells_to_unit_address(const unsigned_cell *cell,
   1185 		      device_unit *unit,
   1186 		      int nr_cells)
   1187 {
   1188   int i;
   1189   memset(unit, 0, sizeof(*unit));
   1190   unit->nr_cells = nr_cells;
   1191   for (i = 0; i < unit->nr_cells; i++) {
   1192     unit->cells[i] = BE2H_cell(*cell);
   1193     cell += 1;
   1194   }
   1195   return cell;
   1196 }
   1197 
   1198 
   1199 STATIC_INLINE_DEVICE\
   1200 (unsigned)
   1201 nr_range_property_cells(device *me,
   1202 			int nr_ranges)
   1203 {
   1204   return ((device_nr_address_cells(me)
   1205 	   + device_nr_address_cells(device_parent(me))
   1206 	   + device_nr_size_cells(me))
   1207 	  ) * nr_ranges;
   1208 }
   1209 
   1210 INLINE_DEVICE\
   1211 (void)
   1212 device_add_range_array_property(device *me,
   1213 				const char *property,
   1214 				const range_property_spec *ranges,
   1215 				unsigned nr_ranges)
   1216 {
   1217   unsigned sizeof_cells = (nr_range_property_cells(me, nr_ranges)
   1218 			   * sizeof(unsigned_cell));
   1219   unsigned_cell *cells = zalloc(sizeof_cells);
   1220   unsigned_cell *cell;
   1221   int i;
   1222 
   1223   /* copy the property elements over */
   1224   cell = cells;
   1225   for (i = 0; i < nr_ranges; i++) {
   1226     const range_property_spec *range = &ranges[i];
   1227     /* copy the child address */
   1228     cell = unit_address_to_cells(&range->child_address, cell,
   1229 				 device_nr_address_cells(me));
   1230     /* copy the parent address */
   1231     cell = unit_address_to_cells(&range->parent_address, cell,
   1232 				 device_nr_address_cells(device_parent(me)));
   1233     /* copy the size */
   1234     cell = unit_address_to_cells(&range->size, cell,
   1235 				 device_nr_size_cells(me));
   1236   }
   1237   ASSERT(cell == &cells[nr_range_property_cells(me, nr_ranges)]);
   1238 
   1239   /* add it */
   1240   device_add_property(me, property, range_array_property,
   1241 		      cells, sizeof_cells,
   1242 		      cells, sizeof_cells,
   1243 		      NULL, permenant_object);
   1244 
   1245   free(cells);
   1246 }
   1247 
   1248 INLINE_DEVICE\
   1249 (int)
   1250 device_find_range_array_property(device *me,
   1251 				 const char *property,
   1252 				 unsigned index,
   1253 				 range_property_spec *range)
   1254 {
   1255   const device_property *node;
   1256   unsigned sizeof_entry = (nr_range_property_cells(me, 1)
   1257 			   * sizeof(unsigned_cell));
   1258   const unsigned_cell *cells;
   1259 
   1260   /* locate the property */
   1261   node = device_find_property(me, property);
   1262   if (node == (device_property*)0
   1263       || node->type != range_array_property)
   1264     device_error(me, "property %s not found or of wrong type", property);
   1265 
   1266   /* aligned ? */
   1267   if ((node->sizeof_array % sizeof_entry) != 0)
   1268     device_error(me, "property %s contains an incomplete number of entries",
   1269 		 property);
   1270 
   1271   /* within bounds? */
   1272   if (node->sizeof_array < sizeof_entry * (index + 1))
   1273     return 0;
   1274 
   1275   /* find the range of interest */
   1276   cells = (unsigned_cell*)((char*)node->array + sizeof_entry * index);
   1277 
   1278   /* copy the child address out - converting as we go */
   1279   cells = cells_to_unit_address(cells, &range->child_address,
   1280 				device_nr_address_cells(me));
   1281 
   1282   /* copy the parent address out - converting as we go */
   1283   cells = cells_to_unit_address(cells, &range->parent_address,
   1284 				device_nr_address_cells(device_parent(me)));
   1285 
   1286   /* copy the size - converting as we go */
   1287   cells = cells_to_unit_address(cells, &range->size,
   1288 				device_nr_size_cells(me));
   1289 
   1290   return node->sizeof_array / sizeof_entry;
   1291 }
   1292 
   1293 
   1294 STATIC_INLINE_DEVICE\
   1295 (unsigned)
   1296 nr_reg_property_cells(device *me,
   1297 		      int nr_regs)
   1298 {
   1299   return (device_nr_address_cells(device_parent(me))
   1300 	  + device_nr_size_cells(device_parent(me))
   1301 	  ) * nr_regs;
   1302 }
   1303 
   1304 INLINE_DEVICE\
   1305 (void)
   1306 device_add_reg_array_property(device *me,
   1307 			      const char *property,
   1308 			      const reg_property_spec *regs,
   1309 			      unsigned nr_regs)
   1310 {
   1311   unsigned sizeof_cells = (nr_reg_property_cells(me, nr_regs)
   1312 			   * sizeof(unsigned_cell));
   1313   unsigned_cell *cells = zalloc(sizeof_cells);
   1314   unsigned_cell *cell;
   1315   int i;
   1316 
   1317   /* copy the property elements over */
   1318   cell = cells;
   1319   for (i = 0; i < nr_regs; i++) {
   1320     const reg_property_spec *reg = &regs[i];
   1321     /* copy the address */
   1322     cell = unit_address_to_cells(&reg->address, cell,
   1323 				 device_nr_address_cells(device_parent(me)));
   1324     /* copy the size */
   1325     cell = unit_address_to_cells(&reg->size, cell,
   1326 				 device_nr_size_cells(device_parent(me)));
   1327   }
   1328   ASSERT(cell == &cells[nr_reg_property_cells(me, nr_regs)]);
   1329 
   1330   /* add it */
   1331   device_add_property(me, property, reg_array_property,
   1332 		      cells, sizeof_cells,
   1333 		      cells, sizeof_cells,
   1334 		      NULL, permenant_object);
   1335 
   1336   free(cells);
   1337 }
   1338 
   1339 INLINE_DEVICE\
   1340 (int)
   1341 device_find_reg_array_property(device *me,
   1342 			       const char *property,
   1343 			       unsigned index,
   1344 			       reg_property_spec *reg)
   1345 {
   1346   const device_property *node;
   1347   unsigned sizeof_entry = (nr_reg_property_cells(me, 1)
   1348 			   * sizeof(unsigned_cell));
   1349   const unsigned_cell *cells;
   1350 
   1351   /* locate the property */
   1352   node = device_find_property(me, property);
   1353   if (node == (device_property*)0
   1354       || node->type != reg_array_property)
   1355     device_error(me, "property %s not found or of wrong type", property);
   1356 
   1357   /* aligned ? */
   1358   if ((node->sizeof_array % sizeof_entry) != 0)
   1359     device_error(me, "property %s contains an incomplete number of entries",
   1360 		 property);
   1361 
   1362   /* within bounds? */
   1363   if (node->sizeof_array < sizeof_entry * (index + 1))
   1364     return 0;
   1365 
   1366   /* find the range of interest */
   1367   cells = (unsigned_cell*)((char*)node->array + sizeof_entry * index);
   1368 
   1369   /* copy the address out - converting as we go */
   1370   cells = cells_to_unit_address(cells, &reg->address,
   1371 				device_nr_address_cells(device_parent(me)));
   1372 
   1373   /* copy the size out - converting as we go */
   1374   cells = cells_to_unit_address(cells, &reg->size,
   1375 				device_nr_size_cells(device_parent(me)));
   1376 
   1377   return node->sizeof_array / sizeof_entry;
   1378 }
   1379 
   1380 
   1381 INLINE_DEVICE\
   1382 (void)
   1383 device_add_string_property(device *me,
   1384                            const char *property,
   1385                            const char *string)
   1386 {
   1387   device_add_property(me, property, string_property,
   1388                       string, strlen(string) + 1,
   1389                       string, strlen(string) + 1,
   1390                       NULL, permenant_object);
   1391 }
   1392 
   1393 INLINE_DEVICE\
   1394 (const char *)
   1395 device_find_string_property(device *me,
   1396 			    const char *property)
   1397 {
   1398   const device_property *node;
   1399   const char *string;
   1400   node = device_find_property(me, property);
   1401   if (node == (device_property*)0
   1402       || node->type != string_property)
   1403     device_error(me, "property %s not found or of wrong type", property);
   1404   string = node->array;
   1405   ASSERT(strlen(string) + 1 == node->sizeof_array);
   1406   return string;
   1407 }
   1408 
   1409 INLINE_DEVICE\
   1410 (void)
   1411 device_add_string_array_property(device *me,
   1412 				 const char *property,
   1413 				 const string_property_spec *strings,
   1414 				 unsigned nr_strings)
   1415 {
   1416   int sizeof_array;
   1417   int string_nr;
   1418   char *array;
   1419   char *chp;
   1420   if (nr_strings == 0)
   1421     device_error(me, "property %s must be non-null", property);
   1422   /* total up the size of the needed array */
   1423   for (sizeof_array = 0, string_nr = 0;
   1424        string_nr < nr_strings;
   1425        string_nr ++) {
   1426     sizeof_array += strlen(strings[string_nr]) + 1;
   1427   }
   1428   /* create the array */
   1429   array = (char*)zalloc(sizeof_array);
   1430   chp = array;
   1431   for (string_nr = 0;
   1432        string_nr < nr_strings;
   1433        string_nr++) {
   1434     strcpy(chp, strings[string_nr]);
   1435     chp += strlen(chp) + 1;
   1436   }
   1437   ASSERT(chp == array + sizeof_array);
   1438   /* now enter it */
   1439   device_add_property(me, property, string_array_property,
   1440 		      array, sizeof_array,
   1441 		      array, sizeof_array,
   1442 		      NULL, permenant_object);
   1443 }
   1444 
   1445 INLINE_DEVICE\
   1446 (int)
   1447 device_find_string_array_property(device *me,
   1448 				  const char *property,
   1449 				  unsigned index,
   1450 				  string_property_spec *string)
   1451 {
   1452   const device_property *node;
   1453   node = device_find_property(me, property);
   1454   if (node == (device_property*)0)
   1455     device_error(me, "property %s not found", property);
   1456   switch (node->type) {
   1457   default:
   1458     device_error(me, "property %s of wrong type", property);
   1459     break;
   1460   case string_property:
   1461     if (index == 0) {
   1462       *string = node->array;
   1463       ASSERT(strlen(*string) + 1 == node->sizeof_array);
   1464       return 1;
   1465     }
   1466     break;
   1467   case array_property:
   1468     if (node->sizeof_array == 0
   1469 	|| ((char*)node->array)[node->sizeof_array - 1] != '\0')
   1470       device_error(me, "property %s invalid for string array", property);
   1471     /* FALL THROUGH */
   1472   case string_array_property:
   1473     ASSERT(node->sizeof_array > 0);
   1474     ASSERT(((char*)node->array)[node->sizeof_array - 1] == '\0');
   1475     {
   1476       const char *chp = node->array;
   1477       int nr_entries = 0;
   1478       /* count the number of strings, keeping an eye out for the one
   1479          we're looking for */
   1480       *string = chp;
   1481       do {
   1482 	if (*chp == '\0') {
   1483 	  /* next string */
   1484 	  nr_entries++;
   1485 	  chp++;
   1486 	  if (nr_entries == index)
   1487 	    *string = chp;
   1488 	}
   1489 	else {
   1490 	  chp++;
   1491 	}
   1492       } while (chp < (char*)node->array + node->sizeof_array);
   1493       if (index < nr_entries)
   1494 	return nr_entries;
   1495       else {
   1496 	*string = NULL;
   1497 	return 0;
   1498       }
   1499     }
   1500     break;
   1501   }
   1502   return 0;
   1503 }
   1504 
   1505 INLINE_DEVICE\
   1506 (void)
   1507 device_add_duplicate_property(device *me,
   1508 			      const char *property,
   1509 			      const device_property *original)
   1510 {
   1511   device_property_entry *master;
   1512   TRACE(trace_devices,
   1513 	("device_add_duplicate_property(me=0x%lx, property=%s, ...)\n",
   1514 	 (long)me, property));
   1515   if (original->disposition != permenant_object)
   1516     device_error(me, "Can only duplicate permenant objects");
   1517   /* find the original's master */
   1518   master = original->owner->properties;
   1519   while (master->value != original) {
   1520     master = master->next;
   1521     ASSERT(master != NULL);
   1522   }
   1523   /* now duplicate it */
   1524   device_add_property(me, property,
   1525 		      original->type,
   1526 		      master->init_array, master->sizeof_init_array,
   1527 		      original->array, original->sizeof_array,
   1528 		      original, permenant_object);
   1529 }
   1530 
   1531 
   1532 
   1533 /* Device Hardware: */
   1535 
   1536 INLINE_DEVICE\
   1537 (unsigned)
   1538 device_io_read_buffer(device *me,
   1539 		      void *dest,
   1540 		      int space,
   1541 		      unsigned_word addr,
   1542 		      unsigned nr_bytes,
   1543 		      cpu *processor,
   1544 		      unsigned_word cia)
   1545 {
   1546   if (me->callback->io.read_buffer == NULL)
   1547     device_error(me, "no io.read_buffer method");
   1548   return me->callback->io.read_buffer(me, dest, space,
   1549 				      addr, nr_bytes,
   1550 				      processor, cia);
   1551 }
   1552 
   1553 INLINE_DEVICE\
   1554 (unsigned)
   1555 device_io_write_buffer(device *me,
   1556 		       const void *source,
   1557 		       int space,
   1558 		       unsigned_word addr,
   1559 		       unsigned nr_bytes,
   1560 		       cpu *processor,
   1561 		       unsigned_word cia)
   1562 {
   1563   if (me->callback->io.write_buffer == NULL)
   1564     device_error(me, "no io.write_buffer method");
   1565   return me->callback->io.write_buffer(me, source, space,
   1566 				       addr, nr_bytes,
   1567 				       processor, cia);
   1568 }
   1569 
   1570 INLINE_DEVICE\
   1571 (unsigned)
   1572 device_dma_read_buffer(device *me,
   1573 		       void *dest,
   1574 		       int space,
   1575 		       unsigned_word addr,
   1576 		       unsigned nr_bytes)
   1577 {
   1578   if (me->callback->dma.read_buffer == NULL)
   1579     device_error(me, "no dma.read_buffer method");
   1580   return me->callback->dma.read_buffer(me, dest, space,
   1581 				       addr, nr_bytes);
   1582 }
   1583 
   1584 INLINE_DEVICE\
   1585 (unsigned)
   1586 device_dma_write_buffer(device *me,
   1587 			const void *source,
   1588 			int space,
   1589 			unsigned_word addr,
   1590 			unsigned nr_bytes,
   1591 			int violate_read_only_section)
   1592 {
   1593   if (me->callback->dma.write_buffer == NULL)
   1594     device_error(me, "no dma.write_buffer method");
   1595   return me->callback->dma.write_buffer(me, source, space,
   1596 					addr, nr_bytes,
   1597 					violate_read_only_section);
   1598 }
   1599 
   1600 INLINE_DEVICE\
   1601 (void)
   1602 device_attach_address(device *me,
   1603 		      attach_type attach,
   1604 		      int space,
   1605 		      unsigned_word addr,
   1606 		      unsigned nr_bytes,
   1607 		      access_type access,
   1608 		      device *client) /*callback/default*/
   1609 {
   1610   if (me->callback->address.attach == NULL)
   1611     device_error(me, "no address.attach method");
   1612   me->callback->address.attach(me, attach, space,
   1613 			       addr, nr_bytes, access, client);
   1614 }
   1615 
   1616 INLINE_DEVICE\
   1617 (void)
   1618 device_detach_address(device *me,
   1619 		      attach_type attach,
   1620 		      int space,
   1621 		      unsigned_word addr,
   1622 		      unsigned nr_bytes,
   1623 		      access_type access,
   1624 		      device *client) /*callback/default*/
   1625 {
   1626   if (me->callback->address.detach == NULL)
   1627     device_error(me, "no address.detach method");
   1628   me->callback->address.detach(me, attach, space,
   1629 			       addr, nr_bytes, access, client);
   1630 }
   1631 
   1632 
   1633 
   1634 /* Interrupts: */
   1636 
   1637 INLINE_DEVICE(void)
   1638 device_interrupt_event(device *me,
   1639 		       int my_port,
   1640 		       int level,
   1641 		       cpu *processor,
   1642 		       unsigned_word cia)
   1643 {
   1644   int found_an_edge = 0;
   1645   device_interrupt_edge *edge;
   1646   /* device's interrupt lines directly connected */
   1647   for (edge = me->interrupt_destinations;
   1648        edge != NULL;
   1649        edge = edge->next) {
   1650     if (edge->my_port == my_port) {
   1651       if (edge->dest->callback->interrupt.event == NULL)
   1652 	device_error(me, "no interrupt method");
   1653       edge->dest->callback->interrupt.event(edge->dest,
   1654 					    edge->dest_port,
   1655 					    me,
   1656 					    my_port,
   1657 					    level,
   1658 					    processor, cia);
   1659       found_an_edge = 1;
   1660     }
   1661   }
   1662   if (!found_an_edge) {
   1663     device_error(me, "No interrupt edge for port %d", my_port);
   1664   }
   1665 }
   1666 
   1667 INLINE_DEVICE\
   1668 (void)
   1669 device_interrupt_attach(device *me,
   1670 			int my_port,
   1671 			device *dest,
   1672 			int dest_port,
   1673 			object_disposition disposition)
   1674 {
   1675   attach_device_interrupt_edge(&me->interrupt_destinations,
   1676 			       my_port,
   1677 			       dest,
   1678 			       dest_port,
   1679 			       disposition);
   1680 }
   1681 
   1682 INLINE_DEVICE\
   1683 (void)
   1684 device_interrupt_detach(device *me,
   1685 			int my_port,
   1686 			device *dest,
   1687 			int dest_port)
   1688 {
   1689   detach_device_interrupt_edge(me,
   1690 			       &me->interrupt_destinations,
   1691 			       my_port,
   1692 			       dest,
   1693 			       dest_port);
   1694 }
   1695 
   1696 INLINE_DEVICE\
   1697 (void)
   1698 device_interrupt_traverse(device *me,
   1699 			  device_interrupt_traverse_function *handler,
   1700 			  void *data)
   1701 {
   1702   device_interrupt_edge *interrupt_edge;
   1703   for (interrupt_edge = me->interrupt_destinations;
   1704        interrupt_edge != NULL;
   1705        interrupt_edge = interrupt_edge->next) {
   1706     handler(me, interrupt_edge->my_port,
   1707 	    interrupt_edge->dest, interrupt_edge->dest_port,
   1708 	    data);
   1709   }
   1710 }
   1711 
   1712 INLINE_DEVICE\
   1713 (int)
   1714 device_interrupt_decode(device *me,
   1715 			const char *port_name,
   1716 			port_direction direction)
   1717 {
   1718   if (port_name == NULL || port_name[0] == '\0')
   1719     return 0;
   1720   if (isdigit(port_name[0])) {
   1721     return strtoul(port_name, NULL, 0);
   1722   }
   1723   else {
   1724     const device_interrupt_port_descriptor *ports =
   1725       me->callback->interrupt.ports;
   1726     if (ports != NULL) {
   1727       while (ports->name != NULL) {
   1728 	if (ports->direction == bidirect_port
   1729 	    || ports->direction == direction) {
   1730 	  if (ports->nr_ports > 0) {
   1731 	    int len = strlen(ports->name);
   1732 	    if (strncmp(port_name, ports->name, len) == 0) {
   1733 	      if (port_name[len] == '\0')
   1734 		return ports->number;
   1735 	      else if(isdigit(port_name[len])) {
   1736 		int port = ports->number + strtoul(&port_name[len], NULL, 0);
   1737 		if (port >= ports->number + ports->nr_ports)
   1738 		  device_error(me, "Interrupt port %s out of range",
   1739 			       port_name);
   1740 		return port;
   1741 	      }
   1742 	    }
   1743 	  }
   1744 	  else if (strcmp(port_name, ports->name) == 0)
   1745 	    return ports->number;
   1746 	}
   1747 	ports++;
   1748       }
   1749     }
   1750   }
   1751   device_error(me, "Unreconized interrupt port %s", port_name);
   1752   return 0;
   1753 }
   1754 
   1755 INLINE_DEVICE\
   1756 (int)
   1757 device_interrupt_encode(device *me,
   1758 			int port_number,
   1759 			char *buf,
   1760 			int sizeof_buf,
   1761 			port_direction direction)
   1762 {
   1763   const device_interrupt_port_descriptor *ports = NULL;
   1764   ports = me->callback->interrupt.ports;
   1765   if (ports != NULL) {
   1766     while (ports->name != NULL) {
   1767       if (ports->direction == bidirect_port
   1768 	  || ports->direction == direction) {
   1769 	if (ports->nr_ports > 0) {
   1770 	  if (port_number >= ports->number
   1771 	      && port_number < ports->number + ports->nr_ports) {
   1772 	    strcpy(buf, ports->name);
   1773 	    sprintf(buf + strlen(buf), "%d", port_number - ports->number);
   1774 	    if (strlen(buf) >= sizeof_buf)
   1775 	      error("device_interrupt_encode: buffer overflow");
   1776 	    return strlen(buf);
   1777 	  }
   1778 	}
   1779 	else {
   1780 	  if (ports->number == port_number) {
   1781 	    if (strlen(ports->name) >= sizeof_buf)
   1782 	      error("device_interrupt_encode: buffer overflow");
   1783 	    strcpy(buf, ports->name);
   1784 	    return strlen(buf);
   1785 	  }
   1786 	}
   1787       }
   1788       ports++;
   1789     }
   1790   }
   1791   sprintf(buf, "%d", port_number);
   1792   if (strlen(buf) >= sizeof_buf)
   1793     error("device_interrupt_encode: buffer overflow");
   1794   return strlen(buf);
   1795 }
   1796 
   1797 
   1798 
   1799 /* IOCTL: */
   1801 
   1802 EXTERN_DEVICE\
   1803 (int)
   1804 device_ioctl(device *me,
   1805 	     cpu *processor,
   1806 	     unsigned_word cia,
   1807 	     device_ioctl_request request,
   1808 	     ...)
   1809 {
   1810   int status;
   1811   va_list ap;
   1812   va_start(ap, request);
   1813   if (me->callback->ioctl == NULL)
   1814     device_error(me, "no ioctl method");
   1815   status = me->callback->ioctl(me, processor, cia, request, ap);
   1816   va_end(ap);
   1817   return status;
   1818 }
   1819 
   1820 
   1821 
   1822 /* I/O */
   1824 
   1825 EXTERN_DEVICE\
   1826 (void)
   1827 device_error(device *me,
   1828 	     const char *fmt,
   1829 	     ...)
   1830 {
   1831   char message[1024];
   1832   va_list ap;
   1833   /* format the message */
   1834   va_start(ap, fmt);
   1835   vsprintf(message, fmt, ap);
   1836   va_end(ap);
   1837   /* sanity check */
   1838   if (strlen(message) >= sizeof(message))
   1839     error("device_error: buffer overflow");
   1840   if (me == NULL)
   1841     error("device: %s", message);
   1842   else if (me->path != NULL && me->path[0] != '\0')
   1843     error("%s: %s", me->path, message);
   1844   else if (me->name != NULL && me->name[0] != '\0')
   1845     error("%s: %s", me->name, message);
   1846   else
   1847     error("device: %s", message);
   1848   while(1);
   1849 }
   1850 
   1851 INLINE_DEVICE\
   1852 (int)
   1853 device_trace(device *me)
   1854 {
   1855   return me->trace;
   1856 }
   1857 
   1858 
   1859 /* External representation */
   1861 
   1862 INLINE_DEVICE\
   1863 (device *)
   1864 external_to_device(device *tree_member,
   1865 		   unsigned_cell phandle)
   1866 {
   1867   device *me = cap_internal(tree_member->phandles, phandle);
   1868   return me;
   1869 }
   1870 
   1871 INLINE_DEVICE\
   1872 (unsigned_cell)
   1873 device_to_external(device *me)
   1874 {
   1875   unsigned_cell phandle = cap_external(me->phandles, me);
   1876   return phandle;
   1877 }
   1878 
   1879 INLINE_DEVICE\
   1880 (device_instance *)
   1881 external_to_device_instance(device *tree_member,
   1882 			    unsigned_cell ihandle)
   1883 {
   1884   device_instance *instance = cap_internal(tree_member->ihandles, ihandle);
   1885   return instance;
   1886 }
   1887 
   1888 INLINE_DEVICE\
   1889 (unsigned_cell)
   1890 device_instance_to_external(device_instance *instance)
   1891 {
   1892   unsigned_cell ihandle = cap_external(instance->owner->ihandles, instance);
   1893   return ihandle;
   1894 }
   1895 
   1896 
   1897 /* Map onto the event functions */
   1898 
   1899 INLINE_DEVICE\
   1900 (event_entry_tag)
   1901 device_event_queue_schedule(device *me,
   1902 			    signed64 delta_time,
   1903 			    device_event_handler *handler,
   1904 			    void *data)
   1905 {
   1906   return event_queue_schedule(psim_event_queue(me->system),
   1907 			      delta_time,
   1908 			      handler,
   1909 			      data);
   1910 }
   1911 
   1912 INLINE_DEVICE\
   1913 (void)
   1914 device_event_queue_deschedule(device *me,
   1915 			      event_entry_tag event_to_remove)
   1916 {
   1917   event_queue_deschedule(psim_event_queue(me->system),
   1918 			 event_to_remove);
   1919 }
   1920 
   1921 INLINE_DEVICE\
   1922 (signed64)
   1923 device_event_queue_time(device *me)
   1924 {
   1925   return event_queue_time(psim_event_queue(me->system));
   1926 }
   1927 
   1928 
   1929 /* Initialization: */
   1930 
   1931 
   1932 INLINE_DEVICE\
   1933 (void)
   1934 device_clean(device *me,
   1935 	     void *data)
   1936 {
   1937   psim *system;
   1938   system = (psim*)data;
   1939   TRACE(trace_device_init, ("device_clean - initializing %s", me->path));
   1940   clean_device_interrupt_edges(&me->interrupt_destinations);
   1941   clean_device_instances(me);
   1942   clean_device_properties(me);
   1943 }
   1944 
   1945 /* Device initialization: */
   1946 
   1947 INLINE_DEVICE\
   1948 (void)
   1949 device_init_address(device *me,
   1950 		    void *data)
   1951 {
   1952   psim *system = (psim*)data;
   1953   int nr_address_cells;
   1954   int nr_size_cells;
   1955   TRACE(trace_device_init, ("device_init_address - initializing %s", me->path));
   1956 
   1957   /* ensure the cap database is valid */
   1958   if (me->parent == NULL) {
   1959     cap_init(me->ihandles);
   1960     cap_init(me->phandles);
   1961   }
   1962 
   1963   /* some basics */
   1964   me->system = system; /* misc things not known until now */
   1965   me->trace = (device_find_property(me, "trace")
   1966 	       ? device_find_integer_property(me, "trace")
   1967 	       : 0);
   1968 
   1969   /* Ensure that the first address found in the reg property matches
   1970      anything that was specified as part of the devices name */
   1971   if (device_find_property(me, "reg") != NULL) {
   1972     reg_property_spec unit;
   1973     device_find_reg_array_property(me, "reg", 0, &unit);
   1974     if (memcmp(device_unit_address(me), &unit.address, sizeof(unit.address))
   1975 	!= 0)
   1976       device_error(me, "Unit address as specified by the reg property in conflict with the value previously specified in the devices path");
   1977   }
   1978 
   1979   /* ensure that the devices #address/size-cells is consistent */
   1980   nr_address_cells = device_nr_address_cells(me);
   1981   if (device_find_property(me, "#address-cells") != NULL
   1982       && (nr_address_cells
   1983 	  != device_find_integer_property(me, "#address-cells")))
   1984     device_error(me, "#address-cells property used before defined");
   1985   nr_size_cells = device_nr_size_cells(me);
   1986   if (device_find_property(me, "#size-cells") != NULL
   1987       && (nr_size_cells
   1988 	  != device_find_integer_property(me, "#size-cells")))
   1989     device_error(me, "#size-cells property used before defined");
   1990 
   1991   /* now init it */
   1992   if (me->callback->init.address != NULL)
   1993     me->callback->init.address(me);
   1994 }
   1995 
   1996 INLINE_DEVICE\
   1997 (void)
   1998 device_init_data(device *me,
   1999 		    void *data)
   2000 {
   2001   TRACE(trace_device_init, ("device_init_data - initializing %s", me->path));
   2002   if (me->callback->init.data != NULL)
   2003     me->callback->init.data(me);
   2004 }
   2005 
   2006 #endif /* _DEVICE_C_ */
   2007