#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;
static BusState *main_system_bus;
static void main_system_bus_create(void);
-DeviceInfo *device_info_list;
-
-static BusState *qbus_find_recursive(BusState *bus, const char *name,
- const BusInfo *info);
-static BusState *qbus_find(const char *path);
-
/* 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);
+ DeviceClass *dc = DEVICE_GET_CLASS(dev);
+ return dc->vmsd;
+}
- info->next = device_info_list;
- device_info_list = info;
+BusInfo *qdev_get_bus_info(DeviceState *dev)
+{
+ DeviceClass *dc = DEVICE_GET_CLASS(dev);
+ return dc->bus_info;
}
-static DeviceInfo *qdev_find_info(BusInfo *bus_info, const char *name)
+Property *qdev_get_props(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;
- }
+ DeviceClass *dc = DEVICE_GET_CLASS(dev);
+ return dc->props;
+}
- /* 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;
+const char *qdev_fw_name(DeviceState *dev)
+{
+ DeviceClass *dc = DEVICE_GET_CLASS(dev);
+
+ if (dc->fw_name) {
+ return dc->fw_name;
}
- return NULL;
+
+ return object_get_typename(OBJECT(dev));
}
-static DeviceState *qdev_create_from_info(BusState *bus, DeviceInfo *info)
+bool qdev_exists(const char *name)
+{
+ return !!object_class_by_name(name);
+}
+
+static void qdev_property_add_legacy(DeviceState *dev, Property *prop,
+ Error **errp);
+
+void qdev_set_parent_bus(DeviceState *dev, BusState *bus)
{
- DeviceState *dev;
Property *prop;
- assert(bus->info == info->bus_info);
- dev = g_malloc0(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);
- QTAILQ_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;
- QTAILQ_INIT(&dev->properties);
- dev->state = DEV_STATE_CREATED;
- for (prop = dev->info->props; prop && prop->name; prop++) {
- qdev_property_add_legacy(dev, prop, NULL);
- }
+ dev->parent_bus = bus;
+ QTAILQ_INSERT_HEAD(&bus->children, dev, sibling);
- for (prop = dev->info->bus_info->props; prop && prop->name; prop++) {
+ 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 dev;
+ qdev_prop_set_defaults(dev, dev->parent_bus->info->props);
}
/* Create a new device. This only initializes the device state structure
DeviceState *qdev_try_create(BusState *bus, const char *name)
{
- DeviceInfo *info;
-
- if (!bus) {
- bus = sysbus_get_default();
- }
+ DeviceState *dev;
- info = qdev_find_info(bus->info, name);
- if (!info) {
+ if (object_class_by_name(name) == NULL) {
return NULL;
}
-
- return qdev_create_from_info(bus, info);
-}
-
-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 int set_property(const char *name, const char *value, void *opaque)
-{
- DeviceState *dev = opaque;
-
- if (strcmp(name, "driver") == 0)
- return 0;
- if (strcmp(name, "bus") == 0)
- return 0;
-
- if (qdev_prop_parse(dev, name, value) == -1) {
- return -1;
- }
- return 0;
-}
-
-int qdev_device_help(QemuOpts *opts)
-{
- const char *driver;
- DeviceInfo *info;
- Property *prop;
-
- 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);
- }
- return 1;
- }
-
- if (!driver || !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);
- }
- for (prop = info->bus_info->props; prop && prop->name; prop++) {
- 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;
-}
-
-DeviceState *qdev_device_add(QemuOpts *opts)
-{
- const char *driver, *path, *id;
- DeviceInfo *info;
- DeviceState *qdev;
- BusState *bus;
-
- 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 && dev->info->reset) {
- dev->info->reset(dev);
+ 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);
-
- if (dev->ref != 0) {
- qerror_report(QERR_DEVICE_IN_USE, dev->id?:"");
- return -1;
- }
+ 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;
}
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", info->name);
+ error_report("Initialization of device %s failed",
+ object_get_typename(OBJECT(dev)));
exit(1);
}
}
-static void qdev_property_del_all(DeviceState *dev)
-{
- while (!QTAILQ_EMPTY(&dev->properties)) {
- DeviceProperty *prop = QTAILQ_FIRST(&dev->properties);
-
- QTAILQ_REMOVE(&dev->properties, prop, node);
-
- if (prop->release) {
- prop->release(dev, prop->name, prop->opaque);
- }
-
- g_free(prop->name);
- g_free(prop->type);
- g_free(prop);
- }
-}
-
/* Unlink device from bus and free the structure. */
void qdev_free(DeviceState *dev)
{
- BusState *bus;
- Property *prop;
-
- qdev_property_del_all(dev);
-
- 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);
- }
- QTAILQ_REMOVE(&dev->parent_bus->children, dev, sibling);
- for (prop = dev->info->props; prop && prop->name; prop++) {
- if (prop->info->free) {
- prop->info->free(dev, prop);
- }
- }
- g_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;
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;
- }
-
- QTAILQ_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;
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);
- QTAILQ_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
- */
- QTAILQ_FOREACH(dev, &bus->children, sibling) {
- if (dev->id && strcmp(dev->id, elem) == 0) {
- return dev;
- }
- }
- QTAILQ_FOREACH(dev, &bus->children, sibling) {
- if (strcmp(dev->info->name, elem) == 0) {
- return dev;
- }
- }
- QTAILQ_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)
{
}
}
-#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)
-{
- char buf[64];
-
- 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);
- }
- props++;
- }
-}
-
-static void qdev_print(Monitor *mon, DeviceState *dev, int indent)
-{
- 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);
- }
-}
-
-static void qbus_print(Monitor *mon, BusState *bus, int indent)
-{
- struct DeviceState *dev;
-
- qdev_printf("bus: %s\n", bus->name);
- indent += 2;
- qdev_printf("type %s\n", bus->info->name);
- QTAILQ_FOREACH(dev, &bus->children, sibling) {
- qdev_print(mon, dev, indent);
- }
-}
-#undef qdev_printf
-
-void do_info_qtree(Monitor *mon)
-{
- if (main_system_bus)
- qbus_print(mon, main_system_bus, 0);
-}
-
-void do_info_qdm(Monitor *mon)
-{
- DeviceInfo *info;
-
- for (info = device_info_list; info != NULL; info = info->next) {
- qdev_print_devinfo(info);
- }
-}
-
-int do_device_add(Monitor *mon, const QDict *qdict, QObject **ret_data)
-{
- QemuOpts *opts;
-
- 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 (!qdev_device_add(opts)) {
- qemu_opts_del(opts);
- return -1;
- }
- return 0;
-}
-
-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) {
- 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;
l += snprintf(p + l, size - l, "%s", d);
g_free(d);
} else {
- l += snprintf(p + l, size - l, "%s", dev->info->name);
+ l += snprintf(p + l, size - l, "%s", object_get_typename(OBJECT(dev)));
}
}
l += snprintf(p + l , size - l, "/");
return strdup(path);
}
-void qdev_ref(DeviceState *dev)
-{
- dev->ref++;
-}
-
-void qdev_unref(DeviceState *dev)
-{
- g_assert(dev->ref > 0);
- dev->ref--;
-}
-
-void qdev_property_add(DeviceState *dev, const char *name, const char *type,
- DevicePropertyAccessor *get, DevicePropertyAccessor *set,
- DevicePropertyRelease *release,
- void *opaque, Error **errp)
-{
- DeviceProperty *prop = g_malloc0(sizeof(*prop));
-
- prop->name = g_strdup(name);
- prop->type = g_strdup(type);
-
- prop->get = get;
- prop->set = set;
- prop->release = release;
- prop->opaque = opaque;
-
- QTAILQ_INSERT_TAIL(&dev->properties, prop, node);
-}
-
-static DeviceProperty *qdev_property_find(DeviceState *dev, const char *name)
-{
- DeviceProperty *prop;
-
- QTAILQ_FOREACH(prop, &dev->properties, node) {
- if (strcmp(prop->name, name) == 0) {
- return prop;
- }
- }
-
- return NULL;
-}
-
-void qdev_property_get(DeviceState *dev, Visitor *v, const char *name,
- Error **errp)
-{
- DeviceProperty *prop = qdev_property_find(dev, name);
-
- if (prop == NULL) {
- error_set(errp, QERR_PROPERTY_NOT_FOUND, dev->id?:"", name);
- return;
- }
-
- if (!prop->get) {
- error_set(errp, QERR_PERMISSION_DENIED);
- } else {
- prop->get(dev, v, prop->opaque, name, errp);
- }
-}
-
-void qdev_property_set(DeviceState *dev, Visitor *v, const char *name,
- Error **errp)
-{
- DeviceProperty *prop = qdev_property_find(dev, name);
-
- if (prop == NULL) {
- error_set(errp, QERR_PROPERTY_NOT_FOUND, dev->id?:"", name);
- return;
- }
-
- if (!prop->set) {
- error_set(errp, QERR_PERMISSION_DENIED);
- } else {
- prop->set(dev, prop->opaque, v, name, errp);
- }
-}
-
-const char *qdev_property_get_type(DeviceState *dev, const char *name, Error **errp)
+static char *qdev_get_type(Object *obj, Error **errp)
{
- DeviceProperty *prop = qdev_property_find(dev, name);
-
- if (prop == NULL) {
- error_set(errp, QERR_PROPERTY_NOT_FOUND, dev->id?:"", name);
- return NULL;
- }
-
- return prop->type;
+ return g_strdup(object_get_typename(obj));
}
/**
* Legacy property handling
*/
-static void qdev_get_legacy_property(DeviceState *dev, Visitor *v, void *opaque,
+static void qdev_get_legacy_property(Object *obj, Visitor *v, void *opaque,
const char *name, Error **errp)
{
+ DeviceState *dev = DEVICE(obj);
Property *prop = opaque;
- if (prop->info->print) {
- char buffer[1024];
- char *ptr = buffer;
+ char buffer[1024];
+ char *ptr = buffer;
- prop->info->print(dev, prop, buffer, sizeof(buffer));
- visit_type_str(v, &ptr, name, errp);
- } else {
- error_set(errp, QERR_PERMISSION_DENIED);
- }
+ prop->info->print(dev, prop, buffer, sizeof(buffer));
+ visit_type_str(v, &ptr, name, errp);
}
-static void qdev_set_legacy_property(DeviceState *dev, Visitor *v, void *opaque,
+static void qdev_set_legacy_property(Object *obj, Visitor *v, void *opaque,
const char *name, Error **errp)
{
+ DeviceState *dev = DEVICE(obj);
Property *prop = opaque;
+ Error *local_err = NULL;
+ char *ptr = NULL;
+ int ret;
if (dev->state != DEV_STATE_CREATED) {
error_set(errp, QERR_PERMISSION_DENIED);
return;
}
- if (prop->info->parse) {
- Error *local_err = NULL;
- char *ptr = NULL;
-
- visit_type_str(v, &ptr, name, &local_err);
- if (!local_err) {
- int ret;
- ret = prop->info->parse(dev, prop, ptr);
- if (ret != 0) {
- error_set(errp, QERR_INVALID_PARAMETER_VALUE,
- name, prop->info->name);
- }
- g_free(ptr);
- } else {
- error_propagate(errp, local_err);
- }
- } else {
- error_set(errp, QERR_PERMISSION_DENIED);
+ 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);
}
/**
* @qdev_add_legacy_property - adds a legacy property
*
* Do not use this is new code! Properties added through this interface will
- * be given types in the "legacy<>" type namespace.
+ * be given names and types in the "legacy" namespace.
*
- * Legacy properties are always processed as strings. The format of the string
- * depends on the property type.
+ * 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)
{
- gchar *type;
+ gchar *name, *type;
- type = g_strdup_printf("legacy<%s>", prop->info->name);
+ if (!prop->info->print && !prop->info->parse) {
+ return;
+ }
+ name = g_strdup_printf("legacy-%s", prop->name);
+ type = g_strdup_printf("legacy<%s>",
+ prop->info->legacy_name ?: prop->info->name);
- qdev_property_add(dev, prop->name, type,
- qdev_get_legacy_property,
- qdev_set_legacy_property,
- NULL,
- prop, errp);
+ 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);
}
-DeviceState *qdev_get_root(void)
+/**
+ * @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)
{
- static DeviceState *qdev_root;
-
- if (!qdev_root) {
- qdev_root = qdev_create(NULL, "container");
- qdev_init_nofail(qdev_root);
+ /*
+ * 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 qdev_root;
+ object_property_add(OBJECT(dev), prop->name, prop->info->name,
+ prop->info->get, prop->info->set,
+ prop->info->release,
+ prop, errp);
}
-static gchar *qdev_get_path_in(DeviceState *parent, DeviceState *dev)
+static void device_initfn(Object *obj)
{
- DeviceProperty *prop;
+ DeviceState *dev = DEVICE(obj);
+ Property *prop;
- if (parent == dev) {
- return g_strdup("");
+ if (qdev_hotplug) {
+ dev->hotplugged = 1;
+ qdev_hot_added = true;
}
- QTAILQ_FOREACH(prop, &parent->properties, node) {
- gchar *subpath;
-
- if (!strstart(prop->type, "child<", NULL)) {
- continue;
- }
-
- /* Check to see if the device is one of parent's children */
- if (prop->opaque == dev) {
- return g_strdup(prop->name);
- }
-
- /* Check to see if the device is a child of our child */
- subpath = qdev_get_path_in(prop->opaque, dev);
- if (subpath) {
- gchar *path;
-
- path = g_strdup_printf("%s/%s", prop->name, subpath);
- g_free(subpath);
+ dev->instance_id_alias = -1;
+ dev->state = DEV_STATE_CREATED;
- return path;
- }
+ for (prop = qdev_get_props(dev); prop && prop->name; prop++) {
+ qdev_property_add_legacy(dev, prop, NULL);
+ qdev_property_add_static(dev, prop, NULL);
}
- return NULL;
+ object_property_add_str(OBJECT(dev), "type", qdev_get_type, NULL, NULL);
+ qdev_prop_set_defaults(dev, qdev_get_props(dev));
}
-gchar *qdev_get_canonical_path(DeviceState *dev)
-{
- gchar *path, *newpath;
-
- path = qdev_get_path_in(qdev_get_root(), dev);
- g_assert(path != NULL);
-
- newpath = g_strdup_printf("/%s", path);
- g_free(path);
-
- return newpath;
-}
-
-static DeviceState *qdev_resolve_abs_path(DeviceState *parent,
- gchar **parts,
- int index)
+/* Unlink device from bus and free the structure. */
+static void device_finalize(Object *obj)
{
- DeviceProperty *prop;
- DeviceState *child;
-
- if (parts[index] == NULL) {
- return parent;
- }
-
- if (strcmp(parts[index], "") == 0) {
- return qdev_resolve_abs_path(parent, parts, index + 1);
- }
-
- prop = qdev_property_find(parent, parts[index]);
- if (prop == NULL) {
- return NULL;
- }
+ DeviceState *dev = DEVICE(obj);
+ BusState *bus;
+ DeviceClass *dc = DEVICE_GET_CLASS(dev);
- child = NULL;
- if (strstart(prop->type, "link<", NULL)) {
- DeviceState **pchild = prop->opaque;
- if (*pchild) {
- child = *pchild;
+ if (dev->state == DEV_STATE_INITIALIZED) {
+ while (dev->num_child_bus) {
+ bus = QLIST_FIRST(&dev->child_bus);
+ qbus_free(bus);
}
- } else if (strstart(prop->type, "child<", NULL)) {
- child = prop->opaque;
- }
-
- if (!child) {
- return NULL;
- }
-
- return qdev_resolve_abs_path(child, parts, index + 1);
-}
-
-static DeviceState *qdev_resolve_partial_path(DeviceState *parent,
- gchar **parts,
- bool *ambiguous)
-{
- DeviceState *dev;
- DeviceProperty *prop;
-
- dev = qdev_resolve_abs_path(parent, parts, 0);
-
- QTAILQ_FOREACH(prop, &parent->properties, node) {
- DeviceState *found;
-
- if (!strstart(prop->type, "child<", NULL)) {
- continue;
+ if (qdev_get_vmsd(dev)) {
+ vmstate_unregister(dev, qdev_get_vmsd(dev), dev);
}
-
- found = qdev_resolve_partial_path(prop->opaque, parts, ambiguous);
- if (found) {
- if (dev) {
- if (ambiguous) {
- *ambiguous = true;
- }
- return NULL;
- }
- dev = found;
+ if (dc->exit) {
+ dc->exit(dev);
}
-
- if (ambiguous && *ambiguous) {
- return NULL;
+ if (dev->opts) {
+ qemu_opts_del(dev->opts);
}
}
-
- return dev;
+ QTAILQ_REMOVE(&dev->parent_bus->children, dev, sibling);
}
-DeviceState *qdev_resolve_path(const char *path, bool *ambiguous)
+void device_reset(DeviceState *dev)
{
- bool partial_path = true;
- DeviceState *dev;
- gchar **parts;
-
- parts = g_strsplit(path, "/", 0);
- if (parts == NULL || parts[0] == NULL) {
- g_strfreev(parts);
- return qdev_get_root();
- }
+ DeviceClass *klass = DEVICE_GET_CLASS(dev);
- if (strcmp(parts[0], "") == 0) {
- partial_path = false;
- }
-
- if (partial_path) {
- if (ambiguous) {
- *ambiguous = false;
- }
- dev = qdev_resolve_partial_path(qdev_get_root(), parts, ambiguous);
- } else {
- dev = qdev_resolve_abs_path(qdev_get_root(), parts, 1);
+ if (klass->reset) {
+ klass->reset(dev);
}
+}
- g_strfreev(parts);
+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 dev;
+static void qdev_register_types(void)
+{
+ type_register_static(&device_type_info);
}
+type_init(qdev_register_types)