diff options
author | Anthony Liguori <aliguori@us.ibm.com> | 2011-12-12 14:29:26 -0600 |
---|---|---|
committer | Anthony Liguori <aliguori@us.ibm.com> | 2011-12-15 09:20:47 -0600 |
commit | 44677ded43f1dec44fabfe52f3a4f6eb28134f95 (patch) | |
tree | bf238a0e96f0f23df7d80d83c3674128f340a489 /hw/qdev.c | |
parent | 85ed303bfe1f67a4c18ffe51916e73cffd7d9e9b (diff) |
qom: add new dynamic property infrastructure based on Visitors (v2)
qdev properties are settable only during construction and static to classes.
This isn't flexible enough for QOM.
This patch introduces a property interface for qdev that provides dynamic
properties that are tied to objects, instead of classes. These properties are
Visitor based instead of string based too.
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
Diffstat (limited to 'hw/qdev.c')
-rw-r--r-- | hw/qdev.c | 97 |
1 files changed, 97 insertions, 0 deletions
@@ -98,6 +98,7 @@ static DeviceState *qdev_create_from_info(BusState *bus, DeviceInfo *info) qdev_hot_added = true; } dev->instance_id_alias = -1; + QTAILQ_INIT(&dev->properties); dev->state = DEV_STATE_CREATED; return dev; } @@ -395,12 +396,31 @@ void qdev_init_nofail(DeviceState *dev) } } +static void qdev_property_del_all(DeviceState *dev) +{ + while (!QTAILQ_EMPTY(&dev->properties)) { + DeviceProperty *prop = QTAILQ_FIRST(&dev->properties); + + QTAILQ_REMOVE(&dev->properties, prop, node); + + if (prop->release) { + prop->release(dev, prop->name, prop->opaque); + } + + g_free(prop->name); + g_free(prop->type); + g_free(prop); + } +} + /* Unlink device from bus and free the structure. */ void qdev_free(DeviceState *dev) { BusState *bus; Property *prop; + qdev_property_del_all(dev); + if (dev->state == DEV_STATE_INITIALIZED) { while (dev->num_child_bus) { bus = QLIST_FIRST(&dev->child_bus); @@ -978,3 +998,80 @@ void qdev_unref(DeviceState *dev) g_assert(dev->ref > 0); dev->ref--; } + +void qdev_property_add(DeviceState *dev, const char *name, const char *type, + DevicePropertyAccessor *get, DevicePropertyAccessor *set, + DevicePropertyRelease *release, + void *opaque, Error **errp) +{ + DeviceProperty *prop = g_malloc0(sizeof(*prop)); + + prop->name = g_strdup(name); + prop->type = g_strdup(type); + + prop->get = get; + prop->set = set; + prop->release = release; + prop->opaque = opaque; + + QTAILQ_INSERT_TAIL(&dev->properties, prop, node); +} + +static DeviceProperty *qdev_property_find(DeviceState *dev, const char *name) +{ + DeviceProperty *prop; + + QTAILQ_FOREACH(prop, &dev->properties, node) { + if (strcmp(prop->name, name) == 0) { + return prop; + } + } + + return NULL; +} + +void qdev_property_get(DeviceState *dev, Visitor *v, const char *name, + Error **errp) +{ + DeviceProperty *prop = qdev_property_find(dev, name); + + if (prop == NULL) { + error_set(errp, QERR_PROPERTY_NOT_FOUND, dev->id?:"", name); + return; + } + + if (!prop->get) { + error_set(errp, QERR_PERMISSION_DENIED); + } else { + prop->get(dev, v, prop->opaque, name, errp); + } +} + +void qdev_property_set(DeviceState *dev, Visitor *v, const char *name, + Error **errp) +{ + DeviceProperty *prop = qdev_property_find(dev, name); + + if (prop == NULL) { + error_set(errp, QERR_PROPERTY_NOT_FOUND, dev->id?:"", name); + return; + } + + if (!prop->set) { + error_set(errp, QERR_PERMISSION_DENIED); + } else { + prop->set(dev, prop->opaque, v, name, errp); + } +} + +const char *qdev_property_get_type(DeviceState *dev, const char *name, Error **errp) +{ + DeviceProperty *prop = qdev_property_find(dev, name); + + if (prop == NULL) { + error_set(errp, QERR_PROPERTY_NOT_FOUND, dev->id?:"", name); + return NULL; + } + + return prop->type; +} |