summary refs log tree commit diff stats
path: root/hw
diff options
context:
space:
mode:
Diffstat (limited to 'hw')
-rw-r--r--hw/9pfs/virtio-9p-device.c48
-rw-r--r--hw/a9mpcore.c46
-rw-r--r--hw/ac97.c87
-rw-r--r--hw/acpi_piix4.c63
-rw-r--r--hw/adlib.c2
-rw-r--r--hw/ads7846.c20
-rw-r--r--hw/alpha_pci.c6
-rw-r--r--hw/alpha_typhoon.c21
-rw-r--r--hw/apb_pci.c84
-rw-r--r--hw/apic.c365
-rw-r--r--hw/apic.h1
-rw-r--r--hw/apic_common.c321
-rw-r--r--hw/apic_internal.h122
-rw-r--r--hw/applesmc.c34
-rw-r--r--hw/arm-misc.h17
-rw-r--r--hw/arm11mpcore.c75
-rw-r--r--hw/arm_boot.c65
-rw-r--r--hw/arm_gic.c68
-rw-r--r--hw/arm_l2x0.c35
-rw-r--r--hw/arm_mptimer.c35
-rw-r--r--hw/arm_sysctl.c35
-rw-r--r--hw/arm_timer.c54
-rw-r--r--hw/armv7m.c29
-rw-r--r--hw/armv7m_nvic.c42
-rw-r--r--hw/bitbang_i2c.c21
-rw-r--r--hw/boards.h1
-rw-r--r--hw/bonito.c55
-rw-r--r--hw/ccid-card-emulated.c48
-rw-r--r--hw/ccid-card-passthru.c41
-rw-r--r--hw/ccid.h27
-rw-r--r--hw/cirrus_vga.c115
-rw-r--r--hw/cirrus_vga_template.h102
-rw-r--r--hw/container.c20
-rw-r--r--hw/cs4231.c31
-rw-r--r--hw/cs4231a.c50
-rw-r--r--hw/debugcon.c32
-rw-r--r--hw/dec_pci.c82
-rw-r--r--hw/ds1225y.c33
-rw-r--r--hw/ds1338.c34
-rw-r--r--hw/e1000.c57
-rw-r--r--hw/eccmemctl.c33
-rw-r--r--hw/eepro100.c207
-rw-r--r--hw/empty_slot.c18
-rw-r--r--hw/es1370.c74
-rw-r--r--hw/escc.c47
-rw-r--r--hw/esp.c31
-rw-r--r--hw/etraxfs_eth.c37
-rw-r--r--hw/etraxfs_pic.c29
-rw-r--r--hw/etraxfs_ser.c23
-rw-r--r--hw/etraxfs_timer.c17
-rw-r--r--hw/fdc.c110
-rw-r--r--hw/framebuffer.c9
-rw-r--r--hw/fw_cfg.c37
-rw-r--r--hw/g364fb.c51
-rw-r--r--hw/grackle_pci.c49
-rw-r--r--hw/grlib_apbuart.c135
-rw-r--r--hw/grlib_gptimer.c35
-rw-r--r--hw/grlib_irqmp.c33
-rw-r--r--hw/gt64xxx.c43
-rw-r--r--hw/gus.c58
-rw-r--r--hw/hda-audio.c64
-rw-r--r--hw/highbank.c339
-rw-r--r--hw/hpet.c37
-rw-r--r--hw/i2c.c116
-rw-r--r--hw/i2c.h51
-rw-r--r--hw/i82374.c165
-rw-r--r--hw/i82378.c275
-rw-r--r--hw/i8254.c36
-rw-r--r--hw/i8259.c173
-rw-r--r--hw/i8259_common.c161
-rw-r--r--hw/i8259_internal.h82
-rw-r--r--hw/ide/ahci.c53
-rw-r--r--hw/ide/cmd646.c43
-rw-r--r--hw/ide/ich.c38
-rw-r--r--hw/ide/internal.h20
-rw-r--r--hw/ide/isa.c36
-rw-r--r--hw/ide/pci.c4
-rw-r--r--hw/ide/piix.c97
-rw-r--r--hw/ide/qdev.c136
-rw-r--r--hw/ide/via.c31
-rw-r--r--hw/integratorcp.c45
-rw-r--r--hw/intel-hda.c104
-rw-r--r--hw/intel-hda.h25
-rw-r--r--hw/ioapic.c149
-rw-r--r--hw/ioapic_common.c121
-rw-r--r--hw/ioapic_internal.h102
-rw-r--r--hw/ioh3420.c63
-rw-r--r--hw/isa-bus.c63
-rw-r--r--hw/isa.h21
-rw-r--r--hw/ivshmem.c51
-rw-r--r--hw/kvm/apic.c147
-rw-r--r--hw/kvm/clock.c (renamed from hw/kvmclock.c)27
-rw-r--r--hw/kvm/clock.h (renamed from hw/kvmclock.h)0
-rw-r--r--hw/kvm/i8259.c138
-rw-r--r--hw/kvm/ioapic.c125
-rw-r--r--hw/lan9118.c159
-rw-r--r--hw/lance.c37
-rw-r--r--hw/lm32_juart.c25
-rw-r--r--hw/lm32_pic.c23
-rw-r--r--hw/lm32_sys.c33
-rw-r--r--hw/lm32_timer.c35
-rw-r--r--hw/lm32_uart.c25
-rw-r--r--hw/lm832x.c37
-rw-r--r--hw/loader.c6
-rw-r--r--hw/lsi53c895a.c36
-rw-r--r--hw/m48t59.c75
-rw-r--r--hw/macio.c51
-rw-r--r--hw/marvell_88w8618_audio.c39
-rw-r--r--hw/max111x.c40
-rw-r--r--hw/max7310.c39
-rw-r--r--hw/mc146818rtc.c66
-rw-r--r--hw/milkymist-ac97.c23
-rw-r--r--hw/milkymist-hpdmc.c23
-rw-r--r--hw/milkymist-memcard.c23
-rw-r--r--hw/milkymist-minimac2.c41
-rw-r--r--hw/milkymist-pfpu.c23
-rw-r--r--hw/milkymist-softusb.c47
-rw-r--r--hw/milkymist-sysctl.c47
-rw-r--r--hw/milkymist-tmu2.c23
-rw-r--r--hw/milkymist-uart.c25
-rw-r--r--hw/milkymist-vgafb.c35
-rw-r--r--hw/milkymist-vgafb_template.h2
-rw-r--r--hw/mips_malta.c27
-rw-r--r--hw/mipsnet.c37
-rw-r--r--hw/mpc8544_guts.c18
-rw-r--r--hw/msi.c8
-rw-r--r--hw/msi.h2
-rw-r--r--hw/msix.c9
-rw-r--r--hw/msix.h2
-rw-r--r--hw/mst_fpga.c23
-rw-r--r--hw/musicpal.c182
-rw-r--r--hw/nand.c37
-rw-r--r--hw/ne2000-isa.c34
-rw-r--r--hw/ne2000.c41
-rw-r--r--hw/omap_gpio.c78
-rw-r--r--hw/omap_intc.c70
-rw-r--r--hw/onenand.c39
-rw-r--r--hw/opencores_eth.c35
-rw-r--r--hw/openpic.c30
-rw-r--r--hw/openpic.h2
-rw-r--r--hw/parallel.c34
-rw-r--r--hw/pc.c51
-rw-r--r--hw/pc.h9
-rw-r--r--hw/pc_piix.c75
-rw-r--r--hw/pci.c179
-rw-r--r--hw/pci.h84
-rw-r--r--hw/pci_bridge.c2
-rw-r--r--hw/pci_ids.h4
-rw-r--r--hw/pcie.c2
-rw-r--r--hw/pckbd.c22
-rw-r--r--hw/pcnet-pci.c43
-rw-r--r--hw/pcnet.c5
-rw-r--r--hw/piix4.c37
-rw-r--r--hw/piix_pci.c140
-rw-r--r--hw/pl011.c40
-rw-r--r--hw/pl022.c16
-rw-r--r--hw/pl031.c23
-rw-r--r--hw/pl041.c38
-rw-r--r--hw/pl050.c42
-rw-r--r--hw/pl061.c42
-rw-r--r--hw/pl080.c46
-rw-r--r--hw/pl110.c69
-rw-r--r--hw/pl181.c25
-rw-r--r--hw/pl190.c25
-rw-r--r--hw/ppc440.c106
-rw-r--r--hw/ppc440.h21
-rw-r--r--hw/ppc440_bamboo.c154
-rw-r--r--hw/ppc4xx_pci.c147
-rw-r--r--hw/ppc_newworld.c2
-rw-r--r--hw/ppc_prep.c82
-rw-r--r--hw/ppce500_pci.c46
-rw-r--r--hw/ppce500_spin.c18
-rw-r--r--hw/prep_pci.c184
-rw-r--r--hw/prep_pci.h11
-rw-r--r--hw/pxa2xx.c108
-rw-r--r--hw/pxa2xx_dma.c33
-rw-r--r--hw/pxa2xx_gpio.c33
-rw-r--r--hw/pxa2xx_pic.c23
-rw-r--r--hw/pxa2xx_timer.c74
-rw-r--r--hw/qdev-addr.c6
-rw-r--r--hw/qdev-monitor.c588
-rw-r--r--hw/qdev-properties.c132
-rw-r--r--hw/qdev.c1141
-rw-r--r--hw/qdev.h363
-rw-r--r--hw/qxl.c77
-rw-r--r--hw/realview.c20
-rw-r--r--hw/realview_gic.c24
-rw-r--r--hw/rtl8139.c47
-rw-r--r--hw/s390-virtio-bus.c156
-rw-r--r--hw/s390-virtio-bus.h19
-rw-r--r--hw/s390-virtio.c1
-rw-r--r--hw/sb16.c140
-rw-r--r--hw/sbi.c23
-rw-r--r--hw/scsi-bus.c104
-rw-r--r--hw/scsi-disk.c187
-rw-r--r--hw/scsi-generic.c41
-rw-r--r--hw/scsi.h30
-rw-r--r--hw/serial.c36
-rw-r--r--hw/sga.c21
-rw-r--r--hw/sh_pci.c41
-rw-r--r--hw/slavio_intctl.c23
-rw-r--r--hw/slavio_misc.c41
-rw-r--r--hw/slavio_timer.c33
-rw-r--r--hw/sm501.c11
-rw-r--r--hw/smbus.c85
-rw-r--r--hw/smbus.h40
-rw-r--r--hw/smbus_eeprom.c39
-rw-r--r--hw/smc91c111.c35
-rw-r--r--hw/spapr.c136
-rw-r--r--hw/spapr_llan.c43
-rw-r--r--hw/spapr_pci.c208
-rw-r--r--hw/spapr_vio.c85
-rw-r--r--hw/spapr_vio.h34
-rw-r--r--hw/spapr_vscsi.c39
-rw-r--r--hw/spapr_vty.c39
-rw-r--r--hw/sparc32_dma.c35
-rw-r--r--hw/spitz.c110
-rw-r--r--hw/ssd0303.c37
-rw-r--r--hw/ssd0323.c20
-rw-r--r--hw/ssi-sd.c20
-rw-r--r--hw/ssi.c39
-rw-r--r--hw/ssi.h18
-rw-r--r--hw/stellaris.c71
-rw-r--r--hw/stellaris_enet.c31
-rw-r--r--hw/strongarm.c148
-rw-r--r--hw/sun4c_intctl.c23
-rw-r--r--hw/sun4m.c92
-rw-r--r--hw/sun4m_iommu.c33
-rw-r--r--hw/sun4u.c82
-rw-r--r--hw/sysbus.c50
-rw-r--r--hw/sysbus.h23
-rw-r--r--hw/tcx.c74
-rw-r--r--hw/tmp105.c41
-rw-r--r--hw/tosa.c54
-rw-r--r--hw/tusb6010.c21
-rw-r--r--hw/twl92230.c39
-rw-r--r--hw/unin_pci.c220
-rw-r--r--hw/usb-audio.c715
-rw-r--r--hw/usb-bt.c57
-rw-r--r--hw/usb-bus.c196
-rw-r--r--hw/usb-ccid.c142
-rw-r--r--hw/usb-desc.c161
-rw-r--r--hw/usb-desc.h5
-rw-r--r--hw/usb-ehci.c70
-rw-r--r--hw/usb-hid.c123
-rw-r--r--hw/usb-hub.c44
-rw-r--r--hw/usb-msd.c66
-rw-r--r--hw/usb-musb.c3
-rw-r--r--hw/usb-net.c66
-rw-r--r--hw/usb-ohci.c80
-rw-r--r--hw/usb-serial.c103
-rw-r--r--hw/usb-uhci.c204
-rw-r--r--hw/usb-wacom.c46
-rw-r--r--hw/usb-xhci.c2759
-rw-r--r--hw/usb.c147
-rw-r--r--hw/usb.h93
-rw-r--r--hw/versatile_pci.c58
-rw-r--r--hw/versatilepb.c23
-rw-r--r--hw/vexpress.c1
-rw-r--r--hw/vga-isa.c22
-rw-r--r--hw/vga-pci.c31
-rw-r--r--hw/vga.c397
-rw-r--r--hw/vga.h159
-rw-r--r--hw/vga_int.h16
-rw-r--r--hw/vga_template.h74
-rw-r--r--hw/vhost.c2
-rw-r--r--hw/virtex_ml507.c1
-rw-r--r--hw/virtio-blk.c2
-rw-r--r--hw/virtio-console.c77
-rw-r--r--hw/virtio-net.c2
-rw-r--r--hw/virtio-pci.c242
-rw-r--r--hw/virtio-serial-bus.c77
-rw-r--r--hw/virtio-serial.h85
-rw-r--r--hw/virtio.c12
-rw-r--r--hw/vmmouse.c36
-rw-r--r--hw/vmport.c20
-rw-r--r--hw/vmware_vga.c38
-rw-r--r--hw/vmware_vga.h8
-rw-r--r--hw/vt82c686.c136
-rw-r--r--hw/wdt_i6300esb.c37
-rw-r--r--hw/wdt_ib700.c22
-rw-r--r--hw/wm8750.c41
-rw-r--r--hw/xen_platform.c38
-rw-r--r--hw/xgmac.c433
-rw-r--r--hw/xilinx_axidma.c31
-rw-r--r--hw/xilinx_axienet.c39
-rw-r--r--hw/xilinx_ethlite.c35
-rw-r--r--hw/xilinx_intc.c29
-rw-r--r--hw/xilinx_timer.c31
-rw-r--r--hw/xilinx_uartlite.c19
-rw-r--r--hw/xio3130_downstream.c63
-rw-r--r--hw/xio3130_upstream.c57
-rw-r--r--hw/z2.c60
-rw-r--r--hw/zaurus.c31
294 files changed, 16283 insertions, 7096 deletions
diff --git a/hw/9pfs/virtio-9p-device.c b/hw/9pfs/virtio-9p-device.c
index 41a1a820e0..791a5572bb 100644
--- a/hw/9pfs/virtio-9p-device.c
+++ b/hw/9pfs/virtio-9p-device.c
@@ -154,29 +154,39 @@ static int virtio_9p_init_pci(PCIDevice *pci_dev)
     return 0;
 }
 
-static PCIDeviceInfo virtio_9p_info = {
-    .qdev.name = "virtio-9p-pci",
-    .qdev.size = sizeof(VirtIOPCIProxy),
-    .init      = virtio_9p_init_pci,
-    .vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET,
-    .device_id = 0x1009,
-    .revision  = VIRTIO_PCI_ABI_VERSION,
-    .class_id  = 0x2,
-    .qdev.props = (Property[]) {
-        DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
-                        VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
-        DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2),
-        DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features),
-        DEFINE_PROP_STRING("mount_tag", VirtIOPCIProxy, fsconf.tag),
-        DEFINE_PROP_STRING("fsdev", VirtIOPCIProxy, fsconf.fsdev_id),
-        DEFINE_PROP_END_OF_LIST(),
-    },
-    .qdev.reset = virtio_pci_reset,
+static Property virtio_9p_properties[] = {
+    DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags, VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
+    DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2),
+    DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features),
+    DEFINE_PROP_STRING("mount_tag", VirtIOPCIProxy, fsconf.tag),
+    DEFINE_PROP_STRING("fsdev", VirtIOPCIProxy, fsconf.fsdev_id),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void virtio_9p_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->init = virtio_9p_init_pci;
+    k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
+    k->device_id = 0x1009;
+    k->revision = VIRTIO_PCI_ABI_VERSION;
+    k->class_id = 0x2;
+    dc->props = virtio_9p_properties;
+    dc->reset = virtio_pci_reset;
+}
+
+static TypeInfo virtio_9p_info = {
+    .name          = "virtio-9p-pci",
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(VirtIOPCIProxy),
+    .class_init    = virtio_9p_class_init,
 };
 
 static void virtio_9p_register_devices(void)
 {
-    pci_qdev_register(&virtio_9p_info);
+    type_register_static(&virtio_9p_info);
     virtio_9p_set_fd_limit();
 }
 
diff --git a/hw/a9mpcore.c b/hw/a9mpcore.c
index 3ef0e138c4..19de12b4b4 100644
--- a/hw/a9mpcore.c
+++ b/hw/a9mpcore.c
@@ -11,9 +11,8 @@
 #include "sysbus.h"
 
 /* Configuration for arm_gic.c:
- * number of external IRQ lines, max number of CPUs, how to ID current CPU
+ * max number of CPUs, how to ID current CPU
  */
-#define GIC_NIRQ 96
 #define NCPU 4
 
 static inline int
@@ -37,6 +36,7 @@ typedef struct a9mp_priv_state {
     MemoryRegion ptimer_iomem;
     MemoryRegion container;
     DeviceState *mptimer;
+    uint32_t num_irq;
 } a9mp_priv_state;
 
 static uint64_t a9_scu_read(void *opaque, target_phys_addr_t offset,
@@ -153,7 +153,7 @@ static int a9mp_priv_init(SysBusDevice *dev)
         hw_error("a9mp_priv_init: num-cpu may not be more than %d\n", NCPU);
     }
 
-    gic_init(&s->gic, s->num_cpu);
+    gic_init(&s->gic, s->num_cpu, s->num_irq);
 
     s->mptimer = qdev_create(NULL, "arm_mptimer");
     qdev_prop_set_uint32(s->mptimer, "num-cpu", s->num_cpu);
@@ -208,21 +208,39 @@ static const VMStateDescription vmstate_a9mp_priv = {
     }
 };
 
-static SysBusDeviceInfo a9mp_priv_info = {
-    .init = a9mp_priv_init,
-    .qdev.name  = "a9mpcore_priv",
-    .qdev.size  = sizeof(a9mp_priv_state),
-    .qdev.vmsd = &vmstate_a9mp_priv,
-    .qdev.reset = a9mp_priv_reset,
-    .qdev.props = (Property[]) {
-        DEFINE_PROP_UINT32("num-cpu", a9mp_priv_state, num_cpu, 1),
-        DEFINE_PROP_END_OF_LIST(),
-    }
+static Property a9mp_priv_properties[] = {
+    DEFINE_PROP_UINT32("num-cpu", a9mp_priv_state, num_cpu, 1),
+    /* The Cortex-A9MP may have anything from 0 to 224 external interrupt
+     * IRQ lines (with another 32 internal). We default to 64+32, which
+     * is the number provided by the Cortex-A9MP test chip in the
+     * Realview PBX-A9 and Versatile Express A9 development boards.
+     * Other boards may differ and should set this property appropriately.
+     */
+    DEFINE_PROP_UINT32("num-irq", a9mp_priv_state, num_irq, 96),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void a9mp_priv_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = a9mp_priv_init;
+    dc->props = a9mp_priv_properties;
+    dc->vmsd = &vmstate_a9mp_priv;
+    dc->reset = a9mp_priv_reset;
+}
+
+static TypeInfo a9mp_priv_info = {
+    .name          = "a9mpcore_priv",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(a9mp_priv_state),
+    .class_init    = a9mp_priv_class_init,
 };
 
 static void a9mp_register_devices(void)
 {
-    sysbus_register_withprop(&a9mp_priv_info);
+    type_register_static(&a9mp_priv_info);
 }
 
 device_init(a9mp_register_devices)
diff --git a/hw/ac97.c b/hw/ac97.c
index 03be99b08a..7bf9171487 100644
--- a/hw/ac97.c
+++ b/hw/ac97.c
@@ -1175,17 +1175,17 @@ static const VMStateDescription vmstate_ac97_bm_regs = {
     .minimum_version_id = 1,
     .minimum_version_id_old = 1,
     .fields      = (VMStateField []) {
-        VMSTATE_UINT32(bdbar, AC97BusMasterRegs),
-        VMSTATE_UINT8(civ, AC97BusMasterRegs),
-        VMSTATE_UINT8(lvi, AC97BusMasterRegs),
-        VMSTATE_UINT16(sr, AC97BusMasterRegs),
-        VMSTATE_UINT16(picb, AC97BusMasterRegs),
-        VMSTATE_UINT8(piv, AC97BusMasterRegs),
-        VMSTATE_UINT8(cr, AC97BusMasterRegs),
-        VMSTATE_UINT32(bd_valid, AC97BusMasterRegs),
-        VMSTATE_UINT32(bd.addr, AC97BusMasterRegs),
-        VMSTATE_UINT32(bd.ctl_len, AC97BusMasterRegs),
-        VMSTATE_END_OF_LIST()
+        VMSTATE_UINT32 (bdbar, AC97BusMasterRegs),
+        VMSTATE_UINT8 (civ, AC97BusMasterRegs),
+        VMSTATE_UINT8 (lvi, AC97BusMasterRegs),
+        VMSTATE_UINT16 (sr, AC97BusMasterRegs),
+        VMSTATE_UINT16 (picb, AC97BusMasterRegs),
+        VMSTATE_UINT8 (piv, AC97BusMasterRegs),
+        VMSTATE_UINT8 (cr, AC97BusMasterRegs),
+        VMSTATE_UINT32 (bd_valid, AC97BusMasterRegs),
+        VMSTATE_UINT32 (bd.addr, AC97BusMasterRegs),
+        VMSTATE_UINT32 (bd.ctl_len, AC97BusMasterRegs),
+        VMSTATE_END_OF_LIST ()
     }
 };
 
@@ -1224,15 +1224,15 @@ static const VMStateDescription vmstate_ac97 = {
     .minimum_version_id_old = 2,
     .post_load = ac97_post_load,
     .fields      = (VMStateField []) {
-        VMSTATE_PCI_DEVICE(dev, AC97LinkState),
-        VMSTATE_UINT32(glob_cnt, AC97LinkState),
-        VMSTATE_UINT32(glob_sta, AC97LinkState),
-        VMSTATE_UINT32(cas, AC97LinkState),
-        VMSTATE_STRUCT_ARRAY(bm_regs, AC97LinkState, 3, 1,
-                             vmstate_ac97_bm_regs, AC97BusMasterRegs),
-        VMSTATE_BUFFER(mixer_data, AC97LinkState),
-        VMSTATE_UNUSED_TEST(is_version_2, 3),
-        VMSTATE_END_OF_LIST()
+        VMSTATE_PCI_DEVICE (dev, AC97LinkState),
+        VMSTATE_UINT32 (glob_cnt, AC97LinkState),
+        VMSTATE_UINT32 (glob_sta, AC97LinkState),
+        VMSTATE_UINT32 (cas, AC97LinkState),
+        VMSTATE_STRUCT_ARRAY (bm_regs, AC97LinkState, 3, 1,
+                              vmstate_ac97_bm_regs, AC97BusMasterRegs),
+        VMSTATE_BUFFER (mixer_data, AC97LinkState),
+        VMSTATE_UNUSED_TEST (is_version_2, 3),
+        VMSTATE_END_OF_LIST ()
     }
 };
 
@@ -1243,7 +1243,7 @@ static const MemoryRegionPortio nam_portio[] = {
     { 0, 256 * 1, 1, .write = nam_writeb, },
     { 0, 256 * 2, 2, .write = nam_writew, },
     { 0, 256 * 4, 4, .write = nam_writel, },
-    PORTIO_END_OF_LIST(),
+    PORTIO_END_OF_LIST (),
 };
 
 static const MemoryRegionOps ac97_io_nam_ops = {
@@ -1257,7 +1257,7 @@ static const MemoryRegionPortio nabm_portio[] = {
     { 0, 64 * 1, 1, .write = nabm_writeb, },
     { 0, 64 * 2, 2, .write = nabm_writew, },
     { 0, 64 * 4, 4, .write = nabm_writel, },
-    PORTIO_END_OF_LIST()
+    PORTIO_END_OF_LIST ()
 };
 
 static const MemoryRegionOps ac97_io_nabm_ops = {
@@ -1344,26 +1344,37 @@ int ac97_init (PCIBus *bus)
     return 0;
 }
 
-static PCIDeviceInfo ac97_info = {
-    .qdev.name    = "AC97",
-    .qdev.desc    = "Intel 82801AA AC97 Audio",
-    .qdev.size    = sizeof (AC97LinkState),
-    .qdev.vmsd    = &vmstate_ac97,
-    .init         = ac97_initfn,
-    .exit         = ac97_exitfn,
-    .vendor_id    = PCI_VENDOR_ID_INTEL,
-    .device_id    = PCI_DEVICE_ID_INTEL_82801AA_5,
-    .revision     = 0x01,
-    .class_id     = PCI_CLASS_MULTIMEDIA_AUDIO,
-    .qdev.props   = (Property[]) {
-        DEFINE_PROP_UINT32("use_broken_id", AC97LinkState, use_broken_id, 0),
-        DEFINE_PROP_END_OF_LIST(),
-    }
+static Property ac97_properties[] = {
+    DEFINE_PROP_UINT32 ("use_broken_id", AC97LinkState, use_broken_id, 0),
+    DEFINE_PROP_END_OF_LIST (),
+};
+
+static void ac97_class_init (ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS (klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS (klass);
+
+    k->init = ac97_initfn;
+    k->exit = ac97_exitfn;
+    k->vendor_id = PCI_VENDOR_ID_INTEL;
+    k->device_id = PCI_DEVICE_ID_INTEL_82801AA_5;
+    k->revision = 0x01;
+    k->class_id = PCI_CLASS_MULTIMEDIA_AUDIO;
+    dc->desc = "Intel 82801AA AC97 Audio";
+    dc->vmsd = &vmstate_ac97;
+    dc->props = ac97_properties;
+}
+
+static TypeInfo ac97_info = {
+    .name          = "AC97",
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof (AC97LinkState),
+    .class_init    = ac97_class_init,
 };
 
 static void ac97_register (void)
 {
-    pci_qdev_register (&ac97_info);
+    type_register_static (&ac97_info);
 }
 device_init (ac97_register);
 
diff --git a/hw/acpi_piix4.c b/hw/acpi_piix4.c
index bdc55a1eaa..21484aec42 100644
--- a/hw/acpi_piix4.c
+++ b/hw/acpi_piix4.c
@@ -280,11 +280,11 @@ static void piix4_update_hotplug(PIIX4PMState *s)
     s->pci0_hotplug_enable = ~0;
 
     QTAILQ_FOREACH_SAFE(qdev, &bus->children, sibling, next) {
-        PCIDeviceInfo *info = container_of(qdev->info, PCIDeviceInfo, qdev);
-        PCIDevice *pdev = DO_UPCAST(PCIDevice, qdev, qdev);
+        PCIDevice *pdev = PCI_DEVICE(qdev);
+        PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(pdev);
         int slot = PCI_SLOT(pdev->devfn);
 
-        if (info->no_hotplug) {
+        if (pc->no_hotplug) {
             s->pci0_hotplug_enable &= ~(1 << slot);
         }
     }
@@ -396,28 +396,39 @@ i2c_bus *piix4_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base,
     return s->smb.smbus;
 }
 
-static PCIDeviceInfo piix4_pm_info = {
-    .qdev.name          = "PIIX4_PM",
-    .qdev.desc          = "PM",
-    .qdev.size          = sizeof(PIIX4PMState),
-    .qdev.vmsd          = &vmstate_acpi,
-    .qdev.no_user       = 1,
-    .no_hotplug         = 1,
-    .init               = piix4_pm_initfn,
-    .config_write       = pm_write_config,
-    .vendor_id          = PCI_VENDOR_ID_INTEL,
-    .device_id          = PCI_DEVICE_ID_INTEL_82371AB_3,
-    .revision           = 0x03,
-    .class_id           = PCI_CLASS_BRIDGE_OTHER,
-    .qdev.props         = (Property[]) {
-        DEFINE_PROP_UINT32("smb_io_base", PIIX4PMState, smb_io_base, 0),
-        DEFINE_PROP_END_OF_LIST(),
-    }
+static Property piix4_pm_properties[] = {
+    DEFINE_PROP_UINT32("smb_io_base", PIIX4PMState, smb_io_base, 0),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void piix4_pm_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->no_hotplug = 1;
+    k->init = piix4_pm_initfn;
+    k->config_write = pm_write_config;
+    k->vendor_id = PCI_VENDOR_ID_INTEL;
+    k->device_id = PCI_DEVICE_ID_INTEL_82371AB_3;
+    k->revision = 0x03;
+    k->class_id = PCI_CLASS_BRIDGE_OTHER;
+    dc->desc = "PM";
+    dc->no_user = 1;
+    dc->vmsd = &vmstate_acpi;
+    dc->props = piix4_pm_properties;
+}
+
+static TypeInfo piix4_pm_info = {
+    .name          = "PIIX4_PM",
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(PIIX4PMState),
+    .class_init    = piix4_pm_class_init,
 };
 
 static void piix4_pm_register(void)
 {
-    pci_qdev_register(&piix4_pm_info);
+    type_register_static(&piix4_pm_info);
 }
 
 device_init(piix4_pm_register);
@@ -485,14 +496,12 @@ static void pciej_write(void *opaque, uint32_t addr, uint32_t val)
 {
     BusState *bus = opaque;
     DeviceState *qdev, *next;
-    PCIDevice *dev;
-    PCIDeviceInfo *info;
     int slot = ffs(val) - 1;
 
     QTAILQ_FOREACH_SAFE(qdev, &bus->children, sibling, next) {
-        dev = DO_UPCAST(PCIDevice, qdev, qdev);
-        info = container_of(qdev->info, PCIDeviceInfo, qdev);
-        if (PCI_SLOT(dev->devfn) == slot && !info->no_hotplug) {
+        PCIDevice *dev = PCI_DEVICE(qdev);
+        PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(dev);
+        if (PCI_SLOT(dev->devfn) == slot && !pc->no_hotplug) {
             qdev_free(qdev);
         }
     }
@@ -553,7 +562,7 @@ static int piix4_device_hotplug(DeviceState *qdev, PCIDevice *dev,
 {
     int slot = PCI_SLOT(dev->devfn);
     PIIX4PMState *s = DO_UPCAST(PIIX4PMState, dev,
-                                DO_UPCAST(PCIDevice, qdev, qdev));
+                                PCI_DEVICE(qdev));
 
     /* Don't send event when device is enabled during qemu machine creation:
      * it is present on boot, no hotplug event is necessary. We do send an
diff --git a/hw/adlib.c b/hw/adlib.c
index dd8b1888cf..d39cd97384 100644
--- a/hw/adlib.c
+++ b/hw/adlib.c
@@ -164,7 +164,7 @@ static void timer_handler (int c, double interval_Sec)
 
     s->ticking[n] = 1;
 #ifdef DEBUG
-    interval = get_ticks_per_sec() * interval_Sec;
+    interval = get_ticks_per_sec () * interval_Sec;
     exp = qemu_get_clock_ns (vm_clock) + interval;
     s->exp[n] = exp;
 #endif
diff --git a/hw/ads7846.c b/hw/ads7846.c
index de3f7af127..3cfdecbe5c 100644
--- a/hw/ads7846.c
+++ b/hw/ads7846.c
@@ -153,16 +153,24 @@ static int ads7846_init(SSISlave *dev)
     return 0;
 }
 
-static SSISlaveInfo ads7846_info = {
-    .qdev.name ="ads7846",
-    .qdev.size = sizeof(ADS7846State),
-    .init = ads7846_init,
-    .transfer = ads7846_transfer
+static void ads7846_class_init(ObjectClass *klass, void *data)
+{
+    SSISlaveClass *k = SSI_SLAVE_CLASS(klass);
+
+    k->init = ads7846_init;
+    k->transfer = ads7846_transfer;
+}
+
+static TypeInfo ads7846_info = {
+    .name          = "ads7846",
+    .parent        = TYPE_SSI_SLAVE,
+    .instance_size = sizeof(ADS7846State),
+    .class_init    = ads7846_class_init,
 };
 
 static void ads7846_register_devices(void)
 {
-    ssi_register_slave(&ads7846_info);
+    type_register_static(&ads7846_info);
 }
 
 device_init(ads7846_register_devices)
diff --git a/hw/alpha_pci.c b/hw/alpha_pci.c
index e9757028af..673557781e 100644
--- a/hw/alpha_pci.c
+++ b/hw/alpha_pci.c
@@ -121,10 +121,8 @@ void alpha_pci_vga_setup(PCIBus *pci_bus)
         pci_cirrus_vga_init(pci_bus);
         return;
     case VGA_VMWARE:
-        if (pci_vmsvga_init(pci_bus)) {
-            return;
-        }
-        break;
+        pci_vmsvga_init(pci_bus);
+        return;
     }
     /* If VGA is enabled at all, and one of the above didn't work, then
        fallback to Standard VGA.  */
diff --git a/hw/alpha_typhoon.c b/hw/alpha_typhoon.c
index 7d924a3f08..736c28a3a9 100644
--- a/hw/alpha_typhoon.c
+++ b/hw/alpha_typhoon.c
@@ -808,15 +808,24 @@ static int typhoon_pcihost_init(SysBusDevice *dev)
     return 0;
 }
 
-static SysBusDeviceInfo typhoon_pcihost_info = {
-    .init = typhoon_pcihost_init,
-    .qdev.name = "typhoon-pcihost",
-    .qdev.size = sizeof(TyphoonState),
-    .qdev.no_user = 1
+static void typhoon_pcihost_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = typhoon_pcihost_init;
+    dc->no_user = 1;
+}
+
+static TypeInfo typhoon_pcihost_info = {
+    .name          = "typhoon-pcihost",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(TyphoonState),
+    .class_init    = typhoon_pcihost_class_init,
 };
 
 static void typhoon_register(void)
 {
-    sysbus_register_withprop(&typhoon_pcihost_info);
+    type_register_static(&typhoon_pcihost_info);
 }
 device_init(typhoon_register);
diff --git a/hw/apb_pci.c b/hw/apb_pci.c
index 3a1b111455..c7aaa72d07 100644
--- a/hw/apb_pci.c
+++ b/hw/apb_pci.c
@@ -350,7 +350,7 @@ PCIBus *pci_apb_init(target_phys_addr_t special_base,
         sysbus_connect_irq(s, i, pic[i]);
     }
 
-    pci_create_simple(d->bus, 0, "pbm");
+    pci_create_simple(d->bus, 0, "pbm-pci");
 
     /* APB secondary busses */
     pci_dev = pci_create_multifunction(d->bus, PCI_DEVFN(1, 0), true,
@@ -436,42 +436,68 @@ static int pbm_pci_host_init(PCIDevice *d)
     return 0;
 }
 
-static PCIDeviceInfo pbm_pci_host_info = {
-    .qdev.name = "pbm",
-    .qdev.size = sizeof(PCIDevice),
-    .init      = pbm_pci_host_init,
-    .vendor_id = PCI_VENDOR_ID_SUN,
-    .device_id = PCI_DEVICE_ID_SUN_SABRE,
-    .class_id  = PCI_CLASS_BRIDGE_HOST,
-    .is_bridge = 1,
+static void pbm_pci_host_class_init(ObjectClass *klass, void *data)
+{
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->init = pbm_pci_host_init;
+    k->vendor_id = PCI_VENDOR_ID_SUN;
+    k->device_id = PCI_DEVICE_ID_SUN_SABRE;
+    k->class_id = PCI_CLASS_BRIDGE_HOST;
+    k->is_bridge = 1;
+}
+
+static TypeInfo pbm_pci_host_info = {
+    .name          = "pbm-pci",
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(PCIDevice),
+    .class_init    = pbm_pci_host_class_init,
 };
 
-static SysBusDeviceInfo pbm_host_info = {
-    .qdev.name = "pbm",
-    .qdev.size = sizeof(APBState),
-    .qdev.reset = pci_pbm_reset,
-    .init = pci_pbm_init_device,
+static void pbm_host_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = pci_pbm_init_device;
+    dc->reset = pci_pbm_reset;
+}
+
+static TypeInfo pbm_host_info = {
+    .name          = "pbm",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(APBState),
+    .class_init    = pbm_host_class_init,
 };
 
-static PCIDeviceInfo pbm_pci_bridge_info = {
-    .qdev.name = "pbm-bridge",
-    .qdev.size = sizeof(PCIBridge),
-    .qdev.vmsd = &vmstate_pci_device,
-    .qdev.reset = pci_bridge_reset,
-    .init = apb_pci_bridge_initfn,
-    .exit = pci_bridge_exitfn,
-    .vendor_id = PCI_VENDOR_ID_SUN,
-    .device_id = PCI_DEVICE_ID_SUN_SIMBA,
-    .revision = 0x11,
-    .config_write = pci_bridge_write_config,
-    .is_bridge = 1,
+static void pbm_pci_bridge_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->init = apb_pci_bridge_initfn;
+    k->exit = pci_bridge_exitfn;
+    k->vendor_id = PCI_VENDOR_ID_SUN;
+    k->device_id = PCI_DEVICE_ID_SUN_SIMBA;
+    k->revision = 0x11;
+    k->config_write = pci_bridge_write_config;
+    k->is_bridge = 1;
+    dc->reset = pci_bridge_reset;
+    dc->vmsd = &vmstate_pci_device;
+}
+
+static TypeInfo pbm_pci_bridge_info = {
+    .name          = "pbm-bridge",
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(PCIBridge),
+    .class_init    = pbm_pci_bridge_class_init,
 };
 
 static void pbm_register_devices(void)
 {
-    sysbus_register_withprop(&pbm_host_info);
-    pci_qdev_register(&pbm_pci_host_info);
-    pci_qdev_register(&pbm_pci_bridge_info);
+    type_register_static(&pbm_host_info);
+    type_register_static(&pbm_pci_host_info);
+    type_register_static(&pbm_pci_bridge_info);
 }
 
 device_init(pbm_register_devices)
diff --git a/hw/apic.c b/hw/apic.c
index 9d0f460b58..086c544bf3 100644
--- a/hw/apic.c
+++ b/hw/apic.c
@@ -16,53 +16,13 @@
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, see <http://www.gnu.org/licenses/>
  */
-#include "hw.h"
+#include "apic_internal.h"
 #include "apic.h"
 #include "ioapic.h"
-#include "qemu-timer.h"
 #include "host-utils.h"
-#include "sysbus.h"
 #include "trace.h"
 #include "pc.h"
 
-/* APIC Local Vector Table */
-#define APIC_LVT_TIMER   0
-#define APIC_LVT_THERMAL 1
-#define APIC_LVT_PERFORM 2
-#define APIC_LVT_LINT0   3
-#define APIC_LVT_LINT1   4
-#define APIC_LVT_ERROR   5
-#define APIC_LVT_NB      6
-
-/* APIC delivery modes */
-#define APIC_DM_FIXED	0
-#define APIC_DM_LOWPRI	1
-#define APIC_DM_SMI	2
-#define APIC_DM_NMI	4
-#define APIC_DM_INIT	5
-#define APIC_DM_SIPI	6
-#define APIC_DM_EXTINT	7
-
-/* APIC destination mode */
-#define APIC_DESTMODE_FLAT	0xf
-#define APIC_DESTMODE_CLUSTER	1
-
-#define APIC_TRIGGER_EDGE  0
-#define APIC_TRIGGER_LEVEL 1
-
-#define	APIC_LVT_TIMER_PERIODIC		(1<<17)
-#define	APIC_LVT_MASKED			(1<<16)
-#define	APIC_LVT_LEVEL_TRIGGER		(1<<15)
-#define	APIC_LVT_REMOTE_IRR		(1<<14)
-#define	APIC_INPUT_POLARITY		(1<<13)
-#define	APIC_SEND_PENDING		(1<<12)
-
-#define ESR_ILLEGAL_ADDRESS (1 << 7)
-
-#define APIC_SV_DIRECTED_IO             (1<<12)
-#define APIC_SV_ENABLE                  (1<<8)
-
-#define MAX_APICS 255
 #define MAX_APIC_WORDS 8
 
 /* Intel APIC constants: from include/asm/msidef.h */
@@ -75,43 +35,10 @@
 #define MSI_ADDR_DEST_ID_SHIFT		12
 #define	MSI_ADDR_DEST_ID_MASK		0x00ffff0
 
-#define MSI_ADDR_SIZE                   0x100000
-
-typedef struct APICState APICState;
-
-struct APICState {
-    SysBusDevice busdev;
-    MemoryRegion io_memory;
-    void *cpu_env;
-    uint32_t apicbase;
-    uint8_t id;
-    uint8_t arb_id;
-    uint8_t tpr;
-    uint32_t spurious_vec;
-    uint8_t log_dest;
-    uint8_t dest_mode;
-    uint32_t isr[8];  /* in service register */
-    uint32_t tmr[8];  /* trigger mode register */
-    uint32_t irr[8]; /* interrupt request register */
-    uint32_t lvt[APIC_LVT_NB];
-    uint32_t esr; /* error register */
-    uint32_t icr[2];
-
-    uint32_t divide_conf;
-    int count_shift;
-    uint32_t initial_count;
-    int64_t initial_count_load_time, next_time;
-    uint32_t idx;
-    QEMUTimer *timer;
-    int sipi_vector;
-    int wait_for_sipi;
-};
-
-static APICState *local_apics[MAX_APICS + 1];
-static int apic_irq_delivered;
+static APICCommonState *local_apics[MAX_APICS + 1];
 
-static void apic_set_irq(APICState *s, int vector_num, int trigger_mode);
-static void apic_update_irq(APICState *s);
+static void apic_set_irq(APICCommonState *s, int vector_num, int trigger_mode);
+static void apic_update_irq(APICCommonState *s);
 static void apic_get_delivery_bitmask(uint32_t *deliver_bitmask,
                                       uint8_t dest, uint8_t dest_mode);
 
@@ -151,7 +78,7 @@ static inline int get_bit(uint32_t *tab, int index)
     return !!(tab[i] & mask);
 }
 
-static void apic_local_deliver(APICState *s, int vector)
+static void apic_local_deliver(APICCommonState *s, int vector)
 {
     uint32_t lvt = s->lvt[vector];
     int trigger_mode;
@@ -185,7 +112,7 @@ static void apic_local_deliver(APICState *s, int vector)
 
 void apic_deliver_pic_intr(DeviceState *d, int level)
 {
-    APICState *s = DO_UPCAST(APICState, busdev.qdev, d);
+    APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d);
 
     if (level) {
         apic_local_deliver(s, APIC_LVT_LINT0);
@@ -205,6 +132,11 @@ void apic_deliver_pic_intr(DeviceState *d, int level)
     }
 }
 
+static void apic_external_nmi(APICCommonState *s)
+{
+    apic_local_deliver(s, APIC_LVT_LINT1);
+}
+
 #define foreach_apic(apic, deliver_bitmask, code) \
 {\
     int __i, __j, __mask;\
@@ -227,7 +159,7 @@ static void apic_bus_deliver(const uint32_t *deliver_bitmask,
                              uint8_t delivery_mode, uint8_t vector_num,
                              uint8_t trigger_mode)
 {
-    APICState *apic_iter;
+    APICCommonState *apic_iter;
 
     switch (delivery_mode) {
         case APIC_DM_LOWPRI:
@@ -293,14 +225,8 @@ void apic_deliver_irq(uint8_t dest, uint8_t dest_mode, uint8_t delivery_mode,
     apic_bus_deliver(deliver_bitmask, delivery_mode, vector_num, trigger_mode);
 }
 
-void cpu_set_apic_base(DeviceState *d, uint64_t val)
+static void apic_set_base(APICCommonState *s, uint64_t val)
 {
-    APICState *s = DO_UPCAST(APICState, busdev.qdev, d);
-
-    trace_cpu_set_apic_base(val);
-
-    if (!s)
-        return;
     s->apicbase = (val & 0xfffff000) |
         (s->apicbase & (MSR_IA32_APICBASE_BSP | MSR_IA32_APICBASE_ENABLE));
     /* if disabled, cannot be enabled again */
@@ -311,32 +237,12 @@ void cpu_set_apic_base(DeviceState *d, uint64_t val)
     }
 }
 
-uint64_t cpu_get_apic_base(DeviceState *d)
-{
-    APICState *s = DO_UPCAST(APICState, busdev.qdev, d);
-
-    trace_cpu_get_apic_base(s ? (uint64_t)s->apicbase: 0);
-
-    return s ? s->apicbase : 0;
-}
-
-void cpu_set_apic_tpr(DeviceState *d, uint8_t val)
+static void apic_set_tpr(APICCommonState *s, uint8_t val)
 {
-    APICState *s = DO_UPCAST(APICState, busdev.qdev, d);
-
-    if (!s)
-        return;
     s->tpr = (val & 0x0f) << 4;
     apic_update_irq(s);
 }
 
-uint8_t cpu_get_apic_tpr(DeviceState *d)
-{
-    APICState *s = DO_UPCAST(APICState, busdev.qdev, d);
-
-    return s ? s->tpr >> 4 : 0;
-}
-
 /* return -1 if no bit is set */
 static int get_highest_priority_int(uint32_t *tab)
 {
@@ -349,7 +255,7 @@ static int get_highest_priority_int(uint32_t *tab)
     return -1;
 }
 
-static int apic_get_ppr(APICState *s)
+static int apic_get_ppr(APICCommonState *s)
 {
     int tpr, isrv, ppr;
 
@@ -365,7 +271,7 @@ static int apic_get_ppr(APICState *s)
     return ppr;
 }
 
-static int apic_get_arb_pri(APICState *s)
+static int apic_get_arb_pri(APICCommonState *s)
 {
     /* XXX: arbitration */
     return 0;
@@ -377,7 +283,7 @@ static int apic_get_arb_pri(APICState *s)
  * 0  - no interrupt,
  * >0 - interrupt number
  */
-static int apic_irq_pending(APICState *s)
+static int apic_irq_pending(APICCommonState *s)
 {
     int irrv, ppr;
     irrv = get_highest_priority_int(s->irr);
@@ -393,7 +299,7 @@ static int apic_irq_pending(APICState *s)
 }
 
 /* signal the CPU if an irq is pending */
-static void apic_update_irq(APICState *s)
+static void apic_update_irq(APICCommonState *s)
 {
     if (!(s->spurious_vec & APIC_SV_ENABLE)) {
         return;
@@ -406,25 +312,9 @@ static void apic_update_irq(APICState *s)
     }
 }
 
-void apic_reset_irq_delivered(void)
+static void apic_set_irq(APICCommonState *s, int vector_num, int trigger_mode)
 {
-    trace_apic_reset_irq_delivered(apic_irq_delivered);
-
-    apic_irq_delivered = 0;
-}
-
-int apic_get_irq_delivered(void)
-{
-    trace_apic_get_irq_delivered(apic_irq_delivered);
-
-    return apic_irq_delivered;
-}
-
-static void apic_set_irq(APICState *s, int vector_num, int trigger_mode)
-{
-    apic_irq_delivered += !get_bit(s->irr, vector_num);
-
-    trace_apic_set_irq(apic_irq_delivered);
+    apic_report_irq_delivered(!get_bit(s->irr, vector_num));
 
     set_bit(s->irr, vector_num);
     if (trigger_mode)
@@ -434,7 +324,7 @@ static void apic_set_irq(APICState *s, int vector_num, int trigger_mode)
     apic_update_irq(s);
 }
 
-static void apic_eoi(APICState *s)
+static void apic_eoi(APICCommonState *s)
 {
     int isrv;
     isrv = get_highest_priority_int(s->isr);
@@ -449,7 +339,7 @@ static void apic_eoi(APICState *s)
 
 static int apic_find_dest(uint8_t dest)
 {
-    APICState *apic = local_apics[dest];
+    APICCommonState *apic = local_apics[dest];
     int i;
 
     if (apic && apic->id == dest)
@@ -469,7 +359,7 @@ static int apic_find_dest(uint8_t dest)
 static void apic_get_delivery_bitmask(uint32_t *deliver_bitmask,
                                       uint8_t dest, uint8_t dest_mode)
 {
-    APICState *apic_iter;
+    APICCommonState *apic_iter;
     int i;
 
     if (dest_mode == 0) {
@@ -503,34 +393,7 @@ static void apic_get_delivery_bitmask(uint32_t *deliver_bitmask,
     }
 }
 
-void apic_init_reset(DeviceState *d)
-{
-    APICState *s = DO_UPCAST(APICState, busdev.qdev, d);
-    int i;
-
-    if (!s)
-        return;
-
-    s->tpr = 0;
-    s->spurious_vec = 0xff;
-    s->log_dest = 0;
-    s->dest_mode = 0xf;
-    memset(s->isr, 0, sizeof(s->isr));
-    memset(s->tmr, 0, sizeof(s->tmr));
-    memset(s->irr, 0, sizeof(s->irr));
-    for(i = 0; i < APIC_LVT_NB; i++)
-        s->lvt[i] = 1 << 16; /* mask LVT */
-    s->esr = 0;
-    memset(s->icr, 0, sizeof(s->icr));
-    s->divide_conf = 0;
-    s->count_shift = 0;
-    s->initial_count = 0;
-    s->initial_count_load_time = 0;
-    s->next_time = 0;
-    s->wait_for_sipi = 1;
-}
-
-static void apic_startup(APICState *s, int vector_num)
+static void apic_startup(APICCommonState *s, int vector_num)
 {
     s->sipi_vector = vector_num;
     cpu_interrupt(s->cpu_env, CPU_INTERRUPT_SIPI);
@@ -538,7 +401,7 @@ static void apic_startup(APICState *s, int vector_num)
 
 void apic_sipi(DeviceState *d)
 {
-    APICState *s = DO_UPCAST(APICState, busdev.qdev, d);
+    APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d);
 
     cpu_reset_interrupt(s->cpu_env, CPU_INTERRUPT_SIPI);
 
@@ -552,10 +415,10 @@ static void apic_deliver(DeviceState *d, uint8_t dest, uint8_t dest_mode,
                          uint8_t delivery_mode, uint8_t vector_num,
                          uint8_t trigger_mode)
 {
-    APICState *s = DO_UPCAST(APICState, busdev.qdev, d);
+    APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d);
     uint32_t deliver_bitmask[MAX_APIC_WORDS];
     int dest_shorthand = (s->icr[0] >> 18) & 3;
-    APICState *apic_iter;
+    APICCommonState *apic_iter;
 
     switch (dest_shorthand) {
     case 0:
@@ -598,7 +461,7 @@ static void apic_deliver(DeviceState *d, uint8_t dest, uint8_t dest_mode,
 
 int apic_get_interrupt(DeviceState *d)
 {
-    APICState *s = DO_UPCAST(APICState, busdev.qdev, d);
+    APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d);
     int intno;
 
     /* if the APIC is installed or enabled, we let the 8259 handle the
@@ -623,7 +486,7 @@ int apic_get_interrupt(DeviceState *d)
 
 int apic_accept_pic_intr(DeviceState *d)
 {
-    APICState *s = DO_UPCAST(APICState, busdev.qdev, d);
+    APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d);
     uint32_t lvt0;
 
     if (!s)
@@ -638,7 +501,7 @@ int apic_accept_pic_intr(DeviceState *d)
     return 0;
 }
 
-static uint32_t apic_get_current_count(APICState *s)
+static uint32_t apic_get_current_count(APICCommonState *s)
 {
     int64_t d;
     uint32_t val;
@@ -656,34 +519,18 @@ static uint32_t apic_get_current_count(APICState *s)
     return val;
 }
 
-static void apic_timer_update(APICState *s, int64_t current_time)
+static void apic_timer_update(APICCommonState *s, int64_t current_time)
 {
-    int64_t next_time, d;
-
-    if (!(s->lvt[APIC_LVT_TIMER] & APIC_LVT_MASKED)) {
-        d = (current_time - s->initial_count_load_time) >>
-            s->count_shift;
-        if (s->lvt[APIC_LVT_TIMER] & APIC_LVT_TIMER_PERIODIC) {
-            if (!s->initial_count)
-                goto no_timer;
-            d = ((d / ((uint64_t)s->initial_count + 1)) + 1) * ((uint64_t)s->initial_count + 1);
-        } else {
-            if (d >= s->initial_count)
-                goto no_timer;
-            d = (uint64_t)s->initial_count + 1;
-        }
-        next_time = s->initial_count_load_time + (d << s->count_shift);
-        qemu_mod_timer(s->timer, next_time);
-        s->next_time = next_time;
+    if (apic_next_timer(s, current_time)) {
+        qemu_mod_timer(s->timer, s->next_time);
     } else {
-    no_timer:
         qemu_del_timer(s->timer);
     }
 }
 
 static void apic_timer(void *opaque)
 {
-    APICState *s = opaque;
+    APICCommonState *s = opaque;
 
     apic_local_deliver(s, APIC_LVT_TIMER);
     apic_timer_update(s, s->next_time);
@@ -710,7 +557,7 @@ static void apic_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
 static uint32_t apic_mem_readl(void *opaque, target_phys_addr_t addr)
 {
     DeviceState *d;
-    APICState *s;
+    APICCommonState *s;
     uint32_t val;
     int index;
 
@@ -718,7 +565,7 @@ static uint32_t apic_mem_readl(void *opaque, target_phys_addr_t addr)
     if (!d) {
         return 0;
     }
-    s = DO_UPCAST(APICState, busdev.qdev, d);
+    s = DO_UPCAST(APICCommonState, busdev.qdev, d);
 
     index = (addr >> 4) & 0xff;
     switch(index) {
@@ -801,7 +648,7 @@ static void apic_send_msi(target_phys_addr_t addr, uint32_t data)
 static void apic_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
 {
     DeviceState *d;
-    APICState *s;
+    APICCommonState *s;
     int index = (addr >> 4) & 0xff;
     if (addr > 0xfff || !index) {
         /* MSI and MMIO APIC are at the same memory location,
@@ -817,7 +664,7 @@ static void apic_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
     if (!d) {
         return;
     }
-    s = DO_UPCAST(APICState, busdev.qdev, d);
+    s = DO_UPCAST(APICCommonState, busdev.qdev, d);
 
     trace_apic_mem_writel(addr, val);
 
@@ -890,93 +737,12 @@ static void apic_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
     }
 }
 
-/* This function is only used for old state version 1 and 2 */
-static int apic_load_old(QEMUFile *f, void *opaque, int version_id)
+static void apic_post_load(APICCommonState *s)
 {
-    APICState *s = opaque;
-    int i;
-
-    if (version_id > 2)
-        return -EINVAL;
-
-    /* XXX: what if the base changes? (registered memory regions) */
-    qemu_get_be32s(f, &s->apicbase);
-    qemu_get_8s(f, &s->id);
-    qemu_get_8s(f, &s->arb_id);
-    qemu_get_8s(f, &s->tpr);
-    qemu_get_be32s(f, &s->spurious_vec);
-    qemu_get_8s(f, &s->log_dest);
-    qemu_get_8s(f, &s->dest_mode);
-    for (i = 0; i < 8; i++) {
-        qemu_get_be32s(f, &s->isr[i]);
-        qemu_get_be32s(f, &s->tmr[i]);
-        qemu_get_be32s(f, &s->irr[i]);
-    }
-    for (i = 0; i < APIC_LVT_NB; i++) {
-        qemu_get_be32s(f, &s->lvt[i]);
-    }
-    qemu_get_be32s(f, &s->esr);
-    qemu_get_be32s(f, &s->icr[0]);
-    qemu_get_be32s(f, &s->icr[1]);
-    qemu_get_be32s(f, &s->divide_conf);
-    s->count_shift=qemu_get_be32(f);
-    qemu_get_be32s(f, &s->initial_count);
-    s->initial_count_load_time=qemu_get_be64(f);
-    s->next_time=qemu_get_be64(f);
-
-    if (version_id >= 2)
-        qemu_get_timer(f, s->timer);
-    return 0;
-}
-
-static const VMStateDescription vmstate_apic = {
-    .name = "apic",
-    .version_id = 3,
-    .minimum_version_id = 3,
-    .minimum_version_id_old = 1,
-    .load_state_old = apic_load_old,
-    .fields      = (VMStateField []) {
-        VMSTATE_UINT32(apicbase, APICState),
-        VMSTATE_UINT8(id, APICState),
-        VMSTATE_UINT8(arb_id, APICState),
-        VMSTATE_UINT8(tpr, APICState),
-        VMSTATE_UINT32(spurious_vec, APICState),
-        VMSTATE_UINT8(log_dest, APICState),
-        VMSTATE_UINT8(dest_mode, APICState),
-        VMSTATE_UINT32_ARRAY(isr, APICState, 8),
-        VMSTATE_UINT32_ARRAY(tmr, APICState, 8),
-        VMSTATE_UINT32_ARRAY(irr, APICState, 8),
-        VMSTATE_UINT32_ARRAY(lvt, APICState, APIC_LVT_NB),
-        VMSTATE_UINT32(esr, APICState),
-        VMSTATE_UINT32_ARRAY(icr, APICState, 2),
-        VMSTATE_UINT32(divide_conf, APICState),
-        VMSTATE_INT32(count_shift, APICState),
-        VMSTATE_UINT32(initial_count, APICState),
-        VMSTATE_INT64(initial_count_load_time, APICState),
-        VMSTATE_INT64(next_time, APICState),
-        VMSTATE_TIMER(timer, APICState),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static void apic_reset(DeviceState *d)
-{
-    APICState *s = DO_UPCAST(APICState, busdev.qdev, d);
-    int bsp;
-
-    bsp = cpu_is_bsp(s->cpu_env);
-    s->apicbase = 0xfee00000 |
-        (bsp ? MSR_IA32_APICBASE_BSP : 0) | MSR_IA32_APICBASE_ENABLE;
-
-    apic_init_reset(d);
-
-    if (bsp) {
-        /*
-         * LINT0 delivery mode on CPU #0 is set to ExtInt at initialization
-         * time typically by BIOS, so PIC interrupt can be delivered to the
-         * processor when local APIC is enabled.
-         */
-        s->lvt[APIC_LVT_LINT0] = 0x700;
+    if (s->timer_expiry != -1) {
+        qemu_mod_timer(s->timer, s->timer_expiry);
+    } else {
+        qemu_del_timer(s->timer);
     }
 }
 
@@ -988,41 +754,36 @@ static const MemoryRegionOps apic_io_ops = {
     .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
-static int apic_init1(SysBusDevice *dev)
+static void apic_init(APICCommonState *s)
 {
-    APICState *s = FROM_SYSBUS(APICState, dev);
-    static int last_apic_idx;
-
-    if (last_apic_idx >= MAX_APICS) {
-        return -1;
-    }
-    memory_region_init_io(&s->io_memory, &apic_io_ops, s, "apic",
-                          MSI_ADDR_SIZE);
-    sysbus_init_mmio(dev, &s->io_memory);
+    memory_region_init_io(&s->io_memory, &apic_io_ops, s, "apic-msi",
+                          MSI_SPACE_SIZE);
 
     s->timer = qemu_new_timer_ns(vm_clock, apic_timer, s);
-    s->idx = last_apic_idx++;
     local_apics[s->idx] = s;
-    return 0;
 }
 
-static SysBusDeviceInfo apic_info = {
-    .init = apic_init1,
-    .qdev.name = "apic",
-    .qdev.size = sizeof(APICState),
-    .qdev.vmsd = &vmstate_apic,
-    .qdev.reset = apic_reset,
-    .qdev.no_user = 1,
-    .qdev.props = (Property[]) {
-        DEFINE_PROP_UINT8("id", APICState, id, -1),
-        DEFINE_PROP_PTR("cpu_env", APICState, cpu_env),
-        DEFINE_PROP_END_OF_LIST(),
-    }
+static void apic_class_init(ObjectClass *klass, void *data)
+{
+    APICCommonClass *k = APIC_COMMON_CLASS(klass);
+
+    k->init = apic_init;
+    k->set_base = apic_set_base;
+    k->set_tpr = apic_set_tpr;
+    k->external_nmi = apic_external_nmi;
+    k->post_load = apic_post_load;
+}
+
+static TypeInfo apic_info = {
+    .name          = "apic",
+    .instance_size = sizeof(APICCommonState),
+    .parent        = TYPE_APIC_COMMON,
+    .class_init    = apic_class_init,
 };
 
 static void apic_register_devices(void)
 {
-    sysbus_register_withprop(&apic_info);
+    type_register_static(&apic_info);
 }
 
 device_init(apic_register_devices)
diff --git a/hw/apic.h b/hw/apic.h
index a5c910fe0a..a62d83ba9f 100644
--- a/hw/apic.h
+++ b/hw/apic.h
@@ -8,6 +8,7 @@ void apic_deliver_irq(uint8_t dest, uint8_t dest_mode, uint8_t delivery_mode,
                       uint8_t vector_num, uint8_t trigger_mode);
 int apic_accept_pic_intr(DeviceState *s);
 void apic_deliver_pic_intr(DeviceState *s, int level);
+void apic_deliver_nmi(DeviceState *d);
 int apic_get_interrupt(DeviceState *s);
 void apic_reset_irq_delivered(void);
 int apic_get_irq_delivered(void);
diff --git a/hw/apic_common.c b/hw/apic_common.c
new file mode 100644
index 0000000000..26991b4516
--- /dev/null
+++ b/hw/apic_common.c
@@ -0,0 +1,321 @@
+/*
+ *  APIC support - common bits of emulated and KVM kernel model
+ *
+ *  Copyright (c) 2004-2005 Fabrice Bellard
+ *  Copyright (c) 2011      Jan Kiszka, Siemens AG
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>
+ */
+#include "apic.h"
+#include "apic_internal.h"
+#include "trace.h"
+
+static int apic_irq_delivered;
+
+void cpu_set_apic_base(DeviceState *d, uint64_t val)
+{
+    trace_cpu_set_apic_base(val);
+
+    if (d) {
+        APICCommonState *s = APIC_COMMON(d);
+        APICCommonClass *info = APIC_COMMON_GET_CLASS(s);
+        info->set_base(s, val);
+    }
+}
+
+uint64_t cpu_get_apic_base(DeviceState *d)
+{
+    if (d) {
+        APICCommonState *s = APIC_COMMON(d);
+        trace_cpu_get_apic_base((uint64_t)s->apicbase);
+        return s->apicbase;
+    } else {
+        trace_cpu_get_apic_base(0);
+        return 0;
+    }
+}
+
+void cpu_set_apic_tpr(DeviceState *d, uint8_t val)
+{
+    APICCommonState *s;
+    APICCommonClass *info;
+
+    if (!d) {
+        return;
+    }
+
+    s = APIC_COMMON(d);
+    info = APIC_COMMON_GET_CLASS(s);
+
+    info->set_tpr(s, val);
+}
+
+uint8_t cpu_get_apic_tpr(DeviceState *d)
+{
+    APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d);
+
+    return s ? s->tpr >> 4 : 0;
+}
+
+void apic_report_irq_delivered(int delivered)
+{
+    apic_irq_delivered += delivered;
+
+    trace_apic_report_irq_delivered(apic_irq_delivered);
+}
+
+void apic_reset_irq_delivered(void)
+{
+    trace_apic_reset_irq_delivered(apic_irq_delivered);
+
+    apic_irq_delivered = 0;
+}
+
+int apic_get_irq_delivered(void)
+{
+    trace_apic_get_irq_delivered(apic_irq_delivered);
+
+    return apic_irq_delivered;
+}
+
+void apic_deliver_nmi(DeviceState *d)
+{
+    APICCommonState *s = APIC_COMMON(d);
+    APICCommonClass *info = APIC_COMMON_GET_CLASS(s);
+
+    info->external_nmi(s);
+}
+
+bool apic_next_timer(APICCommonState *s, int64_t current_time)
+{
+    int64_t d;
+
+    /* We need to store the timer state separately to support APIC
+     * implementations that maintain a non-QEMU timer, e.g. inside the
+     * host kernel. This open-coded state allows us to migrate between
+     * both models. */
+    s->timer_expiry = -1;
+
+    if (s->lvt[APIC_LVT_TIMER] & APIC_LVT_MASKED) {
+        return false;
+    }
+
+    d = (current_time - s->initial_count_load_time) >> s->count_shift;
+
+    if (s->lvt[APIC_LVT_TIMER] & APIC_LVT_TIMER_PERIODIC) {
+        if (!s->initial_count) {
+            return false;
+        }
+        d = ((d / ((uint64_t)s->initial_count + 1)) + 1) *
+            ((uint64_t)s->initial_count + 1);
+    } else {
+        if (d >= s->initial_count) {
+            return false;
+        }
+        d = (uint64_t)s->initial_count + 1;
+    }
+    s->next_time = s->initial_count_load_time + (d << s->count_shift);
+    s->timer_expiry = s->next_time;
+    return true;
+}
+
+void apic_init_reset(DeviceState *d)
+{
+    APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d);
+    int i;
+
+    if (!s) {
+        return;
+    }
+    s->tpr = 0;
+    s->spurious_vec = 0xff;
+    s->log_dest = 0;
+    s->dest_mode = 0xf;
+    memset(s->isr, 0, sizeof(s->isr));
+    memset(s->tmr, 0, sizeof(s->tmr));
+    memset(s->irr, 0, sizeof(s->irr));
+    for (i = 0; i < APIC_LVT_NB; i++) {
+        s->lvt[i] = APIC_LVT_MASKED;
+    }
+    s->esr = 0;
+    memset(s->icr, 0, sizeof(s->icr));
+    s->divide_conf = 0;
+    s->count_shift = 0;
+    s->initial_count = 0;
+    s->initial_count_load_time = 0;
+    s->next_time = 0;
+    s->wait_for_sipi = 1;
+
+    if (s->timer) {
+        qemu_del_timer(s->timer);
+    }
+    s->timer_expiry = -1;
+}
+
+static void apic_reset_common(DeviceState *d)
+{
+    APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d);
+    bool bsp;
+
+    bsp = cpu_is_bsp(s->cpu_env);
+    s->apicbase = 0xfee00000 |
+        (bsp ? MSR_IA32_APICBASE_BSP : 0) | MSR_IA32_APICBASE_ENABLE;
+
+    apic_init_reset(d);
+
+    if (bsp) {
+        /*
+         * LINT0 delivery mode on CPU #0 is set to ExtInt at initialization
+         * time typically by BIOS, so PIC interrupt can be delivered to the
+         * processor when local APIC is enabled.
+         */
+        s->lvt[APIC_LVT_LINT0] = 0x700;
+    }
+}
+
+/* This function is only used for old state version 1 and 2 */
+static int apic_load_old(QEMUFile *f, void *opaque, int version_id)
+{
+    APICCommonState *s = opaque;
+    int i;
+
+    if (version_id > 2) {
+        return -EINVAL;
+    }
+
+    /* XXX: what if the base changes? (registered memory regions) */
+    qemu_get_be32s(f, &s->apicbase);
+    qemu_get_8s(f, &s->id);
+    qemu_get_8s(f, &s->arb_id);
+    qemu_get_8s(f, &s->tpr);
+    qemu_get_be32s(f, &s->spurious_vec);
+    qemu_get_8s(f, &s->log_dest);
+    qemu_get_8s(f, &s->dest_mode);
+    for (i = 0; i < 8; i++) {
+        qemu_get_be32s(f, &s->isr[i]);
+        qemu_get_be32s(f, &s->tmr[i]);
+        qemu_get_be32s(f, &s->irr[i]);
+    }
+    for (i = 0; i < APIC_LVT_NB; i++) {
+        qemu_get_be32s(f, &s->lvt[i]);
+    }
+    qemu_get_be32s(f, &s->esr);
+    qemu_get_be32s(f, &s->icr[0]);
+    qemu_get_be32s(f, &s->icr[1]);
+    qemu_get_be32s(f, &s->divide_conf);
+    s->count_shift = qemu_get_be32(f);
+    qemu_get_be32s(f, &s->initial_count);
+    s->initial_count_load_time = qemu_get_be64(f);
+    s->next_time = qemu_get_be64(f);
+
+    if (version_id >= 2) {
+        qemu_get_timer(f, s->timer);
+    }
+    return 0;
+}
+
+static int apic_init_common(SysBusDevice *dev)
+{
+    APICCommonState *s = APIC_COMMON(dev);
+    APICCommonClass *info;
+    static int apic_no;
+
+    if (apic_no >= MAX_APICS) {
+        return -1;
+    }
+    s->idx = apic_no++;
+
+    info = APIC_COMMON_GET_CLASS(s);
+    info->init(s);
+
+    sysbus_init_mmio(&s->busdev, &s->io_memory);
+    return 0;
+}
+
+static int apic_dispatch_post_load(void *opaque, int version_id)
+{
+    APICCommonState *s = APIC_COMMON(opaque);
+    APICCommonClass *info = APIC_COMMON_GET_CLASS(s);
+
+    if (info->post_load) {
+        info->post_load(s);
+    }
+    return 0;
+}
+
+static const VMStateDescription vmstate_apic_common = {
+    .name = "apic",
+    .version_id = 3,
+    .minimum_version_id = 3,
+    .minimum_version_id_old = 1,
+    .load_state_old = apic_load_old,
+    .post_load = apic_dispatch_post_load,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(apicbase, APICCommonState),
+        VMSTATE_UINT8(id, APICCommonState),
+        VMSTATE_UINT8(arb_id, APICCommonState),
+        VMSTATE_UINT8(tpr, APICCommonState),
+        VMSTATE_UINT32(spurious_vec, APICCommonState),
+        VMSTATE_UINT8(log_dest, APICCommonState),
+        VMSTATE_UINT8(dest_mode, APICCommonState),
+        VMSTATE_UINT32_ARRAY(isr, APICCommonState, 8),
+        VMSTATE_UINT32_ARRAY(tmr, APICCommonState, 8),
+        VMSTATE_UINT32_ARRAY(irr, APICCommonState, 8),
+        VMSTATE_UINT32_ARRAY(lvt, APICCommonState, APIC_LVT_NB),
+        VMSTATE_UINT32(esr, APICCommonState),
+        VMSTATE_UINT32_ARRAY(icr, APICCommonState, 2),
+        VMSTATE_UINT32(divide_conf, APICCommonState),
+        VMSTATE_INT32(count_shift, APICCommonState),
+        VMSTATE_UINT32(initial_count, APICCommonState),
+        VMSTATE_INT64(initial_count_load_time, APICCommonState),
+        VMSTATE_INT64(next_time, APICCommonState),
+        VMSTATE_INT64(timer_expiry,
+                      APICCommonState), /* open-coded timer state */
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static Property apic_properties_common[] = {
+    DEFINE_PROP_UINT8("id", APICCommonState, id, -1),
+    DEFINE_PROP_PTR("cpu_env", APICCommonState, cpu_env),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void apic_common_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *sc = SYS_BUS_DEVICE_CLASS(klass);
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    dc->vmsd = &vmstate_apic_common;
+    dc->reset = apic_reset_common;
+    dc->no_user = 1;
+    dc->props = apic_properties_common;
+    sc->init = apic_init_common;
+}
+
+static TypeInfo apic_common_type = {
+    .name = TYPE_APIC_COMMON,
+    .parent = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(APICCommonState),
+    .class_size = sizeof(APICCommonClass),
+    .class_init = apic_common_class_init,
+    .abstract = true,
+};
+
+static void register_devices(void)
+{
+    type_register_static(&apic_common_type);
+}
+
+device_init(register_devices);
diff --git a/hw/apic_internal.h b/hw/apic_internal.h
new file mode 100644
index 0000000000..0cab010717
--- /dev/null
+++ b/hw/apic_internal.h
@@ -0,0 +1,122 @@
+/*
+ *  APIC support - internal interfaces
+ *
+ *  Copyright (c) 2004-2005 Fabrice Bellard
+ *  Copyright (c) 2011      Jan Kiszka, Siemens AG
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>
+ */
+#ifndef QEMU_APIC_INTERNAL_H
+#define QEMU_APIC_INTERNAL_H
+
+#include "memory.h"
+#include "sysbus.h"
+#include "qemu-timer.h"
+
+/* APIC Local Vector Table */
+#define APIC_LVT_TIMER                  0
+#define APIC_LVT_THERMAL                1
+#define APIC_LVT_PERFORM                2
+#define APIC_LVT_LINT0                  3
+#define APIC_LVT_LINT1                  4
+#define APIC_LVT_ERROR                  5
+#define APIC_LVT_NB                     6
+
+/* APIC delivery modes */
+#define APIC_DM_FIXED                   0
+#define APIC_DM_LOWPRI                  1
+#define APIC_DM_SMI                     2
+#define APIC_DM_NMI                     4
+#define APIC_DM_INIT                    5
+#define APIC_DM_SIPI                    6
+#define APIC_DM_EXTINT                  7
+
+/* APIC destination mode */
+#define APIC_DESTMODE_FLAT              0xf
+#define APIC_DESTMODE_CLUSTER           1
+
+#define APIC_TRIGGER_EDGE               0
+#define APIC_TRIGGER_LEVEL              1
+
+#define APIC_LVT_TIMER_PERIODIC         (1<<17)
+#define APIC_LVT_MASKED                 (1<<16)
+#define APIC_LVT_LEVEL_TRIGGER          (1<<15)
+#define APIC_LVT_REMOTE_IRR             (1<<14)
+#define APIC_INPUT_POLARITY             (1<<13)
+#define APIC_SEND_PENDING               (1<<12)
+
+#define ESR_ILLEGAL_ADDRESS (1 << 7)
+
+#define APIC_SV_DIRECTED_IO             (1<<12)
+#define APIC_SV_ENABLE                  (1<<8)
+
+#define MAX_APICS 255
+
+#define MSI_SPACE_SIZE                  0x100000
+
+typedef struct APICCommonState APICCommonState;
+
+#define TYPE_APIC_COMMON "apic-common"
+#define APIC_COMMON(obj) \
+     OBJECT_CHECK(APICCommonState, (obj), TYPE_APIC_COMMON)
+#define APIC_COMMON_CLASS(klass) \
+     OBJECT_CLASS_CHECK(APICCommonClass, (klass), TYPE_APIC_COMMON)
+#define APIC_COMMON_GET_CLASS(obj) \
+     OBJECT_GET_CLASS(APICCommonClass, (obj), TYPE_APIC_COMMON)
+
+typedef struct APICCommonClass
+{
+    SysBusDeviceClass parent_class;
+
+    void (*init)(APICCommonState *s);
+    void (*set_base)(APICCommonState *s, uint64_t val);
+    void (*set_tpr)(APICCommonState *s, uint8_t val);
+    void (*external_nmi)(APICCommonState *s);
+    void (*post_load)(APICCommonState *s);
+} APICCommonClass;
+
+struct APICCommonState {
+    SysBusDevice busdev;
+    MemoryRegion io_memory;
+    void *cpu_env;
+    uint32_t apicbase;
+    uint8_t id;
+    uint8_t arb_id;
+    uint8_t tpr;
+    uint32_t spurious_vec;
+    uint8_t log_dest;
+    uint8_t dest_mode;
+    uint32_t isr[8];  /* in service register */
+    uint32_t tmr[8];  /* trigger mode register */
+    uint32_t irr[8]; /* interrupt request register */
+    uint32_t lvt[APIC_LVT_NB];
+    uint32_t esr; /* error register */
+    uint32_t icr[2];
+
+    uint32_t divide_conf;
+    int count_shift;
+    uint32_t initial_count;
+    int64_t initial_count_load_time;
+    int64_t next_time;
+    int idx;
+    QEMUTimer *timer;
+    int64_t timer_expiry;
+    int sipi_vector;
+    int wait_for_sipi;
+};
+
+void apic_report_irq_delivered(int delivered);
+bool apic_next_timer(APICCommonState *s, int64_t current_time);
+
+#endif /* !QEMU_APIC_INTERNAL_H */
diff --git a/hw/applesmc.c b/hw/applesmc.c
index c47b592747..b06487f70d 100644
--- a/hw/applesmc.c
+++ b/hw/applesmc.c
@@ -220,22 +220,32 @@ static int applesmc_isa_init(ISADevice *dev)
     return 0;
 }
 
-static ISADeviceInfo applesmc_isa_info = {
-    .qdev.name  = "isa-applesmc",
-    .qdev.size  = sizeof(struct AppleSMCStatus),
-    .qdev.reset = qdev_applesmc_isa_reset,
-    .init       = applesmc_isa_init,
-    .qdev.props = (Property[]) {
-        DEFINE_PROP_HEX32("iobase", struct AppleSMCStatus, iobase,
-                          APPLESMC_DEFAULT_IOBASE),
-        DEFINE_PROP_STRING("osk", struct AppleSMCStatus, osk),
-        DEFINE_PROP_END_OF_LIST(),
-    },
+static Property applesmc_isa_properties[] = {
+    DEFINE_PROP_HEX32("iobase", struct AppleSMCStatus, iobase,
+                      APPLESMC_DEFAULT_IOBASE),
+    DEFINE_PROP_STRING("osk", struct AppleSMCStatus, osk),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void qdev_applesmc_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    ISADeviceClass *ic = ISA_DEVICE_CLASS(klass);
+    ic->init = applesmc_isa_init;
+    dc->reset = qdev_applesmc_isa_reset;
+    dc->props = applesmc_isa_properties;
+}
+
+static TypeInfo applesmc_isa_info = {
+    .name          = "isa-applesmc",
+    .parent        = TYPE_ISA_DEVICE,
+    .instance_size = sizeof(struct AppleSMCStatus),
+    .class_init    = qdev_applesmc_class_init,
 };
 
 static void applesmc_register_devices(void)
 {
-    isa_qdev_register(&applesmc_isa_info);
+    type_register_static(&applesmc_isa_info);
 }
 
 device_init(applesmc_register_devices)
diff --git a/hw/arm-misc.h b/hw/arm-misc.h
index 6e8ae6b02e..5e5204bbf5 100644
--- a/hw/arm-misc.h
+++ b/hw/arm-misc.h
@@ -30,12 +30,29 @@ struct arm_boot_info {
     const char *kernel_cmdline;
     const char *initrd_filename;
     target_phys_addr_t loader_start;
+    /* multicore boards that use the default secondary core boot functions
+     * need to put the address of the secondary boot code, the boot reg,
+     * and the GIC address in the next 3 values, respectively. boards that
+     * have their own boot functions can use these values as they want.
+     */
     target_phys_addr_t smp_loader_start;
     target_phys_addr_t smp_bootreg_addr;
     target_phys_addr_t smp_priv_base;
     int nb_cpus;
     int board_id;
     int (*atag_board)(const struct arm_boot_info *info, void *p);
+    /* multicore boards that use the default secondary core boot functions
+     * can ignore these two function calls. If the default functions won't
+     * work, then write_secondary_boot() should write a suitable blob of
+     * code mimicing the secondary CPU startup process used by the board's
+     * boot loader/boot ROM code, and secondary_cpu_reset_hook() should
+     * perform any necessary CPU reset handling and set the PC for thei
+     * secondary CPUs to point at this boot blob.
+     */
+    void (*write_secondary_boot)(CPUState *env,
+                                 const struct arm_boot_info *info);
+    void (*secondary_cpu_reset_hook)(CPUState *env,
+                                     const struct arm_boot_info *info);
     /* Used internally by arm_boot.c */
     int is_linux;
     target_phys_addr_t initrd_size;
diff --git a/hw/arm11mpcore.c b/hw/arm11mpcore.c
index bc0457e58b..3c0839c4b4 100644
--- a/hw/arm11mpcore.c
+++ b/hw/arm11mpcore.c
@@ -10,11 +10,6 @@
 #include "sysbus.h"
 #include "qemu-timer.h"
 
-/* ??? The MPCore TRM says the on-chip controller has 224 external IRQ lines
-   (+ 32 internal).  However my test chip only exposes/reports 32.
-   More importantly Linux falls over if more than 32 are present!  */
-#define GIC_NIRQ 64
-
 #define NCPU 4
 
 static inline int
@@ -37,6 +32,7 @@ typedef struct mpcore_priv_state {
     MemoryRegion iomem;
     MemoryRegion container;
     DeviceState *mptimer;
+    uint32_t num_irq;
 } mpcore_priv_state;
 
 /* Per-CPU private memory mapped IO.  */
@@ -132,7 +128,7 @@ static int mpcore_priv_init(SysBusDevice *dev)
 {
     mpcore_priv_state *s = FROM_SYSBUSGIC(mpcore_priv_state, dev);
 
-    gic_init(&s->gic, s->num_cpu);
+    gic_init(&s->gic, s->num_cpu, s->num_irq);
     s->mptimer = qdev_create(NULL, "arm_mptimer");
     qdev_prop_set_uint32(s->mptimer, "num-cpu", s->num_cpu);
     qdev_init_nofail(s->mptimer);
@@ -205,30 +201,61 @@ static int realview_mpcore_init(SysBusDevice *dev)
     return 0;
 }
 
-static SysBusDeviceInfo mpcore_rirq_info = {
-    .init = realview_mpcore_init,
-    .qdev.name  = "realview_mpcore",
-    .qdev.size  = sizeof(mpcore_rirq_state),
-    .qdev.props = (Property[]) {
-        DEFINE_PROP_UINT32("num-cpu", mpcore_rirq_state, num_cpu, 1),
-        DEFINE_PROP_END_OF_LIST(),
-    }
+static Property mpcore_rirq_properties[] = {
+    DEFINE_PROP_UINT32("num-cpu", mpcore_priv_state, num_cpu, 1),
+    /* The ARM11 MPCORE TRM says the on-chip controller may have
+     * anything from 0 to 224 external interrupt IRQ lines (with another
+     * 32 internal). We default to 32+32, which is the number provided by
+     * the ARM11 MPCore test chip in the Realview Versatile Express
+     * coretile. Other boards may differ and should set this property
+     * appropriately. Some Linux kernels may not boot if the hardware
+     * has more IRQ lines than the kernel expects.
+     */
+    DEFINE_PROP_UINT32("num-irq", mpcore_priv_state, num_irq, 64),
+    DEFINE_PROP_END_OF_LIST(),
 };
 
-static SysBusDeviceInfo mpcore_priv_info = {
-    .init = mpcore_priv_init,
-    .qdev.name  = "arm11mpcore_priv",
-    .qdev.size  = sizeof(mpcore_priv_state),
-    .qdev.props = (Property[]) {
-        DEFINE_PROP_UINT32("num-cpu", mpcore_priv_state, num_cpu, 1),
-        DEFINE_PROP_END_OF_LIST(),
-    }
+static void mpcore_rirq_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = realview_mpcore_init;
+    dc->props = mpcore_rirq_properties;
+}
+
+static TypeInfo mpcore_rirq_info = {
+    .name          = "realview_mpcore",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(mpcore_rirq_state),
+    .class_init    = mpcore_rirq_class_init,
+};
+
+static Property mpcore_priv_properties[] = {
+    DEFINE_PROP_UINT32("num-cpu", mpcore_priv_state, num_cpu, 1),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void mpcore_priv_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = mpcore_priv_init;
+    dc->props = mpcore_priv_properties;
+}
+
+static TypeInfo mpcore_priv_info = {
+    .name          = "arm11mpcore_priv",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(mpcore_priv_state),
+    .class_init    = mpcore_priv_class_init,
 };
 
 static void arm11mpcore_register_devices(void)
 {
-    sysbus_register_withprop(&mpcore_rirq_info);
-    sysbus_register_withprop(&mpcore_priv_info);
+    type_register_static(&mpcore_rirq_info);
+    type_register_static(&mpcore_priv_info);
 }
 
 device_init(arm11mpcore_register_devices)
diff --git a/hw/arm_boot.c b/hw/arm_boot.c
index bf509a8eb9..5f163fda02 100644
--- a/hw/arm_boot.c
+++ b/hw/arm_boot.c
@@ -20,16 +20,28 @@
 /* The worlds second smallest bootloader.  Set r0-r2, then jump to kernel.  */
 static uint32_t bootloader[] = {
   0xe3a00000, /* mov     r0, #0 */
-  0xe3a01000, /* mov     r1, #0x?? */
-  0xe3811c00, /* orr     r1, r1, #0x??00 */
-  0xe59f2000, /* ldr     r2, [pc, #0] */
-  0xe59ff000, /* ldr     pc, [pc, #0] */
+  0xe59f1004, /* ldr     r1, [pc, #4] */
+  0xe59f2004, /* ldr     r2, [pc, #4] */
+  0xe59ff004, /* ldr     pc, [pc, #4] */
+  0, /* Board ID */
   0, /* Address of kernel args.  Set by integratorcp_init.  */
   0  /* Kernel entry point.  Set by integratorcp_init.  */
 };
 
-/* Entry point for secondary CPUs.  Enable interrupt controller and
-   Issue WFI until start address is written to system controller.  */
+/* Handling for secondary CPU boot in a multicore system.
+ * Unlike the uniprocessor/primary CPU boot, this is platform
+ * dependent. The default code here is based on the secondary
+ * CPU boot protocol used on realview/vexpress boards, with
+ * some parameterisation to increase its flexibility.
+ * QEMU platform models for which this code is not appropriate
+ * should override write_secondary_boot and secondary_cpu_reset_hook
+ * instead.
+ *
+ * This code enables the interrupt controllers for the secondary
+ * CPUs and then puts all the secondary CPUs into a loop waiting
+ * for an interprocessor interrupt and polling a configurable
+ * location for the kernel secondary CPU entry point.
+ */
 static uint32_t smpboot[] = {
   0xe59f201c, /* ldr r2, privbase */
   0xe59f001c, /* ldr r0, startaddr */
@@ -44,6 +56,26 @@ static uint32_t smpboot[] = {
   0           /* bootreg: Boot register address is held here */
 };
 
+static void default_write_secondary(CPUState *env,
+                                    const struct arm_boot_info *info)
+{
+    int n;
+    smpboot[ARRAY_SIZE(smpboot) - 1] = info->smp_bootreg_addr;
+    smpboot[ARRAY_SIZE(smpboot) - 2] = info->smp_priv_base;
+    for (n = 0; n < ARRAY_SIZE(smpboot); n++) {
+        smpboot[n] = tswap32(smpboot[n]);
+    }
+    rom_add_blob_fixed("smpboot", smpboot, sizeof(smpboot),
+                       info->smp_loader_start);
+}
+
+static void default_reset_secondary(CPUState *env,
+                                    const struct arm_boot_info *info)
+{
+    stl_phys_notdirty(info->smp_bootreg_addr, 0);
+    env->regs[15] = info->smp_loader_start;
+}
+
 #define WRITE_WORD(p, value) do { \
     stl_phys_notdirty(p, value);  \
     p += 4;                       \
@@ -197,8 +229,7 @@ static void do_cpu_reset(void *opaque)
                                     info->loader_start);
                 }
             } else {
-                stl_phys_notdirty(info->smp_bootreg_addr, 0);
-                env->regs[15] = info->smp_loader_start;
+                info->secondary_cpu_reset_hook(env, info);
             }
         }
     }
@@ -220,6 +251,13 @@ void arm_load_kernel(CPUState *env, struct arm_boot_info *info)
         exit(1);
     }
 
+    if (!info->secondary_cpu_reset_hook) {
+        info->secondary_cpu_reset_hook = default_reset_secondary;
+    }
+    if (!info->write_secondary_boot) {
+        info->write_secondary_boot = default_write_secondary;
+    }
+
     if (info->nb_cpus == 0)
         info->nb_cpus = 1;
 
@@ -263,8 +301,7 @@ void arm_load_kernel(CPUState *env, struct arm_boot_info *info)
         } else {
             initrd_size = 0;
         }
-        bootloader[1] |= info->board_id & 0xff;
-        bootloader[2] |= (info->board_id >> 8) & 0xff;
+        bootloader[4] = info->board_id;
         bootloader[5] = info->loader_start + KERNEL_ARGS_ADDR;
         bootloader[6] = entry;
         for (n = 0; n < sizeof(bootloader) / 4; n++) {
@@ -273,13 +310,7 @@ void arm_load_kernel(CPUState *env, struct arm_boot_info *info)
         rom_add_blob_fixed("bootloader", bootloader, sizeof(bootloader),
                            info->loader_start);
         if (info->nb_cpus > 1) {
-            smpboot[ARRAY_SIZE(smpboot) - 1] = info->smp_bootreg_addr;
-            smpboot[ARRAY_SIZE(smpboot) - 2] = info->smp_priv_base;
-            for (n = 0; n < ARRAY_SIZE(smpboot); n++) {
-                smpboot[n] = tswap32(smpboot[n]);
-            }
-            rom_add_blob_fixed("smpboot", smpboot, sizeof(smpboot),
-                               info->smp_loader_start);
+            info->write_secondary_boot(env, info);
         }
         info->initrd_size = initrd_size;
     }
diff --git a/hw/arm_gic.c b/hw/arm_gic.c
index 0339cf59fb..cf582a5a14 100644
--- a/hw/arm_gic.c
+++ b/hw/arm_gic.c
@@ -11,6 +11,8 @@
    controller, MPCore distributed interrupt controller and ARMv7-M
    Nested Vectored Interrupt Controller.  */
 
+/* Maximum number of possible interrupts, determined by the GIC architecture */
+#define GIC_MAXIRQ 1020
 //#define DEBUG_GIC
 
 #ifdef DEBUG_GIC
@@ -86,13 +88,13 @@ typedef struct gic_state
     int enabled;
     int cpu_enabled[NCPU];
 
-    gic_irq_state irq_state[GIC_NIRQ];
+    gic_irq_state irq_state[GIC_MAXIRQ];
 #ifndef NVIC
-    int irq_target[GIC_NIRQ];
+    int irq_target[GIC_MAXIRQ];
 #endif
     int priority1[32][NCPU];
-    int priority2[GIC_NIRQ - 32];
-    int last_active[GIC_NIRQ][NCPU];
+    int priority2[GIC_MAXIRQ - 32];
+    int last_active[GIC_MAXIRQ][NCPU];
 
     int priority_mask[NCPU];
     int running_irq[NCPU];
@@ -111,6 +113,7 @@ typedef struct gic_state
     struct gic_state *backref[NCPU];
     MemoryRegion cpuiomem[NCPU+1]; /* CPU interfaces */
 #endif
+    uint32_t num_irq;
 } gic_state;
 
 /* TODO: Many places that call this routine could be optimized.  */
@@ -133,7 +136,7 @@ static void gic_update(gic_state *s)
         }
         best_prio = 0x100;
         best_irq = 1023;
-        for (irq = 0; irq < GIC_NIRQ; irq++) {
+        for (irq = 0; irq < s->num_irq; irq++) {
             if (GIC_TEST_ENABLED(irq, cm) && GIC_TEST_PENDING(irq, cm)) {
                 if (GIC_GET_PRIORITY(irq, cpu) < best_prio) {
                     best_prio = GIC_GET_PRIORITY(irq, cpu);
@@ -222,7 +225,7 @@ static void gic_complete_irq(gic_state * s, int cpu, int irq)
     int update = 0;
     int cm = 1 << cpu;
     DPRINTF("EOI %d\n", irq);
-    if (irq >= GIC_NIRQ) {
+    if (irq >= s->num_irq) {
         /* This handles two cases:
          * 1. If software writes the ID of a spurious interrupt [ie 1023]
          * to the GICC_EOIR, the GIC ignores that write.
@@ -279,7 +282,7 @@ static uint32_t gic_dist_readb(void *opaque, target_phys_addr_t offset)
         if (offset == 0)
             return s->enabled;
         if (offset == 4)
-            return ((GIC_NIRQ / 32) - 1) | ((NUM_CPU(s) - 1) << 5);
+            return ((s->num_irq / 32) - 1) | ((NUM_CPU(s) - 1) << 5);
         if (offset < 0x08)
             return 0;
         if (offset >= 0x80) {
@@ -295,7 +298,7 @@ static uint32_t gic_dist_readb(void *opaque, target_phys_addr_t offset)
         else
             irq = (offset - 0x180) * 8;
         irq += GIC_BASE_IRQ;
-        if (irq >= GIC_NIRQ)
+        if (irq >= s->num_irq)
             goto bad_reg;
         res = 0;
         for (i = 0; i < 8; i++) {
@@ -310,7 +313,7 @@ static uint32_t gic_dist_readb(void *opaque, target_phys_addr_t offset)
         else
             irq = (offset - 0x280) * 8;
         irq += GIC_BASE_IRQ;
-        if (irq >= GIC_NIRQ)
+        if (irq >= s->num_irq)
             goto bad_reg;
         res = 0;
         mask = (irq < 32) ?  cm : ALL_CPU_MASK;
@@ -322,7 +325,7 @@ static uint32_t gic_dist_readb(void *opaque, target_phys_addr_t offset)
     } else if (offset < 0x400) {
         /* Interrupt Active.  */
         irq = (offset - 0x300) * 8 + GIC_BASE_IRQ;
-        if (irq >= GIC_NIRQ)
+        if (irq >= s->num_irq)
             goto bad_reg;
         res = 0;
         mask = (irq < 32) ?  cm : ALL_CPU_MASK;
@@ -334,14 +337,14 @@ static uint32_t gic_dist_readb(void *opaque, target_phys_addr_t offset)
     } else if (offset < 0x800) {
         /* Interrupt Priority.  */
         irq = (offset - 0x400) + GIC_BASE_IRQ;
-        if (irq >= GIC_NIRQ)
+        if (irq >= s->num_irq)
             goto bad_reg;
         res = GIC_GET_PRIORITY(irq, cpu);
 #ifndef NVIC
     } else if (offset < 0xc00) {
         /* Interrupt CPU Target.  */
         irq = (offset - 0x800) + GIC_BASE_IRQ;
-        if (irq >= GIC_NIRQ)
+        if (irq >= s->num_irq)
             goto bad_reg;
         if (irq >= 29 && irq <= 31) {
             res = cm;
@@ -351,7 +354,7 @@ static uint32_t gic_dist_readb(void *opaque, target_phys_addr_t offset)
     } else if (offset < 0xf00) {
         /* Interrupt Configuration.  */
         irq = (offset - 0xc00) * 2 + GIC_BASE_IRQ;
-        if (irq >= GIC_NIRQ)
+        if (irq >= s->num_irq)
             goto bad_reg;
         res = 0;
         for (i = 0; i < 4; i++) {
@@ -426,7 +429,7 @@ static void gic_dist_writeb(void *opaque, target_phys_addr_t offset,
     } else if (offset < 0x180) {
         /* Interrupt Set Enable.  */
         irq = (offset - 0x100) * 8 + GIC_BASE_IRQ;
-        if (irq >= GIC_NIRQ)
+        if (irq >= s->num_irq)
             goto bad_reg;
         if (irq < 16)
           value = 0xff;
@@ -451,7 +454,7 @@ static void gic_dist_writeb(void *opaque, target_phys_addr_t offset,
     } else if (offset < 0x200) {
         /* Interrupt Clear Enable.  */
         irq = (offset - 0x180) * 8 + GIC_BASE_IRQ;
-        if (irq >= GIC_NIRQ)
+        if (irq >= s->num_irq)
             goto bad_reg;
         if (irq < 16)
           value = 0;
@@ -468,7 +471,7 @@ static void gic_dist_writeb(void *opaque, target_phys_addr_t offset,
     } else if (offset < 0x280) {
         /* Interrupt Set Pending.  */
         irq = (offset - 0x200) * 8 + GIC_BASE_IRQ;
-        if (irq >= GIC_NIRQ)
+        if (irq >= s->num_irq)
             goto bad_reg;
         if (irq < 16)
           irq = 0;
@@ -481,7 +484,7 @@ static void gic_dist_writeb(void *opaque, target_phys_addr_t offset,
     } else if (offset < 0x300) {
         /* Interrupt Clear Pending.  */
         irq = (offset - 0x280) * 8 + GIC_BASE_IRQ;
-        if (irq >= GIC_NIRQ)
+        if (irq >= s->num_irq)
             goto bad_reg;
         for (i = 0; i < 8; i++) {
             /* ??? This currently clears the pending bit for all CPUs, even
@@ -497,7 +500,7 @@ static void gic_dist_writeb(void *opaque, target_phys_addr_t offset,
     } else if (offset < 0x800) {
         /* Interrupt Priority.  */
         irq = (offset - 0x400) + GIC_BASE_IRQ;
-        if (irq >= GIC_NIRQ)
+        if (irq >= s->num_irq)
             goto bad_reg;
         if (irq < 32) {
             s->priority1[irq][cpu] = value;
@@ -508,7 +511,7 @@ static void gic_dist_writeb(void *opaque, target_phys_addr_t offset,
     } else if (offset < 0xc00) {
         /* Interrupt CPU Target.  */
         irq = (offset - 0x800) + GIC_BASE_IRQ;
-        if (irq >= GIC_NIRQ)
+        if (irq >= s->num_irq)
             goto bad_reg;
         if (irq < 29)
             value = 0;
@@ -518,7 +521,7 @@ static void gic_dist_writeb(void *opaque, target_phys_addr_t offset,
     } else if (offset < 0xf00) {
         /* Interrupt Configuration.  */
         irq = (offset - 0xc00) * 4 + GIC_BASE_IRQ;
-        if (irq >= GIC_NIRQ)
+        if (irq >= s->num_irq)
             goto bad_reg;
         if (irq < 32)
             value |= 0xaa;
@@ -699,7 +702,7 @@ static const MemoryRegionOps gic_cpu_ops = {
 static void gic_reset(gic_state *s)
 {
     int i;
-    memset(s->irq_state, 0, GIC_NIRQ * sizeof(gic_irq_state));
+    memset(s->irq_state, 0, GIC_MAXIRQ * sizeof(gic_irq_state));
     for (i = 0 ; i < NUM_CPU(s); i++) {
         s->priority_mask[i] = 0xf0;
         s->current_pending[i] = 1023;
@@ -735,17 +738,17 @@ static void gic_save(QEMUFile *f, void *opaque)
         qemu_put_be32(f, s->cpu_enabled[i]);
         for (j = 0; j < 32; j++)
             qemu_put_be32(f, s->priority1[j][i]);
-        for (j = 0; j < GIC_NIRQ; j++)
+        for (j = 0; j < s->num_irq; j++)
             qemu_put_be32(f, s->last_active[j][i]);
         qemu_put_be32(f, s->priority_mask[i]);
         qemu_put_be32(f, s->running_irq[i]);
         qemu_put_be32(f, s->running_priority[i]);
         qemu_put_be32(f, s->current_pending[i]);
     }
-    for (i = 0; i < GIC_NIRQ - 32; i++) {
+    for (i = 0; i < s->num_irq - 32; i++) {
         qemu_put_be32(f, s->priority2[i]);
     }
-    for (i = 0; i < GIC_NIRQ; i++) {
+    for (i = 0; i < s->num_irq; i++) {
 #ifndef NVIC
         qemu_put_be32(f, s->irq_target[i]);
 #endif
@@ -772,17 +775,17 @@ static int gic_load(QEMUFile *f, void *opaque, int version_id)
         s->cpu_enabled[i] = qemu_get_be32(f);
         for (j = 0; j < 32; j++)
             s->priority1[j][i] = qemu_get_be32(f);
-        for (j = 0; j < GIC_NIRQ; j++)
+        for (j = 0; j < s->num_irq; j++)
             s->last_active[j][i] = qemu_get_be32(f);
         s->priority_mask[i] = qemu_get_be32(f);
         s->running_irq[i] = qemu_get_be32(f);
         s->running_priority[i] = qemu_get_be32(f);
         s->current_pending[i] = qemu_get_be32(f);
     }
-    for (i = 0; i < GIC_NIRQ - 32; i++) {
+    for (i = 0; i < s->num_irq - 32; i++) {
         s->priority2[i] = qemu_get_be32(f);
     }
-    for (i = 0; i < GIC_NIRQ; i++) {
+    for (i = 0; i < s->num_irq; i++) {
 #ifndef NVIC
         s->irq_target[i] = qemu_get_be32(f);
 #endif
@@ -798,9 +801,9 @@ static int gic_load(QEMUFile *f, void *opaque, int version_id)
 }
 
 #if NCPU > 1
-static void gic_init(gic_state *s, int num_cpu)
+static void gic_init(gic_state *s, int num_cpu, int num_irq)
 #else
-static void gic_init(gic_state *s)
+static void gic_init(gic_state *s, int num_irq)
 #endif
 {
     int i;
@@ -808,7 +811,12 @@ static void gic_init(gic_state *s)
 #if NCPU > 1
     s->num_cpu = num_cpu;
 #endif
-    qdev_init_gpio_in(&s->busdev.qdev, gic_set_irq, GIC_NIRQ - 32);
+    s->num_irq = num_irq + GIC_BASE_IRQ;
+    if (s->num_irq > GIC_MAXIRQ) {
+        hw_error("requested %u interrupt lines exceeds GIC maximum %d\n",
+                 num_irq, GIC_MAXIRQ);
+    }
+    qdev_init_gpio_in(&s->busdev.qdev, gic_set_irq, s->num_irq - 32);
     for (i = 0; i < NUM_CPU(s); i++) {
         sysbus_init_irq(&s->busdev, &s->parent_irq[i]);
     }
diff --git a/hw/arm_l2x0.c b/hw/arm_l2x0.c
index 2faed39f0f..ba26abc6f4 100644
--- a/hw/arm_l2x0.c
+++ b/hw/arm_l2x0.c
@@ -160,22 +160,33 @@ static int l2x0_priv_init(SysBusDevice *dev)
     return 0;
 }
 
-static SysBusDeviceInfo l2x0_info = {
-    .init = l2x0_priv_init,
-    .qdev.name = "l2x0",
-    .qdev.size = sizeof(l2x0_state),
-    .qdev.vmsd = &vmstate_l2x0,
-    .qdev.no_user = 1,
-    .qdev.props = (Property[]) {
-        DEFINE_PROP_UINT32("type", l2x0_state, cache_type, 0x1c100100),
-        DEFINE_PROP_END_OF_LIST(),
-    },
-    .qdev.reset = l2x0_priv_reset,
+static Property l2x0_properties[] = {
+    DEFINE_PROP_UINT32("type", l2x0_state, cache_type, 0x1c100100),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void l2x0_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    k->init = l2x0_priv_init;
+    dc->vmsd = &vmstate_l2x0;
+    dc->no_user = 1;
+    dc->props = l2x0_properties;
+    dc->reset = l2x0_priv_reset;
+}
+
+static TypeInfo l2x0_info = {
+    .name = "l2x0",
+    .parent = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(l2x0_state),
+    .class_init = l2x0_class_init,
 };
 
 static void l2x0_register_device(void)
 {
-    sysbus_register_withprop(&l2x0_info);
+    type_register_static(&l2x0_info);
 }
 
 device_init(l2x0_register_device)
diff --git a/hw/arm_mptimer.c b/hw/arm_mptimer.c
index 455a0aa55a..5a02365b6f 100644
--- a/hw/arm_mptimer.c
+++ b/hw/arm_mptimer.c
@@ -311,22 +311,33 @@ static const VMStateDescription vmstate_arm_mptimer = {
     }
 };
 
-static SysBusDeviceInfo arm_mptimer_info = {
-    .init = arm_mptimer_init,
-    .qdev.name = "arm_mptimer",
-    .qdev.size = sizeof(arm_mptimer_state),
-    .qdev.vmsd = &vmstate_arm_mptimer,
-    .qdev.reset = arm_mptimer_reset,
-    .qdev.no_user = 1,
-    .qdev.props = (Property[]) {
-        DEFINE_PROP_UINT32("num-cpu", arm_mptimer_state, num_cpu, 0),
-        DEFINE_PROP_END_OF_LIST()
-    }
+static Property arm_mptimer_properties[] = {
+    DEFINE_PROP_UINT32("num-cpu", arm_mptimer_state, num_cpu, 0),
+    DEFINE_PROP_END_OF_LIST()
+};
+
+static void arm_mptimer_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass);
+
+    sbc->init = arm_mptimer_init;
+    dc->vmsd = &vmstate_arm_mptimer;
+    dc->reset = arm_mptimer_reset;
+    dc->no_user = 1;
+    dc->props = arm_mptimer_properties;
+}
+
+static TypeInfo arm_mptimer_info = {
+    .name          = "arm_mptimer",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(arm_mptimer_state),
+    .class_init    = arm_mptimer_class_init,
 };
 
 static void arm_mptimer_register_devices(void)
 {
-    sysbus_register_withprop(&arm_mptimer_info);
+    type_register_static(&arm_mptimer_info);
 }
 
 device_init(arm_mptimer_register_devices)
diff --git a/hw/arm_sysctl.c b/hw/arm_sysctl.c
index 4b88648780..9d257994c0 100644
--- a/hw/arm_sysctl.c
+++ b/hw/arm_sysctl.c
@@ -401,22 +401,33 @@ void arm_sysctl_init(uint32_t base, uint32_t sys_id, uint32_t proc_id)
     sysbus_mmio_map(sysbus_from_qdev(dev), 0, base);
 }
 
-static SysBusDeviceInfo arm_sysctl_info = {
-    .init = arm_sysctl_init1,
-    .qdev.name  = "realview_sysctl",
-    .qdev.size  = sizeof(arm_sysctl_state),
-    .qdev.vmsd = &vmstate_arm_sysctl,
-    .qdev.reset = arm_sysctl_reset,
-    .qdev.props = (Property[]) {
-        DEFINE_PROP_UINT32("sys_id", arm_sysctl_state, sys_id, 0),
-        DEFINE_PROP_UINT32("proc_id", arm_sysctl_state, proc_id, 0),
-        DEFINE_PROP_END_OF_LIST(),
-    }
+static Property arm_sysctl_properties[] = {
+    DEFINE_PROP_UINT32("sys_id", arm_sysctl_state, sys_id, 0),
+    DEFINE_PROP_UINT32("proc_id", arm_sysctl_state, proc_id, 0),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void arm_sysctl_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = arm_sysctl_init1;
+    dc->reset = arm_sysctl_reset;
+    dc->vmsd = &vmstate_arm_sysctl;
+    dc->props = arm_sysctl_properties;
+}
+
+static TypeInfo arm_sysctl_info = {
+    .name          = "realview_sysctl",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(arm_sysctl_state),
+    .class_init    = arm_sysctl_class_init,
 };
 
 static void arm_sysctl_register_devices(void)
 {
-    sysbus_register_withprop(&arm_sysctl_info);
+    type_register_static(&arm_sysctl_info);
 }
 
 device_init(arm_sysctl_register_devices)
diff --git a/hw/arm_timer.c b/hw/arm_timer.c
index 1902f1a7b9..1019d41b3e 100644
--- a/hw/arm_timer.c
+++ b/hw/arm_timer.c
@@ -273,11 +273,8 @@ static int sp804_init(SysBusDevice *dev)
 
     qi = qemu_allocate_irqs(sp804_set_irq, s, 2);
     sysbus_init_irq(dev, &s->irq);
-    /* The timers are configurable between 32kHz and 1MHz
-     * defaulting to 1MHz but overrideable as individual properties */
     s->timer[0] = arm_timer_init(s->freq0);
     s->timer[1] = arm_timer_init(s->freq1);
-
     s->timer[0]->irq = qi[0];
     s->timer[1]->irq = qi[1];
     memory_region_init_io(&s->iomem, &sp804_ops, s, "sp804", 0x1000);
@@ -286,17 +283,6 @@ static int sp804_init(SysBusDevice *dev)
     return 0;
 }
 
-static SysBusDeviceInfo sp804_info = {
-    .init = sp804_init,
-    .qdev.name = "sp804",
-    .qdev.size = sizeof(sp804_state),
-    .qdev.props = (Property[]) {
-        DEFINE_PROP_UINT32("freq0", sp804_state, freq0, 1000000),
-        DEFINE_PROP_UINT32("freq1", sp804_state, freq1, 1000000),
-        DEFINE_PROP_END_OF_LIST(),
-    }
-};
-
 /* Integrator/CP timer module.  */
 
 typedef struct {
@@ -361,10 +347,46 @@ static int icp_pit_init(SysBusDevice *dev)
     return 0;
 }
 
+static void icp_pit_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+
+    sdc->init = icp_pit_init;
+}
+
+static TypeInfo icp_pit_info = {
+    .name          = "integrator_pit",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(icp_pit_state),
+    .class_init    = icp_pit_class_init,
+};
+
+static Property sp804_properties[] = {
+    DEFINE_PROP_UINT32("freq0", sp804_state, freq0, 1000000),
+    DEFINE_PROP_UINT32("freq1", sp804_state, freq1, 1000000),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void sp804_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+    DeviceClass *k = DEVICE_CLASS(klass);
+
+    sdc->init = sp804_init;
+    k->props = sp804_properties;
+}
+
+static TypeInfo sp804_info = {
+    .name          = "sp804",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(sp804_state),
+    .class_init    = sp804_class_init,
+};
+
 static void arm_timer_register_devices(void)
 {
-    sysbus_register_dev("integrator_pit", sizeof(icp_pit_state), icp_pit_init);
-    sysbus_register_withprop(&sp804_info);
+    type_register_static(&icp_pit_info);
+    type_register_static(&sp804_info);
 }
 
 device_init(arm_timer_register_devices)
diff --git a/hw/armv7m.c b/hw/armv7m.c
index 5c7a9502c6..de3d7e0828 100644
--- a/hw/armv7m.c
+++ b/hw/armv7m.c
@@ -245,19 +245,30 @@ qemu_irq *armv7m_init(MemoryRegion *address_space_mem,
     return pic;
 }
 
-static SysBusDeviceInfo bitband_info = {
-    .init = bitband_init,
-    .qdev.name  = "ARM,bitband-memory",
-    .qdev.size  = sizeof(BitBandState),
-    .qdev.props = (Property[]) {
-        DEFINE_PROP_UINT32("base", BitBandState, base, 0),
-        DEFINE_PROP_END_OF_LIST(),
-    }
+static Property bitband_properties[] = {
+    DEFINE_PROP_UINT32("base", BitBandState, base, 0),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void bitband_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = bitband_init;
+    dc->props = bitband_properties;
+}
+
+static TypeInfo bitband_info = {
+    .name          = "ARM,bitband-memory",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(BitBandState),
+    .class_init    = bitband_class_init,
 };
 
 static void armv7m_register_devices(void)
 {
-    sysbus_register_withprop(&bitband_info);
+    type_register_static(&bitband_info);
 }
 
 device_init(armv7m_register_devices)
diff --git a/hw/armv7m_nvic.c b/hw/armv7m_nvic.c
index bf8c3c50dc..1ed0abc3e7 100644
--- a/hw/armv7m_nvic.c
+++ b/hw/armv7m_nvic.c
@@ -15,9 +15,6 @@
 #include "arm-misc.h"
 #include "exec-memory.h"
 
-/* 32 internal lines (16 used for system exceptions) plus 64 external
-   interrupt lines.  */
-#define GIC_NIRQ 96
 #define NCPU 1
 #define NVIC 1
 
@@ -41,6 +38,7 @@ typedef struct {
         int64_t tick;
         QEMUTimer *timer;
     } systick;
+    uint32_t num_irq;
 } nvic_state;
 
 /* qemu timers run at 1GHz.   We want something closer to 1MHz.  */
@@ -125,7 +123,7 @@ static uint32_t nvic_readl(void *opaque, uint32_t offset)
 
     switch (offset) {
     case 4: /* Interrupt Control Type.  */
-        return (GIC_NIRQ / 32) - 1;
+        return (s->num_irq / 32) - 1;
     case 0x10: /* SysTick Control and Status.  */
         val = s->systick.control;
         s->systick.control &= ~SYSTICK_COUNTFLAG;
@@ -169,7 +167,7 @@ static uint32_t nvic_readl(void *opaque, uint32_t offset)
         if (s->gic.current_pending[0] != 1023)
             val |= (s->gic.current_pending[0] << 12);
         /* ISRPENDING */
-        for (irq = 32; irq < GIC_NIRQ; irq++) {
+        for (irq = 32; irq < s->num_irq; irq++) {
             if (s->gic.irq_state[irq].pending) {
                 val |= (1 << 22);
                 break;
@@ -384,16 +382,44 @@ static int armv7m_nvic_init(SysBusDevice *dev)
 {
     nvic_state *s= FROM_SYSBUSGIC(nvic_state, dev);
 
-    gic_init(&s->gic);
+   /* note that for the M profile gic_init() takes the number of external
+    * interrupt lines only.
+    */
+    gic_init(&s->gic, s->num_irq);
     memory_region_add_subregion(get_system_memory(), 0xe000e000, &s->gic.iomem);
     s->systick.timer = qemu_new_timer_ns(vm_clock, systick_timer_tick, s);
-    vmstate_register(&dev->qdev, -1, &vmstate_nvic, s);
     return 0;
 }
 
+static Property armv7m_nvic_properties[] = {
+    /* The ARM v7m may have anything from 0 to 496 external interrupt
+     * IRQ lines. We default to 64. Other boards may differ and should
+     * set this property appropriately.
+     */
+    DEFINE_PROP_UINT32("num-irq", nvic_state, num_irq, 64),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void armv7m_nvic_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+
+    sdc->init = armv7m_nvic_init;
+    dc->vmsd  = &vmstate_nvic;
+    dc->props = armv7m_nvic_properties;
+}
+
+static TypeInfo armv7m_nvic_info = {
+    .name          = "armv7m_nvic",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(nvic_state),
+    .class_init    = armv7m_nvic_class_init,
+};
+
 static void armv7m_nvic_register_devices(void)
 {
-    sysbus_register_dev("armv7m_nvic", sizeof(nvic_state), armv7m_nvic_init);
+    type_register_static(&armv7m_nvic_info);
 }
 
 device_init(armv7m_nvic_register_devices)
diff --git a/hw/bitbang_i2c.c b/hw/bitbang_i2c.c
index 93fb2ed2c8..c9c11823af 100644
--- a/hw/bitbang_i2c.c
+++ b/hw/bitbang_i2c.c
@@ -221,16 +221,25 @@ static int gpio_i2c_init(SysBusDevice *dev)
     return 0;
 }
 
-static SysBusDeviceInfo gpio_i2c_info = {
-    .init = gpio_i2c_init,
-    .qdev.name  = "gpio_i2c",
-    .qdev.desc  = "Virtual GPIO to I2C bridge",
-    .qdev.size  = sizeof(GPIOI2CState),
+static void gpio_i2c_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = gpio_i2c_init;
+    dc->desc = "Virtual GPIO to I2C bridge";
+}
+
+static TypeInfo gpio_i2c_info = {
+    .name          = "gpio_i2c",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(GPIOI2CState),
+    .class_init    = gpio_i2c_class_init,
 };
 
 static void bitbang_i2c_register(void)
 {
-    sysbus_register_withprop(&gpio_i2c_info);
+    type_register_static(&gpio_i2c_info);
 }
 
 device_init(bitbang_i2c_register)
diff --git a/hw/boards.h b/hw/boards.h
index 716fd7b1a6..f6d3784cf1 100644
--- a/hw/boards.h
+++ b/hw/boards.h
@@ -22,7 +22,6 @@ typedef struct QEMUMachine {
     unsigned int no_serial:1,
         no_parallel:1,
         use_virtcon:1,
-        no_vga:1,
         no_floppy:1,
         no_cdrom:1,
         no_sdcard:1;
diff --git a/hw/bonito.c b/hw/bonito.c
index f2c78377bb..7350a4f9ec 100644
--- a/hw/bonito.c
+++ b/hw/bonito.c
@@ -766,30 +766,47 @@ PCIBus *bonito_init(qemu_irq *pic)
     return b;
 }
 
-static PCIDeviceInfo bonito_info = {
-    .qdev.name    = "Bonito",
-    .qdev.desc    = "Host bridge",
-    .qdev.size    = sizeof(PCIBonitoState),
-    .qdev.vmsd    = &vmstate_bonito,
-    .qdev.no_user = 1,
-    .init         = bonito_initfn,
-    /*Bonito North Bridge, built on FPGA, VENDOR_ID/DEVICE_ID are "undefined"*/
-    .vendor_id    = 0xdf53,
-    .device_id    = 0x00d5,
-    .revision     = 0x01,
-    .class_id     = PCI_CLASS_BRIDGE_HOST,
+static void bonito_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->init = bonito_initfn;
+    k->vendor_id = 0xdf53;
+    k->device_id = 0x00d5;
+    k->revision = 0x01;
+    k->class_id = PCI_CLASS_BRIDGE_HOST;
+    dc->desc = "Host bridge";
+    dc->no_user = 1;
+    dc->vmsd = &vmstate_bonito;
+}
+
+static TypeInfo bonito_info = {
+    .name          = "Bonito",
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(PCIBonitoState),
+    .class_init    = bonito_class_init,
 };
 
-static SysBusDeviceInfo bonito_pcihost_info = {
-    .init         = bonito_pcihost_initfn,
-    .qdev.name    = "Bonito-pcihost",
-    .qdev.size    = sizeof(BonitoState),
-    .qdev.no_user = 1,
+static void bonito_pcihost_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = bonito_pcihost_initfn;
+    dc->no_user = 1;
+}
+
+static TypeInfo bonito_pcihost_info = {
+    .name          = "Bonito-pcihost",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(BonitoState),
+    .class_init    = bonito_pcihost_class_init,
 };
 
 static void bonito_register(void)
 {
-    sysbus_register_withprop(&bonito_pcihost_info);
-    pci_qdev_register(&bonito_info);
+    type_register_static(&bonito_pcihost_info);
+    type_register_static(&bonito_info);
 }
 device_init(bonito_register);
diff --git a/hw/ccid-card-emulated.c b/hw/ccid-card-emulated.c
index 2d2ebce852..9510ed4d94 100644
--- a/hw/ccid-card-emulated.c
+++ b/hw/ccid-card-emulated.c
@@ -564,29 +564,39 @@ static int emulated_exitfn(CCIDCardState *base)
     return 0;
 }
 
-static CCIDCardInfo emulated_card_info = {
-    .qdev.name = EMULATED_DEV_NAME,
-    .qdev.desc = "emulated smartcard",
-    .qdev.size = sizeof(EmulatedState),
-    .initfn = emulated_initfn,
-    .exitfn = emulated_exitfn,
-    .get_atr = emulated_get_atr,
-    .apdu_from_guest = emulated_apdu_from_guest,
-    .qdev.unplug    = qdev_simple_unplug_cb,
-    .qdev.props     = (Property[]) {
-        DEFINE_PROP_STRING("backend", EmulatedState, backend_str),
-        DEFINE_PROP_STRING("cert1", EmulatedState, cert1),
-        DEFINE_PROP_STRING("cert2", EmulatedState, cert2),
-        DEFINE_PROP_STRING("cert3", EmulatedState, cert3),
-        DEFINE_PROP_STRING("db", EmulatedState, db),
-        DEFINE_PROP_UINT8("debug", EmulatedState, debug, 0),
-        DEFINE_PROP_END_OF_LIST(),
-    },
+static Property emulated_card_properties[] = {
+    DEFINE_PROP_STRING("backend", EmulatedState, backend_str),
+    DEFINE_PROP_STRING("cert1", EmulatedState, cert1),
+    DEFINE_PROP_STRING("cert2", EmulatedState, cert2),
+    DEFINE_PROP_STRING("cert3", EmulatedState, cert3),
+    DEFINE_PROP_STRING("db", EmulatedState, db),
+    DEFINE_PROP_UINT8("debug", EmulatedState, debug, 0),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void emulated_class_initfn(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    CCIDCardClass *cc = CCID_CARD_CLASS(klass);
+
+    cc->initfn = emulated_initfn;
+    cc->exitfn = emulated_exitfn;
+    cc->get_atr = emulated_get_atr;
+    cc->apdu_from_guest = emulated_apdu_from_guest;
+    dc->desc = "emulated smartcard";
+    dc->props = emulated_card_properties;
+}
+
+static TypeInfo emulated_card_info = {
+    .name          = EMULATED_DEV_NAME,
+    .parent        = TYPE_CCID_CARD,
+    .instance_size = sizeof(EmulatedState),
+    .class_init    = emulated_class_initfn,
 };
 
 static void ccid_card_emulated_register_devices(void)
 {
-    ccid_card_qdev_register(&emulated_card_info);
+    type_register_static(&emulated_card_info);
 }
 
 device_init(ccid_card_emulated_register_devices)
diff --git a/hw/ccid-card-passthru.c b/hw/ccid-card-passthru.c
index 9f51c6cb05..a7006ca035 100644
--- a/hw/ccid-card-passthru.c
+++ b/hw/ccid-card-passthru.c
@@ -316,25 +316,36 @@ static VMStateDescription passthru_vmstate = {
     }
 };
 
-static CCIDCardInfo passthru_card_info = {
-    .qdev.name = PASSTHRU_DEV_NAME,
-    .qdev.desc = "passthrough smartcard",
-    .qdev.size = sizeof(PassthruState),
-    .qdev.vmsd = &passthru_vmstate,
-    .initfn = passthru_initfn,
-    .exitfn = passthru_exitfn,
-    .get_atr = passthru_get_atr,
-    .apdu_from_guest = passthru_apdu_from_guest,
-    .qdev.props     = (Property[]) {
-        DEFINE_PROP_CHR("chardev", PassthruState, cs),
-        DEFINE_PROP_UINT8("debug", PassthruState, debug, 0),
-        DEFINE_PROP_END_OF_LIST(),
-    },
+static Property passthru_card_properties[] = {
+    DEFINE_PROP_CHR("chardev", PassthruState, cs),
+    DEFINE_PROP_UINT8("debug", PassthruState, debug, 0),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void passthru_class_initfn(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    CCIDCardClass *cc = CCID_CARD_CLASS(klass);
+
+    cc->initfn = passthru_initfn;
+    cc->exitfn = passthru_exitfn;
+    cc->get_atr = passthru_get_atr;
+    cc->apdu_from_guest = passthru_apdu_from_guest;
+    dc->desc = "passthrough smartcard";
+    dc->vmsd = &passthru_vmstate;
+    dc->props = passthru_card_properties;
+}
+
+static TypeInfo passthru_card_info = {
+    .name          = PASSTHRU_DEV_NAME,
+    .parent        = TYPE_CCID_CARD,
+    .instance_size = sizeof(PassthruState),
+    .class_init    = passthru_class_initfn,
 };
 
 static void ccid_card_passthru_register_devices(void)
 {
-    ccid_card_qdev_register(&passthru_card_info);
+    type_register_static(&passthru_card_info);
 }
 
 device_init(ccid_card_passthru_register_devices)
diff --git a/hw/ccid.h b/hw/ccid.h
index 9e3abe1b4c..6adc745a6d 100644
--- a/hw/ccid.h
+++ b/hw/ccid.h
@@ -15,26 +15,34 @@
 typedef struct CCIDCardState CCIDCardState;
 typedef struct CCIDCardInfo CCIDCardInfo;
 
-/*
- * state of the CCID Card device (i.e. hw/ccid-card-*.c)
- */
-struct CCIDCardState {
-    DeviceState qdev;
-    uint32_t    slot; /* For future use with multiple slot reader. */
-};
+#define TYPE_CCID_CARD "ccid-card"
+#define CCID_CARD(obj) \
+     OBJECT_CHECK(CCIDCardState, (obj), TYPE_CCID_CARD)
+#define CCID_CARD_CLASS(klass) \
+     OBJECT_CLASS_CHECK(CCIDCardClass, (klass), TYPE_CCID_CARD)
+#define CCID_CARD_GET_CLASS(obj) \
+     OBJECT_GET_CLASS(CCIDCardClass, (obj), TYPE_CCID_CARD)
 
 /*
  * callbacks to be used by the CCID device (hw/usb-ccid.c) to call
  * into the smartcard device (hw/ccid-card-*.c)
  */
-struct CCIDCardInfo {
-    DeviceInfo qdev;
+typedef struct CCIDCardClass {
+    DeviceClass parent_class;
     const uint8_t *(*get_atr)(CCIDCardState *card, uint32_t *len);
     void (*apdu_from_guest)(CCIDCardState *card,
                             const uint8_t *apdu,
                             uint32_t len);
     int (*exitfn)(CCIDCardState *card);
     int (*initfn)(CCIDCardState *card);
+} CCIDCardClass;
+
+/*
+ * state of the CCID Card device (i.e. hw/ccid-card-*.c)
+ */
+struct CCIDCardState {
+    DeviceState qdev;
+    uint32_t    slot; /* For future use with multiple slot reader. */
 };
 
 /*
@@ -46,7 +54,6 @@ void ccid_card_send_apdu_to_guest(CCIDCardState *card,
 void ccid_card_card_removed(CCIDCardState *card);
 void ccid_card_card_inserted(CCIDCardState *card);
 void ccid_card_card_error(CCIDCardState *card, uint64_t error);
-void ccid_card_qdev_register(CCIDCardInfo *card);
 
 /*
  * support guest visible insertion/removal of ccid devices based on actual
diff --git a/hw/cirrus_vga.c b/hw/cirrus_vga.c
index f7b1d3d785..a8e8ab7660 100644
--- a/hw/cirrus_vga.c
+++ b/hw/cirrus_vga.c
@@ -250,6 +250,11 @@ typedef struct PCICirrusVGAState {
     CirrusVGAState cirrus_vga;
 } PCICirrusVGAState;
 
+typedef struct ISACirrusVGAState {
+    ISADevice dev;
+    CirrusVGAState cirrus_vga;
+} ISACirrusVGAState;
+
 static uint8_t rop_to_index[256];
 
 /***************************************
@@ -613,11 +618,7 @@ static void cirrus_invalidate_region(CirrusVGAState * s, int off_begin,
     for (y = 0; y < lines; y++) {
 	off_cur = off_begin;
 	off_cur_end = (off_cur + bytesperline) & s->cirrus_addr_mask;
-	off_cur &= TARGET_PAGE_MASK;
-	while (off_cur < off_cur_end) {
-	    memory_region_set_dirty(&s->vga.vram, off_cur);
-	    off_cur += TARGET_PAGE_SIZE;
-	}
+        memory_region_set_dirty(&s->vga.vram, off_cur, off_cur_end - off_cur);
 	off_begin += off_pitch;
     }
 }
@@ -1895,8 +1896,6 @@ static void cirrus_mmio_blt_write(CirrusVGAState * s, unsigned address,
  *
  *  write mode 4/5
  *
- * assume TARGET_PAGE_SIZE >= 16
- *
  ***************************************/
 
 static void cirrus_mem_writeb_mode4and5_8bpp(CirrusVGAState * s,
@@ -1918,8 +1917,7 @@ static void cirrus_mem_writeb_mode4and5_8bpp(CirrusVGAState * s,
 	val <<= 1;
 	dst++;
     }
-    memory_region_set_dirty(&s->vga.vram, offset);
-    memory_region_set_dirty(&s->vga.vram, offset + 7);
+    memory_region_set_dirty(&s->vga.vram, offset, 8);
 }
 
 static void cirrus_mem_writeb_mode4and5_16bpp(CirrusVGAState * s,
@@ -1943,8 +1941,7 @@ static void cirrus_mem_writeb_mode4and5_16bpp(CirrusVGAState * s,
 	val <<= 1;
 	dst += 2;
     }
-    memory_region_set_dirty(&s->vga.vram, offset);
-    memory_region_set_dirty(&s->vga.vram, offset + 15);
+    memory_region_set_dirty(&s->vga.vram, offset, 16);
 }
 
 /***************************************
@@ -2034,7 +2031,8 @@ static void cirrus_vga_mem_write(void *opaque,
 		mode = s->vga.gr[0x05] & 0x7;
 		if (mode < 4 || mode > 5 || ((s->vga.gr[0x0B] & 0x4) == 0)) {
 		    *(s->vga.vram_ptr + bank_offset) = mem_value;
-		    memory_region_set_dirty(&s->vga.vram, bank_offset);
+                    memory_region_set_dirty(&s->vga.vram, bank_offset,
+                                            sizeof(mem_value));
 		} else {
 		    if ((s->vga.gr[0x0B] & 0x14) != 0x14) {
 			cirrus_mem_writeb_mode4and5_8bpp(s, mode,
@@ -2166,6 +2164,15 @@ static void cirrus_cursor_invalidate(VGACommonState *s1)
     }
 }
 
+#define DEPTH 8
+#include "cirrus_vga_template.h"
+
+#define DEPTH 16
+#include "cirrus_vga_template.h"
+
+#define DEPTH 32
+#include "cirrus_vga_template.h"
+
 static void cirrus_cursor_draw_line(VGACommonState *s1, uint8_t *d1, int scr_y)
 {
     CirrusVGAState *s = container_of(s1, CirrusVGAState, vga);
@@ -2306,7 +2313,7 @@ static void cirrus_linear_write(void *opaque, target_phys_addr_t addr,
 	mode = s->vga.gr[0x05] & 0x7;
 	if (mode < 4 || mode > 5 || ((s->vga.gr[0x0B] & 0x4) == 0)) {
 	    *(s->vga.vram_ptr + addr) = (uint8_t) val;
-	    memory_region_set_dirty(&s->vga.vram, addr);
+            memory_region_set_dirty(&s->vga.vram, addr, 1);
 	} else {
 	    if ((s->vga.gr[0x0B] & 0x14) != 0x14) {
 		cirrus_mem_writeb_mode4and5_8bpp(s, mode, addr, val);
@@ -2883,24 +2890,45 @@ static void cirrus_init_common(CirrusVGAState * s, int device_id, int is_pci,
  *
  ***************************************/
 
-DeviceState *isa_cirrus_vga_init(MemoryRegion *system_memory)
+static int vga_initfn(ISADevice *dev)
 {
-    CirrusVGAState *s;
-
-    s = g_malloc0(sizeof(CirrusVGAState));
-
-    vga_common_init(&s->vga, VGA_RAM_SIZE);
-    cirrus_init_common(s, CIRRUS_ID_CLGD5430, 0, system_memory);
-    s->vga.ds = graphic_console_init(s->vga.update, s->vga.invalidate,
-                                     s->vga.screen_dump, s->vga.text_update,
-                                     &s->vga);
-    vmstate_register(NULL, 0, &vmstate_cirrus_vga, s);
+    ISACirrusVGAState *d = DO_UPCAST(ISACirrusVGAState, dev, dev);
+    VGACommonState *s = &d->cirrus_vga.vga;
+
+    vga_common_init(s, VGA_RAM_SIZE);
+    cirrus_init_common(&d->cirrus_vga, CIRRUS_ID_CLGD5430, 0,
+                       isa_address_space(dev));
+    s->ds = graphic_console_init(s->update, s->invalidate,
+                                 s->screen_dump, s->text_update,
+                                 s);
     rom_add_vga(VGABIOS_CIRRUS_FILENAME);
     /* XXX ISA-LFB support */
     /* FIXME not qdev yet */
-    return NULL;
+    return 0;
+}
+
+static void isa_cirrus_vga_class_init(ObjectClass *klass, void *data)
+{
+    ISADeviceClass *k = ISA_DEVICE_CLASS(klass);
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    dc->vmsd  = &vmstate_cirrus_vga;
+    k->init   = vga_initfn;
 }
 
+static TypeInfo isa_cirrus_vga_info = {
+    .name          = "isa-cirrus-vga",
+    .parent        = TYPE_ISA_DEVICE,
+    .instance_size = sizeof(ISACirrusVGAState),
+    .class_init = isa_cirrus_vga_class_init,
+};
+
+static void isa_cirrus_vga_register(void)
+{
+    type_register_static(&isa_cirrus_vga_info);
+}
+device_init(isa_cirrus_vga_register)
+
 /***************************************
  *
  *  PCI bus support
@@ -2911,8 +2939,8 @@ static int pci_cirrus_vga_initfn(PCIDevice *dev)
 {
      PCICirrusVGAState *d = DO_UPCAST(PCICirrusVGAState, dev, dev);
      CirrusVGAState *s = &d->cirrus_vga;
-     PCIDeviceInfo *info = DO_UPCAST(PCIDeviceInfo, qdev, dev->qdev.info);
-     int16_t device_id = info->device_id;
+     PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(dev);
+     int16_t device_id = pc->device_id;
 
      /* setup VGA */
      vga_common_init(&s->vga, VGA_RAM_SIZE);
@@ -2946,21 +2974,30 @@ DeviceState *pci_cirrus_vga_init(PCIBus *bus)
     return &pci_create_simple(bus, -1, "cirrus-vga")->qdev;
 }
 
-static PCIDeviceInfo cirrus_vga_info = {
-    .qdev.name    = "cirrus-vga",
-    .qdev.desc    = "Cirrus CLGD 54xx VGA",
-    .qdev.size    = sizeof(PCICirrusVGAState),
-    .qdev.vmsd    = &vmstate_pci_cirrus_vga,
-    .no_hotplug   = 1,
-    .init         = pci_cirrus_vga_initfn,
-    .romfile      = VGABIOS_CIRRUS_FILENAME,
-    .vendor_id    = PCI_VENDOR_ID_CIRRUS,
-    .device_id    = CIRRUS_ID_CLGD5446,
-    .class_id     = PCI_CLASS_DISPLAY_VGA,
+static void cirrus_vga_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->no_hotplug = 1;
+    k->init = pci_cirrus_vga_initfn;
+    k->romfile = VGABIOS_CIRRUS_FILENAME;
+    k->vendor_id = PCI_VENDOR_ID_CIRRUS;
+    k->device_id = CIRRUS_ID_CLGD5446;
+    k->class_id = PCI_CLASS_DISPLAY_VGA;
+    dc->desc = "Cirrus CLGD 54xx VGA";
+    dc->vmsd = &vmstate_pci_cirrus_vga;
+}
+
+static TypeInfo cirrus_vga_info = {
+    .name          = "cirrus-vga",
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(PCICirrusVGAState),
+    .class_init    = cirrus_vga_class_init,
 };
 
 static void cirrus_vga_register(void)
 {
-    pci_qdev_register(&cirrus_vga_info);
+    type_register_static(&cirrus_vga_info);
 }
 device_init(cirrus_vga_register);
diff --git a/hw/cirrus_vga_template.h b/hw/cirrus_vga_template.h
new file mode 100644
index 0000000000..3b28280588
--- /dev/null
+++ b/hw/cirrus_vga_template.h
@@ -0,0 +1,102 @@
+/*
+ * QEMU Cirrus VGA Emulator templates
+ *
+ * Copyright (c) 2003 Fabrice Bellard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#if DEPTH == 8
+#define BPP 1
+#elif DEPTH == 15 || DEPTH == 16
+#define BPP 2
+#elif DEPTH == 32
+#define BPP 4
+#else
+#error unsupported depth
+#endif
+
+static void glue(vga_draw_cursor_line_, DEPTH)(uint8_t *d1,
+                                               const uint8_t *src1,
+                                               int poffset, int w,
+                                               unsigned int color0,
+                                               unsigned int color1,
+                                               unsigned int color_xor)
+{
+    const uint8_t *plane0, *plane1;
+    int x, b0, b1;
+    uint8_t *d;
+
+    d = d1;
+    plane0 = src1;
+    plane1 = src1 + poffset;
+    for (x = 0; x < w; x++) {
+        b0 = (plane0[x >> 3] >> (7 - (x & 7))) & 1;
+        b1 = (plane1[x >> 3] >> (7 - (x & 7))) & 1;
+#if DEPTH == 8
+        switch (b0 | (b1 << 1)) {
+        case 0:
+            break;
+        case 1:
+            d[0] ^= color_xor;
+            break;
+        case 2:
+            d[0] = color0;
+            break;
+        case 3:
+            d[0] = color1;
+            break;
+        }
+#elif DEPTH == 16
+        switch (b0 | (b1 << 1)) {
+        case 0:
+            break;
+        case 1:
+            ((uint16_t *)d)[0] ^= color_xor;
+            break;
+        case 2:
+            ((uint16_t *)d)[0] = color0;
+            break;
+        case 3:
+            ((uint16_t *)d)[0] = color1;
+            break;
+        }
+#elif DEPTH == 32
+        switch (b0 | (b1 << 1)) {
+        case 0:
+            break;
+        case 1:
+            ((uint32_t *)d)[0] ^= color_xor;
+            break;
+        case 2:
+            ((uint32_t *)d)[0] = color0;
+            break;
+        case 3:
+            ((uint32_t *)d)[0] = color1;
+            break;
+        }
+#else
+#error unsupported depth
+#endif
+        d += BPP;
+    }
+}
+
+#undef DEPTH
+#undef BPP
diff --git a/hw/container.c b/hw/container.c
deleted file mode 100644
index 9cbf3992c4..0000000000
--- a/hw/container.c
+++ /dev/null
@@ -1,20 +0,0 @@
-#include "sysbus.h"
-
-static int container_initfn(SysBusDevice *dev)
-{
-    return 0;
-}
-
-static SysBusDeviceInfo container_info = {
-    .init = container_initfn,
-    .qdev.name = "container",
-    .qdev.size = sizeof(SysBusDevice),
-    .qdev.no_user = 1,
-};
-
-static void container_init(void)
-{
-    sysbus_register_withprop(&container_info);
-}
-
-device_init(container_init);
diff --git a/hw/cs4231.c b/hw/cs4231.c
index 2dfb708fe7..c0badbff5c 100644
--- a/hw/cs4231.c
+++ b/hw/cs4231.c
@@ -151,20 +151,31 @@ static int cs4231_init1(SysBusDevice *dev)
     return 0;
 }
 
-static SysBusDeviceInfo cs4231_info = {
-    .init = cs4231_init1,
-    .qdev.name  = "SUNW,CS4231",
-    .qdev.size  = sizeof(CSState),
-    .qdev.vmsd  = &vmstate_cs4231,
-    .qdev.reset = cs_reset,
-    .qdev.props = (Property[]) {
-        {.name = NULL}
-    }
+static Property cs4231_properties[] = {
+    {.name = NULL},
+};
+
+static void cs4231_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = cs4231_init1;
+    dc->reset = cs_reset;
+    dc->vmsd = &vmstate_cs4231;
+    dc->props = cs4231_properties;
+}
+
+static TypeInfo cs4231_info = {
+    .name          = "SUNW,CS4231",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(CSState),
+    .class_init    = cs4231_class_init,
 };
 
 static void cs4231_register_devices(void)
 {
-    sysbus_register_withprop(&cs4231_info);
+    type_register_static(&cs4231_info);
 }
 
 device_init(cs4231_register_devices)
diff --git a/hw/cs4231a.c b/hw/cs4231a.c
index dc77a3aa15..ad04ad667c 100644
--- a/hw/cs4231a.c
+++ b/hw/cs4231a.c
@@ -622,13 +622,13 @@ static const VMStateDescription vmstate_cs4231a = {
     .pre_load = cs4231a_pre_load,
     .post_load = cs4231a_post_load,
     .fields      = (VMStateField []) {
-        VMSTATE_UINT32_ARRAY(regs, CSState, CS_REGS),
-        VMSTATE_BUFFER(dregs, CSState),
-        VMSTATE_INT32(dma_running, CSState),
-        VMSTATE_INT32(audio_free, CSState),
-        VMSTATE_INT32(transferred, CSState),
-        VMSTATE_INT32(aci_counter, CSState),
-        VMSTATE_END_OF_LIST()
+        VMSTATE_UINT32_ARRAY (regs, CSState, CS_REGS),
+        VMSTATE_BUFFER (dregs, CSState),
+        VMSTATE_INT32 (dma_running, CSState),
+        VMSTATE_INT32 (audio_free, CSState),
+        VMSTATE_INT32 (transferred, CSState),
+        VMSTATE_INT32 (aci_counter, CSState),
+        VMSTATE_END_OF_LIST ()
     }
 };
 
@@ -665,22 +665,32 @@ int cs4231a_init (ISABus *bus)
     return 0;
 }
 
-static ISADeviceInfo cs4231a_info = {
-    .qdev.name     = "cs4231a",
-    .qdev.desc     = "Crystal Semiconductor CS4231A",
-    .qdev.size     = sizeof (CSState),
-    .qdev.vmsd     = &vmstate_cs4231a,
-    .init          = cs4231a_initfn,
-    .qdev.props    = (Property[]) {
-        DEFINE_PROP_HEX32  ("iobase",  CSState, port, 0x534),
-        DEFINE_PROP_UINT32 ("irq",     CSState, irq,  9),
-        DEFINE_PROP_UINT32 ("dma",     CSState, dma,  3),
-        DEFINE_PROP_END_OF_LIST (),
-    },
+static Property cs4231a_properties[] = {
+    DEFINE_PROP_HEX32  ("iobase",  CSState, port, 0x534),
+    DEFINE_PROP_UINT32 ("irq",     CSState, irq,  9),
+    DEFINE_PROP_UINT32 ("dma",     CSState, dma,  3),
+    DEFINE_PROP_END_OF_LIST (),
+};
+
+static void cs4231a_class_initfn (ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS (klass);
+    ISADeviceClass *ic = ISA_DEVICE_CLASS (klass);
+    ic->init = cs4231a_initfn;
+    dc->desc = "Crystal Semiconductor CS4231A";
+    dc->vmsd = &vmstate_cs4231a;
+    dc->props = cs4231a_properties;
+}
+
+static TypeInfo cs4231a_info = {
+    .name          = "cs4231a",
+    .parent        = TYPE_ISA_DEVICE,
+    .instance_size = sizeof (CSState),
+    .class_init    = cs4231a_class_initfn,
 };
 
 static void cs4231a_register (void)
 {
-    isa_qdev_register (&cs4231a_info);
+    type_register_static (&cs4231a_info);
 }
 device_init (cs4231a_register)
diff --git a/hw/debugcon.c b/hw/debugcon.c
index c9ee6d90b0..3903b2605d 100644
--- a/hw/debugcon.c
+++ b/hw/debugcon.c
@@ -87,21 +87,31 @@ static int debugcon_isa_initfn(ISADevice *dev)
     return 0;
 }
 
-static ISADeviceInfo debugcon_isa_info = {
-    .qdev.name  = "isa-debugcon",
-    .qdev.size  = sizeof(ISADebugconState),
-    .init       = debugcon_isa_initfn,
-    .qdev.props = (Property[]) {
-        DEFINE_PROP_HEX32("iobase", ISADebugconState, iobase, 0xe9),
-        DEFINE_PROP_CHR("chardev",  ISADebugconState, state.chr),
-        DEFINE_PROP_HEX32("readback", ISADebugconState, state.readback, 0xe9),
-        DEFINE_PROP_END_OF_LIST(),
-    },
+static Property debugcon_isa_properties[] = {
+    DEFINE_PROP_HEX32("iobase", ISADebugconState, iobase, 0xe9),
+    DEFINE_PROP_CHR("chardev",  ISADebugconState, state.chr),
+    DEFINE_PROP_HEX32("readback", ISADebugconState, state.readback, 0xe9),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void debugcon_isa_class_initfn(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    ISADeviceClass *ic = ISA_DEVICE_CLASS(klass);
+    ic->init = debugcon_isa_initfn;
+    dc->props = debugcon_isa_properties;
+}
+
+static TypeInfo debugcon_isa_info = {
+    .name          = "isa-debugcon",
+    .parent        = TYPE_ISA_DEVICE,
+    .instance_size = sizeof(ISADebugconState),
+    .class_init    = debugcon_isa_class_initfn,
 };
 
 static void debugcon_register_devices(void)
 {
-    isa_qdev_register(&debugcon_isa_info);
+    type_register_static(&debugcon_isa_info);
 }
 
 device_init(debugcon_register_devices)
diff --git a/hw/dec_pci.c b/hw/dec_pci.c
index 08d4e06697..a40fbcf3e5 100644
--- a/hw/dec_pci.c
+++ b/hw/dec_pci.c
@@ -50,18 +50,27 @@ static int dec_map_irq(PCIDevice *pci_dev, int irq_num)
     return irq_num;
 }
 
-static PCIDeviceInfo dec_21154_pci_bridge_info = {
-    .qdev.name = "dec-21154-p2p-bridge",
-    .qdev.desc = "DEC 21154 PCI-PCI bridge",
-    .qdev.size = sizeof(PCIBridge),
-    .qdev.vmsd = &vmstate_pci_device,
-    .qdev.reset = pci_bridge_reset,
-    .init = pci_bridge_initfn,
-    .exit = pci_bridge_exitfn,
-    .vendor_id = PCI_VENDOR_ID_DEC,
-    .device_id = PCI_DEVICE_ID_DEC_21154,
-    .config_write = pci_bridge_write_config,
-    .is_bridge = 1,
+static void dec_21154_pci_bridge_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->init = pci_bridge_initfn;
+    k->exit = pci_bridge_exitfn;
+    k->vendor_id = PCI_VENDOR_ID_DEC;
+    k->device_id = PCI_DEVICE_ID_DEC_21154;
+    k->config_write = pci_bridge_write_config;
+    k->is_bridge = 1;
+    dc->desc = "DEC 21154 PCI-PCI bridge";
+    dc->reset = pci_bridge_reset;
+    dc->vmsd = &vmstate_pci_device;
+}
+
+static TypeInfo dec_21154_pci_bridge_info = {
+    .name          = "dec-21154-p2p-bridge",
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(PCIBridge),
+    .class_init    = dec_21154_pci_bridge_class_init,
 };
 
 PCIBus *pci_dec_21154_init(PCIBus *parent_bus, int devfn)
@@ -77,7 +86,7 @@ PCIBus *pci_dec_21154_init(PCIBus *parent_bus, int devfn)
     return pci_bridge_get_sec_bus(br);
 }
 
-static int pci_dec_21154_init_device(SysBusDevice *dev)
+static int pci_dec_21154_device_init(SysBusDevice *dev)
 {
     DECState *s;
 
@@ -98,23 +107,44 @@ static int dec_21154_pci_host_init(PCIDevice *d)
     return 0;
 }
 
-static PCIDeviceInfo dec_21154_pci_host_info = {
-    .qdev.name = "dec-21154",
-    .qdev.size = sizeof(PCIDevice),
-    .init      = dec_21154_pci_host_init,
-    .vendor_id = PCI_VENDOR_ID_DEC,
-    .device_id = PCI_DEVICE_ID_DEC_21154,
-    .revision = 0x02,
-    .class_id = PCI_CLASS_BRIDGE_PCI,
-    .is_bridge  = 1,
+static void dec_21154_pci_host_class_init(ObjectClass *klass, void *data)
+{
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->init = dec_21154_pci_host_init;
+    k->vendor_id = PCI_VENDOR_ID_DEC;
+    k->device_id = PCI_DEVICE_ID_DEC_21154;
+    k->revision = 0x02;
+    k->class_id = PCI_CLASS_BRIDGE_PCI;
+    k->is_bridge = 1;
+}
+
+static TypeInfo dec_21154_pci_host_info = {
+    .name          = "dec-21154",
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(PCIDevice),
+    .class_init    = dec_21154_pci_host_class_init,
+};
+
+static void pci_dec_21154_device_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+
+    sdc->init = pci_dec_21154_device_init;
+}
+
+static TypeInfo pci_dec_21154_device_info = {
+    .name          = "dec-21154-sysbus",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(DECState),
+    .class_init    = pci_dec_21154_device_class_init,
 };
 
 static void dec_register_devices(void)
 {
-    sysbus_register_dev("dec-21154", sizeof(DECState),
-                        pci_dec_21154_init_device);
-    pci_qdev_register(&dec_21154_pci_host_info);
-    pci_qdev_register(&dec_21154_pci_bridge_info);
+    type_register_static(&pci_dec_21154_device_info);
+    type_register_static(&dec_21154_pci_host_info);
+    type_register_static(&dec_21154_pci_bridge_info);
 }
 
 device_init(dec_register_devices)
diff --git a/hw/ds1225y.c b/hw/ds1225y.c
index 7aa0832266..539bcebae0 100644
--- a/hw/ds1225y.c
+++ b/hw/ds1225y.c
@@ -134,21 +134,32 @@ static int nvram_sysbus_initfn(SysBusDevice *dev)
     return 0;
 }
 
-static SysBusDeviceInfo nvram_sysbus_info = {
-    .qdev.name  = "ds1225y",
-    .qdev.size  = sizeof(SysBusNvRamState),
-    .qdev.vmsd  = &vmstate_nvram,
-    .init       = nvram_sysbus_initfn,
-    .qdev.props = (Property[]) {
-        DEFINE_PROP_UINT32("size", SysBusNvRamState, nvram.chip_size, 0x2000),
-        DEFINE_PROP_STRING("filename", SysBusNvRamState, nvram.filename),
-        DEFINE_PROP_END_OF_LIST(),
-    },
+static Property nvram_sysbus_properties[] = {
+    DEFINE_PROP_UINT32("size", SysBusNvRamState, nvram.chip_size, 0x2000),
+    DEFINE_PROP_STRING("filename", SysBusNvRamState, nvram.filename),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void nvram_sysbus_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = nvram_sysbus_initfn;
+    dc->vmsd = &vmstate_nvram;
+    dc->props = nvram_sysbus_properties;
+}
+
+static TypeInfo nvram_sysbus_info = {
+    .name          = "ds1225y",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(SysBusNvRamState),
+    .class_init    = nvram_sysbus_class_init,
 };
 
 static void nvram_register(void)
 {
-    sysbus_register_withprop(&nvram_sysbus_info);
+    type_register_static(&nvram_sysbus_info);
 }
 
 device_init(nvram_register)
diff --git a/hw/ds1338.c b/hw/ds1338.c
index f754cb7cea..b137e13379 100644
--- a/hw/ds1338.c
+++ b/hw/ds1338.c
@@ -13,7 +13,7 @@
 #include "i2c.h"
 
 typedef struct {
-    i2c_slave i2c;
+    I2CSlave i2c;
     time_t offset;
     struct tm now;
     uint8_t nvram[56];
@@ -21,7 +21,7 @@ typedef struct {
     int addr_byte;
 } DS1338State;
 
-static void ds1338_event(i2c_slave *i2c, enum i2c_event event)
+static void ds1338_event(I2CSlave *i2c, enum i2c_event event)
 {
     DS1338State *s = FROM_I2C_SLAVE(DS1338State, i2c);
 
@@ -51,7 +51,7 @@ static void ds1338_event(i2c_slave *i2c, enum i2c_event event)
     }
 }
 
-static int ds1338_recv(i2c_slave *i2c)
+static int ds1338_recv(I2CSlave *i2c)
 {
     DS1338State *s = FROM_I2C_SLAVE(DS1338State, i2c);
     uint8_t res;
@@ -61,7 +61,7 @@ static int ds1338_recv(i2c_slave *i2c)
     return res;
 }
 
-static int ds1338_send(i2c_slave *i2c, uint8_t data)
+static int ds1338_send(I2CSlave *i2c, uint8_t data)
 {
     DS1338State *s = FROM_I2C_SLAVE(DS1338State, i2c);
     if (s->addr_byte) {
@@ -113,23 +113,31 @@ static int ds1338_send(i2c_slave *i2c, uint8_t data)
     return 0;
 }
 
-static int ds1338_init(i2c_slave *i2c)
+static int ds1338_init(I2CSlave *i2c)
 {
     return 0;
 }
 
-static I2CSlaveInfo ds1338_info = {
-    .qdev.name = "ds1338",
-    .qdev.size = sizeof(DS1338State),
-    .init = ds1338_init,
-    .event = ds1338_event,
-    .recv = ds1338_recv,
-    .send = ds1338_send,
+static void ds1338_class_init(ObjectClass *klass, void *data)
+{
+    I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
+
+    k->init = ds1338_init;
+    k->event = ds1338_event;
+    k->recv = ds1338_recv;
+    k->send = ds1338_send;
+}
+
+static TypeInfo ds1338_info = {
+    .name          = "ds1338",
+    .parent        = TYPE_I2C_SLAVE,
+    .instance_size = sizeof(DS1338State),
+    .class_init    = ds1338_class_init,
 };
 
 static void ds1338_register_devices(void)
 {
-    i2c_register_slave(&ds1338_info);
+    type_register_static(&ds1338_info);
 }
 
 device_init(ds1338_register_devices)
diff --git a/hw/e1000.c b/hw/e1000.c
index a29c944df4..751f79d5ff 100644
--- a/hw/e1000.c
+++ b/hw/e1000.c
@@ -466,6 +466,8 @@ process_tx_desc(E1000State *s, struct e1000_tx_desc *dp)
             bytes = split_size;
             if (tp->size + bytes > msh)
                 bytes = msh - tp->size;
+
+            bytes = MIN(sizeof(tp->data) - tp->size, bytes);
             pci_dma_read(&s->dev, addr, tp->data + tp->size, bytes);
             if ((sz = tp->size + bytes) >= hdr && tp->size < hdr)
                 memmove(tp->header, tp->data, hdr);
@@ -481,6 +483,7 @@ process_tx_desc(E1000State *s, struct e1000_tx_desc *dp)
         // context descriptor TSE is not set, while data descriptor TSE is set
         DBGOUT(TXERR, "TCP segmentaion Error\n");
     } else {
+        split_size = MIN(sizeof(tp->data) - tp->size, split_size);
         pci_dma_read(&s->dev, addr, tp->data + tp->size, split_size);
         tp->size += split_size;
     }
@@ -1130,6 +1133,11 @@ static void e1000_reset(void *opaque)
     memmove(d->mac_reg, mac_reg_init, sizeof mac_reg_init);
     d->rxbuf_min_shift = 1;
     memset(&d->tx, 0, sizeof d->tx);
+
+    if (d->nic->nc.link_down) {
+        d->mac_reg[STATUS] &= ~E1000_STATUS_LU;
+        d->phy_reg[PHY_STATUS] &= ~MII_SR_LINK_STATUS;
+    }
 }
 
 static NetClientInfo net_e1000_info = {
@@ -1174,7 +1182,7 @@ static int pci_e1000_init(PCIDevice *pci_dev)
     d->eeprom_data[EEPROM_CHECKSUM_REG] = checksum;
 
     d->nic = qemu_new_nic(&net_e1000_info, &d->conf,
-                          d->dev.qdev.info->name, d->dev.qdev.id, d);
+                          object_get_typename(OBJECT(d)), d->dev.qdev.id, d);
 
     qemu_format_nic_info_str(&d->nic->nc, macaddr);
 
@@ -1189,28 +1197,39 @@ static void qdev_e1000_reset(DeviceState *dev)
     e1000_reset(d);
 }
 
-static PCIDeviceInfo e1000_info = {
-    .qdev.name  = "e1000",
-    .qdev.desc  = "Intel Gigabit Ethernet",
-    .qdev.size  = sizeof(E1000State),
-    .qdev.reset = qdev_e1000_reset,
-    .qdev.vmsd  = &vmstate_e1000,
-    .init       = pci_e1000_init,
-    .exit       = pci_e1000_uninit,
-    .romfile    = "pxe-e1000.rom",
-    .vendor_id  = PCI_VENDOR_ID_INTEL,
-    .device_id  = E1000_DEVID,
-    .revision   = 0x03,
-    .class_id   = PCI_CLASS_NETWORK_ETHERNET,
-    .qdev.props = (Property[]) {
-        DEFINE_NIC_PROPERTIES(E1000State, conf),
-        DEFINE_PROP_END_OF_LIST(),
-    }
+static Property e1000_properties[] = {
+    DEFINE_NIC_PROPERTIES(E1000State, conf),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void e1000_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->init = pci_e1000_init;
+    k->exit = pci_e1000_uninit;
+    k->romfile = "pxe-e1000.rom";
+    k->vendor_id = PCI_VENDOR_ID_INTEL;
+    k->device_id = E1000_DEVID;
+    k->revision = 0x03;
+    k->class_id = PCI_CLASS_NETWORK_ETHERNET;
+    dc->desc = "Intel Gigabit Ethernet";
+    dc->reset = qdev_e1000_reset;
+    dc->vmsd = &vmstate_e1000;
+    dc->props = e1000_properties;
+}
+
+static TypeInfo e1000_info = {
+    .name          = "e1000",
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(E1000State),
+    .class_init    = e1000_class_init,
 };
 
 static void e1000_register_devices(void)
 {
-    pci_qdev_register(&e1000_info);
+    type_register_static(&e1000_info);
 }
 
 device_init(e1000_register_devices)
diff --git a/hw/eccmemctl.c b/hw/eccmemctl.c
index 774346543a..1cf2090c1f 100644
--- a/hw/eccmemctl.c
+++ b/hw/eccmemctl.c
@@ -308,22 +308,33 @@ static int ecc_init1(SysBusDevice *dev)
     return 0;
 }
 
-static SysBusDeviceInfo ecc_info = {
-    .init = ecc_init1,
-    .qdev.name  = "eccmemctl",
-    .qdev.size  = sizeof(ECCState),
-    .qdev.vmsd  = &vmstate_ecc,
-    .qdev.reset = ecc_reset,
-    .qdev.props = (Property[]) {
-        DEFINE_PROP_HEX32("version", ECCState, version, -1),
-        DEFINE_PROP_END_OF_LIST(),
-    }
+static Property ecc_properties[] = {
+    DEFINE_PROP_HEX32("version", ECCState, version, -1),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void ecc_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = ecc_init1;
+    dc->reset = ecc_reset;
+    dc->vmsd = &vmstate_ecc;
+    dc->props = ecc_properties;
+}
+
+static TypeInfo ecc_info = {
+    .name          = "eccmemctl",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(ECCState),
+    .class_init    = ecc_class_init,
 };
 
 
 static void ecc_register_devices(void)
 {
-    sysbus_register_withprop(&ecc_info);
+    type_register_static(&ecc_info);
 }
 
 device_init(ecc_register_devices)
diff --git a/hw/eepro100.c b/hw/eepro100.c
index 6a162f607f..843610c933 100644
--- a/hw/eepro100.c
+++ b/hw/eepro100.c
@@ -128,7 +128,13 @@
 #define DRVR_INT        0x0200  /* Driver generated interrupt. */
 
 typedef struct {
-    PCIDeviceInfo pci;
+    const char *name;
+    const char *desc;
+    uint16_t device_id;
+    uint8_t revision;
+    uint16_t subsystem_vendor_id;
+    uint16_t subsystem_id;
+
     uint32_t device;
     uint8_t stats_size;
     bool has_extended_tcb_support;
@@ -318,6 +324,8 @@ static const uint16_t eepro100_mdi_mask[] = {
 
 #define POLYNOMIAL 0x04c11db6
 
+static E100PCIDeviceInfo *eepro100_get_class(EEPRO100State *s);
+
 /* From FreeBSD */
 /* XXX: optimize */
 static unsigned compute_mcast_idx(const uint8_t * ep)
@@ -487,8 +495,9 @@ static void eepro100_fcp_interrupt(EEPRO100State * s)
 }
 #endif
 
-static void e100_pci_reset(EEPRO100State * s, E100PCIDeviceInfo *e100_device)
+static void e100_pci_reset(EEPRO100State * s)
 {
+    E100PCIDeviceInfo *info = eepro100_get_class(s);
     uint32_t device = s->device;
     uint8_t *pci_conf = s->dev.config;
 
@@ -508,8 +517,8 @@ static void e100_pci_reset(EEPRO100State * s, E100PCIDeviceInfo *e100_device)
     /* Maximum Latency */
     pci_set_byte(pci_conf + PCI_MAX_LAT, 0x18);
 
-    s->stats_size = e100_device->stats_size;
-    s->has_extended_tcb_support = e100_device->has_extended_tcb_support;
+    s->stats_size = info->stats_size;
+    s->has_extended_tcb_support = info->has_extended_tcb_support;
 
     switch (device) {
     case i82550:
@@ -558,7 +567,7 @@ static void e100_pci_reset(EEPRO100State * s, E100PCIDeviceInfo *e100_device)
     }
     assert(s->stats_size > 0 && s->stats_size <= sizeof(s->statistics));
 
-    if (e100_device->power_management) {
+    if (info->power_management) {
         /* Power Management Capabilities */
         int cfg_offset = 0xdc;
         int r = pci_add_capability(&s->dev, PCI_CAP_ID_PM,
@@ -1847,14 +1856,13 @@ static NetClientInfo net_eepro100_info = {
 static int e100_nic_init(PCIDevice *pci_dev)
 {
     EEPRO100State *s = DO_UPCAST(EEPRO100State, dev, pci_dev);
-    E100PCIDeviceInfo *e100_device = DO_UPCAST(E100PCIDeviceInfo, pci.qdev,
-                                               pci_dev->qdev.info);
+    E100PCIDeviceInfo *info = eepro100_get_class(s);
 
     TRACE(OTHER, logout("\n"));
 
-    s->device = e100_device->device;
+    s->device = info->device;
 
-    e100_pci_reset(s, e100_device);
+    e100_pci_reset(s);
 
     /* Add 64 * 2 EEPROM. i82557 and i82558 support a 64 word EEPROM,
      * i82559 and later support 64 or 256 word EEPROM. */
@@ -1878,7 +1886,7 @@ static int e100_nic_init(PCIDevice *pci_dev)
     nic_reset(s);
 
     s->nic = qemu_new_nic(&net_eepro100_info, &s->conf,
-                          pci_dev->qdev.info->name, pci_dev->qdev.id, s);
+                          object_get_typename(OBJECT(pci_dev)), pci_dev->qdev.id, s);
 
     qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a);
     TRACE(OTHER, logout("%s\n", s->nic->nc.info_str));
@@ -1897,156 +1905,203 @@ static int e100_nic_init(PCIDevice *pci_dev)
 
 static E100PCIDeviceInfo e100_devices[] = {
     {
-        .pci.qdev.name = "i82550",
-        .pci.qdev.desc = "Intel i82550 Ethernet",
+        .name = "i82550",
+        .desc = "Intel i82550 Ethernet",
         .device = i82550,
         /* TODO: check device id. */
-        .pci.device_id = PCI_DEVICE_ID_INTEL_82551IT,
+        .device_id = PCI_DEVICE_ID_INTEL_82551IT,
         /* Revision ID: 0x0c, 0x0d, 0x0e. */
-        .pci.revision = 0x0e,
+        .revision = 0x0e,
         /* TODO: check size of statistical counters. */
         .stats_size = 80,
         /* TODO: check extended tcb support. */
         .has_extended_tcb_support = true,
         .power_management = true,
     },{
-        .pci.qdev.name = "i82551",
-        .pci.qdev.desc = "Intel i82551 Ethernet",
+        .name = "i82551",
+        .desc = "Intel i82551 Ethernet",
         .device = i82551,
-        .pci.device_id = PCI_DEVICE_ID_INTEL_82551IT,
+        .device_id = PCI_DEVICE_ID_INTEL_82551IT,
         /* Revision ID: 0x0f, 0x10. */
-        .pci.revision = 0x0f,
+        .revision = 0x0f,
         /* TODO: check size of statistical counters. */
         .stats_size = 80,
         .has_extended_tcb_support = true,
         .power_management = true,
     },{
-        .pci.qdev.name = "i82557a",
-        .pci.qdev.desc = "Intel i82557A Ethernet",
+        .name = "i82557a",
+        .desc = "Intel i82557A Ethernet",
         .device = i82557A,
-        .pci.device_id = PCI_DEVICE_ID_INTEL_82557,
-        .pci.revision = 0x01,
+        .device_id = PCI_DEVICE_ID_INTEL_82557,
+        .revision = 0x01,
         .power_management = false,
     },{
-        .pci.qdev.name = "i82557b",
-        .pci.qdev.desc = "Intel i82557B Ethernet",
+        .name = "i82557b",
+        .desc = "Intel i82557B Ethernet",
         .device = i82557B,
-        .pci.device_id = PCI_DEVICE_ID_INTEL_82557,
-        .pci.revision = 0x02,
+        .device_id = PCI_DEVICE_ID_INTEL_82557,
+        .revision = 0x02,
         .power_management = false,
     },{
-        .pci.qdev.name = "i82557c",
-        .pci.qdev.desc = "Intel i82557C Ethernet",
+        .name = "i82557c",
+        .desc = "Intel i82557C Ethernet",
         .device = i82557C,
-        .pci.device_id = PCI_DEVICE_ID_INTEL_82557,
-        .pci.revision = 0x03,
+        .device_id = PCI_DEVICE_ID_INTEL_82557,
+        .revision = 0x03,
         .power_management = false,
     },{
-        .pci.qdev.name = "i82558a",
-        .pci.qdev.desc = "Intel i82558A Ethernet",
+        .name = "i82558a",
+        .desc = "Intel i82558A Ethernet",
         .device = i82558A,
-        .pci.device_id = PCI_DEVICE_ID_INTEL_82557,
-        .pci.revision = 0x04,
+        .device_id = PCI_DEVICE_ID_INTEL_82557,
+        .revision = 0x04,
         .stats_size = 76,
         .has_extended_tcb_support = true,
         .power_management = true,
     },{
-        .pci.qdev.name = "i82558b",
-        .pci.qdev.desc = "Intel i82558B Ethernet",
+        .name = "i82558b",
+        .desc = "Intel i82558B Ethernet",
         .device = i82558B,
-        .pci.device_id = PCI_DEVICE_ID_INTEL_82557,
-        .pci.revision = 0x05,
+        .device_id = PCI_DEVICE_ID_INTEL_82557,
+        .revision = 0x05,
         .stats_size = 76,
         .has_extended_tcb_support = true,
         .power_management = true,
     },{
-        .pci.qdev.name = "i82559a",
-        .pci.qdev.desc = "Intel i82559A Ethernet",
+        .name = "i82559a",
+        .desc = "Intel i82559A Ethernet",
         .device = i82559A,
-        .pci.device_id = PCI_DEVICE_ID_INTEL_82557,
-        .pci.revision = 0x06,
+        .device_id = PCI_DEVICE_ID_INTEL_82557,
+        .revision = 0x06,
         .stats_size = 80,
         .has_extended_tcb_support = true,
         .power_management = true,
     },{
-        .pci.qdev.name = "i82559b",
-        .pci.qdev.desc = "Intel i82559B Ethernet",
+        .name = "i82559b",
+        .desc = "Intel i82559B Ethernet",
         .device = i82559B,
-        .pci.device_id = PCI_DEVICE_ID_INTEL_82557,
-        .pci.revision = 0x07,
+        .device_id = PCI_DEVICE_ID_INTEL_82557,
+        .revision = 0x07,
         .stats_size = 80,
         .has_extended_tcb_support = true,
         .power_management = true,
     },{
-        .pci.qdev.name = "i82559c",
-        .pci.qdev.desc = "Intel i82559C Ethernet",
+        .name = "i82559c",
+        .desc = "Intel i82559C Ethernet",
         .device = i82559C,
-        .pci.device_id = PCI_DEVICE_ID_INTEL_82557,
+        .device_id = PCI_DEVICE_ID_INTEL_82557,
 #if 0
-        .pci.revision = 0x08,
+        .revision = 0x08,
 #endif
         /* TODO: Windows wants revision id 0x0c. */
-        .pci.revision = 0x0c,
+        .revision = 0x0c,
 #if EEPROM_SIZE > 0
-        .pci.subsystem_vendor_id = PCI_VENDOR_ID_INTEL,
-        .pci.subsystem_id = 0x0040,
+        .subsystem_vendor_id = PCI_VENDOR_ID_INTEL,
+        .subsystem_id = 0x0040,
 #endif
         .stats_size = 80,
         .has_extended_tcb_support = true,
         .power_management = true,
     },{
-        .pci.qdev.name = "i82559er",
-        .pci.qdev.desc = "Intel i82559ER Ethernet",
+        .name = "i82559er",
+        .desc = "Intel i82559ER Ethernet",
         .device = i82559ER,
-        .pci.device_id = PCI_DEVICE_ID_INTEL_82551IT,
-        .pci.revision = 0x09,
+        .device_id = PCI_DEVICE_ID_INTEL_82551IT,
+        .revision = 0x09,
         .stats_size = 80,
         .has_extended_tcb_support = true,
         .power_management = true,
     },{
-        .pci.qdev.name = "i82562",
-        .pci.qdev.desc = "Intel i82562 Ethernet",
+        .name = "i82562",
+        .desc = "Intel i82562 Ethernet",
         .device = i82562,
         /* TODO: check device id. */
-        .pci.device_id = PCI_DEVICE_ID_INTEL_82551IT,
+        .device_id = PCI_DEVICE_ID_INTEL_82551IT,
         /* TODO: wrong revision id. */
-        .pci.revision = 0x0e,
+        .revision = 0x0e,
         .stats_size = 80,
         .has_extended_tcb_support = true,
         .power_management = true,
     },{
         /* Toshiba Tecra 8200. */
-        .pci.qdev.name = "i82801",
-        .pci.qdev.desc = "Intel i82801 Ethernet",
+        .name = "i82801",
+        .desc = "Intel i82801 Ethernet",
         .device = i82801,
-        .pci.device_id = 0x2449,
-        .pci.revision = 0x03,
+        .device_id = 0x2449,
+        .revision = 0x03,
         .stats_size = 80,
         .has_extended_tcb_support = true,
         .power_management = true,
     }
 };
 
+static E100PCIDeviceInfo *eepro100_get_class_by_name(const char *typename)
+{
+    E100PCIDeviceInfo *info = NULL;
+    int i;
+
+    /* This is admittedly awkward but also temporary.  QOM allows for
+     * parameterized typing and for subclassing both of which would suitable
+     * handle what's going on here.  But class_data is already being used as
+     * a stop-gap hack to allow incremental qdev conversion so we cannot use it
+     * right now.  Once we merge the final QOM series, we can come back here and
+     * do this in a much more elegant fashion.
+     */
+    for (i = 0; i < ARRAY_SIZE(e100_devices); i++) {
+        if (strcmp(e100_devices[i].name, typename) == 0) {
+            info = &e100_devices[i];
+            break;
+        }
+    }
+    assert(info != NULL);
+
+    return info;
+}
+
+static E100PCIDeviceInfo *eepro100_get_class(EEPRO100State *s)
+{
+    return eepro100_get_class_by_name(object_get_typename(OBJECT(s)));
+}
+
 static Property e100_properties[] = {
     DEFINE_NIC_PROPERTIES(EEPRO100State, conf),
     DEFINE_PROP_END_OF_LIST(),
 };
 
+static void eepro100_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+    E100PCIDeviceInfo *info;
+
+    info = eepro100_get_class_by_name(object_class_get_name(klass));
+
+    dc->props = e100_properties;
+    dc->desc = info->desc;
+    k->vendor_id = PCI_VENDOR_ID_INTEL;
+    k->class_id = PCI_CLASS_NETWORK_ETHERNET;
+    k->romfile = "pxe-eepro100.rom";
+    k->init = e100_nic_init;
+    k->exit = pci_nic_uninit;
+    k->device_id = info->device_id;
+    k->revision = info->revision;
+    k->subsystem_vendor_id = info->subsystem_vendor_id;
+    k->subsystem_id = info->subsystem_id;
+}
+
 static void eepro100_register_devices(void)
 {
     size_t i;
     for (i = 0; i < ARRAY_SIZE(e100_devices); i++) {
-        PCIDeviceInfo *pci_dev = &e100_devices[i].pci;
-        /* We use the same rom file for all device ids.
-           QEMU fixes the device id during rom load. */
-        pci_dev->vendor_id = PCI_VENDOR_ID_INTEL;
-        pci_dev->class_id = PCI_CLASS_NETWORK_ETHERNET;
-        pci_dev->romfile = "pxe-eepro100.rom";
-        pci_dev->init = e100_nic_init;
-        pci_dev->exit = pci_nic_uninit;
-        pci_dev->qdev.props = e100_properties;
-        pci_dev->qdev.size = sizeof(EEPRO100State);
-        pci_qdev_register(pci_dev);
+        TypeInfo type_info = {};
+        E100PCIDeviceInfo *info = &e100_devices[i];
+
+        type_info.name = info->name;
+        type_info.parent = TYPE_PCI_DEVICE;
+        type_info.class_init = eepro100_class_init;
+        type_info.instance_size = sizeof(EEPRO100State);
+        
+        type_register(&type_info);
     }
 }
 
diff --git a/hw/empty_slot.c b/hw/empty_slot.c
index 8b734f2c9f..1bc181555f 100644
--- a/hw/empty_slot.c
+++ b/hw/empty_slot.c
@@ -76,15 +76,23 @@ static int empty_slot_init1(SysBusDevice *dev)
     return 0;
 }
 
-static SysBusDeviceInfo empty_slot_info = {
-    .init = empty_slot_init1,
-    .qdev.name  = "empty_slot",
-    .qdev.size  = sizeof(EmptySlot),
+static void empty_slot_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = empty_slot_init1;
+}
+
+static TypeInfo empty_slot_info = {
+    .name          = "empty_slot",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(EmptySlot),
+    .class_init    = empty_slot_class_init,
 };
 
 static void empty_slot_register_devices(void)
 {
-    sysbus_register_withprop(&empty_slot_info);
+    type_register_static(&empty_slot_info);
 }
 
 device_init(empty_slot_register_devices);
diff --git a/hw/es1370.c b/hw/es1370.c
index 6a3ba55f6f..e377c48e49 100644
--- a/hw/es1370.c
+++ b/hw/es1370.c
@@ -914,7 +914,7 @@ static const MemoryRegionPortio es1370_portio[] = {
     { 0, 0x40 * 4, 1, .read = es1370_readb, },
     { 0, 0x40 * 2, 2, .read = es1370_readw, },
     { 0, 0x40, 4, .read = es1370_readl, },
-    PORTIO_END_OF_LIST()
+    PORTIO_END_OF_LIST ()
 };
 
 static const MemoryRegionOps es1370_io_ops = {
@@ -928,12 +928,12 @@ static const VMStateDescription vmstate_es1370_channel = {
     .minimum_version_id = 2,
     .minimum_version_id_old = 2,
     .fields      = (VMStateField []) {
-        VMSTATE_UINT32(shift, struct chan),
-        VMSTATE_UINT32(leftover, struct chan),
-        VMSTATE_UINT32(scount, struct chan),
-        VMSTATE_UINT32(frame_addr, struct chan),
-        VMSTATE_UINT32(frame_cnt, struct chan),
-        VMSTATE_END_OF_LIST()
+        VMSTATE_UINT32 (shift, struct chan),
+        VMSTATE_UINT32 (leftover, struct chan),
+        VMSTATE_UINT32 (scount, struct chan),
+        VMSTATE_UINT32 (frame_addr, struct chan),
+        VMSTATE_UINT32 (frame_cnt, struct chan),
+        VMSTATE_END_OF_LIST ()
     }
 };
 
@@ -973,15 +973,15 @@ static const VMStateDescription vmstate_es1370 = {
     .minimum_version_id_old = 2,
     .post_load = es1370_post_load,
     .fields      = (VMStateField []) {
-        VMSTATE_PCI_DEVICE(dev, ES1370State),
-        VMSTATE_STRUCT_ARRAY(chan, ES1370State, NB_CHANNELS, 2,
-                             vmstate_es1370_channel, struct chan),
-        VMSTATE_UINT32(ctl, ES1370State),
-        VMSTATE_UINT32(status, ES1370State),
-        VMSTATE_UINT32(mempage, ES1370State),
-        VMSTATE_UINT32(codec, ES1370State),
-        VMSTATE_UINT32(sctl, ES1370State),
-        VMSTATE_END_OF_LIST()
+        VMSTATE_PCI_DEVICE (dev, ES1370State),
+        VMSTATE_STRUCT_ARRAY (chan, ES1370State, NB_CHANNELS, 2,
+                              vmstate_es1370_channel, struct chan),
+        VMSTATE_UINT32 (ctl, ES1370State),
+        VMSTATE_UINT32 (status, ES1370State),
+        VMSTATE_UINT32 (mempage, ES1370State),
+        VMSTATE_UINT32 (codec, ES1370State),
+        VMSTATE_UINT32 (sctl, ES1370State),
+        VMSTATE_END_OF_LIST ()
     }
 };
 
@@ -1017,7 +1017,7 @@ static int es1370_initfn (PCIDevice *dev)
     return 0;
 }
 
-static int es1370_exitfn(PCIDevice *dev)
+static int es1370_exitfn (PCIDevice *dev)
 {
     ES1370State *s = DO_UPCAST (ES1370State, dev, dev);
 
@@ -1031,28 +1031,32 @@ int es1370_init (PCIBus *bus)
     return 0;
 }
 
-static PCIDeviceInfo es1370_info = {
-    .qdev.name    = "ES1370",
-    .qdev.desc    = "ENSONIQ AudioPCI ES1370",
-    .qdev.size    = sizeof (ES1370State),
-    .qdev.vmsd    = &vmstate_es1370,
-    .init         = es1370_initfn,
-    .exit         = es1370_exitfn,
-    .vendor_id    = PCI_VENDOR_ID_ENSONIQ,
-    .device_id    = PCI_DEVICE_ID_ENSONIQ_ES1370,
-    .class_id     = PCI_CLASS_MULTIMEDIA_AUDIO,
-#if 1
-    .subsystem_vendor_id = 0x4942,
-    .subsystem_id = 0x4c4c,
-#else
-    .subsystem_vendor_id = 0x1274,
-    .subsystem_id = 0x1371,
-#endif
+static void es1370_class_init (ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS (klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS (klass);
+
+    k->init = es1370_initfn;
+    k->exit = es1370_exitfn;
+    k->vendor_id = PCI_VENDOR_ID_ENSONIQ;
+    k->device_id = PCI_DEVICE_ID_ENSONIQ_ES1370;
+    k->class_id = PCI_CLASS_MULTIMEDIA_AUDIO;
+    k->subsystem_vendor_id = 0x4942;
+    k->subsystem_id = 0x4c4c;
+    dc->desc = "ENSONIQ AudioPCI ES1370";
+    dc->vmsd = &vmstate_es1370;
+}
+
+static TypeInfo es1370_info = {
+    .name          = "ES1370",
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof (ES1370State),
+    .class_init    = es1370_class_init,
 };
 
 static void es1370_register (void)
 {
-    pci_qdev_register (&es1370_info);
+    type_register_static (&es1370_info);
 }
 device_init (es1370_register);
 
diff --git a/hw/escc.c b/hw/escc.c
index 81204a633d..9fe282f7b8 100644
--- a/hw/escc.c
+++ b/hw/escc.c
@@ -901,28 +901,39 @@ static int escc_init1(SysBusDevice *dev)
     return 0;
 }
 
-static SysBusDeviceInfo escc_info = {
-    .init = escc_init1,
-    .qdev.name  = "escc",
-    .qdev.size  = sizeof(SerialState),
-    .qdev.vmsd  = &vmstate_escc,
-    .qdev.reset = escc_reset,
-    .qdev.props = (Property[]) {
-        DEFINE_PROP_UINT32("frequency", SerialState, frequency,   0),
-        DEFINE_PROP_UINT32("it_shift",  SerialState, it_shift,    0),
-        DEFINE_PROP_UINT32("disabled",  SerialState, disabled,    0),
-        DEFINE_PROP_UINT32("disabled",  SerialState, disabled,    0),
-        DEFINE_PROP_UINT32("chnBtype",  SerialState, chn[0].type, 0),
-        DEFINE_PROP_UINT32("chnAtype",  SerialState, chn[1].type, 0),
-        DEFINE_PROP_CHR("chrB", SerialState, chn[0].chr),
-        DEFINE_PROP_CHR("chrA", SerialState, chn[1].chr),
-        DEFINE_PROP_END_OF_LIST(),
-    }
+static Property escc_properties[] = {
+    DEFINE_PROP_UINT32("frequency", SerialState, frequency,   0),
+    DEFINE_PROP_UINT32("it_shift",  SerialState, it_shift,    0),
+    DEFINE_PROP_UINT32("disabled",  SerialState, disabled,    0),
+    DEFINE_PROP_UINT32("disabled",  SerialState, disabled,    0),
+    DEFINE_PROP_UINT32("chnBtype",  SerialState, chn[0].type, 0),
+    DEFINE_PROP_UINT32("chnAtype",  SerialState, chn[1].type, 0),
+    DEFINE_PROP_CHR("chrB", SerialState, chn[0].chr),
+    DEFINE_PROP_CHR("chrA", SerialState, chn[1].chr),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void escc_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = escc_init1;
+    dc->reset = escc_reset;
+    dc->vmsd = &vmstate_escc;
+    dc->props = escc_properties;
+}
+
+static TypeInfo escc_info = {
+    .name          = "escc",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(SerialState),
+    .class_init    = escc_class_init,
 };
 
 static void escc_register_devices(void)
 {
-    sysbus_register_withprop(&escc_info);
+    type_register_static(&escc_info);
 }
 
 device_init(escc_register_devices)
diff --git a/hw/esp.c b/hw/esp.c
index 9551c7846b..2f44386233 100644
--- a/hw/esp.c
+++ b/hw/esp.c
@@ -753,20 +753,31 @@ static int esp_init1(SysBusDevice *dev)
     return scsi_bus_legacy_handle_cmdline(&s->bus);
 }
 
-static SysBusDeviceInfo esp_info = {
-    .init = esp_init1,
-    .qdev.name  = "esp",
-    .qdev.size  = sizeof(ESPState),
-    .qdev.vmsd  = &vmstate_esp,
-    .qdev.reset = esp_hard_reset,
-    .qdev.props = (Property[]) {
-        {.name = NULL}
-    }
+static Property esp_properties[] = {
+    {.name = NULL},
+};
+
+static void esp_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = esp_init1;
+    dc->reset = esp_hard_reset;
+    dc->vmsd = &vmstate_esp;
+    dc->props = esp_properties;
+}
+
+static TypeInfo esp_info = {
+    .name          = "esp",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(ESPState),
+    .class_init    = esp_class_init,
 };
 
 static void esp_register_devices(void)
 {
-    sysbus_register_withprop(&esp_info);
+    type_register_static(&esp_info);
 }
 
 device_init(esp_register_devices)
diff --git a/hw/etraxfs_eth.c b/hw/etraxfs_eth.c
index 5afa55fb29..aefd5778ab 100644
--- a/hw/etraxfs_eth.c
+++ b/hw/etraxfs_eth.c
@@ -605,7 +605,7 @@ static int fs_eth_init(SysBusDevice *dev)
 
 	qemu_macaddr_default_if_unset(&s->conf.macaddr);
 	s->nic = qemu_new_nic(&net_etraxfs_info, &s->conf,
-			      dev->qdev.info->name, dev->qdev.id, s);
+			      object_get_typename(OBJECT(s)), dev->qdev.id, s);
 	qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a);
 
 	tdk_init(&s->phy);
@@ -613,22 +613,33 @@ static int fs_eth_init(SysBusDevice *dev)
 	return 0;
 }
 
-static SysBusDeviceInfo etraxfs_eth_info = {
-	.init = fs_eth_init,
-	.qdev.name  = "etraxfs-eth",
-	.qdev.size  = sizeof(struct fs_eth),
-	.qdev.props = (Property[]) {
-		DEFINE_PROP_UINT32("phyaddr", struct fs_eth, phyaddr, 1),
-		DEFINE_PROP_PTR("dma_out", struct fs_eth, vdma_out),
-		DEFINE_PROP_PTR("dma_in", struct fs_eth, vdma_in),
-		DEFINE_NIC_PROPERTIES(struct fs_eth, conf),
-		DEFINE_PROP_END_OF_LIST(),
-	}
+static Property etraxfs_eth_properties[] = {
+    DEFINE_PROP_UINT32("phyaddr", struct fs_eth, phyaddr, 1),
+    DEFINE_PROP_PTR("dma_out", struct fs_eth, vdma_out),
+    DEFINE_PROP_PTR("dma_in", struct fs_eth, vdma_in),
+    DEFINE_NIC_PROPERTIES(struct fs_eth, conf),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void etraxfs_eth_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = fs_eth_init;
+    dc->props = etraxfs_eth_properties;
+}
+
+static TypeInfo etraxfs_eth_info = {
+    .name          = "etraxfs-eth",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(struct fs_eth),
+    .class_init    = etraxfs_eth_class_init,
 };
 
 static void etraxfs_eth_register(void)
 {
-	sysbus_register_withprop(&etraxfs_eth_info);
+    type_register_static(&etraxfs_eth_info);
 }
 
 device_init(etraxfs_eth_register)
diff --git a/hw/etraxfs_pic.c b/hw/etraxfs_pic.c
index 993d6a8885..33541fcc61 100644
--- a/hw/etraxfs_pic.c
+++ b/hw/etraxfs_pic.c
@@ -151,19 +151,30 @@ static int etraxfs_pic_init(SysBusDevice *dev)
     return 0;
 }
 
-static SysBusDeviceInfo etraxfs_pic_info = {
-    .init = etraxfs_pic_init,
-    .qdev.name  = "etraxfs,pic",
-    .qdev.size  = sizeof(struct etrax_pic),
-    .qdev.props = (Property[]) {
-        DEFINE_PROP_PTR("interrupt_vector", struct etrax_pic, interrupt_vector),
-        DEFINE_PROP_END_OF_LIST(),
-    }
+static Property etraxfs_pic_properties[] = {
+    DEFINE_PROP_PTR("interrupt_vector", struct etrax_pic, interrupt_vector),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void etraxfs_pic_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = etraxfs_pic_init;
+    dc->props = etraxfs_pic_properties;
+}
+
+static TypeInfo etraxfs_pic_info = {
+    .name          = "etraxfs,pic",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(struct etrax_pic),
+    .class_init    = etraxfs_pic_class_init,
 };
 
 static void etraxfs_pic_register(void)
 {
-    sysbus_register_withprop(&etraxfs_pic_info);
+    type_register_static(&etraxfs_pic_info);
 }
 
 device_init(etraxfs_pic_register)
diff --git a/hw/etraxfs_ser.c b/hw/etraxfs_ser.c
index 2623dab9d4..567cb8cc2d 100644
--- a/hw/etraxfs_ser.c
+++ b/hw/etraxfs_ser.c
@@ -216,7 +216,7 @@ static int etraxfs_ser_init(SysBusDevice *dev)
     memory_region_init_io(&s->mmio, &ser_ops, s, "etraxfs-serial", R_MAX * 4);
     sysbus_init_mmio(dev, &s->mmio);
 
-    s->chr = qdev_init_chardev(&dev->qdev);
+    s->chr = qemu_char_get_next_serial();
     if (s->chr)
         qemu_chr_add_handlers(s->chr,
                       serial_can_receive, serial_receive,
@@ -224,16 +224,25 @@ static int etraxfs_ser_init(SysBusDevice *dev)
     return 0;
 }
 
-static SysBusDeviceInfo etraxfs_ser_info = {
-    .init = etraxfs_ser_init,
-    .qdev.name  = "etraxfs,serial",
-    .qdev.size  = sizeof(struct etrax_serial),
-    .qdev.reset = etraxfs_ser_reset,
+static void etraxfs_ser_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = etraxfs_ser_init;
+    dc->reset = etraxfs_ser_reset;
+}
+
+static TypeInfo etraxfs_ser_info = {
+    .name          = "etraxfs,serial",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(struct etrax_serial),
+    .class_init    = etraxfs_ser_class_init,
 };
 
 static void etraxfs_serial_register(void)
 {
-    sysbus_register_withprop(&etraxfs_ser_info);
+    type_register_static(&etraxfs_ser_info);
 }
 
 device_init(etraxfs_serial_register)
diff --git a/hw/etraxfs_timer.c b/hw/etraxfs_timer.c
index 2dfdb3063e..b71c5ee9d5 100644
--- a/hw/etraxfs_timer.c
+++ b/hw/etraxfs_timer.c
@@ -329,10 +329,23 @@ static int etraxfs_timer_init(SysBusDevice *dev)
     return 0;
 }
 
+static void etraxfs_timer_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+
+    sdc->init = etraxfs_timer_init;
+}
+
+static TypeInfo etraxfs_timer_info = {
+    .name          = "etraxfs,timer",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof (struct etrax_timer),
+    .class_init    = etraxfs_timer_class_init,
+};
+
 static void etraxfs_timer_register(void)
 {
-    sysbus_register_dev("etraxfs,timer", sizeof (struct etrax_timer),
-                        etraxfs_timer_init);
+    type_register_static(&etraxfs_timer_info);
 }
 
 device_init(etraxfs_timer_register)
diff --git a/hw/fdc.c b/hw/fdc.c
index 70aa5c7b56..f575a2c9f5 100644
--- a/hw/fdc.c
+++ b/hw/fdc.c
@@ -1959,21 +1959,31 @@ static const VMStateDescription vmstate_isa_fdc ={
     }
 };
 
-static ISADeviceInfo isa_fdc_info = {
-    .init = isabus_fdc_init1,
-    .qdev.name  = "isa-fdc",
-    .qdev.fw_name  = "fdc",
-    .qdev.size  = sizeof(FDCtrlISABus),
-    .qdev.no_user = 1,
-    .qdev.vmsd  = &vmstate_isa_fdc,
-    .qdev.reset = fdctrl_external_reset_isa,
-    .qdev.props = (Property[]) {
-        DEFINE_PROP_DRIVE("driveA", FDCtrlISABus, state.drives[0].bs),
-        DEFINE_PROP_DRIVE("driveB", FDCtrlISABus, state.drives[1].bs),
-        DEFINE_PROP_INT32("bootindexA", FDCtrlISABus, bootindexA, -1),
-        DEFINE_PROP_INT32("bootindexB", FDCtrlISABus, bootindexB, -1),
-        DEFINE_PROP_END_OF_LIST(),
-    },
+static Property isa_fdc_properties[] = {
+    DEFINE_PROP_DRIVE("driveA", FDCtrlISABus, state.drives[0].bs),
+    DEFINE_PROP_DRIVE("driveB", FDCtrlISABus, state.drives[1].bs),
+    DEFINE_PROP_INT32("bootindexA", FDCtrlISABus, bootindexA, -1),
+    DEFINE_PROP_INT32("bootindexB", FDCtrlISABus, bootindexB, -1),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void isabus_fdc_class_init1(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    ISADeviceClass *ic = ISA_DEVICE_CLASS(klass);
+    ic->init = isabus_fdc_init1;
+    dc->fw_name = "fdc";
+    dc->no_user = 1;
+    dc->reset = fdctrl_external_reset_isa;
+    dc->vmsd = &vmstate_isa_fdc;
+    dc->props = isa_fdc_properties;
+}
+
+static TypeInfo isa_fdc_info = {
+    .name          = "isa-fdc",
+    .parent        = TYPE_ISA_DEVICE,
+    .instance_size = sizeof(FDCtrlISABus),
+    .class_init    = isabus_fdc_class_init1,
 };
 
 static const VMStateDescription vmstate_sysbus_fdc ={
@@ -1986,36 +1996,58 @@ static const VMStateDescription vmstate_sysbus_fdc ={
     }
 };
 
-static SysBusDeviceInfo sysbus_fdc_info = {
-    .init = sysbus_fdc_init1,
-    .qdev.name  = "sysbus-fdc",
-    .qdev.size  = sizeof(FDCtrlSysBus),
-    .qdev.vmsd  = &vmstate_sysbus_fdc,
-    .qdev.reset = fdctrl_external_reset_sysbus,
-    .qdev.props = (Property[]) {
-        DEFINE_PROP_DRIVE("driveA", FDCtrlSysBus, state.drives[0].bs),
-        DEFINE_PROP_DRIVE("driveB", FDCtrlSysBus, state.drives[1].bs),
-        DEFINE_PROP_END_OF_LIST(),
-    },
+static Property sysbus_fdc_properties[] = {
+    DEFINE_PROP_DRIVE("driveA", FDCtrlSysBus, state.drives[0].bs),
+    DEFINE_PROP_DRIVE("driveB", FDCtrlSysBus, state.drives[1].bs),
+    DEFINE_PROP_END_OF_LIST(),
 };
 
-static SysBusDeviceInfo sun4m_fdc_info = {
-    .init = sun4m_fdc_init1,
-    .qdev.name  = "SUNW,fdtwo",
-    .qdev.size  = sizeof(FDCtrlSysBus),
-    .qdev.vmsd  = &vmstate_sysbus_fdc,
-    .qdev.reset = fdctrl_external_reset_sysbus,
-    .qdev.props = (Property[]) {
-        DEFINE_PROP_DRIVE("drive", FDCtrlSysBus, state.drives[0].bs),
-        DEFINE_PROP_END_OF_LIST(),
-    },
+static void sysbus_fdc_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = sysbus_fdc_init1;
+    dc->reset = fdctrl_external_reset_sysbus;
+    dc->vmsd = &vmstate_sysbus_fdc;
+    dc->props = sysbus_fdc_properties;
+}
+
+static TypeInfo sysbus_fdc_info = {
+    .name          = "sysbus-fdc",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(FDCtrlSysBus),
+    .class_init    = sysbus_fdc_class_init,
+};
+
+static Property sun4m_fdc_properties[] = {
+    DEFINE_PROP_DRIVE("drive", FDCtrlSysBus, state.drives[0].bs),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void sun4m_fdc_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = sun4m_fdc_init1;
+    dc->reset = fdctrl_external_reset_sysbus;
+    dc->vmsd = &vmstate_sysbus_fdc;
+    dc->props = sun4m_fdc_properties;
+}
+
+static TypeInfo sun4m_fdc_info = {
+    .name          = "SUNW,fdtwo",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(FDCtrlSysBus),
+    .class_init    = sun4m_fdc_class_init,
 };
 
 static void fdc_register_devices(void)
 {
-    isa_qdev_register(&isa_fdc_info);
-    sysbus_register_withprop(&sysbus_fdc_info);
-    sysbus_register_withprop(&sun4m_fdc_info);
+    type_register_static(&isa_fdc_info);
+    type_register_static(&sysbus_fdc_info);
+    type_register_static(&sun4m_fdc_info);
 }
 
 device_init(fdc_register_devices)
diff --git a/hw/framebuffer.c b/hw/framebuffer.c
index 6bf48dc046..ea122fb266 100644
--- a/hw/framebuffer.c
+++ b/hw/framebuffer.c
@@ -87,15 +87,8 @@ void framebuffer_update_display(
     dest += i * dest_row_pitch;
 
     for (; i < rows; i++) {
-        target_phys_addr_t dirty_offset;
-        dirty = 0;
-        dirty_offset = 0;
-        while (addr + dirty_offset < TARGET_PAGE_ALIGN(addr + src_width)) {
-            dirty |= memory_region_get_dirty(mem, addr + dirty_offset,
+        dirty = memory_region_get_dirty(mem, addr, addr + src_width,
                                              DIRTY_MEMORY_VGA);
-            dirty_offset += TARGET_PAGE_SIZE;
-        }
-
         if (dirty || invalidate) {
             fn(opaque, dest, src, cols, dest_col_pitch);
             if (first == -1)
diff --git a/hw/fw_cfg.c b/hw/fw_cfg.c
index f9535328f0..6b2f7d1986 100644
--- a/hw/fw_cfg.c
+++ b/hw/fw_cfg.c
@@ -531,23 +531,34 @@ static int fw_cfg_init1(SysBusDevice *dev)
     return 0;
 }
 
-static SysBusDeviceInfo fw_cfg_info = {
-    .init = fw_cfg_init1,
-    .qdev.name = "fw_cfg",
-    .qdev.size = sizeof(FWCfgState),
-    .qdev.vmsd = &vmstate_fw_cfg,
-    .qdev.reset = fw_cfg_reset,
-    .qdev.no_user = 1,
-    .qdev.props = (Property[]) {
-        DEFINE_PROP_HEX32("ctl_iobase", FWCfgState, ctl_iobase, -1),
-        DEFINE_PROP_HEX32("data_iobase", FWCfgState, data_iobase, -1),
-        DEFINE_PROP_END_OF_LIST(),
-    },
+static Property fw_cfg_properties[] = {
+    DEFINE_PROP_HEX32("ctl_iobase", FWCfgState, ctl_iobase, -1),
+    DEFINE_PROP_HEX32("data_iobase", FWCfgState, data_iobase, -1),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void fw_cfg_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = fw_cfg_init1;
+    dc->no_user = 1;
+    dc->reset = fw_cfg_reset;
+    dc->vmsd = &vmstate_fw_cfg;
+    dc->props = fw_cfg_properties;
+}
+
+static TypeInfo fw_cfg_info = {
+    .name          = "fw_cfg",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(FWCfgState),
+    .class_init    = fw_cfg_class_init,
 };
 
 static void fw_cfg_register_devices(void)
 {
-    sysbus_register_withprop(&fw_cfg_info);
+    type_register_static(&fw_cfg_info);
 }
 
 device_init(fw_cfg_register_devices)
diff --git a/hw/g364fb.c b/hw/g364fb.c
index 33ec149e0f..66d0044c06 100644
--- a/hw/g364fb.c
+++ b/hw/g364fb.c
@@ -62,7 +62,8 @@ typedef struct G364State {
 
 static inline int check_dirty(G364State *s, ram_addr_t page)
 {
-    return memory_region_get_dirty(&s->mem_vram, page, DIRTY_MEMORY_VGA);
+    return memory_region_get_dirty(&s->mem_vram, page, G364_PAGE_SIZE,
+                                   DIRTY_MEMORY_VGA);
 }
 
 static inline void reset_dirty(G364State *s,
@@ -268,12 +269,9 @@ static void g364fb_update_display(void *opaque)
 static inline void g364fb_invalidate_display(void *opaque)
 {
     G364State *s = opaque;
-    int i;
 
     s->blanked = 0;
-    for (i = 0; i < s->vram_size; i += G364_PAGE_SIZE) {
-        memory_region_set_dirty(&s->mem_vram, i);
-    }
+    memory_region_set_dirty(&s->mem_vram, 0, s->vram_size);
 }
 
 static void g364fb_reset(G364State *s)
@@ -385,7 +383,7 @@ static void g364fb_update_depth(G364State *s)
 
 static void g364_invalidate_cursor_position(G364State *s)
 {
-    int ymin, ymax, start, end, i;
+    int ymin, ymax, start, end;
 
     /* invalidate only near the cursor */
     ymin = s->cursor_position & 0xfff;
@@ -393,9 +391,7 @@ static void g364_invalidate_cursor_position(G364State *s)
     start = ymin * ds_get_linesize(s->ds);
     end = (ymax + 1) * ds_get_linesize(s->ds);
 
-    for (i = start; i < end; i += G364_PAGE_SIZE) {
-        memory_region_set_dirty(&s->mem_vram, i);
-    }
+    memory_region_set_dirty(&s->mem_vram, start, end - start);
 }
 
 static void g364fb_ctrl_write(void *opaque,
@@ -553,23 +549,34 @@ static void g364fb_sysbus_reset(DeviceState *d)
     g364fb_reset(&s->g364);
 }
 
-static SysBusDeviceInfo g364fb_sysbus_info = {
-    .init = g364fb_sysbus_init,
-    .qdev.name = "sysbus-g364",
-    .qdev.desc = "G364 framebuffer",
-    .qdev.size = sizeof(G364SysBusState),
-    .qdev.vmsd = &vmstate_g364fb,
-    .qdev.reset = g364fb_sysbus_reset,
-    .qdev.props = (Property[]) {
-        DEFINE_PROP_HEX32("vram_size", G364SysBusState, g364.vram_size,
-                          8 * 1024 * 1024),
-        DEFINE_PROP_END_OF_LIST(),
-    }
+static Property g364fb_sysbus_properties[] = {
+    DEFINE_PROP_HEX32("vram_size", G364SysBusState, g364.vram_size,
+    8 * 1024 * 1024),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void g364fb_sysbus_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = g364fb_sysbus_init;
+    dc->desc = "G364 framebuffer";
+    dc->reset = g364fb_sysbus_reset;
+    dc->vmsd = &vmstate_g364fb;
+    dc->props = g364fb_sysbus_properties;
+}
+
+static TypeInfo g364fb_sysbus_info = {
+    .name          = "sysbus-g364",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(G364SysBusState),
+    .class_init    = g364fb_sysbus_class_init,
 };
 
 static void g364fb_register(void)
 {
-    sysbus_register_withprop(&g364fb_sysbus_info);
+    type_register_static(&g364fb_sysbus_info);
 }
 
 device_init(g364fb_register);
diff --git a/hw/grackle_pci.c b/hw/grackle_pci.c
index 1e529fb5d0..8122baf482 100644
--- a/hw/grackle_pci.c
+++ b/hw/grackle_pci.c
@@ -71,7 +71,7 @@ PCIBus *pci_grackle_init(uint32_t base, qemu_irq *pic,
     SysBusDevice *s;
     GrackleState *d;
 
-    dev = qdev_create(NULL, "grackle");
+    dev = qdev_create(NULL, "grackle-pcihost");
     qdev_init_nofail(dev);
     s = sysbus_from_qdev(dev);
     d = FROM_SYSBUS(GrackleState, s);
@@ -121,21 +121,46 @@ static int grackle_pci_host_init(PCIDevice *d)
     return 0;
 }
 
-static PCIDeviceInfo grackle_pci_host_info = {
-    .qdev.name = "grackle",
-    .qdev.size = sizeof(PCIDevice),
-    .init      = grackle_pci_host_init,
-    .vendor_id = PCI_VENDOR_ID_MOTOROLA,
-    .device_id = PCI_DEVICE_ID_MOTOROLA_MPC106,
-    .revision  = 0x00,
-    .class_id  = PCI_CLASS_BRIDGE_HOST,
+static void grackle_pci_class_init(ObjectClass *klass, void *data)
+{
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    k->init      = grackle_pci_host_init;
+    k->vendor_id = PCI_VENDOR_ID_MOTOROLA;
+    k->device_id = PCI_DEVICE_ID_MOTOROLA_MPC106;
+    k->revision  = 0x00;
+    k->class_id  = PCI_CLASS_BRIDGE_HOST;
+    dc->no_user = 1;
+}
+
+static TypeInfo grackle_pci_info = {
+    .name          = "grackle",
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(PCIDevice),
+    .class_init = grackle_pci_class_init,
+};
+
+static void pci_grackle_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    k->init = pci_grackle_init_device;
+    dc->no_user = 1;
+}
+
+static TypeInfo grackle_pci_host_info = {
+    .name          = "grackle-pcihost",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(GrackleState),
+    .class_init    = pci_grackle_class_init,
 };
 
 static void grackle_register_devices(void)
 {
-    sysbus_register_dev("grackle", sizeof(GrackleState),
-                        pci_grackle_init_device);
-    pci_qdev_register(&grackle_pci_host_info);
+    type_register_static(&grackle_pci_info);
+    type_register_static(&grackle_pci_host_info);
 }
 
 device_init(grackle_register_devices)
diff --git a/hw/grlib_apbuart.c b/hw/grlib_apbuart.c
index f8a64e1644..89de2d85ae 100644
--- a/hw/grlib_apbuart.c
+++ b/hw/grlib_apbuart.c
@@ -24,7 +24,6 @@
 
 #include "sysbus.h"
 #include "qemu-char.h"
-#include "ptimer.h"
 
 #include "trace.h"
 
@@ -66,6 +65,8 @@
 #define SCALER_OFFSET     0x0C  /* not supported */
 #define FIFO_DEBUG_OFFSET 0x10  /* not supported */
 
+#define FIFO_LENGTH 1024
+
 typedef struct UART {
     SysBusDevice busdev;
     MemoryRegion iomem;
@@ -77,21 +78,67 @@ typedef struct UART {
     uint32_t receive;
     uint32_t status;
     uint32_t control;
+
+    /* FIFO */
+    char buffer[FIFO_LENGTH];
+    int  len;
+    int  current;
 } UART;
 
+static int uart_data_to_read(UART *uart)
+{
+    return uart->current < uart->len;
+}
+
+static char uart_pop(UART *uart)
+{
+    char ret;
+
+    if (uart->len == 0) {
+        uart->status &= ~UART_DATA_READY;
+        return 0;
+    }
+
+    ret = uart->buffer[uart->current++];
+
+    if (uart->current >= uart->len) {
+        /* Flush */
+        uart->len     = 0;
+        uart->current = 0;
+    }
+
+    if (!uart_data_to_read(uart)) {
+        uart->status &= ~UART_DATA_READY;
+    }
+
+    return ret;
+}
+
+static void uart_add_to_fifo(UART          *uart,
+                             const uint8_t *buffer,
+                             int            length)
+{
+    if (uart->len + length > FIFO_LENGTH) {
+        abort();
+    }
+    memcpy(uart->buffer + uart->len, buffer, length);
+    uart->len += length;
+}
+
 static int grlib_apbuart_can_receive(void *opaque)
 {
     UART *uart = opaque;
 
-    return !!(uart->status & UART_DATA_READY);
+    return FIFO_LENGTH - uart->len;
 }
 
 static void grlib_apbuart_receive(void *opaque, const uint8_t *buf, int size)
 {
     UART *uart = opaque;
 
-    uart->receive  = *buf;
-    uart->status  |= UART_DATA_READY;
+    uart_add_to_fifo(uart, buf, size);
+
+    uart->status |= UART_DATA_READY;
 
     if (uart->control & UART_RECEIVE_INTERRUPT) {
         qemu_irq_pulse(uart->irq);
@@ -103,9 +150,39 @@ static void grlib_apbuart_event(void *opaque, int event)
     trace_grlib_apbuart_event(event);
 }
 
-static void
-grlib_apbuart_write(void *opaque, target_phys_addr_t addr,
-                    uint64_t value, unsigned size)
+
+static uint64_t grlib_apbuart_read(void *opaque, target_phys_addr_t addr,
+                                   unsigned size)
+{
+    UART     *uart = opaque;
+
+    addr &= 0xff;
+
+    /* Unit registers */
+    switch (addr) {
+    case DATA_OFFSET:
+    case DATA_OFFSET + 3:       /* when only one byte read */
+        return uart_pop(uart);
+
+    case STATUS_OFFSET:
+        /* Read Only */
+        return uart->status;
+
+    case CONTROL_OFFSET:
+        return uart->control;
+
+    case SCALER_OFFSET:
+        /* Not supported */
+        return 0;
+
+    default:
+        trace_grlib_apbuart_readl_unknown(addr);
+        return 0;
+    }
+}
+
+static void grlib_apbuart_write(void *opaque, target_phys_addr_t addr,
+                                uint64_t value, unsigned size)
 {
     UART          *uart = opaque;
     unsigned char  c    = 0;
@@ -115,6 +192,7 @@ grlib_apbuart_write(void *opaque, target_phys_addr_t addr,
     /* Unit registers */
     switch (addr) {
     case DATA_OFFSET:
+    case DATA_OFFSET + 3:       /* When only one byte write */
         c = value & 0xFF;
         qemu_chr_fe_write(uart->chr, &c, 1);
         return;
@@ -124,7 +202,7 @@ grlib_apbuart_write(void *opaque, target_phys_addr_t addr,
         return;
 
     case CONTROL_OFFSET:
-        /* Not supported */
+        uart->control = value;
         return;
 
     case SCALER_OFFSET:
@@ -138,21 +216,15 @@ grlib_apbuart_write(void *opaque, target_phys_addr_t addr,
     trace_grlib_apbuart_writel_unknown(addr, value);
 }
 
-static bool grlib_apbuart_accepts(void *opaque, target_phys_addr_t addr,
-                                  unsigned size, bool is_write)
-{
-    return is_write && size == 4;
-}
-
 static const MemoryRegionOps grlib_apbuart_ops = {
-    .write = grlib_apbuart_write,
-    .valid.accepts = grlib_apbuart_accepts,
+    .write      = grlib_apbuart_write,
+    .read       = grlib_apbuart_read,
     .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
 static int grlib_apbuart_init(SysBusDevice *dev)
 {
-    UART *uart      = FROM_SYSBUS(typeof(*uart), dev);
+    UART *uart = FROM_SYSBUS(typeof(*uart), dev);
 
     qemu_chr_add_handlers(uart->chr,
                           grlib_apbuart_can_receive,
@@ -170,19 +242,30 @@ static int grlib_apbuart_init(SysBusDevice *dev)
     return 0;
 }
 
-static SysBusDeviceInfo grlib_gptimer_info = {
-    .init       = grlib_apbuart_init,
-    .qdev.name  = "grlib,apbuart",
-    .qdev.size  = sizeof(UART),
-    .qdev.props = (Property[]) {
-        DEFINE_PROP_CHR("chrdev", UART, chr),
-        DEFINE_PROP_END_OF_LIST()
-    }
+static Property grlib_gptimer_properties[] = {
+    DEFINE_PROP_CHR("chrdev", UART, chr),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void grlib_gptimer_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = grlib_apbuart_init;
+    dc->props = grlib_gptimer_properties;
+}
+
+static TypeInfo grlib_gptimer_info = {
+    .name          = "grlib,apbuart",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(UART),
+    .class_init    = grlib_gptimer_class_init,
 };
 
 static void grlib_gptimer_register(void)
 {
-    sysbus_register_withprop(&grlib_gptimer_info);
+    type_register_static(&grlib_gptimer_info);
 }
 
 device_init(grlib_gptimer_register)
diff --git a/hw/grlib_gptimer.c b/hw/grlib_gptimer.c
index 9c98a830d7..fb0b236746 100644
--- a/hw/grlib_gptimer.c
+++ b/hw/grlib_gptimer.c
@@ -372,22 +372,33 @@ static int grlib_gptimer_init(SysBusDevice *dev)
     return 0;
 }
 
-static SysBusDeviceInfo grlib_gptimer_info = {
-    .init       = grlib_gptimer_init,
-    .qdev.name  = "grlib,gptimer",
-    .qdev.reset = grlib_gptimer_reset,
-    .qdev.size  = sizeof(GPTimerUnit),
-    .qdev.props = (Property[]) {
-        DEFINE_PROP_UINT32("frequency", GPTimerUnit, freq_hz,   40000000),
-        DEFINE_PROP_UINT32("irq-line",  GPTimerUnit, irq_line,  8),
-        DEFINE_PROP_UINT32("nr-timers", GPTimerUnit, nr_timers, 2),
-        DEFINE_PROP_END_OF_LIST()
-    }
+static Property grlib_gptimer_properties[] = {
+    DEFINE_PROP_UINT32("frequency", GPTimerUnit, freq_hz,   40000000),
+    DEFINE_PROP_UINT32("irq-line",  GPTimerUnit, irq_line,  8),
+    DEFINE_PROP_UINT32("nr-timers", GPTimerUnit, nr_timers, 2),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void grlib_gptimer_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = grlib_gptimer_init;
+    dc->reset = grlib_gptimer_reset;
+    dc->props = grlib_gptimer_properties;
+}
+
+static TypeInfo grlib_gptimer_info = {
+    .name          = "grlib,gptimer",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(GPTimerUnit),
+    .class_init    = grlib_gptimer_class_init,
 };
 
 static void grlib_gptimer_register(void)
 {
-    sysbus_register_withprop(&grlib_gptimer_info);
+    type_register_static(&grlib_gptimer_info);
 }
 
 device_init(grlib_gptimer_register)
diff --git a/hw/grlib_irqmp.c b/hw/grlib_irqmp.c
index 28725563c0..1e5ad826f5 100644
--- a/hw/grlib_irqmp.c
+++ b/hw/grlib_irqmp.c
@@ -354,21 +354,32 @@ static int grlib_irqmp_init(SysBusDevice *dev)
     return 0;
 }
 
-static SysBusDeviceInfo grlib_irqmp_info = {
-    .init = grlib_irqmp_init,
-    .qdev.name  = "grlib,irqmp",
-    .qdev.reset = grlib_irqmp_reset,
-    .qdev.size  = sizeof(IRQMP),
-    .qdev.props = (Property[]) {
-        DEFINE_PROP_PTR("set_pil_in", IRQMP, set_pil_in),
-        DEFINE_PROP_PTR("set_pil_in_opaque", IRQMP, set_pil_in_opaque),
-        DEFINE_PROP_END_OF_LIST(),
-    }
+static Property grlib_irqmp_properties[] = {
+    DEFINE_PROP_PTR("set_pil_in", IRQMP, set_pil_in),
+    DEFINE_PROP_PTR("set_pil_in_opaque", IRQMP, set_pil_in_opaque),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void grlib_irqmp_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = grlib_irqmp_init;
+    dc->reset = grlib_irqmp_reset;
+    dc->props = grlib_irqmp_properties;
+}
+
+static TypeInfo grlib_irqmp_info = {
+    .name          = "grlib,irqmp",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(IRQMP),
+    .class_init    = grlib_irqmp_class_init,
 };
 
 static void grlib_irqmp_register(void)
 {
-    sysbus_register_withprop(&grlib_irqmp_info);
+    type_register_static(&grlib_irqmp_info);
 }
 
 device_init(grlib_irqmp_register)
diff --git a/hw/gt64xxx.c b/hw/gt64xxx.c
index 432683acea..e8cd59c3a4 100644
--- a/hw/gt64xxx.c
+++ b/hw/gt64xxx.c
@@ -1136,21 +1136,42 @@ static int gt64120_pci_init(PCIDevice *d)
     return 0;
 }
 
-static PCIDeviceInfo gt64120_pci_info = {
-    .qdev.name = "gt64120_pci",
-    .qdev.size = sizeof(PCIDevice),
-    .init      = gt64120_pci_init,
-    .vendor_id = PCI_VENDOR_ID_MARVELL,
-    .device_id = PCI_DEVICE_ID_MARVELL_GT6412X,
-    .revision  = 0x10,
-    .class_id  = PCI_CLASS_BRIDGE_HOST,
+static void gt64120_pci_class_init(ObjectClass *klass, void *data)
+{
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->init = gt64120_pci_init;
+    k->vendor_id = PCI_VENDOR_ID_MARVELL;
+    k->device_id = PCI_DEVICE_ID_MARVELL_GT6412X;
+    k->revision = 0x10;
+    k->class_id = PCI_CLASS_BRIDGE_HOST;
+}
+
+static TypeInfo gt64120_pci_info = {
+    .name          = "gt64120_pci",
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(PCIDevice),
+    .class_init    = gt64120_pci_class_init,
+};
+
+static void gt64120_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+
+    sdc->init = gt64120_init;
+}
+
+static TypeInfo gt64120_info = {
+    .name          = "gt64120",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(GT64120State),
+    .class_init    = gt64120_class_init,
 };
 
 static void gt64120_pci_register_devices(void)
 {
-    sysbus_register_dev("gt64120", sizeof(GT64120State),
-                        gt64120_init);
-    pci_qdev_register(&gt64120_pci_info);
+    type_register_static(&gt64120_info);
+    type_register_static(&gt64120_pci_info);
 }
 
 device_init(gt64120_pci_register_devices)
diff --git a/hw/gus.c b/hw/gus.c
index ab872d8dc5..20547075ec 100644
--- a/hw/gus.c
+++ b/hw/gus.c
@@ -221,14 +221,14 @@ static const VMStateDescription vmstate_gus = {
     .minimum_version_id = 2,
     .minimum_version_id_old = 2,
     .fields      = (VMStateField []) {
-        VMSTATE_INT32(pos, GUSState),
-        VMSTATE_INT32(left, GUSState),
-        VMSTATE_INT32(shift, GUSState),
-        VMSTATE_INT32(irqs, GUSState),
-        VMSTATE_INT32(samples, GUSState),
-        VMSTATE_INT64(last_ticks, GUSState),
-        VMSTATE_BUFFER(himem, GUSState),
-        VMSTATE_END_OF_LIST()
+        VMSTATE_INT32 (pos, GUSState),
+        VMSTATE_INT32 (left, GUSState),
+        VMSTATE_INT32 (shift, GUSState),
+        VMSTATE_INT32 (irqs, GUSState),
+        VMSTATE_INT32 (samples, GUSState),
+        VMSTATE_INT64 (last_ticks, GUSState),
+        VMSTATE_BUFFER (himem, GUSState),
+        VMSTATE_END_OF_LIST ()
     }
 };
 
@@ -239,13 +239,13 @@ static const MemoryRegionPortio gus_portio_list1[] = {
     {0x006, 10, 2, .read = gus_readw, .write = gus_writew },
     {0x100,  8, 1, .read = gus_readb, .write = gus_writeb },
     {0x100,  8, 2, .read = gus_readw, .write = gus_writew },
-    PORTIO_END_OF_LIST(),
+    PORTIO_END_OF_LIST (),
 };
 
 static const MemoryRegionPortio gus_portio_list2[] = {
     {0, 1, 1, .read = gus_readb },
     {0, 1, 2, .read = gus_readw },
-    PORTIO_END_OF_LIST(),
+    PORTIO_END_OF_LIST (),
 };
 
 static int gus_initfn (ISADevice *dev)
@@ -299,23 +299,33 @@ int GUS_init (ISABus *bus)
     return 0;
 }
 
-static ISADeviceInfo gus_info = {
-    .qdev.name     = "gus",
-    .qdev.desc     = "Gravis Ultrasound GF1",
-    .qdev.size     = sizeof (GUSState),
-    .qdev.vmsd     = &vmstate_gus,
-    .init          = gus_initfn,
-    .qdev.props    = (Property[]) {
-        DEFINE_PROP_UINT32 ("freq",    GUSState, freq,        44100),
-        DEFINE_PROP_HEX32  ("iobase",  GUSState, port,        0x240),
-        DEFINE_PROP_UINT32 ("irq",     GUSState, emu.gusirq,  7),
-        DEFINE_PROP_UINT32 ("dma",     GUSState, emu.gusdma,  3),
-        DEFINE_PROP_END_OF_LIST (),
-    },
+static Property gus_properties[] = {
+    DEFINE_PROP_UINT32 ("freq",    GUSState, freq,        44100),
+    DEFINE_PROP_HEX32  ("iobase",  GUSState, port,        0x240),
+    DEFINE_PROP_UINT32 ("irq",     GUSState, emu.gusirq,  7),
+    DEFINE_PROP_UINT32 ("dma",     GUSState, emu.gusdma,  3),
+    DEFINE_PROP_END_OF_LIST (),
+};
+
+static void gus_class_initfn (ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS (klass);
+    ISADeviceClass *ic = ISA_DEVICE_CLASS (klass);
+    ic->init = gus_initfn;
+    dc->desc = "Gravis Ultrasound GF1";
+    dc->vmsd = &vmstate_gus;
+    dc->props = gus_properties;
+}
+
+static TypeInfo gus_info = {
+    .name          = "gus",
+    .parent        = TYPE_ISA_DEVICE,
+    .instance_size = sizeof (GUSState),
+    .class_init    = gus_class_initfn,
 };
 
 static void gus_register (void)
 {
-    isa_qdev_register (&gus_info);
+    type_register_static (&gus_info);
 }
 device_init (gus_register)
diff --git a/hw/hda-audio.c b/hw/hda-audio.c
index 9b089e65b4..152f8e6f13 100644
--- a/hw/hda-audio.c
+++ b/hw/hda-audio.c
@@ -777,7 +777,7 @@ static int hda_audio_init(HDACodecDevice *hda, const struct desc_codec *desc)
     uint32_t i, type;
 
     a->desc = desc;
-    a->name = a->hda.qdev.info->name;
+    a->name = object_get_typename(OBJECT(a));
     dprint(a, 1, "%s: cad %d\n", __FUNCTION__, a->hda.cad);
 
     AUD_register_card("hda", &a->card);
@@ -906,33 +906,51 @@ static int hda_audio_init_duplex(HDACodecDevice *hda)
     return hda_audio_init(hda, &duplex);
 }
 
-static HDACodecDeviceInfo hda_audio_info_output = {
-    .qdev.name    = "hda-output",
-    .qdev.desc    = "HDA Audio Codec, output-only",
-    .qdev.size    = sizeof(HDAAudioState),
-    .qdev.vmsd    = &vmstate_hda_audio,
-    .qdev.props   = hda_audio_properties,
-    .init         = hda_audio_init_output,
-    .exit         = hda_audio_exit,
-    .command      = hda_audio_command,
-    .stream       = hda_audio_stream,
+static void hda_audio_output_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    HDACodecDeviceClass *k = HDA_CODEC_DEVICE_CLASS(klass);
+
+    k->init = hda_audio_init_output;
+    k->exit = hda_audio_exit;
+    k->command = hda_audio_command;
+    k->stream = hda_audio_stream;
+    dc->desc = "HDA Audio Codec, output-only";
+    dc->vmsd = &vmstate_hda_audio;
+    dc->props = hda_audio_properties;
+}
+
+static TypeInfo hda_audio_output_info = {
+    .name          = "hda-output",
+    .parent        = TYPE_HDA_CODEC_DEVICE,
+    .instance_size = sizeof(HDAAudioState),
+    .class_init    = hda_audio_output_class_init,
 };
 
-static HDACodecDeviceInfo hda_audio_info_duplex = {
-    .qdev.name    = "hda-duplex",
-    .qdev.desc    = "HDA Audio Codec, duplex",
-    .qdev.size    = sizeof(HDAAudioState),
-    .qdev.vmsd    = &vmstate_hda_audio,
-    .qdev.props   = hda_audio_properties,
-    .init         = hda_audio_init_duplex,
-    .exit         = hda_audio_exit,
-    .command      = hda_audio_command,
-    .stream       = hda_audio_stream,
+static void hda_audio_duplex_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    HDACodecDeviceClass *k = HDA_CODEC_DEVICE_CLASS(klass);
+
+    k->init = hda_audio_init_duplex;
+    k->exit = hda_audio_exit;
+    k->command = hda_audio_command;
+    k->stream = hda_audio_stream;
+    dc->desc = "HDA Audio Codec, duplex";
+    dc->vmsd = &vmstate_hda_audio;
+    dc->props = hda_audio_properties;
+}
+
+static TypeInfo hda_audio_duplex_info = {
+    .name          = "hda-duplex",
+    .parent        = TYPE_HDA_CODEC_DEVICE,
+    .instance_size = sizeof(HDAAudioState),
+    .class_init    = hda_audio_duplex_class_init,
 };
 
 static void hda_audio_register(void)
 {
-    hda_codec_register(&hda_audio_info_output);
-    hda_codec_register(&hda_audio_info_duplex);
+    type_register_static(&hda_audio_output_info);
+    type_register_static(&hda_audio_duplex_info);
 }
 device_init(hda_audio_register);
diff --git a/hw/highbank.c b/hw/highbank.c
new file mode 100644
index 0000000000..684178ee3e
--- /dev/null
+++ b/hw/highbank.c
@@ -0,0 +1,339 @@
+/*
+ * Calxeda Highbank SoC emulation
+ *
+ * Copyright (c) 2010-2012 Calxeda
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2 or later, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "sysbus.h"
+#include "arm-misc.h"
+#include "primecell.h"
+#include "devices.h"
+#include "loader.h"
+#include "net.h"
+#include "sysemu.h"
+#include "boards.h"
+#include "sysbus.h"
+#include "blockdev.h"
+#include "exec-memory.h"
+
+#define SMP_BOOT_ADDR 0x100
+#define SMP_BOOT_REG  0x40
+#define GIC_BASE_ADDR 0xfff10000
+
+#define NIRQ_GIC      160
+
+/* Board init.  */
+static void highbank_cpu_reset(void *opaque)
+{
+    CPUState *env = opaque;
+
+    env->cp15.c15_config_base_address = GIC_BASE_ADDR;
+}
+
+static void hb_write_secondary(CPUState *env, const struct arm_boot_info *info)
+{
+    int n;
+    uint32_t smpboot[] = {
+        0xee100fb0, /* mrc p15, 0, r0, c0, c0, 5 - read current core id */
+        0xe210000f, /* ands r0, r0, #0x0f */
+        0xe3a03040, /* mov r3, #0x40 - jump address is 0x40 + 0x10 * core id */
+        0xe0830200, /* add r0, r3, r0, lsl #4 */
+        0xe59f2018, /* ldr r2, privbase */
+        0xe3a01001, /* mov r1, #1 */
+        0xe5821100, /* str r1, [r2, #256] */
+        0xe320f003, /* wfi */
+        0xe5901000, /* ldr     r1, [r0] */
+        0xe1110001, /* tst     r1, r1 */
+        0x0afffffb, /* beq     <wfi> */
+        0xe12fff11, /* bx      r1 */
+        GIC_BASE_ADDR      /* privbase: gic address.  */
+    };
+    for (n = 0; n < ARRAY_SIZE(smpboot); n++) {
+        smpboot[n] = tswap32(smpboot[n]);
+    }
+    rom_add_blob_fixed("smpboot", smpboot, sizeof(smpboot), SMP_BOOT_ADDR);
+}
+
+static void hb_reset_secondary(CPUState *env, const struct arm_boot_info *info)
+{
+    switch (info->nb_cpus) {
+    case 4:
+        stl_phys_notdirty(SMP_BOOT_REG + 0x30, 0);
+    case 3:
+        stl_phys_notdirty(SMP_BOOT_REG + 0x20, 0);
+    case 2:
+        stl_phys_notdirty(SMP_BOOT_REG + 0x10, 0);
+        env->regs[15] = SMP_BOOT_ADDR;
+        break;
+    default:
+        break;
+    }
+}
+
+#define NUM_REGS      0x200
+static void hb_regs_write(void *opaque, target_phys_addr_t offset,
+                          uint64_t value, unsigned size)
+{
+    uint32_t *regs = opaque;
+
+    if (offset == 0xf00) {
+        if (value == 1 || value == 2) {
+            qemu_system_reset_request();
+        } else if (value == 3) {
+            qemu_system_shutdown_request();
+        }
+    }
+
+    regs[offset/4] = value;
+}
+
+static uint64_t hb_regs_read(void *opaque, target_phys_addr_t offset,
+                             unsigned size)
+{
+    uint32_t *regs = opaque;
+    uint32_t value = regs[offset/4];
+
+    if ((offset == 0x100) || (offset == 0x108) || (offset == 0x10C)) {
+        value |= 0x30000000;
+    }
+
+    return value;
+}
+
+static const MemoryRegionOps hb_mem_ops = {
+    .read = hb_regs_read,
+    .write = hb_regs_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+typedef struct {
+    SysBusDevice busdev;
+    MemoryRegion *iomem;
+    uint32_t regs[NUM_REGS];
+} HighbankRegsState;
+
+static VMStateDescription vmstate_highbank_regs = {
+    .name = "highbank-regs",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32_ARRAY(regs, HighbankRegsState, NUM_REGS),
+        VMSTATE_END_OF_LIST(),
+    },
+};
+
+static void highbank_regs_reset(DeviceState *dev)
+{
+    SysBusDevice *sys_dev = sysbus_from_qdev(dev);
+    HighbankRegsState *s = FROM_SYSBUS(HighbankRegsState, sys_dev);
+
+    s->regs[0x40] = 0x05F20121;
+    s->regs[0x41] = 0x2;
+    s->regs[0x42] = 0x05F30121;
+    s->regs[0x43] = 0x05F40121;
+}
+
+static int highbank_regs_init(SysBusDevice *dev)
+{
+    HighbankRegsState *s = FROM_SYSBUS(HighbankRegsState, dev);
+
+    s->iomem = g_new(MemoryRegion, 1);
+    memory_region_init_io(s->iomem, &hb_mem_ops, s->regs, "highbank_regs",
+                          0x1000);
+    sysbus_init_mmio(dev, s->iomem);
+
+    return 0;
+}
+
+static void highbank_regs_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass);
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    sbc->init = highbank_regs_init;
+    dc->desc = "Calxeda Highbank registers";
+    dc->vmsd = &vmstate_highbank_regs;
+    dc->reset = highbank_regs_reset;
+}
+
+static TypeInfo highbank_regs_info = {
+    .name          = "highbank-regs",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(HighbankRegsState),
+    .class_init    = highbank_regs_class_init,
+};
+
+static void highbank_regs_register_device(void)
+{
+    type_register_static(&highbank_regs_info);
+}
+
+device_init(highbank_regs_register_device)
+
+static struct arm_boot_info highbank_binfo;
+
+/* ram_size must be set to match the upper bound of memory in the
+ * device tree (linux/arch/arm/boot/dts/highbank.dts), which is
+ * normally 0xff900000 or -m 4089. When running this board on a
+ * 32-bit host, set the reg value of memory to 0xf7ff00000 in the
+ * device tree and pass -m 2047 to QEMU.
+ */
+static void highbank_init(ram_addr_t ram_size,
+                     const char *boot_device,
+                     const char *kernel_filename, const char *kernel_cmdline,
+                     const char *initrd_filename, const char *cpu_model)
+{
+    CPUState *env = NULL;
+    DeviceState *dev;
+    SysBusDevice *busdev;
+    qemu_irq *irqp;
+    qemu_irq pic[128];
+    int n;
+    qemu_irq cpu_irq[4];
+    MemoryRegion *sysram;
+    MemoryRegion *dram;
+    MemoryRegion *sysmem;
+    char *sysboot_filename;
+
+    if (!cpu_model) {
+        cpu_model = "cortex-a9";
+    }
+
+    for (n = 0; n < smp_cpus; n++) {
+        env = cpu_init(cpu_model);
+        if (!env) {
+            fprintf(stderr, "Unable to find CPU definition\n");
+            exit(1);
+        }
+        irqp = arm_pic_init_cpu(env);
+        cpu_irq[n] = irqp[ARM_PIC_CPU_IRQ];
+        qemu_register_reset(highbank_cpu_reset, env);
+    }
+
+    sysmem = get_system_memory();
+    dram = g_new(MemoryRegion, 1);
+    memory_region_init_ram(dram, "highbank.dram", ram_size);
+    /* SDRAM at address zero.  */
+    memory_region_add_subregion(sysmem, 0, dram);
+
+    sysram = g_new(MemoryRegion, 1);
+    memory_region_init_ram(sysram, "highbank.sysram", 0x8000);
+    memory_region_add_subregion(sysmem, 0xfff88000, sysram);
+    if (bios_name != NULL) {
+        sysboot_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
+        if (sysboot_filename != NULL) {
+            uint32_t filesize = get_image_size(sysboot_filename);
+            if (load_image_targphys("sysram.bin", 0xfff88000, filesize) < 0) {
+                hw_error("Unable to load %s\n", bios_name);
+            }
+        } else {
+           hw_error("Unable to find %s\n", bios_name);
+        }
+    }
+
+    dev = qdev_create(NULL, "a9mpcore_priv");
+    qdev_prop_set_uint32(dev, "num-cpu", smp_cpus);
+    qdev_prop_set_uint32(dev, "num-irq", NIRQ_GIC);
+    qdev_init_nofail(dev);
+    busdev = sysbus_from_qdev(dev);
+    sysbus_mmio_map(busdev, 0, GIC_BASE_ADDR);
+    for (n = 0; n < smp_cpus; n++) {
+        sysbus_connect_irq(busdev, n, cpu_irq[n]);
+    }
+
+    for (n = 0; n < 128; n++) {
+        pic[n] = qdev_get_gpio_in(dev, n);
+    }
+
+    dev = qdev_create(NULL, "l2x0");
+    qdev_init_nofail(dev);
+    busdev = sysbus_from_qdev(dev);
+    sysbus_mmio_map(busdev, 0, 0xfff12000);
+
+    dev = qdev_create(NULL, "sp804");
+    qdev_prop_set_uint32(dev, "freq0", 150000000);
+    qdev_prop_set_uint32(dev, "freq1", 150000000);
+    qdev_init_nofail(dev);
+    busdev = sysbus_from_qdev(dev);
+    sysbus_mmio_map(busdev, 0, 0xfff34000);
+    sysbus_connect_irq(busdev, 0, pic[18]);
+    sysbus_create_simple("pl011", 0xfff36000, pic[20]);
+
+    dev = qdev_create(NULL, "highbank-regs");
+    qdev_init_nofail(dev);
+    busdev = sysbus_from_qdev(dev);
+    sysbus_mmio_map(busdev, 0, 0xfff3c000);
+
+    sysbus_create_simple("pl061", 0xfff30000, pic[14]);
+    sysbus_create_simple("pl061", 0xfff31000, pic[15]);
+    sysbus_create_simple("pl061", 0xfff32000, pic[16]);
+    sysbus_create_simple("pl061", 0xfff33000, pic[17]);
+    sysbus_create_simple("pl031", 0xfff35000, pic[19]);
+    sysbus_create_simple("pl022", 0xfff39000, pic[23]);
+
+    sysbus_create_simple("sysbus-ahci", 0xffe08000, pic[83]);
+
+    if (nd_table[0].vlan) {
+        qemu_check_nic_model(&nd_table[0], "xgmac");
+        dev = qdev_create(NULL, "xgmac");
+        qdev_set_nic_properties(dev, &nd_table[0]);
+        qdev_init_nofail(dev);
+        sysbus_mmio_map(sysbus_from_qdev(dev), 0, 0xfff50000);
+        sysbus_connect_irq(sysbus_from_qdev(dev), 0, pic[77]);
+        sysbus_connect_irq(sysbus_from_qdev(dev), 1, pic[78]);
+        sysbus_connect_irq(sysbus_from_qdev(dev), 2, pic[79]);
+
+        qemu_check_nic_model(&nd_table[1], "xgmac");
+        dev = qdev_create(NULL, "xgmac");
+        qdev_set_nic_properties(dev, &nd_table[1]);
+        qdev_init_nofail(dev);
+        sysbus_mmio_map(sysbus_from_qdev(dev), 0, 0xfff51000);
+        sysbus_connect_irq(sysbus_from_qdev(dev), 0, pic[80]);
+        sysbus_connect_irq(sysbus_from_qdev(dev), 1, pic[81]);
+        sysbus_connect_irq(sysbus_from_qdev(dev), 2, pic[82]);
+    }
+
+    highbank_binfo.ram_size = ram_size;
+    highbank_binfo.kernel_filename = kernel_filename;
+    highbank_binfo.kernel_cmdline = kernel_cmdline;
+    highbank_binfo.initrd_filename = initrd_filename;
+    /* highbank requires a dtb in order to boot, and the dtb will override
+     * the board ID. The following value is ignored, so set it to -1 to be
+     * clear that the value is meaningless.
+     */
+    highbank_binfo.board_id = -1;
+    highbank_binfo.nb_cpus = smp_cpus;
+    highbank_binfo.loader_start = 0;
+    highbank_binfo.write_secondary_boot = hb_write_secondary;
+    highbank_binfo.secondary_cpu_reset_hook = hb_reset_secondary;
+    arm_load_kernel(first_cpu, &highbank_binfo);
+}
+
+static QEMUMachine highbank_machine = {
+    .name = "highbank",
+    .desc = "Calxeda Highbank (ECX-1000)",
+    .init = highbank_init,
+    .use_scsi = 1,
+    .max_cpus = 4,
+};
+
+static void highbank_machine_init(void)
+{
+    qemu_register_machine(&highbank_machine);
+}
+
+machine_init(highbank_machine_init);
diff --git a/hw/hpet.c b/hw/hpet.c
index 5312df7c3a..b6ace4e696 100644
--- a/hw/hpet.c
+++ b/hw/hpet.c
@@ -695,23 +695,34 @@ static int hpet_init(SysBusDevice *dev)
     return 0;
 }
 
-static SysBusDeviceInfo hpet_device_info = {
-    .qdev.name    = "hpet",
-    .qdev.size    = sizeof(HPETState),
-    .qdev.no_user = 1,
-    .qdev.vmsd    = &vmstate_hpet,
-    .qdev.reset   = hpet_reset,
-    .init         = hpet_init,
-    .qdev.props = (Property[]) {
-        DEFINE_PROP_UINT8("timers", HPETState, num_timers, HPET_MIN_TIMERS),
-        DEFINE_PROP_BIT("msi", HPETState, flags, HPET_MSI_SUPPORT, false),
-        DEFINE_PROP_END_OF_LIST(),
-    },
+static Property hpet_device_properties[] = {
+    DEFINE_PROP_UINT8("timers", HPETState, num_timers, HPET_MIN_TIMERS),
+    DEFINE_PROP_BIT("msi", HPETState, flags, HPET_MSI_SUPPORT, false),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void hpet_device_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = hpet_init;
+    dc->no_user = 1;
+    dc->reset = hpet_reset;
+    dc->vmsd = &vmstate_hpet;
+    dc->props = hpet_device_properties;
+}
+
+static TypeInfo hpet_device_info = {
+    .name          = "hpet",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(HPETState),
+    .class_init    = hpet_device_class_init,
 };
 
 static void hpet_register_device(void)
 {
-    sysbus_register_withprop(&hpet_device_info);
+    type_register_static(&hpet_device_info);
 }
 
 device_init(hpet_register_device)
diff --git a/hw/i2c.c b/hw/i2c.c
index 9bcf3e1d31..8ae4aaae1d 100644
--- a/hw/i2c.c
+++ b/hw/i2c.c
@@ -12,8 +12,8 @@
 struct i2c_bus
 {
     BusState qbus;
-    i2c_slave *current_dev;
-    i2c_slave *dev;
+    I2CSlave *current_dev;
+    I2CSlave *dev;
     uint8_t saved_address;
 };
 
@@ -21,7 +21,7 @@ static struct BusInfo i2c_bus_info = {
     .name = "I2C",
     .size = sizeof(i2c_bus),
     .props = (Property[]) {
-        DEFINE_PROP_UINT8("address", struct i2c_slave, address, 0),
+        DEFINE_PROP_UINT8("address", struct I2CSlave, address, 0),
         DEFINE_PROP_END_OF_LIST(),
     }
 };
@@ -66,7 +66,7 @@ i2c_bus *i2c_init_bus(DeviceState *parent, const char *name)
     return bus;
 }
 
-void i2c_set_slave_address(i2c_slave *dev, uint8_t address)
+void i2c_set_slave_address(I2CSlave *dev, uint8_t address)
 {
     dev->address = address;
 }
@@ -82,71 +82,100 @@ int i2c_bus_busy(i2c_bus *bus)
 int i2c_start_transfer(i2c_bus *bus, uint8_t address, int recv)
 {
     DeviceState *qdev;
-    i2c_slave *slave = NULL;
+    I2CSlave *slave = NULL;
+    I2CSlaveClass *sc;
 
     QTAILQ_FOREACH(qdev, &bus->qbus.children, sibling) {
-        i2c_slave *candidate = I2C_SLAVE_FROM_QDEV(qdev);
+        I2CSlave *candidate = I2C_SLAVE_FROM_QDEV(qdev);
         if (candidate->address == address) {
             slave = candidate;
             break;
         }
     }
 
-    if (!slave)
+    if (!slave) {
         return 1;
+    }
 
+    sc = I2C_SLAVE_GET_CLASS(slave);
     /* If the bus is already busy, assume this is a repeated
        start condition.  */
     bus->current_dev = slave;
-    slave->info->event(slave, recv ? I2C_START_RECV : I2C_START_SEND);
+    if (sc->event) {
+        sc->event(slave, recv ? I2C_START_RECV : I2C_START_SEND);
+    }
     return 0;
 }
 
 void i2c_end_transfer(i2c_bus *bus)
 {
-    i2c_slave *dev = bus->current_dev;
+    I2CSlave *dev = bus->current_dev;
+    I2CSlaveClass *sc;
 
-    if (!dev)
+    if (!dev) {
         return;
+    }
 
-    dev->info->event(dev, I2C_FINISH);
+    sc = I2C_SLAVE_GET_CLASS(dev);
+    if (sc->event) {
+        sc->event(dev, I2C_FINISH);
+    }
 
     bus->current_dev = NULL;
 }
 
 int i2c_send(i2c_bus *bus, uint8_t data)
 {
-    i2c_slave *dev = bus->current_dev;
+    I2CSlave *dev = bus->current_dev;
+    I2CSlaveClass *sc;
 
-    if (!dev)
+    if (!dev) {
         return -1;
+    }
+
+    sc = I2C_SLAVE_GET_CLASS(dev);
+    if (sc->send) {
+        return sc->send(dev, data);
+    }
 
-    return dev->info->send(dev, data);
+    return -1;
 }
 
 int i2c_recv(i2c_bus *bus)
 {
-    i2c_slave *dev = bus->current_dev;
+    I2CSlave *dev = bus->current_dev;
+    I2CSlaveClass *sc;
 
-    if (!dev)
+    if (!dev) {
         return -1;
+    }
+
+    sc = I2C_SLAVE_GET_CLASS(dev);
+    if (sc->recv) {
+        return sc->recv(dev);
+    }
 
-    return dev->info->recv(dev);
+    return -1;
 }
 
 void i2c_nack(i2c_bus *bus)
 {
-    i2c_slave *dev = bus->current_dev;
+    I2CSlave *dev = bus->current_dev;
+    I2CSlaveClass *sc;
 
-    if (!dev)
+    if (!dev) {
         return;
+    }
 
-    dev->info->event(dev, I2C_NACK);
+    sc = I2C_SLAVE_GET_CLASS(dev);
+    if (sc->event) {
+        sc->event(dev, I2C_NACK);
+    }
 }
 
 static int i2c_slave_post_load(void *opaque, int version_id)
 {
-    i2c_slave *dev = opaque;
+    I2CSlave *dev = opaque;
     i2c_bus *bus;
     bus = FROM_QBUS(i2c_bus, qdev_get_parent_bus(&dev->qdev));
     if (bus->saved_address == dev->address) {
@@ -156,33 +185,23 @@ static int i2c_slave_post_load(void *opaque, int version_id)
 }
 
 const VMStateDescription vmstate_i2c_slave = {
-    .name = "i2c_slave",
+    .name = "I2CSlave",
     .version_id = 1,
     .minimum_version_id = 1,
     .minimum_version_id_old = 1,
     .post_load = i2c_slave_post_load,
     .fields      = (VMStateField []) {
-        VMSTATE_UINT8(address, i2c_slave),
+        VMSTATE_UINT8(address, I2CSlave),
         VMSTATE_END_OF_LIST()
     }
 };
 
-static int i2c_slave_qdev_init(DeviceState *dev, DeviceInfo *base)
+static int i2c_slave_qdev_init(DeviceState *dev)
 {
-    I2CSlaveInfo *info = container_of(base, I2CSlaveInfo, qdev);
-    i2c_slave *s = I2C_SLAVE_FROM_QDEV(dev);
-
-    s->info = info;
+    I2CSlave *s = I2C_SLAVE_FROM_QDEV(dev);
+    I2CSlaveClass *sc = I2C_SLAVE_GET_CLASS(s);
 
-    return info->init(s);
-}
-
-void i2c_register_slave(I2CSlaveInfo *info)
-{
-    assert(info->qdev.size >= sizeof(i2c_slave));
-    info->qdev.init = i2c_slave_qdev_init;
-    info->qdev.bus_info = &i2c_bus_info;
-    qdev_register(&info->qdev);
+    return sc->init(s);
 }
 
 DeviceState *i2c_create_slave(i2c_bus *bus, const char *name, uint8_t addr)
@@ -194,3 +213,26 @@ DeviceState *i2c_create_slave(i2c_bus *bus, const char *name, uint8_t addr)
     qdev_init_nofail(dev);
     return dev;
 }
+
+static void i2c_slave_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *k = DEVICE_CLASS(klass);
+    k->init = i2c_slave_qdev_init;
+    k->bus_info = &i2c_bus_info;
+}
+
+static TypeInfo i2c_slave_type_info = {
+    .name = TYPE_I2C_SLAVE,
+    .parent = TYPE_DEVICE,
+    .instance_size = sizeof(I2CSlave),
+    .abstract = true,
+    .class_size = sizeof(I2CSlaveClass),
+    .class_init = i2c_slave_class_init,
+};
+
+static void i2c_slave_register_devices(void)
+{
+    type_register_static(&i2c_slave_type_info);
+}
+
+device_init(i2c_slave_register_devices);
diff --git a/hw/i2c.h b/hw/i2c.h
index a3383ff025..0f5682b4b0 100644
--- a/hw/i2c.h
+++ b/hw/i2c.h
@@ -15,36 +15,43 @@ enum i2c_event {
     I2C_NACK /* Masker NACKed a receive byte.  */
 };
 
-/* Master to slave.  */
-typedef int (*i2c_send_cb)(i2c_slave *s, uint8_t data);
-/* Slave to master.  */
-typedef int (*i2c_recv_cb)(i2c_slave *s);
-/* Notify the slave of a bus state change.  */
-typedef void (*i2c_event_cb)(i2c_slave *s, enum i2c_event event);
+typedef struct I2CSlave I2CSlave;
 
-typedef int (*i2c_slave_initfn)(i2c_slave *dev);
+#define TYPE_I2C_SLAVE "i2c-slave"
+#define I2C_SLAVE(obj) \
+     OBJECT_CHECK(I2CSlave, (obj), TYPE_I2C_SLAVE)
+#define I2C_SLAVE_CLASS(klass) \
+     OBJECT_CLASS_CHECK(I2CSlaveClass, (klass), TYPE_I2C_SLAVE)
+#define I2C_SLAVE_GET_CLASS(obj) \
+     OBJECT_GET_CLASS(I2CSlaveClass, (obj), TYPE_I2C_SLAVE)
 
-typedef struct {
-    DeviceInfo qdev;
+typedef struct I2CSlaveClass
+{
+    DeviceClass parent_class;
 
     /* Callbacks provided by the device.  */
-    i2c_slave_initfn init;
-    i2c_event_cb event;
-    i2c_recv_cb recv;
-    i2c_send_cb send;
-} I2CSlaveInfo;
+    int (*init)(I2CSlave *dev);
+
+    /* Master to slave.  */
+    int (*send)(I2CSlave *s, uint8_t data);
+
+    /* Slave to master.  */
+    int (*recv)(I2CSlave *s);
 
-struct i2c_slave
+    /* Notify the slave of a bus state change.  */
+    void (*event)(I2CSlave *s, enum i2c_event event);
+} I2CSlaveClass;
+
+struct I2CSlave
 {
     DeviceState qdev;
-    I2CSlaveInfo *info;
 
     /* Remaining fields for internal use by the I2C code.  */
     uint8_t address;
 };
 
 i2c_bus *i2c_init_bus(DeviceState *parent, const char *name);
-void i2c_set_slave_address(i2c_slave *dev, uint8_t address);
+void i2c_set_slave_address(I2CSlave *dev, uint8_t address);
 int i2c_bus_busy(i2c_bus *bus);
 int i2c_start_transfer(i2c_bus *bus, uint8_t address, int recv);
 void i2c_end_transfer(i2c_bus *bus);
@@ -52,11 +59,9 @@ void i2c_nack(i2c_bus *bus);
 int i2c_send(i2c_bus *bus, uint8_t data);
 int i2c_recv(i2c_bus *bus);
 
-#define I2C_SLAVE_FROM_QDEV(dev) DO_UPCAST(i2c_slave, qdev, dev)
+#define I2C_SLAVE_FROM_QDEV(dev) DO_UPCAST(I2CSlave, qdev, dev)
 #define FROM_I2C_SLAVE(type, dev) DO_UPCAST(type, i2c, dev)
 
-void i2c_register_slave(I2CSlaveInfo *type);
-
 DeviceState *i2c_create_slave(i2c_bus *bus, const char *name, uint8_t addr);
 
 /* wm8750.c */
@@ -69,7 +74,7 @@ void wm8750_dac_commit(void *opaque);
 void wm8750_set_bclk_in(void *opaque, int new_hz);
 
 /* tmp105.c */
-void tmp105_set(i2c_slave *i2c, int temp);
+void tmp105_set(I2CSlave *i2c, int temp);
 
 /* lm832x.c */
 void lm832x_key_event(DeviceState *dev, int key, int state);
@@ -78,10 +83,10 @@ extern const VMStateDescription vmstate_i2c_slave;
 
 #define VMSTATE_I2C_SLAVE(_field, _state) {                          \
     .name       = (stringify(_field)),                               \
-    .size       = sizeof(i2c_slave),                                 \
+    .size       = sizeof(I2CSlave),                                  \
     .vmsd       = &vmstate_i2c_slave,                                \
     .flags      = VMS_STRUCT,                                        \
-    .offset     = vmstate_offset_value(_state, _field, i2c_slave),   \
+    .offset     = vmstate_offset_value(_state, _field, I2CSlave),    \
 }
 
 #endif
diff --git a/hw/i82374.c b/hw/i82374.c
new file mode 100644
index 0000000000..220e8cccb6
--- /dev/null
+++ b/hw/i82374.c
@@ -0,0 +1,165 @@
+/*
+ * QEMU Intel 82374 emulation (Enhanced DMA controller)
+ *
+ * Copyright (c) 2010 Hervé Poussineau
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "isa.h"
+
+//#define DEBUG_I82374
+
+#ifdef DEBUG_I82374
+#define DPRINTF(fmt, ...) \
+do { fprintf(stderr, "i82374: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...) \
+do {} while (0)
+#endif
+#define BADF(fmt, ...) \
+do { fprintf(stderr, "i82374 ERROR: " fmt , ## __VA_ARGS__); } while (0)
+
+typedef struct I82374State {
+    uint8_t commands[8];
+} I82374State;
+
+static const VMStateDescription vmstate_i82374 = {
+    .name = "i82374",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT8_ARRAY(commands, I82374State, 8),
+        VMSTATE_END_OF_LIST()
+    },
+};
+
+static uint32_t i82374_read_isr(void *opaque, uint32_t nport)
+{
+    uint32_t val = 0;
+
+    BADF("%s: %08x\n", __func__, nport);
+
+    DPRINTF("%s: %08x=%08x\n", __func__, nport, val);
+    return val;
+}
+
+static void i82374_write_command(void *opaque, uint32_t nport, uint32_t data)
+{
+    DPRINTF("%s: %08x=%08x\n", __func__, nport, data);
+
+    if (data != 0x42) {
+        /* Not Stop S/G command */
+        BADF("%s: %08x=%08x\n", __func__, nport, data);
+    }
+}
+
+static uint32_t i82374_read_status(void *opaque, uint32_t nport)
+{
+    uint32_t val = 0;
+
+    BADF("%s: %08x\n", __func__, nport);
+
+    DPRINTF("%s: %08x=%08x\n", __func__, nport, val);
+    return val;
+}
+
+static void i82374_write_descriptor(void *opaque, uint32_t nport, uint32_t data)
+{
+    DPRINTF("%s: %08x=%08x\n", __func__, nport, data);
+
+    BADF("%s: %08x=%08x\n", __func__, nport, data);
+}
+
+static uint32_t i82374_read_descriptor(void *opaque, uint32_t nport)
+{
+    uint32_t val = 0;
+
+    BADF("%s: %08x\n", __func__, nport);
+
+    DPRINTF("%s: %08x=%08x\n", __func__, nport, val);
+    return val;
+}
+
+static void i82374_init(I82374State *s)
+{
+    DMA_init(1, NULL);
+    memset(s->commands, 0, sizeof(s->commands));
+}
+
+typedef struct ISAi82374State {
+    ISADevice dev;
+    uint32_t iobase;
+    I82374State state;
+} ISAi82374State;
+
+static const VMStateDescription vmstate_isa_i82374 = {
+    .name = "isa-i82374",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .fields = (VMStateField[]) {
+        VMSTATE_STRUCT(state, ISAi82374State, 0, vmstate_i82374, I82374State),
+        VMSTATE_END_OF_LIST()
+    },
+};
+
+static int i82374_isa_init(ISADevice *dev)
+{
+    ISAi82374State *isa = DO_UPCAST(ISAi82374State, dev, dev);
+    I82374State *s = &isa->state;
+
+    register_ioport_read(isa->iobase + 0x0A, 1, 1, i82374_read_isr, s);
+    register_ioport_write(isa->iobase + 0x10, 8, 1, i82374_write_command, s);
+    register_ioport_read(isa->iobase + 0x18, 8, 1, i82374_read_status, s);
+    register_ioport_write(isa->iobase + 0x20, 0x20, 1, i82374_write_descriptor, s);
+    register_ioport_read(isa->iobase + 0x20, 0x20, 1, i82374_read_descriptor, s);
+
+    i82374_init(s);
+
+    return 0;
+}
+
+static Property i82374_properties[] = {
+    DEFINE_PROP_HEX32("iobase", ISAi82374State, iobase, 0x400),
+    DEFINE_PROP_END_OF_LIST()
+};
+
+static void i82374_class_init(ObjectClass *klass, void *data)
+{
+    ISADeviceClass *k = ISA_DEVICE_CLASS(klass);
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    
+    k->init  = i82374_isa_init;
+    dc->vmsd = &vmstate_isa_i82374;
+    dc->props = i82374_properties;
+}
+
+static TypeInfo i82374_isa_info = {
+    .name  = "i82374",
+    .parent = TYPE_ISA_DEVICE,
+    .instance_size  = sizeof(ISAi82374State),
+    .class_init = i82374_class_init,
+};
+
+static void i82374_register_devices(void)
+{
+    type_register_static(&i82374_isa_info);
+}
+
+device_init(i82374_register_devices)
diff --git a/hw/i82378.c b/hw/i82378.c
new file mode 100644
index 0000000000..9c3efe8b95
--- /dev/null
+++ b/hw/i82378.c
@@ -0,0 +1,275 @@
+/*
+ * QEMU Intel i82378 emulation (PCI to ISA bridge)
+ *
+ * Copyright (c) 2010-2011 Hervé Poussineau
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "pci.h"
+#include "pc.h"
+
+//#define DEBUG_I82378
+
+#ifdef DEBUG_I82378
+#define DPRINTF(fmt, ...) \
+do { fprintf(stderr, "i82378: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...) \
+do {} while (0)
+#endif
+
+#define BADF(fmt, ...) \
+do { fprintf(stderr, "i82378 ERROR: " fmt , ## __VA_ARGS__); } while (0)
+
+typedef struct I82378State {
+    qemu_irq out[2];
+    qemu_irq *i8259;
+    MemoryRegion io;
+    MemoryRegion mem;
+} I82378State;
+
+typedef struct PCIi82378State {
+    PCIDevice pci_dev;
+    uint32_t isa_io_base;
+    uint32_t isa_mem_base;
+    I82378State state;
+} PCIi82378State;
+
+static const VMStateDescription vmstate_pci_i82378 = {
+    .name = "pci-i82378",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .fields = (VMStateField[]) {
+        VMSTATE_PCI_DEVICE(pci_dev, PCIi82378State),
+        VMSTATE_END_OF_LIST()
+    },
+};
+
+static void i82378_io_write(void *opaque, target_phys_addr_t addr,
+                            uint64_t value, unsigned int size)
+{
+    switch (size) {
+    case 1:
+        DPRINTF("%s: " TARGET_FMT_plx "=%02" PRIx64 "\n", __func__,
+                addr, value);
+        cpu_outb(addr, value);
+        break;
+    case 2:
+        DPRINTF("%s: " TARGET_FMT_plx "=%04" PRIx64 "\n", __func__,
+                addr, value);
+        cpu_outw(addr, value);
+        break;
+    case 4:
+        DPRINTF("%s: " TARGET_FMT_plx "=%08" PRIx64 "\n", __func__,
+                addr, value);
+        cpu_outl(addr, value);
+        break;
+    default:
+        abort();
+    }
+}
+
+static uint64_t i82378_io_read(void *opaque, target_phys_addr_t addr,
+                               unsigned int size)
+{
+    DPRINTF("%s: " TARGET_FMT_plx "\n", __func__, addr);
+    switch (size) {
+    case 1:
+        return cpu_inb(addr);
+    case 2:
+        return cpu_inw(addr);
+    case 4:
+        return cpu_inl(addr);
+    default:
+        abort();
+    }
+}
+
+static const MemoryRegionOps i82378_io_ops = {
+    .read = i82378_io_read,
+    .write = i82378_io_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static void i82378_mem_write(void *opaque, target_phys_addr_t addr,
+                             uint64_t value, unsigned int size)
+{
+    switch (size) {
+    case 1:
+        DPRINTF("%s: " TARGET_FMT_plx "=%02" PRIx64 "\n", __func__,
+                addr, value);
+        cpu_outb(addr, value);
+        break;
+    case 2:
+        DPRINTF("%s: " TARGET_FMT_plx "=%04" PRIx64 "\n", __func__,
+                addr, value);
+        cpu_outw(addr, value);
+        break;
+    case 4:
+        DPRINTF("%s: " TARGET_FMT_plx "=%08" PRIx64 "\n", __func__,
+                addr, value);
+        cpu_outl(addr, value);
+        break;
+    default:
+        abort();
+    }
+}
+
+static uint64_t i82378_mem_read(void *opaque, target_phys_addr_t addr,
+                                unsigned int size)
+{
+    DPRINTF("%s: " TARGET_FMT_plx "\n", __func__, addr);
+    switch (size) {
+    case 1:
+        return cpu_inb(addr);
+    case 2:
+        return cpu_inw(addr);
+    case 4:
+        return cpu_inl(addr);
+    default:
+        abort();
+    }
+}
+
+static const MemoryRegionOps i82378_mem_ops = {
+    .read = i82378_mem_read,
+    .write = i82378_mem_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static void i82378_request_out0_irq(void *opaque, int irq, int level)
+{
+    I82378State *s = opaque;
+    qemu_set_irq(s->out[0], level);
+}
+
+static void i82378_request_pic_irq(void *opaque, int irq, int level)
+{
+    DeviceState *dev = opaque;
+    PCIDevice *pci = DO_UPCAST(PCIDevice, qdev, dev);
+    PCIi82378State *s = DO_UPCAST(PCIi82378State, pci_dev, pci);
+
+    qemu_set_irq(s->state.i8259[irq], level);
+}
+
+static void i82378_init(DeviceState *dev, I82378State *s)
+{
+    ISABus *isabus = DO_UPCAST(ISABus, qbus, qdev_get_child_bus(dev, "isa.0"));
+    ISADevice *pit;
+    qemu_irq *out0_irq;
+
+    /* This device has:
+       2 82C59 (irq)
+       1 82C54 (pit)
+       2 82C37 (dma)
+       NMI
+       Utility Bus Support Registers
+
+       All devices accept byte access only, except timer
+     */
+
+    qdev_init_gpio_out(dev, s->out, 2);
+    qdev_init_gpio_in(dev, i82378_request_pic_irq, 16);
+
+    /* Workaround the fact that i8259 is not qdev'ified... */
+    out0_irq = qemu_allocate_irqs(i82378_request_out0_irq, s, 1);
+
+    /* 2 82C59 (irq) */
+    s->i8259 = i8259_init(isabus, *out0_irq);
+    isa_bus_irqs(isabus, s->i8259);
+
+    /* 1 82C54 (pit) */
+    pit = pit_init(isabus, 0x40, 0);
+
+    /* speaker */
+    pcspk_init(pit);
+
+    /* 2 82C37 (dma) */
+    DMA_init(1, &s->out[1]);
+    isa_create_simple(isabus, "i82374");
+
+    /* timer */
+    isa_create_simple(isabus, "mc146818rtc");
+}
+
+static int pci_i82378_init(PCIDevice *dev)
+{
+    PCIi82378State *pci = DO_UPCAST(PCIi82378State, pci_dev, dev);
+    I82378State *s = &pci->state;
+    uint8_t *pci_conf;
+
+    pci_conf = dev->config;
+    pci_set_word(pci_conf + PCI_COMMAND,
+                 PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
+    pci_set_word(pci_conf + PCI_STATUS,
+                 PCI_STATUS_DEVSEL_MEDIUM);
+
+    pci_conf[PCI_INTERRUPT_PIN] = 1; /* interrupt pin 0 */
+
+    memory_region_init_io(&s->io, &i82378_io_ops, s, "i82378-io", 0x00010000);
+    pci_register_bar(dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->io);
+
+    memory_region_init_io(&s->mem, &i82378_mem_ops, s, "i82378-mem", 0x01000000);
+    memory_region_set_coalescing(&s->mem);
+    pci_register_bar(dev, 1, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->mem);
+
+    /* Make I/O address read only */
+    pci_set_word(dev->wmask + PCI_COMMAND, PCI_COMMAND_SPECIAL);
+    pci_set_long(dev->wmask + PCI_BASE_ADDRESS_0, 0);
+    pci_set_long(pci_conf + PCI_BASE_ADDRESS_0, pci->isa_io_base);
+
+    isa_mem_base = pci->isa_mem_base;
+    isa_bus_new(&dev->qdev, pci_address_space_io(dev));
+
+    i82378_init(&dev->qdev, s);
+
+    return 0;
+}
+
+static Property i82378_properties[] = {
+    DEFINE_PROP_HEX32("iobase", PCIi82378State, isa_io_base, 0x80000000),
+    DEFINE_PROP_HEX32("membase", PCIi82378State, isa_mem_base, 0xc0000000),
+    DEFINE_PROP_END_OF_LIST()
+};
+
+static void pci_i82378_class_init(ObjectClass *klass, void *data)
+{
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    k->init = pci_i82378_init;
+    k->vendor_id = PCI_VENDOR_ID_INTEL;
+    k->device_id = PCI_DEVICE_ID_INTEL_82378;
+    k->revision = 0x03;
+    k->class_id = PCI_CLASS_BRIDGE_ISA;
+    k->subsystem_vendor_id = 0x0;
+    k->subsystem_id = 0x0;
+    dc->vmsd = &vmstate_pci_i82378;
+    dc->props = i82378_properties;
+}
+
+static TypeInfo pci_i82378_info = {
+    .name = "i82378",
+    .parent = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(PCIi82378State),
+    .class_init = pci_i82378_class_init,
+};
+
+static void i82378_register_devices(void)
+{
+    type_register_static(&pci_i82378_info);
+}
+
+device_init(i82378_register_devices)
diff --git a/hw/i8254.c b/hw/i8254.c
index cf9ed2ff25..522fed8809 100644
--- a/hw/i8254.c
+++ b/hw/i8254.c
@@ -535,22 +535,32 @@ static int pit_initfn(ISADevice *dev)
     return 0;
 }
 
-static ISADeviceInfo pit_info = {
-    .qdev.name     = "isa-pit",
-    .qdev.size     = sizeof(PITState),
-    .qdev.vmsd     = &vmstate_pit,
-    .qdev.reset    = pit_reset,
-    .qdev.no_user  = 1,
-    .init          = pit_initfn,
-    .qdev.props = (Property[]) {
-        DEFINE_PROP_UINT32("irq", PITState, irq,  -1),
-        DEFINE_PROP_HEX32("iobase", PITState, iobase,  -1),
-        DEFINE_PROP_END_OF_LIST(),
-    },
+static Property pit_properties[] = {
+    DEFINE_PROP_UINT32("irq", PITState, irq,  -1),
+    DEFINE_PROP_HEX32("iobase", PITState, iobase,  -1),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void pit_class_initfn(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    ISADeviceClass *ic = ISA_DEVICE_CLASS(klass);
+    ic->init = pit_initfn;
+    dc->no_user = 1;
+    dc->reset = pit_reset;
+    dc->vmsd = &vmstate_pit;
+    dc->props = pit_properties;
+}
+
+static TypeInfo pit_info = {
+    .name          = "isa-pit",
+    .parent        = TYPE_ISA_DEVICE,
+    .instance_size = sizeof(PITState),
+    .class_init    = pit_class_initfn,
 };
 
 static void pit_register(void)
 {
-    isa_qdev_register(&pit_info);
+    type_register_static(&pit_info);
 }
 device_init(pit_register)
diff --git a/hw/i8259.c b/hw/i8259.c
index 7331e0e61c..7ae53805d7 100644
--- a/hw/i8259.c
+++ b/hw/i8259.c
@@ -26,6 +26,7 @@
 #include "isa.h"
 #include "monitor.h"
 #include "qemu-timer.h"
+#include "i8259_internal.h"
 
 /* debug PIC */
 //#define DEBUG_PIC
@@ -40,33 +41,6 @@
 //#define DEBUG_IRQ_LATENCY
 //#define DEBUG_IRQ_COUNT
 
-struct PicState {
-    ISADevice dev;
-    uint8_t last_irr; /* edge detection */
-    uint8_t irr; /* interrupt request register */
-    uint8_t imr; /* interrupt mask register */
-    uint8_t isr; /* interrupt service register */
-    uint8_t priority_add; /* highest irq priority */
-    uint8_t irq_base;
-    uint8_t read_reg_select;
-    uint8_t poll;
-    uint8_t special_mask;
-    uint8_t init_state;
-    uint8_t auto_eoi;
-    uint8_t rotate_on_auto_eoi;
-    uint8_t special_fully_nested_mode;
-    uint8_t init4; /* true if 4 byte init */
-    uint8_t single_mode; /* true if slave pic is not initialized */
-    uint8_t elcr; /* PIIX edge/trigger selection*/
-    uint8_t elcr_mask;
-    qemu_irq int_out[1];
-    uint32_t master; /* reflects /SP input pin */
-    uint32_t iobase;
-    uint32_t elcr_addr;
-    MemoryRegion base_io;
-    MemoryRegion elcr_io;
-};
-
 #if defined(DEBUG_PIC) || defined(DEBUG_IRQ_COUNT)
 static int irq_level[16];
 #endif
@@ -76,12 +50,12 @@ static uint64_t irq_count[16];
 #ifdef DEBUG_IRQ_LATENCY
 static int64_t irq_time[16];
 #endif
-PicState *isa_pic;
-static PicState *slave_pic;
+DeviceState *isa_pic;
+static PICCommonState *slave_pic;
 
 /* return the highest priority found in mask (highest = smallest
    number). Return 8 if no irq */
-static int get_priority(PicState *s, int mask)
+static int get_priority(PICCommonState *s, int mask)
 {
     int priority;
 
@@ -96,7 +70,7 @@ static int get_priority(PicState *s, int mask)
 }
 
 /* return the pic wanted interrupt. return -1 if none */
-static int pic_get_irq(PicState *s)
+static int pic_get_irq(PICCommonState *s)
 {
     int mask, cur_priority, priority;
 
@@ -125,7 +99,7 @@ static int pic_get_irq(PicState *s)
 }
 
 /* Update INT output. Must be called every time the output may have changed. */
-static void pic_update_irq(PicState *s)
+static void pic_update_irq(PICCommonState *s)
 {
     int irq;
 
@@ -142,7 +116,7 @@ static void pic_update_irq(PicState *s)
 /* set irq level. If an edge is detected, then the IRR is set to 1 */
 static void pic_set_irq(void *opaque, int irq, int level)
 {
-    PicState *s = opaque;
+    PICCommonState *s = opaque;
     int mask = 1 << irq;
 
 #if defined(DEBUG_PIC) || defined(DEBUG_IRQ_COUNT) || \
@@ -190,7 +164,7 @@ static void pic_set_irq(void *opaque, int irq, int level)
 }
 
 /* acknowledge interrupt 'irq' */
-static void pic_intack(PicState *s, int irq)
+static void pic_intack(PICCommonState *s, int irq)
 {
     if (s->auto_eoi) {
         if (s->rotate_on_auto_eoi) {
@@ -206,8 +180,9 @@ static void pic_intack(PicState *s, int irq)
     pic_update_irq(s);
 }
 
-int pic_read_irq(PicState *s)
+int pic_read_irq(DeviceState *d)
 {
+    PICCommonState *s = DO_UPCAST(PICCommonState, dev.qdev, d);
     int irq, irq2, intno;
 
     irq = pic_get_irq(s);
@@ -246,30 +221,15 @@ int pic_read_irq(PicState *s)
     return intno;
 }
 
-static void pic_init_reset(PicState *s)
+static void pic_init_reset(PICCommonState *s)
 {
-    s->last_irr = 0;
-    s->irr = 0;
-    s->imr = 0;
-    s->isr = 0;
-    s->priority_add = 0;
-    s->irq_base = 0;
-    s->read_reg_select = 0;
-    s->poll = 0;
-    s->special_mask = 0;
-    s->init_state = 0;
-    s->auto_eoi = 0;
-    s->rotate_on_auto_eoi = 0;
-    s->special_fully_nested_mode = 0;
-    s->init4 = 0;
-    s->single_mode = 0;
-    /* Note: ELCR is not reset */
+    pic_reset_common(s);
     pic_update_irq(s);
 }
 
 static void pic_reset(DeviceState *dev)
 {
-    PicState *s = container_of(dev, PicState, dev.qdev);
+    PICCommonState *s = DO_UPCAST(PICCommonState, dev.qdev, dev);
 
     pic_init_reset(s);
     s->elcr = 0;
@@ -278,7 +238,7 @@ static void pic_reset(DeviceState *dev)
 static void pic_ioport_write(void *opaque, target_phys_addr_t addr64,
                              uint64_t val64, unsigned size)
 {
-    PicState *s = opaque;
+    PICCommonState *s = opaque;
     uint32_t addr = addr64;
     uint32_t val = val64;
     int priority, cmd, irq;
@@ -372,7 +332,7 @@ static void pic_ioport_write(void *opaque, target_phys_addr_t addr64,
 static uint64_t pic_ioport_read(void *opaque, target_phys_addr_t addr,
                                 unsigned size)
 {
-    PicState *s = opaque;
+    PICCommonState *s = opaque;
     int ret;
 
     if (s->poll) {
@@ -399,51 +359,27 @@ static uint64_t pic_ioport_read(void *opaque, target_phys_addr_t addr,
     return ret;
 }
 
-int pic_get_output(PicState *s)
+int pic_get_output(DeviceState *d)
 {
+    PICCommonState *s = DO_UPCAST(PICCommonState, dev.qdev, d);
+
     return (pic_get_irq(s) >= 0);
 }
 
 static void elcr_ioport_write(void *opaque, target_phys_addr_t addr,
                               uint64_t val, unsigned size)
 {
-    PicState *s = opaque;
+    PICCommonState *s = opaque;
     s->elcr = val & s->elcr_mask;
 }
 
 static uint64_t elcr_ioport_read(void *opaque, target_phys_addr_t addr,
                                  unsigned size)
 {
-    PicState *s = opaque;
+    PICCommonState *s = opaque;
     return s->elcr;
 }
 
-static const VMStateDescription vmstate_pic = {
-    .name = "i8259",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields = (VMStateField[]) {
-        VMSTATE_UINT8(last_irr, PicState),
-        VMSTATE_UINT8(irr, PicState),
-        VMSTATE_UINT8(imr, PicState),
-        VMSTATE_UINT8(isr, PicState),
-        VMSTATE_UINT8(priority_add, PicState),
-        VMSTATE_UINT8(irq_base, PicState),
-        VMSTATE_UINT8(read_reg_select, PicState),
-        VMSTATE_UINT8(poll, PicState),
-        VMSTATE_UINT8(special_mask, PicState),
-        VMSTATE_UINT8(init_state, PicState),
-        VMSTATE_UINT8(auto_eoi, PicState),
-        VMSTATE_UINT8(rotate_on_auto_eoi, PicState),
-        VMSTATE_UINT8(special_fully_nested_mode, PicState),
-        VMSTATE_UINT8(init4, PicState),
-        VMSTATE_UINT8(single_mode, PicState),
-        VMSTATE_UINT8(elcr, PicState),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
 static const MemoryRegionOps pic_base_ioport_ops = {
     .read = pic_ioport_read,
     .write = pic_ioport_write,
@@ -462,36 +398,25 @@ static const MemoryRegionOps pic_elcr_ioport_ops = {
     },
 };
 
-static int pic_initfn(ISADevice *dev)
+static void pic_init(PICCommonState *s)
 {
-    PicState *s = DO_UPCAST(PicState, dev, dev);
-
     memory_region_init_io(&s->base_io, &pic_base_ioport_ops, s, "pic", 2);
     memory_region_init_io(&s->elcr_io, &pic_elcr_ioport_ops, s, "elcr", 1);
 
-    isa_register_ioport(dev, &s->base_io, s->iobase);
-    if (s->elcr_addr != -1) {
-        isa_register_ioport(dev, &s->elcr_io, s->elcr_addr);
-    }
-
-    qdev_init_gpio_out(&dev->qdev, s->int_out, ARRAY_SIZE(s->int_out));
-    qdev_init_gpio_in(&dev->qdev, pic_set_irq, 8);
-
-    qdev_set_legacy_instance_id(&dev->qdev, s->iobase, 1);
-
-    return 0;
+    qdev_init_gpio_out(&s->dev.qdev, s->int_out, ARRAY_SIZE(s->int_out));
+    qdev_init_gpio_in(&s->dev.qdev, pic_set_irq, 8);
 }
 
 void pic_info(Monitor *mon)
 {
     int i;
-    PicState *s;
+    PICCommonState *s;
 
     if (!isa_pic) {
         return;
     }
     for (i = 0; i < 2; i++) {
-        s = i == 0 ? isa_pic : slave_pic;
+        s = i == 0 ? DO_UPCAST(PICCommonState, dev.qdev, isa_pic) : slave_pic;
         monitor_printf(mon, "pic%d: irr=%02x imr=%02x isr=%02x hprio=%d "
                        "irq_base=%02x rr_sel=%d elcr=%02x fnm=%d\n",
                        i, s->irr, s->imr, s->isr, s->priority_add,
@@ -526,54 +451,46 @@ qemu_irq *i8259_init(ISABus *bus, qemu_irq parent_irq)
 
     irq_set = g_malloc(ISA_NUM_IRQS * sizeof(qemu_irq));
 
-    dev = isa_create(bus, "isa-i8259");
-    qdev_prop_set_uint32(&dev->qdev, "iobase", 0x20);
-    qdev_prop_set_uint32(&dev->qdev, "elcr_addr", 0x4d0);
-    qdev_prop_set_uint8(&dev->qdev, "elcr_mask", 0xf8);
-    qdev_prop_set_bit(&dev->qdev, "master", true);
-    qdev_init_nofail(&dev->qdev);
+    dev = i8259_init_chip("isa-i8259", bus, true);
 
     qdev_connect_gpio_out(&dev->qdev, 0, parent_irq);
     for (i = 0 ; i < 8; i++) {
         irq_set[i] = qdev_get_gpio_in(&dev->qdev, i);
     }
 
-    isa_pic = DO_UPCAST(PicState, dev, dev);
+    isa_pic = &dev->qdev;
 
-    dev = isa_create(bus, "isa-i8259");
-    qdev_prop_set_uint32(&dev->qdev, "iobase", 0xa0);
-    qdev_prop_set_uint32(&dev->qdev, "elcr_addr", 0x4d1);
-    qdev_prop_set_uint8(&dev->qdev, "elcr_mask", 0xde);
-    qdev_init_nofail(&dev->qdev);
+    dev = i8259_init_chip("isa-i8259", bus, false);
 
     qdev_connect_gpio_out(&dev->qdev, 0, irq_set[2]);
     for (i = 0 ; i < 8; i++) {
         irq_set[i + 8] = qdev_get_gpio_in(&dev->qdev, i);
     }
 
-    slave_pic = DO_UPCAST(PicState, dev, dev);
+    slave_pic = DO_UPCAST(PICCommonState, dev, dev);
 
     return irq_set;
 }
 
-static ISADeviceInfo i8259_info = {
-    .qdev.name     = "isa-i8259",
-    .qdev.size     = sizeof(PicState),
-    .qdev.vmsd     = &vmstate_pic,
-    .qdev.reset    = pic_reset,
-    .qdev.no_user  = 1,
-    .init          = pic_initfn,
-    .qdev.props = (Property[]) {
-        DEFINE_PROP_HEX32("iobase", PicState, iobase,  -1),
-        DEFINE_PROP_HEX32("elcr_addr", PicState, elcr_addr,  -1),
-        DEFINE_PROP_HEX8("elcr_mask", PicState, elcr_mask,  -1),
-        DEFINE_PROP_BIT("master", PicState, master,  0, false),
-        DEFINE_PROP_END_OF_LIST(),
-    },
+static void i8259_class_init(ObjectClass *klass, void *data)
+{
+    PICCommonClass *k = PIC_COMMON_CLASS(klass);
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    k->init = pic_init;
+    dc->reset = pic_reset;
+}
+
+static TypeInfo i8259_info = {
+    .name       = "isa-i8259",
+    .instance_size = sizeof(PICCommonState),
+    .parent     = TYPE_PIC_COMMON,
+    .class_init = i8259_class_init,
 };
 
 static void pic_register(void)
 {
-    isa_qdev_register(&i8259_info);
+    type_register_static(&i8259_info);
 }
+
 device_init(pic_register)
diff --git a/hw/i8259_common.c b/hw/i8259_common.c
new file mode 100644
index 0000000000..9f150bc6d0
--- /dev/null
+++ b/hw/i8259_common.c
@@ -0,0 +1,161 @@
+/*
+ * QEMU 8259 - common bits of emulated and KVM kernel model
+ *
+ * Copyright (c) 2003-2004 Fabrice Bellard
+ * Copyright (c) 2011      Jan Kiszka, Siemens AG
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "pc.h"
+#include "i8259_internal.h"
+
+void pic_reset_common(PICCommonState *s)
+{
+    s->last_irr = 0;
+    s->irr = 0;
+    s->imr = 0;
+    s->isr = 0;
+    s->priority_add = 0;
+    s->irq_base = 0;
+    s->read_reg_select = 0;
+    s->poll = 0;
+    s->special_mask = 0;
+    s->init_state = 0;
+    s->auto_eoi = 0;
+    s->rotate_on_auto_eoi = 0;
+    s->special_fully_nested_mode = 0;
+    s->init4 = 0;
+    s->single_mode = 0;
+    /* Note: ELCR is not reset */
+}
+
+static void pic_dispatch_pre_save(void *opaque)
+{
+    PICCommonState *s = opaque;
+    PICCommonClass *info = PIC_COMMON_GET_CLASS(s);
+
+    if (info->pre_save) {
+        info->pre_save(s);
+    }
+}
+
+static int pic_dispatch_post_load(void *opaque, int version_id)
+{
+    PICCommonState *s = opaque;
+    PICCommonClass *info = PIC_COMMON_GET_CLASS(s);
+
+    if (info->post_load) {
+        info->post_load(s);
+    }
+    return 0;
+}
+
+static int pic_init_common(ISADevice *dev)
+{
+    PICCommonState *s = DO_UPCAST(PICCommonState, dev, dev);
+    PICCommonClass *info = PIC_COMMON_GET_CLASS(s);
+
+    info->init(s);
+
+    isa_register_ioport(NULL, &s->base_io, s->iobase);
+    if (s->elcr_addr != -1) {
+        isa_register_ioport(NULL, &s->elcr_io, s->elcr_addr);
+    }
+
+    qdev_set_legacy_instance_id(&s->dev.qdev, s->iobase, 1);
+
+    return 0;
+}
+
+ISADevice *i8259_init_chip(const char *name, ISABus *bus, bool master)
+{
+    ISADevice *dev;
+
+    dev = isa_create(bus, name);
+    qdev_prop_set_uint32(&dev->qdev, "iobase", master ? 0x20 : 0xa0);
+    qdev_prop_set_uint32(&dev->qdev, "elcr_addr", master ? 0x4d0 : 0x4d1);
+    qdev_prop_set_uint8(&dev->qdev, "elcr_mask", master ? 0xf8 : 0xde);
+    qdev_prop_set_bit(&dev->qdev, "master", master);
+    qdev_init_nofail(&dev->qdev);
+
+    return dev;
+}
+
+static const VMStateDescription vmstate_pic_common = {
+    .name = "i8259",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .pre_save = pic_dispatch_pre_save,
+    .post_load = pic_dispatch_post_load,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT8(last_irr, PICCommonState),
+        VMSTATE_UINT8(irr, PICCommonState),
+        VMSTATE_UINT8(imr, PICCommonState),
+        VMSTATE_UINT8(isr, PICCommonState),
+        VMSTATE_UINT8(priority_add, PICCommonState),
+        VMSTATE_UINT8(irq_base, PICCommonState),
+        VMSTATE_UINT8(read_reg_select, PICCommonState),
+        VMSTATE_UINT8(poll, PICCommonState),
+        VMSTATE_UINT8(special_mask, PICCommonState),
+        VMSTATE_UINT8(init_state, PICCommonState),
+        VMSTATE_UINT8(auto_eoi, PICCommonState),
+        VMSTATE_UINT8(rotate_on_auto_eoi, PICCommonState),
+        VMSTATE_UINT8(special_fully_nested_mode, PICCommonState),
+        VMSTATE_UINT8(init4, PICCommonState),
+        VMSTATE_UINT8(single_mode, PICCommonState),
+        VMSTATE_UINT8(elcr, PICCommonState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static Property pic_properties_common[] = {
+    DEFINE_PROP_HEX32("iobase", PICCommonState, iobase,  -1),
+    DEFINE_PROP_HEX32("elcr_addr", PICCommonState, elcr_addr,  -1),
+    DEFINE_PROP_HEX8("elcr_mask", PICCommonState, elcr_mask,  -1),
+    DEFINE_PROP_BIT("master", PICCommonState, master,  0, false),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void pic_common_class_init(ObjectClass *klass, void *data)
+{
+    ISADeviceClass *ic = ISA_DEVICE_CLASS(klass);
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    dc->vmsd = &vmstate_pic_common;
+    dc->no_user = 1;
+    dc->props = pic_properties_common;
+    ic->init = pic_init_common;
+}
+
+static TypeInfo pic_common_type = {
+    .name = TYPE_PIC_COMMON,
+    .parent = TYPE_ISA_DEVICE,
+    .instance_size = sizeof(PICCommonState),
+    .class_size = sizeof(PICCommonClass),
+    .class_init = pic_common_class_init,
+    .abstract = true,
+};
+
+static void register_devices(void)
+{
+    type_register_static(&pic_common_type);
+}
+
+device_init(register_devices);
diff --git a/hw/i8259_internal.h b/hw/i8259_internal.h
new file mode 100644
index 0000000000..4137b61703
--- /dev/null
+++ b/hw/i8259_internal.h
@@ -0,0 +1,82 @@
+/*
+ * QEMU 8259 - internal interfaces
+ *
+ * Copyright (c) 2011 Jan Kiszka, Siemens AG
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef QEMU_I8259_INTERNAL_H
+#define QEMU_I8259_INTERNAL_H
+
+#include "hw.h"
+#include "pc.h"
+#include "isa.h"
+
+typedef struct PICCommonState PICCommonState;
+
+#define TYPE_PIC_COMMON "pic-common"
+#define PIC_COMMON(obj) \
+     OBJECT_CHECK(PICCommon, (obj), TYPE_PIC_COMMON)
+#define PIC_COMMON_CLASS(klass) \
+     OBJECT_CLASS_CHECK(PICCommonClass, (klass), TYPE_PIC_COMMON)
+#define PIC_COMMON_GET_CLASS(obj) \
+     OBJECT_GET_CLASS(PICCommonClass, (obj), TYPE_PIC_COMMON)
+
+typedef struct PICCommonClass
+{
+    ISADeviceClass parent_class;
+    void (*init)(PICCommonState *s);
+    void (*pre_save)(PICCommonState *s);
+    void (*post_load)(PICCommonState *s);
+} PICCommonClass;
+
+struct PICCommonState {
+    ISADevice dev;
+    uint8_t last_irr; /* edge detection */
+    uint8_t irr; /* interrupt request register */
+    uint8_t imr; /* interrupt mask register */
+    uint8_t isr; /* interrupt service register */
+    uint8_t priority_add; /* highest irq priority */
+    uint8_t irq_base;
+    uint8_t read_reg_select;
+    uint8_t poll;
+    uint8_t special_mask;
+    uint8_t init_state;
+    uint8_t auto_eoi;
+    uint8_t rotate_on_auto_eoi;
+    uint8_t special_fully_nested_mode;
+    uint8_t init4; /* true if 4 byte init */
+    uint8_t single_mode; /* true if slave pic is not initialized */
+    uint8_t elcr; /* PIIX edge/trigger selection*/
+    uint8_t elcr_mask;
+    qemu_irq int_out[1];
+    uint32_t master; /* reflects /SP input pin */
+    uint32_t iobase;
+    uint32_t elcr_addr;
+    MemoryRegion base_io;
+    MemoryRegion elcr_io;
+};
+
+void pic_reset_common(PICCommonState *s);
+
+ISADevice *i8259_init_chip(const char *name, ISABus *bus, bool master);
+
+
+#endif /* !QEMU_I8259_INTERNAL_H */
diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c
index 0af201de2f..c87a6ca515 100644
--- a/hw/ide/ahci.c
+++ b/hw/ide/ahci.c
@@ -25,6 +25,7 @@
 #include <hw/msi.h>
 #include <hw/pc.h>
 #include <hw/pci.h>
+#include <hw/sysbus.h>
 
 #include "monitor.h"
 #include "dma.h"
@@ -1214,3 +1215,55 @@ void ahci_reset(void *opaque)
         ahci_reset_port(&d->ahci, i);
     }
 }
+
+typedef struct SysbusAHCIState {
+    SysBusDevice busdev;
+    AHCIState ahci;
+    uint32_t num_ports;
+} SysbusAHCIState;
+
+static const VMStateDescription vmstate_sysbus_ahci = {
+    .name = "sysbus-ahci",
+    .unmigratable = 1,
+};
+
+static int sysbus_ahci_init(SysBusDevice *dev)
+{
+    SysbusAHCIState *s = FROM_SYSBUS(SysbusAHCIState, dev);
+    ahci_init(&s->ahci, &dev->qdev, s->num_ports);
+
+    sysbus_init_mmio(dev, &s->ahci.mem);
+    sysbus_init_irq(dev, &s->ahci.irq);
+
+    qemu_register_reset(ahci_reset, &s->ahci);
+    return 0;
+}
+
+static Property sysbus_ahci_properties[] = {
+    DEFINE_PROP_UINT32("num-ports", SysbusAHCIState, num_ports, 1),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void sysbus_ahci_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass);
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    sbc->init = sysbus_ahci_init;
+    dc->vmsd = &vmstate_sysbus_ahci;
+    dc->props = sysbus_ahci_properties;
+}
+
+static TypeInfo sysbus_ahci_info = {
+    .name          = "sysbus-ahci",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(SysbusAHCIState),
+    .class_init    = sysbus_ahci_class_init,
+};
+
+static void sysbus_ahci_register(void)
+{
+    type_register_static(&sysbus_ahci_info);
+}
+
+device_init(sysbus_ahci_register);
diff --git a/hw/ide/cmd646.c b/hw/ide/cmd646.c
index 5fe98b1bb3..a119500f40 100644
--- a/hw/ide/cmd646.c
+++ b/hw/ide/cmd646.c
@@ -325,27 +325,34 @@ void pci_cmd646_ide_init(PCIBus *bus, DriveInfo **hd_table,
     pci_ide_create_devs(dev, hd_table);
 }
 
-static PCIDeviceInfo cmd646_ide_info[] = {
-    {
-        .qdev.name    = "cmd646-ide",
-        .qdev.size    = sizeof(PCIIDEState),
-        .init         = pci_cmd646_ide_initfn,
-        .exit         = pci_cmd646_ide_exitfn,
-        .vendor_id    = PCI_VENDOR_ID_CMD,
-        .device_id    = PCI_DEVICE_ID_CMD_646,
-        .revision     = 0x07, // IDE controller revision
-        .class_id     = PCI_CLASS_STORAGE_IDE,
-        .qdev.props   = (Property[]) {
-            DEFINE_PROP_UINT32("secondary", PCIIDEState, secondary, 0),
-            DEFINE_PROP_END_OF_LIST(),
-        },
-    },{
-        /* end of list */
-    }
+static Property cmd646_ide_properties[] = {
+    DEFINE_PROP_UINT32("secondary", PCIIDEState, secondary, 0),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void cmd646_ide_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->init = pci_cmd646_ide_initfn;
+    k->exit = pci_cmd646_ide_exitfn;
+    k->vendor_id = PCI_VENDOR_ID_CMD;
+    k->device_id = PCI_DEVICE_ID_CMD_646;
+    k->revision = 0x07;
+    k->class_id = PCI_CLASS_STORAGE_IDE;
+    dc->props = cmd646_ide_properties;
+}
+
+static TypeInfo cmd646_ide_info = {
+    .name          = "cmd646-ide",
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(PCIIDEState),
+    .class_init    = cmd646_ide_class_init,
 };
 
 static void cmd646_ide_register(void)
 {
-    pci_qdev_register_many(cmd646_ide_info);
+    type_register_static(&cmd646_ide_info);
 }
 device_init(cmd646_ide_register);
diff --git a/hw/ide/ich.c b/hw/ide/ich.c
index 3f7510f52e..5cdaa990ea 100644
--- a/hw/ide/ich.c
+++ b/hw/ide/ich.c
@@ -146,26 +146,30 @@ static void pci_ich9_write_config(PCIDevice *pci, uint32_t addr,
     msi_write_config(pci, addr, val, len);
 }
 
-static PCIDeviceInfo ich_ahci_info[] = {
-    {
-        .qdev.name    = "ich9-ahci",
-        .qdev.alias   = "ahci",
-        .qdev.size    = sizeof(AHCIPCIState),
-        .qdev.vmsd    = &vmstate_ahci,
-        .init         = pci_ich9_ahci_init,
-        .exit         = pci_ich9_uninit,
-        .config_write = pci_ich9_write_config,
-        .vendor_id    = PCI_VENDOR_ID_INTEL,
-        .device_id    = PCI_DEVICE_ID_INTEL_82801IR,
-        .revision     = 0x02,
-        .class_id     = PCI_CLASS_STORAGE_SATA,
-    },{
-        /* end of list */
-    }
+static void ich_ahci_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->init = pci_ich9_ahci_init;
+    k->exit = pci_ich9_uninit;
+    k->config_write = pci_ich9_write_config;
+    k->vendor_id = PCI_VENDOR_ID_INTEL;
+    k->device_id = PCI_DEVICE_ID_INTEL_82801IR;
+    k->revision = 0x02;
+    k->class_id = PCI_CLASS_STORAGE_SATA;
+    dc->vmsd = &vmstate_ahci;
+}
+
+static TypeInfo ich_ahci_info = {
+    .name          = "ich9-ahci",
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(AHCIPCIState),
+    .class_init    = ich_ahci_class_init,
 };
 
 static void ich_ahci_register(void)
 {
-    pci_qdev_register_many(ich_ahci_info);
+    type_register_static(&ich_ahci_info);
 }
 device_init(ich_ahci_register);
diff --git a/hw/ide/internal.h b/hw/ide/internal.h
index 00b28dfdbc..c808a0ddf8 100644
--- a/hw/ide/internal.h
+++ b/hw/ide/internal.h
@@ -21,7 +21,6 @@
 
 typedef struct IDEBus IDEBus;
 typedef struct IDEDevice IDEDevice;
-typedef struct IDEDeviceInfo IDEDeviceInfo;
 typedef struct IDEState IDEState;
 typedef struct IDEDMA IDEDMA;
 typedef struct IDEDMAOps IDEDMAOps;
@@ -450,6 +449,19 @@ struct IDEBus {
     int error_status;
 };
 
+#define TYPE_IDE_DEVICE "ide-device"
+#define IDE_DEVICE(obj) \
+     OBJECT_CHECK(IDEDevice, (obj), TYPE_IDE_DEVICE)
+#define IDE_DEVICE_CLASS(klass) \
+     OBJECT_CLASS_CHECK(IDEDeviceClass, (klass), TYPE_IDE_DEVICE)
+#define IDE_DEVICE_GET_CLASS(obj) \
+     OBJECT_GET_CLASS(IDEDeviceClass, (obj), TYPE_IDE_DEVICE)
+
+typedef struct IDEDeviceClass {
+    DeviceClass parent_class;
+    int (*init)(IDEDevice *dev);
+} IDEDeviceClass;
+
 struct IDEDevice {
     DeviceState qdev;
     uint32_t unit;
@@ -458,12 +470,6 @@ struct IDEDevice {
     char *serial;
 };
 
-typedef int (*ide_qdev_initfn)(IDEDevice *dev);
-struct IDEDeviceInfo {
-    DeviceInfo qdev;
-    ide_qdev_initfn init;
-};
-
 #define BM_STATUS_DMAING 0x01
 #define BM_STATUS_ERROR  0x02
 #define BM_STATUS_INT    0x04
diff --git a/hw/ide/isa.c b/hw/ide/isa.c
index 219f3a4c6b..a0bcb43eba 100644
--- a/hw/ide/isa.c
+++ b/hw/ide/isa.c
@@ -94,23 +94,33 @@ ISADevice *isa_ide_init(ISABus *bus, int iobase, int iobase2, int isairq,
     return dev;
 }
 
-static ISADeviceInfo isa_ide_info = {
-    .qdev.name  = "isa-ide",
-    .qdev.fw_name  = "ide",
-    .qdev.size  = sizeof(ISAIDEState),
-    .init       = isa_ide_initfn,
-    .qdev.reset = isa_ide_reset,
-    .qdev.props = (Property[]) {
-        DEFINE_PROP_HEX32("iobase",  ISAIDEState, iobase,  0x1f0),
-        DEFINE_PROP_HEX32("iobase2", ISAIDEState, iobase2, 0x3f6),
-        DEFINE_PROP_UINT32("irq",    ISAIDEState, isairq,  14),
-        DEFINE_PROP_END_OF_LIST(),
-    },
+static Property isa_ide_properties[] = {
+    DEFINE_PROP_HEX32("iobase",  ISAIDEState, iobase,  0x1f0),
+    DEFINE_PROP_HEX32("iobase2", ISAIDEState, iobase2, 0x3f6),
+    DEFINE_PROP_UINT32("irq",    ISAIDEState, isairq,  14),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void isa_ide_class_initfn(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    ISADeviceClass *ic = ISA_DEVICE_CLASS(klass);
+    ic->init = isa_ide_initfn;
+    dc->fw_name = "ide";
+    dc->reset = isa_ide_reset;
+    dc->props = isa_ide_properties;
+}
+
+static TypeInfo isa_ide_info = {
+    .name          = "isa-ide",
+    .parent        = TYPE_ISA_DEVICE,
+    .instance_size = sizeof(ISAIDEState),
+    .class_init    = isa_ide_class_initfn,
 };
 
 static void isa_ide_register_devices(void)
 {
-    isa_qdev_register(&isa_ide_info);
+    type_register_static(&isa_ide_info);
 }
 
 device_init(isa_ide_register_devices)
diff --git a/hw/ide/pci.c b/hw/ide/pci.c
index cb3de6537b..246dd5704b 100644
--- a/hw/ide/pci.c
+++ b/hw/ide/pci.c
@@ -327,7 +327,7 @@ void bmdma_cmd_writeb(BMDMAState *bm, uint32_t val)
     bm->cmd = val & 0x09;
 }
 
-static uint64_t bmdma_addr_read(void *opaque, dma_addr_t addr,
+static uint64_t bmdma_addr_read(void *opaque, target_phys_addr_t addr,
                                 unsigned width)
 {
     BMDMAState *bm = opaque;
@@ -341,7 +341,7 @@ static uint64_t bmdma_addr_read(void *opaque, dma_addr_t addr,
     return data;
 }
 
-static void bmdma_addr_write(void *opaque, dma_addr_t addr,
+static void bmdma_addr_write(void *opaque, target_phys_addr_t addr,
                              uint64_t data, unsigned width)
 {
     BMDMAState *bm = opaque;
diff --git a/hw/ide/piix.c b/hw/ide/piix.c
index 34733454ea..bf4465bb49 100644
--- a/hw/ide/piix.c
+++ b/hw/ide/piix.c
@@ -195,7 +195,6 @@ PCIDevice *pci_piix3_xen_ide_init(PCIBus *bus, DriveInfo **hd_table, int devfn)
     PCIDevice *dev;
 
     dev = pci_create_simple(bus, devfn, "piix3-ide-xen");
-    dev->qdev.info->unplug = pci_piix3_xen_ide_unplug;
     pci_ide_create_devs(dev, hd_table);
     return dev;
 }
@@ -238,42 +237,72 @@ PCIDevice *pci_piix4_ide_init(PCIBus *bus, DriveInfo **hd_table, int devfn)
     return dev;
 }
 
-static PCIDeviceInfo piix_ide_info[] = {
-    {
-        .qdev.name    = "piix3-ide",
-        .qdev.size    = sizeof(PCIIDEState),
-        .qdev.no_user = 1,
-        .no_hotplug   = 1,
-        .init         = pci_piix_ide_initfn,
-        .exit         = pci_piix_ide_exitfn,
-        .vendor_id    = PCI_VENDOR_ID_INTEL,
-        .device_id    = PCI_DEVICE_ID_INTEL_82371SB_1,
-        .class_id     = PCI_CLASS_STORAGE_IDE,
-    },{
-        .qdev.name    = "piix3-ide-xen",
-        .qdev.size    = sizeof(PCIIDEState),
-        .qdev.no_user = 1,
-        .init         = pci_piix_ide_initfn,
-        .vendor_id    = PCI_VENDOR_ID_INTEL,
-        .device_id    = PCI_DEVICE_ID_INTEL_82371SB_1,
-        .class_id     = PCI_CLASS_STORAGE_IDE,
-    },{
-        .qdev.name    = "piix4-ide",
-        .qdev.size    = sizeof(PCIIDEState),
-        .qdev.no_user = 1,
-        .no_hotplug   = 1,
-        .init         = pci_piix_ide_initfn,
-        .exit         = pci_piix_ide_exitfn,
-        .vendor_id    = PCI_VENDOR_ID_INTEL,
-        .device_id    = PCI_DEVICE_ID_INTEL_82371AB,
-        .class_id     = PCI_CLASS_STORAGE_IDE,
-    },{
-        /* end of list */
-    }
+static void piix3_ide_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->no_hotplug = 1;
+    k->init = pci_piix_ide_initfn;
+    k->exit = pci_piix_ide_exitfn;
+    k->vendor_id = PCI_VENDOR_ID_INTEL;
+    k->device_id = PCI_DEVICE_ID_INTEL_82371SB_1;
+    k->class_id = PCI_CLASS_STORAGE_IDE;
+    dc->no_user = 1;
+}
+
+static TypeInfo piix3_ide_info = {
+    .name          = "piix3-ide",
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(PCIIDEState),
+    .class_init    = piix3_ide_class_init,
+};
+
+static void piix3_ide_xen_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->init = pci_piix_ide_initfn;
+    k->vendor_id = PCI_VENDOR_ID_INTEL;
+    k->device_id = PCI_DEVICE_ID_INTEL_82371SB_1;
+    k->class_id = PCI_CLASS_STORAGE_IDE;
+    dc->no_user = 1;
+    dc->unplug = pci_piix3_xen_ide_unplug;
+}
+
+static TypeInfo piix3_ide_xen_info = {
+    .name          = "piix3-ide-xen",
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(PCIIDEState),
+    .class_init    = piix3_ide_xen_class_init,
+};
+
+static void piix4_ide_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->no_hotplug = 1;
+    k->init = pci_piix_ide_initfn;
+    k->exit = pci_piix_ide_exitfn;
+    k->vendor_id = PCI_VENDOR_ID_INTEL;
+    k->device_id = PCI_DEVICE_ID_INTEL_82371AB;
+    k->class_id = PCI_CLASS_STORAGE_IDE;
+    dc->no_user = 1;
+}
+
+static TypeInfo piix4_ide_info = {
+    .name          = "piix4-ide",
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(PCIIDEState),
+    .class_init    = piix4_ide_class_init,
 };
 
 static void piix_ide_register(void)
 {
-    pci_qdev_register_many(piix_ide_info);
+    type_register_static(&piix3_ide_info);
+    type_register_static(&piix3_ide_xen_info);
+    type_register_static(&piix4_ide_info);
 }
 device_init(piix_ide_register);
diff --git a/hw/ide/qdev.c b/hw/ide/qdev.c
index 42071277bb..1640616906 100644
--- a/hw/ide/qdev.c
+++ b/hw/ide/qdev.c
@@ -53,10 +53,10 @@ static char *idebus_get_fw_dev_path(DeviceState *dev)
     return strdup(path);
 }
 
-static int ide_qdev_init(DeviceState *qdev, DeviceInfo *base)
+static int ide_qdev_init(DeviceState *qdev)
 {
-    IDEDevice *dev = DO_UPCAST(IDEDevice, qdev, qdev);
-    IDEDeviceInfo *info = DO_UPCAST(IDEDeviceInfo, qdev, base);
+    IDEDevice *dev = IDE_DEVICE(qdev);
+    IDEDeviceClass *dc = IDE_DEVICE_GET_CLASS(dev);
     IDEBus *bus = DO_UPCAST(IDEBus, qbus, qdev->parent_bus);
 
     if (!dev->conf.bs) {
@@ -85,19 +85,12 @@ static int ide_qdev_init(DeviceState *qdev, DeviceInfo *base)
         error_report("Invalid IDE unit %d", dev->unit);
         goto err;
     }
-    return info->init(dev);
+    return dc->init(dev);
 
 err:
     return -1;
 }
 
-static void ide_qdev_register(IDEDeviceInfo *info)
-{
-    info->qdev.init = ide_qdev_init;
-    info->qdev.bus_info = &ide_bus_info;
-    qdev_register(&info->qdev);
-}
-
 IDEDevice *ide_create_drive(IDEBus *bus, int unit, DriveInfo *drive)
 {
     DeviceState *dev;
@@ -182,46 +175,93 @@ static int ide_drive_initfn(IDEDevice *dev)
     DEFINE_PROP_STRING("ver",  IDEDrive, dev.version),  \
     DEFINE_PROP_STRING("serial",  IDEDrive, dev.serial)
 
-static IDEDeviceInfo ide_dev_info[] = {
-    {
-        .qdev.name    = "ide-hd",
-        .qdev.fw_name = "drive",
-        .qdev.desc    = "virtual IDE disk",
-        .qdev.size    = sizeof(IDEDrive),
-        .init         = ide_hd_initfn,
-        .qdev.props   = (Property[]) {
-            DEFINE_IDE_DEV_PROPERTIES(),
-            DEFINE_PROP_END_OF_LIST(),
-        }
-    },{
-        .qdev.name    = "ide-cd",
-        .qdev.fw_name = "drive",
-        .qdev.desc    = "virtual IDE CD-ROM",
-        .qdev.size    = sizeof(IDEDrive),
-        .init         = ide_cd_initfn,
-        .qdev.props   = (Property[]) {
-            DEFINE_IDE_DEV_PROPERTIES(),
-            DEFINE_PROP_END_OF_LIST(),
-        }
-    },{
-        .qdev.name    = "ide-drive", /* legacy -device ide-drive */
-        .qdev.fw_name = "drive",
-        .qdev.desc    = "virtual IDE disk or CD-ROM (legacy)",
-        .qdev.size    = sizeof(IDEDrive),
-        .init         = ide_drive_initfn,
-        .qdev.props   = (Property[]) {
-            DEFINE_IDE_DEV_PROPERTIES(),
-            DEFINE_PROP_END_OF_LIST(),
-        }
-    }
+static Property ide_hd_properties[] = {
+    DEFINE_IDE_DEV_PROPERTIES(),
+    DEFINE_PROP_END_OF_LIST(),
 };
 
-static void ide_dev_register(void)
+static void ide_hd_class_init(ObjectClass *klass, void *data)
 {
-    int i;
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    IDEDeviceClass *k = IDE_DEVICE_CLASS(klass);
+    k->init = ide_hd_initfn;
+    dc->fw_name = "drive";
+    dc->desc = "virtual IDE disk";
+    dc->props = ide_hd_properties;
+}
 
-    for (i = 0; i < ARRAY_SIZE(ide_dev_info); i++) {
-        ide_qdev_register(&ide_dev_info[i]);
-    }
+static TypeInfo ide_hd_info = {
+    .name          = "ide-hd",
+    .parent        = TYPE_IDE_DEVICE,
+    .instance_size = sizeof(IDEDrive),
+    .class_init    = ide_hd_class_init,
+};
+
+static Property ide_cd_properties[] = {
+    DEFINE_IDE_DEV_PROPERTIES(),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void ide_cd_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    IDEDeviceClass *k = IDE_DEVICE_CLASS(klass);
+    k->init = ide_cd_initfn;
+    dc->fw_name = "drive";
+    dc->desc = "virtual IDE CD-ROM";
+    dc->props = ide_cd_properties;
+}
+
+static TypeInfo ide_cd_info = {
+    .name          = "ide-cd",
+    .parent        = TYPE_IDE_DEVICE,
+    .instance_size = sizeof(IDEDrive),
+    .class_init    = ide_cd_class_init,
+};
+
+static Property ide_drive_properties[] = {
+    DEFINE_IDE_DEV_PROPERTIES(),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void ide_drive_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    IDEDeviceClass *k = IDE_DEVICE_CLASS(klass);
+    k->init = ide_drive_initfn;
+    dc->fw_name = "drive";
+    dc->desc = "virtual IDE disk or CD-ROM (legacy)";
+    dc->props = ide_drive_properties;
+}
+
+static TypeInfo ide_drive_info = {
+    .name          = "ide-drive",
+    .parent        = TYPE_IDE_DEVICE,
+    .instance_size = sizeof(IDEDrive),
+    .class_init    = ide_drive_class_init,
+};
+
+static void ide_device_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *k = DEVICE_CLASS(klass);
+    k->init = ide_qdev_init;
+    k->bus_info = &ide_bus_info;
+}
+
+static TypeInfo ide_device_type_info = {
+    .name = TYPE_IDE_DEVICE,
+    .parent = TYPE_DEVICE,
+    .instance_size = sizeof(IDEDevice),
+    .abstract = true,
+    .class_size = sizeof(IDEDeviceClass),
+    .class_init = ide_device_class_init,
+};
+
+static void ide_dev_register(void)
+{
+    type_register_static(&ide_hd_info);
+    type_register_static(&ide_cd_info);
+    type_register_static(&ide_drive_info);
+    type_register_static(&ide_device_type_info);
 }
 device_init(ide_dev_register);
diff --git a/hw/ide/via.c b/hw/ide/via.c
index 4ea2064498..b4ca6f27b3 100644
--- a/hw/ide/via.c
+++ b/hw/ide/via.c
@@ -213,20 +213,29 @@ void vt82c686b_ide_init(PCIBus *bus, DriveInfo **hd_table, int devfn)
     pci_ide_create_devs(dev, hd_table);
 }
 
-static PCIDeviceInfo via_ide_info = {
-    .qdev.name    = "via-ide",
-    .qdev.size    = sizeof(PCIIDEState),
-    .qdev.no_user = 1,
-    .init         = vt82c686b_ide_initfn,
-    .exit         = vt82c686b_ide_exitfn,
-    .vendor_id    = PCI_VENDOR_ID_VIA,
-    .device_id    = PCI_DEVICE_ID_VIA_IDE,
-    .revision     = 0x06,
-    .class_id     = PCI_CLASS_STORAGE_IDE,
+static void via_ide_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->init = vt82c686b_ide_initfn;
+    k->exit = vt82c686b_ide_exitfn;
+    k->vendor_id = PCI_VENDOR_ID_VIA;
+    k->device_id = PCI_DEVICE_ID_VIA_IDE;
+    k->revision = 0x06;
+    k->class_id = PCI_CLASS_STORAGE_IDE;
+    dc->no_user = 1;
+}
+
+static TypeInfo via_ide_info = {
+    .name          = "via-ide",
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(PCIIDEState),
+    .class_init    = via_ide_class_init,
 };
 
 static void via_ide_register(void)
 {
-    pci_qdev_register(&via_ide_info);
+    type_register_static(&via_ide_info);
 }
 device_init(via_ide_register);
diff --git a/hw/integratorcp.c b/hw/integratorcp.c
index e5712fc3e7..6dbd649908 100644
--- a/hw/integratorcp.c
+++ b/hw/integratorcp.c
@@ -518,20 +518,45 @@ static void integratorcp_machine_init(void)
 
 machine_init(integratorcp_machine_init);
 
-static SysBusDeviceInfo core_info = {
-    .init = integratorcm_init,
-    .qdev.name  = "integrator_core",
-    .qdev.size  = sizeof(integratorcm_state),
-    .qdev.props = (Property[]) {
-        DEFINE_PROP_UINT32("memsz", integratorcm_state, memsz, 0),
-        DEFINE_PROP_END_OF_LIST(),
-    }
+static Property core_properties[] = {
+    DEFINE_PROP_UINT32("memsz", integratorcm_state, memsz, 0),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void core_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = integratorcm_init;
+    dc->props = core_properties;
+}
+
+static TypeInfo core_info = {
+    .name          = "integrator_core",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(integratorcm_state),
+    .class_init    = core_class_init,
+};
+
+static void icp_pic_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+
+    sdc->init = icp_pic_init;
+}
+
+static TypeInfo icp_pic_info = {
+    .name          = "integrator_pic",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(icp_pic_state),
+    .class_init    = icp_pic_class_init,
 };
 
 static void integratorcp_register_devices(void)
 {
-    sysbus_register_dev("integrator_pic", sizeof(icp_pic_state), icp_pic_init);
-    sysbus_register_withprop(&core_info);
+    type_register_static(&icp_pic_info);
+    type_register_static(&core_info);
 }
 
 device_init(integratorcp_register_devices)
diff --git a/hw/intel-hda.c b/hw/intel-hda.c
index 10769e0f49..83c42d58b6 100644
--- a/hw/intel-hda.c
+++ b/hw/intel-hda.c
@@ -47,13 +47,12 @@ void hda_codec_bus_init(DeviceState *dev, HDACodecBus *bus,
     bus->xfer = xfer;
 }
 
-static int hda_codec_dev_init(DeviceState *qdev, DeviceInfo *base)
+static int hda_codec_dev_init(DeviceState *qdev)
 {
     HDACodecBus *bus = DO_UPCAST(HDACodecBus, qbus, qdev->parent_bus);
     HDACodecDevice *dev = DO_UPCAST(HDACodecDevice, qdev, qdev);
-    HDACodecDeviceInfo *info = DO_UPCAST(HDACodecDeviceInfo, qdev, base);
+    HDACodecDeviceClass *cdc = HDA_CODEC_DEVICE_GET_CLASS(dev);
 
-    dev->info = info;
     if (dev->cad == -1) {
         dev->cad = bus->next_cad;
     }
@@ -61,27 +60,20 @@ static int hda_codec_dev_init(DeviceState *qdev, DeviceInfo *base)
         return -1;
     }
     bus->next_cad = dev->cad + 1;
-    return info->init(dev);
+    return cdc->init(dev);
 }
 
 static int hda_codec_dev_exit(DeviceState *qdev)
 {
     HDACodecDevice *dev = DO_UPCAST(HDACodecDevice, qdev, qdev);
+    HDACodecDeviceClass *cdc = HDA_CODEC_DEVICE_GET_CLASS(dev);
 
-    if (dev->info->exit) {
-        dev->info->exit(dev);
+    if (cdc->exit) {
+        cdc->exit(dev);
     }
     return 0;
 }
 
-void hda_codec_register(HDACodecDeviceInfo *info)
-{
-    info->qdev.init = hda_codec_dev_init;
-    info->qdev.exit = hda_codec_dev_exit;
-    info->qdev.bus_info = &hda_codec_bus_info;
-    qdev_register(&info->qdev);
-}
-
 HDACodecDevice *hda_codec_find(HDACodecBus *bus, uint32_t cad)
 {
     DeviceState *qdev;
@@ -283,6 +275,7 @@ static int intel_hda_send_command(IntelHDAState *d, uint32_t verb)
 {
     uint32_t cad, nid, data;
     HDACodecDevice *codec;
+    HDACodecDeviceClass *cdc;
 
     cad = (verb >> 28) & 0x0f;
     if (verb & (1 << 27)) {
@@ -298,7 +291,8 @@ static int intel_hda_send_command(IntelHDAState *d, uint32_t verb)
         dprint(d, 1, "%s: addressed non-existing codec\n", __FUNCTION__);
         return -1;
     }
-    codec->info->command(codec, nid, data);
+    cdc = HDA_CODEC_DEVICE_GET_CLASS(codec);
+    cdc->command(codec, nid, data);
     return 0;
 }
 
@@ -491,9 +485,12 @@ static void intel_hda_notify_codecs(IntelHDAState *d, uint32_t stream, bool runn
     HDACodecDevice *cdev;
 
     QTAILQ_FOREACH(qdev, &d->codecs.qbus.children, sibling) {
+        HDACodecDeviceClass *cdc;
+
         cdev = DO_UPCAST(HDACodecDevice, qdev, qdev);
-        if (cdev->info->stream) {
-            cdev->info->stream(cdev, stream, running, output);
+        cdc = HDA_CODEC_DEVICE_GET_CLASS(cdev);
+        if (cdc->stream) {
+            cdc->stream(cdev, stream, running, output);
         }
     }
 }
@@ -1116,9 +1113,7 @@ static void intel_hda_reset(DeviceState *dev)
     /* reset codecs */
     QTAILQ_FOREACH(qdev, &d->codecs.qbus.children, sibling) {
         cdev = DO_UPCAST(HDACodecDevice, qdev, qdev);
-        if (qdev->info->reset) {
-            qdev->info->reset(qdev);
-        }
+        device_reset(DEVICE(cdev));
         d->state_sts |= (1 << cdev->cad);
     }
     intel_hda_update_irq(d);
@@ -1129,7 +1124,7 @@ static int intel_hda_init(PCIDevice *pci)
     IntelHDAState *d = DO_UPCAST(IntelHDAState, pci, pci);
     uint8_t *conf = d->pci.config;
 
-    d->name = d->pci.qdev.info->name;
+    d->name = object_get_typename(OBJECT(d));
 
     pci_config_set_interrupt_pin(conf, 1);
 
@@ -1244,29 +1239,58 @@ static const VMStateDescription vmstate_intel_hda = {
     }
 };
 
-static PCIDeviceInfo intel_hda_info = {
-    .qdev.name    = "intel-hda",
-    .qdev.desc    = "Intel HD Audio Controller",
-    .qdev.size    = sizeof(IntelHDAState),
-    .qdev.vmsd    = &vmstate_intel_hda,
-    .qdev.reset   = intel_hda_reset,
-    .init         = intel_hda_init,
-    .exit         = intel_hda_exit,
-    .config_write = intel_hda_write_config,
-    .vendor_id    = PCI_VENDOR_ID_INTEL,
-    .device_id    = 0x2668,
-    .revision     = 1,
-    .class_id     = PCI_CLASS_MULTIMEDIA_HD_AUDIO,
-    .qdev.props   = (Property[]) {
-        DEFINE_PROP_UINT32("debug", IntelHDAState, debug, 0),
-        DEFINE_PROP_UINT32("msi", IntelHDAState, msi, 1),
-        DEFINE_PROP_END_OF_LIST(),
-    }
+static Property intel_hda_properties[] = {
+    DEFINE_PROP_UINT32("debug", IntelHDAState, debug, 0),
+    DEFINE_PROP_UINT32("msi", IntelHDAState, msi, 1),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void intel_hda_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    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;
+    k->class_id = PCI_CLASS_MULTIMEDIA_HD_AUDIO;
+    dc->desc = "Intel HD Audio Controller";
+    dc->reset = intel_hda_reset;
+    dc->vmsd = &vmstate_intel_hda;
+    dc->props = intel_hda_properties;
+}
+
+static TypeInfo intel_hda_info = {
+    .name          = "intel-hda",
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(IntelHDAState),
+    .class_init    = intel_hda_class_init,
+};
+
+static void hda_codec_device_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *k = DEVICE_CLASS(klass);
+    k->init = hda_codec_dev_init;
+    k->exit = hda_codec_dev_exit;
+    k->bus_info = &hda_codec_bus_info;
+}
+
+static TypeInfo hda_codec_device_type_info = {
+    .name = TYPE_HDA_CODEC_DEVICE,
+    .parent = TYPE_DEVICE,
+    .instance_size = sizeof(HDACodecDevice),
+    .abstract = true,
+    .class_size = sizeof(HDACodecDeviceClass),
+    .class_init = hda_codec_device_class_init,
 };
 
 static void intel_hda_register(void)
 {
-    pci_qdev_register(&intel_hda_info);
+    type_register_static(&intel_hda_info);
+    type_register_static(&hda_codec_device_type_info);
 }
 device_init(intel_hda_register);
 
diff --git a/hw/intel-hda.h b/hw/intel-hda.h
index 65fd2a85bb..a1cca5b1bb 100644
--- a/hw/intel-hda.h
+++ b/hw/intel-hda.h
@@ -6,9 +6,16 @@
 /* --------------------------------------------------------------------- */
 /* hda bus                                                               */
 
+#define TYPE_HDA_CODEC_DEVICE "hda-codec"
+#define HDA_CODEC_DEVICE(obj) \
+     OBJECT_CHECK(HDACodecDevice, (obj), TYPE_HDA_CODEC_DEVICE)
+#define HDA_CODEC_DEVICE_CLASS(klass) \
+     OBJECT_CLASS_CHECK(HDACodecDeviceClass, (klass), TYPE_HDA_CODEC_DEVICE)
+#define HDA_CODEC_DEVICE_GET_CLASS(obj) \
+     OBJECT_GET_CLASS(HDACodecDeviceClass, (obj), TYPE_HDA_CODEC_DEVICE)
+
 typedef struct HDACodecBus HDACodecBus;
 typedef struct HDACodecDevice HDACodecDevice;
-typedef struct HDACodecDeviceInfo HDACodecDeviceInfo;
 
 typedef void (*hda_codec_response_func)(HDACodecDevice *dev,
                                         bool solicited, uint32_t response);
@@ -23,24 +30,24 @@ struct HDACodecBus {
     hda_codec_xfer_func xfer;
 };
 
-struct HDACodecDevice {
-    DeviceState         qdev;
-    HDACodecDeviceInfo  *info;
-    uint32_t            cad;    /* codec address */
-};
+typedef struct HDACodecDeviceClass
+{
+    DeviceClass parent_class;
 
-struct HDACodecDeviceInfo {
-    DeviceInfo qdev;
     int (*init)(HDACodecDevice *dev);
     int (*exit)(HDACodecDevice *dev);
     void (*command)(HDACodecDevice *dev, uint32_t nid, uint32_t data);
     void (*stream)(HDACodecDevice *dev, uint32_t stnr, bool running, bool output);
+} HDACodecDeviceClass;
+
+struct HDACodecDevice {
+    DeviceState         qdev;
+    uint32_t            cad;    /* codec address */
 };
 
 void hda_codec_bus_init(DeviceState *dev, HDACodecBus *bus,
                         hda_codec_response_func response,
                         hda_codec_xfer_func xfer);
-void hda_codec_register(HDACodecDeviceInfo *info);
 HDACodecDevice *hda_codec_find(HDACodecBus *bus, uint32_t cad);
 
 void hda_codec_response(HDACodecDevice *dev, bool solicited, uint32_t response);
diff --git a/hw/ioapic.c b/hw/ioapic.c
index 27b07c6317..79549f8ed1 100644
--- a/hw/ioapic.c
+++ b/hw/ioapic.c
@@ -24,9 +24,7 @@
 #include "pc.h"
 #include "apic.h"
 #include "ioapic.h"
-#include "qemu-timer.h"
-#include "host-utils.h"
-#include "sysbus.h"
+#include "ioapic_internal.h"
 
 //#define DEBUG_IOAPIC
 
@@ -37,65 +35,9 @@
 #define DPRINTF(fmt, ...)
 #endif
 
-#define MAX_IOAPICS                     1
+static IOAPICCommonState *ioapics[MAX_IOAPICS];
 
-#define IOAPIC_VERSION                  0x11
-
-#define IOAPIC_LVT_DEST_SHIFT           56
-#define IOAPIC_LVT_MASKED_SHIFT         16
-#define IOAPIC_LVT_TRIGGER_MODE_SHIFT   15
-#define IOAPIC_LVT_REMOTE_IRR_SHIFT     14
-#define IOAPIC_LVT_POLARITY_SHIFT       13
-#define IOAPIC_LVT_DELIV_STATUS_SHIFT   12
-#define IOAPIC_LVT_DEST_MODE_SHIFT      11
-#define IOAPIC_LVT_DELIV_MODE_SHIFT     8
-
-#define IOAPIC_LVT_MASKED               (1 << IOAPIC_LVT_MASKED_SHIFT)
-#define IOAPIC_LVT_REMOTE_IRR           (1 << IOAPIC_LVT_REMOTE_IRR_SHIFT)
-
-#define IOAPIC_TRIGGER_EDGE             0
-#define IOAPIC_TRIGGER_LEVEL            1
-
-/*io{apic,sapic} delivery mode*/
-#define IOAPIC_DM_FIXED                 0x0
-#define IOAPIC_DM_LOWEST_PRIORITY       0x1
-#define IOAPIC_DM_PMI                   0x2
-#define IOAPIC_DM_NMI                   0x4
-#define IOAPIC_DM_INIT                  0x5
-#define IOAPIC_DM_SIPI                  0x6
-#define IOAPIC_DM_EXTINT                0x7
-#define IOAPIC_DM_MASK                  0x7
-
-#define IOAPIC_VECTOR_MASK              0xff
-
-#define IOAPIC_IOREGSEL                 0x00
-#define IOAPIC_IOWIN                    0x10
-
-#define IOAPIC_REG_ID                   0x00
-#define IOAPIC_REG_VER                  0x01
-#define IOAPIC_REG_ARB                  0x02
-#define IOAPIC_REG_REDTBL_BASE          0x10
-#define IOAPIC_ID                       0x00
-
-#define IOAPIC_ID_SHIFT                 24
-#define IOAPIC_ID_MASK                  0xf
-
-#define IOAPIC_VER_ENTRIES_SHIFT        16
-
-typedef struct IOAPICState IOAPICState;
-
-struct IOAPICState {
-    SysBusDevice busdev;
-    MemoryRegion io_memory;
-    uint8_t id;
-    uint8_t ioregsel;
-    uint32_t irr;
-    uint64_t ioredtbl[IOAPIC_NUM_PINS];
-};
-
-static IOAPICState *ioapics[MAX_IOAPICS];
-
-static void ioapic_service(IOAPICState *s)
+static void ioapic_service(IOAPICCommonState *s)
 {
     uint8_t i;
     uint8_t trig_mode;
@@ -135,7 +77,7 @@ static void ioapic_service(IOAPICState *s)
 
 static void ioapic_set_irq(void *opaque, int vector, int level)
 {
-    IOAPICState *s = opaque;
+    IOAPICCommonState *s = opaque;
 
     /* ISA IRQs map to GSI 1-1 except for IRQ0 which maps
      * to GSI 2.  GSI maps to ioapic 1-1.  This is not
@@ -174,7 +116,7 @@ static void ioapic_set_irq(void *opaque, int vector, int level)
 
 void ioapic_eoi_broadcast(int vector)
 {
-    IOAPICState *s;
+    IOAPICCommonState *s;
     uint64_t entry;
     int i, n;
 
@@ -199,7 +141,7 @@ void ioapic_eoi_broadcast(int vector)
 static uint64_t
 ioapic_mem_read(void *opaque, target_phys_addr_t addr, unsigned int size)
 {
-    IOAPICState *s = opaque;
+    IOAPICCommonState *s = opaque;
     int index;
     uint32_t val = 0;
 
@@ -242,7 +184,7 @@ static void
 ioapic_mem_write(void *opaque, target_phys_addr_t addr, uint64_t val,
                  unsigned int size)
 {
-    IOAPICState *s = opaque;
+    IOAPICCommonState *s = opaque;
     int index;
 
     switch (addr & 0xff) {
@@ -278,83 +220,40 @@ ioapic_mem_write(void *opaque, target_phys_addr_t addr, uint64_t val,
     }
 }
 
-static int ioapic_post_load(void *opaque, int version_id)
-{
-    IOAPICState *s = opaque;
-
-    if (version_id == 1) {
-        /* set sane value */
-        s->irr = 0;
-    }
-    return 0;
-}
-
-static const VMStateDescription vmstate_ioapic = {
-    .name = "ioapic",
-    .version_id = 3,
-    .post_load = ioapic_post_load,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields = (VMStateField[]) {
-        VMSTATE_UINT8(id, IOAPICState),
-        VMSTATE_UINT8(ioregsel, IOAPICState),
-        VMSTATE_UNUSED_V(2, 8), /* to account for qemu-kvm's v2 format */
-        VMSTATE_UINT32_V(irr, IOAPICState, 2),
-        VMSTATE_UINT64_ARRAY(ioredtbl, IOAPICState, IOAPIC_NUM_PINS),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static void ioapic_reset(DeviceState *d)
-{
-    IOAPICState *s = DO_UPCAST(IOAPICState, busdev.qdev, d);
-    int i;
-
-    s->id = 0;
-    s->ioregsel = 0;
-    s->irr = 0;
-    for (i = 0; i < IOAPIC_NUM_PINS; i++) {
-        s->ioredtbl[i] = 1 << IOAPIC_LVT_MASKED_SHIFT;
-    }
-}
-
 static const MemoryRegionOps ioapic_io_ops = {
     .read = ioapic_mem_read,
     .write = ioapic_mem_write,
     .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
-static int ioapic_init1(SysBusDevice *dev)
+static void ioapic_init(IOAPICCommonState *s, int instance_no)
 {
-    IOAPICState *s = FROM_SYSBUS(IOAPICState, dev);
-    static int ioapic_no;
-
-    if (ioapic_no >= MAX_IOAPICS) {
-        return -1;
-    }
-
     memory_region_init_io(&s->io_memory, &ioapic_io_ops, s, "ioapic", 0x1000);
-    sysbus_init_mmio(dev, &s->io_memory);
 
-    qdev_init_gpio_in(&dev->qdev, ioapic_set_irq, IOAPIC_NUM_PINS);
+    qdev_init_gpio_in(&s->busdev.qdev, ioapic_set_irq, IOAPIC_NUM_PINS);
+
+    ioapics[instance_no] = s;
+}
 
-    ioapics[ioapic_no++] = s;
+static void ioapic_class_init(ObjectClass *klass, void *data)
+{
+    IOAPICCommonClass *k = IOAPIC_COMMON_CLASS(klass);
+    DeviceClass *dc = DEVICE_CLASS(klass);
 
-    return 0;
+    k->init = ioapic_init;
+    dc->reset = ioapic_reset_common;
 }
 
-static SysBusDeviceInfo ioapic_info = {
-    .init = ioapic_init1,
-    .qdev.name = "ioapic",
-    .qdev.size = sizeof(IOAPICState),
-    .qdev.vmsd = &vmstate_ioapic,
-    .qdev.reset = ioapic_reset,
-    .qdev.no_user = 1,
+static TypeInfo ioapic_info = {
+    .name          = "ioapic",
+    .parent        = TYPE_IOAPIC_COMMON,
+    .instance_size = sizeof(IOAPICCommonState),
+    .class_init    = ioapic_class_init,
 };
 
 static void ioapic_register_devices(void)
 {
-    sysbus_register_withprop(&ioapic_info);
+    type_register_static(&ioapic_info);
 }
 
 device_init(ioapic_register_devices)
diff --git a/hw/ioapic_common.c b/hw/ioapic_common.c
new file mode 100644
index 0000000000..f932700d12
--- /dev/null
+++ b/hw/ioapic_common.c
@@ -0,0 +1,121 @@
+/*
+ *  IOAPIC emulation logic - common bits of emulated and KVM kernel model
+ *
+ *  Copyright (c) 2004-2005 Fabrice Bellard
+ *  Copyright (c) 2009      Xiantao Zhang, Intel
+ *  Copyright (c) 2011      Jan Kiszka, Siemens AG
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "ioapic.h"
+#include "ioapic_internal.h"
+#include "sysbus.h"
+
+void ioapic_reset_common(DeviceState *dev)
+{
+    IOAPICCommonState *s = IOAPIC_COMMON(dev);
+    int i;
+
+    s->id = 0;
+    s->ioregsel = 0;
+    s->irr = 0;
+    for (i = 0; i < IOAPIC_NUM_PINS; i++) {
+        s->ioredtbl[i] = 1 << IOAPIC_LVT_MASKED_SHIFT;
+    }
+}
+
+static void ioapic_dispatch_pre_save(void *opaque)
+{
+    IOAPICCommonState *s = IOAPIC_COMMON(opaque);
+    IOAPICCommonClass *info = IOAPIC_COMMON_GET_CLASS(s);
+
+    if (info->pre_save) {
+        info->pre_save(s);
+    }
+}
+
+static int ioapic_dispatch_post_load(void *opaque, int version_id)
+{
+    IOAPICCommonState *s = IOAPIC_COMMON(opaque);
+    IOAPICCommonClass *info = IOAPIC_COMMON_GET_CLASS(s);
+
+    if (info->post_load) {
+        info->post_load(s);
+    }
+    return 0;
+}
+
+static int ioapic_init_common(SysBusDevice *dev)
+{
+    IOAPICCommonState *s = FROM_SYSBUS(IOAPICCommonState, dev);
+    IOAPICCommonClass *info;
+    static int ioapic_no;
+
+    if (ioapic_no >= MAX_IOAPICS) {
+        return -1;
+    }
+
+    info = IOAPIC_COMMON_GET_CLASS(s);
+    info->init(s, ioapic_no);
+
+    sysbus_init_mmio(&s->busdev, &s->io_memory);
+    ioapic_no++;
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_ioapic_common = {
+    .name = "ioapic",
+    .version_id = 3,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .pre_save = ioapic_dispatch_pre_save,
+    .post_load = ioapic_dispatch_post_load,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT8(id, IOAPICCommonState),
+        VMSTATE_UINT8(ioregsel, IOAPICCommonState),
+        VMSTATE_UNUSED_V(2, 8), /* to account for qemu-kvm's v2 format */
+        VMSTATE_UINT32_V(irr, IOAPICCommonState, 2),
+        VMSTATE_UINT64_ARRAY(ioredtbl, IOAPICCommonState, IOAPIC_NUM_PINS),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void ioapic_common_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *sc = SYS_BUS_DEVICE_CLASS(klass);
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    sc->init = ioapic_init_common;
+    dc->vmsd = &vmstate_ioapic_common;
+    dc->no_user = 1;
+}
+
+static TypeInfo ioapic_common_type = {
+    .name = TYPE_IOAPIC_COMMON,
+    .parent = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(IOAPICCommonState),
+    .class_size = sizeof(IOAPICCommonClass),
+    .class_init = ioapic_common_class_init,
+    .abstract = true,
+};
+
+static void register_devices(void)
+{
+    type_register_static(&ioapic_common_type);
+}
+
+device_init(register_devices);
+
diff --git a/hw/ioapic_internal.h b/hw/ioapic_internal.h
new file mode 100644
index 0000000000..e04c9f3c12
--- /dev/null
+++ b/hw/ioapic_internal.h
@@ -0,0 +1,102 @@
+/*
+ *  IOAPIC emulation logic - internal interfaces
+ *
+ *  Copyright (c) 2004-2005 Fabrice Bellard
+ *  Copyright (c) 2009      Xiantao Zhang, Intel
+ *  Copyright (c) 2011 Jan Kiszka, Siemens AG
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef QEMU_IOAPIC_INTERNAL_H
+#define QEMU_IOAPIC_INTERNAL_H
+
+#include "hw.h"
+#include "memory.h"
+#include "sysbus.h"
+
+#define MAX_IOAPICS                     1
+
+#define IOAPIC_VERSION                  0x11
+
+#define IOAPIC_LVT_DEST_SHIFT           56
+#define IOAPIC_LVT_MASKED_SHIFT         16
+#define IOAPIC_LVT_TRIGGER_MODE_SHIFT   15
+#define IOAPIC_LVT_REMOTE_IRR_SHIFT     14
+#define IOAPIC_LVT_POLARITY_SHIFT       13
+#define IOAPIC_LVT_DELIV_STATUS_SHIFT   12
+#define IOAPIC_LVT_DEST_MODE_SHIFT      11
+#define IOAPIC_LVT_DELIV_MODE_SHIFT     8
+
+#define IOAPIC_LVT_MASKED               (1 << IOAPIC_LVT_MASKED_SHIFT)
+#define IOAPIC_LVT_REMOTE_IRR           (1 << IOAPIC_LVT_REMOTE_IRR_SHIFT)
+
+#define IOAPIC_TRIGGER_EDGE             0
+#define IOAPIC_TRIGGER_LEVEL            1
+
+/*io{apic,sapic} delivery mode*/
+#define IOAPIC_DM_FIXED                 0x0
+#define IOAPIC_DM_LOWEST_PRIORITY       0x1
+#define IOAPIC_DM_PMI                   0x2
+#define IOAPIC_DM_NMI                   0x4
+#define IOAPIC_DM_INIT                  0x5
+#define IOAPIC_DM_SIPI                  0x6
+#define IOAPIC_DM_EXTINT                0x7
+#define IOAPIC_DM_MASK                  0x7
+
+#define IOAPIC_VECTOR_MASK              0xff
+
+#define IOAPIC_IOREGSEL                 0x00
+#define IOAPIC_IOWIN                    0x10
+
+#define IOAPIC_REG_ID                   0x00
+#define IOAPIC_REG_VER                  0x01
+#define IOAPIC_REG_ARB                  0x02
+#define IOAPIC_REG_REDTBL_BASE          0x10
+#define IOAPIC_ID                       0x00
+
+#define IOAPIC_ID_SHIFT                 24
+#define IOAPIC_ID_MASK                  0xf
+
+#define IOAPIC_VER_ENTRIES_SHIFT        16
+
+typedef struct IOAPICCommonState IOAPICCommonState;
+
+#define TYPE_IOAPIC_COMMON "ioapic-common"
+#define IOAPIC_COMMON(obj) \
+     OBJECT_CHECK(IOAPICCommonState, (obj), TYPE_IOAPIC_COMMON)
+#define IOAPIC_COMMON_CLASS(klass) \
+     OBJECT_CLASS_CHECK(IOAPICCommonClass, (klass), TYPE_IOAPIC_COMMON)
+#define IOAPIC_COMMON_GET_CLASS(obj) \
+     OBJECT_GET_CLASS(IOAPICCommonClass, (obj), TYPE_IOAPIC_COMMON)
+
+typedef struct IOAPICCommonClass {
+    SysBusDeviceClass parent_class;
+    void (*init)(IOAPICCommonState *s, int instance_no);
+    void (*pre_save)(IOAPICCommonState *s);
+    void (*post_load)(IOAPICCommonState *s);
+} IOAPICCommonClass;
+
+struct IOAPICCommonState {
+    SysBusDevice busdev;
+    MemoryRegion io_memory;
+    uint8_t id;
+    uint8_t ioregsel;
+    uint32_t irr;
+    uint64_t ioredtbl[IOAPIC_NUM_PINS];
+};
+
+void ioapic_reset_common(DeviceState *dev);
+
+#endif /* !QEMU_IOAPIC_INTERNAL_H */
diff --git a/hw/ioh3420.c b/hw/ioh3420.c
index a6bfbb9173..1c60123d43 100644
--- a/hw/ioh3420.c
+++ b/hw/ioh3420.c
@@ -80,7 +80,7 @@ static void ioh3420_write_config(PCIDevice *d,
 
 static void ioh3420_reset(DeviceState *qdev)
 {
-    PCIDevice *d = DO_UPCAST(PCIDevice, qdev, qdev);
+    PCIDevice *d = PCI_DEVICE(qdev);
     msi_reset(d);
     ioh3420_aer_vector_update(d);
     pcie_cap_root_reset(d);
@@ -201,36 +201,45 @@ static const VMStateDescription vmstate_ioh3420 = {
     }
 };
 
-static PCIDeviceInfo ioh3420_info = {
-    .qdev.name = "ioh3420",
-    .qdev.desc = "Intel IOH device id 3420 PCIE Root Port",
-    .qdev.size = sizeof(PCIESlot),
-    .qdev.reset = ioh3420_reset,
-    .qdev.vmsd = &vmstate_ioh3420,
-
-    .is_express = 1,
-    .is_bridge = 1,
-    .config_write = ioh3420_write_config,
-    .init = ioh3420_initfn,
-    .exit = ioh3420_exitfn,
-    .vendor_id = PCI_VENDOR_ID_INTEL,
-    .device_id = PCI_DEVICE_ID_IOH_EPORT,
-    .revision = PCI_DEVICE_ID_IOH_REV,
-
-    .qdev.props = (Property[]) {
-        DEFINE_PROP_UINT8("port", PCIESlot, port.port, 0),
-        DEFINE_PROP_UINT8("chassis", PCIESlot, chassis, 0),
-        DEFINE_PROP_UINT16("slot", PCIESlot, slot, 0),
-        DEFINE_PROP_UINT16("aer_log_max", PCIESlot,
-                           port.br.dev.exp.aer_log.log_max,
-                           PCIE_AER_LOG_MAX_DEFAULT),
-        DEFINE_PROP_END_OF_LIST(),
-    }
+static Property ioh3420_properties[] = {
+    DEFINE_PROP_UINT8("port", PCIESlot, port.port, 0),
+    DEFINE_PROP_UINT8("chassis", PCIESlot, chassis, 0),
+    DEFINE_PROP_UINT16("slot", PCIESlot, slot, 0),
+    DEFINE_PROP_UINT16("aer_log_max", PCIESlot,
+    port.br.dev.exp.aer_log.log_max,
+    PCIE_AER_LOG_MAX_DEFAULT),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void ioh3420_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->is_express = 1;
+    k->is_bridge = 1;
+    k->config_write = ioh3420_write_config;
+    k->init = ioh3420_initfn;
+    k->exit = ioh3420_exitfn;
+    k->vendor_id = PCI_VENDOR_ID_INTEL;
+    k->device_id = PCI_DEVICE_ID_IOH_EPORT;
+    k->revision = PCI_DEVICE_ID_IOH_REV;
+    dc->desc = "Intel IOH device id 3420 PCIE Root Port";
+    dc->reset = ioh3420_reset;
+    dc->vmsd = &vmstate_ioh3420;
+    dc->props = ioh3420_properties;
+}
+
+static TypeInfo ioh3420_info = {
+    .name          = "ioh3420",
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(PCIESlot),
+    .class_init    = ioh3420_class_init,
 };
 
 static void ioh3420_register(void)
 {
-    pci_qdev_register(&ioh3420_info);
+    type_register_static(&ioh3420_info);
 }
 
 device_init(ioh3420_register);
diff --git a/hw/isa-bus.c b/hw/isa-bus.c
index 5af790bf81..d03f82824c 100644
--- a/hw/isa-bus.c
+++ b/hw/isa-bus.c
@@ -110,22 +110,19 @@ void isa_register_portio_list(ISADevice *dev, uint16_t start,
     portio_list_add(piolist, isabus->address_space_io, start);
 }
 
-static int isa_qdev_init(DeviceState *qdev, DeviceInfo *base)
+static int isa_qdev_init(DeviceState *qdev)
 {
-    ISADevice *dev = DO_UPCAST(ISADevice, qdev, qdev);
-    ISADeviceInfo *info = DO_UPCAST(ISADeviceInfo, qdev, base);
+    ISADevice *dev = ISA_DEVICE(qdev);
+    ISADeviceClass *klass = ISA_DEVICE_GET_CLASS(dev);
 
     dev->isairq[0] = -1;
     dev->isairq[1] = -1;
 
-    return info->init(dev);
-}
+    if (klass->init) {
+        return klass->init(dev);
+    }
 
-void isa_qdev_register(ISADeviceInfo *info)
-{
-    info->qdev.init = isa_qdev_init;
-    info->qdev.bus_info = &isa_bus_info;
-    qdev_register(&info->qdev);
+    return 0;
 }
 
 ISADevice *isa_create(ISABus *bus, const char *name)
@@ -137,7 +134,7 @@ ISADevice *isa_create(ISABus *bus, const char *name)
                  name);
     }
     dev = qdev_create(&bus->qbus, name);
-    return DO_UPCAST(ISADevice, qdev, dev);
+    return ISA_DEVICE(dev);
 }
 
 ISADevice *isa_try_create(ISABus *bus, const char *name)
@@ -149,7 +146,7 @@ ISADevice *isa_try_create(ISABus *bus, const char *name)
                  name);
     }
     dev = qdev_try_create(&bus->qbus, name);
-    return DO_UPCAST(ISADevice, qdev, dev);
+    return ISA_DEVICE(dev);
 }
 
 ISADevice *isa_create_simple(ISABus *bus, const char *name)
@@ -163,7 +160,7 @@ ISADevice *isa_create_simple(ISABus *bus, const char *name)
 
 static void isabus_dev_print(Monitor *mon, DeviceState *dev, int indent)
 {
-    ISADevice *d = DO_UPCAST(ISADevice, qdev, dev);
+    ISADevice *d = ISA_DEVICE(dev);
 
     if (d->isairq[1] != -1) {
         monitor_printf(mon, "%*sisa irqs %d,%d\n", indent, "",
@@ -180,17 +177,43 @@ static int isabus_bridge_init(SysBusDevice *dev)
     return 0;
 }
 
-static SysBusDeviceInfo isabus_bridge_info = {
-    .init = isabus_bridge_init,
-    .qdev.name  = "isabus-bridge",
-    .qdev.fw_name  = "isa",
-    .qdev.size  = sizeof(SysBusDevice),
-    .qdev.no_user = 1,
+static void isabus_bridge_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = isabus_bridge_init;
+    dc->fw_name = "isa";
+    dc->no_user = 1;
+}
+
+static TypeInfo isabus_bridge_info = {
+    .name          = "isabus-bridge",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(SysBusDevice),
+    .class_init    = isabus_bridge_class_init,
+};
+
+static void isa_device_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *k = DEVICE_CLASS(klass);
+    k->init = isa_qdev_init;
+    k->bus_info = &isa_bus_info;
+}
+
+static TypeInfo isa_device_type_info = {
+    .name = TYPE_ISA_DEVICE,
+    .parent = TYPE_DEVICE,
+    .instance_size = sizeof(ISADevice),
+    .abstract = true,
+    .class_size = sizeof(ISADeviceClass),
+    .class_init = isa_device_class_init,
 };
 
 static void isabus_register_devices(void)
 {
-    sysbus_register_withprop(&isabus_bridge_info);
+    type_register_static(&isabus_bridge_info);
+    type_register_static(&isa_device_type_info);
 }
 
 static char *isabus_get_fw_dev_path(DeviceState *dev)
diff --git a/hw/isa.h b/hw/isa.h
index b11a0be27f..40373fb107 100644
--- a/hw/isa.h
+++ b/hw/isa.h
@@ -10,7 +10,19 @@
 #define ISA_NUM_IRQS 16
 
 typedef struct ISADevice ISADevice;
-typedef struct ISADeviceInfo ISADeviceInfo;
+
+#define TYPE_ISA_DEVICE "isa-device"
+#define ISA_DEVICE(obj) \
+     OBJECT_CHECK(ISADevice, (obj), TYPE_ISA_DEVICE)
+#define ISA_DEVICE_CLASS(klass) \
+     OBJECT_CLASS_CHECK(ISADeviceClass, (klass), TYPE_ISA_DEVICE)
+#define ISA_DEVICE_GET_CLASS(obj) \
+     OBJECT_GET_CLASS(ISADeviceClass, (obj), TYPE_ISA_DEVICE)
+
+typedef struct ISADeviceClass {
+    DeviceClass parent_class;
+    int (*init)(ISADevice *dev);
+} ISADeviceClass;
 
 struct ISABus {
     BusState qbus;
@@ -25,17 +37,10 @@ struct ISADevice {
     int ioport_id;
 };
 
-typedef int (*isa_qdev_initfn)(ISADevice *dev);
-struct ISADeviceInfo {
-    DeviceInfo qdev;
-    isa_qdev_initfn init;
-};
-
 ISABus *isa_bus_new(DeviceState *dev, MemoryRegion *address_space_io);
 void isa_bus_irqs(ISABus *bus, qemu_irq *irqs);
 qemu_irq isa_get_irq(ISADevice *dev, int isairq);
 void isa_init_irq(ISADevice *dev, qemu_irq *p, int isairq);
-void isa_qdev_register(ISADeviceInfo *info);
 MemoryRegion *isa_address_space(ISADevice *dev);
 ISADevice *isa_create(ISABus *bus, const char *name);
 ISADevice *isa_try_create(ISABus *bus, const char *name);
diff --git a/hw/ivshmem.c b/hw/ivshmem.c
index bec2e0b8fe..6f017d474c 100644
--- a/hw/ivshmem.c
+++ b/hw/ivshmem.c
@@ -766,30 +766,41 @@ static int pci_ivshmem_uninit(PCIDevice *dev)
     return 0;
 }
 
-static PCIDeviceInfo ivshmem_info = {
-    .qdev.name  = "ivshmem",
-    .qdev.size  = sizeof(IVShmemState),
-    .qdev.reset = ivshmem_reset,
-    .init       = pci_ivshmem_init,
-    .exit       = pci_ivshmem_uninit,
-    .vendor_id  = PCI_VENDOR_ID_REDHAT_QUMRANET,
-    .device_id  = 0x1110,
-    .class_id   = PCI_CLASS_MEMORY_RAM,
-    .qdev.props = (Property[]) {
-        DEFINE_PROP_CHR("chardev", IVShmemState, server_chr),
-        DEFINE_PROP_STRING("size", IVShmemState, sizearg),
-        DEFINE_PROP_UINT32("vectors", IVShmemState, vectors, 1),
-        DEFINE_PROP_BIT("ioeventfd", IVShmemState, features, IVSHMEM_IOEVENTFD, false),
-        DEFINE_PROP_BIT("msi", IVShmemState, features, IVSHMEM_MSI, true),
-        DEFINE_PROP_STRING("shm", IVShmemState, shmobj),
-        DEFINE_PROP_STRING("role", IVShmemState, role),
-        DEFINE_PROP_END_OF_LIST(),
-    }
+static Property ivshmem_properties[] = {
+    DEFINE_PROP_CHR("chardev", IVShmemState, server_chr),
+    DEFINE_PROP_STRING("size", IVShmemState, sizearg),
+    DEFINE_PROP_UINT32("vectors", IVShmemState, vectors, 1),
+    DEFINE_PROP_BIT("ioeventfd", IVShmemState, features, IVSHMEM_IOEVENTFD, false),
+    DEFINE_PROP_BIT("msi", IVShmemState, features, IVSHMEM_MSI, true),
+    DEFINE_PROP_STRING("shm", IVShmemState, shmobj),
+    DEFINE_PROP_STRING("role", IVShmemState, role),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void ivshmem_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->init = pci_ivshmem_init;
+    k->exit = pci_ivshmem_uninit;
+    k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
+    k->device_id = 0x1110;
+    k->class_id = PCI_CLASS_MEMORY_RAM;
+    dc->reset = ivshmem_reset;
+    dc->props = ivshmem_properties;
+}
+
+static TypeInfo ivshmem_info = {
+    .name          = "ivshmem",
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(IVShmemState),
+    .class_init    = ivshmem_class_init,
 };
 
 static void ivshmem_register_devices(void)
 {
-    pci_qdev_register(&ivshmem_info);
+    type_register_static(&ivshmem_info);
 }
 
 device_init(ivshmem_register_devices)
diff --git a/hw/kvm/apic.c b/hw/kvm/apic.c
new file mode 100644
index 0000000000..dfc2ab3b03
--- /dev/null
+++ b/hw/kvm/apic.c
@@ -0,0 +1,147 @@
+/*
+ * KVM in-kernel APIC support
+ *
+ * Copyright (c) 2011 Siemens AG
+ *
+ * Authors:
+ *  Jan Kiszka          <jan.kiszka@siemens.com>
+ *
+ * This work is licensed under the terms of the GNU GPL version 2.
+ * See the COPYING file in the top-level directory.
+ */
+#include "hw/apic_internal.h"
+#include "kvm.h"
+
+static inline void kvm_apic_set_reg(struct kvm_lapic_state *kapic,
+                                    int reg_id, uint32_t val)
+{
+    *((uint32_t *)(kapic->regs + (reg_id << 4))) = val;
+}
+
+static inline uint32_t kvm_apic_get_reg(struct kvm_lapic_state *kapic,
+                                        int reg_id)
+{
+    return *((uint32_t *)(kapic->regs + (reg_id << 4)));
+}
+
+void kvm_put_apic_state(DeviceState *d, struct kvm_lapic_state *kapic)
+{
+    APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d);
+    int i;
+
+    memset(kapic, 0, sizeof(kapic));
+    kvm_apic_set_reg(kapic, 0x2, s->id << 24);
+    kvm_apic_set_reg(kapic, 0x8, s->tpr);
+    kvm_apic_set_reg(kapic, 0xd, s->log_dest << 24);
+    kvm_apic_set_reg(kapic, 0xe, s->dest_mode << 28 | 0x0fffffff);
+    kvm_apic_set_reg(kapic, 0xf, s->spurious_vec);
+    for (i = 0; i < 8; i++) {
+        kvm_apic_set_reg(kapic, 0x10 + i, s->isr[i]);
+        kvm_apic_set_reg(kapic, 0x18 + i, s->tmr[i]);
+        kvm_apic_set_reg(kapic, 0x20 + i, s->irr[i]);
+    }
+    kvm_apic_set_reg(kapic, 0x28, s->esr);
+    kvm_apic_set_reg(kapic, 0x30, s->icr[0]);
+    kvm_apic_set_reg(kapic, 0x31, s->icr[1]);
+    for (i = 0; i < APIC_LVT_NB; i++) {
+        kvm_apic_set_reg(kapic, 0x32 + i, s->lvt[i]);
+    }
+    kvm_apic_set_reg(kapic, 0x38, s->initial_count);
+    kvm_apic_set_reg(kapic, 0x3e, s->divide_conf);
+}
+
+void kvm_get_apic_state(DeviceState *d, struct kvm_lapic_state *kapic)
+{
+    APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d);
+    int i, v;
+
+    s->id = kvm_apic_get_reg(kapic, 0x2) >> 24;
+    s->tpr = kvm_apic_get_reg(kapic, 0x8);
+    s->arb_id = kvm_apic_get_reg(kapic, 0x9);
+    s->log_dest = kvm_apic_get_reg(kapic, 0xd) >> 24;
+    s->dest_mode = kvm_apic_get_reg(kapic, 0xe) >> 28;
+    s->spurious_vec = kvm_apic_get_reg(kapic, 0xf);
+    for (i = 0; i < 8; i++) {
+        s->isr[i] = kvm_apic_get_reg(kapic, 0x10 + i);
+        s->tmr[i] = kvm_apic_get_reg(kapic, 0x18 + i);
+        s->irr[i] = kvm_apic_get_reg(kapic, 0x20 + i);
+    }
+    s->esr = kvm_apic_get_reg(kapic, 0x28);
+    s->icr[0] = kvm_apic_get_reg(kapic, 0x30);
+    s->icr[1] = kvm_apic_get_reg(kapic, 0x31);
+    for (i = 0; i < APIC_LVT_NB; i++) {
+        s->lvt[i] = kvm_apic_get_reg(kapic, 0x32 + i);
+    }
+    s->initial_count = kvm_apic_get_reg(kapic, 0x38);
+    s->divide_conf = kvm_apic_get_reg(kapic, 0x3e);
+
+    v = (s->divide_conf & 3) | ((s->divide_conf >> 1) & 4);
+    s->count_shift = (v + 1) & 7;
+
+    s->initial_count_load_time = qemu_get_clock_ns(vm_clock);
+    apic_next_timer(s, s->initial_count_load_time);
+}
+
+static void kvm_apic_set_base(APICCommonState *s, uint64_t val)
+{
+    s->apicbase = val;
+}
+
+static void kvm_apic_set_tpr(APICCommonState *s, uint8_t val)
+{
+    s->tpr = (val & 0x0f) << 4;
+}
+
+static void do_inject_external_nmi(void *data)
+{
+    APICCommonState *s = data;
+    CPUState *env = s->cpu_env;
+    uint32_t lvt;
+    int ret;
+
+    cpu_synchronize_state(env);
+
+    lvt = s->lvt[APIC_LVT_LINT1];
+    if (!(lvt & APIC_LVT_MASKED) && ((lvt >> 8) & 7) == APIC_DM_NMI) {
+        ret = kvm_vcpu_ioctl(env, KVM_NMI);
+        if (ret < 0) {
+            fprintf(stderr, "KVM: injection failed, NMI lost (%s)\n",
+                    strerror(-ret));
+        }
+    }
+}
+
+static void kvm_apic_external_nmi(APICCommonState *s)
+{
+    run_on_cpu(s->cpu_env, do_inject_external_nmi, s);
+}
+
+static void kvm_apic_init(APICCommonState *s)
+{
+    memory_region_init_reservation(&s->io_memory, "kvm-apic-msi",
+                                   MSI_SPACE_SIZE);
+}
+
+static void kvm_apic_class_init(ObjectClass *klass, void *data)
+{
+    APICCommonClass *k = APIC_COMMON_CLASS(klass);
+
+    k->init = kvm_apic_init;
+    k->set_base = kvm_apic_set_base;
+    k->set_tpr = kvm_apic_set_tpr;
+    k->external_nmi = kvm_apic_external_nmi;
+}
+
+static TypeInfo kvm_apic_info = {
+    .name = "kvm-apic",
+    .parent = TYPE_APIC_COMMON,
+    .instance_size = sizeof(APICCommonState),
+    .class_init = kvm_apic_class_init,
+};
+
+static void kvm_apic_register_device(void)
+{
+    type_register_static(&kvm_apic_info);
+}
+
+device_init(kvm_apic_register_device)
diff --git a/hw/kvmclock.c b/hw/kvm/clock.c
index 3b9fb20495..d5a53869b3 100644
--- a/hw/kvmclock.c
+++ b/hw/kvm/clock.c
@@ -15,9 +15,9 @@
 
 #include "qemu-common.h"
 #include "sysemu.h"
-#include "sysbus.h"
 #include "kvm.h"
-#include "kvmclock.h"
+#include "hw/sysbus.h"
+#include "hw/kvm/clock.h"
 
 #include <linux/kvm.h>
 #include <linux/kvm_para.h>
@@ -92,12 +92,21 @@ static const VMStateDescription kvmclock_vmsd = {
     }
 };
 
-static SysBusDeviceInfo kvmclock_info = {
-    .qdev.name = "kvmclock",
-    .qdev.size = sizeof(KVMClockState),
-    .qdev.vmsd = &kvmclock_vmsd,
-    .qdev.no_user = 1,
-    .init = kvmclock_init,
+static void kvmclock_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = kvmclock_init;
+    dc->no_user = 1;
+    dc->vmsd = &kvmclock_vmsd;
+}
+
+static TypeInfo kvmclock_info = {
+    .name          = "kvmclock",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(KVMClockState),
+    .class_init    = kvmclock_class_init,
 };
 
 /* Note: Must be called after VCPU initialization. */
@@ -113,7 +122,7 @@ void kvmclock_create(void)
 static void kvmclock_register_device(void)
 {
     if (kvm_enabled()) {
-        sysbus_register_withprop(&kvmclock_info);
+    type_register_static(&kvmclock_info);
     }
 }
 
diff --git a/hw/kvmclock.h b/hw/kvm/clock.h
index 252ea13461..252ea13461 100644
--- a/hw/kvmclock.h
+++ b/hw/kvm/clock.h
diff --git a/hw/kvm/i8259.c b/hw/kvm/i8259.c
new file mode 100644
index 0000000000..14bd427518
--- /dev/null
+++ b/hw/kvm/i8259.c
@@ -0,0 +1,138 @@
+/*
+ * KVM in-kernel PIC (i8259) support
+ *
+ * Copyright (c) 2011 Siemens AG
+ *
+ * Authors:
+ *  Jan Kiszka          <jan.kiszka@siemens.com>
+ *
+ * This work is licensed under the terms of the GNU GPL version 2.
+ * See the COPYING file in the top-level directory.
+ */
+#include "hw/i8259_internal.h"
+#include "hw/apic_internal.h"
+#include "kvm.h"
+
+static void kvm_pic_get(PICCommonState *s)
+{
+    struct kvm_irqchip chip;
+    struct kvm_pic_state *kpic;
+    int ret;
+
+    chip.chip_id = s->master ? KVM_IRQCHIP_PIC_MASTER : KVM_IRQCHIP_PIC_SLAVE;
+    ret = kvm_vm_ioctl(kvm_state, KVM_GET_IRQCHIP, &chip);
+    if (ret < 0) {
+        fprintf(stderr, "KVM_GET_IRQCHIP failed: %s\n", strerror(ret));
+        abort();
+    }
+
+    kpic = &chip.chip.pic;
+
+    s->last_irr = kpic->last_irr;
+    s->irr = kpic->irr;
+    s->imr = kpic->imr;
+    s->isr = kpic->isr;
+    s->priority_add = kpic->priority_add;
+    s->irq_base = kpic->irq_base;
+    s->read_reg_select = kpic->read_reg_select;
+    s->poll = kpic->poll;
+    s->special_mask = kpic->special_mask;
+    s->init_state = kpic->init_state;
+    s->auto_eoi = kpic->auto_eoi;
+    s->rotate_on_auto_eoi = kpic->rotate_on_auto_eoi;
+    s->special_fully_nested_mode = kpic->special_fully_nested_mode;
+    s->init4 = kpic->init4;
+    s->elcr = kpic->elcr;
+    s->elcr_mask = kpic->elcr_mask;
+}
+
+static void kvm_pic_put(PICCommonState *s)
+{
+    struct kvm_irqchip chip;
+    struct kvm_pic_state *kpic;
+    int ret;
+
+    chip.chip_id = s->master ? KVM_IRQCHIP_PIC_MASTER : KVM_IRQCHIP_PIC_SLAVE;
+
+    kpic = &chip.chip.pic;
+
+    kpic->last_irr = s->last_irr;
+    kpic->irr = s->irr;
+    kpic->imr = s->imr;
+    kpic->isr = s->isr;
+    kpic->priority_add = s->priority_add;
+    kpic->irq_base = s->irq_base;
+    kpic->read_reg_select = s->read_reg_select;
+    kpic->poll = s->poll;
+    kpic->special_mask = s->special_mask;
+    kpic->init_state = s->init_state;
+    kpic->auto_eoi = s->auto_eoi;
+    kpic->rotate_on_auto_eoi = s->rotate_on_auto_eoi;
+    kpic->special_fully_nested_mode = s->special_fully_nested_mode;
+    kpic->init4 = s->init4;
+    kpic->elcr = s->elcr;
+    kpic->elcr_mask = s->elcr_mask;
+
+    ret = kvm_vm_ioctl(kvm_state, KVM_SET_IRQCHIP, &chip);
+    if (ret < 0) {
+        fprintf(stderr, "KVM_GET_IRQCHIP failed: %s\n", strerror(ret));
+        abort();
+    }
+}
+
+static void kvm_pic_reset(DeviceState *dev)
+{
+    PICCommonState *s = DO_UPCAST(PICCommonState, dev.qdev, dev);
+
+    pic_reset_common(s);
+    s->elcr = 0;
+
+    kvm_pic_put(s);
+}
+
+static void kvm_pic_set_irq(void *opaque, int irq, int level)
+{
+    int delivered;
+
+    delivered = kvm_irqchip_set_irq(kvm_state, irq, level);
+    apic_report_irq_delivered(delivered);
+}
+
+static void kvm_pic_init(PICCommonState *s)
+{
+    memory_region_init_reservation(&s->base_io, "kvm-pic", 2);
+    memory_region_init_reservation(&s->elcr_io, "kvm-elcr", 1);
+}
+
+qemu_irq *kvm_i8259_init(ISABus *bus)
+{
+    i8259_init_chip("kvm-i8259", bus, true);
+    i8259_init_chip("kvm-i8259", bus, false);
+
+    return qemu_allocate_irqs(kvm_pic_set_irq, NULL, ISA_NUM_IRQS);
+}
+
+static void kvm_i8259_class_init(ObjectClass *klass, void *data)
+{
+    PICCommonClass *k = PIC_COMMON_CLASS(klass);
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    dc->reset     = kvm_pic_reset;
+    k->init       = kvm_pic_init;
+    k->pre_save   = kvm_pic_get;
+    k->post_load  = kvm_pic_put;
+}
+
+static TypeInfo kvm_i8259_info = {
+    .name  = "kvm-i8259",
+    .parent = TYPE_PIC_COMMON,
+    .instance_size = sizeof(PICCommonState),
+    .class_init = kvm_i8259_class_init,
+};
+
+static void kvm_pic_register(void)
+{
+    type_register_static(&kvm_i8259_info);
+}
+
+device_init(kvm_pic_register)
diff --git a/hw/kvm/ioapic.c b/hw/kvm/ioapic.c
new file mode 100644
index 0000000000..b316933a96
--- /dev/null
+++ b/hw/kvm/ioapic.c
@@ -0,0 +1,125 @@
+/*
+ * KVM in-kernel IOPIC support
+ *
+ * Copyright (c) 2011 Siemens AG
+ *
+ * Authors:
+ *  Jan Kiszka          <jan.kiszka@siemens.com>
+ *
+ * This work is licensed under the terms of the GNU GPL version 2.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "hw/pc.h"
+#include "hw/ioapic_internal.h"
+#include "hw/apic_internal.h"
+#include "kvm.h"
+
+typedef struct KVMIOAPICState KVMIOAPICState;
+
+struct KVMIOAPICState {
+    IOAPICCommonState ioapic;
+    uint32_t kvm_gsi_base;
+};
+
+static void kvm_ioapic_get(IOAPICCommonState *s)
+{
+    struct kvm_irqchip chip;
+    struct kvm_ioapic_state *kioapic;
+    int ret, i;
+
+    chip.chip_id = KVM_IRQCHIP_IOAPIC;
+    ret = kvm_vm_ioctl(kvm_state, KVM_GET_IRQCHIP, &chip);
+    if (ret < 0) {
+        fprintf(stderr, "KVM_GET_IRQCHIP failed: %s\n", strerror(ret));
+        abort();
+    }
+
+    kioapic = &chip.chip.ioapic;
+
+    s->id = kioapic->id;
+    s->ioregsel = kioapic->ioregsel;
+    s->irr = kioapic->irr;
+    for (i = 0; i < IOAPIC_NUM_PINS; i++) {
+        s->ioredtbl[i] = kioapic->redirtbl[i].bits;
+    }
+}
+
+static void kvm_ioapic_put(IOAPICCommonState *s)
+{
+    struct kvm_irqchip chip;
+    struct kvm_ioapic_state *kioapic;
+    int ret, i;
+
+    chip.chip_id = KVM_IRQCHIP_IOAPIC;
+    kioapic = &chip.chip.ioapic;
+
+    kioapic->id = s->id;
+    kioapic->ioregsel = s->ioregsel;
+    kioapic->base_address = s->busdev.mmio[0].addr;
+    kioapic->irr = s->irr;
+    for (i = 0; i < IOAPIC_NUM_PINS; i++) {
+        kioapic->redirtbl[i].bits = s->ioredtbl[i];
+    }
+
+    ret = kvm_vm_ioctl(kvm_state, KVM_SET_IRQCHIP, &chip);
+    if (ret < 0) {
+        fprintf(stderr, "KVM_GET_IRQCHIP failed: %s\n", strerror(ret));
+        abort();
+    }
+}
+
+static void kvm_ioapic_reset(DeviceState *dev)
+{
+    IOAPICCommonState *s = DO_UPCAST(IOAPICCommonState, busdev.qdev, dev);
+
+    ioapic_reset_common(dev);
+    kvm_ioapic_put(s);
+}
+
+static void kvm_ioapic_set_irq(void *opaque, int irq, int level)
+{
+    KVMIOAPICState *s = opaque;
+    int delivered;
+
+    delivered = kvm_irqchip_set_irq(kvm_state, s->kvm_gsi_base + irq, level);
+    apic_report_irq_delivered(delivered);
+}
+
+static void kvm_ioapic_init(IOAPICCommonState *s, int instance_no)
+{
+    memory_region_init_reservation(&s->io_memory, "kvm-ioapic", 0x1000);
+
+    qdev_init_gpio_in(&s->busdev.qdev, kvm_ioapic_set_irq, IOAPIC_NUM_PINS);
+}
+
+static Property kvm_ioapic_properties[] = {
+    DEFINE_PROP_UINT32("gsi_base", KVMIOAPICState, kvm_gsi_base, 0),
+    DEFINE_PROP_END_OF_LIST()
+};
+
+static void kvm_ioapic_class_init(ObjectClass *klass, void *data)
+{
+    IOAPICCommonClass *k = IOAPIC_COMMON_CLASS(klass);
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    k->init      = kvm_ioapic_init;
+    k->pre_save  = kvm_ioapic_get;
+    k->post_load = kvm_ioapic_put;
+    dc->reset    = kvm_ioapic_reset;
+    dc->props    = kvm_ioapic_properties;
+}
+
+static TypeInfo kvm_ioapic_info = {
+    .name  = "kvm-ioapic",
+    .parent = TYPE_IOAPIC_COMMON,
+    .instance_size = sizeof(KVMIOAPICState),
+    .class_init = kvm_ioapic_class_init,
+};
+
+static void kvm_ioapic_register_device(void)
+{
+    type_register_static(&kvm_ioapic_info);
+}
+
+device_init(kvm_ioapic_register_device)
diff --git a/hw/lan9118.c b/hw/lan9118.c
index 8b83fe2198..78777c7336 100644
--- a/hw/lan9118.c
+++ b/hw/lan9118.c
@@ -140,17 +140,36 @@ enum tx_state {
 };
 
 typedef struct {
-    enum tx_state state;
+    /* state is a tx_state but we can't put enums in VMStateDescriptions. */
+    uint32_t state;
     uint32_t cmd_a;
     uint32_t cmd_b;
-    int buffer_size;
-    int offset;
-    int pad;
-    int fifo_used;
-    int len;
+    int32_t buffer_size;
+    int32_t offset;
+    int32_t pad;
+    int32_t fifo_used;
+    int32_t len;
     uint8_t data[2048];
 } LAN9118Packet;
 
+static const VMStateDescription vmstate_lan9118_packet = {
+    .name = "lan9118_packet",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(state, LAN9118Packet),
+        VMSTATE_UINT32(cmd_a, LAN9118Packet),
+        VMSTATE_UINT32(cmd_b, LAN9118Packet),
+        VMSTATE_INT32(buffer_size, LAN9118Packet),
+        VMSTATE_INT32(offset, LAN9118Packet),
+        VMSTATE_INT32(pad, LAN9118Packet),
+        VMSTATE_INT32(fifo_used, LAN9118Packet),
+        VMSTATE_INT32(len, LAN9118Packet),
+        VMSTATE_UINT8_ARRAY(data, LAN9118Packet, 2048),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
 typedef struct {
     SysBusDevice busdev;
     NICState *nic;
@@ -190,34 +209,95 @@ typedef struct {
     uint32_t phy_int;
     uint32_t phy_int_mask;
 
-    int eeprom_writable;
+    int32_t eeprom_writable;
     uint8_t eeprom[128];
 
-    int tx_fifo_size;
+    int32_t tx_fifo_size;
     LAN9118Packet *txp;
     LAN9118Packet tx_packet;
 
-    int tx_status_fifo_used;
-    int tx_status_fifo_head;
+    int32_t tx_status_fifo_used;
+    int32_t tx_status_fifo_head;
     uint32_t tx_status_fifo[512];
 
-    int rx_status_fifo_size;
-    int rx_status_fifo_used;
-    int rx_status_fifo_head;
+    int32_t rx_status_fifo_size;
+    int32_t rx_status_fifo_used;
+    int32_t rx_status_fifo_head;
     uint32_t rx_status_fifo[896];
-    int rx_fifo_size;
-    int rx_fifo_used;
-    int rx_fifo_head;
+    int32_t rx_fifo_size;
+    int32_t rx_fifo_used;
+    int32_t rx_fifo_head;
     uint32_t rx_fifo[3360];
-    int rx_packet_size_head;
-    int rx_packet_size_tail;
-    int rx_packet_size[1024];
+    int32_t rx_packet_size_head;
+    int32_t rx_packet_size_tail;
+    int32_t rx_packet_size[1024];
 
-    int rxp_offset;
-    int rxp_size;
-    int rxp_pad;
+    int32_t rxp_offset;
+    int32_t rxp_size;
+    int32_t rxp_pad;
 } lan9118_state;
 
+static const VMStateDescription vmstate_lan9118 = {
+    .name = "lan9118",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_PTIMER(timer, lan9118_state),
+        VMSTATE_UINT32(irq_cfg, lan9118_state),
+        VMSTATE_UINT32(int_sts, lan9118_state),
+        VMSTATE_UINT32(int_en, lan9118_state),
+        VMSTATE_UINT32(fifo_int, lan9118_state),
+        VMSTATE_UINT32(rx_cfg, lan9118_state),
+        VMSTATE_UINT32(tx_cfg, lan9118_state),
+        VMSTATE_UINT32(hw_cfg, lan9118_state),
+        VMSTATE_UINT32(pmt_ctrl, lan9118_state),
+        VMSTATE_UINT32(gpio_cfg, lan9118_state),
+        VMSTATE_UINT32(gpt_cfg, lan9118_state),
+        VMSTATE_UINT32(word_swap, lan9118_state),
+        VMSTATE_UINT32(free_timer_start, lan9118_state),
+        VMSTATE_UINT32(mac_cmd, lan9118_state),
+        VMSTATE_UINT32(mac_data, lan9118_state),
+        VMSTATE_UINT32(afc_cfg, lan9118_state),
+        VMSTATE_UINT32(e2p_cmd, lan9118_state),
+        VMSTATE_UINT32(e2p_data, lan9118_state),
+        VMSTATE_UINT32(mac_cr, lan9118_state),
+        VMSTATE_UINT32(mac_hashh, lan9118_state),
+        VMSTATE_UINT32(mac_hashl, lan9118_state),
+        VMSTATE_UINT32(mac_mii_acc, lan9118_state),
+        VMSTATE_UINT32(mac_mii_data, lan9118_state),
+        VMSTATE_UINT32(mac_flow, lan9118_state),
+        VMSTATE_UINT32(phy_status, lan9118_state),
+        VMSTATE_UINT32(phy_control, lan9118_state),
+        VMSTATE_UINT32(phy_advertise, lan9118_state),
+        VMSTATE_UINT32(phy_int, lan9118_state),
+        VMSTATE_UINT32(phy_int_mask, lan9118_state),
+        VMSTATE_INT32(eeprom_writable, lan9118_state),
+        VMSTATE_UINT8_ARRAY(eeprom, lan9118_state, 128),
+        VMSTATE_INT32(tx_fifo_size, lan9118_state),
+        /* txp always points at tx_packet so need not be saved */
+        VMSTATE_STRUCT(tx_packet, lan9118_state, 0,
+                       vmstate_lan9118_packet, LAN9118Packet),
+        VMSTATE_INT32(tx_status_fifo_used, lan9118_state),
+        VMSTATE_INT32(tx_status_fifo_head, lan9118_state),
+        VMSTATE_UINT32_ARRAY(tx_status_fifo, lan9118_state, 512),
+        VMSTATE_INT32(rx_status_fifo_size, lan9118_state),
+        VMSTATE_INT32(rx_status_fifo_used, lan9118_state),
+        VMSTATE_INT32(rx_status_fifo_head, lan9118_state),
+        VMSTATE_UINT32_ARRAY(rx_status_fifo, lan9118_state, 896),
+        VMSTATE_INT32(rx_fifo_size, lan9118_state),
+        VMSTATE_INT32(rx_fifo_used, lan9118_state),
+        VMSTATE_INT32(rx_fifo_head, lan9118_state),
+        VMSTATE_UINT32_ARRAY(rx_fifo, lan9118_state, 3360),
+        VMSTATE_INT32(rx_packet_size_head, lan9118_state),
+        VMSTATE_INT32(rx_packet_size_tail, lan9118_state),
+        VMSTATE_INT32_ARRAY(rx_packet_size, lan9118_state, 1024),
+        VMSTATE_INT32(rxp_offset, lan9118_state),
+        VMSTATE_INT32(rxp_size, lan9118_state),
+        VMSTATE_INT32(rxp_pad, lan9118_state),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
 static void lan9118_update(lan9118_state *s)
 {
     int level;
@@ -1141,7 +1221,7 @@ static int lan9118_init1(SysBusDevice *dev)
     qemu_macaddr_default_if_unset(&s->conf.macaddr);
 
     s->nic = qemu_new_nic(&net_lan9118_info, &s->conf,
-                          dev->qdev.info->name, dev->qdev.id, s);
+                          object_get_typename(OBJECT(dev)), dev->qdev.id, s);
     qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a);
     s->eeprom[0] = 0xa5;
     for (i = 0; i < 6; i++) {
@@ -1155,24 +1235,35 @@ static int lan9118_init1(SysBusDevice *dev)
     ptimer_set_freq(s->timer, 10000);
     ptimer_set_limit(s->timer, 0xffff, 1);
 
-    /* ??? Save/restore.  */
     return 0;
 }
 
-static SysBusDeviceInfo lan9118_info = {
-    .init = lan9118_init1,
-    .qdev.name  = "lan9118",
-    .qdev.size  = sizeof(lan9118_state),
-    .qdev.reset = lan9118_reset,
-    .qdev.props = (Property[]) {
-        DEFINE_NIC_PROPERTIES(lan9118_state, conf),
-        DEFINE_PROP_END_OF_LIST(),
-    }
+static Property lan9118_properties[] = {
+    DEFINE_NIC_PROPERTIES(lan9118_state, conf),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void lan9118_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = lan9118_init1;
+    dc->reset = lan9118_reset;
+    dc->props = lan9118_properties;
+    dc->vmsd = &vmstate_lan9118;
+}
+
+static TypeInfo lan9118_info = {
+    .name          = "lan9118",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(lan9118_state),
+    .class_init    = lan9118_class_init,
 };
 
 static void lan9118_register_devices(void)
 {
-    sysbus_register_withprop(&lan9118_info);
+    type_register_static(&lan9118_info);
 }
 
 /* Legacy helper function.  Should go away when machine config files are
diff --git a/hw/lance.c b/hw/lance.c
index 716470061c..519720bd9c 100644
--- a/hw/lance.c
+++ b/hw/lance.c
@@ -137,22 +137,33 @@ static void lance_reset(DeviceState *dev)
     pcnet_h_reset(&d->state);
 }
 
-static SysBusDeviceInfo lance_info = {
-    .init       = lance_init,
-    .qdev.name  = "lance",
-    .qdev.fw_name  = "ethernet",
-    .qdev.size  = sizeof(SysBusPCNetState),
-    .qdev.reset = lance_reset,
-    .qdev.vmsd  = &vmstate_lance,
-    .qdev.props = (Property[]) {
-        DEFINE_PROP_PTR("dma", SysBusPCNetState, state.dma_opaque),
-        DEFINE_NIC_PROPERTIES(SysBusPCNetState, state.conf),
-        DEFINE_PROP_END_OF_LIST(),
-    }
+static Property lance_properties[] = {
+    DEFINE_PROP_PTR("dma", SysBusPCNetState, state.dma_opaque),
+    DEFINE_NIC_PROPERTIES(SysBusPCNetState, state.conf),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void lance_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = lance_init;
+    dc->fw_name = "ethernet";
+    dc->reset = lance_reset;
+    dc->vmsd = &vmstate_lance;
+    dc->props = lance_properties;
+}
+
+static TypeInfo lance_info = {
+    .name          = "lance",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(SysBusPCNetState),
+    .class_init    = lance_class_init,
 };
 
 static void lance_register_devices(void)
 {
-    sysbus_register_withprop(&lance_info);
+    type_register_static(&lance_info);
 }
 device_init(lance_register_devices)
diff --git a/hw/lm32_juart.c b/hw/lm32_juart.c
index 5454aa4e4d..38dd28230d 100644
--- a/hw/lm32_juart.c
+++ b/hw/lm32_juart.c
@@ -114,7 +114,7 @@ static int lm32_juart_init(SysBusDevice *dev)
 {
     LM32JuartState *s = FROM_SYSBUS(typeof(*s), dev);
 
-    s->chr = qdev_init_chardev(&dev->qdev);
+    s->chr = qemu_char_get_next_serial();
     if (s->chr) {
         qemu_chr_add_handlers(s->chr, juart_can_rx, juart_rx, juart_event, s);
     }
@@ -134,17 +134,26 @@ static const VMStateDescription vmstate_lm32_juart = {
     }
 };
 
-static SysBusDeviceInfo lm32_juart_info = {
-    .init = lm32_juart_init,
-    .qdev.name  = "lm32-juart",
-    .qdev.size  = sizeof(LM32JuartState),
-    .qdev.vmsd  = &vmstate_lm32_juart,
-    .qdev.reset = juart_reset,
+static void lm32_juart_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = lm32_juart_init;
+    dc->reset = juart_reset;
+    dc->vmsd = &vmstate_lm32_juart;
+}
+
+static TypeInfo lm32_juart_info = {
+    .name          = "lm32-juart",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(LM32JuartState),
+    .class_init    = lm32_juart_class_init,
 };
 
 static void lm32_juart_register(void)
 {
-    sysbus_register_withprop(&lm32_juart_info);
+    type_register_static(&lm32_juart_info);
 }
 
 device_init(lm32_juart_register)
diff --git a/hw/lm32_pic.c b/hw/lm32_pic.c
index 8dd005077c..7be6d0d68e 100644
--- a/hw/lm32_pic.c
+++ b/hw/lm32_pic.c
@@ -174,17 +174,26 @@ static const VMStateDescription vmstate_lm32_pic = {
     }
 };
 
-static SysBusDeviceInfo lm32_pic_info = {
-    .init = lm32_pic_init,
-    .qdev.name  = "lm32-pic",
-    .qdev.size  = sizeof(LM32PicState),
-    .qdev.vmsd  = &vmstate_lm32_pic,
-    .qdev.reset = pic_reset,
+static void lm32_pic_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = lm32_pic_init;
+    dc->reset = pic_reset;
+    dc->vmsd = &vmstate_lm32_pic;
+}
+
+static TypeInfo lm32_pic_info = {
+    .name          = "lm32-pic",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(LM32PicState),
+    .class_init    = lm32_pic_class_init,
 };
 
 static void lm32_pic_register(void)
 {
-    sysbus_register_withprop(&lm32_pic_info);
+    type_register_static(&lm32_pic_info);
 }
 
 device_init(lm32_pic_register)
diff --git a/hw/lm32_sys.c b/hw/lm32_sys.c
index 83974ee4fb..ba6f4acbaa 100644
--- a/hw/lm32_sys.c
+++ b/hw/lm32_sys.c
@@ -141,21 +141,32 @@ static const VMStateDescription vmstate_lm32_sys = {
     }
 };
 
-static SysBusDeviceInfo lm32_sys_info = {
-    .init = lm32_sys_init,
-    .qdev.name  = "lm32-sys",
-    .qdev.size  = sizeof(LM32SysState),
-    .qdev.vmsd  = &vmstate_lm32_sys,
-    .qdev.reset = sys_reset,
-    .qdev.props = (Property[]) {
-        DEFINE_PROP_UINT32("base", LM32SysState, base, 0xffff0000),
-        DEFINE_PROP_END_OF_LIST(),
-    }
+static Property lm32_sys_properties[] = {
+    DEFINE_PROP_UINT32("base", LM32SysState, base, 0xffff0000),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void lm32_sys_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = lm32_sys_init;
+    dc->reset = sys_reset;
+    dc->vmsd = &vmstate_lm32_sys;
+    dc->props = lm32_sys_properties;
+}
+
+static TypeInfo lm32_sys_info = {
+    .name          = "lm32-sys",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(LM32SysState),
+    .class_init    = lm32_sys_class_init,
 };
 
 static void lm32_sys_register(void)
 {
-    sysbus_register_withprop(&lm32_sys_info);
+    type_register_static(&lm32_sys_info);
 }
 
 device_init(lm32_sys_register)
diff --git a/hw/lm32_timer.c b/hw/lm32_timer.c
index 115e1e968f..3cb4e0a4f3 100644
--- a/hw/lm32_timer.c
+++ b/hw/lm32_timer.c
@@ -199,23 +199,32 @@ static const VMStateDescription vmstate_lm32_timer = {
     }
 };
 
-static SysBusDeviceInfo lm32_timer_info = {
-    .init = lm32_timer_init,
-    .qdev.name  = "lm32-timer",
-    .qdev.size  = sizeof(LM32TimerState),
-    .qdev.vmsd  = &vmstate_lm32_timer,
-    .qdev.reset = timer_reset,
-    .qdev.props = (Property[]) {
-        DEFINE_PROP_UINT32(
-                "frequency", LM32TimerState, freq_hz, DEFAULT_FREQUENCY
-        ),
-        DEFINE_PROP_END_OF_LIST(),
-    }
+static Property lm32_timer_properties[] = {
+    DEFINE_PROP_UINT32("frequency", LM32TimerState, freq_hz, DEFAULT_FREQUENCY),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void lm32_timer_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = lm32_timer_init;
+    dc->reset = timer_reset;
+    dc->vmsd = &vmstate_lm32_timer;
+    dc->props = lm32_timer_properties;
+}
+
+static TypeInfo lm32_timer_info = {
+    .name          = "lm32-timer",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(LM32TimerState),
+    .class_init    = lm32_timer_class_init,
 };
 
 static void lm32_timer_register(void)
 {
-    sysbus_register_withprop(&lm32_timer_info);
+    type_register_static(&lm32_timer_info);
 }
 
 device_init(lm32_timer_register)
diff --git a/hw/lm32_uart.c b/hw/lm32_uart.c
index d013abd1c6..630ccb7131 100644
--- a/hw/lm32_uart.c
+++ b/hw/lm32_uart.c
@@ -252,7 +252,7 @@ static int lm32_uart_init(SysBusDevice *dev)
     memory_region_init_io(&s->iomem, &uart_ops, s, "uart", R_MAX * 4);
     sysbus_init_mmio(dev, &s->iomem);
 
-    s->chr = qdev_init_chardev(&dev->qdev);
+    s->chr = qemu_char_get_next_serial();
     if (s->chr) {
         qemu_chr_add_handlers(s->chr, uart_can_rx, uart_rx, uart_event, s);
     }
@@ -271,17 +271,26 @@ static const VMStateDescription vmstate_lm32_uart = {
     }
 };
 
-static SysBusDeviceInfo lm32_uart_info = {
-    .init = lm32_uart_init,
-    .qdev.name  = "lm32-uart",
-    .qdev.size  = sizeof(LM32UartState),
-    .qdev.vmsd  = &vmstate_lm32_uart,
-    .qdev.reset = uart_reset,
+static void lm32_uart_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = lm32_uart_init;
+    dc->reset = uart_reset;
+    dc->vmsd = &vmstate_lm32_uart;
+}
+
+static TypeInfo lm32_uart_info = {
+    .name          = "lm32-uart",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(LM32UartState),
+    .class_init    = lm32_uart_class_init,
 };
 
 static void lm32_uart_register(void)
 {
-    sysbus_register_withprop(&lm32_uart_info);
+    type_register_static(&lm32_uart_info);
 }
 
 device_init(lm32_uart_register)
diff --git a/hw/lm832x.c b/hw/lm832x.c
index 992ce49729..895d306635 100644
--- a/hw/lm832x.c
+++ b/hw/lm832x.c
@@ -24,7 +24,7 @@
 #include "console.h"
 
 typedef struct {
-    i2c_slave i2c;
+    I2CSlave i2c;
     uint8_t i2c_dir;
     uint8_t i2c_cycle;
     uint8_t reg;
@@ -378,7 +378,7 @@ static void lm_kbd_write(LM823KbdState *s, int reg, int byte, uint8_t value)
     }
 }
 
-static void lm_i2c_event(i2c_slave *i2c, enum i2c_event event)
+static void lm_i2c_event(I2CSlave *i2c, enum i2c_event event)
 {
     LM823KbdState *s = FROM_I2C_SLAVE(LM823KbdState, i2c);
 
@@ -394,14 +394,14 @@ static void lm_i2c_event(i2c_slave *i2c, enum i2c_event event)
     }
 }
 
-static int lm_i2c_rx(i2c_slave *i2c)
+static int lm_i2c_rx(I2CSlave *i2c)
 {
     LM823KbdState *s = FROM_I2C_SLAVE(LM823KbdState, i2c);
 
     return lm_kbd_read(s, s->reg, s->i2c_cycle ++);
 }
 
-static int lm_i2c_tx(i2c_slave *i2c, uint8_t data)
+static int lm_i2c_tx(I2CSlave *i2c, uint8_t data)
 {
     LM823KbdState *s = (LM823KbdState *) i2c;
 
@@ -458,7 +458,7 @@ static const VMStateDescription vmstate_lm_kbd = {
 };
 
 
-static int lm8323_init(i2c_slave *i2c)
+static int lm8323_init(I2CSlave *i2c)
 {
     LM823KbdState *s = FROM_I2C_SLAVE(LM823KbdState, i2c);
 
@@ -494,19 +494,28 @@ void lm832x_key_event(DeviceState *dev, int key, int state)
     lm_kbd_irq_update(s);
 }
 
-static I2CSlaveInfo lm8323_info = {
-    .qdev.name = "lm8323",
-    .qdev.size = sizeof(LM823KbdState),
-    .qdev.vmsd = &vmstate_lm_kbd,
-    .init = lm8323_init,
-    .event = lm_i2c_event,
-    .recv = lm_i2c_rx,
-    .send = lm_i2c_tx
+static void lm8323_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
+
+    k->init = lm8323_init;
+    k->event = lm_i2c_event;
+    k->recv = lm_i2c_rx;
+    k->send = lm_i2c_tx;
+    dc->vmsd = &vmstate_lm_kbd;
+}
+
+static TypeInfo lm8323_info = {
+    .name          = "lm8323",
+    .parent        = TYPE_I2C_SLAVE,
+    .instance_size = sizeof(LM823KbdState),
+    .class_init    = lm8323_class_init,
 };
 
 static void lm832x_register_devices(void)
 {
-    i2c_register_slave(&lm8323_info);
+    type_register_static(&lm8323_info);
 }
 
 device_init(lm832x_register_devices)
diff --git a/hw/loader.c b/hw/loader.c
index 446b62874e..415cdce534 100644
--- a/hw/loader.c
+++ b/hw/loader.c
@@ -108,8 +108,12 @@ int load_image_targphys(const char *filename,
     int size;
 
     size = get_image_size(filename);
-    if (size > 0)
+    if (size > max_sz) {
+        return -1;
+    }
+    if (size > 0) {
         rom_add_file_fixed(filename, addr, -1);
+    }
     return size;
 }
 
diff --git a/hw/lsi53c895a.c b/hw/lsi53c895a.c
index 0d3a1016df..9a7ffe3f42 100644
--- a/hw/lsi53c895a.c
+++ b/hw/lsi53c895a.c
@@ -1681,7 +1681,7 @@ static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val)
                 DeviceState *dev;
 
                 QTAILQ_FOREACH(dev, &s->bus.qbus.children, sibling) {
-                    dev->info->reset(dev);
+                    device_reset(dev);
                 }
                 s->sstat0 |= LSI_SSTAT0_RST;
                 lsi_script_scsi_interrupt(s, LSI_SIST0_RST, 0);
@@ -2120,23 +2120,31 @@ static int lsi_scsi_init(PCIDevice *dev)
     return 0;
 }
 
-static PCIDeviceInfo lsi_info = {
-    .qdev.name  = "lsi53c895a",
-    .qdev.alias = "lsi",
-    .qdev.size  = sizeof(LSIState),
-    .qdev.reset = lsi_scsi_reset,
-    .qdev.vmsd  = &vmstate_lsi_scsi,
-    .init       = lsi_scsi_init,
-    .exit       = lsi_scsi_uninit,
-    .vendor_id  = PCI_VENDOR_ID_LSI_LOGIC,
-    .device_id  = PCI_DEVICE_ID_LSI_53C895A,
-    .class_id   = PCI_CLASS_STORAGE_SCSI,
-    .subsystem_id = 0x1000,
+static void lsi_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->init = lsi_scsi_init;
+    k->exit = lsi_scsi_uninit;
+    k->vendor_id = PCI_VENDOR_ID_LSI_LOGIC;
+    k->device_id = PCI_DEVICE_ID_LSI_53C895A;
+    k->class_id = PCI_CLASS_STORAGE_SCSI;
+    k->subsystem_id = 0x1000;
+    dc->reset = lsi_scsi_reset;
+    dc->vmsd = &vmstate_lsi_scsi;
+}
+
+static TypeInfo lsi_info = {
+    .name          = "lsi53c895a",
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(LSIState),
+    .class_init    = lsi_class_init,
 };
 
 static void lsi53c895a_register_devices(void)
 {
-    pci_qdev_register(&lsi_info);
+    type_register_static(&lsi_info);
 }
 
 device_init(lsi53c895a_register_devices);
diff --git a/hw/m48t59.c b/hw/m48t59.c
index c0439966cf..c35867d0a1 100644
--- a/hw/m48t59.c
+++ b/hw/m48t59.c
@@ -126,7 +126,7 @@ static void alarm_cb (void *opaque)
         /* Repeat once a second */
         next_time = 1;
     }
-    qemu_mod_timer(NVRAM->alrm_timer, qemu_get_clock_ns(vm_clock) +
+    qemu_mod_timer(NVRAM->alrm_timer, qemu_get_clock_ns(rtc_clock) +
                     next_time * 1000);
     qemu_set_irq(NVRAM->IRQ, 0);
 }
@@ -687,7 +687,7 @@ static void m48t59_init_common(M48t59State *s)
 {
     s->buffer = g_malloc0(s->size);
     if (s->type == 59) {
-        s->alrm_timer = qemu_new_timer_ns(vm_clock, &alarm_cb, s);
+        s->alrm_timer = qemu_new_timer_ns(rtc_clock, &alarm_cb, s);
         s->wd_timer = qemu_new_timer_ns(vm_clock, &watchdog_cb, s);
     }
     qemu_get_timedate(&s->alarm, 0);
@@ -720,37 +720,58 @@ static int m48t59_init1(SysBusDevice *dev)
     return 0;
 }
 
-static ISADeviceInfo m48t59_isa_info = {
-    .init = m48t59_init_isa1,
-    .qdev.name = "m48t59_isa",
-    .qdev.size = sizeof(M48t59ISAState),
-    .qdev.reset = m48t59_reset_isa,
-    .qdev.no_user = 1,
-    .qdev.props = (Property[]) {
-        DEFINE_PROP_UINT32("size",    M48t59ISAState, state.size,    -1),
-        DEFINE_PROP_UINT32("type",    M48t59ISAState, state.type,    -1),
-        DEFINE_PROP_HEX32( "io_base", M48t59ISAState, state.io_base,  0),
-        DEFINE_PROP_END_OF_LIST(),
-    }
+static Property m48t59_isa_properties[] = {
+    DEFINE_PROP_UINT32("size",    M48t59ISAState, state.size,    -1),
+    DEFINE_PROP_UINT32("type",    M48t59ISAState, state.type,    -1),
+    DEFINE_PROP_HEX32( "io_base", M48t59ISAState, state.io_base,  0),
+    DEFINE_PROP_END_OF_LIST(),
 };
 
-static SysBusDeviceInfo m48t59_info = {
-    .init = m48t59_init1,
-    .qdev.name  = "m48t59",
-    .qdev.size = sizeof(M48t59SysBusState),
-    .qdev.reset = m48t59_reset_sysbus,
-    .qdev.props = (Property[]) {
-        DEFINE_PROP_UINT32("size",    M48t59SysBusState, state.size,    -1),
-        DEFINE_PROP_UINT32("type",    M48t59SysBusState, state.type,    -1),
-        DEFINE_PROP_HEX32( "io_base", M48t59SysBusState, state.io_base,  0),
-        DEFINE_PROP_END_OF_LIST(),
-    }
+static void m48t59_init_class_isa1(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    ISADeviceClass *ic = ISA_DEVICE_CLASS(klass);
+    ic->init = m48t59_init_isa1;
+    dc->no_user = 1;
+    dc->reset = m48t59_reset_isa;
+    dc->props = m48t59_isa_properties;
+}
+
+static TypeInfo m48t59_isa_info = {
+    .name          = "m48t59_isa",
+    .parent        = TYPE_ISA_DEVICE,
+    .instance_size = sizeof(M48t59ISAState),
+    .class_init    = m48t59_init_class_isa1,
+};
+
+static Property m48t59_properties[] = {
+    DEFINE_PROP_UINT32("size",    M48t59SysBusState, state.size,    -1),
+    DEFINE_PROP_UINT32("type",    M48t59SysBusState, state.type,    -1),
+    DEFINE_PROP_HEX32( "io_base", M48t59SysBusState, state.io_base,  0),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void m48t59_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = m48t59_init1;
+    dc->reset = m48t59_reset_sysbus;
+    dc->props = m48t59_properties;
+}
+
+static TypeInfo m48t59_info = {
+    .name          = "m48t59",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(M48t59SysBusState),
+    .class_init    = m48t59_class_init,
 };
 
 static void m48t59_register_devices(void)
 {
-    sysbus_register_withprop(&m48t59_info);
-    isa_qdev_register(&m48t59_isa_info);
+    type_register_static(&m48t59_info);
+    type_register_static(&m48t59_isa_info);
 }
 
 device_init(m48t59_register_devices)
diff --git a/hw/macio.c b/hw/macio.c
index cc6ae40050..3d648e934b 100644
--- a/hw/macio.c
+++ b/hw/macio.c
@@ -27,8 +27,9 @@
 #include "pci.h"
 #include "escc.h"
 
-typedef struct macio_state_t macio_state_t;
-struct macio_state_t {
+typedef struct MacIOState
+{
+    PCIDevice parent;
     int is_oldworld;
     MemoryRegion bar;
     MemoryRegion *pic_mem;
@@ -38,9 +39,9 @@ struct macio_state_t {
     void *nvram;
     int nb_ide;
     MemoryRegion *ide_mem[4];
-};
+} MacIOState;
 
-static void macio_bar_setup(macio_state_t *macio_state)
+static void macio_bar_setup(MacIOState *macio_state)
 {
     int i;
     MemoryRegion *bar = &macio_state->bar;
@@ -74,6 +75,35 @@ static void macio_bar_setup(macio_state_t *macio_state)
         macio_nvram_setup_bar(macio_state->nvram, bar, 0x60000);
 }
 
+static int macio_initfn(PCIDevice *d)
+{
+    d->config[0x3d] = 0x01; // interrupt on pin 1
+    return 0;
+}
+
+static void macio_class_init(ObjectClass *klass, void *data)
+{
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->init = macio_initfn;
+    k->vendor_id = PCI_VENDOR_ID_APPLE;
+    k->class_id = PCI_CLASS_OTHERS << 8;
+}
+
+static TypeInfo macio_info = {
+    .name          = "macio",
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(MacIOState),
+    .class_init    = macio_class_init,
+};
+
+static void macio_register(void)
+{
+    type_register_static(&macio_info);
+}
+
+device_init(macio_register);
+
 void macio_init (PCIBus *bus, int device_id, int is_oldworld,
                  MemoryRegion *pic_mem, MemoryRegion *dbdma_mem,
                  MemoryRegion *cuda_mem, void *nvram,
@@ -81,13 +111,12 @@ void macio_init (PCIBus *bus, int device_id, int is_oldworld,
                  MemoryRegion *escc_mem)
 {
     PCIDevice *d;
-    macio_state_t *macio_state;
+    MacIOState *macio_state;
     int i;
 
-    d = pci_register_device(bus, "macio",
-                            sizeof(PCIDevice) + sizeof(macio_state_t),
-                            -1, NULL, NULL);
-    macio_state = (macio_state_t *)(d + 1);
+    d = pci_create_simple(bus, -1, "macio");
+
+    macio_state = DO_UPCAST(MacIOState, parent, d);
     macio_state->is_oldworld = is_oldworld;
     macio_state->pic_mem = pic_mem;
     macio_state->dbdma_mem = dbdma_mem;
@@ -104,11 +133,7 @@ void macio_init (PCIBus *bus, int device_id, int is_oldworld,
     /* Note: this code is strongly inspirated from the corresponding code
        in PearPC */
 
-    pci_config_set_vendor_id(d->config, PCI_VENDOR_ID_APPLE);
     pci_config_set_device_id(d->config, device_id);
-    pci_config_set_class(d->config, PCI_CLASS_OTHERS << 8);
-
-    d->config[0x3d] = 0x01; // interrupt on pin 1
 
     macio_bar_setup(macio_state);
     pci_register_bar(d, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &macio_state->bar);
diff --git a/hw/marvell_88w8618_audio.c b/hw/marvell_88w8618_audio.c
index 0cd8410622..b628f1718d 100644
--- a/hw/marvell_88w8618_audio.c
+++ b/hw/marvell_88w8618_audio.c
@@ -50,7 +50,7 @@ typedef struct mv88w8618_audio_state {
     uint32_t play_pos;
     uint32_t last_free;
     uint32_t clock_div;
-    DeviceState *wm;
+    void *wm;
 } mv88w8618_audio_state;
 
 static void mv88w8618_audio_callback(void *opaque, int free_out, int free_in)
@@ -272,25 +272,32 @@ static const VMStateDescription mv88w8618_audio_vmsd = {
     }
 };
 
-static SysBusDeviceInfo mv88w8618_audio_info = {
-    .init = mv88w8618_audio_init,
-    .qdev.name  = "mv88w8618_audio",
-    .qdev.size  = sizeof(mv88w8618_audio_state),
-    .qdev.reset = mv88w8618_audio_reset,
-    .qdev.vmsd  = &mv88w8618_audio_vmsd,
-    .qdev.props = (Property[]) {
-        {
-            .name   = "wm8750",
-            .info   = &qdev_prop_ptr,
-            .offset = offsetof(mv88w8618_audio_state, wm),
-        },
-        {/* end of list */}
-    }
+static Property mv88w8618_audio_properties[] = {
+    DEFINE_PROP_PTR("wm8750", mv88w8618_audio_state, wm),
+    {/* end of list */},
+};
+
+static void mv88w8618_audio_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = mv88w8618_audio_init;
+    dc->reset = mv88w8618_audio_reset;
+    dc->vmsd = &mv88w8618_audio_vmsd;
+    dc->props = mv88w8618_audio_properties;
+}
+
+static TypeInfo mv88w8618_audio_info = {
+    .name          = "mv88w8618_audio",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(mv88w8618_audio_state),
+    .class_init    = mv88w8618_audio_class_init,
 };
 
 static void mv88w8618_register_devices(void)
 {
-    sysbus_register_withprop(&mv88w8618_audio_info);
+    type_register_static(&mv88w8618_audio_info);
 }
 
 device_init(mv88w8618_register_devices)
diff --git a/hw/max111x.c b/hw/max111x.c
index fc79814bf8..9d61aa98db 100644
--- a/hw/max111x.c
+++ b/hw/max111x.c
@@ -153,24 +153,40 @@ void max111x_set_input(DeviceState *dev, int line, uint8_t value)
     s->input[line] = value;
 }
 
-static SSISlaveInfo max1110_info = {
-    .qdev.name = "max1110",
-    .qdev.size = sizeof(MAX111xState),
-    .init = max1110_init,
-    .transfer = max111x_transfer
+static void max1110_class_init(ObjectClass *klass, void *data)
+{
+    SSISlaveClass *k = SSI_SLAVE_CLASS(klass);
+
+    k->init = max1110_init;
+    k->transfer = max111x_transfer;
+}
+
+static TypeInfo max1110_info = {
+    .name          = "max1110",
+    .parent        = TYPE_SSI_SLAVE,
+    .instance_size = sizeof(MAX111xState),
+    .class_init    = max1110_class_init,
 };
 
-static SSISlaveInfo max1111_info = {
-    .qdev.name = "max1111",
-    .qdev.size = sizeof(MAX111xState),
-    .init = max1111_init,
-    .transfer = max111x_transfer
+static void max1111_class_init(ObjectClass *klass, void *data)
+{
+    SSISlaveClass *k = SSI_SLAVE_CLASS(klass);
+
+    k->init = max1111_init;
+    k->transfer = max111x_transfer;
+}
+
+static TypeInfo max1111_info = {
+    .name          = "max1111",
+    .parent        = TYPE_SSI_SLAVE,
+    .instance_size = sizeof(MAX111xState),
+    .class_init    = max1111_class_init,
 };
 
 static void max111x_register_devices(void)
 {
-    ssi_register_slave(&max1110_info);
-    ssi_register_slave(&max1111_info);
+    type_register_static(&max1110_info);
+    type_register_static(&max1111_info);
 }
 
 device_init(max111x_register_devices)
diff --git a/hw/max7310.c b/hw/max7310.c
index c1bdb2ee0c..3a6bb961ef 100644
--- a/hw/max7310.c
+++ b/hw/max7310.c
@@ -10,7 +10,7 @@
 #include "i2c.h"
 
 typedef struct {
-    i2c_slave i2c;
+    I2CSlave i2c;
     int i2c_command_byte;
     int len;
 
@@ -33,7 +33,7 @@ static void max7310_reset(DeviceState *dev)
     s->command = 0x00;
 }
 
-static int max7310_rx(i2c_slave *i2c)
+static int max7310_rx(I2CSlave *i2c)
 {
     MAX7310State *s = (MAX7310State *) i2c;
 
@@ -68,7 +68,7 @@ static int max7310_rx(i2c_slave *i2c)
     return 0xff;
 }
 
-static int max7310_tx(i2c_slave *i2c, uint8_t data)
+static int max7310_tx(I2CSlave *i2c, uint8_t data)
 {
     MAX7310State *s = (MAX7310State *) i2c;
     uint8_t diff;
@@ -123,7 +123,7 @@ static int max7310_tx(i2c_slave *i2c, uint8_t data)
     return 0;
 }
 
-static void max7310_event(i2c_slave *i2c, enum i2c_event event)
+static void max7310_event(I2CSlave *i2c, enum i2c_event event)
 {
     MAX7310State *s = (MAX7310State *) i2c;
     s->len = 0;
@@ -175,7 +175,7 @@ static void max7310_gpio_set(void *opaque, int line, int level)
 
 /* MAX7310 is SMBus-compatible (can be used with only SMBus protocols),
  * but also accepts sequences that are not SMBus so return an I2C device.  */
-static int max7310_init(i2c_slave *i2c)
+static int max7310_init(I2CSlave *i2c)
 {
     MAX7310State *s = FROM_I2C_SLAVE(MAX7310State, i2c);
 
@@ -185,20 +185,29 @@ static int max7310_init(i2c_slave *i2c)
     return 0;
 }
 
-static I2CSlaveInfo max7310_info = {
-    .qdev.name = "max7310",
-    .qdev.size = sizeof(MAX7310State),
-    .qdev.vmsd = &vmstate_max7310,
-    .qdev.reset = max7310_reset,
-    .init = max7310_init,
-    .event = max7310_event,
-    .recv = max7310_rx,
-    .send = max7310_tx
+static void max7310_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
+
+    k->init = max7310_init;
+    k->event = max7310_event;
+    k->recv = max7310_rx;
+    k->send = max7310_tx;
+    dc->reset = max7310_reset;
+    dc->vmsd = &vmstate_max7310;
+}
+
+static TypeInfo max7310_info = {
+    .name          = "max7310",
+    .parent        = TYPE_I2C_SLAVE,
+    .instance_size = sizeof(MAX7310State),
+    .class_init    = max7310_class_init,
 };
 
 static void max7310_register_devices(void)
 {
-    i2c_register_slave(&max7310_info);
+    type_register_static(&max7310_info);
 }
 
 device_init(max7310_register_devices)
diff --git a/hw/mc146818rtc.c b/hw/mc146818rtc.c
index 657fa10d6d..4a43225707 100644
--- a/hw/mc146818rtc.c
+++ b/hw/mc146818rtc.c
@@ -101,6 +101,7 @@ typedef struct RTCState {
     QEMUTimer *second_timer;
     QEMUTimer *second_timer2;
     Notifier clock_reset_notifier;
+    LostTickPolicy lost_tick_policy;
 } RTCState;
 
 static void rtc_set_time(RTCState *s);
@@ -183,7 +184,7 @@ static void rtc_periodic_timer(void *opaque)
     if (s->cmos_data[RTC_REG_B] & REG_B_PIE) {
         s->cmos_data[RTC_REG_C] |= REG_C_IRQF;
 #ifdef TARGET_I386
-        if(rtc_td_hack) {
+        if (s->lost_tick_policy == LOST_TICK_SLEW) {
             if (s->irq_reinject_on_ack_count >= RTC_REINJECT_ON_ACK_COUNT)
                 s->irq_reinject_on_ack_count = 0;		
             apic_reset_irq_delivered();
@@ -544,7 +545,7 @@ static int rtc_post_load(void *opaque, int version_id)
     RTCState *s = opaque;
 
     if (version_id >= 2) {
-        if (rtc_td_hack) {
+        if (s->lost_tick_policy == LOST_TICK_SLEW) {
             rtc_coalesced_timer_update(s);
         }
     }
@@ -589,7 +590,7 @@ static void rtc_notify_clock_reset(Notifier *notifier, void *data)
     qemu_mod_timer(s->second_timer2, s->next_second_time);
     rtc_timer_update(s, now);
 #ifdef TARGET_I386
-    if (rtc_td_hack) {
+    if (s->lost_tick_policy == LOST_TICK_SLEW) {
         rtc_coalesced_timer_update(s);
     }
 #endif
@@ -605,8 +606,9 @@ static void rtc_reset(void *opaque)
     qemu_irq_lower(s->irq);
 
 #ifdef TARGET_I386
-    if (rtc_td_hack)
-	    s->irq_coalesced = 0;
+    if (s->lost_tick_policy == LOST_TICK_SLEW) {
+        s->irq_coalesced = 0;
+    }
 #endif
 }
 
@@ -626,10 +628,10 @@ static void visit_type_int32(Visitor *v, int *value, const char *name, Error **e
     visit_type_int(v, &val, name, errp);
 }
 
-static void rtc_get_date(DeviceState *dev, Visitor *v, void *opaque,
+static void rtc_get_date(Object *obj, Visitor *v, void *opaque,
                          const char *name, Error **errp)
 {
-    ISADevice *isa = DO_UPCAST(ISADevice, qdev, dev);
+    ISADevice *isa = ISA_DEVICE(obj);
     RTCState *s = DO_UPCAST(RTCState, dev, isa);
 
     visit_start_struct(v, NULL, "struct tm", name, 0, errp);
@@ -654,12 +656,20 @@ static int rtc_initfn(ISADevice *dev)
 
     rtc_set_date_from_host(dev);
 
-    s->periodic_timer = qemu_new_timer_ns(rtc_clock, rtc_periodic_timer, s);
 #ifdef TARGET_I386
-    if (rtc_td_hack)
+    switch (s->lost_tick_policy) {
+    case LOST_TICK_SLEW:
         s->coalesced_timer =
             qemu_new_timer_ns(rtc_clock, rtc_coalesced_timer, s);
+        break;
+    case LOST_TICK_DISCARD:
+        break;
+    default:
+        return -EINVAL;
+    }
 #endif
+
+    s->periodic_timer = qemu_new_timer_ns(rtc_clock, rtc_periodic_timer, s);
     s->second_timer = qemu_new_timer_ns(rtc_clock, rtc_update_second, s);
     s->second_timer2 = qemu_new_timer_ns(rtc_clock, rtc_update_second2, s);
 
@@ -676,8 +686,8 @@ static int rtc_initfn(ISADevice *dev)
     qdev_set_legacy_instance_id(&dev->qdev, base, 2);
     qemu_register_reset(rtc_reset, s);
 
-    qdev_property_add(&s->dev.qdev, "date", "struct tm",
-                      rtc_get_date, NULL, NULL, s, NULL);
+    object_property_add(OBJECT(s), "date", "struct tm",
+                        rtc_get_date, NULL, NULL, s, NULL);
 
     return 0;
 }
@@ -699,20 +709,32 @@ ISADevice *rtc_init(ISABus *bus, int base_year, qemu_irq intercept_irq)
     return dev;
 }
 
-static ISADeviceInfo mc146818rtc_info = {
-    .qdev.name     = "mc146818rtc",
-    .qdev.size     = sizeof(RTCState),
-    .qdev.no_user  = 1,
-    .qdev.vmsd     = &vmstate_rtc,
-    .init          = rtc_initfn,
-    .qdev.props    = (Property[]) {
-        DEFINE_PROP_INT32("base_year", RTCState, base_year, 1980),
-        DEFINE_PROP_END_OF_LIST(),
-    }
+static Property mc146818rtc_properties[] = {
+    DEFINE_PROP_INT32("base_year", RTCState, base_year, 1980),
+    DEFINE_PROP_LOSTTICKPOLICY("lost_tick_policy", RTCState,
+                               lost_tick_policy, LOST_TICK_DISCARD),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void rtc_class_initfn(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    ISADeviceClass *ic = ISA_DEVICE_CLASS(klass);
+    ic->init = rtc_initfn;
+    dc->no_user = 1;
+    dc->vmsd = &vmstate_rtc;
+    dc->props = mc146818rtc_properties;
+}
+
+static TypeInfo mc146818rtc_info = {
+    .name          = "mc146818rtc",
+    .parent        = TYPE_ISA_DEVICE,
+    .instance_size = sizeof(RTCState),
+    .class_init    = rtc_class_initfn,
 };
 
 static void mc146818rtc_register(void)
 {
-    isa_qdev_register(&mc146818rtc_info);
+    type_register_static(&mc146818rtc_info);
 }
 device_init(mc146818rtc_register)
diff --git a/hw/milkymist-ac97.c b/hw/milkymist-ac97.c
index e824a49e9a..0881643a4c 100644
--- a/hw/milkymist-ac97.c
+++ b/hw/milkymist-ac97.c
@@ -319,17 +319,26 @@ static const VMStateDescription vmstate_milkymist_ac97 = {
     }
 };
 
-static SysBusDeviceInfo milkymist_ac97_info = {
-    .init = milkymist_ac97_init,
-    .qdev.name  = "milkymist-ac97",
-    .qdev.size  = sizeof(MilkymistAC97State),
-    .qdev.vmsd  = &vmstate_milkymist_ac97,
-    .qdev.reset = milkymist_ac97_reset,
+static void milkymist_ac97_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = milkymist_ac97_init;
+    dc->reset = milkymist_ac97_reset;
+    dc->vmsd = &vmstate_milkymist_ac97;
+}
+
+static TypeInfo milkymist_ac97_info = {
+    .name          = "milkymist-ac97",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(MilkymistAC97State),
+    .class_init    = milkymist_ac97_class_init,
 };
 
 static void milkymist_ac97_register(void)
 {
-    sysbus_register_withprop(&milkymist_ac97_info);
+    type_register_static(&milkymist_ac97_info);
 }
 
 device_init(milkymist_ac97_register)
diff --git a/hw/milkymist-hpdmc.c b/hw/milkymist-hpdmc.c
index be575c98a0..b5122afd57 100644
--- a/hw/milkymist-hpdmc.c
+++ b/hw/milkymist-hpdmc.c
@@ -145,17 +145,26 @@ static const VMStateDescription vmstate_milkymist_hpdmc = {
     }
 };
 
-static SysBusDeviceInfo milkymist_hpdmc_info = {
-    .init = milkymist_hpdmc_init,
-    .qdev.name  = "milkymist-hpdmc",
-    .qdev.size  = sizeof(MilkymistHpdmcState),
-    .qdev.vmsd  = &vmstate_milkymist_hpdmc,
-    .qdev.reset = milkymist_hpdmc_reset,
+static void milkymist_hpdmc_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = milkymist_hpdmc_init;
+    dc->reset = milkymist_hpdmc_reset;
+    dc->vmsd = &vmstate_milkymist_hpdmc;
+}
+
+static TypeInfo milkymist_hpdmc_info = {
+    .name          = "milkymist-hpdmc",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(MilkymistHpdmcState),
+    .class_init    = milkymist_hpdmc_class_init,
 };
 
 static void milkymist_hpdmc_register(void)
 {
-    sysbus_register_withprop(&milkymist_hpdmc_info);
+    type_register_static(&milkymist_hpdmc_info);
 }
 
 device_init(milkymist_hpdmc_register)
diff --git a/hw/milkymist-memcard.c b/hw/milkymist-memcard.c
index 865a46c127..3c1c68a2e7 100644
--- a/hw/milkymist-memcard.c
+++ b/hw/milkymist-memcard.c
@@ -278,17 +278,26 @@ static const VMStateDescription vmstate_milkymist_memcard = {
     }
 };
 
-static SysBusDeviceInfo milkymist_memcard_info = {
-    .init = milkymist_memcard_init,
-    .qdev.name  = "milkymist-memcard",
-    .qdev.size  = sizeof(MilkymistMemcardState),
-    .qdev.vmsd  = &vmstate_milkymist_memcard,
-    .qdev.reset = milkymist_memcard_reset,
+static void milkymist_memcard_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = milkymist_memcard_init;
+    dc->reset = milkymist_memcard_reset;
+    dc->vmsd = &vmstate_milkymist_memcard;
+}
+
+static TypeInfo milkymist_memcard_info = {
+    .name          = "milkymist-memcard",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(MilkymistMemcardState),
+    .class_init    = milkymist_memcard_class_init,
 };
 
 static void milkymist_memcard_register(void)
 {
-    sysbus_register_withprop(&milkymist_memcard_info);
+    type_register_static(&milkymist_memcard_info);
 }
 
 device_init(milkymist_memcard_register)
diff --git a/hw/milkymist-minimac2.c b/hw/milkymist-minimac2.c
index 7006d29788..b9b553fc95 100644
--- a/hw/milkymist-minimac2.c
+++ b/hw/milkymist-minimac2.c
@@ -479,7 +479,7 @@ static int milkymist_minimac2_init(SysBusDevice *dev)
 
     qemu_macaddr_default_if_unset(&s->conf.macaddr);
     s->nic = qemu_new_nic(&net_milkymist_minimac2_info, &s->conf,
-                          dev->qdev.info->name, dev->qdev.id, s);
+                          object_get_typename(OBJECT(dev)), dev->qdev.id, s);
     qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a);
 
     return 0;
@@ -516,24 +516,35 @@ static const VMStateDescription vmstate_milkymist_minimac2 = {
     }
 };
 
-static SysBusDeviceInfo milkymist_minimac2_info = {
-    .init = milkymist_minimac2_init,
-    .qdev.name  = "milkymist-minimac2",
-    .qdev.size  = sizeof(MilkymistMinimac2State),
-    .qdev.vmsd  = &vmstate_milkymist_minimac2,
-    .qdev.reset = milkymist_minimac2_reset,
-    .qdev.props = (Property[]) {
-        DEFINE_PROP_TADDR("buffers_base", MilkymistMinimac2State,
-                buffers_base, 0),
-        DEFINE_NIC_PROPERTIES(MilkymistMinimac2State, conf),
-        DEFINE_PROP_STRING("phy_model", MilkymistMinimac2State, phy_model),
-        DEFINE_PROP_END_OF_LIST(),
-    }
+static Property milkymist_minimac2_properties[] = {
+    DEFINE_PROP_TADDR("buffers_base", MilkymistMinimac2State,
+    buffers_base, 0),
+    DEFINE_NIC_PROPERTIES(MilkymistMinimac2State, conf),
+    DEFINE_PROP_STRING("phy_model", MilkymistMinimac2State, phy_model),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void milkymist_minimac2_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = milkymist_minimac2_init;
+    dc->reset = milkymist_minimac2_reset;
+    dc->vmsd = &vmstate_milkymist_minimac2;
+    dc->props = milkymist_minimac2_properties;
+}
+
+static TypeInfo milkymist_minimac2_info = {
+    .name          = "milkymist-minimac2",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(MilkymistMinimac2State),
+    .class_init    = milkymist_minimac2_class_init,
 };
 
 static void milkymist_minimac2_register(void)
 {
-    sysbus_register_withprop(&milkymist_minimac2_info);
+    type_register_static(&milkymist_minimac2_info);
 }
 
 device_init(milkymist_minimac2_register)
diff --git a/hw/milkymist-pfpu.c b/hw/milkymist-pfpu.c
index dc92eb68e3..1b73a4686b 100644
--- a/hw/milkymist-pfpu.c
+++ b/hw/milkymist-pfpu.c
@@ -519,17 +519,26 @@ static const VMStateDescription vmstate_milkymist_pfpu = {
     }
 };
 
-static SysBusDeviceInfo milkymist_pfpu_info = {
-    .init = milkymist_pfpu_init,
-    .qdev.name  = "milkymist-pfpu",
-    .qdev.size  = sizeof(MilkymistPFPUState),
-    .qdev.vmsd  = &vmstate_milkymist_pfpu,
-    .qdev.reset = milkymist_pfpu_reset,
+static void milkymist_pfpu_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = milkymist_pfpu_init;
+    dc->reset = milkymist_pfpu_reset;
+    dc->vmsd = &vmstate_milkymist_pfpu;
+}
+
+static TypeInfo milkymist_pfpu_info = {
+    .name          = "milkymist-pfpu",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(MilkymistPFPUState),
+    .class_init    = milkymist_pfpu_class_init,
 };
 
 static void milkymist_pfpu_register(void)
 {
-    sysbus_register_withprop(&milkymist_pfpu_info);
+    type_register_static(&milkymist_pfpu_info);
 }
 
 device_init(milkymist_pfpu_register)
diff --git a/hw/milkymist-softusb.c b/hw/milkymist-softusb.c
index 83bd1c4c6b..5d496cbdb0 100644
--- a/hw/milkymist-softusb.c
+++ b/hw/milkymist-softusb.c
@@ -297,32 +297,35 @@ static const VMStateDescription vmstate_milkymist_softusb = {
     }
 };
 
-static SysBusDeviceInfo milkymist_softusb_info = {
-    .init = milkymist_softusb_init,
-    .qdev.name  = "milkymist-softusb",
-    .qdev.size  = sizeof(MilkymistSoftUsbState),
-    .qdev.vmsd  = &vmstate_milkymist_softusb,
-    .qdev.reset = milkymist_softusb_reset,
-    .qdev.props = (Property[]) {
-        DEFINE_PROP_UINT32(
-                "pmem_base", MilkymistSoftUsbState, pmem_base, 0xa0000000
-        ),
-        DEFINE_PROP_UINT32(
-                "pmem_size", MilkymistSoftUsbState, pmem_size, 0x00001000
-        ),
-        DEFINE_PROP_UINT32(
-                "dmem_base", MilkymistSoftUsbState, dmem_base, 0xa0020000
-        ),
-        DEFINE_PROP_UINT32(
-                "dmem_size", MilkymistSoftUsbState, dmem_size, 0x00002000
-        ),
-        DEFINE_PROP_END_OF_LIST(),
-    }
+static Property milkymist_softusb_properties[] = {
+    DEFINE_PROP_UINT32("pmem_base", MilkymistSoftUsbState, pmem_base, 0xa0000000),
+    DEFINE_PROP_UINT32("pmem_size", MilkymistSoftUsbState, pmem_size, 0x00001000),
+    DEFINE_PROP_UINT32("dmem_base", MilkymistSoftUsbState, dmem_base, 0xa0020000),
+    DEFINE_PROP_UINT32("dmem_size", MilkymistSoftUsbState, dmem_size, 0x00002000),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void milkymist_softusb_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = milkymist_softusb_init;
+    dc->reset = milkymist_softusb_reset;
+    dc->vmsd = &vmstate_milkymist_softusb;
+    dc->props = milkymist_softusb_properties;
+}
+
+static TypeInfo milkymist_softusb_info = {
+    .name          = "milkymist-softusb",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(MilkymistSoftUsbState),
+    .class_init    = milkymist_softusb_class_init,
 };
 
 static void milkymist_softusb_register(void)
 {
-    sysbus_register_withprop(&milkymist_softusb_info);
+    type_register_static(&milkymist_softusb_info);
 }
 
 device_init(milkymist_softusb_register)
diff --git a/hw/milkymist-sysctl.c b/hw/milkymist-sysctl.c
index bd2a298d2e..18171f6165 100644
--- a/hw/milkymist-sysctl.c
+++ b/hw/milkymist-sysctl.c
@@ -292,28 +292,39 @@ static const VMStateDescription vmstate_milkymist_sysctl = {
     }
 };
 
-static SysBusDeviceInfo milkymist_sysctl_info = {
-    .init = milkymist_sysctl_init,
-    .qdev.name  = "milkymist-sysctl",
-    .qdev.size  = sizeof(MilkymistSysctlState),
-    .qdev.vmsd  = &vmstate_milkymist_sysctl,
-    .qdev.reset = milkymist_sysctl_reset,
-    .qdev.props = (Property[]) {
-        DEFINE_PROP_UINT32("frequency", MilkymistSysctlState,
-                freq_hz, 80000000),
-        DEFINE_PROP_UINT32("capabilities", MilkymistSysctlState,
-                capabilities, 0x00000000),
-        DEFINE_PROP_UINT32("systemid", MilkymistSysctlState,
-                systemid, 0x10014d31),
-        DEFINE_PROP_UINT32("gpio_strappings", MilkymistSysctlState,
-                strappings, 0x00000001),
-        DEFINE_PROP_END_OF_LIST(),
-    }
+static Property milkymist_sysctl_properties[] = {
+    DEFINE_PROP_UINT32("frequency", MilkymistSysctlState,
+    freq_hz, 80000000),
+    DEFINE_PROP_UINT32("capabilities", MilkymistSysctlState,
+    capabilities, 0x00000000),
+    DEFINE_PROP_UINT32("systemid", MilkymistSysctlState,
+    systemid, 0x10014d31),
+    DEFINE_PROP_UINT32("gpio_strappings", MilkymistSysctlState,
+    strappings, 0x00000001),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void milkymist_sysctl_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = milkymist_sysctl_init;
+    dc->reset = milkymist_sysctl_reset;
+    dc->vmsd = &vmstate_milkymist_sysctl;
+    dc->props = milkymist_sysctl_properties;
+}
+
+static TypeInfo milkymist_sysctl_info = {
+    .name          = "milkymist-sysctl",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(MilkymistSysctlState),
+    .class_init    = milkymist_sysctl_class_init,
 };
 
 static void milkymist_sysctl_register(void)
 {
-    sysbus_register_withprop(&milkymist_sysctl_info);
+    type_register_static(&milkymist_sysctl_info);
 }
 
 device_init(milkymist_sysctl_register)
diff --git a/hw/milkymist-tmu2.c b/hw/milkymist-tmu2.c
index 20110e5a83..474eae0a4a 100644
--- a/hw/milkymist-tmu2.c
+++ b/hw/milkymist-tmu2.c
@@ -465,17 +465,26 @@ static const VMStateDescription vmstate_milkymist_tmu2 = {
     }
 };
 
-static SysBusDeviceInfo milkymist_tmu2_info = {
-    .init = milkymist_tmu2_init,
-    .qdev.name  = "milkymist-tmu2",
-    .qdev.size  = sizeof(MilkymistTMU2State),
-    .qdev.vmsd  = &vmstate_milkymist_tmu2,
-    .qdev.reset = milkymist_tmu2_reset,
+static void milkymist_tmu2_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = milkymist_tmu2_init;
+    dc->reset = milkymist_tmu2_reset;
+    dc->vmsd = &vmstate_milkymist_tmu2;
+}
+
+static TypeInfo milkymist_tmu2_info = {
+    .name          = "milkymist-tmu2",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(MilkymistTMU2State),
+    .class_init    = milkymist_tmu2_class_init,
 };
 
 static void milkymist_tmu2_register(void)
 {
-    sysbus_register_withprop(&milkymist_tmu2_info);
+    type_register_static(&milkymist_tmu2_info);
 }
 
 device_init(milkymist_tmu2_register)
diff --git a/hw/milkymist-uart.c b/hw/milkymist-uart.c
index eaf1c0dce1..f9a229cf68 100644
--- a/hw/milkymist-uart.c
+++ b/hw/milkymist-uart.c
@@ -199,7 +199,7 @@ static int milkymist_uart_init(SysBusDevice *dev)
             "milkymist-uart", R_MAX * 4);
     sysbus_init_mmio(dev, &s->regs_region);
 
-    s->chr = qdev_init_chardev(&dev->qdev);
+    s->chr = qemu_char_get_next_serial();
     if (s->chr) {
         qemu_chr_add_handlers(s->chr, uart_can_rx, uart_rx, uart_event, s);
     }
@@ -218,17 +218,26 @@ static const VMStateDescription vmstate_milkymist_uart = {
     }
 };
 
-static SysBusDeviceInfo milkymist_uart_info = {
-    .init = milkymist_uart_init,
-    .qdev.name  = "milkymist-uart",
-    .qdev.size  = sizeof(MilkymistUartState),
-    .qdev.vmsd  = &vmstate_milkymist_uart,
-    .qdev.reset = milkymist_uart_reset,
+static void milkymist_uart_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = milkymist_uart_init;
+    dc->reset = milkymist_uart_reset;
+    dc->vmsd = &vmstate_milkymist_uart;
+}
+
+static TypeInfo milkymist_uart_info = {
+    .name          = "milkymist-uart",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(MilkymistUartState),
+    .class_init    = milkymist_uart_class_init,
 };
 
 static void milkymist_uart_register(void)
 {
-    sysbus_register_withprop(&milkymist_uart_info);
+    type_register_static(&milkymist_uart_info);
 }
 
 device_init(milkymist_uart_register)
diff --git a/hw/milkymist-vgafb.c b/hw/milkymist-vgafb.c
index 108115e300..92ad02f9e2 100644
--- a/hw/milkymist-vgafb.c
+++ b/hw/milkymist-vgafb.c
@@ -299,22 +299,33 @@ static const VMStateDescription vmstate_milkymist_vgafb = {
     }
 };
 
-static SysBusDeviceInfo milkymist_vgafb_info = {
-    .init = milkymist_vgafb_init,
-    .qdev.name  = "milkymist-vgafb",
-    .qdev.size  = sizeof(MilkymistVgafbState),
-    .qdev.vmsd  = &vmstate_milkymist_vgafb,
-    .qdev.reset = milkymist_vgafb_reset,
-    .qdev.props = (Property[]) {
-        DEFINE_PROP_UINT32("fb_offset", MilkymistVgafbState, fb_offset, 0x0),
-        DEFINE_PROP_UINT32("fb_mask", MilkymistVgafbState, fb_mask, 0xffffffff),
-        DEFINE_PROP_END_OF_LIST(),
-    }
+static Property milkymist_vgafb_properties[] = {
+    DEFINE_PROP_UINT32("fb_offset", MilkymistVgafbState, fb_offset, 0x0),
+    DEFINE_PROP_UINT32("fb_mask", MilkymistVgafbState, fb_mask, 0xffffffff),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void milkymist_vgafb_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = milkymist_vgafb_init;
+    dc->reset = milkymist_vgafb_reset;
+    dc->vmsd = &vmstate_milkymist_vgafb;
+    dc->props = milkymist_vgafb_properties;
+}
+
+static TypeInfo milkymist_vgafb_info = {
+    .name          = "milkymist-vgafb",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(MilkymistVgafbState),
+    .class_init    = milkymist_vgafb_class_init,
 };
 
 static void milkymist_vgafb_register(void)
 {
-    sysbus_register_withprop(&milkymist_vgafb_info);
+    type_register_static(&milkymist_vgafb_info);
 }
 
 device_init(milkymist_vgafb_register)
diff --git a/hw/milkymist-vgafb_template.h b/hw/milkymist-vgafb_template.h
index 69af9ef3f6..1d33ee8b50 100644
--- a/hw/milkymist-vgafb_template.h
+++ b/hw/milkymist-vgafb_template.h
@@ -39,7 +39,7 @@
 #elif BITS == 24
 #define COPY_PIXEL(to, r, g, b)                    \
     do {                                           \
-        uint32 tmp = rgb_to_pixel24(r, g, b);      \
+        uint32_t tmp = rgb_to_pixel24(r, g, b);    \
         *(to++) =         tmp & 0xff;              \
         *(to++) =  (tmp >> 8) & 0xff;              \
         *(to++) = (tmp >> 16) & 0xff;              \
diff --git a/hw/mips_malta.c b/hw/mips_malta.c
index e625ec398f..d232630e66 100644
--- a/hw/mips_malta.c
+++ b/hw/mips_malta.c
@@ -996,11 +996,7 @@ void mips_malta_init (ram_addr_t ram_size,
     if (cirrus_vga_enabled) {
         pci_cirrus_vga_init(pci_bus);
     } else if (vmsvga_enabled) {
-        if (!pci_vmsvga_init(pci_bus)) {
-            fprintf(stderr, "Warning: vmware_vga not available,"
-                    " using standard VGA instead\n");
-            pci_vga_init(pci_bus);
-        }
+        pci_vmsvga_init(pci_bus);
     } else if (std_vga_enabled) {
         pci_vga_init(pci_bus);
     }
@@ -1011,13 +1007,18 @@ static int mips_malta_sysbus_device_init(SysBusDevice *sysbusdev)
     return 0;
 }
 
-static SysBusDeviceInfo mips_malta_device = {
-    .init = mips_malta_sysbus_device_init,
-    .qdev.name  = "mips-malta",
-    .qdev.size  = sizeof(MaltaState),
-    .qdev.props = (Property[]) {
-        DEFINE_PROP_END_OF_LIST(),
-    }
+static void mips_malta_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = mips_malta_sysbus_device_init;
+}
+
+static TypeInfo mips_malta_device = {
+    .name          = "mips-malta",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(MaltaState),
+    .class_init    = mips_malta_class_init,
 };
 
 static QEMUMachine mips_malta_machine = {
@@ -1030,7 +1031,7 @@ static QEMUMachine mips_malta_machine = {
 
 static void mips_malta_device_init(void)
 {
-    sysbus_register_withprop(&mips_malta_device);
+    type_register_static(&mips_malta_device);
 }
 
 static void mips_malta_machine_init(void)
diff --git a/hw/mipsnet.c b/hw/mipsnet.c
index b1234b8282..a0e6c9fa1e 100644
--- a/hw/mipsnet.c
+++ b/hw/mipsnet.c
@@ -240,7 +240,7 @@ static int mipsnet_sysbus_init(SysBusDevice *dev)
     sysbus_init_irq(dev, &s->irq);
 
     s->nic = qemu_new_nic(&net_mipsnet_info, &s->conf,
-                          dev->qdev.info->name, dev->qdev.id, s);
+                          object_get_typename(OBJECT(dev)), dev->qdev.id, s);
     qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a);
 
     return 0;
@@ -252,22 +252,33 @@ static void mipsnet_sysbus_reset(DeviceState *dev)
     mipsnet_reset(s);
 }
 
-static SysBusDeviceInfo mipsnet_info = {
-    .init = mipsnet_sysbus_init,
-    .qdev.name = "mipsnet",
-    .qdev.desc = "MIPS Simulator network device",
-    .qdev.size = sizeof(MIPSnetState),
-    .qdev.vmsd = &vmstate_mipsnet,
-    .qdev.reset = mipsnet_sysbus_reset,
-    .qdev.props = (Property[]) {
-        DEFINE_NIC_PROPERTIES(MIPSnetState, conf),
-        DEFINE_PROP_END_OF_LIST(),
-    }
+static Property mipsnet_properties[] = {
+    DEFINE_NIC_PROPERTIES(MIPSnetState, conf),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void mipsnet_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = mipsnet_sysbus_init;
+    dc->desc = "MIPS Simulator network device";
+    dc->reset = mipsnet_sysbus_reset;
+    dc->vmsd = &vmstate_mipsnet;
+    dc->props = mipsnet_properties;
+}
+
+static TypeInfo mipsnet_info = {
+    .name          = "mipsnet",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(MIPSnetState),
+    .class_init    = mipsnet_class_init,
 };
 
 static void mipsnet_register_devices(void)
 {
-    sysbus_register_withprop(&mipsnet_info);
+    type_register_static(&mipsnet_info);
 }
 
 device_init(mipsnet_register_devices)
diff --git a/hw/mpc8544_guts.c b/hw/mpc8544_guts.c
index f01b38cfc2..28cd60d89c 100644
--- a/hw/mpc8544_guts.c
+++ b/hw/mpc8544_guts.c
@@ -121,14 +121,22 @@ static int mpc8544_guts_initfn(SysBusDevice *dev)
     return 0;
 }
 
-static SysBusDeviceInfo mpc8544_guts_info = {
-    .init         = mpc8544_guts_initfn,
-    .qdev.name    = "mpc8544-guts",
-    .qdev.size    = sizeof(GutsState),
+static void mpc8544_guts_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = mpc8544_guts_initfn;
+}
+
+static TypeInfo mpc8544_guts_info = {
+    .name          = "mpc8544-guts",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(GutsState),
+    .class_init    = mpc8544_guts_class_init,
 };
 
 static void mpc8544_guts_register(void)
 {
-    sysbus_register_withprop(&mpc8544_guts_info);
+    type_register_static(&mpc8544_guts_info);
 }
 device_init(mpc8544_guts_register);
diff --git a/hw/msi.c b/hw/msi.c
index f214fcf579..5d6ceb6df0 100644
--- a/hw/msi.c
+++ b/hw/msi.c
@@ -36,6 +36,9 @@
 
 #define PCI_MSI_VECTORS_MAX     32
 
+/* Flag for interrupt controller to declare MSI/MSI-X support */
+bool msi_supported;
+
 /* If we get rid of cap allocator, we won't need this. */
 static inline uint8_t msi_cap_sizeof(uint16_t flags)
 {
@@ -116,6 +119,11 @@ int msi_init(struct PCIDevice *dev, uint8_t offset,
     uint16_t flags;
     uint8_t cap_size;
     int config_offset;
+
+    if (!msi_supported) {
+        return -ENOTSUP;
+    }
+
     MSI_DEV_PRINTF(dev,
                    "init offset: 0x%"PRIx8" vector: %"PRId8
                    " 64bit %d mask %d\n",
diff --git a/hw/msi.h b/hw/msi.h
index 5766018d79..3040bb0b43 100644
--- a/hw/msi.h
+++ b/hw/msi.h
@@ -24,6 +24,8 @@
 #include "qemu-common.h"
 #include "pci.h"
 
+extern bool msi_supported;
+
 bool msi_enabled(const PCIDevice *dev);
 int msi_init(struct PCIDevice *dev, uint8_t offset,
              unsigned int nr_vectors, bool msi64bit, bool msi_per_vector_mask);
diff --git a/hw/msix.c b/hw/msix.c
index f47d26bb49..3835eaaf28 100644
--- a/hw/msix.c
+++ b/hw/msix.c
@@ -15,6 +15,7 @@
  */
 
 #include "hw.h"
+#include "msi.h"
 #include "msix.h"
 #include "pci.h"
 #include "range.h"
@@ -35,9 +36,6 @@
 #define MSIX_MAX_ENTRIES 32
 
 
-/* Flag for interrupt controller to declare MSI-X support */
-int msix_supported;
-
 /* Add MSI-X capability to the config space for the device. */
 /* Given a bar and its size, add MSI-X table on top of it
  * and fill MSI-X capability in the config space.
@@ -238,10 +236,11 @@ int msix_init(struct PCIDevice *dev, unsigned short nentries,
               unsigned bar_nr, unsigned bar_size)
 {
     int ret;
+
     /* Nothing to do if MSI is not supported by interrupt controller */
-    if (!msix_supported)
+    if (!msi_supported) {
         return -ENOTSUP;
-
+    }
     if (nentries > MSIX_MAX_ENTRIES)
         return -EINVAL;
 
diff --git a/hw/msix.h b/hw/msix.h
index 7e04336618..5aba22b858 100644
--- a/hw/msix.h
+++ b/hw/msix.h
@@ -29,6 +29,4 @@ void msix_notify(PCIDevice *dev, unsigned vector);
 
 void msix_reset(PCIDevice *dev);
 
-extern int msix_supported;
-
 #endif
diff --git a/hw/mst_fpga.c b/hw/mst_fpga.c
index 8bfa5dda37..1729db01a4 100644
--- a/hw/mst_fpga.c
+++ b/hw/mst_fpga.c
@@ -238,16 +238,25 @@ static VMStateDescription vmstate_mst_fpga_regs = {
 	},
 };
 
-static SysBusDeviceInfo mst_fpga_info = {
-	.init = mst_fpga_init,
-	.qdev.name = "mainstone-fpga",
-	.qdev.desc = "Mainstone II FPGA",
-	.qdev.size = sizeof(mst_irq_state),
-	.qdev.vmsd = &vmstate_mst_fpga_regs,
+static void mst_fpga_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = mst_fpga_init;
+    dc->desc = "Mainstone II FPGA";
+    dc->vmsd = &vmstate_mst_fpga_regs;
+}
+
+static TypeInfo mst_fpga_info = {
+    .name          = "mainstone-fpga",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(mst_irq_state),
+    .class_init    = mst_fpga_class_init,
 };
 
 static void mst_fpga_register(void)
 {
-	sysbus_register_withprop(&mst_fpga_info);
+    type_register_static(&mst_fpga_info);
 }
 device_init(mst_fpga_register);
diff --git a/hw/musicpal.c b/hw/musicpal.c
index 977ffb6e50..ac909248d4 100644
--- a/hw/musicpal.c
+++ b/hw/musicpal.c
@@ -387,7 +387,7 @@ static int mv88w8618_eth_init(SysBusDevice *dev)
 
     sysbus_init_irq(dev, &s->irq);
     s->nic = qemu_new_nic(&net_mv88w8618_info, &s->conf,
-                          dev->qdev.info->name, dev->qdev.id, s);
+                          object_get_typename(OBJECT(dev)), dev->qdev.id, s);
     memory_region_init_io(&s->iomem, &mv88w8618_eth_ops, s, "mv88w8618-eth",
                           MP_ETH_SIZE);
     sysbus_init_mmio(dev, &s->iomem);
@@ -412,15 +412,26 @@ static const VMStateDescription mv88w8618_eth_vmsd = {
     }
 };
 
-static SysBusDeviceInfo mv88w8618_eth_info = {
-    .init = mv88w8618_eth_init,
-    .qdev.name = "mv88w8618_eth",
-    .qdev.size = sizeof(mv88w8618_eth_state),
-    .qdev.vmsd = &mv88w8618_eth_vmsd,
-    .qdev.props = (Property[]) {
-        DEFINE_NIC_PROPERTIES(mv88w8618_eth_state, conf),
-        DEFINE_PROP_END_OF_LIST(),
-    },
+static Property mv88w8618_eth_properties[] = {
+    DEFINE_NIC_PROPERTIES(mv88w8618_eth_state, conf),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void mv88w8618_eth_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = mv88w8618_eth_init;
+    dc->vmsd = &mv88w8618_eth_vmsd;
+    dc->props = mv88w8618_eth_properties;
+}
+
+static TypeInfo mv88w8618_eth_info = {
+    .name          = "mv88w8618_eth",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(mv88w8618_eth_state),
+    .class_init    = mv88w8618_eth_class_init,
 };
 
 /* LCD register offsets */
@@ -624,11 +635,20 @@ static const VMStateDescription musicpal_lcd_vmsd = {
     }
 };
 
-static SysBusDeviceInfo musicpal_lcd_info = {
-    .init = musicpal_lcd_init,
-    .qdev.name = "musicpal_lcd",
-    .qdev.size = sizeof(musicpal_lcd_state),
-    .qdev.vmsd = &musicpal_lcd_vmsd,
+static void musicpal_lcd_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = musicpal_lcd_init;
+    dc->vmsd = &musicpal_lcd_vmsd;
+}
+
+static TypeInfo musicpal_lcd_info = {
+    .name          = "musicpal_lcd",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(musicpal_lcd_state),
+    .class_init    = musicpal_lcd_class_init,
 };
 
 /* PIC register offsets */
@@ -733,12 +753,21 @@ static const VMStateDescription mv88w8618_pic_vmsd = {
     }
 };
 
-static SysBusDeviceInfo mv88w8618_pic_info = {
-    .init = mv88w8618_pic_init,
-    .qdev.name = "mv88w8618_pic",
-    .qdev.size = sizeof(mv88w8618_pic_state),
-    .qdev.reset = mv88w8618_pic_reset,
-    .qdev.vmsd = &mv88w8618_pic_vmsd,
+static void mv88w8618_pic_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = mv88w8618_pic_init;
+    dc->reset = mv88w8618_pic_reset;
+    dc->vmsd = &mv88w8618_pic_vmsd;
+}
+
+static TypeInfo mv88w8618_pic_info = {
+    .name          = "mv88w8618_pic",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(mv88w8618_pic_state),
+    .class_init    = mv88w8618_pic_class_init,
 };
 
 /* PIT register offsets */
@@ -901,12 +930,21 @@ static const VMStateDescription mv88w8618_pit_vmsd = {
     }
 };
 
-static SysBusDeviceInfo mv88w8618_pit_info = {
-    .init = mv88w8618_pit_init,
-    .qdev.name  = "mv88w8618_pit",
-    .qdev.size  = sizeof(mv88w8618_pit_state),
-    .qdev.reset = mv88w8618_pit_reset,
-    .qdev.vmsd  = &mv88w8618_pit_vmsd,
+static void mv88w8618_pit_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = mv88w8618_pit_init;
+    dc->reset = mv88w8618_pit_reset;
+    dc->vmsd = &mv88w8618_pit_vmsd;
+}
+
+static TypeInfo mv88w8618_pit_info = {
+    .name          = "mv88w8618_pit",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(mv88w8618_pit_state),
+    .class_init    = mv88w8618_pit_class_init,
 };
 
 /* Flash config register offsets */
@@ -973,11 +1011,20 @@ static const VMStateDescription mv88w8618_flashcfg_vmsd = {
     }
 };
 
-static SysBusDeviceInfo mv88w8618_flashcfg_info = {
-    .init = mv88w8618_flashcfg_init,
-    .qdev.name  = "mv88w8618_flashcfg",
-    .qdev.size  = sizeof(mv88w8618_flashcfg_state),
-    .qdev.vmsd  = &mv88w8618_flashcfg_vmsd,
+static void mv88w8618_flashcfg_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = mv88w8618_flashcfg_init;
+    dc->vmsd = &mv88w8618_flashcfg_vmsd;
+}
+
+static TypeInfo mv88w8618_flashcfg_info = {
+    .name          = "mv88w8618_flashcfg",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(mv88w8618_flashcfg_state),
+    .class_init    = mv88w8618_flashcfg_class_init,
 };
 
 /* Misc register offsets */
@@ -1285,12 +1332,21 @@ static const VMStateDescription musicpal_gpio_vmsd = {
     }
 };
 
-static SysBusDeviceInfo musicpal_gpio_info = {
-    .init = musicpal_gpio_init,
-    .qdev.name  = "musicpal_gpio",
-    .qdev.size  = sizeof(musicpal_gpio_state),
-    .qdev.reset = musicpal_gpio_reset,
-    .qdev.vmsd  = &musicpal_gpio_vmsd,
+static void musicpal_gpio_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = musicpal_gpio_init;
+    dc->reset = musicpal_gpio_reset;
+    dc->vmsd = &musicpal_gpio_vmsd;
+}
+
+static TypeInfo musicpal_gpio_info = {
+    .name          = "musicpal_gpio",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(musicpal_gpio_state),
+    .class_init    = musicpal_gpio_class_init,
 };
 
 /* Keyboard codes & masks */
@@ -1431,11 +1487,20 @@ static const VMStateDescription musicpal_key_vmsd = {
     }
 };
 
-static SysBusDeviceInfo musicpal_key_info = {
-    .init = musicpal_key_init,
-    .qdev.name  = "musicpal_key",
-    .qdev.size  = sizeof(musicpal_key_state),
-    .qdev.vmsd  = &musicpal_key_vmsd,
+static void musicpal_key_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = musicpal_key_init;
+    dc->vmsd = &musicpal_key_vmsd;
+}
+
+static TypeInfo musicpal_key_info = {
+    .name          = "musicpal_key",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(musicpal_key_state),
+    .class_init    = musicpal_key_class_init,
 };
 
 static struct arm_boot_info musicpal_binfo = {
@@ -1602,17 +1667,30 @@ static void musicpal_machine_init(void)
 
 machine_init(musicpal_machine_init);
 
+static void mv88w8618_wlan_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+
+    sdc->init = mv88w8618_wlan_init;
+}
+
+static TypeInfo mv88w8618_wlan_info = {
+    .name          = "mv88w8618_wlan",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(SysBusDevice),
+    .class_init    = mv88w8618_wlan_class_init,
+};
+
 static void musicpal_register_devices(void)
 {
-    sysbus_register_withprop(&mv88w8618_pic_info);
-    sysbus_register_withprop(&mv88w8618_pit_info);
-    sysbus_register_withprop(&mv88w8618_flashcfg_info);
-    sysbus_register_withprop(&mv88w8618_eth_info);
-    sysbus_register_dev("mv88w8618_wlan", sizeof(SysBusDevice),
-                        mv88w8618_wlan_init);
-    sysbus_register_withprop(&musicpal_lcd_info);
-    sysbus_register_withprop(&musicpal_gpio_info);
-    sysbus_register_withprop(&musicpal_key_info);
+    type_register_static(&mv88w8618_pic_info);
+    type_register_static(&mv88w8618_pit_info);
+    type_register_static(&mv88w8618_flashcfg_info);
+    type_register_static(&mv88w8618_eth_info);
+    type_register_static(&mv88w8618_wlan_info);
+    type_register_static(&musicpal_lcd_info);
+    type_register_static(&musicpal_gpio_info);
+    type_register_static(&musicpal_key_info);
 }
 
 device_init(musicpal_register_devices)
diff --git a/hw/nand.c b/hw/nand.c
index 8597aa6b1c..5d947b1ced 100644
--- a/hw/nand.c
+++ b/hw/nand.c
@@ -417,23 +417,34 @@ static int nand_device_init(SysBusDevice *dev)
     return 0;
 }
 
-static SysBusDeviceInfo nand_info = {
-    .init = nand_device_init,
-    .qdev.name = "nand",
-    .qdev.size = sizeof(NANDFlashState),
-    .qdev.reset = nand_reset,
-    .qdev.vmsd = &vmstate_nand,
-    .qdev.props = (Property[]) {
-        DEFINE_PROP_UINT8("manufacturer_id", NANDFlashState, manf_id, 0),
-        DEFINE_PROP_UINT8("chip_id", NANDFlashState, chip_id, 0),
-        DEFINE_PROP_DRIVE("drive", NANDFlashState, bdrv),
-        DEFINE_PROP_END_OF_LIST()
-    }
+static Property nand_properties[] = {
+    DEFINE_PROP_UINT8("manufacturer_id", NANDFlashState, manf_id, 0),
+    DEFINE_PROP_UINT8("chip_id", NANDFlashState, chip_id, 0),
+    DEFINE_PROP_DRIVE("drive", NANDFlashState, bdrv),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void nand_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = nand_device_init;
+    dc->reset = nand_reset;
+    dc->vmsd = &vmstate_nand;
+    dc->props = nand_properties;
+}
+
+static TypeInfo nand_info = {
+    .name          = "nand",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(NANDFlashState),
+    .class_init    = nand_class_init,
 };
 
 static void nand_create_device(void)
 {
-    sysbus_register_withprop(&nand_info);
+    type_register_static(&nand_info);
 }
 
 /*
diff --git a/hw/ne2000-isa.c b/hw/ne2000-isa.c
index 11ffee7d7c..1352282152 100644
--- a/hw/ne2000-isa.c
+++ b/hw/ne2000-isa.c
@@ -76,27 +76,37 @@ static int isa_ne2000_initfn(ISADevice *dev)
     ne2000_reset(s);
 
     s->nic = qemu_new_nic(&net_ne2000_isa_info, &s->c,
-                          dev->qdev.info->name, dev->qdev.id, s);
+                          object_get_typename(OBJECT(dev)), dev->qdev.id, s);
     qemu_format_nic_info_str(&s->nic->nc, s->c.macaddr.a);
 
     return 0;
 }
 
-static ISADeviceInfo ne2000_isa_info = {
-    .qdev.name  = "ne2k_isa",
-    .qdev.size  = sizeof(ISANE2000State),
-    .init       = isa_ne2000_initfn,
-    .qdev.props = (Property[]) {
-        DEFINE_PROP_HEX32("iobase", ISANE2000State, iobase, 0x300),
-        DEFINE_PROP_UINT32("irq",   ISANE2000State, isairq, 9),
-        DEFINE_NIC_PROPERTIES(ISANE2000State, ne2000.c),
-        DEFINE_PROP_END_OF_LIST(),
-    },
+static Property ne2000_isa_properties[] = {
+    DEFINE_PROP_HEX32("iobase", ISANE2000State, iobase, 0x300),
+    DEFINE_PROP_UINT32("irq",   ISANE2000State, isairq, 9),
+    DEFINE_NIC_PROPERTIES(ISANE2000State, ne2000.c),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void isa_ne2000_class_initfn(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    ISADeviceClass *ic = ISA_DEVICE_CLASS(klass);
+    ic->init = isa_ne2000_initfn;
+    dc->props = ne2000_isa_properties;
+}
+
+static TypeInfo ne2000_isa_info = {
+    .name          = "ne2k_isa",
+    .parent        = TYPE_ISA_DEVICE,
+    .instance_size = sizeof(ISANE2000State),
+    .class_init    = isa_ne2000_class_initfn,
 };
 
 static void ne2000_isa_register_devices(void)
 {
-    isa_qdev_register(&ne2000_isa_info);
+    type_register_static(&ne2000_isa_info);
 }
 
 device_init(ne2000_isa_register_devices)
diff --git a/hw/ne2000.c b/hw/ne2000.c
index 62e082f8a9..080811ec4d 100644
--- a/hw/ne2000.c
+++ b/hw/ne2000.c
@@ -760,7 +760,7 @@ static int pci_ne2000_init(PCIDevice *pci_dev)
     ne2000_reset(s);
 
     s->nic = qemu_new_nic(&net_ne2000_info, &s->c,
-                          pci_dev->qdev.info->name, pci_dev->qdev.id, s);
+                          object_get_typename(OBJECT(pci_dev)), pci_dev->qdev.id, s);
     qemu_format_nic_info_str(&s->nic->nc, s->c.macaddr.a);
 
     if (!pci_dev->qdev.hotplugged) {
@@ -786,24 +786,35 @@ static int pci_ne2000_exit(PCIDevice *pci_dev)
     return 0;
 }
 
-static PCIDeviceInfo ne2000_info = {
-    .qdev.name  = "ne2k_pci",
-    .qdev.size  = sizeof(PCINE2000State),
-    .qdev.vmsd  = &vmstate_pci_ne2000,
-    .init       = pci_ne2000_init,
-    .exit       = pci_ne2000_exit,
-    .vendor_id  = PCI_VENDOR_ID_REALTEK,
-    .device_id  = PCI_DEVICE_ID_REALTEK_8029,
-    .class_id   = PCI_CLASS_NETWORK_ETHERNET,
-    .qdev.props = (Property[]) {
-        DEFINE_NIC_PROPERTIES(PCINE2000State, ne2000.c),
-        DEFINE_PROP_END_OF_LIST(),
-    }
+static Property ne2000_properties[] = {
+    DEFINE_NIC_PROPERTIES(PCINE2000State, ne2000.c),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void ne2000_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->init = pci_ne2000_init;
+    k->exit = pci_ne2000_exit;
+    k->vendor_id = PCI_VENDOR_ID_REALTEK;
+    k->device_id = PCI_DEVICE_ID_REALTEK_8029;
+    k->class_id = PCI_CLASS_NETWORK_ETHERNET;
+    dc->vmsd = &vmstate_pci_ne2000;
+    dc->props = ne2000_properties;
+}
+
+static TypeInfo ne2000_info = {
+    .name          = "ne2k_pci",
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(PCINE2000State),
+    .class_init    = ne2000_class_init,
 };
 
 static void ne2000_register_devices(void)
 {
-    pci_qdev_register(&ne2000_info);
+    type_register_static(&ne2000_info);
 }
 
 device_init(ne2000_register_devices)
diff --git a/hw/omap_gpio.c b/hw/omap_gpio.c
index 29147be8b8..9a9a8e183f 100644
--- a/hw/omap_gpio.c
+++ b/hw/omap_gpio.c
@@ -731,40 +731,62 @@ static int omap2_gpio_init(SysBusDevice *dev)
  * translation.)
  */
 
-static SysBusDeviceInfo omap_gpio_info = {
-    .init = omap_gpio_init,
-    .qdev.name = "omap-gpio",
-    .qdev.size = sizeof(struct omap_gpif_s),
-    .qdev.reset = omap_gpif_reset,
-    .qdev.props = (Property[]) {
-        DEFINE_PROP_INT32("mpu_model", struct omap_gpif_s, mpu_model, 0),
-        DEFINE_PROP_PTR("clk", struct omap_gpif_s, clk),
-        DEFINE_PROP_END_OF_LIST()
-    }
+static Property omap_gpio_properties[] = {
+    DEFINE_PROP_INT32("mpu_model", struct omap_gpif_s, mpu_model, 0),
+    DEFINE_PROP_PTR("clk", struct omap_gpif_s, clk),
+    DEFINE_PROP_END_OF_LIST(),
 };
 
-static SysBusDeviceInfo omap2_gpio_info = {
-    .init = omap2_gpio_init,
-    .qdev.name = "omap2-gpio",
-    .qdev.size = sizeof(struct omap2_gpif_s),
-    .qdev.reset = omap2_gpif_reset,
-    .qdev.props = (Property[]) {
-        DEFINE_PROP_INT32("mpu_model", struct omap2_gpif_s, mpu_model, 0),
-        DEFINE_PROP_PTR("iclk", struct omap2_gpif_s, iclk),
-        DEFINE_PROP_PTR("fclk0", struct omap2_gpif_s, fclk[0]),
-        DEFINE_PROP_PTR("fclk1", struct omap2_gpif_s, fclk[1]),
-        DEFINE_PROP_PTR("fclk2", struct omap2_gpif_s, fclk[2]),
-        DEFINE_PROP_PTR("fclk3", struct omap2_gpif_s, fclk[3]),
-        DEFINE_PROP_PTR("fclk4", struct omap2_gpif_s, fclk[4]),
-        DEFINE_PROP_PTR("fclk5", struct omap2_gpif_s, fclk[5]),
-        DEFINE_PROP_END_OF_LIST()
-    }
+static void omap_gpio_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = omap_gpio_init;
+    dc->reset = omap_gpif_reset;
+    dc->props = omap_gpio_properties;
+}
+
+static TypeInfo omap_gpio_info = {
+    .name          = "omap-gpio",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(struct omap_gpif_s),
+    .class_init    = omap_gpio_class_init,
+};
+
+static Property omap2_gpio_properties[] = {
+    DEFINE_PROP_INT32("mpu_model", struct omap2_gpif_s, mpu_model, 0),
+    DEFINE_PROP_PTR("iclk", struct omap2_gpif_s, iclk),
+    DEFINE_PROP_PTR("fclk0", struct omap2_gpif_s, fclk[0]),
+    DEFINE_PROP_PTR("fclk1", struct omap2_gpif_s, fclk[1]),
+    DEFINE_PROP_PTR("fclk2", struct omap2_gpif_s, fclk[2]),
+    DEFINE_PROP_PTR("fclk3", struct omap2_gpif_s, fclk[3]),
+    DEFINE_PROP_PTR("fclk4", struct omap2_gpif_s, fclk[4]),
+    DEFINE_PROP_PTR("fclk5", struct omap2_gpif_s, fclk[5]),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void omap2_gpio_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = omap2_gpio_init;
+    dc->reset = omap2_gpif_reset;
+    dc->props = omap2_gpio_properties;
+}
+
+static TypeInfo omap2_gpio_info = {
+    .name          = "omap2-gpio",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(struct omap2_gpif_s),
+    .class_init    = omap2_gpio_class_init,
 };
 
 static void omap_gpio_register_device(void)
 {
-    sysbus_register_withprop(&omap_gpio_info);
-    sysbus_register_withprop(&omap2_gpio_info);
+    type_register_static(&omap_gpio_info);
+    type_register_static(&omap2_gpio_info);
 }
 
 device_init(omap_gpio_register_device)
diff --git a/hw/omap_intc.c b/hw/omap_intc.c
index fc53ec71fb..5aa98a8fdb 100644
--- a/hw/omap_intc.c
+++ b/hw/omap_intc.c
@@ -373,16 +373,27 @@ static int omap_intc_init(SysBusDevice *dev)
     return 0;
 }
 
-static SysBusDeviceInfo omap_intc_info = {
-    .init = omap_intc_init,
-    .qdev.name = "omap-intc",
-    .qdev.size = sizeof(struct omap_intr_handler_s),
-    .qdev.reset = omap_inth_reset,
-    .qdev.props = (Property[]) {
-        DEFINE_PROP_UINT32("size", struct omap_intr_handler_s, size, 0x100),
-        DEFINE_PROP_PTR("clk", struct omap_intr_handler_s, iclk),
-        DEFINE_PROP_END_OF_LIST()
-    }
+static Property omap_intc_properties[] = {
+    DEFINE_PROP_UINT32("size", struct omap_intr_handler_s, size, 0x100),
+    DEFINE_PROP_PTR("clk", struct omap_intr_handler_s, iclk),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void omap_intc_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = omap_intc_init;
+    dc->reset = omap_inth_reset;
+    dc->props = omap_intc_properties;
+}
+
+static TypeInfo omap_intc_info = {
+    .name          = "omap-intc",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(struct omap_intr_handler_s),
+    .class_init    = omap_intc_class_init,
 };
 
 static uint64_t omap2_inth_read(void *opaque, target_phys_addr_t addr,
@@ -604,24 +615,35 @@ static int omap2_intc_init(SysBusDevice *dev)
     return 0;
 }
 
-static SysBusDeviceInfo omap2_intc_info = {
-    .init = omap2_intc_init,
-    .qdev.name = "omap2-intc",
-    .qdev.size = sizeof(struct omap_intr_handler_s),
-    .qdev.reset = omap_inth_reset,
-    .qdev.props = (Property[]) {
-        DEFINE_PROP_UINT8("revision", struct omap_intr_handler_s,
-                          revision, 0x21),
-        DEFINE_PROP_PTR("iclk", struct omap_intr_handler_s, iclk),
-        DEFINE_PROP_PTR("fclk", struct omap_intr_handler_s, fclk),
-        DEFINE_PROP_END_OF_LIST()
-    }
+static Property omap2_intc_properties[] = {
+    DEFINE_PROP_UINT8("revision", struct omap_intr_handler_s,
+    revision, 0x21),
+    DEFINE_PROP_PTR("iclk", struct omap_intr_handler_s, iclk),
+    DEFINE_PROP_PTR("fclk", struct omap_intr_handler_s, fclk),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void omap2_intc_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = omap2_intc_init;
+    dc->reset = omap_inth_reset;
+    dc->props = omap2_intc_properties;
+}
+
+static TypeInfo omap2_intc_info = {
+    .name          = "omap2-intc",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(struct omap_intr_handler_s),
+    .class_init    = omap2_intc_class_init,
 };
 
 static void omap_intc_register_device(void)
 {
-    sysbus_register_withprop(&omap_intc_info);
-    sysbus_register_withprop(&omap2_intc_info);
+    type_register_static(&omap_intc_info);
+    type_register_static(&omap2_intc_info);
 }
 
 device_init(omap_intc_register_device)
diff --git a/hw/onenand.c b/hw/onenand.c
index 33c9718629..8744b04db3 100644
--- a/hw/onenand.c
+++ b/hw/onenand.c
@@ -802,24 +802,35 @@ static int onenand_initfn(SysBusDevice *dev)
     return 0;
 }
 
-static SysBusDeviceInfo onenand_info = {
-    .init = onenand_initfn,
-    .qdev.name = "onenand",
-    .qdev.size = sizeof(OneNANDState),
-    .qdev.reset = onenand_system_reset,
-    .qdev.props = (Property[]) {
-        DEFINE_PROP_UINT16("manufacturer_id", OneNANDState, id.man, 0),
-        DEFINE_PROP_UINT16("device_id", OneNANDState, id.dev, 0),
-        DEFINE_PROP_UINT16("version_id", OneNANDState, id.ver, 0),
-        DEFINE_PROP_INT32("shift", OneNANDState, shift, 0),
-        DEFINE_PROP_DRIVE("drive", OneNANDState, bdrv),
-        DEFINE_PROP_END_OF_LIST()
-    }
+static Property onenand_properties[] = {
+    DEFINE_PROP_UINT16("manufacturer_id", OneNANDState, id.man, 0),
+    DEFINE_PROP_UINT16("device_id", OneNANDState, id.dev, 0),
+    DEFINE_PROP_UINT16("version_id", OneNANDState, id.ver, 0),
+    DEFINE_PROP_INT32("shift", OneNANDState, shift, 0),
+    DEFINE_PROP_DRIVE("drive", OneNANDState, bdrv),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void onenand_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = onenand_initfn;
+    dc->reset = onenand_system_reset;
+    dc->props = onenand_properties;
+}
+
+static TypeInfo onenand_info = {
+    .name          = "onenand",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(OneNANDState),
+    .class_init    = onenand_class_init,
 };
 
 static void onenand_register_device(void)
 {
-    sysbus_register_withprop(&onenand_info);
+    type_register_static(&onenand_info);
 }
 
 void *onenand_raw_otp(DeviceState *onenand_device)
diff --git a/hw/opencores_eth.c b/hw/opencores_eth.c
index f7cc1b403b..09f2757df3 100644
--- a/hw/opencores_eth.c
+++ b/hw/opencores_eth.c
@@ -717,7 +717,7 @@ static int sysbus_open_eth_init(SysBusDevice *dev)
     sysbus_init_irq(dev, &s->irq);
 
     s->nic = qemu_new_nic(&net_open_eth_info, &s->conf,
-                          s->dev.qdev.info->name, s->dev.qdev.id, s);
+                          object_get_typename(OBJECT(s)), s->dev.qdev.id, s);
     return 0;
 }
 
@@ -727,21 +727,32 @@ static void qdev_open_eth_reset(DeviceState *dev)
     open_eth_reset(d);
 }
 
-static SysBusDeviceInfo open_eth_info = {
-    .qdev.name  = "open_eth",
-    .qdev.desc  = "Opencores 10/100 Mbit Ethernet",
-    .qdev.size  = sizeof(OpenEthState),
-    .qdev.reset = qdev_open_eth_reset,
-    .init       = sysbus_open_eth_init,
-    .qdev.props = (Property[]) {
-        DEFINE_NIC_PROPERTIES(OpenEthState, conf),
-        DEFINE_PROP_END_OF_LIST(),
-    }
+static Property open_eth_properties[] = {
+    DEFINE_NIC_PROPERTIES(OpenEthState, conf),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void open_eth_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = sysbus_open_eth_init;
+    dc->desc = "Opencores 10/100 Mbit Ethernet";
+    dc->reset = qdev_open_eth_reset;
+    dc->props = open_eth_properties;
+}
+
+static TypeInfo open_eth_info = {
+    .name          = "open_eth",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(OpenEthState),
+    .class_init    = open_eth_class_init,
 };
 
 static void open_eth_register_devices(void)
 {
-    sysbus_register_withprop(&open_eth_info);
+    type_register_static(&open_eth_info);
 }
 
 device_init(open_eth_register_devices)
diff --git a/hw/openpic.c b/hw/openpic.c
index 22fc275b62..280b7a9bbb 100644
--- a/hw/openpic.c
+++ b/hw/openpic.c
@@ -1181,41 +1181,17 @@ static void openpic_irq_raise(openpic_t *opp, int n_CPU, IRQ_src_t *src)
     qemu_irq_raise(opp->dst[n_CPU].irqs[OPENPIC_OUTPUT_INT]);
 }
 
-qemu_irq *openpic_init (PCIBus *bus, MemoryRegion **pmem, int nb_cpus,
+qemu_irq *openpic_init (MemoryRegion **pmem, int nb_cpus,
                         qemu_irq **irqs, qemu_irq irq_out)
 {
     openpic_t *opp;
-    uint8_t *pci_conf;
     int i, m;
 
     /* XXX: for now, only one CPU is supported */
     if (nb_cpus != 1)
         return NULL;
-    if (bus) {
-        opp = (openpic_t *)pci_register_device(bus, "OpenPIC", sizeof(openpic_t),
-                                               -1, NULL, NULL);
-        pci_conf = opp->pci_dev.config;
-        pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_IBM);
-        pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_IBM_OPENPIC2);
-        pci_config_set_class(pci_conf, PCI_CLASS_SYSTEM_OTHER); // FIXME?
-        pci_conf[0x3d] = 0x00; // no interrupt pin
-
-        memory_region_init_io(&opp->mem, &openpic_ops, opp, "openpic", 0x40000);
-#if 0 // Don't implement ISU for now
-        opp_io_memory = cpu_register_io_memory(openpic_src_read,
-                                               openpic_src_write, NULL
-                                               DEVICE_NATIVE_ENDIAN);
-        cpu_register_physical_memory(isu_base, 0x20 * (EXT_IRQ + 2),
-                                     opp_io_memory);
-#endif
-
-        /* Register I/O spaces */
-        pci_register_bar(&opp->pci_dev, 0,
-                         PCI_BASE_ADDRESS_SPACE_MEMORY, &opp->mem);
-    } else {
-        opp = g_malloc0(sizeof(openpic_t));
-        memory_region_init_io(&opp->mem, &openpic_ops, opp, "openpic", 0x40000);
-    }
+    opp = g_malloc0(sizeof(openpic_t));
+    memory_region_init_io(&opp->mem, &openpic_ops, opp, "openpic", 0x40000);
 
     //    isu_base &= 0xFFFC0000;
     opp->nb_cpus = nb_cpus;
diff --git a/hw/openpic.h b/hw/openpic.h
index 715f0847bf..855603026b 100644
--- a/hw/openpic.h
+++ b/hw/openpic.h
@@ -11,7 +11,7 @@ enum {
     OPENPIC_OUTPUT_NB,
 };
 
-qemu_irq *openpic_init (PCIBus *bus, MemoryRegion **pmem, int nb_cpus,
+qemu_irq *openpic_init (MemoryRegion **pmem, int nb_cpus,
                         qemu_irq **irqs, qemu_irq irq_out);
 qemu_irq *mpic_init (MemoryRegion *address_space, target_phys_addr_t base,
                      int nb_cpus, qemu_irq **irqs, qemu_irq irq_out);
diff --git a/hw/parallel.c b/hw/parallel.c
index c4c5dbee5b..484d727927 100644
--- a/hw/parallel.c
+++ b/hw/parallel.c
@@ -583,22 +583,32 @@ bool parallel_mm_init(MemoryRegion *address_space,
     return true;
 }
 
-static ISADeviceInfo parallel_isa_info = {
-    .qdev.name  = "isa-parallel",
-    .qdev.size  = sizeof(ISAParallelState),
-    .init       = parallel_isa_initfn,
-    .qdev.props = (Property[]) {
-        DEFINE_PROP_UINT32("index", ISAParallelState, index,   -1),
-        DEFINE_PROP_HEX32("iobase", ISAParallelState, iobase,  -1),
-        DEFINE_PROP_UINT32("irq",   ISAParallelState, isairq,  7),
-        DEFINE_PROP_CHR("chardev",  ISAParallelState, state.chr),
-        DEFINE_PROP_END_OF_LIST(),
-    },
+static Property parallel_isa_properties[] = {
+    DEFINE_PROP_UINT32("index", ISAParallelState, index,   -1),
+    DEFINE_PROP_HEX32("iobase", ISAParallelState, iobase,  -1),
+    DEFINE_PROP_UINT32("irq",   ISAParallelState, isairq,  7),
+    DEFINE_PROP_CHR("chardev",  ISAParallelState, state.chr),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void parallel_isa_class_initfn(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    ISADeviceClass *ic = ISA_DEVICE_CLASS(klass);
+    ic->init = parallel_isa_initfn;
+    dc->props = parallel_isa_properties;
+}
+
+static TypeInfo parallel_isa_info = {
+    .name          = "isa-parallel",
+    .parent        = TYPE_ISA_DEVICE,
+    .instance_size = sizeof(ISAParallelState),
+    .class_init    = parallel_isa_class_initfn,
 };
 
 static void parallel_register_devices(void)
 {
-    isa_qdev_register(&parallel_isa_info);
+    type_register_static(&parallel_isa_info);
 }
 
 device_init(parallel_register_devices)
diff --git a/hw/pc.c b/hw/pc.c
index 85304cf115..7f3aa65d20 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -36,9 +36,10 @@
 #include "elf.h"
 #include "multiboot.h"
 #include "mc146818rtc.h"
-#include "msix.h"
+#include "msi.h"
 #include "sysbus.h"
 #include "sysemu.h"
+#include "kvm.h"
 #include "blockdev.h"
 #include "ui/qemu-spice.h"
 #include "memory.h"
@@ -496,18 +497,26 @@ static int port92_initfn(ISADevice *dev)
     return 0;
 }
 
-static ISADeviceInfo port92_info = {
-    .qdev.name     = "port92",
-    .qdev.size     = sizeof(Port92State),
-    .qdev.vmsd     = &vmstate_port92_isa,
-    .qdev.no_user  = 1,
-    .qdev.reset    = port92_reset,
-    .init          = port92_initfn,
+static void port92_class_initfn(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    ISADeviceClass *ic = ISA_DEVICE_CLASS(klass);
+    ic->init = port92_initfn;
+    dc->no_user = 1;
+    dc->reset = port92_reset;
+    dc->vmsd = &vmstate_port92_isa;
+}
+
+static TypeInfo port92_info = {
+    .name          = "port92",
+    .parent        = TYPE_ISA_DEVICE,
+    .instance_size = sizeof(Port92State),
+    .class_init    = port92_class_initfn,
 };
 
 static void port92_register(void)
 {
-    isa_qdev_register(&port92_info);
+    type_register_static(&port92_info);
 }
 device_init(port92_register)
 
@@ -609,7 +618,7 @@ static void *bochs_bios_init(void)
     fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size);
     fw_cfg_add_bytes(fw_cfg, FW_CFG_ACPI_TABLES, (uint8_t *)acpi_tables,
                      acpi_tables_len);
-    fw_cfg_add_bytes(fw_cfg, FW_CFG_IRQ0_OVERRIDE, &irq0override, 1);
+    fw_cfg_add_i32(fw_cfg, FW_CFG_IRQ0_OVERRIDE, kvm_allows_irq0_override());
 
     smbios_table = smbios_get_table(&smbios_len);
     if (smbios_table)
@@ -878,25 +887,30 @@ DeviceState *cpu_get_current_apic(void)
 static DeviceState *apic_init(void *env, uint8_t apic_id)
 {
     DeviceState *dev;
-    SysBusDevice *d;
     static int apic_mapped;
 
-    dev = qdev_create(NULL, "apic");
+    if (kvm_enabled() && kvm_irqchip_in_kernel()) {
+        dev = qdev_create(NULL, "kvm-apic");
+    } else {
+        dev = qdev_create(NULL, "apic");
+    }
     qdev_prop_set_uint8(dev, "id", apic_id);
     qdev_prop_set_ptr(dev, "cpu_env", env);
     qdev_init_nofail(dev);
-    d = sysbus_from_qdev(dev);
 
     /* XXX: mapping more APICs at the same memory location */
     if (apic_mapped == 0) {
         /* NOTE: the APIC is directly connected to the CPU - it is not
            on the global memory bus. */
         /* XXX: what if the base changes? */
-        sysbus_mmio_map(d, 0, MSI_ADDR_BASE);
+        sysbus_mmio_map(sysbus_from_qdev(dev), 0, MSI_ADDR_BASE);
         apic_mapped = 1;
     }
 
-    msix_supported = 1;
+    /* KVM does not support MSI yet. */
+    if (!kvm_enabled() || !kvm_irqchip_in_kernel()) {
+        msi_supported = true;
+    }
 
     return dev;
 }
@@ -1080,16 +1094,11 @@ DeviceState *pc_vga_init(ISABus *isa_bus, PCIBus *pci_bus)
         if (pci_bus) {
             dev = pci_cirrus_vga_init(pci_bus);
         } else {
-            dev = isa_cirrus_vga_init(get_system_memory());
+            dev = &isa_create_simple(isa_bus, "isa-cirrus-vga")->qdev;
         }
     } else if (vmsvga_enabled) {
         if (pci_bus) {
             dev = pci_vmsvga_init(pci_bus);
-            if (!dev) {
-                fprintf(stderr, "Warning: vmware_vga not available,"
-                        " using standard VGA instead\n");
-                dev = pci_vga_init(pci_bus);
-            }
         } else {
             fprintf(stderr, "%s: vmware_vga: no PCI bus\n", __FUNCTION__);
         }
diff --git a/hw/pc.h b/hw/pc.h
index 13e41f101e..c666ec9827 100644
--- a/hw/pc.h
+++ b/hw/pc.h
@@ -62,11 +62,11 @@ bool parallel_mm_init(MemoryRegion *address_space,
 
 /* i8259.c */
 
-typedef struct PicState PicState;
-extern PicState *isa_pic;
+extern DeviceState *isa_pic;
 qemu_irq *i8259_init(ISABus *bus, qemu_irq parent_irq);
-int pic_read_irq(PicState *s);
-int pic_get_output(PicState *s);
+qemu_irq *kvm_i8259_init(ISABus *bus);
+int pic_read_irq(DeviceState *d);
+int pic_get_output(DeviceState *d);
 void pic_info(Monitor *mon);
 void irq_info(Monitor *mon);
 
@@ -226,7 +226,6 @@ int isa_vga_mm_init(target_phys_addr_t vram_base,
 
 /* cirrus_vga.c */
 DeviceState *pci_cirrus_vga_init(PCIBus *bus);
-DeviceState *isa_cirrus_vga_init(MemoryRegion *address_space);
 
 /* ne2000.c */
 static inline bool isa_ne2000_init(ISABus *bus, int base, int irq, NICInfo *nd)
diff --git a/hw/pc_piix.c b/hw/pc_piix.c
index 3aea3cc9de..c06f1b544e 100644
--- a/hw/pc_piix.c
+++ b/hw/pc_piix.c
@@ -34,7 +34,7 @@
 #include "boards.h"
 #include "ide.h"
 #include "kvm.h"
-#include "kvmclock.h"
+#include "kvm/clock.h"
 #include "sysemu.h"
 #include "sysbus.h"
 #include "arch_init.h"
@@ -53,13 +53,62 @@ static const int ide_iobase[MAX_IDE_BUS] = { 0x1f0, 0x170 };
 static const int ide_iobase2[MAX_IDE_BUS] = { 0x3f6, 0x376 };
 static const int ide_irq[MAX_IDE_BUS] = { 14, 15 };
 
+static void kvm_piix3_setup_irq_routing(bool pci_enabled)
+{
+#ifdef CONFIG_KVM
+    KVMState *s = kvm_state;
+    int ret, i;
+
+    if (kvm_check_extension(s, KVM_CAP_IRQ_ROUTING)) {
+        for (i = 0; i < 8; ++i) {
+            if (i == 2) {
+                continue;
+            }
+            kvm_irqchip_add_route(s, i, KVM_IRQCHIP_PIC_MASTER, i);
+        }
+        for (i = 8; i < 16; ++i) {
+            kvm_irqchip_add_route(s, i, KVM_IRQCHIP_PIC_SLAVE, i - 8);
+        }
+        if (pci_enabled) {
+            for (i = 0; i < 24; ++i) {
+                if (i == 0) {
+                    kvm_irqchip_add_route(s, i, KVM_IRQCHIP_IOAPIC, 2);
+                } else if (i != 2) {
+                    kvm_irqchip_add_route(s, i, KVM_IRQCHIP_IOAPIC, i);
+                }
+            }
+        }
+        ret = kvm_irqchip_commit_routes(s);
+        if (ret < 0) {
+            hw_error("KVM IRQ routing setup failed");
+        }
+    }
+#endif /* CONFIG_KVM */
+}
+
+static void kvm_piix3_gsi_handler(void *opaque, int n, int level)
+{
+    GSIState *s = opaque;
+
+    if (n < ISA_NUM_IRQS) {
+        /* Kernel will forward to both PIC and IOAPIC */
+        qemu_set_irq(s->i8259_irq[n], level);
+    } else {
+        qemu_set_irq(s->ioapic_irq[n], level);
+    }
+}
+
 static void ioapic_init(GSIState *gsi_state)
 {
     DeviceState *dev;
     SysBusDevice *d;
     unsigned int i;
 
-    dev = qdev_create(NULL, "ioapic");
+    if (kvm_enabled() && kvm_irqchip_in_kernel()) {
+        dev = qdev_create(NULL, "kvm-ioapic");
+    } else {
+        dev = qdev_create(NULL, "ioapic");
+    }
     qdev_init_nofail(dev);
     d = sysbus_from_qdev(dev);
     sysbus_mmio_map(d, 0, 0xfec00000);
@@ -134,7 +183,13 @@ static void pc_init1(MemoryRegion *system_memory,
     }
 
     gsi_state = g_malloc0(sizeof(*gsi_state));
-    gsi = qemu_allocate_irqs(gsi_handler, gsi_state, GSI_NUM_PINS);
+    if (kvm_enabled() && kvm_irqchip_in_kernel()) {
+        kvm_piix3_setup_irq_routing(pci_enabled);
+        gsi = qemu_allocate_irqs(kvm_piix3_gsi_handler, gsi_state,
+                                 GSI_NUM_PINS);
+    } else {
+        gsi = qemu_allocate_irqs(gsi_handler, gsi_state, GSI_NUM_PINS);
+    }
 
     if (pci_enabled) {
         pci_bus = i440fx_init(&i440fx_state, &piix3_devfn, &isa_bus, gsi,
@@ -154,11 +209,13 @@ static void pc_init1(MemoryRegion *system_memory,
     }
     isa_bus_irqs(isa_bus, gsi);
 
-    if (!xen_enabled()) {
+    if (kvm_enabled() && kvm_irqchip_in_kernel()) {
+        i8259 = kvm_i8259_init(isa_bus);
+    } else if (xen_enabled()) {
+        i8259 = xen_interrupt_controller_init();
+    } else {
         cpu_irq = pc_allocate_cpu_irq();
         i8259 = i8259_init(isa_bus, cpu_irq[0]);
-    } else {
-        i8259 = xen_interrupt_controller_init();
     }
 
     for (i = 0; i < ISA_NUM_IRQS; i++) {
@@ -172,7 +229,7 @@ static void pc_init1(MemoryRegion *system_memory,
 
     dev = pc_vga_init(isa_bus, pci_enabled ? pci_bus : NULL);
     if (dev) {
-        qdev_property_add_child(qdev_get_root(), "vga", dev, NULL);
+        object_property_add_child(object_get_root(), "vga", OBJECT(dev), NULL);
     }
 
     if (xen_enabled()) {
@@ -210,8 +267,8 @@ static void pc_init1(MemoryRegion *system_memory,
          * For now, let's "fix" this by making judicious use of paths.  This
          * is not generally the right way to do this.
          */
-        qdev_property_add_child(qdev_resolve_path("/i440fx/piix3", NULL),
-                                "rtc", (DeviceState *)rtc_state, NULL);
+        object_property_add_child(object_resolve_path("/i440fx/piix3", NULL),
+                                  "rtc", (Object *)rtc_state, NULL);
     } else {
         for(i = 0; i < MAX_IDE_BUS; i++) {
             ISADevice *dev;
diff --git a/hw/pci.c b/hw/pci.c
index c3082bc7c6..5f4f80ed10 100644
--- a/hw/pci.c
+++ b/hw/pci.c
@@ -89,7 +89,6 @@ static const VMStateDescription vmstate_pcibus = {
         VMSTATE_END_OF_LIST()
     }
 };
-
 static int pci_bar(PCIDevice *d, int reg)
 {
     uint8_t type;
@@ -159,11 +158,8 @@ void pci_device_deassert_intx(PCIDevice *dev)
 void pci_device_reset(PCIDevice *dev)
 {
     int r;
-    /* TODO: call the below unconditionally once all pci devices
-     * are qdevified */
-    if (dev->qdev.info) {
-        qdev_reset_all(&dev->qdev);
-    }
+
+    qdev_reset_all(&dev->qdev);
 
     dev->irq_state = 0;
     pci_update_irq_status(dev);
@@ -733,11 +729,11 @@ static void pci_config_free(PCIDevice *pci_dev)
 
 /* -1 for devfn means auto assign */
 static PCIDevice *do_pci_register_device(PCIDevice *pci_dev, PCIBus *bus,
-                                         const char *name, int devfn,
-                                         const PCIDeviceInfo *info)
+                                         const char *name, int devfn)
 {
-    PCIConfigReadFunc *config_read = info->config_read;
-    PCIConfigWriteFunc *config_write = info->config_write;
+    PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(pci_dev);
+    PCIConfigReadFunc *config_read = pc->config_read;
+    PCIConfigWriteFunc *config_write = pc->config_write;
 
     if (devfn < 0) {
         for(devfn = bus->devfn_min ; devfn < ARRAY_SIZE(bus->devices);
@@ -759,29 +755,29 @@ static PCIDevice *do_pci_register_device(PCIDevice *pci_dev, PCIBus *bus,
     pci_dev->irq_state = 0;
     pci_config_alloc(pci_dev);
 
-    pci_config_set_vendor_id(pci_dev->config, info->vendor_id);
-    pci_config_set_device_id(pci_dev->config, info->device_id);
-    pci_config_set_revision(pci_dev->config, info->revision);
-    pci_config_set_class(pci_dev->config, info->class_id);
+    pci_config_set_vendor_id(pci_dev->config, pc->vendor_id);
+    pci_config_set_device_id(pci_dev->config, pc->device_id);
+    pci_config_set_revision(pci_dev->config, pc->revision);
+    pci_config_set_class(pci_dev->config, pc->class_id);
 
-    if (!info->is_bridge) {
-        if (info->subsystem_vendor_id || info->subsystem_id) {
+    if (!pc->is_bridge) {
+        if (pc->subsystem_vendor_id || pc->subsystem_id) {
             pci_set_word(pci_dev->config + PCI_SUBSYSTEM_VENDOR_ID,
-                         info->subsystem_vendor_id);
+                         pc->subsystem_vendor_id);
             pci_set_word(pci_dev->config + PCI_SUBSYSTEM_ID,
-                         info->subsystem_id);
+                         pc->subsystem_id);
         } else {
             pci_set_default_subsystem_id(pci_dev);
         }
     } else {
         /* subsystem_vendor_id/subsystem_id are only for header type 0 */
-        assert(!info->subsystem_vendor_id);
-        assert(!info->subsystem_id);
+        assert(!pc->subsystem_vendor_id);
+        assert(!pc->subsystem_id);
     }
     pci_init_cmask(pci_dev);
     pci_init_wmask(pci_dev);
     pci_init_w1cmask(pci_dev);
-    if (info->is_bridge) {
+    if (pc->is_bridge) {
         pci_init_wmask_bridge(pci_dev);
     }
     if (pci_init_multifunction(bus, pci_dev)) {
@@ -808,26 +804,6 @@ static void do_pci_unregister_device(PCIDevice *pci_dev)
     pci_config_free(pci_dev);
 }
 
-/* TODO: obsolete. eliminate this once all pci devices are qdevifed. */
-PCIDevice *pci_register_device(PCIBus *bus, const char *name,
-                               int instance_size, int devfn,
-                               PCIConfigReadFunc *config_read,
-                               PCIConfigWriteFunc *config_write)
-{
-    PCIDevice *pci_dev;
-    PCIDeviceInfo info = {
-        .config_read = config_read,
-        .config_write = config_write,
-    };
-
-    pci_dev = g_malloc0(instance_size);
-    pci_dev = do_pci_register_device(pci_dev, bus, name, devfn, &info);
-    if (pci_dev == NULL) {
-        hw_error("PCI: can't register device\n");
-    }
-    return pci_dev;
-}
-
 static void pci_unregister_io_regions(PCIDevice *pci_dev)
 {
     PCIIORegion *r;
@@ -843,12 +819,12 @@ static void pci_unregister_io_regions(PCIDevice *pci_dev)
 
 static int pci_unregister_device(DeviceState *dev)
 {
-    PCIDevice *pci_dev = DO_UPCAST(PCIDevice, qdev, dev);
-    PCIDeviceInfo *info = DO_UPCAST(PCIDeviceInfo, qdev, dev->info);
+    PCIDevice *pci_dev = PCI_DEVICE(dev);
+    PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(pci_dev);
     int ret = 0;
 
-    if (info->exit)
-        ret = info->exit(pci_dev);
+    if (pc->exit)
+        ret = pc->exit(pci_dev);
     if (ret)
         return ret;
 
@@ -1477,31 +1453,32 @@ PCIDevice *pci_find_device(PCIBus *bus, int bus_num, uint8_t devfn)
     return bus->devices[devfn];
 }
 
-static int pci_qdev_init(DeviceState *qdev, DeviceInfo *base)
+static int pci_qdev_init(DeviceState *qdev)
 {
     PCIDevice *pci_dev = (PCIDevice *)qdev;
-    PCIDeviceInfo *info = container_of(base, PCIDeviceInfo, qdev);
+    PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(pci_dev);
     PCIBus *bus;
     int rc;
     bool is_default_rom;
 
     /* initialize cap_present for pci_is_express() and pci_config_size() */
-    if (info->is_express) {
+    if (pc->is_express) {
         pci_dev->cap_present |= QEMU_PCI_CAP_EXPRESS;
     }
 
     bus = FROM_QBUS(PCIBus, qdev_get_parent_bus(qdev));
-    pci_dev = do_pci_register_device(pci_dev, bus, base->name,
-                                     pci_dev->devfn, info);
+    pci_dev = do_pci_register_device(pci_dev, bus,
+                                     object_get_typename(OBJECT(qdev)),
+                                     pci_dev->devfn);
     if (pci_dev == NULL)
         return -1;
-    if (qdev->hotplugged && info->no_hotplug) {
-        qerror_report(QERR_DEVICE_NO_HOTPLUG, info->qdev.name);
+    if (qdev->hotplugged && pc->no_hotplug) {
+        qerror_report(QERR_DEVICE_NO_HOTPLUG, object_get_typename(OBJECT(pci_dev)));
         do_pci_unregister_device(pci_dev);
         return -1;
     }
-    if (info->init) {
-        rc = info->init(pci_dev);
+    if (pc->init) {
+        rc = pc->init(pci_dev);
         if (rc != 0) {
             do_pci_unregister_device(pci_dev);
             return rc;
@@ -1510,8 +1487,8 @@ static int pci_qdev_init(DeviceState *qdev, DeviceInfo *base)
 
     /* rom loading */
     is_default_rom = false;
-    if (pci_dev->romfile == NULL && info->romfile != NULL) {
-        pci_dev->romfile = g_strdup(info->romfile);
+    if (pci_dev->romfile == NULL && pc->romfile != NULL) {
+        pci_dev->romfile = g_strdup(pc->romfile);
         is_default_rom = true;
     }
     pci_add_option_rom(pci_dev, is_default_rom);
@@ -1533,34 +1510,18 @@ static int pci_qdev_init(DeviceState *qdev, DeviceInfo *base)
 
 static int pci_unplug_device(DeviceState *qdev)
 {
-    PCIDevice *dev = DO_UPCAST(PCIDevice, qdev, qdev);
-    PCIDeviceInfo *info = container_of(qdev->info, PCIDeviceInfo, qdev);
+    PCIDevice *dev = PCI_DEVICE(qdev);
+    PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(dev);
 
-    if (info->no_hotplug) {
-        qerror_report(QERR_DEVICE_NO_HOTPLUG, info->qdev.name);
+    if (pc->no_hotplug) {
+        qerror_report(QERR_DEVICE_NO_HOTPLUG, object_get_typename(OBJECT(dev)));
         return -1;
     }
+    object_unparent(OBJECT(dev));
     return dev->bus->hotplug(dev->bus->hotplug_qdev, dev,
                              PCI_HOTPLUG_DISABLED);
 }
 
-void pci_qdev_register(PCIDeviceInfo *info)
-{
-    info->qdev.init = pci_qdev_init;
-    info->qdev.unplug = pci_unplug_device;
-    info->qdev.exit = pci_unregister_device;
-    info->qdev.bus_info = &pci_bus_info;
-    qdev_register(&info->qdev);
-}
-
-void pci_qdev_register_many(PCIDeviceInfo *info)
-{
-    while (info->qdev.name) {
-        pci_qdev_register(info);
-        info++;
-    }
-}
-
 PCIDevice *pci_create_multifunction(PCIBus *bus, int devfn, bool multifunction,
                                     const char *name)
 {
@@ -1569,22 +1530,7 @@ PCIDevice *pci_create_multifunction(PCIBus *bus, int devfn, bool multifunction,
     dev = qdev_create(&bus->qbus, name);
     qdev_prop_set_uint32(dev, "addr", devfn);
     qdev_prop_set_bit(dev, "multifunction", multifunction);
-    return DO_UPCAST(PCIDevice, qdev, dev);
-}
-
-PCIDevice *pci_try_create_multifunction(PCIBus *bus, int devfn,
-                                        bool multifunction,
-                                        const char *name)
-{
-    DeviceState *dev;
-
-    dev = qdev_try_create(&bus->qbus, name);
-    if (!dev) {
-        return NULL;
-    }
-    qdev_prop_set_uint32(dev, "addr", devfn);
-    qdev_prop_set_bit(dev, "multifunction", multifunction);
-    return DO_UPCAST(PCIDevice, qdev, dev);
+    return PCI_DEVICE(dev);
 }
 
 PCIDevice *pci_create_simple_multifunction(PCIBus *bus, int devfn,
@@ -1606,11 +1552,6 @@ PCIDevice *pci_create_simple(PCIBus *bus, int devfn, const char *name)
     return pci_create_simple_multifunction(bus, devfn, false, name);
 }
 
-PCIDevice *pci_try_create(PCIBus *bus, int devfn, const char *name)
-{
-    return pci_try_create_multifunction(bus, devfn, false, name);
-}
-
 static int pci_find_space(PCIDevice *pdev, uint8_t size)
 {
     int config_size = pci_config_size(pdev);
@@ -1724,6 +1665,7 @@ static int pci_add_option_rom(PCIDevice *pdev, bool is_default_rom)
     char *path;
     void *ptr;
     char name[32];
+    const VMStateDescription *vmsd;
 
     if (!pdev->romfile)
         return 0;
@@ -1760,10 +1702,13 @@ static int pci_add_option_rom(PCIDevice *pdev, bool is_default_rom)
         size = 1 << qemu_fls(size);
     }
 
-    if (pdev->qdev.info->vmsd)
-        snprintf(name, sizeof(name), "%s.rom", pdev->qdev.info->vmsd->name);
-    else
-        snprintf(name, sizeof(name), "%s.rom", pdev->qdev.info->name);
+    vmsd = qdev_get_vmsd(DEVICE(pdev));
+
+    if (vmsd) {
+        snprintf(name, sizeof(name), "%s.rom", vmsd->name);
+    } else {
+        snprintf(name, sizeof(name), "%s.rom", object_get_typename(OBJECT(pdev)));
+    }
     pdev->has_rom = true;
     memory_region_init_ram(&pdev->rom, name, size);
     vmstate_register_ram(&pdev->rom, &pdev->qdev);
@@ -2004,9 +1949,8 @@ static int pci_qdev_find_recursive(PCIBus *bus,
     }
 
     /* roughly check if given qdev is pci device */
-    if (qdev->info->init == &pci_qdev_init &&
-        qdev->parent_bus->info == &pci_bus_info) {
-        *pdev = DO_UPCAST(PCIDevice, qdev, qdev);
+    if (object_dynamic_cast(OBJECT(qdev), TYPE_PCI_DEVICE)) {
+        *pdev = PCI_DEVICE(qdev);
         return 0;
     }
     return -EINVAL;
@@ -2040,3 +1984,28 @@ MemoryRegion *pci_address_space_io(PCIDevice *dev)
 {
     return dev->bus->address_space_io;
 }
+
+static void pci_device_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *k = DEVICE_CLASS(klass);
+    k->init = pci_qdev_init;
+    k->unplug = pci_unplug_device;
+    k->exit = pci_unregister_device;
+    k->bus_info = &pci_bus_info;
+}
+
+static TypeInfo pci_device_type_info = {
+    .name = TYPE_PCI_DEVICE,
+    .parent = TYPE_DEVICE,
+    .instance_size = sizeof(PCIDevice),
+    .abstract = true,
+    .class_size = sizeof(PCIDeviceClass),
+    .class_init = pci_device_class_init,
+};
+
+static void pci_register_devices(void)
+{
+    type_register_static(&pci_device_type_info);
+}
+
+device_init(pci_register_devices);
diff --git a/hw/pci.h b/hw/pci.h
index 0d2cff6fec..33b0b184ea 100644
--- a/hw/pci.h
+++ b/hw/pci.h
@@ -127,6 +127,46 @@ enum {
     QEMU_PCI_CAP_SERR = (1 << QEMU_PCI_CAP_SERR_BITNR),
 };
 
+#define TYPE_PCI_DEVICE "pci-device"
+#define PCI_DEVICE(obj) \
+     OBJECT_CHECK(PCIDevice, (obj), TYPE_PCI_DEVICE)
+#define PCI_DEVICE_CLASS(klass) \
+     OBJECT_CLASS_CHECK(PCIDeviceClass, (klass), TYPE_PCI_DEVICE)
+#define PCI_DEVICE_GET_CLASS(obj) \
+     OBJECT_GET_CLASS(PCIDeviceClass, (obj), TYPE_PCI_DEVICE)
+
+typedef struct PCIDeviceClass {
+    DeviceClass parent_class;
+
+    int (*init)(PCIDevice *dev);
+    PCIUnregisterFunc *exit;
+    PCIConfigReadFunc *config_read;
+    PCIConfigWriteFunc *config_write;
+
+    uint16_t vendor_id;
+    uint16_t device_id;
+    uint8_t revision;
+    uint16_t class_id;
+    uint16_t subsystem_vendor_id;       /* only for header type = 0 */
+    uint16_t subsystem_id;              /* only for header type = 0 */
+
+    /*
+     * pci-to-pci bridge or normal device.
+     * This doesn't mean pci host switch.
+     * When card bus bridge is supported, this would be enhanced.
+     */
+    int is_bridge;
+
+    /* pcie stuff */
+    int is_express;   /* is this device pci express? */
+
+    /* device isn't hot-pluggable */
+    int no_hotplug;
+
+    /* rom bar */
+    const char *romfile;
+} PCIDeviceClass;
+
 struct PCIDevice {
     DeviceState qdev;
     /* PCI config space */
@@ -196,11 +236,6 @@ struct PCIDevice {
     uint32_t rom_bar;
 };
 
-PCIDevice *pci_register_device(PCIBus *bus, const char *name,
-                               int instance_size, int devfn,
-                               PCIConfigReadFunc *config_read,
-                               PCIConfigWriteFunc *config_write);
-
 void pci_register_bar(PCIDevice *pci_dev, int region_num,
                       uint8_t attr, MemoryRegion *memory);
 pcibus_t pci_get_bar_addr(PCIDevice *pci_dev, int region_num);
@@ -429,52 +464,13 @@ pci_quad_test_and_set_mask(uint8_t *config, uint64_t mask)
     return val & mask;
 }
 
-typedef int (*pci_qdev_initfn)(PCIDevice *dev);
-typedef struct {
-    DeviceInfo qdev;
-    pci_qdev_initfn init;
-    PCIUnregisterFunc *exit;
-    PCIConfigReadFunc *config_read;
-    PCIConfigWriteFunc *config_write;
-
-    uint16_t vendor_id;
-    uint16_t device_id;
-    uint8_t revision;
-    uint16_t class_id;
-    uint16_t subsystem_vendor_id;       /* only for header type = 0 */
-    uint16_t subsystem_id;              /* only for header type = 0 */
-
-    /*
-     * pci-to-pci bridge or normal device.
-     * This doesn't mean pci host switch.
-     * When card bus bridge is supported, this would be enhanced.
-     */
-    int is_bridge;
-
-    /* pcie stuff */
-    int is_express;   /* is this device pci express? */
-
-    /* device isn't hot-pluggable */
-    int no_hotplug;
-
-    /* rom bar */
-    const char *romfile;
-} PCIDeviceInfo;
-
-void pci_qdev_register(PCIDeviceInfo *info);
-void pci_qdev_register_many(PCIDeviceInfo *info);
-
 PCIDevice *pci_create_multifunction(PCIBus *bus, int devfn, bool multifunction,
                                     const char *name);
 PCIDevice *pci_create_simple_multifunction(PCIBus *bus, int devfn,
                                            bool multifunction,
                                            const char *name);
-PCIDevice *pci_try_create_multifunction(PCIBus *bus, int devfn,
-                                        bool multifunction,
-                                        const char *name);
 PCIDevice *pci_create(PCIBus *bus, int devfn, const char *name);
 PCIDevice *pci_create_simple(PCIBus *bus, int devfn, const char *name);
-PCIDevice *pci_try_create(PCIBus *bus, int devfn, const char *name);
 
 static inline int pci_is_express(const PCIDevice *d)
 {
diff --git a/hw/pci_bridge.c b/hw/pci_bridge.c
index 650d1650c5..1ed43394de 100644
--- a/hw/pci_bridge.c
+++ b/hw/pci_bridge.c
@@ -294,7 +294,7 @@ void pci_bridge_reset_reg(PCIDevice *dev)
 /* default reset function for PCI-to-PCI bridge */
 void pci_bridge_reset(DeviceState *qdev)
 {
-    PCIDevice *dev = DO_UPCAST(PCIDevice, qdev, qdev);
+    PCIDevice *dev = PCI_DEVICE(qdev);
     pci_bridge_reset_reg(dev);
 }
 
diff --git a/hw/pci_ids.h b/hw/pci_ids.h
index 83f38934ec..e8235a7d05 100644
--- a/hw/pci_ids.h
+++ b/hw/pci_ids.h
@@ -98,6 +98,7 @@
 #define PCI_DEVICE_ID_MPC8533E           0x0030
 
 #define PCI_VENDOR_ID_INTEL              0x8086
+#define PCI_DEVICE_ID_INTEL_82378        0x0484
 #define PCI_DEVICE_ID_INTEL_82441        0x1237
 #define PCI_DEVICE_ID_INTEL_82801AA_5    0x2415
 #define PCI_DEVICE_ID_INTEL_82801D       0x24CD
@@ -120,3 +121,6 @@
 
 #define PCI_VENDOR_ID_XEN               0x5853
 #define PCI_DEVICE_ID_XEN_PLATFORM      0x0001
+
+#define PCI_VENDOR_ID_NEC                0x1033
+#define PCI_DEVICE_ID_NEC_UPD720200      0x0194
diff --git a/hw/pcie.c b/hw/pcie.c
index 5c9eb2f0ac..7c92f193e7 100644
--- a/hw/pcie.c
+++ b/hw/pcie.c
@@ -203,7 +203,7 @@ static void pcie_cap_slot_event(PCIDevice *dev, PCIExpressHotPlugEvent event)
 static int pcie_cap_slot_hotplug(DeviceState *qdev,
                                  PCIDevice *pci_dev, PCIHotplugState state)
 {
-    PCIDevice *d = DO_UPCAST(PCIDevice, qdev, qdev);
+    PCIDevice *d = PCI_DEVICE(qdev);
     uint8_t *exp_cap = d->config + d->exp.exp_cap;
     uint16_t sltsta = pci_get_word(exp_cap + PCI_EXP_SLTSTA);
 
diff --git a/hw/pckbd.c b/hw/pckbd.c
index 06b40c540c..b4c53bed6c 100644
--- a/hw/pckbd.c
+++ b/hw/pckbd.c
@@ -497,16 +497,24 @@ static int i8042_initfn(ISADevice *dev)
     return 0;
 }
 
-static ISADeviceInfo i8042_info = {
-    .qdev.name     = "i8042",
-    .qdev.size     = sizeof(ISAKBDState),
-    .qdev.vmsd     = &vmstate_kbd_isa,
-    .qdev.no_user  = 1,
-    .init          = i8042_initfn,
+static void i8042_class_initfn(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    ISADeviceClass *ic = ISA_DEVICE_CLASS(klass);
+    ic->init = i8042_initfn;
+    dc->no_user = 1;
+    dc->vmsd = &vmstate_kbd_isa;
+}
+
+static TypeInfo i8042_info = {
+    .name          = "i8042",
+    .parent        = TYPE_ISA_DEVICE,
+    .instance_size = sizeof(ISAKBDState),
+    .class_init    = i8042_class_initfn,
 };
 
 static void i8042_register(void)
 {
-    isa_qdev_register(&i8042_info);
+    type_register_static(&i8042_info);
 }
 device_init(i8042_register)
diff --git a/hw/pcnet-pci.c b/hw/pcnet-pci.c
index 4e164da3ac..439f32caae 100644
--- a/hw/pcnet-pci.c
+++ b/hw/pcnet-pci.c
@@ -348,26 +348,37 @@ static void pci_reset(DeviceState *dev)
     pcnet_h_reset(&d->state);
 }
 
-static PCIDeviceInfo pcnet_info = {
-    .qdev.name  = "pcnet",
-    .qdev.size  = sizeof(PCIPCNetState),
-    .qdev.reset = pci_reset,
-    .qdev.vmsd  = &vmstate_pci_pcnet,
-    .init       = pci_pcnet_init,
-    .exit       = pci_pcnet_uninit,
-    .vendor_id  = PCI_VENDOR_ID_AMD,
-    .device_id  = PCI_DEVICE_ID_AMD_LANCE,
-    .revision   = 0x10,
-    .class_id   = PCI_CLASS_NETWORK_ETHERNET,
-    .qdev.props = (Property[]) {
-        DEFINE_NIC_PROPERTIES(PCIPCNetState, state.conf),
-        DEFINE_PROP_END_OF_LIST(),
-    }
+static Property pcnet_properties[] = {
+    DEFINE_NIC_PROPERTIES(PCIPCNetState, state.conf),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void pcnet_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->init = pci_pcnet_init;
+    k->exit = pci_pcnet_uninit;
+    k->vendor_id = PCI_VENDOR_ID_AMD;
+    k->device_id = PCI_DEVICE_ID_AMD_LANCE;
+    k->revision = 0x10;
+    k->class_id = PCI_CLASS_NETWORK_ETHERNET;
+    dc->reset = pci_reset;
+    dc->vmsd = &vmstate_pci_pcnet;
+    dc->props = pcnet_properties;
+}
+
+static TypeInfo pcnet_info = {
+    .name          = "pcnet",
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(PCIPCNetState),
+    .class_init    = pcnet_class_init,
 };
 
 static void pci_pcnet_register_devices(void)
 {
-    pci_qdev_register(&pcnet_info);
+    type_register_static(&pcnet_info);
 }
 
 device_init(pci_pcnet_register_devices)
diff --git a/hw/pcnet.c b/hw/pcnet.c
index 306dc6ed7e..c53f06ef3b 100644
--- a/hw/pcnet.c
+++ b/hw/pcnet.c
@@ -688,7 +688,6 @@ static void pcnet_s_reset(PCNetState *s)
     printf("pcnet_s_reset\n");
 #endif
 
-    s->lnkst = 0x40;
     s->rdra = 0;
     s->tdra = 0;
     s->rap = 0;
@@ -1719,7 +1718,7 @@ int pcnet_common_init(DeviceState *dev, PCNetState *s, NetClientInfo *info)
     s->poll_timer = qemu_new_timer_ns(vm_clock, pcnet_poll_timer, s);
 
     qemu_macaddr_default_if_unset(&s->conf.macaddr);
-    s->nic = qemu_new_nic(info, &s->conf, dev->info->name, dev->id, s);
+    s->nic = qemu_new_nic(info, &s->conf, object_get_typename(OBJECT(dev)), dev->id, s);
     qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a);
 
     add_boot_device_path(s->conf.bootindex, dev, "/ethernet-phy@0");
@@ -1751,5 +1750,7 @@ int pcnet_common_init(DeviceState *dev, PCNetState *s, NetClientInfo *info)
     }
     *(uint16_t *)&s->prom[12] = cpu_to_le16(checksum);
 
+    s->lnkst = 0x40; /* initial link state: up */
+
     return 0;
 }
diff --git a/hw/piix4.c b/hw/piix4.c
index 51af459073..4e7a2370cd 100644
--- a/hw/piix4.c
+++ b/hw/piix4.c
@@ -102,25 +102,30 @@ int piix4_init(PCIBus *bus, ISABus **isa_bus, int devfn)
     return d->devfn;
 }
 
-static PCIDeviceInfo piix4_info[] = {
-    {
-        .qdev.name    = "PIIX4",
-        .qdev.desc    = "ISA bridge",
-        .qdev.size    = sizeof(PIIX4State),
-        .qdev.vmsd    = &vmstate_piix4,
-        .qdev.no_user = 1,
-        .no_hotplug   = 1,
-        .init         = piix4_initfn,
-        .vendor_id    = PCI_VENDOR_ID_INTEL,
-        .device_id    = PCI_DEVICE_ID_INTEL_82371AB_0, // 82371AB/EB/MB PIIX4 PCI-to-ISA bridge
-        .class_id     = PCI_CLASS_BRIDGE_ISA,
-    },{
-        /* end of list */
-    }
+static void piix4_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->no_hotplug = 1;
+    k->init = piix4_initfn;
+    k->vendor_id = PCI_VENDOR_ID_INTEL;
+    k->device_id = PCI_DEVICE_ID_INTEL_82371AB_0;
+    k->class_id = PCI_CLASS_BRIDGE_ISA;
+    dc->desc = "ISA bridge";
+    dc->no_user = 1;
+    dc->vmsd = &vmstate_piix4;
+}
+
+static TypeInfo piix4_info = {
+    .name          = "PIIX4",
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(PIIX4State),
+    .class_init    = piix4_class_init,
 };
 
 static void piix4_register(void)
 {
-    pci_qdev_register_many(piix4_info);
+    type_register_static(&piix4_info);
 }
 device_init(piix4_register);
diff --git a/hw/piix_pci.c b/hw/piix_pci.c
index 3652522e58..190642733f 100644
--- a/hw/piix_pci.c
+++ b/hw/piix_pci.c
@@ -277,7 +277,7 @@ static PCIBus *i440fx_common_init(const char *device_name,
                     address_space_io, 0);
     s->bus = b;
     qdev_init_nofail(dev);
-    qdev_property_add_child(qdev_get_root(), "i440fx", dev, NULL);
+    object_property_add_child(object_get_root(), "i440fx", OBJECT(dev), NULL);
 
     d = pci_create_simple(b, 0, device_name);
     *pi440fx_state = DO_UPCAST(PCII440FXState, dev, d);
@@ -316,7 +316,7 @@ static PCIBus *i440fx_common_init(const char *device_name,
         pci_bus_irqs(b, piix3_set_irq, pci_slot_get_pirq, piix3,
                 PIIX_NUM_PIRQS);
     }
-    qdev_property_add_child(dev, "piix3", &piix3->dev.qdev, NULL);
+    object_property_add_child(OBJECT(dev), "piix3", OBJECT(piix3), NULL);
     piix3->pic = pic;
     *isa_bus = DO_UPCAST(ISABus, qbus,
                          qdev_get_child_bus(&piix3->dev.qdev, "isa.0"));
@@ -502,60 +502,98 @@ static int piix3_initfn(PCIDevice *dev)
     return 0;
 }
 
-static PCIDeviceInfo i440fx_info[] = {
-    {
-        .qdev.name    = "i440FX",
-        .qdev.desc    = "Host bridge",
-        .qdev.size    = sizeof(PCII440FXState),
-        .qdev.vmsd    = &vmstate_i440fx,
-        .qdev.no_user = 1,
-        .no_hotplug   = 1,
-        .init         = i440fx_initfn,
-        .config_write = i440fx_write_config,
-        .vendor_id    = PCI_VENDOR_ID_INTEL,
-        .device_id    = PCI_DEVICE_ID_INTEL_82441,
-        .revision     = 0x02,
-        .class_id     = PCI_CLASS_BRIDGE_HOST,
-    },{
-        .qdev.name    = "PIIX3",
-        .qdev.desc    = "ISA bridge",
-        .qdev.size    = sizeof(PIIX3State),
-        .qdev.vmsd    = &vmstate_piix3,
-        .qdev.no_user = 1,
-        .no_hotplug   = 1,
-        .init         = piix3_initfn,
-        .config_write = piix3_write_config,
-        .vendor_id    = PCI_VENDOR_ID_INTEL,
-        .device_id    = PCI_DEVICE_ID_INTEL_82371SB_0, // 82371SB PIIX3 PCI-to-ISA bridge (Step A1)
-        .class_id     = PCI_CLASS_BRIDGE_ISA,
-    },{
-        .qdev.name    = "PIIX3-xen",
-        .qdev.desc    = "ISA bridge",
-        .qdev.size    = sizeof(PIIX3State),
-        .qdev.vmsd    = &vmstate_piix3,
-        .qdev.no_user = 1,
-        .no_hotplug   = 1,
-        .init         = piix3_initfn,
-        .config_write = piix3_write_config_xen,
-        .vendor_id    = PCI_VENDOR_ID_INTEL,
-        .device_id    = PCI_DEVICE_ID_INTEL_82371SB_0, // 82371SB PIIX3 PCI-to-ISA bridge (Step A1)
-        .class_id     = PCI_CLASS_BRIDGE_ISA,
-    },{
-        /* end of list */
-    }
+static void piix3_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    dc->desc        = "ISA bridge";
+    dc->vmsd        = &vmstate_piix3;
+    dc->no_user     = 1,
+    k->no_hotplug   = 1;
+    k->init         = piix3_initfn;
+    k->config_write = piix3_write_config;
+    k->vendor_id    = PCI_VENDOR_ID_INTEL;
+    k->device_id    = PCI_DEVICE_ID_INTEL_82371SB_0; // 82371SB PIIX3 PCI-to-ISA bridge (Step A1)
+    k->class_id     = PCI_CLASS_BRIDGE_ISA;
+}
+
+static TypeInfo piix3_info = {
+    .name          = "PIIX3",
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(PIIX3State),
+    .class_init    = piix3_class_init,
+};
+
+static void piix3_xen_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    dc->desc        = "ISA bridge";
+    dc->vmsd        = &vmstate_piix3;
+    dc->no_user     = 1;
+    k->no_hotplug   = 1;
+    k->init         = piix3_initfn;
+    k->config_write = piix3_write_config_xen;
+    k->vendor_id    = PCI_VENDOR_ID_INTEL;
+    k->device_id    = PCI_DEVICE_ID_INTEL_82371SB_0; // 82371SB PIIX3 PCI-to-ISA bridge (Step A1)
+    k->class_id     = PCI_CLASS_BRIDGE_ISA;
+};
+
+static TypeInfo piix3_xen_info = {
+    .name          = "PIIX3-xen",
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(PIIX3State),
+    .class_init    = piix3_xen_class_init,
 };
 
-static SysBusDeviceInfo i440fx_pcihost_info = {
-    .init         = i440fx_pcihost_initfn,
-    .qdev.name    = "i440FX-pcihost",
-    .qdev.fw_name = "pci",
-    .qdev.size    = sizeof(I440FXState),
-    .qdev.no_user = 1,
+static void i440fx_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->no_hotplug = 1;
+    k->init = i440fx_initfn;
+    k->config_write = i440fx_write_config;
+    k->vendor_id = PCI_VENDOR_ID_INTEL;
+    k->device_id = PCI_DEVICE_ID_INTEL_82441;
+    k->revision = 0x02;
+    k->class_id = PCI_CLASS_BRIDGE_HOST;
+    dc->desc = "Host bridge";
+    dc->no_user = 1;
+    dc->vmsd = &vmstate_i440fx;
+}
+
+static TypeInfo i440fx_info = {
+    .name          = "i440FX",
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(PCII440FXState),
+    .class_init    = i440fx_class_init,
+};
+
+static void i440fx_pcihost_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = i440fx_pcihost_initfn;
+    dc->fw_name = "pci";
+    dc->no_user = 1;
+}
+
+static TypeInfo i440fx_pcihost_info = {
+    .name          = "i440FX-pcihost",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(I440FXState),
+    .class_init    = i440fx_pcihost_class_init,
 };
 
 static void i440fx_register(void)
 {
-    sysbus_register_withprop(&i440fx_pcihost_info);
-    pci_qdev_register_many(i440fx_info);
+    type_register_static(&i440fx_info);
+    type_register_static(&piix3_info);
+    type_register_static(&piix3_xen_info);
+    type_register_static(&i440fx_pcihost_info);
 }
 device_init(i440fx_register);
diff --git a/hw/pl011.c b/hw/pl011.c
index 1b05d76a78..752cbf9725 100644
--- a/hw/pl011.c
+++ b/hw/pl011.c
@@ -264,7 +264,7 @@ static int pl011_init(SysBusDevice *dev, const unsigned char *id)
     sysbus_init_mmio(dev, &s->iomem);
     sysbus_init_irq(dev, &s->irq);
     s->id = id;
-    s->chr = qdev_init_chardev(&dev->qdev);
+    s->chr = qemu_char_get_next_serial();
 
     s->read_trigger = 1;
     s->ifl = 0x12;
@@ -278,22 +278,48 @@ static int pl011_init(SysBusDevice *dev, const unsigned char *id)
     return 0;
 }
 
-static int pl011_init_arm(SysBusDevice *dev)
+static int pl011_arm_init(SysBusDevice *dev)
 {
     return pl011_init(dev, pl011_id_arm);
 }
 
-static int pl011_init_luminary(SysBusDevice *dev)
+static int pl011_luminary_init(SysBusDevice *dev)
 {
     return pl011_init(dev, pl011_id_luminary);
 }
 
+static void pl011_arm_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+
+    sdc->init = pl011_arm_init;
+}
+
+static TypeInfo pl011_arm_info = {
+    .name          = "pl011",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(pl011_state),
+    .class_init    = pl011_arm_class_init,
+};
+
+static void pl011_luminary_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+
+    sdc->init = pl011_luminary_init;
+}
+
+static TypeInfo pl011_luminary_info = {
+    .name          = "pl011_luminary",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(pl011_state),
+    .class_init    = pl011_luminary_class_init,
+};
+
 static void pl011_register_devices(void)
 {
-    sysbus_register_dev("pl011", sizeof(pl011_state),
-                        pl011_init_arm);
-    sysbus_register_dev("pl011_luminary", sizeof(pl011_state),
-                        pl011_init_luminary);
+    type_register_static(&pl011_arm_info);
+    type_register_static(&pl011_luminary_info);
 }
 
 device_init(pl011_register_devices)
diff --git a/hw/pl022.c b/hw/pl022.c
index d43e4a29da..30bd3442bb 100644
--- a/hw/pl022.c
+++ b/hw/pl022.c
@@ -285,9 +285,23 @@ static int pl022_init(SysBusDevice *dev)
     return 0;
 }
 
+static void pl022_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+
+    sdc->init = pl022_init;
+}
+
+static TypeInfo pl022_info = {
+    .name          = "pl022",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(pl022_state),
+    .class_init    = pl022_class_init,
+};
+
 static void pl022_register_devices(void)
 {
-    sysbus_register_dev("pl022", sizeof(pl022_state), pl022_init);
+    type_register_static(&pl022_info);
 }
 
 device_init(pl022_register_devices)
diff --git a/hw/pl031.c b/hw/pl031.c
index 2fb0c8ef24..8416a609ef 100644
--- a/hw/pl031.c
+++ b/hw/pl031.c
@@ -213,17 +213,26 @@ static int pl031_init(SysBusDevice *dev)
     return 0;
 }
 
-static SysBusDeviceInfo pl031_info = {
-    .init = pl031_init,
-    .qdev.name = "pl031",
-    .qdev.size = sizeof(pl031_state),
-    .qdev.vmsd = &vmstate_pl031,
-    .qdev.no_user = 1,
+static void pl031_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = pl031_init;
+    dc->no_user = 1;
+    dc->vmsd = &vmstate_pl031;
+}
+
+static TypeInfo pl031_info = {
+    .name          = "pl031",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(pl031_state),
+    .class_init    = pl031_class_init,
 };
 
 static void pl031_register_devices(void)
 {
-    sysbus_register_withprop(&pl031_info);
+    type_register_static(&pl031_info);
 }
 
 device_init(pl031_register_devices)
diff --git a/hw/pl041.c b/hw/pl041.c
index 4585ccf9c0..6d99c9cbbc 100644
--- a/hw/pl041.c
+++ b/hw/pl041.c
@@ -613,24 +613,34 @@ static const VMStateDescription vmstate_pl041 = {
     }
 };
 
-static SysBusDeviceInfo pl041_device_info = {
-    .init = pl041_init,
-    .qdev.name = "pl041",
-    .qdev.size = sizeof(pl041_state),
-    .qdev.vmsd = &vmstate_pl041,
-    .qdev.reset = pl041_device_reset,
-    .qdev.no_user = 1,
-    .qdev.props = (Property[]) {
-        /* Non-compact FIFO depth property */
-        DEFINE_PROP_UINT32("nc_fifo_depth", pl041_state,
-                           fifo_depth, DEFAULT_FIFO_DEPTH),
-        DEFINE_PROP_END_OF_LIST(),
-    },
+static Property pl041_device_properties[] = {
+    /* Non-compact FIFO depth property */
+    DEFINE_PROP_UINT32("nc_fifo_depth", pl041_state, fifo_depth, DEFAULT_FIFO_DEPTH),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void pl041_device_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = pl041_init;
+    dc->no_user = 1;
+    dc->reset = pl041_device_reset;
+    dc->vmsd = &vmstate_pl041;
+    dc->props = pl041_device_properties;
+}
+
+static TypeInfo pl041_device_info = {
+    .name          = "pl041",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(pl041_state),
+    .class_init    = pl041_device_class_init,
 };
 
 static void pl041_register_device(void)
 {
-    sysbus_register_withprop(&pl041_device_info);
+    type_register_static(&pl041_device_info);
 }
 
 device_init(pl041_register_device)
diff --git a/hw/pl050.c b/hw/pl050.c
index 8182a1c82d..b0094ac9b3 100644
--- a/hw/pl050.c
+++ b/hw/pl050.c
@@ -157,24 +157,42 @@ static int pl050_init_mouse(SysBusDevice *dev)
     return pl050_init(dev, 1);
 }
 
-static SysBusDeviceInfo pl050_kbd_info = {
-    .init = pl050_init_keyboard,
-    .qdev.name  = "pl050_keyboard",
-    .qdev.size  = sizeof(pl050_state),
-    .qdev.vmsd = &vmstate_pl050,
+static void pl050_kbd_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = pl050_init_keyboard;
+    dc->vmsd = &vmstate_pl050;
+}
+
+static TypeInfo pl050_kbd_info = {
+    .name          = "pl050_keyboard",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(pl050_state),
+    .class_init    = pl050_kbd_class_init,
 };
 
-static SysBusDeviceInfo pl050_mouse_info = {
-    .init = pl050_init_mouse,
-    .qdev.name  = "pl050_mouse",
-    .qdev.size  = sizeof(pl050_state),
-    .qdev.vmsd = &vmstate_pl050,
+static void pl050_mouse_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = pl050_init_mouse;
+    dc->vmsd = &vmstate_pl050;
+}
+
+static TypeInfo pl050_mouse_info = {
+    .name          = "pl050_mouse",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(pl050_state),
+    .class_init    = pl050_mouse_class_init,
 };
 
 static void pl050_register_devices(void)
 {
-    sysbus_register_withprop(&pl050_kbd_info);
-    sysbus_register_withprop(&pl050_mouse_info);
+    type_register_static(&pl050_kbd_info);
+    type_register_static(&pl050_mouse_info);
 }
 
 device_init(pl050_register_devices)
diff --git a/hw/pl061.c b/hw/pl061.c
index f33ae84408..3136c99423 100644
--- a/hw/pl061.c
+++ b/hw/pl061.c
@@ -293,24 +293,42 @@ static int pl061_init_arm(SysBusDevice *dev)
     return pl061_init(dev, pl061_id);
 }
 
-static SysBusDeviceInfo pl061_info = {
-    .init = pl061_init_arm,
-    .qdev.name = "pl061",
-    .qdev.size = sizeof(pl061_state),
-    .qdev.vmsd = &vmstate_pl061,
+static void pl061_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = pl061_init_arm;
+    dc->vmsd = &vmstate_pl061;
+}
+
+static TypeInfo pl061_info = {
+    .name          = "pl061",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(pl061_state),
+    .class_init    = pl061_class_init,
 };
 
-static SysBusDeviceInfo pl061_luminary_info = {
-    .init = pl061_init_luminary,
-    .qdev.name = "pl061_luminary",
-    .qdev.size = sizeof(pl061_state),
-    .qdev.vmsd = &vmstate_pl061,
+static void pl061_luminary_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = pl061_init_luminary;
+    dc->vmsd = &vmstate_pl061;
+}
+
+static TypeInfo pl061_luminary_info = {
+    .name          = "pl061_luminary",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(pl061_state),
+    .class_init    = pl061_luminary_class_init,
 };
 
 static void pl061_register_devices(void)
 {
-    sysbus_register_withprop(&pl061_info);
-    sysbus_register_withprop(&pl061_luminary_info);
+    type_register_static(&pl061_info);
+    type_register_static(&pl061_luminary_info);
 }
 
 device_init(pl061_register_devices)
diff --git a/hw/pl080.c b/hw/pl080.c
index e001df92e0..4405d1823b 100644
--- a/hw/pl080.c
+++ b/hw/pl080.c
@@ -373,28 +373,46 @@ static int pl081_init(SysBusDevice *dev)
     return pl08x_init(dev, 2);
 }
 
-static SysBusDeviceInfo pl080_info = {
-    .init = pl080_init,
-    .qdev.name = "pl080",
-    .qdev.size = sizeof(pl080_state),
-    .qdev.vmsd = &vmstate_pl080,
-    .qdev.no_user = 1,
+static void pl080_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = pl080_init;
+    dc->no_user = 1;
+    dc->vmsd = &vmstate_pl080;
+}
+
+static TypeInfo pl080_info = {
+    .name          = "pl080",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(pl080_state),
+    .class_init    = pl080_class_init,
 };
 
-static SysBusDeviceInfo pl081_info = {
-    .init = pl081_init,
-    .qdev.name = "pl081",
-    .qdev.size = sizeof(pl080_state),
-    .qdev.vmsd = &vmstate_pl080,
-    .qdev.no_user = 1,
+static void pl081_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = pl081_init;
+    dc->no_user = 1;
+    dc->vmsd = &vmstate_pl080;
+}
+
+static TypeInfo pl081_info = {
+    .name          = "pl081",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(pl080_state),
+    .class_init    = pl081_class_init,
 };
 
 /* The PL080 and PL081 are the same except for the number of channels
    they implement (8 and 2 respectively).  */
 static void pl080_register_devices(void)
 {
-    sysbus_register_withprop(&pl080_info);
-    sysbus_register_withprop(&pl081_info);
+    type_register_static(&pl080_info);
+    type_register_static(&pl081_info);
 }
 
 device_init(pl080_register_devices)
diff --git a/hw/pl110.c b/hw/pl110.c
index 0e1f415aeb..86e95a3ffd 100644
--- a/hw/pl110.c
+++ b/hw/pl110.c
@@ -469,35 +469,62 @@ static int pl111_init(SysBusDevice *dev)
     return pl110_init(dev);
 }
 
-static SysBusDeviceInfo pl110_info = {
-    .init = pl110_init,
-    .qdev.name = "pl110",
-    .qdev.size = sizeof(pl110_state),
-    .qdev.vmsd = &vmstate_pl110,
-    .qdev.no_user = 1,
+static void pl110_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = pl110_init;
+    dc->no_user = 1;
+    dc->vmsd = &vmstate_pl110;
+}
+
+static TypeInfo pl110_info = {
+    .name          = "pl110",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(pl110_state),
+    .class_init    = pl110_class_init,
 };
 
-static SysBusDeviceInfo pl110_versatile_info = {
-    .init = pl110_versatile_init,
-    .qdev.name = "pl110_versatile",
-    .qdev.size = sizeof(pl110_state),
-    .qdev.vmsd = &vmstate_pl110,
-    .qdev.no_user = 1,
+static void pl110_versatile_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = pl110_versatile_init;
+    dc->no_user = 1;
+    dc->vmsd = &vmstate_pl110;
+}
+
+static TypeInfo pl110_versatile_info = {
+    .name          = "pl110_versatile",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(pl110_state),
+    .class_init    = pl110_versatile_class_init,
 };
 
-static SysBusDeviceInfo pl111_info = {
-    .init = pl111_init,
-    .qdev.name = "pl111",
-    .qdev.size = sizeof(pl110_state),
-    .qdev.vmsd = &vmstate_pl110,
-    .qdev.no_user = 1,
+static void pl111_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = pl111_init;
+    dc->no_user = 1;
+    dc->vmsd = &vmstate_pl110;
+}
+
+static TypeInfo pl111_info = {
+    .name          = "pl111",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(pl110_state),
+    .class_init    = pl111_class_init,
 };
 
 static void pl110_register_devices(void)
 {
-    sysbus_register_withprop(&pl110_info);
-    sysbus_register_withprop(&pl110_versatile_info);
-    sysbus_register_withprop(&pl111_info);
+    type_register_static(&pl110_info);
+    type_register_static(&pl110_versatile_info);
+    type_register_static(&pl111_info);
 }
 
 device_init(pl110_register_devices)
diff --git a/hw/pl181.c b/hw/pl181.c
index b79aa418fa..ae636e220e 100644
--- a/hw/pl181.c
+++ b/hw/pl181.c
@@ -487,18 +487,27 @@ static int pl181_init(SysBusDevice *dev)
     return 0;
 }
 
-static SysBusDeviceInfo pl181_info = {
-    .init = pl181_init,
-    .qdev.name = "pl181",
-    .qdev.size = sizeof(pl181_state),
-    .qdev.vmsd = &vmstate_pl181,
-    .qdev.reset = pl181_reset,
-    .qdev.no_user = 1,
+static void pl181_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+    DeviceClass *k = DEVICE_CLASS(klass);
+
+    sdc->init = pl181_init;
+    k->vmsd = &vmstate_pl181;
+    k->reset = pl181_reset;
+    k->no_user = 1;
+}
+
+static TypeInfo pl181_info = {
+    .name          = "pl181",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(pl181_state),
+    .class_init    = pl181_class_init,
 };
 
 static void pl181_register_devices(void)
 {
-    sysbus_register_withprop(&pl181_info);
+    type_register_static(&pl181_info);
 }
 
 device_init(pl181_register_devices)
diff --git a/hw/pl190.c b/hw/pl190.c
index 6fc2656f69..956ab21c6a 100644
--- a/hw/pl190.c
+++ b/hw/pl190.c
@@ -255,18 +255,27 @@ static const VMStateDescription vmstate_pl190 = {
     }
 };
 
-static SysBusDeviceInfo pl190_info = {
-    .init = pl190_init,
-    .qdev.name = "pl190",
-    .qdev.size = sizeof(pl190_state),
-    .qdev.vmsd = &vmstate_pl190,
-    .qdev.reset = pl190_reset,
-    .qdev.no_user = 1,
+static void pl190_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = pl190_init;
+    dc->no_user = 1;
+    dc->reset = pl190_reset;
+    dc->vmsd = &vmstate_pl190;
+}
+
+static TypeInfo pl190_info = {
+    .name          = "pl190",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(pl190_state),
+    .class_init    = pl190_class_init,
 };
 
 static void pl190_register_devices(void)
 {
-    sysbus_register_withprop(&pl190_info);
+    type_register_static(&pl190_info);
 }
 
 device_init(pl190_register_devices)
diff --git a/hw/ppc440.c b/hw/ppc440.c
deleted file mode 100644
index cd8a95d52b..0000000000
--- a/hw/ppc440.c
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * Qemu PowerPC 440 chip emulation
- *
- * Copyright 2007 IBM Corporation.
- * Authors:
- * 	Jerone Young <jyoung5@us.ibm.com>
- * 	Christian Ehrhardt <ehrhardt@linux.vnet.ibm.com>
- * 	Hollis Blanchard <hollisb@us.ibm.com>
- *
- * This work is licensed under the GNU GPL license version 2 or later.
- *
- */
-
-#include "hw.h"
-#include "pc.h"
-#include "isa.h"
-#include "ppc.h"
-#include "ppc4xx.h"
-#include "ppc440.h"
-#include "ppc405.h"
-#include "sysemu.h"
-#include "kvm.h"
-
-#define PPC440EP_PCI_CONFIG     0xeec00000
-#define PPC440EP_PCI_INTACK     0xeed00000
-#define PPC440EP_PCI_SPECIAL    0xeed00000
-#define PPC440EP_PCI_REGS       0xef400000
-#define PPC440EP_PCI_IO         0xe8000000
-#define PPC440EP_PCI_IOLEN      0x00010000
-
-#define PPC440EP_SDRAM_NR_BANKS 4
-
-static const unsigned int ppc440ep_sdram_bank_sizes[] = {
-    256<<20, 128<<20, 64<<20, 32<<20, 16<<20, 8<<20, 0
-};
-
-CPUState *ppc440ep_init(MemoryRegion *address_space_mem, ram_addr_t *ram_size,
-                        PCIBus **pcip, const unsigned int pci_irq_nrs[4],
-                        int do_init, const char *cpu_model)
-{
-    MemoryRegion *ram_memories
-        = g_malloc(PPC440EP_SDRAM_NR_BANKS * sizeof(*ram_memories));
-    target_phys_addr_t ram_bases[PPC440EP_SDRAM_NR_BANKS];
-    target_phys_addr_t ram_sizes[PPC440EP_SDRAM_NR_BANKS];
-    CPUState *env;
-    qemu_irq *pic;
-    qemu_irq *irqs;
-    qemu_irq *pci_irqs;
-
-    if (cpu_model == NULL) {
-        cpu_model = "440-Xilinx"; // XXX: should be 440EP
-    }
-    env = cpu_init(cpu_model);
-    if (!env) {
-        fprintf(stderr, "Unable to initialize CPU!\n");
-        exit(1);
-    }
-
-    ppc_dcr_init(env, NULL, NULL);
-
-    /* interrupt controller */
-    irqs = g_malloc0(sizeof(qemu_irq) * PPCUIC_OUTPUT_NB);
-    irqs[PPCUIC_OUTPUT_INT] = ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_INT];
-    irqs[PPCUIC_OUTPUT_CINT] = ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_CINT];
-    pic = ppcuic_init(env, irqs, 0x0C0, 0, 1);
-
-    /* SDRAM controller */
-    memset(ram_bases, 0, sizeof(ram_bases));
-    memset(ram_sizes, 0, sizeof(ram_sizes));
-    *ram_size = ppc4xx_sdram_adjust(*ram_size, PPC440EP_SDRAM_NR_BANKS,
-                                    ram_memories,
-                                    ram_bases, ram_sizes,
-                                    ppc440ep_sdram_bank_sizes);
-    /* XXX 440EP's ECC interrupts are on UIC1, but we've only created UIC0. */
-    ppc4xx_sdram_init(env, pic[14], PPC440EP_SDRAM_NR_BANKS, ram_memories,
-                      ram_bases, ram_sizes, do_init);
-
-    /* PCI */
-    pci_irqs = g_malloc(sizeof(qemu_irq) * 4);
-    pci_irqs[0] = pic[pci_irq_nrs[0]];
-    pci_irqs[1] = pic[pci_irq_nrs[1]];
-    pci_irqs[2] = pic[pci_irq_nrs[2]];
-    pci_irqs[3] = pic[pci_irq_nrs[3]];
-    *pcip = ppc4xx_pci_init(env, pci_irqs,
-                            PPC440EP_PCI_CONFIG,
-                            PPC440EP_PCI_INTACK,
-                            PPC440EP_PCI_SPECIAL,
-                            PPC440EP_PCI_REGS);
-    if (!*pcip)
-        printf("couldn't create PCI controller!\n");
-
-    isa_mmio_init(PPC440EP_PCI_IO, PPC440EP_PCI_IOLEN);
-
-    if (serial_hds[0] != NULL) {
-        serial_mm_init(address_space_mem, 0xef600300, 0, pic[0],
-                       PPC_SERIAL_MM_BAUDBASE, serial_hds[0],
-                       DEVICE_BIG_ENDIAN);
-    }
-    if (serial_hds[1] != NULL) {
-        serial_mm_init(address_space_mem, 0xef600400, 0, pic[1],
-                       PPC_SERIAL_MM_BAUDBASE, serial_hds[1],
-                       DEVICE_BIG_ENDIAN);
-    }
-
-    return env;
-}
diff --git a/hw/ppc440.h b/hw/ppc440.h
deleted file mode 100644
index 9c27c36fd0..0000000000
--- a/hw/ppc440.h
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * Qemu PowerPC 440 board emualtion
- *
- * Copyright 2007 IBM Corporation.
- * Authors: Jerone Young <jyoung5@us.ibm.com>
- * 	    Christian Ehrhardt <ehrhardt@linux.vnet.ibm.com>
- *
- * This work is licensed under the GNU GPL licence version 2 or later
- *
- */
-
-#ifndef QEMU_PPC440_H
-#define QEMU_PPC440_H
-
-#include "hw.h"
-
-CPUState *ppc440ep_init(MemoryRegion *address_space, ram_addr_t *ram_size,
-                        PCIBus **pcip, const unsigned int pci_irq_nrs[4],
-                        int do_init, const char *cpu_model);
-
-#endif
diff --git a/hw/ppc440_bamboo.c b/hw/ppc440_bamboo.c
index b734e3a56c..f86b16838a 100644
--- a/hw/ppc440_bamboo.c
+++ b/hw/ppc440_bamboo.c
@@ -3,9 +3,9 @@
  *
  * Copyright 2007 IBM Corporation.
  * Authors:
- * 	Jerone Young <jyoung5@us.ibm.com>
- * 	Christian Ehrhardt <ehrhardt@linux.vnet.ibm.com>
- * 	Hollis Blanchard <hollisb@us.ibm.com>
+ *	Jerone Young <jyoung5@us.ibm.com>
+ *	Christian Ehrhardt <ehrhardt@linux.vnet.ibm.com>
+ *	Hollis Blanchard <hollisb@us.ibm.com>
  *
  * This work is licensed under the GNU GPL license version 2 or later.
  *
@@ -17,13 +17,17 @@
 #include "hw.h"
 #include "pci.h"
 #include "boards.h"
-#include "ppc440.h"
 #include "kvm.h"
 #include "kvm_ppc.h"
 #include "device_tree.h"
 #include "loader.h"
 #include "elf.h"
 #include "exec-memory.h"
+#include "pc.h"
+#include "ppc.h"
+#include "ppc405.h"
+#include "sysemu.h"
+#include "sysbus.h"
 
 #define BINARY_DEVICE_TREE_FILE "bamboo.dtb"
 
@@ -32,6 +36,21 @@
 #define FDT_ADDR     0x1800000
 #define RAMDISK_ADDR 0x1900000
 
+#define PPC440EP_PCI_CONFIG     0xeec00000
+#define PPC440EP_PCI_INTACK     0xeed00000
+#define PPC440EP_PCI_SPECIAL    0xeed00000
+#define PPC440EP_PCI_REGS       0xef400000
+#define PPC440EP_PCI_IO         0xe8000000
+#define PPC440EP_PCI_IOLEN      0x00010000
+
+#define PPC440EP_SDRAM_NR_BANKS 4
+
+static const unsigned int ppc440ep_sdram_bank_sizes[] = {
+    256<<20, 128<<20, 64<<20, 32<<20, 16<<20, 8<<20, 0
+};
+
+static target_phys_addr_t entry;
+
 static int bamboo_load_device_tree(target_phys_addr_t addr,
                                      uint32_t ramsize,
                                      target_phys_addr_t initrd_base,
@@ -101,6 +120,42 @@ out:
     return ret;
 }
 
+/* Create reset TLB entries for BookE, spanning the 32bit addr space.  */
+static void mmubooke_create_initial_mapping(CPUState *env,
+                                     target_ulong va,
+                                     target_phys_addr_t pa)
+{
+    ppcemb_tlb_t *tlb = &env->tlb.tlbe[0];
+
+    tlb->attr = 0;
+    tlb->prot = PAGE_VALID | ((PAGE_READ | PAGE_WRITE | PAGE_EXEC) << 4);
+    tlb->size = 1 << 31; /* up to 0x80000000  */
+    tlb->EPN = va & TARGET_PAGE_MASK;
+    tlb->RPN = pa & TARGET_PAGE_MASK;
+    tlb->PID = 0;
+
+    tlb = &env->tlb.tlbe[1];
+    tlb->attr = 0;
+    tlb->prot = PAGE_VALID | ((PAGE_READ | PAGE_WRITE | PAGE_EXEC) << 4);
+    tlb->size = 1 << 31; /* up to 0xffffffff  */
+    tlb->EPN = 0x80000000 & TARGET_PAGE_MASK;
+    tlb->RPN = 0x80000000 & TARGET_PAGE_MASK;
+    tlb->PID = 0;
+}
+
+static void main_cpu_reset(void *opaque)
+{
+    CPUState *env = opaque;
+
+    cpu_reset(env);
+    env->gpr[1] = (16<<20) - 8;
+    env->gpr[3] = FDT_ADDR;
+    env->nip = entry;
+
+    /* Create a mapping for the kernel.  */
+    mmubooke_create_initial_mapping(env, 0, 0);
+}
+
 static void bamboo_init(ram_addr_t ram_size,
                         const char *boot_device,
                         const char *kernel_filename,
@@ -110,19 +165,76 @@ static void bamboo_init(ram_addr_t ram_size,
 {
     unsigned int pci_irq_nrs[4] = { 28, 27, 26, 25 };
     MemoryRegion *address_space_mem = get_system_memory();
+    MemoryRegion *ram_memories
+        = g_malloc(PPC440EP_SDRAM_NR_BANKS * sizeof(*ram_memories));
+    target_phys_addr_t ram_bases[PPC440EP_SDRAM_NR_BANKS];
+    target_phys_addr_t ram_sizes[PPC440EP_SDRAM_NR_BANKS];
+    qemu_irq *pic;
+    qemu_irq *irqs;
     PCIBus *pcibus;
     CPUState *env;
     uint64_t elf_entry;
     uint64_t elf_lowaddr;
-    target_phys_addr_t entry = 0;
     target_phys_addr_t loadaddr = 0;
     target_long initrd_size = 0;
+    DeviceState *dev;
     int success;
     int i;
 
     /* Setup CPU. */
-    env = ppc440ep_init(address_space_mem, &ram_size, &pcibus,
-                        pci_irq_nrs, 1, cpu_model);
+    if (cpu_model == NULL) {
+        cpu_model = "440EP";
+    }
+    env = cpu_init(cpu_model);
+    if (!env) {
+        fprintf(stderr, "Unable to initialize CPU!\n");
+        exit(1);
+    }
+
+    qemu_register_reset(main_cpu_reset, env);
+    ppc_booke_timers_init(env, 400000000, 0);
+    ppc_dcr_init(env, NULL, NULL);
+
+    /* interrupt controller */
+    irqs = g_malloc0(sizeof(qemu_irq) * PPCUIC_OUTPUT_NB);
+    irqs[PPCUIC_OUTPUT_INT] = ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_INT];
+    irqs[PPCUIC_OUTPUT_CINT] = ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_CINT];
+    pic = ppcuic_init(env, irqs, 0x0C0, 0, 1);
+
+    /* SDRAM controller */
+    memset(ram_bases, 0, sizeof(ram_bases));
+    memset(ram_sizes, 0, sizeof(ram_sizes));
+    ram_size = ppc4xx_sdram_adjust(ram_size, PPC440EP_SDRAM_NR_BANKS,
+                                   ram_memories,
+                                   ram_bases, ram_sizes,
+                                   ppc440ep_sdram_bank_sizes);
+    /* XXX 440EP's ECC interrupts are on UIC1, but we've only created UIC0. */
+    ppc4xx_sdram_init(env, pic[14], PPC440EP_SDRAM_NR_BANKS, ram_memories,
+                      ram_bases, ram_sizes, 1);
+
+    /* PCI */
+    dev = sysbus_create_varargs("ppc4xx-pcihost", PPC440EP_PCI_CONFIG,
+                                pic[pci_irq_nrs[0]], pic[pci_irq_nrs[1]],
+                                pic[pci_irq_nrs[2]], pic[pci_irq_nrs[3]],
+                                NULL);
+    pcibus = (PCIBus *)qdev_get_child_bus(dev, "pci.0");
+    if (!pcibus) {
+        fprintf(stderr, "couldn't create PCI controller!\n");
+        exit(1);
+    }
+
+    isa_mmio_init(PPC440EP_PCI_IO, PPC440EP_PCI_IOLEN);
+
+    if (serial_hds[0] != NULL) {
+        serial_mm_init(address_space_mem, 0xef600300, 0, pic[0],
+                       PPC_SERIAL_MM_BAUDBASE, serial_hds[0],
+                       DEVICE_BIG_ENDIAN);
+    }
+    if (serial_hds[1] != NULL) {
+        serial_mm_init(address_space_mem, 0xef600400, 0, pic[1],
+                       PPC_SERIAL_MM_BAUDBASE, serial_hds[1],
+                       DEVICE_BIG_ENDIAN);
+    }
 
     if (pcibus) {
         /* Register network interfaces. */
@@ -169,12 +281,6 @@ static void bamboo_init(ram_addr_t ram_size,
             fprintf(stderr, "couldn't load device tree\n");
             exit(1);
         }
-
-        /* Set initial guest state. */
-        env->gpr[1] = (16<<20) - 8;
-        env->gpr[3] = FDT_ADDR;
-        env->nip = entry;
-        /* XXX we currently depend on KVM to create some initial TLB entries. */
     }
 
     if (kvm_enabled())
@@ -182,34 +288,14 @@ static void bamboo_init(ram_addr_t ram_size,
 }
 
 static QEMUMachine bamboo_machine = {
-    .name = "bamboo-0.13",
-    .alias = "bamboo",
-    .desc = "bamboo",
-    .init = bamboo_init,
-};
-
-static QEMUMachine bamboo_machine_v0_12 = {
-    .name = "bamboo-0.12",
+    .name = "bamboo",
     .desc = "bamboo",
     .init = bamboo_init,
-    .compat_props = (GlobalProperty[]) {
-        {
-            .driver   = "virtio-serial-pci",
-            .property = "max_ports",
-            .value    = stringify(1),
-        },{
-            .driver   = "virtio-serial-pci",
-            .property = "vectors",
-            .value    = stringify(0),
-        },
-        { /* end of list */ }
-    },
 };
 
 static void bamboo_machine_init(void)
 {
     qemu_register_machine(&bamboo_machine);
-    qemu_register_machine(&bamboo_machine_v0_12);
 }
 
 machine_init(bamboo_machine_init);
diff --git a/hw/ppc4xx_pci.c b/hw/ppc4xx_pci.c
index 2c69210225..d11f120d32 100644
--- a/hw/ppc4xx_pci.c
+++ b/hw/ppc4xx_pci.c
@@ -49,13 +49,14 @@ struct PCITargetMap {
 #define PPC4xx_PCI_NR_PTMS 2
 
 struct PPC4xxPCIState {
+    PCIHostState pci_state;
+
     struct PCIMasterMap pmm[PPC4xx_PCI_NR_PMMS];
     struct PCITargetMap ptm[PPC4xx_PCI_NR_PTMS];
+    qemu_irq irq[4];
 
-    PCIHostState pci_state;
-    PCIDevice *pci_dev;
-    MemoryRegion iomem_addr;
-    MemoryRegion iomem_regs;
+    MemoryRegion container;
+    MemoryRegion iomem;
 };
 typedef struct PPC4xxPCIState PPC4xxPCIState;
 
@@ -83,8 +84,10 @@ typedef struct PPC4xxPCIState PPC4xxPCIState;
 #define PCIL0_PTM1LA        0x34
 #define PCIL0_PTM2MS        0x38
 #define PCIL0_PTM2LA        0x3c
+#define PCI_REG_BASE        0x800000
 #define PCI_REG_SIZE        0x40
 
+#define PCI_ALL_SIZE        (PCI_REG_BASE + PCI_REG_SIZE)
 
 static uint64_t pci4xx_cfgaddr_read(void *opaque, target_phys_addr_t addr,
                                     unsigned size)
@@ -275,6 +278,10 @@ static void ppc4xx_pci_set_irq(void *opaque, int irq_num, int level)
     qemu_irq *pci_irqs = opaque;
 
     DPRINTF("%s: PCI irq %d\n", __func__, irq_num);
+    if (irq_num < 0) {
+        fprintf(stderr, "%s: PCI irq %d\n", __func__, irq_num);
+        return;
+    }
     qemu_set_irq(pci_irqs[irq_num], level);
 }
 
@@ -310,7 +317,6 @@ static const VMStateDescription vmstate_ppc4xx_pci = {
     .minimum_version_id = 1,
     .minimum_version_id_old = 1,
     .fields      = (VMStateField[]) {
-        VMSTATE_PCI_DEVICE_POINTER(pci_dev, PPC4xxPCIState),
         VMSTATE_STRUCT_ARRAY(pmm, PPC4xxPCIState, PPC4xx_PCI_NR_PMMS, 1,
                              vmstate_pci_master_map,
                              struct PCIMasterMap),
@@ -322,60 +328,81 @@ static const VMStateDescription vmstate_ppc4xx_pci = {
 };
 
 /* XXX Interrupt acknowledge cycles not supported. */
-PCIBus *ppc4xx_pci_init(CPUState *env, qemu_irq pci_irqs[4],
-                        target_phys_addr_t config_space,
-                        target_phys_addr_t int_ack,
-                        target_phys_addr_t special_cycle,
-                        target_phys_addr_t registers)
+static int ppc4xx_pcihost_initfn(SysBusDevice *dev)
+{
+    PPC4xxPCIState *s;
+    PCIHostState *h;
+    PCIBus *b;
+    int i;
+
+    h = FROM_SYSBUS(PCIHostState, sysbus_from_qdev(dev));
+    s = DO_UPCAST(PPC4xxPCIState, pci_state, h);
+
+    for (i = 0; i < ARRAY_SIZE(s->irq); i++) {
+        sysbus_init_irq(dev, &s->irq[i]);
+    }
+
+    b = pci_register_bus(&s->pci_state.busdev.qdev, NULL, ppc4xx_pci_set_irq,
+                         ppc4xx_pci_map_irq, s->irq, get_system_memory(),
+                         get_system_io(), 0, 4);
+    s->pci_state.bus = b;
+
+    pci_create_simple(b, 0, "ppc4xx-host-bridge");
+
+    /* XXX split into 2 memory regions, one for config space, one for regs */
+    memory_region_init(&s->container, "pci-container", PCI_ALL_SIZE);
+    memory_region_init_io(&h->conf_mem, &pci_host_conf_le_ops, h,
+                          "pci-conf-idx", 4);
+    memory_region_init_io(&h->data_mem, &pci_host_data_le_ops, h,
+                          "pci-conf-data", 4);
+    memory_region_init_io(&s->iomem, &pci_reg_ops, s,
+                          "pci.reg", PCI_REG_SIZE);
+    memory_region_add_subregion(&s->container, PCIC0_CFGADDR, &h->conf_mem);
+    memory_region_add_subregion(&s->container, PCIC0_CFGDATA, &h->data_mem);
+    memory_region_add_subregion(&s->container, PCI_REG_BASE, &s->iomem);
+    sysbus_init_mmio(dev, &s->container);
+    qemu_register_reset(ppc4xx_pci_reset, s);
+
+    return 0;
+}
+
+static void ppc4xx_host_bridge_class_init(ObjectClass *klass, void *data)
+{
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    dc->desc        = "Host bridge";
+    k->vendor_id    = PCI_VENDOR_ID_IBM;
+    k->device_id    = PCI_DEVICE_ID_IBM_440GX;
+    k->class_id     = PCI_CLASS_BRIDGE_OTHER;
+}
+
+static TypeInfo ppc4xx_host_bridge_info = {
+    .name          = "ppc4xx-host-bridge",
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(PCIDevice),
+    .class_init    = ppc4xx_host_bridge_class_init,
+};
+
+static void ppc4xx_pcihost_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    k->init = ppc4xx_pcihost_initfn;
+    dc->vmsd = &vmstate_ppc4xx_pci;
+}
+
+static TypeInfo ppc4xx_pcihost_info = {
+    .name          = "ppc4xx-pcihost",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(PPC4xxPCIState),
+    .class_init    = ppc4xx_pcihost_class_init,
+};
+
+static void ppc4xx_pci_register(void)
 {
-    PPC4xxPCIState *controller;
-    static int ppc4xx_pci_id;
-    uint8_t *pci_conf;
-
-    controller = g_malloc0(sizeof(PPC4xxPCIState));
-
-    controller->pci_state.bus = pci_register_bus(NULL, "pci",
-                                                 ppc4xx_pci_set_irq,
-                                                 ppc4xx_pci_map_irq,
-                                                 pci_irqs,
-                                                 get_system_memory(),
-                                                 get_system_io(),
-                                                 0, 4);
-
-    controller->pci_dev = pci_register_device(controller->pci_state.bus,
-                                              "host bridge", sizeof(PCIDevice),
-                                              0, NULL, NULL);
-    pci_conf = controller->pci_dev->config;
-    pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_IBM);
-    pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_IBM_440GX);
-    pci_config_set_class(pci_conf, PCI_CLASS_BRIDGE_OTHER);
-
-    /* CFGADDR */
-    memory_region_init_io(&controller->iomem_addr, &pci4xx_cfgaddr_ops,
-                          controller, "pci.cfgaddr", 4);
-    memory_region_add_subregion(get_system_memory(),
-                                config_space + PCIC0_CFGADDR,
-                                &controller->iomem_addr);
-
-    /* CFGDATA */
-    memory_region_init_io(&controller->pci_state.data_mem,
-                          &pci_host_data_be_ops,
-                          &controller->pci_state, "pci-conf-data", 4);
-    memory_region_add_subregion(get_system_memory(),
-                                config_space + PCIC0_CFGDATA,
-                                &controller->pci_state.data_mem);
-
-    /* Internal registers */
-    memory_region_init_io(&controller->iomem_regs, &pci_reg_ops, controller,
-                          "pci.regs", PCI_REG_SIZE);
-    memory_region_add_subregion(get_system_memory(), registers,
-                                &controller->iomem_regs);
-
-    qemu_register_reset(ppc4xx_pci_reset, controller);
-
-    /* XXX load/save code not tested. */
-    vmstate_register(&controller->pci_dev->qdev, ppc4xx_pci_id++,
-                     &vmstate_ppc4xx_pci, controller);
-
-    return controller->pci_state.bus;
+    type_register_static(&ppc4xx_pcihost_info);
+    type_register_static(&ppc4xx_host_bridge_info);
 }
+device_init(ppc4xx_pci_register);
diff --git a/hw/ppc_newworld.c b/hw/ppc_newworld.c
index a746c9c3c6..506187b182 100644
--- a/hw/ppc_newworld.c
+++ b/hw/ppc_newworld.c
@@ -311,7 +311,7 @@ static void ppc_core99_init (ram_addr_t ram_size,
             exit(1);
         }
     }
-    pic = openpic_init(NULL, &pic_mem, smp_cpus, openpic_irqs, NULL);
+    pic = openpic_init(&pic_mem, smp_cpus, openpic_irqs, NULL);
     if (PPC_INPUT(env) == PPC_FLAGS_INPUT_970) {
         /* 970 gets a U3 bus */
         pci_bus = pci_pmac_u3_init(pic, get_system_memory(), get_system_io());
diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c
index 47dab3f184..eb43fb5849 100644
--- a/hw/ppc_prep.c
+++ b/hw/ppc_prep.c
@@ -29,7 +29,7 @@
 #include "sysemu.h"
 #include "isa.h"
 #include "pci.h"
-#include "prep_pci.h"
+#include "pci_host.h"
 #include "usb-ohci.h"
 #include "ppc.h"
 #include "boards.h"
@@ -83,37 +83,9 @@ static const int ide_irq[2] = { 13, 13 };
 static uint32_t ne2000_io[NE2000_NB_MAX] = { 0x300, 0x320, 0x340, 0x360, 0x280, 0x380 };
 static int ne2000_irq[NE2000_NB_MAX] = { 9, 10, 11, 3, 4, 5 };
 
-//static ISADevice *pit;
-
 /* ISA IO ports bridge */
 #define PPC_IO_BASE 0x80000000
 
-#if 0
-/* Speaker port 0x61 */
-static int speaker_data_on;
-static int dummy_refresh_clock;
-#endif
-
-static void speaker_ioport_write (void *opaque, uint32_t addr, uint32_t val)
-{
-#if 0
-    speaker_data_on = (val >> 1) & 1;
-    pit_set_gate(pit, 2, val & 1);
-#endif
-}
-
-static uint32_t speaker_ioport_read (void *opaque, uint32_t addr)
-{
-#if 0
-    int out;
-    out = pit_get_out(pit, 2, qemu_get_clock_ns(vm_clock));
-    dummy_refresh_clock ^= 1;
-    return (speaker_data_on << 1) | pit_get_gate(pit, 2) | (out << 5) |
-        (dummy_refresh_clock << 4);
-#endif
-    return 0;
-}
-
 /* PCI intack register */
 /* Read-only register (?) */
 static void PPC_intack_write (void *opaque, target_phys_addr_t addr,
@@ -522,9 +494,12 @@ static void ppc_prep_init (ram_addr_t ram_size,
     MemoryRegion *bios = g_new(MemoryRegion, 1);
     uint32_t kernel_base, initrd_base;
     long kernel_size, initrd_size;
+    DeviceState *dev;
+    SysBusDevice *sys;
+    PCIHostState *pcihost;
     PCIBus *pci_bus;
+    PCIDevice *pci;
     ISABus *isa_bus;
-    qemu_irq *i8259;
     qemu_irq *cpu_exit_irq;
     int ppc_boot_device;
     DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
@@ -560,6 +535,8 @@ static void ppc_prep_init (ram_addr_t ram_size,
 
     /* allocate and load BIOS */
     memory_region_init_ram(bios, "ppc_prep.bios", BIOS_SIZE);
+    memory_region_set_readonly(bios, true);
+    memory_region_add_subregion(sysmem, (uint32_t)(-BIOS_SIZE), bios);
     vmstate_register_ram_global(bios);
     if (bios_name == NULL)
         bios_name = BIOS_FILENAME;
@@ -573,8 +550,6 @@ static void ppc_prep_init (ram_addr_t ram_size,
         target_phys_addr_t bios_addr;
         bios_size = (bios_size + 0xfff) & ~0xfff;
         bios_addr = (uint32_t)(-bios_size);
-        memory_region_set_readonly(bios, true);
-        memory_region_add_subregion(sysmem, bios_addr, bios);
         bios_size = load_image_targphys(filename, bios_addr, bios_size);
     }
     if (bios_size < 0 || bios_size > BIOS_SIZE) {
@@ -626,16 +601,34 @@ static void ppc_prep_init (ram_addr_t ram_size,
         }
     }
 
-    isa_mem_base = 0xc0000000;
     if (PPC_INPUT(env) != PPC_FLAGS_INPUT_6xx) {
         hw_error("Only 6xx bus is supported on PREP machine\n");
     }
-    /* Hmm, prep has no pci-isa bridge ??? */
-    isa_bus = isa_bus_new(NULL, get_system_io());
-    i8259 = i8259_init(isa_bus, first_cpu->irq_inputs[PPC6xx_INPUT_INT]);
-    pci_bus = pci_prep_init(i8259, get_system_memory(), get_system_io());
-    isa_bus_irqs(isa_bus, i8259);
-    //    pci_bus = i440fx_init();
+
+    dev = qdev_create(NULL, "raven-pcihost");
+    sys = sysbus_from_qdev(dev);
+    pcihost = DO_UPCAST(PCIHostState, busdev, sys);
+    pcihost->address_space = get_system_memory();
+    qdev_init_nofail(dev);
+    object_property_add_child(object_get_root(), "raven", OBJECT(dev), NULL);
+    pci_bus = (PCIBus *)qdev_get_child_bus(dev, "pci.0");
+    if (pci_bus == NULL) {
+        fprintf(stderr, "Couldn't create PCI host controller.\n");
+        exit(1);
+    }
+
+    /* PCI -> ISA bridge */
+    pci = pci_create_simple(pci_bus, PCI_DEVFN(1, 0), "i82378");
+    cpu_exit_irq = qemu_allocate_irqs(cpu_request_exit, NULL, 1);
+    qdev_connect_gpio_out(&pci->qdev, 0,
+                          first_cpu->irq_inputs[PPC6xx_INPUT_INT]);
+    qdev_connect_gpio_out(&pci->qdev, 1, *cpu_exit_irq);
+    sysbus_connect_irq(&pcihost->busdev, 0, qdev_get_gpio_in(&pci->qdev, 9));
+    sysbus_connect_irq(&pcihost->busdev, 1, qdev_get_gpio_in(&pci->qdev, 11));
+    sysbus_connect_irq(&pcihost->busdev, 2, qdev_get_gpio_in(&pci->qdev, 9));
+    sysbus_connect_irq(&pcihost->busdev, 3, qdev_get_gpio_in(&pci->qdev, 11));
+    isa_bus = DO_UPCAST(ISABus, qbus, qdev_get_child_bus(&pci->qdev, "isa.0"));
+
     /* Register 8 MB of ISA IO space (needed for non-contiguous map) */
     memory_region_init_io(PPC_io_memory, &PPC_prep_io_ops, sysctrl,
                           "ppc-io", 0x00800000);
@@ -643,9 +636,6 @@ static void ppc_prep_init (ram_addr_t ram_size,
 
     /* init basic PC hardware */
     pci_vga_init(pci_bus);
-    //    openpic = openpic_init(0x00000000, 0xF0000000, 1);
-    //    pit = pit_init(0x40, 0);
-    rtc_init(isa_bus, 2000, NULL);
 
     if (serial_hds[0])
         serial_isa_init(isa_bus, 0, serial_hds[0]);
@@ -672,9 +662,6 @@ static void ppc_prep_init (ram_addr_t ram_size,
     }
     isa_create_simple(isa_bus, "i8042");
 
-    cpu_exit_irq = qemu_allocate_irqs(cpu_request_exit, NULL, 1);
-    DMA_init(1, cpu_exit_irq);
-
     //    SB16_init();
 
     for(i = 0; i < MAX_FD; i++) {
@@ -682,9 +669,6 @@ static void ppc_prep_init (ram_addr_t ram_size,
     }
     fdctrl_init_isa(isa_bus, fd);
 
-    /* Register speaker port */
-    register_ioport_read(0x61, 1, 1, speaker_ioport_read, NULL);
-    register_ioport_write(0x61, 1, 1, speaker_ioport_write, NULL);
     /* Register fake IO ports for PREP */
     sysctrl->reset_irq = first_cpu->irq_inputs[PPC6xx_INPUT_HRESET];
     register_ioport_read(0x398, 2, 1, &PREP_io_read, sysctrl);
@@ -707,7 +691,7 @@ static void ppc_prep_init (ram_addr_t ram_size,
         usb_ohci_init_pci(pci_bus, -1);
     }
 
-    m48t59 = m48t59_init(i8259[8], 0, 0x0074, NVRAM_SIZE, 59);
+    m48t59 = m48t59_init_isa(isa_bus, 0x0074, NVRAM_SIZE, 59);
     if (m48t59 == NULL)
         return;
     sysctrl->nvram = m48t59;
diff --git a/hw/ppce500_pci.c b/hw/ppce500_pci.c
index b606206e00..d5bce71429 100644
--- a/hw/ppce500_pci.c
+++ b/hw/ppce500_pci.c
@@ -339,25 +339,43 @@ static int e500_pcihost_initfn(SysBusDevice *dev)
     return 0;
 }
 
-static PCIDeviceInfo e500_host_bridge_info = {
-    .qdev.name    = "e500-host-bridge",
-    .qdev.desc    = "Host bridge",
-    .qdev.size    = sizeof(PCIDevice),
-    .vendor_id    = PCI_VENDOR_ID_FREESCALE,
-    .device_id    = PCI_DEVICE_ID_MPC8533E,
-    .class_id     = PCI_CLASS_PROCESSOR_POWERPC,
+static void e500_host_bridge_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->vendor_id = PCI_VENDOR_ID_FREESCALE;
+    k->device_id = PCI_DEVICE_ID_MPC8533E;
+    k->class_id = PCI_CLASS_PROCESSOR_POWERPC;
+    dc->desc = "Host bridge";
+}
+
+static TypeInfo e500_host_bridge_info = {
+    .name          = "e500-host-bridge",
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(PCIDevice),
+    .class_init    = e500_host_bridge_class_init,
 };
 
-static SysBusDeviceInfo e500_pcihost_info = {
-    .init         = e500_pcihost_initfn,
-    .qdev.name    = "e500-pcihost",
-    .qdev.size    = sizeof(PPCE500PCIState),
-    .qdev.vmsd    = &vmstate_ppce500_pci,
+static void e500_pcihost_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = e500_pcihost_initfn;
+    dc->vmsd = &vmstate_ppce500_pci;
+}
+
+static TypeInfo e500_pcihost_info = {
+    .name          = "e500-pcihost",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(PPCE500PCIState),
+    .class_init    = e500_pcihost_class_init,
 };
 
 static void e500_pci_register(void)
 {
-    sysbus_register_withprop(&e500_pcihost_info);
-    pci_qdev_register(&e500_host_bridge_info);
+    type_register_static(&e500_pcihost_info);
+    type_register_static(&e500_host_bridge_info);
 }
 device_init(e500_pci_register);
diff --git a/hw/ppce500_spin.c b/hw/ppce500_spin.c
index e7b1453855..9d648ec90a 100644
--- a/hw/ppce500_spin.c
+++ b/hw/ppce500_spin.c
@@ -203,14 +203,22 @@ static int ppce500_spin_initfn(SysBusDevice *dev)
     return 0;
 }
 
-static SysBusDeviceInfo ppce500_spin_info = {
-    .init         = ppce500_spin_initfn,
-    .qdev.name    = "e500-spin",
-    .qdev.size    = sizeof(SpinState),
+static void ppce500_spin_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = ppce500_spin_initfn;
+}
+
+static TypeInfo ppce500_spin_info = {
+    .name          = "e500-spin",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(SpinState),
+    .class_init    = ppce500_spin_class_init,
 };
 
 static void ppce500_spin_register(void)
 {
-    sysbus_register_withprop(&ppce500_spin_info);
+    type_register_static(&ppce500_spin_info);
 }
 device_init(ppce500_spin_register);
diff --git a/hw/prep_pci.c b/hw/prep_pci.c
index ea9fb6902c..40b8bb0edd 100644
--- a/hw/prep_pci.c
+++ b/hw/prep_pci.c
@@ -25,9 +25,16 @@
 #include "hw.h"
 #include "pci.h"
 #include "pci_host.h"
-#include "prep_pci.h"
+#include "exec-memory.h"
 
-typedef PCIHostState PREPPCIState;
+typedef struct PRePPCIState {
+    PCIHostState host_state;
+    qemu_irq irq[4];
+} PREPPCIState;
+
+typedef struct RavenPCIState {
+    PCIDevice dev;
+} RavenPCIState;
 
 static inline uint32_t PPC_PCIIO_config(target_phys_addr_t addr)
 {
@@ -40,58 +47,24 @@ static inline uint32_t PPC_PCIIO_config(target_phys_addr_t addr)
     return (addr & 0x7ff) |  (i << 11);
 }
 
-static void PPC_PCIIO_writeb (void *opaque, target_phys_addr_t addr, uint32_t val)
-{
-    PREPPCIState *s = opaque;
-    pci_data_write(s->bus, PPC_PCIIO_config(addr), val, 1);
-}
-
-static void PPC_PCIIO_writew (void *opaque, target_phys_addr_t addr, uint32_t val)
-{
-    PREPPCIState *s = opaque;
-    val = bswap16(val);
-    pci_data_write(s->bus, PPC_PCIIO_config(addr), val, 2);
-}
-
-static void PPC_PCIIO_writel (void *opaque, target_phys_addr_t addr, uint32_t val)
+static void ppc_pci_io_write(void *opaque, target_phys_addr_t addr,
+                             uint64_t val, unsigned int size)
 {
     PREPPCIState *s = opaque;
-    val = bswap32(val);
-    pci_data_write(s->bus, PPC_PCIIO_config(addr), val, 4);
+    pci_data_write(s->host_state.bus, PPC_PCIIO_config(addr), val, size);
 }
 
-static uint32_t PPC_PCIIO_readb (void *opaque, target_phys_addr_t addr)
+static uint64_t ppc_pci_io_read(void *opaque, target_phys_addr_t addr,
+                                unsigned int size)
 {
     PREPPCIState *s = opaque;
-    uint32_t val;
-    val = pci_data_read(s->bus, PPC_PCIIO_config(addr), 1);
-    return val;
-}
-
-static uint32_t PPC_PCIIO_readw (void *opaque, target_phys_addr_t addr)
-{
-    PREPPCIState *s = opaque;
-    uint32_t val;
-    val = pci_data_read(s->bus, PPC_PCIIO_config(addr), 2);
-    val = bswap16(val);
-    return val;
-}
-
-static uint32_t PPC_PCIIO_readl (void *opaque, target_phys_addr_t addr)
-{
-    PREPPCIState *s = opaque;
-    uint32_t val;
-    val = pci_data_read(s->bus, PPC_PCIIO_config(addr), 4);
-    val = bswap32(val);
-    return val;
+    return pci_data_read(s->host_state.bus, PPC_PCIIO_config(addr), size);
 }
 
 static const MemoryRegionOps PPC_PCIIO_ops = {
-    .old_mmio = {
-        .read = { PPC_PCIIO_readb, PPC_PCIIO_readw, PPC_PCIIO_readl, },
-        .write = { PPC_PCIIO_writeb, PPC_PCIIO_writew, PPC_PCIIO_writel, },
-    },
-    .endianness = DEVICE_NATIVE_ENDIAN,
+    .read = ppc_pci_io_read,
+    .write = ppc_pci_io_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
 };
 
 static int prep_map_irq(PCIDevice *pci_dev, int irq_num)
@@ -103,46 +76,107 @@ static void prep_set_irq(void *opaque, int irq_num, int level)
 {
     qemu_irq *pic = opaque;
 
-    qemu_set_irq(pic[(irq_num & 1) ? 11 : 9] , level);
+    qemu_set_irq(pic[irq_num] , level);
 }
 
-PCIBus *pci_prep_init(qemu_irq *pic,
-                      MemoryRegion *address_space_mem,
-                      MemoryRegion *address_space_io)
+static int raven_pcihost_init(SysBusDevice *dev)
 {
-    PREPPCIState *s;
-    PCIDevice *d;
+    PCIHostState *h = FROM_SYSBUS(PCIHostState, dev);
+    PREPPCIState *s = DO_UPCAST(PREPPCIState, host_state, h);
+    MemoryRegion *address_space_mem = get_system_memory();
+    MemoryRegion *address_space_io = get_system_io();
+    PCIBus *bus;
+    int i;
+
+    for (i = 0; i < 4; i++) {
+        sysbus_init_irq(dev, &s->irq[i]);
+    }
 
-    s = g_malloc0(sizeof(PREPPCIState));
-    s->bus = pci_register_bus(NULL, "pci",
-                              prep_set_irq, prep_map_irq, pic,
-                              address_space_mem,
-                              address_space_io,
-                              0, 4);
+    bus = pci_register_bus(&h->busdev.qdev, NULL,
+                           prep_set_irq, prep_map_irq, s->irq,
+                           address_space_mem, address_space_io, 0, 4);
+    h->bus = bus;
 
-    memory_region_init_io(&s->conf_mem, &pci_host_conf_be_ops, s,
+    memory_region_init_io(&h->conf_mem, &pci_host_conf_be_ops, s,
                           "pci-conf-idx", 1);
-    memory_region_add_subregion(address_space_io, 0xcf8, &s->conf_mem);
-    sysbus_init_ioports(&s->busdev, 0xcf8, 1);
+    sysbus_add_io(dev, 0xcf8, &h->conf_mem);
+    sysbus_init_ioports(&h->busdev, 0xcf8, 1);
 
-    memory_region_init_io(&s->data_mem, &pci_host_data_be_ops, s,
+    memory_region_init_io(&h->data_mem, &pci_host_data_be_ops, s,
                           "pci-conf-data", 1);
-    memory_region_add_subregion(address_space_io, 0xcfc, &s->data_mem);
-    sysbus_init_ioports(&s->busdev, 0xcfc, 1);
-
-    memory_region_init_io(&s->mmcfg, &PPC_PCIIO_ops, s, "pciio", 0x00400000);
-    memory_region_add_subregion(address_space_mem, 0x80800000, &s->mmcfg);
-
-    /* PCI host bridge */
-    d = pci_register_device(s->bus, "PREP Host Bridge - Motorola Raven",
-                            sizeof(PCIDevice), 0, NULL, NULL);
-    pci_config_set_vendor_id(d->config, PCI_VENDOR_ID_MOTOROLA);
-    pci_config_set_device_id(d->config, PCI_DEVICE_ID_MOTOROLA_RAVEN);
-    d->config[0x08] = 0x00; // revision
-    pci_config_set_class(d->config, PCI_CLASS_BRIDGE_HOST);
+    sysbus_add_io(dev, 0xcfc, &h->data_mem);
+    sysbus_init_ioports(&h->busdev, 0xcfc, 1);
+
+    memory_region_init_io(&h->mmcfg, &PPC_PCIIO_ops, s, "pciio", 0x00400000);
+    memory_region_add_subregion(address_space_mem, 0x80800000, &h->mmcfg);
+
+    pci_create_simple(bus, 0, "raven");
+
+    return 0;
+}
+
+static int raven_init(PCIDevice *d)
+{
     d->config[0x0C] = 0x08; // cache_line_size
     d->config[0x0D] = 0x10; // latency_timer
     d->config[0x34] = 0x00; // capabilities_pointer
 
-    return s->bus;
+    return 0;
+}
+
+static const VMStateDescription vmstate_raven = {
+    .name = "raven",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .fields = (VMStateField[]) {
+        VMSTATE_PCI_DEVICE(dev, RavenPCIState),
+        VMSTATE_END_OF_LIST()
+    },
+};
+
+static void raven_class_init(ObjectClass *klass, void *data)
+{
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    k->init = raven_init;
+    k->vendor_id = PCI_VENDOR_ID_MOTOROLA;
+    k->device_id = PCI_DEVICE_ID_MOTOROLA_RAVEN;
+    k->revision = 0x00;
+    k->class_id = PCI_CLASS_BRIDGE_HOST;
+    dc->desc = "PReP Host Bridge - Motorola Raven";
+    dc->vmsd = &vmstate_raven;
+    dc->no_user = 1;
+}
+
+static TypeInfo raven_info = {
+    .name = "raven",
+    .parent = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(RavenPCIState),
+    .class_init = raven_class_init,
+};
+
+static void raven_pcihost_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    k->init = raven_pcihost_init;
+    dc->fw_name = "pci";
+    dc->no_user = 1;
 }
+
+static TypeInfo raven_pcihost_info = {
+    .name = "raven-pcihost",
+    .parent = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(PREPPCIState),
+    .class_init = raven_pcihost_class_init,
+};
+
+static void raven_register_devices(void)
+{
+    type_register_static(&raven_pcihost_info);
+    type_register_static(&raven_info);
+}
+
+device_init(raven_register_devices)
diff --git a/hw/prep_pci.h b/hw/prep_pci.h
deleted file mode 100644
index b6b481a517..0000000000
--- a/hw/prep_pci.h
+++ /dev/null
@@ -1,11 +0,0 @@
-#ifndef QEMU_PREP_PCI_H
-#define QEMU_PREP_PCI_H
-
-#include "qemu-common.h"
-#include "memory.h"
-
-PCIBus *pci_prep_init(qemu_irq *pic,
-                      MemoryRegion *address_space_mem,
-                      MemoryRegion *address_space_io);
-
-#endif
diff --git a/hw/pxa2xx.c b/hw/pxa2xx.c
index 6ddd5005de..244c614510 100644
--- a/hw/pxa2xx.c
+++ b/hw/pxa2xx.c
@@ -1233,17 +1233,26 @@ static const VMStateDescription vmstate_pxa2xx_rtc_regs = {
     },
 };
 
-static SysBusDeviceInfo pxa2xx_rtc_sysbus_info = {
-    .init       = pxa2xx_rtc_init,
-    .qdev.name  = "pxa2xx_rtc",
-    .qdev.desc  = "PXA2xx RTC Controller",
-    .qdev.size  = sizeof(PXA2xxRTCState),
-    .qdev.vmsd  = &vmstate_pxa2xx_rtc_regs,
+static void pxa2xx_rtc_sysbus_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = pxa2xx_rtc_init;
+    dc->desc = "PXA2xx RTC Controller";
+    dc->vmsd = &vmstate_pxa2xx_rtc_regs;
+}
+
+static TypeInfo pxa2xx_rtc_sysbus_info = {
+    .name          = "pxa2xx_rtc",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(PXA2xxRTCState),
+    .class_init    = pxa2xx_rtc_sysbus_class_init,
 };
 
 /* I2C Interface */
 typedef struct {
-    i2c_slave i2c;
+    I2CSlave i2c;
     PXA2xxI2CState *host;
 } PXA2xxI2CSlaveState;
 
@@ -1279,7 +1288,7 @@ static void pxa2xx_i2c_update(PXA2xxI2CState *s)
 }
 
 /* These are only stubs now.  */
-static void pxa2xx_i2c_event(i2c_slave *i2c, enum i2c_event event)
+static void pxa2xx_i2c_event(I2CSlave *i2c, enum i2c_event event)
 {
     PXA2xxI2CSlaveState *slave = FROM_I2C_SLAVE(PXA2xxI2CSlaveState, i2c);
     PXA2xxI2CState *s = slave->host;
@@ -1303,7 +1312,7 @@ static void pxa2xx_i2c_event(i2c_slave *i2c, enum i2c_event event)
     pxa2xx_i2c_update(s);
 }
 
-static int pxa2xx_i2c_rx(i2c_slave *i2c)
+static int pxa2xx_i2c_rx(I2CSlave *i2c)
 {
     PXA2xxI2CSlaveState *slave = FROM_I2C_SLAVE(PXA2xxI2CSlaveState, i2c);
     PXA2xxI2CState *s = slave->host;
@@ -1318,7 +1327,7 @@ static int pxa2xx_i2c_rx(i2c_slave *i2c)
     return s->data;
 }
 
-static int pxa2xx_i2c_tx(i2c_slave *i2c, uint8_t data)
+static int pxa2xx_i2c_tx(I2CSlave *i2c, uint8_t data)
 {
     PXA2xxI2CSlaveState *slave = FROM_I2C_SLAVE(PXA2xxI2CSlaveState, i2c);
     PXA2xxI2CState *s = slave->host;
@@ -1466,19 +1475,27 @@ static const VMStateDescription vmstate_pxa2xx_i2c = {
     }
 };
 
-static int pxa2xx_i2c_slave_init(i2c_slave *i2c)
+static int pxa2xx_i2c_slave_init(I2CSlave *i2c)
 {
     /* Nothing to do.  */
     return 0;
 }
 
-static I2CSlaveInfo pxa2xx_i2c_slave_info = {
-    .qdev.name = "pxa2xx-i2c-slave",
-    .qdev.size = sizeof(PXA2xxI2CSlaveState),
-    .init = pxa2xx_i2c_slave_init,
-    .event = pxa2xx_i2c_event,
-    .recv = pxa2xx_i2c_rx,
-    .send = pxa2xx_i2c_tx
+static void pxa2xx_i2c_slave_class_init(ObjectClass *klass, void *data)
+{
+    I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
+
+    k->init = pxa2xx_i2c_slave_init;
+    k->event = pxa2xx_i2c_event;
+    k->recv = pxa2xx_i2c_rx;
+    k->send = pxa2xx_i2c_tx;
+}
+
+static TypeInfo pxa2xx_i2c_slave_info = {
+    .name          = "pxa2xx-i2c-slave",
+    .parent        = TYPE_I2C_SLAVE,
+    .instance_size = sizeof(PXA2xxI2CSlaveState),
+    .class_init    = pxa2xx_i2c_slave_class_init,
 };
 
 PXA2xxI2CState *pxa2xx_i2c_init(target_phys_addr_t base,
@@ -1526,17 +1543,28 @@ i2c_bus *pxa2xx_i2c_bus(PXA2xxI2CState *s)
     return s->bus;
 }
 
-static SysBusDeviceInfo pxa2xx_i2c_info = {
-    .init       = pxa2xx_i2c_initfn,
-    .qdev.name  = "pxa2xx_i2c",
-    .qdev.desc  = "PXA2xx I2C Bus Controller",
-    .qdev.size  = sizeof(PXA2xxI2CState),
-    .qdev.vmsd  = &vmstate_pxa2xx_i2c,
-    .qdev.props = (Property[]) {
-        DEFINE_PROP_UINT32("size", PXA2xxI2CState, region_size, 0x10000),
-        DEFINE_PROP_UINT32("offset", PXA2xxI2CState, offset, 0),
-        DEFINE_PROP_END_OF_LIST(),
-    },
+static Property pxa2xx_i2c_properties[] = {
+    DEFINE_PROP_UINT32("size", PXA2xxI2CState, region_size, 0x10000),
+    DEFINE_PROP_UINT32("offset", PXA2xxI2CState, offset, 0),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void pxa2xx_i2c_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = pxa2xx_i2c_initfn;
+    dc->desc = "PXA2xx I2C Bus Controller";
+    dc->vmsd = &vmstate_pxa2xx_i2c;
+    dc->props = pxa2xx_i2c_properties;
+}
+
+static TypeInfo pxa2xx_i2c_info = {
+    .name          = "pxa2xx_i2c",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(PXA2xxI2CState),
+    .class_init    = pxa2xx_i2c_class_init,
 };
 
 /* PXA Inter-IC Sound Controller */
@@ -2288,12 +2316,26 @@ PXA2xxState *pxa255_init(MemoryRegion *address_space, unsigned int sdram_size)
     return s;
 }
 
+static void pxa2xx_ssp_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+
+    sdc->init = pxa2xx_ssp_init;
+}
+
+static TypeInfo pxa2xx_ssp_info = {
+    .name          = "pxa2xx-ssp",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(PXA2xxSSPState),
+    .class_init    = pxa2xx_ssp_class_init,
+};
+
 static void pxa2xx_register_devices(void)
 {
-    i2c_register_slave(&pxa2xx_i2c_slave_info);
-    sysbus_register_dev("pxa2xx-ssp", sizeof(PXA2xxSSPState), pxa2xx_ssp_init);
-    sysbus_register_withprop(&pxa2xx_i2c_info);
-    sysbus_register_withprop(&pxa2xx_rtc_sysbus_info);
+    type_register_static(&pxa2xx_i2c_slave_info);
+    type_register_static(&pxa2xx_ssp_info);
+    type_register_static(&pxa2xx_i2c_info);
+    type_register_static(&pxa2xx_rtc_sysbus_info);
 }
 
 device_init(pxa2xx_register_devices)
diff --git a/hw/pxa2xx_dma.c b/hw/pxa2xx_dma.c
index cb281071f0..2d61565f1d 100644
--- a/hw/pxa2xx_dma.c
+++ b/hw/pxa2xx_dma.c
@@ -543,20 +543,31 @@ static VMStateDescription vmstate_pxa2xx_dma = {
     },
 };
 
-static SysBusDeviceInfo pxa2xx_dma_info = {
-    .init       = pxa2xx_dma_init,
-    .qdev.name  = "pxa2xx-dma",
-    .qdev.desc  = "PXA2xx DMA controller",
-    .qdev.size  = sizeof(PXA2xxDMAState),
-    .qdev.vmsd  = &vmstate_pxa2xx_dma,
-    .qdev.props = (Property[]) {
-        DEFINE_PROP_INT32("channels", PXA2xxDMAState, channels, -1),
-        DEFINE_PROP_END_OF_LIST(),
-    },
+static Property pxa2xx_dma_properties[] = {
+    DEFINE_PROP_INT32("channels", PXA2xxDMAState, channels, -1),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void pxa2xx_dma_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = pxa2xx_dma_init;
+    dc->desc = "PXA2xx DMA controller";
+    dc->vmsd = &vmstate_pxa2xx_dma;
+    dc->props = pxa2xx_dma_properties;
+}
+
+static TypeInfo pxa2xx_dma_info = {
+    .name          = "pxa2xx-dma",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(PXA2xxDMAState),
+    .class_init    = pxa2xx_dma_class_init,
 };
 
 static void pxa2xx_dma_register(void)
 {
-    sysbus_register_withprop(&pxa2xx_dma_info);
+    type_register_static(&pxa2xx_dma_info);
 }
 device_init(pxa2xx_dma_register);
diff --git a/hw/pxa2xx_gpio.c b/hw/pxa2xx_gpio.c
index cc58c40914..67fd17c4ca 100644
--- a/hw/pxa2xx_gpio.c
+++ b/hw/pxa2xx_gpio.c
@@ -317,20 +317,31 @@ static const VMStateDescription vmstate_pxa2xx_gpio_regs = {
     },
 };
 
-static SysBusDeviceInfo pxa2xx_gpio_info = {
-    .init       = pxa2xx_gpio_initfn,
-    .qdev.name  = "pxa2xx-gpio",
-    .qdev.desc  = "PXA2xx GPIO controller",
-    .qdev.size  = sizeof(PXA2xxGPIOInfo),
-    .qdev.props = (Property []) {
-        DEFINE_PROP_INT32("lines", PXA2xxGPIOInfo, lines, 0),
-        DEFINE_PROP_INT32("ncpu", PXA2xxGPIOInfo, ncpu, 0),
-        DEFINE_PROP_END_OF_LIST(),
-    }
+static Property pxa2xx_gpio_properties[] = {
+    DEFINE_PROP_INT32("lines", PXA2xxGPIOInfo, lines, 0),
+    DEFINE_PROP_INT32("ncpu", PXA2xxGPIOInfo, ncpu, 0),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void pxa2xx_gpio_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = pxa2xx_gpio_initfn;
+    dc->desc = "PXA2xx GPIO controller";
+    dc->props = pxa2xx_gpio_properties;
+}
+
+static TypeInfo pxa2xx_gpio_info = {
+    .name          = "pxa2xx-gpio",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(PXA2xxGPIOInfo),
+    .class_init    = pxa2xx_gpio_class_init,
 };
 
 static void pxa2xx_gpio_register(void)
 {
-    sysbus_register_withprop(&pxa2xx_gpio_info);
+    type_register_static(&pxa2xx_gpio_info);
 }
 device_init(pxa2xx_gpio_register);
diff --git a/hw/pxa2xx_pic.c b/hw/pxa2xx_pic.c
index 92effbc806..ca85743aea 100644
--- a/hw/pxa2xx_pic.c
+++ b/hw/pxa2xx_pic.c
@@ -296,16 +296,25 @@ static int pxa2xx_pic_initfn(SysBusDevice *dev)
     return 0;
 }
 
-static SysBusDeviceInfo pxa2xx_pic_info = {
-    .init       = pxa2xx_pic_initfn,
-    .qdev.name  = "pxa2xx_pic",
-    .qdev.desc  = "PXA2xx PIC",
-    .qdev.size  = sizeof(PXA2xxPICState),
-    .qdev.vmsd  = &vmstate_pxa2xx_pic_regs,
+static void pxa2xx_pic_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = pxa2xx_pic_initfn;
+    dc->desc = "PXA2xx PIC";
+    dc->vmsd = &vmstate_pxa2xx_pic_regs;
+}
+
+static TypeInfo pxa2xx_pic_info = {
+    .name          = "pxa2xx_pic",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(PXA2xxPICState),
+    .class_init    = pxa2xx_pic_class_init,
 };
 
 static void pxa2xx_pic_register(void)
 {
-    sysbus_register_withprop(&pxa2xx_pic_info);
+    type_register_static(&pxa2xx_pic_info);
 }
 device_init(pxa2xx_pic_register);
diff --git a/hw/pxa2xx_timer.c b/hw/pxa2xx_timer.c
index 50e26789d2..90800751b1 100644
--- a/hw/pxa2xx_timer.c
+++ b/hw/pxa2xx_timer.c
@@ -477,37 +477,59 @@ static const VMStateDescription vmstate_pxa2xx_timer_regs = {
     }
 };
 
-static SysBusDeviceInfo pxa25x_timer_dev_info = {
-    .init       = pxa2xx_timer_init,
-    .qdev.name  = "pxa25x-timer",
-    .qdev.desc  = "PXA25x timer",
-    .qdev.size  = sizeof(PXA2xxTimerInfo),
-    .qdev.vmsd  = &vmstate_pxa2xx_timer_regs,
-    .qdev.props = (Property[]) {
-        DEFINE_PROP_UINT32("freq", PXA2xxTimerInfo, freq, PXA25X_FREQ),
-        DEFINE_PROP_BIT("tm4", PXA2xxTimerInfo, flags,
-                        PXA2XX_TIMER_HAVE_TM4, false),
-        DEFINE_PROP_END_OF_LIST(),
-    },
+static Property pxa25x_timer_dev_properties[] = {
+    DEFINE_PROP_UINT32("freq", PXA2xxTimerInfo, freq, PXA25X_FREQ),
+    DEFINE_PROP_BIT("tm4", PXA2xxTimerInfo, flags,
+    PXA2XX_TIMER_HAVE_TM4, false),
+    DEFINE_PROP_END_OF_LIST(),
 };
 
-static SysBusDeviceInfo pxa27x_timer_dev_info = {
-    .init       = pxa2xx_timer_init,
-    .qdev.name  = "pxa27x-timer",
-    .qdev.desc  = "PXA27x timer",
-    .qdev.size  = sizeof(PXA2xxTimerInfo),
-    .qdev.vmsd  = &vmstate_pxa2xx_timer_regs,
-    .qdev.props = (Property[]) {
-        DEFINE_PROP_UINT32("freq", PXA2xxTimerInfo, freq, PXA27X_FREQ),
-        DEFINE_PROP_BIT("tm4", PXA2xxTimerInfo, flags,
-                        PXA2XX_TIMER_HAVE_TM4, true),
-        DEFINE_PROP_END_OF_LIST(),
-    },
+static void pxa25x_timer_dev_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = pxa2xx_timer_init;
+    dc->desc = "PXA25x timer";
+    dc->vmsd = &vmstate_pxa2xx_timer_regs;
+    dc->props = pxa25x_timer_dev_properties;
+}
+
+static TypeInfo pxa25x_timer_dev_info = {
+    .name          = "pxa25x-timer",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(PXA2xxTimerInfo),
+    .class_init    = pxa25x_timer_dev_class_init,
+};
+
+static Property pxa27x_timer_dev_properties[] = {
+    DEFINE_PROP_UINT32("freq", PXA2xxTimerInfo, freq, PXA27X_FREQ),
+    DEFINE_PROP_BIT("tm4", PXA2xxTimerInfo, flags,
+    PXA2XX_TIMER_HAVE_TM4, true),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void pxa27x_timer_dev_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = pxa2xx_timer_init;
+    dc->desc = "PXA27x timer";
+    dc->vmsd = &vmstate_pxa2xx_timer_regs;
+    dc->props = pxa27x_timer_dev_properties;
+}
+
+static TypeInfo pxa27x_timer_dev_info = {
+    .name          = "pxa27x-timer",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(PXA2xxTimerInfo),
+    .class_init    = pxa27x_timer_dev_class_init,
 };
 
 static void pxa2xx_timer_register(void)
 {
-    sysbus_register_withprop(&pxa25x_timer_dev_info);
-    sysbus_register_withprop(&pxa27x_timer_dev_info);
+    type_register_static(&pxa25x_timer_dev_info);
+    type_register_static(&pxa27x_timer_dev_info);
 };
 device_init(pxa2xx_timer_register);
diff --git a/hw/qdev-addr.c b/hw/qdev-addr.c
index 5ddda2d0f4..5976dcdf47 100644
--- a/hw/qdev-addr.c
+++ b/hw/qdev-addr.c
@@ -18,9 +18,10 @@ static int print_taddr(DeviceState *dev, Property *prop, char *dest, size_t len)
     return snprintf(dest, len, "0x" TARGET_FMT_plx, *ptr);
 }
 
-static void get_taddr(DeviceState *dev, Visitor *v, void *opaque,
+static void get_taddr(Object *obj, Visitor *v, void *opaque,
                       const char *name, Error **errp)
 {
+    DeviceState *dev = DEVICE(obj);
     Property *prop = opaque;
     target_phys_addr_t *ptr = qdev_get_prop_ptr(dev, prop);
     int64_t value;
@@ -29,9 +30,10 @@ static void get_taddr(DeviceState *dev, Visitor *v, void *opaque,
     visit_type_int(v, &value, name, errp);
 }
 
-static void set_taddr(DeviceState *dev, Visitor *v, void *opaque,
+static void set_taddr(Object *obj, Visitor *v, void *opaque,
                       const char *name, Error **errp)
 {
+    DeviceState *dev = DEVICE(obj);
     Property *prop = opaque;
     target_phys_addr_t *ptr = qdev_get_prop_ptr(dev, prop);
     Error *local_err = NULL;
diff --git a/hw/qdev-monitor.c b/hw/qdev-monitor.c
new file mode 100644
index 0000000000..135c2bf237
--- /dev/null
+++ b/hw/qdev-monitor.c
@@ -0,0 +1,588 @@
+/*
+ *  Dynamic device configuration and creation.
+ *
+ *  Copyright (c) 2009 CodeSourcery
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qdev.h"
+#include "monitor.h"
+
+/*
+ * Aliases were a bad idea from the start.  Let's keep them
+ * from spreading further.
+ */
+typedef struct QDevAlias
+{
+    const char *typename;
+    const char *alias;
+} QDevAlias;
+
+static const QDevAlias qdev_alias_table[] = {
+    { "virtio-blk-pci", "virtio-blk" },
+    { "virtio-net-pci", "virtio-net" },
+    { "virtio-serial-pci", "virtio-serial" },
+    { "virtio-balloon-pci", "virtio-balloon" },
+    { "virtio-blk-s390", "virtio-blk" },
+    { "virtio-net-s390", "virtio-net" },
+    { "virtio-serial-s390", "virtio-serial" },
+    { "lsi53c895a", "lsi" },
+    { "ich9-ahci", "ahci" },
+    { }
+};
+
+static const char *qdev_class_get_alias(DeviceClass *dc)
+{
+    const char *typename = object_class_get_name(OBJECT_CLASS(dc));
+    int i;
+
+    for (i = 0; qdev_alias_table[i].typename; i++) {
+        if (strcmp(qdev_alias_table[i].typename, typename) == 0) {
+            return qdev_alias_table[i].alias;
+        }
+    }
+
+    return NULL;
+}
+
+static bool qdev_class_has_alias(DeviceClass *dc)
+{
+    return (qdev_class_get_alias(dc) != NULL);
+}
+
+static void qdev_print_devinfo(ObjectClass *klass, void *opaque)
+{
+    DeviceClass *dc;
+    bool *show_no_user = opaque;
+
+    dc = (DeviceClass *)object_class_dynamic_cast(klass, TYPE_DEVICE);
+
+    if (!dc || (show_no_user && !*show_no_user && dc->no_user)) {
+        return;
+    }
+
+    error_printf("name \"%s\"", object_class_get_name(klass));
+    if (dc->bus_info) {
+        error_printf(", bus %s", dc->bus_info->name);
+    }
+    if (qdev_class_has_alias(dc)) {
+        error_printf(", alias \"%s\"", qdev_class_get_alias(dc));
+    }
+    if (dc->desc) {
+        error_printf(", desc \"%s\"", dc->desc);
+    }
+    if (dc->no_user) {
+        error_printf(", no-user");
+    }
+    error_printf("\n");
+}
+
+static int set_property(const char *name, const char *value, void *opaque)
+{
+    DeviceState *dev = opaque;
+
+    if (strcmp(name, "driver") == 0)
+        return 0;
+    if (strcmp(name, "bus") == 0)
+        return 0;
+
+    if (qdev_prop_parse(dev, name, value) == -1) {
+        return -1;
+    }
+    return 0;
+}
+
+static const char *find_typename_by_alias(const char *alias)
+{
+    int i;
+
+    for (i = 0; qdev_alias_table[i].alias; i++) {
+        if (strcmp(qdev_alias_table[i].alias, alias) == 0) {
+            return qdev_alias_table[i].typename;
+        }
+    }
+
+    return NULL;
+}
+
+int qdev_device_help(QemuOpts *opts)
+{
+    const char *driver;
+    Property *prop;
+    ObjectClass *klass;
+    DeviceClass *info;
+
+    driver = qemu_opt_get(opts, "driver");
+    if (driver && !strcmp(driver, "?")) {
+        bool show_no_user = false;
+        object_class_foreach(qdev_print_devinfo, TYPE_DEVICE, false, &show_no_user);
+        return 1;
+    }
+
+    if (!driver || !qemu_opt_get(opts, "?")) {
+        return 0;
+    }
+
+    klass = object_class_by_name(driver);
+    if (!klass) {
+        const char *typename = find_typename_by_alias(driver);
+
+        if (typename) {
+            driver = typename;
+            klass = object_class_by_name(driver);
+        }
+    }
+
+    if (!klass) {
+        return 0;
+    }
+    info = DEVICE_CLASS(klass);
+
+    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", driver, prop->name,
+                     prop->info->legacy_name ?: prop->info->name);
+    }
+    if (info->bus_info) {
+        for (prop = info->bus_info->props; prop && prop->name; prop++) {
+            if (!prop->info->parse) {
+                continue;           /* no way to set it, don't show */
+            }
+            error_printf("%s.%s=%s\n", driver, prop->name,
+                         prop->info->legacy_name ?: prop->info->name);
+        }
+    }
+    return 1;
+}
+
+static Object *qdev_get_peripheral(void)
+{
+    static Object *dev;
+
+    if (dev == NULL) {
+        dev = object_new("container");
+        object_property_add_child(object_get_root(), "peripheral",
+                                  OBJECT(dev), NULL);
+    }
+
+    return dev;
+}
+
+static Object *qdev_get_peripheral_anon(void)
+{
+    static Object *dev;
+
+    if (dev == NULL) {
+        dev = object_new("container");
+        object_property_add_child(object_get_root(), "peripheral-anon",
+                                  OBJECT(dev), NULL);
+    }
+
+    return dev;
+}
+
+static void qbus_list_bus(DeviceState *dev)
+{
+    BusState *child;
+    const char *sep = " ";
+
+    error_printf("child busses at \"%s\":",
+                 dev->id ? dev->id : object_get_typename(OBJECT(dev)));
+    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);
+    QTAILQ_FOREACH(dev, &bus->children, sibling) {
+        error_printf("%s\"%s\"", sep, object_get_typename(OBJECT(dev)));
+        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
+     */
+    QTAILQ_FOREACH(dev, &bus->children, sibling) {
+        if (dev->id  &&  strcmp(dev->id, elem) == 0) {
+            return dev;
+        }
+    }
+    QTAILQ_FOREACH(dev, &bus->children, sibling) {
+        if (strcmp(object_get_typename(OBJECT(dev)), elem) == 0) {
+            return dev;
+        }
+    }
+    QTAILQ_FOREACH(dev, &bus->children, sibling) {
+        DeviceClass *dc = DEVICE_GET_CLASS(dev);
+
+        if (qdev_class_has_alias(dc) &&
+            strcmp(qdev_class_get_alias(dc), elem) == 0) {
+            return dev;
+        }
+    }
+    return NULL;
+}
+
+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;
+    }
+
+    QTAILQ_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;
+}
+
+static BusState *qbus_find(const char *path)
+{
+    DeviceState *dev;
+    BusState *bus;
+    char elem[128];
+    int pos, len;
+
+    /* find start element */
+    if (path[0] == '/') {
+        bus = sysbus_get_default();
+        pos = 0;
+    } else {
+        if (sscanf(path, "%127[^/]%n", elem, &len) != 1) {
+            assert(!path[0]);
+            elem[0] = len = 0;
+        }
+        bus = qbus_find_recursive(sysbus_get_default(), 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;
+        }
+    }
+}
+
+DeviceState *qdev_device_add(QemuOpts *opts)
+{
+    ObjectClass *obj;
+    DeviceClass *k;
+    const char *driver, *path, *id;
+    DeviceState *qdev;
+    BusState *bus;
+
+    driver = qemu_opt_get(opts, "driver");
+    if (!driver) {
+        qerror_report(QERR_MISSING_PARAMETER, "driver");
+        return NULL;
+    }
+
+    /* find driver */
+    obj = object_class_by_name(driver);
+    if (!obj) {
+        const char *typename = find_typename_by_alias(driver);
+
+        if (typename) {
+            driver = typename;
+            obj = object_class_by_name(driver);
+        }
+    }
+
+    if (!obj) {
+        qerror_report(QERR_INVALID_PARAMETER_VALUE, "driver", "device type");
+        return NULL;
+    }
+
+    k = DEVICE_CLASS(obj);
+
+    /* find bus */
+    path = qemu_opt_get(opts, "bus");
+    if (path != NULL) {
+        bus = qbus_find(path);
+        if (!bus) {
+            return NULL;
+        }
+        if (bus->info != k->bus_info) {
+            qerror_report(QERR_BAD_BUS_FOR_DEVICE,
+                           driver, bus->info->name);
+            return NULL;
+        }
+    } else {
+        bus = qbus_find_recursive(sysbus_get_default(), NULL, k->bus_info);
+        if (!bus) {
+            qerror_report(QERR_NO_BUS_FOR_DEVICE,
+                          driver, k->bus_info->name);
+            return NULL;
+        }
+    }
+    if (qdev_hotplug && !bus->allow_hotplug) {
+        qerror_report(QERR_BUS_NO_HOTPLUG, bus->name);
+        return NULL;
+    }
+
+    if (!bus) {
+        bus = sysbus_get_default();
+    }
+
+    /* create device, set properties */
+    qdev = DEVICE(object_new(driver));
+    qdev_set_parent_bus(qdev, bus);
+    qdev_prop_set_globals(qdev);
+
+    id = qemu_opts_id(opts);
+    if (id) {
+        qdev->id = id;
+        object_property_add_child(qdev_get_peripheral(), qdev->id,
+                                  OBJECT(qdev), NULL);
+    } else {
+        static int anon_count;
+        gchar *name = g_strdup_printf("device[%d]", anon_count++);
+        object_property_add_child(qdev_get_peripheral_anon(), name,
+                                  OBJECT(qdev), NULL);
+        g_free(name);
+    }        
+    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;
+}
+
+
+#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)
+{
+    char buf[64];
+
+    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);
+        }
+        props++;
+    }
+}
+
+static void qdev_print(Monitor *mon, DeviceState *dev, int indent)
+{
+    BusState *child;
+    qdev_printf("dev: %s, id \"%s\"\n", object_get_typename(OBJECT(dev)),
+                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, qdev_get_props(dev), "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);
+    }
+}
+
+static void qbus_print(Monitor *mon, BusState *bus, int indent)
+{
+    struct DeviceState *dev;
+
+    qdev_printf("bus: %s\n", bus->name);
+    indent += 2;
+    qdev_printf("type %s\n", bus->info->name);
+    QTAILQ_FOREACH(dev, &bus->children, sibling) {
+        qdev_print(mon, dev, indent);
+    }
+}
+#undef qdev_printf
+
+void do_info_qtree(Monitor *mon)
+{
+    if (sysbus_get_default())
+        qbus_print(mon, sysbus_get_default(), 0);
+}
+
+void do_info_qdm(Monitor *mon)
+{
+    object_class_foreach(qdev_print_devinfo, TYPE_DEVICE, false, NULL);
+}
+
+int do_device_add(Monitor *mon, const QDict *qdict, QObject **ret_data)
+{
+    QemuOpts *opts;
+
+    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 (!qdev_device_add(opts)) {
+        qemu_opts_del(opts);
+        return -1;
+    }
+    return 0;
+}
+
+int do_device_del(Monitor *mon, const QDict *qdict, QObject **ret_data)
+{
+    const char *id = qdict_get_str(qdict, "id");
+    DeviceState *dev;
+
+    dev = qdev_find_recursive(sysbus_get_default(), id);
+    if (NULL == dev) {
+        qerror_report(QERR_DEVICE_NOT_FOUND, id);
+        return -1;
+    }
+    return qdev_unplug(dev);
+}
+
+void qdev_machine_init(void)
+{
+    qdev_get_peripheral_anon();
+    qdev_get_peripheral();
+}
diff --git a/hw/qdev-properties.c b/hw/qdev-properties.c
index 02f0dae0bc..c4583a14d7 100644
--- a/hw/qdev-properties.c
+++ b/hw/qdev-properties.c
@@ -40,9 +40,9 @@ static void qdev_prop_cpy(DeviceState *dev, Property *props, void *src)
 /* Bit */
 static int parse_bit(DeviceState *dev, Property *prop, const char *str)
 {
-    if (!strncasecmp(str, "on", 2))
+    if (!strcasecmp(str, "on"))
         bit_prop_set(dev, prop, true);
-    else if (!strncasecmp(str, "off", 3))
+    else if (!strcasecmp(str, "off"))
         bit_prop_set(dev, prop, false);
     else
         return -EINVAL;
@@ -55,9 +55,10 @@ static int print_bit(DeviceState *dev, Property *prop, char *dest, size_t len)
     return snprintf(dest, len, (*p & qdev_get_prop_mask(prop)) ? "on" : "off");
 }
 
-static void get_bit(DeviceState *dev, Visitor *v, void *opaque,
+static void get_bit(Object *obj, Visitor *v, void *opaque,
                     const char *name, Error **errp)
 {
+    DeviceState *dev = DEVICE(obj);
     Property *prop = opaque;
     uint32_t *p = qdev_get_prop_ptr(dev, prop);
     bool value = (*p & qdev_get_prop_mask(prop)) != 0;
@@ -65,9 +66,10 @@ static void get_bit(DeviceState *dev, Visitor *v, void *opaque,
     visit_type_bool(v, &value, name, errp);
 }
 
-static void set_bit(DeviceState *dev, Visitor *v, void *opaque,
+static void set_bit(Object *obj, Visitor *v, void *opaque,
                     const char *name, Error **errp)
 {
+    DeviceState *dev = DEVICE(obj);
     Property *prop = opaque;
     Error *local_err = NULL;
     bool value;
@@ -118,9 +120,10 @@ static int print_uint8(DeviceState *dev, Property *prop, char *dest, size_t len)
     return snprintf(dest, len, "%" PRIu8, *ptr);
 }
 
-static void get_int8(DeviceState *dev, Visitor *v, void *opaque,
+static void get_int8(Object *obj, Visitor *v, void *opaque,
                      const char *name, Error **errp)
 {
+    DeviceState *dev = DEVICE(obj);
     Property *prop = opaque;
     int8_t *ptr = qdev_get_prop_ptr(dev, prop);
     int64_t value;
@@ -129,9 +132,10 @@ static void get_int8(DeviceState *dev, Visitor *v, void *opaque,
     visit_type_int(v, &value, name, errp);
 }
 
-static void set_int8(DeviceState *dev, Visitor *v, void *opaque,
-                      const char *name, Error **errp)
+static void set_int8(Object *obj, Visitor *v, void *opaque,
+                     const char *name, Error **errp)
 {
+    DeviceState *dev = DEVICE(obj);
     Property *prop = opaque;
     int8_t *ptr = qdev_get_prop_ptr(dev, prop);
     Error *local_err = NULL;
@@ -224,9 +228,10 @@ static int print_uint16(DeviceState *dev, Property *prop, char *dest, size_t len
     return snprintf(dest, len, "%" PRIu16, *ptr);
 }
 
-static void get_int16(DeviceState *dev, Visitor *v, void *opaque,
+static void get_int16(Object *obj, Visitor *v, void *opaque,
                       const char *name, Error **errp)
 {
+    DeviceState *dev = DEVICE(obj);
     Property *prop = opaque;
     int16_t *ptr = qdev_get_prop_ptr(dev, prop);
     int64_t value;
@@ -235,9 +240,10 @@ static void get_int16(DeviceState *dev, Visitor *v, void *opaque,
     visit_type_int(v, &value, name, errp);
 }
 
-static void set_int16(DeviceState *dev, Visitor *v, void *opaque,
+static void set_int16(Object *obj, Visitor *v, void *opaque,
                       const char *name, Error **errp)
 {
+    DeviceState *dev = DEVICE(obj);
     Property *prop = opaque;
     int16_t *ptr = qdev_get_prop_ptr(dev, prop);
     Error *local_err = NULL;
@@ -296,9 +302,10 @@ static int print_uint32(DeviceState *dev, Property *prop, char *dest, size_t len
     return snprintf(dest, len, "%" PRIu32, *ptr);
 }
 
-static void get_int32(DeviceState *dev, Visitor *v, void *opaque,
+static void get_int32(Object *obj, Visitor *v, void *opaque,
                       const char *name, Error **errp)
 {
+    DeviceState *dev = DEVICE(obj);
     Property *prop = opaque;
     int32_t *ptr = qdev_get_prop_ptr(dev, prop);
     int64_t value;
@@ -307,9 +314,10 @@ static void get_int32(DeviceState *dev, Visitor *v, void *opaque,
     visit_type_int(v, &value, name, errp);
 }
 
-static void set_int32(DeviceState *dev, Visitor *v, void *opaque,
+static void set_int32(Object *obj, Visitor *v, void *opaque,
                       const char *name, Error **errp)
 {
+    DeviceState *dev = DEVICE(obj);
     Property *prop = opaque;
     int32_t *ptr = qdev_get_prop_ptr(dev, prop);
     Error *local_err = NULL;
@@ -433,18 +441,20 @@ static int print_uint64(DeviceState *dev, Property *prop, char *dest, size_t len
     return snprintf(dest, len, "%" PRIu64, *ptr);
 }
 
-static void get_int64(DeviceState *dev, Visitor *v, void *opaque,
+static void get_int64(Object *obj, Visitor *v, void *opaque,
                       const char *name, Error **errp)
 {
+    DeviceState *dev = DEVICE(obj);
     Property *prop = opaque;
     int64_t *ptr = qdev_get_prop_ptr(dev, prop);
 
     visit_type_int(v, ptr, name, errp);
 }
 
-static void set_int64(DeviceState *dev, Visitor *v, void *opaque,
+static void set_int64(Object *obj, Visitor *v, void *opaque,
                       const char *name, Error **errp)
 {
+    DeviceState *dev = DEVICE(obj);
     Property *prop = opaque;
     int64_t *ptr = qdev_get_prop_ptr(dev, prop);
 
@@ -523,9 +533,10 @@ static int print_string(DeviceState *dev, Property *prop, char *dest, size_t len
     return snprintf(dest, len, "\"%s\"", *ptr);
 }
 
-static void get_string(DeviceState *dev, Visitor *v, void *opaque,
+static void get_string(Object *obj, Visitor *v, void *opaque,
                        const char *name, Error **errp)
 {
+    DeviceState *dev = DEVICE(obj);
     Property *prop = opaque;
     char **ptr = qdev_get_prop_ptr(dev, prop);
 
@@ -537,9 +548,10 @@ static void get_string(DeviceState *dev, Visitor *v, void *opaque,
     }
 }
 
-static void set_string(DeviceState *dev, Visitor *v, void *opaque,
+static void set_string(Object *obj, Visitor *v, void *opaque,
                        const char *name, Error **errp)
 {
+    DeviceState *dev = DEVICE(obj);
     Property *prop = opaque;
     char **ptr = qdev_get_prop_ptr(dev, prop);
     Error *local_err = NULL;
@@ -609,9 +621,10 @@ static int print_drive(DeviceState *dev, Property *prop, char *dest, size_t len)
                     *ptr ? bdrv_get_device_name(*ptr) : "<null>");
 }
 
-static void get_generic(DeviceState *dev, Visitor *v, void *opaque,
+static void get_generic(Object *obj, Visitor *v, void *opaque,
                        const char *name, Error **errp)
 {
+    DeviceState *dev = DEVICE(obj);
     Property *prop = opaque;
     void **ptr = qdev_get_prop_ptr(dev, prop);
     char buffer[1024];
@@ -624,9 +637,10 @@ static void get_generic(DeviceState *dev, Visitor *v, void *opaque,
     visit_type_str(v, &p, name, errp);
 }
 
-static void set_generic(DeviceState *dev, Visitor *v, void *opaque,
+static void set_generic(Object *obj, Visitor *v, void *opaque,
                         const char *name, Error **errp)
 {
+    DeviceState *dev = DEVICE(obj);
     Property *prop = opaque;
     Error *local_err = NULL;
     char *str;
@@ -774,9 +788,10 @@ static int print_vlan(DeviceState *dev, Property *prop, char *dest, size_t len)
     }
 }
 
-static void get_vlan(DeviceState *dev, Visitor *v, void *opaque,
+static void get_vlan(Object *obj, Visitor *v, void *opaque,
                      const char *name, Error **errp)
 {
+    DeviceState *dev = DEVICE(obj);
     Property *prop = opaque;
     VLANState **ptr = qdev_get_prop_ptr(dev, prop);
     int64_t id;
@@ -785,9 +800,10 @@ static void get_vlan(DeviceState *dev, Visitor *v, void *opaque,
     visit_type_int(v, &id, name, errp);
 }
 
-static void set_vlan(DeviceState *dev, Visitor *v, void *opaque,
+static void set_vlan(Object *obj, Visitor *v, void *opaque,
                      const char *name, Error **errp)
 {
+    DeviceState *dev = DEVICE(obj);
     Property *prop = opaque;
     VLANState **ptr = qdev_get_prop_ptr(dev, prop);
     Error *local_err = NULL;
@@ -885,6 +901,55 @@ PropertyInfo qdev_prop_macaddr = {
     .set   = set_generic,
 };
 
+
+/* --- lost tick policy --- */
+
+static const struct {
+    const char *name;
+    LostTickPolicy code;
+} lost_tick_policy_table[] = {
+    { .name = "discard", .code = LOST_TICK_DISCARD },
+    { .name = "delay", .code = LOST_TICK_DELAY },
+    { .name = "merge", .code = LOST_TICK_MERGE },
+    { .name = "slew", .code = LOST_TICK_SLEW },
+};
+
+static int parse_lost_tick_policy(DeviceState *dev, Property *prop,
+                                  const char *str)
+{
+    LostTickPolicy *ptr = qdev_get_prop_ptr(dev, prop);
+    int i;
+
+    for (i = 0; i < ARRAY_SIZE(lost_tick_policy_table); i++) {
+        if (!strcasecmp(str, lost_tick_policy_table[i].name)) {
+            *ptr = lost_tick_policy_table[i].code;
+            break;
+        }
+    }
+    if (i == ARRAY_SIZE(lost_tick_policy_table)) {
+        return -EINVAL;
+    }
+    return 0;
+}
+
+static int print_lost_tick_policy(DeviceState *dev, Property *prop, char *dest,
+                                  size_t len)
+{
+    LostTickPolicy *ptr = qdev_get_prop_ptr(dev, prop);
+
+    return snprintf(dest, len, "%s", lost_tick_policy_table[*ptr].name);
+}
+
+PropertyInfo qdev_prop_losttickpolicy = {
+    .name  = "lost_tick_policy",
+    .type  = PROP_TYPE_LOSTTICKPOLICY,
+    .size  = sizeof(LostTickPolicy),
+    .parse = parse_lost_tick_policy,
+    .print = print_lost_tick_policy,
+    .get   = get_generic,
+    .set   = set_generic,
+};
+
 /* --- pci address --- */
 
 /*
@@ -922,9 +987,10 @@ static int print_pci_devfn(DeviceState *dev, Property *prop, char *dest, size_t
     }
 }
 
-static void get_pci_devfn(DeviceState *dev, Visitor *v, void *opaque,
+static void get_pci_devfn(Object *obj, Visitor *v, void *opaque,
                           const char *name, Error **errp)
 {
+    DeviceState *dev = DEVICE(obj);
     Property *prop = opaque;
     uint32_t *ptr = qdev_get_prop_ptr(dev, prop);
     char buffer[32];
@@ -966,7 +1032,7 @@ static Property *qdev_prop_find(DeviceState *dev, const char *name)
     Property *prop;
 
     /* device properties */
-    prop = qdev_prop_walk(dev->info->props, name);
+    prop = qdev_prop_walk(qdev_get_props(dev), name);
     if (prop)
         return prop;
 
@@ -989,16 +1055,16 @@ void error_set_from_qdev_prop_error(Error **errp, int ret, DeviceState *dev,
     switch (ret) {
     case -EEXIST:
         error_set(errp, QERR_PROPERTY_VALUE_IN_USE,
-                  dev->info->name, prop->name, value);
+                  object_get_typename(OBJECT(dev)), prop->name, value);
         break;
     default:
     case -EINVAL:
         error_set(errp, QERR_PROPERTY_VALUE_BAD,
-                  dev->info->name, prop->name, value);
+                  object_get_typename(OBJECT(dev)), prop->name, value);
         break;
     case -ENOENT:
         error_set(errp, QERR_PROPERTY_VALUE_NOT_FOUND,
-                  dev->info->name, prop->name, value);
+                  object_get_typename(OBJECT(dev)), prop->name, value);
         break;
     case 0:
         break;
@@ -1018,7 +1084,7 @@ int qdev_prop_parse(DeviceState *dev, const char *name, const char *value)
      * removed along with it.
      */
     if (!prop || !prop->info->parse) {
-        qerror_report(QERR_PROPERTY_NOT_FOUND, dev->info->name, name);
+        qerror_report(QERR_PROPERTY_NOT_FOUND, object_get_typename(OBJECT(dev)), name);
         return -1;
     }
     ret = prop->info->parse(dev, prop, value);
@@ -1039,12 +1105,12 @@ void qdev_prop_set(DeviceState *dev, const char *name, void *src, enum PropertyT
     prop = qdev_prop_find(dev, name);
     if (!prop) {
         fprintf(stderr, "%s: property \"%s.%s\" not found\n",
-                __FUNCTION__, dev->info->name, name);
+                __FUNCTION__, object_get_typename(OBJECT(dev)), name);
         abort();
     }
     if (prop->info->type != type) {
         fprintf(stderr, "%s: property \"%s.%s\" type mismatch\n",
-                __FUNCTION__, dev->info->name, name);
+                __FUNCTION__, object_get_typename(OBJECT(dev)), name);
         abort();
     }
     qdev_prop_cpy(dev, prop, src);
@@ -1093,7 +1159,7 @@ int qdev_prop_set_drive(DeviceState *dev, const char *name, BlockDriverState *va
     if (res < 0) {
         error_report("Can't attach drive %s to %s.%s: %s",
                      bdrv_get_device_name(value),
-                     dev->id ? dev->id : dev->info->name,
+                     dev->id ? dev->id : object_get_typename(OBJECT(dev)),
                      name, strerror(-res));
         return -1;
     }
@@ -1127,6 +1193,12 @@ void qdev_prop_set_macaddr(DeviceState *dev, const char *name, uint8_t *value)
     qdev_prop_set(dev, name, value, PROP_TYPE_MACADDR);
 }
 
+void qdev_prop_set_losttickpolicy(DeviceState *dev, const char *name,
+                                  LostTickPolicy *value)
+{
+    qdev_prop_set(dev, name, value, PROP_TYPE_LOSTTICKPOLICY);
+}
+
 void qdev_prop_set_ptr(DeviceState *dev, const char *name, void *value)
 {
     qdev_prop_set(dev, name, &value, PROP_TYPE_PTR);
@@ -1165,8 +1237,8 @@ void qdev_prop_set_globals(DeviceState *dev)
     GlobalProperty *prop;
 
     QTAILQ_FOREACH(prop, &global_props, next) {
-        if (strcmp(dev->info->name, prop->driver) != 0 &&
-            strcmp(dev->info->bus_info->name, prop->driver) != 0) {
+        if (strcmp(object_get_typename(OBJECT(dev)), prop->driver) != 0 &&
+            strcmp(qdev_get_bus_info(dev)->name, prop->driver) != 0) {
             continue;
         }
         if (qdev_prop_parse(dev, prop->property, prop->value) != 0) {
diff --git a/hw/qdev.c b/hw/qdev.c
index e59f3455d7..e3b53b7f62 100644
--- a/hw/qdev.c
+++ b/hw/qdev.c
@@ -28,9 +28,8 @@
 #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;
 
@@ -38,86 +37,60 @@ static bool qdev_hot_removed = false;
 static BusState *main_system_bus;
 static void main_system_bus_create(void);
 
-DeviceInfo *device_info_list;
-
-static BusState *qbus_find_recursive(BusState *bus, const char *name,
-                                     const BusInfo *info);
-static BusState *qbus_find(const char *path);
-
 /* Register a new device type.  */
-void qdev_register(DeviceInfo *info)
+const VMStateDescription *qdev_get_vmsd(DeviceState *dev)
+{
+    DeviceClass *dc = DEVICE_GET_CLASS(dev);
+    return dc->vmsd;
+}
+
+BusInfo *qdev_get_bus_info(DeviceState *dev)
 {
-    assert(info->size >= sizeof(DeviceState));
-    assert(!info->next);
+    DeviceClass *dc = DEVICE_GET_CLASS(dev);
+    return dc->bus_info;
+}
 
-    info->next = device_info_list;
-    device_info_list = info;
+Property *qdev_get_props(DeviceState *dev)
+{
+    DeviceClass *dc = DEVICE_GET_CLASS(dev);
+    return dc->props;
 }
 
-static DeviceInfo *qdev_find_info(BusInfo *bus_info, const char *name)
+const char *qdev_fw_name(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;
-    }
+    DeviceClass *dc = DEVICE_GET_CLASS(dev);
 
-    /* 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;
+    if (dc->fw_name) {
+        return dc->fw_name;
     }
-    return NULL;
+
+    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);
 
-static DeviceState *qdev_create_from_info(BusState *bus, DeviceInfo *info)
+void qdev_set_parent_bus(DeviceState *dev, BusState *bus)
 {
-    DeviceState *dev;
     Property *prop;
 
-    assert(bus->info == info->bus_info);
-    dev = g_malloc0(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);
-    QTAILQ_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;
-    QTAILQ_INIT(&dev->properties);
-    dev->state = DEV_STATE_CREATED;
 
-    for (prop = dev->info->props; prop && prop->name; prop++) {
-        qdev_property_add_legacy(dev, prop, NULL);
-        qdev_property_add_static(dev, prop, NULL);
-    }
+    dev->parent_bus = bus;
+    QTAILQ_INSERT_HEAD(&bus->children, dev, sibling);
 
-    for (prop = dev->info->bus_info->props; prop && prop->name; prop++) {
+    qdev_prop_set_defaults(dev, dev->parent_bus->info->props);
+    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_property_add_str(dev, "type", qdev_get_type, NULL, NULL);
-
-    return dev;
 }
 
 /* Create a new device.  This only initializes the device state structure
@@ -142,197 +115,23 @@ DeviceState *qdev_create(BusState *bus, const char *name)
 
 DeviceState *qdev_try_create(BusState *bus, const char *name)
 {
-    DeviceInfo *info;
-
-    if (!bus) {
-        bus = sysbus_get_default();
-    }
+    DeviceState *dev;
 
-    info = qdev_find_info(bus->info, name);
-    if (!info) {
+    dev = DEVICE(object_new(name));
+    if (!dev) {
         return NULL;
     }
 
-    return qdev_create_from_info(bus, info);
-}
-
-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 int set_property(const char *name, const char *value, void *opaque)
-{
-    DeviceState *dev = opaque;
-
-    if (strcmp(name, "driver") == 0)
-        return 0;
-    if (strcmp(name, "bus") == 0)
-        return 0;
-
-    if (qdev_prop_parse(dev, name, value) == -1) {
-        return -1;
-    }
-    return 0;
-}
-
-int qdev_device_help(QemuOpts *opts)
-{
-    const char *driver;
-    DeviceInfo *info;
-    Property *prop;
-
-    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);
-        }
-        return 1;
-    }
-
-    if (!driver || !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->legacy_name ?: prop->info->name);
-    }
-    for (prop = info->bus_info->props; prop && prop->name; prop++) {
-        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->legacy_name ?: prop->info->name);
-    }
-    return 1;
-}
-
-static DeviceState *qdev_get_peripheral(void)
-{
-    static DeviceState *dev;
-
-    if (dev == NULL) {
-        dev = qdev_create(NULL, "container");
-        qdev_property_add_child(qdev_get_root(), "peripheral", dev, NULL);
-        qdev_init_nofail(dev);
+    if (!bus) {
+        bus = sysbus_get_default();
     }
 
-    return dev;
-}
-
-static DeviceState *qdev_get_peripheral_anon(void)
-{
-    static DeviceState *dev;
-
-    if (dev == NULL) {
-        dev = qdev_create(NULL, "container");
-        qdev_property_add_child(qdev_get_root(), "peripheral-anon", dev, NULL);
-        qdev_init_nofail(dev);
-    }
+    qdev_set_parent_bus(dev, bus);
+    qdev_prop_set_globals(dev);
 
     return dev;
 }
 
-DeviceState *qdev_device_add(QemuOpts *opts)
-{
-    const char *driver, *path, *id;
-    DeviceInfo *info;
-    DeviceState *qdev;
-    BusState *bus;
-
-    driver = qemu_opt_get(opts, "driver");
-    if (!driver) {
-        qerror_report(QERR_MISSING_PARAMETER, "driver");
-        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;
-    }
-
-    /* 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;
-    }
-
-    /* create device, set properties */
-    qdev = qdev_create_from_info(bus, info);
-    id = qemu_opts_id(opts);
-    if (id) {
-        qdev->id = id;
-        qdev_property_add_child(qdev_get_peripheral(), qdev->id, qdev, NULL);
-    } else {
-        static int anon_count;
-        gchar *name = g_strdup_printf("device[%d]", anon_count++);
-        qdev_property_add_child(qdev_get_peripheral_anon(), name,
-                                qdev, NULL);
-        g_free(name);
-    }        
-    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;
-}
-
 /* Initialize a device.  Device properties should be set before calling
    this function.  IRQs and MMIO regions should be connected/mapped after
    calling this function.
@@ -340,22 +139,24 @@ 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 && dev->info->reset) {
-        dev->info->reset(dev);
+    if (dev->hotplugged) {
+        device_reset(dev);
     }
     return 0;
 }
@@ -370,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;
 }
@@ -421,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;
 }
@@ -435,87 +237,17 @@ 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", info->name);
+        error_report("Initialization of device %s failed",
+                     object_get_typename(OBJECT(dev)));
         exit(1);
     }
 }
 
-static void qdev_property_del_all(DeviceState *dev)
-{
-    while (!QTAILQ_EMPTY(&dev->properties)) {
-        DeviceProperty *prop = QTAILQ_FIRST(&dev->properties);
-
-        QTAILQ_REMOVE(&dev->properties, prop, node);
-
-        if (prop->release) {
-            prop->release(dev, prop->name, prop->opaque);
-        }
-
-        g_free(prop->name);
-        g_free(prop->type);
-        g_free(prop);
-    }
-}
-
-static void qdev_property_del_child(DeviceState *dev, DeviceState *child, Error **errp)
-{
-    DeviceProperty *prop;
-
-    QTAILQ_FOREACH(prop, &dev->properties, node) {
-        if (strstart(prop->type, "child<", NULL) && prop->opaque == child) {
-            break;
-        }
-    }
-
-    g_assert(prop != NULL);
-
-    QTAILQ_REMOVE(&dev->properties, prop, node);
-
-    if (prop->release) {
-        prop->release(dev, prop->name, prop->opaque);
-    }
-
-    g_free(prop->name);
-    g_free(prop->type);
-    g_free(prop);
-}
-
 /* Unlink device from bus and free the structure.  */
 void qdev_free(DeviceState *dev)
 {
-    BusState *bus;
-    Property *prop;
-
-    qdev_property_del_all(dev);
-
-    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);
-    }
-    QTAILQ_REMOVE(&dev->parent_bus->children, dev, sibling);
-    for (prop = dev->info->props; prop && prop->name; prop++) {
-        if (prop->info->free) {
-            prop->info->free(dev, prop);
-        }
-    }
-    if (dev->parent) {
-        qdev_property_del_child(dev->parent, dev, NULL);
-    }
-    if (dev->ref != 0) {
-        qerror_report(QERR_DEVICE_IN_USE, dev->id?:"");
-    }
-    g_free(dev);
+    object_delete(OBJECT(dev));
 }
 
 void qdev_machine_creation_done(void)
@@ -532,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;
@@ -644,34 +367,6 @@ 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;
-    }
-
-    QTAILQ_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;
@@ -690,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);
-    QTAILQ_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
-     */
-    QTAILQ_FOREACH(dev, &bus->children, sibling) {
-        if (dev->id  &&  strcmp(dev->id, elem) == 0) {
-            return dev;
-        }
-    }
-    QTAILQ_FOREACH(dev, &bus->children, sibling) {
-        if (strcmp(dev->info->name, elem) == 0) {
-            return dev;
-        }
-    }
-    QTAILQ_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)
 {
@@ -926,112 +465,6 @@ void qbus_free(BusState *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)
-{
-    char buf[64];
-
-    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);
-        }
-        props++;
-    }
-}
-
-static void qdev_print(Monitor *mon, DeviceState *dev, int indent)
-{
-    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);
-    }
-}
-
-static void qbus_print(Monitor *mon, BusState *bus, int indent)
-{
-    struct DeviceState *dev;
-
-    qdev_printf("bus: %s\n", bus->name);
-    indent += 2;
-    qdev_printf("type %s\n", bus->info->name);
-    QTAILQ_FOREACH(dev, &bus->children, sibling) {
-        qdev_print(mon, dev, indent);
-    }
-}
-#undef qdev_printf
-
-void do_info_qtree(Monitor *mon)
-{
-    if (main_system_bus)
-        qbus_print(mon, main_system_bus, 0);
-}
-
-void do_info_qdm(Monitor *mon)
-{
-    DeviceInfo *info;
-
-    for (info = device_info_list; info != NULL; info = info->next) {
-        qdev_print_devinfo(info);
-    }
-}
-
-int do_device_add(Monitor *mon, const QDict *qdict, QObject **ret_data)
-{
-    QemuOpts *opts;
-
-    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 (!qdev_device_add(opts)) {
-        qemu_opts_del(opts);
-        return -1;
-    }
-    return 0;
-}
-
-int do_device_del(Monitor *mon, const QDict *qdict, QObject **ret_data)
-{
-    const char *id = qdict_get_str(qdict, "id");
-    DeviceState *dev;
-
-    dev = qdev_find_recursive(main_system_bus, id);
-    if (NULL == dev) {
-        qerror_report(QERR_DEVICE_NOT_FOUND, id);
-        return -1;
-    }
-    return qdev_unplug(dev);
-}
-
 static int qdev_get_fw_dev_path_helper(DeviceState *dev, char *p, int size)
 {
     int l = 0;
@@ -1044,7 +477,7 @@ static int qdev_get_fw_dev_path_helper(DeviceState *dev, char *p, int size)
             l += snprintf(p + l, size - l, "%s", d);
             g_free(d);
         } else {
-            l += snprintf(p + l, size - l, "%s", dev->info->name);
+            l += snprintf(p + l, size - l, "%s", object_get_typename(OBJECT(dev)));
         }
     }
     l += snprintf(p + l , size - l, "/");
@@ -1064,106 +497,19 @@ char* qdev_get_fw_dev_path(DeviceState *dev)
     return strdup(path);
 }
 
-char *qdev_get_type(DeviceState *dev, Error **errp)
+static char *qdev_get_type(Object *obj, Error **errp)
 {
-    return g_strdup(dev->info->name);
-}
-
-void qdev_ref(DeviceState *dev)
-{
-    dev->ref++;
-}
-
-void qdev_unref(DeviceState *dev)
-{
-    g_assert(dev->ref > 0);
-    dev->ref--;
-}
-
-void qdev_property_add(DeviceState *dev, const char *name, const char *type,
-                       DevicePropertyAccessor *get, DevicePropertyAccessor *set,
-                       DevicePropertyRelease *release,
-                       void *opaque, Error **errp)
-{
-    DeviceProperty *prop = g_malloc0(sizeof(*prop));
-
-    prop->name = g_strdup(name);
-    prop->type = g_strdup(type);
-
-    prop->get = get;
-    prop->set = set;
-    prop->release = release;
-    prop->opaque = opaque;
-
-    QTAILQ_INSERT_TAIL(&dev->properties, prop, node);
-}
-
-static DeviceProperty *qdev_property_find(DeviceState *dev, const char *name)
-{
-    DeviceProperty *prop;
-
-    QTAILQ_FOREACH(prop, &dev->properties, node) {
-        if (strcmp(prop->name, name) == 0) {
-            return prop;
-        }
-    }
-
-    return NULL;
-}
-
-void qdev_property_get(DeviceState *dev, Visitor *v, const char *name,
-                       Error **errp)
-{
-    DeviceProperty *prop = qdev_property_find(dev, name);
-
-    if (prop == NULL) {
-        error_set(errp, QERR_PROPERTY_NOT_FOUND, dev->id?:"", name);
-        return;
-    }
-
-    if (!prop->get) {
-        error_set(errp, QERR_PERMISSION_DENIED);
-    } else {
-        prop->get(dev, v, prop->opaque, name, errp);
-    }
-}
-
-void qdev_property_set(DeviceState *dev, Visitor *v, const char *name,
-                       Error **errp)
-{
-    DeviceProperty *prop = qdev_property_find(dev, name);
-
-    if (prop == NULL) {
-        error_set(errp, QERR_PROPERTY_NOT_FOUND, dev->id?:"", name);
-        return;
-    }
-
-    if (!prop->set) {
-        error_set(errp, QERR_PERMISSION_DENIED);
-    } else {
-        prop->set(dev, v, prop->opaque, name, errp);
-    }
-}
-
-const char *qdev_property_get_type(DeviceState *dev, const char *name, Error **errp)
-{
-    DeviceProperty *prop = qdev_property_find(dev, name);
-
-    if (prop == NULL) {
-        error_set(errp, QERR_PROPERTY_NOT_FOUND, dev->id?:"", name);
-        return NULL;
-    }
-
-    return prop->type;
+    return g_strdup(object_get_typename(obj));
 }
 
 /**
  * Legacy property handling
  */
 
-static void qdev_get_legacy_property(DeviceState *dev, Visitor *v, void *opaque,
+static void qdev_get_legacy_property(Object *obj, Visitor *v, void *opaque,
                                      const char *name, Error **errp)
 {
+    DeviceState *dev = DEVICE(obj);
     Property *prop = opaque;
 
     char buffer[1024];
@@ -1173,9 +519,10 @@ static void qdev_get_legacy_property(DeviceState *dev, Visitor *v, void *opaque,
     visit_type_str(v, &ptr, name, errp);
 }
 
-static void qdev_set_legacy_property(DeviceState *dev, Visitor *v, void *opaque,
+static void qdev_set_legacy_property(Object *obj, Visitor *v, void *opaque,
                                      const char *name, Error **errp)
 {
+    DeviceState *dev = DEVICE(obj);
     Property *prop = opaque;
     Error *local_err = NULL;
     char *ptr = NULL;
@@ -1215,11 +562,11 @@ void qdev_property_add_legacy(DeviceState *dev, Property *prop,
     type = g_strdup_printf("legacy<%s>",
                            prop->info->legacy_name ?: prop->info->name);
 
-    qdev_property_add(dev, name, type,
-                      prop->info->print ? qdev_get_legacy_property : NULL,
-                      prop->info->parse ? qdev_set_legacy_property : NULL,
-                      NULL,
-                      prop, errp);
+    object_property_add(OBJECT(dev), name, type,
+                        prop->info->print ? qdev_get_legacy_property : NULL,
+                        prop->info->parse ? qdev_set_legacy_property : NULL,
+                        NULL,
+                        prop, errp);
 
     g_free(type);
     g_free(name);
@@ -1234,337 +581,87 @@ void qdev_property_add_legacy(DeviceState *dev, Property *prop,
 void qdev_property_add_static(DeviceState *dev, Property *prop,
                               Error **errp)
 {
-    qdev_property_add(dev, prop->name, prop->info->name,
-                      prop->info->get, prop->info->set,
-                      NULL,
-                      prop, errp);
-}
-
-DeviceState *qdev_get_root(void)
-{
-    static DeviceState *qdev_root;
-
-    if (!qdev_root) {
-        qdev_root = qdev_create(NULL, "container");
-        qdev_init_nofail(qdev_root);
-    }
-
-    return qdev_root;
-}
-
-static void qdev_get_child_property(DeviceState *dev, Visitor *v, void *opaque,
-                                    const char *name, Error **errp)
-{
-    DeviceState *child = opaque;
-    gchar *path;
-
-    path = qdev_get_canonical_path(child);
-    visit_type_str(v, &path, name, errp);
-    g_free(path);
+    object_property_add(OBJECT(dev), prop->name, prop->info->name,
+                        prop->info->get, prop->info->set,
+                        NULL,
+                        prop, errp);
 }
 
-static void qdev_release_child_property(DeviceState *dev, const char *name,
-                                        void *opaque)
+static void device_initfn(Object *obj)
 {
-    DeviceState *child = opaque;
-
-    qdev_unref(child);
-}
-
-void qdev_property_add_child(DeviceState *dev, const char *name,
-                             DeviceState *child, Error **errp)
-{
-    gchar *type;
-
-    type = g_strdup_printf("child<%s>", child->info->name);
-
-    qdev_property_add(dev, name, type, qdev_get_child_property,
-                      NULL, qdev_release_child_property,
-                      child, errp);
-
-    qdev_ref(child);
-    g_assert(child->parent == NULL);
-    child->parent = dev;
-
-    g_free(type);
-}
-
-static void qdev_get_link_property(DeviceState *dev, Visitor *v, void *opaque,
-                                   const char *name, Error **errp)
-{
-    DeviceState **child = opaque;
-    gchar *path;
-
-    if (*child) {
-        path = qdev_get_canonical_path(*child);
-        visit_type_str(v, &path, name, errp);
-        g_free(path);
-    } else {
-        path = (gchar *)"";
-        visit_type_str(v, &path, name, errp);
-    }
-}
-
-static void qdev_set_link_property(DeviceState *dev, Visitor *v, void *opaque,
-                                   const char *name, Error **errp)
-{
-    DeviceState **child = opaque;
-    bool ambiguous = false;
-    const char *type;
-    char *path;
-
-    type = qdev_property_get_type(dev, name, NULL);
-
-    visit_type_str(v, &path, name, errp);
-
-    if (*child) {
-        qdev_unref(*child);
-    }
-
-    if (strcmp(path, "") != 0) {
-        DeviceState *target;
-
-        target = qdev_resolve_path(path, &ambiguous);
-        if (target) {
-            gchar *target_type;
-
-            target_type = g_strdup_printf("link<%s>", target->info->name);
-            if (strcmp(target_type, type) == 0) {
-                *child = target;
-                qdev_ref(target);
-            } else {
-                error_set(errp, QERR_INVALID_PARAMETER_TYPE, name, type);
-            }
+    DeviceState *dev = DEVICE(obj);
+    Property *prop;
 
-            g_free(target_type);
-        } else {
-            error_set(errp, QERR_DEVICE_NOT_FOUND, path);
-        }
-    } else {
-        *child = NULL;
+    if (qdev_hotplug) {
+        dev->hotplugged = 1;
+        qdev_hot_added = true;
     }
 
-    g_free(path);
-}
-
-void qdev_property_add_link(DeviceState *dev, const char *name,
-                            const char *type, DeviceState **child,
-                            Error **errp)
-{
-    gchar *full_type;
-
-    full_type = g_strdup_printf("link<%s>", type);
-
-    qdev_property_add(dev, name, full_type,
-                      qdev_get_link_property,
-                      qdev_set_link_property,
-                      NULL, child, errp);
-
-    g_free(full_type);
-}
-
-gchar *qdev_get_canonical_path(DeviceState *dev)
-{
-    DeviceState *root = qdev_get_root();
-    char *newpath = NULL, *path = NULL;
-
-    while (dev != root) {
-        DeviceProperty *prop = NULL;
-
-        g_assert(dev->parent != NULL);
-
-        QTAILQ_FOREACH(prop, &dev->parent->properties, node) {
-            if (!strstart(prop->type, "child<", NULL)) {
-                continue;
-            }
-
-            if (prop->opaque == dev) {
-                if (path) {
-                    newpath = g_strdup_printf("%s/%s", prop->name, path);
-                    g_free(path);
-                    path = newpath;
-                } else {
-                    path = g_strdup(prop->name);
-                }
-                break;
-            }
-        }
-
-        g_assert(prop != NULL);
+    dev->instance_id_alias = -1;
+    dev->state = DEV_STATE_CREATED;
 
-        dev = dev->parent;
+    qdev_prop_set_defaults(dev, qdev_get_props(dev));
+    for (prop = qdev_get_props(dev); prop && prop->name; prop++) {
+        qdev_property_add_legacy(dev, prop, NULL);
+        qdev_property_add_static(dev, prop, NULL);
     }
 
-    newpath = g_strdup_printf("/%s", path);
-    g_free(path);
-
-    return newpath;
+    object_property_add_str(OBJECT(dev), "type", qdev_get_type, NULL, NULL);
 }
 
-static DeviceState *qdev_resolve_abs_path(DeviceState *parent,
-                                          gchar **parts,
-                                          int index)
+/* Unlink device from bus and free the structure.  */
+static void device_finalize(Object *obj)
 {
-    DeviceProperty *prop;
-    DeviceState *child;
-
-    if (parts[index] == NULL) {
-        return parent;
-    }
-
-    if (strcmp(parts[index], "") == 0) {
-        return qdev_resolve_abs_path(parent, parts, index + 1);
-    }
-
-    prop = qdev_property_find(parent, parts[index]);
-    if (prop == NULL) {
-        return NULL;
-    }
+    DeviceState *dev = DEVICE(obj);
+    BusState *bus;
+    Property *prop;
+    DeviceClass *dc = DEVICE_GET_CLASS(dev);
 
-    child = NULL;
-    if (strstart(prop->type, "link<", NULL)) {
-        DeviceState **pchild = prop->opaque;
-        if (*pchild) {
-            child = *pchild;
+    if (dev->state == DEV_STATE_INITIALIZED) {
+        while (dev->num_child_bus) {
+            bus = QLIST_FIRST(&dev->child_bus);
+            qbus_free(bus);
         }
-    } else if (strstart(prop->type, "child<", NULL)) {
-        child = prop->opaque;
-    }
-
-    if (!child) {
-        return NULL;
-    }
-
-    return qdev_resolve_abs_path(child, parts, index + 1);
-}
-
-static DeviceState *qdev_resolve_partial_path(DeviceState *parent,
-                                              gchar **parts,
-                                              bool *ambiguous)
-{
-    DeviceState *dev;
-    DeviceProperty *prop;
-
-    dev = qdev_resolve_abs_path(parent, parts, 0);
-
-    QTAILQ_FOREACH(prop, &parent->properties, node) {
-        DeviceState *found;
-
-        if (!strstart(prop->type, "child<", NULL)) {
-            continue;
+        if (qdev_get_vmsd(dev)) {
+            vmstate_unregister(dev, qdev_get_vmsd(dev), dev);
         }
-
-        found = qdev_resolve_partial_path(prop->opaque, parts, ambiguous);
-        if (found) {
-            if (dev) {
-                if (ambiguous) {
-                    *ambiguous = true;
-                }
-                return NULL;
-            }
-            dev = found;
+        if (dc->exit) {
+            dc->exit(dev);
         }
-
-        if (ambiguous && *ambiguous) {
-            return NULL;
+        if (dev->opts) {
+            qemu_opts_del(dev->opts);
         }
     }
-
-    return dev;
-}
-
-DeviceState *qdev_resolve_path(const char *path, bool *ambiguous)
-{
-    bool partial_path = true;
-    DeviceState *dev;
-    gchar **parts;
-
-    parts = g_strsplit(path, "/", 0);
-    if (parts == NULL || parts[0] == NULL) {
-        g_strfreev(parts);
-        return qdev_get_root();
-    }
-
-    if (strcmp(parts[0], "") == 0) {
-        partial_path = false;
-    }
-
-    if (partial_path) {
-        if (ambiguous) {
-            *ambiguous = false;
+    QTAILQ_REMOVE(&dev->parent_bus->children, dev, sibling);
+    for (prop = qdev_get_props(dev); prop && prop->name; prop++) {
+        if (prop->info->free) {
+            prop->info->free(dev, prop);
         }
-        dev = qdev_resolve_partial_path(qdev_get_root(), parts, ambiguous);
-    } else {
-        dev = qdev_resolve_abs_path(qdev_get_root(), parts, 1);
-    }
-
-    g_strfreev(parts);
-
-    return dev;
-}
-
-typedef struct StringProperty
-{
-    char *(*get)(DeviceState *, Error **);
-    void (*set)(DeviceState *, const char *, Error **);
-} StringProperty;
-
-static void qdev_property_get_str(DeviceState *dev, Visitor *v, void *opaque,
-                                  const char *name, Error **errp)
-{
-    StringProperty *prop = opaque;
-    char *value;
-
-    value = prop->get(dev, errp);
-    if (value) {
-        visit_type_str(v, &value, name, errp);
-        g_free(value);
     }
 }
 
-static void qdev_property_set_str(DeviceState *dev, Visitor *v, void *opaque,
-                                  const char *name, Error **errp)
+void device_reset(DeviceState *dev)
 {
-    StringProperty *prop = opaque;
-    char *value;
-    Error *local_err = NULL;
+    DeviceClass *klass = DEVICE_GET_CLASS(dev);
 
-    visit_type_str(v, &value, name, &local_err);
-    if (local_err) {
-        error_propagate(errp, local_err);
-        return;
+    if (klass->reset) {
+        klass->reset(dev);
     }
-
-    prop->set(dev, value, errp);
-    g_free(value);
 }
 
-static void qdev_property_release_str(DeviceState *dev, const char *name,
-                                      void *opaque)
-{
-    StringProperty *prop = opaque;
-    g_free(prop);
-}
+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),
+};
 
-void qdev_property_add_str(DeviceState *dev, const char *name,
-                           char *(*get)(DeviceState *, Error **),
-                           void (*set)(DeviceState *, const char *, Error **),
-                           Error **errp)
+static void init_qdev(void)
 {
-    StringProperty *prop = g_malloc0(sizeof(*prop));
-
-    prop->get = get;
-    prop->set = set;
-
-    qdev_property_add(dev, name, "string",
-                      get ? qdev_property_get_str : NULL,
-                      set ? qdev_property_set_str : NULL,
-                      qdev_property_release_str,
-                      prop, errp);
+    type_register_static(&device_type_info);
 }
 
-void qdev_machine_init(void)
-{
-    qdev_get_peripheral_anon();
-    qdev_get_peripheral();
-}
+device_init(init_qdev);
diff --git a/hw/qdev.h b/hw/qdev.h
index 2abb767389..ab53273632 100644
--- a/hw/qdev.h
+++ b/hw/qdev.h
@@ -6,6 +6,7 @@
 #include "qemu-char.h"
 #include "qemu-option.h"
 #include "qapi/qapi-visit-core.h"
+#include "qemu/object.h"
 
 typedef struct Property Property;
 
@@ -13,8 +14,6 @@ typedef struct PropertyInfo PropertyInfo;
 
 typedef struct CompatProperty CompatProperty;
 
-typedef struct DeviceInfo DeviceInfo;
-
 typedef struct BusState BusState;
 
 typedef struct BusInfo BusInfo;
@@ -28,52 +27,45 @@ enum {
     DEV_NVECTORS_UNSPECIFIED = -1,
 };
 
-/**
- * @DevicePropertyAccessor - called when trying to get/set a property
- *
- * @dev the device that owns the property
- * @v the visitor that contains the property data
- * @opaque the device property opaque
- * @name the name of the property
- * @errp a pointer to an Error that is filled if getting/setting fails.
- */
-typedef void (DevicePropertyAccessor)(DeviceState *dev,
-                                      Visitor *v,
-                                      void *opaque,
-                                      const char *name,
-                                      Error **errp);
+#define TYPE_DEVICE "device"
+#define DEVICE(obj) OBJECT_CHECK(DeviceState, (obj), TYPE_DEVICE)
+#define DEVICE_CLASS(klass) OBJECT_CLASS_CHECK(DeviceClass, (klass), TYPE_DEVICE)
+#define DEVICE_GET_CLASS(obj) OBJECT_GET_CLASS(DeviceClass, (obj), TYPE_DEVICE)
 
-/**
- * @DevicePropertyRelease - called when a property is removed from a device
- *
- * @dev the device that owns the property
- * @name the name of the property
- * @opaque the opaque registered with the property
- */
-typedef void (DevicePropertyRelease)(DeviceState *dev,
-                                     const char *name,
-                                     void *opaque);
-
-typedef struct DeviceProperty
-{
-    gchar *name;
-    gchar *type;
-    DevicePropertyAccessor *get;
-    DevicePropertyAccessor *set;
-    DevicePropertyRelease *release;
-    void *opaque;
-
-    QTAILQ_ENTRY(DeviceProperty) node;
-} DeviceProperty;
+typedef int (*qdev_initfn)(DeviceState *dev);
+typedef int (*qdev_event)(DeviceState *dev);
+typedef void (*qdev_resetfn)(DeviceState *dev);
+
+typedef struct DeviceClass {
+    ObjectClass parent_class;
+
+    const char *fw_name;
+    const char *desc;
+    Property *props;
+    int no_user;
+
+    /* callbacks */
+    void (*reset)(DeviceState *dev);
+
+    /* device state */
+    const VMStateDescription *vmsd;
+
+    /* Private to qdev / bus.  */
+    qdev_initfn init;
+    qdev_event unplug;
+    qdev_event exit;
+    BusInfo *bus_info;
+} DeviceClass;
 
 /* This structure should not be accessed directly.  We declare it here
    so that it can be embedded in individual device state structures.  */
 struct DeviceState {
+    Object parent_obj;
+
     const char *id;
     enum DevState state;
     QemuOpts *opts;
     int hotplugged;
-    DeviceInfo *info;
     BusState *parent_bus;
     int num_gpio_out;
     qemu_irq *gpio_out;
@@ -84,18 +76,6 @@ struct DeviceState {
     QTAILQ_ENTRY(DeviceState) sibling;
     int instance_id_alias;
     int alias_required_for_version;
-
-    /**
-     * This tracks the number of references between devices.  See @qdev_ref for
-     * more information.
-     */
-    uint32_t ref;
-
-    QTAILQ_HEAD(, DeviceProperty) properties;
-
-    /* Do not, under any circumstance, use this parent link below anywhere
-     * outside of qdev.c.  You have been warned. */
-    DeviceState *parent;
 };
 
 typedef void (*bus_dev_printfn)(Monitor *mon, DeviceState *dev, int indent);
@@ -145,6 +125,7 @@ enum PropertyType {
     PROP_TYPE_UINT64,
     PROP_TYPE_TADDR,
     PROP_TYPE_MACADDR,
+    PROP_TYPE_LOSTTICKPOLICY,
     PROP_TYPE_DRIVE,
     PROP_TYPE_CHR,
     PROP_TYPE_STRING,
@@ -164,8 +145,8 @@ struct PropertyInfo {
     int (*parse)(DeviceState *dev, Property *prop, const char *str);
     int (*print)(DeviceState *dev, Property *prop, char *dest, size_t len);
     void (*free)(DeviceState *dev, Property *prop);
-    DevicePropertyAccessor *get;
-    DevicePropertyAccessor *set;
+    ObjectPropertyAccessor *get;
+    ObjectPropertyAccessor *set;
 };
 
 typedef struct GlobalProperty {
@@ -179,6 +160,7 @@ typedef struct GlobalProperty {
 
 DeviceState *qdev_create(BusState *bus, const char *name);
 DeviceState *qdev_try_create(BusState *bus, const char *name);
+bool qdev_exists(const char *name);
 int qdev_device_help(QemuOpts *opts);
 DeviceState *qdev_device_add(QemuOpts *opts);
 int qdev_init(DeviceState *dev) QEMU_WARN_UNUSED_RESULT;
@@ -198,43 +180,11 @@ BusState *qdev_get_child_bus(DeviceState *dev, const char *name);
 
 /*** Device API.  ***/
 
-typedef int (*qdev_initfn)(DeviceState *dev, DeviceInfo *info);
-typedef int (*qdev_event)(DeviceState *dev);
-typedef void (*qdev_resetfn)(DeviceState *dev);
-
-struct DeviceInfo {
-    const char *name;
-    const char *fw_name;
-    const char *alias;
-    const char *desc;
-    size_t size;
-    Property *props;
-    int no_user;
-
-    /* callbacks */
-    qdev_resetfn reset;
-
-    /* device state */
-    const VMStateDescription *vmsd;
-
-    /* Private to qdev / bus.  */
-    qdev_initfn init;
-    qdev_event unplug;
-    qdev_event exit;
-    BusInfo *bus_info;
-    struct DeviceInfo *next;
-};
-extern DeviceInfo *device_info_list;
-
-void qdev_register(DeviceInfo *info);
-
 /* Register device properties.  */
 /* GPIO inputs also double as IRQ sinks.  */
 void qdev_init_gpio_in(DeviceState *dev, qemu_irq_handler handler, int n);
 void qdev_init_gpio_out(DeviceState *dev, qemu_irq *pins, int n);
 
-CharDriverState *qdev_init_chardev(DeviceState *dev);
-
 BusState *qdev_get_parent_bus(DeviceState *dev);
 
 /*** BUS API. ***/
@@ -287,6 +237,7 @@ extern PropertyInfo qdev_prop_string;
 extern PropertyInfo qdev_prop_chr;
 extern PropertyInfo qdev_prop_ptr;
 extern PropertyInfo qdev_prop_macaddr;
+extern PropertyInfo qdev_prop_losttickpolicy;
 extern PropertyInfo qdev_prop_drive;
 extern PropertyInfo qdev_prop_netdev;
 extern PropertyInfo qdev_prop_vlan;
@@ -347,6 +298,9 @@ extern PropertyInfo qdev_prop_pci_devfn;
     DEFINE_PROP(_n, _s, _f, qdev_prop_drive, BlockDriverState *)
 #define DEFINE_PROP_MACADDR(_n, _s, _f)         \
     DEFINE_PROP(_n, _s, _f, qdev_prop_macaddr, MACAddr)
+#define DEFINE_PROP_LOSTTICKPOLICY(_n, _s, _f, _d) \
+    DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_losttickpolicy, \
+                        LostTickPolicy)
 
 #define DEFINE_PROP_END_OF_LIST()               \
     {}
@@ -369,6 +323,8 @@ void qdev_prop_set_vlan(DeviceState *dev, const char *name, VLANState *value);
 int qdev_prop_set_drive(DeviceState *dev, const char *name, BlockDriverState *value) QEMU_WARN_UNUSED_RESULT;
 void qdev_prop_set_drive_nofail(DeviceState *dev, const char *name, BlockDriverState *value);
 void qdev_prop_set_macaddr(DeviceState *dev, const char *name, uint8_t *value);
+void qdev_prop_set_losttickpolicy(DeviceState *dev, const char *name,
+                                  LostTickPolicy *value);
 /* FIXME: Remove opaque pointer properties.  */
 void qdev_prop_set_ptr(DeviceState *dev, const char *name, void *value);
 void qdev_prop_set_defaults(DeviceState *dev, Property *props);
@@ -378,250 +334,43 @@ void qdev_prop_set_globals(DeviceState *dev);
 void error_set_from_qdev_prop_error(Error **errp, int ret, DeviceState *dev,
                                     Property *prop, const char *value);
 
-static inline const char *qdev_fw_name(DeviceState *dev)
-{
-    return dev->info->fw_name ? : dev->info->alias ? : dev->info->name;
-}
-
 char *qdev_get_fw_dev_path(DeviceState *dev);
+
 /* This is a nasty hack to allow passing a NULL bus to qdev_create.  */
 extern struct BusInfo system_bus_info;
 
 /**
- * @qdev_ref
- *
- * Increase the reference count of a device.  A device cannot be freed as long
- * as its reference count is greater than zero.
- *
- * @dev - the device
- */
-void qdev_ref(DeviceState *dev);
-
-/**
- * @qdef_unref
- *
- * Decrease the reference count of a device.  A device cannot be freed as long
- * as its reference count is greater than zero.
- *
- * @dev - the device
- */
-void qdev_unref(DeviceState *dev);
-
-/**
- * @qdev_property_add - add a new property to a device
- *
- * @dev - the device to add a property to
- *
- * @name - the name of the property.  This can contain any character except for
- *         a forward slash.  In general, you should use hyphens '-' instead of
- *         underscores '_' when naming properties.
- *
- * @type - the type name of the property.  This namespace is pretty loosely
- *         defined.  Sub namespaces are constructed by using a prefix and then
- *         to angle brackets.  For instance, the type 'virtio-net-pci' in the
- *         'link' namespace would be 'link<virtio-net-pci>'.
- *
- * @get - the getter to be called to read a property.  If this is NULL, then
- *        the property cannot be read.
- *
- * @set - the setter to be called to write a property.  If this is NULL,
- *        then the property cannot be written.
- *
- * @release - called when the property is removed from the device.  This is
- *            meant to allow a property to free its opaque upon device
- *            destruction.  This may be NULL.
- *
- * @opaque - an opaque pointer to pass to the callbacks for the property
- *
- * @errp - returns an error if this function fails
- */
-void qdev_property_add(DeviceState *dev, const char *name, const char *type,
-                       DevicePropertyAccessor *get, DevicePropertyAccessor *set,
-                       DevicePropertyRelease *release,
-                       void *opaque, Error **errp);
-
-/**
- * @qdev_property_get - reads a property from a device
- *
- * @dev - the device
- *
- * @v - the visitor that will receive the property value.  This should be an
- *      Output visitor and the data will be written with @name as the name.
- *
- * @name - the name of the property
- *
- * @errp - returns an error if this function fails
- */
-void qdev_property_get(DeviceState *dev, Visitor *v, const char *name,
-                       Error **errp);
-
-/**
- * @qdev_property_set - writes a property to a device
- *
- * @dev - the device
- *
- * @v - the visitor that will be used to write the property value.  This should
- *      be an Input visitor and the data will be first read with @name as the
- *      name and then written as the property value.
- *
- * @name - the name of the property
- *
- * @errp - returns an error if this function fails
- */
-void qdev_property_set(DeviceState *dev, Visitor *v, const char *name,
-                       Error **errp);
-
-/**
- * @qdev_property_get_type - returns the type of a property
- *
- * @dev - the device
- *
- * @name - the name of the property
- *
- * @errp - returns an error if this function fails
- *
- * Returns:
- *   The type name of the property.
- */
-const char *qdev_property_get_type(DeviceState *dev, const char *name,
-                                   Error **errp);
-
-/**
  * @qdev_property_add_static - add a @Property to a device referencing a
  * field in a struct.
  */
 void qdev_property_add_static(DeviceState *dev, Property *prop, Error **errp);
 
 /**
- * @qdev_get_root - returns the root device of the composition tree
+ * @qdev_machine_init
  *
- * Returns:
- *   The root of the composition tree.
+ * Initialize platform devices before machine init.  This is a hack until full
+ * support for composition is added.
  */
-DeviceState *qdev_get_root(void);
+void qdev_machine_init(void);
 
 /**
- * @qdev_get_canonical_path - returns the canonical path for a device.  This
- * is the path within the composition tree starting from the root.
+ * @device_reset
  *
- * Returns:
- *   The canonical path in the composition tree.
+ * Reset a single device (by calling the reset method).
  */
-gchar *qdev_get_canonical_path(DeviceState *dev);
+void device_reset(DeviceState *dev);
 
-/**
- * @qdev_resolve_path - resolves a path returning a device
- *
- * There are two types of supported paths--absolute paths and partial paths.
- * 
- * Absolute paths are derived from the root device and can follow child<> or
- * link<> properties.  Since they can follow link<> properties, they can be
- * arbitrarily long.  Absolute paths look like absolute filenames and are
- * prefixed with a leading slash.
- * 
- * Partial paths look like relative filenames.  They do not begin with a
- * prefix.  The matching rules for partial paths are subtle but designed to make
- * specifying devices easy.  At each level of the composition tree, the partial
- * path is matched as an absolute path.  The first match is not returned.  At
- * least two matches are searched for.  A successful result is only returned if
- * only one match is founded.  If more than one match is found, a flag is
- * return to indicate that the match was ambiguous.
- *
- * @path - the path to resolve
- *
- * @ambiguous - returns true if the path resolution failed because of an
- *              ambiguous match
- *
- * Returns:
- *   The matched device or NULL on path lookup failure.
- */
-DeviceState *qdev_resolve_path(const char *path, bool *ambiguous);
+const VMStateDescription *qdev_get_vmsd(DeviceState *dev);
 
-/**
- * @qdev_property_add_child - Add a child property to a device
- *
- * Child properties form the composition tree.  All devices need to be a child
- * of another device.  Devices can only be a child of one device.
- *
- * There is no way for a child to determine what its parent is.  It is not
- * a bidirectional relationship.  This is by design.
- *
- * @dev - the device to add a property to
- *
- * @name - the name of the property
- *
- * @child - the child device
- *
- * @errp - if an error occurs, a pointer to an area to store the area
- */
-void qdev_property_add_child(DeviceState *dev, const char *name,
-                             DeviceState *child, Error **errp);
+const char *qdev_fw_name(DeviceState *dev);
 
-/**
- * @qdev_property_add_link - Add a link property to a device
- *
- * Links establish relationships between devices.  Links are unidirectional
- * although two links can be combined to form a bidirectional relationship
- * between devices.
- *
- * Links form the graph in the device model.
- *
- * @dev - the device to add a property to
- *
- * @name - the name of the property
- *
- * @type - the qdev type of the link
- *
- * @child - a pointer to where the link device reference is stored
- *
- * @errp - if an error occurs, a pointer to an area to store the area
- */
-void qdev_property_add_link(DeviceState *dev, const char *name,
-                            const char *type, DeviceState **child,
-                            Error **errp);
+BusInfo *qdev_get_bus_info(DeviceState *dev);
 
-/**
- * @qdev_property_add_str
- *
- * Add a string property using getters/setters.  This function will add a
- * property of type 'string'.
- *
- * @dev - the device to add a property to
- *
- * @name - the name of the property
- *
- * @get - the getter or NULL if the property is write-only.  This function must
- *        return a string to be freed by @g_free().
- *
- * @set - the setter or NULL if the property is read-only
- *
- * @errp - if an error occurs, a pointer to an area to store the error
- */
-void qdev_property_add_str(DeviceState *dev, const char *name,
-                           char *(*get)(DeviceState *, Error **),
-                           void (*set)(DeviceState *, const char *, Error **),
-                           Error **errp);
+Property *qdev_get_props(DeviceState *dev);
 
-/**
- * @qdev_get_type
- *
- * Returns the string representation of the type of this object.
- *
- * @dev - the device
- *
- * @errp - if an error occurs, a pointer to an area to store the error
- *
- * Returns: a string representing the type.  This must be freed by the caller
- *          with g_free().
- */
-char *qdev_get_type(DeviceState *dev, Error **errp);
+/* FIXME: make this a link<> */
+void qdev_set_parent_bus(DeviceState *dev, BusState *bus);
 
-/**
- * @qdev_machine_init
- *
- * Initialize platform devices before machine init.  This is a hack until full
- * support for composition is added.
- */
-void qdev_machine_init(void);
+extern int qdev_hotplug;
 
 #endif
diff --git a/hw/qxl.c b/hw/qxl.c
index ac819271b2..bc03c1dc77 100644
--- a/hw/qxl.c
+++ b/hw/qxl.c
@@ -343,10 +343,7 @@ static void init_qxl_ram(PCIQXLDevice *d)
 /* can be called from spice server thread context */
 static void qxl_set_dirty(MemoryRegion *mr, ram_addr_t addr, ram_addr_t end)
 {
-    while (addr < end) {
-        memory_region_set_dirty(mr, addr);
-        addr += TARGET_PAGE_SIZE;
-    }
+    memory_region_set_dirty(mr, addr, end - addr);
 }
 
 static void qxl_rom_set_dirty(PCIQXLDevice *qxl)
@@ -1020,7 +1017,7 @@ void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL pqxl, int group_id)
     case MEMSLOT_GROUP_HOST:
         return (void*)offset;
     case MEMSLOT_GROUP_GUEST:
-        PANIC_ON(slot > NUM_MEMSLOTS);
+        PANIC_ON(slot >= NUM_MEMSLOTS);
         PANIC_ON(!qxl->guest_slots[slot].active);
         PANIC_ON(offset < qxl->guest_slots[slot].delta);
         offset -= qxl->guest_slots[slot].delta;
@@ -1827,38 +1824,56 @@ static Property qxl_properties[] = {
         DEFINE_PROP_END_OF_LIST(),
 };
 
-static PCIDeviceInfo qxl_info_primary = {
-    .qdev.name    = "qxl-vga",
-    .qdev.desc    = "Spice QXL GPU (primary, vga compatible)",
-    .qdev.size    = sizeof(PCIQXLDevice),
-    .qdev.reset   = qxl_reset_handler,
-    .qdev.vmsd    = &qxl_vmstate,
-    .no_hotplug   = 1,
-    .init         = qxl_init_primary,
-    .romfile      = "vgabios-qxl.bin",
-    .vendor_id    = REDHAT_PCI_VENDOR_ID,
-    .device_id    = QXL_DEVICE_ID_STABLE,
-    .class_id     = PCI_CLASS_DISPLAY_VGA,
-    .qdev.props   = qxl_properties,
+static void qxl_primary_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->no_hotplug = 1;
+    k->init = qxl_init_primary;
+    k->romfile = "vgabios-qxl.bin";
+    k->vendor_id = REDHAT_PCI_VENDOR_ID;
+    k->device_id = QXL_DEVICE_ID_STABLE;
+    k->class_id = PCI_CLASS_DISPLAY_VGA;
+    dc->desc = "Spice QXL GPU (primary, vga compatible)";
+    dc->reset = qxl_reset_handler;
+    dc->vmsd = &qxl_vmstate;
+    dc->props = qxl_properties;
+}
+
+static TypeInfo qxl_primary_info = {
+    .name          = "qxl-vga",
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(PCIQXLDevice),
+    .class_init    = qxl_primary_class_init,
 };
 
-static PCIDeviceInfo qxl_info_secondary = {
-    .qdev.name    = "qxl",
-    .qdev.desc    = "Spice QXL GPU (secondary)",
-    .qdev.size    = sizeof(PCIQXLDevice),
-    .qdev.reset   = qxl_reset_handler,
-    .qdev.vmsd    = &qxl_vmstate,
-    .init         = qxl_init_secondary,
-    .vendor_id    = REDHAT_PCI_VENDOR_ID,
-    .device_id    = QXL_DEVICE_ID_STABLE,
-    .class_id     = PCI_CLASS_DISPLAY_OTHER,
-    .qdev.props   = qxl_properties,
+static void qxl_secondary_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->init = qxl_init_secondary;
+    k->vendor_id = REDHAT_PCI_VENDOR_ID;
+    k->device_id = QXL_DEVICE_ID_STABLE;
+    k->class_id = PCI_CLASS_DISPLAY_OTHER;
+    dc->desc = "Spice QXL GPU (secondary)";
+    dc->reset = qxl_reset_handler;
+    dc->vmsd = &qxl_vmstate;
+    dc->props = qxl_properties;
+}
+
+static TypeInfo qxl_secondary_info = {
+    .name          = "qxl",
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(PCIQXLDevice),
+    .class_init    = qxl_secondary_class_init,
 };
 
 static void qxl_register(void)
 {
-    pci_qdev_register(&qxl_info_primary);
-    pci_qdev_register(&qxl_info_secondary);
+    type_register_static(&qxl_primary_info);
+    type_register_static(&qxl_secondary_info);
 }
 
 device_init(qxl_register);
diff --git a/hw/realview.c b/hw/realview.c
index 3f35118f21..821e627560 100644
--- a/hw/realview.c
+++ b/hw/realview.c
@@ -82,15 +82,23 @@ static int realview_i2c_init(SysBusDevice *dev)
     return 0;
 }
 
-static SysBusDeviceInfo realview_i2c_info = {
-    .init = realview_i2c_init,
-    .qdev.name  = "realview_i2c",
-    .qdev.size  = sizeof(RealViewI2CState),
+static void realview_i2c_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = realview_i2c_init;
+}
+
+static TypeInfo realview_i2c_info = {
+    .name          = "realview_i2c",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(RealViewI2CState),
+    .class_init    = realview_i2c_class_init,
 };
 
 static void realview_register_devices(void)
 {
-    sysbus_register_withprop(&realview_i2c_info);
+    type_register_static(&realview_i2c_info);
 }
 
 /* Board init.  */
@@ -227,6 +235,8 @@ static void realview_init(ram_addr_t ram_size,
         for (n = 0; n < smp_cpus; n++) {
             sysbus_connect_irq(busdev, n, cpu_irq[n]);
         }
+        sysbus_create_varargs("l2x0", realview_binfo.smp_priv_base + 0x2000,
+                              NULL);
     } else {
         uint32_t gic_addr = is_pb ? 0x1e000000 : 0x10040000;
         /* For now just create the nIRQ GIC, and ignore the others.  */
diff --git a/hw/realview_gic.c b/hw/realview_gic.c
index 8c4d509ee7..4121502c7b 100644
--- a/hw/realview_gic.c
+++ b/hw/realview_gic.c
@@ -9,7 +9,6 @@
 
 #include "sysbus.h"
 
-#define GIC_NIRQ 96
 #define NCPU 1
 
 /* Only a single "CPU" interface is present.  */
@@ -37,16 +36,33 @@ static int realview_gic_init(SysBusDevice *dev)
 {
     RealViewGICState *s = FROM_SYSBUSGIC(RealViewGICState, dev);
 
-    gic_init(&s->gic);
+    /* The GICs on the RealView boards have a fixed nonconfigurable
+     * number of interrupt lines, so we don't need to expose this as
+     * a qdev property.
+     */
+    gic_init(&s->gic, 96);
     realview_gic_map_setup(s);
     sysbus_init_mmio(dev, &s->container);
     return 0;
 }
 
+static void realview_gic_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+
+    sdc->init = realview_gic_init;
+}
+
+static TypeInfo realview_gic_info = {
+    .name          = "realview_gic",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(RealViewGICState),
+    .class_init    = realview_gic_class_init,
+};
+
 static void realview_gic_register_devices(void)
 {
-    sysbus_register_dev("realview_gic", sizeof(RealViewGICState),
-                        realview_gic_init);
+    type_register_static(&realview_gic_info);
 }
 
 device_init(realview_gic_register_devices)
diff --git a/hw/rtl8139.c b/hw/rtl8139.c
index 0ae9f5774b..1668390e1f 100644
--- a/hw/rtl8139.c
+++ b/hw/rtl8139.c
@@ -3478,7 +3478,7 @@ static int pci_rtl8139_init(PCIDevice *dev)
     s->eeprom.contents[9] = s->conf.macaddr.a[4] | s->conf.macaddr.a[5] << 8;
 
     s->nic = qemu_new_nic(&net_rtl8139_info, &s->conf,
-                          dev->qdev.info->name, dev->qdev.id, s);
+                          object_get_typename(OBJECT(dev)), dev->qdev.id, s);
     qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a);
 
     s->cplus_txbuffer = NULL;
@@ -3494,27 +3494,38 @@ static int pci_rtl8139_init(PCIDevice *dev)
     return 0;
 }
 
-static PCIDeviceInfo rtl8139_info = {
-    .qdev.name  = "rtl8139",
-    .qdev.size  = sizeof(RTL8139State),
-    .qdev.reset = rtl8139_reset,
-    .qdev.vmsd  = &vmstate_rtl8139,
-    .init       = pci_rtl8139_init,
-    .exit       = pci_rtl8139_uninit,
-    .romfile    = "pxe-rtl8139.rom",
-    .vendor_id  = PCI_VENDOR_ID_REALTEK,
-    .device_id  = PCI_DEVICE_ID_REALTEK_8139,
-    .revision   = RTL8139_PCI_REVID, /* >=0x20 is for 8139C+ */
-    .class_id   = PCI_CLASS_NETWORK_ETHERNET,
-    .qdev.props = (Property[]) {
-        DEFINE_NIC_PROPERTIES(RTL8139State, conf),
-        DEFINE_PROP_END_OF_LIST(),
-    }
+static Property rtl8139_properties[] = {
+    DEFINE_NIC_PROPERTIES(RTL8139State, conf),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void rtl8139_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->init = pci_rtl8139_init;
+    k->exit = pci_rtl8139_uninit;
+    k->romfile = "pxe-rtl8139.rom";
+    k->vendor_id = PCI_VENDOR_ID_REALTEK;
+    k->device_id = PCI_DEVICE_ID_REALTEK_8139;
+    k->revision = RTL8139_PCI_REVID; /* >=0x20 is for 8139C+ */
+    k->class_id = PCI_CLASS_NETWORK_ETHERNET;
+    dc->reset = rtl8139_reset;
+    dc->vmsd = &vmstate_rtl8139;
+    dc->props = rtl8139_properties;
+}
+
+static TypeInfo rtl8139_info = {
+    .name          = "rtl8139",
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(RTL8139State),
+    .class_init    = rtl8139_class_init,
 };
 
 static void rtl8139_register_devices(void)
 {
-    pci_qdev_register(&rtl8139_info);
+    type_register_static(&rtl8139_info);
 }
 
 device_init(rtl8139_register_devices)
diff --git a/hw/s390-virtio-bus.c b/hw/s390-virtio-bus.c
index 2efea9f184..49140f8a9e 100644
--- a/hw/s390-virtio-bus.c
+++ b/hw/s390-virtio-bus.c
@@ -50,12 +50,6 @@ struct BusInfo s390_virtio_bus_info = {
     .size       = sizeof(VirtIOS390Bus),
 };
 
-typedef struct {
-    DeviceInfo qdev;
-    int (*init)(VirtIOS390Device *dev);
-} VirtIOS390DeviceInfo;
-
-
 static const VirtIOBindings virtio_s390_bindings;
 
 static ram_addr_t s390_virtio_device_num_vq(VirtIOS390Device *dev);
@@ -343,69 +337,108 @@ static const VirtIOBindings virtio_s390_bindings = {
     .get_features = virtio_s390_get_features,
 };
 
-static VirtIOS390DeviceInfo s390_virtio_net = {
-    .init = s390_virtio_net_init,
-    .qdev.name = "virtio-net-s390",
-    .qdev.alias = "virtio-net",
-    .qdev.size = sizeof(VirtIOS390Device),
-    .qdev.props = (Property[]) {
-        DEFINE_NIC_PROPERTIES(VirtIOS390Device, nic),
-        DEFINE_PROP_UINT32("x-txtimer", VirtIOS390Device,
-                           net.txtimer, TX_TIMER_INTERVAL),
-        DEFINE_PROP_INT32("x-txburst", VirtIOS390Device,
-                          net.txburst, TX_BURST),
-        DEFINE_PROP_STRING("tx", VirtIOS390Device, net.tx),
-        DEFINE_PROP_END_OF_LIST(),
-    },
+static Property s390_virtio_net_properties[] = {
+    DEFINE_NIC_PROPERTIES(VirtIOS390Device, nic),
+    DEFINE_PROP_UINT32("x-txtimer", VirtIOS390Device,
+                       net.txtimer, TX_TIMER_INTERVAL),
+    DEFINE_PROP_INT32("x-txburst", VirtIOS390Device,
+                      net.txburst, TX_BURST),
+    DEFINE_PROP_STRING("tx", VirtIOS390Device, net.tx),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void s390_virtio_net_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    VirtIOS390DeviceClass *k = VIRTIO_S390_DEVICE_CLASS(klass);
+
+    k->init = s390_virtio_net_init;
+    dc->props = s390_virtio_net_properties;
+}
+
+static TypeInfo s390_virtio_net = {
+    .name          = "virtio-net-s390",
+    .parent        = TYPE_VIRTIO_S390_DEVICE,
+    .instance_size = sizeof(VirtIOS390Device),
+    .class_init    = s390_virtio_net_class_init,
+};
+
+static Property s390_virtio_blk_properties[] = {
+    DEFINE_BLOCK_PROPERTIES(VirtIOS390Device, block),
+    DEFINE_PROP_STRING("serial", VirtIOS390Device, block_serial),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void s390_virtio_blk_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    VirtIOS390DeviceClass *k = VIRTIO_S390_DEVICE_CLASS(klass);
+
+    k->init = s390_virtio_blk_init;
+    dc->props = s390_virtio_blk_properties;
+}
+
+static TypeInfo s390_virtio_blk = {
+    .name          = "virtio-blk-s390",
+    .parent        = TYPE_VIRTIO_S390_DEVICE,
+    .instance_size = sizeof(VirtIOS390Device),
+    .class_init    = s390_virtio_blk_class_init,
 };
 
-static VirtIOS390DeviceInfo s390_virtio_blk = {
-    .init = s390_virtio_blk_init,
-    .qdev.name = "virtio-blk-s390",
-    .qdev.alias = "virtio-blk",
-    .qdev.size = sizeof(VirtIOS390Device),
-    .qdev.props = (Property[]) {
-        DEFINE_BLOCK_PROPERTIES(VirtIOS390Device, block),
-        DEFINE_PROP_STRING("serial", VirtIOS390Device, block_serial),
-        DEFINE_PROP_END_OF_LIST(),
-    },
+static Property s390_virtio_serial_properties[] = {
+    DEFINE_PROP_UINT32("max_ports", VirtIOS390Device,
+                       serial.max_virtserial_ports, 31),
+    DEFINE_PROP_END_OF_LIST(),
 };
 
-static VirtIOS390DeviceInfo s390_virtio_serial = {
-    .init = s390_virtio_serial_init,
-    .qdev.name = "virtio-serial-s390",
-    .qdev.alias = "virtio-serial",
-    .qdev.size = sizeof(VirtIOS390Device),
-    .qdev.props = (Property[]) {
-        DEFINE_PROP_UINT32("max_ports", VirtIOS390Device,
-                           serial.max_virtserial_ports, 31),
-        DEFINE_PROP_END_OF_LIST(),
-    },
+static void s390_virtio_serial_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    VirtIOS390DeviceClass *k = VIRTIO_S390_DEVICE_CLASS(klass);
+
+    k->init = s390_virtio_serial_init;
+    dc->props = s390_virtio_serial_properties;
+}
+
+static TypeInfo s390_virtio_serial = {
+    .name          = "virtio-serial-s390",
+    .parent        = TYPE_VIRTIO_S390_DEVICE,
+    .instance_size = sizeof(VirtIOS390Device),
+    .class_init    = s390_virtio_serial_class_init,
 };
 
-static int s390_virtio_busdev_init(DeviceState *dev, DeviceInfo *info)
+static int s390_virtio_busdev_init(DeviceState *dev)
 {
-    VirtIOS390DeviceInfo *_info = (VirtIOS390DeviceInfo *)info;
     VirtIOS390Device *_dev = (VirtIOS390Device *)dev;
+    VirtIOS390DeviceClass *_info = VIRTIO_S390_DEVICE_GET_CLASS(dev);
 
     return _info->init(_dev);
 }
 
-static void s390_virtio_bus_register_withprop(VirtIOS390DeviceInfo *info)
+static void virtio_s390_device_class_init(ObjectClass *klass, void *data)
 {
-    info->qdev.init = s390_virtio_busdev_init;
-    info->qdev.bus_info = &s390_virtio_bus_info;
-    info->qdev.unplug = qdev_simple_unplug_cb;
+    DeviceClass *dc = DEVICE_CLASS(klass);
 
-    assert(info->qdev.size >= sizeof(VirtIOS390Device));
-    qdev_register(&info->qdev);
+    dc->init = s390_virtio_busdev_init;
+    dc->bus_info = &s390_virtio_bus_info;
+    dc->unplug = qdev_simple_unplug_cb;
 }
 
+static TypeInfo virtio_s390_device_info = {
+    .name = TYPE_VIRTIO_S390_DEVICE,
+    .parent = TYPE_DEVICE,
+    .instance_size = sizeof(VirtIOS390Device),
+    .class_init = virtio_s390_device_class_init,
+    .class_size = sizeof(VirtIOS390DeviceClass),
+    .abstract = true,
+};
+
 static void s390_virtio_register(void)
 {
-    s390_virtio_bus_register_withprop(&s390_virtio_serial);
-    s390_virtio_bus_register_withprop(&s390_virtio_blk);
-    s390_virtio_bus_register_withprop(&s390_virtio_net);
+    type_register_static(&virtio_s390_device_info);
+    type_register_static(&s390_virtio_serial);
+    type_register_static(&s390_virtio_blk);
+    type_register_static(&s390_virtio_net);
 }
 device_init(s390_virtio_register);
 
@@ -419,16 +452,25 @@ static int s390_virtio_bridge_init(SysBusDevice *dev)
     return 0;
 }
 
-static SysBusDeviceInfo s390_virtio_bridge_info = {
-    .init = s390_virtio_bridge_init,
-    .qdev.name  = "s390-virtio-bridge",
-    .qdev.size  = sizeof(SysBusDevice),
-    .qdev.no_user = 1,
+static void s390_virtio_bridge_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = s390_virtio_bridge_init;
+    dc->no_user = 1;
+}
+
+static TypeInfo s390_virtio_bridge_info = {
+    .name          = "s390-virtio-bridge",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(SysBusDevice),
+    .class_init    = s390_virtio_bridge_class_init,
 };
 
 static void s390_virtio_register_devices(void)
 {
-    sysbus_register_withprop(&s390_virtio_bridge_info);
+    type_register_static(&s390_virtio_bridge_info);
 }
 
 device_init(s390_virtio_register_devices)
diff --git a/hw/s390-virtio-bus.h b/hw/s390-virtio-bus.h
index d02a90709d..b5e59b7d4b 100644
--- a/hw/s390-virtio-bus.h
+++ b/hw/s390-virtio-bus.h
@@ -40,7 +40,22 @@
 #define VIRTIO_PARAM_CONFIG_CHANGED     0x1
 #define VIRTIO_PARAM_DEV_ADD            0x2
 
-typedef struct VirtIOS390Device {
+#define TYPE_VIRTIO_S390_DEVICE "virtio-s390-device"
+#define VIRTIO_S390_DEVICE(obj) \
+     OBJECT_CHECK(VirtIOS390Device, (obj), TYPE_VIRTIO_S390_DEVICE)
+#define VIRTIO_S390_DEVICE_CLASS(klass) \
+     OBJECT_CLASS_CHECK(VirtIOS390DeviceClass, (klass), TYPE_VIRTIO_S390_DEVICE)
+#define VIRTIO_S390_DEVICE_GET_CLASS(obj) \
+     OBJECT_GET_CLASS(VirtIOS390DeviceClass, (obj), TYPE_VIRTIO_S390_DEVICE)
+
+typedef struct VirtIOS390Device VirtIOS390Device;
+
+typedef struct VirtIOS390DeviceClass {
+    DeviceClass qdev;
+    int (*init)(VirtIOS390Device *dev);
+} VirtIOS390DeviceClass;
+
+struct VirtIOS390Device {
     DeviceState qdev;
     ram_addr_t dev_offs;
     ram_addr_t feat_offs;
@@ -52,7 +67,7 @@ typedef struct VirtIOS390Device {
     uint32_t host_features;
     virtio_serial_conf serial;
     virtio_net_conf net;
-} VirtIOS390Device;
+};
 
 typedef struct VirtIOS390Bus {
     BusState bus;
diff --git a/hw/s390-virtio.c b/hw/s390-virtio.c
index 2210b8ac7e..51123a7535 100644
--- a/hw/s390-virtio.c
+++ b/hw/s390-virtio.c
@@ -317,7 +317,6 @@ static QEMUMachine s390_machine = {
     .no_serial = 1,
     .no_parallel = 1,
     .use_virtcon = 1,
-    .no_vga = 1,
     .max_cpus = 255,
     .is_default = 1,
 };
diff --git a/hw/sb16.c b/hw/sb16.c
index 887b32e794..db8929b98e 100644
--- a/hw/sb16.c
+++ b/hw/sb16.c
@@ -1289,55 +1289,55 @@ static const VMStateDescription vmstate_sb16 = {
     .minimum_version_id_old = 1,
     .post_load = sb16_post_load,
     .fields      = (VMStateField []) {
-        VMSTATE_UINT32(irq, SB16State),
-        VMSTATE_UINT32(dma, SB16State),
-        VMSTATE_UINT32(hdma, SB16State),
-        VMSTATE_UINT32(port, SB16State),
-        VMSTATE_UINT32(ver, SB16State),
-        VMSTATE_INT32(in_index, SB16State),
-        VMSTATE_INT32(out_data_len, SB16State),
-        VMSTATE_INT32(fmt_stereo, SB16State),
-        VMSTATE_INT32(fmt_signed, SB16State),
-        VMSTATE_INT32(fmt_bits, SB16State),
-        VMSTATE_UINT32(fmt, SB16State),
-        VMSTATE_INT32(dma_auto, SB16State),
-        VMSTATE_INT32(block_size, SB16State),
-        VMSTATE_INT32(fifo, SB16State),
-        VMSTATE_INT32(freq, SB16State),
-        VMSTATE_INT32(time_const, SB16State),
-        VMSTATE_INT32(speaker, SB16State),
-        VMSTATE_INT32(needed_bytes, SB16State),
-        VMSTATE_INT32(cmd, SB16State),
-        VMSTATE_INT32(use_hdma, SB16State),
-        VMSTATE_INT32(highspeed, SB16State),
-        VMSTATE_INT32(can_write, SB16State),
-        VMSTATE_INT32(v2x6, SB16State),
-
-        VMSTATE_UINT8(csp_param, SB16State),
-        VMSTATE_UINT8(csp_value, SB16State),
-        VMSTATE_UINT8(csp_mode, SB16State),
-        VMSTATE_UINT8(csp_param, SB16State),
-        VMSTATE_BUFFER(csp_regs, SB16State),
-        VMSTATE_UINT8(csp_index, SB16State),
-        VMSTATE_BUFFER(csp_reg83, SB16State),
-        VMSTATE_INT32(csp_reg83r, SB16State),
-        VMSTATE_INT32(csp_reg83w, SB16State),
-
-        VMSTATE_BUFFER(in2_data, SB16State),
-        VMSTATE_BUFFER(out_data, SB16State),
-        VMSTATE_UINT8(test_reg, SB16State),
-        VMSTATE_UINT8(last_read_byte, SB16State),
-
-        VMSTATE_INT32(nzero, SB16State),
-        VMSTATE_INT32(left_till_irq, SB16State),
-        VMSTATE_INT32(dma_running, SB16State),
-        VMSTATE_INT32(bytes_per_second, SB16State),
-        VMSTATE_INT32(align, SB16State),
-
-        VMSTATE_INT32(mixer_nreg, SB16State),
-        VMSTATE_BUFFER(mixer_regs, SB16State),
-
-        VMSTATE_END_OF_LIST()
+        VMSTATE_UINT32 (irq, SB16State),
+        VMSTATE_UINT32 (dma, SB16State),
+        VMSTATE_UINT32 (hdma, SB16State),
+        VMSTATE_UINT32 (port, SB16State),
+        VMSTATE_UINT32 (ver, SB16State),
+        VMSTATE_INT32 (in_index, SB16State),
+        VMSTATE_INT32 (out_data_len, SB16State),
+        VMSTATE_INT32 (fmt_stereo, SB16State),
+        VMSTATE_INT32 (fmt_signed, SB16State),
+        VMSTATE_INT32 (fmt_bits, SB16State),
+        VMSTATE_UINT32 (fmt, SB16State),
+        VMSTATE_INT32 (dma_auto, SB16State),
+        VMSTATE_INT32 (block_size, SB16State),
+        VMSTATE_INT32 (fifo, SB16State),
+        VMSTATE_INT32 (freq, SB16State),
+        VMSTATE_INT32 (time_const, SB16State),
+        VMSTATE_INT32 (speaker, SB16State),
+        VMSTATE_INT32 (needed_bytes, SB16State),
+        VMSTATE_INT32 (cmd, SB16State),
+        VMSTATE_INT32 (use_hdma, SB16State),
+        VMSTATE_INT32 (highspeed, SB16State),
+        VMSTATE_INT32 (can_write, SB16State),
+        VMSTATE_INT32 (v2x6, SB16State),
+
+        VMSTATE_UINT8 (csp_param, SB16State),
+        VMSTATE_UINT8 (csp_value, SB16State),
+        VMSTATE_UINT8 (csp_mode, SB16State),
+        VMSTATE_UINT8 (csp_param, SB16State),
+        VMSTATE_BUFFER (csp_regs, SB16State),
+        VMSTATE_UINT8 (csp_index, SB16State),
+        VMSTATE_BUFFER (csp_reg83, SB16State),
+        VMSTATE_INT32 (csp_reg83r, SB16State),
+        VMSTATE_INT32 (csp_reg83w, SB16State),
+
+        VMSTATE_BUFFER (in2_data, SB16State),
+        VMSTATE_BUFFER (out_data, SB16State),
+        VMSTATE_UINT8 (test_reg, SB16State),
+        VMSTATE_UINT8 (last_read_byte, SB16State),
+
+        VMSTATE_INT32 (nzero, SB16State),
+        VMSTATE_INT32 (left_till_irq, SB16State),
+        VMSTATE_INT32 (dma_running, SB16State),
+        VMSTATE_INT32 (bytes_per_second, SB16State),
+        VMSTATE_INT32 (align, SB16State),
+
+        VMSTATE_INT32 (mixer_nreg, SB16State),
+        VMSTATE_BUFFER (mixer_regs, SB16State),
+
+        VMSTATE_END_OF_LIST ()
     }
 };
 
@@ -1349,7 +1349,7 @@ static const MemoryRegionPortio sb16_ioport_list[] = {
     { 10, 1, 1, .read = dsp_read },
     { 12, 1, 1, .write = dsp_write },
     { 12, 4, 1, .read = dsp_read },
-    PORTIO_END_OF_LIST(),
+    PORTIO_END_OF_LIST (),
 };
 
 
@@ -1391,24 +1391,34 @@ int SB16_init (ISABus *bus)
     return 0;
 }
 
-static ISADeviceInfo sb16_info = {
-    .qdev.name     = "sb16",
-    .qdev.desc     = "Creative Sound Blaster 16",
-    .qdev.size     = sizeof (SB16State),
-    .qdev.vmsd     = &vmstate_sb16,
-    .init          = sb16_initfn,
-    .qdev.props    = (Property[]) {
-        DEFINE_PROP_HEX32  ("version", SB16State, ver,  0x0405), /* 4.5 */
-        DEFINE_PROP_HEX32  ("iobase",  SB16State, port, 0x220),
-        DEFINE_PROP_UINT32 ("irq",     SB16State, irq,  5),
-        DEFINE_PROP_UINT32 ("dma",     SB16State, dma,  1),
-        DEFINE_PROP_UINT32 ("dma16",   SB16State, hdma, 5),
-        DEFINE_PROP_END_OF_LIST (),
-    },
+static Property sb16_properties[] = {
+    DEFINE_PROP_HEX32  ("version", SB16State, ver,  0x0405), /* 4.5 */
+    DEFINE_PROP_HEX32  ("iobase",  SB16State, port, 0x220),
+    DEFINE_PROP_UINT32 ("irq",     SB16State, irq,  5),
+    DEFINE_PROP_UINT32 ("dma",     SB16State, dma,  1),
+    DEFINE_PROP_UINT32 ("dma16",   SB16State, hdma, 5),
+    DEFINE_PROP_END_OF_LIST (),
+};
+
+static void sb16_class_initfn (ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS (klass);
+    ISADeviceClass *ic = ISA_DEVICE_CLASS (klass);
+    ic->init = sb16_initfn;
+    dc->desc = "Creative Sound Blaster 16";
+    dc->vmsd = &vmstate_sb16;
+    dc->props = sb16_properties;
+}
+
+static TypeInfo sb16_info = {
+    .name          = "sb16",
+    .parent        = TYPE_ISA_DEVICE,
+    .instance_size = sizeof (SB16State),
+    .class_init    = sb16_class_initfn,
 };
 
 static void sb16_register (void)
 {
-    isa_qdev_register (&sb16_info);
+    type_register_static (&sb16_info);
 }
 device_init (sb16_register)
diff --git a/hw/sbi.c b/hw/sbi.c
index 8965a71771..847a4dde84 100644
--- a/hw/sbi.c
+++ b/hw/sbi.c
@@ -131,17 +131,26 @@ static int sbi_init1(SysBusDevice *dev)
     return 0;
 }
 
-static SysBusDeviceInfo sbi_info = {
-    .init = sbi_init1,
-    .qdev.name  = "sbi",
-    .qdev.size  = sizeof(SBIState),
-    .qdev.vmsd  = &vmstate_sbi,
-    .qdev.reset = sbi_reset,
+static void sbi_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = sbi_init1;
+    dc->reset = sbi_reset;
+    dc->vmsd = &vmstate_sbi;
+}
+
+static TypeInfo sbi_info = {
+    .name          = "sbi",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(SBIState),
+    .class_init    = sbi_class_init,
 };
 
 static void sbi_register_devices(void)
 {
-    sysbus_register_withprop(&sbi_info);
+    type_register_static(&sbi_info);
 }
 
 device_init(sbi_register_devices)
diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c
index 64e709ee9f..0ee50a8360 100644
--- a/hw/scsi-bus.c
+++ b/hw/scsi-bus.c
@@ -23,6 +23,42 @@ static struct BusInfo scsi_bus_info = {
 };
 static int next_scsi_bus;
 
+static int scsi_device_init(SCSIDevice *s)
+{
+    SCSIDeviceClass *sc = SCSI_DEVICE_GET_CLASS(s);
+    if (sc->init) {
+        return sc->init(s);
+    }
+    return 0;
+}
+
+static void scsi_device_destroy(SCSIDevice *s)
+{
+    SCSIDeviceClass *sc = SCSI_DEVICE_GET_CLASS(s);
+    if (sc->destroy) {
+        sc->destroy(s);
+    }
+}
+
+static SCSIRequest *scsi_device_alloc_req(SCSIDevice *s, uint32_t tag, uint32_t lun,
+                                          uint8_t *buf, void *hba_private)
+{
+    SCSIDeviceClass *sc = SCSI_DEVICE_GET_CLASS(s);
+    if (sc->alloc_req) {
+        return sc->alloc_req(s, tag, lun, buf, hba_private);
+    }
+
+    return NULL;
+}
+
+static void scsi_device_unit_attention_reported(SCSIDevice *s)
+{
+    SCSIDeviceClass *sc = SCSI_DEVICE_GET_CLASS(s);
+    if (sc->unit_attention_reported) {
+        sc->unit_attention_reported(s);
+    }
+}
+
 /* Create a scsi bus, and attach devices to it.  */
 void scsi_bus_new(SCSIBus *bus, DeviceState *host, const SCSIBusInfo *info)
 {
@@ -79,10 +115,9 @@ static void scsi_dma_restart_cb(void *opaque, int running, RunState state)
     }
 }
 
-static int scsi_qdev_init(DeviceState *qdev, DeviceInfo *base)
+static int scsi_qdev_init(DeviceState *qdev)
 {
-    SCSIDevice *dev = DO_UPCAST(SCSIDevice, qdev, qdev);
-    SCSIDeviceInfo *info = DO_UPCAST(SCSIDeviceInfo, qdev, base);
+    SCSIDevice *dev = SCSI_DEVICE(qdev);
     SCSIBus *bus = DO_UPCAST(SCSIBus, qbus, dev->qdev.parent_bus);
     SCSIDevice *d;
     int rc = -1;
@@ -126,9 +161,8 @@ static int scsi_qdev_init(DeviceState *qdev, DeviceInfo *base)
         }
     }
 
-    dev->info = info;
     QTAILQ_INIT(&dev->requests);
-    rc = dev->info->init(dev);
+    rc = scsi_device_init(dev);
     if (rc == 0) {
         dev->vmsentry = qemu_add_vm_change_state_handler(scsi_dma_restart_cb,
                                                          dev);
@@ -140,26 +174,15 @@ err:
 
 static int scsi_qdev_exit(DeviceState *qdev)
 {
-    SCSIDevice *dev = DO_UPCAST(SCSIDevice, qdev, qdev);
+    SCSIDevice *dev = SCSI_DEVICE(qdev);
 
     if (dev->vmsentry) {
         qemu_del_vm_change_state_handler(dev->vmsentry);
     }
-    if (dev->info->destroy) {
-        dev->info->destroy(dev);
-    }
+    scsi_device_destroy(dev);
     return 0;
 }
 
-void scsi_qdev_register(SCSIDeviceInfo *info)
-{
-    info->qdev.bus_info = &scsi_bus_info;
-    info->qdev.init     = scsi_qdev_init;
-    info->qdev.unplug   = qdev_simple_unplug_cb;
-    info->qdev.exit     = scsi_qdev_exit;
-    qdev_register(&info->qdev);
-}
-
 /* handle legacy '-drive if=scsi,...' cmd line args */
 SCSIDevice *scsi_bus_legacy_add_drive(SCSIBus *bus, BlockDriverState *bdrv,
                                       int unit, bool removable, int bootindex)
@@ -182,7 +205,7 @@ SCSIDevice *scsi_bus_legacy_add_drive(SCSIBus *bus, BlockDriverState *bdrv,
     }
     if (qdev_init(dev) < 0)
         return NULL;
-    return DO_UPCAST(SCSIDevice, qdev, dev);
+    return SCSI_DEVICE(dev);
 }
 
 int scsi_bus_legacy_handle_cmdline(SCSIBus *bus)
@@ -278,7 +301,7 @@ static bool scsi_target_emulate_report_luns(SCSITargetReq *r)
     found_lun0 = false;
     n = 0;
     QTAILQ_FOREACH(qdev, &r->req.bus->qbus.children, sibling) {
-        SCSIDevice *dev = DO_UPCAST(SCSIDevice, qdev, qdev);
+        SCSIDevice *dev = SCSI_DEVICE(qdev);
 
         if (dev->channel == channel && dev->id == id) {
             if (dev->lun == 0) {
@@ -300,7 +323,7 @@ static bool scsi_target_emulate_report_luns(SCSITargetReq *r)
     stl_be_p(&r->buf, n);
     i = found_lun0 ? 8 : 16;
     QTAILQ_FOREACH(qdev, &r->req.bus->qbus.children, sibling) {
-        SCSIDevice *dev = DO_UPCAST(SCSIDevice, qdev, qdev);
+        SCSIDevice *dev = SCSI_DEVICE(qdev);
 
         if (dev->channel == channel && dev->id == id) {
             store_lun(&r->buf[i], dev->lun);
@@ -398,9 +421,7 @@ static int32_t scsi_target_send_command(SCSIRequest *req, uint8_t *buf)
                                        MIN(req->cmd.xfer, sizeof r->buf),
                                        (req->cmd.buf[1] & 1) == 0);
         if (r->req.dev->sense_is_ua) {
-            if (r->req.dev->info->unit_attention_reported) {
-                r->req.dev->info->unit_attention_reported(req->dev);
-            }
+            scsi_device_unit_attention_reported(req->dev);
             r->req.dev->sense_len = 0;
             r->req.dev->sense_is_ua = false;
         }
@@ -507,7 +528,7 @@ SCSIRequest *scsi_req_new(SCSIDevice *d, uint32_t tag, uint32_t lun,
             req = scsi_req_alloc(&reqops_target_command, d, tag, lun,
                                  hba_private);
         } else {
-            req = d->info->alloc_req(d, tag, lun, buf, hba_private);
+            req = scsi_device_alloc_req(d, tag, lun, buf, hba_private);
         }
     }
 
@@ -597,9 +618,7 @@ int scsi_req_get_sense(SCSIRequest *req, uint8_t *buf, int len)
      * Here we handle unit attention clearing for UA_INTLCK_CTRL == 00b.
      */
     if (req->dev->sense_is_ua) {
-        if (req->dev->info->unit_attention_reported) {
-            req->dev->info->unit_attention_reported(req->dev);
-        }
+        scsi_device_unit_attention_reported(req->dev);
         req->dev->sense_len = 0;
         req->dev->sense_is_ua = false;
     }
@@ -1367,7 +1386,7 @@ void scsi_device_purge_requests(SCSIDevice *sdev, SCSISense sense)
 
 static char *scsibus_get_fw_dev_path(DeviceState *dev)
 {
-    SCSIDevice *d = DO_UPCAST(SCSIDevice, qdev, dev);
+    SCSIDevice *d = SCSI_DEVICE(dev);
     char path[100];
 
     snprintf(path, sizeof(path), "channel@%x/%s@%x,%x", d->channel,
@@ -1382,7 +1401,7 @@ SCSIDevice *scsi_device_find(SCSIBus *bus, int channel, int id, int lun)
     SCSIDevice *target_dev = NULL;
 
     QTAILQ_FOREACH_REVERSE(qdev, &bus->qbus.children, ChildrenHead, sibling) {
-        SCSIDevice *dev = DO_UPCAST(SCSIDevice, qdev, qdev);
+        SCSIDevice *dev = SCSI_DEVICE(qdev);
 
         if (dev->channel == channel && dev->id == id) {
             if (dev->lun == lun) {
@@ -1393,3 +1412,28 @@ SCSIDevice *scsi_device_find(SCSIBus *bus, int channel, int id, int lun)
     }
     return target_dev;
 }
+
+static void scsi_device_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *k = DEVICE_CLASS(klass);
+    k->bus_info = &scsi_bus_info;
+    k->init     = scsi_qdev_init;
+    k->unplug   = qdev_simple_unplug_cb;
+    k->exit     = scsi_qdev_exit;
+}
+
+static TypeInfo scsi_device_type_info = {
+    .name = TYPE_SCSI_DEVICE,
+    .parent = TYPE_DEVICE,
+    .instance_size = sizeof(SCSIDevice),
+    .abstract = true,
+    .class_size = sizeof(SCSIDeviceClass),
+    .class_init = scsi_device_class_init,
+};
+
+static void scsi_register_devices(void)
+{
+    type_register_static(&scsi_device_type_info);
+}
+
+device_init(scsi_register_devices);
diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index 5d8bf53586..399e51e494 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -391,9 +391,6 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
             }
 
             l = strlen(s->serial);
-            if (l > req->cmd.xfer) {
-                l = req->cmd.xfer;
-            }
             if (l > 20) {
                 l = 20;
             }
@@ -1002,9 +999,6 @@ static int scsi_disk_emulate_mode_sense(SCSIDiskReq *r, uint8_t *outbuf)
         outbuf[0] = ((buflen - 2) >> 8) & 0xff;
         outbuf[1] = (buflen - 2) & 0xff;
     }
-    if (buflen > r->req.cmd.xfer) {
-        buflen = r->req.cmd.xfer;
-    }
     return buflen;
 }
 
@@ -1038,9 +1032,6 @@ static int scsi_disk_emulate_read_toc(SCSIRequest *req, uint8_t *outbuf)
     default:
         return -1;
     }
-    if (toclen > req->cmd.xfer) {
-        toclen = req->cmd.xfer;
-    }
     return toclen;
 }
 
@@ -1251,6 +1242,7 @@ static int scsi_disk_emulate_command(SCSIDiskReq *r)
         scsi_check_condition(r, SENSE_CODE(INVALID_OPCODE));
         return -1;
     }
+    buflen = MIN(buflen, req->cmd.xfer);
     return buflen;
 
 not_ready:
@@ -1720,75 +1712,124 @@ static SCSIRequest *scsi_block_new_request(SCSIDevice *d, uint32_t tag,
     DEFINE_PROP_STRING("ver",  SCSIDiskState, version),         \
     DEFINE_PROP_STRING("serial",  SCSIDiskState, serial)
 
-static SCSIDeviceInfo scsi_disk_info[] = {
-    {
-        .qdev.name    = "scsi-hd",
-        .qdev.fw_name = "disk",
-        .qdev.desc    = "virtual SCSI disk",
-        .qdev.size    = sizeof(SCSIDiskState),
-        .qdev.reset   = scsi_disk_reset,
-        .init         = scsi_hd_initfn,
-        .destroy      = scsi_destroy,
-        .alloc_req    = scsi_new_request,
-        .unit_attention_reported = scsi_disk_unit_attention_reported,
-        .qdev.props   = (Property[]) {
-            DEFINE_SCSI_DISK_PROPERTIES(),
-            DEFINE_PROP_BIT("removable", SCSIDiskState, removable, 0, false),
-            DEFINE_PROP_END_OF_LIST(),
-        }
-    },{
-        .qdev.name    = "scsi-cd",
-        .qdev.fw_name = "disk",
-        .qdev.desc    = "virtual SCSI CD-ROM",
-        .qdev.size    = sizeof(SCSIDiskState),
-        .qdev.reset   = scsi_disk_reset,
-        .init         = scsi_cd_initfn,
-        .destroy      = scsi_destroy,
-        .alloc_req    = scsi_new_request,
-        .unit_attention_reported = scsi_disk_unit_attention_reported,
-        .qdev.props   = (Property[]) {
-            DEFINE_SCSI_DISK_PROPERTIES(),
-            DEFINE_PROP_END_OF_LIST(),
-        },
+static Property scsi_hd_properties[] = {
+    DEFINE_SCSI_DISK_PROPERTIES(),
+    DEFINE_PROP_BIT("removable", SCSIDiskState, removable, 0, false),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void scsi_hd_class_initfn(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SCSIDeviceClass *sc = SCSI_DEVICE_CLASS(klass);
+
+    sc->init         = scsi_hd_initfn;
+    sc->destroy      = scsi_destroy;
+    sc->alloc_req    = scsi_new_request;
+    sc->unit_attention_reported = scsi_disk_unit_attention_reported;
+    dc->fw_name = "disk";
+    dc->desc = "virtual SCSI disk";
+    dc->reset = scsi_disk_reset;
+    dc->props = scsi_hd_properties;
+}
+
+static TypeInfo scsi_hd_info = {
+    .name          = "scsi-hd",
+    .parent        = TYPE_SCSI_DEVICE,
+    .instance_size = sizeof(SCSIDiskState),
+    .class_init    = scsi_hd_class_initfn,
+};
+
+static Property scsi_cd_properties[] = {
+    DEFINE_SCSI_DISK_PROPERTIES(),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void scsi_cd_class_initfn(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SCSIDeviceClass *sc = SCSI_DEVICE_CLASS(klass);
+
+    sc->init         = scsi_cd_initfn;
+    sc->destroy      = scsi_destroy;
+    sc->alloc_req    = scsi_new_request;
+    sc->unit_attention_reported = scsi_disk_unit_attention_reported;
+    dc->fw_name = "disk";
+    dc->desc = "virtual SCSI CD-ROM";
+    dc->reset = scsi_disk_reset;
+    dc->props = scsi_cd_properties;
+}
+
+static TypeInfo scsi_cd_info = {
+    .name          = "scsi-cd",
+    .parent        = TYPE_SCSI_DEVICE,
+    .instance_size = sizeof(SCSIDiskState),
+    .class_init    = scsi_cd_class_initfn,
+};
+
 #ifdef __linux__
-    },{
-        .qdev.name    = "scsi-block",
-        .qdev.fw_name = "disk",
-        .qdev.desc    = "SCSI block device passthrough",
-        .qdev.size    = sizeof(SCSIDiskState),
-        .qdev.reset   = scsi_disk_reset,
-        .init         = scsi_block_initfn,
-        .destroy      = scsi_destroy,
-        .alloc_req    = scsi_block_new_request,
-        .qdev.props   = (Property[]) {
-            DEFINE_SCSI_DISK_PROPERTIES(),
-            DEFINE_PROP_END_OF_LIST(),
-        },
+static Property scsi_block_properties[] = {
+    DEFINE_SCSI_DISK_PROPERTIES(),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void scsi_block_class_initfn(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SCSIDeviceClass *sc = SCSI_DEVICE_CLASS(klass);
+
+    sc->init         = scsi_block_initfn;
+    sc->destroy      = scsi_destroy;
+    sc->alloc_req    = scsi_block_new_request;
+    dc->fw_name = "disk";
+    dc->desc = "SCSI block device passthrough";
+    dc->reset = scsi_disk_reset;
+    dc->props = scsi_block_properties;
+}
+
+static TypeInfo scsi_block_info = {
+    .name          = "scsi-block",
+    .parent        = TYPE_SCSI_DEVICE,
+    .instance_size = sizeof(SCSIDiskState),
+    .class_init    = scsi_block_class_initfn,
+};
 #endif
-    },{
-        .qdev.name    = "scsi-disk", /* legacy -device scsi-disk */
-        .qdev.fw_name = "disk",
-        .qdev.desc    = "virtual SCSI disk or CD-ROM (legacy)",
-        .qdev.size    = sizeof(SCSIDiskState),
-        .qdev.reset   = scsi_disk_reset,
-        .init         = scsi_disk_initfn,
-        .destroy      = scsi_destroy,
-        .alloc_req    = scsi_new_request,
-        .unit_attention_reported = scsi_disk_unit_attention_reported,
-        .qdev.props   = (Property[]) {
-            DEFINE_SCSI_DISK_PROPERTIES(),
-            DEFINE_PROP_BIT("removable", SCSIDiskState, removable, 0, false),
-            DEFINE_PROP_END_OF_LIST(),
-        }
-    }
+
+static Property scsi_disk_properties[] = {
+    DEFINE_SCSI_DISK_PROPERTIES(),
+    DEFINE_PROP_BIT("removable", SCSIDiskState, removable, 0, false),
+    DEFINE_PROP_END_OF_LIST(),
 };
 
-static void scsi_disk_register_devices(void)
+static void scsi_disk_class_initfn(ObjectClass *klass, void *data)
 {
-    int i;
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SCSIDeviceClass *sc = SCSI_DEVICE_CLASS(klass);
+
+    sc->init         = scsi_disk_initfn;
+    sc->destroy      = scsi_destroy;
+    sc->alloc_req    = scsi_new_request;
+    sc->unit_attention_reported = scsi_disk_unit_attention_reported;
+    dc->fw_name = "disk";
+    dc->desc = "virtual SCSI disk or CD-ROM (legacy)";
+    dc->reset = scsi_disk_reset;
+    dc->props = scsi_disk_properties;
+}
 
-    for (i = 0; i < ARRAY_SIZE(scsi_disk_info); i++) {
-        scsi_qdev_register(&scsi_disk_info[i]);
-    }
+static TypeInfo scsi_disk_info = {
+    .name          = "scsi-disk",
+    .parent        = TYPE_SCSI_DEVICE,
+    .instance_size = sizeof(SCSIDiskState),
+    .class_init    = scsi_disk_class_initfn,
+};
+
+static void scsi_disk_register_devices(void)
+{
+    type_register_static(&scsi_hd_info);
+    type_register_static(&scsi_cd_info);
+#ifdef __linux__
+    type_register_static(&scsi_block_info);
+#endif
+    type_register_static(&scsi_disk_info);
 }
 device_init(scsi_disk_register_devices)
diff --git a/hw/scsi-generic.c b/hw/scsi-generic.c
index 0aebcddf6e..4859212734 100644
--- a/hw/scsi-generic.c
+++ b/hw/scsi-generic.c
@@ -357,7 +357,7 @@ static int get_stream_blocksize(BlockDriverState *bdrv)
 
 static void scsi_generic_reset(DeviceState *dev)
 {
-    SCSIDevice *s = DO_UPCAST(SCSIDevice, qdev, dev);
+    SCSIDevice *s = SCSI_DEVICE(dev);
 
     scsi_device_purge_requests(s, SENSE_CODE(RESET));
 }
@@ -457,24 +457,35 @@ static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun,
     return req;
 }
 
-static SCSIDeviceInfo scsi_generic_info = {
-    .qdev.name    = "scsi-generic",
-    .qdev.fw_name = "disk",
-    .qdev.desc    = "pass through generic scsi device (/dev/sg*)",
-    .qdev.size    = sizeof(SCSIDevice),
-    .qdev.reset   = scsi_generic_reset,
-    .init         = scsi_generic_initfn,
-    .destroy      = scsi_destroy,
-    .alloc_req    = scsi_new_request,
-    .qdev.props   = (Property[]) {
-        DEFINE_BLOCK_PROPERTIES(SCSIDevice, conf),
-        DEFINE_PROP_END_OF_LIST(),
-    },
+static Property scsi_generic_properties[] = {
+    DEFINE_BLOCK_PROPERTIES(SCSIDevice, conf),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void scsi_generic_class_initfn(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SCSIDeviceClass *sc = SCSI_DEVICE_CLASS(klass);
+
+    sc->init         = scsi_generic_initfn;
+    sc->destroy      = scsi_destroy;
+    sc->alloc_req    = scsi_new_request;
+    dc->fw_name = "disk";
+    dc->desc = "pass through generic scsi device (/dev/sg*)";
+    dc->reset = scsi_generic_reset;
+    dc->props = scsi_generic_properties;
+}
+
+static TypeInfo scsi_generic_info = {
+    .name          = "scsi-generic",
+    .parent        = TYPE_SCSI_DEVICE,
+    .instance_size = sizeof(SCSIDevice),
+    .class_init    = scsi_generic_class_initfn,
 };
 
 static void scsi_generic_register_devices(void)
 {
-    scsi_qdev_register(&scsi_generic_info);
+    type_register_static(&scsi_generic_info);
 }
 device_init(scsi_generic_register_devices)
 
diff --git a/hw/scsi.h b/hw/scsi.h
index ab6e952327..dc72b6fc1e 100644
--- a/hw/scsi.h
+++ b/hw/scsi.h
@@ -13,7 +13,6 @@ typedef struct SCSIBus SCSIBus;
 typedef struct SCSIBusInfo SCSIBusInfo;
 typedef struct SCSICommand SCSICommand;
 typedef struct SCSIDevice SCSIDevice;
-typedef struct SCSIDeviceInfo SCSIDeviceInfo;
 typedef struct SCSIRequest SCSIRequest;
 typedef struct SCSIReqOps SCSIReqOps;
 
@@ -58,6 +57,23 @@ struct SCSIRequest {
     QTAILQ_ENTRY(SCSIRequest) next;
 };
 
+#define TYPE_SCSI_DEVICE "scsi-device"
+#define SCSI_DEVICE(obj) \
+     OBJECT_CHECK(SCSIDevice, (obj), TYPE_SCSI_DEVICE)
+#define SCSI_DEVICE_CLASS(klass) \
+     OBJECT_CLASS_CHECK(SCSIDeviceClass, (klass), TYPE_SCSI_DEVICE)
+#define SCSI_DEVICE_GET_CLASS(obj) \
+     OBJECT_GET_CLASS(SCSIDeviceClass, (obj), TYPE_SCSI_DEVICE)
+
+typedef struct SCSIDeviceClass {
+    DeviceClass parent_class;
+    int (*init)(SCSIDevice *dev);
+    void (*destroy)(SCSIDevice *s);
+    SCSIRequest *(*alloc_req)(SCSIDevice *s, uint32_t tag, uint32_t lun,
+                              uint8_t *buf, void *hba_private);
+    void (*unit_attention_reported)(SCSIDevice *s);
+} SCSIDeviceClass;
+
 struct SCSIDevice
 {
     DeviceState qdev;
@@ -65,7 +81,6 @@ struct SCSIDevice
     QEMUBH *bh;
     uint32_t id;
     BlockConf conf;
-    SCSIDeviceInfo *info;
     SCSISense unit_attention;
     bool sense_is_ua;
     uint8_t sense[SCSI_SENSE_BUF_SIZE];
@@ -93,16 +108,6 @@ struct SCSIReqOps {
     uint8_t *(*get_buf)(SCSIRequest *req);
 };
 
-typedef int (*scsi_qdev_initfn)(SCSIDevice *dev);
-struct SCSIDeviceInfo {
-    DeviceInfo qdev;
-    scsi_qdev_initfn init;
-    void (*destroy)(SCSIDevice *s);
-    SCSIRequest *(*alloc_req)(SCSIDevice *s, uint32_t tag, uint32_t lun,
-                              uint8_t *buf, void *hba_private);
-    void (*unit_attention_reported)(SCSIDevice *s);
-};
-
 struct SCSIBusInfo {
     int tcq;
     int max_channel, max_target, max_lun;
@@ -120,7 +125,6 @@ struct SCSIBus {
 };
 
 void scsi_bus_new(SCSIBus *bus, DeviceState *host, const SCSIBusInfo *info);
-void scsi_qdev_register(SCSIDeviceInfo *info);
 
 static inline SCSIBus *scsi_bus_from_device(SCSIDevice *d)
 {
diff --git a/hw/serial.c b/hw/serial.c
index d35c7a9207..82917e24d7 100644
--- a/hw/serial.c
+++ b/hw/serial.c
@@ -879,23 +879,33 @@ SerialState *serial_mm_init(MemoryRegion *address_space,
     return s;
 }
 
-static ISADeviceInfo serial_isa_info = {
-    .qdev.name  = "isa-serial",
-    .qdev.size  = sizeof(ISASerialState),
-    .qdev.vmsd  = &vmstate_isa_serial,
-    .init       = serial_isa_initfn,
-    .qdev.props = (Property[]) {
-        DEFINE_PROP_UINT32("index", ISASerialState, index,   -1),
-        DEFINE_PROP_HEX32("iobase", ISASerialState, iobase,  -1),
-        DEFINE_PROP_UINT32("irq",   ISASerialState, isairq,  -1),
-        DEFINE_PROP_CHR("chardev",  ISASerialState, state.chr),
-        DEFINE_PROP_END_OF_LIST(),
-    },
+static Property serial_isa_properties[] = {
+    DEFINE_PROP_UINT32("index", ISASerialState, index,   -1),
+    DEFINE_PROP_HEX32("iobase", ISASerialState, iobase,  -1),
+    DEFINE_PROP_UINT32("irq",   ISASerialState, isairq,  -1),
+    DEFINE_PROP_CHR("chardev",  ISASerialState, state.chr),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void serial_isa_class_initfn(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    ISADeviceClass *ic = ISA_DEVICE_CLASS(klass);
+    ic->init = serial_isa_initfn;
+    dc->vmsd = &vmstate_isa_serial;
+    dc->props = serial_isa_properties;
+}
+
+static TypeInfo serial_isa_info = {
+    .name          = "isa-serial",
+    .parent        = TYPE_ISA_DEVICE,
+    .instance_size = sizeof(ISASerialState),
+    .class_init    = serial_isa_class_initfn,
 };
 
 static void serial_register_devices(void)
 {
-    isa_qdev_register(&serial_isa_info);
+    type_register_static(&serial_isa_info);
 }
 
 device_init(serial_register_devices)
diff --git a/hw/sga.c b/hw/sga.c
index 7ef750adf6..b08e3c5aea 100644
--- a/hw/sga.c
+++ b/hw/sga.c
@@ -35,22 +35,29 @@ typedef struct ISAGAState {
     ISADevice dev;
 } ISASGAState;
 
-static int isa_cirrus_vga_initfn(ISADevice *dev)
+static int sga_initfn(ISADevice *dev)
 {
     rom_add_vga(SGABIOS_FILENAME);
     return 0;
 }
+static void sga_class_initfn(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    ISADeviceClass *ic = ISA_DEVICE_CLASS(klass);
+    ic->init = sga_initfn;
+    dc->desc = "Serial Graphics Adapter";
+}
 
-static ISADeviceInfo sga_info = {
-    .qdev.name    = "sga",
-    .qdev.desc    = "Serial Graphics Adapter",
-    .qdev.size    = sizeof(ISASGAState),
-    .init         = isa_cirrus_vga_initfn,
+static TypeInfo sga_info = {
+    .name          = "sga",
+    .parent        = TYPE_ISA_DEVICE,
+    .instance_size = sizeof(ISASGAState),
+    .class_init    = sga_class_initfn,
 };
 
 static void sga_register(void)
 {
-      isa_qdev_register(&sga_info);
+    type_register_static(&sga_info);
 }
 
 device_init(sga_register);
diff --git a/hw/sh_pci.c b/hw/sh_pci.c
index d4d028d811..4234d935e7 100644
--- a/hw/sh_pci.c
+++ b/hw/sh_pci.c
@@ -110,7 +110,7 @@ static void sh_pci_set_irq(void *opaque, int irq_num, int level)
     qemu_set_irq(pic[irq_num], level);
 }
 
-static int sh_pci_init_device(SysBusDevice *dev)
+static int sh_pci_device_init(SysBusDevice *dev)
 {
     SHPCIState *s;
     int i;
@@ -147,19 +147,40 @@ static int sh_pci_host_init(PCIDevice *d)
     return 0;
 }
 
-static PCIDeviceInfo sh_pci_host_info = {
-    .qdev.name = "sh_pci_host",
-    .qdev.size = sizeof(PCIDevice),
-    .init      = sh_pci_host_init,
-    .vendor_id = PCI_VENDOR_ID_HITACHI,
-    .device_id = PCI_DEVICE_ID_HITACHI_SH7751R,
+static void sh_pci_host_class_init(ObjectClass *klass, void *data)
+{
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->init = sh_pci_host_init;
+    k->vendor_id = PCI_VENDOR_ID_HITACHI;
+    k->device_id = PCI_DEVICE_ID_HITACHI_SH7751R;
+}
+
+static TypeInfo sh_pci_host_info = {
+    .name          = "sh_pci_host",
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(PCIDevice),
+    .class_init    = sh_pci_host_class_init,
+};
+
+static void sh_pci_device_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+
+    sdc->init = sh_pci_device_init;
+}
+
+static TypeInfo sh_pci_device_info = {
+    .name          = "sh_pci",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(SHPCIState),
+    .class_init    = sh_pci_device_class_init,
 };
 
 static void sh_pci_register_devices(void)
 {
-    sysbus_register_dev("sh_pci", sizeof(SHPCIState),
-                        sh_pci_init_device);
-    pci_qdev_register(&sh_pci_host_info);
+    type_register_static(&sh_pci_device_info);
+    type_register_static(&sh_pci_host_info);
 }
 
 device_init(sh_pci_register_devices)
diff --git a/hw/slavio_intctl.c b/hw/slavio_intctl.c
index 9925e6460b..e3701c75d2 100644
--- a/hw/slavio_intctl.c
+++ b/hw/slavio_intctl.c
@@ -446,17 +446,26 @@ static int slavio_intctl_init1(SysBusDevice *dev)
     return 0;
 }
 
-static SysBusDeviceInfo slavio_intctl_info = {
-    .init = slavio_intctl_init1,
-    .qdev.name  = "slavio_intctl",
-    .qdev.size  = sizeof(SLAVIO_INTCTLState),
-    .qdev.vmsd  = &vmstate_intctl,
-    .qdev.reset = slavio_intctl_reset,
+static void slavio_intctl_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = slavio_intctl_init1;
+    dc->reset = slavio_intctl_reset;
+    dc->vmsd = &vmstate_intctl;
+}
+
+static TypeInfo slavio_intctl_info = {
+    .name          = "slavio_intctl",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(SLAVIO_INTCTLState),
+    .class_init    = slavio_intctl_class_init,
 };
 
 static void slavio_intctl_register_devices(void)
 {
-    sysbus_register_withprop(&slavio_intctl_info);
+    type_register_static(&slavio_intctl_info);
 }
 
 device_init(slavio_intctl_register_devices)
diff --git a/hw/slavio_misc.c b/hw/slavio_misc.c
index 484301c48a..5a025186af 100644
--- a/hw/slavio_misc.c
+++ b/hw/slavio_misc.c
@@ -468,24 +468,41 @@ static int slavio_misc_init1(SysBusDevice *dev)
     return 0;
 }
 
-static SysBusDeviceInfo slavio_misc_info = {
-    .init = slavio_misc_init1,
-    .qdev.name  = "slavio_misc",
-    .qdev.size  = sizeof(MiscState),
-    .qdev.vmsd  = &vmstate_misc,
-    .qdev.reset  = slavio_misc_reset,
+static void slavio_misc_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = slavio_misc_init1;
+    dc->reset = slavio_misc_reset;
+    dc->vmsd = &vmstate_misc;
+}
+
+static TypeInfo slavio_misc_info = {
+    .name          = "slavio_misc",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(MiscState),
+    .class_init    = slavio_misc_class_init,
 };
 
-static SysBusDeviceInfo apc_info = {
-    .init = apc_init1,
-    .qdev.name  = "apc",
-    .qdev.size  = sizeof(MiscState),
+static void apc_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = apc_init1;
+}
+
+static TypeInfo apc_info = {
+    .name          = "apc",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(MiscState),
+    .class_init    = apc_class_init,
 };
 
 static void slavio_misc_register_devices(void)
 {
-    sysbus_register_withprop(&slavio_misc_info);
-    sysbus_register_withprop(&apc_info);
+    type_register_static(&slavio_misc_info);
+    type_register_static(&apc_info);
 }
 
 device_init(slavio_misc_register_devices)
diff --git a/hw/slavio_timer.c b/hw/slavio_timer.c
index 44b500a5fa..3878f6fa5e 100644
--- a/hw/slavio_timer.c
+++ b/hw/slavio_timer.c
@@ -404,21 +404,32 @@ static int slavio_timer_init1(SysBusDevice *dev)
     return 0;
 }
 
-static SysBusDeviceInfo slavio_timer_info = {
-    .init = slavio_timer_init1,
-    .qdev.name  = "slavio_timer",
-    .qdev.size  = sizeof(SLAVIO_TIMERState),
-    .qdev.vmsd  = &vmstate_slavio_timer,
-    .qdev.reset = slavio_timer_reset,
-    .qdev.props = (Property[]) {
-        DEFINE_PROP_UINT32("num_cpus",  SLAVIO_TIMERState, num_cpus,  0),
-        DEFINE_PROP_END_OF_LIST(),
-    }
+static Property slavio_timer_properties[] = {
+    DEFINE_PROP_UINT32("num_cpus",  SLAVIO_TIMERState, num_cpus,  0),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void slavio_timer_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = slavio_timer_init1;
+    dc->reset = slavio_timer_reset;
+    dc->vmsd = &vmstate_slavio_timer;
+    dc->props = slavio_timer_properties;
+}
+
+static TypeInfo slavio_timer_info = {
+    .name          = "slavio_timer",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(SLAVIO_TIMERState),
+    .class_init    = slavio_timer_class_init,
 };
 
 static void slavio_timer_register_devices(void)
 {
-    sysbus_register_withprop(&slavio_timer_info);
+    type_register_static(&slavio_timer_info);
 }
 
 device_init(slavio_timer_register_devices)
diff --git a/hw/sm501.c b/hw/sm501.c
index 09c5894cf9..94c0abf4cb 100644
--- a/hw/sm501.c
+++ b/hw/sm501.c
@@ -1323,15 +1323,12 @@ static void sm501_draw_crt(SM501State * s)
     for (y = 0; y < height; y++) {
 	int update_hwc = draw_hwc_line ? within_hwc_y_range(s, y, 1) : 0;
 	int update = full_update || update_hwc;
-	ram_addr_t page0 = offset & TARGET_PAGE_MASK;
-	ram_addr_t page1 = (offset + width * src_bpp - 1) & TARGET_PAGE_MASK;
-	ram_addr_t page;
+        ram_addr_t page0 = offset;
+        ram_addr_t page1 = offset + width * src_bpp - 1;
 
 	/* check dirty flags for each line */
-	for (page = page0; page <= page1; page += TARGET_PAGE_SIZE)
-            if (memory_region_get_dirty(&s->local_mem_region, page,
-                                        DIRTY_MEMORY_VGA))
-		update = 1;
+        update = memory_region_get_dirty(&s->local_mem_region, page0, page1,
+                                         DIRTY_MEMORY_VGA);
 
 	/* draw line and change status */
 	if (update) {
diff --git a/hw/smbus.c b/hw/smbus.c
index ff027c814f..77626f3645 100644
--- a/hw/smbus.c
+++ b/hw/smbus.c
@@ -37,37 +37,38 @@ enum {
 
 static void smbus_do_quick_cmd(SMBusDevice *dev, int recv)
 {
-    SMBusDeviceInfo *t = container_of(dev->i2c.info, SMBusDeviceInfo, i2c);
+    SMBusDeviceClass *sc = SMBUS_DEVICE_GET_CLASS(dev);
 
     DPRINTF("Quick Command %d\n", recv);
-    if (t->quick_cmd)
-        t->quick_cmd(dev, recv);
+    if (sc->quick_cmd) {
+        sc->quick_cmd(dev, recv);
+    }
 }
 
 static void smbus_do_write(SMBusDevice *dev)
 {
-    SMBusDeviceInfo *t = container_of(dev->i2c.info, SMBusDeviceInfo, i2c);
+    SMBusDeviceClass *sc = SMBUS_DEVICE_GET_CLASS(dev);
 
     if (dev->data_len == 0) {
         smbus_do_quick_cmd(dev, 0);
     } else if (dev->data_len == 1) {
         DPRINTF("Send Byte\n");
-        if (t->send_byte) {
-            t->send_byte(dev, dev->data_buf[0]);
+        if (sc->send_byte) {
+            sc->send_byte(dev, dev->data_buf[0]);
         }
     } else {
         dev->command = dev->data_buf[0];
         DPRINTF("Command %d len %d\n", dev->command, dev->data_len - 1);
-        if (t->write_data) {
-            t->write_data(dev, dev->command, dev->data_buf + 1,
-                          dev->data_len - 1);
+        if (sc->write_data) {
+            sc->write_data(dev, dev->command, dev->data_buf + 1,
+                           dev->data_len - 1);
         }
     }
 }
 
-static void smbus_i2c_event(i2c_slave *s, enum i2c_event event)
+static void smbus_i2c_event(I2CSlave *s, enum i2c_event event)
 {
-    SMBusDevice *dev = FROM_I2C_SLAVE(SMBusDevice, s);
+    SMBusDevice *dev = SMBUS_DEVICE(s);
 
     switch (event) {
     case I2C_START_SEND:
@@ -148,16 +149,16 @@ static void smbus_i2c_event(i2c_slave *s, enum i2c_event event)
     }
 }
 
-static int smbus_i2c_recv(i2c_slave *s)
+static int smbus_i2c_recv(I2CSlave *s)
 {
-    SMBusDeviceInfo *t = container_of(s->info, SMBusDeviceInfo, i2c);
-    SMBusDevice *dev = FROM_I2C_SLAVE(SMBusDevice, s);
+    SMBusDevice *dev = SMBUS_DEVICE(s);
+    SMBusDeviceClass *sc = SMBUS_DEVICE_GET_CLASS(dev);
     int ret;
 
     switch (dev->mode) {
     case SMBUS_RECV_BYTE:
-        if (t->receive_byte) {
-            ret = t->receive_byte(dev);
+        if (sc->receive_byte) {
+            ret = sc->receive_byte(dev);
         } else {
             ret = 0;
         }
@@ -165,8 +166,8 @@ static int smbus_i2c_recv(i2c_slave *s)
         dev->mode = SMBUS_DONE;
         break;
     case SMBUS_READ_DATA:
-        if (t->read_data) {
-            ret = t->read_data(dev, dev->command, dev->data_len);
+        if (sc->read_data) {
+            ret = sc->read_data(dev, dev->command, dev->data_len);
             dev->data_len++;
         } else {
             ret = 0;
@@ -182,9 +183,9 @@ static int smbus_i2c_recv(i2c_slave *s)
     return ret;
 }
 
-static int smbus_i2c_send(i2c_slave *s, uint8_t data)
+static int smbus_i2c_send(I2CSlave *s, uint8_t data)
 {
-    SMBusDevice *dev = FROM_I2C_SLAVE(SMBusDevice, s);
+    SMBusDevice *dev = SMBUS_DEVICE(s);
 
     switch (dev->mode) {
     case SMBUS_WRITE_DATA:
@@ -198,22 +199,12 @@ static int smbus_i2c_send(i2c_slave *s, uint8_t data)
     return 0;
 }
 
-static int smbus_device_init(i2c_slave *i2c)
+static int smbus_device_init(I2CSlave *i2c)
 {
-    SMBusDeviceInfo *t = container_of(i2c->info, SMBusDeviceInfo, i2c);
-    SMBusDevice *dev = FROM_I2C_SLAVE(SMBusDevice, i2c);
-
-    return t->init(dev);
-}
+    SMBusDevice *dev = SMBUS_DEVICE(i2c);
+    SMBusDeviceClass *sc = SMBUS_DEVICE_GET_CLASS(dev);
 
-void smbus_register_device(SMBusDeviceInfo *info)
-{
-    assert(info->i2c.qdev.size >= sizeof(SMBusDevice));
-    info->i2c.init = smbus_device_init;
-    info->i2c.event = smbus_i2c_event;
-    info->i2c.recv = smbus_i2c_recv;
-    info->i2c.send = smbus_i2c_send;
-    i2c_register_slave(&info->i2c);
+    return sc->init(dev);
 }
 
 /* Master device commands.  */
@@ -316,3 +307,29 @@ void smbus_write_block(i2c_bus *bus, uint8_t addr, uint8_t command, uint8_t *dat
         i2c_send(bus, data[i]);
     i2c_end_transfer(bus);
 }
+
+static void smbus_device_class_init(ObjectClass *klass, void *data)
+{
+    I2CSlaveClass *sc = I2C_SLAVE_CLASS(klass);
+
+    sc->init = smbus_device_init;
+    sc->event = smbus_i2c_event;
+    sc->recv = smbus_i2c_recv;
+    sc->send = smbus_i2c_send;
+}
+
+static TypeInfo smbus_device_type_info = {
+    .name = TYPE_SMBUS_DEVICE,
+    .parent = TYPE_I2C_SLAVE,
+    .instance_size = sizeof(SMBusDevice),
+    .abstract = true,
+    .class_size = sizeof(SMBusDeviceClass),
+    .class_init = smbus_device_class_init,
+};
+
+static void smbus_device_register_devices(void)
+{
+    type_register_static(&smbus_device_type_info);
+}
+
+device_init(smbus_device_register_devices);
diff --git a/hw/smbus.h b/hw/smbus.h
index a39871593b..6ed45bd03d 100644
--- a/hw/smbus.h
+++ b/hw/smbus.h
@@ -1,3 +1,6 @@
+#ifndef QEMU_SMBUS_H
+#define QEMU_SMBUS_H
+
 /*
  * QEMU SMBus API
  *
@@ -24,19 +27,17 @@
 
 #include "i2c.h"
 
-struct SMBusDevice {
-    /* The SMBus protocol is implemented on top of I2C.  */
-    i2c_slave i2c;
-
-    /* Remaining fields for internal use only.  */
-    int mode;
-    int data_len;
-    uint8_t data_buf[34]; /* command + len + 32 bytes of data.  */
-    uint8_t command;
-};
+#define TYPE_SMBUS_DEVICE "smbus-device"
+#define SMBUS_DEVICE(obj) \
+     OBJECT_CHECK(SMBusDevice, (obj), TYPE_SMBUS_DEVICE)
+#define SMBUS_DEVICE_CLASS(klass) \
+     OBJECT_CLASS_CHECK(SMBusDeviceClass, (klass), TYPE_SMBUS_DEVICE)
+#define SMBUS_DEVICE_GET_CLASS(obj) \
+     OBJECT_GET_CLASS(SMBusDeviceClass, (obj), TYPE_SMBUS_DEVICE)
 
-typedef struct {
-    I2CSlaveInfo i2c;
+typedef struct SMBusDeviceClass
+{
+    I2CSlaveClass parent_class;
     int (*init)(SMBusDevice *dev);
     void (*quick_cmd)(SMBusDevice *dev, uint8_t read);
     void (*send_byte)(SMBusDevice *dev, uint8_t val);
@@ -51,9 +52,18 @@ typedef struct {
        byte at a time.  The device is responsible for adding the length
        byte on block reads.  */
     uint8_t (*read_data)(SMBusDevice *dev, uint8_t cmd, int n);
-} SMBusDeviceInfo;
+} SMBusDeviceClass;
 
-void smbus_register_device(SMBusDeviceInfo *info);
+struct SMBusDevice {
+    /* The SMBus protocol is implemented on top of I2C.  */
+    I2CSlave i2c;
+
+    /* Remaining fields for internal use only.  */
+    int mode;
+    int data_len;
+    uint8_t data_buf[34]; /* command + len + 32 bytes of data.  */
+    uint8_t command;
+};
 
 /* Master device commands.  */
 void smbus_quick_command(i2c_bus *bus, uint8_t addr, int read);
@@ -69,3 +79,5 @@ void smbus_write_block(i2c_bus *bus, uint8_t addr, uint8_t command, uint8_t *dat
 
 void smbus_eeprom_init(i2c_bus *smbus, int nb_eeprom,
                        const uint8_t *eeprom_spd, int size);
+
+#endif
diff --git a/hw/smbus_eeprom.c b/hw/smbus_eeprom.c
index 5d080abed7..9d96cbe41a 100644
--- a/hw/smbus_eeprom.c
+++ b/hw/smbus_eeprom.c
@@ -104,24 +104,35 @@ static int smbus_eeprom_initfn(SMBusDevice *dev)
     return 0;
 }
 
-static SMBusDeviceInfo smbus_eeprom_info = {
-    .i2c.qdev.name = "smbus-eeprom",
-    .i2c.qdev.size = sizeof(SMBusEEPROMDevice),
-    .i2c.qdev.props = (Property[]) {
-        DEFINE_PROP_PTR("data", SMBusEEPROMDevice, data),
-        DEFINE_PROP_END_OF_LIST(),
-    },
-    .init = smbus_eeprom_initfn,
-    .quick_cmd = eeprom_quick_cmd,
-    .send_byte = eeprom_send_byte,
-    .receive_byte = eeprom_receive_byte,
-    .write_data = eeprom_write_data,
-    .read_data = eeprom_read_data
+static Property smbus_eeprom_properties[] = {
+    DEFINE_PROP_PTR("data", SMBusEEPROMDevice, data),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void smbus_eeprom_class_initfn(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SMBusDeviceClass *sc = SMBUS_DEVICE_CLASS(klass);
+
+    sc->init = smbus_eeprom_initfn;
+    sc->quick_cmd = eeprom_quick_cmd;
+    sc->send_byte = eeprom_send_byte;
+    sc->receive_byte = eeprom_receive_byte;
+    sc->write_data = eeprom_write_data;
+    sc->read_data = eeprom_read_data;
+    dc->props = smbus_eeprom_properties;
+}
+
+static TypeInfo smbus_eeprom_info = {
+    .name          = "smbus-eeprom",
+    .parent        = TYPE_SMBUS_DEVICE,
+    .instance_size = sizeof(SMBusEEPROMDevice),
+    .class_init    = smbus_eeprom_class_initfn,
 };
 
 static void smbus_eeprom_register_devices(void)
 {
-    smbus_register_device(&smbus_eeprom_info);
+    type_register_static(&smbus_eeprom_info);
 }
 
 device_init(smbus_eeprom_register_devices)
diff --git a/hw/smc91c111.c b/hw/smc91c111.c
index 82b8811459..1bf2901d1a 100644
--- a/hw/smc91c111.c
+++ b/hw/smc91c111.c
@@ -752,27 +752,38 @@ static int smc91c111_init1(SysBusDevice *dev)
     sysbus_init_irq(dev, &s->irq);
     qemu_macaddr_default_if_unset(&s->conf.macaddr);
     s->nic = qemu_new_nic(&net_smc91c111_info, &s->conf,
-                          dev->qdev.info->name, dev->qdev.id, s);
+                          object_get_typename(OBJECT(dev)), dev->qdev.id, s);
     qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a);
     /* ??? Save/restore.  */
     return 0;
 }
 
-static SysBusDeviceInfo smc91c111_info = {
-    .init = smc91c111_init1,
-    .qdev.name  = "smc91c111",
-    .qdev.size  = sizeof(smc91c111_state),
-    .qdev.vmsd = &vmstate_smc91c111,
-    .qdev.reset = smc91c111_reset,
-    .qdev.props = (Property[]) {
-        DEFINE_NIC_PROPERTIES(smc91c111_state, conf),
-        DEFINE_PROP_END_OF_LIST(),
-    }
+static Property smc91c111_properties[] = {
+    DEFINE_NIC_PROPERTIES(smc91c111_state, conf),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void smc91c111_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = smc91c111_init1;
+    dc->reset = smc91c111_reset;
+    dc->vmsd = &vmstate_smc91c111;
+    dc->props = smc91c111_properties;
+}
+
+static TypeInfo smc91c111_info = {
+    .name          = "smc91c111",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(smc91c111_state),
+    .class_init    = smc91c111_class_init,
 };
 
 static void smc91c111_register_devices(void)
 {
-    sysbus_register_withprop(&smc91c111_info);
+    type_register_static(&smc91c111_info);
 }
 
 /* Legacy helper function.  Should go away when machine config files are
diff --git a/hw/spapr.c b/hw/spapr.c
index 0e1f80dfdc..dffb6a2a50 100644
--- a/hw/spapr.c
+++ b/hw/spapr.c
@@ -50,19 +50,29 @@
 
 #include <libfdt.h>
 
-#define KERNEL_LOAD_ADDR        0x00000000
-#define INITRD_LOAD_ADDR        0x02800000
+/* SLOF memory layout:
+ *
+ * SLOF raw image loaded at 0, copies its romfs right below the flat
+ * device-tree, then position SLOF itself 31M below that
+ *
+ * So we set FW_OVERHEAD to 40MB which should account for all of that
+ * and more
+ *
+ * We load our kernel at 4M, leaving space for SLOF initial image
+ */
 #define FDT_MAX_SIZE            0x10000
 #define RTAS_MAX_SIZE           0x10000
 #define FW_MAX_SIZE             0x400000
 #define FW_FILE_NAME            "slof.bin"
+#define FW_OVERHEAD             0x2800000
+#define KERNEL_LOAD_ADDR        FW_MAX_SIZE
 
-#define MIN_RMA_SLOF		128UL
+#define MIN_RMA_SLOF            128UL
 
 #define TIMEBASE_FREQ           512000000ULL
 
 #define MAX_CPUS                256
-#define XICS_IRQS		1024
+#define XICS_IRQS               1024
 
 #define SPAPR_PCI_BUID          0x800000020000001ULL
 #define SPAPR_PCI_MEM_WIN_ADDR  (0x10000000000ULL + 0xA0000000)
@@ -139,6 +149,7 @@ static void *spapr_create_fdt_skel(const char *cpu_model,
                                    target_phys_addr_t rma_size,
                                    target_phys_addr_t initrd_base,
                                    target_phys_addr_t initrd_size,
+                                   target_phys_addr_t kernel_size,
                                    const char *boot_device,
                                    const char *kernel_cmdline,
                                    long hash_shift)
@@ -176,6 +187,12 @@ static void *spapr_create_fdt_skel(const char *cpu_model,
     fdt = g_malloc0(FDT_MAX_SIZE);
     _FDT((fdt_create(fdt, FDT_MAX_SIZE)));
 
+    if (kernel_size) {
+        _FDT((fdt_add_reservemap_entry(fdt, KERNEL_LOAD_ADDR, kernel_size)));
+    }
+    if (initrd_size) {
+        _FDT((fdt_add_reservemap_entry(fdt, initrd_base, initrd_size)));
+    }
     _FDT((fdt_finish_reservemap(fdt)));
 
     /* Root node */
@@ -197,15 +214,13 @@ static void *spapr_create_fdt_skel(const char *cpu_model,
                        &start_prop, sizeof(start_prop))));
     _FDT((fdt_property(fdt, "linux,initrd-end",
                        &end_prop, sizeof(end_prop))));
-    _FDT((fdt_property_string(fdt, "qemu,boot-device", boot_device)));
+    if (kernel_size) {
+        uint64_t kprop[2] = { cpu_to_be64(KERNEL_LOAD_ADDR),
+                              cpu_to_be64(kernel_size) };
 
-    /*
-     * Because we don't always invoke any firmware, we can't rely on
-     * that to do BAR allocation.  Long term, we should probably do
-     * that ourselves, but for now, this setting (plus advertising the
-     * current BARs as 0) causes sufficiently recent kernels to to the
-     * BAR assignment themselves */
-    _FDT((fdt_property_cell(fdt, "linux,pci-probe-only", 0)));
+        _FDT((fdt_property(fdt, "qemu,boot-kernel", &kprop, sizeof(kprop))));
+    }
+    _FDT((fdt_property_string(fdt, "qemu,boot-device", boot_device)));
 
     _FDT((fdt_end_node(fdt)));
 
@@ -445,6 +460,12 @@ static void spapr_finalize_fdt(sPAPREnvironment *spapr,
 
     _FDT((fdt_pack(fdt)));
 
+    if (fdt_totalsize(fdt) > FDT_MAX_SIZE) {
+        hw_error("FDT too big ! 0x%x bytes (max is 0x%x)\n",
+                 fdt_totalsize(fdt), FDT_MAX_SIZE);
+        exit(1);
+    }
+
     cpu_physical_memory_write(fdt_addr, fdt, fdt_totalsize(fdt));
 
     g_free(fdt);
@@ -494,8 +515,9 @@ static void ppc_spapr_init(ram_addr_t ram_size,
     MemoryRegion *sysmem = get_system_memory();
     MemoryRegion *ram = g_new(MemoryRegion, 1);
     target_phys_addr_t rma_alloc_size, rma_size;
-    uint32_t initrd_base;
-    long kernel_size, initrd_size, fw_size;
+    uint32_t initrd_base = 0;
+    long kernel_size = 0, initrd_size = 0;
+    long load_limit, rtas_limit, fw_size;
     long pteg_shift = 17;
     char *filename;
 
@@ -517,11 +539,13 @@ static void ppc_spapr_init(ram_addr_t ram_size,
         rma_size = ram_size;
     }
 
-    /* We place the device tree just below either the top of the RMA,
+    /* We place the device tree and RTAS just below either the top of the RMA,
      * or just below 2GB, whichever is lowere, so that it can be
      * processed with 32-bit real mode code if necessary */
-    spapr->fdt_addr = MIN(rma_size, 0x80000000) - FDT_MAX_SIZE;
-    spapr->rtas_addr = spapr->fdt_addr - RTAS_MAX_SIZE;
+    rtas_limit = MIN(rma_size, 0x80000000);
+    spapr->rtas_addr = rtas_limit - RTAS_MAX_SIZE;
+    spapr->fdt_addr = spapr->rtas_addr - FDT_MAX_SIZE;
+    load_limit = spapr->fdt_addr - FW_OVERHEAD;
 
     /* init CPUs */
     if (cpu_model == NULL) {
@@ -577,13 +601,19 @@ static void ppc_spapr_init(ram_addr_t ram_size,
 
     filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, "spapr-rtas.bin");
     spapr->rtas_size = load_image_targphys(filename, spapr->rtas_addr,
-                                           ram_size - spapr->rtas_addr);
+                                           rtas_limit - spapr->rtas_addr);
     if (spapr->rtas_size < 0) {
         hw_error("qemu: could not load LPAR rtas '%s'\n", filename);
         exit(1);
     }
+    if (spapr->rtas_size > RTAS_MAX_SIZE) {
+        hw_error("RTAS too big ! 0x%lx bytes (max is 0x%x)\n",
+                 spapr->rtas_size, RTAS_MAX_SIZE);
+        exit(1);
+    }
     g_free(filename);
 
+
     /* Set up Interrupt Controller */
     spapr->icp = xics_system_init(XICS_IRQS);
     spapr->next_irq = 16;
@@ -622,6 +652,20 @@ static void ppc_spapr_init(ram_addr_t ram_size,
         spapr_vscsi_create(spapr->vio_bus, 0x2000 + i);
     }
 
+    if (rma_size < (MIN_RMA_SLOF << 20)) {
+        fprintf(stderr, "qemu: pSeries SLOF firmware requires >= "
+                "%ldM guest RMA (Real Mode Area memory)\n", MIN_RMA_SLOF);
+        exit(1);
+    }
+
+    fprintf(stderr, "sPAPR memory map:\n");
+    fprintf(stderr, "RTAS                 : 0x%08lx..%08lx\n",
+            (unsigned long)spapr->rtas_addr,
+            (unsigned long)(spapr->rtas_addr + spapr->rtas_size - 1));
+    fprintf(stderr, "FDT                  : 0x%08lx..%08lx\n",
+            (unsigned long)spapr->fdt_addr,
+            (unsigned long)(spapr->fdt_addr + FDT_MAX_SIZE - 1));
+
     if (kernel_filename) {
         uint64_t lowaddr = 0;
 
@@ -630,57 +674,60 @@ static void ppc_spapr_init(ram_addr_t ram_size,
         if (kernel_size < 0) {
             kernel_size = load_image_targphys(kernel_filename,
                                               KERNEL_LOAD_ADDR,
-                                              ram_size - KERNEL_LOAD_ADDR);
+                                              load_limit - KERNEL_LOAD_ADDR);
         }
         if (kernel_size < 0) {
             fprintf(stderr, "qemu: could not load kernel '%s'\n",
                     kernel_filename);
             exit(1);
         }
+        fprintf(stderr, "Kernel               : 0x%08x..%08lx\n",
+                KERNEL_LOAD_ADDR, KERNEL_LOAD_ADDR + kernel_size - 1);
 
         /* load initrd */
         if (initrd_filename) {
-            initrd_base = INITRD_LOAD_ADDR;
+            /* Try to locate the initrd in the gap between the kernel
+             * and the firmware. Add a bit of space just in case
+             */
+            initrd_base = (KERNEL_LOAD_ADDR + kernel_size + 0x1ffff) & ~0xffff;
             initrd_size = load_image_targphys(initrd_filename, initrd_base,
-                                              ram_size - initrd_base);
+                                              load_limit - initrd_base);
             if (initrd_size < 0) {
                 fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
                         initrd_filename);
                 exit(1);
             }
+            fprintf(stderr, "Ramdisk              : 0x%08lx..%08lx\n",
+                    (long)initrd_base, (long)(initrd_base + initrd_size - 1));
         } else {
             initrd_base = 0;
             initrd_size = 0;
         }
+    }
 
-        spapr->entry_point = KERNEL_LOAD_ADDR;
-    } else {
-        if (rma_size < (MIN_RMA_SLOF << 20)) {
-            fprintf(stderr, "qemu: pSeries SLOF firmware requires >= "
-                    "%ldM guest RMA (Real Mode Area memory)\n", MIN_RMA_SLOF);
-            exit(1);
-        }
-        filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, FW_FILE_NAME);
-        fw_size = load_image_targphys(filename, 0, FW_MAX_SIZE);
-        if (fw_size < 0) {
-            hw_error("qemu: could not load LPAR rtas '%s'\n", filename);
-            exit(1);
-        }
-        g_free(filename);
-        spapr->entry_point = 0x100;
-        initrd_base = 0;
-        initrd_size = 0;
-
-        /* SLOF will startup the secondary CPUs using RTAS,
-           rather than expecting a kexec() style entry */
-        for (env = first_cpu; env != NULL; env = env->next_cpu) {
-            env->halted = 1;
-        }
+    filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, FW_FILE_NAME);
+    fw_size = load_image_targphys(filename, 0, FW_MAX_SIZE);
+    if (fw_size < 0) {
+        hw_error("qemu: could not load LPAR rtas '%s'\n", filename);
+        exit(1);
+    }
+    g_free(filename);
+    fprintf(stderr, "Firmware load        : 0x%08x..%08lx\n",
+            0, fw_size);
+    fprintf(stderr, "Firmware runtime     : 0x%08lx..%08lx\n",
+            load_limit, (unsigned long)spapr->fdt_addr);
+
+    spapr->entry_point = 0x100;
+
+    /* SLOF will startup the secondary CPUs using RTAS */
+    for (env = first_cpu; env != NULL; env = env->next_cpu) {
+        env->halted = 1;
     }
 
     /* Prepare the device tree */
     spapr->fdt_skel = spapr_create_fdt_skel(cpu_model, rma_size,
                                             initrd_base, initrd_size,
+                                            kernel_size,
                                             boot_device, kernel_cmdline,
                                             pteg_shift + 7);
     assert(spapr->fdt_skel != NULL);
@@ -693,7 +740,6 @@ static QEMUMachine spapr_machine = {
     .desc = "pSeries Logical Partition (PAPR compliant)",
     .init = ppc_spapr_init,
     .max_cpus = MAX_CPUS,
-    .no_vga = 1,
     .no_parallel = 1,
     .use_scsi = 1,
 };
diff --git a/hw/spapr_llan.c b/hw/spapr_llan.c
index 45674c4cb9..79b394132b 100644
--- a/hw/spapr_llan.c
+++ b/hw/spapr_llan.c
@@ -189,7 +189,7 @@ static int spapr_vlan_init(VIOsPAPRDevice *sdev)
     qemu_macaddr_default_if_unset(&dev->nicconf.macaddr);
 
     dev->nic = qemu_new_nic(&net_spapr_vlan_info, &dev->nicconf,
-                            sdev->qdev.info->name, sdev->qdev.id, dev);
+                            object_get_typename(OBJECT(sdev)), sdev->qdev.id, dev);
     qemu_format_nic_info_str(&dev->nic->nc, dev->nicconf.macaddr.a);
 
     return 0;
@@ -474,30 +474,41 @@ static target_ulong h_multicast_ctrl(CPUState *env, sPAPREnvironment *spapr,
     return H_SUCCESS;
 }
 
-static VIOsPAPRDeviceInfo spapr_vlan = {
-    .init = spapr_vlan_init,
-    .devnode = spapr_vlan_devnode,
-    .dt_name = "l-lan",
-    .dt_type = "network",
-    .dt_compatible = "IBM,l-lan",
-    .signal_mask = 0x1,
-    .qdev.name = "spapr-vlan",
-    .qdev.size = sizeof(VIOsPAPRVLANDevice),
-    .qdev.props = (Property[]) {
-        DEFINE_SPAPR_PROPERTIES(VIOsPAPRVLANDevice, sdev, 0x1000, 0x10000000),
-        DEFINE_NIC_PROPERTIES(VIOsPAPRVLANDevice, nicconf),
-        DEFINE_PROP_END_OF_LIST(),
-    },
+static Property spapr_vlan_properties[] = {
+    DEFINE_SPAPR_PROPERTIES(VIOsPAPRVLANDevice, sdev, 0x1000, 0x10000000),
+    DEFINE_NIC_PROPERTIES(VIOsPAPRVLANDevice, nicconf),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void spapr_vlan_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    VIOsPAPRDeviceClass *k = VIO_SPAPR_DEVICE_CLASS(klass);
+
+    k->init = spapr_vlan_init;
+    k->devnode = spapr_vlan_devnode;
+    k->dt_name = "l-lan";
+    k->dt_type = "network";
+    k->dt_compatible = "IBM,l-lan";
+    k->signal_mask = 0x1;
+    dc->props = spapr_vlan_properties;
+}
+
+static TypeInfo spapr_vlan_info = {
+    .name          = "spapr-vlan",
+    .parent        = TYPE_VIO_SPAPR_DEVICE,
+    .instance_size = sizeof(VIOsPAPRVLANDevice),
+    .class_init    = spapr_vlan_class_init,
 };
 
 static void spapr_vlan_register(void)
 {
-    spapr_vio_bus_register_withprop(&spapr_vlan);
     spapr_register_hypercall(H_REGISTER_LOGICAL_LAN, h_register_logical_lan);
     spapr_register_hypercall(H_FREE_LOGICAL_LAN, h_free_logical_lan);
     spapr_register_hypercall(H_SEND_LOGICAL_LAN, h_send_logical_lan);
     spapr_register_hypercall(H_ADD_LOGICAL_LAN_BUFFER,
                              h_add_logical_lan_buffer);
     spapr_register_hypercall(H_MULTICAST_CTRL, h_multicast_ctrl);
+    type_register_static(&spapr_vlan_info);
 }
 device_init(spapr_vlan_register);
diff --git a/hw/spapr_pci.c b/hw/spapr_pci.c
index 9b6a032cce..ed2e4b33e7 100644
--- a/hw/spapr_pci.c
+++ b/hw/spapr_pci.c
@@ -62,6 +62,30 @@ static PCIDevice *find_dev(sPAPREnvironment *spapr,
     return NULL;
 }
 
+static uint32_t rtas_pci_cfgaddr(uint32_t arg)
+{
+    return ((arg >> 20) & 0xf00) | (arg & 0xff);
+}
+
+static uint32_t rtas_read_pci_config_do(PCIDevice *pci_dev, uint32_t addr,
+                                        uint32_t limit, uint32_t len)
+{
+    if ((addr + len) <= limit) {
+        return pci_host_config_read_common(pci_dev, addr, limit, len);
+    } else {
+        return ~0x0;
+    }
+}
+
+static void rtas_write_pci_config_do(PCIDevice *pci_dev, uint32_t addr,
+                                     uint32_t limit, uint32_t val,
+                                     uint32_t len)
+{
+    if ((addr + len) <= limit) {
+        pci_host_config_write_common(pci_dev, addr, limit, val, len);
+    }
+}
+
 static void rtas_ibm_read_pci_config(sPAPREnvironment *spapr,
                                      uint32_t token, uint32_t nargs,
                                      target_ulong args,
@@ -76,8 +100,8 @@ static void rtas_ibm_read_pci_config(sPAPREnvironment *spapr,
         return;
     }
     size = rtas_ld(args, 3);
-    addr = rtas_ld(args, 0) & 0xFF;
-    val = pci_default_read_config(dev, addr, size);
+    addr = rtas_pci_cfgaddr(rtas_ld(args, 0));
+    val = rtas_read_pci_config_do(dev, addr, pci_config_size(dev), size);
     rtas_st(rets, 0, 0);
     rtas_st(rets, 1, val);
 }
@@ -95,8 +119,8 @@ static void rtas_read_pci_config(sPAPREnvironment *spapr,
         return;
     }
     size = rtas_ld(args, 1);
-    addr = rtas_ld(args, 0) & 0xFF;
-    val = pci_default_read_config(dev, addr, size);
+    addr = rtas_pci_cfgaddr(rtas_ld(args, 0));
+    val = rtas_read_pci_config_do(dev, addr, pci_config_size(dev), size);
     rtas_st(rets, 0, 0);
     rtas_st(rets, 1, val);
 }
@@ -116,8 +140,8 @@ static void rtas_ibm_write_pci_config(sPAPREnvironment *spapr,
     }
     val = rtas_ld(args, 4);
     size = rtas_ld(args, 3);
-    addr = rtas_ld(args, 0) & 0xFF;
-    pci_default_write_config(dev, addr, val, size);
+    addr = rtas_pci_cfgaddr(rtas_ld(args, 0));
+    rtas_write_pci_config_do(dev, addr, pci_config_size(dev), val, size);
     rtas_st(rets, 0, 0);
 }
 
@@ -135,8 +159,8 @@ static void rtas_write_pci_config(sPAPREnvironment *spapr,
     }
     val = rtas_ld(args, 2);
     size = rtas_ld(args, 1);
-    addr = rtas_ld(args, 0) & 0xFF;
-    pci_default_write_config(dev, addr, val, size);
+    addr = rtas_pci_cfgaddr(rtas_ld(args, 0));
+    rtas_write_pci_config_do(dev, addr, pci_config_size(dev), val, size);
     rtas_st(rets, 0, 0);
 }
 
@@ -190,17 +214,38 @@ static int spapr_main_pci_host_init(PCIDevice *d)
     return 0;
 }
 
-static PCIDeviceInfo spapr_main_pci_host_info = {
-    .qdev.name = "spapr-pci-host-bridge",
-    .qdev.size = sizeof(PCIDevice),
-    .init      = spapr_main_pci_host_init,
+static void spapr_main_pci_host_class_init(ObjectClass *klass, void *data)
+{
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->init = spapr_main_pci_host_init;
+}
+
+static TypeInfo spapr_main_pci_host_info = {
+    .name          = "spapr-pci-host-bridge-pci",
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(PCIDevice),
+    .class_init    = spapr_main_pci_host_class_init,
+};
+
+static void spapr_phb_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+
+    sdc->init = spapr_phb_init;
+}
+
+static TypeInfo spapr_phb_info = {
+    .name          = "spapr-pci-host-bridge",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(sPAPRPHBState),
+    .class_init    = spapr_phb_class_init,
 };
 
 static void spapr_register_devices(void)
 {
-    sysbus_register_dev("spapr-pci-host-bridge", sizeof(sPAPRPHBState),
-                        spapr_phb_init);
-    pci_qdev_register(&spapr_main_pci_host_info);
+    type_register_static(&spapr_phb_info);
+    type_register_static(&spapr_main_pci_host_info);
 }
 
 device_init(spapr_register_devices)
@@ -319,31 +364,13 @@ void spapr_create_phb(sPAPREnvironment *spapr,
 #define b_fff(x)        b_x((x), 8, 3)  /* function number */
 #define b_rrrrrrrr(x)   b_x((x), 0, 8)  /* register number */
 
-static uint32_t regtype_to_ss(uint8_t type)
-{
-    if (type & PCI_BASE_ADDRESS_MEM_TYPE_64) {
-        return 3;
-    }
-    if (type == PCI_BASE_ADDRESS_SPACE_IO) {
-        return 1;
-    }
-    return 2;
-}
-
 int spapr_populate_pci_devices(sPAPRPHBState *phb,
                                uint32_t xics_phandle,
                                void *fdt)
 {
     PCIBus *bus = phb->host_state.bus;
-    int bus_off, node_off = 0, devid, fn, i, n, devices;
-    DeviceState *qdev;
+    int bus_off, i;
     char nodename[256];
-    struct {
-        uint32_t hi;
-        uint64_t addr;
-        uint64_t size;
-    } __attribute__((packed)) reg[PCI_NUM_REGIONS + 1],
-          assigned_addresses[PCI_NUM_REGIONS];
     uint32_t bus_range[] = { cpu_to_be32(0), cpu_to_be32(0xff) };
     struct {
         uint32_t hi;
@@ -364,7 +391,7 @@ int spapr_populate_pci_devices(sPAPRPHBState *phb,
     };
     uint64_t bus_reg[] = { cpu_to_be64(phb->buid), 0 };
     uint32_t interrupt_map_mask[] = {
-        cpu_to_be32(b_ddddd(-1)|b_fff(-1)), 0x0, 0x0, 0x0};
+        cpu_to_be32(b_ddddd(-1)|b_fff(0)), 0x0, 0x0, 0x0};
     uint32_t interrupt_map[bus->nirq][7];
 
     /* Start populating the FDT */
@@ -392,117 +419,26 @@ int spapr_populate_pci_devices(sPAPRPHBState *phb,
     _FDT(fdt_setprop(fdt, bus_off, "bus-range", &bus_range, sizeof(bus_range)));
     _FDT(fdt_setprop(fdt, bus_off, "ranges", &ranges, sizeof(ranges)));
     _FDT(fdt_setprop(fdt, bus_off, "reg", &bus_reg, sizeof(bus_reg)));
+    _FDT(fdt_setprop_cell(fdt, bus_off, "ibm,pci-config-space-type", 0x1));
+
+    /* Build the interrupt-map, this must matches what is done
+     * in pci_spapr_map_irq
+     */
     _FDT(fdt_setprop(fdt, bus_off, "interrupt-map-mask",
                      &interrupt_map_mask, sizeof(interrupt_map_mask)));
-
-    /* Populate PCI devices and allocate IRQs */
-    devices = 0;
-    QTAILQ_FOREACH(qdev, &bus->qbus.children, sibling) {
-        PCIDevice *dev = DO_UPCAST(PCIDevice, qdev, qdev);
-        int irq_index = pci_spapr_map_irq(dev, 0);
-        uint32_t *irqmap = interrupt_map[devices];
-        uint8_t *config = dev->config;
-
-        devid = dev->devfn >> 3;
-        fn = dev->devfn & 7;
-
-        sprintf(nodename, "pci@%u,%u", devid, fn);
-
-        /* Allocate interrupt from the map */
-        if (devid > bus->nirq)  {
-            printf("Unexpected behaviour in spapr_populate_pci_devices,"
-                    "wrong devid %u\n", devid);
-            exit(-1);
-        }
-        irqmap[0] = cpu_to_be32(b_ddddd(devid)|b_fff(fn));
+    for (i = 0; i < 7; i++) {
+        uint32_t *irqmap = interrupt_map[i];
+        irqmap[0] = cpu_to_be32(b_ddddd(i)|b_fff(0));
         irqmap[1] = 0;
         irqmap[2] = 0;
         irqmap[3] = 0;
         irqmap[4] = cpu_to_be32(xics_phandle);
-        irqmap[5] = cpu_to_be32(phb->lsi_table[irq_index].dt_irq);
+        irqmap[5] = cpu_to_be32(phb->lsi_table[i % SPAPR_PCI_NUM_LSI].dt_irq);
         irqmap[6] = cpu_to_be32(0x8);
-
-        /* Add node to FDT */
-        node_off = fdt_add_subnode(fdt, bus_off, nodename);
-        if (node_off < 0) {
-            return node_off;
-        }
-
-        _FDT(fdt_setprop_cell(fdt, node_off, "vendor-id",
-                              pci_get_word(&config[PCI_VENDOR_ID])));
-        _FDT(fdt_setprop_cell(fdt, node_off, "device-id",
-                              pci_get_word(&config[PCI_DEVICE_ID])));
-        _FDT(fdt_setprop_cell(fdt, node_off, "revision-id",
-                              pci_get_byte(&config[PCI_REVISION_ID])));
-        _FDT(fdt_setprop_cell(fdt, node_off, "class-code",
-                              pci_get_long(&config[PCI_CLASS_REVISION]) >> 8));
-        _FDT(fdt_setprop_cell(fdt, node_off, "subsystem-id",
-                              pci_get_word(&config[PCI_SUBSYSTEM_ID])));
-        _FDT(fdt_setprop_cell(fdt, node_off, "subsystem-vendor-id",
-                              pci_get_word(&config[PCI_SUBSYSTEM_VENDOR_ID])));
-
-        /* Config space region comes first */
-        reg[0].hi = cpu_to_be32(
-            b_n(0) |
-            b_p(0) |
-            b_t(0) |
-            b_ss(0/*config*/) |
-            b_bbbbbbbb(0) |
-            b_ddddd(devid) |
-            b_fff(fn));
-        reg[0].addr = 0;
-        reg[0].size = 0;
-
-        n = 0;
-        for (i = 0; i < ARRAY_SIZE(bars); ++i) {
-            if (0 == dev->io_regions[i].size) {
-                continue;
-            }
-
-            reg[n+1].hi = cpu_to_be32(
-                b_n(0) |
-                b_p(0) |
-                b_t(0) |
-                b_ss(regtype_to_ss(dev->io_regions[i].type)) |
-                b_bbbbbbbb(0) |
-                b_ddddd(devid) |
-                b_fff(fn) |
-                b_rrrrrrrr(bars[i]));
-            reg[n+1].addr = 0;
-            reg[n+1].size = cpu_to_be64(dev->io_regions[i].size);
-
-            assigned_addresses[n].hi = cpu_to_be32(
-                b_n(1) |
-                b_p(0) |
-                b_t(0) |
-                b_ss(regtype_to_ss(dev->io_regions[i].type)) |
-                b_bbbbbbbb(0) |
-                b_ddddd(devid) |
-                b_fff(fn) |
-                b_rrrrrrrr(bars[i]));
-
-            /*
-             * Writing zeroes to assigned_addresses causes the guest kernel to
-             * reassign BARs
-             */
-            assigned_addresses[n].addr = cpu_to_be64(dev->io_regions[i].addr);
-            assigned_addresses[n].size = reg[n+1].size;
-
-            ++n;
-        }
-        _FDT(fdt_setprop(fdt, node_off, "reg", reg, sizeof(reg[0])*(n+1)));
-        _FDT(fdt_setprop(fdt, node_off, "assigned-addresses",
-                         assigned_addresses,
-                         sizeof(assigned_addresses[0])*(n)));
-        _FDT(fdt_setprop_cell(fdt, node_off, "interrupts",
-                              pci_get_byte(&config[PCI_INTERRUPT_PIN])));
-
-        ++devices;
     }
-
     /* Write interrupt map */
     _FDT(fdt_setprop(fdt, bus_off, "interrupt-map", &interrupt_map,
-                     devices * sizeof(interrupt_map[0])));
+                     7 * sizeof(interrupt_map[0])));
 
     return 0;
 }
diff --git a/hw/spapr_vio.c b/hw/spapr_vio.c
index 7a86dc8d2c..64f0009814 100644
--- a/hw/spapr_vio.c
+++ b/hw/spapr_vio.c
@@ -75,11 +75,11 @@ VIOsPAPRDevice *spapr_vio_find_by_reg(VIOsPAPRBus *bus, uint32_t reg)
 
 static char *vio_format_dev_name(VIOsPAPRDevice *dev)
 {
-    VIOsPAPRDeviceInfo *info = (VIOsPAPRDeviceInfo *)dev->qdev.info;
+    VIOsPAPRDeviceClass *pc = VIO_SPAPR_DEVICE_GET_CLASS(dev);
     char *name;
 
     /* Device tree style name device@reg */
-    if (asprintf(&name, "%s@%x", info->dt_name, dev->reg) < 0) {
+    if (asprintf(&name, "%s@%x", pc->dt_name, dev->reg) < 0) {
         return NULL;
     }
 
@@ -90,7 +90,7 @@ static char *vio_format_dev_name(VIOsPAPRDevice *dev)
 static int vio_make_devnode(VIOsPAPRDevice *dev,
                             void *fdt)
 {
-    VIOsPAPRDeviceInfo *info = (VIOsPAPRDeviceInfo *)dev->qdev.info;
+    VIOsPAPRDeviceClass *pc = VIO_SPAPR_DEVICE_GET_CLASS(dev);
     int vdevice_off, node_off, ret;
     char *dt_name;
 
@@ -115,17 +115,17 @@ static int vio_make_devnode(VIOsPAPRDevice *dev,
         return ret;
     }
 
-    if (info->dt_type) {
+    if (pc->dt_type) {
         ret = fdt_setprop_string(fdt, node_off, "device_type",
-                                 info->dt_type);
+                                 pc->dt_type);
         if (ret < 0) {
             return ret;
         }
     }
 
-    if (info->dt_compatible) {
+    if (pc->dt_compatible) {
         ret = fdt_setprop_string(fdt, node_off, "compatible",
-                                 info->dt_compatible);
+                                 pc->dt_compatible);
         if (ret < 0) {
             return ret;
         }
@@ -163,8 +163,8 @@ static int vio_make_devnode(VIOsPAPRDevice *dev,
         }
     }
 
-    if (info->devnode) {
-        ret = (info->devnode)(dev, fdt, node_off);
+    if (pc->devnode) {
+        ret = (pc->devnode)(dev, fdt, node_off);
         if (ret < 0) {
             return ret;
         }
@@ -621,7 +621,7 @@ static void rtas_quiesce(sPAPREnvironment *spapr, uint32_t token,
     rtas_st(rets, 0, 0);
 }
 
-static int spapr_vio_check_reg(VIOsPAPRDevice *sdev, VIOsPAPRDeviceInfo *info)
+static int spapr_vio_check_reg(VIOsPAPRDevice *sdev)
 {
     VIOsPAPRDevice *other_sdev;
     DeviceState *qdev;
@@ -639,7 +639,9 @@ static int spapr_vio_check_reg(VIOsPAPRDevice *sdev, VIOsPAPRDeviceInfo *info)
 
         if (other_sdev != sdev && other_sdev->reg == sdev->reg) {
             fprintf(stderr, "vio: %s and %s devices conflict at address %#x\n",
-                    info->qdev.name, other_sdev->qdev.info->name, sdev->reg);
+                    object_get_typename(OBJECT(sdev)),
+                    object_get_typename(OBJECT(qdev)),
+                    sdev->reg);
             return -EEXIST;
         }
     }
@@ -647,14 +649,14 @@ static int spapr_vio_check_reg(VIOsPAPRDevice *sdev, VIOsPAPRDeviceInfo *info)
     return 0;
 }
 
-static int spapr_vio_busdev_init(DeviceState *qdev, DeviceInfo *qinfo)
+static int spapr_vio_busdev_init(DeviceState *qdev)
 {
-    VIOsPAPRDeviceInfo *info = (VIOsPAPRDeviceInfo *)qinfo;
     VIOsPAPRDevice *dev = (VIOsPAPRDevice *)qdev;
+    VIOsPAPRDeviceClass *pc = VIO_SPAPR_DEVICE_GET_CLASS(dev);
     char *id;
     int ret;
 
-    ret = spapr_vio_check_reg(dev, info);
+    ret = spapr_vio_check_reg(dev);
     if (ret) {
         return ret;
     }
@@ -675,16 +677,7 @@ static int spapr_vio_busdev_init(DeviceState *qdev, DeviceInfo *qinfo)
 
     rtce_init(dev);
 
-    return info->init(dev);
-}
-
-void spapr_vio_bus_register_withprop(VIOsPAPRDeviceInfo *info)
-{
-    info->qdev.init = spapr_vio_busdev_init;
-    info->qdev.bus_info = &spapr_vio_bus_info;
-
-    assert(info->qdev.size >= sizeof(VIOsPAPRDevice));
-    qdev_register(&info->qdev);
+    return pc->init(dev);
 }
 
 static target_ulong h_vio_signal(CPUState *env, sPAPREnvironment *spapr,
@@ -694,15 +687,15 @@ static target_ulong h_vio_signal(CPUState *env, sPAPREnvironment *spapr,
     target_ulong reg = args[0];
     target_ulong mode = args[1];
     VIOsPAPRDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
-    VIOsPAPRDeviceInfo *info;
+    VIOsPAPRDeviceClass *pc;
 
     if (!dev) {
         return H_PARAMETER;
     }
 
-    info = (VIOsPAPRDeviceInfo *)dev->qdev.info;
+    pc = VIO_SPAPR_DEVICE_GET_CLASS(dev);
 
-    if (mode & ~info->signal_mask) {
+    if (mode & ~pc->signal_mask) {
         return H_PARAMETER;
     }
 
@@ -753,16 +746,42 @@ static int spapr_vio_bridge_init(SysBusDevice *dev)
     return 0;
 }
 
-static SysBusDeviceInfo spapr_vio_bridge_info = {
-    .init = spapr_vio_bridge_init,
-    .qdev.name  = "spapr-vio-bridge",
-    .qdev.size  = sizeof(SysBusDevice),
-    .qdev.no_user = 1,
+static void spapr_vio_bridge_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = spapr_vio_bridge_init;
+    dc->no_user = 1;
+}
+
+static TypeInfo spapr_vio_bridge_info = {
+    .name          = "spapr-vio-bridge",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(SysBusDevice),
+    .class_init    = spapr_vio_bridge_class_init,
+};
+
+static void vio_spapr_device_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *k = DEVICE_CLASS(klass);
+    k->init = spapr_vio_busdev_init;
+    k->bus_info = &spapr_vio_bus_info;
+}
+
+static TypeInfo spapr_vio_type_info = {
+    .name = TYPE_VIO_SPAPR_DEVICE,
+    .parent = TYPE_DEVICE,
+    .instance_size = sizeof(VIOsPAPRDevice),
+    .abstract = true,
+    .class_size = sizeof(VIOsPAPRDeviceClass),
+    .class_init = vio_spapr_device_class_init,
 };
 
 static void spapr_vio_register_devices(void)
 {
-    sysbus_register_withprop(&spapr_vio_bridge_info);
+    type_register_static(&spapr_vio_bridge_info);
+    type_register_static(&spapr_vio_type_info);
 }
 
 device_init(spapr_vio_register_devices)
diff --git a/hw/spapr_vio.h b/hw/spapr_vio.h
index 0984d559db..d8527bed90 100644
--- a/hw/spapr_vio.h
+++ b/hw/spapr_vio.h
@@ -34,6 +34,14 @@ enum VIOsPAPR_TCEAccess {
 
 #define SPAPR_VTY_BASE_ADDRESS     0x30000000
 
+#define TYPE_VIO_SPAPR_DEVICE "vio-spapr-device"
+#define VIO_SPAPR_DEVICE(obj) \
+     OBJECT_CHECK(VIOsPAPRDevice, (obj), TYPE_VIO_SPAPR_DEVICE)
+#define VIO_SPAPR_DEVICE_CLASS(klass) \
+     OBJECT_CLASS_CHECK(VIOsPAPRDeviceClass, (klass), TYPE_VIO_SPAPR_DEVICE)
+#define VIO_SPAPR_DEVICE_GET_CLASS(obj) \
+     OBJECT_GET_CLASS(VIOsPAPRDeviceClass, (obj), TYPE_VIO_SPAPR_DEVICE)
+
 struct VIOsPAPRDevice;
 
 typedef struct VIOsPAPR_RTCE {
@@ -47,7 +55,20 @@ typedef struct VIOsPAPR_CRQ {
     int(*SendFunc)(struct VIOsPAPRDevice *vdev, uint8_t *crq);
 } VIOsPAPR_CRQ;
 
-typedef struct VIOsPAPRDevice {
+typedef struct VIOsPAPRDevice VIOsPAPRDevice;
+typedef struct VIOsPAPRBus VIOsPAPRBus;
+
+typedef struct VIOsPAPRDeviceClass {
+    DeviceClass parent_class;
+
+    const char *dt_name, *dt_type, *dt_compatible;
+    target_ulong signal_mask;
+    int (*init)(VIOsPAPRDevice *dev);
+    void (*hcalls)(VIOsPAPRBus *bus);
+    int (*devnode)(VIOsPAPRDevice *dev, void *fdt, int node_off);
+} VIOsPAPRDeviceClass;
+
+struct VIOsPAPRDevice {
     DeviceState qdev;
     uint32_t reg;
     uint32_t flags;
@@ -59,28 +80,23 @@ typedef struct VIOsPAPRDevice {
     VIOsPAPR_RTCE *rtce_table;
     int kvmtce_fd;
     VIOsPAPR_CRQ crq;
-} VIOsPAPRDevice;
+};
 
 #define DEFINE_SPAPR_PROPERTIES(type, field, default_reg, default_dma_window) \
         DEFINE_PROP_UINT32("reg", type, field.reg, default_reg), \
         DEFINE_PROP_UINT32("dma-window", type, field.rtce_window_size, \
                            default_dma_window)
 
-typedef struct VIOsPAPRBus {
+struct VIOsPAPRBus {
     BusState bus;
-} VIOsPAPRBus;
-
-typedef struct {
-    DeviceInfo qdev;
     const char *dt_name, *dt_type, *dt_compatible;
     target_ulong signal_mask;
     int (*init)(VIOsPAPRDevice *dev);
     int (*devnode)(VIOsPAPRDevice *dev, void *fdt, int node_off);
-} VIOsPAPRDeviceInfo;
+};
 
 extern VIOsPAPRBus *spapr_vio_bus_init(void);
 extern VIOsPAPRDevice *spapr_vio_find_by_reg(VIOsPAPRBus *bus, uint32_t reg);
-extern void spapr_vio_bus_register_withprop(VIOsPAPRDeviceInfo *info);
 extern int spapr_populate_vdevice(VIOsPAPRBus *bus, void *fdt);
 extern int spapr_populate_chosen_stdout(void *fdt, VIOsPAPRBus *bus);
 
diff --git a/hw/spapr_vscsi.c b/hw/spapr_vscsi.c
index 00e2d2d5d3..9cfce19a73 100644
--- a/hw/spapr_vscsi.c
+++ b/hw/spapr_vscsi.c
@@ -947,23 +947,34 @@ static int spapr_vscsi_devnode(VIOsPAPRDevice *dev, void *fdt, int node_off)
     return 0;
 }
 
-static VIOsPAPRDeviceInfo spapr_vscsi = {
-    .init = spapr_vscsi_init,
-    .devnode = spapr_vscsi_devnode,
-    .dt_name = "v-scsi",
-    .dt_type = "vscsi",
-    .dt_compatible = "IBM,v-scsi",
-    .signal_mask = 0x00000001,
-    .qdev.name = "spapr-vscsi",
-    .qdev.size = sizeof(VSCSIState),
-    .qdev.props = (Property[]) {
-        DEFINE_SPAPR_PROPERTIES(VSCSIState, vdev, 0x2000, 0x10000000),
-        DEFINE_PROP_END_OF_LIST(),
-    },
+static Property spapr_vscsi_properties[] = {
+    DEFINE_SPAPR_PROPERTIES(VSCSIState, vdev, 0x2000, 0x10000000),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void spapr_vscsi_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    VIOsPAPRDeviceClass *k = VIO_SPAPR_DEVICE_CLASS(klass);
+
+    k->init = spapr_vscsi_init;
+    k->devnode = spapr_vscsi_devnode;
+    k->dt_name = "v-scsi";
+    k->dt_type = "vscsi";
+    k->dt_compatible = "IBM,v-scsi";
+    k->signal_mask = 0x00000001;
+    dc->props = spapr_vscsi_properties;
+}
+
+static TypeInfo spapr_vscsi_info = {
+    .name          = "spapr-vscsi",
+    .parent        = TYPE_VIO_SPAPR_DEVICE,
+    .instance_size = sizeof(VSCSIState),
+    .class_init    = spapr_vscsi_class_init,
 };
 
 static void spapr_vscsi_register(void)
 {
-    spapr_vio_bus_register_withprop(&spapr_vscsi);
+    type_register_static(&spapr_vscsi_info);
 }
 device_init(spapr_vscsi_register);
diff --git a/hw/spapr_vty.c b/hw/spapr_vty.c
index c5fb0968ed..a954e7d29b 100644
--- a/hw/spapr_vty.c
+++ b/hw/spapr_vty.c
@@ -135,18 +135,29 @@ void spapr_vty_create(VIOsPAPRBus *bus, uint32_t reg, CharDriverState *chardev)
     qdev_init_nofail(dev);
 }
 
-static VIOsPAPRDeviceInfo spapr_vty = {
-    .init = spapr_vty_init,
-    .dt_name = "vty",
-    .dt_type = "serial",
-    .dt_compatible = "hvterm1",
-    .qdev.name = "spapr-vty",
-    .qdev.size = sizeof(VIOsPAPRVTYDevice),
-    .qdev.props = (Property[]) {
-        DEFINE_SPAPR_PROPERTIES(VIOsPAPRVTYDevice, sdev, SPAPR_VTY_BASE_ADDRESS, 0),
-        DEFINE_PROP_CHR("chardev", VIOsPAPRVTYDevice, chardev),
-        DEFINE_PROP_END_OF_LIST(),
-    },
+static Property spapr_vty_properties[] = {
+    DEFINE_SPAPR_PROPERTIES(VIOsPAPRVTYDevice, sdev, SPAPR_VTY_BASE_ADDRESS, 0),
+    DEFINE_PROP_CHR("chardev", VIOsPAPRVTYDevice, chardev),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void spapr_vty_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    VIOsPAPRDeviceClass *k = VIO_SPAPR_DEVICE_CLASS(klass);
+
+    k->init = spapr_vty_init;
+    k->dt_name = "vty";
+    k->dt_type = "serial";
+    k->dt_compatible = "hvterm1";
+    dc->props = spapr_vty_properties;
+}
+
+static TypeInfo spapr_vty_info = {
+    .name          = "spapr-vty",
+    .parent        = TYPE_VIO_SPAPR_DEVICE,
+    .instance_size = sizeof(VIOsPAPRVTYDevice),
+    .class_init    = spapr_vty_class_init,
 };
 
 VIOsPAPRDevice *spapr_vty_get_default(VIOsPAPRBus *bus)
@@ -163,7 +174,7 @@ VIOsPAPRDevice *spapr_vty_get_default(VIOsPAPRBus *bus)
     selected = NULL;
     QTAILQ_FOREACH(iter, &bus->bus.children, sibling) {
         /* Only look at VTY devices */
-        if (iter->info != &spapr_vty.qdev) {
+        if (!object_dynamic_cast(OBJECT(iter), "spapr-vty")) {
             continue;
         }
 
@@ -203,8 +214,8 @@ static VIOsPAPRDevice *vty_lookup(sPAPREnvironment *spapr, target_ulong reg)
 
 static void spapr_vty_register(void)
 {
-    spapr_vio_bus_register_withprop(&spapr_vty);
     spapr_register_hypercall(H_PUT_TERM_CHAR, h_put_term_char);
     spapr_register_hypercall(H_GET_TERM_CHAR, h_get_term_char);
+    type_register_static(&spapr_vty_info);
 }
 device_init(spapr_vty_register);
diff --git a/hw/sparc32_dma.c b/hw/sparc32_dma.c
index 035d2e205b..f07cc6fdf0 100644
--- a/hw/sparc32_dma.c
+++ b/hw/sparc32_dma.c
@@ -283,22 +283,33 @@ static int sparc32_dma_init1(SysBusDevice *dev)
     return 0;
 }
 
-static SysBusDeviceInfo sparc32_dma_info = {
-    .init = sparc32_dma_init1,
-    .qdev.name  = "sparc32_dma",
-    .qdev.size  = sizeof(DMAState),
-    .qdev.vmsd  = &vmstate_dma,
-    .qdev.reset = dma_reset,
-    .qdev.props = (Property[]) {
-        DEFINE_PROP_PTR("iommu_opaque", DMAState, iommu),
-        DEFINE_PROP_UINT32("is_ledma", DMAState, is_ledma, 0),
-        DEFINE_PROP_END_OF_LIST(),
-    }
+static Property sparc32_dma_properties[] = {
+    DEFINE_PROP_PTR("iommu_opaque", DMAState, iommu),
+    DEFINE_PROP_UINT32("is_ledma", DMAState, is_ledma, 0),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void sparc32_dma_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = sparc32_dma_init1;
+    dc->reset = dma_reset;
+    dc->vmsd = &vmstate_dma;
+    dc->props = sparc32_dma_properties;
+}
+
+static TypeInfo sparc32_dma_info = {
+    .name          = "sparc32_dma",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(DMAState),
+    .class_init    = sparc32_dma_class_init,
 };
 
 static void sparc32_dma_register_devices(void)
 {
-    sysbus_register_withprop(&sparc32_dma_info);
+    type_register_static(&sparc32_dma_info);
 }
 
 device_init(sparc32_dma_register_devices)
diff --git a/hw/spitz.c b/hw/spitz.c
index 9d129c22b9..4e6540d976 100644
--- a/hw/spitz.c
+++ b/hw/spitz.c
@@ -717,7 +717,7 @@ static void spitz_microdrive_attach(PXA2xxState *cpu, int slot)
 
 static void spitz_wm8750_addr(void *opaque, int line, int level)
 {
-    i2c_slave *wm = (i2c_slave *) opaque;
+    I2CSlave *wm = (I2CSlave *) opaque;
     if (level)
         i2c_set_slave_address(wm, SPITZ_WM_ADDRH);
     else
@@ -1023,16 +1023,27 @@ static VMStateDescription vmstate_sl_nand_info = {
     },
 };
 
-static SysBusDeviceInfo sl_nand_info = {
-    .init = sl_nand_init,
-    .qdev.name = "sl-nand",
-    .qdev.size = sizeof(SLNANDState),
-    .qdev.vmsd = &vmstate_sl_nand_info,
-    .qdev.props = (Property []) {
-        DEFINE_PROP_UINT8("manf_id", SLNANDState, manf_id, NAND_MFR_SAMSUNG),
-        DEFINE_PROP_UINT8("chip_id", SLNANDState, chip_id, 0xf1),
-        DEFINE_PROP_END_OF_LIST(),
-    },
+static Property sl_nand_properties[] = {
+    DEFINE_PROP_UINT8("manf_id", SLNANDState, manf_id, NAND_MFR_SAMSUNG),
+    DEFINE_PROP_UINT8("chip_id", SLNANDState, chip_id, 0xf1),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void sl_nand_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = sl_nand_init;
+    dc->vmsd = &vmstate_sl_nand_info;
+    dc->props = sl_nand_properties;
+}
+
+static TypeInfo sl_nand_info = {
+    .name          = "sl-nand",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(SLNANDState),
+    .class_init    = sl_nand_class_init,
 };
 
 static VMStateDescription vmstate_spitz_kbd = {
@@ -1049,14 +1060,25 @@ static VMStateDescription vmstate_spitz_kbd = {
     },
 };
 
-static SysBusDeviceInfo spitz_keyboard_info = {
-    .init = spitz_keyboard_init,
-    .qdev.name = "spitz-keyboard",
-    .qdev.size = sizeof(SpitzKeyboardState),
-    .qdev.vmsd = &vmstate_spitz_kbd,
-    .qdev.props = (Property []) {
-        DEFINE_PROP_END_OF_LIST(),
-    },
+static Property spitz_keyboard_properties[] = {
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void spitz_keyboard_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = spitz_keyboard_init;
+    dc->vmsd = &vmstate_spitz_kbd;
+    dc->props = spitz_keyboard_properties;
+}
+
+static TypeInfo spitz_keyboard_info = {
+    .name          = "spitz-keyboard",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(SpitzKeyboardState),
+    .class_init    = spitz_keyboard_class_init,
 };
 
 static const VMStateDescription vmstate_corgi_ssp_regs = {
@@ -1070,12 +1092,21 @@ static const VMStateDescription vmstate_corgi_ssp_regs = {
     }
 };
 
-static SSISlaveInfo corgi_ssp_info = {
-    .qdev.name = "corgi-ssp",
-    .qdev.size = sizeof(CorgiSSPState),
-    .qdev.vmsd = &vmstate_corgi_ssp_regs,
-    .init = corgi_ssp_init,
-    .transfer = corgi_ssp_transfer
+static void corgi_ssp_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SSISlaveClass *k = SSI_SLAVE_CLASS(klass);
+
+    k->init = corgi_ssp_init;
+    k->transfer = corgi_ssp_transfer;
+    dc->vmsd = &vmstate_corgi_ssp_regs;
+}
+
+static TypeInfo corgi_ssp_info = {
+    .name          = "corgi-ssp",
+    .parent        = TYPE_SSI_SLAVE,
+    .instance_size = sizeof(CorgiSSPState),
+    .class_init    = corgi_ssp_class_init,
 };
 
 static const VMStateDescription vmstate_spitz_lcdtg_regs = {
@@ -1090,20 +1121,29 @@ static const VMStateDescription vmstate_spitz_lcdtg_regs = {
     }
 };
 
-static SSISlaveInfo spitz_lcdtg_info = {
-    .qdev.name = "spitz-lcdtg",
-    .qdev.size = sizeof(SpitzLCDTG),
-    .qdev.vmsd = &vmstate_spitz_lcdtg_regs,
-    .init = spitz_lcdtg_init,
-    .transfer = spitz_lcdtg_transfer
+static void spitz_lcdtg_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SSISlaveClass *k = SSI_SLAVE_CLASS(klass);
+
+    k->init = spitz_lcdtg_init;
+    k->transfer = spitz_lcdtg_transfer;
+    dc->vmsd = &vmstate_spitz_lcdtg_regs;
+}
+
+static TypeInfo spitz_lcdtg_info = {
+    .name          = "spitz-lcdtg",
+    .parent        = TYPE_SSI_SLAVE,
+    .instance_size = sizeof(SpitzLCDTG),
+    .class_init    = spitz_lcdtg_class_init,
 };
 
 static void spitz_register_devices(void)
 {
-    ssi_register_slave(&corgi_ssp_info);
-    ssi_register_slave(&spitz_lcdtg_info);
-    sysbus_register_withprop(&spitz_keyboard_info);
-    sysbus_register_withprop(&sl_nand_info);
+    type_register_static(&corgi_ssp_info);
+    type_register_static(&spitz_lcdtg_info);
+    type_register_static(&spitz_keyboard_info);
+    type_register_static(&sl_nand_info);
 }
 
 device_init(spitz_register_devices)
diff --git a/hw/ssd0303.c b/hw/ssd0303.c
index bcad7bf922..685602a584 100644
--- a/hw/ssd0303.c
+++ b/hw/ssd0303.c
@@ -42,7 +42,7 @@ enum ssd0303_cmd {
 };
 
 typedef struct {
-    i2c_slave i2c;
+    I2CSlave i2c;
     DisplayState *ds;
     int row;
     int col;
@@ -57,13 +57,13 @@ typedef struct {
     uint8_t framebuffer[132*8];
 } ssd0303_state;
 
-static int ssd0303_recv(i2c_slave *i2c)
+static int ssd0303_recv(I2CSlave *i2c)
 {
     BADF("Reads not implemented\n");
     return -1;
 }
 
-static int ssd0303_send(i2c_slave *i2c, uint8_t data)
+static int ssd0303_send(I2CSlave *i2c, uint8_t data)
 {
     ssd0303_state *s = (ssd0303_state *)i2c;
     enum ssd0303_cmd old_cmd_state;
@@ -173,7 +173,7 @@ static int ssd0303_send(i2c_slave *i2c, uint8_t data)
     return 0;
 }
 
-static void ssd0303_event(i2c_slave *i2c, enum i2c_event event)
+static void ssd0303_event(I2CSlave *i2c, enum i2c_event event)
 {
     ssd0303_state *s = (ssd0303_state *)i2c;
     switch (event) {
@@ -283,7 +283,7 @@ static const VMStateDescription vmstate_ssd0303 = {
     }
 };
 
-static int ssd0303_init(i2c_slave *i2c)
+static int ssd0303_init(I2CSlave *i2c)
 {
     ssd0303_state *s = FROM_I2C_SLAVE(ssd0303_state, i2c);
 
@@ -294,19 +294,28 @@ static int ssd0303_init(i2c_slave *i2c)
     return 0;
 }
 
-static I2CSlaveInfo ssd0303_info = {
-    .qdev.name = "ssd0303",
-    .qdev.size = sizeof(ssd0303_state),
-    .qdev.vmsd = &vmstate_ssd0303,
-    .init = ssd0303_init,
-    .event = ssd0303_event,
-    .recv = ssd0303_recv,
-    .send = ssd0303_send
+static void ssd0303_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
+
+    k->init = ssd0303_init;
+    k->event = ssd0303_event;
+    k->recv = ssd0303_recv;
+    k->send = ssd0303_send;
+    dc->vmsd = &vmstate_ssd0303;
+}
+
+static TypeInfo ssd0303_info = {
+    .name          = "ssd0303",
+    .parent        = TYPE_I2C_SLAVE,
+    .instance_size = sizeof(ssd0303_state),
+    .class_init    = ssd0303_class_init,
 };
 
 static void ssd0303_register_devices(void)
 {
-    i2c_register_slave(&ssd0303_info);
+    type_register_static(&ssd0303_info);
 }
 
 device_init(ssd0303_register_devices)
diff --git a/hw/ssd0323.c b/hw/ssd0323.c
index 1eb3823fed..3c43738ae1 100644
--- a/hw/ssd0323.c
+++ b/hw/ssd0323.c
@@ -340,16 +340,24 @@ static int ssd0323_init(SSISlave *dev)
     return 0;
 }
 
-static SSISlaveInfo ssd0323_info = {
-    .qdev.name = "ssd0323",
-    .qdev.size = sizeof(ssd0323_state),
-    .init = ssd0323_init,
-    .transfer = ssd0323_transfer
+static void ssd0323_class_init(ObjectClass *klass, void *data)
+{
+    SSISlaveClass *k = SSI_SLAVE_CLASS(klass);
+
+    k->init = ssd0323_init;
+    k->transfer = ssd0323_transfer;
+}
+
+static TypeInfo ssd0323_info = {
+    .name          = "ssd0323",
+    .parent        = TYPE_SSI_SLAVE,
+    .instance_size = sizeof(ssd0323_state),
+    .class_init    = ssd0323_class_init,
 };
 
 static void ssd03232_register_devices(void)
 {
-    ssi_register_slave(&ssd0323_info);
+    type_register_static(&ssd0323_info);
 }
 
 device_init(ssd03232_register_devices)
diff --git a/hw/ssi-sd.c b/hw/ssi-sd.c
index 2d89cfe522..f2e6cecb71 100644
--- a/hw/ssi-sd.c
+++ b/hw/ssi-sd.c
@@ -244,16 +244,24 @@ static int ssi_sd_init(SSISlave *dev)
     return 0;
 }
 
-static SSISlaveInfo ssi_sd_info = {
-    .qdev.name = "ssi-sd",
-    .qdev.size = sizeof(ssi_sd_state),
-    .init = ssi_sd_init,
-    .transfer = ssi_sd_transfer
+static void ssi_sd_class_init(ObjectClass *klass, void *data)
+{
+    SSISlaveClass *k = SSI_SLAVE_CLASS(klass);
+
+    k->init = ssi_sd_init;
+    k->transfer = ssi_sd_transfer;
+}
+
+static TypeInfo ssi_sd_info = {
+    .name          = "ssi-sd",
+    .parent        = TYPE_SSI_SLAVE,
+    .instance_size = sizeof(ssi_sd_state),
+    .class_init    = ssi_sd_class_init,
 };
 
 static void ssi_sd_register_devices(void)
 {
-    ssi_register_slave(&ssi_sd_info);
+    type_register_static(&ssi_sd_info);
 }
 
 device_init(ssi_sd_register_devices)
diff --git a/hw/ssi.c b/hw/ssi.c
index b47953a989..ead446c49a 100644
--- a/hw/ssi.c
+++ b/hw/ssi.c
@@ -21,10 +21,10 @@ static struct BusInfo ssi_bus_info = {
     .size = sizeof(SSIBus),
 };
 
-static int ssi_slave_init(DeviceState *dev, DeviceInfo *base_info)
+static int ssi_slave_init(DeviceState *dev)
 {
-    SSISlaveInfo *info = container_of(base_info, SSISlaveInfo, qdev);
-    SSISlave *s = SSI_SLAVE_FROM_QDEV(dev);
+    SSISlave *s = SSI_SLAVE(dev);
+    SSISlaveClass *ssc = SSI_SLAVE_GET_CLASS(s);
     SSIBus *bus;
 
     bus = FROM_QBUS(SSIBus, qdev_get_parent_bus(dev));
@@ -33,18 +33,24 @@ static int ssi_slave_init(DeviceState *dev, DeviceInfo *base_info)
         hw_error("Too many devices on SSI bus");
     }
 
-    s->info = info;
-    return info->init(s);
+    return ssc->init(s);
 }
 
-void ssi_register_slave(SSISlaveInfo *info)
+static void ssi_slave_class_init(ObjectClass *klass, void *data)
 {
-    assert(info->qdev.size >= sizeof(SSISlave));
-    info->qdev.init = ssi_slave_init;
-    info->qdev.bus_info = &ssi_bus_info;
-    qdev_register(&info->qdev);
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    dc->init = ssi_slave_init;
+    dc->bus_info = &ssi_bus_info;
 }
 
+static TypeInfo ssi_slave_info = {
+    .name = TYPE_SSI_SLAVE,
+    .parent = TYPE_DEVICE,
+    .class_init = ssi_slave_class_init,
+    .class_size = sizeof(SSISlaveClass),
+    .abstract = true,
+};
+
 DeviceState *ssi_create_slave(SSIBus *bus, const char *name)
 {
     DeviceState *dev;
@@ -64,10 +70,19 @@ uint32_t ssi_transfer(SSIBus *bus, uint32_t val)
 {
     DeviceState *dev;
     SSISlave *slave;
+    SSISlaveClass *ssc;
     dev = QTAILQ_FIRST(&bus->qbus.children);
     if (!dev) {
         return 0;
     }
-    slave = SSI_SLAVE_FROM_QDEV(dev);
-    return slave->info->transfer(slave, val);
+    slave = SSI_SLAVE(dev);
+    ssc = SSI_SLAVE_GET_CLASS(slave);
+    return ssc->transfer(slave, val);
+}
+
+static void register_ssi_slave(void)
+{
+    type_register_static(&ssi_slave_info);
 }
+
+device_init(register_ssi_slave);
diff --git a/hw/ssi.h b/hw/ssi.h
index 24610a80cb..06657d7c16 100644
--- a/hw/ssi.h
+++ b/hw/ssi.h
@@ -15,23 +15,29 @@
 
 typedef struct SSISlave SSISlave;
 
+#define TYPE_SSI_SLAVE "ssi-slave"
+#define SSI_SLAVE(obj) \
+     OBJECT_CHECK(SSISlave, (obj), TYPE_SSI_SLAVE)
+#define SSI_SLAVE_CLASS(klass) \
+     OBJECT_CLASS_CHECK(SSISlaveClass, (klass), TYPE_SSI_SLAVE)
+#define SSI_SLAVE_GET_CLASS(obj) \
+     OBJECT_GET_CLASS(SSISlaveClass, (obj), TYPE_SSI_SLAVE)
+
 /* Slave devices.  */
-typedef struct {
-    DeviceInfo qdev;
+typedef struct SSISlaveClass {
+    DeviceClass parent_class;
+
     int (*init)(SSISlave *dev);
     uint32_t (*transfer)(SSISlave *dev, uint32_t val);
-} SSISlaveInfo;
+} SSISlaveClass;
 
 struct SSISlave {
     DeviceState qdev;
-    SSISlaveInfo *info;
 };
 
 #define SSI_SLAVE_FROM_QDEV(dev) DO_UPCAST(SSISlave, qdev, dev)
 #define FROM_SSI_SLAVE(type, dev) DO_UPCAST(type, ssidev, dev)
 
-void ssi_register_slave(SSISlaveInfo *info);
-
 DeviceState *ssi_create_slave(SSIBus *bus, const char *name);
 
 /* Master interface.  */
diff --git a/hw/stellaris.c b/hw/stellaris.c
index 7a73074982..31a65cfb77 100644
--- a/hw/stellaris.c
+++ b/hw/stellaris.c
@@ -1394,22 +1394,69 @@ static void stellaris_machine_init(void)
 
 machine_init(stellaris_machine_init);
 
-static SSISlaveInfo stellaris_ssi_bus_info = {
-    .qdev.name = "evb6965-ssi",
-    .qdev.size = sizeof(stellaris_ssi_bus_state),
-    .init = stellaris_ssi_bus_init,
-    .transfer = stellaris_ssi_bus_transfer
+static void stellaris_ssi_bus_class_init(ObjectClass *klass, void *data)
+{
+    SSISlaveClass *k = SSI_SLAVE_CLASS(klass);
+
+    k->init = stellaris_ssi_bus_init;
+    k->transfer = stellaris_ssi_bus_transfer;
+}
+
+static TypeInfo stellaris_ssi_bus_info = {
+    .name          = "evb6965-ssi",
+    .parent        = TYPE_SSI_SLAVE,
+    .instance_size = sizeof(stellaris_ssi_bus_state),
+    .class_init    = stellaris_ssi_bus_class_init,
+};
+
+static void stellaris_i2c_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+
+    sdc->init = stellaris_i2c_init;
+}
+
+static TypeInfo stellaris_i2c_info = {
+    .name          = "stellaris-i2c",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(stellaris_i2c_state),
+    .class_init    = stellaris_i2c_class_init,
+};
+
+static void stellaris_gptm_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+
+    sdc->init = stellaris_gptm_init;
+}
+
+static TypeInfo stellaris_gptm_info = {
+    .name          = "stellaris-gptm",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(gptm_state),
+    .class_init    = stellaris_gptm_class_init,
+};
+
+static void stellaris_adc_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+
+    sdc->init = stellaris_adc_init;
+}
+
+static TypeInfo stellaris_adc_info = {
+    .name          = "stellaris-adc",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(stellaris_adc_state),
+    .class_init    = stellaris_adc_class_init,
 };
 
 static void stellaris_register_devices(void)
 {
-    sysbus_register_dev("stellaris-i2c", sizeof(stellaris_i2c_state),
-                        stellaris_i2c_init);
-    sysbus_register_dev("stellaris-gptm", sizeof(gptm_state),
-                        stellaris_gptm_init);
-    sysbus_register_dev("stellaris-adc", sizeof(stellaris_adc_state),
-                        stellaris_adc_init);
-    ssi_register_slave(&stellaris_ssi_bus_info);
+    type_register_static(&stellaris_i2c_info);
+    type_register_static(&stellaris_gptm_info);
+    type_register_static(&stellaris_adc_info);
+    type_register_static(&stellaris_ssi_bus_info);
 }
 
 device_init(stellaris_register_devices)
diff --git a/hw/stellaris_enet.c b/hw/stellaris_enet.c
index 866c9a2381..9b1be8dadc 100644
--- a/hw/stellaris_enet.c
+++ b/hw/stellaris_enet.c
@@ -411,7 +411,7 @@ static int stellaris_enet_init(SysBusDevice *dev)
     qemu_macaddr_default_if_unset(&s->conf.macaddr);
 
     s->nic = qemu_new_nic(&net_stellaris_enet_info, &s->conf,
-                          dev->qdev.info->name, dev->qdev.id, s);
+                          object_get_typename(OBJECT(dev)), dev->qdev.id, s);
     qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a);
 
     stellaris_enet_reset(s);
@@ -420,19 +420,30 @@ static int stellaris_enet_init(SysBusDevice *dev)
     return 0;
 }
 
-static SysBusDeviceInfo stellaris_enet_info = {
-    .init = stellaris_enet_init,
-    .qdev.name  = "stellaris_enet",
-    .qdev.size  = sizeof(stellaris_enet_state),
-    .qdev.props = (Property[]) {
-        DEFINE_NIC_PROPERTIES(stellaris_enet_state, conf),
-        DEFINE_PROP_END_OF_LIST(),
-    }
+static Property stellaris_enet_properties[] = {
+    DEFINE_NIC_PROPERTIES(stellaris_enet_state, conf),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void stellaris_enet_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = stellaris_enet_init;
+    dc->props = stellaris_enet_properties;
+}
+
+static TypeInfo stellaris_enet_info = {
+    .name          = "stellaris_enet",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(stellaris_enet_state),
+    .class_init    = stellaris_enet_class_init,
 };
 
 static void stellaris_enet_register_devices(void)
 {
-    sysbus_register_withprop(&stellaris_enet_info);
+    type_register_static(&stellaris_enet_info);
 }
 
 device_init(stellaris_enet_register_devices)
diff --git a/hw/strongarm.c b/hw/strongarm.c
index fe63fd7ab7..8d2e7eb6fe 100644
--- a/hw/strongarm.c
+++ b/hw/strongarm.c
@@ -201,12 +201,21 @@ static VMStateDescription vmstate_strongarm_pic_regs = {
     },
 };
 
-static SysBusDeviceInfo strongarm_pic_info = {
-    .init       = strongarm_pic_initfn,
-    .qdev.name  = "strongarm_pic",
-    .qdev.desc  = "StrongARM PIC",
-    .qdev.size  = sizeof(StrongARMPICState),
-    .qdev.vmsd  = &vmstate_strongarm_pic_regs,
+static void strongarm_pic_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = strongarm_pic_initfn;
+    dc->desc = "StrongARM PIC";
+    dc->vmsd = &vmstate_strongarm_pic_regs;
+}
+
+static TypeInfo strongarm_pic_info = {
+    .name          = "strongarm_pic",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(StrongARMPICState),
+    .class_init    = strongarm_pic_class_init,
 };
 
 /* Real-Time Clock */
@@ -413,12 +422,21 @@ static const VMStateDescription vmstate_strongarm_rtc_regs = {
     },
 };
 
-static SysBusDeviceInfo strongarm_rtc_sysbus_info = {
-    .init       = strongarm_rtc_init,
-    .qdev.name  = "strongarm-rtc",
-    .qdev.desc  = "StrongARM RTC Controller",
-    .qdev.size  = sizeof(StrongARMRTCState),
-    .qdev.vmsd  = &vmstate_strongarm_rtc_regs,
+static void strongarm_rtc_sysbus_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = strongarm_rtc_init;
+    dc->desc = "StrongARM RTC Controller";
+    dc->vmsd = &vmstate_strongarm_rtc_regs;
+}
+
+static TypeInfo strongarm_rtc_sysbus_info = {
+    .name          = "strongarm-rtc",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(StrongARMRTCState),
+    .class_init    = strongarm_rtc_sysbus_class_init,
 };
 
 /* GPIO */
@@ -646,11 +664,20 @@ static const VMStateDescription vmstate_strongarm_gpio_regs = {
     },
 };
 
-static SysBusDeviceInfo strongarm_gpio_info = {
-    .init       = strongarm_gpio_initfn,
-    .qdev.name  = "strongarm-gpio",
-    .qdev.desc  = "StrongARM GPIO controller",
-    .qdev.size  = sizeof(StrongARMGPIOInfo),
+static void strongarm_gpio_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = strongarm_gpio_initfn;
+    dc->desc = "StrongARM GPIO controller";
+}
+
+static TypeInfo strongarm_gpio_info = {
+    .name          = "strongarm-gpio",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(StrongARMGPIOInfo),
+    .class_init    = strongarm_gpio_class_init,
 };
 
 /* Peripheral Pin Controller */
@@ -803,11 +830,20 @@ static const VMStateDescription vmstate_strongarm_ppc_regs = {
     },
 };
 
-static SysBusDeviceInfo strongarm_ppc_info = {
-    .init       = strongarm_ppc_init,
-    .qdev.name  = "strongarm-ppc",
-    .qdev.desc  = "StrongARM PPC controller",
-    .qdev.size  = sizeof(StrongARMPPCInfo),
+static void strongarm_ppc_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = strongarm_ppc_init;
+    dc->desc = "StrongARM PPC controller";
+}
+
+static TypeInfo strongarm_ppc_info = {
+    .name          = "strongarm-ppc",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(StrongARMPPCInfo),
+    .class_init    = strongarm_ppc_class_init,
 };
 
 /* UART Ports */
@@ -1245,17 +1281,28 @@ static const VMStateDescription vmstate_strongarm_uart_regs = {
     },
 };
 
-static SysBusDeviceInfo strongarm_uart_info = {
-    .init       = strongarm_uart_init,
-    .qdev.name  = "strongarm-uart",
-    .qdev.desc  = "StrongARM UART controller",
-    .qdev.size  = sizeof(StrongARMUARTState),
-    .qdev.reset = strongarm_uart_reset,
-    .qdev.vmsd  = &vmstate_strongarm_uart_regs,
-    .qdev.props = (Property[]) {
-        DEFINE_PROP_CHR("chardev", StrongARMUARTState, chr),
-        DEFINE_PROP_END_OF_LIST(),
-    }
+static Property strongarm_uart_properties[] = {
+    DEFINE_PROP_CHR("chardev", StrongARMUARTState, chr),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void strongarm_uart_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = strongarm_uart_init;
+    dc->desc = "StrongARM UART controller";
+    dc->reset = strongarm_uart_reset;
+    dc->vmsd = &vmstate_strongarm_uart_regs;
+    dc->props = strongarm_uart_properties;
+}
+
+static TypeInfo strongarm_uart_info = {
+    .name          = "strongarm-uart",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(StrongARMUARTState),
+    .class_init    = strongarm_uart_class_init,
 };
 
 /* Synchronous Serial Ports */
@@ -1479,13 +1526,22 @@ static const VMStateDescription vmstate_strongarm_ssp_regs = {
     },
 };
 
-static SysBusDeviceInfo strongarm_ssp_info = {
-    .init       = strongarm_ssp_init,
-    .qdev.name  = "strongarm-ssp",
-    .qdev.desc  = "StrongARM SSP controller",
-    .qdev.size  = sizeof(StrongARMSSPState),
-    .qdev.reset = strongarm_ssp_reset,
-    .qdev.vmsd  = &vmstate_strongarm_ssp_regs,
+static void strongarm_ssp_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = strongarm_ssp_init;
+    dc->desc = "StrongARM SSP controller";
+    dc->reset = strongarm_ssp_reset;
+    dc->vmsd = &vmstate_strongarm_ssp_regs;
+}
+
+static TypeInfo strongarm_ssp_info = {
+    .name          = "strongarm-ssp",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(StrongARMSSPState),
+    .class_init    = strongarm_ssp_class_init,
 };
 
 /* Main CPU functions */
@@ -1555,11 +1611,11 @@ StrongARMState *sa1110_init(MemoryRegion *sysmem,
 
 static void strongarm_register_devices(void)
 {
-    sysbus_register_withprop(&strongarm_pic_info);
-    sysbus_register_withprop(&strongarm_rtc_sysbus_info);
-    sysbus_register_withprop(&strongarm_gpio_info);
-    sysbus_register_withprop(&strongarm_ppc_info);
-    sysbus_register_withprop(&strongarm_uart_info);
-    sysbus_register_withprop(&strongarm_ssp_info);
+    type_register_static(&strongarm_pic_info);
+    type_register_static(&strongarm_rtc_sysbus_info);
+    type_register_static(&strongarm_gpio_info);
+    type_register_static(&strongarm_ppc_info);
+    type_register_static(&strongarm_uart_info);
+    type_register_static(&strongarm_ssp_info);
 }
 device_init(strongarm_register_devices)
diff --git a/hw/sun4c_intctl.c b/hw/sun4c_intctl.c
index e15b1674ce..081d6cc8bd 100644
--- a/hw/sun4c_intctl.c
+++ b/hw/sun4c_intctl.c
@@ -206,17 +206,26 @@ static int sun4c_intctl_init1(SysBusDevice *dev)
     return 0;
 }
 
-static SysBusDeviceInfo sun4c_intctl_info = {
-    .init = sun4c_intctl_init1,
-    .qdev.name  = "sun4c_intctl",
-    .qdev.size  = sizeof(Sun4c_INTCTLState),
-    .qdev.vmsd  = &vmstate_sun4c_intctl,
-    .qdev.reset = sun4c_intctl_reset,
+static void sun4c_intctl_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = sun4c_intctl_init1;
+    dc->reset = sun4c_intctl_reset;
+    dc->vmsd = &vmstate_sun4c_intctl;
+}
+
+static TypeInfo sun4c_intctl_info = {
+    .name          = "sun4c_intctl",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(Sun4c_INTCTLState),
+    .class_init    = sun4c_intctl_class_init,
 };
 
 static void sun4c_intctl_register_devices(void)
 {
-    sysbus_register_withprop(&sun4c_intctl_info);
+    type_register_static(&sun4c_intctl_info);
 }
 
 device_init(sun4c_intctl_register_devices)
diff --git a/hw/sun4m.c b/hw/sun4m.c
index 941cc98b9b..b79d14c35a 100644
--- a/hw/sun4m.c
+++ b/hw/sun4m.c
@@ -609,15 +609,23 @@ static int idreg_init1(SysBusDevice *dev)
     return 0;
 }
 
-static SysBusDeviceInfo idreg_info = {
-    .init = idreg_init1,
-    .qdev.name  = "macio_idreg",
-    .qdev.size  = sizeof(IDRegState),
+static void idreg_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = idreg_init1;
+}
+
+static TypeInfo idreg_info = {
+    .name          = "macio_idreg",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(IDRegState),
+    .class_init    = idreg_class_init,
 };
 
 static void idreg_register_devices(void)
 {
-    sysbus_register_withprop(&idreg_info);
+    type_register_static(&idreg_info);
 }
 
 device_init(idreg_register_devices);
@@ -650,15 +658,23 @@ static int afx_init1(SysBusDevice *dev)
     return 0;
 }
 
-static SysBusDeviceInfo afx_info = {
-    .init = afx_init1,
-    .qdev.name  = "tcx_afx",
-    .qdev.size  = sizeof(AFXState),
+static void afx_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = afx_init1;
+}
+
+static TypeInfo afx_info = {
+    .name          = "tcx_afx",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(AFXState),
+    .class_init    = afx_class_init,
 };
 
 static void afx_register_devices(void)
 {
-    sysbus_register_withprop(&afx_info);
+    type_register_static(&afx_info);
 }
 
 device_init(afx_register_devices);
@@ -720,18 +736,29 @@ static int prom_init1(SysBusDevice *dev)
     return 0;
 }
 
-static SysBusDeviceInfo prom_info = {
-    .init = prom_init1,
-    .qdev.name  = "openprom",
-    .qdev.size  = sizeof(PROMState),
-    .qdev.props = (Property[]) {
-        {/* end of property list */}
-    }
+static Property prom_properties[] = {
+    {/* end of property list */},
+};
+
+static void prom_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = prom_init1;
+    dc->props = prom_properties;
+}
+
+static TypeInfo prom_info = {
+    .name          = "openprom",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(PROMState),
+    .class_init    = prom_class_init,
 };
 
 static void prom_register_devices(void)
 {
-    sysbus_register_withprop(&prom_info);
+    type_register_static(&prom_info);
 }
 
 device_init(prom_register_devices);
@@ -779,19 +806,30 @@ static void ram_init(target_phys_addr_t addr, ram_addr_t RAM_size,
     sysbus_mmio_map(s, 0, addr);
 }
 
-static SysBusDeviceInfo ram_info = {
-    .init = ram_init1,
-    .qdev.name  = "memory",
-    .qdev.size  = sizeof(RamDevice),
-    .qdev.props = (Property[]) {
-        DEFINE_PROP_UINT64("size", RamDevice, size, 0),
-        DEFINE_PROP_END_OF_LIST(),
-    }
+static Property ram_properties[] = {
+    DEFINE_PROP_UINT64("size", RamDevice, size, 0),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void ram_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = ram_init1;
+    dc->props = ram_properties;
+}
+
+static TypeInfo ram_info = {
+    .name          = "memory",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(RamDevice),
+    .class_init    = ram_class_init,
 };
 
 static void ram_register_devices(void)
 {
-    sysbus_register_withprop(&ram_info);
+    type_register_static(&ram_info);
 }
 
 device_init(ram_register_devices);
diff --git a/hw/sun4m_iommu.c b/hw/sun4m_iommu.c
index ef7627c467..727532cb09 100644
--- a/hw/sun4m_iommu.c
+++ b/hw/sun4m_iommu.c
@@ -357,21 +357,32 @@ static int iommu_init1(SysBusDevice *dev)
     return 0;
 }
 
-static SysBusDeviceInfo iommu_info = {
-    .init = iommu_init1,
-    .qdev.name  = "iommu",
-    .qdev.size  = sizeof(IOMMUState),
-    .qdev.vmsd  = &vmstate_iommu,
-    .qdev.reset = iommu_reset,
-    .qdev.props = (Property[]) {
-        DEFINE_PROP_HEX32("version", IOMMUState, version, 0),
-        DEFINE_PROP_END_OF_LIST(),
-    }
+static Property iommu_properties[] = {
+    DEFINE_PROP_HEX32("version", IOMMUState, version, 0),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void iommu_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = iommu_init1;
+    dc->reset = iommu_reset;
+    dc->vmsd = &vmstate_iommu;
+    dc->props = iommu_properties;
+}
+
+static TypeInfo iommu_info = {
+    .name          = "iommu",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(IOMMUState),
+    .class_init    = iommu_class_init,
 };
 
 static void iommu_register_devices(void)
 {
-    sysbus_register_withprop(&iommu_info);
+    type_register_static(&iommu_info);
 }
 
 device_init(iommu_register_devices)
diff --git a/hw/sun4u.c b/hw/sun4u.c
index 2dc3d0439f..79bbd495eb 100644
--- a/hw/sun4u.c
+++ b/hw/sun4u.c
@@ -562,19 +562,27 @@ pci_ebus_init1(PCIDevice *pci_dev)
     return 0;
 }
 
-static PCIDeviceInfo ebus_info = {
-    .qdev.name = "ebus",
-    .qdev.size = sizeof(EbusState),
-    .init = pci_ebus_init1,
-    .vendor_id = PCI_VENDOR_ID_SUN,
-    .device_id = PCI_DEVICE_ID_SUN_EBUS,
-    .revision = 0x01,
-    .class_id = PCI_CLASS_BRIDGE_OTHER,
+static void ebus_class_init(ObjectClass *klass, void *data)
+{
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->init = pci_ebus_init1;
+    k->vendor_id = PCI_VENDOR_ID_SUN;
+    k->device_id = PCI_DEVICE_ID_SUN_EBUS;
+    k->revision = 0x01;
+    k->class_id = PCI_CLASS_BRIDGE_OTHER;
+}
+
+static TypeInfo ebus_info = {
+    .name          = "ebus",
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(EbusState),
+    .class_init    = ebus_class_init,
 };
 
 static void pci_ebus_register(void)
 {
-    pci_qdev_register(&ebus_info);
+    type_register_static(&ebus_info);
 }
 
 device_init(pci_ebus_register);
@@ -636,18 +644,29 @@ static int prom_init1(SysBusDevice *dev)
     return 0;
 }
 
-static SysBusDeviceInfo prom_info = {
-    .init = prom_init1,
-    .qdev.name  = "openprom",
-    .qdev.size  = sizeof(PROMState),
-    .qdev.props = (Property[]) {
-        {/* end of property list */}
-    }
+static Property prom_properties[] = {
+    {/* end of property list */},
+};
+
+static void prom_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = prom_init1;
+    dc->props = prom_properties;
+}
+
+static TypeInfo prom_info = {
+    .name          = "openprom",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(PROMState),
+    .class_init    = prom_class_init,
 };
 
 static void prom_register_devices(void)
 {
-    sysbus_register_withprop(&prom_info);
+    type_register_static(&prom_info);
 }
 
 device_init(prom_register_devices);
@@ -688,19 +707,30 @@ static void ram_init(target_phys_addr_t addr, ram_addr_t RAM_size)
     sysbus_mmio_map(s, 0, addr);
 }
 
-static SysBusDeviceInfo ram_info = {
-    .init = ram_init1,
-    .qdev.name  = "memory",
-    .qdev.size  = sizeof(RamDevice),
-    .qdev.props = (Property[]) {
-        DEFINE_PROP_UINT64("size", RamDevice, size, 0),
-        DEFINE_PROP_END_OF_LIST(),
-    }
+static Property ram_properties[] = {
+    DEFINE_PROP_UINT64("size", RamDevice, size, 0),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void ram_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = ram_init1;
+    dc->props = ram_properties;
+}
+
+static TypeInfo ram_info = {
+    .name          = "memory",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(RamDevice),
+    .class_init    = ram_class_init,
 };
 
 static void ram_register_devices(void)
 {
-    sysbus_register_withprop(&ram_info);
+    type_register_static(&ram_info);
 }
 
 device_init(ram_register_devices);
diff --git a/hw/sysbus.c b/hw/sysbus.c
index 2e06fe823c..282060abb6 100644
--- a/hw/sysbus.c
+++ b/hw/sysbus.c
@@ -105,31 +105,12 @@ void sysbus_init_ioports(SysBusDevice *dev, pio_addr_t ioport, pio_addr_t size)
     }
 }
 
-static int sysbus_device_init(DeviceState *dev, DeviceInfo *base)
+static int sysbus_device_init(DeviceState *dev)
 {
-    SysBusDeviceInfo *info = container_of(base, SysBusDeviceInfo, qdev);
+    SysBusDevice *sd = SYS_BUS_DEVICE(dev);
+    SysBusDeviceClass *sbc = SYS_BUS_DEVICE_GET_CLASS(sd);
 
-    return info->init(sysbus_from_qdev(dev));
-}
-
-void sysbus_register_withprop(SysBusDeviceInfo *info)
-{
-    info->qdev.init = sysbus_device_init;
-    info->qdev.bus_info = &system_bus_info;
-
-    assert(info->qdev.size >= sizeof(SysBusDevice));
-    qdev_register(&info->qdev);
-}
-
-void sysbus_register_dev(const char *name, size_t size, sysbus_initfn init)
-{
-    SysBusDeviceInfo *info;
-
-    info = g_malloc0(sizeof(*info));
-    info->qdev.name = g_strdup(name);
-    info->qdev.size = size;
-    info->init = init;
-    sysbus_register_withprop(info);
+    return sbc->init(sd);
 }
 
 DeviceState *sysbus_create_varargs(const char *name,
@@ -258,3 +239,26 @@ MemoryRegion *sysbus_address_space(SysBusDevice *dev)
 {
     return get_system_memory();
 }
+
+static void sysbus_device_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *k = DEVICE_CLASS(klass);
+    k->init = sysbus_device_init;
+    k->bus_info = &system_bus_info;
+}
+
+static TypeInfo sysbus_device_type_info = {
+    .name = TYPE_SYS_BUS_DEVICE,
+    .parent = TYPE_DEVICE,
+    .instance_size = sizeof(SysBusDevice),
+    .abstract = true,
+    .class_size = sizeof(SysBusDeviceClass),
+    .class_init = sysbus_device_class_init,
+};
+
+static void sysbus_register(void)
+{
+    type_register_static(&sysbus_device_type_info);
+}
+
+device_init(sysbus_register);
diff --git a/hw/sysbus.h b/hw/sysbus.h
index 7b8ca236bf..22555cd443 100644
--- a/hw/sysbus.h
+++ b/hw/sysbus.h
@@ -12,6 +12,20 @@
 
 typedef struct SysBusDevice SysBusDevice;
 
+#define TYPE_SYS_BUS_DEVICE "sys-bus-device"
+#define SYS_BUS_DEVICE(obj) \
+     OBJECT_CHECK(SysBusDevice, (obj), TYPE_SYS_BUS_DEVICE)
+#define SYS_BUS_DEVICE_CLASS(klass) \
+     OBJECT_CLASS_CHECK(SysBusDeviceClass, (klass), TYPE_SYS_BUS_DEVICE)
+#define SYS_BUS_DEVICE_GET_CLASS(obj) \
+     OBJECT_GET_CLASS(SysBusDeviceClass, (obj), TYPE_SYS_BUS_DEVICE)
+
+typedef struct SysBusDeviceClass {
+    DeviceClass parent_class;
+
+    int (*init)(SysBusDevice *dev);
+} SysBusDeviceClass;
+
 struct SysBusDevice {
     DeviceState qdev;
     int num_irq;
@@ -26,19 +40,10 @@ struct SysBusDevice {
     pio_addr_t pio[QDEV_MAX_PIO];
 };
 
-typedef int (*sysbus_initfn)(SysBusDevice *dev);
-
 /* Macros to compensate for lack of type inheritance in C.  */
 #define sysbus_from_qdev(dev) ((SysBusDevice *)(dev))
 #define FROM_SYSBUS(type, dev) DO_UPCAST(type, busdev, dev)
 
-typedef struct {
-    DeviceInfo qdev;
-    sysbus_initfn init;
-} SysBusDeviceInfo;
-
-void sysbus_register_dev(const char *name, size_t size, sysbus_initfn init);
-void sysbus_register_withprop(SysBusDeviceInfo *info);
 void *sysbus_new(void);
 void sysbus_init_mmio(SysBusDevice *dev, MemoryRegion *memory);
 MemoryRegion *sysbus_mmio_get_region(SysBusDevice *dev, int n);
diff --git a/hw/tcx.c b/hw/tcx.c
index 75a28f2ee5..ceb94c74a7 100644
--- a/hw/tcx.c
+++ b/hw/tcx.c
@@ -61,21 +61,13 @@ static void tcx24_screen_dump(void *opaque, const char *filename);
 
 static void tcx_set_dirty(TCXState *s)
 {
-    unsigned int i;
-
-    for (i = 0; i < MAXX * MAXY; i += TARGET_PAGE_SIZE) {
-        memory_region_set_dirty(&s->vram_mem, i);
-    }
+    memory_region_set_dirty(&s->vram_mem, 0, MAXX * MAXY);
 }
 
 static void tcx24_set_dirty(TCXState *s)
 {
-    unsigned int i;
-
-    for (i = 0; i < MAXX * MAXY * 4; i += TARGET_PAGE_SIZE) {
-        memory_region_set_dirty(&s->vram_mem, s->vram24_offset + i);
-        memory_region_set_dirty(&s->vram_mem, s->cplane_offset + i);
-    }
+    memory_region_set_dirty(&s->vram_mem, s->vram24_offset, MAXX * MAXY * 4);
+    memory_region_set_dirty(&s->vram_mem, s->cplane_offset, MAXX * MAXY * 4);
 }
 
 static void update_palette_entries(TCXState *s, int start, int end)
@@ -186,15 +178,13 @@ static inline int check_dirty(TCXState *s, ram_addr_t page, ram_addr_t page24,
                               ram_addr_t cpage)
 {
     int ret;
-    unsigned int off;
-
-    ret = memory_region_get_dirty(&s->vram_mem, page, DIRTY_MEMORY_VGA);
-    for (off = 0; off < TARGET_PAGE_SIZE * 4; off += TARGET_PAGE_SIZE) {
-        ret |= memory_region_get_dirty(&s->vram_mem, page24 + off,
-                                       DIRTY_MEMORY_VGA);
-        ret |= memory_region_get_dirty(&s->vram_mem, cpage + off,
-                                       DIRTY_MEMORY_VGA);
-    }
+
+    ret = memory_region_get_dirty(&s->vram_mem, page, TARGET_PAGE_SIZE,
+                                  DIRTY_MEMORY_VGA);
+    ret |= memory_region_get_dirty(&s->vram_mem, page24, TARGET_PAGE_SIZE * 4,
+                                   DIRTY_MEMORY_VGA);
+    ret |= memory_region_get_dirty(&s->vram_mem, cpage, TARGET_PAGE_SIZE * 4,
+                                   DIRTY_MEMORY_VGA);
     return ret;
 }
 
@@ -253,7 +243,8 @@ static void tcx_update_display(void *opaque)
     }
 
     for(y = 0; y < ts->height; y += 4, page += TARGET_PAGE_SIZE) {
-        if (memory_region_get_dirty(&ts->vram_mem, page, DIRTY_MEMORY_VGA)) {
+        if (memory_region_get_dirty(&ts->vram_mem, page, TARGET_PAGE_SIZE,
+                                    DIRTY_MEMORY_VGA)) {
             if (y_start < 0)
                 y_start = y;
             if (page < page_min)
@@ -646,25 +637,36 @@ static void tcx24_screen_dump(void *opaque, const char *filename)
     return;
 }
 
-static SysBusDeviceInfo tcx_info = {
-    .init = tcx_init1,
-    .qdev.name  = "SUNW,tcx",
-    .qdev.size  = sizeof(TCXState),
-    .qdev.reset = tcx_reset,
-    .qdev.vmsd  = &vmstate_tcx,
-    .qdev.props = (Property[]) {
-        DEFINE_PROP_TADDR("addr",      TCXState, addr,      -1),
-        DEFINE_PROP_HEX32("vram_size", TCXState, vram_size, -1),
-        DEFINE_PROP_UINT16("width",    TCXState, width,     -1),
-        DEFINE_PROP_UINT16("height",   TCXState, height,    -1),
-        DEFINE_PROP_UINT16("depth",    TCXState, depth,     -1),
-        DEFINE_PROP_END_OF_LIST(),
-    }
+static Property tcx_properties[] = {
+    DEFINE_PROP_TADDR("addr",      TCXState, addr,      -1),
+    DEFINE_PROP_HEX32("vram_size", TCXState, vram_size, -1),
+    DEFINE_PROP_UINT16("width",    TCXState, width,     -1),
+    DEFINE_PROP_UINT16("height",   TCXState, height,    -1),
+    DEFINE_PROP_UINT16("depth",    TCXState, depth,     -1),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void tcx_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = tcx_init1;
+    dc->reset = tcx_reset;
+    dc->vmsd = &vmstate_tcx;
+    dc->props = tcx_properties;
+}
+
+static TypeInfo tcx_info = {
+    .name          = "SUNW,tcx",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(TCXState),
+    .class_init    = tcx_class_init,
 };
 
 static void tcx_register_devices(void)
 {
-    sysbus_register_withprop(&tcx_info);
+    type_register_static(&tcx_info);
 }
 
 device_init(tcx_register_devices)
diff --git a/hw/tmp105.c b/hw/tmp105.c
index f7e6f2b909..a3bdd91d40 100644
--- a/hw/tmp105.c
+++ b/hw/tmp105.c
@@ -22,7 +22,7 @@
 #include "i2c.h"
 
 typedef struct {
-    i2c_slave i2c;
+    I2CSlave i2c;
     uint8_t len;
     uint8_t buf[2];
     qemu_irq pin;
@@ -65,7 +65,7 @@ static void tmp105_alarm_update(TMP105State *s)
 }
 
 /* Units are 0.001 centigrades relative to 0 C.  */
-void tmp105_set(i2c_slave *i2c, int temp)
+void tmp105_set(I2CSlave *i2c, int temp)
 {
     TMP105State *s = (TMP105State *) i2c;
 
@@ -138,7 +138,7 @@ static void tmp105_write(TMP105State *s)
     }
 }
 
-static int tmp105_rx(i2c_slave *i2c)
+static int tmp105_rx(I2CSlave *i2c)
 {
     TMP105State *s = (TMP105State *) i2c;
 
@@ -148,7 +148,7 @@ static int tmp105_rx(i2c_slave *i2c)
         return 0xff;
 }
 
-static int tmp105_tx(i2c_slave *i2c, uint8_t data)
+static int tmp105_tx(I2CSlave *i2c, uint8_t data)
 {
     TMP105State *s = (TMP105State *) i2c;
 
@@ -163,7 +163,7 @@ static int tmp105_tx(i2c_slave *i2c, uint8_t data)
     return 0;
 }
 
-static void tmp105_event(i2c_slave *i2c, enum i2c_event event)
+static void tmp105_event(I2CSlave *i2c, enum i2c_event event)
 {
     TMP105State *s = (TMP105State *) i2c;
 
@@ -202,7 +202,7 @@ static const VMStateDescription vmstate_tmp105 = {
     }
 };
 
-static void tmp105_reset(i2c_slave *i2c)
+static void tmp105_reset(I2CSlave *i2c)
 {
     TMP105State *s = (TMP105State *) i2c;
 
@@ -215,7 +215,7 @@ static void tmp105_reset(i2c_slave *i2c)
     tmp105_interrupt_update(s);
 }
 
-static int tmp105_init(i2c_slave *i2c)
+static int tmp105_init(I2CSlave *i2c)
 {
     TMP105State *s = FROM_I2C_SLAVE(TMP105State, i2c);
 
@@ -226,19 +226,28 @@ static int tmp105_init(i2c_slave *i2c)
     return 0;
 }
 
-static I2CSlaveInfo tmp105_info = {
-    .qdev.name = "tmp105",
-    .qdev.size = sizeof(TMP105State),
-    .qdev.vmsd = &vmstate_tmp105,
-    .init = tmp105_init,
-    .event = tmp105_event,
-    .recv = tmp105_rx,
-    .send = tmp105_tx
+static void tmp105_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
+
+    k->init = tmp105_init;
+    k->event = tmp105_event;
+    k->recv = tmp105_rx;
+    k->send = tmp105_tx;
+    dc->vmsd = &vmstate_tmp105;
+}
+
+static TypeInfo tmp105_info = {
+    .name          = "tmp105",
+    .parent        = TYPE_I2C_SLAVE,
+    .instance_size = sizeof(TMP105State),
+    .class_init    = tmp105_class_init,
 };
 
 static void tmp105_register_devices(void)
 {
-    i2c_register_slave(&tmp105_info);
+    type_register_static(&tmp105_info);
 }
 
 device_init(tmp105_register_devices)
diff --git a/hw/tosa.c b/hw/tosa.c
index 0caba79c98..c0d401759e 100644
--- a/hw/tosa.c
+++ b/hw/tosa.c
@@ -133,12 +133,12 @@ static int tosa_ssp_init(SSISlave *dev)
 }
 
 typedef struct {
-    i2c_slave i2c;
+    I2CSlave i2c;
     int len;
     char buf[3];
 } TosaDACState;
 
-static int tosa_dac_send(i2c_slave *i2c, uint8_t data)
+static int tosa_dac_send(I2CSlave *i2c, uint8_t data)
 {
     TosaDACState *s = FROM_I2C_SLAVE(TosaDACState, i2c);
     s->buf[s->len] = data;
@@ -157,7 +157,7 @@ static int tosa_dac_send(i2c_slave *i2c, uint8_t data)
     return 0;
 }
 
-static void tosa_dac_event(i2c_slave *i2c, enum i2c_event event)
+static void tosa_dac_event(I2CSlave *i2c, enum i2c_event event)
 {
     TosaDACState *s = FROM_I2C_SLAVE(TosaDACState, i2c);
     s->len = 0;
@@ -180,13 +180,13 @@ static void tosa_dac_event(i2c_slave *i2c, enum i2c_event event)
     }
 }
 
-static int tosa_dac_recv(i2c_slave *s)
+static int tosa_dac_recv(I2CSlave *s)
 {
     printf("%s: recv not supported!!!\n", __FUNCTION__);
     return -1;
 }
 
-static int tosa_dac_init(i2c_slave *i2c)
+static int tosa_dac_init(I2CSlave *i2c)
 {
     /* Nothing to do.  */
     return 0;
@@ -259,26 +259,42 @@ static void tosapda_machine_init(void)
 
 machine_init(tosapda_machine_init);
 
-static I2CSlaveInfo tosa_dac_info = {
-    .qdev.name = "tosa_dac",
-    .qdev.size = sizeof(TosaDACState),
-    .init = tosa_dac_init,
-    .event = tosa_dac_event,
-    .recv = tosa_dac_recv,
-    .send = tosa_dac_send
+static void tosa_dac_class_init(ObjectClass *klass, void *data)
+{
+    I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
+
+    k->init = tosa_dac_init;
+    k->event = tosa_dac_event;
+    k->recv = tosa_dac_recv;
+    k->send = tosa_dac_send;
+}
+
+static TypeInfo tosa_dac_info = {
+    .name          = "tosa_dac",
+    .parent        = TYPE_I2C_SLAVE,
+    .instance_size = sizeof(TosaDACState),
+    .class_init    = tosa_dac_class_init,
 };
 
-static SSISlaveInfo tosa_ssp_info = {
-    .qdev.name = "tosa-ssp",
-    .qdev.size = sizeof(SSISlave),
-    .init = tosa_ssp_init,
-    .transfer = tosa_ssp_tansfer
+static void tosa_ssp_class_init(ObjectClass *klass, void *data)
+{
+    SSISlaveClass *k = SSI_SLAVE_CLASS(klass);
+
+    k->init = tosa_ssp_init;
+    k->transfer = tosa_ssp_tansfer;
+}
+
+static TypeInfo tosa_ssp_info = {
+    .name          = "tosa-ssp",
+    .parent        = TYPE_SSI_SLAVE,
+    .instance_size = sizeof(SSISlave),
+    .class_init    = tosa_ssp_class_init,
 };
 
 static void tosa_register_devices(void)
 {
-    i2c_register_slave(&tosa_dac_info);
-    ssi_register_slave(&tosa_ssp_info);
+    type_register_static(&tosa_dac_info);
+    type_register_static(&tosa_ssp_info);
 }
 
 device_init(tosa_register_devices)
diff --git a/hw/tusb6010.c b/hw/tusb6010.c
index 276300a302..0ade670906 100644
--- a/hw/tusb6010.c
+++ b/hw/tusb6010.c
@@ -789,16 +789,25 @@ static int tusb6010_init(SysBusDevice *dev)
     return 0;
 }
 
-static SysBusDeviceInfo tusb6010_info = {
-    .init = tusb6010_init,
-    .qdev.name = "tusb6010",
-    .qdev.size = sizeof(TUSBState),
-    .qdev.reset = tusb6010_reset,
+static void tusb6010_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = tusb6010_init;
+    dc->reset = tusb6010_reset;
+}
+
+static TypeInfo tusb6010_info = {
+    .name          = "tusb6010",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(TUSBState),
+    .class_init    = tusb6010_class_init,
 };
 
 static void tusb6010_register_device(void)
 {
-    sysbus_register_withprop(&tusb6010_info);
+    type_register_static(&tusb6010_info);
 }
 
 device_init(tusb6010_register_device)
diff --git a/hw/twl92230.c b/hw/twl92230.c
index a75448f06a..03fdccc8ce 100644
--- a/hw/twl92230.c
+++ b/hw/twl92230.c
@@ -27,7 +27,7 @@
 #define VERBOSE 1
 
 typedef struct {
-    i2c_slave i2c;
+    I2CSlave i2c;
 
     int firstbyte;
     uint8_t reg;
@@ -126,7 +126,7 @@ static void menelaus_rtc_hz(void *opaque)
     menelaus_update(s);
 }
 
-static void menelaus_reset(i2c_slave *i2c)
+static void menelaus_reset(I2CSlave *i2c)
 {
     MenelausState *s = (MenelausState *) i2c;
     s->reg = 0x00;
@@ -709,7 +709,7 @@ static void menelaus_write(void *opaque, uint8_t addr, uint8_t value)
     }
 }
 
-static void menelaus_event(i2c_slave *i2c, enum i2c_event event)
+static void menelaus_event(I2CSlave *i2c, enum i2c_event event)
 {
     MenelausState *s = (MenelausState *) i2c;
 
@@ -717,7 +717,7 @@ static void menelaus_event(i2c_slave *i2c, enum i2c_event event)
         s->firstbyte = 1;
 }
 
-static int menelaus_tx(i2c_slave *i2c, uint8_t data)
+static int menelaus_tx(I2CSlave *i2c, uint8_t data)
 {
     MenelausState *s = (MenelausState *) i2c;
     /* Interpret register address byte */
@@ -730,7 +730,7 @@ static int menelaus_tx(i2c_slave *i2c, uint8_t data)
     return 0;
 }
 
-static int menelaus_rx(i2c_slave *i2c)
+static int menelaus_rx(I2CSlave *i2c)
 {
     MenelausState *s = (MenelausState *) i2c;
 
@@ -842,7 +842,7 @@ static const VMStateDescription vmstate_menelaus = {
     }
 };
 
-static int twl92230_init(i2c_slave *i2c)
+static int twl92230_init(I2CSlave *i2c)
 {
     MenelausState *s = FROM_I2C_SLAVE(MenelausState, i2c);
 
@@ -857,19 +857,28 @@ static int twl92230_init(i2c_slave *i2c)
     return 0;
 }
 
-static I2CSlaveInfo twl92230_info = {
-    .qdev.name ="twl92230",
-    .qdev.size = sizeof(MenelausState),
-    .qdev.vmsd = &vmstate_menelaus,
-    .init = twl92230_init,
-    .event = menelaus_event,
-    .recv = menelaus_rx,
-    .send = menelaus_tx
+static void twl92230_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    I2CSlaveClass *sc = I2C_SLAVE_CLASS(klass);
+
+    sc->init = twl92230_init;
+    sc->event = menelaus_event;
+    sc->recv = menelaus_rx;
+    sc->send = menelaus_tx;
+    dc->vmsd = &vmstate_menelaus;
+}
+
+static TypeInfo twl92230_info = {
+    .name          = "twl92230",
+    .parent        = TYPE_I2C_SLAVE,
+    .instance_size = sizeof(MenelausState),
+    .class_init    = twl92230_class_init,
 };
 
 static void twl92230_register_devices(void)
 {
-    i2c_register_slave(&twl92230_info);
+    type_register_static(&twl92230_info);
 }
 
 device_init(twl92230_register_devices)
diff --git a/hw/unin_pci.c b/hw/unin_pci.c
index 14d99147f3..17d86aac68 100644
--- a/hw/unin_pci.c
+++ b/hw/unin_pci.c
@@ -39,7 +39,6 @@
 static const int unin_irq_line[] = { 0x1b, 0x1c, 0x1d, 0x1e };
 
 typedef struct UNINState {
-    SysBusDevice busdev;
     PCIHostState host_state;
     MemoryRegion pci_mmio;
     MemoryRegion pci_hole;
@@ -64,10 +63,6 @@ static void pci_unin_set_irq(void *opaque, int irq_num, int level)
     qemu_set_irq(pic[unin_irq_line[irq_num]], level);
 }
 
-static void pci_unin_reset(void *opaque)
-{
-}
-
 static uint32_t unin_get_config_reg(uint32_t reg, uint32_t addr)
 {
     uint32_t retval;
@@ -134,11 +129,13 @@ static const MemoryRegionOps unin_data_ops = {
 
 static int pci_unin_main_init_device(SysBusDevice *dev)
 {
+    PCIHostState *h;
     UNINState *s;
 
     /* Use values found on a real PowerMac */
     /* Uninorth main bus */
-    s = FROM_SYSBUS(UNINState, dev);
+    h = FROM_SYSBUS(PCIHostState, dev);
+    s = DO_UPCAST(UNINState, host_state, h);
 
     memory_region_init_io(&s->host_state.conf_mem, &pci_host_conf_le_ops,
                           &s->host_state, "pci-conf-idx", 0x1000);
@@ -147,17 +144,18 @@ static int pci_unin_main_init_device(SysBusDevice *dev)
     sysbus_init_mmio(dev, &s->host_state.conf_mem);
     sysbus_init_mmio(dev, &s->host_state.data_mem);
 
-    qemu_register_reset(pci_unin_reset, &s->host_state);
     return 0;
 }
 
 
 static int pci_u3_agp_init_device(SysBusDevice *dev)
 {
+    PCIHostState *h;
     UNINState *s;
 
     /* Uninorth U3 AGP bus */
-    s = FROM_SYSBUS(UNINState, dev);
+    h = FROM_SYSBUS(PCIHostState, dev);
+    s = DO_UPCAST(UNINState, host_state, h);
 
     memory_region_init_io(&s->host_state.conf_mem, &pci_host_conf_le_ops,
                           &s->host_state, "pci-conf-idx", 0x1000);
@@ -166,17 +164,17 @@ static int pci_u3_agp_init_device(SysBusDevice *dev)
     sysbus_init_mmio(dev, &s->host_state.conf_mem);
     sysbus_init_mmio(dev, &s->host_state.data_mem);
 
-    qemu_register_reset(pci_unin_reset, &s->host_state);
-
     return 0;
 }
 
 static int pci_unin_agp_init_device(SysBusDevice *dev)
 {
+    PCIHostState *h;
     UNINState *s;
 
     /* Uninorth AGP bus */
-    s = FROM_SYSBUS(UNINState, dev);
+    h = FROM_SYSBUS(PCIHostState, dev);
+    s = DO_UPCAST(UNINState, host_state, h);
 
     memory_region_init_io(&s->host_state.conf_mem, &pci_host_conf_le_ops,
                           &s->host_state, "pci-conf-idx", 0x1000);
@@ -189,10 +187,12 @@ static int pci_unin_agp_init_device(SysBusDevice *dev)
 
 static int pci_unin_internal_init_device(SysBusDevice *dev)
 {
+    PCIHostState *h;
     UNINState *s;
 
     /* Uninorth internal bus */
-    s = FROM_SYSBUS(UNINState, dev);
+    h = FROM_SYSBUS(PCIHostState, dev);
+    s = DO_UPCAST(UNINState, host_state, h);
 
     memory_region_init_io(&s->host_state.conf_mem, &pci_host_conf_le_ops,
                           &s->host_state, "pci-conf-idx", 0x1000);
@@ -209,21 +209,23 @@ PCIBus *pci_pmac_init(qemu_irq *pic,
 {
     DeviceState *dev;
     SysBusDevice *s;
+    PCIHostState *h;
     UNINState *d;
 
     /* Use values found on a real PowerMac */
     /* Uninorth main bus */
-    dev = qdev_create(NULL, "uni-north");
+    dev = qdev_create(NULL, "uni-north-pci-pcihost");
     qdev_init_nofail(dev);
     s = sysbus_from_qdev(dev);
-    d = FROM_SYSBUS(UNINState, s);
+    h = FROM_SYSBUS(PCIHostState, s);
+    d = DO_UPCAST(UNINState, host_state, h);
     memory_region_init(&d->pci_mmio, "pci-mmio", 0x100000000ULL);
     memory_region_init_alias(&d->pci_hole, "pci-hole", &d->pci_mmio,
                              0x80000000ULL, 0x70000000ULL);
     memory_region_add_subregion(address_space_mem, 0x80000000ULL,
                                 &d->pci_hole);
 
-    d->host_state.bus = pci_register_bus(&d->busdev.qdev, "pci",
+    d->host_state.bus = pci_register_bus(dev, "pci",
                                          pci_unin_set_irq, pci_unin_map_irq,
                                          pic,
                                          &d->pci_mmio,
@@ -245,7 +247,7 @@ PCIBus *pci_pmac_init(qemu_irq *pic,
 
     /* Uninorth AGP bus */
     pci_create_simple(d->host_state.bus, PCI_DEVFN(11, 0), "uni-north-agp");
-    dev = qdev_create(NULL, "uni-north-agp");
+    dev = qdev_create(NULL, "uni-north-agp-pcihost");
     qdev_init_nofail(dev);
     s = sysbus_from_qdev(dev);
     sysbus_mmio_map(s, 0, 0xf0800000);
@@ -254,8 +256,9 @@ PCIBus *pci_pmac_init(qemu_irq *pic,
     /* Uninorth internal bus */
 #if 0
     /* XXX: not needed for now */
-    pci_create_simple(d->host_state.bus, PCI_DEVFN(14, 0), "uni-north-pci");
-    dev = qdev_create(NULL, "uni-north-pci");
+    pci_create_simple(d->host_state.bus, PCI_DEVFN(14, 0),
+                      "uni-north-internal-pci");
+    dev = qdev_create(NULL, "uni-north-internal-pci-pcihost");
     qdev_init_nofail(dev);
     s = sysbus_from_qdev(dev);
     sysbus_mmio_map(s, 0, 0xf4800000);
@@ -271,14 +274,16 @@ PCIBus *pci_pmac_u3_init(qemu_irq *pic,
 {
     DeviceState *dev;
     SysBusDevice *s;
+    PCIHostState *h;
     UNINState *d;
 
     /* Uninorth AGP bus */
 
-    dev = qdev_create(NULL, "u3-agp");
+    dev = qdev_create(NULL, "u3-agp-pcihost");
     qdev_init_nofail(dev);
     s = sysbus_from_qdev(dev);
-    d = FROM_SYSBUS(UNINState, s);
+    h = FROM_SYSBUS(PCIHostState, s);
+    d = DO_UPCAST(UNINState, host_state, h);
 
     memory_region_init(&d->pci_mmio, "pci-mmio", 0x100000000ULL);
     memory_region_init_alias(&d->pci_hole, "pci-hole", &d->pci_mmio,
@@ -286,7 +291,7 @@ PCIBus *pci_pmac_u3_init(qemu_irq *pic,
     memory_region_add_subregion(address_space_mem, 0x80000000ULL,
                                 &d->pci_hole);
 
-    d->host_state.bus = pci_register_bus(&d->busdev.qdev, "pci",
+    d->host_state.bus = pci_register_bus(dev, "pci",
                                          pci_unin_set_irq, pci_unin_map_irq,
                                          pic,
                                          &d->pci_mmio,
@@ -334,60 +339,145 @@ static int unin_internal_pci_host_init(PCIDevice *d)
     return 0;
 }
 
-static PCIDeviceInfo unin_main_pci_host_info = {
-    .qdev.name = "uni-north",
-    .qdev.size = sizeof(PCIDevice),
-    .init      = unin_main_pci_host_init,
-    .vendor_id = PCI_VENDOR_ID_APPLE,
-    .device_id = PCI_DEVICE_ID_APPLE_UNI_N_PCI,
-    .revision  = 0x00,
-    .class_id  = PCI_CLASS_BRIDGE_HOST,
+static void unin_main_pci_host_class_init(ObjectClass *klass, void *data)
+{
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->init      = unin_main_pci_host_init;
+    k->vendor_id = PCI_VENDOR_ID_APPLE;
+    k->device_id = PCI_DEVICE_ID_APPLE_UNI_N_PCI;
+    k->revision  = 0x00;
+    k->class_id  = PCI_CLASS_BRIDGE_HOST;
+}
+
+static TypeInfo unin_main_pci_host_info = {
+    .name = "uni-north-pci",
+    .parent = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(PCIDevice),
+    .class_init = unin_main_pci_host_class_init,
+};
+
+static void u3_agp_pci_host_class_init(ObjectClass *klass, void *data)
+{
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->init      = u3_agp_pci_host_init;
+    k->vendor_id = PCI_VENDOR_ID_APPLE;
+    k->device_id = PCI_DEVICE_ID_APPLE_U3_AGP;
+    k->revision  = 0x00;
+    k->class_id  = PCI_CLASS_BRIDGE_HOST;
+}
+
+static TypeInfo u3_agp_pci_host_info = {
+    .name = "u3-agp",
+    .parent = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(PCIDevice),
+    .class_init = u3_agp_pci_host_class_init,
+};
+
+static void unin_agp_pci_host_class_init(ObjectClass *klass, void *data)
+{
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->init      = unin_agp_pci_host_init;
+    k->vendor_id = PCI_VENDOR_ID_APPLE;
+    k->device_id = PCI_DEVICE_ID_APPLE_UNI_N_AGP;
+    k->revision  = 0x00;
+    k->class_id  = PCI_CLASS_BRIDGE_HOST;
+}
+
+static TypeInfo unin_agp_pci_host_info = {
+    .name = "uni-north-agp",
+    .parent = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(PCIDevice),
+    .class_init = unin_agp_pci_host_class_init,
+};
+
+static void unin_internal_pci_host_class_init(ObjectClass *klass, void *data)
+{
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->init      = unin_internal_pci_host_init;
+    k->vendor_id = PCI_VENDOR_ID_APPLE;
+    k->device_id = PCI_DEVICE_ID_APPLE_UNI_N_I_PCI;
+    k->revision  = 0x00;
+    k->class_id  = PCI_CLASS_BRIDGE_HOST;
+}
+
+static TypeInfo unin_internal_pci_host_info = {
+    .name = "uni-north-internal-pci",
+    .parent = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(PCIDevice),
+    .class_init = unin_internal_pci_host_class_init,
 };
 
-static PCIDeviceInfo u3_agp_pci_host_info = {
-    .qdev.name = "u3-agp",
-    .qdev.size = sizeof(PCIDevice),
-    .init      = u3_agp_pci_host_init,
-    .vendor_id = PCI_VENDOR_ID_APPLE,
-    .device_id = PCI_DEVICE_ID_APPLE_U3_AGP,
-    .revision  = 0x00,
-    .class_id  = PCI_CLASS_BRIDGE_HOST,
+static void pci_unin_main_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass);
+
+    sbc->init = pci_unin_main_init_device;
+}
+
+static TypeInfo pci_unin_main_info = {
+    .name          = "uni-north-pci-pcihost",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(UNINState),
+    .class_init    = pci_unin_main_class_init,
+};
+
+static void pci_u3_agp_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass);
+
+    sbc->init = pci_u3_agp_init_device;
+}
+
+static TypeInfo pci_u3_agp_info = {
+    .name          = "u3-agp-pcihost",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(UNINState),
+    .class_init    = pci_u3_agp_class_init,
 };
 
-static PCIDeviceInfo unin_agp_pci_host_info = {
-    .qdev.name = "uni-north-agp",
-    .qdev.size = sizeof(PCIDevice),
-    .init      = unin_agp_pci_host_init,
-    .vendor_id = PCI_VENDOR_ID_APPLE,
-    .device_id = PCI_DEVICE_ID_APPLE_UNI_N_AGP,
-    .revision  = 0x00,
-    .class_id  = PCI_CLASS_BRIDGE_HOST,
+static void pci_unin_agp_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass);
+
+    sbc->init = pci_unin_agp_init_device;
+}
+
+static TypeInfo pci_unin_agp_info = {
+    .name          = "uni-north-agp-pcihost",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(UNINState),
+    .class_init    = pci_unin_agp_class_init,
 };
 
-static PCIDeviceInfo unin_internal_pci_host_info = {
-    .qdev.name = "uni-north-pci",
-    .qdev.size = sizeof(PCIDevice),
-    .init      = unin_internal_pci_host_init,
-    .vendor_id = PCI_VENDOR_ID_APPLE,
-    .device_id = PCI_DEVICE_ID_APPLE_UNI_N_I_PCI,
-    .revision  = 0x00,
-    .class_id  = PCI_CLASS_BRIDGE_HOST,
+static void pci_unin_internal_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass);
+
+    sbc->init = pci_unin_internal_init_device;
+}
+
+static TypeInfo pci_unin_internal_info = {
+    .name          = "uni-north-internal-pci-pcihost",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(UNINState),
+    .class_init    = pci_unin_internal_class_init,
 };
 
 static void unin_register_devices(void)
 {
-    sysbus_register_dev("uni-north", sizeof(UNINState),
-                        pci_unin_main_init_device);
-    pci_qdev_register(&unin_main_pci_host_info);
-    sysbus_register_dev("u3-agp", sizeof(UNINState),
-                        pci_u3_agp_init_device);
-    pci_qdev_register(&u3_agp_pci_host_info);
-    sysbus_register_dev("uni-north-agp", sizeof(UNINState),
-                        pci_unin_agp_init_device);
-    pci_qdev_register(&unin_agp_pci_host_info);
-    sysbus_register_dev("uni-north-pci", sizeof(UNINState),
-                        pci_unin_internal_init_device);
-    pci_qdev_register(&unin_internal_pci_host_info);
+    type_register_static(&unin_main_pci_host_info);
+    type_register_static(&u3_agp_pci_host_info);
+    type_register_static(&unin_agp_pci_host_info);
+    type_register_static(&unin_internal_pci_host_info);
+
+    type_register_static(&pci_unin_main_info);
+    type_register_static(&pci_u3_agp_info);
+    type_register_static(&pci_unin_agp_info);
+    type_register_static(&pci_unin_internal_info);
 }
 
 device_init(unin_register_devices)
diff --git a/hw/usb-audio.c b/hw/usb-audio.c
new file mode 100644
index 0000000000..cd589b718a
--- /dev/null
+++ b/hw/usb-audio.c
@@ -0,0 +1,715 @@
+/*
+ * QEMU USB audio device
+ *
+ * written by:
+ *  H. Peter Anvin <hpa@linux.intel.com>
+ *  Gerd Hoffmann <kraxel@redhat.com>
+ *
+ * lousely based on usb net device code which is:
+ *
+ * Copyright (c) 2006 Thomas Sailer
+ * Copyright (c) 2008 Andrzej Zaborowski
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "qemu-common.h"
+#include "usb.h"
+#include "usb-desc.h"
+#include "hw.h"
+#include "audiodev.h"
+#include "audio/audio.h"
+
+#define USBAUDIO_VENDOR_NUM     0x46f4 /* CRC16() of "QEMU" */
+#define USBAUDIO_PRODUCT_NUM    0x0002
+
+#define DEV_CONFIG_VALUE        1 /* The one and only */
+
+/* Descriptor subtypes for AC interfaces */
+#define DST_AC_HEADER           1
+#define DST_AC_INPUT_TERMINAL   2
+#define DST_AC_OUTPUT_TERMINAL  3
+#define DST_AC_FEATURE_UNIT     6
+/* Descriptor subtypes for AS interfaces */
+#define DST_AS_GENERAL          1
+#define DST_AS_FORMAT_TYPE      2
+/* Descriptor subtypes for endpoints */
+#define DST_EP_GENERAL          1
+
+enum usb_audio_strings {
+    STRING_NULL,
+    STRING_MANUFACTURER,
+    STRING_PRODUCT,
+    STRING_SERIALNUMBER,
+    STRING_CONFIG,
+    STRING_USBAUDIO_CONTROL,
+    STRING_INPUT_TERMINAL,
+    STRING_FEATURE_UNIT,
+    STRING_OUTPUT_TERMINAL,
+    STRING_NULL_STREAM,
+    STRING_REAL_STREAM,
+};
+
+static const USBDescStrings usb_audio_stringtable = {
+    [STRING_MANUFACTURER]       = "QEMU",
+    [STRING_PRODUCT]            = "QEMU USB Audio",
+    [STRING_SERIALNUMBER]       = "1",
+    [STRING_CONFIG]             = "Audio Configuration",
+    [STRING_USBAUDIO_CONTROL]   = "Audio Device",
+    [STRING_INPUT_TERMINAL]     = "Audio Output Pipe",
+    [STRING_FEATURE_UNIT]       = "Audio Output Volume Control",
+    [STRING_OUTPUT_TERMINAL]    = "Audio Output Terminal",
+    [STRING_NULL_STREAM]        = "Audio Output - Disabled",
+    [STRING_REAL_STREAM]        = "Audio Output - 48 kHz Stereo",
+};
+
+#define U16(x) ((x) & 0xff), (((x) >> 8) & 0xff)
+#define U24(x) U16(x), (((x) >> 16) & 0xff)
+#define U32(x) U24(x), (((x) >> 24) & 0xff)
+
+/*
+ * A Basic Audio Device uses these specific values
+ */
+#define USBAUDIO_PACKET_SIZE     192
+#define USBAUDIO_SAMPLE_RATE     48000
+#define USBAUDIO_PACKET_INTERVAL 1
+
+static const USBDescIface desc_iface[] = {
+    {
+        .bInterfaceNumber              = 0,
+        .bNumEndpoints                 = 0,
+        .bInterfaceClass               = USB_CLASS_AUDIO,
+        .bInterfaceSubClass            = USB_SUBCLASS_AUDIO_CONTROL,
+        .bInterfaceProtocol            = 0x04,
+        .iInterface                    = STRING_USBAUDIO_CONTROL,
+        .ndesc                         = 4,
+        .descs = (USBDescOther[]) {
+            {
+                /* Headphone Class-Specific AC Interface Header Descriptor */
+                .data = (uint8_t[]) {
+                    0x09,                       /*  u8  bLength */
+                    USB_DT_CS_INTERFACE,        /*  u8  bDescriptorType */
+                    DST_AC_HEADER,              /*  u8  bDescriptorSubtype */
+                    U16(0x0100),                /* u16  bcdADC */
+                    U16(0x2b),                  /* u16  wTotalLength */
+                    0x01,                       /*  u8  bInCollection */
+                    0x01,                       /*  u8  baInterfaceNr */
+                }
+            },{
+                /* Generic Stereo Input Terminal ID1 Descriptor */
+                .data = (uint8_t[]) {
+                    0x0c,                       /*  u8  bLength */
+                    USB_DT_CS_INTERFACE,        /*  u8  bDescriptorType */
+                    DST_AC_INPUT_TERMINAL,      /*  u8  bDescriptorSubtype */
+                    0x01,                       /*  u8  bTerminalID */
+                    U16(0x0101),                /* u16  wTerminalType */
+                    0x00,                       /*  u8  bAssocTerminal */
+                    0x02,                       /* u16  bNrChannels */
+                    U16(0x0003),                /* u16  wChannelConfig */
+                    0x00,                       /*  u8  iChannelNames */
+                    STRING_INPUT_TERMINAL,      /*  u8  iTerminal */
+                }
+            },{
+                /* Generic Stereo Feature Unit ID2 Descriptor */
+                .data = (uint8_t[]) {
+                    0x0d,                       /*  u8  bLength */
+                    USB_DT_CS_INTERFACE,        /*  u8  bDescriptorType */
+                    DST_AC_FEATURE_UNIT,        /*  u8  bDescriptorSubtype */
+                    0x02,                       /*  u8  bUnitID */
+                    0x01,                       /*  u8  bSourceID */
+                    0x02,                       /*  u8  bControlSize */
+                    U16(0x0001),                /* u16  bmaControls(0) */
+                    U16(0x0002),                /* u16  bmaControls(1) */
+                    U16(0x0002),                /* u16  bmaControls(2) */
+                    STRING_FEATURE_UNIT,        /*  u8  iFeature */
+                }
+            },{
+                /* Headphone Ouptut Terminal ID3 Descriptor */
+                .data = (uint8_t[]) {
+                    0x09,                       /*  u8  bLength */
+                    USB_DT_CS_INTERFACE,        /*  u8  bDescriptorType */
+                    DST_AC_OUTPUT_TERMINAL,     /*  u8  bDescriptorSubtype */
+                    0x03,                       /*  u8  bUnitID */
+                    U16(0x0301),                /* u16  wTerminalType (SPK) */
+                    0x00,                       /*  u8  bAssocTerminal */
+                    0x02,                       /*  u8  bSourceID */
+                    STRING_OUTPUT_TERMINAL,     /*  u8  iTerminal */
+                }
+            }
+        },
+    },{
+        .bInterfaceNumber              = 1,
+        .bAlternateSetting             = 0,
+        .bNumEndpoints                 = 0,
+        .bInterfaceClass               = USB_CLASS_AUDIO,
+        .bInterfaceSubClass            = USB_SUBCLASS_AUDIO_STREAMING,
+        .iInterface                    = STRING_NULL_STREAM,
+    },{
+        .bInterfaceNumber              = 1,
+        .bAlternateSetting             = 1,
+        .bNumEndpoints                 = 1,
+        .bInterfaceClass               = USB_CLASS_AUDIO,
+        .bInterfaceSubClass            = USB_SUBCLASS_AUDIO_STREAMING,
+        .iInterface                    = STRING_REAL_STREAM,
+        .ndesc                         = 2,
+        .descs = (USBDescOther[]) {
+            {
+                /* Headphone Class-specific AS General Interface Descriptor */
+                .data = (uint8_t[]) {
+                    0x07,                       /*  u8  bLength */
+                    USB_DT_CS_INTERFACE,        /*  u8  bDescriptorType */
+                    DST_AS_GENERAL,             /*  u8  bDescriptorSubtype */
+                    0x01,                       /*  u8  bTerminalLink */
+                    0x00,                       /*  u8  bDelay */
+                    0x01, 0x00,                 /* u16  wFormatTag */
+                }
+            },{
+                /* Headphone Type I Format Type Descriptor */
+                .data = (uint8_t[]) {
+                    0x0b,                       /*  u8  bLength */
+                    USB_DT_CS_INTERFACE,        /*  u8  bDescriptorType */
+                    DST_AS_FORMAT_TYPE,         /*  u8  bDescriptorSubtype */
+                    0x01,                       /*  u8  bFormatType */
+                    0x02,                       /*  u8  bNrChannels */
+                    0x02,                       /*  u8  bSubFrameSize */
+                    0x10,                       /*  u8  bBitResolution */
+                    0x01,                       /*  u8  bSamFreqType */
+                    U24(USBAUDIO_SAMPLE_RATE),  /* u24  tSamFreq */
+                }
+            }
+        },
+        .eps = (USBDescEndpoint[]) {
+            {
+                .bEndpointAddress      = USB_DIR_OUT | 0x01,
+                .bmAttributes          = 0x0d,
+                .wMaxPacketSize        = USBAUDIO_PACKET_SIZE,
+                .bInterval             = 1,
+                .is_audio              = 1,
+                /* Stereo Headphone Class-specific
+                   AS Audio Data Endpoint Descriptor */
+                .extra = (uint8_t[]) {
+                    0x07,                       /*  u8  bLength */
+                    USB_DT_CS_ENDPOINT,         /*  u8  bDescriptorType */
+                    DST_EP_GENERAL,             /*  u8  bDescriptorSubtype */
+                    0x00,                       /*  u8  bmAttributes */
+                    0x00,                       /*  u8  bLockDelayUnits */
+                    U16(0x0000),                /* u16  wLockDelay */
+                },
+            },
+        }
+    }
+};
+
+static const USBDescDevice desc_device = {
+    .bcdUSB                        = 0x0200,
+    .bMaxPacketSize0               = 64,
+    .bNumConfigurations            = 1,
+    .confs = (USBDescConfig[]) {
+        {
+            .bNumInterfaces        = 2,
+            .bConfigurationValue   = DEV_CONFIG_VALUE,
+            .iConfiguration        = STRING_CONFIG,
+            .bmAttributes          = 0xc0,
+            .bMaxPower             = 0x32,
+            .nif = ARRAY_SIZE(desc_iface),
+            .ifs = desc_iface,
+        },
+    },
+};
+
+static const USBDesc desc_audio = {
+    .id = {
+        .idVendor          = USBAUDIO_VENDOR_NUM,
+        .idProduct         = USBAUDIO_PRODUCT_NUM,
+        .bcdDevice         = 0,
+        .iManufacturer     = STRING_MANUFACTURER,
+        .iProduct          = STRING_PRODUCT,
+        .iSerialNumber     = STRING_SERIALNUMBER,
+    },
+    .full = &desc_device,
+    .str  = usb_audio_stringtable,
+};
+
+/*
+ * A USB audio device supports an arbitrary number of alternate
+ * interface settings for each interface.  Each corresponds to a block
+ * diagram of parameterized blocks.  This can thus refer to things like
+ * number of channels, data rates, or in fact completely different
+ * block diagrams.  Alternative setting 0 is always the null block diagram,
+ * which is used by a disabled device.
+ */
+enum usb_audio_altset {
+    ALTSET_OFF  = 0x00,         /* No endpoint */
+    ALTSET_ON   = 0x01,         /* Single endpoint */
+};
+
+/*
+ * Class-specific control requests
+ */
+#define CR_SET_CUR      0x01
+#define CR_GET_CUR      0x81
+#define CR_SET_MIN      0x02
+#define CR_GET_MIN      0x82
+#define CR_SET_MAX      0x03
+#define CR_GET_MAX      0x83
+#define CR_SET_RES      0x04
+#define CR_GET_RES      0x84
+#define CR_SET_MEM      0x05
+#define CR_GET_MEM      0x85
+#define CR_GET_STAT     0xff
+
+/*
+ * Feature Unit Control Selectors
+ */
+#define MUTE_CONTROL                    0x01
+#define VOLUME_CONTROL                  0x02
+#define BASS_CONTROL                    0x03
+#define MID_CONTROL                     0x04
+#define TREBLE_CONTROL                  0x05
+#define GRAPHIC_EQUALIZER_CONTROL       0x06
+#define AUTOMATIC_GAIN_CONTROL          0x07
+#define DELAY_CONTROL                   0x08
+#define BASS_BOOST_CONTROL              0x09
+#define LOUDNESS_CONTROL                0x0a
+
+/*
+ * buffering
+ */
+
+struct streambuf {
+    uint8_t *data;
+    uint32_t size;
+    uint32_t prod;
+    uint32_t cons;
+};
+
+static void streambuf_init(struct streambuf *buf, uint32_t size)
+{
+    g_free(buf->data);
+    buf->size = size - (size % USBAUDIO_PACKET_SIZE);
+    buf->data = g_malloc(buf->size);
+    buf->prod = 0;
+    buf->cons = 0;
+}
+
+static void streambuf_fini(struct streambuf *buf)
+{
+    g_free(buf->data);
+    buf->data = NULL;
+}
+
+static int streambuf_put(struct streambuf *buf, USBPacket *p)
+{
+    uint32_t free = buf->size - (buf->prod - buf->cons);
+
+    if (!free) {
+        return 0;
+    }
+    assert(free >= USBAUDIO_PACKET_SIZE);
+    usb_packet_copy(p, buf->data + (buf->prod % buf->size),
+                    USBAUDIO_PACKET_SIZE);
+    buf->prod += USBAUDIO_PACKET_SIZE;
+    return USBAUDIO_PACKET_SIZE;
+}
+
+static uint8_t *streambuf_get(struct streambuf *buf)
+{
+    uint32_t used = buf->prod - buf->cons;
+    uint8_t *data;
+
+    if (!used) {
+        return NULL;
+    }
+    assert(used >= USBAUDIO_PACKET_SIZE);
+    data = buf->data + (buf->cons % buf->size);
+    buf->cons += USBAUDIO_PACKET_SIZE;
+    return data;
+}
+
+typedef struct USBAudioState {
+    /* qemu interfaces */
+    USBDevice dev;
+    QEMUSoundCard card;
+
+    /* state */
+    struct {
+        enum usb_audio_altset altset;
+        struct audsettings as;
+        SWVoiceOut *voice;
+        bool mute;
+        uint8_t vol[2];
+        struct streambuf buf;
+    } out;
+
+    /* properties */
+    uint32_t debug;
+    uint32_t buffer;
+} USBAudioState;
+
+static void output_callback(void *opaque, int avail)
+{
+    USBAudioState *s = opaque;
+    uint8_t *data;
+
+    for (;;) {
+        if (avail < USBAUDIO_PACKET_SIZE) {
+            return;
+        }
+        data = streambuf_get(&s->out.buf);
+        if (NULL == data) {
+            return;
+        }
+        AUD_write(s->out.voice, data, USBAUDIO_PACKET_SIZE);
+        avail -= USBAUDIO_PACKET_SIZE;
+    }
+}
+
+static int usb_audio_set_output_altset(USBAudioState *s, int altset)
+{
+    switch (altset) {
+    case ALTSET_OFF:
+        streambuf_init(&s->out.buf, s->buffer);
+        AUD_set_active_out(s->out.voice, false);
+        break;
+    case ALTSET_ON:
+        AUD_set_active_out(s->out.voice, true);
+        break;
+    default:
+        return -1;
+    }
+
+    if (s->debug) {
+        fprintf(stderr, "usb-audio: set interface %d\n", altset);
+    }
+    s->out.altset = altset;
+    return 0;
+}
+
+/*
+ * Note: we arbitrarily map the volume control range onto -inf..+8 dB
+ */
+#define ATTRIB_ID(cs, attrib, idif)     \
+    (((cs) << 24) | ((attrib) << 16) | (idif))
+
+static int usb_audio_get_control(USBAudioState *s, uint8_t attrib,
+                                 uint16_t cscn, uint16_t idif,
+                                 int length, uint8_t *data)
+{
+    uint8_t cs = cscn >> 8;
+    uint8_t cn = cscn - 1;      /* -1 for the non-present master control */
+    uint32_t aid = ATTRIB_ID(cs, attrib, idif);
+    int ret = USB_RET_STALL;
+
+    switch (aid) {
+    case ATTRIB_ID(MUTE_CONTROL, CR_GET_CUR, 0x0200):
+        data[0] = s->out.mute;
+        ret = 1;
+        break;
+    case ATTRIB_ID(VOLUME_CONTROL, CR_GET_CUR, 0x0200):
+        if (cn < 2) {
+            uint16_t vol = (s->out.vol[cn] * 0x8800 + 127) / 255 + 0x8000;
+            data[0] = vol;
+            data[1] = vol >> 8;
+            ret = 2;
+        }
+        break;
+    case ATTRIB_ID(VOLUME_CONTROL, CR_GET_MIN, 0x0200):
+        if (cn < 2) {
+            data[0] = 0x01;
+            data[1] = 0x80;
+            ret = 2;
+        }
+        break;
+    case ATTRIB_ID(VOLUME_CONTROL, CR_GET_MAX, 0x0200):
+        if (cn < 2) {
+            data[0] = 0x00;
+            data[1] = 0x08;
+            ret = 2;
+        }
+        break;
+    case ATTRIB_ID(VOLUME_CONTROL, CR_GET_RES, 0x0200):
+        if (cn < 2) {
+            data[0] = 0x88;
+            data[1] = 0x00;
+            ret = 2;
+        }
+        break;
+    }
+
+    return ret;
+}
+static int usb_audio_set_control(USBAudioState *s, uint8_t attrib,
+                                 uint16_t cscn, uint16_t idif,
+                                 int length, uint8_t *data)
+{
+    uint8_t cs = cscn >> 8;
+    uint8_t cn = cscn - 1;      /* -1 for the non-present master control */
+    uint32_t aid = ATTRIB_ID(cs, attrib, idif);
+    int ret = USB_RET_STALL;
+    bool set_vol = false;
+
+    switch (aid) {
+    case ATTRIB_ID(MUTE_CONTROL, CR_SET_CUR, 0x0200):
+        s->out.mute = data[0] & 1;
+        set_vol = true;
+        ret = 0;
+        break;
+    case ATTRIB_ID(VOLUME_CONTROL, CR_SET_CUR, 0x0200):
+        if (cn < 2) {
+            uint16_t vol = data[0] + (data[1] << 8);
+
+            if (s->debug) {
+                fprintf(stderr, "usb-audio: vol %04x\n", (uint16_t)vol);
+            }
+
+            vol -= 0x8000;
+            vol = (vol * 255 + 0x4400) / 0x8800;
+            if (vol > 255) {
+                vol = 255;
+            }
+
+            s->out.vol[cn] = vol;
+            set_vol = true;
+            ret = 0;
+        }
+        break;
+    }
+
+    if (set_vol) {
+        if (s->debug) {
+            fprintf(stderr, "usb-audio: mute %d, lvol %3d, rvol %3d\n",
+                    s->out.mute, s->out.vol[0], s->out.vol[1]);
+        }
+        AUD_set_volume_out(s->out.voice, s->out.mute,
+                           s->out.vol[0], s->out.vol[1]);
+    }
+
+    return ret;
+}
+
+static int usb_audio_handle_control(USBDevice *dev, USBPacket *p,
+                                    int request, int value, int index,
+                                    int length, uint8_t *data)
+{
+    USBAudioState *s = DO_UPCAST(USBAudioState, dev, dev);
+    int ret = 0;
+
+    if (s->debug) {
+        fprintf(stderr, "usb-audio: control transaction: "
+                "request 0x%04x value 0x%04x index 0x%04x length 0x%04x\n",
+                request, value, index, length);
+    }
+
+    ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
+    if (ret >= 0) {
+        return ret;
+    }
+
+    switch (request) {
+    case ClassInterfaceRequest | CR_GET_CUR:
+    case ClassInterfaceRequest | CR_GET_MIN:
+    case ClassInterfaceRequest | CR_GET_MAX:
+    case ClassInterfaceRequest | CR_GET_RES:
+        ret = usb_audio_get_control(s, request & 0xff, value, index,
+                                    length, data);
+        if (ret < 0) {
+            if (s->debug) {
+                fprintf(stderr, "usb-audio: fail: get control\n");
+            }
+            goto fail;
+        }
+        break;
+
+    case ClassInterfaceOutRequest | CR_SET_CUR:
+    case ClassInterfaceOutRequest | CR_SET_MIN:
+    case ClassInterfaceOutRequest | CR_SET_MAX:
+    case ClassInterfaceOutRequest | CR_SET_RES:
+        ret = usb_audio_set_control(s, request & 0xff, value, index,
+                                    length, data);
+        if (ret < 0) {
+            if (s->debug) {
+                fprintf(stderr, "usb-audio: fail: set control\n");
+            }
+            goto fail;
+        }
+        break;
+
+    default:
+fail:
+        if (s->debug) {
+            fprintf(stderr, "usb-audio: failed control transaction: "
+                    "request 0x%04x value 0x%04x index 0x%04x length 0x%04x\n",
+                    request, value, index, length);
+        }
+        ret = USB_RET_STALL;
+        break;
+    }
+    return ret;
+}
+
+static void usb_audio_set_interface(USBDevice *dev, int iface,
+                                    int old, int value)
+{
+    USBAudioState *s = DO_UPCAST(USBAudioState, dev, dev);
+
+    if (iface == 1) {
+        usb_audio_set_output_altset(s, value);
+    }
+}
+
+static void usb_audio_handle_reset(USBDevice *dev)
+{
+    USBAudioState *s = DO_UPCAST(USBAudioState, dev, dev);
+
+    if (s->debug) {
+        fprintf(stderr, "usb-audio: reset\n");
+    }
+    usb_audio_set_output_altset(s, ALTSET_OFF);
+}
+
+static int usb_audio_handle_dataout(USBAudioState *s, USBPacket *p)
+{
+    int rc;
+
+    if (s->out.altset == ALTSET_OFF) {
+        return USB_RET_STALL;
+    }
+
+    rc = streambuf_put(&s->out.buf, p);
+    if (rc < p->iov.size && s->debug > 1) {
+        fprintf(stderr, "usb-audio: output overrun (%zd bytes)\n",
+                p->iov.size - rc);
+    }
+
+    return 0;
+}
+
+static int usb_audio_handle_data(USBDevice *dev, USBPacket *p)
+{
+    USBAudioState *s = (USBAudioState *) dev;
+    int ret = 0;
+
+    switch (p->pid) {
+    case USB_TOKEN_OUT:
+        switch (p->devep) {
+        case 1:
+            ret = usb_audio_handle_dataout(s, p);
+            break;
+        default:
+            goto fail;
+        }
+        break;
+
+    default:
+fail:
+        ret = USB_RET_STALL;
+        break;
+    }
+    if (ret == USB_RET_STALL && s->debug) {
+        fprintf(stderr, "usb-audio: failed data transaction: "
+                        "pid 0x%x ep 0x%x len 0x%zx\n",
+                        p->pid, p->devep, p->iov.size);
+    }
+    return ret;
+}
+
+static void usb_audio_handle_destroy(USBDevice *dev)
+{
+    USBAudioState *s = DO_UPCAST(USBAudioState, dev, dev);
+
+    if (s->debug) {
+        fprintf(stderr, "usb-audio: destroy\n");
+    }
+
+    usb_audio_set_output_altset(s, ALTSET_OFF);
+    AUD_close_out(&s->card, s->out.voice);
+    AUD_remove_card(&s->card);
+
+    streambuf_fini(&s->out.buf);
+}
+
+static int usb_audio_initfn(USBDevice *dev)
+{
+    USBAudioState *s = DO_UPCAST(USBAudioState, dev, dev);
+
+    usb_desc_init(dev);
+    s->dev.opaque = s;
+    AUD_register_card("usb-audio", &s->card);
+
+    s->out.altset        = ALTSET_OFF;
+    s->out.mute          = false;
+    s->out.vol[0]        = 240; /* 0 dB */
+    s->out.vol[1]        = 240; /* 0 dB */
+    s->out.as.freq       = USBAUDIO_SAMPLE_RATE;
+    s->out.as.nchannels  = 2;
+    s->out.as.fmt        = AUD_FMT_S16;
+    s->out.as.endianness = 0;
+    streambuf_init(&s->out.buf, s->buffer);
+
+    s->out.voice = AUD_open_out(&s->card, s->out.voice, "usb-audio",
+                                s, output_callback, &s->out.as);
+    AUD_set_volume_out(s->out.voice, s->out.mute, s->out.vol[0], s->out.vol[1]);
+    AUD_set_active_out(s->out.voice, 0);
+    return 0;
+}
+
+static const VMStateDescription vmstate_usb_audio = {
+    .name = "usb-audio",
+    .unmigratable = 1,
+};
+
+static Property usb_audio_properties[] = {
+    DEFINE_PROP_UINT32("debug", USBAudioState, debug, 0),
+    DEFINE_PROP_UINT32("buffer", USBAudioState, buffer,
+                       8 * USBAUDIO_PACKET_SIZE),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void usb_audio_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    USBDeviceClass *k = USB_DEVICE_CLASS(klass);
+
+    dc->vmsd          = &vmstate_usb_audio;
+    dc->props         = usb_audio_properties;
+    k->product_desc   = "QEMU USB Audio Interface";
+    k->usb_desc       = &desc_audio;
+    k->init           = usb_audio_initfn;
+    k->handle_packet  = usb_generic_handle_packet;
+    k->handle_reset   = usb_audio_handle_reset;
+    k->handle_control = usb_audio_handle_control;
+    k->handle_data    = usb_audio_handle_data;
+    k->handle_destroy = usb_audio_handle_destroy;
+    k->set_interface  = usb_audio_set_interface;
+}
+
+static TypeInfo usb_audio_info = {
+    .name          = "usb-audio",
+    .parent        = TYPE_USB_DEVICE,
+    .instance_size = sizeof(USBAudioState),
+    .class_init    = usb_audio_class_init,
+};
+
+static void usb_audio_register_devices(void)
+{
+    type_register_static(&usb_audio_info);
+    usb_legacy_register("usb-audio", "audio", NULL);
+}
+
+device_init(usb_audio_register_devices)
diff --git a/hw/usb-bt.c b/hw/usb-bt.c
index f30eec1ea2..90c3b0e0eb 100644
--- a/hw/usb-bt.c
+++ b/hw/usb-bt.c
@@ -28,7 +28,6 @@ struct USBBtState {
     USBDevice dev;
     struct HCIInfo *hci;
 
-    int altsetting;
     int config;
 
 #define CFIFO_LEN_MASK	255
@@ -362,7 +361,6 @@ static void usb_bt_handle_reset(USBDevice *dev)
     s->outcmd.len = 0;
     s->outacl.len = 0;
     s->outsco.len = 0;
-    s->altsetting = 0;
 }
 
 static int usb_bt_handle_control(USBDevice *dev, USBPacket *p,
@@ -402,26 +400,6 @@ static int usb_bt_handle_control(USBDevice *dev, USBPacket *p,
     case EndpointOutRequest | USB_REQ_SET_FEATURE:
         goto fail;
         break;
-    case InterfaceRequest | USB_REQ_GET_INTERFACE:
-        if (value != 0 || (index & ~1) || length != 1)
-            goto fail;
-        if (index == 1)
-            data[0] = s->altsetting;
-        else
-            data[0] = 0;
-        ret = 1;
-        break;
-    case InterfaceOutRequest | USB_REQ_SET_INTERFACE:
-        if ((index & ~1) || length != 0 ||
-                        (index == 1 && (value < 0 || value > 4)) ||
-                        (index == 0 && value != 0)) {
-            printf("%s: Wrong SET_INTERFACE request (%i, %i)\n",
-                            __FUNCTION__, index, value);
-            goto fail;
-        }
-        s->altsetting = value;
-        ret = 0;
-        break;
     case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_DEVICE) << 8):
         if (s->config)
             usb_bt_fifo_out_enqueue(s, &s->outcmd, s->hci->cmd_send,
@@ -549,22 +527,31 @@ static const VMStateDescription vmstate_usb_bt = {
     .unmigratable = 1,
 };
 
-static struct USBDeviceInfo bt_info = {
-    .product_desc   = "QEMU BT dongle",
-    .qdev.name      = "usb-bt-dongle",
-    .qdev.size      = sizeof(struct USBBtState),
-    .qdev.vmsd      = &vmstate_usb_bt,
-    .usb_desc       = &desc_bluetooth,
-    .init           = usb_bt_initfn,
-    .handle_packet  = usb_generic_handle_packet,
-    .handle_reset   = usb_bt_handle_reset,
-    .handle_control = usb_bt_handle_control,
-    .handle_data    = usb_bt_handle_data,
-    .handle_destroy = usb_bt_handle_destroy,
+static void usb_bt_class_initfn(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
+
+    uc->init           = usb_bt_initfn;
+    uc->product_desc   = "QEMU BT dongle";
+    uc->usb_desc       = &desc_bluetooth;
+    uc->handle_packet  = usb_generic_handle_packet;
+    uc->handle_reset   = usb_bt_handle_reset;
+    uc->handle_control = usb_bt_handle_control;
+    uc->handle_data    = usb_bt_handle_data;
+    uc->handle_destroy = usb_bt_handle_destroy;
+    dc->vmsd = &vmstate_usb_bt;
+}
+
+static TypeInfo bt_info = {
+    .name          = "usb-bt-dongle",
+    .parent        = TYPE_USB_DEVICE,
+    .instance_size = sizeof(struct USBBtState),
+    .class_init    = usb_bt_class_initfn,
 };
 
 static void usb_bt_register_devices(void)
 {
-    usb_qdev_register(&bt_info);
+    type_register_static(&bt_info);
 }
 device_init(usb_bt_register_devices)
diff --git a/hw/usb-bus.c b/hw/usb-bus.c
index bd4afa7e2b..b753834584 100644
--- a/hw/usb-bus.c
+++ b/hw/usb-bus.c
@@ -65,21 +65,112 @@ USBBus *usb_bus_find(int busnr)
     return NULL;
 }
 
-static int usb_qdev_init(DeviceState *qdev, DeviceInfo *base)
+static int usb_device_init(USBDevice *dev)
 {
-    USBDevice *dev = DO_UPCAST(USBDevice, qdev, qdev);
-    USBDeviceInfo *info = DO_UPCAST(USBDeviceInfo, qdev, base);
+    USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
+    if (klass->init) {
+        return klass->init(dev);
+    }
+    return 0;
+}
+
+static void usb_device_handle_destroy(USBDevice *dev)
+{
+    USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
+    if (klass->handle_destroy) {
+        klass->handle_destroy(dev);
+    }
+}
+
+int usb_device_handle_packet(USBDevice *dev, USBPacket *p)
+{
+    USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
+    if (klass->handle_packet) {
+        return klass->handle_packet(dev, p);
+    }
+    return -ENOSYS;
+}
+
+void usb_device_cancel_packet(USBDevice *dev, USBPacket *p)
+{
+    USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
+    if (klass->cancel_packet) {
+        klass->cancel_packet(dev, p);
+    }
+}
+
+void usb_device_handle_attach(USBDevice *dev)
+{
+    USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
+    if (klass->handle_attach) {
+        klass->handle_attach(dev);
+    }
+}
+
+void usb_device_handle_reset(USBDevice *dev)
+{
+    USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
+    if (klass->handle_reset) {
+        klass->handle_reset(dev);
+    }
+}
+
+int usb_device_handle_control(USBDevice *dev, USBPacket *p, int request,
+                              int value, int index, int length, uint8_t *data)
+{
+    USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
+    if (klass->handle_control) {
+        return klass->handle_control(dev, p, request, value, index, length,
+                                         data);
+    }
+    return -ENOSYS;
+}
+
+int usb_device_handle_data(USBDevice *dev, USBPacket *p)
+{
+    USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
+    if (klass->handle_data) {
+        return klass->handle_data(dev, p);
+    }
+    return -ENOSYS;
+}
+
+const char *usb_device_get_product_desc(USBDevice *dev)
+{
+    USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
+    return klass->product_desc;
+}
+
+const USBDesc *usb_device_get_usb_desc(USBDevice *dev)
+{
+    USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
+    return klass->usb_desc;
+}
+
+void usb_device_set_interface(USBDevice *dev, int interface,
+                              int alt_old, int alt_new)
+{
+    USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
+    if (klass->set_interface) {
+        klass->set_interface(dev, interface, alt_old, alt_new);
+    }
+}
+
+static int usb_qdev_init(DeviceState *qdev)
+{
+    USBDevice *dev = USB_DEVICE(qdev);
     int rc;
 
-    pstrcpy(dev->product_desc, sizeof(dev->product_desc), info->product_desc);
-    dev->info = info;
+    pstrcpy(dev->product_desc, sizeof(dev->product_desc),
+            usb_device_get_product_desc(dev));
     dev->auto_attach = 1;
     QLIST_INIT(&dev->strings);
+    usb_ep_init(dev);
     rc = usb_claim_port(dev);
     if (rc != 0) {
         return rc;
     }
-    rc = dev->info->init(dev);
+    rc = usb_device_init(dev);
     if (rc != 0) {
         usb_release_port(dev);
         return rc;
@@ -96,34 +187,36 @@ static int usb_qdev_init(DeviceState *qdev, DeviceInfo *base)
 
 static int usb_qdev_exit(DeviceState *qdev)
 {
-    USBDevice *dev = DO_UPCAST(USBDevice, qdev, qdev);
+    USBDevice *dev = USB_DEVICE(qdev);
 
     if (dev->attached) {
         usb_device_detach(dev);
     }
-    if (dev->info->handle_destroy) {
-        dev->info->handle_destroy(dev);
-    }
+    usb_device_handle_destroy(dev);
     if (dev->port) {
         usb_release_port(dev);
     }
     return 0;
 }
 
-void usb_qdev_register(USBDeviceInfo *info)
+typedef struct LegacyUSBFactory
 {
-    info->qdev.bus_info = &usb_bus_info;
-    info->qdev.init     = usb_qdev_init;
-    info->qdev.unplug   = qdev_simple_unplug_cb;
-    info->qdev.exit     = usb_qdev_exit;
-    qdev_register(&info->qdev);
-}
+    const char *name;
+    const char *usbdevice_name;
+    USBDevice *(*usbdevice_init)(const char *params);
+} LegacyUSBFactory;
 
-void usb_qdev_register_many(USBDeviceInfo *info)
+static GSList *legacy_usb_factory;
+
+void usb_legacy_register(const char *typename, const char *usbdevice_name,
+                         USBDevice *(*usbdevice_init)(const char *params))
 {
-    while (info->qdev.name) {
-        usb_qdev_register(info);
-        info++;
+    if (usbdevice_name) {
+        LegacyUSBFactory *f = g_malloc0(sizeof(*f));
+        f->name = typename;
+        f->usbdevice_name = usbdevice_name;
+        f->usbdevice_init = usbdevice_init;
+        legacy_usb_factory = g_slist_append(legacy_usb_factory, f);
     }
 }
 
@@ -143,7 +236,7 @@ USBDevice *usb_create(USBBus *bus, const char *name)
 #endif
 
     dev = qdev_create(&bus->qbus, name);
-    return DO_UPCAST(USBDevice, qdev, dev);
+    return USB_DEVICE(dev);
 }
 
 USBDevice *usb_create_simple(USBBus *bus, const char *name)
@@ -249,7 +342,7 @@ int usb_claim_port(USBDevice *dev)
             return -1;
         }
     } else {
-        if (bus->nfree == 1 && strcmp(dev->qdev.info->name, "usb-hub") != 0) {
+        if (bus->nfree == 1 && strcmp(object_get_typename(OBJECT(dev)), "usb-hub") != 0) {
             /* Create a new hub and chain it on */
             usb_create_simple(bus, "usb-hub");
         }
@@ -364,7 +457,7 @@ static const char *usb_speed(unsigned int speed)
 
 static void usb_bus_dev_print(Monitor *mon, DeviceState *qdev, int indent)
 {
-    USBDevice *dev = DO_UPCAST(USBDevice, qdev, qdev);
+    USBDevice *dev = USB_DEVICE(qdev);
     USBBus *bus = usb_bus_from_device(dev);
 
     monitor_printf(mon, "%*saddr %d.%d, port %s, speed %s, name %s%s\n",
@@ -376,13 +469,13 @@ static void usb_bus_dev_print(Monitor *mon, DeviceState *qdev, int indent)
 
 static char *usb_get_dev_path(DeviceState *qdev)
 {
-    USBDevice *dev = DO_UPCAST(USBDevice, qdev, qdev);
+    USBDevice *dev = USB_DEVICE(qdev);
     return g_strdup(dev->port->path);
 }
 
 static char *usb_get_fw_dev_path(DeviceState *qdev)
 {
-    USBDevice *dev = DO_UPCAST(USBDevice, qdev, qdev);
+    USBDevice *dev = USB_DEVICE(qdev);
     char *fw_path, *in;
     ssize_t pos = 0, fw_len;
     long nr;
@@ -433,8 +526,8 @@ void usb_info(Monitor *mon)
 USBDevice *usbdevice_create(const char *cmdline)
 {
     USBBus *bus = usb_bus_find(-1 /* any */);
-    DeviceInfo *info;
-    USBDeviceInfo *usb;
+    LegacyUSBFactory *f = NULL;
+    GSList *i;
     char driver[32];
     const char *params;
     int len;
@@ -451,17 +544,13 @@ USBDevice *usbdevice_create(const char *cmdline)
         pstrcpy(driver, sizeof(driver), cmdline);
     }
 
-    for (info = device_info_list; info != NULL; info = info->next) {
-        if (info->bus_info != &usb_bus_info)
-            continue;
-        usb = DO_UPCAST(USBDeviceInfo, qdev, info);
-        if (usb->usbdevice_name == NULL)
-            continue;
-        if (strcmp(usb->usbdevice_name, driver) != 0)
-            continue;
-        break;
+    for (i = legacy_usb_factory; i; i = i->next) {
+        f = i->data;
+        if (strcmp(f->usbdevice_name, driver) == 0) {
+            break;
+        }
     }
-    if (info == NULL) {
+    if (i == NULL) {
 #if 0
         /* no error because some drivers are not converted (yet) */
         error_report("usbdevice %s not found", driver);
@@ -469,12 +558,37 @@ USBDevice *usbdevice_create(const char *cmdline)
         return NULL;
     }
 
-    if (!usb->usbdevice_init) {
+    if (!f->usbdevice_init) {
         if (*params) {
             error_report("usbdevice %s accepts no params", driver);
             return NULL;
         }
-        return usb_create_simple(bus, usb->qdev.name);
+        return usb_create_simple(bus, f->name);
     }
-    return usb->usbdevice_init(params);
+    return f->usbdevice_init(params);
+}
+
+static void usb_device_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *k = DEVICE_CLASS(klass);
+    k->bus_info = &usb_bus_info;
+    k->init     = usb_qdev_init;
+    k->unplug   = qdev_simple_unplug_cb;
+    k->exit     = usb_qdev_exit;
 }
+
+static TypeInfo usb_device_type_info = {
+    .name = TYPE_USB_DEVICE,
+    .parent = TYPE_DEVICE,
+    .instance_size = sizeof(USBDevice),
+    .abstract = true,
+    .class_size = sizeof(USBDeviceClass),
+    .class_init = usb_device_class_init,
+};
+
+static void usb_register_devices(void)
+{
+    type_register_static(&usb_device_type_info);
+}
+
+device_init(usb_register_devices);
diff --git a/hw/usb-ccid.c b/hw/usb-ccid.c
index cd349f3f17..881da3002e 100644
--- a/hw/usb-ccid.c
+++ b/hw/usb-ccid.c
@@ -269,7 +269,6 @@ typedef struct USBCCIDState {
     USBDevice dev;
     CCIDBus bus;
     CCIDCardState *card;
-    CCIDCardInfo *cardinfo; /* caching the info pointer */
     BulkIn bulk_in_pending[BULK_IN_PENDING_NUM]; /* circular */
     uint32_t bulk_in_pending_start;
     uint32_t bulk_in_pending_end; /* first free */
@@ -468,6 +467,43 @@ static const USBDesc desc_ccid = {
     .str  = desc_strings,
 };
 
+static const uint8_t *ccid_card_get_atr(CCIDCardState *card, uint32_t *len)
+{
+    CCIDCardClass *cc = CCID_CARD_GET_CLASS(card);
+    if (cc->get_atr) {
+        return cc->get_atr(card, len);
+    }
+    return NULL;
+}
+
+static void ccid_card_apdu_from_guest(CCIDCardState *card,
+                                      const uint8_t *apdu,
+                                      uint32_t len)
+{
+    CCIDCardClass *cc = CCID_CARD_GET_CLASS(card);
+    if (cc->apdu_from_guest) {
+        cc->apdu_from_guest(card, apdu, len);
+    }
+}
+
+static int ccid_card_exitfn(CCIDCardState *card)
+{
+    CCIDCardClass *cc = CCID_CARD_GET_CLASS(card);
+    if (cc->exitfn) {
+        return cc->exitfn(card);
+    }
+    return 0;
+}
+
+static int ccid_card_initfn(CCIDCardState *card)
+{
+    CCIDCardClass *cc = CCID_CARD_GET_CLASS(card);
+    if (cc->initfn) {
+        return cc->initfn(card);
+    }
+    return 0;
+}
+
 static bool ccid_has_pending_answers(USBCCIDState *s)
 {
     return s->pending_answers_num > 0;
@@ -611,14 +647,6 @@ static int ccid_handle_control(USBDevice *dev, USBPacket *p, int request,
     }
 
     switch (request) {
-    case DeviceRequest | USB_REQ_GET_INTERFACE:
-        data[0] = 0;
-        ret = 1;
-        break;
-    case InterfaceOutRequest | USB_REQ_SET_INTERFACE:
-        ret = 0;
-        break;
-
         /* Class specific requests.  */
     case InterfaceOutClass | CCID_CONTROL_ABORT:
         DPRINTF(s, 1, "ccid_control abort UNIMPLEMENTED\n");
@@ -749,7 +777,7 @@ static void ccid_write_data_block_atr(USBCCIDState *s, CCID_Header *recv)
     uint32_t len = 0;
 
     if (s->card) {
-        atr = s->cardinfo->get_atr(s->card, &len);
+        atr = ccid_card_get_atr(s->card, &len);
     }
     ccid_write_data_block(s, recv->bSlot, recv->bSeq, atr, len);
 }
@@ -835,7 +863,7 @@ static void ccid_on_apdu_from_guest(USBCCIDState *s, CCID_XferBlock *recv)
                 recv->hdr.bSeq, len);
     ccid_add_pending_answer(s, (CCID_Header *)recv);
     if (s->card) {
-        s->cardinfo->apdu_from_guest(s->card, recv->abData, len);
+        ccid_card_apdu_from_guest(s->card, recv->abData, len);
     } else {
         DPRINTF(s, D_WARN, "warning: discarded apdu\n");
     }
@@ -1121,26 +1149,21 @@ void ccid_card_card_inserted(CCIDCardState *card)
 static int ccid_card_exit(DeviceState *qdev)
 {
     int ret = 0;
-    CCIDCardState *card = DO_UPCAST(CCIDCardState, qdev, qdev);
-    CCIDCardInfo *info = DO_UPCAST(CCIDCardInfo, qdev, qdev->info);
+    CCIDCardState *card = CCID_CARD(qdev);
     USBCCIDState *s =
         DO_UPCAST(USBCCIDState, dev.qdev, card->qdev.parent_bus->parent);
 
     if (ccid_card_inserted(s)) {
         ccid_card_card_removed(card);
     }
-    if (info->exitfn) {
-        ret = info->exitfn(card);
-    }
+    ret = ccid_card_exitfn(card);
     s->card = NULL;
-    s->cardinfo = NULL;
     return ret;
 }
 
-static int ccid_card_init(DeviceState *qdev, DeviceInfo *base)
+static int ccid_card_init(DeviceState *qdev)
 {
-    CCIDCardState *card = DO_UPCAST(CCIDCardState, qdev, qdev);
-    CCIDCardInfo *info = DO_UPCAST(CCIDCardInfo, qdev, base);
+    CCIDCardState *card = CCID_CARD(qdev);
     USBCCIDState *s =
         DO_UPCAST(USBCCIDState, dev.qdev, card->qdev.parent_bus->parent);
     int ret = 0;
@@ -1154,22 +1177,13 @@ static int ccid_card_init(DeviceState *qdev, DeviceInfo *base)
         error_report("Warning: usb-ccid card already full, not adding");
         return -1;
     }
-    ret = info->initfn ? info->initfn(card) : ret;
+    ret = ccid_card_initfn(card);
     if (ret == 0) {
         s->card = card;
-        s->cardinfo = info;
     }
     return ret;
 }
 
-void ccid_card_qdev_register(CCIDCardInfo *card)
-{
-    card->qdev.bus_info = &ccid_bus_info;
-    card->qdev.init = ccid_card_init;
-    card->qdev.exit = ccid_card_exit;
-    qdev_register(&card->qdev);
-}
-
 static int ccid_initfn(USBDevice *dev)
 {
     USBCCIDState *s = DO_UPCAST(USBCCIDState, dev, dev);
@@ -1178,7 +1192,6 @@ static int ccid_initfn(USBDevice *dev)
     qbus_create_inplace(&s->bus.qbus, &ccid_bus_info, &dev->qdev, NULL);
     s->bus.qbus.allow_hotplug = 1;
     s->card = NULL;
-    s->cardinfo = NULL;
     s->migration_state = MIGRATION_NONE;
     s->migration_target_ip = 0;
     s->migration_target_port = 0;
@@ -1294,28 +1307,57 @@ static VMStateDescription ccid_vmstate = {
     }
 };
 
-static struct USBDeviceInfo ccid_info = {
-    .product_desc   = "QEMU USB CCID",
-    .qdev.name      = CCID_DEV_NAME,
-    .qdev.desc      = "CCID Rev 1.1 smartcard reader",
-    .qdev.size      = sizeof(USBCCIDState),
-    .init           = ccid_initfn,
-    .usb_desc       = &desc_ccid,
-    .handle_packet  = usb_generic_handle_packet,
-    .handle_reset   = ccid_handle_reset,
-    .handle_control = ccid_handle_control,
-    .handle_data    = ccid_handle_data,
-    .handle_destroy = ccid_handle_destroy,
-    .usbdevice_name = "ccid",
-    .qdev.props     = (Property[]) {
-        DEFINE_PROP_UINT8("debug", USBCCIDState, debug, 0),
-        DEFINE_PROP_END_OF_LIST(),
-    },
-    .qdev.vmsd      = &ccid_vmstate,
+static Property ccid_properties[] = {
+    DEFINE_PROP_UINT8("debug", USBCCIDState, debug, 0),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void ccid_class_initfn(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
+
+    uc->init           = ccid_initfn;
+    uc->product_desc   = "QEMU USB CCID";
+    uc->usb_desc       = &desc_ccid;
+    uc->handle_packet  = usb_generic_handle_packet;
+    uc->handle_reset   = ccid_handle_reset;
+    uc->handle_control = ccid_handle_control;
+    uc->handle_data    = ccid_handle_data;
+    uc->handle_destroy = ccid_handle_destroy;
+    dc->desc = "CCID Rev 1.1 smartcard reader";
+    dc->vmsd = &ccid_vmstate;
+    dc->props = ccid_properties;
+}
+
+static TypeInfo ccid_info = {
+    .name          = CCID_DEV_NAME,
+    .parent        = TYPE_USB_DEVICE,
+    .instance_size = sizeof(USBCCIDState),
+    .class_init    = ccid_class_initfn,
+};
+
+static void ccid_card_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *k = DEVICE_CLASS(klass);
+    k->bus_info = &ccid_bus_info;
+    k->init = ccid_card_init;
+    k->exit = ccid_card_exit;
+}
+
+static TypeInfo ccid_card_type_info = {
+    .name = TYPE_CCID_CARD,
+    .parent = TYPE_DEVICE,
+    .instance_size = sizeof(CCIDCardState),
+    .abstract = true,
+    .class_size = sizeof(CCIDCardClass),
+    .class_init = ccid_card_class_init,
 };
 
 static void ccid_register_devices(void)
 {
-    usb_qdev_register(&ccid_info);
+    type_register_static(&ccid_card_type_info);
+    type_register_static(&ccid_info);
+    usb_legacy_register(CCID_DEV_NAME, "ccid", NULL);
 }
 device_init(ccid_register_devices)
diff --git a/hw/usb-desc.c b/hw/usb-desc.c
index ae2d384bb3..3c3ed6a802 100644
--- a/hw/usb-desc.c
+++ b/hw/usb-desc.c
@@ -192,9 +192,10 @@ int usb_desc_iface(const USBDescIface *iface, uint8_t *dest, size_t len)
 
 int usb_desc_endpoint(const USBDescEndpoint *ep, uint8_t *dest, size_t len)
 {
-    uint8_t bLength = 0x07;
+    uint8_t bLength = ep->is_audio ? 0x09 : 0x07;
+    uint8_t extralen = ep->extra ? ep->extra[0] : 0;
 
-    if (len < bLength) {
+    if (len < bLength + extralen) {
         return -1;
     }
 
@@ -205,8 +206,15 @@ int usb_desc_endpoint(const USBDescEndpoint *ep, uint8_t *dest, size_t len)
     dest[0x04] = usb_lo(ep->wMaxPacketSize);
     dest[0x05] = usb_hi(ep->wMaxPacketSize);
     dest[0x06] = ep->bInterval;
+    if (ep->is_audio) {
+        dest[0x07] = ep->bRefresh;
+        dest[0x08] = ep->bSynchAddress;
+    }
+    if (ep->extra) {
+        memcpy(dest + bLength, ep->extra, extralen);
+    }
 
-    return bLength;
+    return bLength + extralen;
 }
 
 int usb_desc_other(const USBDescOther *desc, uint8_t *dest, size_t len)
@@ -223,9 +231,114 @@ int usb_desc_other(const USBDescOther *desc, uint8_t *dest, size_t len)
 
 /* ------------------------------------------------------------------ */
 
+static void usb_desc_ep_init(USBDevice *dev)
+{
+    const USBDescIface *iface;
+    int i, e, pid, ep;
+
+    usb_ep_init(dev);
+    for (i = 0; i < dev->ninterfaces; i++) {
+        iface = dev->ifaces[i];
+        if (iface == NULL) {
+            continue;
+        }
+        for (e = 0; e < iface->bNumEndpoints; e++) {
+            pid = (iface->eps[e].bEndpointAddress & USB_DIR_IN) ?
+                USB_TOKEN_IN : USB_TOKEN_OUT;
+            ep = iface->eps[e].bEndpointAddress & 0x0f;
+            usb_ep_set_type(dev, pid, ep, iface->eps[e].bmAttributes & 0x03);
+            usb_ep_set_ifnum(dev, pid, ep, iface->bInterfaceNumber);
+            usb_ep_set_max_packet_size(dev, pid, ep,
+                                       iface->eps[e].wMaxPacketSize);
+        }
+    }
+}
+
+static const USBDescIface *usb_desc_find_interface(USBDevice *dev,
+                                                   int nif, int alt)
+{
+    const USBDescIface *iface;
+    int g, i;
+
+    if (!dev->config) {
+        return NULL;
+    }
+    for (g = 0; g < dev->config->nif_groups; g++) {
+        for (i = 0; i < dev->config->if_groups[g].nif; i++) {
+            iface = &dev->config->if_groups[g].ifs[i];
+            if (iface->bInterfaceNumber == nif &&
+                iface->bAlternateSetting == alt) {
+                return iface;
+            }
+        }
+    }
+    for (i = 0; i < dev->config->nif; i++) {
+        iface = &dev->config->ifs[i];
+        if (iface->bInterfaceNumber == nif &&
+            iface->bAlternateSetting == alt) {
+            return iface;
+        }
+    }
+    return NULL;
+}
+
+static int usb_desc_set_interface(USBDevice *dev, int index, int value)
+{
+    const USBDescIface *iface;
+    int old;
+
+    iface = usb_desc_find_interface(dev, index, value);
+    if (iface == NULL) {
+        return -1;
+    }
+
+    old = dev->altsetting[index];
+    dev->altsetting[index] = value;
+    dev->ifaces[index] = iface;
+    usb_desc_ep_init(dev);
+
+    if (old != value) {
+        usb_device_set_interface(dev, index, old, value);
+    }
+    return 0;
+}
+
+static int usb_desc_set_config(USBDevice *dev, int value)
+{
+    int i;
+
+    if (value == 0) {
+        dev->configuration = 0;
+        dev->ninterfaces   = 0;
+        dev->config = NULL;
+    } else {
+        for (i = 0; i < dev->device->bNumConfigurations; i++) {
+            if (dev->device->confs[i].bConfigurationValue == value) {
+                dev->configuration = value;
+                dev->ninterfaces   = dev->device->confs[i].bNumInterfaces;
+                dev->config = dev->device->confs + i;
+                assert(dev->ninterfaces <= USB_MAX_INTERFACES);
+            }
+        }
+        if (i < dev->device->bNumConfigurations) {
+            return -1;
+        }
+    }
+
+    for (i = 0; i < dev->ninterfaces; i++) {
+        usb_desc_set_interface(dev, i, 0);
+    }
+    for (; i < USB_MAX_INTERFACES; i++) {
+        dev->altsetting[i] = 0;
+        dev->ifaces[i] = NULL;
+    }
+
+    return 0;
+}
+
 static void usb_desc_setdefaults(USBDevice *dev)
 {
-    const USBDesc *desc = dev->info->usb_desc;
+    const USBDesc *desc = usb_device_get_usb_desc(dev);
 
     assert(desc != NULL);
     switch (dev->speed) {
@@ -237,12 +350,12 @@ static void usb_desc_setdefaults(USBDevice *dev)
         dev->device = desc->high;
         break;
     }
-    dev->config = dev->device->confs;
+    usb_desc_set_config(dev, 0);
 }
 
 void usb_desc_init(USBDevice *dev)
 {
-    const USBDesc *desc = dev->info->usb_desc;
+    const USBDesc *desc = usb_device_get_usb_desc(dev);
 
     assert(desc != NULL);
     dev->speed = USB_SPEED_FULL;
@@ -258,7 +371,7 @@ void usb_desc_init(USBDevice *dev)
 
 void usb_desc_attach(USBDevice *dev)
 {
-    const USBDesc *desc = dev->info->usb_desc;
+    const USBDesc *desc = usb_device_get_usb_desc(dev);
 
     assert(desc != NULL);
     if (desc->high && (dev->port->speedmask & USB_SPEED_MASK_HIGH)) {
@@ -267,7 +380,7 @@ void usb_desc_attach(USBDevice *dev)
         dev->speed = USB_SPEED_FULL;
     } else {
         fprintf(stderr, "usb: port/device speed mismatch for \"%s\"\n",
-                dev->info->product_desc);
+                usb_device_get_product_desc(dev));
         return;
     }
     usb_desc_setdefaults(dev);
@@ -323,7 +436,7 @@ int usb_desc_string(USBDevice *dev, int index, uint8_t *dest, size_t len)
 
     str = usb_desc_get_string(dev, index);
     if (str == NULL) {
-        str = dev->info->usb_desc->str[index];
+        str = usb_device_get_usb_desc(dev)->str[index];
         if (str == NULL) {
             return 0;
         }
@@ -342,7 +455,7 @@ int usb_desc_string(USBDevice *dev, int index, uint8_t *dest, size_t len)
 
 int usb_desc_get_descriptor(USBDevice *dev, int value, uint8_t *dest, size_t len)
 {
-    const USBDesc *desc = dev->info->usb_desc;
+    const USBDesc *desc = usb_device_get_usb_desc(dev);
     const USBDescDevice *other_dev;
     uint8_t buf[256];
     uint8_t type = value >> 8;
@@ -350,9 +463,9 @@ int usb_desc_get_descriptor(USBDevice *dev, int value, uint8_t *dest, size_t len
     int ret = -1;
 
     if (dev->speed == USB_SPEED_HIGH) {
-        other_dev = dev->info->usb_desc->full;
+        other_dev = usb_device_get_usb_desc(dev)->full;
     } else {
-        other_dev = dev->info->usb_desc->high;
+        other_dev = usb_device_get_usb_desc(dev)->high;
     }
 
     switch(type) {
@@ -407,8 +520,8 @@ int usb_desc_get_descriptor(USBDevice *dev, int value, uint8_t *dest, size_t len
 int usb_desc_handle_control(USBDevice *dev, USBPacket *p,
         int request, int value, int index, int length, uint8_t *data)
 {
-    const USBDesc *desc = dev->info->usb_desc;
-    int i, ret = -1;
+    const USBDesc *desc = usb_device_get_usb_desc(dev);
+    int ret = -1;
 
     assert(desc != NULL);
     switch(request) {
@@ -427,12 +540,7 @@ int usb_desc_handle_control(USBDevice *dev, USBPacket *p,
         ret = 1;
         break;
     case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
-        for (i = 0; i < dev->device->bNumConfigurations; i++) {
-            if (dev->device->confs[i].bConfigurationValue == value) {
-                dev->config = dev->device->confs + i;
-                ret = 0;
-            }
-        }
+        ret = usb_desc_set_config(dev, value);
         trace_usb_set_config(dev->addr, value, ret);
         break;
 
@@ -461,6 +569,19 @@ int usb_desc_handle_control(USBDevice *dev, USBPacket *p,
         }
         trace_usb_set_device_feature(dev->addr, value, ret);
         break;
+
+    case InterfaceRequest | USB_REQ_GET_INTERFACE:
+        if (index < 0 || index >= dev->ninterfaces) {
+            break;
+        }
+        data[0] = dev->altsetting[index];
+        ret = 1;
+        break;
+    case InterfaceOutRequest | USB_REQ_SET_INTERFACE:
+        ret = usb_desc_set_interface(dev, index, value);
+        trace_usb_set_interface(dev->addr, index, value, ret);
+        break;
+
     }
     return ret;
 }
diff --git a/hw/usb-desc.h b/hw/usb-desc.h
index 5c14e4abdc..d6e07ea5d2 100644
--- a/hw/usb-desc.h
+++ b/hw/usb-desc.h
@@ -71,6 +71,11 @@ struct USBDescEndpoint {
     uint8_t                   bmAttributes;
     uint16_t                  wMaxPacketSize;
     uint8_t                   bInterval;
+    uint8_t                   bRefresh;
+    uint8_t                   bSynchAddress;
+
+    uint8_t                   is_audio; /* has bRefresh + bSynchAddress */
+    uint8_t                   *extra;
 };
 
 struct USBDescOther {
diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c
index 7c926c0d47..75ef71e69e 100644
--- a/hw/usb-ehci.c
+++ b/hw/usb-ehci.c
@@ -715,7 +715,8 @@ static void ehci_queues_rip_device(EHCIState *ehci, USBDevice *dev)
     EHCIQueue *q, *tmp;
 
     QTAILQ_FOREACH_SAFE(q, &ehci->queues, next, tmp) {
-        if (q->packet.owner != dev) {
+        if (q->packet.owner == NULL ||
+            q->packet.owner->dev != dev) {
             continue;
         }
         ehci_free_queue(q);
@@ -2262,30 +2263,46 @@ static Property ehci_properties[] = {
     DEFINE_PROP_END_OF_LIST(),
 };
 
-static PCIDeviceInfo ehci_info[] = {
-    {
-        .qdev.name    = "usb-ehci",
-        .qdev.size    = sizeof(EHCIState),
-        .qdev.vmsd    = &vmstate_ehci,
-        .init         = usb_ehci_initfn,
-        .vendor_id    = PCI_VENDOR_ID_INTEL,
-        .device_id    = PCI_DEVICE_ID_INTEL_82801D, /* ich4 */
-        .revision     = 0x10,
-        .class_id     = PCI_CLASS_SERIAL_USB,
-        .qdev.props   = ehci_properties,
-    },{
-        .qdev.name    = "ich9-usb-ehci1",
-        .qdev.size    = sizeof(EHCIState),
-        .qdev.vmsd    = &vmstate_ehci,
-        .init         = usb_ehci_initfn,
-        .vendor_id    = PCI_VENDOR_ID_INTEL,
-        .device_id    = PCI_DEVICE_ID_INTEL_82801I_EHCI1,
-        .revision     = 0x03,
-        .class_id     = PCI_CLASS_SERIAL_USB,
-        .qdev.props   = ehci_properties,
-    },{
-        /* end of list */
-    }
+static void ehci_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->init = usb_ehci_initfn;
+    k->vendor_id = PCI_VENDOR_ID_INTEL;
+    k->device_id = PCI_DEVICE_ID_INTEL_82801D; /* ich4 */
+    k->revision = 0x10;
+    k->class_id = PCI_CLASS_SERIAL_USB;
+    dc->vmsd = &vmstate_ehci;
+    dc->props = ehci_properties;
+}
+
+static TypeInfo ehci_info = {
+    .name          = "usb-ehci",
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(EHCIState),
+    .class_init    = ehci_class_init,
+};
+
+static void ich9_ehci_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->init = usb_ehci_initfn;
+    k->vendor_id = PCI_VENDOR_ID_INTEL;
+    k->device_id = PCI_DEVICE_ID_INTEL_82801I_EHCI1;
+    k->revision = 0x03;
+    k->class_id = PCI_CLASS_SERIAL_USB;
+    dc->vmsd = &vmstate_ehci;
+    dc->props = ehci_properties;
+}
+
+static TypeInfo ich9_ehci_info = {
+    .name          = "ich9-usb-ehci1",
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(EHCIState),
+    .class_init    = ich9_ehci_class_init,
 };
 
 static int usb_ehci_initfn(PCIDevice *dev)
@@ -2361,7 +2378,8 @@ static int usb_ehci_initfn(PCIDevice *dev)
 
 static void ehci_register(void)
 {
-    pci_qdev_register_many(ehci_info);
+    type_register_static(&ehci_info);
+    type_register_static(&ich9_ehci_info);
 }
 device_init(ehci_register);
 
diff --git a/hw/usb-hid.c b/hw/usb-hid.c
index a110c74dda..3c4e45da70 100644
--- a/hw/usb-hid.c
+++ b/hw/usb-hid.c
@@ -384,13 +384,6 @@ static int usb_hid_handle_control(USBDevice *dev, USBPacket *p,
 
     ret = 0;
     switch (request) {
-    case DeviceRequest | USB_REQ_GET_INTERFACE:
-        data[0] = 0;
-        ret = 1;
-        break;
-    case DeviceOutRequest | USB_REQ_SET_INTERFACE:
-        ret = 0;
-        break;
         /* hid specific requests */
     case InterfaceRequest | USB_REQ_GET_DESCRIPTOR:
         switch (value >> 8) {
@@ -560,53 +553,81 @@ static const VMStateDescription vmstate_usb_kbd = {
     }
 };
 
-static struct USBDeviceInfo hid_info[] = {
-    {
-        .product_desc   = "QEMU USB Tablet",
-        .qdev.name      = "usb-tablet",
-        .usbdevice_name = "tablet",
-        .qdev.size      = sizeof(USBHIDState),
-        .qdev.vmsd      = &vmstate_usb_ptr,
-        .usb_desc       = &desc_tablet,
-        .init           = usb_tablet_initfn,
-        .handle_packet  = usb_generic_handle_packet,
-        .handle_reset   = usb_hid_handle_reset,
-        .handle_control = usb_hid_handle_control,
-        .handle_data    = usb_hid_handle_data,
-        .handle_destroy = usb_hid_handle_destroy,
-    },{
-        .product_desc   = "QEMU USB Mouse",
-        .qdev.name      = "usb-mouse",
-        .usbdevice_name = "mouse",
-        .qdev.size      = sizeof(USBHIDState),
-        .qdev.vmsd      = &vmstate_usb_ptr,
-        .usb_desc       = &desc_mouse,
-        .init           = usb_mouse_initfn,
-        .handle_packet  = usb_generic_handle_packet,
-        .handle_reset   = usb_hid_handle_reset,
-        .handle_control = usb_hid_handle_control,
-        .handle_data    = usb_hid_handle_data,
-        .handle_destroy = usb_hid_handle_destroy,
-    },{
-        .product_desc   = "QEMU USB Keyboard",
-        .qdev.name      = "usb-kbd",
-        .usbdevice_name = "keyboard",
-        .qdev.size      = sizeof(USBHIDState),
-        .qdev.vmsd      = &vmstate_usb_kbd,
-        .usb_desc       = &desc_keyboard,
-        .init           = usb_keyboard_initfn,
-        .handle_packet  = usb_generic_handle_packet,
-        .handle_reset   = usb_hid_handle_reset,
-        .handle_control = usb_hid_handle_control,
-        .handle_data    = usb_hid_handle_data,
-        .handle_destroy = usb_hid_handle_destroy,
-    },{
-        /* end of list */
-    }
+static void usb_hid_class_initfn(ObjectClass *klass, void *data)
+{
+    USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
+
+    uc->handle_packet  = usb_generic_handle_packet;
+    uc->handle_reset   = usb_hid_handle_reset;
+    uc->handle_control = usb_hid_handle_control;
+    uc->handle_data    = usb_hid_handle_data;
+    uc->handle_destroy = usb_hid_handle_destroy;
+}
+
+static void usb_tablet_class_initfn(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
+
+    usb_hid_class_initfn(klass, data);
+    uc->init           = usb_tablet_initfn;
+    uc->product_desc   = "QEMU USB Tablet";
+    uc->usb_desc       = &desc_tablet;
+    dc->vmsd = &vmstate_usb_ptr;
+}
+
+static TypeInfo usb_tablet_info = {
+    .name          = "usb-tablet",
+    .parent        = TYPE_USB_DEVICE,
+    .instance_size = sizeof(USBHIDState),
+    .class_init    = usb_tablet_class_initfn,
+};
+
+static void usb_mouse_class_initfn(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
+
+    usb_hid_class_initfn(klass, data);
+    uc->init           = usb_mouse_initfn;
+    uc->product_desc   = "QEMU USB Mouse";
+    uc->usb_desc       = &desc_mouse;
+    dc->vmsd = &vmstate_usb_ptr;
+}
+
+static TypeInfo usb_mouse_info = {
+    .name          = "usb-mouse",
+    .parent        = TYPE_USB_DEVICE,
+    .instance_size = sizeof(USBHIDState),
+    .class_init    = usb_mouse_class_initfn,
+};
+
+static void usb_keyboard_class_initfn(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
+
+    usb_hid_class_initfn(klass, data);
+    uc->init           = usb_keyboard_initfn;
+    uc->product_desc   = "QEMU USB Keyboard";
+    uc->usb_desc       = &desc_keyboard;
+    dc->vmsd = &vmstate_usb_kbd;
+}
+
+static TypeInfo usb_keyboard_info = {
+    .name          = "usb-kbd",
+    .parent        = TYPE_USB_DEVICE,
+    .instance_size = sizeof(USBHIDState),
+    .class_init    = usb_keyboard_class_initfn,
 };
 
 static void usb_hid_register_devices(void)
 {
-    usb_qdev_register_many(hid_info);
+    type_register_static(&usb_tablet_info);
+    usb_legacy_register("usb-tablet", "tablet", NULL);
+    type_register_static(&usb_mouse_info);
+    usb_legacy_register("usb-mouse", "mouse", NULL);
+    type_register_static(&usb_keyboard_info);
+    usb_legacy_register("usb-kbd", "keyboard", NULL);
 }
 device_init(usb_hid_register_devices)
diff --git a/hw/usb-hub.c b/hw/usb-hub.c
index e1959372e7..956b020eed 100644
--- a/hw/usb-hub.c
+++ b/hw/usb-hub.c
@@ -258,13 +258,6 @@ static int usb_hub_handle_control(USBDevice *dev, USBPacket *p,
         }
         ret = 0;
         break;
-    case DeviceRequest | USB_REQ_GET_INTERFACE:
-        data[0] = 0;
-        ret = 1;
-        break;
-    case DeviceOutRequest | USB_REQ_SET_INTERFACE:
-        ret = 0;
-        break;
         /* usb specific requests */
     case GetHubStatus:
         data[0] = 0;
@@ -540,23 +533,32 @@ static const VMStateDescription vmstate_usb_hub = {
     }
 };
 
-static struct USBDeviceInfo hub_info = {
-    .product_desc   = "QEMU USB Hub",
-    .qdev.name      = "usb-hub",
-    .qdev.fw_name    = "hub",
-    .qdev.size      = sizeof(USBHubState),
-    .qdev.vmsd      = &vmstate_usb_hub,
-    .usb_desc       = &desc_hub,
-    .init           = usb_hub_initfn,
-    .handle_packet  = usb_hub_handle_packet,
-    .handle_reset   = usb_hub_handle_reset,
-    .handle_control = usb_hub_handle_control,
-    .handle_data    = usb_hub_handle_data,
-    .handle_destroy = usb_hub_handle_destroy,
+static void usb_hub_class_initfn(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
+
+    uc->init           = usb_hub_initfn;
+    uc->product_desc   = "QEMU USB Hub";
+    uc->usb_desc       = &desc_hub;
+    uc->handle_packet  = usb_hub_handle_packet;
+    uc->handle_reset   = usb_hub_handle_reset;
+    uc->handle_control = usb_hub_handle_control;
+    uc->handle_data    = usb_hub_handle_data;
+    uc->handle_destroy = usb_hub_handle_destroy;
+    dc->fw_name = "hub";
+    dc->vmsd = &vmstate_usb_hub;
+}
+
+static TypeInfo hub_info = {
+    .name          = "usb-hub",
+    .parent        = TYPE_USB_DEVICE,
+    .instance_size = sizeof(USBHubState),
+    .class_init    = usb_hub_class_initfn,
 };
 
 static void usb_hub_register_devices(void)
 {
-    usb_qdev_register(&hub_info);
+    type_register_static(&hub_info);
 }
 device_init(usb_hub_register_devices)
diff --git a/hw/usb-msd.c b/hw/usb-msd.c
index e42729699d..6153376f3f 100644
--- a/hw/usb-msd.c
+++ b/hw/usb-msd.c
@@ -306,19 +306,9 @@ static int usb_msd_handle_control(USBDevice *dev, USBPacket *p,
 
     ret = 0;
     switch (request) {
-    case DeviceRequest | USB_REQ_GET_INTERFACE:
-        data[0] = 0;
-        ret = 1;
-        break;
-    case DeviceOutRequest | USB_REQ_SET_INTERFACE:
-        ret = 0;
-        break;
     case EndpointOutRequest | USB_REQ_CLEAR_FEATURE:
         ret = 0;
         break;
-    case InterfaceOutRequest | USB_REQ_SET_INTERFACE:
-        ret = 0;
-        break;
         /* Class specific requests.  */
     case ClassInterfaceOutRequest | MassStorageReset:
         /* Reset state ready for the next CBW.  */
@@ -646,32 +636,42 @@ static const VMStateDescription vmstate_usb_msd = {
     }
 };
 
-static struct USBDeviceInfo msd_info = {
-    .product_desc   = "QEMU USB MSD",
-    .qdev.name      = "usb-storage",
-    .qdev.fw_name      = "storage",
-    .qdev.size      = sizeof(MSDState),
-    .qdev.vmsd      = &vmstate_usb_msd,
-    .usb_desc       = &desc,
-    .init           = usb_msd_initfn,
-    .handle_packet  = usb_generic_handle_packet,
-    .cancel_packet  = usb_msd_cancel_io,
-    .handle_attach  = usb_desc_attach,
-    .handle_reset   = usb_msd_handle_reset,
-    .handle_control = usb_msd_handle_control,
-    .handle_data    = usb_msd_handle_data,
-    .usbdevice_name = "disk",
-    .usbdevice_init = usb_msd_init,
-    .qdev.props     = (Property[]) {
-        DEFINE_BLOCK_PROPERTIES(MSDState, conf),
-        DEFINE_PROP_STRING("serial", MSDState, serial),
-        DEFINE_PROP_BIT("removable", MSDState, removable, 0, false),
-        DEFINE_PROP_END_OF_LIST(),
-    },
+static Property msd_properties[] = {
+    DEFINE_BLOCK_PROPERTIES(MSDState, conf),
+    DEFINE_PROP_STRING("serial", MSDState, serial),
+    DEFINE_PROP_BIT("removable", MSDState, removable, 0, false),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void usb_msd_class_initfn(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
+
+    uc->init           = usb_msd_initfn;
+    uc->product_desc   = "QEMU USB MSD";
+    uc->usb_desc       = &desc;
+    uc->handle_packet  = usb_generic_handle_packet;
+    uc->cancel_packet  = usb_msd_cancel_io;
+    uc->handle_attach  = usb_desc_attach;
+    uc->handle_reset   = usb_msd_handle_reset;
+    uc->handle_control = usb_msd_handle_control;
+    uc->handle_data    = usb_msd_handle_data;
+    dc->fw_name = "storage";
+    dc->vmsd = &vmstate_usb_msd;
+    dc->props = msd_properties;
+}
+
+static TypeInfo msd_info = {
+    .name          = "usb-storage",
+    .parent        = TYPE_USB_DEVICE,
+    .instance_size = sizeof(MSDState),
+    .class_init    = usb_msd_class_initfn,
 };
 
 static void usb_msd_register_devices(void)
 {
-    usb_qdev_register(&msd_info);
+    type_register_static(&msd_info);
+    usb_legacy_register("usb-storage", "disk", usb_msd_init);
 }
 device_init(usb_msd_register_devices)
diff --git a/hw/usb-musb.c b/hw/usb-musb.c
index 01e2e7c389..4f528d25e5 100644
--- a/hw/usb-musb.c
+++ b/hw/usb-musb.c
@@ -812,7 +812,8 @@ static void musb_async_cancel_device(MUSBState *s, USBDevice *dev)
 
     for (ep = 0; ep < 16; ep++) {
         for (dir = 0; dir < 2; dir++) {
-            if (s->ep[ep].packey[dir].p.owner != dev) {
+            if (s->ep[ep].packey[dir].p.owner == NULL ||
+                s->ep[ep].packey[dir].p.owner->dev != dev) {
                 continue;
             }
             usb_cancel_packet(&s->ep[ep].packey[dir].p);
diff --git a/hw/usb-net.c b/hw/usb-net.c
index f91fa32334..e2111413b4 100644
--- a/hw/usb-net.c
+++ b/hw/usb-net.c
@@ -71,9 +71,6 @@ enum usbstring_idx {
 #define USB_CDC_UNION_TYPE		0x06	/* union_desc */
 #define USB_CDC_ETHERNET_TYPE		0x0f	/* ether_desc */
 
-#define USB_DT_CS_INTERFACE		0x24
-#define USB_DT_CS_ENDPOINT		0x25
-
 #define USB_CDC_SEND_ENCAPSULATED_COMMAND	0x00
 #define USB_CDC_GET_ENCAPSULATED_RESPONSE	0x01
 #define USB_CDC_REQ_SET_LINE_CODING		0x20
@@ -1098,17 +1095,6 @@ static int usb_net_handle_control(USBDevice *dev, USBPacket *p,
 #endif
         break;
 
-    case DeviceRequest | USB_REQ_GET_INTERFACE:
-    case InterfaceRequest | USB_REQ_GET_INTERFACE:
-        data[0] = 0;
-        ret = 1;
-        break;
-
-    case DeviceOutRequest | USB_REQ_SET_INTERFACE:
-    case InterfaceOutRequest | USB_REQ_SET_INTERFACE:
-        ret = 0;
-        break;
-
     default:
     fail:
         fprintf(stderr, "usbnet: failed control transaction: "
@@ -1351,7 +1337,7 @@ static int usb_net_initfn(USBDevice *dev)
 
     qemu_macaddr_default_if_unset(&s->conf.macaddr);
     s->nic = qemu_new_nic(&net_usbnet_info, &s->conf,
-                          s->dev.qdev.info->name, s->dev.qdev.id, s);
+                          object_get_typename(OBJECT(s)), s->dev.qdev.id, s);
     qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a);
     snprintf(s->usbstring_mac, sizeof(s->usbstring_mac),
              "%02x%02x%02x%02x%02x%02x",
@@ -1399,29 +1385,39 @@ static const VMStateDescription vmstate_usb_net = {
     .unmigratable = 1,
 };
 
-static struct USBDeviceInfo net_info = {
-    .product_desc   = "QEMU USB Network Interface",
-    .qdev.name      = "usb-net",
-    .qdev.fw_name    = "network",
-    .qdev.size      = sizeof(USBNetState),
-    .qdev.vmsd      = &vmstate_usb_net,
-    .usb_desc       = &desc_net,
-    .init           = usb_net_initfn,
-    .handle_packet  = usb_generic_handle_packet,
-    .handle_reset   = usb_net_handle_reset,
-    .handle_control = usb_net_handle_control,
-    .handle_data    = usb_net_handle_data,
-    .handle_destroy = usb_net_handle_destroy,
-    .usbdevice_name = "net",
-    .usbdevice_init = usb_net_init,
-    .qdev.props     = (Property[]) {
-        DEFINE_NIC_PROPERTIES(USBNetState, conf),
-        DEFINE_PROP_END_OF_LIST(),
-    }
+static Property net_properties[] = {
+    DEFINE_NIC_PROPERTIES(USBNetState, conf),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void usb_net_class_initfn(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
+
+    uc->init           = usb_net_initfn;
+    uc->product_desc   = "QEMU USB Network Interface";
+    uc->usb_desc       = &desc_net;
+    uc->handle_packet  = usb_generic_handle_packet;
+    uc->handle_reset   = usb_net_handle_reset;
+    uc->handle_control = usb_net_handle_control;
+    uc->handle_data    = usb_net_handle_data;
+    uc->handle_destroy = usb_net_handle_destroy;
+    dc->fw_name = "network";
+    dc->vmsd = &vmstate_usb_net;
+    dc->props = net_properties;
+}
+
+static TypeInfo net_info = {
+    .name          = "usb-net",
+    .parent        = TYPE_USB_DEVICE,
+    .instance_size = sizeof(USBNetState),
+    .class_init    = usb_net_class_initfn,
 };
 
 static void usb_net_register_devices(void)
 {
-    usb_qdev_register(&net_info);
+    type_register_static(&net_info);
+    usb_legacy_register("usb-net", "net", usb_net_init);
 }
 device_init(usb_net_register_devices)
diff --git a/hw/usb-ohci.c b/hw/usb-ohci.c
index 81488c48e2..425030f141 100644
--- a/hw/usb-ohci.c
+++ b/hw/usb-ohci.c
@@ -1707,7 +1707,9 @@ static void ohci_mem_write(void *opaque,
 
 static void ohci_async_cancel_device(OHCIState *ohci, USBDevice *dev)
 {
-    if (ohci->async_td && ohci->usb_packet.owner == dev) {
+    if (ohci->async_td &&
+        ohci->usb_packet.owner != NULL &&
+        ohci->usb_packet.owner->dev == dev) {
         usb_cancel_packet(&ohci->usb_packet);
         ohci->async_td = 0;
     }
@@ -1775,7 +1777,7 @@ static int usb_ohci_init(OHCIState *ohci, DeviceState *dev,
     memory_region_init_io(&ohci->mem, &ohci_mem_ops, ohci, "ohci", 256);
     ohci->localmem_base = localmem_base;
 
-    ohci->name = dev->info->name;
+    ohci->name = object_get_typename(OBJECT(dev));
     usb_packet_init(&ohci->usb_packet);
 
     ohci->async_td = 0;
@@ -1834,37 +1836,59 @@ static int ohci_init_pxa(SysBusDevice *dev)
     return 0;
 }
 
-static PCIDeviceInfo ohci_pci_info = {
-    .qdev.name    = "pci-ohci",
-    .qdev.desc    = "Apple USB Controller",
-    .qdev.size    = sizeof(OHCIPCIState),
-    .init         = usb_ohci_initfn_pci,
-    .vendor_id    = PCI_VENDOR_ID_APPLE,
-    .device_id    = PCI_DEVICE_ID_APPLE_IPID_USB,
-    .class_id     = PCI_CLASS_SERIAL_USB,
-    .qdev.props   = (Property[]) {
-        DEFINE_PROP_STRING("masterbus", OHCIPCIState, masterbus),
-        DEFINE_PROP_UINT32("num-ports", OHCIPCIState, num_ports, 3),
-        DEFINE_PROP_UINT32("firstport", OHCIPCIState, firstport, 0),
-        DEFINE_PROP_END_OF_LIST(),
-    },
+static Property ohci_pci_properties[] = {
+    DEFINE_PROP_STRING("masterbus", OHCIPCIState, masterbus),
+    DEFINE_PROP_UINT32("num-ports", OHCIPCIState, num_ports, 3),
+    DEFINE_PROP_UINT32("firstport", OHCIPCIState, firstport, 0),
+    DEFINE_PROP_END_OF_LIST(),
 };
 
-static SysBusDeviceInfo ohci_sysbus_info = {
-    .init         = ohci_init_pxa,
-    .qdev.name    = "sysbus-ohci",
-    .qdev.desc    = "OHCI USB Controller",
-    .qdev.size    = sizeof(OHCISysBusState),
-    .qdev.props = (Property[]) {
-        DEFINE_PROP_UINT32("num-ports", OHCISysBusState, num_ports, 3),
-        DEFINE_PROP_TADDR("dma-offset", OHCISysBusState, dma_offset, 3),
-        DEFINE_PROP_END_OF_LIST(),
-    }
+static void ohci_pci_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->init = usb_ohci_initfn_pci;
+    k->vendor_id = PCI_VENDOR_ID_APPLE;
+    k->device_id = PCI_DEVICE_ID_APPLE_IPID_USB;
+    k->class_id = PCI_CLASS_SERIAL_USB;
+    dc->desc = "Apple USB Controller";
+    dc->props = ohci_pci_properties;
+}
+
+static TypeInfo ohci_pci_info = {
+    .name          = "pci-ohci",
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(OHCIPCIState),
+    .class_init    = ohci_pci_class_init,
+};
+
+static Property ohci_sysbus_properties[] = {
+    DEFINE_PROP_UINT32("num-ports", OHCISysBusState, num_ports, 3),
+    DEFINE_PROP_TADDR("dma-offset", OHCISysBusState, dma_offset, 3),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void ohci_sysbus_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass);
+
+    sbc->init = ohci_init_pxa;
+    dc->desc = "OHCI USB Controller";
+    dc->props = ohci_sysbus_properties;
+}
+
+static TypeInfo ohci_sysbus_info = {
+    .name          = "sysbus-ohci",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(OHCISysBusState),
+    .class_init    = ohci_sysbus_class_init,
 };
 
 static void ohci_register(void)
 {
-    pci_qdev_register(&ohci_pci_info);
-    sysbus_register_withprop(&ohci_sysbus_info);
+    type_register_static(&ohci_pci_info);
+    type_register_static(&ohci_sysbus_info);
 }
 device_init(ohci_register);
diff --git a/hw/usb-serial.c b/hw/usb-serial.c
index 7dbf6dfc6d..c2cb6d24e8 100644
--- a/hw/usb-serial.c
+++ b/hw/usb-serial.c
@@ -233,13 +233,6 @@ static int usb_serial_handle_control(USBDevice *dev, USBPacket *p,
 
     ret = 0;
     switch (request) {
-    case DeviceRequest | USB_REQ_GET_INTERFACE:
-        data[0] = 0;
-        ret = 1;
-        break;
-    case InterfaceOutRequest | USB_REQ_SET_INTERFACE:
-        ret = 0;
-        break;
     case EndpointOutRequest | USB_REQ_CLEAR_FEATURE:
         ret = 0;
         break;
@@ -577,49 +570,69 @@ static const VMStateDescription vmstate_usb_serial = {
     .unmigratable = 1,
 };
 
-static struct USBDeviceInfo serial_info = {
-    .product_desc   = "QEMU USB Serial",
-    .qdev.name      = "usb-serial",
-    .qdev.size      = sizeof(USBSerialState),
-    .qdev.vmsd      = &vmstate_usb_serial,
-    .usb_desc       = &desc_serial,
-    .init           = usb_serial_initfn,
-    .handle_packet  = usb_generic_handle_packet,
-    .handle_reset   = usb_serial_handle_reset,
-    .handle_control = usb_serial_handle_control,
-    .handle_data    = usb_serial_handle_data,
-    .handle_destroy = usb_serial_handle_destroy,
-    .usbdevice_name = "serial",
-    .usbdevice_init = usb_serial_init,
-    .qdev.props     = (Property[]) {
-        DEFINE_PROP_CHR("chardev", USBSerialState, cs),
-        DEFINE_PROP_END_OF_LIST(),
-    },
+static Property serial_properties[] = {
+    DEFINE_PROP_CHR("chardev", USBSerialState, cs),
+    DEFINE_PROP_END_OF_LIST(),
 };
 
-static struct USBDeviceInfo braille_info = {
-    .product_desc   = "QEMU USB Braille",
-    .qdev.name      = "usb-braille",
-    .qdev.size      = sizeof(USBSerialState),
-    .qdev.vmsd      = &vmstate_usb_serial,
-    .usb_desc       = &desc_braille,
-    .init           = usb_serial_initfn,
-    .handle_packet  = usb_generic_handle_packet,
-    .handle_reset   = usb_serial_handle_reset,
-    .handle_control = usb_serial_handle_control,
-    .handle_data    = usb_serial_handle_data,
-    .handle_destroy = usb_serial_handle_destroy,
-    .usbdevice_name = "braille",
-    .usbdevice_init = usb_braille_init,
-    .qdev.props     = (Property[]) {
-        DEFINE_PROP_CHR("chardev", USBSerialState, cs),
-        DEFINE_PROP_END_OF_LIST(),
-    },
+static void usb_serial_class_initfn(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
+
+    uc->init = usb_serial_initfn;
+    uc->product_desc   = "QEMU USB Serial";
+    uc->usb_desc       = &desc_serial;
+    uc->handle_packet  = usb_generic_handle_packet;
+    uc->handle_reset   = usb_serial_handle_reset;
+    uc->handle_control = usb_serial_handle_control;
+    uc->handle_data    = usb_serial_handle_data;
+    uc->handle_destroy = usb_serial_handle_destroy;
+    dc->vmsd = &vmstate_usb_serial;
+    dc->props = serial_properties;
+}
+
+static TypeInfo serial_info = {
+    .name          = "usb-serial",
+    .parent        = TYPE_USB_DEVICE,
+    .instance_size = sizeof(USBSerialState),
+    .class_init    = usb_serial_class_initfn,
+};
+
+static Property braille_properties[] = {
+    DEFINE_PROP_CHR("chardev", USBSerialState, cs),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void usb_braille_class_initfn(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
+
+    uc->init           = usb_serial_initfn;
+    uc->product_desc   = "QEMU USB Braille";
+    uc->usb_desc       = &desc_braille;
+    uc->handle_packet  = usb_generic_handle_packet;
+    uc->handle_reset   = usb_serial_handle_reset;
+    uc->handle_control = usb_serial_handle_control;
+    uc->handle_data    = usb_serial_handle_data;
+    uc->handle_destroy = usb_serial_handle_destroy;
+    dc->vmsd = &vmstate_usb_serial;
+    dc->props = braille_properties;
+}
+
+static TypeInfo braille_info = {
+    .name          = "usb-braille",
+    .parent        = TYPE_USB_DEVICE,
+    .instance_size = sizeof(USBSerialState),
+    .class_init    = usb_braille_class_initfn,
 };
 
 static void usb_serial_register_devices(void)
 {
-    usb_qdev_register(&serial_info);
-    usb_qdev_register(&braille_info);
+    type_register_static(&serial_info);
+    usb_legacy_register("usb-serial", "serial", usb_serial_init);
+    type_register_static(&braille_info);
+    usb_legacy_register("usb-braille", "braille", usb_braille_init);
 }
 device_init(usb_serial_register_devices)
diff --git a/hw/usb-uhci.c b/hw/usb-uhci.c
index f8912e2b0b..cddcc8927a 100644
--- a/hw/usb-uhci.c
+++ b/hw/usb-uhci.c
@@ -245,7 +245,8 @@ static void uhci_async_cancel_device(UHCIState *s, USBDevice *dev)
     UHCIAsync *curr, *n;
 
     QTAILQ_FOREACH_SAFE(curr, &s->async_pending, next, n) {
-        if (curr->packet.owner != dev) {
+        if (curr->packet.owner == NULL ||
+            curr->packet.owner->dev != dev) {
             continue;
         }
         uhci_async_unlink(s, curr);
@@ -1191,78 +1192,143 @@ static Property uhci_properties[] = {
     DEFINE_PROP_END_OF_LIST(),
 };
 
-static PCIDeviceInfo uhci_info[] = {
-    {
-        .qdev.name    = "piix3-usb-uhci",
-        .qdev.size    = sizeof(UHCIState),
-        .qdev.vmsd    = &vmstate_uhci,
-        .init         = usb_uhci_common_initfn,
-        .exit         = usb_uhci_exit,
-        .vendor_id    = PCI_VENDOR_ID_INTEL,
-        .device_id    = PCI_DEVICE_ID_INTEL_82371SB_2,
-        .revision     = 0x01,
-        .class_id     = PCI_CLASS_SERIAL_USB,
-        .qdev.props   = uhci_properties,
-    },{
-        .qdev.name    = "piix4-usb-uhci",
-        .qdev.size    = sizeof(UHCIState),
-        .qdev.vmsd    = &vmstate_uhci,
-        .init         = usb_uhci_common_initfn,
-        .exit         = usb_uhci_exit,
-        .vendor_id    = PCI_VENDOR_ID_INTEL,
-        .device_id    = PCI_DEVICE_ID_INTEL_82371AB_2,
-        .revision     = 0x01,
-        .class_id     = PCI_CLASS_SERIAL_USB,
-        .qdev.props   = uhci_properties,
-    },{
-        .qdev.name    = "vt82c686b-usb-uhci",
-        .qdev.size    = sizeof(UHCIState),
-        .qdev.vmsd    = &vmstate_uhci,
-        .init         = usb_uhci_vt82c686b_initfn,
-        .exit         = usb_uhci_exit,
-        .vendor_id    = PCI_VENDOR_ID_VIA,
-        .device_id    = PCI_DEVICE_ID_VIA_UHCI,
-        .revision     = 0x01,
-        .class_id     = PCI_CLASS_SERIAL_USB,
-        .qdev.props   = uhci_properties,
-    },{
-        .qdev.name    = "ich9-usb-uhci1",
-        .qdev.size    = sizeof(UHCIState),
-        .qdev.vmsd    = &vmstate_uhci,
-        .init         = usb_uhci_common_initfn,
-        .vendor_id    = PCI_VENDOR_ID_INTEL,
-        .device_id    = PCI_DEVICE_ID_INTEL_82801I_UHCI1,
-        .revision     = 0x03,
-        .class_id     = PCI_CLASS_SERIAL_USB,
-        .qdev.props   = uhci_properties,
-    },{
-        .qdev.name    = "ich9-usb-uhci2",
-        .qdev.size    = sizeof(UHCIState),
-        .qdev.vmsd    = &vmstate_uhci,
-        .init         = usb_uhci_common_initfn,
-        .vendor_id    = PCI_VENDOR_ID_INTEL,
-        .device_id    = PCI_DEVICE_ID_INTEL_82801I_UHCI2,
-        .revision     = 0x03,
-        .class_id     = PCI_CLASS_SERIAL_USB,
-        .qdev.props   = uhci_properties,
-    },{
-        .qdev.name    = "ich9-usb-uhci3",
-        .qdev.size    = sizeof(UHCIState),
-        .qdev.vmsd    = &vmstate_uhci,
-        .init         = usb_uhci_common_initfn,
-        .vendor_id    = PCI_VENDOR_ID_INTEL,
-        .device_id    = PCI_DEVICE_ID_INTEL_82801I_UHCI3,
-        .revision     = 0x03,
-        .class_id     = PCI_CLASS_SERIAL_USB,
-        .qdev.props   = uhci_properties,
-    },{
-        /* end of list */
-    }
+static void piix3_uhci_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->init = usb_uhci_common_initfn;
+    k->exit = usb_uhci_exit;
+    k->vendor_id = PCI_VENDOR_ID_INTEL;
+    k->device_id = PCI_DEVICE_ID_INTEL_82371SB_2;
+    k->revision = 0x01;
+    k->class_id = PCI_CLASS_SERIAL_USB;
+    dc->vmsd = &vmstate_uhci;
+    dc->props = uhci_properties;
+}
+
+static TypeInfo piix3_uhci_info = {
+    .name          = "piix3-usb-uhci",
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(UHCIState),
+    .class_init    = piix3_uhci_class_init,
+};
+
+static void piix4_uhci_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->init = usb_uhci_common_initfn;
+    k->exit = usb_uhci_exit;
+    k->vendor_id = PCI_VENDOR_ID_INTEL;
+    k->device_id = PCI_DEVICE_ID_INTEL_82371AB_2;
+    k->revision = 0x01;
+    k->class_id = PCI_CLASS_SERIAL_USB;
+    dc->vmsd = &vmstate_uhci;
+    dc->props = uhci_properties;
+}
+
+static TypeInfo piix4_uhci_info = {
+    .name          = "piix4-usb-uhci",
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(UHCIState),
+    .class_init    = piix4_uhci_class_init,
+};
+
+static void vt82c686b_uhci_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->init = usb_uhci_vt82c686b_initfn;
+    k->exit = usb_uhci_exit;
+    k->vendor_id = PCI_VENDOR_ID_VIA;
+    k->device_id = PCI_DEVICE_ID_VIA_UHCI;
+    k->revision = 0x01;
+    k->class_id = PCI_CLASS_SERIAL_USB;
+    dc->vmsd = &vmstate_uhci;
+    dc->props = uhci_properties;
+}
+
+static TypeInfo vt82c686b_uhci_info = {
+    .name          = "vt82c686b-usb-uhci",
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(UHCIState),
+    .class_init    = vt82c686b_uhci_class_init,
+};
+
+static void ich9_uhci1_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->init = usb_uhci_common_initfn;
+    k->vendor_id = PCI_VENDOR_ID_INTEL;
+    k->device_id = PCI_DEVICE_ID_INTEL_82801I_UHCI1;
+    k->revision = 0x03;
+    k->class_id = PCI_CLASS_SERIAL_USB;
+    dc->vmsd = &vmstate_uhci;
+    dc->props = uhci_properties;
+}
+
+static TypeInfo ich9_uhci1_info = {
+    .name          = "ich9-usb-uhci1",
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(UHCIState),
+    .class_init    = ich9_uhci1_class_init,
+};
+
+static void ich9_uhci2_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->init = usb_uhci_common_initfn;
+    k->vendor_id = PCI_VENDOR_ID_INTEL;
+    k->device_id = PCI_DEVICE_ID_INTEL_82801I_UHCI2;
+    k->revision = 0x03;
+    k->class_id = PCI_CLASS_SERIAL_USB;
+    dc->vmsd = &vmstate_uhci;
+    dc->props = uhci_properties;
+}
+
+static TypeInfo ich9_uhci2_info = {
+    .name          = "ich9-usb-uhci2",
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(UHCIState),
+    .class_init    = ich9_uhci2_class_init,
+};
+
+static void ich9_uhci3_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->init = usb_uhci_common_initfn;
+    k->vendor_id = PCI_VENDOR_ID_INTEL;
+    k->device_id = PCI_DEVICE_ID_INTEL_82801I_UHCI3;
+    k->revision = 0x03;
+    k->class_id = PCI_CLASS_SERIAL_USB;
+    dc->vmsd = &vmstate_uhci;
+    dc->props = uhci_properties;
+}
+
+static TypeInfo ich9_uhci3_info = {
+    .name          = "ich9-usb-uhci3",
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(UHCIState),
+    .class_init    = ich9_uhci3_class_init,
 };
 
 static void uhci_register(void)
 {
-    pci_qdev_register_many(uhci_info);
+    type_register_static(&piix3_uhci_info);
+    type_register_static(&piix4_uhci_info);
+    type_register_static(&vt82c686b_uhci_info);
+    type_register_static(&ich9_uhci1_info);
+    type_register_static(&ich9_uhci2_info);
+    type_register_static(&ich9_uhci3_info);
 }
 device_init(uhci_register);
 
diff --git a/hw/usb-wacom.c b/hw/usb-wacom.c
index 25580067f2..14de14d5f7 100644
--- a/hw/usb-wacom.c
+++ b/hw/usb-wacom.c
@@ -263,13 +263,6 @@ static int usb_wacom_handle_control(USBDevice *dev, USBPacket *p,
 
     ret = 0;
     switch (request) {
-    case DeviceRequest | USB_REQ_GET_INTERFACE:
-        data[0] = 0;
-        ret = 1;
-        break;
-    case DeviceOutRequest | USB_REQ_SET_INTERFACE:
-        ret = 0;
-        break;
     case WACOM_SET_REPORT:
         if (s->mouse_grabbed) {
             qemu_remove_mouse_event_handler(s->eh_entry);
@@ -356,24 +349,33 @@ static const VMStateDescription vmstate_usb_wacom = {
     .unmigratable = 1,
 };
 
-static struct USBDeviceInfo wacom_info = {
-    .product_desc   = "QEMU PenPartner Tablet",
-    .qdev.name      = "usb-wacom-tablet",
-    .qdev.desc      = "QEMU PenPartner Tablet",
-    .usbdevice_name = "wacom-tablet",
-    .usb_desc       = &desc_wacom,
-    .qdev.size      = sizeof(USBWacomState),
-    .qdev.vmsd      = &vmstate_usb_wacom,
-    .init           = usb_wacom_initfn,
-    .handle_packet  = usb_generic_handle_packet,
-    .handle_reset   = usb_wacom_handle_reset,
-    .handle_control = usb_wacom_handle_control,
-    .handle_data    = usb_wacom_handle_data,
-    .handle_destroy = usb_wacom_handle_destroy,
+static void usb_wacom_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
+
+    uc->product_desc   = "QEMU PenPartner Tablet";
+    uc->usb_desc       = &desc_wacom;
+    uc->init           = usb_wacom_initfn;
+    uc->handle_packet  = usb_generic_handle_packet;
+    uc->handle_reset   = usb_wacom_handle_reset;
+    uc->handle_control = usb_wacom_handle_control;
+    uc->handle_data    = usb_wacom_handle_data;
+    uc->handle_destroy = usb_wacom_handle_destroy;
+    dc->desc = "QEMU PenPartner Tablet";
+    dc->vmsd = &vmstate_usb_wacom;
+}
+
+static TypeInfo wacom_info = {
+    .name          = "usb-wacom-tablet",
+    .parent        = TYPE_USB_DEVICE,
+    .instance_size = sizeof(USBWacomState),
+    .class_init    = usb_wacom_class_init,
 };
 
 static void usb_wacom_register_devices(void)
 {
-    usb_qdev_register(&wacom_info);
+    type_register_static(&wacom_info);
+    usb_legacy_register("usb-wacom-tablet", "wacom-tablet", NULL);
 }
 device_init(usb_wacom_register_devices)
diff --git a/hw/usb-xhci.c b/hw/usb-xhci.c
new file mode 100644
index 0000000000..37e887c431
--- /dev/null
+++ b/hw/usb-xhci.c
@@ -0,0 +1,2759 @@
+/*
+ * USB xHCI controller emulation
+ *
+ * Copyright (c) 2011 Securiforest
+ * Date: 2011-05-11 ;  Author: Hector Martin <hector@marcansoft.com>
+ * Based on usb-ohci.c, emulates Renesas NEC USB 3.0
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include "hw.h"
+#include "qemu-timer.h"
+#include "usb.h"
+#include "pci.h"
+#include "qdev-addr.h"
+#include "msi.h"
+
+//#define DEBUG_XHCI
+//#define DEBUG_DATA
+
+#ifdef DEBUG_XHCI
+#define DPRINTF(...) fprintf(stderr, __VA_ARGS__)
+#else
+#define DPRINTF(...) do {} while (0)
+#endif
+#define FIXME() do { fprintf(stderr, "FIXME %s:%d\n", \
+                             __func__, __LINE__); abort(); } while (0)
+
+#define MAXSLOTS 8
+#define MAXINTRS 1
+
+#define USB2_PORTS 4
+#define USB3_PORTS 4
+
+#define MAXPORTS (USB2_PORTS+USB3_PORTS)
+
+#define TD_QUEUE 24
+#define BG_XFERS 8
+#define BG_PKTS 8
+
+/* Very pessimistic, let's hope it's enough for all cases */
+#define EV_QUEUE (((3*TD_QUEUE)+16)*MAXSLOTS)
+/* Do not deliver ER Full events. NEC's driver does some things not bound
+ * to the specs when it gets them */
+#define ER_FULL_HACK
+
+#define LEN_CAP         0x40
+#define OFF_OPER        LEN_CAP
+#define LEN_OPER        (0x400 + 0x10 * MAXPORTS)
+#define OFF_RUNTIME     ((OFF_OPER + LEN_OPER + 0x20) & ~0x1f)
+#define LEN_RUNTIME     (0x20 + MAXINTRS * 0x20)
+#define OFF_DOORBELL    (OFF_RUNTIME + LEN_RUNTIME)
+#define LEN_DOORBELL    ((MAXSLOTS + 1) * 0x20)
+
+/* must be power of 2 */
+#define LEN_REGS        0x2000
+
+#if (OFF_DOORBELL + LEN_DOORBELL) > LEN_REGS
+# error Increase LEN_REGS
+#endif
+
+#if MAXINTRS > 1
+# error TODO: only one interrupter supported
+#endif
+
+/* bit definitions */
+#define USBCMD_RS       (1<<0)
+#define USBCMD_HCRST    (1<<1)
+#define USBCMD_INTE     (1<<2)
+#define USBCMD_HSEE     (1<<3)
+#define USBCMD_LHCRST   (1<<7)
+#define USBCMD_CSS      (1<<8)
+#define USBCMD_CRS      (1<<9)
+#define USBCMD_EWE      (1<<10)
+#define USBCMD_EU3S     (1<<11)
+
+#define USBSTS_HCH      (1<<0)
+#define USBSTS_HSE      (1<<2)
+#define USBSTS_EINT     (1<<3)
+#define USBSTS_PCD      (1<<4)
+#define USBSTS_SSS      (1<<8)
+#define USBSTS_RSS      (1<<9)
+#define USBSTS_SRE      (1<<10)
+#define USBSTS_CNR      (1<<11)
+#define USBSTS_HCE      (1<<12)
+
+
+#define PORTSC_CCS          (1<<0)
+#define PORTSC_PED          (1<<1)
+#define PORTSC_OCA          (1<<3)
+#define PORTSC_PR           (1<<4)
+#define PORTSC_PLS_SHIFT        5
+#define PORTSC_PLS_MASK     0xf
+#define PORTSC_PP           (1<<9)
+#define PORTSC_SPEED_SHIFT      10
+#define PORTSC_SPEED_MASK   0xf
+#define PORTSC_SPEED_FULL   (1<<10)
+#define PORTSC_SPEED_LOW    (2<<10)
+#define PORTSC_SPEED_HIGH   (3<<10)
+#define PORTSC_SPEED_SUPER  (4<<10)
+#define PORTSC_PIC_SHIFT        14
+#define PORTSC_PIC_MASK     0x3
+#define PORTSC_LWS          (1<<16)
+#define PORTSC_CSC          (1<<17)
+#define PORTSC_PEC          (1<<18)
+#define PORTSC_WRC          (1<<19)
+#define PORTSC_OCC          (1<<20)
+#define PORTSC_PRC          (1<<21)
+#define PORTSC_PLC          (1<<22)
+#define PORTSC_CEC          (1<<23)
+#define PORTSC_CAS          (1<<24)
+#define PORTSC_WCE          (1<<25)
+#define PORTSC_WDE          (1<<26)
+#define PORTSC_WOE          (1<<27)
+#define PORTSC_DR           (1<<30)
+#define PORTSC_WPR          (1<<31)
+
+#define CRCR_RCS        (1<<0)
+#define CRCR_CS         (1<<1)
+#define CRCR_CA         (1<<2)
+#define CRCR_CRR        (1<<3)
+
+#define IMAN_IP         (1<<0)
+#define IMAN_IE         (1<<1)
+
+#define ERDP_EHB        (1<<3)
+
+#define TRB_SIZE 16
+typedef struct XHCITRB {
+    uint64_t parameter;
+    uint32_t status;
+    uint32_t control;
+    target_phys_addr_t addr;
+    bool ccs;
+} XHCITRB;
+
+
+typedef enum TRBType {
+    TRB_RESERVED = 0,
+    TR_NORMAL,
+    TR_SETUP,
+    TR_DATA,
+    TR_STATUS,
+    TR_ISOCH,
+    TR_LINK,
+    TR_EVDATA,
+    TR_NOOP,
+    CR_ENABLE_SLOT,
+    CR_DISABLE_SLOT,
+    CR_ADDRESS_DEVICE,
+    CR_CONFIGURE_ENDPOINT,
+    CR_EVALUATE_CONTEXT,
+    CR_RESET_ENDPOINT,
+    CR_STOP_ENDPOINT,
+    CR_SET_TR_DEQUEUE,
+    CR_RESET_DEVICE,
+    CR_FORCE_EVENT,
+    CR_NEGOTIATE_BW,
+    CR_SET_LATENCY_TOLERANCE,
+    CR_GET_PORT_BANDWIDTH,
+    CR_FORCE_HEADER,
+    CR_NOOP,
+    ER_TRANSFER = 32,
+    ER_COMMAND_COMPLETE,
+    ER_PORT_STATUS_CHANGE,
+    ER_BANDWIDTH_REQUEST,
+    ER_DOORBELL,
+    ER_HOST_CONTROLLER,
+    ER_DEVICE_NOTIFICATION,
+    ER_MFINDEX_WRAP,
+    /* vendor specific bits */
+    CR_VENDOR_VIA_CHALLENGE_RESPONSE = 48,
+    CR_VENDOR_NEC_FIRMWARE_REVISION  = 49,
+    CR_VENDOR_NEC_CHALLENGE_RESPONSE = 50,
+} TRBType;
+
+#define CR_LINK TR_LINK
+
+typedef enum TRBCCode {
+    CC_INVALID = 0,
+    CC_SUCCESS,
+    CC_DATA_BUFFER_ERROR,
+    CC_BABBLE_DETECTED,
+    CC_USB_TRANSACTION_ERROR,
+    CC_TRB_ERROR,
+    CC_STALL_ERROR,
+    CC_RESOURCE_ERROR,
+    CC_BANDWIDTH_ERROR,
+    CC_NO_SLOTS_ERROR,
+    CC_INVALID_STREAM_TYPE_ERROR,
+    CC_SLOT_NOT_ENABLED_ERROR,
+    CC_EP_NOT_ENABLED_ERROR,
+    CC_SHORT_PACKET,
+    CC_RING_UNDERRUN,
+    CC_RING_OVERRUN,
+    CC_VF_ER_FULL,
+    CC_PARAMETER_ERROR,
+    CC_BANDWIDTH_OVERRUN,
+    CC_CONTEXT_STATE_ERROR,
+    CC_NO_PING_RESPONSE_ERROR,
+    CC_EVENT_RING_FULL_ERROR,
+    CC_INCOMPATIBLE_DEVICE_ERROR,
+    CC_MISSED_SERVICE_ERROR,
+    CC_COMMAND_RING_STOPPED,
+    CC_COMMAND_ABORTED,
+    CC_STOPPED,
+    CC_STOPPED_LENGTH_INVALID,
+    CC_MAX_EXIT_LATENCY_TOO_LARGE_ERROR = 29,
+    CC_ISOCH_BUFFER_OVERRUN = 31,
+    CC_EVENT_LOST_ERROR,
+    CC_UNDEFINED_ERROR,
+    CC_INVALID_STREAM_ID_ERROR,
+    CC_SECONDARY_BANDWIDTH_ERROR,
+    CC_SPLIT_TRANSACTION_ERROR
+} TRBCCode;
+
+#define TRB_C               (1<<0)
+#define TRB_TYPE_SHIFT          10
+#define TRB_TYPE_MASK       0x3f
+#define TRB_TYPE(t)         (((t).control >> TRB_TYPE_SHIFT) & TRB_TYPE_MASK)
+
+#define TRB_EV_ED           (1<<2)
+
+#define TRB_TR_ENT          (1<<1)
+#define TRB_TR_ISP          (1<<2)
+#define TRB_TR_NS           (1<<3)
+#define TRB_TR_CH           (1<<4)
+#define TRB_TR_IOC          (1<<5)
+#define TRB_TR_IDT          (1<<6)
+#define TRB_TR_TBC_SHIFT        7
+#define TRB_TR_TBC_MASK     0x3
+#define TRB_TR_BEI          (1<<9)
+#define TRB_TR_TLBPC_SHIFT      16
+#define TRB_TR_TLBPC_MASK   0xf
+#define TRB_TR_FRAMEID_SHIFT    20
+#define TRB_TR_FRAMEID_MASK 0x7ff
+#define TRB_TR_SIA          (1<<31)
+
+#define TRB_TR_DIR          (1<<16)
+
+#define TRB_CR_SLOTID_SHIFT     24
+#define TRB_CR_SLOTID_MASK  0xff
+#define TRB_CR_EPID_SHIFT       16
+#define TRB_CR_EPID_MASK    0x1f
+
+#define TRB_CR_BSR          (1<<9)
+#define TRB_CR_DC           (1<<9)
+
+#define TRB_LK_TC           (1<<1)
+
+#define EP_TYPE_MASK        0x7
+#define EP_TYPE_SHIFT           3
+
+#define EP_STATE_MASK       0x7
+#define EP_DISABLED         (0<<0)
+#define EP_RUNNING          (1<<0)
+#define EP_HALTED           (2<<0)
+#define EP_STOPPED          (3<<0)
+#define EP_ERROR            (4<<0)
+
+#define SLOT_STATE_MASK     0x1f
+#define SLOT_STATE_SHIFT        27
+#define SLOT_STATE(s)       (((s)>>SLOT_STATE_SHIFT)&SLOT_STATE_MASK)
+#define SLOT_ENABLED        0
+#define SLOT_DEFAULT        1
+#define SLOT_ADDRESSED      2
+#define SLOT_CONFIGURED     3
+
+#define SLOT_CONTEXT_ENTRIES_MASK 0x1f
+#define SLOT_CONTEXT_ENTRIES_SHIFT 27
+
+typedef enum EPType {
+    ET_INVALID = 0,
+    ET_ISO_OUT,
+    ET_BULK_OUT,
+    ET_INTR_OUT,
+    ET_CONTROL,
+    ET_ISO_IN,
+    ET_BULK_IN,
+    ET_INTR_IN,
+} EPType;
+
+typedef struct XHCIRing {
+    target_phys_addr_t base;
+    target_phys_addr_t dequeue;
+    bool ccs;
+} XHCIRing;
+
+typedef struct XHCIPort {
+    USBPort port;
+    uint32_t portsc;
+} XHCIPort;
+
+struct XHCIState;
+typedef struct XHCIState XHCIState;
+
+typedef struct XHCITransfer {
+    XHCIState *xhci;
+    USBPacket packet;
+    bool running;
+    bool cancelled;
+    bool complete;
+    bool backgrounded;
+    unsigned int iso_pkts;
+    unsigned int slotid;
+    unsigned int epid;
+    bool in_xfer;
+    bool iso_xfer;
+    bool bg_xfer;
+
+    unsigned int trb_count;
+    unsigned int trb_alloced;
+    XHCITRB *trbs;
+
+    unsigned int data_length;
+    unsigned int data_alloced;
+    uint8_t *data;
+
+    TRBCCode status;
+
+    unsigned int pkts;
+    unsigned int pktsize;
+    unsigned int cur_pkt;
+} XHCITransfer;
+
+typedef struct XHCIEPContext {
+    XHCIRing ring;
+    unsigned int next_xfer;
+    unsigned int comp_xfer;
+    XHCITransfer transfers[TD_QUEUE];
+    bool bg_running;
+    bool bg_updating;
+    unsigned int next_bg;
+    XHCITransfer bg_transfers[BG_XFERS];
+    EPType type;
+    target_phys_addr_t pctx;
+    unsigned int max_psize;
+    bool has_bg;
+    uint32_t state;
+} XHCIEPContext;
+
+typedef struct XHCISlot {
+    bool enabled;
+    target_phys_addr_t ctx;
+    unsigned int port;
+    unsigned int devaddr;
+    XHCIEPContext * eps[31];
+} XHCISlot;
+
+typedef struct XHCIEvent {
+    TRBType type;
+    TRBCCode ccode;
+    uint64_t ptr;
+    uint32_t length;
+    uint32_t flags;
+    uint8_t slotid;
+    uint8_t epid;
+} XHCIEvent;
+
+struct XHCIState {
+    PCIDevice pci_dev;
+    USBBus bus;
+    qemu_irq irq;
+    MemoryRegion mem;
+    const char *name;
+    uint32_t msi;
+    unsigned int devaddr;
+
+    /* Operational Registers */
+    uint32_t usbcmd;
+    uint32_t usbsts;
+    uint32_t dnctrl;
+    uint32_t crcr_low;
+    uint32_t crcr_high;
+    uint32_t dcbaap_low;
+    uint32_t dcbaap_high;
+    uint32_t config;
+
+    XHCIPort ports[MAXPORTS];
+    XHCISlot slots[MAXSLOTS];
+
+    /* Runtime Registers */
+    uint32_t mfindex;
+    /* note: we only support one interrupter */
+    uint32_t iman;
+    uint32_t imod;
+    uint32_t erstsz;
+    uint32_t erstba_low;
+    uint32_t erstba_high;
+    uint32_t erdp_low;
+    uint32_t erdp_high;
+
+    target_phys_addr_t er_start;
+    uint32_t er_size;
+    bool er_pcs;
+    unsigned int er_ep_idx;
+    bool er_full;
+
+    XHCIEvent ev_buffer[EV_QUEUE];
+    unsigned int ev_buffer_put;
+    unsigned int ev_buffer_get;
+
+    XHCIRing cmd_ring;
+};
+
+typedef struct XHCIEvRingSeg {
+    uint32_t addr_low;
+    uint32_t addr_high;
+    uint32_t size;
+    uint32_t rsvd;
+} XHCIEvRingSeg;
+
+static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid,
+                         unsigned int epid);
+
+static inline target_phys_addr_t xhci_addr64(uint32_t low, uint32_t high)
+{
+#if TARGET_PHYS_ADDR_BITS > 32
+    return low | ((target_phys_addr_t)high << 32);
+#else
+    return low;
+#endif
+}
+
+static inline target_phys_addr_t xhci_mask64(uint64_t addr)
+{
+#if TARGET_PHYS_ADDR_BITS > 32
+    return addr;
+#else
+    return addr & 0xffffffff;
+#endif
+}
+
+static void xhci_irq_update(XHCIState *xhci)
+{
+    int level = 0;
+
+    if (xhci->iman & IMAN_IP && xhci->iman & IMAN_IE &&
+        xhci->usbcmd && USBCMD_INTE) {
+        level = 1;
+    }
+
+    DPRINTF("xhci_irq_update(): %d\n", level);
+
+    if (xhci->msi && msi_enabled(&xhci->pci_dev)) {
+        if (level) {
+            DPRINTF("xhci_irq_update(): MSI signal\n");
+            msi_notify(&xhci->pci_dev, 0);
+        }
+    } else {
+        qemu_set_irq(xhci->irq, level);
+    }
+}
+
+static inline int xhci_running(XHCIState *xhci)
+{
+    return !(xhci->usbsts & USBSTS_HCH) && !xhci->er_full;
+}
+
+static void xhci_die(XHCIState *xhci)
+{
+    xhci->usbsts |= USBSTS_HCE;
+    fprintf(stderr, "xhci: asserted controller error\n");
+}
+
+static void xhci_write_event(XHCIState *xhci, XHCIEvent *event)
+{
+    XHCITRB ev_trb;
+    target_phys_addr_t addr;
+
+    ev_trb.parameter = cpu_to_le64(event->ptr);
+    ev_trb.status = cpu_to_le32(event->length | (event->ccode << 24));
+    ev_trb.control = (event->slotid << 24) | (event->epid << 16) |
+                     event->flags | (event->type << TRB_TYPE_SHIFT);
+    if (xhci->er_pcs) {
+        ev_trb.control |= TRB_C;
+    }
+    ev_trb.control = cpu_to_le32(ev_trb.control);
+
+    DPRINTF("xhci_write_event(): [%d] %016"PRIx64" %08x %08x\n",
+            xhci->er_ep_idx, ev_trb.parameter, ev_trb.status, ev_trb.control);
+
+    addr = xhci->er_start + TRB_SIZE*xhci->er_ep_idx;
+    cpu_physical_memory_write(addr, (uint8_t *) &ev_trb, TRB_SIZE);
+
+    xhci->er_ep_idx++;
+    if (xhci->er_ep_idx >= xhci->er_size) {
+        xhci->er_ep_idx = 0;
+        xhci->er_pcs = !xhci->er_pcs;
+    }
+}
+
+static void xhci_events_update(XHCIState *xhci)
+{
+    target_phys_addr_t erdp;
+    unsigned int dp_idx;
+    bool do_irq = 0;
+
+    if (xhci->usbsts & USBSTS_HCH) {
+        return;
+    }
+
+    erdp = xhci_addr64(xhci->erdp_low, xhci->erdp_high);
+    if (erdp < xhci->er_start ||
+        erdp >= (xhci->er_start + TRB_SIZE*xhci->er_size)) {
+        fprintf(stderr, "xhci: ERDP out of bounds: "TARGET_FMT_plx"\n", erdp);
+        fprintf(stderr, "xhci: ER at "TARGET_FMT_plx" len %d\n",
+                xhci->er_start, xhci->er_size);
+        xhci_die(xhci);
+        return;
+    }
+    dp_idx = (erdp - xhci->er_start) / TRB_SIZE;
+    assert(dp_idx < xhci->er_size);
+
+    /* NEC didn't read section 4.9.4 of the spec (v1.0 p139 top Note) and thus
+     * deadlocks when the ER is full. Hack it by holding off events until
+     * the driver decides to free at least half of the ring */
+    if (xhci->er_full) {
+        int er_free = dp_idx - xhci->er_ep_idx;
+        if (er_free <= 0) {
+            er_free += xhci->er_size;
+        }
+        if (er_free < (xhci->er_size/2)) {
+            DPRINTF("xhci_events_update(): event ring still "
+                    "more than half full (hack)\n");
+            return;
+        }
+    }
+
+    while (xhci->ev_buffer_put != xhci->ev_buffer_get) {
+        assert(xhci->er_full);
+        if (((xhci->er_ep_idx+1) % xhci->er_size) == dp_idx) {
+            DPRINTF("xhci_events_update(): event ring full again\n");
+#ifndef ER_FULL_HACK
+            XHCIEvent full = {ER_HOST_CONTROLLER, CC_EVENT_RING_FULL_ERROR};
+            xhci_write_event(xhci, &full);
+#endif
+            do_irq = 1;
+            break;
+        }
+        XHCIEvent *event = &xhci->ev_buffer[xhci->ev_buffer_get];
+        xhci_write_event(xhci, event);
+        xhci->ev_buffer_get++;
+        do_irq = 1;
+        if (xhci->ev_buffer_get == EV_QUEUE) {
+            xhci->ev_buffer_get = 0;
+        }
+    }
+
+    if (do_irq) {
+        xhci->erdp_low |= ERDP_EHB;
+        xhci->iman |= IMAN_IP;
+        xhci->usbsts |= USBSTS_EINT;
+        xhci_irq_update(xhci);
+    }
+
+    if (xhci->er_full && xhci->ev_buffer_put == xhci->ev_buffer_get) {
+        DPRINTF("xhci_events_update(): event ring no longer full\n");
+        xhci->er_full = 0;
+    }
+    return;
+}
+
+static void xhci_event(XHCIState *xhci, XHCIEvent *event)
+{
+    target_phys_addr_t erdp;
+    unsigned int dp_idx;
+
+    if (xhci->er_full) {
+        DPRINTF("xhci_event(): ER full, queueing\n");
+        if (((xhci->ev_buffer_put+1) % EV_QUEUE) == xhci->ev_buffer_get) {
+            fprintf(stderr, "xhci: event queue full, dropping event!\n");
+            return;
+        }
+        xhci->ev_buffer[xhci->ev_buffer_put++] = *event;
+        if (xhci->ev_buffer_put == EV_QUEUE) {
+            xhci->ev_buffer_put = 0;
+        }
+        return;
+    }
+
+    erdp = xhci_addr64(xhci->erdp_low, xhci->erdp_high);
+    if (erdp < xhci->er_start ||
+        erdp >= (xhci->er_start + TRB_SIZE*xhci->er_size)) {
+        fprintf(stderr, "xhci: ERDP out of bounds: "TARGET_FMT_plx"\n", erdp);
+        fprintf(stderr, "xhci: ER at "TARGET_FMT_plx" len %d\n",
+                xhci->er_start, xhci->er_size);
+        xhci_die(xhci);
+        return;
+    }
+
+    dp_idx = (erdp - xhci->er_start) / TRB_SIZE;
+    assert(dp_idx < xhci->er_size);
+
+    if ((xhci->er_ep_idx+1) % xhci->er_size == dp_idx) {
+        DPRINTF("xhci_event(): ER full, queueing\n");
+#ifndef ER_FULL_HACK
+        XHCIEvent full = {ER_HOST_CONTROLLER, CC_EVENT_RING_FULL_ERROR};
+        xhci_write_event(xhci, &full);
+#endif
+        xhci->er_full = 1;
+        if (((xhci->ev_buffer_put+1) % EV_QUEUE) == xhci->ev_buffer_get) {
+            fprintf(stderr, "xhci: event queue full, dropping event!\n");
+            return;
+        }
+        xhci->ev_buffer[xhci->ev_buffer_put++] = *event;
+        if (xhci->ev_buffer_put == EV_QUEUE) {
+            xhci->ev_buffer_put = 0;
+        }
+    } else {
+        xhci_write_event(xhci, event);
+    }
+
+    xhci->erdp_low |= ERDP_EHB;
+    xhci->iman |= IMAN_IP;
+    xhci->usbsts |= USBSTS_EINT;
+
+    xhci_irq_update(xhci);
+}
+
+static void xhci_ring_init(XHCIState *xhci, XHCIRing *ring,
+                           target_phys_addr_t base)
+{
+    ring->base = base;
+    ring->dequeue = base;
+    ring->ccs = 1;
+}
+
+static TRBType xhci_ring_fetch(XHCIState *xhci, XHCIRing *ring, XHCITRB *trb,
+                               target_phys_addr_t *addr)
+{
+    while (1) {
+        TRBType type;
+        cpu_physical_memory_read(ring->dequeue, (uint8_t *) trb, TRB_SIZE);
+        trb->addr = ring->dequeue;
+        trb->ccs = ring->ccs;
+        le64_to_cpus(&trb->parameter);
+        le32_to_cpus(&trb->status);
+        le32_to_cpus(&trb->control);
+
+        DPRINTF("xhci: TRB fetched [" TARGET_FMT_plx "]: "
+                "%016" PRIx64 " %08x %08x\n",
+                ring->dequeue, trb->parameter, trb->status, trb->control);
+
+        if ((trb->control & TRB_C) != ring->ccs) {
+            return 0;
+        }
+
+        type = TRB_TYPE(*trb);
+
+        if (type != TR_LINK) {
+            if (addr) {
+                *addr = ring->dequeue;
+            }
+            ring->dequeue += TRB_SIZE;
+            return type;
+        } else {
+            ring->dequeue = xhci_mask64(trb->parameter);
+            if (trb->control & TRB_LK_TC) {
+                ring->ccs = !ring->ccs;
+            }
+        }
+    }
+}
+
+static int xhci_ring_chain_length(XHCIState *xhci, const XHCIRing *ring)
+{
+    XHCITRB trb;
+    int length = 0;
+    target_phys_addr_t dequeue = ring->dequeue;
+    bool ccs = ring->ccs;
+    /* hack to bundle together the two/three TDs that make a setup transfer */
+    bool control_td_set = 0;
+
+    while (1) {
+        TRBType type;
+        cpu_physical_memory_read(dequeue, (uint8_t *) &trb, TRB_SIZE);
+        le64_to_cpus(&trb.parameter);
+        le32_to_cpus(&trb.status);
+        le32_to_cpus(&trb.control);
+
+        DPRINTF("xhci: TRB peeked [" TARGET_FMT_plx "]: "
+                "%016" PRIx64 " %08x %08x\n",
+                dequeue, trb.parameter, trb.status, trb.control);
+
+        if ((trb.control & TRB_C) != ccs) {
+            return -length;
+        }
+
+        type = TRB_TYPE(trb);
+
+        if (type == TR_LINK) {
+            dequeue = xhci_mask64(trb.parameter);
+            if (trb.control & TRB_LK_TC) {
+                ccs = !ccs;
+            }
+            continue;
+        }
+
+        length += 1;
+        dequeue += TRB_SIZE;
+
+        if (type == TR_SETUP) {
+            control_td_set = 1;
+        } else if (type == TR_STATUS) {
+            control_td_set = 0;
+        }
+
+        if (!control_td_set && !(trb.control & TRB_TR_CH)) {
+            return length;
+        }
+    }
+}
+
+static void xhci_er_reset(XHCIState *xhci)
+{
+    XHCIEvRingSeg seg;
+
+    /* cache the (sole) event ring segment location */
+    if (xhci->erstsz != 1) {
+        fprintf(stderr, "xhci: invalid value for ERSTSZ: %d\n", xhci->erstsz);
+        xhci_die(xhci);
+        return;
+    }
+    target_phys_addr_t erstba = xhci_addr64(xhci->erstba_low, xhci->erstba_high);
+    cpu_physical_memory_read(erstba, (uint8_t *) &seg, sizeof(seg));
+    le32_to_cpus(&seg.addr_low);
+    le32_to_cpus(&seg.addr_high);
+    le32_to_cpus(&seg.size);
+    if (seg.size < 16 || seg.size > 4096) {
+        fprintf(stderr, "xhci: invalid value for segment size: %d\n", seg.size);
+        xhci_die(xhci);
+        return;
+    }
+    xhci->er_start = xhci_addr64(seg.addr_low, seg.addr_high);
+    xhci->er_size = seg.size;
+
+    xhci->er_ep_idx = 0;
+    xhci->er_pcs = 1;
+    xhci->er_full = 0;
+
+    DPRINTF("xhci: event ring:" TARGET_FMT_plx " [%d]\n",
+            xhci->er_start, xhci->er_size);
+}
+
+static void xhci_run(XHCIState *xhci)
+{
+    DPRINTF("xhci_run()\n");
+
+    xhci->usbsts &= ~USBSTS_HCH;
+}
+
+static void xhci_stop(XHCIState *xhci)
+{
+    DPRINTF("xhci_stop()\n");
+    xhci->usbsts |= USBSTS_HCH;
+    xhci->crcr_low &= ~CRCR_CRR;
+}
+
+static void xhci_set_ep_state(XHCIState *xhci, XHCIEPContext *epctx,
+                              uint32_t state)
+{
+    uint32_t ctx[5];
+    if (epctx->state == state) {
+        return;
+    }
+
+    cpu_physical_memory_read(epctx->pctx, (uint8_t *) ctx, sizeof(ctx));
+    ctx[0] &= ~EP_STATE_MASK;
+    ctx[0] |= state;
+    ctx[2] = epctx->ring.dequeue | epctx->ring.ccs;
+    ctx[3] = (epctx->ring.dequeue >> 16) >> 16;
+    DPRINTF("xhci: set epctx: " TARGET_FMT_plx " state=%d dequeue=%08x%08x\n",
+            epctx->pctx, state, ctx[3], ctx[2]);
+    cpu_physical_memory_write(epctx->pctx, (uint8_t *) ctx, sizeof(ctx));
+    epctx->state = state;
+}
+
+static TRBCCode xhci_enable_ep(XHCIState *xhci, unsigned int slotid,
+                               unsigned int epid, target_phys_addr_t pctx,
+                               uint32_t *ctx)
+{
+    XHCISlot *slot;
+    XHCIEPContext *epctx;
+    target_phys_addr_t dequeue;
+    int i;
+
+    assert(slotid >= 1 && slotid <= MAXSLOTS);
+    assert(epid >= 1 && epid <= 31);
+
+    DPRINTF("xhci_enable_ep(%d, %d)\n", slotid, epid);
+
+    slot = &xhci->slots[slotid-1];
+    if (slot->eps[epid-1]) {
+        fprintf(stderr, "xhci: slot %d ep %d already enabled!\n", slotid, epid);
+        return CC_TRB_ERROR;
+    }
+
+    epctx = g_malloc(sizeof(XHCIEPContext));
+    memset(epctx, 0, sizeof(XHCIEPContext));
+
+    slot->eps[epid-1] = epctx;
+
+    dequeue = xhci_addr64(ctx[2] & ~0xf, ctx[3]);
+    xhci_ring_init(xhci, &epctx->ring, dequeue);
+    epctx->ring.ccs = ctx[2] & 1;
+
+    epctx->type = (ctx[1] >> EP_TYPE_SHIFT) & EP_TYPE_MASK;
+    DPRINTF("xhci: endpoint %d.%d type is %d\n", epid/2, epid%2, epctx->type);
+    epctx->pctx = pctx;
+    epctx->max_psize = ctx[1]>>16;
+    epctx->max_psize *= 1+((ctx[1]>>8)&0xff);
+    epctx->has_bg = false;
+    if (epctx->type == ET_ISO_IN) {
+        epctx->has_bg = true;
+    }
+    DPRINTF("xhci: endpoint %d.%d max transaction (burst) size is %d\n",
+            epid/2, epid%2, epctx->max_psize);
+    for (i = 0; i < ARRAY_SIZE(epctx->transfers); i++) {
+        usb_packet_init(&epctx->transfers[i].packet);
+    }
+
+    epctx->state = EP_RUNNING;
+    ctx[0] &= ~EP_STATE_MASK;
+    ctx[0] |= EP_RUNNING;
+
+    return CC_SUCCESS;
+}
+
+static int xhci_ep_nuke_xfers(XHCIState *xhci, unsigned int slotid,
+                               unsigned int epid)
+{
+    XHCISlot *slot;
+    XHCIEPContext *epctx;
+    int i, xferi, killed = 0;
+    assert(slotid >= 1 && slotid <= MAXSLOTS);
+    assert(epid >= 1 && epid <= 31);
+
+    DPRINTF("xhci_ep_nuke_xfers(%d, %d)\n", slotid, epid);
+
+    slot = &xhci->slots[slotid-1];
+
+    if (!slot->eps[epid-1]) {
+        return 0;
+    }
+
+    epctx = slot->eps[epid-1];
+
+    xferi = epctx->next_xfer;
+    for (i = 0; i < TD_QUEUE; i++) {
+        XHCITransfer *t = &epctx->transfers[xferi];
+        if (t->running) {
+            t->cancelled = 1;
+            /* libusb_cancel_transfer(t->usbxfer) */
+            DPRINTF("xhci: cancelling transfer %d, waiting for it to complete...\n", i);
+            killed++;
+        }
+        if (t->backgrounded) {
+            t->backgrounded = 0;
+        }
+        if (t->trbs) {
+            g_free(t->trbs);
+        }
+        if (t->data) {
+            g_free(t->data);
+        }
+
+        t->trbs = NULL;
+        t->data = NULL;
+        t->trb_count = t->trb_alloced = 0;
+        t->data_length = t->data_alloced = 0;
+        xferi = (xferi + 1) % TD_QUEUE;
+    }
+    if (epctx->has_bg) {
+        xferi = epctx->next_bg;
+        for (i = 0; i < BG_XFERS; i++) {
+            XHCITransfer *t = &epctx->bg_transfers[xferi];
+            if (t->running) {
+                t->cancelled = 1;
+                /* libusb_cancel_transfer(t->usbxfer); */
+                DPRINTF("xhci: cancelling bg transfer %d, waiting for it to complete...\n", i);
+                killed++;
+            }
+            if (t->data) {
+                g_free(t->data);
+            }
+
+            t->data = NULL;
+            xferi = (xferi + 1) % BG_XFERS;
+        }
+    }
+    return killed;
+}
+
+static TRBCCode xhci_disable_ep(XHCIState *xhci, unsigned int slotid,
+                               unsigned int epid)
+{
+    XHCISlot *slot;
+    XHCIEPContext *epctx;
+
+    assert(slotid >= 1 && slotid <= MAXSLOTS);
+    assert(epid >= 1 && epid <= 31);
+
+    DPRINTF("xhci_disable_ep(%d, %d)\n", slotid, epid);
+
+    slot = &xhci->slots[slotid-1];
+
+    if (!slot->eps[epid-1]) {
+        DPRINTF("xhci: slot %d ep %d already disabled\n", slotid, epid);
+        return CC_SUCCESS;
+    }
+
+    xhci_ep_nuke_xfers(xhci, slotid, epid);
+
+    epctx = slot->eps[epid-1];
+
+    xhci_set_ep_state(xhci, epctx, EP_DISABLED);
+
+    g_free(epctx);
+    slot->eps[epid-1] = NULL;
+
+    return CC_SUCCESS;
+}
+
+static TRBCCode xhci_stop_ep(XHCIState *xhci, unsigned int slotid,
+                             unsigned int epid)
+{
+    XHCISlot *slot;
+    XHCIEPContext *epctx;
+
+    DPRINTF("xhci_stop_ep(%d, %d)\n", slotid, epid);
+
+    assert(slotid >= 1 && slotid <= MAXSLOTS);
+
+    if (epid < 1 || epid > 31) {
+        fprintf(stderr, "xhci: bad ep %d\n", epid);
+        return CC_TRB_ERROR;
+    }
+
+    slot = &xhci->slots[slotid-1];
+
+    if (!slot->eps[epid-1]) {
+        DPRINTF("xhci: slot %d ep %d not enabled\n", slotid, epid);
+        return CC_EP_NOT_ENABLED_ERROR;
+    }
+
+    if (xhci_ep_nuke_xfers(xhci, slotid, epid) > 0) {
+        fprintf(stderr, "xhci: FIXME: endpoint stopped w/ xfers running, "
+                "data might be lost\n");
+    }
+
+    epctx = slot->eps[epid-1];
+
+    xhci_set_ep_state(xhci, epctx, EP_STOPPED);
+
+    return CC_SUCCESS;
+}
+
+static TRBCCode xhci_reset_ep(XHCIState *xhci, unsigned int slotid,
+                              unsigned int epid)
+{
+    XHCISlot *slot;
+    XHCIEPContext *epctx;
+    USBDevice *dev;
+
+    assert(slotid >= 1 && slotid <= MAXSLOTS);
+
+    DPRINTF("xhci_reset_ep(%d, %d)\n", slotid, epid);
+
+    if (epid < 1 || epid > 31) {
+        fprintf(stderr, "xhci: bad ep %d\n", epid);
+        return CC_TRB_ERROR;
+    }
+
+    slot = &xhci->slots[slotid-1];
+
+    if (!slot->eps[epid-1]) {
+        DPRINTF("xhci: slot %d ep %d not enabled\n", slotid, epid);
+        return CC_EP_NOT_ENABLED_ERROR;
+    }
+
+    epctx = slot->eps[epid-1];
+
+    if (epctx->state != EP_HALTED) {
+        fprintf(stderr, "xhci: reset EP while EP %d not halted (%d)\n",
+                epid, epctx->state);
+        return CC_CONTEXT_STATE_ERROR;
+    }
+
+    if (xhci_ep_nuke_xfers(xhci, slotid, epid) > 0) {
+        fprintf(stderr, "xhci: FIXME: endpoint reset w/ xfers running, "
+                "data might be lost\n");
+    }
+
+    uint8_t ep = epid>>1;
+
+    if (epid & 1) {
+        ep |= 0x80;
+    }
+
+    dev = xhci->ports[xhci->slots[slotid-1].port-1].port.dev;
+    if (!dev) {
+        return CC_USB_TRANSACTION_ERROR;
+    }
+
+    xhci_set_ep_state(xhci, epctx, EP_STOPPED);
+
+    return CC_SUCCESS;
+}
+
+static TRBCCode xhci_set_ep_dequeue(XHCIState *xhci, unsigned int slotid,
+                                    unsigned int epid, uint64_t pdequeue)
+{
+    XHCISlot *slot;
+    XHCIEPContext *epctx;
+    target_phys_addr_t dequeue;
+
+    assert(slotid >= 1 && slotid <= MAXSLOTS);
+
+    if (epid < 1 || epid > 31) {
+        fprintf(stderr, "xhci: bad ep %d\n", epid);
+        return CC_TRB_ERROR;
+    }
+
+    DPRINTF("xhci_set_ep_dequeue(%d, %d, %016"PRIx64")\n", slotid, epid, pdequeue);
+    dequeue = xhci_mask64(pdequeue);
+
+    slot = &xhci->slots[slotid-1];
+
+    if (!slot->eps[epid-1]) {
+        DPRINTF("xhci: slot %d ep %d not enabled\n", slotid, epid);
+        return CC_EP_NOT_ENABLED_ERROR;
+    }
+
+    epctx = slot->eps[epid-1];
+
+
+    if (epctx->state != EP_STOPPED) {
+        fprintf(stderr, "xhci: set EP dequeue pointer while EP %d not stopped\n", epid);
+        return CC_CONTEXT_STATE_ERROR;
+    }
+
+    xhci_ring_init(xhci, &epctx->ring, dequeue & ~0xF);
+    epctx->ring.ccs = dequeue & 1;
+
+    xhci_set_ep_state(xhci, epctx, EP_STOPPED);
+
+    return CC_SUCCESS;
+}
+
+static int xhci_xfer_data(XHCITransfer *xfer, uint8_t *data,
+                          unsigned int length, bool in_xfer, bool out_xfer,
+                          bool report)
+{
+    int i;
+    uint32_t edtla = 0;
+    unsigned int transferred = 0;
+    unsigned int left = length;
+    bool reported = 0;
+    bool shortpkt = 0;
+    XHCIEvent event = {ER_TRANSFER, CC_SUCCESS};
+    XHCIState *xhci = xfer->xhci;
+
+    DPRINTF("xhci_xfer_data(len=%d, in_xfer=%d, out_xfer=%d, report=%d)\n",
+            length, in_xfer, out_xfer, report);
+
+    assert(!(in_xfer && out_xfer));
+
+    for (i = 0; i < xfer->trb_count; i++) {
+        XHCITRB *trb = &xfer->trbs[i];
+        target_phys_addr_t addr;
+        unsigned int chunk = 0;
+
+        switch (TRB_TYPE(*trb)) {
+        case TR_DATA:
+            if ((!(trb->control & TRB_TR_DIR)) != (!in_xfer)) {
+                fprintf(stderr, "xhci: data direction mismatch for TR_DATA\n");
+                xhci_die(xhci);
+                return transferred;
+            }
+            /* fallthrough */
+        case TR_NORMAL:
+        case TR_ISOCH:
+            addr = xhci_mask64(trb->parameter);
+            chunk = trb->status & 0x1ffff;
+            if (chunk > left) {
+                chunk = left;
+                shortpkt = 1;
+            }
+            if (in_xfer || out_xfer) {
+                if (trb->control & TRB_TR_IDT) {
+                    uint64_t idata;
+                    if (chunk > 8 || in_xfer) {
+                        fprintf(stderr, "xhci: invalid immediate data TRB\n");
+                        xhci_die(xhci);
+                        return transferred;
+                    }
+                    idata = le64_to_cpu(trb->parameter);
+                    memcpy(data, &idata, chunk);
+                } else {
+                    DPRINTF("xhci_xfer_data: r/w(%d) %d bytes at "
+                            TARGET_FMT_plx "\n", in_xfer, chunk, addr);
+                    if (in_xfer) {
+                        cpu_physical_memory_write(addr, data, chunk);
+                    } else {
+                        cpu_physical_memory_read(addr, data, chunk);
+                    }
+#ifdef DEBUG_DATA
+                    unsigned int count = chunk;
+                    int i;
+                    if (count > 16) {
+                        count = 16;
+                    }
+                    DPRINTF(" ::");
+                    for (i = 0; i < count; i++) {
+                        DPRINTF(" %02x", data[i]);
+                    }
+                    DPRINTF("\n");
+#endif
+                }
+            }
+            left -= chunk;
+            data += chunk;
+            edtla += chunk;
+            transferred += chunk;
+            break;
+        case TR_STATUS:
+            reported = 0;
+            shortpkt = 0;
+            break;
+        }
+
+        if (report && !reported && (trb->control & TRB_TR_IOC ||
+            (shortpkt && (trb->control & TRB_TR_ISP)))) {
+            event.slotid = xfer->slotid;
+            event.epid = xfer->epid;
+            event.length = (trb->status & 0x1ffff) - chunk;
+            event.flags = 0;
+            event.ptr = trb->addr;
+            if (xfer->status == CC_SUCCESS) {
+                event.ccode = shortpkt ? CC_SHORT_PACKET : CC_SUCCESS;
+            } else {
+                event.ccode = xfer->status;
+            }
+            if (TRB_TYPE(*trb) == TR_EVDATA) {
+                event.ptr = trb->parameter;
+                event.flags |= TRB_EV_ED;
+                event.length = edtla & 0xffffff;
+                DPRINTF("xhci_xfer_data: EDTLA=%d\n", event.length);
+                edtla = 0;
+            }
+            xhci_event(xhci, &event);
+            reported = 1;
+        }
+    }
+    return transferred;
+}
+
+static void xhci_stall_ep(XHCITransfer *xfer)
+{
+    XHCIState *xhci = xfer->xhci;
+    XHCISlot *slot = &xhci->slots[xfer->slotid-1];
+    XHCIEPContext *epctx = slot->eps[xfer->epid-1];
+
+    epctx->ring.dequeue = xfer->trbs[0].addr;
+    epctx->ring.ccs = xfer->trbs[0].ccs;
+    xhci_set_ep_state(xhci, epctx, EP_HALTED);
+    DPRINTF("xhci: stalled slot %d ep %d\n", xfer->slotid, xfer->epid);
+    DPRINTF("xhci: will continue at "TARGET_FMT_plx"\n", epctx->ring.dequeue);
+}
+
+static int xhci_submit(XHCIState *xhci, XHCITransfer *xfer,
+                       XHCIEPContext *epctx);
+
+static void xhci_bg_update(XHCIState *xhci, XHCIEPContext *epctx)
+{
+    if (epctx->bg_updating) {
+        return;
+    }
+    DPRINTF("xhci_bg_update(%p, %p)\n", xhci, epctx);
+    assert(epctx->has_bg);
+    DPRINTF("xhci: fg=%d bg=%d\n", epctx->comp_xfer, epctx->next_bg);
+    epctx->bg_updating = 1;
+    while (epctx->transfers[epctx->comp_xfer].backgrounded &&
+           epctx->bg_transfers[epctx->next_bg].complete) {
+        XHCITransfer *fg = &epctx->transfers[epctx->comp_xfer];
+        XHCITransfer *bg = &epctx->bg_transfers[epctx->next_bg];
+#if 0
+        DPRINTF("xhci: completing fg %d from bg %d.%d (stat: %d)\n",
+                epctx->comp_xfer, epctx->next_bg, bg->cur_pkt,
+                bg->usbxfer->iso_packet_desc[bg->cur_pkt].status
+               );
+#endif
+        assert(epctx->type == ET_ISO_IN);
+        assert(bg->iso_xfer);
+        assert(bg->in_xfer);
+        uint8_t *p = bg->data + bg->cur_pkt * bg->pktsize;
+#if 0
+        int len = bg->usbxfer->iso_packet_desc[bg->cur_pkt].actual_length;
+        fg->status = libusb_to_ccode(bg->usbxfer->iso_packet_desc[bg->cur_pkt].status);
+#else
+        int len = 0;
+        FIXME();
+#endif
+        fg->complete = 1;
+        fg->backgrounded = 0;
+
+        if (fg->status == CC_STALL_ERROR) {
+            xhci_stall_ep(fg);
+        }
+
+        xhci_xfer_data(fg, p, len, 1, 0, 1);
+
+        epctx->comp_xfer++;
+        if (epctx->comp_xfer == TD_QUEUE) {
+            epctx->comp_xfer = 0;
+        }
+        DPRINTF("next fg xfer: %d\n", epctx->comp_xfer);
+        bg->cur_pkt++;
+        if (bg->cur_pkt == bg->pkts) {
+            bg->complete = 0;
+            if (xhci_submit(xhci, bg, epctx) < 0) {
+                fprintf(stderr, "xhci: bg resubmit failed\n");
+            }
+            epctx->next_bg++;
+            if (epctx->next_bg == BG_XFERS) {
+                epctx->next_bg = 0;
+            }
+            DPRINTF("next bg xfer: %d\n", epctx->next_bg);
+
+        xhci_kick_ep(xhci, fg->slotid, fg->epid);
+        }
+    }
+    epctx->bg_updating = 0;
+}
+
+#if 0
+static void xhci_xfer_cb(struct libusb_transfer *transfer)
+{
+    XHCIState *xhci;
+    XHCITransfer *xfer;
+
+    xfer = (XHCITransfer *)transfer->user_data;
+    xhci = xfer->xhci;
+
+    DPRINTF("xhci_xfer_cb(slot=%d, ep=%d, status=%d)\n", xfer->slotid,
+            xfer->epid, transfer->status);
+
+    assert(xfer->slotid >= 1 && xfer->slotid <= MAXSLOTS);
+    assert(xfer->epid >= 1 && xfer->epid <= 31);
+
+    if (xfer->cancelled) {
+        DPRINTF("xhci: transfer cancelled, not reporting anything\n");
+        xfer->running = 0;
+        return;
+    }
+
+    XHCIEPContext *epctx;
+    XHCISlot *slot;
+    slot = &xhci->slots[xfer->slotid-1];
+    assert(slot->eps[xfer->epid-1]);
+    epctx = slot->eps[xfer->epid-1];
+
+    if (xfer->bg_xfer) {
+        DPRINTF("xhci: background transfer, updating\n");
+        xfer->complete = 1;
+        xfer->running = 0;
+        xhci_bg_update(xhci, epctx);
+        return;
+    }
+
+    if (xfer->iso_xfer) {
+        transfer->status = transfer->iso_packet_desc[0].status;
+        transfer->actual_length = transfer->iso_packet_desc[0].actual_length;
+    }
+
+    xfer->status = libusb_to_ccode(transfer->status);
+
+    xfer->complete = 1;
+    xfer->running = 0;
+
+    if (transfer->status == LIBUSB_TRANSFER_STALL)
+        xhci_stall_ep(xhci, epctx, xfer);
+
+    DPRINTF("xhci: transfer actual length = %d\n", transfer->actual_length);
+
+    if (xfer->in_xfer) {
+        if (xfer->epid == 1) {
+            xhci_xfer_data(xhci, xfer, xfer->data + 8,
+                           transfer->actual_length, 1, 0, 1);
+        } else {
+            xhci_xfer_data(xhci, xfer, xfer->data,
+                           transfer->actual_length, 1, 0, 1);
+        }
+    } else {
+        xhci_xfer_data(xhci, xfer, NULL, transfer->actual_length, 0, 0, 1);
+    }
+
+    xhci_kick_ep(xhci, xfer->slotid, xfer->epid);
+}
+
+static int xhci_hle_control(XHCIState *xhci, XHCITransfer *xfer,
+                            uint8_t bmRequestType, uint8_t bRequest,
+                            uint16_t wValue, uint16_t wIndex, uint16_t wLength)
+{
+    uint16_t type_req = (bmRequestType << 8) | bRequest;
+
+    switch (type_req) {
+        case 0x0000 | USB_REQ_SET_CONFIGURATION:
+            DPRINTF("xhci: HLE switch configuration\n");
+            return xhci_switch_config(xhci, xfer->slotid, wValue) == 0;
+        case 0x0100 | USB_REQ_SET_INTERFACE:
+            DPRINTF("xhci: HLE set interface altsetting\n");
+            return xhci_set_iface_alt(xhci, xfer->slotid, wIndex, wValue) == 0;
+        case 0x0200 | USB_REQ_CLEAR_FEATURE:
+            if (wValue == 0) { // endpoint halt
+                DPRINTF("xhci: HLE clear halt\n");
+                return xhci_clear_halt(xhci, xfer->slotid, wIndex);
+            }
+        case 0x0000 | USB_REQ_SET_ADDRESS:
+            fprintf(stderr, "xhci: warn: illegal SET_ADDRESS request\n");
+            return 0;
+        default:
+            return 0;
+    }
+}
+#endif
+
+static int xhci_setup_packet(XHCITransfer *xfer, XHCIPort *port, int ep)
+{
+    usb_packet_setup(&xfer->packet,
+                     xfer->in_xfer ? USB_TOKEN_IN : USB_TOKEN_OUT,
+                     xfer->xhci->slots[xfer->slotid-1].devaddr,
+                     ep & 0x7f);
+    usb_packet_addbuf(&xfer->packet, xfer->data, xfer->data_length);
+    DPRINTF("xhci: setup packet pid 0x%x addr %d ep %d\n",
+            xfer->packet.pid, xfer->packet.devaddr, xfer->packet.devep);
+    return 0;
+}
+
+static int xhci_complete_packet(XHCITransfer *xfer, int ret)
+{
+    if (ret == USB_RET_ASYNC) {
+        xfer->running = 1;
+        xfer->complete = 0;
+        xfer->cancelled = 0;
+        return 0;
+    } else {
+        xfer->running = 0;
+        xfer->complete = 1;
+    }
+
+    if (ret >= 0) {
+        xfer->status = CC_SUCCESS;
+        xhci_xfer_data(xfer, xfer->data, ret, xfer->in_xfer, 0, 1);
+        return 0;
+    }
+
+    /* error */
+    switch (ret) {
+    case USB_RET_NODEV:
+        xfer->status = CC_USB_TRANSACTION_ERROR;
+        xhci_xfer_data(xfer, xfer->data, 0, xfer->in_xfer, 0, 1);
+        xhci_stall_ep(xfer);
+        break;
+    case USB_RET_STALL:
+        xfer->status = CC_STALL_ERROR;
+        xhci_xfer_data(xfer, xfer->data, 0, xfer->in_xfer, 0, 1);
+        xhci_stall_ep(xfer);
+        break;
+    default:
+        fprintf(stderr, "%s: FIXME: ret = %d\n", __FUNCTION__, ret);
+        FIXME();
+    }
+    return 0;
+}
+
+static int xhci_fire_ctl_transfer(XHCIState *xhci, XHCITransfer *xfer)
+{
+    XHCITRB *trb_setup, *trb_status;
+    uint8_t bmRequestType, bRequest;
+    uint16_t wValue, wLength, wIndex;
+    XHCIPort *port;
+    USBDevice *dev;
+    int ret;
+
+    DPRINTF("xhci_fire_ctl_transfer(slot=%d)\n", xfer->slotid);
+
+    trb_setup = &xfer->trbs[0];
+    trb_status = &xfer->trbs[xfer->trb_count-1];
+
+    /* at most one Event Data TRB allowed after STATUS */
+    if (TRB_TYPE(*trb_status) == TR_EVDATA && xfer->trb_count > 2) {
+        trb_status--;
+    }
+
+    /* do some sanity checks */
+    if (TRB_TYPE(*trb_setup) != TR_SETUP) {
+        fprintf(stderr, "xhci: ep0 first TD not SETUP: %d\n",
+                TRB_TYPE(*trb_setup));
+        return -1;
+    }
+    if (TRB_TYPE(*trb_status) != TR_STATUS) {
+        fprintf(stderr, "xhci: ep0 last TD not STATUS: %d\n",
+                TRB_TYPE(*trb_status));
+        return -1;
+    }
+    if (!(trb_setup->control & TRB_TR_IDT)) {
+        fprintf(stderr, "xhci: Setup TRB doesn't have IDT set\n");
+        return -1;
+    }
+    if ((trb_setup->status & 0x1ffff) != 8) {
+        fprintf(stderr, "xhci: Setup TRB has bad length (%d)\n",
+                (trb_setup->status & 0x1ffff));
+        return -1;
+    }
+
+    bmRequestType = trb_setup->parameter;
+    bRequest = trb_setup->parameter >> 8;
+    wValue = trb_setup->parameter >> 16;
+    wIndex = trb_setup->parameter >> 32;
+    wLength = trb_setup->parameter >> 48;
+
+    if (xfer->data && xfer->data_alloced < wLength) {
+        xfer->data_alloced = 0;
+        g_free(xfer->data);
+        xfer->data = NULL;
+    }
+    if (!xfer->data) {
+        DPRINTF("xhci: alloc %d bytes data\n", wLength);
+        xfer->data = g_malloc(wLength+1);
+        xfer->data_alloced = wLength;
+    }
+    xfer->data_length = wLength;
+
+    port = &xhci->ports[xhci->slots[xfer->slotid-1].port-1];
+    dev = port->port.dev;
+    if (!dev) {
+        fprintf(stderr, "xhci: slot %d port %d has no device\n", xfer->slotid,
+                xhci->slots[xfer->slotid-1].port);
+        return -1;
+    }
+
+    xfer->in_xfer = bmRequestType & USB_DIR_IN;
+    xfer->iso_xfer = false;
+
+    xhci_setup_packet(xfer, port, 0);
+    if (!xfer->in_xfer) {
+        xhci_xfer_data(xfer, xfer->data, wLength, 0, 1, 0);
+    }
+    ret = usb_device_handle_control(dev, &xfer->packet,
+                                    (bmRequestType << 8) | bRequest,
+                                    wValue, wIndex, wLength, xfer->data);
+
+    xhci_complete_packet(xfer, ret);
+    if (!xfer->running) {
+        xhci_kick_ep(xhci, xfer->slotid, xfer->epid);
+    }
+    return 0;
+}
+
+static int xhci_submit(XHCIState *xhci, XHCITransfer *xfer, XHCIEPContext *epctx)
+{
+    XHCIPort *port;
+    USBDevice *dev;
+    int ret;
+
+    DPRINTF("xhci_submit(slotid=%d,epid=%d)\n", xfer->slotid, xfer->epid);
+    uint8_t ep = xfer->epid>>1;
+
+    xfer->in_xfer = epctx->type>>2;
+    if (xfer->in_xfer) {
+        ep |= 0x80;
+    }
+
+    if (xfer->data && xfer->data_alloced < xfer->data_length) {
+        xfer->data_alloced = 0;
+        g_free(xfer->data);
+        xfer->data = NULL;
+    }
+    if (!xfer->data && xfer->data_length) {
+        DPRINTF("xhci: alloc %d bytes data\n", xfer->data_length);
+        xfer->data = g_malloc(xfer->data_length);
+        xfer->data_alloced = xfer->data_length;
+    }
+    if (epctx->type == ET_ISO_IN || epctx->type == ET_ISO_OUT) {
+        if (!xfer->bg_xfer) {
+            xfer->pkts = 1;
+        }
+    } else {
+        xfer->pkts = 0;
+    }
+
+    port = &xhci->ports[xhci->slots[xfer->slotid-1].port-1];
+    dev = port->port.dev;
+    if (!dev) {
+        fprintf(stderr, "xhci: slot %d port %d has no device\n", xfer->slotid,
+                xhci->slots[xfer->slotid-1].port);
+        return -1;
+    }
+
+    xhci_setup_packet(xfer, port, ep);
+
+    switch(epctx->type) {
+    case ET_INTR_OUT:
+    case ET_INTR_IN:
+    case ET_BULK_OUT:
+    case ET_BULK_IN:
+        break;
+    case ET_ISO_OUT:
+    case ET_ISO_IN:
+        FIXME();
+        break;
+    default:
+        fprintf(stderr, "xhci: unknown or unhandled EP type %d (ep %02x)\n",
+                epctx->type, ep);
+        return -1;
+    }
+
+    if (!xfer->in_xfer) {
+        xhci_xfer_data(xfer, xfer->data, xfer->data_length, 0, 1, 0);
+    }
+    ret = usb_handle_packet(dev, &xfer->packet);
+
+    xhci_complete_packet(xfer, ret);
+    if (!xfer->running) {
+        xhci_kick_ep(xhci, xfer->slotid, xfer->epid);
+    }
+    return 0;
+}
+
+static int xhci_fire_transfer(XHCIState *xhci, XHCITransfer *xfer, XHCIEPContext *epctx)
+{
+    int i;
+    unsigned int length = 0;
+    XHCITRB *trb;
+
+    DPRINTF("xhci_fire_transfer(slotid=%d,epid=%d)\n", xfer->slotid, xfer->epid);
+
+    for (i = 0; i < xfer->trb_count; i++) {
+        trb = &xfer->trbs[i];
+        if (TRB_TYPE(*trb) == TR_NORMAL || TRB_TYPE(*trb) == TR_ISOCH) {
+            length += trb->status & 0x1ffff;
+        }
+    }
+    DPRINTF("xhci: total TD length=%d\n", length);
+
+    if (!epctx->has_bg) {
+        xfer->data_length = length;
+        xfer->backgrounded = 0;
+        return xhci_submit(xhci, xfer, epctx);
+    } else {
+        if (!epctx->bg_running) {
+            for (i = 0; i < BG_XFERS; i++) {
+                XHCITransfer *t = &epctx->bg_transfers[i];
+                t->xhci = xhci;
+                t->epid = xfer->epid;
+                t->slotid = xfer->slotid;
+                t->pkts = BG_PKTS;
+                t->pktsize = epctx->max_psize;
+                t->data_length = t->pkts * t->pktsize;
+                t->bg_xfer = 1;
+                if (xhci_submit(xhci, t, epctx) < 0) {
+                    fprintf(stderr, "xhci: bg submit failed\n");
+                    return -1;
+                }
+            }
+            epctx->bg_running = 1;
+        }
+        xfer->backgrounded = 1;
+        xhci_bg_update(xhci, epctx);
+        return 0;
+    }
+}
+
+static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid, unsigned int epid)
+{
+    XHCIEPContext *epctx;
+    int length;
+    int i;
+
+    assert(slotid >= 1 && slotid <= MAXSLOTS);
+    assert(epid >= 1 && epid <= 31);
+    DPRINTF("xhci_kick_ep(%d, %d)\n", slotid, epid);
+
+    if (!xhci->slots[slotid-1].enabled) {
+        fprintf(stderr, "xhci: xhci_kick_ep for disabled slot %d\n", slotid);
+        return;
+    }
+    epctx = xhci->slots[slotid-1].eps[epid-1];
+    if (!epctx) {
+        fprintf(stderr, "xhci: xhci_kick_ep for disabled endpoint %d,%d\n",
+                epid, slotid);
+        return;
+    }
+
+    if (epctx->state == EP_HALTED) {
+        DPRINTF("xhci: ep halted, not running schedule\n");
+        return;
+    }
+
+    xhci_set_ep_state(xhci, epctx, EP_RUNNING);
+
+    while (1) {
+        XHCITransfer *xfer = &epctx->transfers[epctx->next_xfer];
+        if (xfer->running || xfer->backgrounded) {
+            DPRINTF("xhci: ep is busy\n");
+            break;
+        }
+        length = xhci_ring_chain_length(xhci, &epctx->ring);
+        if (length < 0) {
+            DPRINTF("xhci: incomplete TD (%d TRBs)\n", -length);
+            break;
+        } else if (length == 0) {
+            break;
+        }
+        DPRINTF("xhci: fetching %d-TRB TD\n", length);
+        if (xfer->trbs && xfer->trb_alloced < length) {
+            xfer->trb_count = 0;
+            xfer->trb_alloced = 0;
+            g_free(xfer->trbs);
+            xfer->trbs = NULL;
+        }
+        if (!xfer->trbs) {
+            xfer->trbs = g_malloc(sizeof(XHCITRB) * length);
+            xfer->trb_alloced = length;
+        }
+        xfer->trb_count = length;
+
+        for (i = 0; i < length; i++) {
+            assert(xhci_ring_fetch(xhci, &epctx->ring, &xfer->trbs[i], NULL));
+        }
+        xfer->xhci = xhci;
+        xfer->epid = epid;
+        xfer->slotid = slotid;
+
+        if (epid == 1) {
+            if (xhci_fire_ctl_transfer(xhci, xfer) >= 0) {
+                epctx->next_xfer = (epctx->next_xfer + 1) % TD_QUEUE;
+            } else {
+                fprintf(stderr, "xhci: error firing CTL transfer\n");
+            }
+        } else {
+            if (xhci_fire_transfer(xhci, xfer, epctx) >= 0) {
+                epctx->next_xfer = (epctx->next_xfer + 1) % TD_QUEUE;
+            } else {
+                fprintf(stderr, "xhci: error firing data transfer\n");
+            }
+        }
+
+        /*
+         * Qemu usb can't handle multiple in-flight xfers.
+         * Also xfers might be finished here already,
+         * possibly with an error.  Stop here for now.
+         */
+        break;
+    }
+}
+
+static TRBCCode xhci_enable_slot(XHCIState *xhci, unsigned int slotid)
+{
+    assert(slotid >= 1 && slotid <= MAXSLOTS);
+    DPRINTF("xhci_enable_slot(%d)\n", slotid);
+    xhci->slots[slotid-1].enabled = 1;
+    xhci->slots[slotid-1].port = 0;
+    memset(xhci->slots[slotid-1].eps, 0, sizeof(XHCIEPContext*)*31);
+
+    return CC_SUCCESS;
+}
+
+static TRBCCode xhci_disable_slot(XHCIState *xhci, unsigned int slotid)
+{
+    int i;
+
+    assert(slotid >= 1 && slotid <= MAXSLOTS);
+    DPRINTF("xhci_disable_slot(%d)\n", slotid);
+
+    for (i = 1; i <= 31; i++) {
+        if (xhci->slots[slotid-1].eps[i-1]) {
+            xhci_disable_ep(xhci, slotid, i);
+        }
+    }
+
+    xhci->slots[slotid-1].enabled = 0;
+    return CC_SUCCESS;
+}
+
+static TRBCCode xhci_address_slot(XHCIState *xhci, unsigned int slotid,
+                                  uint64_t pictx, bool bsr)
+{
+    XHCISlot *slot;
+    USBDevice *dev;
+    target_phys_addr_t ictx, octx, dcbaap;
+    uint64_t poctx;
+    uint32_t ictl_ctx[2];
+    uint32_t slot_ctx[4];
+    uint32_t ep0_ctx[5];
+    unsigned int port;
+    int i;
+    TRBCCode res;
+
+    assert(slotid >= 1 && slotid <= MAXSLOTS);
+    DPRINTF("xhci_address_slot(%d)\n", slotid);
+
+    dcbaap = xhci_addr64(xhci->dcbaap_low, xhci->dcbaap_high);
+    cpu_physical_memory_read(dcbaap + 8*slotid,
+                             (uint8_t *) &poctx, sizeof(poctx));
+    ictx = xhci_mask64(pictx);
+    octx = xhci_mask64(le64_to_cpu(poctx));
+
+    DPRINTF("xhci: input context at "TARGET_FMT_plx"\n", ictx);
+    DPRINTF("xhci: output context at "TARGET_FMT_plx"\n", octx);
+
+    cpu_physical_memory_read(ictx, (uint8_t *) ictl_ctx, sizeof(ictl_ctx));
+
+    if (ictl_ctx[0] != 0x0 || ictl_ctx[1] != 0x3) {
+        fprintf(stderr, "xhci: invalid input context control %08x %08x\n",
+                ictl_ctx[0], ictl_ctx[1]);
+        return CC_TRB_ERROR;
+    }
+
+    cpu_physical_memory_read(ictx+32, (uint8_t *) slot_ctx, sizeof(slot_ctx));
+    cpu_physical_memory_read(ictx+64, (uint8_t *) ep0_ctx, sizeof(ep0_ctx));
+
+    DPRINTF("xhci: input slot context: %08x %08x %08x %08x\n",
+            slot_ctx[0], slot_ctx[1], slot_ctx[2], slot_ctx[3]);
+
+    DPRINTF("xhci: input ep0 context: %08x %08x %08x %08x %08x\n",
+            ep0_ctx[0], ep0_ctx[1], ep0_ctx[2], ep0_ctx[3], ep0_ctx[4]);
+
+    port = (slot_ctx[1]>>16) & 0xFF;
+    dev = xhci->ports[port-1].port.dev;
+
+    if (port < 1 || port > MAXPORTS) {
+        fprintf(stderr, "xhci: bad port %d\n", port);
+        return CC_TRB_ERROR;
+    } else if (!dev) {
+        fprintf(stderr, "xhci: port %d not connected\n", port);
+        return CC_USB_TRANSACTION_ERROR;
+    }
+
+    for (i = 0; i < MAXSLOTS; i++) {
+        if (xhci->slots[i].port == port) {
+            fprintf(stderr, "xhci: port %d already assigned to slot %d\n",
+                    port, i+1);
+            return CC_TRB_ERROR;
+        }
+    }
+
+    slot = &xhci->slots[slotid-1];
+    slot->port = port;
+    slot->ctx = octx;
+
+    if (bsr) {
+        slot_ctx[3] = SLOT_DEFAULT << SLOT_STATE_SHIFT;
+    } else {
+        slot->devaddr = xhci->devaddr++;
+        slot_ctx[3] = (SLOT_ADDRESSED << SLOT_STATE_SHIFT) | slot->devaddr;
+        DPRINTF("xhci: device address is %d\n", slot->devaddr);
+        usb_device_handle_control(dev, NULL,
+                                  DeviceOutRequest | USB_REQ_SET_ADDRESS,
+                                  slot->devaddr, 0, 0, NULL);
+    }
+
+    res = xhci_enable_ep(xhci, slotid, 1, octx+32, ep0_ctx);
+
+    DPRINTF("xhci: output slot context: %08x %08x %08x %08x\n",
+            slot_ctx[0], slot_ctx[1], slot_ctx[2], slot_ctx[3]);
+    DPRINTF("xhci: output ep0 context: %08x %08x %08x %08x %08x\n",
+            ep0_ctx[0], ep0_ctx[1], ep0_ctx[2], ep0_ctx[3], ep0_ctx[4]);
+
+    cpu_physical_memory_write(octx, (uint8_t *) slot_ctx, sizeof(slot_ctx));
+    cpu_physical_memory_write(octx+32, (uint8_t *) ep0_ctx, sizeof(ep0_ctx));
+
+    return res;
+}
+
+
+static TRBCCode xhci_configure_slot(XHCIState *xhci, unsigned int slotid,
+                                  uint64_t pictx, bool dc)
+{
+    target_phys_addr_t ictx, octx;
+    uint32_t ictl_ctx[2];
+    uint32_t slot_ctx[4];
+    uint32_t islot_ctx[4];
+    uint32_t ep_ctx[5];
+    int i;
+    TRBCCode res;
+
+    assert(slotid >= 1 && slotid <= MAXSLOTS);
+    DPRINTF("xhci_configure_slot(%d)\n", slotid);
+
+    ictx = xhci_mask64(pictx);
+    octx = xhci->slots[slotid-1].ctx;
+
+    DPRINTF("xhci: input context at "TARGET_FMT_plx"\n", ictx);
+    DPRINTF("xhci: output context at "TARGET_FMT_plx"\n", octx);
+
+    if (dc) {
+        for (i = 2; i <= 31; i++) {
+            if (xhci->slots[slotid-1].eps[i-1]) {
+                xhci_disable_ep(xhci, slotid, i);
+            }
+        }
+
+        cpu_physical_memory_read(octx, (uint8_t *) slot_ctx, sizeof(slot_ctx));
+        slot_ctx[3] &= ~(SLOT_STATE_MASK << SLOT_STATE_SHIFT);
+        slot_ctx[3] |= SLOT_ADDRESSED << SLOT_STATE_SHIFT;
+        DPRINTF("xhci: output slot context: %08x %08x %08x %08x\n",
+                slot_ctx[0], slot_ctx[1], slot_ctx[2], slot_ctx[3]);
+        cpu_physical_memory_write(octx, (uint8_t *) slot_ctx, sizeof(slot_ctx));
+
+        return CC_SUCCESS;
+    }
+
+    cpu_physical_memory_read(ictx, (uint8_t *) ictl_ctx, sizeof(ictl_ctx));
+
+    if ((ictl_ctx[0] & 0x3) != 0x0 || (ictl_ctx[1] & 0x3) != 0x1) {
+        fprintf(stderr, "xhci: invalid input context control %08x %08x\n",
+                ictl_ctx[0], ictl_ctx[1]);
+        return CC_TRB_ERROR;
+    }
+
+    cpu_physical_memory_read(ictx+32, (uint8_t *) islot_ctx, sizeof(islot_ctx));
+    cpu_physical_memory_read(octx, (uint8_t *) slot_ctx, sizeof(slot_ctx));
+
+    if (SLOT_STATE(slot_ctx[3]) < SLOT_ADDRESSED) {
+        fprintf(stderr, "xhci: invalid slot state %08x\n", slot_ctx[3]);
+        return CC_CONTEXT_STATE_ERROR;
+    }
+
+    for (i = 2; i <= 31; i++) {
+        if (ictl_ctx[0] & (1<<i)) {
+            xhci_disable_ep(xhci, slotid, i);
+        }
+        if (ictl_ctx[1] & (1<<i)) {
+            cpu_physical_memory_read(ictx+32+(32*i),
+                                     (uint8_t *) ep_ctx, sizeof(ep_ctx));
+            DPRINTF("xhci: input ep%d.%d context: %08x %08x %08x %08x %08x\n",
+                    i/2, i%2, ep_ctx[0], ep_ctx[1], ep_ctx[2],
+                    ep_ctx[3], ep_ctx[4]);
+            xhci_disable_ep(xhci, slotid, i);
+            res = xhci_enable_ep(xhci, slotid, i, octx+(32*i), ep_ctx);
+            if (res != CC_SUCCESS) {
+                return res;
+            }
+            DPRINTF("xhci: output ep%d.%d context: %08x %08x %08x %08x %08x\n",
+                    i/2, i%2, ep_ctx[0], ep_ctx[1], ep_ctx[2],
+                    ep_ctx[3], ep_ctx[4]);
+            cpu_physical_memory_write(octx+(32*i),
+                                      (uint8_t *) ep_ctx, sizeof(ep_ctx));
+        }
+    }
+
+    slot_ctx[3] &= ~(SLOT_STATE_MASK << SLOT_STATE_SHIFT);
+    slot_ctx[3] |= SLOT_CONFIGURED << SLOT_STATE_SHIFT;
+    slot_ctx[0] &= ~(SLOT_CONTEXT_ENTRIES_MASK << SLOT_CONTEXT_ENTRIES_SHIFT);
+    slot_ctx[0] |= islot_ctx[0] & (SLOT_CONTEXT_ENTRIES_MASK <<
+                                   SLOT_CONTEXT_ENTRIES_SHIFT);
+    DPRINTF("xhci: output slot context: %08x %08x %08x %08x\n",
+            slot_ctx[0], slot_ctx[1], slot_ctx[2], slot_ctx[3]);
+
+    cpu_physical_memory_write(octx, (uint8_t *) slot_ctx, sizeof(slot_ctx));
+
+    return CC_SUCCESS;
+}
+
+
+static TRBCCode xhci_evaluate_slot(XHCIState *xhci, unsigned int slotid,
+                                   uint64_t pictx)
+{
+    target_phys_addr_t ictx, octx;
+    uint32_t ictl_ctx[2];
+    uint32_t iep0_ctx[5];
+    uint32_t ep0_ctx[5];
+    uint32_t islot_ctx[4];
+    uint32_t slot_ctx[4];
+
+    assert(slotid >= 1 && slotid <= MAXSLOTS);
+    DPRINTF("xhci_evaluate_slot(%d)\n", slotid);
+
+    ictx = xhci_mask64(pictx);
+    octx = xhci->slots[slotid-1].ctx;
+
+    DPRINTF("xhci: input context at "TARGET_FMT_plx"\n", ictx);
+    DPRINTF("xhci: output context at "TARGET_FMT_plx"\n", octx);
+
+    cpu_physical_memory_read(ictx, (uint8_t *) ictl_ctx, sizeof(ictl_ctx));
+
+    if (ictl_ctx[0] != 0x0 || ictl_ctx[1] & ~0x3) {
+        fprintf(stderr, "xhci: invalid input context control %08x %08x\n",
+                ictl_ctx[0], ictl_ctx[1]);
+        return CC_TRB_ERROR;
+    }
+
+    if (ictl_ctx[1] & 0x1) {
+        cpu_physical_memory_read(ictx+32,
+                                 (uint8_t *) islot_ctx, sizeof(islot_ctx));
+
+        DPRINTF("xhci: input slot context: %08x %08x %08x %08x\n",
+                islot_ctx[0], islot_ctx[1], islot_ctx[2], islot_ctx[3]);
+
+        cpu_physical_memory_read(octx, (uint8_t *) slot_ctx, sizeof(slot_ctx));
+
+        slot_ctx[1] &= ~0xFFFF; /* max exit latency */
+        slot_ctx[1] |= islot_ctx[1] & 0xFFFF;
+        slot_ctx[2] &= ~0xFF00000; /* interrupter target */
+        slot_ctx[2] |= islot_ctx[2] & 0xFF000000;
+
+        DPRINTF("xhci: output slot context: %08x %08x %08x %08x\n",
+                slot_ctx[0], slot_ctx[1], slot_ctx[2], slot_ctx[3]);
+
+        cpu_physical_memory_write(octx, (uint8_t *) slot_ctx, sizeof(slot_ctx));
+    }
+
+    if (ictl_ctx[1] & 0x2) {
+        cpu_physical_memory_read(ictx+64,
+                                 (uint8_t *) iep0_ctx, sizeof(iep0_ctx));
+
+        DPRINTF("xhci: input ep0 context: %08x %08x %08x %08x %08x\n",
+                iep0_ctx[0], iep0_ctx[1], iep0_ctx[2],
+                iep0_ctx[3], iep0_ctx[4]);
+
+        cpu_physical_memory_read(octx+32, (uint8_t *) ep0_ctx, sizeof(ep0_ctx));
+
+        ep0_ctx[1] &= ~0xFFFF0000; /* max packet size*/
+        ep0_ctx[1] |= iep0_ctx[1] & 0xFFFF0000;
+
+        DPRINTF("xhci: output ep0 context: %08x %08x %08x %08x %08x\n",
+                ep0_ctx[0], ep0_ctx[1], ep0_ctx[2], ep0_ctx[3], ep0_ctx[4]);
+
+        cpu_physical_memory_write(octx+32,
+                                  (uint8_t *) ep0_ctx, sizeof(ep0_ctx));
+    }
+
+    return CC_SUCCESS;
+}
+
+static TRBCCode xhci_reset_slot(XHCIState *xhci, unsigned int slotid)
+{
+    uint32_t slot_ctx[4];
+    target_phys_addr_t octx;
+    int i;
+
+    assert(slotid >= 1 && slotid <= MAXSLOTS);
+    DPRINTF("xhci_reset_slot(%d)\n", slotid);
+
+    octx = xhci->slots[slotid-1].ctx;
+
+    DPRINTF("xhci: output context at "TARGET_FMT_plx"\n", octx);
+
+    for (i = 2; i <= 31; i++) {
+        if (xhci->slots[slotid-1].eps[i-1]) {
+            xhci_disable_ep(xhci, slotid, i);
+        }
+    }
+
+    cpu_physical_memory_read(octx, (uint8_t *) slot_ctx, sizeof(slot_ctx));
+    slot_ctx[3] &= ~(SLOT_STATE_MASK << SLOT_STATE_SHIFT);
+    slot_ctx[3] |= SLOT_DEFAULT << SLOT_STATE_SHIFT;
+    DPRINTF("xhci: output slot context: %08x %08x %08x %08x\n",
+            slot_ctx[0], slot_ctx[1], slot_ctx[2], slot_ctx[3]);
+    cpu_physical_memory_write(octx, (uint8_t *) slot_ctx, sizeof(slot_ctx));
+
+    return CC_SUCCESS;
+}
+
+static unsigned int xhci_get_slot(XHCIState *xhci, XHCIEvent *event, XHCITRB *trb)
+{
+    unsigned int slotid;
+    slotid = (trb->control >> TRB_CR_SLOTID_SHIFT) & TRB_CR_SLOTID_MASK;
+    if (slotid < 1 || slotid > MAXSLOTS) {
+        fprintf(stderr, "xhci: bad slot id %d\n", slotid);
+        event->ccode = CC_TRB_ERROR;
+        return 0;
+    } else if (!xhci->slots[slotid-1].enabled) {
+        fprintf(stderr, "xhci: slot id %d not enabled\n", slotid);
+        event->ccode = CC_SLOT_NOT_ENABLED_ERROR;
+        return 0;
+    }
+    return slotid;
+}
+
+static TRBCCode xhci_get_port_bandwidth(XHCIState *xhci, uint64_t pctx)
+{
+    target_phys_addr_t ctx;
+    uint8_t bw_ctx[MAXPORTS+1];
+
+    DPRINTF("xhci_get_port_bandwidth()\n");
+
+    ctx = xhci_mask64(pctx);
+
+    DPRINTF("xhci: bandwidth context at "TARGET_FMT_plx"\n", ctx);
+
+    /* TODO: actually implement real values here */
+    bw_ctx[0] = 0;
+    memset(&bw_ctx[1], 80, MAXPORTS); /* 80% */
+    cpu_physical_memory_write(ctx, bw_ctx, sizeof(bw_ctx));
+
+    return CC_SUCCESS;
+}
+
+static uint32_t rotl(uint32_t v, unsigned count)
+{
+    count &= 31;
+    return (v << count) | (v >> (32 - count));
+}
+
+
+static uint32_t xhci_nec_challenge(uint32_t hi, uint32_t lo)
+{
+    uint32_t val;
+    val = rotl(lo - 0x49434878, 32 - ((hi>>8) & 0x1F));
+    val += rotl(lo + 0x49434878, hi & 0x1F);
+    val -= rotl(hi ^ 0x49434878, (lo >> 16) & 0x1F);
+    return ~val;
+}
+
+static void xhci_via_challenge(uint64_t addr)
+{
+    uint32_t buf[8];
+    uint32_t obuf[8];
+    target_phys_addr_t paddr = xhci_mask64(addr);
+
+    cpu_physical_memory_read(paddr, (uint8_t *) &buf, 32);
+
+    memcpy(obuf, buf, sizeof(obuf));
+
+    if ((buf[0] & 0xff) == 2) {
+        obuf[0] = 0x49932000 + 0x54dc200 * buf[2] + 0x7429b578 * buf[3];
+        obuf[0] |=  (buf[2] * buf[3]) & 0xff;
+        obuf[1] = 0x0132bb37 + 0xe89 * buf[2] + 0xf09 * buf[3];
+        obuf[2] = 0x0066c2e9 + 0x2091 * buf[2] + 0x19bd * buf[3];
+        obuf[3] = 0xd5281342 + 0x2cc9691 * buf[2] + 0x2367662 * buf[3];
+        obuf[4] = 0x0123c75c + 0x1595 * buf[2] + 0x19ec * buf[3];
+        obuf[5] = 0x00f695de + 0x26fd * buf[2] + 0x3e9 * buf[3];
+        obuf[6] = obuf[2] ^ obuf[3] ^ 0x29472956;
+        obuf[7] = obuf[2] ^ obuf[3] ^ 0x65866593;
+    }
+
+    cpu_physical_memory_write(paddr, (uint8_t *) &obuf, 32);
+}
+
+static void xhci_process_commands(XHCIState *xhci)
+{
+    XHCITRB trb;
+    TRBType type;
+    XHCIEvent event = {ER_COMMAND_COMPLETE, CC_SUCCESS};
+    target_phys_addr_t addr;
+    unsigned int i, slotid = 0;
+
+    DPRINTF("xhci_process_commands()\n");
+    if (!xhci_running(xhci)) {
+        DPRINTF("xhci_process_commands() called while xHC stopped or paused\n");
+        return;
+    }
+
+    xhci->crcr_low |= CRCR_CRR;
+
+    while ((type = xhci_ring_fetch(xhci, &xhci->cmd_ring, &trb, &addr))) {
+        event.ptr = addr;
+        switch (type) {
+        case CR_ENABLE_SLOT:
+            for (i = 0; i < MAXSLOTS; i++) {
+                if (!xhci->slots[i].enabled) {
+                    break;
+                }
+            }
+            if (i >= MAXSLOTS) {
+                fprintf(stderr, "xhci: no device slots available\n");
+                event.ccode = CC_NO_SLOTS_ERROR;
+            } else {
+                slotid = i+1;
+                event.ccode = xhci_enable_slot(xhci, slotid);
+            }
+            break;
+        case CR_DISABLE_SLOT:
+            slotid = xhci_get_slot(xhci, &event, &trb);
+            if (slotid) {
+                event.ccode = xhci_disable_slot(xhci, slotid);
+            }
+            break;
+        case CR_ADDRESS_DEVICE:
+            slotid = xhci_get_slot(xhci, &event, &trb);
+            if (slotid) {
+                event.ccode = xhci_address_slot(xhci, slotid, trb.parameter,
+                                                trb.control & TRB_CR_BSR);
+            }
+            break;
+        case CR_CONFIGURE_ENDPOINT:
+            slotid = xhci_get_slot(xhci, &event, &trb);
+            if (slotid) {
+                event.ccode = xhci_configure_slot(xhci, slotid, trb.parameter,
+                                                  trb.control & TRB_CR_DC);
+            }
+            break;
+        case CR_EVALUATE_CONTEXT:
+            slotid = xhci_get_slot(xhci, &event, &trb);
+            if (slotid) {
+                event.ccode = xhci_evaluate_slot(xhci, slotid, trb.parameter);
+            }
+            break;
+        case CR_STOP_ENDPOINT:
+            slotid = xhci_get_slot(xhci, &event, &trb);
+            if (slotid) {
+                unsigned int epid = (trb.control >> TRB_CR_EPID_SHIFT)
+                    & TRB_CR_EPID_MASK;
+                event.ccode = xhci_stop_ep(xhci, slotid, epid);
+            }
+            break;
+        case CR_RESET_ENDPOINT:
+            slotid = xhci_get_slot(xhci, &event, &trb);
+            if (slotid) {
+                unsigned int epid = (trb.control >> TRB_CR_EPID_SHIFT)
+                    & TRB_CR_EPID_MASK;
+                event.ccode = xhci_reset_ep(xhci, slotid, epid);
+            }
+            break;
+        case CR_SET_TR_DEQUEUE:
+            slotid = xhci_get_slot(xhci, &event, &trb);
+            if (slotid) {
+                unsigned int epid = (trb.control >> TRB_CR_EPID_SHIFT)
+                    & TRB_CR_EPID_MASK;
+                event.ccode = xhci_set_ep_dequeue(xhci, slotid, epid,
+                                                  trb.parameter);
+            }
+            break;
+        case CR_RESET_DEVICE:
+            slotid = xhci_get_slot(xhci, &event, &trb);
+            if (slotid) {
+                event.ccode = xhci_reset_slot(xhci, slotid);
+            }
+            break;
+        case CR_GET_PORT_BANDWIDTH:
+            event.ccode = xhci_get_port_bandwidth(xhci, trb.parameter);
+            break;
+        case CR_VENDOR_VIA_CHALLENGE_RESPONSE:
+            xhci_via_challenge(trb.parameter);
+            break;
+        case CR_VENDOR_NEC_FIRMWARE_REVISION:
+            event.type = 48; /* NEC reply */
+            event.length = 0x3025;
+            break;
+        case CR_VENDOR_NEC_CHALLENGE_RESPONSE:
+        {
+            uint32_t chi = trb.parameter >> 32;
+            uint32_t clo = trb.parameter;
+            uint32_t val = xhci_nec_challenge(chi, clo);
+            event.length = val & 0xFFFF;
+            event.epid = val >> 16;
+            slotid = val >> 24;
+            event.type = 48; /* NEC reply */
+        }
+        break;
+        default:
+            fprintf(stderr, "xhci: unimplemented command %d\n", type);
+            event.ccode = CC_TRB_ERROR;
+            break;
+        }
+        event.slotid = slotid;
+        xhci_event(xhci, &event);
+    }
+}
+
+static void xhci_update_port(XHCIState *xhci, XHCIPort *port, int is_detach)
+{
+    int nr = port->port.index + 1;
+
+    port->portsc = PORTSC_PP;
+    if (port->port.dev && !is_detach) {
+        port->portsc |= PORTSC_CCS;
+        switch (port->port.dev->speed) {
+        case USB_SPEED_LOW:
+            port->portsc |= PORTSC_SPEED_LOW;
+            break;
+        case USB_SPEED_FULL:
+            port->portsc |= PORTSC_SPEED_FULL;
+            break;
+        case USB_SPEED_HIGH:
+            port->portsc |= PORTSC_SPEED_HIGH;
+            break;
+        }
+    }
+
+    if (xhci_running(xhci)) {
+        port->portsc |= PORTSC_CSC;
+        XHCIEvent ev = { ER_PORT_STATUS_CHANGE, CC_SUCCESS, nr << 24};
+        xhci_event(xhci, &ev);
+        DPRINTF("xhci: port change event for port %d\n", nr);
+    }
+}
+
+static void xhci_reset(void *opaque)
+{
+    XHCIState *xhci = opaque;
+    int i;
+
+    DPRINTF("xhci: full reset\n");
+    if (!(xhci->usbsts & USBSTS_HCH)) {
+        fprintf(stderr, "xhci: reset while running!\n");
+    }
+
+    xhci->usbcmd = 0;
+    xhci->usbsts = USBSTS_HCH;
+    xhci->dnctrl = 0;
+    xhci->crcr_low = 0;
+    xhci->crcr_high = 0;
+    xhci->dcbaap_low = 0;
+    xhci->dcbaap_high = 0;
+    xhci->config = 0;
+    xhci->devaddr = 2;
+
+    for (i = 0; i < MAXSLOTS; i++) {
+        xhci_disable_slot(xhci, i+1);
+    }
+
+    for (i = 0; i < MAXPORTS; i++) {
+        xhci_update_port(xhci, xhci->ports + i, 0);
+    }
+
+    xhci->mfindex = 0;
+    xhci->iman = 0;
+    xhci->imod = 0;
+    xhci->erstsz = 0;
+    xhci->erstba_low = 0;
+    xhci->erstba_high = 0;
+    xhci->erdp_low = 0;
+    xhci->erdp_high = 0;
+
+    xhci->er_ep_idx = 0;
+    xhci->er_pcs = 1;
+    xhci->er_full = 0;
+    xhci->ev_buffer_put = 0;
+    xhci->ev_buffer_get = 0;
+}
+
+static uint32_t xhci_cap_read(XHCIState *xhci, uint32_t reg)
+{
+    DPRINTF("xhci_cap_read(0x%x)\n", reg);
+
+    switch (reg) {
+    case 0x00: /* HCIVERSION, CAPLENGTH */
+        return 0x01000000 | LEN_CAP;
+    case 0x04: /* HCSPARAMS 1 */
+        return (MAXPORTS<<24) | (MAXINTRS<<8) | MAXSLOTS;
+    case 0x08: /* HCSPARAMS 2 */
+        return 0x0000000f;
+    case 0x0c: /* HCSPARAMS 3 */
+        return 0x00000000;
+    case 0x10: /* HCCPARAMS */
+#if TARGET_PHYS_ADDR_BITS > 32
+        return 0x00081001;
+#else
+        return 0x00081000;
+#endif
+    case 0x14: /* DBOFF */
+        return OFF_DOORBELL;
+    case 0x18: /* RTSOFF */
+        return OFF_RUNTIME;
+
+    /* extended capabilities */
+    case 0x20: /* Supported Protocol:00 */
+#if USB3_PORTS > 0
+        return 0x02000402; /* USB 2.0 */
+#else
+        return 0x02000002; /* USB 2.0 */
+#endif
+    case 0x24: /* Supported Protocol:04 */
+        return 0x20425455; /* "USB " */
+    case 0x28: /* Supported Protocol:08 */
+        return 0x00000001 | (USB2_PORTS<<8);
+    case 0x2c: /* Supported Protocol:0c */
+        return 0x00000000; /* reserved */
+#if USB3_PORTS > 0
+    case 0x30: /* Supported Protocol:00 */
+        return 0x03000002; /* USB 3.0 */
+    case 0x34: /* Supported Protocol:04 */
+        return 0x20425455; /* "USB " */
+    case 0x38: /* Supported Protocol:08 */
+        return 0x00000000 | (USB2_PORTS+1) | (USB3_PORTS<<8);
+    case 0x3c: /* Supported Protocol:0c */
+        return 0x00000000; /* reserved */
+#endif
+    default:
+        fprintf(stderr, "xhci_cap_read: reg %d unimplemented\n", reg);
+    }
+    return 0;
+}
+
+static uint32_t xhci_port_read(XHCIState *xhci, uint32_t reg)
+{
+    uint32_t port = reg >> 4;
+    if (port >= MAXPORTS) {
+        fprintf(stderr, "xhci_port_read: port %d out of bounds\n", port);
+        return 0;
+    }
+
+    switch (reg & 0xf) {
+    case 0x00: /* PORTSC */
+        return xhci->ports[port].portsc;
+    case 0x04: /* PORTPMSC */
+    case 0x08: /* PORTLI */
+        return 0;
+    case 0x0c: /* reserved */
+    default:
+        fprintf(stderr, "xhci_port_read (port %d): reg 0x%x unimplemented\n",
+                port, reg);
+        return 0;
+    }
+}
+
+static void xhci_port_write(XHCIState *xhci, uint32_t reg, uint32_t val)
+{
+    uint32_t port = reg >> 4;
+    uint32_t portsc;
+
+    if (port >= MAXPORTS) {
+        fprintf(stderr, "xhci_port_read: port %d out of bounds\n", port);
+        return;
+    }
+
+    switch (reg & 0xf) {
+    case 0x00: /* PORTSC */
+        portsc = xhci->ports[port].portsc;
+        /* write-1-to-clear bits*/
+        portsc &= ~(val & (PORTSC_CSC|PORTSC_PEC|PORTSC_WRC|PORTSC_OCC|
+                           PORTSC_PRC|PORTSC_PLC|PORTSC_CEC));
+        if (val & PORTSC_LWS) {
+            /* overwrite PLS only when LWS=1 */
+            portsc &= ~(PORTSC_PLS_MASK << PORTSC_PLS_SHIFT);
+            portsc |= val & (PORTSC_PLS_MASK << PORTSC_PLS_SHIFT);
+        }
+        /* read/write bits */
+        portsc &= ~(PORTSC_PP|PORTSC_WCE|PORTSC_WDE|PORTSC_WOE);
+        portsc |= (val & (PORTSC_PP|PORTSC_WCE|PORTSC_WDE|PORTSC_WOE));
+        /* write-1-to-start bits */
+        if (val & PORTSC_PR) {
+            DPRINTF("xhci: port %d reset\n", port);
+            if (xhci->ports[port].port.dev) {
+                usb_send_msg(xhci->ports[port].port.dev, USB_MSG_RESET);
+            }
+            portsc |= PORTSC_PRC | PORTSC_PED;
+        }
+        xhci->ports[port].portsc = portsc;
+        break;
+    case 0x04: /* PORTPMSC */
+    case 0x08: /* PORTLI */
+    default:
+        fprintf(stderr, "xhci_port_write (port %d): reg 0x%x unimplemented\n",
+                port, reg);
+    }
+}
+
+static uint32_t xhci_oper_read(XHCIState *xhci, uint32_t reg)
+{
+    DPRINTF("xhci_oper_read(0x%x)\n", reg);
+
+    if (reg >= 0x400) {
+        return xhci_port_read(xhci, reg - 0x400);
+    }
+
+    switch (reg) {
+    case 0x00: /* USBCMD */
+        return xhci->usbcmd;
+    case 0x04: /* USBSTS */
+        return xhci->usbsts;
+    case 0x08: /* PAGESIZE */
+        return 1; /* 4KiB */
+    case 0x14: /* DNCTRL */
+        return xhci->dnctrl;
+    case 0x18: /* CRCR low */
+        return xhci->crcr_low & ~0xe;
+    case 0x1c: /* CRCR high */
+        return xhci->crcr_high;
+    case 0x30: /* DCBAAP low */
+        return xhci->dcbaap_low;
+    case 0x34: /* DCBAAP high */
+        return xhci->dcbaap_high;
+    case 0x38: /* CONFIG */
+        return xhci->config;
+    default:
+        fprintf(stderr, "xhci_oper_read: reg 0x%x unimplemented\n", reg);
+    }
+    return 0;
+}
+
+static void xhci_oper_write(XHCIState *xhci, uint32_t reg, uint32_t val)
+{
+    DPRINTF("xhci_oper_write(0x%x, 0x%08x)\n", reg, val);
+
+    if (reg >= 0x400) {
+        xhci_port_write(xhci, reg - 0x400, val);
+        return;
+    }
+
+    switch (reg) {
+    case 0x00: /* USBCMD */
+        if ((val & USBCMD_RS) && !(xhci->usbcmd & USBCMD_RS)) {
+            xhci_run(xhci);
+        } else if (!(val & USBCMD_RS) && (xhci->usbcmd & USBCMD_RS)) {
+            xhci_stop(xhci);
+        }
+        xhci->usbcmd = val & 0xc0f;
+        if (val & USBCMD_HCRST) {
+            xhci_reset(xhci);
+        }
+        xhci_irq_update(xhci);
+        break;
+
+    case 0x04: /* USBSTS */
+        /* these bits are write-1-to-clear */
+        xhci->usbsts &= ~(val & (USBSTS_HSE|USBSTS_EINT|USBSTS_PCD|USBSTS_SRE));
+        xhci_irq_update(xhci);
+        break;
+
+    case 0x14: /* DNCTRL */
+        xhci->dnctrl = val & 0xffff;
+        break;
+    case 0x18: /* CRCR low */
+        xhci->crcr_low = (val & 0xffffffcf) | (xhci->crcr_low & CRCR_CRR);
+        break;
+    case 0x1c: /* CRCR high */
+        xhci->crcr_high = val;
+        if (xhci->crcr_low & (CRCR_CA|CRCR_CS) && (xhci->crcr_low & CRCR_CRR)) {
+            XHCIEvent event = {ER_COMMAND_COMPLETE, CC_COMMAND_RING_STOPPED};
+            xhci->crcr_low &= ~CRCR_CRR;
+            xhci_event(xhci, &event);
+            DPRINTF("xhci: command ring stopped (CRCR=%08x)\n", xhci->crcr_low);
+        } else {
+            target_phys_addr_t base = xhci_addr64(xhci->crcr_low & ~0x3f, val);
+            xhci_ring_init(xhci, &xhci->cmd_ring, base);
+        }
+        xhci->crcr_low &= ~(CRCR_CA | CRCR_CS);
+        break;
+    case 0x30: /* DCBAAP low */
+        xhci->dcbaap_low = val & 0xffffffc0;
+        break;
+    case 0x34: /* DCBAAP high */
+        xhci->dcbaap_high = val;
+        break;
+    case 0x38: /* CONFIG */
+        xhci->config = val & 0xff;
+        break;
+    default:
+        fprintf(stderr, "xhci_oper_write: reg 0x%x unimplemented\n", reg);
+    }
+}
+
+static uint32_t xhci_runtime_read(XHCIState *xhci, uint32_t reg)
+{
+    DPRINTF("xhci_runtime_read(0x%x)\n", reg);
+
+    switch (reg) {
+    case 0x00: /* MFINDEX */
+        fprintf(stderr, "xhci_runtime_read: MFINDEX not yet implemented\n");
+        return xhci->mfindex;
+    case 0x20: /* IMAN */
+        return xhci->iman;
+    case 0x24: /* IMOD */
+        return xhci->imod;
+    case 0x28: /* ERSTSZ */
+        return xhci->erstsz;
+    case 0x30: /* ERSTBA low */
+        return xhci->erstba_low;
+    case 0x34: /* ERSTBA high */
+        return xhci->erstba_high;
+    case 0x38: /* ERDP low */
+        return xhci->erdp_low;
+    case 0x3c: /* ERDP high */
+        return xhci->erdp_high;
+    default:
+        fprintf(stderr, "xhci_runtime_read: reg 0x%x unimplemented\n", reg);
+    }
+    return 0;
+}
+
+static void xhci_runtime_write(XHCIState *xhci, uint32_t reg, uint32_t val)
+{
+    DPRINTF("xhci_runtime_write(0x%x, 0x%08x)\n", reg, val);
+
+    switch (reg) {
+    case 0x20: /* IMAN */
+        if (val & IMAN_IP) {
+            xhci->iman &= ~IMAN_IP;
+        }
+        xhci->iman &= ~IMAN_IE;
+        xhci->iman |= val & IMAN_IE;
+        xhci_irq_update(xhci);
+        break;
+    case 0x24: /* IMOD */
+        xhci->imod = val;
+        break;
+    case 0x28: /* ERSTSZ */
+        xhci->erstsz = val & 0xffff;
+        break;
+    case 0x30: /* ERSTBA low */
+        /* XXX NEC driver bug: it doesn't align this to 64 bytes
+        xhci->erstba_low = val & 0xffffffc0; */
+        xhci->erstba_low = val & 0xfffffff0;
+        break;
+    case 0x34: /* ERSTBA high */
+        xhci->erstba_high = val;
+        xhci_er_reset(xhci);
+        break;
+    case 0x38: /* ERDP low */
+        if (val & ERDP_EHB) {
+            xhci->erdp_low &= ~ERDP_EHB;
+        }
+        xhci->erdp_low = (val & ~ERDP_EHB) | (xhci->erdp_low & ERDP_EHB);
+        break;
+    case 0x3c: /* ERDP high */
+        xhci->erdp_high = val;
+        xhci_events_update(xhci);
+        break;
+    default:
+        fprintf(stderr, "xhci_oper_write: reg 0x%x unimplemented\n", reg);
+    }
+}
+
+static uint32_t xhci_doorbell_read(XHCIState *xhci, uint32_t reg)
+{
+    DPRINTF("xhci_doorbell_read(0x%x)\n", reg);
+    /* doorbells always read as 0 */
+    return 0;
+}
+
+static void xhci_doorbell_write(XHCIState *xhci, uint32_t reg, uint32_t val)
+{
+    DPRINTF("xhci_doorbell_write(0x%x, 0x%08x)\n", reg, val);
+
+    if (!xhci_running(xhci)) {
+        fprintf(stderr, "xhci: wrote doorbell while xHC stopped or paused\n");
+        return;
+    }
+
+    reg >>= 2;
+
+    if (reg == 0) {
+        if (val == 0) {
+            xhci_process_commands(xhci);
+        } else {
+            fprintf(stderr, "xhci: bad doorbell 0 write: 0x%x\n", val);
+        }
+    } else {
+        if (reg > MAXSLOTS) {
+            fprintf(stderr, "xhci: bad doorbell %d\n", reg);
+        } else if (val > 31) {
+            fprintf(stderr, "xhci: bad doorbell %d write: 0x%x\n", reg, val);
+        } else {
+            xhci_kick_ep(xhci, reg, val);
+        }
+    }
+}
+
+static uint64_t xhci_mem_read(void *ptr, target_phys_addr_t addr,
+                              unsigned size)
+{
+    XHCIState *xhci = ptr;
+
+    /* Only aligned reads are allowed on xHCI */
+    if (addr & 3) {
+        fprintf(stderr, "xhci_mem_read: Mis-aligned read\n");
+        return 0;
+    }
+
+    if (addr < LEN_CAP) {
+        return xhci_cap_read(xhci, addr);
+    } else if (addr >= OFF_OPER && addr < (OFF_OPER + LEN_OPER)) {
+        return xhci_oper_read(xhci, addr - OFF_OPER);
+    } else if (addr >= OFF_RUNTIME && addr < (OFF_RUNTIME + LEN_RUNTIME)) {
+        return xhci_runtime_read(xhci, addr - OFF_RUNTIME);
+    } else if (addr >= OFF_DOORBELL && addr < (OFF_DOORBELL + LEN_DOORBELL)) {
+        return xhci_doorbell_read(xhci, addr - OFF_DOORBELL);
+    } else {
+        fprintf(stderr, "xhci_mem_read: Bad offset %x\n", (int)addr);
+        return 0;
+    }
+}
+
+static void xhci_mem_write(void *ptr, target_phys_addr_t addr,
+                           uint64_t val, unsigned size)
+{
+    XHCIState *xhci = ptr;
+
+    /* Only aligned writes are allowed on xHCI */
+    if (addr & 3) {
+        fprintf(stderr, "xhci_mem_write: Mis-aligned write\n");
+        return;
+    }
+
+    if (addr >= OFF_OPER && addr < (OFF_OPER + LEN_OPER)) {
+        xhci_oper_write(xhci, addr - OFF_OPER, val);
+    } else if (addr >= OFF_RUNTIME && addr < (OFF_RUNTIME + LEN_RUNTIME)) {
+        xhci_runtime_write(xhci, addr - OFF_RUNTIME, val);
+    } else if (addr >= OFF_DOORBELL && addr < (OFF_DOORBELL + LEN_DOORBELL)) {
+        xhci_doorbell_write(xhci, addr - OFF_DOORBELL, val);
+    } else {
+        fprintf(stderr, "xhci_mem_write: Bad offset %x\n", (int)addr);
+    }
+}
+
+static const MemoryRegionOps xhci_mem_ops = {
+    .read = xhci_mem_read,
+    .write = xhci_mem_write,
+    .valid.min_access_size = 4,
+    .valid.max_access_size = 4,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static void xhci_attach(USBPort *usbport)
+{
+    XHCIState *xhci = usbport->opaque;
+    XHCIPort *port = &xhci->ports[usbport->index];
+
+    xhci_update_port(xhci, port, 0);
+}
+
+static void xhci_detach(USBPort *usbport)
+{
+    XHCIState *xhci = usbport->opaque;
+    XHCIPort *port = &xhci->ports[usbport->index];
+
+    xhci_update_port(xhci, port, 1);
+}
+
+static void xhci_complete(USBPort *port, USBPacket *packet)
+{
+    XHCITransfer *xfer = container_of(packet, XHCITransfer, packet);
+
+    xhci_complete_packet(xfer, packet->result);
+    xhci_kick_ep(xfer->xhci, xfer->slotid, xfer->epid);
+}
+
+static void xhci_child_detach(USBPort *port, USBDevice *child)
+{
+    FIXME();
+}
+
+static USBPortOps xhci_port_ops = {
+    .attach   = xhci_attach,
+    .detach   = xhci_detach,
+    .complete = xhci_complete,
+    .child_detach = xhci_child_detach,
+};
+
+static USBBusOps xhci_bus_ops = {
+};
+
+static void usb_xhci_init(XHCIState *xhci, DeviceState *dev)
+{
+    int i;
+
+    xhci->usbsts = USBSTS_HCH;
+
+    usb_bus_new(&xhci->bus, &xhci_bus_ops, &xhci->pci_dev.qdev);
+
+    for (i = 0; i < MAXPORTS; i++) {
+        memset(&xhci->ports[i], 0, sizeof(xhci->ports[i]));
+        usb_register_port(&xhci->bus, &xhci->ports[i].port, xhci, i,
+                          &xhci_port_ops, USB_SPEED_MASK_HIGH);
+    }
+    for (i = 0; i < MAXSLOTS; i++) {
+        xhci->slots[i].enabled = 0;
+    }
+
+    qemu_register_reset(xhci_reset, xhci);
+}
+
+static int usb_xhci_initfn(struct PCIDevice *dev)
+{
+    int ret;
+
+    XHCIState *xhci = DO_UPCAST(XHCIState, pci_dev, dev);
+
+    xhci->pci_dev.config[PCI_CLASS_PROG] = 0x30;    /* xHCI */
+    xhci->pci_dev.config[PCI_INTERRUPT_PIN] = 0x01; /* interrupt pin 1 */
+    xhci->pci_dev.config[PCI_CACHE_LINE_SIZE] = 0x10;
+    xhci->pci_dev.config[0x60] = 0x30; /* release number */
+
+    usb_xhci_init(xhci, &dev->qdev);
+
+    xhci->irq = xhci->pci_dev.irq[0];
+
+    memory_region_init_io(&xhci->mem, &xhci_mem_ops, xhci,
+                          "xhci", LEN_REGS);
+    pci_register_bar(&xhci->pci_dev, 0,
+                     PCI_BASE_ADDRESS_SPACE_MEMORY|PCI_BASE_ADDRESS_MEM_TYPE_64,
+                     &xhci->mem);
+
+    ret = pcie_cap_init(&xhci->pci_dev, 0xa0, PCI_EXP_TYPE_ENDPOINT, 0);
+    assert(ret >= 0);
+
+    if (xhci->msi) {
+        ret = msi_init(&xhci->pci_dev, 0x70, 1, true, false);
+        assert(ret >= 0);
+    }
+
+    return 0;
+}
+
+static void xhci_write_config(PCIDevice *dev, uint32_t addr, uint32_t val,
+                              int len)
+{
+    XHCIState *xhci = DO_UPCAST(XHCIState, pci_dev, dev);
+
+    pci_default_write_config(dev, addr, val, len);
+    if (xhci->msi) {
+        msi_write_config(dev, addr, val, len);
+    }
+}
+
+static const VMStateDescription vmstate_xhci = {
+    .name = "xhci",
+    .unmigratable = 1,
+};
+
+static Property xhci_properties[] = {
+    DEFINE_PROP_UINT32("msi", XHCIState, msi, 0),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void xhci_class_init(ObjectClass *klass, void *data)
+{
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    dc->vmsd    = &vmstate_xhci;
+    dc->props   = xhci_properties;
+    k->init         = usb_xhci_initfn;
+    k->vendor_id    = PCI_VENDOR_ID_NEC;
+    k->device_id    = PCI_DEVICE_ID_NEC_UPD720200;
+    k->class_id     = PCI_CLASS_SERIAL_USB;
+    k->revision     = 0x03;
+    k->is_express   = 1;
+    k->config_write = xhci_write_config;
+}
+
+static TypeInfo xhci_info = {
+    .name          = "nec-usb-xhci",
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(XHCIState),
+    .class_init    = xhci_class_init,
+};
+
+static void xhci_register(void)
+{
+    type_register_static(&xhci_info);
+}
+device_init(xhci_register);
diff --git a/hw/usb.c b/hw/usb.c
index 2216efe077..c3ff5b7093 100644
--- a/hw/usb.c
+++ b/hw/usb.c
@@ -95,8 +95,8 @@ static int do_token_setup(USBDevice *s, USBPacket *p)
     index   = (s->setup_buf[5] << 8) | s->setup_buf[4];
 
     if (s->setup_buf[0] & USB_DIR_IN) {
-        ret = s->info->handle_control(s, p, request, value, index,
-                                      s->setup_len, s->data_buf);
+        ret = usb_device_handle_control(s, p, request, value, index,
+                                        s->setup_len, s->data_buf);
         if (ret == USB_RET_ASYNC) {
              s->setup_state = SETUP_STATE_SETUP;
              return USB_RET_ASYNC;
@@ -129,7 +129,7 @@ static int do_token_in(USBDevice *s, USBPacket *p)
     int ret = 0;
 
     if (p->devep != 0)
-        return s->info->handle_data(s, p);
+        return usb_device_handle_data(s, p);
 
     request = (s->setup_buf[0] << 8) | s->setup_buf[1];
     value   = (s->setup_buf[3] << 8) | s->setup_buf[2];
@@ -138,8 +138,8 @@ static int do_token_in(USBDevice *s, USBPacket *p)
     switch(s->setup_state) {
     case SETUP_STATE_ACK:
         if (!(s->setup_buf[0] & USB_DIR_IN)) {
-            ret = s->info->handle_control(s, p, request, value, index,
-                                          s->setup_len, s->data_buf);
+            ret = usb_device_handle_control(s, p, request, value, index,
+                                            s->setup_len, s->data_buf);
             if (ret == USB_RET_ASYNC) {
                 return USB_RET_ASYNC;
             }
@@ -176,7 +176,7 @@ static int do_token_in(USBDevice *s, USBPacket *p)
 static int do_token_out(USBDevice *s, USBPacket *p)
 {
     if (p->devep != 0)
-        return s->info->handle_data(s, p);
+        return usb_device_handle_data(s, p);
 
     switch(s->setup_state) {
     case SETUP_STATE_ACK:
@@ -220,9 +220,7 @@ int usb_generic_handle_packet(USBDevice *s, USBPacket *p)
     switch(p->pid) {
     case USB_MSG_ATTACH:
         s->state = USB_STATE_ATTACHED;
-        if (s->info->handle_attach) {
-            s->info->handle_attach(s);
-        }
+        usb_device_handle_attach(s);
         return 0;
 
     case USB_MSG_DETACH:
@@ -233,9 +231,7 @@ int usb_generic_handle_packet(USBDevice *s, USBPacket *p)
         s->remote_wakeup = 0;
         s->addr = 0;
         s->state = USB_STATE_DEFAULT;
-        if (s->info->handle_reset) {
-            s->info->handle_reset(s);
-        }
+        usb_device_handle_reset(s);
         return 0;
     }
 
@@ -326,10 +322,10 @@ int usb_handle_packet(USBDevice *dev, USBPacket *p)
     int ret;
 
     assert(p->owner == NULL);
-    ret = dev->info->handle_packet(dev, p);
+    ret = usb_device_handle_packet(dev, p);
     if (ret == USB_RET_ASYNC) {
         if (p->owner == NULL) {
-            p->owner = dev;
+            p->owner = usb_ep_get(dev, p->pid, p->devep);
         } else {
             /* We'll end up here when usb_handle_packet is called
              * recursively due to a hub being in the chain.  Nothing
@@ -357,7 +353,7 @@ void usb_packet_complete(USBDevice *dev, USBPacket *p)
 void usb_cancel_packet(USBPacket * p)
 {
     assert(p->owner != NULL);
-    p->owner->info->cancel_packet(p->owner, p);
+    usb_device_cancel_packet(p->owner->dev, p);
     p->owner = NULL;
 }
 
@@ -414,3 +410,124 @@ void usb_packet_cleanup(USBPacket *p)
 {
     qemu_iovec_destroy(&p->iov);
 }
+
+void usb_ep_init(USBDevice *dev)
+{
+    int ep;
+
+    dev->ep_ctl.type = USB_ENDPOINT_XFER_CONTROL;
+    dev->ep_ctl.ifnum = 0;
+    dev->ep_ctl.dev = dev;
+    for (ep = 0; ep < USB_MAX_ENDPOINTS; ep++) {
+        dev->ep_in[ep].type = USB_ENDPOINT_XFER_INVALID;
+        dev->ep_out[ep].type = USB_ENDPOINT_XFER_INVALID;
+        dev->ep_in[ep].ifnum = 0;
+        dev->ep_out[ep].ifnum = 0;
+        dev->ep_in[ep].dev = dev;
+        dev->ep_out[ep].dev = dev;
+    }
+}
+
+void usb_ep_dump(USBDevice *dev)
+{
+    static const char *tname[] = {
+        [USB_ENDPOINT_XFER_CONTROL] = "control",
+        [USB_ENDPOINT_XFER_ISOC]    = "isoc",
+        [USB_ENDPOINT_XFER_BULK]    = "bulk",
+        [USB_ENDPOINT_XFER_INT]     = "int",
+    };
+    int ifnum, ep, first;
+
+    fprintf(stderr, "Device \"%s\", config %d\n",
+            dev->product_desc, dev->configuration);
+    for (ifnum = 0; ifnum < 16; ifnum++) {
+        first = 1;
+        for (ep = 0; ep < USB_MAX_ENDPOINTS; ep++) {
+            if (dev->ep_in[ep].type != USB_ENDPOINT_XFER_INVALID &&
+                dev->ep_in[ep].ifnum == ifnum) {
+                if (first) {
+                    first = 0;
+                    fprintf(stderr, "  Interface %d, alternative %d\n",
+                            ifnum, dev->altsetting[ifnum]);
+                }
+                fprintf(stderr, "    Endpoint %d, IN, %s, %d max\n", ep,
+                        tname[dev->ep_in[ep].type],
+                        dev->ep_in[ep].max_packet_size);
+            }
+            if (dev->ep_out[ep].type != USB_ENDPOINT_XFER_INVALID &&
+                dev->ep_out[ep].ifnum == ifnum) {
+                if (first) {
+                    first = 0;
+                    fprintf(stderr, "  Interface %d, alternative %d\n",
+                            ifnum, dev->altsetting[ifnum]);
+                }
+                fprintf(stderr, "    Endpoint %d, OUT, %s, %d max\n", ep,
+                        tname[dev->ep_out[ep].type],
+                        dev->ep_out[ep].max_packet_size);
+            }
+        }
+    }
+    fprintf(stderr, "--\n");
+}
+
+struct USBEndpoint *usb_ep_get(USBDevice *dev, int pid, int ep)
+{
+    struct USBEndpoint *eps = pid == USB_TOKEN_IN ? dev->ep_in : dev->ep_out;
+    if (ep == 0) {
+        return &dev->ep_ctl;
+    }
+    assert(pid == USB_TOKEN_IN || pid == USB_TOKEN_OUT);
+    assert(ep > 0 && ep <= USB_MAX_ENDPOINTS);
+    return eps + ep - 1;
+}
+
+uint8_t usb_ep_get_type(USBDevice *dev, int pid, int ep)
+{
+    struct USBEndpoint *uep = usb_ep_get(dev, pid, ep);
+    return uep->type;
+}
+
+void usb_ep_set_type(USBDevice *dev, int pid, int ep, uint8_t type)
+{
+    struct USBEndpoint *uep = usb_ep_get(dev, pid, ep);
+    uep->type = type;
+}
+
+uint8_t usb_ep_get_ifnum(USBDevice *dev, int pid, int ep)
+{
+    struct USBEndpoint *uep = usb_ep_get(dev, pid, ep);
+    return uep->ifnum;
+}
+
+void usb_ep_set_ifnum(USBDevice *dev, int pid, int ep, uint8_t ifnum)
+{
+    struct USBEndpoint *uep = usb_ep_get(dev, pid, ep);
+    uep->ifnum = ifnum;
+}
+
+void usb_ep_set_max_packet_size(USBDevice *dev, int pid, int ep,
+                                uint16_t raw)
+{
+    struct USBEndpoint *uep = usb_ep_get(dev, pid, ep);
+    int size, microframes;
+
+    size = raw & 0x7ff;
+    switch ((raw >> 11) & 3) {
+    case 1:
+        microframes = 2;
+        break;
+    case 2:
+        microframes = 3;
+        break;
+    default:
+        microframes = 1;
+        break;
+    }
+    uep->max_packet_size = size * microframes;
+}
+
+int usb_ep_get_max_packet_size(USBDevice *dev, int pid, int ep)
+{
+    struct USBEndpoint *uep = usb_ep_get(dev, pid, ep);
+    return uep->max_packet_size;
+}
diff --git a/hw/usb.h b/hw/usb.h
index 7ea90e4d9c..13e7c8ea7f 100644
--- a/hw/usb.h
+++ b/hw/usb.h
@@ -1,3 +1,6 @@
+#ifndef QEMU_USB_H
+#define QEMU_USB_H
+
 /*
  * QEMU USB API
  *
@@ -79,6 +82,11 @@
 #define USB_CLASS_APP_SPEC		0xfe
 #define USB_CLASS_VENDOR_SPEC		0xff
 
+#define USB_SUBCLASS_UNDEFINED          0
+#define USB_SUBCLASS_AUDIO_CONTROL      1
+#define USB_SUBCLASS_AUDIO_STREAMING    2
+#define USB_SUBCLASS_AUDIO_MIDISTREAMING 3
+
 #define USB_DIR_OUT			0
 #define USB_DIR_IN			0x80
 
@@ -132,18 +140,21 @@
 #define USB_DT_OTHER_SPEED_CONFIG       0x07
 #define USB_DT_DEBUG                    0x0A
 #define USB_DT_INTERFACE_ASSOC          0x0B
+#define USB_DT_CS_INTERFACE             0x24
+#define USB_DT_CS_ENDPOINT              0x25
 
 #define USB_ENDPOINT_XFER_CONTROL	0
 #define USB_ENDPOINT_XFER_ISOC		1
 #define USB_ENDPOINT_XFER_BULK		2
 #define USB_ENDPOINT_XFER_INT		3
+#define USB_ENDPOINT_XFER_INVALID     255
 
 typedef struct USBBus USBBus;
 typedef struct USBBusOps USBBusOps;
 typedef struct USBPort USBPort;
 typedef struct USBDevice USBDevice;
-typedef struct USBDeviceInfo USBDeviceInfo;
 typedef struct USBPacket USBPacket;
+typedef struct USBEndpoint USBEndpoint;
 
 typedef struct USBDesc USBDesc;
 typedef struct USBDescID USBDescID;
@@ -161,10 +172,19 @@ struct USBDescString {
     QLIST_ENTRY(USBDescString) next;
 };
 
+#define USB_MAX_ENDPOINTS  15
+#define USB_MAX_INTERFACES 16
+
+struct USBEndpoint {
+    uint8_t type;
+    uint8_t ifnum;
+    int max_packet_size;
+    USBDevice *dev;
+};
+
 /* definition of a USB device */
 struct USBDevice {
     DeviceState qdev;
-    USBDeviceInfo *info;
     USBPort *port;
     char *port_path;
     void *opaque;
@@ -186,13 +206,31 @@ struct USBDevice {
     int32_t setup_len;
     int32_t setup_index;
 
+    USBEndpoint ep_ctl;
+    USBEndpoint ep_in[USB_MAX_ENDPOINTS];
+    USBEndpoint ep_out[USB_MAX_ENDPOINTS];
+
     QLIST_HEAD(, USBDescString) strings;
     const USBDescDevice *device;
+
+    int configuration;
+    int ninterfaces;
+    int altsetting[USB_MAX_INTERFACES];
     const USBDescConfig *config;
+    const USBDescIface  *ifaces[USB_MAX_INTERFACES];
 };
 
-struct USBDeviceInfo {
-    DeviceInfo qdev;
+#define TYPE_USB_DEVICE "usb-device"
+#define USB_DEVICE(obj) \
+     OBJECT_CHECK(USBDevice, (obj), TYPE_USB_DEVICE)
+#define USB_DEVICE_CLASS(klass) \
+     OBJECT_CLASS_CHECK(USBDeviceClass, (klass), TYPE_USB_DEVICE)
+#define USB_DEVICE_GET_CLASS(obj) \
+     OBJECT_GET_CLASS(USBDeviceClass, (obj), TYPE_USB_DEVICE)
+
+typedef struct USBDeviceClass {
+    DeviceClass parent_class;
+
     int (*init)(USBDevice *dev);
 
     /*
@@ -241,13 +279,12 @@ struct USBDeviceInfo {
      */
     int (*handle_data)(USBDevice *dev, USBPacket *p);
 
+    void (*set_interface)(USBDevice *dev, int interface,
+                          int alt_old, int alt_new);
+
     const char *product_desc;
     const USBDesc *usb_desc;
-
-    /* handle legacy -usbdevice command line options */
-    const char *usbdevice_name;
-    USBDevice *(*usbdevice_init)(const char *params);
-};
+} USBDeviceClass;
 
 typedef struct USBPortOps {
     void (*attach)(USBPort *port);
@@ -288,7 +325,7 @@ struct USBPacket {
     QEMUIOVector iov;
     int result; /* transfer length or USB_RET_* status code */
     /* Internal use by the USB layer.  */
-    USBDevice *owner;
+    USBEndpoint *owner;
 };
 
 void usb_packet_init(USBPacket *p);
@@ -304,6 +341,17 @@ int usb_handle_packet(USBDevice *dev, USBPacket *p);
 void usb_packet_complete(USBDevice *dev, USBPacket *p);
 void usb_cancel_packet(USBPacket * p);
 
+void usb_ep_init(USBDevice *dev);
+void usb_ep_dump(USBDevice *dev);
+struct USBEndpoint *usb_ep_get(USBDevice *dev, int pid, int ep);
+uint8_t usb_ep_get_type(USBDevice *dev, int pid, int ep);
+uint8_t usb_ep_get_ifnum(USBDevice *dev, int pid, int ep);
+void usb_ep_set_type(USBDevice *dev, int pid, int ep, uint8_t type);
+void usb_ep_set_ifnum(USBDevice *dev, int pid, int ep, uint8_t ifnum);
+void usb_ep_set_max_packet_size(USBDevice *dev, int pid, int ep,
+                                uint16_t raw);
+int usb_ep_get_max_packet_size(USBDevice *dev, int pid, int ep);
+
 void usb_attach(USBPort *port);
 void usb_detach(USBPort *port);
 void usb_reset(USBPort *port);
@@ -370,8 +418,8 @@ struct USBBusOps {
 
 void usb_bus_new(USBBus *bus, USBBusOps *ops, DeviceState *host);
 USBBus *usb_bus_find(int busnr);
-void usb_qdev_register(USBDeviceInfo *info);
-void usb_qdev_register_many(USBDeviceInfo *info);
+void usb_legacy_register(const char *typename, const char *usbdevice_name,
+                         USBDevice *(*usbdevice_init)(const char *params));
 USBDevice *usb_create(USBBus *bus, const char *name);
 USBDevice *usb_create_simple(USBBus *bus, const char *name);
 USBDevice *usbdevice_create(const char *cmdline);
@@ -403,4 +451,25 @@ extern const VMStateDescription vmstate_usb_device;
     .offset     = vmstate_offset_value(_state, _field, USBDevice),   \
 }
 
+int usb_device_handle_packet(USBDevice *dev, USBPacket *p);
+
+void usb_device_cancel_packet(USBDevice *dev, USBPacket *p);
+
+void usb_device_handle_attach(USBDevice *dev);
+
+void usb_device_handle_reset(USBDevice *dev);
+
+int usb_device_handle_control(USBDevice *dev, USBPacket *p, int request, int value,
+                              int index, int length, uint8_t *data);
+
+int usb_device_handle_data(USBDevice *dev, USBPacket *p);
+
+void usb_device_set_interface(USBDevice *dev, int interface,
+                              int alt_old, int alt_new);
+
+const char *usb_device_get_product_desc(USBDevice *dev);
+
+const USBDesc *usb_device_get_usb_desc(USBDevice *dev);
+
+#endif
 
diff --git a/hw/versatile_pci.c b/hw/versatile_pci.c
index a285f7f383..c4105e977b 100644
--- a/hw/versatile_pci.c
+++ b/hw/versatile_pci.c
@@ -109,22 +109,56 @@ static int versatile_pci_host_init(PCIDevice *d)
     return 0;
 }
 
-static PCIDeviceInfo versatile_pci_host_info = {
-    .qdev.name = "versatile_pci_host",
-    .qdev.size = sizeof(PCIDevice),
-    .init      = versatile_pci_host_init,
-    .vendor_id = PCI_VENDOR_ID_XILINX,
-    /* Both boards have the same device ID.  Oh well.  */
-    .device_id = PCI_DEVICE_ID_XILINX_XC2VP30,
-    .class_id  = PCI_CLASS_PROCESSOR_CO,
+static void versatile_pci_host_class_init(ObjectClass *klass, void *data)
+{
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->init = versatile_pci_host_init;
+    k->vendor_id = PCI_VENDOR_ID_XILINX;
+    k->device_id = PCI_DEVICE_ID_XILINX_XC2VP30;
+    k->class_id = PCI_CLASS_PROCESSOR_CO;
+}
+
+static TypeInfo versatile_pci_host_info = {
+    .name          = "versatile_pci_host",
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(PCIDevice),
+    .class_init    = versatile_pci_host_class_init,
+};
+
+static void pci_vpb_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+
+    sdc->init = pci_vpb_init;
+}
+
+static TypeInfo pci_vpb_info = {
+    .name          = "versatile_pci",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(PCIVPBState),
+    .class_init    = pci_vpb_class_init,
+};
+
+static void pci_realview_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+
+    sdc->init = pci_realview_init;
+}
+
+static TypeInfo pci_realview_info = {
+    .name          = "realview_pci",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(PCIVPBState),
+    .class_init    = pci_realview_class_init,
 };
 
 static void versatile_pci_register_devices(void)
 {
-    sysbus_register_dev("versatile_pci", sizeof(PCIVPBState), pci_vpb_init);
-    sysbus_register_dev("realview_pci", sizeof(PCIVPBState),
-                        pci_realview_init);
-    pci_qdev_register(&versatile_pci_host_info);
+    type_register_static(&pci_vpb_info);
+    type_register_static(&pci_realview_info);
+    type_register_static(&versatile_pci_host_info);
 }
 
 device_init(versatile_pci_register_devices)
diff --git a/hw/versatilepb.c b/hw/versatilepb.c
index 0312b7564a..6e28e78f44 100644
--- a/hw/versatilepb.c
+++ b/hw/versatilepb.c
@@ -365,17 +365,26 @@ static void versatile_machine_init(void)
 
 machine_init(versatile_machine_init);
 
-static SysBusDeviceInfo vpb_sic_info = {
-    .init = vpb_sic_init,
-    .qdev.name = "versatilepb_sic",
-    .qdev.size = sizeof(vpb_sic_state),
-    .qdev.vmsd = &vmstate_vpb_sic,
-    .qdev.no_user = 1,
+static void vpb_sic_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = vpb_sic_init;
+    dc->no_user = 1;
+    dc->vmsd = &vmstate_vpb_sic;
+}
+
+static TypeInfo vpb_sic_info = {
+    .name          = "versatilepb_sic",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(vpb_sic_state),
+    .class_init    = vpb_sic_class_init,
 };
 
 static void versatilepb_register_devices(void)
 {
-    sysbus_register_withprop(&vpb_sic_info);
+    type_register_static(&vpb_sic_info);
 }
 
 device_init(versatilepb_register_devices)
diff --git a/hw/vexpress.c b/hw/vexpress.c
index 71115564e0..64fab4574c 100644
--- a/hw/vexpress.c
+++ b/hw/vexpress.c
@@ -182,6 +182,7 @@ static void vexpress_a9_init(ram_addr_t ram_size,
     /* 0x100ec000 TrustZone Address Space Controller */
     /* 0x10200000 CoreSight debug APB */
     /* 0x1e00a000 PL310 L2 Cache Controller */
+    sysbus_create_varargs("l2x0", 0x1e00a000, NULL);
 
     /* CS0: NOR0 flash          : 0x40000000 .. 0x44000000 */
     /* CS4: NOR1 flash          : 0x44000000 .. 0x48000000 */
diff --git a/hw/vga-isa.c b/hw/vga-isa.c
index 4825313f67..8d3ff0d47b 100644
--- a/hw/vga-isa.c
+++ b/hw/vga-isa.c
@@ -69,16 +69,24 @@ static int vga_initfn(ISADevice *dev)
     return 0;
 }
 
-static ISADeviceInfo vga_info = {
-    .qdev.name     = "isa-vga",
-    .qdev.size     = sizeof(ISAVGAState),
-    .qdev.vmsd     = &vmstate_vga_common,
-    .qdev.reset     = vga_reset_isa,
-    .init          = vga_initfn,
+static void vga_class_initfn(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    ISADeviceClass *ic = ISA_DEVICE_CLASS(klass);
+    ic->init = vga_initfn;
+    dc->reset = vga_reset_isa;
+    dc->vmsd = &vmstate_vga_common;
+}
+
+static TypeInfo vga_info = {
+    .name          = "isa-vga",
+    .parent        = TYPE_ISA_DEVICE,
+    .instance_size = sizeof(ISAVGAState),
+    .class_init    = vga_class_initfn,
 };
 
 static void vga_register(void)
 {
-    isa_qdev_register(&vga_info);
+    type_register_static(&vga_info);
 }
 device_init(vga_register)
diff --git a/hw/vga-pci.c b/hw/vga-pci.c
index a75dbf3974..974a7a9d6f 100644
--- a/hw/vga-pci.c
+++ b/hw/vga-pci.c
@@ -75,22 +75,29 @@ DeviceState *pci_vga_init(PCIBus *bus)
     return &pci_create_simple(bus, -1, "VGA")->qdev;
 }
 
-static PCIDeviceInfo vga_info = {
-    .qdev.name    = "VGA",
-    .qdev.size    = sizeof(PCIVGAState),
-    .qdev.vmsd    = &vmstate_vga_pci,
-    .no_hotplug   = 1,
-    .init         = pci_vga_initfn,
-    .romfile      = "vgabios-stdvga.bin",
+static void vga_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->no_hotplug = 1;
+    k->init = pci_vga_initfn;
+    k->romfile = "vgabios-stdvga.bin";
+    k->vendor_id = PCI_VENDOR_ID_QEMU;
+    k->device_id = PCI_DEVICE_ID_QEMU_VGA;
+    k->class_id = PCI_CLASS_DISPLAY_VGA;
+    dc->vmsd = &vmstate_vga_pci;
+}
 
-    /* dummy VGA (same as Bochs ID) */
-    .vendor_id    = PCI_VENDOR_ID_QEMU,
-    .device_id    = PCI_DEVICE_ID_QEMU_VGA,
-    .class_id     = PCI_CLASS_DISPLAY_VGA,
+static TypeInfo vga_info = {
+    .name          = "VGA",
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(PCIVGAState),
+    .class_init    = vga_class_init,
 };
 
 static void vga_register(void)
 {
-    pci_qdev_register(&vga_info);
+    type_register_static(&vga_info);
 }
 device_init(vga_register);
diff --git a/hw/vga.c b/hw/vga.c
index 950f97e440..d87c4f9f5b 100644
--- a/hw/vga.c
+++ b/hw/vga.c
@@ -22,6 +22,7 @@
  * THE SOFTWARE.
  */
 #include "hw.h"
+#include "vga.h"
 #include "console.h"
 #include "pc.h"
 #include "pci.h"
@@ -36,6 +37,18 @@
 
 //#define DEBUG_BOCHS_VBE
 
+/*
+ * Video Graphics Array (VGA)
+ *
+ * Chipset docs for original IBM VGA:
+ * http://www.mcamafia.de/pdf/ibm_vgaxga_trm2.pdf
+ *
+ * FreeVGA site:
+ * http://www.osdever.net/FreeVGA/home.htm
+ *
+ * Standard VGA features and Bochs VBE extensions are implemented.
+ */
+
 /* force some bits to zero */
 const uint8_t sr_mask[8] = {
     0x03,
@@ -160,9 +173,10 @@ static void vga_update_memory_access(VGACommonState *s)
 
     s->chain4_alias = NULL;
 
-    if ((s->sr[0x02] & 0xf) == 0xf && s->sr[0x04] & 0x08) {
+    if ((s->sr[VGA_SEQ_PLANE_WRITE] & VGA_SR02_ALL_PLANES) ==
+        VGA_SR02_ALL_PLANES && s->sr[VGA_SEQ_MEMORY_MODE] & VGA_SR04_CHN_4M) {
         offset = 0;
-        switch ((s->gr[6] >> 2) & 3) {
+        switch ((s->gr[VGA_GFX_MISC] >> 2) & 3) {
         case 0:
             base = 0xa0000;
             size = 0x20000;
@@ -223,22 +237,20 @@ static void vga_precise_update_retrace_info(VGACommonState *s)
     int64_t chars_per_sec;
     struct vga_precise_retrace *r = &s->retrace_info.precise;
 
-    htotal_chars = s->cr[0x00] + 5;
-    hretr_start_char = s->cr[0x04];
-    hretr_skew_chars = (s->cr[0x05] >> 5) & 3;
-    hretr_end_char = s->cr[0x05] & 0x1f;
+    htotal_chars = s->cr[VGA_CRTC_H_TOTAL] + 5;
+    hretr_start_char = s->cr[VGA_CRTC_H_SYNC_START];
+    hretr_skew_chars = (s->cr[VGA_CRTC_H_SYNC_END] >> 5) & 3;
+    hretr_end_char = s->cr[VGA_CRTC_H_SYNC_END] & 0x1f;
 
-    vtotal_lines = (s->cr[0x06]
-                    | (((s->cr[0x07] & 1) | ((s->cr[0x07] >> 4) & 2)) << 8)) + 2
-        ;
-    vretr_start_line = s->cr[0x10]
-        | ((((s->cr[0x07] >> 2) & 1) | ((s->cr[0x07] >> 6) & 2)) << 8)
-        ;
-    vretr_end_line = s->cr[0x11] & 0xf;
+    vtotal_lines = (s->cr[VGA_CRTC_V_TOTAL] |
+                    (((s->cr[VGA_CRTC_OVERFLOW] & 1) |
+                      ((s->cr[VGA_CRTC_OVERFLOW] >> 4) & 2)) << 8)) + 2;
+    vretr_start_line = s->cr[VGA_CRTC_V_SYNC_START] |
+        ((((s->cr[VGA_CRTC_OVERFLOW] >> 2) & 1) |
+          ((s->cr[VGA_CRTC_OVERFLOW] >> 6) & 2)) << 8);
+    vretr_end_line = s->cr[VGA_CRTC_V_SYNC_END] & 0xf;
 
-
-
-    clocking_mode = (s->sr[0x01] >> 3) & 1;
+    clocking_mode = (s->sr[VGA_SEQ_CLOCK_MODE] >> 3) & 1;
     clock_sel = (s->msr >> 2) & 3;
     dots = (s->msr & 1) ? 8 : 9;
 
@@ -261,8 +273,8 @@ static void vga_precise_update_retrace_info(VGACommonState *s)
     r->htotal = htotal_chars;
 
 #if 0
-    div2 = (s->cr[0x17] >> 2) & 1;
-    sldiv2 = (s->cr[0x17] >> 3) & 1;
+    div2 = (s->cr[VGA_CRTC_MODE] >> 2) & 1;
+    sldiv2 = (s->cr[VGA_CRTC_MODE] >> 3) & 1;
     printf (
         "hz=%f\n"
         "htotal = %d\n"
@@ -332,7 +344,7 @@ static uint8_t vga_dumb_retrace(VGACommonState *s)
 
 int vga_ioport_invalid(VGACommonState *s, uint32_t addr)
 {
-    if (s->msr & MSR_COLOR_EMULATION) {
+    if (s->msr & VGA_MIS_COLOR) {
         /* Color */
         return (addr >= 0x3b0 && addr <= 0x3bf);
     } else {
@@ -350,73 +362,74 @@ uint32_t vga_ioport_read(void *opaque, uint32_t addr)
         val = 0xff;
     } else {
         switch(addr) {
-        case 0x3c0:
+        case VGA_ATT_W:
             if (s->ar_flip_flop == 0) {
                 val = s->ar_index;
             } else {
                 val = 0;
             }
             break;
-        case 0x3c1:
+        case VGA_ATT_R:
             index = s->ar_index & 0x1f;
-            if (index < 21)
+            if (index < VGA_ATT_C) {
                 val = s->ar[index];
-            else
+            } else {
                 val = 0;
+            }
             break;
-        case 0x3c2:
+        case VGA_MIS_W:
             val = s->st00;
             break;
-        case 0x3c4:
+        case VGA_SEQ_I:
             val = s->sr_index;
             break;
-        case 0x3c5:
+        case VGA_SEQ_D:
             val = s->sr[s->sr_index];
 #ifdef DEBUG_VGA_REG
             printf("vga: read SR%x = 0x%02x\n", s->sr_index, val);
 #endif
             break;
-        case 0x3c7:
+        case VGA_PEL_IR:
             val = s->dac_state;
             break;
-        case 0x3c8:
+        case VGA_PEL_IW:
             val = s->dac_write_index;
             break;
-        case 0x3c9:
+        case VGA_PEL_D:
             val = s->palette[s->dac_read_index * 3 + s->dac_sub_index];
             if (++s->dac_sub_index == 3) {
                 s->dac_sub_index = 0;
                 s->dac_read_index++;
             }
             break;
-        case 0x3ca:
+        case VGA_FTC_R:
             val = s->fcr;
             break;
-        case 0x3cc:
+        case VGA_MIS_R:
             val = s->msr;
             break;
-        case 0x3ce:
+        case VGA_GFX_I:
             val = s->gr_index;
             break;
-        case 0x3cf:
+        case VGA_GFX_D:
             val = s->gr[s->gr_index];
 #ifdef DEBUG_VGA_REG
             printf("vga: read GR%x = 0x%02x\n", s->gr_index, val);
 #endif
             break;
-        case 0x3b4:
-        case 0x3d4:
+        case VGA_CRT_IM:
+        case VGA_CRT_IC:
             val = s->cr_index;
             break;
-        case 0x3b5:
-        case 0x3d5:
+        case VGA_CRT_DM:
+        case VGA_CRT_DC:
             val = s->cr[s->cr_index];
 #ifdef DEBUG_VGA_REG
             printf("vga: read CR%x = 0x%02x\n", s->cr_index, val);
 #endif
             break;
-        case 0x3ba:
-        case 0x3da:
+        case VGA_IS1_RM:
+        case VGA_IS1_RC:
             /* just toggle to fool polling */
             val = s->st01 = s->retrace(s);
             s->ar_flip_flop = 0;
@@ -446,29 +459,29 @@ void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
 #endif
 
     switch(addr) {
-    case 0x3c0:
+    case VGA_ATT_W:
         if (s->ar_flip_flop == 0) {
             val &= 0x3f;
             s->ar_index = val;
         } else {
             index = s->ar_index & 0x1f;
             switch(index) {
-            case 0x00 ... 0x0f:
+            case VGA_ATC_PALETTE0 ... VGA_ATC_PALETTEF:
                 s->ar[index] = val & 0x3f;
                 break;
-            case 0x10:
+            case VGA_ATC_MODE:
                 s->ar[index] = val & ~0x10;
                 break;
-            case 0x11:
+            case VGA_ATC_OVERSCAN:
                 s->ar[index] = val;
                 break;
-            case 0x12:
+            case VGA_ATC_PLANE_ENABLE:
                 s->ar[index] = val & ~0xc0;
                 break;
-            case 0x13:
+            case VGA_ATC_PEL:
                 s->ar[index] = val & ~0xf0;
                 break;
-            case 0x14:
+            case VGA_ATC_COLOR_PAGE:
                 s->ar[index] = val & ~0xf0;
                 break;
             default:
@@ -477,32 +490,34 @@ void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
         }
         s->ar_flip_flop ^= 1;
         break;
-    case 0x3c2:
+    case VGA_MIS_W:
         s->msr = val & ~0x10;
         s->update_retrace_info(s);
         break;
-    case 0x3c4:
+    case VGA_SEQ_I:
         s->sr_index = val & 7;
         break;
-    case 0x3c5:
+    case VGA_SEQ_D:
 #ifdef DEBUG_VGA_REG
         printf("vga: write SR%x = 0x%02x\n", s->sr_index, val);
 #endif
         s->sr[s->sr_index] = val & sr_mask[s->sr_index];
-        if (s->sr_index == 1) s->update_retrace_info(s);
+        if (s->sr_index == VGA_SEQ_CLOCK_MODE) {
+            s->update_retrace_info(s);
+        }
         vga_update_memory_access(s);
         break;
-    case 0x3c7:
+    case VGA_PEL_IR:
         s->dac_read_index = val;
         s->dac_sub_index = 0;
         s->dac_state = 3;
         break;
-    case 0x3c8:
+    case VGA_PEL_IW:
         s->dac_write_index = val;
         s->dac_sub_index = 0;
         s->dac_state = 0;
         break;
-    case 0x3c9:
+    case VGA_PEL_D:
         s->dac_cache[s->dac_sub_index] = val;
         if (++s->dac_sub_index == 3) {
             memcpy(&s->palette[s->dac_write_index * 3], s->dac_cache, 3);
@@ -510,48 +525,51 @@ void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
             s->dac_write_index++;
         }
         break;
-    case 0x3ce:
+    case VGA_GFX_I:
         s->gr_index = val & 0x0f;
         break;
-    case 0x3cf:
+    case VGA_GFX_D:
 #ifdef DEBUG_VGA_REG
         printf("vga: write GR%x = 0x%02x\n", s->gr_index, val);
 #endif
         s->gr[s->gr_index] = val & gr_mask[s->gr_index];
         vga_update_memory_access(s);
         break;
-    case 0x3b4:
-    case 0x3d4:
+    case VGA_CRT_IM:
+    case VGA_CRT_IC:
         s->cr_index = val;
         break;
-    case 0x3b5:
-    case 0x3d5:
+    case VGA_CRT_DM:
+    case VGA_CRT_DC:
 #ifdef DEBUG_VGA_REG
         printf("vga: write CR%x = 0x%02x\n", s->cr_index, val);
 #endif
         /* handle CR0-7 protection */
-        if ((s->cr[0x11] & 0x80) && s->cr_index <= 7) {
+        if ((s->cr[VGA_CRTC_V_SYNC_END] & VGA_CR11_LOCK_CR0_CR7) &&
+            s->cr_index <= VGA_CRTC_OVERFLOW) {
             /* can always write bit 4 of CR7 */
-            if (s->cr_index == 7)
-                s->cr[7] = (s->cr[7] & ~0x10) | (val & 0x10);
+            if (s->cr_index == VGA_CRTC_OVERFLOW) {
+                s->cr[VGA_CRTC_OVERFLOW] = (s->cr[VGA_CRTC_OVERFLOW] & ~0x10) |
+                    (val & 0x10);
+            }
             return;
         }
         s->cr[s->cr_index] = val;
 
         switch(s->cr_index) {
-        case 0x00:
-        case 0x04:
-        case 0x05:
-        case 0x06:
-        case 0x07:
-        case 0x11:
-        case 0x17:
+        case VGA_CRTC_H_TOTAL:
+        case VGA_CRTC_H_SYNC_START:
+        case VGA_CRTC_H_SYNC_END:
+        case VGA_CRTC_V_TOTAL:
+        case VGA_CRTC_OVERFLOW:
+        case VGA_CRTC_V_SYNC_END:
+        case VGA_CRTC_MODE:
             s->update_retrace_info(s);
             break;
         }
         break;
-    case 0x3ba:
-    case 0x3da:
+    case VGA_IS1_RM:
+    case VGA_IS1_RC:
         s->fcr = val & 0x10;
         break;
     }
@@ -681,31 +699,37 @@ static void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val)
 
                 /* we initialize the VGA graphic mode (should be done
                    in BIOS) */
-                s->gr[0x06] = (s->gr[0x06] & ~0x0c) | 0x05; /* graphic mode + memory map 1 */
-                s->cr[0x17] |= 3; /* no CGA modes */
-                s->cr[0x13] = s->vbe_line_offset >> 3;
+                /* graphic mode + memory map 1 */
+                s->gr[VGA_GFX_MISC] = (s->gr[VGA_GFX_MISC] & ~0x0c) | 0x04 |
+                    VGA_GR06_GRAPHICS_MODE;
+                s->cr[VGA_CRTC_MODE] |= 3; /* no CGA modes */
+                s->cr[VGA_CRTC_OFFSET] = s->vbe_line_offset >> 3;
                 /* width */
-                s->cr[0x01] = (s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 3) - 1;
+                s->cr[VGA_CRTC_H_DISP] =
+                    (s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 3) - 1;
                 /* height (only meaningful if < 1024) */
                 h = s->vbe_regs[VBE_DISPI_INDEX_YRES] - 1;
-                s->cr[0x12] = h;
-                s->cr[0x07] = (s->cr[0x07] & ~0x42) |
+                s->cr[VGA_CRTC_V_DISP_END] = h;
+                s->cr[VGA_CRTC_OVERFLOW] = (s->cr[VGA_CRTC_OVERFLOW] & ~0x42) |
                     ((h >> 7) & 0x02) | ((h >> 3) & 0x40);
                 /* line compare to 1023 */
-                s->cr[0x18] = 0xff;
-                s->cr[0x07] |= 0x10;
-                s->cr[0x09] |= 0x40;
+                s->cr[VGA_CRTC_LINE_COMPARE] = 0xff;
+                s->cr[VGA_CRTC_OVERFLOW] |= 0x10;
+                s->cr[VGA_CRTC_MAX_SCAN] |= 0x40;
 
                 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
                     shift_control = 0;
-                    s->sr[0x01] &= ~8; /* no double line */
+                    s->sr[VGA_SEQ_CLOCK_MODE] &= ~8; /* no double line */
                 } else {
                     shift_control = 2;
-                    s->sr[4] |= 0x08; /* set chain 4 mode */
-                    s->sr[2] |= 0x0f; /* activate all planes */
+                    /* set chain 4 mode */
+                    s->sr[VGA_SEQ_MEMORY_MODE] |= VGA_SR04_CHN_4M;
+                    /* activate all planes */
+                    s->sr[VGA_SEQ_PLANE_WRITE] |= VGA_SR02_ALL_PLANES;
                 }
-                s->gr[0x05] = (s->gr[0x05] & ~0x60) | (shift_control << 5);
-                s->cr[0x09] &= ~0x9f; /* no double scan */
+                s->gr[VGA_GFX_MODE] = (s->gr[VGA_GFX_MODE] & ~0x60) |
+                    (shift_control << 5);
+                s->cr[VGA_CRTC_MAX_SCAN] &= ~0x9f; /* no double scan */
             } else {
                 /* XXX: the bios should do that */
                 s->bank_offset = 0;
@@ -762,7 +786,7 @@ uint32_t vga_mem_readb(VGACommonState *s, target_phys_addr_t addr)
     uint32_t ret;
 
     /* convert to VGA memory offset */
-    memory_map_mode = (s->gr[6] >> 2) & 3;
+    memory_map_mode = (s->gr[VGA_GFX_MISC] >> 2) & 3;
     addr &= 0x1ffff;
     switch(memory_map_mode) {
     case 0:
@@ -785,24 +809,25 @@ uint32_t vga_mem_readb(VGACommonState *s, target_phys_addr_t addr)
         break;
     }
 
-    if (s->sr[4] & 0x08) {
+    if (s->sr[VGA_SEQ_MEMORY_MODE] & VGA_SR04_CHN_4M) {
         /* chain 4 mode : simplest access */
         ret = s->vram_ptr[addr];
-    } else if (s->gr[5] & 0x10) {
+    } else if (s->gr[VGA_GFX_MODE] & 0x10) {
         /* odd/even mode (aka text mode mapping) */
-        plane = (s->gr[4] & 2) | (addr & 1);
+        plane = (s->gr[VGA_GFX_PLANE_READ] & 2) | (addr & 1);
         ret = s->vram_ptr[((addr & ~1) << 1) | plane];
     } else {
         /* standard VGA latched access */
         s->latch = ((uint32_t *)s->vram_ptr)[addr];
 
-        if (!(s->gr[5] & 0x08)) {
+        if (!(s->gr[VGA_GFX_MODE] & 0x08)) {
             /* read mode 0 */
-            plane = s->gr[4];
+            plane = s->gr[VGA_GFX_PLANE_READ];
             ret = GET_PLANE(s->latch, plane);
         } else {
             /* read mode 1 */
-            ret = (s->latch ^ mask16[s->gr[2]]) & mask16[s->gr[7]];
+            ret = (s->latch ^ mask16[s->gr[VGA_GFX_COMPARE_VALUE]]) &
+                mask16[s->gr[VGA_GFX_COMPARE_MASK]];
             ret |= ret >> 16;
             ret |= ret >> 8;
             ret = (~ret) & 0xff;
@@ -821,7 +846,7 @@ void vga_mem_writeb(VGACommonState *s, target_phys_addr_t addr, uint32_t val)
     printf("vga: [0x" TARGET_FMT_plx "] = 0x%02x\n", addr, val);
 #endif
     /* convert to VGA memory offset */
-    memory_map_mode = (s->gr[6] >> 2) & 3;
+    memory_map_mode = (s->gr[VGA_GFX_MISC] >> 2) & 3;
     addr &= 0x1ffff;
     switch(memory_map_mode) {
     case 0:
@@ -844,67 +869,68 @@ void vga_mem_writeb(VGACommonState *s, target_phys_addr_t addr, uint32_t val)
         break;
     }
 
-    if (s->sr[4] & 0x08) {
+    if (s->sr[VGA_SEQ_MEMORY_MODE] & VGA_SR04_CHN_4M) {
         /* chain 4 mode : simplest access */
         plane = addr & 3;
         mask = (1 << plane);
-        if (s->sr[2] & mask) {
+        if (s->sr[VGA_SEQ_PLANE_WRITE] & mask) {
             s->vram_ptr[addr] = val;
 #ifdef DEBUG_VGA_MEM
             printf("vga: chain4: [0x" TARGET_FMT_plx "]\n", addr);
 #endif
             s->plane_updated |= mask; /* only used to detect font change */
-            memory_region_set_dirty(&s->vram, addr);
+            memory_region_set_dirty(&s->vram, addr, 1);
         }
-    } else if (s->gr[5] & 0x10) {
+    } else if (s->gr[VGA_GFX_MODE] & 0x10) {
         /* odd/even mode (aka text mode mapping) */
-        plane = (s->gr[4] & 2) | (addr & 1);
+        plane = (s->gr[VGA_GFX_PLANE_READ] & 2) | (addr & 1);
         mask = (1 << plane);
-        if (s->sr[2] & mask) {
+        if (s->sr[VGA_SEQ_PLANE_WRITE] & mask) {
             addr = ((addr & ~1) << 1) | plane;
             s->vram_ptr[addr] = val;
 #ifdef DEBUG_VGA_MEM
             printf("vga: odd/even: [0x" TARGET_FMT_plx "]\n", addr);
 #endif
             s->plane_updated |= mask; /* only used to detect font change */
-            memory_region_set_dirty(&s->vram, addr);
+            memory_region_set_dirty(&s->vram, addr, 1);
         }
     } else {
         /* standard VGA latched access */
-        write_mode = s->gr[5] & 3;
+        write_mode = s->gr[VGA_GFX_MODE] & 3;
         switch(write_mode) {
         default:
         case 0:
             /* rotate */
-            b = s->gr[3] & 7;
+            b = s->gr[VGA_GFX_DATA_ROTATE] & 7;
             val = ((val >> b) | (val << (8 - b))) & 0xff;
             val |= val << 8;
             val |= val << 16;
 
             /* apply set/reset mask */
-            set_mask = mask16[s->gr[1]];
-            val = (val & ~set_mask) | (mask16[s->gr[0]] & set_mask);
-            bit_mask = s->gr[8];
+            set_mask = mask16[s->gr[VGA_GFX_SR_ENABLE]];
+            val = (val & ~set_mask) |
+                (mask16[s->gr[VGA_GFX_SR_VALUE]] & set_mask);
+            bit_mask = s->gr[VGA_GFX_BIT_MASK];
             break;
         case 1:
             val = s->latch;
             goto do_write;
         case 2:
             val = mask16[val & 0x0f];
-            bit_mask = s->gr[8];
+            bit_mask = s->gr[VGA_GFX_BIT_MASK];
             break;
         case 3:
             /* rotate */
-            b = s->gr[3] & 7;
+            b = s->gr[VGA_GFX_DATA_ROTATE] & 7;
             val = (val >> b) | (val << (8 - b));
 
-            bit_mask = s->gr[8] & val;
-            val = mask16[s->gr[0]];
+            bit_mask = s->gr[VGA_GFX_BIT_MASK] & val;
+            val = mask16[s->gr[VGA_GFX_SR_VALUE]];
             break;
         }
 
         /* apply logical operation */
-        func_select = s->gr[3] >> 3;
+        func_select = s->gr[VGA_GFX_DATA_ROTATE] >> 3;
         switch(func_select) {
         case 0:
         default:
@@ -931,7 +957,7 @@ void vga_mem_writeb(VGACommonState *s, target_phys_addr_t addr, uint32_t val)
 
     do_write:
         /* mask data according to sr[2] */
-        mask = s->sr[2];
+        mask = s->sr[VGA_SEQ_PLANE_WRITE];
         s->plane_updated |= mask; /* only used to detect font change */
         write_mask = mask16[mask];
         ((uint32_t *)s->vram_ptr)[addr] =
@@ -941,7 +967,7 @@ void vga_mem_writeb(VGACommonState *s, target_phys_addr_t addr, uint32_t val)
         printf("vga: latch: [0x" TARGET_FMT_plx "] mask=0x%08x val=0x%08x\n",
                addr * 4, write_mask, val);
 #endif
-        memory_region_set_dirty(&s->vram, addr << 2);
+        memory_region_set_dirty(&s->vram, addr << 2, sizeof(uint32_t));
     }
 }
 
@@ -1045,10 +1071,11 @@ static int update_palette16(VGACommonState *s)
     palette = s->last_palette;
     for(i = 0; i < 16; i++) {
         v = s->ar[i];
-        if (s->ar[0x10] & 0x80)
-            v = ((s->ar[0x14] & 0xf) << 4) | (v & 0xf);
-        else
-            v = ((s->ar[0x14] & 0xc) << 4) | (v & 0x3f);
+        if (s->ar[VGA_ATC_MODE] & 0x80) {
+            v = ((s->ar[VGA_ATC_COLOR_PAGE] & 0xf) << 4) | (v & 0xf);
+        } else {
+            v = ((s->ar[VGA_ATC_COLOR_PAGE] & 0xc) << 4) | (v & 0x3f);
+        }
         v = v * 3;
         col = s->rgb_to_pixel(c6_to_8(s->palette[v]),
                               c6_to_8(s->palette[v + 1]),
@@ -1104,16 +1131,17 @@ static void vga_get_offsets(VGACommonState *s,
 #endif
     {
         /* compute line_offset in bytes */
-        line_offset = s->cr[0x13];
+        line_offset = s->cr[VGA_CRTC_OFFSET];
         line_offset <<= 3;
 
         /* starting address */
-        start_addr = s->cr[0x0d] | (s->cr[0x0c] << 8);
+        start_addr = s->cr[VGA_CRTC_START_LO] |
+            (s->cr[VGA_CRTC_START_HI] << 8);
 
         /* line compare */
-        line_compare = s->cr[0x18] |
-            ((s->cr[0x07] & 0x10) << 4) |
-            ((s->cr[0x09] & 0x40) << 3);
+        line_compare = s->cr[VGA_CRTC_LINE_COMPARE] |
+            ((s->cr[VGA_CRTC_OVERFLOW] & 0x10) << 4) |
+            ((s->cr[VGA_CRTC_MAX_SCAN] & 0x40) << 3);
     }
     *pline_offset = line_offset;
     *pstart_addr = start_addr;
@@ -1216,20 +1244,22 @@ static void vga_get_text_resolution(VGACommonState *s, int *pwidth, int *pheight
     int width, cwidth, height, cheight;
 
     /* total width & height */
-    cheight = (s->cr[9] & 0x1f) + 1;
+    cheight = (s->cr[VGA_CRTC_MAX_SCAN] & 0x1f) + 1;
     cwidth = 8;
-    if (!(s->sr[1] & 0x01))
+    if (!(s->sr[VGA_SEQ_CLOCK_MODE] & VGA_SR01_CHAR_CLK_8DOTS)) {
         cwidth = 9;
-    if (s->sr[1] & 0x08)
+    }
+    if (s->sr[VGA_SEQ_CLOCK_MODE] & 0x08) {
         cwidth = 16; /* NOTE: no 18 pixel wide */
-    width = (s->cr[0x01] + 1);
-    if (s->cr[0x06] == 100) {
+    }
+    width = (s->cr[VGA_CRTC_H_DISP] + 1);
+    if (s->cr[VGA_CRTC_V_TOTAL] == 100) {
         /* ugly hack for CGA 160x100x16 - explain me the logic */
         height = 100;
     } else {
-        height = s->cr[0x12] |
-            ((s->cr[0x07] & 0x02) << 7) |
-            ((s->cr[0x07] & 0x40) << 3);
+        height = s->cr[VGA_CRTC_V_DISP_END] |
+            ((s->cr[VGA_CRTC_OVERFLOW] & 0x02) << 7) |
+            ((s->cr[VGA_CRTC_OVERFLOW] & 0x40) << 3);
         height = (height + 1) / cheight;
     }
 
@@ -1273,7 +1303,7 @@ static void vga_draw_text(VGACommonState *s, int full_update)
     vga_draw_glyph9_func *vga_draw_glyph9;
 
     /* compute font data address (in plane 2) */
-    v = s->sr[3];
+    v = s->sr[VGA_SEQ_CHARACTER_MAP];
     offset = (((v >> 4) & 1) | ((v << 1) & 6)) * 8192 * 4 + 2;
     if (offset != s->font_offsets[0]) {
         s->font_offsets[0] = offset;
@@ -1321,10 +1351,11 @@ static void vga_draw_text(VGACommonState *s, int full_update)
     palette = s->last_palette;
     x_incr = cw * ((ds_get_bits_per_pixel(s->ds) + 7) >> 3);
 
-    cursor_offset = ((s->cr[0x0e] << 8) | s->cr[0x0f]) - s->start_addr;
+    cursor_offset = ((s->cr[VGA_CRTC_CURSOR_HI] << 8) |
+                     s->cr[VGA_CRTC_CURSOR_LO]) - s->start_addr;
     if (cursor_offset != s->cursor_offset ||
-        s->cr[0xa] != s->cursor_start ||
-        s->cr[0xb] != s->cursor_end) {
+        s->cr[VGA_CRTC_CURSOR_START] != s->cursor_start ||
+        s->cr[VGA_CRTC_CURSOR_END] != s->cursor_end) {
       /* if the cursor position changed, we update the old and new
          chars */
         if (s->cursor_offset < CH_ATTR_SIZE)
@@ -1332,8 +1363,8 @@ static void vga_draw_text(VGACommonState *s, int full_update)
         if (cursor_offset < CH_ATTR_SIZE)
             s->last_ch_attr[cursor_offset] = -1;
         s->cursor_offset = cursor_offset;
-        s->cursor_start = s->cr[0xa];
-        s->cursor_end = s->cr[0xb];
+        s->cursor_start = s->cr[VGA_CRTC_CURSOR_START];
+        s->cursor_end = s->cr[VGA_CRTC_CURSOR_END];
     }
     cursor_ptr = s->vram_ptr + (s->start_addr + cursor_offset) * 4;
 
@@ -1378,17 +1409,19 @@ static void vga_draw_text(VGACommonState *s, int full_update)
                                     font_ptr, cheight, fgcol, bgcol);
                 } else {
                     dup9 = 0;
-                    if (ch >= 0xb0 && ch <= 0xdf && (s->ar[0x10] & 0x04))
+                    if (ch >= 0xb0 && ch <= 0xdf &&
+                        (s->ar[VGA_ATC_MODE] & 0x04)) {
                         dup9 = 1;
+                    }
                     vga_draw_glyph9(d1, linesize,
                                     font_ptr, cheight, fgcol, bgcol, dup9);
                 }
                 if (src == cursor_ptr &&
-                    !(s->cr[0x0a] & 0x20)) {
+                    !(s->cr[VGA_CRTC_CURSOR_START] & 0x20)) {
                     int line_start, line_last, h;
                     /* draw the cursor */
-                    line_start = s->cr[0x0a] & 0x1f;
-                    line_last = s->cr[0x0b] & 0x1f;
+                    line_start = s->cr[VGA_CRTC_CURSOR_START] & 0x1f;
+                    line_last = s->cr[VGA_CRTC_CURSOR_END] & 0x1f;
                     /* XXX: check that */
                     if (line_last > cheight - 1)
                         line_last = cheight - 1;
@@ -1544,10 +1577,10 @@ static void vga_get_resolution(VGACommonState *s, int *pwidth, int *pheight)
     } else
 #endif
     {
-        width = (s->cr[0x01] + 1) * 8;
-        height = s->cr[0x12] |
-            ((s->cr[0x07] & 0x02) << 7) |
-            ((s->cr[0x07] & 0x40) << 3);
+        width = (s->cr[VGA_CRTC_H_DISP] + 1) * 8;
+        height = s->cr[VGA_CRTC_V_DISP_END] |
+            ((s->cr[VGA_CRTC_OVERFLOW] & 0x02) << 7) |
+            ((s->cr[VGA_CRTC_OVERFLOW] & 0x40) << 3);
         height = (height + 1);
     }
     *pwidth = width;
@@ -1602,10 +1635,11 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
     s->get_resolution(s, &width, &height);
     disp_width = width;
 
-    shift_control = (s->gr[0x05] >> 5) & 3;
-    double_scan = (s->cr[0x09] >> 7);
+    shift_control = (s->gr[VGA_GFX_MODE] >> 5) & 3;
+    double_scan = (s->cr[VGA_CRTC_MAX_SCAN] >> 7);
     if (shift_control != 1) {
-        multi_scan = (((s->cr[0x09] & 0x1f) + 1) << double_scan) - 1;
+        multi_scan = (((s->cr[VGA_CRTC_MAX_SCAN] & 0x1f) + 1) << double_scan)
+            - 1;
     } else {
         /* in CGA modes, multi_scan is ignored */
         /* XXX: is it correct ? */
@@ -1620,11 +1654,11 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
     }
 
     if (shift_control == 0) {
-        if (s->sr[0x01] & 8) {
+        if (s->sr[VGA_SEQ_CLOCK_MODE] & 8) {
             disp_width <<= 1;
         }
     } else if (shift_control == 1) {
-        if (s->sr[0x01] & 8) {
+        if (s->sr[VGA_SEQ_CLOCK_MODE] & 8) {
             disp_width <<= 1;
         }
     }
@@ -1668,7 +1702,7 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
 
     if (shift_control == 0) {
         full_update |= update_palette16(s);
-        if (s->sr[0x01] & 8) {
+        if (s->sr[VGA_SEQ_CLOCK_MODE] & 8) {
             v = VGA_DRAW_LINE4D2;
         } else {
             v = VGA_DRAW_LINE4;
@@ -1676,7 +1710,7 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
         bits = 4;
     } else if (shift_control == 1) {
         full_update |= update_palette16(s);
-        if (s->sr[0x01] & 8) {
+        if (s->sr[VGA_SEQ_CLOCK_MODE] & 8) {
             v = VGA_DRAW_LINE2D2;
         } else {
             v = VGA_DRAW_LINE2;
@@ -1721,7 +1755,8 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
     line_offset = s->line_offset;
 #if 0
     printf("w=%d h=%d v=%d line_offset=%d cr[0x09]=0x%02x cr[0x17]=0x%02x linecmp=%d sr[0x01]=0x%02x\n",
-           width, height, v, line_offset, s->cr[9], s->cr[0x17], s->line_compare, s->sr[0x01]);
+           width, height, v, line_offset, s->cr[9], s->cr[VGA_CRTC_MODE],
+           s->line_compare, s->sr[VGA_SEQ_CLOCK_MODE]);
 #endif
     addr1 = (s->start_addr * 4);
     bwidth = (width * bits + 7) / 8;
@@ -1733,26 +1768,19 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
     y1 = 0;
     for(y = 0; y < height; y++) {
         addr = addr1;
-        if (!(s->cr[0x17] & 1)) {
+        if (!(s->cr[VGA_CRTC_MODE] & 1)) {
             int shift;
             /* CGA compatibility handling */
-            shift = 14 + ((s->cr[0x17] >> 6) & 1);
+            shift = 14 + ((s->cr[VGA_CRTC_MODE] >> 6) & 1);
             addr = (addr & ~(1 << shift)) | ((y1 & 1) << shift);
         }
-        if (!(s->cr[0x17] & 2)) {
+        if (!(s->cr[VGA_CRTC_MODE] & 2)) {
             addr = (addr & ~0x8000) | ((y1 & 2) << 14);
         }
-        page0 = addr & TARGET_PAGE_MASK;
-        page1 = (addr + bwidth - 1) & TARGET_PAGE_MASK;
-        update = full_update |
-            memory_region_get_dirty(&s->vram, page0, DIRTY_MEMORY_VGA) |
-            memory_region_get_dirty(&s->vram, page1, DIRTY_MEMORY_VGA);
-        if ((page1 - page0) > TARGET_PAGE_SIZE) {
-            /* if wide line, can use another page */
-            update |= memory_region_get_dirty(&s->vram,
-                                              page0 + TARGET_PAGE_SIZE,
-                                              DIRTY_MEMORY_VGA);
-        }
+        page0 = addr;
+        page1 = addr + bwidth - 1;
+        update = memory_region_get_dirty(&s->vram, page0, page1,
+                                         DIRTY_MEMORY_VGA);
         /* explicit invalidation for the hardware cursor */
         update |= (s->invalidated_y_table[y >> 5] >> (y & 0x1f)) & 1;
         if (update) {
@@ -1776,7 +1804,7 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
             }
         }
         if (!multi_run) {
-            mask = (s->cr[0x17] & 3) ^ 3;
+            mask = (s->cr[VGA_CRTC_MODE] & 3) ^ 3;
             if ((y1 & mask) == mask)
                 addr1 += line_offset;
             y1++;
@@ -1798,7 +1826,7 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
     if (page_max >= page_min) {
         memory_region_reset_dirty(&s->vram,
                                   page_min,
-                                  page_max + TARGET_PAGE_SIZE - page_min,
+                                  page_max - page_min,
                                   DIRTY_MEMORY_VGA);
     }
     memset(s->invalidated_y_table, 0, ((height + 31) >> 5) * 4);
@@ -1848,7 +1876,7 @@ static void vga_update_display(void *opaque)
         if (!(s->ar_index & 0x20)) {
             graphic_mode = GMODE_BLANK;
         } else {
-            graphic_mode = s->gr[6] & 1;
+            graphic_mode = s->gr[VGA_GFX_MISC] & VGA_GR06_GRAPHICS_MODE;
         }
         if (graphic_mode != s->graphic_mode) {
             s->graphic_mode = graphic_mode;
@@ -1966,7 +1994,7 @@ static void vga_update_text(void *opaque, console_ch_t *chardata)
     if (!(s->ar_index & 0x20)) {
         graphic_mode = GMODE_BLANK;
     } else {
-        graphic_mode = s->gr[6] & 1;
+        graphic_mode = s->gr[VGA_GFX_MISC] & VGA_GR06_GRAPHICS_MODE;
     }
     if (graphic_mode != s->graphic_mode) {
         s->graphic_mode = graphic_mode;
@@ -1983,20 +2011,22 @@ static void vga_update_text(void *opaque, console_ch_t *chardata)
         full_update |= update_basic_params(s);
 
         /* total width & height */
-        cheight = (s->cr[9] & 0x1f) + 1;
+        cheight = (s->cr[VGA_CRTC_MAX_SCAN] & 0x1f) + 1;
         cw = 8;
-        if (!(s->sr[1] & 0x01))
+        if (!(s->sr[VGA_SEQ_CLOCK_MODE] & VGA_SR01_CHAR_CLK_8DOTS)) {
             cw = 9;
-        if (s->sr[1] & 0x08)
+        }
+        if (s->sr[VGA_SEQ_CLOCK_MODE] & 0x08) {
             cw = 16; /* NOTE: no 18 pixel wide */
-        width = (s->cr[0x01] + 1);
-        if (s->cr[0x06] == 100) {
+        }
+        width = (s->cr[VGA_CRTC_H_DISP] + 1);
+        if (s->cr[VGA_CRTC_V_TOTAL] == 100) {
             /* ugly hack for CGA 160x100x16 - explain me the logic */
             height = 100;
         } else {
-            height = s->cr[0x12] | 
-                ((s->cr[0x07] & 0x02) << 7) | 
-                ((s->cr[0x07] & 0x40) << 3);
+            height = s->cr[VGA_CRTC_V_DISP_END] |
+                ((s->cr[VGA_CRTC_OVERFLOW] & 0x02) << 7) |
+                ((s->cr[VGA_CRTC_OVERFLOW] & 0x40) << 3);
             height = (height + 1) / cheight;
         }
 
@@ -2025,11 +2055,12 @@ static void vga_update_text(void *opaque, console_ch_t *chardata)
         }
 
         /* Update "hardware" cursor */
-        cursor_offset = ((s->cr[0x0e] << 8) | s->cr[0x0f]) - s->start_addr;
+        cursor_offset = ((s->cr[VGA_CRTC_CURSOR_HI] << 8) |
+                         s->cr[VGA_CRTC_CURSOR_LO]) - s->start_addr;
         if (cursor_offset != s->cursor_offset ||
-            s->cr[0xa] != s->cursor_start ||
-            s->cr[0xb] != s->cursor_end || full_update) {
-            cursor_visible = !(s->cr[0xa] & 0x20);
+            s->cr[VGA_CRTC_CURSOR_START] != s->cursor_start ||
+            s->cr[VGA_CRTC_CURSOR_END] != s->cursor_end || full_update) {
+            cursor_visible = !(s->cr[VGA_CRTC_CURSOR_START] & 0x20);
             if (cursor_visible && cursor_offset < size && cursor_offset >= 0)
                 dpy_cursor(s->ds,
                            TEXTMODE_X(cursor_offset),
@@ -2037,8 +2068,8 @@ static void vga_update_text(void *opaque, console_ch_t *chardata)
             else
                 dpy_cursor(s->ds, -1, -1);
             s->cursor_offset = cursor_offset;
-            s->cursor_start = s->cr[0xa];
-            s->cursor_end = s->cr[0xb];
+            s->cursor_start = s->cr[VGA_CRTC_CURSOR_START];
+            s->cursor_end = s->cr[VGA_CRTC_CURSOR_END];
         }
 
         src = (uint32_t *) s->vram_ptr + s->start_addr;
diff --git a/hw/vga.h b/hw/vga.h
new file mode 100644
index 0000000000..d917046da6
--- /dev/null
+++ b/hw/vga.h
@@ -0,0 +1,159 @@
+/*
+ * linux/include/video/vga.h -- standard VGA chipset interaction
+ *
+ * Copyright 1999 Jeff Garzik <jgarzik@pobox.com>
+ *
+ * Copyright history from vga16fb.c:
+ *	Copyright 1999 Ben Pfaff and Petr Vandrovec
+ *	Based on VGA info at http://www.osdever.net/FreeVGA/home.htm
+ *	Based on VESA framebuffer (c) 1998 Gerd Knorr
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License.  See the file COPYING in the main directory of this
+ * archive for more details.
+ *
+ */
+
+#ifndef __linux_video_vga_h__
+#define __linux_video_vga_h__
+
+/* Some of the code below is taken from SVGAlib.  The original,
+   unmodified copyright notice for that code is below. */
+/* VGAlib version 1.2 - (c) 1993 Tommy Frandsen                    */
+/*                                                                 */
+/* This library is free software; you can redistribute it and/or   */
+/* modify it without any restrictions. This library is distributed */
+/* in the hope that it will be useful, but without any warranty.   */
+
+/* Multi-chipset support Copyright 1993 Harm Hanemaayer */
+/* partially copyrighted (C) 1993 by Hartmut Schirmer */
+
+/* VGA data register ports */
+#define VGA_CRT_DC      0x3D5   /* CRT Controller Data Register - color emulation */
+#define VGA_CRT_DM      0x3B5   /* CRT Controller Data Register - mono emulation */
+#define VGA_ATT_R       0x3C1   /* Attribute Controller Data Read Register */
+#define VGA_ATT_W       0x3C0   /* Attribute Controller Data Write Register */
+#define VGA_GFX_D       0x3CF   /* Graphics Controller Data Register */
+#define VGA_SEQ_D       0x3C5   /* Sequencer Data Register */
+#define VGA_MIS_R       0x3CC   /* Misc Output Read Register */
+#define VGA_MIS_W       0x3C2   /* Misc Output Write Register */
+#define VGA_FTC_R       0x3CA   /* Feature Control Read Register */
+#define VGA_IS1_RC      0x3DA   /* Input Status Register 1 - color emulation */
+#define VGA_IS1_RM      0x3BA   /* Input Status Register 1 - mono emulation */
+#define VGA_PEL_D       0x3C9   /* PEL Data Register */
+#define VGA_PEL_MSK     0x3C6   /* PEL mask register */
+
+/* EGA-specific registers */
+#define EGA_GFX_E0      0x3CC   /* Graphics enable processor 0 */
+#define EGA_GFX_E1      0x3CA   /* Graphics enable processor 1 */
+
+/* VGA index register ports */
+#define VGA_CRT_IC      0x3D4   /* CRT Controller Index - color emulation */
+#define VGA_CRT_IM      0x3B4   /* CRT Controller Index - mono emulation */
+#define VGA_ATT_IW      0x3C0   /* Attribute Controller Index & Data Write Register */
+#define VGA_GFX_I       0x3CE   /* Graphics Controller Index */
+#define VGA_SEQ_I       0x3C4   /* Sequencer Index */
+#define VGA_PEL_IW      0x3C8   /* PEL Write Index */
+#define VGA_PEL_IR      0x3C7   /* PEL Read Index */
+
+/* standard VGA indexes max counts */
+#define VGA_CRT_C       0x19    /* Number of CRT Controller Registers */
+#define VGA_ATT_C       0x15    /* Number of Attribute Controller Registers */
+#define VGA_GFX_C       0x09    /* Number of Graphics Controller Registers */
+#define VGA_SEQ_C       0x05    /* Number of Sequencer Registers */
+#define VGA_MIS_C       0x01    /* Number of Misc Output Register */
+
+/* VGA misc register bit masks */
+#define VGA_MIS_COLOR           0x01
+#define VGA_MIS_ENB_MEM_ACCESS  0x02
+#define VGA_MIS_DCLK_28322_720  0x04
+#define VGA_MIS_ENB_PLL_LOAD    (0x04 | 0x08)
+#define VGA_MIS_SEL_HIGH_PAGE   0x20
+
+/* VGA CRT controller register indices */
+#define VGA_CRTC_H_TOTAL        0
+#define VGA_CRTC_H_DISP         1
+#define VGA_CRTC_H_BLANK_START  2
+#define VGA_CRTC_H_BLANK_END    3
+#define VGA_CRTC_H_SYNC_START   4
+#define VGA_CRTC_H_SYNC_END     5
+#define VGA_CRTC_V_TOTAL        6
+#define VGA_CRTC_OVERFLOW       7
+#define VGA_CRTC_PRESET_ROW     8
+#define VGA_CRTC_MAX_SCAN       9
+#define VGA_CRTC_CURSOR_START   0x0A
+#define VGA_CRTC_CURSOR_END     0x0B
+#define VGA_CRTC_START_HI       0x0C
+#define VGA_CRTC_START_LO       0x0D
+#define VGA_CRTC_CURSOR_HI      0x0E
+#define VGA_CRTC_CURSOR_LO      0x0F
+#define VGA_CRTC_V_SYNC_START   0x10
+#define VGA_CRTC_V_SYNC_END     0x11
+#define VGA_CRTC_V_DISP_END     0x12
+#define VGA_CRTC_OFFSET         0x13
+#define VGA_CRTC_UNDERLINE      0x14
+#define VGA_CRTC_V_BLANK_START  0x15
+#define VGA_CRTC_V_BLANK_END    0x16
+#define VGA_CRTC_MODE           0x17
+#define VGA_CRTC_LINE_COMPARE   0x18
+#define VGA_CRTC_REGS           VGA_CRT_C
+
+/* VGA CRT controller bit masks */
+#define VGA_CR11_LOCK_CR0_CR7   0x80 /* lock writes to CR0 - CR7 */
+#define VGA_CR17_H_V_SIGNALS_ENABLED 0x80
+
+/* VGA attribute controller register indices */
+#define VGA_ATC_PALETTE0        0x00
+#define VGA_ATC_PALETTE1        0x01
+#define VGA_ATC_PALETTE2        0x02
+#define VGA_ATC_PALETTE3        0x03
+#define VGA_ATC_PALETTE4        0x04
+#define VGA_ATC_PALETTE5        0x05
+#define VGA_ATC_PALETTE6        0x06
+#define VGA_ATC_PALETTE7        0x07
+#define VGA_ATC_PALETTE8        0x08
+#define VGA_ATC_PALETTE9        0x09
+#define VGA_ATC_PALETTEA        0x0A
+#define VGA_ATC_PALETTEB        0x0B
+#define VGA_ATC_PALETTEC        0x0C
+#define VGA_ATC_PALETTED        0x0D
+#define VGA_ATC_PALETTEE        0x0E
+#define VGA_ATC_PALETTEF        0x0F
+#define VGA_ATC_MODE            0x10
+#define VGA_ATC_OVERSCAN        0x11
+#define VGA_ATC_PLANE_ENABLE    0x12
+#define VGA_ATC_PEL             0x13
+#define VGA_ATC_COLOR_PAGE      0x14
+
+#define VGA_AR_ENABLE_DISPLAY   0x20
+
+/* VGA sequencer register indices */
+#define VGA_SEQ_RESET           0x00
+#define VGA_SEQ_CLOCK_MODE      0x01
+#define VGA_SEQ_PLANE_WRITE     0x02
+#define VGA_SEQ_CHARACTER_MAP   0x03
+#define VGA_SEQ_MEMORY_MODE     0x04
+
+/* VGA sequencer register bit masks */
+#define VGA_SR01_CHAR_CLK_8DOTS 0x01 /* bit 0: character clocks 8 dots wide are generated */
+#define VGA_SR01_SCREEN_OFF     0x20 /* bit 5: Screen is off */
+#define VGA_SR02_ALL_PLANES     0x0F /* bits 3-0: enable access to all planes */
+#define VGA_SR04_EXT_MEM        0x02 /* bit 1: allows complete mem access to 256K */
+#define VGA_SR04_SEQ_MODE       0x04 /* bit 2: directs system to use a sequential addressing mode */
+#define VGA_SR04_CHN_4M         0x08 /* bit 3: selects modulo 4 addressing for CPU access to display memory */
+
+/* VGA graphics controller register indices */
+#define VGA_GFX_SR_VALUE        0x00
+#define VGA_GFX_SR_ENABLE       0x01
+#define VGA_GFX_COMPARE_VALUE   0x02
+#define VGA_GFX_DATA_ROTATE     0x03
+#define VGA_GFX_PLANE_READ      0x04
+#define VGA_GFX_MODE            0x05
+#define VGA_GFX_MISC            0x06
+#define VGA_GFX_COMPARE_MASK    0x07
+#define VGA_GFX_BIT_MASK        0x08
+
+/* VGA graphics controller bit masks */
+#define VGA_GR06_GRAPHICS_MODE  0x01
+
+#endif /* __linux_video_vga_h__ */
diff --git a/hw/vga_int.h b/hw/vga_int.h
index c1e700fa0b..7685b2b167 100644
--- a/hw/vga_int.h
+++ b/hw/vga_int.h
@@ -25,9 +25,6 @@
 #include <hw/hw.h>
 #include "memory.h"
 
-#define MSR_COLOR_EMULATION 0x01
-#define MSR_PAGE_SELECT     0x20
-
 #define ST01_V_RETRACE      0x08
 #define ST01_DISP_ENABLE    0x01
 
@@ -205,19 +202,6 @@ void vga_mem_writeb(VGACommonState *s, target_phys_addr_t addr, uint32_t val);
 void vga_invalidate_scanlines(VGACommonState *s, int y1, int y2);
 int ppm_save(const char *filename, struct DisplaySurface *ds);
 
-void vga_draw_cursor_line_8(uint8_t *d1, const uint8_t *src1,
-                            int poffset, int w,
-                            unsigned int color0, unsigned int color1,
-                            unsigned int color_xor);
-void vga_draw_cursor_line_16(uint8_t *d1, const uint8_t *src1,
-                             int poffset, int w,
-                             unsigned int color0, unsigned int color1,
-                             unsigned int color_xor);
-void vga_draw_cursor_line_32(uint8_t *d1, const uint8_t *src1,
-                             int poffset, int w,
-                             unsigned int color0, unsigned int color1,
-                             unsigned int color_xor);
-
 int vga_ioport_invalid(VGACommonState *s, uint32_t addr);
 void vga_init_vbe(VGACommonState *s, MemoryRegion *address_space);
 
diff --git a/hw/vga_template.h b/hw/vga_template.h
index 681425f9a2..f6f6a01d84 100644
--- a/hw/vga_template.h
+++ b/hw/vga_template.h
@@ -161,7 +161,7 @@ static void glue(vga_draw_line2_, DEPTH)(VGACommonState *s1, uint8_t *d,
     int x;
 
     palette = s1->last_palette;
-    plane_mask = mask16[s1->ar[0x12] & 0xf];
+    plane_mask = mask16[s1->ar[VGA_ATC_PLANE_ENABLE] & 0xf];
     width >>= 3;
     for(x = 0; x < width; x++) {
         data = ((uint32_t *)s)[0];
@@ -203,7 +203,7 @@ static void glue(vga_draw_line2d2_, DEPTH)(VGACommonState *s1, uint8_t *d,
     int x;
 
     palette = s1->last_palette;
-    plane_mask = mask16[s1->ar[0x12] & 0xf];
+    plane_mask = mask16[s1->ar[VGA_ATC_PLANE_ENABLE] & 0xf];
     width >>= 3;
     for(x = 0; x < width; x++) {
         data = ((uint32_t *)s)[0];
@@ -236,7 +236,7 @@ static void glue(vga_draw_line4_, DEPTH)(VGACommonState *s1, uint8_t *d,
     int x;
 
     palette = s1->last_palette;
-    plane_mask = mask16[s1->ar[0x12] & 0xf];
+    plane_mask = mask16[s1->ar[VGA_ATC_PLANE_ENABLE] & 0xf];
     width >>= 3;
     for(x = 0; x < width; x++) {
         data = ((uint32_t *)s)[0];
@@ -268,7 +268,7 @@ static void glue(vga_draw_line4d2_, DEPTH)(VGACommonState *s1, uint8_t *d,
     int x;
 
     palette = s1->last_palette;
-    plane_mask = mask16[s1->ar[0x12] & 0xf];
+    plane_mask = mask16[s1->ar[VGA_ATC_PLANE_ENABLE] & 0xf];
     width >>= 3;
     for(x = 0; x < width; x++) {
         data = ((uint32_t *)s)[0];
@@ -340,72 +340,6 @@ static void glue(vga_draw_line8_, DEPTH)(VGACommonState *s1, uint8_t *d,
     }
 }
 
-void glue(vga_draw_cursor_line_, DEPTH)(uint8_t *d1,
-                                        const uint8_t *src1,
-                                        int poffset, int w,
-                                        unsigned int color0,
-                                        unsigned int color1,
-                                        unsigned int color_xor)
-{
-    const uint8_t *plane0, *plane1;
-    int x, b0, b1;
-    uint8_t *d;
-
-    d = d1;
-    plane0 = src1;
-    plane1 = src1 + poffset;
-    for(x = 0; x < w; x++) {
-        b0 = (plane0[x >> 3] >> (7 - (x & 7))) & 1;
-        b1 = (plane1[x >> 3] >> (7 - (x & 7))) & 1;
-#if DEPTH == 8
-        switch(b0 | (b1 << 1)) {
-        case 0:
-            break;
-        case 1:
-            d[0] ^= color_xor;
-            break;
-        case 2:
-            d[0] = color0;
-            break;
-        case 3:
-            d[0] = color1;
-            break;
-        }
-#elif DEPTH == 16
-        switch(b0 | (b1 << 1)) {
-        case 0:
-            break;
-        case 1:
-            ((uint16_t *)d)[0] ^= color_xor;
-            break;
-        case 2:
-            ((uint16_t *)d)[0] = color0;
-            break;
-        case 3:
-            ((uint16_t *)d)[0] = color1;
-            break;
-        }
-#elif DEPTH == 32
-        switch(b0 | (b1 << 1)) {
-        case 0:
-            break;
-        case 1:
-            ((uint32_t *)d)[0] ^= color_xor;
-            break;
-        case 2:
-            ((uint32_t *)d)[0] = color0;
-            break;
-        case 3:
-            ((uint32_t *)d)[0] = color1;
-            break;
-        }
-#else
-#error unsupported depth
-#endif
-        d += BPP;
-    }
-}
-
 #endif /* DEPTH != 15 */
 
 
diff --git a/hw/vhost.c b/hw/vhost.c
index 4778521102..5ece659f4a 100644
--- a/hw/vhost.c
+++ b/hw/vhost.c
@@ -55,7 +55,7 @@ static void vhost_dev_sync_region(struct vhost_dev *dev,
             ram_addr_t ram_addr;
             bit -= 1;
             ram_addr = section->offset_within_region + bit * VHOST_LOG_PAGE;
-            memory_region_set_dirty(section->mr, ram_addr);
+            memory_region_set_dirty(section->mr, ram_addr, VHOST_LOG_PAGE);
             log &= ~(0x1ull << bit);
         }
         addr += VHOST_LOG_CHUNK;
diff --git a/hw/virtex_ml507.c b/hw/virtex_ml507.c
index bd16b97934..f8d2b1be04 100644
--- a/hw/virtex_ml507.c
+++ b/hw/virtex_ml507.c
@@ -38,7 +38,6 @@
 
 #include "ppc.h"
 #include "ppc4xx.h"
-#include "ppc440.h"
 #include "ppc405.h"
 
 #include "blockdev.h"
diff --git a/hw/virtio-blk.c b/hw/virtio-blk.c
index 5b416c36ee..a5a439668b 100644
--- a/hw/virtio-blk.c
+++ b/hw/virtio-blk.c
@@ -346,6 +346,8 @@ static void virtio_blk_handle_read(VirtIOBlockReq *req)
 
     bdrv_acct_start(req->dev->bs, &req->acct, req->qiov.size, BDRV_ACCT_READ);
 
+    trace_virtio_blk_handle_read(req, sector, req->qiov.size / 512);
+
     if (sector & req->dev->sector_mask) {
         virtio_blk_rw_complete(req, -EIO);
         return;
diff --git a/hw/virtio-console.c b/hw/virtio-console.c
index 0b28a30b8c..4f2c3e4379 100644
--- a/hw/virtio-console.c
+++ b/hw/virtio-console.c
@@ -109,10 +109,9 @@ static void chr_event(void *opaque, int event)
 static int virtconsole_initfn(VirtIOSerialPort *port)
 {
     VirtConsole *vcon = DO_UPCAST(VirtConsole, port, port);
-    VirtIOSerialPortInfo *info = DO_UPCAST(VirtIOSerialPortInfo, qdev,
-                                           vcon->port.dev.info);
+    VirtIOSerialPortClass *k = VIRTIO_SERIAL_PORT_GET_CLASS(port);
 
-    if (port->id == 0 && !info->is_console) {
+    if (port->id == 0 && !k->is_console) {
         error_report("Port number 0 on virtio-serial devices reserved for virtconsole devices for backward compatibility.");
         return -1;
     }
@@ -125,41 +124,63 @@ static int virtconsole_initfn(VirtIOSerialPort *port)
     return 0;
 }
 
-static VirtIOSerialPortInfo virtconsole_info = {
-    .qdev.name     = "virtconsole",
-    .qdev.size     = sizeof(VirtConsole),
-    .is_console    = true,
-    .init          = virtconsole_initfn,
-    .have_data     = flush_buf,
-    .guest_open    = guest_open,
-    .guest_close   = guest_close,
-    .qdev.props = (Property[]) {
-        DEFINE_PROP_CHR("chardev", VirtConsole, chr),
-        DEFINE_PROP_END_OF_LIST(),
-    },
+static Property virtconsole_properties[] = {
+    DEFINE_PROP_CHR("chardev", VirtConsole, chr),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void virtconsole_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    VirtIOSerialPortClass *k = VIRTIO_SERIAL_PORT_CLASS(klass);
+
+    k->is_console = true;
+    k->init = virtconsole_initfn;
+    k->have_data = flush_buf;
+    k->guest_open = guest_open;
+    k->guest_close = guest_close;
+    dc->props = virtconsole_properties;
+}
+
+static TypeInfo virtconsole_info = {
+    .name          = "virtconsole",
+    .parent        = TYPE_VIRTIO_SERIAL_PORT,
+    .instance_size = sizeof(VirtConsole),
+    .class_init    = virtconsole_class_init,
 };
 
 static void virtconsole_register(void)
 {
-    virtio_serial_port_qdev_register(&virtconsole_info);
+    type_register_static(&virtconsole_info);
 }
 device_init(virtconsole_register)
 
-static VirtIOSerialPortInfo virtserialport_info = {
-    .qdev.name     = "virtserialport",
-    .qdev.size     = sizeof(VirtConsole),
-    .init          = virtconsole_initfn,
-    .have_data     = flush_buf,
-    .guest_open    = guest_open,
-    .guest_close   = guest_close,
-    .qdev.props = (Property[]) {
-        DEFINE_PROP_CHR("chardev", VirtConsole, chr),
-        DEFINE_PROP_END_OF_LIST(),
-    },
+static Property virtserialport_properties[] = {
+    DEFINE_PROP_CHR("chardev", VirtConsole, chr),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void virtserialport_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    VirtIOSerialPortClass *k = VIRTIO_SERIAL_PORT_CLASS(klass);
+
+    k->init = virtconsole_initfn;
+    k->have_data = flush_buf;
+    k->guest_open = guest_open;
+    k->guest_close = guest_close;
+    dc->props = virtserialport_properties;
+}
+
+static TypeInfo virtserialport_info = {
+    .name          = "virtserialport",
+    .parent        = TYPE_VIRTIO_SERIAL_PORT,
+    .instance_size = sizeof(VirtConsole),
+    .class_init    = virtserialport_class_init,
 };
 
 static void virtserialport_register(void)
 {
-    virtio_serial_port_qdev_register(&virtserialport_info);
+    type_register_static(&virtserialport_info);
 }
 device_init(virtserialport_register)
diff --git a/hw/virtio-net.c b/hw/virtio-net.c
index 8c2f460147..bc5e3a83d1 100644
--- a/hw/virtio-net.c
+++ b/hw/virtio-net.c
@@ -1030,7 +1030,7 @@ VirtIODevice *virtio_net_init(DeviceState *dev, NICConf *conf,
     memcpy(&n->mac[0], &conf->macaddr, sizeof(n->mac));
     n->status = VIRTIO_NET_S_LINK_UP;
 
-    n->nic = qemu_new_nic(&net_virtio_info, conf, dev->info->name, dev->id, n);
+    n->nic = qemu_new_nic(&net_virtio_info, conf, object_get_typename(OBJECT(dev)), dev->id, n);
 
     qemu_format_nic_info_str(&n->nic->nc, conf->macaddr.a);
 
diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c
index caff0aa2eb..93fff54782 100644
--- a/hw/virtio-pci.c
+++ b/hw/virtio-pci.c
@@ -91,6 +91,9 @@
  */
 #define wmb() do { } while (0)
 
+/* HACK for virtio to determine if it's running a big endian guest */
+bool virtio_is_big_endian(void);
+
 /* virtio device */
 
 static void virtio_pci_notify(void *opaque, uint16_t vector)
@@ -414,20 +417,35 @@ static uint32_t virtio_pci_config_readw(void *opaque, uint32_t addr)
 {
     VirtIOPCIProxy *proxy = opaque;
     uint32_t config = VIRTIO_PCI_CONFIG(&proxy->pci_dev);
+    uint16_t val;
     if (addr < config)
         return virtio_ioport_read(proxy, addr);
     addr -= config;
-    return virtio_config_readw(proxy->vdev, addr);
+    val = virtio_config_readw(proxy->vdev, addr);
+    if (virtio_is_big_endian()) {
+        /*
+         * virtio is odd, ioports are LE but config space is target native
+         * endian. However, in qemu, all PIO is LE, so we need to re-swap
+         * on BE targets
+         */
+        val = bswap16(val);
+    }
+    return val;
 }
 
 static uint32_t virtio_pci_config_readl(void *opaque, uint32_t addr)
 {
     VirtIOPCIProxy *proxy = opaque;
     uint32_t config = VIRTIO_PCI_CONFIG(&proxy->pci_dev);
+    uint32_t val;
     if (addr < config)
         return virtio_ioport_read(proxy, addr);
     addr -= config;
-    return virtio_config_readl(proxy->vdev, addr);
+    val = virtio_config_readl(proxy->vdev, addr);
+    if (virtio_is_big_endian()) {
+        val = bswap32(val);
+    }
+    return val;
 }
 
 static void virtio_pci_config_writeb(void *opaque, uint32_t addr, uint32_t val)
@@ -451,6 +469,9 @@ static void virtio_pci_config_writew(void *opaque, uint32_t addr, uint32_t val)
         return;
     }
     addr -= config;
+    if (virtio_is_big_endian()) {
+        val = bswap16(val);
+    }
     virtio_config_writew(proxy->vdev, addr, val);
 }
 
@@ -463,6 +484,9 @@ static void virtio_pci_config_writel(void *opaque, uint32_t addr, uint32_t val)
         return;
     }
     addr -= config;
+    if (virtio_is_big_endian()) {
+        val = bswap32(val);
+    }
     virtio_config_writel(proxy->vdev, addr, val);
 }
 
@@ -782,98 +806,136 @@ static int virtio_balloon_exit_pci(PCIDevice *pci_dev)
     return virtio_exit_pci(pci_dev);
 }
 
-static PCIDeviceInfo virtio_info[] = {
-    {
-        .qdev.name = "virtio-blk-pci",
-        .qdev.alias = "virtio-blk",
-        .qdev.size = sizeof(VirtIOPCIProxy),
-        .init      = virtio_blk_init_pci,
-        .exit      = virtio_blk_exit_pci,
-        .vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET,
-        .device_id = PCI_DEVICE_ID_VIRTIO_BLOCK,
-        .revision  = VIRTIO_PCI_ABI_VERSION,
-        .class_id  = PCI_CLASS_STORAGE_SCSI,
-        .qdev.props = (Property[]) {
-            DEFINE_PROP_HEX32("class", VirtIOPCIProxy, class_code, 0),
-            DEFINE_BLOCK_PROPERTIES(VirtIOPCIProxy, block),
-            DEFINE_PROP_STRING("serial", VirtIOPCIProxy, block_serial),
-            DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
-                            VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
-            DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2),
-            DEFINE_VIRTIO_BLK_FEATURES(VirtIOPCIProxy, host_features),
-            DEFINE_PROP_END_OF_LIST(),
-        },
-        .qdev.reset = virtio_pci_reset,
-    },{
-        .qdev.name  = "virtio-net-pci",
-        .qdev.alias = "virtio-net",
-        .qdev.size  = sizeof(VirtIOPCIProxy),
-        .init       = virtio_net_init_pci,
-        .exit       = virtio_net_exit_pci,
-        .romfile    = "pxe-virtio.rom",
-        .vendor_id  = PCI_VENDOR_ID_REDHAT_QUMRANET,
-        .device_id  = PCI_DEVICE_ID_VIRTIO_NET,
-        .revision   = VIRTIO_PCI_ABI_VERSION,
-        .class_id   = PCI_CLASS_NETWORK_ETHERNET,
-        .qdev.props = (Property[]) {
-            DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
-                            VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, false),
-            DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 3),
-            DEFINE_VIRTIO_NET_FEATURES(VirtIOPCIProxy, host_features),
-            DEFINE_NIC_PROPERTIES(VirtIOPCIProxy, nic),
-            DEFINE_PROP_UINT32("x-txtimer", VirtIOPCIProxy,
-                               net.txtimer, TX_TIMER_INTERVAL),
-            DEFINE_PROP_INT32("x-txburst", VirtIOPCIProxy,
-                              net.txburst, TX_BURST),
-            DEFINE_PROP_STRING("tx", VirtIOPCIProxy, net.tx),
-            DEFINE_PROP_END_OF_LIST(),
-        },
-        .qdev.reset = virtio_pci_reset,
-    },{
-        .qdev.name = "virtio-serial-pci",
-        .qdev.alias = "virtio-serial",
-        .qdev.size = sizeof(VirtIOPCIProxy),
-        .init      = virtio_serial_init_pci,
-        .exit      = virtio_serial_exit_pci,
-        .vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET,
-        .device_id = PCI_DEVICE_ID_VIRTIO_CONSOLE,
-        .revision  = VIRTIO_PCI_ABI_VERSION,
-        .class_id  = PCI_CLASS_COMMUNICATION_OTHER,
-        .qdev.props = (Property[]) {
-            DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
-                            VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
-            DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors,
-                               DEV_NVECTORS_UNSPECIFIED),
-            DEFINE_PROP_HEX32("class", VirtIOPCIProxy, class_code, 0),
-            DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features),
-            DEFINE_PROP_UINT32("max_ports", VirtIOPCIProxy,
-                               serial.max_virtserial_ports, 31),
-            DEFINE_PROP_END_OF_LIST(),
-        },
-        .qdev.reset = virtio_pci_reset,
-    },{
-        .qdev.name = "virtio-balloon-pci",
-        .qdev.alias = "virtio-balloon",
-        .qdev.size = sizeof(VirtIOPCIProxy),
-        .init      = virtio_balloon_init_pci,
-        .exit      = virtio_balloon_exit_pci,
-        .vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET,
-        .device_id = PCI_DEVICE_ID_VIRTIO_BALLOON,
-        .revision  = VIRTIO_PCI_ABI_VERSION,
-        .class_id  = PCI_CLASS_MEMORY_RAM,
-        .qdev.props = (Property[]) {
-            DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features),
-            DEFINE_PROP_END_OF_LIST(),
-        },
-        .qdev.reset = virtio_pci_reset,
-    },{
-        /* end of list */
-    }
+static Property virtio_blk_properties[] = {
+    DEFINE_PROP_HEX32("class", VirtIOPCIProxy, class_code, 0),
+    DEFINE_BLOCK_PROPERTIES(VirtIOPCIProxy, block),
+    DEFINE_PROP_STRING("serial", VirtIOPCIProxy, block_serial),
+    DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags, VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
+    DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2),
+    DEFINE_VIRTIO_BLK_FEATURES(VirtIOPCIProxy, host_features),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void virtio_blk_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->init = virtio_blk_init_pci;
+    k->exit = virtio_blk_exit_pci;
+    k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
+    k->device_id = PCI_DEVICE_ID_VIRTIO_BLOCK;
+    k->revision = VIRTIO_PCI_ABI_VERSION;
+    k->class_id = PCI_CLASS_STORAGE_SCSI;
+    dc->reset = virtio_pci_reset;
+    dc->props = virtio_blk_properties;
+}
+
+static TypeInfo virtio_blk_info = {
+    .name          = "virtio-blk-pci",
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(VirtIOPCIProxy),
+    .class_init    = virtio_blk_class_init,
+};
+
+static Property virtio_net_properties[] = {
+    DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags, VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, false),
+    DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 3),
+    DEFINE_VIRTIO_NET_FEATURES(VirtIOPCIProxy, host_features),
+    DEFINE_NIC_PROPERTIES(VirtIOPCIProxy, nic),
+    DEFINE_PROP_UINT32("x-txtimer", VirtIOPCIProxy, net.txtimer, TX_TIMER_INTERVAL),
+    DEFINE_PROP_INT32("x-txburst", VirtIOPCIProxy, net.txburst, TX_BURST),
+    DEFINE_PROP_STRING("tx", VirtIOPCIProxy, net.tx),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void virtio_net_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->init = virtio_net_init_pci;
+    k->exit = virtio_net_exit_pci;
+    k->romfile = "pxe-virtio.rom";
+    k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
+    k->device_id = PCI_DEVICE_ID_VIRTIO_NET;
+    k->revision = VIRTIO_PCI_ABI_VERSION;
+    k->class_id = PCI_CLASS_NETWORK_ETHERNET;
+    dc->reset = virtio_pci_reset;
+    dc->props = virtio_net_properties;
+}
+
+static TypeInfo virtio_net_info = {
+    .name          = "virtio-net-pci",
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(VirtIOPCIProxy),
+    .class_init    = virtio_net_class_init,
+};
+
+static Property virtio_serial_properties[] = {
+    DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags, VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
+    DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, DEV_NVECTORS_UNSPECIFIED),
+    DEFINE_PROP_HEX32("class", VirtIOPCIProxy, class_code, 0),
+    DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features),
+    DEFINE_PROP_UINT32("max_ports", VirtIOPCIProxy, serial.max_virtserial_ports, 31),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void virtio_serial_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->init = virtio_serial_init_pci;
+    k->exit = virtio_serial_exit_pci;
+    k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
+    k->device_id = PCI_DEVICE_ID_VIRTIO_CONSOLE;
+    k->revision = VIRTIO_PCI_ABI_VERSION;
+    k->class_id = PCI_CLASS_COMMUNICATION_OTHER;
+    dc->reset = virtio_pci_reset;
+    dc->props = virtio_serial_properties;
+}
+
+static TypeInfo virtio_serial_info = {
+    .name          = "virtio-serial-pci",
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(VirtIOPCIProxy),
+    .class_init    = virtio_serial_class_init,
+};
+
+static Property virtio_balloon_properties[] = {
+    DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void virtio_balloon_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->init = virtio_balloon_init_pci;
+    k->exit = virtio_balloon_exit_pci;
+    k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
+    k->device_id = PCI_DEVICE_ID_VIRTIO_BALLOON;
+    k->revision = VIRTIO_PCI_ABI_VERSION;
+    k->class_id = PCI_CLASS_MEMORY_RAM;
+    dc->reset = virtio_pci_reset;
+    dc->props = virtio_balloon_properties;
+}
+
+static TypeInfo virtio_balloon_info = {
+    .name          = "virtio-balloon-pci",
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(VirtIOPCIProxy),
+    .class_init    = virtio_balloon_class_init,
 };
 
 static void virtio_pci_register_devices(void)
 {
-    pci_qdev_register_many(virtio_info);
+    type_register_static(&virtio_blk_info);
+    type_register_static(&virtio_net_info);
+    type_register_static(&virtio_serial_info);
+    type_register_static(&virtio_balloon_info);
 }
 
 device_init(virtio_pci_register_devices)
diff --git a/hw/virtio-serial-bus.c b/hw/virtio-serial-bus.c
index 32e46e98cb..61176299a3 100644
--- a/hw/virtio-serial-bus.c
+++ b/hw/virtio-serial-bus.c
@@ -133,12 +133,12 @@ static void discard_vq_data(VirtQueue *vq, VirtIODevice *vdev)
 static void do_flush_queued_data(VirtIOSerialPort *port, VirtQueue *vq,
                                  VirtIODevice *vdev)
 {
-    VirtIOSerialPortInfo *info;
+    VirtIOSerialPortClass *vsc;
 
     assert(port);
     assert(virtio_queue_ready(vq));
 
-    info = DO_UPCAST(VirtIOSerialPortInfo, qdev, port->dev.info);
+    vsc = VIRTIO_SERIAL_PORT_GET_CLASS(port);
 
     while (!port->throttled) {
         unsigned int i;
@@ -157,7 +157,7 @@ static void do_flush_queued_data(VirtIOSerialPort *port, VirtQueue *vq,
             ssize_t ret;
 
             buf_size = port->elem.out_sg[i].iov_len - port->iov_offset;
-            ret = info->have_data(port,
+            ret = vsc->have_data(port,
                                   port->elem.out_sg[i].iov_base
                                   + port->iov_offset,
                                   buf_size);
@@ -176,7 +176,7 @@ static void do_flush_queued_data(VirtIOSerialPort *port, VirtQueue *vq,
                  * 1: chardevs can notify frondends
                  * 2: the guest driver does not spin in these cases
                  */
-                if (!info->is_console) {
+                if (!vsc->is_console) {
                     virtio_serial_throttle_port(port, true);
                 }
                 port->iov_idx = i;
@@ -331,7 +331,7 @@ void virtio_serial_throttle_port(VirtIOSerialPort *port, bool throttle)
 static void handle_control_message(VirtIOSerial *vser, void *buf, size_t len)
 {
     struct VirtIOSerialPort *port;
-    struct VirtIOSerialPortInfo *info;
+    VirtIOSerialPortClass *vsc;
     struct virtio_console_control cpkt, *gcpkt;
     uint8_t *buffer;
     size_t buffer_len;
@@ -373,7 +373,7 @@ static void handle_control_message(VirtIOSerial *vser, void *buf, size_t len)
 
     trace_virtio_serial_handle_control_message_port(port->id);
 
-    info = DO_UPCAST(VirtIOSerialPortInfo, qdev, port->dev.info);
+    vsc = VIRTIO_SERIAL_PORT_GET_CLASS(port);
 
     switch(cpkt.event) {
     case VIRTIO_CONSOLE_PORT_READY:
@@ -389,7 +389,7 @@ static void handle_control_message(VirtIOSerial *vser, void *buf, size_t len)
          * this port is a console port so that the guest can hook it
          * up to hvc.
          */
-        if (info->is_console) {
+        if (vsc->is_console) {
             send_control_event(port, VIRTIO_CONSOLE_CONSOLE_PORT, 1);
         }
 
@@ -418,21 +418,21 @@ static void handle_control_message(VirtIOSerial *vser, void *buf, size_t len)
          * initialised. If some app is interested in knowing about
          * this event, let it know.
          */
-        if (info->guest_ready) {
-            info->guest_ready(port);
+        if (vsc->guest_ready) {
+            vsc->guest_ready(port);
         }
         break;
 
     case VIRTIO_CONSOLE_PORT_OPEN:
         port->guest_connected = cpkt.value;
-        if (cpkt.value && info->guest_open) {
+        if (cpkt.value && vsc->guest_open) {
             /* Send the guest opened notification if an app is interested */
-            info->guest_open(port);
+            vsc->guest_open(port);
         }
 
-        if (!cpkt.value && info->guest_close) {
+        if (!cpkt.value && vsc->guest_close) {
             /* Send the guest closed notification if an app is interested */
-            info->guest_close(port);
+            vsc->guest_close(port);
         }
         break;
     }
@@ -748,10 +748,10 @@ static void remove_port(VirtIOSerial *vser, uint32_t port_id)
     send_control_event(port, VIRTIO_CONSOLE_PORT_REMOVE, 1);
 }
 
-static int virtser_port_qdev_init(DeviceState *qdev, DeviceInfo *base)
+static int virtser_port_qdev_init(DeviceState *qdev)
 {
     VirtIOSerialPort *port = DO_UPCAST(VirtIOSerialPort, dev, qdev);
-    VirtIOSerialPortInfo *info = DO_UPCAST(VirtIOSerialPortInfo, qdev, base);
+    VirtIOSerialPortClass *vsc = VIRTIO_SERIAL_PORT_GET_CLASS(port);
     VirtIOSerialBus *bus = DO_UPCAST(VirtIOSerialBus, qbus, qdev->parent_bus);
     int ret, max_nr_ports;
     bool plugging_port0;
@@ -759,14 +759,14 @@ static int virtser_port_qdev_init(DeviceState *qdev, DeviceInfo *base)
     port->vser = bus->vser;
     port->bh = qemu_bh_new(flush_queued_data_bh, port);
 
-    assert(info->have_data);
+    assert(vsc->have_data);
 
     /*
      * Is the first console port we're seeing? If so, put it up at
      * location 0. This is done for backward compatibility (old
      * kernel, new qemu).
      */
-    plugging_port0 = info->is_console && !find_port_by_id(port->vser, 0);
+    plugging_port0 = vsc->is_console && !find_port_by_id(port->vser, 0);
 
     if (find_port_by_id(port->vser, port->id)) {
         error_report("virtio-serial-bus: A port already exists at id %u",
@@ -793,7 +793,7 @@ static int virtser_port_qdev_init(DeviceState *qdev, DeviceInfo *base)
         return -1;
     }
 
-    ret = info->init(port);
+    ret = vsc->init(port);
     if (ret) {
         return ret;
     }
@@ -823,8 +823,7 @@ static int virtser_port_qdev_init(DeviceState *qdev, DeviceInfo *base)
 static int virtser_port_qdev_exit(DeviceState *qdev)
 {
     VirtIOSerialPort *port = DO_UPCAST(VirtIOSerialPort, dev, qdev);
-    VirtIOSerialPortInfo *info = DO_UPCAST(VirtIOSerialPortInfo, qdev,
-                                           port->dev.info);
+    VirtIOSerialPortClass *vsc = VIRTIO_SERIAL_PORT_GET_CLASS(port);
     VirtIOSerial *vser = port->vser;
 
     qemu_bh_delete(port->bh);
@@ -832,21 +831,12 @@ static int virtser_port_qdev_exit(DeviceState *qdev)
 
     QTAILQ_REMOVE(&vser->ports, port, next);
 
-    if (info->exit) {
-        info->exit(port);
+    if (vsc->exit) {
+        vsc->exit(port);
     }
     return 0;
 }
 
-void virtio_serial_port_qdev_register(VirtIOSerialPortInfo *info)
-{
-    info->qdev.init = virtser_port_qdev_init;
-    info->qdev.bus_info = &virtser_bus_info;
-    info->qdev.exit = virtser_port_qdev_exit;
-    info->qdev.unplug = qdev_simple_unplug_cb;
-    qdev_register(&info->qdev);
-}
-
 VirtIODevice *virtio_serial_init(DeviceState *dev, virtio_serial_conf *conf)
 {
     VirtIOSerial *vser;
@@ -940,3 +930,28 @@ void virtio_serial_exit(VirtIODevice *vdev)
 
     virtio_cleanup(vdev);
 }
+
+static void virtio_serial_port_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *k = DEVICE_CLASS(klass);
+    k->init = virtser_port_qdev_init;
+    k->bus_info = &virtser_bus_info;
+    k->exit = virtser_port_qdev_exit;
+    k->unplug = qdev_simple_unplug_cb;
+}
+
+static TypeInfo virtio_serial_port_type_info = {
+    .name = TYPE_VIRTIO_SERIAL_PORT,
+    .parent = TYPE_DEVICE,
+    .instance_size = sizeof(VirtIOSerialPort),
+    .abstract = true,
+    .class_size = sizeof(VirtIOSerialPortClass),
+    .class_init = virtio_serial_port_class_init,
+};
+
+static void virtio_serial_register_devices(void)
+{
+    type_register_static(&virtio_serial_port_type_info);
+}
+
+device_init(virtio_serial_register_devices);
diff --git a/hw/virtio-serial.h b/hw/virtio-serial.h
index ab138038c0..16e39820a2 100644
--- a/hw/virtio-serial.h
+++ b/hw/virtio-serial.h
@@ -62,10 +62,52 @@ struct virtio_serial_conf {
 
 /* == In-qemu interface == */
 
+#define TYPE_VIRTIO_SERIAL_PORT "virtio-serial-port"
+#define VIRTIO_SERIAL_PORT(obj) \
+     OBJECT_CHECK(VirtIOSerialPort, (obj), TYPE_VIRTIO_SERIAL_PORT)
+#define VIRTIO_SERIAL_PORT_CLASS(klass) \
+     OBJECT_CLASS_CHECK(VirtIOSerialPortClass, (klass), TYPE_VIRTIO_SERIAL_PORT)
+#define VIRTIO_SERIAL_PORT_GET_CLASS(obj) \
+     OBJECT_GET_CLASS(VirtIOSerialPortClass, (obj), TYPE_VIRTIO_SERIAL_PORT)
+
 typedef struct VirtIOSerial VirtIOSerial;
 typedef struct VirtIOSerialBus VirtIOSerialBus;
 typedef struct VirtIOSerialPort VirtIOSerialPort;
-typedef struct VirtIOSerialPortInfo VirtIOSerialPortInfo;
+
+typedef struct VirtIOSerialPortClass {
+    DeviceClass parent_class;
+
+    /* Is this a device that binds with hvc in the guest? */
+    bool is_console;
+
+    /*
+     * The per-port (or per-app) init function that's called when a
+     * new device is found on the bus.
+     */
+    int (*init)(VirtIOSerialPort *port);
+    /*
+     * Per-port exit function that's called when a port gets
+     * hot-unplugged or removed.
+     */
+    int (*exit)(VirtIOSerialPort *port);
+
+    /* Callbacks for guest events */
+        /* Guest opened device. */
+    void (*guest_open)(VirtIOSerialPort *port);
+        /* Guest closed device. */
+    void (*guest_close)(VirtIOSerialPort *port);
+
+        /* Guest is now ready to accept data (virtqueues set up). */
+    void (*guest_ready)(VirtIOSerialPort *port);
+
+    /*
+     * Guest wrote some data to the port. This data is handed over to
+     * the app via this callback.  The app can return a size less than
+     * 'len'.  In this case, throttling will be enabled for this port.
+     */
+    ssize_t (*have_data)(VirtIOSerialPort *port, const uint8_t *buf,
+                         size_t len);
+} VirtIOSerialPortClass;
 
 /*
  * This is the state that's shared between all the ports.  Some of the
@@ -131,50 +173,9 @@ struct VirtIOSerialPort {
     bool throttled;
 };
 
-struct VirtIOSerialPortInfo {
-    DeviceInfo qdev;
-
-    /* Is this a device that binds with hvc in the guest? */
-    bool is_console;
-
-    /*
-     * The per-port (or per-app) init function that's called when a
-     * new device is found on the bus.
-     */
-    int (*init)(VirtIOSerialPort *port);
-    /*
-     * Per-port exit function that's called when a port gets
-     * hot-unplugged or removed.
-     */
-    int (*exit)(VirtIOSerialPort *port);
-
-    /* Callbacks for guest events */
-        /* Guest opened device. */
-    void (*guest_open)(VirtIOSerialPort *port);
-        /* Guest closed device. */
-    void (*guest_close)(VirtIOSerialPort *port);
-
-        /* Guest is now ready to accept data (virtqueues set up). */
-    void (*guest_ready)(VirtIOSerialPort *port);
-
-    /*
-     * Guest wrote some data to the port. This data is handed over to
-     * the app via this callback.  The app can return a size less than
-     * 'len'.  In this case, throttling will be enabled for this port.
-     */
-    ssize_t (*have_data)(VirtIOSerialPort *port, const uint8_t *buf,
-                         size_t len);
-};
-
 /* Interface to the virtio-serial bus */
 
 /*
- * Individual ports/apps should call this function to register the port
- * with the virtio-serial bus
- */
-void virtio_serial_port_qdev_register(VirtIOSerialPortInfo *info);
-
-/*
  * Open a connection to the port
  *   Returns 0 on success (always).
  */
diff --git a/hw/virtio.c b/hw/virtio.c
index 81ecc40b31..74cc038af9 100644
--- a/hw/virtio.c
+++ b/hw/virtio.c
@@ -539,7 +539,7 @@ uint32_t virtio_config_readb(VirtIODevice *vdev, uint32_t addr)
     if (addr > (vdev->config_len - sizeof(val)))
         return (uint32_t)-1;
 
-    memcpy(&val, vdev->config + addr, sizeof(val));
+    val = ldub_p(vdev->config + addr);
     return val;
 }
 
@@ -552,7 +552,7 @@ uint32_t virtio_config_readw(VirtIODevice *vdev, uint32_t addr)
     if (addr > (vdev->config_len - sizeof(val)))
         return (uint32_t)-1;
 
-    memcpy(&val, vdev->config + addr, sizeof(val));
+    val = lduw_p(vdev->config + addr);
     return val;
 }
 
@@ -565,7 +565,7 @@ uint32_t virtio_config_readl(VirtIODevice *vdev, uint32_t addr)
     if (addr > (vdev->config_len - sizeof(val)))
         return (uint32_t)-1;
 
-    memcpy(&val, vdev->config + addr, sizeof(val));
+    val = ldl_p(vdev->config + addr);
     return val;
 }
 
@@ -576,7 +576,7 @@ void virtio_config_writeb(VirtIODevice *vdev, uint32_t addr, uint32_t data)
     if (addr > (vdev->config_len - sizeof(val)))
         return;
 
-    memcpy(vdev->config + addr, &val, sizeof(val));
+    stb_p(vdev->config + addr, val);
 
     if (vdev->set_config)
         vdev->set_config(vdev, vdev->config);
@@ -589,7 +589,7 @@ void virtio_config_writew(VirtIODevice *vdev, uint32_t addr, uint32_t data)
     if (addr > (vdev->config_len - sizeof(val)))
         return;
 
-    memcpy(vdev->config + addr, &val, sizeof(val));
+    stw_p(vdev->config + addr, val);
 
     if (vdev->set_config)
         vdev->set_config(vdev, vdev->config);
@@ -602,7 +602,7 @@ void virtio_config_writel(VirtIODevice *vdev, uint32_t addr, uint32_t data)
     if (addr > (vdev->config_len - sizeof(val)))
         return;
 
-    memcpy(vdev->config + addr, &val, sizeof(val));
+    stl_p(vdev->config + addr, val);
 
     if (vdev->set_config)
         vdev->set_config(vdev, vdev->config);
diff --git a/hw/vmmouse.c b/hw/vmmouse.c
index 1113f33d68..fda4f89a76 100644
--- a/hw/vmmouse.c
+++ b/hw/vmmouse.c
@@ -254,6 +254,8 @@ static void vmmouse_reset(DeviceState *d)
 
     s->status = 0xffff;
     s->queue_size = VMMOUSE_QUEUE_SIZE;
+
+    vmmouse_disable(s);
 }
 
 static int vmmouse_initfn(ISADevice *dev)
@@ -269,21 +271,31 @@ static int vmmouse_initfn(ISADevice *dev)
     return 0;
 }
 
-static ISADeviceInfo vmmouse_info = {
-    .init          = vmmouse_initfn,
-    .qdev.name     = "vmmouse",
-    .qdev.size     = sizeof(VMMouseState),
-    .qdev.vmsd     = &vmstate_vmmouse,
-    .qdev.no_user  = 1,
-    .qdev.reset    = vmmouse_reset,
-    .qdev.props = (Property[]) {
-        DEFINE_PROP_PTR("ps2_mouse", VMMouseState, ps2_mouse),
-        DEFINE_PROP_END_OF_LIST(),
-    }
+static Property vmmouse_properties[] = {
+    DEFINE_PROP_PTR("ps2_mouse", VMMouseState, ps2_mouse),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void vmmouse_class_initfn(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    ISADeviceClass *ic = ISA_DEVICE_CLASS(klass);
+    ic->init = vmmouse_initfn;
+    dc->no_user = 1;
+    dc->reset = vmmouse_reset;
+    dc->vmsd = &vmstate_vmmouse;
+    dc->props = vmmouse_properties;
+}
+
+static TypeInfo vmmouse_info = {
+    .name          = "vmmouse",
+    .parent        = TYPE_ISA_DEVICE,
+    .instance_size = sizeof(VMMouseState),
+    .class_init    = vmmouse_class_initfn,
 };
 
 static void vmmouse_dev_register(void)
 {
-    isa_qdev_register(&vmmouse_info);
+    type_register_static(&vmmouse_info);
 }
 device_init(vmmouse_dev_register)
diff --git a/hw/vmport.c b/hw/vmport.c
index 0a3dbc5ef5..a2c45e1950 100644
--- a/hw/vmport.c
+++ b/hw/vmport.c
@@ -144,15 +144,23 @@ static int vmport_initfn(ISADevice *dev)
     return 0;
 }
 
-static ISADeviceInfo vmport_info = {
-    .qdev.name     = "vmport",
-    .qdev.size     = sizeof(VMPortState),
-    .qdev.no_user  = 1,
-    .init          = vmport_initfn,
+static void vmport_class_initfn(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    ISADeviceClass *ic = ISA_DEVICE_CLASS(klass);
+    ic->init = vmport_initfn;
+    dc->no_user = 1;
+}
+
+static TypeInfo vmport_info = {
+    .name          = "vmport",
+    .parent        = TYPE_ISA_DEVICE,
+    .instance_size = sizeof(VMPortState),
+    .class_init    = vmport_class_initfn,
 };
 
 static void vmport_dev_register(void)
 {
-    isa_qdev_register(&vmport_info);
+    type_register_static(&vmport_info);
 }
 device_init(vmport_dev_register)
diff --git a/hw/vmware_vga.c b/hw/vmware_vga.c
index b1885c3c19..3f3eb21d02 100644
--- a/hw/vmware_vga.c
+++ b/hw/vmware_vga.c
@@ -1199,24 +1199,32 @@ static int pci_vmsvga_initfn(PCIDevice *dev)
     return 0;
 }
 
-static PCIDeviceInfo vmsvga_info = {
-    .qdev.name    = "vmware-svga",
-    .qdev.size    = sizeof(struct pci_vmsvga_state_s),
-    .qdev.vmsd    = &vmstate_vmware_vga,
-    .qdev.reset   = vmsvga_reset,
-    .no_hotplug   = 1,
-    .init         = pci_vmsvga_initfn,
-    .romfile      = "vgabios-vmware.bin",
-
-    .vendor_id    =  PCI_VENDOR_ID_VMWARE,
-    .device_id    = SVGA_PCI_DEVICE_ID,
-    .class_id     = PCI_CLASS_DISPLAY_VGA,
-    .subsystem_vendor_id = PCI_VENDOR_ID_VMWARE,
-    .subsystem_id = SVGA_PCI_DEVICE_ID,
+static void vmsvga_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->no_hotplug = 1;
+    k->init = pci_vmsvga_initfn;
+    k->romfile = "vgabios-vmware.bin";
+    k->vendor_id = PCI_VENDOR_ID_VMWARE;
+    k->device_id = SVGA_PCI_DEVICE_ID;
+    k->class_id = PCI_CLASS_DISPLAY_VGA;
+    k->subsystem_vendor_id = PCI_VENDOR_ID_VMWARE;
+    k->subsystem_id = SVGA_PCI_DEVICE_ID;
+    dc->reset = vmsvga_reset;
+    dc->vmsd = &vmstate_vmware_vga;
+}
+
+static TypeInfo vmsvga_info = {
+    .name          = "vmware-svga",
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(struct pci_vmsvga_state_s),
+    .class_init    = vmsvga_class_init,
 };
 
 static void vmsvga_register(void)
 {
-    pci_qdev_register(&vmsvga_info);
+    type_register_static(&vmsvga_info);
 }
 device_init(vmsvga_register);
diff --git a/hw/vmware_vga.h b/hw/vmware_vga.h
index db11cbfac8..000fbddc0f 100644
--- a/hw/vmware_vga.h
+++ b/hw/vmware_vga.h
@@ -8,12 +8,8 @@ static inline DeviceState *pci_vmsvga_init(PCIBus *bus)
 {
     PCIDevice *dev;
 
-    dev = pci_try_create(bus, -1, "vmware-svga");
-    if (!dev || qdev_init(&dev->qdev) < 0) {
-        return NULL;
-    } else {
-        return &dev->qdev;
-    }
+    dev = pci_create_simple(bus, -1, "vmware-svga");
+    return &dev->qdev;
 }
 
 #endif
diff --git a/hw/vt82c686.c b/hw/vt82c686.c
index 7fb88a53bf..aa0954f487 100644
--- a/hw/vt82c686.c
+++ b/hw/vt82c686.c
@@ -346,20 +346,29 @@ void vt82c686b_ac97_init(PCIBus *bus, int devfn)
     qdev_init_nofail(&dev->qdev);
 }
 
-static PCIDeviceInfo via_ac97_info = {
-    .qdev.name          = "VT82C686B_AC97",
-    .qdev.desc          = "AC97",
-    .qdev.size          = sizeof(VT686AC97State),
-    .init               = vt82c686b_ac97_initfn,
-    .vendor_id          = PCI_VENDOR_ID_VIA,
-    .device_id          = PCI_DEVICE_ID_VIA_AC97,
-    .revision           = 0x50,
-    .class_id           = PCI_CLASS_MULTIMEDIA_AUDIO,
+static void via_ac97_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->init = vt82c686b_ac97_initfn;
+    k->vendor_id = PCI_VENDOR_ID_VIA;
+    k->device_id = PCI_DEVICE_ID_VIA_AC97;
+    k->revision = 0x50;
+    k->class_id = PCI_CLASS_MULTIMEDIA_AUDIO;
+    dc->desc = "AC97";
+}
+
+static TypeInfo via_ac97_info = {
+    .name          = "VT82C686B_AC97",
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(VT686AC97State),
+    .class_init    = via_ac97_class_init,
 };
 
 static void vt82c686b_ac97_register(void)
 {
-    pci_qdev_register(&via_ac97_info);
+    type_register_static(&via_ac97_info);
 }
 
 device_init(vt82c686b_ac97_register);
@@ -385,20 +394,29 @@ void vt82c686b_mc97_init(PCIBus *bus, int devfn)
     qdev_init_nofail(&dev->qdev);
 }
 
-static PCIDeviceInfo via_mc97_info = {
-    .qdev.name          = "VT82C686B_MC97",
-    .qdev.desc          = "MC97",
-    .qdev.size          = sizeof(VT686MC97State),
-    .init               = vt82c686b_mc97_initfn,
-    .vendor_id          = PCI_VENDOR_ID_VIA,
-    .device_id          = PCI_DEVICE_ID_VIA_MC97,
-    .class_id           = PCI_CLASS_COMMUNICATION_OTHER,
-    .revision           = 0x30,
+static void via_mc97_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->init = vt82c686b_mc97_initfn;
+    k->vendor_id = PCI_VENDOR_ID_VIA;
+    k->device_id = PCI_DEVICE_ID_VIA_MC97;
+    k->class_id = PCI_CLASS_COMMUNICATION_OTHER;
+    k->revision = 0x30;
+    dc->desc = "MC97";
+}
+
+static TypeInfo via_mc97_info = {
+    .name          = "VT82C686B_MC97",
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(VT686MC97State),
+    .class_init    = via_mc97_class_init,
 };
 
 static void vt82c686b_mc97_register(void)
 {
-    pci_qdev_register(&via_mc97_info);
+    type_register_static(&via_mc97_info);
 }
 
 device_init(vt82c686b_mc97_register);
@@ -451,26 +469,37 @@ i2c_bus *vt82c686b_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base,
     return s->smb.smbus;
 }
 
-static PCIDeviceInfo via_pm_info = {
-    .qdev.name          = "VT82C686B_PM",
-    .qdev.desc          = "PM",
-    .qdev.size          = sizeof(VT686PMState),
-    .qdev.vmsd          = &vmstate_acpi,
-    .init               = vt82c686b_pm_initfn,
-    .config_write       = pm_write_config,
-    .vendor_id          = PCI_VENDOR_ID_VIA,
-    .device_id          = PCI_DEVICE_ID_VIA_ACPI,
-    .class_id           = PCI_CLASS_BRIDGE_OTHER,
-    .revision           = 0x40,
-    .qdev.props         = (Property[]) {
-        DEFINE_PROP_UINT32("smb_io_base", VT686PMState, smb_io_base, 0),
-        DEFINE_PROP_END_OF_LIST(),
-    }
+static Property via_pm_properties[] = {
+    DEFINE_PROP_UINT32("smb_io_base", VT686PMState, smb_io_base, 0),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void via_pm_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->init = vt82c686b_pm_initfn;
+    k->config_write = pm_write_config;
+    k->vendor_id = PCI_VENDOR_ID_VIA;
+    k->device_id = PCI_DEVICE_ID_VIA_ACPI;
+    k->class_id = PCI_CLASS_BRIDGE_OTHER;
+    k->revision = 0x40;
+    dc->desc = "PM";
+    dc->vmsd = &vmstate_acpi;
+    dc->props = via_pm_properties;
+}
+
+static TypeInfo via_pm_info = {
+    .name          = "VT82C686B_PM",
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(VT686PMState),
+    .class_init    = via_pm_class_init,
 };
 
 static void vt82c686b_pm_register(void)
 {
-    pci_qdev_register(&via_pm_info);
+    type_register_static(&via_pm_info);
 }
 
 device_init(vt82c686b_pm_register);
@@ -519,22 +548,31 @@ ISABus *vt82c686b_init(PCIBus *bus, int devfn)
     return DO_UPCAST(ISABus, qbus, qdev_get_child_bus(&d->qdev, "isa.0"));
 }
 
-static PCIDeviceInfo via_info = {
-    .qdev.name    = "VT82C686B",
-    .qdev.desc    = "ISA bridge",
-    .qdev.size    = sizeof(VT82C686BState),
-    .qdev.vmsd    = &vmstate_via,
-    .qdev.no_user = 1,
-    .init         = vt82c686b_initfn,
-    .config_write = vt82c686b_write_config,
-    .vendor_id    = PCI_VENDOR_ID_VIA,
-    .device_id    = PCI_DEVICE_ID_VIA_ISA_BRIDGE,
-    .class_id     = PCI_CLASS_BRIDGE_ISA,
-    .revision     = 0x40,
+static void via_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->init = vt82c686b_initfn;
+    k->config_write = vt82c686b_write_config;
+    k->vendor_id = PCI_VENDOR_ID_VIA;
+    k->device_id = PCI_DEVICE_ID_VIA_ISA_BRIDGE;
+    k->class_id = PCI_CLASS_BRIDGE_ISA;
+    k->revision = 0x40;
+    dc->desc = "ISA bridge";
+    dc->no_user = 1;
+    dc->vmsd = &vmstate_via;
+}
+
+static TypeInfo via_info = {
+    .name          = "VT82C686B",
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(VT82C686BState),
+    .class_init    = via_class_init,
 };
 
 static void vt82c686b_register(void)
 {
-    pci_qdev_register(&via_info);
+    type_register_static(&via_info);
 }
 device_init(vt82c686b_register);
diff --git a/hw/wdt_i6300esb.c b/hw/wdt_i6300esb.c
index 20d8673186..41325f0955 100644
--- a/hw/wdt_i6300esb.c
+++ b/hw/wdt_i6300esb.c
@@ -143,7 +143,7 @@ static void i6300esb_disable_timer(I6300State *d)
 
 static void i6300esb_reset(DeviceState *dev)
 {
-    PCIDevice *pdev = DO_UPCAST(PCIDevice, qdev, dev);
+    PCIDevice *pdev = PCI_DEVICE(dev);
     I6300State *d = DO_UPCAST(I6300State, dev, pdev);
 
     i6300esb_debug("I6300State = %p\n", d);
@@ -425,24 +425,33 @@ static WatchdogTimerModel model = {
     .wdt_description = "Intel 6300ESB",
 };
 
-static PCIDeviceInfo i6300esb_info = {
-    .qdev.name    = "i6300esb",
-    .qdev.size    = sizeof(I6300State),
-    .qdev.vmsd    = &vmstate_i6300esb,
-    .qdev.reset   = i6300esb_reset,
-    .config_read  = i6300esb_config_read,
-    .config_write = i6300esb_config_write,
-    .init         = i6300esb_init,
-    .exit         = i6300esb_exit,
-    .vendor_id    = PCI_VENDOR_ID_INTEL,
-    .device_id    = PCI_DEVICE_ID_INTEL_ESB_9,
-    .class_id     = PCI_CLASS_SYSTEM_OTHER,
+static void i6300esb_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->config_read = i6300esb_config_read;
+    k->config_write = i6300esb_config_write;
+    k->init = i6300esb_init;
+    k->exit = i6300esb_exit;
+    k->vendor_id = PCI_VENDOR_ID_INTEL;
+    k->device_id = PCI_DEVICE_ID_INTEL_ESB_9;
+    k->class_id = PCI_CLASS_SYSTEM_OTHER;
+    dc->reset = i6300esb_reset;
+    dc->vmsd = &vmstate_i6300esb;
+}
+
+static TypeInfo i6300esb_info = {
+    .name          = "i6300esb",
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(I6300State),
+    .class_init    = i6300esb_class_init,
 };
 
 static void i6300esb_register_devices(void)
 {
     watchdog_add_model(&model);
-    pci_qdev_register(&i6300esb_info);
+    type_register_static(&i6300esb_info);
 }
 
 device_init(i6300esb_register_devices);
diff --git a/hw/wdt_ib700.c b/hw/wdt_ib700.c
index ba1d92d615..8faa2316c9 100644
--- a/hw/wdt_ib700.c
+++ b/hw/wdt_ib700.c
@@ -120,18 +120,26 @@ static WatchdogTimerModel model = {
     .wdt_description = "iBASE 700",
 };
 
-static ISADeviceInfo wdt_ib700_info = {
-    .qdev.name  = "ib700",
-    .qdev.size  = sizeof(IB700State),
-    .qdev.vmsd  = &vmstate_ib700,
-    .qdev.reset = wdt_ib700_reset,
-    .init       = wdt_ib700_init,
+static void wdt_ib700_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    ISADeviceClass *ic = ISA_DEVICE_CLASS(klass);
+    ic->init = wdt_ib700_init;
+    dc->reset = wdt_ib700_reset;
+    dc->vmsd = &vmstate_ib700;
+}
+
+static TypeInfo wdt_ib700_info = {
+    .name          = "ib700",
+    .parent        = TYPE_ISA_DEVICE,
+    .instance_size = sizeof(IB700State),
+    .class_init    = wdt_ib700_class_init,
 };
 
 static void wdt_ib700_register_devices(void)
 {
     watchdog_add_model(&model);
-    isa_qdev_register(&wdt_ib700_info);
+    type_register_static(&wdt_ib700_info);
 }
 
 device_init(wdt_ib700_register_devices);
diff --git a/hw/wm8750.c b/hw/wm8750.c
index 9fbdf3d54b..18afa4c1ac 100644
--- a/hw/wm8750.c
+++ b/hw/wm8750.c
@@ -24,7 +24,7 @@ typedef struct {
 } WMRate;
 
 typedef struct {
-    i2c_slave i2c;
+    I2CSlave i2c;
     uint8_t i2c_data[2];
     int i2c_len;
     QEMUSoundCard card;
@@ -254,7 +254,7 @@ static void wm8750_clk_update(WM8750State *s, int ext)
     }
 }
 
-static void wm8750_reset(i2c_slave *i2c)
+static void wm8750_reset(I2CSlave *i2c)
 {
     WM8750State *s = (WM8750State *) i2c;
     s->rate = &wm_rate_table[0];
@@ -297,7 +297,7 @@ static void wm8750_reset(i2c_slave *i2c)
     s->i2c_len = 0;
 }
 
-static void wm8750_event(i2c_slave *i2c, enum i2c_event event)
+static void wm8750_event(I2CSlave *i2c, enum i2c_event event)
 {
     WM8750State *s = (WM8750State *) i2c;
 
@@ -354,7 +354,7 @@ static void wm8750_event(i2c_slave *i2c, enum i2c_event event)
 #define WM8750_ROUT2V	0x29
 #define WM8750_MOUTV	0x2a
 
-static int wm8750_tx(i2c_slave *i2c, uint8_t data)
+static int wm8750_tx(I2CSlave *i2c, uint8_t data)
 {
     WM8750State *s = (WM8750State *) i2c;
     uint8_t cmd;
@@ -554,7 +554,7 @@ static int wm8750_tx(i2c_slave *i2c, uint8_t data)
     return 0;
 }
 
-static int wm8750_rx(i2c_slave *i2c)
+static int wm8750_rx(I2CSlave *i2c)
 {
     return 0x00;
 }
@@ -609,7 +609,7 @@ static const VMStateDescription vmstate_wm8750 = {
     }
 };
 
-static int wm8750_init(i2c_slave *i2c)
+static int wm8750_init(I2CSlave *i2c)
 {
     WM8750State *s = FROM_I2C_SLAVE(WM8750State, i2c);
 
@@ -620,7 +620,7 @@ static int wm8750_init(i2c_slave *i2c)
 }
 
 #if 0
-static void wm8750_fini(i2c_slave *i2c)
+static void wm8750_fini(I2CSlave *i2c)
 {
     WM8750State *s = (WM8750State *) i2c;
     wm8750_reset(&s->i2c);
@@ -689,19 +689,28 @@ void wm8750_set_bclk_in(void *opaque, int new_hz)
     wm8750_clk_update(s, 1);
 }
 
-static I2CSlaveInfo wm8750_info = {
-    .qdev.name = "wm8750",
-    .qdev.size = sizeof(WM8750State),
-    .qdev.vmsd = &vmstate_wm8750,
-    .init = wm8750_init,
-    .event = wm8750_event,
-    .recv = wm8750_rx,
-    .send = wm8750_tx
+static void wm8750_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    I2CSlaveClass *sc = I2C_SLAVE_CLASS(klass);
+
+    sc->init = wm8750_init;
+    sc->event = wm8750_event;
+    sc->recv = wm8750_rx;
+    sc->send = wm8750_tx;
+    dc->vmsd = &vmstate_wm8750;
+}
+
+static TypeInfo wm8750_info = {
+    .name          = "wm8750",
+    .parent        = TYPE_I2C_SLAVE,
+    .instance_size = sizeof(WM8750State),
+    .class_init    = wm8750_class_init,
 };
 
 static void wm8750_register_devices(void)
 {
-    i2c_register_slave(&wm8750_info);
+    type_register_static(&wm8750_info);
 }
 
 device_init(wm8750_register_devices)
diff --git a/hw/xen_platform.c b/hw/xen_platform.c
index e62eaef7d1..e7571022e4 100644
--- a/hw/xen_platform.c
+++ b/hw/xen_platform.c
@@ -372,25 +372,33 @@ static void platform_reset(DeviceState *dev)
     platform_fixed_ioport_reset(s);
 }
 
-static PCIDeviceInfo xen_platform_info = {
-    .init = xen_platform_initfn,
-    .qdev.name = "xen-platform",
-    .qdev.desc = "XEN platform pci device",
-    .qdev.size = sizeof(PCIXenPlatformState),
-    .qdev.vmsd = &vmstate_xen_platform,
-    .qdev.reset = platform_reset,
-
-    .vendor_id    =  PCI_VENDOR_ID_XEN,
-    .device_id    = PCI_DEVICE_ID_XEN_PLATFORM,
-    .class_id     = PCI_CLASS_OTHERS << 8 | 0x80,
-    .subsystem_vendor_id = PCI_VENDOR_ID_XEN,
-    .subsystem_id = PCI_DEVICE_ID_XEN_PLATFORM,
-    .revision = 1,
+static void xen_platform_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->init = xen_platform_initfn;
+    k->vendor_id = PCI_VENDOR_ID_XEN;
+    k->device_id = PCI_DEVICE_ID_XEN_PLATFORM;
+    k->class_id = PCI_CLASS_OTHERS << 8 | 0x80;
+    k->subsystem_vendor_id = PCI_VENDOR_ID_XEN;
+    k->subsystem_id = PCI_DEVICE_ID_XEN_PLATFORM;
+    k->revision = 1;
+    dc->desc = "XEN platform pci device";
+    dc->reset = platform_reset;
+    dc->vmsd = &vmstate_xen_platform;
+}
+
+static TypeInfo xen_platform_info = {
+    .name          = "xen-platform",
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(PCIXenPlatformState),
+    .class_init    = xen_platform_class_init,
 };
 
 static void xen_platform_register(void)
 {
-    pci_qdev_register(&xen_platform_info);
+    type_register_static(&xen_platform_info);
 }
 
 device_init(xen_platform_register);
diff --git a/hw/xgmac.c b/hw/xgmac.c
new file mode 100644
index 0000000000..d395b1cc2d
--- /dev/null
+++ b/hw/xgmac.c
@@ -0,0 +1,433 @@
+/*
+ * QEMU model of XGMAC Ethernet.
+ *
+ * derived from the Xilinx AXI-Ethernet by Edgar E. Iglesias.
+ *
+ * Copyright (c) 2011 Calxeda, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "sysbus.h"
+#include "qemu-char.h"
+#include "qemu-log.h"
+#include "net.h"
+#include "net/checksum.h"
+
+#ifdef DEBUG_XGMAC
+#define DEBUGF_BRK(message, args...) do { \
+                                         fprintf(stderr, (message), ## args); \
+                                     } while (0)
+#else
+#define DEBUGF_BRK(message, args...) do { } while (0)
+#endif
+
+#define XGMAC_CONTROL           0x00000000   /* MAC Configuration */
+#define XGMAC_FRAME_FILTER      0x00000001   /* MAC Frame Filter */
+#define XGMAC_FLOW_CTRL         0x00000006   /* MAC Flow Control */
+#define XGMAC_VLAN_TAG          0x00000007   /* VLAN Tags */
+#define XGMAC_VERSION           0x00000008   /* Version */
+/* VLAN tag for insertion or replacement into tx frames */
+#define XGMAC_VLAN_INCL         0x00000009
+#define XGMAC_LPI_CTRL          0x0000000a   /* LPI Control and Status */
+#define XGMAC_LPI_TIMER         0x0000000b   /* LPI Timers Control */
+#define XGMAC_TX_PACE           0x0000000c   /* Transmit Pace and Stretch */
+#define XGMAC_VLAN_HASH         0x0000000d   /* VLAN Hash Table */
+#define XGMAC_DEBUG             0x0000000e   /* Debug */
+#define XGMAC_INT_STATUS        0x0000000f   /* Interrupt and Control */
+/* HASH table registers */
+#define XGMAC_HASH(n)           ((0x00000300/4) + (n))
+#define XGMAC_NUM_HASH          16
+/* Operation Mode */
+#define XGMAC_OPMODE            (0x00000400/4)
+/* Remote Wake-Up Frame Filter */
+#define XGMAC_REMOTE_WAKE       (0x00000700/4)
+/* PMT Control and Status */
+#define XGMAC_PMT               (0x00000704/4)
+
+#define XGMAC_ADDR_HIGH(reg)    (0x00000010+((reg) * 2))
+#define XGMAC_ADDR_LOW(reg)     (0x00000011+((reg) * 2))
+
+#define DMA_BUS_MODE            0x000003c0   /* Bus Mode */
+#define DMA_XMT_POLL_DEMAND     0x000003c1   /* Transmit Poll Demand */
+#define DMA_RCV_POLL_DEMAND     0x000003c2   /* Received Poll Demand */
+#define DMA_RCV_BASE_ADDR       0x000003c3   /* Receive List Base */
+#define DMA_TX_BASE_ADDR        0x000003c4   /* Transmit List Base */
+#define DMA_STATUS              0x000003c5   /* Status Register */
+#define DMA_CONTROL             0x000003c6   /* Ctrl (Operational Mode) */
+#define DMA_INTR_ENA            0x000003c7   /* Interrupt Enable */
+#define DMA_MISSED_FRAME_CTR    0x000003c8   /* Missed Frame Counter */
+/* Receive Interrupt Watchdog Timer */
+#define DMA_RI_WATCHDOG_TIMER   0x000003c9
+#define DMA_AXI_BUS             0x000003ca   /* AXI Bus Mode */
+#define DMA_AXI_STATUS          0x000003cb   /* AXI Status */
+#define DMA_CUR_TX_DESC_ADDR    0x000003d2   /* Current Host Tx Descriptor */
+#define DMA_CUR_RX_DESC_ADDR    0x000003d3   /* Current Host Rx Descriptor */
+#define DMA_CUR_TX_BUF_ADDR     0x000003d4   /* Current Host Tx Buffer */
+#define DMA_CUR_RX_BUF_ADDR     0x000003d5   /* Current Host Rx Buffer */
+#define DMA_HW_FEATURE          0x000003d6   /* Enabled Hardware Features */
+
+/* DMA Status register defines */
+#define DMA_STATUS_GMI          0x08000000   /* MMC interrupt */
+#define DMA_STATUS_GLI          0x04000000   /* GMAC Line interface int */
+#define DMA_STATUS_EB_MASK      0x00380000   /* Error Bits Mask */
+#define DMA_STATUS_EB_TX_ABORT  0x00080000   /* Error Bits - TX Abort */
+#define DMA_STATUS_EB_RX_ABORT  0x00100000   /* Error Bits - RX Abort */
+#define DMA_STATUS_TS_MASK      0x00700000   /* Transmit Process State */
+#define DMA_STATUS_TS_SHIFT     20
+#define DMA_STATUS_RS_MASK      0x000e0000   /* Receive Process State */
+#define DMA_STATUS_RS_SHIFT     17
+#define DMA_STATUS_NIS          0x00010000   /* Normal Interrupt Summary */
+#define DMA_STATUS_AIS          0x00008000   /* Abnormal Interrupt Summary */
+#define DMA_STATUS_ERI          0x00004000   /* Early Receive Interrupt */
+#define DMA_STATUS_FBI          0x00002000   /* Fatal Bus Error Interrupt */
+#define DMA_STATUS_ETI          0x00000400   /* Early Transmit Interrupt */
+#define DMA_STATUS_RWT          0x00000200   /* Receive Watchdog Timeout */
+#define DMA_STATUS_RPS          0x00000100   /* Receive Process Stopped */
+#define DMA_STATUS_RU           0x00000080   /* Receive Buffer Unavailable */
+#define DMA_STATUS_RI           0x00000040   /* Receive Interrupt */
+#define DMA_STATUS_UNF          0x00000020   /* Transmit Underflow */
+#define DMA_STATUS_OVF          0x00000010   /* Receive Overflow */
+#define DMA_STATUS_TJT          0x00000008   /* Transmit Jabber Timeout */
+#define DMA_STATUS_TU           0x00000004   /* Transmit Buffer Unavailable */
+#define DMA_STATUS_TPS          0x00000002   /* Transmit Process Stopped */
+#define DMA_STATUS_TI           0x00000001   /* Transmit Interrupt */
+
+/* DMA Control register defines */
+#define DMA_CONTROL_ST          0x00002000   /* Start/Stop Transmission */
+#define DMA_CONTROL_SR          0x00000002   /* Start/Stop Receive */
+#define DMA_CONTROL_DFF         0x01000000   /* Disable flush of rx frames */
+
+struct desc {
+    uint32_t ctl_stat;
+    uint16_t buffer1_size;
+    uint16_t buffer2_size;
+    uint32_t buffer1_addr;
+    uint32_t buffer2_addr;
+    uint32_t ext_stat;
+    uint32_t res[3];
+};
+
+#define R_MAX 0x400
+
+typedef struct RxTxStats {
+    uint64_t rx_bytes;
+    uint64_t tx_bytes;
+
+    uint64_t rx;
+    uint64_t rx_bcast;
+    uint64_t rx_mcast;
+} RxTxStats;
+
+typedef struct XgmacState {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+    qemu_irq sbd_irq;
+    qemu_irq pmt_irq;
+    qemu_irq mci_irq;
+    NICState *nic;
+    NICConf conf;
+
+    struct RxTxStats stats;
+    uint32_t regs[R_MAX];
+} XgmacState;
+
+const VMStateDescription vmstate_rxtx_stats = {
+    .name = "xgmac_stats",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT64(rx_bytes, RxTxStats),
+        VMSTATE_UINT64(tx_bytes, RxTxStats),
+        VMSTATE_UINT64(rx, RxTxStats),
+        VMSTATE_UINT64(rx_bcast, RxTxStats),
+        VMSTATE_UINT64(rx_mcast, RxTxStats),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const VMStateDescription vmstate_xgmac = {
+    .name = "xgmac",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_STRUCT(stats, XgmacState, 0, vmstate_rxtx_stats, RxTxStats),
+        VMSTATE_UINT32_ARRAY(regs, XgmacState, R_MAX),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void xgmac_read_desc(struct XgmacState *s, struct desc *d, int rx)
+{
+    uint32_t addr = rx ? s->regs[DMA_CUR_RX_DESC_ADDR] :
+        s->regs[DMA_CUR_TX_DESC_ADDR];
+    cpu_physical_memory_read(addr, d, sizeof(*d));
+}
+
+static void xgmac_write_desc(struct XgmacState *s, struct desc *d, int rx)
+{
+    int reg = rx ? DMA_CUR_RX_DESC_ADDR : DMA_CUR_TX_DESC_ADDR;
+    uint32_t addr = s->regs[reg];
+
+    if (!rx && (d->ctl_stat & 0x00200000)) {
+        s->regs[reg] = s->regs[DMA_TX_BASE_ADDR];
+    } else if (rx && (d->buffer1_size & 0x8000)) {
+        s->regs[reg] = s->regs[DMA_RCV_BASE_ADDR];
+    } else {
+        s->regs[reg] += sizeof(*d);
+    }
+    cpu_physical_memory_write(addr, d, sizeof(*d));
+}
+
+static void xgmac_enet_send(struct XgmacState *s)
+{
+    struct desc bd;
+    int frame_size;
+    int len;
+    uint8_t frame[8192];
+    uint8_t *ptr;
+
+    ptr = frame;
+    frame_size = 0;
+    while (1) {
+        xgmac_read_desc(s, &bd, 0);
+        if ((bd.ctl_stat & 0x80000000) == 0) {
+            /* Run out of descriptors to transmit.  */
+            break;
+        }
+        len = (bd.buffer1_size & 0xfff) + (bd.buffer2_size & 0xfff);
+
+        if ((bd.buffer1_size & 0xfff) > 2048) {
+            DEBUGF_BRK("qemu:%s:ERROR...ERROR...ERROR... -- "
+                        "xgmac buffer 1 len on send > 2048 (0x%x)\n",
+                         __func__, bd.buffer1_size & 0xfff);
+        }
+        if ((bd.buffer2_size & 0xfff) != 0) {
+            DEBUGF_BRK("qemu:%s:ERROR...ERROR...ERROR... -- "
+                        "xgmac buffer 2 len on send != 0 (0x%x)\n",
+                        __func__, bd.buffer2_size & 0xfff);
+        }
+        if (len >= sizeof(frame)) {
+            DEBUGF_BRK("qemu:%s: buffer overflow %d read into %zu "
+                        "buffer\n" , __func__, len, sizeof(frame));
+            DEBUGF_BRK("qemu:%s: buffer1.size=%d; buffer2.size=%d\n",
+                        __func__, bd.buffer1_size, bd.buffer2_size);
+        }
+
+        cpu_physical_memory_read(bd.buffer1_addr, ptr, len);
+        ptr += len;
+        frame_size += len;
+        if (bd.ctl_stat & 0x20000000) {
+            /* Last buffer in frame.  */
+            qemu_send_packet(&s->nic->nc, frame, len);
+            ptr = frame;
+            frame_size = 0;
+            s->regs[DMA_STATUS] |= DMA_STATUS_TI | DMA_STATUS_NIS;
+        }
+        bd.ctl_stat &= ~0x80000000;
+        /* Write back the modified descriptor.  */
+        xgmac_write_desc(s, &bd, 0);
+    }
+}
+
+static void enet_update_irq(struct XgmacState *s)
+{
+    int stat = s->regs[DMA_STATUS] & s->regs[DMA_INTR_ENA];
+    qemu_set_irq(s->sbd_irq, !!stat);
+}
+
+static uint64_t enet_read(void *opaque, target_phys_addr_t addr, unsigned size)
+{
+    struct XgmacState *s = opaque;
+    uint64_t r = 0;
+    addr >>= 2;
+
+    switch (addr) {
+    case XGMAC_VERSION:
+        r = 0x1012;
+        break;
+    default:
+        if (addr < ARRAY_SIZE(s->regs)) {
+            r = s->regs[addr];
+        }
+        break;
+    }
+    return r;
+}
+
+static void enet_write(void *opaque, target_phys_addr_t addr,
+                       uint64_t value, unsigned size)
+{
+    struct XgmacState *s = opaque;
+
+    addr >>= 2;
+    switch (addr) {
+    case DMA_BUS_MODE:
+        s->regs[DMA_BUS_MODE] = value & ~0x1;
+        break;
+    case DMA_XMT_POLL_DEMAND:
+        xgmac_enet_send(s);
+        break;
+    case DMA_STATUS:
+        s->regs[DMA_STATUS] = s->regs[DMA_STATUS] & ~value;
+        break;
+    case DMA_RCV_BASE_ADDR:
+        s->regs[DMA_RCV_BASE_ADDR] = s->regs[DMA_CUR_RX_DESC_ADDR] = value;
+        break;
+    case DMA_TX_BASE_ADDR:
+        s->regs[DMA_TX_BASE_ADDR] = s->regs[DMA_CUR_TX_DESC_ADDR] = value;
+        break;
+    default:
+        if (addr < ARRAY_SIZE(s->regs)) {
+            s->regs[addr] = value;
+        }
+        break;
+    }
+    enet_update_irq(s);
+}
+
+static const MemoryRegionOps enet_mem_ops = {
+    .read = enet_read,
+    .write = enet_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static int eth_can_rx(VLANClientState *nc)
+{
+    struct XgmacState *s = DO_UPCAST(NICState, nc, nc)->opaque;
+
+    /* RX enabled?  */
+    return s->regs[DMA_CONTROL] & DMA_CONTROL_SR;
+}
+
+static ssize_t eth_rx(VLANClientState *nc, const uint8_t *buf, size_t size)
+{
+    struct XgmacState *s = DO_UPCAST(NICState, nc, nc)->opaque;
+    static const unsigned char sa_bcast[6] = {0xff, 0xff, 0xff,
+                                              0xff, 0xff, 0xff};
+    int unicast, broadcast, multicast;
+    struct desc bd;
+    ssize_t ret;
+
+    unicast = ~buf[0] & 0x1;
+    broadcast = memcmp(buf, sa_bcast, 6) == 0;
+    multicast = !unicast && !broadcast;
+    if (size < 12) {
+        s->regs[DMA_STATUS] |= DMA_STATUS_RI | DMA_STATUS_NIS;
+        ret = -1;
+        goto out;
+    }
+
+    xgmac_read_desc(s, &bd, 1);
+    if ((bd.ctl_stat & 0x80000000) == 0) {
+        s->regs[DMA_STATUS] |= DMA_STATUS_RU | DMA_STATUS_AIS;
+        ret = size;
+        goto out;
+    }
+
+    cpu_physical_memory_write(bd.buffer1_addr, buf, size);
+
+    /* Add in the 4 bytes for crc (the real hw returns length incl crc) */
+    size += 4;
+    bd.ctl_stat = (size << 16) | 0x300;
+    xgmac_write_desc(s, &bd, 1);
+
+    s->stats.rx_bytes += size;
+    s->stats.rx++;
+    if (multicast) {
+        s->stats.rx_mcast++;
+    } else if (broadcast) {
+        s->stats.rx_bcast++;
+    }
+
+    s->regs[DMA_STATUS] |= DMA_STATUS_RI | DMA_STATUS_NIS;
+    ret = size;
+
+out:
+    enet_update_irq(s);
+    return ret;
+}
+
+static void eth_cleanup(VLANClientState *nc)
+{
+    struct XgmacState *s = DO_UPCAST(NICState, nc, nc)->opaque;
+    s->nic = NULL;
+}
+
+static NetClientInfo net_xgmac_enet_info = {
+    .type = NET_CLIENT_TYPE_NIC,
+    .size = sizeof(NICState),
+    .can_receive = eth_can_rx,
+    .receive = eth_rx,
+    .cleanup = eth_cleanup,
+};
+
+static int xgmac_enet_init(SysBusDevice *dev)
+{
+    struct XgmacState *s = FROM_SYSBUS(typeof(*s), dev);
+
+    memory_region_init_io(&s->iomem, &enet_mem_ops, s, "xgmac", 0x1000);
+    sysbus_init_mmio(dev, &s->iomem);
+    sysbus_init_irq(dev, &s->sbd_irq);
+    sysbus_init_irq(dev, &s->pmt_irq);
+    sysbus_init_irq(dev, &s->mci_irq);
+
+    qemu_macaddr_default_if_unset(&s->conf.macaddr);
+    s->nic = qemu_new_nic(&net_xgmac_enet_info, &s->conf,
+                          object_get_typename(OBJECT(dev)), dev->qdev.id, s);
+    qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a);
+
+    s->regs[XGMAC_ADDR_HIGH(0)] = (s->conf.macaddr.a[5] << 8) |
+                                   s->conf.macaddr.a[4];
+    s->regs[XGMAC_ADDR_LOW(0)] = (s->conf.macaddr.a[3] << 24) |
+                                 (s->conf.macaddr.a[2] << 16) |
+                                 (s->conf.macaddr.a[1] << 8) |
+                                  s->conf.macaddr.a[0];
+
+    return 0;
+}
+
+static Property xgmac_properties[] = {
+    DEFINE_NIC_PROPERTIES(struct XgmacState, conf),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void xgmac_enet_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass);
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    sbc->init = xgmac_enet_init;
+    dc->vmsd = &vmstate_xgmac;
+    dc->props = xgmac_properties;
+}
+
+static TypeInfo xgmac_enet_info = {
+    .name          = "xgmac",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(struct XgmacState),
+    .class_init    = xgmac_enet_class_init,
+};
+
+static void xgmac_enet_register(void)
+{
+    type_register_static(&xgmac_enet_info);
+}
+
+device_init(xgmac_enet_register)
diff --git a/hw/xilinx_axidma.c b/hw/xilinx_axidma.c
index 0da20d9565..e8a53123f9 100644
--- a/hw/xilinx_axidma.c
+++ b/hw/xilinx_axidma.c
@@ -486,20 +486,31 @@ static int xilinx_axidma_init(SysBusDevice *dev)
     return 0;
 }
 
-static SysBusDeviceInfo axidma_info = {
-    .init = xilinx_axidma_init,
-    .qdev.name  = "xilinx,axidma",
-    .qdev.size  = sizeof(struct XilinxAXIDMA),
-    .qdev.props = (Property[]) {
-        DEFINE_PROP_UINT32("freqhz", struct XilinxAXIDMA, freqhz, 50000000),
-        DEFINE_PROP_PTR("dmach", struct XilinxAXIDMA, dmach),
-        DEFINE_PROP_END_OF_LIST(),
-    }
+static Property axidma_properties[] = {
+    DEFINE_PROP_UINT32("freqhz", struct XilinxAXIDMA, freqhz, 50000000),
+    DEFINE_PROP_PTR("dmach", struct XilinxAXIDMA, dmach),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void axidma_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = xilinx_axidma_init;
+    dc->props = axidma_properties;
+}
+
+static TypeInfo axidma_info = {
+    .name          = "xilinx,axidma",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(struct XilinxAXIDMA),
+    .class_init    = axidma_class_init,
 };
 
 static void xilinx_axidma_register(void)
 {
-    sysbus_register_withprop(&axidma_info);
+    type_register_static(&axidma_info);
 }
 
 device_init(xilinx_axidma_register)
diff --git a/hw/xilinx_axienet.c b/hw/xilinx_axienet.c
index a2eb3e6d5b..1ce2db4510 100644
--- a/hw/xilinx_axienet.c
+++ b/hw/xilinx_axienet.c
@@ -856,7 +856,7 @@ static int xilinx_enet_init(SysBusDevice *dev)
 
     qemu_macaddr_default_if_unset(&s->conf.macaddr);
     s->nic = qemu_new_nic(&net_xilinx_enet_info, &s->conf,
-                          dev->qdev.info->name, dev->qdev.id, s);
+                          object_get_typename(OBJECT(dev)), dev->qdev.id, s);
     qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a);
 
     tdk_init(&s->TEMAC.phy);
@@ -870,22 +870,33 @@ static int xilinx_enet_init(SysBusDevice *dev)
     return 0;
 }
 
-static SysBusDeviceInfo xilinx_enet_info = {
-    .init = xilinx_enet_init,
-    .qdev.name  = "xilinx,axienet",
-    .qdev.size  = sizeof(struct XilinxAXIEnet),
-    .qdev.props = (Property[]) {
-        DEFINE_PROP_UINT32("phyaddr", struct XilinxAXIEnet, c_phyaddr, 7),
-        DEFINE_PROP_UINT32("c_rxmem", struct XilinxAXIEnet, c_rxmem, 0x1000),
-        DEFINE_PROP_UINT32("c_txmem", struct XilinxAXIEnet, c_txmem, 0x1000),
-        DEFINE_PROP_PTR("dmach", struct XilinxAXIEnet, dmach),
-        DEFINE_NIC_PROPERTIES(struct XilinxAXIEnet, conf),
-        DEFINE_PROP_END_OF_LIST(),
-    }
+static Property xilinx_enet_properties[] = {
+    DEFINE_PROP_UINT32("phyaddr", struct XilinxAXIEnet, c_phyaddr, 7),
+    DEFINE_PROP_UINT32("c_rxmem", struct XilinxAXIEnet, c_rxmem, 0x1000),
+    DEFINE_PROP_UINT32("c_txmem", struct XilinxAXIEnet, c_txmem, 0x1000),
+    DEFINE_PROP_PTR("dmach", struct XilinxAXIEnet, dmach),
+    DEFINE_NIC_PROPERTIES(struct XilinxAXIEnet, conf),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void xilinx_enet_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = xilinx_enet_init;
+    dc->props = xilinx_enet_properties;
+}
+
+static TypeInfo xilinx_enet_info = {
+    .name          = "xilinx,axienet",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(struct XilinxAXIEnet),
+    .class_init    = xilinx_enet_class_init,
 };
 static void xilinx_enet_register(void)
 {
-    sysbus_register_withprop(&xilinx_enet_info);
+    type_register_static(&xilinx_enet_info);
 }
 
 device_init(xilinx_enet_register)
diff --git a/hw/xilinx_ethlite.c b/hw/xilinx_ethlite.c
index 6777254f35..499feef488 100644
--- a/hw/xilinx_ethlite.c
+++ b/hw/xilinx_ethlite.c
@@ -221,26 +221,37 @@ static int xilinx_ethlite_init(SysBusDevice *dev)
 
     qemu_macaddr_default_if_unset(&s->conf.macaddr);
     s->nic = qemu_new_nic(&net_xilinx_ethlite_info, &s->conf,
-                          dev->qdev.info->name, dev->qdev.id, s);
+                          object_get_typename(OBJECT(dev)), dev->qdev.id, s);
     qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a);
     return 0;
 }
 
-static SysBusDeviceInfo xilinx_ethlite_info = {
-    .init = xilinx_ethlite_init,
-    .qdev.name  = "xilinx,ethlite",
-    .qdev.size  = sizeof(struct xlx_ethlite),
-    .qdev.props = (Property[]) {
-        DEFINE_PROP_UINT32("txpingpong", struct xlx_ethlite, c_tx_pingpong, 1),
-        DEFINE_PROP_UINT32("rxpingpong", struct xlx_ethlite, c_rx_pingpong, 1),
-        DEFINE_NIC_PROPERTIES(struct xlx_ethlite, conf),
-        DEFINE_PROP_END_OF_LIST(),
-    }
+static Property xilinx_ethlite_properties[] = {
+    DEFINE_PROP_UINT32("txpingpong", struct xlx_ethlite, c_tx_pingpong, 1),
+    DEFINE_PROP_UINT32("rxpingpong", struct xlx_ethlite, c_rx_pingpong, 1),
+    DEFINE_NIC_PROPERTIES(struct xlx_ethlite, conf),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void xilinx_ethlite_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = xilinx_ethlite_init;
+    dc->props = xilinx_ethlite_properties;
+}
+
+static TypeInfo xilinx_ethlite_info = {
+    .name          = "xilinx,ethlite",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(struct xlx_ethlite),
+    .class_init    = xilinx_ethlite_class_init,
 };
 
 static void xilinx_ethlite_register(void)
 {
-    sysbus_register_withprop(&xilinx_ethlite_info);
+    type_register_static(&xilinx_ethlite_info);
 }
 
 device_init(xilinx_ethlite_register)
diff --git a/hw/xilinx_intc.c b/hw/xilinx_intc.c
index c567885bcf..73eed6dc5f 100644
--- a/hw/xilinx_intc.c
+++ b/hw/xilinx_intc.c
@@ -161,19 +161,30 @@ static int xilinx_intc_init(SysBusDevice *dev)
     return 0;
 }
 
-static SysBusDeviceInfo xilinx_intc_info = {
-    .init = xilinx_intc_init,
-    .qdev.name  = "xilinx,intc",
-    .qdev.size  = sizeof(struct xlx_pic),
-    .qdev.props = (Property[]) {
-        DEFINE_PROP_UINT32("kind-of-intr", struct xlx_pic, c_kind_of_intr, 0),
-        DEFINE_PROP_END_OF_LIST(),
-    }
+static Property xilinx_intc_properties[] = {
+    DEFINE_PROP_UINT32("kind-of-intr", struct xlx_pic, c_kind_of_intr, 0),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void xilinx_intc_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = xilinx_intc_init;
+    dc->props = xilinx_intc_properties;
+}
+
+static TypeInfo xilinx_intc_info = {
+    .name          = "xilinx,intc",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(struct xlx_pic),
+    .class_init    = xilinx_intc_class_init,
 };
 
 static void xilinx_intc_register(void)
 {
-    sysbus_register_withprop(&xilinx_intc_info);
+    type_register_static(&xilinx_intc_info);
 }
 
 device_init(xilinx_intc_register)
diff --git a/hw/xilinx_timer.c b/hw/xilinx_timer.c
index adca53b98c..c8236d2e2a 100644
--- a/hw/xilinx_timer.c
+++ b/hw/xilinx_timer.c
@@ -219,20 +219,31 @@ static int xilinx_timer_init(SysBusDevice *dev)
     return 0;
 }
 
-static SysBusDeviceInfo xilinx_timer_info = {
-    .init = xilinx_timer_init,
-    .qdev.name  = "xilinx,timer",
-    .qdev.size  = sizeof(struct timerblock),
-    .qdev.props = (Property[]) {
-        DEFINE_PROP_UINT32("frequency", struct timerblock, freq_hz,   0),
-        DEFINE_PROP_UINT32("nr-timers", struct timerblock, nr_timers, 0),
-        DEFINE_PROP_END_OF_LIST(),
-    }
+static Property xilinx_timer_properties[] = {
+    DEFINE_PROP_UINT32("frequency", struct timerblock, freq_hz,   0),
+    DEFINE_PROP_UINT32("nr-timers", struct timerblock, nr_timers, 0),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void xilinx_timer_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = xilinx_timer_init;
+    dc->props = xilinx_timer_properties;
+}
+
+static TypeInfo xilinx_timer_info = {
+    .name          = "xilinx,timer",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(struct timerblock),
+    .class_init    = xilinx_timer_class_init,
 };
 
 static void xilinx_timer_register(void)
 {
-    sysbus_register_withprop(&xilinx_timer_info);
+    type_register_static(&xilinx_timer_info);
 }
 
 device_init(xilinx_timer_register)
diff --git a/hw/xilinx_uartlite.c b/hw/xilinx_uartlite.c
index 6533df934f..1c2b9087b4 100644
--- a/hw/xilinx_uartlite.c
+++ b/hw/xilinx_uartlite.c
@@ -205,16 +205,29 @@ static int xilinx_uartlite_init(SysBusDevice *dev)
     memory_region_init_io(&s->mmio, &uart_ops, s, "xilinx-uartlite", R_MAX * 4);
     sysbus_init_mmio(dev, &s->mmio);
 
-    s->chr = qdev_init_chardev(&dev->qdev);
+    s->chr = qemu_char_get_next_serial();
     if (s->chr)
         qemu_chr_add_handlers(s->chr, uart_can_rx, uart_rx, uart_event, s);
     return 0;
 }
 
+static void xilinx_uartlite_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+
+    sdc->init = xilinx_uartlite_init;
+}
+
+static TypeInfo xilinx_uartlite_info = {
+    .name          = "xilinx,uartlite",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof (struct xlx_uartlite),
+    .class_init    = xilinx_uartlite_class_init,
+};
+
 static void xilinx_uart_register(void)
 {
-    sysbus_register_dev("xilinx,uartlite", sizeof (struct xlx_uartlite),
-                        xilinx_uartlite_init);
+    type_register_static(&xilinx_uartlite_info);
 }
 
 device_init(xilinx_uart_register)
diff --git a/hw/xio3130_downstream.c b/hw/xio3130_downstream.c
index d3c387d6cb..07e4fc1018 100644
--- a/hw/xio3130_downstream.c
+++ b/hw/xio3130_downstream.c
@@ -47,7 +47,7 @@ static void xio3130_downstream_write_config(PCIDevice *d, uint32_t address,
 
 static void xio3130_downstream_reset(DeviceState *qdev)
 {
-    PCIDevice *d = DO_UPCAST(PCIDevice, qdev, qdev);
+    PCIDevice *d = PCI_DEVICE(qdev);
     msi_reset(d);
     pcie_cap_deverr_reset(d);
     pcie_cap_slot_reset(d);
@@ -167,36 +167,45 @@ static const VMStateDescription vmstate_xio3130_downstream = {
     }
 };
 
-static PCIDeviceInfo xio3130_downstream_info = {
-    .qdev.name = "xio3130-downstream",
-    .qdev.desc = "TI X3130 Downstream Port of PCI Express Switch",
-    .qdev.size = sizeof(PCIESlot),
-    .qdev.reset = xio3130_downstream_reset,
-    .qdev.vmsd = &vmstate_xio3130_downstream,
-
-    .is_express = 1,
-    .is_bridge = 1,
-    .config_write = xio3130_downstream_write_config,
-    .init = xio3130_downstream_initfn,
-    .exit = xio3130_downstream_exitfn,
-    .vendor_id = PCI_VENDOR_ID_TI,
-    .device_id = PCI_DEVICE_ID_TI_XIO3130D,
-    .revision = XIO3130_REVISION,
-
-    .qdev.props = (Property[]) {
-        DEFINE_PROP_UINT8("port", PCIESlot, port.port, 0),
-        DEFINE_PROP_UINT8("chassis", PCIESlot, chassis, 0),
-        DEFINE_PROP_UINT16("slot", PCIESlot, slot, 0),
-        DEFINE_PROP_UINT16("aer_log_max", PCIESlot,
-                           port.br.dev.exp.aer_log.log_max,
-                           PCIE_AER_LOG_MAX_DEFAULT),
-        DEFINE_PROP_END_OF_LIST(),
-    }
+static Property xio3130_downstream_properties[] = {
+    DEFINE_PROP_UINT8("port", PCIESlot, port.port, 0),
+    DEFINE_PROP_UINT8("chassis", PCIESlot, chassis, 0),
+    DEFINE_PROP_UINT16("slot", PCIESlot, slot, 0),
+    DEFINE_PROP_UINT16("aer_log_max", PCIESlot,
+    port.br.dev.exp.aer_log.log_max,
+    PCIE_AER_LOG_MAX_DEFAULT),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void xio3130_downstream_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->is_express = 1;
+    k->is_bridge = 1;
+    k->config_write = xio3130_downstream_write_config;
+    k->init = xio3130_downstream_initfn;
+    k->exit = xio3130_downstream_exitfn;
+    k->vendor_id = PCI_VENDOR_ID_TI;
+    k->device_id = PCI_DEVICE_ID_TI_XIO3130D;
+    k->revision = XIO3130_REVISION;
+    dc->desc = "TI X3130 Downstream Port of PCI Express Switch";
+    dc->reset = xio3130_downstream_reset;
+    dc->vmsd = &vmstate_xio3130_downstream;
+    dc->props = xio3130_downstream_properties;
+}
+
+static TypeInfo xio3130_downstream_info = {
+    .name          = "xio3130-downstream",
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(PCIESlot),
+    .class_init    = xio3130_downstream_class_init,
 };
 
 static void xio3130_downstream_register(void)
 {
-    pci_qdev_register(&xio3130_downstream_info);
+    type_register_static(&xio3130_downstream_info);
 }
 
 device_init(xio3130_downstream_register);
diff --git a/hw/xio3130_upstream.c b/hw/xio3130_upstream.c
index 82836958a4..7887c92fcc 100644
--- a/hw/xio3130_upstream.c
+++ b/hw/xio3130_upstream.c
@@ -46,7 +46,7 @@ static void xio3130_upstream_write_config(PCIDevice *d, uint32_t address,
 
 static void xio3130_upstream_reset(DeviceState *qdev)
 {
-    PCIDevice *d = DO_UPCAST(PCIDevice, qdev, qdev);
+    PCIDevice *d = PCI_DEVICE(qdev);
     msi_reset(d);
     pci_bridge_reset(qdev);
     pcie_cap_deverr_reset(d);
@@ -144,33 +144,42 @@ static const VMStateDescription vmstate_xio3130_upstream = {
     }
 };
 
-static PCIDeviceInfo xio3130_upstream_info = {
-    .qdev.name = "x3130-upstream",
-    .qdev.desc = "TI X3130 Upstream Port of PCI Express Switch",
-    .qdev.size = sizeof(PCIEPort),
-    .qdev.reset = xio3130_upstream_reset,
-    .qdev.vmsd = &vmstate_xio3130_upstream,
-
-    .is_express = 1,
-    .is_bridge = 1,
-    .config_write = xio3130_upstream_write_config,
-    .init = xio3130_upstream_initfn,
-    .exit = xio3130_upstream_exitfn,
-    .vendor_id = PCI_VENDOR_ID_TI,
-    .device_id = PCI_DEVICE_ID_TI_XIO3130U,
-    .revision = XIO3130_REVISION,
-
-    .qdev.props = (Property[]) {
-        DEFINE_PROP_UINT8("port", PCIEPort, port, 0),
-        DEFINE_PROP_UINT16("aer_log_max", PCIEPort, br.dev.exp.aer_log.log_max,
-                           PCIE_AER_LOG_MAX_DEFAULT),
-        DEFINE_PROP_END_OF_LIST(),
-    }
+static Property xio3130_upstream_properties[] = {
+    DEFINE_PROP_UINT8("port", PCIEPort, port, 0),
+    DEFINE_PROP_UINT16("aer_log_max", PCIEPort, br.dev.exp.aer_log.log_max,
+    PCIE_AER_LOG_MAX_DEFAULT),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void xio3130_upstream_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->is_express = 1;
+    k->is_bridge = 1;
+    k->config_write = xio3130_upstream_write_config;
+    k->init = xio3130_upstream_initfn;
+    k->exit = xio3130_upstream_exitfn;
+    k->vendor_id = PCI_VENDOR_ID_TI;
+    k->device_id = PCI_DEVICE_ID_TI_XIO3130U;
+    k->revision = XIO3130_REVISION;
+    dc->desc = "TI X3130 Upstream Port of PCI Express Switch";
+    dc->reset = xio3130_upstream_reset;
+    dc->vmsd = &vmstate_xio3130_upstream;
+    dc->props = xio3130_upstream_properties;
+}
+
+static TypeInfo xio3130_upstream_info = {
+    .name          = "x3130-upstream",
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(PCIEPort),
+    .class_init    = xio3130_upstream_class_init,
 };
 
 static void xio3130_upstream_register(void)
 {
-    pci_qdev_register(&xio3130_upstream_info);
+    type_register_static(&xio3130_upstream_info);
 }
 
 device_init(xio3130_upstream_register);
diff --git a/hw/z2.c b/hw/z2.c
index 8d48488331..654ac55f5c 100644
--- a/hw/z2.c
+++ b/hw/z2.c
@@ -174,21 +174,30 @@ static VMStateDescription vmstate_zipit_lcd_state = {
     }
 };
 
-static SSISlaveInfo zipit_lcd_info = {
-    .qdev.name = "zipit-lcd",
-    .qdev.size = sizeof(ZipitLCD),
-    .qdev.vmsd = &vmstate_zipit_lcd_state,
-    .init = zipit_lcd_init,
-    .transfer = zipit_lcd_transfer
+static void zipit_lcd_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SSISlaveClass *k = SSI_SLAVE_CLASS(klass);
+
+    k->init = zipit_lcd_init;
+    k->transfer = zipit_lcd_transfer;
+    dc->vmsd = &vmstate_zipit_lcd_state;
+}
+
+static TypeInfo zipit_lcd_info = {
+    .name          = "zipit-lcd",
+    .parent        = TYPE_SSI_SLAVE,
+    .instance_size = sizeof(ZipitLCD),
+    .class_init    = zipit_lcd_class_init,
 };
 
 typedef struct {
-    i2c_slave i2c;
+    I2CSlave i2c;
     int len;
     uint8_t buf[3];
 } AER915State;
 
-static int aer915_send(i2c_slave *i2c, uint8_t data)
+static int aer915_send(I2CSlave *i2c, uint8_t data)
 {
     AER915State *s = FROM_I2C_SLAVE(AER915State, i2c);
     s->buf[s->len] = data;
@@ -206,7 +215,7 @@ static int aer915_send(i2c_slave *i2c, uint8_t data)
     return 0;
 }
 
-static void aer915_event(i2c_slave *i2c, enum i2c_event event)
+static void aer915_event(I2CSlave *i2c, enum i2c_event event)
 {
     AER915State *s = FROM_I2C_SLAVE(AER915State, i2c);
     switch (event) {
@@ -225,7 +234,7 @@ static void aer915_event(i2c_slave *i2c, enum i2c_event event)
     }
 }
 
-static int aer915_recv(i2c_slave *slave)
+static int aer915_recv(I2CSlave *slave)
 {
     int retval = 0x00;
     AER915State *s = FROM_I2C_SLAVE(AER915State, slave);
@@ -248,7 +257,7 @@ static int aer915_recv(i2c_slave *slave)
     return retval;
 }
 
-static int aer915_init(i2c_slave *i2c)
+static int aer915_init(I2CSlave *i2c)
 {
     /* Nothing to do.  */
     return 0;
@@ -266,14 +275,23 @@ static VMStateDescription vmstate_aer915_state = {
     }
 };
 
-static I2CSlaveInfo aer915_info = {
-    .qdev.name = "aer915",
-    .qdev.size = sizeof(AER915State),
-    .qdev.vmsd = &vmstate_aer915_state,
-    .init = aer915_init,
-    .event = aer915_event,
-    .recv = aer915_recv,
-    .send = aer915_send
+static void aer915_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
+
+    k->init = aer915_init;
+    k->event = aer915_event;
+    k->recv = aer915_recv;
+    k->send = aer915_send;
+    dc->vmsd = &vmstate_aer915_state;
+}
+
+static TypeInfo aer915_info = {
+    .name          = "aer915",
+    .parent        = TYPE_I2C_SLAVE,
+    .instance_size = sizeof(AER915State),
+    .class_init    = aer915_class_init,
 };
 
 static void z2_init(ram_addr_t ram_size,
@@ -326,8 +344,8 @@ static void z2_init(ram_addr_t ram_size,
         NULL,
         qdev_get_gpio_in(cpu->gpio, Z2_GPIO_SD_DETECT));
 
-    ssi_register_slave(&zipit_lcd_info);
-    i2c_register_slave(&aer915_info);
+    type_register_static(&zipit_lcd_info);
+    type_register_static(&aer915_info);
     z2_lcd = ssi_create_slave(cpu->ssp[1], "zipit-lcd");
     bus = pxa2xx_i2c_bus(cpu->i2c[0]);
     i2c_create_slave(bus, "aer915", 0x55);
diff --git a/hw/zaurus.c b/hw/zaurus.c
index c4bcd29825..055df9b4e2 100644
--- a/hw/zaurus.c
+++ b/hw/zaurus.c
@@ -221,20 +221,31 @@ static const VMStateDescription vmstate_scoop_regs = {
     },
 };
 
-static SysBusDeviceInfo scoop_sysbus_info = {
-    .init           = scoop_init,
-    .qdev.name      = "scoop",
-    .qdev.desc      = "Scoop2 Sharp custom ASIC",
-    .qdev.size      = sizeof(ScoopInfo),
-    .qdev.vmsd      = &vmstate_scoop_regs,
-    .qdev.props     = (Property[]) {
-        DEFINE_PROP_END_OF_LIST(),
-    }
+static Property scoop_sysbus_properties[] = {
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void scoop_sysbus_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = scoop_init;
+    dc->desc = "Scoop2 Sharp custom ASIC";
+    dc->vmsd = &vmstate_scoop_regs;
+    dc->props = scoop_sysbus_properties;
+}
+
+static TypeInfo scoop_sysbus_info = {
+    .name          = "scoop",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(ScoopInfo),
+    .class_init    = scoop_sysbus_class_init,
 };
 
 static void scoop_register(void)
 {
-    sysbus_register_withprop(&scoop_sysbus_info);
+    type_register_static(&scoop_sysbus_info);
 }
 device_init(scoop_register);