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