1 /* This file is part of the program psim.
3 Copyright (C) 1994-1995, Andrew Cagney <cagney@highland.com.au>
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.
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.
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.
27 #include "device_table.h"
45 typedef struct _device_property_entry device_property_entry
;
46 struct _device_property_entry
{
48 device_property_entry
*next
;
49 device_property
*value
;
57 const char *full_name
;
63 void *data
; /* device specific data */
64 const device_callbacks
*callback
;
65 /* device properties */
66 device_property_entry
*properties
;
72 device_create(const char *name
,
75 device_descriptor
*descr
;
78 chp
= strchr(name
, '@');
79 name_len
= (chp
== NULL
? strlen(name
) : chp
- name
);
80 for (descr
= device_table
; descr
->name
!= NULL
; descr
++) {
81 if (strncmp(name
, descr
->name
, name_len
) == 0
82 && (descr
->name
[name_len
] == '\0'
83 || descr
->name
[name_len
] == '@')) {
84 void *data
= (descr
->creator
!= NULL
85 ? descr
->creator(name
, parent
)
87 return device_create_from(name
, data
, descr
->callbacks
, parent
);
90 error("device_create() unknown device %s\n", name
);
96 device_create_from(const char *name
,
98 const device_callbacks
*callbacks
,
101 device
*new_device
= ZALLOC(device
);
102 new_device
->data
= data
;
103 new_device
->name
= strdup(name
);
104 new_device
->callback
= callbacks
;
105 new_device
->parent
= parent
;
112 device_parent(device
*me
)
119 device_sibling(device
*me
)
126 device_child(device
*me
)
133 device_name(device
*me
)
140 device_data(device
*me
)
147 device_traverse_properties(device
*me
,
148 device_traverse_property_function
*traverse
,
151 device_property_entry
*entry
= me
->properties
;
152 while (entry
!= NULL
) {
153 traverse(me
, entry
->name
, data
);
160 device_init(device
*me
,
163 me
->callback
->init(me
, system
);
168 device_attach_address(device
*me
,
175 device
*who
) /*callback/default*/
177 me
->callback
->attach_address(me
, name
, attach
, space
,
178 addr
, nr_bytes
, access
, who
);
183 device_detach_address(device
*me
,
190 device
*who
) /*callback/default*/
192 me
->callback
->detach_address(me
, name
, attach
, space
,
193 addr
, nr_bytes
, access
, who
);
198 device_io_read_buffer(device
*me
,
206 return me
->callback
->io_read_buffer(me
, dest
, space
,
213 device_io_write_buffer(device
*me
,
221 return me
->callback
->io_write_buffer(me
, source
, space
,
228 device_dma_read_buffer(device
*me
,
234 return me
->callback
->dma_read_buffer(me
, dest
, space
,
240 device_dma_write_buffer(device
*me
,
245 int violate_read_only_section
)
247 return me
->callback
->dma_write_buffer(me
, source
, space
,
249 violate_read_only_section
);
254 device_attach_interrupt(device
*me
,
259 me
->callback
->attach_interrupt(me
, who
, interrupt_line
, name
);
264 device_detach_interrupt(device
*me
,
269 me
->callback
->detach_interrupt(me
, who
, interrupt_line
, name
);
274 device_interrupt(device
*me
,
277 int interrupt_status
,
281 me
->callback
->interrupt(me
, who
, interrupt_line
, interrupt_status
,
287 device_interrupt_ack(device
*me
,
289 int interrupt_status
)
291 me
->callback
->interrupt_ack(me
, interrupt_line
, interrupt_status
);
296 device_ioctl(device
*me
,
304 me
->callback
->ioctl(me
, system
, processor
, cia
, ap
);
309 /* Manipulate properties attached to devices */
311 STATIC_INLINE_DEVICE\
313 device_add_property(device
*me
,
314 const char *property
,
315 device_property_type type
,
319 device_property_entry
*new_entry
= 0;
320 device_property
*new_value
= 0;
322 /* find the list end */
323 device_property_entry
**insertion_point
= &me
->properties
;
324 while (*insertion_point
!= NULL
) {
325 if (strcmp((**insertion_point
).name
, property
) == 0)
326 return (**insertion_point
).value
;
327 insertion_point
= &(**insertion_point
).next
;
329 /* alloc data for the new property */
330 new_entry
= ZALLOC(device_property_entry
);
331 new_value
= ZALLOC(device_property
);
332 new_array
= (sizeof_array
> 0
333 ? zalloc(sizeof_array
)
335 /* insert the new property into the list */
336 *insertion_point
= new_entry
;
337 new_entry
->name
= strdup(property
);
338 new_entry
->value
= new_value
;
339 new_value
->type
= type
;
340 new_value
->sizeof_array
= sizeof_array
;
341 new_value
->array
= new_array
;
342 if (sizeof_array
> 0)
343 memcpy(new_array
, array
, sizeof_array
);
349 device_add_array_property(device
*me
,
350 const char *property
,
355 ("device_add_array_property(me=0x%lx, property=%s, ...)\n",
356 (long)me
, property
));
357 device_add_property(me
, property
,
358 array_property
, array
, sizeof_array
);
363 device_add_integer_property(device
*me
,
364 const char *property
,
368 ("device_add_integer_property(me=0x%lx, property=%s, integer=%ld)\n",
369 (long)me
, property
, (long)integer
));
371 device_add_property(me
, property
, integer_property
,
372 &integer
, sizeof(integer
));
377 device_add_boolean_property(device
*me
,
378 const char *property
,
381 signed32 new_boolean
= (boolean
? -1 : 0);
383 ("device_add_boolean(me=0x%lx, property=%s, boolean=%d)\n",
384 (long)me
, property
, boolean
));
385 device_add_property(me
, property
, boolean_property
,
386 &new_boolean
, sizeof(new_boolean
));
391 device_add_null_property(device
*me
,
392 const char *property
)
395 ("device_add_null(me=0x%lx, property=%s)\n",
396 (long)me
, property
));
397 device_add_property(me
, property
, null_property
,
403 device_add_string_property(device
*me
,
404 const char *property
,
409 ("device_add_property(me=0x%lx, property=%s, string=%s)\n",
410 (long)me
, property
, string
));
411 device_add_property(me
, property
, string_property
,
412 string
, strlen(string
) + 1);
416 (const device_property
*)
417 device_find_property(device
*me
,
418 const char *property
)
420 if (me
!= (device
*)0) {
421 device_property_entry
*entry
= me
->properties
;
422 while (entry
!= (device_property_entry
*)0) {
423 if (strcmp(entry
->name
, property
) == 0)
428 return (device_property
*)0;
433 device_find_next_property(device
*me
,
434 const char *property
)
437 if (property
== NULL
|| strcmp(property
, "") == 0) {
438 return (me
->properties
!= NULL
439 ? me
->properties
->name
443 device_property_entry
*entry
= me
->properties
;
444 while (entry
!= NULL
) {
445 if (strcmp(entry
->name
, property
) == 0)
446 return (entry
->next
!= NULL
457 (const device_property
*)
458 device_find_array_property(device
*me
,
459 const char *property
)
461 const device_property
*node
;
463 ("device_find_integer(me=0x%lx, property=%s)\n",
464 (long)me
, property
));
465 node
= device_find_property(me
, property
);
466 if (node
== (device_property
*)0
467 || node
->type
!= array_property
)
468 error("%s property %s not found or of wrong type\n",
475 device_find_integer_property(device
*me
,
476 const char *property
)
478 const device_property
*node
;
481 ("device_find_integer(me=0x%lx, property=%s)\n",
482 (long)me
, property
));
483 node
= device_find_property(me
, property
);
484 if (node
== (device_property
*)0
485 || node
->type
!= integer_property
)
486 error("%s property %s not found or of wrong type\n",
488 ASSERT(sizeof(integer
) == node
->sizeof_array
);
489 memcpy(&integer
, node
->array
, sizeof(integer
));
496 device_find_boolean_property(device
*me
,
497 const char *property
)
499 const device_property
*node
;
502 ("device_find_boolean(me=0x%lx, property=%s)\n",
503 (long)me
, property
));
504 node
= device_find_property(me
, property
);
505 if (node
== (device_property
*)0
506 || node
->type
!= boolean_property
)
507 error("%s property %s not found or of wrong type\n",
509 ASSERT(sizeof(boolean
) == node
->sizeof_array
);
510 memcpy(&boolean
, node
->array
, sizeof(boolean
));
516 device_find_string_property(device
*me
,
517 const char *property
)
519 const device_property
*node
;
522 ("device_find_string(me=0x%lx, property=%s)\n",
523 (long)me
, property
));
524 node
= device_find_property(me
, property
);
525 if (node
== (device_property
*)0
526 || node
->type
!= string_property
)
527 error("%s property %s not found or of wrong type\n",
529 string
= node
->array
;
530 ASSERT(strlen(string
) + 1 == node
->sizeof_array
);
535 /* determine the full name of the device. If buf is specified it is
536 stored in there. Failing that, a safe area of memory is allocated */
537 STATIC_INLINE_DEVICE\
539 device_tree_full_name(device
*leaf
,
544 char full_name
[1024];
545 if (buf
== (char*)0) {
547 sizeof_buf
= sizeof(full_name
);
550 /* construct a name */
551 if (leaf
->parent
== NULL
) {
553 error("device_full_name() buffer overflow\n");
557 device_tree_full_name(leaf
->parent
, buf
, sizeof_buf
);
558 if (strlen(buf
) + strlen("/") + strlen(leaf
->name
) + 1 > sizeof_buf
)
559 error("device_full_name() buffer overflow\n");
561 strcat(buf
, leaf
->name
);
564 /* return it usefully */
565 if (buf
== full_name
)
566 buf
= strdup(full_name
);
571 /* find/create a node in the device tree */
574 device_tree_return_null
= 2,
575 device_tree_abort
= 3,
576 } device_tree_action
;
578 STATIC_INLINE_DEVICE\
580 device_tree_find_node(device
*root
,
582 const char *full_path
,
583 device_tree_action action
)
589 /* strip off any leading `/', `../' or `./' */
591 if (strncmp(path
, "/", strlen("/")) == 0) {
592 while (root
!= NULL
&& root
->parent
!= NULL
)
596 else if (strncmp(path
, "./", strlen("./")) == 0) {
598 path
+= strlen("./");
600 else if (strncmp(path
, "../", strlen("../")) == 0) {
601 if (root
!= NULL
&& root
->parent
!= NULL
)
603 path
+= strlen("../");
610 /* parse the driver_name/unit-address */
611 ASSERT(*path
!= '/');
613 while (isalnum(*path
)
614 || *path
== ',' || *path
== ',' || *path
== '_'
615 || *path
== '+' || *path
== '-')
617 if ((*path
!= '/' && *path
!= '@' && *path
!= ':' && *path
!= '\0')
618 || (name
== path
&& *name
!= '\0'))
619 error("device_tree: path %s invalid at %s\n", full_path
, path
);
621 /* parse the unit-address */
624 while ((*path
!= '\0' && *path
!= ':' && *path
!= '/')
625 || (*path
== ':' && path
[-1] == '\\')
626 || (*path
== '/' && path
[-1] == '\\'))
629 strlen_name
= path
- name
;
631 /* skip the device-arguments */
634 while ((*path
!= '\0' && *path
!= '/' && *path
!= ':' && *path
!= '@')
635 || (*path
== '/' && path
[-1] == '\\')
636 || (*path
== ':' && path
[-1] == '\\')
637 || (*path
== '@' && path
[-1] == '\\'))
642 if (*path
!= '\0' && *path
!= '/')
643 error("device_tree: path %s invalid at %s\n", full_path
, path
);
645 /* leaf? and growing? */
646 if (name
[0] == '\0') {
649 else if (root
!= NULL
) {
650 for (child
= root
->children
;
652 child
= child
->sibling
) {
653 if (strncmp(name
, child
->name
, strlen_name
) == 0
654 && strlen(child
->name
) >= strlen_name
655 && (child
->name
[strlen_name
] == '\0'
656 || child
->name
[strlen_name
] == '@')) {
660 return device_tree_find_node(child
,
668 /* search failed, take default action */
670 case device_tree_return_null
:
672 case device_tree_abort
:
673 error("device_tree_find_node() could not find %s in tree\n",
677 error("device_tree_find_node() invalid default action %d\n", action
);
683 /* grow the device tree */
687 device_tree_add_device(device
*root
,
689 device
*new_sub_tree
)
692 TRACE(trace_device_tree
,
693 ("device_tree_add_device(root=0x%lx, prefix=%s, dev=0x%lx)\n",
694 (long)root
, prefix
, (long)new_sub_tree
));
696 /* find our parent */
697 parent
= device_tree_find_node(root
,
699 prefix
, /* full-path */
702 /* create/insert a new child */
703 new_sub_tree
->parent
= parent
;
704 if (parent
!= NULL
) {
705 device
**sibling
= &parent
->children
;
706 while ((*sibling
) != NULL
)
707 sibling
= &(*sibling
)->sibling
;
708 *sibling
= new_sub_tree
;
716 device_tree_find_device(device
*root
,
720 TRACE(trace_device_tree
,
721 ("device_tree_find_device_tree(root=0x%lx, path=%s)\n",
723 node
= device_tree_find_node(root
,
725 path
, /* full-name */
726 device_tree_return_null
);
731 /* init all the devices */
733 STATIC_INLINE_DEVICE\
735 device_tree_init_device(device
*root
,
739 system
= (psim
*)data
;
740 TRACE(trace_device_tree
,
741 ("device_tree_init() initializing device=0x%lx:%s\n",
742 (long)root
, root
->full_name
));
743 device_init(root
, system
);
749 device_tree_init(device
*root
,
752 TRACE(trace_device_tree
,
753 ("device_tree_init(root=0x%lx, system=0x%lx)\n", (long)root
, (long)system
));
754 device_tree_traverse(root
, device_tree_init_device
, NULL
, system
);
755 TRACE(trace_device_tree
,
756 ("device_tree_init() = void\n"));
760 /* traverse a device tree applying prefix/postfix functions to it */
764 device_tree_traverse(device
*root
,
765 device_tree_traverse_function
*prefix
,
766 device_tree_traverse_function
*postfix
,
772 for (child
= root
->children
; child
!= NULL
; child
= child
->sibling
) {
773 device_tree_traverse(child
, prefix
, postfix
, data
);
780 /* dump out a device node and addresses */
784 device_tree_dump(device
*device
,
785 void *ignore_data_argument
)
787 printf_filtered("(device_tree@0x%lx\n", (long)device
);
788 printf_filtered(" (parent 0x%lx)\n", (long)device
->parent
);
789 printf_filtered(" (children 0x%lx)\n", (long)device
->children
);
790 printf_filtered(" (sibling 0x%lx)\n", (long)device
->sibling
);
791 printf_filtered(" (name %s)\n", device
->name
);
792 error("FIXME - need to print out properties\n");
793 printf_filtered(")\n");
797 /* lookup/create a device various formats */
799 STATIC_INLINE_DEVICE\
804 if (MASKED64(uw
, 32, 63) == uw
805 || WITH_HOST_WORD_BITSIZE
== 64) {
806 char *end
= strchr(buf
, '\0');
807 sprintf(end
, "0x%x", (unsigned)uw
);
810 char *end
= strchr(buf
, '\0');
811 sprintf(end
, "0x%x%08x",
812 (unsigned)EXTRACTED64(uw
, 0, 31),
813 (unsigned)EXTRACTED64(uw
, 32, 63));
817 STATIC_INLINE_DEVICE\
822 char *end
= strchr(buf
, '\0');
824 if (*c
== '/' || *c
== ',')
833 device_tree_add_found(device
*root
,
840 TRACE(trace_device_tree
,
841 ("device_tree_add_found(root=0x%lx, prefix=%s, name=%lx)\n",
842 (unsigned long)root
, prefix
, (unsigned long)name
));
843 parent
= device_tree_find_node(root
, prefix
, prefix
,
845 new_device
= device_tree_find_device(parent
, name
);
846 if (new_device
!= NULL
)
849 new_device
= device_create(name
, parent
);
850 new_node
= device_tree_add_device(parent
, "", new_device
);
851 ASSERT(new_device
== new_node
);
858 device_tree_add_found_c(device
*root
,
867 if (strlen(buf
) + 1 >= sizeof(buf
))
868 error("device_tree_add_found_c - buffer overflow\n");
869 return device_tree_add_found(root
, prefix
, buf
);
874 device_tree_add_found_c_uw(device
*root
,
886 if (strlen(buf
) + 1 >= sizeof(buf
))
887 error("device_tree_add_found_* - buffer overflow\n");
888 return device_tree_add_found(root
, prefix
, buf
);
893 device_tree_add_found_uw_u(device
*root
,
905 if (strlen(buf
) + 1 >= sizeof(buf
))
906 error("device_tree_add_found_* - buffer overflow\n");
907 return device_tree_add_found(root
, prefix
, buf
);
912 device_tree_add_found_uw_u_u(device
*root
,
927 if (strlen(buf
) + 1 >= sizeof(buf
))
928 error("device_tree_add_found_* - buffer overflow\n");
929 return device_tree_add_found(root
, prefix
, buf
);
934 device_tree_add_found_uw_u_u_c(device
*root
,
952 if (strlen(buf
) + 1 >= sizeof(buf
))
953 error("device_tree_add_found_* - buffer overflow\n");
954 return device_tree_add_found(root
, prefix
, buf
);
959 device_tree_add_found_uw_uw_u_u_c(device
*root
,
980 if (strlen(buf
) + 1 >= sizeof(buf
))
981 error("device_tree_add_found_* - buffer overflow\n");
982 return device_tree_add_found(root
, prefix
, buf
);
987 device_tree_add_found_uw_uw_u_u_u(device
*root
,
1008 if (strlen(buf
) + 1 >= sizeof(buf
))
1009 error("device_tree_add_found_* - buffer overflow\n");
1010 return device_tree_add_found(root
, prefix
, buf
);
1014 /* Parse a device name, various formats */
1016 #define SCAN_INIT(NAME) \
1017 char *START = (char*)0; \
1018 char *END = (char*)0; \
1020 /* find the first element */ \
1021 END = strchr(NAME, '@'); \
1022 if (END == (char*)0) \
1032 *U = strtoul(START, &END, 0); \
1043 *P = (void*)(unsigned)strtouq(START, END, 0); \
1052 #define SCAN_C(C, SIZE) \
1056 while (*END != '\0' && *END != ',') { \
1062 if ((SIZE) <= ((END) - (START))) \
1063 return COUNT; /* overflow */ \
1076 scand_c(const char *name
,
1087 scand_c_uw_u(const char *name
,
1102 scand_uw(const char *name
,
1112 scand_uw_c(const char *name
,
1125 scand_uw_u(const char *name
,
1137 scand_uw_u_u(const char *name
,
1151 scand_uw_u_u_c(const char *name
,
1168 scand_uw_uw(const char *name
,
1180 scand_uw_uw_u(const char *name
,
1194 scand_uw_uw_u_u_c(const char *name
,
1213 scand_uw_uw_u_u_u(const char *name
,
1230 #endif /* _DEVICE_C_ */