xref: /netbsd-src/external/gpl3/gdb/dist/sim/common/hw-properties.c (revision 88241920d21b339bf319c0e979ffda80c49a2936)
14e98e3e1Schristos /* The common simulator framework for GDB, the GNU Debugger.
24e98e3e1Schristos 
3*88241920Schristos    Copyright 2002-2024 Free Software Foundation, Inc.
44e98e3e1Schristos 
54e98e3e1Schristos    Contributed by Andrew Cagney and Red Hat.
64e98e3e1Schristos 
74e98e3e1Schristos    This file is part of GDB.
84e98e3e1Schristos 
94e98e3e1Schristos    This program is free software; you can redistribute it and/or modify
104e98e3e1Schristos    it under the terms of the GNU General Public License as published by
114e98e3e1Schristos    the Free Software Foundation; either version 3 of the License, or
124e98e3e1Schristos    (at your option) any later version.
134e98e3e1Schristos 
144e98e3e1Schristos    This program is distributed in the hope that it will be useful,
154e98e3e1Schristos    but WITHOUT ANY WARRANTY; without even the implied warranty of
164e98e3e1Schristos    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
174e98e3e1Schristos    GNU General Public License for more details.
184e98e3e1Schristos 
194e98e3e1Schristos    You should have received a copy of the GNU General Public License
204e98e3e1Schristos    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
214e98e3e1Schristos 
224b169a6bSchristos /* This must come before any other includes.  */
234b169a6bSchristos #include "defs.h"
244b169a6bSchristos 
254b169a6bSchristos #include <string.h>
264b169a6bSchristos 
274e98e3e1Schristos #include "hw-main.h"
284e98e3e1Schristos #include "hw-base.h"
294e98e3e1Schristos 
304e98e3e1Schristos #include "sim-io.h"
314e98e3e1Schristos #include "sim-assert.h"
324e98e3e1Schristos 
334e98e3e1Schristos /* property entries */
344e98e3e1Schristos 
354e98e3e1Schristos struct hw_property_data
364e98e3e1Schristos {
374e98e3e1Schristos   struct hw_property_data *next;
384e98e3e1Schristos   struct hw_property *property;
394e98e3e1Schristos   const void *init_array;
404e98e3e1Schristos   unsigned sizeof_init_array;
414e98e3e1Schristos };
424e98e3e1Schristos 
434e98e3e1Schristos void
444e98e3e1Schristos create_hw_property_data (struct hw *me)
454e98e3e1Schristos {
464e98e3e1Schristos }
474e98e3e1Schristos 
484e98e3e1Schristos void
494e98e3e1Schristos delete_hw_property_data (struct hw *me)
504e98e3e1Schristos {
514e98e3e1Schristos }
524e98e3e1Schristos 
534e98e3e1Schristos 
544e98e3e1Schristos /* Device Properties: */
554e98e3e1Schristos 
564e98e3e1Schristos static struct hw_property_data *
574e98e3e1Schristos find_property_data (struct hw *me,
584e98e3e1Schristos 		    const char *property)
594e98e3e1Schristos {
604e98e3e1Schristos   struct hw_property_data *entry;
614e98e3e1Schristos   ASSERT (property != NULL);
624e98e3e1Schristos   entry = me->properties_of_hw;
634e98e3e1Schristos   while (entry != NULL)
644e98e3e1Schristos     {
654e98e3e1Schristos       if (strcmp (entry->property->name, property) == 0)
664e98e3e1Schristos 	return entry;
674e98e3e1Schristos       entry = entry->next;
684e98e3e1Schristos     }
694e98e3e1Schristos   return NULL;
704e98e3e1Schristos }
714e98e3e1Schristos 
724e98e3e1Schristos 
734e98e3e1Schristos static void
744e98e3e1Schristos hw_add_property (struct hw *me,
754e98e3e1Schristos 		 const char *property,
764e98e3e1Schristos 		 hw_property_type type,
774e98e3e1Schristos 		 const void *init_array,
784e98e3e1Schristos 		 unsigned sizeof_init_array,
794e98e3e1Schristos 		 const void *array,
804e98e3e1Schristos 		 unsigned sizeof_array,
814e98e3e1Schristos 		 const struct hw_property *original,
824e98e3e1Schristos 		 object_disposition disposition)
834e98e3e1Schristos {
844e98e3e1Schristos   struct hw_property_data *new_entry = NULL;
854e98e3e1Schristos   struct hw_property *new_value = NULL;
864e98e3e1Schristos 
874e98e3e1Schristos   /* find the list end */
884e98e3e1Schristos   struct hw_property_data **insertion_point = &me->properties_of_hw;
894e98e3e1Schristos   while (*insertion_point != NULL)
904e98e3e1Schristos     {
914e98e3e1Schristos       if (strcmp ((*insertion_point)->property->name, property) == 0)
924e98e3e1Schristos 	return;
934e98e3e1Schristos       insertion_point = &(*insertion_point)->next;
944e98e3e1Schristos     }
954e98e3e1Schristos 
964e98e3e1Schristos   /* create a new value */
974e98e3e1Schristos   new_value = HW_ZALLOC (me, struct hw_property);
984e98e3e1Schristos   new_value->name = (char *) strdup (property);
994e98e3e1Schristos   new_value->type = type;
1004e98e3e1Schristos   if (sizeof_array > 0)
1014e98e3e1Schristos     {
1024e98e3e1Schristos       void *new_array = hw_zalloc (me, sizeof_array);
1034e98e3e1Schristos       memcpy (new_array, array, sizeof_array);
1044e98e3e1Schristos       new_value->array = new_array;
1054e98e3e1Schristos       new_value->sizeof_array = sizeof_array;
1064e98e3e1Schristos     }
1074e98e3e1Schristos   new_value->owner = me;
1084e98e3e1Schristos   new_value->original = original;
1094e98e3e1Schristos   new_value->disposition = disposition;
1104e98e3e1Schristos 
1114e98e3e1Schristos   /* insert the value into the list */
1124e98e3e1Schristos   new_entry = HW_ZALLOC (me, struct hw_property_data);
1134e98e3e1Schristos   *insertion_point = new_entry;
1144e98e3e1Schristos   if (sizeof_init_array > 0)
1154e98e3e1Schristos     {
1164e98e3e1Schristos       void *new_init_array = hw_zalloc (me, sizeof_init_array);
1174e98e3e1Schristos       memcpy (new_init_array, init_array, sizeof_init_array);
1184e98e3e1Schristos       new_entry->init_array = new_init_array;
1194e98e3e1Schristos       new_entry->sizeof_init_array = sizeof_init_array;
1204e98e3e1Schristos     }
1214e98e3e1Schristos   new_entry->property = new_value;
1224e98e3e1Schristos }
1234e98e3e1Schristos 
1244e98e3e1Schristos 
1254e98e3e1Schristos static void
1264e98e3e1Schristos hw_set_property (struct hw *me,
1274e98e3e1Schristos 		 const char *property,
1284e98e3e1Schristos 		 hw_property_type type,
1294e98e3e1Schristos 		 const void *array,
1304e98e3e1Schristos 		 int sizeof_array)
1314e98e3e1Schristos {
1324e98e3e1Schristos   /* find the property */
1334e98e3e1Schristos   struct hw_property_data *entry = find_property_data (me, property);
1344e98e3e1Schristos   if (entry != NULL)
1354e98e3e1Schristos     {
1364e98e3e1Schristos       /* existing property - update it */
1374e98e3e1Schristos       void *new_array = 0;
1384e98e3e1Schristos       struct hw_property *value = entry->property;
1394e98e3e1Schristos       /* check the type matches */
1404e98e3e1Schristos       if (value->type != type)
1414e98e3e1Schristos 	hw_abort (me, "conflict between type of new and old value for property %s", property);
1424e98e3e1Schristos       /* replace its value */
1434e98e3e1Schristos       if (value->array != NULL)
1444e98e3e1Schristos 	hw_free (me, (void*)value->array);
1454e98e3e1Schristos       new_array = (sizeof_array > 0
1464e98e3e1Schristos 		   ? hw_zalloc (me, sizeof_array)
1474e98e3e1Schristos 		   : (void*)0);
1484e98e3e1Schristos       value->array = new_array;
1494e98e3e1Schristos       value->sizeof_array = sizeof_array;
1504e98e3e1Schristos       if (sizeof_array > 0)
1514e98e3e1Schristos 	memcpy (new_array, array, sizeof_array);
1524e98e3e1Schristos       return;
1534e98e3e1Schristos     }
1544e98e3e1Schristos   else
1554e98e3e1Schristos     {
1564e98e3e1Schristos       /* new property - create it */
1574e98e3e1Schristos       hw_add_property (me, property, type,
1584e98e3e1Schristos 		       NULL, 0, array, sizeof_array,
1594e98e3e1Schristos 		       NULL, temporary_object);
1604e98e3e1Schristos     }
1614e98e3e1Schristos }
1624e98e3e1Schristos 
1634e98e3e1Schristos 
1644e98e3e1Schristos #if 0
1654e98e3e1Schristos static void
1664e98e3e1Schristos clean_hw_properties (struct hw *me)
1674e98e3e1Schristos {
1684e98e3e1Schristos   struct hw_property_data **delete_point = &me->properties_of_hw;
1694e98e3e1Schristos   while (*delete_point != NULL)
1704e98e3e1Schristos     {
1714e98e3e1Schristos       struct hw_property_data *current = *delete_point;
1724e98e3e1Schristos       switch (current->property->disposition)
1734e98e3e1Schristos 	{
174*88241920Schristos 	case permanent_object:
1754e98e3e1Schristos 	  /* zap the current value, will be initialized later */
1764e98e3e1Schristos 	  ASSERT (current->init_array != NULL);
1774e98e3e1Schristos 	  if (current->property->array != NULL)
1784e98e3e1Schristos 	    {
1794e98e3e1Schristos 	      hw_free (me, (void*)current->property->array);
1804e98e3e1Schristos 	      current->property->array = NULL;
1814e98e3e1Schristos 	    }
1824e98e3e1Schristos 	  delete_point = &(*delete_point)->next;
1834e98e3e1Schristos 	  break;
1844e98e3e1Schristos 	case temporary_object:
1854e98e3e1Schristos 	  /* zap the actual property, was created during simulation run */
1864e98e3e1Schristos 	  ASSERT (current->init_array == NULL);
1874e98e3e1Schristos 	  *delete_point = current->next;
1884e98e3e1Schristos 	  if (current->property->array != NULL)
1894e98e3e1Schristos 	    hw_free (me, (void*)current->property->array);
1904e98e3e1Schristos 	  hw_free (me, current->property);
1914e98e3e1Schristos 	  hw_free (me, current);
1924e98e3e1Schristos 	  break;
1934e98e3e1Schristos 	}
1944e98e3e1Schristos     }
1954e98e3e1Schristos }
1964e98e3e1Schristos #endif
1974e98e3e1Schristos 
1984e98e3e1Schristos #if 0
1994e98e3e1Schristos void
2004e98e3e1Schristos hw_init_static_properties (SIM_DESC sd,
2014e98e3e1Schristos 			   struct hw *me,
2024e98e3e1Schristos 			   void *data)
2034e98e3e1Schristos {
2044e98e3e1Schristos   struct hw_property_data *property;
2054e98e3e1Schristos   for (property = me->properties_of_hw;
2064e98e3e1Schristos        property != NULL;
2074e98e3e1Schristos        property = property->next)
2084e98e3e1Schristos     {
2094e98e3e1Schristos       ASSERT (property->init_array != NULL);
2104e98e3e1Schristos       ASSERT (property->property->array == NULL);
211*88241920Schristos       ASSERT (property->property->disposition == permanent_object);
2124e98e3e1Schristos       switch (property->property->type)
2134e98e3e1Schristos 	{
2144e98e3e1Schristos 	case array_property:
2154e98e3e1Schristos 	case boolean_property:
2164e98e3e1Schristos 	case range_array_property:
2174e98e3e1Schristos 	case reg_array_property:
2184e98e3e1Schristos 	case string_property:
2194e98e3e1Schristos 	case string_array_property:
2204e98e3e1Schristos 	case integer_property:
2214e98e3e1Schristos 	  /* delete the property, and replace it with the original */
2224e98e3e1Schristos 	  hw_set_property (me, property->property->name,
2234e98e3e1Schristos 			   property->property->type,
2244e98e3e1Schristos 			   property->init_array,
2254e98e3e1Schristos 			   property->sizeof_init_array);
2264e98e3e1Schristos 	  break;
2274e98e3e1Schristos #if 0
2284e98e3e1Schristos 	case ihandle_property:
2294e98e3e1Schristos 	  break;
2304e98e3e1Schristos #endif
2314e98e3e1Schristos 	}
2324e98e3e1Schristos     }
2334e98e3e1Schristos }
2344e98e3e1Schristos #endif
2354e98e3e1Schristos 
2364e98e3e1Schristos 
2374e98e3e1Schristos #if 0
2384e98e3e1Schristos void
2394e98e3e1Schristos hw_init_runtime_properties (SIM_DESC sd,
2404e98e3e1Schristos 			    struct hw *me,
2414e98e3e1Schristos 			    void *data)
2424e98e3e1Schristos {
2434e98e3e1Schristos   struct hw_property_data *property;
2444e98e3e1Schristos   for (property = me->properties_of_hw;
2454e98e3e1Schristos        property != NULL;
2464e98e3e1Schristos        property = property->next)
2474e98e3e1Schristos     {
2484e98e3e1Schristos       switch (property->property->disposition)
2494e98e3e1Schristos 	{
250*88241920Schristos 	case permanent_object:
2514e98e3e1Schristos 	  switch (property->property->type)
2524e98e3e1Schristos 	    {
2534e98e3e1Schristos #if 0
2544e98e3e1Schristos 	    case ihandle_property:
2554e98e3e1Schristos 	      {
2564e98e3e1Schristos 		struct hw_instance *ihandle;
2574e98e3e1Schristos 		ihandle_runtime_property_spec spec;
2584e98e3e1Schristos 		ASSERT (property->init_array != NULL);
2594e98e3e1Schristos 		ASSERT (property->property->array == NULL);
2604e98e3e1Schristos 		hw_find_ihandle_runtime_property (me, property->property->name, &spec);
2614e98e3e1Schristos 		ihandle = tree_instance (me, spec.full_path);
2624e98e3e1Schristos 		hw_set_ihandle_property (me, property->property->name, ihandle);
2634e98e3e1Schristos 		break;
2644e98e3e1Schristos 	      }
2654e98e3e1Schristos #endif
2664e98e3e1Schristos 	    case array_property:
2674e98e3e1Schristos 	    case boolean_property:
2684e98e3e1Schristos 	    case range_array_property:
2694e98e3e1Schristos 	    case integer_property:
2704e98e3e1Schristos 	    case reg_array_property:
2714e98e3e1Schristos 	    case string_property:
2724e98e3e1Schristos 	    case string_array_property:
2734e98e3e1Schristos 	      ASSERT (property->init_array != NULL);
2744e98e3e1Schristos 	      ASSERT (property->property->array != NULL);
2754e98e3e1Schristos 	      break;
2764e98e3e1Schristos 	    }
2774e98e3e1Schristos 	  break;
2784e98e3e1Schristos 	case temporary_object:
2794e98e3e1Schristos 	  ASSERT (property->init_array == NULL);
2804e98e3e1Schristos 	  ASSERT (property->property->array != NULL);
2814e98e3e1Schristos 	  break;
2824e98e3e1Schristos 	}
2834e98e3e1Schristos     }
2844e98e3e1Schristos }
2854e98e3e1Schristos #endif
2864e98e3e1Schristos 
2874e98e3e1Schristos 
2884e98e3e1Schristos 
2894e98e3e1Schristos const struct hw_property *
2904e98e3e1Schristos hw_next_property (const struct hw_property *property)
2914e98e3e1Schristos {
2924e98e3e1Schristos   /* find the property in the list */
2934e98e3e1Schristos   struct hw *owner = property->owner;
2944e98e3e1Schristos   struct hw_property_data *entry = owner->properties_of_hw;
2954e98e3e1Schristos   while (entry != NULL && entry->property != property)
2964e98e3e1Schristos     entry = entry->next;
2974e98e3e1Schristos   /* now return the following property */
2984e98e3e1Schristos   ASSERT (entry != NULL); /* must be a member! */
2994e98e3e1Schristos   if (entry->next != NULL)
3004e98e3e1Schristos     return entry->next->property;
3014e98e3e1Schristos   else
3024e98e3e1Schristos     return NULL;
3034e98e3e1Schristos }
3044e98e3e1Schristos 
3054e98e3e1Schristos 
3064e98e3e1Schristos const struct hw_property *
3074e98e3e1Schristos hw_find_property (struct hw *me,
3084e98e3e1Schristos 		  const char *property)
3094e98e3e1Schristos {
3104e98e3e1Schristos   if (me == NULL)
3114e98e3e1Schristos     {
3124e98e3e1Schristos       return NULL;
3134e98e3e1Schristos     }
3144e98e3e1Schristos   else if (property == NULL || strcmp (property, "") == 0)
3154e98e3e1Schristos     {
3164e98e3e1Schristos       if (me->properties_of_hw == NULL)
3174e98e3e1Schristos 	return NULL;
3184e98e3e1Schristos       else
3194e98e3e1Schristos 	return me->properties_of_hw->property;
3204e98e3e1Schristos     }
3214e98e3e1Schristos   else
3224e98e3e1Schristos     {
3234e98e3e1Schristos       struct hw_property_data *entry = find_property_data (me, property);
3244e98e3e1Schristos       if (entry != NULL)
3254e98e3e1Schristos 	return entry->property;
3264e98e3e1Schristos     }
3274e98e3e1Schristos   return NULL;
3284e98e3e1Schristos }
3294e98e3e1Schristos 
3304e98e3e1Schristos 
3314e98e3e1Schristos void
3324e98e3e1Schristos hw_add_array_property (struct hw *me,
3334e98e3e1Schristos 		       const char *property,
3344e98e3e1Schristos 		       const void *array,
3354e98e3e1Schristos 		       int sizeof_array)
3364e98e3e1Schristos {
3374e98e3e1Schristos   hw_add_property (me, property, array_property,
3384e98e3e1Schristos 		   array, sizeof_array, array, sizeof_array,
339*88241920Schristos 		   NULL, permanent_object);
3404e98e3e1Schristos }
3414e98e3e1Schristos 
3424e98e3e1Schristos void
3434e98e3e1Schristos hw_set_array_property (struct hw *me,
3444e98e3e1Schristos 		       const char *property,
3454e98e3e1Schristos 		       const void *array,
3464e98e3e1Schristos 		       int sizeof_array)
3474e98e3e1Schristos {
3484e98e3e1Schristos   hw_set_property (me, property, array_property, array, sizeof_array);
3494e98e3e1Schristos }
3504e98e3e1Schristos 
3514e98e3e1Schristos const struct hw_property *
3524e98e3e1Schristos hw_find_array_property (struct hw *me,
3534e98e3e1Schristos 			const char *property)
3544e98e3e1Schristos {
3554e98e3e1Schristos   const struct hw_property *node;
3564e98e3e1Schristos   node = hw_find_property (me, property);
3574e98e3e1Schristos   if (node == NULL)
3584e98e3e1Schristos     hw_abort (me, "property \"%s\" not found", property);
3594e98e3e1Schristos   if (node->type != array_property)
3604e98e3e1Schristos     hw_abort (me, "property \"%s\" of wrong type (array)", property);
3614e98e3e1Schristos   return node;
3624e98e3e1Schristos }
3634e98e3e1Schristos 
3644e98e3e1Schristos 
3654e98e3e1Schristos 
3664e98e3e1Schristos void
3674e98e3e1Schristos hw_add_boolean_property (struct hw *me,
3684e98e3e1Schristos 			 const char *property,
3694e98e3e1Schristos 			 int boolean)
3704e98e3e1Schristos {
3714b169a6bSchristos   int32_t new_boolean = (boolean ? -1 : 0);
3724e98e3e1Schristos   hw_add_property (me, property, boolean_property,
3734e98e3e1Schristos 		   &new_boolean, sizeof (new_boolean),
3744e98e3e1Schristos 		   &new_boolean, sizeof (new_boolean),
375*88241920Schristos 		   NULL, permanent_object);
3764e98e3e1Schristos }
3774e98e3e1Schristos 
3784e98e3e1Schristos int
3794e98e3e1Schristos hw_find_boolean_property (struct hw *me,
3804e98e3e1Schristos 			  const char *property)
3814e98e3e1Schristos {
3824e98e3e1Schristos   const struct hw_property *node;
3834e98e3e1Schristos   unsigned_cell boolean;
3844e98e3e1Schristos   node = hw_find_property (me, property);
3854e98e3e1Schristos   if (node == NULL)
3864e98e3e1Schristos     hw_abort (me, "property \"%s\" not found", property);
3874e98e3e1Schristos   if (node->type != boolean_property)
3884e98e3e1Schristos     hw_abort (me, "property \"%s\" of wrong type (boolean)", property);
3894e98e3e1Schristos   ASSERT (sizeof (boolean) == node->sizeof_array);
3904e98e3e1Schristos   memcpy (&boolean, node->array, sizeof (boolean));
3914e98e3e1Schristos   return boolean;
3924e98e3e1Schristos }
3934e98e3e1Schristos 
3944e98e3e1Schristos 
3954e98e3e1Schristos 
3964e98e3e1Schristos #if 0
3974e98e3e1Schristos void
3984e98e3e1Schristos hw_add_ihandle_runtime_property (struct hw *me,
3994e98e3e1Schristos 				 const char *property,
4004e98e3e1Schristos 				 const ihandle_runtime_property_spec *ihandle)
4014e98e3e1Schristos {
4024e98e3e1Schristos   /* enter the full path as the init array */
4034e98e3e1Schristos   hw_add_property (me, property, ihandle_property,
4044e98e3e1Schristos 		   ihandle->full_path, strlen (ihandle->full_path) + 1,
4054e98e3e1Schristos 		   NULL, 0,
406*88241920Schristos 		   NULL, permanent_object);
4074e98e3e1Schristos }
4084e98e3e1Schristos #endif
4094e98e3e1Schristos 
4104e98e3e1Schristos #if 0
4114e98e3e1Schristos void
4124e98e3e1Schristos hw_find_ihandle_runtime_property (struct hw *me,
4134e98e3e1Schristos 				  const char *property,
4144e98e3e1Schristos 				  ihandle_runtime_property_spec *ihandle)
4154e98e3e1Schristos {
4164e98e3e1Schristos   struct hw_property_data *entry = find_property_data (me, property);
4174e98e3e1Schristos   if (entry == NULL)
4184e98e3e1Schristos     hw_abort (me, "property \"%s\" not found", property);
4194e98e3e1Schristos   if (entry->property->type != ihandle_property
420*88241920Schristos       || entry->property->disposition != permanent_object)
4214e98e3e1Schristos     hw_abort (me, "property \"%s\" of wrong type", property);
4224e98e3e1Schristos   ASSERT (entry->init_array != NULL);
4234e98e3e1Schristos   /* the full path */
4244e98e3e1Schristos   ihandle->full_path = entry->init_array;
4254e98e3e1Schristos }
4264e98e3e1Schristos #endif
4274e98e3e1Schristos 
4284e98e3e1Schristos 
4294e98e3e1Schristos 
4304e98e3e1Schristos #if 0
4314e98e3e1Schristos void
4324e98e3e1Schristos hw_set_ihandle_property (struct hw *me,
4334e98e3e1Schristos 			 const char *property,
4344e98e3e1Schristos 			 hw_instance *ihandle)
4354e98e3e1Schristos {
4364e98e3e1Schristos   unsigned_cell cells;
4374e98e3e1Schristos   cells = H2BE_cell (hw_instance_to_external (ihandle));
4384e98e3e1Schristos   hw_set_property (me, property, ihandle_property,
4394e98e3e1Schristos 		   &cells, sizeof (cells));
4404e98e3e1Schristos 
4414e98e3e1Schristos }
4424e98e3e1Schristos #endif
4434e98e3e1Schristos 
4444e98e3e1Schristos #if 0
4454e98e3e1Schristos hw_instance *
4464e98e3e1Schristos hw_find_ihandle_property (struct hw *me,
4474e98e3e1Schristos 			  const char *property)
4484e98e3e1Schristos {
4494e98e3e1Schristos   const hw_property_data *node;
4504e98e3e1Schristos   unsigned_cell ihandle;
4514e98e3e1Schristos   hw_instance *instance;
4524e98e3e1Schristos 
4534e98e3e1Schristos   node = hw_find_property (me, property);
4544e98e3e1Schristos   if (node == NULL)
4554e98e3e1Schristos     hw_abort (me, "property \"%s\" not found", property);
4564e98e3e1Schristos   if (node->type != ihandle_property)
4574e98e3e1Schristos     hw_abort (me, "property \"%s\" of wrong type (ihandle)", property);
4584e98e3e1Schristos   if (node->array == NULL)
4594e98e3e1Schristos     hw_abort (me, "runtime property \"%s\" not yet initialized", property);
4604e98e3e1Schristos 
4614e98e3e1Schristos   ASSERT (sizeof (ihandle) == node->sizeof_array);
4624e98e3e1Schristos   memcpy (&ihandle, node->array, sizeof (ihandle));
4634e98e3e1Schristos   instance = external_to_hw_instance (me, BE2H_cell (ihandle));
4644e98e3e1Schristos   ASSERT (instance != NULL);
4654e98e3e1Schristos   return instance;
4664e98e3e1Schristos }
4674e98e3e1Schristos #endif
4684e98e3e1Schristos 
4694e98e3e1Schristos 
4704e98e3e1Schristos void
4714e98e3e1Schristos hw_add_integer_property (struct hw *me,
4724e98e3e1Schristos 			 const char *property,
4734e98e3e1Schristos 			 signed_cell integer)
4744e98e3e1Schristos {
4754e98e3e1Schristos   H2BE (integer);
4764e98e3e1Schristos   hw_add_property (me, property, integer_property,
4774e98e3e1Schristos 		   &integer, sizeof (integer),
4784e98e3e1Schristos 		   &integer, sizeof (integer),
479*88241920Schristos 		   NULL, permanent_object);
4804e98e3e1Schristos }
4814e98e3e1Schristos 
4824e98e3e1Schristos signed_cell
4834e98e3e1Schristos hw_find_integer_property (struct hw *me,
4844e98e3e1Schristos 			  const char *property)
4854e98e3e1Schristos {
4864e98e3e1Schristos   const struct hw_property *node;
4874e98e3e1Schristos   signed_cell integer;
4884e98e3e1Schristos   node = hw_find_property (me, property);
4894e98e3e1Schristos   if (node == NULL)
4904e98e3e1Schristos     hw_abort (me, "property \"%s\" not found", property);
4914e98e3e1Schristos   if (node->type != integer_property)
4924e98e3e1Schristos     hw_abort (me, "property \"%s\" of wrong type (integer)", property);
4934e98e3e1Schristos   ASSERT (sizeof (integer) == node->sizeof_array);
4944e98e3e1Schristos   memcpy (&integer, node->array, sizeof (integer));
4954e98e3e1Schristos   return BE2H_cell (integer);
4964e98e3e1Schristos }
4974e98e3e1Schristos 
4984e98e3e1Schristos int
4994e98e3e1Schristos hw_find_integer_array_property (struct hw *me,
5004e98e3e1Schristos 				const char *property,
5014e98e3e1Schristos 				unsigned index,
5024e98e3e1Schristos 				signed_cell *integer)
5034e98e3e1Schristos {
5044e98e3e1Schristos   const struct hw_property *node;
5054e98e3e1Schristos   int sizeof_integer = sizeof (*integer);
5064e98e3e1Schristos   signed_cell *cell;
5074e98e3e1Schristos 
5084e98e3e1Schristos   /* check things sane */
5094e98e3e1Schristos   node = hw_find_property (me, property);
5104e98e3e1Schristos   if (node == NULL)
5114e98e3e1Schristos     hw_abort (me, "property \"%s\" not found", property);
5124e98e3e1Schristos   if (node->type != integer_property
5134e98e3e1Schristos       && node->type != array_property)
5144e98e3e1Schristos     hw_abort (me, "property \"%s\" of wrong type (integer or array)", property);
5154e98e3e1Schristos   if ((node->sizeof_array % sizeof_integer) != 0)
5164e98e3e1Schristos     hw_abort (me, "property \"%s\" contains an incomplete number of cells", property);
5174e98e3e1Schristos   if (node->sizeof_array <= sizeof_integer * index)
5184e98e3e1Schristos     return 0;
5194e98e3e1Schristos 
5204e98e3e1Schristos   /* Find and convert the value */
5214e98e3e1Schristos   cell = ((signed_cell*)node->array) + index;
5224e98e3e1Schristos   *integer = BE2H_cell (*cell);
5234e98e3e1Schristos 
5244e98e3e1Schristos   return node->sizeof_array / sizeof_integer;
5254e98e3e1Schristos }
5264e98e3e1Schristos 
5274e98e3e1Schristos 
5284e98e3e1Schristos static unsigned_cell *
5294e98e3e1Schristos unit_address_to_cells (const hw_unit *unit,
5304e98e3e1Schristos 		       unsigned_cell *cell,
5314e98e3e1Schristos 		       int nr_cells)
5324e98e3e1Schristos {
5334e98e3e1Schristos   int i;
5344e98e3e1Schristos   ASSERT (nr_cells == unit->nr_cells);
5354e98e3e1Schristos   for (i = 0; i < unit->nr_cells; i++)
5364e98e3e1Schristos     {
5374e98e3e1Schristos       *cell = H2BE_cell (unit->cells[i]);
5384e98e3e1Schristos       cell += 1;
5394e98e3e1Schristos     }
5404e98e3e1Schristos   return cell;
5414e98e3e1Schristos }
5424e98e3e1Schristos 
5434e98e3e1Schristos 
5444e98e3e1Schristos static const unsigned_cell *
5454e98e3e1Schristos cells_to_unit_address (const unsigned_cell *cell,
5464e98e3e1Schristos 		       hw_unit *unit,
5474e98e3e1Schristos 		       int nr_cells)
5484e98e3e1Schristos {
5494e98e3e1Schristos   int i;
5504e98e3e1Schristos   memset (unit, 0, sizeof (*unit));
5514e98e3e1Schristos   unit->nr_cells = nr_cells;
5524e98e3e1Schristos   for (i = 0; i < unit->nr_cells; i++)
5534e98e3e1Schristos     {
5544e98e3e1Schristos       unit->cells[i] = BE2H_cell (*cell);
5554e98e3e1Schristos       cell += 1;
5564e98e3e1Schristos     }
5574e98e3e1Schristos   return cell;
5584e98e3e1Schristos }
5594e98e3e1Schristos 
5604e98e3e1Schristos 
5614e98e3e1Schristos static unsigned
5624e98e3e1Schristos nr_range_property_cells (struct hw *me,
5634e98e3e1Schristos 			 int nr_ranges)
5644e98e3e1Schristos {
5654e98e3e1Schristos   return ((hw_unit_nr_address_cells (me)
5664e98e3e1Schristos 	   + hw_unit_nr_address_cells (hw_parent (me))
5674e98e3e1Schristos 	   + hw_unit_nr_size_cells (me))
5684e98e3e1Schristos 	  ) * nr_ranges;
5694e98e3e1Schristos }
5704e98e3e1Schristos 
5714e98e3e1Schristos void
5724e98e3e1Schristos hw_add_range_array_property (struct hw *me,
5734e98e3e1Schristos 			     const char *property,
5744e98e3e1Schristos 			     const range_property_spec *ranges,
5754e98e3e1Schristos 			     unsigned nr_ranges)
5764e98e3e1Schristos {
5774e98e3e1Schristos   unsigned sizeof_cells = (nr_range_property_cells (me, nr_ranges)
5784e98e3e1Schristos 			   * sizeof (unsigned_cell));
5794e98e3e1Schristos   unsigned_cell *cells = hw_zalloc (me, sizeof_cells);
5804e98e3e1Schristos   unsigned_cell *cell;
5814e98e3e1Schristos   int i;
5824e98e3e1Schristos 
5834e98e3e1Schristos   /* copy the property elements over */
5844e98e3e1Schristos   cell = cells;
5854e98e3e1Schristos   for (i = 0; i < nr_ranges; i++)
5864e98e3e1Schristos     {
5874e98e3e1Schristos       const range_property_spec *range = &ranges[i];
5884e98e3e1Schristos       /* copy the child address */
5894e98e3e1Schristos       cell = unit_address_to_cells (&range->child_address, cell,
5904e98e3e1Schristos 				    hw_unit_nr_address_cells (me));
5914e98e3e1Schristos       /* copy the parent address */
5924e98e3e1Schristos       cell = unit_address_to_cells (&range->parent_address, cell,
5934e98e3e1Schristos 				    hw_unit_nr_address_cells (hw_parent (me)));
5944e98e3e1Schristos       /* copy the size */
5954e98e3e1Schristos       cell = unit_address_to_cells (&range->size, cell,
5964e98e3e1Schristos 				    hw_unit_nr_size_cells (me));
5974e98e3e1Schristos     }
5984e98e3e1Schristos   ASSERT (cell == &cells[nr_range_property_cells (me, nr_ranges)]);
5994e98e3e1Schristos 
6004e98e3e1Schristos   /* add it */
6014e98e3e1Schristos   hw_add_property (me, property, range_array_property,
6024e98e3e1Schristos 		   cells, sizeof_cells,
6034e98e3e1Schristos 		   cells, sizeof_cells,
604*88241920Schristos 		   NULL, permanent_object);
6054e98e3e1Schristos 
6064e98e3e1Schristos   hw_free (me, cells);
6074e98e3e1Schristos }
6084e98e3e1Schristos 
6094e98e3e1Schristos int
6104e98e3e1Schristos hw_find_range_array_property (struct hw *me,
6114e98e3e1Schristos 			      const char *property,
6124e98e3e1Schristos 			      unsigned index,
6134e98e3e1Schristos 			      range_property_spec *range)
6144e98e3e1Schristos {
6154e98e3e1Schristos   const struct hw_property *node;
6164e98e3e1Schristos   unsigned sizeof_entry = (nr_range_property_cells (me, 1)
6174e98e3e1Schristos 			   * sizeof (unsigned_cell));
6184e98e3e1Schristos   const unsigned_cell *cells;
6194e98e3e1Schristos 
6204e98e3e1Schristos   /* locate the property */
6214e98e3e1Schristos   node = hw_find_property (me, property);
6224e98e3e1Schristos   if (node == NULL)
6234e98e3e1Schristos     hw_abort (me, "property \"%s\" not found", property);
6244e98e3e1Schristos   if (node->type != range_array_property)
6254e98e3e1Schristos     hw_abort (me, "property \"%s\" of wrong type (range array)", property);
6264e98e3e1Schristos 
6274e98e3e1Schristos   /* aligned ? */
6284e98e3e1Schristos   if ((node->sizeof_array % sizeof_entry) != 0)
6294e98e3e1Schristos     hw_abort (me, "property \"%s\" contains an incomplete number of entries",
6304e98e3e1Schristos 	      property);
6314e98e3e1Schristos 
6324e98e3e1Schristos   /* within bounds? */
6334e98e3e1Schristos   if (node->sizeof_array < sizeof_entry * (index + 1))
6344e98e3e1Schristos     return 0;
6354e98e3e1Schristos 
6364e98e3e1Schristos   /* find the range of interest */
6374e98e3e1Schristos   cells = (unsigned_cell*)((char*)node->array + sizeof_entry * index);
6384e98e3e1Schristos 
6394e98e3e1Schristos   /* copy the child address out - converting as we go */
6404e98e3e1Schristos   cells = cells_to_unit_address (cells, &range->child_address,
6414e98e3e1Schristos 				 hw_unit_nr_address_cells (me));
6424e98e3e1Schristos 
6434e98e3e1Schristos   /* copy the parent address out - converting as we go */
6444e98e3e1Schristos   cells = cells_to_unit_address (cells, &range->parent_address,
6454e98e3e1Schristos 				 hw_unit_nr_address_cells (hw_parent (me)));
6464e98e3e1Schristos 
6474e98e3e1Schristos   /* copy the size - converting as we go */
6484e98e3e1Schristos   cells = cells_to_unit_address (cells, &range->size,
6494e98e3e1Schristos 				 hw_unit_nr_size_cells (me));
6504e98e3e1Schristos 
6514e98e3e1Schristos   return node->sizeof_array / sizeof_entry;
6524e98e3e1Schristos }
6534e98e3e1Schristos 
6544e98e3e1Schristos 
6554e98e3e1Schristos static unsigned
6564e98e3e1Schristos nr_reg_property_cells (struct hw *me,
6574e98e3e1Schristos 		       int nr_regs)
6584e98e3e1Schristos {
6594e98e3e1Schristos   return (hw_unit_nr_address_cells (hw_parent (me))
6604e98e3e1Schristos 	  + hw_unit_nr_size_cells (hw_parent (me))
6614e98e3e1Schristos 	  ) * nr_regs;
6624e98e3e1Schristos }
6634e98e3e1Schristos 
6644e98e3e1Schristos void
6654e98e3e1Schristos hw_add_reg_array_property (struct hw *me,
6664e98e3e1Schristos 			   const char *property,
6674e98e3e1Schristos 			   const reg_property_spec *regs,
6684e98e3e1Schristos 			   unsigned nr_regs)
6694e98e3e1Schristos {
6704e98e3e1Schristos   unsigned sizeof_cells = (nr_reg_property_cells (me, nr_regs)
6714e98e3e1Schristos 			   * sizeof (unsigned_cell));
6724e98e3e1Schristos   unsigned_cell *cells = hw_zalloc (me, sizeof_cells);
6734e98e3e1Schristos   unsigned_cell *cell;
6744e98e3e1Schristos   int i;
6754e98e3e1Schristos 
6764e98e3e1Schristos   /* copy the property elements over */
6774e98e3e1Schristos   cell = cells;
6784e98e3e1Schristos   for (i = 0; i < nr_regs; i++)
6794e98e3e1Schristos     {
6804e98e3e1Schristos       const reg_property_spec *reg = &regs[i];
6814e98e3e1Schristos       /* copy the address */
6824e98e3e1Schristos       cell = unit_address_to_cells (&reg->address, cell,
6834e98e3e1Schristos 				    hw_unit_nr_address_cells (hw_parent (me)));
6844e98e3e1Schristos       /* copy the size */
6854e98e3e1Schristos       cell = unit_address_to_cells (&reg->size, cell,
6864e98e3e1Schristos 				    hw_unit_nr_size_cells (hw_parent (me)));
6874e98e3e1Schristos     }
6884e98e3e1Schristos   ASSERT (cell == &cells[nr_reg_property_cells (me, nr_regs)]);
6894e98e3e1Schristos 
6904e98e3e1Schristos   /* add it */
6914e98e3e1Schristos   hw_add_property (me, property, reg_array_property,
6924e98e3e1Schristos 		   cells, sizeof_cells,
6934e98e3e1Schristos 		   cells, sizeof_cells,
694*88241920Schristos 		   NULL, permanent_object);
6954e98e3e1Schristos 
6964e98e3e1Schristos   hw_free (me, cells);
6974e98e3e1Schristos }
6984e98e3e1Schristos 
6994e98e3e1Schristos int
7004e98e3e1Schristos hw_find_reg_array_property (struct hw *me,
7014e98e3e1Schristos 			    const char *property,
7024e98e3e1Schristos 			    unsigned index,
7034e98e3e1Schristos 			    reg_property_spec *reg)
7044e98e3e1Schristos {
7054e98e3e1Schristos   const struct hw_property *node;
7064e98e3e1Schristos   unsigned sizeof_entry = (nr_reg_property_cells (me, 1)
7074e98e3e1Schristos 			   * sizeof (unsigned_cell));
7084e98e3e1Schristos   const unsigned_cell *cells;
7094e98e3e1Schristos 
7104e98e3e1Schristos   /* locate the property */
7114e98e3e1Schristos   node = hw_find_property (me, property);
7124e98e3e1Schristos   if (node == NULL)
7134e98e3e1Schristos     hw_abort (me, "property \"%s\" not found", property);
7144e98e3e1Schristos   if (node->type != reg_array_property)
7154e98e3e1Schristos     hw_abort (me, "property \"%s\" of wrong type (reg array)", property);
7164e98e3e1Schristos 
7174e98e3e1Schristos   /* aligned ? */
7184e98e3e1Schristos   if ((node->sizeof_array % sizeof_entry) != 0)
7194e98e3e1Schristos     hw_abort (me, "property \"%s\" contains an incomplete number of entries",
7204e98e3e1Schristos 	      property);
7214e98e3e1Schristos 
7224e98e3e1Schristos   /* within bounds? */
7234e98e3e1Schristos   if (node->sizeof_array < sizeof_entry * (index + 1))
7244e98e3e1Schristos     return 0;
7254e98e3e1Schristos 
7264e98e3e1Schristos   /* find the range of interest */
7274e98e3e1Schristos   cells = (unsigned_cell*)((char*)node->array + sizeof_entry * index);
7284e98e3e1Schristos 
7294e98e3e1Schristos   /* copy the address out - converting as we go */
7304e98e3e1Schristos   cells = cells_to_unit_address (cells, &reg->address,
7314e98e3e1Schristos 				 hw_unit_nr_address_cells (hw_parent (me)));
7324e98e3e1Schristos 
7334e98e3e1Schristos   /* copy the size out - converting as we go */
7344e98e3e1Schristos   cells = cells_to_unit_address (cells, &reg->size,
7354e98e3e1Schristos 				 hw_unit_nr_size_cells (hw_parent (me)));
7364e98e3e1Schristos 
7374e98e3e1Schristos   return node->sizeof_array / sizeof_entry;
7384e98e3e1Schristos }
7394e98e3e1Schristos 
7404e98e3e1Schristos 
7414e98e3e1Schristos void
7424e98e3e1Schristos hw_add_string_property (struct hw *me,
7434e98e3e1Schristos 			const char *property,
7444e98e3e1Schristos 			const char *string)
7454e98e3e1Schristos {
7464e98e3e1Schristos   hw_add_property (me, property, string_property,
7474e98e3e1Schristos 		   string, strlen (string) + 1,
7484e98e3e1Schristos 		   string, strlen (string) + 1,
749*88241920Schristos 		   NULL, permanent_object);
7504e98e3e1Schristos }
7514e98e3e1Schristos 
7524e98e3e1Schristos const char *
7534e98e3e1Schristos hw_find_string_property (struct hw *me,
7544e98e3e1Schristos 			 const char *property)
7554e98e3e1Schristos {
7564e98e3e1Schristos   const struct hw_property *node;
7574e98e3e1Schristos   const char *string;
7584e98e3e1Schristos   node = hw_find_property (me, property);
7594e98e3e1Schristos   if (node == NULL)
7604e98e3e1Schristos     hw_abort (me, "property \"%s\" not found", property);
7614e98e3e1Schristos   if (node->type != string_property)
7624e98e3e1Schristos     hw_abort (me, "property \"%s\" of wrong type (string)", property);
7634e98e3e1Schristos   string = node->array;
7644e98e3e1Schristos   ASSERT (strlen (string) + 1 == node->sizeof_array);
7654e98e3e1Schristos   return string;
7664e98e3e1Schristos }
7674e98e3e1Schristos 
7684e98e3e1Schristos void
7694e98e3e1Schristos hw_add_string_array_property (struct hw *me,
7704e98e3e1Schristos 			      const char *property,
7714e98e3e1Schristos 			      const string_property_spec *strings,
7724e98e3e1Schristos 			      unsigned nr_strings)
7734e98e3e1Schristos {
7744e98e3e1Schristos   int sizeof_array;
7754e98e3e1Schristos   int string_nr;
7764e98e3e1Schristos   char *array;
7774e98e3e1Schristos   char *chp;
7784e98e3e1Schristos   if (nr_strings == 0)
7794e98e3e1Schristos     hw_abort (me, "property \"%s\" must be non-null", property);
7804e98e3e1Schristos   /* total up the size of the needed array */
7814e98e3e1Schristos   for (sizeof_array = 0, string_nr = 0;
7824e98e3e1Schristos        string_nr < nr_strings;
7834e98e3e1Schristos        string_nr ++)
7844e98e3e1Schristos     {
7854e98e3e1Schristos       sizeof_array += strlen (strings[string_nr]) + 1;
7864e98e3e1Schristos     }
7874e98e3e1Schristos   /* create the array */
7884e98e3e1Schristos   array = (char*) hw_zalloc (me, sizeof_array);
7894e98e3e1Schristos   chp = array;
7904e98e3e1Schristos   for (string_nr = 0;
7914e98e3e1Schristos        string_nr < nr_strings;
7924e98e3e1Schristos        string_nr++)
7934e98e3e1Schristos     {
7944e98e3e1Schristos       strcpy (chp, strings[string_nr]);
7954e98e3e1Schristos       chp += strlen (chp) + 1;
7964e98e3e1Schristos     }
7974e98e3e1Schristos   ASSERT (chp == array + sizeof_array);
7984e98e3e1Schristos   /* now enter it */
7994e98e3e1Schristos   hw_add_property (me, property, string_array_property,
8004e98e3e1Schristos 		   array, sizeof_array,
8014e98e3e1Schristos 		   array, sizeof_array,
802*88241920Schristos 		   NULL, permanent_object);
8034e98e3e1Schristos }
8044e98e3e1Schristos 
8054e98e3e1Schristos int
8064e98e3e1Schristos hw_find_string_array_property (struct hw *me,
8074e98e3e1Schristos 			       const char *property,
8084e98e3e1Schristos 			       unsigned index,
8094e98e3e1Schristos 			       string_property_spec *string)
8104e98e3e1Schristos {
8114e98e3e1Schristos   const struct hw_property *node;
8124e98e3e1Schristos   node = hw_find_property (me, property);
8134e98e3e1Schristos   if (node == NULL)
8144e98e3e1Schristos     hw_abort (me, "property \"%s\" not found", property);
8154e98e3e1Schristos   switch (node->type)
8164e98e3e1Schristos     {
8174e98e3e1Schristos     default:
8184e98e3e1Schristos       hw_abort (me, "property \"%s\" of wrong type", property);
8194e98e3e1Schristos       break;
8204e98e3e1Schristos     case string_property:
8214e98e3e1Schristos       if (index == 0)
8224e98e3e1Schristos 	{
8234e98e3e1Schristos 	  *string = node->array;
8244e98e3e1Schristos 	  ASSERT (strlen (*string) + 1 == node->sizeof_array);
8254e98e3e1Schristos 	  return 1;
8264e98e3e1Schristos 	}
8274e98e3e1Schristos       break;
8284e98e3e1Schristos     case array_property:
8294e98e3e1Schristos       if (node->sizeof_array == 0
8304e98e3e1Schristos 	  || ((char*)node->array)[node->sizeof_array - 1] != '\0')
8314e98e3e1Schristos 	hw_abort (me, "property \"%s\" invalid for string array", property);
832*88241920Schristos       ATTRIBUTE_FALLTHROUGH;
8334e98e3e1Schristos     case string_array_property:
8344e98e3e1Schristos       ASSERT (node->sizeof_array > 0);
8354e98e3e1Schristos       ASSERT (((char*)node->array)[node->sizeof_array - 1] == '\0');
8364e98e3e1Schristos       {
8374e98e3e1Schristos 	const char *chp = node->array;
8384e98e3e1Schristos 	int nr_entries = 0;
8394e98e3e1Schristos 	/* count the number of strings, keeping an eye out for the one
8404e98e3e1Schristos 	   we're looking for */
8414e98e3e1Schristos 	*string = chp;
8424e98e3e1Schristos 	do
8434e98e3e1Schristos 	  {
8444e98e3e1Schristos 	    if (*chp == '\0')
8454e98e3e1Schristos 	      {
8464e98e3e1Schristos 		/* next string */
8474e98e3e1Schristos 		nr_entries++;
8484e98e3e1Schristos 		chp++;
8494e98e3e1Schristos 		if (nr_entries == index)
8504e98e3e1Schristos 		  *string = chp;
8514e98e3e1Schristos 	      }
8524e98e3e1Schristos 	    else
8534e98e3e1Schristos 	      {
8544e98e3e1Schristos 		chp++;
8554e98e3e1Schristos 	      }
8564e98e3e1Schristos 	  } while (chp < (char*)node->array + node->sizeof_array);
8574e98e3e1Schristos 	if (index < nr_entries)
8584e98e3e1Schristos 	  return nr_entries;
8594e98e3e1Schristos 	else
8604e98e3e1Schristos 	  {
8614e98e3e1Schristos 	    *string = NULL;
8624e98e3e1Schristos 	    return 0;
8634e98e3e1Schristos 	  }
8644e98e3e1Schristos       }
8654e98e3e1Schristos       break;
8664e98e3e1Schristos     }
8674e98e3e1Schristos   return 0;
8684e98e3e1Schristos }
8694e98e3e1Schristos 
8704e98e3e1Schristos void
8714e98e3e1Schristos hw_add_duplicate_property (struct hw *me,
8724e98e3e1Schristos 			   const char *property,
8734e98e3e1Schristos 			   const struct hw_property *original)
8744e98e3e1Schristos {
8754e98e3e1Schristos   struct hw_property_data *master;
876*88241920Schristos   if (original->disposition != permanent_object)
877*88241920Schristos     hw_abort (me, "Can only duplicate permanent objects");
8784e98e3e1Schristos   /* find the original's master */
8794e98e3e1Schristos   master = original->owner->properties_of_hw;
8804e98e3e1Schristos   while (master->property != original)
8814e98e3e1Schristos     {
8824e98e3e1Schristos       master = master->next;
8834e98e3e1Schristos       ASSERT (master != NULL);
8844e98e3e1Schristos     }
8854e98e3e1Schristos   /* now duplicate it */
8864e98e3e1Schristos   hw_add_property (me, property,
8874e98e3e1Schristos 		   original->type,
8884e98e3e1Schristos 		   master->init_array, master->sizeof_init_array,
8894e98e3e1Schristos 		   original->array, original->sizeof_array,
890*88241920Schristos 		   original, permanent_object);
8914e98e3e1Schristos }
892