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