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