Merge remote-tracking branch 'afaerber-or/qom-next-2' into staging
authorAnthony Liguori <aliguori@us.ibm.com>
Mon, 18 Jun 2012 15:35:16 +0000 (10:35 -0500)
committerAnthony Liguori <aliguori@us.ibm.com>
Mon, 18 Jun 2012 15:35:16 +0000 (10:35 -0500)
* afaerber-or/qom-next-2: (22 commits)
  qom: Push error reporting to object_property_find()
  qdev: Remove qdev_prop_exists()
  qbus: Initialize in standard way
  qbus: Make child devices links
  qdev: Connect busses with their parent devices
  qdev: Convert busses to QEMU Object Model
  qdev: Move SysBus initialization to sysbus.c
  qdev: Use wrapper for qdev_get_path
  qdev: Remove qdev_prop_set_defaults
  qdev: Clean up global properties
  qdev: Move bus properties to abstract superclasses
  qdev: Move bus properties to a separate global
  qdev: Push "type" property up to Object
  arm_l2x0: Rename "type" property to "cache-type"
  m48t59: Rename "type" property to "model"
  qom: Assert that public types have a non-NULL parent field
  qom: Drop type_register_static_alias() macro
  qom: Make Object a type
  qom: Add class_base_init
  qom: Add object_child_foreach()
  ...

1  2 
hw/intel-hda.c
hw/isa.h
hw/pci.c
hw/pci_bridge.c
hw/qdev.c
savevm.c

diff --combined hw/intel-hda.c
index 8f3b70bd1474fbf859078064b83d3d1b78ba11ee,c11fd30cab4f90ca6741f1b1990b1062d937f674..31fe1c54f680f17ee2c590553a0178925fee1f45
  /* --------------------------------------------------------------------- */
  /* hda bus                                                               */
  
- static struct BusInfo hda_codec_bus_info = {
-     .name      = "HDA",
-     .size      = sizeof(HDACodecBus),
-     .props     = (Property[]) {
-         DEFINE_PROP_UINT32("cad", HDACodecDevice, cad, -1),
-         DEFINE_PROP_END_OF_LIST()
-     }
+ static Property hda_props[] = {
+     DEFINE_PROP_UINT32("cad", HDACodecDevice, cad, -1),
+     DEFINE_PROP_END_OF_LIST()
+ };
+ static const TypeInfo hda_codec_bus_info = {
+     .name = TYPE_HDA_BUS,
+     .parent = TYPE_BUS,
+     .instance_size = sizeof(HDACodecBus),
  };
  
  void hda_codec_bus_init(DeviceState *dev, HDACodecBus *bus,
                          hda_codec_response_func response,
                          hda_codec_xfer_func xfer)
  {
-     qbus_create_inplace(&bus->qbus, &hda_codec_bus_info, dev, NULL);
+     qbus_create_inplace(&bus->qbus, TYPE_HDA_BUS, dev, NULL);
      bus->response = response;
      bus->xfer = xfer;
  }
@@@ -76,10 -78,11 +78,11 @@@ static int hda_codec_dev_exit(DeviceSta
  
  HDACodecDevice *hda_codec_find(HDACodecBus *bus, uint32_t cad)
  {
-     DeviceState *qdev;
+     BusChild *kid;
      HDACodecDevice *cdev;
  
-     QTAILQ_FOREACH(qdev, &bus->qbus.children, sibling) {
+     QTAILQ_FOREACH(kid, &bus->qbus.children, sibling) {
+         DeviceState *qdev = kid->child;
          cdev = DO_UPCAST(HDACodecDevice, qdev, qdev);
          if (cdev->cad == cad) {
              return cdev;
@@@ -481,10 -484,11 +484,11 @@@ static void intel_hda_parse_bdl(IntelHD
  
  static void intel_hda_notify_codecs(IntelHDAState *d, uint32_t stream, bool running, bool output)
  {
-     DeviceState *qdev;
+     BusChild *kid;
      HDACodecDevice *cdev;
  
-     QTAILQ_FOREACH(qdev, &d->codecs.qbus.children, sibling) {
+     QTAILQ_FOREACH(kid, &d->codecs.qbus.children, sibling) {
+         DeviceState *qdev = kid->child;
          HDACodecDeviceClass *cdc;
  
          cdev = DO_UPCAST(HDACodecDevice, qdev, qdev);
@@@ -1103,15 -1107,16 +1107,16 @@@ static const MemoryRegionOps intel_hda_
  
  static void intel_hda_reset(DeviceState *dev)
  {
+     BusChild *kid;
      IntelHDAState *d = DO_UPCAST(IntelHDAState, pci.qdev, dev);
-     DeviceState *qdev;
      HDACodecDevice *cdev;
  
      intel_hda_regs_reset(d);
      d->wall_base_ns = qemu_get_clock_ns(vm_clock);
  
      /* reset codecs */
-     QTAILQ_FOREACH(qdev, &d->codecs.qbus.children, sibling) {
+     QTAILQ_FOREACH(kid, &d->codecs.qbus.children, sibling) {
+         DeviceState *qdev = kid->child;
          cdev = DO_UPCAST(HDACodecDevice, qdev, qdev);
          device_reset(DEVICE(cdev));
          d->state_sts |= (1 << cdev->cad);
@@@ -1153,6 -1158,17 +1158,6 @@@ static int intel_hda_exit(PCIDevice *pc
      return 0;
  }
  
 -static void intel_hda_write_config(PCIDevice *pci, uint32_t addr,
 -                                   uint32_t val, int len)
 -{
 -    IntelHDAState *d = DO_UPCAST(IntelHDAState, pci, pci);
 -
 -    pci_default_write_config(pci, addr, val, len);
 -    if (d->msi) {
 -        msi_write_config(pci, addr, val, len);
 -    }
 -}
 -
  static int intel_hda_post_load(void *opaque, int version)
  {
      IntelHDAState* d = opaque;
@@@ -1241,6 -1257,7 +1246,6 @@@ static void intel_hda_class_init(Object
  
      k->init = intel_hda_init;
      k->exit = intel_hda_exit;
 -    k->config_write = intel_hda_write_config;
      k->vendor_id = PCI_VENDOR_ID_INTEL;
      k->device_id = 0x2668;
      k->revision = 1;
@@@ -1263,7 -1280,8 +1268,8 @@@ static void hda_codec_device_class_init
      DeviceClass *k = DEVICE_CLASS(klass);
      k->init = hda_codec_dev_init;
      k->exit = hda_codec_dev_exit;
-     k->bus_info = &hda_codec_bus_info;
+     k->bus_type = TYPE_HDA_BUS;
+     k->props = hda_props;
  }
  
  static TypeInfo hda_codec_device_type_info = {
  
  static void intel_hda_register_types(void)
  {
+     type_register_static(&hda_codec_bus_info);
      type_register_static(&intel_hda_info);
      type_register_static(&hda_codec_device_type_info);
  }
diff --combined hw/isa.h
index 6c6fd7fac98c8aac24809939d9c70ee33c42b696,f7ddf2362879cafa6b4d7d3c522d12700e404d64..dc970527ae6eee933056afc87a05f06c8c041bb3
+++ b/hw/isa.h
@@@ -9,6 -9,8 +9,6 @@@
  
  #define ISA_NUM_IRQS 16
  
 -typedef struct ISADevice ISADevice;
 -
  #define TYPE_ISA_DEVICE "isa-device"
  #define ISA_DEVICE(obj) \
       OBJECT_CHECK(ISADevice, (obj), TYPE_ISA_DEVICE)
@@@ -17,6 -19,9 +17,9 @@@
  #define ISA_DEVICE_GET_CLASS(obj) \
       OBJECT_GET_CLASS(ISADeviceClass, (obj), TYPE_ISA_DEVICE)
  
+ #define TYPE_ISA_BUS "ISA"
+ #define ISA_BUS(obj) OBJECT_CHECK(ISABus, (obj), TYPE_ISA_BUS)
  typedef struct ISADeviceClass {
      DeviceClass parent_class;
      int (*init)(ISADevice *dev);
diff --combined hw/pci.c
index 9daa0bfb204b7ac74b7afb8242aa9e1c43428eb9,d6ce9a54fa3db04bff082ea1fdf248308b4f9869..bdfb3d6540ee654e4ddc0711912b88feab2c5b4f
+++ b/hw/pci.c
@@@ -31,8 -31,6 +31,8 @@@
  #include "loader.h"
  #include "range.h"
  #include "qmp-commands.h"
 +#include "msi.h"
 +#include "msix.h"
  
  //#define DEBUG_PCI
  #ifdef DEBUG_PCI
@@@ -46,23 -44,32 +46,32 @@@ static char *pcibus_get_dev_path(Device
  static char *pcibus_get_fw_dev_path(DeviceState *dev);
  static int pcibus_reset(BusState *qbus);
  
- struct BusInfo pci_bus_info = {
-     .name       = "PCI",
-     .size       = sizeof(PCIBus),
-     .print_dev  = pcibus_dev_print,
-     .get_dev_path = pcibus_get_dev_path,
-     .get_fw_dev_path = pcibus_get_fw_dev_path,
-     .reset      = pcibus_reset,
-     .props      = (Property[]) {
-         DEFINE_PROP_PCI_DEVFN("addr", PCIDevice, devfn, -1),
-         DEFINE_PROP_STRING("romfile", PCIDevice, romfile),
-         DEFINE_PROP_UINT32("rombar",  PCIDevice, rom_bar, 1),
-         DEFINE_PROP_BIT("multifunction", PCIDevice, cap_present,
-                         QEMU_PCI_CAP_MULTIFUNCTION_BITNR, false),
-         DEFINE_PROP_BIT("command_serr_enable", PCIDevice, cap_present,
-                         QEMU_PCI_CAP_SERR_BITNR, true),
-         DEFINE_PROP_END_OF_LIST()
-     }
+ static Property pci_props[] = {
+     DEFINE_PROP_PCI_DEVFN("addr", PCIDevice, devfn, -1),
+     DEFINE_PROP_STRING("romfile", PCIDevice, romfile),
+     DEFINE_PROP_UINT32("rombar",  PCIDevice, rom_bar, 1),
+     DEFINE_PROP_BIT("multifunction", PCIDevice, cap_present,
+                     QEMU_PCI_CAP_MULTIFUNCTION_BITNR, false),
+     DEFINE_PROP_BIT("command_serr_enable", PCIDevice, cap_present,
+                     QEMU_PCI_CAP_SERR_BITNR, true),
+     DEFINE_PROP_END_OF_LIST()
+ };
+ static void pci_bus_class_init(ObjectClass *klass, void *data)
+ {
+     BusClass *k = BUS_CLASS(klass);
+     k->print_dev = pcibus_dev_print;
+     k->get_dev_path = pcibus_get_dev_path;
+     k->get_fw_dev_path = pcibus_get_fw_dev_path;
+     k->reset = pcibus_reset;
+ }
+ static const TypeInfo pci_bus_info = {
+     .name = TYPE_PCI_BUS,
+     .parent = TYPE_BUS,
+     .instance_size = sizeof(PCIBus),
+     .class_init = pci_bus_class_init,
  };
  
  static PCIBus *pci_find_bus_nr(PCIBus *bus, int bus_num);
@@@ -190,9 -197,6 +199,9 @@@ void pci_device_reset(PCIDevice *dev
          }
      }
      pci_update_mappings(dev);
 +
 +    msi_reset(dev);
 +    msix_reset(dev);
  }
  
  /*
@@@ -270,7 -274,7 +279,7 @@@ void pci_bus_new_inplace(PCIBus *bus, D
                           MemoryRegion *address_space_io,
                           uint8_t devfn_min)
  {
-     qbus_create_inplace(&bus->qbus, &pci_bus_info, parent, name);
+     qbus_create_inplace(&bus->qbus, TYPE_PCI_BUS, parent, name);
      assert(PCI_FUNC(devfn_min) == 0);
      bus->devfn_min = devfn_min;
      bus->address_space_mem = address_space_mem;
@@@ -291,7 -295,7 +300,7 @@@ PCIBus *pci_bus_new(DeviceState *parent
      PCIBus *bus;
  
      bus = g_malloc0(sizeof(*bus));
-     bus->qbus.qdev_allocated = 1;
+     bus->qbus.glib_allocated = true;
      pci_bus_new_inplace(bus, parent, name, address_space_mem,
                          address_space_io, devfn_min);
      return bus;
@@@ -1042,9 -1046,6 +1051,9 @@@ void pci_default_write_config(PCIDevic
  
      if (range_covers_byte(addr, l, PCI_COMMAND))
          pci_update_irq_disabled(d, was_irq_disabled);
 +
 +    msi_write_config(d, addr, val, l);
 +    msix_write_config(d, addr, val, l);
  }
  
  /***********************************************************/
@@@ -2008,7 -2009,8 +2017,8 @@@ static void pci_device_class_init(Objec
      k->init = pci_qdev_init;
      k->unplug = pci_unplug_device;
      k->exit = pci_unregister_device;
-     k->bus_info = &pci_bus_info;
+     k->bus_type = TYPE_PCI_BUS;
+     k->props = pci_props;
  }
  
  static TypeInfo pci_device_type_info = {
  
  static void pci_register_types(void)
  {
+     type_register_static(&pci_bus_info);
      type_register_static(&pci_device_type_info);
  }
  
diff --combined hw/pci_bridge.c
index e0832b4a67e92ca1dfab6e416eca85c6080cc42b,253e034981a68f23521ffe7b48eba3ee9a621354..0916276c4d4255900ab8a4743dfc64fc85e8802c
@@@ -254,9 -254,8 +254,9 @@@ void pci_bridge_disable_base_limit(PCID
  }
  
  /* reset bridge specific configuration registers */
 -void pci_bridge_reset_reg(PCIDevice *dev)
 +void pci_bridge_reset(DeviceState *qdev)
  {
 +    PCIDevice *dev = PCI_DEVICE(qdev);
      uint8_t *conf = dev->config;
  
      conf[PCI_PRIMARY_BUS] = 0;
      pci_set_word(conf + PCI_BRIDGE_CONTROL, 0);
  }
  
 -/* default reset function for PCI-to-PCI bridge */
 -void pci_bridge_reset(DeviceState *qdev)
 -{
 -    PCIDevice *dev = PCI_DEVICE(qdev);
 -    pci_bridge_reset_reg(dev);
 -}
 -
  /* default qdev initialization function for PCI-to-PCI bridge */
  int pci_bridge_initfn(PCIDevice *dev)
  {
            br->bus_name = dev->qdev.id;
      }
  
-     qbus_create_inplace(&sec_bus->qbus, &pci_bus_info, &dev->qdev,
+     qbus_create_inplace(&sec_bus->qbus, TYPE_PCI_BUS, &dev->qdev,
                          br->bus_name);
      sec_bus->parent_dev = dev;
      sec_bus->map_irq = br->map_irq;
diff --combined hw/qdev.c
index af419b9c1318e1728824984698f1639faea46554,b20b34d11fa4763470f00de566daa3e911856bc9..a6c4c02947748bc3d091fe8a3bae2a8dcaf653ac
+++ b/hw/qdev.c
@@@ -34,10 -34,6 +34,6 @@@ 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)
  {
      return dc->vmsd;
  }
  
- BusInfo *qdev_get_bus_info(DeviceState *dev)
- {
-     DeviceClass *dc = DEVICE_GET_CLASS(dev);
-     return dc->bus_info;
- }
- Property *qdev_get_props(DeviceState *dev)
- {
-     DeviceClass *dc = DEVICE_GET_CLASS(dev);
-     return dc->props;
- }
  const char *qdev_fw_name(DeviceState *dev)
  {
      DeviceClass *dc = DEVICE_GET_CLASS(dev);
@@@ -76,22 -60,48 +60,48 @@@ bool qdev_exists(const char *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)
  {
-     Property *prop;
+     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);
      }
  
-     dev->parent_bus = bus;
-     QTAILQ_INSERT_HEAD(&bus->children, dev, sibling);
+     kid->index = bus->max_index++;
+     kid->child = child;
  
-     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);
-     }
-     qdev_prop_set_defaults(dev, dev->parent_bus->info->props);
+     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);
  }
  
  /* Create a new device.  This only initializes the device state structure
@@@ -105,7 -115,7 +115,7 @@@ DeviceState *qdev_create(BusState *bus
      if (!dev) {
          if (bus) {
              hw_error("Unknown device '%s' for bus '%s'\n", name,
-                      bus->info->name);
+                      object_get_typename(OBJECT(bus)));
          } else {
              hw_error("Unknown device '%s' for default sysbus\n", name);
          }
@@@ -131,7 -141,6 +141,6 @@@ DeviceState *qdev_try_create(BusState *
      }
  
      qdev_set_parent_bus(dev, bus);
-     qdev_prop_set_globals(dev);
  
      return dev;
  }
@@@ -150,7 -159,6 +159,7 @@@ int qdev_init(DeviceState *dev
  
      rc = dc->init(dev);
      if (rc < 0) {
 +        object_unparent(OBJECT(dev));
          qdev_free(dev);
          return rc;
      }
@@@ -210,18 -218,11 +219,11 @@@ static int qdev_reset_one(DeviceState *
      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;
  }
@@@ -322,7 -323,7 +324,7 @@@ void qdev_set_nic_properties(DeviceStat
      if (nd->netdev)
          qdev_prop_set_netdev(dev, "netdev", nd->netdev);
      if (nd->nvectors != DEV_NVECTORS_UNSPECIFIED &&
-         qdev_prop_exists(dev, "vectors")) {
+         object_property_find(OBJECT(dev), "vectors", NULL)) {
          qdev_prop_set_uint32(dev, "vectors", nd->nvectors);
      }
      nd->instantiated = 1;
@@@ -343,7 -344,7 +345,7 @@@ BusState *qdev_get_child_bus(DeviceStat
  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;
          }
@@@ -388,12 -389,17 +390,17 @@@ int qdev_walk_children(DeviceState *dev
  
  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)
  {
-     BusState *bus;
+     object_initialize(bus, typename);
  
-     bus = g_malloc0(info->size);
-     bus->qdev_allocated = 1;
-     qbus_create_inplace(bus, info, parent, name);
-     return bus;
+     bus->parent = parent;
+     bus->name = name ? g_strdup(name) : NULL;
+     qbus_realize(bus);
  }
  
static void main_system_bus_create(void)
BusState *qbus_create(const char *typename, DeviceState *parent, const char *name)
  {
-     /* 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");
+     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)
  {
-     DeviceState *dev;
-     while ((dev = QTAILQ_FIRST(&bus->children)) != NULL) {
-         qdev_free(dev);
-     }
-     if (bus->parent) {
-         QLIST_REMOVE(bus, sibling);
-         bus->parent->num_child_bus--;
+     if (bus->qom_allocated) {
+         object_delete(OBJECT(bus));
      } else {
-         assert(bus != main_system_bus); /* main_system_bus is never freed */
-         qemu_unregister_reset(qbus_reset_all_fn, bus);
+         object_finalize(OBJECT(bus));
+         if (bus->glib_allocated) {
+             g_free(bus);
+         }
      }
-     g_free((void*)bus->name);
-     if (bus->qdev_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)
      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 {
@@@ -516,9 -525,20 +526,20 @@@ char* qdev_get_fw_dev_path(DeviceState 
      return strdup(path);
  }
  
static char *qdev_get_type(Object *obj, Error **errp)
char *qdev_get_dev_path(DeviceState *dev)
  {
-     return g_strdup(object_get_typename(obj));
+     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;
  }
  
  /**
@@@ -606,6 -626,9 +627,9 @@@ void qdev_property_add_legacy(DeviceSta
  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)
  {
      DeviceState *dev = DEVICE(obj);
+     ObjectClass *class;
      Property *prop;
  
      if (qdev_hotplug) {
      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);
-     }
+     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_str(OBJECT(dev), "type", qdev_get_type, NULL, NULL);
-     qdev_prop_set_defaults(dev, qdev_get_props(dev));
+     object_property_add_link(OBJECT(dev), "parent_bus", TYPE_BUS,
+                              (Object **)&dev->parent_bus, NULL);
  }
  
  /* Unlink device from bus and free the structure.  */
@@@ -665,7 -712,19 +713,19 @@@ static void device_finalize(Object *obj
              qemu_opts_del(dev->opts);
          }
      }
-     QTAILQ_REMOVE(&dev->parent_bus->children, dev, sibling);
+     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)
@@@ -694,12 -753,50 +754,50 @@@ static TypeInfo device_type_info = 
      .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 {
+         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);
  }
  
diff --combined savevm.c
index 2b6833d5f59506c8880eaf841aebbc5015d35b31,818ddfc8591bbe614943a39775005d8ec38d0146..faa81457d5f657b711f9d8f5ff0b08a173c1001f
+++ b/savevm.c
@@@ -400,7 -400,7 +400,7 @@@ static int block_get_buffer(void *opaqu
  
  static int bdrv_fclose(void *opaque)
  {
 -    return 0;
 +    return bdrv_flush(opaque);
  }
  
  static QEMUFile *qemu_fopen_bdrv(BlockDriverState *bs, int is_writable)
@@@ -1248,8 -1248,8 +1248,8 @@@ int register_savevm_live(DeviceState *d
          se->is_ram = 1;
      }
  
-     if (dev && dev->parent_bus && dev->parent_bus->info->get_dev_path) {
-         char *id = dev->parent_bus->info->get_dev_path(dev);
+     if (dev) {
+         char *id = qdev_get_dev_path(dev);
          if (id) {
              pstrcpy(se->idstr, sizeof(se->idstr), id);
              pstrcat(se->idstr, sizeof(se->idstr), "/");
@@@ -1292,8 -1292,8 +1292,8 @@@ void unregister_savevm(DeviceState *dev
      SaveStateEntry *se, *new_se;
      char id[256] = "";
  
-     if (dev && dev->parent_bus && dev->parent_bus->info->get_dev_path) {
-         char *path = dev->parent_bus->info->get_dev_path(dev);
+     if (dev) {
+         char *path = qdev_get_dev_path(dev);
          if (path) {
              pstrcpy(id, sizeof(id), path);
              pstrcat(id, sizeof(id), "/");
@@@ -1334,8 -1334,8 +1334,8 @@@ int vmstate_register_with_alias_id(Devi
      se->alias_id = alias_id;
      se->no_migrate = vmsd->unmigratable;
  
-     if (dev && dev->parent_bus && dev->parent_bus->info->get_dev_path) {
-         char *id = dev->parent_bus->info->get_dev_path(dev);
+     if (dev) {
+         char *id = qdev_get_dev_path(dev);
          if (id) {
              pstrcpy(se->idstr, sizeof(se->idstr), id);
              pstrcat(se->idstr, sizeof(se->idstr), "/");