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