inherit from a particular bus (e.g. PCI or I2C) rather than
this API directly. */
-#include "net.h"
#include "qdev.h"
-#include "sysemu.h"
-#include "error.h"
+#include "sysemu/sysemu.h"
+#include "qapi/error.h"
+#include "qapi/visitor.h"
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;
-static void main_system_bus_create(void);
-
-/* Register a new device type. */
const VMStateDescription *qdev_get_vmsd(DeviceState *dev)
{
DeviceClass *dc = DEVICE_GET_CLASS(dev);
return object_get_typename(OBJECT(dev));
}
-bool qdev_exists(const char *name)
-{
- return !!object_class_by_name(name);
-}
-
static void qdev_property_add_legacy(DeviceState *dev, Property *prop,
Error **errp);
-void qdev_set_parent_bus(DeviceState *dev, BusState *bus)
+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;
- QTAILQ_INSERT_HEAD(&bus->children, dev, sibling);
+ bus_add_child(bus, dev);
}
/* Create a new device. This only initializes the device state structure
dev = qdev_try_create(bus, name);
if (!dev) {
if (bus) {
- hw_error("Unknown device '%s' for bus '%s'\n", name,
- bus->info->name);
+ error_report("Unknown device '%s' for bus '%s'\n", name,
+ object_get_typename(OBJECT(bus)));
+ abort();
} else {
- hw_error("Unknown device '%s' for default sysbus\n", name);
+ error_report("Unknown device '%s' for default sysbus\n", name);
+ abort();
}
}
}
qdev_set_parent_bus(dev, bus);
- qdev_prop_set_globals(dev);
return dev;
}
return 0;
}
-BusState *sysbus_get_default(void)
-{
- if (!main_system_bus) {
- main_system_bus_create();
- }
- return main_system_bus;
-}
-
static int qbus_reset_one(BusState *bus, void *opaque)
{
- if (bus->info->reset) {
- return bus->info->reset(bus);
+ BusClass *bc = BUS_GET_CLASS(bus);
+ if (bc->reset) {
+ return bc->reset(bus);
}
return 0;
}
qdev_walk_children(dev, qdev_reset_one, qbus_reset_one, NULL);
}
+void qbus_reset_all(BusState *bus)
+{
+ qbus_walk_children(bus, qdev_reset_one, qbus_reset_one, NULL);
+}
+
void qbus_reset_all_fn(void *opaque)
{
BusState *bus = opaque;
- qbus_walk_children(bus, qdev_reset_one, qbus_reset_one, NULL);
+ qbus_reset_all(bus);
}
/* can be used as ->unplug() callback for the simple cases */
int qdev_simple_unplug_cb(DeviceState *dev)
{
/* just zap it */
- object_unparent(OBJECT(dev));
qdev_free(dev);
return 0;
}
way is somewhat unclean, and best avoided. */
void qdev_init_nofail(DeviceState *dev)
{
+ const char *typename = object_get_typename(OBJECT(dev));
+
if (qdev_init(dev) < 0) {
- error_report("Initialization of device %s failed",
- object_get_typename(OBJECT(dev)));
+ error_report("Initialization of device %s failed", typename);
exit(1);
}
}
void qdev_init_gpio_in(DeviceState *dev, qemu_irq_handler handler, int n)
{
- assert(dev->num_gpio_in == 0);
- dev->num_gpio_in = n;
- dev->gpio_in = qemu_allocate_irqs(handler, dev, n);
+ dev->gpio_in = qemu_extend_irqs(dev->gpio_in, dev->num_gpio_in, handler,
+ dev, n);
+ dev->num_gpio_in += n;
}
void qdev_init_gpio_out(DeviceState *dev, qemu_irq *pins, int n)
dev->gpio_out[n] = pin;
}
-void qdev_set_nic_properties(DeviceState *dev, NICInfo *nd)
-{
- qdev_prop_set_macaddr(dev, "mac", nd->macaddr.a);
- if (nd->vlan)
- qdev_prop_set_vlan(dev, "vlan", nd->vlan);
- if (nd->netdev)
- qdev_prop_set_netdev(dev, "netdev", nd->netdev);
- if (nd->nvectors != DEV_NVECTORS_UNSPECIFIED &&
- qdev_prop_exists(dev, "vectors")) {
- qdev_prop_set_uint32(dev, "vectors", nd->nvectors);
- }
- nd->instantiated = 1;
-}
-
BusState *qdev_get_child_bus(DeviceState *dev, const char *name)
{
BusState *bus;
int qbus_walk_children(BusState *bus, qdev_walkerfn *devfn,
qbus_walkerfn *busfn, void *opaque)
{
- DeviceState *dev;
+ BusChild *kid;
int err;
if (busfn) {
}
}
- QTAILQ_FOREACH(dev, &bus->children, sibling) {
- err = qdev_walk_children(dev, devfn, busfn, opaque);
+ QTAILQ_FOREACH(kid, &bus->children, sibling) {
+ err = qdev_walk_children(kid->child, devfn, busfn, opaque);
if (err < 0) {
return err;
}
DeviceState *qdev_find_recursive(BusState *bus, const char *id)
{
- DeviceState *dev, *ret;
+ BusChild *kid;
+ DeviceState *ret;
BusState *child;
- QTAILQ_FOREACH(dev, &bus->children, sibling) {
- if (dev->id && strcmp(dev->id, id) == 0)
+ 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 NULL;
}
-void qbus_create_inplace(BusState *bus, BusInfo *info,
- DeviceState *parent, const char *name)
+static void qbus_realize(BusState *bus)
{
+ const char *typename = object_get_typename(OBJECT(bus));
char *buf;
int i,len;
- bus->info = info;
- bus->parent = parent;
-
- if (name) {
+ if (bus->name) {
/* use supplied name */
- bus->name = g_strdup(name);
- } else if (parent && parent->id) {
+ } else if (bus->parent && bus->parent->id) {
/* parent device has id -> use it for bus name */
- len = strlen(parent->id) + 16;
+ len = strlen(bus->parent->id) + 16;
buf = g_malloc(len);
- snprintf(buf, len, "%s.%d", parent->id, parent->num_child_bus);
+ 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(info->name) + 16;
+ len = strlen(typename) + 16;
buf = g_malloc(len);
- len = snprintf(buf, len, "%s.%d", info->name,
- parent ? parent->num_child_bus : 0);
+ 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;
}
- QTAILQ_INIT(&bus->children);
- if (parent) {
- QLIST_INSERT_HEAD(&parent->child_bus, bus, sibling);
- parent->num_child_bus++;
- } else if (bus != main_system_bus) {
+ 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 if (bus != sysbus_get_default()) {
/* TODO: once all bus devices are qdevified,
only reset handler for main_system_bus should be registered here. */
qemu_register_reset(qbus_reset_all_fn, bus);
}
}
-BusState *qbus_create(BusInfo *info, DeviceState *parent, const char *name)
+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 = g_malloc0(info->size);
- bus->qdev_allocated = 1;
- qbus_create_inplace(bus, info, parent, name);
+ bus = BUS(object_new(typename));
+
+ bus->parent = parent;
+ bus->name = name ? g_strdup(name) : NULL;
+ qbus_realize(bus);
+
return bus;
}
-static void main_system_bus_create(void)
+void qbus_free(BusState *bus)
{
- /* 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");
+ object_delete(OBJECT(bus));
}
-void qbus_free(BusState *bus)
+static char *bus_get_fw_dev_path(BusState *bus, DeviceState *dev)
{
- DeviceState *dev;
+ BusClass *bc = BUS_GET_CLASS(bus);
- while ((dev = QTAILQ_FIRST(&bus->children)) != NULL) {
- qdev_free(dev);
- }
- if (bus->parent) {
- QLIST_REMOVE(bus, sibling);
- bus->parent->num_child_bus--;
- } else {
- assert(bus != main_system_bus); /* main_system_bus is never freed */
- qemu_unregister_reset(qbus_reset_all_fn, bus);
- }
- g_free((void*)bus->name);
- if (bus->qdev_allocated) {
- g_free(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)
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);
+ d = bus_get_fw_dev_path(dev->parent_bus, dev);
+ if (d) {
l += snprintf(p + l, size - l, "%s", d);
g_free(d);
} else {
path[l-1] = '\0';
- return strdup(path);
+ 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;
}
/**
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
return;
}
- object_property_add(OBJECT(dev), prop->name, prop->info->name,
+ object_property_add(obj, prop->name, prop->info->name,
prop->info->get, prop->info->set,
prop->info->release,
- prop, errp);
+ 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)
qdev_property_add_legacy(dev, prop, NULL);
qdev_property_add_static(dev, prop, NULL);
}
- qdev_prop_set_defaults(dev, DEVICE_CLASS(class)->props);
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. */
qemu_opts_del(dev->opts);
}
}
- QTAILQ_REMOVE(&dev->parent_bus->children, dev, sibling);
}
static void device_class_base_init(ObjectClass *class, void *data)
klass->props = NULL;
}
+static void device_unparent(Object *obj)
+{
+ DeviceState *dev = DEVICE(obj);
+
+ if (dev->parent_bus != NULL) {
+ bus_remove_child(dev->parent_bus, dev);
+ }
+}
+
+static void device_class_init(ObjectClass *class, void *data)
+{
+ class->unparent = device_unparent;
+}
+
void device_reset(DeviceState *dev)
{
DeviceClass *klass = DEVICE_GET_CLASS(dev);
return dev;
}
-static TypeInfo device_type_info = {
+static const 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,
+ .class_init = device_class_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 {
+ assert(bus != sysbus_get_default()); /* main_system_bus is never freed */
+ qemu_unregister_reset(qbus_reset_all_fn, 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);
}