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