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 ®); 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 ®.address, 5474e98e3e1Schristos &attach_space, 5484e98e3e1Schristos &attach_address, 5494e98e3e1Schristos hw)) 5504e98e3e1Schristos continue; 5514e98e3e1Schristos if (!hw_unit_size_to_attach_size (hw_parent (hw), 5524e98e3e1Schristos ®.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