@@ -239,6 +239,50 @@ void qbus_reset_all_fn(void *opaque)
qbus_walk_children(bus, qdev_reset_one, qbus_reset_one, NULL, 0);
}
+static int qdev_device_delete(DeviceState *dev, void *opaque)
+{
+ Object *obj = OBJECT(dev);
+ BusState *b = dev->parent_bus;
+
+ dev->parent_bus = NULL;
+ /* removed from list and bus->dev link */
+ bus_remove_child(b, dev);
+ /* remove bus<-dev link */
+ object_property_del(OBJECT(dev), "parent_bus", NULL);
+
+ /* when mmio-dispatch out of big lock, remove it!
+ * refcnt hold by
+ * object_property_add_child(qdev_get_peripheral(), ., OBJECT(qdev),..)
+ * should be released before here.
+ */
+ g_assert(obj->ref == 1);
+ object_unref(OBJECT(dev));
+
+ return 0;
+}
+
+static int qdev_bus_delete(BusState *bus, void *opaque)
+{
+ Object *obj = OBJECT(bus);
+ DeviceState *d = bus->parent;
+
+ bus->parent = NULL;
+ QLIST_REMOVE(bus, sibling);
+ d->num_child_bus--;
+ object_property_del_child(OBJECT(d), OBJECT(bus), NULL);
+ /* when mmio-dispatch out of big lock, remove it!*/
+ g_assert(obj->ref == 1);
+ object_unref(obj);
+
+ return 0;
+}
+
+/* Delete the composite tree which starts from @dev */
+void qdev_delete_subtree(DeviceState *dev)
+{
+ qdev_walk_children(dev, qdev_device_delete, qdev_bus_delete, NULL, 1);
+}
+
/* can be used as ->unplug() callback for the simple cases */
int qdev_simple_unplug_cb(DeviceState *dev)
{
@@ -162,6 +162,7 @@ void qdev_set_legacy_instance_id(DeviceState *dev, int alias_id,
int required_for_version);
void qdev_unplug(DeviceState *dev, Error **errp);
void qdev_free(DeviceState *dev);
+void qdev_delete_subtree(DeviceState *dev);
int qdev_simple_unplug_cb(DeviceState *dev);
void qdev_machine_creation_done(void);
bool qdev_machine_modified(void);