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