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
;
70 device INLINE_DEVICE
*
71 device_create(const char *name
,
74 device_descriptor
*descr
;
77 chp
= strchr(name
, '@');
78 name_len
= (chp
== NULL
? strlen(name
) : chp
- name
);
79 for (descr
= device_table
; descr
->name
!= NULL
; descr
++) {
80 if (strncmp(name
, descr
->name
, name_len
) == 0
81 && (descr
->name
[name_len
] == '\0'
82 || descr
->name
[name_len
] == '@')) {
83 void *data
= (descr
->creator
!= NULL
84 ? descr
->creator(name
, parent
)
86 return device_create_from(name
, data
, descr
->callbacks
, parent
);
89 error("device_create() unknown device %s\n", name
);
93 device INLINE_DEVICE
*
94 device_create_from(const char *name
,
96 const device_callbacks
*callbacks
,
99 device
*new_device
= ZALLOC(device
);
100 new_device
->data
= data
;
101 new_device
->name
= strdup(name
);
102 new_device
->callback
= callbacks
;
103 new_device
->parent
= parent
;
108 device INLINE_DEVICE
*
109 device_parent(device
*me
)
114 const char INLINE_DEVICE
*
115 device_name(device
*me
)
121 device_data(device
*me
)
127 device_traverse_properties(device
*me
,
128 device_traverse_property_function
*traverse
,
131 device_property_entry
*entry
= me
->properties
;
132 while (entry
!= NULL
) {
133 traverse(me
, entry
->name
, data
);
139 device_init(device
*me
,
142 me
->callback
->init(me
, system
);
146 device_attach_address(device
*me
,
153 device
*who
) /*callback/default*/
155 me
->callback
->attach_address(me
, name
, attach
, space
,
156 addr
, nr_bytes
, access
, who
);
160 device_detach_address(device
*me
,
167 device
*who
) /*callback/default*/
169 me
->callback
->detach_address(me
, name
, attach
, space
,
170 addr
, nr_bytes
, access
, who
);
173 unsigned INLINE_DEVICE
174 device_io_read_buffer(device
*me
,
182 return me
->callback
->io_read_buffer(me
, dest
, space
,
187 unsigned INLINE_DEVICE
188 device_io_write_buffer(device
*me
,
196 return me
->callback
->io_write_buffer(me
, source
, space
,
201 unsigned INLINE_DEVICE
202 device_dma_read_buffer(device
*me
,
208 return me
->callback
->dma_read_buffer(me
, dest
, space
,
212 unsigned INLINE_DEVICE
213 device_dma_write_buffer(device
*me
,
218 int violate_read_only_section
)
220 return me
->callback
->dma_write_buffer(me
, source
, space
,
222 violate_read_only_section
);
226 device_attach_interrupt(device
*me
,
231 me
->callback
->attach_interrupt(me
, who
, interrupt_line
, name
);
235 device_detach_interrupt(device
*me
,
240 me
->callback
->detach_interrupt(me
, who
, interrupt_line
, name
);
244 device_interrupt(device
*me
,
247 int interrupt_status
,
251 me
->callback
->interrupt(me
, who
, interrupt_line
, interrupt_status
,
256 device_interrupt_ack(device
*me
,
258 int interrupt_status
)
260 me
->callback
->interrupt_ack(me
, interrupt_line
, interrupt_status
);
264 device_ioctl(device
*me
,
272 me
->callback
->ioctl(me
, system
, processor
, cia
, ap
);
277 /* Manipulate properties attached to devices */
279 device_property STATIC_INLINE_DEVICE
*
280 device_add_property(device
*me
,
281 const char *property
,
282 device_property_type type
,
286 device_property_entry
*new_entry
= 0;
287 device_property
*new_value
= 0;
289 /* find the list end */
290 device_property_entry
**insertion_point
= &me
->properties
;
291 while (*insertion_point
!= NULL
) {
292 if (strcmp((**insertion_point
).name
, property
) == 0)
293 return (**insertion_point
).value
;
294 insertion_point
= &(**insertion_point
).next
;
296 /* alloc data for the new property */
297 new_entry
= ZALLOC(device_property_entry
);
298 new_value
= ZALLOC(device_property
);
299 new_array
= (sizeof_array
> 0
300 ? zalloc(sizeof_array
)
302 /* insert the new property into the list */
303 *insertion_point
= new_entry
;
304 new_entry
->name
= strdup(property
);
305 new_entry
->value
= new_value
;
306 new_value
->type
= type
;
307 new_value
->sizeof_array
= sizeof_array
;
308 new_value
->array
= new_array
;
309 if (sizeof_array
> 0)
310 memcpy(new_array
, array
, sizeof_array
);
315 device_add_array_property(device
*me
,
316 const char *property
,
321 ("device_add_array_property(me=0x%lx, property=%s, ...)\n",
322 (long)me
, property
));
323 device_add_property(me
, property
,
324 array_property
, array
, sizeof_array
);
328 device_add_integer_property(device
*me
,
329 const char *property
,
333 ("device_add_integer_property(me=0x%lx, property=%s, integer=%ld)\n",
334 (long)me
, property
, (long)integer
));
336 device_add_property(me
, property
, integer_property
,
337 &integer
, sizeof(integer
));
341 device_add_boolean_property(device
*me
,
342 const char *property
,
345 signed32 new_boolean
= (boolean
? -1 : 0);
347 ("device_add_boolean(me=0x%lx, property=%s, boolean=%d)\n",
348 (long)me
, property
, boolean
));
349 device_add_property(me
, property
, boolean_property
,
350 &new_boolean
, sizeof(new_boolean
));
354 device_add_null_property(device
*me
,
355 const char *property
)
358 ("device_add_null(me=0x%lx, property=%s)\n",
359 (long)me
, property
));
360 device_add_property(me
, property
, null_property
,
365 device_add_string_property(device
*me
,
366 const char *property
,
371 ("device_add_property(me=0x%lx, property=%s, string=%s)\n",
372 (long)me
, property
, string
));
373 device_add_property(me
, property
, string_property
,
374 string
, strlen(string
) + 1);
377 const device_property INLINE_DEVICE
*
378 device_find_property(device
*me
,
379 const char *property
)
381 if (me
!= (device
*)0) {
382 device_property_entry
*entry
= me
->properties
;
383 while (entry
!= (device_property_entry
*)0) {
384 if (strcmp(entry
->name
, property
) == 0)
389 return (device_property
*)0;
392 const char INLINE_DEVICE
*
393 device_find_next_property(device
*me
,
394 const char *property
)
397 if (property
== NULL
|| strcmp(property
, "") == 0) {
398 return (me
->properties
!= NULL
399 ? me
->properties
->name
403 device_property_entry
*entry
= me
->properties
;
404 while (entry
!= NULL
) {
405 if (strcmp(entry
->name
, property
) == 0)
406 return (entry
->next
!= NULL
416 const device_property INLINE_DEVICE
*
417 device_find_array_property(device
*me
,
418 const char *property
)
420 const device_property
*node
;
422 ("device_find_integer(me=0x%lx, property=%s)\n",
423 (long)me
, property
));
424 node
= device_find_property(me
, property
);
425 if (node
== (device_property
*)0
426 || node
->type
!= array_property
)
427 error("%s property %s not found or of wrong type\n",
432 signed_word INLINE_DEVICE
433 device_find_integer_property(device
*me
,
434 const char *property
)
436 const device_property
*node
;
439 ("device_find_integer(me=0x%lx, property=%s)\n",
440 (long)me
, property
));
441 node
= device_find_property(me
, property
);
442 if (node
== (device_property
*)0
443 || node
->type
!= integer_property
)
444 error("%s property %s not found or of wrong type\n",
446 ASSERT(sizeof(integer
) == node
->sizeof_array
);
447 memcpy(&integer
, node
->array
, sizeof(integer
));
453 device_find_boolean_property(device
*me
,
454 const char *property
)
456 const device_property
*node
;
459 ("device_find_boolean(me=0x%lx, property=%s)\n",
460 (long)me
, property
));
461 node
= device_find_property(me
, property
);
462 if (node
== (device_property
*)0
463 || node
->type
!= boolean_property
)
464 error("%s property %s not found or of wrong type\n",
466 ASSERT(sizeof(boolean
) == node
->sizeof_array
);
467 memcpy(&boolean
, node
->array
, sizeof(boolean
));
471 const char INLINE_DEVICE
*
472 device_find_string_property(device
*me
,
473 const char *property
)
475 const device_property
*node
;
478 ("device_find_string(me=0x%lx, property=%s)\n",
479 (long)me
, property
));
480 node
= device_find_property(me
, property
);
481 if (node
== (device_property
*)0
482 || node
->type
!= string_property
)
483 error("%s property %s not found or of wrong type\n",
485 string
= node
->array
;
486 ASSERT(strlen(string
) + 1 == node
->sizeof_array
);
491 /* determine the full name of the device. If buf is specified it is
492 stored in there. Failing that, a safe area of memory is allocated */
493 const char STATIC_INLINE_DEVICE
*
494 device_tree_full_name(device
*leaf
,
499 char full_name
[1024];
500 if (buf
== (char*)0) {
502 sizeof_buf
= sizeof(full_name
);
505 /* construct a name */
506 if (leaf
->parent
== NULL
) {
508 error("device_full_name() buffer overflow\n");
512 device_tree_full_name(leaf
->parent
, buf
, sizeof_buf
);
513 if (strlen(buf
) + strlen("/") + strlen(leaf
->name
) + 1 > sizeof_buf
)
514 error("device_full_name() buffer overflow\n");
516 strcat(buf
, leaf
->name
);
519 /* return it usefully */
520 if (buf
== full_name
)
521 buf
= strdup(full_name
);
526 /* find/create a node in the device tree */
529 device_tree_return_null
= 2,
530 device_tree_abort
= 3,
531 } device_tree_action
;
533 device STATIC_INLINE_DEVICE
*
534 device_tree_find_node(device
*root
,
536 const char *full_path
,
537 device_tree_action action
)
543 /* strip off any leading `/', `../' or `./' */
545 if (strncmp(path
, "/", strlen("/")) == 0) {
546 while (root
!= NULL
&& root
->parent
!= NULL
)
550 else if (strncmp(path
, "./", strlen("./")) == 0) {
552 path
+= strlen("./");
554 else if (strncmp(path
, "../", strlen("../")) == 0) {
555 if (root
!= NULL
&& root
->parent
!= NULL
)
557 path
+= strlen("../");
564 /* parse the driver_name/unit-address */
565 ASSERT(*path
!= '/');
567 while (isalnum(*path
)
568 || *path
== ',' || *path
== ',' || *path
== '_'
569 || *path
== '+' || *path
== '-')
571 if ((*path
!= '/' && *path
!= '@' && *path
!= ':' && *path
!= '\0')
572 || (name
== path
&& *name
!= '\0'))
573 error("device_tree: path %s invalid at %s\n", full_path
, path
);
575 /* parse the unit-address */
578 while ((*path
!= '\0' && *path
!= ':' && *path
!= '/')
579 || (*path
== ':' && path
[-1] == '\\')
580 || (*path
== '/' && path
[-1] == '\\'))
583 strlen_name
= path
- name
;
585 /* skip the device-arguments */
588 while ((*path
!= '\0' && *path
!= '/' && *path
!= ':' && *path
!= '@')
589 || (*path
== '/' && path
[-1] == '\\')
590 || (*path
== ':' && path
[-1] == '\\')
591 || (*path
== '@' && path
[-1] == '\\'))
596 if (*path
!= '\0' && *path
!= '/')
597 error("device_tree: path %s invalid at %s\n", full_path
, path
);
599 /* leaf? and growing? */
600 if (name
[0] == '\0') {
603 else if (root
!= NULL
) {
604 for (child
= root
->children
;
606 child
= child
->sibling
) {
607 if (strncmp(name
, child
->name
, strlen_name
) == 0
608 && strlen(child
->name
) == strlen_name
) {
612 return device_tree_find_node(child
,
620 /* search failed, take default action */
622 case device_tree_return_null
:
624 case device_tree_abort
:
625 error("device_tree_find_node() could not find %s in tree\n",
629 error("device_tree_find_node() invalid default action %d\n", action
);
635 /* grow the device tree */
637 device INLINE_DEVICE
*
638 device_tree_add_device(device
*root
,
640 device
*new_sub_tree
)
643 TRACE(trace_device_tree
,
644 ("device_tree_add_device(root=0x%lx, prefix=%s, dev=0x%lx)\n",
645 (long)root
, prefix
, (long)new_sub_tree
));
647 /* find our parent */
648 parent
= device_tree_find_node(root
,
650 prefix
, /* full-path */
653 /* create/insert a new child */
654 new_sub_tree
->parent
= parent
;
655 if (parent
!= NULL
) {
656 device
**sibling
= &parent
->children
;
657 while ((*sibling
) != NULL
)
658 sibling
= &(*sibling
)->sibling
;
659 *sibling
= new_sub_tree
;
665 device INLINE_DEVICE
*
666 device_tree_find_device(device
*root
,
670 TRACE(trace_device_tree
,
671 ("device_tree_find_device_tree(root=0x%lx, path=%s)\n",
673 node
= device_tree_find_node(root
,
675 path
, /* full-name */
676 device_tree_return_null
);
681 /* init all the devices */
683 void STATIC_INLINE_DEVICE
684 device_tree_init_device(device
*root
,
688 system
= (psim
*)data
;
689 TRACE(trace_device_tree
,
690 ("device_tree_init() initializing device=0x%lx:%s\n",
691 (long)root
, root
->full_name
));
692 device_init(root
, system
);
697 device_tree_init(device
*root
,
700 TRACE(trace_device_tree
,
701 ("device_tree_init(root=0x%lx, system=0x%lx)\n", (long)root
, (long)system
));
702 device_tree_traverse(root
, device_tree_init_device
, NULL
, system
);
703 TRACE(trace_device_tree
,
704 ("device_tree_init() = void\n"));
708 /* traverse a device tree applying prefix/postfix functions to it */
711 device_tree_traverse(device
*root
,
712 device_tree_traverse_function
*prefix
,
713 device_tree_traverse_function
*postfix
,
719 for (child
= root
->children
; child
!= NULL
; child
= child
->sibling
) {
720 device_tree_traverse(child
, prefix
, postfix
, data
);
727 /* dump out a device node and addresses */
730 device_tree_dump(device
*device
,
731 void *ignore_data_argument
)
733 printf_filtered("(device_tree@0x%lx\n", (long)device
);
734 printf_filtered(" (parent 0x%lx)\n", (long)device
->parent
);
735 printf_filtered(" (children 0x%lx)\n", (long)device
->children
);
736 printf_filtered(" (sibling 0x%lx)\n", (long)device
->sibling
);
737 printf_filtered(" (name %s)\n", device
->name
);
738 error("FIXME - need to print out properties\n");
739 printf_filtered(")\n");
743 /* lookup/create a device various formats */
745 void STATIC_INLINE_DEVICE
749 if (MASKED64(uw
, 32, 63) == uw
750 || WITH_HOST_WORD_BITSIZE
== 64) {
751 char *end
= strchr(buf
, '\0');
752 sprintf(end
, "0x%x", (unsigned)uw
);
755 char *end
= strchr(buf
, '\0');
756 sprintf(end
, "0x%x%08x",
757 (unsigned)EXTRACTED64(uw
, 0, 31),
758 (unsigned)EXTRACTED64(uw
, 32, 63));
762 void STATIC_INLINE_DEVICE
766 char *end
= strchr(buf
, '\0');
768 if (*c
== '/' || *c
== ',')
775 device INLINE_DEVICE
*
776 device_tree_add_found(device
*root
,
783 TRACE(trace_device_tree
,
784 ("device_tree_add_found(root=0x%lx, prefix=%s, name=%x)\n",
785 (long)root
, prefix
, name
));
786 parent
= device_tree_find_node(root
, prefix
, prefix
,
788 new_device
= device_tree_find_device(parent
, name
);
789 if (new_device
!= NULL
)
792 new_device
= device_create(name
, parent
);
793 new_node
= device_tree_add_device(parent
, "", new_device
);
794 ASSERT(new_device
== new_node
);
799 device INLINE_DEVICE
*
800 device_tree_add_found_c(device
*root
,
809 if (strlen(buf
) + 1 >= sizeof(buf
))
810 error("device_tree_add_found_c - buffer overflow\n");
811 return device_tree_add_found(root
, prefix
, buf
);
814 device INLINE_DEVICE
*
815 device_tree_add_found_c_uw(device
*root
,
827 if (strlen(buf
) + 1 >= sizeof(buf
))
828 error("device_tree_add_found_* - buffer overflow\n");
829 return device_tree_add_found(root
, prefix
, buf
);
832 device INLINE_DEVICE
*
833 device_tree_add_found_uw_u(device
*root
,
845 if (strlen(buf
) + 1 >= sizeof(buf
))
846 error("device_tree_add_found_* - buffer overflow\n");
847 return device_tree_add_found(root
, prefix
, buf
);
850 device INLINE_DEVICE
*
851 device_tree_add_found_uw_u_u(device
*root
,
866 if (strlen(buf
) + 1 >= sizeof(buf
))
867 error("device_tree_add_found_* - buffer overflow\n");
868 return device_tree_add_found(root
, prefix
, buf
);
871 device INLINE_DEVICE
*
872 device_tree_add_found_uw_u_u_c(device
*root
,
890 if (strlen(buf
) + 1 >= sizeof(buf
))
891 error("device_tree_add_found_* - buffer overflow\n");
892 return device_tree_add_found(root
, prefix
, buf
);
895 device INLINE_DEVICE
*
896 device_tree_add_found_uw_uw_u_u_c(device
*root
,
917 if (strlen(buf
) + 1 >= sizeof(buf
))
918 error("device_tree_add_found_* - buffer overflow\n");
919 return device_tree_add_found(root
, prefix
, buf
);
922 device INLINE_DEVICE
*
923 device_tree_add_found_uw_uw_u_u_u(device
*root
,
944 if (strlen(buf
) + 1 >= sizeof(buf
))
945 error("device_tree_add_found_* - buffer overflow\n");
946 return device_tree_add_found(root
, prefix
, buf
);
950 /* Parse a device name, various formats */
952 #define SCAN_INIT(NAME) \
953 char *START = (char*)0; \
954 char *END = (char*)0; \
956 /* find the first element */ \
957 END = strchr(NAME, '@'); \
958 if (END == (char*)0) \
968 *U = strtoul(START, &END, 0); \
979 *P = (void*)(unsigned)strtouq(START, END, 0); \
988 #define SCAN_C(C, SIZE) \
992 while (*END != '\0' && *END != ',') { \
998 if ((SIZE) <= ((END) - (START))) \
999 return COUNT; /* overflow */ \
1011 scand_c(const char *name
,
1021 scand_c_uw_u(const char *name
,
1035 scand_uw(const char *name
,
1044 scand_uw_c(const char *name
,
1056 scand_uw_u(const char *name
,
1067 scand_uw_u_u(const char *name
,
1080 scand_uw_u_u_c(const char *name
,
1096 scand_uw_uw(const char *name
,
1107 scand_uw_uw_u(const char *name
,
1120 scand_uw_uw_u_u_c(const char *name
,
1138 scand_uw_uw_u_u_u(const char *name
,
1155 #endif /* _DEVICE_C_ */