summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--hw/qdev.c74
-rw-r--r--hw/qdev.h23
2 files changed, 97 insertions, 0 deletions
diff --git a/hw/qdev.c b/hw/qdev.c
index 167f459996..d4482754b0 100644
--- a/hw/qdev.c
+++ b/hw/qdev.c
@@ -1200,6 +1200,80 @@ void qdev_property_add_child(DeviceState *dev, const char *name,
g_free(type);
}
+static void qdev_get_link_property(DeviceState *dev, Visitor *v, void *opaque,
+ const char *name, Error **errp)
+{
+ DeviceState **child = opaque;
+ gchar *path;
+
+ if (*child) {
+ path = qdev_get_canonical_path(*child);
+ visit_type_str(v, &path, name, errp);
+ g_free(path);
+ } else {
+ path = (gchar *)"";
+ visit_type_str(v, &path, name, errp);
+ }
+}
+
+static void qdev_set_link_property(DeviceState *dev, Visitor *v, void *opaque,
+ const char *name, Error **errp)
+{
+ DeviceState **child = opaque;
+ bool ambiguous = false;
+ const char *type;
+ char *path;
+
+ type = qdev_property_get_type(dev, name, NULL);
+
+ visit_type_str(v, &path, name, errp);
+
+ if (*child) {
+ qdev_unref(*child);
+ }
+
+ if (strcmp(path, "") != 0) {
+ DeviceState *target;
+
+ target = qdev_resolve_path(path, &ambiguous);
+ if (target) {
+ gchar *target_type;
+
+ target_type = g_strdup_printf("link<%s>", target->info->name);
+ if (strcmp(target_type, type) == 0) {
+ *child = target;
+ qdev_ref(target);
+ } else {
+ error_set(errp, QERR_INVALID_PARAMETER_TYPE, name, type);
+ }
+
+ g_free(target_type);
+ } else {
+ error_set(errp, QERR_DEVICE_NOT_FOUND, path);
+ }
+ } else {
+ *child = NULL;
+ }
+
+ g_free(path);
+}
+
+void qdev_property_add_link(DeviceState *dev, const char *name,
+ const char *type, DeviceState **child,
+ Error **errp)
+{
+ gchar *full_type;
+
+ full_type = g_strdup_printf("link<%s>", type);
+
+ qdev_property_add(dev, name, full_type,
+ qdev_get_link_property,
+ qdev_set_link_property,
+ NULL, child, errp);
+
+ g_free(full_type);
+}
+
static gchar *qdev_get_path_in(DeviceState *parent, DeviceState *dev)
{
DeviceProperty *prop;
diff --git a/hw/qdev.h b/hw/qdev.h
index 38b36e8b91..4351e2e5af 100644
--- a/hw/qdev.h
+++ b/hw/qdev.h
@@ -547,4 +547,27 @@ DeviceState *qdev_resolve_path(const char *path, bool *ambiguous);
void qdev_property_add_child(DeviceState *dev, const char *name,
DeviceState *child, Error **errp);
+/**
+ * @qdev_property_add_link - Add a link property to a device
+ *
+ * Links establish relationships between devices. Links are unidirectional
+ * although two links can be combined to form a bidirectional relationship
+ * between devices.
+ *
+ * Links form the graph in the device model.
+ *
+ * @dev - the device to add a property to
+ *
+ * @name - the name of the property
+ *
+ * @type - the qdev type of the link
+ *
+ * @child - a pointer to where the link device reference is stored
+ *
+ * @errp - if an error occurs, a pointer to an area to store the area
+ */
+void qdev_property_add_link(DeviceState *dev, const char *name,
+ const char *type, DeviceState **child,
+ Error **errp);
+
#endif