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