#include "net.h"
#include "qdev.h"
#include "sysemu.h"
-#include "monitor.h"
-static int qdev_hotplug = 0;
+int qdev_hotplug = 0;
static bool qdev_hot_added = false;
static bool qdev_hot_removed = false;
/* This is a nasty hack to allow passing a NULL bus to qdev_create. */
static BusState *main_system_bus;
-
-DeviceInfo *device_info_list;
-
-static BusState *qbus_find_recursive(BusState *bus, const char *name,
- const BusInfo *info);
-static BusState *qbus_find(const char *path);
+static void main_system_bus_create(void);
/* Register a new device type. */
-void qdev_register(DeviceInfo *info)
+const VMStateDescription *qdev_get_vmsd(DeviceState *dev)
{
- assert(info->size >= sizeof(DeviceState));
- assert(!info->next);
-
- info->next = device_info_list;
- device_info_list = info;
+ DeviceClass *dc = DEVICE_GET_CLASS(dev);
+ return dc->vmsd;
}
-static DeviceInfo *qdev_find_info(BusInfo *bus_info, const char *name)
+BusInfo *qdev_get_bus_info(DeviceState *dev)
{
- DeviceInfo *info;
-
- /* first check device names */
- for (info = device_info_list; info != NULL; info = info->next) {
- if (bus_info && info->bus_info != bus_info)
- continue;
- if (strcmp(info->name, name) != 0)
- continue;
- return info;
- }
-
- /* failing that check the aliases */
- for (info = device_info_list; info != NULL; info = info->next) {
- if (bus_info && info->bus_info != bus_info)
- continue;
- if (!info->alias)
- continue;
- if (strcmp(info->alias, name) != 0)
- continue;
- return info;
- }
- return NULL;
+ DeviceClass *dc = DEVICE_GET_CLASS(dev);
+ return dc->bus_info;
}
-static DeviceState *qdev_create_from_info(BusState *bus, DeviceInfo *info)
+Property *qdev_get_props(DeviceState *dev)
{
- DeviceState *dev;
-
- assert(bus->info == info->bus_info);
- dev = qemu_mallocz(info->size);
- dev->info = info;
- dev->parent_bus = bus;
- qdev_prop_set_defaults(dev, dev->info->props);
- qdev_prop_set_defaults(dev, dev->parent_bus->info->props);
- qdev_prop_set_globals(dev);
- QLIST_INSERT_HEAD(&bus->children, dev, sibling);
- if (qdev_hotplug) {
- assert(bus->allow_hotplug);
- dev->hotplugged = 1;
- qdev_hot_added = true;
- }
- dev->instance_id_alias = -1;
- dev->state = DEV_STATE_CREATED;
- return dev;
+ DeviceClass *dc = DEVICE_GET_CLASS(dev);
+ return dc->props;
}
-/* Create a new device. This only initializes the device state structure
- and allows properties to be set. qdev_init should be called to
- initialize the actual device emulation. */
-DeviceState *qdev_create(BusState *bus, const char *name)
+const char *qdev_fw_name(DeviceState *dev)
{
- DeviceState *dev;
+ DeviceClass *dc = DEVICE_GET_CLASS(dev);
- dev = qdev_try_create(bus, name);
- if (!dev) {
- hw_error("Unknown device '%s' for bus '%s'\n", name, bus->info->name);
+ if (dc->fw_name) {
+ return dc->fw_name;
}
- return dev;
+ return object_get_typename(OBJECT(dev));
}
-DeviceState *qdev_try_create(BusState *bus, const char *name)
+bool qdev_exists(const char *name)
{
- DeviceInfo *info;
-
- if (!bus) {
- bus = sysbus_get_default();
- }
-
- info = qdev_find_info(bus->info, name);
- if (!info) {
- return NULL;
- }
-
- return qdev_create_from_info(bus, info);
+ return !!object_class_by_name(name);
}
-static void qdev_print_devinfo(DeviceInfo *info)
-{
- error_printf("name \"%s\", bus %s",
- info->name, info->bus_info->name);
- if (info->alias) {
- error_printf(", alias \"%s\"", info->alias);
- }
- if (info->desc) {
- error_printf(", desc \"%s\"", info->desc);
- }
- if (info->no_user) {
- error_printf(", no-user");
- }
- error_printf("\n");
-}
+static void qdev_property_add_legacy(DeviceState *dev, Property *prop,
+ Error **errp);
-static int set_property(const char *name, const char *value, void *opaque)
+void qdev_set_parent_bus(DeviceState *dev, BusState *bus)
{
- DeviceState *dev = opaque;
+ Property *prop;
- if (strcmp(name, "driver") == 0)
- return 0;
- if (strcmp(name, "bus") == 0)
- return 0;
+ if (qdev_hotplug) {
+ assert(bus->allow_hotplug);
+ }
- if (qdev_prop_parse(dev, name, value) == -1) {
- return -1;
+ dev->parent_bus = bus;
+ QTAILQ_INSERT_HEAD(&bus->children, dev, sibling);
+
+ for (prop = qdev_get_bus_info(dev)->props; prop && prop->name; prop++) {
+ qdev_property_add_legacy(dev, prop, NULL);
+ qdev_property_add_static(dev, prop, NULL);
}
- return 0;
+ qdev_prop_set_defaults(dev, dev->parent_bus->info->props);
}
-int qdev_device_help(QemuOpts *opts)
+/* Create a new device. This only initializes the device state structure
+ and allows properties to be set. qdev_init should be called to
+ initialize the actual device emulation. */
+DeviceState *qdev_create(BusState *bus, const char *name)
{
- const char *driver;
- DeviceInfo *info;
- Property *prop;
+ DeviceState *dev;
- driver = qemu_opt_get(opts, "driver");
- if (driver && !strcmp(driver, "?")) {
- for (info = device_info_list; info != NULL; info = info->next) {
- if (info->no_user) {
- continue; /* not available, don't show */
- }
- qdev_print_devinfo(info);
+ dev = qdev_try_create(bus, name);
+ if (!dev) {
+ if (bus) {
+ hw_error("Unknown device '%s' for bus '%s'\n", name,
+ bus->info->name);
+ } else {
+ hw_error("Unknown device '%s' for default sysbus\n", name);
}
- return 1;
- }
-
- if (!qemu_opt_get(opts, "?")) {
- return 0;
- }
-
- info = qdev_find_info(NULL, driver);
- if (!info) {
- return 0;
}
- for (prop = info->props; prop && prop->name; prop++) {
- /*
- * TODO Properties without a parser are just for dirty hacks.
- * qdev_prop_ptr is the only such PropertyInfo. It's marked
- * for removal. This conditional should be removed along with
- * it.
- */
- if (!prop->info->parse) {
- continue; /* no way to set it, don't show */
- }
- error_printf("%s.%s=%s\n", info->name, prop->name, prop->info->name);
- }
- return 1;
+ return dev;
}
-DeviceState *qdev_device_add(QemuOpts *opts)
+DeviceState *qdev_try_create(BusState *bus, const char *name)
{
- const char *driver, *path, *id;
- DeviceInfo *info;
- DeviceState *qdev;
- BusState *bus;
+ DeviceState *dev;
- driver = qemu_opt_get(opts, "driver");
- if (!driver) {
- qerror_report(QERR_MISSING_PARAMETER, "driver");
+ dev = DEVICE(object_new(name));
+ if (!dev) {
return NULL;
}
- /* find driver */
- info = qdev_find_info(NULL, driver);
- if (!info || info->no_user) {
- qerror_report(QERR_INVALID_PARAMETER_VALUE, "driver", "a driver name");
- error_printf_unless_qmp("Try with argument '?' for a list.\n");
- return NULL;
+ if (!bus) {
+ bus = sysbus_get_default();
}
- /* find bus */
- path = qemu_opt_get(opts, "bus");
- if (path != NULL) {
- bus = qbus_find(path);
- if (!bus) {
- return NULL;
- }
- if (bus->info != info->bus_info) {
- qerror_report(QERR_BAD_BUS_FOR_DEVICE,
- driver, bus->info->name);
- return NULL;
- }
- } else {
- bus = qbus_find_recursive(main_system_bus, NULL, info->bus_info);
- if (!bus) {
- qerror_report(QERR_NO_BUS_FOR_DEVICE,
- info->name, info->bus_info->name);
- return NULL;
- }
- }
- if (qdev_hotplug && !bus->allow_hotplug) {
- qerror_report(QERR_BUS_NO_HOTPLUG, bus->name);
- return NULL;
- }
+ qdev_set_parent_bus(dev, bus);
+ qdev_prop_set_globals(dev);
- /* create device, set properties */
- qdev = qdev_create_from_info(bus, info);
- id = qemu_opts_id(opts);
- if (id) {
- qdev->id = id;
- }
- if (qemu_opt_foreach(opts, set_property, qdev, 1) != 0) {
- qdev_free(qdev);
- return NULL;
- }
- if (qdev_init(qdev) < 0) {
- qerror_report(QERR_DEVICE_INIT_FAILED, driver);
- return NULL;
- }
- qdev->opts = opts;
- return qdev;
+ return dev;
}
/* Initialize a device. Device properties should be set before calling
Return 0 on success. */
int qdev_init(DeviceState *dev)
{
+ DeviceClass *dc = DEVICE_GET_CLASS(dev);
int rc;
assert(dev->state == DEV_STATE_CREATED);
- rc = dev->info->init(dev, dev->info);
+
+ rc = dc->init(dev);
if (rc < 0) {
qdev_free(dev);
return rc;
}
- if (dev->info->vmsd) {
- vmstate_register_with_alias_id(dev, -1, dev->info->vmsd, dev,
+ if (qdev_get_vmsd(dev)) {
+ vmstate_register_with_alias_id(dev, -1, qdev_get_vmsd(dev), dev,
dev->instance_id_alias,
dev->alias_required_for_version);
}
dev->state = DEV_STATE_INITIALIZED;
+ if (dev->hotplugged) {
+ device_reset(dev);
+ }
return 0;
}
int qdev_unplug(DeviceState *dev)
{
+ DeviceClass *dc = DEVICE_GET_CLASS(dev);
+
if (!dev->parent_bus->allow_hotplug) {
qerror_report(QERR_BUS_NO_HOTPLUG, dev->parent_bus->name);
return -1;
}
- assert(dev->info->unplug != NULL);
+ assert(dc->unplug != NULL);
qdev_hot_removed = true;
- return dev->info->unplug(dev);
+ return dc->unplug(dev);
}
static int qdev_reset_one(DeviceState *dev, void *opaque)
{
- if (dev->info->reset) {
- dev->info->reset(dev);
- }
+ device_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");
+ main_system_bus_create();
}
return main_system_bus;
}
int qdev_simple_unplug_cb(DeviceState *dev)
{
/* just zap it */
+ object_unparent(OBJECT(dev));
qdev_free(dev);
return 0;
}
way is somewhat unclean, and best avoided. */
void qdev_init_nofail(DeviceState *dev)
{
- DeviceInfo *info = dev->info;
-
if (qdev_init(dev) < 0) {
- error_report("Initialization of device %s failed\n", info->name);
+ error_report("Initialization of device %s failed",
+ object_get_typename(OBJECT(dev)));
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) {
- bus = QLIST_FIRST(&dev->child_bus);
- qbus_free(bus);
- }
- if (dev->info->vmsd)
- vmstate_unregister(dev, dev->info->vmsd, dev);
- if (dev->info->exit)
- dev->info->exit(dev);
- if (dev->opts)
- qemu_opts_del(dev->opts);
- }
- 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);
+ object_delete(OBJECT(dev));
}
void qdev_machine_creation_done(void)
return qdev_hot_added || qdev_hot_removed;
}
-/* Get a character (serial) device interface. */
-CharDriverState *qdev_init_chardev(DeviceState *dev)
-{
- static int next_serial;
-
- /* FIXME: This function needs to go away: use chardev properties! */
- return serial_hds[next_serial++];
-}
-
BusState *qdev_get_parent_bus(DeviceState *dev)
{
return dev->parent_bus;
void qdev_set_nic_properties(DeviceState *dev, NICInfo *nd)
{
- qdev_prop_set_macaddr(dev, "mac", nd->macaddr);
+ qdev_prop_set_macaddr(dev, "mac", nd->macaddr.a);
if (nd->vlan)
qdev_prop_set_vlan(dev, "vlan", nd->vlan);
if (nd->netdev)
}
}
- QLIST_FOREACH(dev, &bus->children, sibling) {
+ QTAILQ_FOREACH(dev, &bus->children, sibling) {
err = qdev_walk_children(dev, devfn, busfn, opaque);
if (err < 0) {
return err;
return 0;
}
-static BusState *qbus_find_recursive(BusState *bus, const char *name,
- const BusInfo *info)
-{
- DeviceState *dev;
- BusState *child, *ret;
- int match = 1;
-
- if (name && (strcmp(bus->name, name) != 0)) {
- match = 0;
- }
- if (info && (bus->info != info)) {
- match = 0;
- }
- if (match) {
- return bus;
- }
-
- QLIST_FOREACH(dev, &bus->children, sibling) {
- QLIST_FOREACH(child, &dev->child_bus, sibling) {
- ret = qbus_find_recursive(child, name, info);
- if (ret) {
- return ret;
- }
- }
- }
- return NULL;
-}
-
DeviceState *qdev_find_recursive(BusState *bus, const char *id)
{
DeviceState *dev, *ret;
BusState *child;
- QLIST_FOREACH(dev, &bus->children, sibling) {
+ QTAILQ_FOREACH(dev, &bus->children, sibling) {
if (dev->id && strcmp(dev->id, id) == 0)
return dev;
QLIST_FOREACH(child, &dev->child_bus, sibling) {
return NULL;
}
-static void qbus_list_bus(DeviceState *dev)
-{
- BusState *child;
- const char *sep = " ";
-
- error_printf("child busses at \"%s\":",
- dev->id ? dev->id : dev->info->name);
- QLIST_FOREACH(child, &dev->child_bus, sibling) {
- error_printf("%s\"%s\"", sep, child->name);
- sep = ", ";
- }
- error_printf("\n");
-}
-
-static void qbus_list_dev(BusState *bus)
-{
- DeviceState *dev;
- const char *sep = " ";
-
- error_printf("devices at \"%s\":", bus->name);
- QLIST_FOREACH(dev, &bus->children, sibling) {
- error_printf("%s\"%s\"", sep, dev->info->name);
- if (dev->id)
- error_printf("/\"%s\"", dev->id);
- sep = ", ";
- }
- error_printf("\n");
-}
-
-static BusState *qbus_find_bus(DeviceState *dev, char *elem)
-{
- BusState *child;
-
- QLIST_FOREACH(child, &dev->child_bus, sibling) {
- if (strcmp(child->name, elem) == 0) {
- return child;
- }
- }
- return NULL;
-}
-
-static DeviceState *qbus_find_dev(BusState *bus, char *elem)
-{
- DeviceState *dev;
-
- /*
- * try to match in order:
- * (1) instance id, if present
- * (2) driver name
- * (3) driver alias, if present
- */
- QLIST_FOREACH(dev, &bus->children, sibling) {
- if (dev->id && strcmp(dev->id, elem) == 0) {
- return dev;
- }
- }
- QLIST_FOREACH(dev, &bus->children, sibling) {
- if (strcmp(dev->info->name, elem) == 0) {
- return dev;
- }
- }
- QLIST_FOREACH(dev, &bus->children, sibling) {
- if (dev->info->alias && strcmp(dev->info->alias, elem) == 0) {
- return dev;
- }
- }
- return NULL;
-}
-
-static BusState *qbus_find(const char *path)
-{
- DeviceState *dev;
- BusState *bus;
- char elem[128];
- int pos, len;
-
- /* find start element */
- if (path[0] == '/') {
- bus = main_system_bus;
- pos = 0;
- } else {
- if (sscanf(path, "%127[^/]%n", elem, &len) != 1) {
- assert(!path[0]);
- elem[0] = len = 0;
- }
- bus = qbus_find_recursive(main_system_bus, elem, NULL);
- if (!bus) {
- qerror_report(QERR_BUS_NOT_FOUND, elem);
- return NULL;
- }
- pos = len;
- }
-
- for (;;) {
- assert(path[pos] == '/' || !path[pos]);
- while (path[pos] == '/') {
- pos++;
- }
- if (path[pos] == '\0') {
- return bus;
- }
-
- /* find device */
- if (sscanf(path+pos, "%127[^/]%n", elem, &len) != 1) {
- assert(0);
- elem[0] = len = 0;
- }
- pos += len;
- dev = qbus_find_dev(bus, elem);
- if (!dev) {
- qerror_report(QERR_DEVICE_NOT_FOUND, elem);
- if (!monitor_cur_is_qmp()) {
- qbus_list_dev(bus);
- }
- return NULL;
- }
-
- assert(path[pos] == '/' || !path[pos]);
- while (path[pos] == '/') {
- pos++;
- }
- if (path[pos] == '\0') {
- /* last specified element is a device. If it has exactly
- * one child bus accept it nevertheless */
- switch (dev->num_child_bus) {
- case 0:
- qerror_report(QERR_DEVICE_NO_BUS, elem);
- return NULL;
- case 1:
- return QLIST_FIRST(&dev->child_bus);
- default:
- qerror_report(QERR_DEVICE_MULTIPLE_BUSSES, elem);
- if (!monitor_cur_is_qmp()) {
- qbus_list_bus(dev);
- }
- return NULL;
- }
- }
-
- /* find bus */
- if (sscanf(path+pos, "%127[^/]%n", elem, &len) != 1) {
- assert(0);
- elem[0] = len = 0;
- }
- pos += len;
- bus = qbus_find_bus(dev, elem);
- if (!bus) {
- qerror_report(QERR_BUS_NOT_FOUND, elem);
- if (!monitor_cur_is_qmp()) {
- qbus_list_bus(dev);
- }
- return NULL;
- }
- }
-}
-
void qbus_create_inplace(BusState *bus, BusInfo *info,
DeviceState *parent, const char *name)
{
if (name) {
/* use supplied name */
- bus->name = qemu_strdup(name);
+ bus->name = g_strdup(name);
} else if (parent && parent->id) {
/* parent device has id -> use it for bus name */
len = strlen(parent->id) + 16;
- buf = qemu_malloc(len);
+ buf = g_malloc(len);
snprintf(buf, len, "%s.%d", parent->id, parent->num_child_bus);
bus->name = buf;
} else {
/* no id -> use lowercase bus type for bus name */
len = strlen(info->name) + 16;
- buf = qemu_malloc(len);
+ buf = g_malloc(len);
len = snprintf(buf, len, "%s.%d", info->name,
parent ? parent->num_child_bus : 0);
for (i = 0; i < len; i++)
bus->name = buf;
}
- QLIST_INIT(&bus->children);
+ QTAILQ_INIT(&bus->children);
if (parent) {
QLIST_INSERT_HEAD(&parent->child_bus, bus, sibling);
parent->num_child_bus++;
{
BusState *bus;
- bus = qemu_mallocz(info->size);
+ bus = g_malloc0(info->size);
bus->qdev_allocated = 1;
qbus_create_inplace(bus, info, parent, name);
return bus;
}
+static void main_system_bus_create(void)
+{
+ /* assign main_system_bus before qbus_create_inplace()
+ * in order to make "if (bus != main_system_bus)" work */
+ main_system_bus = g_malloc0(system_bus_info.size);
+ main_system_bus->qdev_allocated = 1;
+ qbus_create_inplace(main_system_bus, &system_bus_info, NULL,
+ "main-system-bus");
+}
+
void qbus_free(BusState *bus)
{
DeviceState *dev;
- while ((dev = QLIST_FIRST(&bus->children)) != NULL) {
+ while ((dev = QTAILQ_FIRST(&bus->children)) != NULL) {
qdev_free(dev);
}
if (bus->parent) {
assert(bus != main_system_bus); /* main_system_bus is never freed */
qemu_unregister_reset(qbus_reset_all_fn, bus);
}
- qemu_free((void*)bus->name);
+ g_free((void*)bus->name);
if (bus->qdev_allocated) {
- qemu_free(bus);
+ g_free(bus);
}
}
-#define qdev_printf(fmt, ...) monitor_printf(mon, "%*s" fmt, indent, "", ## __VA_ARGS__)
-static void qbus_print(Monitor *mon, BusState *bus, int indent);
-
-static void qdev_print_props(Monitor *mon, DeviceState *dev, Property *props,
- const char *prefix, int indent)
+static int qdev_get_fw_dev_path_helper(DeviceState *dev, char *p, int size)
{
- char buf[64];
+ int l = 0;
- if (!props)
- return;
- while (props->name) {
- /*
- * TODO Properties without a print method are just for dirty
- * hacks. qdev_prop_ptr is the only such PropertyInfo. It's
- * marked for removal. The test props->info->print should be
- * removed along with it.
- */
- if (props->info->print) {
- props->info->print(dev, props, buf, sizeof(buf));
- qdev_printf("%s-prop: %s = %s\n", prefix, props->name, buf);
+ 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);
+ g_free(d);
+ } else {
+ l += snprintf(p + l, size - l, "%s", object_get_typename(OBJECT(dev)));
}
- props++;
}
+ l += snprintf(p + l , size - l, "/");
+
+ return l;
}
-static void qdev_print(Monitor *mon, DeviceState *dev, int indent)
+char* qdev_get_fw_dev_path(DeviceState *dev)
{
- BusState *child;
- qdev_printf("dev: %s, id \"%s\"\n", dev->info->name,
- dev->id ? dev->id : "");
- indent += 2;
- if (dev->num_gpio_in) {
- qdev_printf("gpio-in %d\n", dev->num_gpio_in);
- }
- if (dev->num_gpio_out) {
- qdev_printf("gpio-out %d\n", dev->num_gpio_out);
- }
- qdev_print_props(mon, dev, dev->info->props, "dev", indent);
- qdev_print_props(mon, dev, dev->parent_bus->info->props, "bus", indent);
- if (dev->parent_bus->info->print_dev)
- dev->parent_bus->info->print_dev(mon, dev, indent);
- QLIST_FOREACH(child, &dev->child_bus, sibling) {
- qbus_print(mon, child, indent);
- }
+ char path[128];
+ int l;
+
+ l = qdev_get_fw_dev_path_helper(dev, path, 128);
+
+ path[l-1] = '\0';
+
+ return strdup(path);
}
-static void qbus_print(Monitor *mon, BusState *bus, int indent)
+static char *qdev_get_type(Object *obj, Error **errp)
{
- struct DeviceState *dev;
-
- qdev_printf("bus: %s\n", bus->name);
- indent += 2;
- qdev_printf("type %s\n", bus->info->name);
- QLIST_FOREACH(dev, &bus->children, sibling) {
- qdev_print(mon, dev, indent);
- }
+ return g_strdup(object_get_typename(obj));
}
-#undef qdev_printf
-void do_info_qtree(Monitor *mon)
+/**
+ * Legacy property handling
+ */
+
+static void qdev_get_legacy_property(Object *obj, Visitor *v, void *opaque,
+ const char *name, Error **errp)
{
- if (main_system_bus)
- qbus_print(mon, main_system_bus, 0);
+ DeviceState *dev = DEVICE(obj);
+ Property *prop = opaque;
+
+ char buffer[1024];
+ char *ptr = buffer;
+
+ prop->info->print(dev, prop, buffer, sizeof(buffer));
+ visit_type_str(v, &ptr, name, errp);
}
-void do_info_qdm(Monitor *mon)
+static void qdev_set_legacy_property(Object *obj, Visitor *v, void *opaque,
+ const char *name, Error **errp)
{
- DeviceInfo *info;
+ DeviceState *dev = DEVICE(obj);
+ Property *prop = opaque;
+ Error *local_err = NULL;
+ char *ptr = NULL;
+ int ret;
- for (info = device_info_list; info != NULL; info = info->next) {
- qdev_print_devinfo(info);
+ if (dev->state != DEV_STATE_CREATED) {
+ error_set(errp, QERR_PERMISSION_DENIED);
+ return;
}
+
+ visit_type_str(v, &ptr, name, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
+
+ ret = prop->info->parse(dev, prop, ptr);
+ error_set_from_qdev_prop_error(errp, ret, dev, prop, ptr);
+ g_free(ptr);
}
-int do_device_add(Monitor *mon, const QDict *qdict, QObject **ret_data)
+/**
+ * @qdev_add_legacy_property - adds a legacy property
+ *
+ * Do not use this is new code! Properties added through this interface will
+ * be given names and types in the "legacy" namespace.
+ *
+ * Legacy properties are string versions of other OOM properties. The format
+ * of the string depends on the property type.
+ */
+void qdev_property_add_legacy(DeviceState *dev, Property *prop,
+ Error **errp)
{
- QemuOpts *opts;
+ gchar *name, *type;
- opts = qemu_opts_from_qdict(qemu_find_opts("device"), qdict);
- if (!opts) {
- return -1;
- }
- if (!monitor_cur_is_qmp() && qdev_device_help(opts)) {
- qemu_opts_del(opts);
- return 0;
+ if (!prop->info->print && !prop->info->parse) {
+ return;
}
- if (!qdev_device_add(opts)) {
- qemu_opts_del(opts);
- return -1;
+ name = g_strdup_printf("legacy-%s", prop->name);
+ type = g_strdup_printf("legacy<%s>",
+ prop->info->legacy_name ?: prop->info->name);
+
+ object_property_add(OBJECT(dev), name, type,
+ prop->info->print ? qdev_get_legacy_property : prop->info->get,
+ prop->info->parse ? qdev_set_legacy_property : prop->info->set,
+ NULL,
+ prop, errp);
+
+ g_free(type);
+ g_free(name);
+}
+
+/**
+ * @qdev_property_add_static - add a @Property to a device.
+ *
+ * Static properties access data in a struct. The actual type of the
+ * property and the field depends on the property type.
+ */
+void qdev_property_add_static(DeviceState *dev, Property *prop,
+ Error **errp)
+{
+ /*
+ * TODO qdev_prop_ptr does not have getters or setters. It must
+ * go now that it can be replaced with links. The test should be
+ * removed along with it: all static properties are read/write.
+ */
+ if (!prop->info->get && !prop->info->set) {
+ return;
}
- return 0;
+
+ object_property_add(OBJECT(dev), prop->name, prop->info->name,
+ prop->info->get, prop->info->set,
+ prop->info->release,
+ prop, errp);
}
-int do_device_del(Monitor *mon, const QDict *qdict, QObject **ret_data)
+static void device_initfn(Object *obj)
{
- const char *id = qdict_get_str(qdict, "id");
- DeviceState *dev;
+ DeviceState *dev = DEVICE(obj);
+ Property *prop;
- dev = qdev_find_recursive(main_system_bus, id);
- if (NULL == dev) {
- qerror_report(QERR_DEVICE_NOT_FOUND, id);
- return -1;
+ if (qdev_hotplug) {
+ dev->hotplugged = 1;
+ qdev_hot_added = true;
}
- return qdev_unplug(dev);
+
+ dev->instance_id_alias = -1;
+ dev->state = DEV_STATE_CREATED;
+
+ for (prop = qdev_get_props(dev); prop && prop->name; prop++) {
+ qdev_property_add_legacy(dev, prop, NULL);
+ qdev_property_add_static(dev, prop, NULL);
+ }
+
+ object_property_add_str(OBJECT(dev), "type", qdev_get_type, NULL, NULL);
+ qdev_prop_set_defaults(dev, qdev_get_props(dev));
}
-static int qdev_get_fw_dev_path_helper(DeviceState *dev, char *p, int size)
+/* Unlink device from bus and free the structure. */
+static void device_finalize(Object *obj)
{
- int l = 0;
+ DeviceState *dev = DEVICE(obj);
+ BusState *bus;
+ DeviceClass *dc = DEVICE_GET_CLASS(dev);
- 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);
+ if (dev->state == DEV_STATE_INITIALIZED) {
+ while (dev->num_child_bus) {
+ bus = QLIST_FIRST(&dev->child_bus);
+ qbus_free(bus);
+ }
+ if (qdev_get_vmsd(dev)) {
+ vmstate_unregister(dev, qdev_get_vmsd(dev), dev);
+ }
+ if (dc->exit) {
+ dc->exit(dev);
+ }
+ if (dev->opts) {
+ qemu_opts_del(dev->opts);
}
}
- l += snprintf(p + l , size - l, "/");
-
- return l;
+ QTAILQ_REMOVE(&dev->parent_bus->children, dev, sibling);
}
-char* qdev_get_fw_dev_path(DeviceState *dev)
+void device_reset(DeviceState *dev)
{
- char path[128];
- int l;
+ DeviceClass *klass = DEVICE_GET_CLASS(dev);
- l = qdev_get_fw_dev_path_helper(dev, path, 128);
+ if (klass->reset) {
+ klass->reset(dev);
+ }
+}
- path[l-1] = '\0';
+static TypeInfo device_type_info = {
+ .name = TYPE_DEVICE,
+ .parent = TYPE_OBJECT,
+ .instance_size = sizeof(DeviceState),
+ .instance_init = device_initfn,
+ .instance_finalize = device_finalize,
+ .abstract = true,
+ .class_size = sizeof(DeviceClass),
+};
- return strdup(path);
+static void qdev_register_types(void)
+{
+ type_register_static(&device_type_info);
}
+
+type_init(qdev_register_types)