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