diff options
Diffstat (limited to 'sim/ppc/device.c')
-rw-r--r-- | sim/ppc/device.c | 2182 |
1 files changed, 1132 insertions, 1050 deletions
diff --git a/sim/ppc/device.c b/sim/ppc/device.c index 83d9e3f..7d69c3f 100644 --- a/sim/ppc/device.c +++ b/sim/ppc/device.c @@ -27,6 +27,9 @@ #include "device_table.h" #include "cap.h" +#include "events.h" +#include "psim.h" + #ifdef HAVE_STDLIB_H #include <stdlib.h> #endif @@ -42,7 +45,6 @@ #include <ctype.h> STATIC_INLINE_DEVICE (void) clean_device_properties(device *); -STATIC_INLINE_DEVICE (void) init_device_properties(device *, void*); /* property entries */ @@ -97,13 +99,13 @@ detach_device_interrupt_edge(device *me, && 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\n"); + device_error(me, "attempt to delete permenant interrupt"); *list = old_edge->next; zfree(old_edge); return; } } - device_error(me, "attempt to delete unattached interrupt\n"); + device_error(me, "attempt to delete unattached interrupt"); } STATIC_INLINE_DEVICE\ @@ -133,6 +135,8 @@ struct _device { const char *name; device_unit unit_address; const char *path; + int nr_address_cells; + int nr_size_cells; /* device tree */ device *parent; @@ -156,6 +160,9 @@ struct _device { cap *ihandles; cap *phandles; psim *system; + + /* debugging */ + int trace; }; @@ -175,76 +182,13 @@ struct _device_instance { -/* Device node: */ - -INLINE_DEVICE\ -(device *) -device_parent(device *me) -{ - return me->parent; -} - -INLINE_DEVICE\ -(device *) -device_sibling(device *me) -{ - return me->sibling; -} - -INLINE_DEVICE\ -(device *) -device_child(device *me) -{ - return me->children; -} - -INLINE_DEVICE\ -(const char *) -device_name(device *me) -{ - return me->name; -} - -INLINE_DEVICE\ -(const char *) -device_path(device *me) -{ - return me->path; -} - -INLINE_DEVICE\ -(void *) -device_data(device *me) -{ - return me->data; -} - -INLINE_DEVICE\ -(psim *) -device_system(device *me) -{ - return me->system; -} - -INLINE_DEVICE\ -(const device_unit *) -device_unit_address(device *me) -{ - return &me->unit_address; -} - - - -/* device template: */ - -/* 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 */ +/* creation */ STATIC_INLINE_DEVICE\ (const char *) device_full_name(device *leaf, - char *buf, - unsigned sizeof_buf) + char *buf, + unsigned sizeof_buf) { /* get a buffer */ char full_name[1024]; @@ -256,23 +200,23 @@ device_full_name(device *leaf, /* construct a name */ if (leaf->parent == NULL) { if (sizeof_buf < 1) - error("device_full_name: buffer overflow\n"); + error("device_full_name: buffer overflow"); *buf = '\0'; } else { char unit[1024]; device_full_name(leaf->parent, buf, sizeof_buf); if (leaf->parent != NULL - && leaf->parent->callback->convert.encode_unit(leaf->parent, - &leaf->unit_address, - unit+1, - sizeof(unit)-1) > 0) + && 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\n"); + >= sizeof_buf) + error("device_full_name: buffer overflow"); strcat(buf, "/"); strcat(buf, leaf->name); strcat (buf, unit); @@ -280,271 +224,10 @@ device_full_name(device *leaf, /* return it usefully */ if (buf == full_name) - buf = strdup(full_name); + buf = (char *) strdup(full_name); return buf; } -/* manipulate/lookup device names */ - -typedef struct _name_specifier { - /* components in the full length name */ - char *path; - char *property; - char *value; - /* current device */ - char *name; - char *unit; - char *args; - /* previous device */ - char *last_name; - char *last_unit; - char *last_args; - /* work area */ - char buf[1024]; -} name_specifier; - -/* Given a device specifier, break it up into its main components: - path (and if present) property name and property value. */ -STATIC_INLINE_DEVICE\ -(int) -split_device_specifier(const char *device_specifier, - name_specifier *spec) -{ - char *chp; - if (strlen(device_specifier) >= sizeof(spec->buf)) - error("split_device_specifier: buffer overflow\n"); - - /* expand aliases (later) */ - strcpy(spec->buf, device_specifier); - - /* strip the leading spaces and check that remainder isn't a comment */ - chp = spec->buf; - while (*chp != '\0' && isspace(*chp)) - chp++; - if (*chp == '\0' || *chp == '#') - return 0; - - /* find the path and terminate it with null */ - spec->path = chp; - while (*chp != '\0' && !isspace(*chp)) - chp++; - if (*chp != '\0') { - *chp = '\0'; - chp++; - } - - /* and any value */ - while (*chp != '\0' && isspace(*chp)) - chp++; - spec->value = chp; - - /* now go back and chop the property off of the path */ - if (spec->value[0] == '\0') { - spec->property = NULL; /*not a property*/ - spec->value = NULL; - } - else if (spec->value[0] == '>' - || spec->value[0] == '<') { - /* an interrupt spec */ - spec->property = NULL; - } - else { - chp = strrchr(spec->path, '/'); - if (chp == NULL) { - spec->property = spec->path; - spec->path = strchr(spec->property, '\0'); - } - else { - *chp = '\0'; - spec->property = chp+1; - } - } - - /* and mark the rest as invalid */ - spec->name = NULL; - spec->unit = NULL; - spec->args = NULL; - spec->last_name = NULL; - spec->last_unit = NULL; - spec->last_args = NULL; - - return 1; -} - -/* given a device specifier break it up into its main components - - path and property name - assuming that the last `device' is a - property name. */ -STATIC_INLINE_DEVICE\ -(int) -split_property_specifier(const char *property_specifier, - name_specifier *spec) -{ - if (split_device_specifier(property_specifier, spec)) { - if (spec->property == NULL) { - /* force the last name to be a property name */ - char *chp = strrchr(spec->path, '/'); - if (chp == NULL) { - spec->property = spec->path; - spec->path = strrchr(spec->property, '\0');; - } - else { - *chp = '\0'; - spec->property = chp+1; - } - } - return 1; - } - else - return 0; -} - -/* parse the next device name and split it up, return 0 when no more - names to parse */ -STATIC_INLINE_DEVICE\ -(int) -split_device_name(name_specifier *spec) -{ - char *chp; - /* remember what came before */ - spec->last_name = spec->name; - spec->last_unit = spec->unit; - spec->last_args = spec->args; - /* finished? */ - if (spec->path[0] == '\0') { - spec->name = NULL; - spec->unit = NULL; - spec->args = NULL; - return 0; - } - /* break the device name from the path */ - spec->name = spec->path; - chp = strchr(spec->name, '/'); - if (chp == NULL) - spec->path = strchr(spec->name, '\0'); - else { - spec->path = chp+1; - *chp = '\0'; - } - /* now break out the unit */ - chp = strchr(spec->name, '@'); - if (chp == NULL) { - spec->unit = NULL; - chp = spec->name; - } - else { - *chp = '\0'; - chp += 1; - spec->unit = chp; - } - /* finally any args */ - chp = strchr(chp, ':'); - if (chp == NULL) - spec->args = NULL; - else { - *chp = '\0'; - spec->args = chp+1; - } - return 1; -} - -/* parse the value, returning the next non-space token */ - -STATIC_INLINE_DEVICE\ -(char *) -split_value(name_specifier *spec) -{ - char *token; - if (spec->value == NULL) - return NULL; - /* skip leading white space */ - while (isspace(spec->value[0])) - spec->value++; - if (spec->value[0] == '\0') { - spec->value = NULL; - return NULL; - } - token = spec->value; - /* find trailing space */ - while (spec->value[0] != '\0' && !isspace(spec->value[0])) - spec->value++; - /* chop this value out */ - if (spec->value[0] != '\0') { - spec->value[0] = '\0'; - spec->value++; - } - return token; -} - - - -/* traverse the path specified by spec starting at current */ - -STATIC_INLINE_DEVICE\ -(device *) -split_find_device(device *current, - name_specifier *spec) -{ - /* strip off (and process) any leading ., .., ./ and / */ - while (1) { - if (strncmp(spec->path, "/", strlen("/")) == 0) { - /* cd /... */ - while (current != NULL && current->parent != NULL) - current = current->parent; - spec->path += strlen("/"); - } - else if (strncmp(spec->path, "./", strlen("./")) == 0) { - /* cd ./... */ - current = current; - spec->path += strlen("./"); - } - else if (strncmp(spec->path, "../", strlen("../")) == 0) { - /* cd ../... */ - if (current != NULL && current->parent != NULL) - current = current->parent; - spec->path += strlen("../"); - } - else if (strcmp(spec->path, ".") == 0) { - /* cd . */ - current = current; - spec->path += strlen("."); - } - else if (strcmp(spec->path, "..") == 0) { - /* cd . */ - if (current != NULL && current->parent != NULL) - current = current->parent; - spec->path += strlen(".."); - } - else - break; - } - - /* now go through the path proper */ - - if (current == NULL) { - split_device_name(spec); - return current; - } - - while (split_device_name(spec)) { - device_unit phys; - device *child; - current->callback->convert.decode_unit(current, spec->unit, &phys); - for (child = current->children; child != NULL; child = child->sibling) { - if (strcmp(spec->name, child->name) == 0) { - if (phys.nr_cells == 0 - || memcmp(&phys, &child->unit_address, sizeof(device_unit)) == 0) - break; - } - } - if (child == NULL) - return current; /* search failed */ - current = child; - } - - return current; -} - - STATIC_INLINE_DEVICE\ (device *) device_create_from(const char *name, @@ -566,7 +249,7 @@ device_create_from(const char *name, } /* give it a name */ - new_device->name = strdup(name); + new_device->name = (char *) strdup(name); new_device->unit_address = *unit_address; new_device->path = device_full_name(new_device, NULL, 0); @@ -582,35 +265,36 @@ device_create_from(const char *name, 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; } -STATIC_INLINE_DEVICE\ + +INLINE_DEVICE\ (device *) -device_template_create_device(device *parent, - const char *name, - const char *unit_address, - const char *args) +device_create(device *parent, + const char *base, + const char *name, + const char *unit_address, + const char *args) { const device_descriptor *const *table; - int name_len; - char *chp; - chp = strchr(name, '@'); - name_len = (chp == NULL ? strlen(name) : chp - name); for (table = device_table; *table != NULL; table++) { const device_descriptor *descr; for (descr = *table; descr->name != NULL; descr++) { - if (strncmp(name, descr->name, name_len) == 0 - && (descr->name[name_len] == '\0' - || descr->name[name_len] == '@')) { + if (strcmp(base, descr->name) == 0) { device_unit address = { 0 }; void *data = NULL; - if (parent != NULL && parent->callback->convert.decode_unit != NULL) - parent->callback->convert.decode_unit(parent, - unit_address, - &address); + 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, @@ -618,10 +302,207 @@ device_template_create_device(device *parent, } } } - device_error(parent, "attempt to attach unknown device %s\n", name); + device_error(parent, "attempt to attach unknown device %s", name); return NULL; } + + +INLINE_DEVICE\ +(void) +device_usage(int verbose) +{ + 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); + } + } + } +} + + + + + +/* Device node: */ + +INLINE_DEVICE\ +(device *) +device_parent(device *me) +{ + return me->parent; +} + +INLINE_DEVICE\ +(device *) +device_root(device *me) +{ + ASSERT(me != NULL); + while (me->parent != NULL) + me = me->parent; + return me; +} + +INLINE_DEVICE\ +(device *) +device_sibling(device *me) +{ + return me->sibling; +} + +INLINE_DEVICE\ +(device *) +device_child(device *me) +{ + return me->children; +} + +INLINE_DEVICE\ +(const char *) +device_name(device *me) +{ + return me->name; +} + +INLINE_DEVICE\ +(const char *) +device_path(device *me) +{ + return me->path; +} + +INLINE_DEVICE\ +(void *) +device_data(device *me) +{ + return me->data; +} + +INLINE_DEVICE\ +(psim *) +device_system(device *me) +{ + return me->system; +} + +INLINE_DEVICE\ +(const device_unit *) +device_unit_address(device *me) +{ + return &me->unit_address; +} + + +INLINE_DEVICE\ +(int) +device_address_to_attach_address(device *me, + const device_unit *address, + int *attach_space, + unsigned_word *attach_address, + device *client) +{ + 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); +} + + +INLINE_DEVICE\ +(int) +device_size_to_attach_size(device *me, + const device_unit *size, + unsigned *nr_bytes, + device *client) +{ + 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); +} + + +INLINE_DEVICE\ +(int) +device_decode_unit(device *bus, + const char *unit, + device_unit *address) +{ + if (bus->callback->convert.decode_unit == NULL) + device_error(bus, "no convert.decode_unit method"); + return bus->callback->convert.decode_unit(bus, unit, address); +} + + +INLINE_DEVICE\ +(int) +device_encode_unit(device *bus, + const device_unit *unit_address, + char *buf, + int sizeof_buf) +{ + 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); +} + +INLINE_DEVICE\ +(unsigned) +device_nr_address_cells(device *me) +{ + 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; +} + +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-instance: */ @@ -636,29 +517,40 @@ device_create_instance_from(device *me, { device_instance *instance = ZALLOC(device_instance); if ((me == NULL) == (parent == NULL)) - device_error(me, "can't have both parent instance and parent device\n"); - instance->owner = me; - instance->parent = parent; - instance->data = data; - instance->args = (args == NULL ? NULL : strdup(args)); - instance->path = (path == NULL ? NULL : strdup(path)); - instance->callback = callbacks; + 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; } 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) + 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; } @@ -666,22 +558,16 @@ device_create_instance_from(device *me, INLINE_DEVICE\ (device_instance *) device_create_instance(device *me, - const char *device_specifier) + const char *path, + const char *args) { - /* find the device node */ - name_specifier spec; - if (!split_device_specifier(device_specifier, &spec)) - return NULL; - me = split_find_device(me, &spec); - if (spec.name != NULL) - return NULL; /* create the instance */ if (me->callback->instance_create == NULL) - device_error(me, "no instance_create method\n"); - return me->callback->instance_create(me, - device_specifier, spec.last_args); + device_error(me, "no instance_create method"); + return me->callback->instance_create(me, path, args); } + STATIC_INLINE_DEVICE\ (void) clean_device_instances(device *me) @@ -694,24 +580,40 @@ clean_device_instances(device *me) } } + INLINE_DEVICE\ (void) device_instance_delete(device_instance *instance) { device *me = instance->owner; - device_instance **curr; if (instance->callback->delete == NULL) - device_error(me, "no delete method\n"); + device_error(me, "no delete method"); instance->callback->delete(instance); if (instance->args != NULL) zfree(instance->args); if (instance->path != NULL) zfree(instance->path); - curr = &me->instances; - while (*curr != NULL && *curr != instance) - curr = &(*curr)->next; - ASSERT(*curr != NULL); - *curr = instance->next; + 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); zfree(instance); } @@ -723,7 +625,7 @@ device_instance_read(device_instance *instance, { device *me = instance->owner; if (instance->callback->read == NULL) - device_error(me, "no read method\n"); + device_error(me, "no read method"); return instance->callback->read(instance, addr, len); } @@ -735,7 +637,7 @@ device_instance_write(device_instance *instance, { device *me = instance->owner; if (instance->callback->write == NULL) - device_error(me, "no write method\n"); + device_error(me, "no write method"); return instance->callback->write(instance, addr, len); } @@ -747,34 +649,36 @@ device_instance_seek(device_instance *instance, { device *me = instance->owner; if (instance->callback->seek == NULL) - device_error(me, "no seek method\n"); + device_error(me, "no seek method"); return instance->callback->seek(instance, pos_hi, pos_lo); } INLINE_DEVICE\ -(unsigned_word) -device_instance_claim(device_instance *instance, - unsigned_word address, - unsigned_word length, - unsigned_word alignment) +(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*/]) { device *me = instance->owner; - if (instance->callback->claim == NULL) - device_error(me, "no claim method\n"); - return instance->callback->claim(instance, address, length, alignment); + 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++; + } + device_error(me, "no %s method", method_name); + return 0; } -INLINE_DEVICE\ -(void) -device_instance_release(device_instance *instance, - unsigned_word address, - unsigned_word length) -{ - device *me = instance->owner; - if (instance->callback->release == NULL) - device_error(me, "no release method\n"); - instance->callback->release(instance, address, length); -} INLINE_DEVICE\ (device *) @@ -799,64 +703,24 @@ device_instance_data(device_instance *instance) -/* Device initialization: */ - -STATIC_INLINE_DEVICE\ -(void) -clean_device(device *root, - void *data) -{ - psim *system; - system = (psim*)data; - clean_device_interrupt_edges(&root->interrupt_destinations); - clean_device_instances(root); - clean_device_properties(root); -} - -STATIC_INLINE_DEVICE\ -(void) -init_device_address(device *me, - void *data) -{ - psim *system = (psim*)data; - TRACE(trace_device_init, ("init_device_address() initializing %s\n", me->path)); - me->system = system; /* misc things not known until now */ - if (me->callback->init.address != NULL) - me->callback->init.address(me); -} +/* Device Properties: */ STATIC_INLINE_DEVICE\ -(void) -init_device_data(device *me, - void *data) -{ - TRACE(trace_device_init, ("device_init_data() initializing %s\n", me->path)); - if (me->callback->init.data != NULL) - me->callback->init.data(me); -} - -INLINE_DEVICE\ -(void) -device_tree_init(device *root, - psim *system) +(device_property_entry *) +find_property_entry(device *me, + const char *property) { - TRACE(trace_device_tree, ("device_tree_init(root=0x%lx, system=0x%lx)\n", - (long)root, - (long)system)); - /* remove the old, rebuild the new */ - device_tree_traverse(root, clean_device, NULL, system); - TRACE(trace_tbd, ("Need to dump the device tree here\n")); - device_tree_traverse(root, init_device_address, NULL, system); - device_tree_traverse(root, init_device_properties, NULL, system); - device_tree_traverse(root, init_device_data, NULL, system); - TRACE(trace_device_tree, ("device_tree_init() = void\n")); + 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; } - - -/* Device Properties: */ - -/* local - not available externally */ STATIC_INLINE_DEVICE\ (void) device_add_property(device *me, @@ -871,8 +735,6 @@ device_add_property(device *me, { device_property_entry *new_entry = NULL; device_property *new_value = NULL; - void *new_array = NULL; - void *new_init_array = NULL; /* find the list end */ device_property_entry **insertion_point = &me->properties; @@ -884,26 +746,28 @@ device_add_property(device *me, /* create a new value */ new_value = ZALLOC(device_property); - new_value->name = strdup(property); + new_value->name = (char *) strdup(property); new_value->type = type; - new_value->sizeof_array = sizeof_array; - new_array = (sizeof_array > 0 ? zalloc(sizeof_array) : NULL); - new_value->array = new_array; + 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; - if (sizeof_array > 0) - memcpy(new_array, array, sizeof_array); /* insert the value into the list */ new_entry = ZALLOC(device_property_entry); *insertion_point = new_entry; - new_entry->sizeof_init_array = sizeof_init_array; - new_init_array = (sizeof_init_array > 0 ? zalloc(sizeof_init_array) : NULL); - new_entry->init_array = new_init_array; - new_entry->value = new_value; - if (sizeof_init_array > 0) + 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; } @@ -915,35 +779,35 @@ device_set_property(device *me, const char *property, device_property_type type, const void *array, - int sizeof_array, - const device_property *original) + int sizeof_array) { /* find the property */ - device_property_entry *entry = me->properties; - while (entry != NULL) { - if (strcmp(entry->value->name, property) == 0) { - 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\n", property); - /* replace its value */ - if (value->array != NULL) - zfree((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; - } - entry = entry->next; + 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) + zfree((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); } - device_add_property(me, property, type, - NULL, 0, array, sizeof_array, - original, tempoary_object); } @@ -954,70 +818,105 @@ clean_device_properties(device *me) device_property_entry **delete_point = &me->properties; while (*delete_point != NULL) { device_property_entry *current = *delete_point; - device_property *property = current->value; switch (current->value->disposition) { case permenant_object: - { - /* delete the property, and replace it with the original */ - ASSERT(((property->array == NULL) == (current->init_array == NULL)) - || property->type == ihandle_property); - if (current->init_array != NULL) { - zfree((void*)current->value->array); - current->value->array = NULL; - if (property->type != ihandle_property) { - device_set_property(me, property->name, - property->type, - current->init_array, current->sizeof_init_array, - NULL); - } - } - delete_point = &(*delete_point)->next; + /* zap the current value, will be initialized later */ + ASSERT(current->init_array != NULL); + if (current->value->array != NULL) { + zfree((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 */ - *delete_point = current->next; - if (current->value->array != NULL) - zfree((void*)current->value->array); - zfree(current->value); - zfree(current); - } + /* zap the actual property, was created during simulation run */ + ASSERT(current->init_array == NULL); + *delete_point = current->next; + if (current->value->array != NULL) + zfree((void*)current->value->array); + zfree(current->value); + zfree(current); break; } } } -STATIC_INLINE_DEVICE\ +INLINE_DEVICE\ (void) -init_device_properties(device *me, - void *data) -{ - device_property_entry *property = me->properties; - while (property != NULL) { - /* now do the phandles */ - if (property->value->type == ihandle_property) { - if (property->value->original != NULL) { - const device_property *original = property->value->original; - if (original->array == NULL) { - init_device_properties(original->owner, data); +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 = device_create_instance(spec.phandle, + spec.full_path, + spec.args); + device_set_ihandle_property(me, property->value->name, ihandle); + break; } - ASSERT(original->array != NULL); - device_set_property(me, property->value->name, - ihandle_property, - original->array, original->sizeof_array, NULL); - } - else { - device_instance *instance = - device_create_instance(me, (char*)property->init_array); - unsigned32 ihandle = H2BE_4(device_instance_to_external(instance)); - device_set_property(me, property->value->name, - ihandle_property, - &ihandle, sizeof(ihandle), NULL); + 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; } - property = property->next; } } @@ -1039,12 +938,12 @@ device_next_property(const device_property *property) return NULL; } + INLINE_DEVICE\ (const device_property *) device_find_property(device *me, const char *property) { - name_specifier spec; if (me == NULL) { return NULL; } @@ -1054,33 +953,25 @@ device_find_property(device *me, else return me->properties->value; } - else if (split_property_specifier(property, &spec)) { - me = split_find_device(me, &spec); - if (spec.name == NULL) { /*got to root*/ - device_property_entry *entry = me->properties; - while (entry != NULL) { - if (strcmp(entry->value->name, spec.property) == 0) - return entry->value; - entry = entry->next; - } - } + else { + device_property_entry *entry = find_property_entry(me, property); + if (entry != NULL) + return entry->value; } return NULL; } -STATIC_INLINE_DEVICE\ + +INLINE_DEVICE\ (void) device_add_array_property(device *me, - const char *property, - const void *array, - int sizeof_array) + const char *property, + const void *array, + int sizeof_array) { - 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, array, sizeof_array, - NULL, permenant_object); + array, sizeof_array, array, sizeof_array, + NULL, permenant_object); } INLINE_DEVICE\ @@ -1090,10 +981,7 @@ device_set_array_property(device *me, const void *array, int sizeof_array) { - TRACE(trace_devices, - ("device_set_array_property(me=0x%lx, property=%s, ...)\n", - (long)me, property)); - device_set_property(me, property, array_property, array, sizeof_array, NULL); + device_set_property(me, property, array_property, array, sizeof_array); } INLINE_DEVICE\ @@ -1102,31 +990,25 @@ device_find_array_property(device *me, const char *property) { 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) - device_error(me, "property %s not found or of wrong type\n", property); + device_error(me, "property %s not found or of wrong type", property); return node; } -STATIC_INLINE_DEVICE\ +INLINE_DEVICE\ (void) device_add_boolean_property(device *me, - const char *property, - int boolean) + const char *property, + int boolean) { 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), - &new_boolean, sizeof(new_boolean), - NULL, permenant_object); + &new_boolean, sizeof(new_boolean), + &new_boolean, sizeof(new_boolean), + NULL, permenant_object); } INLINE_DEVICE\ @@ -1135,108 +1017,427 @@ device_find_boolean_property(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)); + unsigned_cell boolean; node = device_find_property(me, property); if (node == (device_property*)0 || node->type != boolean_property) - device_error(me, "property %s not found or of wrong type\n", 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; } -STATIC_INLINE_DEVICE\ + +INLINE_DEVICE\ (void) -device_add_ihandle_property(device *me, - const char *property, - const char *path) +device_add_ihandle_runtime_property(device *me, + const char *property, + const ihandle_runtime_property_spec *ihandle) { - TRACE(trace_devices, - ("device_add_ihandle_property(me=0x%lx, property=%s, path=%s)\n", - (long)me, property, path)); + unsigned_cell *cells; + char *chp; + unsigned sizeof_cells = (sizeof(unsigned_cell) * 3 + + (strlen(ihandle->full_path) + 1) + + (ihandle->args != NULL + ? (strlen(ihandle->args) + 1) + : 0)); + + /* the basics */ + cells = zalloc(sizeof_cells); + cells[0] = H2BE_cell(device_to_external(ihandle->phandle)); + cells[1] = (ihandle->full_path == NULL ? 0 : -1); + cells[2] = (ihandle->args == NULL ? 0 : -1); + chp = (char*)&cells[3]; + + /* the full path (if present) */ + if (ihandle->full_path != NULL) { + strcpy(chp, ihandle->full_path); + chp += strlen(ihandle->full_path) + 1; + } + + /* the args (if present) */ + if (ihandle->args != NULL) { + strcpy(chp, ihandle->args); + chp += strlen(ihandle->args) + 1; + } + + /* add it */ + ASSERT(sizeof_cells == (chp - (char*)cells)); device_add_property(me, property, ihandle_property, - path, strlen(path) + 1, + cells, sizeof_cells, NULL, 0, NULL, permenant_object); } INLINE_DEVICE\ +(void) +device_find_ihandle_runtime_property(device *me, + const char *property, + ihandle_runtime_property_spec *ihandle) +{ + const unsigned_cell *cells; + const char *chp; + 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); + cells = entry->init_array; + chp = (char*)&cells[3]; + ASSERT(entry->init_array != NULL); + /* the device to be opened */ + ihandle->phandle = external_to_device(me, BE2H_cell(cells[0])); + /* the full path */ + if (cells[1] != 0) { + ihandle->full_path = chp; + chp += strlen(ihandle->full_path) + 1; + } + else + ihandle->full_path = NULL; + /* the args */ + if (cells[2] != 0) { + ihandle->args = chp; + chp += strlen(ihandle->args) + 1; + } + else + ihandle->args = NULL; + /* reached the end? */ + ASSERT(entry->sizeof_init_array + == (chp - (char*)cells)); + return; +} + + + +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; - unsigned32 ihandle; + unsigned_cell ihandle; device_instance *instance; - TRACE(trace_devices, - ("device_find_ihandle_property(me=0x%lx, property=%s)\n", - (long)me, property)); + node = device_find_property(me, property); if (node == NULL || node->type != ihandle_property) - device_error(me, "property %s not found or of wrong type\n", property); + device_error(me, "property %s not found or of wrong type", property); if (node->array == NULL) - device_error(me, "property %s not yet initialized\n", property); + device_error(me, "runtime property %s not yet initialized", property); + ASSERT(sizeof(ihandle) == node->sizeof_array); memcpy(&ihandle, node->array, sizeof(ihandle)); - BE2H(ihandle); - instance = external_to_device_instance(me, ihandle); + instance = external_to_device_instance(me, BE2H_cell(ihandle)); ASSERT(instance != NULL); return instance; } -STATIC_INLINE_DEVICE\ + +INLINE_DEVICE\ (void) device_add_integer_property(device *me, const char *property, - signed32 integer) + signed_cell integer) { - 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), - &integer, sizeof(integer), - NULL, permenant_object); + &integer, sizeof(integer), + &integer, sizeof(integer), + NULL, permenant_object); } INLINE_DEVICE\ -(signed_word) +(signed_cell) device_find_integer_property(device *me, const char *property) { const device_property *node; - signed32 integer; + 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\n", 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)); - BE2H(integer); - return 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_string_property(device *me, - const char *property, - const char *string) +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); + + zfree(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; - 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, - string, strlen(string) + 1, + /* 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); + + zfree(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\ @@ -1246,32 +1447,133 @@ device_find_string_property(device *me, { 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) - device_error(me, "property %s not found or of wrong type\n", 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; } -STATIC_INLINE_DEVICE\ +INLINE_DEVICE\ +(void) +device_add_string_array_property(device *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) + 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); +} + +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; + } + 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\n"); + 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); + } + /* now duplicate it */ device_add_property(me, property, original->type, - original->array, original->sizeof_array, + master->init_array, master->sizeof_init_array, original->array, original->sizeof_array, original, permenant_object); } @@ -1291,7 +1593,7 @@ device_io_read_buffer(device *me, unsigned_word cia) { if (me->callback->io.read_buffer == NULL) - device_error(me, "no io_read_buffer method\n"); + device_error(me, "no io.read_buffer method"); return me->callback->io.read_buffer(me, dest, space, addr, nr_bytes, processor, cia); @@ -1308,7 +1610,7 @@ device_io_write_buffer(device *me, unsigned_word cia) { if (me->callback->io.write_buffer == NULL) - device_error(me, "no io_write_buffer method\n"); + device_error(me, "no io.write_buffer method"); return me->callback->io.write_buffer(me, source, space, addr, nr_bytes, processor, cia); @@ -1323,7 +1625,7 @@ device_dma_read_buffer(device *me, unsigned nr_bytes) { if (me->callback->dma.read_buffer == NULL) - device_error(me, "no dma_read_buffer method\n"); + device_error(me, "no dma.read_buffer method"); return me->callback->dma.read_buffer(me, dest, space, addr, nr_bytes); } @@ -1338,7 +1640,7 @@ device_dma_write_buffer(device *me, int violate_read_only_section) { if (me->callback->dma.write_buffer == NULL) - device_error(me, "no dma_write_buffer method\n"); + device_error(me, "no dma.write_buffer method"); return me->callback->dma.write_buffer(me, source, space, addr, nr_bytes, violate_read_only_section); @@ -1347,35 +1649,33 @@ device_dma_write_buffer(device *me, INLINE_DEVICE\ (void) 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*/ + device *client) /*callback/default*/ { if (me->callback->address.attach == NULL) - device_error(me, "no address_attach method\n"); - me->callback->address.attach(me, name, attach, space, - addr, nr_bytes, access, who); + 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, - const char *name, attach_type attach, int space, unsigned_word addr, unsigned nr_bytes, access_type access, - device *who) /*callback/default*/ + device *client) /*callback/default*/ { if (me->callback->address.detach == NULL) - device_error(me, "no address_detach method\n"); - me->callback->address.detach(me, name, attach, space, - addr, nr_bytes, access, who); + device_error(me, "no address.detach method"); + me->callback->address.detach(me, attach, space, + addr, nr_bytes, access, client); } @@ -1397,7 +1697,7 @@ device_interrupt_event(device *me, edge = edge->next) { if (edge->my_port == my_port) { if (edge->dest->callback->interrupt.event == NULL) - device_error(me, "no interrupt method\n"); + device_error(me, "no interrupt method"); edge->dest->callback->interrupt.event(edge->dest, edge->dest_port, me, @@ -1408,7 +1708,7 @@ device_interrupt_event(device *me, } } if (!found_an_edge) { - device_error(me, "No interrupt edge for port %d\n", my_port); + device_error(me, "No interrupt edge for port %d", my_port); } } @@ -1442,9 +1742,26 @@ device_interrupt_detach(device *me, } 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); + } +} + +INLINE_DEVICE\ (int) device_interrupt_decode(device *me, - const char *port_name) + const char *port_name, + port_direction direction) { if (port_name == NULL || port_name[0] == '\0') return 0; @@ -1456,27 +1773,30 @@ device_interrupt_decode(device *me, me->callback->interrupt.ports; if (ports != NULL) { while (ports->name != NULL) { - if (ports->bound > ports->number) { - 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->bound) - device_error(me, "Interrupt port %s out of range\n", - port_name); - return port; + 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; } - else if (strcmp(port_name, ports->name) == 0) - return ports->number; ports++; } } } - device_error(me, "Unreconized interrupt port %s\n", port_name); + device_error(me, "Unreconized interrupt port %s", port_name); return 0; } @@ -1485,28 +1805,32 @@ INLINE_DEVICE\ device_interrupt_encode(device *me, int port_number, char *buf, - int sizeof_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->bound > ports->number) { - if (port_number >= ports->number - && port_number < ports->bound) { - strcpy(buf, ports->name); - sprintf(buf + strlen(buf), "%d", port_number - ports->number); - if (strlen(buf) >= sizeof_buf) - error("device_interrupt_encode:buffer overflow\n"); - return strlen(buf); + 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\n"); - strcpy(buf, ports->name); - 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++; @@ -1514,7 +1838,7 @@ device_interrupt_encode(device *me, } sprintf(buf, "%d", port_number); if (strlen(buf) >= sizeof_buf) - error("device_interrupt_encode: buffer overflow\n"); + error("device_interrupt_encode: buffer overflow"); return strlen(buf); } @@ -1527,14 +1851,15 @@ EXTERN_DEVICE\ device_ioctl(device *me, cpu *processor, unsigned_word cia, + device_ioctl_request request, ...) { int status; va_list ap; - va_start(ap, cia); + va_start(ap, request); if (me->callback->ioctl == NULL) - device_error(me, "no ioctl method\n"); - status = me->callback->ioctl(me, processor, cia, ap); + device_error(me, "no ioctl method"); + status = me->callback->ioctl(me, processor, cia, request, ap); va_end(ap); return status; } @@ -1557,413 +1882,170 @@ device_error(device *me, va_end(ap); /* sanity check */ if (strlen(message) >= sizeof(message)) - error("device_error: buffer overflow\n"); + error("device_error: buffer overflow"); if (me == NULL) - error("device: %s\n", message); + 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("%s: %s\n", me->path, message); + error("device: %s", message); while(1); } +INLINE_DEVICE\ +(int) +device_trace(device *me) +{ + return me->trace; +} + -/* Tree utilities: */ +/* External representation */ -EXTERN_DEVICE\ +INLINE_DEVICE\ (device *) -device_tree_add_parsed(device *current, - const char *fmt, - ...) -{ - char device_specifier[1024]; - name_specifier spec; - - /* format the path */ - { - va_list ap; - va_start(ap, fmt); - vsprintf(device_specifier, fmt, ap); - va_end(ap); - if (strlen(device_specifier) >= sizeof(device_specifier)) - error("device_tree_add_parsed: buffer overflow\n"); - } - - /* break it up */ - if (!split_device_specifier(device_specifier, &spec)) - device_error(current, "error parsing %s\n", device_specifier); - - /* fill our tree with its contents */ - current = split_find_device(current, &spec); - - /* add any additional devices as needed */ - if (spec.name != NULL) { - do { - current = - device_template_create_device(current, spec.name, spec.unit, spec.args); - } while (split_device_name(&spec)); - } - - /* is there an interrupt spec */ - if (spec.property == NULL - && spec.value != NULL) { - char *op = split_value(&spec); - switch (op[0]) { - case '>': - { - char *my_port_name = split_value(&spec); - char *dest_port_name = split_value(&spec); - device *dest = device_tree_find_device(current, split_value(&spec)); - int my_port = device_interrupt_decode(current, my_port_name); - int dest_port = device_interrupt_decode(dest, dest_port_name); - device_interrupt_attach(current, - my_port, - dest, - dest_port, - permenant_object); - } - break; - default: - device_error(current, "unreconised interrupt spec %s\n", spec.value); - break; - } - } - - /* is there a property */ - if (spec.property != NULL) { - if (strcmp(spec.value, "true") == 0) - device_add_boolean_property(current, spec.property, 1); - else if (strcmp(spec.value, "false") == 0) - device_add_boolean_property(current, spec.property, 0); - else { - const device_property *property; - switch (spec.value[0]) { - case '*': - { - spec.value++; - device_add_ihandle_property(current, spec.property, spec.value); - } - break; - case '-': case '+': - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - { - unsigned long ul = strtoul(spec.value, &spec.value, 0); - device_add_integer_property(current, spec.property, ul); - } - break; - case '[': - { - unsigned8 words[1024]; - char *curr = spec.value + 1; - int nr_words = 0; - while (1) { - char *next; - words[nr_words] = H2BE_1(strtoul(curr, &next, 0)); - if (curr == next) - break; - curr = next; - nr_words += 1; - } - device_add_array_property(current, spec.property, - words, sizeof(words[0]) * nr_words); - } - break; - case '{': - { - unsigned32 words[1024]; - char *curr = spec.value + 1; - int nr_words = 0; - while (1) { - char *next; - words[nr_words] = H2BE_4(strtoul(curr, &next, 0)); - if (curr == next) - break; - curr = next; - nr_words += 1; - } - device_add_array_property(current, spec.property, - words, sizeof(words[0]) * nr_words); - } - break; - case '"': - spec.value++; - default: - device_add_string_property(current, spec.property, spec.value); - break; - case '!': - spec.value++; - property = device_find_property(current, spec.value); - if (property == NULL) - device_error(current, "property %s not found\n", spec.value); - device_add_duplicate_property(current, - spec.property, - property); - break; - } - } - } - return current; +external_to_device(device *tree_member, + unsigned_cell phandle) +{ + device *me = cap_internal(tree_member->phandles, phandle); + return me; } INLINE_DEVICE\ -(void) -device_tree_traverse(device *root, - device_tree_traverse_function *prefix, - device_tree_traverse_function *postfix, - 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); +(unsigned_cell) +device_to_external(device *me) +{ + unsigned_cell phandle = cap_external(me->phandles, me); + return phandle; } INLINE_DEVICE\ -(void) -device_tree_print_device(device *me, - void *ignore_or_null) +(device_instance *) +external_to_device_instance(device *tree_member, + unsigned_cell ihandle) { - const device_property *property; - device_interrupt_edge *interrupt_edge; - /* output my name */ - printf_filtered("%s\n", me->path); - /* properties */ - for (property = device_find_property(me, NULL); - property != NULL; - property = device_next_property(property)) { - printf_filtered("%s/%s", me->path, property->name); - if (property->original != NULL) { - printf_filtered(" !"); - printf_filtered("%s/%s\n", property->original->owner->path, - property->original->name); - } - else { - switch (property->type) { - case array_property: - { - if ((property->sizeof_array % sizeof(unsigned32)) == 0) { - unsigned32 *w = (unsigned32*)property->array; - printf_filtered(" {"); - while ((char*)w - (char*)property->array < property->sizeof_array) { - printf_filtered(" 0x%lx", BE2H_4(*w)); - w++; - } - } - else { - unsigned8 *w = (unsigned8*)property->array; - printf_filtered(" ["); - while ((char*)w - (char*)property->array < property->sizeof_array) { - printf_filtered(" 0x%2x", BE2H_1(*w)); - w++; - } - } - printf_filtered("\n"); - } - break; - case boolean_property: - { - int b = device_find_boolean_property(me, property->name); - printf_filtered(" %s\n", b ? "true" : "false"); - } - break; - case ihandle_property: - { - if (property->array != NULL) { - device_instance *i = device_find_ihandle_property(me, property->name); - printf_filtered(" *%s\n", i->path); - } - else { - /* drats, the instance hasn't yet been created. Grub - around and find the path that will be used to create - the ihandle */ - device_property_entry *entry = me->properties; - while (entry->value != property) { - entry = entry->next; - ASSERT(entry != NULL); - } - ASSERT(entry->init_array != NULL); - printf_filtered(" *%s\n", (char*)entry->init_array); - } - } - break; - case integer_property: - { - unsigned_word w = device_find_integer_property(me, property->name); - printf_filtered(" 0x%lx\n", (unsigned long)w); - } - break; - case string_property: - { - const char *s = device_find_string_property(me, property->name); - printf_filtered(" \"%s\n", s); - } - break; - } - } - } - /* interrupts */ - for (interrupt_edge = me->interrupt_destinations; - interrupt_edge != NULL; - interrupt_edge = interrupt_edge->next) { - char src[32]; - char dst[32]; - device_interrupt_encode(me, interrupt_edge->my_port, src, sizeof(src)); - device_interrupt_encode(interrupt_edge->dest, - interrupt_edge->dest_port, dst, sizeof(dst)); - printf_filtered("%s > %s %s %s\n", - me->path, - src, dst, - interrupt_edge->dest->path); - } + device_instance *instance = cap_internal(tree_member->ihandles, ihandle); + return instance; } INLINE_DEVICE\ -(device *) -device_tree_find_device(device *root, - const char *path) -{ - device *node; - name_specifier spec; - TRACE(trace_device_tree, - ("device_tree_find_device_tree(root=0x%lx, path=%s)\n", - (long)root, path)); - /* parse the path */ - split_device_specifier(path, &spec); - if (spec.value != NULL) - return NULL; /* something wierd */ - - /* now find it */ - node = split_find_device(root, &spec); - if (spec.name != NULL) - return NULL; /* not a leaf */ +(unsigned_cell) +device_instance_to_external(device_instance *instance) +{ + unsigned_cell ihandle = cap_external(instance->owner->ihandles, instance); + return ihandle; +} - return node; + +/* Map onto the event functions */ + +INLINE_DEVICE\ +(event_entry_tag) +device_event_queue_schedule(device *me, + signed64 delta_time, + device_event_handler *handler, + void *data) +{ + return event_queue_schedule(psim_event_queue(me->system), + delta_time, + handler, + data); } INLINE_DEVICE\ (void) -device_usage(int verbose) +device_event_queue_deschedule(device *me, + event_entry_tag event_to_remove) { - if (verbose == 1) { - const device_descriptor *const *table; - int pos; - printf_filtered("\n"); - printf_filtered("A device/property specifier has the form:\n"); - printf_filtered("\n"); - printf_filtered(" /path/to/a/device [ property-value ]\n"); - printf_filtered("\n"); - printf_filtered("and a possible device is\n"); - printf_filtered("\n"); - 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) { - const device_descriptor *const *table; - printf_filtered("\n"); - printf_filtered("A device/property specifier (<spec>) has the format:\n"); - printf_filtered("\n"); - printf_filtered(" <spec> ::= <path> [ <value> ] ;\n"); - printf_filtered(" <path> ::= { <prefix> } { <node> \"/\" } <node> ;\n"); - printf_filtered(" <prefix> ::= ( | \"/\" | \"../\" | \"./\" ) ;\n"); - printf_filtered(" <node> ::= <name> [ \"@\" <unit> ] [ \":\" <args> ] ;\n"); - printf_filtered(" <unit> ::= <number> { \",\" <number> } ;\n"); - printf_filtered("\n"); - printf_filtered("Where:\n"); - printf_filtered("\n"); - printf_filtered(" <name> is the name of a device (list below)\n"); - printf_filtered(" <unit> is the unit-address relative to the parent bus\n"); - printf_filtered(" <args> additional arguments used when creating the device\n"); - printf_filtered(" <value> ::= ( <number> # integer property\n"); - printf_filtered(" | \"[\" { <number> } # array property (byte)\n"); - printf_filtered(" | \"{\" { <number> } # array property (cell)\n"); - printf_filtered(" | [ \"true\" | \"false\" ] # boolean property\n"); - printf_filtered(" | \"*\" <path> # ihandle property\n"); - printf_filtered(" | \"!\" <path> # copy property\n"); - printf_filtered(" | \">\" [ <number> ] <path> # attach interrupt\n"); - printf_filtered(" | \"<\" <path> # attach child interrupt\n"); - printf_filtered(" | \"\\\"\" <text> # string property\n"); - printf_filtered(" | <text> # string property\n"); - printf_filtered(" ) ;\n"); - printf_filtered("\n"); - printf_filtered("And the following are valid device names:\n"); - printf_filtered("\n"); - 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); - } - } - } + event_queue_deschedule(psim_event_queue(me->system), + event_to_remove); } - - -/* External representation */ - INLINE_DEVICE\ -(device *) -external_to_device(device *tree_member, - unsigned32 phandle) +(signed64) +device_event_queue_time(device *me) { - device *root = device_tree_find_device(tree_member, "/"); - device *me = cap_internal(root->phandles, phandle); - return me; + return event_queue_time(psim_event_queue(me->system)); } + +/* Initialization: */ + + INLINE_DEVICE\ -(unsigned32) -device_to_external(device *me) +(void) +device_clean(device *me, + void *data) { - device *root = device_tree_find_device(me, "/"); - unsigned32 phandle = cap_external(root->phandles, me); - return phandle; + 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); } +/* Device initialization: */ + INLINE_DEVICE\ -(device_instance *) -external_to_device_instance(device *tree_member, - unsigned32 ihandle) +(void) +device_init_address(device *me, + void *data) { - device *root = device_tree_find_device(tree_member, "/"); - device_instance *instance = cap_internal(root->ihandles, ihandle); - return instance; + 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); + } + + /* 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"); + } + + /* 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\ -(unsigned32) -device_instance_to_external(device_instance *instance) +(void) +device_init_data(device *me, + void *data) { - device *root = device_tree_find_device(instance->owner, "/"); - unsigned32 ihandle = cap_external(root->ihandles, instance); - return ihandle; + 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_ */ |