Message ID | 1350414523-8117-12-git-send-email-ehabkost@redhat.com |
---|---|
State | New |
Headers | show |
Eduardo Habkost <ehabkost@redhat.com> writes: > The code depends on some functions from qemu-option.o, so add > qemu-option.o to universal-obj-y to make sure it's included. > > Signed-off-by: Eduardo Habkost <ehabkost@redhat.com> > --- > Makefile.objs | 3 + > hw/Makefile.objs | 2 +- > hw/qdev-core.c | 727 ------------------------------------- > hw/qdev-properties.c | 963 -------------------------------------------------- > qom/Makefile.objs | 2 +- > qom/qdev-core.c | 727 +++++++++++++++++++++++++++++++++++++ > qom/qdev-properties.c | 963 ++++++++++++++++++++++++++++++++++++++++++++++++++ > 7 files changed, 1695 insertions(+), 1692 deletions(-) > delete mode 100644 hw/qdev-core.c > delete mode 100644 hw/qdev-properties.c > create mode 100644 qom/qdev-core.c > create mode 100644 qom/qdev-properties.c Stick the following in your .git/config: [diff] renames = true It's dangerously close to bike-shedding, but i don't think qdev belongs in qom/. It's not core infrastructure. It's the device base class and belongs IMHO in hw/. Regards, Anthony Liguori > > diff --git a/Makefile.objs b/Makefile.objs > index 74b3542..fcd1336 100644 > --- a/Makefile.objs > +++ b/Makefile.objs > @@ -16,6 +16,9 @@ universal-obj-y += $(qobject-obj-y) > qom-obj-y = qom/ > > universal-obj-y += $(qom-obj-y) > +# QOM qdev-core.o requires qemu-option.o: > +universal-obj-y += qemu-option.o > + > > ####################################################################### > # oslib-obj-y is code depending on the OS (win32 vs posix) > diff --git a/hw/Makefile.objs b/hw/Makefile.objs > index 70f2014..3ce38d2 100644 > --- a/hw/Makefile.objs > +++ b/hw/Makefile.objs > @@ -180,7 +180,7 @@ common-obj-$(CONFIG_SD) += sd.o > common-obj-y += bt.o bt-l2cap.o bt-sdp.o bt-hci.o bt-hid.o > common-obj-y += bt-hci-csr.o > common-obj-y += msmouse.o ps2.o > -common-obj-y += qdev-core.o qdev-properties.o qdev-monitor.o > +common-obj-y += qdev-monitor.o > common-obj-y += qdev-system.o qdev-properties-system.o > common-obj-$(CONFIG_BRLAPI) += baum.o > > diff --git a/hw/qdev-core.c b/hw/qdev-core.c > deleted file mode 100644 > index fbb7cb5..0000000 > --- a/hw/qdev-core.c > +++ /dev/null > @@ -1,727 +0,0 @@ > -/* > - * Dynamic device configuration and creation. > - * > - * Copyright (c) 2009 CodeSourcery > - * > - * This library is free software; you can redistribute it and/or > - * modify it under the terms of the GNU Lesser General Public > - * License as published by the Free Software Foundation; either > - * version 2 of the License, or (at your option) any later version. > - * > - * This library is distributed in the hope that it will be useful, > - * but WITHOUT ANY WARRANTY; without even the implied warranty of > - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > - * Lesser General Public License for more details. > - * > - * You should have received a copy of the GNU Lesser General Public > - * License along with this library; if not, see <http://www.gnu.org/licenses/>. > - */ > - > -/* The theory here is that it should be possible to create a machine without > - knowledge of specific devices. Historically board init routines have > - passed a bunch of arguments to each device, requiring the board know > - exactly which device it is dealing with. This file provides an abstract > - API for device configuration and initialization. Devices will generally > - inherit from a particular bus (e.g. PCI or I2C) rather than > - this API directly. */ > - > -#include "hw/qdev.h" > -#include "sysemu.h" > -#include "error.h" > -#include "qapi/qapi-visit-core.h" > - > -int qdev_hotplug = 0; > -static bool qdev_hot_added = false; > -static bool qdev_hot_removed = false; > - > -/* vmstate handling: > - * > - * The real implementations are on qdev-system.c. Those are weak symbols > - * used by *-user. > - */ > -void GCC_WEAK qdev_init_vmstate(DeviceState *dev) > -{ > -} > - > -void GCC_WEAK qdev_finalize_vmstate(DeviceState *dev) > -{ > -} > - > -/* reset handler register/unregister: > - * > - * The real implementations are on qdev-system.c. Those are weak symbols > - * used by *-user. > - */ > -void GCC_WEAK qbus_register_reset(BusState *bus) > -{ > -} > - > -void GCC_WEAK qbus_unregister_reset(BusState *bus) > -{ > -} > - > -const char *qdev_fw_name(DeviceState *dev) > -{ > - DeviceClass *dc = DEVICE_GET_CLASS(dev); > - > - if (dc->fw_name) { > - return dc->fw_name; > - } > - > - return object_get_typename(OBJECT(dev)); > -} > - > -static void qdev_property_add_legacy(DeviceState *dev, Property *prop, > - Error **errp); > - > -static void bus_remove_child(BusState *bus, DeviceState *child) > -{ > - BusChild *kid; > - > - QTAILQ_FOREACH(kid, &bus->children, sibling) { > - if (kid->child == child) { > - char name[32]; > - > - snprintf(name, sizeof(name), "child[%d]", kid->index); > - QTAILQ_REMOVE(&bus->children, kid, sibling); > - object_property_del(OBJECT(bus), name, NULL); > - g_free(kid); > - return; > - } > - } > -} > - > -static void bus_add_child(BusState *bus, DeviceState *child) > -{ > - char name[32]; > - BusChild *kid = g_malloc0(sizeof(*kid)); > - > - if (qdev_hotplug) { > - assert(bus->allow_hotplug); > - } > - > - kid->index = bus->max_index++; > - kid->child = child; > - > - QTAILQ_INSERT_HEAD(&bus->children, kid, sibling); > - > - snprintf(name, sizeof(name), "child[%d]", kid->index); > - object_property_add_link(OBJECT(bus), name, > - object_get_typename(OBJECT(child)), > - (Object **)&kid->child, > - NULL); > -} > - > -void qdev_set_parent_bus(DeviceState *dev, BusState *bus) > -{ > - dev->parent_bus = bus; > - bus_add_child(bus, 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. > - On failure, destroy the device and return negative value. > - Return 0 on success. */ > -int qdev_init(DeviceState *dev) > -{ > - DeviceClass *dc = DEVICE_GET_CLASS(dev); > - int rc; > - > - assert(dev->state == DEV_STATE_CREATED); > - > - rc = dc->init(dev); > - if (rc < 0) { > - qdev_free(dev); > - return rc; > - } > - > - if (!OBJECT(dev)->parent) { > - static int unattached_count = 0; > - gchar *name = g_strdup_printf("device[%d]", unattached_count++); > - > - object_property_add_child(container_get(qdev_get_machine(), > - "/unattached"), > - name, OBJECT(dev), NULL); > - g_free(name); > - } > - > - qdev_init_vmstate(dev); > - dev->state = DEV_STATE_INITIALIZED; > - if (dev->hotplugged) { > - device_reset(dev); > - } > - 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; > -} > - > -void qdev_unplug(DeviceState *dev, Error **errp) > -{ > - DeviceClass *dc = DEVICE_GET_CLASS(dev); > - > - if (!dev->parent_bus->allow_hotplug) { > - error_set(errp, QERR_BUS_NO_HOTPLUG, dev->parent_bus->name); > - return; > - } > - assert(dc->unplug != NULL); > - > - qdev_hot_removed = true; > - > - if (dc->unplug(dev) < 0) { > - error_set(errp, QERR_UNDEFINED_ERROR); > - return; > - } > -} > - > -static int qdev_reset_one(DeviceState *dev, void *opaque) > -{ > - device_reset(dev); > - > - return 0; > -} > - > -static int qbus_reset_one(BusState *bus, void *opaque) > -{ > - BusClass *bc = BUS_GET_CLASS(bus); > - if (bc->reset) { > - return bc->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_fn(void *opaque) > -{ > - BusState *bus = opaque; > - 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) > -{ > - /* just zap it */ > - qdev_free(dev); > - return 0; > -} > - > - > -/* Like qdev_init(), but terminate program via error_report() instead of > - returning an error value. This is okay during machine creation. > - Don't use for hotplug, because there callers need to recover from > - failure. Exception: if you know the device's init() callback can't > - fail, then qdev_init_nofail() can't fail either, and is therefore > - usable even then. But relying on the device implementation that > - way is somewhat unclean, and best avoided. */ > -void qdev_init_nofail(DeviceState *dev) > -{ > - const char *typename = object_get_typename(OBJECT(dev)); > - > - if (qdev_init(dev) < 0) { > - error_report("Initialization of device %s failed", typename); > - exit(1); > - } > -} > - > -/* Unlink device from bus and free the structure. */ > -void qdev_free(DeviceState *dev) > -{ > - object_delete(OBJECT(dev)); > -} > - > -void qdev_machine_creation_done(void) > -{ > - /* > - * ok, initial machine setup is done, starting from now we can > - * only create hotpluggable devices > - */ > - qdev_hotplug = 1; > -} > - > -bool qdev_machine_modified(void) > -{ > - return qdev_hot_added || qdev_hot_removed; > -} > - > -BusState *qdev_get_parent_bus(DeviceState *dev) > -{ > - return dev->parent_bus; > -} > - > -BusState *qdev_get_child_bus(DeviceState *dev, const char *name) > -{ > - BusState *bus; > - > - QLIST_FOREACH(bus, &dev->child_bus, sibling) { > - if (strcmp(name, bus->name) == 0) { > - return bus; > - } > - } > - return NULL; > -} > - > -int qbus_walk_children(BusState *bus, qdev_walkerfn *devfn, > - qbus_walkerfn *busfn, void *opaque) > -{ > - BusChild *kid; > - int err; > - > - if (busfn) { > - err = busfn(bus, opaque); > - if (err) { > - return err; > - } > - } > - > - QTAILQ_FOREACH(kid, &bus->children, sibling) { > - err = qdev_walk_children(kid->child, 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; > -} > - > -DeviceState *qdev_find_recursive(BusState *bus, const char *id) > -{ > - BusChild *kid; > - DeviceState *ret; > - BusState *child; > - > - QTAILQ_FOREACH(kid, &bus->children, sibling) { > - DeviceState *dev = kid->child; > - > - if (dev->id && strcmp(dev->id, id) == 0) { > - return dev; > - } > - > - QLIST_FOREACH(child, &dev->child_bus, sibling) { > - ret = qdev_find_recursive(child, id); > - if (ret) { > - return ret; > - } > - } > - } > - return NULL; > -} > - > -static void qbus_realize(BusState *bus) > -{ > - const char *typename = object_get_typename(OBJECT(bus)); > - char *buf; > - int i,len; > - > - if (bus->name) { > - /* use supplied name */ > - } else if (bus->parent && bus->parent->id) { > - /* parent device has id -> use it for bus name */ > - len = strlen(bus->parent->id) + 16; > - buf = g_malloc(len); > - snprintf(buf, len, "%s.%d", bus->parent->id, bus->parent->num_child_bus); > - bus->name = buf; > - } else { > - /* no id -> use lowercase bus type for bus name */ > - len = strlen(typename) + 16; > - buf = g_malloc(len); > - len = snprintf(buf, len, "%s.%d", typename, > - bus->parent ? bus->parent->num_child_bus : 0); > - for (i = 0; i < len; i++) > - buf[i] = qemu_tolower(buf[i]); > - bus->name = buf; > - } > - > - if (bus->parent) { > - QLIST_INSERT_HEAD(&bus->parent->child_bus, bus, sibling); > - bus->parent->num_child_bus++; > - object_property_add_child(OBJECT(bus->parent), bus->name, OBJECT(bus), NULL); > - } else { > - qbus_register_reset(bus); > - } > -} > - > -void qbus_create_inplace(BusState *bus, const char *typename, > - DeviceState *parent, const char *name) > -{ > - object_initialize(bus, typename); > - > - bus->parent = parent; > - bus->name = name ? g_strdup(name) : NULL; > - qbus_realize(bus); > -} > - > -BusState *qbus_create(const char *typename, DeviceState *parent, const char *name) > -{ > - BusState *bus; > - > - bus = BUS(object_new(typename)); > - bus->qom_allocated = true; > - > - bus->parent = parent; > - bus->name = name ? g_strdup(name) : NULL; > - qbus_realize(bus); > - > - return bus; > -} > - > -void qbus_free(BusState *bus) > -{ > - if (bus->qom_allocated) { > - object_delete(OBJECT(bus)); > - } else { > - object_finalize(OBJECT(bus)); > - if (bus->glib_allocated) { > - g_free(bus); > - } > - } > -} > - > -static char *bus_get_fw_dev_path(BusState *bus, DeviceState *dev) > -{ > - BusClass *bc = BUS_GET_CLASS(bus); > - > - if (bc->get_fw_dev_path) { > - return bc->get_fw_dev_path(dev); > - } > - > - return NULL; > -} > - > -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); > - d = bus_get_fw_dev_path(dev->parent_bus, dev); > - if (d) { > - l += snprintf(p + l, size - l, "%s", d); > - g_free(d); > - } else { > - l += snprintf(p + l, size - l, "%s", object_get_typename(OBJECT(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 g_strdup(path); > -} > - > -char *qdev_get_dev_path(DeviceState *dev) > -{ > - BusClass *bc; > - > - if (!dev || !dev->parent_bus) { > - return NULL; > - } > - > - bc = BUS_GET_CLASS(dev->parent_bus); > - if (bc->get_dev_path) { > - return bc->get_dev_path(dev); > - } > - > - return NULL; > -} > - > -/** > - * Legacy property handling > - */ > - > -static void qdev_get_legacy_property(Object *obj, Visitor *v, void *opaque, > - const char *name, Error **errp) > -{ > - 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); > -} > - > -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; > - } > - > - 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 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) > -{ > - gchar *name, *type; > - > - /* Register pointer properties as legacy properties */ > - if (!prop->info->print && !prop->info->parse && > - (prop->info->set || prop->info->get)) { > - return; > - } > - > - 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) > -{ > - Error *local_err = NULL; > - Object *obj = OBJECT(dev); > - > - /* > - * 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; > - } > - > - object_property_add(obj, prop->name, prop->info->name, > - prop->info->get, prop->info->set, > - prop->info->release, > - prop, &local_err); > - > - if (local_err) { > - error_propagate(errp, local_err); > - return; > - } > - if (prop->qtype == QTYPE_NONE) { > - return; > - } > - > - if (prop->qtype == QTYPE_QBOOL) { > - object_property_set_bool(obj, prop->defval, prop->name, &local_err); > - } else if (prop->info->enum_table) { > - object_property_set_str(obj, prop->info->enum_table[prop->defval], > - prop->name, &local_err); > - } else if (prop->qtype == QTYPE_QINT) { > - object_property_set_int(obj, prop->defval, prop->name, &local_err); > - } > - assert_no_error(local_err); > -} > - > -static void device_initfn(Object *obj) > -{ > - DeviceState *dev = DEVICE(obj); > - ObjectClass *class; > - Property *prop; > - > - if (qdev_hotplug) { > - dev->hotplugged = 1; > - qdev_hot_added = true; > - } > - > - dev->instance_id_alias = -1; > - dev->state = DEV_STATE_CREATED; > - > - class = object_get_class(OBJECT(dev)); > - do { > - for (prop = DEVICE_CLASS(class)->props; prop && prop->name; prop++) { > - qdev_property_add_legacy(dev, prop, NULL); > - qdev_property_add_static(dev, prop, NULL); > - } > - class = object_class_get_parent(class); > - } while (class != object_class_by_name(TYPE_DEVICE)); > - qdev_prop_set_globals(dev); > - > - object_property_add_link(OBJECT(dev), "parent_bus", TYPE_BUS, > - (Object **)&dev->parent_bus, NULL); > -} > - > -/* Unlink device from bus and free the structure. */ > -static void device_finalize(Object *obj) > -{ > - DeviceState *dev = DEVICE(obj); > - BusState *bus; > - DeviceClass *dc = DEVICE_GET_CLASS(dev); > - > - if (dev->state == DEV_STATE_INITIALIZED) { > - while (dev->num_child_bus) { > - bus = QLIST_FIRST(&dev->child_bus); > - qbus_free(bus); > - } > - qdev_finalize_vmstate(dev); > - if (dc->exit) { > - dc->exit(dev); > - } > - if (dev->opts) { > - qemu_opts_del(dev->opts); > - } > - } > - if (dev->parent_bus) { > - bus_remove_child(dev->parent_bus, dev); > - } > -} > - > -static void device_class_base_init(ObjectClass *class, void *data) > -{ > - DeviceClass *klass = DEVICE_CLASS(class); > - > - /* We explicitly look up properties in the superclasses, > - * so do not propagate them to the subclasses. > - */ > - klass->props = NULL; > -} > - > -void device_reset(DeviceState *dev) > -{ > - DeviceClass *klass = DEVICE_GET_CLASS(dev); > - > - if (klass->reset) { > - klass->reset(dev); > - } > -} > - > -Object *qdev_get_machine(void) > -{ > - static Object *dev; > - > - if (dev == NULL) { > - dev = container_get(object_get_root(), "/machine"); > - } > - > - return dev; > -} > - > -static TypeInfo device_type_info = { > - .name = TYPE_DEVICE, > - .parent = TYPE_OBJECT, > - .instance_size = sizeof(DeviceState), > - .instance_init = device_initfn, > - .instance_finalize = device_finalize, > - .class_base_init = device_class_base_init, > - .abstract = true, > - .class_size = sizeof(DeviceClass), > -}; > - > -static void qbus_initfn(Object *obj) > -{ > - BusState *bus = BUS(obj); > - > - QTAILQ_INIT(&bus->children); > -} > - > -static void qbus_finalize(Object *obj) > -{ > - BusState *bus = BUS(obj); > - BusChild *kid; > - > - while ((kid = QTAILQ_FIRST(&bus->children)) != NULL) { > - DeviceState *dev = kid->child; > - qdev_free(dev); > - } > - if (bus->parent) { > - QLIST_REMOVE(bus, sibling); > - bus->parent->num_child_bus--; > - } else { > - qbus_unregister_reset(bus); > - } > - g_free((char *)bus->name); > -} > - > -static const TypeInfo bus_info = { > - .name = TYPE_BUS, > - .parent = TYPE_OBJECT, > - .instance_size = sizeof(BusState), > - .abstract = true, > - .class_size = sizeof(BusClass), > - .instance_init = qbus_initfn, > - .instance_finalize = qbus_finalize, > -}; > - > -static void qdev_register_types(void) > -{ > - type_register_static(&bus_info); > - type_register_static(&device_type_info); > -} > - > -type_init(qdev_register_types) > diff --git a/hw/qdev-properties.c b/hw/qdev-properties.c > deleted file mode 100644 > index 2e82cb9..0000000 > --- a/hw/qdev-properties.c > +++ /dev/null > @@ -1,963 +0,0 @@ > -#include "net.h" > -#include "hw/qdev.h" > -#include "qerror.h" > -#include "blockdev.h" > -#include "hw/block-common.h" > -#include "net/hub.h" > -#include "qapi/qapi-visit-core.h" > - > -void *qdev_get_prop_ptr(DeviceState *dev, Property *prop) > -{ > - void *ptr = dev; > - ptr += prop->offset; > - return ptr; > -} > - > -static void get_enum(Object *obj, Visitor *v, void *opaque, > - const char *name, Error **errp) > -{ > - DeviceState *dev = DEVICE(obj); > - Property *prop = opaque; > - int *ptr = qdev_get_prop_ptr(dev, prop); > - > - visit_type_enum(v, ptr, prop->info->enum_table, > - prop->info->name, prop->name, errp); > -} > - > -static void set_enum(Object *obj, Visitor *v, void *opaque, > - const char *name, Error **errp) > -{ > - DeviceState *dev = DEVICE(obj); > - Property *prop = opaque; > - int *ptr = qdev_get_prop_ptr(dev, prop); > - > - if (dev->state != DEV_STATE_CREATED) { > - error_set(errp, QERR_PERMISSION_DENIED); > - return; > - } > - > - visit_type_enum(v, ptr, prop->info->enum_table, > - prop->info->name, prop->name, errp); > -} > - > -/* Bit */ > - > -static uint32_t qdev_get_prop_mask(Property *prop) > -{ > - assert(prop->info == &qdev_prop_bit); > - return 0x1 << prop->bitnr; > -} > - > -static void bit_prop_set(DeviceState *dev, Property *props, bool val) > -{ > - uint32_t *p = qdev_get_prop_ptr(dev, props); > - uint32_t mask = qdev_get_prop_mask(props); > - if (val) > - *p |= mask; > - else > - *p &= ~mask; > -} > - > -static int print_bit(DeviceState *dev, Property *prop, char *dest, size_t len) > -{ > - uint32_t *p = qdev_get_prop_ptr(dev, prop); > - return snprintf(dest, len, (*p & qdev_get_prop_mask(prop)) ? "on" : "off"); > -} > - > -static void get_bit(Object *obj, Visitor *v, void *opaque, > - const char *name, Error **errp) > -{ > - DeviceState *dev = DEVICE(obj); > - Property *prop = opaque; > - uint32_t *p = qdev_get_prop_ptr(dev, prop); > - bool value = (*p & qdev_get_prop_mask(prop)) != 0; > - > - visit_type_bool(v, &value, name, errp); > -} > - > -static void set_bit(Object *obj, Visitor *v, void *opaque, > - const char *name, Error **errp) > -{ > - DeviceState *dev = DEVICE(obj); > - Property *prop = opaque; > - Error *local_err = NULL; > - bool value; > - > - if (dev->state != DEV_STATE_CREATED) { > - error_set(errp, QERR_PERMISSION_DENIED); > - return; > - } > - > - visit_type_bool(v, &value, name, &local_err); > - if (local_err) { > - error_propagate(errp, local_err); > - return; > - } > - bit_prop_set(dev, prop, value); > -} > - > -PropertyInfo qdev_prop_bit = { > - .name = "boolean", > - .legacy_name = "on/off", > - .print = print_bit, > - .get = get_bit, > - .set = set_bit, > -}; > - > -/* --- 8bit integer --- */ > - > -static void get_uint8(Object *obj, Visitor *v, void *opaque, > - const char *name, Error **errp) > -{ > - DeviceState *dev = DEVICE(obj); > - Property *prop = opaque; > - uint8_t *ptr = qdev_get_prop_ptr(dev, prop); > - > - visit_type_uint8(v, ptr, name, errp); > -} > - > -static void set_uint8(Object *obj, Visitor *v, void *opaque, > - const char *name, Error **errp) > -{ > - DeviceState *dev = DEVICE(obj); > - Property *prop = opaque; > - uint8_t *ptr = qdev_get_prop_ptr(dev, prop); > - > - if (dev->state != DEV_STATE_CREATED) { > - error_set(errp, QERR_PERMISSION_DENIED); > - return; > - } > - > - visit_type_uint8(v, ptr, name, errp); > -} > - > -PropertyInfo qdev_prop_uint8 = { > - .name = "uint8", > - .get = get_uint8, > - .set = set_uint8, > -}; > - > -/* --- 8bit hex value --- */ > - > -static int parse_hex8(DeviceState *dev, Property *prop, const char *str) > -{ > - uint8_t *ptr = qdev_get_prop_ptr(dev, prop); > - char *end; > - > - if (str[0] != '0' || str[1] != 'x') { > - return -EINVAL; > - } > - > - *ptr = strtoul(str, &end, 16); > - if ((*end != '\0') || (end == str)) { > - return -EINVAL; > - } > - > - return 0; > -} > - > -static int print_hex8(DeviceState *dev, Property *prop, char *dest, size_t len) > -{ > - uint8_t *ptr = qdev_get_prop_ptr(dev, prop); > - return snprintf(dest, len, "0x%" PRIx8, *ptr); > -} > - > -PropertyInfo qdev_prop_hex8 = { > - .name = "uint8", > - .legacy_name = "hex8", > - .parse = parse_hex8, > - .print = print_hex8, > - .get = get_uint8, > - .set = set_uint8, > -}; > - > -/* --- 16bit integer --- */ > - > -static void get_uint16(Object *obj, Visitor *v, void *opaque, > - const char *name, Error **errp) > -{ > - DeviceState *dev = DEVICE(obj); > - Property *prop = opaque; > - uint16_t *ptr = qdev_get_prop_ptr(dev, prop); > - > - visit_type_uint16(v, ptr, name, errp); > -} > - > -static void set_uint16(Object *obj, Visitor *v, void *opaque, > - const char *name, Error **errp) > -{ > - DeviceState *dev = DEVICE(obj); > - Property *prop = opaque; > - uint16_t *ptr = qdev_get_prop_ptr(dev, prop); > - > - if (dev->state != DEV_STATE_CREATED) { > - error_set(errp, QERR_PERMISSION_DENIED); > - return; > - } > - > - visit_type_uint16(v, ptr, name, errp); > -} > - > -PropertyInfo qdev_prop_uint16 = { > - .name = "uint16", > - .get = get_uint16, > - .set = set_uint16, > -}; > - > -/* --- 32bit integer --- */ > - > -static void get_uint32(Object *obj, Visitor *v, void *opaque, > - const char *name, Error **errp) > -{ > - DeviceState *dev = DEVICE(obj); > - Property *prop = opaque; > - uint32_t *ptr = qdev_get_prop_ptr(dev, prop); > - > - visit_type_uint32(v, ptr, name, errp); > -} > - > -static void set_uint32(Object *obj, Visitor *v, void *opaque, > - const char *name, Error **errp) > -{ > - DeviceState *dev = DEVICE(obj); > - Property *prop = opaque; > - uint32_t *ptr = qdev_get_prop_ptr(dev, prop); > - > - if (dev->state != DEV_STATE_CREATED) { > - error_set(errp, QERR_PERMISSION_DENIED); > - return; > - } > - > - visit_type_uint32(v, ptr, name, errp); > -} > - > -static void get_int32(Object *obj, Visitor *v, void *opaque, > - const char *name, Error **errp) > -{ > - DeviceState *dev = DEVICE(obj); > - Property *prop = opaque; > - int32_t *ptr = qdev_get_prop_ptr(dev, prop); > - > - visit_type_int32(v, ptr, name, errp); > -} > - > -static void set_int32(Object *obj, Visitor *v, void *opaque, > - const char *name, Error **errp) > -{ > - DeviceState *dev = DEVICE(obj); > - Property *prop = opaque; > - int32_t *ptr = qdev_get_prop_ptr(dev, prop); > - > - if (dev->state != DEV_STATE_CREATED) { > - error_set(errp, QERR_PERMISSION_DENIED); > - return; > - } > - > - visit_type_int32(v, ptr, name, errp); > -} > - > -PropertyInfo qdev_prop_uint32 = { > - .name = "uint32", > - .get = get_uint32, > - .set = set_uint32, > -}; > - > -PropertyInfo qdev_prop_int32 = { > - .name = "int32", > - .get = get_int32, > - .set = set_int32, > -}; > - > -/* --- 32bit hex value --- */ > - > -static int parse_hex32(DeviceState *dev, Property *prop, const char *str) > -{ > - uint32_t *ptr = qdev_get_prop_ptr(dev, prop); > - char *end; > - > - if (str[0] != '0' || str[1] != 'x') { > - return -EINVAL; > - } > - > - *ptr = strtoul(str, &end, 16); > - if ((*end != '\0') || (end == str)) { > - return -EINVAL; > - } > - > - return 0; > -} > - > -static int print_hex32(DeviceState *dev, Property *prop, char *dest, size_t len) > -{ > - uint32_t *ptr = qdev_get_prop_ptr(dev, prop); > - return snprintf(dest, len, "0x%" PRIx32, *ptr); > -} > - > -PropertyInfo qdev_prop_hex32 = { > - .name = "uint32", > - .legacy_name = "hex32", > - .parse = parse_hex32, > - .print = print_hex32, > - .get = get_uint32, > - .set = set_uint32, > -}; > - > -/* --- 64bit integer --- */ > - > -static void get_uint64(Object *obj, Visitor *v, void *opaque, > - const char *name, Error **errp) > -{ > - DeviceState *dev = DEVICE(obj); > - Property *prop = opaque; > - uint64_t *ptr = qdev_get_prop_ptr(dev, prop); > - > - visit_type_uint64(v, ptr, name, errp); > -} > - > -static void set_uint64(Object *obj, Visitor *v, void *opaque, > - const char *name, Error **errp) > -{ > - DeviceState *dev = DEVICE(obj); > - Property *prop = opaque; > - uint64_t *ptr = qdev_get_prop_ptr(dev, prop); > - > - if (dev->state != DEV_STATE_CREATED) { > - error_set(errp, QERR_PERMISSION_DENIED); > - return; > - } > - > - visit_type_uint64(v, ptr, name, errp); > -} > - > -PropertyInfo qdev_prop_uint64 = { > - .name = "uint64", > - .get = get_uint64, > - .set = set_uint64, > -}; > - > -/* --- 64bit hex value --- */ > - > -static int parse_hex64(DeviceState *dev, Property *prop, const char *str) > -{ > - uint64_t *ptr = qdev_get_prop_ptr(dev, prop); > - char *end; > - > - if (str[0] != '0' || str[1] != 'x') { > - return -EINVAL; > - } > - > - *ptr = strtoull(str, &end, 16); > - if ((*end != '\0') || (end == str)) { > - return -EINVAL; > - } > - > - return 0; > -} > - > -static int print_hex64(DeviceState *dev, Property *prop, char *dest, size_t len) > -{ > - uint64_t *ptr = qdev_get_prop_ptr(dev, prop); > - return snprintf(dest, len, "0x%" PRIx64, *ptr); > -} > - > -PropertyInfo qdev_prop_hex64 = { > - .name = "uint64", > - .legacy_name = "hex64", > - .parse = parse_hex64, > - .print = print_hex64, > - .get = get_uint64, > - .set = set_uint64, > -}; > - > -/* --- string --- */ > - > -static void release_string(Object *obj, const char *name, void *opaque) > -{ > - Property *prop = opaque; > - g_free(*(char **)qdev_get_prop_ptr(DEVICE(obj), prop)); > -} > - > -static int print_string(DeviceState *dev, Property *prop, char *dest, size_t len) > -{ > - char **ptr = qdev_get_prop_ptr(dev, prop); > - if (!*ptr) > - return snprintf(dest, len, "<null>"); > - return snprintf(dest, len, "\"%s\"", *ptr); > -} > - > -static void get_string(Object *obj, Visitor *v, void *opaque, > - const char *name, Error **errp) > -{ > - DeviceState *dev = DEVICE(obj); > - Property *prop = opaque; > - char **ptr = qdev_get_prop_ptr(dev, prop); > - > - if (!*ptr) { > - char *str = (char *)""; > - visit_type_str(v, &str, name, errp); > - } else { > - visit_type_str(v, ptr, name, errp); > - } > -} > - > -static void set_string(Object *obj, Visitor *v, void *opaque, > - const char *name, Error **errp) > -{ > - DeviceState *dev = DEVICE(obj); > - Property *prop = opaque; > - char **ptr = qdev_get_prop_ptr(dev, prop); > - Error *local_err = NULL; > - char *str; > - > - if (dev->state != DEV_STATE_CREATED) { > - error_set(errp, QERR_PERMISSION_DENIED); > - return; > - } > - > - visit_type_str(v, &str, name, &local_err); > - if (local_err) { > - error_propagate(errp, local_err); > - return; > - } > - if (*ptr) { > - g_free(*ptr); > - } > - *ptr = str; > -} > - > -PropertyInfo qdev_prop_string = { > - .name = "string", > - .print = print_string, > - .release = release_string, > - .get = get_string, > - .set = set_string, > -}; > - > -/* --- pointer --- */ > - > -/* Not a proper property, just for dirty hacks. TODO Remove it! */ > -PropertyInfo qdev_prop_ptr = { > - .name = "ptr", > -}; > - > -/* --- mac address --- */ > - > -/* > - * accepted syntax versions: > - * 01:02:03:04:05:06 > - * 01-02-03-04-05-06 > - */ > -static void get_mac(Object *obj, Visitor *v, void *opaque, > - const char *name, Error **errp) > -{ > - DeviceState *dev = DEVICE(obj); > - Property *prop = opaque; > - MACAddr *mac = qdev_get_prop_ptr(dev, prop); > - char buffer[2 * 6 + 5 + 1]; > - char *p = buffer; > - > - snprintf(buffer, sizeof(buffer), "%02x:%02x:%02x:%02x:%02x:%02x", > - mac->a[0], mac->a[1], mac->a[2], > - mac->a[3], mac->a[4], mac->a[5]); > - > - visit_type_str(v, &p, name, errp); > -} > - > -static void set_mac(Object *obj, Visitor *v, void *opaque, > - const char *name, Error **errp) > -{ > - DeviceState *dev = DEVICE(obj); > - Property *prop = opaque; > - MACAddr *mac = qdev_get_prop_ptr(dev, prop); > - Error *local_err = NULL; > - int i, pos; > - char *str, *p; > - > - if (dev->state != DEV_STATE_CREATED) { > - error_set(errp, QERR_PERMISSION_DENIED); > - return; > - } > - > - visit_type_str(v, &str, name, &local_err); > - if (local_err) { > - error_propagate(errp, local_err); > - return; > - } > - > - for (i = 0, pos = 0; i < 6; i++, pos += 3) { > - if (!qemu_isxdigit(str[pos])) > - goto inval; > - if (!qemu_isxdigit(str[pos+1])) > - goto inval; > - if (i == 5) { > - if (str[pos+2] != '\0') > - goto inval; > - } else { > - if (str[pos+2] != ':' && str[pos+2] != '-') > - goto inval; > - } > - mac->a[i] = strtol(str+pos, &p, 16); > - } > - g_free(str); > - return; > - > -inval: > - error_set_from_qdev_prop_error(errp, EINVAL, dev, prop, str); > - g_free(str); > -} > - > -PropertyInfo qdev_prop_macaddr = { > - .name = "macaddr", > - .get = get_mac, > - .set = set_mac, > -}; > - > -/* --- lost tick policy --- */ > - > -static const char *lost_tick_policy_table[LOST_TICK_MAX+1] = { > - [LOST_TICK_DISCARD] = "discard", > - [LOST_TICK_DELAY] = "delay", > - [LOST_TICK_MERGE] = "merge", > - [LOST_TICK_SLEW] = "slew", > - [LOST_TICK_MAX] = NULL, > -}; > - > -QEMU_BUILD_BUG_ON(sizeof(LostTickPolicy) != sizeof(int)); > - > -PropertyInfo qdev_prop_losttickpolicy = { > - .name = "LostTickPolicy", > - .enum_table = lost_tick_policy_table, > - .get = get_enum, > - .set = set_enum, > -}; > - > -/* --- BIOS CHS translation */ > - > -static const char *bios_chs_trans_table[] = { > - [BIOS_ATA_TRANSLATION_AUTO] = "auto", > - [BIOS_ATA_TRANSLATION_NONE] = "none", > - [BIOS_ATA_TRANSLATION_LBA] = "lba", > -}; > - > -PropertyInfo qdev_prop_bios_chs_trans = { > - .name = "bios-chs-trans", > - .enum_table = bios_chs_trans_table, > - .get = get_enum, > - .set = set_enum, > -}; > - > -/* --- pci address --- */ > - > -/* > - * bus-local address, i.e. "$slot" or "$slot.$fn" > - */ > -static void set_pci_devfn(Object *obj, Visitor *v, void *opaque, > - const char *name, Error **errp) > -{ > - DeviceState *dev = DEVICE(obj); > - Property *prop = opaque; > - int32_t value, *ptr = qdev_get_prop_ptr(dev, prop); > - unsigned int slot, fn, n; > - Error *local_err = NULL; > - char *str; > - > - if (dev->state != DEV_STATE_CREATED) { > - error_set(errp, QERR_PERMISSION_DENIED); > - return; > - } > - > - visit_type_str(v, &str, name, &local_err); > - if (local_err) { > - error_free(local_err); > - local_err = NULL; > - visit_type_int32(v, &value, name, &local_err); > - if (local_err) { > - error_propagate(errp, local_err); > - } else if (value < -1 || value > 255) { > - error_set(errp, QERR_INVALID_PARAMETER_VALUE, name ? name : "null", > - "pci_devfn"); > - } else { > - *ptr = value; > - } > - return; > - } > - > - if (sscanf(str, "%x.%x%n", &slot, &fn, &n) != 2) { > - fn = 0; > - if (sscanf(str, "%x%n", &slot, &n) != 1) { > - goto invalid; > - } > - } > - if (str[n] != '\0' || fn > 7 || slot > 31) { > - goto invalid; > - } > - *ptr = slot << 3 | fn; > - g_free(str); > - return; > - > -invalid: > - error_set_from_qdev_prop_error(errp, EINVAL, dev, prop, str); > - g_free(str); > -} > - > -static int print_pci_devfn(DeviceState *dev, Property *prop, char *dest, size_t len) > -{ > - int32_t *ptr = qdev_get_prop_ptr(dev, prop); > - > - if (*ptr == -1) { > - return snprintf(dest, len, "<unset>"); > - } else { > - return snprintf(dest, len, "%02x.%x", *ptr >> 3, *ptr & 7); > - } > -} > - > -PropertyInfo qdev_prop_pci_devfn = { > - .name = "int32", > - .legacy_name = "pci-devfn", > - .print = print_pci_devfn, > - .get = get_int32, > - .set = set_pci_devfn, > -}; > - > -/* --- blocksize --- */ > - > -static void set_blocksize(Object *obj, Visitor *v, void *opaque, > - const char *name, Error **errp) > -{ > - DeviceState *dev = DEVICE(obj); > - Property *prop = opaque; > - uint16_t value, *ptr = qdev_get_prop_ptr(dev, prop); > - Error *local_err = NULL; > - const int64_t min = 512; > - const int64_t max = 32768; > - > - if (dev->state != DEV_STATE_CREATED) { > - error_set(errp, QERR_PERMISSION_DENIED); > - return; > - } > - > - visit_type_uint16(v, &value, name, &local_err); > - if (local_err) { > - error_propagate(errp, local_err); > - return; > - } > - if (value < min || value > max) { > - error_set(errp, QERR_PROPERTY_VALUE_OUT_OF_RANGE, > - dev->id?:"", name, (int64_t)value, min, max); > - return; > - } > - > - /* We rely on power-of-2 blocksizes for bitmasks */ > - if ((value & (value - 1)) != 0) { > - error_set(errp, QERR_PROPERTY_VALUE_NOT_POWER_OF_2, > - dev->id?:"", name, (int64_t)value); > - return; > - } > - > - *ptr = value; > -} > - > -PropertyInfo qdev_prop_blocksize = { > - .name = "blocksize", > - .get = get_uint16, > - .set = set_blocksize, > -}; > - > -/* --- pci host address --- */ > - > -static void get_pci_host_devaddr(Object *obj, Visitor *v, void *opaque, > - const char *name, Error **errp) > -{ > - DeviceState *dev = DEVICE(obj); > - Property *prop = opaque; > - PCIHostDeviceAddress *addr = qdev_get_prop_ptr(dev, prop); > - char buffer[] = "xxxx:xx:xx.x"; > - char *p = buffer; > - int rc = 0; > - > - rc = snprintf(buffer, sizeof(buffer), "%04x:%02x:%02x.%d", > - addr->domain, addr->bus, addr->slot, addr->function); > - assert(rc == sizeof(buffer) - 1); > - > - visit_type_str(v, &p, name, errp); > -} > - > -/* > - * Parse [<domain>:]<bus>:<slot>.<func> > - * if <domain> is not supplied, it's assumed to be 0. > - */ > -static void set_pci_host_devaddr(Object *obj, Visitor *v, void *opaque, > - const char *name, Error **errp) > -{ > - DeviceState *dev = DEVICE(obj); > - Property *prop = opaque; > - PCIHostDeviceAddress *addr = qdev_get_prop_ptr(dev, prop); > - Error *local_err = NULL; > - char *str, *p; > - char *e; > - unsigned long val; > - unsigned long dom = 0, bus = 0; > - unsigned int slot = 0, func = 0; > - > - if (dev->state != DEV_STATE_CREATED) { > - error_set(errp, QERR_PERMISSION_DENIED); > - return; > - } > - > - visit_type_str(v, &str, name, &local_err); > - if (local_err) { > - error_propagate(errp, local_err); > - return; > - } > - > - p = str; > - val = strtoul(p, &e, 16); > - if (e == p || *e != ':') { > - goto inval; > - } > - bus = val; > - > - p = e + 1; > - val = strtoul(p, &e, 16); > - if (e == p) { > - goto inval; > - } > - if (*e == ':') { > - dom = bus; > - bus = val; > - p = e + 1; > - val = strtoul(p, &e, 16); > - if (e == p) { > - goto inval; > - } > - } > - slot = val; > - > - if (*e != '.') { > - goto inval; > - } > - p = e + 1; > - val = strtoul(p, &e, 10); > - if (e == p) { > - goto inval; > - } > - func = val; > - > - if (dom > 0xffff || bus > 0xff || slot > 0x1f || func > 7) { > - goto inval; > - } > - > - if (*e) { > - goto inval; > - } > - > - addr->domain = dom; > - addr->bus = bus; > - addr->slot = slot; > - addr->function = func; > - > - g_free(str); > - return; > - > -inval: > - error_set_from_qdev_prop_error(errp, EINVAL, dev, prop, str); > - g_free(str); > -} > - > -PropertyInfo qdev_prop_pci_host_devaddr = { > - .name = "pci-host-devaddr", > - .get = get_pci_host_devaddr, > - .set = set_pci_host_devaddr, > -}; > - > -/* --- public helpers --- */ > - > -static Property *qdev_prop_walk(Property *props, const char *name) > -{ > - if (!props) > - return NULL; > - while (props->name) { > - if (strcmp(props->name, name) == 0) > - return props; > - props++; > - } > - return NULL; > -} > - > -static Property *qdev_prop_find(DeviceState *dev, const char *name) > -{ > - ObjectClass *class; > - Property *prop; > - > - /* device properties */ > - class = object_get_class(OBJECT(dev)); > - do { > - prop = qdev_prop_walk(DEVICE_CLASS(class)->props, name); > - if (prop) { > - return prop; > - } > - class = object_class_get_parent(class); > - } while (class != object_class_by_name(TYPE_DEVICE)); > - > - return NULL; > -} > - > -void error_set_from_qdev_prop_error(Error **errp, int ret, DeviceState *dev, > - Property *prop, const char *value) > -{ > - switch (ret) { > - case -EEXIST: > - error_set(errp, QERR_PROPERTY_VALUE_IN_USE, > - object_get_typename(OBJECT(dev)), prop->name, value); > - break; > - default: > - case -EINVAL: > - error_set(errp, QERR_PROPERTY_VALUE_BAD, > - object_get_typename(OBJECT(dev)), prop->name, value); > - break; > - case -ENOENT: > - error_set(errp, QERR_PROPERTY_VALUE_NOT_FOUND, > - object_get_typename(OBJECT(dev)), prop->name, value); > - break; > - case 0: > - break; > - } > -} > - > -int qdev_prop_parse(DeviceState *dev, const char *name, const char *value) > -{ > - char *legacy_name; > - Error *err = NULL; > - > - legacy_name = g_strdup_printf("legacy-%s", name); > - if (object_property_get_type(OBJECT(dev), legacy_name, NULL)) { > - object_property_parse(OBJECT(dev), value, legacy_name, &err); > - } else { > - object_property_parse(OBJECT(dev), value, name, &err); > - } > - g_free(legacy_name); > - > - if (err) { > - qerror_report_err(err); > - error_free(err); > - return -1; > - } > - return 0; > -} > - > -void qdev_prop_set_bit(DeviceState *dev, const char *name, bool value) > -{ > - Error *errp = NULL; > - object_property_set_bool(OBJECT(dev), value, name, &errp); > - assert_no_error(errp); > -} > - > -void qdev_prop_set_uint8(DeviceState *dev, const char *name, uint8_t value) > -{ > - Error *errp = NULL; > - object_property_set_int(OBJECT(dev), value, name, &errp); > - assert_no_error(errp); > -} > - > -void qdev_prop_set_uint16(DeviceState *dev, const char *name, uint16_t value) > -{ > - Error *errp = NULL; > - object_property_set_int(OBJECT(dev), value, name, &errp); > - assert_no_error(errp); > -} > - > -void qdev_prop_set_uint32(DeviceState *dev, const char *name, uint32_t value) > -{ > - Error *errp = NULL; > - object_property_set_int(OBJECT(dev), value, name, &errp); > - assert_no_error(errp); > -} > - > -void qdev_prop_set_int32(DeviceState *dev, const char *name, int32_t value) > -{ > - Error *errp = NULL; > - object_property_set_int(OBJECT(dev), value, name, &errp); > - assert_no_error(errp); > -} > - > -void qdev_prop_set_uint64(DeviceState *dev, const char *name, uint64_t value) > -{ > - Error *errp = NULL; > - object_property_set_int(OBJECT(dev), value, name, &errp); > - assert_no_error(errp); > -} > - > -void qdev_prop_set_string(DeviceState *dev, const char *name, const char *value) > -{ > - Error *errp = NULL; > - object_property_set_str(OBJECT(dev), value, name, &errp); > - assert_no_error(errp); > -} > - > -void qdev_prop_set_macaddr(DeviceState *dev, const char *name, uint8_t *value) > -{ > - Error *errp = NULL; > - char str[2 * 6 + 5 + 1]; > - snprintf(str, sizeof(str), "%02x:%02x:%02x:%02x:%02x:%02x", > - value[0], value[1], value[2], value[3], value[4], value[5]); > - > - object_property_set_str(OBJECT(dev), str, name, &errp); > - assert_no_error(errp); > -} > - > -void qdev_prop_set_enum(DeviceState *dev, const char *name, int value) > -{ > - Property *prop; > - Error *errp = NULL; > - > - prop = qdev_prop_find(dev, name); > - object_property_set_str(OBJECT(dev), prop->info->enum_table[value], > - name, &errp); > - assert_no_error(errp); > -} > - > -void qdev_prop_set_ptr(DeviceState *dev, const char *name, void *value) > -{ > - Property *prop; > - void **ptr; > - > - prop = qdev_prop_find(dev, name); > - assert(prop && prop->info == &qdev_prop_ptr); > - ptr = qdev_get_prop_ptr(dev, prop); > - *ptr = value; > -} > - > -static QTAILQ_HEAD(, GlobalProperty) global_props = QTAILQ_HEAD_INITIALIZER(global_props); > - > -void qdev_prop_register_global(GlobalProperty *prop) > -{ > - QTAILQ_INSERT_TAIL(&global_props, prop, next); > -} > - > -void qdev_prop_register_global_list(GlobalProperty *props) > -{ > - int i; > - > - for (i = 0; props[i].driver != NULL; i++) { > - qdev_prop_register_global(props+i); > - } > -} > - > -void qdev_prop_set_globals(DeviceState *dev) > -{ > - ObjectClass *class = object_get_class(OBJECT(dev)); > - > - do { > - GlobalProperty *prop; > - QTAILQ_FOREACH(prop, &global_props, next) { > - if (strcmp(object_class_get_name(class), prop->driver) != 0) { > - continue; > - } > - if (qdev_prop_parse(dev, prop->property, prop->value) != 0) { > - exit(1); > - } > - } > - class = object_class_get_parent(class); > - } while (class); > -} > - > diff --git a/qom/Makefile.objs b/qom/Makefile.objs > index 5ef060a..09ef871 100644 > --- a/qom/Makefile.objs > +++ b/qom/Makefile.objs > @@ -1,4 +1,4 @@ > qom-obj-y = object.o container.o qom-qobject.o > -qom-obj-twice-y = cpu.o > +qom-obj-twice-y = cpu.o qdev-core.o qdev-properties.o > common-obj-y = $(qom-obj-twice-y) > user-obj-y = $(qom-obj-twice-y) > diff --git a/qom/qdev-core.c b/qom/qdev-core.c > new file mode 100644 > index 0000000..fbb7cb5 > --- /dev/null > +++ b/qom/qdev-core.c > @@ -0,0 +1,727 @@ > +/* > + * Dynamic device configuration and creation. > + * > + * Copyright (c) 2009 CodeSourcery > + * > + * This library is free software; you can redistribute it and/or > + * modify it under the terms of the GNU Lesser General Public > + * License as published by the Free Software Foundation; either > + * version 2 of the License, or (at your option) any later version. > + * > + * This library is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > + * Lesser General Public License for more details. > + * > + * You should have received a copy of the GNU Lesser General Public > + * License along with this library; if not, see <http://www.gnu.org/licenses/>. > + */ > + > +/* The theory here is that it should be possible to create a machine without > + knowledge of specific devices. Historically board init routines have > + passed a bunch of arguments to each device, requiring the board know > + exactly which device it is dealing with. This file provides an abstract > + API for device configuration and initialization. Devices will generally > + inherit from a particular bus (e.g. PCI or I2C) rather than > + this API directly. */ > + > +#include "hw/qdev.h" > +#include "sysemu.h" > +#include "error.h" > +#include "qapi/qapi-visit-core.h" > + > +int qdev_hotplug = 0; > +static bool qdev_hot_added = false; > +static bool qdev_hot_removed = false; > + > +/* vmstate handling: > + * > + * The real implementations are on qdev-system.c. Those are weak symbols > + * used by *-user. > + */ > +void GCC_WEAK qdev_init_vmstate(DeviceState *dev) > +{ > +} > + > +void GCC_WEAK qdev_finalize_vmstate(DeviceState *dev) > +{ > +} > + > +/* reset handler register/unregister: > + * > + * The real implementations are on qdev-system.c. Those are weak symbols > + * used by *-user. > + */ > +void GCC_WEAK qbus_register_reset(BusState *bus) > +{ > +} > + > +void GCC_WEAK qbus_unregister_reset(BusState *bus) > +{ > +} > + > +const char *qdev_fw_name(DeviceState *dev) > +{ > + DeviceClass *dc = DEVICE_GET_CLASS(dev); > + > + if (dc->fw_name) { > + return dc->fw_name; > + } > + > + return object_get_typename(OBJECT(dev)); > +} > + > +static void qdev_property_add_legacy(DeviceState *dev, Property *prop, > + Error **errp); > + > +static void bus_remove_child(BusState *bus, DeviceState *child) > +{ > + BusChild *kid; > + > + QTAILQ_FOREACH(kid, &bus->children, sibling) { > + if (kid->child == child) { > + char name[32]; > + > + snprintf(name, sizeof(name), "child[%d]", kid->index); > + QTAILQ_REMOVE(&bus->children, kid, sibling); > + object_property_del(OBJECT(bus), name, NULL); > + g_free(kid); > + return; > + } > + } > +} > + > +static void bus_add_child(BusState *bus, DeviceState *child) > +{ > + char name[32]; > + BusChild *kid = g_malloc0(sizeof(*kid)); > + > + if (qdev_hotplug) { > + assert(bus->allow_hotplug); > + } > + > + kid->index = bus->max_index++; > + kid->child = child; > + > + QTAILQ_INSERT_HEAD(&bus->children, kid, sibling); > + > + snprintf(name, sizeof(name), "child[%d]", kid->index); > + object_property_add_link(OBJECT(bus), name, > + object_get_typename(OBJECT(child)), > + (Object **)&kid->child, > + NULL); > +} > + > +void qdev_set_parent_bus(DeviceState *dev, BusState *bus) > +{ > + dev->parent_bus = bus; > + bus_add_child(bus, 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. > + On failure, destroy the device and return negative value. > + Return 0 on success. */ > +int qdev_init(DeviceState *dev) > +{ > + DeviceClass *dc = DEVICE_GET_CLASS(dev); > + int rc; > + > + assert(dev->state == DEV_STATE_CREATED); > + > + rc = dc->init(dev); > + if (rc < 0) { > + qdev_free(dev); > + return rc; > + } > + > + if (!OBJECT(dev)->parent) { > + static int unattached_count = 0; > + gchar *name = g_strdup_printf("device[%d]", unattached_count++); > + > + object_property_add_child(container_get(qdev_get_machine(), > + "/unattached"), > + name, OBJECT(dev), NULL); > + g_free(name); > + } > + > + qdev_init_vmstate(dev); > + dev->state = DEV_STATE_INITIALIZED; > + if (dev->hotplugged) { > + device_reset(dev); > + } > + 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; > +} > + > +void qdev_unplug(DeviceState *dev, Error **errp) > +{ > + DeviceClass *dc = DEVICE_GET_CLASS(dev); > + > + if (!dev->parent_bus->allow_hotplug) { > + error_set(errp, QERR_BUS_NO_HOTPLUG, dev->parent_bus->name); > + return; > + } > + assert(dc->unplug != NULL); > + > + qdev_hot_removed = true; > + > + if (dc->unplug(dev) < 0) { > + error_set(errp, QERR_UNDEFINED_ERROR); > + return; > + } > +} > + > +static int qdev_reset_one(DeviceState *dev, void *opaque) > +{ > + device_reset(dev); > + > + return 0; > +} > + > +static int qbus_reset_one(BusState *bus, void *opaque) > +{ > + BusClass *bc = BUS_GET_CLASS(bus); > + if (bc->reset) { > + return bc->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_fn(void *opaque) > +{ > + BusState *bus = opaque; > + 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) > +{ > + /* just zap it */ > + qdev_free(dev); > + return 0; > +} > + > + > +/* Like qdev_init(), but terminate program via error_report() instead of > + returning an error value. This is okay during machine creation. > + Don't use for hotplug, because there callers need to recover from > + failure. Exception: if you know the device's init() callback can't > + fail, then qdev_init_nofail() can't fail either, and is therefore > + usable even then. But relying on the device implementation that > + way is somewhat unclean, and best avoided. */ > +void qdev_init_nofail(DeviceState *dev) > +{ > + const char *typename = object_get_typename(OBJECT(dev)); > + > + if (qdev_init(dev) < 0) { > + error_report("Initialization of device %s failed", typename); > + exit(1); > + } > +} > + > +/* Unlink device from bus and free the structure. */ > +void qdev_free(DeviceState *dev) > +{ > + object_delete(OBJECT(dev)); > +} > + > +void qdev_machine_creation_done(void) > +{ > + /* > + * ok, initial machine setup is done, starting from now we can > + * only create hotpluggable devices > + */ > + qdev_hotplug = 1; > +} > + > +bool qdev_machine_modified(void) > +{ > + return qdev_hot_added || qdev_hot_removed; > +} > + > +BusState *qdev_get_parent_bus(DeviceState *dev) > +{ > + return dev->parent_bus; > +} > + > +BusState *qdev_get_child_bus(DeviceState *dev, const char *name) > +{ > + BusState *bus; > + > + QLIST_FOREACH(bus, &dev->child_bus, sibling) { > + if (strcmp(name, bus->name) == 0) { > + return bus; > + } > + } > + return NULL; > +} > + > +int qbus_walk_children(BusState *bus, qdev_walkerfn *devfn, > + qbus_walkerfn *busfn, void *opaque) > +{ > + BusChild *kid; > + int err; > + > + if (busfn) { > + err = busfn(bus, opaque); > + if (err) { > + return err; > + } > + } > + > + QTAILQ_FOREACH(kid, &bus->children, sibling) { > + err = qdev_walk_children(kid->child, 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; > +} > + > +DeviceState *qdev_find_recursive(BusState *bus, const char *id) > +{ > + BusChild *kid; > + DeviceState *ret; > + BusState *child; > + > + QTAILQ_FOREACH(kid, &bus->children, sibling) { > + DeviceState *dev = kid->child; > + > + if (dev->id && strcmp(dev->id, id) == 0) { > + return dev; > + } > + > + QLIST_FOREACH(child, &dev->child_bus, sibling) { > + ret = qdev_find_recursive(child, id); > + if (ret) { > + return ret; > + } > + } > + } > + return NULL; > +} > + > +static void qbus_realize(BusState *bus) > +{ > + const char *typename = object_get_typename(OBJECT(bus)); > + char *buf; > + int i,len; > + > + if (bus->name) { > + /* use supplied name */ > + } else if (bus->parent && bus->parent->id) { > + /* parent device has id -> use it for bus name */ > + len = strlen(bus->parent->id) + 16; > + buf = g_malloc(len); > + snprintf(buf, len, "%s.%d", bus->parent->id, bus->parent->num_child_bus); > + bus->name = buf; > + } else { > + /* no id -> use lowercase bus type for bus name */ > + len = strlen(typename) + 16; > + buf = g_malloc(len); > + len = snprintf(buf, len, "%s.%d", typename, > + bus->parent ? bus->parent->num_child_bus : 0); > + for (i = 0; i < len; i++) > + buf[i] = qemu_tolower(buf[i]); > + bus->name = buf; > + } > + > + if (bus->parent) { > + QLIST_INSERT_HEAD(&bus->parent->child_bus, bus, sibling); > + bus->parent->num_child_bus++; > + object_property_add_child(OBJECT(bus->parent), bus->name, OBJECT(bus), NULL); > + } else { > + qbus_register_reset(bus); > + } > +} > + > +void qbus_create_inplace(BusState *bus, const char *typename, > + DeviceState *parent, const char *name) > +{ > + object_initialize(bus, typename); > + > + bus->parent = parent; > + bus->name = name ? g_strdup(name) : NULL; > + qbus_realize(bus); > +} > + > +BusState *qbus_create(const char *typename, DeviceState *parent, const char *name) > +{ > + BusState *bus; > + > + bus = BUS(object_new(typename)); > + bus->qom_allocated = true; > + > + bus->parent = parent; > + bus->name = name ? g_strdup(name) : NULL; > + qbus_realize(bus); > + > + return bus; > +} > + > +void qbus_free(BusState *bus) > +{ > + if (bus->qom_allocated) { > + object_delete(OBJECT(bus)); > + } else { > + object_finalize(OBJECT(bus)); > + if (bus->glib_allocated) { > + g_free(bus); > + } > + } > +} > + > +static char *bus_get_fw_dev_path(BusState *bus, DeviceState *dev) > +{ > + BusClass *bc = BUS_GET_CLASS(bus); > + > + if (bc->get_fw_dev_path) { > + return bc->get_fw_dev_path(dev); > + } > + > + return NULL; > +} > + > +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); > + d = bus_get_fw_dev_path(dev->parent_bus, dev); > + if (d) { > + l += snprintf(p + l, size - l, "%s", d); > + g_free(d); > + } else { > + l += snprintf(p + l, size - l, "%s", object_get_typename(OBJECT(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 g_strdup(path); > +} > + > +char *qdev_get_dev_path(DeviceState *dev) > +{ > + BusClass *bc; > + > + if (!dev || !dev->parent_bus) { > + return NULL; > + } > + > + bc = BUS_GET_CLASS(dev->parent_bus); > + if (bc->get_dev_path) { > + return bc->get_dev_path(dev); > + } > + > + return NULL; > +} > + > +/** > + * Legacy property handling > + */ > + > +static void qdev_get_legacy_property(Object *obj, Visitor *v, void *opaque, > + const char *name, Error **errp) > +{ > + 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); > +} > + > +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; > + } > + > + 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 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) > +{ > + gchar *name, *type; > + > + /* Register pointer properties as legacy properties */ > + if (!prop->info->print && !prop->info->parse && > + (prop->info->set || prop->info->get)) { > + return; > + } > + > + 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) > +{ > + Error *local_err = NULL; > + Object *obj = OBJECT(dev); > + > + /* > + * 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; > + } > + > + object_property_add(obj, prop->name, prop->info->name, > + prop->info->get, prop->info->set, > + prop->info->release, > + prop, &local_err); > + > + if (local_err) { > + error_propagate(errp, local_err); > + return; > + } > + if (prop->qtype == QTYPE_NONE) { > + return; > + } > + > + if (prop->qtype == QTYPE_QBOOL) { > + object_property_set_bool(obj, prop->defval, prop->name, &local_err); > + } else if (prop->info->enum_table) { > + object_property_set_str(obj, prop->info->enum_table[prop->defval], > + prop->name, &local_err); > + } else if (prop->qtype == QTYPE_QINT) { > + object_property_set_int(obj, prop->defval, prop->name, &local_err); > + } > + assert_no_error(local_err); > +} > + > +static void device_initfn(Object *obj) > +{ > + DeviceState *dev = DEVICE(obj); > + ObjectClass *class; > + Property *prop; > + > + if (qdev_hotplug) { > + dev->hotplugged = 1; > + qdev_hot_added = true; > + } > + > + dev->instance_id_alias = -1; > + dev->state = DEV_STATE_CREATED; > + > + class = object_get_class(OBJECT(dev)); > + do { > + for (prop = DEVICE_CLASS(class)->props; prop && prop->name; prop++) { > + qdev_property_add_legacy(dev, prop, NULL); > + qdev_property_add_static(dev, prop, NULL); > + } > + class = object_class_get_parent(class); > + } while (class != object_class_by_name(TYPE_DEVICE)); > + qdev_prop_set_globals(dev); > + > + object_property_add_link(OBJECT(dev), "parent_bus", TYPE_BUS, > + (Object **)&dev->parent_bus, NULL); > +} > + > +/* Unlink device from bus and free the structure. */ > +static void device_finalize(Object *obj) > +{ > + DeviceState *dev = DEVICE(obj); > + BusState *bus; > + DeviceClass *dc = DEVICE_GET_CLASS(dev); > + > + if (dev->state == DEV_STATE_INITIALIZED) { > + while (dev->num_child_bus) { > + bus = QLIST_FIRST(&dev->child_bus); > + qbus_free(bus); > + } > + qdev_finalize_vmstate(dev); > + if (dc->exit) { > + dc->exit(dev); > + } > + if (dev->opts) { > + qemu_opts_del(dev->opts); > + } > + } > + if (dev->parent_bus) { > + bus_remove_child(dev->parent_bus, dev); > + } > +} > + > +static void device_class_base_init(ObjectClass *class, void *data) > +{ > + DeviceClass *klass = DEVICE_CLASS(class); > + > + /* We explicitly look up properties in the superclasses, > + * so do not propagate them to the subclasses. > + */ > + klass->props = NULL; > +} > + > +void device_reset(DeviceState *dev) > +{ > + DeviceClass *klass = DEVICE_GET_CLASS(dev); > + > + if (klass->reset) { > + klass->reset(dev); > + } > +} > + > +Object *qdev_get_machine(void) > +{ > + static Object *dev; > + > + if (dev == NULL) { > + dev = container_get(object_get_root(), "/machine"); > + } > + > + return dev; > +} > + > +static TypeInfo device_type_info = { > + .name = TYPE_DEVICE, > + .parent = TYPE_OBJECT, > + .instance_size = sizeof(DeviceState), > + .instance_init = device_initfn, > + .instance_finalize = device_finalize, > + .class_base_init = device_class_base_init, > + .abstract = true, > + .class_size = sizeof(DeviceClass), > +}; > + > +static void qbus_initfn(Object *obj) > +{ > + BusState *bus = BUS(obj); > + > + QTAILQ_INIT(&bus->children); > +} > + > +static void qbus_finalize(Object *obj) > +{ > + BusState *bus = BUS(obj); > + BusChild *kid; > + > + while ((kid = QTAILQ_FIRST(&bus->children)) != NULL) { > + DeviceState *dev = kid->child; > + qdev_free(dev); > + } > + if (bus->parent) { > + QLIST_REMOVE(bus, sibling); > + bus->parent->num_child_bus--; > + } else { > + qbus_unregister_reset(bus); > + } > + g_free((char *)bus->name); > +} > + > +static const TypeInfo bus_info = { > + .name = TYPE_BUS, > + .parent = TYPE_OBJECT, > + .instance_size = sizeof(BusState), > + .abstract = true, > + .class_size = sizeof(BusClass), > + .instance_init = qbus_initfn, > + .instance_finalize = qbus_finalize, > +}; > + > +static void qdev_register_types(void) > +{ > + type_register_static(&bus_info); > + type_register_static(&device_type_info); > +} > + > +type_init(qdev_register_types) > diff --git a/qom/qdev-properties.c b/qom/qdev-properties.c > new file mode 100644 > index 0000000..2e82cb9 > --- /dev/null > +++ b/qom/qdev-properties.c > @@ -0,0 +1,963 @@ > +#include "net.h" > +#include "hw/qdev.h" > +#include "qerror.h" > +#include "blockdev.h" > +#include "hw/block-common.h" > +#include "net/hub.h" > +#include "qapi/qapi-visit-core.h" > + > +void *qdev_get_prop_ptr(DeviceState *dev, Property *prop) > +{ > + void *ptr = dev; > + ptr += prop->offset; > + return ptr; > +} > + > +static void get_enum(Object *obj, Visitor *v, void *opaque, > + const char *name, Error **errp) > +{ > + DeviceState *dev = DEVICE(obj); > + Property *prop = opaque; > + int *ptr = qdev_get_prop_ptr(dev, prop); > + > + visit_type_enum(v, ptr, prop->info->enum_table, > + prop->info->name, prop->name, errp); > +} > + > +static void set_enum(Object *obj, Visitor *v, void *opaque, > + const char *name, Error **errp) > +{ > + DeviceState *dev = DEVICE(obj); > + Property *prop = opaque; > + int *ptr = qdev_get_prop_ptr(dev, prop); > + > + if (dev->state != DEV_STATE_CREATED) { > + error_set(errp, QERR_PERMISSION_DENIED); > + return; > + } > + > + visit_type_enum(v, ptr, prop->info->enum_table, > + prop->info->name, prop->name, errp); > +} > + > +/* Bit */ > + > +static uint32_t qdev_get_prop_mask(Property *prop) > +{ > + assert(prop->info == &qdev_prop_bit); > + return 0x1 << prop->bitnr; > +} > + > +static void bit_prop_set(DeviceState *dev, Property *props, bool val) > +{ > + uint32_t *p = qdev_get_prop_ptr(dev, props); > + uint32_t mask = qdev_get_prop_mask(props); > + if (val) > + *p |= mask; > + else > + *p &= ~mask; > +} > + > +static int print_bit(DeviceState *dev, Property *prop, char *dest, size_t len) > +{ > + uint32_t *p = qdev_get_prop_ptr(dev, prop); > + return snprintf(dest, len, (*p & qdev_get_prop_mask(prop)) ? "on" : "off"); > +} > + > +static void get_bit(Object *obj, Visitor *v, void *opaque, > + const char *name, Error **errp) > +{ > + DeviceState *dev = DEVICE(obj); > + Property *prop = opaque; > + uint32_t *p = qdev_get_prop_ptr(dev, prop); > + bool value = (*p & qdev_get_prop_mask(prop)) != 0; > + > + visit_type_bool(v, &value, name, errp); > +} > + > +static void set_bit(Object *obj, Visitor *v, void *opaque, > + const char *name, Error **errp) > +{ > + DeviceState *dev = DEVICE(obj); > + Property *prop = opaque; > + Error *local_err = NULL; > + bool value; > + > + if (dev->state != DEV_STATE_CREATED) { > + error_set(errp, QERR_PERMISSION_DENIED); > + return; > + } > + > + visit_type_bool(v, &value, name, &local_err); > + if (local_err) { > + error_propagate(errp, local_err); > + return; > + } > + bit_prop_set(dev, prop, value); > +} > + > +PropertyInfo qdev_prop_bit = { > + .name = "boolean", > + .legacy_name = "on/off", > + .print = print_bit, > + .get = get_bit, > + .set = set_bit, > +}; > + > +/* --- 8bit integer --- */ > + > +static void get_uint8(Object *obj, Visitor *v, void *opaque, > + const char *name, Error **errp) > +{ > + DeviceState *dev = DEVICE(obj); > + Property *prop = opaque; > + uint8_t *ptr = qdev_get_prop_ptr(dev, prop); > + > + visit_type_uint8(v, ptr, name, errp); > +} > + > +static void set_uint8(Object *obj, Visitor *v, void *opaque, > + const char *name, Error **errp) > +{ > + DeviceState *dev = DEVICE(obj); > + Property *prop = opaque; > + uint8_t *ptr = qdev_get_prop_ptr(dev, prop); > + > + if (dev->state != DEV_STATE_CREATED) { > + error_set(errp, QERR_PERMISSION_DENIED); > + return; > + } > + > + visit_type_uint8(v, ptr, name, errp); > +} > + > +PropertyInfo qdev_prop_uint8 = { > + .name = "uint8", > + .get = get_uint8, > + .set = set_uint8, > +}; > + > +/* --- 8bit hex value --- */ > + > +static int parse_hex8(DeviceState *dev, Property *prop, const char *str) > +{ > + uint8_t *ptr = qdev_get_prop_ptr(dev, prop); > + char *end; > + > + if (str[0] != '0' || str[1] != 'x') { > + return -EINVAL; > + } > + > + *ptr = strtoul(str, &end, 16); > + if ((*end != '\0') || (end == str)) { > + return -EINVAL; > + } > + > + return 0; > +} > + > +static int print_hex8(DeviceState *dev, Property *prop, char *dest, size_t len) > +{ > + uint8_t *ptr = qdev_get_prop_ptr(dev, prop); > + return snprintf(dest, len, "0x%" PRIx8, *ptr); > +} > + > +PropertyInfo qdev_prop_hex8 = { > + .name = "uint8", > + .legacy_name = "hex8", > + .parse = parse_hex8, > + .print = print_hex8, > + .get = get_uint8, > + .set = set_uint8, > +}; > + > +/* --- 16bit integer --- */ > + > +static void get_uint16(Object *obj, Visitor *v, void *opaque, > + const char *name, Error **errp) > +{ > + DeviceState *dev = DEVICE(obj); > + Property *prop = opaque; > + uint16_t *ptr = qdev_get_prop_ptr(dev, prop); > + > + visit_type_uint16(v, ptr, name, errp); > +} > + > +static void set_uint16(Object *obj, Visitor *v, void *opaque, > + const char *name, Error **errp) > +{ > + DeviceState *dev = DEVICE(obj); > + Property *prop = opaque; > + uint16_t *ptr = qdev_get_prop_ptr(dev, prop); > + > + if (dev->state != DEV_STATE_CREATED) { > + error_set(errp, QERR_PERMISSION_DENIED); > + return; > + } > + > + visit_type_uint16(v, ptr, name, errp); > +} > + > +PropertyInfo qdev_prop_uint16 = { > + .name = "uint16", > + .get = get_uint16, > + .set = set_uint16, > +}; > + > +/* --- 32bit integer --- */ > + > +static void get_uint32(Object *obj, Visitor *v, void *opaque, > + const char *name, Error **errp) > +{ > + DeviceState *dev = DEVICE(obj); > + Property *prop = opaque; > + uint32_t *ptr = qdev_get_prop_ptr(dev, prop); > + > + visit_type_uint32(v, ptr, name, errp); > +} > + > +static void set_uint32(Object *obj, Visitor *v, void *opaque, > + const char *name, Error **errp) > +{ > + DeviceState *dev = DEVICE(obj); > + Property *prop = opaque; > + uint32_t *ptr = qdev_get_prop_ptr(dev, prop); > + > + if (dev->state != DEV_STATE_CREATED) { > + error_set(errp, QERR_PERMISSION_DENIED); > + return; > + } > + > + visit_type_uint32(v, ptr, name, errp); > +} > + > +static void get_int32(Object *obj, Visitor *v, void *opaque, > + const char *name, Error **errp) > +{ > + DeviceState *dev = DEVICE(obj); > + Property *prop = opaque; > + int32_t *ptr = qdev_get_prop_ptr(dev, prop); > + > + visit_type_int32(v, ptr, name, errp); > +} > + > +static void set_int32(Object *obj, Visitor *v, void *opaque, > + const char *name, Error **errp) > +{ > + DeviceState *dev = DEVICE(obj); > + Property *prop = opaque; > + int32_t *ptr = qdev_get_prop_ptr(dev, prop); > + > + if (dev->state != DEV_STATE_CREATED) { > + error_set(errp, QERR_PERMISSION_DENIED); > + return; > + } > + > + visit_type_int32(v, ptr, name, errp); > +} > + > +PropertyInfo qdev_prop_uint32 = { > + .name = "uint32", > + .get = get_uint32, > + .set = set_uint32, > +}; > + > +PropertyInfo qdev_prop_int32 = { > + .name = "int32", > + .get = get_int32, > + .set = set_int32, > +}; > + > +/* --- 32bit hex value --- */ > + > +static int parse_hex32(DeviceState *dev, Property *prop, const char *str) > +{ > + uint32_t *ptr = qdev_get_prop_ptr(dev, prop); > + char *end; > + > + if (str[0] != '0' || str[1] != 'x') { > + return -EINVAL; > + } > + > + *ptr = strtoul(str, &end, 16); > + if ((*end != '\0') || (end == str)) { > + return -EINVAL; > + } > + > + return 0; > +} > + > +static int print_hex32(DeviceState *dev, Property *prop, char *dest, size_t len) > +{ > + uint32_t *ptr = qdev_get_prop_ptr(dev, prop); > + return snprintf(dest, len, "0x%" PRIx32, *ptr); > +} > + > +PropertyInfo qdev_prop_hex32 = { > + .name = "uint32", > + .legacy_name = "hex32", > + .parse = parse_hex32, > + .print = print_hex32, > + .get = get_uint32, > + .set = set_uint32, > +}; > + > +/* --- 64bit integer --- */ > + > +static void get_uint64(Object *obj, Visitor *v, void *opaque, > + const char *name, Error **errp) > +{ > + DeviceState *dev = DEVICE(obj); > + Property *prop = opaque; > + uint64_t *ptr = qdev_get_prop_ptr(dev, prop); > + > + visit_type_uint64(v, ptr, name, errp); > +} > + > +static void set_uint64(Object *obj, Visitor *v, void *opaque, > + const char *name, Error **errp) > +{ > + DeviceState *dev = DEVICE(obj); > + Property *prop = opaque; > + uint64_t *ptr = qdev_get_prop_ptr(dev, prop); > + > + if (dev->state != DEV_STATE_CREATED) { > + error_set(errp, QERR_PERMISSION_DENIED); > + return; > + } > + > + visit_type_uint64(v, ptr, name, errp); > +} > + > +PropertyInfo qdev_prop_uint64 = { > + .name = "uint64", > + .get = get_uint64, > + .set = set_uint64, > +}; > + > +/* --- 64bit hex value --- */ > + > +static int parse_hex64(DeviceState *dev, Property *prop, const char *str) > +{ > + uint64_t *ptr = qdev_get_prop_ptr(dev, prop); > + char *end; > + > + if (str[0] != '0' || str[1] != 'x') { > + return -EINVAL; > + } > + > + *ptr = strtoull(str, &end, 16); > + if ((*end != '\0') || (end == str)) { > + return -EINVAL; > + } > + > + return 0; > +} > + > +static int print_hex64(DeviceState *dev, Property *prop, char *dest, size_t len) > +{ > + uint64_t *ptr = qdev_get_prop_ptr(dev, prop); > + return snprintf(dest, len, "0x%" PRIx64, *ptr); > +} > + > +PropertyInfo qdev_prop_hex64 = { > + .name = "uint64", > + .legacy_name = "hex64", > + .parse = parse_hex64, > + .print = print_hex64, > + .get = get_uint64, > + .set = set_uint64, > +}; > + > +/* --- string --- */ > + > +static void release_string(Object *obj, const char *name, void *opaque) > +{ > + Property *prop = opaque; > + g_free(*(char **)qdev_get_prop_ptr(DEVICE(obj), prop)); > +} > + > +static int print_string(DeviceState *dev, Property *prop, char *dest, size_t len) > +{ > + char **ptr = qdev_get_prop_ptr(dev, prop); > + if (!*ptr) > + return snprintf(dest, len, "<null>"); > + return snprintf(dest, len, "\"%s\"", *ptr); > +} > + > +static void get_string(Object *obj, Visitor *v, void *opaque, > + const char *name, Error **errp) > +{ > + DeviceState *dev = DEVICE(obj); > + Property *prop = opaque; > + char **ptr = qdev_get_prop_ptr(dev, prop); > + > + if (!*ptr) { > + char *str = (char *)""; > + visit_type_str(v, &str, name, errp); > + } else { > + visit_type_str(v, ptr, name, errp); > + } > +} > + > +static void set_string(Object *obj, Visitor *v, void *opaque, > + const char *name, Error **errp) > +{ > + DeviceState *dev = DEVICE(obj); > + Property *prop = opaque; > + char **ptr = qdev_get_prop_ptr(dev, prop); > + Error *local_err = NULL; > + char *str; > + > + if (dev->state != DEV_STATE_CREATED) { > + error_set(errp, QERR_PERMISSION_DENIED); > + return; > + } > + > + visit_type_str(v, &str, name, &local_err); > + if (local_err) { > + error_propagate(errp, local_err); > + return; > + } > + if (*ptr) { > + g_free(*ptr); > + } > + *ptr = str; > +} > + > +PropertyInfo qdev_prop_string = { > + .name = "string", > + .print = print_string, > + .release = release_string, > + .get = get_string, > + .set = set_string, > +}; > + > +/* --- pointer --- */ > + > +/* Not a proper property, just for dirty hacks. TODO Remove it! */ > +PropertyInfo qdev_prop_ptr = { > + .name = "ptr", > +}; > + > +/* --- mac address --- */ > + > +/* > + * accepted syntax versions: > + * 01:02:03:04:05:06 > + * 01-02-03-04-05-06 > + */ > +static void get_mac(Object *obj, Visitor *v, void *opaque, > + const char *name, Error **errp) > +{ > + DeviceState *dev = DEVICE(obj); > + Property *prop = opaque; > + MACAddr *mac = qdev_get_prop_ptr(dev, prop); > + char buffer[2 * 6 + 5 + 1]; > + char *p = buffer; > + > + snprintf(buffer, sizeof(buffer), "%02x:%02x:%02x:%02x:%02x:%02x", > + mac->a[0], mac->a[1], mac->a[2], > + mac->a[3], mac->a[4], mac->a[5]); > + > + visit_type_str(v, &p, name, errp); > +} > + > +static void set_mac(Object *obj, Visitor *v, void *opaque, > + const char *name, Error **errp) > +{ > + DeviceState *dev = DEVICE(obj); > + Property *prop = opaque; > + MACAddr *mac = qdev_get_prop_ptr(dev, prop); > + Error *local_err = NULL; > + int i, pos; > + char *str, *p; > + > + if (dev->state != DEV_STATE_CREATED) { > + error_set(errp, QERR_PERMISSION_DENIED); > + return; > + } > + > + visit_type_str(v, &str, name, &local_err); > + if (local_err) { > + error_propagate(errp, local_err); > + return; > + } > + > + for (i = 0, pos = 0; i < 6; i++, pos += 3) { > + if (!qemu_isxdigit(str[pos])) > + goto inval; > + if (!qemu_isxdigit(str[pos+1])) > + goto inval; > + if (i == 5) { > + if (str[pos+2] != '\0') > + goto inval; > + } else { > + if (str[pos+2] != ':' && str[pos+2] != '-') > + goto inval; > + } > + mac->a[i] = strtol(str+pos, &p, 16); > + } > + g_free(str); > + return; > + > +inval: > + error_set_from_qdev_prop_error(errp, EINVAL, dev, prop, str); > + g_free(str); > +} > + > +PropertyInfo qdev_prop_macaddr = { > + .name = "macaddr", > + .get = get_mac, > + .set = set_mac, > +}; > + > +/* --- lost tick policy --- */ > + > +static const char *lost_tick_policy_table[LOST_TICK_MAX+1] = { > + [LOST_TICK_DISCARD] = "discard", > + [LOST_TICK_DELAY] = "delay", > + [LOST_TICK_MERGE] = "merge", > + [LOST_TICK_SLEW] = "slew", > + [LOST_TICK_MAX] = NULL, > +}; > + > +QEMU_BUILD_BUG_ON(sizeof(LostTickPolicy) != sizeof(int)); > + > +PropertyInfo qdev_prop_losttickpolicy = { > + .name = "LostTickPolicy", > + .enum_table = lost_tick_policy_table, > + .get = get_enum, > + .set = set_enum, > +}; > + > +/* --- BIOS CHS translation */ > + > +static const char *bios_chs_trans_table[] = { > + [BIOS_ATA_TRANSLATION_AUTO] = "auto", > + [BIOS_ATA_TRANSLATION_NONE] = "none", > + [BIOS_ATA_TRANSLATION_LBA] = "lba", > +}; > + > +PropertyInfo qdev_prop_bios_chs_trans = { > + .name = "bios-chs-trans", > + .enum_table = bios_chs_trans_table, > + .get = get_enum, > + .set = set_enum, > +}; > + > +/* --- pci address --- */ > + > +/* > + * bus-local address, i.e. "$slot" or "$slot.$fn" > + */ > +static void set_pci_devfn(Object *obj, Visitor *v, void *opaque, > + const char *name, Error **errp) > +{ > + DeviceState *dev = DEVICE(obj); > + Property *prop = opaque; > + int32_t value, *ptr = qdev_get_prop_ptr(dev, prop); > + unsigned int slot, fn, n; > + Error *local_err = NULL; > + char *str; > + > + if (dev->state != DEV_STATE_CREATED) { > + error_set(errp, QERR_PERMISSION_DENIED); > + return; > + } > + > + visit_type_str(v, &str, name, &local_err); > + if (local_err) { > + error_free(local_err); > + local_err = NULL; > + visit_type_int32(v, &value, name, &local_err); > + if (local_err) { > + error_propagate(errp, local_err); > + } else if (value < -1 || value > 255) { > + error_set(errp, QERR_INVALID_PARAMETER_VALUE, name ? name : "null", > + "pci_devfn"); > + } else { > + *ptr = value; > + } > + return; > + } > + > + if (sscanf(str, "%x.%x%n", &slot, &fn, &n) != 2) { > + fn = 0; > + if (sscanf(str, "%x%n", &slot, &n) != 1) { > + goto invalid; > + } > + } > + if (str[n] != '\0' || fn > 7 || slot > 31) { > + goto invalid; > + } > + *ptr = slot << 3 | fn; > + g_free(str); > + return; > + > +invalid: > + error_set_from_qdev_prop_error(errp, EINVAL, dev, prop, str); > + g_free(str); > +} > + > +static int print_pci_devfn(DeviceState *dev, Property *prop, char *dest, size_t len) > +{ > + int32_t *ptr = qdev_get_prop_ptr(dev, prop); > + > + if (*ptr == -1) { > + return snprintf(dest, len, "<unset>"); > + } else { > + return snprintf(dest, len, "%02x.%x", *ptr >> 3, *ptr & 7); > + } > +} > + > +PropertyInfo qdev_prop_pci_devfn = { > + .name = "int32", > + .legacy_name = "pci-devfn", > + .print = print_pci_devfn, > + .get = get_int32, > + .set = set_pci_devfn, > +}; > + > +/* --- blocksize --- */ > + > +static void set_blocksize(Object *obj, Visitor *v, void *opaque, > + const char *name, Error **errp) > +{ > + DeviceState *dev = DEVICE(obj); > + Property *prop = opaque; > + uint16_t value, *ptr = qdev_get_prop_ptr(dev, prop); > + Error *local_err = NULL; > + const int64_t min = 512; > + const int64_t max = 32768; > + > + if (dev->state != DEV_STATE_CREATED) { > + error_set(errp, QERR_PERMISSION_DENIED); > + return; > + } > + > + visit_type_uint16(v, &value, name, &local_err); > + if (local_err) { > + error_propagate(errp, local_err); > + return; > + } > + if (value < min || value > max) { > + error_set(errp, QERR_PROPERTY_VALUE_OUT_OF_RANGE, > + dev->id?:"", name, (int64_t)value, min, max); > + return; > + } > + > + /* We rely on power-of-2 blocksizes for bitmasks */ > + if ((value & (value - 1)) != 0) { > + error_set(errp, QERR_PROPERTY_VALUE_NOT_POWER_OF_2, > + dev->id?:"", name, (int64_t)value); > + return; > + } > + > + *ptr = value; > +} > + > +PropertyInfo qdev_prop_blocksize = { > + .name = "blocksize", > + .get = get_uint16, > + .set = set_blocksize, > +}; > + > +/* --- pci host address --- */ > + > +static void get_pci_host_devaddr(Object *obj, Visitor *v, void *opaque, > + const char *name, Error **errp) > +{ > + DeviceState *dev = DEVICE(obj); > + Property *prop = opaque; > + PCIHostDeviceAddress *addr = qdev_get_prop_ptr(dev, prop); > + char buffer[] = "xxxx:xx:xx.x"; > + char *p = buffer; > + int rc = 0; > + > + rc = snprintf(buffer, sizeof(buffer), "%04x:%02x:%02x.%d", > + addr->domain, addr->bus, addr->slot, addr->function); > + assert(rc == sizeof(buffer) - 1); > + > + visit_type_str(v, &p, name, errp); > +} > + > +/* > + * Parse [<domain>:]<bus>:<slot>.<func> > + * if <domain> is not supplied, it's assumed to be 0. > + */ > +static void set_pci_host_devaddr(Object *obj, Visitor *v, void *opaque, > + const char *name, Error **errp) > +{ > + DeviceState *dev = DEVICE(obj); > + Property *prop = opaque; > + PCIHostDeviceAddress *addr = qdev_get_prop_ptr(dev, prop); > + Error *local_err = NULL; > + char *str, *p; > + char *e; > + unsigned long val; > + unsigned long dom = 0, bus = 0; > + unsigned int slot = 0, func = 0; > + > + if (dev->state != DEV_STATE_CREATED) { > + error_set(errp, QERR_PERMISSION_DENIED); > + return; > + } > + > + visit_type_str(v, &str, name, &local_err); > + if (local_err) { > + error_propagate(errp, local_err); > + return; > + } > + > + p = str; > + val = strtoul(p, &e, 16); > + if (e == p || *e != ':') { > + goto inval; > + } > + bus = val; > + > + p = e + 1; > + val = strtoul(p, &e, 16); > + if (e == p) { > + goto inval; > + } > + if (*e == ':') { > + dom = bus; > + bus = val; > + p = e + 1; > + val = strtoul(p, &e, 16); > + if (e == p) { > + goto inval; > + } > + } > + slot = val; > + > + if (*e != '.') { > + goto inval; > + } > + p = e + 1; > + val = strtoul(p, &e, 10); > + if (e == p) { > + goto inval; > + } > + func = val; > + > + if (dom > 0xffff || bus > 0xff || slot > 0x1f || func > 7) { > + goto inval; > + } > + > + if (*e) { > + goto inval; > + } > + > + addr->domain = dom; > + addr->bus = bus; > + addr->slot = slot; > + addr->function = func; > + > + g_free(str); > + return; > + > +inval: > + error_set_from_qdev_prop_error(errp, EINVAL, dev, prop, str); > + g_free(str); > +} > + > +PropertyInfo qdev_prop_pci_host_devaddr = { > + .name = "pci-host-devaddr", > + .get = get_pci_host_devaddr, > + .set = set_pci_host_devaddr, > +}; > + > +/* --- public helpers --- */ > + > +static Property *qdev_prop_walk(Property *props, const char *name) > +{ > + if (!props) > + return NULL; > + while (props->name) { > + if (strcmp(props->name, name) == 0) > + return props; > + props++; > + } > + return NULL; > +} > + > +static Property *qdev_prop_find(DeviceState *dev, const char *name) > +{ > + ObjectClass *class; > + Property *prop; > + > + /* device properties */ > + class = object_get_class(OBJECT(dev)); > + do { > + prop = qdev_prop_walk(DEVICE_CLASS(class)->props, name); > + if (prop) { > + return prop; > + } > + class = object_class_get_parent(class); > + } while (class != object_class_by_name(TYPE_DEVICE)); > + > + return NULL; > +} > + > +void error_set_from_qdev_prop_error(Error **errp, int ret, DeviceState *dev, > + Property *prop, const char *value) > +{ > + switch (ret) { > + case -EEXIST: > + error_set(errp, QERR_PROPERTY_VALUE_IN_USE, > + object_get_typename(OBJECT(dev)), prop->name, value); > + break; > + default: > + case -EINVAL: > + error_set(errp, QERR_PROPERTY_VALUE_BAD, > + object_get_typename(OBJECT(dev)), prop->name, value); > + break; > + case -ENOENT: > + error_set(errp, QERR_PROPERTY_VALUE_NOT_FOUND, > + object_get_typename(OBJECT(dev)), prop->name, value); > + break; > + case 0: > + break; > + } > +} > + > +int qdev_prop_parse(DeviceState *dev, const char *name, const char *value) > +{ > + char *legacy_name; > + Error *err = NULL; > + > + legacy_name = g_strdup_printf("legacy-%s", name); > + if (object_property_get_type(OBJECT(dev), legacy_name, NULL)) { > + object_property_parse(OBJECT(dev), value, legacy_name, &err); > + } else { > + object_property_parse(OBJECT(dev), value, name, &err); > + } > + g_free(legacy_name); > + > + if (err) { > + qerror_report_err(err); > + error_free(err); > + return -1; > + } > + return 0; > +} > + > +void qdev_prop_set_bit(DeviceState *dev, const char *name, bool value) > +{ > + Error *errp = NULL; > + object_property_set_bool(OBJECT(dev), value, name, &errp); > + assert_no_error(errp); > +} > + > +void qdev_prop_set_uint8(DeviceState *dev, const char *name, uint8_t value) > +{ > + Error *errp = NULL; > + object_property_set_int(OBJECT(dev), value, name, &errp); > + assert_no_error(errp); > +} > + > +void qdev_prop_set_uint16(DeviceState *dev, const char *name, uint16_t value) > +{ > + Error *errp = NULL; > + object_property_set_int(OBJECT(dev), value, name, &errp); > + assert_no_error(errp); > +} > + > +void qdev_prop_set_uint32(DeviceState *dev, const char *name, uint32_t value) > +{ > + Error *errp = NULL; > + object_property_set_int(OBJECT(dev), value, name, &errp); > + assert_no_error(errp); > +} > + > +void qdev_prop_set_int32(DeviceState *dev, const char *name, int32_t value) > +{ > + Error *errp = NULL; > + object_property_set_int(OBJECT(dev), value, name, &errp); > + assert_no_error(errp); > +} > + > +void qdev_prop_set_uint64(DeviceState *dev, const char *name, uint64_t value) > +{ > + Error *errp = NULL; > + object_property_set_int(OBJECT(dev), value, name, &errp); > + assert_no_error(errp); > +} > + > +void qdev_prop_set_string(DeviceState *dev, const char *name, const char *value) > +{ > + Error *errp = NULL; > + object_property_set_str(OBJECT(dev), value, name, &errp); > + assert_no_error(errp); > +} > + > +void qdev_prop_set_macaddr(DeviceState *dev, const char *name, uint8_t *value) > +{ > + Error *errp = NULL; > + char str[2 * 6 + 5 + 1]; > + snprintf(str, sizeof(str), "%02x:%02x:%02x:%02x:%02x:%02x", > + value[0], value[1], value[2], value[3], value[4], value[5]); > + > + object_property_set_str(OBJECT(dev), str, name, &errp); > + assert_no_error(errp); > +} > + > +void qdev_prop_set_enum(DeviceState *dev, const char *name, int value) > +{ > + Property *prop; > + Error *errp = NULL; > + > + prop = qdev_prop_find(dev, name); > + object_property_set_str(OBJECT(dev), prop->info->enum_table[value], > + name, &errp); > + assert_no_error(errp); > +} > + > +void qdev_prop_set_ptr(DeviceState *dev, const char *name, void *value) > +{ > + Property *prop; > + void **ptr; > + > + prop = qdev_prop_find(dev, name); > + assert(prop && prop->info == &qdev_prop_ptr); > + ptr = qdev_get_prop_ptr(dev, prop); > + *ptr = value; > +} > + > +static QTAILQ_HEAD(, GlobalProperty) global_props = QTAILQ_HEAD_INITIALIZER(global_props); > + > +void qdev_prop_register_global(GlobalProperty *prop) > +{ > + QTAILQ_INSERT_TAIL(&global_props, prop, next); > +} > + > +void qdev_prop_register_global_list(GlobalProperty *props) > +{ > + int i; > + > + for (i = 0; props[i].driver != NULL; i++) { > + qdev_prop_register_global(props+i); > + } > +} > + > +void qdev_prop_set_globals(DeviceState *dev) > +{ > + ObjectClass *class = object_get_class(OBJECT(dev)); > + > + do { > + GlobalProperty *prop; > + QTAILQ_FOREACH(prop, &global_props, next) { > + if (strcmp(object_class_get_name(class), prop->driver) != 0) { > + continue; > + } > + if (qdev_prop_parse(dev, prop->property, prop->value) != 0) { > + exit(1); > + } > + } > + class = object_class_get_parent(class); > + } while (class); > +} > + > -- > 1.7.11.7
On Wed, Oct 17, 2012 at 01:11:41PM -0500, Anthony Liguori wrote: > Eduardo Habkost <ehabkost@redhat.com> writes: > > > The code depends on some functions from qemu-option.o, so add > > qemu-option.o to universal-obj-y to make sure it's included. > > > > Signed-off-by: Eduardo Habkost <ehabkost@redhat.com> > > --- > > Makefile.objs | 3 + > > hw/Makefile.objs | 2 +- > > hw/qdev-core.c | 727 ------------------------------------- > > hw/qdev-properties.c | 963 -------------------------------------------------- > > qom/Makefile.objs | 2 +- > > qom/qdev-core.c | 727 +++++++++++++++++++++++++++++++++++++ > > qom/qdev-properties.c | 963 ++++++++++++++++++++++++++++++++++++++++++++++++++ > > 7 files changed, 1695 insertions(+), 1692 deletions(-) > > delete mode 100644 hw/qdev-core.c > > delete mode 100644 hw/qdev-properties.c > > create mode 100644 qom/qdev-core.c > > create mode 100644 qom/qdev-properties.c > > Stick the following in your .git/config: > > [diff] > renames = true Done. > > It's dangerously close to bike-shedding, but i don't think qdev belongs > in qom/. It's not core infrastructure. It's the device base class and > belongs IMHO in hw/. I don't mind keeping it on hw/, either. I was unsure wheter to move it, or if it would be OK for *-user to start including files from the hw/ directory. If nobody complains, I will change the patches to keep the files on "hw/" on the next version of the series. > > Regards, > > Anthony Liguori > > > > > diff --git a/Makefile.objs b/Makefile.objs > > index 74b3542..fcd1336 100644 > > --- a/Makefile.objs > > +++ b/Makefile.objs > > @@ -16,6 +16,9 @@ universal-obj-y += $(qobject-obj-y) > > qom-obj-y = qom/ > > > > universal-obj-y += $(qom-obj-y) > > +# QOM qdev-core.o requires qemu-option.o: > > +universal-obj-y += qemu-option.o > > + > > > > ####################################################################### > > # oslib-obj-y is code depending on the OS (win32 vs posix) > > diff --git a/hw/Makefile.objs b/hw/Makefile.objs > > index 70f2014..3ce38d2 100644 > > --- a/hw/Makefile.objs > > +++ b/hw/Makefile.objs > > @@ -180,7 +180,7 @@ common-obj-$(CONFIG_SD) += sd.o > > common-obj-y += bt.o bt-l2cap.o bt-sdp.o bt-hci.o bt-hid.o > > common-obj-y += bt-hci-csr.o > > common-obj-y += msmouse.o ps2.o > > -common-obj-y += qdev-core.o qdev-properties.o qdev-monitor.o > > +common-obj-y += qdev-monitor.o > > common-obj-y += qdev-system.o qdev-properties-system.o > > common-obj-$(CONFIG_BRLAPI) += baum.o > > > > diff --git a/hw/qdev-core.c b/hw/qdev-core.c > > deleted file mode 100644 > > index fbb7cb5..0000000 > > --- a/hw/qdev-core.c > > +++ /dev/null > > @@ -1,727 +0,0 @@ > > -/* > > - * Dynamic device configuration and creation. > > - * > > - * Copyright (c) 2009 CodeSourcery > > - * > > - * This library is free software; you can redistribute it and/or > > - * modify it under the terms of the GNU Lesser General Public > > - * License as published by the Free Software Foundation; either > > - * version 2 of the License, or (at your option) any later version. > > - * > > - * This library is distributed in the hope that it will be useful, > > - * but WITHOUT ANY WARRANTY; without even the implied warranty of > > - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > > - * Lesser General Public License for more details. > > - * > > - * You should have received a copy of the GNU Lesser General Public > > - * License along with this library; if not, see <http://www.gnu.org/licenses/>. > > - */ > > - > > -/* The theory here is that it should be possible to create a machine without > > - knowledge of specific devices. Historically board init routines have > > - passed a bunch of arguments to each device, requiring the board know > > - exactly which device it is dealing with. This file provides an abstract > > - API for device configuration and initialization. Devices will generally > > - inherit from a particular bus (e.g. PCI or I2C) rather than > > - this API directly. */ > > - > > -#include "hw/qdev.h" > > -#include "sysemu.h" > > -#include "error.h" > > -#include "qapi/qapi-visit-core.h" > > - > > -int qdev_hotplug = 0; > > -static bool qdev_hot_added = false; > > -static bool qdev_hot_removed = false; > > - > > -/* vmstate handling: > > - * > > - * The real implementations are on qdev-system.c. Those are weak symbols > > - * used by *-user. > > - */ > > -void GCC_WEAK qdev_init_vmstate(DeviceState *dev) > > -{ > > -} > > - > > -void GCC_WEAK qdev_finalize_vmstate(DeviceState *dev) > > -{ > > -} > > - > > -/* reset handler register/unregister: > > - * > > - * The real implementations are on qdev-system.c. Those are weak symbols > > - * used by *-user. > > - */ > > -void GCC_WEAK qbus_register_reset(BusState *bus) > > -{ > > -} > > - > > -void GCC_WEAK qbus_unregister_reset(BusState *bus) > > -{ > > -} > > - > > -const char *qdev_fw_name(DeviceState *dev) > > -{ > > - DeviceClass *dc = DEVICE_GET_CLASS(dev); > > - > > - if (dc->fw_name) { > > - return dc->fw_name; > > - } > > - > > - return object_get_typename(OBJECT(dev)); > > -} > > - > > -static void qdev_property_add_legacy(DeviceState *dev, Property *prop, > > - Error **errp); > > - > > -static void bus_remove_child(BusState *bus, DeviceState *child) > > -{ > > - BusChild *kid; > > - > > - QTAILQ_FOREACH(kid, &bus->children, sibling) { > > - if (kid->child == child) { > > - char name[32]; > > - > > - snprintf(name, sizeof(name), "child[%d]", kid->index); > > - QTAILQ_REMOVE(&bus->children, kid, sibling); > > - object_property_del(OBJECT(bus), name, NULL); > > - g_free(kid); > > - return; > > - } > > - } > > -} > > - > > -static void bus_add_child(BusState *bus, DeviceState *child) > > -{ > > - char name[32]; > > - BusChild *kid = g_malloc0(sizeof(*kid)); > > - > > - if (qdev_hotplug) { > > - assert(bus->allow_hotplug); > > - } > > - > > - kid->index = bus->max_index++; > > - kid->child = child; > > - > > - QTAILQ_INSERT_HEAD(&bus->children, kid, sibling); > > - > > - snprintf(name, sizeof(name), "child[%d]", kid->index); > > - object_property_add_link(OBJECT(bus), name, > > - object_get_typename(OBJECT(child)), > > - (Object **)&kid->child, > > - NULL); > > -} > > - > > -void qdev_set_parent_bus(DeviceState *dev, BusState *bus) > > -{ > > - dev->parent_bus = bus; > > - bus_add_child(bus, 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. > > - On failure, destroy the device and return negative value. > > - Return 0 on success. */ > > -int qdev_init(DeviceState *dev) > > -{ > > - DeviceClass *dc = DEVICE_GET_CLASS(dev); > > - int rc; > > - > > - assert(dev->state == DEV_STATE_CREATED); > > - > > - rc = dc->init(dev); > > - if (rc < 0) { > > - qdev_free(dev); > > - return rc; > > - } > > - > > - if (!OBJECT(dev)->parent) { > > - static int unattached_count = 0; > > - gchar *name = g_strdup_printf("device[%d]", unattached_count++); > > - > > - object_property_add_child(container_get(qdev_get_machine(), > > - "/unattached"), > > - name, OBJECT(dev), NULL); > > - g_free(name); > > - } > > - > > - qdev_init_vmstate(dev); > > - dev->state = DEV_STATE_INITIALIZED; > > - if (dev->hotplugged) { > > - device_reset(dev); > > - } > > - 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; > > -} > > - > > -void qdev_unplug(DeviceState *dev, Error **errp) > > -{ > > - DeviceClass *dc = DEVICE_GET_CLASS(dev); > > - > > - if (!dev->parent_bus->allow_hotplug) { > > - error_set(errp, QERR_BUS_NO_HOTPLUG, dev->parent_bus->name); > > - return; > > - } > > - assert(dc->unplug != NULL); > > - > > - qdev_hot_removed = true; > > - > > - if (dc->unplug(dev) < 0) { > > - error_set(errp, QERR_UNDEFINED_ERROR); > > - return; > > - } > > -} > > - > > -static int qdev_reset_one(DeviceState *dev, void *opaque) > > -{ > > - device_reset(dev); > > - > > - return 0; > > -} > > - > > -static int qbus_reset_one(BusState *bus, void *opaque) > > -{ > > - BusClass *bc = BUS_GET_CLASS(bus); > > - if (bc->reset) { > > - return bc->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_fn(void *opaque) > > -{ > > - BusState *bus = opaque; > > - 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) > > -{ > > - /* just zap it */ > > - qdev_free(dev); > > - return 0; > > -} > > - > > - > > -/* Like qdev_init(), but terminate program via error_report() instead of > > - returning an error value. This is okay during machine creation. > > - Don't use for hotplug, because there callers need to recover from > > - failure. Exception: if you know the device's init() callback can't > > - fail, then qdev_init_nofail() can't fail either, and is therefore > > - usable even then. But relying on the device implementation that > > - way is somewhat unclean, and best avoided. */ > > -void qdev_init_nofail(DeviceState *dev) > > -{ > > - const char *typename = object_get_typename(OBJECT(dev)); > > - > > - if (qdev_init(dev) < 0) { > > - error_report("Initialization of device %s failed", typename); > > - exit(1); > > - } > > -} > > - > > -/* Unlink device from bus and free the structure. */ > > -void qdev_free(DeviceState *dev) > > -{ > > - object_delete(OBJECT(dev)); > > -} > > - > > -void qdev_machine_creation_done(void) > > -{ > > - /* > > - * ok, initial machine setup is done, starting from now we can > > - * only create hotpluggable devices > > - */ > > - qdev_hotplug = 1; > > -} > > - > > -bool qdev_machine_modified(void) > > -{ > > - return qdev_hot_added || qdev_hot_removed; > > -} > > - > > -BusState *qdev_get_parent_bus(DeviceState *dev) > > -{ > > - return dev->parent_bus; > > -} > > - > > -BusState *qdev_get_child_bus(DeviceState *dev, const char *name) > > -{ > > - BusState *bus; > > - > > - QLIST_FOREACH(bus, &dev->child_bus, sibling) { > > - if (strcmp(name, bus->name) == 0) { > > - return bus; > > - } > > - } > > - return NULL; > > -} > > - > > -int qbus_walk_children(BusState *bus, qdev_walkerfn *devfn, > > - qbus_walkerfn *busfn, void *opaque) > > -{ > > - BusChild *kid; > > - int err; > > - > > - if (busfn) { > > - err = busfn(bus, opaque); > > - if (err) { > > - return err; > > - } > > - } > > - > > - QTAILQ_FOREACH(kid, &bus->children, sibling) { > > - err = qdev_walk_children(kid->child, 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; > > -} > > - > > -DeviceState *qdev_find_recursive(BusState *bus, const char *id) > > -{ > > - BusChild *kid; > > - DeviceState *ret; > > - BusState *child; > > - > > - QTAILQ_FOREACH(kid, &bus->children, sibling) { > > - DeviceState *dev = kid->child; > > - > > - if (dev->id && strcmp(dev->id, id) == 0) { > > - return dev; > > - } > > - > > - QLIST_FOREACH(child, &dev->child_bus, sibling) { > > - ret = qdev_find_recursive(child, id); > > - if (ret) { > > - return ret; > > - } > > - } > > - } > > - return NULL; > > -} > > - > > -static void qbus_realize(BusState *bus) > > -{ > > - const char *typename = object_get_typename(OBJECT(bus)); > > - char *buf; > > - int i,len; > > - > > - if (bus->name) { > > - /* use supplied name */ > > - } else if (bus->parent && bus->parent->id) { > > - /* parent device has id -> use it for bus name */ > > - len = strlen(bus->parent->id) + 16; > > - buf = g_malloc(len); > > - snprintf(buf, len, "%s.%d", bus->parent->id, bus->parent->num_child_bus); > > - bus->name = buf; > > - } else { > > - /* no id -> use lowercase bus type for bus name */ > > - len = strlen(typename) + 16; > > - buf = g_malloc(len); > > - len = snprintf(buf, len, "%s.%d", typename, > > - bus->parent ? bus->parent->num_child_bus : 0); > > - for (i = 0; i < len; i++) > > - buf[i] = qemu_tolower(buf[i]); > > - bus->name = buf; > > - } > > - > > - if (bus->parent) { > > - QLIST_INSERT_HEAD(&bus->parent->child_bus, bus, sibling); > > - bus->parent->num_child_bus++; > > - object_property_add_child(OBJECT(bus->parent), bus->name, OBJECT(bus), NULL); > > - } else { > > - qbus_register_reset(bus); > > - } > > -} > > - > > -void qbus_create_inplace(BusState *bus, const char *typename, > > - DeviceState *parent, const char *name) > > -{ > > - object_initialize(bus, typename); > > - > > - bus->parent = parent; > > - bus->name = name ? g_strdup(name) : NULL; > > - qbus_realize(bus); > > -} > > - > > -BusState *qbus_create(const char *typename, DeviceState *parent, const char *name) > > -{ > > - BusState *bus; > > - > > - bus = BUS(object_new(typename)); > > - bus->qom_allocated = true; > > - > > - bus->parent = parent; > > - bus->name = name ? g_strdup(name) : NULL; > > - qbus_realize(bus); > > - > > - return bus; > > -} > > - > > -void qbus_free(BusState *bus) > > -{ > > - if (bus->qom_allocated) { > > - object_delete(OBJECT(bus)); > > - } else { > > - object_finalize(OBJECT(bus)); > > - if (bus->glib_allocated) { > > - g_free(bus); > > - } > > - } > > -} > > - > > -static char *bus_get_fw_dev_path(BusState *bus, DeviceState *dev) > > -{ > > - BusClass *bc = BUS_GET_CLASS(bus); > > - > > - if (bc->get_fw_dev_path) { > > - return bc->get_fw_dev_path(dev); > > - } > > - > > - return NULL; > > -} > > - > > -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); > > - d = bus_get_fw_dev_path(dev->parent_bus, dev); > > - if (d) { > > - l += snprintf(p + l, size - l, "%s", d); > > - g_free(d); > > - } else { > > - l += snprintf(p + l, size - l, "%s", object_get_typename(OBJECT(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 g_strdup(path); > > -} > > - > > -char *qdev_get_dev_path(DeviceState *dev) > > -{ > > - BusClass *bc; > > - > > - if (!dev || !dev->parent_bus) { > > - return NULL; > > - } > > - > > - bc = BUS_GET_CLASS(dev->parent_bus); > > - if (bc->get_dev_path) { > > - return bc->get_dev_path(dev); > > - } > > - > > - return NULL; > > -} > > - > > -/** > > - * Legacy property handling > > - */ > > - > > -static void qdev_get_legacy_property(Object *obj, Visitor *v, void *opaque, > > - const char *name, Error **errp) > > -{ > > - 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); > > -} > > - > > -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; > > - } > > - > > - 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 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) > > -{ > > - gchar *name, *type; > > - > > - /* Register pointer properties as legacy properties */ > > - if (!prop->info->print && !prop->info->parse && > > - (prop->info->set || prop->info->get)) { > > - return; > > - } > > - > > - 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) > > -{ > > - Error *local_err = NULL; > > - Object *obj = OBJECT(dev); > > - > > - /* > > - * 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; > > - } > > - > > - object_property_add(obj, prop->name, prop->info->name, > > - prop->info->get, prop->info->set, > > - prop->info->release, > > - prop, &local_err); > > - > > - if (local_err) { > > - error_propagate(errp, local_err); > > - return; > > - } > > - if (prop->qtype == QTYPE_NONE) { > > - return; > > - } > > - > > - if (prop->qtype == QTYPE_QBOOL) { > > - object_property_set_bool(obj, prop->defval, prop->name, &local_err); > > - } else if (prop->info->enum_table) { > > - object_property_set_str(obj, prop->info->enum_table[prop->defval], > > - prop->name, &local_err); > > - } else if (prop->qtype == QTYPE_QINT) { > > - object_property_set_int(obj, prop->defval, prop->name, &local_err); > > - } > > - assert_no_error(local_err); > > -} > > - > > -static void device_initfn(Object *obj) > > -{ > > - DeviceState *dev = DEVICE(obj); > > - ObjectClass *class; > > - Property *prop; > > - > > - if (qdev_hotplug) { > > - dev->hotplugged = 1; > > - qdev_hot_added = true; > > - } > > - > > - dev->instance_id_alias = -1; > > - dev->state = DEV_STATE_CREATED; > > - > > - class = object_get_class(OBJECT(dev)); > > - do { > > - for (prop = DEVICE_CLASS(class)->props; prop && prop->name; prop++) { > > - qdev_property_add_legacy(dev, prop, NULL); > > - qdev_property_add_static(dev, prop, NULL); > > - } > > - class = object_class_get_parent(class); > > - } while (class != object_class_by_name(TYPE_DEVICE)); > > - qdev_prop_set_globals(dev); > > - > > - object_property_add_link(OBJECT(dev), "parent_bus", TYPE_BUS, > > - (Object **)&dev->parent_bus, NULL); > > -} > > - > > -/* Unlink device from bus and free the structure. */ > > -static void device_finalize(Object *obj) > > -{ > > - DeviceState *dev = DEVICE(obj); > > - BusState *bus; > > - DeviceClass *dc = DEVICE_GET_CLASS(dev); > > - > > - if (dev->state == DEV_STATE_INITIALIZED) { > > - while (dev->num_child_bus) { > > - bus = QLIST_FIRST(&dev->child_bus); > > - qbus_free(bus); > > - } > > - qdev_finalize_vmstate(dev); > > - if (dc->exit) { > > - dc->exit(dev); > > - } > > - if (dev->opts) { > > - qemu_opts_del(dev->opts); > > - } > > - } > > - if (dev->parent_bus) { > > - bus_remove_child(dev->parent_bus, dev); > > - } > > -} > > - > > -static void device_class_base_init(ObjectClass *class, void *data) > > -{ > > - DeviceClass *klass = DEVICE_CLASS(class); > > - > > - /* We explicitly look up properties in the superclasses, > > - * so do not propagate them to the subclasses. > > - */ > > - klass->props = NULL; > > -} > > - > > -void device_reset(DeviceState *dev) > > -{ > > - DeviceClass *klass = DEVICE_GET_CLASS(dev); > > - > > - if (klass->reset) { > > - klass->reset(dev); > > - } > > -} > > - > > -Object *qdev_get_machine(void) > > -{ > > - static Object *dev; > > - > > - if (dev == NULL) { > > - dev = container_get(object_get_root(), "/machine"); > > - } > > - > > - return dev; > > -} > > - > > -static TypeInfo device_type_info = { > > - .name = TYPE_DEVICE, > > - .parent = TYPE_OBJECT, > > - .instance_size = sizeof(DeviceState), > > - .instance_init = device_initfn, > > - .instance_finalize = device_finalize, > > - .class_base_init = device_class_base_init, > > - .abstract = true, > > - .class_size = sizeof(DeviceClass), > > -}; > > - > > -static void qbus_initfn(Object *obj) > > -{ > > - BusState *bus = BUS(obj); > > - > > - QTAILQ_INIT(&bus->children); > > -} > > - > > -static void qbus_finalize(Object *obj) > > -{ > > - BusState *bus = BUS(obj); > > - BusChild *kid; > > - > > - while ((kid = QTAILQ_FIRST(&bus->children)) != NULL) { > > - DeviceState *dev = kid->child; > > - qdev_free(dev); > > - } > > - if (bus->parent) { > > - QLIST_REMOVE(bus, sibling); > > - bus->parent->num_child_bus--; > > - } else { > > - qbus_unregister_reset(bus); > > - } > > - g_free((char *)bus->name); > > -} > > - > > -static const TypeInfo bus_info = { > > - .name = TYPE_BUS, > > - .parent = TYPE_OBJECT, > > - .instance_size = sizeof(BusState), > > - .abstract = true, > > - .class_size = sizeof(BusClass), > > - .instance_init = qbus_initfn, > > - .instance_finalize = qbus_finalize, > > -}; > > - > > -static void qdev_register_types(void) > > -{ > > - type_register_static(&bus_info); > > - type_register_static(&device_type_info); > > -} > > - > > -type_init(qdev_register_types) > > diff --git a/hw/qdev-properties.c b/hw/qdev-properties.c > > deleted file mode 100644 > > index 2e82cb9..0000000 > > --- a/hw/qdev-properties.c > > +++ /dev/null > > @@ -1,963 +0,0 @@ > > -#include "net.h" > > -#include "hw/qdev.h" > > -#include "qerror.h" > > -#include "blockdev.h" > > -#include "hw/block-common.h" > > -#include "net/hub.h" > > -#include "qapi/qapi-visit-core.h" > > - > > -void *qdev_get_prop_ptr(DeviceState *dev, Property *prop) > > -{ > > - void *ptr = dev; > > - ptr += prop->offset; > > - return ptr; > > -} > > - > > -static void get_enum(Object *obj, Visitor *v, void *opaque, > > - const char *name, Error **errp) > > -{ > > - DeviceState *dev = DEVICE(obj); > > - Property *prop = opaque; > > - int *ptr = qdev_get_prop_ptr(dev, prop); > > - > > - visit_type_enum(v, ptr, prop->info->enum_table, > > - prop->info->name, prop->name, errp); > > -} > > - > > -static void set_enum(Object *obj, Visitor *v, void *opaque, > > - const char *name, Error **errp) > > -{ > > - DeviceState *dev = DEVICE(obj); > > - Property *prop = opaque; > > - int *ptr = qdev_get_prop_ptr(dev, prop); > > - > > - if (dev->state != DEV_STATE_CREATED) { > > - error_set(errp, QERR_PERMISSION_DENIED); > > - return; > > - } > > - > > - visit_type_enum(v, ptr, prop->info->enum_table, > > - prop->info->name, prop->name, errp); > > -} > > - > > -/* Bit */ > > - > > -static uint32_t qdev_get_prop_mask(Property *prop) > > -{ > > - assert(prop->info == &qdev_prop_bit); > > - return 0x1 << prop->bitnr; > > -} > > - > > -static void bit_prop_set(DeviceState *dev, Property *props, bool val) > > -{ > > - uint32_t *p = qdev_get_prop_ptr(dev, props); > > - uint32_t mask = qdev_get_prop_mask(props); > > - if (val) > > - *p |= mask; > > - else > > - *p &= ~mask; > > -} > > - > > -static int print_bit(DeviceState *dev, Property *prop, char *dest, size_t len) > > -{ > > - uint32_t *p = qdev_get_prop_ptr(dev, prop); > > - return snprintf(dest, len, (*p & qdev_get_prop_mask(prop)) ? "on" : "off"); > > -} > > - > > -static void get_bit(Object *obj, Visitor *v, void *opaque, > > - const char *name, Error **errp) > > -{ > > - DeviceState *dev = DEVICE(obj); > > - Property *prop = opaque; > > - uint32_t *p = qdev_get_prop_ptr(dev, prop); > > - bool value = (*p & qdev_get_prop_mask(prop)) != 0; > > - > > - visit_type_bool(v, &value, name, errp); > > -} > > - > > -static void set_bit(Object *obj, Visitor *v, void *opaque, > > - const char *name, Error **errp) > > -{ > > - DeviceState *dev = DEVICE(obj); > > - Property *prop = opaque; > > - Error *local_err = NULL; > > - bool value; > > - > > - if (dev->state != DEV_STATE_CREATED) { > > - error_set(errp, QERR_PERMISSION_DENIED); > > - return; > > - } > > - > > - visit_type_bool(v, &value, name, &local_err); > > - if (local_err) { > > - error_propagate(errp, local_err); > > - return; > > - } > > - bit_prop_set(dev, prop, value); > > -} > > - > > -PropertyInfo qdev_prop_bit = { > > - .name = "boolean", > > - .legacy_name = "on/off", > > - .print = print_bit, > > - .get = get_bit, > > - .set = set_bit, > > -}; > > - > > -/* --- 8bit integer --- */ > > - > > -static void get_uint8(Object *obj, Visitor *v, void *opaque, > > - const char *name, Error **errp) > > -{ > > - DeviceState *dev = DEVICE(obj); > > - Property *prop = opaque; > > - uint8_t *ptr = qdev_get_prop_ptr(dev, prop); > > - > > - visit_type_uint8(v, ptr, name, errp); > > -} > > - > > -static void set_uint8(Object *obj, Visitor *v, void *opaque, > > - const char *name, Error **errp) > > -{ > > - DeviceState *dev = DEVICE(obj); > > - Property *prop = opaque; > > - uint8_t *ptr = qdev_get_prop_ptr(dev, prop); > > - > > - if (dev->state != DEV_STATE_CREATED) { > > - error_set(errp, QERR_PERMISSION_DENIED); > > - return; > > - } > > - > > - visit_type_uint8(v, ptr, name, errp); > > -} > > - > > -PropertyInfo qdev_prop_uint8 = { > > - .name = "uint8", > > - .get = get_uint8, > > - .set = set_uint8, > > -}; > > - > > -/* --- 8bit hex value --- */ > > - > > -static int parse_hex8(DeviceState *dev, Property *prop, const char *str) > > -{ > > - uint8_t *ptr = qdev_get_prop_ptr(dev, prop); > > - char *end; > > - > > - if (str[0] != '0' || str[1] != 'x') { > > - return -EINVAL; > > - } > > - > > - *ptr = strtoul(str, &end, 16); > > - if ((*end != '\0') || (end == str)) { > > - return -EINVAL; > > - } > > - > > - return 0; > > -} > > - > > -static int print_hex8(DeviceState *dev, Property *prop, char *dest, size_t len) > > -{ > > - uint8_t *ptr = qdev_get_prop_ptr(dev, prop); > > - return snprintf(dest, len, "0x%" PRIx8, *ptr); > > -} > > - > > -PropertyInfo qdev_prop_hex8 = { > > - .name = "uint8", > > - .legacy_name = "hex8", > > - .parse = parse_hex8, > > - .print = print_hex8, > > - .get = get_uint8, > > - .set = set_uint8, > > -}; > > - > > -/* --- 16bit integer --- */ > > - > > -static void get_uint16(Object *obj, Visitor *v, void *opaque, > > - const char *name, Error **errp) > > -{ > > - DeviceState *dev = DEVICE(obj); > > - Property *prop = opaque; > > - uint16_t *ptr = qdev_get_prop_ptr(dev, prop); > > - > > - visit_type_uint16(v, ptr, name, errp); > > -} > > - > > -static void set_uint16(Object *obj, Visitor *v, void *opaque, > > - const char *name, Error **errp) > > -{ > > - DeviceState *dev = DEVICE(obj); > > - Property *prop = opaque; > > - uint16_t *ptr = qdev_get_prop_ptr(dev, prop); > > - > > - if (dev->state != DEV_STATE_CREATED) { > > - error_set(errp, QERR_PERMISSION_DENIED); > > - return; > > - } > > - > > - visit_type_uint16(v, ptr, name, errp); > > -} > > - > > -PropertyInfo qdev_prop_uint16 = { > > - .name = "uint16", > > - .get = get_uint16, > > - .set = set_uint16, > > -}; > > - > > -/* --- 32bit integer --- */ > > - > > -static void get_uint32(Object *obj, Visitor *v, void *opaque, > > - const char *name, Error **errp) > > -{ > > - DeviceState *dev = DEVICE(obj); > > - Property *prop = opaque; > > - uint32_t *ptr = qdev_get_prop_ptr(dev, prop); > > - > > - visit_type_uint32(v, ptr, name, errp); > > -} > > - > > -static void set_uint32(Object *obj, Visitor *v, void *opaque, > > - const char *name, Error **errp) > > -{ > > - DeviceState *dev = DEVICE(obj); > > - Property *prop = opaque; > > - uint32_t *ptr = qdev_get_prop_ptr(dev, prop); > > - > > - if (dev->state != DEV_STATE_CREATED) { > > - error_set(errp, QERR_PERMISSION_DENIED); > > - return; > > - } > > - > > - visit_type_uint32(v, ptr, name, errp); > > -} > > - > > -static void get_int32(Object *obj, Visitor *v, void *opaque, > > - const char *name, Error **errp) > > -{ > > - DeviceState *dev = DEVICE(obj); > > - Property *prop = opaque; > > - int32_t *ptr = qdev_get_prop_ptr(dev, prop); > > - > > - visit_type_int32(v, ptr, name, errp); > > -} > > - > > -static void set_int32(Object *obj, Visitor *v, void *opaque, > > - const char *name, Error **errp) > > -{ > > - DeviceState *dev = DEVICE(obj); > > - Property *prop = opaque; > > - int32_t *ptr = qdev_get_prop_ptr(dev, prop); > > - > > - if (dev->state != DEV_STATE_CREATED) { > > - error_set(errp, QERR_PERMISSION_DENIED); > > - return; > > - } > > - > > - visit_type_int32(v, ptr, name, errp); > > -} > > - > > -PropertyInfo qdev_prop_uint32 = { > > - .name = "uint32", > > - .get = get_uint32, > > - .set = set_uint32, > > -}; > > - > > -PropertyInfo qdev_prop_int32 = { > > - .name = "int32", > > - .get = get_int32, > > - .set = set_int32, > > -}; > > - > > -/* --- 32bit hex value --- */ > > - > > -static int parse_hex32(DeviceState *dev, Property *prop, const char *str) > > -{ > > - uint32_t *ptr = qdev_get_prop_ptr(dev, prop); > > - char *end; > > - > > - if (str[0] != '0' || str[1] != 'x') { > > - return -EINVAL; > > - } > > - > > - *ptr = strtoul(str, &end, 16); > > - if ((*end != '\0') || (end == str)) { > > - return -EINVAL; > > - } > > - > > - return 0; > > -} > > - > > -static int print_hex32(DeviceState *dev, Property *prop, char *dest, size_t len) > > -{ > > - uint32_t *ptr = qdev_get_prop_ptr(dev, prop); > > - return snprintf(dest, len, "0x%" PRIx32, *ptr); > > -} > > - > > -PropertyInfo qdev_prop_hex32 = { > > - .name = "uint32", > > - .legacy_name = "hex32", > > - .parse = parse_hex32, > > - .print = print_hex32, > > - .get = get_uint32, > > - .set = set_uint32, > > -}; > > - > > -/* --- 64bit integer --- */ > > - > > -static void get_uint64(Object *obj, Visitor *v, void *opaque, > > - const char *name, Error **errp) > > -{ > > - DeviceState *dev = DEVICE(obj); > > - Property *prop = opaque; > > - uint64_t *ptr = qdev_get_prop_ptr(dev, prop); > > - > > - visit_type_uint64(v, ptr, name, errp); > > -} > > - > > -static void set_uint64(Object *obj, Visitor *v, void *opaque, > > - const char *name, Error **errp) > > -{ > > - DeviceState *dev = DEVICE(obj); > > - Property *prop = opaque; > > - uint64_t *ptr = qdev_get_prop_ptr(dev, prop); > > - > > - if (dev->state != DEV_STATE_CREATED) { > > - error_set(errp, QERR_PERMISSION_DENIED); > > - return; > > - } > > - > > - visit_type_uint64(v, ptr, name, errp); > > -} > > - > > -PropertyInfo qdev_prop_uint64 = { > > - .name = "uint64", > > - .get = get_uint64, > > - .set = set_uint64, > > -}; > > - > > -/* --- 64bit hex value --- */ > > - > > -static int parse_hex64(DeviceState *dev, Property *prop, const char *str) > > -{ > > - uint64_t *ptr = qdev_get_prop_ptr(dev, prop); > > - char *end; > > - > > - if (str[0] != '0' || str[1] != 'x') { > > - return -EINVAL; > > - } > > - > > - *ptr = strtoull(str, &end, 16); > > - if ((*end != '\0') || (end == str)) { > > - return -EINVAL; > > - } > > - > > - return 0; > > -} > > - > > -static int print_hex64(DeviceState *dev, Property *prop, char *dest, size_t len) > > -{ > > - uint64_t *ptr = qdev_get_prop_ptr(dev, prop); > > - return snprintf(dest, len, "0x%" PRIx64, *ptr); > > -} > > - > > -PropertyInfo qdev_prop_hex64 = { > > - .name = "uint64", > > - .legacy_name = "hex64", > > - .parse = parse_hex64, > > - .print = print_hex64, > > - .get = get_uint64, > > - .set = set_uint64, > > -}; > > - > > -/* --- string --- */ > > - > > -static void release_string(Object *obj, const char *name, void *opaque) > > -{ > > - Property *prop = opaque; > > - g_free(*(char **)qdev_get_prop_ptr(DEVICE(obj), prop)); > > -} > > - > > -static int print_string(DeviceState *dev, Property *prop, char *dest, size_t len) > > -{ > > - char **ptr = qdev_get_prop_ptr(dev, prop); > > - if (!*ptr) > > - return snprintf(dest, len, "<null>"); > > - return snprintf(dest, len, "\"%s\"", *ptr); > > -} > > - > > -static void get_string(Object *obj, Visitor *v, void *opaque, > > - const char *name, Error **errp) > > -{ > > - DeviceState *dev = DEVICE(obj); > > - Property *prop = opaque; > > - char **ptr = qdev_get_prop_ptr(dev, prop); > > - > > - if (!*ptr) { > > - char *str = (char *)""; > > - visit_type_str(v, &str, name, errp); > > - } else { > > - visit_type_str(v, ptr, name, errp); > > - } > > -} > > - > > -static void set_string(Object *obj, Visitor *v, void *opaque, > > - const char *name, Error **errp) > > -{ > > - DeviceState *dev = DEVICE(obj); > > - Property *prop = opaque; > > - char **ptr = qdev_get_prop_ptr(dev, prop); > > - Error *local_err = NULL; > > - char *str; > > - > > - if (dev->state != DEV_STATE_CREATED) { > > - error_set(errp, QERR_PERMISSION_DENIED); > > - return; > > - } > > - > > - visit_type_str(v, &str, name, &local_err); > > - if (local_err) { > > - error_propagate(errp, local_err); > > - return; > > - } > > - if (*ptr) { > > - g_free(*ptr); > > - } > > - *ptr = str; > > -} > > - > > -PropertyInfo qdev_prop_string = { > > - .name = "string", > > - .print = print_string, > > - .release = release_string, > > - .get = get_string, > > - .set = set_string, > > -}; > > - > > -/* --- pointer --- */ > > - > > -/* Not a proper property, just for dirty hacks. TODO Remove it! */ > > -PropertyInfo qdev_prop_ptr = { > > - .name = "ptr", > > -}; > > - > > -/* --- mac address --- */ > > - > > -/* > > - * accepted syntax versions: > > - * 01:02:03:04:05:06 > > - * 01-02-03-04-05-06 > > - */ > > -static void get_mac(Object *obj, Visitor *v, void *opaque, > > - const char *name, Error **errp) > > -{ > > - DeviceState *dev = DEVICE(obj); > > - Property *prop = opaque; > > - MACAddr *mac = qdev_get_prop_ptr(dev, prop); > > - char buffer[2 * 6 + 5 + 1]; > > - char *p = buffer; > > - > > - snprintf(buffer, sizeof(buffer), "%02x:%02x:%02x:%02x:%02x:%02x", > > - mac->a[0], mac->a[1], mac->a[2], > > - mac->a[3], mac->a[4], mac->a[5]); > > - > > - visit_type_str(v, &p, name, errp); > > -} > > - > > -static void set_mac(Object *obj, Visitor *v, void *opaque, > > - const char *name, Error **errp) > > -{ > > - DeviceState *dev = DEVICE(obj); > > - Property *prop = opaque; > > - MACAddr *mac = qdev_get_prop_ptr(dev, prop); > > - Error *local_err = NULL; > > - int i, pos; > > - char *str, *p; > > - > > - if (dev->state != DEV_STATE_CREATED) { > > - error_set(errp, QERR_PERMISSION_DENIED); > > - return; > > - } > > - > > - visit_type_str(v, &str, name, &local_err); > > - if (local_err) { > > - error_propagate(errp, local_err); > > - return; > > - } > > - > > - for (i = 0, pos = 0; i < 6; i++, pos += 3) { > > - if (!qemu_isxdigit(str[pos])) > > - goto inval; > > - if (!qemu_isxdigit(str[pos+1])) > > - goto inval; > > - if (i == 5) { > > - if (str[pos+2] != '\0') > > - goto inval; > > - } else { > > - if (str[pos+2] != ':' && str[pos+2] != '-') > > - goto inval; > > - } > > - mac->a[i] = strtol(str+pos, &p, 16); > > - } > > - g_free(str); > > - return; > > - > > -inval: > > - error_set_from_qdev_prop_error(errp, EINVAL, dev, prop, str); > > - g_free(str); > > -} > > - > > -PropertyInfo qdev_prop_macaddr = { > > - .name = "macaddr", > > - .get = get_mac, > > - .set = set_mac, > > -}; > > - > > -/* --- lost tick policy --- */ > > - > > -static const char *lost_tick_policy_table[LOST_TICK_MAX+1] = { > > - [LOST_TICK_DISCARD] = "discard", > > - [LOST_TICK_DELAY] = "delay", > > - [LOST_TICK_MERGE] = "merge", > > - [LOST_TICK_SLEW] = "slew", > > - [LOST_TICK_MAX] = NULL, > > -}; > > - > > -QEMU_BUILD_BUG_ON(sizeof(LostTickPolicy) != sizeof(int)); > > - > > -PropertyInfo qdev_prop_losttickpolicy = { > > - .name = "LostTickPolicy", > > - .enum_table = lost_tick_policy_table, > > - .get = get_enum, > > - .set = set_enum, > > -}; > > - > > -/* --- BIOS CHS translation */ > > - > > -static const char *bios_chs_trans_table[] = { > > - [BIOS_ATA_TRANSLATION_AUTO] = "auto", > > - [BIOS_ATA_TRANSLATION_NONE] = "none", > > - [BIOS_ATA_TRANSLATION_LBA] = "lba", > > -}; > > - > > -PropertyInfo qdev_prop_bios_chs_trans = { > > - .name = "bios-chs-trans", > > - .enum_table = bios_chs_trans_table, > > - .get = get_enum, > > - .set = set_enum, > > -}; > > - > > -/* --- pci address --- */ > > - > > -/* > > - * bus-local address, i.e. "$slot" or "$slot.$fn" > > - */ > > -static void set_pci_devfn(Object *obj, Visitor *v, void *opaque, > > - const char *name, Error **errp) > > -{ > > - DeviceState *dev = DEVICE(obj); > > - Property *prop = opaque; > > - int32_t value, *ptr = qdev_get_prop_ptr(dev, prop); > > - unsigned int slot, fn, n; > > - Error *local_err = NULL; > > - char *str; > > - > > - if (dev->state != DEV_STATE_CREATED) { > > - error_set(errp, QERR_PERMISSION_DENIED); > > - return; > > - } > > - > > - visit_type_str(v, &str, name, &local_err); > > - if (local_err) { > > - error_free(local_err); > > - local_err = NULL; > > - visit_type_int32(v, &value, name, &local_err); > > - if (local_err) { > > - error_propagate(errp, local_err); > > - } else if (value < -1 || value > 255) { > > - error_set(errp, QERR_INVALID_PARAMETER_VALUE, name ? name : "null", > > - "pci_devfn"); > > - } else { > > - *ptr = value; > > - } > > - return; > > - } > > - > > - if (sscanf(str, "%x.%x%n", &slot, &fn, &n) != 2) { > > - fn = 0; > > - if (sscanf(str, "%x%n", &slot, &n) != 1) { > > - goto invalid; > > - } > > - } > > - if (str[n] != '\0' || fn > 7 || slot > 31) { > > - goto invalid; > > - } > > - *ptr = slot << 3 | fn; > > - g_free(str); > > - return; > > - > > -invalid: > > - error_set_from_qdev_prop_error(errp, EINVAL, dev, prop, str); > > - g_free(str); > > -} > > - > > -static int print_pci_devfn(DeviceState *dev, Property *prop, char *dest, size_t len) > > -{ > > - int32_t *ptr = qdev_get_prop_ptr(dev, prop); > > - > > - if (*ptr == -1) { > > - return snprintf(dest, len, "<unset>"); > > - } else { > > - return snprintf(dest, len, "%02x.%x", *ptr >> 3, *ptr & 7); > > - } > > -} > > - > > -PropertyInfo qdev_prop_pci_devfn = { > > - .name = "int32", > > - .legacy_name = "pci-devfn", > > - .print = print_pci_devfn, > > - .get = get_int32, > > - .set = set_pci_devfn, > > -}; > > - > > -/* --- blocksize --- */ > > - > > -static void set_blocksize(Object *obj, Visitor *v, void *opaque, > > - const char *name, Error **errp) > > -{ > > - DeviceState *dev = DEVICE(obj); > > - Property *prop = opaque; > > - uint16_t value, *ptr = qdev_get_prop_ptr(dev, prop); > > - Error *local_err = NULL; > > - const int64_t min = 512; > > - const int64_t max = 32768; > > - > > - if (dev->state != DEV_STATE_CREATED) { > > - error_set(errp, QERR_PERMISSION_DENIED); > > - return; > > - } > > - > > - visit_type_uint16(v, &value, name, &local_err); > > - if (local_err) { > > - error_propagate(errp, local_err); > > - return; > > - } > > - if (value < min || value > max) { > > - error_set(errp, QERR_PROPERTY_VALUE_OUT_OF_RANGE, > > - dev->id?:"", name, (int64_t)value, min, max); > > - return; > > - } > > - > > - /* We rely on power-of-2 blocksizes for bitmasks */ > > - if ((value & (value - 1)) != 0) { > > - error_set(errp, QERR_PROPERTY_VALUE_NOT_POWER_OF_2, > > - dev->id?:"", name, (int64_t)value); > > - return; > > - } > > - > > - *ptr = value; > > -} > > - > > -PropertyInfo qdev_prop_blocksize = { > > - .name = "blocksize", > > - .get = get_uint16, > > - .set = set_blocksize, > > -}; > > - > > -/* --- pci host address --- */ > > - > > -static void get_pci_host_devaddr(Object *obj, Visitor *v, void *opaque, > > - const char *name, Error **errp) > > -{ > > - DeviceState *dev = DEVICE(obj); > > - Property *prop = opaque; > > - PCIHostDeviceAddress *addr = qdev_get_prop_ptr(dev, prop); > > - char buffer[] = "xxxx:xx:xx.x"; > > - char *p = buffer; > > - int rc = 0; > > - > > - rc = snprintf(buffer, sizeof(buffer), "%04x:%02x:%02x.%d", > > - addr->domain, addr->bus, addr->slot, addr->function); > > - assert(rc == sizeof(buffer) - 1); > > - > > - visit_type_str(v, &p, name, errp); > > -} > > - > > -/* > > - * Parse [<domain>:]<bus>:<slot>.<func> > > - * if <domain> is not supplied, it's assumed to be 0. > > - */ > > -static void set_pci_host_devaddr(Object *obj, Visitor *v, void *opaque, > > - const char *name, Error **errp) > > -{ > > - DeviceState *dev = DEVICE(obj); > > - Property *prop = opaque; > > - PCIHostDeviceAddress *addr = qdev_get_prop_ptr(dev, prop); > > - Error *local_err = NULL; > > - char *str, *p; > > - char *e; > > - unsigned long val; > > - unsigned long dom = 0, bus = 0; > > - unsigned int slot = 0, func = 0; > > - > > - if (dev->state != DEV_STATE_CREATED) { > > - error_set(errp, QERR_PERMISSION_DENIED); > > - return; > > - } > > - > > - visit_type_str(v, &str, name, &local_err); > > - if (local_err) { > > - error_propagate(errp, local_err); > > - return; > > - } > > - > > - p = str; > > - val = strtoul(p, &e, 16); > > - if (e == p || *e != ':') { > > - goto inval; > > - } > > - bus = val; > > - > > - p = e + 1; > > - val = strtoul(p, &e, 16); > > - if (e == p) { > > - goto inval; > > - } > > - if (*e == ':') { > > - dom = bus; > > - bus = val; > > - p = e + 1; > > - val = strtoul(p, &e, 16); > > - if (e == p) { > > - goto inval; > > - } > > - } > > - slot = val; > > - > > - if (*e != '.') { > > - goto inval; > > - } > > - p = e + 1; > > - val = strtoul(p, &e, 10); > > - if (e == p) { > > - goto inval; > > - } > > - func = val; > > - > > - if (dom > 0xffff || bus > 0xff || slot > 0x1f || func > 7) { > > - goto inval; > > - } > > - > > - if (*e) { > > - goto inval; > > - } > > - > > - addr->domain = dom; > > - addr->bus = bus; > > - addr->slot = slot; > > - addr->function = func; > > - > > - g_free(str); > > - return; > > - > > -inval: > > - error_set_from_qdev_prop_error(errp, EINVAL, dev, prop, str); > > - g_free(str); > > -} > > - > > -PropertyInfo qdev_prop_pci_host_devaddr = { > > - .name = "pci-host-devaddr", > > - .get = get_pci_host_devaddr, > > - .set = set_pci_host_devaddr, > > -}; > > - > > -/* --- public helpers --- */ > > - > > -static Property *qdev_prop_walk(Property *props, const char *name) > > -{ > > - if (!props) > > - return NULL; > > - while (props->name) { > > - if (strcmp(props->name, name) == 0) > > - return props; > > - props++; > > - } > > - return NULL; > > -} > > - > > -static Property *qdev_prop_find(DeviceState *dev, const char *name) > > -{ > > - ObjectClass *class; > > - Property *prop; > > - > > - /* device properties */ > > - class = object_get_class(OBJECT(dev)); > > - do { > > - prop = qdev_prop_walk(DEVICE_CLASS(class)->props, name); > > - if (prop) { > > - return prop; > > - } > > - class = object_class_get_parent(class); > > - } while (class != object_class_by_name(TYPE_DEVICE)); > > - > > - return NULL; > > -} > > - > > -void error_set_from_qdev_prop_error(Error **errp, int ret, DeviceState *dev, > > - Property *prop, const char *value) > > -{ > > - switch (ret) { > > - case -EEXIST: > > - error_set(errp, QERR_PROPERTY_VALUE_IN_USE, > > - object_get_typename(OBJECT(dev)), prop->name, value); > > - break; > > - default: > > - case -EINVAL: > > - error_set(errp, QERR_PROPERTY_VALUE_BAD, > > - object_get_typename(OBJECT(dev)), prop->name, value); > > - break; > > - case -ENOENT: > > - error_set(errp, QERR_PROPERTY_VALUE_NOT_FOUND, > > - object_get_typename(OBJECT(dev)), prop->name, value); > > - break; > > - case 0: > > - break; > > - } > > -} > > - > > -int qdev_prop_parse(DeviceState *dev, const char *name, const char *value) > > -{ > > - char *legacy_name; > > - Error *err = NULL; > > - > > - legacy_name = g_strdup_printf("legacy-%s", name); > > - if (object_property_get_type(OBJECT(dev), legacy_name, NULL)) { > > - object_property_parse(OBJECT(dev), value, legacy_name, &err); > > - } else { > > - object_property_parse(OBJECT(dev), value, name, &err); > > - } > > - g_free(legacy_name); > > - > > - if (err) { > > - qerror_report_err(err); > > - error_free(err); > > - return -1; > > - } > > - return 0; > > -} > > - > > -void qdev_prop_set_bit(DeviceState *dev, const char *name, bool value) > > -{ > > - Error *errp = NULL; > > - object_property_set_bool(OBJECT(dev), value, name, &errp); > > - assert_no_error(errp); > > -} > > - > > -void qdev_prop_set_uint8(DeviceState *dev, const char *name, uint8_t value) > > -{ > > - Error *errp = NULL; > > - object_property_set_int(OBJECT(dev), value, name, &errp); > > - assert_no_error(errp); > > -} > > - > > -void qdev_prop_set_uint16(DeviceState *dev, const char *name, uint16_t value) > > -{ > > - Error *errp = NULL; > > - object_property_set_int(OBJECT(dev), value, name, &errp); > > - assert_no_error(errp); > > -} > > - > > -void qdev_prop_set_uint32(DeviceState *dev, const char *name, uint32_t value) > > -{ > > - Error *errp = NULL; > > - object_property_set_int(OBJECT(dev), value, name, &errp); > > - assert_no_error(errp); > > -} > > - > > -void qdev_prop_set_int32(DeviceState *dev, const char *name, int32_t value) > > -{ > > - Error *errp = NULL; > > - object_property_set_int(OBJECT(dev), value, name, &errp); > > - assert_no_error(errp); > > -} > > - > > -void qdev_prop_set_uint64(DeviceState *dev, const char *name, uint64_t value) > > -{ > > - Error *errp = NULL; > > - object_property_set_int(OBJECT(dev), value, name, &errp); > > - assert_no_error(errp); > > -} > > - > > -void qdev_prop_set_string(DeviceState *dev, const char *name, const char *value) > > -{ > > - Error *errp = NULL; > > - object_property_set_str(OBJECT(dev), value, name, &errp); > > - assert_no_error(errp); > > -} > > - > > -void qdev_prop_set_macaddr(DeviceState *dev, const char *name, uint8_t *value) > > -{ > > - Error *errp = NULL; > > - char str[2 * 6 + 5 + 1]; > > - snprintf(str, sizeof(str), "%02x:%02x:%02x:%02x:%02x:%02x", > > - value[0], value[1], value[2], value[3], value[4], value[5]); > > - > > - object_property_set_str(OBJECT(dev), str, name, &errp); > > - assert_no_error(errp); > > -} > > - > > -void qdev_prop_set_enum(DeviceState *dev, const char *name, int value) > > -{ > > - Property *prop; > > - Error *errp = NULL; > > - > > - prop = qdev_prop_find(dev, name); > > - object_property_set_str(OBJECT(dev), prop->info->enum_table[value], > > - name, &errp); > > - assert_no_error(errp); > > -} > > - > > -void qdev_prop_set_ptr(DeviceState *dev, const char *name, void *value) > > -{ > > - Property *prop; > > - void **ptr; > > - > > - prop = qdev_prop_find(dev, name); > > - assert(prop && prop->info == &qdev_prop_ptr); > > - ptr = qdev_get_prop_ptr(dev, prop); > > - *ptr = value; > > -} > > - > > -static QTAILQ_HEAD(, GlobalProperty) global_props = QTAILQ_HEAD_INITIALIZER(global_props); > > - > > -void qdev_prop_register_global(GlobalProperty *prop) > > -{ > > - QTAILQ_INSERT_TAIL(&global_props, prop, next); > > -} > > - > > -void qdev_prop_register_global_list(GlobalProperty *props) > > -{ > > - int i; > > - > > - for (i = 0; props[i].driver != NULL; i++) { > > - qdev_prop_register_global(props+i); > > - } > > -} > > - > > -void qdev_prop_set_globals(DeviceState *dev) > > -{ > > - ObjectClass *class = object_get_class(OBJECT(dev)); > > - > > - do { > > - GlobalProperty *prop; > > - QTAILQ_FOREACH(prop, &global_props, next) { > > - if (strcmp(object_class_get_name(class), prop->driver) != 0) { > > - continue; > > - } > > - if (qdev_prop_parse(dev, prop->property, prop->value) != 0) { > > - exit(1); > > - } > > - } > > - class = object_class_get_parent(class); > > - } while (class); > > -} > > - > > diff --git a/qom/Makefile.objs b/qom/Makefile.objs > > index 5ef060a..09ef871 100644 > > --- a/qom/Makefile.objs > > +++ b/qom/Makefile.objs > > @@ -1,4 +1,4 @@ > > qom-obj-y = object.o container.o qom-qobject.o > > -qom-obj-twice-y = cpu.o > > +qom-obj-twice-y = cpu.o qdev-core.o qdev-properties.o > > common-obj-y = $(qom-obj-twice-y) > > user-obj-y = $(qom-obj-twice-y) > > diff --git a/qom/qdev-core.c b/qom/qdev-core.c > > new file mode 100644 > > index 0000000..fbb7cb5 > > --- /dev/null > > +++ b/qom/qdev-core.c > > @@ -0,0 +1,727 @@ > > +/* > > + * Dynamic device configuration and creation. > > + * > > + * Copyright (c) 2009 CodeSourcery > > + * > > + * This library is free software; you can redistribute it and/or > > + * modify it under the terms of the GNU Lesser General Public > > + * License as published by the Free Software Foundation; either > > + * version 2 of the License, or (at your option) any later version. > > + * > > + * This library is distributed in the hope that it will be useful, > > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > > + * Lesser General Public License for more details. > > + * > > + * You should have received a copy of the GNU Lesser General Public > > + * License along with this library; if not, see <http://www.gnu.org/licenses/>. > > + */ > > + > > +/* The theory here is that it should be possible to create a machine without > > + knowledge of specific devices. Historically board init routines have > > + passed a bunch of arguments to each device, requiring the board know > > + exactly which device it is dealing with. This file provides an abstract > > + API for device configuration and initialization. Devices will generally > > + inherit from a particular bus (e.g. PCI or I2C) rather than > > + this API directly. */ > > + > > +#include "hw/qdev.h" > > +#include "sysemu.h" > > +#include "error.h" > > +#include "qapi/qapi-visit-core.h" > > + > > +int qdev_hotplug = 0; > > +static bool qdev_hot_added = false; > > +static bool qdev_hot_removed = false; > > + > > +/* vmstate handling: > > + * > > + * The real implementations are on qdev-system.c. Those are weak symbols > > + * used by *-user. > > + */ > > +void GCC_WEAK qdev_init_vmstate(DeviceState *dev) > > +{ > > +} > > + > > +void GCC_WEAK qdev_finalize_vmstate(DeviceState *dev) > > +{ > > +} > > + > > +/* reset handler register/unregister: > > + * > > + * The real implementations are on qdev-system.c. Those are weak symbols > > + * used by *-user. > > + */ > > +void GCC_WEAK qbus_register_reset(BusState *bus) > > +{ > > +} > > + > > +void GCC_WEAK qbus_unregister_reset(BusState *bus) > > +{ > > +} > > + > > +const char *qdev_fw_name(DeviceState *dev) > > +{ > > + DeviceClass *dc = DEVICE_GET_CLASS(dev); > > + > > + if (dc->fw_name) { > > + return dc->fw_name; > > + } > > + > > + return object_get_typename(OBJECT(dev)); > > +} > > + > > +static void qdev_property_add_legacy(DeviceState *dev, Property *prop, > > + Error **errp); > > + > > +static void bus_remove_child(BusState *bus, DeviceState *child) > > +{ > > + BusChild *kid; > > + > > + QTAILQ_FOREACH(kid, &bus->children, sibling) { > > + if (kid->child == child) { > > + char name[32]; > > + > > + snprintf(name, sizeof(name), "child[%d]", kid->index); > > + QTAILQ_REMOVE(&bus->children, kid, sibling); > > + object_property_del(OBJECT(bus), name, NULL); > > + g_free(kid); > > + return; > > + } > > + } > > +} > > + > > +static void bus_add_child(BusState *bus, DeviceState *child) > > +{ > > + char name[32]; > > + BusChild *kid = g_malloc0(sizeof(*kid)); > > + > > + if (qdev_hotplug) { > > + assert(bus->allow_hotplug); > > + } > > + > > + kid->index = bus->max_index++; > > + kid->child = child; > > + > > + QTAILQ_INSERT_HEAD(&bus->children, kid, sibling); > > + > > + snprintf(name, sizeof(name), "child[%d]", kid->index); > > + object_property_add_link(OBJECT(bus), name, > > + object_get_typename(OBJECT(child)), > > + (Object **)&kid->child, > > + NULL); > > +} > > + > > +void qdev_set_parent_bus(DeviceState *dev, BusState *bus) > > +{ > > + dev->parent_bus = bus; > > + bus_add_child(bus, 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. > > + On failure, destroy the device and return negative value. > > + Return 0 on success. */ > > +int qdev_init(DeviceState *dev) > > +{ > > + DeviceClass *dc = DEVICE_GET_CLASS(dev); > > + int rc; > > + > > + assert(dev->state == DEV_STATE_CREATED); > > + > > + rc = dc->init(dev); > > + if (rc < 0) { > > + qdev_free(dev); > > + return rc; > > + } > > + > > + if (!OBJECT(dev)->parent) { > > + static int unattached_count = 0; > > + gchar *name = g_strdup_printf("device[%d]", unattached_count++); > > + > > + object_property_add_child(container_get(qdev_get_machine(), > > + "/unattached"), > > + name, OBJECT(dev), NULL); > > + g_free(name); > > + } > > + > > + qdev_init_vmstate(dev); > > + dev->state = DEV_STATE_INITIALIZED; > > + if (dev->hotplugged) { > > + device_reset(dev); > > + } > > + 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; > > +} > > + > > +void qdev_unplug(DeviceState *dev, Error **errp) > > +{ > > + DeviceClass *dc = DEVICE_GET_CLASS(dev); > > + > > + if (!dev->parent_bus->allow_hotplug) { > > + error_set(errp, QERR_BUS_NO_HOTPLUG, dev->parent_bus->name); > > + return; > > + } > > + assert(dc->unplug != NULL); > > + > > + qdev_hot_removed = true; > > + > > + if (dc->unplug(dev) < 0) { > > + error_set(errp, QERR_UNDEFINED_ERROR); > > + return; > > + } > > +} > > + > > +static int qdev_reset_one(DeviceState *dev, void *opaque) > > +{ > > + device_reset(dev); > > + > > + return 0; > > +} > > + > > +static int qbus_reset_one(BusState *bus, void *opaque) > > +{ > > + BusClass *bc = BUS_GET_CLASS(bus); > > + if (bc->reset) { > > + return bc->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_fn(void *opaque) > > +{ > > + BusState *bus = opaque; > > + 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) > > +{ > > + /* just zap it */ > > + qdev_free(dev); > > + return 0; > > +} > > + > > + > > +/* Like qdev_init(), but terminate program via error_report() instead of > > + returning an error value. This is okay during machine creation. > > + Don't use for hotplug, because there callers need to recover from > > + failure. Exception: if you know the device's init() callback can't > > + fail, then qdev_init_nofail() can't fail either, and is therefore > > + usable even then. But relying on the device implementation that > > + way is somewhat unclean, and best avoided. */ > > +void qdev_init_nofail(DeviceState *dev) > > +{ > > + const char *typename = object_get_typename(OBJECT(dev)); > > + > > + if (qdev_init(dev) < 0) { > > + error_report("Initialization of device %s failed", typename); > > + exit(1); > > + } > > +} > > + > > +/* Unlink device from bus and free the structure. */ > > +void qdev_free(DeviceState *dev) > > +{ > > + object_delete(OBJECT(dev)); > > +} > > + > > +void qdev_machine_creation_done(void) > > +{ > > + /* > > + * ok, initial machine setup is done, starting from now we can > > + * only create hotpluggable devices > > + */ > > + qdev_hotplug = 1; > > +} > > + > > +bool qdev_machine_modified(void) > > +{ > > + return qdev_hot_added || qdev_hot_removed; > > +} > > + > > +BusState *qdev_get_parent_bus(DeviceState *dev) > > +{ > > + return dev->parent_bus; > > +} > > + > > +BusState *qdev_get_child_bus(DeviceState *dev, const char *name) > > +{ > > + BusState *bus; > > + > > + QLIST_FOREACH(bus, &dev->child_bus, sibling) { > > + if (strcmp(name, bus->name) == 0) { > > + return bus; > > + } > > + } > > + return NULL; > > +} > > + > > +int qbus_walk_children(BusState *bus, qdev_walkerfn *devfn, > > + qbus_walkerfn *busfn, void *opaque) > > +{ > > + BusChild *kid; > > + int err; > > + > > + if (busfn) { > > + err = busfn(bus, opaque); > > + if (err) { > > + return err; > > + } > > + } > > + > > + QTAILQ_FOREACH(kid, &bus->children, sibling) { > > + err = qdev_walk_children(kid->child, 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; > > +} > > + > > +DeviceState *qdev_find_recursive(BusState *bus, const char *id) > > +{ > > + BusChild *kid; > > + DeviceState *ret; > > + BusState *child; > > + > > + QTAILQ_FOREACH(kid, &bus->children, sibling) { > > + DeviceState *dev = kid->child; > > + > > + if (dev->id && strcmp(dev->id, id) == 0) { > > + return dev; > > + } > > + > > + QLIST_FOREACH(child, &dev->child_bus, sibling) { > > + ret = qdev_find_recursive(child, id); > > + if (ret) { > > + return ret; > > + } > > + } > > + } > > + return NULL; > > +} > > + > > +static void qbus_realize(BusState *bus) > > +{ > > + const char *typename = object_get_typename(OBJECT(bus)); > > + char *buf; > > + int i,len; > > + > > + if (bus->name) { > > + /* use supplied name */ > > + } else if (bus->parent && bus->parent->id) { > > + /* parent device has id -> use it for bus name */ > > + len = strlen(bus->parent->id) + 16; > > + buf = g_malloc(len); > > + snprintf(buf, len, "%s.%d", bus->parent->id, bus->parent->num_child_bus); > > + bus->name = buf; > > + } else { > > + /* no id -> use lowercase bus type for bus name */ > > + len = strlen(typename) + 16; > > + buf = g_malloc(len); > > + len = snprintf(buf, len, "%s.%d", typename, > > + bus->parent ? bus->parent->num_child_bus : 0); > > + for (i = 0; i < len; i++) > > + buf[i] = qemu_tolower(buf[i]); > > + bus->name = buf; > > + } > > + > > + if (bus->parent) { > > + QLIST_INSERT_HEAD(&bus->parent->child_bus, bus, sibling); > > + bus->parent->num_child_bus++; > > + object_property_add_child(OBJECT(bus->parent), bus->name, OBJECT(bus), NULL); > > + } else { > > + qbus_register_reset(bus); > > + } > > +} > > + > > +void qbus_create_inplace(BusState *bus, const char *typename, > > + DeviceState *parent, const char *name) > > +{ > > + object_initialize(bus, typename); > > + > > + bus->parent = parent; > > + bus->name = name ? g_strdup(name) : NULL; > > + qbus_realize(bus); > > +} > > + > > +BusState *qbus_create(const char *typename, DeviceState *parent, const char *name) > > +{ > > + BusState *bus; > > + > > + bus = BUS(object_new(typename)); > > + bus->qom_allocated = true; > > + > > + bus->parent = parent; > > + bus->name = name ? g_strdup(name) : NULL; > > + qbus_realize(bus); > > + > > + return bus; > > +} > > + > > +void qbus_free(BusState *bus) > > +{ > > + if (bus->qom_allocated) { > > + object_delete(OBJECT(bus)); > > + } else { > > + object_finalize(OBJECT(bus)); > > + if (bus->glib_allocated) { > > + g_free(bus); > > + } > > + } > > +} > > + > > +static char *bus_get_fw_dev_path(BusState *bus, DeviceState *dev) > > +{ > > + BusClass *bc = BUS_GET_CLASS(bus); > > + > > + if (bc->get_fw_dev_path) { > > + return bc->get_fw_dev_path(dev); > > + } > > + > > + return NULL; > > +} > > + > > +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); > > + d = bus_get_fw_dev_path(dev->parent_bus, dev); > > + if (d) { > > + l += snprintf(p + l, size - l, "%s", d); > > + g_free(d); > > + } else { > > + l += snprintf(p + l, size - l, "%s", object_get_typename(OBJECT(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 g_strdup(path); > > +} > > + > > +char *qdev_get_dev_path(DeviceState *dev) > > +{ > > + BusClass *bc; > > + > > + if (!dev || !dev->parent_bus) { > > + return NULL; > > + } > > + > > + bc = BUS_GET_CLASS(dev->parent_bus); > > + if (bc->get_dev_path) { > > + return bc->get_dev_path(dev); > > + } > > + > > + return NULL; > > +} > > + > > +/** > > + * Legacy property handling > > + */ > > + > > +static void qdev_get_legacy_property(Object *obj, Visitor *v, void *opaque, > > + const char *name, Error **errp) > > +{ > > + 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); > > +} > > + > > +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; > > + } > > + > > + 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 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) > > +{ > > + gchar *name, *type; > > + > > + /* Register pointer properties as legacy properties */ > > + if (!prop->info->print && !prop->info->parse && > > + (prop->info->set || prop->info->get)) { > > + return; > > + } > > + > > + 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) > > +{ > > + Error *local_err = NULL; > > + Object *obj = OBJECT(dev); > > + > > + /* > > + * 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; > > + } > > + > > + object_property_add(obj, prop->name, prop->info->name, > > + prop->info->get, prop->info->set, > > + prop->info->release, > > + prop, &local_err); > > + > > + if (local_err) { > > + error_propagate(errp, local_err); > > + return; > > + } > > + if (prop->qtype == QTYPE_NONE) { > > + return; > > + } > > + > > + if (prop->qtype == QTYPE_QBOOL) { > > + object_property_set_bool(obj, prop->defval, prop->name, &local_err); > > + } else if (prop->info->enum_table) { > > + object_property_set_str(obj, prop->info->enum_table[prop->defval], > > + prop->name, &local_err); > > + } else if (prop->qtype == QTYPE_QINT) { > > + object_property_set_int(obj, prop->defval, prop->name, &local_err); > > + } > > + assert_no_error(local_err); > > +} > > + > > +static void device_initfn(Object *obj) > > +{ > > + DeviceState *dev = DEVICE(obj); > > + ObjectClass *class; > > + Property *prop; > > + > > + if (qdev_hotplug) { > > + dev->hotplugged = 1; > > + qdev_hot_added = true; > > + } > > + > > + dev->instance_id_alias = -1; > > + dev->state = DEV_STATE_CREATED; > > + > > + class = object_get_class(OBJECT(dev)); > > + do { > > + for (prop = DEVICE_CLASS(class)->props; prop && prop->name; prop++) { > > + qdev_property_add_legacy(dev, prop, NULL); > > + qdev_property_add_static(dev, prop, NULL); > > + } > > + class = object_class_get_parent(class); > > + } while (class != object_class_by_name(TYPE_DEVICE)); > > + qdev_prop_set_globals(dev); > > + > > + object_property_add_link(OBJECT(dev), "parent_bus", TYPE_BUS, > > + (Object **)&dev->parent_bus, NULL); > > +} > > + > > +/* Unlink device from bus and free the structure. */ > > +static void device_finalize(Object *obj) > > +{ > > + DeviceState *dev = DEVICE(obj); > > + BusState *bus; > > + DeviceClass *dc = DEVICE_GET_CLASS(dev); > > + > > + if (dev->state == DEV_STATE_INITIALIZED) { > > + while (dev->num_child_bus) { > > + bus = QLIST_FIRST(&dev->child_bus); > > + qbus_free(bus); > > + } > > + qdev_finalize_vmstate(dev); > > + if (dc->exit) { > > + dc->exit(dev); > > + } > > + if (dev->opts) { > > + qemu_opts_del(dev->opts); > > + } > > + } > > + if (dev->parent_bus) { > > + bus_remove_child(dev->parent_bus, dev); > > + } > > +} > > + > > +static void device_class_base_init(ObjectClass *class, void *data) > > +{ > > + DeviceClass *klass = DEVICE_CLASS(class); > > + > > + /* We explicitly look up properties in the superclasses, > > + * so do not propagate them to the subclasses. > > + */ > > + klass->props = NULL; > > +} > > + > > +void device_reset(DeviceState *dev) > > +{ > > + DeviceClass *klass = DEVICE_GET_CLASS(dev); > > + > > + if (klass->reset) { > > + klass->reset(dev); > > + } > > +} > > + > > +Object *qdev_get_machine(void) > > +{ > > + static Object *dev; > > + > > + if (dev == NULL) { > > + dev = container_get(object_get_root(), "/machine"); > > + } > > + > > + return dev; > > +} > > + > > +static TypeInfo device_type_info = { > > + .name = TYPE_DEVICE, > > + .parent = TYPE_OBJECT, > > + .instance_size = sizeof(DeviceState), > > + .instance_init = device_initfn, > > + .instance_finalize = device_finalize, > > + .class_base_init = device_class_base_init, > > + .abstract = true, > > + .class_size = sizeof(DeviceClass), > > +}; > > + > > +static void qbus_initfn(Object *obj) > > +{ > > + BusState *bus = BUS(obj); > > + > > + QTAILQ_INIT(&bus->children); > > +} > > + > > +static void qbus_finalize(Object *obj) > > +{ > > + BusState *bus = BUS(obj); > > + BusChild *kid; > > + > > + while ((kid = QTAILQ_FIRST(&bus->children)) != NULL) { > > + DeviceState *dev = kid->child; > > + qdev_free(dev); > > + } > > + if (bus->parent) { > > + QLIST_REMOVE(bus, sibling); > > + bus->parent->num_child_bus--; > > + } else { > > + qbus_unregister_reset(bus); > > + } > > + g_free((char *)bus->name); > > +} > > + > > +static const TypeInfo bus_info = { > > + .name = TYPE_BUS, > > + .parent = TYPE_OBJECT, > > + .instance_size = sizeof(BusState), > > + .abstract = true, > > + .class_size = sizeof(BusClass), > > + .instance_init = qbus_initfn, > > + .instance_finalize = qbus_finalize, > > +}; > > + > > +static void qdev_register_types(void) > > +{ > > + type_register_static(&bus_info); > > + type_register_static(&device_type_info); > > +} > > + > > +type_init(qdev_register_types) > > diff --git a/qom/qdev-properties.c b/qom/qdev-properties.c > > new file mode 100644 > > index 0000000..2e82cb9 > > --- /dev/null > > +++ b/qom/qdev-properties.c > > @@ -0,0 +1,963 @@ > > +#include "net.h" > > +#include "hw/qdev.h" > > +#include "qerror.h" > > +#include "blockdev.h" > > +#include "hw/block-common.h" > > +#include "net/hub.h" > > +#include "qapi/qapi-visit-core.h" > > + > > +void *qdev_get_prop_ptr(DeviceState *dev, Property *prop) > > +{ > > + void *ptr = dev; > > + ptr += prop->offset; > > + return ptr; > > +} > > + > > +static void get_enum(Object *obj, Visitor *v, void *opaque, > > + const char *name, Error **errp) > > +{ > > + DeviceState *dev = DEVICE(obj); > > + Property *prop = opaque; > > + int *ptr = qdev_get_prop_ptr(dev, prop); > > + > > + visit_type_enum(v, ptr, prop->info->enum_table, > > + prop->info->name, prop->name, errp); > > +} > > + > > +static void set_enum(Object *obj, Visitor *v, void *opaque, > > + const char *name, Error **errp) > > +{ > > + DeviceState *dev = DEVICE(obj); > > + Property *prop = opaque; > > + int *ptr = qdev_get_prop_ptr(dev, prop); > > + > > + if (dev->state != DEV_STATE_CREATED) { > > + error_set(errp, QERR_PERMISSION_DENIED); > > + return; > > + } > > + > > + visit_type_enum(v, ptr, prop->info->enum_table, > > + prop->info->name, prop->name, errp); > > +} > > + > > +/* Bit */ > > + > > +static uint32_t qdev_get_prop_mask(Property *prop) > > +{ > > + assert(prop->info == &qdev_prop_bit); > > + return 0x1 << prop->bitnr; > > +} > > + > > +static void bit_prop_set(DeviceState *dev, Property *props, bool val) > > +{ > > + uint32_t *p = qdev_get_prop_ptr(dev, props); > > + uint32_t mask = qdev_get_prop_mask(props); > > + if (val) > > + *p |= mask; > > + else > > + *p &= ~mask; > > +} > > + > > +static int print_bit(DeviceState *dev, Property *prop, char *dest, size_t len) > > +{ > > + uint32_t *p = qdev_get_prop_ptr(dev, prop); > > + return snprintf(dest, len, (*p & qdev_get_prop_mask(prop)) ? "on" : "off"); > > +} > > + > > +static void get_bit(Object *obj, Visitor *v, void *opaque, > > + const char *name, Error **errp) > > +{ > > + DeviceState *dev = DEVICE(obj); > > + Property *prop = opaque; > > + uint32_t *p = qdev_get_prop_ptr(dev, prop); > > + bool value = (*p & qdev_get_prop_mask(prop)) != 0; > > + > > + visit_type_bool(v, &value, name, errp); > > +} > > + > > +static void set_bit(Object *obj, Visitor *v, void *opaque, > > + const char *name, Error **errp) > > +{ > > + DeviceState *dev = DEVICE(obj); > > + Property *prop = opaque; > > + Error *local_err = NULL; > > + bool value; > > + > > + if (dev->state != DEV_STATE_CREATED) { > > + error_set(errp, QERR_PERMISSION_DENIED); > > + return; > > + } > > + > > + visit_type_bool(v, &value, name, &local_err); > > + if (local_err) { > > + error_propagate(errp, local_err); > > + return; > > + } > > + bit_prop_set(dev, prop, value); > > +} > > + > > +PropertyInfo qdev_prop_bit = { > > + .name = "boolean", > > + .legacy_name = "on/off", > > + .print = print_bit, > > + .get = get_bit, > > + .set = set_bit, > > +}; > > + > > +/* --- 8bit integer --- */ > > + > > +static void get_uint8(Object *obj, Visitor *v, void *opaque, > > + const char *name, Error **errp) > > +{ > > + DeviceState *dev = DEVICE(obj); > > + Property *prop = opaque; > > + uint8_t *ptr = qdev_get_prop_ptr(dev, prop); > > + > > + visit_type_uint8(v, ptr, name, errp); > > +} > > + > > +static void set_uint8(Object *obj, Visitor *v, void *opaque, > > + const char *name, Error **errp) > > +{ > > + DeviceState *dev = DEVICE(obj); > > + Property *prop = opaque; > > + uint8_t *ptr = qdev_get_prop_ptr(dev, prop); > > + > > + if (dev->state != DEV_STATE_CREATED) { > > + error_set(errp, QERR_PERMISSION_DENIED); > > + return; > > + } > > + > > + visit_type_uint8(v, ptr, name, errp); > > +} > > + > > +PropertyInfo qdev_prop_uint8 = { > > + .name = "uint8", > > + .get = get_uint8, > > + .set = set_uint8, > > +}; > > + > > +/* --- 8bit hex value --- */ > > + > > +static int parse_hex8(DeviceState *dev, Property *prop, const char *str) > > +{ > > + uint8_t *ptr = qdev_get_prop_ptr(dev, prop); > > + char *end; > > + > > + if (str[0] != '0' || str[1] != 'x') { > > + return -EINVAL; > > + } > > + > > + *ptr = strtoul(str, &end, 16); > > + if ((*end != '\0') || (end == str)) { > > + return -EINVAL; > > + } > > + > > + return 0; > > +} > > + > > +static int print_hex8(DeviceState *dev, Property *prop, char *dest, size_t len) > > +{ > > + uint8_t *ptr = qdev_get_prop_ptr(dev, prop); > > + return snprintf(dest, len, "0x%" PRIx8, *ptr); > > +} > > + > > +PropertyInfo qdev_prop_hex8 = { > > + .name = "uint8", > > + .legacy_name = "hex8", > > + .parse = parse_hex8, > > + .print = print_hex8, > > + .get = get_uint8, > > + .set = set_uint8, > > +}; > > + > > +/* --- 16bit integer --- */ > > + > > +static void get_uint16(Object *obj, Visitor *v, void *opaque, > > + const char *name, Error **errp) > > +{ > > + DeviceState *dev = DEVICE(obj); > > + Property *prop = opaque; > > + uint16_t *ptr = qdev_get_prop_ptr(dev, prop); > > + > > + visit_type_uint16(v, ptr, name, errp); > > +} > > + > > +static void set_uint16(Object *obj, Visitor *v, void *opaque, > > + const char *name, Error **errp) > > +{ > > + DeviceState *dev = DEVICE(obj); > > + Property *prop = opaque; > > + uint16_t *ptr = qdev_get_prop_ptr(dev, prop); > > + > > + if (dev->state != DEV_STATE_CREATED) { > > + error_set(errp, QERR_PERMISSION_DENIED); > > + return; > > + } > > + > > + visit_type_uint16(v, ptr, name, errp); > > +} > > + > > +PropertyInfo qdev_prop_uint16 = { > > + .name = "uint16", > > + .get = get_uint16, > > + .set = set_uint16, > > +}; > > + > > +/* --- 32bit integer --- */ > > + > > +static void get_uint32(Object *obj, Visitor *v, void *opaque, > > + const char *name, Error **errp) > > +{ > > + DeviceState *dev = DEVICE(obj); > > + Property *prop = opaque; > > + uint32_t *ptr = qdev_get_prop_ptr(dev, prop); > > + > > + visit_type_uint32(v, ptr, name, errp); > > +} > > + > > +static void set_uint32(Object *obj, Visitor *v, void *opaque, > > + const char *name, Error **errp) > > +{ > > + DeviceState *dev = DEVICE(obj); > > + Property *prop = opaque; > > + uint32_t *ptr = qdev_get_prop_ptr(dev, prop); > > + > > + if (dev->state != DEV_STATE_CREATED) { > > + error_set(errp, QERR_PERMISSION_DENIED); > > + return; > > + } > > + > > + visit_type_uint32(v, ptr, name, errp); > > +} > > + > > +static void get_int32(Object *obj, Visitor *v, void *opaque, > > + const char *name, Error **errp) > > +{ > > + DeviceState *dev = DEVICE(obj); > > + Property *prop = opaque; > > + int32_t *ptr = qdev_get_prop_ptr(dev, prop); > > + > > + visit_type_int32(v, ptr, name, errp); > > +} > > + > > +static void set_int32(Object *obj, Visitor *v, void *opaque, > > + const char *name, Error **errp) > > +{ > > + DeviceState *dev = DEVICE(obj); > > + Property *prop = opaque; > > + int32_t *ptr = qdev_get_prop_ptr(dev, prop); > > + > > + if (dev->state != DEV_STATE_CREATED) { > > + error_set(errp, QERR_PERMISSION_DENIED); > > + return; > > + } > > + > > + visit_type_int32(v, ptr, name, errp); > > +} > > + > > +PropertyInfo qdev_prop_uint32 = { > > + .name = "uint32", > > + .get = get_uint32, > > + .set = set_uint32, > > +}; > > + > > +PropertyInfo qdev_prop_int32 = { > > + .name = "int32", > > + .get = get_int32, > > + .set = set_int32, > > +}; > > + > > +/* --- 32bit hex value --- */ > > + > > +static int parse_hex32(DeviceState *dev, Property *prop, const char *str) > > +{ > > + uint32_t *ptr = qdev_get_prop_ptr(dev, prop); > > + char *end; > > + > > + if (str[0] != '0' || str[1] != 'x') { > > + return -EINVAL; > > + } > > + > > + *ptr = strtoul(str, &end, 16); > > + if ((*end != '\0') || (end == str)) { > > + return -EINVAL; > > + } > > + > > + return 0; > > +} > > + > > +static int print_hex32(DeviceState *dev, Property *prop, char *dest, size_t len) > > +{ > > + uint32_t *ptr = qdev_get_prop_ptr(dev, prop); > > + return snprintf(dest, len, "0x%" PRIx32, *ptr); > > +} > > + > > +PropertyInfo qdev_prop_hex32 = { > > + .name = "uint32", > > + .legacy_name = "hex32", > > + .parse = parse_hex32, > > + .print = print_hex32, > > + .get = get_uint32, > > + .set = set_uint32, > > +}; > > + > > +/* --- 64bit integer --- */ > > + > > +static void get_uint64(Object *obj, Visitor *v, void *opaque, > > + const char *name, Error **errp) > > +{ > > + DeviceState *dev = DEVICE(obj); > > + Property *prop = opaque; > > + uint64_t *ptr = qdev_get_prop_ptr(dev, prop); > > + > > + visit_type_uint64(v, ptr, name, errp); > > +} > > + > > +static void set_uint64(Object *obj, Visitor *v, void *opaque, > > + const char *name, Error **errp) > > +{ > > + DeviceState *dev = DEVICE(obj); > > + Property *prop = opaque; > > + uint64_t *ptr = qdev_get_prop_ptr(dev, prop); > > + > > + if (dev->state != DEV_STATE_CREATED) { > > + error_set(errp, QERR_PERMISSION_DENIED); > > + return; > > + } > > + > > + visit_type_uint64(v, ptr, name, errp); > > +} > > + > > +PropertyInfo qdev_prop_uint64 = { > > + .name = "uint64", > > + .get = get_uint64, > > + .set = set_uint64, > > +}; > > + > > +/* --- 64bit hex value --- */ > > + > > +static int parse_hex64(DeviceState *dev, Property *prop, const char *str) > > +{ > > + uint64_t *ptr = qdev_get_prop_ptr(dev, prop); > > + char *end; > > + > > + if (str[0] != '0' || str[1] != 'x') { > > + return -EINVAL; > > + } > > + > > + *ptr = strtoull(str, &end, 16); > > + if ((*end != '\0') || (end == str)) { > > + return -EINVAL; > > + } > > + > > + return 0; > > +} > > + > > +static int print_hex64(DeviceState *dev, Property *prop, char *dest, size_t len) > > +{ > > + uint64_t *ptr = qdev_get_prop_ptr(dev, prop); > > + return snprintf(dest, len, "0x%" PRIx64, *ptr); > > +} > > + > > +PropertyInfo qdev_prop_hex64 = { > > + .name = "uint64", > > + .legacy_name = "hex64", > > + .parse = parse_hex64, > > + .print = print_hex64, > > + .get = get_uint64, > > + .set = set_uint64, > > +}; > > + > > +/* --- string --- */ > > + > > +static void release_string(Object *obj, const char *name, void *opaque) > > +{ > > + Property *prop = opaque; > > + g_free(*(char **)qdev_get_prop_ptr(DEVICE(obj), prop)); > > +} > > + > > +static int print_string(DeviceState *dev, Property *prop, char *dest, size_t len) > > +{ > > + char **ptr = qdev_get_prop_ptr(dev, prop); > > + if (!*ptr) > > + return snprintf(dest, len, "<null>"); > > + return snprintf(dest, len, "\"%s\"", *ptr); > > +} > > + > > +static void get_string(Object *obj, Visitor *v, void *opaque, > > + const char *name, Error **errp) > > +{ > > + DeviceState *dev = DEVICE(obj); > > + Property *prop = opaque; > > + char **ptr = qdev_get_prop_ptr(dev, prop); > > + > > + if (!*ptr) { > > + char *str = (char *)""; > > + visit_type_str(v, &str, name, errp); > > + } else { > > + visit_type_str(v, ptr, name, errp); > > + } > > +} > > + > > +static void set_string(Object *obj, Visitor *v, void *opaque, > > + const char *name, Error **errp) > > +{ > > + DeviceState *dev = DEVICE(obj); > > + Property *prop = opaque; > > + char **ptr = qdev_get_prop_ptr(dev, prop); > > + Error *local_err = NULL; > > + char *str; > > + > > + if (dev->state != DEV_STATE_CREATED) { > > + error_set(errp, QERR_PERMISSION_DENIED); > > + return; > > + } > > + > > + visit_type_str(v, &str, name, &local_err); > > + if (local_err) { > > + error_propagate(errp, local_err); > > + return; > > + } > > + if (*ptr) { > > + g_free(*ptr); > > + } > > + *ptr = str; > > +} > > + > > +PropertyInfo qdev_prop_string = { > > + .name = "string", > > + .print = print_string, > > + .release = release_string, > > + .get = get_string, > > + .set = set_string, > > +}; > > + > > +/* --- pointer --- */ > > + > > +/* Not a proper property, just for dirty hacks. TODO Remove it! */ > > +PropertyInfo qdev_prop_ptr = { > > + .name = "ptr", > > +}; > > + > > +/* --- mac address --- */ > > + > > +/* > > + * accepted syntax versions: > > + * 01:02:03:04:05:06 > > + * 01-02-03-04-05-06 > > + */ > > +static void get_mac(Object *obj, Visitor *v, void *opaque, > > + const char *name, Error **errp) > > +{ > > + DeviceState *dev = DEVICE(obj); > > + Property *prop = opaque; > > + MACAddr *mac = qdev_get_prop_ptr(dev, prop); > > + char buffer[2 * 6 + 5 + 1]; > > + char *p = buffer; > > + > > + snprintf(buffer, sizeof(buffer), "%02x:%02x:%02x:%02x:%02x:%02x", > > + mac->a[0], mac->a[1], mac->a[2], > > + mac->a[3], mac->a[4], mac->a[5]); > > + > > + visit_type_str(v, &p, name, errp); > > +} > > + > > +static void set_mac(Object *obj, Visitor *v, void *opaque, > > + const char *name, Error **errp) > > +{ > > + DeviceState *dev = DEVICE(obj); > > + Property *prop = opaque; > > + MACAddr *mac = qdev_get_prop_ptr(dev, prop); > > + Error *local_err = NULL; > > + int i, pos; > > + char *str, *p; > > + > > + if (dev->state != DEV_STATE_CREATED) { > > + error_set(errp, QERR_PERMISSION_DENIED); > > + return; > > + } > > + > > + visit_type_str(v, &str, name, &local_err); > > + if (local_err) { > > + error_propagate(errp, local_err); > > + return; > > + } > > + > > + for (i = 0, pos = 0; i < 6; i++, pos += 3) { > > + if (!qemu_isxdigit(str[pos])) > > + goto inval; > > + if (!qemu_isxdigit(str[pos+1])) > > + goto inval; > > + if (i == 5) { > > + if (str[pos+2] != '\0') > > + goto inval; > > + } else { > > + if (str[pos+2] != ':' && str[pos+2] != '-') > > + goto inval; > > + } > > + mac->a[i] = strtol(str+pos, &p, 16); > > + } > > + g_free(str); > > + return; > > + > > +inval: > > + error_set_from_qdev_prop_error(errp, EINVAL, dev, prop, str); > > + g_free(str); > > +} > > + > > +PropertyInfo qdev_prop_macaddr = { > > + .name = "macaddr", > > + .get = get_mac, > > + .set = set_mac, > > +}; > > + > > +/* --- lost tick policy --- */ > > + > > +static const char *lost_tick_policy_table[LOST_TICK_MAX+1] = { > > + [LOST_TICK_DISCARD] = "discard", > > + [LOST_TICK_DELAY] = "delay", > > + [LOST_TICK_MERGE] = "merge", > > + [LOST_TICK_SLEW] = "slew", > > + [LOST_TICK_MAX] = NULL, > > +}; > > + > > +QEMU_BUILD_BUG_ON(sizeof(LostTickPolicy) != sizeof(int)); > > + > > +PropertyInfo qdev_prop_losttickpolicy = { > > + .name = "LostTickPolicy", > > + .enum_table = lost_tick_policy_table, > > + .get = get_enum, > > + .set = set_enum, > > +}; > > + > > +/* --- BIOS CHS translation */ > > + > > +static const char *bios_chs_trans_table[] = { > > + [BIOS_ATA_TRANSLATION_AUTO] = "auto", > > + [BIOS_ATA_TRANSLATION_NONE] = "none", > > + [BIOS_ATA_TRANSLATION_LBA] = "lba", > > +}; > > + > > +PropertyInfo qdev_prop_bios_chs_trans = { > > + .name = "bios-chs-trans", > > + .enum_table = bios_chs_trans_table, > > + .get = get_enum, > > + .set = set_enum, > > +}; > > + > > +/* --- pci address --- */ > > + > > +/* > > + * bus-local address, i.e. "$slot" or "$slot.$fn" > > + */ > > +static void set_pci_devfn(Object *obj, Visitor *v, void *opaque, > > + const char *name, Error **errp) > > +{ > > + DeviceState *dev = DEVICE(obj); > > + Property *prop = opaque; > > + int32_t value, *ptr = qdev_get_prop_ptr(dev, prop); > > + unsigned int slot, fn, n; > > + Error *local_err = NULL; > > + char *str; > > + > > + if (dev->state != DEV_STATE_CREATED) { > > + error_set(errp, QERR_PERMISSION_DENIED); > > + return; > > + } > > + > > + visit_type_str(v, &str, name, &local_err); > > + if (local_err) { > > + error_free(local_err); > > + local_err = NULL; > > + visit_type_int32(v, &value, name, &local_err); > > + if (local_err) { > > + error_propagate(errp, local_err); > > + } else if (value < -1 || value > 255) { > > + error_set(errp, QERR_INVALID_PARAMETER_VALUE, name ? name : "null", > > + "pci_devfn"); > > + } else { > > + *ptr = value; > > + } > > + return; > > + } > > + > > + if (sscanf(str, "%x.%x%n", &slot, &fn, &n) != 2) { > > + fn = 0; > > + if (sscanf(str, "%x%n", &slot, &n) != 1) { > > + goto invalid; > > + } > > + } > > + if (str[n] != '\0' || fn > 7 || slot > 31) { > > + goto invalid; > > + } > > + *ptr = slot << 3 | fn; > > + g_free(str); > > + return; > > + > > +invalid: > > + error_set_from_qdev_prop_error(errp, EINVAL, dev, prop, str); > > + g_free(str); > > +} > > + > > +static int print_pci_devfn(DeviceState *dev, Property *prop, char *dest, size_t len) > > +{ > > + int32_t *ptr = qdev_get_prop_ptr(dev, prop); > > + > > + if (*ptr == -1) { > > + return snprintf(dest, len, "<unset>"); > > + } else { > > + return snprintf(dest, len, "%02x.%x", *ptr >> 3, *ptr & 7); > > + } > > +} > > + > > +PropertyInfo qdev_prop_pci_devfn = { > > + .name = "int32", > > + .legacy_name = "pci-devfn", > > + .print = print_pci_devfn, > > + .get = get_int32, > > + .set = set_pci_devfn, > > +}; > > + > > +/* --- blocksize --- */ > > + > > +static void set_blocksize(Object *obj, Visitor *v, void *opaque, > > + const char *name, Error **errp) > > +{ > > + DeviceState *dev = DEVICE(obj); > > + Property *prop = opaque; > > + uint16_t value, *ptr = qdev_get_prop_ptr(dev, prop); > > + Error *local_err = NULL; > > + const int64_t min = 512; > > + const int64_t max = 32768; > > + > > + if (dev->state != DEV_STATE_CREATED) { > > + error_set(errp, QERR_PERMISSION_DENIED); > > + return; > > + } > > + > > + visit_type_uint16(v, &value, name, &local_err); > > + if (local_err) { > > + error_propagate(errp, local_err); > > + return; > > + } > > + if (value < min || value > max) { > > + error_set(errp, QERR_PROPERTY_VALUE_OUT_OF_RANGE, > > + dev->id?:"", name, (int64_t)value, min, max); > > + return; > > + } > > + > > + /* We rely on power-of-2 blocksizes for bitmasks */ > > + if ((value & (value - 1)) != 0) { > > + error_set(errp, QERR_PROPERTY_VALUE_NOT_POWER_OF_2, > > + dev->id?:"", name, (int64_t)value); > > + return; > > + } > > + > > + *ptr = value; > > +} > > + > > +PropertyInfo qdev_prop_blocksize = { > > + .name = "blocksize", > > + .get = get_uint16, > > + .set = set_blocksize, > > +}; > > + > > +/* --- pci host address --- */ > > + > > +static void get_pci_host_devaddr(Object *obj, Visitor *v, void *opaque, > > + const char *name, Error **errp) > > +{ > > + DeviceState *dev = DEVICE(obj); > > + Property *prop = opaque; > > + PCIHostDeviceAddress *addr = qdev_get_prop_ptr(dev, prop); > > + char buffer[] = "xxxx:xx:xx.x"; > > + char *p = buffer; > > + int rc = 0; > > + > > + rc = snprintf(buffer, sizeof(buffer), "%04x:%02x:%02x.%d", > > + addr->domain, addr->bus, addr->slot, addr->function); > > + assert(rc == sizeof(buffer) - 1); > > + > > + visit_type_str(v, &p, name, errp); > > +} > > + > > +/* > > + * Parse [<domain>:]<bus>:<slot>.<func> > > + * if <domain> is not supplied, it's assumed to be 0. > > + */ > > +static void set_pci_host_devaddr(Object *obj, Visitor *v, void *opaque, > > + const char *name, Error **errp) > > +{ > > + DeviceState *dev = DEVICE(obj); > > + Property *prop = opaque; > > + PCIHostDeviceAddress *addr = qdev_get_prop_ptr(dev, prop); > > + Error *local_err = NULL; > > + char *str, *p; > > + char *e; > > + unsigned long val; > > + unsigned long dom = 0, bus = 0; > > + unsigned int slot = 0, func = 0; > > + > > + if (dev->state != DEV_STATE_CREATED) { > > + error_set(errp, QERR_PERMISSION_DENIED); > > + return; > > + } > > + > > + visit_type_str(v, &str, name, &local_err); > > + if (local_err) { > > + error_propagate(errp, local_err); > > + return; > > + } > > + > > + p = str; > > + val = strtoul(p, &e, 16); > > + if (e == p || *e != ':') { > > + goto inval; > > + } > > + bus = val; > > + > > + p = e + 1; > > + val = strtoul(p, &e, 16); > > + if (e == p) { > > + goto inval; > > + } > > + if (*e == ':') { > > + dom = bus; > > + bus = val; > > + p = e + 1; > > + val = strtoul(p, &e, 16); > > + if (e == p) { > > + goto inval; > > + } > > + } > > + slot = val; > > + > > + if (*e != '.') { > > + goto inval; > > + } > > + p = e + 1; > > + val = strtoul(p, &e, 10); > > + if (e == p) { > > + goto inval; > > + } > > + func = val; > > + > > + if (dom > 0xffff || bus > 0xff || slot > 0x1f || func > 7) { > > + goto inval; > > + } > > + > > + if (*e) { > > + goto inval; > > + } > > + > > + addr->domain = dom; > > + addr->bus = bus; > > + addr->slot = slot; > > + addr->function = func; > > + > > + g_free(str); > > + return; > > + > > +inval: > > + error_set_from_qdev_prop_error(errp, EINVAL, dev, prop, str); > > + g_free(str); > > +} > > + > > +PropertyInfo qdev_prop_pci_host_devaddr = { > > + .name = "pci-host-devaddr", > > + .get = get_pci_host_devaddr, > > + .set = set_pci_host_devaddr, > > +}; > > + > > +/* --- public helpers --- */ > > + > > +static Property *qdev_prop_walk(Property *props, const char *name) > > +{ > > + if (!props) > > + return NULL; > > + while (props->name) { > > + if (strcmp(props->name, name) == 0) > > + return props; > > + props++; > > + } > > + return NULL; > > +} > > + > > +static Property *qdev_prop_find(DeviceState *dev, const char *name) > > +{ > > + ObjectClass *class; > > + Property *prop; > > + > > + /* device properties */ > > + class = object_get_class(OBJECT(dev)); > > + do { > > + prop = qdev_prop_walk(DEVICE_CLASS(class)->props, name); > > + if (prop) { > > + return prop; > > + } > > + class = object_class_get_parent(class); > > + } while (class != object_class_by_name(TYPE_DEVICE)); > > + > > + return NULL; > > +} > > + > > +void error_set_from_qdev_prop_error(Error **errp, int ret, DeviceState *dev, > > + Property *prop, const char *value) > > +{ > > + switch (ret) { > > + case -EEXIST: > > + error_set(errp, QERR_PROPERTY_VALUE_IN_USE, > > + object_get_typename(OBJECT(dev)), prop->name, value); > > + break; > > + default: > > + case -EINVAL: > > + error_set(errp, QERR_PROPERTY_VALUE_BAD, > > + object_get_typename(OBJECT(dev)), prop->name, value); > > + break; > > + case -ENOENT: > > + error_set(errp, QERR_PROPERTY_VALUE_NOT_FOUND, > > + object_get_typename(OBJECT(dev)), prop->name, value); > > + break; > > + case 0: > > + break; > > + } > > +} > > + > > +int qdev_prop_parse(DeviceState *dev, const char *name, const char *value) > > +{ > > + char *legacy_name; > > + Error *err = NULL; > > + > > + legacy_name = g_strdup_printf("legacy-%s", name); > > + if (object_property_get_type(OBJECT(dev), legacy_name, NULL)) { > > + object_property_parse(OBJECT(dev), value, legacy_name, &err); > > + } else { > > + object_property_parse(OBJECT(dev), value, name, &err); > > + } > > + g_free(legacy_name); > > + > > + if (err) { > > + qerror_report_err(err); > > + error_free(err); > > + return -1; > > + } > > + return 0; > > +} > > + > > +void qdev_prop_set_bit(DeviceState *dev, const char *name, bool value) > > +{ > > + Error *errp = NULL; > > + object_property_set_bool(OBJECT(dev), value, name, &errp); > > + assert_no_error(errp); > > +} > > + > > +void qdev_prop_set_uint8(DeviceState *dev, const char *name, uint8_t value) > > +{ > > + Error *errp = NULL; > > + object_property_set_int(OBJECT(dev), value, name, &errp); > > + assert_no_error(errp); > > +} > > + > > +void qdev_prop_set_uint16(DeviceState *dev, const char *name, uint16_t value) > > +{ > > + Error *errp = NULL; > > + object_property_set_int(OBJECT(dev), value, name, &errp); > > + assert_no_error(errp); > > +} > > + > > +void qdev_prop_set_uint32(DeviceState *dev, const char *name, uint32_t value) > > +{ > > + Error *errp = NULL; > > + object_property_set_int(OBJECT(dev), value, name, &errp); > > + assert_no_error(errp); > > +} > > + > > +void qdev_prop_set_int32(DeviceState *dev, const char *name, int32_t value) > > +{ > > + Error *errp = NULL; > > + object_property_set_int(OBJECT(dev), value, name, &errp); > > + assert_no_error(errp); > > +} > > + > > +void qdev_prop_set_uint64(DeviceState *dev, const char *name, uint64_t value) > > +{ > > + Error *errp = NULL; > > + object_property_set_int(OBJECT(dev), value, name, &errp); > > + assert_no_error(errp); > > +} > > + > > +void qdev_prop_set_string(DeviceState *dev, const char *name, const char *value) > > +{ > > + Error *errp = NULL; > > + object_property_set_str(OBJECT(dev), value, name, &errp); > > + assert_no_error(errp); > > +} > > + > > +void qdev_prop_set_macaddr(DeviceState *dev, const char *name, uint8_t *value) > > +{ > > + Error *errp = NULL; > > + char str[2 * 6 + 5 + 1]; > > + snprintf(str, sizeof(str), "%02x:%02x:%02x:%02x:%02x:%02x", > > + value[0], value[1], value[2], value[3], value[4], value[5]); > > + > > + object_property_set_str(OBJECT(dev), str, name, &errp); > > + assert_no_error(errp); > > +} > > + > > +void qdev_prop_set_enum(DeviceState *dev, const char *name, int value) > > +{ > > + Property *prop; > > + Error *errp = NULL; > > + > > + prop = qdev_prop_find(dev, name); > > + object_property_set_str(OBJECT(dev), prop->info->enum_table[value], > > + name, &errp); > > + assert_no_error(errp); > > +} > > + > > +void qdev_prop_set_ptr(DeviceState *dev, const char *name, void *value) > > +{ > > + Property *prop; > > + void **ptr; > > + > > + prop = qdev_prop_find(dev, name); > > + assert(prop && prop->info == &qdev_prop_ptr); > > + ptr = qdev_get_prop_ptr(dev, prop); > > + *ptr = value; > > +} > > + > > +static QTAILQ_HEAD(, GlobalProperty) global_props = QTAILQ_HEAD_INITIALIZER(global_props); > > + > > +void qdev_prop_register_global(GlobalProperty *prop) > > +{ > > + QTAILQ_INSERT_TAIL(&global_props, prop, next); > > +} > > + > > +void qdev_prop_register_global_list(GlobalProperty *props) > > +{ > > + int i; > > + > > + for (i = 0; props[i].driver != NULL; i++) { > > + qdev_prop_register_global(props+i); > > + } > > +} > > + > > +void qdev_prop_set_globals(DeviceState *dev) > > +{ > > + ObjectClass *class = object_get_class(OBJECT(dev)); > > + > > + do { > > + GlobalProperty *prop; > > + QTAILQ_FOREACH(prop, &global_props, next) { > > + if (strcmp(object_class_get_name(class), prop->driver) != 0) { > > + continue; > > + } > > + if (qdev_prop_parse(dev, prop->property, prop->value) != 0) { > > + exit(1); > > + } > > + } > > + class = object_class_get_parent(class); > > + } while (class); > > +} > > + > > -- > > 1.7.11.7
On 17 October 2012 19:11, Anthony Liguori <anthony@codemonkey.ws> wrote: > It's dangerously close to bike-shedding, but i don't think qdev belongs > in qom/. It's not core infrastructure. It's the device base class and > belongs IMHO in hw/. "-user emulators don't get anything from hw/" is one of those semi arbitrary but easily definable lines that I'd prefer it if we didn't break. (Although IIRC there was a directory-renaming proposal recently which maybe defines some different lines instead.) -- PMM
On Wed, Oct 17, 2012 at 08:21:17PM +0100, Peter Maydell wrote: > On 17 October 2012 19:11, Anthony Liguori <anthony@codemonkey.ws> wrote: > > It's dangerously close to bike-shedding, but i don't think qdev belongs > > in qom/. It's not core infrastructure. It's the device base class and > > belongs IMHO in hw/. > > "-user emulators don't get anything from hw/" is one of those semi > arbitrary but easily definable lines that I'd prefer it if we didn't > break. (Although IIRC there was a directory-renaming proposal recently > which maybe defines some different lines instead.) I just rememberd another reason for moving qdev-core to qom: the CPU class itself (that's going to be a child of DeviceState) is already inside qom. Keeping qdev-core it on hw/ would mean having a qom->hw->qom dependency chain (qom/cpu.c -> hw/qdev.c -> qom/object.c). So, by now I am keeping the proposed patch as-is (moving qdev-core to qom/).
On Tue, 16 Oct 2012 16:08:42 -0300 Eduardo Habkost <ehabkost@redhat.com> wrote: [...] > diff --git a/qom/qdev-properties.c b/qom/qdev-properties.c > new file mode 100644 > index 0000000..2e82cb9 > --- /dev/null > +++ b/qom/qdev-properties.c [...] > +void qdev_prop_set_globals(DeviceState *dev) > +{ > + ObjectClass *class = object_get_class(OBJECT(dev)); > + > + do { > + GlobalProperty *prop; > + QTAILQ_FOREACH(prop, &global_props, next) { > + if (strcmp(object_class_get_name(class), prop->driver) != 0) { > + continue; > + } > + if (qdev_prop_parse(dev, prop->property, prop->value) != 0) { > + exit(1); > + } > + } > + class = object_class_get_parent(class); > + } while (class); > +} > + ^^^ git complains "whitespace line at EOF"
On Mon, Oct 22, 2012 at 02:36:01PM +0200, Igor Mammedov wrote: > On Tue, 16 Oct 2012 16:08:42 -0300 > Eduardo Habkost <ehabkost@redhat.com> wrote: > [...] > > diff --git a/qom/qdev-properties.c b/qom/qdev-properties.c > > new file mode 100644 > > index 0000000..2e82cb9 > > --- /dev/null > > +++ b/qom/qdev-properties.c > [...] > > +void qdev_prop_set_globals(DeviceState *dev) > > +{ > > + ObjectClass *class = object_get_class(OBJECT(dev)); > > + > > + do { > > + GlobalProperty *prop; > > + QTAILQ_FOREACH(prop, &global_props, next) { > > + if (strcmp(object_class_get_name(class), prop->driver) != 0) { > > + continue; > > + } > > + if (qdev_prop_parse(dev, prop->property, prop->value) != 0) { > > + exit(1); > > + } > > + } > > + class = object_class_get_parent(class); > > + } while (class); > > +} > > + > ^^^ git complains "whitespace line at EOF" I will fix it on the next version. Thanks.
diff --git a/Makefile.objs b/Makefile.objs index 74b3542..fcd1336 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -16,6 +16,9 @@ universal-obj-y += $(qobject-obj-y) qom-obj-y = qom/ universal-obj-y += $(qom-obj-y) +# QOM qdev-core.o requires qemu-option.o: +universal-obj-y += qemu-option.o + ####################################################################### # oslib-obj-y is code depending on the OS (win32 vs posix) diff --git a/hw/Makefile.objs b/hw/Makefile.objs index 70f2014..3ce38d2 100644 --- a/hw/Makefile.objs +++ b/hw/Makefile.objs @@ -180,7 +180,7 @@ common-obj-$(CONFIG_SD) += sd.o common-obj-y += bt.o bt-l2cap.o bt-sdp.o bt-hci.o bt-hid.o common-obj-y += bt-hci-csr.o common-obj-y += msmouse.o ps2.o -common-obj-y += qdev-core.o qdev-properties.o qdev-monitor.o +common-obj-y += qdev-monitor.o common-obj-y += qdev-system.o qdev-properties-system.o common-obj-$(CONFIG_BRLAPI) += baum.o diff --git a/hw/qdev-core.c b/hw/qdev-core.c deleted file mode 100644 index fbb7cb5..0000000 --- a/hw/qdev-core.c +++ /dev/null @@ -1,727 +0,0 @@ -/* - * Dynamic device configuration and creation. - * - * Copyright (c) 2009 CodeSourcery - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see <http://www.gnu.org/licenses/>. - */ - -/* The theory here is that it should be possible to create a machine without - knowledge of specific devices. Historically board init routines have - passed a bunch of arguments to each device, requiring the board know - exactly which device it is dealing with. This file provides an abstract - API for device configuration and initialization. Devices will generally - inherit from a particular bus (e.g. PCI or I2C) rather than - this API directly. */ - -#include "hw/qdev.h" -#include "sysemu.h" -#include "error.h" -#include "qapi/qapi-visit-core.h" - -int qdev_hotplug = 0; -static bool qdev_hot_added = false; -static bool qdev_hot_removed = false; - -/* vmstate handling: - * - * The real implementations are on qdev-system.c. Those are weak symbols - * used by *-user. - */ -void GCC_WEAK qdev_init_vmstate(DeviceState *dev) -{ -} - -void GCC_WEAK qdev_finalize_vmstate(DeviceState *dev) -{ -} - -/* reset handler register/unregister: - * - * The real implementations are on qdev-system.c. Those are weak symbols - * used by *-user. - */ -void GCC_WEAK qbus_register_reset(BusState *bus) -{ -} - -void GCC_WEAK qbus_unregister_reset(BusState *bus) -{ -} - -const char *qdev_fw_name(DeviceState *dev) -{ - DeviceClass *dc = DEVICE_GET_CLASS(dev); - - if (dc->fw_name) { - return dc->fw_name; - } - - return object_get_typename(OBJECT(dev)); -} - -static void qdev_property_add_legacy(DeviceState *dev, Property *prop, - Error **errp); - -static void bus_remove_child(BusState *bus, DeviceState *child) -{ - BusChild *kid; - - QTAILQ_FOREACH(kid, &bus->children, sibling) { - if (kid->child == child) { - char name[32]; - - snprintf(name, sizeof(name), "child[%d]", kid->index); - QTAILQ_REMOVE(&bus->children, kid, sibling); - object_property_del(OBJECT(bus), name, NULL); - g_free(kid); - return; - } - } -} - -static void bus_add_child(BusState *bus, DeviceState *child) -{ - char name[32]; - BusChild *kid = g_malloc0(sizeof(*kid)); - - if (qdev_hotplug) { - assert(bus->allow_hotplug); - } - - kid->index = bus->max_index++; - kid->child = child; - - QTAILQ_INSERT_HEAD(&bus->children, kid, sibling); - - snprintf(name, sizeof(name), "child[%d]", kid->index); - object_property_add_link(OBJECT(bus), name, - object_get_typename(OBJECT(child)), - (Object **)&kid->child, - NULL); -} - -void qdev_set_parent_bus(DeviceState *dev, BusState *bus) -{ - dev->parent_bus = bus; - bus_add_child(bus, 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. - On failure, destroy the device and return negative value. - Return 0 on success. */ -int qdev_init(DeviceState *dev) -{ - DeviceClass *dc = DEVICE_GET_CLASS(dev); - int rc; - - assert(dev->state == DEV_STATE_CREATED); - - rc = dc->init(dev); - if (rc < 0) { - qdev_free(dev); - return rc; - } - - if (!OBJECT(dev)->parent) { - static int unattached_count = 0; - gchar *name = g_strdup_printf("device[%d]", unattached_count++); - - object_property_add_child(container_get(qdev_get_machine(), - "/unattached"), - name, OBJECT(dev), NULL); - g_free(name); - } - - qdev_init_vmstate(dev); - dev->state = DEV_STATE_INITIALIZED; - if (dev->hotplugged) { - device_reset(dev); - } - 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; -} - -void qdev_unplug(DeviceState *dev, Error **errp) -{ - DeviceClass *dc = DEVICE_GET_CLASS(dev); - - if (!dev->parent_bus->allow_hotplug) { - error_set(errp, QERR_BUS_NO_HOTPLUG, dev->parent_bus->name); - return; - } - assert(dc->unplug != NULL); - - qdev_hot_removed = true; - - if (dc->unplug(dev) < 0) { - error_set(errp, QERR_UNDEFINED_ERROR); - return; - } -} - -static int qdev_reset_one(DeviceState *dev, void *opaque) -{ - device_reset(dev); - - return 0; -} - -static int qbus_reset_one(BusState *bus, void *opaque) -{ - BusClass *bc = BUS_GET_CLASS(bus); - if (bc->reset) { - return bc->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_fn(void *opaque) -{ - BusState *bus = opaque; - 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) -{ - /* just zap it */ - qdev_free(dev); - return 0; -} - - -/* Like qdev_init(), but terminate program via error_report() instead of - returning an error value. This is okay during machine creation. - Don't use for hotplug, because there callers need to recover from - failure. Exception: if you know the device's init() callback can't - fail, then qdev_init_nofail() can't fail either, and is therefore - usable even then. But relying on the device implementation that - way is somewhat unclean, and best avoided. */ -void qdev_init_nofail(DeviceState *dev) -{ - const char *typename = object_get_typename(OBJECT(dev)); - - if (qdev_init(dev) < 0) { - error_report("Initialization of device %s failed", typename); - exit(1); - } -} - -/* Unlink device from bus and free the structure. */ -void qdev_free(DeviceState *dev) -{ - object_delete(OBJECT(dev)); -} - -void qdev_machine_creation_done(void) -{ - /* - * ok, initial machine setup is done, starting from now we can - * only create hotpluggable devices - */ - qdev_hotplug = 1; -} - -bool qdev_machine_modified(void) -{ - return qdev_hot_added || qdev_hot_removed; -} - -BusState *qdev_get_parent_bus(DeviceState *dev) -{ - return dev->parent_bus; -} - -BusState *qdev_get_child_bus(DeviceState *dev, const char *name) -{ - BusState *bus; - - QLIST_FOREACH(bus, &dev->child_bus, sibling) { - if (strcmp(name, bus->name) == 0) { - return bus; - } - } - return NULL; -} - -int qbus_walk_children(BusState *bus, qdev_walkerfn *devfn, - qbus_walkerfn *busfn, void *opaque) -{ - BusChild *kid; - int err; - - if (busfn) { - err = busfn(bus, opaque); - if (err) { - return err; - } - } - - QTAILQ_FOREACH(kid, &bus->children, sibling) { - err = qdev_walk_children(kid->child, 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; -} - -DeviceState *qdev_find_recursive(BusState *bus, const char *id) -{ - BusChild *kid; - DeviceState *ret; - BusState *child; - - QTAILQ_FOREACH(kid, &bus->children, sibling) { - DeviceState *dev = kid->child; - - if (dev->id && strcmp(dev->id, id) == 0) { - return dev; - } - - QLIST_FOREACH(child, &dev->child_bus, sibling) { - ret = qdev_find_recursive(child, id); - if (ret) { - return ret; - } - } - } - return NULL; -} - -static void qbus_realize(BusState *bus) -{ - const char *typename = object_get_typename(OBJECT(bus)); - char *buf; - int i,len; - - if (bus->name) { - /* use supplied name */ - } else if (bus->parent && bus->parent->id) { - /* parent device has id -> use it for bus name */ - len = strlen(bus->parent->id) + 16; - buf = g_malloc(len); - snprintf(buf, len, "%s.%d", bus->parent->id, bus->parent->num_child_bus); - bus->name = buf; - } else { - /* no id -> use lowercase bus type for bus name */ - len = strlen(typename) + 16; - buf = g_malloc(len); - len = snprintf(buf, len, "%s.%d", typename, - bus->parent ? bus->parent->num_child_bus : 0); - for (i = 0; i < len; i++) - buf[i] = qemu_tolower(buf[i]); - bus->name = buf; - } - - if (bus->parent) { - QLIST_INSERT_HEAD(&bus->parent->child_bus, bus, sibling); - bus->parent->num_child_bus++; - object_property_add_child(OBJECT(bus->parent), bus->name, OBJECT(bus), NULL); - } else { - qbus_register_reset(bus); - } -} - -void qbus_create_inplace(BusState *bus, const char *typename, - DeviceState *parent, const char *name) -{ - object_initialize(bus, typename); - - bus->parent = parent; - bus->name = name ? g_strdup(name) : NULL; - qbus_realize(bus); -} - -BusState *qbus_create(const char *typename, DeviceState *parent, const char *name) -{ - BusState *bus; - - bus = BUS(object_new(typename)); - bus->qom_allocated = true; - - bus->parent = parent; - bus->name = name ? g_strdup(name) : NULL; - qbus_realize(bus); - - return bus; -} - -void qbus_free(BusState *bus) -{ - if (bus->qom_allocated) { - object_delete(OBJECT(bus)); - } else { - object_finalize(OBJECT(bus)); - if (bus->glib_allocated) { - g_free(bus); - } - } -} - -static char *bus_get_fw_dev_path(BusState *bus, DeviceState *dev) -{ - BusClass *bc = BUS_GET_CLASS(bus); - - if (bc->get_fw_dev_path) { - return bc->get_fw_dev_path(dev); - } - - return NULL; -} - -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); - d = bus_get_fw_dev_path(dev->parent_bus, dev); - if (d) { - l += snprintf(p + l, size - l, "%s", d); - g_free(d); - } else { - l += snprintf(p + l, size - l, "%s", object_get_typename(OBJECT(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 g_strdup(path); -} - -char *qdev_get_dev_path(DeviceState *dev) -{ - BusClass *bc; - - if (!dev || !dev->parent_bus) { - return NULL; - } - - bc = BUS_GET_CLASS(dev->parent_bus); - if (bc->get_dev_path) { - return bc->get_dev_path(dev); - } - - return NULL; -} - -/** - * Legacy property handling - */ - -static void qdev_get_legacy_property(Object *obj, Visitor *v, void *opaque, - const char *name, Error **errp) -{ - 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); -} - -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; - } - - 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 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) -{ - gchar *name, *type; - - /* Register pointer properties as legacy properties */ - if (!prop->info->print && !prop->info->parse && - (prop->info->set || prop->info->get)) { - return; - } - - 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) -{ - Error *local_err = NULL; - Object *obj = OBJECT(dev); - - /* - * 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; - } - - object_property_add(obj, prop->name, prop->info->name, - prop->info->get, prop->info->set, - prop->info->release, - prop, &local_err); - - if (local_err) { - error_propagate(errp, local_err); - return; - } - if (prop->qtype == QTYPE_NONE) { - return; - } - - if (prop->qtype == QTYPE_QBOOL) { - object_property_set_bool(obj, prop->defval, prop->name, &local_err); - } else if (prop->info->enum_table) { - object_property_set_str(obj, prop->info->enum_table[prop->defval], - prop->name, &local_err); - } else if (prop->qtype == QTYPE_QINT) { - object_property_set_int(obj, prop->defval, prop->name, &local_err); - } - assert_no_error(local_err); -} - -static void device_initfn(Object *obj) -{ - DeviceState *dev = DEVICE(obj); - ObjectClass *class; - Property *prop; - - if (qdev_hotplug) { - dev->hotplugged = 1; - qdev_hot_added = true; - } - - dev->instance_id_alias = -1; - dev->state = DEV_STATE_CREATED; - - class = object_get_class(OBJECT(dev)); - do { - for (prop = DEVICE_CLASS(class)->props; prop && prop->name; prop++) { - qdev_property_add_legacy(dev, prop, NULL); - qdev_property_add_static(dev, prop, NULL); - } - class = object_class_get_parent(class); - } while (class != object_class_by_name(TYPE_DEVICE)); - qdev_prop_set_globals(dev); - - object_property_add_link(OBJECT(dev), "parent_bus", TYPE_BUS, - (Object **)&dev->parent_bus, NULL); -} - -/* Unlink device from bus and free the structure. */ -static void device_finalize(Object *obj) -{ - DeviceState *dev = DEVICE(obj); - BusState *bus; - DeviceClass *dc = DEVICE_GET_CLASS(dev); - - if (dev->state == DEV_STATE_INITIALIZED) { - while (dev->num_child_bus) { - bus = QLIST_FIRST(&dev->child_bus); - qbus_free(bus); - } - qdev_finalize_vmstate(dev); - if (dc->exit) { - dc->exit(dev); - } - if (dev->opts) { - qemu_opts_del(dev->opts); - } - } - if (dev->parent_bus) { - bus_remove_child(dev->parent_bus, dev); - } -} - -static void device_class_base_init(ObjectClass *class, void *data) -{ - DeviceClass *klass = DEVICE_CLASS(class); - - /* We explicitly look up properties in the superclasses, - * so do not propagate them to the subclasses. - */ - klass->props = NULL; -} - -void device_reset(DeviceState *dev) -{ - DeviceClass *klass = DEVICE_GET_CLASS(dev); - - if (klass->reset) { - klass->reset(dev); - } -} - -Object *qdev_get_machine(void) -{ - static Object *dev; - - if (dev == NULL) { - dev = container_get(object_get_root(), "/machine"); - } - - return dev; -} - -static TypeInfo device_type_info = { - .name = TYPE_DEVICE, - .parent = TYPE_OBJECT, - .instance_size = sizeof(DeviceState), - .instance_init = device_initfn, - .instance_finalize = device_finalize, - .class_base_init = device_class_base_init, - .abstract = true, - .class_size = sizeof(DeviceClass), -}; - -static void qbus_initfn(Object *obj) -{ - BusState *bus = BUS(obj); - - QTAILQ_INIT(&bus->children); -} - -static void qbus_finalize(Object *obj) -{ - BusState *bus = BUS(obj); - BusChild *kid; - - while ((kid = QTAILQ_FIRST(&bus->children)) != NULL) { - DeviceState *dev = kid->child; - qdev_free(dev); - } - if (bus->parent) { - QLIST_REMOVE(bus, sibling); - bus->parent->num_child_bus--; - } else { - qbus_unregister_reset(bus); - } - g_free((char *)bus->name); -} - -static const TypeInfo bus_info = { - .name = TYPE_BUS, - .parent = TYPE_OBJECT, - .instance_size = sizeof(BusState), - .abstract = true, - .class_size = sizeof(BusClass), - .instance_init = qbus_initfn, - .instance_finalize = qbus_finalize, -}; - -static void qdev_register_types(void) -{ - type_register_static(&bus_info); - type_register_static(&device_type_info); -} - -type_init(qdev_register_types) diff --git a/hw/qdev-properties.c b/hw/qdev-properties.c deleted file mode 100644 index 2e82cb9..0000000 --- a/hw/qdev-properties.c +++ /dev/null @@ -1,963 +0,0 @@ -#include "net.h" -#include "hw/qdev.h" -#include "qerror.h" -#include "blockdev.h" -#include "hw/block-common.h" -#include "net/hub.h" -#include "qapi/qapi-visit-core.h" - -void *qdev_get_prop_ptr(DeviceState *dev, Property *prop) -{ - void *ptr = dev; - ptr += prop->offset; - return ptr; -} - -static void get_enum(Object *obj, Visitor *v, void *opaque, - const char *name, Error **errp) -{ - DeviceState *dev = DEVICE(obj); - Property *prop = opaque; - int *ptr = qdev_get_prop_ptr(dev, prop); - - visit_type_enum(v, ptr, prop->info->enum_table, - prop->info->name, prop->name, errp); -} - -static void set_enum(Object *obj, Visitor *v, void *opaque, - const char *name, Error **errp) -{ - DeviceState *dev = DEVICE(obj); - Property *prop = opaque; - int *ptr = qdev_get_prop_ptr(dev, prop); - - if (dev->state != DEV_STATE_CREATED) { - error_set(errp, QERR_PERMISSION_DENIED); - return; - } - - visit_type_enum(v, ptr, prop->info->enum_table, - prop->info->name, prop->name, errp); -} - -/* Bit */ - -static uint32_t qdev_get_prop_mask(Property *prop) -{ - assert(prop->info == &qdev_prop_bit); - return 0x1 << prop->bitnr; -} - -static void bit_prop_set(DeviceState *dev, Property *props, bool val) -{ - uint32_t *p = qdev_get_prop_ptr(dev, props); - uint32_t mask = qdev_get_prop_mask(props); - if (val) - *p |= mask; - else - *p &= ~mask; -} - -static int print_bit(DeviceState *dev, Property *prop, char *dest, size_t len) -{ - uint32_t *p = qdev_get_prop_ptr(dev, prop); - return snprintf(dest, len, (*p & qdev_get_prop_mask(prop)) ? "on" : "off"); -} - -static void get_bit(Object *obj, Visitor *v, void *opaque, - const char *name, Error **errp) -{ - DeviceState *dev = DEVICE(obj); - Property *prop = opaque; - uint32_t *p = qdev_get_prop_ptr(dev, prop); - bool value = (*p & qdev_get_prop_mask(prop)) != 0; - - visit_type_bool(v, &value, name, errp); -} - -static void set_bit(Object *obj, Visitor *v, void *opaque, - const char *name, Error **errp) -{ - DeviceState *dev = DEVICE(obj); - Property *prop = opaque; - Error *local_err = NULL; - bool value; - - if (dev->state != DEV_STATE_CREATED) { - error_set(errp, QERR_PERMISSION_DENIED); - return; - } - - visit_type_bool(v, &value, name, &local_err); - if (local_err) { - error_propagate(errp, local_err); - return; - } - bit_prop_set(dev, prop, value); -} - -PropertyInfo qdev_prop_bit = { - .name = "boolean", - .legacy_name = "on/off", - .print = print_bit, - .get = get_bit, - .set = set_bit, -}; - -/* --- 8bit integer --- */ - -static void get_uint8(Object *obj, Visitor *v, void *opaque, - const char *name, Error **errp) -{ - DeviceState *dev = DEVICE(obj); - Property *prop = opaque; - uint8_t *ptr = qdev_get_prop_ptr(dev, prop); - - visit_type_uint8(v, ptr, name, errp); -} - -static void set_uint8(Object *obj, Visitor *v, void *opaque, - const char *name, Error **errp) -{ - DeviceState *dev = DEVICE(obj); - Property *prop = opaque; - uint8_t *ptr = qdev_get_prop_ptr(dev, prop); - - if (dev->state != DEV_STATE_CREATED) { - error_set(errp, QERR_PERMISSION_DENIED); - return; - } - - visit_type_uint8(v, ptr, name, errp); -} - -PropertyInfo qdev_prop_uint8 = { - .name = "uint8", - .get = get_uint8, - .set = set_uint8, -}; - -/* --- 8bit hex value --- */ - -static int parse_hex8(DeviceState *dev, Property *prop, const char *str) -{ - uint8_t *ptr = qdev_get_prop_ptr(dev, prop); - char *end; - - if (str[0] != '0' || str[1] != 'x') { - return -EINVAL; - } - - *ptr = strtoul(str, &end, 16); - if ((*end != '\0') || (end == str)) { - return -EINVAL; - } - - return 0; -} - -static int print_hex8(DeviceState *dev, Property *prop, char *dest, size_t len) -{ - uint8_t *ptr = qdev_get_prop_ptr(dev, prop); - return snprintf(dest, len, "0x%" PRIx8, *ptr); -} - -PropertyInfo qdev_prop_hex8 = { - .name = "uint8", - .legacy_name = "hex8", - .parse = parse_hex8, - .print = print_hex8, - .get = get_uint8, - .set = set_uint8, -}; - -/* --- 16bit integer --- */ - -static void get_uint16(Object *obj, Visitor *v, void *opaque, - const char *name, Error **errp) -{ - DeviceState *dev = DEVICE(obj); - Property *prop = opaque; - uint16_t *ptr = qdev_get_prop_ptr(dev, prop); - - visit_type_uint16(v, ptr, name, errp); -} - -static void set_uint16(Object *obj, Visitor *v, void *opaque, - const char *name, Error **errp) -{ - DeviceState *dev = DEVICE(obj); - Property *prop = opaque; - uint16_t *ptr = qdev_get_prop_ptr(dev, prop); - - if (dev->state != DEV_STATE_CREATED) { - error_set(errp, QERR_PERMISSION_DENIED); - return; - } - - visit_type_uint16(v, ptr, name, errp); -} - -PropertyInfo qdev_prop_uint16 = { - .name = "uint16", - .get = get_uint16, - .set = set_uint16, -}; - -/* --- 32bit integer --- */ - -static void get_uint32(Object *obj, Visitor *v, void *opaque, - const char *name, Error **errp) -{ - DeviceState *dev = DEVICE(obj); - Property *prop = opaque; - uint32_t *ptr = qdev_get_prop_ptr(dev, prop); - - visit_type_uint32(v, ptr, name, errp); -} - -static void set_uint32(Object *obj, Visitor *v, void *opaque, - const char *name, Error **errp) -{ - DeviceState *dev = DEVICE(obj); - Property *prop = opaque; - uint32_t *ptr = qdev_get_prop_ptr(dev, prop); - - if (dev->state != DEV_STATE_CREATED) { - error_set(errp, QERR_PERMISSION_DENIED); - return; - } - - visit_type_uint32(v, ptr, name, errp); -} - -static void get_int32(Object *obj, Visitor *v, void *opaque, - const char *name, Error **errp) -{ - DeviceState *dev = DEVICE(obj); - Property *prop = opaque; - int32_t *ptr = qdev_get_prop_ptr(dev, prop); - - visit_type_int32(v, ptr, name, errp); -} - -static void set_int32(Object *obj, Visitor *v, void *opaque, - const char *name, Error **errp) -{ - DeviceState *dev = DEVICE(obj); - Property *prop = opaque; - int32_t *ptr = qdev_get_prop_ptr(dev, prop); - - if (dev->state != DEV_STATE_CREATED) { - error_set(errp, QERR_PERMISSION_DENIED); - return; - } - - visit_type_int32(v, ptr, name, errp); -} - -PropertyInfo qdev_prop_uint32 = { - .name = "uint32", - .get = get_uint32, - .set = set_uint32, -}; - -PropertyInfo qdev_prop_int32 = { - .name = "int32", - .get = get_int32, - .set = set_int32, -}; - -/* --- 32bit hex value --- */ - -static int parse_hex32(DeviceState *dev, Property *prop, const char *str) -{ - uint32_t *ptr = qdev_get_prop_ptr(dev, prop); - char *end; - - if (str[0] != '0' || str[1] != 'x') { - return -EINVAL; - } - - *ptr = strtoul(str, &end, 16); - if ((*end != '\0') || (end == str)) { - return -EINVAL; - } - - return 0; -} - -static int print_hex32(DeviceState *dev, Property *prop, char *dest, size_t len) -{ - uint32_t *ptr = qdev_get_prop_ptr(dev, prop); - return snprintf(dest, len, "0x%" PRIx32, *ptr); -} - -PropertyInfo qdev_prop_hex32 = { - .name = "uint32", - .legacy_name = "hex32", - .parse = parse_hex32, - .print = print_hex32, - .get = get_uint32, - .set = set_uint32, -}; - -/* --- 64bit integer --- */ - -static void get_uint64(Object *obj, Visitor *v, void *opaque, - const char *name, Error **errp) -{ - DeviceState *dev = DEVICE(obj); - Property *prop = opaque; - uint64_t *ptr = qdev_get_prop_ptr(dev, prop); - - visit_type_uint64(v, ptr, name, errp); -} - -static void set_uint64(Object *obj, Visitor *v, void *opaque, - const char *name, Error **errp) -{ - DeviceState *dev = DEVICE(obj); - Property *prop = opaque; - uint64_t *ptr = qdev_get_prop_ptr(dev, prop); - - if (dev->state != DEV_STATE_CREATED) { - error_set(errp, QERR_PERMISSION_DENIED); - return; - } - - visit_type_uint64(v, ptr, name, errp); -} - -PropertyInfo qdev_prop_uint64 = { - .name = "uint64", - .get = get_uint64, - .set = set_uint64, -}; - -/* --- 64bit hex value --- */ - -static int parse_hex64(DeviceState *dev, Property *prop, const char *str) -{ - uint64_t *ptr = qdev_get_prop_ptr(dev, prop); - char *end; - - if (str[0] != '0' || str[1] != 'x') { - return -EINVAL; - } - - *ptr = strtoull(str, &end, 16); - if ((*end != '\0') || (end == str)) { - return -EINVAL; - } - - return 0; -} - -static int print_hex64(DeviceState *dev, Property *prop, char *dest, size_t len) -{ - uint64_t *ptr = qdev_get_prop_ptr(dev, prop); - return snprintf(dest, len, "0x%" PRIx64, *ptr); -} - -PropertyInfo qdev_prop_hex64 = { - .name = "uint64", - .legacy_name = "hex64", - .parse = parse_hex64, - .print = print_hex64, - .get = get_uint64, - .set = set_uint64, -}; - -/* --- string --- */ - -static void release_string(Object *obj, const char *name, void *opaque) -{ - Property *prop = opaque; - g_free(*(char **)qdev_get_prop_ptr(DEVICE(obj), prop)); -} - -static int print_string(DeviceState *dev, Property *prop, char *dest, size_t len) -{ - char **ptr = qdev_get_prop_ptr(dev, prop); - if (!*ptr) - return snprintf(dest, len, "<null>"); - return snprintf(dest, len, "\"%s\"", *ptr); -} - -static void get_string(Object *obj, Visitor *v, void *opaque, - const char *name, Error **errp) -{ - DeviceState *dev = DEVICE(obj); - Property *prop = opaque; - char **ptr = qdev_get_prop_ptr(dev, prop); - - if (!*ptr) { - char *str = (char *)""; - visit_type_str(v, &str, name, errp); - } else { - visit_type_str(v, ptr, name, errp); - } -} - -static void set_string(Object *obj, Visitor *v, void *opaque, - const char *name, Error **errp) -{ - DeviceState *dev = DEVICE(obj); - Property *prop = opaque; - char **ptr = qdev_get_prop_ptr(dev, prop); - Error *local_err = NULL; - char *str; - - if (dev->state != DEV_STATE_CREATED) { - error_set(errp, QERR_PERMISSION_DENIED); - return; - } - - visit_type_str(v, &str, name, &local_err); - if (local_err) { - error_propagate(errp, local_err); - return; - } - if (*ptr) { - g_free(*ptr); - } - *ptr = str; -} - -PropertyInfo qdev_prop_string = { - .name = "string", - .print = print_string, - .release = release_string, - .get = get_string, - .set = set_string, -}; - -/* --- pointer --- */ - -/* Not a proper property, just for dirty hacks. TODO Remove it! */ -PropertyInfo qdev_prop_ptr = { - .name = "ptr", -}; - -/* --- mac address --- */ - -/* - * accepted syntax versions: - * 01:02:03:04:05:06 - * 01-02-03-04-05-06 - */ -static void get_mac(Object *obj, Visitor *v, void *opaque, - const char *name, Error **errp) -{ - DeviceState *dev = DEVICE(obj); - Property *prop = opaque; - MACAddr *mac = qdev_get_prop_ptr(dev, prop); - char buffer[2 * 6 + 5 + 1]; - char *p = buffer; - - snprintf(buffer, sizeof(buffer), "%02x:%02x:%02x:%02x:%02x:%02x", - mac->a[0], mac->a[1], mac->a[2], - mac->a[3], mac->a[4], mac->a[5]); - - visit_type_str(v, &p, name, errp); -} - -static void set_mac(Object *obj, Visitor *v, void *opaque, - const char *name, Error **errp) -{ - DeviceState *dev = DEVICE(obj); - Property *prop = opaque; - MACAddr *mac = qdev_get_prop_ptr(dev, prop); - Error *local_err = NULL; - int i, pos; - char *str, *p; - - if (dev->state != DEV_STATE_CREATED) { - error_set(errp, QERR_PERMISSION_DENIED); - return; - } - - visit_type_str(v, &str, name, &local_err); - if (local_err) { - error_propagate(errp, local_err); - return; - } - - for (i = 0, pos = 0; i < 6; i++, pos += 3) { - if (!qemu_isxdigit(str[pos])) - goto inval; - if (!qemu_isxdigit(str[pos+1])) - goto inval; - if (i == 5) { - if (str[pos+2] != '\0') - goto inval; - } else { - if (str[pos+2] != ':' && str[pos+2] != '-') - goto inval; - } - mac->a[i] = strtol(str+pos, &p, 16); - } - g_free(str); - return; - -inval: - error_set_from_qdev_prop_error(errp, EINVAL, dev, prop, str); - g_free(str); -} - -PropertyInfo qdev_prop_macaddr = { - .name = "macaddr", - .get = get_mac, - .set = set_mac, -}; - -/* --- lost tick policy --- */ - -static const char *lost_tick_policy_table[LOST_TICK_MAX+1] = { - [LOST_TICK_DISCARD] = "discard", - [LOST_TICK_DELAY] = "delay", - [LOST_TICK_MERGE] = "merge", - [LOST_TICK_SLEW] = "slew", - [LOST_TICK_MAX] = NULL, -}; - -QEMU_BUILD_BUG_ON(sizeof(LostTickPolicy) != sizeof(int)); - -PropertyInfo qdev_prop_losttickpolicy = { - .name = "LostTickPolicy", - .enum_table = lost_tick_policy_table, - .get = get_enum, - .set = set_enum, -}; - -/* --- BIOS CHS translation */ - -static const char *bios_chs_trans_table[] = { - [BIOS_ATA_TRANSLATION_AUTO] = "auto", - [BIOS_ATA_TRANSLATION_NONE] = "none", - [BIOS_ATA_TRANSLATION_LBA] = "lba", -}; - -PropertyInfo qdev_prop_bios_chs_trans = { - .name = "bios-chs-trans", - .enum_table = bios_chs_trans_table, - .get = get_enum, - .set = set_enum, -}; - -/* --- pci address --- */ - -/* - * bus-local address, i.e. "$slot" or "$slot.$fn" - */ -static void set_pci_devfn(Object *obj, Visitor *v, void *opaque, - const char *name, Error **errp) -{ - DeviceState *dev = DEVICE(obj); - Property *prop = opaque; - int32_t value, *ptr = qdev_get_prop_ptr(dev, prop); - unsigned int slot, fn, n; - Error *local_err = NULL; - char *str; - - if (dev->state != DEV_STATE_CREATED) { - error_set(errp, QERR_PERMISSION_DENIED); - return; - } - - visit_type_str(v, &str, name, &local_err); - if (local_err) { - error_free(local_err); - local_err = NULL; - visit_type_int32(v, &value, name, &local_err); - if (local_err) { - error_propagate(errp, local_err); - } else if (value < -1 || value > 255) { - error_set(errp, QERR_INVALID_PARAMETER_VALUE, name ? name : "null", - "pci_devfn"); - } else { - *ptr = value; - } - return; - } - - if (sscanf(str, "%x.%x%n", &slot, &fn, &n) != 2) { - fn = 0; - if (sscanf(str, "%x%n", &slot, &n) != 1) { - goto invalid; - } - } - if (str[n] != '\0' || fn > 7 || slot > 31) { - goto invalid; - } - *ptr = slot << 3 | fn; - g_free(str); - return; - -invalid: - error_set_from_qdev_prop_error(errp, EINVAL, dev, prop, str); - g_free(str); -} - -static int print_pci_devfn(DeviceState *dev, Property *prop, char *dest, size_t len) -{ - int32_t *ptr = qdev_get_prop_ptr(dev, prop); - - if (*ptr == -1) { - return snprintf(dest, len, "<unset>"); - } else { - return snprintf(dest, len, "%02x.%x", *ptr >> 3, *ptr & 7); - } -} - -PropertyInfo qdev_prop_pci_devfn = { - .name = "int32", - .legacy_name = "pci-devfn", - .print = print_pci_devfn, - .get = get_int32, - .set = set_pci_devfn, -}; - -/* --- blocksize --- */ - -static void set_blocksize(Object *obj, Visitor *v, void *opaque, - const char *name, Error **errp) -{ - DeviceState *dev = DEVICE(obj); - Property *prop = opaque; - uint16_t value, *ptr = qdev_get_prop_ptr(dev, prop); - Error *local_err = NULL; - const int64_t min = 512; - const int64_t max = 32768; - - if (dev->state != DEV_STATE_CREATED) { - error_set(errp, QERR_PERMISSION_DENIED); - return; - } - - visit_type_uint16(v, &value, name, &local_err); - if (local_err) { - error_propagate(errp, local_err); - return; - } - if (value < min || value > max) { - error_set(errp, QERR_PROPERTY_VALUE_OUT_OF_RANGE, - dev->id?:"", name, (int64_t)value, min, max); - return; - } - - /* We rely on power-of-2 blocksizes for bitmasks */ - if ((value & (value - 1)) != 0) { - error_set(errp, QERR_PROPERTY_VALUE_NOT_POWER_OF_2, - dev->id?:"", name, (int64_t)value); - return; - } - - *ptr = value; -} - -PropertyInfo qdev_prop_blocksize = { - .name = "blocksize", - .get = get_uint16, - .set = set_blocksize, -}; - -/* --- pci host address --- */ - -static void get_pci_host_devaddr(Object *obj, Visitor *v, void *opaque, - const char *name, Error **errp) -{ - DeviceState *dev = DEVICE(obj); - Property *prop = opaque; - PCIHostDeviceAddress *addr = qdev_get_prop_ptr(dev, prop); - char buffer[] = "xxxx:xx:xx.x"; - char *p = buffer; - int rc = 0; - - rc = snprintf(buffer, sizeof(buffer), "%04x:%02x:%02x.%d", - addr->domain, addr->bus, addr->slot, addr->function); - assert(rc == sizeof(buffer) - 1); - - visit_type_str(v, &p, name, errp); -} - -/* - * Parse [<domain>:]<bus>:<slot>.<func> - * if <domain> is not supplied, it's assumed to be 0. - */ -static void set_pci_host_devaddr(Object *obj, Visitor *v, void *opaque, - const char *name, Error **errp) -{ - DeviceState *dev = DEVICE(obj); - Property *prop = opaque; - PCIHostDeviceAddress *addr = qdev_get_prop_ptr(dev, prop); - Error *local_err = NULL; - char *str, *p; - char *e; - unsigned long val; - unsigned long dom = 0, bus = 0; - unsigned int slot = 0, func = 0; - - if (dev->state != DEV_STATE_CREATED) { - error_set(errp, QERR_PERMISSION_DENIED); - return; - } - - visit_type_str(v, &str, name, &local_err); - if (local_err) { - error_propagate(errp, local_err); - return; - } - - p = str; - val = strtoul(p, &e, 16); - if (e == p || *e != ':') { - goto inval; - } - bus = val; - - p = e + 1; - val = strtoul(p, &e, 16); - if (e == p) { - goto inval; - } - if (*e == ':') { - dom = bus; - bus = val; - p = e + 1; - val = strtoul(p, &e, 16); - if (e == p) { - goto inval; - } - } - slot = val; - - if (*e != '.') { - goto inval; - } - p = e + 1; - val = strtoul(p, &e, 10); - if (e == p) { - goto inval; - } - func = val; - - if (dom > 0xffff || bus > 0xff || slot > 0x1f || func > 7) { - goto inval; - } - - if (*e) { - goto inval; - } - - addr->domain = dom; - addr->bus = bus; - addr->slot = slot; - addr->function = func; - - g_free(str); - return; - -inval: - error_set_from_qdev_prop_error(errp, EINVAL, dev, prop, str); - g_free(str); -} - -PropertyInfo qdev_prop_pci_host_devaddr = { - .name = "pci-host-devaddr", - .get = get_pci_host_devaddr, - .set = set_pci_host_devaddr, -}; - -/* --- public helpers --- */ - -static Property *qdev_prop_walk(Property *props, const char *name) -{ - if (!props) - return NULL; - while (props->name) { - if (strcmp(props->name, name) == 0) - return props; - props++; - } - return NULL; -} - -static Property *qdev_prop_find(DeviceState *dev, const char *name) -{ - ObjectClass *class; - Property *prop; - - /* device properties */ - class = object_get_class(OBJECT(dev)); - do { - prop = qdev_prop_walk(DEVICE_CLASS(class)->props, name); - if (prop) { - return prop; - } - class = object_class_get_parent(class); - } while (class != object_class_by_name(TYPE_DEVICE)); - - return NULL; -} - -void error_set_from_qdev_prop_error(Error **errp, int ret, DeviceState *dev, - Property *prop, const char *value) -{ - switch (ret) { - case -EEXIST: - error_set(errp, QERR_PROPERTY_VALUE_IN_USE, - object_get_typename(OBJECT(dev)), prop->name, value); - break; - default: - case -EINVAL: - error_set(errp, QERR_PROPERTY_VALUE_BAD, - object_get_typename(OBJECT(dev)), prop->name, value); - break; - case -ENOENT: - error_set(errp, QERR_PROPERTY_VALUE_NOT_FOUND, - object_get_typename(OBJECT(dev)), prop->name, value); - break; - case 0: - break; - } -} - -int qdev_prop_parse(DeviceState *dev, const char *name, const char *value) -{ - char *legacy_name; - Error *err = NULL; - - legacy_name = g_strdup_printf("legacy-%s", name); - if (object_property_get_type(OBJECT(dev), legacy_name, NULL)) { - object_property_parse(OBJECT(dev), value, legacy_name, &err); - } else { - object_property_parse(OBJECT(dev), value, name, &err); - } - g_free(legacy_name); - - if (err) { - qerror_report_err(err); - error_free(err); - return -1; - } - return 0; -} - -void qdev_prop_set_bit(DeviceState *dev, const char *name, bool value) -{ - Error *errp = NULL; - object_property_set_bool(OBJECT(dev), value, name, &errp); - assert_no_error(errp); -} - -void qdev_prop_set_uint8(DeviceState *dev, const char *name, uint8_t value) -{ - Error *errp = NULL; - object_property_set_int(OBJECT(dev), value, name, &errp); - assert_no_error(errp); -} - -void qdev_prop_set_uint16(DeviceState *dev, const char *name, uint16_t value) -{ - Error *errp = NULL; - object_property_set_int(OBJECT(dev), value, name, &errp); - assert_no_error(errp); -} - -void qdev_prop_set_uint32(DeviceState *dev, const char *name, uint32_t value) -{ - Error *errp = NULL; - object_property_set_int(OBJECT(dev), value, name, &errp); - assert_no_error(errp); -} - -void qdev_prop_set_int32(DeviceState *dev, const char *name, int32_t value) -{ - Error *errp = NULL; - object_property_set_int(OBJECT(dev), value, name, &errp); - assert_no_error(errp); -} - -void qdev_prop_set_uint64(DeviceState *dev, const char *name, uint64_t value) -{ - Error *errp = NULL; - object_property_set_int(OBJECT(dev), value, name, &errp); - assert_no_error(errp); -} - -void qdev_prop_set_string(DeviceState *dev, const char *name, const char *value) -{ - Error *errp = NULL; - object_property_set_str(OBJECT(dev), value, name, &errp); - assert_no_error(errp); -} - -void qdev_prop_set_macaddr(DeviceState *dev, const char *name, uint8_t *value) -{ - Error *errp = NULL; - char str[2 * 6 + 5 + 1]; - snprintf(str, sizeof(str), "%02x:%02x:%02x:%02x:%02x:%02x", - value[0], value[1], value[2], value[3], value[4], value[5]); - - object_property_set_str(OBJECT(dev), str, name, &errp); - assert_no_error(errp); -} - -void qdev_prop_set_enum(DeviceState *dev, const char *name, int value) -{ - Property *prop; - Error *errp = NULL; - - prop = qdev_prop_find(dev, name); - object_property_set_str(OBJECT(dev), prop->info->enum_table[value], - name, &errp); - assert_no_error(errp); -} - -void qdev_prop_set_ptr(DeviceState *dev, const char *name, void *value) -{ - Property *prop; - void **ptr; - - prop = qdev_prop_find(dev, name); - assert(prop && prop->info == &qdev_prop_ptr); - ptr = qdev_get_prop_ptr(dev, prop); - *ptr = value; -} - -static QTAILQ_HEAD(, GlobalProperty) global_props = QTAILQ_HEAD_INITIALIZER(global_props); - -void qdev_prop_register_global(GlobalProperty *prop) -{ - QTAILQ_INSERT_TAIL(&global_props, prop, next); -} - -void qdev_prop_register_global_list(GlobalProperty *props) -{ - int i; - - for (i = 0; props[i].driver != NULL; i++) { - qdev_prop_register_global(props+i); - } -} - -void qdev_prop_set_globals(DeviceState *dev) -{ - ObjectClass *class = object_get_class(OBJECT(dev)); - - do { - GlobalProperty *prop; - QTAILQ_FOREACH(prop, &global_props, next) { - if (strcmp(object_class_get_name(class), prop->driver) != 0) { - continue; - } - if (qdev_prop_parse(dev, prop->property, prop->value) != 0) { - exit(1); - } - } - class = object_class_get_parent(class); - } while (class); -} - diff --git a/qom/Makefile.objs b/qom/Makefile.objs index 5ef060a..09ef871 100644 --- a/qom/Makefile.objs +++ b/qom/Makefile.objs @@ -1,4 +1,4 @@ qom-obj-y = object.o container.o qom-qobject.o -qom-obj-twice-y = cpu.o +qom-obj-twice-y = cpu.o qdev-core.o qdev-properties.o common-obj-y = $(qom-obj-twice-y) user-obj-y = $(qom-obj-twice-y) diff --git a/qom/qdev-core.c b/qom/qdev-core.c new file mode 100644 index 0000000..fbb7cb5 --- /dev/null +++ b/qom/qdev-core.c @@ -0,0 +1,727 @@ +/* + * Dynamic device configuration and creation. + * + * Copyright (c) 2009 CodeSourcery + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + +/* The theory here is that it should be possible to create a machine without + knowledge of specific devices. Historically board init routines have + passed a bunch of arguments to each device, requiring the board know + exactly which device it is dealing with. This file provides an abstract + API for device configuration and initialization. Devices will generally + inherit from a particular bus (e.g. PCI or I2C) rather than + this API directly. */ + +#include "hw/qdev.h" +#include "sysemu.h" +#include "error.h" +#include "qapi/qapi-visit-core.h" + +int qdev_hotplug = 0; +static bool qdev_hot_added = false; +static bool qdev_hot_removed = false; + +/* vmstate handling: + * + * The real implementations are on qdev-system.c. Those are weak symbols + * used by *-user. + */ +void GCC_WEAK qdev_init_vmstate(DeviceState *dev) +{ +} + +void GCC_WEAK qdev_finalize_vmstate(DeviceState *dev) +{ +} + +/* reset handler register/unregister: + * + * The real implementations are on qdev-system.c. Those are weak symbols + * used by *-user. + */ +void GCC_WEAK qbus_register_reset(BusState *bus) +{ +} + +void GCC_WEAK qbus_unregister_reset(BusState *bus) +{ +} + +const char *qdev_fw_name(DeviceState *dev) +{ + DeviceClass *dc = DEVICE_GET_CLASS(dev); + + if (dc->fw_name) { + return dc->fw_name; + } + + return object_get_typename(OBJECT(dev)); +} + +static void qdev_property_add_legacy(DeviceState *dev, Property *prop, + Error **errp); + +static void bus_remove_child(BusState *bus, DeviceState *child) +{ + BusChild *kid; + + QTAILQ_FOREACH(kid, &bus->children, sibling) { + if (kid->child == child) { + char name[32]; + + snprintf(name, sizeof(name), "child[%d]", kid->index); + QTAILQ_REMOVE(&bus->children, kid, sibling); + object_property_del(OBJECT(bus), name, NULL); + g_free(kid); + return; + } + } +} + +static void bus_add_child(BusState *bus, DeviceState *child) +{ + char name[32]; + BusChild *kid = g_malloc0(sizeof(*kid)); + + if (qdev_hotplug) { + assert(bus->allow_hotplug); + } + + kid->index = bus->max_index++; + kid->child = child; + + QTAILQ_INSERT_HEAD(&bus->children, kid, sibling); + + snprintf(name, sizeof(name), "child[%d]", kid->index); + object_property_add_link(OBJECT(bus), name, + object_get_typename(OBJECT(child)), + (Object **)&kid->child, + NULL); +} + +void qdev_set_parent_bus(DeviceState *dev, BusState *bus) +{ + dev->parent_bus = bus; + bus_add_child(bus, 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. + On failure, destroy the device and return negative value. + Return 0 on success. */ +int qdev_init(DeviceState *dev) +{ + DeviceClass *dc = DEVICE_GET_CLASS(dev); + int rc; + + assert(dev->state == DEV_STATE_CREATED); + + rc = dc->init(dev); + if (rc < 0) { + qdev_free(dev); + return rc; + } + + if (!OBJECT(dev)->parent) { + static int unattached_count = 0; + gchar *name = g_strdup_printf("device[%d]", unattached_count++); + + object_property_add_child(container_get(qdev_get_machine(), + "/unattached"), + name, OBJECT(dev), NULL); + g_free(name); + } + + qdev_init_vmstate(dev); + dev->state = DEV_STATE_INITIALIZED; + if (dev->hotplugged) { + device_reset(dev); + } + 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; +} + +void qdev_unplug(DeviceState *dev, Error **errp) +{ + DeviceClass *dc = DEVICE_GET_CLASS(dev); + + if (!dev->parent_bus->allow_hotplug) { + error_set(errp, QERR_BUS_NO_HOTPLUG, dev->parent_bus->name); + return; + } + assert(dc->unplug != NULL); + + qdev_hot_removed = true; + + if (dc->unplug(dev) < 0) { + error_set(errp, QERR_UNDEFINED_ERROR); + return; + } +} + +static int qdev_reset_one(DeviceState *dev, void *opaque) +{ + device_reset(dev); + + return 0; +} + +static int qbus_reset_one(BusState *bus, void *opaque) +{ + BusClass *bc = BUS_GET_CLASS(bus); + if (bc->reset) { + return bc->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_fn(void *opaque) +{ + BusState *bus = opaque; + 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) +{ + /* just zap it */ + qdev_free(dev); + return 0; +} + + +/* Like qdev_init(), but terminate program via error_report() instead of + returning an error value. This is okay during machine creation. + Don't use for hotplug, because there callers need to recover from + failure. Exception: if you know the device's init() callback can't + fail, then qdev_init_nofail() can't fail either, and is therefore + usable even then. But relying on the device implementation that + way is somewhat unclean, and best avoided. */ +void qdev_init_nofail(DeviceState *dev) +{ + const char *typename = object_get_typename(OBJECT(dev)); + + if (qdev_init(dev) < 0) { + error_report("Initialization of device %s failed", typename); + exit(1); + } +} + +/* Unlink device from bus and free the structure. */ +void qdev_free(DeviceState *dev) +{ + object_delete(OBJECT(dev)); +} + +void qdev_machine_creation_done(void) +{ + /* + * ok, initial machine setup is done, starting from now we can + * only create hotpluggable devices + */ + qdev_hotplug = 1; +} + +bool qdev_machine_modified(void) +{ + return qdev_hot_added || qdev_hot_removed; +} + +BusState *qdev_get_parent_bus(DeviceState *dev) +{ + return dev->parent_bus; +} + +BusState *qdev_get_child_bus(DeviceState *dev, const char *name) +{ + BusState *bus; + + QLIST_FOREACH(bus, &dev->child_bus, sibling) { + if (strcmp(name, bus->name) == 0) { + return bus; + } + } + return NULL; +} + +int qbus_walk_children(BusState *bus, qdev_walkerfn *devfn, + qbus_walkerfn *busfn, void *opaque) +{ + BusChild *kid; + int err; + + if (busfn) { + err = busfn(bus, opaque); + if (err) { + return err; + } + } + + QTAILQ_FOREACH(kid, &bus->children, sibling) { + err = qdev_walk_children(kid->child, 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; +} + +DeviceState *qdev_find_recursive(BusState *bus, const char *id) +{ + BusChild *kid; + DeviceState *ret; + BusState *child; + + QTAILQ_FOREACH(kid, &bus->children, sibling) { + DeviceState *dev = kid->child; + + if (dev->id && strcmp(dev->id, id) == 0) { + return dev; + } + + QLIST_FOREACH(child, &dev->child_bus, sibling) { + ret = qdev_find_recursive(child, id); + if (ret) { + return ret; + } + } + } + return NULL; +} + +static void qbus_realize(BusState *bus) +{ + const char *typename = object_get_typename(OBJECT(bus)); + char *buf; + int i,len; + + if (bus->name) { + /* use supplied name */ + } else if (bus->parent && bus->parent->id) { + /* parent device has id -> use it for bus name */ + len = strlen(bus->parent->id) + 16; + buf = g_malloc(len); + snprintf(buf, len, "%s.%d", bus->parent->id, bus->parent->num_child_bus); + bus->name = buf; + } else { + /* no id -> use lowercase bus type for bus name */ + len = strlen(typename) + 16; + buf = g_malloc(len); + len = snprintf(buf, len, "%s.%d", typename, + bus->parent ? bus->parent->num_child_bus : 0); + for (i = 0; i < len; i++) + buf[i] = qemu_tolower(buf[i]); + bus->name = buf; + } + + if (bus->parent) { + QLIST_INSERT_HEAD(&bus->parent->child_bus, bus, sibling); + bus->parent->num_child_bus++; + object_property_add_child(OBJECT(bus->parent), bus->name, OBJECT(bus), NULL); + } else { + qbus_register_reset(bus); + } +} + +void qbus_create_inplace(BusState *bus, const char *typename, + DeviceState *parent, const char *name) +{ + object_initialize(bus, typename); + + bus->parent = parent; + bus->name = name ? g_strdup(name) : NULL; + qbus_realize(bus); +} + +BusState *qbus_create(const char *typename, DeviceState *parent, const char *name) +{ + BusState *bus; + + bus = BUS(object_new(typename)); + bus->qom_allocated = true; + + bus->parent = parent; + bus->name = name ? g_strdup(name) : NULL; + qbus_realize(bus); + + return bus; +} + +void qbus_free(BusState *bus) +{ + if (bus->qom_allocated) { + object_delete(OBJECT(bus)); + } else { + object_finalize(OBJECT(bus)); + if (bus->glib_allocated) { + g_free(bus); + } + } +} + +static char *bus_get_fw_dev_path(BusState *bus, DeviceState *dev) +{ + BusClass *bc = BUS_GET_CLASS(bus); + + if (bc->get_fw_dev_path) { + return bc->get_fw_dev_path(dev); + } + + return NULL; +} + +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); + d = bus_get_fw_dev_path(dev->parent_bus, dev); + if (d) { + l += snprintf(p + l, size - l, "%s", d); + g_free(d); + } else { + l += snprintf(p + l, size - l, "%s", object_get_typename(OBJECT(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 g_strdup(path); +} + +char *qdev_get_dev_path(DeviceState *dev) +{ + BusClass *bc; + + if (!dev || !dev->parent_bus) { + return NULL; + } + + bc = BUS_GET_CLASS(dev->parent_bus); + if (bc->get_dev_path) { + return bc->get_dev_path(dev); + } + + return NULL; +} + +/** + * Legacy property handling + */ + +static void qdev_get_legacy_property(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) +{ + 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); +} + +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; + } + + 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 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) +{ + gchar *name, *type; + + /* Register pointer properties as legacy properties */ + if (!prop->info->print && !prop->info->parse && + (prop->info->set || prop->info->get)) { + return; + } + + 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) +{ + Error *local_err = NULL; + Object *obj = OBJECT(dev); + + /* + * 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; + } + + object_property_add(obj, prop->name, prop->info->name, + prop->info->get, prop->info->set, + prop->info->release, + prop, &local_err); + + if (local_err) { + error_propagate(errp, local_err); + return; + } + if (prop->qtype == QTYPE_NONE) { + return; + } + + if (prop->qtype == QTYPE_QBOOL) { + object_property_set_bool(obj, prop->defval, prop->name, &local_err); + } else if (prop->info->enum_table) { + object_property_set_str(obj, prop->info->enum_table[prop->defval], + prop->name, &local_err); + } else if (prop->qtype == QTYPE_QINT) { + object_property_set_int(obj, prop->defval, prop->name, &local_err); + } + assert_no_error(local_err); +} + +static void device_initfn(Object *obj) +{ + DeviceState *dev = DEVICE(obj); + ObjectClass *class; + Property *prop; + + if (qdev_hotplug) { + dev->hotplugged = 1; + qdev_hot_added = true; + } + + dev->instance_id_alias = -1; + dev->state = DEV_STATE_CREATED; + + class = object_get_class(OBJECT(dev)); + do { + for (prop = DEVICE_CLASS(class)->props; prop && prop->name; prop++) { + qdev_property_add_legacy(dev, prop, NULL); + qdev_property_add_static(dev, prop, NULL); + } + class = object_class_get_parent(class); + } while (class != object_class_by_name(TYPE_DEVICE)); + qdev_prop_set_globals(dev); + + object_property_add_link(OBJECT(dev), "parent_bus", TYPE_BUS, + (Object **)&dev->parent_bus, NULL); +} + +/* Unlink device from bus and free the structure. */ +static void device_finalize(Object *obj) +{ + DeviceState *dev = DEVICE(obj); + BusState *bus; + DeviceClass *dc = DEVICE_GET_CLASS(dev); + + if (dev->state == DEV_STATE_INITIALIZED) { + while (dev->num_child_bus) { + bus = QLIST_FIRST(&dev->child_bus); + qbus_free(bus); + } + qdev_finalize_vmstate(dev); + if (dc->exit) { + dc->exit(dev); + } + if (dev->opts) { + qemu_opts_del(dev->opts); + } + } + if (dev->parent_bus) { + bus_remove_child(dev->parent_bus, dev); + } +} + +static void device_class_base_init(ObjectClass *class, void *data) +{ + DeviceClass *klass = DEVICE_CLASS(class); + + /* We explicitly look up properties in the superclasses, + * so do not propagate them to the subclasses. + */ + klass->props = NULL; +} + +void device_reset(DeviceState *dev) +{ + DeviceClass *klass = DEVICE_GET_CLASS(dev); + + if (klass->reset) { + klass->reset(dev); + } +} + +Object *qdev_get_machine(void) +{ + static Object *dev; + + if (dev == NULL) { + dev = container_get(object_get_root(), "/machine"); + } + + return dev; +} + +static TypeInfo device_type_info = { + .name = TYPE_DEVICE, + .parent = TYPE_OBJECT, + .instance_size = sizeof(DeviceState), + .instance_init = device_initfn, + .instance_finalize = device_finalize, + .class_base_init = device_class_base_init, + .abstract = true, + .class_size = sizeof(DeviceClass), +}; + +static void qbus_initfn(Object *obj) +{ + BusState *bus = BUS(obj); + + QTAILQ_INIT(&bus->children); +} + +static void qbus_finalize(Object *obj) +{ + BusState *bus = BUS(obj); + BusChild *kid; + + while ((kid = QTAILQ_FIRST(&bus->children)) != NULL) { + DeviceState *dev = kid->child; + qdev_free(dev); + } + if (bus->parent) { + QLIST_REMOVE(bus, sibling); + bus->parent->num_child_bus--; + } else { + qbus_unregister_reset(bus); + } + g_free((char *)bus->name); +} + +static const TypeInfo bus_info = { + .name = TYPE_BUS, + .parent = TYPE_OBJECT, + .instance_size = sizeof(BusState), + .abstract = true, + .class_size = sizeof(BusClass), + .instance_init = qbus_initfn, + .instance_finalize = qbus_finalize, +}; + +static void qdev_register_types(void) +{ + type_register_static(&bus_info); + type_register_static(&device_type_info); +} + +type_init(qdev_register_types) diff --git a/qom/qdev-properties.c b/qom/qdev-properties.c new file mode 100644 index 0000000..2e82cb9 --- /dev/null +++ b/qom/qdev-properties.c @@ -0,0 +1,963 @@ +#include "net.h" +#include "hw/qdev.h" +#include "qerror.h" +#include "blockdev.h" +#include "hw/block-common.h" +#include "net/hub.h" +#include "qapi/qapi-visit-core.h" + +void *qdev_get_prop_ptr(DeviceState *dev, Property *prop) +{ + void *ptr = dev; + ptr += prop->offset; + return ptr; +} + +static void get_enum(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) +{ + DeviceState *dev = DEVICE(obj); + Property *prop = opaque; + int *ptr = qdev_get_prop_ptr(dev, prop); + + visit_type_enum(v, ptr, prop->info->enum_table, + prop->info->name, prop->name, errp); +} + +static void set_enum(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) +{ + DeviceState *dev = DEVICE(obj); + Property *prop = opaque; + int *ptr = qdev_get_prop_ptr(dev, prop); + + if (dev->state != DEV_STATE_CREATED) { + error_set(errp, QERR_PERMISSION_DENIED); + return; + } + + visit_type_enum(v, ptr, prop->info->enum_table, + prop->info->name, prop->name, errp); +} + +/* Bit */ + +static uint32_t qdev_get_prop_mask(Property *prop) +{ + assert(prop->info == &qdev_prop_bit); + return 0x1 << prop->bitnr; +} + +static void bit_prop_set(DeviceState *dev, Property *props, bool val) +{ + uint32_t *p = qdev_get_prop_ptr(dev, props); + uint32_t mask = qdev_get_prop_mask(props); + if (val) + *p |= mask; + else + *p &= ~mask; +} + +static int print_bit(DeviceState *dev, Property *prop, char *dest, size_t len) +{ + uint32_t *p = qdev_get_prop_ptr(dev, prop); + return snprintf(dest, len, (*p & qdev_get_prop_mask(prop)) ? "on" : "off"); +} + +static void get_bit(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) +{ + DeviceState *dev = DEVICE(obj); + Property *prop = opaque; + uint32_t *p = qdev_get_prop_ptr(dev, prop); + bool value = (*p & qdev_get_prop_mask(prop)) != 0; + + visit_type_bool(v, &value, name, errp); +} + +static void set_bit(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) +{ + DeviceState *dev = DEVICE(obj); + Property *prop = opaque; + Error *local_err = NULL; + bool value; + + if (dev->state != DEV_STATE_CREATED) { + error_set(errp, QERR_PERMISSION_DENIED); + return; + } + + visit_type_bool(v, &value, name, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } + bit_prop_set(dev, prop, value); +} + +PropertyInfo qdev_prop_bit = { + .name = "boolean", + .legacy_name = "on/off", + .print = print_bit, + .get = get_bit, + .set = set_bit, +}; + +/* --- 8bit integer --- */ + +static void get_uint8(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) +{ + DeviceState *dev = DEVICE(obj); + Property *prop = opaque; + uint8_t *ptr = qdev_get_prop_ptr(dev, prop); + + visit_type_uint8(v, ptr, name, errp); +} + +static void set_uint8(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) +{ + DeviceState *dev = DEVICE(obj); + Property *prop = opaque; + uint8_t *ptr = qdev_get_prop_ptr(dev, prop); + + if (dev->state != DEV_STATE_CREATED) { + error_set(errp, QERR_PERMISSION_DENIED); + return; + } + + visit_type_uint8(v, ptr, name, errp); +} + +PropertyInfo qdev_prop_uint8 = { + .name = "uint8", + .get = get_uint8, + .set = set_uint8, +}; + +/* --- 8bit hex value --- */ + +static int parse_hex8(DeviceState *dev, Property *prop, const char *str) +{ + uint8_t *ptr = qdev_get_prop_ptr(dev, prop); + char *end; + + if (str[0] != '0' || str[1] != 'x') { + return -EINVAL; + } + + *ptr = strtoul(str, &end, 16); + if ((*end != '\0') || (end == str)) { + return -EINVAL; + } + + return 0; +} + +static int print_hex8(DeviceState *dev, Property *prop, char *dest, size_t len) +{ + uint8_t *ptr = qdev_get_prop_ptr(dev, prop); + return snprintf(dest, len, "0x%" PRIx8, *ptr); +} + +PropertyInfo qdev_prop_hex8 = { + .name = "uint8", + .legacy_name = "hex8", + .parse = parse_hex8, + .print = print_hex8, + .get = get_uint8, + .set = set_uint8, +}; + +/* --- 16bit integer --- */ + +static void get_uint16(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) +{ + DeviceState *dev = DEVICE(obj); + Property *prop = opaque; + uint16_t *ptr = qdev_get_prop_ptr(dev, prop); + + visit_type_uint16(v, ptr, name, errp); +} + +static void set_uint16(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) +{ + DeviceState *dev = DEVICE(obj); + Property *prop = opaque; + uint16_t *ptr = qdev_get_prop_ptr(dev, prop); + + if (dev->state != DEV_STATE_CREATED) { + error_set(errp, QERR_PERMISSION_DENIED); + return; + } + + visit_type_uint16(v, ptr, name, errp); +} + +PropertyInfo qdev_prop_uint16 = { + .name = "uint16", + .get = get_uint16, + .set = set_uint16, +}; + +/* --- 32bit integer --- */ + +static void get_uint32(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) +{ + DeviceState *dev = DEVICE(obj); + Property *prop = opaque; + uint32_t *ptr = qdev_get_prop_ptr(dev, prop); + + visit_type_uint32(v, ptr, name, errp); +} + +static void set_uint32(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) +{ + DeviceState *dev = DEVICE(obj); + Property *prop = opaque; + uint32_t *ptr = qdev_get_prop_ptr(dev, prop); + + if (dev->state != DEV_STATE_CREATED) { + error_set(errp, QERR_PERMISSION_DENIED); + return; + } + + visit_type_uint32(v, ptr, name, errp); +} + +static void get_int32(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) +{ + DeviceState *dev = DEVICE(obj); + Property *prop = opaque; + int32_t *ptr = qdev_get_prop_ptr(dev, prop); + + visit_type_int32(v, ptr, name, errp); +} + +static void set_int32(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) +{ + DeviceState *dev = DEVICE(obj); + Property *prop = opaque; + int32_t *ptr = qdev_get_prop_ptr(dev, prop); + + if (dev->state != DEV_STATE_CREATED) { + error_set(errp, QERR_PERMISSION_DENIED); + return; + } + + visit_type_int32(v, ptr, name, errp); +} + +PropertyInfo qdev_prop_uint32 = { + .name = "uint32", + .get = get_uint32, + .set = set_uint32, +}; + +PropertyInfo qdev_prop_int32 = { + .name = "int32", + .get = get_int32, + .set = set_int32, +}; + +/* --- 32bit hex value --- */ + +static int parse_hex32(DeviceState *dev, Property *prop, const char *str) +{ + uint32_t *ptr = qdev_get_prop_ptr(dev, prop); + char *end; + + if (str[0] != '0' || str[1] != 'x') { + return -EINVAL; + } + + *ptr = strtoul(str, &end, 16); + if ((*end != '\0') || (end == str)) { + return -EINVAL; + } + + return 0; +} + +static int print_hex32(DeviceState *dev, Property *prop, char *dest, size_t len) +{ + uint32_t *ptr = qdev_get_prop_ptr(dev, prop); + return snprintf(dest, len, "0x%" PRIx32, *ptr); +} + +PropertyInfo qdev_prop_hex32 = { + .name = "uint32", + .legacy_name = "hex32", + .parse = parse_hex32, + .print = print_hex32, + .get = get_uint32, + .set = set_uint32, +}; + +/* --- 64bit integer --- */ + +static void get_uint64(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) +{ + DeviceState *dev = DEVICE(obj); + Property *prop = opaque; + uint64_t *ptr = qdev_get_prop_ptr(dev, prop); + + visit_type_uint64(v, ptr, name, errp); +} + +static void set_uint64(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) +{ + DeviceState *dev = DEVICE(obj); + Property *prop = opaque; + uint64_t *ptr = qdev_get_prop_ptr(dev, prop); + + if (dev->state != DEV_STATE_CREATED) { + error_set(errp, QERR_PERMISSION_DENIED); + return; + } + + visit_type_uint64(v, ptr, name, errp); +} + +PropertyInfo qdev_prop_uint64 = { + .name = "uint64", + .get = get_uint64, + .set = set_uint64, +}; + +/* --- 64bit hex value --- */ + +static int parse_hex64(DeviceState *dev, Property *prop, const char *str) +{ + uint64_t *ptr = qdev_get_prop_ptr(dev, prop); + char *end; + + if (str[0] != '0' || str[1] != 'x') { + return -EINVAL; + } + + *ptr = strtoull(str, &end, 16); + if ((*end != '\0') || (end == str)) { + return -EINVAL; + } + + return 0; +} + +static int print_hex64(DeviceState *dev, Property *prop, char *dest, size_t len) +{ + uint64_t *ptr = qdev_get_prop_ptr(dev, prop); + return snprintf(dest, len, "0x%" PRIx64, *ptr); +} + +PropertyInfo qdev_prop_hex64 = { + .name = "uint64", + .legacy_name = "hex64", + .parse = parse_hex64, + .print = print_hex64, + .get = get_uint64, + .set = set_uint64, +}; + +/* --- string --- */ + +static void release_string(Object *obj, const char *name, void *opaque) +{ + Property *prop = opaque; + g_free(*(char **)qdev_get_prop_ptr(DEVICE(obj), prop)); +} + +static int print_string(DeviceState *dev, Property *prop, char *dest, size_t len) +{ + char **ptr = qdev_get_prop_ptr(dev, prop); + if (!*ptr) + return snprintf(dest, len, "<null>"); + return snprintf(dest, len, "\"%s\"", *ptr); +} + +static void get_string(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) +{ + DeviceState *dev = DEVICE(obj); + Property *prop = opaque; + char **ptr = qdev_get_prop_ptr(dev, prop); + + if (!*ptr) { + char *str = (char *)""; + visit_type_str(v, &str, name, errp); + } else { + visit_type_str(v, ptr, name, errp); + } +} + +static void set_string(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) +{ + DeviceState *dev = DEVICE(obj); + Property *prop = opaque; + char **ptr = qdev_get_prop_ptr(dev, prop); + Error *local_err = NULL; + char *str; + + if (dev->state != DEV_STATE_CREATED) { + error_set(errp, QERR_PERMISSION_DENIED); + return; + } + + visit_type_str(v, &str, name, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } + if (*ptr) { + g_free(*ptr); + } + *ptr = str; +} + +PropertyInfo qdev_prop_string = { + .name = "string", + .print = print_string, + .release = release_string, + .get = get_string, + .set = set_string, +}; + +/* --- pointer --- */ + +/* Not a proper property, just for dirty hacks. TODO Remove it! */ +PropertyInfo qdev_prop_ptr = { + .name = "ptr", +}; + +/* --- mac address --- */ + +/* + * accepted syntax versions: + * 01:02:03:04:05:06 + * 01-02-03-04-05-06 + */ +static void get_mac(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) +{ + DeviceState *dev = DEVICE(obj); + Property *prop = opaque; + MACAddr *mac = qdev_get_prop_ptr(dev, prop); + char buffer[2 * 6 + 5 + 1]; + char *p = buffer; + + snprintf(buffer, sizeof(buffer), "%02x:%02x:%02x:%02x:%02x:%02x", + mac->a[0], mac->a[1], mac->a[2], + mac->a[3], mac->a[4], mac->a[5]); + + visit_type_str(v, &p, name, errp); +} + +static void set_mac(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) +{ + DeviceState *dev = DEVICE(obj); + Property *prop = opaque; + MACAddr *mac = qdev_get_prop_ptr(dev, prop); + Error *local_err = NULL; + int i, pos; + char *str, *p; + + if (dev->state != DEV_STATE_CREATED) { + error_set(errp, QERR_PERMISSION_DENIED); + return; + } + + visit_type_str(v, &str, name, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } + + for (i = 0, pos = 0; i < 6; i++, pos += 3) { + if (!qemu_isxdigit(str[pos])) + goto inval; + if (!qemu_isxdigit(str[pos+1])) + goto inval; + if (i == 5) { + if (str[pos+2] != '\0') + goto inval; + } else { + if (str[pos+2] != ':' && str[pos+2] != '-') + goto inval; + } + mac->a[i] = strtol(str+pos, &p, 16); + } + g_free(str); + return; + +inval: + error_set_from_qdev_prop_error(errp, EINVAL, dev, prop, str); + g_free(str); +} + +PropertyInfo qdev_prop_macaddr = { + .name = "macaddr", + .get = get_mac, + .set = set_mac, +}; + +/* --- lost tick policy --- */ + +static const char *lost_tick_policy_table[LOST_TICK_MAX+1] = { + [LOST_TICK_DISCARD] = "discard", + [LOST_TICK_DELAY] = "delay", + [LOST_TICK_MERGE] = "merge", + [LOST_TICK_SLEW] = "slew", + [LOST_TICK_MAX] = NULL, +}; + +QEMU_BUILD_BUG_ON(sizeof(LostTickPolicy) != sizeof(int)); + +PropertyInfo qdev_prop_losttickpolicy = { + .name = "LostTickPolicy", + .enum_table = lost_tick_policy_table, + .get = get_enum, + .set = set_enum, +}; + +/* --- BIOS CHS translation */ + +static const char *bios_chs_trans_table[] = { + [BIOS_ATA_TRANSLATION_AUTO] = "auto", + [BIOS_ATA_TRANSLATION_NONE] = "none", + [BIOS_ATA_TRANSLATION_LBA] = "lba", +}; + +PropertyInfo qdev_prop_bios_chs_trans = { + .name = "bios-chs-trans", + .enum_table = bios_chs_trans_table, + .get = get_enum, + .set = set_enum, +}; + +/* --- pci address --- */ + +/* + * bus-local address, i.e. "$slot" or "$slot.$fn" + */ +static void set_pci_devfn(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) +{ + DeviceState *dev = DEVICE(obj); + Property *prop = opaque; + int32_t value, *ptr = qdev_get_prop_ptr(dev, prop); + unsigned int slot, fn, n; + Error *local_err = NULL; + char *str; + + if (dev->state != DEV_STATE_CREATED) { + error_set(errp, QERR_PERMISSION_DENIED); + return; + } + + visit_type_str(v, &str, name, &local_err); + if (local_err) { + error_free(local_err); + local_err = NULL; + visit_type_int32(v, &value, name, &local_err); + if (local_err) { + error_propagate(errp, local_err); + } else if (value < -1 || value > 255) { + error_set(errp, QERR_INVALID_PARAMETER_VALUE, name ? name : "null", + "pci_devfn"); + } else { + *ptr = value; + } + return; + } + + if (sscanf(str, "%x.%x%n", &slot, &fn, &n) != 2) { + fn = 0; + if (sscanf(str, "%x%n", &slot, &n) != 1) { + goto invalid; + } + } + if (str[n] != '\0' || fn > 7 || slot > 31) { + goto invalid; + } + *ptr = slot << 3 | fn; + g_free(str); + return; + +invalid: + error_set_from_qdev_prop_error(errp, EINVAL, dev, prop, str); + g_free(str); +} + +static int print_pci_devfn(DeviceState *dev, Property *prop, char *dest, size_t len) +{ + int32_t *ptr = qdev_get_prop_ptr(dev, prop); + + if (*ptr == -1) { + return snprintf(dest, len, "<unset>"); + } else { + return snprintf(dest, len, "%02x.%x", *ptr >> 3, *ptr & 7); + } +} + +PropertyInfo qdev_prop_pci_devfn = { + .name = "int32", + .legacy_name = "pci-devfn", + .print = print_pci_devfn, + .get = get_int32, + .set = set_pci_devfn, +}; + +/* --- blocksize --- */ + +static void set_blocksize(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) +{ + DeviceState *dev = DEVICE(obj); + Property *prop = opaque; + uint16_t value, *ptr = qdev_get_prop_ptr(dev, prop); + Error *local_err = NULL; + const int64_t min = 512; + const int64_t max = 32768; + + if (dev->state != DEV_STATE_CREATED) { + error_set(errp, QERR_PERMISSION_DENIED); + return; + } + + visit_type_uint16(v, &value, name, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } + if (value < min || value > max) { + error_set(errp, QERR_PROPERTY_VALUE_OUT_OF_RANGE, + dev->id?:"", name, (int64_t)value, min, max); + return; + } + + /* We rely on power-of-2 blocksizes for bitmasks */ + if ((value & (value - 1)) != 0) { + error_set(errp, QERR_PROPERTY_VALUE_NOT_POWER_OF_2, + dev->id?:"", name, (int64_t)value); + return; + } + + *ptr = value; +} + +PropertyInfo qdev_prop_blocksize = { + .name = "blocksize", + .get = get_uint16, + .set = set_blocksize, +}; + +/* --- pci host address --- */ + +static void get_pci_host_devaddr(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) +{ + DeviceState *dev = DEVICE(obj); + Property *prop = opaque; + PCIHostDeviceAddress *addr = qdev_get_prop_ptr(dev, prop); + char buffer[] = "xxxx:xx:xx.x"; + char *p = buffer; + int rc = 0; + + rc = snprintf(buffer, sizeof(buffer), "%04x:%02x:%02x.%d", + addr->domain, addr->bus, addr->slot, addr->function); + assert(rc == sizeof(buffer) - 1); + + visit_type_str(v, &p, name, errp); +} + +/* + * Parse [<domain>:]<bus>:<slot>.<func> + * if <domain> is not supplied, it's assumed to be 0. + */ +static void set_pci_host_devaddr(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) +{ + DeviceState *dev = DEVICE(obj); + Property *prop = opaque; + PCIHostDeviceAddress *addr = qdev_get_prop_ptr(dev, prop); + Error *local_err = NULL; + char *str, *p; + char *e; + unsigned long val; + unsigned long dom = 0, bus = 0; + unsigned int slot = 0, func = 0; + + if (dev->state != DEV_STATE_CREATED) { + error_set(errp, QERR_PERMISSION_DENIED); + return; + } + + visit_type_str(v, &str, name, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } + + p = str; + val = strtoul(p, &e, 16); + if (e == p || *e != ':') { + goto inval; + } + bus = val; + + p = e + 1; + val = strtoul(p, &e, 16); + if (e == p) { + goto inval; + } + if (*e == ':') { + dom = bus; + bus = val; + p = e + 1; + val = strtoul(p, &e, 16); + if (e == p) { + goto inval; + } + } + slot = val; + + if (*e != '.') { + goto inval; + } + p = e + 1; + val = strtoul(p, &e, 10); + if (e == p) { + goto inval; + } + func = val; + + if (dom > 0xffff || bus > 0xff || slot > 0x1f || func > 7) { + goto inval; + } + + if (*e) { + goto inval; + } + + addr->domain = dom; + addr->bus = bus; + addr->slot = slot; + addr->function = func; + + g_free(str); + return; + +inval: + error_set_from_qdev_prop_error(errp, EINVAL, dev, prop, str); + g_free(str); +} + +PropertyInfo qdev_prop_pci_host_devaddr = { + .name = "pci-host-devaddr", + .get = get_pci_host_devaddr, + .set = set_pci_host_devaddr, +}; + +/* --- public helpers --- */ + +static Property *qdev_prop_walk(Property *props, const char *name) +{ + if (!props) + return NULL; + while (props->name) { + if (strcmp(props->name, name) == 0) + return props; + props++; + } + return NULL; +} + +static Property *qdev_prop_find(DeviceState *dev, const char *name) +{ + ObjectClass *class; + Property *prop; + + /* device properties */ + class = object_get_class(OBJECT(dev)); + do { + prop = qdev_prop_walk(DEVICE_CLASS(class)->props, name); + if (prop) { + return prop; + } + class = object_class_get_parent(class); + } while (class != object_class_by_name(TYPE_DEVICE)); + + return NULL; +} + +void error_set_from_qdev_prop_error(Error **errp, int ret, DeviceState *dev, + Property *prop, const char *value) +{ + switch (ret) { + case -EEXIST: + error_set(errp, QERR_PROPERTY_VALUE_IN_USE, + object_get_typename(OBJECT(dev)), prop->name, value); + break; + default: + case -EINVAL: + error_set(errp, QERR_PROPERTY_VALUE_BAD, + object_get_typename(OBJECT(dev)), prop->name, value); + break; + case -ENOENT: + error_set(errp, QERR_PROPERTY_VALUE_NOT_FOUND, + object_get_typename(OBJECT(dev)), prop->name, value); + break; + case 0: + break; + } +} + +int qdev_prop_parse(DeviceState *dev, const char *name, const char *value) +{ + char *legacy_name; + Error *err = NULL; + + legacy_name = g_strdup_printf("legacy-%s", name); + if (object_property_get_type(OBJECT(dev), legacy_name, NULL)) { + object_property_parse(OBJECT(dev), value, legacy_name, &err); + } else { + object_property_parse(OBJECT(dev), value, name, &err); + } + g_free(legacy_name); + + if (err) { + qerror_report_err(err); + error_free(err); + return -1; + } + return 0; +} + +void qdev_prop_set_bit(DeviceState *dev, const char *name, bool value) +{ + Error *errp = NULL; + object_property_set_bool(OBJECT(dev), value, name, &errp); + assert_no_error(errp); +} + +void qdev_prop_set_uint8(DeviceState *dev, const char *name, uint8_t value) +{ + Error *errp = NULL; + object_property_set_int(OBJECT(dev), value, name, &errp); + assert_no_error(errp); +} + +void qdev_prop_set_uint16(DeviceState *dev, const char *name, uint16_t value) +{ + Error *errp = NULL; + object_property_set_int(OBJECT(dev), value, name, &errp); + assert_no_error(errp); +} + +void qdev_prop_set_uint32(DeviceState *dev, const char *name, uint32_t value) +{ + Error *errp = NULL; + object_property_set_int(OBJECT(dev), value, name, &errp); + assert_no_error(errp); +} + +void qdev_prop_set_int32(DeviceState *dev, const char *name, int32_t value) +{ + Error *errp = NULL; + object_property_set_int(OBJECT(dev), value, name, &errp); + assert_no_error(errp); +} + +void qdev_prop_set_uint64(DeviceState *dev, const char *name, uint64_t value) +{ + Error *errp = NULL; + object_property_set_int(OBJECT(dev), value, name, &errp); + assert_no_error(errp); +} + +void qdev_prop_set_string(DeviceState *dev, const char *name, const char *value) +{ + Error *errp = NULL; + object_property_set_str(OBJECT(dev), value, name, &errp); + assert_no_error(errp); +} + +void qdev_prop_set_macaddr(DeviceState *dev, const char *name, uint8_t *value) +{ + Error *errp = NULL; + char str[2 * 6 + 5 + 1]; + snprintf(str, sizeof(str), "%02x:%02x:%02x:%02x:%02x:%02x", + value[0], value[1], value[2], value[3], value[4], value[5]); + + object_property_set_str(OBJECT(dev), str, name, &errp); + assert_no_error(errp); +} + +void qdev_prop_set_enum(DeviceState *dev, const char *name, int value) +{ + Property *prop; + Error *errp = NULL; + + prop = qdev_prop_find(dev, name); + object_property_set_str(OBJECT(dev), prop->info->enum_table[value], + name, &errp); + assert_no_error(errp); +} + +void qdev_prop_set_ptr(DeviceState *dev, const char *name, void *value) +{ + Property *prop; + void **ptr; + + prop = qdev_prop_find(dev, name); + assert(prop && prop->info == &qdev_prop_ptr); + ptr = qdev_get_prop_ptr(dev, prop); + *ptr = value; +} + +static QTAILQ_HEAD(, GlobalProperty) global_props = QTAILQ_HEAD_INITIALIZER(global_props); + +void qdev_prop_register_global(GlobalProperty *prop) +{ + QTAILQ_INSERT_TAIL(&global_props, prop, next); +} + +void qdev_prop_register_global_list(GlobalProperty *props) +{ + int i; + + for (i = 0; props[i].driver != NULL; i++) { + qdev_prop_register_global(props+i); + } +} + +void qdev_prop_set_globals(DeviceState *dev) +{ + ObjectClass *class = object_get_class(OBJECT(dev)); + + do { + GlobalProperty *prop; + QTAILQ_FOREACH(prop, &global_props, next) { + if (strcmp(object_class_get_name(class), prop->driver) != 0) { + continue; + } + if (qdev_prop_parse(dev, prop->property, prop->value) != 0) { + exit(1); + } + } + class = object_class_get_parent(class); + } while (class); +} +
The code depends on some functions from qemu-option.o, so add qemu-option.o to universal-obj-y to make sure it's included. Signed-off-by: Eduardo Habkost <ehabkost@redhat.com> --- Makefile.objs | 3 + hw/Makefile.objs | 2 +- hw/qdev-core.c | 727 ------------------------------------- hw/qdev-properties.c | 963 -------------------------------------------------- qom/Makefile.objs | 2 +- qom/qdev-core.c | 727 +++++++++++++++++++++++++++++++++++++ qom/qdev-properties.c | 963 ++++++++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 1695 insertions(+), 1692 deletions(-) delete mode 100644 hw/qdev-core.c delete mode 100644 hw/qdev-properties.c create mode 100644 qom/qdev-core.c create mode 100644 qom/qdev-properties.c