aboutsummaryrefslogtreecommitdiff
path: root/hw
diff options
context:
space:
mode:
Diffstat (limited to 'hw')
-rw-r--r--hw/core/bus.c14
-rw-r--r--hw/core/qdev.c90
2 files changed, 104 insertions, 0 deletions
diff --git a/hw/core/bus.c b/hw/core/bus.c
index 33a4443..6f6071f 100644
--- a/hw/core/bus.c
+++ b/hw/core/bus.c
@@ -164,6 +164,20 @@ BusState *qbus_create(const char *typename, DeviceState *parent, const char *nam
return bus;
}
+bool qbus_realize(BusState *bus, Error **errp)
+{
+ Error *err = NULL;
+
+ object_property_set_bool(OBJECT(bus), true, "realized", &err);
+ error_propagate(errp, err);
+ return !err;
+}
+
+void qbus_unrealize(BusState *bus)
+{
+ object_property_set_bool(OBJECT(bus), false, "realized", &error_abort);
+}
+
static bool bus_get_realized(Object *obj, Error **errp)
{
BusState *bus = BUS(obj);
diff --git a/hw/core/qdev.c b/hw/core/qdev.c
index a68ba67..f2c5cee 100644
--- a/hw/core/qdev.c
+++ b/hw/core/qdev.c
@@ -176,6 +176,32 @@ DeviceState *qdev_try_create(BusState *bus, const char *type)
return dev;
}
+/*
+ * Create a device on the heap.
+ * A type @name must exist.
+ * This only initializes the device state structure and allows
+ * properties to be set. The device still needs to be realized. See
+ * qdev-core.h.
+ */
+DeviceState *qdev_new(const char *name)
+{
+ return DEVICE(object_new(name));
+}
+
+/*
+ * Try to create a device on the heap.
+ * This is like qdev_new(), except it returns %NULL when type @name
+ * does not exist.
+ */
+DeviceState *qdev_try_new(const char *name)
+{
+ if (!object_class_by_name(name)) {
+ return NULL;
+ }
+
+ return DEVICE(object_new(name));
+}
+
static QTAILQ_HEAD(, DeviceListener) device_listeners
= QTAILQ_HEAD_INITIALIZER(device_listeners);
@@ -427,6 +453,66 @@ void qdev_init_nofail(DeviceState *dev)
object_unref(OBJECT(dev));
}
+/*
+ * Realize @dev.
+ * @dev must not be plugged into a bus.
+ * Plug @dev into @bus if non-null, else into the main system bus.
+ * This takes a reference to @dev.
+ * If @dev has no QOM parent, make one up, taking another reference.
+ * On success, return true.
+ * On failure, store an error through @errp and return false.
+ */
+bool qdev_realize(DeviceState *dev, BusState *bus, Error **errp)
+{
+ Error *err = NULL;
+
+ assert(!dev->realized && !dev->parent_bus);
+
+ if (!bus) {
+ /*
+ * Assert that the device really is a SysBusDevice before we
+ * put it onto the sysbus. Non-sysbus devices which aren't
+ * being put onto a bus should be realized with
+ * object_property_set_bool(OBJECT(dev), true, "realized",
+ * errp);
+ */
+ g_assert(object_dynamic_cast(OBJECT(dev), TYPE_SYS_BUS_DEVICE));
+ bus = sysbus_get_default();
+ }
+
+ qdev_set_parent_bus(dev, bus);
+
+ object_property_set_bool(OBJECT(dev), true, "realized", &err);
+ if (err) {
+ error_propagate(errp, err);
+ }
+ return !err;
+}
+
+/*
+ * Realize @dev and drop a reference.
+ * This is like qdev_realize(), except the caller must hold a
+ * (private) reference, which is dropped on return regardless of
+ * success or failure. Intended use:
+ * dev = qdev_new();
+ * [...]
+ * qdev_realize_and_unref(dev, bus, errp);
+ * Now @dev can go away without further ado.
+ */
+bool qdev_realize_and_unref(DeviceState *dev, BusState *bus, Error **errp)
+{
+ bool ret;
+
+ ret = qdev_realize(dev, bus, errp);
+ object_unref(OBJECT(dev));
+ return ret;
+}
+
+void qdev_unrealize(DeviceState *dev)
+{
+ object_property_set_bool(OBJECT(dev), false, "realized", &error_abort);
+}
+
static int qdev_assert_realized_properly(Object *obj, void *opaque)
{
DeviceState *dev = DEVICE(object_dynamic_cast(obj, TYPE_DEVICE));
@@ -1002,6 +1088,10 @@ post_realize_fail:
fail:
error_propagate(errp, local_err);
if (unattached_parent) {
+ /*
+ * Beware, this doesn't just revert
+ * object_property_add_child(), it also runs bus_remove()!
+ */
object_unparent(OBJECT(dev));
unattached_count--;
}