xref: /netbsd-src/external/gpl3/gdb/dist/sim/common/hw-base.c (revision 0d3e0572e40d81edb4fdbff937458d47b685c34c)
14e98e3e1Schristos /* The common simulator framework for GDB, the GNU Debugger.
24e98e3e1Schristos 
3*0d3e0572Schristos    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 <ctype.h>
264b169a6bSchristos #include <stdlib.h>
274b169a6bSchristos #include <string.h>
284e98e3e1Schristos 
294e98e3e1Schristos #include "hw-main.h"
304e98e3e1Schristos #include "hw-base.h"
314e98e3e1Schristos #include "hw-config.h"
324e98e3e1Schristos 
334e98e3e1Schristos struct hw_base_data
344e98e3e1Schristos {
354e98e3e1Schristos   int finished_p;
364e98e3e1Schristos   const struct hw_descriptor *descriptor;
374e98e3e1Schristos   hw_delete_callback *to_delete;
384e98e3e1Schristos };
394e98e3e1Schristos 
404e98e3e1Schristos static int
414e98e3e1Schristos generic_hw_unit_decode (struct hw *bus,
424e98e3e1Schristos 			const char *unit,
434e98e3e1Schristos 			hw_unit *phys)
444e98e3e1Schristos {
454e98e3e1Schristos   memset (phys, 0, sizeof (*phys));
464e98e3e1Schristos   if (unit == NULL)
474e98e3e1Schristos     return 0;
484e98e3e1Schristos   else
494e98e3e1Schristos     {
504e98e3e1Schristos       int nr_cells = 0;
514e98e3e1Schristos       const int max_nr_cells = hw_unit_nr_address_cells (bus);
524e98e3e1Schristos       while (1)
534e98e3e1Schristos 	{
544e98e3e1Schristos 	  char *end = NULL;
554e98e3e1Schristos 	  unsigned long val;
564e98e3e1Schristos 	  val = strtoul (unit, &end, 0);
574e98e3e1Schristos 	  /* parse error? */
584e98e3e1Schristos 	  if (unit == end)
594e98e3e1Schristos 	    return -1;
604e98e3e1Schristos 	  /* two many cells? */
614e98e3e1Schristos 	  if (nr_cells >= max_nr_cells)
624e98e3e1Schristos 	    return -1;
634e98e3e1Schristos 	  /* save it */
644e98e3e1Schristos 	  phys->cells[nr_cells] = val;
654e98e3e1Schristos 	  nr_cells++;
664e98e3e1Schristos 	  unit = end;
674e98e3e1Schristos 	  /* more to follow? */
684e98e3e1Schristos 	  if (isspace (*unit) || *unit == '\0')
694e98e3e1Schristos 	    break;
704e98e3e1Schristos 	  if (*unit != ',')
714e98e3e1Schristos 	    return -1;
724e98e3e1Schristos 	  unit++;
734e98e3e1Schristos 	}
744e98e3e1Schristos       if (nr_cells < max_nr_cells)
754e98e3e1Schristos 	{
764e98e3e1Schristos 	  /* shift everything to correct position */
774e98e3e1Schristos 	  int i;
784e98e3e1Schristos 
794e98e3e1Schristos 	  for (i = 1; i <= nr_cells; i++)
804e98e3e1Schristos 	    phys->cells[max_nr_cells - i] = phys->cells[nr_cells - i];
814e98e3e1Schristos 	  for (i = 0; i < (max_nr_cells - nr_cells); i++)
824e98e3e1Schristos 	    phys->cells[i] = 0;
834e98e3e1Schristos 	}
844e98e3e1Schristos       phys->nr_cells = max_nr_cells;
854e98e3e1Schristos       return max_nr_cells;
864e98e3e1Schristos   }
874e98e3e1Schristos }
884e98e3e1Schristos 
894e98e3e1Schristos static int
904e98e3e1Schristos generic_hw_unit_encode (struct hw *bus,
914e98e3e1Schristos 			const hw_unit *phys,
924e98e3e1Schristos 			char *buf,
934e98e3e1Schristos 			int sizeof_buf)
944e98e3e1Schristos {
954e98e3e1Schristos   int i;
964e98e3e1Schristos   int len;
974e98e3e1Schristos   char *pos = buf;
984e98e3e1Schristos   /* skip leading zero's */
994e98e3e1Schristos   for (i = 0; i < phys->nr_cells; i++)
1004e98e3e1Schristos     {
1014e98e3e1Schristos       if (phys->cells[i] != 0)
1024e98e3e1Schristos 	break;
1034e98e3e1Schristos     }
1044e98e3e1Schristos   /* don't output anything if empty */
1054e98e3e1Schristos   if (phys->nr_cells == 0)
1064e98e3e1Schristos     {
1074e98e3e1Schristos       strcpy (pos, "");
1084e98e3e1Schristos       len = 0;
1094e98e3e1Schristos     }
1104e98e3e1Schristos   else if (i == phys->nr_cells)
1114e98e3e1Schristos     {
1124e98e3e1Schristos       /* all zero */
1134e98e3e1Schristos       strcpy (pos, "0");
1144e98e3e1Schristos       len = 1;
1154e98e3e1Schristos     }
1164e98e3e1Schristos   else
1174e98e3e1Schristos     {
1184e98e3e1Schristos       for (; i < phys->nr_cells; i++)
1194e98e3e1Schristos 	{
1204e98e3e1Schristos 	  if (pos != buf)
1214e98e3e1Schristos 	    {
1224e98e3e1Schristos 	      strcat (pos, ",");
1234e98e3e1Schristos 	      pos = strchr (pos, '\0');
1244e98e3e1Schristos 	    }
1254e98e3e1Schristos 	  if (phys->cells[i] < 10)
1264e98e3e1Schristos 	    sprintf (pos, "%ld", (unsigned long)phys->cells[i]);
1274e98e3e1Schristos 	  else
1284e98e3e1Schristos 	    sprintf (pos, "0x%lx", (unsigned long)phys->cells[i]);
1294e98e3e1Schristos 	  pos = strchr (pos, '\0');
1304e98e3e1Schristos 	}
1314e98e3e1Schristos       len = pos - buf;
1324e98e3e1Schristos     }
1334e98e3e1Schristos   if (len >= sizeof_buf)
1344e98e3e1Schristos     hw_abort (NULL, "generic_unit_encode - buffer overflow\n");
1354e98e3e1Schristos   return len;
1364e98e3e1Schristos }
1374e98e3e1Schristos 
1384e98e3e1Schristos static int
1394e98e3e1Schristos generic_hw_unit_address_to_attach_address (struct hw *me,
1404e98e3e1Schristos 					   const hw_unit *address,
1414e98e3e1Schristos 					   int *attach_space,
1424e98e3e1Schristos 					   unsigned_word *attach_address,
1434e98e3e1Schristos 					   struct hw *client)
1444e98e3e1Schristos {
1454e98e3e1Schristos   int i;
1464e98e3e1Schristos   for (i = 0; i < address->nr_cells - 2; i++)
1474e98e3e1Schristos     {
1484e98e3e1Schristos       if (address->cells[i] != 0)
1494e98e3e1Schristos 	hw_abort (me, "Only 32bit addresses supported");
1504e98e3e1Schristos     }
1514e98e3e1Schristos   if (address->nr_cells >= 2)
1524e98e3e1Schristos     *attach_space = address->cells[address->nr_cells - 2];
1534e98e3e1Schristos   else
1544e98e3e1Schristos     *attach_space = 0;
1554e98e3e1Schristos   *attach_address = address->cells[address->nr_cells - 1];
1564e98e3e1Schristos   return 1;
1574e98e3e1Schristos }
1584e98e3e1Schristos 
1594e98e3e1Schristos static int
1604e98e3e1Schristos generic_hw_unit_size_to_attach_size (struct hw *me,
1614e98e3e1Schristos 				     const hw_unit *size,
1624e98e3e1Schristos 				     unsigned *nr_bytes,
1634e98e3e1Schristos 				     struct hw *client)
1644e98e3e1Schristos {
1654e98e3e1Schristos   int i;
1664e98e3e1Schristos   for (i = 0; i < size->nr_cells - 1; i++)
1674e98e3e1Schristos     {
1684e98e3e1Schristos       if (size->cells[i] != 0)
1694e98e3e1Schristos 	hw_abort (me, "Only 32bit sizes supported");
1704e98e3e1Schristos     }
1714e98e3e1Schristos   *nr_bytes = size->cells[0];
1724e98e3e1Schristos   return *nr_bytes;
1734e98e3e1Schristos }
1744e98e3e1Schristos 
1754e98e3e1Schristos 
1764e98e3e1Schristos /* ignore/passthrough versions of each function */
1774e98e3e1Schristos 
1784e98e3e1Schristos static void
1794e98e3e1Schristos passthrough_hw_attach_address (struct hw *me,
1804e98e3e1Schristos 			       int level,
1814e98e3e1Schristos 			       int space,
1824e98e3e1Schristos 			       address_word addr,
1834e98e3e1Schristos 			       address_word nr_bytes,
1844e98e3e1Schristos 			       struct hw *client) /*callback/default*/
1854e98e3e1Schristos {
1864e98e3e1Schristos   if (hw_parent (me) == NULL)
1874e98e3e1Schristos     hw_abort (client, "hw_attach_address: no parent attach method");
1884e98e3e1Schristos   hw_attach_address (hw_parent (me), level,
1894e98e3e1Schristos 		     space, addr, nr_bytes,
1904e98e3e1Schristos 		     client);
1914e98e3e1Schristos }
1924e98e3e1Schristos 
1934e98e3e1Schristos static void
1944e98e3e1Schristos passthrough_hw_detach_address (struct hw *me,
1954e98e3e1Schristos 			       int level,
1964e98e3e1Schristos 			       int space,
1974e98e3e1Schristos 			       address_word addr,
1984e98e3e1Schristos 			       address_word nr_bytes,
1994e98e3e1Schristos 			       struct hw *client) /*callback/default*/
2004e98e3e1Schristos {
2014e98e3e1Schristos   if (hw_parent (me) == NULL)
2024e98e3e1Schristos     hw_abort (client, "hw_attach_address: no parent attach method");
2034e98e3e1Schristos   hw_detach_address (hw_parent (me), level,
2044e98e3e1Schristos 		     space, addr, nr_bytes,
2054e98e3e1Schristos 		     client);
2064e98e3e1Schristos }
2074e98e3e1Schristos 
2084e98e3e1Schristos static unsigned
2094e98e3e1Schristos panic_hw_io_read_buffer (struct hw *me,
2104e98e3e1Schristos 			 void *dest,
2114e98e3e1Schristos 			 int space,
2124e98e3e1Schristos 			 unsigned_word addr,
2134e98e3e1Schristos 			 unsigned nr_bytes)
2144e98e3e1Schristos {
2154e98e3e1Schristos   hw_abort (me, "no io-read method");
2164e98e3e1Schristos   return 0;
2174e98e3e1Schristos }
2184e98e3e1Schristos 
2194e98e3e1Schristos static unsigned
2204e98e3e1Schristos panic_hw_io_write_buffer (struct hw *me,
2214e98e3e1Schristos 			  const void *source,
2224e98e3e1Schristos 			  int space,
2234e98e3e1Schristos 			  unsigned_word addr,
2244e98e3e1Schristos 			  unsigned nr_bytes)
2254e98e3e1Schristos {
2264e98e3e1Schristos   hw_abort (me, "no io-write method");
2274e98e3e1Schristos   return 0;
2284e98e3e1Schristos }
2294e98e3e1Schristos 
2304e98e3e1Schristos static unsigned
2314e98e3e1Schristos passthrough_hw_dma_read_buffer (struct hw *me,
2324e98e3e1Schristos 				void *dest,
2334e98e3e1Schristos 				int space,
2344e98e3e1Schristos 				unsigned_word addr,
2354e98e3e1Schristos 				unsigned nr_bytes)
2364e98e3e1Schristos {
2374e98e3e1Schristos   if (hw_parent (me) == NULL)
2384e98e3e1Schristos     hw_abort (me, "no parent dma-read method");
2394e98e3e1Schristos   return hw_dma_read_buffer (hw_parent (me), dest,
2404e98e3e1Schristos 			     space, addr, nr_bytes);
2414e98e3e1Schristos }
2424e98e3e1Schristos 
2434e98e3e1Schristos static unsigned
2444e98e3e1Schristos passthrough_hw_dma_write_buffer (struct hw *me,
2454e98e3e1Schristos 				 const void *source,
2464e98e3e1Schristos 				 int space,
2474e98e3e1Schristos 				 unsigned_word addr,
2484e98e3e1Schristos 				 unsigned nr_bytes,
2494e98e3e1Schristos 				 int violate_read_only_section)
2504e98e3e1Schristos {
2514e98e3e1Schristos   if (hw_parent (me) == NULL)
2524e98e3e1Schristos     hw_abort (me, "no parent dma-write method");
2534e98e3e1Schristos   return hw_dma_write_buffer (hw_parent (me), source,
2544e98e3e1Schristos 			      space, addr,
2554e98e3e1Schristos 			      nr_bytes,
2564e98e3e1Schristos 			      violate_read_only_section);
2574e98e3e1Schristos }
2584e98e3e1Schristos 
2594e98e3e1Schristos static void
2604e98e3e1Schristos ignore_hw_delete (struct hw *me)
2614e98e3e1Schristos {
2624e98e3e1Schristos   /* NOP */
2634e98e3e1Schristos }
2644e98e3e1Schristos 
2654e98e3e1Schristos 
2664e98e3e1Schristos 
2674e98e3e1Schristos 
2684e98e3e1Schristos static const char *
2694e98e3e1Schristos full_name_of_hw (struct hw *leaf,
2704e98e3e1Schristos 		 char *buf,
2714e98e3e1Schristos 		 unsigned sizeof_buf)
2724e98e3e1Schristos {
2734e98e3e1Schristos   /* get a buffer */
2744b169a6bSchristos   if (buf == NULL)
2754e98e3e1Schristos     {
2764b169a6bSchristos       sizeof_buf = 1024;
2774b169a6bSchristos       buf = hw_malloc (leaf, sizeof_buf);
2784e98e3e1Schristos     }
2794e98e3e1Schristos 
2804e98e3e1Schristos   /* use head recursion to construct the path */
2814e98e3e1Schristos 
2824e98e3e1Schristos   if (hw_parent (leaf) == NULL)
2834e98e3e1Schristos     /* root */
2844e98e3e1Schristos     {
2854e98e3e1Schristos       if (sizeof_buf < 1)
2864e98e3e1Schristos 	hw_abort (leaf, "buffer overflow");
2874e98e3e1Schristos       *buf = '\0';
2884e98e3e1Schristos     }
2894e98e3e1Schristos   else
2904e98e3e1Schristos     /* sub node */
2914e98e3e1Schristos     {
2924e98e3e1Schristos       char unit[1024];
2934e98e3e1Schristos       full_name_of_hw (hw_parent (leaf), buf, sizeof_buf);
2944e98e3e1Schristos       if (hw_unit_encode (hw_parent (leaf),
2954e98e3e1Schristos 			  hw_unit_address (leaf),
2964e98e3e1Schristos 			  unit + 1,
2974e98e3e1Schristos 			  sizeof (unit) - 1)
2984e98e3e1Schristos 	  > 0)
2994e98e3e1Schristos 	unit[0] = '@';
3004e98e3e1Schristos       else
3014e98e3e1Schristos 	unit[0] = '\0';
3024e98e3e1Schristos       if (strlen (buf) + strlen ("/") + strlen (hw_name (leaf)) + strlen (unit)
3034e98e3e1Schristos 	  >= sizeof_buf)
3044e98e3e1Schristos 	hw_abort (leaf, "buffer overflow");
3054e98e3e1Schristos       strcat (buf, "/");
3064e98e3e1Schristos       strcat (buf, hw_name (leaf));
3074e98e3e1Schristos       strcat (buf, unit);
3084e98e3e1Schristos     }
3094e98e3e1Schristos 
3104e98e3e1Schristos   return buf;
3114e98e3e1Schristos }
3124e98e3e1Schristos 
3134e98e3e1Schristos struct hw *
3144e98e3e1Schristos hw_create (struct sim_state *sd,
3154e98e3e1Schristos 	   struct hw *parent,
3164e98e3e1Schristos 	   const char *family,
3174e98e3e1Schristos 	   const char *name,
3184e98e3e1Schristos 	   const char *unit,
3194e98e3e1Schristos 	   const char *args)
3204e98e3e1Schristos {
3214e98e3e1Schristos  /* NOTE: HW must be allocated using ZALLOC, others use HW_ZALLOC */
3224e98e3e1Schristos   struct hw *hw = ZALLOC (struct hw);
3234e98e3e1Schristos 
3244e98e3e1Schristos   /* our identity */
3254e98e3e1Schristos   hw->family_of_hw = hw_strdup (hw, family);
3264e98e3e1Schristos   hw->name_of_hw = hw_strdup (hw, name);
3274e98e3e1Schristos   hw->args_of_hw = hw_strdup (hw, args);
3284e98e3e1Schristos 
3294e98e3e1Schristos   /* a hook into the system */
3304e98e3e1Schristos   if (sd != NULL)
3314e98e3e1Schristos     hw->system_of_hw = sd;
3324e98e3e1Schristos   else if (parent != NULL)
3334e98e3e1Schristos     hw->system_of_hw = hw_system (parent);
3344e98e3e1Schristos   else
3354e98e3e1Schristos     hw_abort (parent, "No system found");
3364e98e3e1Schristos 
3374e98e3e1Schristos   /* in a tree */
3384e98e3e1Schristos   if (parent != NULL)
3394e98e3e1Schristos     {
3404e98e3e1Schristos       struct hw **sibling = &parent->child_of_hw;
3414e98e3e1Schristos       while ((*sibling) != NULL)
3424e98e3e1Schristos 	sibling = &(*sibling)->sibling_of_hw;
3434e98e3e1Schristos       *sibling = hw;
3444e98e3e1Schristos       hw->parent_of_hw = parent;
3454e98e3e1Schristos     }
3464e98e3e1Schristos 
3474e98e3e1Schristos   /* top of tree */
3484e98e3e1Schristos   if (parent != NULL)
3494e98e3e1Schristos     {
3504e98e3e1Schristos       struct hw *root = parent;
3514e98e3e1Schristos       while (root->parent_of_hw != NULL)
3524e98e3e1Schristos 	root = root->parent_of_hw;
3534e98e3e1Schristos       hw->root_of_hw = root;
3544e98e3e1Schristos     }
3554e98e3e1Schristos 
3564e98e3e1Schristos   /* a unique identifier for the device on the parents bus */
3574e98e3e1Schristos   if (parent != NULL)
3584e98e3e1Schristos     {
3594e98e3e1Schristos       hw_unit_decode (parent, unit, &hw->unit_address_of_hw);
3604e98e3e1Schristos     }
3614e98e3e1Schristos 
3624e98e3e1Schristos   /* Determine our path */
3634e98e3e1Schristos   if (parent != NULL)
3644e98e3e1Schristos     hw->path_of_hw = full_name_of_hw (hw, NULL, 0);
3654e98e3e1Schristos   else
3664e98e3e1Schristos     hw->path_of_hw = "/";
3674e98e3e1Schristos 
3684e98e3e1Schristos   /* create our base type */
3694e98e3e1Schristos   hw->base_of_hw = HW_ZALLOC (hw, struct hw_base_data);
3704e98e3e1Schristos   hw->base_of_hw->finished_p = 0;
3714e98e3e1Schristos 
3724e98e3e1Schristos   /* our callbacks */
3734e98e3e1Schristos   set_hw_io_read_buffer (hw, panic_hw_io_read_buffer);
3744e98e3e1Schristos   set_hw_io_write_buffer (hw, panic_hw_io_write_buffer);
3754e98e3e1Schristos   set_hw_dma_read_buffer (hw, passthrough_hw_dma_read_buffer);
3764e98e3e1Schristos   set_hw_dma_write_buffer (hw, passthrough_hw_dma_write_buffer);
3774e98e3e1Schristos   set_hw_unit_decode (hw, generic_hw_unit_decode);
3784e98e3e1Schristos   set_hw_unit_encode (hw, generic_hw_unit_encode);
3794e98e3e1Schristos   set_hw_unit_address_to_attach_address (hw, generic_hw_unit_address_to_attach_address);
3804e98e3e1Schristos   set_hw_unit_size_to_attach_size (hw, generic_hw_unit_size_to_attach_size);
3814e98e3e1Schristos   set_hw_attach_address (hw, passthrough_hw_attach_address);
3824e98e3e1Schristos   set_hw_detach_address (hw, passthrough_hw_detach_address);
3834e98e3e1Schristos   set_hw_delete (hw, ignore_hw_delete);
3844e98e3e1Schristos 
3854e98e3e1Schristos   /* locate a descriptor */
3864e98e3e1Schristos   {
3874b169a6bSchristos     const struct hw_descriptor * const *table;
3884e98e3e1Schristos     for (table = hw_descriptors;
3894e98e3e1Schristos 	 *table != NULL;
3904e98e3e1Schristos 	 table++)
3914e98e3e1Schristos       {
3924e98e3e1Schristos 	const struct hw_descriptor *entry;
3934e98e3e1Schristos 	for (entry = *table;
3944e98e3e1Schristos 	     entry->family != NULL;
3954e98e3e1Schristos 	     entry++)
3964e98e3e1Schristos 	  {
3974e98e3e1Schristos 	    if (strcmp (family, entry->family) == 0)
3984e98e3e1Schristos 	      {
3994e98e3e1Schristos 		hw->base_of_hw->descriptor = entry;
4004e98e3e1Schristos 		break;
4014e98e3e1Schristos 	      }
4024e98e3e1Schristos 	  }
4034e98e3e1Schristos       }
4044e98e3e1Schristos     if (hw->base_of_hw->descriptor == NULL)
4054e98e3e1Schristos       {
4064e98e3e1Schristos 	hw_abort (parent, "Unknown device `%s'", family);
4074e98e3e1Schristos       }
4084e98e3e1Schristos   }
4094e98e3e1Schristos 
4104e98e3e1Schristos   /* Attach dummy ports */
4114e98e3e1Schristos   create_hw_alloc_data (hw);
4124e98e3e1Schristos   create_hw_property_data (hw);
4134e98e3e1Schristos   create_hw_port_data (hw);
4144e98e3e1Schristos   create_hw_event_data (hw);
4154e98e3e1Schristos   create_hw_handle_data (hw);
4164e98e3e1Schristos   create_hw_instance_data (hw);
4174e98e3e1Schristos 
4184e98e3e1Schristos   return hw;
4194e98e3e1Schristos }
4204e98e3e1Schristos 
4214e98e3e1Schristos 
4224e98e3e1Schristos int
4234e98e3e1Schristos hw_finished_p (struct hw *me)
4244e98e3e1Schristos {
4254e98e3e1Schristos   return (me->base_of_hw->finished_p);
4264e98e3e1Schristos }
4274e98e3e1Schristos 
4284e98e3e1Schristos void
4294e98e3e1Schristos hw_finish (struct hw *me)
4304e98e3e1Schristos {
4314e98e3e1Schristos   if (hw_finished_p (me))
4324e98e3e1Schristos     hw_abort (me, "Attempt to finish finished device");
4334e98e3e1Schristos 
4344e98e3e1Schristos   /* Fill in the (hopefully) defined address/size cells values */
4354e98e3e1Schristos   if (hw_find_property (me, "#address-cells") != NULL)
4364e98e3e1Schristos     me->nr_address_cells_of_hw_unit =
4374e98e3e1Schristos       hw_find_integer_property (me, "#address-cells");
4384e98e3e1Schristos   else
4394e98e3e1Schristos     me->nr_address_cells_of_hw_unit = 2;
4404e98e3e1Schristos   if (hw_find_property (me, "#size-cells") != NULL)
4414e98e3e1Schristos     me->nr_size_cells_of_hw_unit =
4424e98e3e1Schristos       hw_find_integer_property (me, "#size-cells");
4434e98e3e1Schristos   else
4444e98e3e1Schristos     me->nr_size_cells_of_hw_unit = 1;
4454e98e3e1Schristos 
4464e98e3e1Schristos   /* Fill in the (hopefully) defined trace variable */
4474e98e3e1Schristos   if (hw_find_property (me, "trace?") != NULL)
4484e98e3e1Schristos     me->trace_of_hw_p = hw_find_boolean_property (me, "trace?");
4494e98e3e1Schristos   /* allow global variable to define default tracing */
4504e98e3e1Schristos   else if (! hw_trace_p (me)
4514e98e3e1Schristos 	   && hw_find_property (hw_root (me), "global-trace?") != NULL
4524e98e3e1Schristos 	   && hw_find_boolean_property (hw_root (me), "global-trace?"))
4534e98e3e1Schristos     me->trace_of_hw_p = 1;
4544e98e3e1Schristos 
4554e98e3e1Schristos 
4564e98e3e1Schristos   /* Allow the real device to override any methods */
4574e98e3e1Schristos   me->base_of_hw->descriptor->to_finish (me);
4584e98e3e1Schristos   me->base_of_hw->finished_p = 1;
4594e98e3e1Schristos }
4604e98e3e1Schristos 
4614e98e3e1Schristos 
4624e98e3e1Schristos void
4634e98e3e1Schristos hw_delete (struct hw *me)
4644e98e3e1Schristos {
4654e98e3e1Schristos   /* give the object a chance to tidy up */
4664e98e3e1Schristos   me->base_of_hw->to_delete (me);
4674e98e3e1Schristos 
4684e98e3e1Schristos   delete_hw_instance_data (me);
4694e98e3e1Schristos   delete_hw_handle_data (me);
4704e98e3e1Schristos   delete_hw_event_data (me);
4714e98e3e1Schristos   delete_hw_port_data (me);
4724e98e3e1Schristos   delete_hw_property_data (me);
4734e98e3e1Schristos 
4744e98e3e1Schristos   /* now unlink us from the tree */
4754e98e3e1Schristos   if (hw_parent (me))
4764e98e3e1Schristos     {
4774e98e3e1Schristos       struct hw **sibling = &hw_parent (me)->child_of_hw;
4784e98e3e1Schristos       while (*sibling != NULL)
4794e98e3e1Schristos 	{
4804e98e3e1Schristos 	  if (*sibling == me)
4814e98e3e1Schristos 	    {
4824e98e3e1Schristos 	      *sibling = me->sibling_of_hw;
4834e98e3e1Schristos 	      me->sibling_of_hw = NULL;
4844e98e3e1Schristos 	      me->parent_of_hw = NULL;
4854e98e3e1Schristos 	      break;
4864e98e3e1Schristos 	    }
4874e98e3e1Schristos 	}
4884e98e3e1Schristos     }
4894e98e3e1Schristos 
4904e98e3e1Schristos   /* some sanity checks */
4914e98e3e1Schristos   if (hw_child (me) != NULL)
4924e98e3e1Schristos     {
4934e98e3e1Schristos       hw_abort (me, "attempt to delete device with children");
4944e98e3e1Schristos     }
4954e98e3e1Schristos   if (hw_sibling (me) != NULL)
4964e98e3e1Schristos     {
4974e98e3e1Schristos       hw_abort (me, "attempt to delete device with siblings");
4984e98e3e1Schristos     }
4994e98e3e1Schristos 
5004e98e3e1Schristos   /* blow away all memory belonging to the device */
5014e98e3e1Schristos   delete_hw_alloc_data (me);
5024e98e3e1Schristos 
5034e98e3e1Schristos   /* finally */
5044e98e3e1Schristos   free (me);
5054e98e3e1Schristos }
5064e98e3e1Schristos 
5074e98e3e1Schristos void
5084e98e3e1Schristos set_hw_delete (struct hw *hw, hw_delete_callback method)
5094e98e3e1Schristos {
5104e98e3e1Schristos   hw->base_of_hw->to_delete = method;
5114e98e3e1Schristos }
5124e98e3e1Schristos 
5134e98e3e1Schristos 
5144e98e3e1Schristos /* Go through the devices various reg properties for those that
5154e98e3e1Schristos    specify attach addresses */
5164e98e3e1Schristos 
5174e98e3e1Schristos 
5184e98e3e1Schristos void
5194e98e3e1Schristos do_hw_attach_regs (struct hw *hw)
5204e98e3e1Schristos {
5214e98e3e1Schristos   static const char *(reg_property_names[]) = {
5224e98e3e1Schristos     "attach-addresses",
5234e98e3e1Schristos     "assigned-addresses",
5244e98e3e1Schristos     "reg",
5254e98e3e1Schristos     "alternate-reg" ,
5264e98e3e1Schristos     NULL
5274e98e3e1Schristos   };
5284e98e3e1Schristos   const char **reg_property_name;
5294e98e3e1Schristos   for (reg_property_name = reg_property_names;
5304e98e3e1Schristos        *reg_property_name != NULL;
5314e98e3e1Schristos        reg_property_name++)
5324e98e3e1Schristos     {
5334e98e3e1Schristos       if (hw_find_property (hw, *reg_property_name) != NULL)
5344e98e3e1Schristos 	{
5354e98e3e1Schristos 	  reg_property_spec reg;
5364e98e3e1Schristos 	  int reg_entry;
5374e98e3e1Schristos 	  for (reg_entry = 0;
5384e98e3e1Schristos 	       hw_find_reg_array_property (hw, *reg_property_name, reg_entry,
5394e98e3e1Schristos 					   &reg);
5404e98e3e1Schristos 	       reg_entry++)
5414e98e3e1Schristos 	    {
5424e98e3e1Schristos 	      unsigned_word attach_address;
5434e98e3e1Schristos 	      int attach_space;
5444e98e3e1Schristos 	      unsigned attach_size;
5454e98e3e1Schristos 	      if (!hw_unit_address_to_attach_address (hw_parent (hw),
5464e98e3e1Schristos 						      &reg.address,
5474e98e3e1Schristos 						      &attach_space,
5484e98e3e1Schristos 						      &attach_address,
5494e98e3e1Schristos 						      hw))
5504e98e3e1Schristos 		continue;
5514e98e3e1Schristos 	      if (!hw_unit_size_to_attach_size (hw_parent (hw),
5524e98e3e1Schristos 						&reg.size,
5534e98e3e1Schristos 						&attach_size, hw))
5544e98e3e1Schristos 		continue;
5554e98e3e1Schristos 	      hw_attach_address (hw_parent (hw),
5564e98e3e1Schristos 				 0,
5574e98e3e1Schristos 				 attach_space, attach_address, attach_size,
5584e98e3e1Schristos 				 hw);
5594e98e3e1Schristos 	    }
5604e98e3e1Schristos 	  /* if first option matches don't try for any others */
5614e98e3e1Schristos 	  if (reg_property_name == reg_property_names)
5624e98e3e1Schristos 	    break;
5634e98e3e1Schristos 	}
5644e98e3e1Schristos     }
5654e98e3e1Schristos }
566