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