PowerPC64 ld segfault with code in non-executable sections
[external/binutils.git] / sim / ppc / device.c
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
46 STATIC_INLINE_DEVICE (void) clean_device_properties(device *);
47
48 /* property entries */
49
50 typedef struct _device_property_entry device_property_entry;
51 struct _device_property_entry {
52   device_property_entry *next;
53   device_property *value;
54   const void *init_array;
55   unsigned sizeof_init_array;
56 };
57
58
59 /* Interrupt edges */
60
61 typedef struct _device_interrupt_edge device_interrupt_edge;
62 struct _device_interrupt_edge {
63   int my_port;
64   device *dest;
65   int dest_port;
66   device_interrupt_edge *next;
67   object_disposition disposition;
68 };
69
70 STATIC_INLINE_DEVICE\
71 (void)
72 attach_device_interrupt_edge(device_interrupt_edge **list,
73                              int my_port,
74                              device *dest,
75                              int dest_port,
76                              object_disposition disposition)
77 {
78   device_interrupt_edge *new_edge = ZALLOC(device_interrupt_edge);
79   new_edge->my_port = my_port;
80   new_edge->dest = dest;
81   new_edge->dest_port = dest_port;
82   new_edge->next = *list;
83   new_edge->disposition = disposition;
84   *list = new_edge;
85 }
86
87 STATIC_INLINE_DEVICE\
88 (void)
89 detach_device_interrupt_edge(device *me,
90                              device_interrupt_edge **list,
91                              int my_port,
92                              device *dest,
93                              int dest_port)
94 {
95   while (*list != NULL) {
96     device_interrupt_edge *old_edge = *list;
97     if (old_edge->dest == dest
98         && old_edge->dest_port == dest_port
99         && old_edge->my_port == my_port) {
100       if (old_edge->disposition == permenant_object)
101         device_error(me, "attempt to delete permenant interrupt");
102       *list = old_edge->next;
103       free(old_edge);
104       return;
105     }
106   }
107   device_error(me, "attempt to delete unattached interrupt");
108 }
109
110 STATIC_INLINE_DEVICE\
111 (void)
112 clean_device_interrupt_edges(device_interrupt_edge **list)
113 {
114   while (*list != NULL) {
115     device_interrupt_edge *old_edge = *list;
116     switch (old_edge->disposition) {
117     case permenant_object:
118       list = &old_edge->next;
119       break;
120     case tempoary_object:
121       *list = old_edge->next;
122       free(old_edge);
123       break;
124     }
125   }
126 }
127
128
129 /* A device */
130
131 struct _device {
132
133   /* my name is ... */
134   const char *name;
135   device_unit unit_address;
136   const char *path;
137   int nr_address_cells;
138   int nr_size_cells;
139
140   /* device tree */
141   device *parent;
142   device *children;
143   device *sibling;
144
145   /* its template methods */
146   void *data; /* device specific data */
147   const device_callbacks *callback;
148
149   /* device properties */
150   device_property_entry *properties;
151
152   /* interrupts */
153   device_interrupt_edge *interrupt_destinations;
154
155   /* any open instances of this device */
156   device_instance *instances;
157
158   /* the internal/external mappings and other global requirements */
159   cap *ihandles;
160   cap *phandles;
161   psim *system;
162
163   /* debugging */
164   int trace;
165 };
166
167
168 /* an instance of a device */
169 struct _device_instance {
170   void *data;
171   char *args;
172   char *path;
173   const device_instance_callbacks *callback;
174   /* the root instance */
175   device *owner;
176   device_instance *next;
177   /* interposed instance */
178   device_instance *parent;
179   device_instance *child;
180 };
181
182
183 \f
184 /* creation */
185
186 STATIC_INLINE_DEVICE\
187 (const char *)
188 device_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
230 STATIC_INLINE_DEVICE\
231 (device *)
232 device_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
278 INLINE_DEVICE\
279 (device *)
280 device_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
310 INLINE_DEVICE\
311 (void)
312 device_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 \f
358 /* Device node: */
359
360 INLINE_DEVICE\
361 (device *)
362 device_parent(device *me)
363 {
364   return me->parent;
365 }
366
367 INLINE_DEVICE\
368 (device *)
369 device_root(device *me)
370 {
371   ASSERT(me != NULL);
372   while (me->parent != NULL)
373     me = me->parent;
374   return me;
375 }
376
377 INLINE_DEVICE\
378 (device *)
379 device_sibling(device *me)
380 {
381   return me->sibling;
382 }
383
384 INLINE_DEVICE\
385 (device *)
386 device_child(device *me)
387 {
388   return me->children;
389 }
390
391 INLINE_DEVICE\
392 (const char *)
393 device_name(device *me)
394 {
395   return me->name;
396 }
397
398 INLINE_DEVICE\
399 (const char *)
400 device_path(device *me)
401 {
402   return me->path;
403 }
404
405 INLINE_DEVICE\
406 (void *)
407 device_data(device *me)
408 {
409   return me->data;
410 }
411
412 INLINE_DEVICE\
413 (psim *)
414 device_system(device *me)
415 {
416   return me->system;
417 }
418
419 INLINE_DEVICE\
420 (const device_unit *)
421 device_unit_address(device *me)
422 {
423   return &me->unit_address;
424 }
425
426
427 INLINE_DEVICE\
428 (int)
429 device_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
441 INLINE_DEVICE\
442 (int)
443 device_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
454 INLINE_DEVICE\
455 (int)
456 device_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
466 INLINE_DEVICE\
467 (int)
468 device_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
478 INLINE_DEVICE\
479 (unsigned)
480 device_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
491 INLINE_DEVICE\
492 (unsigned)
493 device_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 \f
506 /* device-instance: */
507
508 INLINE_DEVICE\
509 (device_instance *)
510 device_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
557 INLINE_DEVICE\
558 (device_instance *)
559 device_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
570 STATIC_INLINE_DEVICE\
571 (void)
572 clean_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
583 INLINE_DEVICE\
584 (void)
585 device_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
619 INLINE_DEVICE\
620 (int)
621 device_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
631 INLINE_DEVICE\
632 (int)
633 device_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
643 INLINE_DEVICE\
644 (int)
645 device_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
655 INLINE_DEVICE\
656 (int)
657 device_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
682 INLINE_DEVICE\
683 (device *)
684 device_instance_device(device_instance *instance)
685 {
686   return instance->owner;
687 }
688
689 INLINE_DEVICE\
690 (const char *)
691 device_instance_path(device_instance *instance)
692 {
693   return instance->path;
694 }
695
696 INLINE_DEVICE\
697 (void *)
698 device_instance_data(device_instance *instance)
699 {
700   return instance->data;
701 }
702
703
704 \f
705 /* Device Properties: */
706
707 STATIC_INLINE_DEVICE\
708 (device_property_entry *)
709 find_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
723 STATIC_INLINE_DEVICE\
724 (void)
725 device_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 */
774 STATIC_INLINE_DEVICE\
775 (void)
776 device_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
812 STATIC_INLINE_DEVICE\
813 (void)
814 clean_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
843 INLINE_DEVICE\
844 (void)
845 device_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
876 INLINE_DEVICE\
877 (void)
878 device_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
920 INLINE_DEVICE\
921 (const device_property *)
922 device_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
938 INLINE_DEVICE\
939 (const device_property *)
940 device_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
961 INLINE_DEVICE\
962 (void)
963 device_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
973 INLINE_DEVICE\
974 (void)
975 device_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
983 INLINE_DEVICE\
984 (const device_property *)
985 device_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
997 INLINE_DEVICE\
998 (void)
999 device_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
1010 INLINE_DEVICE\
1011 (int)
1012 device_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
1027 INLINE_DEVICE\
1028 (void)
1029 device_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
1040 INLINE_DEVICE\
1041 (void)
1042 device_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
1061 INLINE_DEVICE\
1062 (void)
1063 device_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
1074 INLINE_DEVICE\
1075 (device_instance *)
1076 device_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
1097 INLINE_DEVICE\
1098 (void)
1099 device_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
1110 INLINE_DEVICE\
1111 (signed_cell)
1112 device_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
1129 INLINE_DEVICE\
1130 (int)
1131 device_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
1162 STATIC_INLINE_DEVICE\
1163 (unsigned_cell *)
1164 unit_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
1178 STATIC_INLINE_DEVICE\
1179 (const unsigned_cell *)
1180 cells_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
1195 STATIC_INLINE_DEVICE\
1196 (unsigned)
1197 nr_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
1206 INLINE_DEVICE\
1207 (void)
1208 device_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
1244 INLINE_DEVICE\
1245 (int)
1246 device_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
1290 STATIC_INLINE_DEVICE\
1291 (unsigned)
1292 nr_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
1300 INLINE_DEVICE\
1301 (void)
1302 device_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
1335 INLINE_DEVICE\
1336 (int)
1337 device_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
1377 INLINE_DEVICE\
1378 (void)
1379 device_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
1389 INLINE_DEVICE\
1390 (const char *)
1391 device_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
1405 INLINE_DEVICE\
1406 (void)
1407 device_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
1441 INLINE_DEVICE\
1442 (int)
1443 device_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
1501 INLINE_DEVICE\
1502 (void)
1503 device_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 \f
1529 /* Device Hardware: */
1530
1531 INLINE_DEVICE\
1532 (unsigned)
1533 device_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
1548 INLINE_DEVICE\
1549 (unsigned)
1550 device_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
1565 INLINE_DEVICE\
1566 (unsigned)
1567 device_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
1579 INLINE_DEVICE\
1580 (unsigned)
1581 device_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
1595 INLINE_DEVICE\
1596 (void)
1597 device_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
1611 INLINE_DEVICE\
1612 (void)
1613 device_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 \f
1629 /* Interrupts: */
1630
1631 INLINE_DEVICE(void)
1632 device_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
1661 INLINE_DEVICE\
1662 (void)
1663 device_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
1676 INLINE_DEVICE\
1677 (void)
1678 device_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
1690 INLINE_DEVICE\
1691 (void)
1692 device_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
1706 INLINE_DEVICE\
1707 (int)
1708 device_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
1749 INLINE_DEVICE\
1750 (int)
1751 device_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 \f
1793 /* IOCTL: */
1794
1795 EXTERN_DEVICE\
1796 (int)
1797 device_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 \f
1815 /* I/O */
1816
1817 EXTERN_DEVICE\
1818 (void)
1819 device_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
1843 INLINE_DEVICE\
1844 (int)
1845 device_trace(device *me)
1846 {
1847   return me->trace;
1848 }
1849
1850 \f
1851 /* External representation */
1852
1853 INLINE_DEVICE\
1854 (device *)
1855 external_to_device(device *tree_member,
1856                    unsigned_cell phandle)
1857 {
1858   device *me = cap_internal(tree_member->phandles, phandle);
1859   return me;
1860 }
1861
1862 INLINE_DEVICE\
1863 (unsigned_cell)
1864 device_to_external(device *me)
1865 {
1866   unsigned_cell phandle = cap_external(me->phandles, me);
1867   return phandle;
1868 }
1869
1870 INLINE_DEVICE\
1871 (device_instance *)
1872 external_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
1879 INLINE_DEVICE\
1880 (unsigned_cell)
1881 device_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
1890 INLINE_DEVICE\
1891 (event_entry_tag)
1892 device_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
1903 INLINE_DEVICE\
1904 (void)
1905 device_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
1912 INLINE_DEVICE\
1913 (signed64)
1914 device_event_queue_time(device *me)
1915 {
1916   return event_queue_time(psim_event_queue(me->system));
1917 }
1918
1919
1920 /* Initialization: */
1921
1922
1923 INLINE_DEVICE\
1924 (void)
1925 device_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
1938 INLINE_DEVICE\
1939 (void)
1940 device_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
1987 INLINE_DEVICE\
1988 (void)
1989 device_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_ */