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