@@ -57,7 +57,7 @@ typedef void (*BusUnrealize)(BusState *bus);
* After successful realization, setting static properties will fail.
*
* As an interim step, the #DeviceState:realized property can also be
- * set with qdev_init_nofail().
+ * set with qdev_realize() or qdev_init_nofail().
* In the future, devices will propagate this state change to their children
* and along busses they expose.
* The point in time will be deferred to machine creation, so that values
@@ -322,7 +322,13 @@ compat_props_add(GPtrArray *arr,
DeviceState *qdev_create(BusState *bus, const char *name);
DeviceState *qdev_try_create(BusState *bus, const char *name);
+DeviceState *qdev_new(const char *name);
+DeviceState *qdev_try_new(const char *name);
void qdev_init_nofail(DeviceState *dev);
+bool qdev_realize(DeviceState *dev, BusState *bus, Error **errp);
+bool qdev_realize_and_unref(DeviceState *dev, BusState *bus, Error **errp);
+void qdev_unrealize(DeviceState *dev);
+
void qdev_set_legacy_instance_id(DeviceState *dev, int alias_id,
int required_for_version);
HotplugHandler *qdev_get_bus_hotplug_handler(DeviceState *dev);
@@ -411,6 +417,9 @@ typedef int (qdev_walkerfn)(DeviceState *dev, void *opaque);
void qbus_create_inplace(void *bus, size_t size, const char *typename,
DeviceState *parent, const char *name);
BusState *qbus_create(const char *typename, DeviceState *parent, const char *name);
+bool qbus_realize(BusState *bus, Error **errp);
+void qbus_unrealize(BusState *bus);
+
/* Returns > 0 if either devfn or busfn skip walk somewhere in cursion,
* < 0 if either devfn or busfn terminate walk somewhere in cursion,
* 0 otherwise. */
@@ -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);
@@ -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--;
}