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