forked from Imagelibrary/binutils-gdb
Add hw_{malloc,zalloc,free} functions to hw_device. Any memory
allocated using these functions is reclaimed when the corresponding device is deleted.
This commit is contained in:
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
128
sim/common/hw-base.h
Normal file
128
sim/common/hw-base.h
Normal file
@@ -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
|
||||
214
sim/common/hw-device.c
Normal file
214
sim/common/hw-device.c
Normal file
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -349,6 +349,25 @@ typedef int (hw_unit_size_to_attach_size_callback)
|
||||
((bus)->to_unit_size_to_attach_size (bus, unit_size, attach_size, client))
|
||||
|
||||
|
||||
|
||||
/* 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;
|
||||
|
||||
};
|
||||
|
||||
|
||||
881
sim/common/hw-properties.c
Normal file
881
sim/common/hw-properties.c
Normal file
@@ -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);
|
||||
}
|
||||
Reference in New Issue
Block a user