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