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 = &regs[i];
696       /* copy the address */
697       cell = unit_address_to_cells (&reg->address, cell,
698 				    hw_unit_nr_address_cells (hw_parent (me)));
699       /* copy the size */
700       cell = unit_address_to_cells (&reg->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, &reg->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, &reg->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