aboutsummaryrefslogtreecommitdiff
path: root/hw/qdev.c
diff options
context:
space:
mode:
authorAnthony Liguori <aliguori@us.ibm.com>2011-12-12 14:29:26 -0600
committerAnthony Liguori <aliguori@us.ibm.com>2011-12-15 09:20:47 -0600
commit44677ded43f1dec44fabfe52f3a4f6eb28134f95 (patch)
treebf238a0e96f0f23df7d80d83c3674128f340a489 /hw/qdev.c
parent85ed303bfe1f67a4c18ffe51916e73cffd7d9e9b (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.c97
1 files changed, 97 insertions, 0 deletions
diff --git a/hw/qdev.c b/hw/qdev.c
index fdc984312c..94f14c1f1c 100644
--- a/hw/qdev.c
+++ b/hw/qdev.c
@@ -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;
+}