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