diff --git a/hw/qdev.c b/hw/qdev.c index 167f4599966df5b73d626698318087f2ccd4499d..d4482754b057ba6e8a721f1f39076261e44f1b11 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 38b36e8b91c3219527ed9dbe8d908d6a77cd6641..4351e2e5afa0e35d854c045178efa248acda90e1 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