/* This file is part of the program psim.
- Copyright (C) 1994-1995, Andrew Cagney <cagney@highland.com.au>
+ Copyright (C) 1994-1997, 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
+ the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
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.
+ along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include "device_table.h"
+#include "cap.h"
+
+#include "events.h"
+#include "psim.h"
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#include <ctype.h>
+STATIC_INLINE_DEVICE (void) clean_device_properties(device *);
+/* property entries */
typedef struct _device_property_entry device_property_entry;
struct _device_property_entry {
- const char *name;
device_property_entry *next;
device_property *value;
+ const void *init_array;
+ unsigned sizeof_init_array;
+};
+
+
+/* Interrupt edges */
+
+typedef struct _device_interrupt_edge device_interrupt_edge;
+struct _device_interrupt_edge {
+ int my_port;
+ device *dest;
+ int dest_port;
+ device_interrupt_edge *next;
+ object_disposition disposition;
};
+STATIC_INLINE_DEVICE\
+(void)
+attach_device_interrupt_edge(device_interrupt_edge **list,
+ int my_port,
+ device *dest,
+ int dest_port,
+ object_disposition disposition)
+{
+ device_interrupt_edge *new_edge = ZALLOC(device_interrupt_edge);
+ new_edge->my_port = my_port;
+ new_edge->dest = dest;
+ new_edge->dest_port = dest_port;
+ new_edge->next = *list;
+ new_edge->disposition = disposition;
+ *list = new_edge;
+}
+
+STATIC_INLINE_DEVICE\
+(void)
+detach_device_interrupt_edge(device *me,
+ device_interrupt_edge **list,
+ int my_port,
+ device *dest,
+ int dest_port)
+{
+ while (*list != NULL) {
+ device_interrupt_edge *old_edge = *list;
+ if (old_edge->dest == dest
+ && old_edge->dest_port == dest_port
+ && old_edge->my_port == my_port) {
+ if (old_edge->disposition == permenant_object)
+ device_error(me, "attempt to delete permenant interrupt");
+ *list = old_edge->next;
+ free(old_edge);
+ return;
+ }
+ }
+ device_error(me, "attempt to delete unattached interrupt");
+}
+
+STATIC_INLINE_DEVICE\
+(void)
+clean_device_interrupt_edges(device_interrupt_edge **list)
+{
+ while (*list != NULL) {
+ device_interrupt_edge *old_edge = *list;
+ switch (old_edge->disposition) {
+ case permenant_object:
+ list = &old_edge->next;
+ break;
+ case tempoary_object:
+ *list = old_edge->next;
+ free(old_edge);
+ break;
+ }
+ }
+}
+
/* A device */
+
struct _device {
+
/* my name is ... */
const char *name;
- const char *full_name;
+ device_unit unit_address;
+ const char *path;
+ int nr_address_cells;
+ int nr_size_cells;
+
/* device tree */
device *parent;
device *children;
device *sibling;
- /* hw/sw callbacks */
+
+ /* its template methods */
void *data; /* device specific data */
const device_callbacks *callback;
+
/* device properties */
device_property_entry *properties;
+
+ /* interrupts */
+ device_interrupt_edge *interrupt_destinations;
+
+ /* any open instances of this device */
+ device_instance *instances;
+
+ /* the internal/external mappings and other global requirements */
+ cap *ihandles;
+ cap *phandles;
+ psim *system;
+
+ /* debugging */
+ int trace;
+};
+
+
+/* an instance of a device */
+struct _device_instance {
+ void *data;
+ char *args;
+ char *path;
+ const device_instance_callbacks *callback;
+ /* the root instance */
+ device *owner;
+ device_instance *next;
+ /* interposed instance */
+ device_instance *parent;
+ device_instance *child;
};
-device INLINE_DEVICE *
-device_create(const char *name,
- device *parent)
+\f
+/* creation */
+
+STATIC_INLINE_DEVICE\
+(const char *)
+device_full_name(device *leaf,
+ char *buf,
+ unsigned sizeof_buf)
{
- device_descriptor *descr;
- int name_len;
- char *chp;
- chp = strchr(name, '@');
- name_len = (chp == NULL ? strlen(name) : chp - name);
- for (descr = device_table; descr->name != NULL; descr++) {
- if (strncmp(name, descr->name, name_len) == 0
- && (descr->name[name_len] == '\0'
- || descr->name[name_len] == '@')) {
- void *data = (descr->creator != NULL
- ? descr->creator(name, parent)
- : NULL);
- return device_create_from(name, data, descr->callbacks, parent);
- }
+ /* get a buffer */
+ char full_name[1024];
+ if (buf == (char*)0) {
+ buf = full_name;
+ sizeof_buf = sizeof(full_name);
}
- error("device_create() unknown device %s\n", name);
- return NULL;
+
+ /* construct a name */
+ if (leaf->parent == NULL) {
+ if (sizeof_buf < 1)
+ error("device_full_name: buffer overflow");
+ *buf = '\0';
+ }
+ else {
+ char unit[1024];
+ device_full_name(leaf->parent, buf, sizeof_buf);
+ if (leaf->parent != NULL
+ && device_encode_unit(leaf->parent,
+ &leaf->unit_address,
+ unit+1,
+ sizeof(unit)-1) > 0)
+ unit[0] = '@';
+ else
+ unit[0] = '\0';
+ if (strlen(buf) + strlen("/") + strlen(leaf->name) + strlen(unit)
+ >= sizeof_buf)
+ error("device_full_name: buffer overflow");
+ strcat(buf, "/");
+ strcat(buf, leaf->name);
+ strcat (buf, unit);
+ }
+
+ /* return it usefully */
+ if (buf == full_name)
+ buf = (char *) strdup(full_name);
+ return buf;
}
-device INLINE_DEVICE *
+STATIC_INLINE_DEVICE\
+(device *)
device_create_from(const char *name,
+ const device_unit *unit_address,
void *data,
const device_callbacks *callbacks,
device *parent)
{
device *new_device = ZALLOC(device);
+
+ /* insert it into the device tree */
+ new_device->parent = parent;
+ new_device->children = NULL;
+ if (parent != NULL) {
+ device **sibling = &parent->children;
+ while ((*sibling) != NULL)
+ sibling = &(*sibling)->sibling;
+ *sibling = new_device;
+ }
+
+ /* give it a name */
+ new_device->name = (char *) strdup(name);
+ new_device->unit_address = *unit_address;
+ new_device->path = device_full_name(new_device, NULL, 0);
+
+ /* its template */
new_device->data = data;
- new_device->name = strdup(name);
new_device->callback = callbacks;
- new_device->parent = parent;
+
+ /* its properties - already null */
+ /* interrupts - already null */
+
+ /* mappings - if needed */
+ if (parent == NULL) {
+ new_device->ihandles = cap_create(name);
+ new_device->phandles = cap_create(name);
+ }
+ else {
+ new_device->ihandles = device_root(parent)->ihandles;
+ new_device->phandles = device_root(parent)->phandles;
+ }
+
+ cap_add(new_device->phandles, new_device);
return new_device;
}
-device INLINE_DEVICE *
-device_parent(device *me)
+
+INLINE_DEVICE\
+(device *)
+device_create(device *parent,
+ const char *base,
+ const char *name,
+ const char *unit_address,
+ const char *args)
{
- return me->parent;
+ const device_descriptor *const *table;
+ for (table = device_table; *table != NULL; table++) {
+ const device_descriptor *descr;
+ for (descr = *table; descr->name != NULL; descr++) {
+ if (strcmp(base, descr->name) == 0) {
+ device_unit address = { 0 };
+ void *data = NULL;
+ if (parent != NULL)
+ if (device_decode_unit(parent, unit_address, &address) < 0)
+ device_error(parent, "invalid address %s for device %s",
+ unit_address, name);
+ if (descr->creator != NULL)
+ data = descr->creator(name, &address, args);
+ return device_create_from(name, &address, data,
+ descr->callbacks, parent);
+ }
+ }
+ }
+ device_error(parent, "attempt to attach unknown device %s", name);
+ return NULL;
}
-const char INLINE_DEVICE *
-device_name(device *me)
+
+
+INLINE_DEVICE\
+(void)
+device_usage(int verbose)
{
- return me->name;
+ const device_descriptor *const *table;
+ if (verbose == 1) {
+ int pos = 0;
+ for (table = device_table; *table != NULL; table++) {
+ const device_descriptor *descr;
+ for (descr = *table; descr->name != NULL; descr++) {
+ pos += strlen(descr->name) + 2;
+ if (pos > 75) {
+ pos = strlen(descr->name) + 2;
+ printf_filtered("\n");
+ }
+ printf_filtered(" %s", descr->name);
+ }
+ printf_filtered("\n");
+ }
+ }
+ if (verbose > 1) {
+ for (table = device_table; *table != NULL; table++) {
+ const device_descriptor *descr;
+ for (descr = *table; descr->name != NULL; descr++) {
+ printf_filtered(" %s:\n", descr->name);
+ /* interrupt ports */
+ if (descr->callbacks->interrupt.ports != NULL) {
+ const device_interrupt_port_descriptor *ports =
+ descr->callbacks->interrupt.ports;
+ printf_filtered(" interrupt ports:");
+ while (ports->name != NULL) {
+ printf_filtered(" %s", ports->name);
+ ports++;
+ }
+ printf_filtered("\n");
+ }
+ /* general info */
+ if (descr->callbacks->usage != NULL)
+ descr->callbacks->usage(verbose);
+ }
+ }
+ }
}
+
-void INLINE_DEVICE *
-device_data(device *me)
+
+
+\f
+/* Device node: */
+
+INLINE_DEVICE\
+(device *)
+device_parent(device *me)
{
- return me->data;
+ return me->parent;
}
-void INLINE_DEVICE
-device_traverse_properties(device *me,
- device_traverse_property_function *traverse,
- void *data)
+INLINE_DEVICE\
+(device *)
+device_root(device *me)
{
- device_property_entry *entry = me->properties;
- while (entry != NULL) {
- traverse(me, entry->name, data);
- entry = entry->next;
- }
+ ASSERT(me != NULL);
+ while (me->parent != NULL)
+ me = me->parent;
+ return me;
}
-void INLINE_DEVICE
-device_init(device *me,
- psim *system)
+INLINE_DEVICE\
+(device *)
+device_sibling(device *me)
{
- me->callback->init(me, system);
+ return me->sibling;
}
-void INLINE_DEVICE
-device_attach_address(device *me,
- const char *name,
- attach_type attach,
- int space,
- unsigned_word addr,
- unsigned nr_bytes,
- access_type access,
- device *who) /*callback/default*/
+INLINE_DEVICE\
+(device *)
+device_child(device *me)
{
- me->callback->attach_address(me, name, attach, space,
- addr, nr_bytes, access, who);
+ return me->children;
}
-void INLINE_DEVICE
-device_detach_address(device *me,
- const char *name,
- attach_type attach,
- int space,
- unsigned_word addr,
- unsigned nr_bytes,
- access_type access,
- device *who) /*callback/default*/
+INLINE_DEVICE\
+(const char *)
+device_name(device *me)
{
- me->callback->detach_address(me, name, attach, space,
- addr, nr_bytes, access, who);
+ return me->name;
}
-unsigned INLINE_DEVICE
-device_io_read_buffer(device *me,
- void *dest,
- int space,
- unsigned_word addr,
- unsigned nr_bytes,
- cpu *processor,
- unsigned_word cia)
+INLINE_DEVICE\
+(const char *)
+device_path(device *me)
{
- return me->callback->io_read_buffer(me, dest, space,
- addr, nr_bytes,
- processor, cia);
+ return me->path;
}
-unsigned INLINE_DEVICE
-device_io_write_buffer(device *me,
- const void *source,
- int space,
- unsigned_word addr,
- unsigned nr_bytes,
- cpu *processor,
- unsigned_word cia)
+INLINE_DEVICE\
+(void *)
+device_data(device *me)
{
- return me->callback->io_write_buffer(me, source, space,
- addr, nr_bytes,
- processor, cia);
+ return me->data;
}
-unsigned INLINE_DEVICE
-device_dma_read_buffer(device *me,
- void *dest,
- int space,
- unsigned_word addr,
- unsigned nr_bytes)
+INLINE_DEVICE\
+(psim *)
+device_system(device *me)
{
- return me->callback->dma_read_buffer(me, dest, space,
- addr, nr_bytes);
+ return me->system;
}
-unsigned INLINE_DEVICE
-device_dma_write_buffer(device *me,
- const void *source,
- int space,
- unsigned_word addr,
- unsigned nr_bytes,
- int violate_read_only_section)
+INLINE_DEVICE\
+(const device_unit *)
+device_unit_address(device *me)
{
- return me->callback->dma_write_buffer(me, source, space,
- addr, nr_bytes,
- violate_read_only_section);
+ return &me->unit_address;
}
-void INLINE_DEVICE
-device_attach_interrupt(device *me,
- device *who,
- int interrupt_line,
- const char *name)
+
+INLINE_DEVICE\
+(int)
+device_address_to_attach_address(device *me,
+ const device_unit *address,
+ int *attach_space,
+ unsigned_word *attach_address,
+ device *client)
{
- me->callback->attach_interrupt(me, who, interrupt_line, name);
+ if (me->callback->convert.address_to_attach_address == NULL)
+ device_error(me, "no convert.address_to_attach_address method");
+ return me->callback->convert.address_to_attach_address(me, address, attach_space, attach_address, client);
}
-void INLINE_DEVICE
-device_detach_interrupt(device *me,
- device *who,
- int interrupt_line,
- const char *name)
+
+INLINE_DEVICE\
+(int)
+device_size_to_attach_size(device *me,
+ const device_unit *size,
+ unsigned *nr_bytes,
+ device *client)
{
- me->callback->detach_interrupt(me, who, interrupt_line, name);
+ if (me->callback->convert.size_to_attach_size == NULL)
+ device_error(me, "no convert.size_to_attach_size method");
+ return me->callback->convert.size_to_attach_size(me, size, nr_bytes, client);
}
-void INLINE_DEVICE
-device_interrupt(device *me,
- device *who,
- int interrupt_line,
- int interrupt_status,
- cpu *processor,
- unsigned_word cia)
+
+INLINE_DEVICE\
+(int)
+device_decode_unit(device *bus,
+ const char *unit,
+ device_unit *address)
{
- me->callback->interrupt(me, who, interrupt_line, interrupt_status,
- processor, cia);
+ if (bus->callback->convert.decode_unit == NULL)
+ device_error(bus, "no convert.decode_unit method");
+ return bus->callback->convert.decode_unit(bus, unit, address);
}
-void INLINE_DEVICE
-device_interrupt_ack(device *me,
- int interrupt_line,
- int interrupt_status)
+
+INLINE_DEVICE\
+(int)
+device_encode_unit(device *bus,
+ const device_unit *unit_address,
+ char *buf,
+ int sizeof_buf)
{
- me->callback->interrupt_ack(me, interrupt_line, interrupt_status);
+ if (bus->callback->convert.encode_unit == NULL)
+ device_error(bus, "no convert.encode_unit method");
+ return bus->callback->convert.encode_unit(bus, unit_address, buf, sizeof_buf);
}
-void EXTERN_DEVICE
-device_ioctl(device *me,
- psim *system,
- cpu *processor,
- unsigned_word cia,
- ...)
+INLINE_DEVICE\
+(unsigned)
+device_nr_address_cells(device *me)
{
- va_list ap;
- va_start(ap, cia);
- me->callback->ioctl(me, system, processor, cia, ap);
- va_end(ap);
+ if (me->nr_address_cells == 0) {
+ if (device_find_property(me, "#address-cells") != NULL)
+ me->nr_address_cells = device_find_integer_property(me, "#address-cells");
+ else
+ me->nr_address_cells = 2;
+ }
+ return me->nr_address_cells;
}
-
-/* Manipulate properties attached to devices */
+INLINE_DEVICE\
+(unsigned)
+device_nr_size_cells(device *me)
+{
+ if (me->nr_size_cells == 0) {
+ if (device_find_property(me, "#size-cells") != NULL)
+ me->nr_size_cells = device_find_integer_property(me, "#size-cells");
+ else
+ me->nr_size_cells = 1;
+ }
+ return me->nr_size_cells;
+}
-device_property STATIC_INLINE_DEVICE *
-device_add_property(device *me,
- const char *property,
- device_property_type type,
- const void *array,
- int sizeof_array)
+
+\f
+/* device-instance: */
+
+INLINE_DEVICE\
+(device_instance *)
+device_create_instance_from(device *me,
+ device_instance *parent,
+ void *data,
+ const char *path,
+ const char *args,
+ const device_instance_callbacks *callbacks)
{
- device_property_entry *new_entry = 0;
- device_property *new_value = 0;
- void *new_array = 0;
- /* find the list end */
- device_property_entry **insertion_point = &me->properties;
- while (*insertion_point != NULL) {
- if (strcmp((**insertion_point).name, property) == 0)
- return (**insertion_point).value;
- insertion_point = &(**insertion_point).next;
+ device_instance *instance = ZALLOC(device_instance);
+ if ((me == NULL) == (parent == NULL))
+ device_error(me, "can't have both parent instance and parent device");
+ /*instance->unit*/
+ /* link this instance into the devices list */
+ if (me != NULL) {
+ ASSERT(parent == NULL);
+ instance->owner = me;
+ instance->parent = NULL;
+ /* link this instance into the front of the devices instance list */
+ instance->next = me->instances;
+ me->instances = instance;
}
- /* alloc data for the new property */
- new_entry = ZALLOC(device_property_entry);
- new_value = ZALLOC(device_property);
- new_array = (sizeof_array > 0
- ? zalloc(sizeof_array)
- : (void*)0);
- /* insert the new property into the list */
- *insertion_point = new_entry;
- new_entry->name = strdup(property);
- new_entry->value = new_value;
- new_value->type = type;
- new_value->sizeof_array = sizeof_array;
- new_value->array = new_array;
- if (sizeof_array > 0)
- memcpy(new_array, array, sizeof_array);
- return new_value;
+ if (parent != NULL) {
+ device_instance **previous;
+ ASSERT(parent->child == NULL);
+ parent->child = instance;
+ ASSERT(me == NULL);
+ instance->owner = parent->owner;
+ instance->parent = parent;
+ /* in the devices instance list replace the parent instance with
+ this one */
+ instance->next = parent->next;
+ /* replace parent with this new node */
+ previous = &instance->owner->instances;
+ while (*previous != parent) {
+ ASSERT(*previous != NULL);
+ previous = &(*previous)->next;
+ }
+ *previous = instance;
+ }
+ instance->data = data;
+ instance->args = (args == NULL ? NULL : (char *) strdup(args));
+ instance->path = (path == NULL ? NULL : (char *) strdup(path));
+ instance->callback = callbacks;
+ cap_add(instance->owner->ihandles, instance);
+ return instance;
}
-void INLINE_DEVICE
-device_add_array_property(device *me,
- const char *property,
- const void *array,
- int sizeof_array)
+
+INLINE_DEVICE\
+(device_instance *)
+device_create_instance(device *me,
+ const char *path,
+ const char *args)
{
- TRACE(trace_devices,
- ("device_add_array_property(me=0x%lx, property=%s, ...)\n",
- (long)me, property));
- device_add_property(me, property,
- array_property, array, sizeof_array);
+ /* create the instance */
+ if (me->callback->instance_create == NULL)
+ device_error(me, "no instance_create method");
+ return me->callback->instance_create(me, path, args);
}
-void INLINE_DEVICE
-device_add_integer_property(device *me,
- const char *property,
- signed32 integer)
+
+STATIC_INLINE_DEVICE\
+(void)
+clean_device_instances(device *me)
{
- TRACE(trace_devices,
- ("device_add_integer_property(me=0x%lx, property=%s, integer=%ld)\n",
- (long)me, property, (long)integer));
- H2BE(integer);
- device_add_property(me, property, integer_property,
- &integer, sizeof(integer));
+ device_instance **instance = &me->instances;
+ while (*instance != NULL) {
+ device_instance *old_instance = *instance;
+ device_instance_delete(old_instance);
+ instance = &me->instances;
+ }
}
-void INLINE_DEVICE
-device_add_boolean_property(device *me,
- const char *property,
- int boolean)
+
+INLINE_DEVICE\
+(void)
+device_instance_delete(device_instance *instance)
{
- signed32 new_boolean = (boolean ? -1 : 0);
- TRACE(trace_devices,
- ("device_add_boolean(me=0x%lx, property=%s, boolean=%d)\n",
- (long)me, property, boolean));
- device_add_property(me, property, boolean_property,
- &new_boolean, sizeof(new_boolean));
+ device *me = instance->owner;
+ if (instance->callback->delete == NULL)
+ device_error(me, "no delete method");
+ instance->callback->delete(instance);
+ if (instance->args != NULL)
+ free(instance->args);
+ if (instance->path != NULL)
+ free(instance->path);
+ if (instance->child == NULL) {
+ /* only remove leaf nodes */
+ device_instance **curr = &me->instances;
+ while (*curr != instance) {
+ ASSERT(*curr != NULL);
+ curr = &(*curr)->next;
+ }
+ *curr = instance->next;
+ }
+ else {
+ /* check it isn't in the instance list */
+ device_instance *curr = me->instances;
+ while (curr != NULL) {
+ ASSERT(curr != instance);
+ curr = curr->next;
+ }
+ /* unlink the child */
+ ASSERT(instance->child->parent == instance);
+ instance->child->parent = NULL;
+ }
+ cap_remove(me->ihandles, instance);
+ free(instance);
}
-void INLINE_DEVICE
-device_add_null_property(device *me,
- const char *property)
+INLINE_DEVICE\
+(int)
+device_instance_read(device_instance *instance,
+ void *addr,
+ unsigned_word len)
{
- TRACE(trace_devices,
- ("device_add_null(me=0x%lx, property=%s)\n",
- (long)me, property));
- device_add_property(me, property, null_property,
- NULL, 0);
+ device *me = instance->owner;
+ if (instance->callback->read == NULL)
+ device_error(me, "no read method");
+ return instance->callback->read(instance, addr, len);
}
-void INLINE_DEVICE
-device_add_string_property(device *me,
- const char *property,
- const char *string)
+INLINE_DEVICE\
+(int)
+device_instance_write(device_instance *instance,
+ const void *addr,
+ unsigned_word len)
{
+ device *me = instance->owner;
+ if (instance->callback->write == NULL)
+ device_error(me, "no write method");
+ return instance->callback->write(instance, addr, len);
+}
- TRACE(trace_devices,
- ("device_add_property(me=0x%lx, property=%s, string=%s)\n",
- (long)me, property, string));
- device_add_property(me, property, string_property,
- string, strlen(string) + 1);
+INLINE_DEVICE\
+(int)
+device_instance_seek(device_instance *instance,
+ unsigned_word pos_hi,
+ unsigned_word pos_lo)
+{
+ device *me = instance->owner;
+ if (instance->callback->seek == NULL)
+ device_error(me, "no seek method");
+ return instance->callback->seek(instance, pos_hi, pos_lo);
}
-const device_property INLINE_DEVICE *
-device_find_property(device *me,
- const char *property)
+INLINE_DEVICE\
+(int)
+device_instance_call_method(device_instance *instance,
+ const char *method_name,
+ int n_stack_args,
+ unsigned_cell stack_args[/*n_stack_args*/],
+ int n_stack_returns,
+ unsigned_cell stack_returns[/*n_stack_args*/])
{
- if (me != (device*)0) {
- device_property_entry *entry = me->properties;
- while (entry != (device_property_entry*)0) {
- if (strcmp(entry->name, property) == 0)
- return entry->value;
- entry = entry->next;
+ device *me = instance->owner;
+ const device_instance_methods *method = instance->callback->methods;
+ if (method == NULL) {
+ device_error(me, "no methods (want %s)", method_name);
+ }
+ while (method->name != NULL) {
+ if (strcmp(method->name, method_name) == 0) {
+ return method->method(instance,
+ n_stack_args, stack_args,
+ n_stack_returns, stack_returns);
}
+ method++;
}
- return (device_property*)0;
+ device_error(me, "no %s method", method_name);
+ return 0;
}
-const char INLINE_DEVICE *
-device_find_next_property(device *me,
- const char *property)
+
+INLINE_DEVICE\
+(device *)
+device_instance_device(device_instance *instance)
{
- if (me != NULL) {
- if (property == NULL || strcmp(property, "") == 0) {
- return (me->properties != NULL
- ? me->properties->name
- : NULL);
- }
- else {
- device_property_entry *entry = me->properties;
- while (entry != NULL) {
- if (strcmp(entry->name, property) == 0)
- return (entry->next != NULL
- ? entry->next->name
- : NULL);
- entry = entry->next;
- }
- }
- }
- return NULL;
+ return instance->owner;
}
-const device_property INLINE_DEVICE *
-device_find_array_property(device *me,
- const char *property)
+INLINE_DEVICE\
+(const char *)
+device_instance_path(device_instance *instance)
{
- const device_property *node;
- TRACE(trace_devices,
- ("device_find_integer(me=0x%lx, property=%s)\n",
- (long)me, property));
- node = device_find_property(me, property);
- if (node == (device_property*)0
- || node->type != array_property)
- error("%s property %s not found or of wrong type\n",
- me->name, property);
- return node;
+ return instance->path;
}
-signed_word INLINE_DEVICE
-device_find_integer_property(device *me,
- const char *property)
+INLINE_DEVICE\
+(void *)
+device_instance_data(device_instance *instance)
{
- const device_property *node;
- signed32 integer;
- TRACE(trace_devices,
- ("device_find_integer(me=0x%lx, property=%s)\n",
- (long)me, property));
- node = device_find_property(me, property);
- if (node == (device_property*)0
- || node->type != integer_property)
- error("%s property %s not found or of wrong type\n",
- me->name, property);
- ASSERT(sizeof(integer) == node->sizeof_array);
- memcpy(&integer, node->array, sizeof(integer));
- BE2H(integer);
- return integer;
+ return instance->data;
}
-int INLINE_DEVICE
-device_find_boolean_property(device *me,
- const char *property)
+
+\f
+/* Device Properties: */
+
+STATIC_INLINE_DEVICE\
+(device_property_entry *)
+find_property_entry(device *me,
+ const char *property)
{
- const device_property *node;
- unsigned32 boolean;
- TRACE(trace_devices,
- ("device_find_boolean(me=0x%lx, property=%s)\n",
- (long)me, property));
+ device_property_entry *entry;
+ ASSERT(property != NULL);
+ entry = me->properties;
+ while (entry != NULL) {
+ if (strcmp(entry->value->name, property) == 0)
+ return entry;
+ entry = entry->next;
+ }
+ return NULL;
+}
+
+STATIC_INLINE_DEVICE\
+(void)
+device_add_property(device *me,
+ const char *property,
+ device_property_type type,
+ const void *init_array,
+ unsigned sizeof_init_array,
+ const void *array,
+ unsigned sizeof_array,
+ const device_property *original,
+ object_disposition disposition)
+{
+ device_property_entry *new_entry = NULL;
+ device_property *new_value = NULL;
+
+ /* find the list end */
+ device_property_entry **insertion_point = &me->properties;
+ while (*insertion_point != NULL) {
+ if (strcmp((*insertion_point)->value->name, property) == 0)
+ return;
+ insertion_point = &(*insertion_point)->next;
+ }
+
+ /* create a new value */
+ new_value = ZALLOC(device_property);
+ new_value->name = (char *) strdup(property);
+ new_value->type = type;
+ if (sizeof_array > 0) {
+ void *new_array = zalloc(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 = ZALLOC(device_property_entry);
+ *insertion_point = new_entry;
+ if (sizeof_init_array > 0) {
+ void *new_init_array = zalloc(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->value = new_value;
+}
+
+
+/* local - not available externally */
+STATIC_INLINE_DEVICE\
+(void)
+device_set_property(device *me,
+ const char *property,
+ device_property_type type,
+ const void *array,
+ int sizeof_array)
+{
+ /* find the property */
+ device_property_entry *entry = find_property_entry(me, property);
+ if (entry != NULL) {
+ /* existing property - update it */
+ void *new_array = 0;
+ device_property *value = entry->value;
+ /* check the type matches */
+ if (value->type != type)
+ device_error(me, "conflict between type of new and old value for property %s", property);
+ /* replace its value */
+ if (value->array != NULL)
+ free((void*)value->array);
+ new_array = (sizeof_array > 0
+ ? zalloc(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 */
+ device_add_property(me, property, type,
+ NULL, 0, array, sizeof_array,
+ NULL, tempoary_object);
+ }
+}
+
+
+STATIC_INLINE_DEVICE\
+(void)
+clean_device_properties(device *me)
+{
+ device_property_entry **delete_point = &me->properties;
+ while (*delete_point != NULL) {
+ device_property_entry *current = *delete_point;
+ switch (current->value->disposition) {
+ case permenant_object:
+ /* zap the current value, will be initialized later */
+ ASSERT(current->init_array != NULL);
+ if (current->value->array != NULL) {
+ free((void*)current->value->array);
+ current->value->array = NULL;
+ }
+ delete_point = &(*delete_point)->next;
+ break;
+ case tempoary_object:
+ /* zap the actual property, was created during simulation run */
+ ASSERT(current->init_array == NULL);
+ *delete_point = current->next;
+ if (current->value->array != NULL)
+ free((void*)current->value->array);
+ free(current->value);
+ free(current);
+ break;
+ }
+ }
+}
+
+
+INLINE_DEVICE\
+(void)
+device_init_static_properties(device *me,
+ void *data)
+{
+ device_property_entry *property;
+ for (property = me->properties;
+ property != NULL;
+ property = property->next) {
+ ASSERT(property->init_array != NULL);
+ ASSERT(property->value->array == NULL);
+ ASSERT(property->value->disposition == permenant_object);
+ switch (property->value->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 */
+ device_set_property(me, property->value->name,
+ property->value->type,
+ property->init_array,
+ property->sizeof_init_array);
+ break;
+ case ihandle_property:
+ break;
+ }
+ }
+}
+
+
+INLINE_DEVICE\
+(void)
+device_init_runtime_properties(device *me,
+ void *data)
+{
+ device_property_entry *property;
+ for (property = me->properties;
+ property != NULL;
+ property = property->next) {
+ switch (property->value->disposition) {
+ case permenant_object:
+ switch (property->value->type) {
+ case ihandle_property:
+ {
+ device_instance *ihandle;
+ ihandle_runtime_property_spec spec;
+ ASSERT(property->init_array != NULL);
+ ASSERT(property->value->array == NULL);
+ device_find_ihandle_runtime_property(me, property->value->name, &spec);
+ ihandle = tree_instance(me, spec.full_path);
+ device_set_ihandle_property(me, property->value->name, ihandle);
+ break;
+ }
+ 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->value->array != NULL);
+ break;
+ }
+ break;
+ case tempoary_object:
+ ASSERT(property->init_array == NULL);
+ ASSERT(property->value->array != NULL);
+ break;
+ }
+ }
+}
+
+
+INLINE_DEVICE\
+(const device_property *)
+device_next_property(const device_property *property)
+{
+ /* find the property in the list */
+ device *owner = property->owner;
+ device_property_entry *entry = owner->properties;
+ while (entry != NULL && entry->value != property)
+ entry = entry->next;
+ /* now return the following property */
+ ASSERT(entry != NULL); /* must be a member! */
+ if (entry->next != NULL)
+ return entry->next->value;
+ else
+ return NULL;
+}
+
+
+INLINE_DEVICE\
+(const device_property *)
+device_find_property(device *me,
+ const char *property)
+{
+ if (me == NULL) {
+ return NULL;
+ }
+ else if (property == NULL || strcmp(property, "") == 0) {
+ if (me->properties == NULL)
+ return NULL;
+ else
+ return me->properties->value;
+ }
+ else {
+ device_property_entry *entry = find_property_entry(me, property);
+ if (entry != NULL)
+ return entry->value;
+ }
+ return NULL;
+}
+
+
+INLINE_DEVICE\
+(void)
+device_add_array_property(device *me,
+ const char *property,
+ const void *array,
+ int sizeof_array)
+{
+ device_add_property(me, property, array_property,
+ array, sizeof_array, array, sizeof_array,
+ NULL, permenant_object);
+}
+
+INLINE_DEVICE\
+(void)
+device_set_array_property(device *me,
+ const char *property,
+ const void *array,
+ int sizeof_array)
+{
+ device_set_property(me, property, array_property, array, sizeof_array);
+}
+
+INLINE_DEVICE\
+(const device_property *)
+device_find_array_property(device *me,
+ const char *property)
+{
+ const device_property *node;
+ node = device_find_property(me, property);
+ if (node == (device_property*)0
+ || node->type != array_property)
+ device_error(me, "property %s not found or of wrong type", property);
+ return node;
+}
+
+
+INLINE_DEVICE\
+(void)
+device_add_boolean_property(device *me,
+ const char *property,
+ int boolean)
+{
+ signed32 new_boolean = (boolean ? -1 : 0);
+ device_add_property(me, property, boolean_property,
+ &new_boolean, sizeof(new_boolean),
+ &new_boolean, sizeof(new_boolean),
+ NULL, permenant_object);
+}
+
+INLINE_DEVICE\
+(int)
+device_find_boolean_property(device *me,
+ const char *property)
+{
+ const device_property *node;
+ unsigned_cell boolean;
node = device_find_property(me, property);
if (node == (device_property*)0
|| node->type != boolean_property)
- error("%s property %s not found or of wrong type\n",
- me->name, property);
+ device_error(me, "property %s not found or of wrong type", property);
ASSERT(sizeof(boolean) == node->sizeof_array);
memcpy(&boolean, node->array, sizeof(boolean));
return boolean;
}
-const char INLINE_DEVICE *
+
+INLINE_DEVICE\
+(void)
+device_add_ihandle_runtime_property(device *me,
+ const char *property,
+ const ihandle_runtime_property_spec *ihandle)
+{
+ /* enter the full path as the init array */
+ device_add_property(me, property, ihandle_property,
+ ihandle->full_path, strlen(ihandle->full_path) + 1,
+ NULL, 0,
+ NULL, permenant_object);
+}
+
+INLINE_DEVICE\
+(void)
+device_find_ihandle_runtime_property(device *me,
+ const char *property,
+ ihandle_runtime_property_spec *ihandle)
+{
+ device_property_entry *entry = find_property_entry(me, property);
+ TRACE(trace_devices,
+ ("device_find_ihandle_runtime_property(me=0x%lx, property=%s)\n",
+ (long)me, property));
+ if (entry == NULL
+ || entry->value->type != ihandle_property
+ || entry->value->disposition != permenant_object)
+ device_error(me, "property %s not found or of wrong type", property);
+ ASSERT(entry->init_array != NULL);
+ /* the full path */
+ ihandle->full_path = entry->init_array;
+}
+
+
+
+INLINE_DEVICE\
+(void)
+device_set_ihandle_property(device *me,
+ const char *property,
+ device_instance *ihandle)
+{
+ unsigned_cell cells;
+ cells = H2BE_cell(device_instance_to_external(ihandle));
+ device_set_property(me, property, ihandle_property,
+ &cells, sizeof(cells));
+
+}
+
+INLINE_DEVICE\
+(device_instance *)
+device_find_ihandle_property(device *me,
+ const char *property)
+{
+ const device_property *node;
+ unsigned_cell ihandle;
+ device_instance *instance;
+
+ node = device_find_property(me, property);
+ if (node == NULL || node->type != ihandle_property)
+ device_error(me, "property %s not found or of wrong type", property);
+ if (node->array == NULL)
+ device_error(me, "runtime property %s not yet initialized", property);
+
+ ASSERT(sizeof(ihandle) == node->sizeof_array);
+ memcpy(&ihandle, node->array, sizeof(ihandle));
+ instance = external_to_device_instance(me, BE2H_cell(ihandle));
+ ASSERT(instance != NULL);
+ return instance;
+}
+
+
+INLINE_DEVICE\
+(void)
+device_add_integer_property(device *me,
+ const char *property,
+ signed_cell integer)
+{
+ H2BE(integer);
+ device_add_property(me, property, integer_property,
+ &integer, sizeof(integer),
+ &integer, sizeof(integer),
+ NULL, permenant_object);
+}
+
+INLINE_DEVICE\
+(signed_cell)
+device_find_integer_property(device *me,
+ const char *property)
+{
+ const device_property *node;
+ signed_cell integer;
+ TRACE(trace_devices,
+ ("device_find_integer(me=0x%lx, property=%s)\n",
+ (long)me, property));
+ node = device_find_property(me, property);
+ if (node == (device_property*)0
+ || node->type != integer_property)
+ device_error(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);
+}
+
+INLINE_DEVICE\
+(int)
+device_find_integer_array_property(device *me,
+ const char *property,
+ unsigned index,
+ signed_cell *integer)
+{
+ const device_property *node;
+ int sizeof_integer = sizeof(*integer);
+ signed_cell *cell;
+ TRACE(trace_devices,
+ ("device_find_integer(me=0x%lx, property=%s)\n",
+ (long)me, property));
+
+ /* check things sane */
+ node = device_find_property(me, property);
+ if (node == (device_property*)0
+ || (node->type != integer_property
+ && node->type != array_property))
+ device_error(me, "property %s not found or of wrong type", property);
+ if ((node->sizeof_array % sizeof_integer) != 0)
+ device_error(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_INLINE_DEVICE\
+(unsigned_cell *)
+unit_address_to_cells(const device_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_INLINE_DEVICE\
+(const unsigned_cell *)
+cells_to_unit_address(const unsigned_cell *cell,
+ device_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_INLINE_DEVICE\
+(unsigned)
+nr_range_property_cells(device *me,
+ int nr_ranges)
+{
+ return ((device_nr_address_cells(me)
+ + device_nr_address_cells(device_parent(me))
+ + device_nr_size_cells(me))
+ ) * nr_ranges;
+}
+
+INLINE_DEVICE\
+(void)
+device_add_range_array_property(device *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 = zalloc(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,
+ device_nr_address_cells(me));
+ /* copy the parent address */
+ cell = unit_address_to_cells(&range->parent_address, cell,
+ device_nr_address_cells(device_parent(me)));
+ /* copy the size */
+ cell = unit_address_to_cells(&range->size, cell,
+ device_nr_size_cells(me));
+ }
+ ASSERT(cell == &cells[nr_range_property_cells(me, nr_ranges)]);
+
+ /* add it */
+ device_add_property(me, property, range_array_property,
+ cells, sizeof_cells,
+ cells, sizeof_cells,
+ NULL, permenant_object);
+
+ free(cells);
+}
+
+INLINE_DEVICE\
+(int)
+device_find_range_array_property(device *me,
+ const char *property,
+ unsigned index,
+ range_property_spec *range)
+{
+ const device_property *node;
+ unsigned sizeof_entry = (nr_range_property_cells(me, 1)
+ * sizeof(unsigned_cell));
+ const unsigned_cell *cells;
+
+ /* locate the property */
+ node = device_find_property(me, property);
+ if (node == (device_property*)0
+ || node->type != range_array_property)
+ device_error(me, "property %s not found or of wrong type", property);
+
+ /* aligned ? */
+ if ((node->sizeof_array % sizeof_entry) != 0)
+ device_error(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,
+ device_nr_address_cells(me));
+
+ /* copy the parent address out - converting as we go */
+ cells = cells_to_unit_address(cells, &range->parent_address,
+ device_nr_address_cells(device_parent(me)));
+
+ /* copy the size - converting as we go */
+ cells = cells_to_unit_address(cells, &range->size,
+ device_nr_size_cells(me));
+
+ return node->sizeof_array / sizeof_entry;
+}
+
+
+STATIC_INLINE_DEVICE\
+(unsigned)
+nr_reg_property_cells(device *me,
+ int nr_regs)
+{
+ return (device_nr_address_cells(device_parent(me))
+ + device_nr_size_cells(device_parent(me))
+ ) * nr_regs;
+}
+
+INLINE_DEVICE\
+(void)
+device_add_reg_array_property(device *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 = zalloc(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,
+ device_nr_address_cells(device_parent(me)));
+ /* copy the size */
+ cell = unit_address_to_cells(®->size, cell,
+ device_nr_size_cells(device_parent(me)));
+ }
+ ASSERT(cell == &cells[nr_reg_property_cells(me, nr_regs)]);
+
+ /* add it */
+ device_add_property(me, property, reg_array_property,
+ cells, sizeof_cells,
+ cells, sizeof_cells,
+ NULL, permenant_object);
+
+ free(cells);
+}
+
+INLINE_DEVICE\
+(int)
+device_find_reg_array_property(device *me,
+ const char *property,
+ unsigned index,
+ reg_property_spec *reg)
+{
+ const device_property *node;
+ unsigned sizeof_entry = (nr_reg_property_cells(me, 1)
+ * sizeof(unsigned_cell));
+ const unsigned_cell *cells;
+
+ /* locate the property */
+ node = device_find_property(me, property);
+ if (node == (device_property*)0
+ || node->type != reg_array_property)
+ device_error(me, "property %s not found or of wrong type", property);
+
+ /* aligned ? */
+ if ((node->sizeof_array % sizeof_entry) != 0)
+ device_error(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,
+ device_nr_address_cells(device_parent(me)));
+
+ /* copy the size out - converting as we go */
+ cells = cells_to_unit_address(cells, ®->size,
+ device_nr_size_cells(device_parent(me)));
+
+ return node->sizeof_array / sizeof_entry;
+}
+
+
+INLINE_DEVICE\
+(void)
+device_add_string_property(device *me,
+ const char *property,
+ const char *string)
+{
+ device_add_property(me, property, string_property,
+ string, strlen(string) + 1,
+ string, strlen(string) + 1,
+ NULL, permenant_object);
+}
+
+INLINE_DEVICE\
+(const char *)
device_find_string_property(device *me,
const char *property)
{
const device_property *node;
const char *string;
- TRACE(trace_devices,
- ("device_find_string(me=0x%lx, property=%s)\n",
- (long)me, property));
node = device_find_property(me, property);
if (node == (device_property*)0
|| node->type != string_property)
- error("%s property %s not found or of wrong type\n",
- me->name, property);
+ device_error(me, "property %s not found or of wrong type", property);
string = node->array;
ASSERT(strlen(string) + 1 == node->sizeof_array);
return string;
}
-
-/* determine the full name of the device. If buf is specified it is
- stored in there. Failing that, a safe area of memory is allocated */
-const char STATIC_INLINE_DEVICE *
-device_tree_full_name(device *leaf,
- char *buf,
- unsigned sizeof_buf)
+INLINE_DEVICE\
+(void)
+device_add_string_array_property(device *me,
+ const char *property,
+ const string_property_spec *strings,
+ unsigned nr_strings)
{
- /* get a buffer */
- char full_name[1024];
- if (buf == (char*)0) {
- buf = full_name;
- sizeof_buf = sizeof(full_name);
+ int sizeof_array;
+ int string_nr;
+ char *array;
+ char *chp;
+ if (nr_strings == 0)
+ device_error(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*)zalloc(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 */
+ device_add_property(me, property, string_array_property,
+ array, sizeof_array,
+ array, sizeof_array,
+ NULL, permenant_object);
+}
- /* construct a name */
- if (leaf->parent == NULL) {
- if (sizeof_buf < 1)
- error("device_full_name() buffer overflow\n");
- *buf = '\0';
+INLINE_DEVICE\
+(int)
+device_find_string_array_property(device *me,
+ const char *property,
+ unsigned index,
+ string_property_spec *string)
+{
+ const device_property *node;
+ node = device_find_property(me, property);
+ if (node == (device_property*)0)
+ device_error(me, "property %s not found", property);
+ switch (node->type) {
+ default:
+ device_error(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')
+ device_error(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;
}
- else {
- device_tree_full_name(leaf->parent, buf, sizeof_buf);
- if (strlen(buf) + strlen("/") + strlen(leaf->name) + 1 > sizeof_buf)
- error("device_full_name() buffer overflow\n");
- strcat(buf, "/");
- strcat(buf, leaf->name);
+ return 0;
+}
+
+INLINE_DEVICE\
+(void)
+device_add_duplicate_property(device *me,
+ const char *property,
+ const device_property *original)
+{
+ device_property_entry *master;
+ TRACE(trace_devices,
+ ("device_add_duplicate_property(me=0x%lx, property=%s, ...)\n",
+ (long)me, property));
+ if (original->disposition != permenant_object)
+ device_error(me, "Can only duplicate permenant objects");
+ /* find the original's master */
+ master = original->owner->properties;
+ while (master->value != original) {
+ master = master->next;
+ ASSERT(master != NULL);
}
-
- /* return it usefully */
- if (buf == full_name)
- buf = strdup(full_name);
- return buf;
+ /* now duplicate it */
+ device_add_property(me, property,
+ original->type,
+ master->init_array, master->sizeof_init_array,
+ original->array, original->sizeof_array,
+ original, permenant_object);
}
-/* find/create a node in the device tree */
+\f
+/* Device Hardware: */
+
+INLINE_DEVICE\
+(unsigned)
+device_io_read_buffer(device *me,
+ void *dest,
+ int space,
+ unsigned_word addr,
+ unsigned nr_bytes,
+ cpu *processor,
+ unsigned_word cia)
+{
+ if (me->callback->io.read_buffer == NULL)
+ device_error(me, "no io.read_buffer method");
+ return me->callback->io.read_buffer(me, dest, space,
+ addr, nr_bytes,
+ processor, cia);
+}
-typedef enum {
- device_tree_return_null = 2,
- device_tree_abort = 3,
-} device_tree_action;
+INLINE_DEVICE\
+(unsigned)
+device_io_write_buffer(device *me,
+ const void *source,
+ int space,
+ unsigned_word addr,
+ unsigned nr_bytes,
+ cpu *processor,
+ unsigned_word cia)
+{
+ if (me->callback->io.write_buffer == NULL)
+ device_error(me, "no io.write_buffer method");
+ return me->callback->io.write_buffer(me, source, space,
+ addr, nr_bytes,
+ processor, cia);
+}
-device STATIC_INLINE_DEVICE *
-device_tree_find_node(device *root,
- const char *path,
- const char *full_path,
- device_tree_action action)
+INLINE_DEVICE\
+(unsigned)
+device_dma_read_buffer(device *me,
+ void *dest,
+ int space,
+ unsigned_word addr,
+ unsigned nr_bytes)
{
- const char *name;
- int strlen_name;
- device *child;
-
- /* strip off any leading `/', `../' or `./' */
- while (1) {
- if (strncmp(path, "/", strlen("/")) == 0) {
- while (root != NULL && root->parent != NULL)
- root = root->parent;
- path += strlen("/");
- }
- else if (strncmp(path, "./", strlen("./")) == 0) {
- root = root;
- path += strlen("./");
- }
- else if (strncmp(path, "../", strlen("../")) == 0) {
- if (root != NULL && root->parent != NULL)
- root = root->parent;
- path += strlen("../");
- }
- else {
- break;
- }
- }
+ if (me->callback->dma.read_buffer == NULL)
+ device_error(me, "no dma.read_buffer method");
+ return me->callback->dma.read_buffer(me, dest, space,
+ addr, nr_bytes);
+}
+
+INLINE_DEVICE\
+(unsigned)
+device_dma_write_buffer(device *me,
+ const void *source,
+ int space,
+ unsigned_word addr,
+ unsigned nr_bytes,
+ int violate_read_only_section)
+{
+ if (me->callback->dma.write_buffer == NULL)
+ device_error(me, "no dma.write_buffer method");
+ return me->callback->dma.write_buffer(me, source, space,
+ addr, nr_bytes,
+ violate_read_only_section);
+}
+
+INLINE_DEVICE\
+(void)
+device_attach_address(device *me,
+ attach_type attach,
+ int space,
+ unsigned_word addr,
+ unsigned nr_bytes,
+ access_type access,
+ device *client) /*callback/default*/
+{
+ if (me->callback->address.attach == NULL)
+ device_error(me, "no address.attach method");
+ me->callback->address.attach(me, attach, space,
+ addr, nr_bytes, access, client);
+}
+
+INLINE_DEVICE\
+(void)
+device_detach_address(device *me,
+ attach_type attach,
+ int space,
+ unsigned_word addr,
+ unsigned nr_bytes,
+ access_type access,
+ device *client) /*callback/default*/
+{
+ if (me->callback->address.detach == NULL)
+ device_error(me, "no address.detach method");
+ me->callback->address.detach(me, attach, space,
+ addr, nr_bytes, access, client);
+}
+
+
+\f
+/* Interrupts: */
- /* parse the driver_name/unit-address */
- ASSERT(*path != '/');
- name = path;
- while (isalnum(*path)
- || *path == ',' || *path == ',' || *path == '_'
- || *path == '+' || *path == '-')
- path++;
- if ((*path != '/' && *path != '@' && *path != ':' && *path != '\0')
- || (name == path && *name != '\0'))
- error("device_tree: path %s invalid at %s\n", full_path, path);
-
- /* parse the unit-address */
- if (*path == '@') {
- path++;
- while ((*path != '\0' && *path != ':' && *path != '/')
- || (*path == ':' && path[-1] == '\\')
- || (*path == '/' && path[-1] == '\\'))
- path++;
+INLINE_DEVICE(void)
+device_interrupt_event(device *me,
+ int my_port,
+ int level,
+ cpu *processor,
+ unsigned_word cia)
+{
+ int found_an_edge = 0;
+ device_interrupt_edge *edge;
+ /* device's interrupt lines directly connected */
+ for (edge = me->interrupt_destinations;
+ edge != NULL;
+ edge = edge->next) {
+ if (edge->my_port == my_port) {
+ if (edge->dest->callback->interrupt.event == NULL)
+ device_error(me, "no interrupt method");
+ edge->dest->callback->interrupt.event(edge->dest,
+ edge->dest_port,
+ me,
+ my_port,
+ level,
+ processor, cia);
+ found_an_edge = 1;
+ }
}
- strlen_name = path - name;
-
- /* skip the device-arguments */
- if (*path == ':') {
- path++;
- while ((*path != '\0' && *path != '/' && *path != ':' && *path != '@')
- || (*path == '/' && path[-1] == '\\')
- || (*path == ':' && path[-1] == '\\')
- || (*path == '@' && path[-1] == '\\'))
- path++;
+ if (!found_an_edge) {
+ device_error(me, "No interrupt edge for port %d", my_port);
}
+}
- /* sanity checks */
- if (*path != '\0' && *path != '/')
- error("device_tree: path %s invalid at %s\n", full_path, path);
+INLINE_DEVICE\
+(void)
+device_interrupt_attach(device *me,
+ int my_port,
+ device *dest,
+ int dest_port,
+ object_disposition disposition)
+{
+ attach_device_interrupt_edge(&me->interrupt_destinations,
+ my_port,
+ dest,
+ dest_port,
+ disposition);
+}
+
+INLINE_DEVICE\
+(void)
+device_interrupt_detach(device *me,
+ int my_port,
+ device *dest,
+ int dest_port)
+{
+ detach_device_interrupt_edge(me,
+ &me->interrupt_destinations,
+ my_port,
+ dest,
+ dest_port);
+}
+
+INLINE_DEVICE\
+(void)
+device_interrupt_traverse(device *me,
+ device_interrupt_traverse_function *handler,
+ void *data)
+{
+ device_interrupt_edge *interrupt_edge;
+ for (interrupt_edge = me->interrupt_destinations;
+ interrupt_edge != NULL;
+ interrupt_edge = interrupt_edge->next) {
+ handler(me, interrupt_edge->my_port,
+ interrupt_edge->dest, interrupt_edge->dest_port,
+ data);
+ }
+}
- /* leaf? and growing? */
- if (name[0] == '\0') {
- return root;
+INLINE_DEVICE\
+(int)
+device_interrupt_decode(device *me,
+ const char *port_name,
+ port_direction direction)
+{
+ if (port_name == NULL || port_name[0] == '\0')
+ return 0;
+ if (isdigit(port_name[0])) {
+ return strtoul(port_name, NULL, 0);
}
- else if (root != NULL) {
- for (child = root->children;
- child != NULL;
- child = child->sibling) {
- if (strncmp(name, child->name, strlen_name) == 0
- && strlen(child->name) == strlen_name) {
- if (*path == '\0')
- return child;
- else
- return device_tree_find_node(child,
- path + 1/* / */,
- full_path,
- action);
+ else {
+ const device_interrupt_port_descriptor *ports =
+ me->callback->interrupt.ports;
+ if (ports != NULL) {
+ while (ports->name != NULL) {
+ if (ports->direction == bidirect_port
+ || ports->direction == direction) {
+ if (ports->nr_ports > 0) {
+ int len = strlen(ports->name);
+ if (strncmp(port_name, ports->name, len) == 0) {
+ if (port_name[len] == '\0')
+ return ports->number;
+ else if(isdigit(port_name[len])) {
+ int port = ports->number + strtoul(&port_name[len], NULL, 0);
+ if (port >= ports->number + ports->nr_ports)
+ device_error(me, "Interrupt port %s out of range",
+ port_name);
+ return port;
+ }
+ }
+ }
+ else if (strcmp(port_name, ports->name) == 0)
+ return ports->number;
+ }
+ ports++;
}
}
}
+ device_error(me, "Unreconized interrupt port %s", port_name);
+ return 0;
+}
- /* search failed, take default action */
- switch (action) {
- case device_tree_return_null:
- return NULL;
- case device_tree_abort:
- error("device_tree_find_node() could not find %s in tree\n",
- full_path);
- return NULL;
- default:
- error("device_tree_find_node() invalid default action %d\n", action);
- return NULL;
+INLINE_DEVICE\
+(int)
+device_interrupt_encode(device *me,
+ int port_number,
+ char *buf,
+ int sizeof_buf,
+ port_direction direction)
+{
+ const device_interrupt_port_descriptor *ports = NULL;
+ ports = me->callback->interrupt.ports;
+ if (ports != NULL) {
+ while (ports->name != NULL) {
+ if (ports->direction == bidirect_port
+ || ports->direction == direction) {
+ if (ports->nr_ports > 0) {
+ if (port_number >= ports->number
+ && port_number < ports->number + ports->nr_ports) {
+ strcpy(buf, ports->name);
+ sprintf(buf + strlen(buf), "%d", port_number - ports->number);
+ if (strlen(buf) >= sizeof_buf)
+ error("device_interrupt_encode: buffer overflow");
+ return strlen(buf);
+ }
+ }
+ else {
+ if (ports->number == port_number) {
+ if (strlen(ports->name) >= sizeof_buf)
+ error("device_interrupt_encode: buffer overflow");
+ strcpy(buf, ports->name);
+ return strlen(buf);
+ }
+ }
+ }
+ ports++;
+ }
}
+ sprintf(buf, "%d", port_number);
+ if (strlen(buf) >= sizeof_buf)
+ error("device_interrupt_encode: buffer overflow");
+ return strlen(buf);
}
-/* grow the device tree */
+\f
+/* IOCTL: */
-device INLINE_DEVICE *
-device_tree_add_device(device *root,
- const char *prefix,
- device *new_sub_tree)
+EXTERN_DEVICE\
+(int)
+device_ioctl(device *me,
+ cpu *processor,
+ unsigned_word cia,
+ device_ioctl_request request,
+ ...)
{
- device *parent;
- TRACE(trace_device_tree,
- ("device_tree_add_device(root=0x%lx, prefix=%s, dev=0x%lx)\n",
- (long)root, prefix, (long)new_sub_tree));
-
- /* find our parent */
- parent = device_tree_find_node(root,
- prefix,
- prefix, /* full-path */
- device_tree_abort);
-
- /* create/insert a new child */
- new_sub_tree->parent = parent;
- if (parent != NULL) {
- device **sibling = &parent->children;
- while ((*sibling) != NULL)
- sibling = &(*sibling)->sibling;
- *sibling = new_sub_tree;
- }
+ int status;
+ va_list ap;
+ va_start(ap, request);
+ if (me->callback->ioctl == NULL)
+ device_error(me, "no ioctl method");
+ status = me->callback->ioctl(me, processor, cia, request, ap);
+ va_end(ap);
+ return status;
+}
+
+
+\f
+/* I/O */
- return new_sub_tree;
+EXTERN_DEVICE\
+(void)
+device_error(device *me,
+ const char *fmt,
+ ...)
+{
+ char message[1024];
+ va_list ap;
+ /* format the message */
+ va_start(ap, fmt);
+ vsprintf(message, fmt, ap);
+ va_end(ap);
+ /* sanity check */
+ if (strlen(message) >= sizeof(message))
+ error("device_error: buffer overflow");
+ if (me == NULL)
+ error("device: %s", message);
+ else if (me->path != NULL && me->path[0] != '\0')
+ error("%s: %s", me->path, message);
+ else if (me->name != NULL && me->name[0] != '\0')
+ error("%s: %s", me->name, message);
+ else
+ error("device: %s", message);
+ while(1);
}
-device INLINE_DEVICE *
-device_tree_find_device(device *root,
- const char *path)
+INLINE_DEVICE\
+(int)
+device_trace(device *me)
{
- device *node;
- TRACE(trace_device_tree,
- ("device_tree_find_device_tree(root=0x%lx, path=%s)\n",
- (long)root, path));
- node = device_tree_find_node(root,
- path,
- path, /* full-name */
- device_tree_return_null);
- return node;
+ return me->trace;
}
+\f
+/* External representation */
-/* init all the devices */
+INLINE_DEVICE\
+(device *)
+external_to_device(device *tree_member,
+ unsigned_cell phandle)
+{
+ device *me = cap_internal(tree_member->phandles, phandle);
+ return me;
+}
-void STATIC_INLINE_DEVICE
-device_tree_init_device(device *root,
- void *data)
+INLINE_DEVICE\
+(unsigned_cell)
+device_to_external(device *me)
{
- psim *system;
- system = (psim*)data;
- TRACE(trace_device_tree,
- ("device_tree_init() initializing device=0x%lx:%s\n",
- (long)root, root->full_name));
- device_init(root, system);
+ unsigned_cell phandle = cap_external(me->phandles, me);
+ return phandle;
}
+INLINE_DEVICE\
+(device_instance *)
+external_to_device_instance(device *tree_member,
+ unsigned_cell ihandle)
+{
+ device_instance *instance = cap_internal(tree_member->ihandles, ihandle);
+ return instance;
+}
-void INLINE_DEVICE
-device_tree_init(device *root,
- psim *system)
+INLINE_DEVICE\
+(unsigned_cell)
+device_instance_to_external(device_instance *instance)
{
- TRACE(trace_device_tree,
- ("device_tree_init(root=0x%lx, system=0x%lx)\n", (long)root, (long)system));
- device_tree_traverse(root, device_tree_init_device, NULL, system);
- TRACE(trace_device_tree,
- ("device_tree_init() = void\n"));
+ unsigned_cell ihandle = cap_external(instance->owner->ihandles, instance);
+ return ihandle;
}
-/* traverse a device tree applying prefix/postfix functions to it */
+/* Map onto the event functions */
-void INLINE_DEVICE
-device_tree_traverse(device *root,
- device_tree_traverse_function *prefix,
- device_tree_traverse_function *postfix,
- void *data)
+INLINE_DEVICE\
+(event_entry_tag)
+device_event_queue_schedule(device *me,
+ signed64 delta_time,
+ device_event_handler *handler,
+ void *data)
{
- device *child;
- if (prefix != NULL)
- prefix(root, data);
- for (child = root->children; child != NULL; child = child->sibling) {
- device_tree_traverse(child, prefix, postfix, data);
- }
- if (postfix != NULL)
- postfix(root, data);
+ return event_queue_schedule(psim_event_queue(me->system),
+ delta_time,
+ handler,
+ data);
}
+INLINE_DEVICE\
+(void)
+device_event_queue_deschedule(device *me,
+ event_entry_tag event_to_remove)
+{
+ event_queue_deschedule(psim_event_queue(me->system),
+ event_to_remove);
+}
-/* dump out a device node and addresses */
-
-void INLINE_DEVICE
-device_tree_dump(device *device,
- void *ignore_data_argument)
+INLINE_DEVICE\
+(signed64)
+device_event_queue_time(device *me)
{
- printf_filtered("(device_tree@0x%lx\n", (long)device);
- printf_filtered(" (parent 0x%lx)\n", (long)device->parent);
- printf_filtered(" (children 0x%lx)\n", (long)device->children);
- printf_filtered(" (sibling 0x%lx)\n", (long)device->sibling);
- printf_filtered(" (name %s)\n", device->name);
- error("FIXME - need to print out properties\n");
- printf_filtered(")\n");
+ return event_queue_time(psim_event_queue(me->system));
}
-/* lookup/create a device various formats */
+/* Initialization: */
+
-void STATIC_INLINE_DEVICE
-u_strcat(char *buf,
- unsigned_word uw)
+INLINE_DEVICE\
+(void)
+device_clean(device *me,
+ void *data)
{
- if (MASKED64(uw, 32, 63) == uw
- || WITH_HOST_WORD_BITSIZE == 64) {
- char *end = strchr(buf, '\0');
- sprintf(end, "0x%x", (unsigned)uw);
- }
- else {
- char *end = strchr(buf, '\0');
- sprintf(end, "0x%x%08x",
- (unsigned)EXTRACTED64(uw, 0, 31),
- (unsigned)EXTRACTED64(uw, 32, 63));
- }
+ psim *system;
+ system = (psim*)data;
+ TRACE(trace_device_init, ("device_clean - initializing %s", me->path));
+ clean_device_interrupt_edges(&me->interrupt_destinations);
+ clean_device_instances(me);
+ clean_device_properties(me);
}
-void STATIC_INLINE_DEVICE
-c_strcat(char *buf,
- const char *c)
+/* Device initialization: */
+
+INLINE_DEVICE\
+(void)
+device_init_address(device *me,
+ void *data)
{
- char *end = strchr(buf, '\0');
- while (*c) {
- if (*c == '/' || *c == ',')
- *end++ = '\\';
- *end++ = *c++;
+ psim *system = (psim*)data;
+ int nr_address_cells;
+ int nr_size_cells;
+ TRACE(trace_device_init, ("device_init_address - initializing %s", me->path));
+
+ /* ensure the cap database is valid */
+ if (me->parent == NULL) {
+ cap_init(me->ihandles);
+ cap_init(me->phandles);
}
- *end = '\0';
-}
-device INLINE_DEVICE *
-device_tree_add_found(device *root,
- const char *prefix,
- const char *name)
-{
- device *parent;
- device *new_device;
- device *new_node;
- TRACE(trace_device_tree,
- ("device_tree_add_found(root=0x%lx, prefix=%s, name=%x)\n",
- (long)root, prefix, name));
- parent = device_tree_find_node(root, prefix, prefix,
- device_tree_abort);
- new_device = device_tree_find_device(parent, name);
- if (new_device != NULL)
- return new_device;
- else {
- new_device = device_create(name, parent);
- new_node = device_tree_add_device(parent, "", new_device);
- ASSERT(new_device == new_node);
- return new_node;
+ /* some basics */
+ me->system = system; /* misc things not known until now */
+ me->trace = (device_find_property(me, "trace")
+ ? device_find_integer_property(me, "trace")
+ : 0);
+
+ /* Ensure that the first address found in the reg property matches
+ anything that was specified as part of the devices name */
+ if (device_find_property(me, "reg") != NULL) {
+ reg_property_spec unit;
+ device_find_reg_array_property(me, "reg", 0, &unit);
+ if (memcmp(device_unit_address(me), &unit.address, sizeof(unit.address))
+ != 0)
+ device_error(me, "Unit address as specified by the reg property in conflict with the value previously specified in the devices path");
}
-}
-device INLINE_DEVICE *
-device_tree_add_found_c(device *root,
- const char *prefix,
- const char *name,
- const char *c1)
-{
- char buf[1024];
- strcpy(buf, name);
- strcat(buf, "@");
- c_strcat(buf, c1);
- if (strlen(buf) + 1 >= sizeof(buf))
- error("device_tree_add_found_c - buffer overflow\n");
- return device_tree_add_found(root, prefix, buf);
-}
-
-device INLINE_DEVICE *
-device_tree_add_found_c_uw(device *root,
- const char *prefix,
- const char *name,
- const char *c1,
- unsigned_word uw2)
-{
- char buf[1024];
- strcpy(buf, name);
- strcat(buf, "@");
- c_strcat(buf, c1);
- strcat(buf, ",");
- u_strcat(buf, uw2);
- if (strlen(buf) + 1 >= sizeof(buf))
- error("device_tree_add_found_* - buffer overflow\n");
- return device_tree_add_found(root, prefix, buf);
-}
-
-device INLINE_DEVICE *
-device_tree_add_found_uw_u(device *root,
- const char *prefix,
- const char *name,
- unsigned_word uw1,
- unsigned u2)
-{
- char buf[1024];
- strcpy(buf, name);
- strcat(buf, "@");
- u_strcat(buf, uw1);
- strcat(buf, ",");
- u_strcat(buf, u2);
- if (strlen(buf) + 1 >= sizeof(buf))
- error("device_tree_add_found_* - buffer overflow\n");
- return device_tree_add_found(root, prefix, buf);
-}
-
-device INLINE_DEVICE *
-device_tree_add_found_uw_u_u(device *root,
- const char *prefix,
- const char *name,
- unsigned_word uw1,
- unsigned u2,
- unsigned u3)
-{
- char buf[1024];
- strcpy(buf, name);
- strcat(buf, "@");
- u_strcat(buf, uw1);
- strcat(buf, ",");
- u_strcat(buf, u2);
- strcat(buf, ",");
- u_strcat(buf, u3);
- if (strlen(buf) + 1 >= sizeof(buf))
- error("device_tree_add_found_* - buffer overflow\n");
- return device_tree_add_found(root, prefix, buf);
-}
-
-device INLINE_DEVICE *
-device_tree_add_found_uw_u_u_c(device *root,
- const char *prefix,
- const char *name,
- unsigned_word uw1,
- unsigned u2,
- unsigned u3,
- const char *c4)
-{
- char buf[1024];
- strcpy(buf, name);
- strcat(buf, "@");
- u_strcat(buf, uw1);
- strcat(buf, ",");
- u_strcat(buf, u2);
- strcat(buf, ",");
- u_strcat(buf, u3);
- strcat(buf, ",");
- c_strcat(buf, c4);
- if (strlen(buf) + 1 >= sizeof(buf))
- error("device_tree_add_found_* - buffer overflow\n");
- return device_tree_add_found(root, prefix, buf);
-}
-
-device INLINE_DEVICE *
-device_tree_add_found_uw_uw_u_u_c(device *root,
- const char *prefix,
- const char *name,
- unsigned_word uw1,
- unsigned_word uw2,
- unsigned u3,
- unsigned u4,
- const char *c5)
-{
- char buf[1024];
- strcpy(buf, name);
- strcat(buf, "@");
- u_strcat(buf, uw1);
- strcat(buf, ",");
- u_strcat(buf, uw2);
- strcat(buf, ",");
- u_strcat(buf, u3);
- strcat(buf, ",");
- u_strcat(buf, u4);
- strcat(buf, ",");
- c_strcat(buf, c5);
- if (strlen(buf) + 1 >= sizeof(buf))
- error("device_tree_add_found_* - buffer overflow\n");
- return device_tree_add_found(root, prefix, buf);
-}
-
-device INLINE_DEVICE *
-device_tree_add_found_uw_uw_u_u_u(device *root,
- const char *prefix,
- const char *name,
- unsigned_word uw1,
- unsigned_word uw2,
- unsigned u3,
- unsigned u4,
- unsigned u5)
-{
- char buf[1024];
- strcpy(buf, name);
- strcat(buf, "@");
- u_strcat(buf, uw1);
- strcat(buf, ",");
- u_strcat(buf, uw2);
- strcat(buf, ",");
- u_strcat(buf, u3);
- strcat(buf, ",");
- u_strcat(buf, u4);
- strcat(buf, ",");
- u_strcat(buf, u5);
- if (strlen(buf) + 1 >= sizeof(buf))
- error("device_tree_add_found_* - buffer overflow\n");
- return device_tree_add_found(root, prefix, buf);
-}
-
-
-/* Parse a device name, various formats */
-
-#define SCAN_INIT(NAME) \
- char *START = (char*)0; \
- char *END = (char*)0; \
- int COUNT = -1; \
- /* find the first element */ \
- END = strchr(NAME, '@'); \
- if (END == (char*)0) \
- return COUNT; \
- COUNT += 1; \
- START = END + 1
-
-#define SCAN_END \
- return COUNT
-
-#define SCAN_U(U) \
-do { \
- *U = strtoul(START, &END, 0); \
- if (START == END) \
- return COUNT; \
- COUNT += 1; \
- if (*END != ',') \
- return COUNT; \
- START = END + 1; \
-} while (0)
-
-#define SCAN_P(P) \
-do { \
- *P = (void*)(unsigned)strtouq(START, END, 0); \
- if (START == END) \
- return COUNT; \
- COUNT += 1; \
- if (*END != ',') \
- return COUNT; \
- START = END + 1; \
-} while (0)
-
-#define SCAN_C(C, SIZE) \
-do { \
- char *chp = C; \
- END = START; \
- while (*END != '\0' && *END != ',') { \
- if (*END == '\\') \
- END += 1; \
- *chp = *END; \
- chp += 1; \
- END += 1; \
- if ((SIZE) <= ((END) - (START))) \
- return COUNT; /* overflow */ \
- } \
- *chp = '\0'; \
- if (START == END) \
- return COUNT; \
- COUNT += 1; \
- if (*END != ',') \
- return COUNT; \
- START = END + 1; \
-} while (0)
-
-int INLINE_DEVICE
-scand_c(const char *name,
- char *c1,
- unsigned c1size)
-{
- SCAN_INIT(name);
- SCAN_C(c1, c1size);
- SCAN_END;
-}
-
-int INLINE_DEVICE
-scand_c_uw_u(const char *name,
- char *c1,
- unsigned c1size,
- unsigned_word *uw2,
- unsigned *u3)
-{
- SCAN_INIT(name);
- SCAN_C(c1, c1size);
- SCAN_U(uw2);
- SCAN_U(u3);
- SCAN_END;
-}
-
-int INLINE_DEVICE
-scand_uw(const char *name,
- unsigned_word *uw1)
-{
- SCAN_INIT(name);
- SCAN_U(uw1);
- SCAN_END;
-}
-
-int INLINE_DEVICE
-scand_uw_c(const char *name,
- unsigned_word *uw1,
- char *c2,
- unsigned c2size)
-{
- SCAN_INIT(name);
- SCAN_U(uw1);
- SCAN_C(c2, c2size);
- SCAN_END;
-}
-
-int INLINE_DEVICE
-scand_uw_u(const char *name,
- unsigned_word *uw1,
- unsigned *u2)
-{
- SCAN_INIT(name);
- SCAN_U(uw1);
- SCAN_U(u2);
- SCAN_END;
-}
-
-int INLINE_DEVICE
-scand_uw_u_u(const char *name,
- unsigned_word *uw1,
- unsigned *u2,
- unsigned *u3)
-{
- SCAN_INIT(name);
- SCAN_U(uw1);
- SCAN_U(u2);
- SCAN_U(u3);
- SCAN_END;
-}
-
-int INLINE_DEVICE
-scand_uw_u_u_c(const char *name,
- unsigned_word *uw1,
- unsigned *u2,
- unsigned *u3,
- char *c4,
- unsigned c4size)
-{
- SCAN_INIT(name);
- SCAN_U(uw1);
- SCAN_U(u2);
- SCAN_U(u3);
- SCAN_C(c4, c4size);
- SCAN_END;
-}
-
-int INLINE_DEVICE
-scand_uw_uw(const char *name,
- unsigned_word *uw1,
- unsigned_word *uw2)
-{
- SCAN_INIT(name);
- SCAN_U(uw1);
- SCAN_U(uw2);
- SCAN_END;
-}
-
-int INLINE_DEVICE
-scand_uw_uw_u(const char *name,
- unsigned_word *uw1,
- unsigned_word *uw2,
- unsigned *u3)
-{
- SCAN_INIT(name);
- SCAN_U(uw1);
- SCAN_U(uw2);
- SCAN_U(u3);
- SCAN_END;
-}
-
-int INLINE_DEVICE
-scand_uw_uw_u_u_c(const char *name,
- unsigned_word *uw1,
- unsigned_word *uw2,
- unsigned *u3,
- unsigned *u4,
- char *c5,
- unsigned c5size)
-{
- SCAN_INIT(name);
- SCAN_U(uw1);
- SCAN_U(uw2);
- SCAN_U(u3);
- SCAN_U(u4);
- SCAN_C(c5, c5size);
- SCAN_END;
-}
-
-int INLINE_DEVICE
-scand_uw_uw_u_u_u(const char *name,
- unsigned_word *uw1,
- unsigned_word *uw2,
- unsigned *u3,
- unsigned *u4,
- unsigned *u5)
-{
- SCAN_INIT(name);
- SCAN_U(uw1);
- SCAN_U(uw2);
- SCAN_U(u3);
- SCAN_U(u4);
- SCAN_U(u5);
- SCAN_END;
+ /* ensure that the devices #address/size-cells is consistent */
+ nr_address_cells = device_nr_address_cells(me);
+ if (device_find_property(me, "#address-cells") != NULL
+ && (nr_address_cells
+ != device_find_integer_property(me, "#address-cells")))
+ device_error(me, "#address-cells property used before defined");
+ nr_size_cells = device_nr_size_cells(me);
+ if (device_find_property(me, "#size-cells") != NULL
+ && (nr_size_cells
+ != device_find_integer_property(me, "#size-cells")))
+ device_error(me, "#size-cells property used before defined");
+
+ /* now init it */
+ if (me->callback->init.address != NULL)
+ me->callback->init.address(me);
}
+INLINE_DEVICE\
+(void)
+device_init_data(device *me,
+ void *data)
+{
+ TRACE(trace_device_init, ("device_init_data - initializing %s", me->path));
+ if (me->callback->init.data != NULL)
+ me->callback->init.data(me);
+}
#endif /* _DEVICE_C_ */