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