diff options
author | Andrew Cagney <cagney@redhat.com> | 1998-03-22 05:06:27 +0000 |
---|---|---|
committer | Andrew Cagney <cagney@redhat.com> | 1998-03-22 05:06:27 +0000 |
commit | e5f0d498af49da4680564df06b9709423523ba6e (patch) | |
tree | 0e052b4638713a10794e9fbd11df0651dcf974c7 /sim | |
parent | b1e9223cee0728b89f6b909c445a896d9fe41452 (diff) | |
download | gdb-e5f0d498af49da4680564df06b9709423523ba6e.zip gdb-e5f0d498af49da4680564df06b9709423523ba6e.tar.gz gdb-e5f0d498af49da4680564df06b9709423523ba6e.tar.bz2 |
Add hw_{malloc,zalloc,free} functions to hw_device. Any memory
allocated using these functions is reclaimed when the corresponding
device is deleted.
Diffstat (limited to 'sim')
-rw-r--r-- | sim/common/ChangeLog | 29 | ||||
-rw-r--r-- | sim/common/dv-pal.c | 2 | ||||
-rw-r--r-- | sim/common/hw-base.c | 68 | ||||
-rw-r--r-- | sim/common/hw-base.h | 128 | ||||
-rw-r--r-- | sim/common/hw-device.c | 214 | ||||
-rw-r--r-- | sim/common/hw-device.h | 21 | ||||
-rw-r--r-- | sim/common/hw-properties.c | 881 |
7 files changed, 1335 insertions, 8 deletions
diff --git a/sim/common/ChangeLog b/sim/common/ChangeLog index 65499fd..e760208 100644 --- a/sim/common/ChangeLog +++ b/sim/common/ChangeLog @@ -1,3 +1,32 @@ +Sun Mar 22 15:23:35 1998 Andrew Cagney <cagney@b1.cygnus.com> + + * hw-device.h (HW_ZALLOC, HW_MALLOC): New macros. + (hw_alloc_data): Delcare. + (struct hw): Add member alloc_of_hw. + + * hw-device.c (hw_zalloc, hw_malloc, hw_free, hw_free_all): New + functions. Assocate memory with a device. + (stdlib.h): Include. + + * hw-base.h (set_hw_delete): Define. + (hw_delete_callback): Declare. + (hw_delete): Declare. + + * hw-base.c (hw_delete): Implement function. + (struct hw_base_data): Add member to_delete. + (ignore_hw_delete): New function, does nothing. + (hw_create): Set the hw_delete method. + (hw_create): Allocate the base type using HW_ZALLOC before setting + any methods. + + * hw-properties.c: Replace zalloc/zfree with hw_zalloc/hw_free. + + * hw-ports.c: Replace zalloc/zfree with hw_zalloc/hw_free. + (attach_hw_port_edge): Add struct hw argument + + * dv-pal.c (hw_pal_finish): Replace zalloc/zfree with + hw_zalloc/hw_free. + Sun Mar 22 15:09:52 1998 Andrew Cagney <cagney@b1.cygnus.com> * hw-device.h (hw_attach_address_callback, diff --git a/sim/common/dv-pal.c b/sim/common/dv-pal.c index afef9c8..f15f5c9 100644 --- a/sim/common/dv-pal.c +++ b/sim/common/dv-pal.c @@ -368,7 +368,7 @@ static void hw_pal_finish (struct hw *hw) { /* create the descriptor */ - hw_pal_device *hw_pal = ZALLOC (hw_pal_device); + hw_pal_device *hw_pal = HW_ZALLOC (hw, hw_pal_device); hw_pal->output.status = 1; hw_pal->output.buffer = '\0'; hw_pal->input.status = 0; diff --git a/sim/common/hw-base.c b/sim/common/hw-base.c index 0c4b8a5..495f96d 100644 --- a/sim/common/hw-base.c +++ b/sim/common/hw-base.c @@ -24,10 +24,6 @@ /* LATER: #include "hwconfig.h" */ -struct hw_base_data { - int finished_p; - const struct hw_device_descriptor *descriptor; -}; extern const struct hw_device_descriptor dv_core_descriptor[]; extern const struct hw_device_descriptor dv_pal_descriptor[]; const struct hw_device_descriptor *hw_descriptors[] = { @@ -50,6 +46,11 @@ const struct hw_device_descriptor *hw_descriptors[] = { #include <ctype.h> +struct hw_base_data { + int finished_p; + const struct hw_device_descriptor *descriptor; + hw_delete_callback *to_delete; +}; static int generic_hw_unit_decode (struct hw *bus, @@ -287,6 +288,14 @@ panic_hw_port_event (struct hw *me, hw_abort (me, "no port method"); } +static void +ignore_hw_delete (struct hw *me) +{ + /* NOP */ +} + + + static const char * full_name_of_hw (struct hw *leaf, @@ -345,6 +354,7 @@ hw_create (SIM_DESC sd, const char *unit, const char *args) { + /* NOTE: HW must be allocated using ZALLOC, others use HW_ZALLOC */ struct hw *hw = ZALLOC (struct hw); /* our identity */ @@ -391,6 +401,10 @@ hw_create (SIM_DESC sd, else hw->path_of_hw = "/"; + /* create our base type */ + hw->base_of_hw = HW_ZALLOC (hw, struct hw_base_data); + hw->base_of_hw->finished_p = 0; + /* our callbacks */ set_hw_io_read_buffer (hw, panic_hw_io_read_buffer); set_hw_io_write_buffer (hw, panic_hw_io_write_buffer); @@ -402,6 +416,7 @@ hw_create (SIM_DESC sd, set_hw_unit_size_to_attach_size (hw, generic_hw_unit_size_to_attach_size); set_hw_attach_address (hw, passthrough_hw_attach_address); set_hw_detach_address (hw, passthrough_hw_detach_address); + set_hw_delete (hw, ignore_hw_delete); /* locate a descriptor */ { @@ -417,13 +432,11 @@ hw_create (SIM_DESC sd, { if (strcmp (family, entry->family) == 0) { - hw->base_of_hw = ZALLOC (struct hw_base_data); hw->base_of_hw->descriptor = entry; - hw->base_of_hw->finished_p = 0; } } } - if (hw->base_of_hw == NULL) + if (hw->base_of_hw->descriptor == NULL) { hw_abort (parent, "Unknown device `%s'", family); } @@ -465,3 +478,44 @@ hw_finish (struct hw *me) me->base_of_hw->descriptor->to_finish (me); me->base_of_hw->finished_p = 1; } + + +void +hw_delete (struct hw *me) +{ + /* give the object a chance to tidy up */ + me->base_of_hw->to_delete (me); + + /* now unlink us from the tree */ + if (hw_parent (me)) + { + struct hw **sibling = &hw_parent (me)->child_of_hw; + while (*sibling != NULL) + { + if (*sibling == me) + { + *sibling = me->sibling_of_hw; + me->sibling_of_hw = NULL; + me->parent_of_hw = NULL; + break; + } + } + } + + /* some sanity checks */ + if (hw_child (me) != NULL) + { + hw_abort (me, "attempt to delete device with children"); + } + if (hw_sibling (me) != NULL) + { + hw_abort (me, "attempt to delete device with siblings"); + } + + /* blow away all memory belonging to the device */ + hw_free_all (me); + + /* finally */ + zfree (me->base_of_hw); + zfree (me); +} diff --git a/sim/common/hw-base.h b/sim/common/hw-base.h new file mode 100644 index 0000000..ee787dd --- /dev/null +++ b/sim/common/hw-base.h @@ -0,0 +1,128 @@ +/* This file is part of the program psim. + + Copyright (C) 1994-1998, Andrew Cagney <cagney@highland.com.au> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + */ + + +#ifndef HW_ROOT +#define HW_ROOT + +/* A root device from which dv-* devices can be built */ + +#include "hw-device.h" + +#include "hw-properties.h" +/* #include "hw-instances.h" */ +/* #include "hw-handles.h" */ +#include "hw-ports.h" + +typedef void (hw_finish_callback) + (struct hw *me); + +struct hw_device_descriptor { + const char *family; + hw_finish_callback *to_finish; +}; + +/* Create a primative device */ + +struct hw *hw_create +(SIM_DESC sd, + struct hw *parent, + const char *family, + const char *name, + const char *unit, + const char *args); + + +/* Complete the creation of that device (finish overrides methods + using the set_hw_* operations below) */ + +void hw_finish +(struct hw *me); + +int hw_finished_p +(struct hw *me); + + +/* Delete the entire device */ + +void hw_delete +(struct hw *me); + + +/* Override device methods */ + +#define set_hw_data(hw, value) \ +((hw)->data_of_hw = (value)) + +#define set_hw_reset(hw, method) \ +((hw)->to_reset = method) + +#define set_hw_io_read_buffer(hw, method) \ +((hw)->to_io_read_buffer = (method)) +#define set_hw_io_write_buffer(hw, method) \ +((hw)->to_io_write_buffer = (method)) + +#define set_hw_dma_read_buffer(me, method) \ +((me)->to_dma_read_buffer = (method)) +#define set_hw_dma_write_buffer(me, method) \ +((me)->to_dma_write_buffer = (method)) + +#define set_hw_attach_address(hw, method) \ +((hw)->to_attach_address = (method)) +#define set_hw_detach_address(hw, method) \ +((hw)->to_detach_address = (method)) + +#define set_hw_unit_decode(hw, method) \ +((hw)->to_unit_decode = (method)) +#define set_hw_unit_encode(hw, method) \ +((hw)->to_unit_encode = (method)) + +#define set_hw_unit_address_to_attach_address(hw, method) \ +((hw)->to_unit_address_to_attach_address = (method)) +#define set_hw_unit_size_to_attach_size(hw, method) \ +((hw)->to_unit_size_to_attach_size = (method)) + +typedef void (hw_delete_callback) + (struct hw *me); + +#define set_hw_delete(hw, method) \ +((hw)->base_of_hw->to_delete = (method)) + + +struct hw_port_descriptor { + const char *name; + int number; + int nr_ports; + port_direction direction; +}; + +typedef void (hw_port_event_callback) + (struct hw *me, + int my_port, + struct hw *source, + int source_port, + int level, + sim_cpu *processor, + sim_cia cia); + +extern void set_hw_ports (struct hw *hw, const struct hw_port_descriptor ports[]); +extern void set_hw_port_event (struct hw *hw, hw_port_event_callback *to_port_event); + +#endif diff --git a/sim/common/hw-device.c b/sim/common/hw-device.c new file mode 100644 index 0000000..3f57190 --- /dev/null +++ b/sim/common/hw-device.c @@ -0,0 +1,214 @@ +/* This file is part of the program psim. + + Copyright (C) 1994-1998, Andrew Cagney <cagney@highland.com.au> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + */ + + +#include "sim-main.h" + +#include "hw-device.h" +#include "hw-properties.h" + +#if HAVE_STDLIB_H +#include <stdlib.h> +#endif + + +/* Address methods */ + +const hw_unit * +hw_unit_address (struct hw *me) +{ + return &me->unit_address_of_hw; +} + + + +/* IOCTL: */ + +int +hw_ioctl (struct hw *me, + sim_cpu *processor, + sim_cia cia, + hw_ioctl_request request, + ...) +{ + int status; + va_list ap; + va_start(ap, request); + status = me->to_ioctl (me, processor, cia, request, ap); + va_end(ap); + return status; +} + +/* I/O */ + +void volatile +hw_abort (struct hw *me, + const char *fmt, + ...) +{ + SIM_DESC sd; + const char *name; + va_list ap; + va_start(ap, fmt); + /* find a system to abort through */ + if (me == NULL || hw_system (me) == NULL) + sd = NULL; + else + sd = hw_system (me); + /* find an identity */ + if (me != NULL && hw_path (me) != NULL && hw_path (me) [0] != '\0') + name = hw_path (me); + else if (me != NULL && hw_name (me) != NULL && hw_name (me)[0] != '\0') + name = hw_name (me); + else if (me != NULL && hw_family (me) != NULL && hw_family (me)[0] != '\0') + name = hw_family (me); + else + name = "device"; + /* report the problem */ + sim_io_eprintf (sd, "%s: ", name); + sim_io_evprintf (sd, fmt, ap); + sim_io_error (sd, "%s", ""); +} + + +/* The event queue abstraction (for devices) */ + + +struct _hw_event { + void *data; + struct hw *me; + hw_event_handler *handler; + sim_event *real; +}; + +/* Pass the H/W event onto the real handler */ + +static void +bounce_hw_event (SIM_DESC sd, + void *data) +{ + hw_event event = * (hw_event*) data; + zfree (data); + event.handler (event.me, event.data); +} + + +/* Map onto the event functions */ + +hw_event * +hw_event_queue_schedule (struct hw *me, + signed64 delta_time, + hw_event_handler *handler, + void *data) +{ + hw_event *event = ZALLOC (hw_event); + event->data = data; + event->handler = handler; + event->me = me; + event->real = sim_events_schedule (hw_system (me), + delta_time, + bounce_hw_event, + event); + return event; +} + +void +hw_event_queue_deschedule (struct hw *me, + hw_event *event_to_remove) +{ + sim_events_deschedule (hw_system (me), + event_to_remove->real); + zfree (event_to_remove); +} + +signed64 +hw_event_queue_time (struct hw *me) +{ + return sim_events_time (hw_system (me)); +} + + +/* Mechanism for associating allocated memory regions to a device. + When a device is deleted any remaining memory regions are also + reclaimed. + + FIXME: Perhaphs this can be generalized, perhaphs it should not + be. */ + +struct hw_alloc_data { + void *alloc; + int zalloc_p; + struct hw_alloc_data *next; +}; + +extern void * +hw_zalloc (struct hw *me, unsigned long size) +{ + struct hw_alloc_data *memory = ZALLOC (struct hw_alloc_data); + memory->alloc = zalloc (size); + memory->zalloc_p = 1; + memory->next = me->alloc_of_hw; + me->alloc_of_hw = memory; + return memory->alloc; +} + +extern void * +hw_malloc (struct hw *me, unsigned long size) +{ + struct hw_alloc_data *memory = ZALLOC (struct hw_alloc_data); + memory->alloc = zalloc (size); + memory->zalloc_p = 0; + memory->next = me->alloc_of_hw; + me->alloc_of_hw = memory; + return memory->alloc; +} + +extern void +hw_free (struct hw *me, + void *alloc) +{ + struct hw_alloc_data **memory; + for (memory = &me->alloc_of_hw; + *memory != NULL; + memory = &(*memory)->next) + { + if ((*memory)->alloc == alloc) + { + struct hw_alloc_data *die = (*memory); + (*memory) = die->next; + if (die->zalloc_p) + zfree (die->alloc); + else + free (die->alloc); + zfree (die); + return; + } + } + hw_abort (me, "free of memory not belonging to a device"); +} + +extern void +hw_free_all (struct hw *me) +{ + while (me->alloc_of_hw != NULL) + { + hw_free (me, me->alloc_of_hw->alloc); + } +} diff --git a/sim/common/hw-device.h b/sim/common/hw-device.h index ecbedca..4abe207 100644 --- a/sim/common/hw-device.h +++ b/sim/common/hw-device.h @@ -350,6 +350,25 @@ typedef int (hw_unit_size_to_attach_size_callback) +/* Memory allocator / de-allocator. + + All memory allocated using the below will be automatically + reclaimed when the device is deleted. + + A device implementation can either use these functions when + allocating memory or use malloc/zalloc/free an co-ordinate its own + garbage collection. */ + +#define HW_ZALLOC(me,type) (type*) hw_zalloc (me, sizeof (type)) +#define HW_MALLOC(me,type) (type*) hw_malloc (me, sizeof (type)) + +extern void *hw_zalloc (struct hw *me, unsigned long size); +extern void *hw_malloc (struct hw *me, unsigned long size); +extern void hw_free (struct hw *me, void *); +extern void hw_free_all (struct hw *me); + + + /* Utilities: */ @@ -435,6 +454,7 @@ void volatile NORETURN hw_abort struct hw_property_data; struct hw_port_data; struct hw_base_data; +struct hw_alloc_data; /* Finally the hardware device - keep your grubby little mits off of these internals! :-) */ @@ -489,6 +509,7 @@ struct hw { struct hw_property_data *properties_of_hw; struct hw_port_data *ports_of_hw; struct hw_base_data *base_of_hw; + struct hw_alloc_data *alloc_of_hw; }; diff --git a/sim/common/hw-properties.c b/sim/common/hw-properties.c new file mode 100644 index 0000000..a42c0c9 --- /dev/null +++ b/sim/common/hw-properties.c @@ -0,0 +1,881 @@ +/* This file is part of the program psim. + + Copyright (C) 1994-1998, Andrew Cagney <cagney@highland.com.au> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + */ + +#include "sim-main.h" + +#include "hw-device.h" +#include "hw-properties.h" + +#include "sim-assert.h" + +#ifdef HAVE_STRING_H +#include <string.h> +#else +#ifdef HAVE_STRINGS_H +#include <strings.h> +#endif +#endif + +#define TRACE(A,B) + +/* property entries */ + +struct hw_property_data { + struct hw_property_data *next; + struct hw_property *property; + const void *init_array; + unsigned sizeof_init_array; +}; + +/* Device Properties: */ + +static struct hw_property_data * +find_property_data (struct hw *me, + const char *property) +{ + struct hw_property_data *entry; + ASSERT (property != NULL); + entry = me->properties_of_hw; + while (entry != NULL) + { + if (strcmp (entry->property->name, property) == 0) + return entry; + entry = entry->next; + } + return NULL; +} + + +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) +{ + struct hw_property_data *new_entry = NULL; + struct hw_property *new_value = NULL; + + /* find the list end */ + struct hw_property_data **insertion_point = &me->properties_of_hw; + while (*insertion_point != NULL) + { + if (strcmp ((*insertion_point)->property->name, property) == 0) + return; + insertion_point = &(*insertion_point)->next; + } + + /* create a new value */ + new_value = HW_ZALLOC (me, struct hw_property); + new_value->name = (char *) strdup (property); + new_value->type = type; + if (sizeof_array > 0) + { + void *new_array = hw_zalloc (me, sizeof_array); + memcpy (new_array, array, sizeof_array); + new_value->array = new_array; + new_value->sizeof_array = sizeof_array; + } + new_value->owner = me; + new_value->original = original; + new_value->disposition = disposition; + + /* insert the value into the list */ + new_entry = HW_ZALLOC (me, struct hw_property_data); + *insertion_point = new_entry; + if (sizeof_init_array > 0) + { + void *new_init_array = hw_zalloc (me, sizeof_init_array); + memcpy (new_init_array, init_array, sizeof_init_array); + new_entry->init_array = new_init_array; + new_entry->sizeof_init_array = sizeof_init_array; + } + new_entry->property = new_value; +} + + +static void +hw_set_property (struct hw *me, + const char *property, + hw_property_type type, + const void *array, + int sizeof_array) +{ + /* find the property */ + struct hw_property_data *entry = find_property_data (me, property); + if (entry != NULL) + { + /* existing property - update it */ + void *new_array = 0; + struct hw_property *value = entry->property; + /* check the type matches */ + if (value->type != type) + hw_abort (me, "conflict between type of new and old value for property %s", property); + /* replace its value */ + if (value->array != NULL) + hw_free (me, (void*)value->array); + new_array = (sizeof_array > 0 + ? hw_zalloc (me, sizeof_array) + : (void*)0); + value->array = new_array; + value->sizeof_array = sizeof_array; + if (sizeof_array > 0) + memcpy (new_array, array, sizeof_array); + return; + } + else + { + /* new property - create it */ + hw_add_property (me, property, type, + NULL, 0, array, sizeof_array, + NULL, temporary_object); + } +} + + +#if 0 +static void +clean_hw_properties (struct hw *me) +{ + struct hw_property_data **delete_point = &me->properties_of_hw; + while (*delete_point != NULL) + { + struct hw_property_data *current = *delete_point; + switch (current->property->disposition) + { + case permenant_object: + /* zap the current value, will be initialized later */ + ASSERT (current->init_array != NULL); + if (current->property->array != NULL) + { + hw_free (me, (void*)current->property->array); + current->property->array = NULL; + } + delete_point = &(*delete_point)->next; + break; + case temporary_object: + /* zap the actual property, was created during simulation run */ + ASSERT (current->init_array == NULL); + *delete_point = current->next; + if (current->property->array != NULL) + hw_free (me, (void*)current->property->array); + hw_free (me, current->property); + hw_free (me, current); + break; + } + } +} +#endif + +#if 0 +void +hw_init_static_properties (SIM_DESC sd, + struct hw *me, + void *data) +{ + struct hw_property_data *property; + for (property = me->properties_of_hw; + property != NULL; + property = property->next) + { + ASSERT (property->init_array != NULL); + ASSERT (property->property->array == NULL); + ASSERT(property->property->disposition == permenant_object); + switch (property->property->type) + { + case array_property: + case boolean_property: + case range_array_property: + case reg_array_property: + case string_property: + case string_array_property: + case integer_property: + /* delete the property, and replace it with the original */ + hw_set_property (me, property->property->name, + property->property->type, + property->init_array, + property->sizeof_init_array); + break; +#if 0 + case ihandle_property: + break; +#endif + } + } +} +#endif + + +#if 0 +void +hw_init_runtime_properties (SIM_DESC sd, + struct hw *me, + void *data) +{ + struct hw_property_data *property; + for (property = me->properties_of_hw; + property != NULL; + property = property->next) + { + switch (property->property->disposition) + { + case permenant_object: + switch (property->property->type) + { +#if 0 + case ihandle_property: + { + struct hw_instance *ihandle; + ihandle_runtime_property_spec spec; + ASSERT (property->init_array != NULL); + ASSERT (property->property->array == NULL); + hw_find_ihandle_runtime_property (me, property->property->name, &spec); + ihandle = tree_instance (me, spec.full_path); + hw_set_ihandle_property (me, property->property->name, ihandle); + break; + } +#endif + case array_property: + case boolean_property: + case range_array_property: + case integer_property: + case reg_array_property: + case string_property: + case string_array_property: + ASSERT (property->init_array != NULL); + ASSERT (property->property->array != NULL); + break; + } + break; + case temporary_object: + ASSERT (property->init_array == NULL); + ASSERT (property->property->array != NULL); + break; + } + } +} +#endif + + + +const struct hw_property * +hw_next_property (const struct hw_property *property) +{ + /* find the property in the list */ + struct hw *owner = property->owner; + struct hw_property_data *entry = owner->properties_of_hw; + while (entry != NULL && entry->property != property) + entry = entry->next; + /* now return the following property */ + ASSERT (entry != NULL); /* must be a member! */ + if (entry->next != NULL) + return entry->next->property; + else + return NULL; +} + + +const struct hw_property * +hw_find_property (struct hw *me, + const char *property) +{ + if (me == NULL) + { + return NULL; + } + else if (property == NULL || strcmp (property, "") == 0) + { + if (me->properties_of_hw == NULL) + return NULL; + else + return me->properties_of_hw->property; + } + else + { + struct hw_property_data *entry = find_property_data (me, property); + if (entry != NULL) + return entry->property; + } + return NULL; +} + + +void +hw_add_array_property (struct hw *me, + const char *property, + const void *array, + int sizeof_array) +{ + hw_add_property (me, property, array_property, + array, sizeof_array, array, sizeof_array, + NULL, permenant_object); +} + +void +hw_set_array_property (struct hw *me, + const char *property, + const void *array, + int sizeof_array) +{ + hw_set_property (me, property, array_property, array, sizeof_array); +} + +const struct hw_property * +hw_find_array_property (struct hw *me, + const char *property) +{ + const struct hw_property *node; + node = hw_find_property (me, property); + if (node == NULL + || node->type != array_property) + hw_abort(me, "property %s not found or of wrong type", property); + return node; +} + + + +void +hw_add_boolean_property (struct hw *me, + const char *property, + int boolean) +{ + signed32 new_boolean = (boolean ? -1 : 0); + hw_add_property (me, property, boolean_property, + &new_boolean, sizeof(new_boolean), + &new_boolean, sizeof(new_boolean), + NULL, permenant_object); +} + +int +hw_find_boolean_property (struct hw *me, + const char *property) +{ + const struct hw_property *node; + unsigned_cell boolean; + node = hw_find_property (me, property); + if (node == NULL || node->type != boolean_property) + hw_abort (me, "property %s not found or of wrong type", property); + ASSERT (sizeof (boolean) == node->sizeof_array); + memcpy (&boolean, node->array, sizeof (boolean)); + return boolean; +} + + + +#if 0 +void +hw_add_ihandle_runtime_property (struct hw *me, + const char *property, + const ihandle_runtime_property_spec *ihandle) +{ + /* enter the full path as the init array */ + hw_add_property (me, property, ihandle_property, + ihandle->full_path, strlen(ihandle->full_path) + 1, + NULL, 0, + NULL, permenant_object); +} +#endif + +#if 0 +void +hw_find_ihandle_runtime_property (struct hw *me, + const char *property, + ihandle_runtime_property_spec *ihandle) +{ + struct hw_property_data *entry = find_property_data (me, property); + TRACE (trace_devices, + ("hw_find_ihandle_runtime_property(me=0x%lx, property=%s)\n", + (long)me, property)); + if (entry == NULL + || entry->property->type != ihandle_property + || entry->property->disposition != permenant_object) + hw_abort (me, "property %s not found or of wrong type", property); + ASSERT (entry->init_array != NULL); + /* the full path */ + ihandle->full_path = entry->init_array; +} +#endif + + + +#if 0 +void +hw_set_ihandle_property (struct hw *me, + const char *property, + hw_instance *ihandle) +{ + unsigned_cell cells; + cells = H2BE_cell (hw_instance_to_external (ihandle)); + hw_set_property (me, property, ihandle_property, + &cells, sizeof (cells)); + +} +#endif + +#if 0 +hw_instance * +hw_find_ihandle_property (struct hw *me, + const char *property) +{ + const hw_property_data *node; + unsigned_cell ihandle; + hw_instance *instance; + + node = hw_find_property (me, property); + if (node == NULL || node->type != ihandle_property) + hw_abort(me, "property %s not found or of wrong type", property); + if (node->array == NULL) + hw_abort(me, "runtime property %s not yet initialized", property); + + ASSERT (sizeof(ihandle) == node->sizeof_array); + memcpy (&ihandle, node->array, sizeof(ihandle)); + instance = external_to_hw_instance (me, BE2H_cell(ihandle)); + ASSERT (instance != NULL); + return instance; +} +#endif + + +void +hw_add_integer_property (struct hw *me, + const char *property, + signed_cell integer) +{ + H2BE (integer); + hw_add_property (me, property, integer_property, + &integer, sizeof(integer), + &integer, sizeof(integer), + NULL, permenant_object); +} + +signed_cell +hw_find_integer_property (struct hw *me, + const char *property) +{ + const struct hw_property *node; + signed_cell integer; + TRACE (trace_devices, + ("hw_find_integer(me=0x%lx, property=%s)\n", + (long)me, property)); + node = hw_find_property (me, property); + if (node == NULL || node->type != integer_property) + hw_abort (me, "property %s not found or of wrong type", property); + ASSERT (sizeof(integer) == node->sizeof_array); + memcpy (&integer, node->array, sizeof (integer)); + return BE2H_cell (integer); +} + +int +hw_find_integer_array_property (struct hw *me, + const char *property, + unsigned index, + signed_cell *integer) +{ + const struct hw_property *node; + int sizeof_integer = sizeof (*integer); + signed_cell *cell; + TRACE (trace_devices, + ("hw_find_integer(me=0x%lx, property=%s)\n", + (long)me, property)); + + /* check things sane */ + node = hw_find_property (me, property); + if (node == NULL + || (node->type != integer_property + && node->type != array_property)) + hw_abort (me, "property %s not found or of wrong type", property); + if ((node->sizeof_array % sizeof_integer) != 0) + hw_abort (me, "property %s contains an incomplete number of cells", property); + if (node->sizeof_array <= sizeof_integer * index) + return 0; + + /* Find and convert the value */ + cell = ((signed_cell*)node->array) + index; + *integer = BE2H_cell (*cell); + + return node->sizeof_array / sizeof_integer; +} + + +static unsigned_cell * +unit_address_to_cells (const hw_unit *unit, + unsigned_cell *cell, + int nr_cells) +{ + int i; + ASSERT(nr_cells == unit->nr_cells); + for (i = 0; i < unit->nr_cells; i++) + { + *cell = H2BE_cell (unit->cells[i]); + cell += 1; + } + return cell; +} + + +static const unsigned_cell * +cells_to_unit_address (const unsigned_cell *cell, + hw_unit *unit, + int nr_cells) +{ + int i; + memset(unit, 0, sizeof(*unit)); + unit->nr_cells = nr_cells; + for (i = 0; i < unit->nr_cells; i++) + { + unit->cells[i] = BE2H_cell (*cell); + cell += 1; + } + return cell; +} + + +static unsigned +nr_range_property_cells (struct hw *me, + int nr_ranges) +{ + return ((hw_unit_nr_address_cells (me) + + hw_unit_nr_address_cells (hw_parent (me)) + + hw_unit_nr_size_cells (me)) + ) * nr_ranges; +} + +void +hw_add_range_array_property (struct hw *me, + const char *property, + const range_property_spec *ranges, + unsigned nr_ranges) +{ + unsigned sizeof_cells = (nr_range_property_cells (me, nr_ranges) + * sizeof (unsigned_cell)); + unsigned_cell *cells = hw_zalloc (me, sizeof_cells); + unsigned_cell *cell; + int i; + + /* copy the property elements over */ + cell = cells; + for (i = 0; i < nr_ranges; i++) + { + const range_property_spec *range = &ranges[i]; + /* copy the child address */ + cell = unit_address_to_cells (&range->child_address, cell, + hw_unit_nr_address_cells (me)); + /* copy the parent address */ + cell = unit_address_to_cells (&range->parent_address, cell, + hw_unit_nr_address_cells (hw_parent (me))); + /* copy the size */ + cell = unit_address_to_cells (&range->size, cell, + hw_unit_nr_size_cells (me)); + } + ASSERT (cell == &cells[nr_range_property_cells (me, nr_ranges)]); + + /* add it */ + hw_add_property (me, property, range_array_property, + cells, sizeof_cells, + cells, sizeof_cells, + NULL, permenant_object); + + hw_free (me, cells); +} + +int +hw_find_range_array_property (struct hw *me, + const char *property, + unsigned index, + range_property_spec *range) +{ + const struct hw_property *node; + unsigned sizeof_entry = (nr_range_property_cells (me, 1) + * sizeof (unsigned_cell)); + const unsigned_cell *cells; + + /* locate the property */ + node = hw_find_property (me, property); + if (node == NULL || node->type != range_array_property) + hw_abort (me, "property %s not found or of wrong type", property); + + /* aligned ? */ + if ((node->sizeof_array % sizeof_entry) != 0) + hw_abort (me, "property %s contains an incomplete number of entries", + property); + + /* within bounds? */ + if (node->sizeof_array < sizeof_entry * (index + 1)) + return 0; + + /* find the range of interest */ + cells = (unsigned_cell*)((char*)node->array + sizeof_entry * index); + + /* copy the child address out - converting as we go */ + cells = cells_to_unit_address (cells, &range->child_address, + hw_unit_nr_address_cells (me)); + + /* copy the parent address out - converting as we go */ + cells = cells_to_unit_address (cells, &range->parent_address, + hw_unit_nr_address_cells (hw_parent (me))); + + /* copy the size - converting as we go */ + cells = cells_to_unit_address (cells, &range->size, + hw_unit_nr_size_cells (me)); + + return node->sizeof_array / sizeof_entry; +} + + +static unsigned +nr_reg_property_cells (struct hw *me, + int nr_regs) +{ + return (hw_unit_nr_address_cells (hw_parent(me)) + + hw_unit_nr_size_cells (hw_parent(me)) + ) * nr_regs; +} + +void +hw_add_reg_array_property (struct hw *me, + const char *property, + const reg_property_spec *regs, + unsigned nr_regs) +{ + unsigned sizeof_cells = (nr_reg_property_cells (me, nr_regs) + * sizeof (unsigned_cell)); + unsigned_cell *cells = hw_zalloc (me, sizeof_cells); + unsigned_cell *cell; + int i; + + /* copy the property elements over */ + cell = cells; + for (i = 0; i < nr_regs; i++) + { + const reg_property_spec *reg = ®s[i]; + /* copy the address */ + cell = unit_address_to_cells (®->address, cell, + hw_unit_nr_address_cells (hw_parent (me))); + /* copy the size */ + cell = unit_address_to_cells (®->size, cell, + hw_unit_nr_size_cells (hw_parent (me))); + } + ASSERT (cell == &cells[nr_reg_property_cells (me, nr_regs)]); + + /* add it */ + hw_add_property (me, property, reg_array_property, + cells, sizeof_cells, + cells, sizeof_cells, + NULL, permenant_object); + + hw_free (me, cells); +} + +int +hw_find_reg_array_property (struct hw *me, + const char *property, + unsigned index, + reg_property_spec *reg) +{ + const struct hw_property *node; + unsigned sizeof_entry = (nr_reg_property_cells (me, 1) + * sizeof (unsigned_cell)); + const unsigned_cell *cells; + + /* locate the property */ + node = hw_find_property (me, property); + if (node == NULL || node->type != reg_array_property) + hw_abort (me, "property %s not found or of wrong type", property); + + /* aligned ? */ + if ((node->sizeof_array % sizeof_entry) != 0) + hw_abort (me, "property %s contains an incomplete number of entries", + property); + + /* within bounds? */ + if (node->sizeof_array < sizeof_entry * (index + 1)) + return 0; + + /* find the range of interest */ + cells = (unsigned_cell*)((char*)node->array + sizeof_entry * index); + + /* copy the address out - converting as we go */ + cells = cells_to_unit_address (cells, ®->address, + hw_unit_nr_address_cells (hw_parent (me))); + + /* copy the size out - converting as we go */ + cells = cells_to_unit_address (cells, ®->size, + hw_unit_nr_size_cells (hw_parent (me))); + + return node->sizeof_array / sizeof_entry; +} + + +void +hw_add_string_property (struct hw *me, + const char *property, + const char *string) +{ + hw_add_property (me, property, string_property, + string, strlen(string) + 1, + string, strlen(string) + 1, + NULL, permenant_object); +} + +const char * +hw_find_string_property (struct hw *me, + const char *property) +{ + const struct hw_property *node; + const char *string; + node = hw_find_property (me, property); + if (node == NULL || node->type != string_property) + hw_abort (me, "property %s not found or of wrong type", property); + string = node->array; + ASSERT (strlen(string) + 1 == node->sizeof_array); + return string; +} + +void +hw_add_string_array_property (struct hw *me, + const char *property, + const string_property_spec *strings, + unsigned nr_strings) +{ + int sizeof_array; + int string_nr; + char *array; + char *chp; + if (nr_strings == 0) + hw_abort (me, "property %s must be non-null", property); + /* total up the size of the needed array */ + for (sizeof_array = 0, string_nr = 0; + string_nr < nr_strings; + string_nr ++) + { + sizeof_array += strlen (strings[string_nr]) + 1; + } + /* create the array */ + array = (char*) hw_zalloc (me, sizeof_array); + chp = array; + for (string_nr = 0; + string_nr < nr_strings; + string_nr++) + { + strcpy (chp, strings[string_nr]); + chp += strlen (chp) + 1; + } + ASSERT (chp == array + sizeof_array); + /* now enter it */ + hw_add_property (me, property, string_array_property, + array, sizeof_array, + array, sizeof_array, + NULL, permenant_object); +} + +int +hw_find_string_array_property (struct hw *me, + const char *property, + unsigned index, + string_property_spec *string) +{ + const struct hw_property *node; + node = hw_find_property (me, property); + if (node == NULL) + hw_abort (me, "property %s not found", property); + switch (node->type) + { + default: + hw_abort (me, "property %s of wrong type", property); + break; + case string_property: + if (index == 0) + { + *string = node->array; + ASSERT (strlen(*string) + 1 == node->sizeof_array); + return 1; + } + break; + case array_property: + if (node->sizeof_array == 0 + || ((char*)node->array)[node->sizeof_array - 1] != '\0') + hw_abort (me, "property %s invalid for string array", property); + /* FALL THROUGH */ + case string_array_property: + ASSERT (node->sizeof_array > 0); + ASSERT (((char*)node->array)[node->sizeof_array - 1] == '\0'); + { + const char *chp = node->array; + int nr_entries = 0; + /* count the number of strings, keeping an eye out for the one + we're looking for */ + *string = chp; + do + { + if (*chp == '\0') + { + /* next string */ + nr_entries++; + chp++; + if (nr_entries == index) + *string = chp; + } + else + { + chp++; + } + } while (chp < (char*)node->array + node->sizeof_array); + if (index < nr_entries) + return nr_entries; + else + { + *string = NULL; + return 0; + } + } + break; + } + return 0; +} + +void +hw_add_duplicate_property (struct hw *me, + const char *property, + const struct hw_property *original) +{ + struct hw_property_data *master; + TRACE (trace_devices, + ("hw_add_duplicate_property(me=0x%lx, property=%s, ...)\n", + (long)me, property)); + if (original->disposition != permenant_object) + hw_abort (me, "Can only duplicate permenant objects"); + /* find the original's master */ + master = original->owner->properties_of_hw; + while (master->property != original) + { + master = master->next; + ASSERT(master != NULL); + } + /* now duplicate it */ + hw_add_property (me, property, + original->type, + master->init_array, master->sizeof_init_array, + original->array, original->sizeof_array, + original, permenant_object); +} |