OSDN Git Service

d8cab87bd6f6a1d8bc64c8739978cbc5ecd59500
[pf3gnuchains/pf3gnuchains3x.git] / sim / common / hw-properties.c
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
40 struct 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
47 void
48 create_hw_property_data (struct hw *me)
49 {
50 }
51
52 void
53 delete_hw_property_data (struct hw *me)
54 {
55 }
56
57
58 /* Device Properties: */
59
60 static struct hw_property_data *
61 find_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
77 static void
78 hw_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
129 static void
130 hw_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
169 static void
170 clean_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
203 void
204 hw_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
242 void
243 hw_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
293 const struct hw_property *
294 hw_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
310 const struct hw_property *
311 hw_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
335 void
336 hw_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
346 void
347 hw_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
355 const struct hw_property *
356 hw_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
370 void
371 hw_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
382 int
383 hw_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
401 void
402 hw_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
415 void
416 hw_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
438 void
439 hw_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
452 hw_instance *
453 hw_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
477 void
478 hw_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
489 signed_cell
490 hw_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
508 int
509 hw_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
541 static unsigned_cell *
542 unit_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
557 static const unsigned_cell *
558 cells_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
574 static unsigned
575 nr_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
584 void
585 hw_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
622 int
623 hw_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
668 static unsigned
669 nr_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
677 void
678 hw_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 = &regs[i];
694       /* copy the address */
695       cell = unit_address_to_cells (&reg->address, cell,
696                                     hw_unit_nr_address_cells (hw_parent (me)));
697       /* copy the size */
698       cell = unit_address_to_cells (&reg->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
712 int
713 hw_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, &reg->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, &reg->size,
748                                  hw_unit_nr_size_cells (hw_parent (me)));
749   
750   return node->sizeof_array / sizeof_entry;
751 }
752
753
754 void
755 hw_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
765 const char *
766 hw_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
781 void
782 hw_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
818 int
819 hw_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
883 void
884 hw_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 }