@@ -94,13 +94,23 @@ static void bus_add_child(BusState *bus, DeviceState *child)
0);
}
-void qdev_set_parent_bus(DeviceState *dev, BusState *bus)
+static bool bus_check_address(BusState *bus, DeviceState *child, Error **errp)
+{
+ BusClass *bc = BUS_GET_CLASS(bus);
+ return !bc->check_address || bc->check_address(bus, child, errp);
+}
+
+bool qdev_set_parent_bus(DeviceState *dev, BusState *bus, Error **errp)
{
BusState *old_parent_bus = dev->parent_bus;
DeviceClass *dc = DEVICE_GET_CLASS(dev);
assert(dc->bus_type && object_dynamic_cast(OBJECT(bus), dc->bus_type));
+ if (!bus_check_address(bus, dev, errp)) {
+ return false;
+ }
+
if (old_parent_bus) {
trace_qdev_update_parent_bus(dev, object_get_typename(OBJECT(dev)),
old_parent_bus, object_get_typename(OBJECT(old_parent_bus)),
@@ -126,6 +136,7 @@ void qdev_set_parent_bus(DeviceState *dev, BusState *bus)
object_unref(OBJECT(old_parent_bus));
object_unref(OBJECT(dev));
}
+ return true;
}
DeviceState *qdev_new(const char *name)
@@ -371,7 +382,9 @@ bool qdev_realize(DeviceState *dev, BusState *bus, Error **errp)
assert(!dev->realized && !dev->parent_bus);
if (bus) {
- qdev_set_parent_bus(dev, bus);
+ if (!qdev_set_parent_bus(dev, bus, errp)) {
+ return false;
+ }
} else {
assert(!DEVICE_GET_CLASS(dev)->bus_type);
}
@@ -3138,7 +3138,7 @@ static bool failover_replug_primary(VirtIONet *n, Error **errp)
error_setg(errp, "virtio_net: couldn't find primary bus");
return false;
}
- qdev_set_parent_bus(n->primary_dev, n->primary_bus);
+ qdev_set_parent_bus(n->primary_dev, n->primary_bus, &error_abort);
n->primary_should_be_hidden = false;
if (!qemu_opt_set_bool(n->primary_device_opts,
"partially_hotplugged", true, errp)) {
@@ -23,6 +23,7 @@
#include "hw/qdev-core.h"
#include "hw/sd/sd.h"
#include "qemu/module.h"
+#include "qapi/error.h"
#include "trace.h"
static inline const char *sdbus_name(SDBus *sdbus)
@@ -240,7 +241,7 @@ void sdbus_reparent_card(SDBus *from, SDBus *to)
readonly = sc->get_readonly(card);
sdbus_set_inserted(from, false);
- qdev_set_parent_bus(DEVICE(card), &to->qbus);
+ qdev_set_parent_bus(DEVICE(card), &to->qbus, &error_abort);
sdbus_set_inserted(to, true);
sdbus_set_readonly(to, readonly);
}
@@ -210,13 +210,24 @@ struct BusClass {
/* FIXME first arg should be BusState */
void (*print_dev)(Monitor *mon, DeviceState *dev, int indent);
char *(*get_dev_path)(DeviceState *dev);
+
/*
* This callback is used to create Open Firmware device path in accordance
* with OF spec http://forthworks.com/standards/of1275.pdf. Individual bus
* bindings can be found at http://playground.sun.com/1275/bindings/.
*/
char *(*get_fw_dev_path)(DeviceState *dev);
+
void (*reset)(BusState *bus);
+
+ /*
+ * Return whether the device can be added to @bus,
+ * based on the address that was set (via device properties)
+ * before realize. If not, on return @errp contains the
+ * human-readable error message.
+ */
+ bool (*check_address)(BusState *bus, DeviceState *dev, Error **errp);
+
BusRealize realize;
BusUnrealize unrealize;
@@ -788,7 +799,7 @@ const char *qdev_fw_name(DeviceState *dev);
Object *qdev_get_machine(void);
/* FIXME: make this a link<> */
-void qdev_set_parent_bus(DeviceState *dev, BusState *bus);
+bool qdev_set_parent_bus(DeviceState *dev, BusState *bus, Error **errp);
extern bool qdev_hotplug;
extern bool qdev_hot_removed;