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_ */