1/* The common simulator framework for GDB, the GNU Debugger. 2 3 Copyright 2002, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc. 4 5 Contributed by Andrew Cagney and Red Hat. 6 7 This file is part of GDB. 8 9 This program is free software; you can redistribute it and/or modify 10 it under the terms of the GNU General Public License as published by 11 the Free Software Foundation; either version 3 of the License, or 12 (at your option) any later version. 13 14 This program is distributed in the hope that it will be useful, 15 but WITHOUT ANY WARRANTY; without even the implied warranty of 16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 GNU General Public License for more details. 18 19 You should have received a copy of the GNU General Public License 20 along with this program. If not, see <http://www.gnu.org/licenses/>. */ 21 22 23#include "hw-main.h" 24#include "hw-base.h" 25#include "hw-tree.h" 26 27#include "sim-io.h" 28#include "sim-assert.h" 29 30#ifdef HAVE_STDLIB_H 31#include <stdlib.h> 32#endif 33 34#ifdef HAVE_STRING_H 35#include <string.h> 36#else 37#ifdef HAVE_STRINGS_H 38#include <strings.h> 39#endif 40#endif 41 42#include <ctype.h> 43 44/* manipulate/lookup device names */ 45 46typedef struct _name_specifier 47{ 48 49 /* components in the full length name */ 50 char *path; 51 char *property; 52 char *value; 53 54 /* current device */ 55 char *family; 56 char *name; 57 char *unit; 58 char *args; 59 60 /* previous device */ 61 char *last_name; 62 char *last_family; 63 char *last_unit; 64 char *last_args; 65 66 /* work area */ 67 char buf[1024]; 68 69} name_specifier; 70 71 72 73/* Given a device specifier, break it up into its main components: 74 path (and if present) property name and property value. */ 75 76static int 77split_device_specifier (struct hw *current, 78 const char *device_specifier, 79 name_specifier *spec) 80{ 81 char *chp = NULL; 82 83 /* expand any leading alias if present */ 84 if (current != NULL 85 && *device_specifier != '\0' 86 && *device_specifier != '.' 87 && *device_specifier != '/') 88 { 89 struct hw *aliases = hw_tree_find_device (current, "/aliases"); 90 char alias[32]; 91 int len = 0; 92 while (device_specifier[len] != '\0' 93 && device_specifier[len] != '/' 94 && device_specifier[len] != ':' 95 && !isspace (device_specifier[len])) 96 { 97 alias[len] = device_specifier[len]; 98 len++; 99 if (len >= sizeof(alias)) 100 hw_abort (NULL, "split_device_specifier: buffer overflow"); 101 } 102 alias[len] = '\0'; 103 if (aliases != NULL 104 && hw_find_property (aliases, alias)) 105 { 106 strcpy (spec->buf, hw_find_string_property(aliases, alias)); 107 strcat (spec->buf, device_specifier + len); 108 } 109 else 110 { 111 strcpy (spec->buf, device_specifier); 112 } 113 } 114 else 115 { 116 strcpy(spec->buf, device_specifier); 117 } 118 119 /* check no overflow */ 120 if (strlen(spec->buf) >= sizeof(spec->buf)) 121 hw_abort (NULL, "split_device_specifier: buffer overflow\n"); 122 123 /* strip leading spaces */ 124 chp = spec->buf; 125 while (*chp != '\0' && isspace(*chp)) 126 chp++; 127 if (*chp == '\0') 128 return 0; 129 130 /* find the path and terminate it with null */ 131 spec->path = chp; 132 while (*chp != '\0' && !isspace(*chp)) 133 chp++; 134 if (*chp != '\0') 135 { 136 *chp = '\0'; 137 chp++; 138 } 139 140 /* and any value */ 141 while (*chp != '\0' && isspace(*chp)) 142 chp++; 143 spec->value = chp; 144 145 /* now go back and chop the property off of the path */ 146 if (spec->value[0] == '\0') 147 { 148 spec->property = NULL; /*not a property*/ 149 spec->value = NULL; 150 } 151 else if (spec->value[0] == '>' 152 || spec->value[0] == '<') 153 { 154 /* an interrupt spec */ 155 spec->property = NULL; 156 } 157 else 158 { 159 chp = strrchr(spec->path, '/'); 160 if (chp == NULL) 161 { 162 spec->property = spec->path; 163 spec->path = strchr(spec->property, '\0'); 164 } 165 else 166 { 167 *chp = '\0'; 168 spec->property = chp+1; 169 } 170 } 171 172 /* and mark the rest as invalid */ 173 spec->name = NULL; 174 spec->family = NULL; 175 spec->unit = NULL; 176 spec->args = NULL; 177 spec->last_name = NULL; 178 spec->last_family = NULL; 179 spec->last_unit = NULL; 180 spec->last_args = NULL; 181 182 return 1; 183} 184 185 186/* given a device specifier break it up into its main components - 187 path and property name - assuming that the last `device' is a 188 property name. */ 189 190static int 191split_property_specifier (struct hw *current, 192 const char *property_specifier, 193 name_specifier *spec) 194{ 195 if (split_device_specifier (current, property_specifier, spec)) 196 { 197 if (spec->property == NULL) 198 { 199 /* force the last name to be a property name */ 200 char *chp = strrchr (spec->path, '/'); 201 if (chp == NULL) 202 { 203 spec->property = spec->path; 204 spec->path = strrchr (spec->property, '\0');; 205 } 206 else 207 { 208 *chp = '\0'; 209 spec->property = chp + 1; 210 } 211 } 212 return 1; 213 } 214 else 215 return 0; 216} 217 218 219/* device the next device name and split it up, return 0 when no more 220 names to struct hw */ 221 222static int 223split_device_name (name_specifier *spec) 224{ 225 char *chp; 226 /* remember what came before */ 227 spec->last_name = spec->name; 228 spec->last_family = spec->family; 229 spec->last_unit = spec->unit; 230 spec->last_args = spec->args; 231 /* finished? */ 232 if (spec->path[0] == '\0') 233 { 234 spec->name = NULL; 235 spec->family = NULL; 236 spec->unit = NULL; 237 spec->args = NULL; 238 return 0; 239 } 240 /* break the current device spec from the path */ 241 spec->name = spec->path; 242 chp = strchr (spec->name, '/'); 243 if (chp == NULL) 244 spec->path = strchr (spec->name, '\0'); 245 else 246 { 247 spec->path = chp+1; 248 *chp = '\0'; 249 } 250 /* break out the base */ 251 if (spec->name[0] == '(') 252 { 253 chp = strchr(spec->name, ')'); 254 if (chp == NULL) 255 { 256 spec->family = spec->name; 257 } 258 else 259 { 260 *chp = '\0'; 261 spec->family = spec->name + 1; 262 spec->name = chp + 1; 263 } 264 } 265 else 266 { 267 spec->family = spec->name; 268 } 269 /* now break out the unit */ 270 chp = strchr(spec->name, '@'); 271 if (chp == NULL) 272 { 273 spec->unit = NULL; 274 chp = spec->name; 275 } 276 else 277 { 278 *chp = '\0'; 279 chp += 1; 280 spec->unit = chp; 281 } 282 /* finally any args */ 283 chp = strchr(chp, ':'); 284 if (chp == NULL) 285 spec->args = NULL; 286 else 287 { 288 *chp = '\0'; 289 spec->args = chp+1; 290 } 291 return 1; 292} 293 294 295/* device the value, returning the next non-space token */ 296 297static char * 298split_value (name_specifier *spec) 299{ 300 char *token; 301 if (spec->value == NULL) 302 return NULL; 303 /* skip leading white space */ 304 while (isspace (spec->value[0])) 305 spec->value++; 306 if (spec->value[0] == '\0') 307 { 308 spec->value = NULL; 309 return NULL; 310 } 311 token = spec->value; 312 /* find trailing space */ 313 while (spec->value[0] != '\0' && !isspace (spec->value[0])) 314 spec->value++; 315 /* chop this value out */ 316 if (spec->value[0] != '\0') 317 { 318 spec->value[0] = '\0'; 319 spec->value++; 320 } 321 return token; 322} 323 324 325 326/* traverse the path specified by spec starting at current */ 327 328static struct hw * 329split_find_device (struct hw *current, 330 name_specifier *spec) 331{ 332 /* strip off (and process) any leading ., .., ./ and / */ 333 while (1) 334 { 335 if (strncmp (spec->path, "/", strlen ("/")) == 0) 336 { 337 /* cd /... */ 338 while (current != NULL && hw_parent (current) != NULL) 339 current = hw_parent (current); 340 spec->path += strlen ("/"); 341 } 342 else if (strncmp (spec->path, "./", strlen ("./")) == 0) 343 { 344 /* cd ./... */ 345 current = current; 346 spec->path += strlen ("./"); 347 } 348 else if (strncmp (spec->path, "../", strlen ("../")) == 0) 349 { 350 /* cd ../... */ 351 if (current != NULL && hw_parent (current) != NULL) 352 current = hw_parent (current); 353 spec->path += strlen ("../"); 354 } 355 else if (strcmp (spec->path, ".") == 0) 356 { 357 /* cd . */ 358 current = current; 359 spec->path += strlen ("."); 360 } 361 else if (strcmp (spec->path, "..") == 0) 362 { 363 /* cd .. */ 364 if (current != NULL && hw_parent (current) != NULL) 365 current = hw_parent (current); 366 spec->path += strlen (".."); 367 } 368 else 369 break; 370 } 371 372 /* now go through the path proper */ 373 374 if (current == NULL) 375 { 376 split_device_name (spec); 377 return NULL; 378 } 379 380 while (split_device_name (spec)) 381 { 382 struct hw *child; 383 for (child = hw_child (current); 384 child != NULL; child = hw_sibling (child)) 385 { 386 if (strcmp (spec->name, hw_name (child)) == 0) 387 { 388 if (spec->unit == NULL) 389 break; 390 else 391 { 392 hw_unit phys; 393 hw_unit_decode (current, spec->unit, &phys); 394 if (memcmp (&phys, hw_unit_address (child), 395 sizeof (hw_unit)) == 0) 396 break; 397 } 398 } 399 } 400 if (child == NULL) 401 return current; /* search failed */ 402 current = child; 403 } 404 405 return current; 406} 407 408 409static struct hw * 410split_fill_path (struct hw *current, 411 const char *device_specifier, 412 name_specifier *spec) 413{ 414 /* break it up */ 415 if (!split_device_specifier (current, device_specifier, spec)) 416 hw_abort (current, "error parsing %s\n", device_specifier); 417 418 /* fill our tree with its contents */ 419 current = split_find_device (current, spec); 420 421 /* add any additional devices as needed */ 422 if (spec->name != NULL) 423 { 424 do 425 { 426 if (current != NULL && !hw_finished_p (current)) 427 hw_finish (current); 428 current = hw_create (NULL, 429 current, 430 spec->family, 431 spec->name, 432 spec->unit, 433 spec->args); 434 } 435 while (split_device_name (spec)); 436 } 437 438 return current; 439} 440 441 442/* <non-white-space> */ 443 444static const char * 445skip_token(const char *chp) 446{ 447 while (!isspace(*chp) && *chp != '\0') 448 chp++; 449 while (isspace(*chp) && *chp != '\0') 450 chp++; 451 return chp; 452} 453 454 455/* count the number of entries */ 456 457static int 458count_entries (struct hw *current, 459 const char *property_name, 460 const char *property_value, 461 int modulo) 462{ 463 const char *chp = property_value; 464 int nr_entries = 0; 465 while (*chp != '\0') 466 { 467 nr_entries += 1; 468 chp = skip_token (chp); 469 } 470 if ((nr_entries % modulo) != 0) 471 { 472 hw_abort (current, "incorrect number of entries for %s property %s, should be multiple of %d", 473 property_name, property_value, modulo); 474 } 475 return nr_entries / modulo; 476} 477 478 479 480/* parse: <address> ::= <token> ; device dependant */ 481 482static const char * 483parse_address (struct hw *current, 484 struct hw *bus, 485 const char *chp, 486 hw_unit *address) 487{ 488 if (hw_unit_decode (bus, chp, address) < 0) 489 hw_abort (current, "invalid unit address in %s", chp); 490 return skip_token (chp); 491} 492 493 494/* parse: <size> ::= <number> { "," <number> } ; */ 495 496static const char * 497parse_size (struct hw *current, 498 struct hw *bus, 499 const char *chp, 500 hw_unit *size) 501{ 502 int i; 503 int nr; 504 const char *curr = chp; 505 memset(size, 0, sizeof(*size)); 506 /* parse the numeric list */ 507 size->nr_cells = hw_unit_nr_size_cells (bus); 508 nr = 0; 509 while (1) 510 { 511 char *next; 512 size->cells[nr] = strtoul (curr, &next, 0); 513 if (curr == next) 514 hw_abort (current, "Problem parsing <size> %s", chp); 515 nr += 1; 516 if (next[0] != ',') 517 break; 518 if (nr == size->nr_cells) 519 hw_abort (current, "Too many values in <size> %s", chp); 520 curr = next + 1; 521 } 522 ASSERT (nr > 0 && nr <= size->nr_cells); 523 /* right align the numbers */ 524 for (i = 1; i <= size->nr_cells; i++) 525 { 526 if (i <= nr) 527 size->cells[size->nr_cells - i] = size->cells[nr - i]; 528 else 529 size->cells[size->nr_cells - i] = 0; 530 } 531 return skip_token (chp); 532} 533 534 535/* parse: <reg> ::= { <address> <size> } ; */ 536 537static void 538parse_reg_property (struct hw *current, 539 const char *property_name, 540 const char *property_value) 541{ 542 int nr_regs; 543 int reg_nr; 544 reg_property_spec *regs; 545 const char *chp; 546 547 /* determine the number of reg entries by counting tokens */ 548 nr_regs = count_entries (current, property_name, property_value, 2); 549 550 /* create working space */ 551 regs = zalloc (nr_regs * sizeof (*regs)); 552 553 /* fill it in */ 554 chp = property_value; 555 for (reg_nr = 0; reg_nr < nr_regs; reg_nr++) 556 { 557 chp = parse_address (current, hw_parent(current), 558 chp, ®s[reg_nr].address); 559 chp = parse_size (current, hw_parent(current), 560 chp, ®s[reg_nr].size); 561 } 562 563 /* create it */ 564 hw_add_reg_array_property (current, property_name, 565 regs, nr_regs); 566 567 free (regs); 568} 569 570 571/* { <child-address> <parent-address> <child-size> }* */ 572 573static void 574parse_ranges_property (struct hw *current, 575 const char *property_name, 576 const char *property_value) 577{ 578 int nr_ranges; 579 int range_nr; 580 range_property_spec *ranges; 581 const char *chp; 582 583 /* determine the number of ranges specified */ 584 nr_ranges = count_entries (current, property_name, property_value, 3); 585 586 /* create a property of that size */ 587 ranges = zalloc (nr_ranges * sizeof(*ranges)); 588 589 /* fill it in */ 590 chp = property_value; 591 for (range_nr = 0; range_nr < nr_ranges; range_nr++) 592 { 593 chp = parse_address (current, current, 594 chp, &ranges[range_nr].child_address); 595 chp = parse_address (current, hw_parent(current), 596 chp, &ranges[range_nr].parent_address); 597 chp = parse_size (current, current, 598 chp, &ranges[range_nr].size); 599 } 600 601 /* create it */ 602 hw_add_range_array_property (current, property_name, ranges, nr_ranges); 603 604 free (ranges); 605} 606 607 608/* <integer> ... */ 609 610static void 611parse_integer_property (struct hw *current, 612 const char *property_name, 613 const char *property_value) 614{ 615 int nr_entries; 616 unsigned_cell words[1024]; 617 /* integer or integer array? */ 618 nr_entries = 0; 619 while (1) 620 { 621 char *end; 622 words[nr_entries] = strtoul (property_value, &end, 0); 623 if (property_value == end) 624 break; 625 nr_entries += 1; 626 if (nr_entries * sizeof (words[0]) >= sizeof (words)) 627 hw_abort (current, "buffer overflow"); 628 property_value = end; 629 } 630 if (nr_entries == 0) 631 hw_abort (current, "error parsing integer property %s (%s)", 632 property_name, property_value); 633 else if (nr_entries == 1) 634 hw_add_integer_property (current, property_name, words[0]); 635 else 636 { 637 int i; 638 for (i = 0; i < nr_entries; i++) 639 { 640 H2BE (words[i]); 641 } 642 /* perhaps integer array property is better */ 643 hw_add_array_property (current, property_name, words, 644 sizeof(words[0]) * nr_entries); 645 } 646} 647 648 649/* <string> ... */ 650 651static void 652parse_string_property (struct hw *current, 653 const char *property_name, 654 const char *property_value) 655{ 656 char **strings; 657 const char *chp; 658 int nr_strings; 659 int approx_nr_strings; 660 661 /* get an estimate as to the number of strings by counting double 662 quotes */ 663 approx_nr_strings = 2; 664 for (chp = property_value; *chp; chp++) 665 { 666 if (*chp == '"') 667 approx_nr_strings++; 668 } 669 approx_nr_strings = (approx_nr_strings) / 2; 670 671 /* create a string buffer for that many (plus a null) */ 672 strings = (char**) zalloc ((approx_nr_strings + 1) * sizeof(char*)); 673 674 /* now find all the strings */ 675 chp = property_value; 676 nr_strings = 0; 677 while (1) 678 { 679 680 /* skip leading space */ 681 while (*chp != '\0' && isspace (*chp)) 682 chp += 1; 683 if (*chp == '\0') 684 break; 685 686 /* copy it in */ 687 if (*chp == '"') 688 { 689 /* a quoted string - watch for '\' et al. */ 690 /* estimate the size and allocate space for it */ 691 int pos; 692 chp++; 693 pos = 0; 694 while (chp[pos] != '\0' && chp[pos] != '"') 695 { 696 if (chp[pos] == '\\' && chp[pos+1] != '\0') 697 pos += 2; 698 else 699 pos += 1; 700 } 701 strings[nr_strings] = zalloc (pos + 1); 702 /* copy the string over */ 703 pos = 0; 704 while (*chp != '\0' && *chp != '"') 705 { 706 if (*chp == '\\' && *(chp+1) != '\0') 707 { 708 strings[nr_strings][pos] = *(chp+1); 709 chp += 2; 710 pos++; 711 } 712 else 713 { 714 strings[nr_strings][pos] = *chp; 715 chp += 1; 716 pos++; 717 } 718 } 719 if (*chp != '\0') 720 chp++; 721 strings[nr_strings][pos] = '\0'; 722 } 723 else 724 { 725 /* copy over a single unquoted token */ 726 int len = 0; 727 while (chp[len] != '\0' && !isspace(chp[len])) 728 len++; 729 strings[nr_strings] = zalloc(len + 1); 730 strncpy(strings[nr_strings], chp, len); 731 strings[nr_strings][len] = '\0'; 732 chp += len; 733 } 734 nr_strings++; 735 if (nr_strings > approx_nr_strings) 736 hw_abort (current, "String property %s badly formatted", 737 property_name); 738 } 739 ASSERT (strings[nr_strings] == NULL); /* from zalloc */ 740 741 /* install it */ 742 if (nr_strings == 0) 743 hw_add_string_property (current, property_name, ""); 744 else if (nr_strings == 1) 745 hw_add_string_property (current, property_name, strings[0]); 746 else 747 { 748 const char **specs = (const char**) strings; /* stop a bogus error */ 749 hw_add_string_array_property (current, property_name, 750 specs, nr_strings); 751 } 752 753 /* flush the created string */ 754 while (nr_strings > 0) 755 { 756 nr_strings--; 757 free (strings[nr_strings]); 758 } 759 free(strings); 760} 761 762 763/* <path-to-ihandle-device> */ 764 765#if NOT_YET 766static void 767parse_ihandle_property (struct hw *current, 768 const char *property, 769 const char *value) 770{ 771 ihandle_runtime_property_spec ihandle; 772 773 /* pass the full path */ 774 ihandle.full_path = value; 775 776 /* save this ready for the ihandle create */ 777 hw_add_ihandle_runtime_property (current, property, 778 &ihandle); 779} 780#endif 781 782 783struct hw * 784hw_tree_create (SIM_DESC sd, 785 const char *family) 786{ 787 return hw_create (sd, NULL, family, family, NULL, NULL); 788} 789 790void 791hw_tree_delete (struct hw *me) 792{ 793 /* Need to allow devices to disapear under our feet */ 794 while (hw_child (me) != NULL) 795 { 796 hw_tree_delete (hw_child (me)); 797 } 798 hw_delete (me); 799} 800 801 802struct hw * 803hw_tree_parse (struct hw *current, 804 const char *fmt, 805 ...) 806{ 807 va_list ap; 808 va_start (ap, fmt); 809 current = hw_tree_vparse (current, fmt, ap); 810 va_end (ap); 811 return current; 812} 813 814struct hw * 815hw_tree_vparse (struct hw *current, 816 const char *fmt, 817 va_list ap) 818{ 819 char device_specifier[1024]; 820 name_specifier spec; 821 822 /* format the path */ 823 vsprintf (device_specifier, fmt, ap); 824 if (strlen (device_specifier) >= sizeof (device_specifier)) 825 hw_abort (NULL, "device_tree_add_deviced: buffer overflow\n"); 826 827 /* construct the tree down to the final struct hw */ 828 current = split_fill_path (current, device_specifier, &spec); 829 830 /* is there an interrupt spec */ 831 if (spec.property == NULL 832 && spec.value != NULL) 833 { 834 char *op = split_value (&spec); 835 switch (op[0]) 836 { 837 case '>': 838 { 839 char *my_port_name = split_value (&spec); 840 int my_port; 841 char *dest_port_name = split_value (&spec); 842 int dest_port; 843 name_specifier dest_spec; 844 char *dest_hw_name = split_value (&spec); 845 struct hw *dest; 846 /* find my name */ 847 if (!hw_finished_p (current)) 848 hw_finish (current); 849 my_port = hw_port_decode (current, my_port_name, output_port); 850 /* find the dest device and port */ 851 dest = split_fill_path (current, dest_hw_name, &dest_spec); 852 if (!hw_finished_p (dest)) 853 hw_finish (dest); 854 dest_port = hw_port_decode (dest, dest_port_name, 855 input_port); 856 /* connect the two */ 857 hw_port_attach (current, 858 my_port, 859 dest, 860 dest_port, 861 permenant_object); 862 break; 863 } 864 default: 865 hw_abort (current, "unreconised interrupt spec %s\n", spec.value); 866 break; 867 } 868 } 869 870 /* is there a property */ 871 if (spec.property != NULL) 872 { 873 if (strcmp (spec.value, "true") == 0) 874 hw_add_boolean_property (current, spec.property, 1); 875 else if (strcmp (spec.value, "false") == 0) 876 hw_add_boolean_property (current, spec.property, 0); 877 else 878 { 879 const struct hw_property *property; 880 switch (spec.value[0]) 881 { 882#if NOT_YET 883 case '*': 884 { 885 parse_ihandle_property (current, spec.property, spec.value + 1); 886 break; 887 } 888#endif 889 case '[': 890 { 891 unsigned8 words[1024]; 892 char *curr = spec.value + 1; 893 int nr_words = 0; 894 while (1) 895 { 896 char *next; 897 words[nr_words] = H2BE_1 (strtoul (curr, &next, 0)); 898 if (curr == next) 899 break; 900 curr = next; 901 nr_words += 1; 902 } 903 hw_add_array_property (current, spec.property, 904 words, sizeof(words[0]) * nr_words); 905 break; 906 } 907 case '"': 908 { 909 parse_string_property (current, spec.property, spec.value); 910 break; 911 } 912 case '!': 913 { 914 spec.value++; 915 property = hw_tree_find_property (current, spec.value); 916 if (property == NULL) 917 hw_abort (current, "property %s not found\n", spec.value); 918 hw_add_duplicate_property (current, 919 spec.property, 920 property); 921 break; 922 } 923 default: 924 { 925 if (strcmp (spec.property, "reg") == 0 926 || strcmp (spec.property, "assigned-addresses") == 0 927 || strcmp (spec.property, "alternate-reg") == 0) 928 { 929 parse_reg_property (current, spec.property, spec.value); 930 } 931 else if (strcmp (spec.property, "ranges") == 0) 932 { 933 parse_ranges_property (current, spec.property, spec.value); 934 } 935 else if (isdigit(spec.value[0]) 936 || (spec.value[0] == '-' && isdigit(spec.value[1])) 937 || (spec.value[0] == '+' && isdigit(spec.value[1]))) 938 { 939 parse_integer_property(current, spec.property, spec.value); 940 } 941 else 942 parse_string_property(current, spec.property, spec.value); 943 break; 944 } 945 } 946 } 947 } 948 return current; 949} 950 951 952static void 953finish_hw_tree (struct hw *me, 954 void *data) 955{ 956 if (!hw_finished_p (me)) 957 hw_finish (me); 958} 959 960void 961hw_tree_finish (struct hw *root) 962{ 963 hw_tree_traverse (root, finish_hw_tree, NULL, NULL); 964} 965 966 967 968void 969hw_tree_traverse (struct hw *root, 970 hw_tree_traverse_function *prefix, 971 hw_tree_traverse_function *postfix, 972 void *data) 973{ 974 struct hw *child; 975 if (prefix != NULL) 976 prefix (root, data); 977 for (child = hw_child (root); 978 child != NULL; 979 child = hw_sibling (child)) 980 { 981 hw_tree_traverse (child, prefix, postfix, data); 982 } 983 if (postfix != NULL) 984 postfix (root, data); 985} 986 987 988 989struct printer 990{ 991 hw_tree_print_callback *print; 992 void *file; 993}; 994 995static void 996print_address (struct hw *bus, 997 const hw_unit *phys, 998 struct printer *p) 999{ 1000 char unit[32]; 1001 hw_unit_encode (bus, phys, unit, sizeof(unit)); 1002 p->print (p->file, " %s", unit); 1003} 1004 1005static void 1006print_size (struct hw *bus, 1007 const hw_unit *size, 1008 struct printer *p) 1009{ 1010 int i; 1011 for (i = 0; i < size->nr_cells; i++) 1012 if (size->cells[i] != 0) 1013 break; 1014 if (i < size->nr_cells) 1015 { 1016 p->print (p->file, " 0x%lx", (unsigned long) size->cells[i]); 1017 i++; 1018 for (; i < size->nr_cells; i++) 1019 p->print (p->file, ",0x%lx", (unsigned long) size->cells[i]); 1020 } 1021 else 1022 p->print (p->file, " 0"); 1023} 1024 1025static void 1026print_reg_property (struct hw *me, 1027 const struct hw_property *property, 1028 struct printer *p) 1029{ 1030 int reg_nr; 1031 reg_property_spec reg; 1032 for (reg_nr = 0; 1033 hw_find_reg_array_property (me, property->name, reg_nr, ®); 1034 reg_nr++) 1035 { 1036 print_address (hw_parent (me), ®.address, p); 1037 print_size (me, ®.size, p); 1038 } 1039} 1040 1041static void 1042print_ranges_property (struct hw *me, 1043 const struct hw_property *property, 1044 struct printer *p) 1045{ 1046 int range_nr; 1047 range_property_spec range; 1048 for (range_nr = 0; 1049 hw_find_range_array_property (me, property->name, range_nr, &range); 1050 range_nr++) 1051 { 1052 print_address (me, &range.child_address, p); 1053 print_address (hw_parent (me), &range.parent_address, p); 1054 print_size (me, &range.size, p); 1055 } 1056} 1057 1058static void 1059print_string (struct hw *me, 1060 const char *string, 1061 struct printer *p) 1062{ 1063 p->print (p->file, " \""); 1064 while (*string != '\0') 1065 { 1066 switch (*string) 1067 { 1068 case '"': 1069 p->print (p->file, "\\\""); 1070 break; 1071 case '\\': 1072 p->print (p->file, "\\\\"); 1073 break; 1074 default: 1075 p->print (p->file, "%c", *string); 1076 break; 1077 } 1078 string++; 1079 } 1080 p->print (p->file, "\""); 1081} 1082 1083static void 1084print_string_array_property (struct hw *me, 1085 const struct hw_property *property, 1086 struct printer *p) 1087{ 1088 int nr; 1089 string_property_spec string; 1090 for (nr = 0; 1091 hw_find_string_array_property (me, property->name, nr, &string); 1092 nr++) 1093 { 1094 print_string (me, string, p); 1095 } 1096} 1097 1098static void 1099print_properties (struct hw *me, 1100 struct printer *p) 1101{ 1102 const struct hw_property *property; 1103 for (property = hw_find_property (me, NULL); 1104 property != NULL; 1105 property = hw_next_property (property)) 1106 { 1107 if (hw_parent (me) == NULL) 1108 p->print (p->file, "/%s", property->name); 1109 else 1110 p->print (p->file, "%s/%s", hw_path (me), property->name); 1111 if (property->original != NULL) 1112 { 1113 p->print (p->file, " !"); 1114 p->print (p->file, "%s/%s", 1115 hw_path (property->original->owner), 1116 property->original->name); 1117 } 1118 else 1119 { 1120 switch (property->type) 1121 { 1122 case array_property: 1123 { 1124 if ((property->sizeof_array % sizeof (signed_cell)) == 0) 1125 { 1126 unsigned_cell *w = (unsigned_cell*) property->array; 1127 int cell_nr; 1128 for (cell_nr = 0; 1129 cell_nr < (property->sizeof_array / sizeof (unsigned_cell)); 1130 cell_nr++) 1131 { 1132 p->print (p->file, " 0x%lx", (unsigned long) BE2H_cell (w[cell_nr])); 1133 } 1134 } 1135 else 1136 { 1137 unsigned8 *w = (unsigned8*)property->array; 1138 p->print (p->file, " ["); 1139 while ((char*)w - (char*)property->array < property->sizeof_array) 1140 { 1141 p->print (p->file, " 0x%2x", BE2H_1 (*w)); 1142 w++; 1143 } 1144 } 1145 break; 1146 } 1147 case boolean_property: 1148 { 1149 int b = hw_find_boolean_property(me, property->name); 1150 p->print (p->file, " %s", b ? "true" : "false"); 1151 break; 1152 } 1153#if NOT_YET 1154 case ihandle_property: 1155 { 1156 if (property->array != NULL) 1157 { 1158 device_instance *instance = hw_find_ihandle_property (me, property->name); 1159 p->print (p->file, " *%s", device_instance_path(instance)); 1160 } 1161 else 1162 { 1163 /* not yet initialized, ask the device for the path */ 1164 ihandle_runtime_property_spec spec; 1165 hw_find_ihandle_runtime_property (me, property->name, &spec); 1166 p->print (p->file, " *%s", spec.full_path); 1167 } 1168 break; 1169 } 1170#endif 1171 case integer_property: 1172 { 1173 unsigned_word w = hw_find_integer_property (me, property->name); 1174 p->print (p->file, " 0x%lx", (unsigned long)w); 1175 break; 1176 } 1177 case range_array_property: 1178 { 1179 print_ranges_property (me, property, p); 1180 break; 1181 } 1182 case reg_array_property: 1183 { 1184 print_reg_property (me, property, p); 1185 break; 1186 } 1187 case string_property: 1188 { 1189 const char *s = hw_find_string_property (me, property->name); 1190 print_string (me, s, p); 1191 break; 1192 } 1193 case string_array_property: 1194 { 1195 print_string_array_property (me, property, p); 1196 break; 1197 } 1198 } 1199 } 1200 p->print (p->file, "\n"); 1201 } 1202} 1203 1204static void 1205print_interrupts (struct hw *me, 1206 int my_port, 1207 struct hw *dest, 1208 int dest_port, 1209 void *data) 1210{ 1211 struct printer *p = data; 1212 char src[32]; 1213 char dst[32]; 1214 hw_port_encode (me, my_port, src, sizeof(src), output_port); 1215 hw_port_encode (dest, dest_port, dst, sizeof(dst), input_port); 1216 p->print (p->file, 1217 "%s > %s %s %s\n", 1218 hw_path (me), 1219 src, dst, 1220 hw_path (dest)); 1221} 1222 1223static void 1224print_device (struct hw *me, 1225 void *data) 1226{ 1227 struct printer *p = data; 1228 p->print (p->file, "%s\n", hw_path (me)); 1229 print_properties (me, p); 1230 hw_port_traverse (me, print_interrupts, data); 1231} 1232 1233void 1234hw_tree_print (struct hw *root, 1235 hw_tree_print_callback *print, 1236 void *file) 1237{ 1238 struct printer p; 1239 p.print = print; 1240 p.file = file; 1241 hw_tree_traverse (root, 1242 print_device, NULL, 1243 &p); 1244} 1245 1246 1247 1248#if NOT_YET 1249device_instance * 1250tree_instance(struct hw *root, 1251 const char *device_specifier) 1252{ 1253 /* find the device node */ 1254 struct hw *me; 1255 name_specifier spec; 1256 if (!split_device_specifier(root, device_specifier, &spec)) 1257 return NULL; 1258 me = split_find_device(root, &spec); 1259 if (spec.name != NULL) 1260 return NULL; 1261 /* create the instance */ 1262 return device_create_instance(me, device_specifier, spec.last_args); 1263} 1264#endif 1265 1266struct hw * 1267hw_tree_find_device (struct hw *root, 1268 const char *path_to_device) 1269{ 1270 struct hw *node; 1271 name_specifier spec; 1272 1273 /* parse the path */ 1274 split_device_specifier (root, path_to_device, &spec); 1275 if (spec.value != NULL) 1276 return NULL; /* something wierd */ 1277 1278 /* now find it */ 1279 node = split_find_device (root, &spec); 1280 if (spec.name != NULL) 1281 return NULL; /* not a leaf */ 1282 1283 return node; 1284} 1285 1286 1287const struct hw_property * 1288hw_tree_find_property (struct hw *root, 1289 const char *path_to_property) 1290{ 1291 name_specifier spec; 1292 if (!split_property_specifier (root, path_to_property, &spec)) 1293 hw_abort (root, "Invalid property path %s", path_to_property); 1294 root = split_find_device (root, &spec); 1295 if (spec.name != NULL) 1296 return NULL; /* not a leaf */ 1297 return hw_find_property (root, spec.property); 1298} 1299 1300int 1301hw_tree_find_boolean_property (struct hw *root, 1302 const char *path_to_property) 1303{ 1304 name_specifier spec; 1305 if (!split_property_specifier (root, path_to_property, &spec)) 1306 hw_abort (root, "Invalid property path %s", path_to_property); 1307 root = split_find_device (root, &spec); 1308 if (spec.name != NULL) 1309 hw_abort (root, "device \"%s\" not found (property \"%s\")", 1310 spec.name, path_to_property); 1311 return hw_find_boolean_property (root, spec.property); 1312} 1313 1314signed_cell 1315hw_tree_find_integer_property (struct hw *root, 1316 const char *path_to_property) 1317{ 1318 name_specifier spec; 1319 if (!split_property_specifier (root, path_to_property, &spec)) 1320 hw_abort (root, "Invalid property path %s", path_to_property); 1321 root = split_find_device (root, &spec); 1322 if (spec.name != NULL) 1323 hw_abort (root, "device \"%s\" not found (property \"%s\")", 1324 spec.name, path_to_property); 1325 return hw_find_integer_property (root, spec.property); 1326} 1327 1328#if NOT_YET 1329device_instance * 1330hw_tree_find_ihandle_property (struct hw *root, 1331 const char *path_to_property) 1332{ 1333 struct hw *root; 1334 name_specifier spec; 1335 if (!split_property_specifier (root, path_to_property, &spec)) 1336 hw_abort (root, "Invalid property path %s", path_to_property); 1337 root = split_find_device (root, &spec); 1338 if (spec.name != NULL) 1339 hw_abort (root, "device \"%s\" not found (property \"%s\")", 1340 spec.name, path_to_property); 1341 return hw_find_ihandle_property (root, spec.property); 1342} 1343#endif 1344 1345const char * 1346hw_tree_find_string_property (struct hw *root, 1347 const char *path_to_property) 1348{ 1349 name_specifier spec; 1350 if (!split_property_specifier (root, path_to_property, &spec)) 1351 hw_abort (root, "Invalid property path %s", path_to_property); 1352 root = split_find_device (root, &spec); 1353 if (spec.name != NULL) 1354 hw_abort (root, "device \"%s\" not found (property \"%s\")", 1355 spec.name, path_to_property); 1356 return hw_find_string_property (root, spec.property); 1357} 1358