Changes from Andrew
[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 device INLINE_DEVICE *
71 device_create(const char *name,
72 device *parent)
73 {
74 device_descriptor *descr;
75 int name_len;
76 char *chp;
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)
85 : NULL);
86 return device_create_from(name, data, descr->callbacks, parent);
87 }
88 }
89 error("device_create() unknown device %s\n", name);
90 return NULL;
91 }
92
93 device INLINE_DEVICE *
94 device_create_from(const char *name,
95 void *data,
96 const device_callbacks *callbacks,
97 device *parent)
98 {
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;
104 return new_device;
105 }
106
107
108 device INLINE_DEVICE *
109 device_parent(device *me)
110 {
111 return me->parent;
112 }
113
114 const char INLINE_DEVICE *
115 device_name(device *me)
116 {
117 return me->name;
118 }
119
120 void INLINE_DEVICE *
121 device_data(device *me)
122 {
123 return me->data;
124 }
125
126 void INLINE_DEVICE
127 device_traverse_properties(device *me,
128 device_traverse_property_function *traverse,
129 void *data)
130 {
131 device_property_entry *entry = me->properties;
132 while (entry != NULL) {
133 traverse(me, entry->name, data);
134 entry = entry->next;
135 }
136 }
137
138 void INLINE_DEVICE
139 device_init(device *me,
140 psim *system)
141 {
142 me->callback->init(me, system);
143 }
144
145 void INLINE_DEVICE
146 device_attach_address(device *me,
147 const char *name,
148 attach_type attach,
149 int space,
150 unsigned_word addr,
151 unsigned nr_bytes,
152 access_type access,
153 device *who) /*callback/default*/
154 {
155 me->callback->attach_address(me, name, attach, space,
156 addr, nr_bytes, access, who);
157 }
158
159 void INLINE_DEVICE
160 device_detach_address(device *me,
161 const char *name,
162 attach_type attach,
163 int space,
164 unsigned_word addr,
165 unsigned nr_bytes,
166 access_type access,
167 device *who) /*callback/default*/
168 {
169 me->callback->detach_address(me, name, attach, space,
170 addr, nr_bytes, access, who);
171 }
172
173 unsigned INLINE_DEVICE
174 device_io_read_buffer(device *me,
175 void *dest,
176 int space,
177 unsigned_word addr,
178 unsigned nr_bytes,
179 cpu *processor,
180 unsigned_word cia)
181 {
182 return me->callback->io_read_buffer(me, dest, space,
183 addr, nr_bytes,
184 processor, cia);
185 }
186
187 unsigned INLINE_DEVICE
188 device_io_write_buffer(device *me,
189 const void *source,
190 int space,
191 unsigned_word addr,
192 unsigned nr_bytes,
193 cpu *processor,
194 unsigned_word cia)
195 {
196 return me->callback->io_write_buffer(me, source, space,
197 addr, nr_bytes,
198 processor, cia);
199 }
200
201 unsigned INLINE_DEVICE
202 device_dma_read_buffer(device *me,
203 void *dest,
204 int space,
205 unsigned_word addr,
206 unsigned nr_bytes)
207 {
208 return me->callback->dma_read_buffer(me, dest, space,
209 addr, nr_bytes);
210 }
211
212 unsigned INLINE_DEVICE
213 device_dma_write_buffer(device *me,
214 const void *source,
215 int space,
216 unsigned_word addr,
217 unsigned nr_bytes,
218 int violate_read_only_section)
219 {
220 return me->callback->dma_write_buffer(me, source, space,
221 addr, nr_bytes,
222 violate_read_only_section);
223 }
224
225 void INLINE_DEVICE
226 device_attach_interrupt(device *me,
227 device *who,
228 int interrupt_line,
229 const char *name)
230 {
231 me->callback->attach_interrupt(me, who, interrupt_line, name);
232 }
233
234 void INLINE_DEVICE
235 device_detach_interrupt(device *me,
236 device *who,
237 int interrupt_line,
238 const char *name)
239 {
240 me->callback->detach_interrupt(me, who, interrupt_line, name);
241 }
242
243 void INLINE_DEVICE
244 device_interrupt(device *me,
245 device *who,
246 int interrupt_line,
247 int interrupt_status,
248 cpu *processor,
249 unsigned_word cia)
250 {
251 me->callback->interrupt(me, who, interrupt_line, interrupt_status,
252 processor, cia);
253 }
254
255 void INLINE_DEVICE
256 device_interrupt_ack(device *me,
257 int interrupt_line,
258 int interrupt_status)
259 {
260 me->callback->interrupt_ack(me, interrupt_line, interrupt_status);
261 }
262
263 void EXTERN_DEVICE
264 device_ioctl(device *me,
265 psim *system,
266 cpu *processor,
267 unsigned_word cia,
268 ...)
269 {
270 va_list ap;
271 va_start(ap, cia);
272 me->callback->ioctl(me, system, processor, cia, ap);
273 va_end(ap);
274 }
275
276
277 /* Manipulate properties attached to devices */
278
279 device_property STATIC_INLINE_DEVICE *
280 device_add_property(device *me,
281 const char *property,
282 device_property_type type,
283 const void *array,
284 int sizeof_array)
285 {
286 device_property_entry *new_entry = 0;
287 device_property *new_value = 0;
288 void *new_array = 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;
295 }
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)
301 : (void*)0);
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);
311 return new_value;
312 }
313
314 void INLINE_DEVICE
315 device_add_array_property(device *me,
316 const char *property,
317 const void *array,
318 int sizeof_array)
319 {
320 TRACE(trace_devices,
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);
325 }
326
327 void INLINE_DEVICE
328 device_add_integer_property(device *me,
329 const char *property,
330 signed32 integer)
331 {
332 TRACE(trace_devices,
333 ("device_add_integer_property(me=0x%lx, property=%s, integer=%ld)\n",
334 (long)me, property, (long)integer));
335 H2BE(integer);
336 device_add_property(me, property, integer_property,
337 &integer, sizeof(integer));
338 }
339
340 void INLINE_DEVICE
341 device_add_boolean_property(device *me,
342 const char *property,
343 int boolean)
344 {
345 signed32 new_boolean = (boolean ? -1 : 0);
346 TRACE(trace_devices,
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));
351 }
352
353 void INLINE_DEVICE
354 device_add_null_property(device *me,
355 const char *property)
356 {
357 TRACE(trace_devices,
358 ("device_add_null(me=0x%lx, property=%s)\n",
359 (long)me, property));
360 device_add_property(me, property, null_property,
361 NULL, 0);
362 }
363
364 void INLINE_DEVICE
365 device_add_string_property(device *me,
366 const char *property,
367 const char *string)
368 {
369
370 TRACE(trace_devices,
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);
375 }
376
377 const device_property INLINE_DEVICE *
378 device_find_property(device *me,
379 const char *property)
380 {
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)
385 return entry->value;
386 entry = entry->next;
387 }
388 }
389 return (device_property*)0;
390 }
391
392 const char INLINE_DEVICE *
393 device_find_next_property(device *me,
394 const char *property)
395 {
396 if (me != NULL) {
397 if (property == NULL || strcmp(property, "") == 0) {
398 return (me->properties != NULL
399 ? me->properties->name
400 : NULL);
401 }
402 else {
403 device_property_entry *entry = me->properties;
404 while (entry != NULL) {
405 if (strcmp(entry->name, property) == 0)
406 return (entry->next != NULL
407 ? entry->next->name
408 : NULL);
409 entry = entry->next;
410 }
411 }
412 }
413 return NULL;
414 }
415
416 const device_property INLINE_DEVICE *
417 device_find_array_property(device *me,
418 const char *property)
419 {
420 const device_property *node;
421 TRACE(trace_devices,
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",
428 me->name, property);
429 return node;
430 }
431
432 signed_word INLINE_DEVICE
433 device_find_integer_property(device *me,
434 const char *property)
435 {
436 const device_property *node;
437 signed32 integer;
438 TRACE(trace_devices,
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",
445 me->name, property);
446 ASSERT(sizeof(integer) == node->sizeof_array);
447 memcpy(&integer, node->array, sizeof(integer));
448 BE2H(integer);
449 return integer;
450 }
451
452 int INLINE_DEVICE
453 device_find_boolean_property(device *me,
454 const char *property)
455 {
456 const device_property *node;
457 unsigned32 boolean;
458 TRACE(trace_devices,
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",
465 me->name, property);
466 ASSERT(sizeof(boolean) == node->sizeof_array);
467 memcpy(&boolean, node->array, sizeof(boolean));
468 return boolean;
469 }
470
471 const char INLINE_DEVICE *
472 device_find_string_property(device *me,
473 const char *property)
474 {
475 const device_property *node;
476 const char *string;
477 TRACE(trace_devices,
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",
484 me->name, property);
485 string = node->array;
486 ASSERT(strlen(string) + 1 == node->sizeof_array);
487 return string;
488 }
489
490
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,
495 char *buf,
496 unsigned sizeof_buf)
497 {
498 /* get a buffer */
499 char full_name[1024];
500 if (buf == (char*)0) {
501 buf = full_name;
502 sizeof_buf = sizeof(full_name);
503 }
504
505 /* construct a name */
506 if (leaf->parent == NULL) {
507 if (sizeof_buf < 1)
508 error("device_full_name() buffer overflow\n");
509 *buf = '\0';
510 }
511 else {
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");
515 strcat(buf, "/");
516 strcat(buf, leaf->name);
517 }
518
519 /* return it usefully */
520 if (buf == full_name)
521 buf = strdup(full_name);
522 return buf;
523 }
524
525
526 /* find/create a node in the device tree */
527
528 typedef enum {
529 device_tree_return_null = 2,
530 device_tree_abort = 3,
531 } device_tree_action;
532
533 device STATIC_INLINE_DEVICE *
534 device_tree_find_node(device *root,
535 const char *path,
536 const char *full_path,
537 device_tree_action action)
538 {
539 const char *name;
540 int strlen_name;
541 device *child;
542
543 /* strip off any leading `/', `../' or `./' */
544 while (1) {
545 if (strncmp(path, "/", strlen("/")) == 0) {
546 while (root != NULL && root->parent != NULL)
547 root = root->parent;
548 path += strlen("/");
549 }
550 else if (strncmp(path, "./", strlen("./")) == 0) {
551 root = root;
552 path += strlen("./");
553 }
554 else if (strncmp(path, "../", strlen("../")) == 0) {
555 if (root != NULL && root->parent != NULL)
556 root = root->parent;
557 path += strlen("../");
558 }
559 else {
560 break;
561 }
562 }
563
564 /* parse the driver_name/unit-address */
565 ASSERT(*path != '/');
566 name = path;
567 while (isalnum(*path)
568 || *path == ',' || *path == ',' || *path == '_'
569 || *path == '+' || *path == '-')
570 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);
574
575 /* parse the unit-address */
576 if (*path == '@') {
577 path++;
578 while ((*path != '\0' && *path != ':' && *path != '/')
579 || (*path == ':' && path[-1] == '\\')
580 || (*path == '/' && path[-1] == '\\'))
581 path++;
582 }
583 strlen_name = path - name;
584
585 /* skip the device-arguments */
586 if (*path == ':') {
587 path++;
588 while ((*path != '\0' && *path != '/' && *path != ':' && *path != '@')
589 || (*path == '/' && path[-1] == '\\')
590 || (*path == ':' && path[-1] == '\\')
591 || (*path == '@' && path[-1] == '\\'))
592 path++;
593 }
594
595 /* sanity checks */
596 if (*path != '\0' && *path != '/')
597 error("device_tree: path %s invalid at %s\n", full_path, path);
598
599 /* leaf? and growing? */
600 if (name[0] == '\0') {
601 return root;
602 }
603 else if (root != NULL) {
604 for (child = root->children;
605 child != NULL;
606 child = child->sibling) {
607 if (strncmp(name, child->name, strlen_name) == 0
608 && strlen(child->name) == strlen_name) {
609 if (*path == '\0')
610 return child;
611 else
612 return device_tree_find_node(child,
613 path + 1/* / */,
614 full_path,
615 action);
616 }
617 }
618 }
619
620 /* search failed, take default action */
621 switch (action) {
622 case device_tree_return_null:
623 return NULL;
624 case device_tree_abort:
625 error("device_tree_find_node() could not find %s in tree\n",
626 full_path);
627 return NULL;
628 default:
629 error("device_tree_find_node() invalid default action %d\n", action);
630 return NULL;
631 }
632 }
633
634
635 /* grow the device tree */
636
637 device INLINE_DEVICE *
638 device_tree_add_device(device *root,
639 const char *prefix,
640 device *new_sub_tree)
641 {
642 device *parent;
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));
646
647 /* find our parent */
648 parent = device_tree_find_node(root,
649 prefix,
650 prefix, /* full-path */
651 device_tree_abort);
652
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;
660 }
661
662 return new_sub_tree;
663 }
664
665 device INLINE_DEVICE *
666 device_tree_find_device(device *root,
667 const char *path)
668 {
669 device *node;
670 TRACE(trace_device_tree,
671 ("device_tree_find_device_tree(root=0x%lx, path=%s)\n",
672 (long)root, path));
673 node = device_tree_find_node(root,
674 path,
675 path, /* full-name */
676 device_tree_return_null);
677 return node;
678 }
679
680
681 /* init all the devices */
682
683 void STATIC_INLINE_DEVICE
684 device_tree_init_device(device *root,
685 void *data)
686 {
687 psim *system;
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);
693 }
694
695
696 void INLINE_DEVICE
697 device_tree_init(device *root,
698 psim *system)
699 {
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"));
705 }
706
707
708 /* traverse a device tree applying prefix/postfix functions to it */
709
710 void INLINE_DEVICE
711 device_tree_traverse(device *root,
712 device_tree_traverse_function *prefix,
713 device_tree_traverse_function *postfix,
714 void *data)
715 {
716 device *child;
717 if (prefix != NULL)
718 prefix(root, data);
719 for (child = root->children; child != NULL; child = child->sibling) {
720 device_tree_traverse(child, prefix, postfix, data);
721 }
722 if (postfix != NULL)
723 postfix(root, data);
724 }
725
726
727 /* dump out a device node and addresses */
728
729 void INLINE_DEVICE
730 device_tree_dump(device *device,
731 void *ignore_data_argument)
732 {
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");
740 }
741
742
743 /* lookup/create a device various formats */
744
745 void STATIC_INLINE_DEVICE
746 u_strcat(char *buf,
747 unsigned_word uw)
748 {
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);
753 }
754 else {
755 char *end = strchr(buf, '\0');
756 sprintf(end, "0x%x%08x",
757 (unsigned)EXTRACTED64(uw, 0, 31),
758 (unsigned)EXTRACTED64(uw, 32, 63));
759 }
760 }
761
762 void STATIC_INLINE_DEVICE
763 c_strcat(char *buf,
764 const char *c)
765 {
766 char *end = strchr(buf, '\0');
767 while (*c) {
768 if (*c == '/' || *c == ',')
769 *end++ = '\\';
770 *end++ = *c++;
771 }
772 *end = '\0';
773 }
774
775 device INLINE_DEVICE *
776 device_tree_add_found(device *root,
777 const char *prefix,
778 const char *name)
779 {
780 device *parent;
781 device *new_device;
782 device *new_node;
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,
787 device_tree_abort);
788 new_device = device_tree_find_device(parent, name);
789 if (new_device != NULL)
790 return new_device;
791 else {
792 new_device = device_create(name, parent);
793 new_node = device_tree_add_device(parent, "", new_device);
794 ASSERT(new_device == new_node);
795 return new_node;
796 }
797 }
798
799 device INLINE_DEVICE *
800 device_tree_add_found_c(device *root,
801 const char *prefix,
802 const char *name,
803 const char *c1)
804 {
805 char buf[1024];
806 strcpy(buf, name);
807 strcat(buf, "@");
808 c_strcat(buf, c1);
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);
812 }
813
814 device INLINE_DEVICE *
815 device_tree_add_found_c_uw(device *root,
816 const char *prefix,
817 const char *name,
818 const char *c1,
819 unsigned_word uw2)
820 {
821 char buf[1024];
822 strcpy(buf, name);
823 strcat(buf, "@");
824 c_strcat(buf, c1);
825 strcat(buf, ",");
826 u_strcat(buf, uw2);
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);
830 }
831
832 device INLINE_DEVICE *
833 device_tree_add_found_uw_u(device *root,
834 const char *prefix,
835 const char *name,
836 unsigned_word uw1,
837 unsigned u2)
838 {
839 char buf[1024];
840 strcpy(buf, name);
841 strcat(buf, "@");
842 u_strcat(buf, uw1);
843 strcat(buf, ",");
844 u_strcat(buf, u2);
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);
848 }
849
850 device INLINE_DEVICE *
851 device_tree_add_found_uw_u_u(device *root,
852 const char *prefix,
853 const char *name,
854 unsigned_word uw1,
855 unsigned u2,
856 unsigned u3)
857 {
858 char buf[1024];
859 strcpy(buf, name);
860 strcat(buf, "@");
861 u_strcat(buf, uw1);
862 strcat(buf, ",");
863 u_strcat(buf, u2);
864 strcat(buf, ",");
865 u_strcat(buf, u3);
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);
869 }
870
871 device INLINE_DEVICE *
872 device_tree_add_found_uw_u_u_c(device *root,
873 const char *prefix,
874 const char *name,
875 unsigned_word uw1,
876 unsigned u2,
877 unsigned u3,
878 const char *c4)
879 {
880 char buf[1024];
881 strcpy(buf, name);
882 strcat(buf, "@");
883 u_strcat(buf, uw1);
884 strcat(buf, ",");
885 u_strcat(buf, u2);
886 strcat(buf, ",");
887 u_strcat(buf, u3);
888 strcat(buf, ",");
889 c_strcat(buf, c4);
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);
893 }
894
895 device INLINE_DEVICE *
896 device_tree_add_found_uw_uw_u_u_c(device *root,
897 const char *prefix,
898 const char *name,
899 unsigned_word uw1,
900 unsigned_word uw2,
901 unsigned u3,
902 unsigned u4,
903 const char *c5)
904 {
905 char buf[1024];
906 strcpy(buf, name);
907 strcat(buf, "@");
908 u_strcat(buf, uw1);
909 strcat(buf, ",");
910 u_strcat(buf, uw2);
911 strcat(buf, ",");
912 u_strcat(buf, u3);
913 strcat(buf, ",");
914 u_strcat(buf, u4);
915 strcat(buf, ",");
916 c_strcat(buf, c5);
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);
920 }
921
922 device INLINE_DEVICE *
923 device_tree_add_found_uw_uw_u_u_u(device *root,
924 const char *prefix,
925 const char *name,
926 unsigned_word uw1,
927 unsigned_word uw2,
928 unsigned u3,
929 unsigned u4,
930 unsigned u5)
931 {
932 char buf[1024];
933 strcpy(buf, name);
934 strcat(buf, "@");
935 u_strcat(buf, uw1);
936 strcat(buf, ",");
937 u_strcat(buf, uw2);
938 strcat(buf, ",");
939 u_strcat(buf, u3);
940 strcat(buf, ",");
941 u_strcat(buf, u4);
942 strcat(buf, ",");
943 u_strcat(buf, u5);
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);
947 }
948
949
950 /* Parse a device name, various formats */
951
952 #define SCAN_INIT(NAME) \
953 char *START = (char*)0; \
954 char *END = (char*)0; \
955 int COUNT = -1; \
956 /* find the first element */ \
957 END = strchr(NAME, '@'); \
958 if (END == (char*)0) \
959 return COUNT; \
960 COUNT += 1; \
961 START = END + 1
962
963 #define SCAN_END \
964 return COUNT
965
966 #define SCAN_U(U) \
967 do { \
968 *U = strtoul(START, &END, 0); \
969 if (START == END) \
970 return COUNT; \
971 COUNT += 1; \
972 if (*END != ',') \
973 return COUNT; \
974 START = END + 1; \
975 } while (0)
976
977 #define SCAN_P(P) \
978 do { \
979 *P = (void*)(unsigned)strtouq(START, END, 0); \
980 if (START == END) \
981 return COUNT; \
982 COUNT += 1; \
983 if (*END != ',') \
984 return COUNT; \
985 START = END + 1; \
986 } while (0)
987
988 #define SCAN_C(C, SIZE) \
989 do { \
990 char *chp = C; \
991 END = START; \
992 while (*END != '\0' && *END != ',') { \
993 if (*END == '\\') \
994 END += 1; \
995 *chp = *END; \
996 chp += 1; \
997 END += 1; \
998 if ((SIZE) <= ((END) - (START))) \
999 return COUNT; /* overflow */ \
1000 } \
1001 *chp = '\0'; \
1002 if (START == END) \
1003 return COUNT; \
1004 COUNT += 1; \
1005 if (*END != ',') \
1006 return COUNT; \
1007 START = END + 1; \
1008 } while (0)
1009
1010 int INLINE_DEVICE
1011 scand_c(const char *name,
1012 char *c1,
1013 unsigned c1size)
1014 {
1015 SCAN_INIT(name);
1016 SCAN_C(c1, c1size);
1017 SCAN_END;
1018 }
1019
1020 int INLINE_DEVICE
1021 scand_c_uw_u(const char *name,
1022 char *c1,
1023 unsigned c1size,
1024 unsigned_word *uw2,
1025 unsigned *u3)
1026 {
1027 SCAN_INIT(name);
1028 SCAN_C(c1, c1size);
1029 SCAN_U(uw2);
1030 SCAN_U(u3);
1031 SCAN_END;
1032 }
1033
1034 int INLINE_DEVICE
1035 scand_uw(const char *name,
1036 unsigned_word *uw1)
1037 {
1038 SCAN_INIT(name);
1039 SCAN_U(uw1);
1040 SCAN_END;
1041 }
1042
1043 int INLINE_DEVICE
1044 scand_uw_c(const char *name,
1045 unsigned_word *uw1,
1046 char *c2,
1047 unsigned c2size)
1048 {
1049 SCAN_INIT(name);
1050 SCAN_U(uw1);
1051 SCAN_C(c2, c2size);
1052 SCAN_END;
1053 }
1054
1055 int INLINE_DEVICE
1056 scand_uw_u(const char *name,
1057 unsigned_word *uw1,
1058 unsigned *u2)
1059 {
1060 SCAN_INIT(name);
1061 SCAN_U(uw1);
1062 SCAN_U(u2);
1063 SCAN_END;
1064 }
1065
1066 int INLINE_DEVICE
1067 scand_uw_u_u(const char *name,
1068 unsigned_word *uw1,
1069 unsigned *u2,
1070 unsigned *u3)
1071 {
1072 SCAN_INIT(name);
1073 SCAN_U(uw1);
1074 SCAN_U(u2);
1075 SCAN_U(u3);
1076 SCAN_END;
1077 }
1078
1079 int INLINE_DEVICE
1080 scand_uw_u_u_c(const char *name,
1081 unsigned_word *uw1,
1082 unsigned *u2,
1083 unsigned *u3,
1084 char *c4,
1085 unsigned c4size)
1086 {
1087 SCAN_INIT(name);
1088 SCAN_U(uw1);
1089 SCAN_U(u2);
1090 SCAN_U(u3);
1091 SCAN_C(c4, c4size);
1092 SCAN_END;
1093 }
1094
1095 int INLINE_DEVICE
1096 scand_uw_uw(const char *name,
1097 unsigned_word *uw1,
1098 unsigned_word *uw2)
1099 {
1100 SCAN_INIT(name);
1101 SCAN_U(uw1);
1102 SCAN_U(uw2);
1103 SCAN_END;
1104 }
1105
1106 int INLINE_DEVICE
1107 scand_uw_uw_u(const char *name,
1108 unsigned_word *uw1,
1109 unsigned_word *uw2,
1110 unsigned *u3)
1111 {
1112 SCAN_INIT(name);
1113 SCAN_U(uw1);
1114 SCAN_U(uw2);
1115 SCAN_U(u3);
1116 SCAN_END;
1117 }
1118
1119 int INLINE_DEVICE
1120 scand_uw_uw_u_u_c(const char *name,
1121 unsigned_word *uw1,
1122 unsigned_word *uw2,
1123 unsigned *u3,
1124 unsigned *u4,
1125 char *c5,
1126 unsigned c5size)
1127 {
1128 SCAN_INIT(name);
1129 SCAN_U(uw1);
1130 SCAN_U(uw2);
1131 SCAN_U(u3);
1132 SCAN_U(u4);
1133 SCAN_C(c5, c5size);
1134 SCAN_END;
1135 }
1136
1137 int INLINE_DEVICE
1138 scand_uw_uw_u_u_u(const char *name,
1139 unsigned_word *uw1,
1140 unsigned_word *uw2,
1141 unsigned *u3,
1142 unsigned *u4,
1143 unsigned *u5)
1144 {
1145 SCAN_INIT(name);
1146 SCAN_U(uw1);
1147 SCAN_U(uw2);
1148 SCAN_U(u3);
1149 SCAN_U(u4);
1150 SCAN_U(u5);
1151 SCAN_END;
1152 }
1153
1154
1155 #endif /* _DEVICE_C_ */