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