#include "qapi/qmp/dispatch.h"
#include "qapi/qmp/qdict.h"
#include "qapi/qmp/qerror.h"
+#include "qapi/qmp/qstring.h"
+#include "qapi/qobject-input-visitor.h"
#include "qemu/config-file.h"
#include "qemu/error-report.h"
#include "qemu/help_option.h"
#include "qemu/cutils.h"
#include "hw/qdev-properties.h"
#include "hw/clock.h"
+#include "hw/boards.h"
/*
* Aliases were a bad idea from the start. Let's keep them
{ "virtio-gpu-device", "virtio-gpu", QEMU_ARCH_VIRTIO_MMIO },
{ "virtio-gpu-ccw", "virtio-gpu", QEMU_ARCH_VIRTIO_CCW },
{ "virtio-gpu-pci", "virtio-gpu", QEMU_ARCH_VIRTIO_PCI },
+ { "virtio-gpu-gl-device", "virtio-gpu-gl", QEMU_ARCH_VIRTIO_MMIO },
+ { "virtio-gpu-gl-pci", "virtio-gpu-gl", QEMU_ARCH_VIRTIO_PCI },
{ "virtio-input-host-device", "virtio-input-host", QEMU_ARCH_VIRTIO_MMIO },
{ "virtio-input-host-ccw", "virtio-input-host", QEMU_ARCH_VIRTIO_CCW },
{ "virtio-input-host-pci", "virtio-input-host", QEMU_ARCH_VIRTIO_PCI },
[DEVICE_CATEGORY_SOUND] = "Sound",
[DEVICE_CATEGORY_MISC] = "Misc",
[DEVICE_CATEGORY_CPU] = "CPU",
+ [DEVICE_CATEGORY_WATCHDOG]= "Watchdog",
[DEVICE_CATEGORY_MAX] = "Uncategorized",
};
GSList *list, *elt;
g_slist_free(list);
}
-static int set_property(void *opaque, const char *name, const char *value,
- Error **errp)
-{
- Object *obj = opaque;
-
- if (strcmp(name, "driver") == 0)
- return 0;
- if (strcmp(name, "bus") == 0)
- return 0;
-
- if (!object_property_parse(obj, name, value, errp)) {
- return -1;
- }
- return 0;
-}
-
static const char *find_typename_by_alias(const char *alias)
{
int i;
return NULL;
}
+ if (object_class_dynamic_cast(oc, TYPE_SYS_BUS_DEVICE)) {
+ /* sysbus devices need to be allowed by the machine */
+ MachineClass *mc = MACHINE_CLASS(object_get_class(qdev_get_machine()));
+ if (!device_type_is_dynamic_sysbus(mc, *driver)) {
+ error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "driver",
+ "a dynamic sysbus device type for the machine");
+ return NULL;
+ }
+ }
+
return dc;
}
return bus;
}
-void qdev_set_id(DeviceState *dev, const char *id)
+/* Takes ownership of @id, will be freed when deleting the device */
+const char *qdev_set_id(DeviceState *dev, char *id, Error **errp)
{
- if (id) {
- dev->id = id;
- }
+ ObjectProperty *prop;
+
+ assert(!dev->id && !dev->realized);
- if (dev->id) {
- object_property_add_child(qdev_get_peripheral(), dev->id,
- OBJECT(dev));
+ /*
+ * object_property_[try_]add_child() below will assert the device
+ * has no parent
+ */
+ if (id) {
+ prop = object_property_try_add_child(qdev_get_peripheral(), id,
+ OBJECT(dev), NULL);
+ if (prop) {
+ dev->id = id;
+ } else {
+ error_setg(errp, "Duplicate device ID '%s'", id);
+ g_free(id);
+ return NULL;
+ }
} else {
static int anon_count;
gchar *name = g_strdup_printf("device[%d]", anon_count++);
- object_property_add_child(qdev_get_peripheral_anon(), name,
- OBJECT(dev));
+ prop = object_property_add_child(qdev_get_peripheral_anon(), name,
+ OBJECT(dev));
g_free(name);
}
+
+ return prop->name;
}
-DeviceState *qdev_device_add(QemuOpts *opts, Error **errp)
+DeviceState *qdev_device_add_from_qdict(const QDict *opts,
+ bool from_json, Error **errp)
{
+ ERRP_GUARD();
DeviceClass *dc;
const char *driver, *path;
+ char *id;
DeviceState *dev = NULL;
BusState *bus = NULL;
- driver = qemu_opt_get(opts, "driver");
+ driver = qdict_get_try_str(opts, "driver");
if (!driver) {
error_setg(errp, QERR_MISSING_PARAMETER, "driver");
return NULL;
}
/* find bus */
- path = qemu_opt_get(opts, "bus");
+ path = qdict_get_try_str(opts, "bus");
if (path != NULL) {
bus = qbus_find(path, errp);
if (!bus) {
}
}
- if (qemu_opt_get(opts, "failover_pair_id")) {
- if (!opts->id) {
- error_setg(errp, "Device with failover_pair_id don't have id");
- return NULL;
- }
- if (qdev_should_hide_device(opts)) {
- if (bus && !qbus_is_hotpluggable(bus)) {
- error_setg(errp, QERR_BUS_NO_HOTPLUG, bus->name);
- }
- return NULL;
+ if (qdev_should_hide_device(opts, from_json, errp)) {
+ if (bus && !qbus_is_hotpluggable(bus)) {
+ error_setg(errp, QERR_BUS_NO_HOTPLUG, bus->name);
}
+ return NULL;
+ } else if (*errp) {
+ return NULL;
}
if (phase_check(PHASE_MACHINE_READY) && bus && !qbus_is_hotpluggable(bus)) {
}
}
- qdev_set_id(dev, qemu_opts_id(opts));
+ /*
+ * set dev's parent and register its id.
+ * If it fails it means the id is already taken.
+ */
+ id = g_strdup(qdict_get_try_str(opts, "id"));
+ if (!qdev_set_id(dev, id, errp)) {
+ goto err_del_dev;
+ }
/* set properties */
- if (qemu_opt_foreach(opts, set_property, dev, errp)) {
+ dev->opts = qdict_clone_shallow(opts);
+ qdict_del(dev->opts, "driver");
+ qdict_del(dev->opts, "bus");
+ qdict_del(dev->opts, "id");
+
+ object_set_properties_from_keyval(&dev->parent_obj, dev->opts, from_json,
+ errp);
+ if (*errp) {
goto err_del_dev;
}
- dev->opts = opts;
if (!qdev_realize(DEVICE(dev), bus, errp)) {
- dev->opts = NULL;
goto err_del_dev;
}
return dev;
return NULL;
}
+/* Takes ownership of @opts on success */
+DeviceState *qdev_device_add(QemuOpts *opts, Error **errp)
+{
+ QDict *qdict = qemu_opts_to_qdict(opts, NULL);
+ DeviceState *ret;
+
+ ret = qdev_device_add_from_qdict(qdict, false, errp);
+ if (ret) {
+ qemu_opts_del(opts);
+ }
+ qobject_unref(qdict);
+ return ret;
+}
#define qdev_printf(fmt, ...) monitor_printf(mon, "%*s" fmt, indent, "", ## __VA_ARGS__)
static void qbus_print(Monitor *mon, BusState *bus, int indent);
static DeviceState *find_device_state(const char *id, Error **errp)
{
- Object *obj;
-
- if (id[0] == '/') {
- obj = object_resolve_path(id, NULL);
- } else {
- char *root_path = object_get_canonical_path(qdev_get_peripheral());
- char *path = g_strdup_printf("%s/%s", root_path, id);
-
- g_free(root_path);
- obj = object_resolve_path_type(path, TYPE_DEVICE, NULL);
- g_free(path);
- }
+ Object *obj = object_resolve_path_at(qdev_get_peripheral(), id);
+ DeviceState *dev;
if (!obj) {
error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
return NULL;
}
- if (!object_dynamic_cast(obj, TYPE_DEVICE)) {
+ dev = (DeviceState *)object_dynamic_cast(obj, TYPE_DEVICE);
+ if (!dev) {
error_setg(errp, "%s is not a hotpluggable device", id);
return NULL;
}
- return DEVICE(obj);
+ return dev;
}
void qdev_unplug(DeviceState *dev, Error **errp)
{
DeviceState *dev = find_device_state(id, errp);
if (dev != NULL) {
- if (dev->pending_deleted_event) {
+ if (dev->pending_deleted_event &&
+ (dev->pending_deleted_expires_ms == 0 ||
+ dev->pending_deleted_expires_ms > qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL))) {
error_setg(errp, "Device %s is already in the "
"process of unplug", id);
return;
DeviceState *dev;
BlockBackend *blk;
+ GLOBAL_STATE_CODE();
+
dev = find_device_state(id, errp);
if (dev == NULL) {
return NULL;
if (!opts) {
return -1;
}
+ if (!qemu_opt_get(opts, "driver")
+ || !qemu_opt_get(opts, "property")
+ || !qemu_opt_get(opts, "value")) {
+ error_report("options 'driver', 'property', and 'value'"
+ " are required");
+ return -1;
+ }
return 0;
}