#include "qdev.h"
#include "sysemu.h"
#include "monitor.h"
+#include "blockdev.h"
static int qdev_hotplug = 0;
assert(bus->allow_hotplug);
dev->hotplugged = 1;
}
+ dev->instance_id_alias = -1;
dev->state = DEV_STATE_CREATED;
return dev;
}
DeviceInfo *info;
if (!bus) {
- if (!main_system_bus) {
- main_system_bus = qbus_create(&system_bus_info, NULL, "main-system-bus");
- }
- bus = main_system_bus;
+ bus = sysbus_get_default();
}
info = qdev_find_info(bus->info, name);
/* find driver */
info = qdev_find_info(NULL, driver);
if (!info || info->no_user) {
- qerror_report(QERR_INVALID_PARAMETER, "driver");
+ qerror_report(QERR_INVALID_PARAMETER_VALUE, "driver", "a driver name");
error_printf_unless_qmp("Try with argument '?' for a list.\n");
return NULL;
}
return qdev;
}
-static void qdev_reset(void *opaque)
-{
- DeviceState *dev = opaque;
- if (dev->info->reset)
- dev->info->reset(dev);
-}
-
/* Initialize a device. Device properties should be set before calling
this function. IRQs and MMIO regions should be connected/mapped after
calling this function.
qdev_free(dev);
return rc;
}
- qemu_register_reset(qdev_reset, dev);
- if (dev->info->vmsd)
- vmstate_register(-1, dev->info->vmsd, dev);
+ if (dev->info->vmsd) {
+ vmstate_register_with_alias_id(dev, -1, dev->info->vmsd, dev,
+ dev->instance_id_alias,
+ dev->alias_required_for_version);
+ }
dev->state = DEV_STATE_INITIALIZED;
return 0;
}
+void qdev_set_legacy_instance_id(DeviceState *dev, int alias_id,
+ int required_for_version)
+{
+ assert(dev->state == DEV_STATE_CREATED);
+ dev->instance_id_alias = alias_id;
+ dev->alias_required_for_version = required_for_version;
+}
+
int qdev_unplug(DeviceState *dev)
{
if (!dev->parent_bus->allow_hotplug) {
- error_report("Bus %s does not support hotplugging",
- dev->parent_bus->name);
+ qerror_report(QERR_BUS_NO_HOTPLUG, dev->parent_bus->name);
return -1;
}
assert(dev->info->unplug != NULL);
return dev->info->unplug(dev);
}
+static int qdev_reset_one(DeviceState *dev, void *opaque)
+{
+ if (dev->info->reset) {
+ dev->info->reset(dev);
+ }
+
+ return 0;
+}
+
+BusState *sysbus_get_default(void)
+{
+ if (!main_system_bus) {
+ main_system_bus = qbus_create(&system_bus_info, NULL,
+ "main-system-bus");
+ }
+ return main_system_bus;
+}
+
+static int qbus_reset_one(BusState *bus, void *opaque)
+{
+ if (bus->info->reset) {
+ return bus->info->reset(bus);
+ }
+ return 0;
+}
+
+void qdev_reset_all(DeviceState *dev)
+{
+ qdev_walk_children(dev, qdev_reset_one, qbus_reset_one, NULL);
+}
+
+void qbus_reset_all(BusState *bus)
+{
+ qbus_walk_children(bus, qdev_reset_one, qbus_reset_one, NULL);
+}
+
/* can be used as ->unplug() callback for the simple cases */
int qdev_simple_unplug_cb(DeviceState *dev)
{
{
DeviceInfo *info = dev->info;
- if (qdev_init(dev) < 0)
- hw_error("Initialization of device %s failed\n", info->name);
+ if (qdev_init(dev) < 0) {
+ error_report("Initialization of device %s failed\n", info->name);
+ exit(1);
+ }
}
/* Unlink device from bus and free the structure. */
void qdev_free(DeviceState *dev)
{
BusState *bus;
+ Property *prop;
if (dev->state == DEV_STATE_INITIALIZED) {
while (dev->num_child_bus) {
qbus_free(bus);
}
if (dev->info->vmsd)
- vmstate_unregister(dev->info->vmsd, dev);
+ vmstate_unregister(dev, dev->info->vmsd, dev);
if (dev->info->exit)
dev->info->exit(dev);
if (dev->opts)
qemu_opts_del(dev->opts);
}
- qemu_unregister_reset(qdev_reset, dev);
QLIST_REMOVE(dev, sibling);
+ for (prop = dev->info->props; prop && prop->name; prop++) {
+ if (prop->info->free) {
+ prop->info->free(dev, prop);
+ }
+ }
qemu_free(dev);
}
return NULL;
}
+int qbus_walk_children(BusState *bus, qdev_walkerfn *devfn,
+ qbus_walkerfn *busfn, void *opaque)
+{
+ DeviceState *dev;
+ int err;
+
+ if (busfn) {
+ err = busfn(bus, opaque);
+ if (err) {
+ return err;
+ }
+ }
+
+ QLIST_FOREACH(dev, &bus->children, sibling) {
+ err = qdev_walk_children(dev, devfn, busfn, opaque);
+ if (err < 0) {
+ return err;
+ }
+ }
+
+ return 0;
+}
+
+int qdev_walk_children(DeviceState *dev, qdev_walkerfn *devfn,
+ qbus_walkerfn *busfn, void *opaque)
+{
+ BusState *bus;
+ int err;
+
+ if (devfn) {
+ err = devfn(dev, opaque);
+ if (err) {
+ return err;
+ }
+ }
+
+ QLIST_FOREACH(bus, &dev->child_bus, sibling) {
+ err = qbus_walk_children(bus, devfn, busfn, opaque);
+ if (err < 0) {
+ return err;
+ }
+ }
+
+ return 0;
+}
+
static BusState *qbus_find_recursive(BusState *bus, const char *name,
const BusInfo *info)
{
QLIST_REMOVE(bus, sibling);
bus->parent->num_child_bus--;
}
+ qemu_free((void*)bus->name);
if (bus->qdev_allocated) {
qemu_free(bus);
}
}
}
-/**
- * do_device_add(): Add a device
- *
- * Argument qdict contains
- * - "driver": the name of the new device's driver
- * - "bus": the device's parent bus (device tree path)
- * - "id": the device's ID (must be unique)
- * - device properties
- *
- * Example:
- *
- * { "driver": "usb-net", "id": "eth1", "netdev": "netdev1" }
- */
int do_device_add(Monitor *mon, const QDict *qdict, QObject **ret_data)
{
QemuOpts *opts;
- opts = qemu_opts_from_qdict(&qemu_device_opts, qdict);
+ opts = qemu_opts_from_qdict(qemu_find_opts("device"), qdict);
if (!opts) {
return -1;
}
return 0;
}
-void do_device_del(Monitor *mon, const QDict *qdict)
+int do_device_del(Monitor *mon, const QDict *qdict, QObject **ret_data)
{
const char *id = qdict_get_str(qdict, "id");
DeviceState *dev;
dev = qdev_find_recursive(main_system_bus, id);
if (NULL == dev) {
- error_report("Device '%s' not found", id);
- return;
+ qerror_report(QERR_DEVICE_NOT_FOUND, id);
+ return -1;
+ }
+ return qdev_unplug(dev);
+}
+
+static int qdev_get_fw_dev_path_helper(DeviceState *dev, char *p, int size)
+{
+ int l = 0;
+
+ if (dev && dev->parent_bus) {
+ char *d;
+ l = qdev_get_fw_dev_path_helper(dev->parent_bus->parent, p, size);
+ if (dev->parent_bus->info->get_fw_dev_path) {
+ d = dev->parent_bus->info->get_fw_dev_path(dev);
+ l += snprintf(p + l, size - l, "%s", d);
+ qemu_free(d);
+ } else {
+ l += snprintf(p + l, size - l, "%s", dev->info->name);
+ }
}
- qdev_unplug(dev);
+ l += snprintf(p + l , size - l, "/");
+
+ return l;
+}
+
+char* qdev_get_fw_dev_path(DeviceState *dev)
+{
+ char path[128];
+ int l;
+
+ l = qdev_get_fw_dev_path_helper(dev, path, 128);
+
+ path[l-1] = '\0';
+
+ return strdup(path);
}