aboutsummaryrefslogtreecommitdiff
path: root/hw/core/qdev.c
diff options
context:
space:
mode:
Diffstat (limited to 'hw/core/qdev.c')
-rw-r--r--hw/core/qdev.c149
1 files changed, 54 insertions, 95 deletions
diff --git a/hw/core/qdev.c b/hw/core/qdev.c
index f3a996f..f600226 100644
--- a/hw/core/qdev.c
+++ b/hw/core/qdev.c
@@ -28,7 +28,7 @@
#include "qemu/osdep.h"
#include "qapi/error.h"
#include "qapi/qapi-events-qdev.h"
-#include "qapi/qmp/qdict.h"
+#include "qobject/qdict.h"
#include "qapi/visitor.h"
#include "qemu/error-report.h"
#include "qemu/option.h"
@@ -146,31 +146,16 @@ bool qdev_set_parent_bus(DeviceState *dev, BusState *bus, Error **errp)
DeviceState *qdev_new(const char *name)
{
- ObjectClass *oc = object_class_by_name(name);
-#ifdef CONFIG_MODULES
- if (!oc) {
- int rv = module_load_qom(name, &error_fatal);
- if (rv > 0) {
- oc = object_class_by_name(name);
- } else {
- error_report("could not find a module for type '%s'", name);
- exit(1);
- }
- }
-#endif
- if (!oc) {
- error_report("unknown type '%s'", name);
- abort();
- }
return DEVICE(object_new(name));
}
DeviceState *qdev_try_new(const char *name)
{
- if (!module_object_class_by_name(name)) {
+ ObjectClass *oc = module_object_class_by_name(name);
+ if (!oc) {
return NULL;
}
- return DEVICE(object_new(name));
+ return DEVICE(object_new_with_class(oc));
}
static QTAILQ_HEAD(, DeviceListener) device_listeners
@@ -491,8 +476,7 @@ static void device_set_realized(Object *obj, bool value, Error **errp)
if (!obj->parent) {
gchar *name = g_strdup_printf("device[%d]", unattached_count++);
- object_property_add_child(container_get(qdev_get_machine(),
- "/unattached"),
+ object_property_add_child(machine_get_container("unattached"),
name, obj);
unattached_parent = true;
g_free(name);
@@ -706,11 +690,10 @@ static void device_finalize(Object *obj)
dev->canonical_path = NULL;
}
- qobject_unref(dev->opts);
g_free(dev->id);
}
-static void device_class_base_init(ObjectClass *class, void *data)
+static void device_class_base_init(ObjectClass *class, const void *data)
{
DeviceClass *klass = DEVICE_CLASS(class);
@@ -718,6 +701,7 @@ static void device_class_base_init(ObjectClass *class, void *data)
* so do not propagate them to the subclasses.
*/
klass->props_ = NULL;
+ klass->props_count_ = 0;
}
static void device_unparent(Object *obj)
@@ -747,58 +731,7 @@ device_vmstate_if_get_id(VMStateIf *obj)
return qdev_get_dev_path(dev);
}
-/**
- * device_phases_reset:
- * Transition reset method for devices to allow moving
- * smoothly from legacy reset method to multi-phases
- */
-static void device_phases_reset(DeviceState *dev)
-{
- ResettableClass *rc = RESETTABLE_GET_CLASS(dev);
-
- if (rc->phases.enter) {
- rc->phases.enter(OBJECT(dev), RESET_TYPE_COLD);
- }
- if (rc->phases.hold) {
- rc->phases.hold(OBJECT(dev), RESET_TYPE_COLD);
- }
- if (rc->phases.exit) {
- rc->phases.exit(OBJECT(dev), RESET_TYPE_COLD);
- }
-}
-
-static void device_transitional_reset(Object *obj)
-{
- DeviceClass *dc = DEVICE_GET_CLASS(obj);
-
- /*
- * This will call either @device_phases_reset (for multi-phases transitioned
- * devices) or a device's specific method for not-yet transitioned devices.
- * In both case, it does not reset children.
- */
- if (dc->reset) {
- dc->reset(DEVICE(obj));
- }
-}
-
-/**
- * device_get_transitional_reset:
- * check if the device's class is ready for multi-phase
- */
-static ResettableTrFunction device_get_transitional_reset(Object *obj)
-{
- DeviceClass *dc = DEVICE_GET_CLASS(obj);
- if (dc->reset != device_phases_reset) {
- /*
- * dc->reset has been overridden by a subclass,
- * the device is not ready for multi phase yet.
- */
- return device_transitional_reset;
- }
- return NULL;
-}
-
-static void device_class_init(ObjectClass *class, void *data)
+static void device_class_init(ObjectClass *class, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(class);
VMStateIfClass *vc = VMSTATE_IF_CLASS(class);
@@ -819,20 +752,12 @@ static void device_class_init(ObjectClass *class, void *data)
rc->child_foreach = device_reset_child_foreach;
/*
- * @device_phases_reset is put as the default reset method below, allowing
- * to do the multi-phase transition from base classes to leaf classes. It
- * allows a legacy-reset Device class to extend a multi-phases-reset
- * Device class for the following reason:
- * + If a base class B has been moved to multi-phase, then it does not
- * override this default reset method and may have defined phase methods.
- * + A child class C (extending class B) which uses
- * device_class_set_parent_reset() (or similar means) to override the
- * reset method will still work as expected. @device_phases_reset function
- * will be registered as the parent reset method and effectively call
- * parent reset phases.
+ * A NULL legacy_reset implies a three-phase reset device. Devices can
+ * only be reset using three-phase aware mechanisms, but we still support
+ * for transitional purposes leaf classes which set the old legacy_reset
+ * method via device_class_set_legacy_reset().
*/
- dc->reset = device_phases_reset;
- rc->get_transitional_function = device_get_transitional_reset;
+ dc->legacy_reset = NULL;
object_class_property_add_bool(class, "realized",
device_get_realized, device_set_realized);
@@ -844,12 +769,30 @@ static void device_class_init(ObjectClass *class, void *data)
offsetof(DeviceState, parent_bus), NULL, 0);
}
-void device_class_set_parent_reset(DeviceClass *dc,
- DeviceReset dev_reset,
- DeviceReset *parent_reset)
+static void do_legacy_reset(Object *obj, ResetType type)
{
- *parent_reset = dc->reset;
- dc->reset = dev_reset;
+ DeviceClass *dc = DEVICE_GET_CLASS(obj);
+
+ dc->legacy_reset(DEVICE(obj));
+}
+
+void device_class_set_legacy_reset(DeviceClass *dc, DeviceReset dev_reset)
+{
+ /*
+ * A legacy DeviceClass::reset has identical semantics to the
+ * three-phase "hold" method, with no "enter" or "exit"
+ * behaviour. Classes that use this legacy function must be leaf
+ * classes that do not chain up to their parent class reset.
+ * There is no mechanism for resetting a device that does not
+ * use the three-phase APIs, so the only place which calls
+ * the legacy_reset hook is do_legacy_reset().
+ */
+ ResettableClass *rc = RESETTABLE_CLASS(dc);
+
+ rc->phases.enter = NULL;
+ rc->phases.hold = do_legacy_reset;
+ rc->phases.exit = NULL;
+ dc->legacy_reset = dev_reset;
}
void device_class_set_parent_realize(DeviceClass *dc,
@@ -873,12 +816,28 @@ Object *qdev_get_machine(void)
static Object *dev;
if (dev == NULL) {
- dev = container_get(object_get_root(), "/machine");
+ dev = object_resolve_path_component(object_get_root(), "machine");
+ /*
+ * Any call to this function before machine is created is treated
+ * as a programming error as of now.
+ */
+ assert(dev);
}
return dev;
}
+Object *machine_get_container(const char *name)
+{
+ Object *container, *machine;
+
+ machine = qdev_get_machine();
+ container = object_resolve_path_component(machine, name);
+ assert(object_dynamic_cast(container, TYPE_CONTAINER));
+
+ return container;
+}
+
char *qdev_get_human_name(DeviceState *dev)
{
g_assert(dev != NULL);
@@ -911,7 +870,7 @@ static const TypeInfo device_type_info = {
.class_init = device_class_init,
.abstract = true,
.class_size = sizeof(DeviceClass),
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_VMSTATE_IF },
{ TYPE_RESETTABLE_INTERFACE },
{ }