1/* The common simulator framework for GDB, the GNU Debugger. 2 3 Copyright 2002, 2007 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#include "hw-main.h" 23#include "hw-base.h" 24 25#include "sim-io.h" 26#include "sim-assert.h" 27 28#ifdef HAVE_STRING_H 29#include <string.h> 30#else 31#ifdef HAVE_STRINGS_H 32#include <strings.h> 33#endif 34#endif 35 36#define TRACE(A,B) 37 38/* property entries */ 39 40struct hw_property_data { 41 struct hw_property_data *next; 42 struct hw_property *property; 43 const void *init_array; 44 unsigned sizeof_init_array; 45}; 46 47void 48create_hw_property_data (struct hw *me) 49{ 50} 51 52void 53delete_hw_property_data (struct hw *me) 54{ 55} 56 57 58/* Device Properties: */ 59 60static struct hw_property_data * 61find_property_data (struct hw *me, 62 const char *property) 63{ 64 struct hw_property_data *entry; 65 ASSERT (property != NULL); 66 entry = me->properties_of_hw; 67 while (entry != NULL) 68 { 69 if (strcmp (entry->property->name, property) == 0) 70 return entry; 71 entry = entry->next; 72 } 73 return NULL; 74} 75 76 77static void 78hw_add_property (struct hw *me, 79 const char *property, 80 hw_property_type type, 81 const void *init_array, 82 unsigned sizeof_init_array, 83 const void *array, 84 unsigned sizeof_array, 85 const struct hw_property *original, 86 object_disposition disposition) 87{ 88 struct hw_property_data *new_entry = NULL; 89 struct hw_property *new_value = NULL; 90 91 /* find the list end */ 92 struct hw_property_data **insertion_point = &me->properties_of_hw; 93 while (*insertion_point != NULL) 94 { 95 if (strcmp ((*insertion_point)->property->name, property) == 0) 96 return; 97 insertion_point = &(*insertion_point)->next; 98 } 99 100 /* create a new value */ 101 new_value = HW_ZALLOC (me, struct hw_property); 102 new_value->name = (char *) strdup (property); 103 new_value->type = type; 104 if (sizeof_array > 0) 105 { 106 void *new_array = hw_zalloc (me, sizeof_array); 107 memcpy (new_array, array, sizeof_array); 108 new_value->array = new_array; 109 new_value->sizeof_array = sizeof_array; 110 } 111 new_value->owner = me; 112 new_value->original = original; 113 new_value->disposition = disposition; 114 115 /* insert the value into the list */ 116 new_entry = HW_ZALLOC (me, struct hw_property_data); 117 *insertion_point = new_entry; 118 if (sizeof_init_array > 0) 119 { 120 void *new_init_array = hw_zalloc (me, sizeof_init_array); 121 memcpy (new_init_array, init_array, sizeof_init_array); 122 new_entry->init_array = new_init_array; 123 new_entry->sizeof_init_array = sizeof_init_array; 124 } 125 new_entry->property = new_value; 126} 127 128 129static void 130hw_set_property (struct hw *me, 131 const char *property, 132 hw_property_type type, 133 const void *array, 134 int sizeof_array) 135{ 136 /* find the property */ 137 struct hw_property_data *entry = find_property_data (me, property); 138 if (entry != NULL) 139 { 140 /* existing property - update it */ 141 void *new_array = 0; 142 struct hw_property *value = entry->property; 143 /* check the type matches */ 144 if (value->type != type) 145 hw_abort (me, "conflict between type of new and old value for property %s", property); 146 /* replace its value */ 147 if (value->array != NULL) 148 hw_free (me, (void*)value->array); 149 new_array = (sizeof_array > 0 150 ? hw_zalloc (me, sizeof_array) 151 : (void*)0); 152 value->array = new_array; 153 value->sizeof_array = sizeof_array; 154 if (sizeof_array > 0) 155 memcpy (new_array, array, sizeof_array); 156 return; 157 } 158 else 159 { 160 /* new property - create it */ 161 hw_add_property (me, property, type, 162 NULL, 0, array, sizeof_array, 163 NULL, temporary_object); 164 } 165} 166 167 168#if 0 169static void 170clean_hw_properties (struct hw *me) 171{ 172 struct hw_property_data **delete_point = &me->properties_of_hw; 173 while (*delete_point != NULL) 174 { 175 struct hw_property_data *current = *delete_point; 176 switch (current->property->disposition) 177 { 178 case permenant_object: 179 /* zap the current value, will be initialized later */ 180 ASSERT (current->init_array != NULL); 181 if (current->property->array != NULL) 182 { 183 hw_free (me, (void*)current->property->array); 184 current->property->array = NULL; 185 } 186 delete_point = &(*delete_point)->next; 187 break; 188 case temporary_object: 189 /* zap the actual property, was created during simulation run */ 190 ASSERT (current->init_array == NULL); 191 *delete_point = current->next; 192 if (current->property->array != NULL) 193 hw_free (me, (void*)current->property->array); 194 hw_free (me, current->property); 195 hw_free (me, current); 196 break; 197 } 198 } 199} 200#endif 201 202#if 0 203void 204hw_init_static_properties (SIM_DESC sd, 205 struct hw *me, 206 void *data) 207{ 208 struct hw_property_data *property; 209 for (property = me->properties_of_hw; 210 property != NULL; 211 property = property->next) 212 { 213 ASSERT (property->init_array != NULL); 214 ASSERT (property->property->array == NULL); 215 ASSERT(property->property->disposition == permenant_object); 216 switch (property->property->type) 217 { 218 case array_property: 219 case boolean_property: 220 case range_array_property: 221 case reg_array_property: 222 case string_property: 223 case string_array_property: 224 case integer_property: 225 /* delete the property, and replace it with the original */ 226 hw_set_property (me, property->property->name, 227 property->property->type, 228 property->init_array, 229 property->sizeof_init_array); 230 break; 231#if 0 232 case ihandle_property: 233 break; 234#endif 235 } 236 } 237} 238#endif 239 240 241#if 0 242void 243hw_init_runtime_properties (SIM_DESC sd, 244 struct hw *me, 245 void *data) 246{ 247 struct hw_property_data *property; 248 for (property = me->properties_of_hw; 249 property != NULL; 250 property = property->next) 251 { 252 switch (property->property->disposition) 253 { 254 case permenant_object: 255 switch (property->property->type) 256 { 257#if 0 258 case ihandle_property: 259 { 260 struct hw_instance *ihandle; 261 ihandle_runtime_property_spec spec; 262 ASSERT (property->init_array != NULL); 263 ASSERT (property->property->array == NULL); 264 hw_find_ihandle_runtime_property (me, property->property->name, &spec); 265 ihandle = tree_instance (me, spec.full_path); 266 hw_set_ihandle_property (me, property->property->name, ihandle); 267 break; 268 } 269#endif 270 case array_property: 271 case boolean_property: 272 case range_array_property: 273 case integer_property: 274 case reg_array_property: 275 case string_property: 276 case string_array_property: 277 ASSERT (property->init_array != NULL); 278 ASSERT (property->property->array != NULL); 279 break; 280 } 281 break; 282 case temporary_object: 283 ASSERT (property->init_array == NULL); 284 ASSERT (property->property->array != NULL); 285 break; 286 } 287 } 288} 289#endif 290 291 292 293const struct hw_property * 294hw_next_property (const struct hw_property *property) 295{ 296 /* find the property in the list */ 297 struct hw *owner = property->owner; 298 struct hw_property_data *entry = owner->properties_of_hw; 299 while (entry != NULL && entry->property != property) 300 entry = entry->next; 301 /* now return the following property */ 302 ASSERT (entry != NULL); /* must be a member! */ 303 if (entry->next != NULL) 304 return entry->next->property; 305 else 306 return NULL; 307} 308 309 310const struct hw_property * 311hw_find_property (struct hw *me, 312 const char *property) 313{ 314 if (me == NULL) 315 { 316 return NULL; 317 } 318 else if (property == NULL || strcmp (property, "") == 0) 319 { 320 if (me->properties_of_hw == NULL) 321 return NULL; 322 else 323 return me->properties_of_hw->property; 324 } 325 else 326 { 327 struct hw_property_data *entry = find_property_data (me, property); 328 if (entry != NULL) 329 return entry->property; 330 } 331 return NULL; 332} 333 334 335void 336hw_add_array_property (struct hw *me, 337 const char *property, 338 const void *array, 339 int sizeof_array) 340{ 341 hw_add_property (me, property, array_property, 342 array, sizeof_array, array, sizeof_array, 343 NULL, permenant_object); 344} 345 346void 347hw_set_array_property (struct hw *me, 348 const char *property, 349 const void *array, 350 int sizeof_array) 351{ 352 hw_set_property (me, property, array_property, array, sizeof_array); 353} 354 355const struct hw_property * 356hw_find_array_property (struct hw *me, 357 const char *property) 358{ 359 const struct hw_property *node; 360 node = hw_find_property (me, property); 361 if (node == NULL) 362 hw_abort (me, "property \"%s\" not found", property); 363 if (node->type != array_property) 364 hw_abort (me, "property \"%s\" of wrong type (array)", property); 365 return node; 366} 367 368 369 370void 371hw_add_boolean_property (struct hw *me, 372 const char *property, 373 int boolean) 374{ 375 signed32 new_boolean = (boolean ? -1 : 0); 376 hw_add_property (me, property, boolean_property, 377 &new_boolean, sizeof(new_boolean), 378 &new_boolean, sizeof(new_boolean), 379 NULL, permenant_object); 380} 381 382int 383hw_find_boolean_property (struct hw *me, 384 const char *property) 385{ 386 const struct hw_property *node; 387 unsigned_cell boolean; 388 node = hw_find_property (me, property); 389 if (node == NULL) 390 hw_abort (me, "property \"%s\" not found", property); 391 if (node->type != boolean_property) 392 hw_abort (me, "property \"%s\" of wrong type (boolean)", property); 393 ASSERT (sizeof (boolean) == node->sizeof_array); 394 memcpy (&boolean, node->array, sizeof (boolean)); 395 return boolean; 396} 397 398 399 400#if 0 401void 402hw_add_ihandle_runtime_property (struct hw *me, 403 const char *property, 404 const ihandle_runtime_property_spec *ihandle) 405{ 406 /* enter the full path as the init array */ 407 hw_add_property (me, property, ihandle_property, 408 ihandle->full_path, strlen(ihandle->full_path) + 1, 409 NULL, 0, 410 NULL, permenant_object); 411} 412#endif 413 414#if 0 415void 416hw_find_ihandle_runtime_property (struct hw *me, 417 const char *property, 418 ihandle_runtime_property_spec *ihandle) 419{ 420 struct hw_property_data *entry = find_property_data (me, property); 421 TRACE (trace_devices, 422 ("hw_find_ihandle_runtime_property(me=0x%lx, property=%s)\n", 423 (long)me, property)); 424 if (entry == NULL) 425 hw_abort (me, "property \"%s\" not found", property); 426 if (entry->property->type != ihandle_property 427 || entry->property->disposition != permenant_object) 428 hw_abort (me, "property \"%s\" of wrong type", property); 429 ASSERT (entry->init_array != NULL); 430 /* the full path */ 431 ihandle->full_path = entry->init_array; 432} 433#endif 434 435 436 437#if 0 438void 439hw_set_ihandle_property (struct hw *me, 440 const char *property, 441 hw_instance *ihandle) 442{ 443 unsigned_cell cells; 444 cells = H2BE_cell (hw_instance_to_external (ihandle)); 445 hw_set_property (me, property, ihandle_property, 446 &cells, sizeof (cells)); 447 448} 449#endif 450 451#if 0 452hw_instance * 453hw_find_ihandle_property (struct hw *me, 454 const char *property) 455{ 456 const hw_property_data *node; 457 unsigned_cell ihandle; 458 hw_instance *instance; 459 460 node = hw_find_property (me, property); 461 if (node == NULL) 462 hw_abort (me, "property \"%s\" not found", property); 463 if (node->type != ihandle_property) 464 hw_abort(me, "property \"%s\" of wrong type (ihandle)", property); 465 if (node->array == NULL) 466 hw_abort(me, "runtime property \"%s\" not yet initialized", property); 467 468 ASSERT (sizeof(ihandle) == node->sizeof_array); 469 memcpy (&ihandle, node->array, sizeof(ihandle)); 470 instance = external_to_hw_instance (me, BE2H_cell(ihandle)); 471 ASSERT (instance != NULL); 472 return instance; 473} 474#endif 475 476 477void 478hw_add_integer_property (struct hw *me, 479 const char *property, 480 signed_cell integer) 481{ 482 H2BE (integer); 483 hw_add_property (me, property, integer_property, 484 &integer, sizeof(integer), 485 &integer, sizeof(integer), 486 NULL, permenant_object); 487} 488 489signed_cell 490hw_find_integer_property (struct hw *me, 491 const char *property) 492{ 493 const struct hw_property *node; 494 signed_cell integer; 495 TRACE (trace_devices, 496 ("hw_find_integer(me=0x%lx, property=%s)\n", 497 (long)me, property)); 498 node = hw_find_property (me, property); 499 if (node == NULL) 500 hw_abort (me, "property \"%s\" not found", property); 501 if (node->type != integer_property) 502 hw_abort (me, "property \"%s\" of wrong type (integer)", property); 503 ASSERT (sizeof(integer) == node->sizeof_array); 504 memcpy (&integer, node->array, sizeof (integer)); 505 return BE2H_cell (integer); 506} 507 508int 509hw_find_integer_array_property (struct hw *me, 510 const char *property, 511 unsigned index, 512 signed_cell *integer) 513{ 514 const struct hw_property *node; 515 int sizeof_integer = sizeof (*integer); 516 signed_cell *cell; 517 TRACE (trace_devices, 518 ("hw_find_integer(me=0x%lx, property=%s)\n", 519 (long)me, property)); 520 521 /* check things sane */ 522 node = hw_find_property (me, property); 523 if (node == NULL) 524 hw_abort (me, "property \"%s\" not found", property); 525 if (node->type != integer_property 526 && node->type != array_property) 527 hw_abort (me, "property \"%s\" of wrong type (integer or array)", property); 528 if ((node->sizeof_array % sizeof_integer) != 0) 529 hw_abort (me, "property \"%s\" contains an incomplete number of cells", property); 530 if (node->sizeof_array <= sizeof_integer * index) 531 return 0; 532 533 /* Find and convert the value */ 534 cell = ((signed_cell*)node->array) + index; 535 *integer = BE2H_cell (*cell); 536 537 return node->sizeof_array / sizeof_integer; 538} 539 540 541static unsigned_cell * 542unit_address_to_cells (const hw_unit *unit, 543 unsigned_cell *cell, 544 int nr_cells) 545{ 546 int i; 547 ASSERT(nr_cells == unit->nr_cells); 548 for (i = 0; i < unit->nr_cells; i++) 549 { 550 *cell = H2BE_cell (unit->cells[i]); 551 cell += 1; 552 } 553 return cell; 554} 555 556 557static const unsigned_cell * 558cells_to_unit_address (const unsigned_cell *cell, 559 hw_unit *unit, 560 int nr_cells) 561{ 562 int i; 563 memset(unit, 0, sizeof(*unit)); 564 unit->nr_cells = nr_cells; 565 for (i = 0; i < unit->nr_cells; i++) 566 { 567 unit->cells[i] = BE2H_cell (*cell); 568 cell += 1; 569 } 570 return cell; 571} 572 573 574static unsigned 575nr_range_property_cells (struct hw *me, 576 int nr_ranges) 577{ 578 return ((hw_unit_nr_address_cells (me) 579 + hw_unit_nr_address_cells (hw_parent (me)) 580 + hw_unit_nr_size_cells (me)) 581 ) * nr_ranges; 582} 583 584void 585hw_add_range_array_property (struct hw *me, 586 const char *property, 587 const range_property_spec *ranges, 588 unsigned nr_ranges) 589{ 590 unsigned sizeof_cells = (nr_range_property_cells (me, nr_ranges) 591 * sizeof (unsigned_cell)); 592 unsigned_cell *cells = hw_zalloc (me, sizeof_cells); 593 unsigned_cell *cell; 594 int i; 595 596 /* copy the property elements over */ 597 cell = cells; 598 for (i = 0; i < nr_ranges; i++) 599 { 600 const range_property_spec *range = &ranges[i]; 601 /* copy the child address */ 602 cell = unit_address_to_cells (&range->child_address, cell, 603 hw_unit_nr_address_cells (me)); 604 /* copy the parent address */ 605 cell = unit_address_to_cells (&range->parent_address, cell, 606 hw_unit_nr_address_cells (hw_parent (me))); 607 /* copy the size */ 608 cell = unit_address_to_cells (&range->size, cell, 609 hw_unit_nr_size_cells (me)); 610 } 611 ASSERT (cell == &cells[nr_range_property_cells (me, nr_ranges)]); 612 613 /* add it */ 614 hw_add_property (me, property, range_array_property, 615 cells, sizeof_cells, 616 cells, sizeof_cells, 617 NULL, permenant_object); 618 619 hw_free (me, cells); 620} 621 622int 623hw_find_range_array_property (struct hw *me, 624 const char *property, 625 unsigned index, 626 range_property_spec *range) 627{ 628 const struct hw_property *node; 629 unsigned sizeof_entry = (nr_range_property_cells (me, 1) 630 * sizeof (unsigned_cell)); 631 const unsigned_cell *cells; 632 633 /* locate the property */ 634 node = hw_find_property (me, property); 635 if (node == NULL) 636 hw_abort (me, "property \"%s\" not found", property); 637 if (node->type != range_array_property) 638 hw_abort (me, "property \"%s\" of wrong type (range array)", property); 639 640 /* aligned ? */ 641 if ((node->sizeof_array % sizeof_entry) != 0) 642 hw_abort (me, "property \"%s\" contains an incomplete number of entries", 643 property); 644 645 /* within bounds? */ 646 if (node->sizeof_array < sizeof_entry * (index + 1)) 647 return 0; 648 649 /* find the range of interest */ 650 cells = (unsigned_cell*)((char*)node->array + sizeof_entry * index); 651 652 /* copy the child address out - converting as we go */ 653 cells = cells_to_unit_address (cells, &range->child_address, 654 hw_unit_nr_address_cells (me)); 655 656 /* copy the parent address out - converting as we go */ 657 cells = cells_to_unit_address (cells, &range->parent_address, 658 hw_unit_nr_address_cells (hw_parent (me))); 659 660 /* copy the size - converting as we go */ 661 cells = cells_to_unit_address (cells, &range->size, 662 hw_unit_nr_size_cells (me)); 663 664 return node->sizeof_array / sizeof_entry; 665} 666 667 668static unsigned 669nr_reg_property_cells (struct hw *me, 670 int nr_regs) 671{ 672 return (hw_unit_nr_address_cells (hw_parent(me)) 673 + hw_unit_nr_size_cells (hw_parent(me)) 674 ) * nr_regs; 675} 676 677void 678hw_add_reg_array_property (struct hw *me, 679 const char *property, 680 const reg_property_spec *regs, 681 unsigned nr_regs) 682{ 683 unsigned sizeof_cells = (nr_reg_property_cells (me, nr_regs) 684 * sizeof (unsigned_cell)); 685 unsigned_cell *cells = hw_zalloc (me, sizeof_cells); 686 unsigned_cell *cell; 687 int i; 688 689 /* copy the property elements over */ 690 cell = cells; 691 for (i = 0; i < nr_regs; i++) 692 { 693 const reg_property_spec *reg = ®s[i]; 694 /* copy the address */ 695 cell = unit_address_to_cells (®->address, cell, 696 hw_unit_nr_address_cells (hw_parent (me))); 697 /* copy the size */ 698 cell = unit_address_to_cells (®->size, cell, 699 hw_unit_nr_size_cells (hw_parent (me))); 700 } 701 ASSERT (cell == &cells[nr_reg_property_cells (me, nr_regs)]); 702 703 /* add it */ 704 hw_add_property (me, property, reg_array_property, 705 cells, sizeof_cells, 706 cells, sizeof_cells, 707 NULL, permenant_object); 708 709 hw_free (me, cells); 710} 711 712int 713hw_find_reg_array_property (struct hw *me, 714 const char *property, 715 unsigned index, 716 reg_property_spec *reg) 717{ 718 const struct hw_property *node; 719 unsigned sizeof_entry = (nr_reg_property_cells (me, 1) 720 * sizeof (unsigned_cell)); 721 const unsigned_cell *cells; 722 723 /* locate the property */ 724 node = hw_find_property (me, property); 725 if (node == NULL) 726 hw_abort (me, "property \"%s\" not found", property); 727 if (node->type != reg_array_property) 728 hw_abort (me, "property \"%s\" of wrong type (reg array)", property); 729 730 /* aligned ? */ 731 if ((node->sizeof_array % sizeof_entry) != 0) 732 hw_abort (me, "property \"%s\" contains an incomplete number of entries", 733 property); 734 735 /* within bounds? */ 736 if (node->sizeof_array < sizeof_entry * (index + 1)) 737 return 0; 738 739 /* find the range of interest */ 740 cells = (unsigned_cell*)((char*)node->array + sizeof_entry * index); 741 742 /* copy the address out - converting as we go */ 743 cells = cells_to_unit_address (cells, ®->address, 744 hw_unit_nr_address_cells (hw_parent (me))); 745 746 /* copy the size out - converting as we go */ 747 cells = cells_to_unit_address (cells, ®->size, 748 hw_unit_nr_size_cells (hw_parent (me))); 749 750 return node->sizeof_array / sizeof_entry; 751} 752 753 754void 755hw_add_string_property (struct hw *me, 756 const char *property, 757 const char *string) 758{ 759 hw_add_property (me, property, string_property, 760 string, strlen(string) + 1, 761 string, strlen(string) + 1, 762 NULL, permenant_object); 763} 764 765const char * 766hw_find_string_property (struct hw *me, 767 const char *property) 768{ 769 const struct hw_property *node; 770 const char *string; 771 node = hw_find_property (me, property); 772 if (node == NULL) 773 hw_abort (me, "property \"%s\" not found", property); 774 if (node->type != string_property) 775 hw_abort (me, "property \"%s\" of wrong type (string)", property); 776 string = node->array; 777 ASSERT (strlen(string) + 1 == node->sizeof_array); 778 return string; 779} 780 781void 782hw_add_string_array_property (struct hw *me, 783 const char *property, 784 const string_property_spec *strings, 785 unsigned nr_strings) 786{ 787 int sizeof_array; 788 int string_nr; 789 char *array; 790 char *chp; 791 if (nr_strings == 0) 792 hw_abort (me, "property \"%s\" must be non-null", property); 793 /* total up the size of the needed array */ 794 for (sizeof_array = 0, string_nr = 0; 795 string_nr < nr_strings; 796 string_nr ++) 797 { 798 sizeof_array += strlen (strings[string_nr]) + 1; 799 } 800 /* create the array */ 801 array = (char*) hw_zalloc (me, sizeof_array); 802 chp = array; 803 for (string_nr = 0; 804 string_nr < nr_strings; 805 string_nr++) 806 { 807 strcpy (chp, strings[string_nr]); 808 chp += strlen (chp) + 1; 809 } 810 ASSERT (chp == array + sizeof_array); 811 /* now enter it */ 812 hw_add_property (me, property, string_array_property, 813 array, sizeof_array, 814 array, sizeof_array, 815 NULL, permenant_object); 816} 817 818int 819hw_find_string_array_property (struct hw *me, 820 const char *property, 821 unsigned index, 822 string_property_spec *string) 823{ 824 const struct hw_property *node; 825 node = hw_find_property (me, property); 826 if (node == NULL) 827 hw_abort (me, "property \"%s\" not found", property); 828 switch (node->type) 829 { 830 default: 831 hw_abort (me, "property \"%s\" of wrong type", property); 832 break; 833 case string_property: 834 if (index == 0) 835 { 836 *string = node->array; 837 ASSERT (strlen(*string) + 1 == node->sizeof_array); 838 return 1; 839 } 840 break; 841 case array_property: 842 if (node->sizeof_array == 0 843 || ((char*)node->array)[node->sizeof_array - 1] != '\0') 844 hw_abort (me, "property \"%s\" invalid for string array", property); 845 /* FALL THROUGH */ 846 case string_array_property: 847 ASSERT (node->sizeof_array > 0); 848 ASSERT (((char*)node->array)[node->sizeof_array - 1] == '\0'); 849 { 850 const char *chp = node->array; 851 int nr_entries = 0; 852 /* count the number of strings, keeping an eye out for the one 853 we're looking for */ 854 *string = chp; 855 do 856 { 857 if (*chp == '\0') 858 { 859 /* next string */ 860 nr_entries++; 861 chp++; 862 if (nr_entries == index) 863 *string = chp; 864 } 865 else 866 { 867 chp++; 868 } 869 } while (chp < (char*)node->array + node->sizeof_array); 870 if (index < nr_entries) 871 return nr_entries; 872 else 873 { 874 *string = NULL; 875 return 0; 876 } 877 } 878 break; 879 } 880 return 0; 881} 882 883void 884hw_add_duplicate_property (struct hw *me, 885 const char *property, 886 const struct hw_property *original) 887{ 888 struct hw_property_data *master; 889 TRACE (trace_devices, 890 ("hw_add_duplicate_property(me=0x%lx, property=%s, ...)\n", 891 (long)me, property)); 892 if (original->disposition != permenant_object) 893 hw_abort (me, "Can only duplicate permenant objects"); 894 /* find the original's master */ 895 master = original->owner->properties_of_hw; 896 while (master->property != original) 897 { 898 master = master->next; 899 ASSERT(master != NULL); 900 } 901 /* now duplicate it */ 902 hw_add_property (me, property, 903 original->type, 904 master->init_array, master->sizeof_init_array, 905 original->array, original->sizeof_array, 906 original, permenant_object); 907} 908