Latest cagney update
[binutils-gdb.git] / sim / ppc / device.c
1 /* This file is part of the program psim.
2
3 Copyright (C) 1994-1995, Andrew Cagney <cagney@highland.com.au>
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"
28
29 #ifdef HAVE_STDLIB_H
30 #include <stdlib.h>
31 #endif
32
33 #ifdef HAVE_STRING_H
34 #include <string.h>
35 #else
36 #ifdef HAVE_STRINGS_H
37 #include <strings.h>
38 #endif
39 #endif
40
41 #include <ctype.h>
42
43
44
45 typedef struct _device_property_entry device_property_entry;
46 struct _device_property_entry {
47 const char *name;
48 device_property_entry *next;
49 device_property *value;
50 };
51
52
53 /* A device */
54 struct _device {
55 /* my name is ... */
56 const char *name;
57 const char *full_name;
58 /* device tree */
59 device *parent;
60 device *children;
61 device *sibling;
62 /* hw/sw callbacks */
63 void *data; /* device specific data */
64 const device_callbacks *callback;
65 /* device properties */
66 device_property_entry *properties;
67 };
68
69
70 INLINE_DEVICE\
71 (device *)
72 device_create(const char *name,
73 device *parent)
74 {
75 device_descriptor *descr;
76 int name_len;
77 char *chp;
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)
86 : NULL);
87 return device_create_from(name, data, descr->callbacks, parent);
88 }
89 }
90 error("device_create() unknown device %s\n", name);
91 return NULL;
92 }
93
94 INLINE_DEVICE\
95 (device *)
96 device_create_from(const char *name,
97 void *data,
98 const device_callbacks *callbacks,
99 device *parent)
100 {
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;
106 return new_device;
107 }
108
109
110 INLINE_DEVICE\
111 (device *)
112 device_parent(device *me)
113 {
114 return me->parent;
115 }
116
117 INLINE_DEVICE\
118 (device *)
119 device_sibling(device *me)
120 {
121 return me->sibling;
122 }
123
124 INLINE_DEVICE\
125 (device *)
126 device_child(device *me)
127 {
128 return me->children;
129 }
130
131 INLINE_DEVICE\
132 (const char *)
133 device_name(device *me)
134 {
135 return me->name;
136 }
137
138 INLINE_DEVICE\
139 (void *)
140 device_data(device *me)
141 {
142 return me->data;
143 }
144
145 INLINE_DEVICE\
146 (void)
147 device_traverse_properties(device *me,
148 device_traverse_property_function *traverse,
149 void *data)
150 {
151 device_property_entry *entry = me->properties;
152 while (entry != NULL) {
153 traverse(me, entry->name, data);
154 entry = entry->next;
155 }
156 }
157
158 INLINE_DEVICE\
159 (void)
160 device_init(device *me,
161 psim *system)
162 {
163 me->callback->init(me, system);
164 }
165
166 INLINE_DEVICE\
167 (void)
168 device_attach_address(device *me,
169 const char *name,
170 attach_type attach,
171 int space,
172 unsigned_word addr,
173 unsigned nr_bytes,
174 access_type access,
175 device *who) /*callback/default*/
176 {
177 me->callback->attach_address(me, name, attach, space,
178 addr, nr_bytes, access, who);
179 }
180
181 INLINE_DEVICE\
182 (void)
183 device_detach_address(device *me,
184 const char *name,
185 attach_type attach,
186 int space,
187 unsigned_word addr,
188 unsigned nr_bytes,
189 access_type access,
190 device *who) /*callback/default*/
191 {
192 me->callback->detach_address(me, name, attach, space,
193 addr, nr_bytes, access, who);
194 }
195
196 INLINE_DEVICE\
197 (unsigned)
198 device_io_read_buffer(device *me,
199 void *dest,
200 int space,
201 unsigned_word addr,
202 unsigned nr_bytes,
203 cpu *processor,
204 unsigned_word cia)
205 {
206 return me->callback->io_read_buffer(me, dest, space,
207 addr, nr_bytes,
208 processor, cia);
209 }
210
211 INLINE_DEVICE\
212 (unsigned)
213 device_io_write_buffer(device *me,
214 const void *source,
215 int space,
216 unsigned_word addr,
217 unsigned nr_bytes,
218 cpu *processor,
219 unsigned_word cia)
220 {
221 return me->callback->io_write_buffer(me, source, space,
222 addr, nr_bytes,
223 processor, cia);
224 }
225
226 INLINE_DEVICE\
227 (unsigned)
228 device_dma_read_buffer(device *me,
229 void *dest,
230 int space,
231 unsigned_word addr,
232 unsigned nr_bytes)
233 {
234 return me->callback->dma_read_buffer(me, dest, space,
235 addr, nr_bytes);
236 }
237
238 INLINE_DEVICE\
239 (unsigned)
240 device_dma_write_buffer(device *me,
241 const void *source,
242 int space,
243 unsigned_word addr,
244 unsigned nr_bytes,
245 int violate_read_only_section)
246 {
247 return me->callback->dma_write_buffer(me, source, space,
248 addr, nr_bytes,
249 violate_read_only_section);
250 }
251
252 INLINE_DEVICE\
253 (void)
254 device_attach_interrupt(device *me,
255 device *who,
256 int interrupt_line,
257 const char *name)
258 {
259 me->callback->attach_interrupt(me, who, interrupt_line, name);
260 }
261
262 INLINE_DEVICE\
263 (void)
264 device_detach_interrupt(device *me,
265 device *who,
266 int interrupt_line,
267 const char *name)
268 {
269 me->callback->detach_interrupt(me, who, interrupt_line, name);
270 }
271
272 INLINE_DEVICE\
273 (void)
274 device_interrupt(device *me,
275 device *who,
276 int interrupt_line,
277 int interrupt_status,
278 cpu *processor,
279 unsigned_word cia)
280 {
281 me->callback->interrupt(me, who, interrupt_line, interrupt_status,
282 processor, cia);
283 }
284
285 INLINE_DEVICE\
286 (void)
287 device_interrupt_ack(device *me,
288 int interrupt_line,
289 int interrupt_status)
290 {
291 me->callback->interrupt_ack(me, interrupt_line, interrupt_status);
292 }
293
294 EXTERN_DEVICE\
295 (void)
296 device_ioctl(device *me,
297 psim *system,
298 cpu *processor,
299 unsigned_word cia,
300 ...)
301 {
302 va_list ap;
303 va_start(ap, cia);
304 me->callback->ioctl(me, system, processor, cia, ap);
305 va_end(ap);
306 }
307
308
309 /* Manipulate properties attached to devices */
310
311 STATIC_INLINE_DEVICE\
312 (device_property *)
313 device_add_property(device *me,
314 const char *property,
315 device_property_type type,
316 const void *array,
317 int sizeof_array)
318 {
319 device_property_entry *new_entry = 0;
320 device_property *new_value = 0;
321 void *new_array = 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;
328 }
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)
334 : (void*)0);
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);
344 return new_value;
345 }
346
347 INLINE_DEVICE\
348 (void)
349 device_add_array_property(device *me,
350 const char *property,
351 const void *array,
352 int sizeof_array)
353 {
354 TRACE(trace_devices,
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);
359 }
360
361 INLINE_DEVICE\
362 (void)
363 device_add_integer_property(device *me,
364 const char *property,
365 signed32 integer)
366 {
367 TRACE(trace_devices,
368 ("device_add_integer_property(me=0x%lx, property=%s, integer=%ld)\n",
369 (long)me, property, (long)integer));
370 H2BE(integer);
371 device_add_property(me, property, integer_property,
372 &integer, sizeof(integer));
373 }
374
375 INLINE_DEVICE\
376 (void)
377 device_add_boolean_property(device *me,
378 const char *property,
379 int boolean)
380 {
381 signed32 new_boolean = (boolean ? -1 : 0);
382 TRACE(trace_devices,
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));
387 }
388
389 INLINE_DEVICE\
390 (void)
391 device_add_null_property(device *me,
392 const char *property)
393 {
394 TRACE(trace_devices,
395 ("device_add_null(me=0x%lx, property=%s)\n",
396 (long)me, property));
397 device_add_property(me, property, null_property,
398 NULL, 0);
399 }
400
401 INLINE_DEVICE\
402 (void)
403 device_add_string_property(device *me,
404 const char *property,
405 const char *string)
406 {
407
408 TRACE(trace_devices,
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);
413 }
414
415 INLINE_DEVICE\
416 (const device_property *)
417 device_find_property(device *me,
418 const char *property)
419 {
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)
424 return entry->value;
425 entry = entry->next;
426 }
427 }
428 return (device_property*)0;
429 }
430
431 INLINE_DEVICE\
432 (const char *)
433 device_find_next_property(device *me,
434 const char *property)
435 {
436 if (me != NULL) {
437 if (property == NULL || strcmp(property, "") == 0) {
438 return (me->properties != NULL
439 ? me->properties->name
440 : NULL);
441 }
442 else {
443 device_property_entry *entry = me->properties;
444 while (entry != NULL) {
445 if (strcmp(entry->name, property) == 0)
446 return (entry->next != NULL
447 ? entry->next->name
448 : NULL);
449 entry = entry->next;
450 }
451 }
452 }
453 return NULL;
454 }
455
456 INLINE_DEVICE\
457 (const device_property *)
458 device_find_array_property(device *me,
459 const char *property)
460 {
461 const device_property *node;
462 TRACE(trace_devices,
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",
469 me->name, property);
470 return node;
471 }
472
473 INLINE_DEVICE\
474 (signed_word)
475 device_find_integer_property(device *me,
476 const char *property)
477 {
478 const device_property *node;
479 signed32 integer;
480 TRACE(trace_devices,
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",
487 me->name, property);
488 ASSERT(sizeof(integer) == node->sizeof_array);
489 memcpy(&integer, node->array, sizeof(integer));
490 BE2H(integer);
491 return integer;
492 }
493
494 INLINE_DEVICE\
495 (int)
496 device_find_boolean_property(device *me,
497 const char *property)
498 {
499 const device_property *node;
500 unsigned32 boolean;
501 TRACE(trace_devices,
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",
508 me->name, property);
509 ASSERT(sizeof(boolean) == node->sizeof_array);
510 memcpy(&boolean, node->array, sizeof(boolean));
511 return boolean;
512 }
513
514 INLINE_DEVICE\
515 (const char *)
516 device_find_string_property(device *me,
517 const char *property)
518 {
519 const device_property *node;
520 const char *string;
521 TRACE(trace_devices,
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",
528 me->name, property);
529 string = node->array;
530 ASSERT(strlen(string) + 1 == node->sizeof_array);
531 return string;
532 }
533
534
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\
538 (const char *)
539 device_tree_full_name(device *leaf,
540 char *buf,
541 unsigned sizeof_buf)
542 {
543 /* get a buffer */
544 char full_name[1024];
545 if (buf == (char*)0) {
546 buf = full_name;
547 sizeof_buf = sizeof(full_name);
548 }
549
550 /* construct a name */
551 if (leaf->parent == NULL) {
552 if (sizeof_buf < 1)
553 error("device_full_name() buffer overflow\n");
554 *buf = '\0';
555 }
556 else {
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");
560 strcat(buf, "/");
561 strcat(buf, leaf->name);
562 }
563
564 /* return it usefully */
565 if (buf == full_name)
566 buf = strdup(full_name);
567 return buf;
568 }
569
570
571 /* find/create a node in the device tree */
572
573 typedef enum {
574 device_tree_return_null = 2,
575 device_tree_abort = 3,
576 } device_tree_action;
577
578 STATIC_INLINE_DEVICE\
579 (device *)
580 device_tree_find_node(device *root,
581 const char *path,
582 const char *full_path,
583 device_tree_action action)
584 {
585 const char *name;
586 int strlen_name;
587 device *child;
588
589 /* strip off any leading `/', `../' or `./' */
590 while (1) {
591 if (strncmp(path, "/", strlen("/")) == 0) {
592 while (root != NULL && root->parent != NULL)
593 root = root->parent;
594 path += strlen("/");
595 }
596 else if (strncmp(path, "./", strlen("./")) == 0) {
597 root = root;
598 path += strlen("./");
599 }
600 else if (strncmp(path, "../", strlen("../")) == 0) {
601 if (root != NULL && root->parent != NULL)
602 root = root->parent;
603 path += strlen("../");
604 }
605 else {
606 break;
607 }
608 }
609
610 /* parse the driver_name/unit-address */
611 ASSERT(*path != '/');
612 name = path;
613 while (isalnum(*path)
614 || *path == ',' || *path == ',' || *path == '_'
615 || *path == '+' || *path == '-')
616 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);
620
621 /* parse the unit-address */
622 if (*path == '@') {
623 path++;
624 while ((*path != '\0' && *path != ':' && *path != '/')
625 || (*path == ':' && path[-1] == '\\')
626 || (*path == '/' && path[-1] == '\\'))
627 path++;
628 }
629 strlen_name = path - name;
630
631 /* skip the device-arguments */
632 if (*path == ':') {
633 path++;
634 while ((*path != '\0' && *path != '/' && *path != ':' && *path != '@')
635 || (*path == '/' && path[-1] == '\\')
636 || (*path == ':' && path[-1] == '\\')
637 || (*path == '@' && path[-1] == '\\'))
638 path++;
639 }
640
641 /* sanity checks */
642 if (*path != '\0' && *path != '/')
643 error("device_tree: path %s invalid at %s\n", full_path, path);
644
645 /* leaf? and growing? */
646 if (name[0] == '\0') {
647 return root;
648 }
649 else if (root != NULL) {
650 for (child = root->children;
651 child != NULL;
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] == '@')) {
657 if (*path == '\0')
658 return child;
659 else
660 return device_tree_find_node(child,
661 path + 1/* / */,
662 full_path,
663 action);
664 }
665 }
666 }
667
668 /* search failed, take default action */
669 switch (action) {
670 case device_tree_return_null:
671 return NULL;
672 case device_tree_abort:
673 error("device_tree_find_node() could not find %s in tree\n",
674 full_path);
675 return NULL;
676 default:
677 error("device_tree_find_node() invalid default action %d\n", action);
678 return NULL;
679 }
680 }
681
682
683 /* grow the device tree */
684
685 INLINE_DEVICE\
686 (device *)
687 device_tree_add_device(device *root,
688 const char *prefix,
689 device *new_sub_tree)
690 {
691 device *parent;
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));
695
696 /* find our parent */
697 parent = device_tree_find_node(root,
698 prefix,
699 prefix, /* full-path */
700 device_tree_abort);
701
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;
709 }
710
711 return new_sub_tree;
712 }
713
714 INLINE_DEVICE\
715 (device *)
716 device_tree_find_device(device *root,
717 const char *path)
718 {
719 device *node;
720 TRACE(trace_device_tree,
721 ("device_tree_find_device_tree(root=0x%lx, path=%s)\n",
722 (long)root, path));
723 node = device_tree_find_node(root,
724 path,
725 path, /* full-name */
726 device_tree_return_null);
727 return node;
728 }
729
730
731 /* init all the devices */
732
733 STATIC_INLINE_DEVICE\
734 (void)
735 device_tree_init_device(device *root,
736 void *data)
737 {
738 psim *system;
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);
744 }
745
746
747 INLINE_DEVICE\
748 (void)
749 device_tree_init(device *root,
750 psim *system)
751 {
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"));
757 }
758
759
760 /* traverse a device tree applying prefix/postfix functions to it */
761
762 INLINE_DEVICE\
763 (void)
764 device_tree_traverse(device *root,
765 device_tree_traverse_function *prefix,
766 device_tree_traverse_function *postfix,
767 void *data)
768 {
769 device *child;
770 if (prefix != NULL)
771 prefix(root, data);
772 for (child = root->children; child != NULL; child = child->sibling) {
773 device_tree_traverse(child, prefix, postfix, data);
774 }
775 if (postfix != NULL)
776 postfix(root, data);
777 }
778
779
780 /* dump out a device node and addresses */
781
782 INLINE_DEVICE\
783 (void)
784 device_tree_dump(device *device,
785 void *ignore_data_argument)
786 {
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");
794 }
795
796
797 /* lookup/create a device various formats */
798
799 STATIC_INLINE_DEVICE\
800 (void)
801 u_strcat(char *buf,
802 unsigned_word uw)
803 {
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);
808 }
809 else {
810 char *end = strchr(buf, '\0');
811 sprintf(end, "0x%x%08x",
812 (unsigned)EXTRACTED64(uw, 0, 31),
813 (unsigned)EXTRACTED64(uw, 32, 63));
814 }
815 }
816
817 STATIC_INLINE_DEVICE\
818 (void)
819 c_strcat(char *buf,
820 const char *c)
821 {
822 char *end = strchr(buf, '\0');
823 while (*c) {
824 if (*c == '/' || *c == ',')
825 *end++ = '\\';
826 *end++ = *c++;
827 }
828 *end = '\0';
829 }
830
831 INLINE_DEVICE\
832 (device *)
833 device_tree_add_found(device *root,
834 const char *prefix,
835 const char *name)
836 {
837 device *parent;
838 device *new_device;
839 device *new_node;
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,
844 device_tree_abort);
845 new_device = device_tree_find_device(parent, name);
846 if (new_device != NULL)
847 return new_device;
848 else {
849 new_device = device_create(name, parent);
850 new_node = device_tree_add_device(parent, "", new_device);
851 ASSERT(new_device == new_node);
852 return new_node;
853 }
854 }
855
856 INLINE_DEVICE\
857 (device *)
858 device_tree_add_found_c(device *root,
859 const char *prefix,
860 const char *name,
861 const char *c1)
862 {
863 char buf[1024];
864 strcpy(buf, name);
865 strcat(buf, "@");
866 c_strcat(buf, c1);
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);
870 }
871
872 INLINE_DEVICE\
873 (device *)
874 device_tree_add_found_c_uw(device *root,
875 const char *prefix,
876 const char *name,
877 const char *c1,
878 unsigned_word uw2)
879 {
880 char buf[1024];
881 strcpy(buf, name);
882 strcat(buf, "@");
883 c_strcat(buf, c1);
884 strcat(buf, ",");
885 u_strcat(buf, uw2);
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);
889 }
890
891 INLINE_DEVICE\
892 (device *)
893 device_tree_add_found_uw_u(device *root,
894 const char *prefix,
895 const char *name,
896 unsigned_word uw1,
897 unsigned u2)
898 {
899 char buf[1024];
900 strcpy(buf, name);
901 strcat(buf, "@");
902 u_strcat(buf, uw1);
903 strcat(buf, ",");
904 u_strcat(buf, u2);
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);
908 }
909
910 INLINE_DEVICE\
911 (device *)
912 device_tree_add_found_uw_u_u(device *root,
913 const char *prefix,
914 const char *name,
915 unsigned_word uw1,
916 unsigned u2,
917 unsigned u3)
918 {
919 char buf[1024];
920 strcpy(buf, name);
921 strcat(buf, "@");
922 u_strcat(buf, uw1);
923 strcat(buf, ",");
924 u_strcat(buf, u2);
925 strcat(buf, ",");
926 u_strcat(buf, u3);
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);
930 }
931
932 INLINE_DEVICE\
933 (device *)
934 device_tree_add_found_uw_u_u_c(device *root,
935 const char *prefix,
936 const char *name,
937 unsigned_word uw1,
938 unsigned u2,
939 unsigned u3,
940 const char *c4)
941 {
942 char buf[1024];
943 strcpy(buf, name);
944 strcat(buf, "@");
945 u_strcat(buf, uw1);
946 strcat(buf, ",");
947 u_strcat(buf, u2);
948 strcat(buf, ",");
949 u_strcat(buf, u3);
950 strcat(buf, ",");
951 c_strcat(buf, c4);
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);
955 }
956
957 INLINE_DEVICE\
958 (device *)
959 device_tree_add_found_uw_uw_u_u_c(device *root,
960 const char *prefix,
961 const char *name,
962 unsigned_word uw1,
963 unsigned_word uw2,
964 unsigned u3,
965 unsigned u4,
966 const char *c5)
967 {
968 char buf[1024];
969 strcpy(buf, name);
970 strcat(buf, "@");
971 u_strcat(buf, uw1);
972 strcat(buf, ",");
973 u_strcat(buf, uw2);
974 strcat(buf, ",");
975 u_strcat(buf, u3);
976 strcat(buf, ",");
977 u_strcat(buf, u4);
978 strcat(buf, ",");
979 c_strcat(buf, c5);
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);
983 }
984
985 INLINE_DEVICE\
986 (device *)
987 device_tree_add_found_uw_uw_u_u_u(device *root,
988 const char *prefix,
989 const char *name,
990 unsigned_word uw1,
991 unsigned_word uw2,
992 unsigned u3,
993 unsigned u4,
994 unsigned u5)
995 {
996 char buf[1024];
997 strcpy(buf, name);
998 strcat(buf, "@");
999 u_strcat(buf, uw1);
1000 strcat(buf, ",");
1001 u_strcat(buf, uw2);
1002 strcat(buf, ",");
1003 u_strcat(buf, u3);
1004 strcat(buf, ",");
1005 u_strcat(buf, u4);
1006 strcat(buf, ",");
1007 u_strcat(buf, u5);
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);
1011 }
1012
1013
1014 /* Parse a device name, various formats */
1015
1016 #define SCAN_INIT(NAME) \
1017 char *START = (char*)0; \
1018 char *END = (char*)0; \
1019 int COUNT = -1; \
1020 /* find the first element */ \
1021 END = strchr(NAME, '@'); \
1022 if (END == (char*)0) \
1023 return COUNT; \
1024 COUNT += 1; \
1025 START = END + 1
1026
1027 #define SCAN_END \
1028 return COUNT
1029
1030 #define SCAN_U(U) \
1031 do { \
1032 *U = strtoul(START, &END, 0); \
1033 if (START == END) \
1034 return COUNT; \
1035 COUNT += 1; \
1036 if (*END != ',') \
1037 return COUNT; \
1038 START = END + 1; \
1039 } while (0)
1040
1041 #define SCAN_P(P) \
1042 do { \
1043 *P = (void*)(unsigned)strtouq(START, END, 0); \
1044 if (START == END) \
1045 return COUNT; \
1046 COUNT += 1; \
1047 if (*END != ',') \
1048 return COUNT; \
1049 START = END + 1; \
1050 } while (0)
1051
1052 #define SCAN_C(C, SIZE) \
1053 do { \
1054 char *chp = C; \
1055 END = START; \
1056 while (*END != '\0' && *END != ',') { \
1057 if (*END == '\\') \
1058 END += 1; \
1059 *chp = *END; \
1060 chp += 1; \
1061 END += 1; \
1062 if ((SIZE) <= ((END) - (START))) \
1063 return COUNT; /* overflow */ \
1064 } \
1065 *chp = '\0'; \
1066 if (START == END) \
1067 return COUNT; \
1068 COUNT += 1; \
1069 if (*END != ',') \
1070 return COUNT; \
1071 START = END + 1; \
1072 } while (0)
1073
1074 INLINE_DEVICE\
1075 (int)
1076 scand_c(const char *name,
1077 char *c1,
1078 unsigned c1size)
1079 {
1080 SCAN_INIT(name);
1081 SCAN_C(c1, c1size);
1082 SCAN_END;
1083 }
1084
1085 INLINE_DEVICE\
1086 (int)
1087 scand_c_uw_u(const char *name,
1088 char *c1,
1089 unsigned c1size,
1090 unsigned_word *uw2,
1091 unsigned *u3)
1092 {
1093 SCAN_INIT(name);
1094 SCAN_C(c1, c1size);
1095 SCAN_U(uw2);
1096 SCAN_U(u3);
1097 SCAN_END;
1098 }
1099
1100 INLINE_DEVICE\
1101 (int)
1102 scand_uw(const char *name,
1103 unsigned_word *uw1)
1104 {
1105 SCAN_INIT(name);
1106 SCAN_U(uw1);
1107 SCAN_END;
1108 }
1109
1110 INLINE_DEVICE\
1111 (int)
1112 scand_uw_c(const char *name,
1113 unsigned_word *uw1,
1114 char *c2,
1115 unsigned c2size)
1116 {
1117 SCAN_INIT(name);
1118 SCAN_U(uw1);
1119 SCAN_C(c2, c2size);
1120 SCAN_END;
1121 }
1122
1123 INLINE_DEVICE\
1124 (int)
1125 scand_uw_u(const char *name,
1126 unsigned_word *uw1,
1127 unsigned *u2)
1128 {
1129 SCAN_INIT(name);
1130 SCAN_U(uw1);
1131 SCAN_U(u2);
1132 SCAN_END;
1133 }
1134
1135 INLINE_DEVICE\
1136 (int)
1137 scand_uw_u_u(const char *name,
1138 unsigned_word *uw1,
1139 unsigned *u2,
1140 unsigned *u3)
1141 {
1142 SCAN_INIT(name);
1143 SCAN_U(uw1);
1144 SCAN_U(u2);
1145 SCAN_U(u3);
1146 SCAN_END;
1147 }
1148
1149 INLINE_DEVICE\
1150 (int)
1151 scand_uw_u_u_c(const char *name,
1152 unsigned_word *uw1,
1153 unsigned *u2,
1154 unsigned *u3,
1155 char *c4,
1156 unsigned c4size)
1157 {
1158 SCAN_INIT(name);
1159 SCAN_U(uw1);
1160 SCAN_U(u2);
1161 SCAN_U(u3);
1162 SCAN_C(c4, c4size);
1163 SCAN_END;
1164 }
1165
1166 INLINE_DEVICE\
1167 (int)
1168 scand_uw_uw(const char *name,
1169 unsigned_word *uw1,
1170 unsigned_word *uw2)
1171 {
1172 SCAN_INIT(name);
1173 SCAN_U(uw1);
1174 SCAN_U(uw2);
1175 SCAN_END;
1176 }
1177
1178 INLINE_DEVICE\
1179 (int)
1180 scand_uw_uw_u(const char *name,
1181 unsigned_word *uw1,
1182 unsigned_word *uw2,
1183 unsigned *u3)
1184 {
1185 SCAN_INIT(name);
1186 SCAN_U(uw1);
1187 SCAN_U(uw2);
1188 SCAN_U(u3);
1189 SCAN_END;
1190 }
1191
1192 INLINE_DEVICE\
1193 (int)
1194 scand_uw_uw_u_u_c(const char *name,
1195 unsigned_word *uw1,
1196 unsigned_word *uw2,
1197 unsigned *u3,
1198 unsigned *u4,
1199 char *c5,
1200 unsigned c5size)
1201 {
1202 SCAN_INIT(name);
1203 SCAN_U(uw1);
1204 SCAN_U(uw2);
1205 SCAN_U(u3);
1206 SCAN_U(u4);
1207 SCAN_C(c5, c5size);
1208 SCAN_END;
1209 }
1210
1211 INLINE_DEVICE\
1212 (int)
1213 scand_uw_uw_u_u_u(const char *name,
1214 unsigned_word *uw1,
1215 unsigned_word *uw2,
1216 unsigned *u3,
1217 unsigned *u4,
1218 unsigned *u5)
1219 {
1220 SCAN_INIT(name);
1221 SCAN_U(uw1);
1222 SCAN_U(uw2);
1223 SCAN_U(u3);
1224 SCAN_U(u4);
1225 SCAN_U(u5);
1226 SCAN_END;
1227 }
1228
1229
1230 #endif /* _DEVICE_C_ */