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